@atproto/bsky 0.0.198 → 0.0.200
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/dist/api/age-assurance/const.d.ts +11 -0
- package/dist/api/age-assurance/const.d.ts.map +1 -0
- package/dist/api/age-assurance/const.js +142 -0
- package/dist/api/age-assurance/const.js.map +1 -0
- package/dist/api/age-assurance/index.d.ts +4 -0
- package/dist/api/age-assurance/index.d.ts.map +1 -0
- package/dist/api/age-assurance/index.js +24 -0
- package/dist/api/age-assurance/index.js.map +1 -0
- package/dist/api/age-assurance/kws/age-verified.d.ts +109 -0
- package/dist/api/age-assurance/kws/age-verified.d.ts.map +1 -0
- package/dist/api/age-assurance/kws/age-verified.js +63 -0
- package/dist/api/age-assurance/kws/age-verified.js.map +1 -0
- package/dist/api/age-assurance/kws/const.d.ts +13 -0
- package/dist/api/age-assurance/kws/const.d.ts.map +1 -0
- package/dist/api/age-assurance/kws/const.js +36 -0
- package/dist/api/age-assurance/kws/const.js.map +1 -0
- package/dist/api/age-assurance/kws/external-payload.d.ts +75 -0
- package/dist/api/age-assurance/kws/external-payload.d.ts.map +1 -0
- package/dist/api/age-assurance/kws/external-payload.js +124 -0
- package/dist/api/age-assurance/kws/external-payload.js.map +1 -0
- package/dist/api/age-assurance/kws/external-payload.test.d.ts +2 -0
- package/dist/api/age-assurance/kws/external-payload.test.d.ts.map +1 -0
- package/dist/api/age-assurance/kws/external-payload.test.js +65 -0
- package/dist/api/age-assurance/kws/external-payload.test.js.map +1 -0
- package/dist/api/age-assurance/redirects/kws-age-verified.d.ts +4 -0
- package/dist/api/age-assurance/redirects/kws-age-verified.d.ts.map +1 -0
- package/dist/api/age-assurance/redirects/kws-age-verified.js +76 -0
- package/dist/api/age-assurance/redirects/kws-age-verified.js.map +1 -0
- package/dist/api/age-assurance/stash.d.ts +4 -0
- package/dist/api/age-assurance/stash.d.ts.map +1 -0
- package/dist/api/age-assurance/stash.js +19 -0
- package/dist/api/age-assurance/stash.js.map +1 -0
- package/dist/api/age-assurance/types.d.ts +10 -0
- package/dist/api/age-assurance/types.d.ts.map +1 -0
- package/dist/api/age-assurance/types.js +3 -0
- package/dist/api/age-assurance/types.js.map +1 -0
- package/dist/api/age-assurance/util.d.ts +15 -0
- package/dist/api/age-assurance/util.d.ts.map +1 -0
- package/dist/api/age-assurance/util.js +54 -0
- package/dist/api/age-assurance/util.js.map +1 -0
- package/dist/api/age-assurance/webhooks/kws-age-verified.d.ts +4 -0
- package/dist/api/age-assurance/webhooks/kws-age-verified.d.ts.map +1 -0
- package/dist/api/age-assurance/webhooks/kws-age-verified.js +63 -0
- package/dist/api/age-assurance/webhooks/kws-age-verified.js.map +1 -0
- package/dist/api/app/bsky/ageassurance/begin.d.ts +4 -0
- package/dist/api/app/bsky/ageassurance/begin.d.ts.map +1 -0
- package/dist/api/app/bsky/ageassurance/begin.js +131 -0
- package/dist/api/app/bsky/ageassurance/begin.js.map +1 -0
- package/dist/api/app/bsky/ageassurance/getConfig.d.ts +4 -0
- package/dist/api/app/bsky/ageassurance/getConfig.d.ts.map +1 -0
- package/dist/api/app/bsky/ageassurance/getConfig.js +16 -0
- package/dist/api/app/bsky/ageassurance/getConfig.js.map +1 -0
- package/dist/api/app/bsky/ageassurance/getState.d.ts +4 -0
- package/dist/api/app/bsky/ageassurance/getState.d.ts.map +1 -0
- package/dist/api/app/bsky/ageassurance/getState.js +42 -0
- package/dist/api/app/bsky/ageassurance/getState.js.map +1 -0
- package/dist/api/app/bsky/contact/dismissMatch.d.ts +4 -0
- package/dist/api/app/bsky/contact/dismissMatch.d.ts.map +1 -0
- package/dist/api/app/bsky/contact/dismissMatch.js +23 -0
- package/dist/api/app/bsky/contact/dismissMatch.js.map +1 -0
- package/dist/api/app/bsky/contact/getMatches.d.ts +4 -0
- package/dist/api/app/bsky/contact/getMatches.d.ts.map +1 -0
- package/dist/api/app/bsky/contact/getMatches.js +59 -0
- package/dist/api/app/bsky/contact/getMatches.js.map +1 -0
- package/dist/api/app/bsky/contact/getSyncStatus.d.ts +4 -0
- package/dist/api/app/bsky/contact/getSyncStatus.d.ts.map +1 -0
- package/dist/api/app/bsky/contact/getSyncStatus.js +32 -0
- package/dist/api/app/bsky/contact/getSyncStatus.js.map +1 -0
- package/dist/api/app/bsky/contact/importContacts.d.ts +4 -0
- package/dist/api/app/bsky/contact/importContacts.d.ts.map +1 -0
- package/dist/api/app/bsky/contact/importContacts.js +62 -0
- package/dist/api/app/bsky/contact/importContacts.js.map +1 -0
- package/dist/api/app/bsky/contact/removeData.d.ts +4 -0
- package/dist/api/app/bsky/contact/removeData.d.ts.map +1 -0
- package/dist/api/app/bsky/contact/removeData.js +22 -0
- package/dist/api/app/bsky/contact/removeData.js.map +1 -0
- package/dist/api/app/bsky/contact/startPhoneVerification.d.ts +4 -0
- package/dist/api/app/bsky/contact/startPhoneVerification.d.ts.map +1 -0
- package/dist/api/app/bsky/contact/startPhoneVerification.js +23 -0
- package/dist/api/app/bsky/contact/startPhoneVerification.js.map +1 -0
- package/dist/api/app/bsky/contact/util.d.ts +6 -0
- package/dist/api/app/bsky/contact/util.d.ts.map +1 -0
- package/dist/api/app/bsky/contact/util.js +10 -0
- package/dist/api/app/bsky/contact/util.js.map +1 -0
- package/dist/api/app/bsky/contact/verifyPhone.d.ts +4 -0
- package/dist/api/app/bsky/contact/verifyPhone.d.ts.map +1 -0
- package/dist/api/app/bsky/contact/verifyPhone.js +26 -0
- package/dist/api/app/bsky/contact/verifyPhone.js.map +1 -0
- package/dist/api/app/bsky/graph/getRelationships.d.ts.map +1 -1
- package/dist/api/app/bsky/graph/getRelationships.js +4 -0
- package/dist/api/app/bsky/graph/getRelationships.js.map +1 -1
- package/dist/api/external.d.ts.map +1 -1
- package/dist/api/external.js +2 -0
- package/dist/api/external.js.map +1 -1
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +22 -2
- package/dist/api/index.js.map +1 -1
- package/dist/api/kws/api.d.ts.map +1 -1
- package/dist/api/kws/api.js +44 -26
- package/dist/api/kws/api.js.map +1 -1
- package/dist/api/kws/index.d.ts.map +1 -1
- package/dist/api/kws/index.js +3 -1
- package/dist/api/kws/index.js.map +1 -1
- package/dist/api/kws/webhook.d.ts +3 -1
- package/dist/api/kws/webhook.d.ts.map +1 -1
- package/dist/api/kws/webhook.js +48 -20
- package/dist/api/kws/webhook.js.map +1 -1
- package/dist/config.d.ts +22 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +31 -2
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +3 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +3 -0
- package/dist/context.js.map +1 -1
- package/dist/data-plane/bsync/index.d.ts.map +1 -1
- package/dist/data-plane/bsync/index.js +22 -0
- package/dist/data-plane/bsync/index.js.map +1 -1
- package/dist/data-plane/server/db/migrations/20251120T004738098Z-update-actor-age-assurance-v2.d.ts +4 -0
- package/dist/data-plane/server/db/migrations/20251120T004738098Z-update-actor-age-assurance-v2.d.ts.map +1 -0
- package/dist/data-plane/server/db/migrations/20251120T004738098Z-update-actor-age-assurance-v2.js +30 -0
- package/dist/data-plane/server/db/migrations/20251120T004738098Z-update-actor-age-assurance-v2.js.map +1 -0
- package/dist/data-plane/server/db/migrations/index.d.ts +1 -0
- package/dist/data-plane/server/db/migrations/index.d.ts.map +1 -1
- package/dist/data-plane/server/db/migrations/index.js +2 -1
- package/dist/data-plane/server/db/migrations/index.js.map +1 -1
- package/dist/data-plane/server/db/pagination.d.ts +3 -3
- package/dist/data-plane/server/db/tables/actor.d.ts +3 -0
- package/dist/data-plane/server/db/tables/actor.d.ts.map +1 -1
- package/dist/data-plane/server/db/tables/actor.js.map +1 -1
- package/dist/data-plane/server/routes/profile.d.ts.map +1 -1
- package/dist/data-plane/server/routes/profile.js +13 -1
- package/dist/data-plane/server/routes/profile.js.map +1 -1
- package/dist/hydration/actor.js +1 -1
- package/dist/hydration/actor.js.map +1 -1
- package/dist/hydration/hydrator.js +1 -1
- package/dist/hydration/hydrator.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -1
- package/dist/kws.d.ts +35 -0
- package/dist/kws.d.ts.map +1 -1
- package/dist/kws.js +54 -0
- package/dist/kws.js.map +1 -1
- package/dist/lexicon/index.d.ts +19 -0
- package/dist/lexicon/index.d.ts.map +1 -1
- package/dist/lexicon/index.js +48 -1
- package/dist/lexicon/index.js.map +1 -1
- package/dist/lexicon/lexicons.d.ts +664 -0
- package/dist/lexicon/lexicons.d.ts.map +1 -1
- package/dist/lexicon/lexicons.js +354 -0
- package/dist/lexicon/lexicons.js.map +1 -1
- package/dist/lexicon/types/app/bsky/contact/defs.d.ts +24 -0
- package/dist/lexicon/types/app/bsky/contact/defs.d.ts.map +1 -0
- package/dist/lexicon/types/app/bsky/contact/defs.js +25 -0
- package/dist/lexicon/types/app/bsky/contact/defs.js.map +1 -0
- package/dist/lexicon/types/app/bsky/contact/dismissMatch.d.ts +25 -0
- package/dist/lexicon/types/app/bsky/contact/dismissMatch.d.ts.map +1 -0
- package/dist/lexicon/types/app/bsky/contact/dismissMatch.js +7 -0
- package/dist/lexicon/types/app/bsky/contact/dismissMatch.js.map +1 -0
- package/dist/lexicon/types/app/bsky/contact/getMatches.d.ts +25 -0
- package/dist/lexicon/types/app/bsky/contact/getMatches.d.ts.map +1 -0
- package/dist/lexicon/types/app/bsky/contact/getMatches.js +7 -0
- package/dist/lexicon/types/app/bsky/contact/getMatches.js.map +1 -0
- package/dist/lexicon/types/app/bsky/contact/getSyncStatus.d.ts +21 -0
- package/dist/lexicon/types/app/bsky/contact/getSyncStatus.d.ts.map +1 -0
- package/dist/lexicon/types/app/bsky/contact/getSyncStatus.js +7 -0
- package/dist/lexicon/types/app/bsky/contact/getSyncStatus.js.map +1 -0
- package/dist/lexicon/types/app/bsky/contact/importContacts.d.ts +30 -0
- package/dist/lexicon/types/app/bsky/contact/importContacts.d.ts.map +1 -0
- package/dist/lexicon/types/app/bsky/contact/importContacts.js +7 -0
- package/dist/lexicon/types/app/bsky/contact/importContacts.js.map +1 -0
- package/dist/lexicon/types/app/bsky/contact/removeData.d.ts +23 -0
- package/dist/lexicon/types/app/bsky/contact/removeData.d.ts.map +1 -0
- package/dist/lexicon/types/app/bsky/contact/removeData.js +7 -0
- package/dist/lexicon/types/app/bsky/contact/removeData.js.map +1 -0
- package/dist/lexicon/types/app/bsky/contact/startPhoneVerification.d.ts +25 -0
- package/dist/lexicon/types/app/bsky/contact/startPhoneVerification.d.ts.map +1 -0
- package/dist/lexicon/types/app/bsky/contact/startPhoneVerification.js +7 -0
- package/dist/lexicon/types/app/bsky/contact/startPhoneVerification.js.map +1 -0
- package/dist/lexicon/types/app/bsky/contact/verifyPhone.d.ts +29 -0
- package/dist/lexicon/types/app/bsky/contact/verifyPhone.d.ts.map +1 -0
- package/dist/lexicon/types/app/bsky/contact/verifyPhone.js +7 -0
- package/dist/lexicon/types/app/bsky/contact/verifyPhone.js.map +1 -0
- package/dist/lexicon/types/app/bsky/graph/defs.d.ts +8 -0
- package/dist/lexicon/types/app/bsky/graph/defs.d.ts.map +1 -1
- package/dist/lexicon/types/app/bsky/graph/defs.js.map +1 -1
- package/dist/logger.d.ts +1 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +2 -1
- package/dist/logger.js.map +1 -1
- package/dist/proto/bsky_pb.d.ts +4 -0
- package/dist/proto/bsky_pb.d.ts.map +1 -1
- package/dist/proto/bsky_pb.js +10 -0
- package/dist/proto/bsky_pb.js.map +1 -1
- package/dist/proto/rolodex_connect.d.ts +83 -0
- package/dist/proto/rolodex_connect.d.ts.map +1 -0
- package/dist/proto/rolodex_connect.js +90 -0
- package/dist/proto/rolodex_connect.js.map +1 -0
- package/dist/proto/rolodex_pb.d.ts +363 -0
- package/dist/proto/rolodex_pb.d.ts.map +1 -0
- package/dist/proto/rolodex_pb.js +1032 -0
- package/dist/proto/rolodex_pb.js.map +1 -0
- package/dist/rolodex.d.ts +9 -0
- package/dist/rolodex.d.ts.map +1 -0
- package/dist/rolodex.js +25 -0
- package/dist/rolodex.js.map +1 -0
- package/dist/stash.d.ts +1 -0
- package/dist/stash.d.ts.map +1 -1
- package/dist/stash.js +1 -0
- package/dist/stash.js.map +1 -1
- package/dist/util/uris.d.ts +2 -2
- package/dist/util/uris.d.ts.map +1 -1
- package/package.json +16 -15
- package/proto/bsky.proto +1 -0
- package/proto/rolodex.proto +116 -0
- package/src/api/age-assurance/const.ts +142 -0
- package/src/api/age-assurance/index.ts +34 -0
- package/src/api/age-assurance/kws/age-verified.ts +75 -0
- package/src/api/age-assurance/kws/const.ts +33 -0
- package/src/api/age-assurance/kws/external-payload.test.ts +72 -0
- package/src/api/age-assurance/kws/external-payload.ts +149 -0
- package/src/api/age-assurance/redirects/kws-age-verified.ts +107 -0
- package/src/api/age-assurance/stash.ts +22 -0
- package/src/api/age-assurance/types.ts +10 -0
- package/src/api/age-assurance/util.ts +66 -0
- package/src/api/age-assurance/webhooks/kws-age-verified.ts +75 -0
- package/src/api/app/bsky/ageassurance/begin.ts +167 -0
- package/src/api/app/bsky/ageassurance/getConfig.ts +15 -0
- package/src/api/app/bsky/ageassurance/getState.ts +53 -0
- package/src/api/app/bsky/contact/dismissMatch.ts +24 -0
- package/src/api/app/bsky/contact/getMatches.ts +111 -0
- package/src/api/app/bsky/contact/getSyncStatus.ts +35 -0
- package/src/api/app/bsky/contact/importContacts.ts +118 -0
- package/src/api/app/bsky/contact/removeData.ts +23 -0
- package/src/api/app/bsky/contact/startPhoneVerification.ts +24 -0
- package/src/api/app/bsky/contact/util.ts +13 -0
- package/src/api/app/bsky/contact/verifyPhone.ts +27 -0
- package/src/api/app/bsky/graph/getRelationships.ts +4 -0
- package/src/api/external.ts +2 -0
- package/src/api/index.ts +20 -0
- package/src/api/kws/api.ts +55 -34
- package/src/api/kws/index.ts +7 -1
- package/src/api/kws/webhook.ts +57 -34
- package/src/config.ts +53 -2
- package/src/context.ts +6 -0
- package/src/data-plane/bsync/index.ts +31 -0
- package/src/data-plane/server/db/migrations/20251120T004738098Z-update-actor-age-assurance-v2.ts +28 -0
- package/src/data-plane/server/db/migrations/index.ts +1 -0
- package/src/data-plane/server/db/tables/actor.ts +3 -0
- package/src/data-plane/server/routes/profile.ts +12 -1
- package/src/hydration/actor.ts +1 -1
- package/src/hydration/hydrator.ts +1 -1
- package/src/index.ts +13 -0
- package/src/kws.ts +81 -0
- package/src/lexicon/index.ts +101 -0
- package/src/lexicon/lexicons.ts +375 -0
- package/src/lexicon/types/app/bsky/contact/defs.ts +52 -0
- package/src/lexicon/types/app/bsky/contact/dismissMatch.ts +43 -0
- package/src/lexicon/types/app/bsky/contact/getMatches.ts +43 -0
- package/src/lexicon/types/app/bsky/contact/getSyncStatus.ts +39 -0
- package/src/lexicon/types/app/bsky/contact/importContacts.ts +49 -0
- package/src/lexicon/types/app/bsky/contact/removeData.ts +40 -0
- package/src/lexicon/types/app/bsky/contact/startPhoneVerification.ts +43 -0
- package/src/lexicon/types/app/bsky/contact/verifyPhone.ts +48 -0
- package/src/lexicon/types/app/bsky/graph/defs.ts +8 -0
- package/src/logger.ts +2 -0
- package/src/proto/bsky_pb.ts +6 -0
- package/src/proto/rolodex_connect.ts +89 -0
- package/src/proto/rolodex_pb.ts +746 -0
- package/src/rolodex.ts +42 -0
- package/src/stash.ts +3 -0
- package/tests/views/__snapshots__/profile.test.ts.snap +103 -0
- package/tests/views/age-assurance-v2.test.ts +745 -0
- package/tests/views/age-assurance.test.ts +2 -0
- package/tests/views/profile.test.ts +39 -0
- package/tsconfig.build.tsbuildinfo +1 -1
- package/tsconfig.tests.tsbuildinfo +1 -1
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import crypto from 'node:crypto'
|
|
2
|
+
import { isEmailValid } from '@hapi/address'
|
|
3
|
+
import { isDisposableEmail } from 'disposable-email-domains-js'
|
|
4
|
+
import { getAgeAssuranceRegionConfig } from '@atproto/api'
|
|
5
|
+
import {
|
|
6
|
+
InvalidRequestError,
|
|
7
|
+
MethodNotImplementedError,
|
|
8
|
+
} from '@atproto/xrpc-server'
|
|
9
|
+
import { AppContext } from '../../../../context'
|
|
10
|
+
import { Server } from '../../../../lexicon'
|
|
11
|
+
import { InputSchema } from '../../../../lexicon/types/app/bsky/ageassurance/begin'
|
|
12
|
+
import { httpLogger as log } from '../../../../logger'
|
|
13
|
+
import { ActorInfo } from '../../../../proto/bsky_pb'
|
|
14
|
+
import { AGE_ASSURANCE_CONFIG } from '../../../age-assurance/const'
|
|
15
|
+
import {
|
|
16
|
+
KWS_SUPPORTED_LANGUAGES,
|
|
17
|
+
KWS_V2_COUNTRIES,
|
|
18
|
+
} from '../../../age-assurance/kws/const'
|
|
19
|
+
import {
|
|
20
|
+
KWSExternalPayloadTooLargeError,
|
|
21
|
+
KWSExternalPayloadVersion,
|
|
22
|
+
serializeKWSExternalPayloadV2,
|
|
23
|
+
} from '../../../age-assurance/kws/external-payload'
|
|
24
|
+
import { createEvent } from '../../../age-assurance/stash'
|
|
25
|
+
import { createLocationString } from '../../../age-assurance/util'
|
|
26
|
+
import { getClientUa } from '../../../kws/util'
|
|
27
|
+
|
|
28
|
+
export default function (server: Server, ctx: AppContext) {
|
|
29
|
+
server.app.bsky.ageassurance.begin({
|
|
30
|
+
auth: ctx.authVerifier.standard,
|
|
31
|
+
handler: async ({ auth, input, req }) => {
|
|
32
|
+
if (!ctx.kwsClient) {
|
|
33
|
+
throw new MethodNotImplementedError(
|
|
34
|
+
'This service is not configured to support age assurance.',
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const actorDid = auth.credentials.iss
|
|
39
|
+
const actorInfo = await getAgeVerificationState(ctx, actorDid)
|
|
40
|
+
|
|
41
|
+
if (actorInfo?.ageAssuranceStatus) {
|
|
42
|
+
if (
|
|
43
|
+
actorInfo.ageAssuranceStatus.status !== 'unknown' &&
|
|
44
|
+
actorInfo.ageAssuranceStatus.status !== 'pending'
|
|
45
|
+
) {
|
|
46
|
+
throw new InvalidRequestError(
|
|
47
|
+
`Cannot initiate age assurance flow from current state: ${actorInfo.ageAssuranceStatus.status}`,
|
|
48
|
+
'InvalidInitiation',
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const attemptId = crypto.randomUUID()
|
|
54
|
+
const { email, language, countryCode, regionCode } = validateInput(
|
|
55
|
+
input.body,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
let externalPayload: string
|
|
59
|
+
try {
|
|
60
|
+
externalPayload = serializeKWSExternalPayloadV2({
|
|
61
|
+
version: KWSExternalPayloadVersion.V2,
|
|
62
|
+
actorDid,
|
|
63
|
+
attemptId,
|
|
64
|
+
countryCode,
|
|
65
|
+
regionCode,
|
|
66
|
+
})
|
|
67
|
+
} catch (err) {
|
|
68
|
+
if (err instanceof KWSExternalPayloadTooLargeError) {
|
|
69
|
+
log.error({ err, actorDid }, err.message)
|
|
70
|
+
throw new InvalidRequestError(
|
|
71
|
+
'Age Assurance flow failed because DID is too long',
|
|
72
|
+
'DidTooLong',
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
throw err
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/*
|
|
79
|
+
* Determine if age assurance config exists for this region. The calling
|
|
80
|
+
* application should already have checked for this, so this is just a
|
|
81
|
+
* safeguard.
|
|
82
|
+
*/
|
|
83
|
+
const region = getAgeAssuranceRegionConfig(AGE_ASSURANCE_CONFIG, {
|
|
84
|
+
countryCode,
|
|
85
|
+
regionCode,
|
|
86
|
+
})
|
|
87
|
+
if (!region) {
|
|
88
|
+
const message = 'Age Assurance is not required in this region'
|
|
89
|
+
log.error({ actorDid, countryCode, regionCode }, message)
|
|
90
|
+
throw new InvalidRequestError(message, 'RegionNotSupported')
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const location = createLocationString(countryCode, regionCode)
|
|
94
|
+
|
|
95
|
+
if (KWS_V2_COUNTRIES.has(region.countryCode)) {
|
|
96
|
+
// `age-verified` flow
|
|
97
|
+
await ctx.kwsClient.sendAgeVerifiedFlowEmail({
|
|
98
|
+
location,
|
|
99
|
+
email,
|
|
100
|
+
externalPayload,
|
|
101
|
+
language,
|
|
102
|
+
})
|
|
103
|
+
} else {
|
|
104
|
+
// `adult-verified` flow is what we've been using prior to `age-verified`
|
|
105
|
+
await ctx.kwsClient.sendAdultVerifiedFlowEmail({
|
|
106
|
+
location,
|
|
107
|
+
email,
|
|
108
|
+
externalPayload,
|
|
109
|
+
language,
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const event = await createEvent(ctx, actorDid, {
|
|
114
|
+
attemptId,
|
|
115
|
+
email,
|
|
116
|
+
// Assumes `app.set('trust proxy', ...)` configured with `true` or specific values.
|
|
117
|
+
initIp: req.ip,
|
|
118
|
+
initUa: getClientUa(req),
|
|
119
|
+
status: 'pending',
|
|
120
|
+
access: 'unknown',
|
|
121
|
+
countryCode,
|
|
122
|
+
regionCode,
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
encoding: 'application/json',
|
|
127
|
+
body: {
|
|
128
|
+
lastInitiatedAt: event.createdAt,
|
|
129
|
+
status: 'pending',
|
|
130
|
+
access: 'unknown',
|
|
131
|
+
},
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function validateInput({ email, language, ...rest }: InputSchema): InputSchema {
|
|
138
|
+
if (!isEmailValid(email) || isDisposableEmail(email)) {
|
|
139
|
+
throw new InvalidRequestError(
|
|
140
|
+
'This email address is not supported, please use a different email.',
|
|
141
|
+
'InvalidEmail',
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
email,
|
|
147
|
+
language: KWS_SUPPORTED_LANGUAGES.has(language) ? language : 'en',
|
|
148
|
+
...rest,
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async function getAgeVerificationState(
|
|
153
|
+
ctx: AppContext,
|
|
154
|
+
actorDid: string,
|
|
155
|
+
): Promise<ActorInfo | undefined> {
|
|
156
|
+
try {
|
|
157
|
+
const res = await ctx.dataplane.getActors({
|
|
158
|
+
dids: [actorDid],
|
|
159
|
+
returnAgeAssuranceForDids: [actorDid],
|
|
160
|
+
skipCacheForDids: [actorDid],
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
return res.actors[0]
|
|
164
|
+
} catch (err) {
|
|
165
|
+
return undefined
|
|
166
|
+
}
|
|
167
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AGE_ASSURANCE_CONFIG } from '../../../../api/age-assurance/const'
|
|
2
|
+
import { AppContext } from '../../../../context'
|
|
3
|
+
import { Server } from '../../../../lexicon'
|
|
4
|
+
|
|
5
|
+
export default function (server: Server, ctx: AppContext) {
|
|
6
|
+
server.app.bsky.ageassurance.getConfig({
|
|
7
|
+
auth: ctx.authVerifier.standardOptional,
|
|
8
|
+
handler: async () => {
|
|
9
|
+
return {
|
|
10
|
+
encoding: 'application/json',
|
|
11
|
+
body: AGE_ASSURANCE_CONFIG,
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
})
|
|
15
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { UpstreamFailureError } from '@atproto/xrpc-server'
|
|
2
|
+
import { AppContext } from '../../../../context'
|
|
3
|
+
import { Server } from '../../../../lexicon'
|
|
4
|
+
import { ActorInfo } from '../../../../proto/bsky_pb'
|
|
5
|
+
|
|
6
|
+
export default function (server: Server, ctx: AppContext) {
|
|
7
|
+
server.app.bsky.ageassurance.getState({
|
|
8
|
+
auth: ctx.authVerifier.standard,
|
|
9
|
+
handler: async ({ auth }) => {
|
|
10
|
+
const viewer = auth.credentials.iss
|
|
11
|
+
const actor = await getActorInfo(ctx, viewer)
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
encoding: 'application/json',
|
|
15
|
+
body: {
|
|
16
|
+
state: {
|
|
17
|
+
lastInitiatedAt:
|
|
18
|
+
actor.ageAssuranceStatus?.lastInitiatedAt
|
|
19
|
+
?.toDate()
|
|
20
|
+
.toISOString() || undefined,
|
|
21
|
+
status: actor.ageAssuranceStatus?.status || 'unknown',
|
|
22
|
+
access: actor.ageAssuranceStatus?.access || 'unknown',
|
|
23
|
+
},
|
|
24
|
+
metadata: {
|
|
25
|
+
accountCreatedAt:
|
|
26
|
+
actor.createdAt?.toDate().toISOString() || undefined,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const getActorInfo = async (
|
|
35
|
+
ctx: AppContext,
|
|
36
|
+
actorDid: string,
|
|
37
|
+
): Promise<ActorInfo> => {
|
|
38
|
+
try {
|
|
39
|
+
const res = await ctx.dataplane.getActors({
|
|
40
|
+
dids: [actorDid],
|
|
41
|
+
returnAgeAssuranceForDids: [actorDid],
|
|
42
|
+
skipCacheForDids: [actorDid],
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
return res.actors[0]
|
|
46
|
+
} catch (err) {
|
|
47
|
+
throw new UpstreamFailureError(
|
|
48
|
+
'Cannot get current age assurance state',
|
|
49
|
+
'GetAgeAssuranceStateFailed',
|
|
50
|
+
{ cause: err },
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { AppContext } from '../../../../context'
|
|
2
|
+
import { Server } from '../../../../lexicon'
|
|
3
|
+
import { assertRolodexOrThrowUnimplemented } from './util'
|
|
4
|
+
|
|
5
|
+
export default function (server: Server, ctx: AppContext) {
|
|
6
|
+
server.app.bsky.contact.dismissMatch({
|
|
7
|
+
auth: ctx.authVerifier.standard,
|
|
8
|
+
handler: async ({ input, auth }) => {
|
|
9
|
+
assertRolodexOrThrowUnimplemented(ctx)
|
|
10
|
+
|
|
11
|
+
const actor = auth.credentials.iss
|
|
12
|
+
// TODO: Error handling.
|
|
13
|
+
await ctx.rolodexClient.dismissMatch({
|
|
14
|
+
actor,
|
|
15
|
+
subject: input.body.subject,
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
encoding: 'application/json',
|
|
20
|
+
body: {},
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
})
|
|
24
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { mapDefined } from '@atproto/common'
|
|
2
|
+
import { AppContext } from '../../../../context'
|
|
3
|
+
import {
|
|
4
|
+
HydrateCtx,
|
|
5
|
+
HydrationState,
|
|
6
|
+
Hydrator,
|
|
7
|
+
} from '../../../../hydration/hydrator'
|
|
8
|
+
import { Server } from '../../../../lexicon'
|
|
9
|
+
import { QueryParams } from '../../../../lexicon/types/app/bsky/contact/getMatches'
|
|
10
|
+
import {
|
|
11
|
+
HydrationFnInput,
|
|
12
|
+
SkeletonFnInput,
|
|
13
|
+
createPipeline,
|
|
14
|
+
} from '../../../../pipeline'
|
|
15
|
+
import { RolodexClient } from '../../../../rolodex'
|
|
16
|
+
import { Views } from '../../../../views'
|
|
17
|
+
import { assertRolodexOrThrowUnimplemented } from './util'
|
|
18
|
+
|
|
19
|
+
export default function (server: Server, ctx: AppContext) {
|
|
20
|
+
const getMatches = createPipeline(skeleton, hydration, noBlocks, presentation)
|
|
21
|
+
server.app.bsky.contact.getMatches({
|
|
22
|
+
auth: ctx.authVerifier.standard,
|
|
23
|
+
handler: async ({ params, auth, req }) => {
|
|
24
|
+
assertRolodexOrThrowUnimplemented(ctx)
|
|
25
|
+
|
|
26
|
+
const viewer = auth.credentials.iss
|
|
27
|
+
const labelers = ctx.reqLabelers(req)
|
|
28
|
+
const hydrateCtx = await ctx.hydrator.createContext({
|
|
29
|
+
labelers,
|
|
30
|
+
viewer,
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
const result = await getMatches(
|
|
34
|
+
{ ...params, hydrateCtx: hydrateCtx.copy({ viewer }) },
|
|
35
|
+
ctx,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
encoding: 'application/json',
|
|
40
|
+
body: result,
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const skeleton = async (
|
|
47
|
+
input: SkeletonFnInput<Context, Params>,
|
|
48
|
+
): Promise<SkeletonState> => {
|
|
49
|
+
const { params, ctx } = input
|
|
50
|
+
const actor = params.hydrateCtx.viewer
|
|
51
|
+
// TODO: Error handling.
|
|
52
|
+
const { cursor, subjects } = await ctx.rolodexClient.getMatches({
|
|
53
|
+
actor: params.hydrateCtx.viewer,
|
|
54
|
+
limit: params.limit,
|
|
55
|
+
cursor: params.cursor,
|
|
56
|
+
})
|
|
57
|
+
return {
|
|
58
|
+
actor,
|
|
59
|
+
subjects,
|
|
60
|
+
cursor: cursor || undefined,
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const hydration = async (
|
|
65
|
+
input: HydrationFnInput<Context, Params, SkeletonState>,
|
|
66
|
+
) => {
|
|
67
|
+
const { ctx, params, skeleton } = input
|
|
68
|
+
const { subjects } = skeleton
|
|
69
|
+
return ctx.hydrator.hydrateProfiles(subjects, params.hydrateCtx)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const noBlocks = (inputs: {
|
|
73
|
+
ctx: Context
|
|
74
|
+
skeleton: SkeletonState
|
|
75
|
+
hydration: HydrationState
|
|
76
|
+
}) => {
|
|
77
|
+
const { ctx, skeleton, hydration } = inputs
|
|
78
|
+
skeleton.subjects = skeleton.subjects.filter((subject) => {
|
|
79
|
+
return !ctx.views.viewerBlockExists(subject, hydration)
|
|
80
|
+
})
|
|
81
|
+
return skeleton
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const presentation = (input: {
|
|
85
|
+
ctx: Context
|
|
86
|
+
params: Params
|
|
87
|
+
skeleton: SkeletonState
|
|
88
|
+
hydration: HydrationState
|
|
89
|
+
}) => {
|
|
90
|
+
const { ctx, skeleton, hydration } = input
|
|
91
|
+
const matches = mapDefined(skeleton.subjects, (did) =>
|
|
92
|
+
ctx.views.profile(did, hydration),
|
|
93
|
+
)
|
|
94
|
+
return { matches }
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
type Context = {
|
|
98
|
+
hydrator: Hydrator
|
|
99
|
+
rolodexClient: RolodexClient
|
|
100
|
+
views: Views
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
type Params = QueryParams & {
|
|
104
|
+
hydrateCtx: HydrateCtx & { viewer: string }
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
type SkeletonState = {
|
|
108
|
+
actor: string
|
|
109
|
+
subjects: string[]
|
|
110
|
+
cursor?: string
|
|
111
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { AppContext } from '../../../../context'
|
|
2
|
+
import { Server } from '../../../../lexicon'
|
|
3
|
+
import { SyncStatus } from '../../../../lexicon/types/app/bsky/contact/defs'
|
|
4
|
+
import { assertRolodexOrThrowUnimplemented } from './util'
|
|
5
|
+
|
|
6
|
+
export default function (server: Server, ctx: AppContext) {
|
|
7
|
+
server.app.bsky.contact.getSyncStatus({
|
|
8
|
+
auth: ctx.authVerifier.standard,
|
|
9
|
+
handler: async ({ auth }) => {
|
|
10
|
+
assertRolodexOrThrowUnimplemented(ctx)
|
|
11
|
+
|
|
12
|
+
const actor = auth.credentials.iss
|
|
13
|
+
// TODO: Error handling.
|
|
14
|
+
const res = await ctx.rolodexClient.getSyncStatus({
|
|
15
|
+
actor,
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
let syncStatus: SyncStatus | undefined
|
|
19
|
+
if (res.status && res.status.syncedAt) {
|
|
20
|
+
const syncedAt = res.status?.syncedAt?.toDate().toISOString()
|
|
21
|
+
syncStatus = {
|
|
22
|
+
matchesCount: res.status.matchesCount,
|
|
23
|
+
syncedAt,
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
encoding: 'application/json',
|
|
29
|
+
body: {
|
|
30
|
+
syncStatus,
|
|
31
|
+
},
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
})
|
|
35
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { mapDefined } from '@atproto/common'
|
|
2
|
+
import { AppContext } from '../../../../context'
|
|
3
|
+
import {
|
|
4
|
+
HydrateCtx,
|
|
5
|
+
HydrationState,
|
|
6
|
+
Hydrator,
|
|
7
|
+
} from '../../../../hydration/hydrator'
|
|
8
|
+
import { Server } from '../../../../lexicon'
|
|
9
|
+
import { MatchAndContactIndex } from '../../../../lexicon/types/app/bsky/contact/defs'
|
|
10
|
+
import { InputSchema } from '../../../../lexicon/types/app/bsky/contact/importContacts'
|
|
11
|
+
import {
|
|
12
|
+
HydrationFnInput,
|
|
13
|
+
SkeletonFnInput,
|
|
14
|
+
createPipeline,
|
|
15
|
+
noRules,
|
|
16
|
+
} from '../../../../pipeline'
|
|
17
|
+
import { ImportContactsMatch } from '../../../../proto/rolodex_pb'
|
|
18
|
+
import { RolodexClient } from '../../../../rolodex'
|
|
19
|
+
import { Views } from '../../../../views'
|
|
20
|
+
import { assertRolodexOrThrowUnimplemented } from './util'
|
|
21
|
+
|
|
22
|
+
export default function (server: Server, ctx: AppContext) {
|
|
23
|
+
const importContacts = createPipeline(
|
|
24
|
+
skeleton,
|
|
25
|
+
hydration,
|
|
26
|
+
noRules, //
|
|
27
|
+
presentation,
|
|
28
|
+
)
|
|
29
|
+
server.app.bsky.contact.importContacts({
|
|
30
|
+
auth: ctx.authVerifier.standard,
|
|
31
|
+
handler: async ({ input, auth, req }) => {
|
|
32
|
+
assertRolodexOrThrowUnimplemented(ctx)
|
|
33
|
+
|
|
34
|
+
const viewer = auth.credentials.iss
|
|
35
|
+
const labelers = ctx.reqLabelers(req)
|
|
36
|
+
const hydrateCtx = await ctx.hydrator.createContext({
|
|
37
|
+
labelers,
|
|
38
|
+
viewer,
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
const result = await importContacts(
|
|
42
|
+
{ ...input.body, hydrateCtx: hydrateCtx.copy({ viewer }) },
|
|
43
|
+
ctx,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
encoding: 'application/json',
|
|
48
|
+
body: result,
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const skeleton = async (
|
|
55
|
+
input: SkeletonFnInput<Context, Params>,
|
|
56
|
+
): Promise<SkeletonState> => {
|
|
57
|
+
const { params, ctx } = input
|
|
58
|
+
const actor = params.hydrateCtx.viewer
|
|
59
|
+
// TODO: Error handling.
|
|
60
|
+
const { matches } = await ctx.rolodexClient.importContacts({
|
|
61
|
+
actor: params.hydrateCtx.viewer,
|
|
62
|
+
contacts: params.contacts,
|
|
63
|
+
token: params.token,
|
|
64
|
+
})
|
|
65
|
+
return {
|
|
66
|
+
actor,
|
|
67
|
+
matches,
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const hydration = async (
|
|
72
|
+
input: HydrationFnInput<Context, Params, SkeletonState>,
|
|
73
|
+
) => {
|
|
74
|
+
const { ctx, params, skeleton } = input
|
|
75
|
+
const { matches } = skeleton
|
|
76
|
+
const subjects = matches.map((m) => m.subject)
|
|
77
|
+
return ctx.hydrator.hydrateProfiles(subjects, params.hydrateCtx)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const presentation = (input: {
|
|
81
|
+
ctx: Context
|
|
82
|
+
params: Params
|
|
83
|
+
skeleton: SkeletonState
|
|
84
|
+
hydration: HydrationState
|
|
85
|
+
}) => {
|
|
86
|
+
const { ctx, skeleton, hydration } = input
|
|
87
|
+
const matchesAndContactIndexes = mapDefined(
|
|
88
|
+
skeleton.matches,
|
|
89
|
+
({ subject, inputIndex }): MatchAndContactIndex | undefined => {
|
|
90
|
+
const profile = ctx.views.profile(subject, hydration)
|
|
91
|
+
|
|
92
|
+
if (!profile) {
|
|
93
|
+
return undefined
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
contactIndex: inputIndex,
|
|
98
|
+
match: profile,
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
)
|
|
102
|
+
return { matchesAndContactIndexes }
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
type Context = {
|
|
106
|
+
hydrator: Hydrator
|
|
107
|
+
rolodexClient: RolodexClient
|
|
108
|
+
views: Views
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
type Params = InputSchema & {
|
|
112
|
+
hydrateCtx: HydrateCtx & { viewer: string }
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
type SkeletonState = {
|
|
116
|
+
actor: string
|
|
117
|
+
matches: ImportContactsMatch[]
|
|
118
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { AppContext } from '../../../../context'
|
|
2
|
+
import { Server } from '../../../../lexicon'
|
|
3
|
+
import { assertRolodexOrThrowUnimplemented } from './util'
|
|
4
|
+
|
|
5
|
+
export default function (server: Server, ctx: AppContext) {
|
|
6
|
+
server.app.bsky.contact.removeData({
|
|
7
|
+
auth: ctx.authVerifier.standard,
|
|
8
|
+
handler: async ({ auth }) => {
|
|
9
|
+
assertRolodexOrThrowUnimplemented(ctx)
|
|
10
|
+
|
|
11
|
+
const actor = auth.credentials.iss
|
|
12
|
+
// TODO: Error handling.
|
|
13
|
+
await ctx.rolodexClient.removeData({
|
|
14
|
+
actor,
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
encoding: 'application/json',
|
|
19
|
+
body: {},
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
})
|
|
23
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { AppContext } from '../../../../context'
|
|
2
|
+
import { Server } from '../../../../lexicon'
|
|
3
|
+
import { assertRolodexOrThrowUnimplemented } from './util'
|
|
4
|
+
|
|
5
|
+
export default function (server: Server, ctx: AppContext) {
|
|
6
|
+
server.app.bsky.contact.startPhoneVerification({
|
|
7
|
+
auth: ctx.authVerifier.standard,
|
|
8
|
+
handler: async ({ auth, input }) => {
|
|
9
|
+
assertRolodexOrThrowUnimplemented(ctx)
|
|
10
|
+
|
|
11
|
+
const actor = auth.credentials.iss
|
|
12
|
+
// TODO: Error handling.
|
|
13
|
+
await ctx.rolodexClient.startPhoneVerification({
|
|
14
|
+
actor,
|
|
15
|
+
phone: input.body.phone,
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
encoding: 'application/json',
|
|
20
|
+
body: {},
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
})
|
|
24
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { MethodNotImplementedError } from '@atproto/xrpc-server'
|
|
2
|
+
import { AppContext } from '../../../..'
|
|
3
|
+
import { RolodexClient } from '../../../../rolodex'
|
|
4
|
+
|
|
5
|
+
export function assertRolodexOrThrowUnimplemented(
|
|
6
|
+
ctx: AppContext,
|
|
7
|
+
): asserts ctx is AppContext & { rolodexClient: RolodexClient } {
|
|
8
|
+
if (!ctx.rolodexClient) {
|
|
9
|
+
throw new MethodNotImplementedError(
|
|
10
|
+
'This service is not configured to support contact imports.',
|
|
11
|
+
)
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { AppContext } from '../../../../context'
|
|
2
|
+
import { Server } from '../../../../lexicon'
|
|
3
|
+
import { assertRolodexOrThrowUnimplemented } from './util'
|
|
4
|
+
|
|
5
|
+
export default function (server: Server, ctx: AppContext) {
|
|
6
|
+
server.app.bsky.contact.verifyPhone({
|
|
7
|
+
auth: ctx.authVerifier.standard,
|
|
8
|
+
handler: async ({ auth, input }) => {
|
|
9
|
+
assertRolodexOrThrowUnimplemented(ctx)
|
|
10
|
+
|
|
11
|
+
const actor = auth.credentials.iss
|
|
12
|
+
// TODO: Error handling.
|
|
13
|
+
const res = await ctx.rolodexClient.verifyPhone({
|
|
14
|
+
actor,
|
|
15
|
+
verificationCode: input.body.code,
|
|
16
|
+
phone: input.body.phone,
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
encoding: 'application/json',
|
|
21
|
+
body: {
|
|
22
|
+
token: res.token,
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
})
|
|
27
|
+
}
|
|
@@ -26,6 +26,10 @@ export default function (server: Server, ctx: AppContext) {
|
|
|
26
26
|
did,
|
|
27
27
|
following: subject.following,
|
|
28
28
|
followedBy: subject.followedBy,
|
|
29
|
+
blocking: subject.blocking,
|
|
30
|
+
blockedBy: subject.blockedBy,
|
|
31
|
+
blockingByList: subject.blockingByList,
|
|
32
|
+
blockedByList: subject.blockedByList,
|
|
29
33
|
}
|
|
30
34
|
: {
|
|
31
35
|
$type: 'app.bsky.graph.defs#notFoundActor',
|
package/src/api/external.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Router } from 'express'
|
|
2
2
|
import { AppContext } from '../context'
|
|
3
|
+
import * as aaApi from './age-assurance'
|
|
3
4
|
import * as kwsApi from './kws'
|
|
4
5
|
|
|
5
6
|
export const createRouter = (ctx: AppContext): Router => {
|
|
@@ -7,6 +8,7 @@ export const createRouter = (ctx: AppContext): Router => {
|
|
|
7
8
|
|
|
8
9
|
if (ctx.kwsClient) {
|
|
9
10
|
router.use('/kws', kwsApi.createRouter(ctx))
|
|
11
|
+
router.use(aaApi.createRouter(ctx))
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
return router
|
package/src/api/index.ts
CHANGED
|
@@ -5,9 +5,19 @@ import getProfiles from './app/bsky/actor/getProfiles'
|
|
|
5
5
|
import getSuggestions from './app/bsky/actor/getSuggestions'
|
|
6
6
|
import searchActors from './app/bsky/actor/searchActors'
|
|
7
7
|
import searchActorsTypeahead from './app/bsky/actor/searchActorsTypeahead'
|
|
8
|
+
import aaBegin from './app/bsky/ageassurance/begin'
|
|
9
|
+
import aaGetConfig from './app/bsky/ageassurance/getConfig'
|
|
10
|
+
import aaGetState from './app/bsky/ageassurance/getState'
|
|
8
11
|
import createBookmark from './app/bsky/bookmark/createBookmark'
|
|
9
12
|
import deleteBookmark from './app/bsky/bookmark/deleteBookmark'
|
|
10
13
|
import getBookmarks from './app/bsky/bookmark/getBookmarks'
|
|
14
|
+
import dismissMatch from './app/bsky/contact/dismissMatch'
|
|
15
|
+
import getMatches from './app/bsky/contact/getMatches'
|
|
16
|
+
import getSyncStatus from './app/bsky/contact/getSyncStatus'
|
|
17
|
+
import importContacts from './app/bsky/contact/importContacts'
|
|
18
|
+
import removeData from './app/bsky/contact/removeData'
|
|
19
|
+
import startPhoneVerification from './app/bsky/contact/startPhoneVerification'
|
|
20
|
+
import verifyPhone from './app/bsky/contact/verifyPhone'
|
|
11
21
|
import getActorFeeds from './app/bsky/feed/getActorFeeds'
|
|
12
22
|
import getActorLikes from './app/bsky/feed/getActorLikes'
|
|
13
23
|
import getAuthorFeed from './app/bsky/feed/getAuthorFeed'
|
|
@@ -91,6 +101,13 @@ export default function (server: Server, ctx: AppContext) {
|
|
|
91
101
|
createBookmark(server, ctx)
|
|
92
102
|
deleteBookmark(server, ctx)
|
|
93
103
|
getBookmarks(server, ctx)
|
|
104
|
+
dismissMatch(server, ctx)
|
|
105
|
+
getMatches(server, ctx)
|
|
106
|
+
getSyncStatus(server, ctx)
|
|
107
|
+
importContacts(server, ctx)
|
|
108
|
+
removeData(server, ctx)
|
|
109
|
+
startPhoneVerification(server, ctx)
|
|
110
|
+
verifyPhone(server, ctx)
|
|
94
111
|
getActorFeeds(server, ctx)
|
|
95
112
|
getSuggestedFeeds(server, ctx)
|
|
96
113
|
getAuthorFeed(server, ctx)
|
|
@@ -156,6 +173,9 @@ export default function (server: Server, ctx: AppContext) {
|
|
|
156
173
|
getTaggedSuggestions(server, ctx)
|
|
157
174
|
getAgeAssuranceState(server, ctx)
|
|
158
175
|
initAgeAssurance(server, ctx)
|
|
176
|
+
aaGetConfig(server, ctx)
|
|
177
|
+
aaGetState(server, ctx)
|
|
178
|
+
aaBegin(server, ctx)
|
|
159
179
|
// com.atproto
|
|
160
180
|
getSubjectStatus(server, ctx)
|
|
161
181
|
updateSubjectStatus(server, ctx)
|