@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
|
@@ -23,13 +23,13 @@ import { MANAGED_PAGES_I18N } from "./web/i18n.ts";
|
|
|
23
23
|
// 60s-shared-cache saves the origin-revalidate roundtrip; CMS edits are live within 60s.
|
|
24
24
|
const PUBLIC_PAGE_CACHE = { kind: "revalidate", maxAgeSeconds: 60 } as const;
|
|
25
25
|
|
|
26
|
-
// QN
|
|
27
|
-
//
|
|
28
|
-
//
|
|
26
|
+
// QN constant as a documented public contract — the render path calls
|
|
27
|
+
// the by-slug query in-process via systemQuery (without importing the
|
|
28
|
+
// handler's code, symmetrically with the legal-pages pattern).
|
|
29
29
|
const BY_SLUG_QN = "managed-pages:query:by-slug";
|
|
30
30
|
|
|
31
|
-
// Raw
|
|
32
|
-
//
|
|
31
|
+
// Raw handler return from bySlugQuery (published-only) — systemQuery dispatches
|
|
32
|
+
// directly to the handler, without the `{data}` envelope used on the /api/query wire.
|
|
33
33
|
type BySlugQueryResult = {
|
|
34
34
|
title: string;
|
|
35
35
|
body: string;
|
|
@@ -83,61 +83,61 @@ export type ManagedPagesWrapLayout = (opts: {
|
|
|
83
83
|
}) => string;
|
|
84
84
|
|
|
85
85
|
export type ManagedPagesOptions = {
|
|
86
|
-
/** Host → tenantId
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
* tenantId (
|
|
90
|
-
*
|
|
86
|
+
/** Host → tenantId for anonymous per-tenant delivery. NULL → 404 (no
|
|
87
|
+
* tenant for this host). Apex/marketing apps provide their subdomain or
|
|
88
|
+
* custom-domain resolution here; single-tenant apps return a constant
|
|
89
|
+
* tenantId (or SYSTEM_TENANT_ID). Required because the apex host has no
|
|
90
|
+
* ambient ctx.tenantId. */
|
|
91
91
|
readonly resolveApexTenant: (host: string) => Promise<string | null> | string | null;
|
|
92
|
-
/** Custom
|
|
93
|
-
*
|
|
94
|
-
* **`branding`
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
* (
|
|
98
|
-
* `brandingHeaderHtml(branding)` + `brandingStyleBlock(branding)` (
|
|
99
|
-
*
|
|
100
|
-
* customCss)`
|
|
101
|
-
*
|
|
102
|
-
*
|
|
92
|
+
/** Custom layout wrapper (branding/chrome). Default: a minimal page-render
|
|
93
|
+
* skeleton. Receives slug + SEO meta for free use.
|
|
94
|
+
* **`branding` is RAW, untrusted tenant input.** `title`/`description`
|
|
95
|
+
* are only length-capped on write, NOT HTML-escaped; `customCss` is
|
|
96
|
+
* unsanitized. The wrapper MUST emit them through the boundary helpers
|
|
97
|
+
* (all re-exported from `@cosmicdrift/kumiko-bundled-features/managed-pages`):
|
|
98
|
+
* `brandingHeaderHtml(branding)` + `brandingStyleBlock(branding)` (which
|
|
99
|
+
* escape header/theme) and, with allowCustomCss, `tenantStyleBlock(branding.
|
|
100
|
+
* customCss)` in the `<head>` plus `TENANT_CONTENT_ATTR` on the body
|
|
101
|
+
* container. A custom wrapper that interpolates `branding.title` itself is
|
|
102
|
+
* stored XSS; the default wrapper uses the helpers throughout. */
|
|
103
103
|
readonly wrapLayout?: ManagedPagesWrapLayout;
|
|
104
|
-
/**
|
|
104
|
+
/** Base path for page routes. Default "/p" → GET /p/:slug. */
|
|
105
105
|
readonly basePath?: string;
|
|
106
|
-
/** Default
|
|
106
|
+
/** Default language when `?lang=` is missing. Default "en". */
|
|
107
107
|
readonly defaultLang?: string;
|
|
108
|
-
/**
|
|
109
|
-
* `branding-custom-css`
|
|
110
|
-
*
|
|
111
|
-
* Default **false** (fail-closed — opt-in
|
|
112
|
-
*
|
|
113
|
-
* `managed-pages-css
|
|
114
|
-
*
|
|
115
|
-
*
|
|
108
|
+
/** Enables the per-tenant custom CSS capability (raw, untrusted): a
|
|
109
|
+
* `branding-custom-css` config key + a CSS field in the branding editor +
|
|
110
|
+
* render emission as a scoped, allowlist-sanitized `<style data-tenant-css>`.
|
|
111
|
+
* Default **false** (fail-closed — opt-in for untrusted tenant input). Even
|
|
112
|
+
* when true, emission is additionally gated per tenant by the
|
|
113
|
+
* `managed-pages-css` toggle (createManagedPagesCssFeature) once a
|
|
114
|
+
* feature-toggles/tier-engine runtime is wired. The render-time sanitizer
|
|
115
|
+
* (page-render/css-sanitize) is the safety boundary. */
|
|
116
116
|
readonly allowCustomCss?: boolean;
|
|
117
117
|
};
|
|
118
118
|
|
|
119
|
-
// managed-pages —
|
|
120
|
-
//
|
|
121
|
-
// (`GET /p/:slug`)
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
//
|
|
119
|
+
// managed-pages — tenant-editable, server-rendered public pages.
|
|
120
|
+
// Generalizes the legal-pages rendering pattern: a dynamic slug route
|
|
121
|
+
// (`GET /p/:slug`) that resolves the tenant from the Host (resolveApexTenant),
|
|
122
|
+
// loads the published page, renders hardened Markdown (page-render), and wraps
|
|
123
|
+
// it in chrome through an optional wrapLayout. Drafts → 404. Per-tenant
|
|
124
|
+
// content is cache-isolated through `Vary: Host`.
|
|
125
125
|
//
|
|
126
|
-
// Admin
|
|
127
|
-
// SystemAdmin)
|
|
128
|
-
//
|
|
129
|
-
// same
|
|
126
|
+
// Admin authoring: registers entityList + entityEdit for `page` (TenantAdmin/
|
|
127
|
+
// SystemAdmin) and the convention CRUD handlers dispatched by the renderer.
|
|
128
|
+
// The screens MUST live here (the boot validator requires the entity reference
|
|
129
|
+
// in the same feature); navigation/workspace remains the app's responsibility.
|
|
130
130
|
//
|
|
131
|
-
//
|
|
132
|
-
// • anonymousAccess
|
|
133
|
-
// —
|
|
134
|
-
//
|
|
135
|
-
//
|
|
136
|
-
// • Admin
|
|
137
|
-
// page-list" })`
|
|
138
|
-
// (cross-feature Nav→Screen
|
|
139
|
-
// TenantAdmin.
|
|
140
|
-
// flat-nav
|
|
131
|
+
// App bootstrap requirements:
|
|
132
|
+
// • anonymousAccess must be wired to honor the X-Tenant header
|
|
133
|
+
// — multi-tenant apps use a tenantResolver (or no defaultTenantId).
|
|
134
|
+
// A fixed defaultTenantId locks the app to single-tenant mode and rejects
|
|
135
|
+
// the per-page X-Tenant with 400 tenant_mismatch.
|
|
136
|
+
// • Admin UI: the app exposes these screens via `r.nav({ screen:
|
|
137
|
+
// "managed-pages:screen:page-list" })` plus a workspace entry
|
|
138
|
+
// (cross-feature Nav→Screen is globally validated) and grants its admins
|
|
139
|
+
// TenantAdmin. Without navigation, the screens remain dormant — no leak in
|
|
140
|
+
// flat-nav apps that use managed-pages only for public rendering.
|
|
141
141
|
export function createManagedPagesFeature(opts: ManagedPagesOptions): FeatureDefinition {
|
|
142
142
|
const wrapLayout: ManagedPagesWrapLayout =
|
|
143
143
|
opts.wrapLayout ??
|
|
@@ -192,8 +192,8 @@ export function createManagedPagesFeature(opts: ManagedPagesOptions): FeatureDef
|
|
|
192
192
|
path: `${basePath}/:slug`,
|
|
193
193
|
anonymous: true,
|
|
194
194
|
handler: async (c, { systemQuery }) => {
|
|
195
|
-
// `param("slug")`
|
|
196
|
-
//
|
|
195
|
+
// `param("slug")` is string|undefined because `path` is a computed
|
|
196
|
+
// template (Hono infers `:slug` only from string literals).
|
|
197
197
|
const slug = c.req.param("slug");
|
|
198
198
|
if (!slug) return c.text("not found", 404);
|
|
199
199
|
const lang = c.req.query("lang") || defaultLang;
|
|
@@ -204,13 +204,13 @@ export function createManagedPagesFeature(opts: ManagedPagesOptions): FeatureDef
|
|
|
204
204
|
const tenantId = await opts.resolveApexTenant(host);
|
|
205
205
|
if (!tenantId) return c.text("not found", 404);
|
|
206
206
|
|
|
207
|
-
// Page
|
|
208
|
-
// process
|
|
209
|
-
//
|
|
210
|
-
//
|
|
211
|
-
//
|
|
212
|
-
//
|
|
213
|
-
//
|
|
207
|
+
// Page and branding are read in parallel, both forced through systemQuery
|
|
208
|
+
// in-process for the host-resolved tenantId (no X-Tenant header trick
|
|
209
|
+
// through app.fetch — for a host-based anonymousAccess resolver, that
|
|
210
|
+
// would look like a client override and would rightly be rejected by
|
|
211
|
+
// resolverTrust: "authoritative"; see systemQuery's documentation in
|
|
212
|
+
// http-route.ts). Branding is decorative → a failure degrades to the
|
|
213
|
+
// unbranded default and never blocks the page.
|
|
214
214
|
let pageSettled: { ok: true; data: BySlugQueryResult } | { ok: false };
|
|
215
215
|
let brandingResult: BrandingTokens;
|
|
216
216
|
try {
|
|
@@ -246,8 +246,8 @@ export function createManagedPagesFeature(opts: ManagedPagesOptions): FeatureDef
|
|
|
246
246
|
"content-type": "text/html; charset=utf-8",
|
|
247
247
|
vary: "Host",
|
|
248
248
|
} as const;
|
|
249
|
-
// 304 (
|
|
250
|
-
//
|
|
249
|
+
// 304 (unchanged revision) and HEAD both skip Markdown rendering — the body
|
|
250
|
+
// would be discarded anyway.
|
|
251
251
|
if (etagMatches(c.req.raw.headers.get("if-none-match"), etag) || c.req.method === "HEAD") {
|
|
252
252
|
return cachedSecurePageResponse(c.req.raw, {
|
|
253
253
|
body: null,
|
|
@@ -3,12 +3,11 @@ import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
|
3
3
|
import * as z from "zod";
|
|
4
4
|
import { type PageRow, pagesTable } from "../table.ts";
|
|
5
5
|
|
|
6
|
-
// Public
|
|
7
|
-
//
|
|
8
|
-
// via X-Tenant = Host-resolved-tenant
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// diese Query.
|
|
6
|
+
// Public read by (tenantId, slug, lang), including anonymous access for landing and
|
|
7
|
+
// marketing pages. The tenant comes from query.user.tenantId, set on the render path
|
|
8
|
+
// via X-Tenant = Host-resolved-tenant. Returns ONLY published pages with a body:
|
|
9
|
+
// drafts and empty pages are invisible to anonymous visitors (the route returns 404).
|
|
10
|
+
// Admin editing uses the entity list/edit screens instead of this query.
|
|
12
11
|
export const bySlugQuery = defineQueryHandler({
|
|
13
12
|
name: "by-slug",
|
|
14
13
|
schema: z.object({
|
|
@@ -3,12 +3,12 @@ import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
|
3
3
|
import * as z from "zod";
|
|
4
4
|
import { type PageRow, pagesTable } from "../table.ts";
|
|
5
5
|
|
|
6
|
-
// Public
|
|
7
|
-
// sitemap.xml/llms.txt (
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// Anonymous
|
|
6
|
+
// Public read of all published pages for a tenant, used to discover URLs for
|
|
7
|
+
// sitemap.xml/llms.txt (see the seo feature). Unlike by-slug, which fetches one
|
|
8
|
+
// slug's content, this lists all published slugs in one query, filtered in SQL
|
|
9
|
+
// with `published = true`; drafts never appear, and only slug/title/updatedAt are
|
|
10
|
+
// returned because discovery does not require body content.
|
|
11
|
+
// Anonymous access is explicit in roles, matching text-content's by-tenant.
|
|
12
12
|
export type PublishedPageSummary = {
|
|
13
13
|
readonly slug: string;
|
|
14
14
|
readonly lang: string;
|
|
@@ -19,8 +19,8 @@ export type PublishedPageSummary = {
|
|
|
19
19
|
export const byTenantPublishedQuery = defineQueryHandler({
|
|
20
20
|
name: "by-tenant-published",
|
|
21
21
|
schema: z.object({
|
|
22
|
-
/** Optional cross-tenant read —
|
|
23
|
-
* by-slug.query
|
|
22
|
+
/** Optional cross-tenant read — only for SystemAdmin. Matches the override
|
|
23
|
+
* logic in by-slug.query. */
|
|
24
24
|
tenantIdOverride: z.string().min(1).optional(),
|
|
25
25
|
}),
|
|
26
26
|
access: { roles: ["anonymous", "User", "TenantAdmin", "SystemAdmin"] },
|
|
@@ -18,12 +18,10 @@ const langSchema = z
|
|
|
18
18
|
|
|
19
19
|
const executor = createEventStoreExecutor(pagesTable, pageEntity, { entityName: "page" });
|
|
20
20
|
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
// wenn im Payload weggelassen (undefined) — damit ein Publish-Toggle nicht
|
|
26
|
-
// den Body überschreiben muss und umgekehrt.
|
|
21
|
+
// Upserts one page per (tenantId, slug, lang). The tenant scope defaults to event.user;
|
|
22
|
+
// SystemAdmin can write to another tenant via `tenantIdOverride` (typically SYSTEM_TENANT_ID
|
|
23
|
+
// for app-wide pages). On update, omitted published/description/ogImage values are preserved
|
|
24
|
+
// so a publish toggle does not overwrite the body, and vice versa.
|
|
27
25
|
export const setWrite = defineWriteHandler({
|
|
28
26
|
name: "set",
|
|
29
27
|
schema: z.object({
|
|
@@ -34,7 +32,7 @@ export const setWrite = defineWriteHandler({
|
|
|
34
32
|
description: z.string().max(500).nullable().optional(),
|
|
35
33
|
ogImage: z.string().max(2000).nullable().optional(),
|
|
36
34
|
published: z.boolean().optional(),
|
|
37
|
-
/** Cross-tenant write —
|
|
35
|
+
/** Cross-tenant write — only SystemAdmin (for example, SYSTEM_TENANT_ID pages). */
|
|
38
36
|
tenantIdOverride: z.string().min(1).optional(),
|
|
39
37
|
}),
|
|
40
38
|
access: { roles: ["TenantAdmin", "SystemAdmin"] },
|
|
@@ -3,14 +3,14 @@ import type {
|
|
|
3
3
|
EntityListScreenDefinition,
|
|
4
4
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
5
5
|
|
|
6
|
-
// Admin
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// (
|
|
12
|
-
//
|
|
13
|
-
//
|
|
6
|
+
// Admin authoring screens for the `page` entity. These are JSON-safe data only —
|
|
7
|
+
// the generic DataTable/form renderer mounts them, so no React component is
|
|
8
|
+
// needed. Both MUST be registered in the managed-pages feature (not in the
|
|
9
|
+
// app): the boot validator requires `entity: "page"` to be declared in the
|
|
10
|
+
// same feature as the screen. Navigation and workspace placement remain app-
|
|
11
|
+
// specific (`default` workspace is an app singleton) — the app points to this
|
|
12
|
+
// via `r.nav({ screen: "managed-pages:screen:page-list" })`.
|
|
13
|
+
// Cross-feature Nav→Screen is validated against the global screen QN set.
|
|
14
14
|
|
|
15
15
|
const ADMIN_ROLES = ["TenantAdmin", "SystemAdmin"] as const;
|
|
16
16
|
|
|
@@ -72,9 +72,9 @@ export const pageEditScreen: EntityEditScreenDefinition = {
|
|
|
72
72
|
{ field: "title", span: 2 },
|
|
73
73
|
{ field: "description", span: 2 },
|
|
74
74
|
{ field: "ogImage", span: 2 },
|
|
75
|
-
// Publish/Unpublish:
|
|
76
|
-
//
|
|
77
|
-
// rowAction-payload
|
|
75
|
+
// Publish/Unpublish: the `published` toggle here IS the publishing
|
|
76
|
+
// mechanism (there is no separate one-click list action —
|
|
77
|
+
// rowAction-payload cannot inject constants).
|
|
78
78
|
{ field: "published", span: 1 },
|
|
79
79
|
],
|
|
80
80
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// Test
|
|
2
|
-
//
|
|
3
|
-
//
|
|
1
|
+
// Test/seed helper for managed-pages. Creates a page directly through the
|
|
2
|
+
// event-store executor—the same path as the real set handler, but without an
|
|
3
|
+
// access check. Default ifExists="skip".
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
6
|
createEventStoreExecutor,
|
|
@@ -33,9 +33,9 @@ export type SeedPageOptions = {
|
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
export async function seedPage(db: DbConnection, opts: SeedPageOptions): Promise<{ id: string }> {
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
36
|
+
// The default user must have user.tenantId === opts.tenantId; otherwise the
|
|
37
|
+
// event-store stream ends up in the wrong tenant bucket → version_conflict
|
|
38
|
+
// on subsequent real writes. TestUsers.systemAdmin is testTenantId(1).
|
|
39
39
|
const by = opts.by ?? { ...TestUsers.systemAdmin, tenantId: opts.tenantId };
|
|
40
40
|
const tdb = createTenantDb({ db, tenantId: opts.tenantId, mode: "system" });
|
|
41
41
|
|
|
@@ -70,8 +70,8 @@ export async function seedPage(db: DbConnection, opts: SeedPageOptions): Promise
|
|
|
70
70
|
if (!result.isSuccess) {
|
|
71
71
|
throw new Error(`seedPage create failed: ${JSON.stringify(result)}`);
|
|
72
72
|
}
|
|
73
|
-
// @cast-boundary db-row: executor.create result.data
|
|
74
|
-
// Drizzle
|
|
73
|
+
// @cast-boundary db-row: executor.create result.data is the inserted
|
|
74
|
+
// Drizzle row (Record<string, unknown>), projected from RETURNING.
|
|
75
75
|
const data = result.data as Partial<PageRow>;
|
|
76
76
|
if (data.id === undefined) {
|
|
77
77
|
throw new Error("seedPage: executor.create did not return an id");
|
|
@@ -5,12 +5,13 @@ import {
|
|
|
5
5
|
createTextField,
|
|
6
6
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
7
7
|
|
|
8
|
-
// Page —
|
|
9
|
-
//
|
|
10
|
-
// Markdown
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
8
|
+
// Page — a tenant-editable, server-rendered public page (landing,
|
|
9
|
+
// about, custom). Exactly one row per (tenantId, slug, lang). The body is
|
|
10
|
+
// Markdown, rendered securely on the server via page-render. `published`
|
|
11
|
+
// gates delivery to anonymous visitors: drafts return 404. description and
|
|
12
|
+
// ogImage support SEO and social previews. SYSTEM_TENANT_ID is used for
|
|
13
|
+
// app-wide pages; otherwise the page belongs to the tenant resolved from the
|
|
14
|
+
// host via resolveApexTenant during rendering.
|
|
14
15
|
export const pageEntity = createEntity({
|
|
15
16
|
table: "read_pages",
|
|
16
17
|
description:
|
|
@@ -38,12 +39,12 @@ export const pageEntity = createEntity({
|
|
|
38
39
|
personal: false,
|
|
39
40
|
reason: "is_business_data",
|
|
40
41
|
}),
|
|
41
|
-
// Body
|
|
42
|
-
// (Markdown),
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
// maxLengths
|
|
46
|
-
//
|
|
42
|
+
// Body and description are tenant-admin-authored business content
|
|
43
|
+
// (Markdown), not user-generated PII. `multiline` makes the entityEdit
|
|
44
|
+
// renderer output a <textarea> (createLongTextField currently has a
|
|
45
|
+
// rendering gap: edit.ts/render-field.tsx only gates on type==="text").
|
|
46
|
+
// maxLengths mirror the handler schemas (set.write and convention CRUD
|
|
47
|
+
// derive their zod caps from these field maxLengths).
|
|
47
48
|
body: createTextField({
|
|
48
49
|
multiline: { rows: 16 },
|
|
49
50
|
maxLength: 100_000,
|
|
@@ -59,9 +60,9 @@ export const pageEntity = createEntity({
|
|
|
59
60
|
|
|
60
61
|
export const pagesTable = buildEntityTable("page", pageEntity);
|
|
61
62
|
|
|
62
|
-
// Concrete
|
|
63
|
-
// `row["x"] as Y
|
|
64
|
-
// (id, version, tenantId, createdAt, updatedAt, createdBy, updatedBy).
|
|
63
|
+
// Concrete row type — the single source of truth for named values instead
|
|
64
|
+
// of `row["x"] as Y` casts in handlers. Includes entity.fields and standard
|
|
65
|
+
// columns (id, version, tenantId, createdAt, updatedAt, createdBy, updatedBy).
|
|
65
66
|
export type PageRow = {
|
|
66
67
|
readonly id: string;
|
|
67
68
|
readonly version: number;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
// Client
|
|
2
|
-
//
|
|
3
|
-
// (entityList/entityEdit/configEdit),
|
|
4
|
-
//
|
|
5
|
-
// [managedPagesClient()] })
|
|
1
|
+
// Client feature factory for managed-pages. It provides ONLY translations —
|
|
2
|
+
// the screens (page-list/page-edit/branding-settings) are schema-driven
|
|
3
|
+
// (entityList/entityEdit/configEdit), so no custom React components are
|
|
4
|
+
// registered. Apps mount it in createKumikoApp({ clientFeatures:
|
|
5
|
+
// [managedPagesClient()] }) so the admin labels render translated.
|
|
6
6
|
|
|
7
7
|
import { mergeTranslations, type TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
|
|
8
8
|
import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer/web";
|
|
9
9
|
import { defaultTranslations } from "./default-translations.ts";
|
|
10
10
|
|
|
11
11
|
export type ManagedPagesClientOptions = {
|
|
12
|
-
/** Key-wise
|
|
12
|
+
/** Key-wise overrides of the default bundles (de/en). */
|
|
13
13
|
readonly translations?: TranslationsByLocale;
|
|
14
14
|
};
|
|
15
15
|
|
|
@@ -56,7 +56,7 @@ export const MANAGED_PAGES_I18N: Readonly<Record<string, LocalizedString>> = {
|
|
|
56
56
|
en: "Delete this page?",
|
|
57
57
|
},
|
|
58
58
|
|
|
59
|
-
//
|
|
59
|
+
// Only used when allowCustomCss:true in the screen; supplied unconditionally
|
|
60
60
|
"managed-pages:entity:__config-edit__:field:customCss": { en: "Custom CSS" },
|
|
61
61
|
"managed-pages:branding.section.custom-css": { en: "Custom CSS" },
|
|
62
62
|
};
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
// Strictly append-only by design: no update/delete write-handler is
|
|
16
16
|
// registered (see feature.ts). A correction is a new entry, not an edit —
|
|
17
17
|
// that is the whole point of a note *history* instead of the single
|
|
18
|
-
// overwritable textarea this bundle replaces
|
|
18
|
+
// overwritable textarea this bundle replaces.
|
|
19
19
|
//
|
|
20
20
|
// `body` is about the HOST entity (entityType/entityId), not the author — the
|
|
21
21
|
// author is never the data subject of a note's content, so it is deliberately
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
// employee leaving triggers a forget), garbling unrelated business notes
|
|
25
25
|
// about customers/projects/etc. — data loss, not privacy.
|
|
26
26
|
//
|
|
27
|
-
// `body` is instead `personal: { of: "id" }` (Row-Subject
|
|
27
|
+
// `body` is instead `personal: { of: "id" }` (Row-Subject):
|
|
28
28
|
// the note's OWN row is its content's subject, so `body` is encrypted under a
|
|
29
29
|
// per-note key that nothing else shares. That key gets erased only when the
|
|
30
30
|
// note is reached by a forgotten subject: `note-mention` (below) names the
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
// shreds `authorName` (`personal: { of: "authorId" }`, the name as stamped at
|
|
35
35
|
// write time); the two erasures are independent.
|
|
36
36
|
//
|
|
37
|
-
// Known gap (
|
|
37
|
+
// Known gap (not fixed by this entity): prose that names a third
|
|
38
38
|
// party without a structured @-mention is not tracked — regex/NLP over
|
|
39
39
|
// free text is unreliable. An operator must erase such a note's own record
|
|
40
40
|
// subject (`forget-subject` kind "record", entity "note-entry") to cover it.
|
|
@@ -86,7 +86,7 @@ export function createNoteEntryEntity(
|
|
|
86
86
|
body: createLongTextField({
|
|
87
87
|
required: true,
|
|
88
88
|
maxLength: 20_000,
|
|
89
|
-
// Row-Subject
|
|
89
|
+
// Row-Subject: the note itself is the subject, so its
|
|
90
90
|
// key is erased per-note via `note-mention` lookups, not tied to any
|
|
91
91
|
// user's own forget.
|
|
92
92
|
personal: { of: "id" },
|
|
@@ -78,8 +78,8 @@ export type NotesHistoryFeatureOptions = {
|
|
|
78
78
|
/** Row-level ownership on the note-entry rows themselves — orthogonal to
|
|
79
79
|
* `access`, which only gates whether a caller may dispatch create/list at
|
|
80
80
|
* all. `ownership.read` is no longer what keeps a caller from reading notes
|
|
81
|
-
* on host entities they can't see: that gate is default-on
|
|
82
|
-
*
|
|
81
|
+
* on host entities they can't see: that gate is default-on and derives from
|
|
82
|
+
* the entity's `parentRef`. Use `ownership.read` for an
|
|
83
83
|
* ADDITIONAL row rule on the note row itself (e.g. author-only visibility);
|
|
84
84
|
* it is AND-ed with the host-visibility gate, never a replacement for it.
|
|
85
85
|
*
|
|
@@ -74,7 +74,7 @@ async function selectNotesReachingSubject(
|
|
|
74
74
|
// (entity.ts), so forgetting the AUTHOR already crypto-shreds that field on
|
|
75
75
|
// its own. `body` is Row-Subject (`personal: { of: "id" }`): its key is per
|
|
76
76
|
// note, so forgetting a subject only reaches a body when the note structurally
|
|
77
|
-
// @-mentions the subject (`note-mention
|
|
77
|
+
// @-mentions the subject (`note-mention`) or hangs on it as host.
|
|
78
78
|
// Free-text mentions are NOT detected — the documented gap in entity.ts.
|
|
79
79
|
//
|
|
80
80
|
// Reached bodies are shredded regardless of the host entity's retention strategy:
|
|
@@ -51,19 +51,19 @@ const TENANT_CLIP = `${TENANT_SCOPE}{overflow:hidden}`;
|
|
|
51
51
|
export function tenantStyleBlock(customCss: string): string {
|
|
52
52
|
const sanitized = sanitizeTenantCss(customCss, TENANT_SCOPE);
|
|
53
53
|
if (!sanitized) return "";
|
|
54
|
-
// html-ok: sanitizeTenantCss
|
|
54
|
+
// html-ok: sanitizeTenantCss is the escaping boundary (allowlist, strips `<`).
|
|
55
55
|
return `\n<style data-tenant-css>${TENANT_CONTAINMENT}\n${TENANT_CLIP}\n${sanitized}</style>`;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
//
|
|
59
|
-
// server-
|
|
60
|
-
//
|
|
61
|
-
//
|
|
58
|
+
// Minimal HTML5 skeleton with inline CSS — the default `wrapLayout` for
|
|
59
|
+
// server-rendered public pages, so they look clean without an app layout.
|
|
60
|
+
// Apps that want to wrap the body in their own marketing layout
|
|
61
|
+
// (header/footer/theme) pass their own render function.
|
|
62
62
|
//
|
|
63
|
-
// Branding (optional):
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
//
|
|
63
|
+
// Branding (optional): emits a scoped `:root` override after the base
|
|
64
|
+
// `<style>` (accent color, layout preset → max-width) and a logo/title header.
|
|
65
|
+
// All branding values are tenant-supplied and untrusted; branding.ts
|
|
66
|
+
// revalidates/escapes them before they enter the markup.
|
|
67
67
|
export function wrapInLayout(opts: {
|
|
68
68
|
title: string;
|
|
69
69
|
bodyHtml: string;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { escapeHtml, isSafeHref } from "@cosmicdrift/kumiko-renderer/headless";
|
|
2
2
|
import { Marked } from "marked";
|
|
3
3
|
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// Raw
|
|
7
|
-
//
|
|
8
|
-
// (
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// 'none'`). GFM
|
|
12
|
-
//
|
|
4
|
+
// Shared, hardened Markdown→HTML core for server-rendered public
|
|
5
|
+
// pages (legal-pages, managed-pages). Assumption: untrusted tenant authors.
|
|
6
|
+
// Raw HTML tokens are escaped as text (no <script>/<img onerror>-
|
|
7
|
+
// passthrough), and link/image hrefs are restricted to http(s)/mailto/relative
|
|
8
|
+
// (no javascript:/data:). Markdown structure (headings, lists, links,
|
|
9
|
+
// code) remains intact—this neutralizes XSS vectors without a sanitizer
|
|
10
|
+
// dependency. Defense in depth complements `securePageHeaders` (`script-src
|
|
11
|
+
// 'none'`). GFM and breaks are disabled—structured pages do not need
|
|
12
|
+
// tables/strikethrough/task lists.
|
|
13
13
|
const safeRenderer = new Marked({ gfm: false, breaks: false });
|
|
14
14
|
safeRenderer.use({
|
|
15
15
|
walkTokens(token) {
|
|
@@ -25,7 +25,7 @@ safeRenderer.use({
|
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
export function renderSafeMarkdown(markdown: string): string {
|
|
28
|
-
// @cast-boundary third-party-type-gap marked.parse return
|
|
29
|
-
// `{ async: false }`
|
|
28
|
+
// @cast-boundary third-party-type-gap marked.parse return type is `string | Promise<string>`;
|
|
29
|
+
// `{ async: false }` guarantees synchronous output (string)—the cast only fixes the API contract.
|
|
30
30
|
return safeRenderer.parse(markdown, { async: false }) as string;
|
|
31
31
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
// Security
|
|
2
|
-
// managed-pages). `script-src 'none'`
|
|
3
|
-
// HTML
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
1
|
+
// Security headers for server-rendered public HTML pages (legal-pages,
|
|
2
|
+
// managed-pages). `script-src 'none'` provides defense in depth: even if
|
|
3
|
+
// HTML injection gets through, no script can run. Deliberately omit
|
|
4
|
+
// `default-src` so styles, images, and fonts remain unrestricted for
|
|
5
|
+
// backward compatibility with inline-<style> layouts such as
|
|
6
|
+
// publicstatus' renderLegalLayout.
|
|
7
|
+
// nosniff/SAMEORIGIN/Referrer-Policy are broadly safe defaults.
|
|
7
8
|
const PUBLIC_PAGE_SECURITY_HEADERS = {
|
|
8
9
|
"content-security-policy": "script-src 'none'; object-src 'none'; base-uri 'none'",
|
|
9
10
|
"x-content-type-options": "nosniff",
|
|
@@ -123,12 +123,12 @@ export function createPersonalAccessTokensFeature(
|
|
|
123
123
|
} satisfies AuthProviderPlugin);
|
|
124
124
|
// Direct-write store like store_user_sessions: create/revoke write it, the
|
|
125
125
|
// resolver point-reads it. r.entity would make it a rebuildable projection
|
|
126
|
-
// whose replay (no token events) would wipe every live token
|
|
126
|
+
// whose replay (no token events) would wipe every live token.
|
|
127
127
|
r.storeTable(
|
|
128
128
|
deriveEntityTableMeta(API_TOKEN_ENTITY_NAME, apiTokenEntity, { source: "unmanaged" }),
|
|
129
129
|
{
|
|
130
130
|
reason: "read_side.api_tokens_direct_write",
|
|
131
|
-
// create.write encrypts `name` via encryptForDirectWrite
|
|
131
|
+
// create.write encrypts `name` via encryptForDirectWrite.
|
|
132
132
|
piiEncryptedOnWrite: true,
|
|
133
133
|
},
|
|
134
134
|
);
|
|
@@ -145,9 +145,9 @@ export function createPersonalAccessTokensFeature(
|
|
|
145
145
|
// Password-change auto-revoke — mirrors sessions' own
|
|
146
146
|
// autoRevokeOnPasswordChange postSave hook, including WHY it's a
|
|
147
147
|
// late-bind callback rather than direct ctx.db use: user:write:user:update
|
|
148
|
-
// is r.systemScope()'d (the user aggregate is a systemStream,
|
|
149
|
-
//
|
|
150
|
-
//
|
|
148
|
+
// is r.systemScope()'d (the user aggregate is a systemStream), so a postSave hook
|
|
149
|
+
// on "user" gets a poisoned ctx.db here. The concrete revoker is bound once
|
|
150
|
+
// run{Prod,Dev}App has a real db handle.
|
|
151
151
|
// Explicit option wins; the runtime binding is replaceable so a second boot of the same
|
|
152
152
|
// feature instance binds its own database.
|
|
153
153
|
let boundAutoRevoke: ((userId: string) => Promise<number>) | undefined;
|