@cosmicdrift/kumiko-bundled-features 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/dist/agent-tools/tool-catalog.js +1 -1
- package/dist/agent-tools/tool-dispatch.d.ts +7 -7
- package/dist/agent-tools/tool-dispatch.js +9 -9
- package/dist/audit/handlers/audit-events.js +1 -1
- package/dist/audit/screens.js +1 -1
- package/dist/auth-email-password/feature.js +1 -1
- package/dist/auth-email-password/handlers/change-password.write.js +3 -3
- package/dist/auth-email-password/handlers/confirm-token-flow.js +5 -5
- package/dist/auth-email-password/handlers/invite-accept-with-login.write.js +1 -1
- package/dist/auth-email-password/handlers/invite-accept.write.js +18 -18
- package/dist/auth-email-password/handlers/invite-create.write.d.ts +2 -2
- package/dist/auth-email-password/handlers/invite-create.write.js +10 -10
- package/dist/auth-email-password/handlers/invite-info.query.js +1 -1
- package/dist/auth-email-password/handlers/invite-signup-complete.write.js +24 -26
- package/dist/auth-email-password/handlers/login.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/login.write.js +1 -1
- package/dist/auth-email-password/handlers/self-registration-status.query.js +1 -1
- package/dist/auth-email-password/handlers/signup-confirm.write.js +34 -37
- package/dist/auth-email-password/handlers/signup-request.write.js +6 -7
- package/dist/auth-email-password/handlers/switch-tenant-mfa-gate.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/switch-tenant-mfa-gate.write.js +1 -4
- package/dist/auth-email-password/index.js +5 -5
- package/dist/auth-email-password/lockout-store.js +1 -1
- package/dist/auth-email-password/seeding.d.ts +42 -45
- package/dist/auth-email-password/seeding.js +51 -53
- package/dist/auth-email-password/signup-token-store.js +8 -8
- package/dist/auth-email-password/testing.js +3 -3
- package/dist/auth-email-password/web/auth-client.d.ts +2 -2
- package/dist/auth-email-password/web/auth-client.js +36 -37
- package/dist/auth-email-password/web/auth-form-primitives.js +10 -10
- package/dist/auth-email-password/web/auth-gate.js +15 -16
- package/dist/auth-email-password/web/client-plugin.d.ts +7 -7
- package/dist/auth-email-password/web/client-plugin.js +4 -5
- package/dist/auth-email-password/web/confirm-account-unlock-screen.js +1 -1
- package/dist/auth-email-password/web/constants.js +3 -3
- package/dist/auth-email-password/web/default-topbar-actions.d.ts +8 -8
- package/dist/auth-email-password/web/default-topbar-actions.js +6 -6
- package/dist/auth-email-password/web/forgot-password-screen.d.ts +2 -2
- package/dist/auth-email-password/web/forgot-password-screen.js +9 -9
- package/dist/auth-email-password/web/index.js +5 -5
- package/dist/auth-email-password/web/invite-accept-screen.d.ts +1 -1
- package/dist/auth-email-password/web/invite-accept-screen.js +16 -16
- package/dist/auth-email-password/web/login-screen.d.ts +1 -1
- package/dist/auth-email-password/web/login-screen.js +2 -3
- package/dist/auth-email-password/web/reset-password-screen.d.ts +4 -4
- package/dist/auth-email-password/web/reset-password-screen.js +12 -13
- package/dist/auth-email-password/web/session.d.ts +10 -9
- package/dist/auth-email-password/web/session.js +28 -29
- package/dist/auth-email-password/web/signup-complete-screen.js +3 -3
- package/dist/auth-email-password/web/signup-screen.d.ts +1 -1
- package/dist/auth-email-password/web/signup-screen.js +13 -13
- package/dist/auth-email-password/web/tenant-switcher.d.ts +4 -4
- package/dist/auth-email-password/web/tenant-switcher.js +21 -22
- package/dist/auth-email-password/web/use-shell-user.js +12 -13
- package/dist/auth-email-password/web/user-menu.d.ts +4 -4
- package/dist/auth-email-password/web/user-menu.js +12 -13
- package/dist/auth-email-password/web/verify-email-screen.d.ts +2 -2
- package/dist/auth-email-password/web/verify-email-screen.js +9 -10
- package/dist/auth-foundation/boot-checks.js +4 -4
- package/dist/auth-foundation/resolve-anonymous-access.d.ts +1 -1
- package/dist/auth-foundation/resolve-anonymous-access.js +3 -3
- package/dist/auth-foundation/types.js +2 -2
- package/dist/auth-mfa/feature-exports.d.ts +2 -2
- package/dist/auth-mfa/feature.js +8 -0
- package/dist/auth-mfa/handlers/disable.write.js +3 -3
- package/dist/auth-mfa/handlers/enable-confirm-preauth.write.js +4 -4
- package/dist/auth-mfa/handlers/enable-confirm.write.js +2 -2
- package/dist/auth-mfa/handlers/enable-start-preauth.write.js +1 -1
- package/dist/auth-mfa/handlers/reencrypt.job.js +1 -1
- package/dist/auth-mfa/handlers/regenerate-recovery.write.js +5 -5
- package/dist/auth-mfa/handlers/verify.write.js +1 -1
- package/dist/auth-mfa/token-secrets.js +1 -1
- package/dist/auth-mfa/web/client-plugin.d.ts +1 -1
- package/dist/auth-mfa/web/client-plugin.js +1 -1
- package/dist/auth-mfa/web/i18n.js +8 -4
- package/dist/auth-mfa/web/index.js +4 -4
- package/dist/auth-mfa/web/mfa-client.js +17 -16
- package/dist/auth-mfa/web/mfa-code-or-recovery-field.d.ts +11 -0
- package/dist/auth-mfa/web/mfa-code-or-recovery-field.js +12 -0
- package/dist/auth-mfa/web/mfa-disable-dialog.js +14 -3
- package/dist/auth-mfa/web/mfa-regenerate-recovery-dialog.js +14 -3
- package/dist/auth-mfa/web/mfa-setup-preauth-screen.js +10 -5
- package/dist/auth-mfa/web/mfa-verify-screen.js +32 -11
- package/dist/billing-foundation/aggregate-id.d.ts +5 -5
- package/dist/billing-foundation/aggregate-id.js +10 -11
- package/dist/billing-foundation/checkout-core.d.ts +9 -14
- package/dist/billing-foundation/checkout-core.js +24 -39
- package/dist/billing-foundation/consumer-protection/confirmation-mail.js +8 -2
- package/dist/billing-foundation/consumer-protection/consent-gate.d.ts +1 -0
- package/dist/billing-foundation/consumer-protection/consent-gate.js +1 -0
- package/dist/billing-foundation/consumer-protection/issue-confirmation.js +9 -3
- package/dist/billing-foundation/consumer-protection/mail-notifications.js +3 -1
- package/dist/billing-foundation/consumer-protection/termination-receipt-limit.d.ts +4 -2
- package/dist/billing-foundation/consumer-protection/termination-receipt-limit.js +6 -5
- package/dist/billing-foundation/consumer-protection/termination-record.d.ts +5 -1
- package/dist/billing-foundation/consumer-protection/termination-record.js +27 -17
- package/dist/billing-foundation/consumer-protection/termination-request.js +12 -7
- package/dist/billing-foundation/consumer-protection/termination-revoke.js +12 -7
- package/dist/billing-foundation/consumer-protection/termination-texts.d.ts +1 -1
- package/dist/billing-foundation/consumer-protection/termination-texts.js +3 -0
- package/dist/billing-foundation/consumer-protection/withdrawal-period.d.ts +5 -2
- package/dist/billing-foundation/consumer-protection/withdrawal-period.js +8 -9
- package/dist/billing-foundation/entities.js +27 -27
- package/dist/billing-foundation/events.d.ts +1 -0
- package/dist/billing-foundation/events.js +19 -17
- package/dist/billing-foundation/feature.js +45 -44
- package/dist/billing-foundation/get-subscription-for-tenant.d.ts +3 -3
- package/dist/billing-foundation/get-subscription-for-tenant.js +3 -5
- package/dist/billing-foundation/handlers/billing-plans.query.js +35 -5
- package/dist/billing-foundation/handlers/create-checkout-session.write.js +19 -17
- package/dist/billing-foundation/handlers/create-portal-session.write.js +11 -12
- package/dist/billing-foundation/handlers/list-subscriptions.query.js +4 -4
- package/dist/billing-foundation/handlers/plan-switch-preview.query.d.ts +13 -0
- package/dist/billing-foundation/handlers/plan-switch-preview.query.js +48 -0
- package/dist/billing-foundation/handlers/process-event.write.d.ts +6 -0
- package/dist/billing-foundation/handlers/process-event.write.js +28 -22
- package/dist/billing-foundation/handlers/start-plan-checkout.write.js +32 -5
- package/dist/billing-foundation/handlers/switch-plan.write.d.ts +2 -2
- package/dist/billing-foundation/handlers/switch-plan.write.js +56 -64
- package/dist/billing-foundation/handlers/sync-subscription.write.js +12 -1
- package/dist/billing-foundation/i18n.js +22 -0
- package/dist/billing-foundation/index.d.ts +1 -1
- package/dist/billing-foundation/plan-catalog.d.ts +21 -5
- package/dist/billing-foundation/plan-catalog.js +25 -16
- package/dist/billing-foundation/plan-switch.d.ts +12 -0
- package/dist/billing-foundation/plan-switch.js +60 -0
- package/dist/billing-foundation/projection.d.ts +15 -11
- package/dist/billing-foundation/projection.js +38 -37
- package/dist/billing-foundation/subscription-tier-sync.js +3 -3
- package/dist/billing-foundation/tenant-destroy-hook.d.ts +2 -2
- package/dist/billing-foundation/tenant-destroy-hook.js +7 -7
- package/dist/billing-foundation/types.d.ts +97 -42
- package/dist/billing-foundation/types.js +29 -20
- package/dist/billing-foundation/validate-options.js +17 -0
- package/dist/billing-foundation/web/billing-plans-panel.js +82 -36
- package/dist/billing-foundation/web/checkout-consent-dialog.d.ts +17 -3
- package/dist/billing-foundation/web/checkout-consent-dialog.js +14 -10
- package/dist/billing-foundation/web/constants.d.ts +4 -0
- package/dist/billing-foundation/web/constants.js +4 -0
- package/dist/billing-foundation/web/plan-price.d.ts +15 -0
- package/dist/billing-foundation/web/plan-price.js +32 -0
- package/dist/billing-foundation/web/plan-switch-confirm-dialog.d.ts +15 -0
- package/dist/billing-foundation/web/plan-switch-confirm-dialog.js +66 -0
- package/dist/cap-counter/aggregate-id.js +8 -9
- package/dist/cap-counter/cap-reservation.js +5 -1
- package/dist/cap-counter/constants.js +11 -12
- package/dist/cap-counter/enforce-cap.d.ts +59 -62
- package/dist/cap-counter/enforce-cap.js +49 -49
- package/dist/cap-counter/entity.js +29 -29
- package/dist/cap-counter/feature.js +34 -35
- package/dist/cap-counter/handlers/increment-rolling.write.d.ts +2 -2
- package/dist/cap-counter/handlers/increment-rolling.write.js +31 -31
- package/dist/cap-counter/handlers/mark-soft-warned.write.js +4 -5
- package/dist/cap-counter/stock-cap-guard.js +8 -2
- package/dist/cap-counter/with-cap-enforcement.d.ts +3 -5
- package/dist/channel-email/feature.js +1 -1
- package/dist/channel-email/smtp-transport.d.ts +18 -17
- package/dist/channel-email/smtp-transport.js +24 -21
- package/dist/channel-in-app/handlers/unread-count.query.js +3 -4
- package/dist/compliance-profiles/feature.js +4 -4
- package/dist/compliance-profiles/handlers/for-tenant.query.js +3 -6
- package/dist/compliance-profiles/handlers/list-profiles.query.js +5 -5
- package/dist/compliance-profiles/handlers/needs-profile.query.js +4 -4
- package/dist/compliance-profiles/handlers/set-profile.write.js +13 -14
- package/dist/compliance-profiles/handlers/sub-processors.query.js +9 -11
- package/dist/compliance-profiles/resolve-for-tenant.js +7 -7
- package/dist/compliance-profiles/schema/profile-selection.js +18 -23
- package/dist/compliance-profiles/seeding.js +14 -15
- package/dist/compliance-profiles-ops/handlers/tenants-missing-profile.query.js +3 -3
- package/dist/compliance-profiles-ops/index.js +2 -2
- package/dist/config/handlers/cascade.query.d.ts +5 -0
- package/dist/config/handlers/cascade.query.js +4 -3
- package/dist/config/handlers/readiness.query.d.ts +4 -4
- package/dist/config/handlers/readiness.query.js +1 -1
- package/dist/config/handlers/reencrypt.job.js +4 -5
- package/dist/config/handlers/set.write.js +4 -4
- package/dist/config/handlers/values.query.d.ts +5 -0
- package/dist/config/handlers/values.query.js +4 -3
- package/dist/config/resolver.js +4 -4
- package/dist/config/table.js +10 -10
- package/dist/config/write-helpers.d.ts +1 -0
- package/dist/config/write-helpers.js +19 -10
- package/dist/crypto-shredding/handlers/forget-subject.write.d.ts +2 -2
- package/dist/crypto-shredding/handlers/forget-subject.write.js +25 -21
- package/dist/custom-fields/aggregate-id.d.ts +12 -13
- package/dist/custom-fields/aggregate-id.js +16 -17
- package/dist/custom-fields/entity.js +49 -47
- package/dist/custom-fields/events.js +7 -8
- package/dist/custom-fields/feature.d.ts +14 -14
- package/dist/custom-fields/feature.js +53 -54
- package/dist/custom-fields/handlers/clear-custom-field.write.d.ts +3 -2
- package/dist/custom-fields/handlers/clear-custom-field.write.js +9 -8
- package/dist/custom-fields/handlers/define-tenant-field.write.d.ts +1 -1
- package/dist/custom-fields/handlers/define-tenant-field.write.js +2 -2
- package/dist/custom-fields/handlers/delete-system-field.write.js +6 -7
- package/dist/custom-fields/handlers/delete-tenant-field.write.d.ts +1 -1
- package/dist/custom-fields/handlers/delete-tenant-field.write.js +3 -3
- package/dist/custom-fields/handlers/set-custom-field.write.d.ts +3 -3
- package/dist/custom-fields/handlers/set-custom-field.write.js +25 -28
- package/dist/custom-fields/handlers/update-tenant-field.write.d.ts +1 -1
- package/dist/custom-fields/handlers/update-tenant-field.write.js +1 -1
- package/dist/custom-fields/lib/field-access.js +2 -2
- package/dist/custom-fields/lib/parse-serialized-field.js +1 -1
- package/dist/custom-fields/lib/quota.js +1 -1
- package/dist/custom-fields/lib/value-schema.js +10 -12
- package/dist/custom-fields/run-retention.js +3 -3
- package/dist/custom-fields/schemas.js +14 -14
- package/dist/custom-fields/web/client-plugin.js +2 -5
- package/dist/custom-fields/web/constants.js +2 -2
- package/dist/custom-fields/web/custom-fields-form-section.d.ts +4 -4
- package/dist/custom-fields/web/custom-fields-form-section.js +22 -22
- package/dist/custom-fields/wire-for-entity.js +65 -67
- package/dist/custom-fields/wire-user-data-rights.js +3 -3
- package/dist/data-retention/_internal/parse-override.js +2 -3
- package/dist/data-retention/feature.js +11 -18
- package/dist/data-retention/handlers/policy-for.query.js +6 -6
- package/dist/data-retention/keep-for.d.ts +7 -7
- package/dist/data-retention/keep-for.js +15 -15
- package/dist/data-retention/override-schema.d.ts +3 -4
- package/dist/data-retention/override-schema.js +13 -15
- package/dist/data-retention/presets.d.ts +4 -5
- package/dist/data-retention/presets.js +18 -23
- package/dist/data-retention/resolve-tenant-preset.js +17 -16
- package/dist/data-retention/resolver.d.ts +12 -12
- package/dist/data-retention/resolver.js +24 -23
- package/dist/data-retention/run-retention-cleanup.d.ts +8 -3
- package/dist/data-retention/run-retention-cleanup.js +61 -51
- package/dist/data-retention/schema/tenant-retention-override.js +13 -11
- package/dist/delivery/channel-context.js +6 -3
- package/dist/delivery/db/queries/preferences.js +2 -2
- package/dist/delivery/delivery-service.js +22 -7
- package/dist/delivery/feature.js +2 -2
- package/dist/delivery/handlers/log.query.js +1 -1
- package/dist/delivery/handlers/preferences.query.d.ts +1 -1
- package/dist/delivery/handlers/preferences.query.js +20 -1
- package/dist/delivery/handlers/unsubscribe-page-chrome.query.js +1 -1
- package/dist/delivery/tables.js +9 -8
- package/dist/delivery/unsubscribe-link.d.ts +3 -1
- package/dist/delivery/unsubscribe-page-strings.d.ts +1 -0
- package/dist/delivery/unsubscribe-page-strings.js +1 -0
- package/dist/delivery/unsubscribe-page.d.ts +2 -0
- package/dist/delivery/unsubscribe-page.js +5 -0
- package/dist/delivery/unsubscribe.js +29 -11
- package/dist/document-ingest-foundation/entity.js +4 -4
- package/dist/document-ingest-foundation/events.js +2 -2
- package/dist/document-ingest-foundation/feature.js +2 -2
- package/dist/document-ingest-foundation/pages.js +1 -1
- package/dist/document-ingest-foundation/tenant-destroy-hook.js +4 -4
- package/dist/feature-toggles/compose-tier-resolver.js +1 -1
- package/dist/feature-toggles/feature.js +1 -1
- package/dist/feature-toggles/global-feature-state-table.js +1 -1
- package/dist/feature-toggles/handlers/registered.query.js +5 -5
- package/dist/feature-toggles/toggle-sync-signal.js +1 -1
- package/dist/feature-toggles/web/constants.js +1 -1
- package/dist/file-derivatives/feature.d.ts +1 -1
- package/dist/file-derivatives/feature.js +1 -1
- package/dist/file-derivatives/handlers/public-variant.query.js +1 -1
- package/dist/file-derivatives/presets.js +1 -1
- package/dist/file-foundation/feature.js +6 -6
- package/dist/file-foundation/index.d.ts +1 -1
- package/dist/file-foundation/index.js +1 -1
- package/dist/file-foundation/read-file-ref-content.d.ts +3 -0
- package/dist/file-foundation/read-file-ref-content.js +6 -1
- package/dist/file-provider-inmemory/feature.d.ts +1 -1
- package/dist/file-provider-inmemory/feature.js +16 -16
- package/dist/file-provider-s3/env-named-feature.d.ts +0 -2
- package/dist/file-provider-s3/feature.js +16 -16
- package/dist/file-provider-s3/lib/s3-provider.js +6 -6
- package/dist/files/feature.js +6 -6
- package/dist/files-tenant-data/handlers/sweep-orphaned-derivatives.job.js +4 -4
- package/dist/files-tenant-data/hooks.js +24 -26
- package/dist/files-tenant-data/index.js +1 -1
- package/dist/folders/feature.d.ts +1 -1
- package/dist/folders/web/folder-manager.js +2 -2
- package/dist/folders/web/tree.js +5 -5
- package/dist/form-draft/db/queries/cleanup.js +3 -3
- package/dist/form-draft/db/queries/owned-file-refs.js +1 -1
- package/dist/form-draft/decrypt-draft.js +5 -1
- package/dist/form-draft/entity.js +3 -3
- package/dist/form-draft/feature.js +4 -5
- package/dist/form-draft/handlers/discard.write.js +1 -1
- package/dist/form-draft/release-file-refs.js +6 -6
- package/dist/form-draft/schemas.js +3 -3
- package/dist/form-draft/web/constants.js +0 -2
- package/dist/host-routing/dispatch.js +11 -20
- package/dist/inbound-mail-foundation/aggregate-id.d.ts +13 -13
- package/dist/inbound-mail-foundation/aggregate-id.js +19 -19
- package/dist/inbound-mail-foundation/connect-routes.js +4 -3
- package/dist/inbound-mail-foundation/constants.d.ts +22 -24
- package/dist/inbound-mail-foundation/constants.js +30 -33
- package/dist/inbound-mail-foundation/entities.d.ts +12 -12
- package/dist/inbound-mail-foundation/entities.js +47 -48
- package/dist/inbound-mail-foundation/events.d.ts +4 -3
- package/dist/inbound-mail-foundation/events.js +50 -47
- package/dist/inbound-mail-foundation/feature.js +39 -39
- package/dist/inbound-mail-foundation/handlers/account-state.js +8 -8
- package/dist/inbound-mail-foundation/handlers/connect-account.write.js +25 -26
- package/dist/inbound-mail-foundation/handlers/disconnect-account.write.js +7 -7
- package/dist/inbound-mail-foundation/handlers/ingest-message.write.js +50 -51
- package/dist/inbound-mail-foundation/handlers/list-accounts.query.js +8 -8
- package/dist/inbound-mail-foundation/handlers/list-messages.query.js +10 -10
- package/dist/inbound-mail-foundation/handlers/scope-visibility.js +3 -4
- package/dist/inbound-mail-foundation/handlers/update-account.write.d.ts +2 -2
- package/dist/inbound-mail-foundation/handlers/update-account.write.js +22 -14
- package/dist/inbound-mail-foundation/i18n.js +0 -1
- package/dist/inbound-mail-foundation/oauth-state.d.ts +5 -5
- package/dist/inbound-mail-foundation/oauth-state.js +11 -10
- package/dist/inbound-mail-foundation/projection.d.ts +4 -4
- package/dist/inbound-mail-foundation/projection.js +31 -29
- package/dist/inbound-mail-foundation/provider-factory.d.ts +4 -4
- package/dist/inbound-mail-foundation/provider-factory.js +9 -9
- package/dist/inbound-mail-foundation/retention-sweep.d.ts +5 -3
- package/dist/inbound-mail-foundation/retention-sweep.js +38 -36
- package/dist/inbound-mail-foundation/screens.js +0 -3
- package/dist/inbound-mail-foundation/tenant-destroy-hook.js +14 -16
- package/dist/inbound-mail-foundation/types.d.ts +49 -49
- package/dist/inbound-mail-foundation/types.js +21 -21
- package/dist/inbound-mail-foundation/watch-supervisor.d.ts +10 -10
- package/dist/inbound-mail-foundation/watch-supervisor.js +85 -67
- package/dist/inbound-provider-imap/credential-document.js +13 -13
- package/dist/inbound-provider-imap/feature.d.ts +2 -2
- package/dist/inbound-provider-imap/feature.js +42 -40
- package/dist/inbound-provider-imap/imap-client.d.ts +12 -11
- package/dist/inbound-provider-imap/imap-client.js +20 -19
- package/dist/inbound-provider-inmemory/feature.d.ts +9 -9
- package/dist/inbound-provider-inmemory/feature.js +19 -19
- package/dist/jobs/db/queries/retention.js +2 -2
- package/dist/jobs/db/queries/stale-run-sweep.js +3 -3
- package/dist/jobs/events.js +1 -1
- package/dist/jobs/feature.d.ts +1 -0
- package/dist/jobs/feature.js +13 -10
- package/dist/jobs/handlers/detail.query.js +4 -4
- package/dist/jobs/handlers/list.query.js +1 -1
- package/dist/jobs/handlers/projection-rebuild.job.js +1 -1
- package/dist/jobs/handlers/reindex-entity.job.js +1 -1
- package/dist/jobs/handlers/retry.write.js +1 -1
- package/dist/jobs/handlers/tenant-failures.query.d.ts +1 -1
- package/dist/jobs/handlers/tenant-failures.query.js +45 -41
- package/dist/jobs/handlers/tenant-runs.query.d.ts +1 -1
- package/dist/jobs/handlers/tenant-runs.query.js +54 -50
- package/dist/jobs/job-instant.js +1 -1
- package/dist/jobs/job-run-logger.js +15 -15
- package/dist/jobs/job-run-table.js +3 -3
- package/dist/jobs/screens.js +1 -1
- package/dist/jobs/tenant-job-failure-table.js +1 -1
- package/dist/jobs/tenant-job-run-table.js +1 -1
- package/dist/ledger/entity.js +5 -5
- package/dist/ledger/feature.js +3 -3
- package/dist/ledger/handlers/confirm-schedule-period.write.js +3 -3
- package/dist/ledger/recurring.js +12 -12
- package/dist/ledger/schemas.js +1 -1
- package/dist/ledger/web/constants.js +2 -2
- package/dist/ledger/web/index.js +7 -7
- package/dist/legal-pages/feature.d.ts +4 -4
- package/dist/legal-pages/feature.js +25 -26
- package/dist/legal-pages/markdown.js +3 -3
- package/dist/legal-pages/web/client-plugin.js +23 -24
- package/dist/legal-pages/web/index.js +0 -1
- package/dist/mail-foundation/feature.d.ts +5 -5
- package/dist/mail-foundation/feature.js +27 -25
- package/dist/mail-transport-inmemory/feature.d.ts +4 -4
- package/dist/mail-transport-inmemory/feature.js +27 -28
- package/dist/mail-transport-smtp/feature.js +20 -20
- package/dist/managed-pages/branding.js +6 -6
- package/dist/managed-pages/feature.d.ts +26 -26
- package/dist/managed-pages/feature.js +34 -34
- package/dist/managed-pages/handlers/by-slug.query.js +5 -6
- package/dist/managed-pages/handlers/by-tenant-published.query.js +2 -2
- package/dist/managed-pages/handlers/set.write.js +5 -7
- package/dist/managed-pages/screens/page-screens.js +11 -11
- package/dist/managed-pages/seeding.js +8 -8
- package/dist/managed-pages/table.js +13 -12
- package/dist/managed-pages/web/client-plugin.d.ts +1 -1
- package/dist/managed-pages/web/client-plugin.js +5 -5
- package/dist/managed-pages/web/i18n.js +1 -1
- package/dist/notes-history/entity.js +4 -4
- package/dist/notes-history/feature.d.ts +2 -2
- package/dist/notes-history-user-data/hooks.js +1 -1
- package/dist/page-render/layout.js +9 -9
- package/dist/page-render/markdown.js +11 -11
- package/dist/page-render/security-headers.js +7 -6
- package/dist/personal-access-tokens/feature.d.ts +1 -1
- package/dist/personal-access-tokens/feature.js +9 -5
- package/dist/personal-access-tokens/roles.js +2 -2
- package/dist/readiness/handlers/status.query.js +3 -3
- package/dist/renderer-foundation/api.js +12 -13
- package/dist/renderer-foundation/constants.js +2 -2
- package/dist/renderer-foundation/feature.js +7 -7
- package/dist/renderer-pdf/render-table-pdf.d.ts +1 -1
- package/dist/renderer-pdf/render-table-pdf.js +22 -10
- package/dist/secrets/feature.js +9 -9
- package/dist/secrets/web/constants.js +2 -2
- package/dist/seo/feature.js +3 -3
- package/dist/sessions/constants.d.ts +1 -1
- package/dist/sessions/constants.js +1 -1
- package/dist/sessions/feature.d.ts +2 -2
- package/dist/sessions/feature.js +12 -8
- package/dist/sessions/handlers/revoke-all-for-user.write.js +2 -2
- package/dist/sessions/handlers/revoke-all-others.write.js +2 -2
- package/dist/sessions/handlers/revoke.write.js +1 -1
- package/dist/sessions/schema/user-session.js +4 -4
- package/dist/sessions/screens.js +2 -2
- package/dist/sessions/session-callbacks.js +2 -2
- package/dist/sessions/session-revoked-event.js +2 -2
- package/dist/shared/assert-no-where-rule-in-ownership-write.js +1 -1
- package/dist/shared/decrypt-stored-pii.d.ts +1 -0
- package/dist/shared/decrypt-stored-pii.js +7 -2
- package/dist/shared/encrypt-for-direct-write.js +1 -1
- package/dist/shared/index.d.ts +1 -1
- package/dist/shared/index.js +1 -1
- package/dist/shared/mail-template-body.d.ts +6 -2
- package/dist/shared/mail-template-body.js +7 -4
- package/dist/shared/map-with-concurrency.js +5 -4
- package/dist/shared/parent-visibility.js +2 -2
- package/dist/shared/password-hashing.js +1 -1
- package/dist/shared/signup-handover.js +1 -2
- package/dist/shared/single-use-token-store.js +1 -1
- package/dist/step-dispatcher/feature.js +1 -0
- package/dist/subscription-dodo/client.d.ts +17 -0
- package/dist/subscription-dodo/client.js +31 -0
- package/dist/subscription-dodo/constants.d.ts +12 -0
- package/dist/subscription-dodo/constants.js +19 -0
- package/dist/subscription-dodo/feature.d.ts +37 -0
- package/dist/subscription-dodo/feature.js +144 -0
- package/dist/subscription-dodo/index.d.ts +2 -0
- package/dist/subscription-dodo/index.js +4 -0
- package/dist/subscription-dodo/plugin-methods.d.ts +23 -0
- package/dist/subscription-dodo/plugin-methods.js +260 -0
- package/dist/subscription-dodo/runtime.d.ts +27 -0
- package/dist/subscription-dodo/runtime.js +89 -0
- package/dist/subscription-dodo/verify-webhook.d.ts +37 -0
- package/dist/subscription-dodo/verify-webhook.js +189 -0
- package/dist/subscription-mollie/constants.js +15 -17
- package/dist/subscription-mollie/feature.d.ts +17 -18
- package/dist/subscription-mollie/feature.js +24 -24
- package/dist/subscription-mollie/index.js +3 -3
- package/dist/subscription-mollie/plugin-methods.d.ts +2 -2
- package/dist/subscription-mollie/plugin-methods.js +15 -14
- package/dist/subscription-mollie/verify-webhook.d.ts +10 -10
- package/dist/subscription-mollie/verify-webhook.js +27 -27
- package/dist/subscription-stripe/constants.js +4 -6
- package/dist/subscription-stripe/feature.d.ts +14 -14
- package/dist/subscription-stripe/feature.js +36 -34
- package/dist/subscription-stripe/index.js +6 -6
- package/dist/subscription-stripe/plugin-methods.js +18 -18
- package/dist/subscription-stripe/runtime.d.ts +1 -1
- package/dist/subscription-stripe/runtime.js +8 -7
- package/dist/subscription-stripe/verify-webhook.d.ts +11 -11
- package/dist/subscription-stripe/verify-webhook.js +59 -61
- package/dist/tags/feature.d.ts +3 -3
- package/dist/tags/screens.js +1 -1
- package/dist/template-resolver/api.d.ts +3 -2
- package/dist/template-resolver/api.js +34 -12
- package/dist/template-resolver/compile-document-body.js +1 -0
- package/dist/template-resolver/feature.js +2 -2
- package/dist/template-resolver/handlers/bundle-import.js +3 -3
- package/dist/template-resolver/handlers/copy-locale.write.d.ts +5 -1
- package/dist/template-resolver/handlers/copy-locale.write.js +22 -7
- package/dist/template-resolver/handlers/diff-to-system.query.js +3 -2
- package/dist/template-resolver/handlers/document-base.js +3 -2
- package/dist/template-resolver/handlers/find-by-id.query.js +8 -7
- package/dist/template-resolver/handlers/list.query.js +6 -7
- package/dist/template-resolver/handlers/overview.query.d.ts +3 -0
- package/dist/template-resolver/handlers/overview.query.js +6 -3
- package/dist/template-resolver/handlers/shared.js +2 -2
- package/dist/template-resolver/handlers/template-write.js +3 -3
- package/dist/template-resolver/handlers/tenant-override-counts.query.js +1 -3
- package/dist/template-resolver/handlers/tenant-override-selection.d.ts +2 -1
- package/dist/template-resolver/handlers/tenant-overrides.query.js +28 -5
- package/dist/template-resolver/handlers/upsert-system.write.js +3 -4
- package/dist/template-resolver/handlers/upsert-tenant.write.js +4 -5
- package/dist/template-resolver/handlers/usage.query.d.ts +2 -1
- package/dist/template-resolver/handlers/usage.query.js +26 -16
- package/dist/template-resolver/handlers/validate.query.js +7 -2
- package/dist/template-resolver/seeding.js +30 -14
- package/dist/template-resolver/store-template-resource.d.ts +1 -0
- package/dist/template-resolver/store-template-resource.js +19 -4
- package/dist/template-resolver/table.js +10 -11
- package/dist/template-resolver/template-delivery-policy.d.ts +0 -5
- package/dist/template-resolver/template-delivery-policy.js +0 -6
- package/dist/template-resolver/template-meta.js +7 -4
- package/dist/template-resolver/template-preview.js +4 -3
- package/dist/template-resolver/web/client-plugin.js +2 -2
- package/dist/template-resolver/web/constants.d.ts +2 -2
- package/dist/template-resolver/web/constants.js +3 -3
- package/dist/template-resolver/web/index.d.ts +1 -0
- package/dist/template-resolver/web/index.js +1 -0
- package/dist/template-resolver/web/mail-layout-constants.d.ts +5 -0
- package/dist/template-resolver/web/mail-layout-constants.js +7 -0
- package/dist/tenant/feature.js +7 -7
- package/dist/tenant/handlers/member-directory.query.d.ts +1 -0
- package/dist/tenant/handlers/member-directory.query.js +11 -4
- package/dist/tenant/handlers/members.query.js +1 -1
- package/dist/tenant/handlers/team-list.query.js +1 -1
- package/dist/tenant/handlers/tenant-directory.query.d.ts +1 -0
- package/dist/tenant/handlers/tenant-directory.query.js +9 -5
- package/dist/tenant/invitation-table.js +37 -40
- package/dist/tenant/membership-table.js +3 -3
- package/dist/tenant/schema/tenant.js +7 -9
- package/dist/tenant/screens.js +1 -1
- package/dist/tenant/seeding.d.ts +6 -5
- package/dist/tenant/seeding.js +12 -12
- package/dist/tenant/testing.js +5 -6
- package/dist/tenant/web/constants.js +2 -2
- package/dist/tenant-handover/events.js +5 -7
- package/dist/tenant-handover/feature.js +1 -1
- package/dist/tenant-handover/grant.js +1 -1
- package/dist/tenant-handover/handlers/claim.write.js +1 -1
- package/dist/tenant-handover/move-entity-graph.js +8 -9
- package/dist/tenant-handover/signup-handover-provider.js +1 -2
- package/dist/tenant-handover/transfer-graph.js +4 -5
- package/dist/tenant-lifecycle/boot-checks.js +1 -1
- package/dist/tenant-lifecycle/constants.d.ts +1 -0
- package/dist/tenant-lifecycle/constants.js +4 -0
- package/dist/tenant-lifecycle/feature.js +1 -1
- package/dist/tenant-lifecycle/run-tenant-destroy.js +2 -2
- package/dist/tenant-settings/constants.js +1 -1
- package/dist/tenant-settings/tenant-defaults.d.ts +1 -1
- package/dist/tenant-settings/tenant-defaults.js +9 -2
- package/dist/tier-engine/aggregate-id.d.ts +11 -11
- package/dist/tier-engine/aggregate-id.js +15 -16
- package/dist/tier-engine/compose-app.d.ts +14 -14
- package/dist/tier-engine/compose-app.js +1 -1
- package/dist/tier-engine/entity.js +18 -19
- package/dist/tier-engine/feature.d.ts +19 -17
- package/dist/tier-engine/feature.js +68 -69
- package/dist/tier-engine/handlers/active-tier.query.js +6 -7
- package/dist/tier-engine/handlers/get-tenant-tier.query.js +4 -4
- package/dist/tier-engine/handlers/set-tenant-tier.write.d.ts +7 -8
- package/dist/tier-engine/handlers/set-tenant-tier.write.js +7 -4
- package/dist/tier-engine/tier-resolver.js +2 -2
- package/dist/tier-engine/trial.js +8 -8
- package/dist/tier-engine/web/constants.js +2 -2
- package/dist/tier-engine/web/index.js +4 -4
- package/dist/user/db/queries/stream-tenant-backfill.js +8 -8
- package/dist/user/handlers/create.write.js +4 -4
- package/dist/user/schema/user.d.ts +11 -11
- package/dist/user/schema/user.js +45 -44
- package/dist/user/seeding.d.ts +15 -15
- package/dist/user/seeding.js +28 -28
- package/dist/user/testing.js +3 -3
- package/dist/user-data-rights/audit-download.d.ts +8 -8
- package/dist/user-data-rights/audit-download.js +19 -20
- package/dist/user-data-rights/boot-checks.js +1 -1
- package/dist/user-data-rights/deletion-token.js +1 -1
- package/dist/user-data-rights/feature.d.ts +49 -50
- package/dist/user-data-rights/feature.js +54 -53
- package/dist/user-data-rights/handlers/cancel-deletion.write.js +9 -9
- package/dist/user-data-rights/handlers/confirm-deletion-by-token.write.js +8 -8
- package/dist/user-data-rights/handlers/download-by-job.query.js +29 -30
- package/dist/user-data-rights/handlers/download-by-token.query.js +40 -42
- package/dist/user-data-rights/handlers/export-status.query.js +8 -9
- package/dist/user-data-rights/handlers/lift-restriction.write.js +7 -8
- package/dist/user-data-rights/handlers/list-download-attempts.query.js +2 -2
- package/dist/user-data-rights/handlers/my-audit-log.query.js +4 -4
- package/dist/user-data-rights/handlers/request-deletion-by-email.write.d.ts +5 -5
- package/dist/user-data-rights/handlers/request-deletion-by-email.write.js +16 -15
- package/dist/user-data-rights/handlers/request-deletion.write.d.ts +2 -2
- package/dist/user-data-rights/handlers/request-deletion.write.js +7 -9
- package/dist/user-data-rights/handlers/request-export.write.js +42 -41
- package/dist/user-data-rights/handlers/restrict-account.write.js +22 -19
- package/dist/user-data-rights/handlers/run-forget-cleanup.write.js +8 -8
- package/dist/user-data-rights/index.js +8 -10
- package/dist/user-data-rights/lib/default-mailers.js +3 -3
- package/dist/user-data-rights/lib/update-user-lifecycle.js +14 -17
- package/dist/user-data-rights/run-export-jobs.d.ts +38 -42
- package/dist/user-data-rights/run-export-jobs.js +130 -237
- package/dist/user-data-rights/run-forget-cleanup.d.ts +16 -20
- package/dist/user-data-rights/run-forget-cleanup.js +65 -83
- package/dist/user-data-rights/run-user-export.d.ts +34 -33
- package/dist/user-data-rights/run-user-export.js +55 -57
- package/dist/user-data-rights/schema/download-attempt.js +11 -11
- package/dist/user-data-rights/schema/download-token.js +37 -41
- package/dist/user-data-rights/schema/export-job.d.ts +4 -4
- package/dist/user-data-rights/schema/export-job.js +65 -67
- package/dist/user-data-rights/token-helpers.d.ts +8 -9
- package/dist/user-data-rights/token-helpers.js +21 -25
- package/dist/user-data-rights/web/client-plugin.d.ts +5 -5
- package/dist/user-data-rights/web/client-plugin.js +1 -1
- package/dist/user-data-rights/web/confirm-deletion-screen.js +6 -5
- package/dist/user-data-rights/web/constants.js +1 -1
- package/dist/user-data-rights/web/index.js +5 -5
- package/dist/user-data-rights/web/privacy-center-screen.js +14 -13
- package/dist/user-data-rights/web/public-deletion-gate.d.ts +4 -4
- package/dist/user-data-rights/web/request-deletion-screen.js +6 -6
- package/dist/user-data-rights/zip-path.d.ts +15 -15
- package/dist/user-data-rights/zip-path.js +41 -40
- package/dist/user-data-rights-defaults/feature.js +15 -15
- package/dist/user-data-rights-defaults/hooks/delivery-attempt.userdata-hook.js +3 -5
- package/dist/user-data-rights-defaults/hooks/file-ref.userdata-hook.js +45 -51
- package/dist/user-data-rights-defaults/hooks/job-run.userdata-hook.js +2 -2
- package/dist/user-data-rights-defaults/hooks/notification-preference.userdata-hook.js +1 -1
- package/dist/user-data-rights-defaults/hooks/user-session.userdata-hook.js +3 -3
- package/dist/user-data-rights-defaults/hooks/user.userdata-hook.js +32 -31
- package/dist/user-profile/handlers/change-email.write.js +13 -13
- package/dist/user-profile/index.js +3 -3
- package/dist/user-profile/web/client-plugin.js +1 -1
- package/dist/user-profile/web/constants.js +1 -1
- package/dist/user-profile/web/profile-screen.js +1 -1
- package/dist/waitlist/handlers/export-purge.write.js +2 -1
- package/dist/waitlist/handlers/submit.write.js +5 -5
- package/dist/waitlist/import.d.ts +1 -0
- package/dist/waitlist/import.js +4 -0
- package/dist/waitlist/legacy-migrate.js +17 -6
- package/dist/waitlist/link-on-signup.js +18 -6
- package/dist/waitlist/options.d.ts +3 -0
- package/dist/workflow-runner/aggregate-id.d.ts +1 -1
- package/dist/workflow-runner/aggregate-id.js +1 -1
- package/dist/workflow-runner/event-subscriber.js +4 -5
- package/dist/workflow-runner/event-trigger.js +4 -17
- package/dist/workflow-runner/feature.js +2 -2
- package/dist/workflow-runner/handlers/resume-run.write.js +4 -4
- package/dist/workflow-runner/pending-projection.js +6 -7
- package/dist/workflow-runner/runner.js +6 -6
- package/dist/workflow-runner/tables.js +6 -6
- package/dist/workflow-runner/workflow-registry.js +1 -1
- package/package.json +20 -10
- package/src/agent-tools/changes.json +6 -0
- package/src/audit/changes.json +12 -0
- package/src/auth-mfa/changes.json +6 -0
- package/src/billing-foundation/changes.json +55 -0
- package/src/cap-counter/changes.json +18 -0
- package/src/channel-email/changes.json +6 -0
- package/src/config/changes.json +12 -0
- package/src/crypto-shredding/changes.json +6 -0
- package/src/delivery/changes.json +30 -0
- package/src/form-draft/changes.json +6 -0
- package/src/host-routing/changes.json +6 -0
- package/src/inbound-mail-foundation/changes.json +18 -0
- package/src/jobs/changes.json +13 -0
- package/src/mail-foundation/changes.json +6 -0
- package/src/renderer-pdf/changes.json +6 -0
- package/src/step-dispatcher/changes.json +6 -0
- package/src/subscription-dodo/changes.json +14 -0
- package/src/subscription-stripe/changes.json +12 -0
- package/src/template-resolver/changes.json +48 -0
- package/src/tenant/changes.json +6 -0
- package/src/tenant-lifecycle/changes.json +6 -0
- package/src/tier-engine/changes.json +6 -0
- package/src/waitlist/changes.json +18 -0
- package/dist/billing-foundation/consumer-protection/stored-user-email.d.ts +0 -1
- package/dist/billing-foundation/consumer-protection/stored-user-email.js +0 -8
package/dist/sessions/screens.js
CHANGED
|
@@ -12,7 +12,7 @@ export const createSessionListScreen = (adminRoles = access.admin) => ({
|
|
|
12
12
|
pageSize: MAX_LIST_LIMIT,
|
|
13
13
|
// Mirrors list.query's own fallback (unrecognised/absent sort → createdAt
|
|
14
14
|
// desc) — kept in sync by hand, boot-validator only requires the field
|
|
15
|
-
// be present once the query accepts `sort
|
|
15
|
+
// be present once the query accepts `sort`.
|
|
16
16
|
defaultSort: { field: "createdAt", dir: "desc" },
|
|
17
17
|
columns: [
|
|
18
18
|
{ field: "id", label: i18nKey("sessions.list.col.id") },
|
|
@@ -71,7 +71,7 @@ export const createSessionDetailScreen = (adminRoles = access.admin) => ({
|
|
|
71
71
|
// The shim (projection-detail-shim.ts) stamps every field as
|
|
72
72
|
// type:"text" — field.renderer is the only way this screen
|
|
73
73
|
// type reaches real per-type formatting instead of a raw ISO
|
|
74
|
-
// string
|
|
74
|
+
// string.
|
|
75
75
|
{ field: "createdAt", renderer: { format: "timestamp" } },
|
|
76
76
|
{ field: "expiresAt", renderer: { format: "timestamp" } },
|
|
77
77
|
{ field: "revokedAt", renderer: { format: "timestamp" } },
|
|
@@ -155,11 +155,11 @@ export function createSessionCallbacks(opts) {
|
|
|
155
155
|
return transaction(db, async (tx) => {
|
|
156
156
|
const result = await updateMany(tx, userSessionTable, { revokedAt: Temporal.Now.instant() }, { userId, revokedAt: null });
|
|
157
157
|
// Lightweight append alongside the direct-write above, same pattern
|
|
158
|
-
// as revoke.write.ts
|
|
158
|
+
// as revoke.write.ts — this callback is the password-change
|
|
159
159
|
// auto-revoke path (sessions/feature.ts postSave hook) and has no
|
|
160
160
|
// dispatcher ctx to call unsafeAppendEvent from, so it uses the raw
|
|
161
161
|
// append() like revoke-all-for-user.write.ts does. Without this, the
|
|
162
|
-
// access-invalidation consumer
|
|
162
|
+
// access-invalidation consumer never hears about a password
|
|
163
163
|
// change and an already-open SSE stream survives it — the exact
|
|
164
164
|
// "stale JWT mid-stream" gap this feature exists to close.
|
|
165
165
|
if (result.length > 0) {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as z from "zod";
|
|
2
2
|
// Lightweight custom event appended alongside the direct-write
|
|
3
3
|
// updateMany() in revoke.write.ts / revoke-all-others.write.ts /
|
|
4
|
-
// revoke-all-for-user.write.ts
|
|
4
|
+
// revoke-all-for-user.write.ts. store_user_sessions itself stays
|
|
5
5
|
// an unmanaged direct-write store (see feature.ts) — the row columns are
|
|
6
6
|
// the audit trail, this event is NOT a CRUD/lifecycle event for that
|
|
7
7
|
// table and carries no projection. Its only job is to give cross-instance
|
|
8
|
-
// consumers (access-invalidation
|
|
8
|
+
// consumers (access-invalidation) something to LISTEN for via the
|
|
9
9
|
// existing event-store NOTIFY, keyed by the affected userId.
|
|
10
10
|
//
|
|
11
11
|
// _SHORT/_QN pair mirrors cap-counter's rolling-incremented event:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Boot validation rejects `{ kind: "where" }` in access.write too
|
|
1
|
+
// Boot validation rejects `{ kind: "where" }` in access.write too;
|
|
2
2
|
// failing at factory time names the option instead of an entity scope.
|
|
3
3
|
export function assertNoWhereRuleInOwnershipWrite(factoryName, writeOwnership) {
|
|
4
4
|
// skip: no write ownership declared, nothing to validate
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { requestContext } from "@cosmicdrift/kumiko-framework/api";
|
|
2
|
-
import { configuredPiiSubjectKms, decryptPiiFieldValues, } from "@cosmicdrift/kumiko-framework/crypto";
|
|
2
|
+
import { configuredPiiSubjectKms, decryptPiiFieldValues, PII_ERASED_SENTINEL, } from "@cosmicdrift/kumiko-framework/crypto";
|
|
3
3
|
// Raw reads (fetchOne/selectMany) return the stored column value — with an
|
|
4
4
|
// active KMS that is ciphertext (self-describing: it names its own subject,
|
|
5
5
|
// so no entity/field context is needed for key selection). `field` must
|
|
6
6
|
// still match the field name used at encrypt time — it is part of the
|
|
7
|
-
// AAD
|
|
7
|
+
// AAD, so a mismatch fails decrypt loud rather than silently
|
|
8
8
|
// letting ciphertext cut-and-pasted from another field decrypt. An erased
|
|
9
9
|
// subject yields the sentinel, which matches no real value.
|
|
10
10
|
export async function decryptStoredPii(value, field, fallbackRequestId) {
|
|
@@ -17,3 +17,8 @@ export async function decryptStoredPii(value, field, fallbackRequestId) {
|
|
|
17
17
|
const decrypted = out[field];
|
|
18
18
|
return typeof decrypted === "string" ? decrypted : value;
|
|
19
19
|
}
|
|
20
|
+
// Null for an erased subject: the sentinel must never be mailed or shown as an address.
|
|
21
|
+
export async function decryptStoredUserEmail(stored, fallbackRequestId) {
|
|
22
|
+
const email = await decryptStoredPii(stored, "email", fallbackRequestId);
|
|
23
|
+
return email === PII_ERASED_SENTINEL ? null : email;
|
|
24
|
+
}
|
|
@@ -4,7 +4,7 @@ import { subjectErasedConflict } from "@cosmicdrift/kumiko-framework/errors";
|
|
|
4
4
|
// Unmanaged direct-write stores (r.unmanagedTable) skip the executor, so its
|
|
5
5
|
// PII encryption never runs — every insert of subject-annotated fields must
|
|
6
6
|
// go through this instead, and the feature declares { piiEncryptedOnWrite:
|
|
7
|
-
// true } at the registration site (enforced by the registry
|
|
7
|
+
// true } at the registration site (enforced by the registry).
|
|
8
8
|
export async function encryptForDirectWrite(entity, entityName, row, fallbackRequestId) {
|
|
9
9
|
const kms = configuredPiiSubjectKms();
|
|
10
10
|
if (!kms)
|
package/dist/shared/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export { assertNoWhereRuleInOwnershipWrite } from "./assert-no-where-rule-in-own
|
|
|
3
3
|
export { attachmentFileNameSchema, sanitizePdfAttachmentFileName, } from "./attachment-file-name.ts";
|
|
4
4
|
export { type ChunkedMigrationOptions, type ChunkedMigrationResult, type ChunkedMigrationStopReason, type MigrationRowOutcome, runChunkedMigration, } from "./chunked-entity-migration.ts";
|
|
5
5
|
export { classifyStoredEnvelope, type StoredEnvelopeClassification, } from "./classify-stored-envelope.ts";
|
|
6
|
-
export { decryptStoredPii } from "./decrypt-stored-pii.ts";
|
|
6
|
+
export { decryptStoredPii, decryptStoredUserEmail } from "./decrypt-stored-pii.ts";
|
|
7
7
|
export { encryptForDirectWrite } from "./encrypt-for-direct-write.ts";
|
|
8
8
|
export { entitiesOf } from "./entities-of.ts";
|
|
9
9
|
export { isWithinGracePeriod } from "./grace-period.ts";
|
package/dist/shared/index.js
CHANGED
|
@@ -3,7 +3,7 @@ export { assertNoWhereRuleInOwnershipWrite } from "./assert-no-where-rule-in-own
|
|
|
3
3
|
export { attachmentFileNameSchema, sanitizePdfAttachmentFileName, } from "./attachment-file-name.js";
|
|
4
4
|
export { runChunkedMigration, } from "./chunked-entity-migration.js";
|
|
5
5
|
export { classifyStoredEnvelope, } from "./classify-stored-envelope.js";
|
|
6
|
-
export { decryptStoredPii } from "./decrypt-stored-pii.js";
|
|
6
|
+
export { decryptStoredPii, decryptStoredUserEmail } from "./decrypt-stored-pii.js";
|
|
7
7
|
export { encryptForDirectWrite } from "./encrypt-for-direct-write.js";
|
|
8
8
|
export { entitiesOf } from "./entities-of.js";
|
|
9
9
|
export { isWithinGracePeriod } from "./grace-period.js";
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
export declare function mailTextWithSlotsHtml(text: string): string;
|
|
2
|
-
|
|
2
|
+
type MailParagraphOptions = {
|
|
3
|
+
readonly showIf?: string;
|
|
4
|
+
};
|
|
5
|
+
export declare function mailParagraph(text: string, options?: MailParagraphOptions): string;
|
|
3
6
|
export declare function mailHeading(text: string): string;
|
|
4
7
|
export declare function mailButton(label: string, linkVariable: string): string;
|
|
5
|
-
export declare function mailParagraphWithLink(text: string, linkLabel: string, linkVariable: string): string;
|
|
8
|
+
export declare function mailParagraphWithLink(text: string, linkLabel: string, linkVariable: string, options?: MailParagraphOptions): string;
|
|
6
9
|
export declare function mailRepeatedRows(listName: string, field: string): string;
|
|
7
10
|
export declare function mailSubject(text: string): string;
|
|
11
|
+
export {};
|
|
@@ -5,8 +5,11 @@ const SLOT_PATTERN = /\{([A-Za-z_][A-Za-z0-9_]*)\}/g;
|
|
|
5
5
|
export function mailTextWithSlotsHtml(text) {
|
|
6
6
|
return escapeHtml(text).replace(SLOT_PATTERN, (_, name) => `<span data-variable="${escapeHtmlAttr(name)}"></span>`);
|
|
7
7
|
}
|
|
8
|
-
|
|
9
|
-
return `<p
|
|
8
|
+
function paragraphOpenTag(options) {
|
|
9
|
+
return options?.showIf === undefined ? "<p>" : `<p data-if="${escapeHtmlAttr(options.showIf)}">`;
|
|
10
|
+
}
|
|
11
|
+
export function mailParagraph(text, options) {
|
|
12
|
+
return `${paragraphOpenTag(options)}${mailTextWithSlotsHtml(text)}</p>`;
|
|
10
13
|
}
|
|
11
14
|
export function mailHeading(text) {
|
|
12
15
|
return `<h2>${mailTextWithSlotsHtml(text)}</h2>`;
|
|
@@ -14,8 +17,8 @@ export function mailHeading(text) {
|
|
|
14
17
|
export function mailButton(label, linkVariable) {
|
|
15
18
|
return `<p><a data-button href="{{${escapeHtmlAttr(linkVariable)}}}">${escapeHtml(label)}</a></p>`;
|
|
16
19
|
}
|
|
17
|
-
export function mailParagraphWithLink(text, linkLabel, linkVariable) {
|
|
18
|
-
return
|
|
20
|
+
export function mailParagraphWithLink(text, linkLabel, linkVariable, options) {
|
|
21
|
+
return `${paragraphOpenTag(options)}${mailTextWithSlotsHtml(text)} <a href="{{${escapeHtmlAttr(linkVariable)}}}">${escapeHtml(linkLabel)}</a></p>`;
|
|
19
22
|
}
|
|
20
23
|
// One table row per list entry; the cell shows the entry's `field`.
|
|
21
24
|
export function mailRepeatedRows(listName, field) {
|
|
@@ -12,19 +12,20 @@
|
|
|
12
12
|
// an unhandled rejection — verified in `mapWithConcurrency.test.ts`).
|
|
13
13
|
export async function mapWithConcurrency(items, limit, fn) {
|
|
14
14
|
const results = new Array(items.length);
|
|
15
|
-
|
|
15
|
+
const unclaimed = items.entries();
|
|
16
16
|
let failed = false;
|
|
17
17
|
async function worker() {
|
|
18
18
|
for (;;) {
|
|
19
19
|
// skip: another worker already failed — stop claiming new items.
|
|
20
20
|
if (failed)
|
|
21
21
|
return;
|
|
22
|
-
const
|
|
22
|
+
const claimed = unclaimed.next();
|
|
23
23
|
// skip: cursor exhausted, normal worker-loop exit
|
|
24
|
-
if (
|
|
24
|
+
if (claimed.done)
|
|
25
25
|
return;
|
|
26
|
+
const [index, item] = claimed.value;
|
|
26
27
|
try {
|
|
27
|
-
results[index] = await fn(
|
|
28
|
+
results[index] = await fn(item, index);
|
|
28
29
|
}
|
|
29
30
|
catch (err) {
|
|
30
31
|
failed = true;
|
|
@@ -60,14 +60,14 @@ export async function hostRowIsGone(registry, entityType, entityId, db) {
|
|
|
60
60
|
const row = await db.fetchOne(table, { id: entityId });
|
|
61
61
|
return row === undefined || row["isDeleted"] === true;
|
|
62
62
|
}
|
|
63
|
-
// Write-path half of the parentRef gate
|
|
63
|
+
// Write-path half of the parentRef gate. Resolves the join entity's
|
|
64
64
|
// own `parentRef` declaration from the registry — the same object the read
|
|
65
65
|
// path's SQL gate reads — so the field names and the allowedTypes allowlist
|
|
66
66
|
// exist in exactly one place instead of once per path.
|
|
67
67
|
export async function joinRowParentIsVisible(registry, joinEntityName, payload, user, db) {
|
|
68
68
|
const parentRef = registry.getEntity(joinEntityName)?.parentRef;
|
|
69
69
|
// A mount whose join entity lost its declaration can't derive a gate —
|
|
70
|
-
// deny rather than silently fall back to the
|
|
70
|
+
// deny rather than silently fall back to the open behaviour.
|
|
71
71
|
if (parentRef === undefined)
|
|
72
72
|
return false;
|
|
73
73
|
const entityType = payload[parentRef.entityTypeField];
|
|
@@ -40,7 +40,7 @@ export async function verifyPassword(hashString, password) {
|
|
|
40
40
|
return false;
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
-
// Anti-enumeration timing equaliser
|
|
43
|
+
// Anti-enumeration timing equaliser. The login handler runs this on
|
|
44
44
|
// the no-user / no-hash path so a missing account costs the same argon2
|
|
45
45
|
// latency as a real verify — otherwise response timing leaks whether an
|
|
46
46
|
// email is registered. Derived from hashPassword once and cached, so it
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
// Cross-device try-first handover
|
|
2
|
-
// offlot-app#454): signup-request runs in whichever browser the activation
|
|
1
|
+
// Cross-device try-first handover: signup-request runs in whichever browser the activation
|
|
3
2
|
// link ends up opened in, which may not be the one holding the anonymous
|
|
4
3
|
// visitor's tenant-handover grant. This extension point lets
|
|
5
4
|
// auth-email-password bind a verified grant to the signup token server-side
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
//
|
|
26
26
|
// Every key is derived from sha256(token), never the raw token — Redis key
|
|
27
27
|
// names, MONITOR output, replica traffic, and memory/backup dumps never
|
|
28
|
-
// carry the bearer secret in the clear
|
|
28
|
+
// carry the bearer secret in the clear. The by-subject entry stores
|
|
29
29
|
// the *hash* of the live token, not the token itself, so it can only be
|
|
30
30
|
// used to invalidate (delete the matching forward entry) — never to
|
|
31
31
|
// recover or resend the original token. A resend therefore always mints a
|
|
@@ -42,6 +42,7 @@ export function createStepDispatcherFeature() {
|
|
|
42
42
|
retries: DELIVER_RETRIES,
|
|
43
43
|
backoff: "exponential",
|
|
44
44
|
maxPerTenant: { limit: DELIVER_MAX_PER_TENANT, onLimit: "defer" },
|
|
45
|
+
schema: deliverJobPayloadSchema,
|
|
45
46
|
escapeHatch: { reason: DELIVER_ESCAPE_HATCH_REASON },
|
|
46
47
|
}, async (payload, ctx) => {
|
|
47
48
|
const { aggregateId } = deliverJobPayloadSchema.parse(payload);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type DodoSend = (url: string, init?: RequestInit) => Promise<Response>;
|
|
2
|
+
export type DodoRequest = {
|
|
3
|
+
readonly method: "GET" | "POST" | "PATCH";
|
|
4
|
+
/** Path segments interpolated into it must already be encodeURIComponent'ed. */
|
|
5
|
+
readonly path: string;
|
|
6
|
+
readonly query?: Readonly<Record<string, string>>;
|
|
7
|
+
readonly body?: unknown;
|
|
8
|
+
};
|
|
9
|
+
export type DodoTarget = {
|
|
10
|
+
readonly baseUrl: string;
|
|
11
|
+
readonly apiKey: string;
|
|
12
|
+
};
|
|
13
|
+
export declare class DodoHttpError extends Error {
|
|
14
|
+
readonly status: number;
|
|
15
|
+
constructor(request: DodoRequest, status: number);
|
|
16
|
+
}
|
|
17
|
+
export declare function createDodoHttp(send: DodoSend): (target: DodoTarget, request: DodoRequest) => Promise<unknown>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Thin JSON-over-fetch client for the Dodo Payments REST API. All traffic goes
|
|
2
|
+
// through the injected `send`, which defaults to the SSRF-safe egress in
|
|
3
|
+
// feature.ts and is replaced by a mock in tests.
|
|
4
|
+
import { parseJsonOrThrow } from "@cosmicdrift/kumiko-framework/utils";
|
|
5
|
+
// Never carries the response body or the key: both can hold customer data or secrets.
|
|
6
|
+
export class DodoHttpError extends Error {
|
|
7
|
+
status;
|
|
8
|
+
constructor(request, status) {
|
|
9
|
+
super(`subscription-dodo: ${request.method} ${request.path} failed with status ${status}`);
|
|
10
|
+
this.name = "DodoHttpError";
|
|
11
|
+
this.status = status;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function createDodoHttp(send) {
|
|
15
|
+
return async (target, request) => {
|
|
16
|
+
const query = request.query ? `?${new URLSearchParams(request.query).toString()}` : "";
|
|
17
|
+
const response = await send(`${target.baseUrl}${request.path}${query}`, {
|
|
18
|
+
method: request.method,
|
|
19
|
+
headers: {
|
|
20
|
+
Authorization: `Bearer ${target.apiKey}`,
|
|
21
|
+
Accept: "application/json",
|
|
22
|
+
...(request.body !== undefined && { "Content-Type": "application/json" }),
|
|
23
|
+
},
|
|
24
|
+
...(request.body !== undefined && { body: JSON.stringify(request.body) }),
|
|
25
|
+
});
|
|
26
|
+
if (!response.ok)
|
|
27
|
+
throw new DodoHttpError(request, response.status);
|
|
28
|
+
const text = await response.text();
|
|
29
|
+
return text.length === 0 ? null : parseJsonOrThrow(text, "subscription-dodo response");
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const SUBSCRIPTION_DODO_FEATURE: "subscription-dodo";
|
|
2
|
+
export declare const DODO_PROVIDER_NAME: "dodo";
|
|
3
|
+
export declare const DODO_API_KEY_CONFIG: "api-key";
|
|
4
|
+
export declare const DODO_WEBHOOK_SECRET_CONFIG: "webhook-secret";
|
|
5
|
+
export declare const DODO_BILLING_LIVE_CONFIG: "billingLive";
|
|
6
|
+
export declare const DODO_ENVIRONMENT_CONFIG: "environment";
|
|
7
|
+
export declare const DodoEnvironments: {
|
|
8
|
+
readonly test: "test";
|
|
9
|
+
readonly live: "live";
|
|
10
|
+
};
|
|
11
|
+
export type DodoEnvironment = (typeof DodoEnvironments)[keyof typeof DodoEnvironments];
|
|
12
|
+
export declare const DODO_BASE_URLS: Readonly<Record<DodoEnvironment, string>>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const SUBSCRIPTION_DODO_FEATURE = "subscription-dodo";
|
|
2
|
+
// Must match the path segment in the webhook URL `/api/subscription/webhook/dodo`.
|
|
3
|
+
export const DODO_PROVIDER_NAME = "dodo";
|
|
4
|
+
// Config-key short-names, qualified to `subscription-dodo:config:<name>` at
|
|
5
|
+
// registry-build. api-key + webhook-secret are backing:"secrets".
|
|
6
|
+
export const DODO_API_KEY_CONFIG = "api-key";
|
|
7
|
+
export const DODO_WEBHOOK_SECRET_CONFIG = "webhook-secret";
|
|
8
|
+
export const DODO_BILLING_LIVE_CONFIG = "billingLive";
|
|
9
|
+
export const DODO_ENVIRONMENT_CONFIG = "environment";
|
|
10
|
+
// Separate from billingLive on purpose: staging runs Dodo's test API with
|
|
11
|
+
// billingLive on, production flips both.
|
|
12
|
+
export const DodoEnvironments = {
|
|
13
|
+
test: "test",
|
|
14
|
+
live: "live",
|
|
15
|
+
};
|
|
16
|
+
export const DODO_BASE_URLS = {
|
|
17
|
+
test: "https://test.dodopayments.com",
|
|
18
|
+
live: "https://live.dodopayments.com",
|
|
19
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type FeatureDefinition } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
|
+
import { type FeatureWithEnvSchema } from "@cosmicdrift/kumiko-framework/env";
|
|
3
|
+
import * as z from "zod";
|
|
4
|
+
import type { DodoSend } from "./client.ts";
|
|
5
|
+
/** Bridge contract: both fields are optional fallbacks for the secrets store. */
|
|
6
|
+
export declare const subscriptionDodoEnvSchema: z.ZodObject<{
|
|
7
|
+
DODO_PAYMENTS_API_KEY: z.ZodOptional<z.ZodString>;
|
|
8
|
+
DODO_PAYMENTS_WEBHOOK_KEY: z.ZodOptional<z.ZodString>;
|
|
9
|
+
}, z.core.$strip>;
|
|
10
|
+
type DodoProductEnvShape<TPrice extends string> = {
|
|
11
|
+
[Key in `DODO_PRODUCT_${TPrice}`]: z.ZodOptional<z.ZodString>;
|
|
12
|
+
};
|
|
13
|
+
/** Dodo env block plus one `DODO_PRODUCT_<NAME>` slot per plan product the app
|
|
14
|
+
* maps to a tier, e.g. `dodoEnvSchema({ prices: ["PRO", "TEAM"] })`.
|
|
15
|
+
* Shares its bridge fields with `subscriptionDodoEnvSchema`, so spreading
|
|
16
|
+
* it into `composeEnvSchema({ extend })` next to the mounted feature is no
|
|
17
|
+
* key clash. */
|
|
18
|
+
export declare function dodoEnvSchema<const TPrice extends string>(options: {
|
|
19
|
+
readonly prices: readonly TPrice[];
|
|
20
|
+
}): z.ZodObject<{
|
|
21
|
+
DODO_PAYMENTS_API_KEY: z.ZodOptional<z.ZodString>;
|
|
22
|
+
DODO_PAYMENTS_WEBHOOK_KEY: z.ZodOptional<z.ZodString>;
|
|
23
|
+
} & DodoProductEnvShape<TPrice> extends infer T ? { -readonly [P in keyof T]: T[P]; } : never, z.core.$strip>;
|
|
24
|
+
export type SubscriptionDodoOptions = {
|
|
25
|
+
/** Bridge-fallback API key; the `api-key` config key wins when set. */
|
|
26
|
+
readonly apiKey?: string;
|
|
27
|
+
/** Bridge-fallback webhook secret; the `webhook-secret` config key wins when set. */
|
|
28
|
+
readonly webhookSecret?: string;
|
|
29
|
+
/** Dodo product id → app tier name. Products absent here drop the event. */
|
|
30
|
+
readonly priceToTier?: Readonly<Record<string, string>>;
|
|
31
|
+
/** Product ids a mode:"payment" checkout may target; empty = one-off checkouts closed. */
|
|
32
|
+
readonly oneOffPriceIds?: readonly string[];
|
|
33
|
+
/** HTTP transport; defaults to the SSRF-safe external egress. Test seam. */
|
|
34
|
+
readonly send?: DodoSend;
|
|
35
|
+
};
|
|
36
|
+
export declare function createSubscriptionDodoFeature(options?: SubscriptionDodoOptions): FeatureWithEnvSchema<FeatureDefinition, typeof subscriptionDodoEnvSchema.shape>;
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// kumiko-feature-version: 1
|
|
2
|
+
//
|
|
3
|
+
// subscription-dodo — Dodo Payments (merchant of record) plugin for the
|
|
4
|
+
// billing-foundation plugin API. Credentials, the billing-live master switch and
|
|
5
|
+
// the API environment (test | live) are config keys resolved at call time, like
|
|
6
|
+
// subscription-stripe. `apiKey` / `webhookSecret` options are env→secrets bridge
|
|
7
|
+
// fallbacks.
|
|
8
|
+
import { access, createSystemConfig, defineFeature, } from "@cosmicdrift/kumiko-framework/engine";
|
|
9
|
+
import { featureWithEnvSchema } from "@cosmicdrift/kumiko-framework/env";
|
|
10
|
+
import { egress } from "@cosmicdrift/kumiko-framework/http";
|
|
11
|
+
import * as z from "zod";
|
|
12
|
+
import { DODO_API_KEY_CONFIG, DODO_BILLING_LIVE_CONFIG, DODO_ENVIRONMENT_CONFIG, DODO_PROVIDER_NAME, DODO_WEBHOOK_SECRET_CONFIG, DodoEnvironments, SUBSCRIPTION_DODO_FEATURE, } from "./constants.js";
|
|
13
|
+
import { createDodoApplyPlanSwitch, createDodoCancelSubscription, createDodoCheckoutSession, createDodoPortalSession, createDodoPreviewPlanSwitch, createDodoPriceCache, createDodoResumeSubscription, createDodoRetrievePrices, createDodoRetrieveSubscription, } from "./plugin-methods.js";
|
|
14
|
+
import { createDodoRuntimes } from "./runtime.js";
|
|
15
|
+
import { verifyAndParseDodoWebhook } from "./verify-webhook.js";
|
|
16
|
+
/** Bridge contract: both fields are optional fallbacks for the secrets store. */
|
|
17
|
+
export const subscriptionDodoEnvSchema = z.object({
|
|
18
|
+
DODO_PAYMENTS_API_KEY: z
|
|
19
|
+
.string()
|
|
20
|
+
.min(1)
|
|
21
|
+
.describe("Dodo Payments API key. Bridge-fallback — prefer the secret.")
|
|
22
|
+
.meta({ kumiko: { pulumi: { secret: true } } })
|
|
23
|
+
.optional(),
|
|
24
|
+
DODO_PAYMENTS_WEBHOOK_KEY: z
|
|
25
|
+
.string()
|
|
26
|
+
.min(1)
|
|
27
|
+
.describe("Dodo Payments webhook signing key (`whsec_...`). Bridge-fallback — prefer the secret.")
|
|
28
|
+
.meta({ kumiko: { pulumi: { secret: true } } })
|
|
29
|
+
.optional(),
|
|
30
|
+
});
|
|
31
|
+
/** Dodo env block plus one `DODO_PRODUCT_<NAME>` slot per plan product the app
|
|
32
|
+
* maps to a tier, e.g. `dodoEnvSchema({ prices: ["PRO", "TEAM"] })`.
|
|
33
|
+
* Shares its bridge fields with `subscriptionDodoEnvSchema`, so spreading
|
|
34
|
+
* it into `composeEnvSchema({ extend })` next to the mounted feature is no
|
|
35
|
+
* key clash. */
|
|
36
|
+
export function dodoEnvSchema(options) {
|
|
37
|
+
const productShape = Object.fromEntries(options.prices.map((price) => [
|
|
38
|
+
`DODO_PRODUCT_${price}`,
|
|
39
|
+
z
|
|
40
|
+
.string()
|
|
41
|
+
.regex(/^pdt_/, `DODO_PRODUCT_${price} must start with 'pdt_'`)
|
|
42
|
+
.optional()
|
|
43
|
+
.describe(`Dodo Payments product id (\`pdt_...\`) of the ${price} plan.`),
|
|
44
|
+
]));
|
|
45
|
+
return z.object({ ...subscriptionDodoEnvSchema.shape, ...productShape });
|
|
46
|
+
}
|
|
47
|
+
// Validated once at feature-build time so a typo fails app startup instead of
|
|
48
|
+
// silently widening or narrowing the one-off allowlist at request time.
|
|
49
|
+
function validateOneOffPriceIds(priceIds) {
|
|
50
|
+
const seen = new Set();
|
|
51
|
+
for (const priceId of priceIds) {
|
|
52
|
+
if (priceId.length === 0) {
|
|
53
|
+
throw new Error("subscription-dodo: oneOffPriceIds must not contain an empty string");
|
|
54
|
+
}
|
|
55
|
+
if (seen.has(priceId)) {
|
|
56
|
+
throw new Error(`subscription-dodo: duplicate oneOffPriceIds entry "${priceId}"`);
|
|
57
|
+
}
|
|
58
|
+
seen.add(priceId);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export function createSubscriptionDodoFeature(options = {}) {
|
|
62
|
+
validateOneOffPriceIds(options.oneOffPriceIds ?? []);
|
|
63
|
+
const feature = defineFeature(SUBSCRIPTION_DODO_FEATURE, (r) => {
|
|
64
|
+
r.describe('Dodo Payments provider plugin for `billing-foundation`. Dodo acts as merchant of record: it sells to the customer and issues invoice and VAT, so the consumer-protection texts for this provider come from `consumerProtection.providerTexts`. Reads its API key and webhook secret from system config keys with `backing:"secrets"` (envelope-encrypted in the secrets store under the system tenant), plus a `billingLive` master switch and an `environment` key (test | live). `environment` is its own key because Dodo serves test and live mode from different API hosts and a live key must never hit the test host or the other way round; `billingLive` only decides whether checkouts are offered at all. All four are runtime config, so keys rotate and prod goes live without a redeploy, and the `mask` on each derives the sysadmin settings screen and nav. Mount via `createSubscriptionDodoFeature({ priceToTier })`; the optional `apiKey`/`webhookSecret` options are env to secrets bridge fallbacks (`DODO_PAYMENTS_API_KEY`, `DODO_PAYMENTS_WEBHOOK_KEY`). The plugin always mounts; `createCheckoutSession` throws `feature_disabled` unless `billingLive` is true. Webhooks arrive at `/api/subscription/webhook/dodo` and are verified per the Standard Webhooks spec (HMAC-SHA256 over id, timestamp and the raw body, 5 minute tolerance); events for products outside `priceToTier` or without tenant metadata are dropped. Implements hosted checkout, customer portal, cancel and resume, `retrievePrices` (10-minute TTL cache), `retrieveSubscription` for the sync job, and an in-app plan switch: `previewPlanSwitch` shows the proration before the customer confirms, `applyPlanSwitch` changes the plan without a hosted page and waits for the `plan_changed` webhook to move the tier. A plan switch in Dodo requires all plan products to belong to one Product Collection.');
|
|
65
|
+
r.uiHints({
|
|
66
|
+
displayLabel: "Billing · Dodo Payments",
|
|
67
|
+
category: "billing",
|
|
68
|
+
recommended: false,
|
|
69
|
+
});
|
|
70
|
+
r.requires({ features: ["billing-foundation"] });
|
|
71
|
+
r.requires({ features: ["config"] });
|
|
72
|
+
r.requires({ features: ["secrets"] });
|
|
73
|
+
r.envSchema(subscriptionDodoEnvSchema);
|
|
74
|
+
const configKeys = r.config({
|
|
75
|
+
keys: {
|
|
76
|
+
[DODO_API_KEY_CONFIG]: createSystemConfig("text", {
|
|
77
|
+
backing: "secrets",
|
|
78
|
+
write: access.systemAdmin,
|
|
79
|
+
read: access.admin,
|
|
80
|
+
mask: { title: "subscription-dodo.api-key", icon: "key", order: 1 },
|
|
81
|
+
}),
|
|
82
|
+
[DODO_WEBHOOK_SECRET_CONFIG]: createSystemConfig("text", {
|
|
83
|
+
backing: "secrets",
|
|
84
|
+
write: access.systemAdmin,
|
|
85
|
+
read: access.admin,
|
|
86
|
+
mask: { title: "subscription-dodo.webhook-secret", icon: "shield", order: 2 },
|
|
87
|
+
}),
|
|
88
|
+
[DODO_ENVIRONMENT_CONFIG]: createSystemConfig("select", {
|
|
89
|
+
default: DodoEnvironments.test,
|
|
90
|
+
options: [DodoEnvironments.test, DodoEnvironments.live],
|
|
91
|
+
write: access.systemAdmin,
|
|
92
|
+
read: access.admin,
|
|
93
|
+
mask: { title: "subscription-dodo.environment", icon: "server", order: 3 },
|
|
94
|
+
}),
|
|
95
|
+
[DODO_BILLING_LIVE_CONFIG]: createSystemConfig("boolean", {
|
|
96
|
+
default: false,
|
|
97
|
+
write: access.privileged,
|
|
98
|
+
read: access.admin,
|
|
99
|
+
mask: { title: "subscription-dodo.billing-live", icon: "rocket", order: 4 },
|
|
100
|
+
}),
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
r.translations({
|
|
104
|
+
keys: {
|
|
105
|
+
"subscription-dodo.api-key": { en: "Dodo Payments API key" },
|
|
106
|
+
"subscription-dodo.webhook-secret": { en: "Dodo Payments webhook secret" },
|
|
107
|
+
"subscription-dodo.environment": { en: "Dodo Payments environment" },
|
|
108
|
+
"subscription-dodo.billing-live": { en: "Live billing" },
|
|
109
|
+
"subscription-dodo.settings": { en: "Dodo Payments" },
|
|
110
|
+
"screen:subscription-dodo-system.title": { en: "Dodo Payments" },
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
const priceToTier = options.priceToTier ?? {};
|
|
114
|
+
const runtimes = createDodoRuntimes({
|
|
115
|
+
apiKeyHandle: configKeys[DODO_API_KEY_CONFIG],
|
|
116
|
+
webhookSecretHandle: configKeys[DODO_WEBHOOK_SECRET_CONFIG],
|
|
117
|
+
billingLiveHandle: configKeys[DODO_BILLING_LIVE_CONFIG],
|
|
118
|
+
environmentHandle: configKeys[DODO_ENVIRONMENT_CONFIG],
|
|
119
|
+
send: options.send ?? egress({ kind: "external" }),
|
|
120
|
+
fallback: {
|
|
121
|
+
...(options.apiKey !== undefined && { apiKey: options.apiKey }),
|
|
122
|
+
...(options.webhookSecret !== undefined && { webhookSecret: options.webhookSecret }),
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
const plugin = {
|
|
126
|
+
displayName: "Dodo Payments",
|
|
127
|
+
verifyAndParseWebhook: verifyAndParseDodoWebhook(runtimes.webhook, { priceToTier }),
|
|
128
|
+
createCheckoutSession: createDodoCheckoutSession(runtimes.ctx),
|
|
129
|
+
createPortalSession: createDodoPortalSession(runtimes.ctx),
|
|
130
|
+
cancelSubscription: createDodoCancelSubscription(runtimes.ctx),
|
|
131
|
+
resumeSubscription: createDodoResumeSubscription(runtimes.ctx),
|
|
132
|
+
priceToTier,
|
|
133
|
+
oneOffPriceIds: options.oneOffPriceIds ?? [],
|
|
134
|
+
isBillingEnabled: runtimes.ctx.isBillingEnabled,
|
|
135
|
+
retrievePrices: createDodoRetrievePrices(runtimes.ctx, createDodoPriceCache()),
|
|
136
|
+
retrieveSubscription: createDodoRetrieveSubscription(runtimes.ctx, { priceToTier }),
|
|
137
|
+
previewPlanSwitch: createDodoPreviewPlanSwitch(runtimes.ctx),
|
|
138
|
+
applyPlanSwitch: createDodoApplyPlanSwitch(runtimes.ctx),
|
|
139
|
+
};
|
|
140
|
+
r.useExtension("subscriptionProvider", DODO_PROVIDER_NAME, plugin);
|
|
141
|
+
return { configKeys };
|
|
142
|
+
});
|
|
143
|
+
return featureWithEnvSchema(feature, subscriptionDodoEnvSchema);
|
|
144
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// Public API of the subscription-dodo bundled feature. The webhook verifier,
|
|
2
|
+
// client and plugin methods are internal to feature.ts.
|
|
3
|
+
export { DODO_BASE_URLS, DODO_PROVIDER_NAME, DodoEnvironments, SUBSCRIPTION_DODO_FEATURE, } from "./constants.js";
|
|
4
|
+
export { createSubscriptionDodoFeature, dodoEnvSchema, subscriptionDodoEnvSchema, } from "./feature.js";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type ProviderPrice, type SubscriptionProviderPlugin } from "@cosmicdrift/kumiko-bundled-features/billing-foundation";
|
|
2
|
+
import type { DodoCtxRuntime } from "./runtime.ts";
|
|
3
|
+
type PluginMethod<TName extends keyof SubscriptionProviderPlugin> = NonNullable<SubscriptionProviderPlugin[TName]>;
|
|
4
|
+
export declare function createDodoCheckoutSession(runtime: DodoCtxRuntime): PluginMethod<"createCheckoutSession">;
|
|
5
|
+
export declare function createDodoPortalSession(runtime: DodoCtxRuntime): PluginMethod<"createPortalSession">;
|
|
6
|
+
export declare function createDodoCancelSubscription(runtime: DodoCtxRuntime): PluginMethod<"cancelSubscription">;
|
|
7
|
+
export declare function createDodoResumeSubscription(runtime: DodoCtxRuntime): PluginMethod<"resumeSubscription">;
|
|
8
|
+
export type DodoPriceCache = {
|
|
9
|
+
readonly get: (priceId: string) => ProviderPrice | null | undefined;
|
|
10
|
+
readonly set: (priceId: string, price: ProviderPrice | null) => void;
|
|
11
|
+
};
|
|
12
|
+
export type DodoPriceCacheOptions = {
|
|
13
|
+
readonly ttlMs?: number;
|
|
14
|
+
readonly now?: () => number;
|
|
15
|
+
};
|
|
16
|
+
export declare function createDodoPriceCache({ ttlMs, now, }?: DodoPriceCacheOptions): DodoPriceCache;
|
|
17
|
+
export declare function createDodoRetrievePrices(runtime: DodoCtxRuntime, cache: DodoPriceCache): PluginMethod<"retrievePrices">;
|
|
18
|
+
export declare function createDodoPreviewPlanSwitch(runtime: DodoCtxRuntime): PluginMethod<"previewPlanSwitch">;
|
|
19
|
+
export declare function createDodoApplyPlanSwitch(runtime: DodoCtxRuntime): PluginMethod<"applyPlanSwitch">;
|
|
20
|
+
export declare function createDodoRetrieveSubscription(runtime: DodoCtxRuntime, options: {
|
|
21
|
+
readonly priceToTier: Readonly<Record<string, string>>;
|
|
22
|
+
}): PluginMethod<"retrieveSubscription">;
|
|
23
|
+
export {};
|