@cosmicdrift/kumiko-bundled-features 0.386.0 → 0.388.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (643) hide show
  1. package/LICENSE +21 -57
  2. package/dist/agent-tools/tool-catalog.js +1 -1
  3. package/dist/agent-tools/tool-dispatch.d.ts +7 -7
  4. package/dist/agent-tools/tool-dispatch.js +9 -9
  5. package/dist/audit/handlers/audit-events.js +1 -1
  6. package/dist/audit/screens.js +1 -1
  7. package/dist/auth-email-password/feature.js +1 -1
  8. package/dist/auth-email-password/handlers/change-password.write.js +3 -3
  9. package/dist/auth-email-password/handlers/confirm-token-flow.js +5 -5
  10. package/dist/auth-email-password/handlers/invite-accept-with-login.write.js +1 -1
  11. package/dist/auth-email-password/handlers/invite-accept.write.js +18 -18
  12. package/dist/auth-email-password/handlers/invite-create.write.d.ts +2 -2
  13. package/dist/auth-email-password/handlers/invite-create.write.js +10 -10
  14. package/dist/auth-email-password/handlers/invite-info.query.js +1 -1
  15. package/dist/auth-email-password/handlers/invite-signup-complete.write.js +24 -26
  16. package/dist/auth-email-password/handlers/login.write.d.ts +1 -1
  17. package/dist/auth-email-password/handlers/login.write.js +1 -1
  18. package/dist/auth-email-password/handlers/self-registration-status.query.js +1 -1
  19. package/dist/auth-email-password/handlers/signup-confirm.write.js +34 -37
  20. package/dist/auth-email-password/handlers/signup-request.write.js +6 -7
  21. package/dist/auth-email-password/handlers/switch-tenant-mfa-gate.write.d.ts +1 -1
  22. package/dist/auth-email-password/handlers/switch-tenant-mfa-gate.write.js +1 -4
  23. package/dist/auth-email-password/index.js +5 -5
  24. package/dist/auth-email-password/lockout-store.js +1 -1
  25. package/dist/auth-email-password/seeding.d.ts +42 -45
  26. package/dist/auth-email-password/seeding.js +51 -53
  27. package/dist/auth-email-password/signup-token-store.js +8 -8
  28. package/dist/auth-email-password/testing.js +3 -3
  29. package/dist/auth-email-password/web/auth-client.d.ts +2 -2
  30. package/dist/auth-email-password/web/auth-client.js +36 -37
  31. package/dist/auth-email-password/web/auth-form-primitives.js +10 -10
  32. package/dist/auth-email-password/web/auth-gate.js +15 -16
  33. package/dist/auth-email-password/web/client-plugin.d.ts +7 -7
  34. package/dist/auth-email-password/web/client-plugin.js +4 -5
  35. package/dist/auth-email-password/web/confirm-account-unlock-screen.js +1 -1
  36. package/dist/auth-email-password/web/constants.js +3 -3
  37. package/dist/auth-email-password/web/default-topbar-actions.d.ts +8 -8
  38. package/dist/auth-email-password/web/default-topbar-actions.js +6 -6
  39. package/dist/auth-email-password/web/forgot-password-screen.d.ts +2 -2
  40. package/dist/auth-email-password/web/forgot-password-screen.js +9 -9
  41. package/dist/auth-email-password/web/index.js +5 -5
  42. package/dist/auth-email-password/web/invite-accept-screen.d.ts +1 -1
  43. package/dist/auth-email-password/web/invite-accept-screen.js +16 -16
  44. package/dist/auth-email-password/web/login-screen.d.ts +1 -1
  45. package/dist/auth-email-password/web/login-screen.js +2 -3
  46. package/dist/auth-email-password/web/reset-password-screen.d.ts +4 -4
  47. package/dist/auth-email-password/web/reset-password-screen.js +12 -13
  48. package/dist/auth-email-password/web/session.d.ts +10 -9
  49. package/dist/auth-email-password/web/session.js +28 -29
  50. package/dist/auth-email-password/web/signup-complete-screen.js +3 -3
  51. package/dist/auth-email-password/web/signup-screen.d.ts +1 -1
  52. package/dist/auth-email-password/web/signup-screen.js +13 -13
  53. package/dist/auth-email-password/web/tenant-switcher.d.ts +4 -4
  54. package/dist/auth-email-password/web/tenant-switcher.js +21 -22
  55. package/dist/auth-email-password/web/use-shell-user.js +12 -13
  56. package/dist/auth-email-password/web/user-menu.d.ts +4 -4
  57. package/dist/auth-email-password/web/user-menu.js +12 -13
  58. package/dist/auth-email-password/web/verify-email-screen.d.ts +2 -2
  59. package/dist/auth-email-password/web/verify-email-screen.js +9 -10
  60. package/dist/auth-foundation/boot-checks.js +4 -4
  61. package/dist/auth-foundation/resolve-anonymous-access.d.ts +1 -1
  62. package/dist/auth-foundation/resolve-anonymous-access.js +3 -3
  63. package/dist/auth-foundation/types.js +2 -2
  64. package/dist/auth-mfa/feature-exports.d.ts +2 -2
  65. package/dist/auth-mfa/feature.js +8 -0
  66. package/dist/auth-mfa/handlers/disable.write.js +3 -3
  67. package/dist/auth-mfa/handlers/enable-confirm-preauth.write.js +4 -4
  68. package/dist/auth-mfa/handlers/enable-confirm.write.js +2 -2
  69. package/dist/auth-mfa/handlers/enable-start-preauth.write.js +1 -1
  70. package/dist/auth-mfa/handlers/reencrypt.job.js +1 -1
  71. package/dist/auth-mfa/handlers/regenerate-recovery.write.js +5 -5
  72. package/dist/auth-mfa/handlers/verify.write.js +1 -1
  73. package/dist/auth-mfa/token-secrets.js +1 -1
  74. package/dist/auth-mfa/web/client-plugin.d.ts +1 -1
  75. package/dist/auth-mfa/web/client-plugin.js +1 -1
  76. package/dist/auth-mfa/web/i18n.js +8 -4
  77. package/dist/auth-mfa/web/index.js +4 -4
  78. package/dist/auth-mfa/web/mfa-client.js +17 -16
  79. package/dist/auth-mfa/web/mfa-code-or-recovery-field.d.ts +11 -0
  80. package/dist/auth-mfa/web/mfa-code-or-recovery-field.js +12 -0
  81. package/dist/auth-mfa/web/mfa-disable-dialog.js +14 -3
  82. package/dist/auth-mfa/web/mfa-regenerate-recovery-dialog.js +14 -3
  83. package/dist/auth-mfa/web/mfa-setup-preauth-screen.js +10 -5
  84. package/dist/auth-mfa/web/mfa-verify-screen.js +32 -11
  85. package/dist/billing-foundation/aggregate-id.d.ts +5 -5
  86. package/dist/billing-foundation/aggregate-id.js +10 -11
  87. package/dist/billing-foundation/checkout-core.d.ts +9 -14
  88. package/dist/billing-foundation/checkout-core.js +24 -39
  89. package/dist/billing-foundation/consumer-protection/confirmation-mail.js +8 -2
  90. package/dist/billing-foundation/consumer-protection/consent-gate.d.ts +1 -0
  91. package/dist/billing-foundation/consumer-protection/consent-gate.js +1 -0
  92. package/dist/billing-foundation/consumer-protection/issue-confirmation.js +9 -3
  93. package/dist/billing-foundation/consumer-protection/mail-notifications.js +3 -1
  94. package/dist/billing-foundation/consumer-protection/termination-receipt-limit.d.ts +4 -2
  95. package/dist/billing-foundation/consumer-protection/termination-receipt-limit.js +6 -5
  96. package/dist/billing-foundation/consumer-protection/termination-record.d.ts +5 -1
  97. package/dist/billing-foundation/consumer-protection/termination-record.js +27 -17
  98. package/dist/billing-foundation/consumer-protection/termination-request.js +12 -7
  99. package/dist/billing-foundation/consumer-protection/termination-revoke.js +12 -7
  100. package/dist/billing-foundation/consumer-protection/termination-texts.d.ts +1 -1
  101. package/dist/billing-foundation/consumer-protection/termination-texts.js +3 -0
  102. package/dist/billing-foundation/consumer-protection/withdrawal-period.d.ts +5 -2
  103. package/dist/billing-foundation/consumer-protection/withdrawal-period.js +8 -9
  104. package/dist/billing-foundation/entities.js +27 -27
  105. package/dist/billing-foundation/events.d.ts +1 -0
  106. package/dist/billing-foundation/events.js +19 -17
  107. package/dist/billing-foundation/feature.js +45 -44
  108. package/dist/billing-foundation/get-subscription-for-tenant.d.ts +3 -3
  109. package/dist/billing-foundation/get-subscription-for-tenant.js +3 -5
  110. package/dist/billing-foundation/handlers/billing-plans.query.js +35 -5
  111. package/dist/billing-foundation/handlers/create-checkout-session.write.js +19 -17
  112. package/dist/billing-foundation/handlers/create-portal-session.write.js +11 -12
  113. package/dist/billing-foundation/handlers/list-subscriptions.query.js +4 -4
  114. package/dist/billing-foundation/handlers/plan-switch-preview.query.d.ts +13 -0
  115. package/dist/billing-foundation/handlers/plan-switch-preview.query.js +48 -0
  116. package/dist/billing-foundation/handlers/process-event.write.d.ts +6 -0
  117. package/dist/billing-foundation/handlers/process-event.write.js +28 -22
  118. package/dist/billing-foundation/handlers/start-plan-checkout.write.js +32 -5
  119. package/dist/billing-foundation/handlers/switch-plan.write.d.ts +2 -2
  120. package/dist/billing-foundation/handlers/switch-plan.write.js +56 -64
  121. package/dist/billing-foundation/handlers/sync-subscription.write.js +12 -1
  122. package/dist/billing-foundation/i18n.js +22 -0
  123. package/dist/billing-foundation/index.d.ts +1 -1
  124. package/dist/billing-foundation/plan-catalog.d.ts +21 -5
  125. package/dist/billing-foundation/plan-catalog.js +25 -16
  126. package/dist/billing-foundation/plan-switch.d.ts +12 -0
  127. package/dist/billing-foundation/plan-switch.js +60 -0
  128. package/dist/billing-foundation/projection.d.ts +15 -11
  129. package/dist/billing-foundation/projection.js +38 -37
  130. package/dist/billing-foundation/subscription-tier-sync.js +3 -3
  131. package/dist/billing-foundation/tenant-destroy-hook.d.ts +2 -2
  132. package/dist/billing-foundation/tenant-destroy-hook.js +7 -7
  133. package/dist/billing-foundation/types.d.ts +97 -42
  134. package/dist/billing-foundation/types.js +29 -20
  135. package/dist/billing-foundation/validate-options.js +17 -0
  136. package/dist/billing-foundation/web/billing-plans-panel.js +82 -36
  137. package/dist/billing-foundation/web/checkout-consent-dialog.d.ts +17 -3
  138. package/dist/billing-foundation/web/checkout-consent-dialog.js +14 -10
  139. package/dist/billing-foundation/web/constants.d.ts +4 -0
  140. package/dist/billing-foundation/web/constants.js +4 -0
  141. package/dist/billing-foundation/web/plan-price.d.ts +15 -0
  142. package/dist/billing-foundation/web/plan-price.js +32 -0
  143. package/dist/billing-foundation/web/plan-switch-confirm-dialog.d.ts +15 -0
  144. package/dist/billing-foundation/web/plan-switch-confirm-dialog.js +66 -0
  145. package/dist/cap-counter/aggregate-id.js +8 -9
  146. package/dist/cap-counter/cap-reservation.js +5 -1
  147. package/dist/cap-counter/constants.js +11 -12
  148. package/dist/cap-counter/enforce-cap.d.ts +59 -62
  149. package/dist/cap-counter/enforce-cap.js +49 -49
  150. package/dist/cap-counter/entity.js +29 -29
  151. package/dist/cap-counter/feature.js +34 -35
  152. package/dist/cap-counter/handlers/increment-rolling.write.d.ts +2 -2
  153. package/dist/cap-counter/handlers/increment-rolling.write.js +31 -31
  154. package/dist/cap-counter/handlers/mark-soft-warned.write.js +4 -5
  155. package/dist/cap-counter/stock-cap-guard.js +8 -2
  156. package/dist/cap-counter/with-cap-enforcement.d.ts +3 -5
  157. package/dist/channel-email/feature.js +1 -1
  158. package/dist/channel-email/smtp-transport.d.ts +18 -17
  159. package/dist/channel-email/smtp-transport.js +24 -21
  160. package/dist/channel-in-app/handlers/unread-count.query.js +3 -4
  161. package/dist/compliance-profiles/feature.js +4 -4
  162. package/dist/compliance-profiles/handlers/for-tenant.query.js +3 -6
  163. package/dist/compliance-profiles/handlers/list-profiles.query.js +5 -5
  164. package/dist/compliance-profiles/handlers/needs-profile.query.js +4 -4
  165. package/dist/compliance-profiles/handlers/set-profile.write.js +13 -14
  166. package/dist/compliance-profiles/handlers/sub-processors.query.js +9 -11
  167. package/dist/compliance-profiles/resolve-for-tenant.js +7 -7
  168. package/dist/compliance-profiles/schema/profile-selection.js +18 -23
  169. package/dist/compliance-profiles/seeding.js +14 -15
  170. package/dist/compliance-profiles-ops/handlers/tenants-missing-profile.query.js +3 -3
  171. package/dist/compliance-profiles-ops/index.js +2 -2
  172. package/dist/config/handlers/cascade.query.d.ts +5 -0
  173. package/dist/config/handlers/cascade.query.js +4 -3
  174. package/dist/config/handlers/readiness.query.d.ts +4 -4
  175. package/dist/config/handlers/readiness.query.js +1 -1
  176. package/dist/config/handlers/reencrypt.job.js +4 -5
  177. package/dist/config/handlers/set.write.js +4 -4
  178. package/dist/config/handlers/values.query.d.ts +5 -0
  179. package/dist/config/handlers/values.query.js +4 -3
  180. package/dist/config/resolver.js +4 -4
  181. package/dist/config/table.js +10 -10
  182. package/dist/config/write-helpers.d.ts +1 -0
  183. package/dist/config/write-helpers.js +19 -10
  184. package/dist/crypto-shredding/handlers/forget-subject.write.d.ts +2 -2
  185. package/dist/crypto-shredding/handlers/forget-subject.write.js +25 -21
  186. package/dist/custom-fields/aggregate-id.d.ts +12 -13
  187. package/dist/custom-fields/aggregate-id.js +16 -17
  188. package/dist/custom-fields/entity.js +49 -47
  189. package/dist/custom-fields/events.js +7 -8
  190. package/dist/custom-fields/feature.d.ts +14 -14
  191. package/dist/custom-fields/feature.js +53 -54
  192. package/dist/custom-fields/handlers/clear-custom-field.write.d.ts +3 -2
  193. package/dist/custom-fields/handlers/clear-custom-field.write.js +9 -8
  194. package/dist/custom-fields/handlers/define-tenant-field.write.d.ts +1 -1
  195. package/dist/custom-fields/handlers/define-tenant-field.write.js +2 -2
  196. package/dist/custom-fields/handlers/delete-system-field.write.js +6 -7
  197. package/dist/custom-fields/handlers/delete-tenant-field.write.d.ts +1 -1
  198. package/dist/custom-fields/handlers/delete-tenant-field.write.js +3 -3
  199. package/dist/custom-fields/handlers/set-custom-field.write.d.ts +3 -3
  200. package/dist/custom-fields/handlers/set-custom-field.write.js +25 -28
  201. package/dist/custom-fields/handlers/update-tenant-field.write.d.ts +1 -1
  202. package/dist/custom-fields/handlers/update-tenant-field.write.js +1 -1
  203. package/dist/custom-fields/lib/field-access.js +2 -2
  204. package/dist/custom-fields/lib/parse-serialized-field.js +1 -1
  205. package/dist/custom-fields/lib/quota.js +1 -1
  206. package/dist/custom-fields/lib/value-schema.js +10 -12
  207. package/dist/custom-fields/run-retention.js +3 -3
  208. package/dist/custom-fields/schemas.js +14 -14
  209. package/dist/custom-fields/web/client-plugin.js +2 -5
  210. package/dist/custom-fields/web/constants.js +2 -2
  211. package/dist/custom-fields/web/custom-fields-form-section.d.ts +4 -4
  212. package/dist/custom-fields/web/custom-fields-form-section.js +22 -22
  213. package/dist/custom-fields/wire-for-entity.js +65 -67
  214. package/dist/custom-fields/wire-user-data-rights.js +3 -3
  215. package/dist/data-retention/_internal/parse-override.js +2 -3
  216. package/dist/data-retention/feature.js +11 -18
  217. package/dist/data-retention/handlers/policy-for.query.js +6 -6
  218. package/dist/data-retention/keep-for.d.ts +7 -7
  219. package/dist/data-retention/keep-for.js +15 -15
  220. package/dist/data-retention/override-schema.d.ts +3 -4
  221. package/dist/data-retention/override-schema.js +13 -15
  222. package/dist/data-retention/presets.d.ts +4 -5
  223. package/dist/data-retention/presets.js +18 -23
  224. package/dist/data-retention/resolve-tenant-preset.js +17 -16
  225. package/dist/data-retention/resolver.d.ts +12 -12
  226. package/dist/data-retention/resolver.js +24 -23
  227. package/dist/data-retention/run-retention-cleanup.d.ts +8 -3
  228. package/dist/data-retention/run-retention-cleanup.js +61 -51
  229. package/dist/data-retention/schema/tenant-retention-override.js +13 -11
  230. package/dist/delivery/channel-context.js +6 -3
  231. package/dist/delivery/db/queries/preferences.js +2 -2
  232. package/dist/delivery/delivery-service.js +22 -7
  233. package/dist/delivery/feature.js +2 -2
  234. package/dist/delivery/handlers/log.query.js +1 -1
  235. package/dist/delivery/handlers/preferences.query.d.ts +1 -1
  236. package/dist/delivery/handlers/preferences.query.js +20 -1
  237. package/dist/delivery/handlers/unsubscribe-page-chrome.query.js +1 -1
  238. package/dist/delivery/tables.js +9 -8
  239. package/dist/delivery/unsubscribe-link.d.ts +3 -1
  240. package/dist/delivery/unsubscribe-page-strings.d.ts +1 -0
  241. package/dist/delivery/unsubscribe-page-strings.js +1 -0
  242. package/dist/delivery/unsubscribe-page.d.ts +2 -0
  243. package/dist/delivery/unsubscribe-page.js +5 -0
  244. package/dist/delivery/unsubscribe.js +29 -11
  245. package/dist/document-ingest-foundation/entity.js +4 -4
  246. package/dist/document-ingest-foundation/events.js +2 -2
  247. package/dist/document-ingest-foundation/feature.js +2 -2
  248. package/dist/document-ingest-foundation/pages.js +1 -1
  249. package/dist/document-ingest-foundation/tenant-destroy-hook.js +4 -4
  250. package/dist/feature-toggles/compose-tier-resolver.js +1 -1
  251. package/dist/feature-toggles/feature.js +1 -1
  252. package/dist/feature-toggles/global-feature-state-table.js +1 -1
  253. package/dist/feature-toggles/handlers/registered.query.js +5 -5
  254. package/dist/feature-toggles/toggle-sync-signal.js +1 -1
  255. package/dist/feature-toggles/web/constants.js +1 -1
  256. package/dist/file-derivatives/feature.d.ts +1 -1
  257. package/dist/file-derivatives/feature.js +1 -1
  258. package/dist/file-derivatives/handlers/public-variant.query.js +1 -1
  259. package/dist/file-derivatives/presets.js +1 -1
  260. package/dist/file-foundation/feature.js +6 -6
  261. package/dist/file-foundation/index.d.ts +1 -1
  262. package/dist/file-foundation/index.js +1 -1
  263. package/dist/file-foundation/read-file-ref-content.d.ts +3 -0
  264. package/dist/file-foundation/read-file-ref-content.js +6 -1
  265. package/dist/file-provider-inmemory/feature.d.ts +1 -1
  266. package/dist/file-provider-inmemory/feature.js +16 -16
  267. package/dist/file-provider-s3/env-named-feature.d.ts +0 -2
  268. package/dist/file-provider-s3/feature.js +16 -16
  269. package/dist/file-provider-s3/lib/s3-provider.js +6 -6
  270. package/dist/files/feature.js +6 -6
  271. package/dist/files-tenant-data/handlers/sweep-orphaned-derivatives.job.js +4 -4
  272. package/dist/files-tenant-data/hooks.js +24 -26
  273. package/dist/files-tenant-data/index.js +1 -1
  274. package/dist/folders/feature.d.ts +1 -1
  275. package/dist/folders/web/folder-manager.js +2 -2
  276. package/dist/folders/web/tree.js +5 -5
  277. package/dist/form-draft/db/queries/cleanup.js +3 -3
  278. package/dist/form-draft/db/queries/owned-file-refs.js +1 -1
  279. package/dist/form-draft/decrypt-draft.js +5 -1
  280. package/dist/form-draft/entity.js +3 -3
  281. package/dist/form-draft/feature.js +4 -5
  282. package/dist/form-draft/handlers/discard.write.js +1 -1
  283. package/dist/form-draft/release-file-refs.js +6 -6
  284. package/dist/form-draft/schemas.js +3 -3
  285. package/dist/form-draft/web/constants.js +0 -2
  286. package/dist/host-routing/dispatch.js +11 -20
  287. package/dist/inbound-mail-foundation/aggregate-id.d.ts +13 -13
  288. package/dist/inbound-mail-foundation/aggregate-id.js +19 -19
  289. package/dist/inbound-mail-foundation/connect-routes.js +4 -3
  290. package/dist/inbound-mail-foundation/constants.d.ts +22 -24
  291. package/dist/inbound-mail-foundation/constants.js +30 -33
  292. package/dist/inbound-mail-foundation/entities.d.ts +12 -12
  293. package/dist/inbound-mail-foundation/entities.js +47 -48
  294. package/dist/inbound-mail-foundation/events.d.ts +4 -3
  295. package/dist/inbound-mail-foundation/events.js +50 -47
  296. package/dist/inbound-mail-foundation/feature.js +39 -39
  297. package/dist/inbound-mail-foundation/handlers/account-state.js +8 -8
  298. package/dist/inbound-mail-foundation/handlers/connect-account.write.js +25 -26
  299. package/dist/inbound-mail-foundation/handlers/disconnect-account.write.js +7 -7
  300. package/dist/inbound-mail-foundation/handlers/ingest-message.write.js +50 -51
  301. package/dist/inbound-mail-foundation/handlers/list-accounts.query.js +8 -8
  302. package/dist/inbound-mail-foundation/handlers/list-messages.query.js +10 -10
  303. package/dist/inbound-mail-foundation/handlers/scope-visibility.js +3 -4
  304. package/dist/inbound-mail-foundation/handlers/update-account.write.d.ts +2 -2
  305. package/dist/inbound-mail-foundation/handlers/update-account.write.js +22 -14
  306. package/dist/inbound-mail-foundation/i18n.js +0 -1
  307. package/dist/inbound-mail-foundation/oauth-state.d.ts +5 -5
  308. package/dist/inbound-mail-foundation/oauth-state.js +11 -10
  309. package/dist/inbound-mail-foundation/projection.d.ts +4 -4
  310. package/dist/inbound-mail-foundation/projection.js +31 -29
  311. package/dist/inbound-mail-foundation/provider-factory.d.ts +4 -4
  312. package/dist/inbound-mail-foundation/provider-factory.js +9 -9
  313. package/dist/inbound-mail-foundation/retention-sweep.d.ts +5 -3
  314. package/dist/inbound-mail-foundation/retention-sweep.js +38 -36
  315. package/dist/inbound-mail-foundation/screens.js +0 -3
  316. package/dist/inbound-mail-foundation/tenant-destroy-hook.js +14 -16
  317. package/dist/inbound-mail-foundation/types.d.ts +49 -49
  318. package/dist/inbound-mail-foundation/types.js +21 -21
  319. package/dist/inbound-mail-foundation/watch-supervisor.d.ts +10 -10
  320. package/dist/inbound-mail-foundation/watch-supervisor.js +85 -67
  321. package/dist/inbound-provider-imap/credential-document.js +13 -13
  322. package/dist/inbound-provider-imap/feature.d.ts +2 -2
  323. package/dist/inbound-provider-imap/feature.js +42 -40
  324. package/dist/inbound-provider-imap/imap-client.d.ts +12 -11
  325. package/dist/inbound-provider-imap/imap-client.js +20 -19
  326. package/dist/inbound-provider-inmemory/feature.d.ts +9 -9
  327. package/dist/inbound-provider-inmemory/feature.js +19 -19
  328. package/dist/jobs/db/queries/retention.js +2 -2
  329. package/dist/jobs/db/queries/stale-run-sweep.js +3 -3
  330. package/dist/jobs/events.js +1 -1
  331. package/dist/jobs/feature.d.ts +1 -0
  332. package/dist/jobs/feature.js +13 -10
  333. package/dist/jobs/handlers/detail.query.js +4 -4
  334. package/dist/jobs/handlers/list.query.js +1 -1
  335. package/dist/jobs/handlers/projection-rebuild.job.js +1 -1
  336. package/dist/jobs/handlers/reindex-entity.job.js +1 -1
  337. package/dist/jobs/handlers/retry.write.js +1 -1
  338. package/dist/jobs/handlers/tenant-failures.query.d.ts +1 -1
  339. package/dist/jobs/handlers/tenant-failures.query.js +45 -41
  340. package/dist/jobs/handlers/tenant-runs.query.d.ts +1 -1
  341. package/dist/jobs/handlers/tenant-runs.query.js +54 -50
  342. package/dist/jobs/job-instant.js +1 -1
  343. package/dist/jobs/job-run-logger.js +15 -15
  344. package/dist/jobs/job-run-table.js +3 -3
  345. package/dist/jobs/screens.js +1 -1
  346. package/dist/jobs/tenant-job-failure-table.js +1 -1
  347. package/dist/jobs/tenant-job-run-table.js +1 -1
  348. package/dist/ledger/entity.js +5 -5
  349. package/dist/ledger/feature.js +3 -3
  350. package/dist/ledger/handlers/confirm-schedule-period.write.js +3 -3
  351. package/dist/ledger/recurring.js +12 -12
  352. package/dist/ledger/schemas.js +1 -1
  353. package/dist/ledger/web/constants.js +2 -2
  354. package/dist/ledger/web/index.js +7 -7
  355. package/dist/legal-pages/feature.d.ts +4 -4
  356. package/dist/legal-pages/feature.js +25 -26
  357. package/dist/legal-pages/markdown.js +3 -3
  358. package/dist/legal-pages/web/client-plugin.js +23 -24
  359. package/dist/legal-pages/web/index.js +0 -1
  360. package/dist/mail-foundation/feature.d.ts +5 -5
  361. package/dist/mail-foundation/feature.js +27 -25
  362. package/dist/mail-transport-inmemory/feature.d.ts +4 -4
  363. package/dist/mail-transport-inmemory/feature.js +27 -28
  364. package/dist/mail-transport-smtp/feature.js +20 -20
  365. package/dist/managed-pages/branding.js +6 -6
  366. package/dist/managed-pages/feature.d.ts +26 -26
  367. package/dist/managed-pages/feature.js +34 -34
  368. package/dist/managed-pages/handlers/by-slug.query.js +5 -6
  369. package/dist/managed-pages/handlers/by-tenant-published.query.js +2 -2
  370. package/dist/managed-pages/handlers/set.write.js +5 -7
  371. package/dist/managed-pages/screens/page-screens.js +11 -11
  372. package/dist/managed-pages/seeding.js +8 -8
  373. package/dist/managed-pages/table.js +13 -12
  374. package/dist/managed-pages/web/client-plugin.d.ts +1 -1
  375. package/dist/managed-pages/web/client-plugin.js +5 -5
  376. package/dist/managed-pages/web/i18n.js +1 -1
  377. package/dist/notes-history/entity.js +4 -4
  378. package/dist/notes-history/feature.d.ts +2 -2
  379. package/dist/notes-history-user-data/hooks.js +1 -1
  380. package/dist/page-render/layout.js +9 -9
  381. package/dist/page-render/markdown.js +11 -11
  382. package/dist/page-render/security-headers.js +7 -6
  383. package/dist/personal-access-tokens/feature.d.ts +1 -1
  384. package/dist/personal-access-tokens/feature.js +9 -5
  385. package/dist/personal-access-tokens/roles.js +2 -2
  386. package/dist/readiness/handlers/status.query.js +3 -3
  387. package/dist/renderer-foundation/api.js +12 -13
  388. package/dist/renderer-foundation/constants.js +2 -2
  389. package/dist/renderer-foundation/feature.js +7 -7
  390. package/dist/renderer-pdf/render-table-pdf.d.ts +1 -1
  391. package/dist/renderer-pdf/render-table-pdf.js +22 -10
  392. package/dist/secrets/feature.js +9 -9
  393. package/dist/secrets/web/constants.js +2 -2
  394. package/dist/seo/feature.js +3 -3
  395. package/dist/sessions/constants.d.ts +1 -1
  396. package/dist/sessions/constants.js +1 -1
  397. package/dist/sessions/feature.d.ts +2 -2
  398. package/dist/sessions/feature.js +12 -8
  399. package/dist/sessions/handlers/revoke-all-for-user.write.js +2 -2
  400. package/dist/sessions/handlers/revoke-all-others.write.js +2 -2
  401. package/dist/sessions/handlers/revoke.write.js +1 -1
  402. package/dist/sessions/schema/user-session.js +4 -4
  403. package/dist/sessions/screens.js +2 -2
  404. package/dist/sessions/session-callbacks.js +2 -2
  405. package/dist/sessions/session-revoked-event.js +2 -2
  406. package/dist/shared/assert-no-where-rule-in-ownership-write.js +1 -1
  407. package/dist/shared/decrypt-stored-pii.d.ts +1 -0
  408. package/dist/shared/decrypt-stored-pii.js +7 -2
  409. package/dist/shared/encrypt-for-direct-write.js +1 -1
  410. package/dist/shared/index.d.ts +1 -1
  411. package/dist/shared/index.js +1 -1
  412. package/dist/shared/mail-template-body.d.ts +6 -2
  413. package/dist/shared/mail-template-body.js +7 -4
  414. package/dist/shared/map-with-concurrency.js +5 -4
  415. package/dist/shared/parent-visibility.js +2 -2
  416. package/dist/shared/password-hashing.js +1 -1
  417. package/dist/shared/signup-handover.js +1 -2
  418. package/dist/shared/single-use-token-store.js +1 -1
  419. package/dist/step-dispatcher/feature.js +1 -0
  420. package/dist/subscription-dodo/client.d.ts +17 -0
  421. package/dist/subscription-dodo/client.js +31 -0
  422. package/dist/subscription-dodo/constants.d.ts +12 -0
  423. package/dist/subscription-dodo/constants.js +19 -0
  424. package/dist/subscription-dodo/feature.d.ts +37 -0
  425. package/dist/subscription-dodo/feature.js +144 -0
  426. package/dist/subscription-dodo/index.d.ts +2 -0
  427. package/dist/subscription-dodo/index.js +4 -0
  428. package/dist/subscription-dodo/plugin-methods.d.ts +23 -0
  429. package/dist/subscription-dodo/plugin-methods.js +260 -0
  430. package/dist/subscription-dodo/runtime.d.ts +27 -0
  431. package/dist/subscription-dodo/runtime.js +89 -0
  432. package/dist/subscription-dodo/verify-webhook.d.ts +37 -0
  433. package/dist/subscription-dodo/verify-webhook.js +189 -0
  434. package/dist/subscription-mollie/constants.js +15 -17
  435. package/dist/subscription-mollie/feature.d.ts +17 -18
  436. package/dist/subscription-mollie/feature.js +24 -24
  437. package/dist/subscription-mollie/index.js +3 -3
  438. package/dist/subscription-mollie/plugin-methods.d.ts +2 -2
  439. package/dist/subscription-mollie/plugin-methods.js +15 -14
  440. package/dist/subscription-mollie/verify-webhook.d.ts +10 -10
  441. package/dist/subscription-mollie/verify-webhook.js +27 -27
  442. package/dist/subscription-stripe/constants.js +4 -6
  443. package/dist/subscription-stripe/feature.d.ts +14 -14
  444. package/dist/subscription-stripe/feature.js +36 -34
  445. package/dist/subscription-stripe/index.js +6 -6
  446. package/dist/subscription-stripe/plugin-methods.js +18 -18
  447. package/dist/subscription-stripe/runtime.d.ts +1 -1
  448. package/dist/subscription-stripe/runtime.js +8 -7
  449. package/dist/subscription-stripe/verify-webhook.d.ts +11 -11
  450. package/dist/subscription-stripe/verify-webhook.js +59 -61
  451. package/dist/tags/feature.d.ts +3 -3
  452. package/dist/tags/screens.js +1 -1
  453. package/dist/template-resolver/api.d.ts +3 -2
  454. package/dist/template-resolver/api.js +34 -12
  455. package/dist/template-resolver/compile-document-body.js +1 -0
  456. package/dist/template-resolver/feature.js +2 -2
  457. package/dist/template-resolver/handlers/bundle-import.js +3 -3
  458. package/dist/template-resolver/handlers/copy-locale.write.d.ts +5 -1
  459. package/dist/template-resolver/handlers/copy-locale.write.js +22 -7
  460. package/dist/template-resolver/handlers/diff-to-system.query.js +3 -2
  461. package/dist/template-resolver/handlers/document-base.js +3 -2
  462. package/dist/template-resolver/handlers/find-by-id.query.js +8 -7
  463. package/dist/template-resolver/handlers/list.query.js +6 -7
  464. package/dist/template-resolver/handlers/overview.query.d.ts +3 -0
  465. package/dist/template-resolver/handlers/overview.query.js +6 -3
  466. package/dist/template-resolver/handlers/shared.js +2 -2
  467. package/dist/template-resolver/handlers/template-write.js +3 -3
  468. package/dist/template-resolver/handlers/tenant-override-counts.query.js +1 -3
  469. package/dist/template-resolver/handlers/tenant-override-selection.d.ts +2 -1
  470. package/dist/template-resolver/handlers/tenant-overrides.query.js +28 -5
  471. package/dist/template-resolver/handlers/upsert-system.write.js +3 -4
  472. package/dist/template-resolver/handlers/upsert-tenant.write.js +4 -5
  473. package/dist/template-resolver/handlers/usage.query.d.ts +2 -1
  474. package/dist/template-resolver/handlers/usage.query.js +26 -16
  475. package/dist/template-resolver/handlers/validate.query.js +7 -2
  476. package/dist/template-resolver/seeding.js +30 -14
  477. package/dist/template-resolver/store-template-resource.d.ts +1 -0
  478. package/dist/template-resolver/store-template-resource.js +19 -4
  479. package/dist/template-resolver/table.js +10 -11
  480. package/dist/template-resolver/template-delivery-policy.d.ts +0 -5
  481. package/dist/template-resolver/template-delivery-policy.js +0 -6
  482. package/dist/template-resolver/template-meta.js +7 -4
  483. package/dist/template-resolver/template-preview.js +4 -3
  484. package/dist/template-resolver/web/client-plugin.js +2 -2
  485. package/dist/template-resolver/web/constants.d.ts +2 -2
  486. package/dist/template-resolver/web/constants.js +3 -3
  487. package/dist/template-resolver/web/index.d.ts +1 -0
  488. package/dist/template-resolver/web/index.js +1 -0
  489. package/dist/template-resolver/web/mail-layout-constants.d.ts +5 -0
  490. package/dist/template-resolver/web/mail-layout-constants.js +7 -0
  491. package/dist/tenant/feature.js +7 -7
  492. package/dist/tenant/handlers/member-directory.query.d.ts +1 -0
  493. package/dist/tenant/handlers/member-directory.query.js +11 -4
  494. package/dist/tenant/handlers/members.query.js +1 -1
  495. package/dist/tenant/handlers/team-list.query.js +1 -1
  496. package/dist/tenant/handlers/tenant-directory.query.d.ts +1 -0
  497. package/dist/tenant/handlers/tenant-directory.query.js +9 -5
  498. package/dist/tenant/invitation-table.js +37 -40
  499. package/dist/tenant/membership-table.js +3 -3
  500. package/dist/tenant/schema/tenant.js +7 -9
  501. package/dist/tenant/screens.js +1 -1
  502. package/dist/tenant/seeding.d.ts +6 -5
  503. package/dist/tenant/seeding.js +12 -12
  504. package/dist/tenant/testing.js +5 -6
  505. package/dist/tenant/web/constants.js +2 -2
  506. package/dist/tenant-handover/events.js +5 -7
  507. package/dist/tenant-handover/feature.js +1 -1
  508. package/dist/tenant-handover/grant.js +1 -1
  509. package/dist/tenant-handover/handlers/claim.write.js +1 -1
  510. package/dist/tenant-handover/move-entity-graph.js +8 -9
  511. package/dist/tenant-handover/signup-handover-provider.js +1 -2
  512. package/dist/tenant-handover/transfer-graph.js +4 -5
  513. package/dist/tenant-lifecycle/boot-checks.js +1 -1
  514. package/dist/tenant-lifecycle/constants.d.ts +1 -0
  515. package/dist/tenant-lifecycle/constants.js +4 -0
  516. package/dist/tenant-lifecycle/feature.js +1 -1
  517. package/dist/tenant-lifecycle/run-tenant-destroy.js +2 -2
  518. package/dist/tenant-settings/constants.js +1 -1
  519. package/dist/tenant-settings/tenant-defaults.d.ts +1 -1
  520. package/dist/tenant-settings/tenant-defaults.js +9 -2
  521. package/dist/tier-engine/aggregate-id.d.ts +11 -11
  522. package/dist/tier-engine/aggregate-id.js +15 -16
  523. package/dist/tier-engine/compose-app.d.ts +14 -14
  524. package/dist/tier-engine/compose-app.js +1 -1
  525. package/dist/tier-engine/entity.js +18 -19
  526. package/dist/tier-engine/feature.d.ts +19 -17
  527. package/dist/tier-engine/feature.js +68 -69
  528. package/dist/tier-engine/handlers/active-tier.query.js +6 -7
  529. package/dist/tier-engine/handlers/get-tenant-tier.query.js +4 -4
  530. package/dist/tier-engine/handlers/set-tenant-tier.write.d.ts +7 -8
  531. package/dist/tier-engine/handlers/set-tenant-tier.write.js +7 -4
  532. package/dist/tier-engine/tier-resolver.js +2 -2
  533. package/dist/tier-engine/trial.js +8 -8
  534. package/dist/tier-engine/web/constants.js +2 -2
  535. package/dist/tier-engine/web/index.js +4 -4
  536. package/dist/user/db/queries/stream-tenant-backfill.js +8 -8
  537. package/dist/user/handlers/create.write.js +4 -4
  538. package/dist/user/schema/user.d.ts +11 -11
  539. package/dist/user/schema/user.js +45 -44
  540. package/dist/user/seeding.d.ts +15 -15
  541. package/dist/user/seeding.js +28 -28
  542. package/dist/user/testing.js +3 -3
  543. package/dist/user-data-rights/audit-download.d.ts +8 -8
  544. package/dist/user-data-rights/audit-download.js +19 -20
  545. package/dist/user-data-rights/boot-checks.js +1 -1
  546. package/dist/user-data-rights/deletion-token.js +1 -1
  547. package/dist/user-data-rights/feature.d.ts +49 -50
  548. package/dist/user-data-rights/feature.js +54 -53
  549. package/dist/user-data-rights/handlers/cancel-deletion.write.js +9 -9
  550. package/dist/user-data-rights/handlers/confirm-deletion-by-token.write.js +8 -8
  551. package/dist/user-data-rights/handlers/download-by-job.query.js +29 -30
  552. package/dist/user-data-rights/handlers/download-by-token.query.js +40 -42
  553. package/dist/user-data-rights/handlers/export-status.query.js +8 -9
  554. package/dist/user-data-rights/handlers/lift-restriction.write.js +7 -8
  555. package/dist/user-data-rights/handlers/list-download-attempts.query.js +2 -2
  556. package/dist/user-data-rights/handlers/my-audit-log.query.js +4 -4
  557. package/dist/user-data-rights/handlers/request-deletion-by-email.write.d.ts +5 -5
  558. package/dist/user-data-rights/handlers/request-deletion-by-email.write.js +16 -15
  559. package/dist/user-data-rights/handlers/request-deletion.write.d.ts +2 -2
  560. package/dist/user-data-rights/handlers/request-deletion.write.js +7 -9
  561. package/dist/user-data-rights/handlers/request-export.write.js +42 -41
  562. package/dist/user-data-rights/handlers/restrict-account.write.js +22 -19
  563. package/dist/user-data-rights/handlers/run-forget-cleanup.write.js +8 -8
  564. package/dist/user-data-rights/index.js +8 -10
  565. package/dist/user-data-rights/lib/default-mailers.js +3 -3
  566. package/dist/user-data-rights/lib/update-user-lifecycle.js +14 -17
  567. package/dist/user-data-rights/run-export-jobs.d.ts +38 -42
  568. package/dist/user-data-rights/run-export-jobs.js +130 -237
  569. package/dist/user-data-rights/run-forget-cleanup.d.ts +16 -20
  570. package/dist/user-data-rights/run-forget-cleanup.js +65 -83
  571. package/dist/user-data-rights/run-user-export.d.ts +34 -33
  572. package/dist/user-data-rights/run-user-export.js +55 -57
  573. package/dist/user-data-rights/schema/download-attempt.js +11 -11
  574. package/dist/user-data-rights/schema/download-token.js +37 -41
  575. package/dist/user-data-rights/schema/export-job.d.ts +4 -4
  576. package/dist/user-data-rights/schema/export-job.js +65 -67
  577. package/dist/user-data-rights/token-helpers.d.ts +8 -9
  578. package/dist/user-data-rights/token-helpers.js +21 -25
  579. package/dist/user-data-rights/web/client-plugin.d.ts +5 -5
  580. package/dist/user-data-rights/web/client-plugin.js +1 -1
  581. package/dist/user-data-rights/web/confirm-deletion-screen.js +6 -5
  582. package/dist/user-data-rights/web/constants.js +1 -1
  583. package/dist/user-data-rights/web/index.js +5 -5
  584. package/dist/user-data-rights/web/privacy-center-screen.js +14 -13
  585. package/dist/user-data-rights/web/public-deletion-gate.d.ts +4 -4
  586. package/dist/user-data-rights/web/request-deletion-screen.js +6 -6
  587. package/dist/user-data-rights/zip-path.d.ts +15 -15
  588. package/dist/user-data-rights/zip-path.js +41 -40
  589. package/dist/user-data-rights-defaults/feature.js +15 -15
  590. package/dist/user-data-rights-defaults/hooks/delivery-attempt.userdata-hook.js +3 -5
  591. package/dist/user-data-rights-defaults/hooks/file-ref.userdata-hook.js +45 -51
  592. package/dist/user-data-rights-defaults/hooks/job-run.userdata-hook.js +2 -2
  593. package/dist/user-data-rights-defaults/hooks/notification-preference.userdata-hook.js +1 -1
  594. package/dist/user-data-rights-defaults/hooks/user-session.userdata-hook.js +3 -3
  595. package/dist/user-data-rights-defaults/hooks/user.userdata-hook.js +32 -31
  596. package/dist/user-profile/handlers/change-email.write.js +13 -13
  597. package/dist/user-profile/index.js +3 -3
  598. package/dist/user-profile/web/client-plugin.js +1 -1
  599. package/dist/user-profile/web/constants.js +1 -1
  600. package/dist/user-profile/web/profile-screen.js +1 -1
  601. package/dist/waitlist/handlers/export-purge.write.js +2 -1
  602. package/dist/waitlist/handlers/submit.write.js +5 -5
  603. package/dist/waitlist/import.d.ts +1 -0
  604. package/dist/waitlist/import.js +4 -0
  605. package/dist/waitlist/legacy-migrate.js +17 -6
  606. package/dist/waitlist/link-on-signup.js +18 -6
  607. package/dist/waitlist/options.d.ts +3 -0
  608. package/dist/workflow-runner/aggregate-id.d.ts +1 -1
  609. package/dist/workflow-runner/aggregate-id.js +1 -1
  610. package/dist/workflow-runner/event-subscriber.js +4 -5
  611. package/dist/workflow-runner/event-trigger.js +4 -17
  612. package/dist/workflow-runner/feature.js +2 -2
  613. package/dist/workflow-runner/handlers/resume-run.write.js +4 -4
  614. package/dist/workflow-runner/pending-projection.js +6 -7
  615. package/dist/workflow-runner/runner.js +6 -6
  616. package/dist/workflow-runner/tables.js +6 -6
  617. package/dist/workflow-runner/workflow-registry.js +1 -1
  618. package/package.json +20 -10
  619. package/src/agent-tools/changes.json +6 -0
  620. package/src/audit/changes.json +12 -0
  621. package/src/auth-mfa/changes.json +6 -0
  622. package/src/billing-foundation/changes.json +55 -0
  623. package/src/cap-counter/changes.json +18 -0
  624. package/src/channel-email/changes.json +6 -0
  625. package/src/config/changes.json +12 -0
  626. package/src/crypto-shredding/changes.json +6 -0
  627. package/src/delivery/changes.json +30 -0
  628. package/src/form-draft/changes.json +6 -0
  629. package/src/host-routing/changes.json +6 -0
  630. package/src/inbound-mail-foundation/changes.json +18 -0
  631. package/src/jobs/changes.json +13 -0
  632. package/src/mail-foundation/changes.json +6 -0
  633. package/src/renderer-pdf/changes.json +6 -0
  634. package/src/step-dispatcher/changes.json +6 -0
  635. package/src/subscription-dodo/changes.json +14 -0
  636. package/src/subscription-stripe/changes.json +12 -0
  637. package/src/template-resolver/changes.json +48 -0
  638. package/src/tenant/changes.json +6 -0
  639. package/src/tenant-lifecycle/changes.json +6 -0
  640. package/src/tier-engine/changes.json +6 -0
  641. package/src/waitlist/changes.json +18 -0
  642. package/dist/billing-foundation/consumer-protection/stored-user-email.d.ts +0 -1
  643. package/dist/billing-foundation/consumer-protection/stored-user-email.js +0 -8
@@ -1,4 +1,4 @@
1
- // kumiko-lint-ignore app-feature-structure Phase-3 conversion tracked in #2312 (feature.ts > 300 lines)
1
+ // kumiko-lint-ignore app-feature-structure feature.ts is over 300 lines and not yet split
2
2
  import { UNKNOWN_CLIENT_IP } from "@cosmicdrift/kumiko-framework/api";
3
3
  import { createSystemConfig, createSystemUser, defineFeature, EXT_USER_DATA, i18nKey, SYSTEM_USER_ID, } from "@cosmicdrift/kumiko-framework/engine";
4
4
  import { createFallbackLogger } from "@cosmicdrift/kumiko-framework/logging";
@@ -61,16 +61,16 @@ export function createUserDataRightsFeature(opts = {}) {
61
61
  r.envSchema(deletionTokenSecretEnvSchema);
62
62
  r.usesApi("compliance.forTenant");
63
63
  r.usesApi("retention.policyFor");
64
- // S2.U6 — restrict-account ruft sessions.revokeAllForUser cross-feature.
65
- // r.usesApi sorgt fuer Boot-Validation: App ohne sessions-feature wirft
66
- // beim Boot, statt erst beim ersten Restrict-Call ein opaque "handler
67
- // not found" zu werfen.
64
+ // restrict-account calls sessions.revokeAllForUser across features.
65
+ // r.usesApi enables boot validation: without the sessions feature, the app
66
+ // fails at boot instead of raising an opaque "handler not found" error
67
+ // on the first restrict call.
68
68
  r.usesApi("sessions.revokeAllForUser");
69
- // file-foundation ist soft-dep: nur der Export-Worker (Atom 3b)
70
- // braucht ihn fuer Storage-Schreiben. Apps die nur Forget nutzen
71
- // (kein Export) muessen file-foundation nicht mounten.
69
+ // file-foundation is a soft dependency: only the export worker needs it
70
+ // for storage writes. Apps that use only forget (not export) do not need
71
+ // to mount file-foundation.
72
72
  r.extendsRegistrar(EXT_USER_DATA, {});
73
- // GDPR-storage guards V2+V3 (#1314) — moved off the framework-internal
73
+ // GDPR-storage guards V2+V3 — moved off the framework-internal
74
74
  // boot-validator onto this feature's own r.bootCheck(), since it's the
75
75
  // EXT_USER_DATA channel owner: any r.useExtension(EXT_USER_DATA, ...)
76
76
  // usage already requires user-data-rights to be mounted.
@@ -93,20 +93,20 @@ export function createUserDataRightsFeature(opts = {}) {
93
93
  options: ["single-user", "multi-user"],
94
94
  env: "TENANT_MODEL",
95
95
  }));
96
- // S2.U3 Atom 1b — ExportJob-Lifecycle-Entity.
96
+ // ExportJob-Lifecycle-Entity.
97
97
  r.entity({ name: "export-job", ...exportJobEntity });
98
- // S2.U3 Atom 4a — Download-Token-Entity. Worker generiert Token beim
99
- // Flip auf done (siehe run-export-jobs.ts). Hash in DB, plain im
100
- // RunExportJobsResult fuer Atom 5 (Notification per Email).
98
+ // The worker generates the token when flipping the job to done (see
99
+ // run-export-jobs.ts). The hash is stored in the database, while the plain
100
+ // token is kept in RunExportJobsResult for email notification.
101
101
  r.entity({ name: "export-download-token", ...exportDownloadTokenEntity });
102
- // S2.U7 — Audit-Trail invalid Download-Attempts (DPO Brute-Force-Detection).
102
+ // Audit-Trail invalid Download-Attempts (DPO Brute-Force-Detection).
103
103
  r.entity({ name: "download-attempt", ...downloadAttemptEntity });
104
- // S2.U6 — DSGVO Art. 18 Account-Freeze (Verarbeitungs-Pause).
105
- // Endpoints fuer Restrict + Lift. Login-Block fuer Restricted Users
106
- // lebt in auth-email-password/login.write.ts.
104
+ // GDPR Article 18 account freeze (pause processing).
105
+ // The endpoints restrict and lift the restriction. The login block for
106
+ // restricted users lives in auth-email-password/login.write.ts.
107
107
  r.writeHandler(restrictAccountWrite);
108
108
  r.writeHandler(liftRestrictionWrite);
109
- // S2.U5a — Endpoints fuer DSGVO Art. 17 Forget-Pfad mit Grace.
109
+ // Endpoints for the GDPR Article 17 forget path with a grace period.
110
110
  r.writeHandler(createRequestDeletionHandler({
111
111
  ...(opts.sendDeletionRequestedEmail && {
112
112
  sendDeletionRequestedEmail: opts.sendDeletionRequestedEmail,
@@ -129,26 +129,26 @@ export function createUserDataRightsFeature(opts = {}) {
129
129
  r.writeHandler(createConfirmDeletionByTokenHandler(opts.deletionTokenSecret !== undefined
130
130
  ? { deletionTokenSecret: opts.deletionTokenSecret }
131
131
  : {}));
132
- // S2.U5b — Cleanup-Runner als privileged-Handler. Atom 5b: Wenn
133
- // sendDeletionExecutedEmail gesetzt, reicht der Handler den Callback
134
- // an runForgetCleanup weiter (Worker cached userEmail+tenantIds
135
- // PRE-tx, siehe run-forget-cleanup.ts).
132
+ // Cleanup runner as a privileged handler. When
133
+ // sendDeletionExecutedEmail is set, the handler passes the callback to
134
+ // runForgetCleanup; the worker caches userEmail+tenantIds before the
135
+ // transaction (see run-forget-cleanup.ts).
136
136
  r.writeHandler(createRunForgetCleanupHandler(opts.sendDeletionExecutedEmail
137
137
  ? { sendDeletionExecutedEmail: opts.sendDeletionExecutedEmail }
138
138
  : {}));
139
139
  r.exposesApi("userDataRights.runForget");
140
- // S2.U3 Atom 2 — User-Touchpoints fuer Async Export-Pipeline.
140
+ // User touchpoints for the asynchronous export pipeline.
141
141
  r.writeHandler(requestExportWrite);
142
142
  r.queryHandler(exportStatusQuery);
143
143
  r.exposesApi("userDataRights.runExport");
144
- // S2.U3 Atom 4b — Download-Endpoints (Token-Pfad + Session-Pfad).
145
- // Beide query-handlers verifizieren Token/Session, holen signed-URL
146
- // vom Storage-Provider, und persistieren Audit-Felder am Token-Row.
147
- // r.httpRoute-Wrapper unten machen den 302-Redirect zu signedUrl.
144
+ // Download endpoints for token and session paths.
145
+ // Both query handlers verify the token or session, obtain a signed URL
146
+ // from the storage provider, and persist audit fields on the token row.
147
+ // The r.httpRoute wrappers below issue the 302 redirect to signedUrl.
148
148
  r.queryHandler(downloadByTokenQuery);
149
149
  r.queryHandler(downloadByJobQuery);
150
- // S2.U7 — User-Selbstauskunft (Art. 15) + Operator-Sicht auf
151
- // invalid Download-Attempts (DPO).
150
+ // User self-access under Article 15 and operator access to invalid download
151
+ // attempts (DPO).
152
152
  r.queryHandler(myAuditLogQuery);
153
153
  r.queryHandler(listDownloadAttemptsQuery);
154
154
  // Read-only GDPR operator inspector (SystemAdmin) — screens stay inert until an app navs them.
@@ -306,12 +306,12 @@ export function createUserDataRightsFeature(opts = {}) {
306
306
  // Magic-link path (anonymous): the email link carries the token as a
307
307
  // URL fragment (`#token=<plain>`) instead of a query param — fragments
308
308
  // never leave the browser, so they never hit proxy/access logs
309
- // (issue #1271). This route only serves the interstitial page; the
309
+ // This route only serves the interstitial page; the
310
310
  // external script reads the fragment client-side and exchanges the
311
311
  // token via POST for the signed URL.
312
312
  //
313
- // No `?token=` query fallback: framework is zero-legacy (#1512) — no
314
- // live customer data / no pre-#1271 emails in flight that would need
313
+ // No `?token=` query fallback: framework is zero-legacy — no
314
+ // live customer data / no emails in flight that would need
315
315
  // bridging, so there's nothing a fallback would need to cover. A query
316
316
  // param reaches the server as part of the request URL and gets written
317
317
  // to proxy/access logs regardless of what the handler does with it
@@ -353,7 +353,7 @@ export function createUserDataRightsFeature(opts = {}) {
353
353
  },
354
354
  });
355
355
  // Exchange endpoint for the interstitial page: the token arrives here
356
- // as a POST body instead of a query string (issue #1271). A dedicated
356
+ // as a POST body instead of a query string. A dedicated
357
357
  // route rather than letting the browser JS call /api/query directly,
358
358
  // for two reasons:
359
359
  // 1. IP/UA audit — extractAuditMeta needs the raw request headers and
@@ -391,7 +391,7 @@ export function createUserDataRightsFeature(opts = {}) {
391
391
  // defaults to 0, ignoring headers entirely) nor a socket, so every
392
392
  // fragment-POST download would fall to the shared "unknown" bucket,
393
393
  // turning the per-user 30/min backstop into one global bucket an
394
- // attacker can exhaust for everyone (#1307). Passing `clientIp`
394
+ // attacker can exhaust for everyone. Passing `clientIp`
395
395
  // directly as env — the same server-resolved, trustedProxyHops-
396
396
  // aware value the outer request already trusted — reaches
397
397
  // extractSocketAddress() without going through header/hop-count
@@ -417,7 +417,7 @@ export function createUserDataRightsFeature(opts = {}) {
417
417
  unit: "seconds",
418
418
  description: "Unix timestamp of the last export storage-cleanup pass that completed. Alert on time() minus this value exceeding the cron interval plus a buffer; the backlog-age gauge alone stays at its last value when the cron stops.",
419
419
  });
420
- // S2.U3 Atom 3b — Worker fuer Async Export-Pipeline. Cron-getriggert.
420
+ // Worker for the asynchronous export pipeline, triggered by a cron job.
421
421
  const RUN_EXPORT_JOBS_REASON = "processes pending export jobs across every tenant";
422
422
  r.job({
423
423
  name: "run-export-jobs",
@@ -429,9 +429,9 @@ export function createUserDataRightsFeature(opts = {}) {
429
429
  throw new Error("run-export-jobs: ctx.registry required (JobContext incomplete)");
430
430
  }
431
431
  const T = (await import("@cosmicdrift/kumiko-framework/time")).getTemporal();
432
- // SYSTEM_USER_ID ist die framework-weite Konvention. Der job-
433
- // Discriminator wird via handlerName="user-data-rights:run-export-
434
- // jobs" im Secret-Read-Audit erfasst.
432
+ // SYSTEM_USER_ID is the framework-wide convention. The job discriminator is
433
+ // recorded in the secret-read audit through
434
+ // handlerName="user-data-rights:run-export-jobs".
435
435
  const exportUserId = SYSTEM_USER_ID;
436
436
  const exportDb = ctx.db.unsafeRaw(); // @cast-boundary db-operator — jobs never run inside a DbTx
437
437
  const exportRegistry = ctx.registry;
@@ -441,12 +441,13 @@ export function createUserDataRightsFeature(opts = {}) {
441
441
  const exportMetrics = ctx.meter
442
442
  ? createMetricsHandle(ctx.meter, "user-data-rights")
443
443
  : createNoopMetricsHandle();
444
- // C6 — ohne eigene send*Email-Opts aber mit gemountetem mail-transport
445
- // versendet der Cron die Export-Notifications selbst (Default-Templates).
446
- // Der Resolver baut den per-Tenant-Transport aus configResolver — gleiche
447
- // Bruecke wie buildStorageProvider.
448
- // The cron runs across tenants: each mail needs a notify bound to the
449
- // recipient's tenant (template override, channel config).
444
+ // Without explicit send*Email options, a mounted mail transport sends the
445
+ // export notifications itself using the default templates. The resolver
446
+ // builds the per-tenant transport from configResolver, bridging it in
447
+ // the same way as buildStorageProvider.
448
+ // The cron runs across tenants, so each mail needs a notify function
449
+ // bound to the recipient's tenant for template overrides and channel
450
+ // configuration.
450
451
  const notifyFactory = ctx._notifyFactory;
451
452
  const exportNotifyFor = notifyFactory !== undefined && isGdprMailDeliveryAvailable(exportRegistry)
452
453
  ? (tenantId) => notifyFactory(createSystemUser(tenantId), tenantId)
@@ -483,9 +484,9 @@ export function createUserDataRightsFeature(opts = {}) {
483
484
  handlerName: "user-data-rights:run-export-jobs",
484
485
  }),
485
486
  now: T.Now.instant(),
486
- // App-Author-Callbacks haben Vorrang; sonst greift die mail-foundation-
487
- // Default oben. Beide optional: ohne mail-transport + ohne Callback
488
- // bleibt es bei Polling via export-status.query.
487
+ // App-author callbacks take precedence; otherwise the mail-foundation default
488
+ // is used. Both are optional: without a mail transport or callback,
489
+ // clients continue polling via export-status.query.
489
490
  ...(sendExportReadyEmail && { sendExportReadyEmail }),
490
491
  ...(sendExportFailedEmail && { sendExportFailedEmail }),
491
492
  ...(opts.appExportDownloadUrl !== undefined && {
@@ -498,11 +499,11 @@ export function createUserDataRightsFeature(opts = {}) {
498
499
  });
499
500
  },
500
501
  });
501
- // Autonomer Art.17-Forget-Cron. Spiegelt run-export-jobs: nach Ablauf der
502
- // Grace-Period laeuft runForgetCleanup unbeaufsichtigt (der manuelle
503
- // userDataRights.runForget-API bleibt fuer Operator-Runs). Ohne diesen
504
- // Cron bleibt jeder Loesch-Antrag fuer immer in DeletionRequested haengen
505
- // — Art.17 wuerde nie ausgefuehrt.
502
+ // Automatic Article 17 forget cron. After the grace period, it runs
503
+ // runForgetCleanup without supervision; the manual
504
+ // userDataRights.runForget API remains available for operator runs.
505
+ // Without this cron, deletion requests would remain in
506
+ // DeletionRequested indefinitely and Article 17 erasure would never run.
506
507
  const RUN_FORGET_CLEANUP_REASON = "executes overdue Art.17 forget requests across every tenant";
507
508
  r.job({
508
509
  name: "run-forget-cleanup",
@@ -568,7 +569,7 @@ export function createUserDataRightsFeature(opts = {}) {
568
569
  escapeHatchAuditLog: ctx.log,
569
570
  actor: ctx.systemUser.id,
570
571
  });
571
- // Persist each incomplete report on the job-run log (#1572). The write
572
+ // Persist each incomplete report on the job-run log. The write
572
573
  // handler returns incomplete[] in its response; the cron path used to
573
574
  // discard the array (only a console.warn for rolledBack cases).
574
575
  // ctx.log feeds createJobRunLogger → store_job_run_logs.
@@ -5,17 +5,17 @@ import { isWithinGracePeriod } from "../../shared/index.js";
5
5
  import { USER_STATUS, userTable } from "../../user/index.js";
6
6
  import { updateUserLifecycle } from "../lib/update-user-lifecycle.js";
7
7
  const APPEND_LIFECYCLE_EVENT_REASON = "appends the user lifecycle event on the SYSTEM_TENANT_ID user stream";
8
- // POST /api/user/cancel-deletion (S2.U5).
8
+ // POST /api/user/cancel-deletion.
9
9
  //
10
- // Innerhalb der Grace-Period kann User seinen Forget-Antrag zurueck-
11
- // nehmen. Setzt:
10
+ // During the grace period, the user can withdraw a pending deletion request.
11
+ // This restores:
12
12
  // - status = "active"
13
13
  // - gracePeriodEnd = null
14
14
  //
15
- // Nach Grace-Period: 422 (run-forget-cleanup hat in der Zwischenzeit
16
- // die Hooks schon getriggert — Reversal nicht moeglich).
15
+ // After the grace period, return 422 because cleanup may already have triggered
16
+ // irreversible hooks.
17
17
  //
18
- // Sonderfall: Cancel als "active"-User → 422 (kein pending Forget).
18
+ // Cancelling as an "active" user also returns 422 because no deletion is pending.
19
19
  export const cancelDeletionWrite = defineWriteHandler({
20
20
  name: "cancel-deletion",
21
21
  schema: z.object({}),
@@ -48,12 +48,12 @@ export const cancelDeletionWrite = defineWriteHandler({
48
48
  await updateUserLifecycle(ctx.db.unsafeRaw(), event.user.id, {
49
49
  status: USER_STATUS.Active,
50
50
  gracePeriodEnd: null,
51
- // #354/1: closes the replay-after-cancel window — a still-TTL-valid email
51
+ // Closes the replay-after-cancel window — a still-TTL-valid email
52
52
  // token verified against the nulled requestId can no longer arm a second grace period.
53
53
  pendingDeletionRequestId: null,
54
54
  });
55
- // gracePeriodEnd=null im Response symmetrisch zu request-deletion's
56
- // ISO-Timestamp — Frontend kann beide Endpoints uniform behandeln.
55
+ // gracePeriodEnd=null in the response mirrors request-deletion's
56
+ // ISO timestamp so the frontend can handle both endpoints uniformly.
57
57
  const gracePeriodEnd = null;
58
58
  return {
59
59
  isSuccess: true,
@@ -4,15 +4,15 @@ import * as z from "zod";
4
4
  import { USER_STATUS, userTable } from "../../user/index.js";
5
5
  import { redeemDeletionToken } from "../deletion-token.js";
6
6
  import { resolveGracePeriod, startDeletionGracePeriod } from "./deletion-grace-period.js";
7
- // Generischer 422 für jeden Token-Fehlerpfad (malformed / bad_signature /
8
- // expired / kein Secret) — kein Signal ob ein Token zu einem User gehört.
7
+ // Use the same generic 422 for every token-error path (malformed / bad_signature /
8
+ // expired / missing secret) so callers cannot determine whether a token belongs to a user.
9
9
  function invalidToken() {
10
10
  return new UnprocessableError("invalid_or_expired_token");
11
11
  }
12
- // userId stammt aus dem noch-unverifizierten Token (Angreifer-Eingabe). Ein
13
- // fehlgeschlagener Lookup — z.B. eine typfremde id auf einer int/uuid-Spalte —
14
- // darf nicht als 500 durchschlagen; null behandelt der Caller wie "kein offener
15
- // Antrag" (generischer 422). Die HMAC-Prüfung bleibt der eigentliche Gate.
12
+ // userId comes from the not-yet-verified token (attacker-controlled input). A failed
13
+ // lookup—for example, a type-mismatched id on an int/uuid column—must not surface as a
14
+ // 500; null is treated by the caller as "no pending request" (generic 422). HMAC
15
+ // verification remains the actual gate.
16
16
  async function readPendingDeletionRequestId(ctx, userId) {
17
17
  try {
18
18
  const row = await ctx.db
@@ -32,7 +32,7 @@ async function readPendingDeletionRequestId(ctx, userId) {
32
32
  // the actual grace-period transition, so a crash after the spend can no
33
33
  // longer lose the write step.
34
34
  //
35
- // Replay protection (#354/1): the row's requestId is part of the verify key.
35
+ // Replay protection: the row's requestId is part of the verify key.
36
36
  // We read it via the (unverified, lookup-only) userId from the token, reject
37
37
  // a missing entry, and verify the token against the CURRENT requestId. After
38
38
  // a cancel-deletion (status → Active, pendingDeletionRequestId → null), a
@@ -42,7 +42,7 @@ async function readPendingDeletionRequestId(ctx, userId) {
42
42
  // the same requestId and both verify the HMAC — commitDeletion spends the
43
43
  // anchor AND writes the transition atomically (expect: status===Active &&
44
44
  // pendingDeletionRequestId===requestId), so exactly one wins. The loser gets
45
- // the same generic 422 as an invalid token — no status leak (#354/2).
45
+ // the same generic 422 as an invalid token — no status leak.
46
46
  export function createConfirmDeletionByTokenHandler(opts = {}) {
47
47
  return defineWriteHandler({
48
48
  name: "confirm-deletion-by-token",
@@ -1,26 +1,26 @@
1
- // GET /api/query → user-data-rights:query:download-by-job (S2.U3 Atom 4b).
1
+ // GET /api/query → user-data-rights:query:download-by-job
2
2
  //
3
- // **UI-Klick-Pfad** (session-auth): User pollt status, sieht "done",
4
- // klickt "Download" im UI mit jobId. Server checkt session.userId ==
5
- // job.userId — kein Token noetig (Session IS the auth).
3
+ // **UI download flow** (session-auth): The user polls the status, sees
4
+ // "done", and clicks "Download" with the jobId. The server checks
5
+ // `session.userId == job.userId`; no token is needed because the session
6
+ // provides authentication.
6
7
  //
7
- // **Cross-Tenant-Same-User:** Job ist tenant-agnostisch (1 Job pro
8
- // userId ueber alle Memberships). Alice triggert Export aus Tenant A,
9
- // loggt sich spaeter in Tenant B ein, klickt Download. Server akzeptiert
10
- // — `session.userId == job.userId` reicht, kein Tenant-Match-Check.
11
- // Plan-Decision (Atom 4b Plan, User-Choice).
8
+ // **Cross-tenant same user:** Jobs are tenant-agnostic (one job per userId
9
+ // across all memberships). If Alice starts an export in Tenant A, later
10
+ // signs in to Tenant B, and clicks Download, the server accepts it:
11
+ // `session.userId == job.userId` is sufficient; no tenant-match check applies.
12
12
  //
13
- // **Cross-User-Isolation:** Wenn session.userId != job.userId → 404
14
- // (NICHT 403, kein Existenz-Leak). Selber error wie "Job-ID nicht
15
- // gefunden".
13
+ // **Cross-user isolation:** If session.userId != job.userId, return 404
14
+ // (not 403) to avoid leaking whether the job exists. Use the same error as
15
+ // for an unknown job ID.
16
16
  //
17
- // Verify-Pipeline:
18
- // 1. fetchOne job by jobId
19
- // 2. job.userId === session.userId (cross-user-isolation)
20
- // 3. job.status === "done"
21
- // 4. job.downloadStorageKey != null
22
- // 5. tokenRow lookup (audit-row update only)
23
- // 6. Audit-Update: useCount + 1, IP, UA, lastUsedAt (best-effort)
17
+ // Verification pipeline:
18
+ // 1. Fetch the job by jobId
19
+ // 2. Check job.userId === session.userId (cross-user isolation)
20
+ // 3. Check job.status === "done"
21
+ // 4. Check job.downloadStorageKey != null
22
+ // 5. Look up tokenRow (audit-row update only)
23
+ // 6. Best-effort audit update: useCount + 1, IP, UA, lastUsedAt
24
24
  // 7. Return {url, expiresAt}
25
25
  import { requestContext } from "@cosmicdrift/kumiko-framework/api";
26
26
  import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
@@ -44,7 +44,7 @@ export const downloadByJobQuery = defineQueryHandler({
44
44
  reason: "each signed-in user downloads only their own finished export job; the job " +
45
45
  "lookup checks jobRow.userId against the caller's own id and 404s otherwise",
46
46
  },
47
- }, // openToAll = auth-required, kein anonymous
47
+ }, // openToAll requires authentication; anonymous access is not allowed
48
48
  description: "Returns a short-lived signed download URL for the calling user's own finished data-export job named by job id, backing the download button in the privacy center once export-status reports the job done.",
49
49
  escapeHatch: {
50
50
  grants: ["unsafeRaw"],
@@ -56,9 +56,8 @@ export const downloadByJobQuery = defineQueryHandler({
56
56
  const userId = query.user.id;
57
57
  const jobId = query.payload.jobId;
58
58
  const tenantId = query.user.tenantId;
59
- // IP + UA aus dem request-scoped Kontext (von requestIdMiddleware
60
- // befuellt) — server-trusted, anders als ein vom Client mitgeschickter
61
- // Wert (603/2).
59
+ // IP and UA from the request-scoped context populated by
60
+ // requestIdMiddleware; these are server-trusted rather than client-supplied.
62
61
  const auditIp = requestContext.get()?.ip ?? null;
63
62
  const auditUa = requestContext.get()?.userAgent ?? null;
64
63
  const runner = ctx.db.unsafeRaw();
@@ -149,10 +148,10 @@ export const downloadByJobQuery = defineQueryHandler({
149
148
  contentDisposition: `attachment; filename="user-data-export-${jobRow.id}.zip"`,
150
149
  });
151
150
  const signedUrlExpiresAt = T.Instant.fromEpochMilliseconds(now.epochMilliseconds + SIGNED_URL_TTL_SECONDS * 1000);
152
- // Step 6: Audit-Update via tokenRow-lookup. UI-Pfad benutzt nicht
153
- // den plain-Token, aber wir wollen den useCount inkrementieren
154
- // damit die Audit-Felder konsistent sind (UI-clicks zaehlen auch
155
- // als Use). Lookup via jobId — UNIQUE-Index garantiert max 1 Row.
151
+ // Step 6: Look up tokenRow for the audit update. The UI flow has no plain
152
+ // token, but its useCount must still be incremented so audit fields remain
153
+ // consistent and UI clicks count as uses. The jobId lookup is safe because
154
+ // the UNIQUE index guarantees at most one row.
156
155
  const tokenRow = await fetchOne(runner, exportDownloadTokensTable, {
157
156
  jobId,
158
157
  });
@@ -168,9 +167,9 @@ export const downloadByJobQuery = defineQueryHandler({
168
167
  userAgent: auditUa,
169
168
  });
170
169
  }
171
- // Wenn tokenRow fehlt (sollte nicht passieren wenn Atom 4a sauber
172
- // lief): Audit-Update skipped, Download laeuft weiter. Niemand wird
173
- // hier durch Audit-Failure blockiert.
170
+ // If tokenRow is missing (which should not happen when the preceding token
171
+ // creation flow completed), skip the audit update and continue the download;
172
+ // an audit failure must not block the user.
174
173
  return {
175
174
  url: signedUrl,
176
175
  expiresAt: signedUrlExpiresAt.toString(),
@@ -1,30 +1,29 @@
1
- // GET /api/query → user-data-rights:query:download-by-token (S2.U3 Atom 4b).
1
+ // GET /api/query → user-data-rights:query:download-by-token.
2
2
  //
3
- // **Magic-Link-Pfad** (anonymous): User klickt Email-Link mit
4
- // `#token=<plain>` (URL fragment, issue #1271). Worker hat beim done-flip Token-Hash in DB
5
- // persistiert (Atom 4a). Verify-Pipeline:
3
+ // **Magic-link path** (anonymous): The user clicks an email link with
4
+ // `#token=<plain>` (URL fragment). The worker persisted the token hash in the database
5
+ // when marking the job done. Verification:
6
6
  //
7
7
  // 1. hashDownloadToken(plain) → fetchOne in download-tokens
8
- // 2. expiresAt > now (Multi-use within TTL — Plan-Decision)
8
+ // 2. expiresAt > now (multiple uses within the TTL)
9
9
  // 3. job.status === "done"
10
- // 4. job.downloadStorageKey != null (storage nicht gecleared)
11
- // 5. provider.getSignedUrl pflicht (501 wenn Provider local-fs ist)
12
- // 6. Audit-Update: useCount + 1, lastUsedAt, IP, UA (best-effort, race-tolerant)
10
+ // 4. job.downloadStorageKey != null (storage was not cleared)
11
+ // 5. provider.getSignedUrl is required (501 when the provider is local-fs)
12
+ // 6. Audit update: useCount + 1, lastUsedAt, IP, UA (best-effort, race-tolerant)
13
13
  // 7. Return {url, expiresAt}
14
14
  //
15
- // **Sicherheit:**
16
- // - Token-Hash-Compare via DB-fetchOne (nicht constant-time, aber
17
- // timing-attacks auf SHA256-bytes brauchen >>10k requests + stable
18
- // latenz — in Web-App-Kontext nicht ausnutzbar). Plan-Decision: harden
19
- // wenn Pen-Test es flaggt.
20
- // - 404 bei invalidem Token (kein Existenz-Leak) — gleicher Code-Pfad
21
- // wie nicht-gefundenes Token.
22
- // - tenant-agnostic: Token ist global eindeutig (UUID + SHA256), kein
23
- // Tenant-Filter nötig.
15
+ // **Security:**
16
+ // - Token-hash comparison via DB-fetchOne is not constant-time, but timing attacks
17
+ // against SHA256 bytes require >>10k requests plus stable latency and are not
18
+ // exploitable in a web-app context.
19
+ // - Invalid tokens return 404 without leaking existence, using the same code path
20
+ // as a token that was not found.
21
+ // - The token is tenant-agnostic: UUID + SHA256 makes it globally unique, so no
22
+ // tenant filter is needed.
24
23
  //
25
- // **r.httpRoute-Wrapper** (siehe feature.ts) macht 302-Redirect zu
26
- // signedUrl — User klickt 1× Email-Link, Browser folgt redirect, Download
27
- // startet. Dieser query-handler liefert nur das JSON.
24
+ // **r.httpRoute wrapper** (see feature.ts) redirects to signedUrl with a 302. The user
25
+ // clicks the email link once, the browser follows the redirect, and the download
26
+ // starts. This query handler returns only the JSON.
28
27
  import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
29
28
  import { defineQueryHandler, SYSTEM_USER_ID, } from "@cosmicdrift/kumiko-framework/engine";
30
29
  import { NotFoundError, UnprocessableError } from "@cosmicdrift/kumiko-framework/errors";
@@ -35,7 +34,7 @@ import { makeTenantStorageProviderResolver } from "../lib/storage-provider-resol
35
34
  import { exportDownloadTokensTable } from "../schema/download-token.js";
36
35
  import { EXPORT_JOB_STATUS, exportJobsTable } from "../schema/export-job.js";
37
36
  import { hashDownloadToken } from "../token-helpers.js";
38
- const SIGNED_URL_TTL_SECONDS = 300; // 5 min — kurz genug fuer Replay-Schutz, lang genug fuer slow connections
37
+ const SIGNED_URL_TTL_SECONDS = 300; // 5 min — short enough to limit replay, long enough for slow connections
39
38
  const DOWNLOAD_BY_TOKEN_REASON = "the download token, its job and audit rows are keyed by token hash / job id, not the caller's tenant — the anonymous magic-link path has no tenant context at all";
40
39
  export const downloadByTokenQuery = defineQueryHandler({
41
40
  name: "download-by-token",
@@ -54,12 +53,11 @@ export const downloadByTokenQuery = defineQueryHandler({
54
53
  personalData: "public-intake",
55
54
  },
56
55
  agent: { expose: false },
57
- // Brute-Force-Schutz fuer Token-Hash-Probing. Anonymous-Endpoint mit
58
- // 32-byte-Random-Token = 256 Bit Search-Space, aber rate-limit als
59
- // defense-in-depth + Schutz gegen Storm-Patterns die DB-Last erzeugen.
60
- // 30 attempts/min/IP reicht fuer legitime User (mehrere Klicks bei
61
- // Connection-Abbruch); blockiert automatisierte Probing-Loops.
62
- // Memory `feedback_security_default_on`.
56
+ // Brute-force protection for token-hash probing. This anonymous endpoint uses a
57
+ // 32-byte random token with a 256-bit search space, but rate limiting provides
58
+ // defense in depth and protects against storm patterns that generate database load.
59
+ // 30 attempts/min/IP allows legitimate users several retries after connection
60
+ // failures while blocking automated probing loops.
63
61
  rateLimit: { per: "ip+handler", limit: 30, windowSeconds: 60 },
64
62
  escapeHatch: {
65
63
  grants: ["unsafeRaw"],
@@ -75,26 +73,26 @@ export const downloadByTokenQuery = defineQueryHandler({
75
73
  tokenHash: hash,
76
74
  });
77
75
  if (!tokenRow) {
78
- // Invalid token — 404 ohne Existenz-Leak. Generic NotFoundError
79
- // damit alle Failure-Pfade die gleiche externe Shape haben (kein
80
- // Probing zwischen "Token existiert nicht" vs "Job ist failed").
76
+ // Invalid token — 404 without leaking existence. Use a generic NotFoundError
77
+ // so all failure paths have the same external shape, preventing probing that
78
+ // distinguishes "Token does not exist" from "Job has failed".
81
79
  throw new NotFoundError("export-download", undefined, {
82
80
  i18nKey: "userDataRights.errors.download.notFound",
83
81
  });
84
82
  }
85
83
  const auditIp = query.payload.auditMeta?.ip ?? null;
86
84
  const auditUa = query.payload.auditMeta?.userAgent ?? null;
87
- // Step 2: TTL-check.
85
+ // Step 2: TTL check.
88
86
  //
89
- // **Pragma:** semantisch waere 410 Gone richtig (war mal da, jetzt
90
- // nicht mehr). Framework hat keine GoneError-Class; wir nutzen
91
- // NotFoundError + i18nKey "expired" als Kompromiss. UI rendert
92
- // anhand des i18nKeys, nicht des HTTP-Status — also User sieht
93
- // "Dein Download ist abgelaufen", nicht generic "not found".
87
+ // 410 Gone would be semantically right (the download existed and is now
88
+ // gone), but the framework has no GoneError class. NotFoundError with
89
+ // i18nKey "expired" is the compromise: the UI renders by i18nKey, not by
90
+ // HTTP status, so the user sees "Your download has expired" instead of a
91
+ // generic "not found".
94
92
  if (tokenRow.expiresAt.epochMilliseconds <= now.epochMilliseconds) {
95
- // Audit-Skip noch nicht moeglich — jobRow noch nicht geladen,
96
- // tenantId unbekannt. Wir laden den Job hier noch fuer Audit-Context
97
- // (best-effort — wenn Job auch fehlt, audit-skip ist akzeptabel).
93
+ // Auditing cannot be skipped yet because jobRow has not been loaded and the
94
+ // tenantId is unknown. Load the job to obtain audit context; if it is also
95
+ // missing, skipping the audit is acceptable (best-effort).
98
96
  const jobForAudit = await fetchOne(runner, exportJobsTable, {
99
97
  id: tokenRow.jobId,
100
98
  });
@@ -193,9 +191,9 @@ export const downloadByTokenQuery = defineQueryHandler({
193
191
  contentDisposition: `attachment; filename="user-data-export-${jobRow.id}.zip"`,
194
192
  });
195
193
  const signedUrlExpiresAt = T.Instant.fromEpochMilliseconds(now.epochMilliseconds + SIGNED_URL_TTL_SECONDS * 1000);
196
- // Step 6: Audit-Update best-effort. auditMeta kommt vom httpRoute-
197
- // Wrapper (trusted-source). Direct-API-caller koennen luegen, aber
198
- // Audit ist nicht security-relevant.
194
+ // Step 6: Best-effort audit update. auditMeta comes from the httpRoute wrapper
195
+ // (trusted source). Direct API callers can falsify it, but the audit data is not
196
+ // security-sensitive.
199
197
  await recordDownloadUse({
200
198
  db: runner,
201
199
  tokenId: tokenRow.id,
@@ -1,15 +1,14 @@
1
- // GET /api/user/export-status (S2.U3 Atom 2) — User-Polling.
1
+ // GET /api/user/export-status — user polling.
2
2
  //
3
- // Liefert den meist-aktuellen ExportJob des aufrufenden Users (in
4
- // Reihenfolge: aktiver Job zuerst, sonst neuester done/failed).
3
+ // Returns the calling user's most recent ExportJob (active jobs first,
4
+ // otherwise the newest done/failed job).
5
5
  //
6
- // **Cross-User-Isolation:** Filter ist `userId === query.user.id` — kein
7
- // User kann fremde Job-Status sehen, auch nicht via ID-Guess. Pre-Check
8
- // uses ctx.db.unsafeRaw — ExportJob is tenant-agnostic (see plan doc,
9
- // "Cross-Tenant-Semantik").
6
+ // **Cross-User-Isolation:** The filter is `userId === query.user.id`, so no
7
+ // user can view another user's job status, even by guessing an ID. The
8
+ // pre-check uses ctx.db.unsafeRaw because ExportJob is tenant-agnostic.
10
9
  //
11
- // **Read-Only-Endpoint:** Pollt nur, kein State-Flip. Idempotent + cache-
12
- // fest. UI poll-Intervall typisch 2-5s waehrend running.
10
+ // **Read-Only-Endpoint:** Polling only; it does not change state. The endpoint
11
+ // is idempotent and cacheable. The UI typically polls every 2-5s while running.
13
12
  import { selectMany } from "@cosmicdrift/kumiko-framework/db";
14
13
  import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
15
14
  import * as z from "zod";
@@ -5,7 +5,7 @@ import { USER_STATUS, userTable } from "../../user/index.js";
5
5
  import { denyIfTargetOutsideAdminTenant } from "../lib/deny-if-target-outside-admin-tenant.js";
6
6
  import { updateUserLifecycle } from "../lib/update-user-lifecycle.js";
7
7
  const LIFT_RESTRICTION_ESCAPE_HATCH_REASON = "checks the target user's membership in the admin's tenant and appends the user lifecycle status change on the SYSTEM_TENANT_ID user stream, both via DbRunner helpers outside the admin's own tenant scope.";
8
- // POST /api/user/lift-restriction (S2.U6) — DSGVO Art. 18 Reverse.
8
+ // POST /api/user/lift-restriction — GDPR Art. 18 Reverse.
9
9
  //
10
10
  // Operator-only. A Restricted user's own session is unconditionally
11
11
  // rejected by sessionChecker (BLOCKED_STATUSES) the moment their status
@@ -13,16 +13,15 @@ const LIFT_RESTRICTION_ESCAPE_HATCH_REASON = "checks the target user's membershi
13
13
  // endpoint. There is no self-service path today, so lifting a restriction
14
14
  // always targets someone else's account by id.
15
15
  //
16
- // Tenant scope: `access.admin` includes TenantAdmin (tenant-scoped) even
17
- // though the User-entity is global — see user-data-rights.md "Cross-Tenant-Semantik". Without a membership check, a TenantAdmin
18
- // from tenant A could unrestrict/reactivate a user who has never been a
19
- // member of tenant A. Only SystemAdmin (platform-wide) skips the check;
20
- // the target must have a membership row in the acting admin's
21
- // `event.user.tenantId` (row existence only — no active-status field).
16
+ // Tenant scope: `access.admin` includes TenantAdmin (tenant-scoped) even though the User-entity is
17
+ // global — see user-data-rights.md "Cross-Tenant Semantics". Without a membership check, a
18
+ // TenantAdmin from tenant A could unrestrict/reactivate a user who has never been a member of
19
+ // tenant A. Only SystemAdmin (platform-wide) skips the check; the target must have a membership row
20
+ // in the acting admin's `event.user.tenantId` (row existence only — no active-status field).
22
21
  //
23
22
  // State-Transitions:
24
23
  // Restricted → Active ✓
25
- // Active → ... ✗ 422 not_restricted (Idempotenz-Guard)
24
+ // Active → ... ✗ 422 not_restricted (Idempotency Guard)
26
25
  // DeletionRequested → ... ✗ 422 not_restricted
27
26
  // Deleted → ... ✗ 422 not_restricted
28
27
  export const liftRestrictionWrite = defineWriteHandler({
@@ -4,8 +4,8 @@ import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
4
4
  import * as z from "zod";
5
5
  import { decryptStoredPii } from "../../shared/index.js";
6
6
  import { downloadAttemptsTable } from "../schema/download-attempt.js";
7
- // Operator-Query: invalid Download-Attempts (S2.U7).
8
- // DPO-Sicht fuer Brute-Force-Detection. Tenant-isolated via WHERE.
7
+ // Operator query for invalid download attempts. Provides tenant-isolated visibility for data
8
+ // protection officers investigating brute-force probing.
9
9
  const MAX_LIMIT = 100;
10
10
  const REQUEST_ID = "user-data-rights:list-download-attempts";
11
11
  export const listDownloadAttemptsQuery = defineQueryHandler({