@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,6 +1,7 @@
1
1
  import * as z from "zod";
2
2
  import { HEX_COLOR_PATTERN, PDF_ORIENTATIONS, PDF_PAGE_FORMATS, } from "./web/constants.js";
3
3
  import { MAIL_TONES } from "./web/mail-constants.js";
4
+ import { MAIL_LAYOUT_ACCENT_LINES, MAIL_LAYOUT_BUTTON_STYLES, MAIL_LAYOUT_FONTS, MAIL_LAYOUT_WIDTHS, } from "./web/mail-layout-constants.js";
4
5
  // One or more kebab segments joined by ":" — notification templates are seeded
5
6
  // under their qualified name `feature:notify:name`.
6
7
  export const templateSlugSchema = z
@@ -66,12 +67,14 @@ const pdfMetaSchema = z
66
67
  .optional(),
67
68
  })
68
69
  .strict();
69
- const MAIL_LAYOUT_FONTS = ["sans", "serif"];
70
- const MAIL_LAYOUT_ACCENT_LINES = ["branding", "none"];
71
- const MAIL_LAYOUT_BUTTON_STYLES = ["filled-rounded", "filled-square", "outline"];
70
+ const MAIL_LAYOUT_WIDTH_LITERALS = [
71
+ z.literal(MAIL_LAYOUT_WIDTHS[0]),
72
+ z.literal(MAIL_LAYOUT_WIDTHS[1]),
73
+ z.literal(MAIL_LAYOUT_WIDTHS[2]),
74
+ ];
72
75
  const mailLayoutMetaSchema = z
73
76
  .object({
74
- width: z.union([z.literal(560), z.literal(600), z.literal(640)]).optional(),
77
+ width: z.union(MAIL_LAYOUT_WIDTH_LITERALS).optional(),
75
78
  font: z.enum(MAIL_LAYOUT_FONTS).optional(),
76
79
  outerBackground: z.string().regex(HEX_COLOR_PATTERN, "must be a #rrggbb color").optional(),
77
80
  accentLine: z.enum(MAIL_LAYOUT_ACCENT_LINES).optional(),
@@ -8,7 +8,7 @@ import * as z from "zod";
8
8
  import { createEmailAttachmentReader, createTemplateMailRenderer } from "../delivery/index.js";
9
9
  import { fileContextForTenant } from "../file-foundation/index.js";
10
10
  import { collectRendererPlugins, createRendererFoundationApi, RendererError, } from "../renderer-foundation/index.js";
11
- import { createTemplateResolverApi, TemplateNotFoundError } from "./api.js";
11
+ import { createTemplateResolverApi, isRowDeliveredTo, TemplateNotFoundError, } from "./api.js";
12
12
  import { collectDocumentResourceKeys } from "./compile-document-body.js";
13
13
  import { parseStoredJson } from "./handlers/template-gates.js";
14
14
  import { validateTemplateDraft } from "./handlers/validate.query.js";
@@ -16,7 +16,7 @@ import { readLayoutRegions, sanitizeLayoutHtml, } from "./layout-regions.js";
16
16
  import { parseLinkedResourceEntries } from "./linked-resources.js";
17
17
  import { buildDisplayHtml } from "./preview-display-html.js";
18
18
  import { templateResourcesTable } from "./table.js";
19
- import { deliveryPolicyOf, isRowServedTo } from "./template-delivery-policy.js";
19
+ import { deliveryPolicyOf } from "./template-delivery-policy.js";
20
20
  import { isMailTemplateMeta, parseTemplateMeta, readPdfTemplateMeta, } from "./template-meta.js";
21
21
  import { DEFAULT_MAIL_LAYOUT_SLUG, DEFAULT_PDF_LAYOUT_SLUG, MAIL_PREVIEW_MAX_BYTES, SYSTEM_TENANT_ID, } from "./web/constants.js";
22
22
  import { TemplateResolverErrors } from "./web/qualified-names.js";
@@ -149,7 +149,8 @@ export function estimateMailBytes(args) {
149
149
  async function loadEditedRowResources(ctx, user, input) {
150
150
  const rows = await selectMany(ctx.db, templateResourcesTable, { tenantId: user.tenantId, slug: input.slug, kind: "mail", locale: input.locale }, { limit: 1 });
151
151
  const row = rows[0];
152
- if (row !== undefined && !isRowServedTo(deliveryPolicyOf(ctx.registry), user, row)) {
152
+ if (row !== undefined &&
153
+ !(await isRowDeliveredTo(ctx.db, deliveryPolicyOf(ctx.registry), user, row))) {
153
154
  return undefined;
154
155
  }
155
156
  return row === undefined ? undefined : parseLinkedResourceEntries(row.linkedResources);
@@ -107,7 +107,7 @@ function makeTreeProvider(tenantIdOverride, collectionId) {
107
107
  const csrf = readCsrfToken();
108
108
  if (csrf !== undefined)
109
109
  headers[CSRF_HEADER_NAME] = csrf;
110
- // kumiko-lint-ignore no-raw-hooks Phase-3 conversion tracked in #2312
110
+ // kumiko-lint-ignore no-raw-hooks not yet converted to the framework hook set
111
111
  fetch("/api/query", {
112
112
  method: "POST",
113
113
  headers,
@@ -224,7 +224,7 @@ function TextBlockEditor({ target, }) {
224
224
  const [savedMsg, setSavedMsg] = useState(null);
225
225
  // Sync loaded data into the form state. loaded === null means the block does
226
226
  // not exist yet — empty form for the create flow.
227
- // kumiko-lint-ignore no-raw-hooks Phase-3 conversion tracked in #2312
227
+ // kumiko-lint-ignore no-raw-hooks not yet converted to the framework hook set
228
228
  useEffect(() => {
229
229
  if (loading)
230
230
  return;
@@ -10,7 +10,7 @@ export declare const UPSERT_KINDS: readonly ["mail", "document-pdf", "image-snap
10
10
  export type UpsertKind = (typeof UPSERT_KINDS)[number];
11
11
  export declare const TEXT_BLOCK_KIND: "text-block";
12
12
  export declare const COLLECTION_REFUSED_KINDS: readonly ["mail", "mail-layout", "pdf-layout"];
13
- export declare function isCollectionRefusedKind(kind: string): boolean;
13
+ export declare function isCollectionRefusedKind(kind: unknown): kind is (typeof COLLECTION_REFUSED_KINDS)[number];
14
14
  export declare const CONTENT_FORMATS: readonly ["markdown", "mjml", "html", "plain"];
15
15
  export type ContentFormat = (typeof CONTENT_FORMATS)[number];
16
16
  export declare const TEMPLATE_SCOPES: readonly ["system", "tenant"];
@@ -18,8 +18,8 @@ export type TemplateScope = (typeof TEMPLATE_SCOPES)[number];
18
18
  export declare const TEMPLATE_STATUSES: readonly ["draft", "active", "archived"];
19
19
  export type TemplateStatus = (typeof TEMPLATE_STATUSES)[number];
20
20
  export declare const ACTIVE_TEMPLATE_STATUS = "active";
21
+ export { HEX_COLOR_PATTERN } from "./mail-layout-constants.ts";
21
22
  export { PDF_DEFAULT_MARGIN_MM, PDF_FOOTER_MARGIN_MM, PDF_HEADER_MARGIN_MM, PDF_ORIENTATIONS, PDF_PAGE_FORMATS, type PdfOrientation, type PdfPageFormat, } from "./pdf-constants.ts";
22
- export declare const HEX_COLOR_PATTERN: RegExp;
23
23
  export declare const DEFAULT_MAIL_LAYOUT_SLUG = "default";
24
24
  export declare const DEFAULT_PDF_LAYOUT_SLUG = "default";
25
25
  export declare const MAIL_PREVIEW_MAX_BYTES: number;
@@ -4,6 +4,7 @@
4
4
  // RenderKind identifies the consumer class of a template. Plugin renderers in
5
5
  // `renderer-foundation` match on kind; the resolver here is kind-agnostic: it
6
6
  // only loads, and the content format (markdown/mjml/html) decides who renders it.
7
+ import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
7
8
  export const RENDER_KINDS = ["mail", "document-pdf", "image-snapshot"];
8
9
  // Kinds whose html body is a rich document: the server rebuilds it through the
9
10
  // document schema on every write (see document-sanitizer.ts).
@@ -44,15 +45,14 @@ export const COLLECTION_REFUSED_KINDS = [
44
45
  "pdf-layout",
45
46
  ];
46
47
  export function isCollectionRefusedKind(kind) {
47
- return COLLECTION_REFUSED_KINDS.some((refused) => refused === kind);
48
+ return isOneOf(COLLECTION_REFUSED_KINDS, kind);
48
49
  }
49
50
  export const CONTENT_FORMATS = ["markdown", "mjml", "html", "plain"];
50
51
  export const TEMPLATE_SCOPES = ["system", "tenant"];
51
52
  export const TEMPLATE_STATUSES = ["draft", "active", "archived"];
52
53
  export const ACTIVE_TEMPLATE_STATUS = "active";
54
+ export { HEX_COLOR_PATTERN } from "./mail-layout-constants.js";
53
55
  export { PDF_DEFAULT_MARGIN_MM, PDF_FOOTER_MARGIN_MM, PDF_HEADER_MARGIN_MM, PDF_ORIENTATIONS, PDF_PAGE_FORMATS, } from "./pdf-constants.js";
54
- // Colors end up inside MJML attributes, so only a strict hex is ever written there.
55
- export const HEX_COLOR_PATTERN = /^#[0-9a-fA-F]{6}$/;
56
56
  export const DEFAULT_MAIL_LAYOUT_SLUG = "default";
57
57
  export const DEFAULT_PDF_LAYOUT_SLUG = "default";
58
58
  // The mail transport enforces no size limit of its own; 10 MiB is a common provider ceiling.
@@ -2,6 +2,7 @@ export { textBlocksClient } from "./client-plugin.tsx";
2
2
  export { DocumentContentEditor } from "./document-editor.tsx";
3
3
  export { type DocumentEditorChrome, type DocumentEditorHandle, type DocumentEditorProps, type DocumentResourcePreview, type DocumentToolbarBlock, MAIL_DOCUMENT_BLOCKS, PDF_DOCUMENT_BLOCKS, } from "./document-toolbar-blocks.ts";
4
4
  export { MAIL_TONES, type MailTone } from "./mail-constants.ts";
5
+ export { HEX_COLOR_PATTERN, MAIL_LAYOUT_ACCENT_LINES, MAIL_LAYOUT_BUTTON_STYLES, MAIL_LAYOUT_FONTS, MAIL_LAYOUT_WIDTHS, } from "./mail-layout-constants.ts";
5
6
  export { PDF_DEFAULT_MARGIN_MM, PDF_FOOTER_MARGIN_MM, PDF_HEADER_MARGIN_MM, PDF_ORIENTATIONS, PDF_PAGE_FORMATS, } from "./pdf-constants.ts";
6
7
  export { PlaceholderLineEditor, type PlaceholderLineEditorProps, } from "./placeholder-line-editor-lazy.tsx";
7
8
  export { TemplateResolverErrors, TemplateResolverHandlers, TemplateResolverQueries, } from "./qualified-names.ts";
@@ -7,6 +7,7 @@ export { textBlocksClient } from "./client-plugin.js";
7
7
  export { DocumentContentEditor } from "./document-editor.js";
8
8
  export { MAIL_DOCUMENT_BLOCKS, PDF_DOCUMENT_BLOCKS, } from "./document-toolbar-blocks.js";
9
9
  export { MAIL_TONES } from "./mail-constants.js";
10
+ export { HEX_COLOR_PATTERN, MAIL_LAYOUT_ACCENT_LINES, MAIL_LAYOUT_BUTTON_STYLES, MAIL_LAYOUT_FONTS, MAIL_LAYOUT_WIDTHS, } from "./mail-layout-constants.js";
10
11
  export { PDF_DEFAULT_MARGIN_MM, PDF_FOOTER_MARGIN_MM, PDF_HEADER_MARGIN_MM, PDF_ORIENTATIONS, PDF_PAGE_FORMATS, } from "./pdf-constants.js";
11
12
  export { PlaceholderLineEditor, } from "./placeholder-line-editor-lazy.js";
12
13
  export { TemplateResolverErrors, TemplateResolverHandlers, TemplateResolverQueries, } from "./qualified-names.js";
@@ -0,0 +1,5 @@
1
+ export declare const MAIL_LAYOUT_WIDTHS: readonly [560, 600, 640];
2
+ export declare const MAIL_LAYOUT_FONTS: readonly ["sans", "serif"];
3
+ export declare const MAIL_LAYOUT_ACCENT_LINES: readonly ["branding", "none"];
4
+ export declare const MAIL_LAYOUT_BUTTON_STYLES: readonly ["filled-rounded", "filled-square", "outline"];
5
+ export declare const HEX_COLOR_PATTERN: RegExp;
@@ -0,0 +1,7 @@
1
+ // No imports: web/ re-exports these, and template-meta.ts pulls in zod and the framework engine.
2
+ export const MAIL_LAYOUT_WIDTHS = [560, 600, 640];
3
+ export const MAIL_LAYOUT_FONTS = ["sans", "serif"];
4
+ export const MAIL_LAYOUT_ACCENT_LINES = ["branding", "none"];
5
+ export const MAIL_LAYOUT_BUTTON_STYLES = ["filled-rounded", "filled-square", "outline"];
6
+ // Colors end up inside MJML attributes, so only a strict hex is ever written there.
7
+ export const HEX_COLOR_PATTERN = /^#[0-9a-fA-F]{6}$/;
@@ -54,10 +54,10 @@ export function createTenantFeature(options) {
54
54
  r.entity({ name: "tenant-invitation", ...tenantInvitationEntity });
55
55
  r.config({
56
56
  keys: {
57
- // Stammdaten-Settings — Tenant-Admin darf ändern, alle dürfen lesen.
57
+ // Core tenant settings — tenant admins can change them; all users can read them.
58
58
  companyName: createTenantConfig("text", { default: "" }),
59
- // Pragmatisch kuratierte Liste — IANA hat hunderte, hier die in der
60
- // Praxis relevantesten. Erweiterung später wenn echter Bedarf.
59
+ // Curated subset of IANA time zones covering the most relevant practical cases.
60
+ // Extend it when a real need arises.
61
61
  timezone: createTenantConfig("select", {
62
62
  default: "Europe/Berlin",
63
63
  options: [
@@ -79,16 +79,16 @@ export function createTenantFeature(options) {
79
79
  default: "de",
80
80
  options: ["de", "en", "fr", "es"],
81
81
  }),
82
- // SMTP — nur SystemAdmin (Plattform-Operator) ändert; smtpPass ist
83
- // verschlüsselt + nur für SystemAdmin lesbar.
82
+ // SMTP settings — only SystemAdmin (platform operator) can change them; smtpPass is
83
+ // encrypted and readable only by SystemAdmin.
84
84
  smtpHost: createTenantConfig("text", { write: access.systemAdmin, read: access.admin }),
85
85
  smtpPass: createTenantConfig("text", {
86
86
  write: access.systemAdmin,
87
87
  read: access.systemAdmin,
88
88
  encrypted: true,
89
89
  }),
90
- // System-Settings — nur programmatisch (SYSTEM_USER) änderbar,
91
- // Tenant-Admin sieht readonly.
90
+ // System settings — changeable only programmatically by SYSTEM_USER;
91
+ // tenant admins see them as read-only.
92
92
  priceModel: createSystemConfig("select", {
93
93
  default: "basic",
94
94
  options: ["basic", "pro", "enterprise"],
@@ -2,6 +2,7 @@ import * as z from "zod";
2
2
  export declare const memberDirectoryQuery: import("@cosmicdrift/kumiko-framework/engine").PagedQueryHandlerDefinition<"memberDirectory", z.ZodObject<{
3
3
  limit: z.ZodDefault<z.ZodNumber>;
4
4
  search: z.ZodOptional<z.ZodString>;
5
+ ids: z.ZodOptional<z.ZodArray<z.ZodString>>;
5
6
  }, z.core.$strip>, {
6
7
  id: string;
7
8
  label: string;
@@ -22,7 +22,7 @@ async function loadMemberUserIds(db, tenantId) {
22
22
  const memberships = await selectMany(db, tenantMembershipsTable, { tenantId });
23
23
  return [...new Set(memberships.map((row) => String(row["userId"])))].sort(compareIds);
24
24
  }
25
- // Label source behind every `user:user` reference column (fw#3107). The
25
+ // Label source behind every `user:user` reference column. The
26
26
  // entity-convention lookup, user:query:user:list, is a SystemAdmin
27
27
  // cross-tenant roster, so a TenantAdmin got a 403 and every actor cell fell
28
28
  // back to the raw UUID. Deliberately narrower than tenant:query:members:
@@ -40,6 +40,8 @@ export const memberDirectoryQuery = definePagedQueryHandler({
40
40
  limit: z.number().int().min(1).max(MAX_LIST_LIMIT).default(MAX_LIST_LIMIT),
41
41
  // Sent by the reference combobox while the user types.
42
42
  search: z.string().trim().min(1).optional(),
43
+ // Resolves exactly these users; callers that know their ids must not depend on the cap.
44
+ ids: z.array(z.string().min(1)).max(MAX_LIST_LIMIT).optional(),
43
45
  }),
44
46
  access: { roles: access.admin },
45
47
  description: "Lists users as id/label pairs for resolving user references to display names: the caller's own tenant members for an admin, every user for a SystemAdmin; carries no email or role data.",
@@ -50,21 +52,26 @@ export const memberDirectoryQuery = definePagedQueryHandler({
50
52
  message: "tenant:query:member-directory requires ctx.systemDb — is r.systemScope() still set on the tenant feature?",
51
53
  });
52
54
  }
53
- const { limit, search } = query.payload;
55
+ const { limit, search, ids } = query.payload;
56
+ if (ids?.length === 0)
57
+ return { rows: [], nextCursor: null };
54
58
  // Without a search the first `limit` rows are enough; with one, every
55
59
  // candidate must be decrypted before the limit can apply.
56
60
  const scanLimit = search === undefined ? limit : SEARCH_SCAN_CAP;
57
61
  let users;
58
62
  if (isSystemAdmin(query.user)) {
59
63
  const db = ctx.systemDb.acknowledgeCrossTenant("SystemAdmin reference labels span every tenant, as user:query:user:list did");
60
- users = await selectMany(db, userTable, undefined, {
64
+ users = await selectMany(db, userTable, ids === undefined ? undefined : { id: ids }, {
61
65
  limit: scanLimit,
62
66
  orderBy: { col: "id", direction: "asc" },
63
67
  });
64
68
  }
65
69
  else {
66
70
  const db = ctx.systemDb.assertTenantMatch(query.user.tenantId);
67
- const userIds = (await loadMemberUserIds(db, query.user.tenantId)).slice(0, scanLimit);
71
+ const requestedIds = ids === undefined ? undefined : new Set(ids);
72
+ const userIds = (await loadMemberUserIds(db, query.user.tenantId))
73
+ .filter((id) => requestedIds === undefined || requestedIds.has(id))
74
+ .slice(0, scanLimit);
68
75
  users =
69
76
  userIds.length > 0
70
77
  ? await selectMany(db, userTable, { id: [...userIds] }, {
@@ -16,7 +16,7 @@ export const membersQuery = defineQueryHandler({
16
16
  name: "members",
17
17
  schema: z.object({
18
18
  // Optional single-user filter — audit detail (and similar) only need one
19
- // member's display name, not the full decrypted roster (fw#2291).
19
+ // member's display name, not the full decrypted roster.
20
20
  userId: z.string().min(1).optional(),
21
21
  }),
22
22
  access: { roles: access.admin },
@@ -38,7 +38,7 @@ function compareTeamRows(a, b, field, dir) {
38
38
  const bv = field === "email" ? (b.email ?? "") : b.status;
39
39
  return av.localeCompare(bv) * sign;
40
40
  }
41
- // User-selected facet filters (payload.filters, fw#2224) — `status` is the
41
+ // User-selected facet filters (payload.filters) — `status` is the
42
42
  // only filterable field here: it's synthesized from which table a row came
43
43
  // from, not a stored column, so there is nothing else meaningful to filter
44
44
  // on server-side yet. `filter` (singular, screen-level static filter) is
@@ -2,6 +2,7 @@ import * as z from "zod";
2
2
  export declare const tenantDirectoryQuery: import("@cosmicdrift/kumiko-framework/engine").PagedQueryHandlerDefinition<"tenantDirectory", z.ZodObject<{
3
3
  limit: z.ZodDefault<z.ZodNumber>;
4
4
  search: z.ZodOptional<z.ZodString>;
5
+ ids: z.ZodOptional<z.ZodArray<z.ZodString>>;
5
6
  }, z.core.$strip>, {
6
7
  id: string;
7
8
  label: string;
@@ -5,7 +5,7 @@ import * as z from "zod";
5
5
  import { decryptTenantNames, takeTenantsMatchingDecryptedName } from "../decrypt-tenant-names.js";
6
6
  import { tenantTable } from "../schema/tenant.js";
7
7
  import { isSystemAdmin } from "./is-system-admin.js";
8
- // Label source behind every `tenant:tenant` reference column (fw#3142). The
8
+ // Label source for every `tenant:tenant` reference column. The
9
9
  // entity-convention lookup, tenant:query:tenant:list, is a SystemAdmin-only
10
10
  // entity-list handler, so a TenantAdmin got a 403 and every tenant cell fell
11
11
  // back to the raw UUID. A SystemAdmin keeps the global reach tenant:list gave
@@ -21,9 +21,11 @@ export const tenantDirectoryQuery = definePagedQueryHandler({
21
21
  limit: z.number().int().min(1).max(MAX_LIST_LIMIT).default(MAX_LIST_LIMIT),
22
22
  // Sent by the reference combobox while the user types.
23
23
  search: z.string().trim().min(1).optional(),
24
+ // Resolves exactly these tenants; callers that know their ids must not depend on the cap.
25
+ ids: z.array(z.string().min(1)).max(MAX_LIST_LIMIT).optional(),
24
26
  }),
25
27
  access: { roles: access.admin },
26
- description: "Lists tenants as id/label pairs for resolving tenant references to display names: the caller's own tenant for an admin, every tenant for a SystemAdmin.",
28
+ description: "Lists tenants as id/label pairs for resolving tenant references to display names: the caller's own tenant for an admin, every tenant for a SystemAdmin. A search returns the first `limit` matches in tenant-key order (sorted by label afterwards), not the alphabetically best matches.",
27
29
  agent: { expose: false },
28
30
  handler: async (query, ctx) => {
29
31
  if (!ctx.systemDb) {
@@ -31,12 +33,14 @@ export const tenantDirectoryQuery = definePagedQueryHandler({
31
33
  message: "tenant:query:tenant-directory requires ctx.systemDb — is r.systemScope() still set on the tenant feature?",
32
34
  });
33
35
  }
34
- const { limit, search } = query.payload;
36
+ const { limit, search, ids } = query.payload;
37
+ if (ids?.length === 0)
38
+ return { rows: [], nextCursor: null };
35
39
  const scanLimit = search === undefined ? limit : SEARCH_SCAN_CAP;
36
40
  let tenants;
37
41
  if (isSystemAdmin(query.user)) {
38
42
  const db = ctx.systemDb.acknowledgeCrossTenant("SystemAdmin reference labels span every tenant, as tenant:query:tenant:list did");
39
- tenants = await selectMany(db, tenantTable, undefined, {
43
+ tenants = await selectMany(db, tenantTable, ids === undefined ? undefined : { id: ids }, {
40
44
  limit: scanLimit,
41
45
  orderBy: [
42
46
  { col: "key", direction: "asc" },
@@ -47,7 +51,7 @@ export const tenantDirectoryQuery = definePagedQueryHandler({
47
51
  else {
48
52
  const db = ctx.systemDb.assertTenantMatch(query.user.tenantId);
49
53
  const row = await fetchOne(db, tenantTable, { id: query.user.tenantId });
50
- tenants = row ? [row] : [];
54
+ tenants = row && (ids === undefined || ids.includes(query.user.tenantId)) ? [row] : [];
51
55
  }
52
56
  // name is ciphertext at rest, so the SQL page is keyed by the plaintext
53
57
  // `key`; label order and search happen in memory after decrypting.
@@ -1,44 +1,42 @@
1
- // Tenant-Invitations: Pre-Membership-Records mit Magic-Link-Token-Flow.
1
+ // Tenant invitations are pre-membership records using a magic-link token flow.
2
2
  //
3
3
  // Lifecycle:
4
- // 1. Admin invitet email → DB-Row entsteht mit status="pending",
5
- // Random-Token in Redis (signup-style bidirektional)
6
- // 2. Mail an die invited Email mit Activation-URL
7
- // 3. Klick auf Link → 3 Branches:
8
- // a) Eingeloggt + Email matched session-user → Membership-Add
9
- // b) Anonymous + Email existiert in users → Login → Auto-Accept
10
- // c) Anonymous + Email neu → Password setzen → user+membership entstehen
11
- // 4. Bei Erfolg: status="accepted", token aus Redis gelöscht (single-use-burn)
12
- // 5. Bei Cancel durch Admin: status="cancelled", token aus Redis gelöscht
13
- // 6. Bei TTL-Ablauf: Redis räumt Token, DB-Row bleibt mit status="pending"
14
- // (Cleanup-Job marked sie als "expired" — separater Concern)
4
+ // 1. An admin invites an email → a DB row is created with status="pending",
5
+ // and a random token is stored in Redis (signup-style bidirectional flow).
6
+ // 2. An email containing the activation URL is sent to the invitee.
7
+ // 3. Clicking the link follows one of three branches:
8
+ // a) Logged in + email matches the session user → membership is added
9
+ // b) Anonymous + email exists in users → login → automatic acceptance
10
+ // c) Anonymous + new email → set a password → user and membership are created
11
+ // 4. On success: status="accepted", and the Redis token is deleted (single-use).
12
+ // 5. When cancelled by an admin: status="cancelled", and the Redis token is deleted.
13
+ // 6. When the TTL expires: Redis removes the token, while the DB row remains
14
+ // status="pending" (a cleanup job marks it as "expired" separately).
15
15
  //
16
- // Single-Truth für expiry: Redis-TTL. DB-row.expiresAt ist nur UI-
17
- // Anzeige ("läuft in 6 Tagen ab"). Bei Lookup: pending in DB + token
18
- // nicht mehr in Redis → effectively expired, accept schlägt fehl mit
19
- // invalid-token.
16
+ // Redis-TTL is the single source of truth for expiry. DB-row.expiresAt is only
17
+ // for UI display ("expires in 6 days"). On lookup, a pending DB row without
18
+ // a Redis token is effectively expired, so acceptance fails with invalid-token.
20
19
  //
21
- // Idempotenz: zweiter invite für gleiche (tenantId, email) während
22
- // pending → re-use existing row + refresh Redis-token + send mail
23
- // (analog zu signup-Resend).
20
+ // Idempotency: a second invite for the same (tenantId, email) while pending
21
+ // reuses the existing row, refreshes the Redis token, and sends the email
22
+ // (analogous to signup resend).
24
23
  import { buildEntityTable } from "@cosmicdrift/kumiko-framework/db";
25
24
  import { createEntity, createMultiSelectField, createNumberField, createSelectField, createTextField, createTimestampField, } from "@cosmicdrift/kumiko-framework/engine";
26
25
  // kumiko-lint-ignore cross-feature-import global-role options are owned by the user feature
27
26
  import { GLOBAL_ROLE_OPTIONS } from "../user/web/constants.js";
28
- // Status-const-Object damit Handler-Code keine Magic-Strings nutzt.
29
- // Bei rename (z.B. "cancelled" → "revoked") fällt jeder caller auf
30
- // einmal auf statt verstreut über 5 Stellen.
27
+ // The status constant object prevents handler code from using magic strings.
28
+ // If a value is renamed (for example, "cancelled" → "revoked"), every caller
29
+ // fails at once instead of having stale values scattered across five locations.
31
30
  export const INVITATION_STATUS = {
32
31
  pending: "pending",
33
32
  accepted: "accepted",
34
33
  cancelled: "cancelled",
35
34
  expired: "expired",
36
35
  };
37
- // Order MUSS bit-identisch zur DB-Migration sein. Object.values
38
- // bewahrt insertion-order (JS-spec-stable für string-keys). Wenn
39
- // jemand INVITATION_STATUS reordnet, generiert drizzle-kit eine
40
- // neue Migration. Hardcoded-Tuple zur Sicherheit gegen versehentliches
41
- // Refactoring der Object-Keys.
36
+ // The order MUST be bit-for-bit identical to the database migration. Object.values
37
+ // preserves insertion order (stable for string keys under the JS spec). Reordering
38
+ // INVITATION_STATUS generates a new drizzle-kit migration. The hardcoded tuple
39
+ // also guards against accidental refactoring of the object keys.
42
40
  export const INVITATION_STATUSES = [
43
41
  INVITATION_STATUS.pending,
44
42
  INVITATION_STATUS.accepted,
@@ -48,11 +46,11 @@ export const INVITATION_STATUSES = [
48
46
  export const tenantInvitationEntity = createEntity({
49
47
  table: "read_tenant_invitations",
50
48
  fields: {
51
- // Eingeladene Email — case-insensitive normalisiert beim Insert.
52
- // PII bis zur Annahme (danach hat der User selbst seine email in users).
49
+ // The invited email is normalized case-insensitively on insert.
50
+ // It remains PII until acceptance; afterward, the user owns the email in users.
53
51
  email: createTextField({ required: true, maxLength: 320, personal: "self", find: "exact" }),
54
- // Membership-Rolle die dem User nach Accept gegeben wird. Default
55
- // im handler ist "Admin" (Co-Admin-Pattern für kleine Teams).
52
+ // The membership role granted to the user on acceptance. The handler defaults
53
+ // to "Admin" (a co-admin pattern for small teams).
56
54
  role: createTextField({
57
55
  required: true,
58
56
  maxLength: 50,
@@ -73,11 +71,11 @@ export const tenantInvitationEntity = createEntity({
73
71
  required: true,
74
72
  default: "pending",
75
73
  }),
76
- // userId des einladenden Admins (für Audit-Trail "wer hat eingeladen").
74
+ // ID of the inviting admin, retained for the audit trail ("who invited").
77
75
  // Self-referencing ownerField: the field's own value IS the owner userId.
78
- // lookupable: the delete-hook filters "invitations sent by this user"
79
- // via the generated blind-index column instead of a full-tenant
80
- // decrypt-and-scan (see user-data-rights-defaults' invitation hook).
76
+ // lookupable: the delete hook filters "invitations sent by this user"
77
+ // through the generated blind-index column instead of decrypting and scanning
78
+ // the entire tenant (see user-data-rights-defaults' invitation hook).
81
79
  invitedBy: createTextField({
82
80
  required: true,
83
81
  personal: { of: "invitedBy" },
@@ -91,11 +89,10 @@ export const tenantInvitationEntity = createEntity({
91
89
  // UI-Anzeige — Wahrheit liegt in Redis-TTL.
92
90
  expiresAt: createTimestampField({ required: true }),
93
91
  },
94
- // Eine Invitation-Row pro (tenantId, email). Bei Re-Invite (Admin
95
- // invitet zweite Mal nach Cancel/Accept) wird die existing row
96
- // updated: status pending → cancelled → pending zurück, expiresAt
97
- // refreshed. Verhindert Token-Doppel-Gabe + macht Resend-Idempotenz
98
- // im handler trivial.
92
+ // One invitation row per (tenantId, email). On re-invite after cancellation or
93
+ // acceptance, the existing row is updated: status pending → cancelled → pending,
94
+ // and expiresAt is refreshed. This prevents duplicate tokens and makes resend
95
+ // idempotency trivial in the handler.
99
96
  indexes: [
100
97
  {
101
98
  unique: true,
@@ -11,9 +11,9 @@ import { createEntity, createTextField } from "@cosmicdrift/kumiko-framework/eng
11
11
  // the old serial-id design and keeps duplicate-write protection at the
12
12
  // database level independent of the handler lookup.
13
13
  //
14
- // Single-Source-of-Truth: `tenantMembershipEntity`. Die DB-Tabelle wird
15
- // aus der EntityDefinition über buildEntityTable abgeleitet, der
16
- // unique-Index ist via entity.indexes deklariert.
14
+ // Single source of truth: `tenantMembershipEntity`. The database table is
15
+ // derived from the EntityDefinition through buildEntityTable, and the
16
+ // unique index is declared via entity.indexes.
17
17
  export const tenantMembershipEntity = createEntity({
18
18
  table: "read_tenant_memberships",
19
19
  fields: {
@@ -10,9 +10,9 @@ export const TENANT_LIFECYCLE_STATUSES = [
10
10
  export const tenantEntity = createEntity({
11
11
  description: "A tenant, the isolated workspace every other record belongs to, holding its key and display name, whether it is enabled, and its destruction-lifecycle state.",
12
12
  table: "read_tenants",
13
- // tenant.id IS the tenantId-value that every other table references as FK.
14
- // Alle tenantId-Spalten sind UUID (Migration 2026-04-16) → tenant.id muss
15
- // UUID sein, sonst findet der tenants-Lookup nie. Default gen_random_uuid().
13
+ // `tenant.id` is the `tenantId` value referenced by every other table as a foreign key.
14
+ // Every `tenantId` column is UUID, so `tenant.id` must also be UUID; otherwise
15
+ // the tenant lookup never finds a match. The default is `gen_random_uuid()`.
16
16
  fields: {
17
17
  key: createTextField({
18
18
  required: true,
@@ -48,12 +48,10 @@ export const tenantEntity = createEntity({
48
48
  destroyStartedAt: createTimestampField({}),
49
49
  destroyedAt: createTimestampField({}),
50
50
  },
51
- // tenant.key wird in Admin-URLs verwendet (`admin.<host>/<key>/...`) und
52
- // muss eindeutig sein. Ohne unique-constraint hätte ein konkurrenter
53
- // Self-Signup-Confirm einen TOCTOU-Race zwischen generateUniqueName-
54
- // isAvailable-check und insert: zwei Tabs könnten sequentiell denselben
55
- // Slug claimen, beide commits durch, der dritte User landet auf einem
56
- // shared admin-URL-prefix.
51
+ // `tenant.key` appears in admin URLs (`admin.<host>/<key>/...`) and must be unique.
52
+ // Without a unique constraint, concurrent self-signup confirmation could pass
53
+ // the `generateUniqueName` `isAvailable` check before either insert, allowing
54
+ // two tabs to claim the same slug and causing users to share an admin URL prefix.
57
55
  indexes: [{ unique: true, columns: ["key"] }],
58
56
  });
59
57
  export const tenantTable = buildEntityTable("tenant", tenantEntity);
@@ -141,7 +141,7 @@ export function createMembersScreen(options) {
141
141
  // feature.ts when `TenantFeatureOptions.inviteScreen` is set — see
142
142
  // createMembersScreen's doc comment above for why.
143
143
  export function createInviteCreateScreen(assignableAppRoles = new Map()) {
144
- // Admin sees this screen too, so only app roles Admin may grant are offered (fw#2414).
144
+ // Admin sees this screen too, so only app roles Admin may grant are offered.
145
145
  const appRoleOptions = [...assignableAppRoles]
146
146
  .filter(([, assignableFrom]) => isAssignableByRole(assignableFrom, "Admin"))
147
147
  .map(([role]) => role);
@@ -14,12 +14,13 @@ export type SeedTenantMembershipOptions = {
14
14
  readonly by?: SessionUser;
15
15
  };
16
16
  export type SeedTenantOptions = {
17
- /** Stable UUID — required for fixtures so the FE/BE können dieselbe ID
18
- * hardcoden (Sample-Switcher zeigt den Tenant beim Namen, der Test
19
- * prüft Memberships gegen exakt diese ID). Ohne ID müsste der Caller
20
- * den lookup-by-key extra machen. */
17
+ /**
18
+ * Stable UUID required for fixtures so the FE/BE can hardcode the same ID. The sample switcher
19
+ * displays the tenant by name, while tests verify memberships against this exact ID; without it,
20
+ * callers would need an extra lookup by key.
21
+ */
21
22
  readonly id: TenantId;
22
- /** URL-/Slug-Form (z.B. "dev", "acme"). Indexed unique in der DB. */
23
+ /** URL/slug form (for example, "dev" or "acme"). Indexed unique in the database. */
23
24
  readonly key: string;
24
25
  /** Human-readable label (im Switcher angezeigt). */
25
26
  readonly name: string;
@@ -69,14 +69,14 @@ function buildSeedHookNotify(context, scopedUser, targetTenantId, notifyTiming)
69
69
  // registered entity/handler hooks fire (search-index/SSE system hooks are
70
70
  // wired at server-boot and out of reach here).
71
71
  //
72
- // Tenant re-scope (#1566): when `targetTenantId` is set we rebuild the
72
+ // Tenant re-scope: when `targetTenantId` is set we rebuild the
73
73
  // tenant-bound pieces of the context (`_tenantId`, `db`, `notify`,
74
74
  // `hasFeature`, `user.tenantId`) — a shallow `{ ...ctx, _tenantId }` left
75
75
  // closures over the caller's tenant (self-signup is anonymous/system).
76
76
  // `query`/`write` bridges still share the caller's identity; hooks that
77
77
  // need a full identity switch use `writeAs`/`queryAs`.
78
78
  //
79
- // afterCommit (#1566): when `hooks.context.scheduleAfterCommit` is present
79
+ // afterCommit: when `hooks.context.scheduleAfterCommit` is present
80
80
  // (HandlerContext from a live write), afterCommit hooks are queued onto the
81
81
  // dispatcher's sink and flush post-commit. Without a sink (fixture / plain
82
82
  // Connection) they still fire immediately — there is no outer TX to wait for.
@@ -161,19 +161,19 @@ target) {
161
161
  */
162
162
  export async function seedTenant(db, options, hooks) {
163
163
  const by = options.by ?? TestUsers.systemAdmin;
164
- // executor.create erwartet eine TenantDb (mit .insert()-API), nicht
165
- // die rohe DbConnection. Auch wenn das Tenant-Aggregat selbst NICHT
166
- // tenant-scoped ist, braucht der Wrap-Layer für die runtime-API zu
167
- // existieren. by.tenantId reicht — keine Override-Semantik wie bei
168
- // seedTenantMembership nötig.
164
+ // executor.create expects a TenantDb with an .insert()-API, not the raw
165
+ // DbConnection. Although the tenant aggregate is not tenant-scoped, the
166
+ // wrapper is required by the runtime API. by.tenantId is sufficient; unlike
167
+ // seedTenantMembership, no override semantics are needed.
169
168
  const tdb = createTenantDb({ db, tenantId: by.tenantId, mode: "system" });
170
169
  const existing = await fetchOne(db, tenantTable, { id: options.id });
171
170
  if (existing)
172
171
  return { id: options.id };
173
- // Idempotenz: Aggregate kann im Event-Store existieren ohne Projection-Row
174
- // (Projection-Drift nach rebuild, manuellem DELETE, oder async-lag). Wenn
175
- // Stream-Version > 0 → kein create() — wäre version_conflict. Caller
176
- // bekommt die ID, Projection wird beim nächsten Dispatcher-Cycle aufgebaut.
172
+ // Idempotency: the aggregate may exist in the event store without a
173
+ // projection row (projection drift after a rebuild, manual DELETE, or async
174
+ // lag). If the stream version is > 0, skip create() to avoid
175
+ // version_conflict. Return the ID; the next dispatcher cycle can rebuild the
176
+ // projection.
177
177
  const streamVersion = await getUnscopedAggregateStreamMaxVersion(db, options.id);
178
178
  if (streamVersion > 0)
179
179
  return { id: options.id };
@@ -206,7 +206,7 @@ export async function seedTenant(db, options, hooks) {
206
206
  */
207
207
  export async function seedTenantMembership(db, options,
208
208
  // Optional, append-only — same rationale as seedTenant's hooks param
209
- // (#1478): fires tenantMembership's postSave hooks (e.g. a Welcome-
209
+ // fires tenantMembership's postSave hooks (e.g. a Welcome-
210
210
  // notification or default-notification-preferences hook keyed off
211
211
  // `allOf: "tenantMembership"`) for fixtures/self-signup that opt in.
212
212
  // Omit to keep today's hook-less behavior.
@@ -1,7 +1,6 @@
1
- // /testing re-exportiert /seeding. Ehemalige Heimat der seed-Helpers,
2
- // jetzt nur noch Aggregation. Die Helpers leben in `/seeding` weil sie
3
- // genauso vom Dev-Server-Bootstrap (runDevApp) konsumiert werden — nicht
4
- // nur von Tests. Vertrag der Helpers ist stabil, test-spezifische
5
- // Knöpfe gehören NICHT hier rein (würde dev-boots brechen wenn jemand
6
- // einen lockout-test-Knopf einbaut).
1
+ // `/testing` re-exports `/seeding`; it is no longer the home of the seed helpers.
2
+ // The helpers live in `/seeding` because they are also consumed by the
3
+ // development-server bootstrap (`runDevApp`), not only by tests. Keep their
4
+ // stable contract here; test-specific options do not belong in this module,
5
+ // because they could break development boots when a lockout-test option is added.
7
6
  export * from "./seeding.js";