@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.
- package/LICENSE +21 -57
- package/README.md +1 -1
- package/package.json +2 -2
- package/packages/bundled-features/package.json +9 -2
- package/packages/bundled-features/src/agent-tools/changes.json +6 -0
- package/packages/bundled-features/src/agent-tools/tool-catalog.ts +1 -1
- package/packages/bundled-features/src/agent-tools/tool-dispatch.ts +9 -9
- package/packages/bundled-features/src/audit/changes.json +12 -0
- package/packages/bundled-features/src/audit/handlers/audit-events.ts +1 -1
- package/packages/bundled-features/src/audit/screens.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/auth-user-row.ts +10 -10
- package/packages/bundled-features/src/auth-email-password/feature.ts +6 -6
- package/packages/bundled-features/src/auth-email-password/handlers/change-password.write.ts +3 -3
- package/packages/bundled-features/src/auth-email-password/handlers/confirm-token-flow.ts +5 -5
- package/packages/bundled-features/src/auth-email-password/handlers/invite-accept-with-login.write.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/handlers/invite-accept.write.ts +18 -18
- package/packages/bundled-features/src/auth-email-password/handlers/invite-create.write.ts +12 -12
- package/packages/bundled-features/src/auth-email-password/handlers/invite-info.query.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/handlers/invite-signup-complete.write.ts +24 -26
- package/packages/bundled-features/src/auth-email-password/handlers/login.write.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/handlers/self-registration-status.query.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/handlers/signup-confirm.write.ts +34 -37
- package/packages/bundled-features/src/auth-email-password/handlers/signup-request.write.ts +6 -7
- package/packages/bundled-features/src/auth-email-password/handlers/switch-tenant-mfa-gate.write.ts +1 -5
- package/packages/bundled-features/src/auth-email-password/index.ts +5 -5
- package/packages/bundled-features/src/auth-email-password/lockout-store.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/seeding.ts +63 -66
- package/packages/bundled-features/src/auth-email-password/signup-token-store.ts +8 -8
- package/packages/bundled-features/src/auth-email-password/testing.ts +3 -3
- package/packages/bundled-features/src/auth-email-password/web/auth-client.ts +57 -57
- package/packages/bundled-features/src/auth-email-password/web/auth-form-primitives.tsx +14 -14
- package/packages/bundled-features/src/auth-email-password/web/auth-gate.tsx +15 -16
- package/packages/bundled-features/src/auth-email-password/web/client-plugin.ts +11 -12
- package/packages/bundled-features/src/auth-email-password/web/confirm-account-unlock-screen.tsx +1 -1
- package/packages/bundled-features/src/auth-email-password/web/constants.ts +3 -3
- package/packages/bundled-features/src/auth-email-password/web/default-topbar-actions.tsx +14 -14
- package/packages/bundled-features/src/auth-email-password/web/forgot-password-screen.tsx +11 -11
- package/packages/bundled-features/src/auth-email-password/web/index.ts +5 -5
- package/packages/bundled-features/src/auth-email-password/web/invite-accept-screen.tsx +17 -17
- package/packages/bundled-features/src/auth-email-password/web/login-screen.tsx +3 -4
- package/packages/bundled-features/src/auth-email-password/web/reset-password-screen.tsx +16 -17
- package/packages/bundled-features/src/auth-email-password/web/session.tsx +34 -34
- package/packages/bundled-features/src/auth-email-password/web/signup-complete-screen.tsx +3 -3
- package/packages/bundled-features/src/auth-email-password/web/signup-screen.tsx +14 -14
- package/packages/bundled-features/src/auth-email-password/web/tenant-switcher.tsx +26 -27
- package/packages/bundled-features/src/auth-email-password/web/use-shell-user.ts +12 -13
- package/packages/bundled-features/src/auth-email-password/web/user-menu.tsx +17 -18
- package/packages/bundled-features/src/auth-email-password/web/verify-email-screen.tsx +11 -12
- package/packages/bundled-features/src/auth-foundation/boot-checks.ts +4 -4
- package/packages/bundled-features/src/auth-foundation/resolve-anonymous-access.ts +4 -4
- package/packages/bundled-features/src/auth-foundation/types.ts +2 -2
- package/packages/bundled-features/src/auth-mfa/changes.json +6 -0
- package/packages/bundled-features/src/auth-mfa/feature-exports.ts +2 -2
- package/packages/bundled-features/src/auth-mfa/feature.ts +6 -0
- package/packages/bundled-features/src/auth-mfa/handlers/disable.write.ts +3 -3
- package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm-preauth.write.ts +4 -4
- package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm.write.ts +2 -2
- package/packages/bundled-features/src/auth-mfa/handlers/enable-start-preauth.write.ts +1 -1
- package/packages/bundled-features/src/auth-mfa/handlers/reencrypt.job.ts +1 -1
- package/packages/bundled-features/src/auth-mfa/handlers/regenerate-recovery.write.ts +5 -5
- package/packages/bundled-features/src/auth-mfa/handlers/verify.write.ts +1 -1
- package/packages/bundled-features/src/auth-mfa/token-secrets.ts +1 -1
- package/packages/bundled-features/src/auth-mfa/web/client-plugin.ts +2 -2
- package/packages/bundled-features/src/auth-mfa/web/i18n.ts +9 -4
- package/packages/bundled-features/src/auth-mfa/web/index.ts +4 -4
- package/packages/bundled-features/src/auth-mfa/web/mfa-client.ts +17 -16
- package/packages/bundled-features/src/auth-mfa/web/mfa-code-or-recovery-field.tsx +68 -0
- package/packages/bundled-features/src/auth-mfa/web/mfa-disable-dialog.tsx +23 -13
- package/packages/bundled-features/src/auth-mfa/web/mfa-regenerate-recovery-dialog.tsx +23 -13
- package/packages/bundled-features/src/auth-mfa/web/mfa-setup-preauth-screen.tsx +15 -6
- package/packages/bundled-features/src/auth-mfa/web/mfa-verify-screen.tsx +71 -24
- package/packages/bundled-features/src/billing-foundation/aggregate-id.ts +10 -11
- package/packages/bundled-features/src/billing-foundation/changes.json +55 -0
- package/packages/bundled-features/src/billing-foundation/checkout-core.ts +32 -42
- package/packages/bundled-features/src/billing-foundation/consumer-protection/confirmation-mail.ts +8 -2
- package/packages/bundled-features/src/billing-foundation/consumer-protection/consent-gate.ts +2 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/issue-confirmation.ts +14 -3
- package/packages/bundled-features/src/billing-foundation/consumer-protection/mail-notifications.ts +3 -4
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-receipt-limit.ts +12 -6
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-record.ts +35 -19
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-request.ts +12 -8
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-revoke.ts +14 -8
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-texts.ts +5 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/withdrawal-period.ts +8 -10
- package/packages/bundled-features/src/billing-foundation/entities.ts +27 -27
- package/packages/bundled-features/src/billing-foundation/events.ts +23 -21
- package/packages/bundled-features/src/billing-foundation/feature.ts +45 -44
- package/packages/bundled-features/src/billing-foundation/get-subscription-for-tenant.ts +3 -5
- package/packages/bundled-features/src/billing-foundation/handlers/billing-plans.query.ts +71 -6
- package/packages/bundled-features/src/billing-foundation/handlers/create-checkout-session.write.ts +19 -17
- package/packages/bundled-features/src/billing-foundation/handlers/create-portal-session.write.ts +11 -12
- package/packages/bundled-features/src/billing-foundation/handlers/list-subscriptions.query.ts +4 -4
- package/packages/bundled-features/src/billing-foundation/handlers/plan-switch-preview.query.ts +65 -0
- package/packages/bundled-features/src/billing-foundation/handlers/process-event.write.ts +29 -22
- package/packages/bundled-features/src/billing-foundation/handlers/start-plan-checkout.write.ts +44 -8
- package/packages/bundled-features/src/billing-foundation/handlers/switch-plan.write.ts +72 -82
- package/packages/bundled-features/src/billing-foundation/handlers/sync-subscription.write.ts +14 -1
- package/packages/bundled-features/src/billing-foundation/i18n.ts +22 -0
- package/packages/bundled-features/src/billing-foundation/index.ts +2 -0
- package/packages/bundled-features/src/billing-foundation/plan-catalog.ts +62 -27
- package/packages/bundled-features/src/billing-foundation/plan-switch.ts +84 -0
- package/packages/bundled-features/src/billing-foundation/projection.ts +38 -37
- package/packages/bundled-features/src/billing-foundation/subscription-tier-sync.ts +3 -3
- package/packages/bundled-features/src/billing-foundation/tenant-destroy-hook.ts +7 -8
- package/packages/bundled-features/src/billing-foundation/types.ts +144 -66
- package/packages/bundled-features/src/billing-foundation/validate-options.ts +19 -0
- package/packages/bundled-features/src/billing-foundation/web/billing-plans-panel.tsx +123 -51
- package/packages/bundled-features/src/billing-foundation/web/checkout-consent-dialog.tsx +89 -42
- package/packages/bundled-features/src/billing-foundation/web/constants.ts +4 -0
- package/packages/bundled-features/src/billing-foundation/web/plan-price.ts +55 -0
- package/packages/bundled-features/src/billing-foundation/web/plan-switch-confirm-dialog.tsx +224 -0
- package/packages/bundled-features/src/billing-foundation/webhook-handler.ts +1 -1
- package/packages/bundled-features/src/cap-counter/aggregate-id.ts +8 -9
- package/packages/bundled-features/src/cap-counter/cap-reservation.ts +5 -1
- package/packages/bundled-features/src/cap-counter/changes.json +18 -0
- package/packages/bundled-features/src/cap-counter/constants.ts +11 -12
- package/packages/bundled-features/src/cap-counter/enforce-cap.ts +66 -68
- package/packages/bundled-features/src/cap-counter/entity.ts +29 -29
- package/packages/bundled-features/src/cap-counter/feature.ts +34 -35
- package/packages/bundled-features/src/cap-counter/handlers/increment-rolling.write.ts +31 -31
- package/packages/bundled-features/src/cap-counter/handlers/mark-soft-warned.write.ts +4 -5
- package/packages/bundled-features/src/cap-counter/stock-cap-guard.ts +9 -2
- package/packages/bundled-features/src/cap-counter/with-cap-enforcement.ts +3 -5
- package/packages/bundled-features/src/cap-overview/handlers/caps-usage.query.ts +1 -3
- package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +1 -1
- package/packages/bundled-features/src/channel-email/changes.json +6 -0
- package/packages/bundled-features/src/channel-email/feature.ts +1 -1
- package/packages/bundled-features/src/channel-email/smtp-transport.ts +34 -31
- package/packages/bundled-features/src/channel-in-app/handlers/unread-count.query.ts +3 -4
- package/packages/bundled-features/src/compliance-profiles/feature.ts +15 -16
- package/packages/bundled-features/src/compliance-profiles/handlers/for-tenant.query.ts +3 -6
- package/packages/bundled-features/src/compliance-profiles/handlers/list-profiles.query.ts +5 -5
- package/packages/bundled-features/src/compliance-profiles/handlers/needs-profile.query.ts +4 -4
- package/packages/bundled-features/src/compliance-profiles/handlers/set-profile.write.ts +13 -14
- package/packages/bundled-features/src/compliance-profiles/handlers/sub-processors.query.ts +9 -11
- package/packages/bundled-features/src/compliance-profiles/resolve-for-tenant.ts +7 -7
- package/packages/bundled-features/src/compliance-profiles/schema/profile-selection.ts +18 -23
- package/packages/bundled-features/src/compliance-profiles/seeding.ts +14 -15
- package/packages/bundled-features/src/compliance-profiles-ops/handlers/tenants-missing-profile.query.ts +3 -3
- package/packages/bundled-features/src/compliance-profiles-ops/index.ts +2 -2
- package/packages/bundled-features/src/config/changes.json +12 -0
- package/packages/bundled-features/src/config/handlers/cascade.query.ts +4 -2
- package/packages/bundled-features/src/config/handlers/readiness.query.ts +7 -7
- package/packages/bundled-features/src/config/handlers/reencrypt.job.ts +4 -5
- package/packages/bundled-features/src/config/handlers/set.write.ts +4 -4
- package/packages/bundled-features/src/config/handlers/values.query.ts +4 -2
- package/packages/bundled-features/src/config/resolver.ts +4 -4
- package/packages/bundled-features/src/config/table.ts +10 -10
- package/packages/bundled-features/src/config/write-helpers.ts +28 -9
- package/packages/bundled-features/src/crypto-shredding/changes.json +6 -0
- package/packages/bundled-features/src/crypto-shredding/handlers/forget-subject.write.ts +23 -21
- package/packages/bundled-features/src/custom-fields/aggregate-id.ts +16 -17
- package/packages/bundled-features/src/custom-fields/entity.ts +49 -47
- package/packages/bundled-features/src/custom-fields/events.ts +7 -8
- package/packages/bundled-features/src/custom-fields/feature.ts +70 -72
- package/packages/bundled-features/src/custom-fields/handlers/clear-custom-field.write.ts +9 -8
- package/packages/bundled-features/src/custom-fields/handlers/define-tenant-field.write.ts +28 -26
- package/packages/bundled-features/src/custom-fields/handlers/delete-system-field.write.ts +6 -7
- package/packages/bundled-features/src/custom-fields/handlers/delete-tenant-field.write.ts +12 -13
- package/packages/bundled-features/src/custom-fields/handlers/set-custom-field.write.ts +25 -28
- package/packages/bundled-features/src/custom-fields/handlers/update-tenant-field.write.ts +6 -6
- package/packages/bundled-features/src/custom-fields/lib/field-access.ts +2 -2
- package/packages/bundled-features/src/custom-fields/lib/parse-serialized-field.ts +1 -1
- package/packages/bundled-features/src/custom-fields/lib/quota.ts +1 -1
- package/packages/bundled-features/src/custom-fields/lib/value-schema.ts +10 -12
- package/packages/bundled-features/src/custom-fields/run-retention.ts +3 -3
- package/packages/bundled-features/src/custom-fields/schemas.ts +14 -14
- package/packages/bundled-features/src/custom-fields/web/client-plugin.tsx +2 -5
- package/packages/bundled-features/src/custom-fields/web/constants.ts +2 -2
- package/packages/bundled-features/src/custom-fields/web/custom-fields-form-section.tsx +26 -26
- package/packages/bundled-features/src/custom-fields/wire-for-entity.ts +65 -67
- package/packages/bundled-features/src/custom-fields/wire-user-data-rights.ts +3 -3
- package/packages/bundled-features/src/data-retention/_internal/parse-override.ts +2 -3
- package/packages/bundled-features/src/data-retention/feature.ts +11 -18
- package/packages/bundled-features/src/data-retention/handlers/policy-for.query.ts +6 -6
- package/packages/bundled-features/src/data-retention/keep-for.ts +17 -17
- package/packages/bundled-features/src/data-retention/override-schema.ts +13 -15
- package/packages/bundled-features/src/data-retention/presets.ts +18 -23
- package/packages/bundled-features/src/data-retention/resolve-for-tenant.ts +1 -1
- package/packages/bundled-features/src/data-retention/resolve-tenant-preset.ts +17 -16
- package/packages/bundled-features/src/data-retention/resolver.ts +33 -32
- package/packages/bundled-features/src/data-retention/run-retention-cleanup.ts +71 -58
- package/packages/bundled-features/src/data-retention/schema/tenant-retention-override.ts +13 -11
- package/packages/bundled-features/src/delivery/changes.json +30 -0
- package/packages/bundled-features/src/delivery/channel-context.ts +9 -3
- package/packages/bundled-features/src/delivery/db/queries/preferences.ts +2 -2
- package/packages/bundled-features/src/delivery/delivery-service.ts +35 -5
- package/packages/bundled-features/src/delivery/feature.ts +3 -3
- package/packages/bundled-features/src/delivery/handlers/log.query.ts +1 -1
- package/packages/bundled-features/src/delivery/handlers/preferences.query.ts +20 -1
- package/packages/bundled-features/src/delivery/handlers/unsubscribe-page-chrome.query.ts +1 -1
- package/packages/bundled-features/src/delivery/tables.ts +9 -8
- package/packages/bundled-features/src/delivery/unsubscribe-link.ts +3 -1
- package/packages/bundled-features/src/delivery/unsubscribe-page-strings.ts +1 -0
- package/packages/bundled-features/src/delivery/unsubscribe-page.ts +6 -0
- package/packages/bundled-features/src/delivery/unsubscribe.ts +40 -19
- package/packages/bundled-features/src/delivery/upsert-preference.ts +3 -4
- package/packages/bundled-features/src/document-ingest-foundation/entity.ts +5 -5
- package/packages/bundled-features/src/document-ingest-foundation/events.ts +2 -2
- package/packages/bundled-features/src/document-ingest-foundation/feature.ts +2 -2
- package/packages/bundled-features/src/document-ingest-foundation/pages.ts +1 -1
- package/packages/bundled-features/src/document-ingest-foundation/tenant-destroy-hook.ts +4 -4
- package/packages/bundled-features/src/feature-toggles/compose-tier-resolver.ts +1 -1
- package/packages/bundled-features/src/feature-toggles/feature.ts +1 -1
- package/packages/bundled-features/src/feature-toggles/global-feature-state-table.ts +1 -1
- package/packages/bundled-features/src/feature-toggles/handlers/registered.query.ts +5 -5
- package/packages/bundled-features/src/feature-toggles/toggle-runtime.ts +1 -1
- package/packages/bundled-features/src/feature-toggles/toggle-sync-signal.ts +1 -1
- package/packages/bundled-features/src/feature-toggles/web/constants.ts +1 -1
- package/packages/bundled-features/src/file-derivatives/feature.ts +2 -2
- package/packages/bundled-features/src/file-derivatives/handlers/public-variant.query.ts +1 -1
- package/packages/bundled-features/src/file-derivatives/presets.ts +1 -1
- package/packages/bundled-features/src/file-foundation/feature.ts +6 -6
- package/packages/bundled-features/src/file-foundation/index.ts +1 -0
- package/packages/bundled-features/src/file-foundation/read-file-ref-content.ts +7 -1
- package/packages/bundled-features/src/file-provider-inmemory/feature.ts +16 -16
- package/packages/bundled-features/src/file-provider-s3/env-named-feature.ts +0 -2
- package/packages/bundled-features/src/file-provider-s3/feature.ts +16 -16
- package/packages/bundled-features/src/file-provider-s3/lib/s3-provider.ts +6 -6
- package/packages/bundled-features/src/files/README.md +1 -1
- package/packages/bundled-features/src/files/feature.ts +6 -6
- package/packages/bundled-features/src/files-tenant-data/handlers/sweep-orphaned-derivatives.job.ts +5 -5
- package/packages/bundled-features/src/files-tenant-data/hooks.ts +24 -26
- package/packages/bundled-features/src/files-tenant-data/index.ts +1 -1
- package/packages/bundled-features/src/folders/feature.ts +1 -1
- package/packages/bundled-features/src/folders/web/folder-manager.tsx +2 -2
- package/packages/bundled-features/src/folders/web/tree.ts +5 -5
- package/packages/bundled-features/src/form-draft/changes.json +6 -0
- package/packages/bundled-features/src/form-draft/db/queries/cleanup.ts +3 -3
- package/packages/bundled-features/src/form-draft/db/queries/owned-file-refs.ts +1 -1
- package/packages/bundled-features/src/form-draft/decrypt-draft.ts +4 -1
- package/packages/bundled-features/src/form-draft/entity.ts +3 -3
- package/packages/bundled-features/src/form-draft/feature.ts +4 -5
- package/packages/bundled-features/src/form-draft/handlers/discard.write.ts +1 -1
- package/packages/bundled-features/src/form-draft/release-file-refs.ts +6 -6
- package/packages/bundled-features/src/form-draft/schemas.ts +3 -3
- package/packages/bundled-features/src/form-draft/web/constants.ts +0 -2
- package/packages/bundled-features/src/host-routing/README.md +1 -1
- package/packages/bundled-features/src/host-routing/changes.json +6 -0
- package/packages/bundled-features/src/host-routing/dispatch.ts +16 -17
- package/packages/bundled-features/src/host-routing/options.ts +2 -1
- package/packages/bundled-features/src/inbound-mail-foundation/aggregate-id.ts +19 -19
- package/packages/bundled-features/src/inbound-mail-foundation/changes.json +18 -0
- package/packages/bundled-features/src/inbound-mail-foundation/connect-routes.ts +4 -3
- package/packages/bundled-features/src/inbound-mail-foundation/constants.ts +30 -33
- package/packages/bundled-features/src/inbound-mail-foundation/entities.ts +47 -48
- package/packages/bundled-features/src/inbound-mail-foundation/events.ts +54 -50
- package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +39 -39
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/account-state.ts +8 -8
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/connect-account.write.ts +25 -26
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/disconnect-account.write.ts +7 -7
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/ingest-message.write.ts +50 -51
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-accounts.query.ts +8 -8
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-messages.query.ts +10 -10
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/scope-visibility.ts +3 -4
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/update-account.write.ts +27 -15
- package/packages/bundled-features/src/inbound-mail-foundation/i18n.ts +0 -1
- package/packages/bundled-features/src/inbound-mail-foundation/oauth-state.ts +16 -15
- package/packages/bundled-features/src/inbound-mail-foundation/projection.ts +31 -29
- package/packages/bundled-features/src/inbound-mail-foundation/provider-factory.ts +9 -9
- package/packages/bundled-features/src/inbound-mail-foundation/retention-sweep.ts +45 -41
- package/packages/bundled-features/src/inbound-mail-foundation/screens.ts +0 -3
- package/packages/bundled-features/src/inbound-mail-foundation/tenant-destroy-hook.ts +14 -16
- package/packages/bundled-features/src/inbound-mail-foundation/types.ts +70 -70
- package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +101 -84
- package/packages/bundled-features/src/inbound-provider-imap/credential-document.ts +13 -13
- package/packages/bundled-features/src/inbound-provider-imap/feature.ts +42 -40
- package/packages/bundled-features/src/inbound-provider-imap/imap-client.ts +20 -19
- package/packages/bundled-features/src/inbound-provider-inmemory/feature.ts +21 -21
- package/packages/bundled-features/src/jobs/changes.json +13 -0
- package/packages/bundled-features/src/jobs/db/queries/retention.ts +2 -2
- package/packages/bundled-features/src/jobs/db/queries/stale-run-sweep.ts +3 -3
- package/packages/bundled-features/src/jobs/events.ts +1 -1
- package/packages/bundled-features/src/jobs/feature.ts +20 -11
- package/packages/bundled-features/src/jobs/handlers/detail.query.ts +4 -4
- package/packages/bundled-features/src/jobs/handlers/list.query.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/projection-rebuild.job.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/reindex-entity.job.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/retry.write.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/tenant-failures.query.ts +45 -40
- package/packages/bundled-features/src/jobs/handlers/tenant-runs.query.ts +63 -59
- package/packages/bundled-features/src/jobs/job-instant.ts +1 -1
- package/packages/bundled-features/src/jobs/job-run-logger.ts +19 -19
- package/packages/bundled-features/src/jobs/job-run-table.ts +3 -3
- package/packages/bundled-features/src/jobs/screens.ts +1 -1
- package/packages/bundled-features/src/jobs/tenant-job-failure-table.ts +1 -1
- package/packages/bundled-features/src/jobs/tenant-job-run-table.ts +1 -1
- package/packages/bundled-features/src/ledger/entity.ts +5 -5
- package/packages/bundled-features/src/ledger/feature.ts +3 -3
- package/packages/bundled-features/src/ledger/handlers/confirm-schedule-period.write.ts +3 -3
- package/packages/bundled-features/src/ledger/recurring.ts +12 -12
- package/packages/bundled-features/src/ledger/schemas.ts +1 -1
- package/packages/bundled-features/src/ledger/web/constants.ts +2 -2
- package/packages/bundled-features/src/ledger/web/index.ts +7 -7
- package/packages/bundled-features/src/legal-pages/README.md +1 -1
- package/packages/bundled-features/src/legal-pages/feature.ts +40 -41
- package/packages/bundled-features/src/legal-pages/markdown.ts +3 -3
- package/packages/bundled-features/src/legal-pages/web/client-plugin.ts +23 -24
- package/packages/bundled-features/src/legal-pages/web/index.ts +0 -2
- package/packages/bundled-features/src/mail-foundation/changes.json +6 -0
- package/packages/bundled-features/src/mail-foundation/feature.ts +31 -30
- package/packages/bundled-features/src/mail-transport-inmemory/feature.ts +27 -28
- package/packages/bundled-features/src/mail-transport-smtp/feature.ts +20 -20
- package/packages/bundled-features/src/managed-pages/branding.ts +6 -6
- package/packages/bundled-features/src/managed-pages/feature.ts +62 -62
- package/packages/bundled-features/src/managed-pages/handlers/by-slug.query.ts +5 -6
- package/packages/bundled-features/src/managed-pages/handlers/by-tenant-published.query.ts +8 -8
- package/packages/bundled-features/src/managed-pages/handlers/set.write.ts +5 -7
- package/packages/bundled-features/src/managed-pages/screens/page-screens.ts +11 -11
- package/packages/bundled-features/src/managed-pages/seeding.ts +8 -8
- package/packages/bundled-features/src/managed-pages/table.ts +16 -15
- package/packages/bundled-features/src/managed-pages/web/client-plugin.tsx +6 -6
- package/packages/bundled-features/src/managed-pages/web/i18n.ts +1 -1
- package/packages/bundled-features/src/notes-history/entity.ts +4 -4
- package/packages/bundled-features/src/notes-history/feature.ts +2 -2
- package/packages/bundled-features/src/notes-history-user-data/hooks.ts +1 -1
- package/packages/bundled-features/src/page-render/layout.ts +9 -9
- package/packages/bundled-features/src/page-render/markdown.ts +11 -11
- package/packages/bundled-features/src/page-render/security-headers.ts +7 -6
- package/packages/bundled-features/src/personal-access-tokens/feature.ts +9 -6
- package/packages/bundled-features/src/personal-access-tokens/roles.ts +2 -2
- package/packages/bundled-features/src/readiness/handlers/status.query.ts +3 -3
- package/packages/bundled-features/src/renderer-foundation/api.ts +12 -13
- package/packages/bundled-features/src/renderer-foundation/constants.ts +2 -2
- package/packages/bundled-features/src/renderer-foundation/feature.ts +7 -7
- package/packages/bundled-features/src/renderer-foundation/types.ts +11 -12
- package/packages/bundled-features/src/renderer-pdf/changes.json +6 -0
- package/packages/bundled-features/src/renderer-pdf/render-table-pdf.ts +27 -10
- package/packages/bundled-features/src/secrets/feature.ts +9 -9
- package/packages/bundled-features/src/secrets/web/constants.ts +2 -2
- package/packages/bundled-features/src/seo/feature.ts +3 -3
- package/packages/bundled-features/src/sessions/constants.ts +1 -1
- package/packages/bundled-features/src/sessions/feature.ts +16 -11
- package/packages/bundled-features/src/sessions/handlers/revoke-all-for-user.write.ts +2 -2
- package/packages/bundled-features/src/sessions/handlers/revoke-all-others.write.ts +2 -2
- package/packages/bundled-features/src/sessions/handlers/revoke.write.ts +1 -1
- package/packages/bundled-features/src/sessions/schema/user-session.ts +4 -4
- package/packages/bundled-features/src/sessions/screens.ts +2 -2
- package/packages/bundled-features/src/sessions/session-callbacks.ts +2 -2
- package/packages/bundled-features/src/sessions/session-revoked-event.ts +2 -2
- package/packages/bundled-features/src/shared/assert-no-where-rule-in-ownership-write.ts +1 -1
- package/packages/bundled-features/src/shared/decrypt-stored-pii.ts +11 -1
- package/packages/bundled-features/src/shared/encrypt-for-direct-write.ts +1 -1
- package/packages/bundled-features/src/shared/index.ts +1 -1
- package/packages/bundled-features/src/shared/mail-template-body.ts +10 -3
- package/packages/bundled-features/src/shared/map-with-concurrency.ts +5 -4
- package/packages/bundled-features/src/shared/parent-visibility.ts +2 -2
- package/packages/bundled-features/src/shared/password-hashing.ts +1 -1
- package/packages/bundled-features/src/shared/signup-handover.ts +1 -2
- package/packages/bundled-features/src/shared/single-use-token-store.ts +1 -1
- package/packages/bundled-features/src/step-dispatcher/changes.json +6 -0
- package/packages/bundled-features/src/step-dispatcher/feature.ts +1 -0
- package/packages/bundled-features/src/subscription-dodo/changes.json +14 -0
- package/packages/bundled-features/src/subscription-dodo/client.ts +45 -0
- package/packages/bundled-features/src/subscription-dodo/constants.ts +24 -0
- package/packages/bundled-features/src/subscription-dodo/feature.ts +207 -0
- package/packages/bundled-features/src/subscription-dodo/index.ts +16 -0
- package/packages/bundled-features/src/subscription-dodo/plugin-methods.ts +345 -0
- package/packages/bundled-features/src/subscription-dodo/runtime.ts +126 -0
- package/packages/bundled-features/src/subscription-dodo/verify-webhook.ts +262 -0
- package/packages/bundled-features/src/subscription-mollie/constants.ts +15 -17
- package/packages/bundled-features/src/subscription-mollie/feature.ts +41 -42
- package/packages/bundled-features/src/subscription-mollie/index.ts +3 -3
- package/packages/bundled-features/src/subscription-mollie/plugin-methods.ts +17 -16
- package/packages/bundled-features/src/subscription-mollie/verify-webhook.ts +34 -34
- package/packages/bundled-features/src/subscription-stripe/changes.json +12 -0
- package/packages/bundled-features/src/subscription-stripe/constants.ts +4 -6
- package/packages/bundled-features/src/subscription-stripe/feature.ts +45 -43
- package/packages/bundled-features/src/subscription-stripe/index.ts +6 -6
- package/packages/bundled-features/src/subscription-stripe/plugin-methods.ts +22 -27
- package/packages/bundled-features/src/subscription-stripe/runtime.ts +9 -8
- package/packages/bundled-features/src/subscription-stripe/verify-webhook.ts +62 -64
- package/packages/bundled-features/src/tags/feature.ts +3 -3
- package/packages/bundled-features/src/tags/screens.ts +1 -1
- package/packages/bundled-features/src/template-resolver/api.ts +41 -14
- package/packages/bundled-features/src/template-resolver/changes.json +48 -0
- package/packages/bundled-features/src/template-resolver/compile-document-body.ts +1 -0
- package/packages/bundled-features/src/template-resolver/feature.ts +2 -2
- package/packages/bundled-features/src/template-resolver/handlers/bundle-import.ts +3 -2
- package/packages/bundled-features/src/template-resolver/handlers/copy-locale.write.ts +27 -5
- package/packages/bundled-features/src/template-resolver/handlers/diff-to-system.query.ts +3 -2
- package/packages/bundled-features/src/template-resolver/handlers/document-base.ts +3 -2
- package/packages/bundled-features/src/template-resolver/handlers/find-by-id.query.ts +8 -7
- package/packages/bundled-features/src/template-resolver/handlers/list.query.ts +19 -20
- package/packages/bundled-features/src/template-resolver/handlers/overview.query.ts +15 -5
- package/packages/bundled-features/src/template-resolver/handlers/shared.ts +2 -2
- package/packages/bundled-features/src/template-resolver/handlers/template-write.ts +3 -3
- package/packages/bundled-features/src/template-resolver/handlers/tenant-override-counts.query.ts +9 -5
- package/packages/bundled-features/src/template-resolver/handlers/tenant-override-selection.ts +8 -6
- package/packages/bundled-features/src/template-resolver/handlers/tenant-overrides.query.ts +44 -5
- package/packages/bundled-features/src/template-resolver/handlers/upsert-system.write.ts +3 -4
- package/packages/bundled-features/src/template-resolver/handlers/upsert-tenant.write.ts +4 -5
- package/packages/bundled-features/src/template-resolver/handlers/usage.query.ts +37 -26
- package/packages/bundled-features/src/template-resolver/handlers/validate.query.ts +7 -2
- package/packages/bundled-features/src/template-resolver/seeding.ts +36 -18
- package/packages/bundled-features/src/template-resolver/store-template-resource.ts +22 -4
- package/packages/bundled-features/src/template-resolver/table.ts +13 -14
- package/packages/bundled-features/src/template-resolver/template-delivery-policy.ts +0 -11
- package/packages/bundled-features/src/template-resolver/template-meta.ts +12 -4
- package/packages/bundled-features/src/template-resolver/template-preview.ts +11 -3
- package/packages/bundled-features/src/template-resolver/web/client-plugin.tsx +2 -2
- package/packages/bundled-features/src/template-resolver/web/constants.ts +7 -5
- package/packages/bundled-features/src/template-resolver/web/index.ts +7 -0
- package/packages/bundled-features/src/template-resolver/web/mail-layout-constants.ts +8 -0
- package/packages/bundled-features/src/tenant/changes.json +6 -0
- package/packages/bundled-features/src/tenant/feature.ts +7 -7
- package/packages/bundled-features/src/tenant/handlers/member-directory.query.ts +10 -4
- package/packages/bundled-features/src/tenant/handlers/members.query.ts +1 -1
- package/packages/bundled-features/src/tenant/handlers/memberships.query.ts +1 -1
- package/packages/bundled-features/src/tenant/handlers/team-list.query.ts +1 -1
- package/packages/bundled-features/src/tenant/handlers/tenant-directory.query.ts +8 -5
- package/packages/bundled-features/src/tenant/invitation-table.ts +37 -40
- package/packages/bundled-features/src/tenant/membership-table.ts +3 -3
- package/packages/bundled-features/src/tenant/schema/tenant.ts +7 -9
- package/packages/bundled-features/src/tenant/screens.ts +1 -1
- package/packages/bundled-features/src/tenant/seeding.ts +19 -18
- package/packages/bundled-features/src/tenant/testing.ts +5 -6
- package/packages/bundled-features/src/tenant/web/constants.ts +2 -2
- package/packages/bundled-features/src/tenant-handover/events.ts +5 -7
- package/packages/bundled-features/src/tenant-handover/feature.ts +1 -1
- package/packages/bundled-features/src/tenant-handover/grant.ts +1 -1
- package/packages/bundled-features/src/tenant-handover/handlers/claim.write.ts +1 -1
- package/packages/bundled-features/src/tenant-handover/move-entity-graph.ts +8 -9
- package/packages/bundled-features/src/tenant-handover/signup-handover-provider.ts +1 -2
- package/packages/bundled-features/src/tenant-handover/transfer-graph.ts +4 -5
- package/packages/bundled-features/src/tenant-lifecycle/boot-checks.ts +1 -1
- package/packages/bundled-features/src/tenant-lifecycle/changes.json +6 -0
- package/packages/bundled-features/src/tenant-lifecycle/constants.ts +5 -0
- package/packages/bundled-features/src/tenant-lifecycle/feature.ts +1 -1
- package/packages/bundled-features/src/tenant-lifecycle/run-tenant-destroy.ts +7 -3
- package/packages/bundled-features/src/tenant-lifecycle/stages.ts +1 -1
- package/packages/bundled-features/src/tenant-settings/constants.ts +1 -1
- package/packages/bundled-features/src/tenant-settings/tenant-defaults.ts +12 -5
- package/packages/bundled-features/src/tier-engine/aggregate-id.ts +15 -16
- package/packages/bundled-features/src/tier-engine/changes.json +6 -0
- package/packages/bundled-features/src/tier-engine/compose-app.ts +14 -14
- package/packages/bundled-features/src/tier-engine/entity.ts +18 -19
- package/packages/bundled-features/src/tier-engine/feature.ts +88 -87
- package/packages/bundled-features/src/tier-engine/handlers/active-tier.query.ts +6 -7
- package/packages/bundled-features/src/tier-engine/handlers/get-tenant-tier.query.ts +4 -4
- package/packages/bundled-features/src/tier-engine/handlers/set-tenant-tier.write.ts +12 -9
- package/packages/bundled-features/src/tier-engine/tier-resolver.ts +2 -2
- package/packages/bundled-features/src/tier-engine/trial.ts +13 -13
- package/packages/bundled-features/src/tier-engine/web/constants.ts +3 -3
- package/packages/bundled-features/src/tier-engine/web/index.ts +4 -4
- package/packages/bundled-features/src/user/db/queries/stream-tenant-backfill.ts +8 -8
- package/packages/bundled-features/src/user/handlers/create.write.ts +4 -4
- package/packages/bundled-features/src/user/schema/user.ts +45 -44
- package/packages/bundled-features/src/user/seeding.ts +40 -40
- package/packages/bundled-features/src/user/testing.ts +3 -3
- package/packages/bundled-features/src/user-data-rights/audit-download.ts +27 -28
- package/packages/bundled-features/src/user-data-rights/boot-checks.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/deletion-token.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/feature.ts +112 -113
- package/packages/bundled-features/src/user-data-rights/handlers/cancel-deletion.write.ts +9 -9
- package/packages/bundled-features/src/user-data-rights/handlers/confirm-deletion-by-token.write.ts +8 -8
- package/packages/bundled-features/src/user-data-rights/handlers/download-by-job.query.ts +29 -30
- package/packages/bundled-features/src/user-data-rights/handlers/download-by-token.query.ts +40 -42
- package/packages/bundled-features/src/user-data-rights/handlers/export-status.query.ts +8 -9
- package/packages/bundled-features/src/user-data-rights/handlers/lift-restriction.write.ts +7 -8
- package/packages/bundled-features/src/user-data-rights/handlers/list-download-attempts.query.ts +2 -2
- package/packages/bundled-features/src/user-data-rights/handlers/my-audit-log.query.ts +4 -4
- package/packages/bundled-features/src/user-data-rights/handlers/request-deletion-by-email.write.ts +30 -29
- package/packages/bundled-features/src/user-data-rights/handlers/request-deletion.write.ts +15 -18
- package/packages/bundled-features/src/user-data-rights/handlers/request-export.write.ts +42 -41
- package/packages/bundled-features/src/user-data-rights/handlers/restrict-account.write.ts +22 -19
- package/packages/bundled-features/src/user-data-rights/handlers/run-forget-cleanup.write.ts +8 -8
- package/packages/bundled-features/src/user-data-rights/index.ts +8 -10
- package/packages/bundled-features/src/user-data-rights/lib/default-mailers.ts +3 -3
- package/packages/bundled-features/src/user-data-rights/lib/update-user-lifecycle.ts +24 -27
- package/packages/bundled-features/src/user-data-rights/run-export-jobs.ts +169 -280
- package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +87 -108
- package/packages/bundled-features/src/user-data-rights/run-user-export.ts +67 -69
- package/packages/bundled-features/src/user-data-rights/schema/download-attempt.ts +11 -11
- package/packages/bundled-features/src/user-data-rights/schema/download-token.ts +37 -41
- package/packages/bundled-features/src/user-data-rights/schema/export-job.ts +65 -67
- package/packages/bundled-features/src/user-data-rights/token-helpers.ts +21 -25
- package/packages/bundled-features/src/user-data-rights/web/client-plugin.tsx +6 -6
- package/packages/bundled-features/src/user-data-rights/web/confirm-deletion-screen.tsx +6 -5
- package/packages/bundled-features/src/user-data-rights/web/constants.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/web/index.ts +5 -5
- package/packages/bundled-features/src/user-data-rights/web/privacy-center-screen.tsx +14 -13
- package/packages/bundled-features/src/user-data-rights/web/public-deletion-gate.tsx +13 -12
- package/packages/bundled-features/src/user-data-rights/web/request-deletion-screen.tsx +6 -6
- package/packages/bundled-features/src/user-data-rights/zip-path.ts +41 -40
- package/packages/bundled-features/src/user-data-rights-defaults/feature.ts +15 -15
- package/packages/bundled-features/src/user-data-rights-defaults/hooks/delivery-attempt.userdata-hook.ts +3 -5
- package/packages/bundled-features/src/user-data-rights-defaults/hooks/file-ref.userdata-hook.ts +45 -51
- package/packages/bundled-features/src/user-data-rights-defaults/hooks/job-run.userdata-hook.ts +2 -2
- package/packages/bundled-features/src/user-data-rights-defaults/hooks/notification-preference.userdata-hook.ts +1 -1
- package/packages/bundled-features/src/user-data-rights-defaults/hooks/user-session.userdata-hook.ts +3 -3
- package/packages/bundled-features/src/user-data-rights-defaults/hooks/user.userdata-hook.ts +32 -31
- package/packages/bundled-features/src/user-profile/handlers/change-email.write.ts +13 -13
- package/packages/bundled-features/src/user-profile/index.ts +3 -3
- package/packages/bundled-features/src/user-profile/web/client-plugin.ts +1 -1
- package/packages/bundled-features/src/user-profile/web/constants.ts +1 -1
- package/packages/bundled-features/src/user-profile/web/profile-screen.tsx +1 -1
- package/packages/bundled-features/src/waitlist/changes.json +18 -0
- package/packages/bundled-features/src/waitlist/handlers/export-purge.write.ts +2 -1
- package/packages/bundled-features/src/waitlist/handlers/submit.write.ts +5 -5
- package/packages/bundled-features/src/waitlist/import.ts +5 -0
- package/packages/bundled-features/src/waitlist/legacy-migrate.ts +22 -3
- package/packages/bundled-features/src/waitlist/link-on-signup.ts +20 -10
- package/packages/bundled-features/src/waitlist/options.ts +3 -0
- package/packages/bundled-features/src/workflow-runner/aggregate-id.ts +1 -1
- package/packages/bundled-features/src/workflow-runner/event-subscriber.ts +4 -5
- package/packages/bundled-features/src/workflow-runner/event-trigger.ts +4 -15
- package/packages/bundled-features/src/workflow-runner/feature.ts +2 -2
- package/packages/bundled-features/src/workflow-runner/handlers/resume-run.write.ts +4 -4
- package/packages/bundled-features/src/workflow-runner/pending-projection.ts +6 -7
- package/packages/bundled-features/src/workflow-runner/runner.ts +6 -6
- package/packages/bundled-features/src/workflow-runner/tables.ts +6 -6
- package/packages/bundled-features/src/workflow-runner/workflow-registry.ts +1 -1
- package/samples/apps/styleguide/src/features/widgets/i18n.ts +11 -0
- package/samples/apps/styleguide/src/features/widgets/web/Widgets.tsx +24 -0
- package/samples/apps/use-all-bundled/e2e-billing-gallery/gallery-constants.ts +5 -0
- package/samples/apps/use-all-bundled/e2e-billing-gallery/gallery-features.ts +90 -15
- package/samples/apps/use-all-bundled/e2e-billing-gallery/server.ts +16 -6
- package/samples/apps/use-all-bundled/feature-manifest.json +120 -3
- package/samples/apps/use-all-bundled/src/run-config.ts +9 -3
- package/samples/recipes/auth-mfa/README.md +5 -0
- package/samples/recipes/auth-mfa/package.json +5 -2
- package/samples/recipes/auth-mfa/src/web/confirmation-code-step.tsx +49 -0
- package/samples/recipes/auth-mfa/tsconfig.json +8 -0
- package/samples/recipes/env-composition/README.md +3 -1
- package/samples/recipes/env-composition/src/env.ts +2 -0
- package/samples/recipes/legal-pages/README.md +1 -1
- package/samples/recipes/rate-limiting/README.md +18 -0
- package/samples/recipes/rate-limiting/src/feature.ts +12 -0
- 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
|
-
//
|
|
5
|
-
//
|
|
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
|
|
10
|
+
// Mollie webhook pattern (unlike Stripe)
|
|
11
11
|
// =============================================================================
|
|
12
12
|
//
|
|
13
|
-
// Mollie
|
|
14
|
-
//
|
|
15
|
-
// - `id=tr_xxx` → payment
|
|
16
|
-
// - `id=sub_xxx` → subscription
|
|
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
|
-
// **
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
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
|
|
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
|
-
// -
|
|
31
|
+
// - everything else → null (foundation 200 ignored)
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
// kumiko-feature-version: 1
|
|
2
2
|
//
|
|
3
|
-
// subscription-mollie — Mollie
|
|
4
|
-
//
|
|
3
|
+
// subscription-mollie — Mollie plugin for subscription-foundation
|
|
4
|
+
// plugin API (EU compliance for the DACH mid-market).
|
|
5
5
|
//
|
|
6
|
-
// **Factory
|
|
7
|
-
// mount
|
|
8
|
-
//
|
|
9
|
-
// 4.5.0
|
|
10
|
-
//
|
|
11
|
-
//
|
|
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
|
-
// **
|
|
13
|
+
// **Scope:**
|
|
14
14
|
// - verifyAndParseWebhook ✓ (lazy-fetch payment + subscription via
|
|
15
|
-
// Mollie
|
|
16
|
-
// - createCheckoutSession ✓ (Mollie's
|
|
17
|
-
//
|
|
18
|
-
// - createPortalSession ✗ (Mollie
|
|
19
|
-
// - cancelSubscription ✗ (Mollie
|
|
20
|
-
// subId;
|
|
21
|
-
// via Mollie
|
|
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
|
-
// **
|
|
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
|
|
66
|
-
*
|
|
65
|
+
/** Mollie API key (`test_...` or `live_...`). App-wide, mounted from
|
|
66
|
+
* process.env or system configuration. */
|
|
67
67
|
readonly apiKey: string;
|
|
68
|
-
/** Foundation
|
|
69
|
-
*
|
|
70
|
-
*
|
|
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
|
|
75
|
-
* metadata (= `metadata.priceId`
|
|
76
|
-
* createCheckoutSession
|
|
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
|
|
79
|
-
*
|
|
80
|
-
*
|
|
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
|
|
83
|
-
*
|
|
84
|
-
* factory
|
|
85
|
-
*
|
|
86
|
-
* factory
|
|
87
|
-
*
|
|
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
|
|
106
|
-
//
|
|
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
|
|
122
|
-
//
|
|
123
|
-
//
|
|
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
|
|
164
|
-
// plugin-methods.ts
|
|
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** (
|
|
4
|
-
// - verifyAndParseMollieWebhook (
|
|
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
|
|
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
|
|
2
|
-
// createCheckoutSession
|
|
3
|
-
//
|
|
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
|
|
6
|
-
//
|
|
7
|
-
// - **Cancel:** Mollie
|
|
8
|
-
//
|
|
9
|
-
//
|
|
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
|
|
12
|
-
// payment
|
|
13
|
-
// Mollie
|
|
14
|
-
//
|
|
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
|
|
26
|
-
*
|
|
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
|
|
71
|
-
//
|
|
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,
|