@cosmicdrift/kumiko-bundled-features 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (669) hide show
  1. package/package.json +41 -7
  2. package/src/__tests__/access-invalidation-consumer.integration.test.ts +279 -0
  3. package/src/__tests__/access-invalidation-stream.integration.test.ts +217 -0
  4. package/src/admin-shell/__tests__/admin-shell-security.integration.test.ts +200 -0
  5. package/src/admin-shell/__tests__/admin-shell.boot.test.ts +147 -0
  6. package/src/admin-shell/__tests__/overview-allowlist.test.ts +43 -0
  7. package/src/admin-shell/__tests__/overview-screens.boot.test.ts +35 -0
  8. package/src/admin-shell/constants.ts +11 -0
  9. package/src/admin-shell/feature.ts +135 -0
  10. package/src/admin-shell/i18n.ts +36 -0
  11. package/src/admin-shell/index.ts +17 -0
  12. package/src/admin-shell/overview-allowlist.ts +37 -0
  13. package/src/admin-shell/web/client-plugin.tsx +26 -0
  14. package/src/admin-shell/web/i18n.ts +16 -0
  15. package/src/admin-shell/web/index.ts +2 -0
  16. package/src/admin-shell/web/overview-layout.tsx +69 -0
  17. package/src/admin-shell/web/overview-query.ts +15 -0
  18. package/src/admin-shell/web/platform-overview-screen.tsx +90 -0
  19. package/src/admin-shell/web/tenant-overview-screen.tsx +90 -0
  20. package/src/agent-tools/__tests__/tool-catalog.test.ts +179 -0
  21. package/src/agent-tools/__tests__/tool-dispatch.integration.test.ts +100 -0
  22. package/src/agent-tools/__tests__/tool-dispatch.test.ts +126 -0
  23. package/src/agent-tools/index.ts +9 -0
  24. package/src/agent-tools/tool-catalog.ts +130 -0
  25. package/src/agent-tools/tool-dispatch.ts +82 -0
  26. package/src/agent-tools/types.ts +38 -0
  27. package/src/audit/__tests__/audit-screens.boot.test.ts +51 -0
  28. package/src/audit/__tests__/audit-security.integration.test.ts +201 -0
  29. package/src/audit/__tests__/audit.integration.test.ts +50 -25
  30. package/src/audit/constants.ts +9 -2
  31. package/src/audit/feature.ts +33 -1
  32. package/src/audit/handlers/details.query.ts +47 -0
  33. package/src/audit/handlers/list.query.ts +3 -2
  34. package/src/audit/i18n.ts +31 -0
  35. package/src/audit/web/audit-log-detail-screen.tsx +131 -0
  36. package/src/audit/web/audit-log-screen.tsx +250 -0
  37. package/src/audit/web/client-plugin.tsx +22 -0
  38. package/src/audit/web/i18n.ts +12 -0
  39. package/src/audit/web/index.ts +5 -0
  40. package/src/auth-email-password/__tests__/account-lockout-no-redis.integration.test.ts +4 -4
  41. package/src/auth-email-password/__tests__/account-lockout.integration.test.ts +4 -4
  42. package/src/auth-email-password/__tests__/account-unlock.integration.test.ts +283 -0
  43. package/src/auth-email-password/__tests__/auth-claims.integration.test.ts +10 -11
  44. package/src/auth-email-password/__tests__/auth-user-row.test.ts +36 -0
  45. package/src/auth-email-password/__tests__/auth.integration.test.ts +33 -6
  46. package/src/auth-email-password/__tests__/email-verification.integration.test.ts +9 -6
  47. package/src/auth-email-password/__tests__/feature-options.test.ts +33 -0
  48. package/src/auth-email-password/__tests__/identity-v3-login.integration.test.ts +3 -3
  49. package/src/auth-email-password/__tests__/invite-flow-kms.integration.test.ts +283 -0
  50. package/src/auth-email-password/__tests__/invite-flow.integration.test.ts +35 -1
  51. package/src/auth-email-password/__tests__/login-mfa-setup-required.integration.test.ts +129 -0
  52. package/src/auth-email-password/__tests__/multi-roles.integration.test.ts +1 -1
  53. package/src/auth-email-password/__tests__/password-policy.test.ts +15 -0
  54. package/src/auth-email-password/__tests__/password-reset.integration.test.ts +19 -6
  55. package/src/auth-email-password/__tests__/public-routes-rate-limit.integration.test.ts +3 -3
  56. package/src/auth-email-password/__tests__/seed-admin.integration.test.ts +1 -1
  57. package/src/auth-email-password/__tests__/self-registration-toggle.integration.test.ts +264 -0
  58. package/src/auth-email-password/__tests__/session-callbacks.integration.test.ts +20 -4
  59. package/src/auth-email-password/__tests__/session-strict-mode.integration.test.ts +7 -14
  60. package/src/auth-email-password/__tests__/signup-flow.integration.test.ts +91 -0
  61. package/src/auth-email-password/constants.ts +25 -0
  62. package/src/auth-email-password/email-templates.ts +32 -0
  63. package/src/auth-email-password/errors.ts +9 -0
  64. package/src/auth-email-password/feature.ts +59 -11
  65. package/src/auth-email-password/handlers/change-password.write.ts +14 -13
  66. package/src/auth-email-password/handlers/confirm-account-unlock.write.ts +59 -0
  67. package/src/auth-email-password/handlers/confirm-token-flow.ts +34 -105
  68. package/src/auth-email-password/handlers/invite-accept-with-login.write.ts +12 -5
  69. package/src/auth-email-password/handlers/invite-accept.write.ts +9 -2
  70. package/src/auth-email-password/handlers/invite-create.write.ts +2 -2
  71. package/src/auth-email-password/handlers/invite-signup-complete.write.ts +12 -4
  72. package/src/auth-email-password/handlers/login.write.ts +86 -16
  73. package/src/auth-email-password/handlers/logout.write.ts +4 -2
  74. package/src/auth-email-password/handlers/request-account-unlock.write.ts +38 -0
  75. package/src/auth-email-password/handlers/reset-password.write.ts +3 -2
  76. package/src/auth-email-password/handlers/self-registration-status.query.ts +23 -0
  77. package/src/auth-email-password/handlers/signup-confirm.write.ts +19 -11
  78. package/src/auth-email-password/handlers/signup-request.write.ts +22 -0
  79. package/src/auth-email-password/handlers/token-request-handler.ts +4 -2
  80. package/src/auth-email-password/i18n.ts +52 -0
  81. package/src/auth-email-password/index.ts +13 -2
  82. package/src/auth-email-password/lockout-store.ts +10 -5
  83. package/src/auth-email-password/password-policy.ts +2108 -0
  84. package/src/auth-email-password/seeding.ts +55 -27
  85. package/src/auth-email-password/self-registration-toggle.ts +25 -0
  86. package/src/auth-email-password/signed-token.ts +1 -0
  87. package/src/auth-email-password/unlock-token.ts +28 -0
  88. package/src/auth-email-password/web/__tests__/auth-client.test.ts +542 -0
  89. package/src/auth-email-password/web/__tests__/auth-form-logic.test.ts +44 -0
  90. package/src/auth-email-password/web/__tests__/auth-gate.test.tsx +194 -6
  91. package/src/auth-email-password/web/__tests__/client-plugin.test.tsx +34 -0
  92. package/src/auth-email-password/web/__tests__/confirm-account-unlock-screen.test.tsx +64 -0
  93. package/src/auth-email-password/web/__tests__/forgot-password-screen.test.tsx +5 -1
  94. package/src/auth-email-password/web/__tests__/invite-accept-screen.test.tsx +129 -2
  95. package/src/auth-email-password/web/__tests__/login-screen.test.tsx +149 -5
  96. package/src/auth-email-password/web/__tests__/request-account-unlock-screen.test.tsx +137 -0
  97. package/src/auth-email-password/web/__tests__/reset-password-screen.test.tsx +5 -1
  98. package/src/auth-email-password/web/__tests__/signup-complete-screen.test.tsx +134 -0
  99. package/src/auth-email-password/web/__tests__/signup-screen.test.tsx +93 -0
  100. package/src/auth-email-password/web/__tests__/test-utils.tsx +12 -2
  101. package/src/auth-email-password/web/__tests__/use-url-token.test.tsx +29 -0
  102. package/src/auth-email-password/web/__tests__/verify-email-screen.test.tsx +5 -1
  103. package/src/auth-email-password/web/auth-client.ts +96 -18
  104. package/src/auth-email-password/web/auth-form-logic.ts +30 -0
  105. package/src/auth-email-password/web/auth-form-primitives.tsx +22 -20
  106. package/src/auth-email-password/web/auth-gate.tsx +140 -19
  107. package/src/auth-email-password/web/client-plugin.ts +24 -2
  108. package/src/auth-email-password/web/confirm-account-unlock-screen.tsx +95 -0
  109. package/src/auth-email-password/web/forgot-password-screen.tsx +6 -6
  110. package/src/auth-email-password/web/index.ts +16 -4
  111. package/src/auth-email-password/web/invite-accept-screen.tsx +5 -5
  112. package/src/auth-email-password/web/login-screen.tsx +78 -22
  113. package/src/auth-email-password/web/request-account-unlock-screen.tsx +112 -0
  114. package/src/auth-email-password/web/reset-password-screen.tsx +15 -18
  115. package/src/auth-email-password/web/session.tsx +11 -6
  116. package/src/auth-email-password/web/signup-complete-screen.tsx +13 -15
  117. package/src/auth-email-password/web/signup-screen.tsx +8 -10
  118. package/src/auth-email-password/web/use-shell-user.ts +5 -2
  119. package/src/auth-email-password/web/user-menu.tsx +3 -1
  120. package/src/auth-email-password/web/verify-email-screen.tsx +10 -14
  121. package/src/auth-foundation/__tests__/feature.test.ts +46 -0
  122. package/src/auth-foundation/__tests__/session-store.test.ts +77 -0
  123. package/src/auth-foundation/__tests__/tenant-providers.test.ts +160 -0
  124. package/src/auth-foundation/__tests__/token-verifier.test.ts +150 -0
  125. package/src/auth-foundation/boot-checks.ts +150 -0
  126. package/src/auth-foundation/feature.ts +157 -0
  127. package/src/auth-foundation/index.ts +37 -0
  128. package/src/auth-foundation/resolve-anonymous-access.ts +62 -0
  129. package/src/auth-foundation/types.ts +170 -0
  130. package/src/auth-mfa/__tests__/base32.test.ts +28 -0
  131. package/src/auth-mfa/__tests__/disable-and-regenerate.integration.test.ts +265 -0
  132. package/src/auth-mfa/__tests__/enable-confirm-preauth.integration.test.ts +321 -0
  133. package/src/auth-mfa/__tests__/enable-flow.integration.test.ts +322 -0
  134. package/src/auth-mfa/__tests__/enable-start-preauth.integration.test.ts +237 -0
  135. package/src/auth-mfa/__tests__/errors-i18n-parity.test.ts +39 -0
  136. package/src/auth-mfa/__tests__/mfa-preauth-setup-token.test.ts +113 -0
  137. package/src/auth-mfa/__tests__/no-redis.integration.test.ts +209 -0
  138. package/src/auth-mfa/__tests__/pii-subject-encryption.integration.test.ts +139 -0
  139. package/src/auth-mfa/__tests__/reencrypt-job.integration.test.ts +247 -0
  140. package/src/auth-mfa/__tests__/session-auto-revoke.integration.test.ts +169 -0
  141. package/src/auth-mfa/__tests__/totp.test.ts +131 -0
  142. package/src/auth-mfa/__tests__/verify.integration.test.ts +319 -0
  143. package/src/auth-mfa/base32.ts +51 -0
  144. package/src/auth-mfa/config.ts +26 -0
  145. package/src/auth-mfa/constants.ts +45 -0
  146. package/src/auth-mfa/db/queries.ts +45 -0
  147. package/src/auth-mfa/errors.ts +66 -0
  148. package/src/auth-mfa/feature.ts +170 -0
  149. package/src/auth-mfa/handlers/disable.write.ts +67 -0
  150. package/src/auth-mfa/handlers/enable-confirm-preauth.write.ts +200 -0
  151. package/src/auth-mfa/handlers/enable-confirm.write.ts +106 -0
  152. package/src/auth-mfa/handlers/enable-start-preauth.write.ts +87 -0
  153. package/src/auth-mfa/handlers/enable-start.write.ts +66 -0
  154. package/src/auth-mfa/handlers/reencrypt.job.ts +234 -0
  155. package/src/auth-mfa/handlers/regenerate-recovery.write.ts +77 -0
  156. package/src/auth-mfa/handlers/status.query.ts +23 -0
  157. package/src/auth-mfa/handlers/verify.write.ts +179 -0
  158. package/src/auth-mfa/i18n.ts +12 -0
  159. package/src/auth-mfa/index.ts +19 -0
  160. package/src/auth-mfa/mfa-challenge-token.ts +90 -0
  161. package/src/auth-mfa/mfa-preauth-setup-token.ts +86 -0
  162. package/src/auth-mfa/mfa-setup-token.ts +96 -0
  163. package/src/auth-mfa/mfa-status-checker.ts +84 -0
  164. package/src/auth-mfa/mfa-verify-attempts.ts +90 -0
  165. package/src/auth-mfa/otpauth-uri.ts +21 -0
  166. package/src/auth-mfa/recovery-codes.ts +54 -0
  167. package/src/auth-mfa/schema/user-mfa.ts +60 -0
  168. package/src/auth-mfa/testing.ts +5 -0
  169. package/src/auth-mfa/totp.ts +67 -0
  170. package/src/auth-mfa/verify-factor.ts +58 -0
  171. package/src/auth-mfa/web/__tests__/mfa-client.test.ts +265 -0
  172. package/src/auth-mfa/web/__tests__/mfa-enable-screen.test.tsx +182 -0
  173. package/src/auth-mfa/web/__tests__/mfa-setup-preauth-screen.test.tsx +379 -0
  174. package/src/auth-mfa/web/__tests__/mfa-verify-screen.test.tsx +104 -0
  175. package/src/auth-mfa/web/client-plugin.ts +37 -0
  176. package/src/auth-mfa/web/i18n.ts +136 -0
  177. package/src/auth-mfa/web/index.ts +27 -0
  178. package/src/auth-mfa/web/mfa-client.ts +184 -0
  179. package/src/auth-mfa/web/mfa-disable-dialog.tsx +69 -0
  180. package/src/auth-mfa/web/mfa-enable-screen.tsx +228 -0
  181. package/src/auth-mfa/web/mfa-recovery-codes-reveal.tsx +53 -0
  182. package/src/auth-mfa/web/mfa-regenerate-recovery-dialog.tsx +68 -0
  183. package/src/auth-mfa/web/mfa-setup-preauth-screen.tsx +267 -0
  184. package/src/auth-mfa/web/mfa-verify-screen.tsx +117 -0
  185. package/src/auth-mfa/web/qrcode-browser.d.ts +12 -0
  186. package/src/auth-mfa-user-data/__tests__/hooks.integration.test.ts +134 -0
  187. package/src/auth-mfa-user-data/hooks.ts +53 -0
  188. package/src/auth-mfa-user-data/index.ts +21 -0
  189. package/src/billing-foundation/__tests__/billing-foundation.integration.test.ts +206 -2
  190. package/src/billing-foundation/__tests__/subscription-provider-contract.ts +93 -0
  191. package/src/billing-foundation/entities.ts +28 -4
  192. package/src/billing-foundation/events.ts +6 -2
  193. package/src/billing-foundation/feature.ts +9 -1
  194. package/src/billing-foundation/get-subscription-for-tenant.ts +16 -5
  195. package/src/billing-foundation/handlers/create-portal-session.write.ts +17 -1
  196. package/src/billing-foundation/handlers/list-subscriptions.query.ts +15 -1
  197. package/src/billing-foundation/handlers/process-event.write.ts +39 -3
  198. package/src/billing-foundation/tenant-destroy-hook.ts +46 -0
  199. package/src/cap-counter/__tests__/cap-list.boot.test.ts +27 -0
  200. package/src/cap-counter/__tests__/cap-list.security.integration.test.ts +53 -0
  201. package/src/cap-counter/__tests__/entity-ddl.test.ts +15 -0
  202. package/src/cap-counter/__tests__/with-cap-enforcement.integration.test.ts +8 -5
  203. package/src/cap-counter/constants.ts +2 -0
  204. package/src/cap-counter/enforce-cap.ts +15 -18
  205. package/src/cap-counter/entity.ts +3 -3
  206. package/src/cap-counter/feature.ts +28 -1
  207. package/src/cap-counter/i18n.ts +12 -0
  208. package/src/cap-counter/with-cap-enforcement.ts +2 -2
  209. package/src/channel-email/__tests__/pii-guard.test.ts +56 -0
  210. package/src/channel-email/email-channel.ts +2 -1
  211. package/src/channel-email/index.ts +1 -0
  212. package/src/channel-email/pii-guard.ts +39 -0
  213. package/src/compliance-profiles/__tests__/profile-picker.boot.test.ts +28 -0
  214. package/src/compliance-profiles/__tests__/profile-picker.security.integration.test.ts +91 -0
  215. package/src/compliance-profiles/constants.ts +15 -0
  216. package/src/compliance-profiles/feature.ts +22 -1
  217. package/src/compliance-profiles/handlers/set-profile.write.ts +2 -2
  218. package/src/compliance-profiles/i18n.ts +6 -0
  219. package/src/compliance-profiles/index.ts +6 -0
  220. package/src/compliance-profiles/web/client-plugin.tsx +22 -0
  221. package/src/compliance-profiles/web/compliance-profile-screen.tsx +152 -0
  222. package/src/compliance-profiles/web/i18n.ts +25 -0
  223. package/src/compliance-profiles/web/index.ts +6 -0
  224. package/src/config/__tests__/app-overrides.test.ts +11 -0
  225. package/src/config/__tests__/backing-secrets.integration.test.ts +22 -0
  226. package/src/config/__tests__/cascade.integration.test.ts +35 -0
  227. package/src/config/__tests__/config.integration.test.ts +71 -10
  228. package/src/config/__tests__/deserialize-value.test.ts +5 -8
  229. package/src/config/__tests__/inherited-redaction.integration.test.ts +4 -3
  230. package/src/config/__tests__/pii-encrypted.integration.test.ts +179 -0
  231. package/src/config/__tests__/reencrypt-job-concurrent-write-race.integration.test.ts +234 -0
  232. package/src/config/__tests__/reencrypt-job-kek-rotation.integration.test.ts +243 -0
  233. package/src/config/__tests__/write-helpers.test.ts +23 -0
  234. package/src/config/db/queries/resolver.ts +3 -3
  235. package/src/config/feature.ts +15 -8
  236. package/src/config/handlers/cascade.query.ts +2 -1
  237. package/src/config/handlers/reencrypt.job.ts +209 -0
  238. package/src/config/handlers/set.write.ts +55 -3
  239. package/src/config/handlers/values.query.ts +2 -1
  240. package/src/config/i18n.ts +9 -0
  241. package/src/config/index.ts +5 -4
  242. package/src/config/resolver.ts +75 -61
  243. package/src/config/table.ts +1 -1
  244. package/src/config/write-helpers.ts +22 -0
  245. package/src/crypto-shredding/__tests__/forget-subject.integration.test.ts +148 -0
  246. package/src/crypto-shredding/constants.ts +5 -0
  247. package/src/crypto-shredding/feature.ts +18 -0
  248. package/src/crypto-shredding/handlers/forget-subject.write.ts +91 -0
  249. package/src/crypto-shredding/index.ts +11 -0
  250. package/src/custom-fields/__tests__/audit-integration.integration.test.ts +1 -1
  251. package/src/custom-fields/__tests__/custom-fields.integration.test.ts +92 -53
  252. package/src/custom-fields/__tests__/field-access.integration.test.ts +25 -0
  253. package/src/custom-fields/__tests__/parse-serialized-field.test.ts +11 -3
  254. package/src/custom-fields/__tests__/retention.integration.test.ts +40 -0
  255. package/src/custom-fields/__tests__/user-data-rights.integration.test.ts +26 -79
  256. package/src/custom-fields/constants.ts +1 -0
  257. package/src/custom-fields/db/queries/user-data-rights.ts +0 -20
  258. package/src/custom-fields/entity.ts +1 -1
  259. package/src/custom-fields/events.ts +4 -3
  260. package/src/custom-fields/feature.ts +8 -0
  261. package/src/custom-fields/handlers/delete-system-field.write.ts +2 -1
  262. package/src/custom-fields/handlers/delete-tenant-field.write.ts +2 -1
  263. package/src/custom-fields/handlers/set-custom-field.write.ts +3 -44
  264. package/src/custom-fields/handlers/update-tenant-field.write.ts +0 -17
  265. package/src/custom-fields/lib/field-access.ts +8 -1
  266. package/src/custom-fields/lib/parse-serialized-field.ts +12 -4
  267. package/src/custom-fields/lib/value-schema.ts +1 -1
  268. package/src/custom-fields/run-retention.ts +9 -1
  269. package/src/custom-fields/schemas.ts +9 -9
  270. package/src/custom-fields/wire-for-entity.ts +110 -78
  271. package/src/custom-fields/wire-user-data-rights.ts +5 -54
  272. package/src/data-retention/__tests__/parse-override.test.ts +14 -13
  273. package/src/data-retention/__tests__/retention-cleanup.integration.test.ts +145 -8
  274. package/src/data-retention/feature.ts +3 -3
  275. package/src/data-retention/run-retention-cleanup.ts +102 -19
  276. package/src/delivery/__tests__/delivery-pii-kms.integration.test.ts +171 -0
  277. package/src/delivery/__tests__/delivery-screens.boot.test.ts +27 -0
  278. package/src/delivery/__tests__/delivery-security.integration.test.ts +106 -0
  279. package/src/delivery/constants.ts +13 -51
  280. package/src/delivery/feature.ts +29 -5
  281. package/src/delivery/handlers/log.query.ts +28 -7
  282. package/src/delivery/i18n.ts +6 -0
  283. package/src/delivery/index.ts +6 -1
  284. package/src/delivery/public-names.ts +36 -0
  285. package/src/delivery/tables.ts +3 -3
  286. package/src/delivery/web/client-plugin.tsx +20 -0
  287. package/src/delivery/web/delivery-log-screen.tsx +103 -0
  288. package/src/delivery/web/i18n.ts +25 -0
  289. package/src/delivery/web/index.ts +3 -0
  290. package/src/document-ingest-foundation/__tests__/feature.integration.test.ts +147 -0
  291. package/src/document-ingest-foundation/__tests__/feature.test.ts +105 -0
  292. package/src/document-ingest-foundation/__tests__/pages.test.ts +37 -0
  293. package/src/document-ingest-foundation/entity.ts +43 -0
  294. package/src/document-ingest-foundation/events.ts +25 -0
  295. package/src/document-ingest-foundation/feature.ts +126 -0
  296. package/src/document-ingest-foundation/index.ts +12 -0
  297. package/src/document-ingest-foundation/pages.ts +34 -0
  298. package/src/feature-toggles/__tests__/compose-tier-resolver.test.ts +304 -0
  299. package/src/feature-toggles/__tests__/feature-toggles.integration.test.ts +7 -6
  300. package/src/feature-toggles/__tests__/toggle-admin.boot.test.ts +31 -0
  301. package/src/feature-toggles/__tests__/toggle-admin.security.integration.test.ts +69 -0
  302. package/src/feature-toggles/compose-tier-resolver.ts +134 -0
  303. package/src/feature-toggles/constants.ts +14 -0
  304. package/src/feature-toggles/feature.ts +23 -3
  305. package/src/feature-toggles/global-feature-state-table.ts +20 -1
  306. package/src/feature-toggles/handlers/list.query.ts +1 -1
  307. package/src/feature-toggles/handlers/registered.query.ts +1 -1
  308. package/src/feature-toggles/i18n.ts +6 -0
  309. package/src/feature-toggles/index.ts +8 -0
  310. package/src/feature-toggles/toggle-runtime.ts +14 -0
  311. package/src/feature-toggles/web/client-plugin.tsx +22 -0
  312. package/src/feature-toggles/web/i18n.ts +29 -0
  313. package/src/feature-toggles/web/index.ts +6 -0
  314. package/src/feature-toggles/web/toggle-admin-screen.tsx +136 -0
  315. package/src/file-foundation/__tests__/feature.test.ts +5 -5
  316. package/src/file-foundation/__tests__/file-foundation.integration.test.ts +4 -3
  317. package/src/file-foundation/feature.ts +10 -11
  318. package/src/files-provider-s3/__tests__/s3-provider.integration.test.ts +27 -2
  319. package/src/files-provider-s3/s3-provider.ts +12 -1
  320. package/src/folders/__tests__/folders.integration.test.ts +3 -0
  321. package/src/folders/web/__tests__/folder-manager.test.tsx +43 -2
  322. package/src/folders/web/__tests__/tree.test.ts +8 -0
  323. package/src/folders/web/folder-manager.tsx +2 -3
  324. package/src/folders/web/i18n.ts +0 -2
  325. package/src/folders/web/tree.ts +13 -2
  326. package/src/folders-user-data/__tests__/hooks.integration.test.ts +1 -0
  327. package/src/folders-user-data/index.ts +4 -4
  328. package/src/inbound-mail-foundation/__tests__/account-state.test.ts +30 -0
  329. package/src/inbound-mail-foundation/__tests__/connect-routes.integration.test.ts +307 -0
  330. package/src/inbound-mail-foundation/__tests__/feature.test.ts +169 -0
  331. package/src/inbound-mail-foundation/__tests__/inbound-mail-foundation.integration.test.ts +644 -0
  332. package/src/inbound-mail-foundation/__tests__/inbound-mail-provider-contract.ts +111 -0
  333. package/src/inbound-mail-foundation/__tests__/retention.integration.test.ts +237 -0
  334. package/src/inbound-mail-foundation/__tests__/watch-supervisor.integration.test.ts +433 -0
  335. package/src/inbound-mail-foundation/aggregate-id.ts +40 -0
  336. package/src/inbound-mail-foundation/connect-routes.ts +230 -0
  337. package/src/inbound-mail-foundation/constants.ts +80 -0
  338. package/src/inbound-mail-foundation/db/queries/inbound-projections.ts +38 -0
  339. package/src/inbound-mail-foundation/entities.ts +172 -0
  340. package/src/inbound-mail-foundation/events.ts +147 -0
  341. package/src/inbound-mail-foundation/feature.ts +243 -0
  342. package/src/inbound-mail-foundation/handlers/account-state.ts +23 -0
  343. package/src/inbound-mail-foundation/handlers/connect-account.write.ts +112 -0
  344. package/src/inbound-mail-foundation/handlers/disconnect-account.write.ts +69 -0
  345. package/src/inbound-mail-foundation/handlers/ingest-message.write.ts +333 -0
  346. package/src/inbound-mail-foundation/handlers/list-accounts.query.ts +44 -0
  347. package/src/inbound-mail-foundation/handlers/list-messages.query.ts +58 -0
  348. package/src/inbound-mail-foundation/handlers/scope-visibility.ts +14 -0
  349. package/src/inbound-mail-foundation/handlers/update-account.write.ts +78 -0
  350. package/src/inbound-mail-foundation/index.ts +97 -0
  351. package/src/inbound-mail-foundation/oauth-state.ts +103 -0
  352. package/src/inbound-mail-foundation/projection.ts +152 -0
  353. package/src/inbound-mail-foundation/provider-factory.ts +53 -0
  354. package/src/inbound-mail-foundation/retention-sweep.ts +168 -0
  355. package/src/inbound-mail-foundation/tenant-destroy-hook.ts +93 -0
  356. package/src/inbound-mail-foundation/types.ts +250 -0
  357. package/src/inbound-mail-foundation/watch-supervisor.ts +482 -0
  358. package/src/inbound-provider-imap/__tests__/feature.test.ts +115 -0
  359. package/src/inbound-provider-imap/__tests__/imap-foundation.integration.test.ts +302 -0
  360. package/src/inbound-provider-imap/__tests__/imap-live.integration.test.ts +206 -0
  361. package/src/inbound-provider-imap/__tests__/plugin-mocked.test.ts +358 -0
  362. package/src/inbound-provider-imap/credential-document.ts +51 -0
  363. package/src/inbound-provider-imap/feature.ts +283 -0
  364. package/src/inbound-provider-imap/imap-client.ts +158 -0
  365. package/src/inbound-provider-imap/index.ts +17 -0
  366. package/src/inbound-provider-inmemory/__tests__/feature.test.ts +52 -0
  367. package/src/inbound-provider-inmemory/feature.ts +154 -0
  368. package/src/inbound-provider-inmemory/index.ts +12 -0
  369. package/src/jobs/__tests__/entity-ddl.test.ts +15 -0
  370. package/src/jobs/__tests__/job-instant.test.ts +15 -0
  371. package/src/jobs/__tests__/job-system-user.integration.test.ts +4 -8
  372. package/src/jobs/__tests__/jobs-events.integration.test.ts +37 -1
  373. package/src/jobs/__tests__/jobs-pii-kms.integration.test.ts +120 -0
  374. package/src/jobs/__tests__/jobs-screens.boot.test.ts +36 -0
  375. package/src/jobs/__tests__/jobs-security.integration.test.ts +108 -0
  376. package/src/jobs/__tests__/reindex-entity-job.integration.test.ts +169 -0
  377. package/src/jobs/constants.ts +8 -1
  378. package/src/jobs/feature.ts +52 -8
  379. package/src/jobs/handlers/detail.query.ts +6 -0
  380. package/src/jobs/handlers/list.query.ts +8 -1
  381. package/src/jobs/handlers/projection-rebuild.job.ts +14 -4
  382. package/src/jobs/handlers/reindex-entity.job.ts +49 -0
  383. package/src/jobs/i18n.ts +37 -0
  384. package/src/jobs/job-instant.ts +9 -0
  385. package/src/jobs/job-run-table.ts +4 -4
  386. package/src/jobs/web/client-plugin.tsx +22 -0
  387. package/src/jobs/web/i18n.ts +12 -0
  388. package/src/jobs/web/index.ts +4 -0
  389. package/src/jobs/web/job-run-detail-screen.tsx +180 -0
  390. package/src/jobs/web/job-runs-screen.tsx +146 -0
  391. package/src/ledger/__tests__/ledger.integration.test.ts +8 -3
  392. package/src/ledger/handlers/confirm-schedule-period.write.ts +17 -4
  393. package/src/ledger/recurring.ts +17 -8
  394. package/src/ledger/web/index.ts +3 -2
  395. package/src/legal-pages/__tests__/legal-pages.integration.test.ts +55 -0
  396. package/src/legal-pages/feature.ts +24 -31
  397. package/src/legal-pages/index.ts +1 -0
  398. package/src/mail-foundation/__tests__/feature.test.ts +5 -6
  399. package/src/mail-foundation/__tests__/mail-foundation.integration.test.ts +4 -3
  400. package/src/mail-foundation/__tests__/mail-transport-contract.ts +58 -0
  401. package/src/mail-foundation/feature.ts +26 -24
  402. package/src/mail-transport-inmemory/__tests__/feature.test.ts +23 -0
  403. package/src/mail-transport-smtp/__tests__/feature.test.ts +65 -0
  404. package/src/managed-pages/__tests__/branding-coerce.test.ts +2 -6
  405. package/src/managed-pages/__tests__/i18n-surface.boot.test.ts +30 -0
  406. package/src/managed-pages/__tests__/managed-pages.integration.test.ts +137 -0
  407. package/src/managed-pages/feature.ts +45 -47
  408. package/src/managed-pages/handlers/branding.query.ts +5 -1
  409. package/src/managed-pages/handlers/by-tenant-published.query.ts +52 -0
  410. package/src/managed-pages/i18n.ts +66 -0
  411. package/src/managed-pages/screens/page-screens.ts +5 -1
  412. package/src/managed-pages/web/client-plugin.tsx +22 -0
  413. package/src/managed-pages/web/i18n.ts +24 -0
  414. package/src/managed-pages/web/index.ts +3 -0
  415. package/src/page-render/__tests__/layout.test.ts +63 -0
  416. package/src/page-render/__tests__/markdown.test.ts +29 -0
  417. package/src/page-render/branding.ts +4 -3
  418. package/src/page-render/index.ts +1 -1
  419. package/src/page-render/layout.ts +18 -3
  420. package/src/page-render/markdown.ts +1 -9
  421. package/src/page-render/web.ts +13 -0
  422. package/src/personal-access-tokens/__tests__/feature.test.ts +42 -0
  423. package/src/personal-access-tokens/__tests__/pat.integration.test.ts +239 -0
  424. package/src/personal-access-tokens/__tests__/scopes.test.ts +42 -0
  425. package/src/personal-access-tokens/constants.ts +33 -0
  426. package/src/personal-access-tokens/feature.ts +105 -0
  427. package/src/personal-access-tokens/handlers/available-scopes.query.ts +21 -0
  428. package/src/personal-access-tokens/handlers/create.write.ts +47 -0
  429. package/src/personal-access-tokens/handlers/list.query.ts +50 -0
  430. package/src/personal-access-tokens/handlers/revoke.write.ts +37 -0
  431. package/src/personal-access-tokens/hash.ts +17 -0
  432. package/src/personal-access-tokens/i18n.ts +5 -0
  433. package/src/personal-access-tokens/index.ts +31 -0
  434. package/src/personal-access-tokens/resolver.ts +58 -0
  435. package/src/personal-access-tokens/roles.ts +29 -0
  436. package/src/personal-access-tokens/schema/api-token.ts +63 -0
  437. package/src/personal-access-tokens/scopes.ts +43 -0
  438. package/src/personal-access-tokens/web/client-plugin.tsx +29 -0
  439. package/src/personal-access-tokens/web/i18n.ts +69 -0
  440. package/src/personal-access-tokens/web/index.ts +7 -0
  441. package/src/personal-access-tokens/web/pat-tokens-screen.tsx +265 -0
  442. package/src/readiness/__tests__/readiness.integration.test.ts +4 -3
  443. package/src/renderer-simple/__tests__/resolve-variables.test.ts +37 -0
  444. package/src/renderer-simple/resolve-variables.ts +3 -1
  445. package/src/secrets/__tests__/rotate.integration.test.ts +115 -18
  446. package/src/secrets/handlers/rotate.job.ts +77 -98
  447. package/src/secrets/secrets-context.ts +7 -38
  448. package/src/secrets/table.ts +7 -8
  449. package/src/seo/__tests__/llms-txt.test.ts +38 -0
  450. package/src/seo/__tests__/robots-txt.test.ts +18 -0
  451. package/src/seo/__tests__/schema-builders.test.ts +57 -0
  452. package/src/seo/__tests__/seo.integration.test.ts +350 -0
  453. package/src/seo/__tests__/sitemap.test.ts +38 -0
  454. package/src/seo/constants.ts +60 -0
  455. package/src/seo/feature.ts +316 -0
  456. package/src/seo/handlers/seo-config.query.ts +35 -0
  457. package/src/seo/index.ts +19 -0
  458. package/src/seo/llms-txt.ts +33 -0
  459. package/src/seo/robots-txt.ts +13 -0
  460. package/src/seo/schema-builders.ts +57 -0
  461. package/src/seo/sitemap.ts +33 -0
  462. package/src/sessions/__tests__/auto-revoke-binding.test.ts +71 -0
  463. package/src/sessions/__tests__/cleanup.integration.test.ts +2 -1
  464. package/src/sessions/__tests__/password-auto-revoke.integration.test.ts +11 -7
  465. package/src/sessions/__tests__/rebuild-survival.integration.test.ts +18 -7
  466. package/src/sessions/__tests__/session-store-registration.test.ts +21 -0
  467. package/src/sessions/__tests__/sessions-screens.boot.test.ts +55 -0
  468. package/src/sessions/__tests__/sessions.integration.test.ts +272 -20
  469. package/src/sessions/__tests__/test-helpers.ts +16 -3
  470. package/src/sessions/constants.ts +5 -0
  471. package/src/sessions/db/queries/cleanup.ts +2 -2
  472. package/src/sessions/feature.ts +175 -26
  473. package/src/sessions/handlers/detail.query.ts +36 -0
  474. package/src/sessions/handlers/list.query.ts +14 -9
  475. package/src/sessions/handlers/mine.query.ts +13 -8
  476. package/src/sessions/handlers/revoke-all-for-user.write.ts +51 -12
  477. package/src/sessions/handlers/revoke-all-others.write.ts +19 -1
  478. package/src/sessions/handlers/revoke.write.ts +13 -0
  479. package/src/sessions/i18n.ts +23 -0
  480. package/src/sessions/index.ts +9 -2
  481. package/src/sessions/schema/user-session.ts +8 -2
  482. package/src/sessions/session-callbacks.ts +99 -14
  483. package/src/sessions/session-checker-fail-open.test.ts +77 -0
  484. package/src/sessions/session-revoked-event.ts +29 -0
  485. package/src/sessions/testing.ts +14 -1
  486. package/src/shared/__tests__/chunked-entity-migration.test.ts +145 -0
  487. package/src/shared/chunked-entity-migration.ts +89 -0
  488. package/src/shared/decrypt-stored-pii.ts +26 -0
  489. package/src/shared/encrypt-for-direct-write.ts +23 -0
  490. package/src/shared/entities-of.ts +17 -0
  491. package/src/shared/grace-period.test.ts +26 -0
  492. package/src/shared/grace-period.ts +20 -0
  493. package/src/{auth-email-password/__tests__ → shared}/identity-v3-hash.test.ts +2 -2
  494. package/src/shared/index.ts +16 -0
  495. package/src/shared/map-with-concurrency.test.ts +104 -0
  496. package/src/shared/map-with-concurrency.ts +38 -0
  497. package/src/shared/password-hashing.test.ts +35 -0
  498. package/src/{auth-email-password → shared}/password-hashing.ts +11 -0
  499. package/src/shared/system-query.ts +5 -0
  500. package/src/{auth-email-password → shared}/token-burn-store.ts +1 -1
  501. package/src/subscription-mollie/__tests__/feature.test.ts +97 -0
  502. package/src/subscription-mollie/__tests__/mollie-foundation.integration.test.ts +12 -1
  503. package/src/subscription-mollie/__tests__/verify-webhook.test.ts +21 -0
  504. package/src/subscription-mollie/verify-webhook.ts +1 -0
  505. package/src/subscription-stripe/__tests__/feature.test.ts +127 -1
  506. package/src/subscription-stripe/__tests__/runtime.test.ts +14 -24
  507. package/src/subscription-stripe/__tests__/stripe-foundation.integration.test.ts +15 -5
  508. package/src/subscription-stripe/__tests__/verify-webhook.test.ts +20 -0
  509. package/src/subscription-stripe/feature.ts +2 -0
  510. package/src/subscription-stripe/verify-webhook.ts +3 -2
  511. package/src/tags/__tests__/schemas.test.ts +34 -0
  512. package/src/tags/__tests__/tags.integration.test.ts +12 -1
  513. package/src/tags/entity.ts +6 -1
  514. package/src/tags/feature.ts +2 -0
  515. package/src/tags/i18n.ts +5 -0
  516. package/src/tags/schemas.ts +9 -2
  517. package/src/tags/web/__tests__/tag-manager.test.tsx +333 -0
  518. package/src/tags/web/__tests__/tag-section.test.tsx +47 -1
  519. package/src/tags/web/tag-manager.tsx +1 -1
  520. package/src/tags/web/tag-section.tsx +6 -3
  521. package/src/template-resolver/testing.ts +2 -1
  522. package/src/tenant/__tests__/members-query-kms.integration.test.ts +98 -0
  523. package/src/tenant/__tests__/members-screens.boot.test.ts +51 -0
  524. package/src/tenant/__tests__/multi-tenant.integration.test.ts +1 -1
  525. package/src/tenant/__tests__/tenant-security.integration.test.ts +310 -0
  526. package/src/tenant/__tests__/tenant.integration.test.ts +8 -4
  527. package/src/tenant/constants.ts +5 -0
  528. package/src/tenant/feature.ts +19 -0
  529. package/src/tenant/handlers/active-tenant-ids.query.ts +8 -2
  530. package/src/tenant/handlers/cancel-invitation.write.ts +2 -2
  531. package/src/tenant/handlers/invitations.query.ts +21 -4
  532. package/src/tenant/handlers/members.query.ts +41 -6
  533. package/src/tenant/i18n.ts +28 -0
  534. package/src/tenant/index.ts +7 -2
  535. package/src/tenant/invitation-table.ts +3 -2
  536. package/src/tenant/schema/tenant.ts +27 -2
  537. package/src/tenant/screens.ts +3 -2
  538. package/src/tenant/seeding.ts +136 -3
  539. package/src/tenant/web/client-plugin.tsx +20 -0
  540. package/src/tenant/web/i18n.ts +43 -0
  541. package/src/tenant/web/index.ts +4 -0
  542. package/src/tenant/web/members-screen.tsx +270 -0
  543. package/src/tenant-lifecycle/__tests__/stages.test.ts +22 -0
  544. package/src/tenant-lifecycle/__tests__/tenant-lifecycle.integration.test.ts +471 -0
  545. package/src/tenant-lifecycle/boot-checks.ts +45 -0
  546. package/src/tenant-lifecycle/constants.ts +56 -0
  547. package/src/tenant-lifecycle/events.ts +46 -0
  548. package/src/tenant-lifecycle/feature.ts +112 -0
  549. package/src/tenant-lifecycle/handlers/cancel-destruction.write.ts +79 -0
  550. package/src/tenant-lifecycle/handlers/request-destruction.write.ts +83 -0
  551. package/src/tenant-lifecycle/index.ts +7 -0
  552. package/src/tenant-lifecycle/lib/revoke-tenant-sessions.ts +16 -0
  553. package/src/tenant-lifecycle/lifecycle-gate.ts +65 -0
  554. package/src/tenant-lifecycle/run-tenant-destroy.ts +368 -0
  555. package/src/tenant-lifecycle/stages.ts +206 -0
  556. package/src/tenant-settings/__tests__/tenant-settings.integration.test.ts +115 -0
  557. package/src/tenant-settings/config.ts +44 -0
  558. package/src/tenant-settings/constants.ts +16 -0
  559. package/src/tenant-settings/feature.ts +49 -0
  560. package/src/tenant-settings/index.ts +8 -0
  561. package/src/tenant-settings/tenant-defaults.ts +67 -0
  562. package/src/text-content/web/__tests__/editor-read-only.test.tsx +33 -6
  563. package/src/text-content/web/__tests__/group-blocks.test.ts +28 -3
  564. package/src/text-content/web/client-plugin.tsx +126 -104
  565. package/src/tier-engine/__tests__/auto-default-tier.integration.test.ts +1 -1
  566. package/src/tier-engine/__tests__/resolver.integration.test.ts +1 -1
  567. package/src/tier-engine/__tests__/tier-engine.integration.test.ts +7 -4
  568. package/src/tier-engine/__tests__/trial-config-validation.test.ts +30 -0
  569. package/src/tier-engine/feature.ts +13 -6
  570. package/src/tier-engine/i18n.ts +8 -0
  571. package/src/tier-engine/web/tier-admin-screen.tsx +26 -19
  572. package/src/user/__tests__/stream-tenant-backfill.integration.test.ts +186 -0
  573. package/src/user/__tests__/user.integration.test.ts +26 -0
  574. package/src/user/constants.ts +1 -0
  575. package/src/user/db/queries/stream-tenant-backfill.ts +112 -0
  576. package/src/user/feature.ts +3 -0
  577. package/src/user/handlers/find-for-auth.query.ts +8 -6
  578. package/src/user/i18n.ts +20 -0
  579. package/src/user/index.ts +4 -0
  580. package/src/user/schema/user.ts +6 -2
  581. package/src/user/screens.ts +3 -15
  582. package/src/user/seeding.ts +8 -0
  583. package/src/user-data-rights/COMPLIANCE.md +21 -1
  584. package/src/user-data-rights/__tests__/anonymous-deletion-kms.integration.test.ts +145 -0
  585. package/src/user-data-rights/__tests__/anonymous-deletion.integration.test.ts +3 -0
  586. package/src/user-data-rights/__tests__/audit-log.integration.test.ts +67 -0
  587. package/src/user-data-rights/__tests__/boot-checks.test.ts +170 -0
  588. package/src/user-data-rights/__tests__/cross-data-matrix.integration.test.ts +4 -1
  589. package/src/user-data-rights/__tests__/download-by-token-resolver-trust.integration.test.ts +169 -0
  590. package/src/user-data-rights/__tests__/download.integration.test.ts +101 -33
  591. package/src/user-data-rights/__tests__/email-templates.test.ts +15 -0
  592. package/src/user-data-rights/__tests__/export-encrypted-fields.integration.test.ts +154 -0
  593. package/src/user-data-rights/__tests__/export-job-idempotency.integration.test.ts +2 -0
  594. package/src/user-data-rights/__tests__/export-job-list-cross-tenant.integration.test.ts +2 -0
  595. package/src/user-data-rights/__tests__/file-binary-forget-cleanup.integration.test.ts +4 -1
  596. package/src/user-data-rights/__tests__/file-binary-forget-failure.integration.test.ts +4 -1
  597. package/src/user-data-rights/__tests__/file-retention.integration.test.ts +4 -1
  598. package/src/user-data-rights/__tests__/file-storage-unification.integration.test.ts +4 -1
  599. package/src/user-data-rights/__tests__/forget-cleanup-hook-ordering.integration.test.ts +41 -62
  600. package/src/user-data-rights/__tests__/forget-hook-registry.integration.test.ts +110 -0
  601. package/src/user-data-rights/__tests__/inspector-screens.boot.test.ts +14 -0
  602. package/src/user-data-rights/__tests__/mail-default-bridge.integration.test.ts +19 -2
  603. package/src/user-data-rights/__tests__/read-users-rebuild-survives-lifecycle.integration.test.ts +25 -14
  604. package/src/user-data-rights/__tests__/request-cancel-deletion.integration.test.ts +2 -0
  605. package/src/user-data-rights/__tests__/request-deletion-callback.integration.test.ts +4 -1
  606. package/src/user-data-rights/__tests__/request-export.integration.test.ts +2 -0
  607. package/src/user-data-rights/__tests__/restriction-flow.integration.test.ts +172 -19
  608. package/src/user-data-rights/__tests__/run-export-jobs-cron-context.integration.test.ts +2 -0
  609. package/src/user-data-rights/__tests__/run-export-jobs.integration.test.ts +257 -26
  610. package/src/user-data-rights/__tests__/run-forget-cleanup.integration.test.ts +339 -5
  611. package/src/user-data-rights/__tests__/run-user-export.integration.test.ts +77 -1
  612. package/src/user-data-rights/__tests__/tenant-model-erasure.integration.test.ts +2 -0
  613. package/src/user-data-rights/__tests__/user-data-rights.integration.test.ts +9 -1
  614. package/src/user-data-rights/boot-checks.ts +70 -0
  615. package/src/user-data-rights/db/queries/__tests__/forget-cleanup.integration.test.ts +69 -0
  616. package/src/user-data-rights/db/queries/forget-cleanup.ts +9 -2
  617. package/src/user-data-rights/email-templates.ts +6 -6
  618. package/src/user-data-rights/feature.ts +162 -43
  619. package/src/user-data-rights/handlers/cancel-deletion.write.ts +8 -11
  620. package/src/user-data-rights/handlers/deletion-grace-period.ts +4 -1
  621. package/src/user-data-rights/handlers/download-by-job.query.ts +26 -18
  622. package/src/user-data-rights/handlers/download-by-token.query.ts +23 -15
  623. package/src/user-data-rights/handlers/lift-restriction.write.ts +44 -19
  624. package/src/user-data-rights/handlers/list-download-attempts.query.ts +1 -0
  625. package/src/user-data-rights/handlers/my-audit-log.query.ts +1 -0
  626. package/src/user-data-rights/handlers/request-deletion-by-email.write.ts +3 -1
  627. package/src/user-data-rights/handlers/restrict-account.write.ts +58 -7
  628. package/src/user-data-rights/handlers/run-forget-cleanup.write.ts +2 -0
  629. package/src/user-data-rights/i18n.ts +35 -32
  630. package/src/user-data-rights/lib/is-admin-actor.ts +19 -0
  631. package/src/user-data-rights/lib/storage-provider-resolver.ts +6 -5
  632. package/src/user-data-rights/lib/update-user-lifecycle.ts +8 -24
  633. package/src/user-data-rights/run-export-jobs.ts +55 -19
  634. package/src/user-data-rights/run-forget-cleanup.ts +112 -7
  635. package/src/user-data-rights/run-user-export.ts +70 -4
  636. package/src/user-data-rights/schema/download-token.ts +5 -3
  637. package/src/user-data-rights/schema/export-job.ts +2 -0
  638. package/src/user-data-rights/screens.ts +2 -1
  639. package/src/user-data-rights/web/__tests__/privacy-center-screen.test.tsx +1 -0
  640. package/src/user-data-rights/web/__tests__/public-deletion-gate.test.tsx +7 -1
  641. package/src/user-data-rights/web/client-plugin.tsx +6 -1
  642. package/src/user-data-rights/web/i18n.ts +30 -10
  643. package/src/user-data-rights/web/privacy-center-screen.tsx +5 -3
  644. package/src/user-data-rights-defaults/__tests__/bundled-entities.userdata-hooks.integration.test.ts +455 -0
  645. package/src/user-data-rights-defaults/__tests__/feature-mounted.test.ts +24 -0
  646. package/src/user-data-rights-defaults/__tests__/user-data-rights-defaults.integration.test.ts +33 -9
  647. package/src/user-data-rights-defaults/feature.ts +78 -1
  648. package/src/user-data-rights-defaults/hooks/api-token.userdata-hook.ts +37 -0
  649. package/src/user-data-rights-defaults/hooks/config-value.userdata-hook.ts +51 -0
  650. package/src/user-data-rights-defaults/hooks/delivery-attempt.userdata-hook.ts +37 -0
  651. package/src/user-data-rights-defaults/hooks/feature-mounted.ts +10 -0
  652. package/src/user-data-rights-defaults/hooks/in-app-message.userdata-hook.ts +38 -0
  653. package/src/user-data-rights-defaults/hooks/job-run.userdata-hook.ts +35 -0
  654. package/src/user-data-rights-defaults/hooks/notification-preference.userdata-hook.ts +54 -0
  655. package/src/user-data-rights-defaults/hooks/tenant-invitation.userdata-hook.ts +112 -0
  656. package/src/user-data-rights-defaults/hooks/user-session.userdata-hook.ts +42 -0
  657. package/src/user-data-rights-defaults/index.ts +26 -0
  658. package/src/user-profile/__tests__/change-email.integration.test.ts +7 -1
  659. package/src/user-profile/__tests__/profile-screen.test.tsx +5 -0
  660. package/src/user-profile/feature.ts +4 -1
  661. package/src/user-profile/handlers/change-email.write.ts +15 -10
  662. package/src/user-profile/web/profile-screen.tsx +15 -3
  663. package/src/auth-email-password/stream-tenant.ts +0 -31
  664. package/src/feature-toggles/db/queries/toggle-state.ts +0 -25
  665. package/src/legal-pages/security-headers.ts +0 -1
  666. package/src/sessions/schema/index.ts +0 -5
  667. package/src/tenant/schema/index.ts +0 -5
  668. package/src/user/schema/index.ts +0 -5
  669. /package/src/{auth-email-password → shared}/identity-v3-hash.ts +0 -0
@@ -16,6 +16,7 @@
16
16
  // die Policy entscheidet pro Tenant.
17
17
 
18
18
  import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
19
+ import { authFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
19
20
  import { asRawClient } from "@cosmicdrift/kumiko-framework/bun-db";
20
21
  import {
21
22
  createEventStoreExecutor,
@@ -36,7 +37,7 @@ import { createComplianceProfilesFeature } from "../../compliance-profiles";
36
37
  import { createDataRetentionFeature, tenantRetentionOverrideEntity } from "../../data-retention";
37
38
  import { tenantRetentionOverrideTable } from "../../data-retention/schema/tenant-retention-override";
38
39
  import { createFilesFeature } from "../../files";
39
- import { createSessionsFeature } from "../../sessions";
40
+ import { createSessionsFeature, userSessionEntity } from "../../sessions";
40
41
  import { createUserFeature, USER_STATUS, userEntity, userTable } from "../../user";
41
42
  import { createUserDataRightsDefaultsFeature } from "../../user-data-rights-defaults";
42
43
  import { createUserDataRightsFeature } from "../feature";
@@ -68,6 +69,7 @@ beforeAll(async () => {
68
69
  createFilesFeature(),
69
70
  createDataRetentionFeature(),
70
71
  createComplianceProfilesFeature(),
72
+ authFoundationFeature,
71
73
  createSessionsFeature(),
72
74
  createUserDataRightsFeature(),
73
75
  createUserDataRightsDefaultsFeature(),
@@ -76,6 +78,7 @@ beforeAll(async () => {
76
78
  db = stack.db;
77
79
 
78
80
  await unsafeCreateEntityTable(db, userEntity);
81
+ await unsafeCreateEntityTable(db, userSessionEntity);
79
82
  await unsafeCreateEntityTable(db, tenantRetentionOverrideEntity);
80
83
  await unsafePushTables(db, { fileRefsTable });
81
84
  await asRawClient(db).unsafe(`
@@ -11,6 +11,7 @@
11
11
  // assertion below go red.
12
12
 
13
13
  import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
14
+ import { authFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
14
15
  import { asRawClient } from "@cosmicdrift/kumiko-framework/bun-db";
15
16
  import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
16
17
  import { type SessionUser, SYSTEM_USER_ID } from "@cosmicdrift/kumiko-framework/engine";
@@ -40,7 +41,7 @@ import { configValuesTable } from "../../config/table";
40
41
  import { createDataRetentionFeature, tenantRetentionOverrideEntity } from "../../data-retention";
41
42
  import { fileFoundationFeature } from "../../file-foundation";
42
43
  import { createFilesFeature } from "../../files";
43
- import { createSessionsFeature } from "../../sessions";
44
+ import { createSessionsFeature, userSessionEntity } from "../../sessions";
44
45
  import { createUserFeature, userEntity, userTable } from "../../user";
45
46
  import { createUserDataRightsDefaultsFeature } from "../../user-data-rights-defaults";
46
47
  import { createUserDataRightsFeature } from "../feature";
@@ -94,6 +95,7 @@ beforeAll(async () => {
94
95
  createTestFileProviderFeature(provider, "test"),
95
96
  createDataRetentionFeature(),
96
97
  createComplianceProfilesFeature(),
98
+ authFoundationFeature,
97
99
  createSessionsFeature(),
98
100
  createUserDataRightsFeature(),
99
101
  createUserDataRightsDefaultsFeature(),
@@ -117,6 +119,7 @@ beforeAll(async () => {
117
119
  });
118
120
 
119
121
  await unsafeCreateEntityTable(db, userEntity);
122
+ await unsafeCreateEntityTable(db, userSessionEntity);
120
123
  await unsafeCreateEntityTable(db, tenantRetentionOverrideEntity);
121
124
  await unsafePushTables(db, { fileRefsTable, configValuesTable });
122
125
  await createEventsTable(db);
@@ -1,32 +1,31 @@
1
- // DSGVO forget hook-ordering — the custom-fields anonymize strip must run
2
- // before any host hook that nulls the owner column it filters on, regardless
3
- // of feature registration order.
1
+ // DSGVO forget hook-ordering — a redaction hook with order
2
+ // EXT_USER_DATA_ORDER.REDACT_BEFORE_OWNER must run before any host hook that
3
+ // nulls the owner column it filters on, regardless of feature registration
4
+ // order. (Originally proven via the custom-fields sensitive strip; that strip
5
+ // was removed in #972, so this test pins the generic runner guarantee with a
6
+ // synthetic redact hook.)
4
7
  //
5
8
  // Two host entities are wired with the OPPOSITE EXT_USER_DATA registration
6
- // order: one registers the custom-fields strip first (the order that happened
7
- // to be safe), the other registers the owner-nulling host hook first (the
8
- // order that exposed the bug). Both run through the real `runForgetCleanup`
9
- // with strategy=anonymize. With the order-sentinel fix both strip the
10
- // sensitive jsonb key; without it the host-first entity would leave it behind
11
- // (the strip matches 0 rows after the owner column is nulled).
12
- //
13
- // This drives the full runner on purpose: the existing custom-fields
14
- // user-data-rights test invokes the strip hook in isolation
15
- // (getExtensionUsages + direct call) and is structurally blind to ordering.
9
+ // order: one registers the redact hook first (the order that happened to be
10
+ // safe), the other registers the owner-nulling host hook first (the order
11
+ // that exposed the bug). Both run through the real `runForgetCleanup` with
12
+ // strategy=anonymize. With the order-sentinel both strip the jsonb key;
13
+ // without it the host-first entity would leave it behind (the redact matches
14
+ // 0 rows after the owner column is nulled).
16
15
 
17
16
  import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
17
+ import { authFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
18
18
  import { asRawClient } from "@cosmicdrift/kumiko-framework/bun-db";
19
- import { buildEntityTable } from "@cosmicdrift/kumiko-framework/db";
20
19
  import {
21
20
  createEntity,
22
21
  createTextField,
23
22
  defineFeature,
24
23
  EXT_USER_DATA,
24
+ EXT_USER_DATA_ORDER,
25
25
  type UserDataDeleteHook,
26
26
  } from "@cosmicdrift/kumiko-framework/engine";
27
27
  import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
28
28
  import {
29
- createTestUser,
30
29
  resetEventStore,
31
30
  setupTestStack,
32
31
  type TestStack,
@@ -34,10 +33,7 @@ import {
34
33
  } from "@cosmicdrift/kumiko-framework/stack";
35
34
  import { seedRow as seedProjectionRow } from "@cosmicdrift/kumiko-framework/testing";
36
35
  import { createComplianceProfilesFeature } from "../../compliance-profiles";
37
- import { fieldDefinitionEntity } from "../../custom-fields/entity";
38
- import { createCustomFieldsFeature } from "../../custom-fields/feature";
39
36
  import { customFieldsField } from "../../custom-fields/wire-for-entity";
40
- import { wireCustomFieldsUserDataRightsFor } from "../../custom-fields/wire-user-data-rights";
41
37
  import { createDataRetentionFeature, tenantRetentionOverrideEntity } from "../../data-retention";
42
38
  import { tenantRetentionOverrideTable } from "../../data-retention/schema/tenant-retention-override";
43
39
  import { createSessionsFeature } from "../../sessions";
@@ -70,6 +66,20 @@ function makeHostDeleteHook(tableName: string): UserDataDeleteHook {
70
66
  };
71
67
  }
72
68
 
69
+ // Owner-keyed jsonb redaction with the REDACT_BEFORE_OWNER order sentinel —
70
+ // the shape the removed custom-fields strip had, kept synthetic here.
71
+ function makeRedactHook(tableName: string): UserDataDeleteHook {
72
+ return async (ctx, strategy) => {
73
+ // skip: delete strategy removes rows wholesale — redaction N/A.
74
+ if (strategy === "delete") return;
75
+ await asRawClient(ctx.db).unsafe(
76
+ `UPDATE ${tableName} SET custom_fields = custom_fields - 'ssn'
77
+ WHERE inserted_by_id = $1 AND tenant_id = $2`,
78
+ [ctx.userId, ctx.tenantId],
79
+ );
80
+ };
81
+ }
82
+
73
83
  interface HostSpec {
74
84
  readonly entityName: string;
75
85
  readonly tableName: string;
@@ -99,19 +109,16 @@ function makeEntity(tableName: string) {
99
109
 
100
110
  const cfFirstEntity = makeEntity(CF_FIRST.tableName);
101
111
  const hostFirstEntity = makeEntity(HOST_FIRST.tableName);
102
- const cfFirstTable = buildEntityTable(CF_FIRST.entityName, cfFirstEntity);
103
- const hostFirstTable = buildEntityTable(HOST_FIRST.entityName, hostFirstEntity);
104
112
 
105
- // Registration order is the whole point: cfFirst registers the strip BEFORE the
106
- // owner-nulling host hook; hostFirst registers the host hook FIRST (the order
107
- // that exposed the bug). The order-sentinel must make both correct.
113
+ // Registration order is the whole point: cfFirst registers the redact hook
114
+ // BEFORE the owner-nulling host hook; hostFirst registers the host hook FIRST
115
+ // (the order that exposed the bug). The order-sentinel must make both correct.
108
116
  const cfFirstFeature = defineFeature(CF_FIRST.featureName, (r) => {
109
117
  r.entity(CF_FIRST.entityName, cfFirstEntity);
110
- r.requires("custom-fields");
111
- wireCustomFieldsUserDataRightsFor(r, {
112
- entityName: CF_FIRST.entityName,
113
- entityTable: cfFirstTable,
114
- userIdColumn: "inserted_by_id",
118
+ r.useExtension(EXT_USER_DATA, CF_FIRST.entityName, {
119
+ export: async () => null,
120
+ delete: makeRedactHook(CF_FIRST.tableName),
121
+ order: EXT_USER_DATA_ORDER.REDACT_BEFORE_OWNER,
115
122
  });
116
123
  r.useExtension(EXT_USER_DATA, CF_FIRST.entityName, {
117
124
  export: async () => null,
@@ -121,19 +128,17 @@ const cfFirstFeature = defineFeature(CF_FIRST.featureName, (r) => {
121
128
 
122
129
  const hostFirstFeature = defineFeature(HOST_FIRST.featureName, (r) => {
123
130
  r.entity(HOST_FIRST.entityName, hostFirstEntity);
124
- r.requires("custom-fields");
125
131
  r.useExtension(EXT_USER_DATA, HOST_FIRST.entityName, {
126
132
  export: async () => null,
127
133
  delete: makeHostDeleteHook(HOST_FIRST.tableName),
128
134
  });
129
- wireCustomFieldsUserDataRightsFor(r, {
130
- entityName: HOST_FIRST.entityName,
131
- entityTable: hostFirstTable,
132
- userIdColumn: "inserted_by_id",
135
+ r.useExtension(EXT_USER_DATA, HOST_FIRST.entityName, {
136
+ export: async () => null,
137
+ delete: makeRedactHook(HOST_FIRST.tableName),
138
+ order: EXT_USER_DATA_ORDER.REDACT_BEFORE_OWNER,
133
139
  });
134
140
  });
135
141
 
136
- const admin = createTestUser({ id: 1, roles: ["TenantAdmin"], tenantId: TENANT });
137
142
  const FORGET_USER = "cccccccc-cccc-4ccc-8ccc-0000000000a1";
138
143
 
139
144
  let stack: TestStack;
@@ -144,17 +149,16 @@ beforeAll(async () => {
144
149
  stack = await setupTestStack({
145
150
  features: [
146
151
  createUserFeature(),
152
+ authFoundationFeature,
147
153
  createSessionsFeature(),
148
154
  createDataRetentionFeature(),
149
155
  createComplianceProfilesFeature(),
150
- createCustomFieldsFeature(),
151
156
  createUserDataRightsFeature(),
152
157
  cfFirstFeature,
153
158
  hostFirstFeature,
154
159
  ],
155
160
  });
156
161
  await unsafeCreateEntityTable(stack.db, userEntity);
157
- await unsafeCreateEntityTable(stack.db, fieldDefinitionEntity);
158
162
  await unsafeCreateEntityTable(stack.db, tenantRetentionOverrideEntity);
159
163
  await unsafeCreateEntityTable(stack.db, cfFirstEntity);
160
164
  await unsafeCreateEntityTable(stack.db, hostFirstEntity);
@@ -166,21 +170,6 @@ afterAll(async () => {
166
170
  await stack.cleanup();
167
171
  });
168
172
 
169
- async function defineSensitiveField(entityName: string, fieldKey: string, sensitive: boolean) {
170
- await stack.http.writeOk(
171
- "custom-fields:write:define-tenant-field",
172
- {
173
- entityName,
174
- fieldKey,
175
- serializedField: { type: "text", sensitive },
176
- required: false,
177
- searchable: false,
178
- displayOrder: 0,
179
- },
180
- admin,
181
- );
182
- }
183
-
184
173
  async function seedAnonymizeOverride(entityName: string) {
185
174
  await seedProjectionRow(stack.db, tenantRetentionOverrideTable, {
186
175
  entityName,
@@ -217,25 +206,15 @@ beforeEach(async () => {
217
206
  await resetEventStore(stack);
218
207
  await asRawClient(stack.db).unsafe(`DELETE FROM ${CF_FIRST.tableName}`);
219
208
  await asRawClient(stack.db).unsafe(`DELETE FROM ${HOST_FIRST.tableName}`);
220
- await asRawClient(stack.db).unsafe(`DELETE FROM read_custom_field_definitions`);
221
209
  await asRawClient(stack.db).unsafe(`DELETE FROM read_tenant_retention_overrides`);
222
210
  await asRawClient(stack.db).unsafe(`DELETE FROM read_tenant_memberships`);
223
211
  });
224
212
 
225
213
  describe("forget hook-ordering :: redaction runs before owner-nulling regardless of registration order", () => {
226
- test("both registration orders strip the sensitive jsonb key and null the owner column", async () => {
227
- // Field defs (sensitive ssn, non-sensitive safe) for both entities.
214
+ test("both registration orders strip the redacted jsonb key and null the owner column", async () => {
228
215
  for (const spec of [CF_FIRST, HOST_FIRST]) {
229
- await defineSensitiveField(spec.entityName, "ssn", true);
230
- await defineSensitiveField(spec.entityName, "safe", false);
231
216
  await seedAnonymizeOverride(spec.entityName);
232
217
  }
233
- // Project the field definitions. Assert the pass had no failures: a silent
234
- // projection failure would leave read_custom_field_definitions empty, make
235
- // loadSensitiveFieldKeys return [], and turn the strip into a no-op —
236
- // verifying the test exercises the strip for the right reason.
237
- const pass = await stack.eventDispatcher?.runOnce();
238
- expect(pass?.failed ?? 0).toBe(0);
239
218
 
240
219
  const cfRowId = "dddddddd-dddd-4ddd-8ddd-000000000001";
241
220
  const hostRowId = "dddddddd-dddd-4ddd-8ddd-000000000002";
@@ -0,0 +1,110 @@
1
+ // A forget delete-hook receives the app registry so it can cascade custom child
2
+ // projections for the executor's `<entity>.forgotten` event (runProjectionsForEvent).
3
+ // executor.forget purges only the entity's OWN projection, and the forget pipeline
4
+ // is a job — not a dispatched command — so the dispatcher's post-command projection
5
+ // pass never fires. Without registry in the hook ctx the cascade is unreachable and
6
+ // child read-model rows (m:n joins, per-parent detail projections) are orphaned on
7
+ // live forget (a DSGVO gap). This pins that the plumbing delivers the real,
8
+ // functional registry instance; the end-to-end cascade is covered consumer-side.
9
+
10
+ import { afterAll, beforeAll, beforeEach, expect, test } from "bun:test";
11
+ import { authFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
12
+ import { asRawClient } from "@cosmicdrift/kumiko-framework/bun-db";
13
+ import {
14
+ createEntity,
15
+ createTextField,
16
+ defineFeature,
17
+ EXT_USER_DATA,
18
+ type Registry,
19
+ type UserDataDeleteHook,
20
+ } from "@cosmicdrift/kumiko-framework/engine";
21
+ import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
22
+ import {
23
+ setupTestStack,
24
+ type TestStack,
25
+ unsafeCreateEntityTable,
26
+ } from "@cosmicdrift/kumiko-framework/stack";
27
+ import { createComplianceProfilesFeature } from "../../compliance-profiles";
28
+ import { createDataRetentionFeature, tenantRetentionOverrideEntity } from "../../data-retention";
29
+ import { createSessionsFeature } from "../../sessions";
30
+ import { createUserFeature, userEntity } from "../../user";
31
+ import { createUserDataRightsFeature } from "../feature";
32
+ import { runForgetCleanup } from "../run-forget-cleanup";
33
+ import {
34
+ createForgetSeeders,
35
+ nowInstant,
36
+ READ_TENANT_MEMBERSHIPS_DDL,
37
+ TENANT_SYSTEM,
38
+ } from "./forget-test-helpers";
39
+
40
+ const PROBE = "forget-registry-probe";
41
+ let capturedRegistry: Registry | undefined;
42
+
43
+ const captureHook: UserDataDeleteHook = async (ctx) => {
44
+ capturedRegistry = ctx.registry;
45
+ };
46
+
47
+ const probeEntity = createEntity({
48
+ table: `read_${PROBE.replace(/-/g, "_")}`,
49
+ fields: { name: createTextField({ required: true }) },
50
+ });
51
+
52
+ const probeFeature = defineFeature(PROBE, (r) => {
53
+ r.entity(PROBE, probeEntity);
54
+ r.useExtension(EXT_USER_DATA, PROBE, {
55
+ export: async () => null,
56
+ delete: captureHook,
57
+ });
58
+ });
59
+
60
+ const FORGET_USER = "cccccccc-cccc-4ccc-8ccc-0000000000b1";
61
+ let stack: TestStack;
62
+ const seed = (db: unknown) =>
63
+ // biome-ignore lint/suspicious/noExplicitAny: dummy writer; this seeder never writes binaries.
64
+ createForgetSeeders(db as any, { write: async () => {} });
65
+
66
+ beforeAll(async () => {
67
+ stack = await setupTestStack({
68
+ features: [
69
+ createUserFeature(),
70
+ authFoundationFeature,
71
+ createSessionsFeature(),
72
+ createDataRetentionFeature(),
73
+ createComplianceProfilesFeature(),
74
+ createUserDataRightsFeature(),
75
+ probeFeature,
76
+ ],
77
+ });
78
+ await unsafeCreateEntityTable(stack.db, userEntity);
79
+ await unsafeCreateEntityTable(stack.db, tenantRetentionOverrideEntity);
80
+ await unsafeCreateEntityTable(stack.db, probeEntity);
81
+ await createEventsTable(stack.db);
82
+ await asRawClient(stack.db).unsafe(READ_TENANT_MEMBERSHIPS_DDL);
83
+ });
84
+
85
+ afterAll(async () => {
86
+ await stack.cleanup();
87
+ });
88
+
89
+ beforeEach(() => {
90
+ capturedRegistry = undefined;
91
+ });
92
+
93
+ test("forget delete-hook receives the app registry instance", async () => {
94
+ await seed(stack.db).seedForgetUser(FORGET_USER);
95
+ await seed(stack.db).seedMembership(FORGET_USER, TENANT_SYSTEM);
96
+
97
+ const result = await runForgetCleanup({
98
+ db: stack.db,
99
+ registry: stack.registry,
100
+ now: nowInstant(),
101
+ });
102
+
103
+ expect(result.errors, JSON.stringify(result.errors)).toHaveLength(0);
104
+ expect(result.processedUserIds).toContain(FORGET_USER);
105
+ // The hook ran and got the exact registry passed to runForgetCleanup — not
106
+ // undefined, not a stand-in — so runProjectionsForEvent(event, ctx.registry, db)
107
+ // reaches the real projections.
108
+ expect(capturedRegistry).toBe(stack.registry);
109
+ expect(capturedRegistry?.getProjectionsForSource(PROBE)).toBeDefined();
110
+ });
@@ -1,10 +1,15 @@
1
1
  import { describe, expect, test } from "bun:test";
2
2
  import { access, validateBoot } from "@cosmicdrift/kumiko-framework/engine";
3
+ import { createFilesFeature } from "@cosmicdrift/kumiko-framework/files";
4
+ import { authFoundationFeature } from "../../auth-foundation";
3
5
  import { createComplianceProfilesFeature } from "../../compliance-profiles/feature";
4
6
  import { createConfigFeature } from "../../config/feature";
5
7
  import { createDataRetentionFeature } from "../../data-retention/feature";
8
+ import { createPersonalAccessTokensFeature } from "../../personal-access-tokens";
6
9
  import { createSessionsFeature } from "../../sessions/feature";
10
+ import { createTenantFeature } from "../../tenant/feature";
7
11
  import { createUserFeature } from "../../user/feature";
12
+ import { createUserDataRightsDefaultsFeature } from "../../user-data-rights-defaults/feature";
8
13
  import { createUserDataRightsFeature } from "../feature";
9
14
 
10
15
  // Read-only GDPR inspector screens live IN user-data-rights (the boot-validator
@@ -16,13 +21,22 @@ import { createUserDataRightsFeature } from "../feature";
16
21
  // so an entityList binding is rebuild-safe (unlike jobs/sessions read-models).
17
22
 
18
23
  describe("user-data-rights read-only inspector screens", () => {
24
+ // A realistic assembly: mounting user-data-rights without its default hooks
25
+ // now fails the V3 boot gate (the framework `user` entity holds PII with no
26
+ // erase path). Real apps mount the defaults (which hard-require `files`)
27
+ // alongside — so this set mirrors that.
19
28
  const features = [
20
29
  createConfigFeature(),
21
30
  createUserFeature(),
31
+ createTenantFeature(),
32
+ authFoundationFeature,
33
+ createPersonalAccessTokensFeature({ scopes: {} }),
22
34
  createSessionsFeature(),
23
35
  createDataRetentionFeature(),
24
36
  createComplianceProfilesFeature(),
37
+ createFilesFeature(),
25
38
  createUserDataRightsFeature(),
39
+ createUserDataRightsDefaultsFeature(),
26
40
  ];
27
41
 
28
42
  test("the assembled feature set boot-validates", () => {
@@ -10,6 +10,7 @@
10
10
  // #624: "App mountet mail-foundation+transport → GDPR-Mails ohne Callback-Code".
11
11
 
12
12
  import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
13
+ import { authFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
13
14
  import { asRawClient } from "@cosmicdrift/kumiko-framework/bun-db";
14
15
  import { fileRefsTable } from "@cosmicdrift/kumiko-framework/files";
15
16
  import {
@@ -26,7 +27,7 @@ import { createDataRetentionFeature, tenantRetentionOverrideEntity } from "../..
26
27
  import { createFilesFeature } from "../../files";
27
28
  import { mailFoundationFeature } from "../../mail-foundation";
28
29
  import { clearInbox, getInbox, mailTransportInMemoryFeature } from "../../mail-transport-inmemory";
29
- import { createSessionsFeature } from "../../sessions";
30
+ import { createSessionsFeature, userSessionEntity } from "../../sessions";
30
31
  import { createUserFeature, USER_STATUS, userEntity, userTable } from "../../user";
31
32
  import { createUserDataRightsDefaultsFeature } from "../../user-data-rights-defaults";
32
33
  import { createUserDataRightsFeature } from "../feature";
@@ -56,6 +57,7 @@ beforeAll(async () => {
56
57
  createFilesFeature(),
57
58
  createDataRetentionFeature(),
58
59
  createComplianceProfilesFeature(),
60
+ authFoundationFeature,
59
61
  createSessionsFeature(),
60
62
  mailFoundationFeature,
61
63
  mailTransportInMemoryFeature,
@@ -67,6 +69,7 @@ beforeAll(async () => {
67
69
 
68
70
  await unsafePushTables(stack.db, { configValuesTable });
69
71
  await unsafeCreateEntityTable(stack.db, userEntity);
72
+ await unsafeCreateEntityTable(stack.db, userSessionEntity);
70
73
  await unsafeCreateEntityTable(stack.db, tenantRetentionOverrideEntity);
71
74
  await asRawClient(stack.db).unsafe(`
72
75
  CREATE TABLE IF NOT EXISTS read_tenant_memberships (
@@ -120,7 +123,21 @@ describe("C6 default mail bridge :: forget cron sends deletion-executed without
120
123
  expect(job).toBeDefined();
121
124
 
122
125
  // EXAKT der prod-Job-Kontext: configResolver gesetzt, config undefined.
123
- const jobCtx = { db: stack.db, registry: stack.registry, configResolver };
126
+ // log required since #1572 persists incomplete[] via ctx.log.warn.
127
+ const jobCtx = {
128
+ db: stack.db,
129
+ registry: stack.registry,
130
+ configResolver,
131
+ log: {
132
+ info() {},
133
+ warn() {},
134
+ error() {},
135
+ debug() {},
136
+ child() {
137
+ return this;
138
+ },
139
+ },
140
+ };
124
141
  await job?.handler({}, jobCtx as never);
125
142
 
126
143
  // Loeschung lief autonom durch.
@@ -13,8 +13,8 @@
13
13
 
14
14
  import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
15
15
  import { randomBytes } from "node:crypto";
16
+ import { authFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
16
17
  import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
17
- import { createEncryptionProvider } from "@cosmicdrift/kumiko-framework/db";
18
18
  import {
19
19
  createRegistry,
20
20
  type Registry,
@@ -40,13 +40,13 @@ import {
40
40
  } from "@cosmicdrift/kumiko-framework/stack";
41
41
  import {
42
42
  createLateBoundHolder,
43
+ createTestEnvelopeCipher,
43
44
  resetTestTables,
44
45
  updateRows,
45
46
  } from "@cosmicdrift/kumiko-framework/testing";
46
47
  import { getTemporal } from "@cosmicdrift/kumiko-framework/time";
47
48
  import { AuthHandlers } from "../../auth-email-password/constants";
48
49
  import { createAuthEmailPasswordFeature } from "../../auth-email-password/feature";
49
- import { hashPassword } from "../../auth-email-password/password-hashing";
50
50
  import {
51
51
  createComplianceProfilesFeature,
52
52
  tenantComplianceProfileEntity,
@@ -59,7 +59,8 @@ import { createDataRetentionFeature } from "../../data-retention";
59
59
  import { createSessionsFeature } from "../../sessions";
60
60
  import { userSessionEntity, userSessionTable } from "../../sessions/schema/user-session";
61
61
  import { createSessionCallbacks, type SessionCallbacks } from "../../sessions/session-callbacks";
62
- import { sessionCallbacksFromLateBound } from "../../sessions/testing";
62
+ import { sessionCallbacksFromLateBound, withMintedSession } from "../../sessions/testing";
63
+ import { hashPassword } from "../../shared";
63
64
  import { createTenantFeature, tenantMembershipsTable } from "../../tenant";
64
65
  import { tenantEntity } from "../../tenant/schema/tenant";
65
66
  import { seedTenantMembership } from "../../tenant/seeding";
@@ -91,14 +92,15 @@ function buildFeatures() {
91
92
  createDataRetentionFeature(),
92
93
  createComplianceProfilesFeature(),
93
94
  createAuthEmailPasswordFeature(),
95
+ authFoundationFeature,
94
96
  createSessionsFeature(),
95
97
  createUserDataRightsFeature(),
96
98
  ];
97
99
  }
98
100
 
99
101
  beforeAll(async () => {
100
- const encryption = createEncryptionProvider(encryptionKey);
101
- const resolver = createConfigResolver({ encryption });
102
+ const encryption = createTestEnvelopeCipher(encryptionKey);
103
+ const resolver = createConfigResolver({ cipher: encryption });
102
104
  const bound = sessionCallbacksFromLateBound(callbacks);
103
105
 
104
106
  stack = await setupTestStack({
@@ -137,6 +139,12 @@ beforeEach(async () => {
137
139
  ]);
138
140
  });
139
141
 
142
+ // Any actor hitting a write handler needs a live sid once sessionChecker
143
+ // is wired.
144
+ function mintActor(user: { id: string; tenantId: TenantId; roles: readonly string[] }) {
145
+ return withMintedSession((u, meta) => callbacks.get().sessionCreator(u, meta), user);
146
+ }
147
+
140
148
  describe("#494 :: read_users-Rebuild bewahrt Lifecycle-State", () => {
141
149
  test("Restricted-Status ueberlebt einen Projection-Rebuild (T_create != T_active)", async () => {
142
150
  // Diskriminierende Praemisse: user.created landet auf systemAdmin.tenantId
@@ -149,7 +157,7 @@ describe("#494 :: read_users-Rebuild bewahrt Lifecycle-State", () => {
149
157
  const created = await stack.http.writeOk<{ id: string }>(
150
158
  UserHandlers.create,
151
159
  { email: ALICE_EMAIL, passwordHash: hash, displayName: "Alice" },
152
- TestUsers.systemAdmin,
160
+ await mintActor(TestUsers.systemAdmin),
153
161
  );
154
162
  // Mitgliedschaft + Lifecycle auf einem ANDEREN, aktiven Tenant.
155
163
  await seedTenantMembership(stack.db, {
@@ -158,7 +166,7 @@ describe("#494 :: read_users-Rebuild bewahrt Lifecycle-State", () => {
158
166
  roles: ["Member"],
159
167
  });
160
168
 
161
- const aliceActive = { id: created.id, tenantId: T_ACTIVE, roles: ["Member"] };
169
+ const aliceActive = await mintActor({ id: created.id, tenantId: T_ACTIVE, roles: ["Member"] });
162
170
  const restricted = await stack.http.writeOk<{ status: string }>(RESTRICT, {}, aliceActive);
163
171
  expect(restricted.status).toBe(USER_STATUS.Restricted);
164
172
 
@@ -187,7 +195,7 @@ describe("#494 :: read_users-Rebuild bewahrt Lifecycle-State", () => {
187
195
  const created = await stack.http.writeOk<{ id: string }>(
188
196
  UserHandlers.create,
189
197
  { email: "grace.rebuild@example.com", passwordHash: hash, displayName: "Grace" },
190
- TestUsers.systemAdmin,
198
+ await mintActor(TestUsers.systemAdmin),
191
199
  );
192
200
 
193
201
  const T = getTemporal();
@@ -218,7 +226,7 @@ describe("#494 :: read_users-Rebuild bewahrt Lifecycle-State", () => {
218
226
  const created = await stack.http.writeOk<{ id: string }>(
219
227
  UserHandlers.create,
220
228
  { email: "legacy.rebuild@example.com", passwordHash: hash, displayName: "Legacy" },
221
- TestUsers.systemAdmin,
229
+ await mintActor(TestUsers.systemAdmin),
222
230
  );
223
231
 
224
232
  // Prae-Fix-Zustand simulieren: roher Write OHNE Event.
@@ -256,14 +264,14 @@ describe("#494 :: read_users-Rebuild bewahrt Lifecycle-State", () => {
256
264
  const goodRow = await stack.http.writeOk<{ id: string }>(
257
265
  UserHandlers.create,
258
266
  { email: "healthy.rebuild@example.com", passwordHash: hash, displayName: "Healthy" },
259
- TestUsers.systemAdmin,
267
+ await mintActor(TestUsers.systemAdmin),
260
268
  );
261
269
  await updateRows(stack.db, userTable, { status: USER_STATUS.Restricted }, { id: goodRow.id });
262
270
 
263
271
  const badRow = await stack.http.writeOk<{ id: string }>(
264
272
  UserHandlers.create,
265
273
  { email: "corrupt.rebuild@example.com", passwordHash: hash, displayName: "Corrupt" },
266
- TestUsers.systemAdmin,
274
+ await mintActor(TestUsers.systemAdmin),
267
275
  );
268
276
  await updateRows(stack.db, userTable, { status: USER_STATUS.Restricted }, { id: badRow.id });
269
277
  // userEntity is systemStream:true (schema/user.ts) — its event stream
@@ -283,8 +291,11 @@ describe("#494 :: read_users-Rebuild bewahrt Lifecycle-State", () => {
283
291
  expect(backfilled).toBeGreaterThanOrEqual(1);
284
292
 
285
293
  // Proof the loop didn't abort at the corrupt row: rebuild the projection —
286
- // goodRow got its user.updated event (survives), badRow never did (wiped
287
- // back to Active, exactly the data-loss this backfill exists to prevent).
294
+ // goodRow got its user.updated event (survives). badRow's Stream ist
295
+ // archiviert und replayt seit fw#832 gar nicht mehr: die Row ist nach dem
296
+ // Rebuild WEG (nicht bloss auf Active zurueckgewischt). Genau deshalb ist
297
+ // der failed-Report oben der Operator-Alarm — Heilung: restoreStream +
298
+ // Backfill-Re-Run, DANN rebuild.
288
299
  await rebuildProjection(USER_PROJECTION, { db: stack.db, registry });
289
300
  const rows = (await selectMany(stack.db, userTable, {})) as Array<{
290
301
  id: string;
@@ -293,6 +304,6 @@ describe("#494 :: read_users-Rebuild bewahrt Lifecycle-State", () => {
293
304
  const good = rows.find((r) => r.id === goodRow.id);
294
305
  const bad = rows.find((r) => r.id === badRow.id);
295
306
  expect(good?.status).toBe(USER_STATUS.Restricted);
296
- expect(bad?.status).toBe(USER_STATUS.Active);
307
+ expect(bad).toBeUndefined();
297
308
  });
298
309
  });
@@ -10,6 +10,7 @@
10
10
  // hier; der Frist-Ablauf-Cleanup folgt mit S2.U5b.
11
11
 
12
12
  import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
13
+ import { authFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
13
14
  import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
14
15
  import { createEventsTable, eventsTable } from "@cosmicdrift/kumiko-framework/event-store";
15
16
  import {
@@ -57,6 +58,7 @@ const features = [
57
58
  createUserFeature(),
58
59
  createDataRetentionFeature(),
59
60
  createComplianceProfilesFeature(),
61
+ authFoundationFeature,
60
62
  createSessionsFeature(),
61
63
 
62
64
  createUserDataRightsFeature(),
@@ -8,6 +8,7 @@
8
8
  // Properties — dieser Test verifiziert sie end-to-end.
9
9
 
10
10
  import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
11
+ import { authFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
11
12
  import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
12
13
  import { createEventsTable, eventsTable } from "@cosmicdrift/kumiko-framework/event-store";
13
14
  import {
@@ -24,7 +25,7 @@ import {
24
25
  tenantComplianceProfileTable,
25
26
  } from "../../compliance-profiles";
26
27
  import { createDataRetentionFeature } from "../../data-retention";
27
- import { createSessionsFeature } from "../../sessions";
28
+ import { createSessionsFeature, userSessionEntity } from "../../sessions";
28
29
  import { USER_STATUS, userEntity, userTable } from "../../user";
29
30
  import { createUserFeature } from "../../user/feature";
30
31
  import { createUserDataRightsFeature } from "../feature";
@@ -64,12 +65,14 @@ beforeAll(async () => {
64
65
  createUserFeature(),
65
66
  createDataRetentionFeature(),
66
67
  createComplianceProfilesFeature(),
68
+ authFoundationFeature,
67
69
  createSessionsFeature(),
68
70
 
69
71
  createUserDataRightsFeature({ sendDeletionRequestedEmail }),
70
72
  ],
71
73
  });
72
74
  await unsafeCreateEntityTable(stack.db, userEntity);
75
+ await unsafeCreateEntityTable(stack.db, userSessionEntity);
73
76
  await unsafeCreateEntityTable(stack.db, tenantComplianceProfileEntity);
74
77
  await createEventsTable(stack.db);
75
78
  });