@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.
Files changed (279) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/api/age-assurance/const.d.ts +11 -0
  3. package/dist/api/age-assurance/const.d.ts.map +1 -0
  4. package/dist/api/age-assurance/const.js +142 -0
  5. package/dist/api/age-assurance/const.js.map +1 -0
  6. package/dist/api/age-assurance/index.d.ts +4 -0
  7. package/dist/api/age-assurance/index.d.ts.map +1 -0
  8. package/dist/api/age-assurance/index.js +24 -0
  9. package/dist/api/age-assurance/index.js.map +1 -0
  10. package/dist/api/age-assurance/kws/age-verified.d.ts +109 -0
  11. package/dist/api/age-assurance/kws/age-verified.d.ts.map +1 -0
  12. package/dist/api/age-assurance/kws/age-verified.js +63 -0
  13. package/dist/api/age-assurance/kws/age-verified.js.map +1 -0
  14. package/dist/api/age-assurance/kws/const.d.ts +13 -0
  15. package/dist/api/age-assurance/kws/const.d.ts.map +1 -0
  16. package/dist/api/age-assurance/kws/const.js +36 -0
  17. package/dist/api/age-assurance/kws/const.js.map +1 -0
  18. package/dist/api/age-assurance/kws/external-payload.d.ts +75 -0
  19. package/dist/api/age-assurance/kws/external-payload.d.ts.map +1 -0
  20. package/dist/api/age-assurance/kws/external-payload.js +124 -0
  21. package/dist/api/age-assurance/kws/external-payload.js.map +1 -0
  22. package/dist/api/age-assurance/kws/external-payload.test.d.ts +2 -0
  23. package/dist/api/age-assurance/kws/external-payload.test.d.ts.map +1 -0
  24. package/dist/api/age-assurance/kws/external-payload.test.js +65 -0
  25. package/dist/api/age-assurance/kws/external-payload.test.js.map +1 -0
  26. package/dist/api/age-assurance/redirects/kws-age-verified.d.ts +4 -0
  27. package/dist/api/age-assurance/redirects/kws-age-verified.d.ts.map +1 -0
  28. package/dist/api/age-assurance/redirects/kws-age-verified.js +76 -0
  29. package/dist/api/age-assurance/redirects/kws-age-verified.js.map +1 -0
  30. package/dist/api/age-assurance/stash.d.ts +4 -0
  31. package/dist/api/age-assurance/stash.d.ts.map +1 -0
  32. package/dist/api/age-assurance/stash.js +19 -0
  33. package/dist/api/age-assurance/stash.js.map +1 -0
  34. package/dist/api/age-assurance/types.d.ts +10 -0
  35. package/dist/api/age-assurance/types.d.ts.map +1 -0
  36. package/dist/api/age-assurance/types.js +3 -0
  37. package/dist/api/age-assurance/types.js.map +1 -0
  38. package/dist/api/age-assurance/util.d.ts +15 -0
  39. package/dist/api/age-assurance/util.d.ts.map +1 -0
  40. package/dist/api/age-assurance/util.js +54 -0
  41. package/dist/api/age-assurance/util.js.map +1 -0
  42. package/dist/api/age-assurance/webhooks/kws-age-verified.d.ts +4 -0
  43. package/dist/api/age-assurance/webhooks/kws-age-verified.d.ts.map +1 -0
  44. package/dist/api/age-assurance/webhooks/kws-age-verified.js +63 -0
  45. package/dist/api/age-assurance/webhooks/kws-age-verified.js.map +1 -0
  46. package/dist/api/app/bsky/ageassurance/begin.d.ts +4 -0
  47. package/dist/api/app/bsky/ageassurance/begin.d.ts.map +1 -0
  48. package/dist/api/app/bsky/ageassurance/begin.js +131 -0
  49. package/dist/api/app/bsky/ageassurance/begin.js.map +1 -0
  50. package/dist/api/app/bsky/ageassurance/getConfig.d.ts +4 -0
  51. package/dist/api/app/bsky/ageassurance/getConfig.d.ts.map +1 -0
  52. package/dist/api/app/bsky/ageassurance/getConfig.js +16 -0
  53. package/dist/api/app/bsky/ageassurance/getConfig.js.map +1 -0
  54. package/dist/api/app/bsky/ageassurance/getState.d.ts +4 -0
  55. package/dist/api/app/bsky/ageassurance/getState.d.ts.map +1 -0
  56. package/dist/api/app/bsky/ageassurance/getState.js +42 -0
  57. package/dist/api/app/bsky/ageassurance/getState.js.map +1 -0
  58. package/dist/api/app/bsky/contact/dismissMatch.d.ts +4 -0
  59. package/dist/api/app/bsky/contact/dismissMatch.d.ts.map +1 -0
  60. package/dist/api/app/bsky/contact/dismissMatch.js +23 -0
  61. package/dist/api/app/bsky/contact/dismissMatch.js.map +1 -0
  62. package/dist/api/app/bsky/contact/getMatches.d.ts +4 -0
  63. package/dist/api/app/bsky/contact/getMatches.d.ts.map +1 -0
  64. package/dist/api/app/bsky/contact/getMatches.js +59 -0
  65. package/dist/api/app/bsky/contact/getMatches.js.map +1 -0
  66. package/dist/api/app/bsky/contact/getSyncStatus.d.ts +4 -0
  67. package/dist/api/app/bsky/contact/getSyncStatus.d.ts.map +1 -0
  68. package/dist/api/app/bsky/contact/getSyncStatus.js +32 -0
  69. package/dist/api/app/bsky/contact/getSyncStatus.js.map +1 -0
  70. package/dist/api/app/bsky/contact/importContacts.d.ts +4 -0
  71. package/dist/api/app/bsky/contact/importContacts.d.ts.map +1 -0
  72. package/dist/api/app/bsky/contact/importContacts.js +62 -0
  73. package/dist/api/app/bsky/contact/importContacts.js.map +1 -0
  74. package/dist/api/app/bsky/contact/removeData.d.ts +4 -0
  75. package/dist/api/app/bsky/contact/removeData.d.ts.map +1 -0
  76. package/dist/api/app/bsky/contact/removeData.js +22 -0
  77. package/dist/api/app/bsky/contact/removeData.js.map +1 -0
  78. package/dist/api/app/bsky/contact/startPhoneVerification.d.ts +4 -0
  79. package/dist/api/app/bsky/contact/startPhoneVerification.d.ts.map +1 -0
  80. package/dist/api/app/bsky/contact/startPhoneVerification.js +23 -0
  81. package/dist/api/app/bsky/contact/startPhoneVerification.js.map +1 -0
  82. package/dist/api/app/bsky/contact/util.d.ts +6 -0
  83. package/dist/api/app/bsky/contact/util.d.ts.map +1 -0
  84. package/dist/api/app/bsky/contact/util.js +10 -0
  85. package/dist/api/app/bsky/contact/util.js.map +1 -0
  86. package/dist/api/app/bsky/contact/verifyPhone.d.ts +4 -0
  87. package/dist/api/app/bsky/contact/verifyPhone.d.ts.map +1 -0
  88. package/dist/api/app/bsky/contact/verifyPhone.js +26 -0
  89. package/dist/api/app/bsky/contact/verifyPhone.js.map +1 -0
  90. package/dist/api/app/bsky/graph/getRelationships.d.ts.map +1 -1
  91. package/dist/api/app/bsky/graph/getRelationships.js +4 -0
  92. package/dist/api/app/bsky/graph/getRelationships.js.map +1 -1
  93. package/dist/api/external.d.ts.map +1 -1
  94. package/dist/api/external.js +2 -0
  95. package/dist/api/external.js.map +1 -1
  96. package/dist/api/index.d.ts.map +1 -1
  97. package/dist/api/index.js +22 -2
  98. package/dist/api/index.js.map +1 -1
  99. package/dist/api/kws/api.d.ts.map +1 -1
  100. package/dist/api/kws/api.js +44 -26
  101. package/dist/api/kws/api.js.map +1 -1
  102. package/dist/api/kws/index.d.ts.map +1 -1
  103. package/dist/api/kws/index.js +3 -1
  104. package/dist/api/kws/index.js.map +1 -1
  105. package/dist/api/kws/webhook.d.ts +3 -1
  106. package/dist/api/kws/webhook.d.ts.map +1 -1
  107. package/dist/api/kws/webhook.js +48 -20
  108. package/dist/api/kws/webhook.js.map +1 -1
  109. package/dist/config.d.ts +22 -0
  110. package/dist/config.d.ts.map +1 -1
  111. package/dist/config.js +31 -2
  112. package/dist/config.js.map +1 -1
  113. package/dist/context.d.ts +3 -0
  114. package/dist/context.d.ts.map +1 -1
  115. package/dist/context.js +3 -0
  116. package/dist/context.js.map +1 -1
  117. package/dist/data-plane/bsync/index.d.ts.map +1 -1
  118. package/dist/data-plane/bsync/index.js +22 -0
  119. package/dist/data-plane/bsync/index.js.map +1 -1
  120. package/dist/data-plane/server/db/migrations/20251120T004738098Z-update-actor-age-assurance-v2.d.ts +4 -0
  121. package/dist/data-plane/server/db/migrations/20251120T004738098Z-update-actor-age-assurance-v2.d.ts.map +1 -0
  122. package/dist/data-plane/server/db/migrations/20251120T004738098Z-update-actor-age-assurance-v2.js +30 -0
  123. package/dist/data-plane/server/db/migrations/20251120T004738098Z-update-actor-age-assurance-v2.js.map +1 -0
  124. package/dist/data-plane/server/db/migrations/index.d.ts +1 -0
  125. package/dist/data-plane/server/db/migrations/index.d.ts.map +1 -1
  126. package/dist/data-plane/server/db/migrations/index.js +2 -1
  127. package/dist/data-plane/server/db/migrations/index.js.map +1 -1
  128. package/dist/data-plane/server/db/pagination.d.ts +3 -3
  129. package/dist/data-plane/server/db/tables/actor.d.ts +3 -0
  130. package/dist/data-plane/server/db/tables/actor.d.ts.map +1 -1
  131. package/dist/data-plane/server/db/tables/actor.js.map +1 -1
  132. package/dist/data-plane/server/routes/profile.d.ts.map +1 -1
  133. package/dist/data-plane/server/routes/profile.js +13 -1
  134. package/dist/data-plane/server/routes/profile.js.map +1 -1
  135. package/dist/hydration/actor.js +1 -1
  136. package/dist/hydration/actor.js.map +1 -1
  137. package/dist/hydration/hydrator.js +1 -1
  138. package/dist/hydration/hydrator.js.map +1 -1
  139. package/dist/index.d.ts.map +1 -1
  140. package/dist/index.js +12 -0
  141. package/dist/index.js.map +1 -1
  142. package/dist/kws.d.ts +35 -0
  143. package/dist/kws.d.ts.map +1 -1
  144. package/dist/kws.js +54 -0
  145. package/dist/kws.js.map +1 -1
  146. package/dist/lexicon/index.d.ts +19 -0
  147. package/dist/lexicon/index.d.ts.map +1 -1
  148. package/dist/lexicon/index.js +48 -1
  149. package/dist/lexicon/index.js.map +1 -1
  150. package/dist/lexicon/lexicons.d.ts +664 -0
  151. package/dist/lexicon/lexicons.d.ts.map +1 -1
  152. package/dist/lexicon/lexicons.js +354 -0
  153. package/dist/lexicon/lexicons.js.map +1 -1
  154. package/dist/lexicon/types/app/bsky/contact/defs.d.ts +24 -0
  155. package/dist/lexicon/types/app/bsky/contact/defs.d.ts.map +1 -0
  156. package/dist/lexicon/types/app/bsky/contact/defs.js +25 -0
  157. package/dist/lexicon/types/app/bsky/contact/defs.js.map +1 -0
  158. package/dist/lexicon/types/app/bsky/contact/dismissMatch.d.ts +25 -0
  159. package/dist/lexicon/types/app/bsky/contact/dismissMatch.d.ts.map +1 -0
  160. package/dist/lexicon/types/app/bsky/contact/dismissMatch.js +7 -0
  161. package/dist/lexicon/types/app/bsky/contact/dismissMatch.js.map +1 -0
  162. package/dist/lexicon/types/app/bsky/contact/getMatches.d.ts +25 -0
  163. package/dist/lexicon/types/app/bsky/contact/getMatches.d.ts.map +1 -0
  164. package/dist/lexicon/types/app/bsky/contact/getMatches.js +7 -0
  165. package/dist/lexicon/types/app/bsky/contact/getMatches.js.map +1 -0
  166. package/dist/lexicon/types/app/bsky/contact/getSyncStatus.d.ts +21 -0
  167. package/dist/lexicon/types/app/bsky/contact/getSyncStatus.d.ts.map +1 -0
  168. package/dist/lexicon/types/app/bsky/contact/getSyncStatus.js +7 -0
  169. package/dist/lexicon/types/app/bsky/contact/getSyncStatus.js.map +1 -0
  170. package/dist/lexicon/types/app/bsky/contact/importContacts.d.ts +30 -0
  171. package/dist/lexicon/types/app/bsky/contact/importContacts.d.ts.map +1 -0
  172. package/dist/lexicon/types/app/bsky/contact/importContacts.js +7 -0
  173. package/dist/lexicon/types/app/bsky/contact/importContacts.js.map +1 -0
  174. package/dist/lexicon/types/app/bsky/contact/removeData.d.ts +23 -0
  175. package/dist/lexicon/types/app/bsky/contact/removeData.d.ts.map +1 -0
  176. package/dist/lexicon/types/app/bsky/contact/removeData.js +7 -0
  177. package/dist/lexicon/types/app/bsky/contact/removeData.js.map +1 -0
  178. package/dist/lexicon/types/app/bsky/contact/startPhoneVerification.d.ts +25 -0
  179. package/dist/lexicon/types/app/bsky/contact/startPhoneVerification.d.ts.map +1 -0
  180. package/dist/lexicon/types/app/bsky/contact/startPhoneVerification.js +7 -0
  181. package/dist/lexicon/types/app/bsky/contact/startPhoneVerification.js.map +1 -0
  182. package/dist/lexicon/types/app/bsky/contact/verifyPhone.d.ts +29 -0
  183. package/dist/lexicon/types/app/bsky/contact/verifyPhone.d.ts.map +1 -0
  184. package/dist/lexicon/types/app/bsky/contact/verifyPhone.js +7 -0
  185. package/dist/lexicon/types/app/bsky/contact/verifyPhone.js.map +1 -0
  186. package/dist/lexicon/types/app/bsky/graph/defs.d.ts +8 -0
  187. package/dist/lexicon/types/app/bsky/graph/defs.d.ts.map +1 -1
  188. package/dist/lexicon/types/app/bsky/graph/defs.js.map +1 -1
  189. package/dist/logger.d.ts +1 -0
  190. package/dist/logger.d.ts.map +1 -1
  191. package/dist/logger.js +2 -1
  192. package/dist/logger.js.map +1 -1
  193. package/dist/proto/bsky_pb.d.ts +4 -0
  194. package/dist/proto/bsky_pb.d.ts.map +1 -1
  195. package/dist/proto/bsky_pb.js +10 -0
  196. package/dist/proto/bsky_pb.js.map +1 -1
  197. package/dist/proto/rolodex_connect.d.ts +83 -0
  198. package/dist/proto/rolodex_connect.d.ts.map +1 -0
  199. package/dist/proto/rolodex_connect.js +90 -0
  200. package/dist/proto/rolodex_connect.js.map +1 -0
  201. package/dist/proto/rolodex_pb.d.ts +363 -0
  202. package/dist/proto/rolodex_pb.d.ts.map +1 -0
  203. package/dist/proto/rolodex_pb.js +1032 -0
  204. package/dist/proto/rolodex_pb.js.map +1 -0
  205. package/dist/rolodex.d.ts +9 -0
  206. package/dist/rolodex.d.ts.map +1 -0
  207. package/dist/rolodex.js +25 -0
  208. package/dist/rolodex.js.map +1 -0
  209. package/dist/stash.d.ts +1 -0
  210. package/dist/stash.d.ts.map +1 -1
  211. package/dist/stash.js +1 -0
  212. package/dist/stash.js.map +1 -1
  213. package/dist/util/uris.d.ts +2 -2
  214. package/dist/util/uris.d.ts.map +1 -1
  215. package/package.json +16 -15
  216. package/proto/bsky.proto +1 -0
  217. package/proto/rolodex.proto +116 -0
  218. package/src/api/age-assurance/const.ts +142 -0
  219. package/src/api/age-assurance/index.ts +34 -0
  220. package/src/api/age-assurance/kws/age-verified.ts +75 -0
  221. package/src/api/age-assurance/kws/const.ts +33 -0
  222. package/src/api/age-assurance/kws/external-payload.test.ts +72 -0
  223. package/src/api/age-assurance/kws/external-payload.ts +149 -0
  224. package/src/api/age-assurance/redirects/kws-age-verified.ts +107 -0
  225. package/src/api/age-assurance/stash.ts +22 -0
  226. package/src/api/age-assurance/types.ts +10 -0
  227. package/src/api/age-assurance/util.ts +66 -0
  228. package/src/api/age-assurance/webhooks/kws-age-verified.ts +75 -0
  229. package/src/api/app/bsky/ageassurance/begin.ts +167 -0
  230. package/src/api/app/bsky/ageassurance/getConfig.ts +15 -0
  231. package/src/api/app/bsky/ageassurance/getState.ts +53 -0
  232. package/src/api/app/bsky/contact/dismissMatch.ts +24 -0
  233. package/src/api/app/bsky/contact/getMatches.ts +111 -0
  234. package/src/api/app/bsky/contact/getSyncStatus.ts +35 -0
  235. package/src/api/app/bsky/contact/importContacts.ts +118 -0
  236. package/src/api/app/bsky/contact/removeData.ts +23 -0
  237. package/src/api/app/bsky/contact/startPhoneVerification.ts +24 -0
  238. package/src/api/app/bsky/contact/util.ts +13 -0
  239. package/src/api/app/bsky/contact/verifyPhone.ts +27 -0
  240. package/src/api/app/bsky/graph/getRelationships.ts +4 -0
  241. package/src/api/external.ts +2 -0
  242. package/src/api/index.ts +20 -0
  243. package/src/api/kws/api.ts +55 -34
  244. package/src/api/kws/index.ts +7 -1
  245. package/src/api/kws/webhook.ts +57 -34
  246. package/src/config.ts +53 -2
  247. package/src/context.ts +6 -0
  248. package/src/data-plane/bsync/index.ts +31 -0
  249. package/src/data-plane/server/db/migrations/20251120T004738098Z-update-actor-age-assurance-v2.ts +28 -0
  250. package/src/data-plane/server/db/migrations/index.ts +1 -0
  251. package/src/data-plane/server/db/tables/actor.ts +3 -0
  252. package/src/data-plane/server/routes/profile.ts +12 -1
  253. package/src/hydration/actor.ts +1 -1
  254. package/src/hydration/hydrator.ts +1 -1
  255. package/src/index.ts +13 -0
  256. package/src/kws.ts +81 -0
  257. package/src/lexicon/index.ts +101 -0
  258. package/src/lexicon/lexicons.ts +375 -0
  259. package/src/lexicon/types/app/bsky/contact/defs.ts +52 -0
  260. package/src/lexicon/types/app/bsky/contact/dismissMatch.ts +43 -0
  261. package/src/lexicon/types/app/bsky/contact/getMatches.ts +43 -0
  262. package/src/lexicon/types/app/bsky/contact/getSyncStatus.ts +39 -0
  263. package/src/lexicon/types/app/bsky/contact/importContacts.ts +49 -0
  264. package/src/lexicon/types/app/bsky/contact/removeData.ts +40 -0
  265. package/src/lexicon/types/app/bsky/contact/startPhoneVerification.ts +43 -0
  266. package/src/lexicon/types/app/bsky/contact/verifyPhone.ts +48 -0
  267. package/src/lexicon/types/app/bsky/graph/defs.ts +8 -0
  268. package/src/logger.ts +2 -0
  269. package/src/proto/bsky_pb.ts +6 -0
  270. package/src/proto/rolodex_connect.ts +89 -0
  271. package/src/proto/rolodex_pb.ts +746 -0
  272. package/src/rolodex.ts +42 -0
  273. package/src/stash.ts +3 -0
  274. package/tests/views/__snapshots__/profile.test.ts.snap +103 -0
  275. package/tests/views/age-assurance-v2.test.ts +745 -0
  276. package/tests/views/age-assurance.test.ts +2 -0
  277. package/tests/views/profile.test.ts +39 -0
  278. package/tsconfig.build.tsbuildinfo +1 -1
  279. package/tsconfig.tests.tsbuildinfo +1 -1
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KWSExternalPayloadV2Schema = exports.KWSExternalPayloadV1Schema = exports.KWSExternalPayloadVersion = exports.KWSExternalPayloadTooLargeError = exports.KWS_EXTERNAL_PAYLOAD_CHAR_LIMIT = void 0;
4
+ exports.parseKWSExternalPayloadVersion = parseKWSExternalPayloadVersion;
5
+ exports.parseKWSExternalPayloadV1 = parseKWSExternalPayloadV1;
6
+ exports.serializeKWSExternalPayloadV1 = serializeKWSExternalPayloadV1;
7
+ exports.parseKWSExternalPayloadV1WithV2Compat = parseKWSExternalPayloadV1WithV2Compat;
8
+ exports.serializeKWSExternalPayloadV2 = serializeKWSExternalPayloadV2;
9
+ exports.parseKWSExternalPayloadV2 = parseKWSExternalPayloadV2;
10
+ const zod_1 = require("zod");
11
+ exports.KWS_EXTERNAL_PAYLOAD_CHAR_LIMIT = 250;
12
+ /**
13
+ * Thrown when the provided external payload exceeds KWS's character limit.
14
+ *
15
+ * This is most commonly caused by DIDs that are too long, such as for
16
+ * `did:web` DIDs. But it's very rare, and the client has special handling for
17
+ * this case.
18
+ */
19
+ class KWSExternalPayloadTooLargeError extends Error {
20
+ }
21
+ exports.KWSExternalPayloadTooLargeError = KWSExternalPayloadTooLargeError;
22
+ var KWSExternalPayloadVersion;
23
+ (function (KWSExternalPayloadVersion) {
24
+ KWSExternalPayloadVersion["V1"] = "1";
25
+ KWSExternalPayloadVersion["V2"] = "2";
26
+ })(KWSExternalPayloadVersion || (exports.KWSExternalPayloadVersion = KWSExternalPayloadVersion = {}));
27
+ function parseKWSExternalPayloadVersion(raw) {
28
+ switch (raw) {
29
+ case KWSExternalPayloadVersion.V2:
30
+ return KWSExternalPayloadVersion.V2;
31
+ default:
32
+ return KWSExternalPayloadVersion.V1;
33
+ }
34
+ }
35
+ exports.KWSExternalPayloadV1Schema = zod_1.z.object({
36
+ actorDid: zod_1.z.string(),
37
+ attemptId: zod_1.z.string(),
38
+ });
39
+ function parseKWSExternalPayloadV1(raw) {
40
+ try {
41
+ const value = JSON.parse(raw);
42
+ return exports.KWSExternalPayloadV1Schema.parse(value);
43
+ }
44
+ catch (err) {
45
+ throw new Error(`Failed to parse KWSExternalPayloadV1`, {
46
+ cause: err,
47
+ });
48
+ }
49
+ }
50
+ function serializeKWSExternalPayloadV1(payload) {
51
+ try {
52
+ return JSON.stringify(exports.KWSExternalPayloadV1Schema.parse(payload));
53
+ }
54
+ catch (err) {
55
+ throw new Error('Failed to serialize KWSExternalPayloadV1', { cause: err });
56
+ }
57
+ }
58
+ /**
59
+ * During our migration from v1 to v2 of the KWS external payload, we'll be
60
+ * sending v2 payloads on the v1 flow (the `adult-verified` email flow). We use
61
+ * this utility to parse either v1 or v2 payloads in that flow.
62
+ *
63
+ * Check for the `version` field on the output of this method to discriminate
64
+ * between the two types and handle them differently.
65
+ */
66
+ function parseKWSExternalPayloadV1WithV2Compat(raw) {
67
+ const deserialized = JSON.parse(raw);
68
+ const v2 = deserialized.v === KWSExternalPayloadVersion.V2;
69
+ if (v2) {
70
+ return parseKWSExternalPayloadV2(raw);
71
+ }
72
+ else {
73
+ return {
74
+ ...parseKWSExternalPayloadV1(raw),
75
+ version: KWSExternalPayloadVersion.V1,
76
+ };
77
+ }
78
+ }
79
+ exports.KWSExternalPayloadV2Schema = zod_1.z.object({
80
+ v: zod_1.z.string(),
81
+ id: zod_1.z.string(),
82
+ did: zod_1.z.string(),
83
+ gc: zod_1.z.string().length(2),
84
+ gr: zod_1.z.string().optional(),
85
+ });
86
+ function serializeKWSExternalPayloadV2(payload) {
87
+ let compressed;
88
+ try {
89
+ compressed = exports.KWSExternalPayloadV2Schema.parse({
90
+ v: KWSExternalPayloadVersion.V2, // version
91
+ id: payload.attemptId,
92
+ did: payload.actorDid,
93
+ gc: payload.countryCode, // geolocation country
94
+ gr: payload.regionCode, // geolocation region
95
+ });
96
+ }
97
+ catch (err) {
98
+ throw new Error('Failed to serialize KWSExternalPayloadV2', { cause: err });
99
+ }
100
+ const serialized = JSON.stringify(compressed);
101
+ if (serialized.length > exports.KWS_EXTERNAL_PAYLOAD_CHAR_LIMIT) {
102
+ throw new KWSExternalPayloadTooLargeError(`Serialized external payload size ${serialized.length} exceeds limit of ${exports.KWS_EXTERNAL_PAYLOAD_CHAR_LIMIT}`);
103
+ }
104
+ return serialized;
105
+ }
106
+ function parseKWSExternalPayloadV2(raw) {
107
+ try {
108
+ const deserialized = JSON.parse(raw);
109
+ const parsed = exports.KWSExternalPayloadV2Schema.parse(deserialized);
110
+ return {
111
+ version: KWSExternalPayloadVersion.V2,
112
+ attemptId: parsed.id,
113
+ actorDid: parsed.did,
114
+ countryCode: parsed.gc,
115
+ regionCode: parsed.gr,
116
+ };
117
+ }
118
+ catch (err) {
119
+ throw new Error(`Failed to parse KWSExternalPayloadV2`, {
120
+ cause: err,
121
+ });
122
+ }
123
+ }
124
+ //# sourceMappingURL=external-payload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"external-payload.js","sourceRoot":"","sources":["../../../../src/api/age-assurance/kws/external-payload.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from 'zod'\n\nexport const KWS_EXTERNAL_PAYLOAD_CHAR_LIMIT = 250\n\n/**\n * Thrown when the provided external payload exceeds KWS's character limit.\n *\n * This is most commonly caused by DIDs that are too long, such as for\n * `did:web` DIDs. But it's very rare, and the client has special handling for\n * this case.\n */\nexport class KWSExternalPayloadTooLargeError extends Error {}\n\nexport enum KWSExternalPayloadVersion {\n V1 = '1',\n V2 = '2',\n}\n\nexport function parseKWSExternalPayloadVersion(raw: string) {\n switch (raw) {\n case KWSExternalPayloadVersion.V2:\n return KWSExternalPayloadVersion.V2\n default:\n return KWSExternalPayloadVersion.V1\n }\n}\n\nexport type KWSExternalPayloadV1 = {\n actorDid: string\n attemptId: string\n}\n\nexport const KWSExternalPayloadV1Schema = z.object({\n actorDid: z.string(),\n attemptId: z.string(),\n})\n\nexport function parseKWSExternalPayloadV1(raw: string): KWSExternalPayloadV1 {\n try {\n const value: unknown = JSON.parse(raw)\n return KWSExternalPayloadV1Schema.parse(value)\n } catch (err) {\n throw new Error(`Failed to parse KWSExternalPayloadV1`, {\n cause: err,\n })\n }\n}\n\nexport function serializeKWSExternalPayloadV1(\n payload: KWSExternalPayloadV1,\n): string {\n try {\n return JSON.stringify(KWSExternalPayloadV1Schema.parse(payload))\n } catch (err) {\n throw new Error('Failed to serialize KWSExternalPayloadV1', { cause: err })\n }\n}\n\n/**\n * During our migration from v1 to v2 of the KWS external payload, we'll be\n * sending v2 payloads on the v1 flow (the `adult-verified` email flow). We use\n * this utility to parse either v1 or v2 payloads in that flow.\n *\n * Check for the `version` field on the output of this method to discriminate\n * between the two types and handle them differently.\n */\nexport function parseKWSExternalPayloadV1WithV2Compat(\n raw: string,\n):\n | (KWSExternalPayloadV1 & { version: KWSExternalPayloadVersion.V1 })\n | KWSExternalPayloadV2 {\n const deserialized = JSON.parse(raw)\n const v2 = deserialized.v === KWSExternalPayloadVersion.V2\n\n if (v2) {\n return parseKWSExternalPayloadV2(raw)\n } else {\n return {\n ...parseKWSExternalPayloadV1(raw),\n version: KWSExternalPayloadVersion.V1,\n }\n }\n}\n\n/***************************\n * KWS External Payload V2 *\n ***************************/\n\nexport type KWSExternalPayloadV2 = {\n version: KWSExternalPayloadVersion.V2\n attemptId: string\n actorDid: string\n countryCode: string\n regionCode?: string\n}\n\nexport const KWSExternalPayloadV2Schema = z.object({\n v: z.string(),\n id: z.string(),\n did: z.string(),\n gc: z.string().length(2),\n gr: z.string().optional(),\n})\n\nexport function serializeKWSExternalPayloadV2(\n payload: KWSExternalPayloadV2,\n): string {\n let compressed: z.infer<typeof KWSExternalPayloadV2Schema>\n try {\n compressed = KWSExternalPayloadV2Schema.parse({\n v: KWSExternalPayloadVersion.V2, // version\n id: payload.attemptId,\n did: payload.actorDid,\n gc: payload.countryCode, // geolocation country\n gr: payload.regionCode, // geolocation region\n })\n } catch (err) {\n throw new Error('Failed to serialize KWSExternalPayloadV2', { cause: err })\n }\n\n const serialized = JSON.stringify(compressed)\n\n if (serialized.length > KWS_EXTERNAL_PAYLOAD_CHAR_LIMIT) {\n throw new KWSExternalPayloadTooLargeError(\n `Serialized external payload size ${serialized.length} exceeds limit of ${KWS_EXTERNAL_PAYLOAD_CHAR_LIMIT}`,\n )\n }\n\n return serialized\n}\n\nexport function parseKWSExternalPayloadV2(raw: string): KWSExternalPayloadV2 {\n try {\n const deserialized = JSON.parse(raw)\n const parsed = KWSExternalPayloadV2Schema.parse(deserialized)\n\n return {\n version: KWSExternalPayloadVersion.V2,\n attemptId: parsed.id,\n actorDid: parsed.did,\n countryCode: parsed.gc,\n regionCode: parsed.gr,\n }\n } catch (err) {\n throw new Error(`Failed to parse KWSExternalPayloadV2`, {\n cause: err,\n })\n }\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=external-payload.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"external-payload.test.d.ts","sourceRoot":"","sources":["../../../../src/api/age-assurance/kws/external-payload.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const globals_1 = require("@jest/globals");
4
+ const external_payload_1 = require("./external-payload");
5
+ (0, globals_1.describe)('parseKWSExternalPayloadVersion', () => {
6
+ (0, globals_1.it)('should return V2 for "2"', () => {
7
+ const result = (0, external_payload_1.parseKWSExternalPayloadVersion)('2');
8
+ (0, globals_1.expect)(result).toBe('2');
9
+ });
10
+ (0, globals_1.it)('should return V1 for unknown versions', () => {
11
+ const result = (0, external_payload_1.parseKWSExternalPayloadVersion)('unknown');
12
+ (0, globals_1.expect)(result).toBe('1');
13
+ });
14
+ });
15
+ (0, globals_1.describe)('parseKWSExternalPayloadV1WithV2Compat', () => {
16
+ (0, globals_1.it)('should parse V1 payload correctly', () => {
17
+ const payload = {
18
+ attemptId: '123',
19
+ actorDid: 'did:plc:123',
20
+ };
21
+ const serialized = (0, external_payload_1.serializeKWSExternalPayloadV1)(payload);
22
+ const result = (0, external_payload_1.parseKWSExternalPayloadV1WithV2Compat)(serialized);
23
+ (0, globals_1.expect)(result).toEqual({
24
+ version: external_payload_1.KWSExternalPayloadVersion.V1,
25
+ ...payload,
26
+ });
27
+ });
28
+ (0, globals_1.it)('should parse V2 payload correctly', () => {
29
+ const payload = {
30
+ version: external_payload_1.KWSExternalPayloadVersion.V2,
31
+ attemptId: '123',
32
+ actorDid: 'did:plc:123',
33
+ countryCode: 'US',
34
+ };
35
+ const serialized = (0, external_payload_1.serializeKWSExternalPayloadV2)(payload);
36
+ const result = (0, external_payload_1.parseKWSExternalPayloadV1WithV2Compat)(serialized);
37
+ (0, globals_1.expect)(result).toEqual(payload);
38
+ });
39
+ });
40
+ (0, globals_1.describe)('serializeKWSExternalPayloadV2 & parseKWSExternalPayloadV2', () => {
41
+ const payload = {
42
+ version: external_payload_1.KWSExternalPayloadVersion.V2,
43
+ attemptId: '123',
44
+ actorDid: 'did:plc:123',
45
+ countryCode: 'US',
46
+ regionCode: 'CA',
47
+ };
48
+ (0, globals_1.it)('compresses when serializing', () => {
49
+ const serialized = (0, external_payload_1.serializeKWSExternalPayloadV2)(payload);
50
+ const comparison = JSON.stringify({
51
+ v: external_payload_1.KWSExternalPayloadVersion.V2,
52
+ id: payload.attemptId,
53
+ did: payload.actorDid,
54
+ gc: payload.countryCode,
55
+ gr: payload.regionCode,
56
+ });
57
+ (0, globals_1.expect)(serialized).toEqual(comparison);
58
+ });
59
+ (0, globals_1.it)('decompresses when parsing', () => {
60
+ const serialized = (0, external_payload_1.serializeKWSExternalPayloadV2)(payload);
61
+ const deserialized = (0, external_payload_1.parseKWSExternalPayloadV2)(serialized);
62
+ (0, globals_1.expect)(deserialized).toEqual(payload);
63
+ });
64
+ });
65
+ //# sourceMappingURL=external-payload.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"external-payload.test.js","sourceRoot":"","sources":["../../../../src/api/age-assurance/kws/external-payload.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it } from '@jest/globals'\nimport {\n KWSExternalPayloadVersion,\n parseKWSExternalPayloadV1WithV2Compat,\n parseKWSExternalPayloadV2,\n parseKWSExternalPayloadVersion,\n serializeKWSExternalPayloadV1,\n serializeKWSExternalPayloadV2,\n} from './external-payload'\n\ndescribe('parseKWSExternalPayloadVersion', () => {\n it('should return V2 for \"2\"', () => {\n const result = parseKWSExternalPayloadVersion('2')\n expect(result).toBe('2')\n })\n it('should return V1 for unknown versions', () => {\n const result = parseKWSExternalPayloadVersion('unknown')\n expect(result).toBe('1')\n })\n})\n\ndescribe('parseKWSExternalPayloadV1WithV2Compat', () => {\n it('should parse V1 payload correctly', () => {\n const payload = {\n attemptId: '123',\n actorDid: 'did:plc:123',\n }\n const serialized = serializeKWSExternalPayloadV1(payload)\n const result = parseKWSExternalPayloadV1WithV2Compat(serialized)\n expect(result).toEqual({\n version: KWSExternalPayloadVersion.V1,\n ...payload,\n })\n })\n it('should parse V2 payload correctly', () => {\n const payload = {\n version: KWSExternalPayloadVersion.V2 as const,\n attemptId: '123',\n actorDid: 'did:plc:123',\n countryCode: 'US',\n }\n const serialized = serializeKWSExternalPayloadV2(payload)\n const result = parseKWSExternalPayloadV1WithV2Compat(serialized)\n expect(result).toEqual(payload)\n })\n})\n\ndescribe('serializeKWSExternalPayloadV2 & parseKWSExternalPayloadV2', () => {\n const payload = {\n version: KWSExternalPayloadVersion.V2 as const,\n attemptId: '123',\n actorDid: 'did:plc:123',\n countryCode: 'US',\n regionCode: 'CA',\n }\n it('compresses when serializing', () => {\n const serialized = serializeKWSExternalPayloadV2(payload)\n const comparison = JSON.stringify({\n v: KWSExternalPayloadVersion.V2,\n id: payload.attemptId,\n did: payload.actorDid,\n gc: payload.countryCode,\n gr: payload.regionCode,\n })\n expect(serialized).toEqual(comparison)\n })\n it('decompresses when parsing', () => {\n const serialized = serializeKWSExternalPayloadV2(payload)\n const deserialized = parseKWSExternalPayloadV2(serialized)\n expect(deserialized).toEqual(payload)\n })\n})\n"]}
@@ -0,0 +1,4 @@
1
+ import { RequestHandler } from 'express';
2
+ import { AppContextWithAA } from '../types';
3
+ export declare const handler: (ctx: AppContextWithAA) => RequestHandler;
4
+ //# sourceMappingURL=kws-age-verified.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kws-age-verified.d.ts","sourceRoot":"","sources":["../../../../src/api/age-assurance/redirects/kws-age-verified.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAUjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AA8B3C,eAAO,MAAM,OAAO,GACjB,KAAK,gBAAgB,KAAG,cAiExB,CAAA"}
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handler = void 0;
4
+ const logger_1 = require("../../../logger");
5
+ const util_1 = require("../../kws/util");
6
+ const const_1 = require("../const");
7
+ const age_verified_1 = require("../kws/age-verified");
8
+ const external_payload_1 = require("../kws/external-payload");
9
+ const stash_1 = require("../stash");
10
+ const util_2 = require("../util");
11
+ function parseQueryParams(ctx, req) {
12
+ try {
13
+ const status = String(req.query.status);
14
+ const externalPayload = String(req.query.externalPayload);
15
+ const signature = String(req.query.signature);
16
+ (0, util_1.validateSignature)(ctx.cfg.kws.ageVerifiedRedirectSecret, `${status}:${externalPayload}`, signature);
17
+ return {
18
+ status,
19
+ externalPayload,
20
+ };
21
+ }
22
+ catch (err) {
23
+ throw new Error('Invalid KWS API request', { cause: err });
24
+ }
25
+ }
26
+ const handler = (ctx) => async (req, res) => {
27
+ let externalPayload;
28
+ try {
29
+ const query = parseQueryParams(ctx, req);
30
+ const { verified, verifiedMinimumAge } = (0, age_verified_1.parseKWSAgeVerifiedStatus)(query.status);
31
+ externalPayload = (0, external_payload_1.parseKWSExternalPayloadV2)(query.externalPayload);
32
+ const { actorDid, attemptId, countryCode, regionCode } = externalPayload;
33
+ /*
34
+ * KWS does not send unverified webhooks for age verification, so we
35
+ * expect all webhooks to be verified. This is just a sanity check.
36
+ */
37
+ if (!verified) {
38
+ const message = 'Expected KWS verification redirect to have verified status';
39
+ logger_1.ageAssuranceLogger.error({}, message);
40
+ throw new Error(message);
41
+ }
42
+ const { access } = (0, util_2.computeAgeAssuranceAccessOrThrow)(const_1.AGE_ASSURANCE_CONFIG, {
43
+ countryCode,
44
+ regionCode,
45
+ verifiedMinimumAge,
46
+ });
47
+ await (0, stash_1.createEvent)(ctx, actorDid, {
48
+ attemptId,
49
+ // Assumes `app.set('trust proxy', ...)` configured with `true` or specific values.
50
+ completeIp: req.ip,
51
+ completeUa: (0, util_1.getClientUa)(req),
52
+ countryCode,
53
+ regionCode,
54
+ status: 'assured',
55
+ access,
56
+ });
57
+ const q = new URLSearchParams({ actorDid, result: 'success' });
58
+ return res
59
+ .status(302)
60
+ .setHeader('Location', `${ctx.cfg.kws.redirectUrl}?${q}`)
61
+ .end();
62
+ }
63
+ catch (err) {
64
+ logger_1.ageAssuranceLogger.error({ err, ...externalPayload }, 'Failed to handle KWS verification redirect');
65
+ const q = new URLSearchParams({
66
+ ...(externalPayload ? { actorDid: externalPayload.actorDid } : {}),
67
+ result: 'unknown',
68
+ });
69
+ return res
70
+ .status(302)
71
+ .setHeader('Location', `${ctx.cfg.kws.redirectUrl}?${q}`)
72
+ .end();
73
+ }
74
+ };
75
+ exports.handler = handler;
76
+ //# sourceMappingURL=kws-age-verified.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kws-age-verified.js","sourceRoot":"","sources":["../../../../src/api/age-assurance/redirects/kws-age-verified.ts"],"names":[],"mappings":"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","sourcesContent":["import express, { RequestHandler } from 'express'\nimport { ageAssuranceLogger as logger } from '../../../logger'\nimport { getClientUa, validateSignature } from '../../kws/util'\nimport { AGE_ASSURANCE_CONFIG } from '../const'\nimport { parseKWSAgeVerifiedStatus } from '../kws/age-verified'\nimport {\n type KWSExternalPayloadV2,\n parseKWSExternalPayloadV2,\n} from '../kws/external-payload'\nimport { createEvent } from '../stash'\nimport { AppContextWithAA } from '../types'\nimport { computeAgeAssuranceAccessOrThrow } from '../util'\n\nfunction parseQueryParams(\n ctx: AppContextWithAA,\n req: express.Request,\n): {\n status: string\n externalPayload: string\n} {\n try {\n const status = String(req.query.status)\n const externalPayload = String(req.query.externalPayload)\n const signature = String(req.query.signature)\n\n validateSignature(\n ctx.cfg.kws.ageVerifiedRedirectSecret,\n `${status}:${externalPayload}`,\n signature,\n )\n\n return {\n status,\n externalPayload,\n }\n } catch (err) {\n throw new Error('Invalid KWS API request', { cause: err })\n }\n}\n\nexport const handler =\n (ctx: AppContextWithAA): RequestHandler =>\n async (req: express.Request, res: express.Response) => {\n let externalPayload: KWSExternalPayloadV2 | undefined\n\n try {\n const query = parseQueryParams(ctx, req)\n const { verified, verifiedMinimumAge } = parseKWSAgeVerifiedStatus(\n query.status,\n )\n externalPayload = parseKWSExternalPayloadV2(query.externalPayload)\n const { actorDid, attemptId, countryCode, regionCode } = externalPayload\n\n /*\n * KWS does not send unverified webhooks for age verification, so we\n * expect all webhooks to be verified. This is just a sanity check.\n */\n if (!verified) {\n const message =\n 'Expected KWS verification redirect to have verified status'\n logger.error({}, message)\n throw new Error(message)\n }\n\n const { access } = computeAgeAssuranceAccessOrThrow(\n AGE_ASSURANCE_CONFIG,\n {\n countryCode,\n regionCode,\n verifiedMinimumAge,\n },\n )\n\n await createEvent(ctx, actorDid, {\n attemptId,\n // Assumes `app.set('trust proxy', ...)` configured with `true` or specific values.\n completeIp: req.ip,\n completeUa: getClientUa(req),\n countryCode,\n regionCode,\n status: 'assured',\n access,\n })\n\n const q = new URLSearchParams({ actorDid, result: 'success' })\n\n return res\n .status(302)\n .setHeader('Location', `${ctx.cfg.kws.redirectUrl}?${q}`)\n .end()\n } catch (err) {\n logger.error(\n { err, ...externalPayload },\n 'Failed to handle KWS verification redirect',\n )\n\n const q = new URLSearchParams({\n ...(externalPayload ? { actorDid: externalPayload.actorDid } : {}),\n result: 'unknown',\n })\n\n return res\n .status(302)\n .setHeader('Location', `${ctx.cfg.kws.redirectUrl}?${q}`)\n .end()\n }\n }\n"]}
@@ -0,0 +1,4 @@
1
+ import { AppContext } from '../../context';
2
+ import { Event as AgeAssuranceEvent } from '../../lexicon/types/app/bsky/ageassurance/defs';
3
+ export declare function createEvent(ctx: AppContext, actorDid: string, event: Omit<AgeAssuranceEvent, 'createdAt'>): Promise<AgeAssuranceEvent>;
4
+ //# sourceMappingURL=stash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stash.d.ts","sourceRoot":"","sources":["../../../src/api/age-assurance/stash.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,EAAE,KAAK,IAAI,iBAAiB,EAAE,MAAM,gDAAgD,CAAA;AAG3F,wBAAsB,WAAW,CAC/B,GAAG,EAAE,UAAU,EACf,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,IAAI,CAAC,iBAAiB,EAAE,WAAW,CAAC,8BAa5C"}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createEvent = createEvent;
4
+ const common_1 = require("@atproto/common");
5
+ const stash_1 = require("../../stash");
6
+ async function createEvent(ctx, actorDid, event) {
7
+ const payload = {
8
+ createdAt: new Date().toISOString(),
9
+ ...event,
10
+ };
11
+ await ctx.stashClient.create({
12
+ actorDid: actorDid,
13
+ namespace: stash_1.Namespaces.AppBskyAgeassuranceDefsEvent,
14
+ key: common_1.TID.nextStr(),
15
+ payload,
16
+ });
17
+ return payload;
18
+ }
19
+ //# sourceMappingURL=stash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stash.js","sourceRoot":"","sources":["../../../src/api/age-assurance/stash.ts"],"names":[],"mappings":";;AAKA,kCAgBC;AArBD,4CAAqC;AAGrC,uCAAwC;AAEjC,KAAK,UAAU,WAAW,CAC/B,GAAe,EACf,QAAgB,EAChB,KAA2C;IAE3C,MAAM,OAAO,GAAsB;QACjC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,GAAG,KAAK;KACT,CAAA;IACD,MAAM,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC;QAC3B,QAAQ,EAAE,QAAQ;QAClB,SAAS,EAAE,kBAAU,CAAC,4BAA4B;QAClD,GAAG,EAAE,YAAG,CAAC,OAAO,EAAE;QAClB,OAAO;KACR,CAAC,CAAA;IACF,OAAO,OAAO,CAAA;AAChB,CAAC","sourcesContent":["import { TID } from '@atproto/common'\nimport { AppContext } from '../../context'\nimport { Event as AgeAssuranceEvent } from '../../lexicon/types/app/bsky/ageassurance/defs'\nimport { Namespaces } from '../../stash'\n\nexport async function createEvent(\n ctx: AppContext,\n actorDid: string,\n event: Omit<AgeAssuranceEvent, 'createdAt'>,\n) {\n const payload: AgeAssuranceEvent = {\n createdAt: new Date().toISOString(),\n ...event,\n }\n await ctx.stashClient.create({\n actorDid: actorDid,\n namespace: Namespaces.AppBskyAgeassuranceDefsEvent,\n key: TID.nextStr(),\n payload,\n })\n return payload\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import { KwsConfig, ServerConfig } from '../../config';
2
+ import { AppContext } from '../../context';
3
+ import { KwsClient } from '../../kws';
4
+ export type AppContextWithAA = AppContext & {
5
+ kwsClient: KwsClient;
6
+ cfg: ServerConfig & {
7
+ kws: KwsConfig;
8
+ };
9
+ };
10
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/api/age-assurance/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAErC,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG;IAC1C,SAAS,EAAE,SAAS,CAAA;IACpB,GAAG,EAAE,YAAY,GAAG;QAClB,GAAG,EAAE,SAAS,CAAA;KACf,CAAA;CACF,CAAA"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/api/age-assurance/types.ts"],"names":[],"mappings":"","sourcesContent":["import { KwsConfig, ServerConfig } from '../../config'\nimport { AppContext } from '../../context'\nimport { KwsClient } from '../../kws'\n\nexport type AppContextWithAA = AppContext & {\n kwsClient: KwsClient\n cfg: ServerConfig & {\n kws: KwsConfig\n }\n}\n"]}
@@ -0,0 +1,15 @@
1
+ import { type AppBskyAgeassuranceDefs } from '@atproto/api';
2
+ /**
3
+ * Compute age assurance access based on verified minimum age. Thrown errors
4
+ * are internal errors, so handle them accordingly.
5
+ */
6
+ export declare function computeAgeAssuranceAccessOrThrow(config: AppBskyAgeassuranceDefs.Config, { countryCode, regionCode, verifiedMinimumAge, }: {
7
+ countryCode: string;
8
+ regionCode?: string;
9
+ verifiedMinimumAge: number;
10
+ }): {
11
+ access: AppBskyAgeassuranceDefs.Access;
12
+ reason: import("@atproto/api").AgeAssuranceRuleID;
13
+ };
14
+ export declare function createLocationString(countryCode: string, regionCode?: string): string;
15
+ //# sourceMappingURL=util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../src/api/age-assurance/util.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,uBAAuB,EAG7B,MAAM,cAAc,CAAA;AAErB;;;GAGG;AACH,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,uBAAuB,CAAC,MAAM,EACtC,EACE,WAAW,EACX,UAAU,EACV,kBAAkB,GACnB,EAAE;IACD,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,kBAAkB,EAAE,MAAM,CAAA;CAC3B;YAgCW,wBAAyB,MAAM;;EAO5C;AAED,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,UAI5E"}
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.computeAgeAssuranceAccessOrThrow = computeAgeAssuranceAccessOrThrow;
4
+ exports.createLocationString = createLocationString;
5
+ const api_1 = require("@atproto/api");
6
+ /**
7
+ * Compute age assurance access based on verified minimum age. Thrown errors
8
+ * are internal errors, so handle them accordingly.
9
+ */
10
+ function computeAgeAssuranceAccessOrThrow(config, { countryCode, regionCode, verifiedMinimumAge, }) {
11
+ const region = (0, api_1.getAgeAssuranceRegionConfig)(config, {
12
+ countryCode,
13
+ regionCode,
14
+ });
15
+ if (region) {
16
+ const result = (0, api_1.computeAgeAssuranceRegionAccess)(region, {
17
+ assuredAge: verifiedMinimumAge,
18
+ /*
19
+ * We don't care about this here, this is a client-only rule. If we have
20
+ * verified data, we can use that, and the account creation date is
21
+ * irrelevant.
22
+ */
23
+ accountCreatedAt: undefined,
24
+ });
25
+ if (result) {
26
+ return result;
27
+ }
28
+ else {
29
+ /*
30
+ * If we don't get a result, it's because none of the rules matched,
31
+ * which is a configuration error: there should always be a default
32
+ * rule.
33
+ */
34
+ throw new Error('Cound not compute age assurance region access');
35
+ }
36
+ }
37
+ else {
38
+ /**
39
+ * If we had geolocation data, but we don't have a region config for this
40
+ * geolocation, then it means a user outside of our configured regions
41
+ * has completed age verification. In this case, we can't determine their
42
+ * access level, so we throw an error.
43
+ *
44
+ * This case is also guarded in `app.bsky.ageassurance.begin`.
45
+ */
46
+ throw new Error('Could not get config for region');
47
+ }
48
+ }
49
+ function createLocationString(countryCode, regionCode) {
50
+ return regionCode
51
+ ? `${countryCode.toUpperCase()}-${regionCode.toUpperCase()}`
52
+ : countryCode.toUpperCase();
53
+ }
54
+ //# sourceMappingURL=util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../../../src/api/age-assurance/util.ts"],"names":[],"mappings":";;AAUA,4EAiDC;AAED,oDAIC;AAjED,sCAIqB;AAErB;;;GAGG;AACH,SAAgB,gCAAgC,CAC9C,MAAsC,EACtC,EACE,WAAW,EACX,UAAU,EACV,kBAAkB,GAKnB;IAED,MAAM,MAAM,GAAG,IAAA,iCAA2B,EAAC,MAAM,EAAE;QACjD,WAAW;QACX,UAAU;KACX,CAAC,CAAA;IAEF,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,MAAM,GAAG,IAAA,qCAA+B,EAAC,MAAM,EAAE;YACrD,UAAU,EAAE,kBAAkB;YAC9B;;;;eAIG;YACH,gBAAgB,EAAE,SAAS;SAC5B,CAAC,CAAA;QAEF,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,MAAM,CAAA;QACf,CAAC;aAAM,CAAC;YACN;;;;eAIG;YACH,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;QAClE,CAAC;IACH,CAAC;SAAM,CAAC;QACN;;;;;;;WAOG;QACH,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACpD,CAAC;AACH,CAAC;AAED,SAAgB,oBAAoB,CAAC,WAAmB,EAAE,UAAmB;IAC3E,OAAO,UAAU;QACf,CAAC,CAAC,GAAG,WAAW,CAAC,WAAW,EAAE,IAAI,UAAU,CAAC,WAAW,EAAE,EAAE;QAC5D,CAAC,CAAC,WAAW,CAAC,WAAW,EAAE,CAAA;AAC/B,CAAC","sourcesContent":["import {\n type AppBskyAgeassuranceDefs,\n computeAgeAssuranceRegionAccess,\n getAgeAssuranceRegionConfig,\n} from '@atproto/api'\n\n/**\n * Compute age assurance access based on verified minimum age. Thrown errors\n * are internal errors, so handle them accordingly.\n */\nexport function computeAgeAssuranceAccessOrThrow(\n config: AppBskyAgeassuranceDefs.Config,\n {\n countryCode,\n regionCode,\n verifiedMinimumAge,\n }: {\n countryCode: string\n regionCode?: string\n verifiedMinimumAge: number\n },\n) {\n const region = getAgeAssuranceRegionConfig(config, {\n countryCode,\n regionCode,\n })\n\n if (region) {\n const result = computeAgeAssuranceRegionAccess(region, {\n assuredAge: verifiedMinimumAge,\n /*\n * We don't care about this here, this is a client-only rule. If we have\n * verified data, we can use that, and the account creation date is\n * irrelevant.\n */\n accountCreatedAt: undefined,\n })\n\n if (result) {\n return result\n } else {\n /*\n * If we don't get a result, it's because none of the rules matched,\n * which is a configuration error: there should always be a default\n * rule.\n */\n throw new Error('Cound not compute age assurance region access')\n }\n } else {\n /**\n * If we had geolocation data, but we don't have a region config for this\n * geolocation, then it means a user outside of our configured regions\n * has completed age verification. In this case, we can't determine their\n * access level, so we throw an error.\n *\n * This case is also guarded in `app.bsky.ageassurance.begin`.\n */\n throw new Error('Could not get config for region')\n }\n}\n\nexport function createLocationString(countryCode: string, regionCode?: string) {\n return regionCode\n ? `${countryCode.toUpperCase()}-${regionCode.toUpperCase()}`\n : countryCode.toUpperCase()\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import { RequestHandler } from 'express';
2
+ import { type AppContextWithAA } from '../types';
3
+ export declare const handler: (ctx: AppContextWithAA) => RequestHandler;
4
+ //# sourceMappingURL=kws-age-verified.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kws-age-verified.d.ts","sourceRoot":"","sources":["../../../../src/api/age-assurance/webhooks/kws-age-verified.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AASjD,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAGhD,eAAO,MAAM,OAAO,GACjB,KAAK,gBAAgB,KAAG,cA6DxB,CAAA"}
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handler = void 0;
4
+ const logger_1 = require("../../../logger");
5
+ const const_1 = require("../const");
6
+ const age_verified_1 = require("../kws/age-verified");
7
+ const external_payload_1 = require("../kws/external-payload");
8
+ const stash_1 = require("../stash");
9
+ const util_1 = require("../util");
10
+ const handler = (ctx) => async (req, res) => {
11
+ let body;
12
+ try {
13
+ body = (0, age_verified_1.parseKWSAgeVerifiedWebhook)(req.body);
14
+ }
15
+ catch (err) {
16
+ const message = 'Failed to parse KWS webhook body';
17
+ logger_1.ageAssuranceLogger.error({ err }, message);
18
+ return res.status(400).json({ error: message });
19
+ }
20
+ const { status, externalPayload } = body.payload;
21
+ const { verified, verifiedMinimumAge } = status;
22
+ const { actorDid, countryCode, regionCode, attemptId } = (0, external_payload_1.parseKWSExternalPayloadV2)(externalPayload);
23
+ /*
24
+ * KWS does not send unverified webhooks for age verification, so we
25
+ * expect all webhooks to be verified. This is just a sanity check.
26
+ */
27
+ if (!verified) {
28
+ const message = 'Expected KWS webhook to have verified status';
29
+ logger_1.ageAssuranceLogger.error({}, message);
30
+ return res.status(400).json({ error: message });
31
+ }
32
+ let result;
33
+ try {
34
+ result = (0, util_1.computeAgeAssuranceAccessOrThrow)(const_1.AGE_ASSURANCE_CONFIG, {
35
+ countryCode,
36
+ regionCode,
37
+ verifiedMinimumAge,
38
+ });
39
+ }
40
+ catch (err) {
41
+ // internal errors
42
+ logger_1.ageAssuranceLogger.error({ err, attemptId, actorDid, countryCode, regionCode }, 'Failed to compute age assurance access');
43
+ }
44
+ try {
45
+ if (result) {
46
+ await (0, stash_1.createEvent)(ctx, actorDid, {
47
+ attemptId,
48
+ countryCode,
49
+ regionCode,
50
+ status: 'assured',
51
+ access: result.access,
52
+ });
53
+ }
54
+ return res.status(200).end();
55
+ }
56
+ catch (err) {
57
+ const message = 'Failed to handle KWS webhook';
58
+ logger_1.ageAssuranceLogger.error({ err, attemptId, actorDid, countryCode, regionCode }, message);
59
+ return res.status(500).json({ error: message });
60
+ }
61
+ };
62
+ exports.handler = handler;
63
+ //# sourceMappingURL=kws-age-verified.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kws-age-verified.js","sourceRoot":"","sources":["../../../../src/api/age-assurance/webhooks/kws-age-verified.ts"],"names":[],"mappings":";;;AACA,4CAA8D;AAC9D,oCAA+C;AAC/C,sDAG4B;AAC5B,8DAAmE;AACnE,oCAAsC;AAEtC,kCAA0D;AAEnD,MAAM,OAAO,GAClB,CAAC,GAAqB,EAAkB,EAAE,CAC1C,KAAK,EAAE,GAAoB,EAAE,GAAqB,EAAE,EAAE;IACpD,IAAI,IAA2B,CAAA;IAC/B,IAAI,CAAC;QACH,IAAI,GAAG,IAAA,yCAA0B,EAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC7C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,kCAAkC,CAAA;QAClD,2BAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,OAAO,CAAC,CAAA;QAC9B,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;IACjD,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC,OAAO,CAAA;IAChD,MAAM,EAAE,QAAQ,EAAE,kBAAkB,EAAE,GAAG,MAAM,CAAA;IAC/C,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,GACpD,IAAA,4CAAyB,EAAC,eAAe,CAAC,CAAA;IAE5C;;;OAGG;IACH,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,OAAO,GAAG,8CAA8C,CAAA;QAC9D,2BAAM,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;QACzB,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;IACjD,CAAC;IAED,IAAI,MAAuE,CAAA;IAC3E,IAAI,CAAC;QACH,MAAM,GAAG,IAAA,uCAAgC,EAAC,4BAAoB,EAAE;YAC9D,WAAW;YACX,UAAU;YACV,kBAAkB;SACnB,CAAC,CAAA;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,kBAAkB;QAClB,2BAAM,CAAC,KAAK,CACV,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,EACrD,wCAAwC,CACzC,CAAA;IACH,CAAC;IAED,IAAI,CAAC;QACH,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,IAAA,mBAAW,EAAC,GAAG,EAAE,QAAQ,EAAE;gBAC/B,SAAS;gBACT,WAAW;gBACX,UAAU;gBACV,MAAM,EAAE,SAAS;gBACjB,MAAM,EAAE,MAAM,CAAC,MAAM;aACtB,CAAC,CAAA;QACJ,CAAC;QAED,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAA;IAC9B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,8BAA8B,CAAA;QAC9C,2BAAM,CAAC,KAAK,CACV,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,EACrD,OAAO,CACR,CAAA;QACD,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;IACjD,CAAC;AACH,CAAC,CAAA;AA9DU,QAAA,OAAO,WA8DjB","sourcesContent":["import express, { RequestHandler } from 'express'\nimport { ageAssuranceLogger as logger } from '../../../logger'\nimport { AGE_ASSURANCE_CONFIG } from '../const'\nimport {\n type KWSWebhookAgeVerified,\n parseKWSAgeVerifiedWebhook,\n} from '../kws/age-verified'\nimport { parseKWSExternalPayloadV2 } from '../kws/external-payload'\nimport { createEvent } from '../stash'\nimport { type AppContextWithAA } from '../types'\nimport { computeAgeAssuranceAccessOrThrow } from '../util'\n\nexport const handler =\n (ctx: AppContextWithAA): RequestHandler =>\n async (req: express.Request, res: express.Response) => {\n let body: KWSWebhookAgeVerified\n try {\n body = parseKWSAgeVerifiedWebhook(req.body)\n } catch (err) {\n const message = 'Failed to parse KWS webhook body'\n logger.error({ err }, message)\n return res.status(400).json({ error: message })\n }\n\n const { status, externalPayload } = body.payload\n const { verified, verifiedMinimumAge } = status\n const { actorDid, countryCode, regionCode, attemptId } =\n parseKWSExternalPayloadV2(externalPayload)\n\n /*\n * KWS does not send unverified webhooks for age verification, so we\n * expect all webhooks to be verified. This is just a sanity check.\n */\n if (!verified) {\n const message = 'Expected KWS webhook to have verified status'\n logger.error({}, message)\n return res.status(400).json({ error: message })\n }\n\n let result: ReturnType<typeof computeAgeAssuranceAccessOrThrow> | undefined\n try {\n result = computeAgeAssuranceAccessOrThrow(AGE_ASSURANCE_CONFIG, {\n countryCode,\n regionCode,\n verifiedMinimumAge,\n })\n } catch (err) {\n // internal errors\n logger.error(\n { err, attemptId, actorDid, countryCode, regionCode },\n 'Failed to compute age assurance access',\n )\n }\n\n try {\n if (result) {\n await createEvent(ctx, actorDid, {\n attemptId,\n countryCode,\n regionCode,\n status: 'assured',\n access: result.access,\n })\n }\n\n return res.status(200).end()\n } catch (err) {\n const message = 'Failed to handle KWS webhook'\n logger.error(\n { err, attemptId, actorDid, countryCode, regionCode },\n message,\n )\n return res.status(500).json({ error: message })\n }\n }\n"]}
@@ -0,0 +1,4 @@
1
+ import { AppContext } from '../../../../context';
2
+ import { Server } from '../../../../lexicon';
3
+ export default function (server: Server, ctx: AppContext): void;
4
+ //# sourceMappingURL=begin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"begin.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/ageassurance/begin.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAkB5C,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QA2GvD"}