@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,251 @@
1
+ import type {
2
+ CleanupRunnerDependencies,
3
+ RecoveryRunnerDependencies,
4
+ } from '../share-link-coordinator';
5
+ import { runShareContentCleanupOnce } from '../share-link-coordinator/cleanup-runner';
6
+ import { budgetAllows } from '../share-link-coordinator/budget-helpers';
7
+ import { runShareLinkRecoveryOnce } from '../share-link-coordinator/recovery-runner';
8
+ import type { ShareContentClient } from '../share-content-client/types';
9
+ import type { PruneShareViewReceiptsInput } from '../../accesslayer/share-link/types';
10
+ import {
11
+ createMaintenancePassBudget,
12
+ resolveMaintenanceBudgetMs,
13
+ type MaintenancePassBudget,
14
+ } from './budget';
15
+ import { safeLogMaintenance } from './telemetry';
16
+ import type {
17
+ ShareLinkMaintenanceConfig,
18
+ ShareLinkMaintenanceFailureCategory,
19
+ ShareLinkMaintenanceLogger,
20
+ ShareLinkMaintenanceRunSummary,
21
+ } from './types';
22
+
23
+ export type ShareLinkMaintenanceRunnerDependencies = {
24
+ config: ShareLinkMaintenanceConfig;
25
+ recoveryRepository: RecoveryRunnerDependencies['repository'];
26
+ cleanupRepository: CleanupRunnerDependencies['repository'];
27
+ /**
28
+ * Namespace-scoped, bounded receipt prune. Injected so DB-free unit tests
29
+ * never load the Neo4j `@instance`; production passes the real repository.
30
+ */
31
+ pruneReceipts: (input: PruneShareViewReceiptsInput) => Promise<number>;
32
+ expireAttachmentStages?: typeof import('../../accesslayer/share-link/attachment').expireShareAttachmentStages;
33
+ client: Pick<ShareContentClient, 'stat' | 'delete'>;
34
+ logger: ShareLinkMaintenanceLogger;
35
+ /** Monotonic clock for the cooperative budget; injectable for tests. */
36
+ monotonicNow?: () => number;
37
+ /** Wall clock passed through to the repositories; production omits it. */
38
+ now?: () => Date;
39
+ /**
40
+ * Optional Lambda remaining-time source, in milliseconds. Ignored when a
41
+ * pre-started `budget` is supplied.
42
+ */
43
+ remainingTimeMs?: () => number;
44
+ /**
45
+ * Optional budget already started by the runtime BEFORE dependency
46
+ * initialization. Reused so a slow cold start consumes the invocation
47
+ * deadline rather than receiving a fresh post-setup budget.
48
+ */
49
+ budget?: MaintenancePassBudget;
50
+ };
51
+
52
+ /**
53
+ * Bounded graph cost of the very first recovery stage (discovery read). If this
54
+ * does not fit, neither recovery nor cleanup can start.
55
+ */
56
+ const recoveryDiscoveryCostMs = (config: ShareLinkMaintenanceConfig): number =>
57
+ config.graphTimeoutMs;
58
+
59
+ /**
60
+ * Worst-case bounded cost of one whole cleanup unit:
61
+ * claim (graph) + delete (HTTP) + complete (graph).
62
+ */
63
+ const cleanupUnitCostMs = (config: ShareLinkMaintenanceConfig): number =>
64
+ config.requestTimeoutMs + 2 * config.graphTimeoutMs;
65
+
66
+ /**
67
+ * Bounded cost of one namespace-scoped receipt-prune read transaction.
68
+ */
69
+ const receiptPruneCostMs = (config: ShareLinkMaintenanceConfig): number => config.graphTimeoutMs;
70
+
71
+ /**
72
+ * One bounded maintenance invocation: namespace-scoped recovery followed by
73
+ * namespace-scoped cleanup, each with its own count limit and a shared elapsed
74
+ * deadline.
75
+ *
76
+ * The deadline is cooperative (see `createMaintenancePassBudget`): it is checked
77
+ * before every claim, never enforced with `Promise.race`, so a remote delete or
78
+ * graph mutation that has already started is always awaited to a tracked result.
79
+ * Admission requires the remaining time to cover the whole next unit — the
80
+ * claim, the bounded HTTP call and the finalizing graph write — plus the
81
+ * finalization/telemetry reserve. The HTTP allowance is fixed when the transport
82
+ * client is built, so it cannot be shrunk per call; graph transaction timeouts
83
+ * are dynamically capped to the time actually left.
84
+ *
85
+ * Every failure is folded into a fixed category; the summary exposes aggregate
86
+ * counts and durations only.
87
+ */
88
+ export const runShareLinkMaintenancePass = async (
89
+ dependencies: ShareLinkMaintenanceRunnerDependencies
90
+ ): Promise<ShareLinkMaintenanceRunSummary> => {
91
+ const { config, logger } = dependencies;
92
+
93
+ const budget =
94
+ dependencies.budget ??
95
+ createMaintenancePassBudget({
96
+ budgetMs: resolveMaintenanceBudgetMs(config.budgetMs, dependencies.remainingTimeMs?.()),
97
+ finalizeReserveMs: config.finalizeReserveMs,
98
+ monotonicNow: dependencies.monotonicNow,
99
+ });
100
+
101
+ const categories: Partial<Record<ShareLinkMaintenanceFailureCategory, number>> = {};
102
+
103
+ if (budget.exhausted()) {
104
+ const summary: ShareLinkMaintenanceRunSummary = {
105
+ status: 'deadline_exhausted',
106
+ durationMs: budget.elapsedMs(),
107
+ budgetMs: budget.configuredMs,
108
+ recovery: null,
109
+ cleanup: null,
110
+ receiptPrune: null,
111
+ categories,
112
+ };
113
+
114
+ safeLogMaintenance(logger, summary);
115
+
116
+ return summary;
117
+ }
118
+
119
+ let recovery: ShareLinkMaintenanceRunSummary['recovery'] = null;
120
+ let cleanup: ShareLinkMaintenanceRunSummary['cleanup'] = null;
121
+ let receiptPrune: ShareLinkMaintenanceRunSummary['receiptPrune'] = null;
122
+ let recoveryAttempted = false;
123
+ let cleanupAttempted = false;
124
+ let receiptPruneAttempted = false;
125
+ let budgetStoppedRecovery = false;
126
+ let budgetStoppedCleanup = false;
127
+ let budgetStoppedReceiptPrune = false;
128
+ let attachmentStages: ShareLinkMaintenanceRunSummary['attachmentStages'];
129
+ let stageFailed = false;
130
+
131
+ if (budgetAllows(budget, recoveryDiscoveryCostMs(config))) {
132
+ recoveryAttempted = true;
133
+
134
+ try {
135
+ recovery = await runShareLinkRecoveryOnce({
136
+ repository: dependencies.recoveryRepository,
137
+ client: dependencies.client,
138
+ claimant: config.claimant,
139
+ namespace: config.namespace,
140
+ limit: config.recoveryLimit,
141
+ leaseMs: config.leaseMs,
142
+ budget,
143
+ transactionTimeoutMs: config.graphTimeoutMs,
144
+ requestTimeoutMs: config.requestTimeoutMs,
145
+ noInlineRetry: true,
146
+ now: dependencies.now,
147
+ });
148
+ } catch {
149
+ categories.share_link_maintenance_recovery_failed = 1;
150
+ }
151
+ } else {
152
+ budgetStoppedRecovery = true;
153
+ }
154
+
155
+ if (dependencies.expireAttachmentStages) {
156
+ if (budgetAllows(budget, config.graphTimeoutMs)) {
157
+ try {
158
+ attachmentStages = {
159
+ queued: await dependencies.expireAttachmentStages({
160
+ namespace: config.namespace,
161
+ limit: 10,
162
+ now: dependencies.now?.(),
163
+ transaction: { timeoutMs: config.graphTimeoutMs, noInlineRetry: true },
164
+ }),
165
+ };
166
+ } catch {
167
+ attachmentStages = null;
168
+ stageFailed = true;
169
+ categories.share_link_maintenance_attachment_stage_failed = 1;
170
+ }
171
+ } else {
172
+ budgetStoppedCleanup = true;
173
+ }
174
+ }
175
+
176
+ if (budgetAllows(budget, cleanupUnitCostMs(config))) {
177
+ cleanupAttempted = true;
178
+
179
+ try {
180
+ cleanup = await runShareContentCleanupOnce({
181
+ repository: dependencies.cleanupRepository,
182
+ client: dependencies.client,
183
+ claimant: config.claimant,
184
+ namespace: config.namespace,
185
+ limit: config.cleanupLimit,
186
+ claimMs: config.claimMs,
187
+ // One job per claim so a lapsed deadline can never strand a batch.
188
+ claimBatchSize: 1,
189
+ transactionTimeoutMs: config.graphTimeoutMs,
190
+ requestTimeoutMs: config.requestTimeoutMs,
191
+ noInlineRetry: true,
192
+ budget,
193
+ now: dependencies.now,
194
+ });
195
+ } catch {
196
+ categories.share_link_maintenance_cleanup_failed = 1;
197
+ }
198
+ } else {
199
+ budgetStoppedCleanup = true;
200
+ }
201
+
202
+ if (budgetAllows(budget, receiptPruneCostMs(config))) {
203
+ receiptPruneAttempted = true;
204
+
205
+ try {
206
+ const pruned = await dependencies.pruneReceipts({
207
+ namespace: config.namespace,
208
+ limit: config.receiptPruneLimit,
209
+ now: dependencies.now?.(),
210
+ // One bounded explicit read transaction, no inline retry: the
211
+ // scheduler cadence owns retry.
212
+ transaction: { timeoutMs: config.graphTimeoutMs, noInlineRetry: true },
213
+ });
214
+ receiptPrune = { pruned };
215
+ } catch {
216
+ categories.share_link_maintenance_receipt_prune_failed = 1;
217
+ }
218
+ } else {
219
+ budgetStoppedReceiptPrune = true;
220
+ }
221
+
222
+ const failed =
223
+ stageFailed ||
224
+ (recoveryAttempted && recovery === null) ||
225
+ (cleanupAttempted && cleanup === null) ||
226
+ (receiptPruneAttempted && receiptPrune === null);
227
+ const deadlineStopped =
228
+ budgetStoppedRecovery || budgetStoppedCleanup || budgetStoppedReceiptPrune;
229
+ const status = failed
230
+ ? 'failed'
231
+ : budget.exhausted() || deadlineStopped
232
+ ? 'deadline_exhausted'
233
+ : 'completed';
234
+
235
+ const summary: ShareLinkMaintenanceRunSummary = {
236
+ status,
237
+ durationMs: budget.elapsedMs(),
238
+ budgetMs: budget.configuredMs,
239
+ recovery,
240
+ cleanup,
241
+ receiptPrune,
242
+ ...(dependencies.expireAttachmentStages
243
+ ? { attachmentStages: attachmentStages ?? null }
244
+ : {}),
245
+ categories,
246
+ };
247
+
248
+ safeLogMaintenance(logger, summary);
249
+
250
+ return summary;
251
+ };
@@ -0,0 +1,340 @@
1
+ import type {
2
+ CleanupRunnerDependencies,
3
+ RecoveryRunnerDependencies,
4
+ } from '../share-link-coordinator';
5
+ import type { PruneShareViewReceiptsInput } from '../../accesslayer/share-link/types';
6
+ import type { ShareContentClient } from '../share-content-client/types';
7
+ import { createMaintenancePassBudget, resolveMaintenanceBudgetMs } from './budget';
8
+ import { resolveShareLinkMaintenanceConfig } from './config';
9
+ import { runShareLinkMaintenancePass } from './runner';
10
+ import { safeLogMaintenance } from './telemetry';
11
+ import type {
12
+ ShareLinkMaintenanceConfigResolution,
13
+ ShareLinkMaintenanceLogger,
14
+ ShareLinkMaintenanceRunSummary,
15
+ } from './types';
16
+
17
+ type MaintenanceClient = Pick<ShareContentClient, 'stat' | 'delete'>;
18
+
19
+ type ResolvedRunnerDependencies = {
20
+ expireAttachmentStages?: typeof import('../../accesslayer/share-link/attachment').expireShareAttachmentStages;
21
+ recoveryRepository: RecoveryRunnerDependencies['repository'];
22
+ cleanupRepository: CleanupRunnerDependencies['repository'];
23
+ pruneReceipts: (input: PruneShareViewReceiptsInput) => Promise<number>;
24
+ client: MaintenanceClient;
25
+ };
26
+
27
+ type DependencySetup =
28
+ | { status: 'ready'; dependencies: ResolvedRunnerDependencies }
29
+ | { status: 'failed' }
30
+ | { status: 'expired' };
31
+
32
+ export type ShareLinkMaintenanceRuntime = {
33
+ /** Config outcome fixed at construction; never contains raw values. */
34
+ readonly resolution: ShareLinkMaintenanceConfigResolution;
35
+ runOnce: (options?: {
36
+ /**
37
+ * Live Lambda remaining-time source. A numeric value is accepted as a
38
+ * backward-compatible test seam; production passes the live
39
+ * `getRemainingTimeInMillis` callback.
40
+ */
41
+ remainingTimeMs?: number | (() => number);
42
+ }) => Promise<ShareLinkMaintenanceRunSummary>;
43
+ };
44
+
45
+ export type CreateShareLinkMaintenanceRuntimeOptions = {
46
+ rawEnvironment?: Record<string, unknown>;
47
+ logger?: ShareLinkMaintenanceLogger;
48
+ now?: () => Date;
49
+ monotonicNow?: () => number;
50
+ /** Test seam: resolve the transport client without dynamic imports. */
51
+ createClient?: (
52
+ config: Extract<ShareLinkMaintenanceConfigResolution, { status: 'enabled' }>['config']
53
+ ) => Promise<MaintenanceClient>;
54
+ /** Test seam: resolve the production repositories without loading Neo4j. */
55
+ createRepositories?: (
56
+ client: MaintenanceClient,
57
+ config: Extract<ShareLinkMaintenanceConfigResolution, { status: 'enabled' }>['config']
58
+ ) => Promise<{
59
+ recoveryRepository: RecoveryRunnerDependencies['repository'];
60
+ cleanupRepository: CleanupRunnerDependencies['repository'];
61
+ pruneReceipts: ResolvedRunnerDependencies['pruneReceipts'];
62
+ expireAttachmentStages?: ResolvedRunnerDependencies['expireAttachmentStages'];
63
+ }>;
64
+ };
65
+
66
+ const inertSummary = (
67
+ status: 'disabled' | 'invalid_configuration',
68
+ categories: ShareLinkMaintenanceRunSummary['categories']
69
+ ): ShareLinkMaintenanceRunSummary => ({
70
+ status,
71
+ durationMs: 0,
72
+ budgetMs: 0,
73
+ recovery: null,
74
+ cleanup: null,
75
+ receiptPrune: null,
76
+ categories,
77
+ });
78
+
79
+ const deadlineSummary = (
80
+ budget: ReturnType<typeof createMaintenancePassBudget>
81
+ ): ShareLinkMaintenanceRunSummary => ({
82
+ status: 'deadline_exhausted',
83
+ durationMs: budget.elapsedMs(),
84
+ budgetMs: budget.configuredMs,
85
+ recovery: null,
86
+ cleanup: null,
87
+ receiptPrune: null,
88
+ categories: {},
89
+ });
90
+
91
+ const initializationFailedSummary = (): ShareLinkMaintenanceRunSummary => ({
92
+ status: 'initialization_failed',
93
+ durationMs: 0,
94
+ budgetMs: 0,
95
+ recovery: null,
96
+ cleanup: null,
97
+ receiptPrune: null,
98
+ categories: { share_link_maintenance_initialization_failed: 1 },
99
+ });
100
+
101
+ /** Sample a live remaining-time source once; fail closed on a bad value. */
102
+ const sampleRemainingMs = (source: number | (() => number) | undefined): number | undefined => {
103
+ if (source === undefined) return undefined;
104
+
105
+ let value: unknown;
106
+
107
+ try {
108
+ value = typeof source === 'function' ? source() : source;
109
+ } catch {
110
+ // A throwing Lambda context must not start work; fail closed.
111
+ return 0;
112
+ }
113
+
114
+ if (typeof value !== 'number' || !Number.isFinite(value)) return 0;
115
+
116
+ return value;
117
+ };
118
+
119
+ /**
120
+ * Production composition for the share-link maintenance pass.
121
+ *
122
+ * Disabled or malformed configuration resolves to an inert runtime: `runOnce`
123
+ * returns a fixed summary and never constructs the client, signer, repositories
124
+ * or any graph/remote dependency. When enabled, composition is lazy on the first
125
+ * invocation and reuses the existing did:web signing adapter with an explicitly
126
+ * configured trusted origin/audience/opaque namespace. There is no unsigned or
127
+ * fresh-key path.
128
+ *
129
+ * The invocation budget starts BEFORE dependency initialization: a cold start
130
+ * consumes the same deadline as the work, and an already-exhausted invocation
131
+ * performs no dependency/signer/graph setup at all. A successful setup is cached;
132
+ * a failed or budget-aborted setup is cleared so the next cadence retries.
133
+ */
134
+ export const createShareLinkMaintenanceRuntime = (
135
+ options: CreateShareLinkMaintenanceRuntimeOptions = {}
136
+ ): ShareLinkMaintenanceRuntime => {
137
+ const resolution = resolveShareLinkMaintenanceConfig(
138
+ options.rawEnvironment ?? (process.env as Record<string, unknown>)
139
+ );
140
+ const logger = options.logger ?? consoleLogger;
141
+
142
+ if (resolution.status === 'disabled') {
143
+ const summary = inertSummary('disabled', {});
144
+ return {
145
+ resolution,
146
+ runOnce: async () => {
147
+ safeLogMaintenance(logger, summary);
148
+
149
+ return summary;
150
+ },
151
+ };
152
+ }
153
+
154
+ if (resolution.status === 'invalid') {
155
+ const summary = inertSummary('invalid_configuration', {
156
+ share_link_maintenance_configuration_invalid: 1,
157
+ });
158
+ return {
159
+ resolution,
160
+ runOnce: async () => {
161
+ safeLogMaintenance(logger, summary);
162
+
163
+ return summary;
164
+ },
165
+ };
166
+ }
167
+
168
+ const { config } = resolution;
169
+ let cached: Promise<DependencySetup> | null = null;
170
+
171
+ const buildDependencies = async (
172
+ budget: ReturnType<typeof createMaintenancePassBudget>
173
+ ): Promise<DependencySetup> => {
174
+ try {
175
+ const client = options.createClient
176
+ ? await options.createClient(config)
177
+ : await buildRuntimeClient(config);
178
+
179
+ if (budget.exhausted()) return { status: 'expired' };
180
+
181
+ const repositories = options.createRepositories
182
+ ? await options.createRepositories(client, config)
183
+ : await buildRuntimeRepositories(client, config);
184
+
185
+ if (budget.exhausted()) return { status: 'expired' };
186
+
187
+ return { status: 'ready', dependencies: { client, ...repositories } };
188
+ } catch {
189
+ return { status: 'failed' };
190
+ }
191
+ };
192
+
193
+ const resolveDependencies = async (
194
+ budget: ReturnType<typeof createMaintenancePassBudget>
195
+ ): Promise<DependencySetup> => {
196
+ if (!cached) {
197
+ const pending = buildDependencies(budget);
198
+ cached = pending;
199
+
200
+ const result = await pending;
201
+
202
+ // Keep a successful/in-flight setup cached; clear a failed or
203
+ // budget-aborted one so the next cadence can retry.
204
+ if (result.status !== 'ready' && cached === pending) cached = null;
205
+
206
+ return result;
207
+ }
208
+
209
+ return cached;
210
+ };
211
+
212
+ return {
213
+ resolution,
214
+ runOnce: async runOptions => {
215
+ const requestedRemaining = sampleRemainingMs(runOptions?.remainingTimeMs);
216
+ const budget = createMaintenancePassBudget({
217
+ budgetMs: resolveMaintenanceBudgetMs(config.budgetMs, requestedRemaining),
218
+ finalizeReserveMs: config.finalizeReserveMs,
219
+ monotonicNow: options.monotonicNow,
220
+ });
221
+
222
+ if (budget.exhausted()) {
223
+ const summary = deadlineSummary(budget);
224
+ safeLogMaintenance(logger, summary);
225
+
226
+ return summary;
227
+ }
228
+
229
+ const setup = await resolveDependencies(budget);
230
+
231
+ if (setup.status === 'failed') {
232
+ const summary = initializationFailedSummary();
233
+ safeLogMaintenance(logger, summary);
234
+
235
+ return summary;
236
+ }
237
+
238
+ if (setup.status === 'expired' || budget.exhausted()) {
239
+ const summary = deadlineSummary(budget);
240
+ safeLogMaintenance(logger, summary);
241
+
242
+ return summary;
243
+ }
244
+
245
+ return runShareLinkMaintenancePass({
246
+ config,
247
+ recoveryRepository: setup.dependencies.recoveryRepository,
248
+ cleanupRepository: setup.dependencies.cleanupRepository,
249
+ pruneReceipts: setup.dependencies.pruneReceipts,
250
+ expireAttachmentStages: setup.dependencies.expireAttachmentStages,
251
+ client: setup.dependencies.client,
252
+ logger,
253
+ monotonicNow: options.monotonicNow,
254
+ now: options.now,
255
+ budget,
256
+ });
257
+ },
258
+ };
259
+ };
260
+
261
+ /** Lazy production transport: loads the did:web signer only when enabled. */
262
+ const buildRuntimeClient = async (
263
+ config: Extract<ShareLinkMaintenanceConfigResolution, { status: 'enabled' }>['config']
264
+ ): Promise<MaintenanceClient> => {
265
+ const [{ getServerDidWebDID }, { createDidWebLearnCardTokenSigner }, clientModule] =
266
+ await Promise.all([
267
+ import('../learnCard.helpers'),
268
+ import('../share-content-client/adapters'),
269
+ import('../share-content-client'),
270
+ ]);
271
+
272
+ const signerDid = getServerDidWebDID();
273
+ const clientConfig = clientModule.resolveShareContentClientConfig({
274
+ enabled: true,
275
+ origin: config.origin,
276
+ namespace: config.namespace,
277
+ audience: config.audience,
278
+ signerDid,
279
+ allowInsecureLoopback: config.allowInsecureLoopback,
280
+ signer: createDidWebLearnCardTokenSigner(),
281
+ requestTimeoutMs: config.requestTimeoutMs,
282
+ // Maintenance is one bounded attempt per unit; the scheduler/cadence owns
283
+ // retry, so a transient failure is re-queued rather than retried inline.
284
+ maxAttempts: 1,
285
+ retryBackoffMs: 0,
286
+ });
287
+
288
+ if (!clientConfig.enabled) {
289
+ throw new Error('share-link maintenance client configuration was rejected');
290
+ }
291
+
292
+ return clientModule.createShareContentClient(clientConfig);
293
+ };
294
+
295
+ /** Lazy production repositories: imports the Neo4j-backed wiring only when enabled. */
296
+ const buildRuntimeRepositories = async (
297
+ client: MaintenanceClient,
298
+ config: Extract<ShareLinkMaintenanceConfigResolution, { status: 'enabled' }>['config']
299
+ ): Promise<{
300
+ recoveryRepository: RecoveryRunnerDependencies['repository'];
301
+ cleanupRepository: CleanupRunnerDependencies['repository'];
302
+ pruneReceipts: ResolvedRunnerDependencies['pruneReceipts'];
303
+ expireAttachmentStages?: ResolvedRunnerDependencies['expireAttachmentStages'];
304
+ }> => {
305
+ const runtimeModule = await import('../share-link-coordinator/runtime');
306
+
307
+ const recoveryDependencies = runtimeModule.createRuntimeRecoveryRunnerDependencies({
308
+ client,
309
+ claimant: config.claimant,
310
+ namespace: config.namespace,
311
+ });
312
+ const cleanupDependencies = runtimeModule.createRuntimeCleanupRunnerDependencies({
313
+ client,
314
+ claimant: config.claimant,
315
+ namespace: config.namespace,
316
+ });
317
+
318
+ // Preinitialize the idempotent share-link constraint/index gate once, outside
319
+ // the per-unit budget, so a maintenance transaction never pays the one-time
320
+ // schema setup. It is cached in-process and is not a per-pass cost.
321
+ const { ensureShareLinkConstraints } = await import('../../models/share-link-constraints');
322
+ await ensureShareLinkConstraints();
323
+
324
+ // Load the receipt-prune repository last: it pulls the Neo4j `@instance`, so
325
+ // it must only be imported when an enabled runtime actually composes work.
326
+ const { pruneShareViewReceipts } = await import('../../accesslayer/share-link/receipt');
327
+
328
+ return {
329
+ recoveryRepository: recoveryDependencies.repository,
330
+ cleanupRepository: cleanupDependencies.repository,
331
+ pruneReceipts: pruneShareViewReceipts,
332
+ expireAttachmentStages: (await import('../../accesslayer/share-link/attachment'))
333
+ .expireShareAttachmentStages,
334
+ };
335
+ };
336
+
337
+ const consoleLogger: ShareLinkMaintenanceLogger = {
338
+ info: event => console.log('[share-link-maintenance]', event),
339
+ error: event => console.error('[share-link-maintenance]', event),
340
+ };