@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
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Registry } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
2
|
import { isPlainObject, propertyOf } from "@cosmicdrift/kumiko-types/type-guards";
|
|
3
|
-
import { isSystemAdmin } from "./template-draft.ts";
|
|
4
3
|
import { SYSTEM_TENANT_ID } from "./web/constants.ts";
|
|
5
4
|
import { TEMPLATE_RESOLVER_FEATURE } from "./web/qualified-names.ts";
|
|
6
5
|
|
|
@@ -45,16 +44,6 @@ export function isRowServed(
|
|
|
45
44
|
return row.tenantId === SYSTEM_TENANT_ID || isTenantOverrideServed(policy, row);
|
|
46
45
|
}
|
|
47
46
|
|
|
48
|
-
// A SystemAdmin sees every stored row, so a locked override can still be reset; everyone else
|
|
49
|
-
// sees only what is delivered, which keeps a locked override out of the template-resolver queries for a TenantAdmin (the audit log keeps the history).
|
|
50
|
-
export function isRowServedTo(
|
|
51
|
-
policy: TemplateDeliveryPolicy,
|
|
52
|
-
user: { readonly roles: readonly string[] },
|
|
53
|
-
row: DeliveryTarget & { readonly tenantId: string },
|
|
54
|
-
): boolean {
|
|
55
|
-
return isSystemAdmin(user) || isRowServed(policy, row);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
47
|
function isDeliveryTarget(value: unknown): value is DeliveryTarget {
|
|
59
48
|
return (
|
|
60
49
|
typeof propertyOf(value, "kind") === "string" && typeof propertyOf(value, "slug") === "string"
|
|
@@ -6,6 +6,12 @@ import {
|
|
|
6
6
|
type TemplateKind,
|
|
7
7
|
} from "./web/constants.ts";
|
|
8
8
|
import { MAIL_TONES, type MailTone } from "./web/mail-constants.ts";
|
|
9
|
+
import {
|
|
10
|
+
MAIL_LAYOUT_ACCENT_LINES,
|
|
11
|
+
MAIL_LAYOUT_BUTTON_STYLES,
|
|
12
|
+
MAIL_LAYOUT_FONTS,
|
|
13
|
+
MAIL_LAYOUT_WIDTHS,
|
|
14
|
+
} from "./web/mail-layout-constants.ts";
|
|
9
15
|
|
|
10
16
|
// One or more kebab segments joined by ":" — notification templates are seeded
|
|
11
17
|
// under their qualified name `feature:notify:name`.
|
|
@@ -89,13 +95,15 @@ const pdfMetaSchema = z
|
|
|
89
95
|
})
|
|
90
96
|
.strict();
|
|
91
97
|
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
98
|
+
const MAIL_LAYOUT_WIDTH_LITERALS = [
|
|
99
|
+
z.literal(MAIL_LAYOUT_WIDTHS[0]),
|
|
100
|
+
z.literal(MAIL_LAYOUT_WIDTHS[1]),
|
|
101
|
+
z.literal(MAIL_LAYOUT_WIDTHS[2]),
|
|
102
|
+
] as const;
|
|
95
103
|
|
|
96
104
|
const mailLayoutMetaSchema = z
|
|
97
105
|
.object({
|
|
98
|
-
width: z.union(
|
|
106
|
+
width: z.union(MAIL_LAYOUT_WIDTH_LITERALS).optional(),
|
|
99
107
|
font: z.enum(MAIL_LAYOUT_FONTS).optional(),
|
|
100
108
|
outerBackground: z.string().regex(HEX_COLOR_PATTERN, "must be a #rrggbb color").optional(),
|
|
101
109
|
accentLine: z.enum(MAIL_LAYOUT_ACCENT_LINES).optional(),
|
|
@@ -28,7 +28,12 @@ import {
|
|
|
28
28
|
RendererError,
|
|
29
29
|
type RendererPlugin,
|
|
30
30
|
} from "../renderer-foundation/index.ts";
|
|
31
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
createTemplateResolverApi,
|
|
33
|
+
isRowDeliveredTo,
|
|
34
|
+
TemplateNotFoundError,
|
|
35
|
+
type TemplateResource,
|
|
36
|
+
} from "./api.ts";
|
|
32
37
|
import { collectDocumentResourceKeys } from "./compile-document-body.ts";
|
|
33
38
|
import { parseStoredJson } from "./handlers/template-gates.ts";
|
|
34
39
|
import { validateTemplateDraft } from "./handlers/validate.query.ts";
|
|
@@ -41,7 +46,7 @@ import {
|
|
|
41
46
|
import { type LinkedResourceEntry, parseLinkedResourceEntries } from "./linked-resources.ts";
|
|
42
47
|
import { buildDisplayHtml } from "./preview-display-html.ts";
|
|
43
48
|
import { type TemplateResourceRow, templateResourcesTable } from "./table.ts";
|
|
44
|
-
import { deliveryPolicyOf
|
|
49
|
+
import { deliveryPolicyOf } from "./template-delivery-policy.ts";
|
|
45
50
|
import {
|
|
46
51
|
isMailTemplateMeta,
|
|
47
52
|
type MailTemplateMeta,
|
|
@@ -327,7 +332,10 @@ async function loadEditedRowResources(
|
|
|
327
332
|
{ limit: 1 },
|
|
328
333
|
);
|
|
329
334
|
const row = rows[0];
|
|
330
|
-
if (
|
|
335
|
+
if (
|
|
336
|
+
row !== undefined &&
|
|
337
|
+
!(await isRowDeliveredTo(ctx.db, deliveryPolicyOf(ctx.registry), user, row))
|
|
338
|
+
) {
|
|
331
339
|
return undefined;
|
|
332
340
|
}
|
|
333
341
|
return row === undefined ? undefined : parseLinkedResourceEntries(row.linkedResources);
|
|
@@ -173,7 +173,7 @@ function makeTreeProvider(tenantIdOverride?: string, collectionId?: string): Tre
|
|
|
173
173
|
const headers: Record<string, string> = { "content-type": "application/json" };
|
|
174
174
|
const csrf = readCsrfToken();
|
|
175
175
|
if (csrf !== undefined) headers[CSRF_HEADER_NAME] = csrf;
|
|
176
|
-
// kumiko-lint-ignore no-raw-hooks
|
|
176
|
+
// kumiko-lint-ignore no-raw-hooks not yet converted to the framework hook set
|
|
177
177
|
fetch("/api/query", {
|
|
178
178
|
method: "POST",
|
|
179
179
|
headers,
|
|
@@ -344,7 +344,7 @@ function TextBlockEditor({
|
|
|
344
344
|
|
|
345
345
|
// Sync loaded data into the form state. loaded === null means the block does
|
|
346
346
|
// not exist yet — empty form for the create flow.
|
|
347
|
-
// kumiko-lint-ignore no-raw-hooks
|
|
347
|
+
// kumiko-lint-ignore no-raw-hooks not yet converted to the framework hook set
|
|
348
348
|
useEffect(() => {
|
|
349
349
|
if (loading) return;
|
|
350
350
|
setTitle(loaded?.title ?? "");
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
// RenderKind identifies the consumer class of a template. Plugin renderers in
|
|
5
5
|
// `renderer-foundation` match on kind; the resolver here is kind-agnostic: it
|
|
6
6
|
// only loads, and the content format (markdown/mjml/html) decides who renders it.
|
|
7
|
+
import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
|
|
8
|
+
|
|
7
9
|
export const RENDER_KINDS = ["mail", "document-pdf", "image-snapshot"] as const;
|
|
8
10
|
export type RenderKind = (typeof RENDER_KINDS)[number];
|
|
9
11
|
|
|
@@ -55,8 +57,10 @@ export const COLLECTION_REFUSED_KINDS = [
|
|
|
55
57
|
"pdf-layout",
|
|
56
58
|
] as const satisfies readonly TemplateKind[];
|
|
57
59
|
|
|
58
|
-
export function isCollectionRefusedKind(
|
|
59
|
-
|
|
60
|
+
export function isCollectionRefusedKind(
|
|
61
|
+
kind: unknown,
|
|
62
|
+
): kind is (typeof COLLECTION_REFUSED_KINDS)[number] {
|
|
63
|
+
return isOneOf(COLLECTION_REFUSED_KINDS, kind);
|
|
60
64
|
}
|
|
61
65
|
|
|
62
66
|
export const CONTENT_FORMATS = ["markdown", "mjml", "html", "plain"] as const;
|
|
@@ -69,6 +73,7 @@ export const TEMPLATE_STATUSES = ["draft", "active", "archived"] as const;
|
|
|
69
73
|
export type TemplateStatus = (typeof TEMPLATE_STATUSES)[number];
|
|
70
74
|
export const ACTIVE_TEMPLATE_STATUS = "active" satisfies TemplateStatus;
|
|
71
75
|
|
|
76
|
+
export { HEX_COLOR_PATTERN } from "./mail-layout-constants.ts";
|
|
72
77
|
export {
|
|
73
78
|
PDF_DEFAULT_MARGIN_MM,
|
|
74
79
|
PDF_FOOTER_MARGIN_MM,
|
|
@@ -79,9 +84,6 @@ export {
|
|
|
79
84
|
type PdfPageFormat,
|
|
80
85
|
} from "./pdf-constants.ts";
|
|
81
86
|
|
|
82
|
-
// Colors end up inside MJML attributes, so only a strict hex is ever written there.
|
|
83
|
-
export const HEX_COLOR_PATTERN = /^#[0-9a-fA-F]{6}$/;
|
|
84
|
-
|
|
85
87
|
export const DEFAULT_MAIL_LAYOUT_SLUG = "default";
|
|
86
88
|
export const DEFAULT_PDF_LAYOUT_SLUG = "default";
|
|
87
89
|
|
|
@@ -16,6 +16,13 @@ export {
|
|
|
16
16
|
PDF_DOCUMENT_BLOCKS,
|
|
17
17
|
} from "./document-toolbar-blocks.ts";
|
|
18
18
|
export { MAIL_TONES, type MailTone } from "./mail-constants.ts";
|
|
19
|
+
export {
|
|
20
|
+
HEX_COLOR_PATTERN,
|
|
21
|
+
MAIL_LAYOUT_ACCENT_LINES,
|
|
22
|
+
MAIL_LAYOUT_BUTTON_STYLES,
|
|
23
|
+
MAIL_LAYOUT_FONTS,
|
|
24
|
+
MAIL_LAYOUT_WIDTHS,
|
|
25
|
+
} from "./mail-layout-constants.ts";
|
|
19
26
|
export {
|
|
20
27
|
PDF_DEFAULT_MARGIN_MM,
|
|
21
28
|
PDF_FOOTER_MARGIN_MM,
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// No imports: web/ re-exports these, and template-meta.ts pulls in zod and the framework engine.
|
|
2
|
+
export const MAIL_LAYOUT_WIDTHS = [560, 600, 640] as const;
|
|
3
|
+
export const MAIL_LAYOUT_FONTS = ["sans", "serif"] as const;
|
|
4
|
+
export const MAIL_LAYOUT_ACCENT_LINES = ["branding", "none"] as const;
|
|
5
|
+
export const MAIL_LAYOUT_BUTTON_STYLES = ["filled-rounded", "filled-square", "outline"] as const;
|
|
6
|
+
|
|
7
|
+
// Colors end up inside MJML attributes, so only a strict hex is ever written there.
|
|
8
|
+
export const HEX_COLOR_PATTERN = /^#[0-9a-fA-F]{6}$/;
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.388.0",
|
|
4
|
+
"type": "fix",
|
|
5
|
+
"title": "Tenant directory search contract documented",
|
|
6
|
+
"detail": "A search returns the first limit matches in tenant-key order, sorted by label afterwards; the handler description now says so."
|
|
7
|
+
},
|
|
2
8
|
{
|
|
3
9
|
"version": "0.383.0",
|
|
4
10
|
"type": "improvement",
|
|
@@ -98,10 +98,10 @@ export function createTenantFeature(options?: TenantFeatureOptions): FeatureDefi
|
|
|
98
98
|
|
|
99
99
|
r.config({
|
|
100
100
|
keys: {
|
|
101
|
-
//
|
|
101
|
+
// Core tenant settings — tenant admins can change them; all users can read them.
|
|
102
102
|
companyName: createTenantConfig("text", { default: "" }),
|
|
103
|
-
//
|
|
104
|
-
//
|
|
103
|
+
// Curated subset of IANA time zones covering the most relevant practical cases.
|
|
104
|
+
// Extend it when a real need arises.
|
|
105
105
|
timezone: createTenantConfig("select", {
|
|
106
106
|
default: "Europe/Berlin",
|
|
107
107
|
options: [
|
|
@@ -124,8 +124,8 @@ export function createTenantFeature(options?: TenantFeatureOptions): FeatureDefi
|
|
|
124
124
|
options: ["de", "en", "fr", "es"],
|
|
125
125
|
}),
|
|
126
126
|
|
|
127
|
-
// SMTP —
|
|
128
|
-
//
|
|
127
|
+
// SMTP settings — only SystemAdmin (platform operator) can change them; smtpPass is
|
|
128
|
+
// encrypted and readable only by SystemAdmin.
|
|
129
129
|
smtpHost: createTenantConfig("text", { write: access.systemAdmin, read: access.admin }),
|
|
130
130
|
smtpPass: createTenantConfig("text", {
|
|
131
131
|
write: access.systemAdmin,
|
|
@@ -133,8 +133,8 @@ export function createTenantFeature(options?: TenantFeatureOptions): FeatureDefi
|
|
|
133
133
|
encrypted: true,
|
|
134
134
|
}),
|
|
135
135
|
|
|
136
|
-
// System
|
|
137
|
-
//
|
|
136
|
+
// System settings — changeable only programmatically by SYSTEM_USER;
|
|
137
|
+
// tenant admins see them as read-only.
|
|
138
138
|
priceModel: createSystemConfig("select", {
|
|
139
139
|
default: "basic",
|
|
140
140
|
options: ["basic", "pro", "enterprise"],
|
|
@@ -32,7 +32,7 @@ async function loadMemberUserIds(db: TenantDb, tenantId: string): Promise<readon
|
|
|
32
32
|
return [...new Set(memberships.map((row) => String(row["userId"])))].sort(compareIds);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
// Label source behind every `user:user` reference column
|
|
35
|
+
// Label source behind every `user:user` reference column. The
|
|
36
36
|
// entity-convention lookup, user:query:user:list, is a SystemAdmin
|
|
37
37
|
// cross-tenant roster, so a TenantAdmin got a 403 and every actor cell fell
|
|
38
38
|
// back to the raw UUID. Deliberately narrower than tenant:query:members:
|
|
@@ -50,6 +50,8 @@ export const memberDirectoryQuery = definePagedQueryHandler({
|
|
|
50
50
|
limit: z.number().int().min(1).max(MAX_LIST_LIMIT).default(MAX_LIST_LIMIT),
|
|
51
51
|
// Sent by the reference combobox while the user types.
|
|
52
52
|
search: z.string().trim().min(1).optional(),
|
|
53
|
+
// Resolves exactly these users; callers that know their ids must not depend on the cap.
|
|
54
|
+
ids: z.array(z.string().min(1)).max(MAX_LIST_LIMIT).optional(),
|
|
53
55
|
}),
|
|
54
56
|
access: { roles: access.admin },
|
|
55
57
|
description:
|
|
@@ -62,7 +64,8 @@ export const memberDirectoryQuery = definePagedQueryHandler({
|
|
|
62
64
|
"tenant:query:member-directory requires ctx.systemDb — is r.systemScope() still set on the tenant feature?",
|
|
63
65
|
});
|
|
64
66
|
}
|
|
65
|
-
const { limit, search } = query.payload;
|
|
67
|
+
const { limit, search, ids } = query.payload;
|
|
68
|
+
if (ids?.length === 0) return { rows: [], nextCursor: null };
|
|
66
69
|
// Without a search the first `limit` rows are enough; with one, every
|
|
67
70
|
// candidate must be decrypted before the limit can apply.
|
|
68
71
|
const scanLimit = search === undefined ? limit : SEARCH_SCAN_CAP;
|
|
@@ -71,13 +74,16 @@ export const memberDirectoryQuery = definePagedQueryHandler({
|
|
|
71
74
|
const db = ctx.systemDb.acknowledgeCrossTenant(
|
|
72
75
|
"SystemAdmin reference labels span every tenant, as user:query:user:list did",
|
|
73
76
|
);
|
|
74
|
-
users = await selectMany(db, userTable, undefined, {
|
|
77
|
+
users = await selectMany(db, userTable, ids === undefined ? undefined : { id: ids }, {
|
|
75
78
|
limit: scanLimit,
|
|
76
79
|
orderBy: { col: "id", direction: "asc" },
|
|
77
80
|
});
|
|
78
81
|
} else {
|
|
79
82
|
const db = ctx.systemDb.assertTenantMatch(query.user.tenantId);
|
|
80
|
-
const
|
|
83
|
+
const requestedIds = ids === undefined ? undefined : new Set(ids);
|
|
84
|
+
const userIds = (await loadMemberUserIds(db, query.user.tenantId))
|
|
85
|
+
.filter((id) => requestedIds === undefined || requestedIds.has(id))
|
|
86
|
+
.slice(0, scanLimit);
|
|
81
87
|
users =
|
|
82
88
|
userIds.length > 0
|
|
83
89
|
? await selectMany(
|
|
@@ -20,7 +20,7 @@ export const membersQuery = defineQueryHandler({
|
|
|
20
20
|
name: "members",
|
|
21
21
|
schema: z.object({
|
|
22
22
|
// Optional single-user filter — audit detail (and similar) only need one
|
|
23
|
-
// member's display name, not the full decrypted roster
|
|
23
|
+
// member's display name, not the full decrypted roster.
|
|
24
24
|
userId: z.string().min(1).optional(),
|
|
25
25
|
}),
|
|
26
26
|
access: { roles: access.admin },
|
|
@@ -31,7 +31,7 @@ export const membershipsQuery = defineQueryHandler({
|
|
|
31
31
|
// tenantName/tenantKey make memberships distinguishable in the UI
|
|
32
32
|
// (otherwise just the UUID prefix — seed tenants with a 00000000-…
|
|
33
33
|
// prefix would be indistinguishable). A single IN-batch over all
|
|
34
|
-
// tenantIds instead of fetchOne per membership
|
|
34
|
+
// tenantIds instead of fetchOne per membership.
|
|
35
35
|
type TenantRow = { id: unknown; name?: unknown; key?: unknown; isEnabled?: unknown };
|
|
36
36
|
const tenants = await decryptTenantNames(
|
|
37
37
|
await selectMany<TenantRow>(db, tenantTable, {
|
|
@@ -58,7 +58,7 @@ function compareTeamRows(a: TeamRow, b: TeamRow, field: SortField, dir: "asc" |
|
|
|
58
58
|
return av.localeCompare(bv) * sign;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
// User-selected facet filters (payload.filters
|
|
61
|
+
// User-selected facet filters (payload.filters) — `status` is the
|
|
62
62
|
// only filterable field here: it's synthesized from which table a row came
|
|
63
63
|
// from, not a stored column, so there is nothing else meaningful to filter
|
|
64
64
|
// on server-side yet. `filter` (singular, screen-level static filter) is
|
|
@@ -10,7 +10,7 @@ import { decryptTenantNames, takeTenantsMatchingDecryptedName } from "../decrypt
|
|
|
10
10
|
import { tenantTable } from "../schema/tenant.ts";
|
|
11
11
|
import { isSystemAdmin } from "./is-system-admin.ts";
|
|
12
12
|
|
|
13
|
-
// Label source
|
|
13
|
+
// Label source for every `tenant:tenant` reference column. The
|
|
14
14
|
// entity-convention lookup, tenant:query:tenant:list, is a SystemAdmin-only
|
|
15
15
|
// entity-list handler, so a TenantAdmin got a 403 and every tenant cell fell
|
|
16
16
|
// back to the raw UUID. A SystemAdmin keeps the global reach tenant:list gave
|
|
@@ -27,10 +27,12 @@ export const tenantDirectoryQuery = definePagedQueryHandler({
|
|
|
27
27
|
limit: z.number().int().min(1).max(MAX_LIST_LIMIT).default(MAX_LIST_LIMIT),
|
|
28
28
|
// Sent by the reference combobox while the user types.
|
|
29
29
|
search: z.string().trim().min(1).optional(),
|
|
30
|
+
// Resolves exactly these tenants; callers that know their ids must not depend on the cap.
|
|
31
|
+
ids: z.array(z.string().min(1)).max(MAX_LIST_LIMIT).optional(),
|
|
30
32
|
}),
|
|
31
33
|
access: { roles: access.admin },
|
|
32
34
|
description:
|
|
33
|
-
"Lists tenants as id/label pairs for resolving tenant references to display names: the caller's own tenant for an admin, every tenant for a SystemAdmin.",
|
|
35
|
+
"Lists tenants as id/label pairs for resolving tenant references to display names: the caller's own tenant for an admin, every tenant for a SystemAdmin. A search returns the first `limit` matches in tenant-key order (sorted by label afterwards), not the alphabetically best matches.",
|
|
34
36
|
agent: { expose: false },
|
|
35
37
|
handler: async (query, ctx) => {
|
|
36
38
|
if (!ctx.systemDb) {
|
|
@@ -39,14 +41,15 @@ export const tenantDirectoryQuery = definePagedQueryHandler({
|
|
|
39
41
|
"tenant:query:tenant-directory requires ctx.systemDb — is r.systemScope() still set on the tenant feature?",
|
|
40
42
|
});
|
|
41
43
|
}
|
|
42
|
-
const { limit, search } = query.payload;
|
|
44
|
+
const { limit, search, ids } = query.payload;
|
|
45
|
+
if (ids?.length === 0) return { rows: [], nextCursor: null };
|
|
43
46
|
const scanLimit = search === undefined ? limit : SEARCH_SCAN_CAP;
|
|
44
47
|
let tenants: readonly { id: unknown; name?: unknown }[];
|
|
45
48
|
if (isSystemAdmin(query.user)) {
|
|
46
49
|
const db = ctx.systemDb.acknowledgeCrossTenant(
|
|
47
50
|
"SystemAdmin reference labels span every tenant, as tenant:query:tenant:list did",
|
|
48
51
|
);
|
|
49
|
-
tenants = await selectMany(db, tenantTable, undefined, {
|
|
52
|
+
tenants = await selectMany(db, tenantTable, ids === undefined ? undefined : { id: ids }, {
|
|
50
53
|
limit: scanLimit,
|
|
51
54
|
orderBy: [
|
|
52
55
|
{ col: "key", direction: "asc" },
|
|
@@ -56,7 +59,7 @@ export const tenantDirectoryQuery = definePagedQueryHandler({
|
|
|
56
59
|
} else {
|
|
57
60
|
const db = ctx.systemDb.assertTenantMatch(query.user.tenantId);
|
|
58
61
|
const row = await fetchOne(db, tenantTable, { id: query.user.tenantId });
|
|
59
|
-
tenants = row ? [row] : [];
|
|
62
|
+
tenants = row && (ids === undefined || ids.includes(query.user.tenantId)) ? [row] : [];
|
|
60
63
|
}
|
|
61
64
|
// name is ciphertext at rest, so the SQL page is keyed by the plaintext
|
|
62
65
|
// `key`; label order and search happen in memory after decrypting.
|
|
@@ -1,26 +1,25 @@
|
|
|
1
|
-
// Tenant-
|
|
1
|
+
// Tenant invitations are pre-membership records using a magic-link token flow.
|
|
2
2
|
//
|
|
3
3
|
// Lifecycle:
|
|
4
|
-
// 1.
|
|
5
|
-
//
|
|
6
|
-
// 2.
|
|
7
|
-
// 3.
|
|
8
|
-
// a)
|
|
9
|
-
// b) Anonymous +
|
|
10
|
-
// c) Anonymous +
|
|
11
|
-
// 4.
|
|
12
|
-
// 5.
|
|
13
|
-
// 6.
|
|
14
|
-
// (
|
|
4
|
+
// 1. An admin invites an email → a DB row is created with status="pending",
|
|
5
|
+
// and a random token is stored in Redis (signup-style bidirectional flow).
|
|
6
|
+
// 2. An email containing the activation URL is sent to the invitee.
|
|
7
|
+
// 3. Clicking the link follows one of three branches:
|
|
8
|
+
// a) Logged in + email matches the session user → membership is added
|
|
9
|
+
// b) Anonymous + email exists in users → login → automatic acceptance
|
|
10
|
+
// c) Anonymous + new email → set a password → user and membership are created
|
|
11
|
+
// 4. On success: status="accepted", and the Redis token is deleted (single-use).
|
|
12
|
+
// 5. When cancelled by an admin: status="cancelled", and the Redis token is deleted.
|
|
13
|
+
// 6. When the TTL expires: Redis removes the token, while the DB row remains
|
|
14
|
+
// status="pending" (a cleanup job marks it as "expired" separately).
|
|
15
15
|
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
// invalid-token.
|
|
16
|
+
// Redis-TTL is the single source of truth for expiry. DB-row.expiresAt is only
|
|
17
|
+
// for UI display ("expires in 6 days"). On lookup, a pending DB row without
|
|
18
|
+
// a Redis token is effectively expired, so acceptance fails with invalid-token.
|
|
20
19
|
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
// (
|
|
20
|
+
// Idempotency: a second invite for the same (tenantId, email) while pending
|
|
21
|
+
// reuses the existing row, refreshes the Redis token, and sends the email
|
|
22
|
+
// (analogous to signup resend).
|
|
24
23
|
|
|
25
24
|
import { buildEntityTable } from "@cosmicdrift/kumiko-framework/db";
|
|
26
25
|
import {
|
|
@@ -34,9 +33,9 @@ import {
|
|
|
34
33
|
// kumiko-lint-ignore cross-feature-import global-role options are owned by the user feature
|
|
35
34
|
import { GLOBAL_ROLE_OPTIONS } from "../user/web/constants.ts";
|
|
36
35
|
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
//
|
|
36
|
+
// The status constant object prevents handler code from using magic strings.
|
|
37
|
+
// If a value is renamed (for example, "cancelled" → "revoked"), every caller
|
|
38
|
+
// fails at once instead of having stale values scattered across five locations.
|
|
40
39
|
export const INVITATION_STATUS = {
|
|
41
40
|
pending: "pending",
|
|
42
41
|
accepted: "accepted",
|
|
@@ -45,11 +44,10 @@ export const INVITATION_STATUS = {
|
|
|
45
44
|
} as const;
|
|
46
45
|
export type InvitationStatus = (typeof INVITATION_STATUS)[keyof typeof INVITATION_STATUS];
|
|
47
46
|
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
// Refactoring der Object-Keys.
|
|
47
|
+
// The order MUST be bit-for-bit identical to the database migration. Object.values
|
|
48
|
+
// preserves insertion order (stable for string keys under the JS spec). Reordering
|
|
49
|
+
// INVITATION_STATUS generates a new drizzle-kit migration. The hardcoded tuple
|
|
50
|
+
// also guards against accidental refactoring of the object keys.
|
|
53
51
|
export const INVITATION_STATUSES = [
|
|
54
52
|
INVITATION_STATUS.pending,
|
|
55
53
|
INVITATION_STATUS.accepted,
|
|
@@ -60,11 +58,11 @@ export const INVITATION_STATUSES = [
|
|
|
60
58
|
export const tenantInvitationEntity = createEntity({
|
|
61
59
|
table: "read_tenant_invitations",
|
|
62
60
|
fields: {
|
|
63
|
-
//
|
|
64
|
-
//
|
|
61
|
+
// The invited email is normalized case-insensitively on insert.
|
|
62
|
+
// It remains PII until acceptance; afterward, the user owns the email in users.
|
|
65
63
|
email: createTextField({ required: true, maxLength: 320, personal: "self", find: "exact" }),
|
|
66
|
-
//
|
|
67
|
-
//
|
|
64
|
+
// The membership role granted to the user on acceptance. The handler defaults
|
|
65
|
+
// to "Admin" (a co-admin pattern for small teams).
|
|
68
66
|
role: createTextField({
|
|
69
67
|
required: true,
|
|
70
68
|
maxLength: 50,
|
|
@@ -85,11 +83,11 @@ export const tenantInvitationEntity = createEntity({
|
|
|
85
83
|
required: true,
|
|
86
84
|
default: "pending",
|
|
87
85
|
}),
|
|
88
|
-
//
|
|
86
|
+
// ID of the inviting admin, retained for the audit trail ("who invited").
|
|
89
87
|
// Self-referencing ownerField: the field's own value IS the owner userId.
|
|
90
|
-
// lookupable: the delete
|
|
91
|
-
//
|
|
92
|
-
//
|
|
88
|
+
// lookupable: the delete hook filters "invitations sent by this user"
|
|
89
|
+
// through the generated blind-index column instead of decrypting and scanning
|
|
90
|
+
// the entire tenant (see user-data-rights-defaults' invitation hook).
|
|
93
91
|
invitedBy: createTextField({
|
|
94
92
|
required: true,
|
|
95
93
|
personal: { of: "invitedBy" },
|
|
@@ -103,11 +101,10 @@ export const tenantInvitationEntity = createEntity({
|
|
|
103
101
|
// UI-Anzeige — Wahrheit liegt in Redis-TTL.
|
|
104
102
|
expiresAt: createTimestampField({ required: true }),
|
|
105
103
|
},
|
|
106
|
-
//
|
|
107
|
-
//
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
-
// im handler trivial.
|
|
104
|
+
// One invitation row per (tenantId, email). On re-invite after cancellation or
|
|
105
|
+
// acceptance, the existing row is updated: status pending → cancelled → pending,
|
|
106
|
+
// and expiresAt is refreshed. This prevents duplicate tokens and makes resend
|
|
107
|
+
// idempotency trivial in the handler.
|
|
111
108
|
indexes: [
|
|
112
109
|
{
|
|
113
110
|
unique: true,
|
|
@@ -12,9 +12,9 @@ import { createEntity, createTextField } from "@cosmicdrift/kumiko-framework/eng
|
|
|
12
12
|
// the old serial-id design and keeps duplicate-write protection at the
|
|
13
13
|
// database level independent of the handler lookup.
|
|
14
14
|
//
|
|
15
|
-
// Single
|
|
16
|
-
//
|
|
17
|
-
// unique
|
|
15
|
+
// Single source of truth: `tenantMembershipEntity`. The database table is
|
|
16
|
+
// derived from the EntityDefinition through buildEntityTable, and the
|
|
17
|
+
// unique index is declared via entity.indexes.
|
|
18
18
|
export const tenantMembershipEntity = createEntity({
|
|
19
19
|
table: "read_tenant_memberships",
|
|
20
20
|
fields: {
|
|
@@ -21,9 +21,9 @@ export const tenantEntity = createEntity({
|
|
|
21
21
|
description:
|
|
22
22
|
"A tenant, the isolated workspace every other record belongs to, holding its key and display name, whether it is enabled, and its destruction-lifecycle state.",
|
|
23
23
|
table: "read_tenants",
|
|
24
|
-
// tenant.id
|
|
25
|
-
//
|
|
26
|
-
//
|
|
24
|
+
// `tenant.id` is the `tenantId` value referenced by every other table as a foreign key.
|
|
25
|
+
// Every `tenantId` column is UUID, so `tenant.id` must also be UUID; otherwise
|
|
26
|
+
// the tenant lookup never finds a match. The default is `gen_random_uuid()`.
|
|
27
27
|
fields: {
|
|
28
28
|
key: createTextField({
|
|
29
29
|
required: true,
|
|
@@ -59,12 +59,10 @@ export const tenantEntity = createEntity({
|
|
|
59
59
|
destroyStartedAt: createTimestampField({}),
|
|
60
60
|
destroyedAt: createTimestampField({}),
|
|
61
61
|
},
|
|
62
|
-
// tenant.key
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
// Slug claimen, beide commits durch, der dritte User landet auf einem
|
|
67
|
-
// shared admin-URL-prefix.
|
|
62
|
+
// `tenant.key` appears in admin URLs (`admin.<host>/<key>/...`) and must be unique.
|
|
63
|
+
// Without a unique constraint, concurrent self-signup confirmation could pass
|
|
64
|
+
// the `generateUniqueName` `isAvailable` check before either insert, allowing
|
|
65
|
+
// two tabs to claim the same slug and causing users to share an admin URL prefix.
|
|
68
66
|
indexes: [{ unique: true, columns: ["key"] }],
|
|
69
67
|
});
|
|
70
68
|
|
|
@@ -165,7 +165,7 @@ export function createMembersScreen(options?: {
|
|
|
165
165
|
// feature.ts when `TenantFeatureOptions.inviteScreen` is set — see
|
|
166
166
|
// createMembersScreen's doc comment above for why.
|
|
167
167
|
export function createInviteCreateScreen(assignableAppRoles: AssignableAppRoles = new Map()) {
|
|
168
|
-
// Admin sees this screen too, so only app roles Admin may grant are offered
|
|
168
|
+
// Admin sees this screen too, so only app roles Admin may grant are offered.
|
|
169
169
|
const appRoleOptions = [...assignableAppRoles]
|
|
170
170
|
.filter(([, assignableFrom]) => isAssignableByRole(assignableFrom, "Admin"))
|
|
171
171
|
.map(([role]) => role);
|
|
@@ -76,12 +76,13 @@ export type SeedTenantMembershipOptions = {
|
|
|
76
76
|
};
|
|
77
77
|
|
|
78
78
|
export type SeedTenantOptions = {
|
|
79
|
-
/**
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
79
|
+
/**
|
|
80
|
+
* Stable UUID required for fixtures so the FE/BE can hardcode the same ID. The sample switcher
|
|
81
|
+
* displays the tenant by name, while tests verify memberships against this exact ID; without it,
|
|
82
|
+
* callers would need an extra lookup by key.
|
|
83
|
+
*/
|
|
83
84
|
readonly id: TenantId;
|
|
84
|
-
/** URL
|
|
85
|
+
/** URL/slug form (for example, "dev" or "acme"). Indexed unique in the database. */
|
|
85
86
|
readonly key: string;
|
|
86
87
|
/** Human-readable label (im Switcher angezeigt). */
|
|
87
88
|
readonly name: string;
|
|
@@ -89,7 +90,7 @@ export type SeedTenantOptions = {
|
|
|
89
90
|
};
|
|
90
91
|
|
|
91
92
|
// seedTenant runs through the raw event-store executor, which fires no
|
|
92
|
-
// postSave hooks
|
|
93
|
+
// postSave hooks — feature-registered entity hooks on "tenant"
|
|
93
94
|
// (e.g. tier-engine's auto-default-tier, an app's auto-default-compliance)
|
|
94
95
|
// silently never run for tenants created this way. Pass `hooks` to fire
|
|
95
96
|
// them explicitly, same lookup as the dispatcher (registry.getEntityPostSaveHooks
|
|
@@ -138,14 +139,14 @@ function buildSeedHookNotify(
|
|
|
138
139
|
// registered entity/handler hooks fire (search-index/SSE system hooks are
|
|
139
140
|
// wired at server-boot and out of reach here).
|
|
140
141
|
//
|
|
141
|
-
// Tenant re-scope
|
|
142
|
+
// Tenant re-scope: when `targetTenantId` is set we rebuild the
|
|
142
143
|
// tenant-bound pieces of the context (`_tenantId`, `db`, `notify`,
|
|
143
144
|
// `hasFeature`, `user.tenantId`) — a shallow `{ ...ctx, _tenantId }` left
|
|
144
145
|
// closures over the caller's tenant (self-signup is anonymous/system).
|
|
145
146
|
// `query`/`write` bridges still share the caller's identity; hooks that
|
|
146
147
|
// need a full identity switch use `writeAs`/`queryAs`.
|
|
147
148
|
//
|
|
148
|
-
// afterCommit
|
|
149
|
+
// afterCommit: when `hooks.context.scheduleAfterCommit` is present
|
|
149
150
|
// (HandlerContext from a live write), afterCommit hooks are queued onto the
|
|
150
151
|
// dispatcher's sink and flush post-commit. Without a sink (fixture / plain
|
|
151
152
|
// Connection) they still fire immediately — there is no outer TX to wait for.
|
|
@@ -255,20 +256,20 @@ export async function seedTenant(
|
|
|
255
256
|
hooks?: SeedTenantHooks,
|
|
256
257
|
): Promise<{ id: TenantId }> {
|
|
257
258
|
const by = options.by ?? TestUsers.systemAdmin;
|
|
258
|
-
// executor.create
|
|
259
|
-
//
|
|
260
|
-
//
|
|
261
|
-
//
|
|
262
|
-
// seedTenantMembership nötig.
|
|
259
|
+
// executor.create expects a TenantDb with an .insert()-API, not the raw
|
|
260
|
+
// DbConnection. Although the tenant aggregate is not tenant-scoped, the
|
|
261
|
+
// wrapper is required by the runtime API. by.tenantId is sufficient; unlike
|
|
262
|
+
// seedTenantMembership, no override semantics are needed.
|
|
263
263
|
const tdb = createTenantDb({ db, tenantId: by.tenantId, mode: "system" });
|
|
264
264
|
|
|
265
265
|
const existing = await fetchOne(db, tenantTable, { id: options.id });
|
|
266
266
|
if (existing) return { id: options.id };
|
|
267
267
|
|
|
268
|
-
//
|
|
269
|
-
// (
|
|
270
|
-
//
|
|
271
|
-
//
|
|
268
|
+
// Idempotency: the aggregate may exist in the event store without a
|
|
269
|
+
// projection row (projection drift after a rebuild, manual DELETE, or async
|
|
270
|
+
// lag). If the stream version is > 0, skip create() to avoid
|
|
271
|
+
// version_conflict. Return the ID; the next dispatcher cycle can rebuild the
|
|
272
|
+
// projection.
|
|
272
273
|
const streamVersion = await getUnscopedAggregateStreamMaxVersion(db, options.id);
|
|
273
274
|
if (streamVersion > 0) return { id: options.id };
|
|
274
275
|
|
|
@@ -311,7 +312,7 @@ export async function seedTenantMembership(
|
|
|
311
312
|
db: DbRunner,
|
|
312
313
|
options: SeedTenantMembershipOptions,
|
|
313
314
|
// Optional, append-only — same rationale as seedTenant's hooks param
|
|
314
|
-
//
|
|
315
|
+
// fires tenantMembership's postSave hooks (e.g. a Welcome-
|
|
315
316
|
// notification or default-notification-preferences hook keyed off
|
|
316
317
|
// `allOf: "tenantMembership"`) for fixtures/self-signup that opt in.
|
|
317
318
|
// Omit to keep today's hook-less behavior.
|