@cosmicdrift/kumiko-framework 0.389.0 → 0.390.1
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/driver-value-preparation.js +23 -2
- 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 +84 -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 +6 -0
- package/dist/db/row-level-security-boot-check.js +86 -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 +12 -2
- package/dist/schema-cli/shared.js +24 -2
- package/dist/schema-cli/status-command.js +8 -2
- package/dist/schema-cli/validate-command.js +48 -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 +2 -9
- package/dist/upgrade-cli.js +28 -70
- 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 +23 -19
- package/src/changes.json +236 -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/dist/db/table-builder.js
CHANGED
package/dist/db/table-info.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { camelCase as envCamelCase } from "../env/
|
|
1
|
+
import { camelCase as envCamelCase } from "../env/internals.js";
|
|
2
2
|
import { toSnakeCase } from "./table-builder.js";
|
|
3
3
|
import { asEntityTableMeta } from "./table-introspection.js";
|
|
4
4
|
// Idempotent snake_case → camelCase. `env.camelCase` always lowercases first
|
package/dist/db/table-push.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { EntityDefinition } from "
|
|
1
|
+
import type { EntityDefinition } from "@cosmicdrift/kumiko-types/fields";
|
|
2
2
|
import type { DbConnection } from "./connection.ts";
|
|
3
3
|
import type { ColumnMeta, EntityTableMeta, IndexMeta } from "./entity-table-meta.ts";
|
|
4
|
+
import type { RowLevelSecurityMode } from "./render-rls-ddl.ts";
|
|
4
5
|
/**
|
|
5
6
|
* Bypass: creates an entity-table directly without going through the
|
|
6
7
|
* full registry. Reserved for framework-internal meta-tables and
|
|
@@ -13,6 +14,12 @@ export declare function tableToMeta(table: unknown): EntityTableMeta;
|
|
|
13
14
|
export declare function addMissingColumns(db: DbConnection, tableName: string, columns: readonly ColumnMeta[]): Promise<void>;
|
|
14
15
|
/** CREATE [UNIQUE] INDEX IF NOT EXISTS for exactly the given indexes. */
|
|
15
16
|
export declare function addMissingIndexes(db: DbConnection, tableName: string, indexes: readonly IndexMeta[]): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Re-applies the row-level security DDL on a table that already exists. The create functions of
|
|
19
|
+
* framework tables skip the push for existing tables, so databases created before row-level
|
|
20
|
+
* security was switched on would never get the policies. Idempotent; no-op unless the mode is "on".
|
|
21
|
+
*/
|
|
22
|
+
export declare function ensureTableRowLevelSecurity(db: DbConnection, table: unknown): Promise<void>;
|
|
16
23
|
/**
|
|
17
24
|
* Bypass: pushes table definitions to the database directly. Produces
|
|
18
25
|
* CREATE TABLE IF NOT EXISTS + CREATE INDEX statements via renderTableDdl
|
|
@@ -21,4 +28,6 @@ export declare function addMissingIndexes(db: DbConnection, tableName: string, i
|
|
|
21
28
|
* Reserved for framework-internal meta-tables + test setup. App-defined
|
|
22
29
|
* entities go through `kumiko schema apply` (committed SQL files).
|
|
23
30
|
*/
|
|
24
|
-
export declare function unsafePushTables(db: DbConnection, tables: Record<string, unknown>, prevTables?: Record<string, unknown
|
|
31
|
+
export declare function unsafePushTables(db: DbConnection, tables: Record<string, unknown>, prevTables?: Record<string, unknown>, options?: {
|
|
32
|
+
readonly rowLevelSecurity?: RowLevelSecurityMode;
|
|
33
|
+
}): Promise<void>;
|
package/dist/db/table-push.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { pgTypeToSqlType } from "./dialect.js";
|
|
2
|
-
import { alterTableAddColumn, createIndexIfNotExists, executeDdlStatement } from "./queries/ddl.js";
|
|
2
|
+
import { alterTableAddColumn, applyTableRowLevelSecurity, createIndexIfNotExists, executeDdlStatement, } from "./queries/ddl.js";
|
|
3
3
|
import { renderTableDdl } from "./render-ddl.js";
|
|
4
|
+
import { rowLevelSecurityModeOf } from "./row-level-security-connection.js";
|
|
4
5
|
import { tableExists } from "./schema-inspection.js";
|
|
5
6
|
import { buildEntityTable, toTableName } from "./table-builder.js";
|
|
6
7
|
import { asEntityTableMeta } from "./table-introspection.js";
|
|
@@ -46,6 +47,15 @@ export async function addMissingIndexes(db, tableName, indexes) {
|
|
|
46
47
|
await createIndexIfNotExists(db, kind, idx.name, tableName, colList, idx.whereSql);
|
|
47
48
|
}
|
|
48
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Re-applies the row-level security DDL on a table that already exists. The create functions of
|
|
52
|
+
* framework tables skip the push for existing tables, so databases created before row-level
|
|
53
|
+
* security was switched on would never get the policies. Idempotent; no-op unless the mode is "on".
|
|
54
|
+
*/
|
|
55
|
+
export async function ensureTableRowLevelSecurity(db, table) {
|
|
56
|
+
if (rowLevelSecurityModeOf(db) === "on")
|
|
57
|
+
await applyTableRowLevelSecurity(db, tableToMeta(table));
|
|
58
|
+
}
|
|
49
59
|
/**
|
|
50
60
|
* Bypass: pushes table definitions to the database directly. Produces
|
|
51
61
|
* CREATE TABLE IF NOT EXISTS + CREATE INDEX statements via renderTableDdl
|
|
@@ -54,7 +64,8 @@ export async function addMissingIndexes(db, tableName, indexes) {
|
|
|
54
64
|
* Reserved for framework-internal meta-tables + test setup. App-defined
|
|
55
65
|
* entities go through `kumiko schema apply` (committed SQL files).
|
|
56
66
|
*/
|
|
57
|
-
export async function unsafePushTables(db, tables, prevTables) {
|
|
67
|
+
export async function unsafePushTables(db, tables, prevTables, options = {}) {
|
|
68
|
+
const rowLevelSecurity = options.rowLevelSecurity ?? rowLevelSecurityModeOf(db);
|
|
58
69
|
const prevMetas = new Map();
|
|
59
70
|
if (prevTables) {
|
|
60
71
|
for (const [key, table] of Object.entries(prevTables)) {
|
|
@@ -78,6 +89,8 @@ export async function unsafePushTables(db, tables, prevTables) {
|
|
|
78
89
|
await executeDdlStatement(db, stmt);
|
|
79
90
|
}
|
|
80
91
|
}
|
|
92
|
+
if (rowLevelSecurity === "on")
|
|
93
|
+
await applyTableRowLevelSecurity(db, meta);
|
|
81
94
|
}
|
|
82
95
|
}
|
|
83
96
|
// @wrapper-known semantic-alias
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { TenantDb } from "@cosmicdrift/kumiko-types/tenant-db-types";
|
|
2
|
+
import type { TenantId } from "../engine/types/identifiers.ts";
|
|
2
3
|
import { InternalError } from "../errors/index.ts";
|
|
3
4
|
import type { DbRunner } from "./connection.ts";
|
|
5
|
+
import { type TenantDbModeOptions } from "./row-level-security-scope.ts";
|
|
4
6
|
export declare function isBoundTenantDb(value: unknown): value is TenantDb;
|
|
5
7
|
export declare function isDbRunner(value: unknown): value is DbRunner;
|
|
6
|
-
export declare function bindTenantDbRunner(tenantDb: TenantDb, runner: DbRunner): void;
|
|
8
|
+
export declare function bindTenantDbRunner(tenantDb: TenantDb, runner: DbRunner, modeOptions: TenantDbModeOptions, tenantId: TenantId): void;
|
|
7
9
|
export declare function tenantDbRunner(tenantDb: TenantDb): DbRunner;
|
|
8
10
|
export declare function denyTenantDbWrites(tenantDb: TenantDb, reason: string): void;
|
|
9
11
|
export declare function tenantDbWritesDeniedReason(tenantDb: TenantDb): string | undefined;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { propertyOf } from "@cosmicdrift/kumiko-types/type-guards";
|
|
2
2
|
import { InternalError } from "../errors/index.js";
|
|
3
|
+
import { tenantDbRowLevelSecurityScope, withRowLevelSecurityScope, } from "./row-level-security-scope.js";
|
|
3
4
|
const tenantDbRunners = new WeakMap();
|
|
4
5
|
export function isBoundTenantDb(value) {
|
|
5
6
|
return typeof value === "object" && value !== null && tenantDbRunners.has(value);
|
|
@@ -7,8 +8,8 @@ export function isBoundTenantDb(value) {
|
|
|
7
8
|
export function isDbRunner(value) {
|
|
8
9
|
return typeof propertyOf(value, "unsafe") === "function";
|
|
9
10
|
}
|
|
10
|
-
export function bindTenantDbRunner(tenantDb, runner) {
|
|
11
|
-
tenantDbRunners.set(tenantDb, runner);
|
|
11
|
+
export function bindTenantDbRunner(tenantDb, runner, modeOptions, tenantId) {
|
|
12
|
+
tenantDbRunners.set(tenantDb, withRowLevelSecurityScope(runner, tenantDbRowLevelSecurityScope(modeOptions, tenantId)));
|
|
12
13
|
}
|
|
13
14
|
// WeakMap.get never reads a property off tenantDb — safe even when tenantDb is a
|
|
14
15
|
// throwing systemScope guard Proxy that rejects every property access.
|
|
@@ -31,7 +32,7 @@ export function tenantDbWritesDeniedReason(tenantDb) {
|
|
|
31
32
|
}
|
|
32
33
|
export function tenantDbWritesDeniedError(operation, reason) {
|
|
33
34
|
return new InternalError({
|
|
34
|
-
message: `${operation}: writes are not available ${reason}; run the write through ctx.write so it gets its own transaction`,
|
|
35
|
+
message: `${operation}: writes are not available ${reason}; run the write through ctx.dispatch.write so it gets its own transaction`,
|
|
35
36
|
});
|
|
36
37
|
}
|
|
37
38
|
// For framework code that writes through the raw runner (executor verbs, event appends, projection steps):
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TenantDb } from "@cosmicdrift/kumiko-types/tenant-db-types";
|
|
2
|
+
import type { DbRunner } from "./connection.ts";
|
|
3
|
+
type ScopedRebinder = {
|
|
4
|
+
readonly memberReadOnly: boolean;
|
|
5
|
+
readonly rebind: (runner: DbRunner) => TenantDb;
|
|
6
|
+
};
|
|
7
|
+
export declare function registerScopedRebinder(tenantDb: TenantDb, scoped: ScopedRebinder): void;
|
|
8
|
+
export declare function runInOwnTransaction<T>(tenantDb: TenantDb, fn: (txDb: TenantDb) => Promise<T>): Promise<T>;
|
|
9
|
+
export declare function runInOwnSavepoint<T>(tenantDb: TenantDb, fn: (savepointDb: TenantDb) => Promise<T>): Promise<T>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { InternalError } from "../errors/index.js";
|
|
2
|
+
import { runInNewTransaction, runInSavepointIfSupported } from "./query.js";
|
|
3
|
+
import { tenantDbRunner } from "./tenant-db-runner.js";
|
|
4
|
+
const scopedRebinders = new WeakMap();
|
|
5
|
+
export function registerScopedRebinder(tenantDb, scoped) {
|
|
6
|
+
scopedRebinders.set(tenantDb, scoped);
|
|
7
|
+
}
|
|
8
|
+
function requireScopedRebinder(tenantDb, caller) {
|
|
9
|
+
const scoped = scopedRebinders.get(tenantDb);
|
|
10
|
+
if (!scoped) {
|
|
11
|
+
throw new InternalError({
|
|
12
|
+
message: `${caller} received a TenantDb without a transaction rebinder: either it was not ` +
|
|
13
|
+
"built by createTenantDb, or it is the fail-closed ctx.db/ctx.db.outsideTransaction of an " +
|
|
14
|
+
"r.systemScope() handler (use ctx.systemDb.outsideTransaction there).",
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return scoped;
|
|
18
|
+
}
|
|
19
|
+
export async function runInOwnTransaction(tenantDb, fn) {
|
|
20
|
+
const scoped = requireScopedRebinder(tenantDb, "runInOwnTransaction");
|
|
21
|
+
if (scoped.memberReadOnly) {
|
|
22
|
+
throw new InternalError({
|
|
23
|
+
message: "runInOwnTransaction: memberReadOnly TenantDb — a fresh transaction would escape " +
|
|
24
|
+
"the enforced read-only scope.",
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return runInNewTransaction(tenantDbRunner(tenantDb), (tx) => fn(scoped.rebind(tx)));
|
|
28
|
+
}
|
|
29
|
+
// A throw inside fn rolls back only fn's statements; the caller's transaction stays usable.
|
|
30
|
+
export async function runInOwnSavepoint(tenantDb, fn) {
|
|
31
|
+
const scoped = requireScopedRebinder(tenantDb, "runInOwnSavepoint");
|
|
32
|
+
return runInSavepointIfSupported(tenantDbRunner(tenantDb), (sp) => fn(scoped.rebind(sp)));
|
|
33
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { EntityTableMeta } from "@cosmicdrift/kumiko-types/entity-table-meta-types";
|
|
2
|
+
import type { Meter, Tracer } from "@cosmicdrift/kumiko-types/observability";
|
|
3
|
+
import type { SchemaTable } from "@cosmicdrift/kumiko-types/schema-table-types";
|
|
4
|
+
import type { TenantId } from "../engine/types/identifiers.ts";
|
|
5
|
+
import { type TenantDbModeOptions } from "./row-level-security-scope.ts";
|
|
6
|
+
export type TenantDbStatementRunnerOptions = {
|
|
7
|
+
readonly tracer?: Tracer | undefined;
|
|
8
|
+
readonly meter?: Meter | undefined;
|
|
9
|
+
readonly signal?: AbortSignal | undefined;
|
|
10
|
+
readonly tenantId: TenantId;
|
|
11
|
+
} & TenantDbModeOptions;
|
|
12
|
+
export type TenantDbOperation = "select" | "insert" | "update" | "delete";
|
|
13
|
+
export declare function createTenantDbStatementRunner({ tracer, meter, signal, mode, reason, tenantId, }: TenantDbStatementRunnerOptions): <T>(operation: TenantDbOperation, table: SchemaTable | EntityTableMeta, runner: () => Promise<T>) => Promise<T>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { emitDbQuery } from "../observability/standard-metrics.js";
|
|
2
|
+
import { runInRowLevelSecurityScope, tenantDbRowLevelSecurityScope, } from "./row-level-security-scope.js";
|
|
3
|
+
import { tableNameOf } from "./table-introspection.js";
|
|
4
|
+
export function createTenantDbStatementRunner({ tracer, meter, signal, mode, reason, tenantId, }) {
|
|
5
|
+
return function withDbSpan(operation, table, runner) {
|
|
6
|
+
signal?.throwIfAborted();
|
|
7
|
+
const scope = tenantDbRowLevelSecurityScope(mode === "system" ? { mode, reason } : { mode }, tenantId, table);
|
|
8
|
+
const scopedRunner = () => runInRowLevelSecurityScope(scope, runner);
|
|
9
|
+
if (!tracer && !meter)
|
|
10
|
+
return scopedRunner();
|
|
11
|
+
const tableName = tableNameOf(table);
|
|
12
|
+
const start = performance.now();
|
|
13
|
+
const emitMetric = () => {
|
|
14
|
+
if (meter) {
|
|
15
|
+
emitDbQuery(meter, { operation, table: tableName }, (performance.now() - start) / 1000);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
if (!tracer) {
|
|
19
|
+
return (async () => {
|
|
20
|
+
try {
|
|
21
|
+
return await scopedRunner();
|
|
22
|
+
}
|
|
23
|
+
finally {
|
|
24
|
+
emitMetric();
|
|
25
|
+
}
|
|
26
|
+
})();
|
|
27
|
+
}
|
|
28
|
+
return tracer.withSpan("db.query", {
|
|
29
|
+
kind: "client",
|
|
30
|
+
attributes: {
|
|
31
|
+
"db.system": "postgresql",
|
|
32
|
+
"db.operation": operation,
|
|
33
|
+
"db.table": tableName,
|
|
34
|
+
},
|
|
35
|
+
}, async (span) => {
|
|
36
|
+
try {
|
|
37
|
+
const result = await scopedRunner();
|
|
38
|
+
if (Array.isArray(result)) {
|
|
39
|
+
span.setAttribute("db.row_count", result.length);
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
emitMetric();
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
}
|
package/dist/db/tenant-db.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { EntityTableMeta } from "@cosmicdrift/kumiko-types/entity-table-meta-types";
|
|
2
2
|
import type { ExecutorManagedRunner } from "@cosmicdrift/kumiko-types/executor-brand";
|
|
3
|
-
import type { EscapeHatchDeclaration, EscapeHatchReporter, EscapeHatchTarget } from "@cosmicdrift/kumiko-types/handlers";
|
|
3
|
+
import type { EscapeHatchDeclaration, EscapeHatchReporter, EscapeHatchTarget, HandlerDb } from "@cosmicdrift/kumiko-types/handlers";
|
|
4
|
+
import type { Meter, Tracer } from "@cosmicdrift/kumiko-types/observability";
|
|
4
5
|
import type { SchemaTable } from "@cosmicdrift/kumiko-types/schema-table-types";
|
|
5
|
-
import { type ExecutorManagedTenantDb, type TenantDb, type
|
|
6
|
+
import { type ExecutorManagedTenantDb, type TenantDb, type UncheckedSystemDb } from "@cosmicdrift/kumiko-types/tenant-db-types";
|
|
6
7
|
import { asRawClient } from "../db/query.ts";
|
|
7
8
|
import type { EntityDefinition } from "../engine/types/fields.ts";
|
|
8
9
|
import { type TenantId } from "../engine/types/identifiers.ts";
|
|
9
10
|
import type { Registry } from "../engine/types/index.ts";
|
|
10
|
-
import { type Meter, type Tracer } from "../observability/index.ts";
|
|
11
11
|
import type { DbRunner } from "./connection.ts";
|
|
12
12
|
import { tableNameOf } from "./table-introspection.ts";
|
|
13
13
|
type Table = SchemaTable;
|
|
@@ -19,10 +19,9 @@ export declare function unsafeRawForDeclaredStep(holder: TenantDb | UncheckedSys
|
|
|
19
19
|
export declare function withSystemDbUnsafeRawGrant<T extends object>(systemDb: T, grant: EscapeHatchDeclaration | undefined, deniedCallerLabel: string): T | UncheckedSystemDb;
|
|
20
20
|
export declare function createUncheckedSystemDb(db: TenantDb, dbOutsideTransaction?: TenantDb, report?: EscapeHatchReporter): UncheckedSystemDb;
|
|
21
21
|
export declare function createSystemDbView(db: TenantDb, dbOutsideTransaction?: TenantDb, report?: EscapeHatchReporter): UncheckedSystemDb;
|
|
22
|
-
export declare function scopeTenantDbToTenant(db: TenantDb, tenantId: TenantId): TenantDb;
|
|
23
22
|
export declare function castTenantRows<T>(rows: readonly Record<string, unknown>[]): readonly T[];
|
|
23
|
+
export { requestedTenantIds } from "./tenant-id-filter.ts";
|
|
24
24
|
export { tableNameOf };
|
|
25
|
-
export declare function requestedTenantIds(requested: unknown): readonly unknown[] | undefined;
|
|
26
25
|
export declare function hasTenantColumn(table: Table | EntityTableMeta): boolean;
|
|
27
26
|
export type TenantDbGrants = {
|
|
28
27
|
readonly globalWrites?: EscapeHatchDeclaration;
|
|
@@ -40,26 +39,32 @@ export declare function acknowledgeConventionCrossTenant(tenantDb: TenantDb, rea
|
|
|
40
39
|
}): TenantDb;
|
|
41
40
|
export declare function reportConventionCrossTenantUse(acknowledged: TenantDb, target?: EscapeHatchTarget): void;
|
|
42
41
|
export type OutsideTransactionContext = {
|
|
43
|
-
readonly
|
|
42
|
+
readonly db: Pick<HandlerDb, "outsideTransaction">;
|
|
44
43
|
};
|
|
45
|
-
export declare function hasOutsideTransactionDb(ctx: OutsideTransactionContext): ctx is
|
|
46
|
-
readonly
|
|
44
|
+
export declare function hasOutsideTransactionDb(ctx: OutsideTransactionContext): ctx is {
|
|
45
|
+
readonly db: {
|
|
46
|
+
readonly outsideTransaction: TenantDb;
|
|
47
|
+
};
|
|
47
48
|
};
|
|
48
49
|
export declare function requireOutsideTransactionDb(ctx: OutsideTransactionContext): TenantDb;
|
|
49
|
-
export declare function runInOwnTransaction<T>(tenantDb: TenantDb, fn: (txDb: TenantDb) => Promise<T>): Promise<T>;
|
|
50
50
|
export type CreateTenantDbOptions = {
|
|
51
51
|
readonly db: DbRunner;
|
|
52
52
|
readonly tenantId: TenantId;
|
|
53
|
-
readonly mode?: TenantDbMode;
|
|
54
53
|
readonly tracer?: Tracer;
|
|
55
54
|
readonly meter?: Meter;
|
|
56
55
|
readonly signal?: AbortSignal;
|
|
57
56
|
readonly grants?: TenantDbGrants;
|
|
58
|
-
}
|
|
57
|
+
} & ({
|
|
58
|
+
readonly mode?: "tenant";
|
|
59
|
+
readonly reason?: undefined;
|
|
60
|
+
} | {
|
|
61
|
+
readonly mode: "system";
|
|
62
|
+
readonly reason: string;
|
|
63
|
+
});
|
|
59
64
|
export declare function createTenantDb(options: CreateTenantDbOptions & {
|
|
60
65
|
readonly db: ExecutorManagedRunner;
|
|
61
66
|
}): ExecutorManagedTenantDb;
|
|
62
67
|
export declare function createTenantDb(options: CreateTenantDbOptions): TenantDb;
|
|
63
|
-
export declare function createTenantDataDestroyDb(options: Omit<CreateTenantDbOptions, "mode">): ExecutorManagedTenantDb;
|
|
68
|
+
export declare function createTenantDataDestroyDb(options: Omit<CreateTenantDbOptions, "mode" | "reason">): ExecutorManagedTenantDb;
|
|
64
69
|
export declare function createProjectingTenantDb(db: DbRunner, tenantId: TenantId, projectionRegistry: Registry | undefined): TenantDb;
|
|
65
70
|
export { asRawClient };
|
package/dist/db/tenant-db.js
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
import { SYSTEM_SCOPE_CHECK_BRAND, } from "@cosmicdrift/kumiko-types/tenant-db-types";
|
|
2
|
-
import {
|
|
3
|
-
import { asEntityTableMeta, asRawClient, aggregateWhere as bunAggregateWhere, countWhere as bunCountWhere, deleteMany as bunDeleteMany, fetchOne as bunFetchOne, insertOne as bunInsertOne, selectMany as bunSelectMany, updateMany as bunUpdateMany, runInNewTransaction, } from "../db/query.js";
|
|
2
|
+
import { asEntityTableMeta, asRawClient, aggregateWhere as bunAggregateWhere, countWhere as bunCountWhere, deleteMany as bunDeleteMany, fetchOne as bunFetchOne, insertOne as bunInsertOne, selectMany as bunSelectMany, updateMany as bunUpdateMany, } from "../db/query.js";
|
|
4
3
|
import { assertReason } from "../engine/escape-hatch-reason.js";
|
|
5
4
|
import { SYSTEM_TENANT_ID } from "../engine/types/identifiers.js";
|
|
6
|
-
import { AccessDeniedError, InternalError
|
|
7
|
-
import {
|
|
5
|
+
import { AccessDeniedError, InternalError } from "../errors/index.js";
|
|
6
|
+
import { memberResolutionReadOnlyDenied } from "../errors/member-resolution.js";
|
|
7
|
+
import { fallbackEscapeHatchReporter } from "../observability/escape-hatch-report.js";
|
|
8
|
+
import { registerStandardMetrics } from "../observability/standard-metrics.js";
|
|
8
9
|
import { assertWritableTable, executorManagedWriteDenied, hasExecutorManagedWriteCapability, registerExecutorManagedWriteRunner, } from "./executor-managed-tables.js";
|
|
9
10
|
import { bindProjectionRegistry, projectionRegistryOf } from "./projection-registry-binding.js";
|
|
10
11
|
import { acquireNamespacedAdvisoryLock } from "./queries/advisory-lock.js";
|
|
11
12
|
import { queryDatabaseNow } from "./queries/database-now.js";
|
|
13
|
+
import { systemModeOptions, unsafeRawScopedRunner, unscopedRunnerOf, } from "./row-level-security-scope.js";
|
|
12
14
|
import { hasFieldProperty, tableNameOf } from "./table-introspection.js";
|
|
13
|
-
import { bindTenantDbRunner, denyTenantDbWrites, tenantDbRunner, tenantDbWritesDeniedError,
|
|
15
|
+
import { bindTenantDbRunner, denyTenantDbWrites, tenantDbRunner, tenantDbWritesDeniedError, } from "./tenant-db-runner.js";
|
|
16
|
+
import { registerScopedRebinder } from "./tenant-db-scoped-rebind.js";
|
|
17
|
+
import { createTenantDbStatementRunner } from "./tenant-db-statement-runner.js";
|
|
14
18
|
import { upsertTableDenied, upsertTenantRow } from "./tenant-db-upsert.js";
|
|
19
|
+
import { isForeignTenantId, requestedTenantIds, tenantIdsAfterExclusion, } from "./tenant-id-filter.js";
|
|
20
|
+
import { registerRunnerProxyTarget } from "./transaction-serialization.js";
|
|
15
21
|
export { SYSTEM_SCOPE_CHECK_BRAND, } from "@cosmicdrift/kumiko-types/tenant-db-types";
|
|
16
22
|
const declaredUnsafeRawRunners = new WeakMap();
|
|
17
23
|
// The CRUD executor writes through tenantDbRunner, not insertOne, so it asks the
|
|
@@ -67,6 +73,7 @@ function boundRunner(runner, gate, projectionRegistry, executorManagedWrites) {
|
|
|
67
73
|
return value.bind(target);
|
|
68
74
|
},
|
|
69
75
|
});
|
|
76
|
+
registerRunnerProxyTarget(proxy, runner);
|
|
70
77
|
if (gate)
|
|
71
78
|
runnerPersonalDataGates.set(proxy, gate);
|
|
72
79
|
if (projectionRegistry)
|
|
@@ -166,9 +173,10 @@ function buildUncheckedSystemDb(db, dbOutsideTransaction, report, gate) {
|
|
|
166
173
|
`${gate.deniedCallerLabel} to allow unsafeRaw.`,
|
|
167
174
|
});
|
|
168
175
|
}
|
|
176
|
+
// A granted unsafeRaw is a declared, audited bypass of the TenantDb filter, so row-level security does not narrow it either.
|
|
169
177
|
// Engine-forwarded steps carry their own declared reason; a caller-supplied one never reaches the audit trail.
|
|
170
178
|
report("unsafe-raw", forwardedDeclaredStep ? reason : (gate?.grant?.reason ?? reason));
|
|
171
|
-
const runner = withoutExecutorManagedWrites(tenantDbRunner(db));
|
|
179
|
+
const runner = unsafeRawScopedRunner(withoutExecutorManagedWrites(tenantDbRunner(db)));
|
|
172
180
|
return boundRunner(runner, personalDataGates.get(db), projectionRegistryOf(db), false);
|
|
173
181
|
}
|
|
174
182
|
const uncheckedSystemDb = {
|
|
@@ -234,10 +242,9 @@ function buildUncheckedSystemDb(db, dbOutsideTransaction, report, gate) {
|
|
|
234
242
|
// own tenantId, never a foreign one.
|
|
235
243
|
//
|
|
236
244
|
// dbOutsideTransaction is optional so every existing single-arg call site
|
|
237
|
-
// (jobs/job-runner.ts, tests) keeps compiling — those callers have no
|
|
238
|
-
//
|
|
239
|
-
//
|
|
240
|
-
// is reachable through `ctx.systemDb`.
|
|
245
|
+
// (jobs/job-runner.ts, tests) keeps compiling — those callers have no outside-tx
|
|
246
|
+
// source to hand in. Only buildHandlerContext passes it, which is also the only
|
|
247
|
+
// place `.outsideTransaction` is reachable through `ctx.systemDb`.
|
|
241
248
|
//
|
|
242
249
|
// Ungated here (the handler's own systemScope() is the grant); a hook's own
|
|
243
250
|
// escapeHatch is layered on afterwards via withSystemDbUnsafeRawGrant. Public
|
|
@@ -252,55 +259,16 @@ export function createUncheckedSystemDb(db, dbOutsideTransaction, report = fallb
|
|
|
252
259
|
export function createSystemDbView(db, dbOutsideTransaction, report = fallbackEscapeHatchReporter(db.tenantId)) {
|
|
253
260
|
return buildUncheckedSystemDb(db, dbOutsideTransaction, report, { kind: "source-tenant-db" });
|
|
254
261
|
}
|
|
255
|
-
// Narrows a (possibly "system"-mode) TenantDb to a "tenant"-mode handle for one tenant on the
|
|
256
|
-
// same connection/transaction. For code that must run caller-supplied callbacks (e.g. config
|
|
257
|
-
// validators) without handing them a cross-tenant view.
|
|
258
|
-
export function scopeTenantDbToTenant(db, tenantId) {
|
|
259
|
-
const writesDeniedReason = tenantDbWritesDeniedReason(db);
|
|
260
|
-
return createTenantDb({
|
|
261
|
-
db: tenantDbRunner(db),
|
|
262
|
-
tenantId,
|
|
263
|
-
mode: "tenant",
|
|
264
|
-
...(writesDeniedReason !== undefined && { grants: { writesDeniedReason } }),
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
262
|
// @cast-boundary tenant-db-row
|
|
268
263
|
export function castTenantRows(rows) {
|
|
269
264
|
return rows;
|
|
270
265
|
}
|
|
266
|
+
export { requestedTenantIds } from "./tenant-id-filter.js";
|
|
271
267
|
export { tableNameOf };
|
|
272
268
|
// A grant is only real when its reason is non-empty — `{ reason: "" }` must not silently unlock it.
|
|
273
269
|
function hasGrant(decl) {
|
|
274
270
|
return decl !== undefined && decl.reason.trim().length > 0;
|
|
275
271
|
}
|
|
276
|
-
// Tenant ids left over when the caller excludes some via ne/notIn; undefined for other operator forms.
|
|
277
|
-
function tenantIdsAfterExclusion(requested, allowed) {
|
|
278
|
-
if (!isPlainObject(requested))
|
|
279
|
-
return undefined;
|
|
280
|
-
if ("ne" in requested)
|
|
281
|
-
return allowed.filter((t) => t !== requested["ne"]);
|
|
282
|
-
if (Array.isArray(requested["notIn"])) {
|
|
283
|
-
const excluded = requested["notIn"];
|
|
284
|
-
return allowed.filter((t) => !excluded.includes(t));
|
|
285
|
-
}
|
|
286
|
-
return undefined;
|
|
287
|
-
}
|
|
288
|
-
// Tenant ids a where.tenantId filter asks for; undefined for operator forms
|
|
289
|
-
// that cannot narrow to a tenant list (ne, like, ...).
|
|
290
|
-
export function requestedTenantIds(requested) {
|
|
291
|
-
if (Array.isArray(requested))
|
|
292
|
-
return requested;
|
|
293
|
-
if (!isPlainObject(requested))
|
|
294
|
-
return [requested];
|
|
295
|
-
if (Array.isArray(requested["in"]))
|
|
296
|
-
return requested["in"];
|
|
297
|
-
if ("eq" in requested)
|
|
298
|
-
return [requested["eq"]];
|
|
299
|
-
return undefined;
|
|
300
|
-
}
|
|
301
|
-
function isForeignTenantId(tenantIdValue) {
|
|
302
|
-
return tenantIdValue !== undefined && tenantIdValue !== SYSTEM_TENANT_ID;
|
|
303
|
-
}
|
|
304
272
|
// Checks the canonical EntityTableMeta (branded EntityTable's KUMIKO_META_SYMBOL
|
|
305
273
|
// or a plain deriveEntityTableMeta/defineUnmanagedTable result), not a direct
|
|
306
274
|
// `table.tenantId` property read — the latter only exists on branded EntityTables
|
|
@@ -347,28 +315,16 @@ export function reportConventionCrossTenantUse(acknowledged, target) {
|
|
|
347
315
|
}
|
|
348
316
|
reporter(target);
|
|
349
317
|
}
|
|
350
|
-
const ownTransactionRebinders = new WeakMap();
|
|
351
318
|
export function hasOutsideTransactionDb(ctx) {
|
|
352
|
-
return ctx.
|
|
319
|
+
return ctx.db.outsideTransaction !== undefined;
|
|
353
320
|
}
|
|
354
321
|
export function requireOutsideTransactionDb(ctx) {
|
|
355
322
|
if (!hasOutsideTransactionDb(ctx)) {
|
|
356
323
|
throw new InternalError({
|
|
357
|
-
message: "ctx.
|
|
358
|
-
});
|
|
359
|
-
}
|
|
360
|
-
return ctx.dbOutsideTransaction;
|
|
361
|
-
}
|
|
362
|
-
export async function runInOwnTransaction(tenantDb, fn) {
|
|
363
|
-
const rebind = ownTransactionRebinders.get(tenantDb);
|
|
364
|
-
if (!rebind) {
|
|
365
|
-
throw new InternalError({
|
|
366
|
-
message: "runInOwnTransaction received a TenantDb without a transaction rebinder: either it was not " +
|
|
367
|
-
"built by createTenantDb, or it is the fail-closed ctx.db/ctx.dbOutsideTransaction of an " +
|
|
368
|
-
"r.systemScope() handler (use ctx.systemDb.outsideTransaction there).",
|
|
324
|
+
message: "ctx.db.outsideTransaction is not available in this dispatch phase (member-resolution, before-transaction denial) or metering tenant mode.",
|
|
369
325
|
});
|
|
370
326
|
}
|
|
371
|
-
return
|
|
327
|
+
return ctx.db.outsideTransaction;
|
|
372
328
|
}
|
|
373
329
|
export function createTenantDb(options) {
|
|
374
330
|
return buildTenantDb(options);
|
|
@@ -380,7 +336,9 @@ export function createTenantDataDestroyDb(options) {
|
|
|
380
336
|
// Untyped JS callers or an `as` cast can still hand in undefined; a scoped handle
|
|
381
337
|
// without a tenant would bind `tenant_id = NULL` instead of failing loudly.
|
|
382
338
|
function buildTenantDb(options) {
|
|
383
|
-
const { db, tenantId, mode = "tenant", tracer, meter, signal, grants } = options;
|
|
339
|
+
const { db: givenDb, tenantId, mode = "tenant", reason: systemReason, tracer, meter, signal, grants, } = options;
|
|
340
|
+
const modeOptions = mode === "system" ? systemModeOptions(systemReason) : { mode: "tenant" };
|
|
341
|
+
const db = mode === "system" ? givenDb : unscopedRunnerOf(givenDb);
|
|
384
342
|
if (tenantId === undefined) {
|
|
385
343
|
throw new InternalError({ message: "createTenantDb: tenantId is required" });
|
|
386
344
|
}
|
|
@@ -393,47 +351,13 @@ function buildTenantDb(options) {
|
|
|
393
351
|
const rebindGrants = projectionRegistry && grants?.projectionRegistry === undefined
|
|
394
352
|
? { ...grants, projectionRegistry }
|
|
395
353
|
: grants;
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
if (meter) {
|
|
404
|
-
emitDbQuery(meter, { operation, table: tableName }, (performance.now() - start) / 1000);
|
|
405
|
-
}
|
|
406
|
-
};
|
|
407
|
-
if (!tracer) {
|
|
408
|
-
return (async () => {
|
|
409
|
-
try {
|
|
410
|
-
return await runner();
|
|
411
|
-
}
|
|
412
|
-
finally {
|
|
413
|
-
emitMetric();
|
|
414
|
-
}
|
|
415
|
-
})();
|
|
416
|
-
}
|
|
417
|
-
return tracer.withSpan("db.query", {
|
|
418
|
-
kind: "client",
|
|
419
|
-
attributes: {
|
|
420
|
-
"db.system": "postgresql",
|
|
421
|
-
"db.operation": operation,
|
|
422
|
-
"db.table": tableName,
|
|
423
|
-
},
|
|
424
|
-
}, async (span) => {
|
|
425
|
-
try {
|
|
426
|
-
const result = await runner();
|
|
427
|
-
if (Array.isArray(result)) {
|
|
428
|
-
span.setAttribute("db.row_count", result.length);
|
|
429
|
-
}
|
|
430
|
-
return result;
|
|
431
|
-
}
|
|
432
|
-
finally {
|
|
433
|
-
emitMetric();
|
|
434
|
-
}
|
|
435
|
-
});
|
|
436
|
-
}
|
|
354
|
+
const withDbSpan = createTenantDbStatementRunner({
|
|
355
|
+
tracer,
|
|
356
|
+
meter,
|
|
357
|
+
signal,
|
|
358
|
+
...modeOptions,
|
|
359
|
+
tenantId,
|
|
360
|
+
});
|
|
437
361
|
// Reads see own-tenant rows + reference data (tenantId === SYSTEM_TENANT_ID).
|
|
438
362
|
// Writes never touch reference rows — those are system-mode only.
|
|
439
363
|
// A caller-supplied `where.tenantId` may only NARROW the enforced scope
|
|
@@ -613,7 +537,7 @@ function buildTenantDb(options) {
|
|
|
613
537
|
}
|
|
614
538
|
// Engine-forwarded steps carry their own declared reason; otherwise the grant's reason is audited.
|
|
615
539
|
report("unsafe-raw", declaredStepReason ?? grants?.unsafeRaw?.reason ?? "");
|
|
616
|
-
return boundRunner(withoutExecutorManagedWrites(db), personalDataGate, projectionRegistry, false);
|
|
540
|
+
return boundRunner(unsafeRawScopedRunner(withoutExecutorManagedWrites(db)), personalDataGate, projectionRegistry, false);
|
|
617
541
|
}
|
|
618
542
|
const tenantDb = {
|
|
619
543
|
tenantId,
|
|
@@ -712,7 +636,7 @@ function buildTenantDb(options) {
|
|
|
712
636
|
unsafeRawRebinders.set(tenantDb, (grant) => createTenantDb({
|
|
713
637
|
db,
|
|
714
638
|
tenantId,
|
|
715
|
-
|
|
639
|
+
...modeOptions,
|
|
716
640
|
tracer,
|
|
717
641
|
meter,
|
|
718
642
|
signal,
|
|
@@ -730,6 +654,7 @@ function buildTenantDb(options) {
|
|
|
730
654
|
db,
|
|
731
655
|
tenantId,
|
|
732
656
|
mode: "system",
|
|
657
|
+
reason,
|
|
733
658
|
tracer,
|
|
734
659
|
meter,
|
|
735
660
|
signal,
|
|
@@ -738,18 +663,22 @@ function buildTenantDb(options) {
|
|
|
738
663
|
crossTenantUseReporters.set(acknowledged, (target) => report("acknowledge-cross-tenant", reason, target));
|
|
739
664
|
return acknowledged;
|
|
740
665
|
});
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
666
|
+
// Carries a runner-bound gate (grants.personalDataGate unset, resolved via the fallback above) forward explicitly, since a fresh tx-handle isn't itself registered in runnerPersonalDataGates.
|
|
667
|
+
const scopedGrants = personalDataGate ? { ...rebindGrants, personalDataGate } : rebindGrants;
|
|
668
|
+
registerScopedRebinder(tenantDb, {
|
|
669
|
+
memberReadOnly: grants?.memberReadOnly === true,
|
|
670
|
+
rebind: (runner) => createTenantDb({
|
|
671
|
+
db: runner,
|
|
672
|
+
tenantId,
|
|
673
|
+
...modeOptions,
|
|
674
|
+
tracer,
|
|
675
|
+
meter,
|
|
676
|
+
signal,
|
|
677
|
+
grants: scopedGrants,
|
|
678
|
+
}),
|
|
751
679
|
});
|
|
752
|
-
|
|
680
|
+
// Framework code reading through the raw runner (executor list/detail) must follow the db's own mode, not the ambient scope.
|
|
681
|
+
bindTenantDbRunner(tenantDb, db, modeOptions, tenantId);
|
|
753
682
|
if (grants?.writesDeniedReason !== undefined) {
|
|
754
683
|
denyTenantDbWrites(tenantDb, grants.writesDeniedReason);
|
|
755
684
|
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare function tenantIdsAfterExclusion(requested: unknown, allowed: readonly unknown[]): readonly unknown[] | undefined;
|
|
2
|
+
export declare function requestedTenantIds(requested: unknown): readonly unknown[] | undefined;
|
|
3
|
+
export declare function isForeignTenantId(tenantIdValue: unknown): boolean;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
|
|
2
|
+
import { SYSTEM_TENANT_ID } from "../engine/types/identifiers.js";
|
|
3
|
+
// Tenant ids left over when the caller excludes some via ne/notIn; undefined for other operator forms.
|
|
4
|
+
export function tenantIdsAfterExclusion(requested, allowed) {
|
|
5
|
+
if (!isPlainObject(requested))
|
|
6
|
+
return undefined;
|
|
7
|
+
if ("ne" in requested)
|
|
8
|
+
return allowed.filter((t) => t !== requested["ne"]);
|
|
9
|
+
if (Array.isArray(requested["notIn"])) {
|
|
10
|
+
const excluded = requested["notIn"];
|
|
11
|
+
return allowed.filter((t) => !excluded.includes(t));
|
|
12
|
+
}
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
// Tenant ids a where.tenantId filter asks for; undefined for operator forms
|
|
16
|
+
// that cannot narrow to a tenant list (ne, like, ...).
|
|
17
|
+
export function requestedTenantIds(requested) {
|
|
18
|
+
if (Array.isArray(requested))
|
|
19
|
+
return requested;
|
|
20
|
+
if (!isPlainObject(requested))
|
|
21
|
+
return [requested];
|
|
22
|
+
if (Array.isArray(requested["in"]))
|
|
23
|
+
return requested["in"];
|
|
24
|
+
if ("eq" in requested)
|
|
25
|
+
return [requested["eq"]];
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
export function isForeignTenantId(tenantIdValue) {
|
|
29
|
+
return tenantIdValue !== undefined && tenantIdValue !== SYSTEM_TENANT_ID;
|
|
30
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
type HandleKey = object;
|
|
2
|
+
export declare function registerRunnerProxyTarget(proxy: HandleKey, target: HandleKey): void;
|
|
3
|
+
export declare function openSerializedSavepoint<T>(transactionHandle: HandleKey & {
|
|
4
|
+
savepoint: <R>(fn: (sp: unknown) => Promise<R>) => Promise<R>;
|
|
5
|
+
}, fn: (sp: unknown) => Promise<T>): Promise<T>;
|
|
6
|
+
export {};
|