@cosmicdrift/kumiko-framework 0.388.0 → 0.390.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +12 -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/golden-path.md +13 -1
- 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 +55 -2
- package/agents/examples/list-table-options.md +466 -0
- package/agents/examples/managed-config.md +4 -4
- package/agents/examples/managed-pages.md +1 -1
- package/agents/examples/pdf-audit-export.md +4 -2
- 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 +5 -4
- package/agents/examples/tenant-isolation.md +73 -1
- 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 +5 -4
- package/agents/features.md +1 -1
- package/agents/widgets.md +1 -0
- package/dist/api/api-constants.d.ts +1 -0
- package/dist/api/api-constants.js +2 -0
- package/dist/api/auth-middleware.js +1 -1
- package/dist/api/auth-routes-invite.js +2 -1
- package/dist/api/auth-routes-shared.d.ts +2 -0
- package/dist/api/auth-routes-shared.js +5 -0
- package/dist/api/client-error-route.js +2 -3
- package/dist/api/entity-read-access.d.ts +4 -1
- package/dist/api/entity-read-access.js +14 -0
- package/dist/api/export/export-cells-reference.d.ts +9 -0
- package/dist/api/export/export-cells-reference.js +21 -0
- package/dist/api/export/export-cells.d.ts +11 -0
- package/dist/api/export/export-cells.js +136 -0
- package/dist/api/export/export-ciphertext-guard.d.ts +2 -0
- package/dist/api/export/export-ciphertext-guard.js +27 -0
- package/dist/api/export/export-columns.d.ts +31 -0
- package/dist/api/export/export-columns.js +85 -0
- package/dist/api/export/export-errors.d.ts +4 -0
- package/dist/api/export/export-errors.js +14 -0
- package/dist/api/export/export-route.d.ts +4 -0
- package/dist/api/export/export-route.js +75 -0
- package/dist/api/export/export-rows.d.ts +13 -0
- package/dist/api/export/export-rows.js +62 -0
- package/dist/api/export/export-screen.d.ts +13 -0
- package/dist/api/export/export-screen.js +47 -0
- package/dist/api/export/export-xlsx-writer.d.ts +4 -0
- package/dist/api/export/export-xlsx-writer.js +21 -0
- package/dist/api/extra-route.d.ts +7 -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/pii-leak-guard.d.ts +3 -0
- package/dist/api/pii-leak-guard.js +3 -2
- 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.d.ts +16 -0
- package/dist/api/routes.js +9 -5
- 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 +5 -1
- package/dist/api/server-middleware.js +3 -1
- package/dist/api/server-routes.d.ts +3 -2
- package/dist/api/server-routes.js +8 -2
- package/dist/api/server-wiring.js +8 -4
- package/dist/api/server.d.ts +2 -1
- package/dist/api/sse-route.d.ts +3 -1
- package/dist/api/sse-route.js +11 -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 +11 -9
- 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.d.ts +1 -0
- package/dist/crypto/pg-kms-adapter.js +17 -18
- package/dist/db/aggregate-sql.d.ts +2 -0
- package/dist/db/aggregate-sql.js +10 -0
- 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/closed-connection.js +12 -19
- 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 +7 -6
- package/dist/db/connection.js +43 -24
- 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-row-coercion.js +4 -4
- package/dist/db/driver-value-preparation.js +6 -4
- 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-aggregate-currencies.d.ts +17 -0
- package/dist/db/event-store-executor-read-aggregate-currencies.js +40 -0
- package/dist/db/event-store-executor-read-aggregate.js +36 -5
- package/dist/db/event-store-executor-read-filter.d.ts +1 -1
- package/dist/db/event-store-executor-read-filter.js +6 -3
- 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.d.ts +4 -0
- package/dist/db/event-store-executor-write-atomic.js +42 -0
- package/dist/db/event-store-executor-write-steps.d.ts +3 -5
- package/dist/db/event-store-executor-write-steps.js +0 -5
- package/dist/db/event-store-executor-write.js +22 -19
- package/dist/db/event-store-executor.d.ts +1 -1
- package/dist/db/event-store-executor.js +2 -1
- package/dist/db/executor-managed-tables.d.ts +7 -1
- package/dist/db/executor-managed-tables.js +12 -3
- 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 +7 -3
- 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 +37 -21
- package/dist/db/queries/backfill-pii.js +3 -6
- package/dist/db/queries/database-now.js +2 -1
- 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 +11 -28
- package/dist/db/queries/test-stack.d.ts +4 -1
- package/dist/db/queries/test-stack.js +83 -2
- package/dist/db/query.d.ts +14 -0
- package/dist/db/query.js +77 -48
- package/dist/db/reference-data.d.ts +1 -1
- package/dist/db/reference-data.js +20 -3
- package/dist/db/render-ddl.d.ts +6 -2
- package/dist/db/render-ddl.js +7 -7
- package/dist/db/render-rls-ddl.d.ts +35 -0
- package/dist/db/render-rls-ddl.js +127 -0
- package/dist/db/replay-migration-sql.d.ts +3 -1
- package/dist/db/replay-migration-sql.js +22 -5
- package/dist/db/replay-rls.d.ts +25 -0
- package/dist/db/replay-rls.js +156 -0
- package/dist/db/row-level-security-boot-check.d.ts +5 -0
- package/dist/db/row-level-security-boot-check.js +85 -0
- package/dist/db/row-level-security-connection.d.ts +3 -0
- package/dist/db/row-level-security-connection.js +213 -0
- package/dist/db/row-level-security-scope.d.ts +33 -0
- package/dist/db/row-level-security-scope.js +127 -0
- package/dist/db/scope-tenant-db-to-tenant.d.ts +3 -0
- package/dist/db/scope-tenant-db-to-tenant.js +14 -0
- package/dist/db/sql-identifier.d.ts +1 -0
- package/dist/db/sql-identifier.js +3 -0
- package/dist/db/statement-timeout.js +2 -1
- 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-upsert.d.ts +5 -0
- package/dist/db/tenant-db-upsert.js +91 -0
- package/dist/db/tenant-db.d.ts +17 -12
- package/dist/db/tenant-db.js +60 -121
- 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/bundled-lists-table.d.ts +2 -0
- package/dist/engine/boot-validator/bundled-lists-table.js +36 -0
- 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 +3 -0
- package/dist/engine/boot-validator/entity-list-aggregate-options.js +23 -0
- package/dist/engine/boot-validator/list-bulk-actions.d.ts +3 -0
- package/dist/engine/boot-validator/list-bulk-actions.js +49 -0
- package/dist/engine/boot-validator/list-column-layout.d.ts +8 -0
- package/dist/engine/boot-validator/list-column-layout.js +41 -0
- package/dist/engine/boot-validator/list-table-aggregate-options.d.ts +24 -0
- package/dist/engine/boot-validator/list-table-aggregate-options.js +145 -0
- package/dist/engine/boot-validator/list-table-aggregate-query.d.ts +11 -0
- package/dist/engine/boot-validator/list-table-aggregate-query.js +31 -0
- package/dist/engine/boot-validator/list-table-export-options.d.ts +1 -0
- package/dist/engine/boot-validator/list-table-export-options.js +27 -0
- package/dist/engine/boot-validator/list-table-options.d.ts +3 -0
- package/dist/engine/boot-validator/list-table-options.js +77 -0
- package/dist/engine/boot-validator/list-table-reject-unknown-keys.d.ts +1 -0
- package/dist/engine/boot-validator/list-table-reject-unknown-keys.js +7 -0
- 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/projection-list-screens.js +3 -13
- package/dist/engine/boot-validator/query-refs.d.ts +2 -1
- package/dist/engine/boot-validator/related-list-table-rules.d.ts +4 -0
- package/dist/engine/boot-validator/related-list-table-rules.js +42 -0
- package/dist/engine/boot-validator/screens-forms.d.ts +2 -1
- package/dist/engine/boot-validator/screens-kind-entity-list.js +7 -0
- package/dist/engine/boot-validator/screens-kind-projection-list.js +4 -0
- package/dist/engine/boot-validator/screens-kind-shared.d.ts +3 -1
- package/dist/engine/boot-validator/screens-lists.js +12 -2
- 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/build-app-schema.d.ts +2 -1
- package/dist/engine/build-app-schema.js +9 -1
- package/dist/engine/build-config-feature-schema.js +6 -1
- 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 +5 -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 +9 -1
- package/dist/engine/feature-builder-state.js +1 -0
- 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.d.ts +1 -0
- package/dist/engine/feature-manifest.js +2 -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 +3 -1
- package/dist/engine/field-access.js +12 -0
- package/dist/engine/handler-field-references.d.ts +0 -4
- package/dist/engine/index.d.ts +58 -55
- package/dist/engine/index.js +23 -28
- 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 +2 -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/strip-disabled-features-from-app-schema.js +7 -3
- package/dist/engine/template-variables.d.ts +2 -1
- package/dist/engine/transfer-adjacency.d.ts +1 -1
- package/dist/engine/types/feature.d.ts +1 -0
- package/dist/engine/types/index.d.ts +8 -30
- package/dist/engine/types/index.js +2 -10
- package/dist/engine/types/screen.d.ts +1 -1
- package/dist/engine/types/screen.js +1 -1
- package/dist/engine/validation.d.ts +2 -1
- package/dist/entrypoint/index.d.ts +9 -35
- package/dist/entrypoint/index.js +10 -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.d.ts +1 -0
- package/dist/event-store/event-store.js +42 -32
- 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/provenance-append.js +1 -1
- 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 +6 -3
- package/dist/files/create-file-ref.d.ts +6 -2
- package/dist/files/create-file-ref.js +13 -4
- 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 +3 -1
- package/dist/files/file-routes.js +41 -4
- 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 +6 -4
- package/dist/files/provider-resolver.js +5 -5
- package/dist/files/record-write-check.d.ts +6 -0
- package/dist/files/record-write-check.js +13 -0
- 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/files/upload-ledger.d.ts +2 -2
- package/dist/files/upload-ledger.js +4 -4
- 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/i18n/required-surface-keys.js +7 -2
- 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 +10 -6
- 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-scope.js +6 -6
- package/dist/jobs/job-runner-types.d.ts +2 -1
- package/dist/jobs/job-runner.js +22 -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/escape-hatch-report.js +9 -2
- 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/after-rollback-sink.d.ts +6 -0
- package/dist/pipeline/after-rollback-sink.js +32 -0
- 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 +39 -19
- 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 -194
- 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 +7 -3
- package/dist/pipeline/event-dispatcher.d.ts +3 -2
- package/dist/pipeline/event-dispatcher.js +13 -12
- 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 +14 -6
- package/dist/pipeline/handler-context-dispatch.js +18 -5
- package/dist/pipeline/handler-context-events.d.ts +22 -38
- package/dist/pipeline/handler-context-events.js +42 -35
- 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 +6 -2
- package/dist/pipeline/system-hooks.js +61 -10
- 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/pipeline/write-result-masking.js +13 -10
- package/dist/random/index.d.ts +1 -2
- package/dist/random/index.js +1 -2
- package/dist/rate-limit/bucket.d.ts +2 -1
- package/dist/rate-limit/middleware.js +2 -1
- package/dist/redis/index.d.ts +3 -4
- package/dist/redis/index.js +2 -2
- package/dist/schema-cli/apply-command.js +5 -2
- package/dist/schema-cli/baseline-command.js +7 -2
- package/dist/schema-cli/generate-command.js +7 -9
- package/dist/schema-cli/shared.d.ts +4 -0
- package/dist/schema-cli/shared.js +21 -2
- package/dist/schema-cli/status-command.js +8 -2
- package/dist/schema-cli/validate-command.js +52 -4
- package/dist/schema-cli.d.ts +0 -1
- package/dist/search/configure-tenant-index.d.ts +1 -3
- package/dist/search/configure-tenant-index.js +0 -4
- package/dist/search/index.d.ts +1 -4
- package/dist/search/index.js +0 -2
- package/dist/search/meilisearch-adapter-internals.d.ts +8 -0
- package/dist/search/meilisearch-adapter-internals.js +9 -0
- package/dist/search/meilisearch-adapter.d.ts +1 -8
- package/dist/search/meilisearch-adapter.js +6 -7
- package/dist/search/meilisearch-peer.d.ts +2 -0
- package/dist/search/meilisearch-peer.js +5 -0
- package/dist/search/reindex-entity.js +107 -91
- 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 -0
- package/dist/upgrade-changelog.js +18 -0
- package/dist/upgrade-cli-internals.d.ts +8 -0
- package/dist/upgrade-cli-internals.js +63 -0
- package/dist/upgrade-cli.d.ts +1 -18
- package/dist/upgrade-cli.js +29 -137
- package/dist/upgrade-marker-parse.d.ts +32 -0
- package/dist/upgrade-marker-parse.js +73 -0
- 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 +27 -20
- package/src/changes.json +451 -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 -10
- package/dist/engine/feature-ast/extractors/round1.js +0 -81
- 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 -483
- package/dist/engine/feature-ast/patch.d.ts +0 -210
- package/dist/engine/feature-ast/patch.js +0 -610
- 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 -1476
- package/dist/engine/feature-ast/pattern-change-schema.js +0 -1226
- package/dist/engine/feature-ast/pattern-id-matchers.d.ts +0 -7
- package/dist/engine/feature-ast/pattern-id-matchers.js +0 -210
- package/dist/engine/feature-ast/patterns.d.ts +0 -318
- package/dist/engine/feature-ast/patterns.js +0 -106
- package/dist/engine/feature-ast/render.d.ts +0 -47
- package/dist/engine/feature-ast/render.js +0 -662
- 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 -93
- 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 -20
- package/dist/engine/pattern-library/static-schemas.js +0 -478
- package/dist/engine/pattern-library/types.d.ts +0 -158
- package/dist/engine/pattern-library/types.js +0 -36
- package/dist/engine/provider-plugin-context.d.ts +0 -3
- package/dist/engine/provider-plugin-context.js +0 -28
- 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
|
@@ -4,13 +4,13 @@ import { parseJsonSafe } from "../utils/safe-json.js";
|
|
|
4
4
|
import { isTemporalInstant, isTemporalPlainDate } from "./temporal-value-guards.js";
|
|
5
5
|
// --- Value coercion at the driver boundary ------------------------------
|
|
6
6
|
//
|
|
7
|
-
//
|
|
7
|
+
// The driver returns timestamptz as JS Date (or ISO string depending on
|
|
8
8
|
// driver config). Framework contract says timestamptz surfaces as
|
|
9
9
|
// Temporal.Instant — without coercion every read hands callers a Date and
|
|
10
10
|
// downstream code that does .epochMilliseconds / .add(...) crashes.
|
|
11
11
|
//
|
|
12
|
-
// Symmetric on write: Temporal.Instant doesn't bind directly
|
|
13
|
-
//
|
|
12
|
+
// Symmetric on write: Temporal.Instant doesn't bind directly as a driver
|
|
13
|
+
// param — convert to ISO string when the column pgType is timestamptz.
|
|
14
14
|
// Postgres bigint → JS: safe integers become `number` (matches createBigIntField /
|
|
15
15
|
// drizzle mode:"number"); values outside ±2^53 stay `bigint` (money cents, raw
|
|
16
16
|
// unmanaged columns). Uses BigInt equality check so 9007199254740993n never
|
|
@@ -72,7 +72,7 @@ function instantFromDriver(value) {
|
|
|
72
72
|
// the day, so say so once per column instead of returning the wrong day quietly.
|
|
73
73
|
const warnedNonMidnightDateColumns = new Set();
|
|
74
74
|
const MS_PER_DAY = 86_400_000;
|
|
75
|
-
const dateColumnDriftLog = createFallbackLogger("
|
|
75
|
+
const dateColumnDriftLog = createFallbackLogger("bun-sql");
|
|
76
76
|
function warnIfNotDateColumn(epochMs, column) {
|
|
77
77
|
// skip: midnight value is a correct date column, and an already-warned column is deduped
|
|
78
78
|
if (epochMs % MS_PER_DAY === 0 || warnedNonMidnightDateColumns.has(column))
|
|
@@ -33,7 +33,9 @@ function prepareDateValue(value) {
|
|
|
33
33
|
// structured values bind directly with an ::jsonb cast; JSON.stringify first
|
|
34
34
|
// would produce a JSON-string scalar instead of the structured value.
|
|
35
35
|
export function prepareJsonbValue(value) {
|
|
36
|
-
|
|
36
|
+
// Bun.SQL types JS numbers as int4/float8 params, which Postgres refuses for a jsonb column.
|
|
37
|
+
// Non-finite numbers fall through so Postgres rejects them instead of storing JSON null.
|
|
38
|
+
if (typeof value === "boolean" || (typeof value === "number" && Number.isFinite(value))) {
|
|
37
39
|
return { kind: "param", sql: "::text::jsonb", bound: JSON.stringify(value) };
|
|
38
40
|
}
|
|
39
41
|
if (typeof value !== "object" || isTemporalInstant(value)) {
|
|
@@ -42,7 +44,7 @@ export function prepareJsonbValue(value) {
|
|
|
42
44
|
if (!Array.isArray(value)) {
|
|
43
45
|
return { kind: "param", sql: "::jsonb", bound: value };
|
|
44
46
|
}
|
|
45
|
-
// All-boolean arrays are inferred as boolean[] by
|
|
47
|
+
// All-boolean arrays are inferred as boolean[] by the driver; route via text::jsonb.
|
|
46
48
|
if (value.length > 0 && value.every((entry) => typeof entry === "boolean")) {
|
|
47
49
|
return { kind: "param", sql: "::text::jsonb", bound: JSON.stringify(value) };
|
|
48
50
|
}
|
|
@@ -59,7 +61,7 @@ const INTEGER_PG_TYPES = new Set([
|
|
|
59
61
|
"bigserial",
|
|
60
62
|
]);
|
|
61
63
|
// Postgres rounds sub-millisecond params into timestamptz(3); truncating to ms here keeps the
|
|
62
|
-
// stored instant identical across drivers and equal to what
|
|
64
|
+
// stored instant identical across drivers and equal to what a Date param would store.
|
|
63
65
|
export function instantToTimestamptzParam(instant) {
|
|
64
66
|
return Temporal.Instant.fromEpochMilliseconds(instant.epochMilliseconds).toString();
|
|
65
67
|
}
|
|
@@ -67,7 +69,7 @@ function prepareDriverNeutralScalar(value, pgType) {
|
|
|
67
69
|
if ((pgType === "timestamptz" || pgType === "timestamptz(3)") && isTemporalInstant(value)) {
|
|
68
70
|
return { kind: "param", sql: "", bound: instantToTimestamptzParam(value) };
|
|
69
71
|
}
|
|
70
|
-
//
|
|
72
|
+
// Sent as text, so Postgres rejects 3.5 for an integer column instead of rounding it.
|
|
71
73
|
if (typeof value === "number" && pgType !== undefined && INTEGER_PG_TYPES.has(pgType)) {
|
|
72
74
|
return { kind: "param", sql: "", bound: String(value) };
|
|
73
75
|
}
|
package/dist/db/eagerload.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { EntityDefinition
|
|
1
|
+
import type { EntityDefinition } from "@cosmicdrift/kumiko-types/fields";
|
|
2
|
+
import type { SessionUser } from "../engine/types/index.ts";
|
|
2
3
|
import { type ParentVisibilityOption } from "./parent-ref-clause.ts";
|
|
3
4
|
import type { TenantDb } from "./tenant-db.ts";
|
|
4
5
|
export type EagerLoadEntityResolver = (entityName: string) => EntityDefinition | undefined;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { EntityDefinition } from "
|
|
1
|
+
import type { EntityDefinition } from "@cosmicdrift/kumiko-types/fields";
|
|
2
2
|
import { type Logger } from "../logging/index.ts";
|
|
3
3
|
import type { EnvelopeCipher } from "../secrets/envelope-cipher.ts";
|
|
4
4
|
export declare function collectEncryptedFieldNames(entity: EntityDefinition): ReadonlySet<string>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Writable } from "@cosmicdrift/kumiko-types/executor-brand";
|
|
2
|
+
import type { EntityDefinition } from "@cosmicdrift/kumiko-types/fields";
|
|
2
3
|
import type { EntityTenancy, TenancyBrand } from "@cosmicdrift/kumiko-types/tenancy-brand";
|
|
3
|
-
import type { EntityDefinition } from "../engine/types/index.ts";
|
|
4
4
|
import type { BuildEntityTableMetaOptions, EntityTableMeta, UnmanagedTableInput } from "./entity-table-meta-types.ts";
|
|
5
5
|
export type { BuildEntityTableMetaOptions, ColumnMeta, CompositePrimaryKeyMeta, EntityTableMeta, IndexMeta, PgType, UnmanagedTableInput, } from "./entity-table-meta-types.ts";
|
|
6
6
|
export declare function resolveTableName(entityName: string, entity: EntityDefinition, featureName: string | undefined): string;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import type { EntityDefinition } from "@cosmicdrift/kumiko-types/fields";
|
|
2
|
+
import type { EntityId } from "@cosmicdrift/kumiko-types/identifiers";
|
|
1
3
|
import type { ErasedSubjectHandling } from "../crypto/pii-field-encryption.ts";
|
|
2
4
|
import type { WhereObject } from "../db/query.ts";
|
|
3
|
-
import type {
|
|
5
|
+
import type { SessionUser, TenantId } from "../engine/types/index.ts";
|
|
4
6
|
import { type WriteFailure } from "../errors/index.ts";
|
|
5
7
|
import { type EventMetadata } from "../event-store/index.ts";
|
|
6
8
|
import type { EntityCache } from "../pipeline/entity-cache.ts";
|
|
@@ -5,7 +5,8 @@ import { executeRawQueryRead } from "../db/queries/raw-sql.js";
|
|
|
5
5
|
import { shiftParams } from "../engine/ownership.js";
|
|
6
6
|
import { SYSTEM_TENANT_ID } from "../engine/types/identifiers.js";
|
|
7
7
|
import { AccessDeniedError, InternalError, subjectErasedConflict, UniqueViolationError, writeFailure, } from "../errors/index.js";
|
|
8
|
-
import { ArchivedStreamError
|
|
8
|
+
import { ArchivedStreamError } from "../event-store/errors.js";
|
|
9
|
+
import { isStreamArchived } from "../event-store/index.js";
|
|
9
10
|
import { assertUnreachable } from "../utils/index.js";
|
|
10
11
|
import { rehydrateCompoundTypes } from "./compound-types.js";
|
|
11
12
|
import { collectEncryptedFieldNames, decryptEntityFieldValues, encryptEntityFieldValues, logUndecryptableField, resolveEntityFieldEncryption, } from "./entity-field-encryption.js";
|
|
@@ -120,7 +121,7 @@ export function buildExecutorContext(table, entity, options) {
|
|
|
120
121
|
// old hardcoded user.tenantId). Single source of truth for the stream key.
|
|
121
122
|
const streamTenantFor = (user, requestedStreamTenantId) => entity.systemStream ? SYSTEM_TENANT_ID : (requestedStreamTenantId ?? user.tenantId);
|
|
122
123
|
// Only a system-mode db (r.systemScope() / acknowledged cross-tenant) or a tenant-mode db bound
|
|
123
|
-
// to exactly that stream tenant (ctx.
|
|
124
|
+
// to exactly that stream tenant (ctx.tenants.writeTarget) may address another tenant's stream, and only
|
|
124
125
|
// the tenant of the row it just loaded.
|
|
125
126
|
const streamTenantOverrideFailure = (db, row, requestedStreamTenantId) => {
|
|
126
127
|
if (requestedStreamTenantId === undefined)
|
|
@@ -293,7 +294,7 @@ export function buildExecutorContext(table, entity, options) {
|
|
|
293
294
|
return await decryptForRead(rehydrateCompoundTypes(row, entity));
|
|
294
295
|
}
|
|
295
296
|
// Archive guard for the CRUD write paths. Archived streams are read-only —
|
|
296
|
-
// ctx.
|
|
297
|
+
// ctx.events.append (append-event-core) already enforces this, but the
|
|
297
298
|
// executor appends directly via append() and getStreamVersion() ignores
|
|
298
299
|
// the archive flag, so without this check a PATCH/DELETE on an archived
|
|
299
300
|
// entity would silently land an event and break the read-only contract
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { FieldDefinition } from "@cosmicdrift/kumiko-types/fields";
|
|
2
|
+
import type { ListAggregateCurrencyAmount, ListAggregateMeasureKind } from "@cosmicdrift/kumiko-types/list-aggregate-types";
|
|
3
|
+
import type { OwnershipClause } from "../engine/ownership.ts";
|
|
4
|
+
import type { ExecutorContext } from "./event-store-executor-context.ts";
|
|
5
|
+
import { type ListWhere } from "./event-store-executor-read-filter.ts";
|
|
6
|
+
import type { TenantDb } from "./tenant-db.ts";
|
|
7
|
+
export type CurrencyMeasureCandidate = {
|
|
8
|
+
readonly kind: ListAggregateMeasureKind;
|
|
9
|
+
readonly field: string;
|
|
10
|
+
readonly def: FieldDefinition;
|
|
11
|
+
readonly clause: OwnershipClause;
|
|
12
|
+
};
|
|
13
|
+
export type MeasureCurrencies = ReadonlyMap<string, readonly string[]>;
|
|
14
|
+
export declare function currencyColumnOf(field: string): string;
|
|
15
|
+
export declare function loadMeasureCurrencies(ctx: ExecutorContext, measures: readonly CurrencyMeasureCandidate[], where: ListWhere, db: TenantDb): Promise<MeasureCurrencies>;
|
|
16
|
+
export declare function currencyMeasureAlias(measureIndex: number, currencyIndex: number): string;
|
|
17
|
+
export declare function decodeCurrencyAmounts(row: Readonly<Record<string, unknown>>, measureIndex: number, currencies: readonly string[]): readonly ListAggregateCurrencyAmount[];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { isPerCurrencyMeasure } from "./aggregate-sql.js";
|
|
2
|
+
import { bindShiftedClause } from "./event-store-executor-read-filter.js";
|
|
3
|
+
import { executeRawQueryRead } from "./queries/raw-sql.js";
|
|
4
|
+
import { schemaTableName } from "./table-introspection.js";
|
|
5
|
+
import { tenantDbRunner } from "./tenant-db-runner.js";
|
|
6
|
+
// Above the ~180 ISO 4217 codes, so the cap only bounds malformed data.
|
|
7
|
+
const MAX_AGGREGATE_CURRENCIES = 200;
|
|
8
|
+
export function currencyColumnOf(field) {
|
|
9
|
+
return `${field}Currency`;
|
|
10
|
+
}
|
|
11
|
+
// Runs before the measure query mutates `where`, on a copy of its params, and
|
|
12
|
+
// under the money field's own read clause: an unreadable amount must not reveal
|
|
13
|
+
// which currencies exist.
|
|
14
|
+
export async function loadMeasureCurrencies(ctx, measures, where, db) {
|
|
15
|
+
const byField = new Map();
|
|
16
|
+
const tableName = String(schemaTableName(ctx.table));
|
|
17
|
+
for (const m of measures) {
|
|
18
|
+
if (!isPerCurrencyMeasure(m.kind, m.def.type) || byField.has(m.field))
|
|
19
|
+
continue;
|
|
20
|
+
if (!Object.hasOwn(ctx.table, currencyColumnOf(m.field)))
|
|
21
|
+
continue;
|
|
22
|
+
const params = [...where.params];
|
|
23
|
+
const conditions = [...where.whereSql, `${where.colSql(m.field)} IS NOT NULL`];
|
|
24
|
+
if (m.clause.kind === "sql")
|
|
25
|
+
conditions.push(`(${bindShiftedClause(params, m.clause)})`);
|
|
26
|
+
const currencySql = where.colSql(currencyColumnOf(m.field));
|
|
27
|
+
const rows = await executeRawQueryRead(tenantDbRunner(db), `SELECT DISTINCT ${currencySql} AS cur FROM "${tableName}" WHERE ${conditions.join(" AND ")} AND ${currencySql} IS NOT NULL ORDER BY 1 LIMIT ${MAX_AGGREGATE_CURRENCIES}`, params);
|
|
28
|
+
byField.set(m.field, rows.map((row) => String(row.cur)));
|
|
29
|
+
}
|
|
30
|
+
return byField;
|
|
31
|
+
}
|
|
32
|
+
export function currencyMeasureAlias(measureIndex, currencyIndex) {
|
|
33
|
+
return `m${measureIndex}_${currencyIndex}`;
|
|
34
|
+
}
|
|
35
|
+
export function decodeCurrencyAmounts(row, measureIndex, currencies) {
|
|
36
|
+
return currencies.flatMap((currency, j) => {
|
|
37
|
+
const raw = row[currencyMeasureAlias(measureIndex, j)];
|
|
38
|
+
return raw === null || raw === undefined ? [] : [{ currency, value: Number(raw) }];
|
|
39
|
+
});
|
|
40
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ValidationError } from "../errors/index.js";
|
|
2
|
-
import { aggregateKeyOf, decodeListAggregateValue, emptyListAggregateValue, groupedKeyOrderLimitSql, isListAggregateGroupable, isListAggregateMeasureSupported, listAggregateKeySql, listAggregateMeasureSql, } from "./aggregate-sql.js";
|
|
2
|
+
import { aggregateKeyOf, decodeListAggregateValue, emptyListAggregateValue, groupedKeyOrderLimitSql, isListAggregateGroupable, isListAggregateMeasureSupported, isPerCurrencyMeasure, listAggregateKeySql, listAggregateMeasureSql, listCurrencyMeasureSql, } from "./aggregate-sql.js";
|
|
3
3
|
import { holdsCiphertextOrSecret } from "./entity-field-encryption.js";
|
|
4
|
+
import { currencyColumnOf, currencyMeasureAlias, decodeCurrencyAmounts, loadMeasureCurrencies, } from "./event-store-executor-read-aggregate-currencies.js";
|
|
4
5
|
import { appendShiftedClause, bindShiftedClause, } from "./event-store-executor-read-filter.js";
|
|
5
6
|
import { buildListWhere, createFieldReadClause, } from "./event-store-executor-read-where.js";
|
|
6
7
|
import { executeRawQueryRead } from "./queries/raw-sql.js";
|
|
@@ -61,9 +62,26 @@ function planAggregate(ctx, fieldReadClause, aggregate) {
|
|
|
61
62
|
return { groupBy, measures };
|
|
62
63
|
}
|
|
63
64
|
function emptyMeasureValues(plan) {
|
|
64
|
-
return plan.measures.map((m) =>
|
|
65
|
+
return plan.measures.map((m) => {
|
|
66
|
+
if (m.gate.kind === "silent")
|
|
67
|
+
return null;
|
|
68
|
+
return isPerCurrencyMeasure(m.kind, m.gate.def.type) ? [] : emptyListAggregateValue(m.kind);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function currencyCandidates(plan) {
|
|
72
|
+
return plan.measures.flatMap((m) => m.gate.kind === "ok"
|
|
73
|
+
? [{ kind: m.kind, field: m.field, def: m.gate.def, clause: m.gate.clause }]
|
|
74
|
+
: []);
|
|
65
75
|
}
|
|
66
|
-
function
|
|
76
|
+
function currencyMeasureSelects(measureIndex, kind, field, readFilterSql, currencies, where) {
|
|
77
|
+
return currencies.map((currency, j) => {
|
|
78
|
+
where.params.push(currency);
|
|
79
|
+
const currencyMatch = `${where.colSql(currencyColumnOf(field))} = $${where.params.length}`;
|
|
80
|
+
const filterSql = readFilterSql === undefined ? currencyMatch : `${currencyMatch} AND (${readFilterSql})`;
|
|
81
|
+
return `${listCurrencyMeasureSql(kind, where.colSql(field), filterSql)} AS ${currencyMeasureAlias(measureIndex, j)}`;
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function renderSelectList(plan, where, currencies) {
|
|
67
85
|
const parts = [];
|
|
68
86
|
if (plan.groupBy?.gate.kind === "ok") {
|
|
69
87
|
const { def, clause } = plan.groupBy.gate;
|
|
@@ -77,6 +95,11 @@ function renderSelectList(plan, where) {
|
|
|
77
95
|
if (m.gate.kind === "silent")
|
|
78
96
|
continue; // skip: an unreadable measure stays out of the SELECT and decodes to null
|
|
79
97
|
const filterSql = m.gate.clause.kind === "sql" ? bindShiftedClause(where.params, m.gate.clause) : undefined;
|
|
98
|
+
if (isPerCurrencyMeasure(m.kind, m.gate.def.type)) {
|
|
99
|
+
const fieldCurrencies = currencies.get(m.field) ?? [];
|
|
100
|
+
parts.push(...currencyMeasureSelects(i, m.kind, m.field, filterSql, fieldCurrencies, where));
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
80
103
|
parts.push(`${listAggregateMeasureSql(m.kind, m.gate.def.type, where.colSql(m.field), filterSql)} AS m${i}`);
|
|
81
104
|
}
|
|
82
105
|
return parts.join(", ");
|
|
@@ -93,7 +116,8 @@ export async function aggregateList(ctx, payload, user, db, runtimeOptions) {
|
|
|
93
116
|
};
|
|
94
117
|
}
|
|
95
118
|
const { where, searchTruncated } = built;
|
|
96
|
-
const
|
|
119
|
+
const currencies = await loadMeasureCurrencies(ctx, currencyCandidates(plan), where, db);
|
|
120
|
+
const selectList = renderSelectList(plan, where, currencies);
|
|
97
121
|
const whereText = where.whereSql.length > 0 ? ` WHERE ${where.whereSql.join(" AND ")}` : "";
|
|
98
122
|
const groupText = grouped ? groupedKeyOrderLimitSql(MAX_AGGREGATE_GROUPS + 1) : "";
|
|
99
123
|
const tableName = String(schemaTableName(ctx.table));
|
|
@@ -102,7 +126,14 @@ export async function aggregateList(ctx, payload, user, db, runtimeOptions) {
|
|
|
102
126
|
const groups = rows.slice(0, MAX_AGGREGATE_GROUPS).map((row) => ({
|
|
103
127
|
key: grouped ? aggregateKeyOf(row["k0"]) : null,
|
|
104
128
|
count: Number(row["c"]),
|
|
105
|
-
measures: plan.measures.map((m, i) =>
|
|
129
|
+
measures: plan.measures.map((m, i) => {
|
|
130
|
+
if (m.gate.kind === "silent")
|
|
131
|
+
return null;
|
|
132
|
+
if (isPerCurrencyMeasure(m.kind, m.gate.def.type)) {
|
|
133
|
+
return decodeCurrencyAmounts(row, i, currencies.get(m.field) ?? []);
|
|
134
|
+
}
|
|
135
|
+
return decodeListAggregateValue(row[`m${i}`]);
|
|
136
|
+
}),
|
|
106
137
|
}));
|
|
107
138
|
return {
|
|
108
139
|
groups,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import type { EntityDefinition } from "@cosmicdrift/kumiko-types/fields";
|
|
1
2
|
import { type OwnershipClause } from "../engine/ownership.ts";
|
|
2
|
-
import type { EntityDefinition } from "../engine/types/index.ts";
|
|
3
3
|
import { type Table } from "./event-store-executor-context.ts";
|
|
4
4
|
export type ListWhere = {
|
|
5
5
|
readonly whereSql: string[];
|
|
@@ -58,7 +58,7 @@ function applyMultiSelectFilter(colSql, whereSql, params, f) {
|
|
|
58
58
|
// skip: empty candidate list is unsatisfiable
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
61
|
-
// Bound as text then cast: a JS array makes
|
|
61
|
+
// Bound as text then cast: a JS array makes the driver infer boolean[]/int4[]
|
|
62
62
|
// for client-supplied non-string values, and `boolean[]::jsonb` is rejected
|
|
63
63
|
// (500 on client input). An array value means "contains all of these".
|
|
64
64
|
params.push(JSON.stringify(candidates));
|
|
@@ -163,6 +163,9 @@ export function collectListFilters(payload) {
|
|
|
163
163
|
const single = payload.filter !== undefined ? [payload.filter] : [];
|
|
164
164
|
return payload.filters !== undefined ? [...single, ...payload.filters] : single;
|
|
165
165
|
}
|
|
166
|
+
function isJsonbArrayField(field) {
|
|
167
|
+
return field?.type === "multiSelect" || (field?.type === "reference" && field.multiple === true);
|
|
168
|
+
}
|
|
166
169
|
export function applyListFilter(where, f, table, entity, fieldReadClause) {
|
|
167
170
|
if (!Object.hasOwn(table, f.field)) {
|
|
168
171
|
// skip: unknown field — not a real column, drop the filter (injection guard)
|
|
@@ -194,9 +197,9 @@ export function applyListFilter(where, f, table, entity, fieldReadClause) {
|
|
|
194
197
|
}
|
|
195
198
|
if (readClause.kind === "sql")
|
|
196
199
|
appendShiftedClause(where, readClause);
|
|
197
|
-
if (entity.fields[f.field]
|
|
200
|
+
if (isJsonbArrayField(entity.fields[f.field])) {
|
|
198
201
|
applyMultiSelectFilter(where.colSql, where.whereSql, where.params, f);
|
|
199
|
-
// skip:
|
|
202
|
+
// skip: jsonb-array field already handled — don't fall through to applyScreenFilter
|
|
200
203
|
return;
|
|
201
204
|
}
|
|
202
205
|
applyScreenFilter(table, where.colSql, where.whereSql, where.params, f);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { EntityDefinition
|
|
1
|
+
import type { EntityDefinition } from "@cosmicdrift/kumiko-types/fields";
|
|
2
|
+
import type { TenantId } from "../engine/types/index.ts";
|
|
2
3
|
import type { TableInfo } from "./table-info.ts";
|
|
3
4
|
export declare function withStreamVersion(row: Record<string, unknown>, streamVersion: number): Record<string, unknown>;
|
|
4
5
|
export declare function coerceAndRehydrateRow(raw: Record<string, unknown>, tableInfo: TableInfo, entity: EntityDefinition): Record<string, unknown>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type { EntityDefinition } from "@cosmicdrift/kumiko-types/fields";
|
|
1
2
|
import { type OwnershipClause } from "../engine/ownership.ts";
|
|
2
|
-
import type {
|
|
3
|
+
import type { SessionUser, TenantId } from "../engine/types/index.ts";
|
|
3
4
|
import type { SearchAdapter } from "../search/types.ts";
|
|
4
5
|
import type { EventStoreExecutor } from "./event-store-executor.ts";
|
|
5
6
|
import type { Table } from "./event-store-executor-context.ts";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type { EntityDefinition } from "@cosmicdrift/kumiko-types/fields";
|
|
1
2
|
import { type OwnershipClause } from "../engine/ownership.ts";
|
|
2
|
-
import type {
|
|
3
|
+
import type { SessionUser } from "../engine/types/index.ts";
|
|
3
4
|
import type { EventStoreExecutor } from "./event-store-executor.ts";
|
|
4
5
|
import type { Table } from "./event-store-executor-context.ts";
|
|
5
6
|
import type { ListWhere } from "./event-store-executor-read-filter.ts";
|
|
@@ -59,7 +59,7 @@ export function createReadVerbs(ctx) {
|
|
|
59
59
|
const tableInfo = extractTableInfo(table);
|
|
60
60
|
const encryptedRows = rawRows.map((r) => coerceAndRehydrateRow(r, tableInfo, entity));
|
|
61
61
|
const decryptedRows = await Promise.all(encryptedRows.map((r) => decryptForRead(r, { degradeUndecryptable: () => { } })));
|
|
62
|
-
// Stream version is authoritative (see detail()): ctx.
|
|
62
|
+
// Stream version is authoritative (see detail()): ctx.events.append bumps the
|
|
63
63
|
// stream without touching row.version, so the raw row version would hand
|
|
64
64
|
// clients a stale optimistic-lock base. Rows without events keep theirs.
|
|
65
65
|
const rows = decryptedRows.map((r, i) => withStreamVersion(r, streamVersions[i] ?? 0));
|
|
@@ -101,7 +101,7 @@ export function createReadVerbs(ctx) {
|
|
|
101
101
|
return null;
|
|
102
102
|
const idWhere = idFilter(payload.id);
|
|
103
103
|
// Stream-version authoritative (same policy as update/Block 0):
|
|
104
|
-
// ctx.
|
|
104
|
+
// ctx.events.append (lifecycle-writes like incident:post-update) bumps
|
|
105
105
|
// the stream WITHOUT touching row.version — a detail-read that hands
|
|
106
106
|
// out the stale row.version dooms the next CRUD update built on it
|
|
107
107
|
// (entityEdit loads detail.version as its optimistic-lock base) to a
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { EventStoreExecutor } from "@cosmicdrift/kumiko-types/event-store-executor-types";
|
|
2
|
+
type WriteVerbs = Pick<EventStoreExecutor, "create" | "update" | "delete" | "forget" | "restore">;
|
|
3
|
+
export declare function withOwnTransactionOnPool(verbs: WriteVerbs): WriteVerbs;
|
|
4
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { runnerCanBeginTransaction } from "./query.js";
|
|
2
|
+
import { isBoundTenantDb, tenantDbRunner, tenantDbWritesDeniedReason } from "./tenant-db-runner.js";
|
|
3
|
+
import { runInOwnSavepoint, runInOwnTransaction } from "./tenant-db-scoped-rebind.js";
|
|
4
|
+
// Aborts the surrounding transaction when a verb returns a failure instead of throwing.
|
|
5
|
+
class RollbackOnFailure extends Error {
|
|
6
|
+
}
|
|
7
|
+
// Append, projection and hooks commit or roll back together, also when a handler swallows a failed
|
|
8
|
+
// verb inside its transaction. Savepoints on one tx are serialized, so parallel verbs cannot interleave.
|
|
9
|
+
async function runVerbAtomically(db, run) {
|
|
10
|
+
// Unbound and denied handles keep their original error, a fresh transaction would reword it.
|
|
11
|
+
if (!isBoundTenantDb(db) || tenantDbWritesDeniedReason(db) !== undefined) {
|
|
12
|
+
return run(db);
|
|
13
|
+
}
|
|
14
|
+
const runInOwnScope = runnerCanBeginTransaction(tenantDbRunner(db))
|
|
15
|
+
? runInOwnTransaction
|
|
16
|
+
: runInOwnSavepoint;
|
|
17
|
+
let failure;
|
|
18
|
+
try {
|
|
19
|
+
return await runInOwnScope(db, async (txDb) => {
|
|
20
|
+
const result = await run(txDb);
|
|
21
|
+
if (!result.isSuccess) {
|
|
22
|
+
failure = result;
|
|
23
|
+
throw new RollbackOnFailure();
|
|
24
|
+
}
|
|
25
|
+
return result;
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
if (error instanceof RollbackOnFailure && failure !== undefined)
|
|
30
|
+
return failure;
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export function withOwnTransactionOnPool(verbs) {
|
|
35
|
+
return {
|
|
36
|
+
create: (payload, user, db, options) => runVerbAtomically(db, (txDb) => verbs.create(payload, user, txDb, options)),
|
|
37
|
+
update: (payload, user, db, options) => runVerbAtomically(db, (txDb) => verbs.update(payload, user, txDb, options)),
|
|
38
|
+
delete: (payload, user, db, options) => runVerbAtomically(db, (txDb) => verbs.delete(payload, user, txDb, options)),
|
|
39
|
+
forget: (payload, user, db, options) => runVerbAtomically(db, (txDb) => verbs.forget(payload, user, txDb, options)),
|
|
40
|
+
restore: (payload, user, db, options) => runVerbAtomically(db, (txDb) => verbs.restore(payload, user, txDb, options)),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
+
import type { EntityId } from "@cosmicdrift/kumiko-types/identifiers";
|
|
1
2
|
import type { TenantDb } from "@cosmicdrift/kumiko-types/tenant-db-types";
|
|
2
3
|
import type { ZodType } from "zod";
|
|
3
4
|
import type { UnavailableSelectOption } from "../engine/screen-helpers.ts";
|
|
4
|
-
import type {
|
|
5
|
-
import { type
|
|
5
|
+
import type { UnprocessableOpts } from "../errors/classes.ts";
|
|
6
|
+
import { type WriteFailure, writeFailure } from "../errors/index.ts";
|
|
6
7
|
import type { StoredEvent } from "../event-store/index.ts";
|
|
7
8
|
import type { DbRow, DbRunner } from "./connection.ts";
|
|
8
|
-
export declare function withoutEventInJson<T extends {
|
|
9
|
-
readonly event: unknown;
|
|
10
|
-
}>(result: T): T;
|
|
11
9
|
export declare function projectEntityEvent(db: TenantDb, runner: DbRunner, event: StoredEvent): Promise<void>;
|
|
12
10
|
export declare function selectOptionNotAvailableFailure(entries: readonly UnavailableSelectOption[]): WriteFailure | undefined;
|
|
13
11
|
export type PreSaveFn = (changes: Record<string, unknown>, previous: Record<string, unknown>, isNew: boolean) => Promise<Record<string, unknown>>;
|
|
@@ -2,11 +2,6 @@ import { VersionConflictError as FrameworkVersionConflict, UnprocessableError, w
|
|
|
2
2
|
import { hasLiveProjectionsForEvent, runProjectionsForEvent, } from "../pipeline/projections-runner.js";
|
|
3
3
|
import { projectionRegistryOf } from "./projection-registry-binding.js";
|
|
4
4
|
import { runInSavepointIfSupported } from "./query.js";
|
|
5
|
-
// The echoed event carries entity PII and must never reach a handler's JSON response, while
|
|
6
|
-
// hooks and projections still read it by property. Non-enumerable keeps it out of spread/stringify.
|
|
7
|
-
export function withoutEventInJson(result) {
|
|
8
|
-
return Object.defineProperty(result, "event", { value: result.event, enumerable: false });
|
|
9
|
-
}
|
|
10
5
|
// Custom projections for a write that did not go through the dispatcher (hook or
|
|
11
6
|
// job writing a second aggregate). Savepoint like applyEntityEvent: a throwing
|
|
12
7
|
// projection fails the write and the caller's transaction rolls it back.
|
|
@@ -4,15 +4,18 @@ import { instructionFieldNames } from "../engine/instruction-fields.js";
|
|
|
4
4
|
import { userCanCreateFieldRow, userCanWriteFieldRow } from "../engine/ownership.js";
|
|
5
5
|
import { buildInsertSchema, buildUpdateSchema } from "../engine/schema-builder.js";
|
|
6
6
|
import { findUnavailableSelectOptions, isRecordLocked, isUnchangedValue, } from "../engine/screen-helpers.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { IdempotentReplayError, PreconditionFailedError, RecordLockedError, } from "../errors/classes.js";
|
|
8
|
+
import { AccessDeniedError, VersionConflictError as FrameworkVersionConflict, InternalError, NotFoundError, UnprocessableError, writeFailure, } from "../errors/index.js";
|
|
9
|
+
import { isSubjectErasedConflict } from "../errors/subject-erased.js";
|
|
10
|
+
import { IdempotentAppendConflictError as EventStoreIdempotentAppendConflict } from "../event-store/errors.js";
|
|
11
|
+
import { append, VersionConflictError as EventStoreVersionConflict, getStreamVersion, } from "../event-store/index.js";
|
|
9
12
|
import { assertInstructionFieldWriteAllowed, assertIrreversibleOperationAllowed, isIrreversibleEntityVerb, } from "../pipeline/irreversible-operation-gate.js";
|
|
10
13
|
import { generateId } from "../utils/index.js";
|
|
11
14
|
import { applyEntityEvent } from "./apply-entity-event.js";
|
|
12
15
|
import { flattenCompoundTypes, rehydrateCompoundTypes } from "./compound-types.js";
|
|
13
16
|
import { WritePurposes, } from "./event-store-executor.js";
|
|
14
17
|
import { buildEventMetadata, entityEventName, isForeignTenantOnGlobalEntity, ownershipSubject, tryMapUniqueViolation, } from "./event-store-executor-context.js";
|
|
15
|
-
import { optimisticLockFailure, ownershipDeniedFailure, projectEntityEvent, runPreSave, selectOptionNotAvailableFailure,
|
|
18
|
+
import { optimisticLockFailure, ownershipDeniedFailure, projectEntityEvent, runPreSave, selectOptionNotAvailableFailure, } from "./event-store-executor-write-steps.js";
|
|
16
19
|
import { isFrameworkSystemUser, isLockGuardBypassed } from "./lock-guard.js";
|
|
17
20
|
import { runInSavepointIfSupported } from "./query.js";
|
|
18
21
|
import { assertPersonalDataWrite, tableNameOf, withExecutorManagedWrites } from "./tenant-db.js";
|
|
@@ -131,7 +134,7 @@ export function createWriteVerbs(ctx) {
|
|
|
131
134
|
}
|
|
132
135
|
throw error;
|
|
133
136
|
}
|
|
134
|
-
// Stream-version is authoritative, not row.version. `ctx.
|
|
137
|
+
// Stream-version is authoritative, not row.version. `ctx.events.append`
|
|
135
138
|
// can bump the stream between CRUD writes (domain event on the same
|
|
136
139
|
// aggregate); a stale row.version here would make the next CRUD write
|
|
137
140
|
// trip `events_aggregate_version_uq` (tenant_id, aggregate_id, version)
|
|
@@ -244,14 +247,14 @@ export function createWriteVerbs(ctx) {
|
|
|
244
247
|
// legitimately collide — the same ID has an existing stream — so return
|
|
245
248
|
// version_conflict instead of internal_error. Update uses the same catch.
|
|
246
249
|
try {
|
|
247
|
-
// Savepoint-scoped:
|
|
248
|
-
//
|
|
250
|
+
// Savepoint-scoped: Postgres aborts the WHOLE surrounding
|
|
251
|
+
// transaction once any statement inside it errors, even if the JS error
|
|
249
252
|
// is caught — a losing concurrent create's unique-violation
|
|
250
253
|
// would otherwise abort the caller's outer transaction and surface as
|
|
251
254
|
// internal_error at commit time instead of the version_conflict this
|
|
252
255
|
// catch classifies. runInSavepointIfSupported confines the failed
|
|
253
256
|
// INSERT to a nested scope that rolls back on its own (same pattern as
|
|
254
|
-
// ctx.
|
|
257
|
+
// ctx.events.tryAppend), and falls back to a plain call when the runner
|
|
255
258
|
// is a bare pool connection with no active transaction to poison
|
|
256
259
|
// (seeds/tests calling the executor directly).
|
|
257
260
|
const event = await runInSavepointIfSupported(runner, async (sp) => append(sp, {
|
|
@@ -287,8 +290,8 @@ export function createWriteVerbs(ctx) {
|
|
|
287
290
|
// designer/frontend can show a clear "duplicate" message instead of a cryptic
|
|
288
291
|
// "internal server error".
|
|
289
292
|
// Savepoint like the append: an unclassified DB error from the projection
|
|
290
|
-
// write would otherwise poison the enclosing transaction (
|
|
291
|
-
// whole
|
|
293
|
+
// write would otherwise poison the enclosing transaction (Postgres aborts the
|
|
294
|
+
// whole transaction once any statement in it fails). The savepoint rolls back the failed
|
|
292
295
|
// write while allowing the error to propagate and remain catchable.
|
|
293
296
|
async function applyProjection(runner, event, noRowMessage) {
|
|
294
297
|
let result;
|
|
@@ -462,7 +465,7 @@ export function createWriteVerbs(ctx) {
|
|
|
462
465
|
await projectEntityEvent(db, runner, echoEvent);
|
|
463
466
|
return {
|
|
464
467
|
isSuccess: true,
|
|
465
|
-
data:
|
|
468
|
+
data: {
|
|
466
469
|
kind: "save",
|
|
467
470
|
id: aggregateId,
|
|
468
471
|
data: projection,
|
|
@@ -473,7 +476,7 @@ export function createWriteVerbs(ctx) {
|
|
|
473
476
|
// Persisted event carries ciphertext by design — the caller-facing
|
|
474
477
|
// echo must be plaintext like every other response field.
|
|
475
478
|
event: echoEvent,
|
|
476
|
-
}
|
|
479
|
+
},
|
|
477
480
|
};
|
|
478
481
|
},
|
|
479
482
|
async update(payload, user, db, updateOptions) {
|
|
@@ -526,7 +529,7 @@ export function createWriteVerbs(ctx) {
|
|
|
526
529
|
const { data, echoEvent } = persisted;
|
|
527
530
|
return {
|
|
528
531
|
isSuccess: true,
|
|
529
|
-
data:
|
|
532
|
+
data: {
|
|
530
533
|
kind: "save",
|
|
531
534
|
id: data["id"], // @cast-boundary engine-payload
|
|
532
535
|
data,
|
|
@@ -535,7 +538,7 @@ export function createWriteVerbs(ctx) {
|
|
|
535
538
|
isNew: false,
|
|
536
539
|
entityName,
|
|
537
540
|
event: echoEvent,
|
|
538
|
-
}
|
|
541
|
+
},
|
|
539
542
|
};
|
|
540
543
|
}
|
|
541
544
|
catch (e) {
|
|
@@ -622,14 +625,14 @@ export function createWriteVerbs(ctx) {
|
|
|
622
625
|
await projectEntityEvent(db, runner, echoEvent);
|
|
623
626
|
return {
|
|
624
627
|
isSuccess: true,
|
|
625
|
-
data:
|
|
628
|
+
data: {
|
|
626
629
|
kind: "delete",
|
|
627
630
|
id: payload.id,
|
|
628
631
|
data: existing,
|
|
629
632
|
entityName,
|
|
630
633
|
event: echoEvent,
|
|
631
634
|
...(isLockGuardBypassed(user, options) && { lockGuardBypassed: true }),
|
|
632
|
-
}
|
|
635
|
+
},
|
|
633
636
|
};
|
|
634
637
|
},
|
|
635
638
|
// Hard-purge (Art. 17). Same shape as delete(), but emits `forgotten` which
|
|
@@ -695,14 +698,14 @@ export function createWriteVerbs(ctx) {
|
|
|
695
698
|
await projectEntityEvent(db, runner, echoEvent);
|
|
696
699
|
return {
|
|
697
700
|
isSuccess: true,
|
|
698
|
-
data:
|
|
701
|
+
data: {
|
|
699
702
|
kind: "delete",
|
|
700
703
|
id: payload.id,
|
|
701
704
|
data: existing,
|
|
702
705
|
entityName,
|
|
703
706
|
event: echoEvent,
|
|
704
707
|
lockGuardBypassed: true,
|
|
705
|
-
}
|
|
708
|
+
},
|
|
706
709
|
};
|
|
707
710
|
},
|
|
708
711
|
async restore(payload, user, db, options) {
|
|
@@ -761,7 +764,7 @@ export function createWriteVerbs(ctx) {
|
|
|
761
764
|
await projectEntityEvent(db, runner, echoEvent);
|
|
762
765
|
return {
|
|
763
766
|
isSuccess: true,
|
|
764
|
-
data:
|
|
767
|
+
data: {
|
|
765
768
|
kind: "save",
|
|
766
769
|
id: payload.id,
|
|
767
770
|
data: restoredHydrated,
|
|
@@ -770,7 +773,7 @@ export function createWriteVerbs(ctx) {
|
|
|
770
773
|
isNew: false,
|
|
771
774
|
entityName,
|
|
772
775
|
event: echoEvent,
|
|
773
|
-
}
|
|
776
|
+
},
|
|
774
777
|
};
|
|
775
778
|
},
|
|
776
779
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { EventStoreExecutor } from "@cosmicdrift/kumiko-types/event-store-executor-types";
|
|
2
|
+
import type { EntityDefinition } from "@cosmicdrift/kumiko-types/fields";
|
|
2
3
|
import type { LocalKeyKmsAdapter } from "../crypto/index.ts";
|
|
3
|
-
import type { EntityDefinition } from "../engine/types/index.ts";
|
|
4
4
|
import type { EntityCache } from "../pipeline/entity-cache.ts";
|
|
5
5
|
import type { SearchAdapter } from "../search/types.ts";
|
|
6
6
|
import type { EnvelopeCipher } from "../secrets/envelope-cipher.ts";
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { buildExecutorContext } from "./event-store-executor-context.js";
|
|
2
2
|
import { createReadVerbs } from "./event-store-executor-read.js";
|
|
3
3
|
import { createWriteVerbs } from "./event-store-executor-write.js";
|
|
4
|
+
import { withOwnTransactionOnPool } from "./event-store-executor-write-atomic.js";
|
|
4
5
|
export { WritePurposes } from "@cosmicdrift/kumiko-types/event-store-executor-types";
|
|
5
6
|
export { entityEventName } from "./event-store-executor-context.js";
|
|
6
7
|
export function createEventStoreExecutor(table, entity, options) {
|
|
7
8
|
const ctx = buildExecutorContext(table, entity, options);
|
|
8
9
|
return {
|
|
9
|
-
...createWriteVerbs(ctx),
|
|
10
|
+
...withOwnTransactionOnPool(createWriteVerbs(ctx)),
|
|
10
11
|
...createReadVerbs(ctx),
|
|
11
12
|
};
|
|
12
13
|
}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import type { ExecutorManagedWriteCapability, Writable } from "@cosmicdrift/kumiko-types/executor-brand";
|
|
2
|
+
import type { EntityDefinition } from "@cosmicdrift/kumiko-types/fields";
|
|
2
3
|
import { AccessDeniedError } from "../errors/index.ts";
|
|
3
|
-
export
|
|
4
|
+
export type ExecutorManagedEntitySource = {
|
|
5
|
+
readonly entityName: string;
|
|
6
|
+
readonly entity: EntityDefinition;
|
|
7
|
+
};
|
|
8
|
+
export declare function markExecutorManagedTable(table: object, entitySource?: ExecutorManagedEntitySource): void;
|
|
9
|
+
export declare function executorManagedEntitySourceOf(table: unknown): ExecutorManagedEntitySource | undefined;
|
|
4
10
|
export declare function isExecutorManagedTable(table: unknown): boolean;
|
|
5
11
|
export declare function registerExecutorManagedWriteRunner(runner: object): void;
|
|
6
12
|
export declare function hasExecutorManagedWriteCapability(runner: unknown): runner is ExecutorManagedWriteCapability;
|