@cosmicdrift/kumiko-bundled-features 0.362.0 → 0.364.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 (468) hide show
  1. package/dist/admin-shell/feature.d.ts +3 -0
  2. package/dist/admin-shell/feature.js +6 -1
  3. package/dist/agent-tools/agent-manifest.js +2 -1
  4. package/dist/agent-tools/filter-ops.d.ts +1 -1
  5. package/dist/agent-tools/filter-ops.js +1 -3
  6. package/dist/agent-tools/tool-dispatch.js +2 -1
  7. package/dist/audit/handlers/list.query.js +9 -5
  8. package/dist/auth-email-password/bootstrap.d.ts +8 -5
  9. package/dist/auth-email-password/bootstrap.js +12 -4
  10. package/dist/auth-email-password/email-rate-limits.d.ts +4 -0
  11. package/dist/auth-email-password/email-rate-limits.js +13 -0
  12. package/dist/auth-email-password/email-templates.d.ts +4 -26
  13. package/dist/auth-email-password/email-templates.js +9 -101
  14. package/dist/auth-email-password/feature.js +24 -6
  15. package/dist/auth-email-password/handlers/change-password.write.d.ts +1 -1
  16. package/dist/auth-email-password/handlers/change-password.write.js +6 -2
  17. package/dist/auth-email-password/handlers/confirm-account-unlock.write.d.ts +1 -1
  18. package/dist/auth-email-password/handlers/invite-accept-with-login.write.d.ts +1 -1
  19. package/dist/auth-email-password/handlers/invite-accept.write.d.ts +1 -1
  20. package/dist/auth-email-password/handlers/invite-create.write.d.ts +2 -2
  21. package/dist/auth-email-password/handlers/invite-create.write.js +4 -4
  22. package/dist/auth-email-password/handlers/invite-signup-complete.write.d.ts +1 -1
  23. package/dist/auth-email-password/handlers/login.write.d.ts +1 -1
  24. package/dist/auth-email-password/handlers/logout.write.d.ts +1 -1
  25. package/dist/auth-email-password/handlers/logout.write.js +6 -2
  26. package/dist/auth-email-password/handlers/request-account-unlock.write.d.ts +1 -1
  27. package/dist/auth-email-password/handlers/request-account-unlock.write.js +2 -4
  28. package/dist/auth-email-password/handlers/request-email-verification.write.d.ts +1 -1
  29. package/dist/auth-email-password/handlers/request-email-verification.write.js +2 -4
  30. package/dist/auth-email-password/handlers/request-password-reset.write.d.ts +1 -1
  31. package/dist/auth-email-password/handlers/request-password-reset.write.js +2 -4
  32. package/dist/auth-email-password/handlers/reset-password.write.d.ts +1 -1
  33. package/dist/auth-email-password/handlers/signup-confirm.write.d.ts +1 -1
  34. package/dist/auth-email-password/handlers/signup-confirm.write.js +3 -4
  35. package/dist/auth-email-password/handlers/signup-request.write.d.ts +1 -1
  36. package/dist/auth-email-password/handlers/signup-request.write.js +2 -1
  37. package/dist/auth-email-password/handlers/switch-tenant-mfa-gate.write.d.ts +1 -1
  38. package/dist/auth-email-password/handlers/token-request-handler.d.ts +2 -3
  39. package/dist/auth-email-password/handlers/token-request-handler.js +2 -2
  40. package/dist/auth-email-password/handlers/verify-email.write.d.ts +1 -1
  41. package/dist/auth-email-password/index.d.ts +2 -2
  42. package/dist/auth-email-password/index.js +1 -1
  43. package/dist/auth-email-password/magic-link-mail.d.ts +3 -2
  44. package/dist/auth-email-password/magic-link-mail.js +19 -14
  45. package/dist/auth-email-password/mail-notifications.d.ts +32 -0
  46. package/dist/auth-email-password/mail-notifications.js +116 -0
  47. package/dist/auth-email-password/signup-activation.d.ts +1 -1
  48. package/dist/auth-email-password/signup-activation.js +2 -3
  49. package/dist/auth-email-password/web/auth-gate.js +16 -4
  50. package/dist/auth-foundation/types.js +2 -8
  51. package/dist/auth-mfa/feature.js +4 -4
  52. package/dist/auth-mfa/handlers/disable.write.d.ts +1 -1
  53. package/dist/auth-mfa/handlers/enable-confirm-preauth.write.d.ts +1 -1
  54. package/dist/auth-mfa/handlers/enable-confirm.write.d.ts +1 -1
  55. package/dist/auth-mfa/handlers/enable-start-preauth.write.d.ts +1 -1
  56. package/dist/auth-mfa/handlers/enable-start.write.d.ts +1 -1
  57. package/dist/auth-mfa/handlers/regenerate-recovery.write.d.ts +1 -1
  58. package/dist/auth-mfa/handlers/verify.write.d.ts +1 -1
  59. package/dist/auth-mfa/hmac-token-codec.js +4 -4
  60. package/dist/auth-mfa/mfa-challenge-token.js +3 -3
  61. package/dist/auth-mfa/mfa-preauth-setup-token.js +3 -3
  62. package/dist/auth-mfa/mfa-setup-token.js +8 -8
  63. package/dist/billing-foundation/constants.d.ts +3 -3
  64. package/dist/billing-foundation/constants.js +5 -4
  65. package/dist/billing-foundation/consumer-protection/confirmation-mail.d.ts +32 -14
  66. package/dist/billing-foundation/consumer-protection/confirmation-mail.js +74 -32
  67. package/dist/billing-foundation/consumer-protection/consent-gate.d.ts +3 -0
  68. package/dist/billing-foundation/consumer-protection/consent-gate.js +21 -2
  69. package/dist/billing-foundation/consumer-protection/issue-confirmation.js +3 -3
  70. package/dist/billing-foundation/consumer-protection/mail-notifications.d.ts +8 -0
  71. package/dist/billing-foundation/consumer-protection/mail-notifications.js +95 -0
  72. package/dist/billing-foundation/consumer-protection/register-consent.js +2 -0
  73. package/dist/billing-foundation/consumer-protection/register-termination.js +11 -1
  74. package/dist/billing-foundation/consumer-protection/termination-mail.d.ts +25 -13
  75. package/dist/billing-foundation/consumer-protection/termination-mail.js +11 -23
  76. package/dist/billing-foundation/consumer-protection/termination-notify.js +2 -2
  77. package/dist/billing-foundation/consumer-protection/termination-pages.js +1 -3
  78. package/dist/billing-foundation/consumer-protection/termination-receipt-limit.d.ts +6 -0
  79. package/dist/billing-foundation/consumer-protection/termination-receipt-limit.js +34 -0
  80. package/dist/billing-foundation/consumer-protection/termination-record.d.ts +2 -0
  81. package/dist/billing-foundation/consumer-protection/termination-record.js +7 -1
  82. package/dist/billing-foundation/consumer-protection/termination-request.js +31 -21
  83. package/dist/billing-foundation/consumer-protection/termination-texts.d.ts +1 -1
  84. package/dist/billing-foundation/consumer-protection/termination-texts.js +6 -0
  85. package/dist/billing-foundation/consumer-protection/withdrawal-period.d.ts +10 -0
  86. package/dist/billing-foundation/consumer-protection/withdrawal-period.js +26 -0
  87. package/dist/billing-foundation/handlers/create-checkout-session.write.js +11 -5
  88. package/dist/billing-foundation/handlers/process-event.write.js +12 -8
  89. package/dist/billing-foundation/handlers/process-payment-event.write.js +1 -1
  90. package/dist/billing-foundation/i18n.js +3 -0
  91. package/dist/billing-foundation/subscription-tier-sync.d.ts +7 -1
  92. package/dist/billing-foundation/subscription-tier-sync.js +16 -9
  93. package/dist/billing-foundation/types.d.ts +7 -2
  94. package/dist/cap-counter/calendar-cap-usage-reservation.js +2 -0
  95. package/dist/cap-counter/enforce-cap.d.ts +18 -1
  96. package/dist/cap-counter/enforce-cap.js +49 -6
  97. package/dist/cap-counter/index.d.ts +1 -1
  98. package/dist/cap-counter/index.js +1 -1
  99. package/dist/cap-counter/with-cap-enforcement.d.ts +2 -0
  100. package/dist/cap-overview/handlers/tenant-caps-list.query.js +2 -1
  101. package/dist/cap-overview/web/cap-usage-cell.js +5 -4
  102. package/dist/channel-email/email-channel.d.ts +2 -2
  103. package/dist/channel-email/email-channel.js +101 -26
  104. package/dist/channel-email/feature.js +3 -3
  105. package/dist/channel-email/index.d.ts +1 -1
  106. package/dist/channel-email/index.js +1 -1
  107. package/dist/channel-email/pii-guard.js +10 -0
  108. package/dist/channel-email/smtp-transport.js +13 -0
  109. package/dist/channel-email/types.d.ts +8 -0
  110. package/dist/channel-in-app/handlers/mark-all-read.write.d.ts +1 -1
  111. package/dist/channel-in-app/handlers/mark-read.write.d.ts +1 -1
  112. package/dist/compliance-profiles/handlers/set-profile.write.d.ts +1 -1
  113. package/dist/config/handlers/reset.write.d.ts +1 -1
  114. package/dist/config/handlers/set.write.d.ts +1 -1
  115. package/dist/config/handlers/set.write.js +3 -4
  116. package/dist/config/resolver.d.ts +1 -0
  117. package/dist/config/resolver.js +11 -14
  118. package/dist/config/write-helpers.d.ts +2 -0
  119. package/dist/config/write-helpers.js +19 -0
  120. package/dist/crypto-shredding/handlers/forget-subject.write.d.ts +1 -1
  121. package/dist/crypto-shredding/handlers/forget-subject.write.js +29 -19
  122. package/dist/custom-fields/handlers/update-tenant-field.write.js +0 -1
  123. package/dist/custom-fields/lib/value-schema.js +10 -11
  124. package/dist/custom-fields/wire-user-data-rights.js +7 -6
  125. package/dist/data-retention/index.d.ts +1 -0
  126. package/dist/data-retention/index.js +1 -0
  127. package/dist/data-retention/run-retention-cleanup.js +6 -6
  128. package/dist/delivery/attachment-ref.d.ts +41 -0
  129. package/dist/delivery/attachment-ref.js +78 -0
  130. package/dist/delivery/channel-context.d.ts +8 -4
  131. package/dist/delivery/channel-context.js +94 -2
  132. package/dist/delivery/constants.d.ts +1 -0
  133. package/dist/delivery/constants.js +1 -0
  134. package/dist/delivery/delivery-service.d.ts +4 -1
  135. package/dist/delivery/delivery-service.js +38 -32
  136. package/dist/delivery/feature.js +1 -1
  137. package/dist/delivery/handlers/resubscribe-address.write.d.ts +1 -1
  138. package/dist/delivery/handlers/resubscribe-user.write.d.ts +1 -1
  139. package/dist/delivery/handlers/set-preference.write.d.ts +1 -1
  140. package/dist/delivery/handlers/unsubscribe-address.write.d.ts +1 -1
  141. package/dist/delivery/handlers/unsubscribe-user.write.d.ts +1 -1
  142. package/dist/delivery/index.d.ts +5 -2
  143. package/dist/delivery/index.js +4 -1
  144. package/dist/delivery/jobs.js +66 -14
  145. package/dist/delivery/notify-factory.js +4 -1
  146. package/dist/delivery/testing.d.ts +4 -1
  147. package/dist/delivery/types.d.ts +26 -14
  148. package/dist/delivery/unsubscribe.js +4 -1
  149. package/dist/derivatives-sharp/render.js +1 -18
  150. package/dist/document-ingest-foundation/pages.js +4 -4
  151. package/dist/feature-toggles/handlers/set.write.d.ts +1 -1
  152. package/dist/feature-toggles/toggle-sync-signal.js +4 -4
  153. package/dist/file-derivatives/handlers/public-variant.query.js +1 -1
  154. package/dist/file-foundation/index.d.ts +1 -0
  155. package/dist/file-foundation/index.js +1 -0
  156. package/dist/file-foundation/read-file-ref-content.d.ts +27 -0
  157. package/dist/file-foundation/read-file-ref-content.js +51 -0
  158. package/dist/files-tenant-data/hooks.js +4 -0
  159. package/dist/folders/web/folder-manager.js +3 -2
  160. package/dist/form-draft/db/queries/cleanup.js +4 -4
  161. package/dist/form-draft/db/queries/draft-count.js +2 -2
  162. package/dist/form-draft/db/queries/owned-file-refs.js +2 -2
  163. package/dist/form-draft/handlers/discard.write.d.ts +1 -1
  164. package/dist/form-draft/handlers/save.write.d.ts +1 -1
  165. package/dist/form-draft/release-file-refs.js +3 -2
  166. package/dist/inbound-mail-foundation/handlers/connect-account.write.js +1 -1
  167. package/dist/inbound-mail-foundation/handlers/ingest-message.write.js +6 -6
  168. package/dist/inbound-mail-foundation/handlers/scope-visibility.d.ts +1 -1
  169. package/dist/inbound-mail-foundation/oauth-access-token.js +8 -3
  170. package/dist/inbound-mail-foundation/oauth-state.js +7 -7
  171. package/dist/inbound-mail-foundation/types.js +4 -4
  172. package/dist/inbound-mail-foundation/watch-supervisor.js +24 -13
  173. package/dist/inbound-provider-imap/imap-client.js +4 -3
  174. package/dist/jobs/db/queries/stale-run-sweep.d.ts +1 -1
  175. package/dist/jobs/db/queries/stale-run-sweep.js +12 -5
  176. package/dist/jobs/feature.js +5 -3
  177. package/dist/jobs/handlers/list.query.js +3 -1
  178. package/dist/jobs/handlers/retry.write.d.ts +1 -1
  179. package/dist/jobs/handlers/stale-run-sweep.job.d.ts +1 -1
  180. package/dist/jobs/handlers/stale-run-sweep.job.js +2 -2
  181. package/dist/jobs/handlers/trigger.write.d.ts +1 -1
  182. package/dist/jobs/job-run-logger.js +32 -10
  183. package/dist/jobs/tenant-job-run-table.js +3 -2
  184. package/dist/ledger/entity.js +3 -1
  185. package/dist/ledger/recurring.js +1 -3
  186. package/dist/managed-pages/branding.d.ts +2 -0
  187. package/dist/managed-pages/branding.js +24 -2
  188. package/dist/managed-pages/feature.js +1 -0
  189. package/dist/managed-pages/handlers/set.write.d.ts +1 -1
  190. package/dist/managed-pages/i18n.js +1 -0
  191. package/dist/managed-pages/screens/branding-screen.js +8 -1
  192. package/dist/page-render/branding.d.ts +1 -0
  193. package/dist/page-render/branding.js +1 -0
  194. package/dist/page-render/markdown.js +1 -1
  195. package/dist/personal-access-tokens/feature.js +1 -1
  196. package/dist/personal-access-tokens/handlers/create.write.d.ts +1 -1
  197. package/dist/personal-access-tokens/handlers/list.query.js +2 -1
  198. package/dist/personal-access-tokens/handlers/revoke.write.d.ts +1 -1
  199. package/dist/personal-access-tokens/revoke-for-user.js +2 -1
  200. package/dist/renderer-foundation/api.d.ts +13 -13
  201. package/dist/renderer-foundation/api.js +1 -1
  202. package/dist/renderer-foundation/constants.js +2 -4
  203. package/dist/renderer-foundation/feature.js +7 -7
  204. package/dist/renderer-foundation/index.d.ts +2 -1
  205. package/dist/renderer-foundation/index.js +1 -0
  206. package/dist/renderer-foundation/types.d.ts +94 -32
  207. package/dist/renderer-pdf/feature.js +7 -1
  208. package/dist/renderer-pdf/render-table-pdf.d.ts +27 -33
  209. package/dist/renderer-pdf/render-table-pdf.js +95 -34
  210. package/dist/secrets/feature.js +4 -3
  211. package/dist/secrets/handlers/delete.write.d.ts +1 -1
  212. package/dist/secrets/handlers/set.write.d.ts +1 -1
  213. package/dist/secrets/secrets-context.js +15 -3
  214. package/dist/sessions/db/queries/cleanup.js +2 -2
  215. package/dist/sessions/feature.js +1 -1
  216. package/dist/sessions/handlers/list.query.js +2 -1
  217. package/dist/sessions/handlers/revoke-all-for-user.write.d.ts +1 -1
  218. package/dist/sessions/handlers/revoke-all-others.write.d.ts +1 -1
  219. package/dist/sessions/handlers/revoke.write.d.ts +1 -1
  220. package/dist/shared/attachment-file-name.d.ts +3 -0
  221. package/dist/shared/attachment-file-name.js +35 -0
  222. package/dist/shared/chunked-entity-migration.d.ts +1 -0
  223. package/dist/shared/chunked-entity-migration.js +1 -1
  224. package/dist/shared/index.d.ts +3 -0
  225. package/dist/shared/index.js +3 -0
  226. package/dist/shared/is-tenant-db.js +1 -1
  227. package/dist/shared/mail-template-body.d.ts +7 -0
  228. package/dist/shared/mail-template-body.js +27 -0
  229. package/dist/shared/sharp-input-limits.d.ts +6 -0
  230. package/dist/shared/sharp-input-limits.js +22 -0
  231. package/dist/shared/signup-handover.js +2 -2
  232. package/dist/subscription-stripe/plugin-methods.js +18 -8
  233. package/dist/subscription-stripe/verify-webhook.d.ts +1 -1
  234. package/dist/tags/handlers/assign-tag.write.js +3 -1
  235. package/dist/tags/web/tag-chip.js +2 -0
  236. package/dist/template-resolver/api.d.ts +30 -2
  237. package/dist/template-resolver/api.js +42 -6
  238. package/dist/template-resolver/compile-document-body.d.ts +12 -0
  239. package/dist/template-resolver/compile-document-body.js +205 -0
  240. package/dist/template-resolver/constants.d.ts +13 -4
  241. package/dist/template-resolver/constants.js +32 -10
  242. package/dist/template-resolver/document-sanitizer.d.ts +32 -0
  243. package/dist/template-resolver/document-sanitizer.js +201 -0
  244. package/dist/template-resolver/document-schema.d.ts +21 -0
  245. package/dist/template-resolver/document-schema.js +316 -0
  246. package/dist/template-resolver/feature.d.ts +20 -0
  247. package/dist/template-resolver/feature.js +53 -6
  248. package/dist/template-resolver/handlers/bundle-import.d.ts +20 -0
  249. package/dist/template-resolver/handlers/bundle-import.js +147 -0
  250. package/dist/template-resolver/handlers/collection-set.write.d.ts +1 -1
  251. package/dist/template-resolver/handlers/collection-set.write.js +25 -2
  252. package/dist/template-resolver/handlers/copy-locale.write.d.ts +19 -0
  253. package/dist/template-resolver/handlers/copy-locale.write.js +134 -0
  254. package/dist/template-resolver/handlers/diff-to-system.query.d.ts +22 -0
  255. package/dist/template-resolver/handlers/diff-to-system.query.js +30 -0
  256. package/dist/template-resolver/handlers/discard-draft.write.d.ts +13 -0
  257. package/dist/template-resolver/handlers/discard-draft.write.js +37 -0
  258. package/dist/template-resolver/handlers/export-bundle.query.d.ts +35 -0
  259. package/dist/template-resolver/handlers/export-bundle.query.js +118 -0
  260. package/dist/template-resolver/handlers/find-by-id.query.d.ts +2 -0
  261. package/dist/template-resolver/handlers/find-by-id.query.js +9 -6
  262. package/dist/template-resolver/handlers/import-bundle-system.write.d.ts +39 -0
  263. package/dist/template-resolver/handlers/import-bundle-system.write.js +36 -0
  264. package/dist/template-resolver/handlers/import-bundle.write.d.ts +40 -0
  265. package/dist/template-resolver/handlers/import-bundle.write.js +19 -0
  266. package/dist/template-resolver/handlers/layout-source.query.d.ts +31 -0
  267. package/dist/template-resolver/handlers/layout-source.query.js +87 -0
  268. package/dist/template-resolver/handlers/list.query.d.ts +4 -1
  269. package/dist/template-resolver/handlers/list.query.js +9 -8
  270. package/dist/template-resolver/handlers/override-diff.d.ts +20 -0
  271. package/dist/template-resolver/handlers/override-diff.js +41 -0
  272. package/dist/template-resolver/handlers/overview.query.d.ts +65 -0
  273. package/dist/template-resolver/handlers/overview.query.js +205 -0
  274. package/dist/template-resolver/handlers/preview.query.d.ts +12 -0
  275. package/dist/template-resolver/handlers/preview.query.js +24 -0
  276. package/dist/template-resolver/handlers/reset-to-system.write.d.ts +8 -0
  277. package/dist/template-resolver/handlers/reset-to-system.write.js +50 -0
  278. package/dist/template-resolver/handlers/resource-link-pdf.write.d.ts +8 -0
  279. package/dist/template-resolver/handlers/resource-link-pdf.write.js +32 -0
  280. package/dist/template-resolver/handlers/resource-remove.write.d.ts +9 -0
  281. package/dist/template-resolver/handlers/resource-remove.write.js +44 -0
  282. package/dist/template-resolver/handlers/resource-shared.d.ts +9 -0
  283. package/dist/template-resolver/handlers/resource-shared.js +14 -0
  284. package/dist/template-resolver/handlers/resource-upload.write.d.ts +13 -0
  285. package/dist/template-resolver/handlers/resource-upload.write.js +98 -0
  286. package/dist/template-resolver/handlers/send-test.write.d.ts +13 -0
  287. package/dist/template-resolver/handlers/send-test.write.js +108 -0
  288. package/dist/template-resolver/handlers/set.write.d.ts +5 -2
  289. package/dist/template-resolver/handlers/set.write.js +25 -3
  290. package/dist/template-resolver/handlers/shared.d.ts +9 -5
  291. package/dist/template-resolver/handlers/shared.js +6 -2
  292. package/dist/template-resolver/handlers/template-gates.d.ts +36 -0
  293. package/dist/template-resolver/handlers/template-gates.js +142 -0
  294. package/dist/template-resolver/handlers/template-write.d.ts +45 -0
  295. package/dist/template-resolver/handlers/template-write.js +141 -0
  296. package/dist/template-resolver/handlers/tenant-overrides.query.d.ts +49 -0
  297. package/dist/template-resolver/handlers/tenant-overrides.query.js +112 -0
  298. package/dist/template-resolver/handlers/toggle-status.write.d.ts +27 -2
  299. package/dist/template-resolver/handlers/toggle-status.write.js +47 -15
  300. package/dist/template-resolver/handlers/upsert-system.write.d.ts +5 -8
  301. package/dist/template-resolver/handlers/upsert-system.write.js +14 -59
  302. package/dist/template-resolver/handlers/upsert-tenant.write.d.ts +5 -8
  303. package/dist/template-resolver/handlers/upsert-tenant.write.js +11 -62
  304. package/dist/template-resolver/handlers/usage.query.d.ts +17 -0
  305. package/dist/template-resolver/handlers/usage.query.js +24 -0
  306. package/dist/template-resolver/handlers/validate.query.d.ts +74 -0
  307. package/dist/template-resolver/handlers/validate.query.js +80 -0
  308. package/dist/template-resolver/index.d.ts +19 -1
  309. package/dist/template-resolver/index.js +17 -1
  310. package/dist/template-resolver/layout-appearance.d.ts +10 -0
  311. package/dist/template-resolver/layout-appearance.js +26 -0
  312. package/dist/template-resolver/layout-regions.d.ts +23 -0
  313. package/dist/template-resolver/layout-regions.js +125 -0
  314. package/dist/template-resolver/linked-resources.d.ts +17 -0
  315. package/dist/template-resolver/linked-resources.js +75 -0
  316. package/dist/template-resolver/pdf-constants.d.ts +7 -0
  317. package/dist/template-resolver/pdf-constants.js +8 -0
  318. package/dist/template-resolver/preview-display-html.d.ts +7 -0
  319. package/dist/template-resolver/preview-display-html.js +27 -0
  320. package/dist/template-resolver/print-document.d.ts +1 -0
  321. package/dist/template-resolver/print-document.js +55 -0
  322. package/dist/template-resolver/qualified-names.d.ts +34 -0
  323. package/dist/template-resolver/qualified-names.js +34 -0
  324. package/dist/template-resolver/record-mapping.d.ts +2 -0
  325. package/dist/template-resolver/record-mapping.js +21 -0
  326. package/dist/template-resolver/resource-image.d.ts +15 -0
  327. package/dist/template-resolver/resource-image.js +34 -0
  328. package/dist/template-resolver/seeding.d.ts +14 -1
  329. package/dist/template-resolver/seeding.js +125 -18
  330. package/dist/template-resolver/store-template-resource.d.ts +64 -0
  331. package/dist/template-resolver/store-template-resource.js +264 -0
  332. package/dist/template-resolver/table.d.ts +150 -8
  333. package/dist/template-resolver/table.js +20 -2
  334. package/dist/template-resolver/template-bundle.d.ts +36 -0
  335. package/dist/template-resolver/template-bundle.js +60 -0
  336. package/dist/template-resolver/template-diff.d.ts +7 -0
  337. package/dist/template-resolver/template-diff.js +68 -0
  338. package/dist/template-resolver/template-draft.d.ts +51 -0
  339. package/dist/template-resolver/template-draft.js +72 -0
  340. package/dist/template-resolver/template-meta.d.ts +85 -0
  341. package/dist/template-resolver/template-meta.js +145 -0
  342. package/dist/template-resolver/template-preview.d.ts +103 -0
  343. package/dist/template-resolver/template-preview.js +418 -0
  344. package/dist/template-resolver/template-resources.d.ts +19 -0
  345. package/dist/template-resolver/template-resources.js +73 -0
  346. package/dist/template-resolver/template-usage.d.ts +16 -0
  347. package/dist/template-resolver/template-usage.js +35 -0
  348. package/dist/template-resolver/template-validation.d.ts +22 -0
  349. package/dist/template-resolver/template-validation.js +173 -0
  350. package/dist/template-resolver/testing.js +5 -5
  351. package/dist/template-resolver/user-content-table.d.ts +14 -8
  352. package/dist/template-resolver/web/client-plugin.d.ts +1 -0
  353. package/dist/template-resolver/web/client-plugin.js +12 -7
  354. package/dist/template-resolver/web/document-editor-extensions.d.ts +18 -0
  355. package/dist/template-resolver/web/document-editor-extensions.js +145 -0
  356. package/dist/template-resolver/web/document-editor.d.ts +4 -0
  357. package/dist/template-resolver/web/document-editor.js +17 -0
  358. package/dist/template-resolver/web/document-tiptap-editor.d.ts +3 -0
  359. package/dist/template-resolver/web/document-tiptap-editor.js +492 -0
  360. package/dist/template-resolver/web/document-toolbar-blocks.d.ts +41 -0
  361. package/dist/template-resolver/web/document-toolbar-blocks.js +19 -0
  362. package/dist/template-resolver/web/editor-handle.d.ts +3 -0
  363. package/dist/template-resolver/web/editor-handle.js +24 -0
  364. package/dist/template-resolver/web/i18n.js +91 -0
  365. package/dist/template-resolver/web/index.d.ts +5 -0
  366. package/dist/template-resolver/web/index.js +5 -0
  367. package/dist/template-resolver/web/placeholder-line-editor-lazy.d.ts +4 -0
  368. package/dist/template-resolver/web/placeholder-line-editor-lazy.js +16 -0
  369. package/dist/template-resolver/web/placeholder-line-editor.d.ts +17 -0
  370. package/dist/template-resolver/web/placeholder-line-editor.js +94 -0
  371. package/dist/template-resolver/web/placeholder-text.d.ts +4 -0
  372. package/dist/template-resolver/web/placeholder-text.js +34 -0
  373. package/dist/template-resolver/web/use-stable-by-key.d.ts +1 -0
  374. package/dist/template-resolver/web/use-stable-by-key.js +13 -0
  375. package/dist/tenant/handlers/add-member.write.d.ts +1 -1
  376. package/dist/tenant/handlers/cancel-invitation.write.d.ts +1 -1
  377. package/dist/tenant/handlers/create.write.d.ts +1 -1
  378. package/dist/tenant/handlers/remove-member.write.d.ts +1 -1
  379. package/dist/tenant/handlers/team-list.query.js +3 -2
  380. package/dist/tenant/handlers/toggle-enabled.write.d.ts +2 -2
  381. package/dist/tenant/handlers/update-member-roles.write.d.ts +1 -1
  382. package/dist/tenant/handlers/update.write.d.ts +1 -1
  383. package/dist/tenant/seeding.js +31 -6
  384. package/dist/tenant-handover/handlers/claim.write.d.ts +1 -1
  385. package/dist/tenant-lifecycle/handlers/cancel-destruction.write.d.ts +2 -2
  386. package/dist/tenant-lifecycle/handlers/cancel-destruction.write.js +2 -1
  387. package/dist/tenant-lifecycle/handlers/request-destruction.write.d.ts +1 -1
  388. package/dist/tier-engine/feature.js +9 -3
  389. package/dist/tier-engine/handlers/set-tenant-tier.write.d.ts +1 -1
  390. package/dist/user/db/queries/stream-tenant-backfill.js +4 -4
  391. package/dist/user/handlers/create.write.d.ts +1 -1
  392. package/dist/user/handlers/detail.query.js +2 -1
  393. package/dist/user/handlers/update.write.d.ts +1 -1
  394. package/dist/user/resolve-display-names.js +5 -9
  395. package/dist/user/seeding.js +20 -1
  396. package/dist/user-data-rights/db/queries/forget-cleanup.d.ts +2 -2
  397. package/dist/user-data-rights/email-templates.d.ts +1 -29
  398. package/dist/user-data-rights/email-templates.js +5 -106
  399. package/dist/user-data-rights/feature.js +53 -35
  400. package/dist/user-data-rights/handlers/cancel-deletion.write.d.ts +2 -2
  401. package/dist/user-data-rights/handlers/cancel-deletion.write.js +2 -1
  402. package/dist/user-data-rights/handlers/confirm-deletion-by-token.write.d.ts +1 -1
  403. package/dist/user-data-rights/handlers/lift-restriction.write.d.ts +1 -1
  404. package/dist/user-data-rights/handlers/request-deletion-by-email.write.d.ts +1 -1
  405. package/dist/user-data-rights/handlers/request-deletion.write.d.ts +1 -1
  406. package/dist/user-data-rights/handlers/request-deletion.write.js +5 -7
  407. package/dist/user-data-rights/handlers/request-export.write.d.ts +1 -1
  408. package/dist/user-data-rights/handlers/restrict-account.write.d.ts +1 -1
  409. package/dist/user-data-rights/handlers/run-forget-cleanup.write.d.ts +1 -1
  410. package/dist/user-data-rights/lib/default-mailers.d.ts +15 -7
  411. package/dist/user-data-rights/lib/default-mailers.js +100 -48
  412. package/dist/user-data-rights/lib/update-user-lifecycle.js +1 -1
  413. package/dist/user-data-rights/mail-notifications.d.ts +13 -0
  414. package/dist/user-data-rights/mail-notifications.js +118 -0
  415. package/dist/user-data-rights/web/privacy-center-screen.js +2 -1
  416. package/dist/user-profile/handlers/change-email.write.d.ts +1 -1
  417. package/dist/user-profile/web/profile-screen.js +2 -1
  418. package/dist/waitlist/feature.js +10 -0
  419. package/dist/waitlist/handlers/invite.write.d.ts +1 -1
  420. package/dist/waitlist/handlers/reject.write.d.ts +1 -1
  421. package/dist/waitlist/handlers/submit.write.d.ts +1 -1
  422. package/dist/waitlist/handlers/submit.write.js +3 -4
  423. package/dist/waitlist/mail.d.ts +19 -6
  424. package/dist/waitlist/mail.js +50 -14
  425. package/dist/waitlist/options.js +1 -1
  426. package/dist/workflow-runner/event-trigger.js +2 -2
  427. package/dist/workflow-runner/handlers/resume-run.write.js +7 -2
  428. package/package.json +37 -17
  429. package/src/admin-shell/changes.json +6 -0
  430. package/src/audit/changes.json +6 -0
  431. package/src/auth-email-password/changes.json +51 -0
  432. package/src/billing-foundation/changes.json +43 -0
  433. package/src/cap-counter/changes.json +6 -0
  434. package/src/channel-email/changes.json +19 -0
  435. package/src/config/changes.json +6 -0
  436. package/src/crypto-shredding/changes.json +6 -0
  437. package/src/custom-fields/changes.json +6 -0
  438. package/src/data-retention/changes.json +6 -0
  439. package/src/delivery/changes.json +66 -0
  440. package/src/file-foundation/changes.json +6 -0
  441. package/src/files-tenant-data/changes.json +6 -0
  442. package/src/inbound-mail-foundation/changes.json +6 -0
  443. package/src/jobs/changes.json +19 -0
  444. package/src/ledger/changes.json +7 -0
  445. package/src/managed-pages/changes.json +6 -0
  446. package/src/renderer-foundation/changes.json +39 -0
  447. package/src/renderer-pdf/changes.json +12 -0
  448. package/src/secrets/changes.json +6 -0
  449. package/src/shared/changes.json +6 -0
  450. package/src/subscription-stripe/changes.json +6 -0
  451. package/src/template-resolver/changes.json +186 -0
  452. package/src/tier-engine/changes.json +6 -0
  453. package/src/user/changes.json +6 -0
  454. package/src/user-data-rights/changes.json +13 -0
  455. package/src/user-profile/changes.json +1 -1
  456. package/src/waitlist/changes.json +7 -0
  457. package/src/workflow-runner/changes.json +6 -0
  458. package/dist/renderer-simple/feature.d.ts +0 -10
  459. package/dist/renderer-simple/feature.js +0 -42
  460. package/dist/renderer-simple/index.d.ts +0 -3
  461. package/dist/renderer-simple/index.js +0 -2
  462. package/dist/renderer-simple/mail-blocks.d.ts +0 -21
  463. package/dist/renderer-simple/mail-blocks.js +0 -107
  464. package/dist/renderer-simple/resolve-variables.d.ts +0 -7
  465. package/dist/renderer-simple/resolve-variables.js +0 -47
  466. package/dist/renderer-simple/simple-renderer.d.ts +0 -24
  467. package/dist/renderer-simple/simple-renderer.js +0 -200
  468. package/src/renderer-simple/changes.json +0 -27
@@ -1,65 +1,94 @@
1
- // Default send*Email-Callbacks fuer die GDPR-Notifications, backed by einem
2
- // mail-transport (mail-foundation). Damit muss eine App keinen Callback-Code
3
- // schreiben: sie mountet mail-foundation + einen mail-transport-* und setzt
4
- // fuer Export-Mails appExportDownloadUrl — fertig. Uebergibt sie eigene
5
- // send*Email-Opts, greifen diese Defaults nicht (Opt-Override im feature.ts).
1
+ // Default send*Email callbacks for the GDPR notifications. The app writes no
2
+ // callback code: it mounts delivery + channel-email (+ the template stack) and
3
+ // sets appExportDownloadUrl for export mails. Own send*Email options win over
4
+ // these defaults (opt-override in feature.ts).
6
5
  //
7
- // Jeder Callback rendert das Template (email-templates.ts) und versendet ueber
8
- // den per-Tenant aufgeloesten EmailTransport. `resolveTransport` kommt im Job-
9
- // Lane aus makeTenantMailTransportResolver, im Request-Lane direkt aus
10
- // createTransportForTenant(ctx, ...).
6
+ // Export-ready/-failed and deletion-requested go through ctx.notify addressed
7
+ // to the user, so delivery resolves the address and the attempt row carries
8
+ // the recipientId the forget path erases. Deletion-executed cannot: the user
9
+ // is gone by then, and an attempt row written after the erasure would be new
10
+ // personal data. It renders the seeded template and sends over the tenant's
11
+ // mail transport, with no delivery log.
11
12
  import { MAIL_TRANSPORT_EXTENSION } from "@cosmicdrift/kumiko-bundled-features/mail-foundation";
12
- import { hasMailTranslations } from "@cosmicdrift/kumiko-framework/i18n";
13
- import { normalizeGdprMailLocale, renderDeletionExecutedEmail, renderDeletionRequestedEmail, renderExportFailedEmail, renderExportReadyEmail, } from "../email-templates.js";
14
- // mail-foundation ist eine Soft-Dep von user-data-rights. Die Default-Mailer
15
- // greifen nur wenn mindestens ein mail-transport-* registriert ist — sonst
16
- // kann ohnehin nichts versendet werden und die App bleibt beim bisherigen
17
- // "kein Callback → keine Email"-Verhalten.
13
+ import { hasMailTranslations, mailT } from "@cosmicdrift/kumiko-framework/i18n";
14
+ import { DELIVERY_CHANNEL_EXTENSION } from "../../delivery/index.js";
15
+ import { collectRendererPlugins, createRendererFoundationApi, } from "../../renderer-foundation/index.js";
16
+ import { formatGdprMailTimestamp, normalizeGdprMailLocale, } from "../email-templates.js";
17
+ import { GdprMailNotificationTypes, gdprMailTemplateLocale } from "../mail-notifications.js";
18
+ // The notify-based defaults need the delivery pipeline with an email channel.
19
+ export function isGdprMailDeliveryAvailable(registry) {
20
+ return registry
21
+ .getExtensionUsages(DELIVERY_CHANNEL_EXTENSION)
22
+ .some((usage) => usage.entityName === "email");
23
+ }
18
24
  export function isMailTransportAvailable(registry) {
19
25
  return registry.getExtensionUsages(MAIL_TRANSPORT_EXTENSION).length > 0;
20
26
  }
27
+ export function isMailRendererAvailable(registry) {
28
+ return collectRendererPlugins(registry).some((plugin) => plugin.kinds.includes("mail"));
29
+ }
21
30
  // Per-recipient locale wins (user.locale); mailDefaults.locale is the fallback
22
- // for unknown/unsupported user.locale values; the template itself defaults to en.
23
- function localeFor(userLocale, defaults) {
31
+ // for unknown/unsupported user.locale values; a locale without a template for
32
+ // this notification falls back to en.
33
+ function mailLocaleFor(notificationType, userLocale, defaults) {
24
34
  const user = normalizeGdprMailLocale(userLocale);
25
- if (user !== undefined && hasMailTranslations(user))
26
- return user;
27
- return defaults.locale;
35
+ const preferred = user !== undefined && hasMailTranslations(user) ? user : defaults.locale;
36
+ return gdprMailTemplateLocale(notificationType, preferred ?? "en");
37
+ }
38
+ function appNameFor(locale, defaults) {
39
+ return defaults.appName ?? mailT(locale, "gdpr.mail.appNameDefault");
28
40
  }
29
- export function makeDefaultExportReadyEmail(resolveTransport, defaults = {}) {
41
+ // Delivery failures come back as results, not throws; the callers' best-effort
42
+ // handling only sees them if they throw.
43
+ async function notifyImmediately(notify, notificationType, options) {
44
+ const result = await notify(notificationType, { ...options, immediate: true });
45
+ const failed = result.deliveries.find((delivery) => delivery.status === "failed");
46
+ if (failed) {
47
+ throw new Error(`${notificationType} delivery failed: ${failed.error ?? "unknown"}`);
48
+ }
49
+ }
50
+ export function makeDefaultExportReadyEmail(notifyFor, defaults = {}) {
30
51
  return async (args) => {
31
- const transport = await resolveTransport(args.tenantId);
32
- const { subject, html, text } = renderExportReadyEmail({
33
- downloadUrl: args.downloadUrl,
34
- expiresAt: args.expiresAt,
35
- locale: localeFor(args.userLocale, defaults),
36
- appName: defaults.appName,
52
+ const type = GdprMailNotificationTypes.exportReady;
53
+ const locale = mailLocaleFor(type, args.userLocale, defaults);
54
+ // immediate: the plain magic-link token must not land in a delivery job payload.
55
+ await notifyImmediately(notifyFor(args.tenantId), type, {
56
+ to: args.userId,
57
+ locale,
58
+ data: {
59
+ appName: appNameFor(locale, defaults),
60
+ actionUrl: args.downloadUrl,
61
+ validUntil: formatGdprMailTimestamp(args.expiresAt),
62
+ },
37
63
  });
38
- await transport.send({ to: args.userEmail, subject, html, text });
39
64
  };
40
65
  }
41
- export function makeDefaultExportFailedEmail(resolveTransport, defaults = {}) {
66
+ export function makeDefaultExportFailedEmail(notifyFor, defaults = {}) {
42
67
  return async (args) => {
43
- const transport = await resolveTransport(args.tenantId);
44
- const { subject, html, text } = renderExportFailedEmail({
45
- locale: localeFor(args.userLocale, defaults),
46
- appName: defaults.appName,
68
+ const type = GdprMailNotificationTypes.exportFailed;
69
+ const locale = mailLocaleFor(type, args.userLocale, defaults);
70
+ await notifyImmediately(notifyFor(args.tenantId), type, {
71
+ to: args.userId,
72
+ locale,
73
+ data: { appName: appNameFor(locale, defaults) },
47
74
  });
48
- await transport.send({ to: args.userEmail, subject, html, text });
49
75
  };
50
76
  }
51
- export function makeDefaultDeletionRequestedEmail(resolveTransport, defaults = {}) {
77
+ export function makeDefaultDeletionRequestedEmail(notify, defaults = {}) {
52
78
  return async (args) => {
53
- const transport = await resolveTransport(args.tenantId);
54
- const { subject, html, text } = renderDeletionRequestedEmail({
55
- gracePeriodEnd: args.gracePeriodEnd,
56
- locale: localeFor(args.userLocale, defaults),
57
- appName: defaults.appName,
79
+ const type = GdprMailNotificationTypes.deletionRequested;
80
+ const locale = mailLocaleFor(type, args.userLocale, defaults);
81
+ await notify(type, {
82
+ to: args.userId,
83
+ locale,
84
+ data: {
85
+ appName: appNameFor(locale, defaults),
86
+ deletionDate: formatGdprMailTimestamp(args.gracePeriodEnd),
87
+ },
58
88
  });
59
- await transport.send({ to: args.userEmail, subject, html, text });
60
89
  };
61
90
  }
62
- export function makeDefaultDeletionExecutedEmail(resolveTransport, defaults = {}) {
91
+ export function makeDefaultDeletionExecutedEmail(deps, defaults = {}) {
63
92
  return async (args) => {
64
93
  // Der User ist global, der Mail-Transport per-Tenant — wir senden ueber den
65
94
  // Transport des ersten Memberships. Orphan-User (0 Memberships) liefert
@@ -69,12 +98,35 @@ export function makeDefaultDeletionExecutedEmail(resolveTransport, defaults = {}
69
98
  // skip: orphan user has no tenant whose transport could send the mail
70
99
  return;
71
100
  }
72
- const transport = await resolveTransport(tenantId);
73
- const { subject, html, text } = renderDeletionExecutedEmail({
74
- executedAt: args.executedAt,
75
- locale: localeFor(args.userLocale, defaults),
76
- appName: defaults.appName,
101
+ const type = GdprMailNotificationTypes.deletionExecuted;
102
+ const locale = mailLocaleFor(type, args.userLocale, defaults);
103
+ const plugin = createRendererFoundationApi(collectRendererPlugins(deps.registry)).createRendererForTenant({ tenantId, kind: "mail" });
104
+ const config = deps.configFor(tenantId);
105
+ const rendered = await plugin.render({
106
+ kind: "mail",
107
+ payload: {
108
+ slug: type,
109
+ locale,
110
+ variables: {
111
+ appName: appNameFor(locale, defaults),
112
+ executedAt: formatGdprMailTimestamp(args.executedAt),
113
+ },
114
+ },
115
+ }, {
116
+ db: deps.db,
117
+ registry: deps.registry,
118
+ tenantId,
119
+ ...(config !== undefined && { config }),
120
+ });
121
+ if (rendered.kind !== "mail") {
122
+ throw new Error(`deletion-executed mail: renderer answered with kind "${rendered.kind}"`);
123
+ }
124
+ const transport = await deps.resolveTransport(tenantId);
125
+ await transport.send({
126
+ to: args.userEmail,
127
+ subject: rendered.subject,
128
+ html: rendered.html,
129
+ text: rendered.text,
77
130
  });
78
- await transport.send({ to: args.userEmail, subject, html, text });
79
131
  };
80
132
  }
@@ -51,7 +51,7 @@ export async function updateUserLifecycle(conn, userId, changes, options) {
51
51
  });
52
52
  }
53
53
  export async function backfillUserLifecycleEvents(conn) {
54
- const rows = (await selectMany(conn, userTable, {}));
54
+ const rows = await selectMany(conn, userTable, {});
55
55
  let backfilled = 0;
56
56
  const failed = [];
57
57
  for (const row of rows) {
@@ -0,0 +1,13 @@
1
+ import { type FeatureRegistrar, type NotificationLocalizedTemplate, type TemplateVariables } from "@cosmicdrift/kumiko-framework/engine";
2
+ declare const ALL_GDPR_MAIL_KINDS: readonly ["exportReady", "exportFailed", "deletionRequested", "deletionExecuted"];
3
+ export type GdprMailKind = (typeof ALL_GDPR_MAIL_KINDS)[number];
4
+ export declare const GDPR_MAIL_KINDS: Readonly<Record<GdprMailKind, {
5
+ readonly name: string;
6
+ readonly translationKey: string;
7
+ }>>;
8
+ export declare const GdprMailNotificationTypes: Readonly<Record<GdprMailKind, string>>;
9
+ export declare function gdprMailTemplateLocale(notificationType: string, requestedLocale: string): string;
10
+ export declare const GDPR_MAIL_VARIABLES: Readonly<Record<GdprMailKind, TemplateVariables>>;
11
+ export declare function gdprMailLocalizedTemplate(kind: GdprMailKind): () => NotificationLocalizedTemplate;
12
+ export declare function registerGdprMails(r: FeatureRegistrar): void;
13
+ export {};
@@ -0,0 +1,118 @@
1
+ import { QnTypes, qn, templateVariable, } from "@cosmicdrift/kumiko-framework/engine";
2
+ import { hasMailTranslationKey, listMailLocales, mailT, resolveMailLocale, } from "@cosmicdrift/kumiko-framework/i18n";
3
+ import { escapeHtml } from "@cosmicdrift/kumiko-headless";
4
+ import { mailParagraph } from "../shared/index.js";
5
+ import { USER_DATA_RIGHTS_FEATURE } from "./constants.js";
6
+ const ALL_GDPR_MAIL_KINDS = [
7
+ "exportReady",
8
+ "exportFailed",
9
+ "deletionRequested",
10
+ "deletionExecuted",
11
+ ];
12
+ export const GDPR_MAIL_KINDS = {
13
+ exportReady: { name: "export-ready", translationKey: "exportReady" },
14
+ exportFailed: { name: "export-failed", translationKey: "exportFailed" },
15
+ deletionRequested: { name: "deletion-requested", translationKey: "deletionRequested" },
16
+ deletionExecuted: { name: "deletion-executed", translationKey: "deletionExecuted" },
17
+ };
18
+ export const GdprMailNotificationTypes = {
19
+ exportReady: gdprMailType("exportReady"),
20
+ exportFailed: gdprMailType("exportFailed"),
21
+ deletionRequested: gdprMailType("deletionRequested"),
22
+ deletionExecuted: gdprMailType("deletionExecuted"),
23
+ };
24
+ function gdprMailType(kind) {
25
+ return qn(USER_DATA_RIGHTS_FEATURE, QnTypes.notify, GDPR_MAIL_KINDS[kind].name);
26
+ }
27
+ function subjectKey(kind) {
28
+ return `gdpr.mail.${GDPR_MAIL_KINDS[kind].translationKey}.subject`;
29
+ }
30
+ const SUBJECT_KEY_BY_TYPE = new Map(ALL_GDPR_MAIL_KINDS.map((kind) => [GdprMailNotificationTypes[kind], subjectKey(kind)]));
31
+ // A registered locale whose bundle lacks the subject key has no template (see
32
+ // gdprMailLocalizedTemplate); the renderer has no locale fallback, so the
33
+ // sender must pick a locale that has one or the mail would not go out at all.
34
+ export function gdprMailTemplateLocale(notificationType, requestedLocale) {
35
+ const locale = resolveMailLocale(requestedLocale);
36
+ const key = SUBJECT_KEY_BY_TYPE.get(notificationType);
37
+ return key !== undefined && hasMailTranslationKey(locale, key) ? locale : "en";
38
+ }
39
+ const appName = () => templateVariable.text({ required: true });
40
+ export const GDPR_MAIL_VARIABLES = {
41
+ exportReady: {
42
+ appName: appName(),
43
+ actionUrl: templateVariable.link({ required: true }),
44
+ validUntil: templateVariable.text({ required: true }),
45
+ },
46
+ exportFailed: { appName: appName() },
47
+ deletionRequested: {
48
+ appName: appName(),
49
+ deletionDate: templateVariable.text({ required: true }),
50
+ },
51
+ deletionExecuted: { appName: appName(), executedAt: templateVariable.text({ required: true }) },
52
+ };
53
+ // Translation placeholder -> template variable per kind.
54
+ const PLACEHOLDER_SLOTS = {
55
+ exportReady: { app: "{appName}", when: "{validUntil}" },
56
+ exportFailed: { app: "{appName}" },
57
+ deletionRequested: { app: "{appName}", when: "{deletionDate}" },
58
+ deletionExecuted: { app: "{appName}", when: "{executedAt}" },
59
+ };
60
+ function paragraph(kind, locale, part) {
61
+ const { translationKey } = GDPR_MAIL_KINDS[kind];
62
+ return mailParagraph(mailT(locale, `gdpr.mail.${translationKey}.${part}`, PLACEHOLDER_SLOTS[kind]));
63
+ }
64
+ function greeting(locale) {
65
+ return mailParagraph(mailT(locale, "gdpr.mail.greeting"));
66
+ }
67
+ function mailBody(kind, locale) {
68
+ switch (kind) {
69
+ case "exportReady":
70
+ return [
71
+ greeting(locale),
72
+ paragraph(kind, locale, "intro"),
73
+ `<p><a data-button href="{{actionUrl}}">${escapeHtml(mailT(locale, "gdpr.mail.exportReady.button"))}</a></p>`,
74
+ paragraph(kind, locale, "expiry"),
75
+ ].join("");
76
+ case "exportFailed":
77
+ return [greeting(locale), paragraph(kind, locale, "intro")].join("");
78
+ case "deletionRequested":
79
+ return [
80
+ greeting(locale),
81
+ paragraph(kind, locale, "intro"),
82
+ paragraph(kind, locale, "cancel"),
83
+ ].join("");
84
+ case "deletionExecuted":
85
+ return [greeting(locale), paragraph(kind, locale, "intro")].join("");
86
+ }
87
+ }
88
+ // Evaluated when the registry is built, after every locale feature has
89
+ // registered its mail translations. English always ships; another locale only
90
+ // gets a template when it has its own subject, so a missing translation never
91
+ // silently becomes an English mail in that locale's slot.
92
+ export function gdprMailLocalizedTemplate(kind) {
93
+ const kindSubjectKey = subjectKey(kind);
94
+ return () => {
95
+ const locales = [
96
+ "en",
97
+ ...listMailLocales().filter((locale) => locale !== "en" && hasMailTranslationKey(locale, kindSubjectKey)),
98
+ ];
99
+ return Object.fromEntries(locales.map((locale) => [
100
+ locale,
101
+ {
102
+ body: mailBody(kind, locale),
103
+ meta: {
104
+ subject: mailT(locale, kindSubjectKey, { app: "{{appName}}" }),
105
+ category: "transactional",
106
+ },
107
+ },
108
+ ]));
109
+ };
110
+ }
111
+ export function registerGdprMails(r) {
112
+ for (const kind of ALL_GDPR_MAIL_KINDS) {
113
+ r.notification(GDPR_MAIL_KINDS[kind].name, {
114
+ variables: GDPR_MAIL_VARIABLES[kind],
115
+ localizedTemplate: gdprMailLocalizedTemplate(kind),
116
+ });
117
+ }
118
+ }
@@ -12,6 +12,7 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
12
12
  // declarative fields/actions instead (feature.ts).
13
13
  import { useDispatcher, usePrimitives, useQuery, useTranslation, } from "@cosmicdrift/kumiko-renderer";
14
14
  import { postWithDownload } from "@cosmicdrift/kumiko-renderer-web";
15
+ import { propertyOf } from "@cosmicdrift/kumiko-types/type-guards";
15
16
  import { useEffect, useState } from "react";
16
17
  import { EXPORT_JOB_STATUS, UserDataRightsHandlers, UserDataRightsQueries, } from "../constants.js";
17
18
  // Export-Job läuft async (worker-Lane-Cron, ~1 Min). Solange er pending/running
@@ -21,7 +22,7 @@ const EXPORT_POLL_MS = 4000;
21
22
  // Dispatcher-Failures tragen i18nKey nur wenn der Handler einen setzt —
22
23
  // Boundary-Read mit generischem Fallback.
23
24
  function failureKey(error) {
24
- const key = error?.i18nKey; // @cast-boundary dispatcher-error
25
+ const key = propertyOf(error, "i18nKey");
25
26
  return typeof key === "string" ? key : "userDataRights.privacyCenter.errors.generic";
26
27
  }
27
28
  // Roher ISO-Instant → nur der Datums-Teil ist relevant; reiner String-Slice,
@@ -5,4 +5,4 @@ export declare const changeEmailWrite: import("@cosmicdrift/kumiko-types/define-
5
5
  }, z.core.$strip>, {
6
6
  kind: string;
7
7
  email: string;
8
- }, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap>;
8
+ }, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap, undefined>;
@@ -8,6 +8,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
8
  // (../../user-data-rights/web/privacy-center-screen.tsx), which this file
9
9
  // mirrors.
10
10
  import { useDispatcher, usePrimitives, useTranslation, } from "@cosmicdrift/kumiko-renderer";
11
+ import { propertyOf } from "@cosmicdrift/kumiko-types/type-guards";
11
12
  import { useState } from "react";
12
13
  import { AuthHandlers } from "../../auth-email-password/constants.js";
13
14
  import { requestEmailVerification } from "../../auth-email-password/web/index.js";
@@ -15,7 +16,7 @@ import { UserProfileHandlers } from "../constants.js";
15
16
  // Dispatcher failures carry an i18nKey only when the handler sets one —
16
17
  // boundary read with a generic fallback.
17
18
  function failureKey(error) {
18
- const key = error?.i18nKey; // @cast-boundary dispatcher-error
19
+ const key = propertyOf(error, "i18nKey");
19
20
  return typeof key === "string" ? key : "profile.errors.generic";
20
21
  }
21
22
  function StatusBanner({ status }) {
@@ -7,6 +7,7 @@ import { rejectHandler } from "./handlers/reject.write.js";
7
7
  import { createSubmitHandler } from "./handlers/submit.write.js";
8
8
  import { WAITLIST_I18N } from "./i18n.js";
9
9
  import { adminAccess } from "./lib.js";
10
+ import { WAITLIST_ADMIN_NOTICE_RECORD, WAITLIST_ADMIN_NOTICE_VARIABLES, WAITLIST_CONFIRMATION_VARIABLES, waitlistAdminNoticeTemplate, waitlistConfirmationTemplate, } from "./mail.js";
10
11
  import { waitlistListScreen } from "./screens.js";
11
12
  import { waitlistEntryDeleteHook, waitlistEntryExportHook } from "./user-data-hooks.js";
12
13
  export function createWaitlistFeature(opts = {}) {
@@ -16,6 +17,15 @@ export function createWaitlistFeature(opts = {}) {
16
17
  r.systemScope();
17
18
  r.requires("tenant", "auth-email-password", "user-data-rights");
18
19
  r.translations({ keys: WAITLIST_I18N });
20
+ r.notification("confirmation", {
21
+ variables: WAITLIST_CONFIRMATION_VARIABLES,
22
+ localizedTemplate: waitlistConfirmationTemplate,
23
+ });
24
+ r.notification("admin-notice", {
25
+ variables: WAITLIST_ADMIN_NOTICE_VARIABLES,
26
+ record: WAITLIST_ADMIN_NOTICE_RECORD,
27
+ localizedTemplate: waitlistAdminNoticeTemplate,
28
+ });
19
29
  r.entity("waitlistEntry", waitlistEntryEntity);
20
30
  r.writeHandler(createSubmitHandler(opts));
21
31
  r.writeHandler(createInviteHandler(opts.invite));
@@ -6,4 +6,4 @@ export type WaitlistInviteData = {
6
6
  };
7
7
  export declare function createInviteHandler(invite?: WaitlistInviteOptions): import("@cosmicdrift/kumiko-types/define-handler").WriteHandlerDefinition<"invite", import("zod").ZodObject<{
8
8
  id: import("zod").ZodUUID;
9
- }, import("zod/v4/core").$strict>, WaitlistInviteData, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap>;
9
+ }, import("zod/v4/core").$strict>, WaitlistInviteData, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap, undefined>;
@@ -4,4 +4,4 @@ export type WaitlistRejectData = {
4
4
  };
5
5
  export declare const rejectHandler: import("@cosmicdrift/kumiko-types/define-handler").WriteHandlerDefinition<"reject", import("zod").ZodObject<{
6
6
  id: import("zod").ZodUUID;
7
- }, import("zod/v4/core").$strict>, WaitlistRejectData, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap>;
7
+ }, import("zod/v4/core").$strict>, WaitlistRejectData, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap, undefined>;
@@ -10,4 +10,4 @@ export declare function createSubmitHandler(opts: WaitlistOptions): import("@cos
10
10
  message: import("zod").ZodOptional<import("zod").ZodString>;
11
11
  locale: import("zod").ZodPipe<import("zod").ZodString, import("zod").ZodTransform<string, string>>;
12
12
  website: import("zod").ZodOptional<import("zod").ZodString>;
13
- }, import("zod/v4/core").$strict>, WaitlistSubmitData, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap>;
13
+ }, import("zod/v4/core").$strict>, WaitlistSubmitData, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap, undefined>;
@@ -4,7 +4,7 @@ import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
4
4
  import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
5
5
  import { WAITLIST_NOTIFICATION_TYPES, WAITLIST_STATUS } from "../constants.js";
6
6
  import { normalizeEmail, platformActor, waitlistDb, waitlistExecutor } from "../lib.js";
7
- import { renderWaitlistAdminNoticeEmail, renderWaitlistConfirmationEmail, resolveWaitlistAdminMailLocale, resolveWaitlistMailLocale, } from "../mail.js";
7
+ import { resolveWaitlistAdminMailLocale, resolveWaitlistMailLocale, waitlistAdminNoticeVariables, waitlistConfirmationVariables, } from "../mail.js";
8
8
  import { DEFAULT_SUBMIT_EMAIL_RATE_LIMITS, DEFAULT_SUBMIT_RATE_LIMIT, } from "../options.js";
9
9
  import { WaitlistSubmitSchema } from "../payloads.js";
10
10
  // pg_advisory_xact_lock namespace (int4): 'wlst' as ASCII, disjoint from the
@@ -81,7 +81,7 @@ export function createSubmitHandler(opts) {
81
81
  return created;
82
82
  await sendBestEffort(ctx, "confirmation", (notify) => notify(WAITLIST_NOTIFICATION_TYPES.confirmation, {
83
83
  route: { email },
84
- data: renderWaitlistConfirmationEmail({
84
+ data: waitlistConfirmationVariables({
85
85
  locale: payload.locale,
86
86
  appName: opts.appName,
87
87
  }),
@@ -95,12 +95,11 @@ export function createSubmitHandler(opts) {
95
95
  return;
96
96
  await notify(WAITLIST_NOTIFICATION_TYPES.adminNotice, {
97
97
  route: { email: adminRecipient },
98
- data: renderWaitlistAdminNoticeEmail({
98
+ data: waitlistAdminNoticeVariables({
99
99
  name: payload.name,
100
100
  email,
101
101
  company: payload.company,
102
102
  message: payload.message,
103
- adminLocale: ctx.locale,
104
103
  }),
105
104
  priority: "normal",
106
105
  locale: resolveWaitlistAdminMailLocale(ctx.locale),
@@ -1,15 +1,28 @@
1
- import type { AuthMailContent } from "../auth-email-password/index.js";
1
+ import { type NotificationLocalizedTemplate, type NotificationRecordMapping, type TemplateVariables } from "@cosmicdrift/kumiko-framework/engine";
2
2
  export type WaitlistMailLocale = "en" | "de" | "es";
3
3
  export declare function resolveWaitlistMailLocale(locale: string | undefined): WaitlistMailLocale;
4
- export declare function renderWaitlistConfirmationEmail(args: {
4
+ export declare const WAITLIST_CONFIRMATION_VARIABLES: TemplateVariables;
5
+ export declare const WAITLIST_ADMIN_NOTICE_RECORD: NotificationRecordMapping;
6
+ export declare const WAITLIST_ADMIN_NOTICE_VARIABLES: TemplateVariables;
7
+ export declare function waitlistConfirmationVariables(args: {
5
8
  readonly locale: string | undefined;
6
9
  readonly appName?: string | undefined;
7
- }): AuthMailContent;
10
+ }): {
11
+ readonly subject: string;
12
+ readonly intro: string;
13
+ readonly footer: string;
14
+ };
15
+ export declare function waitlistConfirmationTemplate(): NotificationLocalizedTemplate;
8
16
  export declare function resolveWaitlistAdminMailLocale(adminLocale: string | undefined): "en" | "de";
9
- export declare function renderWaitlistAdminNoticeEmail(args: {
17
+ export declare function waitlistAdminNoticeVariables(args: {
10
18
  readonly name: string;
11
19
  readonly email: string;
12
20
  readonly company: string | undefined;
13
21
  readonly message: string | undefined;
14
- readonly adminLocale: string | undefined;
15
- }): AuthMailContent;
22
+ }): {
23
+ readonly name: string;
24
+ readonly details: readonly {
25
+ readonly text: string;
26
+ }[];
27
+ };
28
+ export declare function waitlistAdminNoticeTemplate(): NotificationLocalizedTemplate;
@@ -1,3 +1,5 @@
1
+ import { templateVariable, } from "@cosmicdrift/kumiko-framework/engine";
2
+ import { mailHeading, mailParagraph, mailRepeatedRows } from "../shared/index.js";
1
3
  const CONFIRMATION_STRINGS = {
2
4
  en: {
3
5
  subject: (app) => (app ? `You're on the ${app} waitlist` : "You're on the waitlist"),
@@ -42,32 +44,66 @@ export function resolveWaitlistMailLocale(locale) {
42
44
  const language = languageOf(locale);
43
45
  return isConfirmationLocale(language) ? language : "en";
44
46
  }
47
+ export const WAITLIST_CONFIRMATION_VARIABLES = {
48
+ subject: templateVariable.text({ required: true }),
49
+ intro: templateVariable.text({ required: true }),
50
+ footer: templateVariable.text({ required: true }),
51
+ };
52
+ // Only `name` is a plain entry field; the details rows are composed from several fields.
53
+ export const WAITLIST_ADMIN_NOTICE_RECORD = {
54
+ entity: "waitlistEntry",
55
+ map: { name: "name" },
56
+ };
57
+ export const WAITLIST_ADMIN_NOTICE_VARIABLES = {
58
+ name: templateVariable.text({ required: true }),
59
+ details: templateVariable.list({ text: templateVariable.text({ required: true }) }, { required: true }),
60
+ };
61
+ // The app name is optional, so the sentences that mention it are computed in
62
+ // code and handed over as variables; the template keeps heading and structure.
45
63
  // The submitter's name stays out: the address is unverified, so any text in
46
64
  // this mail could be planted by whoever typed someone else's email.
47
- export function renderWaitlistConfirmationEmail(args) {
65
+ export function waitlistConfirmationVariables(args) {
48
66
  const t = CONFIRMATION_STRINGS[resolveWaitlistMailLocale(args.locale)];
49
67
  return {
50
68
  subject: t.subject(args.appName),
51
- header: t.header,
52
- sections: [{ text: t.intro(args.appName) }],
69
+ intro: t.intro(args.appName),
53
70
  footer: t.footer(args.appName),
54
71
  };
55
72
  }
73
+ export function waitlistConfirmationTemplate() {
74
+ return Object.fromEntries(Object.entries(CONFIRMATION_STRINGS).map(([locale, t]) => [
75
+ locale,
76
+ {
77
+ body: [mailHeading(t.header), mailParagraph("{intro}"), mailParagraph("{footer}")].join(""),
78
+ meta: { subject: "{{subject}}", category: "transactional" },
79
+ },
80
+ ]));
81
+ }
56
82
  // Operator-facing, so the entrant's locale does not apply: en/de, en default.
57
83
  export function resolveWaitlistAdminMailLocale(adminLocale) {
58
84
  return languageOf(adminLocale) === "de" ? "de" : "en";
59
85
  }
60
- export function renderWaitlistAdminNoticeEmail(args) {
61
- const t = ADMIN_NOTICE_STRINGS[resolveWaitlistAdminMailLocale(args.adminLocale)];
62
- const details = [
63
- `${args.name} <${args.email}>`,
64
- ...(args.company ? [args.company] : []),
65
- ...(args.message ? [args.message] : []),
66
- ];
86
+ export function waitlistAdminNoticeVariables(args) {
67
87
  return {
68
- subject: t.subject(args.name),
69
- header: t.header,
70
- sections: [{ text: t.intro }, { text: details.join("\n") }],
71
- footer: t.footer,
88
+ name: args.name,
89
+ details: [
90
+ `${args.name} <${args.email}>`,
91
+ ...(args.company ? [args.company] : []),
92
+ ...(args.message ? [args.message] : []),
93
+ ].map((text) => ({ text })),
72
94
  };
73
95
  }
96
+ export function waitlistAdminNoticeTemplate() {
97
+ return Object.fromEntries(Object.entries(ADMIN_NOTICE_STRINGS).map(([locale, t]) => [
98
+ locale,
99
+ {
100
+ body: [
101
+ mailHeading(t.header),
102
+ mailParagraph(t.intro),
103
+ mailRepeatedRows("details", "text"),
104
+ mailParagraph(t.footer),
105
+ ].join(""),
106
+ meta: { subject: t.subject("{{name}}"), category: "transactional" },
107
+ },
108
+ ]));
109
+ }
@@ -4,5 +4,5 @@ export const DEFAULT_SUBMIT_RATE_LIMIT = {
4
4
  windowSeconds: 10 * 60,
5
5
  };
6
6
  export const DEFAULT_SUBMIT_EMAIL_RATE_LIMITS = [
7
- { per: { payloadField: "email" }, limit: 3, windowSeconds: 24 * 60 * 60 },
7
+ { per: { payloadField: "email" }, limit: 3, windowSeconds: 24 * 60 * 60, normalize: "email" },
8
8
  ];
@@ -8,7 +8,7 @@
8
8
  // wiring uses the unbound pool), so `workflow.run-started` and the rest of
9
9
  // the pipeline are not atomic. A throw from startAndRunWorkflow is recorded
10
10
  // as `workflow.run-failed` and swallowed, so the dispatcher moves on.
11
- import { buildPipelineSteps, createSystemUser, describeWorkflowStepError, getStep, SYSTEM_TENANT_ID, WORKFLOW_AGGREGATE_TYPE, WORKFLOW_RUN_FAILED_TYPE, WorkflowStepError, } from "@cosmicdrift/kumiko-framework/engine";
11
+ import { buildPipelineSteps, createSystemUser, describeWorkflowStepError, getStep, SYSTEM_TENANT_ID, unwrapWorkflowStepError, WORKFLOW_AGGREGATE_TYPE, WORKFLOW_RUN_FAILED_TYPE, WorkflowStepError, } from "@cosmicdrift/kumiko-framework/engine";
12
12
  import { createFallbackLogger } from "@cosmicdrift/kumiko-framework/logging";
13
13
  import { workflowRunAggregateId } from "./aggregate-id.js";
14
14
  import { registerEventWakeup } from "./event-subscriber.js";
@@ -135,7 +135,7 @@ export function registerEventTrigger(r, workflow) {
135
135
  runId,
136
136
  workflowName: workflow.name,
137
137
  stepIndex,
138
- error: String(error),
138
+ error: String(unwrapWorkflowStepError(error)),
139
139
  });
140
140
  const failedPayload = {
141
141
  workflowName: workflow.name,
@@ -30,7 +30,7 @@
30
30
  // resultKey on steps/wait-for-event.ts) — pre-seeded into stepsAcc below so
31
31
  // a subsequent step's resolver can read `ctx.steps[awaits.someKey]`.
32
32
  import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
33
- import { buildPipelineSteps, computeDefinitionFingerprint, describeWorkflowStepError, getStep, runStepList, SYSTEM_ROLE, WORKFLOW_AGGREGATE_TYPE, WORKFLOW_RESUMED_TYPE, WORKFLOW_RETRY_SCHEDULED_TYPE, WORKFLOW_RUN_COMPLETED_TYPE, WORKFLOW_RUN_FAILED_TYPE, WORKFLOW_RUN_STARTED_TYPE, WORKFLOW_WAITING_FOR_EVENT_TYPE, WorkflowStepError, } from "@cosmicdrift/kumiko-framework/engine";
33
+ import { buildPipelineSteps, computeDefinitionFingerprint, describeWorkflowStepError, getStep, runStepList, SYSTEM_ROLE, unwrapWorkflowStepError, WORKFLOW_AGGREGATE_TYPE, WORKFLOW_RESUMED_TYPE, WORKFLOW_RETRY_SCHEDULED_TYPE, WORKFLOW_RUN_COMPLETED_TYPE, WORKFLOW_RUN_FAILED_TYPE, WORKFLOW_RUN_STARTED_TYPE, WORKFLOW_WAITING_FOR_EVENT_TYPE, WorkflowStepError, } from "@cosmicdrift/kumiko-framework/engine";
34
34
  import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
35
35
  import { createFallbackLogger } from "@cosmicdrift/kumiko-framework/logging";
36
36
  import * as z from "zod";
@@ -237,7 +237,12 @@ async function runResumedPipeline(ctx, input) {
237
237
  return { isSuccess: true, data: { outcome: "completed" } };
238
238
  }
239
239
  catch (error) {
240
- log.warn("workflow run failed", { runId, workflowName, stepIndex, error: String(error) });
240
+ log.warn("workflow run failed", {
241
+ runId,
242
+ workflowName,
243
+ stepIndex,
244
+ error: String(unwrapWorkflowStepError(error)),
245
+ });
241
246
  // The input stepIndex is the suspended step; the failure happened at the step the resumed pass reached.
242
247
  const failedPayload = {
243
248
  workflowName,