@learncard/network-brain-service 3.18.0 → 3.19.1

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 (478) hide show
  1. package/.env.example +38 -2
  2. package/CHANGELOG.md +118 -0
  3. package/README.md +42 -0
  4. package/compose.inbox.yml +7 -0
  5. package/dist/accesslayer/auth-grant/read.d.ts +1 -0
  6. package/dist/accesslayer/auth-grant/read.d.ts.map +1 -1
  7. package/dist/accesslayer/consentflowcontract/relationships/create.d.ts.map +1 -1
  8. package/dist/accesslayer/consentflowcontract/relationships/update.d.ts.map +1 -1
  9. package/dist/accesslayer/credential-activity/create.d.ts.map +1 -1
  10. package/dist/accesslayer/credential-refresh/email-delivery.d.ts +18 -0
  11. package/dist/accesslayer/credential-refresh/email-delivery.d.ts.map +1 -0
  12. package/dist/accesslayer/credential-refresh/index.d.ts +1 -0
  13. package/dist/accesslayer/credential-refresh/index.d.ts.map +1 -1
  14. package/dist/accesslayer/credential-refresh/read.d.ts.map +1 -1
  15. package/dist/accesslayer/credential-refresh/update.d.ts.map +1 -1
  16. package/dist/accesslayer/inbox-batch/store.d.ts +33 -0
  17. package/dist/accesslayer/inbox-batch/store.d.ts.map +1 -0
  18. package/dist/accesslayer/inbox-credential/create.d.ts +5 -0
  19. package/dist/accesslayer/inbox-credential/create.d.ts.map +1 -1
  20. package/dist/accesslayer/inbox-credential/refresh.d.ts +71 -0
  21. package/dist/accesslayer/inbox-credential/refresh.d.ts.map +1 -0
  22. package/dist/accesslayer/inbox-credential/update.d.ts +1 -1
  23. package/dist/accesslayer/inbox-credential/update.d.ts.map +1 -1
  24. package/dist/accesslayer/presentation/read.d.ts.map +1 -1
  25. package/dist/accesslayer/presentation/relationships/create.d.ts +2 -2
  26. package/dist/accesslayer/presentation/relationships/create.d.ts.map +1 -1
  27. package/dist/accesslayer/presentation/relationships/read.d.ts.map +1 -1
  28. package/dist/accesslayer/share-link/abandon.d.ts +3 -0
  29. package/dist/accesslayer/share-link/abandon.d.ts.map +1 -0
  30. package/dist/accesslayer/share-link/cleanup.d.ts +6 -0
  31. package/dist/accesslayer/share-link/cleanup.d.ts.map +1 -0
  32. package/dist/accesslayer/share-link/errors.d.ts +8 -0
  33. package/dist/accesslayer/share-link/errors.d.ts.map +1 -0
  34. package/dist/accesslayer/share-link/finalize.d.ts +3 -0
  35. package/dist/accesslayer/share-link/finalize.d.ts.map +1 -0
  36. package/dist/accesslayer/share-link/helpers.d.ts +56 -0
  37. package/dist/accesslayer/share-link/helpers.d.ts.map +1 -0
  38. package/dist/accesslayer/share-link/index.d.ts +12 -0
  39. package/dist/accesslayer/share-link/index.d.ts.map +1 -0
  40. package/dist/accesslayer/share-link/list.d.ts +5 -0
  41. package/dist/accesslayer/share-link/list.d.ts.map +1 -0
  42. package/dist/accesslayer/share-link/read.d.ts +5 -0
  43. package/dist/accesslayer/share-link/read.d.ts.map +1 -0
  44. package/dist/accesslayer/share-link/receipt.d.ts +11 -0
  45. package/dist/accesslayer/share-link/receipt.d.ts.map +1 -0
  46. package/dist/accesslayer/share-link/recovery.d.ts +6 -0
  47. package/dist/accesslayer/share-link/recovery.d.ts.map +1 -0
  48. package/dist/accesslayer/share-link/reserve.d.ts +4 -0
  49. package/dist/accesslayer/share-link/reserve.d.ts.map +1 -0
  50. package/dist/accesslayer/share-link/revoke.d.ts +3 -0
  51. package/dist/accesslayer/share-link/revoke.d.ts.map +1 -0
  52. package/dist/accesslayer/share-link/transaction-execution.d.ts +18 -0
  53. package/dist/accesslayer/share-link/transaction-execution.d.ts.map +1 -0
  54. package/dist/accesslayer/share-link/transaction.d.ts +15 -0
  55. package/dist/accesslayer/share-link/transaction.d.ts.map +1 -0
  56. package/dist/accesslayer/share-link/types.d.ts +370 -0
  57. package/dist/accesslayer/share-link/types.d.ts.map +1 -0
  58. package/dist/app.d.ts +4 -0
  59. package/dist/app.d.ts.map +1 -1
  60. package/dist/cache/atomic-counter.test-helpers.d.ts +3 -0
  61. package/dist/cache/atomic-counter.test-helpers.d.ts.map +1 -0
  62. package/dist/cache/atomic-counter.test.d.ts +2 -0
  63. package/dist/cache/atomic-counter.test.d.ts.map +1 -0
  64. package/dist/cache/index.d.ts +1 -1
  65. package/dist/cache/index.d.ts.map +1 -1
  66. package/dist/config/environment.d.ts +55 -0
  67. package/dist/config/environment.d.ts.map +1 -1
  68. package/dist/constants/auth-grant.d.ts +2 -0
  69. package/dist/constants/auth-grant.d.ts.map +1 -1
  70. package/dist/credential-refresh.d.ts.map +1 -1
  71. package/dist/helpers/activity.helpers.d.ts +4 -0
  72. package/dist/helpers/activity.helpers.d.ts.map +1 -1
  73. package/dist/helpers/boost.helpers.d.ts.map +1 -1
  74. package/dist/helpers/contact-method.helpers.d.ts.map +1 -1
  75. package/dist/helpers/contact-method.helpers.test.d.ts +2 -0
  76. package/dist/helpers/contact-method.helpers.test.d.ts.map +1 -0
  77. package/dist/helpers/credential-refresh-email-content.helpers.d.ts +44 -0
  78. package/dist/helpers/credential-refresh-email-content.helpers.d.ts.map +1 -0
  79. package/dist/helpers/credential-refresh-email-content.helpers.test.d.ts +2 -0
  80. package/dist/helpers/credential-refresh-email-content.helpers.test.d.ts.map +1 -0
  81. package/dist/helpers/credential-refresh-email.helpers.d.ts +17 -0
  82. package/dist/helpers/credential-refresh-email.helpers.d.ts.map +1 -0
  83. package/dist/helpers/credential-refresh-proof.helpers.d.ts +4 -0
  84. package/dist/helpers/credential-refresh-proof.helpers.d.ts.map +1 -0
  85. package/dist/helpers/credential-refresh-proof.helpers.test.d.ts +2 -0
  86. package/dist/helpers/credential-refresh-proof.helpers.test.d.ts.map +1 -0
  87. package/dist/helpers/credential-refresh.helpers.d.ts +45 -2
  88. package/dist/helpers/credential-refresh.helpers.d.ts.map +1 -1
  89. package/dist/helpers/credential.helpers.d.ts +2 -1
  90. package/dist/helpers/credential.helpers.d.ts.map +1 -1
  91. package/dist/helpers/credentialSubject.helpers.d.ts +3 -0
  92. package/dist/helpers/credentialSubject.helpers.d.ts.map +1 -0
  93. package/dist/helpers/credentialSubject.helpers.test.d.ts +2 -0
  94. package/dist/helpers/credentialSubject.helpers.test.d.ts.map +1 -0
  95. package/dist/helpers/finalize-inbox.helpers.d.ts.map +1 -1
  96. package/dist/helpers/inbox-batch-http.helpers.d.ts +15 -0
  97. package/dist/helpers/inbox-batch-http.helpers.d.ts.map +1 -0
  98. package/dist/helpers/inbox-batch-http.helpers.test.d.ts +2 -0
  99. package/dist/helpers/inbox-batch-http.helpers.test.d.ts.map +1 -0
  100. package/dist/helpers/inbox-batch-status.helpers.d.ts +3 -0
  101. package/dist/helpers/inbox-batch-status.helpers.d.ts.map +1 -0
  102. package/dist/helpers/inbox-batch.helpers.d.ts +10 -0
  103. package/dist/helpers/inbox-batch.helpers.d.ts.map +1 -0
  104. package/dist/helpers/inbox-batch.helpers.test.d.ts +2 -0
  105. package/dist/helpers/inbox-batch.helpers.test.d.ts.map +1 -0
  106. package/dist/helpers/inbox-issuance-error.helpers.d.ts +13 -0
  107. package/dist/helpers/inbox-issuance-error.helpers.d.ts.map +1 -0
  108. package/dist/helpers/inbox-queue.helpers.d.ts +11 -0
  109. package/dist/helpers/inbox-queue.helpers.d.ts.map +1 -0
  110. package/dist/helpers/inbox-queue.helpers.test.d.ts +2 -0
  111. package/dist/helpers/inbox-queue.helpers.test.d.ts.map +1 -0
  112. package/dist/helpers/inbox-refresh.helpers.d.ts +186 -0
  113. package/dist/helpers/inbox-refresh.helpers.d.ts.map +1 -0
  114. package/dist/helpers/inbox.helpers.d.ts +9 -1
  115. package/dist/helpers/inbox.helpers.d.ts.map +1 -1
  116. package/dist/helpers/notificationMessages.d.ts +1 -1
  117. package/dist/helpers/notificationMessages.d.ts.map +1 -1
  118. package/dist/helpers/notifications.helpers.d.ts.map +1 -1
  119. package/dist/helpers/presentation-metadata.d.ts +4 -0
  120. package/dist/helpers/presentation-metadata.d.ts.map +1 -0
  121. package/dist/helpers/presentation.helpers.d.ts +1 -1
  122. package/dist/helpers/presentation.helpers.d.ts.map +1 -1
  123. package/dist/helpers/profile.helpers.d.ts +1 -0
  124. package/dist/helpers/profile.helpers.d.ts.map +1 -1
  125. package/dist/helpers/rateLimit.helpers.d.ts.map +1 -1
  126. package/dist/helpers/refresh-send-intent.helpers.d.ts +51 -0
  127. package/dist/helpers/refresh-send-intent.helpers.d.ts.map +1 -0
  128. package/dist/helpers/share-content-client/adapters.d.ts +10 -0
  129. package/dist/helpers/share-content-client/adapters.d.ts.map +1 -0
  130. package/dist/helpers/share-content-client/canonical.d.ts +7 -0
  131. package/dist/helpers/share-content-client/canonical.d.ts.map +1 -0
  132. package/dist/helpers/share-content-client/client.d.ts +5 -0
  133. package/dist/helpers/share-content-client/client.d.ts.map +1 -0
  134. package/dist/helpers/share-content-client/config.d.ts +11 -0
  135. package/dist/helpers/share-content-client/config.d.ts.map +1 -0
  136. package/dist/helpers/share-content-client/index.d.ts +6 -0
  137. package/dist/helpers/share-content-client/index.d.ts.map +1 -0
  138. package/dist/helpers/share-content-client/responses.d.ts +16 -0
  139. package/dist/helpers/share-content-client/responses.d.ts.map +1 -0
  140. package/dist/helpers/share-content-client/types.d.ts +145 -0
  141. package/dist/helpers/share-content-client/types.d.ts.map +1 -0
  142. package/dist/helpers/share-link-coordinator/budget-helpers.d.ts +5 -0
  143. package/dist/helpers/share-link-coordinator/budget-helpers.d.ts.map +1 -0
  144. package/dist/helpers/share-link-coordinator/cleanup-runner.d.ts +3 -0
  145. package/dist/helpers/share-link-coordinator/cleanup-runner.d.ts.map +1 -0
  146. package/dist/helpers/share-link-coordinator/coordinator.d.ts +4 -0
  147. package/dist/helpers/share-link-coordinator/coordinator.d.ts.map +1 -0
  148. package/dist/helpers/share-link-coordinator/index.d.ts +5 -0
  149. package/dist/helpers/share-link-coordinator/index.d.ts.map +1 -0
  150. package/dist/helpers/share-link-coordinator/recovery-runner.d.ts +9 -0
  151. package/dist/helpers/share-link-coordinator/recovery-runner.d.ts.map +1 -0
  152. package/dist/helpers/share-link-coordinator/runtime.d.ts +11 -0
  153. package/dist/helpers/share-link-coordinator/runtime.d.ts.map +1 -0
  154. package/dist/helpers/share-link-coordinator/stat.d.ts +4 -0
  155. package/dist/helpers/share-link-coordinator/stat.d.ts.map +1 -0
  156. package/dist/helpers/share-link-coordinator/types.d.ts +160 -0
  157. package/dist/helpers/share-link-coordinator/types.d.ts.map +1 -0
  158. package/dist/helpers/share-link-lifecycle/index.d.ts +5 -0
  159. package/dist/helpers/share-link-lifecycle/index.d.ts.map +1 -0
  160. package/dist/helpers/share-link-lifecycle/lease.helpers.d.ts +4 -0
  161. package/dist/helpers/share-link-lifecycle/lease.helpers.d.ts.map +1 -0
  162. package/dist/helpers/share-link-lifecycle/recovery.helpers.d.ts +21 -0
  163. package/dist/helpers/share-link-lifecycle/recovery.helpers.d.ts.map +1 -0
  164. package/dist/helpers/share-link-lifecycle/request-hash.helpers.d.ts +9 -0
  165. package/dist/helpers/share-link-lifecycle/request-hash.helpers.d.ts.map +1 -0
  166. package/dist/helpers/share-link-lifecycle/types.d.ts +14 -0
  167. package/dist/helpers/share-link-lifecycle/types.d.ts.map +1 -0
  168. package/dist/helpers/share-link-maintenance/budget.d.ts +12 -0
  169. package/dist/helpers/share-link-maintenance/budget.d.ts.map +1 -0
  170. package/dist/helpers/share-link-maintenance/config.d.ts +48 -0
  171. package/dist/helpers/share-link-maintenance/config.d.ts.map +1 -0
  172. package/dist/helpers/share-link-maintenance/index.d.ts +8 -0
  173. package/dist/helpers/share-link-maintenance/index.d.ts.map +1 -0
  174. package/dist/helpers/share-link-maintenance/runner.d.ts +19 -0
  175. package/dist/helpers/share-link-maintenance/runner.d.ts.map +1 -0
  176. package/dist/helpers/share-link-maintenance/runtime.d.ts +36 -0
  177. package/dist/helpers/share-link-maintenance/runtime.d.ts.map +1 -0
  178. package/dist/helpers/share-link-maintenance/scheduler.d.ts +18 -0
  179. package/dist/helpers/share-link-maintenance/scheduler.d.ts.map +1 -0
  180. package/dist/helpers/share-link-maintenance/telemetry.d.ts +5 -0
  181. package/dist/helpers/share-link-maintenance/telemetry.d.ts.map +1 -0
  182. package/dist/helpers/share-link-maintenance/types.d.ts +53 -0
  183. package/dist/helpers/share-link-maintenance/types.d.ts.map +1 -0
  184. package/dist/helpers/share-link-owner/config.d.ts +16 -0
  185. package/dist/helpers/share-link-owner/config.d.ts.map +1 -0
  186. package/dist/helpers/share-link-owner/diagnostics.d.ts +26 -0
  187. package/dist/helpers/share-link-owner/diagnostics.d.ts.map +1 -0
  188. package/dist/helpers/share-link-owner/lazy-initializer.d.ts +2 -0
  189. package/dist/helpers/share-link-owner/lazy-initializer.d.ts.map +1 -0
  190. package/dist/helpers/share-link-owner-projection.d.ts +4 -0
  191. package/dist/helpers/share-link-owner-projection.d.ts.map +1 -0
  192. package/dist/helpers/share-link-passcode-abuse.d.ts +2 -0
  193. package/dist/helpers/share-link-passcode-abuse.d.ts.map +1 -0
  194. package/dist/helpers/share-link-passcode.d.ts +6 -0
  195. package/dist/helpers/share-link-passcode.d.ts.map +1 -0
  196. package/dist/helpers/share-link-policy/index.d.ts +4 -0
  197. package/dist/helpers/share-link-policy/index.d.ts.map +1 -0
  198. package/dist/helpers/share-link-policy/production.d.ts +13 -0
  199. package/dist/helpers/share-link-policy/production.d.ts.map +1 -0
  200. package/dist/helpers/share-link-policy/resolver.d.ts +6 -0
  201. package/dist/helpers/share-link-policy/resolver.d.ts.map +1 -0
  202. package/dist/helpers/share-link-policy/types.d.ts +16 -0
  203. package/dist/helpers/share-link-policy/types.d.ts.map +1 -0
  204. package/dist/helpers/share-link-public/config.d.ts +13 -0
  205. package/dist/helpers/share-link-public/config.d.ts.map +1 -0
  206. package/dist/helpers/share-link-view-notification.d.ts +2 -0
  207. package/dist/helpers/share-link-view-notification.d.ts.map +1 -0
  208. package/dist/helpers/shim.d.ts +1 -1
  209. package/dist/helpers/shim.d.ts.map +1 -1
  210. package/dist/inbox-queue-local.d.ts +2 -0
  211. package/dist/inbox-queue-local.d.ts.map +1 -0
  212. package/dist/index.js +2 -2
  213. package/dist/models/AuthGrant.d.ts.map +1 -1
  214. package/dist/models/CredentialActivity.d.ts +1 -0
  215. package/dist/models/CredentialActivity.d.ts.map +1 -1
  216. package/dist/models/CredentialRefresh.d.ts +5 -2
  217. package/dist/models/CredentialRefresh.d.ts.map +1 -1
  218. package/dist/models/InboxCredential.d.ts +1 -0
  219. package/dist/models/InboxCredential.d.ts.map +1 -1
  220. package/dist/models/Presentation.d.ts +2 -0
  221. package/dist/models/Presentation.d.ts.map +1 -1
  222. package/dist/models/Profile.d.ts +2 -0
  223. package/dist/models/Profile.d.ts.map +1 -1
  224. package/dist/models/ShareLink.d.ts +44 -0
  225. package/dist/models/ShareLink.d.ts.map +1 -0
  226. package/dist/models/ShareViewReceipt.d.ts +22 -0
  227. package/dist/models/ShareViewReceipt.d.ts.map +1 -0
  228. package/dist/models/credential-refresh-constraints.d.ts.map +1 -1
  229. package/dist/models/index.d.ts +1 -0
  230. package/dist/models/index.d.ts.map +1 -1
  231. package/dist/models/share-link-constraints.d.ts +3 -0
  232. package/dist/models/share-link-constraints.d.ts.map +1 -0
  233. package/dist/openapi.d.ts.map +1 -1
  234. package/dist/public-share-link-http.d.ts +4 -0
  235. package/dist/public-share-link-http.d.ts.map +1 -0
  236. package/dist/routes/act-as.test.d.ts +2 -0
  237. package/dist/routes/act-as.test.d.ts.map +1 -0
  238. package/dist/routes/activity.d.ts +3 -0
  239. package/dist/routes/activity.d.ts.map +1 -1
  240. package/dist/routes/app-store.d.ts.map +1 -1
  241. package/dist/routes/auth-grants.d.ts +10 -0
  242. package/dist/routes/auth-grants.d.ts.map +1 -1
  243. package/dist/routes/boosts.d.ts +494 -0
  244. package/dist/routes/boosts.d.ts.map +1 -1
  245. package/dist/routes/contracts.d.ts +2 -2
  246. package/dist/routes/contracts.d.ts.map +1 -1
  247. package/dist/routes/credential-refreshes.d.ts.map +1 -1
  248. package/dist/routes/credentials.d.ts +1 -1
  249. package/dist/routes/credentials.d.ts.map +1 -1
  250. package/dist/routes/inbox.d.ts +953 -11
  251. package/dist/routes/inbox.d.ts.map +1 -1
  252. package/dist/routes/index.d.ts +154 -85
  253. package/dist/routes/index.d.ts.map +1 -1
  254. package/dist/routes/presentations.d.ts +1 -0
  255. package/dist/routes/presentations.d.ts.map +1 -1
  256. package/dist/routes/profile-manager.d.ts.map +1 -1
  257. package/dist/routes/profiles.d.ts.map +1 -1
  258. package/dist/routes/public-share-links.d.ts +230 -0
  259. package/dist/routes/public-share-links.d.ts.map +1 -0
  260. package/dist/routes/share-links.d.ts +844 -0
  261. package/dist/routes/share-links.d.ts.map +1 -0
  262. package/dist/routes/workflows.d.ts.map +1 -1
  263. package/dist/services/delivery/adapters/postmark.adapter.d.ts.map +1 -1
  264. package/dist/services/delivery/adapters/postmark.adapter.test.d.ts +2 -0
  265. package/dist/services/delivery/adapters/postmark.adapter.test.d.ts.map +1 -0
  266. package/dist/services/registry/registry.factory.d.ts.map +1 -1
  267. package/dist/types/activity.d.ts +4 -0
  268. package/dist/types/activity.d.ts.map +1 -1
  269. package/dist/types/consentflowcontract.d.ts +1 -1
  270. package/dist/types/credential-refresh.d.ts +10 -1
  271. package/dist/types/credential-refresh.d.ts.map +1 -1
  272. package/dist/types/inbox-batch.d.ts +38 -0
  273. package/dist/types/inbox-batch.d.ts.map +1 -0
  274. package/inbox-e2e-setup.ts +53 -1
  275. package/inbox-elasticmq.conf +10 -0
  276. package/lambda.ts +64 -16
  277. package/package.json +24 -16
  278. package/scripts/seed-demo-persona.ts +425 -0
  279. package/scripts/setup-inbox-queues.ts +60 -0
  280. package/serverless-local.yml +2 -0
  281. package/serverless.yml +111 -0
  282. package/shareLinkMaintenanceLambda.ts +49 -0
  283. package/src/accesslayer/auth-grant/read.ts +2 -1
  284. package/src/accesslayer/consentflowcontract/relationships/create.ts +9 -16
  285. package/src/accesslayer/consentflowcontract/relationships/update.ts +15 -28
  286. package/src/accesslayer/credential-activity/create.ts +1 -0
  287. package/src/accesslayer/credential-refresh/email-delivery.ts +116 -0
  288. package/src/accesslayer/credential-refresh/index.ts +1 -0
  289. package/src/accesslayer/credential-refresh/read.ts +8 -2
  290. package/src/accesslayer/credential-refresh/update.ts +4 -0
  291. package/src/accesslayer/inbox-batch/store.ts +469 -0
  292. package/src/accesslayer/inbox-credential/create.ts +51 -19
  293. package/src/accesslayer/inbox-credential/refresh.ts +221 -0
  294. package/src/accesslayer/inbox-credential/update.ts +1 -1
  295. package/src/accesslayer/presentation/read.ts +57 -25
  296. package/src/accesslayer/presentation/relationships/create.ts +54 -11
  297. package/src/accesslayer/presentation/relationships/read.ts +21 -6
  298. package/src/accesslayer/share-link/abandon.ts +100 -0
  299. package/src/accesslayer/share-link/cleanup.ts +271 -0
  300. package/src/accesslayer/share-link/errors.ts +32 -0
  301. package/src/accesslayer/share-link/finalize.ts +265 -0
  302. package/src/accesslayer/share-link/helpers.ts +419 -0
  303. package/src/accesslayer/share-link/index.ts +11 -0
  304. package/src/accesslayer/share-link/list.ts +162 -0
  305. package/src/accesslayer/share-link/read.ts +107 -0
  306. package/src/accesslayer/share-link/receipt.ts +548 -0
  307. package/src/accesslayer/share-link/recovery.ts +545 -0
  308. package/src/accesslayer/share-link/reserve.ts +684 -0
  309. package/src/accesslayer/share-link/revoke.ts +197 -0
  310. package/src/accesslayer/share-link/transaction-execution.ts +72 -0
  311. package/src/accesslayer/share-link/transaction.ts +126 -0
  312. package/src/accesslayer/share-link/types.ts +601 -0
  313. package/src/app.ts +6 -0
  314. package/src/cache/atomic-counter.test-helpers.ts +27 -0
  315. package/src/cache/atomic-counter.test.ts +6 -0
  316. package/src/cache/index.ts +25 -13
  317. package/src/config/environment.ts +40 -0
  318. package/src/constants/auth-grant.ts +5 -0
  319. package/src/credential-refresh.ts +5 -1
  320. package/src/docker-entry.ts +65 -0
  321. package/src/helpers/activity.helpers.ts +4 -0
  322. package/src/helpers/app-counter.helpers.ts +1 -1
  323. package/src/helpers/boost.helpers.ts +4 -31
  324. package/src/helpers/contact-method.helpers.test.ts +43 -0
  325. package/src/helpers/contact-method.helpers.ts +3 -4
  326. package/src/helpers/credential-refresh-email-content.helpers.test.ts +222 -0
  327. package/src/helpers/credential-refresh-email-content.helpers.ts +155 -0
  328. package/src/helpers/credential-refresh-email.helpers.ts +201 -0
  329. package/src/helpers/credential-refresh-proof.helpers.test.ts +103 -0
  330. package/src/helpers/credential-refresh-proof.helpers.ts +43 -0
  331. package/src/helpers/credential-refresh.helpers.ts +375 -99
  332. package/src/helpers/credential.helpers.ts +4 -1
  333. package/src/helpers/credentialSubject.helpers.test.ts +114 -0
  334. package/src/helpers/credentialSubject.helpers.ts +40 -0
  335. package/src/helpers/finalize-inbox.helpers.ts +29 -14
  336. package/src/helpers/inbox-batch-http.helpers.test.ts +188 -0
  337. package/src/helpers/inbox-batch-http.helpers.ts +150 -0
  338. package/src/helpers/inbox-batch-status.helpers.ts +11 -0
  339. package/src/helpers/inbox-batch.helpers.test.ts +668 -0
  340. package/src/helpers/inbox-batch.helpers.ts +374 -0
  341. package/src/helpers/inbox-issuance-error.helpers.ts +25 -0
  342. package/src/helpers/inbox-queue.helpers.test.ts +253 -0
  343. package/src/helpers/inbox-queue.helpers.ts +372 -0
  344. package/src/helpers/inbox-refresh.helpers.ts +432 -0
  345. package/src/helpers/inbox.helpers.ts +275 -36
  346. package/src/helpers/notificationMessages.ts +18 -1
  347. package/src/helpers/notifications.helpers.ts +4 -2
  348. package/src/helpers/presentation-metadata.ts +41 -0
  349. package/src/helpers/presentation.helpers.ts +27 -20
  350. package/src/helpers/profile.helpers.ts +7 -0
  351. package/src/helpers/rateLimit.helpers.ts +2 -5
  352. package/src/helpers/refresh-send-intent.helpers.ts +273 -0
  353. package/src/helpers/share-content-client/adapters.ts +55 -0
  354. package/src/helpers/share-content-client/canonical.ts +25 -0
  355. package/src/helpers/share-content-client/client.ts +440 -0
  356. package/src/helpers/share-content-client/config.ts +189 -0
  357. package/src/helpers/share-content-client/index.ts +27 -0
  358. package/src/helpers/share-content-client/responses.ts +273 -0
  359. package/src/helpers/share-content-client/types.ts +253 -0
  360. package/src/helpers/share-link-coordinator/budget-helpers.ts +53 -0
  361. package/src/helpers/share-link-coordinator/cleanup-runner.ts +286 -0
  362. package/src/helpers/share-link-coordinator/coordinator.ts +714 -0
  363. package/src/helpers/share-link-coordinator/index.ts +8 -0
  364. package/src/helpers/share-link-coordinator/recovery-runner.ts +428 -0
  365. package/src/helpers/share-link-coordinator/runtime.ts +88 -0
  366. package/src/helpers/share-link-coordinator/stat.ts +30 -0
  367. package/src/helpers/share-link-coordinator/types.ts +353 -0
  368. package/src/helpers/share-link-lifecycle/index.ts +4 -0
  369. package/src/helpers/share-link-lifecycle/lease.helpers.ts +35 -0
  370. package/src/helpers/share-link-lifecycle/recovery.helpers.ts +173 -0
  371. package/src/helpers/share-link-lifecycle/request-hash.helpers.ts +130 -0
  372. package/src/helpers/share-link-lifecycle/types.ts +58 -0
  373. package/src/helpers/share-link-maintenance/budget.ts +63 -0
  374. package/src/helpers/share-link-maintenance/config.ts +312 -0
  375. package/src/helpers/share-link-maintenance/index.ts +24 -0
  376. package/src/helpers/share-link-maintenance/runner.ts +223 -0
  377. package/src/helpers/share-link-maintenance/runtime.ts +334 -0
  378. package/src/helpers/share-link-maintenance/scheduler.ts +126 -0
  379. package/src/helpers/share-link-maintenance/telemetry.ts +70 -0
  380. package/src/helpers/share-link-maintenance/types.ts +89 -0
  381. package/src/helpers/share-link-owner/config.ts +48 -0
  382. package/src/helpers/share-link-owner/diagnostics.ts +89 -0
  383. package/src/helpers/share-link-owner/lazy-initializer.ts +29 -0
  384. package/src/helpers/share-link-owner-projection.ts +52 -0
  385. package/src/helpers/share-link-passcode-abuse.ts +36 -0
  386. package/src/helpers/share-link-passcode.ts +47 -0
  387. package/src/helpers/share-link-policy/index.ts +7 -0
  388. package/src/helpers/share-link-policy/production.ts +88 -0
  389. package/src/helpers/share-link-policy/resolver.ts +108 -0
  390. package/src/helpers/share-link-policy/types.ts +48 -0
  391. package/src/helpers/share-link-public/config.ts +41 -0
  392. package/src/helpers/share-link-view-notification.ts +18 -0
  393. package/src/helpers/shim.ts +32 -31
  394. package/src/inbox-queue-local.ts +28 -0
  395. package/src/models/AuthGrant.ts +1 -0
  396. package/src/models/CredentialActivity.ts +3 -5
  397. package/src/models/CredentialRefresh.ts +4 -2
  398. package/src/models/InboxCredential.ts +2 -0
  399. package/src/models/Presentation.ts +2 -2
  400. package/src/models/Profile.ts +3 -2
  401. package/src/models/ShareLink.ts +130 -0
  402. package/src/models/ShareViewReceipt.ts +69 -0
  403. package/src/models/credential-refresh-constraints.test.ts +8 -3
  404. package/src/models/credential-refresh-constraints.ts +5 -0
  405. package/src/models/index.ts +2 -0
  406. package/src/models/share-link-constraints.ts +93 -0
  407. package/src/openapi.ts +8 -0
  408. package/src/public-share-link-http.ts +49 -0
  409. package/src/routes/act-as.test.ts +239 -0
  410. package/src/routes/app-store.ts +4 -13
  411. package/src/routes/auth-grants.ts +13 -11
  412. package/src/routes/boosts.ts +916 -103
  413. package/src/routes/contracts.ts +2 -11
  414. package/src/routes/credential-refreshes.test.ts +8 -2
  415. package/src/routes/credential-refreshes.ts +4 -1
  416. package/src/routes/credentials.ts +2 -1
  417. package/src/routes/inbox.ts +95 -49
  418. package/src/routes/index.ts +216 -46
  419. package/src/routes/presentations.ts +19 -3
  420. package/src/routes/profile-manager.ts +10 -2
  421. package/src/routes/profiles.ts +17 -6
  422. package/src/routes/public-share-links.ts +814 -0
  423. package/src/routes/share-links.ts +640 -0
  424. package/src/routes/skills.ts +1 -1
  425. package/src/routes/workflows.ts +43 -24
  426. package/src/services/delivery/adapters/postmark.adapter.test.ts +54 -0
  427. package/src/services/delivery/adapters/postmark.adapter.ts +16 -1
  428. package/src/services/registry/registry.factory.ts +2 -1
  429. package/src/types/activity.ts +2 -0
  430. package/src/types/credential-refresh.ts +21 -2
  431. package/src/types/inbox-batch.ts +46 -0
  432. package/test/atomic-counter.e2e.ts +12 -0
  433. package/test/auth-grant.spec.ts +21 -21
  434. package/test/credential-refresh-email.spec.ts +663 -0
  435. package/test/credential-refresh-publication.spec.ts +2 -0
  436. package/test/dids.spec.ts +10 -1
  437. package/test/guardian-gated-routes.spec.ts +13 -0
  438. package/test/helpers/inbox-e2e-environment.ts +6 -0
  439. package/test/helpers/share-link-fixtures.ts +94 -0
  440. package/test/inbox-batch.spec.ts +1338 -0
  441. package/test/inbox-refresh.spec.ts +534 -0
  442. package/test/managed-recipient-inbox.spec.ts +130 -0
  443. package/test/notificationMessages.spec.ts +13 -0
  444. package/test/openapi.spec.ts +61 -1
  445. package/test/presentations.spec.ts +54 -6
  446. package/test/profiles.spec.ts +67 -1
  447. package/test/refresh-send.spec.ts +1799 -0
  448. package/test/registry.spec.ts +56 -11
  449. package/test/share-content-client.contract.spec.ts +365 -0
  450. package/test/share-content-client.unit.spec.ts +462 -0
  451. package/test/share-link-abuse.unit.spec.ts +65 -0
  452. package/test/share-link-coordinator.neo4j.spec.ts +684 -0
  453. package/test/share-link-coordinator.unit.spec.ts +990 -0
  454. package/test/share-link-dependency-diagnostics.unit.spec.ts +127 -0
  455. package/test/share-link-lifecycle.neo4j.spec.ts +1268 -0
  456. package/test/share-link-lifecycle.unit.spec.ts +205 -0
  457. package/test/share-link-list-cursor.unit.spec.ts +86 -0
  458. package/test/share-link-list.neo4j.spec.ts +324 -0
  459. package/test/share-link-maintenance.neo4j.spec.ts +355 -0
  460. package/test/share-link-maintenance.unit.spec.ts +1113 -0
  461. package/test/share-link-owner-policy.unit.spec.ts +210 -0
  462. package/test/share-link-owner-route.unit.spec.ts +752 -0
  463. package/test/share-link-owner-runtime.unit.spec.ts +102 -0
  464. package/test/share-link-passcode.unit.spec.ts +29 -0
  465. package/test/share-link-policy.unit.spec.ts +135 -0
  466. package/test/share-link-presentation-metadata.unit.spec.ts +49 -0
  467. package/test/share-link-production-policy.unit.spec.ts +77 -0
  468. package/test/share-link-public-config.unit.spec.ts +64 -0
  469. package/test/share-link-public-http-adapter.unit.spec.ts +315 -0
  470. package/test/share-link-public-route.unit.spec.ts +800 -0
  471. package/test/share-link-receipt.neo4j.spec.ts +943 -0
  472. package/test/share-link-recovery.neo4j.spec.ts +935 -0
  473. package/test/share-link-recovery.unit.spec.ts +726 -0
  474. package/vitest.config.ts +10 -0
  475. package/vitest.inbox-e2e.config.ts +5 -1
  476. package/vitest.integration.config.ts +2 -0
  477. package/vitest.share-links-neo4j.config.ts +19 -0
  478. package/vitest.share-links-unit.config.ts +28 -0
@@ -0,0 +1,432 @@
1
+ import { randomUUID, createHmac } from 'node:crypto';
2
+ import { TRPCError } from '@trpc/server';
3
+ import { UnsignedVCValidator, VCValidator } from '@learncard/types';
4
+ import type {
5
+ InboxCredentialRefreshReceipt,
6
+ PublishCredentialRefreshInput,
7
+ PublishCredentialRefreshResult,
8
+ VC,
9
+ } from '@learncard/types';
10
+ import {
11
+ canonicalizeCredentialJson,
12
+ injectManagedRefreshService,
13
+ getManagedRefreshServices,
14
+ getCredentialEffectiveTime,
15
+ getCredentialIssuerId,
16
+ getBitstringStatusListEntries,
17
+ } from '@learncard/helpers';
18
+ import { getCredentialRefreshRuntimeEnvironment } from '@environment';
19
+ import { AUTH_GRANT_NO_ACCESS_SCOPE } from '../constants/auth-grant';
20
+ import { ensureCredentialRefreshConstraints } from '../models/credential-refresh-constraints';
21
+ import { getCredentialRefresh, generateRefreshId } from '@accesslayer/credential-refresh';
22
+ import { getInboxCredentialById } from '@accesslayer/inbox-credential/read';
23
+ import {
24
+ advancePendingInboxRefresh,
25
+ bindPendingInboxRefresh,
26
+ getInboxRefreshIssue,
27
+ getPendingInboxPublication,
28
+ getInboxRefreshSnapshot,
29
+ } from '@accesslayer/inbox-credential/refresh';
30
+ import { getProfileByDid, getProfileByProfileId } from '@accesslayer/profile/read';
31
+ import { getProfilesThatManageAProfile } from '@accesslayer/profile/relationships/read';
32
+ import { getSigningAuthorityForUserByName } from '@accesslayer/signing-authority/relationships/read';
33
+ import { getBoostByUri } from '@accesslayer/boost/read';
34
+ import { INBOX_DELIVERY_RETENTION_DAYS } from 'types/inbox-delivery';
35
+ import type { ProfileType } from 'types/profile';
36
+ import type { CredentialRefreshRecord } from 'types/credential-refresh';
37
+ import { userHasRequiredScopes } from './auth-grant.helpers';
38
+ import { getDidWeb } from './did.helpers';
39
+ import { encryptInboxCredential, decryptInboxCredential } from './inbox-encryption.helpers';
40
+ import {
41
+ getCredentialRefreshServiceUrl,
42
+ computeRefreshEtag,
43
+ getManagedCredentialUri,
44
+ getInitialRefreshRoot,
45
+ sendInitialCredentialNotificationOnce,
46
+ } from './credential-refresh.helpers';
47
+ import {
48
+ getCredentialRefreshDigestSecret,
49
+ computeCredentialMaterialDigest,
50
+ computeCredentialStatusDigest,
51
+ computeCredentialSubjectDigest,
52
+ } from './credential-refresh-materiality.helpers';
53
+ import { appendBitstringStatusListEntries } from './status-list.helpers';
54
+ import { issueCredentialWithSigningAuthority } from './signingAuthority.helpers';
55
+ import { verifyManagedRefreshProof } from './credential-refresh-proof.helpers';
56
+ import { createDagJweForRecipients, getLearnCard } from './learnCard.helpers';
57
+ import { isRelationshipBlocked } from './connection.helpers';
58
+
59
+ export const assertInboxRefreshEnabled = async (scope?: string): Promise<void> => {
60
+ if (!getCredentialRefreshRuntimeEnvironment().CREDENTIAL_REFRESH_ENABLED)
61
+ throw new TRPCError({ code: 'NOT_FOUND', message: 'Credential refresh is not available' });
62
+ if (!userHasRequiredScopes(scope ?? AUTH_GRANT_NO_ACCESS_SCOPE, 'credentials:write'))
63
+ throw new TRPCError({
64
+ code: 'UNAUTHORIZED',
65
+ message: 'This operation requires credentials:write scope',
66
+ });
67
+ await ensureCredentialRefreshConstraints();
68
+ };
69
+
70
+ export const inboxRefreshRequestDigest = (request: unknown): string =>
71
+ createHmac('sha256', getCredentialRefreshDigestSecret())
72
+ .update('inbox-refresh-issue:v1\0')
73
+ .update(canonicalizeCredentialJson(request))
74
+ .digest('base64url');
75
+
76
+ export const getInboxRefreshIssueKey = (issuerProfileId: string, key: string): string =>
77
+ `${issuerProfileId}:${key}`;
78
+
79
+ export const getInboxRefreshReplay = async (
80
+ issuerProfileId: string,
81
+ key: string | undefined,
82
+ requestDigest: string
83
+ ) => {
84
+ if (!key) return null;
85
+ const existing = await getInboxRefreshIssue(getInboxRefreshIssueKey(issuerProfileId, key));
86
+ if (existing && existing.requestDigest !== requestDigest)
87
+ throw new TRPCError({
88
+ code: 'CONFLICT',
89
+ message: 'This idempotencyKey was used for a different inbox issuance.',
90
+ });
91
+ return existing;
92
+ };
93
+
94
+ const serviceFor = (refreshId: string, domain: string) => ({
95
+ id: getCredentialRefreshServiceUrl(refreshId, domain),
96
+ type: 'LearnCardCredentialRefresh2026' as const,
97
+ authorization: { type: 'LearnCardDIDAuth' as const },
98
+ });
99
+
100
+ /** Metadata only: status coordinates are public mechanisms, never credential claims. */
101
+ export const getInboxRefreshReceipt = async (
102
+ refreshId: string,
103
+ domain: string
104
+ ): Promise<InboxCredentialRefreshReceipt> => {
105
+ const aggregate = await getCredentialRefresh(refreshId);
106
+ if (!aggregate)
107
+ throw new TRPCError({ code: 'NOT_FOUND', message: 'Credential refresh not found' });
108
+ const status = aggregate.inboxCredentialStatus
109
+ ? JSON.parse(aggregate.inboxCredentialStatus)
110
+ : undefined;
111
+ return {
112
+ refreshId,
113
+ refreshService: serviceFor(refreshId, domain),
114
+ credentialId: aggregate.credentialId,
115
+ issuerDid: aggregate.issuerDid,
116
+ ...(aggregate.holderDid ? { holderDid: aggregate.holderDid } : {}),
117
+ ...(status ? { credentialStatus: status } : {}),
118
+ };
119
+ };
120
+
121
+ export const prepareInboxRefresh = async (
122
+ credential: unknown,
123
+ issuer: ProfileType,
124
+ domain: string
125
+ ) => {
126
+ const body = UnsignedVCValidator.parse(credential);
127
+ if (
128
+ body.proof ||
129
+ !body.type.includes('VerifiableCredential') ||
130
+ body.type.includes('VerifiablePresentation') ||
131
+ Array.isArray(body.credentialSubject)
132
+ ) {
133
+ throw new TRPCError({
134
+ code: 'BAD_REQUEST',
135
+ message:
136
+ 'Inbox refresh requires an unsigned credential with a single subject and a signing authority.',
137
+ });
138
+ }
139
+ if (getManagedRefreshServices(body).length)
140
+ throw new TRPCError({
141
+ code: 'BAD_REQUEST',
142
+ message:
143
+ 'Inbox refresh allocates its own refresh service; omit an existing managed service.',
144
+ });
145
+ const refreshId = generateRefreshId();
146
+ const issuerDid = getDidWeb(domain, issuer.profileId);
147
+ // Inbox is explicitly addressed by verified contact; the eventual claimant binds the subject.
148
+ const { id: _id, did: _did, ...subject } = body.credentialSubject;
149
+ const prepared = injectManagedRefreshService(
150
+ await appendBitstringStatusListEntries(
151
+ {
152
+ ...body,
153
+ id: body.id || `urn:uuid:${randomUUID()}`,
154
+ issuer: issuerDid,
155
+ credentialSubject: subject,
156
+ },
157
+ issuer.profileId,
158
+ domain
159
+ ),
160
+ serviceFor(refreshId, domain)
161
+ );
162
+ const now = new Date().toISOString();
163
+ return {
164
+ credential: prepared,
165
+ aggregate: {
166
+ refreshId,
167
+ issuerProfileId: issuer.profileId,
168
+ issuerDid,
169
+ credentialId: prepared.id!,
170
+ state: 'pending_holder',
171
+ currentVersion: 1,
172
+ createdAt: now,
173
+ updatedAt: now,
174
+ credentialStatusDigest: computeCredentialStatusDigest(prepared.credentialStatus),
175
+ inboxCredentialStatus: JSON.stringify(prepared.credentialStatus ?? null),
176
+ materialDigest: computeCredentialMaterialDigest(prepared),
177
+ },
178
+ };
179
+ };
180
+
181
+ /** Pending publications remain unsigned; finalization adds the verified holder before signing. */
182
+ export const publishPendingInboxRefresh = async (
183
+ aggregate: CredentialRefreshRecord,
184
+ issuer: ProfileType,
185
+ input: PublishCredentialRefreshInput,
186
+ domain: string
187
+ ): Promise<PublishCredentialRefreshResult> => {
188
+ const replay = await getPendingInboxPublication(aggregate.refreshId, input.idempotencyKey);
189
+ if (replay) return replay;
190
+ if (input.mode !== 'signing-authority')
191
+ throw new TRPCError({
192
+ code: 'BAD_REQUEST',
193
+ message:
194
+ 'Pending inbox refresh requires unsigned content in signing-authority mode; the holder is bound at claim.',
195
+ });
196
+ const inbox = await getInboxCredentialById(aggregate.inboxCredentialId!);
197
+ if (!inbox || inbox.currentStatus !== 'PENDING' || Date.parse(inbox.expiresAt) <= Date.now())
198
+ throw new TRPCError({ code: 'CONFLICT', message: 'Inbox credential is no longer pending' });
199
+ const authority = inbox.signingAuthority;
200
+ if (
201
+ !authority?.endpoint ||
202
+ !authority.name ||
203
+ input.signingAuthority.endpoint !== authority.endpoint ||
204
+ String(input.signingAuthority.name).toLowerCase() !== authority.name.toLowerCase() ||
205
+ !(await getSigningAuthorityForUserByName(issuer, authority.endpoint, authority.name))
206
+ )
207
+ throw new TRPCError({
208
+ code: 'UNAUTHORIZED',
209
+ message: 'Publication must use the inbox issuance signing authority',
210
+ });
211
+ const body = input.credential;
212
+ const previous = UnsignedVCValidator.parse(
213
+ JSON.parse(await decryptInboxCredential(inbox.credential))
214
+ );
215
+ if (
216
+ body.proof ||
217
+ Array.isArray(body.credentialSubject) ||
218
+ body.id !== aggregate.credentialId ||
219
+ getCredentialIssuerId(body) !== aggregate.issuerDid ||
220
+ computeCredentialSubjectDigest(body.credentialSubject) !==
221
+ computeCredentialSubjectDigest(previous.credentialSubject) ||
222
+ body.boostId !== previous.boostId ||
223
+ computeCredentialStatusDigest(body.credentialStatus) !== aggregate.credentialStatusDigest ||
224
+ canonicalizeCredentialJson(body.refreshService) !==
225
+ canonicalizeCredentialJson(previous.refreshService)
226
+ )
227
+ throw new TRPCError({
228
+ code: 'BAD_REQUEST',
229
+ message:
230
+ 'Pending update must preserve credential identity, issuer, subject, boost, status and refresh service.',
231
+ });
232
+ const previousTime = getCredentialEffectiveTime(previous);
233
+ const nextTime = getCredentialEffectiveTime(body);
234
+ if (previousTime !== undefined && nextTime !== undefined && nextTime < previousTime)
235
+ throw new TRPCError({
236
+ code: 'BAD_REQUEST',
237
+ message: 'Credential effective time is older than the current version',
238
+ });
239
+ const prepared = injectManagedRefreshService(body, serviceFor(aggregate.refreshId, domain));
240
+ const result = await advancePendingInboxRefresh({
241
+ refreshId: aggregate.refreshId,
242
+ expectedVersion: aggregate.currentVersion,
243
+ credential: await encryptInboxCredential(JSON.stringify(prepared)),
244
+ credentialName: typeof prepared.name === 'string' ? prepared.name : undefined,
245
+ materialDigest: computeCredentialMaterialDigest(prepared),
246
+ idempotencyKey: input.idempotencyKey,
247
+ updateSummary: input.updateSummary,
248
+ });
249
+ if (!result)
250
+ throw new TRPCError({
251
+ code: 'CONFLICT',
252
+ message: 'Inbox refresh changed during publication; retry with current state.',
253
+ });
254
+ return result;
255
+ };
256
+
257
+ /** Claim/finalize share this path. A racing publish forces a re-read and a fresh signature. */
258
+ export const finalizeInboxRefresh = async (params: {
259
+ inboxId: string;
260
+ holderDid: string;
261
+ holderProfile?: ProfileType | null;
262
+ domain: string;
263
+ accepted?: boolean;
264
+ }): Promise<{ credential: VC; uri: string }> => {
265
+ const { inboxId, holderDid, holderProfile, domain, accepted = true } = params;
266
+ if (!getCredentialRefreshRuntimeEnvironment().CREDENTIAL_REFRESH_ENABLED)
267
+ throw new TRPCError({ code: 'NOT_FOUND', message: 'Credential refresh is not available' });
268
+ for (let attempt = 0; attempt < 3; attempt++) {
269
+ const snapshot = await getInboxRefreshSnapshot(inboxId);
270
+ const inbox = snapshot?.inbox;
271
+ if (
272
+ !inbox?.refreshId ||
273
+ inbox.currentStatus !== 'PENDING' ||
274
+ Date.parse(inbox.expiresAt) <= Date.now() ||
275
+ (inbox.guardianStatus && inbox.guardianStatus !== 'GUARDIAN_APPROVED')
276
+ )
277
+ throw new TRPCError({
278
+ code: 'CONFLICT',
279
+ message: 'Inbox credential is no longer eligible for claim',
280
+ });
281
+ const aggregate = snapshot?.aggregate;
282
+ if (!aggregate || aggregate.state !== 'pending_holder')
283
+ throw new TRPCError({ code: 'CONFLICT', message: 'Inbox credential is already bound' });
284
+ const issuer = await getProfileByDid(inbox.issuerDid);
285
+ if (!issuer || (holderProfile && (await isRelationshipBlocked(issuer, holderProfile))))
286
+ throw new TRPCError({ code: 'NOT_FOUND', message: 'Profile not found' });
287
+ const authority =
288
+ inbox.signingAuthority?.endpoint && inbox.signingAuthority?.name
289
+ ? await getSigningAuthorityForUserByName(
290
+ issuer,
291
+ inbox.signingAuthority.endpoint,
292
+ inbox.signingAuthority.name
293
+ )
294
+ : null;
295
+ if (!authority)
296
+ throw new TRPCError({ code: 'NOT_FOUND', message: 'Signing authority not found' });
297
+ const template = UnsignedVCValidator.parse(
298
+ JSON.parse(await decryptInboxCredential(inbox.credential))
299
+ );
300
+ if (Array.isArray(template.credentialSubject))
301
+ throw new TRPCError({
302
+ code: 'BAD_REQUEST',
303
+ message: 'Inbox refresh requires one subject',
304
+ });
305
+ const unsigned = injectManagedRefreshService(
306
+ {
307
+ ...template,
308
+ issuer: aggregate.issuerDid,
309
+ credentialSubject: { ...template.credentialSubject, id: holderDid },
310
+ },
311
+ serviceFor(aggregate.refreshId, domain)
312
+ );
313
+ const credential = VCValidator.parse(
314
+ (
315
+ await issueCredentialWithSigningAuthority(
316
+ { type: 'profile', profile: issuer },
317
+ unsigned,
318
+ authority,
319
+ domain,
320
+ false,
321
+ undefined,
322
+ false
323
+ )
324
+ ).credential
325
+ );
326
+ if (
327
+ credential.id !== aggregate.credentialId ||
328
+ getCredentialIssuerId(credential) !== aggregate.issuerDid ||
329
+ computeCredentialSubjectDigest(credential.credentialSubject) !==
330
+ computeCredentialSubjectDigest(unsigned.credentialSubject) ||
331
+ computeCredentialStatusDigest(credential.credentialStatus) !==
332
+ aggregate.credentialStatusDigest ||
333
+ canonicalizeCredentialJson(credential.refreshService) !==
334
+ canonicalizeCredentialJson(unsigned.refreshService) ||
335
+ computeCredentialMaterialDigest(credential) !==
336
+ computeCredentialMaterialDigest(unsigned)
337
+ )
338
+ throw new TRPCError({
339
+ code: 'BAD_REQUEST',
340
+ message: 'Signing authority changed the prepared inbox credential',
341
+ });
342
+ await verifyManagedRefreshProof(
343
+ (await getLearnCard()).invoke,
344
+ credential,
345
+ aggregate.issuerDid
346
+ );
347
+ const managers = holderProfile
348
+ ? await getProfilesThatManageAProfile(holderProfile.profileId)
349
+ : [];
350
+ const encrypted = JSON.stringify(
351
+ await createDagJweForRecipients(credential, [
352
+ ...new Set([holderProfile?.did ?? holderDid, ...managers.map(p => p.did)]),
353
+ ])
354
+ );
355
+ const boost = inbox.boostUri ? await getBoostByUri(inbox.boostUri) : null;
356
+ if (inbox.boostUri && !boost)
357
+ throw new TRPCError({ code: 'NOT_FOUND', message: 'Boost not found' });
358
+ const id = randomUUID();
359
+ const now = new Date().toISOString();
360
+ const materialDigest = computeCredentialMaterialDigest(credential);
361
+ const etag = computeRefreshEtag(encrypted);
362
+ const effectiveTime = getCredentialEffectiveTime(credential);
363
+ const bound = await bindPendingInboxRefresh({
364
+ inboxId,
365
+ refreshId: aggregate.refreshId,
366
+ expectedVersion: aggregate.currentVersion,
367
+ issuerProfileId: issuer.profileId,
368
+ holderDid,
369
+ holderProfileId: holderProfile?.profileId,
370
+ boostId: boost?.id,
371
+ accepted,
372
+ deliveryCredential: encrypted,
373
+ deliveryExpiresAt: new Date(
374
+ Date.now() + INBOX_DELIVERY_RETENTION_DAYS * 86400000
375
+ ).toISOString(),
376
+ root: {
377
+ id,
378
+ credential: encrypted,
379
+ statusEntries: JSON.stringify(getBitstringStatusListEntries(credential)),
380
+ refreshId: aggregate.refreshId,
381
+ version: aggregate.currentVersion,
382
+ refreshVersionKey: `${aggregate.refreshId}:${aggregate.currentVersion}`,
383
+ publishedAt: aggregate.lastPublishedAt ?? now,
384
+ signingMode: 'signing-authority',
385
+ ...(effectiveTime === undefined
386
+ ? {}
387
+ : { effectiveAt: new Date(effectiveTime).toISOString() }),
388
+ ...(aggregate.updateSummary ? { updateSummary: aggregate.updateSummary } : {}),
389
+ etag,
390
+ },
391
+ aggregate: {
392
+ etag,
393
+ initialNotificationSuppressed:
394
+ accepted || issuer.profileId === holderProfile?.profileId,
395
+ materialDigest,
396
+ rootMaterialDigest: materialDigest,
397
+ credentialSubjectDigest: computeCredentialSubjectDigest(
398
+ credential.credentialSubject
399
+ ),
400
+ ...(boost ? { boostId: boost.id } : {}),
401
+ },
402
+ });
403
+ if (bound) return { credential, uri: getManagedCredentialUri(id, domain) };
404
+ }
405
+ throw new TRPCError({
406
+ code: 'CONFLICT',
407
+ message: 'Inbox refresh changed during claim; retry.',
408
+ });
409
+ };
410
+
411
+ /** Resume the initial notification after binding committed but delivery failed. No re-signing. */
412
+ export const resumeInboxRefreshDelivery = async (
413
+ refreshId: string,
414
+ domain: string
415
+ ): Promise<void> => {
416
+ const aggregate = await getCredentialRefresh(refreshId);
417
+ if (!aggregate?.holderProfileId || aggregate.initialNotificationSuppressed) return;
418
+ const root = await getInitialRefreshRoot(refreshId);
419
+ if (!root) return;
420
+ const [issuerProfile, holderProfile] = await Promise.all([
421
+ getProfileByProfileId(aggregate.issuerProfileId),
422
+ getProfileByProfileId(aggregate.holderProfileId),
423
+ ]);
424
+ if (!issuerProfile || !holderProfile) return;
425
+ await sendInitialCredentialNotificationOnce({
426
+ refreshId,
427
+ uri: getManagedCredentialUri(root.rootId, domain),
428
+ issuerProfile,
429
+ holderProfile,
430
+ initialNotificationSuppressed: false,
431
+ });
432
+ };