@cosmicdrift/kumiko-samples 0.386.0 → 0.388.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (530) hide show
  1. package/LICENSE +21 -57
  2. package/README.md +1 -1
  3. package/package.json +2 -2
  4. package/packages/bundled-features/package.json +9 -2
  5. package/packages/bundled-features/src/agent-tools/changes.json +6 -0
  6. package/packages/bundled-features/src/agent-tools/tool-catalog.ts +1 -1
  7. package/packages/bundled-features/src/agent-tools/tool-dispatch.ts +9 -9
  8. package/packages/bundled-features/src/audit/changes.json +12 -0
  9. package/packages/bundled-features/src/audit/handlers/audit-events.ts +1 -1
  10. package/packages/bundled-features/src/audit/screens.ts +1 -1
  11. package/packages/bundled-features/src/auth-email-password/auth-user-row.ts +10 -10
  12. package/packages/bundled-features/src/auth-email-password/feature.ts +6 -6
  13. package/packages/bundled-features/src/auth-email-password/handlers/change-password.write.ts +3 -3
  14. package/packages/bundled-features/src/auth-email-password/handlers/confirm-token-flow.ts +5 -5
  15. package/packages/bundled-features/src/auth-email-password/handlers/invite-accept-with-login.write.ts +1 -1
  16. package/packages/bundled-features/src/auth-email-password/handlers/invite-accept.write.ts +18 -18
  17. package/packages/bundled-features/src/auth-email-password/handlers/invite-create.write.ts +12 -12
  18. package/packages/bundled-features/src/auth-email-password/handlers/invite-info.query.ts +1 -1
  19. package/packages/bundled-features/src/auth-email-password/handlers/invite-signup-complete.write.ts +24 -26
  20. package/packages/bundled-features/src/auth-email-password/handlers/login.write.ts +1 -1
  21. package/packages/bundled-features/src/auth-email-password/handlers/self-registration-status.query.ts +1 -1
  22. package/packages/bundled-features/src/auth-email-password/handlers/signup-confirm.write.ts +34 -37
  23. package/packages/bundled-features/src/auth-email-password/handlers/signup-request.write.ts +6 -7
  24. package/packages/bundled-features/src/auth-email-password/handlers/switch-tenant-mfa-gate.write.ts +1 -5
  25. package/packages/bundled-features/src/auth-email-password/index.ts +5 -5
  26. package/packages/bundled-features/src/auth-email-password/lockout-store.ts +1 -1
  27. package/packages/bundled-features/src/auth-email-password/seeding.ts +63 -66
  28. package/packages/bundled-features/src/auth-email-password/signup-token-store.ts +8 -8
  29. package/packages/bundled-features/src/auth-email-password/testing.ts +3 -3
  30. package/packages/bundled-features/src/auth-email-password/web/auth-client.ts +57 -57
  31. package/packages/bundled-features/src/auth-email-password/web/auth-form-primitives.tsx +14 -14
  32. package/packages/bundled-features/src/auth-email-password/web/auth-gate.tsx +15 -16
  33. package/packages/bundled-features/src/auth-email-password/web/client-plugin.ts +11 -12
  34. package/packages/bundled-features/src/auth-email-password/web/confirm-account-unlock-screen.tsx +1 -1
  35. package/packages/bundled-features/src/auth-email-password/web/constants.ts +3 -3
  36. package/packages/bundled-features/src/auth-email-password/web/default-topbar-actions.tsx +14 -14
  37. package/packages/bundled-features/src/auth-email-password/web/forgot-password-screen.tsx +11 -11
  38. package/packages/bundled-features/src/auth-email-password/web/index.ts +5 -5
  39. package/packages/bundled-features/src/auth-email-password/web/invite-accept-screen.tsx +17 -17
  40. package/packages/bundled-features/src/auth-email-password/web/login-screen.tsx +3 -4
  41. package/packages/bundled-features/src/auth-email-password/web/reset-password-screen.tsx +16 -17
  42. package/packages/bundled-features/src/auth-email-password/web/session.tsx +34 -34
  43. package/packages/bundled-features/src/auth-email-password/web/signup-complete-screen.tsx +3 -3
  44. package/packages/bundled-features/src/auth-email-password/web/signup-screen.tsx +14 -14
  45. package/packages/bundled-features/src/auth-email-password/web/tenant-switcher.tsx +26 -27
  46. package/packages/bundled-features/src/auth-email-password/web/use-shell-user.ts +12 -13
  47. package/packages/bundled-features/src/auth-email-password/web/user-menu.tsx +17 -18
  48. package/packages/bundled-features/src/auth-email-password/web/verify-email-screen.tsx +11 -12
  49. package/packages/bundled-features/src/auth-foundation/boot-checks.ts +4 -4
  50. package/packages/bundled-features/src/auth-foundation/resolve-anonymous-access.ts +4 -4
  51. package/packages/bundled-features/src/auth-foundation/types.ts +2 -2
  52. package/packages/bundled-features/src/auth-mfa/changes.json +6 -0
  53. package/packages/bundled-features/src/auth-mfa/feature-exports.ts +2 -2
  54. package/packages/bundled-features/src/auth-mfa/feature.ts +6 -0
  55. package/packages/bundled-features/src/auth-mfa/handlers/disable.write.ts +3 -3
  56. package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm-preauth.write.ts +4 -4
  57. package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm.write.ts +2 -2
  58. package/packages/bundled-features/src/auth-mfa/handlers/enable-start-preauth.write.ts +1 -1
  59. package/packages/bundled-features/src/auth-mfa/handlers/reencrypt.job.ts +1 -1
  60. package/packages/bundled-features/src/auth-mfa/handlers/regenerate-recovery.write.ts +5 -5
  61. package/packages/bundled-features/src/auth-mfa/handlers/verify.write.ts +1 -1
  62. package/packages/bundled-features/src/auth-mfa/token-secrets.ts +1 -1
  63. package/packages/bundled-features/src/auth-mfa/web/client-plugin.ts +2 -2
  64. package/packages/bundled-features/src/auth-mfa/web/i18n.ts +9 -4
  65. package/packages/bundled-features/src/auth-mfa/web/index.ts +4 -4
  66. package/packages/bundled-features/src/auth-mfa/web/mfa-client.ts +17 -16
  67. package/packages/bundled-features/src/auth-mfa/web/mfa-code-or-recovery-field.tsx +68 -0
  68. package/packages/bundled-features/src/auth-mfa/web/mfa-disable-dialog.tsx +23 -13
  69. package/packages/bundled-features/src/auth-mfa/web/mfa-regenerate-recovery-dialog.tsx +23 -13
  70. package/packages/bundled-features/src/auth-mfa/web/mfa-setup-preauth-screen.tsx +15 -6
  71. package/packages/bundled-features/src/auth-mfa/web/mfa-verify-screen.tsx +71 -24
  72. package/packages/bundled-features/src/billing-foundation/aggregate-id.ts +10 -11
  73. package/packages/bundled-features/src/billing-foundation/changes.json +55 -0
  74. package/packages/bundled-features/src/billing-foundation/checkout-core.ts +32 -42
  75. package/packages/bundled-features/src/billing-foundation/consumer-protection/confirmation-mail.ts +8 -2
  76. package/packages/bundled-features/src/billing-foundation/consumer-protection/consent-gate.ts +2 -0
  77. package/packages/bundled-features/src/billing-foundation/consumer-protection/issue-confirmation.ts +14 -3
  78. package/packages/bundled-features/src/billing-foundation/consumer-protection/mail-notifications.ts +3 -4
  79. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-receipt-limit.ts +12 -6
  80. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-record.ts +35 -19
  81. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-request.ts +12 -8
  82. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-revoke.ts +14 -8
  83. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-texts.ts +5 -0
  84. package/packages/bundled-features/src/billing-foundation/consumer-protection/withdrawal-period.ts +8 -10
  85. package/packages/bundled-features/src/billing-foundation/entities.ts +27 -27
  86. package/packages/bundled-features/src/billing-foundation/events.ts +23 -21
  87. package/packages/bundled-features/src/billing-foundation/feature.ts +45 -44
  88. package/packages/bundled-features/src/billing-foundation/get-subscription-for-tenant.ts +3 -5
  89. package/packages/bundled-features/src/billing-foundation/handlers/billing-plans.query.ts +71 -6
  90. package/packages/bundled-features/src/billing-foundation/handlers/create-checkout-session.write.ts +19 -17
  91. package/packages/bundled-features/src/billing-foundation/handlers/create-portal-session.write.ts +11 -12
  92. package/packages/bundled-features/src/billing-foundation/handlers/list-subscriptions.query.ts +4 -4
  93. package/packages/bundled-features/src/billing-foundation/handlers/plan-switch-preview.query.ts +65 -0
  94. package/packages/bundled-features/src/billing-foundation/handlers/process-event.write.ts +29 -22
  95. package/packages/bundled-features/src/billing-foundation/handlers/start-plan-checkout.write.ts +44 -8
  96. package/packages/bundled-features/src/billing-foundation/handlers/switch-plan.write.ts +72 -82
  97. package/packages/bundled-features/src/billing-foundation/handlers/sync-subscription.write.ts +14 -1
  98. package/packages/bundled-features/src/billing-foundation/i18n.ts +22 -0
  99. package/packages/bundled-features/src/billing-foundation/index.ts +2 -0
  100. package/packages/bundled-features/src/billing-foundation/plan-catalog.ts +62 -27
  101. package/packages/bundled-features/src/billing-foundation/plan-switch.ts +84 -0
  102. package/packages/bundled-features/src/billing-foundation/projection.ts +38 -37
  103. package/packages/bundled-features/src/billing-foundation/subscription-tier-sync.ts +3 -3
  104. package/packages/bundled-features/src/billing-foundation/tenant-destroy-hook.ts +7 -8
  105. package/packages/bundled-features/src/billing-foundation/types.ts +144 -66
  106. package/packages/bundled-features/src/billing-foundation/validate-options.ts +19 -0
  107. package/packages/bundled-features/src/billing-foundation/web/billing-plans-panel.tsx +123 -51
  108. package/packages/bundled-features/src/billing-foundation/web/checkout-consent-dialog.tsx +89 -42
  109. package/packages/bundled-features/src/billing-foundation/web/constants.ts +4 -0
  110. package/packages/bundled-features/src/billing-foundation/web/plan-price.ts +55 -0
  111. package/packages/bundled-features/src/billing-foundation/web/plan-switch-confirm-dialog.tsx +224 -0
  112. package/packages/bundled-features/src/billing-foundation/webhook-handler.ts +1 -1
  113. package/packages/bundled-features/src/cap-counter/aggregate-id.ts +8 -9
  114. package/packages/bundled-features/src/cap-counter/cap-reservation.ts +5 -1
  115. package/packages/bundled-features/src/cap-counter/changes.json +18 -0
  116. package/packages/bundled-features/src/cap-counter/constants.ts +11 -12
  117. package/packages/bundled-features/src/cap-counter/enforce-cap.ts +66 -68
  118. package/packages/bundled-features/src/cap-counter/entity.ts +29 -29
  119. package/packages/bundled-features/src/cap-counter/feature.ts +34 -35
  120. package/packages/bundled-features/src/cap-counter/handlers/increment-rolling.write.ts +31 -31
  121. package/packages/bundled-features/src/cap-counter/handlers/mark-soft-warned.write.ts +4 -5
  122. package/packages/bundled-features/src/cap-counter/stock-cap-guard.ts +9 -2
  123. package/packages/bundled-features/src/cap-counter/with-cap-enforcement.ts +3 -5
  124. package/packages/bundled-features/src/cap-overview/handlers/caps-usage.query.ts +1 -3
  125. package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +1 -1
  126. package/packages/bundled-features/src/channel-email/changes.json +6 -0
  127. package/packages/bundled-features/src/channel-email/feature.ts +1 -1
  128. package/packages/bundled-features/src/channel-email/smtp-transport.ts +34 -31
  129. package/packages/bundled-features/src/channel-in-app/handlers/unread-count.query.ts +3 -4
  130. package/packages/bundled-features/src/compliance-profiles/feature.ts +15 -16
  131. package/packages/bundled-features/src/compliance-profiles/handlers/for-tenant.query.ts +3 -6
  132. package/packages/bundled-features/src/compliance-profiles/handlers/list-profiles.query.ts +5 -5
  133. package/packages/bundled-features/src/compliance-profiles/handlers/needs-profile.query.ts +4 -4
  134. package/packages/bundled-features/src/compliance-profiles/handlers/set-profile.write.ts +13 -14
  135. package/packages/bundled-features/src/compliance-profiles/handlers/sub-processors.query.ts +9 -11
  136. package/packages/bundled-features/src/compliance-profiles/resolve-for-tenant.ts +7 -7
  137. package/packages/bundled-features/src/compliance-profiles/schema/profile-selection.ts +18 -23
  138. package/packages/bundled-features/src/compliance-profiles/seeding.ts +14 -15
  139. package/packages/bundled-features/src/compliance-profiles-ops/handlers/tenants-missing-profile.query.ts +3 -3
  140. package/packages/bundled-features/src/compliance-profiles-ops/index.ts +2 -2
  141. package/packages/bundled-features/src/config/changes.json +12 -0
  142. package/packages/bundled-features/src/config/handlers/cascade.query.ts +4 -2
  143. package/packages/bundled-features/src/config/handlers/readiness.query.ts +7 -7
  144. package/packages/bundled-features/src/config/handlers/reencrypt.job.ts +4 -5
  145. package/packages/bundled-features/src/config/handlers/set.write.ts +4 -4
  146. package/packages/bundled-features/src/config/handlers/values.query.ts +4 -2
  147. package/packages/bundled-features/src/config/resolver.ts +4 -4
  148. package/packages/bundled-features/src/config/table.ts +10 -10
  149. package/packages/bundled-features/src/config/write-helpers.ts +28 -9
  150. package/packages/bundled-features/src/crypto-shredding/changes.json +6 -0
  151. package/packages/bundled-features/src/crypto-shredding/handlers/forget-subject.write.ts +23 -21
  152. package/packages/bundled-features/src/custom-fields/aggregate-id.ts +16 -17
  153. package/packages/bundled-features/src/custom-fields/entity.ts +49 -47
  154. package/packages/bundled-features/src/custom-fields/events.ts +7 -8
  155. package/packages/bundled-features/src/custom-fields/feature.ts +70 -72
  156. package/packages/bundled-features/src/custom-fields/handlers/clear-custom-field.write.ts +9 -8
  157. package/packages/bundled-features/src/custom-fields/handlers/define-tenant-field.write.ts +28 -26
  158. package/packages/bundled-features/src/custom-fields/handlers/delete-system-field.write.ts +6 -7
  159. package/packages/bundled-features/src/custom-fields/handlers/delete-tenant-field.write.ts +12 -13
  160. package/packages/bundled-features/src/custom-fields/handlers/set-custom-field.write.ts +25 -28
  161. package/packages/bundled-features/src/custom-fields/handlers/update-tenant-field.write.ts +6 -6
  162. package/packages/bundled-features/src/custom-fields/lib/field-access.ts +2 -2
  163. package/packages/bundled-features/src/custom-fields/lib/parse-serialized-field.ts +1 -1
  164. package/packages/bundled-features/src/custom-fields/lib/quota.ts +1 -1
  165. package/packages/bundled-features/src/custom-fields/lib/value-schema.ts +10 -12
  166. package/packages/bundled-features/src/custom-fields/run-retention.ts +3 -3
  167. package/packages/bundled-features/src/custom-fields/schemas.ts +14 -14
  168. package/packages/bundled-features/src/custom-fields/web/client-plugin.tsx +2 -5
  169. package/packages/bundled-features/src/custom-fields/web/constants.ts +2 -2
  170. package/packages/bundled-features/src/custom-fields/web/custom-fields-form-section.tsx +26 -26
  171. package/packages/bundled-features/src/custom-fields/wire-for-entity.ts +65 -67
  172. package/packages/bundled-features/src/custom-fields/wire-user-data-rights.ts +3 -3
  173. package/packages/bundled-features/src/data-retention/_internal/parse-override.ts +2 -3
  174. package/packages/bundled-features/src/data-retention/feature.ts +11 -18
  175. package/packages/bundled-features/src/data-retention/handlers/policy-for.query.ts +6 -6
  176. package/packages/bundled-features/src/data-retention/keep-for.ts +17 -17
  177. package/packages/bundled-features/src/data-retention/override-schema.ts +13 -15
  178. package/packages/bundled-features/src/data-retention/presets.ts +18 -23
  179. package/packages/bundled-features/src/data-retention/resolve-for-tenant.ts +1 -1
  180. package/packages/bundled-features/src/data-retention/resolve-tenant-preset.ts +17 -16
  181. package/packages/bundled-features/src/data-retention/resolver.ts +33 -32
  182. package/packages/bundled-features/src/data-retention/run-retention-cleanup.ts +71 -58
  183. package/packages/bundled-features/src/data-retention/schema/tenant-retention-override.ts +13 -11
  184. package/packages/bundled-features/src/delivery/changes.json +30 -0
  185. package/packages/bundled-features/src/delivery/channel-context.ts +9 -3
  186. package/packages/bundled-features/src/delivery/db/queries/preferences.ts +2 -2
  187. package/packages/bundled-features/src/delivery/delivery-service.ts +35 -5
  188. package/packages/bundled-features/src/delivery/feature.ts +3 -3
  189. package/packages/bundled-features/src/delivery/handlers/log.query.ts +1 -1
  190. package/packages/bundled-features/src/delivery/handlers/preferences.query.ts +20 -1
  191. package/packages/bundled-features/src/delivery/handlers/unsubscribe-page-chrome.query.ts +1 -1
  192. package/packages/bundled-features/src/delivery/tables.ts +9 -8
  193. package/packages/bundled-features/src/delivery/unsubscribe-link.ts +3 -1
  194. package/packages/bundled-features/src/delivery/unsubscribe-page-strings.ts +1 -0
  195. package/packages/bundled-features/src/delivery/unsubscribe-page.ts +6 -0
  196. package/packages/bundled-features/src/delivery/unsubscribe.ts +40 -19
  197. package/packages/bundled-features/src/delivery/upsert-preference.ts +3 -4
  198. package/packages/bundled-features/src/document-ingest-foundation/entity.ts +5 -5
  199. package/packages/bundled-features/src/document-ingest-foundation/events.ts +2 -2
  200. package/packages/bundled-features/src/document-ingest-foundation/feature.ts +2 -2
  201. package/packages/bundled-features/src/document-ingest-foundation/pages.ts +1 -1
  202. package/packages/bundled-features/src/document-ingest-foundation/tenant-destroy-hook.ts +4 -4
  203. package/packages/bundled-features/src/feature-toggles/compose-tier-resolver.ts +1 -1
  204. package/packages/bundled-features/src/feature-toggles/feature.ts +1 -1
  205. package/packages/bundled-features/src/feature-toggles/global-feature-state-table.ts +1 -1
  206. package/packages/bundled-features/src/feature-toggles/handlers/registered.query.ts +5 -5
  207. package/packages/bundled-features/src/feature-toggles/toggle-runtime.ts +1 -1
  208. package/packages/bundled-features/src/feature-toggles/toggle-sync-signal.ts +1 -1
  209. package/packages/bundled-features/src/feature-toggles/web/constants.ts +1 -1
  210. package/packages/bundled-features/src/file-derivatives/feature.ts +2 -2
  211. package/packages/bundled-features/src/file-derivatives/handlers/public-variant.query.ts +1 -1
  212. package/packages/bundled-features/src/file-derivatives/presets.ts +1 -1
  213. package/packages/bundled-features/src/file-foundation/feature.ts +6 -6
  214. package/packages/bundled-features/src/file-foundation/index.ts +1 -0
  215. package/packages/bundled-features/src/file-foundation/read-file-ref-content.ts +7 -1
  216. package/packages/bundled-features/src/file-provider-inmemory/feature.ts +16 -16
  217. package/packages/bundled-features/src/file-provider-s3/env-named-feature.ts +0 -2
  218. package/packages/bundled-features/src/file-provider-s3/feature.ts +16 -16
  219. package/packages/bundled-features/src/file-provider-s3/lib/s3-provider.ts +6 -6
  220. package/packages/bundled-features/src/files/README.md +1 -1
  221. package/packages/bundled-features/src/files/feature.ts +6 -6
  222. package/packages/bundled-features/src/files-tenant-data/handlers/sweep-orphaned-derivatives.job.ts +5 -5
  223. package/packages/bundled-features/src/files-tenant-data/hooks.ts +24 -26
  224. package/packages/bundled-features/src/files-tenant-data/index.ts +1 -1
  225. package/packages/bundled-features/src/folders/feature.ts +1 -1
  226. package/packages/bundled-features/src/folders/web/folder-manager.tsx +2 -2
  227. package/packages/bundled-features/src/folders/web/tree.ts +5 -5
  228. package/packages/bundled-features/src/form-draft/changes.json +6 -0
  229. package/packages/bundled-features/src/form-draft/db/queries/cleanup.ts +3 -3
  230. package/packages/bundled-features/src/form-draft/db/queries/owned-file-refs.ts +1 -1
  231. package/packages/bundled-features/src/form-draft/decrypt-draft.ts +4 -1
  232. package/packages/bundled-features/src/form-draft/entity.ts +3 -3
  233. package/packages/bundled-features/src/form-draft/feature.ts +4 -5
  234. package/packages/bundled-features/src/form-draft/handlers/discard.write.ts +1 -1
  235. package/packages/bundled-features/src/form-draft/release-file-refs.ts +6 -6
  236. package/packages/bundled-features/src/form-draft/schemas.ts +3 -3
  237. package/packages/bundled-features/src/form-draft/web/constants.ts +0 -2
  238. package/packages/bundled-features/src/host-routing/README.md +1 -1
  239. package/packages/bundled-features/src/host-routing/changes.json +6 -0
  240. package/packages/bundled-features/src/host-routing/dispatch.ts +16 -17
  241. package/packages/bundled-features/src/host-routing/options.ts +2 -1
  242. package/packages/bundled-features/src/inbound-mail-foundation/aggregate-id.ts +19 -19
  243. package/packages/bundled-features/src/inbound-mail-foundation/changes.json +18 -0
  244. package/packages/bundled-features/src/inbound-mail-foundation/connect-routes.ts +4 -3
  245. package/packages/bundled-features/src/inbound-mail-foundation/constants.ts +30 -33
  246. package/packages/bundled-features/src/inbound-mail-foundation/entities.ts +47 -48
  247. package/packages/bundled-features/src/inbound-mail-foundation/events.ts +54 -50
  248. package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +39 -39
  249. package/packages/bundled-features/src/inbound-mail-foundation/handlers/account-state.ts +8 -8
  250. package/packages/bundled-features/src/inbound-mail-foundation/handlers/connect-account.write.ts +25 -26
  251. package/packages/bundled-features/src/inbound-mail-foundation/handlers/disconnect-account.write.ts +7 -7
  252. package/packages/bundled-features/src/inbound-mail-foundation/handlers/ingest-message.write.ts +50 -51
  253. package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-accounts.query.ts +8 -8
  254. package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-messages.query.ts +10 -10
  255. package/packages/bundled-features/src/inbound-mail-foundation/handlers/scope-visibility.ts +3 -4
  256. package/packages/bundled-features/src/inbound-mail-foundation/handlers/update-account.write.ts +27 -15
  257. package/packages/bundled-features/src/inbound-mail-foundation/i18n.ts +0 -1
  258. package/packages/bundled-features/src/inbound-mail-foundation/oauth-state.ts +16 -15
  259. package/packages/bundled-features/src/inbound-mail-foundation/projection.ts +31 -29
  260. package/packages/bundled-features/src/inbound-mail-foundation/provider-factory.ts +9 -9
  261. package/packages/bundled-features/src/inbound-mail-foundation/retention-sweep.ts +45 -41
  262. package/packages/bundled-features/src/inbound-mail-foundation/screens.ts +0 -3
  263. package/packages/bundled-features/src/inbound-mail-foundation/tenant-destroy-hook.ts +14 -16
  264. package/packages/bundled-features/src/inbound-mail-foundation/types.ts +70 -70
  265. package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +101 -84
  266. package/packages/bundled-features/src/inbound-provider-imap/credential-document.ts +13 -13
  267. package/packages/bundled-features/src/inbound-provider-imap/feature.ts +42 -40
  268. package/packages/bundled-features/src/inbound-provider-imap/imap-client.ts +20 -19
  269. package/packages/bundled-features/src/inbound-provider-inmemory/feature.ts +21 -21
  270. package/packages/bundled-features/src/jobs/changes.json +13 -0
  271. package/packages/bundled-features/src/jobs/db/queries/retention.ts +2 -2
  272. package/packages/bundled-features/src/jobs/db/queries/stale-run-sweep.ts +3 -3
  273. package/packages/bundled-features/src/jobs/events.ts +1 -1
  274. package/packages/bundled-features/src/jobs/feature.ts +20 -11
  275. package/packages/bundled-features/src/jobs/handlers/detail.query.ts +4 -4
  276. package/packages/bundled-features/src/jobs/handlers/list.query.ts +1 -1
  277. package/packages/bundled-features/src/jobs/handlers/projection-rebuild.job.ts +1 -1
  278. package/packages/bundled-features/src/jobs/handlers/reindex-entity.job.ts +1 -1
  279. package/packages/bundled-features/src/jobs/handlers/retry.write.ts +1 -1
  280. package/packages/bundled-features/src/jobs/handlers/tenant-failures.query.ts +45 -40
  281. package/packages/bundled-features/src/jobs/handlers/tenant-runs.query.ts +63 -59
  282. package/packages/bundled-features/src/jobs/job-instant.ts +1 -1
  283. package/packages/bundled-features/src/jobs/job-run-logger.ts +19 -19
  284. package/packages/bundled-features/src/jobs/job-run-table.ts +3 -3
  285. package/packages/bundled-features/src/jobs/screens.ts +1 -1
  286. package/packages/bundled-features/src/jobs/tenant-job-failure-table.ts +1 -1
  287. package/packages/bundled-features/src/jobs/tenant-job-run-table.ts +1 -1
  288. package/packages/bundled-features/src/ledger/entity.ts +5 -5
  289. package/packages/bundled-features/src/ledger/feature.ts +3 -3
  290. package/packages/bundled-features/src/ledger/handlers/confirm-schedule-period.write.ts +3 -3
  291. package/packages/bundled-features/src/ledger/recurring.ts +12 -12
  292. package/packages/bundled-features/src/ledger/schemas.ts +1 -1
  293. package/packages/bundled-features/src/ledger/web/constants.ts +2 -2
  294. package/packages/bundled-features/src/ledger/web/index.ts +7 -7
  295. package/packages/bundled-features/src/legal-pages/README.md +1 -1
  296. package/packages/bundled-features/src/legal-pages/feature.ts +40 -41
  297. package/packages/bundled-features/src/legal-pages/markdown.ts +3 -3
  298. package/packages/bundled-features/src/legal-pages/web/client-plugin.ts +23 -24
  299. package/packages/bundled-features/src/legal-pages/web/index.ts +0 -2
  300. package/packages/bundled-features/src/mail-foundation/changes.json +6 -0
  301. package/packages/bundled-features/src/mail-foundation/feature.ts +31 -30
  302. package/packages/bundled-features/src/mail-transport-inmemory/feature.ts +27 -28
  303. package/packages/bundled-features/src/mail-transport-smtp/feature.ts +20 -20
  304. package/packages/bundled-features/src/managed-pages/branding.ts +6 -6
  305. package/packages/bundled-features/src/managed-pages/feature.ts +62 -62
  306. package/packages/bundled-features/src/managed-pages/handlers/by-slug.query.ts +5 -6
  307. package/packages/bundled-features/src/managed-pages/handlers/by-tenant-published.query.ts +8 -8
  308. package/packages/bundled-features/src/managed-pages/handlers/set.write.ts +5 -7
  309. package/packages/bundled-features/src/managed-pages/screens/page-screens.ts +11 -11
  310. package/packages/bundled-features/src/managed-pages/seeding.ts +8 -8
  311. package/packages/bundled-features/src/managed-pages/table.ts +16 -15
  312. package/packages/bundled-features/src/managed-pages/web/client-plugin.tsx +6 -6
  313. package/packages/bundled-features/src/managed-pages/web/i18n.ts +1 -1
  314. package/packages/bundled-features/src/notes-history/entity.ts +4 -4
  315. package/packages/bundled-features/src/notes-history/feature.ts +2 -2
  316. package/packages/bundled-features/src/notes-history-user-data/hooks.ts +1 -1
  317. package/packages/bundled-features/src/page-render/layout.ts +9 -9
  318. package/packages/bundled-features/src/page-render/markdown.ts +11 -11
  319. package/packages/bundled-features/src/page-render/security-headers.ts +7 -6
  320. package/packages/bundled-features/src/personal-access-tokens/feature.ts +9 -6
  321. package/packages/bundled-features/src/personal-access-tokens/roles.ts +2 -2
  322. package/packages/bundled-features/src/readiness/handlers/status.query.ts +3 -3
  323. package/packages/bundled-features/src/renderer-foundation/api.ts +12 -13
  324. package/packages/bundled-features/src/renderer-foundation/constants.ts +2 -2
  325. package/packages/bundled-features/src/renderer-foundation/feature.ts +7 -7
  326. package/packages/bundled-features/src/renderer-foundation/types.ts +11 -12
  327. package/packages/bundled-features/src/renderer-pdf/changes.json +6 -0
  328. package/packages/bundled-features/src/renderer-pdf/render-table-pdf.ts +27 -10
  329. package/packages/bundled-features/src/secrets/feature.ts +9 -9
  330. package/packages/bundled-features/src/secrets/web/constants.ts +2 -2
  331. package/packages/bundled-features/src/seo/feature.ts +3 -3
  332. package/packages/bundled-features/src/sessions/constants.ts +1 -1
  333. package/packages/bundled-features/src/sessions/feature.ts +16 -11
  334. package/packages/bundled-features/src/sessions/handlers/revoke-all-for-user.write.ts +2 -2
  335. package/packages/bundled-features/src/sessions/handlers/revoke-all-others.write.ts +2 -2
  336. package/packages/bundled-features/src/sessions/handlers/revoke.write.ts +1 -1
  337. package/packages/bundled-features/src/sessions/schema/user-session.ts +4 -4
  338. package/packages/bundled-features/src/sessions/screens.ts +2 -2
  339. package/packages/bundled-features/src/sessions/session-callbacks.ts +2 -2
  340. package/packages/bundled-features/src/sessions/session-revoked-event.ts +2 -2
  341. package/packages/bundled-features/src/shared/assert-no-where-rule-in-ownership-write.ts +1 -1
  342. package/packages/bundled-features/src/shared/decrypt-stored-pii.ts +11 -1
  343. package/packages/bundled-features/src/shared/encrypt-for-direct-write.ts +1 -1
  344. package/packages/bundled-features/src/shared/index.ts +1 -1
  345. package/packages/bundled-features/src/shared/mail-template-body.ts +10 -3
  346. package/packages/bundled-features/src/shared/map-with-concurrency.ts +5 -4
  347. package/packages/bundled-features/src/shared/parent-visibility.ts +2 -2
  348. package/packages/bundled-features/src/shared/password-hashing.ts +1 -1
  349. package/packages/bundled-features/src/shared/signup-handover.ts +1 -2
  350. package/packages/bundled-features/src/shared/single-use-token-store.ts +1 -1
  351. package/packages/bundled-features/src/step-dispatcher/changes.json +6 -0
  352. package/packages/bundled-features/src/step-dispatcher/feature.ts +1 -0
  353. package/packages/bundled-features/src/subscription-dodo/changes.json +14 -0
  354. package/packages/bundled-features/src/subscription-dodo/client.ts +45 -0
  355. package/packages/bundled-features/src/subscription-dodo/constants.ts +24 -0
  356. package/packages/bundled-features/src/subscription-dodo/feature.ts +207 -0
  357. package/packages/bundled-features/src/subscription-dodo/index.ts +16 -0
  358. package/packages/bundled-features/src/subscription-dodo/plugin-methods.ts +345 -0
  359. package/packages/bundled-features/src/subscription-dodo/runtime.ts +126 -0
  360. package/packages/bundled-features/src/subscription-dodo/verify-webhook.ts +262 -0
  361. package/packages/bundled-features/src/subscription-mollie/constants.ts +15 -17
  362. package/packages/bundled-features/src/subscription-mollie/feature.ts +41 -42
  363. package/packages/bundled-features/src/subscription-mollie/index.ts +3 -3
  364. package/packages/bundled-features/src/subscription-mollie/plugin-methods.ts +17 -16
  365. package/packages/bundled-features/src/subscription-mollie/verify-webhook.ts +34 -34
  366. package/packages/bundled-features/src/subscription-stripe/changes.json +12 -0
  367. package/packages/bundled-features/src/subscription-stripe/constants.ts +4 -6
  368. package/packages/bundled-features/src/subscription-stripe/feature.ts +45 -43
  369. package/packages/bundled-features/src/subscription-stripe/index.ts +6 -6
  370. package/packages/bundled-features/src/subscription-stripe/plugin-methods.ts +22 -27
  371. package/packages/bundled-features/src/subscription-stripe/runtime.ts +9 -8
  372. package/packages/bundled-features/src/subscription-stripe/verify-webhook.ts +62 -64
  373. package/packages/bundled-features/src/tags/feature.ts +3 -3
  374. package/packages/bundled-features/src/tags/screens.ts +1 -1
  375. package/packages/bundled-features/src/template-resolver/api.ts +41 -14
  376. package/packages/bundled-features/src/template-resolver/changes.json +48 -0
  377. package/packages/bundled-features/src/template-resolver/compile-document-body.ts +1 -0
  378. package/packages/bundled-features/src/template-resolver/feature.ts +2 -2
  379. package/packages/bundled-features/src/template-resolver/handlers/bundle-import.ts +3 -2
  380. package/packages/bundled-features/src/template-resolver/handlers/copy-locale.write.ts +27 -5
  381. package/packages/bundled-features/src/template-resolver/handlers/diff-to-system.query.ts +3 -2
  382. package/packages/bundled-features/src/template-resolver/handlers/document-base.ts +3 -2
  383. package/packages/bundled-features/src/template-resolver/handlers/find-by-id.query.ts +8 -7
  384. package/packages/bundled-features/src/template-resolver/handlers/list.query.ts +19 -20
  385. package/packages/bundled-features/src/template-resolver/handlers/overview.query.ts +15 -5
  386. package/packages/bundled-features/src/template-resolver/handlers/shared.ts +2 -2
  387. package/packages/bundled-features/src/template-resolver/handlers/template-write.ts +3 -3
  388. package/packages/bundled-features/src/template-resolver/handlers/tenant-override-counts.query.ts +9 -5
  389. package/packages/bundled-features/src/template-resolver/handlers/tenant-override-selection.ts +8 -6
  390. package/packages/bundled-features/src/template-resolver/handlers/tenant-overrides.query.ts +44 -5
  391. package/packages/bundled-features/src/template-resolver/handlers/upsert-system.write.ts +3 -4
  392. package/packages/bundled-features/src/template-resolver/handlers/upsert-tenant.write.ts +4 -5
  393. package/packages/bundled-features/src/template-resolver/handlers/usage.query.ts +37 -26
  394. package/packages/bundled-features/src/template-resolver/handlers/validate.query.ts +7 -2
  395. package/packages/bundled-features/src/template-resolver/seeding.ts +36 -18
  396. package/packages/bundled-features/src/template-resolver/store-template-resource.ts +22 -4
  397. package/packages/bundled-features/src/template-resolver/table.ts +13 -14
  398. package/packages/bundled-features/src/template-resolver/template-delivery-policy.ts +0 -11
  399. package/packages/bundled-features/src/template-resolver/template-meta.ts +12 -4
  400. package/packages/bundled-features/src/template-resolver/template-preview.ts +11 -3
  401. package/packages/bundled-features/src/template-resolver/web/client-plugin.tsx +2 -2
  402. package/packages/bundled-features/src/template-resolver/web/constants.ts +7 -5
  403. package/packages/bundled-features/src/template-resolver/web/index.ts +7 -0
  404. package/packages/bundled-features/src/template-resolver/web/mail-layout-constants.ts +8 -0
  405. package/packages/bundled-features/src/tenant/changes.json +6 -0
  406. package/packages/bundled-features/src/tenant/feature.ts +7 -7
  407. package/packages/bundled-features/src/tenant/handlers/member-directory.query.ts +10 -4
  408. package/packages/bundled-features/src/tenant/handlers/members.query.ts +1 -1
  409. package/packages/bundled-features/src/tenant/handlers/memberships.query.ts +1 -1
  410. package/packages/bundled-features/src/tenant/handlers/team-list.query.ts +1 -1
  411. package/packages/bundled-features/src/tenant/handlers/tenant-directory.query.ts +8 -5
  412. package/packages/bundled-features/src/tenant/invitation-table.ts +37 -40
  413. package/packages/bundled-features/src/tenant/membership-table.ts +3 -3
  414. package/packages/bundled-features/src/tenant/schema/tenant.ts +7 -9
  415. package/packages/bundled-features/src/tenant/screens.ts +1 -1
  416. package/packages/bundled-features/src/tenant/seeding.ts +19 -18
  417. package/packages/bundled-features/src/tenant/testing.ts +5 -6
  418. package/packages/bundled-features/src/tenant/web/constants.ts +2 -2
  419. package/packages/bundled-features/src/tenant-handover/events.ts +5 -7
  420. package/packages/bundled-features/src/tenant-handover/feature.ts +1 -1
  421. package/packages/bundled-features/src/tenant-handover/grant.ts +1 -1
  422. package/packages/bundled-features/src/tenant-handover/handlers/claim.write.ts +1 -1
  423. package/packages/bundled-features/src/tenant-handover/move-entity-graph.ts +8 -9
  424. package/packages/bundled-features/src/tenant-handover/signup-handover-provider.ts +1 -2
  425. package/packages/bundled-features/src/tenant-handover/transfer-graph.ts +4 -5
  426. package/packages/bundled-features/src/tenant-lifecycle/boot-checks.ts +1 -1
  427. package/packages/bundled-features/src/tenant-lifecycle/changes.json +6 -0
  428. package/packages/bundled-features/src/tenant-lifecycle/constants.ts +5 -0
  429. package/packages/bundled-features/src/tenant-lifecycle/feature.ts +1 -1
  430. package/packages/bundled-features/src/tenant-lifecycle/run-tenant-destroy.ts +7 -3
  431. package/packages/bundled-features/src/tenant-lifecycle/stages.ts +1 -1
  432. package/packages/bundled-features/src/tenant-settings/constants.ts +1 -1
  433. package/packages/bundled-features/src/tenant-settings/tenant-defaults.ts +12 -5
  434. package/packages/bundled-features/src/tier-engine/aggregate-id.ts +15 -16
  435. package/packages/bundled-features/src/tier-engine/changes.json +6 -0
  436. package/packages/bundled-features/src/tier-engine/compose-app.ts +14 -14
  437. package/packages/bundled-features/src/tier-engine/entity.ts +18 -19
  438. package/packages/bundled-features/src/tier-engine/feature.ts +88 -87
  439. package/packages/bundled-features/src/tier-engine/handlers/active-tier.query.ts +6 -7
  440. package/packages/bundled-features/src/tier-engine/handlers/get-tenant-tier.query.ts +4 -4
  441. package/packages/bundled-features/src/tier-engine/handlers/set-tenant-tier.write.ts +12 -9
  442. package/packages/bundled-features/src/tier-engine/tier-resolver.ts +2 -2
  443. package/packages/bundled-features/src/tier-engine/trial.ts +13 -13
  444. package/packages/bundled-features/src/tier-engine/web/constants.ts +3 -3
  445. package/packages/bundled-features/src/tier-engine/web/index.ts +4 -4
  446. package/packages/bundled-features/src/user/db/queries/stream-tenant-backfill.ts +8 -8
  447. package/packages/bundled-features/src/user/handlers/create.write.ts +4 -4
  448. package/packages/bundled-features/src/user/schema/user.ts +45 -44
  449. package/packages/bundled-features/src/user/seeding.ts +40 -40
  450. package/packages/bundled-features/src/user/testing.ts +3 -3
  451. package/packages/bundled-features/src/user-data-rights/audit-download.ts +27 -28
  452. package/packages/bundled-features/src/user-data-rights/boot-checks.ts +1 -1
  453. package/packages/bundled-features/src/user-data-rights/deletion-token.ts +1 -1
  454. package/packages/bundled-features/src/user-data-rights/feature.ts +112 -113
  455. package/packages/bundled-features/src/user-data-rights/handlers/cancel-deletion.write.ts +9 -9
  456. package/packages/bundled-features/src/user-data-rights/handlers/confirm-deletion-by-token.write.ts +8 -8
  457. package/packages/bundled-features/src/user-data-rights/handlers/download-by-job.query.ts +29 -30
  458. package/packages/bundled-features/src/user-data-rights/handlers/download-by-token.query.ts +40 -42
  459. package/packages/bundled-features/src/user-data-rights/handlers/export-status.query.ts +8 -9
  460. package/packages/bundled-features/src/user-data-rights/handlers/lift-restriction.write.ts +7 -8
  461. package/packages/bundled-features/src/user-data-rights/handlers/list-download-attempts.query.ts +2 -2
  462. package/packages/bundled-features/src/user-data-rights/handlers/my-audit-log.query.ts +4 -4
  463. package/packages/bundled-features/src/user-data-rights/handlers/request-deletion-by-email.write.ts +30 -29
  464. package/packages/bundled-features/src/user-data-rights/handlers/request-deletion.write.ts +15 -18
  465. package/packages/bundled-features/src/user-data-rights/handlers/request-export.write.ts +42 -41
  466. package/packages/bundled-features/src/user-data-rights/handlers/restrict-account.write.ts +22 -19
  467. package/packages/bundled-features/src/user-data-rights/handlers/run-forget-cleanup.write.ts +8 -8
  468. package/packages/bundled-features/src/user-data-rights/index.ts +8 -10
  469. package/packages/bundled-features/src/user-data-rights/lib/default-mailers.ts +3 -3
  470. package/packages/bundled-features/src/user-data-rights/lib/update-user-lifecycle.ts +24 -27
  471. package/packages/bundled-features/src/user-data-rights/run-export-jobs.ts +169 -280
  472. package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +87 -108
  473. package/packages/bundled-features/src/user-data-rights/run-user-export.ts +67 -69
  474. package/packages/bundled-features/src/user-data-rights/schema/download-attempt.ts +11 -11
  475. package/packages/bundled-features/src/user-data-rights/schema/download-token.ts +37 -41
  476. package/packages/bundled-features/src/user-data-rights/schema/export-job.ts +65 -67
  477. package/packages/bundled-features/src/user-data-rights/token-helpers.ts +21 -25
  478. package/packages/bundled-features/src/user-data-rights/web/client-plugin.tsx +6 -6
  479. package/packages/bundled-features/src/user-data-rights/web/confirm-deletion-screen.tsx +6 -5
  480. package/packages/bundled-features/src/user-data-rights/web/constants.ts +1 -1
  481. package/packages/bundled-features/src/user-data-rights/web/index.ts +5 -5
  482. package/packages/bundled-features/src/user-data-rights/web/privacy-center-screen.tsx +14 -13
  483. package/packages/bundled-features/src/user-data-rights/web/public-deletion-gate.tsx +13 -12
  484. package/packages/bundled-features/src/user-data-rights/web/request-deletion-screen.tsx +6 -6
  485. package/packages/bundled-features/src/user-data-rights/zip-path.ts +41 -40
  486. package/packages/bundled-features/src/user-data-rights-defaults/feature.ts +15 -15
  487. package/packages/bundled-features/src/user-data-rights-defaults/hooks/delivery-attempt.userdata-hook.ts +3 -5
  488. package/packages/bundled-features/src/user-data-rights-defaults/hooks/file-ref.userdata-hook.ts +45 -51
  489. package/packages/bundled-features/src/user-data-rights-defaults/hooks/job-run.userdata-hook.ts +2 -2
  490. package/packages/bundled-features/src/user-data-rights-defaults/hooks/notification-preference.userdata-hook.ts +1 -1
  491. package/packages/bundled-features/src/user-data-rights-defaults/hooks/user-session.userdata-hook.ts +3 -3
  492. package/packages/bundled-features/src/user-data-rights-defaults/hooks/user.userdata-hook.ts +32 -31
  493. package/packages/bundled-features/src/user-profile/handlers/change-email.write.ts +13 -13
  494. package/packages/bundled-features/src/user-profile/index.ts +3 -3
  495. package/packages/bundled-features/src/user-profile/web/client-plugin.ts +1 -1
  496. package/packages/bundled-features/src/user-profile/web/constants.ts +1 -1
  497. package/packages/bundled-features/src/user-profile/web/profile-screen.tsx +1 -1
  498. package/packages/bundled-features/src/waitlist/changes.json +18 -0
  499. package/packages/bundled-features/src/waitlist/handlers/export-purge.write.ts +2 -1
  500. package/packages/bundled-features/src/waitlist/handlers/submit.write.ts +5 -5
  501. package/packages/bundled-features/src/waitlist/import.ts +5 -0
  502. package/packages/bundled-features/src/waitlist/legacy-migrate.ts +22 -3
  503. package/packages/bundled-features/src/waitlist/link-on-signup.ts +20 -10
  504. package/packages/bundled-features/src/waitlist/options.ts +3 -0
  505. package/packages/bundled-features/src/workflow-runner/aggregate-id.ts +1 -1
  506. package/packages/bundled-features/src/workflow-runner/event-subscriber.ts +4 -5
  507. package/packages/bundled-features/src/workflow-runner/event-trigger.ts +4 -15
  508. package/packages/bundled-features/src/workflow-runner/feature.ts +2 -2
  509. package/packages/bundled-features/src/workflow-runner/handlers/resume-run.write.ts +4 -4
  510. package/packages/bundled-features/src/workflow-runner/pending-projection.ts +6 -7
  511. package/packages/bundled-features/src/workflow-runner/runner.ts +6 -6
  512. package/packages/bundled-features/src/workflow-runner/tables.ts +6 -6
  513. package/packages/bundled-features/src/workflow-runner/workflow-registry.ts +1 -1
  514. package/samples/apps/styleguide/src/features/widgets/i18n.ts +11 -0
  515. package/samples/apps/styleguide/src/features/widgets/web/Widgets.tsx +24 -0
  516. package/samples/apps/use-all-bundled/e2e-billing-gallery/gallery-constants.ts +5 -0
  517. package/samples/apps/use-all-bundled/e2e-billing-gallery/gallery-features.ts +90 -15
  518. package/samples/apps/use-all-bundled/e2e-billing-gallery/server.ts +16 -6
  519. package/samples/apps/use-all-bundled/feature-manifest.json +120 -3
  520. package/samples/apps/use-all-bundled/src/run-config.ts +9 -3
  521. package/samples/recipes/auth-mfa/README.md +5 -0
  522. package/samples/recipes/auth-mfa/package.json +5 -2
  523. package/samples/recipes/auth-mfa/src/web/confirmation-code-step.tsx +49 -0
  524. package/samples/recipes/auth-mfa/tsconfig.json +8 -0
  525. package/samples/recipes/env-composition/README.md +3 -1
  526. package/samples/recipes/env-composition/src/env.ts +2 -0
  527. package/samples/recipes/legal-pages/README.md +1 -1
  528. package/samples/recipes/rate-limiting/README.md +18 -0
  529. package/samples/recipes/rate-limiting/src/feature.ts +12 -0
  530. package/packages/bundled-features/src/billing-foundation/consumer-protection/stored-user-email.ts +0 -12
@@ -0,0 +1,262 @@
1
+ // Dodo Payments webhook: Standard Webhooks signature verification plus mapping
2
+ // of Dodo's event envelope onto the foundation's normalized events.
3
+ //
4
+ // Verification always runs against the raw body string; re-serialized JSON
5
+ // would change whitespace and break the HMAC. The signature check happens
6
+ // before any parsing, so no path bypasses it.
7
+
8
+ import { createHmac, timingSafeEqual } from "node:crypto";
9
+ import {
10
+ BillingEventKinds,
11
+ type PaymentEvent,
12
+ parseProviderConsentId,
13
+ type SubscriptionEvent,
14
+ type SubscriptionEventType,
15
+ SubscriptionEventTypes,
16
+ type SubscriptionStatus,
17
+ SubscriptionStatuses,
18
+ } from "@cosmicdrift/kumiko-bundled-features/billing-foundation";
19
+ import type { SecretsContext } from "@cosmicdrift/kumiko-framework/secrets";
20
+ import { parseJsonOrThrow } from "@cosmicdrift/kumiko-framework/utils";
21
+ import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
22
+ import * as z from "zod";
23
+ import { DODO_PROVIDER_NAME } from "./constants.ts";
24
+ import type { DodoWebhookRuntime } from "./runtime.ts";
25
+
26
+ export const WEBHOOK_TOLERANCE_SECONDS = 300;
27
+
28
+ const SECRET_PREFIX = "whsec_";
29
+ const SIGNATURE_VERSION = "v1";
30
+ const TIMESTAMP_PATTERN = /^\d+$/;
31
+
32
+ export type StandardWebhookHeaders = Readonly<Record<string, string>>;
33
+
34
+ function signatureFor(secretKey: Buffer, signedContent: string): Buffer {
35
+ return createHmac("sha256", secretKey).update(signedContent).digest();
36
+ }
37
+
38
+ function matchesAnyV1Signature(header: string, expected: Buffer): boolean {
39
+ return header.split(" ").some((entry) => {
40
+ const [version, encoded] = entry.split(",");
41
+ if (version !== SIGNATURE_VERSION || !encoded) return false;
42
+ const candidate = Buffer.from(encoded, "base64");
43
+ return candidate.length === expected.length && timingSafeEqual(candidate, expected);
44
+ });
45
+ }
46
+
47
+ /** Throws unless the Standard Webhooks signature over `rawBody` is valid and
48
+ * the timestamp is within the tolerance in both directions. */
49
+ export function verifyStandardWebhook(
50
+ rawBody: string,
51
+ headers: StandardWebhookHeaders,
52
+ secret: string,
53
+ nowSeconds: number,
54
+ ): void {
55
+ const id = headers["webhook-id"];
56
+ const timestamp = headers["webhook-timestamp"];
57
+ const signatureHeader = headers["webhook-signature"];
58
+ if (!id || !timestamp || !signatureHeader) {
59
+ throw new Error(
60
+ "subscription-dodo: webhook-id, webhook-timestamp or webhook-signature missing",
61
+ );
62
+ }
63
+ if (!TIMESTAMP_PATTERN.test(timestamp)) {
64
+ throw new Error("subscription-dodo: webhook-timestamp is not a Unix timestamp in seconds");
65
+ }
66
+ if (Math.abs(nowSeconds - Number(timestamp)) > WEBHOOK_TOLERANCE_SECONDS) {
67
+ throw new Error("subscription-dodo: webhook timestamp outside the tolerance window");
68
+ }
69
+ const secretKey = Buffer.from(
70
+ secret.startsWith(SECRET_PREFIX) ? secret.slice(SECRET_PREFIX.length) : secret,
71
+ "base64",
72
+ );
73
+ const expected = signatureFor(secretKey, `${id}.${timestamp}.${rawBody}`);
74
+ if (!matchesAnyV1Signature(signatureHeader, expected)) {
75
+ throw new Error("subscription-dodo: webhook signature verify failed");
76
+ }
77
+ }
78
+
79
+ // =============================================================================
80
+ // Event mapping
81
+ // =============================================================================
82
+
83
+ const DODO_SUBSCRIPTION_EVENT_TYPES: Readonly<Record<string, SubscriptionEventType>> = {
84
+ "subscription.active": SubscriptionEventTypes.created,
85
+ "subscription.updated": SubscriptionEventTypes.updated,
86
+ "subscription.plan_changed": SubscriptionEventTypes.updated,
87
+ "subscription.paused": SubscriptionEventTypes.updated,
88
+ "subscription.unpaused": SubscriptionEventTypes.updated,
89
+ "subscription.update_payment_method": SubscriptionEventTypes.updated,
90
+ "subscription.renewed": SubscriptionEventTypes.invoicePaid,
91
+ "subscription.past_due": SubscriptionEventTypes.invoicePaymentFailed,
92
+ "subscription.on_hold": SubscriptionEventTypes.invoicePaymentFailed,
93
+ "subscription.cancelled": SubscriptionEventTypes.canceled,
94
+ "subscription.expired": SubscriptionEventTypes.canceled,
95
+ "subscription.failed": SubscriptionEventTypes.canceled,
96
+ };
97
+
98
+ const DODO_SUBSCRIPTION_STATUSES: Readonly<Record<string, SubscriptionStatus>> = {
99
+ pending: SubscriptionStatuses.incomplete,
100
+ active: SubscriptionStatuses.active,
101
+ on_hold: SubscriptionStatuses.pastDue,
102
+ past_due: SubscriptionStatuses.pastDue,
103
+ paused: SubscriptionStatuses.pastDue,
104
+ cancelled: SubscriptionStatuses.canceled,
105
+ failed: SubscriptionStatuses.canceled,
106
+ expired: SubscriptionStatuses.canceled,
107
+ };
108
+
109
+ const PAYMENT_SUCCEEDED = "payment.succeeded";
110
+
111
+ const metadataSchema = z.record(z.string(), z.unknown()).nullish();
112
+ const customerSchema = z.object({ customer_id: z.string().min(1) });
113
+
114
+ const envelopeSchema = z.object({
115
+ type: z.string(),
116
+ timestamp: z.iso.datetime({ offset: true }),
117
+ data: z.unknown(),
118
+ });
119
+
120
+ export const dodoSubscriptionSchema = z.object({
121
+ subscription_id: z.string().min(1),
122
+ product_id: z.string().min(1),
123
+ status: z.string(),
124
+ customer: customerSchema,
125
+ metadata: metadataSchema,
126
+ next_billing_date: z.iso.datetime({ offset: true }),
127
+ cancel_at_next_billing_date: z.boolean().nullish(),
128
+ });
129
+ export type DodoSubscription = z.infer<typeof dodoSubscriptionSchema>;
130
+
131
+ const dodoPaymentSchema = z.object({
132
+ subscription_id: z.string().nullish(),
133
+ checkout_session_id: z.string().nullish(),
134
+ customer: customerSchema,
135
+ metadata: metadataSchema,
136
+ product_cart: z.array(z.object({ product_id: z.string().min(1) })).nullish(),
137
+ });
138
+
139
+ function metadataString(metadata: DodoSubscription["metadata"], key: string): string | undefined {
140
+ const value = metadata?.[key];
141
+ return typeof value === "string" && value.length > 0 ? value : undefined;
142
+ }
143
+
144
+ export type MappedDodoSubscriptionState = {
145
+ readonly status: SubscriptionStatus;
146
+ readonly tier: string;
147
+ readonly currentPeriodEnd: string;
148
+ readonly cancelAt: string | null;
149
+ };
150
+
151
+ /** Shared by the webhook and retrieveSubscription so both map Dodo state
152
+ * identically. Null when the status is unknown or the product is not in
153
+ * `priceToTier` (SubscriptionEvent.tier is required). */
154
+ export function mapDodoSubscriptionState(
155
+ sub: DodoSubscription,
156
+ priceToTier: Readonly<Record<string, string>>,
157
+ ): MappedDodoSubscriptionState | null {
158
+ const status = DODO_SUBSCRIPTION_STATUSES[sub.status];
159
+ const tier = priceToTier[sub.product_id];
160
+ if (!status || !tier) return null;
161
+ return {
162
+ status,
163
+ tier,
164
+ currentPeriodEnd: sub.next_billing_date,
165
+ cancelAt: sub.cancel_at_next_billing_date === true ? sub.next_billing_date : null,
166
+ };
167
+ }
168
+
169
+ export type DodoWebhookOptions = {
170
+ readonly priceToTier: Readonly<Record<string, string>>;
171
+ /** Test seam: Unix seconds. Defaults to the wall clock. */
172
+ readonly nowSeconds?: () => number;
173
+ };
174
+
175
+ function currentUnixSeconds(): number {
176
+ return Math.floor(Temporal.Now.instant().epochMilliseconds / 1000);
177
+ }
178
+
179
+ function parsePaymentEvent(providerEventId: string, data: unknown): PaymentEvent | null {
180
+ const parsed = dodoPaymentSchema.safeParse(data);
181
+ if (!parsed.success) return null;
182
+ const payment = parsed.data;
183
+ // A subscription's own payments are covered by its subscription.* events.
184
+ if (payment.subscription_id) return null;
185
+ const tenantId = metadataString(payment.metadata, "tenantId");
186
+ const priceId = payment.product_cart?.[0]?.product_id;
187
+ if (!tenantId || !priceId) return null;
188
+ const consentId = parseProviderConsentId(payment.metadata?.["consentId"]);
189
+ return {
190
+ kind: BillingEventKinds.payment,
191
+ providerEventId,
192
+ providerName: DODO_PROVIDER_NAME,
193
+ tenantId,
194
+ ...(consentId !== undefined && { consentId }),
195
+ ...(payment.checkout_session_id && { providerCheckoutId: payment.checkout_session_id }),
196
+ providerCustomerId: payment.customer.customer_id,
197
+ priceId,
198
+ };
199
+ }
200
+
201
+ function parseSubscriptionEvent(
202
+ providerEventId: string,
203
+ type: SubscriptionEventType,
204
+ providerEventAt: string,
205
+ data: unknown,
206
+ priceToTier: Readonly<Record<string, string>>,
207
+ ): SubscriptionEvent | null {
208
+ const parsed = dodoSubscriptionSchema.safeParse(data);
209
+ if (!parsed.success) return null;
210
+ const sub = parsed.data;
211
+ const tenantId = metadataString(sub.metadata, "tenantId");
212
+ const state = mapDodoSubscriptionState(sub, priceToTier);
213
+ if (!tenantId || !state) return null;
214
+ const consentId = parseProviderConsentId(sub.metadata?.["consentId"]);
215
+ return {
216
+ providerEventId,
217
+ providerName: DODO_PROVIDER_NAME,
218
+ type,
219
+ tenantId,
220
+ ...(consentId !== undefined && { consentId }),
221
+ providerCustomerId: sub.customer.customer_id,
222
+ providerSubscriptionId: sub.subscription_id,
223
+ providerEventAt,
224
+ ...state,
225
+ };
226
+ }
227
+
228
+ export function verifyAndParseDodoWebhook(
229
+ runtime: DodoWebhookRuntime,
230
+ options: DodoWebhookOptions,
231
+ ): (
232
+ rawBody: string,
233
+ headers: Record<string, string>,
234
+ systemSecrets?: SecretsContext,
235
+ ) => Promise<SubscriptionEvent | PaymentEvent | null> {
236
+ const nowSeconds = options.nowSeconds ?? currentUnixSeconds;
237
+ return async (rawBody, headers, systemSecrets) => {
238
+ const secret = await runtime.resolveWebhookSecret(systemSecrets);
239
+ verifyStandardWebhook(rawBody, headers, secret, nowSeconds());
240
+
241
+ // Past verification the body is trusted to be Dodo's; a malformed shape is
242
+ // schema drift, so it is dropped (200 ignored) instead of answered with a 401.
243
+ const envelope = envelopeSchema.safeParse(
244
+ parseJsonOrThrow<unknown>(rawBody, "subscription-dodo webhook body"),
245
+ );
246
+ // verifyStandardWebhook has checked webhook-id is present.
247
+ const providerEventId = headers["webhook-id"];
248
+ if (!envelope.success || !providerEventId) return null;
249
+
250
+ const { type, timestamp, data } = envelope.data;
251
+ if (type === PAYMENT_SUCCEEDED) return parsePaymentEvent(providerEventId, data);
252
+ const normalizedType = DODO_SUBSCRIPTION_EVENT_TYPES[type];
253
+ if (!normalizedType) return null;
254
+ return parseSubscriptionEvent(
255
+ providerEventId,
256
+ normalizedType,
257
+ timestamp,
258
+ data,
259
+ options.priceToTier,
260
+ );
261
+ };
262
+ }
@@ -1,33 +1,31 @@
1
1
  // Feature name
2
2
  export const SUBSCRIPTION_MOLLIE_FEATURE = "subscription-mollie" as const;
3
3
 
4
- // entityName under den der Plugin gegen "subscriptionProvider"
5
- // registriert. Matcht den path-segment in der webhook-URL
4
+ // Entity name under which the plugin registers against
5
+ // "subscriptionProvider". Matches the path segment in the webhook URL
6
6
  // `/api/subscription/webhook/mollie`.
7
7
  export const MOLLIE_PROVIDER_NAME = "mollie" as const;
8
8
 
9
9
  // =============================================================================
10
- // Mollie-Webhook-Pattern (anders als Stripe!)
10
+ // Mollie webhook pattern (unlike Stripe)
11
11
  // =============================================================================
12
12
  //
13
- // Mollie sendet bei JEDEM event nur die ID im body (form-urlencoded
14
- // oder JSON). Plugin muss IMMER lazy-fetchen via Mollie-API:
15
- // - `id=tr_xxx` → payment-id, fetch payment + subscription
16
- // - `id=sub_xxx` → subscription-id, fetch subscription direkt
13
+ // Mollie sends only the ID in the body for EVERY event (form-urlencoded
14
+ // or JSON). The plugin must ALWAYS fetch lazily via the Mollie API:
15
+ // - `id=tr_xxx` → payment ID, fetch payment + subscription
16
+ // - `id=sub_xxx` → subscription ID, fetch subscription directly
17
17
  //
18
- // **Keine native HMAC-sig-verify** in Mollie-SDK 4.5.0. Mollie's
19
- // Sicherheits-Modell stützt sich auf nicht-guessable IDs (~10^25
20
- // brute-force-space) + API-Lookup-Validation (garbage-id → 401 von
21
- // Mollie-API). Plus: App-Builder kann zusätzlich einen URL-Token-
22
- // Wrapper vor die Foundation-route schalten (eigener extraRoute der
23
- // einen secret-token im URL-Pfad verifiziert + dann an die Foundation
24
- // weiterreicht).
18
+ // **No native HMAC signature verification** in Mollie SDK 4.5.0. Mollie's
19
+ // security model relies on non-guessable IDs (~10^25 brute-force space)
20
+ // plus API lookup validation (garbage ID → 401 from the Mollie API). In
21
+ // addition, the app builder can place a URL-token wrapper before the
22
+ // foundation route (a custom extraRoute that verifies a secret token in
23
+ // the URL path and then forwards to the foundation).
25
24
  //
26
- // **Event-Type-Mapping** ist heuristisch — Mollie hat keine explicit-
27
- // typed events:
25
+ // **Event type mapping** is heuristic—Mollie has no explicitly typed events:
28
26
  // - sub_xxx + status=canceled/completed → SubscriptionEventTypes.canceled
29
27
  // - sub_xxx + status=active/pending → SubscriptionEventTypes.updated
30
28
  // - tr_xxx + sequenceType=first + paid → SubscriptionEventTypes.created
31
29
  // - tr_xxx + sequenceType=recurring + paid → SubscriptionEventTypes.invoicePaid
32
30
  // - tr_xxx + sequenceType=recurring + failed → SubscriptionEventTypes.invoicePaymentFailed
33
- // - alles andere → null (foundation 200 ignored)
31
+ // - everything else → null (foundation 200 ignored)
@@ -1,26 +1,26 @@
1
1
  // kumiko-feature-version: 1
2
2
  //
3
- // subscription-mollie — Mollie-Plugin für die subscription-foundation
4
- // Plugin-API (EU-Compliance-Story für DACH-Mid-Market).
3
+ // subscription-mollie — Mollie plugin for subscription-foundation
4
+ // plugin API (EU compliance for the DACH mid-market).
5
5
  //
6
- // **Factory-Pattern (analog subscription-stripe):** liest API-key beim
7
- // mount-time aus den factory-options (typisch process.env aus dem App-
8
- // Builder-bin/server.ts). Mollie hat KEIN webhook-secret — Mollie-SDK
9
- // 4.5.0 bietet keine native HMAC-sig-verify-API. Sicherheit kommt aus
10
- // nicht-guessable IDs + API-Validation; App-Builder kann optional
11
- // einen URL-Token-Wrapper davor schalten.
6
+ // **Factory pattern (analogous to subscription-stripe):** reads the API key
7
+ // at mount time from the factory options (typically process.env from the app
8
+ // builder's bin/server.ts). Mollie has NO webhook secret — Mollie SDK
9
+ // 4.5.0 provides no native HMAC signature verification API. Security comes
10
+ // from non-guessable IDs + API validation; the app builder can optionally
11
+ // add a URL-token wrapper in front.
12
12
  //
13
- // **Phase-5.3-Scope:**
13
+ // **Scope:**
14
14
  // - verifyAndParseWebhook ✓ (lazy-fetch payment + subscription via
15
- // Mollie-API, heuristisches event-type-mapping)
16
- // - createCheckoutSession ✓ (Mollie's mehrstufiger flow: customer
17
- // anlegen + first-payment mit sequenceType="first" → redirectUrl)
18
- // - createPortalSession ✗ (Mollie hat keinen Customer-Portal)
19
- // - cancelSubscription ✗ (Mollie braucht customerId zusätzlich zur
20
- // subId; Plugin-Contract reicht's nicht durch — App-Builder cancelt
21
- // via Mollie-Dashboard oder custom-route)
15
+ // Mollie API, heuristic event-type mapping)
16
+ // - createCheckoutSession ✓ (Mollie's multistep flow: create customer
17
+ // + first payment with sequenceType="first" → redirectUrl)
18
+ // - createPortalSession ✗ (Mollie has no customer portal)
19
+ // - cancelSubscription ✗ (Mollie additionally requires customerId besides
20
+ // subId; the plugin contract does not pass it through — the app builder
21
+ // cancels via the Mollie dashboard or a custom route)
22
22
  //
23
- // **Beispiel-Verwendung in run-config.ts:**
23
+ // **Example usage in run-config.ts:**
24
24
  //
25
25
  // const features = [
26
26
  // billingFoundationFeature,
@@ -62,29 +62,28 @@ export const subscriptionMollieEnvSchema = z.object({
62
62
  });
63
63
 
64
64
  export type SubscriptionMollieOptions = {
65
- /** Mollie-API-key (`test_...` oder `live_...`). App-wide, beim Plugin-
66
- * mount aus process.env oder system-config. */
65
+ /** Mollie API key (`test_...` or `live_...`). App-wide, mounted from
66
+ * process.env or system configuration. */
67
67
  readonly apiKey: string;
68
- /** Foundation-webhook-URL die der App-Builder unter Mollie-Dashboard
69
- * als webhook eingetragen hat. Plugin reicht das beim payment-
70
- * create an Mollie weiter — Mollie sendet beim payment-event
71
- * webhooks an diese URL. Typisch:
68
+ /** Foundation webhook URL registered by the app builder in the Mollie
69
+ * dashboard. The plugin passes it to Mollie when creating a payment;
70
+ * Mollie sends payment-event webhooks to this URL. Typically:
72
71
  * `https://app.example.com/api/subscription/webhook/mollie`. */
73
72
  readonly webhookUrl: string;
74
- /** Price-to-tier-Map. Plugin liest die priceId aus dem subscription-
75
- * metadata (= `metadata.priceId` den der App-Builder beim
76
- * createCheckoutSession setzt) und mappt auf einen tier-name. */
73
+ /** Price-to-tier map. The plugin reads the priceId from the subscription
74
+ * metadata (= `metadata.priceId` set by the app builder when calling
75
+ * createCheckoutSession) and maps it to a tier name. */
77
76
  readonly priceToTier: Readonly<Record<string, string>>;
78
- /** Mollie-Subscription-Setup pro priceId. Mollie hat keinen nativen
79
- * price-id-Konzept — App-Builder muss pro virtuellem priceId einen
80
- * amount/interval/description bereitstellen. */
77
+ /** Mollie subscription setup per priceId. Mollie has no native price-ID
78
+ * concept, so the app builder must provide an amount/interval/description
79
+ * for each virtual priceId. */
81
80
  readonly priceToConfig: Readonly<Record<string, MolliePriceConfig>>;
82
- /** @internal Test-only injection-port: ersetzt den verify-webhook-
83
- * fetch-client durch eine Mock-instance. Production left undefined —
84
- * factory baut den Adapter aus `createMollieClient(apiKey)`. Wird
85
- * vom IT (mollie-foundation.integration.ts) genutzt damit der echte
86
- * factory-Code (drift-validation, plugin-registration) im Test-pfad
87
- * durchläuft, ohne dass Mollie-API-Calls passieren. */
81
+ /** @internal Test-only injection port: replaces the verify-webhook fetch
82
+ * client with a mock instance. Production leaves this undefined; the
83
+ * factory builds the adapter from `createMollieClient(apiKey)`. The
84
+ * integration test (mollie-foundation.integration.ts) uses it so the real
85
+ * factory code (drift validation, plugin registration) runs in the test
86
+ * path without making Mollie API calls. */
88
87
  readonly _clientShapeForTests?: MollieClientShape;
89
88
  };
90
89
 
@@ -102,8 +101,8 @@ export function createSubscriptionMollieFeature(
102
101
  );
103
102
  }
104
103
 
105
- // Drift-Guard: priceToTier + priceToConfig müssen identische Keys
106
- // haben — sonst silent-null-returns aus verifyAndParseWebhook.
104
+ // Drift guard: priceToTier and priceToConfig must have identical keys;
105
+ // otherwise verifyAndParseWebhook silently returns null.
107
106
  const tierKeys = new Set(Object.keys(options.priceToTier));
108
107
  const configKeys = new Set(Object.keys(options.priceToConfig));
109
108
  const missingInConfig = [...tierKeys].filter((k) => !configKeys.has(k));
@@ -118,9 +117,9 @@ export function createSubscriptionMollieFeature(
118
117
 
119
118
  const client = createMollieClient({ apiKey: options.apiKey });
120
119
 
121
- // Adapter um den Plugin's verify-fetch-client an den vollen Mollie-
122
- // Client zu binden. Plugin-fetch-API ist minimal damit Tests ohne
123
- // den vollen MollieClient mocken können.
120
+ // Adapter that binds the plugin's minimal fetch client to the full Mollie
121
+ // client. The minimal plugin fetch API lets tests mock it without mocking
122
+ // the full MollieClient.
124
123
  const fetchAdapter: MollieClientShape = options._clientShapeForTests ?? {
125
124
  payments: { get: (id: string) => client.payments.get(id) },
126
125
  customerSubscriptions: {
@@ -160,8 +159,8 @@ export function createSubscriptionMollieFeature(
160
159
  const plugin: SubscriptionProviderPlugin = {
161
160
  verifyAndParseWebhook: verifyAndParse,
162
161
  createCheckoutSession: checkoutSession,
163
- // createPortalSession + cancelSubscription bewusst nicht — siehe
164
- // plugin-methods.ts für Begründung.
162
+ // createPortalSession and cancelSubscription are intentionally omitted;
163
+ // see plugin-methods.ts for why.
165
164
  priceToTier: options.priceToTier,
166
165
  };
167
166
  r.useExtension("subscriptionProvider", MOLLIE_PROVIDER_NAME, plugin);
@@ -1,9 +1,9 @@
1
1
  // Public API of the subscription-mollie bundled-feature.
2
2
  //
3
- // **Internal-only** (NICHT im public-barrel — App-Builder nutzt das nie direkt):
4
- // - verifyAndParseMollieWebhook (intern vom feature.ts factory aufgerufen)
3
+ // **Internal-only** (not in the public barrel—the App Builder never uses it directly):
4
+ // - verifyAndParseMollieWebhook (called internally by the feature.ts factory)
5
5
  // - mapMollieEventType / mapMollieStatus / extractMollieId (pure helpers,
6
- // test-only — direct-import aus dem File wenn echt mal extern gebraucht)
6
+ // test-only—direct-import from the file if ever genuinely needed externally)
7
7
 
8
8
  export { MOLLIE_PROVIDER_NAME, SUBSCRIPTION_MOLLIE_FEATURE } from "./constants.ts";
9
9
  export {
@@ -1,17 +1,18 @@
1
- // Mollie-Plugin-Methoden für die POST-tenant-resolution-Phase:
2
- // createCheckoutSession (only). createPortalSession + cancelSubscription
3
- // nicht implementiert weil Mollie's API die Patterns nicht 1:1 bietet:
1
+ // Mollie plugin methods for the POST-tenant-resolution phase:
2
+ // createCheckoutSession only. createPortalSession and cancelSubscription
3
+ // are not implemented because Mollie's API does not provide these patterns
4
+ // 1:1:
4
5
  //
5
- // - **Portal:** Mollie hat keinen Customer-Portal — App-Builder UI muss
6
- // das selbst rendern.
7
- // - **Cancel:** Mollie braucht (customerId, subId), Plugin-Contract
8
- // reicht aber nur subId durch — App-Builder cancelt via Mollie-
9
- // Dashboard oder eigener Route bis Foundation-Contract erweitert ist.
6
+ // - **Portal:** Mollie has no customer portal, so the App Builder UI must
7
+ // render it itself.
8
+ // - **Cancel:** Mollie requires (customerId, subId), but the plugin contract
9
+ // passes through only subId. The App Builder cancels through the Mollie
10
+ // dashboard or a custom route until the Foundation contract is extended.
10
11
  //
11
- // **Mollie-Checkout-Flow ist mehrstufig:** Customer anlegen → first-
12
- // payment mit sequenceType="first" (= Mandate-setup) → User bezahlt →
13
- // Mollie-webhook → verify-webhook erstellt die Mollie-Subscription
14
- // idempotent (siehe verify-webhook.ts ensureSubscriptionForMandate).
12
+ // **The Mollie checkout flow has multiple steps:** create customer → first
13
+ // payment with sequenceType="first" (= mandate setup) → user pays →
14
+ // Mollie webhook → verify-webhook creates the Mollie subscription
15
+ // idempotently (see verify-webhook.ts ensureSubscriptionForMandate).
15
16
 
16
17
  import type { SubscriptionProviderPlugin } from "@cosmicdrift/kumiko-bundled-features/billing-foundation";
17
18
  import type { HandlerContext } from "@cosmicdrift/kumiko-framework/engine";
@@ -22,8 +23,8 @@ export type MollieCheckoutOptions = Parameters<
22
23
  NonNullable<SubscriptionProviderPlugin["createCheckoutSession"]>
23
24
  >[1];
24
25
 
25
- /** Mollie hat keinen nativen price-id-Konzept — App-Builder pflegt
26
- * pro virtuellem priceId einen amount/interval/description. */
26
+ /** Mollie has no native price ID concept; the App Builder maintains
27
+ * an amount/interval/description for each virtual priceId. */
27
28
  export type MolliePriceConfig = {
28
29
  /** Mollie-format: 2-decimal string, z.B. `"9.99"`. */
29
30
  readonly amountValue: string;
@@ -67,8 +68,8 @@ export function createMollieCheckoutSession(
67
68
  // any mandate/subscription handling.
68
69
  const sequenceType = options.mode === "payment" ? SequenceType.oneoff : SequenceType.first;
69
70
 
70
- // payments.create ist overloaded (Promise OR void mit callback);
71
- // explicit cast auf Promise<Payment>-overload.
71
+ // payments.create is overloaded (Promise or void with a callback);
72
+ // explicitly cast to the Promise<Payment> overload.
72
73
  const payment = (await (client.payments.create({
73
74
  amount: { currency: priceCfg.amountCurrency, value: priceCfg.amountValue },
74
75
  description: priceCfg.description,