@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,273 @@
1
+ import type {
2
+ ShareContentActiveSummary,
3
+ ShareContentContentProjection,
4
+ ShareContentDeleteValue,
5
+ ShareContentEnvelope,
6
+ ShareContentOwnerRecovery,
7
+ ShareContentPutValue,
8
+ ShareContentRecoveryProjection,
9
+ ShareContentStatValue,
10
+ ShareContentTombstoneSummary,
11
+ } from './types';
12
+
13
+ /**
14
+ * Narrow local validators for the LearnCloud JSON response envelope. They are
15
+ * intentionally hand-written (rather than reusing a shared schema) so the
16
+ * transport contract is pinned here: every accepted field is checked, unknown
17
+ * fields are rejected, and no opaque payload is ever coerced or rewritten.
18
+ *
19
+ * Dates arrive as ISO-8601 strings because the C2 repository's `Date` values are
20
+ * JSON-serialized by the route.
21
+ */
22
+
23
+ const isPlainObject = (value: unknown): value is Record<string, unknown> =>
24
+ typeof value === 'object' &&
25
+ value !== null &&
26
+ !Array.isArray(value) &&
27
+ (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
28
+
29
+ const isNonEmptyString = (value: unknown): value is string =>
30
+ typeof value === 'string' && value.length > 0;
31
+
32
+ const isSafeIntegerAtLeast = (value: unknown, minimum: number): value is number =>
33
+ typeof value === 'number' && Number.isSafeInteger(value) && value >= minimum;
34
+
35
+ const isSha256Hex = (value: unknown): value is string =>
36
+ typeof value === 'string' && /^[0-9a-f]{64}$/.test(value);
37
+
38
+ const hasExactKeys = (value: Record<string, unknown>, keys: readonly string[]): boolean => {
39
+ const actual = Object.keys(value);
40
+
41
+ return actual.length === keys.length && actual.every(key => keys.includes(key));
42
+ };
43
+
44
+ const parseEnvelope = (value: unknown): ShareContentEnvelope | null => {
45
+ if (!isPlainObject(value) || !hasExactKeys(value, ['v', 'alg', 'iv', 'ct'])) return null;
46
+ if (value.v !== 1 || value.alg !== 'A256GCM') return null;
47
+ if (!isNonEmptyString(value.iv) || !isNonEmptyString(value.ct)) return null;
48
+
49
+ return { v: 1, alg: 'A256GCM', iv: value.iv, ct: value.ct };
50
+ };
51
+
52
+ const parseOwnerRecovery = (value: unknown): ShareContentOwnerRecovery | null =>
53
+ isPlainObject(value) ? { ...value } : null;
54
+
55
+ const parseTupleFields = (
56
+ value: Record<string, unknown>
57
+ ): {
58
+ namespace: string;
59
+ ownerProfileId: string;
60
+ shareId: string;
61
+ contentVersion: number;
62
+ objectId: string;
63
+ operationId: string;
64
+ } | null => {
65
+ if (!isNonEmptyString(value.namespace)) return null;
66
+ if (!isNonEmptyString(value.ownerProfileId)) return null;
67
+ if (!isNonEmptyString(value.shareId)) return null;
68
+ if (!isSafeIntegerAtLeast(value.contentVersion, 1)) return null;
69
+ if (!isNonEmptyString(value.objectId)) return null;
70
+ if (!isNonEmptyString(value.operationId)) return null;
71
+
72
+ return {
73
+ namespace: value.namespace,
74
+ ownerProfileId: value.ownerProfileId,
75
+ shareId: value.shareId,
76
+ contentVersion: value.contentVersion,
77
+ objectId: value.objectId,
78
+ operationId: value.operationId,
79
+ };
80
+ };
81
+
82
+ const parseActiveSummary = (value: unknown): ShareContentActiveSummary | null => {
83
+ if (!isPlainObject(value) || value.kind !== 'active') return null;
84
+ if (
85
+ !hasExactKeys(value, [
86
+ 'kind',
87
+ 'namespace',
88
+ 'ownerProfileId',
89
+ 'shareId',
90
+ 'contentVersion',
91
+ 'objectId',
92
+ 'operationId',
93
+ 'contentHash',
94
+ 'payloadHash',
95
+ 'ciphertextBytes',
96
+ 'recoveryBytes',
97
+ 'createdAt',
98
+ ])
99
+ )
100
+ return null;
101
+
102
+ const tuple = parseTupleFields(value);
103
+
104
+ if (!tuple) return null;
105
+ if (!isSha256Hex(value.contentHash) || !isSha256Hex(value.payloadHash)) return null;
106
+ if (!isSafeIntegerAtLeast(value.ciphertextBytes, 0)) return null;
107
+ if (!isSafeIntegerAtLeast(value.recoveryBytes, 0)) return null;
108
+ if (!isNonEmptyString(value.createdAt)) return null;
109
+
110
+ return {
111
+ kind: 'active',
112
+ ...tuple,
113
+ contentHash: value.contentHash,
114
+ payloadHash: value.payloadHash,
115
+ ciphertextBytes: value.ciphertextBytes,
116
+ recoveryBytes: value.recoveryBytes,
117
+ createdAt: value.createdAt,
118
+ };
119
+ };
120
+
121
+ const parseTombstoneSummary = (value: unknown): ShareContentTombstoneSummary | null => {
122
+ if (!isPlainObject(value) || value.kind !== 'tombstone') return null;
123
+
124
+ const allowed = [
125
+ 'kind',
126
+ 'namespace',
127
+ 'ownerProfileId',
128
+ 'shareId',
129
+ 'contentVersion',
130
+ 'objectId',
131
+ 'operationId',
132
+ 'contentHash',
133
+ 'deletedAt',
134
+ ];
135
+
136
+ if (Object.keys(value).some(key => !allowed.includes(key))) return null;
137
+
138
+ const tuple = parseTupleFields(value);
139
+
140
+ if (!tuple) return null;
141
+ if (value.contentHash !== undefined && !isSha256Hex(value.contentHash)) return null;
142
+ if (!isNonEmptyString(value.deletedAt)) return null;
143
+
144
+ return {
145
+ kind: 'tombstone',
146
+ ...tuple,
147
+ ...(value.contentHash !== undefined ? { contentHash: value.contentHash } : {}),
148
+ deletedAt: value.deletedAt,
149
+ };
150
+ };
151
+
152
+ export const parseShareContentActiveSummary = parseActiveSummary;
153
+ export const parseShareContentTombstoneSummary = parseTombstoneSummary;
154
+
155
+ export const parseShareContentStatValue = (value: unknown): ShareContentStatValue | null =>
156
+ parseActiveSummary(value) ?? parseTombstoneSummary(value);
157
+
158
+ export const parseShareContentDeleteValue = (value: unknown): ShareContentDeleteValue | null =>
159
+ parseTombstoneSummary(value);
160
+
161
+ export const parseShareContentPutValue = (value: unknown): ShareContentPutValue | null => {
162
+ if (!isPlainObject(value) || !hasExactKeys(value, ['status', 'record'])) return null;
163
+ if (value.status !== 'created' && value.status !== 'idempotent') return null;
164
+
165
+ const record = parseActiveSummary(value.record);
166
+
167
+ if (!record) return null;
168
+
169
+ return { status: value.status, record };
170
+ };
171
+
172
+ export const parseShareContentContentProjection = (
173
+ value: unknown
174
+ ): ShareContentContentProjection | null => {
175
+ if (!isPlainObject(value) || value.kind !== 'active') return null;
176
+ if (
177
+ !hasExactKeys(value, [
178
+ 'kind',
179
+ 'namespace',
180
+ 'ownerProfileId',
181
+ 'shareId',
182
+ 'contentVersion',
183
+ 'objectId',
184
+ 'operationId',
185
+ 'contentHash',
186
+ 'payloadHash',
187
+ 'envelope',
188
+ 'ciphertextBytes',
189
+ 'createdAt',
190
+ ])
191
+ )
192
+ return null;
193
+
194
+ const tuple = parseTupleFields(value);
195
+ const envelope = parseEnvelope(value.envelope);
196
+
197
+ if (!tuple || !envelope) return null;
198
+ if (!isSha256Hex(value.contentHash) || !isSha256Hex(value.payloadHash)) return null;
199
+ if (!isSafeIntegerAtLeast(value.ciphertextBytes, 0)) return null;
200
+ if (!isNonEmptyString(value.createdAt)) return null;
201
+
202
+ return {
203
+ kind: 'active',
204
+ ...tuple,
205
+ contentHash: value.contentHash,
206
+ payloadHash: value.payloadHash,
207
+ envelope,
208
+ ciphertextBytes: value.ciphertextBytes,
209
+ createdAt: value.createdAt,
210
+ };
211
+ };
212
+
213
+ export const parseShareContentRecoveryProjection = (
214
+ value: unknown
215
+ ): ShareContentRecoveryProjection | null => {
216
+ if (!isPlainObject(value) || value.kind !== 'active') return null;
217
+ if (
218
+ !hasExactKeys(value, [
219
+ 'kind',
220
+ 'namespace',
221
+ 'ownerProfileId',
222
+ 'shareId',
223
+ 'contentVersion',
224
+ 'objectId',
225
+ 'operationId',
226
+ 'contentHash',
227
+ 'payloadHash',
228
+ 'ownerEncryptedRecovery',
229
+ 'recoveryBytes',
230
+ 'createdAt',
231
+ ])
232
+ )
233
+ return null;
234
+
235
+ const tuple = parseTupleFields(value);
236
+ const recovery = parseOwnerRecovery(value.ownerEncryptedRecovery);
237
+
238
+ if (!tuple || !recovery) return null;
239
+ if (!isSha256Hex(value.contentHash) || !isSha256Hex(value.payloadHash)) return null;
240
+ if (!isSafeIntegerAtLeast(value.recoveryBytes, 0)) return null;
241
+ if (!isNonEmptyString(value.createdAt)) return null;
242
+
243
+ return {
244
+ kind: 'active',
245
+ ...tuple,
246
+ contentHash: value.contentHash,
247
+ payloadHash: value.payloadHash,
248
+ ownerEncryptedRecovery: recovery,
249
+ recoveryBytes: value.recoveryBytes,
250
+ createdAt: value.createdAt,
251
+ };
252
+ };
253
+
254
+ /** Parse the fixed `{ok:true,value}` / `{ok:false,error}` JSON envelope. */
255
+ export const parseShareContentResponseEnvelope = (
256
+ parsed: unknown
257
+ ): { ok: true; value: unknown } | { ok: false; error: string } | null => {
258
+ if (!isPlainObject(parsed)) return null;
259
+
260
+ if (parsed.ok === true) {
261
+ if (!('value' in parsed)) return null;
262
+
263
+ return { ok: true, value: parsed.value };
264
+ }
265
+
266
+ if (parsed.ok === false) {
267
+ if (typeof parsed.error !== 'string' || parsed.error.length === 0) return null;
268
+
269
+ return { ok: false, error: parsed.error };
270
+ }
271
+
272
+ return null;
273
+ };
@@ -0,0 +1,253 @@
1
+ /**
2
+ * LC-2187 Brain → LearnCloud share-content HTTP client types.
3
+ *
4
+ * This module defines the *transport* grammar for the fixed server-to-server
5
+ * contract. It is deliberately local to brain-service: production must never
6
+ * import LearnCloud runtime code, so the few shared literals (the six-field
7
+ * tuple, the operation names, the request-hash canon) are restated here and
8
+ * pinned by cross-implementation contract tests.
9
+ *
10
+ * The client never persists or logs the ciphertext, the owner recovery JWE, the
11
+ * signed token or the claims. Every value that crosses this boundary is either a
12
+ * non-secret binding or an already-encrypted opaque payload.
13
+ */
14
+
15
+ /**
16
+ * The exact operation allowlist. The operation is carried by the route, not the
17
+ * request body, so it is a client-side parameter, never a body field.
18
+ */
19
+ export const SHARE_CONTENT_OPERATIONS = ['put', 'get', 'stat', 'delete', 'readRecovery'] as const;
20
+
21
+ export type ShareContentOperation = (typeof SHARE_CONTENT_OPERATIONS)[number];
22
+
23
+ /** Signed purpose claim accepted by the C1 verifier. */
24
+ export const SHARE_CONTENT_AUTH_PURPOSE = 'lc-share-content/v1' as const;
25
+
26
+ /** Bound on the complete JSON request body. */
27
+ export const DEFAULT_MAX_SHARE_CONTENT_REQUEST_BYTES = 1024 * 1024;
28
+ /** Bound on the complete JSON response body. */
29
+ export const DEFAULT_MAX_SHARE_CONTENT_RESPONSE_BYTES = 2 * 1024 * 1024;
30
+ /** Maximum signed token lifetime in seconds; the contract caps this at 60. */
31
+ export const MAX_SHARE_CONTENT_TOKEN_TTL_SECONDS = 60;
32
+ export const DEFAULT_SHARE_CONTENT_REQUEST_TIMEOUT_MS = 10_000;
33
+ export const DEFAULT_SHARE_CONTENT_MAX_ATTEMPTS = 3;
34
+ export const DEFAULT_SHARE_CONTENT_RETRY_BACKOFF_MS = 200;
35
+ export const MAX_SHARE_CONTENT_RETRY_BACKOFF_MS = 5_000;
36
+
37
+ /** A256GCM envelope exactly as stored by LearnCloud. */
38
+ export type ShareContentEnvelope = {
39
+ v: 1;
40
+ alg: 'A256GCM';
41
+ iv: string;
42
+ ct: string;
43
+ };
44
+
45
+ /** Opaque owner-encrypted recovery JWE. Never interpreted by this module. */
46
+ export type ShareContentOwnerRecovery = Record<string, unknown>;
47
+
48
+ /**
49
+ * The exact six-field immutable tuple. Every request — including `put` — carries
50
+ * these fields and the route supplies the operation.
51
+ */
52
+ export type ShareContentTuple = {
53
+ namespace: string;
54
+ ownerProfileId: string;
55
+ shareId: string;
56
+ contentVersion: number;
57
+ objectId: string;
58
+ operationId: string;
59
+ };
60
+
61
+ export type ShareContentPutRequest = ShareContentTuple & {
62
+ envelope: ShareContentEnvelope;
63
+ ownerEncryptedRecovery: ShareContentOwnerRecovery;
64
+ };
65
+
66
+ /** Claims signed into the JWT-VP `nonce`; mirrors the reviewed C1 claim list. */
67
+ export type ShareContentAuthorizationClaims = {
68
+ iss: string;
69
+ aud: string;
70
+ purpose: typeof SHARE_CONTENT_AUTH_PURPOSE;
71
+ namespace: string;
72
+ op: ShareContentOperation;
73
+ shareId: string;
74
+ contentVersion: number;
75
+ ownerProfileId: string;
76
+ objectId: string;
77
+ operationId: string;
78
+ requestHash: string;
79
+ iat: number;
80
+ exp: number;
81
+ jti: string;
82
+ };
83
+
84
+ /**
85
+ * Injected signing adapter. The runtime implementation wraps the existing
86
+ * did:web LearnCard primitives; tests inject a fake or a checked-in DIDKit
87
+ * fixture. `claims` already contains a fresh CSPRNG `jti` and bounded times.
88
+ */
89
+ export type ShareContentTokenSigner = (claims: ShareContentAuthorizationClaims) => Promise<string>;
90
+
91
+ /** Response value: active object summary (no ciphertext or recovery). */
92
+ export type ShareContentActiveSummary = {
93
+ kind: 'active';
94
+ namespace: string;
95
+ ownerProfileId: string;
96
+ shareId: string;
97
+ contentVersion: number;
98
+ objectId: string;
99
+ operationId: string;
100
+ contentHash: string;
101
+ payloadHash: string;
102
+ ciphertextBytes: number;
103
+ recoveryBytes: number;
104
+ createdAt: string;
105
+ };
106
+
107
+ /** Response value: permanent tombstone summary. */
108
+ export type ShareContentTombstoneSummary = {
109
+ kind: 'tombstone';
110
+ namespace: string;
111
+ ownerProfileId: string;
112
+ shareId: string;
113
+ contentVersion: number;
114
+ objectId: string;
115
+ operationId: string;
116
+ contentHash?: string;
117
+ deletedAt: string;
118
+ };
119
+
120
+ export type ShareContentStatValue = ShareContentActiveSummary | ShareContentTombstoneSummary;
121
+
122
+ /** Response value for `put`. */
123
+ export type ShareContentPutValue = {
124
+ status: 'created' | 'idempotent';
125
+ record: ShareContentActiveSummary;
126
+ };
127
+
128
+ /** Response value for `get`: content projection, never owner recovery. */
129
+ export type ShareContentContentProjection = {
130
+ kind: 'active';
131
+ namespace: string;
132
+ ownerProfileId: string;
133
+ shareId: string;
134
+ contentVersion: number;
135
+ objectId: string;
136
+ operationId: string;
137
+ contentHash: string;
138
+ payloadHash: string;
139
+ envelope: ShareContentEnvelope;
140
+ ciphertextBytes: number;
141
+ createdAt: string;
142
+ };
143
+
144
+ /** Response value for `readRecovery`: owner-only projection, never ciphertext. */
145
+ export type ShareContentRecoveryProjection = {
146
+ kind: 'active';
147
+ namespace: string;
148
+ ownerProfileId: string;
149
+ shareId: string;
150
+ contentVersion: number;
151
+ objectId: string;
152
+ operationId: string;
153
+ contentHash: string;
154
+ payloadHash: string;
155
+ ownerEncryptedRecovery: ShareContentOwnerRecovery;
156
+ recoveryBytes: number;
157
+ createdAt: string;
158
+ };
159
+
160
+ /** Response value for `delete`: the permanent tombstone. */
161
+ export type ShareContentDeleteValue = ShareContentTombstoneSummary;
162
+
163
+ /**
164
+ * Stable, non-secret transport/repository codes. Routes and callers must map
165
+ * every one to a generic external result; none of them carry token or body data.
166
+ */
167
+ export type ShareContentClientErrorCode =
168
+ | 'DISABLED'
169
+ | 'INVALID_INPUT'
170
+ | 'UNAUTHORIZED'
171
+ | 'NOT_FOUND'
172
+ | 'CONFLICT'
173
+ | 'PAYLOAD_TOO_LARGE'
174
+ | 'UNAVAILABLE'
175
+ | 'UNEXPECTED_STATUS'
176
+ | 'MALFORMED_RESPONSE'
177
+ | 'RESPONSE_TOO_LARGE'
178
+ | 'RESPONSE_TUPLE_MISMATCH'
179
+ | 'REDIRECT_REJECTED'
180
+ | 'TIMEOUT'
181
+ | 'NETWORK_ERROR'
182
+ | 'SIGNING_FAILED';
183
+
184
+ export type ShareContentClientResult<T> =
185
+ { ok: true; value: T } | { ok: false; error: ShareContentClientErrorCode };
186
+
187
+ /** Transport errors that a bounded retry (with a fresh token/jti) may re-attempt. */
188
+ export const TRANSIENT_SHARE_CONTENT_ERRORS: readonly ShareContentClientErrorCode[] = [
189
+ 'UNAVAILABLE',
190
+ 'TIMEOUT',
191
+ 'NETWORK_ERROR',
192
+ ];
193
+
194
+ export const isTransientShareContentError = (code: ShareContentClientErrorCode): boolean =>
195
+ TRANSIENT_SHARE_CONTENT_ERRORS.includes(code);
196
+
197
+ /** Configuration/validation failure raised before any network I/O. */
198
+ export class ShareContentClientConfigurationError extends Error {
199
+ readonly code = 'SHARE_CONTENT_CLIENT_CONFIGURATION_ERROR';
200
+
201
+ constructor(message: string) {
202
+ super(message);
203
+ this.name = 'ShareContentClientConfigurationError';
204
+ }
205
+ }
206
+
207
+ export type ShareContentClientConfig = {
208
+ /** Fail-closed switch. When false every operation returns `DISABLED`. */
209
+ enabled: boolean;
210
+ /** Trusted origin, e.g. `https://learncloud.example`. No path/query/userinfo. */
211
+ origin: string;
212
+ /** Explicit stable opaque namespace accepted by C1/C2 (no `%`/`:`). */
213
+ namespace: string;
214
+ /** LearnCloud service DID (the token audience). */
215
+ audience: string;
216
+ /** Brain service DID the signer is expected to sign as. */
217
+ signerDid: string;
218
+ /**
219
+ * When true, a loopback `http://localhost`/`127.0.0.1`/`[::1]` origin is
220
+ * accepted for local tests/development. The cryptographic auth path is
221
+ * identical; there is never an unsigned bypass.
222
+ */
223
+ allowInsecureLoopback: boolean;
224
+ signer: ShareContentTokenSigner;
225
+ requestTimeoutMs: number;
226
+ maxAttempts: number;
227
+ retryBackoffMs: number;
228
+ maxRequestBytes: number;
229
+ maxResponseBytes: number;
230
+ /** Epoch-milliseconds clock, injectable for deterministic tests. */
231
+ now: () => number;
232
+ /** Bound sleep, injectable so retry tests do not wait. */
233
+ sleep: (ms: number) => Promise<void>;
234
+ /** Injectable fetch for tests; defaults to the global fetch. */
235
+ fetchImpl: typeof fetch;
236
+ };
237
+
238
+ export type ShareContentClient = {
239
+ readonly config: ShareContentClientConfig;
240
+ put: (
241
+ request: ShareContentPutRequest
242
+ ) => Promise<ShareContentClientResult<ShareContentPutValue>>;
243
+ get: (
244
+ request: ShareContentTuple
245
+ ) => Promise<ShareContentClientResult<ShareContentContentProjection>>;
246
+ stat: (request: ShareContentTuple) => Promise<ShareContentClientResult<ShareContentStatValue>>;
247
+ delete: (
248
+ request: ShareContentTuple
249
+ ) => Promise<ShareContentClientResult<ShareContentDeleteValue>>;
250
+ readRecovery: (
251
+ request: ShareContentTuple
252
+ ) => Promise<ShareContentClientResult<ShareContentRecoveryProjection>>;
253
+ };
@@ -0,0 +1,53 @@
1
+ import type { MaintenanceBudget } from './types';
2
+
3
+ /**
4
+ * True only for the maintenance budget that opted into whole-unit admission.
5
+ * Legacy/direct callers that pass a bare budget keep the reviewed `exhausted`
6
+ * gate and are never subjected to the extra mid-unit rechecks.
7
+ */
8
+ export const budgetHasUnitReserve = (budget: MaintenanceBudget | undefined): boolean =>
9
+ budget !== undefined && typeof budget.reserveMs === 'function';
10
+
11
+ /**
12
+ * Cooperative budget helpers shared by the recovery and cleanup runners.
13
+ *
14
+ * `budgetAllows` is deliberately conservative only when the caller opted into the
15
+ * maintenance reserve (`reserveMs`). Direct/legacy callers that pass a bare budget
16
+ * keep the reviewed `exhausted()` behaviour, so this cannot silently disable a
17
+ * one-shot runner that predates the maintenance scheduler.
18
+ */
19
+ export const budgetAllows = (budget: MaintenanceBudget | undefined, costMs: number): boolean => {
20
+ if (!budget) return true;
21
+
22
+ if (typeof budget.reserveMs !== 'function' || !Number.isFinite(costMs)) {
23
+ return !budget.exhausted();
24
+ }
25
+
26
+ const remaining = budget.remainingMs();
27
+ if (!Number.isFinite(remaining)) return false;
28
+
29
+ return remaining - budget.reserveMs() >= Math.max(0, costMs);
30
+ };
31
+
32
+ /**
33
+ * Bound a per-call managed-transaction timeout by the time actually left before
34
+ * the pass reserve. The result is always >= 1 so an explicit maintenance
35
+ * transaction still has a positive server-side bound; it can never extend the
36
+ * configured timeout.
37
+ */
38
+ export const boundTransactionTimeout = (
39
+ configuredTimeoutMs: number | undefined,
40
+ budget: MaintenanceBudget | undefined
41
+ ): number | undefined => {
42
+ if (configuredTimeoutMs === undefined) return undefined;
43
+ if (!budget) return configuredTimeoutMs;
44
+
45
+ const remaining = budget.remainingMs();
46
+ if (!Number.isFinite(remaining)) return configuredTimeoutMs;
47
+
48
+ const reserved = typeof budget.reserveMs === 'function' ? budget.reserveMs() : 0;
49
+ const available = remaining - reserved;
50
+ if (!Number.isFinite(available)) return configuredTimeoutMs;
51
+
52
+ return Math.max(1, Math.trunc(Math.min(configuredTimeoutMs, available)));
53
+ };