@cosmicdrift/kumiko-samples 0.385.0 → 0.387.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 +2 -2
- package/packages/bundled-features/src/agent-tools/tool-catalog.ts +1 -1
- package/packages/bundled-features/src/agent-tools/tool-dispatch.ts +0 -2
- 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/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 +3 -3
- 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-verify-screen.tsx +6 -6
- package/packages/bundled-features/src/billing-foundation/aggregate-id.ts +10 -11
- package/packages/bundled-features/src/billing-foundation/entities.ts +27 -27
- package/packages/bundled-features/src/billing-foundation/events.ts +22 -21
- package/packages/bundled-features/src/billing-foundation/feature.ts +42 -43
- package/packages/bundled-features/src/billing-foundation/get-subscription-for-tenant.ts +3 -5
- package/packages/bundled-features/src/billing-foundation/handlers/create-checkout-session.write.ts +18 -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/process-event.write.ts +20 -20
- 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 +64 -65
- package/packages/bundled-features/src/billing-foundation/web/billing-plans-panel.tsx +4 -4
- 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/constants.ts +11 -12
- package/packages/bundled-features/src/cap-counter/enforce-cap.ts +64 -67
- 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 +1 -1
- 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/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/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/resolver.ts +4 -4
- package/packages/bundled-features/src/config/table.ts +10 -10
- package/packages/bundled-features/src/config/write-helpers.ts +1 -1
- package/packages/bundled-features/src/crypto-shredding/handlers/forget-subject.write.ts +13 -12
- 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/feature.ts +3 -3
- package/packages/bundled-features/src/delivery/handlers/log.query.ts +1 -1
- package/packages/bundled-features/src/delivery/tables.ts +9 -8
- package/packages/bundled-features/src/delivery/unsubscribe.ts +4 -4
- 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-provider-inmemory/feature.ts +16 -16
- 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/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/db/queries/cleanup.ts +1 -1
- package/packages/bundled-features/src/form-draft/db/queries/owned-file-refs.ts +1 -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/inbound-mail-foundation/aggregate-id.ts +19 -19
- 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 +11 -11
- 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/tenant-destroy-hook.ts +14 -16
- package/packages/bundled-features/src/inbound-mail-foundation/types.ts +66 -67
- package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +69 -68
- 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/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 +6 -7
- 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/job-instant.ts +1 -1
- package/packages/bundled-features/src/jobs/job-run-logger.ts +14 -15
- 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/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/feature.ts +26 -27
- 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 +5 -5
- 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/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 +9 -9
- 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 +1 -1
- package/packages/bundled-features/src/shared/encrypt-for-direct-write.ts +1 -1
- 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/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/constants.ts +4 -6
- package/packages/bundled-features/src/subscription-stripe/feature.ts +44 -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 +2 -2
- 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 +10 -10
- package/packages/bundled-features/src/template-resolver/handlers/find-by-id.query.ts +5 -5
- package/packages/bundled-features/src/template-resolver/handlers/list.query.ts +1 -1
- 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/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/seeding.ts +4 -4
- package/packages/bundled-features/src/template-resolver/table.ts +13 -14
- package/packages/bundled-features/src/template-resolver/web/client-plugin.tsx +2 -2
- package/packages/bundled-features/src/tenant/feature.ts +7 -7
- package/packages/bundled-features/src/tenant/handlers/member-directory.query.ts +1 -1
- 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 +1 -1
- 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/feature.ts +1 -1
- package/packages/bundled-features/src/tenant-lifecycle/run-tenant-destroy.ts +2 -2
- 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/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 +8 -8
- 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/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 +166 -276
- package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +85 -107
- 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/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
|
@@ -7,38 +7,40 @@ import { countTenantFieldDefinitions } from "../lib/quota.ts";
|
|
|
7
7
|
import { type DefineFieldPayload, defineFieldPayloadSchema } from "../schemas.ts";
|
|
8
8
|
import { DEFAULT_FIELD_DEFINITION_WRITE_ROLES } from "../web/constants.ts";
|
|
9
9
|
|
|
10
|
-
// define-tenant-field — TenantAdmin
|
|
11
|
-
//
|
|
12
|
-
//
|
|
10
|
+
// define-tenant-field — TenantAdmin defines a custom-field definition
|
|
11
|
+
// for its own tenant. tenantId is derived automatically from
|
|
12
|
+
// event.user.tenantId (NOT settable by the caller — prevents cross-tenant
|
|
13
|
+
// mutation).
|
|
13
14
|
//
|
|
14
|
-
// **Same-scope-conflict**
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
15
|
+
// **Same-scope-conflict** is naturally enforced by the
|
|
16
|
+
// aggregate-version-conflict: the deterministic aggregate-id from
|
|
17
|
+
// uuidv5(tenant, entity, fieldKey) makes a second Create for the same
|
|
18
|
+
// definition a version_conflict. The dispatcher returns 409, providing a
|
|
19
|
+
// clean idempotency guarantee without an extra DB round trip.
|
|
18
20
|
//
|
|
19
|
-
// **Cross-scope-conflict** (tenant
|
|
20
|
-
// system
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
21
|
+
// **Cross-scope-conflict** (a tenant attempts to define a fieldKey that
|
|
22
|
+
// already exists in the system scope) is NOT enforced here — the aggregate
|
|
23
|
+
// IDs differ (different tenantIds in uuidv5), so both writes proceed.
|
|
24
|
+
// Resolution at read time shows the system-scope value. A future version
|
|
25
|
+
// could introduce an r.systemScope sub-handler to reject cross-scope-conflict
|
|
26
|
+
// at write time.
|
|
25
27
|
//
|
|
26
|
-
// **Quota
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
//
|
|
28
|
+
// **Quota**: optional `fieldDefinitionLimitPerTenant` gate. When the tenant
|
|
29
|
+
// already has ≥ limit definitions, the handler rejects with `unprocessable`
|
|
30
|
+
// and reason `cap_exceeded` BEFORE attempting the insert. The factory below
|
|
31
|
+
// closes over the limit; the legacy const-export preserves behavior for
|
|
32
|
+
// callers that did not opt into a limit.
|
|
31
33
|
//
|
|
32
|
-
// Soft cap, not a hard guarantee:
|
|
34
|
+
// Soft cap, not a hard guarantee: count-then-insert is not serialized, so
|
|
33
35
|
// N concurrent defines with distinct fieldKeys can each read `current < limit`
|
|
34
|
-
// and overshoot by up to N.
|
|
35
|
-
// low-frequency action and the limit is not wired to
|
|
36
|
-
// If an exact cap is ever needed, serialize via
|
|
37
|
-
// constraint at the insert.
|
|
36
|
+
// and overshoot by up to N. This is acceptable because defining fields is an
|
|
37
|
+
// admin-only, low-frequency action and the limit is not wired to
|
|
38
|
+
// billing/tier enforcement. If an exact cap is ever needed, serialize via
|
|
39
|
+
// advisory lock or add a count constraint at the insert.
|
|
38
40
|
export interface DefineTenantFieldOptions {
|
|
39
41
|
/** Soft cap — `>= limit` definitions per tenant rejects further defines (see header: concurrent defines may overshoot). */
|
|
40
42
|
readonly fieldDefinitionLimitPerTenant?: number;
|
|
41
|
-
/** Access roles for this handler. Default ["TenantAdmin"]
|
|
43
|
+
/** Access roles for this handler. Default ["TenantAdmin"] — apps with
|
|
42
44
|
* their own role vocabulary pass this via createCustomFieldsFeature({
|
|
43
45
|
* fieldDefinitionWriteRoles }), which threads the same roles into
|
|
44
46
|
* update-/delete-tenant-field too (the definition-CRUD triad shares one gate). */
|
|
@@ -66,7 +68,7 @@ export function createDefineTenantFieldHandler(
|
|
|
66
68
|
const payload = event.payload as DefineFieldPayload; // @cast-boundary engine-payload
|
|
67
69
|
const tenantId = event.user.tenantId;
|
|
68
70
|
|
|
69
|
-
// TenantAdmin
|
|
71
|
+
// TenantAdmin MUST NOT write to the system scope — strict guard.
|
|
70
72
|
if (isSystemTenant(tenantId)) {
|
|
71
73
|
throw new Error(
|
|
72
74
|
"define-tenant-field: tenantId is SYSTEM_TENANT_ID — use define-system-field for system-scope definitions",
|
|
@@ -101,5 +103,5 @@ export function createDefineTenantFieldHandler(
|
|
|
101
103
|
}
|
|
102
104
|
|
|
103
105
|
// Backwards-compat: existing imports of `defineTenantFieldHandler` keep
|
|
104
|
-
// working — the handler has no quota, identical to
|
|
106
|
+
// working — the handler has no quota, identical to behavior before the quota.
|
|
105
107
|
export const defineTenantFieldHandler: WriteHandlerDef = createDefineTenantFieldHandler();
|
|
@@ -6,11 +6,10 @@ import { createCustomFieldsFeature } from "../feature.ts";
|
|
|
6
6
|
import { type DeleteFieldPayload, deleteFieldPayloadSchema } from "../schemas.ts";
|
|
7
7
|
import { FIELD_DEFINITION_AGGREGATE_TYPE } from "../web/constants.ts";
|
|
8
8
|
|
|
9
|
-
// delete-system-field — SystemAdmin
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
// Events bleiben für Audit.
|
|
9
|
+
// delete-system-field — SystemAdmin deletes a system-wide field definition.
|
|
10
|
+
// Tenants can no longer set new values for it, but existing values remain in
|
|
11
|
+
// read_<entity>.customFields jsonb until host-entity MSPs remove them in
|
|
12
|
+
// response to the customFieldDefinition.deleted event. Events remain for audit.
|
|
14
13
|
export const deleteSystemFieldHandler: WriteHandlerDef = {
|
|
15
14
|
name: "delete-system-field",
|
|
16
15
|
schema: deleteFieldPayloadSchema,
|
|
@@ -32,8 +31,8 @@ export const deleteSystemFieldHandler: WriteHandlerDef = {
|
|
|
32
31
|
streamTenantId,
|
|
33
32
|
});
|
|
34
33
|
|
|
35
|
-
// Cascade-cleanup
|
|
36
|
-
//
|
|
34
|
+
// Cascade-cleanup event — host-entity MSPs remove orphaned values from their
|
|
35
|
+
// customFields jsonb in the same transaction for atomicity.
|
|
37
36
|
if (result.isSuccess) {
|
|
38
37
|
await ctx.unsafeAppendEvent({
|
|
39
38
|
aggregateId,
|
|
@@ -8,18 +8,17 @@ import {
|
|
|
8
8
|
FIELD_DEFINITION_AGGREGATE_TYPE,
|
|
9
9
|
} from "../web/constants.ts";
|
|
10
10
|
|
|
11
|
-
// delete-tenant-field — TenantAdmin
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
// kümmern wir uns nur um die Definition selbst.
|
|
11
|
+
// delete-tenant-field — TenantAdmin deletes their own field definition.
|
|
12
|
+
// Events remain in the event store for the audit trail, while the read-projection
|
|
13
|
+
// row is removed. The cleanup pipeline (`customFieldDefinition.deleted`-Event → MSP
|
|
14
|
+
// removes values from read_<entity>.customFields jsonb) is wired separately; this
|
|
15
|
+
// handler only manages the definition itself.
|
|
17
16
|
//
|
|
18
|
-
// **Idempotency:**
|
|
19
|
-
// (executor.delete returns failure, dispatcher 404/422).
|
|
20
|
-
// found"
|
|
17
|
+
// **Idempotency:** Deleting a non-existent definition results in version_conflict
|
|
18
|
+
// (executor.delete returns failure, dispatcher 404/422). The caller sees "not
|
|
19
|
+
// found" rather than an exception.
|
|
21
20
|
export interface DeleteTenantFieldOptions {
|
|
22
|
-
/** Access roles for this handler. Default ["TenantAdmin"]
|
|
21
|
+
/** Access roles for this handler. Default ["TenantAdmin"] — see
|
|
23
22
|
* DefineTenantFieldOptions.roles, the definition-CRUD triad shares one gate. */
|
|
24
23
|
readonly roles?: readonly string[];
|
|
25
24
|
}
|
|
@@ -52,9 +51,9 @@ export function createDeleteTenantFieldHandler(
|
|
|
52
51
|
|
|
53
52
|
const result = await fieldDefinitionExecutor.delete({ id: aggregateId }, event.user, ctx.db);
|
|
54
53
|
|
|
55
|
-
// Emit cascade-cleanup
|
|
56
|
-
//
|
|
57
|
-
//
|
|
54
|
+
// Emit the cascade-cleanup event after a successful delete. Host-entity MSPs
|
|
55
|
+
// registered via wireCustomFieldsFor consume it and remove orphaned values
|
|
56
|
+
// from their customFields jsonb. The same transaction makes cleanup atomic.
|
|
58
57
|
if (result.isSuccess) {
|
|
59
58
|
await ctx.unsafeAppendEvent({
|
|
60
59
|
aggregateId,
|
|
@@ -25,30 +25,27 @@ export type SetCustomFieldPayload = z.infer<typeof setCustomFieldPayloadSchema>;
|
|
|
25
25
|
const SET_CUSTOM_FIELD_REASON =
|
|
26
26
|
"reads custom field definitions with an explicit tenant_id = caller tenant via raw SQL with read retry";
|
|
27
27
|
|
|
28
|
-
// set-custom-field —
|
|
28
|
+
// set-custom-field — writes a custom-field value to a host entity.
|
|
29
29
|
//
|
|
30
|
-
//
|
|
30
|
+
// Emits a customField.set event on the host-aggregate
|
|
31
31
|
// stream (aggregateType = host-entity-name, aggregateId = host-entity-id).
|
|
32
|
-
// Last-
|
|
33
|
-
// concurrent writes
|
|
34
|
-
// Concurrency-Tabelle).
|
|
32
|
+
// Last-wins semantics: customField.set is appended WITHOUT expectedVersion,
|
|
33
|
+
// so concurrent writes to the same field both succeed.
|
|
35
34
|
//
|
|
36
|
-
// **Write
|
|
37
|
-
// 1. Definition
|
|
38
|
-
// 2. field-access
|
|
39
|
-
// 403/422. Handler-level RBAC (TenantAdmin/Member)
|
|
40
|
-
// 3. Value
|
|
41
|
-
//
|
|
42
|
-
// 422,
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
// dient clear-custom-field.
|
|
35
|
+
// **Write path (single fetch)** — one fieldDefinition load, three gates:
|
|
36
|
+
// 1. Definition missing → 404.
|
|
37
|
+
// 2. field-access: fieldAccess.write roles must intersect, otherwise
|
|
38
|
+
// 403/422. Handler-level RBAC (TenantAdmin/Member) also applies.
|
|
39
|
+
// 3. Value validation (builder reuse): the value is parsed against the
|
|
40
|
+
// fieldToZod schema rehydrated from serializedField. Type mismatch →
|
|
41
|
+
// 422, NO event is created (the projection remains typed). `value: null`
|
|
42
|
+
// OR `value: undefined` on a typed field are type mismatches → 422; use
|
|
43
|
+
// clear-custom-field to remove a value.
|
|
46
44
|
//
|
|
47
|
-
// Scope:
|
|
48
|
-
// `maxLength`, `format
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
// (Plan-Doc "Stammfeld-Identität" listet sie als eigene Zeilen).
|
|
45
|
+
// Scope: TRUE type-only validation. value-schema.ts strips `required`,
|
|
46
|
+
// `maxLength`, `format`, and `default` from serializedField before building
|
|
47
|
+
// a schema from fieldToZod — we check only the type shape. Required-on-set,
|
|
48
|
+
// default application, and length/format enforcement remain out of scope.
|
|
52
49
|
export const setCustomFieldHandler: WriteHandlerDef = {
|
|
53
50
|
name: "set-custom-field",
|
|
54
51
|
schema: setCustomFieldPayloadSchema,
|
|
@@ -95,11 +92,11 @@ export const setCustomFieldHandler: WriteHandlerDef = {
|
|
|
95
92
|
}
|
|
96
93
|
}
|
|
97
94
|
|
|
98
|
-
// Emit customField.set on host-aggregate stream. unsafeAppendEvent
|
|
99
|
-
//
|
|
100
|
-
// augmentation
|
|
101
|
-
//
|
|
102
|
-
//
|
|
95
|
+
// Emit customField.set on the host-aggregate stream. unsafeAppendEvent
|
|
96
|
+
// is used instead of strict appendEvent because event-type-map has no
|
|
97
|
+
// cross-feature augmentation for this event type; the qualified string
|
|
98
|
+
// name is used directly. The value is ALWAYS included in the event
|
|
99
|
+
// (custom fields carry no PII), so replay fully reproduces the projection.
|
|
103
100
|
await ctx.unsafeAppendEvent({
|
|
104
101
|
aggregateId: payload.entityId,
|
|
105
102
|
aggregateType: payload.entityName,
|
|
@@ -114,9 +111,9 @@ export const setCustomFieldHandler: WriteHandlerDef = {
|
|
|
114
111
|
},
|
|
115
112
|
};
|
|
116
113
|
|
|
117
|
-
/** Value
|
|
118
|
-
*
|
|
119
|
-
* createCustomFieldsFeature({ valueWriteRoles })
|
|
114
|
+
/** Value writes use app roles instead of the bundle defaults — apps with a
|
|
115
|
+
* custom role vocabulary (e.g. "Admin"/"Editor") pass their roles here via
|
|
116
|
+
* createCustomFieldsFeature({ valueWriteRoles }). */
|
|
120
117
|
export function createSetCustomFieldHandler(
|
|
121
118
|
roles: readonly string[] = DEFAULT_VALUE_WRITE_ROLES,
|
|
122
119
|
): WriteHandlerDef {
|
|
@@ -15,10 +15,10 @@ import { DEFAULT_FIELD_DEFINITION_WRITE_ROLES } from "../web/constants.ts";
|
|
|
15
15
|
//
|
|
16
16
|
// **type is immutable**; an omitted type keeps the stored one. A type change
|
|
17
17
|
// would orphan existing values in the host entities' customFields jsonb (a
|
|
18
|
-
// text value under a number field), so delete + re-define is the honest path
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
18
|
+
// text value under a number field), so delete + re-define is the honest path.
|
|
19
|
+
// There is deliberately no delete+redefine inside update, since that destroys
|
|
20
|
+
// event history and field ids, which is exactly the break a type change needs
|
|
21
|
+
// to make visible.
|
|
22
22
|
//
|
|
23
23
|
// **Known MVP limit (deliberate):** the edit does NOT reconcile existing host
|
|
24
24
|
// values against the new definition. Narrowed constraints (enum value removed,
|
|
@@ -32,7 +32,7 @@ import { DEFAULT_FIELD_DEFINITION_WRITE_ROLES } from "../web/constants.ts";
|
|
|
32
32
|
// (same trade-off as the quota soft cap in define), so last write wins instead
|
|
33
33
|
// of a version round trip through the edit screen.
|
|
34
34
|
export interface UpdateTenantFieldOptions {
|
|
35
|
-
/** Access roles for this handler. Default ["TenantAdmin"]
|
|
35
|
+
/** Access roles for this handler. Default ["TenantAdmin"] — see
|
|
36
36
|
* DefineTenantFieldOptions.roles, the definition-CRUD triad shares one gate. */
|
|
37
37
|
readonly roles?: readonly string[];
|
|
38
38
|
}
|
|
@@ -87,7 +87,7 @@ export function createUpdateTenantFieldHandler(
|
|
|
87
87
|
});
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
// entityName/fieldKey
|
|
90
|
+
// entityName/fieldKey define the identity and must not be included in changes.
|
|
91
91
|
const {
|
|
92
92
|
entityName: _entityName,
|
|
93
93
|
fieldKey: _fieldKey,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Per-field write access-check for the set/clear handlers.
|
|
2
2
|
// Plus single-fetch loader so set-custom-field can run access-check AND
|
|
3
3
|
// value-validation off one DB read (no double fetch).
|
|
4
4
|
|
|
@@ -31,7 +31,7 @@ export async function loadFieldDefinition(
|
|
|
31
31
|
): Promise<LoadedFieldDefinition> {
|
|
32
32
|
const serialized = await selectSerializedFieldDefinition(runner, tenantId, entityName, fieldKey);
|
|
33
33
|
if (serialized === null) return { found: false };
|
|
34
|
-
// parseSerializedField throws on a
|
|
34
|
+
// parseSerializedField throws on a legacy `sensitive` definition —
|
|
35
35
|
// that's a corrupt/unprocessable row from this write-gate's perspective,
|
|
36
36
|
// same fail-closed treatment as a shape that fails isShape().
|
|
37
37
|
try {
|
|
@@ -42,7 +42,7 @@ export function parseSerializedField(raw: unknown): SerializedFieldShape | null
|
|
|
42
42
|
const parsed = typeof raw === "string" ? parseJsonSafe<unknown>(raw, null) : raw;
|
|
43
43
|
if (!isShape(parsed)) return null;
|
|
44
44
|
// Fail loud instead of silently dropping the key: a stored definition with
|
|
45
|
-
// `sensitive` predates
|
|
45
|
+
// `sensitive` predates and its PII expectations (event-log exclusion,
|
|
46
46
|
// forget-strip) no longer hold — the field must be recreated.
|
|
47
47
|
if ("sensitive" in parsed) {
|
|
48
48
|
throw new Error(
|
|
@@ -8,23 +8,21 @@ import type * as z from "zod";
|
|
|
8
8
|
import { SUPPORTED_FIELD_TYPES } from "../web/constants.ts";
|
|
9
9
|
|
|
10
10
|
// Builds a Zod schema that validates a custom-field VALUE against its
|
|
11
|
-
// fieldDefinition. Reuses the framework's `fieldToZod`
|
|
12
|
-
//
|
|
13
|
-
// between Stammfeld- and Custom-Field-validation.
|
|
11
|
+
// fieldDefinition. Reuses the framework's `fieldToZod` so built-in and
|
|
12
|
+
// custom-field validation share one field-type schema source.
|
|
14
13
|
//
|
|
15
|
-
// Scope: type-shape only. fieldToZod also folds `required`, `maxLength`,
|
|
16
|
-
// `format`, and `default` into Zod refinements;
|
|
17
|
-
// call
|
|
18
|
-
// Required-on-set, default
|
|
19
|
-
//
|
|
20
|
-
// separate concerns).
|
|
14
|
+
// Scope: type-shape only. `fieldToZod` also folds `required`, `maxLength`,
|
|
15
|
+
// `format`, and `default` into Zod refinements; stripping them before the
|
|
16
|
+
// call ensures that setting a custom field rejects only type mismatches.
|
|
17
|
+
// Required-on-set, default application, and length/format enforcement remain
|
|
18
|
+
// separate concerns.
|
|
21
19
|
//
|
|
22
|
-
// Vocabulary bridge: custom
|
|
23
|
-
//
|
|
20
|
+
// Vocabulary bridge: custom fields expose `enum` through `r.field.enum([...])`,
|
|
21
|
+
// while the framework's FieldDefinition calls the equivalent type `select`
|
|
24
22
|
// with an `options` array.
|
|
25
23
|
//
|
|
26
24
|
// Returns `null` when the serialized field is unparseable or names a type
|
|
27
|
-
// outside the custom-fields-supported set
|
|
25
|
+
// outside the custom-fields-supported set, allowing callers to skip validation.
|
|
28
26
|
|
|
29
27
|
const SUPPORTED_TYPES_SET: ReadonlySet<string> = new Set(SUPPORTED_FIELD_TYPES);
|
|
30
28
|
const SUPPORTED_EMBEDDED_SUB_TYPES: ReadonlySet<string> = new Set([
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Per-field retention sweep for the customFields jsonb.
|
|
2
2
|
//
|
|
3
3
|
// Iterates one host entity's rows, looks up every fieldDefinition with a
|
|
4
4
|
// `retention` policy, and strips/nulls customField values whose host-row
|
|
@@ -158,7 +158,7 @@ async function loadRetentionPolicies(
|
|
|
158
158
|
for (const raw of rows) {
|
|
159
159
|
// skip: see asHostRow rationale.
|
|
160
160
|
if (!isFieldDefinitionRow(raw)) continue;
|
|
161
|
-
// parseSerializedField throws on a
|
|
161
|
+
// parseSerializedField throws on a legacy `sensitive` definition —
|
|
162
162
|
// one unmigrated field must not abort the whole tenant's retention sweep
|
|
163
163
|
// for every other field; skip it (no retention policy to apply anyway).
|
|
164
164
|
let parsed: ReturnType<typeof parseSerializedField>;
|
|
@@ -178,7 +178,7 @@ interface InstantLike {
|
|
|
178
178
|
readonly epochMilliseconds: number;
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
// guard:dup-ok — false positive:
|
|
181
|
+
// guard:dup-ok — false positive: same type-guard structure as isFieldDefinitionRow, but completely different semantics
|
|
182
182
|
function isInstantLike(value: unknown): value is InstantLike {
|
|
183
183
|
if (!value || typeof value !== "object") return false;
|
|
184
184
|
if (!("epochMilliseconds" in value)) return false;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as z from "zod";
|
|
2
2
|
import { SUPPORTED_FIELD_TYPES } from "./web/constants.ts";
|
|
3
3
|
|
|
4
|
-
// Field-Type-Validator — pinnt valid type-Werte für fieldDefinition.
|
|
5
4
|
export const fieldTypeSchema = z.enum(SUPPORTED_FIELD_TYPES);
|
|
6
5
|
|
|
7
6
|
// Per-field access-control. When set, `set/clear-custom-field` handlers
|
|
@@ -9,8 +8,8 @@ export const fieldTypeSchema = z.enum(SUPPORTED_FIELD_TYPES);
|
|
|
9
8
|
// in addition to the handler-level RBAC. Absent or empty `write` means
|
|
10
9
|
// the handler-level RBAC is the only gate.
|
|
11
10
|
//
|
|
12
|
-
// `read` is reserved for the postQuery-flatten pipeline
|
|
13
|
-
// enforced
|
|
11
|
+
// `read` is reserved for the postQuery-flatten pipeline and is not
|
|
12
|
+
// currently enforced.
|
|
14
13
|
export const customFieldAccessSchema = z
|
|
15
14
|
.object({
|
|
16
15
|
read: z.array(z.string()).optional(),
|
|
@@ -19,11 +18,12 @@ export const customFieldAccessSchema = z
|
|
|
19
18
|
.optional();
|
|
20
19
|
export type CustomFieldAccess = z.infer<typeof customFieldAccessSchema>;
|
|
21
20
|
|
|
22
|
-
// Serialized-field
|
|
23
|
-
// In v1
|
|
24
|
-
//
|
|
21
|
+
// Serialized-field JSONB: the value stored in the `serializedField` column.
|
|
22
|
+
// In v1, it is not strictly typed per field type because the base-field
|
|
23
|
+
// builder schemas are not yet exposed. This schema only guarantees the
|
|
24
|
+
// overall structure.
|
|
25
25
|
//
|
|
26
|
-
// Schema
|
|
26
|
+
// Schema shape (example inputs for the different field types):
|
|
27
27
|
//
|
|
28
28
|
// text: { type: "text", required: true, maxLength: 50 }
|
|
29
29
|
// number: { type: "number", required: false, min: 0, max: 100 }
|
|
@@ -33,13 +33,13 @@ export type CustomFieldAccess = z.infer<typeof customFieldAccessSchema>;
|
|
|
33
33
|
// money: { type: "money", required: false, currency: "EUR" }
|
|
34
34
|
// embedded: { type: "embedded", required: false, schema: { ... } }
|
|
35
35
|
//
|
|
36
|
-
// `fieldAccess`
|
|
37
|
-
// Everything else
|
|
36
|
+
// `fieldAccess` is the structured key recognised by the handlers.
|
|
37
|
+
// Everything else remains loose pending per-type discriminated unions —
|
|
38
38
|
// EXCEPT `sensitive`, which is explicitly rejected below: custom fields
|
|
39
|
-
// carry supplemental business data only, PII support was removed
|
|
39
|
+
// carry supplemental business data only, and PII support was removed.
|
|
40
40
|
const serializedFieldBaseShape = {
|
|
41
41
|
fieldAccess: customFieldAccessSchema,
|
|
42
|
-
// `retention
|
|
42
|
+
// `retention`: per-field expiry. The retention-cron strips
|
|
43
43
|
// values whose host-row `modified_at` is older than `keepFor`. Strategy
|
|
44
44
|
// `delete` removes the key from the customFields jsonb; `anonymize`
|
|
45
45
|
// sets it to `null` (key stays, value gone — preserves the schema
|
|
@@ -69,10 +69,10 @@ const updateSerializedFieldSchema = z
|
|
|
69
69
|
.looseObject({ type: fieldTypeSchema.optional(), ...serializedFieldBaseShape })
|
|
70
70
|
.refine(...rejectSensitive);
|
|
71
71
|
|
|
72
|
-
// i18n
|
|
72
|
+
// i18n labels — `{ de: "...", en: "...", ... }`. At least one entry.
|
|
73
73
|
const labelSchema = z.record(z.string().min(2).max(8), z.string().min(1));
|
|
74
74
|
|
|
75
|
-
// Payload
|
|
75
|
+
// Payload for the `define-tenant-field` and `define-system-field` write handlers.
|
|
76
76
|
export const defineFieldPayloadSchema = z.object({
|
|
77
77
|
entityName: z.string().min(1).max(64),
|
|
78
78
|
fieldKey: z
|
|
@@ -100,7 +100,7 @@ export const updateFieldPayloadSchema = defineFieldPayloadSchema.extend({
|
|
|
100
100
|
});
|
|
101
101
|
export type UpdateFieldPayload = z.infer<typeof updateFieldPayloadSchema>;
|
|
102
102
|
|
|
103
|
-
// Payload
|
|
103
|
+
// Payload for `delete-tenant-field` / `delete-system-field`.
|
|
104
104
|
export const deleteFieldPayloadSchema = z.object({
|
|
105
105
|
entityName: z.string().min(1).max(64),
|
|
106
106
|
fieldKey: z.string().min(1).max(64),
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
// und registriert die CustomFieldsFormSection unter dem Namen
|
|
4
|
-
// CUSTOM_FIELDS_FORM_EXTENSION_NAME im ExtensionSectionsProvider. Apps
|
|
5
|
-
// referenzieren den Namen im Screen-Schema:
|
|
1
|
+
// Registers the custom-fields form section under
|
|
2
|
+
// CUSTOM_FIELDS_FORM_EXTENSION_NAME so apps can reference it in their screen schema:
|
|
6
3
|
//
|
|
7
4
|
// layout: { sections: [
|
|
8
5
|
// { kind: "extension", title: "...", contributesToFormSubmit: true, component: {
|
|
@@ -56,8 +56,8 @@ export const CUSTOM_FIELDS_EXTENSION = "customFields";
|
|
|
56
56
|
// every app user.
|
|
57
57
|
export const DEFAULT_VALUE_WRITE_ROLES = ["TenantAdmin", "TenantMember"] as const;
|
|
58
58
|
export const DEFAULT_FIELD_DEFINITION_LIST_ROLES = ["TenantAdmin"] as const;
|
|
59
|
-
// Default-RBAC of the definition-CRUD triad (define-/update-/delete-tenant-field
|
|
60
|
-
//
|
|
59
|
+
// Default-RBAC of the definition-CRUD triad (define-/update-/delete-tenant-field).
|
|
60
|
+
// Apps with their own role vocabulary override via
|
|
61
61
|
// createCustomFieldsFeature({ fieldDefinitionWriteRoles }) — otherwise those three
|
|
62
62
|
// hard-wired handler QNs are access_denied for every app-user without a
|
|
63
63
|
// "TenantAdmin" role (same Role-Naming-Drift as DEFAULT_VALUE_WRITE_ROLES above).
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
// CustomFieldsFormSection — extension-section component
|
|
2
|
-
//
|
|
3
|
-
// host
|
|
4
|
-
// `custom-fields:write:set-custom-field`
|
|
1
|
+
// CustomFieldsFormSection — extension-section component for entityEdit-
|
|
2
|
+
// screens. Loads the tenant's fieldDefinition list, filters it to the
|
|
3
|
+
// host entity, renders a typed input per definition, and dispatches
|
|
4
|
+
// `custom-fields:write:set-custom-field` for each non-empty value on save.
|
|
5
5
|
//
|
|
6
6
|
// Mount via createKumikoApp({ clientFeatures: [customFieldsClient()] })
|
|
7
|
-
// —
|
|
8
|
-
//
|
|
9
|
-
// `component: { react: { __component: CUSTOM_FIELDS_FORM_EXTENSION_NAME } }
|
|
10
|
-
// referenziert.
|
|
7
|
+
// — the clientFeature factory registers this component under the name
|
|
8
|
+
// `CustomFieldsFormSection`, which the app references in the screen schema
|
|
9
|
+
// via `component: { react: { __component: CUSTOM_FIELDS_FORM_EXTENSION_NAME } }`.
|
|
11
10
|
|
|
12
11
|
import {
|
|
13
12
|
type ExtensionSubmitResult,
|
|
@@ -40,10 +39,10 @@ export function CustomFieldsFormSection({
|
|
|
40
39
|
}: {
|
|
41
40
|
readonly entityName: string;
|
|
42
41
|
readonly entityId: string | null;
|
|
43
|
-
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
42
|
+
/** The entity's previously saved customField values, passed through from the
|
|
43
|
+
* detail row. Without them, the section would be write-only: the inputs
|
|
44
|
+
* would not show existing values while editing. `pending` tracks only
|
|
45
|
+
* changes, so the Save button remains disabled until the first edit. */
|
|
47
46
|
readonly initialValues?: Readonly<Record<string, unknown>>;
|
|
48
47
|
}): ReactNode {
|
|
49
48
|
const { Banner, Button, Field, Input, Text } = usePrimitives();
|
|
@@ -58,11 +57,11 @@ export function CustomFieldsFormSection({
|
|
|
58
57
|
const [saving, setSaving] = useState(false);
|
|
59
58
|
const [errorKey, setErrorKey] = useState<string | null>(null);
|
|
60
59
|
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
// false. Dirty
|
|
64
|
-
//
|
|
65
|
-
//
|
|
60
|
+
// Computed before the early returns because useExtensionFormSubmit (a Hook)
|
|
61
|
+
// must run before them. matchingFields is [] while loading, so dirty remains
|
|
62
|
+
// false. Dirty means differing from the SAVED value (not from ""); otherwise
|
|
63
|
+
// clearing an existing value would be invisible and skipped instead of
|
|
64
|
+
// cleared.
|
|
66
65
|
const matchingFields = (query.data?.rows ?? [])
|
|
67
66
|
.filter((f) => f.entityName === entityName)
|
|
68
67
|
.slice()
|
|
@@ -75,9 +74,10 @@ export function CustomFieldsFormSection({
|
|
|
75
74
|
});
|
|
76
75
|
const dirty = changedFields.length > 0;
|
|
77
76
|
|
|
78
|
-
//
|
|
79
|
-
// (
|
|
80
|
-
//
|
|
77
|
+
// Writes all changed fields via set/clear. Used by the composed submit
|
|
78
|
+
// (the main form calls the handler after the entity write) and by the
|
|
79
|
+
// standalone button when the section is mounted without a surrounding
|
|
80
|
+
// composed form.
|
|
81
81
|
const flushChanges = async (targetEntityId: string): Promise<ExtensionSubmitResult> => {
|
|
82
82
|
for (const field of changedFields) {
|
|
83
83
|
const raw = pending[field.fieldKey] ?? "";
|
|
@@ -105,9 +105,9 @@ export function CustomFieldsFormSection({
|
|
|
105
105
|
return { isSuccess: true };
|
|
106
106
|
};
|
|
107
107
|
|
|
108
|
-
// composed =
|
|
109
|
-
//
|
|
110
|
-
//
|
|
108
|
+
// composed = inside an entityEdit form, so there is no separate Save button;
|
|
109
|
+
// the section writes along with the main save. Outside a composed form
|
|
110
|
+
// (composed === false), the standalone button remains available.
|
|
111
111
|
const composed = useExtensionFormSubmit({
|
|
112
112
|
dirty,
|
|
113
113
|
onSubmit: (ctx) => flushChanges(ctx.entityId),
|
|
@@ -236,9 +236,9 @@ function coerceValue(type: string, raw: string): unknown {
|
|
|
236
236
|
return raw;
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
-
//
|
|
240
|
-
//
|
|
241
|
-
//
|
|
239
|
+
// Inverse of coerceValue: converts a stored jsonb value to the string form
|
|
240
|
+
// expected by the input. number/boolean/date/text are represented as their
|
|
241
|
+
// inputs expect; missing values become "".
|
|
242
242
|
function displayValue(type: string, value: unknown): string {
|
|
243
243
|
if (value === undefined || value === null) return "";
|
|
244
244
|
if (type === "boolean") return value === true ? "true" : "false";
|