@cosmicdrift/kumiko-bundled-features 0.378.0 → 0.379.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 (632) hide show
  1. package/dist/account-security/feature.js +2 -2
  2. package/dist/account-security/index.d.ts +2 -2
  3. package/dist/account-security/index.js +2 -2
  4. package/dist/account-security/{constants.js → web/constants.js} +0 -1
  5. package/dist/account-security/{i18n.js → web/i18n.js} +0 -1
  6. package/dist/admin-shell/feature.js +4 -3
  7. package/dist/admin-shell/index.d.ts +2 -2
  8. package/dist/admin-shell/index.js +2 -2
  9. package/dist/admin-shell/web/client-plugin.js +2 -3
  10. package/dist/admin-shell/{constants.js → web/constants.js} +0 -1
  11. package/dist/admin-shell/web/default-translations.d.ts +2 -0
  12. package/dist/admin-shell/web/default-translations.js +4 -0
  13. package/dist/admin-shell/web/i18n.d.ts +5 -2
  14. package/dist/admin-shell/web/i18n.js +50 -5
  15. package/dist/admin-shell/web/index.js +0 -1
  16. package/dist/audit/feature.js +58 -59
  17. package/dist/audit/handlers/audit-events.d.ts +102 -0
  18. package/dist/audit/handlers/audit-events.js +112 -0
  19. package/dist/audit/handlers/audit-system-db.d.ts +1 -0
  20. package/dist/audit/handlers/audit-system-db.js +9 -0
  21. package/dist/audit/handlers/details-all-tenants.query.d.ts +15 -0
  22. package/dist/audit/handlers/details-all-tenants.query.js +20 -0
  23. package/dist/audit/handlers/details.query.d.ts +2 -1
  24. package/dist/audit/handlers/details.query.js +8 -24
  25. package/dist/audit/handlers/list-all-tenants.query.d.ts +41 -0
  26. package/dist/audit/handlers/list-all-tenants.query.js +32 -0
  27. package/dist/audit/handlers/list.query.d.ts +2 -1
  28. package/dist/audit/handlers/list.query.js +9 -99
  29. package/dist/audit/handlers/resolve-audit-tenant.d.ts +3 -1
  30. package/dist/audit/handlers/resolve-audit-tenant.js +21 -7
  31. package/dist/audit/index.d.ts +1 -1
  32. package/dist/audit/index.js +1 -1
  33. package/dist/audit/run-escape-hatch-retention.js +1 -1
  34. package/dist/audit/screens.d.ts +65 -0
  35. package/dist/audit/screens.js +73 -0
  36. package/dist/audit/web/client-plugin.js +2 -3
  37. package/dist/audit/{constants.d.ts → web/constants.d.ts} +8 -0
  38. package/dist/audit/{constants.js → web/constants.js} +8 -1
  39. package/dist/audit/web/default-translations.d.ts +2 -0
  40. package/dist/audit/web/default-translations.js +3 -0
  41. package/dist/audit/web/i18n.d.ts +5 -2
  42. package/dist/audit/web/i18n.js +31 -4
  43. package/dist/audit/web/index.js +0 -1
  44. package/dist/auth-email-password/bootstrap.d.ts +1 -1
  45. package/dist/auth-email-password/bootstrap.js +4 -4
  46. package/dist/auth-email-password/errors.js +1 -1
  47. package/dist/auth-email-password/feature.js +2 -2
  48. package/dist/auth-email-password/handlers/confirm-account-unlock.write.js +1 -1
  49. package/dist/auth-email-password/handlers/invite-accept-with-login.write.js +1 -1
  50. package/dist/auth-email-password/handlers/invite-create.write.d.ts +1 -1
  51. package/dist/auth-email-password/handlers/invite-create.write.js +3 -3
  52. package/dist/auth-email-password/handlers/invite-info.query.js +1 -1
  53. package/dist/auth-email-password/handlers/login.write.d.ts +1 -0
  54. package/dist/auth-email-password/handlers/login.write.js +26 -1
  55. package/dist/auth-email-password/handlers/request-account-unlock.write.js +1 -1
  56. package/dist/auth-email-password/handlers/request-email-verification.write.js +1 -1
  57. package/dist/auth-email-password/handlers/request-password-reset.write.js +1 -1
  58. package/dist/auth-email-password/handlers/reset-password.write.js +1 -1
  59. package/dist/auth-email-password/handlers/verify-email.write.js +1 -1
  60. package/dist/auth-email-password/index.d.ts +1 -1
  61. package/dist/auth-email-password/index.js +1 -1
  62. package/dist/auth-email-password/mail-notifications.js +1 -1
  63. package/dist/auth-email-password/signup-activation.js +1 -1
  64. package/dist/auth-email-password/web/auth-client.js +0 -1
  65. package/dist/auth-email-password/web/auth-form-logic.js +0 -1
  66. package/dist/auth-email-password/web/auth-form-primitives.js +0 -1
  67. package/dist/auth-email-password/web/auth-gate.js +0 -1
  68. package/dist/auth-email-password/web/auth-redirect.js +0 -1
  69. package/dist/auth-email-password/web/client-actions.js +0 -1
  70. package/dist/auth-email-password/web/client-plugin.js +1 -2
  71. package/dist/auth-email-password/web/confirm-account-unlock-screen.js +0 -1
  72. package/dist/auth-email-password/{constants.js → web/constants.js} +3 -6
  73. package/dist/auth-email-password/web/default-topbar-actions.js +0 -1
  74. package/dist/auth-email-password/web/forgot-password-screen.js +0 -1
  75. package/dist/auth-email-password/{i18n.js → web/i18n.js} +3 -4
  76. package/dist/auth-email-password/web/index.d.ts +1 -1
  77. package/dist/auth-email-password/web/index.js +1 -2
  78. package/dist/auth-email-password/web/invite-accept-screen.d.ts +2 -2
  79. package/dist/auth-email-password/web/invite-accept-screen.js +0 -1
  80. package/dist/auth-email-password/web/login-screen.js +0 -1
  81. package/dist/auth-email-password/{mail-i18n.js → web/mail-i18n.js} +0 -1
  82. package/dist/auth-email-password/web/request-account-unlock-screen.js +0 -1
  83. package/dist/auth-email-password/web/reset-password-screen.js +0 -1
  84. package/dist/auth-email-password/web/session-bootstrap-error.js +0 -1
  85. package/dist/auth-email-password/web/session.js +0 -1
  86. package/dist/auth-email-password/web/signup-complete-screen.d.ts +2 -2
  87. package/dist/auth-email-password/web/signup-complete-screen.js +0 -1
  88. package/dist/auth-email-password/web/signup-screen.js +0 -1
  89. package/dist/auth-email-password/web/tenant-menu-items.js +0 -1
  90. package/dist/auth-email-password/web/tenant-switcher.js +0 -1
  91. package/dist/auth-email-password/web/use-shell-user.js +0 -1
  92. package/dist/auth-email-password/web/user-menu.js +0 -1
  93. package/dist/auth-email-password/web/verify-email-screen.js +0 -1
  94. package/dist/auth-mfa/errors.d.ts +1 -1
  95. package/dist/auth-mfa/errors.js +2 -2
  96. package/dist/auth-mfa/handlers/enable-confirm-preauth.write.js +1 -1
  97. package/dist/auth-mfa/handlers/enable-start-preauth.write.js +1 -1
  98. package/dist/auth-mfa/handlers/enable-start.write.js +1 -1
  99. package/dist/auth-mfa/handlers/verify.write.js +1 -1
  100. package/dist/auth-mfa/index.d.ts +1 -1
  101. package/dist/auth-mfa/index.js +1 -1
  102. package/dist/auth-mfa/mfa-status-checker.js +1 -1
  103. package/dist/auth-mfa/screens.js +1 -1
  104. package/dist/auth-mfa/web/client-plugin.js +0 -1
  105. package/dist/auth-mfa/{constants.js → web/constants.js} +0 -1
  106. package/dist/auth-mfa/web/i18n.js +0 -1
  107. package/dist/auth-mfa/web/index.js +0 -1
  108. package/dist/auth-mfa/web/mfa-client.js +0 -1
  109. package/dist/auth-mfa/web/mfa-disable-dialog.js +1 -2
  110. package/dist/auth-mfa/web/mfa-recovery-codes-reveal.js +0 -1
  111. package/dist/auth-mfa/web/mfa-regenerate-recovery-dialog.js +1 -2
  112. package/dist/auth-mfa/web/mfa-setup-preauth-screen.js +11 -18
  113. package/dist/auth-mfa/web/mfa-verify-screen.js +0 -1
  114. package/dist/billing-foundation/checkout-core.js +1 -1
  115. package/dist/billing-foundation/consumer-protection/consent-text.d.ts +2 -2
  116. package/dist/billing-foundation/consumer-protection/consent-text.js +1 -1
  117. package/dist/billing-foundation/consumer-protection/issue-confirmation.js +7 -3
  118. package/dist/billing-foundation/consumer-protection/mail-notifications.js +3 -1
  119. package/dist/billing-foundation/consumer-protection/register-consent.js +1 -1
  120. package/dist/billing-foundation/consumer-protection/register-termination.js +8 -2
  121. package/dist/billing-foundation/consumer-protection/stored-user-email.d.ts +1 -0
  122. package/dist/billing-foundation/consumer-protection/stored-user-email.js +8 -0
  123. package/dist/billing-foundation/consumer-protection/termination-mail.d.ts +5 -1
  124. package/dist/billing-foundation/consumer-protection/termination-mail.js +3 -1
  125. package/dist/billing-foundation/consumer-protection/termination-notify.js +1 -1
  126. package/dist/billing-foundation/consumer-protection/termination-pages.js +109 -15
  127. package/dist/billing-foundation/consumer-protection/termination-record.d.ts +8 -1
  128. package/dist/billing-foundation/consumer-protection/termination-record.js +76 -3
  129. package/dist/billing-foundation/consumer-protection/termination-request.js +33 -6
  130. package/dist/billing-foundation/consumer-protection/termination-revoke.d.ts +28 -0
  131. package/dist/billing-foundation/consumer-protection/termination-revoke.js +149 -0
  132. package/dist/billing-foundation/consumer-protection/termination-texts.d.ts +17 -1
  133. package/dist/billing-foundation/consumer-protection/termination-texts.js +39 -0
  134. package/dist/billing-foundation/events.d.ts +9 -0
  135. package/dist/billing-foundation/events.js +14 -2
  136. package/dist/billing-foundation/feature.js +1 -1
  137. package/dist/billing-foundation/handlers/process-event.write.d.ts +5 -1
  138. package/dist/billing-foundation/handlers/process-event.write.js +57 -3
  139. package/dist/billing-foundation/handlers/switch-plan.write.js +1 -1
  140. package/dist/billing-foundation/handlers/sync-subscription.write.js +1 -1
  141. package/dist/billing-foundation/index.d.ts +2 -2
  142. package/dist/billing-foundation/index.js +2 -2
  143. package/dist/billing-foundation/plan-catalog.js +1 -1
  144. package/dist/billing-foundation/screens.js +1 -1
  145. package/dist/billing-foundation/subscription-tier-sync.js +1 -1
  146. package/dist/billing-foundation/types.d.ts +14 -2
  147. package/dist/billing-foundation/types.js +1 -1
  148. package/dist/billing-foundation/validate-options.js +3 -3
  149. package/dist/billing-foundation/web/billing-contact-plan.js +1 -2
  150. package/dist/billing-foundation/web/billing-plans-panel.js +1 -2
  151. package/dist/billing-foundation/web/cancel-contract-dialog.js +1 -2
  152. package/dist/billing-foundation/web/checkout-consent-dialog.js +1 -2
  153. package/dist/billing-foundation/web/client-plugin.js +1 -1
  154. package/dist/billing-foundation/{constants.d.ts → web/constants.d.ts} +21 -14
  155. package/dist/billing-foundation/{constants.js → web/constants.js} +35 -31
  156. package/dist/billing-foundation/{consumer-protection → web/consumer-protection}/consent-locale.js +0 -1
  157. package/dist/billing-foundation/{contact-card.js → web/contact-card.js} +0 -1
  158. package/dist/billing-foundation/web/index.d.ts +2 -2
  159. package/dist/billing-foundation/web/index.js +2 -3
  160. package/dist/billing-foundation/web/localized-params.js +0 -1
  161. package/dist/billing-foundation/webhook-handler.js +4 -1
  162. package/dist/cap-overview/feature.js +1 -1
  163. package/dist/cap-overview/handlers/caps-usage.query.js +1 -1
  164. package/dist/cap-overview/handlers/tenant-caps-list.query.js +2 -2
  165. package/dist/cap-overview/index.d.ts +2 -2
  166. package/dist/cap-overview/index.js +2 -2
  167. package/dist/cap-overview/screens.js +1 -1
  168. package/dist/cap-overview/web/cap-cards-panel.js +1 -1
  169. package/dist/cap-overview/web/cap-usage-bar.js +1 -2
  170. package/dist/cap-overview/web/client-plugin.js +1 -1
  171. package/dist/cap-overview/{constants.js → web/constants.js} +0 -1
  172. package/dist/cap-overview/web/index.js +0 -1
  173. package/dist/cap-overview/{usage-math.d.ts → web/usage-math.d.ts} +1 -1
  174. package/dist/compliance-profiles/feature.js +1 -1
  175. package/dist/compliance-profiles/index.d.ts +1 -1
  176. package/dist/compliance-profiles/index.js +1 -1
  177. package/dist/compliance-profiles/web/client-plugin.js +1 -2
  178. package/dist/compliance-profiles/web/compliance-profile-catalog.js +1 -2
  179. package/dist/compliance-profiles/{constants.js → web/constants.js} +0 -1
  180. package/dist/compliance-profiles/web/index.js +0 -1
  181. package/dist/config/index.d.ts +1 -1
  182. package/dist/config/index.js +1 -1
  183. package/dist/config/web/client-plugin.d.ts +1 -1
  184. package/dist/config/web/client-plugin.js +1 -2
  185. package/dist/config/{constants.js → web/constants.js} +0 -1
  186. package/dist/config/web/i18n.js +0 -1
  187. package/dist/config/web/index.d.ts +1 -1
  188. package/dist/config/web/index.js +1 -2
  189. package/dist/config/write-helpers.js +1 -1
  190. package/dist/custom-fields/feature.js +1 -1
  191. package/dist/custom-fields/handlers/clear-custom-field.write.js +1 -1
  192. package/dist/custom-fields/handlers/define-tenant-field.write.js +1 -1
  193. package/dist/custom-fields/handlers/delete-system-field.write.js +1 -1
  194. package/dist/custom-fields/handlers/delete-tenant-field.write.js +1 -1
  195. package/dist/custom-fields/handlers/set-custom-field.write.js +1 -1
  196. package/dist/custom-fields/handlers/update-tenant-field.write.js +1 -1
  197. package/dist/custom-fields/index.d.ts +1 -1
  198. package/dist/custom-fields/index.js +1 -1
  199. package/dist/custom-fields/lib/value-schema.js +1 -1
  200. package/dist/custom-fields/schemas.js +1 -1
  201. package/dist/custom-fields/web/client-plugin.js +1 -2
  202. package/dist/custom-fields/{constants.js → web/constants.js} +18 -19
  203. package/dist/custom-fields/web/custom-fields-form-section.js +1 -2
  204. package/dist/custom-fields/web/i18n.js +0 -1
  205. package/dist/custom-fields/web/index.d.ts +1 -1
  206. package/dist/custom-fields/web/index.js +1 -2
  207. package/dist/custom-fields/wire-for-entity.js +1 -1
  208. package/dist/delivery/address-opt-out.js +1 -1
  209. package/dist/delivery/attempt-log-retention.js +21 -3
  210. package/dist/delivery/constants.d.ts +1 -1
  211. package/dist/delivery/constants.js +2 -2
  212. package/dist/delivery/i18n.js +1 -1
  213. package/dist/delivery/unsubscribe-page.js +1 -1
  214. package/dist/delivery/web/client-plugin.js +1 -1
  215. package/dist/delivery/web/delivery-channel-cell.js +0 -1
  216. package/dist/delivery/web/delivery-error-cell.js +0 -1
  217. package/dist/delivery/web/delivery-status-cell.js +1 -2
  218. package/dist/delivery/web/delivery-time-cell.js +0 -1
  219. package/dist/delivery/web/delivery-type-cell.js +0 -1
  220. package/dist/delivery/web/index.js +0 -1
  221. package/dist/delivery/{public-names.js → web/public-names.js} +0 -1
  222. package/dist/document-ingest-foundation/events.d.ts +1 -0
  223. package/dist/document-ingest-foundation/events.js +3 -0
  224. package/dist/document-ingest-foundation/executor.js +2 -1
  225. package/dist/document-ingest-foundation/feature.js +16 -5
  226. package/dist/document-ingest-foundation/index.d.ts +1 -1
  227. package/dist/document-ingest-foundation/index.js +1 -1
  228. package/dist/feature-toggles/feature.d.ts +1 -1
  229. package/dist/feature-toggles/feature.js +2 -2
  230. package/dist/feature-toggles/handlers/list.query.js +1 -1
  231. package/dist/feature-toggles/handlers/registered.query.js +1 -1
  232. package/dist/feature-toggles/handlers/set.write.js +1 -1
  233. package/dist/feature-toggles/index.d.ts +1 -1
  234. package/dist/feature-toggles/index.js +1 -1
  235. package/dist/feature-toggles/web/client-plugin.js +1 -2
  236. package/dist/feature-toggles/{constants.js → web/constants.js} +0 -1
  237. package/dist/feature-toggles/web/index.js +0 -1
  238. package/dist/folders/feature.js +1 -1
  239. package/dist/folders/handlers/clear-folder.write.js +1 -1
  240. package/dist/folders/handlers/delete-folder.write.js +1 -1
  241. package/dist/folders/handlers/set-folder.write.js +1 -1
  242. package/dist/folders/index.d.ts +1 -1
  243. package/dist/folders/index.js +1 -1
  244. package/dist/folders/web/client-plugin.js +1 -2
  245. package/dist/folders/{constants.js → web/constants.js} +0 -1
  246. package/dist/folders/web/folder-manager.js +1 -2
  247. package/dist/folders/web/folder-section.js +1 -2
  248. package/dist/folders/web/i18n.js +0 -1
  249. package/dist/folders/web/index.d.ts +1 -1
  250. package/dist/folders/web/index.js +1 -2
  251. package/dist/folders/web/tree.js +0 -1
  252. package/dist/form-draft/db/queries/cleanup.d.ts +3 -2
  253. package/dist/form-draft/db/queries/cleanup.js +18 -9
  254. package/dist/form-draft/decrypt-draft.d.ts +2 -0
  255. package/dist/form-draft/decrypt-draft.js +19 -0
  256. package/dist/form-draft/entity.js +6 -9
  257. package/dist/form-draft/feature.js +1 -1
  258. package/dist/form-draft/handlers/cleanup.job.d.ts +1 -0
  259. package/dist/form-draft/handlers/cleanup.job.js +17 -4
  260. package/dist/form-draft/handlers/discard.write.js +1 -1
  261. package/dist/form-draft/handlers/get.query.js +6 -7
  262. package/dist/form-draft/handlers/list.query.js +11 -7
  263. package/dist/form-draft/handlers/save.write.js +1 -1
  264. package/dist/form-draft/index.d.ts +1 -1
  265. package/dist/form-draft/index.js +1 -1
  266. package/dist/form-draft/lookup.d.ts +2 -2
  267. package/dist/form-draft/lookup.js +7 -2
  268. package/dist/form-draft/schemas.js +1 -1
  269. package/dist/form-draft/{constants.js → web/constants.js} +0 -1
  270. package/dist/form-draft-user-data/hooks.js +2 -2
  271. package/dist/inbound-mail-foundation/retention-sweep.js +7 -5
  272. package/dist/jobs/feature.js +2 -2
  273. package/dist/jobs/handlers/retry.write.js +1 -1
  274. package/dist/jobs/handlers/trigger.write.js +1 -1
  275. package/dist/jobs/index.d.ts +1 -1
  276. package/dist/jobs/index.js +1 -1
  277. package/dist/jobs/web/client-plugin.js +2 -3
  278. package/dist/jobs/{constants.js → web/constants.js} +0 -1
  279. package/dist/jobs/web/default-translations.d.ts +2 -0
  280. package/dist/jobs/web/default-translations.js +3 -0
  281. package/dist/jobs/web/i18n.d.ts +5 -2
  282. package/dist/jobs/web/i18n.js +51 -4
  283. package/dist/jobs/web/index.js +0 -1
  284. package/dist/ledger/entity.d.ts +1 -1
  285. package/dist/ledger/entity.js +1 -1
  286. package/dist/ledger/feature.js +1 -1
  287. package/dist/ledger/handlers/confirm-schedule-period.write.js +2 -5
  288. package/dist/ledger/handlers/create-transaction.write.js +1 -1
  289. package/dist/ledger/handlers/reports.query.js +1 -1
  290. package/dist/ledger/handlers/reverse-transaction.write.js +1 -1
  291. package/dist/ledger/index.d.ts +1 -1
  292. package/dist/ledger/index.js +1 -1
  293. package/dist/ledger/recurring.d.ts +1 -1
  294. package/dist/ledger/reports.d.ts +1 -1
  295. package/dist/ledger/schemas.js +1 -1
  296. package/dist/ledger/{constants.js → web/constants.js} +0 -1
  297. package/dist/ledger/web/index.d.ts +1 -1
  298. package/dist/ledger/web/index.js +1 -2
  299. package/dist/legal-pages/feature.d.ts +1 -1
  300. package/dist/legal-pages/feature.js +1 -1
  301. package/dist/legal-pages/index.d.ts +1 -1
  302. package/dist/legal-pages/index.js +1 -1
  303. package/dist/legal-pages/lib/boot-check.d.ts +1 -1
  304. package/dist/legal-pages/lib/boot-check.js +1 -1
  305. package/dist/legal-pages/lib/validate-routes.d.ts +1 -1
  306. package/dist/legal-pages/web/client-plugin.js +1 -2
  307. package/dist/legal-pages/{constants.js → web/constants.js} +6 -8
  308. package/dist/legal-pages/web/index.js +0 -1
  309. package/dist/managed-pages/feature.js +1 -1
  310. package/dist/managed-pages/web/client-plugin.js +1 -2
  311. package/dist/managed-pages/web/default-translations.d.ts +2 -0
  312. package/dist/managed-pages/web/default-translations.js +11 -0
  313. package/dist/managed-pages/web/i18n.d.ts +5 -2
  314. package/dist/managed-pages/web/i18n.js +53 -12
  315. package/dist/managed-pages/web/index.d.ts +1 -1
  316. package/dist/managed-pages/web/index.js +1 -2
  317. package/dist/metrics/compute.d.ts +1 -1
  318. package/dist/metrics/compute.js +1 -1
  319. package/dist/metrics/feature.js +1 -1
  320. package/dist/metrics/index.d.ts +1 -1
  321. package/dist/metrics/index.js +1 -1
  322. package/dist/metrics/types.d.ts +1 -1
  323. package/dist/metrics/validate.js +1 -1
  324. package/dist/metrics/{constants.js → web/constants.js} +0 -1
  325. package/dist/metrics/window.d.ts +1 -1
  326. package/dist/notes-history/feature.js +1 -1
  327. package/dist/notes-history/handlers/add-note.write.js +1 -1
  328. package/dist/notes-history/index.d.ts +1 -1
  329. package/dist/notes-history/index.js +1 -1
  330. package/dist/notes-history/web/client-plugin.js +1 -2
  331. package/dist/notes-history/{constants.js → web/constants.js} +0 -1
  332. package/dist/notes-history/web/i18n.js +0 -1
  333. package/dist/notes-history/web/index.d.ts +1 -1
  334. package/dist/notes-history/web/index.js +1 -2
  335. package/dist/notes-history/web/notes-section.js +2 -3
  336. package/dist/personal-access-tokens/feature.d.ts +2 -2
  337. package/dist/personal-access-tokens/feature.js +6 -4
  338. package/dist/personal-access-tokens/handlers/available-scopes.query.d.ts +1 -1
  339. package/dist/personal-access-tokens/handlers/create.write.js +1 -1
  340. package/dist/personal-access-tokens/handlers/revoke.write.js +1 -1
  341. package/dist/personal-access-tokens/hash.js +1 -1
  342. package/dist/personal-access-tokens/i18n.d.ts +1 -1
  343. package/dist/personal-access-tokens/i18n.js +1 -1
  344. package/dist/personal-access-tokens/index.d.ts +5 -5
  345. package/dist/personal-access-tokens/index.js +3 -3
  346. package/dist/personal-access-tokens/resolver.d.ts +1 -1
  347. package/dist/personal-access-tokens/resolver.js +1 -1
  348. package/dist/personal-access-tokens/schema/api-token.js +1 -1
  349. package/dist/personal-access-tokens/screens.d.ts +1 -1
  350. package/dist/personal-access-tokens/screens.js +1 -1
  351. package/dist/personal-access-tokens/{constants.js → web/constants.js} +0 -1
  352. package/dist/presets/index.d.ts +0 -1
  353. package/dist/presets/index.js +0 -1
  354. package/dist/presets/security-baseline.d.ts +1 -1
  355. package/dist/presets/security-baseline.js +1 -1
  356. package/dist/secrets/feature.js +1 -1
  357. package/dist/secrets/handlers/delete.write.js +1 -1
  358. package/dist/secrets/handlers/list.query.js +1 -1
  359. package/dist/secrets/handlers/set.write.js +1 -1
  360. package/dist/secrets/i18n.js +1 -1
  361. package/dist/secrets/index.d.ts +1 -1
  362. package/dist/secrets/index.js +1 -1
  363. package/dist/secrets/{constants.js → web/constants.js} +0 -1
  364. package/dist/secrets/write-gate.js +1 -1
  365. package/dist/sessions/feature.js +7 -4
  366. package/dist/sessions/{i18n.js → web/i18n.js} +0 -1
  367. package/dist/shared/index.d.ts +1 -1
  368. package/dist/shared/index.js +1 -1
  369. package/dist/shared/purge-files-reaching-subject.js +7 -3
  370. package/dist/subscription-stripe/feature.js +2 -1
  371. package/dist/subscription-stripe/plugin-methods.d.ts +3 -0
  372. package/dist/subscription-stripe/plugin-methods.js +14 -0
  373. package/dist/subscription-stripe/verify-webhook.js +1 -0
  374. package/dist/tags/feature.js +1 -1
  375. package/dist/tags/handlers/assign-tag.write.js +11 -7
  376. package/dist/tags/handlers/create-tag.write.js +1 -1
  377. package/dist/tags/handlers/delete-tag.write.js +4 -1
  378. package/dist/tags/handlers/remove-tag.write.js +1 -1
  379. package/dist/tags/handlers/update-tag.write.js +1 -1
  380. package/dist/tags/index.d.ts +1 -1
  381. package/dist/tags/index.js +1 -1
  382. package/dist/tags/screens.js +1 -1
  383. package/dist/tags/web/client-plugin.js +1 -2
  384. package/dist/tags/{constants.d.ts → web/constants.d.ts} +1 -0
  385. package/dist/tags/{constants.js → web/constants.js} +3 -1
  386. package/dist/tags/web/entity-tags.js +1 -2
  387. package/dist/tags/web/i18n.js +2 -2
  388. package/dist/tags/web/index.d.ts +1 -1
  389. package/dist/tags/web/index.js +1 -2
  390. package/dist/tags/web/tag-filter.js +1 -2
  391. package/dist/tags/web/tag-manager.js +5 -4
  392. package/dist/tags/web/tag-picker.js +0 -1
  393. package/dist/tags/web/tag-section.js +1 -2
  394. package/dist/tags/web/tags-cell.js +1 -2
  395. package/dist/template-resolver/api.d.ts +21 -23
  396. package/dist/template-resolver/api.js +34 -6
  397. package/dist/template-resolver/compile-document-body.js +1 -1
  398. package/dist/template-resolver/compile-steps-block.js +2 -2
  399. package/dist/template-resolver/document-ops.d.ts +1 -1
  400. package/dist/template-resolver/document-ops.js +3 -3
  401. package/dist/template-resolver/document-sanitizer.d.ts +1 -1
  402. package/dist/template-resolver/document-sanitizer.js +3 -3
  403. package/dist/template-resolver/feature.d.ts +2 -0
  404. package/dist/template-resolver/feature.js +12 -4
  405. package/dist/template-resolver/handlers/by-slug.query.js +6 -1
  406. package/dist/template-resolver/handlers/by-tenant.query.js +6 -2
  407. package/dist/template-resolver/handlers/collection-item.query.js +1 -1
  408. package/dist/template-resolver/handlers/collection-list.query.js +1 -1
  409. package/dist/template-resolver/handlers/collection-set.write.d.ts +2 -1
  410. package/dist/template-resolver/handlers/collection-set.write.js +14 -2
  411. package/dist/template-resolver/handlers/copy-locale.write.js +2 -2
  412. package/dist/template-resolver/handlers/diff-to-system.query.js +5 -1
  413. package/dist/template-resolver/handlers/discard-draft.write.js +1 -1
  414. package/dist/template-resolver/handlers/document-base.d.ts +1 -1
  415. package/dist/template-resolver/handlers/document-base.js +6 -1
  416. package/dist/template-resolver/handlers/document-blocks.query.d.ts +1 -1
  417. package/dist/template-resolver/handlers/document-blocks.query.js +2 -2
  418. package/dist/template-resolver/handlers/export-bundle.query.js +5 -2
  419. package/dist/template-resolver/handlers/find-by-id.query.js +4 -2
  420. package/dist/template-resolver/handlers/layout-source.query.js +5 -5
  421. package/dist/template-resolver/handlers/list.query.js +5 -2
  422. package/dist/template-resolver/handlers/overview.query.d.ts +10 -2
  423. package/dist/template-resolver/handlers/overview.query.js +44 -12
  424. package/dist/template-resolver/handlers/patch-draft.write.js +1 -1
  425. package/dist/template-resolver/handlers/resource-shared.js +1 -1
  426. package/dist/template-resolver/handlers/resource-upload.write.js +1 -1
  427. package/dist/template-resolver/handlers/send-test.write.js +2 -2
  428. package/dist/template-resolver/handlers/set.write.js +1 -1
  429. package/dist/template-resolver/handlers/shared.js +1 -1
  430. package/dist/template-resolver/handlers/template-gates.d.ts +1 -1
  431. package/dist/template-resolver/handlers/template-gates.js +1 -1
  432. package/dist/template-resolver/handlers/template-write.d.ts +1 -1
  433. package/dist/template-resolver/handlers/template-write.js +1 -1
  434. package/dist/template-resolver/handlers/usage.query.js +3 -2
  435. package/dist/template-resolver/handlers/validate.query.d.ts +1 -1
  436. package/dist/template-resolver/handlers/validate.query.js +3 -1
  437. package/dist/template-resolver/i18n.d.ts +3 -0
  438. package/dist/template-resolver/i18n.js +24 -0
  439. package/dist/template-resolver/index.d.ts +4 -3
  440. package/dist/template-resolver/index.js +3 -3
  441. package/dist/template-resolver/layout-appearance.js +1 -1
  442. package/dist/template-resolver/layout-regions.d.ts +1 -1
  443. package/dist/template-resolver/seeding.d.ts +4 -1
  444. package/dist/template-resolver/seeding.js +13 -7
  445. package/dist/template-resolver/store-template-resource.js +2 -2
  446. package/dist/template-resolver/table.js +1 -1
  447. package/dist/template-resolver/template-bundle.js +2 -2
  448. package/dist/template-resolver/template-delivery-policy.d.ts +22 -0
  449. package/dist/template-resolver/template-delivery-policy.js +40 -0
  450. package/dist/template-resolver/template-draft.d.ts +1 -1
  451. package/dist/template-resolver/template-draft.js +1 -1
  452. package/dist/template-resolver/template-edit-policy.d.ts +1 -1
  453. package/dist/template-resolver/template-edit-policy.js +1 -1
  454. package/dist/template-resolver/template-meta.d.ts +2 -2
  455. package/dist/template-resolver/template-meta.js +2 -2
  456. package/dist/template-resolver/template-preview.d.ts +1 -1
  457. package/dist/template-resolver/template-preview.js +8 -4
  458. package/dist/template-resolver/template-usage.d.ts +1 -1
  459. package/dist/template-resolver/template-usage.js +1 -1
  460. package/dist/template-resolver/template-validation.js +1 -1
  461. package/dist/template-resolver/testing.js +1 -1
  462. package/dist/template-resolver/user-content-table.js +1 -1
  463. package/dist/template-resolver/web/client-plugin.js +1 -2
  464. package/dist/template-resolver/{constants.d.ts → web/constants.d.ts} +1 -1
  465. package/dist/template-resolver/{constants.js → web/constants.js} +7 -10
  466. package/dist/template-resolver/web/document-editor-extensions.js +2 -2
  467. package/dist/template-resolver/web/document-editor.js +0 -1
  468. package/dist/template-resolver/{document-images.js → web/document-images.js} +0 -1
  469. package/dist/template-resolver/{document-schema.js → web/document-schema.js} +0 -1
  470. package/dist/template-resolver/{document-steps.js → web/document-steps.js} +0 -1
  471. package/dist/template-resolver/web/document-tiptap-editor.js +2 -3
  472. package/dist/template-resolver/web/document-toolbar-blocks.d.ts +2 -2
  473. package/dist/template-resolver/web/document-toolbar-blocks.js +1 -1
  474. package/dist/template-resolver/web/editor-handle.js +1 -1
  475. package/dist/template-resolver/web/i18n.js +1 -1
  476. package/dist/template-resolver/web/index.d.ts +3 -3
  477. package/dist/template-resolver/web/index.js +3 -4
  478. package/dist/template-resolver/{mail-constants.js → web/mail-constants.js} +0 -1
  479. package/dist/template-resolver/{pdf-constants.js → web/pdf-constants.js} +0 -1
  480. package/dist/template-resolver/web/placeholder-line-editor-lazy.js +0 -1
  481. package/dist/template-resolver/web/placeholder-line-editor.js +6 -4
  482. package/dist/template-resolver/{qualified-names.js → web/qualified-names.js} +0 -1
  483. package/dist/template-resolver/web/use-stable-by-key.js +0 -1
  484. package/dist/tenant/handlers/add-member.write.js +1 -1
  485. package/dist/tenant/index.d.ts +1 -1
  486. package/dist/tenant/index.js +1 -1
  487. package/dist/tenant/invitation-table.js +1 -1
  488. package/dist/tenant/invited-membership.js +1 -1
  489. package/dist/tenant/last-tenant-admin.js +1 -1
  490. package/dist/tenant/member-role-options.js +1 -1
  491. package/dist/tenant/screens.js +1 -1
  492. package/dist/tenant/web/client-plugin.js +1 -2
  493. package/dist/tenant/{constants.js → web/constants.js} +3 -6
  494. package/dist/tenant/web/index.js +0 -1
  495. package/dist/tenant/web/member-roles-cell.js +0 -1
  496. package/dist/tenant/web/member-status-cell.js +0 -1
  497. package/dist/tenant-lifecycle/stages.js +2 -3
  498. package/dist/tier-engine/entity.d.ts +1 -1
  499. package/dist/tier-engine/entity.js +1 -1
  500. package/dist/tier-engine/feature.js +2 -2
  501. package/dist/tier-engine/handlers/set-tenant-tier.write.js +1 -1
  502. package/dist/tier-engine/index.d.ts +1 -1
  503. package/dist/tier-engine/index.js +1 -1
  504. package/dist/tier-engine/web/client-plugin.js +2 -3
  505. package/dist/tier-engine/{constants.js → web/constants.js} +2 -3
  506. package/dist/tier-engine/{i18n.js → web/i18n.js} +0 -1
  507. package/dist/tier-engine/web/index.js +0 -1
  508. package/dist/user/handlers/create.write.js +1 -1
  509. package/dist/user/handlers/update-roles.js +1 -1
  510. package/dist/user/handlers/update.write.js +1 -1
  511. package/dist/user/index.d.ts +1 -1
  512. package/dist/user/index.js +1 -1
  513. package/dist/user/invited-global-roles.d.ts +1 -1
  514. package/dist/user/invited-global-roles.js +1 -1
  515. package/dist/user/schema/user.js +1 -1
  516. package/dist/user/{constants.js → web/constants.js} +0 -1
  517. package/dist/user-data-rights/env.js +1 -1
  518. package/dist/user-data-rights/feature.js +3 -3
  519. package/dist/user-data-rights/index.d.ts +1 -1
  520. package/dist/user-data-rights/index.js +1 -1
  521. package/dist/user-data-rights/lib/resolve-tenant-model.js +1 -1
  522. package/dist/user-data-rights/mail-notifications.js +1 -1
  523. package/dist/user-data-rights/web/client-plugin.js +2 -3
  524. package/dist/user-data-rights/web/confirm-deletion-screen.js +0 -1
  525. package/dist/user-data-rights/{constants.js → web/constants.js} +11 -12
  526. package/dist/user-data-rights/web/default-translations.d.ts +2 -0
  527. package/dist/user-data-rights/web/default-translations.js +59 -0
  528. package/dist/user-data-rights/web/i18n.d.ts +5 -2
  529. package/dist/user-data-rights/web/i18n.js +37 -59
  530. package/dist/user-data-rights/web/index.d.ts +1 -1
  531. package/dist/user-data-rights/web/index.js +1 -2
  532. package/dist/user-data-rights/web/privacy-center-screen.js +1 -2
  533. package/dist/user-data-rights/web/request-deletion-screen.js +0 -1
  534. package/dist/user-data-rights-defaults/hooks/file-ref.userdata-hook.js +6 -1
  535. package/dist/user-profile/feature.js +1 -1
  536. package/dist/user-profile/handlers/change-email.write.js +1 -1
  537. package/dist/user-profile/index.d.ts +1 -1
  538. package/dist/user-profile/index.js +1 -1
  539. package/dist/user-profile/web/client-plugin.js +2 -3
  540. package/dist/user-profile/{constants.js → web/constants.js} +0 -1
  541. package/dist/user-profile/{i18n.js → web/i18n.js} +0 -1
  542. package/dist/user-profile/web/profile-screen.js +2 -3
  543. package/dist/waitlist/entity.js +1 -1
  544. package/dist/waitlist/feature.js +1 -1
  545. package/dist/waitlist/handlers/export-purge.write.js +1 -1
  546. package/dist/waitlist/handlers/invite.write.js +1 -1
  547. package/dist/waitlist/handlers/reject.write.js +1 -1
  548. package/dist/waitlist/handlers/submit.write.js +4 -3
  549. package/dist/waitlist/import.d.ts +1 -1
  550. package/dist/waitlist/index.d.ts +1 -1
  551. package/dist/waitlist/index.js +1 -1
  552. package/dist/waitlist/legacy-migrate.js +1 -1
  553. package/dist/waitlist/link-on-signup.js +1 -1
  554. package/dist/waitlist/mail.d.ts +0 -1
  555. package/dist/waitlist/mail.js +6 -4
  556. package/dist/waitlist/payloads.js +1 -1
  557. package/dist/waitlist/screens.js +1 -1
  558. package/dist/waitlist/{constants.js → web/constants.js} +0 -1
  559. package/kumiko-es-tables.json +102 -0
  560. package/package.json +30 -29
  561. package/src/audit/changes.json +7 -0
  562. package/src/auth-email-password/changes.json +6 -0
  563. package/src/auth-mfa/changes.json +6 -0
  564. package/src/billing-foundation/changes.json +18 -0
  565. package/src/delivery/changes.json +6 -0
  566. package/src/document-ingest-foundation/changes.json +6 -0
  567. package/src/files/changes.json +7 -0
  568. package/src/form-draft/changes.json +7 -0
  569. package/src/ledger/changes.json +7 -0
  570. package/src/presets/changes.json +7 -0
  571. package/src/tags/changes.json +6 -0
  572. package/src/template-resolver/changes.json +43 -0
  573. package/src/user-data-rights/changes.json +14 -0
  574. package/src/waitlist/changes.json +6 -0
  575. package/dist/admin-shell/i18n.d.ts +0 -5
  576. package/dist/admin-shell/i18n.js +0 -51
  577. package/dist/audit/i18n.d.ts +0 -5
  578. package/dist/audit/i18n.js +0 -22
  579. package/dist/jobs/i18n.d.ts +0 -5
  580. package/dist/jobs/i18n.js +0 -52
  581. package/dist/managed-pages/i18n.d.ts +0 -5
  582. package/dist/managed-pages/i18n.js +0 -55
  583. package/dist/presets/dsgvo-self-service.d.ts +0 -10
  584. package/dist/presets/dsgvo-self-service.js +0 -24
  585. package/dist/user-data-rights/i18n.d.ts +0 -5
  586. package/dist/user-data-rights/i18n.js +0 -39
  587. /package/dist/account-security/{constants.d.ts → web/constants.d.ts} +0 -0
  588. /package/dist/account-security/{i18n.d.ts → web/i18n.d.ts} +0 -0
  589. /package/dist/admin-shell/{constants.d.ts → web/constants.d.ts} +0 -0
  590. /package/dist/auth-email-password/{constants.d.ts → web/constants.d.ts} +0 -0
  591. /package/dist/auth-email-password/{i18n.d.ts → web/i18n.d.ts} +0 -0
  592. /package/dist/auth-email-password/{mail-i18n.d.ts → web/mail-i18n.d.ts} +0 -0
  593. /package/dist/auth-mfa/{constants.d.ts → web/constants.d.ts} +0 -0
  594. /package/dist/billing-foundation/{consumer-protection → web/consumer-protection}/consent-locale.d.ts +0 -0
  595. /package/dist/billing-foundation/{contact-card.d.ts → web/contact-card.d.ts} +0 -0
  596. /package/dist/cap-overview/{constants.d.ts → web/constants.d.ts} +0 -0
  597. /package/dist/cap-overview/{usage-math.js → web/usage-math.js} +0 -0
  598. /package/dist/compliance-profiles/{constants.d.ts → web/constants.d.ts} +0 -0
  599. /package/dist/config/{constants.d.ts → web/constants.d.ts} +0 -0
  600. /package/dist/custom-fields/{constants.d.ts → web/constants.d.ts} +0 -0
  601. /package/dist/delivery/{public-names.d.ts → web/public-names.d.ts} +0 -0
  602. /package/dist/feature-toggles/{constants.d.ts → web/constants.d.ts} +0 -0
  603. /package/dist/folders/{constants.d.ts → web/constants.d.ts} +0 -0
  604. /package/dist/form-draft/{constants.d.ts → web/constants.d.ts} +0 -0
  605. /package/dist/jobs/{constants.d.ts → web/constants.d.ts} +0 -0
  606. /package/dist/ledger/{constants.d.ts → web/constants.d.ts} +0 -0
  607. /package/dist/legal-pages/{constants.d.ts → web/constants.d.ts} +0 -0
  608. /package/dist/metrics/{constants.d.ts → web/constants.d.ts} +0 -0
  609. /package/dist/notes-history/{constants.d.ts → web/constants.d.ts} +0 -0
  610. /package/dist/personal-access-tokens/{constants.d.ts → web/constants.d.ts} +0 -0
  611. /package/dist/personal-access-tokens/{scopes.d.ts → web/scopes.d.ts} +0 -0
  612. /package/dist/personal-access-tokens/{scopes.js → web/scopes.js} +0 -0
  613. /package/dist/secrets/{constants.d.ts → web/constants.d.ts} +0 -0
  614. /package/dist/sessions/{i18n.d.ts → web/i18n.d.ts} +0 -0
  615. /package/dist/template-resolver/{document-blocks.d.ts → web/document-blocks.d.ts} +0 -0
  616. /package/dist/template-resolver/{document-blocks.js → web/document-blocks.js} +0 -0
  617. /package/dist/template-resolver/{document-images.d.ts → web/document-images.d.ts} +0 -0
  618. /package/dist/template-resolver/{document-schema.d.ts → web/document-schema.d.ts} +0 -0
  619. /package/dist/template-resolver/{document-steps.d.ts → web/document-steps.d.ts} +0 -0
  620. /package/dist/template-resolver/{mail-constants.d.ts → web/mail-constants.d.ts} +0 -0
  621. /package/dist/template-resolver/{pdf-constants.d.ts → web/pdf-constants.d.ts} +0 -0
  622. /package/dist/template-resolver/{placeholder-text.d.ts → web/placeholder-text.d.ts} +0 -0
  623. /package/dist/template-resolver/{placeholder-text.js → web/placeholder-text.js} +0 -0
  624. /package/dist/template-resolver/{qualified-names.d.ts → web/qualified-names.d.ts} +0 -0
  625. /package/dist/tenant/{constants.d.ts → web/constants.d.ts} +0 -0
  626. /package/dist/tier-engine/{constants.d.ts → web/constants.d.ts} +0 -0
  627. /package/dist/tier-engine/{i18n.d.ts → web/i18n.d.ts} +0 -0
  628. /package/dist/user/{constants.d.ts → web/constants.d.ts} +0 -0
  629. /package/dist/user-data-rights/{constants.d.ts → web/constants.d.ts} +0 -0
  630. /package/dist/user-profile/{constants.d.ts → web/constants.d.ts} +0 -0
  631. /package/dist/user-profile/{i18n.d.ts → web/i18n.d.ts} +0 -0
  632. /package/dist/waitlist/{constants.d.ts → web/constants.d.ts} +0 -0
@@ -7,10 +7,10 @@ import { UnprocessableError } from "@cosmicdrift/kumiko-framework/errors";
7
7
  import * as z from "zod";
8
8
  import { subscriptionAggregateId, terminationUnmatchedAggregateId } from "../aggregate-id.js";
9
9
  import { resolveProviderPlugin } from "../checkout-core.js";
10
- import { isTerminalSubscriptionStatus, SubscriptionCancelTimings } from "../constants.js";
11
- import { CONTRACT_TERMINATION_CHANNELS, CONTRACT_TERMINATION_DECLARATION_TYPES, CONTRACT_TERMINATION_DECLARED_EVENT_QN, CONTRACT_TERMINATION_KINDS, CONTRACT_TERMINATION_REQUESTED_EVENT_QN, CONTRACT_TERMINATION_UNMATCHED_AGGREGATE_TYPE, CONTRACT_TERMINATION_UNMATCHED_EVENT_QN, contractTerminationRequestedPayloadSchema, SUBSCRIPTION_AGGREGATE_TYPE, } from "../events.js";
10
+ import { CONTRACT_TERMINATION_CHANNELS, CONTRACT_TERMINATION_DECLARATION_TYPES, CONTRACT_TERMINATION_DECLARED_EVENT_QN, CONTRACT_TERMINATION_KINDS, CONTRACT_TERMINATION_REQUESTED_EVENT_QN, CONTRACT_TERMINATION_REVOKED_EVENT_QN, CONTRACT_TERMINATION_UNMATCHED_AGGREGATE_TYPE, CONTRACT_TERMINATION_UNMATCHED_EVENT_QN, contractTerminationRequestedPayloadSchema, contractTerminationRevokedPayloadSchema, SUBSCRIPTION_AGGREGATE_TYPE, } from "../events.js";
12
11
  import { getSubscriptionForTenant } from "../get-subscription-for-tenant.js";
13
- import { CONSENT_LOCALES, FALLBACK_CONSENT_LOCALE } from "./consent-locale.js";
12
+ import { isTerminalSubscriptionStatus, SubscriptionCancelTimings } from "../web/constants.js";
13
+ import { CONSENT_LOCALES, FALLBACK_CONSENT_LOCALE, } from "../web/consumer-protection/consent-locale.js";
14
14
  import { notifyOperator } from "./termination-notify.js";
15
15
  import { isWithinWithdrawalPeriod } from "./withdrawal-period.js";
16
16
  const REQUESTED_CANCEL_TIMINGS = [
@@ -38,6 +38,7 @@ export const declareContractTerminationSchema = z
38
38
  terminationKind: z.enum(CONTRACT_TERMINATION_KINDS),
39
39
  receivedAtIso: z.string().min(1),
40
40
  locale: z.enum(CONSENT_LOCALES),
41
+ revocationTokenHash: z.string().length(64).optional(),
41
42
  })
42
43
  .strict();
43
44
  export const recordUnmatchedContractTerminationSchema = z
@@ -114,6 +115,42 @@ export function createDeclareContractTerminationHandler() {
114
115
  },
115
116
  };
116
117
  }
118
+ function revokedRecordResult(receivedAtIso) {
119
+ return {
120
+ isSuccess: true,
121
+ data: {
122
+ receivedAtIso,
123
+ effectiveAtIso: null,
124
+ providerCancel: "none",
125
+ noticeReason: null,
126
+ withdrawalPeriodExpired: false,
127
+ },
128
+ };
129
+ }
130
+ // A revocation that landed during the provider cancel found nothing to take back yet.
131
+ async function takeBackLateRevokedCancel(ctx, consumerProtection, args) {
132
+ const { payload, tenantId, receivedAtIso, providerCancel } = args;
133
+ // skip: nothing was cancelled at the provider, nothing to resume
134
+ if (providerCancel !== "period-end")
135
+ return;
136
+ const reasons = await resumeAtProvider(ctx, await getSubscriptionForTenant(ctx, tenantId));
137
+ // skip: resumed cleanly, the revocation notice already tells the operator
138
+ if (reasons.length === 0)
139
+ return;
140
+ await notifyOperator(ctx, consumerProtection, {
141
+ locale: payload.locale ?? FALLBACK_CONSENT_LOCALE,
142
+ requestId: payload.requestId,
143
+ receivedAtIso,
144
+ channel: "public",
145
+ declaration: {
146
+ declarationType: payload.declarationType,
147
+ terminationKind: payload.terminationKind,
148
+ },
149
+ reasons,
150
+ tenantId,
151
+ providerCancel,
152
+ });
153
+ }
117
154
  export function createRecordContractTerminationHandler(options, consumerProtection) {
118
155
  return {
119
156
  name: "record-contract-termination",
@@ -153,6 +190,10 @@ export function createRecordContractTerminationHandler(options, consumerProtecti
153
190
  },
154
191
  };
155
192
  }
193
+ // A revoked public declaration never reaches the provider.
194
+ if (hasRevocation(stream.events, payload.requestId)) {
195
+ return revokedRecordResult(receivedAtIso);
196
+ }
156
197
  const withdrawalPeriodExpired = payload.declarationType === "withdrawal" &&
157
198
  payload.when === SubscriptionCancelTimings.immediately &&
158
199
  !isWithinWithdrawalPeriod(stream.events, options.now());
@@ -173,6 +214,16 @@ export function createRecordContractTerminationHandler(options, consumerProtecti
173
214
  aggregateId: subscriptionAggregateId(tenantId),
174
215
  aggregateType: SUBSCRIPTION_AGGREGATE_TYPE,
175
216
  });
217
+ // A revocation that landed during the provider call found no cancel to take back.
218
+ if (hasRevocation(streamAfterProviderCall.events, payload.requestId)) {
219
+ await takeBackLateRevokedCancel(ctx, consumerProtection, {
220
+ payload,
221
+ tenantId,
222
+ receivedAtIso,
223
+ providerCancel,
224
+ });
225
+ return revokedRecordResult(receivedAtIso);
226
+ }
176
227
  await streamAfterProviderCall.appendOne({
177
228
  type: CONTRACT_TERMINATION_REQUESTED_EVENT_QN,
178
229
  payload: recorded,
@@ -207,6 +258,28 @@ export function createRecordContractTerminationHandler(options, consumerProtecti
207
258
  },
208
259
  };
209
260
  }
261
+ export function hasRevocation(events, requestId) {
262
+ return events.some((e) => e.type === CONTRACT_TERMINATION_REVOKED_EVENT_QN &&
263
+ contractTerminationRevokedPayloadSchema.safeParse(e.payload).data?.requestId === requestId);
264
+ }
265
+ export async function resumeAtProvider(ctx, subscription) {
266
+ if (subscription === null || isTerminalSubscriptionStatus(subscription.status)) {
267
+ return ["revocation_resume_manual"];
268
+ }
269
+ const plugin = findPlugin(ctx, subscription.providerName);
270
+ if (!plugin?.resumeSubscription)
271
+ return ["revocation_resume_manual"];
272
+ try {
273
+ await plugin.resumeSubscription(ctx, {
274
+ providerSubscriptionId: subscription.providerSubscriptionId,
275
+ });
276
+ }
277
+ catch (error) {
278
+ ctx.log?.warn(`[billing-foundation:revoke-contract-termination] provider resume failed: ${error instanceof Error ? error.message : String(error)}`);
279
+ return ["revocation_resume_failed"];
280
+ }
281
+ return [];
282
+ }
210
283
  function findPlugin(ctx, providerName) {
211
284
  try {
212
285
  return resolveProviderPlugin(ctx, providerName).plugin;
@@ -8,13 +8,15 @@ import { generateId } from "@cosmicdrift/kumiko-framework/utils";
8
8
  import * as z from "zod";
9
9
  import { TenantQueries } from "../../tenant/index.js";
10
10
  import { UserQueries } from "../../user/index.js";
11
- import { CONTRACT_TERMINATION_RECEIPT_NOTIFICATION_TYPE, SubscriptionCancelTimings, SubscriptionFoundationHandlers, SubscriptionFoundationQueries, } from "../constants.js";
12
11
  import { CONTRACT_TERMINATION_DECLARATION_TYPES, CONTRACT_TERMINATION_KINDS, } from "../events.js";
13
12
  import { purchaseRolesOf } from "../plan-catalog.js";
13
+ import { CONTRACT_TERMINATION_RECEIPT_NOTIFICATION_TYPE, SubscriptionCancelTimings, SubscriptionFoundationHandlers, SubscriptionFoundationQueries, } from "../web/constants.js";
14
14
  import { resolveConsentLocale } from "./consent-text.js";
15
+ import { openStoredUserEmail } from "./stored-user-email.js";
15
16
  import { terminationReceiptVariables } from "./termination-mail.js";
16
17
  import { notifyOperator, requireNotify } from "./termination-notify.js";
17
18
  import { mayMailReceipt } from "./termination-receipt-limit.js";
19
+ import { createRevocationToken, revocationUrl } from "./termination-revoke.js";
18
20
  const EXTRAORDINARY_REASON_MESSAGE = "reason is required for an extraordinary termination";
19
21
  const authUserRowSchema = z.object({
20
22
  id: z.string().min(1),
@@ -66,6 +68,7 @@ async function sendTerminationMails(ctx, consumerProtection, plan) {
66
68
  terminationKind: plan.declaration.terminationKind,
67
69
  },
68
70
  operatorEmail: consumerProtection.operatorEmail,
71
+ ...(plan.revokeUrl !== undefined && { revokeUrl: plan.revokeUrl }),
69
72
  }),
70
73
  locale: plan.locale,
71
74
  priority: "critical",
@@ -77,7 +80,8 @@ async function sendTerminationMails(ctx, consumerProtection, plan) {
77
80
  // skip: no operator notice needed for this declaration
78
81
  if (reasons.length === 0)
79
82
  return;
80
- await notifyOperator(ctx, consumerProtection, { ...plan, reasons });
83
+ const { revokeUrl: _revokeUrl, ...noticePlan } = plan;
84
+ await notifyOperator(ctx, consumerProtection, { ...noticePlan, reasons });
81
85
  }
82
86
  // Tenants the entered email can terminate a contract for: tenants where the
83
87
  // user holds a purchase role and the subscription is not terminal. Every identity
@@ -128,13 +132,32 @@ export function createRequestContractTerminationHandler(options, consumerProtect
128
132
  const reasons = [];
129
133
  const locale = resolveConsentLocale(payload.locale);
130
134
  let matchedTenantId;
135
+ let revokeUrl;
131
136
  const candidates = await findTerminableTenantIds(ctx, options, event.user.tenantId, payload.email);
132
137
  const [onlyCandidate] = candidates;
133
138
  if (candidates.length === 1 && onlyCandidate !== undefined) {
134
139
  matchedTenantId = onlyCandidate;
135
- const declared = await ctx.writeAs(createSystemUser(onlyCandidate), SubscriptionFoundationHandlers.declareContractTermination, { requestId, declarationType, terminationKind, receivedAtIso, locale });
136
- if (!declared.isSuccess)
140
+ const revocation = createRevocationToken();
141
+ const declared = await ctx.writeAs(createSystemUser(onlyCandidate), SubscriptionFoundationHandlers.declareContractTermination, {
142
+ requestId,
143
+ declarationType,
144
+ terminationKind,
145
+ receivedAtIso,
146
+ locale,
147
+ revocationTokenHash: revocation.tokenHash,
148
+ });
149
+ if (!declared.isSuccess) {
137
150
  reasons.push("recording_failed");
151
+ }
152
+ else if (options.baseUrl !== undefined) {
153
+ revokeUrl = revocationUrl({
154
+ baseUrl: options.baseUrl,
155
+ locale,
156
+ requestId,
157
+ token: revocation.token,
158
+ tenantId: onlyCandidate,
159
+ });
160
+ }
138
161
  }
139
162
  else {
140
163
  reasons.push(candidates.length === 0 ? "unmatched" : "ambiguous");
@@ -166,6 +189,7 @@ export function createRequestContractTerminationHandler(options, consumerProtect
166
189
  },
167
190
  reasons,
168
191
  ...(matchedTenantId !== undefined && { tenantId: matchedTenantId }),
192
+ ...(revokeUrl !== undefined && { revokeUrl }),
169
193
  });
170
194
  return {
171
195
  isSuccess: true,
@@ -192,7 +216,10 @@ export function createTerminateContractHandler(options, consumerProtection) {
192
216
  const caller = authUserRowSchema.safeParse(await ctx.queryAs(createSystemUser(tenantId), UserQueries.findForAuth, {
193
217
  id: event.user.id,
194
218
  }));
195
- if (!caller.success || !caller.data.email || caller.data.isDeleted === true) {
219
+ const callerEmail = caller.success && caller.data.email && caller.data.isDeleted !== true
220
+ ? await openStoredUserEmail(caller.data.email, "billing-foundation:terminate-contract")
221
+ : null;
222
+ if (callerEmail === null) {
196
223
  throw new InternalError({
197
224
  message: "billing-foundation:terminate-contract: calling user has no email on record",
198
225
  });
@@ -218,7 +245,7 @@ export function createTerminateContractHandler(options, consumerProtection) {
218
245
  declaration: {
219
246
  declarationType,
220
247
  terminationKind,
221
- email: caller.data.email,
248
+ email: callerEmail,
222
249
  ...(payload.reason !== undefined && { reason: payload.reason }),
223
250
  },
224
251
  reasons: [
@@ -0,0 +1,28 @@
1
+ import { type WriteHandlerDef } from "@cosmicdrift/kumiko-framework/engine";
2
+ import * as z from "zod";
3
+ import type { ConsumerProtectionOptions, ResolvedBillingFoundationOptions } from "../types.ts";
4
+ import type { ConsentLocale } from "./consent-text.ts";
5
+ export declare const REVOCATION_PATHS: Readonly<Record<ConsentLocale, string>>;
6
+ export type RevocationOutcome = "revoked" | "already-revoked" | "too-late" | "invalid";
7
+ export declare function createRevocationToken(): {
8
+ readonly token: string;
9
+ readonly tokenHash: string;
10
+ };
11
+ export declare function revocationUrl(args: {
12
+ readonly baseUrl: string;
13
+ readonly locale: ConsentLocale;
14
+ readonly requestId: string;
15
+ readonly token: string;
16
+ readonly tenantId: string;
17
+ }): string;
18
+ export declare const revokeContractTerminationSchema: z.ZodObject<{
19
+ requestId: z.ZodString;
20
+ token: z.ZodString;
21
+ tenantId: z.ZodUUID;
22
+ }, z.core.$strict>;
23
+ export declare const recordContractTerminationRevocationSchema: z.ZodObject<{
24
+ requestId: z.ZodString;
25
+ token: z.ZodString;
26
+ }, z.core.$strict>;
27
+ export declare function createRevokeContractTerminationHandler(): WriteHandlerDef;
28
+ export declare function createRecordContractTerminationRevocationHandler(options: ResolvedBillingFoundationOptions, consumerProtection: ConsumerProtectionOptions): WriteHandlerDef;
@@ -0,0 +1,149 @@
1
+ // "This cancellation was not me": the signed link in the receipt mail of a
2
+ // matched public declaration takes the cancellation back until it takes effect.
3
+ // The anonymous handler only routes to the declaration's tenant; the system
4
+ // handler checks the token and does the work.
5
+ import { createHash, timingSafeEqual } from "node:crypto";
6
+ import { access, createSystemUser, } from "@cosmicdrift/kumiko-framework/engine";
7
+ import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
8
+ import * as z from "zod";
9
+ import { subscriptionAggregateId } from "../aggregate-id.js";
10
+ import { CONTRACT_TERMINATION_DECLARED_EVENT_QN, CONTRACT_TERMINATION_REQUESTED_EVENT_QN, CONTRACT_TERMINATION_REVOKED_EVENT_QN, contractTerminationDeclaredPayloadSchema, contractTerminationRequestedPayloadSchema, SUBSCRIPTION_AGGREGATE_TYPE, } from "../events.js";
11
+ import { getSubscriptionForTenant } from "../get-subscription-for-tenant.js";
12
+ import { SubscriptionFoundationHandlers } from "../web/constants.js";
13
+ import { notifyOperator } from "./termination-notify.js";
14
+ import { hasRevocation, resumeAtProvider } from "./termination-record.js";
15
+ export const REVOCATION_PATHS = {
16
+ de: "/legal/kuendigen/zuruecknehmen",
17
+ en: "/legal/cancel/revoke",
18
+ };
19
+ const TOKEN_BYTES = 32;
20
+ export function createRevocationToken() {
21
+ const token = Buffer.from(crypto.getRandomValues(new Uint8Array(TOKEN_BYTES))).toString("base64url");
22
+ return { token, tokenHash: hashRevocationToken(token) };
23
+ }
24
+ function hashRevocationToken(token) {
25
+ return createHash("sha256").update(token).digest("hex");
26
+ }
27
+ function tokenMatchesHash(token, expectedHash) {
28
+ const actual = Buffer.from(hashRevocationToken(token));
29
+ const expected = Buffer.from(expectedHash);
30
+ return actual.length === expected.length && timingSafeEqual(actual, expected);
31
+ }
32
+ export function revocationUrl(args) {
33
+ // Origin only: a baseUrl path prefix would not match the routes mounted at the root.
34
+ const url = new URL(REVOCATION_PATHS[args.locale], new URL(args.baseUrl).origin);
35
+ url.searchParams.set("r", args.requestId);
36
+ url.searchParams.set("t", args.token);
37
+ url.searchParams.set("tenant", args.tenantId);
38
+ return url.toString();
39
+ }
40
+ const revocationFieldsSchema = {
41
+ requestId: z.string().min(1).max(100),
42
+ token: z.string().min(1).max(200),
43
+ };
44
+ export const revokeContractTerminationSchema = z
45
+ .object({ ...revocationFieldsSchema, tenantId: z.uuid() })
46
+ .strict();
47
+ export const recordContractTerminationRevocationSchema = z.object(revocationFieldsSchema).strict();
48
+ function parseOutcome(data) {
49
+ const parsed = z
50
+ .object({ outcome: z.enum(["revoked", "already-revoked", "too-late", "invalid"]) })
51
+ .safeParse(data);
52
+ return parsed.success ? parsed.data.outcome : "invalid";
53
+ }
54
+ export function createRevokeContractTerminationHandler() {
55
+ return {
56
+ name: "revoke-contract-termination",
57
+ description: 'Public "this was not me" link of the § 312k receipt mail: takes a public cancellation back until it takes effect; an unknown request and a wrong token answer the same.',
58
+ schema: revokeContractTerminationSchema,
59
+ access: { roles: ["anonymous"] },
60
+ rateLimit: { per: "ip+handler", limit: 5, windowSeconds: 600 },
61
+ // The link only knows baseUrl, which may be a host that resolves no tenant; the token alone authorizes.
62
+ tenantlessAnonymous: true,
63
+ escapeHatch: {
64
+ reason: "Anonymous revoker has no session — writes as the system user of the tenant named in the link; only a declared event in that tenant whose revocationTokenHash matches the link token lets the revocation through, every other case answers the same generic invalid.",
65
+ },
66
+ handler: async (event, ctx) => {
67
+ // @cast-boundary engine-payload — dispatcher-zod-validated payload
68
+ const payload = event.payload;
69
+ const result = await ctx.writeAs(createSystemUser(payload.tenantId), SubscriptionFoundationHandlers.recordContractTerminationRevocation, { requestId: payload.requestId, token: payload.token });
70
+ return {
71
+ isSuccess: true,
72
+ data: { outcome: result.isSuccess ? parseOutcome(result.data) : "invalid" },
73
+ };
74
+ },
75
+ };
76
+ }
77
+ export function createRecordContractTerminationRevocationHandler(options, consumerProtection) {
78
+ return {
79
+ name: "record-contract-termination-revocation",
80
+ agent: { expose: false },
81
+ schema: recordContractTerminationRevocationSchema,
82
+ access: { roles: access.system },
83
+ handler: async (event, ctx) => {
84
+ // @cast-boundary engine-payload — dispatcher-zod-validated payload
85
+ const payload = event.payload;
86
+ const tenantId = event.user.tenantId;
87
+ const outcome = (value) => ({
88
+ isSuccess: true,
89
+ data: { outcome: value },
90
+ });
91
+ const stream = await ctx.fetchForWriting({
92
+ aggregateId: subscriptionAggregateId(tenantId),
93
+ aggregateType: SUBSCRIPTION_AGGREGATE_TYPE,
94
+ });
95
+ const declared = stream.events
96
+ .filter((e) => e.type === CONTRACT_TERMINATION_DECLARED_EVENT_QN)
97
+ .map((e) => contractTerminationDeclaredPayloadSchema.safeParse(e.payload).data)
98
+ .find((candidate) => candidate?.requestId === payload.requestId);
99
+ if (declared?.revocationTokenHash === undefined ||
100
+ !tokenMatchesHash(payload.token, declared.revocationTokenHash)) {
101
+ return outcome("invalid");
102
+ }
103
+ if (hasRevocation(stream.events, payload.requestId))
104
+ return outcome("already-revoked");
105
+ const requested = stream.events
106
+ .filter((e) => e.type === CONTRACT_TERMINATION_REQUESTED_EVENT_QN)
107
+ .map((e) => contractTerminationRequestedPayloadSchema.safeParse(e.payload).data)
108
+ .find((candidate) => candidate?.requestId === payload.requestId);
109
+ const subscription = await getSubscriptionForTenant(ctx, tenantId);
110
+ const effectiveAtIso = requested?.effectiveAtIso ?? subscription?.currentPeriodEnd.toString();
111
+ const now = options.now();
112
+ if (effectiveAtIso !== undefined &&
113
+ Temporal.Instant.compare(now, Temporal.Instant.from(effectiveAtIso)) >= 0) {
114
+ return outcome("too-late");
115
+ }
116
+ const reasons = ["revoked"];
117
+ if (requested?.providerCancel === "period-end") {
118
+ reasons.push(...(await resumeAtProvider(ctx, subscription)));
119
+ }
120
+ // Re-fetch after the external call, like record-contract-termination.
121
+ const streamAfterProviderCall = await ctx.fetchForWriting({
122
+ aggregateId: subscriptionAggregateId(tenantId),
123
+ aggregateType: SUBSCRIPTION_AGGREGATE_TYPE,
124
+ });
125
+ const revoked = {
126
+ requestId: payload.requestId,
127
+ revokedAtIso: now.toString(),
128
+ };
129
+ await streamAfterProviderCall.appendOne({
130
+ type: CONTRACT_TERMINATION_REVOKED_EVENT_QN,
131
+ payload: revoked,
132
+ });
133
+ await notifyOperator(ctx, consumerProtection, {
134
+ locale: declared.locale,
135
+ requestId: declared.requestId,
136
+ receivedAtIso: declared.receivedAtIso,
137
+ channel: "public",
138
+ declaration: {
139
+ declarationType: declared.declarationType,
140
+ terminationKind: declared.terminationKind,
141
+ },
142
+ reasons,
143
+ tenantId,
144
+ ...(requested !== undefined && { providerCancel: requested.providerCancel }),
145
+ });
146
+ return outcome("revoked");
147
+ },
148
+ };
149
+ }
@@ -16,6 +16,8 @@ export type TerminationTexts = {
16
16
  readonly receiptIntro: string;
17
17
  readonly receiptNextSteps: string;
18
18
  readonly receiptRevoke: (operatorEmail: string) => string;
19
+ readonly receiptNotMe: string;
20
+ readonly receiptNotMeLink: string;
19
21
  readonly contact: string;
20
22
  readonly operatorSubject: Readonly<Record<ContractTerminationDeclarationType, string>>;
21
23
  readonly operatorIntro: string;
@@ -57,7 +59,21 @@ export type PageTexts = {
57
59
  readonly errorGeneric: string;
58
60
  readonly rateLimitedTitle: string;
59
61
  readonly rateLimitedBody: string;
62
+ readonly revoke: RevokePageTexts;
60
63
  };
61
- export declare const OPERATOR_NOTICE_REASONS: readonly ["unmatched", "ambiguous", "withdrawal", "extraordinary", "provider_cannot_cancel", "provider_error", "no_active_subscription", "recording_failed", "withdrawal_period_expired", "receipt_rate_limited"];
64
+ export type RevokePageTexts = {
65
+ readonly confirmTitle: string;
66
+ readonly confirmLead: string;
67
+ readonly confirmButton: string;
68
+ readonly revokedTitle: string;
69
+ readonly revokedBody: string;
70
+ readonly alreadyRevokedTitle: string;
71
+ readonly alreadyRevokedBody: string;
72
+ readonly tooLateTitle: string;
73
+ readonly tooLateBody: string;
74
+ readonly invalidTitle: string;
75
+ readonly invalidBody: string;
76
+ };
77
+ export declare const OPERATOR_NOTICE_REASONS: readonly ["unmatched", "ambiguous", "withdrawal", "extraordinary", "provider_cannot_cancel", "provider_error", "no_active_subscription", "recording_failed", "withdrawal_period_expired", "receipt_rate_limited", "revoked", "revocation_resume_manual", "revocation_resume_failed"];
62
78
  export type OperatorNoticeReason = (typeof OPERATOR_NOTICE_REASONS)[number];
63
79
  export declare const TERMINATION_TEXTS: Readonly<Record<ConsentLocale, TerminationTexts>>;
@@ -9,6 +9,9 @@ export const OPERATOR_NOTICE_REASONS = [
9
9
  "recording_failed",
10
10
  "withdrawal_period_expired",
11
11
  "receipt_rate_limited",
12
+ "revoked",
13
+ "revocation_resume_manual",
14
+ "revocation_resume_failed",
12
15
  ];
13
16
  export const TERMINATION_TEXTS = {
14
17
  de: {
@@ -33,6 +36,8 @@ export const TERMINATION_TEXTS = {
33
36
  receiptIntro: "wir bestätigen den Eingang deiner Erklärung mit folgendem Inhalt. Diese E-Mail ist eine Eingangsbestätigung, keine Bestätigung der Wirksamkeit.",
34
37
  receiptNextSteps: "Wir prüfen deine Erklärung und melden uns, sobald sie bearbeitet ist oder wir Rückfragen haben.",
35
38
  receiptRevoke: (operatorEmail) => `Hast du diese Erklärung nicht abgegeben oder möchtest du sie zurücknehmen? Schreib uns bitte umgehend an ${operatorEmail}.`,
39
+ receiptNotMe: "Wurde diese Erklärung nicht von dir abgegeben? Dann nimm die Kündigung bis zu ihrem Wirksamwerden hier zurück:",
40
+ receiptNotMeLink: "Diese Kündigung war ich nicht",
36
41
  contact: "Fragen richtest du bitte an",
37
42
  operatorSubject: {
38
43
  termination: "Kündigung: Bearbeitung nötig",
@@ -50,6 +55,9 @@ export const TERMINATION_TEXTS = {
50
55
  recording_failed: "Die Erklärung konnte nicht gespeichert werden",
51
56
  withdrawal_period_expired: "Widerruf nach Ablauf der Widerrufsfrist: zum Periodenende gekündigt, Anspruch prüfen",
52
57
  receipt_rate_limited: "Keine Eingangsbestätigung versendet: Limit pro Empfängeradresse erreicht",
58
+ revoked: "Die Erklärung wurde vom Postfachinhaber über „Diese Kündigung war ich nicht“ zurückgenommen",
59
+ revocation_resume_manual: "Die Kündigung beim Zahlungsanbieter bitte manuell zurücknehmen (keine Schnittstelle dafür)",
60
+ revocation_resume_failed: "Die Kündigung beim Zahlungsanbieter konnte nicht zurückgenommen werden, bitte manuell zurücknehmen",
53
61
  },
54
62
  noticeReasons: "Grund der Benachrichtigung",
55
63
  channel: "Kanal",
@@ -90,6 +98,19 @@ export const TERMINATION_TEXTS = {
90
98
  errorGeneric: "Deine Erklärung konnte nicht verarbeitet werden. Bitte versuch es erneut.",
91
99
  rateLimitedTitle: "Zu viele Anfragen",
92
100
  rateLimitedBody: "Von deiner Adresse kamen zu viele Anfragen. Bitte versuch es später erneut.",
101
+ revoke: {
102
+ confirmTitle: "Kündigung zurücknehmen?",
103
+ confirmLead: "Mit dem Klick auf den Button unten nimmst du die Kündigung zurück. Dein Vertrag läuft dann weiter.",
104
+ confirmButton: "Diese Kündigung war ich nicht",
105
+ revokedTitle: "Die Kündigung ist zurückgenommen",
106
+ revokedBody: "Dein Vertrag läuft weiter. Wir haben den Betreiber informiert.",
107
+ alreadyRevokedTitle: "Schon zurückgenommen",
108
+ alreadyRevokedBody: "Diese Kündigung wurde bereits zurückgenommen.",
109
+ tooLateTitle: "Zu spät für die Rücknahme",
110
+ tooLateBody: "Die Kündigung ist bereits wirksam geworden. Bitte schreib dem Betreiber, die Adresse steht in der Eingangsbestätigung.",
111
+ invalidTitle: "Link ungültig",
112
+ invalidBody: "Dieser Link ist ungültig oder abgelaufen. Bitte schreib dem Betreiber, die Adresse steht in der Eingangsbestätigung.",
113
+ },
93
114
  },
94
115
  },
95
116
  en: {
@@ -114,6 +135,8 @@ export const TERMINATION_TEXTS = {
114
135
  receiptIntro: "We confirm receipt of your declaration with the following content. This email is a receipt, not a confirmation that the declaration is effective.",
115
136
  receiptNextSteps: "We will review your declaration and get back to you once it is processed or if we have questions.",
116
137
  receiptRevoke: (operatorEmail) => `If you did not make this declaration or want to take it back, please write to ${operatorEmail} right away.`,
138
+ receiptNotMe: "Did you not make this declaration? Then take the termination back here until it takes effect:",
139
+ receiptNotMeLink: "I did not request this cancellation",
117
140
  contact: "Questions go to",
118
141
  operatorSubject: {
119
142
  termination: "Termination: action needed",
@@ -131,6 +154,9 @@ export const TERMINATION_TEXTS = {
131
154
  recording_failed: "The declaration could not be stored",
132
155
  withdrawal_period_expired: "Withdrawal after the withdrawal period: cancelled at period end, review the claim",
133
156
  receipt_rate_limited: "No receipt mail sent: the per-recipient limit was reached",
157
+ revoked: 'The declaration was taken back by the mailbox owner ("I did not request this cancellation")',
158
+ revocation_resume_manual: "Undo the cancellation at the payment provider manually (no API for it)",
159
+ revocation_resume_failed: "Undoing the cancellation at the payment provider failed, undo it manually",
134
160
  },
135
161
  noticeReasons: "Reason for this notice",
136
162
  channel: "Channel",
@@ -171,6 +197,19 @@ export const TERMINATION_TEXTS = {
171
197
  errorGeneric: "Your declaration could not be processed. Please try again.",
172
198
  rateLimitedTitle: "Too many requests",
173
199
  rateLimitedBody: "Too many requests came from your address. Please try again later.",
200
+ revoke: {
201
+ confirmTitle: "Take the cancellation back?",
202
+ confirmLead: "Click the button below to take the cancellation back. Your contract then continues.",
203
+ confirmButton: "I did not request this cancellation",
204
+ revokedTitle: "The cancellation was taken back",
205
+ revokedBody: "Your contract continues. We informed the operator.",
206
+ alreadyRevokedTitle: "Already taken back",
207
+ alreadyRevokedBody: "This cancellation was already taken back.",
208
+ tooLateTitle: "Too late to take it back",
209
+ tooLateBody: "The cancellation has already taken effect. Please write to the operator, the address is in the receipt.",
210
+ invalidTitle: "Invalid link",
211
+ invalidBody: "This link is invalid or has expired. Please write to the operator, the address is in the receipt.",
212
+ },
174
213
  },
175
214
  },
176
215
  };
@@ -25,6 +25,7 @@ export declare const subscriptionEventPayloadSchema: z.ZodObject<{
25
25
  currentPeriodEndIso: z.ZodString;
26
26
  cancelAtIso: z.ZodOptional<z.ZodNullable<z.ZodString>>;
27
27
  consentId: z.ZodOptional<z.ZodString>;
28
+ providerEventAtIso: z.ZodOptional<z.ZodISODateTime>;
28
29
  }, z.core.$strip>;
29
30
  export type SubscriptionEventPayload = z.infer<typeof subscriptionEventPayloadSchema>;
30
31
  export type SubscriptionEventHeaders = {
@@ -127,8 +128,16 @@ export declare const contractTerminationDeclaredPayloadSchema: z.ZodObject<{
127
128
  de: "de";
128
129
  en: "en";
129
130
  }>;
131
+ revocationTokenHash: z.ZodOptional<z.ZodString>;
130
132
  }, z.core.$strip>;
131
133
  export type ContractTerminationDeclaredPayload = z.infer<typeof contractTerminationDeclaredPayloadSchema>;
134
+ export declare const CONTRACT_TERMINATION_REVOKED_EVENT_SHORT: "contract-termination-revoked";
135
+ export declare const CONTRACT_TERMINATION_REVOKED_EVENT_QN: "billing-foundation:event:contract-termination-revoked";
136
+ export declare const contractTerminationRevokedPayloadSchema: z.ZodObject<{
137
+ requestId: z.ZodString;
138
+ revokedAtIso: z.ZodString;
139
+ }, z.core.$strip>;
140
+ export type ContractTerminationRevokedPayload = z.infer<typeof contractTerminationRevokedPayloadSchema>;
132
141
  export declare const CONTRACT_TERMINATION_UNMATCHED_AGGREGATE_TYPE: "contract-termination-unmatched";
133
142
  export declare const CONTRACT_TERMINATION_UNMATCHED_EVENT_SHORT: "contract-termination-unmatched";
134
143
  export declare const CONTRACT_TERMINATION_UNMATCHED_EVENT_QN: "billing-foundation:event:contract-termination-unmatched";
@@ -10,8 +10,8 @@
10
10
  // accounting-export, churn-analytics) listenen direkt auf den event-
11
11
  // type ohne payload-discriminator.
12
12
  import * as z from "zod";
13
- import { BILLING_FOUNDATION_FEATURE, SubscriptionStatuses } from "./constants.js";
14
- import { CONSENT_LOCALES } from "./consumer-protection/consent-locale.js";
13
+ import { BILLING_FOUNDATION_FEATURE, SubscriptionStatuses } from "./web/constants.js";
14
+ import { CONSENT_LOCALES } from "./web/consumer-protection/consent-locale.js";
15
15
  // Aggregate-type für den event-store. Eine subscription pro Tenant ist
16
16
  // ein stream; der subscriptionAggregateId-helper liefert die stream-id.
17
17
  export const SUBSCRIPTION_AGGREGATE_TYPE = "subscription";
@@ -56,6 +56,8 @@ export const subscriptionEventPayloadSchema = z.object({
56
56
  // doesn't report cancelAt at all — projection.ts tells the two apart.
57
57
  cancelAtIso: z.string().min(1).nullable().optional(),
58
58
  consentId: z.string().min(1).max(100).optional(),
59
+ // When the provider emitted the event; lets process-event drop late deliveries.
60
+ providerEventAtIso: z.iso.datetime().optional(),
59
61
  });
60
62
  // =============================================================================
61
63
  // payment-received — one-off-payments (checkout mode "payment")
@@ -151,6 +153,16 @@ export const contractTerminationDeclaredPayloadSchema = z.object({
151
153
  terminationKind: z.enum(CONTRACT_TERMINATION_KINDS),
152
154
  receivedAtIso: z.string().min(1),
153
155
  locale: z.enum(CONSENT_LOCALES),
156
+ // sha256 hex of the "this was not me" link token; events written before the
157
+ // link existed carry none and cannot be revoked.
158
+ revocationTokenHash: z.string().length(64).optional(),
159
+ });
160
+ // The mailbox owner took a public declaration back ("this was not me").
161
+ export const CONTRACT_TERMINATION_REVOKED_EVENT_SHORT = "contract-termination-revoked";
162
+ export const CONTRACT_TERMINATION_REVOKED_EVENT_QN = `${BILLING_FOUNDATION_FEATURE}:event:${CONTRACT_TERMINATION_REVOKED_EVENT_SHORT}`;
163
+ export const contractTerminationRevokedPayloadSchema = z.object({
164
+ requestId: z.string().min(1).max(100),
165
+ revokedAtIso: z.string().min(1),
154
166
  });
155
167
  export const CONTRACT_TERMINATION_UNMATCHED_AGGREGATE_TYPE = "contract-termination-unmatched";
156
168
  export const CONTRACT_TERMINATION_UNMATCHED_EVENT_SHORT = "contract-termination-unmatched";
@@ -51,7 +51,6 @@
51
51
  // `subscription-provider-changed`-event-type später.
52
52
  import { defineFeature, EXT_TENANT_DATA, } from "@cosmicdrift/kumiko-framework/engine";
53
53
  import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
54
- import { BILLING_FOUNDATION_FEATURE, SUBSCRIPTION_PROVIDER_EXTENSION, SubscriptionFoundationHandlers, } from "./constants.js";
55
54
  import { registerConsumerProtection } from "./consumer-protection/register-consent.js";
56
55
  import { paymentEntity, subscriptionEntity } from "./entities.js";
57
56
  import { INVOICE_PAID_EVENT_QN, INVOICE_PAID_EVENT_SHORT, INVOICE_PAYMENT_FAILED_EVENT_QN, INVOICE_PAYMENT_FAILED_EVENT_SHORT, PAYMENT_AGGREGATE_TYPE, PAYMENT_RECEIVED_EVENT_QN, PAYMENT_RECEIVED_EVENT_SHORT, paymentEventPayloadSchema, SUBSCRIPTION_AGGREGATE_TYPE, SUBSCRIPTION_CANCELED_EVENT_QN, SUBSCRIPTION_CANCELED_EVENT_SHORT, SUBSCRIPTION_CREATED_EVENT_QN, SUBSCRIPTION_CREATED_EVENT_SHORT, SUBSCRIPTION_UPDATED_EVENT_QN, SUBSCRIPTION_UPDATED_EVENT_SHORT, subscriptionEventPayloadSchema, } from "./events.js";
@@ -69,6 +68,7 @@ import { applyInvoicePaid, applyInvoicePaymentFailed, applyPaymentReceived, appl
69
68
  import { createBillingPlansScreen } from "./screens.js";
70
69
  import { PAYMENT_TENANT_DESTROY_ARCHIVE_REASON, paymentTenantDestroyHook, SUBSCRIPTION_TENANT_DESTROY_ARCHIVE_REASON, subscriptionTenantDestroyHook, } from "./tenant-destroy-hook.js";
71
70
  import { validateOptions } from "./validate-options.js";
71
+ import { BILLING_FOUNDATION_FEATURE, SUBSCRIPTION_PROVIDER_EXTENSION, SubscriptionFoundationHandlers, } from "./web/constants.js";
72
72
  export function createBillingFoundationFeature(options = {}) {
73
73
  validateOptions(options);
74
74
  // Handlers take the widened, string-tiered options — `TTier` only exists
@@ -1,4 +1,5 @@
1
1
  import type { HandlerContext, WriteHandlerDef } from "@cosmicdrift/kumiko-framework/engine";
2
+ import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
2
3
  import * as z from "zod";
3
4
  export declare const processEventSchema: z.ZodObject<{
4
5
  providerEventId: z.ZodString;
@@ -22,11 +23,14 @@ export declare const processEventSchema: z.ZodObject<{
22
23
  tier: z.ZodString;
23
24
  currentPeriodEndIso: z.ZodString;
24
25
  cancelAtIso: z.ZodOptional<z.ZodNullable<z.ZodString>>;
26
+ providerEventAtIso: z.ZodOptional<z.ZodISODateTime>;
25
27
  consentId: z.ZodOptional<z.ZodString>;
26
28
  }, z.core.$strip>;
27
29
  export type ProcessEventPayload = z.infer<typeof processEventSchema>;
28
- export declare function appendSubscriptionEvent(ctx: HandlerContext, tenantId: string, payload: ProcessEventPayload): Promise<{
30
+ export declare function clampProviderEventAt(payload: ProcessEventPayload, now: Temporal.Instant): ProcessEventPayload;
31
+ export declare function appendSubscriptionEvent(ctx: HandlerContext, tenantId: string, rawPayload: ProcessEventPayload, now?: Temporal.Instant): Promise<{
29
32
  readonly duplicate: boolean;
33
+ readonly stale?: true;
30
34
  readonly subscriptionAggregateId: string;
31
35
  }>;
32
36
  export declare function createProcessEventHandler(now: () => Temporal.Instant): WriteHandlerDef;