@learncard/network-brain-service 3.19.0 → 4.0.0

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 (507) hide show
  1. package/.env.example +47 -82
  2. package/AGENTS.md +52 -0
  3. package/CHANGELOG.md +147 -0
  4. package/README.md +51 -2
  5. package/bootstrapLambda.test.ts +72 -0
  6. package/config/config.dev.json +29 -0
  7. package/config/config.example.json +29 -0
  8. package/config/config.json +1 -0
  9. package/config/config.production.json +29 -0
  10. package/config/config.scouts.dev.json +24 -0
  11. package/config/config.scouts.production.json +24 -0
  12. package/contractEventsLambda.ts +18 -0
  13. package/contractEventsLambdaApp.ts +19 -0
  14. package/didWebLambda.ts +13 -18
  15. package/didWebLambdaApp.ts +22 -0
  16. package/dist/accesslayer/app-manifest-version/create.d.ts +10 -0
  17. package/dist/accesslayer/app-manifest-version/create.d.ts.map +1 -0
  18. package/dist/accesslayer/app-manifest-version/read.d.ts +11 -0
  19. package/dist/accesslayer/app-manifest-version/read.d.ts.map +1 -0
  20. package/dist/accesslayer/app-manifest-version/update.d.ts +7 -0
  21. package/dist/accesslayer/app-manifest-version/update.d.ts.map +1 -0
  22. package/dist/accesslayer/app-store-listing/read.d.ts +2 -1
  23. package/dist/accesslayer/app-store-listing/read.d.ts.map +1 -1
  24. package/dist/accesslayer/app-store-listing/relationships/create.d.ts +1 -0
  25. package/dist/accesslayer/app-store-listing/relationships/create.d.ts.map +1 -1
  26. package/dist/accesslayer/app-store-listing/relationships/read.d.ts +2 -0
  27. package/dist/accesslayer/app-store-listing/relationships/read.d.ts.map +1 -1
  28. package/dist/accesslayer/app-store-listing/update.d.ts +1 -0
  29. package/dist/accesslayer/app-store-listing/update.d.ts.map +1 -1
  30. package/dist/accesslayer/boost/relationships/create.d.ts +2 -1
  31. package/dist/accesslayer/boost/relationships/create.d.ts.map +1 -1
  32. package/dist/accesslayer/consentflowcontract/create.d.ts +9 -1
  33. package/dist/accesslayer/consentflowcontract/create.d.ts.map +1 -1
  34. package/dist/accesslayer/consentflowcontract/read.d.ts +34 -3
  35. package/dist/accesslayer/consentflowcontract/read.d.ts.map +1 -1
  36. package/dist/accesslayer/consentflowcontract/relationships/create.d.ts +4 -1
  37. package/dist/accesslayer/consentflowcontract/relationships/create.d.ts.map +1 -1
  38. package/dist/accesslayer/consentflowcontract/relationships/delete.d.ts.map +1 -1
  39. package/dist/accesslayer/consentflowcontract/relationships/read.d.ts +3 -2
  40. package/dist/accesslayer/consentflowcontract/relationships/read.d.ts.map +1 -1
  41. package/dist/accesslayer/consentflowcontract/relationships/recipients.d.ts +12 -0
  42. package/dist/accesslayer/consentflowcontract/relationships/recipients.d.ts.map +1 -0
  43. package/dist/accesslayer/consentflowcontract/relationships/smartResume.d.ts +12 -0
  44. package/dist/accesslayer/consentflowcontract/relationships/smartResume.d.ts.map +1 -0
  45. package/dist/accesslayer/consentflowcontract/relationships/update.d.ts +8 -5
  46. package/dist/accesslayer/consentflowcontract/relationships/update.d.ts.map +1 -1
  47. package/dist/accesslayer/credential/create.d.ts +2 -1
  48. package/dist/accesslayer/credential/create.d.ts.map +1 -1
  49. package/dist/accesslayer/credential/relationships/create.d.ts +4 -3
  50. package/dist/accesslayer/credential/relationships/create.d.ts.map +1 -1
  51. package/dist/accesslayer/inbox-credential/relationships/create.d.ts +2 -1
  52. package/dist/accesslayer/inbox-credential/relationships/create.d.ts.map +1 -1
  53. package/dist/accesslayer/inbox-credential/update.d.ts +2 -1
  54. package/dist/accesslayer/inbox-credential/update.d.ts.map +1 -1
  55. package/dist/accesslayer/presentation/read.d.ts.map +1 -1
  56. package/dist/accesslayer/presentation/relationships/create.d.ts +2 -2
  57. package/dist/accesslayer/presentation/relationships/create.d.ts.map +1 -1
  58. package/dist/accesslayer/presentation/relationships/read.d.ts.map +1 -1
  59. package/dist/accesslayer/share-link/abandon.d.ts +3 -0
  60. package/dist/accesslayer/share-link/abandon.d.ts.map +1 -0
  61. package/dist/accesslayer/share-link/attachment.d.ts +37 -0
  62. package/dist/accesslayer/share-link/attachment.d.ts.map +1 -0
  63. package/dist/accesslayer/share-link/cleanup.d.ts +6 -0
  64. package/dist/accesslayer/share-link/cleanup.d.ts.map +1 -0
  65. package/dist/accesslayer/share-link/errors.d.ts +8 -0
  66. package/dist/accesslayer/share-link/errors.d.ts.map +1 -0
  67. package/dist/accesslayer/share-link/finalize.d.ts +3 -0
  68. package/dist/accesslayer/share-link/finalize.d.ts.map +1 -0
  69. package/dist/accesslayer/share-link/helpers.d.ts +59 -0
  70. package/dist/accesslayer/share-link/helpers.d.ts.map +1 -0
  71. package/dist/accesslayer/share-link/index.d.ts +12 -0
  72. package/dist/accesslayer/share-link/index.d.ts.map +1 -0
  73. package/dist/accesslayer/share-link/list.d.ts +5 -0
  74. package/dist/accesslayer/share-link/list.d.ts.map +1 -0
  75. package/dist/accesslayer/share-link/read.d.ts +5 -0
  76. package/dist/accesslayer/share-link/read.d.ts.map +1 -0
  77. package/dist/accesslayer/share-link/receipt.d.ts +11 -0
  78. package/dist/accesslayer/share-link/receipt.d.ts.map +1 -0
  79. package/dist/accesslayer/share-link/recovery.d.ts +6 -0
  80. package/dist/accesslayer/share-link/recovery.d.ts.map +1 -0
  81. package/dist/accesslayer/share-link/reserve.d.ts +4 -0
  82. package/dist/accesslayer/share-link/reserve.d.ts.map +1 -0
  83. package/dist/accesslayer/share-link/revoke.d.ts +3 -0
  84. package/dist/accesslayer/share-link/revoke.d.ts.map +1 -0
  85. package/dist/accesslayer/share-link/transaction-execution.d.ts +18 -0
  86. package/dist/accesslayer/share-link/transaction-execution.d.ts.map +1 -0
  87. package/dist/accesslayer/share-link/transaction.d.ts +15 -0
  88. package/dist/accesslayer/share-link/transaction.d.ts.map +1 -0
  89. package/dist/accesslayer/share-link/types.d.ts +375 -0
  90. package/dist/accesslayer/share-link/types.d.ts.map +1 -0
  91. package/dist/app.d.ts +4 -0
  92. package/dist/app.d.ts.map +1 -1
  93. package/dist/cache/app-store.caches.d.ts +49 -0
  94. package/dist/cache/app-store.caches.d.ts.map +1 -1
  95. package/dist/config/applyDockerStageConfig.d.ts +2 -0
  96. package/dist/config/applyDockerStageConfig.d.ts.map +1 -0
  97. package/dist/config/environment.d.ts +14 -0
  98. package/dist/config/environment.d.ts.map +1 -1
  99. package/dist/config/serverlessFunctionEnv.test.d.ts +2 -0
  100. package/dist/config/serverlessFunctionEnv.test.d.ts.map +1 -0
  101. package/dist/config/stageConfig.d.ts +112 -0
  102. package/dist/config/stageConfig.d.ts.map +1 -0
  103. package/dist/config/stageConfig.test.d.ts +2 -0
  104. package/dist/config/stageConfig.test.d.ts.map +1 -0
  105. package/dist/constants/auth-grant.d.ts +2 -0
  106. package/dist/constants/auth-grant.d.ts.map +1 -1
  107. package/dist/didkit_wasm_bg.wasm +0 -0
  108. package/dist/docker-entry.d.ts +1 -1
  109. package/dist/docker-entry.d.ts.map +1 -1
  110. package/dist/helpers/app-manifest.helpers.d.ts +5 -0
  111. package/dist/helpers/app-manifest.helpers.d.ts.map +1 -0
  112. package/dist/helpers/boost.helpers.d.ts.map +1 -1
  113. package/dist/helpers/claim-hooks.helpers.d.ts +2 -1
  114. package/dist/helpers/claim-hooks.helpers.d.ts.map +1 -1
  115. package/dist/helpers/consent-referral.helpers.d.ts +2 -0
  116. package/dist/helpers/consent-referral.helpers.d.ts.map +1 -0
  117. package/dist/helpers/consent-scopes.helpers.d.ts +7 -0
  118. package/dist/helpers/consent-scopes.helpers.d.ts.map +1 -0
  119. package/dist/helpers/contract-event-maintenance.helpers.d.ts +3 -0
  120. package/dist/helpers/contract-event-maintenance.helpers.d.ts.map +1 -0
  121. package/dist/helpers/contract-events.helpers.d.ts +25 -0
  122. package/dist/helpers/contract-events.helpers.d.ts.map +1 -0
  123. package/dist/helpers/contract-requests.helpers.d.ts +19 -0
  124. package/dist/helpers/contract-requests.helpers.d.ts.map +1 -0
  125. package/dist/helpers/credentialSubject.helpers.d.ts +3 -0
  126. package/dist/helpers/credentialSubject.helpers.d.ts.map +1 -0
  127. package/dist/helpers/credentialSubject.helpers.test.d.ts +2 -0
  128. package/dist/helpers/credentialSubject.helpers.test.d.ts.map +1 -0
  129. package/dist/helpers/finalize-inbox.helpers.d.ts +3 -3
  130. package/dist/helpers/finalize-inbox.helpers.d.ts.map +1 -1
  131. package/dist/helpers/inbox.helpers.d.ts.map +1 -1
  132. package/dist/helpers/inline-template.helpers.d.ts +45 -0
  133. package/dist/helpers/inline-template.helpers.d.ts.map +1 -0
  134. package/dist/helpers/notificationMessages.d.ts +1 -1
  135. package/dist/helpers/notificationMessages.d.ts.map +1 -1
  136. package/dist/helpers/notificationQueue.helpers.d.ts.map +1 -1
  137. package/dist/helpers/notifications.helpers.d.ts +6 -0
  138. package/dist/helpers/notifications.helpers.d.ts.map +1 -1
  139. package/dist/helpers/presentation-metadata.d.ts +4 -0
  140. package/dist/helpers/presentation-metadata.d.ts.map +1 -0
  141. package/dist/helpers/presentation.helpers.d.ts +1 -1
  142. package/dist/helpers/presentation.helpers.d.ts.map +1 -1
  143. package/dist/helpers/profile.helpers.d.ts +2 -0
  144. package/dist/helpers/profile.helpers.d.ts.map +1 -1
  145. package/dist/helpers/share-content-client/adapters.d.ts +10 -0
  146. package/dist/helpers/share-content-client/adapters.d.ts.map +1 -0
  147. package/dist/helpers/share-content-client/canonical.d.ts +7 -0
  148. package/dist/helpers/share-content-client/canonical.d.ts.map +1 -0
  149. package/dist/helpers/share-content-client/client.d.ts +5 -0
  150. package/dist/helpers/share-content-client/client.d.ts.map +1 -0
  151. package/dist/helpers/share-content-client/config.d.ts +11 -0
  152. package/dist/helpers/share-content-client/config.d.ts.map +1 -0
  153. package/dist/helpers/share-content-client/index.d.ts +6 -0
  154. package/dist/helpers/share-content-client/index.d.ts.map +1 -0
  155. package/dist/helpers/share-content-client/responses.d.ts +16 -0
  156. package/dist/helpers/share-content-client/responses.d.ts.map +1 -0
  157. package/dist/helpers/share-content-client/types.d.ts +145 -0
  158. package/dist/helpers/share-content-client/types.d.ts.map +1 -0
  159. package/dist/helpers/share-link-attachment-access.d.ts +4 -0
  160. package/dist/helpers/share-link-attachment-access.d.ts.map +1 -0
  161. package/dist/helpers/share-link-attachment.d.ts +18 -0
  162. package/dist/helpers/share-link-attachment.d.ts.map +1 -0
  163. package/dist/helpers/share-link-coordinator/attachment-stat.d.ts +5 -0
  164. package/dist/helpers/share-link-coordinator/attachment-stat.d.ts.map +1 -0
  165. package/dist/helpers/share-link-coordinator/budget-helpers.d.ts +5 -0
  166. package/dist/helpers/share-link-coordinator/budget-helpers.d.ts.map +1 -0
  167. package/dist/helpers/share-link-coordinator/cleanup-runner.d.ts +3 -0
  168. package/dist/helpers/share-link-coordinator/cleanup-runner.d.ts.map +1 -0
  169. package/dist/helpers/share-link-coordinator/coordinator.d.ts +4 -0
  170. package/dist/helpers/share-link-coordinator/coordinator.d.ts.map +1 -0
  171. package/dist/helpers/share-link-coordinator/index.d.ts +5 -0
  172. package/dist/helpers/share-link-coordinator/index.d.ts.map +1 -0
  173. package/dist/helpers/share-link-coordinator/recovery-runner.d.ts +9 -0
  174. package/dist/helpers/share-link-coordinator/recovery-runner.d.ts.map +1 -0
  175. package/dist/helpers/share-link-coordinator/runtime.d.ts +11 -0
  176. package/dist/helpers/share-link-coordinator/runtime.d.ts.map +1 -0
  177. package/dist/helpers/share-link-coordinator/stat.d.ts +4 -0
  178. package/dist/helpers/share-link-coordinator/stat.d.ts.map +1 -0
  179. package/dist/helpers/share-link-coordinator/types.d.ts +160 -0
  180. package/dist/helpers/share-link-coordinator/types.d.ts.map +1 -0
  181. package/dist/helpers/share-link-lifecycle/index.d.ts +5 -0
  182. package/dist/helpers/share-link-lifecycle/index.d.ts.map +1 -0
  183. package/dist/helpers/share-link-lifecycle/lease.helpers.d.ts +4 -0
  184. package/dist/helpers/share-link-lifecycle/lease.helpers.d.ts.map +1 -0
  185. package/dist/helpers/share-link-lifecycle/recovery.helpers.d.ts +21 -0
  186. package/dist/helpers/share-link-lifecycle/recovery.helpers.d.ts.map +1 -0
  187. package/dist/helpers/share-link-lifecycle/request-hash.helpers.d.ts +9 -0
  188. package/dist/helpers/share-link-lifecycle/request-hash.helpers.d.ts.map +1 -0
  189. package/dist/helpers/share-link-lifecycle/types.d.ts +14 -0
  190. package/dist/helpers/share-link-lifecycle/types.d.ts.map +1 -0
  191. package/dist/helpers/share-link-maintenance/budget.d.ts +12 -0
  192. package/dist/helpers/share-link-maintenance/budget.d.ts.map +1 -0
  193. package/dist/helpers/share-link-maintenance/config.d.ts +48 -0
  194. package/dist/helpers/share-link-maintenance/config.d.ts.map +1 -0
  195. package/dist/helpers/share-link-maintenance/index.d.ts +8 -0
  196. package/dist/helpers/share-link-maintenance/index.d.ts.map +1 -0
  197. package/dist/helpers/share-link-maintenance/runner.d.ts +20 -0
  198. package/dist/helpers/share-link-maintenance/runner.d.ts.map +1 -0
  199. package/dist/helpers/share-link-maintenance/runtime.d.ts +38 -0
  200. package/dist/helpers/share-link-maintenance/runtime.d.ts.map +1 -0
  201. package/dist/helpers/share-link-maintenance/scheduler.d.ts +18 -0
  202. package/dist/helpers/share-link-maintenance/scheduler.d.ts.map +1 -0
  203. package/dist/helpers/share-link-maintenance/telemetry.d.ts +5 -0
  204. package/dist/helpers/share-link-maintenance/telemetry.d.ts.map +1 -0
  205. package/dist/helpers/share-link-maintenance/types.d.ts +56 -0
  206. package/dist/helpers/share-link-maintenance/types.d.ts.map +1 -0
  207. package/dist/helpers/share-link-owner/config.d.ts +16 -0
  208. package/dist/helpers/share-link-owner/config.d.ts.map +1 -0
  209. package/dist/helpers/share-link-owner/diagnostics.d.ts +26 -0
  210. package/dist/helpers/share-link-owner/diagnostics.d.ts.map +1 -0
  211. package/dist/helpers/share-link-owner/lazy-initializer.d.ts +2 -0
  212. package/dist/helpers/share-link-owner/lazy-initializer.d.ts.map +1 -0
  213. package/dist/helpers/share-link-owner-projection.d.ts +4 -0
  214. package/dist/helpers/share-link-owner-projection.d.ts.map +1 -0
  215. package/dist/helpers/share-link-passcode-abuse.d.ts +2 -0
  216. package/dist/helpers/share-link-passcode-abuse.d.ts.map +1 -0
  217. package/dist/helpers/share-link-passcode.d.ts +6 -0
  218. package/dist/helpers/share-link-passcode.d.ts.map +1 -0
  219. package/dist/helpers/share-link-policy/index.d.ts +4 -0
  220. package/dist/helpers/share-link-policy/index.d.ts.map +1 -0
  221. package/dist/helpers/share-link-policy/production.d.ts +11 -0
  222. package/dist/helpers/share-link-policy/production.d.ts.map +1 -0
  223. package/dist/helpers/share-link-policy/resolver.d.ts +6 -0
  224. package/dist/helpers/share-link-policy/resolver.d.ts.map +1 -0
  225. package/dist/helpers/share-link-policy/types.d.ts +22 -0
  226. package/dist/helpers/share-link-policy/types.d.ts.map +1 -0
  227. package/dist/helpers/share-link-public/config.d.ts +13 -0
  228. package/dist/helpers/share-link-public/config.d.ts.map +1 -0
  229. package/dist/helpers/share-link-view-notification.d.ts +2 -0
  230. package/dist/helpers/share-link-view-notification.d.ts.map +1 -0
  231. package/dist/helpers/signingAuthority.helpers.d.ts.map +1 -1
  232. package/dist/helpers/smartResume.helpers.d.ts +3 -0
  233. package/dist/helpers/smartResume.helpers.d.ts.map +1 -0
  234. package/dist/index.js +2 -2
  235. package/dist/models/AppManifestVersion.d.ts +20 -0
  236. package/dist/models/AppManifestVersion.d.ts.map +1 -0
  237. package/dist/models/AppStoreListing.d.ts +13 -0
  238. package/dist/models/AppStoreListing.d.ts.map +1 -1
  239. package/dist/models/ConsentFlowContract.d.ts +13 -2
  240. package/dist/models/ConsentFlowContract.d.ts.map +1 -1
  241. package/dist/models/ConsentFlowTerms.d.ts.map +1 -1
  242. package/dist/models/ConsentFlowTransaction.d.ts.map +1 -1
  243. package/dist/models/Integration.d.ts +2 -0
  244. package/dist/models/Integration.d.ts.map +1 -1
  245. package/dist/models/Presentation.d.ts +2 -0
  246. package/dist/models/Presentation.d.ts.map +1 -1
  247. package/dist/models/Profile.d.ts +2 -0
  248. package/dist/models/Profile.d.ts.map +1 -1
  249. package/dist/models/ShareLink.d.ts +46 -0
  250. package/dist/models/ShareLink.d.ts.map +1 -0
  251. package/dist/models/ShareViewReceipt.d.ts +22 -0
  252. package/dist/models/ShareViewReceipt.d.ts.map +1 -0
  253. package/dist/models/index.d.ts +2 -0
  254. package/dist/models/index.d.ts.map +1 -1
  255. package/dist/models/share-link-constraints.d.ts +3 -0
  256. package/dist/models/share-link-constraints.d.ts.map +1 -0
  257. package/dist/openapi.d.ts +1 -1
  258. package/dist/openapi.d.ts.map +1 -1
  259. package/dist/public-share-link-http.d.ts +4 -0
  260. package/dist/public-share-link-http.d.ts.map +1 -0
  261. package/dist/routes/app-store.d.ts +619 -0
  262. package/dist/routes/app-store.d.ts.map +1 -1
  263. package/dist/routes/boosts.d.ts +2 -2
  264. package/dist/routes/boosts.d.ts.map +1 -1
  265. package/dist/routes/contracts.d.ts +148 -5
  266. package/dist/routes/contracts.d.ts.map +1 -1
  267. package/dist/routes/credentials.d.ts +35 -1
  268. package/dist/routes/credentials.d.ts.map +1 -1
  269. package/dist/routes/inbox.d.ts +52 -2
  270. package/dist/routes/inbox.d.ts.map +1 -1
  271. package/dist/routes/index.d.ts +153 -0
  272. package/dist/routes/index.d.ts.map +1 -1
  273. package/dist/routes/presentations.d.ts +1 -0
  274. package/dist/routes/presentations.d.ts.map +1 -1
  275. package/dist/routes/profile-manager.d.ts.map +1 -1
  276. package/dist/routes/profiles.d.ts.map +1 -1
  277. package/dist/routes/public-share-links.d.ts +285 -0
  278. package/dist/routes/public-share-links.d.ts.map +1 -0
  279. package/dist/routes/share-links.d.ts +1005 -0
  280. package/dist/routes/share-links.d.ts.map +1 -0
  281. package/dist/routes/test.d.ts +5 -0
  282. package/dist/routes/test.d.ts.map +1 -1
  283. package/dist/routes/workflows.d.ts.map +1 -1
  284. package/dist/services/delivery/adapters/postmark.adapter.d.ts.map +1 -1
  285. package/dist/types/app-manifest.d.ts +339 -0
  286. package/dist/types/app-manifest.d.ts.map +1 -0
  287. package/dist/types/app-store-listing.d.ts +34 -0
  288. package/dist/types/app-store-listing.d.ts.map +1 -1
  289. package/dist/types/consentflowcontract.d.ts +31 -4
  290. package/dist/types/consentflowcontract.d.ts.map +1 -1
  291. package/dist/types/credential-refresh.d.ts +1 -1
  292. package/esbuildPlugins.cjs +1 -0
  293. package/lambda.ts +49 -192
  294. package/lambdaApp.ts +203 -0
  295. package/package.json +25 -17
  296. package/scripts/export-openapi.ts +20 -0
  297. package/scripts/offline-schema-environment.ts +18 -0
  298. package/scripts/seed-demo-persona.ts +425 -0
  299. package/scripts/verify-python-contracts.ts +72 -0
  300. package/serverless-local.yml +3 -6
  301. package/serverless.function-env.cjs +50 -0
  302. package/serverless.local.yml +0 -1
  303. package/serverless.yml +44 -55
  304. package/shareLinkMaintenanceLambda.ts +18 -0
  305. package/shareLinkMaintenanceLambdaApp.ts +50 -0
  306. package/src/accesslayer/app-manifest-version/create.ts +57 -0
  307. package/src/accesslayer/app-manifest-version/read.ts +129 -0
  308. package/src/accesslayer/app-manifest-version/update.ts +61 -0
  309. package/src/accesslayer/app-store-listing/read.ts +6 -0
  310. package/src/accesslayer/app-store-listing/relationships/create.ts +20 -0
  311. package/src/accesslayer/app-store-listing/relationships/read.ts +24 -1
  312. package/src/accesslayer/app-store-listing/update.ts +15 -0
  313. package/src/accesslayer/boost/relationships/create.ts +8 -2
  314. package/src/accesslayer/consentflowcontract/create.ts +81 -8
  315. package/src/accesslayer/consentflowcontract/read.ts +84 -10
  316. package/src/accesslayer/consentflowcontract/relationships/create.ts +125 -109
  317. package/src/accesslayer/consentflowcontract/relationships/delete.ts +1 -0
  318. package/src/accesslayer/consentflowcontract/relationships/read.ts +184 -108
  319. package/src/accesslayer/consentflowcontract/relationships/recipients.ts +125 -0
  320. package/src/accesslayer/consentflowcontract/relationships/smartResume.ts +125 -0
  321. package/src/accesslayer/consentflowcontract/relationships/update.ts +255 -217
  322. package/src/accesslayer/credential/create.test.ts +2 -115
  323. package/src/accesslayer/credential/create.ts +11 -6
  324. package/src/accesslayer/credential/relationships/create.ts +17 -10
  325. package/src/accesslayer/inbox-credential/relationships/create.ts +70 -48
  326. package/src/accesslayer/inbox-credential/update.ts +4 -2
  327. package/src/accesslayer/presentation/read.ts +57 -25
  328. package/src/accesslayer/presentation/relationships/create.ts +54 -11
  329. package/src/accesslayer/presentation/relationships/read.ts +21 -6
  330. package/src/accesslayer/share-link/abandon.ts +120 -0
  331. package/src/accesslayer/share-link/attachment.ts +360 -0
  332. package/src/accesslayer/share-link/cleanup.ts +271 -0
  333. package/src/accesslayer/share-link/errors.ts +32 -0
  334. package/src/accesslayer/share-link/finalize.ts +313 -0
  335. package/src/accesslayer/share-link/helpers.ts +450 -0
  336. package/src/accesslayer/share-link/index.ts +11 -0
  337. package/src/accesslayer/share-link/list.ts +162 -0
  338. package/src/accesslayer/share-link/read.ts +107 -0
  339. package/src/accesslayer/share-link/receipt.ts +548 -0
  340. package/src/accesslayer/share-link/recovery.ts +565 -0
  341. package/src/accesslayer/share-link/reserve.ts +763 -0
  342. package/src/accesslayer/share-link/revoke.ts +232 -0
  343. package/src/accesslayer/share-link/transaction-execution.ts +72 -0
  344. package/src/accesslayer/share-link/transaction.ts +126 -0
  345. package/src/accesslayer/share-link/types.ts +606 -0
  346. package/src/app.ts +6 -0
  347. package/src/cache/app-store.caches.ts +35 -0
  348. package/src/config/applyDockerStageConfig.ts +6 -0
  349. package/src/config/environment.test.ts +17 -12
  350. package/src/config/environment.ts +15 -0
  351. package/src/config/serverlessFunctionEnv.test.ts +105 -0
  352. package/src/config/stageConfig.test.ts +25 -0
  353. package/src/config/stageConfig.ts +24 -0
  354. package/src/constants/auth-grant.ts +5 -0
  355. package/src/docker-entry.ts +81 -0
  356. package/src/helpers/app-manifest.helpers.ts +185 -0
  357. package/src/helpers/boost.helpers.ts +4 -31
  358. package/src/helpers/claim-hooks.helpers.ts +20 -7
  359. package/src/helpers/consent-referral.helpers.ts +6 -0
  360. package/src/helpers/consent-scopes.helpers.ts +58 -0
  361. package/src/helpers/contract-event-maintenance.helpers.ts +43 -0
  362. package/src/helpers/contract-events.helpers.ts +540 -0
  363. package/src/helpers/contract-requests.helpers.ts +211 -0
  364. package/src/helpers/credentialSubject.helpers.test.ts +114 -0
  365. package/src/helpers/credentialSubject.helpers.ts +40 -0
  366. package/src/helpers/finalize-inbox.helpers.ts +163 -44
  367. package/src/helpers/inbox.helpers.ts +58 -70
  368. package/src/helpers/inline-template.helpers.ts +560 -0
  369. package/src/helpers/notificationMessages.ts +77 -1
  370. package/src/helpers/notificationQueue.helpers.ts +23 -5
  371. package/src/helpers/notifications.helpers.ts +25 -1
  372. package/src/helpers/presentation-metadata.ts +41 -0
  373. package/src/helpers/presentation.helpers.ts +27 -20
  374. package/src/helpers/profile.helpers.ts +13 -0
  375. package/src/helpers/share-content-client/adapters.ts +55 -0
  376. package/src/helpers/share-content-client/canonical.ts +25 -0
  377. package/src/helpers/share-content-client/client.ts +440 -0
  378. package/src/helpers/share-content-client/config.ts +189 -0
  379. package/src/helpers/share-content-client/index.ts +27 -0
  380. package/src/helpers/share-content-client/responses.ts +273 -0
  381. package/src/helpers/share-content-client/types.ts +253 -0
  382. package/src/helpers/share-link-attachment-access.ts +87 -0
  383. package/src/helpers/share-link-attachment.ts +115 -0
  384. package/src/helpers/share-link-coordinator/attachment-stat.ts +41 -0
  385. package/src/helpers/share-link-coordinator/budget-helpers.ts +53 -0
  386. package/src/helpers/share-link-coordinator/cleanup-runner.ts +286 -0
  387. package/src/helpers/share-link-coordinator/coordinator.ts +727 -0
  388. package/src/helpers/share-link-coordinator/index.ts +8 -0
  389. package/src/helpers/share-link-coordinator/recovery-runner.ts +443 -0
  390. package/src/helpers/share-link-coordinator/runtime.ts +88 -0
  391. package/src/helpers/share-link-coordinator/stat.ts +30 -0
  392. package/src/helpers/share-link-coordinator/types.ts +353 -0
  393. package/src/helpers/share-link-lifecycle/index.ts +4 -0
  394. package/src/helpers/share-link-lifecycle/lease.helpers.ts +35 -0
  395. package/src/helpers/share-link-lifecycle/recovery.helpers.ts +173 -0
  396. package/src/helpers/share-link-lifecycle/request-hash.helpers.ts +130 -0
  397. package/src/helpers/share-link-lifecycle/types.ts +58 -0
  398. package/src/helpers/share-link-maintenance/budget.ts +63 -0
  399. package/src/helpers/share-link-maintenance/config.ts +312 -0
  400. package/src/helpers/share-link-maintenance/index.ts +24 -0
  401. package/src/helpers/share-link-maintenance/runner.ts +251 -0
  402. package/src/helpers/share-link-maintenance/runtime.ts +340 -0
  403. package/src/helpers/share-link-maintenance/scheduler.ts +126 -0
  404. package/src/helpers/share-link-maintenance/telemetry.ts +73 -0
  405. package/src/helpers/share-link-maintenance/types.ts +91 -0
  406. package/src/helpers/share-link-owner/config.ts +48 -0
  407. package/src/helpers/share-link-owner/diagnostics.ts +89 -0
  408. package/src/helpers/share-link-owner/lazy-initializer.ts +29 -0
  409. package/src/helpers/share-link-owner-projection.ts +54 -0
  410. package/src/helpers/share-link-passcode-abuse.ts +36 -0
  411. package/src/helpers/share-link-passcode.ts +47 -0
  412. package/src/helpers/share-link-policy/index.ts +7 -0
  413. package/src/helpers/share-link-policy/production.ts +108 -0
  414. package/src/helpers/share-link-policy/resolver.ts +113 -0
  415. package/src/helpers/share-link-policy/types.ts +56 -0
  416. package/src/helpers/share-link-public/config.ts +41 -0
  417. package/src/helpers/share-link-view-notification.ts +18 -0
  418. package/src/helpers/signingAuthority.helpers.ts +23 -14
  419. package/src/helpers/smartResume.helpers.ts +123 -0
  420. package/src/models/AppManifestVersion.ts +43 -0
  421. package/src/models/AppStoreListing.ts +32 -0
  422. package/src/models/ConsentFlowContract.ts +34 -3
  423. package/src/models/ConsentFlowTerms.ts +10 -0
  424. package/src/models/ConsentFlowTransaction.ts +3 -0
  425. package/src/models/Integration.ts +2 -0
  426. package/src/models/Presentation.ts +2 -2
  427. package/src/models/Profile.ts +3 -2
  428. package/src/models/ShareLink.ts +134 -0
  429. package/src/models/ShareViewReceipt.ts +69 -0
  430. package/src/models/index.ts +25 -0
  431. package/src/models/share-link-constraints.ts +98 -0
  432. package/src/openapi.ts +44 -8
  433. package/src/public-share-link-http.ts +49 -0
  434. package/src/routes/app-store.ts +1056 -38
  435. package/src/routes/boosts.ts +14 -25
  436. package/src/routes/contracts.ts +384 -273
  437. package/src/routes/inbox.ts +4 -2
  438. package/src/routes/index.ts +142 -44
  439. package/src/routes/presentations.ts +19 -3
  440. package/src/routes/profile-manager.ts +29 -2
  441. package/src/routes/profiles.ts +29 -6
  442. package/src/routes/public-share-links.ts +983 -0
  443. package/src/routes/share-links.ts +709 -0
  444. package/src/routes/workflows.ts +3 -2
  445. package/src/services/delivery/adapters/postmark.adapter.ts +4 -1
  446. package/src/types/app-manifest.ts +28 -0
  447. package/src/types/app-store-listing.ts +13 -0
  448. package/src/types/consentflowcontract.ts +25 -4
  449. package/test/app-manifest.helpers.spec.ts +170 -0
  450. package/test/app-manifest.routes.spec.ts +299 -0
  451. package/test/app-store-listing-updates.spec.ts +236 -0
  452. package/test/app-store-listing.spec.ts +65 -3
  453. package/test/consent-data-boundaries.spec.ts +352 -0
  454. package/test/consent-recipients.spec.ts +513 -0
  455. package/test/consent-scopes.helpers.spec.ts +67 -0
  456. package/test/consentflow.spec.ts +63 -2
  457. package/test/contract-requests.spec.ts +1588 -0
  458. package/test/credential-storage.neo4j.spec.ts +122 -0
  459. package/test/dids.spec.ts +10 -1
  460. package/test/guardian-gated-routes.spec.ts +49 -0
  461. package/test/helpers/share-link-fixtures.ts +94 -0
  462. package/test/inbox-security.e2e.ts +26 -10
  463. package/test/inbox.spec.ts +184 -8
  464. package/test/inline-template.helpers.spec.ts +49 -0
  465. package/test/managed-recipient-inbox.spec.ts +152 -0
  466. package/test/notificationMessages.spec.ts +13 -0
  467. package/test/openapi.spec.ts +14 -53
  468. package/test/presentations.spec.ts +54 -6
  469. package/test/profiles.spec.ts +97 -1
  470. package/test/share-content-client.contract.spec.ts +365 -0
  471. package/test/share-content-client.unit.spec.ts +462 -0
  472. package/test/share-link-abuse.unit.spec.ts +65 -0
  473. package/test/share-link-attachment.neo4j.spec.ts +262 -0
  474. package/test/share-link-attachment.unit.spec.ts +244 -0
  475. package/test/share-link-coordinator.neo4j.spec.ts +684 -0
  476. package/test/share-link-coordinator.unit.spec.ts +990 -0
  477. package/test/share-link-dependency-diagnostics.unit.spec.ts +127 -0
  478. package/test/share-link-lifecycle.neo4j.spec.ts +1411 -0
  479. package/test/share-link-lifecycle.unit.spec.ts +205 -0
  480. package/test/share-link-list-cursor.unit.spec.ts +86 -0
  481. package/test/share-link-list.neo4j.spec.ts +324 -0
  482. package/test/share-link-maintenance.neo4j.spec.ts +355 -0
  483. package/test/share-link-maintenance.unit.spec.ts +1140 -0
  484. package/test/share-link-owner-policy.unit.spec.ts +210 -0
  485. package/test/share-link-owner-route.unit.spec.ts +820 -0
  486. package/test/share-link-owner-runtime.unit.spec.ts +102 -0
  487. package/test/share-link-passcode.unit.spec.ts +29 -0
  488. package/test/share-link-policy.unit.spec.ts +149 -0
  489. package/test/share-link-presentation-metadata.unit.spec.ts +49 -0
  490. package/test/share-link-production-policy.unit.spec.ts +126 -0
  491. package/test/share-link-public-config.unit.spec.ts +64 -0
  492. package/test/share-link-public-http-adapter.unit.spec.ts +315 -0
  493. package/test/share-link-public-route.unit.spec.ts +1079 -0
  494. package/test/share-link-receipt.neo4j.spec.ts +943 -0
  495. package/test/share-link-recovery.neo4j.spec.ts +935 -0
  496. package/test/share-link-recovery.unit.spec.ts +726 -0
  497. package/test/share-link-service-policy.neo4j.spec.ts +403 -0
  498. package/test/signing-authority-encryption.spec.ts +75 -0
  499. package/test/smart-resume-consent.spec.ts +233 -0
  500. package/test/smart-resume-upload.spec.ts +65 -0
  501. package/tsconfig.build.json +1 -1
  502. package/tsconfig.json +1 -0
  503. package/vitest.config.ts +14 -0
  504. package/vitest.inbox-e2e.config.ts +2 -0
  505. package/vitest.share-links-neo4j.config.ts +19 -0
  506. package/vitest.share-links-unit.config.ts +28 -0
  507. package/workerLambda.test.ts +100 -0
@@ -0,0 +1,108 @@
1
+ import { getProfileByProfileId } from '@accesslayer/profile/read';
2
+ import { isProfileManaged } from '@accesslayer/profile/relationships/read';
3
+ import type { ShareViewEligibilitySource } from '@accesslayer/share-link/types';
4
+ import type { ShareLinkTransaction } from '@accesslayer/share-link/transaction';
5
+ import {
6
+ isServiceProfileExemptFromGuardianship,
7
+ transformProfileId,
8
+ } from '@helpers/profile.helpers';
9
+
10
+ import { composeShareLinkPolicy } from './resolver';
11
+ import type { CurrentShareLinkPolicy, ShareLinkOwnerAge, ShareLinkPolicySource } from './types';
12
+
13
+ const ADULT_AGE = 18;
14
+
15
+ /** Classify persisted human age without inventing a birthdate for service profiles. */
16
+ export const ageFromPersistedProfile = (
17
+ profile: { dob?: unknown; type?: unknown } | null,
18
+ now: Date = new Date()
19
+ ): ShareLinkOwnerAge => {
20
+ if (!profile) return 'unknown';
21
+ if (profile.type === 'child') return 'minor';
22
+ if (typeof profile.dob !== 'string' || !/^\d{4}-\d{2}-\d{2}$/.test(profile.dob)) {
23
+ return 'unknown';
24
+ }
25
+
26
+ const year = Number(profile.dob.slice(0, 4));
27
+ const month = Number(profile.dob.slice(5, 7));
28
+ const day = Number(profile.dob.slice(8, 10));
29
+ const birthday = new Date(Date.UTC(year, month - 1, day));
30
+ if (
31
+ birthday.getUTCFullYear() !== year ||
32
+ birthday.getUTCMonth() !== month - 1 ||
33
+ birthday.getUTCDate() !== day ||
34
+ birthday.getTime() > now.getTime()
35
+ ) {
36
+ return 'unknown';
37
+ }
38
+
39
+ const age =
40
+ now.getUTCFullYear() -
41
+ year -
42
+ (now.getUTCMonth() + 1 < month ||
43
+ (now.getUTCMonth() + 1 === month && now.getUTCDate() < day)
44
+ ? 1
45
+ : 0);
46
+
47
+ return age >= ADULT_AGE ? 'adult' : 'minor';
48
+ };
49
+
50
+ /**
51
+ * Personal profiles require a valid persisted birthdate for tracking. Service
52
+ * profiles are age-exempt, but an explicit child type always keeps protections.
53
+ */
54
+ export const createProductionShareLinkPolicySource = (): ShareLinkPolicySource => ({
55
+ resolveOwner: async profileId => {
56
+ const profile = await getProfileByProfileId(profileId);
57
+ const isServiceProfile = isServiceProfileExemptFromGuardianship(
58
+ profile?.isServiceProfile,
59
+ profile?.type
60
+ );
61
+ const isManaged = await isProfileManaged(profileId);
62
+ return {
63
+ age: ageFromPersistedProfile(profile),
64
+ isServiceProfile,
65
+ isManaged,
66
+ };
67
+ },
68
+ });
69
+
70
+ /** Read current eligibility within the share lock; no request values or network I/O. */
71
+ export const resolveCurrentShareLinkPolicy = async (
72
+ tx: ShareLinkTransaction,
73
+ ownerProfileId: string,
74
+ now: Date
75
+ ): Promise<CurrentShareLinkPolicy> => {
76
+ const result = await tx.run(
77
+ `MATCH (p:Profile {profileId: $profileId})
78
+ OPTIONAL MATCH (p)-[:MANAGED_BY]->(directManager:Profile)
79
+ OPTIONAL MATCH (manager:ProfileManager)-[:MANAGES]->(p)
80
+ RETURN p.dob AS dob, p.type AS profileType,
81
+ p.isServiceProfile AS isServiceProfile,
82
+ (directManager IS NOT NULL OR manager IS NOT NULL) AS isManaged
83
+ LIMIT 1`,
84
+ { profileId: transformProfileId(ownerProfileId) }
85
+ );
86
+ const record = result.records[0];
87
+ if (!record) return { ...composeShareLinkPolicy('unknown', true), isServiceProfile: false };
88
+
89
+ const profileType = record.get('profileType');
90
+ const isServiceProfile = isServiceProfileExemptFromGuardianship(
91
+ record.get('isServiceProfile'),
92
+ profileType
93
+ );
94
+ return {
95
+ ...composeShareLinkPolicy(
96
+ ageFromPersistedProfile({ dob: record.get('dob'), type: profileType }, now),
97
+ record.get('isManaged') !== false,
98
+ isServiceProfile
99
+ ),
100
+ isServiceProfile,
101
+ };
102
+ };
103
+
104
+ export const productionShareViewEligibilitySource: ShareViewEligibilitySource = {
105
+ isEligible: async (tx, input) =>
106
+ (await resolveCurrentShareLinkPolicy(tx, input.ownerProfileId, input.now))
107
+ .viewCountingEnabled,
108
+ };
@@ -0,0 +1,113 @@
1
+ import { DEFAULT_SHARE_LINK_POLICY } from './types';
2
+ import type {
3
+ ShareLinkOwnerAge,
4
+ ShareLinkPolicyResolver,
5
+ ShareLinkPolicySnapshot,
6
+ ShareLinkPolicySource,
7
+ } from './types';
8
+
9
+ /**
10
+ * Pure policy decision table.
11
+ *
12
+ * - personal known minor, managed or unknown age => no views, 30 days
13
+ * - known unmanaged adult => views enabled, 365 days
14
+ * - service profile => views enabled without changing the age-derived expiry
15
+ */
16
+ export const composeShareLinkPolicy = (
17
+ age: ShareLinkOwnerAge,
18
+ isManaged: boolean,
19
+ isServiceProfile = false
20
+ ): ShareLinkPolicySnapshot => {
21
+ // Service age exemption does not establish that the owner is an adult.
22
+ const isMinor = isServiceProfile
23
+ ? false
24
+ : age === 'minor'
25
+ ? true
26
+ : age === 'adult'
27
+ ? false
28
+ : null;
29
+ const policyResolved = isServiceProfile || age !== 'unknown';
30
+ const isUnmanagedAdult = age === 'adult' && !isManaged;
31
+
32
+ return {
33
+ isMinor,
34
+ policyResolved,
35
+ defaultExpiryDays: isUnmanagedAdult ? 365 : 30,
36
+ viewCountingEnabled: isServiceProfile || isUnmanagedAdult,
37
+ };
38
+ };
39
+
40
+ /**
41
+ * Build an injectable resolver over an authoritative source. Any source failure
42
+ * fails closed to the conservative default rather than assuming adult.
43
+ */
44
+ export const createShareLinkPolicyResolver = (
45
+ source: ShareLinkPolicySource
46
+ ): ShareLinkPolicyResolver => ({
47
+ resolve: async (profileId: string): Promise<ShareLinkPolicySnapshot> => {
48
+ try {
49
+ const { age, isManaged, isServiceProfile } = await source.resolveOwner(profileId);
50
+
51
+ return composeShareLinkPolicy(age, isManaged, isServiceProfile);
52
+ } catch {
53
+ return DEFAULT_SHARE_LINK_POLICY;
54
+ }
55
+ },
56
+ });
57
+
58
+ const DAY_MS = 24 * 60 * 60 * 1000;
59
+
60
+ /**
61
+ * Effective expiry: an explicit caller value (including explicit `null`) is
62
+ * preserved; only an omitted value receives the policy default. The default is
63
+ * derived from the policy at first reservation and then persisted, so a retry on
64
+ * a later clock replays the original value.
65
+ */
66
+ export const resolveShareLinkExpiry = (
67
+ policy: ShareLinkPolicySnapshot,
68
+ expiresAt: string | null | undefined,
69
+ now: Date
70
+ ): string | null => {
71
+ if (expiresAt !== undefined) return expiresAt;
72
+
73
+ return new Date(now.getTime() + policy.defaultExpiryDays * DAY_MS).toISOString();
74
+ };
75
+
76
+ /**
77
+ * Conservatively merge a share's currently committed policy with the policy a
78
+ * reservation intends to apply at finalization.
79
+ *
80
+ * A reservation can be created before the owner's authoritative policy changes
81
+ * and then finalized later by a replay or a recovery worker. Applying the stale
82
+ * reservation policy verbatim could re-enable view counting for an owner who has
83
+ * since become managed/minor. The merge therefore only ever tightens:
84
+ *
85
+ * - view counting stays enabled only if BOTH policies allow it;
86
+ * - a known minor on either side is a minor, an unknown on either side is
87
+ * unknown (never inferred adult);
88
+ * - the default expiry is the shorter of the two.
89
+ *
90
+ * Production finalization also rechecks current graph policy under the share
91
+ * lock before an explicit update can replace an old unknown snapshot.
92
+ */
93
+ export const mergeShareLinkPolicyConservatively = (
94
+ current: ShareLinkPolicySnapshot,
95
+ incoming: ShareLinkPolicySnapshot
96
+ ): ShareLinkPolicySnapshot => {
97
+ const isMinor =
98
+ current.isMinor === true || incoming.isMinor === true
99
+ ? true
100
+ : current.isMinor === false && incoming.isMinor === false
101
+ ? false
102
+ : null;
103
+
104
+ return {
105
+ isMinor,
106
+ policyResolved: current.policyResolved && incoming.policyResolved,
107
+ defaultExpiryDays:
108
+ current.defaultExpiryDays <= incoming.defaultExpiryDays
109
+ ? current.defaultExpiryDays
110
+ : incoming.defaultExpiryDays,
111
+ viewCountingEnabled: current.viewCountingEnabled && incoming.viewCountingEnabled,
112
+ };
113
+ };
@@ -0,0 +1,56 @@
1
+ /**
2
+ * LC-2187 owner share-link policy types.
3
+ *
4
+ * Policy is always derived server-side from trusted persisted state; nothing in
5
+ * this module reads the request body. The conservative default (unknown age,
6
+ * 30-day expiry, no view counting) is what an unavailable or untrustworthy age
7
+ * source produces — absence of a manager is NOT evidence of adulthood.
8
+ */
9
+
10
+ /** Result of consulting the authoritative server-side age source. */
11
+ export type ShareLinkOwnerAge = 'adult' | 'minor' | 'unknown';
12
+
13
+ /** Immutable policy snapshot persisted with the share under the write lock. */
14
+ export type ShareLinkPolicySnapshot = {
15
+ /** `true` known minor, `false` known adult/service profile, `null` unknown. */
16
+ isMinor: boolean | null;
17
+ /** `true` when age is known or a persisted service profile is age-exempt. */
18
+ policyResolved: boolean;
19
+ defaultExpiryDays: 30 | 365;
20
+ viewCountingEnabled: boolean;
21
+ };
22
+
23
+ /** Fresh graph-local classification; never persisted or inferred from an old snapshot. */
24
+ export type CurrentShareLinkPolicy = ShareLinkPolicySnapshot & {
25
+ isServiceProfile: boolean;
26
+ };
27
+
28
+ /**
29
+ * Authoritative server-side sources. Implementations must read persisted server
30
+ * state only; no request-derived value may be used as authority.
31
+ */
32
+ export type ShareLinkPolicySource = {
33
+ /**
34
+ * Read age, service classification and management from persisted state.
35
+ * Service profiles may bypass tracking age checks; explicitly typed children
36
+ * must never be classified as service profiles here.
37
+ */
38
+ resolveOwner: (profileId: string) => Promise<{
39
+ age: ShareLinkOwnerAge;
40
+ isManaged: boolean;
41
+ isServiceProfile: boolean;
42
+ }>;
43
+ };
44
+
45
+ /** Injectable server-side policy resolver used by the coordinator. */
46
+ export type ShareLinkPolicyResolver = {
47
+ resolve: (profileId: string) => Promise<ShareLinkPolicySnapshot>;
48
+ };
49
+
50
+ /** Fail-closed policy: no views, 30 days, age unknown. */
51
+ export const DEFAULT_SHARE_LINK_POLICY: ShareLinkPolicySnapshot = Object.freeze({
52
+ isMinor: null,
53
+ policyResolved: false,
54
+ defaultExpiryDays: 30,
55
+ viewCountingEnabled: false,
56
+ });
@@ -0,0 +1,41 @@
1
+ import {
2
+ hasShareLinkServiceTransportConfig,
3
+ resolveShareLinkServiceTransportConfig,
4
+ } from '../share-link-maintenance/config';
5
+
6
+ /**
7
+ * Available automatically once trusted service configuration is complete.
8
+ * Namespace, origin and audience come only from server configuration. Missing
9
+ * wiring is inactive; partial or invalid wiring fails closed.
10
+ */
11
+
12
+ export type ShareLinkPublicApiConfigResolution =
13
+ | { status: 'disabled' }
14
+ | { status: 'invalid' }
15
+ | {
16
+ status: 'enabled';
17
+ namespace: string;
18
+ origin: string;
19
+ audience: string;
20
+ allowInsecureLoopback: boolean;
21
+ };
22
+
23
+ export const resolveShareLinkPublicApiConfig = (
24
+ raw: unknown
25
+ ): ShareLinkPublicApiConfigResolution => {
26
+ if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) return { status: 'invalid' };
27
+
28
+ const source = raw as Record<string, unknown>;
29
+ if (!hasShareLinkServiceTransportConfig(source)) return { status: 'disabled' };
30
+
31
+ const transport = resolveShareLinkServiceTransportConfig(source);
32
+ if (transport.status !== 'enabled') return { status: 'invalid' };
33
+
34
+ return {
35
+ status: 'enabled',
36
+ namespace: transport.config.namespace,
37
+ origin: transport.config.origin,
38
+ audience: transport.config.audience,
39
+ allowInsecureLoopback: transport.config.allowInsecureLoopback,
40
+ };
41
+ };
@@ -0,0 +1,18 @@
1
+ import cache from '@cache';
2
+ import { environment } from '@environment';
3
+
4
+ const WINDOW_SECONDS = 10 * 60;
5
+
6
+ /** One owner alert per share per window, claimed atomically across Brain workers. */
7
+ export const claimShareViewNotification = async (
8
+ namespace: string,
9
+ shareId: string
10
+ ): Promise<boolean> => {
11
+ if (environment.NODE_ENV === 'production' && !cache.redis) return false;
12
+ const count = await cache.incr(
13
+ `share-link-view-notification:${namespace}:${shareId}`,
14
+ WINDOW_SECONDS
15
+ );
16
+ // A cache failure suppresses alerts, never privacy enforcement or view counts.
17
+ return count === 1;
18
+ };
@@ -1,6 +1,10 @@
1
1
  import { environment } from '@environment';
2
2
  import { Agent, fetch as undiciFetch, type Response as UndiciResponse } from 'undici';
3
- import { getDidWebLearnCard, getLearnCard } from '@helpers/learnCard.helpers';
3
+ import {
4
+ createDagJweForRecipients,
5
+ getDidWebLearnCard,
6
+ getLearnCard,
7
+ } from '@helpers/learnCard.helpers';
4
8
  import { getDidWeb } from '@helpers/did.helpers';
5
9
  import { VCValidator, JWEValidator } from '@learncard/types';
6
10
  import type { UnsignedVC, VC, JWE } from '@learncard/types';
@@ -113,9 +117,17 @@ const getSaAgent = (): Agent => {
113
117
  return _saAgent;
114
118
  };
115
119
 
116
- const _mockIssueCredentialWithSigningAuthority = async (credential: UnsignedVC): Promise<VC> => {
120
+ const _mockIssueCredentialWithSigningAuthority = async (
121
+ credential: UnsignedVC,
122
+ recipients?: string[]
123
+ ): Promise<VC | JWE> => {
117
124
  const learnCard = await getLearnCard();
118
- return learnCard.invoke.issueCredential({ ...credential, issuer: learnCard.id.did() });
125
+ const signedCredential = await learnCard.invoke.issueCredential({
126
+ ...credential,
127
+ issuer: learnCard.id.did(),
128
+ });
129
+
130
+ return recipients ? createDagJweForRecipients(signedCredential, recipients) : signedCredential;
119
131
  };
120
132
 
121
133
  export async function issueCredentialWithSigningAuthority(
@@ -151,6 +163,10 @@ export async function issueCredentialWithSigningAuthority(
151
163
  retryable: false,
152
164
  });
153
165
  }
166
+ // The validation above excludes undefined subject IDs on the encrypted path.
167
+ const encryptionRecipients = encrypt
168
+ ? [...new Set([...(subjectIds as string[]), ownerDid, ...additionalEncryptionRecipients])]
169
+ : undefined;
154
170
  const credentialToIssue = appendCredentialStatus
155
171
  ? await appendBitstringStatusListEntries(credential, ownerProfile.profileId, domain)
156
172
  : credential;
@@ -177,7 +193,8 @@ export async function issueCredentialWithSigningAuthority(
177
193
  try {
178
194
  if (IS_TEST_ENVIRONMENT) {
179
195
  return await _mockIssueCredentialWithSigningAuthority(
180
- JSON.parse(serializedCredential)
196
+ JSON.parse(serializedCredential),
197
+ encryptionRecipients
181
198
  );
182
199
  }
183
200
 
@@ -189,16 +206,8 @@ export async function issueCredentialWithSigningAuthority(
189
206
  perf.mark('initDid');
190
207
 
191
208
  // Brain authenticates the request but must not be able to decrypt the response.
192
- const encryption = encrypt
193
- ? {
194
- recipients: [
195
- ...new Set([
196
- ...subjectIds,
197
- ownerDid,
198
- ...additionalEncryptionRecipients,
199
- ]),
200
- ],
201
- }
209
+ const encryption = encryptionRecipients
210
+ ? { recipients: encryptionRecipients }
202
211
  : undefined;
203
212
 
204
213
  const didJwt = await traceCrypto('getDidAuthVp', () =>
@@ -0,0 +1,123 @@
1
+ import { environment } from '@environment';
2
+ import { ConsentFlowTermsValidator, type ConsentFlowTerms } from '@learncard/types';
3
+ import { resolveUri } from '@helpers/uri.helpers';
4
+
5
+ /** Publish only the terms returned by the locked consent/publication claim. */
6
+ export const uploadSmartResume = async (
7
+ terms: ConsentFlowTerms,
8
+ did: string,
9
+ recipientToken: string
10
+ ): Promise<string | undefined> => {
11
+ const isProduction = !environment.IS_OFFLINE;
12
+
13
+ const srUrl = isProduction ? 'https://my.smartresume.com/' : 'https://mystage.smartresume.com/';
14
+ const clientId = environment.SMART_RESUME_CLIENT_ID;
15
+ const accessKey = environment.SMART_RESUME_ACCESS_KEY;
16
+
17
+ const accessTokenResponse = (await fetch(`${srUrl}api/v1/token`, {
18
+ method: 'POST',
19
+ signal: AbortSignal.timeout(30_000),
20
+ headers: {
21
+ 'Content-Type': 'application/x-www-form-urlencoded',
22
+ Authorization: `Basic ${btoa(`${clientId}:${accessKey}`)}`,
23
+ },
24
+ body: new URLSearchParams({
25
+ grant_type: 'client_credentials',
26
+ scope: 'delete readonly replace',
27
+ }),
28
+ }).then(res => {
29
+ if (!res.ok) throw new Error(`SmartResume token request failed (${res.status})`);
30
+ return res.json();
31
+ })) as { access_token?: string };
32
+
33
+ const accessToken = accessTokenResponse.access_token;
34
+ if (!accessToken) throw new Error('Missing access_token for SmartResume');
35
+
36
+ const parsedTerms = ConsentFlowTermsValidator.parse(terms);
37
+
38
+ const categories = parsedTerms.read.credentials.categories;
39
+ const categoryValues = Object.values(categories) as Array<{ shared?: string[] }>;
40
+
41
+ const allSharedCredentialUris = [
42
+ // filter out duplicates
43
+ ...new Set(categoryValues.flatMap(({ shared }) => shared ?? [])),
44
+ ];
45
+
46
+ const resolvedCredentials = await Promise.all(
47
+ allSharedCredentialUris.map(async uri => {
48
+ let timer: ReturnType<typeof setTimeout> | undefined;
49
+ try {
50
+ return await Promise.race([
51
+ resolveUri(uri),
52
+ new Promise<never>((_, reject) => {
53
+ timer = setTimeout(
54
+ () => reject(new Error('Credential resolution timed out')),
55
+ 30_000
56
+ );
57
+ }),
58
+ ]);
59
+ } finally {
60
+ clearTimeout(timer);
61
+ }
62
+ })
63
+ );
64
+
65
+ type ResolvedCredential = {
66
+ issuer?: string | { id: string };
67
+ id?: string;
68
+ boostCredential?: Record<string, unknown>;
69
+ } & Record<string, unknown>;
70
+
71
+ const credentials = resolvedCredentials
72
+ .filter((cred): cred is ResolvedCredential => typeof cred === 'object' && cred !== null)
73
+ .map(cred =>
74
+ cred.boostCredential && typeof cred.boostCredential === 'object'
75
+ ? ({ ...cred.boostCredential, id: cred.id } as ResolvedCredential) // unwrap credential, preserve id
76
+ : cred
77
+ );
78
+
79
+ const transformedCredentials = credentials.map(cred => {
80
+ const issuer =
81
+ typeof cred.issuer === 'string' ? { id: cred.issuer } : cred.issuer || { id: '' };
82
+
83
+ return {
84
+ ...cred,
85
+ issuer,
86
+ };
87
+ });
88
+
89
+ const { name, email } = parsedTerms.read.personal;
90
+
91
+ const body = JSON.stringify({
92
+ '@context': [
93
+ 'https://www.w3.org/ns/credentials/v2',
94
+ 'https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json',
95
+ 'https://w3id.org/security/suites/ed25519-2020/v1',
96
+ ],
97
+ recipienttoken: recipientToken,
98
+ recipient: {
99
+ id: did,
100
+ givenName: name && name !== 'Anonymous' ? name : '',
101
+ familyName: '', // this is necessary in order for givenName to be respected
102
+ email: email && email !== 'anonymous@hidden.com' ? email : '',
103
+ },
104
+ credentials: transformedCredentials,
105
+ });
106
+
107
+ const response = await fetch(`${srUrl}api/v1/credentials`, {
108
+ method: 'POST',
109
+ signal: AbortSignal.timeout(30_000),
110
+ headers: {
111
+ Authorization: `Bearer ${accessToken}`,
112
+ 'Content-Type': 'application/json',
113
+ },
114
+ body,
115
+ });
116
+
117
+ if (!response.ok) {
118
+ throw new Error(`SmartResume upload failed (${response.status})`);
119
+ }
120
+
121
+ const result = (await response.json()) as { redirect_url?: string };
122
+ return result.redirect_url;
123
+ };
@@ -0,0 +1,43 @@
1
+ import { ModelFactory, ModelRelatedNodesI, NeogmaInstance } from 'neogma';
2
+
3
+ import { neogma } from '@instance';
4
+
5
+ import { FlatAppManifestVersionType } from 'types/app-manifest';
6
+ import { Integration, IntegrationInstance } from './Integration';
7
+ import { AppStoreListing, AppStoreListingInstance } from './AppStoreListing';
8
+
9
+ export type AppManifestVersionRelationships = {
10
+ integration: ModelRelatedNodesI<typeof Integration, IntegrationInstance>;
11
+ listing: ModelRelatedNodesI<typeof AppStoreListing, AppStoreListingInstance>;
12
+ };
13
+
14
+ export type AppManifestVersionInstance = NeogmaInstance<
15
+ FlatAppManifestVersionType,
16
+ AppManifestVersionRelationships
17
+ >;
18
+
19
+ export const AppManifestVersion = ModelFactory<
20
+ FlatAppManifestVersionType,
21
+ AppManifestVersionRelationships
22
+ >(
23
+ {
24
+ label: 'AppManifestVersion',
25
+ schema: {
26
+ id: { type: 'string', required: true, uniqueItems: true },
27
+ version: { type: 'number', required: true },
28
+ manifestHash: { type: 'string', required: true },
29
+ manifestJson: { type: 'string', required: true },
30
+ status: { type: 'string', enum: ['draft', 'active', 'superseded'], required: true },
31
+ createdAt: { type: 'string', required: true },
32
+ activatedAt: { type: 'string', required: false },
33
+ },
34
+ relationships: {
35
+ integration: { model: Integration, direction: 'in', name: 'HAS_MANIFEST_VERSION' },
36
+ listing: { model: AppStoreListing, direction: 'in', name: 'USES_MANIFEST_VERSION' },
37
+ },
38
+ primaryKeyField: 'id',
39
+ },
40
+ neogma
41
+ );
42
+
43
+ export default AppManifestVersion;
@@ -6,13 +6,16 @@ import { Integration, IntegrationInstance } from './Integration';
6
6
  import { Profile, ProfileInstance } from './Profile';
7
7
  import { Boost, BoostInstance } from './Boost';
8
8
  import { Credential, CredentialInstance } from './Credential';
9
+ import { ConsentFlowContract, ConsentFlowInstance } from './ConsentFlowContract';
9
10
  import { SigningAuthority, SigningAuthorityInstance } from './SigningAuthority';
11
+ import type { AppManifestVersion, AppManifestVersionInstance } from './AppManifestVersion';
10
12
  import {
11
13
  FlatAppStoreListingType,
12
14
  AppListingStatus,
13
15
  LaunchType,
14
16
  PromotionLevel,
15
17
  AgeRating,
18
+ PendingListingUpdateStatus,
16
19
  } from 'types/app-store-listing';
17
20
 
18
21
  export type AppStoreListingRelationships = {
@@ -73,6 +76,13 @@ export type AppStoreListingRelationships = {
73
76
  { name: string; did: string; isPrimary?: boolean },
74
77
  { name: string; did: string; isPrimary?: boolean }
75
78
  >;
79
+ hasConsentContract: ModelRelatedNodesI<
80
+ typeof ConsentFlowContract,
81
+ ConsentFlowInstance,
82
+ { scopeHash: string; createdAt: string },
83
+ { scopeHash: string; createdAt: string }
84
+ >;
85
+ usesManifestVersion: ModelRelatedNodesI<typeof AppManifestVersion, AppManifestVersionInstance>;
76
86
  };
77
87
 
78
88
  export type AppStoreListingInstance = NeogmaInstance<
@@ -114,6 +124,13 @@ export const AppStoreListing = ModelFactory<FlatAppStoreListingType, AppStoreLis
114
124
  min_age: { type: 'number', required: false },
115
125
  age_rating: { type: 'string', enum: AgeRating.options, required: false },
116
126
  contact_email: { type: 'string', required: false },
127
+ pending_update_json: { type: 'string', required: false },
128
+ pending_update_status: {
129
+ type: 'string',
130
+ enum: PendingListingUpdateStatus.options,
131
+ required: false,
132
+ },
133
+ pending_update_submitted_at: { type: 'string', required: false },
117
134
  } as any,
118
135
  relationships: {
119
136
  publishedBy: { model: Integration, direction: 'in', name: 'PUBLISHES_LISTING' },
@@ -204,6 +221,21 @@ export const AppStoreListing = ModelFactory<FlatAppStoreListingType, AppStoreLis
204
221
  },
205
222
  },
206
223
  },
224
+ hasConsentContract: {
225
+ model: ConsentFlowContract,
226
+ direction: 'out',
227
+ name: 'HAS_CONSENT_CONTRACT',
228
+ properties: {
229
+ scopeHash: {
230
+ property: 'scopeHash',
231
+ schema: { type: 'string', required: true },
232
+ },
233
+ createdAt: {
234
+ property: 'createdAt',
235
+ schema: { type: 'string', required: true },
236
+ },
237
+ },
238
+ },
207
239
  },
208
240
  primaryKeyField: 'listing_id',
209
241
  },