@cosmicdrift/kumiko-framework 0.389.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/AGENTS.md +9 -4
- package/README.md +1 -1
- package/agents/examples/apex-surface-auth.md +2 -3
- package/agents/examples/api-worker-split.md +9 -2
- package/agents/examples/auth-claims.md +1 -1
- package/agents/examples/cross-feature-events.md +12 -12
- package/agents/examples/crypto-shredding-hr.md +2 -2
- package/agents/examples/encrypted-tenant-config.md +1 -1
- package/agents/examples/error-contract.md +12 -7
- package/agents/examples/event-sourcing.md +29 -29
- package/agents/examples/files-post-processing.md +10 -8
- package/agents/examples/inbound-mail-triage.md +1 -0
- package/agents/examples/lane-routing.md +2 -1
- package/agents/examples/legal-pages.md +2 -2
- package/agents/examples/lifecycle-hooks.md +3 -3
- package/agents/examples/managed-config.md +4 -4
- package/agents/examples/managed-pages.md +1 -1
- package/agents/examples/relations.md +19 -4
- package/agents/examples/search.md +4 -4
- package/agents/examples/secrets-demo.md +9 -6
- package/agents/examples/state-machine.md +2 -2
- package/agents/examples/tenant-settings.md +1 -1
- package/agents/examples/user-data-rights.md +3 -6
- package/agents/examples/workflow-engine.md +53 -47
- package/agents/examples.md +4 -4
- package/agents/features.md +1 -1
- package/dist/api/auth-middleware.js +1 -1
- package/dist/api/auth-routes-invite.js +2 -1
- package/dist/api/entity-read-access.d.ts +3 -1
- package/dist/api/export/export-columns.d.ts +3 -1
- package/dist/api/export/export-route.js +3 -2
- package/dist/api/export/export-screen.d.ts +2 -1
- package/dist/api/extra-route.d.ts +3 -1
- package/dist/api/index.d.ts +23 -27
- package/dist/api/index.js +13 -15
- package/dist/api/jwt.js +1 -1
- package/dist/api/observability-middleware.d.ts +1 -1
- package/dist/api/observability-middleware.js +2 -1
- package/dist/api/request-context-internals.d.ts +31 -0
- package/dist/api/request-context-internals.js +11 -0
- package/dist/api/request-context-scopes.d.ts +14 -0
- package/dist/api/request-context-scopes.js +69 -0
- package/dist/api/request-context.d.ts +1 -40
- package/dist/api/request-context.js +22 -51
- package/dist/api/request-id-middleware.d.ts +1 -1
- package/dist/api/route-registrars.d.ts +2 -1
- package/dist/api/route-registrars.js +1 -1
- package/dist/api/routes.js +7 -3
- package/dist/api/server-boot-checks.d.ts +1 -1
- package/dist/api/server-boot-checks.js +2 -2
- package/dist/api/server-event-dispatcher.d.ts +6 -1
- package/dist/api/server-event-dispatcher.js +3 -4
- package/dist/api/server-extra-routes.d.ts +1 -1
- package/dist/api/server-extra-routes.js +2 -1
- package/dist/api/server-middleware.js +3 -1
- package/dist/api/server-routes.d.ts +2 -1
- package/dist/api/server-wiring.js +6 -4
- package/dist/api/server.d.ts +2 -1
- package/dist/api/sse-route.d.ts +2 -1
- package/dist/api/tenant-scoped-secrets.d.ts +2 -0
- package/dist/api/tenant-scoped-secrets.js +13 -0
- package/dist/api/websocket-route.d.ts +1 -1
- package/dist/auth/index.d.ts +0 -1
- package/dist/auth/roles.d.ts +0 -5
- package/dist/compliance/duration-spec.d.ts +0 -1
- package/dist/compliance/duration-spec.js +0 -5
- package/dist/compliance/index.d.ts +4 -4
- package/dist/compliance/index.js +2 -2
- package/dist/compliance/profiles.d.ts +0 -15
- package/dist/compliance/profiles.js +0 -23
- package/dist/config/index.d.ts +10 -10
- package/dist/config/index.js +13 -1
- package/dist/config/internals.d.ts +9 -0
- package/dist/config/internals.js +1 -0
- package/dist/consumer-cli-internals.d.ts +4 -0
- package/dist/consumer-cli-internals.js +1 -0
- package/dist/consumer-cli.d.ts +1 -4
- package/dist/consumer-cli.js +5 -1
- package/dist/crypto/event-pii.js +1 -1
- package/dist/crypto/index.d.ts +8 -9
- package/dist/crypto/index.js +7 -8
- package/dist/crypto/pg-kms-adapter.js +6 -1
- package/dist/db/apply-entity-event.d.ts +1 -1
- package/dist/db/apply-entity-event.js +15 -47
- package/dist/db/blind-index-cleanup.js +91 -77
- package/dist/db/collect-table-metas.js +1 -1
- package/dist/db/compound-types.d.ts +1 -1
- package/dist/db/compound-types.js +0 -7
- package/dist/db/config-seed.d.ts +2 -1
- package/dist/db/config-seed.js +6 -1
- package/dist/db/connection.d.ts +3 -1
- package/dist/db/connection.js +15 -5
- package/dist/db/cross-tenant-reads.d.ts +1 -1
- package/dist/db/cross-tenant-reads.js +1 -1
- package/dist/db/dialect.d.ts +0 -5
- package/dist/db/dialect.js +0 -3
- package/dist/db/eagerload.d.ts +2 -1
- package/dist/db/entity-field-encryption.d.ts +1 -1
- package/dist/db/entity-table-meta.d.ts +1 -1
- package/dist/db/event-store-executor-context.d.ts +3 -1
- package/dist/db/event-store-executor-context.js +4 -3
- package/dist/db/event-store-executor-read-filter.d.ts +1 -1
- package/dist/db/event-store-executor-read-rows.d.ts +2 -1
- package/dist/db/event-store-executor-read-search.d.ts +2 -1
- package/dist/db/event-store-executor-read-sort.d.ts +2 -1
- package/dist/db/event-store-executor-read.js +2 -2
- package/dist/db/event-store-executor-write-atomic.js +8 -7
- package/dist/db/event-store-executor-write-steps.d.ts +3 -2
- package/dist/db/event-store-executor-write.js +7 -4
- package/dist/db/event-store-executor.d.ts +1 -1
- package/dist/db/executor-managed-tables.d.ts +7 -1
- package/dist/db/executor-managed-tables.js +11 -2
- package/dist/db/index.d.ts +29 -28
- package/dist/db/index.js +22 -20
- package/dist/db/known-table-names.d.ts +6 -0
- package/dist/db/known-table-names.js +21 -0
- package/dist/db/list-aggregate-labels.d.ts +1 -1
- package/dist/db/located-timestamp.d.ts +1 -1
- package/dist/db/located-timestamp.js +0 -5
- package/dist/db/migrate-generator.d.ts +17 -1
- package/dist/db/migrate-generator.js +50 -20
- package/dist/db/migrate-primary-key.d.ts +12 -0
- package/dist/db/migrate-primary-key.js +45 -0
- package/dist/db/migrate-rls-diff.d.ts +20 -0
- package/dist/db/migrate-rls-diff.js +61 -0
- package/dist/db/migrate-runner.js +4 -0
- package/dist/db/money.d.ts +1 -1
- package/dist/db/money.js +1 -1
- package/dist/db/parent-ref-clause.d.ts +2 -1
- package/dist/db/pg-error.d.ts +2 -0
- package/dist/db/pg-error.js +11 -0
- package/dist/db/queries/ddl.d.ts +3 -0
- package/dist/db/queries/ddl.js +34 -1
- package/dist/db/queries/event-store.js +4 -2
- package/dist/db/queries/event-tenants.d.ts +2 -0
- package/dist/db/queries/event-tenants.js +17 -0
- package/dist/db/queries/rebuild-rls-guard.d.ts +2 -0
- package/dist/db/queries/rebuild-rls-guard.js +29 -0
- package/dist/db/queries/rls-boot-catalog.d.ts +16 -0
- package/dist/db/queries/rls-boot-catalog.js +39 -0
- package/dist/db/queries/rls-catalog.d.ts +6 -0
- package/dist/db/queries/rls-catalog.js +82 -0
- package/dist/db/queries/rls-scope.d.ts +3 -0
- package/dist/db/queries/rls-scope.js +17 -0
- package/dist/db/queries/rls-shape.d.ts +10 -0
- package/dist/db/queries/rls-shape.js +42 -0
- package/dist/db/queries/session-advisory-lock.d.ts +2 -0
- package/dist/db/queries/session-advisory-lock.js +23 -0
- package/dist/db/queries/shadow-swap.d.ts +1 -2
- package/dist/db/queries/shadow-swap.js +9 -25
- package/dist/db/queries/test-stack.d.ts +4 -1
- package/dist/db/queries/test-stack.js +83 -2
- package/dist/db/query.js +11 -7
- package/dist/db/reference-data.d.ts +1 -1
- package/dist/db/reference-data.js +6 -1
- package/dist/db/render-ddl.d.ts +6 -2
- package/dist/db/render-ddl.js +7 -7
- package/dist/db/render-rls-ddl.d.ts +35 -0
- package/dist/db/render-rls-ddl.js +127 -0
- package/dist/db/replay-migration-sql.d.ts +3 -1
- package/dist/db/replay-migration-sql.js +22 -5
- package/dist/db/replay-rls.d.ts +25 -0
- package/dist/db/replay-rls.js +156 -0
- package/dist/db/row-level-security-boot-check.d.ts +5 -0
- package/dist/db/row-level-security-boot-check.js +85 -0
- package/dist/db/row-level-security-connection.d.ts +3 -0
- package/dist/db/row-level-security-connection.js +213 -0
- package/dist/db/row-level-security-scope.d.ts +33 -0
- package/dist/db/row-level-security-scope.js +127 -0
- package/dist/db/scope-tenant-db-to-tenant.d.ts +3 -0
- package/dist/db/scope-tenant-db-to-tenant.js +14 -0
- package/dist/db/sql-identifier.d.ts +1 -0
- package/dist/db/sql-identifier.js +3 -0
- package/dist/db/table-builder.d.ts +2 -1
- package/dist/db/table-builder.js +1 -1
- package/dist/db/table-info.js +1 -1
- package/dist/db/table-push.d.ts +11 -2
- package/dist/db/table-push.js +15 -2
- package/dist/db/tenant-db-runner.d.ts +3 -1
- package/dist/db/tenant-db-runner.js +4 -3
- package/dist/db/tenant-db-scoped-rebind.d.ts +10 -0
- package/dist/db/tenant-db-scoped-rebind.js +33 -0
- package/dist/db/tenant-db-statement-runner.d.ts +13 -0
- package/dist/db/tenant-db-statement-runner.js +48 -0
- package/dist/db/tenant-db.d.ts +17 -12
- package/dist/db/tenant-db.js +49 -120
- package/dist/db/tenant-id-filter.d.ts +3 -0
- package/dist/db/tenant-id-filter.js +30 -0
- package/dist/db/transaction-serialization.d.ts +6 -0
- package/dist/db/transaction-serialization.js +60 -0
- package/dist/derivatives/delete-stored-file.js +1 -1
- package/dist/derivatives/index.d.ts +2 -5
- package/dist/derivatives/index.js +2 -3
- package/dist/engine/access.d.ts +2 -1
- package/dist/engine/access.js +1 -1
- package/dist/engine/boot-validator/entity-handler.d.ts +2 -1
- package/dist/engine/boot-validator/entity-handler.js +1 -1
- package/dist/engine/boot-validator/entity-list-aggregate-options.d.ts +1 -1
- package/dist/engine/boot-validator/list-table-aggregate-options.d.ts +1 -1
- package/dist/engine/boot-validator/list-table-aggregate-query.d.ts +2 -1
- package/dist/engine/boot-validator/nav.d.ts +3 -1
- package/dist/engine/boot-validator/nav.js +1 -1
- package/dist/engine/boot-validator/ownership.d.ts +2 -1
- package/dist/engine/boot-validator/parent-ref.d.ts +2 -1
- package/dist/engine/boot-validator/projection-list-screens.d.ts +2 -1
- package/dist/engine/boot-validator/query-refs.d.ts +2 -1
- package/dist/engine/boot-validator/screens-forms.d.ts +2 -1
- package/dist/engine/boot-validator/screens-kind-shared.d.ts +3 -1
- package/dist/engine/boot-validator/screens.d.ts +2 -1
- package/dist/engine/boot-validator/workspaces.d.ts +3 -1
- package/dist/engine/bridge-stub.d.ts +5 -2
- package/dist/engine/bridge-stub.js +39 -24
- package/dist/engine/config-helpers.d.ts +2 -2
- package/dist/engine/config-helpers.js +0 -9
- package/dist/engine/constants.d.ts +0 -10
- package/dist/engine/constants.js +0 -8
- package/dist/engine/create-app.js +1 -1
- package/dist/engine/define-feature.d.ts +2 -1
- package/dist/engine/define-feature.js +1 -2
- package/dist/engine/define-handler.d.ts +1 -1
- package/dist/engine/define-step.d.ts +0 -1
- package/dist/engine/define-step.js +0 -3
- package/dist/engine/embedded-derived.d.ts +1 -1
- package/dist/engine/entity-handlers.d.ts +2 -1
- package/dist/engine/entity-handlers.js +7 -7
- package/dist/engine/entity-list-runtime-options.js +3 -1
- package/dist/engine/entity-list-searchability.d.ts +2 -1
- package/dist/engine/event-def.d.ts +2 -1
- package/dist/engine/event-helpers.d.ts +3 -1
- package/dist/engine/event-helpers.js +3 -3
- package/dist/engine/extension-names.d.ts +2 -8
- package/dist/engine/extension-names.js +2 -2
- package/dist/engine/extension-selector-plugins.d.ts +1 -1
- package/dist/engine/extensions/storage-provider.d.ts +1 -2
- package/dist/engine/extensions/user-data.d.ts +0 -8
- package/dist/engine/factories.d.ts +2 -1
- package/dist/engine/feature-builder-state.d.ts +8 -1
- package/dist/engine/feature-changelog.d.ts +1 -1
- package/dist/engine/feature-config-events-jobs.d.ts +4 -1
- package/dist/engine/feature-entity-handlers.d.ts +5 -1
- package/dist/engine/feature-manifest.js +1 -1
- package/dist/engine/feature-ui-extensions.d.ts +7 -1
- package/dist/engine/feature-ui-extensions.js +6 -4
- package/dist/engine/field-access.d.ts +2 -1
- package/dist/engine/handler-field-references.d.ts +0 -4
- package/dist/engine/index.d.ts +57 -54
- package/dist/engine/index.js +22 -27
- package/dist/engine/instruction-fields.d.ts +1 -1
- package/dist/engine/personal-data-fields.d.ts +1 -1
- package/dist/engine/qualified-name.d.ts +0 -1
- package/dist/engine/read-claim.d.ts +2 -1
- package/dist/engine/registry-facade.js +0 -3
- package/dist/engine/registry-ingest.d.ts +2 -1
- package/dist/engine/registry-ingest.js +1 -2
- package/dist/engine/registry-state.d.ts +12 -2
- package/dist/engine/registry-state.js +2 -3
- package/dist/engine/registry-validate.d.ts +3 -1
- package/dist/engine/registry-validate.js +7 -7
- package/dist/engine/run-in.d.ts +1 -1
- package/dist/engine/run-in.js +0 -1
- package/dist/engine/schema-builder.d.ts +1 -1
- package/dist/engine/schema-builder.js +1 -1
- package/dist/engine/screen-filter-ops.d.ts +2 -1
- package/dist/engine/screen-filter-ops.js +0 -5
- package/dist/engine/soft-delete-cleanup.d.ts +1 -1
- package/dist/engine/soft-delete-cleanup.js +4 -4
- package/dist/engine/state-machine.js +2 -1
- package/dist/engine/steps/_read-source.js +1 -1
- package/dist/engine/steps/aggregate-append-event.js +2 -2
- package/dist/engine/steps/call-feature.js +2 -2
- package/dist/engine/steps/mail-send.js +1 -1
- package/dist/engine/steps/retry.js +1 -1
- package/dist/engine/steps/wait-for-event.js +1 -1
- package/dist/engine/steps/wait.js +1 -1
- package/dist/engine/steps/webhook-send.js +1 -1
- package/dist/engine/template-variables.d.ts +2 -1
- package/dist/engine/transfer-adjacency.d.ts +1 -1
- package/dist/engine/types/index.d.ts +8 -31
- package/dist/engine/types/index.js +2 -10
- package/dist/engine/validation.d.ts +2 -1
- package/dist/entrypoint/index.d.ts +7 -35
- package/dist/entrypoint/index.js +7 -1
- package/dist/entrypoint/internals.d.ts +40 -0
- package/dist/entrypoint/internals.js +1 -0
- package/dist/entrypoint/row-level-security-mode-check.d.ts +3 -0
- package/dist/entrypoint/row-level-security-mode-check.js +19 -0
- package/dist/env/dry-run-internals.d.ts +10 -0
- package/dist/env/dry-run-internals.js +1 -0
- package/dist/env/dry-run.d.ts +1 -10
- package/dist/env/dry-run.js +2 -1
- package/dist/env/index.d.ts +1 -85
- package/dist/env/index.js +6 -50
- package/dist/env/internals.d.ts +87 -0
- package/dist/env/internals.js +53 -0
- package/dist/errors/classes.js +2 -2
- package/dist/errors/index.d.ts +5 -14
- package/dist/errors/index.js +4 -9
- package/dist/errors/member-resolution.js +1 -1
- package/dist/errors/reasons.d.ts +0 -1
- package/dist/errors/reasons.js +7 -7
- package/dist/errors/serialize.d.ts +0 -18
- package/dist/errors/serialize.js +0 -27
- package/dist/es-ops/index.d.ts +4 -4
- package/dist/es-ops/index.js +2 -2
- package/dist/es-ops/operations-schema.d.ts +1 -1
- package/dist/es-ops/types.d.ts +4 -5
- package/dist/event-store/admin-api-internals.d.ts +14 -0
- package/dist/event-store/admin-api-internals.js +1 -0
- package/dist/event-store/admin-api.d.ts +1 -14
- package/dist/event-store/admin-api.js +11 -6
- package/dist/event-store/archive.js +4 -2
- package/dist/event-store/errors.js +2 -2
- package/dist/event-store/event-store.js +41 -34
- package/dist/event-store/events-schema.js +4 -1
- package/dist/event-store/index.d.ts +11 -13
- package/dist/event-store/index.js +7 -9
- package/dist/event-store/rebuild-dead-letter.js +4 -2
- package/dist/event-store/snapshot.js +4 -3
- package/dist/event-store/stream-scope.d.ts +2 -0
- package/dist/event-store/stream-scope.js +6 -0
- package/dist/event-store/upcaster-dead-letter.js +4 -2
- package/dist/event-store/upcaster.d.ts +2 -1
- package/dist/files/action-form-upload.d.ts +2 -1
- package/dist/files/action-form-upload.js +1 -1
- package/dist/files/assert-file-refs-belong-to-tenant.d.ts +2 -1
- package/dist/files/assert-file-refs-belong-to-tenant.js +1 -1
- package/dist/files/bind-pending-file-refs.d.ts +2 -1
- package/dist/files/bind-pending-file-refs.js +2 -1
- package/dist/files/bind-referenced-files.write.js +1 -1
- package/dist/files/create-file-ref-from-bytes.d.ts +6 -3
- package/dist/files/create-file-ref-from-bytes.js +3 -3
- package/dist/files/create-file-ref.d.ts +3 -2
- package/dist/files/create-file-ref.js +2 -2
- package/dist/files/dispose-removed-file-refs.d.ts +2 -1
- package/dist/files/dispose-removed-file-refs.js +1 -1
- package/dist/files/feature.js +2 -2
- package/dist/files/file-handle.js +1 -1
- package/dist/files/file-routes.d.ts +1 -1
- package/dist/files/file-routes.js +12 -2
- package/dist/files/index.d.ts +11 -13
- package/dist/files/index.js +5 -7
- package/dist/files/load-save-file-refs.d.ts +2 -1
- package/dist/files/load-save-file-refs.js +1 -1
- package/dist/files/provider-resolver.d.ts +5 -4
- package/dist/files/provider-resolver.js +4 -4
- package/dist/files/storage-tracking.js +4 -2
- package/dist/files/sweep-orphaned-uploads.d.ts +1 -1
- package/dist/files/sweep-orphaned-uploads.js +1 -1
- package/dist/i18n/index.d.ts +2 -8
- package/dist/i18n/index.js +1 -1
- package/dist/i18n/internals.d.ts +7 -0
- package/dist/i18n/internals.js +1 -0
- package/dist/i18n/required-surface-keys.d.ts +4 -1
- package/dist/internal/row-level-security.d.ts +3 -0
- package/dist/internal/row-level-security.js +3 -0
- package/dist/internal/stack-support.d.ts +1 -1
- package/dist/internal/stack-support.js +1 -1
- package/dist/internal/testing.d.ts +1 -0
- package/dist/internal/testing.js +9 -5
- package/dist/jobs/index.d.ts +1 -1
- package/dist/jobs/job-append-event.d.ts +12 -0
- package/dist/jobs/job-append-event.js +30 -0
- package/dist/jobs/job-runner-context.d.ts +2 -2
- package/dist/jobs/job-runner-context.js +46 -16
- package/dist/jobs/job-runner-execution.d.ts +1 -1
- package/dist/jobs/job-runner-execution.js +6 -4
- package/dist/jobs/job-runner-gates.d.ts +1 -1
- package/dist/jobs/job-runner-gates.js +0 -1
- package/dist/jobs/job-runner-helpers.d.ts +11 -4
- package/dist/jobs/job-runner-helpers.js +10 -1
- package/dist/jobs/job-runner-scope.d.ts +5 -2
- package/dist/jobs/job-runner-types.d.ts +2 -1
- package/dist/jobs/job-runner.js +19 -6
- package/dist/jobs/max-per-tenant.d.ts +1 -1
- package/dist/logging/index.d.ts +1 -2
- package/dist/logging/index.js +1 -1
- package/dist/logging/pino-logger.js +1 -1
- package/dist/logging/utils.d.ts +1 -0
- package/dist/logging/utils.js +6 -0
- package/dist/migrations/index.d.ts +3 -3
- package/dist/migrations/index.js +3 -3
- package/dist/migrations/pending-rebuilds.d.ts +1 -1
- package/dist/migrations/pending-rebuilds.js +1 -1
- package/dist/migrations/pii-event-backfill.js +4 -1
- package/dist/observability/escape-hatch-report.d.ts +2 -1
- package/dist/observability/index.d.ts +7 -15
- package/dist/observability/index.js +4 -12
- package/dist/observability/metric-validator.js +1 -1
- package/dist/observability/metrics-handle.d.ts +0 -1
- package/dist/observability/metrics-handle.js +2 -15
- package/dist/observability/recording-tracer.d.ts +1 -2
- package/dist/observability/recording-tracer.js +0 -6
- package/dist/observability/sensitive-filter.d.ts +0 -2
- package/dist/observability/sensitive-filter.js +0 -29
- package/dist/pipeline/active-membership.d.ts +2 -1
- package/dist/pipeline/active-membership.js +6 -2
- package/dist/pipeline/append-event-core.d.ts +2 -1
- package/dist/pipeline/append-event-core.js +2 -2
- package/dist/pipeline/attach-outside-transaction.d.ts +3 -0
- package/dist/pipeline/attach-outside-transaction.js +13 -0
- package/dist/pipeline/auth-claims-resolver.d.ts +2 -1
- package/dist/pipeline/cascade-handler.d.ts +2 -1
- package/dist/pipeline/cascade-handler.js +3 -2
- package/dist/pipeline/config-accessor-factory.d.ts +1 -1
- package/dist/pipeline/config-accessor-factory.js +1 -1
- package/dist/pipeline/context-services.d.ts +56 -0
- package/dist/pipeline/context-services.js +73 -0
- package/dist/pipeline/dispatch-batch.d.ts +2 -1
- package/dist/pipeline/dispatch-batch.js +31 -18
- package/dist/pipeline/dispatch-query.js +5 -4
- package/dist/pipeline/dispatch-scope.d.ts +6 -0
- package/dist/pipeline/dispatch-scope.js +27 -0
- package/dist/pipeline/dispatch-shared.d.ts +13 -9
- package/dist/pipeline/dispatch-shared.js +75 -198
- package/dist/pipeline/dispatch-stream.js +8 -4
- package/dist/pipeline/dispatch-write.d.ts +2 -1
- package/dist/pipeline/dispatch-write.js +10 -8
- package/dist/pipeline/dispatcher-utils.d.ts +3 -1
- package/dist/pipeline/dispatcher-utils.js +8 -2
- package/dist/pipeline/dispatcher.d.ts +3 -2
- package/dist/pipeline/dispatcher.js +4 -3
- package/dist/pipeline/event-consumer-state.d.ts +0 -1
- package/dist/pipeline/event-dispatcher-delivery.d.ts +1 -1
- package/dist/pipeline/event-dispatcher-delivery.js +4 -2
- package/dist/pipeline/event-dispatcher.d.ts +2 -2
- package/dist/pipeline/event-dispatcher.js +7 -3
- package/dist/pipeline/event-retention.js +59 -56
- package/dist/pipeline/handler-access-error.js +2 -1
- package/dist/pipeline/handler-context-auth.d.ts +5 -6
- package/dist/pipeline/handler-context-auth.js +7 -4
- package/dist/pipeline/handler-context-config.d.ts +2 -5
- package/dist/pipeline/handler-context-config.js +2 -2
- package/dist/pipeline/handler-context-db.d.ts +32 -7
- package/dist/pipeline/handler-context-db.js +26 -17
- package/dist/pipeline/handler-context-dispatch.d.ts +13 -7
- package/dist/pipeline/handler-context-dispatch.js +9 -8
- package/dist/pipeline/handler-context-events.d.ts +22 -36
- package/dist/pipeline/handler-context-events.js +36 -31
- package/dist/pipeline/handler-context-member-resolution.d.ts +2 -0
- package/dist/pipeline/handler-context-member-resolution.js +110 -0
- package/dist/pipeline/handler-context-notify.d.ts +3 -2
- package/dist/pipeline/handler-context-notify.js +1 -1
- package/dist/pipeline/handler-context-observability.d.ts +2 -4
- package/dist/pipeline/handler-context-observability.js +7 -5
- package/dist/pipeline/handler-context-phase-denials.d.ts +11 -0
- package/dist/pipeline/handler-context-phase-denials.js +98 -0
- package/dist/pipeline/handler-context-scope.d.ts +7 -10
- package/dist/pipeline/handler-context-scope.js +18 -20
- package/dist/pipeline/index.d.ts +9 -21
- package/dist/pipeline/index.js +5 -7
- package/dist/pipeline/irreversible-operation-gate.d.ts +1 -1
- package/dist/pipeline/irreversible-operation-gate.js +2 -2
- package/dist/pipeline/lifecycle-pipeline.d.ts +8 -7
- package/dist/pipeline/lifecycle-pipeline.js +9 -15
- package/dist/pipeline/member-read-only-transaction.js +11 -3
- package/dist/pipeline/member-reader.d.ts +1 -1
- package/dist/pipeline/member-reader.js +2 -2
- package/dist/pipeline/msp-rebuild.js +5 -3
- package/dist/pipeline/multi-stream-apply-context.js +3 -2
- package/dist/pipeline/notify-scope.d.ts +2 -1
- package/dist/pipeline/pre-handler-gates.d.ts +2 -1
- package/dist/pipeline/pre-transaction-reservations.d.ts +3 -3
- package/dist/pipeline/pre-transaction-reservations.js +9 -7
- package/dist/pipeline/projection-rebuild.js +12 -5
- package/dist/pipeline/projection-state.d.ts +0 -6
- package/dist/pipeline/projection-state.js +0 -5
- package/dist/pipeline/projections-runner.d.ts +2 -1
- package/dist/pipeline/projections-runner.js +10 -6
- package/dist/pipeline/system-hooks.d.ts +3 -1
- package/dist/pipeline/system-hooks.js +6 -4
- package/dist/pipeline/system-identity-switch.d.ts +4 -2
- package/dist/pipeline/system-identity-switch.js +51 -36
- package/dist/pipeline/typed-append-event.d.ts +2 -0
- package/dist/pipeline/typed-append-event.js +4 -0
- package/dist/pipeline/write-origin.js +2 -2
- package/dist/pipeline/write-result-masking.d.ts +1 -1
- package/dist/random/index.d.ts +1 -2
- package/dist/random/index.js +1 -2
- package/dist/rate-limit/bucket.d.ts +2 -1
- package/dist/rate-limit/middleware.js +2 -1
- package/dist/redis/index.d.ts +3 -4
- package/dist/redis/index.js +2 -2
- package/dist/schema-cli/apply-command.js +5 -2
- package/dist/schema-cli/baseline-command.js +7 -2
- package/dist/schema-cli/generate-command.js +7 -9
- package/dist/schema-cli/shared.d.ts +4 -0
- package/dist/schema-cli/shared.js +21 -2
- package/dist/schema-cli/status-command.js +8 -2
- package/dist/schema-cli/validate-command.js +52 -4
- package/dist/schema-cli.d.ts +0 -1
- package/dist/search/configure-tenant-index.d.ts +1 -3
- package/dist/search/configure-tenant-index.js +0 -4
- package/dist/search/index.d.ts +1 -4
- package/dist/search/index.js +0 -2
- package/dist/search/meilisearch-adapter-internals.d.ts +8 -0
- package/dist/search/meilisearch-adapter-internals.js +9 -0
- package/dist/search/meilisearch-adapter.d.ts +1 -8
- package/dist/search/meilisearch-adapter.js +6 -7
- package/dist/search/meilisearch-peer.d.ts +2 -0
- package/dist/search/meilisearch-peer.js +5 -0
- package/dist/search/reindex-entity.js +93 -87
- package/dist/secrets/index.d.ts +3 -4
- package/dist/secrets/index.js +2 -3
- package/dist/seeding/index.d.ts +2 -2
- package/dist/seeding/index.js +1 -2
- package/dist/time/index.d.ts +2 -2
- package/dist/time/index.js +1 -1
- package/dist/time/tz-context.d.ts +0 -5
- package/dist/time/tz-context.js +0 -9
- package/dist/ui-types/index.d.ts +8 -11
- package/dist/ui-types/index.js +3 -3
- package/dist/upgrade-changelog.d.ts +3 -2
- package/dist/upgrade-changelog.js +12 -8
- package/dist/upgrade-cli-internals.d.ts +8 -0
- package/dist/upgrade-cli-internals.js +63 -0
- package/dist/upgrade-cli.d.ts +1 -9
- package/dist/upgrade-cli.js +10 -64
- package/dist/utils/import-optional-peer.d.ts +6 -0
- package/dist/utils/import-optional-peer.js +19 -0
- package/dist/utils/index.d.ts +1 -4
- package/dist/utils/index.js +1 -4
- package/package.json +22 -18
- package/src/changes.json +206 -0
- package/dist/crypto/request-kms-cache.d.ts +0 -8
- package/dist/crypto/request-kms-cache.js +0 -21
- package/dist/engine/codemod/index.d.ts +0 -2
- package/dist/engine/codemod/index.js +0 -1
- package/dist/engine/codemod/pipeline-codemod.d.ts +0 -50
- package/dist/engine/codemod/pipeline-codemod.js +0 -536
- package/dist/engine/feature-ast/entity-field-types.d.ts +0 -13
- package/dist/engine/feature-ast/entity-field-types.js +0 -35
- package/dist/engine/feature-ast/extractors/ai-steps.d.ts +0 -6
- package/dist/engine/feature-ast/extractors/ai-steps.js +0 -254
- package/dist/engine/feature-ast/extractors/events.d.ts +0 -5
- package/dist/engine/feature-ast/extractors/events.js +0 -275
- package/dist/engine/feature-ast/extractors/handlers.d.ts +0 -24
- package/dist/engine/feature-ast/extractors/handlers.js +0 -358
- package/dist/engine/feature-ast/extractors/hooks.d.ts +0 -24
- package/dist/engine/feature-ast/extractors/hooks.js +0 -248
- package/dist/engine/feature-ast/extractors/index.d.ts +0 -14
- package/dist/engine/feature-ast/extractors/index.js +0 -13
- package/dist/engine/feature-ast/extractors/jobs-routes.d.ts +0 -7
- package/dist/engine/feature-ast/extractors/jobs-routes.js +0 -145
- package/dist/engine/feature-ast/extractors/projections-screens.d.ts +0 -10
- package/dist/engine/feature-ast/extractors/projections-screens.js +0 -195
- package/dist/engine/feature-ast/extractors/resolve-import.d.ts +0 -21
- package/dist/engine/feature-ast/extractors/resolve-import.js +0 -180
- package/dist/engine/feature-ast/extractors/round1.d.ts +0 -11
- package/dist/engine/feature-ast/extractors/round1.js +0 -87
- package/dist/engine/feature-ast/extractors/round2.d.ts +0 -7
- package/dist/engine/feature-ast/extractors/round2.js +0 -191
- package/dist/engine/feature-ast/extractors/round3.d.ts +0 -23
- package/dist/engine/feature-ast/extractors/round3.js +0 -292
- package/dist/engine/feature-ast/extractors/round5.d.ts +0 -9
- package/dist/engine/feature-ast/extractors/round5.js +0 -68
- package/dist/engine/feature-ast/extractors/round6.d.ts +0 -4
- package/dist/engine/feature-ast/extractors/round6.js +0 -17
- package/dist/engine/feature-ast/extractors/shared.d.ts +0 -94
- package/dist/engine/feature-ast/extractors/shared.js +0 -343
- package/dist/engine/feature-ast/index.d.ts +0 -16
- package/dist/engine/feature-ast/index.js +0 -10
- package/dist/engine/feature-ast/parse.d.ts +0 -31
- package/dist/engine/feature-ast/parse.js +0 -485
- package/dist/engine/feature-ast/patch.d.ts +0 -212
- package/dist/engine/feature-ast/patch.js +0 -611
- package/dist/engine/feature-ast/patcher.d.ts +0 -217
- package/dist/engine/feature-ast/patcher.js +0 -281
- package/dist/engine/feature-ast/pattern-change-schema.d.ts +0 -1238
- package/dist/engine/feature-ast/pattern-change-schema.js +0 -1072
- package/dist/engine/feature-ast/pattern-id-matchers.d.ts +0 -7
- package/dist/engine/feature-ast/pattern-id-matchers.js +0 -211
- package/dist/engine/feature-ast/pattern-id-schema.d.ts +0 -251
- package/dist/engine/feature-ast/pattern-id-schema.js +0 -166
- package/dist/engine/feature-ast/patterns.d.ts +0 -322
- package/dist/engine/feature-ast/patterns.js +0 -107
- package/dist/engine/feature-ast/render.d.ts +0 -47
- package/dist/engine/feature-ast/render.js +0 -666
- package/dist/engine/feature-ast/source-location.d.ts +0 -17
- package/dist/engine/feature-ast/source-location.js +0 -27
- package/dist/engine/pattern-library/index.d.ts +0 -2
- package/dist/engine/pattern-library/index.js +0 -3
- package/dist/engine/pattern-library/library.d.ts +0 -14
- package/dist/engine/pattern-library/library.js +0 -94
- package/dist/engine/pattern-library/mixed-schemas.d.ts +0 -16
- package/dist/engine/pattern-library/mixed-schemas.js +0 -559
- package/dist/engine/pattern-library/opaque-schemas.d.ts +0 -7
- package/dist/engine/pattern-library/opaque-schemas.js +0 -115
- package/dist/engine/pattern-library/shared-fields.d.ts +0 -122
- package/dist/engine/pattern-library/shared-fields.js +0 -88
- package/dist/engine/pattern-library/static-schemas.d.ts +0 -21
- package/dist/engine/pattern-library/static-schemas.js +0 -487
- package/dist/engine/pattern-library/types.d.ts +0 -158
- package/dist/engine/pattern-library/types.js +0 -36
- package/dist/engine/resolve-config-or-param.d.ts +0 -18
- package/dist/engine/resolve-config-or-param.js +0 -76
- package/src/scripts/codemod/README.md +0 -187
- package/src/scripts/codemod/codemod-support.ts +0 -334
- package/src/scripts/codemod/collect-source-files.ts +0 -48
- package/src/scripts/codemod/crypto-shredding-testing-move.ts +0 -119
- package/src/scripts/codemod/db-factory.ts +0 -810
- package/src/scripts/codemod/feature-factory.ts +0 -429
- package/src/scripts/codemod/feature-layout.ts +0 -424
- package/src/scripts/codemod/import-extensions.ts +0 -118
- package/src/scripts/codemod/migrate-cross-tenant.ts +0 -328
- package/src/scripts/codemod/migrate-db-raw.ts +0 -401
- package/src/scripts/codemod/migrate-open-to-all.ts +0 -235
- package/src/scripts/codemod/object-form.ts +0 -746
- package/src/scripts/codemod/package-merge.ts +0 -299
- package/src/scripts/codemod/pii-personal-migration.ts +0 -816
- package/src/scripts/codemod/remove-engine-payload-casts.ts +0 -318
- package/src/scripts/codemod/s3-imports.ts +0 -236
- package/src/scripts/codemod/tenant-db-options.ts +0 -454
- package/src/scripts/codemod/testing-injection.ts +0 -215
- package/src/scripts/codemod/testing-move-targets.ts +0 -161
- package/src/scripts/codemod/testing-move.ts +0 -542
- package/src/scripts/codemod/unprocessable-error-details-reason.ts +0 -411
package/AGENTS.md
CHANGED
|
@@ -76,7 +76,7 @@ Parents may belong to another feature; refer to them by QN.
|
|
|
76
76
|
|
|
77
77
|
**Events.** Declare a domain event with `r.defineEvent(name, zodSchema)`.
|
|
78
78
|
Emit it inside a write handler with `emitEvent(ctx, def, { ... })` or
|
|
79
|
-
`ctx.
|
|
79
|
+
`ctx.events.append(...)`; it commits in the same transaction as the write.
|
|
80
80
|
React to it with `r.projection(...)` (state on the same stream) or
|
|
81
81
|
`r.multiStreamProjection({ name, apply })` (async consumer across streams,
|
|
82
82
|
at least once, ordered).
|
|
@@ -195,7 +195,7 @@ produces code that compiles and then fails in production.
|
|
|
195
195
|
- Never `INSERT`, `UPDATE` or `DELETE` on an entity table or the events
|
|
196
196
|
table, and never call a raw database client for it. Write through a
|
|
197
197
|
handler: `r.crud`, the `defineEntity*Handler` helpers, the executor from
|
|
198
|
-
`createEntityExecutor`, or `emitEvent` / `ctx.
|
|
198
|
+
`createEntityExecutor`, or `emitEvent` / `ctx.events.append`. The query
|
|
199
199
|
helpers and `ctx.db` throw `AccessDeniedError` on such a write, also
|
|
200
200
|
through `ctx.db.unsafeRaw()`. Test seeds use `seedRow` / `deleteRows` from
|
|
201
201
|
`@cosmicdrift/kumiko-testing`.
|
|
@@ -203,7 +203,12 @@ produces code that compiles and then fails in production.
|
|
|
203
203
|
projection.
|
|
204
204
|
- Never hand-write SQL for reads that an executor `list` or `detail` covers.
|
|
205
205
|
Use `r.queryHandler` with the executor, or a projection with
|
|
206
|
-
`ctx.queryProjection`.
|
|
206
|
+
`ctx.dispatch.queryProjection`.
|
|
207
|
+
- Never pass a JS array as a parameter to `.unsafe(sql, [...])`. Bun.SQL
|
|
208
|
+
binds it as `"a,b"` on Linux (CI) and passes on macOS, so `ANY($n)` only
|
|
209
|
+
fails in CI. Pass `toPostgresArrayLiteral(values)` from
|
|
210
|
+
`@cosmicdrift/kumiko-framework/db` and cast the placeholder (`$1::text[]`);
|
|
211
|
+
the Unsafe Array Param guard warns about array literals.
|
|
207
212
|
- Never filter or count the rows of one `list` page in code. `list` returns
|
|
208
213
|
one page (default 50, `limit` at most 200). Pass
|
|
209
214
|
`filter: { field, op, value }` (`eq`, `ne`, `lt`, `gt`, `lte`, `gte`, `in`)
|
|
@@ -305,7 +310,7 @@ as bundled features.
|
|
|
305
310
|
| Public or anonymous endpoints | `anonymous` role | `agents/examples/anonymous-access.md` |
|
|
306
311
|
| Allowed state changes | Entity transitions | `agents/examples/state-machine.md` |
|
|
307
312
|
| React to a write in another feature | `r.defineEvent` + `emitEvent` + `r.multiStreamProjection` | `agents/examples/cross-feature-events.md` |
|
|
308
|
-
| Projections, event versions, history | `r.projection`, `ctx.
|
|
313
|
+
| Projections, event versions, history | `r.projection`, `ctx.events.load`, `ctx.dispatch.queryProjection` | `agents/examples/event-sourcing.md` |
|
|
309
314
|
| Before or after save logic | Lifecycle hooks | `agents/examples/lifecycle-hooks.md` |
|
|
310
315
|
| Typed errors with reasons | `@cosmicdrift/kumiko-framework/errors` | `agents/examples/error-contract.md` |
|
|
311
316
|
| Translations | `r.translations` + client translations | `agents/examples/i18n.md` |
|
package/README.md
CHANGED
|
@@ -108,7 +108,7 @@ export const taskFeature = defineFeature("tasks", (r) => {
|
|
|
108
108
|
- **Event-sourced by default.** Every write goes through `createEventStoreExecutor`
|
|
109
109
|
and appends a domain event to the aggregate stream. Auto-generated CRUD
|
|
110
110
|
events (`<entity>.created/updated/deleted/restored`) for record writes,
|
|
111
|
-
explicit `ctx.
|
|
111
|
+
explicit `ctx.events.append` for domain events with intent. Projections feed
|
|
112
112
|
off the stream for same-TX read-after-write consistency.
|
|
113
113
|
- **Async side-effects via cursor.** SSE broadcast, search indexing, and
|
|
114
114
|
feature-registered `r.multiStreamProjection` consumers run on a single
|
|
@@ -141,7 +141,7 @@ import type { SendDeletionVerificationEmailFn } from "@cosmicdrift/kumiko-bundle
|
|
|
141
141
|
import { selectMany } from "@cosmicdrift/kumiko-framework/db";
|
|
142
142
|
import { createEventsTable, eventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
143
143
|
import { createTestUser, testTenantId } from "@cosmicdrift/kumiko-framework/seeding";
|
|
144
|
-
import { resetTestTables,
|
|
144
|
+
import { resetTestTables, seedRowViaEventStore } from "@cosmicdrift/kumiko-testing/helpers";
|
|
145
145
|
import {
|
|
146
146
|
setupTestStack,
|
|
147
147
|
type TestStack,
|
|
@@ -186,9 +186,8 @@ afterAll(async () => {
|
|
|
186
186
|
beforeEach(async () => {
|
|
187
187
|
verifyCalls.length = 0;
|
|
188
188
|
await resetTestTables(stack.db, [userTable, tenantComplianceProfileTable, eventsTable]);
|
|
189
|
-
await
|
|
189
|
+
await seedRowViaEventStore(stack.db, userTable, {
|
|
190
190
|
id: user.id,
|
|
191
|
-
tenantId: tenant,
|
|
192
191
|
email: EMAIL,
|
|
193
192
|
passwordHash: "hashed",
|
|
194
193
|
displayName: "User",
|
|
@@ -68,7 +68,8 @@ row and the `read_fulfillments` row appear.
|
|
|
68
68
|
is re-run after `ms` on the same queue job: no retry attempt is used, no failure is logged
|
|
69
69
|
or recorded, and the run log shows only the runs that actually executed. `maxDefers`
|
|
70
70
|
(default 100) bounds it; beyond that the run fails. It needs a queued run: an inline boot
|
|
71
|
-
gate throws.
|
|
71
|
+
gate throws. `context.canDefer` is false in both cases, so the job checks it and calls the
|
|
72
|
+
carrier anyway instead of failing.
|
|
72
73
|
|
|
73
74
|
## Test
|
|
74
75
|
|
|
@@ -257,6 +258,7 @@ describe("api-worker-split", () => {
|
|
|
257
258
|
test("API-only: write lands, but the worker-applied read side stays empty", async () => {
|
|
258
259
|
const prefix = uniquePrefix();
|
|
259
260
|
const api = createApiEntrypoint({
|
|
261
|
+
rowLevelSecurity: "off",
|
|
260
262
|
registry: createRegistry([createApiWorkerSplitFeature()]),
|
|
261
263
|
context: { db: testDb.db, redis: testRedis.redis },
|
|
262
264
|
jwtSecret: JWT,
|
|
@@ -288,12 +290,14 @@ describe("api-worker-split", () => {
|
|
|
288
290
|
test("worker joins: consumes the job, applies the projection, writes the result back", async () => {
|
|
289
291
|
const prefix = uniquePrefix();
|
|
290
292
|
const api = createApiEntrypoint({
|
|
293
|
+
rowLevelSecurity: "off",
|
|
291
294
|
registry: createRegistry([createApiWorkerSplitFeature()]),
|
|
292
295
|
context: { db: testDb.db, redis: testRedis.redis },
|
|
293
296
|
jwtSecret: JWT,
|
|
294
297
|
jobs: { redisUrl: redisUrl(), queueNamePrefix: prefix },
|
|
295
298
|
});
|
|
296
299
|
const worker = createWorkerEntrypoint({
|
|
300
|
+
rowLevelSecurity: "off",
|
|
297
301
|
registry: createRegistry([createApiWorkerSplitFeature()]),
|
|
298
302
|
context: { db: testDb.db, redis: testRedis.redis },
|
|
299
303
|
jwtSecret: JWT,
|
|
@@ -335,12 +339,14 @@ describe("api-worker-split", () => {
|
|
|
335
339
|
test("a busy carrier defers the job without failing it, then the fulfillment lands", async () => {
|
|
336
340
|
const prefix = uniquePrefix();
|
|
337
341
|
const api = createApiEntrypoint({
|
|
342
|
+
rowLevelSecurity: "off",
|
|
338
343
|
registry: createRegistry([createApiWorkerSplitFeature()]),
|
|
339
344
|
context: { db: testDb.db, redis: testRedis.redis },
|
|
340
345
|
jwtSecret: JWT,
|
|
341
346
|
jobs: { redisUrl: redisUrl(), queueNamePrefix: prefix },
|
|
342
347
|
});
|
|
343
348
|
const worker = createWorkerEntrypoint({
|
|
349
|
+
rowLevelSecurity: "off",
|
|
344
350
|
registry: createRegistry([createApiWorkerSplitFeature()]),
|
|
345
351
|
context: { db: testDb.db, redis: testRedis.redis },
|
|
346
352
|
jwtSecret: JWT,
|
|
@@ -508,8 +514,9 @@ export function createApiWorkerSplitFeature() {
|
|
|
508
514
|
}
|
|
509
515
|
const { customerName } = processOrderPayloadSchema.parse(payload);
|
|
510
516
|
// Busy is not a failure: ctx.defer re-runs the job later without burning a retry.
|
|
517
|
+
// Once the defer budget is used up (or the run is inline), try anyway and let a failure retry.
|
|
511
518
|
const retryAfterMs = carrierRetryAfterMs();
|
|
512
|
-
if (retryAfterMs > 0) return context.defer(retryAfterMs);
|
|
519
|
+
if (retryAfterMs > 0 && context.canDefer) return context.defer(retryAfterMs);
|
|
513
520
|
const result = await fulfillWrite({
|
|
514
521
|
handlerQn: "orders:write:fulfillment:create",
|
|
515
522
|
payload: {
|
|
@@ -91,7 +91,7 @@ beforeEach(() => {
|
|
|
91
91
|
});
|
|
92
92
|
|
|
93
93
|
// The resolver needs an AuthClaimsContext per hook run. This sample doesn't
|
|
94
|
-
// exercise ctx.db or ctx.queryAs — real features would, and that's the
|
|
94
|
+
// exercise ctx.db or ctx.dispatch.queryAs — real features would, and that's the
|
|
95
95
|
// point of the fresh TenantDb the dispatcher builds. A stub is fine here.
|
|
96
96
|
const stubContext: AuthClaimsContext = {
|
|
97
97
|
db: {} as AuthClaimsContext["db"],
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# cross-feature-events
|
|
4
4
|
|
|
5
|
-
Feature appends a typed domain event via ctx.
|
|
5
|
+
Feature appends a typed domain event via ctx.events.append; a r.multiStreamProjection reacts asynchronously.
|
|
6
6
|
|
|
7
7
|
## README
|
|
8
8
|
|
|
@@ -19,10 +19,10 @@ Three building blocks:
|
|
|
19
19
|
|
|
20
20
|
- **`r.defineEvent("name", zodSchema)`** declares the name and payload.
|
|
21
21
|
The qualified name (e.g. `pubsub-orders:event:order-placed`) comes
|
|
22
|
-
back as `.name` — pass it directly to `ctx.
|
|
23
|
-
aren't registered are rejected by `ctx.
|
|
22
|
+
back as `.name` — pass it directly to `ctx.events.append`. Events that
|
|
23
|
+
aren't registered are rejected by `ctx.events.append` at the emit site.
|
|
24
24
|
|
|
25
|
-
- **`ctx.
|
|
25
|
+
- **`ctx.events.append({ aggregateId, aggregateType, type, payload })`**
|
|
26
26
|
appends the event onto the aggregate stream within the same TX.
|
|
27
27
|
Version lineage is continued automatically — no synthetic
|
|
28
28
|
`"pubsub"` stream anymore, the event truly lives on the aggregate.
|
|
@@ -40,7 +40,7 @@ Three building blocks:
|
|
|
40
40
|
HTTP → writeHandler
|
|
41
41
|
↓ TX begin
|
|
42
42
|
orderExecutor.create(...) ← business row + auto-event (pubsubOrder.created, v1)
|
|
43
|
-
ctx.
|
|
43
|
+
ctx.events.append({...}) ← domain event (pubsub-orders:event:order-placed, v2)
|
|
44
44
|
↓ TX commit
|
|
45
45
|
(async, post-commit)
|
|
46
46
|
event-dispatcher runOnce
|
|
@@ -50,7 +50,7 @@ HTTP → writeHandler
|
|
|
50
50
|
|
|
51
51
|
## Migration note
|
|
52
52
|
|
|
53
|
-
`r.postEvent` was removed in Sprint E.2. `ctx.
|
|
53
|
+
`r.postEvent` was removed in Sprint E.2. `ctx.events.append` +
|
|
54
54
|
`r.multiStreamProjection` is the unified Marten API for CRUD events,
|
|
55
55
|
domain events, and cross-feature reactions.
|
|
56
56
|
|
|
@@ -78,7 +78,7 @@ bun kumiko test integration samples/cross-feature-events
|
|
|
78
78
|
// Cross-Feature Reactions Sample — Integration Test
|
|
79
79
|
//
|
|
80
80
|
// Proves:
|
|
81
|
-
// 1. ctx.
|
|
81
|
+
// 1. ctx.events.append persists the domain event into the events-table
|
|
82
82
|
// inside the same TX as the business write, on the aggregate's own
|
|
83
83
|
// stream (aggregateType = "pubsub-order", not the legacy "pubsub").
|
|
84
84
|
// 2. The event-dispatcher picks it up and invokes the
|
|
@@ -119,7 +119,7 @@ beforeEach(async () => {
|
|
|
119
119
|
await resetEventStore(stack, ["read_sample_pubsub_orders"]);
|
|
120
120
|
});
|
|
121
121
|
|
|
122
|
-
describe("cross-feature reactions via ctx.
|
|
122
|
+
describe("cross-feature reactions via ctx.events.append + r.multiStreamProjection", () => {
|
|
123
123
|
test("write commits → event on aggregate stream → MSP handler receives it", async () => {
|
|
124
124
|
const data = await stack.http.writeOk(
|
|
125
125
|
"pubsub-orders:write:order:place",
|
|
@@ -195,7 +195,7 @@ describe("cross-feature reactions via ctx.appendEvent + r.multiStreamProjection"
|
|
|
195
195
|
// Cross-Feature Reactions Sample (Marten gold-standard path)
|
|
196
196
|
//
|
|
197
197
|
// Demonstrates the Sprint-E pattern for reacting to events across features:
|
|
198
|
-
// a writeHandler emits a DOMAIN event via `ctx.
|
|
198
|
+
// a writeHandler emits a DOMAIN event via `ctx.events.append(...)` onto the
|
|
199
199
|
// aggregate's own stream, and a `r.multiStreamProjection` picks it up
|
|
200
200
|
// asynchronously through the event-dispatcher.
|
|
201
201
|
//
|
|
@@ -203,11 +203,11 @@ describe("cross-feature reactions via ctx.appendEvent + r.multiStreamProjection"
|
|
|
203
203
|
//
|
|
204
204
|
// 1. `r.defineEvent("short-name", zodSchema)` declares the event shape.
|
|
205
205
|
// Returns a def whose `.name` is the fully-qualified event name —
|
|
206
|
-
// pass that straight to `ctx.
|
|
206
|
+
// pass that straight to `ctx.events.append` so there's no string to
|
|
207
207
|
// hand-type (and no way to emit an unregistered event: appendEvent
|
|
208
208
|
// rejects at the emit site).
|
|
209
209
|
//
|
|
210
|
-
// 2. `ctx.
|
|
210
|
+
// 2. `ctx.events.append({ aggregateId, aggregateType, type, payload })`
|
|
211
211
|
// writes the event onto the aggregate's own stream inside the same
|
|
212
212
|
// transaction as the business write. Commit both or roll back both —
|
|
213
213
|
// no lost events, no orphan events. The event carries real
|
|
@@ -261,7 +261,7 @@ export const pubsubOrderFeature = defineFeature("pubsubOrders", (r) => {
|
|
|
261
261
|
r.entity({ name: "pubsub-order", ...orderEntity });
|
|
262
262
|
|
|
263
263
|
// Define the event shape once. The returned `.name` is the qualified
|
|
264
|
-
// name ("pubsub-orders:event:order-placed") — pass it to ctx.
|
|
264
|
+
// name ("pubsub-orders:event:order-placed") — pass it to ctx.events.append.
|
|
265
265
|
const orderPlaced = r.defineEvent(
|
|
266
266
|
"order-placed",
|
|
267
267
|
z.object({ id: z.string(), customer: z.string(), product: z.string() }),
|
|
@@ -108,7 +108,7 @@ import {
|
|
|
108
108
|
nullBlindIndexesForSubject,
|
|
109
109
|
} from "@cosmicdrift/kumiko-framework/db";
|
|
110
110
|
import type { SaveContext } from "@cosmicdrift/kumiko-framework/engine";
|
|
111
|
-
import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
111
|
+
import { createEventsTable, eventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
112
112
|
import { TestUsers } from "@cosmicdrift/kumiko-framework/seeding";
|
|
113
113
|
import {
|
|
114
114
|
resetBlindIndexKeyForTests,
|
|
@@ -144,7 +144,7 @@ beforeEach(async () => {
|
|
|
144
144
|
// Fresh adapter per test = fresh key universe. Rows from earlier tests
|
|
145
145
|
// would name subjects this adapter never minted (fail-loud KeyNotFound),
|
|
146
146
|
// so the tables reset alongside the KMS.
|
|
147
|
-
await resetTestTables(stack.db, ["read_hr_employees", "read_hr_comments"]);
|
|
147
|
+
await resetTestTables(stack.db, ["read_hr_employees", "read_hr_comments", eventsTable]);
|
|
148
148
|
kms = new InMemoryKmsAdapter();
|
|
149
149
|
configurePiiSubjectKms(kms);
|
|
150
150
|
// Blind-index key: what runProdApp({ blindIndexKey }) wires in production.
|
|
@@ -181,7 +181,7 @@ beforeAll(async () => {
|
|
|
181
181
|
extraContext: ({ registry }) => ({
|
|
182
182
|
configResolver: resolver,
|
|
183
183
|
configEncryption: encryption,
|
|
184
|
-
|
|
184
|
+
configAccessorFactory: createConfigAccessorFactory(registry, resolver),
|
|
185
185
|
}),
|
|
186
186
|
});
|
|
187
187
|
await unsafePushTables(stack.db, { configValuesTable });
|
|
@@ -119,7 +119,7 @@ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
|
119
119
|
import { buildEntityTable } from "@cosmicdrift/kumiko-framework/db";
|
|
120
120
|
import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
121
121
|
import { createTestUser, TestUsers } from "@cosmicdrift/kumiko-framework/seeding";
|
|
122
|
-
import {
|
|
122
|
+
import { updateRowViaEventStore } from "@cosmicdrift/kumiko-testing/helpers";
|
|
123
123
|
import {
|
|
124
124
|
setupTestStack,
|
|
125
125
|
type TestStack,
|
|
@@ -139,7 +139,7 @@ beforeAll(async () => {
|
|
|
139
139
|
await unsafeCreateEntityTable(stack.db, orderEntity);
|
|
140
140
|
await createEventsTable(stack.db);
|
|
141
141
|
});
|
|
142
|
-
afterAll(async () => stack
|
|
142
|
+
afterAll(async () => stack?.cleanup());
|
|
143
143
|
|
|
144
144
|
// --- 1) Zod validation error via schema: empty cart rejected ---
|
|
145
145
|
|
|
@@ -222,11 +222,16 @@ describe("ConflictError → 409", () => {
|
|
|
222
222
|
{ totalCents: 100 },
|
|
223
223
|
alice,
|
|
224
224
|
);
|
|
225
|
-
//
|
|
226
|
-
//
|
|
227
|
-
//
|
|
228
|
-
|
|
229
|
-
|
|
225
|
+
// The sample feature doesn't expose a "place" action, so we can't walk the
|
|
226
|
+
// state machine — the point of this test is ConflictError semantics, not the
|
|
227
|
+
// transition path itself.
|
|
228
|
+
await updateRowViaEventStore(
|
|
229
|
+
stack.db,
|
|
230
|
+
{ table: orderTable, entity: orderEntity, entityName: "order" },
|
|
231
|
+
{ id: order.id },
|
|
232
|
+
{ status: "paid" },
|
|
233
|
+
{ tenantId: alice.tenantId },
|
|
234
|
+
);
|
|
230
235
|
|
|
231
236
|
const error = await stack.http.writeErr(
|
|
232
237
|
"orders-lite:write:order:cancel",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# event-sourcing
|
|
4
4
|
|
|
5
|
-
Production-pattern ES sample: r.defineEvent (versioned + migrations) + ctx.
|
|
5
|
+
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.
|
|
6
6
|
|
|
7
7
|
## README
|
|
8
8
|
|
|
@@ -17,12 +17,12 @@ blocks Kumiko provides.
|
|
|
17
17
|
| API | Purpose |
|
|
18
18
|
|---|---|
|
|
19
19
|
| `r.defineEvent(name, schema, { version, migrations })` | Event schema with version number + upcaster chain |
|
|
20
|
-
| `ctx.
|
|
20
|
+
| `ctx.events.append({ aggregateId, aggregateType, type, payload })` | Domain event on aggregate stream |
|
|
21
21
|
| `r.projection(...)` | Single-stream read model, inline in the write TX |
|
|
22
22
|
| `r.multiStreamProjection(...)` | Cross-aggregate read model, async via dispatcher |
|
|
23
|
-
| `ctx.
|
|
24
|
-
| `ctx.
|
|
25
|
-
| `ctx.queryProjection(name)` | Tenant-scoped read-model query |
|
|
23
|
+
| `ctx.events.load(id, { asOf })` | Live aggregation with point-in-time |
|
|
24
|
+
| `ctx.events.archive(id, { aggregateType })` | Archive a stream (Marten `ArchiveStream`) |
|
|
25
|
+
| `ctx.dispatch.queryProjection(name)` | Tenant-scoped read-model query |
|
|
26
26
|
|
|
27
27
|
## Domain
|
|
28
28
|
|
|
@@ -53,7 +53,7 @@ HTTP POST /api/write { type: "showcase:write:invoice:approve", ... }
|
|
|
53
53
|
↓
|
|
54
54
|
writeHandler("invoice:approve")
|
|
55
55
|
↓ TX begin
|
|
56
|
-
ctx.
|
|
56
|
+
ctx.events.append({ type: "showcase:event:invoice-approved", ... })
|
|
57
57
|
r.projection("invoice-detail") ← updates status = "approved"
|
|
58
58
|
↓ TX commit
|
|
59
59
|
(async)
|
|
@@ -86,12 +86,12 @@ Six integration tests pin everything at once:
|
|
|
86
86
|
//
|
|
87
87
|
// Exercises every Sprint-E Marten gold-standard API end-to-end:
|
|
88
88
|
// - r.defineEvent with version + migrations (sync + async upcaster)
|
|
89
|
-
// - ctx.
|
|
89
|
+
// - ctx.events.append onto the aggregate stream (incl. headers metadata)
|
|
90
90
|
// - r.projection (single-stream, inline)
|
|
91
91
|
// - r.multiStreamProjection (async)
|
|
92
|
-
// - ctx.
|
|
93
|
-
// - ctx.
|
|
94
|
-
// - ctx.queryProjection
|
|
92
|
+
// - ctx.events.load with { asOf }
|
|
93
|
+
// - ctx.events.archive
|
|
94
|
+
// - ctx.dispatch.queryProjection
|
|
95
95
|
// - streamAllEventsByType (memory-bounded ops iteration)
|
|
96
96
|
// - getAllProjectionProgress (projection lag for ops dashboards)
|
|
97
97
|
|
|
@@ -364,7 +364,7 @@ describe("Event Sourcing Showcase", () => {
|
|
|
364
364
|
expect(beforeSnapshot.state.status).toBe("paid");
|
|
365
365
|
expect(beforeSnapshot.state.amountCents).toBe(3300);
|
|
366
366
|
|
|
367
|
-
// Take a snapshot after the pay event. ctx.
|
|
367
|
+
// Take a snapshot after the pay event. ctx.events.snapshot writes
|
|
368
368
|
// kumiko_snapshots with the committed state + version.
|
|
369
369
|
const snapResult = await stack.http.writeOk<{ id: string; snapshotVersion: number }>(
|
|
370
370
|
"showcase:write:invoice:take-snapshot",
|
|
@@ -494,7 +494,7 @@ describe("Event Sourcing Showcase", () => {
|
|
|
494
494
|
expect(otherView[0]?.totalCents).toBe(200);
|
|
495
495
|
});
|
|
496
496
|
|
|
497
|
-
test("ctx.
|
|
497
|
+
test("ctx.events.append with headers: Marten free key/value metadata lands in stored event", async () => {
|
|
498
498
|
const { id } = await stack.http.writeOk<{ id: string }>(
|
|
499
499
|
"showcase:write:invoice:create",
|
|
500
500
|
{ customer: "MetaCo" },
|
|
@@ -535,7 +535,7 @@ describe("Event Sourcing Showcase", () => {
|
|
|
535
535
|
});
|
|
536
536
|
|
|
537
537
|
// Append a v1 acknowledged event directly to simulate a pre-migration
|
|
538
|
-
// payload on disk. ctx.
|
|
538
|
+
// payload on disk. ctx.events.append always writes the current version,
|
|
539
539
|
// so the only way to test the read-time upcaster is to write the older
|
|
540
540
|
// shape via the raw event-store.
|
|
541
541
|
const invoiceId = "00000000-0000-4000-8000-00000000ac01";
|
|
@@ -591,7 +591,7 @@ describe("Event Sourcing Showcase", () => {
|
|
|
591
591
|
approverDisplayName: "Quincy Acknowledger",
|
|
592
592
|
});
|
|
593
593
|
|
|
594
|
-
// Sanity check the ctx.
|
|
594
|
+
// Sanity check the ctx.events.append path too: it writes the current
|
|
595
595
|
// shape directly (handler resolved displayName synchronously), so
|
|
596
596
|
// the upcaster is a no-op on these events.
|
|
597
597
|
const { id: liveId } = await stack.http.writeOk<{ id: string }>(
|
|
@@ -836,10 +836,10 @@ describe("role-restricted write handlers", () => {
|
|
|
836
836
|
// - emitEvent with headers — Marten free key/value metadata
|
|
837
837
|
// - r.projection — single-stream read model (inline in the write TX)
|
|
838
838
|
// - r.multiStreamProjection — cross-aggregate async read model
|
|
839
|
-
// - ctx.
|
|
840
|
-
// - ctx.
|
|
841
|
-
// - ctx.queryProjection — tenant-scoped read of a projection table
|
|
842
|
-
// - ctx.
|
|
839
|
+
// - ctx.events.load with { asOf } — point-in-time aggregate state
|
|
840
|
+
// - ctx.events.archive / ctx.events.restore — Marten ArchiveStream
|
|
841
|
+
// - ctx.dispatch.queryProjection — tenant-scoped read of a projection table
|
|
842
|
+
// - ctx.events.snapshot + ctx.events.loadWithSnapshot — perf path
|
|
843
843
|
// for aggregates with long event tails (O(1) vs O(N) reduce), incl.
|
|
844
844
|
// the auto-snapshot policy ({ snapshotEvery, snapshotVersion })
|
|
845
845
|
// - streamAllEventsByType — memory-bounded iteration for ops/export jobs
|
|
@@ -1166,7 +1166,7 @@ export const invoiceFeature = defineFeature("showcase", (r) => {
|
|
|
1166
1166
|
name: "invoice:archive",
|
|
1167
1167
|
schema: z.object({ id: z.uuid() }),
|
|
1168
1168
|
handler: async (event, ctx) => {
|
|
1169
|
-
await ctx.
|
|
1169
|
+
await ctx.events.archive(event.payload.id, { aggregateType: "showcase-invoice" });
|
|
1170
1170
|
return { isSuccess: true as const, data: { id: event.payload.id } };
|
|
1171
1171
|
},
|
|
1172
1172
|
access: { roles: ["Admin"] },
|
|
@@ -1181,14 +1181,14 @@ export const invoiceFeature = defineFeature("showcase", (r) => {
|
|
|
1181
1181
|
handler: async (event, ctx) => {
|
|
1182
1182
|
// Rebuild the state from the current stream so the snapshot reflects
|
|
1183
1183
|
// the committed event log, not an in-memory guess. Use the upcaster-
|
|
1184
|
-
// aware ctx.
|
|
1185
|
-
const events = await ctx.
|
|
1184
|
+
// aware ctx.events.load to stay consistent with read-time semantics.
|
|
1185
|
+
const events = await ctx.events.load(event.payload.id);
|
|
1186
1186
|
const state: InvoiceState = { ...initialInvoiceState };
|
|
1187
1187
|
for (const evt of events) {
|
|
1188
1188
|
reduceInvoice(state, evt);
|
|
1189
1189
|
}
|
|
1190
1190
|
const version = events.length > 0 ? (events[events.length - 1]?.version ?? 0) : 0;
|
|
1191
|
-
await ctx.
|
|
1191
|
+
await ctx.events.snapshot({
|
|
1192
1192
|
aggregateId: event.payload.id,
|
|
1193
1193
|
aggregateType: "showcase-invoice",
|
|
1194
1194
|
version,
|
|
@@ -1201,13 +1201,13 @@ export const invoiceFeature = defineFeature("showcase", (r) => {
|
|
|
1201
1201
|
|
|
1202
1202
|
// --- Query handlers ---
|
|
1203
1203
|
|
|
1204
|
-
// Live aggregation via ctx.
|
|
1204
|
+
// Live aggregation via ctx.events.load — reduces events into a state
|
|
1205
1205
|
// snapshot. Supports asOf for point-in-time reads.
|
|
1206
1206
|
r.queryHandler({
|
|
1207
1207
|
name: "invoice:state",
|
|
1208
1208
|
schema: z.object({ id: z.uuid(), asOf: z.iso.datetime().optional() }),
|
|
1209
1209
|
handler: async (query, ctx) => {
|
|
1210
|
-
const events = await ctx.
|
|
1210
|
+
const events = await ctx.events.load(query.payload.id, {
|
|
1211
1211
|
...(query.payload.asOf ? { asOf: Temporal.Instant.from(query.payload.asOf) } : {}),
|
|
1212
1212
|
});
|
|
1213
1213
|
const state: InvoiceState = { ...initialInvoiceState };
|
|
@@ -1232,7 +1232,7 @@ export const invoiceFeature = defineFeature("showcase", (r) => {
|
|
|
1232
1232
|
name: "invoice:fast-state",
|
|
1233
1233
|
schema: z.object({ id: z.uuid() }),
|
|
1234
1234
|
handler: async (query, ctx) => {
|
|
1235
|
-
const result = await ctx.
|
|
1235
|
+
const result = await ctx.events.loadWithSnapshot<InvoiceStateRecord>(
|
|
1236
1236
|
query.payload.id,
|
|
1237
1237
|
(state, evt) => {
|
|
1238
1238
|
const next: InvoiceStateRecord = { ...state };
|
|
@@ -1261,7 +1261,7 @@ export const invoiceFeature = defineFeature("showcase", (r) => {
|
|
|
1261
1261
|
},
|
|
1262
1262
|
});
|
|
1263
1263
|
|
|
1264
|
-
// Read-model query via ctx.queryProjection — auto-tenant-scoped. The
|
|
1264
|
+
// Read-model query via ctx.dispatch.queryProjection — auto-tenant-scoped. The
|
|
1265
1265
|
// helper collapses the zero-argument "return this projection" pattern
|
|
1266
1266
|
// into a single call; returns { rows } so the response shape stays
|
|
1267
1267
|
// consistent with other list handlers.
|
|
@@ -1277,11 +1277,11 @@ export const invoiceFeature = defineFeature("showcase", (r) => {
|
|
|
1277
1277
|
}),
|
|
1278
1278
|
);
|
|
1279
1279
|
|
|
1280
|
-
// Slow synthetic export — demonstrates ctx.signal honouring inside a
|
|
1280
|
+
// Slow synthetic export — demonstrates ctx.lifecycle.signal honouring inside a
|
|
1281
1281
|
// long-running handler loop. Real-world equivalents: PDF batch export,
|
|
1282
1282
|
// bulk CSV download, multi-stream audit walk. Mobile clients that
|
|
1283
1283
|
// navigate away mid-export should NOT keep the server busy producing
|
|
1284
|
-
// bytes nobody will read. The handler checks ctx.signal at every
|
|
1284
|
+
// bytes nobody will read. The handler checks ctx.lifecycle.signal at every
|
|
1285
1285
|
// iteration; on abort, throws and the dispatcher returns an error to
|
|
1286
1286
|
// the (already-disconnected) client.
|
|
1287
1287
|
r.queryHandler({
|
|
@@ -1290,7 +1290,7 @@ export const invoiceFeature = defineFeature("showcase", (r) => {
|
|
|
1290
1290
|
handler: async (query, ctx) => {
|
|
1291
1291
|
const accumulated: number[] = [];
|
|
1292
1292
|
for (let i = 0; i < query.payload.chunks; i++) {
|
|
1293
|
-
ctx.signal?.throwIfAborted();
|
|
1293
|
+
ctx.lifecycle.signal?.throwIfAborted();
|
|
1294
1294
|
// Fake "work per chunk". Realistic handler would assemble a row,
|
|
1295
1295
|
// hit a remote service, etc.
|
|
1296
1296
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# files-post-processing
|
|
4
4
|
|
|
5
|
-
The three ways to generate an image variant: declarative field variants, imperative ctx.derivatives.variant() with region-blur, and the public route behind a default-deny predicate.
|
|
5
|
+
The three ways to generate an image variant: declarative field variants, imperative ctx.services.derivatives.variant() with region-blur, and the public route behind a default-deny predicate.
|
|
6
6
|
|
|
7
7
|
## README
|
|
8
8
|
|
|
@@ -13,7 +13,7 @@ File upload plus post-processing hooks.
|
|
|
13
13
|
## What it shows
|
|
14
14
|
|
|
15
15
|
- Declarative `variants` on `createImageField` (file-derivatives)
|
|
16
|
-
- Imperative `ctx.derivatives.variant()` path and the public variant route (`EXT_DERIVATIVE_PUBLIC_PREDICATE`)
|
|
16
|
+
- Imperative `ctx.services.derivatives.variant()` path and the public variant route (`EXT_DERIVATIVE_PUBLIC_PREDICATE`)
|
|
17
17
|
|
|
18
18
|
## Source
|
|
19
19
|
|
|
@@ -41,7 +41,7 @@ bun test
|
|
|
41
41
|
// 1. declarative — GET /api/files/:id/variant/:name resolves a field's
|
|
42
42
|
// declared variant.
|
|
43
43
|
// 2. imperative — the `set-cover` write-handler calls
|
|
44
|
-
// ctx.derivatives.variant() directly, with a region-blur.
|
|
44
|
+
// ctx.services.derivatives.variant() directly, with a region-blur.
|
|
45
45
|
// 3. public route — GET /media/:fileRefId/:variant, default-deny until a
|
|
46
46
|
// photo is explicitly published.
|
|
47
47
|
|
|
@@ -178,7 +178,7 @@ describe("entry point 1 — declarative field variant", () => {
|
|
|
178
178
|
});
|
|
179
179
|
});
|
|
180
180
|
|
|
181
|
-
describe("entry point 2 — imperative ctx.derivatives.variant() with region-blur", () => {
|
|
181
|
+
describe("entry point 2 — imperative ctx.services.derivatives.variant() with region-blur", () => {
|
|
182
182
|
test("set-cover derives a variant with no field declaration involved, and tracks order", async () => {
|
|
183
183
|
const fileId = await uploadPhoto(null);
|
|
184
184
|
|
|
@@ -292,7 +292,7 @@ describe("event emission contract", () => {
|
|
|
292
292
|
// resolves + caches the variant behind the auth-gated
|
|
293
293
|
// `GET /api/files/:id/variant/:name` route, no handler code needed.
|
|
294
294
|
// 2. Imperative — the `set-cover` write-handler calls
|
|
295
|
-
// `ctx.derivatives.variant()` directly. This is for apps that track
|
|
295
|
+
// `ctx.services.derivatives.variant()` directly. This is for apps that track
|
|
296
296
|
// images as their own records (ordering, a chosen cover image) and for
|
|
297
297
|
// region-blur, whose coordinates are runtime data that can't live in a
|
|
298
298
|
// static field declaration.
|
|
@@ -371,13 +371,15 @@ export const filesPostProcessingFeature = defineFeature("files-post-processing",
|
|
|
371
371
|
.optional(),
|
|
372
372
|
}),
|
|
373
373
|
handler: async (event, ctx) => {
|
|
374
|
-
if (!ctx.derivatives) {
|
|
374
|
+
if (!ctx.services.derivatives) {
|
|
375
375
|
return writeFailure(
|
|
376
|
-
new InternalError({
|
|
376
|
+
new InternalError({
|
|
377
|
+
message: "ctx.services.derivatives missing — is file-derivatives mounted?",
|
|
378
|
+
}),
|
|
377
379
|
);
|
|
378
380
|
}
|
|
379
381
|
const { fileRefId, blurRegion } = event.payload;
|
|
380
|
-
const result = await ctx.derivatives.variant(
|
|
382
|
+
const result = await ctx.services.derivatives.variant(
|
|
381
383
|
fileRefId,
|
|
382
384
|
{
|
|
383
385
|
maxEdge: 800,
|
|
@@ -153,6 +153,7 @@ describe("inbound-mail triage sample", () => {
|
|
|
153
153
|
]);
|
|
154
154
|
const redisUrl = `redis://${testRedis.redis.options.host}:${testRedis.redis.options.port}/${testRedis.redis.options.db}`;
|
|
155
155
|
const entry = createAllInOneEntrypoint({
|
|
156
|
+
rowLevelSecurity: "off",
|
|
156
157
|
registry,
|
|
157
158
|
context: { db: testDb.db, redis: testRedis.redis },
|
|
158
159
|
jwtSecret: JWT,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# lane-routing
|
|
4
4
|
|
|
5
|
-
runIn lane-routing: r.job pinned to api/worker deploy-lanes, event-chain via ctx.
|
|
5
|
+
runIn lane-routing: r.job pinned to api/worker deploy-lanes, event-chain via ctx.events.append, verified end-to-end through createAllInOneEntrypoint.
|
|
6
6
|
|
|
7
7
|
## README
|
|
8
8
|
|
|
@@ -94,6 +94,7 @@ describe("lane-routing sample", () => {
|
|
|
94
94
|
const registry = createRegistry([createLaneRoutingFeature()]);
|
|
95
95
|
const redisUrl = `redis://${testRedis.redis.options.host}:${testRedis.redis.options.port}/${testRedis.redis.options.db}`;
|
|
96
96
|
const entry = createAllInOneEntrypoint({
|
|
97
|
+
rowLevelSecurity: "off",
|
|
97
98
|
registry,
|
|
98
99
|
context: { db: testDb.db, redis: testRedis.redis },
|
|
99
100
|
jwtSecret: JWT,
|
|
@@ -108,9 +108,9 @@ A one-shot setup routine that runs on first boot or via the CLI:
|
|
|
108
108
|
// bin/seed-legal.ts
|
|
109
109
|
import { seedTextBlock } from "@cosmicdrift/kumiko-bundled-features/template-resolver/seeding";
|
|
110
110
|
import { SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
|
|
111
|
-
import {
|
|
111
|
+
import { createDbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
112
112
|
|
|
113
|
-
const db =
|
|
113
|
+
const { db } = createDbConnection({ url: process.env.DATABASE_URL! });
|
|
114
114
|
|
|
115
115
|
await seedTextBlock(db, {
|
|
116
116
|
tenantId: SYSTEM_TENANT_ID,
|
|
@@ -35,8 +35,8 @@ back.
|
|
|
35
35
|
- **`r.hook({ type: "postDelete", target: { allOf: entityRef }, handler })`** — fires after commit.
|
|
36
36
|
External side effects (logs, notifications) belong here because
|
|
37
37
|
failures cannot roll the delete back.
|
|
38
|
-
- **`ctx.
|
|
39
|
-
the handler transaction (or the enclosing savepoint of a nested `ctx.write`) does not commit.
|
|
38
|
+
- **`ctx.lifecycle.afterRollback(fn)`** — the counterpart of `ctx.lifecycle.afterCommit`: runs `fn` when
|
|
39
|
+
the handler transaction (or the enclosing savepoint of a nested `ctx.dispatch.write`) does not commit.
|
|
40
40
|
Use it to give back something reserved outside the transaction, like the slot in
|
|
41
41
|
`article:reserve-slot`. A failed COMMIT triggers it too, so write the callback idempotent.
|
|
42
42
|
|
|
@@ -356,7 +356,7 @@ export const articlesFeature = defineFeature("blog", (r) => {
|
|
|
356
356
|
handler: async (event, ctx) => {
|
|
357
357
|
const { slot, reject } = event.payload;
|
|
358
358
|
reservedSlots.add(slot);
|
|
359
|
-
ctx.
|
|
359
|
+
ctx.lifecycle.afterRollback?.(async () => {
|
|
360
360
|
reservedSlots.delete(slot);
|
|
361
361
|
});
|
|
362
362
|
if (reject) return writeFailure(new UnprocessableError("slot_rejected"));
|
|
@@ -51,7 +51,7 @@ r.config({
|
|
|
51
51
|
|
|
52
52
|
- **`backing: "secrets"`** — the value lives in the secrets store (envelope
|
|
53
53
|
encryption, KEK rotation, audit-on-read) instead of `config_values`. Set/read/
|
|
54
|
-
reset dispatch through `ctx.secrets`; the query handlers mask the value while
|
|
54
|
+
reset dispatch through `ctx.services.secrets`; the query handlers mask the value while
|
|
55
55
|
the owning feature still reads the revealed plaintext via `ctx.config`. Only
|
|
56
56
|
valid for `scope: "system"` — secrets are flat per `(tenant, key)` with no
|
|
57
57
|
cascade, so a tenant override would be incoherent and is rejected at boot.
|
|
@@ -80,7 +80,7 @@ await runProdApp({
|
|
|
80
80
|
envSchema, // composeEnvSchema({ core: frameworkCoreEnvSchema, features })
|
|
81
81
|
extraContext: ({ db, registry }) => ({
|
|
82
82
|
configResolver: resolver,
|
|
83
|
-
|
|
83
|
+
configAccessorFactory: createConfigAccessorFactory(registry, resolver),
|
|
84
84
|
// Required whenever a key declares backing:"secrets" — without it the set
|
|
85
85
|
// and read paths fail loud, never silently miss.
|
|
86
86
|
secrets: createSecretsContext({ db, masterKeyProvider, registry }),
|
|
@@ -90,7 +90,7 @@ await runProdApp({
|
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
Register the `secrets` feature too so its `tenant_secrets` table is migrated;
|
|
93
|
-
the config backing only needs the `ctx.secrets` context shown above.
|
|
93
|
+
the config backing only needs the `ctx.services.secrets` context shown above.
|
|
94
94
|
|
|
95
95
|
## Vs. the neighbouring recipes
|
|
96
96
|
|
|
@@ -211,7 +211,7 @@ beforeAll(async () => {
|
|
|
211
211
|
const resolver = createConfigResolver();
|
|
212
212
|
return {
|
|
213
213
|
configResolver: resolver,
|
|
214
|
-
|
|
214
|
+
configAccessorFactory: createConfigAccessorFactory(registry, resolver),
|
|
215
215
|
secrets: createSecretsContext({ db, masterKeyProvider, registry }),
|
|
216
216
|
};
|
|
217
217
|
},
|