@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
|
@@ -2,7 +2,10 @@ import type { AnyDb } from "../query.ts";
|
|
|
2
2
|
export { alterTableAddColumn, createIndexIfNotExists, executeDdlStatement } from "./ddl.ts";
|
|
3
3
|
export declare function truncateTablesRestartIdentity(db: AnyDb, tableNames: readonly string[]): Promise<void>;
|
|
4
4
|
export declare function databaseExists(db: AnyDb, dbName: string): Promise<boolean>;
|
|
5
|
-
export declare function createDatabase(db: AnyDb, dbName: string, templateDbName?: string): Promise<void>;
|
|
5
|
+
export declare function createDatabase(db: AnyDb, dbName: string, templateDbName?: string, owner?: string): Promise<void>;
|
|
6
|
+
export declare function createApplicationRole(admin: AnyDb, role: string, password: string): Promise<void>;
|
|
7
|
+
export declare function transferDatabaseOwnership(admin: AnyDb, dbName: string, owner: string): Promise<void>;
|
|
8
|
+
export declare function transferPublicSchemaOwnership(db: AnyDb, owner: string): Promise<void>;
|
|
6
9
|
export declare function renameDatabase(db: AnyDb, fromName: string, toName: string): Promise<void>;
|
|
7
10
|
export declare function listDatabaseNamesWithPrefix(db: AnyDb, prefix: string): Promise<readonly string[]>;
|
|
8
11
|
export declare function acquireSessionAdvisoryLock(db: AnyDb, key: string): Promise<void>;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { extractPgError } from "../pg-error.js";
|
|
1
2
|
import { asRawClient } from "../query.js";
|
|
3
|
+
import { toPostgresArrayLiteral } from "./postgres-array-literal.js";
|
|
4
|
+
import { PROJECTION_REBUILD_SCHEMA } from "./shadow-swap.js";
|
|
2
5
|
import { quoteTableIdent } from "./table-ops.js";
|
|
3
6
|
// Re-exported for back-compat — the generic DDL helpers moved to ./ddl so
|
|
4
7
|
// the prod-boot path (db/table-push.ts, pipeline/event-consumer-state.ts)
|
|
@@ -12,9 +15,88 @@ export async function databaseExists(db, dbName) {
|
|
|
12
15
|
const rows = await asRawClient(db).unsafe(`SELECT EXISTS (SELECT 1 FROM pg_database WHERE datname = $1) AS exists`, [dbName]);
|
|
13
16
|
return rows[0]?.exists === true;
|
|
14
17
|
}
|
|
15
|
-
export async function createDatabase(db, dbName, templateDbName) {
|
|
18
|
+
export async function createDatabase(db, dbName, templateDbName, owner) {
|
|
16
19
|
const template = templateDbName === undefined ? "" : ` TEMPLATE ${quoteTableIdent(templateDbName)}`;
|
|
17
|
-
|
|
20
|
+
const ownerClause = owner === undefined ? "" : ` OWNER ${quoteTableIdent(owner)}`;
|
|
21
|
+
await asRawClient(db).unsafe(`CREATE DATABASE ${quoteTableIdent(dbName)}${template}${ownerClause}`);
|
|
22
|
+
}
|
|
23
|
+
const DUPLICATE_OBJECT = "42710";
|
|
24
|
+
const UNIQUE_VIOLATION = "23505";
|
|
25
|
+
const INTERNAL_ERROR = "XX000";
|
|
26
|
+
const MAX_CAUSE_DEPTH = 8;
|
|
27
|
+
// XX000 is Postgres' generic internal error; only the concurrent catalog update counts as a lost race.
|
|
28
|
+
// The driver error carrying the message may sit below a wrapper, as for the SQLSTATE.
|
|
29
|
+
function messageInCauseChain(error, needle) {
|
|
30
|
+
let current = error;
|
|
31
|
+
for (let depth = 0; depth < MAX_CAUSE_DEPTH && current instanceof Error; depth++) {
|
|
32
|
+
if (current.message.includes(needle))
|
|
33
|
+
return true;
|
|
34
|
+
current = current.cause;
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
function isLostRoleRace(error) {
|
|
39
|
+
const pgError = extractPgError(error);
|
|
40
|
+
if (pgError?.code === DUPLICATE_OBJECT || pgError?.code === UNIQUE_VIOLATION)
|
|
41
|
+
return true;
|
|
42
|
+
return (pgError?.code === INTERNAL_ERROR && messageInCauseChain(error, "tuple concurrently updated"));
|
|
43
|
+
}
|
|
44
|
+
// Parallel workers race on CREATE ROLE and ALTER ROLE; losing either race means the role has the
|
|
45
|
+
// attributes and password this call wanted, which is the goal.
|
|
46
|
+
export async function createApplicationRole(admin, role, password) {
|
|
47
|
+
const raw = asRawClient(admin);
|
|
48
|
+
const existing = await raw.unsafe(`SELECT 1 FROM pg_roles WHERE rolname = $1`, [role]);
|
|
49
|
+
const attributes = `LOGIN NOSUPERUSER NOBYPASSRLS PASSWORD ${quoteLiteral(password)}`;
|
|
50
|
+
// An earlier run may have created the role with another password, so an existing role is realigned.
|
|
51
|
+
const statement = existing.length > 0
|
|
52
|
+
? `ALTER ROLE ${quoteTableIdent(role)} ${attributes}`
|
|
53
|
+
: `CREATE ROLE ${quoteTableIdent(role)} ${attributes}`;
|
|
54
|
+
try {
|
|
55
|
+
await raw.unsafe(statement);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
if (!isLostRoleRace(error))
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function quoteLiteral(value) {
|
|
63
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
64
|
+
}
|
|
65
|
+
export async function transferDatabaseOwnership(admin, dbName, owner) {
|
|
66
|
+
await asRawClient(admin).unsafe(`ALTER DATABASE ${quoteTableIdent(dbName)} OWNER TO ${quoteTableIdent(owner)}`);
|
|
67
|
+
}
|
|
68
|
+
const OWNED_SCHEMA_PUBLIC = "public";
|
|
69
|
+
const OWNED_RELATION_KINDS = {
|
|
70
|
+
r: "TABLE",
|
|
71
|
+
p: "TABLE",
|
|
72
|
+
S: "SEQUENCE",
|
|
73
|
+
v: "VIEW",
|
|
74
|
+
m: "MATERIALIZED VIEW",
|
|
75
|
+
};
|
|
76
|
+
// Run on a connection to the database itself. REASSIGN OWNED fails for a bootstrap superuser, so owners move per relation.
|
|
77
|
+
// The rebuild schema is included: a persistent database that already rebuilt as superuser would otherwise refuse the
|
|
78
|
+
// application role's next rebuild for lack of CREATE on it.
|
|
79
|
+
export async function transferPublicSchemaOwnership(db, owner) {
|
|
80
|
+
const raw = asRawClient(db);
|
|
81
|
+
const ownedSchemas = [OWNED_SCHEMA_PUBLIC, PROJECTION_REBUILD_SCHEMA];
|
|
82
|
+
const rebuildSchema = await raw.unsafe(`SELECT 1 FROM pg_namespace WHERE nspname = $1`, [
|
|
83
|
+
PROJECTION_REBUILD_SCHEMA,
|
|
84
|
+
]);
|
|
85
|
+
if (rebuildSchema.length > 0) {
|
|
86
|
+
await raw.unsafe(`ALTER SCHEMA ${quoteTableIdent(PROJECTION_REBUILD_SCHEMA)} OWNER TO ${quoteTableIdent(owner)}`);
|
|
87
|
+
}
|
|
88
|
+
const relations = await raw.unsafe(`SELECT n.nspname, c.relname, c.relkind::text AS relkind
|
|
89
|
+
FROM pg_class c
|
|
90
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
91
|
+
JOIN pg_roles r ON r.oid = c.relowner
|
|
92
|
+
WHERE n.nspname = ANY($2::text[]) AND c.relkind IN ('r', 'p', 'S', 'v', 'm') AND r.rolname <> $1
|
|
93
|
+
AND NOT EXISTS (SELECT 1 FROM pg_depend d WHERE d.objid = c.oid AND d.deptype IN ('a', 'i'))`, [owner, toPostgresArrayLiteral(ownedSchemas)]);
|
|
94
|
+
for (const { nspname, relname, relkind } of relations) {
|
|
95
|
+
const kind = OWNED_RELATION_KINDS[relkind];
|
|
96
|
+
if (kind === undefined)
|
|
97
|
+
continue;
|
|
98
|
+
await raw.unsafe(`ALTER ${kind} ${quoteTableIdent(nspname)}.${quoteTableIdent(relname)} OWNER TO ${quoteTableIdent(owner)}`);
|
|
99
|
+
}
|
|
18
100
|
}
|
|
19
101
|
export async function renameDatabase(db, fromName, toName) {
|
|
20
102
|
await asRawClient(db).unsafe(`ALTER DATABASE ${quoteTableIdent(fromName)} RENAME TO ${quoteTableIdent(toName)}`);
|
package/dist/db/query.js
CHANGED
|
@@ -24,6 +24,7 @@ import { executorManagedWriteDenied } from "./executor-managed-tables.js";
|
|
|
24
24
|
import { extractPgError } from "./pg-error.js";
|
|
25
25
|
import { extractTableInfo } from "./table-info.js";
|
|
26
26
|
import { asEntityTableMeta, requireEntityTableMeta } from "./table-introspection.js";
|
|
27
|
+
import { openSerializedSavepoint } from "./transaction-serialization.js";
|
|
27
28
|
import { buildWhereClause } from "./where-clause.js";
|
|
28
29
|
// table() (dialect) stores the canonical, shadow-proof EntityTableMeta under
|
|
29
30
|
// `Symbol.for("kumiko:schema:Meta")`. The column handles on the table object are
|
|
@@ -33,7 +34,10 @@ import { buildWhereClause } from "./where-clause.js";
|
|
|
33
34
|
export { asEntityTableMeta, requireEntityTableMeta };
|
|
34
35
|
export function hasBegin(client) {
|
|
35
36
|
// Tx/savepoint handles can keep a begin() that throws; only savepoint() tells them apart from a pool.
|
|
36
|
-
return typeof client.begin === "function" &&
|
|
37
|
+
return typeof client.begin === "function" && !hasSavepoint(client);
|
|
38
|
+
}
|
|
39
|
+
function hasSavepoint(client) {
|
|
40
|
+
return typeof client.savepoint === "function";
|
|
37
41
|
}
|
|
38
42
|
function isRawClient(value) {
|
|
39
43
|
return typeof propertyOf(value, "unsafe") === "function";
|
|
@@ -71,10 +75,10 @@ function savepointRunnerOf(sp) {
|
|
|
71
75
|
}
|
|
72
76
|
export async function runInSavepoint(tx, fn) {
|
|
73
77
|
const raw = asRawClient(tx);
|
|
74
|
-
if (
|
|
78
|
+
if (!hasSavepoint(raw)) {
|
|
75
79
|
throw new Error("runInSavepoint: transaction handle has no savepoint() — pass the driver tx (Bun.SQL TransactionSQL).");
|
|
76
80
|
}
|
|
77
|
-
return raw
|
|
81
|
+
return openSerializedSavepoint(raw, (sp) => fn(savepointRunnerOf(sp)));
|
|
78
82
|
}
|
|
79
83
|
// Same error-confinement as runInSavepoint, but for call sites that don't
|
|
80
84
|
// know whether `db` is a bare pool connection or an active transaction
|
|
@@ -99,12 +103,12 @@ function isSavepointOnDeadTransactionCode(code) {
|
|
|
99
103
|
}
|
|
100
104
|
export async function runInSavepointIfSupported(db, fn) {
|
|
101
105
|
const raw = asRawClient(db);
|
|
102
|
-
if (
|
|
106
|
+
if (!hasSavepoint(raw))
|
|
103
107
|
return fn(savepointRunnerOf(db));
|
|
104
108
|
// An error from inside fn must never be remapped, even if it carries a closed-connection code.
|
|
105
109
|
let fnStarted = false;
|
|
106
110
|
try {
|
|
107
|
-
return await raw
|
|
111
|
+
return await openSerializedSavepoint(raw, (sp) => {
|
|
108
112
|
fnStarted = true;
|
|
109
113
|
return fn(savepointRunnerOf(sp));
|
|
110
114
|
});
|
|
@@ -117,11 +121,11 @@ export async function runInSavepointIfSupported(db, fn) {
|
|
|
117
121
|
? "runInSavepointIfSupported: the transaction handle's connection is gone — the transaction " +
|
|
118
122
|
"already committed (almost always database work in an afterCommit hook) or the connection dropped. " +
|
|
119
123
|
"afterCommit is the default phase of r.hook/postSave/postDelete. Use HookPhases.inTransaction " +
|
|
120
|
-
"for writes that must roll back with the trigger, or ctx.
|
|
124
|
+
"for writes that must roll back with the trigger, or ctx.db.outsideTransaction for work that must survive a rollback."
|
|
121
125
|
: "runInSavepointIfSupported: savepoint on a transaction that has already committed — " +
|
|
122
126
|
"this is almost always database work in an afterCommit hook. afterCommit is the default " +
|
|
123
127
|
"phase of r.hook/postSave/postDelete. Use HookPhases.inTransaction for writes that must " +
|
|
124
|
-
"roll back with the trigger, or ctx.
|
|
128
|
+
"roll back with the trigger, or ctx.db.outsideTransaction for work that must survive a rollback.",
|
|
125
129
|
cause: e instanceof Error ? e : undefined,
|
|
126
130
|
});
|
|
127
131
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import type { ReferenceDataDef } from "@cosmicdrift/kumiko-types/config";
|
|
1
2
|
import type { Registry } from "../engine/index.ts";
|
|
2
|
-
import type { ReferenceDataDef } from "../engine/types/index.ts";
|
|
3
3
|
import type { DbConnection } from "./connection.ts";
|
|
4
4
|
/**
|
|
5
5
|
* Seed reference data at boot time.
|
|
@@ -19,7 +19,12 @@ export async function seedReferenceData(defs, registry, db) {
|
|
|
19
19
|
let inserted = 0;
|
|
20
20
|
let updated = 0;
|
|
21
21
|
const by = createSystemUser(SYSTEM_TENANT_ID);
|
|
22
|
-
const tdb = createTenantDb({
|
|
22
|
+
const tdb = createTenantDb({
|
|
23
|
+
db,
|
|
24
|
+
tenantId: SYSTEM_TENANT_ID,
|
|
25
|
+
mode: "system",
|
|
26
|
+
reason: "reference data lives in the system tenant",
|
|
27
|
+
});
|
|
23
28
|
for (const def of defs) {
|
|
24
29
|
const entity = registry.getEntity(def.entityName);
|
|
25
30
|
if (!entity)
|
package/dist/db/render-ddl.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { EntityTableMeta, IndexMeta } from "./entity-table-meta.ts";
|
|
2
|
+
import { type RowLevelSecurityMode } from "./render-rls-ddl.ts";
|
|
2
3
|
export declare function renderIndex(tableName: string, idx: IndexMeta): string;
|
|
3
|
-
export
|
|
4
|
-
|
|
4
|
+
export type RenderDdlOptions = {
|
|
5
|
+
readonly rowLevelSecurity?: RowLevelSecurityMode;
|
|
6
|
+
};
|
|
7
|
+
export declare function renderTableDdl(meta: EntityTableMeta, options?: RenderDdlOptions): readonly string[];
|
|
8
|
+
export declare function renderTablesDdl(metas: readonly EntityTableMeta[], options?: RenderDdlOptions): readonly string[];
|
package/dist/db/render-ddl.js
CHANGED
|
@@ -7,9 +7,8 @@
|
|
|
7
7
|
// NO-MAGIC-ON-DATA: this renderer never runs at app runtime, only as a build
|
|
8
8
|
// step. The runner reads the checked-in SQL, not renderer output.
|
|
9
9
|
import { pgTypeToSqlType } from "./dialect.js";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
10
|
+
import { renderTableRowLevelSecurityDdl } from "./render-rls-ddl.js";
|
|
11
|
+
import { quoteIdent } from "./sql-identifier.js";
|
|
13
12
|
function renderColumn(col) {
|
|
14
13
|
const parts = [quoteIdent(col.name), pgTypeToSqlType(col.pgType)];
|
|
15
14
|
if (col.identity)
|
|
@@ -36,7 +35,7 @@ export function renderIndex(tableName, idx) {
|
|
|
36
35
|
const where = idx.whereSql !== undefined ? ` WHERE ${idx.whereSql}` : "";
|
|
37
36
|
return `CREATE ${kind} IF NOT EXISTS ${quoteIdent(idx.name)} ON ${quoteIdent(tableName)} (${colList})${where};`;
|
|
38
37
|
}
|
|
39
|
-
export function renderTableDdl(meta) {
|
|
38
|
+
export function renderTableDdl(meta, options = {}) {
|
|
40
39
|
const colLines = meta.columns.map(renderColumn);
|
|
41
40
|
const lines = [...colLines];
|
|
42
41
|
if (meta.compositePrimaryKey !== undefined) {
|
|
@@ -45,11 +44,12 @@ export function renderTableDdl(meta) {
|
|
|
45
44
|
}
|
|
46
45
|
const create = `CREATE TABLE IF NOT EXISTS ${quoteIdent(meta.tableName)} (\n ${lines.join(",\n ")}\n);`;
|
|
47
46
|
const indexes = meta.indexes.map((idx) => renderIndex(meta.tableName, idx));
|
|
48
|
-
|
|
47
|
+
const policies = options.rowLevelSecurity === "on" ? renderTableRowLevelSecurityDdl(meta) : [];
|
|
48
|
+
return [create, ...indexes, ...policies];
|
|
49
49
|
}
|
|
50
|
-
export function renderTablesDdl(metas) {
|
|
50
|
+
export function renderTablesDdl(metas, options = {}) {
|
|
51
51
|
const stmts = [];
|
|
52
52
|
for (const m of metas)
|
|
53
|
-
stmts.push(...renderTableDdl(m));
|
|
53
|
+
stmts.push(...renderTableDdl(m, options));
|
|
54
54
|
return stmts;
|
|
55
55
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { EntityTableMeta } from "./entity-table-meta.ts";
|
|
2
|
+
export declare const ROW_LEVEL_SECURITY_MODES: readonly ["off", "on"];
|
|
3
|
+
export type RowLevelSecurityMode = (typeof ROW_LEVEL_SECURITY_MODES)[number];
|
|
4
|
+
export declare const DEFAULT_ROW_LEVEL_SECURITY_MODE: RowLevelSecurityMode;
|
|
5
|
+
export declare const TENANT_ISOLATION_POLICY = "kumiko_tenant_isolation";
|
|
6
|
+
export declare const SYSTEM_TENANT_READ_POLICY = "kumiko_system_tenant_read";
|
|
7
|
+
export declare const TENANT_ID_SETTING = "kumiko.tenant_id";
|
|
8
|
+
export declare const SCOPE_SETTING = "kumiko.scope";
|
|
9
|
+
export declare const SYSTEM_SCOPE = "system";
|
|
10
|
+
export declare const POLICY_COMMANDS: readonly ["ALL", "SELECT", "INSERT", "UPDATE", "DELETE"];
|
|
11
|
+
export declare const POLICY_KINDS: readonly ["PERMISSIVE", "RESTRICTIVE"];
|
|
12
|
+
export type RowLevelSecurityPolicy = {
|
|
13
|
+
readonly name: string;
|
|
14
|
+
readonly command: (typeof POLICY_COMMANDS)[number];
|
|
15
|
+
readonly kind: (typeof POLICY_KINDS)[number];
|
|
16
|
+
readonly rolesSql: string;
|
|
17
|
+
readonly using?: string;
|
|
18
|
+
readonly withCheck?: string;
|
|
19
|
+
};
|
|
20
|
+
export type TableRowLevelSecurity = {
|
|
21
|
+
readonly policies: readonly RowLevelSecurityPolicy[];
|
|
22
|
+
};
|
|
23
|
+
export type RowLevelSecurityFlags = {
|
|
24
|
+
readonly enabled: boolean;
|
|
25
|
+
readonly forced: boolean;
|
|
26
|
+
};
|
|
27
|
+
export declare function tenantRowLevelSecurityFor(meta: EntityTableMeta): TableRowLevelSecurity | undefined;
|
|
28
|
+
export declare function rowLevelSecurityByTable(metas: readonly EntityTableMeta[]): Record<string, TableRowLevelSecurity>;
|
|
29
|
+
export declare function renderCreatePolicy(tableSql: string, policy: RowLevelSecurityPolicy): string;
|
|
30
|
+
export declare function renderRowLevelSecurityFlags(tableSql: string, flags: RowLevelSecurityFlags): string[];
|
|
31
|
+
export declare function renderEnableRowLevelSecurity(tableSql: string, next: TableRowLevelSecurity, previous?: TableRowLevelSecurity): string[];
|
|
32
|
+
export declare function renderDisableRowLevelSecurity(tableSql: string, previous: TableRowLevelSecurity): string[];
|
|
33
|
+
export declare function renderTableRowLevelSecurityDdl(meta: EntityTableMeta): readonly string[];
|
|
34
|
+
export declare function isSameTableRowLevelSecurity(a: TableRowLevelSecurity, b: TableRowLevelSecurity): boolean;
|
|
35
|
+
export declare function isTableRowLevelSecurityRecord(value: unknown): value is Record<string, TableRowLevelSecurity>;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// Pure renderer for Postgres row level security: EntityTableMeta → policy DDL.
|
|
2
|
+
// Every table with a `tenant_id` column gets two policies; tables without one are untouched.
|
|
3
|
+
import { SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-types/identifiers";
|
|
4
|
+
import { isOneOf, isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
|
|
5
|
+
import { pgTypeToSqlType } from "./dialect.js";
|
|
6
|
+
import { quoteIdent } from "./sql-identifier.js";
|
|
7
|
+
export const ROW_LEVEL_SECURITY_MODES = ["off", "on"];
|
|
8
|
+
export const DEFAULT_ROW_LEVEL_SECURITY_MODE = "on";
|
|
9
|
+
export const TENANT_ISOLATION_POLICY = "kumiko_tenant_isolation";
|
|
10
|
+
export const SYSTEM_TENANT_READ_POLICY = "kumiko_system_tenant_read";
|
|
11
|
+
export const TENANT_ID_SETTING = "kumiko.tenant_id";
|
|
12
|
+
export const SCOPE_SETTING = "kumiko.scope";
|
|
13
|
+
export const SYSTEM_SCOPE = "system";
|
|
14
|
+
const TENANT_COLUMN = "tenant_id";
|
|
15
|
+
export const POLICY_COMMANDS = ["ALL", "SELECT", "INSERT", "UPDATE", "DELETE"];
|
|
16
|
+
export const POLICY_KINDS = ["PERMISSIVE", "RESTRICTIVE"];
|
|
17
|
+
export function tenantRowLevelSecurityFor(meta) {
|
|
18
|
+
const tenantColumn = meta.columns.find((col) => col.name === TENANT_COLUMN);
|
|
19
|
+
if (tenantColumn === undefined)
|
|
20
|
+
return undefined;
|
|
21
|
+
const sqlType = pgTypeToSqlType(tenantColumn.pgType);
|
|
22
|
+
const column = quoteIdent(TENANT_COLUMN);
|
|
23
|
+
// NULLIF: after a transaction-local set_config, current_setting returns '' instead of NULL.
|
|
24
|
+
const sessionTenant = `NULLIF(current_setting('${TENANT_ID_SETTING}', true), '')`;
|
|
25
|
+
const isolation = `${column} = ${sessionTenant}::${sqlType} OR current_setting('${SCOPE_SETTING}', true) = '${SYSTEM_SCOPE}'`;
|
|
26
|
+
return {
|
|
27
|
+
policies: [
|
|
28
|
+
{
|
|
29
|
+
name: TENANT_ISOLATION_POLICY,
|
|
30
|
+
command: "ALL",
|
|
31
|
+
kind: "PERMISSIVE",
|
|
32
|
+
rolesSql: "PUBLIC",
|
|
33
|
+
using: isolation,
|
|
34
|
+
withCheck: isolation,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: SYSTEM_TENANT_READ_POLICY,
|
|
38
|
+
command: "SELECT",
|
|
39
|
+
kind: "PERMISSIVE",
|
|
40
|
+
rolesSql: "PUBLIC",
|
|
41
|
+
using: `${column} = '${SYSTEM_TENANT_ID}'::${sqlType} AND ${sessionTenant} IS NOT NULL`,
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export function rowLevelSecurityByTable(metas) {
|
|
47
|
+
const byTable = {};
|
|
48
|
+
for (const meta of metas) {
|
|
49
|
+
const spec = tenantRowLevelSecurityFor(meta);
|
|
50
|
+
if (spec !== undefined)
|
|
51
|
+
byTable[meta.tableName] = spec;
|
|
52
|
+
}
|
|
53
|
+
return byTable;
|
|
54
|
+
}
|
|
55
|
+
export function renderCreatePolicy(tableSql, policy) {
|
|
56
|
+
const using = policy.using !== undefined ? ` USING (${policy.using})` : "";
|
|
57
|
+
const withCheck = policy.withCheck !== undefined ? ` WITH CHECK (${policy.withCheck})` : "";
|
|
58
|
+
return `CREATE POLICY ${quoteIdent(policy.name)} ON ${tableSql} AS ${policy.kind} FOR ${policy.command} TO ${policy.rolesSql}${using}${withCheck};`;
|
|
59
|
+
}
|
|
60
|
+
function renderDropPolicy(tableSql, policyName) {
|
|
61
|
+
return `DROP POLICY IF EXISTS ${quoteIdent(policyName)} ON ${tableSql};`;
|
|
62
|
+
}
|
|
63
|
+
export function renderRowLevelSecurityFlags(tableSql, flags) {
|
|
64
|
+
return [
|
|
65
|
+
`ALTER TABLE ${tableSql} ${flags.enabled ? "ENABLE" : "DISABLE"} ROW LEVEL SECURITY;`,
|
|
66
|
+
`ALTER TABLE ${tableSql} ${flags.forced ? "FORCE" : "NO FORCE"} ROW LEVEL SECURITY;`,
|
|
67
|
+
];
|
|
68
|
+
}
|
|
69
|
+
export function renderEnableRowLevelSecurity(tableSql, next, previous) {
|
|
70
|
+
const nextNames = new Set(next.policies.map((policy) => policy.name));
|
|
71
|
+
const vanished = (previous?.policies ?? []).filter((policy) => !nextNames.has(policy.name));
|
|
72
|
+
return [
|
|
73
|
+
...vanished.map((policy) => renderDropPolicy(tableSql, policy.name)),
|
|
74
|
+
...next.policies.flatMap((policy) => [
|
|
75
|
+
renderDropPolicy(tableSql, policy.name),
|
|
76
|
+
renderCreatePolicy(tableSql, policy),
|
|
77
|
+
]),
|
|
78
|
+
...renderRowLevelSecurityFlags(tableSql, { enabled: true, forced: true }),
|
|
79
|
+
];
|
|
80
|
+
}
|
|
81
|
+
export function renderDisableRowLevelSecurity(tableSql, previous) {
|
|
82
|
+
return [
|
|
83
|
+
...previous.policies.map((policy) => renderDropPolicy(tableSql, policy.name)),
|
|
84
|
+
...renderRowLevelSecurityFlags(tableSql, { enabled: false, forced: false }).reverse(),
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
export function renderTableRowLevelSecurityDdl(meta) {
|
|
88
|
+
const spec = tenantRowLevelSecurityFor(meta);
|
|
89
|
+
if (spec === undefined)
|
|
90
|
+
return [];
|
|
91
|
+
return renderEnableRowLevelSecurity(quoteIdent(meta.tableName), spec);
|
|
92
|
+
}
|
|
93
|
+
function isSamePolicy(a, b) {
|
|
94
|
+
return (a.name === b.name &&
|
|
95
|
+
a.command === b.command &&
|
|
96
|
+
a.kind === b.kind &&
|
|
97
|
+
a.rolesSql === b.rolesSql &&
|
|
98
|
+
a.using === b.using &&
|
|
99
|
+
a.withCheck === b.withCheck);
|
|
100
|
+
}
|
|
101
|
+
export function isSameTableRowLevelSecurity(a, b) {
|
|
102
|
+
return (a.policies.length === b.policies.length &&
|
|
103
|
+
a.policies.every((policy, index) => {
|
|
104
|
+
const other = b.policies[index];
|
|
105
|
+
return other !== undefined && isSamePolicy(policy, other);
|
|
106
|
+
}));
|
|
107
|
+
}
|
|
108
|
+
function isOptionalString(value) {
|
|
109
|
+
return value === undefined || typeof value === "string";
|
|
110
|
+
}
|
|
111
|
+
function isRowLevelSecurityPolicy(value) {
|
|
112
|
+
return (isPlainObject(value) &&
|
|
113
|
+
typeof value["name"] === "string" &&
|
|
114
|
+
typeof value["rolesSql"] === "string" &&
|
|
115
|
+
isOneOf(POLICY_COMMANDS, value["command"]) &&
|
|
116
|
+
isOneOf(POLICY_KINDS, value["kind"]) &&
|
|
117
|
+
isOptionalString(value["using"]) &&
|
|
118
|
+
isOptionalString(value["withCheck"]));
|
|
119
|
+
}
|
|
120
|
+
function isTableRowLevelSecurity(value) {
|
|
121
|
+
return (isPlainObject(value) &&
|
|
122
|
+
Array.isArray(value["policies"]) &&
|
|
123
|
+
value["policies"].every(isRowLevelSecurityPolicy));
|
|
124
|
+
}
|
|
125
|
+
export function isTableRowLevelSecurityRecord(value) {
|
|
126
|
+
return isPlainObject(value) && Object.values(value).every(isTableRowLevelSecurity);
|
|
127
|
+
}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import type { Snapshot } from "./migrate-generator.ts";
|
|
2
|
+
import { type ReplayedRowLevelSecurity } from "./replay-rls.ts";
|
|
2
3
|
export type ReplayedTable = {
|
|
3
4
|
readonly columns: ReadonlySet<string>;
|
|
4
5
|
readonly columnsUnknown?: boolean;
|
|
6
|
+
readonly rowLevelSecurity?: ReplayedRowLevelSecurity;
|
|
5
7
|
};
|
|
6
8
|
export type ReplayedSchema = ReadonlyMap<string, ReplayedTable>;
|
|
7
9
|
export declare function replayMigrationsDir(migrationsDir: string): ReplayedSchema;
|
|
8
10
|
export type ReplayMismatch = {
|
|
9
11
|
readonly tableName: string;
|
|
10
|
-
readonly kind: "missing-table" | "unexpected-table" | "column-drift";
|
|
12
|
+
readonly kind: "missing-table" | "unexpected-table" | "column-drift" | "row-level-security-drift";
|
|
11
13
|
readonly detail: string;
|
|
12
14
|
};
|
|
13
15
|
export declare function diffReplayAgainstSnapshot(replayed: ReplayedSchema, snapshot: Snapshot): readonly ReplayMismatch[];
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
// either. Reuses `loadMigrationsFromDir`'s statement-splitting so the replay
|
|
10
10
|
// sees exactly what the real runner would execute.
|
|
11
11
|
import { loadMigrationsFromDir } from "./migrate-runner.js";
|
|
12
|
+
import { applyRowLevelSecurityStatement, IDENT, replayedOnlyRowLevelSecurityDrift, rowLevelSecurityDrift, TABLE_REF, } from "./replay-rls.js";
|
|
12
13
|
// Migration files comment out destructive ops (DROP TABLE/COLUMN) as
|
|
13
14
|
// `-- DESTRUCTIVE: <stmt>; -- uncomment + ensure backup` so the real
|
|
14
15
|
// migrate-runner never executes them unattended. For replay purposes the
|
|
@@ -48,10 +49,6 @@ function splitTopLevel(body) {
|
|
|
48
49
|
parts.push(current);
|
|
49
50
|
return parts;
|
|
50
51
|
}
|
|
51
|
-
// Identifiers in hand-written migrations aren't always quoted (the generator
|
|
52
|
-
// always quotes, but the header explicitly invites hand-editing) — optional
|
|
53
|
-
// quotes so `CREATE TABLE foo (...)` parses the same as `CREATE TABLE "foo" (...)`.
|
|
54
|
-
const IDENT = `"?([^"\\s(;,.]+)"?`;
|
|
55
52
|
function parseColumnNames(body) {
|
|
56
53
|
const columns = new Set();
|
|
57
54
|
for (const part of splitTopLevel(body)) {
|
|
@@ -197,7 +194,7 @@ function applyStatement(schema, statement, context) {
|
|
|
197
194
|
// instead of matching only the first clause, in statement order so an
|
|
198
195
|
// add-then-drop of the same column (unusual, but not impossible) resolves
|
|
199
196
|
// correctly.
|
|
200
|
-
const alterTable = statement.match(new RegExp(`^ALTER TABLE\\s
|
|
197
|
+
const alterTable = statement.match(new RegExp(`^ALTER TABLE\\s+(?:IF EXISTS\\s+)?(?:ONLY\\s+)?${TABLE_REF}\\s+([\\s\\S]*?);?\\s*$`, "i"));
|
|
201
198
|
const alterTableName = alterTable?.[1];
|
|
202
199
|
const alterBody = alterTable?.[2];
|
|
203
200
|
if (alterTableName !== undefined && alterBody !== undefined) {
|
|
@@ -276,10 +273,29 @@ export function replayMigrationsDir(migrationsDir) {
|
|
|
276
273
|
for (const migration of migrations) {
|
|
277
274
|
for (const statement of migration.statements) {
|
|
278
275
|
applyStatement(schema, statement, { file: migration.id });
|
|
276
|
+
applyRowLevelSecurityStatement(schema, statement, { file: migration.id });
|
|
279
277
|
}
|
|
280
278
|
}
|
|
281
279
|
return schema;
|
|
282
280
|
}
|
|
281
|
+
function rowLevelSecurityMismatches(replayed, snapshot) {
|
|
282
|
+
const mismatches = [];
|
|
283
|
+
const specs = snapshot.rowLevelSecurity ?? {};
|
|
284
|
+
for (const { tableName } of snapshot.tables) {
|
|
285
|
+
const table = replayed.get(tableName);
|
|
286
|
+
// skip: a missing table is already reported as missing-table
|
|
287
|
+
if (!table)
|
|
288
|
+
continue;
|
|
289
|
+
const spec = Object.hasOwn(specs, tableName) ? specs[tableName] : undefined;
|
|
290
|
+
const detail = spec === undefined
|
|
291
|
+
? replayedOnlyRowLevelSecurityDrift(table.rowLevelSecurity)
|
|
292
|
+
: rowLevelSecurityDrift(table.rowLevelSecurity, tableName, spec);
|
|
293
|
+
if (detail !== undefined) {
|
|
294
|
+
mismatches.push({ tableName, kind: "row-level-security-drift", detail });
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return mismatches;
|
|
298
|
+
}
|
|
283
299
|
// Compares what the migration files actually produce (`replayed`) against
|
|
284
300
|
// what `.snapshot.json` claims (`snapshot`) — the check that would have
|
|
285
301
|
// caught kumiko-studio's 0016 misgeneration (snapshot correct, SQL wrong).
|
|
@@ -314,6 +330,7 @@ export function diffReplayAgainstSnapshot(replayed, snapshot) {
|
|
|
314
330
|
});
|
|
315
331
|
}
|
|
316
332
|
}
|
|
333
|
+
mismatches.push(...rowLevelSecurityMismatches(replayed, snapshot));
|
|
317
334
|
for (const tableName of replayed.keys()) {
|
|
318
335
|
if (!snapshotTableNames.has(tableName)) {
|
|
319
336
|
mismatches.push({
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type TableRowLevelSecurity } from "./render-rls-ddl.ts";
|
|
2
|
+
export type ReplayedPolicies = ReadonlyMap<string, string | undefined>;
|
|
3
|
+
export type ReplayedRowLevelSecurity = {
|
|
4
|
+
readonly enabled: boolean;
|
|
5
|
+
readonly forced: boolean;
|
|
6
|
+
readonly policies: ReplayedPolicies;
|
|
7
|
+
};
|
|
8
|
+
export type MutableReplayedRowLevelSecurity = {
|
|
9
|
+
enabled: boolean;
|
|
10
|
+
forced: boolean;
|
|
11
|
+
policies: Map<string, string | undefined>;
|
|
12
|
+
};
|
|
13
|
+
type TableWithRowLevelSecurity = {
|
|
14
|
+
rowLevelSecurity?: MutableReplayedRowLevelSecurity;
|
|
15
|
+
};
|
|
16
|
+
export declare const IDENT = "\"?([^\"\\s(;,.]+)\"?";
|
|
17
|
+
export declare const TABLE_REF = "(?:\"?public\"?\\.)?\"?([^\"\\s(;,.]+)\"?";
|
|
18
|
+
type StatementContext = {
|
|
19
|
+
readonly file: string;
|
|
20
|
+
};
|
|
21
|
+
type ReplayTables = ReadonlyMap<string, TableWithRowLevelSecurity>;
|
|
22
|
+
export declare function applyRowLevelSecurityStatement(tables: ReplayTables, statement: string, context: StatementContext): void;
|
|
23
|
+
export declare function rowLevelSecurityDrift(replayed: ReplayedRowLevelSecurity | undefined, tableName: string, expected: TableRowLevelSecurity): string | undefined;
|
|
24
|
+
export declare function replayedOnlyRowLevelSecurityDrift(replayed: ReplayedRowLevelSecurity | undefined): string | undefined;
|
|
25
|
+
export {};
|