@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,5 +1,6 @@
1
1
  import { createHmac, timingSafeEqual } from "node:crypto";
2
2
  import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
3
+ import { isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
3
4
  function hmacSign(input, secret) {
4
5
  return createHmac("sha256", secret).update(input).digest("base64url");
5
6
  }
@@ -8,13 +9,12 @@ function hmacSign(input, secret) {
8
9
  // replayed as a challenge token), since both share the same secret and payload shape.
9
10
  export function createHmacTokenCodec(domain, isPayload) {
10
11
  function splitEncodedBody(value) {
11
- if (typeof value !== "object" || value === null)
12
+ if (!isPlainObject(value))
12
13
  return null;
13
- const v = value;
14
- const expiresAtMs = v["expiresAtMs"];
14
+ const expiresAtMs = value["expiresAtMs"];
15
15
  if (typeof expiresAtMs !== "number")
16
16
  return null;
17
- const { expiresAtMs: _drop, ...rest } = v;
17
+ const { expiresAtMs: _drop, ...rest } = value;
18
18
  return isPayload(rest) ? { payload: rest, expiresAtMs } : null;
19
19
  }
20
20
  return {
@@ -1,10 +1,10 @@
1
1
  import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
2
+ import { isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
2
3
  import { createHmacTokenCodec } from "./hmac-token-codec.js";
3
4
  function isPayload(value) {
4
- if (typeof value !== "object" || value === null)
5
+ if (!isPlainObject(value))
5
6
  return false;
6
- const v = value;
7
- return typeof v["userId"] === "string" && typeof v["tenantId"] === "string";
7
+ return typeof value["userId"] === "string" && typeof value["tenantId"] === "string";
8
8
  }
9
9
  // Domain-separated from mfa-preauth-setup (see hmac-token-codec). Single-use is
10
10
  // enforced by the consumer via burnToken (purpose "mfa-challenge"); this codec
@@ -1,10 +1,10 @@
1
1
  import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
2
+ import { isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
2
3
  import { createHmacTokenCodec } from "./hmac-token-codec.js";
3
4
  function isPayload(value) {
4
- if (typeof value !== "object" || value === null)
5
+ if (!isPlainObject(value))
5
6
  return false;
6
- const v = value;
7
- return typeof v["userId"] === "string" && typeof v["tenantId"] === "string";
7
+ return typeof value["userId"] === "string" && typeof value["tenantId"] === "string";
8
8
  }
9
9
  // Domain "mfa-preauth-setup" must never equal the challenge domain: a setup
10
10
  // token has to fail verification as a challenge token and vice versa. The
@@ -11,6 +11,7 @@
11
11
  // generated secret material, not just re-derive it from a lookup.
12
12
  import { createHmac, timingSafeEqual } from "node:crypto";
13
13
  import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
14
+ import { isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
14
15
  function sign(input, secret) {
15
16
  return createHmac("sha256", secret).update(input).digest("base64url");
16
17
  }
@@ -22,15 +23,14 @@ export function signMfaSetupToken(payload, ttlMinutes, secret, now = Temporal.No
22
23
  return { token: `${bodyB64}.${signature}`, expiresAt };
23
24
  }
24
25
  function isEncodedBody(value) {
25
- if (typeof value !== "object" || value === null)
26
+ if (!isPlainObject(value))
26
27
  return false;
27
- const v = value;
28
- return (typeof v["userId"] === "string" &&
29
- typeof v["totpSecretBase32"] === "string" &&
30
- Array.isArray(v["recoveryCodeHashes"]) &&
31
- v["recoveryCodeHashes"].every((h) => typeof h === "string") &&
32
- typeof v["expiresAtMs"] === "number" &&
33
- (v["tenantId"] === undefined || typeof v["tenantId"] === "string"));
28
+ return (typeof value["userId"] === "string" &&
29
+ typeof value["totpSecretBase32"] === "string" &&
30
+ Array.isArray(value["recoveryCodeHashes"]) &&
31
+ value["recoveryCodeHashes"].every((h) => typeof h === "string") &&
32
+ typeof value["expiresAtMs"] === "number" &&
33
+ (value["tenantId"] === undefined || typeof value["tenantId"] === "string"));
34
34
  }
35
35
  export function verifyMfaSetupToken(token, secret, now = Temporal.Now.instant()) {
36
36
  const parts = token.split(".");
@@ -3,11 +3,11 @@ import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
3
3
  export declare const BILLING_FOUNDATION_FEATURE: "billing-foundation";
4
4
  export declare const SUBSCRIPTION_PROVIDER_EXTENSION: "subscriptionProvider";
5
5
  /** delivery notification type of the § 312f contract confirmation mail. */
6
- export declare const CONTRACT_CONFIRMATION_NOTIFICATION_TYPE: "billing-foundation:contract-confirmation";
6
+ export declare const CONTRACT_CONFIRMATION_NOTIFICATION_TYPE: "billing-foundation:notify:contract-confirmation";
7
7
  /** delivery notification types of the § 312k termination receipt and the
8
8
  * operator notice. */
9
- export declare const CONTRACT_TERMINATION_RECEIPT_NOTIFICATION_TYPE: "billing-foundation:contract-termination-receipt";
10
- export declare const CONTRACT_TERMINATION_OPERATOR_NOTIFICATION_TYPE: "billing-foundation:contract-termination-operator-notice";
9
+ export declare const CONTRACT_TERMINATION_RECEIPT_NOTIFICATION_TYPE: "billing-foundation:notify:contract-termination-receipt";
10
+ export declare const CONTRACT_TERMINATION_OPERATOR_NOTIFICATION_TYPE: "billing-foundation:notify:contract-termination-operator-notice";
11
11
  export declare const SubscriptionFoundationHandlers: {
12
12
  /** Programmatic entry-point für den webhook-handler. Receives the
13
13
  * parsed SubscriptionEvent (vom Plugin schon verifiziert) + macht
@@ -1,17 +1,18 @@
1
1
  /// <reference types="temporal-polyfill/global" preserve="true" />
2
2
  // @runtime client
3
3
  import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
4
+ import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
4
5
  // Feature name
5
6
  export const BILLING_FOUNDATION_FEATURE = "billing-foundation";
6
7
  // Extension-point name fuer Provider-Plugins (subscription-stripe,
7
8
  // subscription-mollie, ...).
8
9
  export const SUBSCRIPTION_PROVIDER_EXTENSION = "subscriptionProvider";
9
10
  /** delivery notification type of the § 312f contract confirmation mail. */
10
- export const CONTRACT_CONFIRMATION_NOTIFICATION_TYPE = "billing-foundation:contract-confirmation";
11
+ export const CONTRACT_CONFIRMATION_NOTIFICATION_TYPE = "billing-foundation:notify:contract-confirmation";
11
12
  /** delivery notification types of the § 312k termination receipt and the
12
13
  * operator notice. */
13
- export const CONTRACT_TERMINATION_RECEIPT_NOTIFICATION_TYPE = "billing-foundation:contract-termination-receipt";
14
- export const CONTRACT_TERMINATION_OPERATOR_NOTIFICATION_TYPE = "billing-foundation:contract-termination-operator-notice";
14
+ export const CONTRACT_TERMINATION_RECEIPT_NOTIFICATION_TYPE = "billing-foundation:notify:contract-termination-receipt";
15
+ export const CONTRACT_TERMINATION_OPERATOR_NOTIFICATION_TYPE = "billing-foundation:notify:contract-termination-operator-notice";
15
16
  // Qualified write handler names (QN format: scope:type:name).
16
17
  export const SubscriptionFoundationHandlers = {
17
18
  /** Programmatic entry-point für den webhook-handler. Receives the
@@ -195,5 +196,5 @@ export const DEFAULT_PURCHASE_ROLES = ["TenantAdmin", "SystemAdmin"];
195
196
  // `<plugin-name>:config:price-to-tier`-Key.
196
197
  export const TERMINATION_SCOPES = ["tenant-host", "platform"];
197
198
  export function isTerminationScope(value) {
198
- return TERMINATION_SCOPES.includes(value);
199
+ return isOneOf(TERMINATION_SCOPES, value);
199
200
  }
@@ -1,18 +1,37 @@
1
1
  import type { CheckoutConsentRecordedPayload } from "../events.js";
2
- export type ContractConfirmationSection = {
2
+ import { type ConsentLocale } from "./consent-text.js";
3
+ type ConfirmationLabels = {
4
+ readonly subject: string;
5
+ readonly intro: string;
6
+ readonly plan: string;
7
+ readonly item: string;
8
+ readonly oneOffPayment: string;
9
+ readonly price: string;
10
+ readonly oneOff: string;
11
+ readonly contractStart: string;
12
+ readonly currentPeriodEnd: string;
13
+ readonly consentHeading: string;
14
+ readonly consentGivenAt: string;
15
+ readonly termsHeading: string;
16
+ readonly contact: string;
17
+ readonly intervals: Readonly<Record<string, {
18
+ one: string;
19
+ many: string;
20
+ }>>;
21
+ readonly every: string;
22
+ };
23
+ export declare const CONFIRMATION_LABELS: Readonly<Record<ConsentLocale, ConfirmationLabels>>;
24
+ type TextRow = {
3
25
  readonly text: string;
4
- } | {
5
- readonly heading: string;
6
- } | {
7
- readonly markdown: string;
8
26
  };
9
- export type ContractConfirmationContent = {
10
- readonly subject: string;
11
- readonly header: string;
12
- readonly sections: readonly ContractConfirmationSection[];
13
- readonly footer: string;
27
+ /** Variables of the contract confirmation template. */
28
+ export type ContractConfirmationVariables = {
29
+ readonly contractLines: readonly TextRow[];
30
+ readonly consentGivenAt: string;
31
+ readonly termsParagraphs: readonly TextRow[];
32
+ readonly operatorEmail: string;
14
33
  };
15
- export type RenderContractConfirmationArgs = {
34
+ export type ContractConfirmationArgs = {
16
35
  readonly consent: CheckoutConsentRecordedPayload;
17
36
  readonly timeZone: string;
18
37
  /** Translated plan name; falls back to the raw tier. */
@@ -26,6 +45,5 @@ export type RenderContractConfirmationArgs = {
26
45
  readonly operatorEmail: string;
27
46
  readonly termsContent: string;
28
47
  };
29
- /** Structured mail content (header/sections/footer) for the email channel's
30
- * renderer; the renderer owns HTML escaping, this only builds plain text. */
31
- export declare function renderContractConfirmation(args: RenderContractConfirmationArgs): ContractConfirmationContent;
48
+ export declare function contractConfirmationVariables(args: ContractConfirmationArgs): ContractConfirmationVariables;
49
+ export {};
@@ -1,6 +1,9 @@
1
+ import { escapeHtml, escapeHtmlAttr } from "@cosmicdrift/kumiko-headless";
1
2
  import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
2
- import { CONSENT_TEXTS, resolveConsentLocale } from "./consent-text.js";
3
- const LABELS = {
3
+ import { Marked } from "marked";
4
+ import { isAllowedDocumentLinkHref, isDocumentPlaceholderHref, } from "../../template-resolver/index.js";
5
+ import { resolveConsentLocale } from "./consent-text.js";
6
+ export const CONFIRMATION_LABELS = {
4
7
  de: {
5
8
  subject: "Vertragsbestätigung",
6
9
  intro: "Vielen Dank für deine Bestellung. Hiermit bestätigen wir den Vertragsschluss mit folgendem Inhalt.",
@@ -47,7 +50,7 @@ const LABELS = {
47
50
  },
48
51
  };
49
52
  function formatPrice(consent, locale) {
50
- const labels = LABELS[locale];
53
+ const labels = CONFIRMATION_LABELS[locale];
51
54
  if (consent.unitAmount === null || consent.currency === null)
52
55
  return "-";
53
56
  let amount;
@@ -89,40 +92,79 @@ function formatDate(iso, locale, timeZone) {
89
92
  timeZoneName: "short",
90
93
  }).format(epochMilliseconds);
91
94
  }
92
- /** Structured mail content (header/sections/footer) for the email channel's
93
- * renderer; the renderer owns HTML escaping, this only builds plain text. */
94
- export function renderContractConfirmation(args) {
95
+ // One richText row of inline HTML per Markdown block. The sanitizer shows a rejected
96
+ // row as escaped text, so author HTML, images and refused links stay plain text.
97
+ const ROW_END = "\n\n";
98
+ function isMailLinkHref(href) {
99
+ return isAllowedDocumentLinkHref(href) && !isDocumentPlaceholderHref(href);
100
+ }
101
+ const inlineHtmlMarkdown = new Marked({ gfm: false, breaks: false });
102
+ inlineHtmlMarkdown.use({
103
+ renderer: {
104
+ heading({ tokens }) {
105
+ const headingHtml = this.parser.parseInline(tokens);
106
+ return `<strong>${headingHtml}</strong>${ROW_END}`;
107
+ },
108
+ paragraph({ tokens }) {
109
+ return `${this.parser.parseInline(tokens)}${ROW_END}`;
110
+ },
111
+ code: ({ text }) => `${escapeHtml(text)}${ROW_END}`,
112
+ blockquote({ tokens }) {
113
+ return this.parser.parse(tokens);
114
+ },
115
+ list({ items }) {
116
+ return items.map((item) => this.parser.parse(item.tokens)).join("");
117
+ },
118
+ hr: () => "",
119
+ space: () => "",
120
+ del({ tokens }) {
121
+ return this.parser.parseInline(tokens);
122
+ },
123
+ br: () => " ",
124
+ html: ({ text }) => escapeHtml(text),
125
+ image: ({ text }) => escapeHtml(text),
126
+ text(token) {
127
+ // Only block-level text (a list item's own text) carries inline child tokens.
128
+ return "tokens" in token && token.tokens
129
+ ? `${this.parser.parseInline(token.tokens)}${ROW_END}`
130
+ : escapeHtml(token.text);
131
+ },
132
+ link({ href, tokens }) {
133
+ const labelHtml = this.parser.parseInline(tokens);
134
+ if (isMailLinkHref(href))
135
+ return `<a href="${escapeHtmlAttr(href)}">${labelHtml}</a>`;
136
+ return labelHtml === escapeHtml(href) ? labelHtml : `${labelHtml} (${escapeHtml(href)})`;
137
+ },
138
+ },
139
+ });
140
+ function termsParagraphsOf(markdown) {
141
+ return inlineHtmlMarkdown
142
+ .parse(markdown, { async: false })
143
+ .split(/\n\s*\n/)
144
+ .map((row) => row.replace(/\s+/g, " ").trim())
145
+ .filter((row) => row.length > 0)
146
+ .map((text) => ({ text }));
147
+ }
148
+ export function contractConfirmationVariables(args) {
95
149
  const locale = resolveConsentLocale(args.consent.locale);
96
- const labels = LABELS[locale];
97
- const texts = CONSENT_TEXTS[locale];
98
- const { consent } = args;
99
- const { timeZone } = args;
150
+ const labels = CONFIRMATION_LABELS[locale];
151
+ const { consent, timeZone } = args;
100
152
  const subjectLine = consent.mode === "payment"
101
153
  ? `${labels.item}: ${args.itemLabel ?? labels.oneOffPayment}`
102
154
  : `${labels.plan}: ${args.tierLabel ?? consent.tier ?? labels.oneOffPayment}`;
103
- const contractLines = [
104
- subjectLine,
105
- `${labels.price}: ${formatPrice(consent, locale)}`,
106
- `${labels.contractStart}: ${formatDate(args.contractStartIso, locale, timeZone)}`,
107
- ...(args.currentPeriodEndIso !== undefined
108
- ? [`${labels.currentPeriodEnd}: ${formatDate(args.currentPeriodEndIso, locale, timeZone)}`]
109
- : []),
110
- ];
111
155
  const vatNote = args.vatNote[locale] ?? args.vatNote[resolveConsentLocale()];
112
156
  return {
113
- subject: labels.subject,
114
- header: labels.subject,
115
- sections: [
116
- { text: labels.intro },
117
- ...contractLines.map((text) => ({ text })),
118
- ...(vatNote !== undefined ? [{ text: vatNote }] : []),
119
- { heading: labels.consentHeading },
120
- { text: texts.earlyPerformance },
121
- { text: texts.withdrawalLoss },
122
- { text: `${labels.consentGivenAt}: ${formatDate(args.consentGivenAtIso, locale, timeZone)}` },
123
- { heading: labels.termsHeading },
124
- { markdown: args.termsContent },
125
- ],
126
- footer: `${labels.contact} ${args.operatorEmail}`,
157
+ contractLines: [
158
+ subjectLine,
159
+ `${labels.price}: ${formatPrice(consent, locale)}`,
160
+ `${labels.contractStart}: ${formatDate(args.contractStartIso, locale, timeZone)}`,
161
+ ...(args.currentPeriodEndIso !== undefined
162
+ ? [`${labels.currentPeriodEnd}: ${formatDate(args.currentPeriodEndIso, locale, timeZone)}`]
163
+ : []),
164
+ ...(vatNote !== undefined ? [vatNote] : []),
165
+ ].map((text) => ({ text })),
166
+ consentGivenAt: formatDate(args.consentGivenAtIso, locale, timeZone),
167
+ termsParagraphs: termsParagraphsOf(args.termsContent),
168
+ operatorEmail: args.operatorEmail,
127
169
  };
128
170
  }
@@ -22,6 +22,9 @@ export type OrderItem = {
22
22
  readonly labelKey: string;
23
23
  readonly params?: Readonly<Record<string, string | number>>;
24
24
  };
25
+ /** Throws an InternalError (an app configuration fault, not a buyer error) for a
26
+ * label the consent event could not store. */
27
+ export declare function assertValidOrderItem(item: OrderItem | undefined, priceId: string): void;
25
28
  export type ConsentPriceDetails = {
26
29
  readonly tier: string | null;
27
30
  readonly priceId: string;
@@ -2,12 +2,12 @@
2
2
  // validate + prepare before the provider call, record only after it succeeded.
3
3
  import { createHash } from "node:crypto";
4
4
  import { SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
5
- import { UnprocessableError } from "@cosmicdrift/kumiko-framework/errors";
5
+ import { InternalError, UnprocessableError } from "@cosmicdrift/kumiko-framework/errors";
6
6
  import { generateId } from "@cosmicdrift/kumiko-framework/utils";
7
7
  import * as z from "zod";
8
8
  import { requireTemplateResolver, TEXT_BLOCK_KIND, TemplateNotFoundError, } from "../../template-resolver/index.js";
9
9
  import { paymentAggregateId, subscriptionAggregateId } from "../aggregate-id.js";
10
- import { CHECKOUT_CONSENT_RECORDED_EVENT_QN, PAYMENT_AGGREGATE_TYPE, SUBSCRIPTION_AGGREGATE_TYPE, } from "../events.js";
10
+ import { CHECKOUT_CONSENT_RECORDED_EVENT_QN, checkoutConsentRecordedPayloadSchema, PAYMENT_AGGREGATE_TYPE, SUBSCRIPTION_AGGREGATE_TYPE, } from "../events.js";
11
11
  import { consentTextVersion, resolveConsentLocale, submitMessageFor } from "./consent-text.js";
12
12
  // Optional at the schema level so a missing/unchecked consent reaches
13
13
  // prepareConsent and fails as 422 consent_required, not as a zod 400.
@@ -19,6 +19,25 @@ export const consentPayloadSchema = z
19
19
  locale: z.string().min(2).max(35),
20
20
  })
21
21
  .strict();
22
+ // Bounds come from the event schema the label ends up in, so an app label that
23
+ // passes here cannot fail the append after the provider session exists.
24
+ const orderItemSchema = z.object({
25
+ labelKey: checkoutConsentRecordedPayloadSchema.shape.itemLabelKey.unwrap(),
26
+ params: checkoutConsentRecordedPayloadSchema.shape.itemLabelParams,
27
+ });
28
+ /** Throws an InternalError (an app configuration fault, not a buyer error) for a
29
+ * label the consent event could not store. */
30
+ export function assertValidOrderItem(item, priceId) {
31
+ // skip: subscription checkouts have no one-off order item
32
+ if (item === undefined)
33
+ return;
34
+ const parsed = orderItemSchema.safeParse(item);
35
+ if (!parsed.success) {
36
+ throw new InternalError({
37
+ message: `billing-foundation: consumerProtection.oneOffItemLabel returned an invalid label for priceId "${priceId}": ${parsed.error.message}`,
38
+ });
39
+ }
40
+ }
22
41
  export async function prepareConsent(ctx, options, consent, mode) {
23
42
  if (!consent?.earlyPerformanceRequested || !consent.withdrawalLossAcknowledged) {
24
43
  throw new UnprocessableError("consent_required", {
@@ -11,7 +11,7 @@ import { UserQueries } from "../../user/index.js";
11
11
  import { paymentAggregateId, subscriptionAggregateId } from "../aggregate-id.js";
12
12
  import { CONTRACT_CONFIRMATION_NOTIFICATION_TYPE } from "../constants.js";
13
13
  import { CHECKOUT_CONSENT_RECORDED_EVENT_QN, CONTRACT_CONFIRMATION_ISSUED_EVENT_QN, checkoutConsentRecordedPayloadSchema, contractConfirmationIssuedPayloadSchema, PAYMENT_AGGREGATE_TYPE, SUBSCRIPTION_AGGREGATE_TYPE, } from "../events.js";
14
- import { renderContractConfirmation } from "./confirmation-mail.js";
14
+ import { contractConfirmationVariables } from "./confirmation-mail.js";
15
15
  import { resolveConsentLocale } from "./consent-text.js";
16
16
  export const issueContractConfirmationSchema = z
17
17
  .object({
@@ -128,7 +128,7 @@ export function createIssueContractConfirmationHandler(options, consumerProtecti
128
128
  ? translatedOrUndefined(i18n.t(consent.itemLabelKey, locale, consent.itemLabelParams), consent.itemLabelKey)
129
129
  : undefined;
130
130
  const issuedAtIso = options.now().toString();
131
- const content = renderContractConfirmation({
131
+ const variables = contractConfirmationVariables({
132
132
  consent,
133
133
  timeZone: pickTimeZone(recipient.data.timezone, ctx.tz.tenant),
134
134
  ...(tierLabel !== undefined && { tierLabel }),
@@ -159,7 +159,7 @@ export function createIssueContractConfirmationHandler(options, consumerProtecti
159
159
  await stream.appendOne({ type: CONTRACT_CONFIRMATION_ISSUED_EVENT_QN, payload: issued });
160
160
  await ctx.notify(CONTRACT_CONFIRMATION_NOTIFICATION_TYPE, {
161
161
  route: { email: recipient.data.email },
162
- data: content,
162
+ data: variables,
163
163
  locale,
164
164
  priority: "critical",
165
165
  });
@@ -0,0 +1,8 @@
1
+ import { type FeatureRegistrar, type NotificationLocalizedTemplate, type TemplateVariables } from "@cosmicdrift/kumiko-framework/engine";
2
+ export declare const TERMINATION_RECEIPT_VARIABLES: TemplateVariables;
3
+ export declare const OPERATOR_NOTICE_VARIABLES: TemplateVariables;
4
+ export declare const CONTRACT_CONFIRMATION_VARIABLES: TemplateVariables;
5
+ export declare function terminationReceiptTemplate(): NotificationLocalizedTemplate;
6
+ export declare function operatorNoticeTemplate(): NotificationLocalizedTemplate;
7
+ export declare function contractConfirmationTemplate(): NotificationLocalizedTemplate;
8
+ export declare function registerConsumerProtectionMails(r: FeatureRegistrar): void;
@@ -0,0 +1,95 @@
1
+ import { templateVariable, } from "@cosmicdrift/kumiko-framework/engine";
2
+ import { mailHeading, mailParagraph, mailRepeatedRows } from "../../shared/index.js";
3
+ import { CONFIRMATION_LABELS } from "./confirmation-mail.js";
4
+ import { CONSENT_LOCALES, CONSENT_TEXTS } from "./consent-text.js";
5
+ import { TERMINATION_TEXTS } from "./termination-texts.js";
6
+ // Slot syntax for the translated texts: `{name}` becomes a template variable.
7
+ const OPERATOR_EMAIL_SLOT = "{operatorEmail}";
8
+ const textRows = () => templateVariable.list({ text: templateVariable.text({ required: true }) }, { required: true });
9
+ export const TERMINATION_RECEIPT_VARIABLES = {
10
+ subject: templateVariable.text({ required: true }),
11
+ receivedAt: templateVariable.text({ required: true }),
12
+ requestId: templateVariable.text({ required: true }),
13
+ details: textRows(),
14
+ operatorEmail: templateVariable.text({ required: true }),
15
+ };
16
+ export const OPERATOR_NOTICE_VARIABLES = {
17
+ subject: templateVariable.text({ required: true }),
18
+ lines: textRows(),
19
+ operatorEmail: templateVariable.text({ required: true }),
20
+ };
21
+ export const CONTRACT_CONFIRMATION_VARIABLES = {
22
+ contractLines: textRows(),
23
+ consentGivenAt: templateVariable.text({ required: true }),
24
+ termsParagraphs: templateVariable.list({ text: templateVariable.richText({ required: true }) }, { required: true }),
25
+ operatorEmail: templateVariable.text({ required: true }),
26
+ };
27
+ function perLocale(build) {
28
+ return Object.fromEntries(CONSENT_LOCALES.map((locale) => {
29
+ const { body, subject } = build(locale);
30
+ return [locale, { body, meta: { subject, category: "transactional" } }];
31
+ }));
32
+ }
33
+ export function terminationReceiptTemplate() {
34
+ return perLocale((locale) => {
35
+ const texts = TERMINATION_TEXTS[locale];
36
+ return {
37
+ subject: "{{subject}}",
38
+ body: [
39
+ mailParagraph(texts.receiptGreeting),
40
+ mailParagraph(texts.receiptIntro),
41
+ mailParagraph(`${texts.receivedAt}: {receivedAt}`),
42
+ mailParagraph(`${texts.requestId}: {requestId}`),
43
+ mailRepeatedRows("details", "text"),
44
+ mailParagraph(texts.receiptNextSteps),
45
+ mailParagraph(texts.receiptRevoke(OPERATOR_EMAIL_SLOT)),
46
+ mailParagraph(`${texts.contact} {operatorEmail}`),
47
+ ].join(""),
48
+ };
49
+ });
50
+ }
51
+ export function operatorNoticeTemplate() {
52
+ return perLocale((locale) => ({
53
+ subject: "{{subject}}",
54
+ body: [
55
+ mailParagraph(TERMINATION_TEXTS[locale].operatorIntro),
56
+ mailRepeatedRows("lines", "text"),
57
+ mailParagraph("{operatorEmail}"),
58
+ ].join(""),
59
+ }));
60
+ }
61
+ export function contractConfirmationTemplate() {
62
+ return perLocale((locale) => {
63
+ const labels = CONFIRMATION_LABELS[locale];
64
+ const consent = CONSENT_TEXTS[locale];
65
+ return {
66
+ subject: labels.subject,
67
+ body: [
68
+ mailParagraph(labels.intro),
69
+ mailRepeatedRows("contractLines", "text"),
70
+ mailHeading(labels.consentHeading),
71
+ mailParagraph(consent.earlyPerformance),
72
+ mailParagraph(consent.withdrawalLoss),
73
+ mailParagraph(`${labels.consentGivenAt}: {consentGivenAt}`),
74
+ mailHeading(labels.termsHeading),
75
+ mailRepeatedRows("termsParagraphs", "text"),
76
+ mailParagraph(`${labels.contact} {operatorEmail}`),
77
+ ].join(""),
78
+ };
79
+ });
80
+ }
81
+ // The registered notification names are the tail of the QN types in constants.ts.
82
+ export function registerConsumerProtectionMails(r) {
83
+ r.notification("contract-confirmation", {
84
+ variables: CONTRACT_CONFIRMATION_VARIABLES,
85
+ localizedTemplate: contractConfirmationTemplate,
86
+ });
87
+ r.notification("contract-termination-receipt", {
88
+ variables: TERMINATION_RECEIPT_VARIABLES,
89
+ localizedTemplate: terminationReceiptTemplate,
90
+ });
91
+ r.notification("contract-termination-operator-notice", {
92
+ variables: OPERATOR_NOTICE_VARIABLES,
93
+ localizedTemplate: operatorNoticeTemplate,
94
+ });
95
+ }
@@ -2,6 +2,7 @@ import { paymentAggregateId, subscriptionAggregateId } from "../aggregate-id.js"
2
2
  import { SubscriptionFoundationHandlers, SubscriptionStatuses } from "../constants.js";
3
3
  import { CHECKOUT_CONSENT_RECORDED_EVENT_SHORT, CONTRACT_CONFIRMATION_ISSUED_EVENT_SHORT, checkoutConsentRecordedPayloadSchema, contractConfirmationIssuedPayloadSchema, INVOICE_PAID_EVENT_QN, PAYMENT_RECEIVED_EVENT_QN, SUBSCRIPTION_CREATED_EVENT_QN, SUBSCRIPTION_UPDATED_EVENT_QN, } from "../events.js";
4
4
  import { createIssueContractConfirmationHandler } from "./issue-confirmation.js";
5
+ import { registerConsumerProtectionMails } from "./mail-notifications.js";
5
6
  import { registerContractTermination } from "./register-termination.js";
6
7
  const CONFIRMATION_TRIGGERS = [
7
8
  {
@@ -22,6 +23,7 @@ function isConfirmableSubscriptionStatus(status) {
22
23
  }
23
24
  export function registerConsumerProtection(r, options, consumerProtection) {
24
25
  r.requires("template-resolver", "delivery", "user", "tenant");
26
+ registerConsumerProtectionMails(r);
25
27
  registerContractTermination(r, options, consumerProtection);
26
28
  r.defineEvent(CHECKOUT_CONSENT_RECORDED_EVENT_SHORT, checkoutConsentRecordedPayloadSchema, {
27
29
  piiFields: "none",
@@ -16,7 +16,17 @@ export function registerContractTermination(r, options, consumerProtection) {
16
16
  // request: matched and unmatched requests then do the same work and the
17
17
  // response time does not tell whether the email belongs to a customer.
18
18
  // The tenant comes from the stored trigger event (the job's system user).
19
- r.job("cancel-on-public-termination-declared", { trigger: { on: CONTRACT_TERMINATION_DECLARED_EVENT_QN }, runIn: "worker" }, async (payload, ctx) => {
19
+ // Every declaration appends to the same subscription stream, so parallel runs
20
+ // and a declaration arriving mid-run hit version conflicts. Sequential runs
21
+ // rule out the first; a retry re-reads the stream and the requestId check in
22
+ // record-contract-termination keeps it from recording twice.
23
+ r.job("cancel-on-public-termination-declared", {
24
+ trigger: { on: CONTRACT_TERMINATION_DECLARED_EVENT_QN },
25
+ runIn: "worker",
26
+ concurrency: "sequential",
27
+ retries: 3,
28
+ backoff: "exponential",
29
+ }, async (payload, ctx) => {
20
30
  const declared = contractTerminationDeclaredPayloadSchema.safeParse(payload);
21
31
  // skip: trigger event carries no usable declaration
22
32
  if (!declared.success)
@@ -1,13 +1,22 @@
1
1
  import type { ContractTerminationDeclarationType, ContractTerminationKind, ProviderCancelOutcome } from "../events.js";
2
2
  import type { ConsentLocale } from "./consent-text.js";
3
3
  import { type OperatorNoticeReason } from "./termination-texts.js";
4
- export type TerminationMailContent = {
4
+ type TextRow = {
5
+ readonly text: string;
6
+ };
7
+ /** Variables of the termination receipt template. */
8
+ export type TerminationReceiptVariables = {
9
+ readonly subject: string;
10
+ readonly receivedAt: string;
11
+ readonly requestId: string;
12
+ readonly details: readonly TextRow[];
13
+ readonly operatorEmail: string;
14
+ };
15
+ /** Variables of the operator notice template. */
16
+ export type OperatorNoticeVariables = {
5
17
  readonly subject: string;
6
- readonly header: string;
7
- readonly sections: readonly {
8
- readonly text: string;
9
- }[];
10
- readonly footer: string;
18
+ readonly lines: readonly TextRow[];
19
+ readonly operatorEmail: string;
11
20
  };
12
21
  /** What the declarant entered; the only input of the receipt. */
13
22
  export type TerminationDeclaration = {
@@ -21,17 +30,19 @@ export type TerminationDeclaration = {
21
30
  /** The operator notice for a provider problem has no declarant data at all. */
22
31
  export type OperatorNoticeDeclaration = Pick<TerminationDeclaration, "declarationType" | "terminationKind"> & Partial<Omit<TerminationDeclaration, "declarationType" | "terminationKind">>;
23
32
  export declare function formatReceivedAt(iso: string, locale: ConsentLocale): string;
24
- export type RenderTerminationReceiptArgs = {
33
+ /** The receipt carries enum fields only: free text from an anonymous caller
34
+ * must not be echoed to an arbitrary address. */
35
+ export type ReceiptDeclaration = Pick<TerminationDeclaration, "declarationType" | "terminationKind">;
36
+ export type TerminationReceiptArgs = {
25
37
  readonly locale: ConsentLocale;
26
38
  readonly requestId: string;
27
39
  readonly receivedAtIso: string;
28
- readonly declaration: TerminationDeclaration;
40
+ readonly declaration: ReceiptDeclaration;
29
41
  readonly operatorEmail: string;
30
42
  };
31
- /** Built from the declarant's own input only: the content must not depend on
32
- * whether (or how) the declaration matched a contract. */
33
- export declare function renderTerminationReceipt(args: RenderTerminationReceiptArgs): TerminationMailContent;
34
- export type RenderOperatorNoticeArgs = {
43
+ /** The content must not depend on whether (or how) the declaration matched a contract. */
44
+ export declare function terminationReceiptVariables(args: TerminationReceiptArgs): TerminationReceiptVariables;
45
+ export type OperatorNoticeArgs = {
35
46
  readonly locale: ConsentLocale;
36
47
  readonly requestId: string;
37
48
  readonly receivedAtIso: string;
@@ -42,4 +53,5 @@ export type RenderOperatorNoticeArgs = {
42
53
  readonly providerCancel?: ProviderCancelOutcome;
43
54
  readonly operatorEmail: string;
44
55
  };
45
- export declare function renderOperatorNotice(args: RenderOperatorNoticeArgs): TerminationMailContent;
56
+ export declare function operatorNoticeVariables(args: OperatorNoticeArgs): OperatorNoticeVariables;
57
+ export {};