@cosmicdrift/kumiko-samples 0.388.0 → 0.390.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/package.json +1 -1
- package/packages/bundled-features/package.json +25 -13
- package/packages/bundled-features/src/agent-tools/changes.json +6 -0
- package/packages/bundled-features/src/agent-tools/index.ts +1 -1
- package/packages/bundled-features/src/agent-tools/tool-dispatch.ts +42 -26
- package/packages/bundled-features/src/audit/feature.ts +2 -1
- package/packages/bundled-features/src/auth-email-password/auth-user-row.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/bootstrap.ts +13 -1
- package/packages/bundled-features/src/auth-email-password/changes.json +18 -0
- package/packages/bundled-features/src/auth-email-password/feature.ts +2 -2
- package/packages/bundled-features/src/auth-email-password/handlers/change-password.write.ts +7 -7
- package/packages/bundled-features/src/auth-email-password/handlers/confirm-account-unlock.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 +9 -7
- package/packages/bundled-features/src/auth-email-password/handlers/invite-accept.write.ts +11 -7
- package/packages/bundled-features/src/auth-email-password/handlers/invite-create.write.ts +4 -4
- package/packages/bundled-features/src/auth-email-password/handlers/invite-info.query.ts +2 -2
- package/packages/bundled-features/src/auth-email-password/handlers/invite-signup-complete.write.ts +9 -7
- package/packages/bundled-features/src/auth-email-password/handlers/login.write.ts +23 -16
- package/packages/bundled-features/src/auth-email-password/handlers/request-account-unlock.write.ts +1 -0
- package/packages/bundled-features/src/auth-email-password/handlers/request-email-verification.write.ts +1 -0
- package/packages/bundled-features/src/auth-email-password/handlers/request-password-reset.write.ts +1 -0
- package/packages/bundled-features/src/auth-email-password/handlers/reset-password.write.ts +3 -2
- package/packages/bundled-features/src/auth-email-password/handlers/signup-confirm.write.ts +12 -12
- package/packages/bundled-features/src/auth-email-password/handlers/signup-request.write.ts +16 -8
- package/packages/bundled-features/src/auth-email-password/handlers/switch-tenant-mfa-gate.write.ts +4 -2
- package/packages/bundled-features/src/auth-email-password/handlers/token-request-handler.ts +10 -2
- package/packages/bundled-features/src/auth-email-password/handlers/verify-email.write.ts +3 -2
- package/packages/bundled-features/src/auth-email-password/magic-link-mail.ts +16 -3
- package/packages/bundled-features/src/auth-email-password/seeding.ts +14 -9
- package/packages/bundled-features/src/auth-email-password/signup-activation.ts +2 -0
- package/packages/bundled-features/src/auth-email-password/web/auth-client.ts +8 -2
- package/packages/bundled-features/src/auth-email-password/web/auth-redirect.ts +23 -21
- package/packages/bundled-features/src/auth-email-password/web/default-auth-pages-gate.tsx +6 -3
- package/packages/bundled-features/src/auth-email-password/web/forgot-password-screen.tsx +11 -1
- package/packages/bundled-features/src/auth-email-password/web/index.ts +5 -0
- package/packages/bundled-features/src/auth-email-password/web/login-screen.tsx +16 -5
- package/packages/bundled-features/src/auth-email-password/web/reset-password-screen.tsx +7 -1
- package/packages/bundled-features/src/auth-email-password/web/return-path.ts +35 -0
- package/packages/bundled-features/src/auth-email-password/web/session.tsx +6 -1
- package/packages/bundled-features/src/auth-email-password/web/signup-complete-screen.tsx +11 -3
- package/packages/bundled-features/src/auth-email-password/web/signup-screen.tsx +12 -2
- package/packages/bundled-features/src/auth-foundation/feature.ts +13 -4
- package/packages/bundled-features/src/auth-mfa/changes.json +6 -0
- package/packages/bundled-features/src/auth-mfa/config.ts +3 -7
- package/packages/bundled-features/src/auth-mfa/handlers/disable.write.ts +5 -5
- package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm-preauth.write.ts +24 -14
- package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm.write.ts +9 -3
- package/packages/bundled-features/src/auth-mfa/handlers/enable-start-preauth.write.ts +6 -1
- package/packages/bundled-features/src/auth-mfa/handlers/enable-start.write.ts +3 -1
- package/packages/bundled-features/src/auth-mfa/handlers/reencrypt.job.ts +14 -9
- package/packages/bundled-features/src/auth-mfa/handlers/regenerate-recovery.write.ts +5 -4
- package/packages/bundled-features/src/auth-mfa/handlers/verify.write.ts +25 -14
- package/packages/bundled-features/src/auth-mfa/mfa-code-verifier.ts +10 -4
- package/packages/bundled-features/src/auth-mfa/mfa-status-checker.ts +17 -8
- package/packages/bundled-features/src/auth-mfa/verify-factor.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/billing-info-query.ts +2 -2
- package/packages/bundled-features/src/billing-foundation/changes.json +6 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/consent-gate.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/consumer-protection/issue-confirmation.ts +5 -5
- package/packages/bundled-features/src/billing-foundation/consumer-protection/register-consent.ts +10 -7
- package/packages/bundled-features/src/billing-foundation/consumer-protection/register-termination.ts +15 -12
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-open-cancels.ts +22 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-provider-lock.ts +4 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-receipt-limit.ts +4 -4
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-record.ts +17 -58
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-request.ts +10 -8
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-revoke.ts +18 -15
- package/packages/bundled-features/src/billing-foundation/events.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/feature.ts +8 -3
- package/packages/bundled-features/src/billing-foundation/get-subscription-for-tenant.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/handlers/process-event.write.ts +5 -5
- package/packages/bundled-features/src/billing-foundation/handlers/process-payment-event.write.ts +3 -3
- package/packages/bundled-features/src/billing-foundation/plan-catalog.ts +2 -2
- package/packages/bundled-features/src/billing-foundation/projection.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/types.ts +1 -1
- package/packages/bundled-features/src/cap-counter/aggregate-id.ts +1 -1
- package/packages/bundled-features/src/cap-counter/book-cap-usage.ts +5 -4
- package/packages/bundled-features/src/cap-counter/cap-reservation.ts +21 -8
- package/packages/bundled-features/src/cap-counter/changes.json +12 -0
- package/packages/bundled-features/src/cap-counter/constants.ts +1 -1
- package/packages/bundled-features/src/cap-counter/feature.ts +3 -2
- package/packages/bundled-features/src/cap-counter/handlers/increment-rolling.write.ts +1 -1
- package/packages/bundled-features/src/cap-counter/reservation-chain.ts +1 -1
- package/packages/bundled-features/src/cap-counter/with-cap-enforcement.ts +4 -4
- package/packages/bundled-features/src/cap-overview/feature.ts +1 -0
- package/packages/bundled-features/src/cap-overview/handlers/caps-usage.query.ts +1 -1
- package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +1 -1
- package/packages/bundled-features/src/compliance-profiles/seeding.ts +12 -7
- package/packages/bundled-features/src/config/changes.json +6 -0
- package/packages/bundled-features/src/config/feature.ts +6 -6
- package/packages/bundled-features/src/config/handlers/cascade.query.ts +1 -1
- package/packages/bundled-features/src/config/handlers/readiness.query.ts +1 -1
- package/packages/bundled-features/src/config/handlers/reencrypt.job.ts +23 -13
- package/packages/bundled-features/src/config/handlers/reset.write.ts +3 -3
- package/packages/bundled-features/src/config/handlers/selected-extensions.query.ts +1 -1
- package/packages/bundled-features/src/config/handlers/set.write.ts +22 -5
- package/packages/bundled-features/src/config/handlers/values.query.ts +1 -1
- package/packages/bundled-features/src/crypto-shredding/changes.json +12 -0
- package/packages/bundled-features/src/crypto-shredding/handlers/forget-subject.write.ts +9 -9
- package/packages/bundled-features/src/crypto-shredding/resolve-file-bytes-deleter.ts +3 -3
- package/packages/bundled-features/src/custom-fields/changes.json +6 -0
- package/packages/bundled-features/src/custom-fields/handlers/clear-custom-field.write.ts +1 -1
- package/packages/bundled-features/src/custom-fields/handlers/delete-system-field.write.ts +1 -1
- package/packages/bundled-features/src/custom-fields/handlers/delete-tenant-field.write.ts +1 -1
- package/packages/bundled-features/src/custom-fields/handlers/set-custom-field.write.ts +1 -1
- package/packages/bundled-features/src/custom-fields/index.ts +4 -0
- package/packages/bundled-features/src/custom-fields/lib/parse-serialized-field.ts +1 -1
- package/packages/bundled-features/src/data-retention/feature.ts +1 -1
- package/packages/bundled-features/src/data-retention/run-retention-cleanup.ts +12 -2
- package/packages/bundled-features/src/delivery/attempt-log.ts +1 -1
- package/packages/bundled-features/src/delivery/changes.json +12 -0
- package/packages/bundled-features/src/delivery/delivery-service.ts +6 -5
- package/packages/bundled-features/src/delivery/feature.ts +3 -2
- package/packages/bundled-features/src/delivery/index.ts +5 -0
- package/packages/bundled-features/src/delivery/jobs.ts +11 -11
- package/packages/bundled-features/src/delivery/system-channel-context.ts +33 -0
- package/packages/bundled-features/src/delivery/testing.ts +1 -1
- package/packages/bundled-features/src/document-ingest-foundation/append-missing-extract-event.ts +84 -0
- package/packages/bundled-features/src/document-ingest-foundation/changes.json +6 -0
- package/packages/bundled-features/src/document-ingest-foundation/events.ts +16 -1
- package/packages/bundled-features/src/document-ingest-foundation/index.ts +11 -0
- package/packages/bundled-features/src/feature-toggles/feature.ts +1 -0
- package/packages/bundled-features/src/feature-toggles/handlers/registered.query.ts +1 -1
- package/packages/bundled-features/src/feature-toggles/handlers/set.write.ts +1 -1
- package/packages/bundled-features/src/feature-toggles/toggle-sync-signal.ts +1 -1
- package/packages/bundled-features/src/file-derivatives/feature.ts +2 -2
- package/packages/bundled-features/src/file-derivatives/handlers/public-variant-by-file-ref.query.ts +5 -1
- package/packages/bundled-features/src/file-derivatives/handlers/public-variant.query.ts +7 -5
- package/packages/bundled-features/src/file-foundation/feature.ts +1 -1
- package/packages/bundled-features/src/file-foundation/read-file-ref-content.ts +7 -5
- package/packages/bundled-features/src/file-provider-s3/feature.ts +4 -1
- package/packages/bundled-features/src/files-tenant-data/handlers/sweep-orphaned-derivatives.job.ts +8 -8
- package/packages/bundled-features/src/form-draft/feature.ts +1 -1
- package/packages/bundled-features/src/form-draft/handlers/cleanup.job.ts +22 -12
- package/packages/bundled-features/src/form-draft/handlers/discard.write.ts +3 -3
- package/packages/bundled-features/src/form-draft/handlers/get.query.ts +1 -1
- package/packages/bundled-features/src/foundation-shared/config-helpers.ts +1 -1
- package/packages/bundled-features/src/host-routing/changes.json +6 -0
- package/packages/bundled-features/src/host-routing/validate-options.ts +5 -0
- package/packages/bundled-features/src/inbound-mail-foundation/events.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +2 -1
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/account-state.ts +2 -2
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/connect-account.write.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/disconnect-account.write.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/ingest-message.write.ts +10 -10
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/update-account.write.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/projection.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +1 -1
- package/packages/bundled-features/src/inbound-provider-imap/feature.ts +4 -1
- package/packages/bundled-features/src/jobs/changes.json +6 -0
- package/packages/bundled-features/src/jobs/events.ts +1 -1
- package/packages/bundled-features/src/jobs/feature.ts +1 -0
- package/packages/bundled-features/src/jobs/handlers/consumer.write.ts +7 -4
- package/packages/bundled-features/src/jobs/handlers/projection-rebuild.job.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/reindex-entity.job.ts +11 -5
- package/packages/bundled-features/src/jobs/handlers/retention-cleanup.job.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/retry.write.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/stale-run-sweep.job.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/trigger.write.ts +2 -2
- package/packages/bundled-features/src/jobs/job-run-logger.ts +139 -90
- package/packages/bundled-features/src/ledger/web/index.ts +1 -1
- package/packages/bundled-features/src/legal-pages/README.md +1 -1
- package/packages/bundled-features/src/legal-pages/lib/boot-check.ts +12 -8
- package/packages/bundled-features/src/legal-pages/seed.ts +5 -2
- package/packages/bundled-features/src/mail-foundation/feature.ts +2 -2
- package/packages/bundled-features/src/mail-transport-smtp/changes.json +12 -0
- package/packages/bundled-features/src/mail-transport-smtp/config-keys.ts +1 -1
- package/packages/bundled-features/src/mail-transport-smtp/feature.ts +13 -12
- package/packages/bundled-features/src/managed-pages/changes.json +6 -0
- package/packages/bundled-features/src/managed-pages/constants.ts +1 -0
- package/packages/bundled-features/src/managed-pages/feature.ts +3 -1
- package/packages/bundled-features/src/managed-pages/index.ts +1 -0
- package/packages/bundled-features/src/managed-pages/seeding.ts +13 -8
- package/packages/bundled-features/src/notes-history/handlers/add-note.write.ts +2 -2
- package/packages/bundled-features/src/personal-access-tokens/feature.ts +2 -1
- package/packages/bundled-features/src/personal-access-tokens/handlers/create.write.ts +2 -2
- package/packages/bundled-features/src/personal-access-tokens/handlers/revoke.write.ts +1 -1
- package/packages/bundled-features/src/rate-limiting/handlers/status.query.ts +2 -2
- package/packages/bundled-features/src/readiness/handlers/status.query.ts +4 -1
- package/packages/bundled-features/src/renderer-foundation/api.ts +3 -3
- package/packages/bundled-features/src/secrets/announce-secret-change.ts +4 -4
- package/packages/bundled-features/src/secrets/changes.json +6 -0
- package/packages/bundled-features/src/secrets/feature.ts +9 -9
- package/packages/bundled-features/src/secrets/handlers/delete.write.ts +4 -3
- package/packages/bundled-features/src/secrets/handlers/rotate.job.ts +13 -8
- package/packages/bundled-features/src/secrets/handlers/set.write.ts +4 -3
- package/packages/bundled-features/src/secrets/secrets-context.ts +16 -6
- package/packages/bundled-features/src/secrets/write-gate.ts +10 -3
- package/packages/bundled-features/src/seo/feature.ts +1 -1
- package/packages/bundled-features/src/sessions/changes.json +19 -0
- package/packages/bundled-features/src/sessions/feature.ts +2 -1
- package/packages/bundled-features/src/sessions/handlers/cleanup.job.ts +2 -2
- package/packages/bundled-features/src/sessions/handlers/detail.query.ts +5 -2
- package/packages/bundled-features/src/sessions/handlers/list.query.ts +5 -2
- package/packages/bundled-features/src/sessions/handlers/mine.query.ts +5 -2
- package/packages/bundled-features/src/sessions/handlers/revoke-all-for-user.write.ts +3 -3
- package/packages/bundled-features/src/sessions/handlers/revoke-all-others.write.ts +1 -1
- package/packages/bundled-features/src/sessions/handlers/revoke.write.ts +1 -1
- package/packages/bundled-features/src/sessions/index.ts +1 -1
- package/packages/bundled-features/src/sessions/screens.ts +8 -4
- package/packages/bundled-features/src/sessions/session-callbacks.ts +1 -9
- package/packages/bundled-features/src/sessions/session-revoked-event.ts +1 -1
- package/packages/bundled-features/src/sessions/web/session-device-cell.tsx +10 -12
- package/packages/bundled-features/src/sessions/web/user-agent.ts +12 -0
- package/packages/bundled-features/src/shared/index.ts +15 -0
- package/packages/bundled-features/src/shared/purge-files-reaching-subject.ts +36 -4
- package/packages/bundled-features/src/shared/require-for-tenant.ts +7 -5
- package/packages/bundled-features/src/shared/run-in-sub-transaction.ts +5 -5
- package/packages/bundled-features/src/shared/stream-tenant-backfill.ts +201 -0
- package/packages/bundled-features/src/shared/stream-tenant-derived-state.ts +107 -0
- package/packages/bundled-features/src/step-dispatcher/changes.json +6 -0
- package/packages/bundled-features/src/step-dispatcher/deliver-dispatch-request.ts +17 -3
- package/packages/bundled-features/src/step-dispatcher/feature.ts +1 -1
- package/packages/bundled-features/src/step-dispatcher/mail-runner.ts +2 -1
- package/packages/bundled-features/src/subscription-dodo/plugin-methods.ts +1 -1
- package/packages/bundled-features/src/subscription-dodo/runtime.ts +7 -7
- package/packages/bundled-features/src/subscription-stripe/plugin-methods.ts +5 -3
- package/packages/bundled-features/src/subscription-stripe/runtime.ts +7 -7
- package/packages/bundled-features/src/tags/feature.ts +1 -0
- package/packages/bundled-features/src/template-resolver/api.ts +3 -3
- package/packages/bundled-features/src/template-resolver/changes.json +54 -0
- package/packages/bundled-features/src/template-resolver/document-ops.ts +20 -1
- package/packages/bundled-features/src/template-resolver/feature.ts +2 -2
- package/packages/bundled-features/src/template-resolver/handlers/bundle-import.ts +5 -4
- package/packages/bundled-features/src/template-resolver/handlers/copy-locale.write.ts +2 -2
- package/packages/bundled-features/src/template-resolver/handlers/export-bundle.query.ts +1 -1
- package/packages/bundled-features/src/template-resolver/handlers/layout-source.query.ts +36 -11
- package/packages/bundled-features/src/template-resolver/handlers/overview.query.ts +32 -7
- package/packages/bundled-features/src/template-resolver/handlers/patch-draft.write.ts +1 -1
- package/packages/bundled-features/src/template-resolver/handlers/send-test-shared.ts +1 -1
- package/packages/bundled-features/src/template-resolver/handlers/send-test-status.query.ts +22 -19
- package/packages/bundled-features/src/template-resolver/handlers/send-test.write.ts +2 -2
- package/packages/bundled-features/src/template-resolver/handlers/tenant-override-selection.ts +6 -2
- package/packages/bundled-features/src/template-resolver/handlers/tenant-overrides.query.ts +4 -2
- package/packages/bundled-features/src/template-resolver/handlers/usage.query.ts +1 -1
- package/packages/bundled-features/src/template-resolver/seeding.ts +22 -5
- package/packages/bundled-features/src/template-resolver/store-template-resource.ts +68 -19
- package/packages/bundled-features/src/template-resolver/template-resources.ts +4 -4
- package/packages/bundled-features/src/template-resolver/testing.ts +2 -2
- package/packages/bundled-features/src/template-resolver/web/document-insert-fields.tsx +222 -0
- package/packages/bundled-features/src/template-resolver/web/document-insert-model.ts +164 -0
- package/packages/bundled-features/src/template-resolver/web/document-insert-panel.tsx +115 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-bubble.tsx +177 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-content.tsx +38 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-context.ts +119 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-editor.tsx +51 -1098
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-helpers.ts +161 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-layout.tsx +83 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-toolbar-groups.tsx +153 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-toolbar.tsx +182 -0
- package/packages/bundled-features/src/template-resolver/web/editor-handle.ts +18 -0
- package/packages/bundled-features/src/template-resolver/web/i18n.ts +6 -0
- package/packages/bundled-features/src/template-resolver/web/placeholder-line-editor.tsx +19 -6
- package/packages/bundled-features/src/template-resolver/web/qualified-names.ts +1 -0
- package/packages/bundled-features/src/template-resolver/web/use-document-tiptap-model.ts +138 -0
- package/packages/bundled-features/src/tenant/changes.json +19 -0
- package/packages/bundled-features/src/tenant/feature.ts +1 -0
- package/packages/bundled-features/src/tenant/handlers/cancel-invitation.write.ts +1 -1
- package/packages/bundled-features/src/tenant/handlers/memberships.query.ts +1 -1
- package/packages/bundled-features/src/tenant/handlers/remove-member.write.ts +2 -2
- package/packages/bundled-features/src/tenant/handlers/team-list.query.ts +3 -3
- package/packages/bundled-features/src/tenant/handlers/update-member-roles.write.ts +1 -1
- package/packages/bundled-features/src/tenant/index.ts +5 -0
- package/packages/bundled-features/src/tenant/invited-membership.ts +6 -1
- package/packages/bundled-features/src/tenant/schema/tenant.ts +4 -1
- package/packages/bundled-features/src/tenant/seeding.ts +65 -62
- package/packages/bundled-features/src/tenant/stream-tenant-backfill.ts +115 -0
- package/packages/bundled-features/src/tenant/testing.ts +77 -0
- package/packages/bundled-features/src/tenant-handover/events.ts +1 -1
- package/packages/bundled-features/src/tenant-handover/handlers/claim.write.ts +1 -1
- package/packages/bundled-features/src/tenant-lifecycle/changes.json +6 -0
- package/packages/bundled-features/src/tenant-lifecycle/feature.ts +5 -5
- package/packages/bundled-features/src/tenant-lifecycle/handlers/cancel-destruction.write.ts +22 -10
- package/packages/bundled-features/src/tenant-lifecycle/handlers/request-destruction.write.ts +22 -11
- package/packages/bundled-features/src/tenant-lifecycle/run-tenant-destroy.ts +23 -12
- package/packages/bundled-features/src/tenant-lifecycle/stages.ts +42 -4
- package/packages/bundled-features/src/tenant-lifecycle/testing.ts +9 -8
- package/packages/bundled-features/src/tier-engine/entity.ts +1 -1
- package/packages/bundled-features/src/tier-engine/feature.ts +8 -3
- package/packages/bundled-features/src/tier-engine/handlers/active-tier.query.ts +3 -3
- package/packages/bundled-features/src/tier-engine/handlers/get-tenant-tier.query.ts +7 -1
- package/packages/bundled-features/src/tier-engine/handlers/set-tenant-tier.write.ts +3 -3
- package/packages/bundled-features/src/user/db/queries/stream-tenant-backfill.ts +71 -97
- package/packages/bundled-features/src/user/feature.ts +1 -0
- package/packages/bundled-features/src/user/handlers/find-for-auth.query.ts +2 -2
- package/packages/bundled-features/src/user/handlers/update-roles.ts +2 -2
- package/packages/bundled-features/src/user/index.ts +2 -0
- package/packages/bundled-features/src/user/invited-global-roles.ts +6 -1
- package/packages/bundled-features/src/user/principal-status.ts +1 -1
- package/packages/bundled-features/src/user/seeding.ts +24 -6
- package/packages/bundled-features/src/user/testing.ts +22 -0
- package/packages/bundled-features/src/user-data-rights/COMPLIANCE.md +1 -1
- package/packages/bundled-features/src/user-data-rights/README.md +1 -1
- package/packages/bundled-features/src/user-data-rights/audit-download.ts +12 -2
- package/packages/bundled-features/src/user-data-rights/changes.json +36 -0
- package/packages/bundled-features/src/user-data-rights/feature.ts +30 -24
- package/packages/bundled-features/src/user-data-rights/handlers/confirm-deletion-by-token.write.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/handlers/deletion-grace-period.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/handlers/download-by-job.query.ts +2 -2
- package/packages/bundled-features/src/user-data-rights/handlers/download-by-token.query.ts +2 -2
- package/packages/bundled-features/src/user-data-rights/handlers/request-deletion.write.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/handlers/restrict-account.write.ts +4 -4
- package/packages/bundled-features/src/user-data-rights/handlers/run-forget-cleanup.write.ts +12 -6
- package/packages/bundled-features/src/user-data-rights/index.ts +8 -1
- package/packages/bundled-features/src/user-data-rights/lib/mail-transport-resolver.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/lib/storage-provider-resolver.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/lib/update-user-lifecycle.ts +6 -1
- package/packages/bundled-features/src/user-data-rights/run-export-jobs.ts +8 -2
- package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +14 -3
- package/packages/bundled-features/src/user-data-rights/run-user-export.ts +11 -1
- package/packages/bundled-features/src/user-data-rights/web/constants.ts +16 -0
- package/packages/bundled-features/src/user-data-rights/web/index.ts +6 -0
- package/packages/bundled-features/src/user-profile/handlers/change-email.write.ts +8 -6
- package/packages/bundled-features/src/waitlist/changes.json +18 -0
- package/packages/bundled-features/src/waitlist/feature.ts +1 -0
- package/packages/bundled-features/src/waitlist/handlers/export-purge.write.ts +1 -1
- package/packages/bundled-features/src/waitlist/handlers/invite.write.ts +2 -2
- package/packages/bundled-features/src/waitlist/handlers/reject.write.ts +1 -1
- package/packages/bundled-features/src/waitlist/handlers/submit.write.ts +34 -10
- package/packages/bundled-features/src/waitlist/import.ts +23 -3
- package/packages/bundled-features/src/waitlist/legacy-migrate.ts +8 -2
- package/packages/bundled-features/src/waitlist/link-on-signup.ts +7 -1
- package/packages/bundled-features/src/waitlist/options.ts +2 -1
- package/packages/bundled-features/src/workflow-runner/changes.json +6 -0
- package/packages/bundled-features/src/workflow-runner/db/queries/due-runs.ts +1 -1
- package/packages/bundled-features/src/workflow-runner/event-subscriber.ts +4 -3
- package/packages/bundled-features/src/workflow-runner/event-trigger.ts +2 -1
- package/packages/bundled-features/src/workflow-runner/feature.ts +2 -2
- package/packages/bundled-features/src/workflow-runner/handlers/resume-run.write.ts +8 -8
- package/packages/bundled-features/src/workflow-runner/runner.ts +6 -4
- package/samples/apps/cap-billing-demo/src/feature.ts +19 -5
- package/samples/apps/config-demo/src/app/server.ts +1 -1
- package/samples/apps/styleguide/src/app/client.tsx +2 -0
- package/samples/apps/styleguide/src/app/seed.ts +6 -4
- package/samples/apps/styleguide/src/app/server.ts +6 -3
- package/samples/apps/styleguide/src/features/widgets/feature.ts +15 -4
- package/samples/apps/styleguide/src/features/workboard/feature.ts +185 -0
- package/samples/apps/styleguide/src/features/workboard/i18n.ts +27 -0
- package/samples/apps/styleguide/src/features/workboard/seed.ts +121 -0
- package/samples/apps/styleguide/src/features/workboard/web.ts +13 -0
- package/samples/apps/ui-walkthrough/src/features/rental/i18n.ts +2 -0
- package/samples/apps/ui-walkthrough/src/features/rental/screens.ts +9 -0
- package/samples/apps/use-all-bundled/bin/main.ts +2 -0
- package/samples/apps/use-all-bundled/feature-manifest.json +17 -1
- package/samples/apps/use-all-bundled/kumiko/schema.ts +2 -0
- package/samples/apps/use-all-bundled/kumiko.config.ts +2 -0
- package/samples/apps/use-all-bundled/package.json +2 -1
- package/samples/apps/use-all-bundled/src/app/dev-app-options.ts +2 -0
- package/samples/apps/use-all-bundled/src/app/notes-feature.ts +2 -0
- package/samples/apps/use-all-bundled/src/app/seed.ts +12 -2
- package/samples/apps/use-all-bundled/src/bundled-lists.ts +15 -0
- package/samples/apps/user-data-rights-demo/README.md +1 -1
- package/samples/apps/user-data-rights-demo/src/feature.ts +3 -2
- package/samples/recipes/api-worker-split/README.md +2 -1
- package/samples/recipes/api-worker-split/src/feature.ts +2 -1
- package/samples/recipes/cross-feature-events/README.md +5 -5
- package/samples/recipes/cross-feature-events/package.json +1 -1
- package/samples/recipes/cross-feature-events/src/feature.ts +4 -4
- package/samples/recipes/event-sourcing/README.md +5 -5
- package/samples/recipes/event-sourcing/package.json +1 -1
- package/samples/recipes/event-sourcing/src/feature.ts +15 -15
- package/samples/recipes/files-post-processing/README.md +1 -1
- package/samples/recipes/files-post-processing/package.json +1 -1
- package/samples/recipes/files-post-processing/src/feature.ts +6 -4
- package/samples/recipes/golden-path/src/feature.ts +2 -1
- package/samples/recipes/lane-routing/package.json +1 -1
- package/samples/recipes/legal-pages/README.md +2 -2
- package/samples/recipes/lifecycle-hooks/README.md +4 -0
- package/samples/recipes/lifecycle-hooks/src/feature.ts +26 -1
- package/samples/recipes/list-table-options/README.md +50 -0
- package/samples/recipes/list-table-options/package.json +11 -0
- package/samples/recipes/list-table-options/src/feature.ts +221 -0
- package/samples/recipes/managed-config/README.md +3 -3
- package/samples/recipes/pdf-audit-export/src/feature.ts +2 -1
- package/samples/recipes/search/README.md +1 -1
- package/samples/recipes/search/src/feature.ts +3 -3
- package/samples/recipes/secrets-demo/README.md +1 -1
- package/samples/recipes/secrets-demo/src/feature.ts +5 -2
- package/samples/recipes/state-machine/src/events.ts +4 -3
- package/samples/recipes/state-machine/src/reducer.ts +1 -1
- package/samples/recipes/tenant-isolation/README.md +1 -0
- package/samples/recipes/tenant-isolation/src/feature.ts +36 -0
- package/samples/recipes/workflow-engine/src/resume-loop.ts +4 -4
- package/samples/recipes/workflow-engine/src/workflow-runner.ts +2 -2
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type { SeedFn } from "@cosmicdrift/kumiko-dev-server";
|
|
2
|
+
import { TestUsers } from "@cosmicdrift/kumiko-framework/seeding";
|
|
3
|
+
|
|
4
|
+
type SeedTask = {
|
|
5
|
+
readonly title: string;
|
|
6
|
+
readonly status: "open" | "inProgress" | "blocked" | "done";
|
|
7
|
+
readonly priority: "low" | "medium" | "high";
|
|
8
|
+
readonly dueDate: string;
|
|
9
|
+
readonly assignee: string;
|
|
10
|
+
readonly estimateHours: number;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const TASKS: readonly SeedTask[] = [
|
|
14
|
+
{
|
|
15
|
+
title: "Quarterly VAT filing",
|
|
16
|
+
status: "inProgress",
|
|
17
|
+
priority: "high",
|
|
18
|
+
dueDate: "2026-11-10",
|
|
19
|
+
assignee: "Ines Vogel",
|
|
20
|
+
estimateHours: 6,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
title: "Renew office lease",
|
|
24
|
+
status: "open",
|
|
25
|
+
priority: "medium",
|
|
26
|
+
dueDate: "2026-12-01",
|
|
27
|
+
assignee: "Tomas Berg",
|
|
28
|
+
estimateHours: 3,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
title: "Onboard new support hire",
|
|
32
|
+
status: "open",
|
|
33
|
+
priority: "high",
|
|
34
|
+
dueDate: "2026-11-03",
|
|
35
|
+
assignee: "Ines Vogel",
|
|
36
|
+
estimateHours: 12,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
title: "Migrate invoices to new numbering",
|
|
40
|
+
status: "blocked",
|
|
41
|
+
priority: "high",
|
|
42
|
+
dueDate: "2026-11-15",
|
|
43
|
+
assignee: "Mara Lindqvist",
|
|
44
|
+
estimateHours: 16,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
title: "Update privacy policy",
|
|
48
|
+
status: "done",
|
|
49
|
+
priority: "medium",
|
|
50
|
+
dueDate: "2026-10-20",
|
|
51
|
+
assignee: "Tomas Berg",
|
|
52
|
+
estimateHours: 4,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
title: "Order replacement laptops",
|
|
56
|
+
status: "inProgress",
|
|
57
|
+
priority: "low",
|
|
58
|
+
dueDate: "2026-11-25",
|
|
59
|
+
assignee: "Mara Lindqvist",
|
|
60
|
+
estimateHours: 2,
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
title: "Prepare annual audit documents",
|
|
64
|
+
status: "open",
|
|
65
|
+
priority: "high",
|
|
66
|
+
dueDate: "2027-01-15",
|
|
67
|
+
assignee: "Ines Vogel",
|
|
68
|
+
estimateHours: 24,
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
title: "Fix mobile checkout layout",
|
|
72
|
+
status: "inProgress",
|
|
73
|
+
priority: "medium",
|
|
74
|
+
dueDate: "2026-11-05",
|
|
75
|
+
assignee: "Jonas Keller",
|
|
76
|
+
estimateHours: 8,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
title: "Review supplier contracts",
|
|
80
|
+
status: "blocked",
|
|
81
|
+
priority: "medium",
|
|
82
|
+
dueDate: "2026-11-30",
|
|
83
|
+
assignee: "Tomas Berg",
|
|
84
|
+
estimateHours: 10,
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
title: "Archive 2025 customer files",
|
|
88
|
+
status: "done",
|
|
89
|
+
priority: "low",
|
|
90
|
+
dueDate: "2026-10-31",
|
|
91
|
+
assignee: "Jonas Keller",
|
|
92
|
+
estimateHours: 5,
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
title: "Plan team offsite",
|
|
96
|
+
status: "open",
|
|
97
|
+
priority: "low",
|
|
98
|
+
dueDate: "2027-02-20",
|
|
99
|
+
assignee: "Mara Lindqvist",
|
|
100
|
+
estimateHours: 7,
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
title: "Set up weekly sales report",
|
|
104
|
+
status: "inProgress",
|
|
105
|
+
priority: "medium",
|
|
106
|
+
dueDate: "2026-11-12",
|
|
107
|
+
assignee: "Jonas Keller",
|
|
108
|
+
estimateHours: 9,
|
|
109
|
+
},
|
|
110
|
+
];
|
|
111
|
+
|
|
112
|
+
export const seedWorkboardTasks: SeedFn = async (stack) => {
|
|
113
|
+
for (const task of TASKS) {
|
|
114
|
+
const res = await stack.http.write("workboard:write:task:create", task, TestUsers.admin);
|
|
115
|
+
if (!res.ok) {
|
|
116
|
+
// biome-ignore lint/suspicious/noConsole: dev-seed surfaces failures in the runner log
|
|
117
|
+
console.error(`[seed] workboard task "${task.title}" failed:`, await res.text());
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ClientFeatureDefinition,
|
|
3
|
+
TranslationsByLocale,
|
|
4
|
+
} from "@cosmicdrift/kumiko-renderer/web";
|
|
5
|
+
import { toClientTranslations } from "../shared-i18n";
|
|
6
|
+
import { WORKBOARD_I18N } from "./i18n";
|
|
7
|
+
|
|
8
|
+
const translations: TranslationsByLocale = toClientTranslations(WORKBOARD_I18N);
|
|
9
|
+
|
|
10
|
+
export const workboardClient: ClientFeatureDefinition = {
|
|
11
|
+
name: "workboard",
|
|
12
|
+
translations,
|
|
13
|
+
};
|
|
@@ -50,6 +50,7 @@ export const rentalTranslations: TranslationsByLocale = {
|
|
|
50
50
|
"rental.party.role.main": "Hauptmieter",
|
|
51
51
|
"rental.party.role.co": "Mitmieterin",
|
|
52
52
|
"rental.action.addParty": "Partei hinzufügen",
|
|
53
|
+
"rental.action.showTerminated": "Beendete Verträge",
|
|
53
54
|
|
|
54
55
|
"rental.tab.parties": "Vertragsparteien",
|
|
55
56
|
"rental.tab.positions": "Positionen",
|
|
@@ -214,6 +215,7 @@ export const rentalTranslations: TranslationsByLocale = {
|
|
|
214
215
|
"rental.party.role.main": "Main tenant",
|
|
215
216
|
"rental.party.role.co": "Co-tenant",
|
|
216
217
|
"rental.action.addParty": "Add party",
|
|
218
|
+
"rental.action.showTerminated": "Terminated leases",
|
|
217
219
|
|
|
218
220
|
"rental.tab.parties": "Parties",
|
|
219
221
|
"rental.tab.positions": "Positions",
|
|
@@ -52,6 +52,15 @@ export const leaseListScreen: EntityListScreenDefinition = {
|
|
|
52
52
|
pageSize: 25,
|
|
53
53
|
createLabel: "rental.action.createLease",
|
|
54
54
|
searchPlaceholder: "rental.search.placeholder",
|
|
55
|
+
toolbarActions: [
|
|
56
|
+
{
|
|
57
|
+
kind: "navigate",
|
|
58
|
+
id: "show-terminated",
|
|
59
|
+
label: "rental.action.showTerminated",
|
|
60
|
+
style: "primary",
|
|
61
|
+
screen: "lease-list-short",
|
|
62
|
+
},
|
|
63
|
+
],
|
|
55
64
|
rowActions: [openLeaseDetail],
|
|
56
65
|
access: OPEN_ACCESS,
|
|
57
66
|
};
|
|
@@ -8,6 +8,7 @@ import { InMemoryKmsAdapter } from "@cosmicdrift/kumiko-framework/crypto";
|
|
|
8
8
|
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
9
9
|
import { composeEnvSchema } from "@cosmicdrift/kumiko-framework/env";
|
|
10
10
|
import { runProdApp } from "@cosmicdrift/kumiko-server-runtime";
|
|
11
|
+
import { BUNDLED_LISTS } from "../src/bundled-lists";
|
|
11
12
|
import {
|
|
12
13
|
APP_FEATURES,
|
|
13
14
|
AUTH_COMPOSE_OPTIONS,
|
|
@@ -27,6 +28,7 @@ await runProdApp({
|
|
|
27
28
|
featureToggles: true,
|
|
28
29
|
envSchema,
|
|
29
30
|
validateBootOptions: VALIDATE_BOOT_OPTIONS,
|
|
31
|
+
bundledLists: BUNDLED_LISTS,
|
|
30
32
|
// Smoke-only: exercises the hard PII boot gate + blind-index gate with
|
|
31
33
|
// every bundled feature mounted. Real apps wire createPgKmsAdapter(...).
|
|
32
34
|
kms: new InMemoryKmsAdapter(),
|
|
@@ -71,6 +71,7 @@
|
|
|
71
71
|
"name": "audit",
|
|
72
72
|
"description": "Exposes the framework's event store as a paginated, filterable audit log via the `audit:query:list` handler (accessible to `Admin` and `SystemAdmin` roles). No separate table or projection — the event store is the audit trail by construction: every entity write already records who, when, what entity, and the event payload with PII stripped. A SystemAdmin can pass `scope: \"system\"` to read the app-instance system events such as `app.started`, and reads the events of every tenant (system tenant excluded) through `audit:query:list-all-tenants` and the `audit-log-all-tenants` screen. Filter by `aggregateType`, `aggregateId`, `eventType`, `userId`, or time range. Also records `audit:event:escape-hatch-used` whenever a handler uses one of the framework's escape hatches (unsafeRaw, acknowledgeCrossTenant, db.global() writes, or a granted identity switch).",
|
|
73
73
|
"toggleableDefault": null,
|
|
74
|
+
"adoptsBundledLists": true,
|
|
74
75
|
"requires": [
|
|
75
76
|
"tenant",
|
|
76
77
|
"user",
|
|
@@ -232,6 +233,7 @@
|
|
|
232
233
|
"validated": false,
|
|
233
234
|
"options": [
|
|
234
235
|
"optional",
|
|
236
|
+
"systemAdmins",
|
|
235
237
|
"admins",
|
|
236
238
|
"all"
|
|
237
239
|
],
|
|
@@ -339,6 +341,7 @@
|
|
|
339
341
|
"name": "cap-counter",
|
|
340
342
|
"description": "Tracks per-tenant usage against configurable limits using two complementary storage models: calendar-period counters (one projection row per tenant/capName/period, reset implicitly by period rollover) and rolling-window counters (append-only event stream, no projection). Use `enforceCap` / `enforceRollingCap` (or the `withCapEnforcement` / `withRollingCapEnforcement` handler wrappers) in your write-handlers to check limits with soft-warn and hard-block tolerances; call `enforceCapAndMaybeNotify` when you also want to trigger a delivery notification on soft-threshold hits.",
|
|
341
343
|
"toggleableDefault": null,
|
|
344
|
+
"adoptsBundledLists": true,
|
|
342
345
|
"requires": [],
|
|
343
346
|
"optionalRequires": [],
|
|
344
347
|
"configReads": [],
|
|
@@ -362,6 +365,7 @@
|
|
|
362
365
|
"name": "cap-overview",
|
|
363
366
|
"description": "Read-only visibility into per-tenant tier assignment and cap usage. SystemAdmin gets a platform-wide tenant list with usage bars; tenant admins (or the roles in `usageVisibleTo`) get their own tenant's usage as dashboard cards. Reads tier-engine, billing-foundation, and tenant data plus app-owned usage tables via caller-supplied CapSpec callbacks — never writes.",
|
|
364
367
|
"toggleableDefault": null,
|
|
368
|
+
"adoptsBundledLists": true,
|
|
365
369
|
"requires": [
|
|
366
370
|
"tenant",
|
|
367
371
|
"tier-engine",
|
|
@@ -744,6 +748,7 @@
|
|
|
744
748
|
"name": "delivery",
|
|
745
749
|
"description": "The notification dispatch core: call `ctx.notify(notificationType, { to, route, data, priority, idempotencyKey })` from any handler to fan out a notification across all registered channels (email, in-app, push). Inside a write handler the delivery runs after the write has committed (the call returns `{ kind: \"deferred\" }`, a rolled-back write sends nothing); `immediate: true` delivers synchronously and returns `{ kind: \"dispatched\", deliveries }`. It stores per-user channel preferences in the `notification-preference` entity, opt-outs for no-account recipient addresses in `notification-address-opt-out` (keyed by a blind-index hash, never the plaintext address), logs every attempt to `store_delivery_attempts`, and enforces idempotency and rate-limiting — add `channel-email`, `channel-in-app`, or `channel-push` on top to actually send anything. Unsubscribe/resubscribe links are served by `createUnsubscribeRoutes({ secret })` mounted via the app's `extraRoutes` at `/api/delivery/unsubscribe` and `/api/delivery/resubscribe`: `GET /unsubscribe?token=` renders a confirmation page (no write), `POST /unsubscribe` performs the opt-out (RFC 8058 one-click, token from the form body or query), `POST /resubscribe` undoes it (JSON `{token}` or form body only, never the query — reachable by a mail-client link prefetcher) — sign links with `signUnsubscribeToken` / `signAddressUnsubscribeToken` using the same secret. `channel-email` sets `List-Unsubscribe` / `List-Unsubscribe-Post` automatically when a message's `data.unsubscribeUrl` points at the unsubscribe route. A notification declared with `unsubscribe: true` gets that link from delivery itself when the service has `unsubscribeLinks` (the `runProdApp` and `runDevApp` option `unsubscribe: { secret }` mounts the routes and wires it; base URL from `auth.publicOrigin`, `auth.mail.baseUrl` or `APP_BASE_URL`): user recipients get a user token, `route` recipients an address token (needs a blind-index key, otherwise no link); a `data.unsubscribeUrl` from the caller wins. `unsubscribe.tenantOrigin: (ctx) => origin | null` points the link at the tenant's own host (subdomain or custom domain, must serve this app's `/api`); null, a throw or a non-https value fall back to the app origin. The token carries the mail's locale, so the confirmation and result pages render in the mail's language. An app serving its own (e.g. legacy) unsubscribe links renders the same result page with `renderUnsubscribeResultPage({ kind, locale })`. To react to a no-account opt-out (e.g. remove the app's own subscriber row), declare `r.job(name, { trigger: { on: DeliveryHandlers.unsubscribeAddress } }, handler)` on a lane the app consumes: it runs after each committed opt-out, also an idempotent repeat, with `unsubscribeAddressPayloadSchema` (`addressHash`, `notificationType`, `channel`) as payload and the tenant in `ctx.triggeredBy.tenantId`; match the subscriber via `hashUnsubscribeAddress(email)`. Declare `unsubscribeUrl` as an optional template variable if the mail body shows it.",
|
|
746
750
|
"toggleableDefault": null,
|
|
751
|
+
"adoptsBundledLists": true,
|
|
747
752
|
"requires": [
|
|
748
753
|
"tenant"
|
|
749
754
|
],
|
|
@@ -895,6 +900,7 @@
|
|
|
895
900
|
"name": "feature-toggles",
|
|
896
901
|
"description": "Persists per-feature enabled/disabled state in the `store_global_feature_state` table and exposes a `set` write-handler plus `list`/`registered` query-handlers so operators can flip features at runtime without redeploying. Each API instance keeps an in-memory `GlobalFeatureToggleRuntime` snapshot (initialize it via `createFeatureToggleRuntime`, pass a `() => runtime` accessor to `createFeatureTogglesFeature`) that the dispatcher gate reads on every request; a `toggle-cache-sync` multi-stream projection with `delivery: \"shared\"` syncs the snapshot across instances whenever a `toggle-set` event is appended.",
|
|
897
902
|
"toggleableDefault": null,
|
|
903
|
+
"adoptsBundledLists": true,
|
|
898
904
|
"requires": [],
|
|
899
905
|
"optionalRequires": [],
|
|
900
906
|
"configReads": [],
|
|
@@ -914,7 +920,7 @@
|
|
|
914
920
|
},
|
|
915
921
|
{
|
|
916
922
|
"name": "file-derivatives",
|
|
917
|
-
"description": "Declares the `derivativeRenderer` extension point. `ctx.derivatives.variant(fileRefId, spec, name)` derives a variant of a tracked FileRef the first time it's requested and reuses the stored result afterwards (derive-on-first-use, keyed by a hash of the spec). Mount at least one `derivatives-*` renderer feature alongside this one — without a registered renderer for the FileRef's MIME type, every `variant(...)` call throws. Also declares the `derivativePublicPredicate` extension point (`r.useExtension(EXT_DERIVATIVE_PUBLIC_PREDICATE, '<entityType>', { isPublic })`) and, when `createFileDerivativesFeature({resolveApexTenant})` is passed a host-resolver, mounts an anonymous `GET {basePath}/:fileRefId/:variant` route that serves any variant name the FileRef's field declared in its `variants` for a FileRef whose entityType has a registered predicate returning true — default-deny (404) otherwise, same as an unknown FileRef or an undeclared variant name. The route's only rate-limit (`per: \"ip\"`) depends on the server's `trustedProxyHops` matching the deployment's actual reverse-proxy count — at the default 0 it ignores `x-forwarded-for` entirely, so every caller shares one bucket until that's configured. `publicTenantResolution: \"fileRef\"` keeps resolveApexTenant as the host gate but reads the variant from the FileRef row's own tenant instead of the host's, so one shared platform host serves every tenant's public variants — each FileRef-tenant's own `isPublic` predicate still default-denies. Also declares the `derivativeOverlayResolver` extension point (`r.useExtension(EXT_DERIVATIVE_OVERLAY_RESOLVER, '<entityType>', { resolve })`), used to turn a variant's `overlays[].dataToken` into the actual QR payload for that FileRef's entityType before the variant is rendered — a variant declaring a `qr` overlay throws at request-time if no resolver is registered for the FileRef's entityType.",
|
|
923
|
+
"description": "Declares the `derivativeRenderer` extension point. `ctx.services.derivatives.variant(fileRefId, spec, name)` derives a variant of a tracked FileRef the first time it's requested and reuses the stored result afterwards (derive-on-first-use, keyed by a hash of the spec). Mount at least one `derivatives-*` renderer feature alongside this one — without a registered renderer for the FileRef's MIME type, every `variant(...)` call throws. Also declares the `derivativePublicPredicate` extension point (`r.useExtension(EXT_DERIVATIVE_PUBLIC_PREDICATE, '<entityType>', { isPublic })`) and, when `createFileDerivativesFeature({resolveApexTenant})` is passed a host-resolver, mounts an anonymous `GET {basePath}/:fileRefId/:variant` route that serves any variant name the FileRef's field declared in its `variants` for a FileRef whose entityType has a registered predicate returning true — default-deny (404) otherwise, same as an unknown FileRef or an undeclared variant name. The route's only rate-limit (`per: \"ip\"`) depends on the server's `trustedProxyHops` matching the deployment's actual reverse-proxy count — at the default 0 it ignores `x-forwarded-for` entirely, so every caller shares one bucket until that's configured. `publicTenantResolution: \"fileRef\"` keeps resolveApexTenant as the host gate but reads the variant from the FileRef row's own tenant instead of the host's, so one shared platform host serves every tenant's public variants — each FileRef-tenant's own `isPublic` predicate still default-denies. Also declares the `derivativeOverlayResolver` extension point (`r.useExtension(EXT_DERIVATIVE_OVERLAY_RESOLVER, '<entityType>', { resolve })`), used to turn a variant's `overlays[].dataToken` into the actual QR payload for that FileRef's entityType before the variant is rendered — a variant declaring a `qr` overlay throws at request-time if no resolver is registered for the FileRef's entityType.",
|
|
918
924
|
"toggleableDefault": null,
|
|
919
925
|
"requires": [
|
|
920
926
|
"file-foundation",
|
|
@@ -1372,6 +1378,7 @@
|
|
|
1372
1378
|
"name": "inbound-mail-foundation",
|
|
1373
1379
|
"description": "Plugin host for inbound e-mail (inbox federation) — provider plugins (inbound-provider-imap, later M365 Graph / Gmail REST) register at the `inboundMailProvider` extension point with verify/fetch and optional oauth/watch (live push). The foundation owns three event-sourced streams (mail-account lifecycle, inbound-message with exactly-once ingest via deterministic aggregate ids, mail-thread rollup) and their projections `read_mail_accounts`/`read_inbound_messages`/`read_mail_threads`; PII fields are envelope-encrypted per tenant subject key before every append (crypto-shredding on tenant destroy). Wire `createInboundMailConnectRoutes` (OAuth connect + anonymous callback outside /api) and `createInboundMailSupervisor` (IDLE watch with backoff + reconciliation poll) in bin/server.ts. Consume `inbound-mail-foundation:event:inbound-message-received` from app features to attach business processes.",
|
|
1374
1380
|
"toggleableDefault": null,
|
|
1381
|
+
"adoptsBundledLists": true,
|
|
1375
1382
|
"requires": [
|
|
1376
1383
|
"tenant-lifecycle"
|
|
1377
1384
|
],
|
|
@@ -1464,6 +1471,7 @@
|
|
|
1464
1471
|
"name": "jobs",
|
|
1465
1472
|
"description": "Persistence and operator tooling for background jobs registered via `r.job(...)`. Every job execution writes directly into `store_job_runs` (current status + duration) and `store_job_run_logs` (per-line log rows) from the BullMQ callbacks — no event stream in between (#2243). A daily `retention-cleanup` job deletes runs (and their logs) older than `retentionDays`; an hourly `stale-run-sweep` job marks runs stuck at status `running` past `staleRunTimeoutHours` as `failed` (#2246 — a crashed worker never fires the completion callback, so nothing else ever revisits the row). Exposes `jobs:write:trigger` (manual run) and `jobs:write:retry` (operator retry of a failed run), plus `jobs:query:list`, `jobs:query:details`, and `jobs:query:catalog` (manual jobs) for the operator UI. A job that declares `tenantVisibleFailure` also records its last failed attempt per tenant and subject in `store_tenant_job_failures`, which the tenant itself reads through `jobs:query:failures` — a translation key only, never the provider's message (fw#3079). A job that declares `tenantVisibleRun` also keeps its run state per tenant and subject in `store_tenant_job_runs` (queued, running, plus the latest completed or failed run, no payload, error text or logs), which the tenant reads through `jobs:query:tenant-runs` (fw#3616); the stale-run sweep fails its stuck `running` rows and drops `queued` rows older than `retentionDays`.",
|
|
1466
1473
|
"toggleableDefault": null,
|
|
1474
|
+
"adoptsBundledLists": true,
|
|
1467
1475
|
"requires": [],
|
|
1468
1476
|
"optionalRequires": [],
|
|
1469
1477
|
"configReads": [],
|
|
@@ -1759,6 +1767,7 @@
|
|
|
1759
1767
|
"name": "managed-pages",
|
|
1760
1768
|
"description": "Tenant-editable, server-rendered public pages with per-tenant branding. Stores one Markdown `page` per `(tenantId, slug, lang)` in the `read_pages` entity table with a `published` gate plus `description`/`ogImage` SEO meta. Registers an anonymous `GET {basePath}/:slug` route that resolves the tenant from the request Host via the app-supplied `resolveApexTenant`, serves only published pages (drafts → 404), renders Markdown through the hardened `page-render` core, and isolates per-tenant content with `Vary: Host`. Ships TenantAdmin/SystemAdmin admin screens (`entityList` + `entityEdit`) backed by convention CRUD handlers (`managed-pages:write:page:{create,update,delete}`, `managed-pages:query:page:{list,detail}`); the app wires nav/workspace onto `managed-pages:screen:page-list`. Also exposes `managed-pages:query:by-tenant-published` (anonymous, SQL-filtered on `published`) for sitemap/discovery consumers such as the `seo` feature. Branding (via `config`, scope tenant): `branding-{title,description,site-url,accent-color,logo-url,layout-preset,custom-css}` keys with write-time validation (hex color, https URLs), a `configEdit` self-service screen (`managed-pages:screen:branding-settings`), and a `managed-pages:query:branding` read that the render path applies as scoped `:root` CSS vars + a logo/title header. Also exposes `managed-pages:write:set` (idempotent slug-keyed upsert, SystemAdmin cross-tenant via `tenantIdOverride`) as a provisioning API. Requires `config` + `anonymousAccess` wired at app bootstrap.",
|
|
1761
1769
|
"toggleableDefault": null,
|
|
1770
|
+
"adoptsBundledLists": true,
|
|
1762
1771
|
"requires": [
|
|
1763
1772
|
"config"
|
|
1764
1773
|
],
|
|
@@ -2088,6 +2097,7 @@
|
|
|
2088
2097
|
"name": "personal-access-tokens",
|
|
2089
2098
|
"description": "Long-lived, revocable Personal Access Tokens for headless HTTP-API access. Stores SHA-256 token hashes in the `store_api_tokens` direct-write table; the plaintext is returned once at creation. `create`/`revoke`/`mine` manage a user's own tokens and `available-scopes` lists the app-declared scope catalog. Bearer tokens carrying the PAT prefix are resolved before jwt.verify (roles resolved live, granted scopes enforced fail-closed at the API boundary) — registered as an auth-foundation tokenVerifier provider, resolved generically by the middleware. Pass { toggleable: { default: false } } to tier-gate the whole feature.",
|
|
2090
2099
|
"toggleableDefault": null,
|
|
2100
|
+
"adoptsBundledLists": true,
|
|
2091
2101
|
"requires": [
|
|
2092
2102
|
"user",
|
|
2093
2103
|
"tenant",
|
|
@@ -2417,6 +2427,7 @@
|
|
|
2417
2427
|
"name": "sessions",
|
|
2418
2428
|
"description": "Tracks signed-in clients in the `store_user_sessions` table (one row per JWT, keyed by the `sid`/`jti` claim) and exposes handlers for `mine` (list your sessions), `revoke`, and `revokeAllOthers`. Session creation and revocation on the hot auth path are handled by `createSessionCallbacks()`, wired into `buildServer({ auth: { ... } })` outside the dispatcher; the same callbacks are also registered as an auth-foundation sessionStore provider, resolvable generically via `resolveSessionStore()`. The feature also ships a manual-trigger cleanup job for pruning expired rows and an optional `autoRevokeOnPasswordChange` hook that mass-revokes all sessions for a user whenever their `passwordHash` changes.",
|
|
2419
2429
|
"toggleableDefault": null,
|
|
2430
|
+
"adoptsBundledLists": true,
|
|
2420
2431
|
"requires": [
|
|
2421
2432
|
"user",
|
|
2422
2433
|
"auth-foundation"
|
|
@@ -2711,6 +2722,7 @@
|
|
|
2711
2722
|
"name": "tags",
|
|
2712
2723
|
"description": "Generic, host-agnostic tagging for any entity. Owns two event-sourced entities — the per-tenant `tag` catalog (`read_tags`, with optional `color` and `scope`) and `tag-assignment` join rows keyed by (entityType, entityId) (`read_tag_assignments`) — so tagging adds NO column to the host entity and needs no relational pivot or JOIN. Catalog screens are declarative (`entityList` + `entityEdit`) and use convention QNs `tag:{create,update,delete}`; TagManager/TagPicker keep `create-tag`/`update-tag`/`delete-tag`. Also: `assign-tag` (idempotent), `remove-tag` (idempotent) and list queries for the catalog and the assignments. Read which tags an entity has, or which entities carry a tag, by listing `tag-assignment` filtered on `entityId` or `tagId` and composing in the read-layer. A tag with empty `scope` is global; a `scope` of an entityType restricts it to that type in the picker. Every path uses one access rule — adopt the host's model with createTagsFeature({ access: { openToAll: { reason } } }) or pin roles with createTagsFeature({ roles }). Pass { toggleable: { default: false } } to make the whole feature tier-gatable via the tier-engine (no host hook).",
|
|
2713
2724
|
"toggleableDefault": null,
|
|
2725
|
+
"adoptsBundledLists": true,
|
|
2714
2726
|
"requires": [],
|
|
2715
2727
|
"optionalRequires": [],
|
|
2716
2728
|
"configReads": [],
|
|
@@ -2826,6 +2838,7 @@
|
|
|
2826
2838
|
"name": "tenant",
|
|
2827
2839
|
"description": "Registers the three core multi-tenancy entities — `tenant`, `tenant-membership`, and `tenant-invitation` (DB tables `read_tenants`, `read_tenant_memberships`, and `read_tenant_invitations`) — along with write handlers for create/update/disable/enable/addMember/removeMember/updateMemberRoles and the matching queries. It also declares a set of per-tenant config keys (companyName, timezone, locale, SMTP credentials) and system-only keys (priceModel, maxUsers) via `r.config({ keys: { ... } })`. Use this feature in every multi-tenant app; membership resolution and invitation flows depend on it, and `auth-email-password` requires it.",
|
|
2828
2840
|
"toggleableDefault": null,
|
|
2841
|
+
"adoptsBundledLists": true,
|
|
2829
2842
|
"requires": [
|
|
2830
2843
|
"config"
|
|
2831
2844
|
],
|
|
@@ -3192,6 +3205,7 @@
|
|
|
3192
3205
|
"name": "user",
|
|
3193
3206
|
"description": "Manages the cross-tenant user identity: the `read_users` table holds each user's email, `displayName`, global `roles`, `emailVerified` flag, and lifecycle `status` (active / restricted / deletionRequested / deleted). Because users exist above any individual tenant, the feature runs with `r.systemScope()` — membership and tenant-specific roles live in the `tenant` feature instead. Add this feature whenever your app needs a persistent, tenant-agnostic user record that auth and GDPR pipelines can reference.",
|
|
3194
3207
|
"toggleableDefault": null,
|
|
3208
|
+
"adoptsBundledLists": true,
|
|
3195
3209
|
"requires": [],
|
|
3196
3210
|
"optionalRequires": [],
|
|
3197
3211
|
"configReads": [],
|
|
@@ -3219,6 +3233,7 @@
|
|
|
3219
3233
|
"name": "user-data-rights",
|
|
3220
3234
|
"description": "Implements GDPR Art. 15 (access / `my-audit-log` query), Art. 17 (erasure / `request-deletion` + `cancel-deletion`, plus the anonymous email-verified `request-deletion-by-email` + `confirm-deletion-by-token` flow for lockout-safe self-service, + cron cleanup with grace period), Art. 18 (restriction / `restrict-account` + `lift-restriction`), and Art. 20 (portability / async `request-export` → ZIP via `file-foundation`, Magic-Link download) as first-class HTTP handlers and cron jobs. Each domain feature opts in by calling `r.useExtension(EXT_USER_DATA, \"<entity>\", { export, delete })` — the feature then orchestrates the export and forget pipelines across all registered hooks automatically. When `mail-foundation` and a `mail-transport-*` are mounted, it also sends the four GDPR notifications (export ready/failed, deletion requested/executed) itself with no app callback code, rendered in each recipient’s locale. Requires `user`, `data-retention`, `compliance-profiles`, and `sessions`.",
|
|
3221
3235
|
"toggleableDefault": null,
|
|
3236
|
+
"adoptsBundledLists": true,
|
|
3222
3237
|
"requires": [
|
|
3223
3238
|
"user",
|
|
3224
3239
|
"data-retention",
|
|
@@ -3386,6 +3401,7 @@
|
|
|
3386
3401
|
"name": "waitlist",
|
|
3387
3402
|
"description": "Public waitlist: an anonymous, rate-limited `submit` handler collects name, email and optional company, portfolio and message (a honeypot field and per-email dedupe keep bots and repeat submits out, and the response body is identical whether or not an address was already listed), and mails the submitter a confirmation. SystemAdmins review entries in a list screen and invite or reject them; an invite creates the entrant's own tenant (or joins one shared tenant) and mails an accept link with the configured membership role, never a global role. Entries are platform-wide, their personal data is crypto-shredding-ready, and the EXT_USER_DATA hooks export and erase entries matching a user's email.",
|
|
3388
3403
|
"toggleableDefault": null,
|
|
3404
|
+
"adoptsBundledLists": true,
|
|
3389
3405
|
"requires": [
|
|
3390
3406
|
"tenant",
|
|
3391
3407
|
"auth-email-password",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import { collectTableMetas, type EntityTableMeta } from "@cosmicdrift/kumiko-framework/db";
|
|
12
12
|
import type { FeatureDefinition } from "@cosmicdrift/kumiko-framework/engine";
|
|
13
13
|
import { composeFeatures } from "@cosmicdrift/kumiko-server-runtime/compose-features";
|
|
14
|
+
import { BUNDLED_LISTS } from "../src/bundled-lists";
|
|
14
15
|
import { APP_FEATURES, AUTH_COMPOSE_OPTIONS, VALIDATE_BOOT_OPTIONS } from "../src/run-config";
|
|
15
16
|
|
|
16
17
|
export { VALIDATE_BOOT_OPTIONS };
|
|
@@ -18,6 +19,7 @@ export { VALIDATE_BOOT_OPTIONS };
|
|
|
18
19
|
export const FEATURES: readonly FeatureDefinition[] = composeFeatures(APP_FEATURES, {
|
|
19
20
|
includeBundled: true,
|
|
20
21
|
authOptions: AUTH_COMPOSE_OPTIONS,
|
|
22
|
+
bundledLists: BUNDLED_LISTS,
|
|
21
23
|
});
|
|
22
24
|
|
|
23
25
|
// collectTableMetas erfasst neben entities auch
|
|
@@ -12,11 +12,13 @@ import {
|
|
|
12
12
|
} from "@cosmicdrift/kumiko-server-runtime/compose-features";
|
|
13
13
|
import { notesFeature } from "./src/app/notes-feature";
|
|
14
14
|
import { appScreensFeature } from "./src/app/screens-feature";
|
|
15
|
+
import { BUNDLED_LISTS } from "./src/bundled-lists";
|
|
15
16
|
import { APP_FEATURES, AUTH_COMPOSE_OPTIONS } from "./src/run-config";
|
|
16
17
|
|
|
17
18
|
export default {
|
|
18
19
|
features: composeFeatures([...APP_FEATURES, appScreensFeature, notesFeature], {
|
|
19
20
|
includeBundled: true,
|
|
21
|
+
bundledLists: BUNDLED_LISTS,
|
|
20
22
|
...(buildComposeAuthOptions(AUTH_COMPOSE_OPTIONS) !== undefined && {
|
|
21
23
|
authOptions: buildComposeAuthOptions(AUTH_COMPOSE_OPTIONS),
|
|
22
24
|
}),
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import { createTemplateResolverApi } from "@cosmicdrift/kumiko-bundled-features/template-resolver";
|
|
14
14
|
import type { RunDevAppOptions } from "@cosmicdrift/kumiko-dev-server";
|
|
15
15
|
import { SYSTEM_TENANT_ID, type TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
16
|
+
import { BUNDLED_LISTS } from "../bundled-lists";
|
|
16
17
|
import { AUTH_COMPOSE_OPTIONS, BOOT_FEATURES, VALIDATE_BOOT_OPTIONS } from "../run-config";
|
|
17
18
|
import { ADMIN_EMAIL, ADMIN_PASSWORD, BETA_TENANT_ID, DEV_TENANT_ID } from "./auth-constants";
|
|
18
19
|
import { invoiceReportsFeature } from "./invoice-reports-feature";
|
|
@@ -31,6 +32,7 @@ export const devAppOptions = {
|
|
|
31
32
|
features: [...BOOT_FEATURES, appScreensFeature, notesFeature, invoiceReportsFeature],
|
|
32
33
|
featureToggles: true,
|
|
33
34
|
validateBootOptions: VALIDATE_BOOT_OPTIONS,
|
|
35
|
+
bundledLists: BUNDLED_LISTS,
|
|
34
36
|
port: Number.parseInt(process.env["PORT"] ?? "4186", 10),
|
|
35
37
|
clientEntry: "./src/app/client.tsx",
|
|
36
38
|
htmlPath: "./public/index.html",
|
|
@@ -45,6 +45,7 @@ export const noteEntity = createEntity({
|
|
|
45
45
|
required: true,
|
|
46
46
|
maxLength: 200,
|
|
47
47
|
sortable: true,
|
|
48
|
+
searchable: true,
|
|
48
49
|
}),
|
|
49
50
|
customFields: customFieldsField(),
|
|
50
51
|
},
|
|
@@ -65,6 +66,7 @@ const noteListScreen: EntityListScreenDefinition = {
|
|
|
65
66
|
},
|
|
66
67
|
],
|
|
67
68
|
searchable: true,
|
|
69
|
+
table: { export: { xlsx: true } },
|
|
68
70
|
defaultSort: { field: "title", dir: "asc" },
|
|
69
71
|
slots: { header: { react: { __component: TAGS_FILTER_EXTENSION_NAME } } },
|
|
70
72
|
rowActions: [
|
|
@@ -93,7 +93,12 @@ async function seedTierAssignment(
|
|
|
93
93
|
adminUserId: string,
|
|
94
94
|
): Promise<void> {
|
|
95
95
|
const by: SessionUser = { ...TestUsers.systemAdmin, tenantId, id: adminUserId };
|
|
96
|
-
const tdb = createTenantDb({
|
|
96
|
+
const tdb = createTenantDb({
|
|
97
|
+
db,
|
|
98
|
+
tenantId,
|
|
99
|
+
mode: "system",
|
|
100
|
+
reason: "demo seed writes tier assignments for the tenant being provisioned",
|
|
101
|
+
});
|
|
97
102
|
const result = await tierAssignmentExecutor.create(
|
|
98
103
|
{ id: tierAssignmentAggregateId(tenantId), tier, source: "manual", tenantId },
|
|
99
104
|
by,
|
|
@@ -117,7 +122,12 @@ async function seedTagsAndNotes(
|
|
|
117
122
|
adminUserId: string,
|
|
118
123
|
): Promise<void> {
|
|
119
124
|
const by: SessionUser = { ...TestUsers.systemAdmin, tenantId, id: adminUserId };
|
|
120
|
-
const tdb = createTenantDb({
|
|
125
|
+
const tdb = createTenantDb({
|
|
126
|
+
db,
|
|
127
|
+
tenantId,
|
|
128
|
+
mode: "system",
|
|
129
|
+
reason: "demo seed writes tier assignments for the tenant being provisioned",
|
|
130
|
+
});
|
|
121
131
|
|
|
122
132
|
const created = async (
|
|
123
133
|
label: string,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { BundledListsOptions } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
|
+
|
|
3
|
+
export const BUNDLED_LISTS = {
|
|
4
|
+
table: {
|
|
5
|
+
rememberState: true,
|
|
6
|
+
resetAll: true,
|
|
7
|
+
columnPicker: true,
|
|
8
|
+
density: { userChoice: true },
|
|
9
|
+
pinning: true,
|
|
10
|
+
resizing: true,
|
|
11
|
+
keyboardNavigation: true,
|
|
12
|
+
export: { xlsx: true },
|
|
13
|
+
},
|
|
14
|
+
pinFirstColumn: true,
|
|
15
|
+
} as const satisfies BundledListsOptions;
|
|
@@ -16,7 +16,7 @@ DSGVO requests work end-to-end:
|
|
|
16
16
|
|
|
17
17
|
| Article | Endpoint / Runner | What it does |
|
|
18
18
|
|---------|-----------|----------------|
|
|
19
|
-
| **Art. 15** | `user-data-rights:query:my-audit-log` | User sees own framework events (auth, deletion-request, restriction). Domain entities like todos appear in the **export bundle** (Art. 20), not the audit-log — only handlers using `ctx.
|
|
19
|
+
| **Art. 15** | `user-data-rights:query:my-audit-log` | User sees own framework events (auth, deletion-request, restriction). Domain entities like todos appear in the **export bundle** (Art. 20), not the audit-log — only handlers using `ctx.events.append` show up here. |
|
|
20
20
|
| **Art. 15+20** | `user-data-rights:write:request-export` | ZIP with user-profile + fileRefs + todos + signed download magic-link |
|
|
21
21
|
| **Art. 17** | `user-data-rights:write:request-deletion` | Soft-delete with grace period; cron anonymizes user + deletes todos |
|
|
22
22
|
| **Art. 18** | `user-data-rights:write:restrict-account` | Auth-middleware blocks logins until lift-restriction |
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
// 3. todoDeleteHook DELETEt alle Rows mit author_id = userId
|
|
26
26
|
// 4. user wird anonymisiert (display_name="(deleted)", email=null)
|
|
27
27
|
|
|
28
|
+
import { UserDataRightsScreens } from "@cosmicdrift/kumiko-bundled-features/user-data-rights";
|
|
28
29
|
import {
|
|
29
30
|
deleteMany,
|
|
30
31
|
deriveEntityTableMeta,
|
|
@@ -182,7 +183,7 @@ export const todosFeature = defineFeature(FEATURE_NAME, (r) => {
|
|
|
182
183
|
id: "gdpr-export-jobs",
|
|
183
184
|
label: "GDPR · Export Jobs",
|
|
184
185
|
icon: "shield",
|
|
185
|
-
screen:
|
|
186
|
+
screen: UserDataRightsScreens.exportJobList,
|
|
186
187
|
access: { roles: ["SystemAdmin"] },
|
|
187
188
|
order: 90,
|
|
188
189
|
});
|
|
@@ -190,7 +191,7 @@ export const todosFeature = defineFeature(FEATURE_NAME, (r) => {
|
|
|
190
191
|
id: "gdpr-download-attempts",
|
|
191
192
|
label: "GDPR · Download Attempts",
|
|
192
193
|
icon: "download",
|
|
193
|
-
screen:
|
|
194
|
+
screen: UserDataRightsScreens.downloadAttemptList,
|
|
194
195
|
access: { roles: ["SystemAdmin"] },
|
|
195
196
|
order: 91,
|
|
196
197
|
});
|
|
@@ -60,7 +60,8 @@ row and the `read_fulfillments` row appear.
|
|
|
60
60
|
is re-run after `ms` on the same queue job: no retry attempt is used, no failure is logged
|
|
61
61
|
or recorded, and the run log shows only the runs that actually executed. `maxDefers`
|
|
62
62
|
(default 100) bounds it; beyond that the run fails. It needs a queued run: an inline boot
|
|
63
|
-
gate throws.
|
|
63
|
+
gate throws. `context.canDefer` is false in both cases, so the job checks it and calls the
|
|
64
|
+
carrier anyway instead of failing.
|
|
64
65
|
|
|
65
66
|
## Test
|
|
66
67
|
|
|
@@ -131,8 +131,9 @@ export function createApiWorkerSplitFeature() {
|
|
|
131
131
|
}
|
|
132
132
|
const { customerName } = processOrderPayloadSchema.parse(payload);
|
|
133
133
|
// Busy is not a failure: ctx.defer re-runs the job later without burning a retry.
|
|
134
|
+
// Once the defer budget is used up (or the run is inline), try anyway and let a failure retry.
|
|
134
135
|
const retryAfterMs = carrierRetryAfterMs();
|
|
135
|
-
if (retryAfterMs > 0) return context.defer(retryAfterMs);
|
|
136
|
+
if (retryAfterMs > 0 && context.canDefer) return context.defer(retryAfterMs);
|
|
136
137
|
const result = await fulfillWrite({
|
|
137
138
|
handlerQn: "orders:write:fulfillment:create",
|
|
138
139
|
payload: {
|
|
@@ -11,10 +11,10 @@ Three building blocks:
|
|
|
11
11
|
|
|
12
12
|
- **`r.defineEvent("name", zodSchema)`** declares the name and payload.
|
|
13
13
|
The qualified name (e.g. `pubsub-orders:event:order-placed`) comes
|
|
14
|
-
back as `.name` — pass it directly to `ctx.
|
|
15
|
-
aren't registered are rejected by `ctx.
|
|
14
|
+
back as `.name` — pass it directly to `ctx.events.append`. Events that
|
|
15
|
+
aren't registered are rejected by `ctx.events.append` at the emit site.
|
|
16
16
|
|
|
17
|
-
- **`ctx.
|
|
17
|
+
- **`ctx.events.append({ aggregateId, aggregateType, type, payload })`**
|
|
18
18
|
appends the event onto the aggregate stream within the same TX.
|
|
19
19
|
Version lineage is continued automatically — no synthetic
|
|
20
20
|
`"pubsub"` stream anymore, the event truly lives on the aggregate.
|
|
@@ -32,7 +32,7 @@ Three building blocks:
|
|
|
32
32
|
HTTP → writeHandler
|
|
33
33
|
↓ TX begin
|
|
34
34
|
orderExecutor.create(...) ← business row + auto-event (pubsubOrder.created, v1)
|
|
35
|
-
ctx.
|
|
35
|
+
ctx.events.append({...}) ← domain event (pubsub-orders:event:order-placed, v2)
|
|
36
36
|
↓ TX commit
|
|
37
37
|
(async, post-commit)
|
|
38
38
|
event-dispatcher runOnce
|
|
@@ -42,7 +42,7 @@ HTTP → writeHandler
|
|
|
42
42
|
|
|
43
43
|
## Migration note
|
|
44
44
|
|
|
45
|
-
`r.postEvent` was removed in Sprint E.2. `ctx.
|
|
45
|
+
`r.postEvent` was removed in Sprint E.2. `ctx.events.append` +
|
|
46
46
|
`r.multiStreamProjection` is the unified Marten API for CRUD events,
|
|
47
47
|
domain events, and cross-feature reactions.
|
|
48
48
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-sample-cross-feature-events",
|
|
3
|
-
"description": "Feature appends a typed domain event via ctx.
|
|
3
|
+
"description": "Feature appends a typed domain event via ctx.events.append; a r.multiStreamProjection reacts asynchronously.",
|
|
4
4
|
"private": true,
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@cosmicdrift/kumiko-framework": "workspace:*"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Cross-Feature Reactions Sample (Marten gold-standard path)
|
|
2
2
|
//
|
|
3
3
|
// Demonstrates the Sprint-E pattern for reacting to events across features:
|
|
4
|
-
// a writeHandler emits a DOMAIN event via `ctx.
|
|
4
|
+
// a writeHandler emits a DOMAIN event via `ctx.events.append(...)` onto the
|
|
5
5
|
// aggregate's own stream, and a `r.multiStreamProjection` picks it up
|
|
6
6
|
// asynchronously through the event-dispatcher.
|
|
7
7
|
//
|
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
//
|
|
10
10
|
// 1. `r.defineEvent("short-name", zodSchema)` declares the event shape.
|
|
11
11
|
// Returns a def whose `.name` is the fully-qualified event name —
|
|
12
|
-
// pass that straight to `ctx.
|
|
12
|
+
// pass that straight to `ctx.events.append` so there's no string to
|
|
13
13
|
// hand-type (and no way to emit an unregistered event: appendEvent
|
|
14
14
|
// rejects at the emit site).
|
|
15
15
|
//
|
|
16
|
-
// 2. `ctx.
|
|
16
|
+
// 2. `ctx.events.append({ aggregateId, aggregateType, type, payload })`
|
|
17
17
|
// writes the event onto the aggregate's own stream inside the same
|
|
18
18
|
// transaction as the business write. Commit both or roll back both —
|
|
19
19
|
// no lost events, no orphan events. The event carries real
|
|
@@ -67,7 +67,7 @@ export const pubsubOrderFeature = defineFeature("pubsubOrders", (r) => {
|
|
|
67
67
|
r.entity({ name: "pubsub-order", ...orderEntity });
|
|
68
68
|
|
|
69
69
|
// Define the event shape once. The returned `.name` is the qualified
|
|
70
|
-
// name ("pubsub-orders:event:order-placed") — pass it to ctx.
|
|
70
|
+
// name ("pubsub-orders:event:order-placed") — pass it to ctx.events.append.
|
|
71
71
|
const orderPlaced = r.defineEvent(
|
|
72
72
|
"order-placed",
|
|
73
73
|
z.object({ id: z.string(), customer: z.string(), product: z.string() }),
|
|
@@ -9,12 +9,12 @@ blocks Kumiko provides.
|
|
|
9
9
|
| API | Purpose |
|
|
10
10
|
|---|---|
|
|
11
11
|
| `r.defineEvent(name, schema, { version, migrations })` | Event schema with version number + upcaster chain |
|
|
12
|
-
| `ctx.
|
|
12
|
+
| `ctx.events.append({ aggregateId, aggregateType, type, payload })` | Domain event on aggregate stream |
|
|
13
13
|
| `r.projection(...)` | Single-stream read model, inline in the write TX |
|
|
14
14
|
| `r.multiStreamProjection(...)` | Cross-aggregate read model, async via dispatcher |
|
|
15
|
-
| `ctx.
|
|
16
|
-
| `ctx.
|
|
17
|
-
| `ctx.queryProjection(name)` | Tenant-scoped read-model query |
|
|
15
|
+
| `ctx.events.load(id, { asOf })` | Live aggregation with point-in-time |
|
|
16
|
+
| `ctx.events.archive(id, { aggregateType })` | Archive a stream (Marten `ArchiveStream`) |
|
|
17
|
+
| `ctx.dispatch.queryProjection(name)` | Tenant-scoped read-model query |
|
|
18
18
|
|
|
19
19
|
## Domain
|
|
20
20
|
|
|
@@ -45,7 +45,7 @@ HTTP POST /api/write { type: "showcase:write:invoice:approve", ... }
|
|
|
45
45
|
↓
|
|
46
46
|
writeHandler("invoice:approve")
|
|
47
47
|
↓ TX begin
|
|
48
|
-
ctx.
|
|
48
|
+
ctx.events.append({ type: "showcase:event:invoice-approved", ... })
|
|
49
49
|
r.projection("invoice-detail") ← updates status = "approved"
|
|
50
50
|
↓ TX commit
|
|
51
51
|
(async)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-sample-event-sourcing",
|
|
3
|
-
"description": "Production-pattern ES sample: r.defineEvent (versioned + migrations) + ctx.
|
|
3
|
+
"description": "Production-pattern ES sample: r.defineEvent (versioned + migrations) + ctx.events.append + r.projection + r.multiStreamProjection + ctx.events.load (asOf) + ctx.events.archive + ctx.dispatch.queryProjection.",
|
|
4
4
|
"private": true,
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@cosmicdrift/kumiko-framework": "workspace:*"
|