@cosmicdrift/kumiko-framework 0.13.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +7 -7
- package/src/__tests__/{anonymous-access.integration.ts → anonymous-access.integration.test.ts} +12 -9
- package/src/__tests__/{error-contract.integration.ts → error-contract.integration.test.ts} +5 -4
- package/src/__tests__/{field-access.integration.ts → field-access.integration.test.ts} +3 -3
- package/src/__tests__/{full-stack.integration.ts → full-stack.integration.test.ts} +7 -16
- package/src/__tests__/{ownership.integration.ts → ownership.integration.test.ts} +3 -2
- package/src/__tests__/{raw-table.integration.ts → raw-table.integration.test.ts} +18 -30
- package/src/__tests__/{reference-data.integration.ts → reference-data.integration.test.ts} +24 -11
- package/src/__tests__/{transition-guard.integration.ts → transition-guard.integration.test.ts} +12 -10
- package/src/api/__tests__/api.test.ts +1 -1
- package/src/api/__tests__/auth-middleware-transport.test.ts +1 -1
- package/src/api/__tests__/auth-routes-cookie.test.ts +1 -1
- package/src/api/__tests__/{batch.integration.ts → batch.integration.test.ts} +30 -30
- package/src/api/__tests__/body-limit.test.ts +1 -1
- package/src/api/__tests__/csrf-middleware.test.ts +1 -1
- package/src/api/__tests__/{dispatcher-live.integration.ts → dispatcher-live.integration.test.ts} +10 -9
- package/src/api/__tests__/metrics-endpoint.test.ts +1 -1
- package/src/api/__tests__/{nested-write.integration.ts → nested-write.integration.test.ts} +13 -16
- package/src/api/__tests__/readiness.test.ts +1 -1
- package/src/api/__tests__/request-id-middleware.test.ts +1 -1
- package/src/api/__tests__/sse-broker.test.ts +12 -12
- package/src/api/__tests__/sse-route.test.ts +1 -1
- package/src/api/readiness.ts +2 -2
- package/src/auth/__tests__/roles.test.ts +2 -2
- package/src/bun-db/__tests__/PATTERN.md +73 -0
- package/src/bun-db/__tests__/_helpers.ts +103 -0
- package/src/bun-db/__tests__/batch-methods.integration.test.ts +143 -0
- package/src/bun-db/__tests__/batch-methods.test.ts +20 -0
- package/src/bun-db/__tests__/bun-test-db.ts +19 -0
- package/src/bun-db/__tests__/bun-test-stack.ts +6 -0
- package/src/bun-db/__tests__/column-types.integration.test.ts +132 -0
- package/src/bun-db/__tests__/compound-types.integration.test.ts +134 -0
- package/src/bun-db/__tests__/jsonb-edge-cases.integration.test.ts +235 -0
- package/src/bun-db/__tests__/smoke.integration.test.ts +43 -0
- package/src/bun-db/__tests__/sql-methods.integration.test.ts +231 -0
- package/src/bun-db/__tests__/where-patterns.integration.test.ts +185 -0
- package/src/bun-db/connection.ts +84 -0
- package/src/bun-db/index.ts +31 -0
- package/src/bun-db/query.ts +845 -0
- package/src/compliance/__tests__/duration-spec.test.ts +1 -1
- package/src/compliance/__tests__/profiles.test.ts +1 -1
- package/src/compliance/__tests__/sub-processors.test.ts +1 -1
- package/src/db/__tests__/{apply-entity-event-tenant.integration.ts → apply-entity-event-tenant.integration.test.ts} +13 -11
- package/src/db/__tests__/big-int-field.test.ts +15 -14
- package/src/db/__tests__/column-ddl.integration.test.ts +113 -0
- package/src/db/__tests__/compound-types.test.ts +1 -1
- package/src/db/__tests__/{config-seed.integration.ts → config-seed.integration.test.ts} +32 -27
- package/src/db/__tests__/connection-options.test.ts +1 -1
- package/src/db/__tests__/dialect-instant.test.ts +1 -1
- package/src/db/__tests__/encryption.test.ts +1 -1
- package/src/db/__tests__/{drizzle-table-types.test.ts → entity-table-types.test.ts} +16 -16
- package/src/db/__tests__/{event-store-executor-list.integration.ts → event-store-executor-list.integration.test.ts} +12 -7
- package/src/db/__tests__/{event-store-executor.integration.ts → event-store-executor.integration.test.ts} +19 -12
- package/src/db/__tests__/{implicit-projection-equivalence.integration.ts → implicit-projection-equivalence.integration.test.ts} +35 -29
- package/src/db/__tests__/located-timestamp.test.ts +1 -1
- package/src/db/__tests__/money.test.ts +1 -1
- package/src/db/__tests__/{multi-row-insert.integration.ts → multi-row-insert.integration.test.ts} +18 -11
- package/src/db/__tests__/parse-auto-verb.test.ts +1 -1
- package/src/db/__tests__/{required-not-null-migration-safety.integration.ts → required-not-null-migration-safety.integration.test.ts} +28 -24
- package/src/db/__tests__/{schema-migration.integration.ts → schema-migration.integration.test.ts} +32 -28
- package/src/db/__tests__/sql-inventory.test.ts +56 -0
- package/src/db/__tests__/table-builder-indexes.test.ts +30 -11
- package/src/db/__tests__/table-builder-required.test.ts +20 -22
- package/src/db/__tests__/{tenant-db.integration.ts → tenant-db.integration.test.ts} +106 -144
- package/src/db/__tests__/{unique-violation-mapping.integration.ts → unique-violation-mapping.integration.test.ts} +13 -8
- package/src/db/api.ts +46 -0
- package/src/db/apply-entity-event.ts +45 -36
- package/src/db/assert-exists-in.ts +5 -16
- package/src/db/bun-provider.ts +37 -0
- package/src/db/config-seed.ts +4 -4
- package/src/db/connection.ts +14 -57
- package/src/db/cursor.ts +5 -56
- package/src/db/dialect.ts +472 -99
- package/src/db/eagerload.ts +5 -12
- package/src/db/entity-table-meta.ts +390 -0
- package/src/db/event-store-executor.ts +158 -100
- package/src/db/index.ts +33 -5
- package/src/db/migrate-generator.ts +350 -0
- package/src/db/migrate-runner.ts +206 -0
- package/src/db/postgres-provider.ts +25 -0
- package/src/db/queries/entity-read.ts +15 -0
- package/src/db/queries/es-ops.ts +17 -0
- package/src/db/queries/event-consumer.ts +170 -0
- package/src/db/queries/event-store-admin.ts +127 -0
- package/src/db/queries/event-store.ts +155 -0
- package/src/db/queries/projection-rebuild.ts +59 -0
- package/src/db/queries/raw-sql.ts +15 -0
- package/src/db/queries/schema-drift.ts +35 -0
- package/src/db/queries/seed-context.ts +58 -0
- package/src/db/queries/table-ops.ts +11 -0
- package/src/db/queries/test-stack.ts +56 -0
- package/src/db/query-api.ts +22 -0
- package/src/db/query.ts +30 -0
- package/src/db/reference-data.ts +19 -22
- package/src/db/render-ddl.ts +57 -0
- package/src/db/row-helpers.ts +3 -52
- package/src/db/schema-inspection.ts +17 -4
- package/src/db/sql-inventory.ts +208 -0
- package/src/db/table-builder.ts +48 -40
- package/src/db/tenant-db.ts +105 -326
- package/src/engine/__tests__/auth-claims-registrar.test.ts +1 -1
- package/src/engine/__tests__/boot-validator-api-exposure.test.ts +3 -3
- package/src/engine/__tests__/boot-validator-located-timestamps.test.ts +1 -1
- package/src/engine/__tests__/boot-validator-pii-retention.test.ts +5 -5
- package/src/engine/__tests__/boot-validator-s0-integration.test.ts +3 -3
- package/src/engine/__tests__/boot-validator.test.ts +4 -3
- package/src/engine/__tests__/build-app-schema.test.ts +1 -1
- package/src/engine/__tests__/build-target.test.ts +1 -1
- package/src/engine/__tests__/claim-keys.test.ts +1 -1
- package/src/engine/__tests__/codemod-pipeline.test.ts +3 -3
- package/src/engine/__tests__/config-helpers.test.ts +1 -1
- package/src/engine/__tests__/effective-features.test.ts +1 -1
- package/src/engine/__tests__/engine.test.ts +1 -1
- package/src/engine/__tests__/entity-handlers.test.ts +3 -3
- package/src/engine/__tests__/event-helpers.test.ts +3 -3
- package/src/engine/__tests__/extends-registrar.test.ts +4 -4
- package/src/engine/__tests__/factories-long-text.test.ts +1 -1
- package/src/engine/__tests__/factories-time.test.ts +1 -1
- package/src/engine/__tests__/field-predicates.test.ts +1 -1
- package/src/engine/__tests__/hook-phases.test.ts +1 -1
- package/src/engine/__tests__/identifiers.test.ts +1 -1
- package/src/engine/__tests__/lifecycle-hooks.test.ts +1 -1
- package/src/engine/__tests__/nav.test.ts +1 -1
- package/src/engine/__tests__/ownership.test.ts +10 -11
- package/src/engine/__tests__/parse-ref-target.test.ts +1 -1
- package/src/engine/__tests__/pipeline-engine.test.ts +1 -1
- package/src/engine/__tests__/{pipeline-handler.integration.ts → pipeline-handler.integration.test.ts} +38 -52
- package/src/engine/__tests__/{pipeline-observability.integration.ts → pipeline-observability.integration.test.ts} +1 -1
- package/src/engine/__tests__/{pipeline-performance.integration.ts → pipeline-performance.integration.test.ts} +1 -1
- package/src/engine/__tests__/pipeline-sub-pipelines.test.ts +1 -1
- package/src/engine/__tests__/post-query-hook.test.ts +1 -1
- package/src/engine/__tests__/projection-helpers.test.ts +25 -17
- package/src/engine/__tests__/projection.test.ts +4 -4
- package/src/engine/__tests__/qualified-name.test.ts +1 -1
- package/src/engine/__tests__/raw-table.test.ts +9 -8
- package/src/engine/__tests__/resolve-config-or-param.test.ts +5 -5
- package/src/engine/__tests__/run-in.test.ts +1 -1
- package/src/engine/__tests__/schema-builder.test.ts +1 -1
- package/src/engine/__tests__/screen.test.ts +1 -1
- package/src/engine/__tests__/search-payload-extension.test.ts +3 -3
- package/src/engine/__tests__/state-machine.test.ts +1 -1
- package/src/engine/__tests__/steps-aggregate-append-event.test.ts +7 -7
- package/src/engine/__tests__/steps-aggregate-create.test.ts +4 -4
- package/src/engine/__tests__/steps-aggregate-update.test.ts +3 -3
- package/src/engine/__tests__/steps-call-feature.test.ts +5 -5
- package/src/engine/__tests__/steps-mail-send.test.ts +7 -7
- package/src/engine/__tests__/steps-read.test.ts +34 -40
- package/src/engine/__tests__/steps-resolver-utils.test.ts +6 -6
- package/src/engine/__tests__/steps-unsafe-projection-delete.test.ts +24 -19
- package/src/engine/__tests__/steps-unsafe-projection-upsert.test.ts +28 -17
- package/src/engine/__tests__/steps-webhook-send.test.ts +6 -6
- package/src/engine/__tests__/steps-workflow.test.ts +7 -7
- package/src/engine/__tests__/system-user.test.ts +1 -1
- package/src/engine/__tests__/validate-projection-allowlist.test.ts +4 -5
- package/src/engine/__tests__/validation-hooks.test.ts +1 -1
- package/src/engine/__tests__/visual-tree-patterns.test.ts +1 -1
- package/src/engine/boot-validator/entity-handler.ts +3 -3
- package/src/engine/boot-validator/ownership.ts +1 -1
- package/src/engine/define-feature.ts +1 -2
- package/src/engine/entity-handlers.ts +5 -5
- package/src/engine/factories.ts +1 -1
- package/src/engine/feature-ast/__tests__/canonical-form.test.ts +1 -1
- package/src/engine/feature-ast/__tests__/parse-happy-path.test.ts +1 -1
- package/src/engine/feature-ast/__tests__/parse-real-features.test.ts +2 -2
- package/src/engine/feature-ast/__tests__/parse.test.ts +1 -1
- package/src/engine/feature-ast/__tests__/patch.test.ts +1 -1
- package/src/engine/feature-ast/__tests__/patcher.test.ts +1 -1
- package/src/engine/feature-ast/__tests__/render-roundtrip.test.ts +1 -1
- package/src/engine/feature-ast/__tests__/visual-tree-parse.test.ts +1 -1
- package/src/engine/ownership.ts +113 -41
- package/src/engine/pattern-library/__tests__/library.test.ts +2 -2
- package/src/engine/projection-helpers.ts +2 -11
- package/src/engine/registry.ts +2 -2
- package/src/engine/steps/read-find-many.ts +13 -13
- package/src/engine/steps/read-find-one.ts +7 -9
- package/src/engine/steps/unsafe-projection-delete.ts +4 -5
- package/src/engine/steps/unsafe-projection-upsert.ts +63 -31
- package/src/engine/types/feature.ts +7 -2
- package/src/engine/types/fields.ts +4 -5
- package/src/engine/types/step.ts +10 -10
- package/src/engine/validate-projection-allowlist.ts +23 -3
- package/src/entrypoint/__tests__/{entrypoint-job-wiring.integration.ts → entrypoint-job-wiring.integration.test.ts} +4 -3
- package/src/entrypoint/__tests__/{split-deploy.integration.ts → split-deploy.integration.test.ts} +4 -3
- package/src/env/__tests__/compose-env-schema.test.ts +1 -1
- package/src/env/__tests__/dry-run.test.ts +1 -1
- package/src/errors/__tests__/classes.test.ts +1 -1
- package/src/errors/__tests__/write-failures.test.ts +1 -1
- package/src/es-ops/__tests__/{context.integration.ts → context.integration.test.ts} +43 -29
- package/src/es-ops/__tests__/{runner.integration.ts → runner.integration.test.ts} +25 -23
- package/src/es-ops/__tests__/runner.test.ts +29 -19
- package/src/es-ops/context.ts +9 -43
- package/src/es-ops/operations-schema.ts +2 -2
- package/src/es-ops/runner.ts +12 -26
- package/src/event-store/__tests__/{admin-api.integration.ts → admin-api.integration.test.ts} +71 -45
- package/src/event-store/__tests__/{event-store.integration.ts → event-store.integration.test.ts} +7 -5
- package/src/event-store/__tests__/{get-stream-version-perf.integration.ts → get-stream-version-perf.integration.test.ts} +5 -3
- package/src/event-store/__tests__/{perf.integration.ts → perf.integration.test.ts} +24 -16
- package/src/event-store/__tests__/{snapshot.integration.ts → snapshot.integration.test.ts} +34 -28
- package/src/event-store/__tests__/{upcaster-dead-letter.integration.ts → upcaster-dead-letter.integration.test.ts} +11 -12
- package/src/event-store/__tests__/{upcaster.integration.ts → upcaster.integration.test.ts} +19 -32
- package/src/event-store/admin-api.ts +55 -83
- package/src/event-store/archive.ts +15 -39
- package/src/event-store/event-store.ts +92 -86
- package/src/event-store/events-schema.ts +2 -1
- package/src/event-store/index.ts +1 -0
- package/src/event-store/snapshot.ts +26 -24
- package/src/event-store/upcaster-dead-letter.ts +19 -18
- package/src/files/__tests__/content-disposition.test.ts +1 -1
- package/src/files/__tests__/{file-field-pipeline.integration.ts → file-field-pipeline.integration.test.ts} +8 -5
- package/src/files/__tests__/file-handle.test.ts +1 -1
- package/src/files/__tests__/{files.integration.ts → files.integration.test.ts} +32 -17
- package/src/files/__tests__/read-stream.test.ts +1 -1
- package/src/files/__tests__/{storage-tracking.integration.ts → storage-tracking.integration.test.ts} +26 -30
- package/src/files/__tests__/write-stream.test.ts +1 -1
- package/src/files/__tests__/zip-stream.test.ts +1 -1
- package/src/files/file-ref-table.ts +2 -2
- package/src/files/file-routes.ts +7 -9
- package/src/files/storage-tracking.ts +9 -17
- package/src/i18n/__tests__/i18n.test.ts +1 -1
- package/src/jobs/__tests__/{job-event-trigger.integration.ts → job-event-trigger.integration.test.ts} +6 -3
- package/src/jobs/__tests__/{job-multi-trigger.integration.ts → job-multi-trigger.integration.test.ts} +6 -3
- package/src/jobs/__tests__/{jobs.integration.ts → jobs.integration.test.ts} +5 -7
- package/src/lifecycle/__tests__/{lifecycle-server.integration.ts → lifecycle-server.integration.test.ts} +1 -1
- package/src/lifecycle/__tests__/lifecycle.test.ts +6 -6
- package/src/lifecycle/__tests__/signal-handlers.test.ts +6 -6
- package/src/logging/__tests__/pino-trace-bridge.test.ts +1 -1
- package/src/migrations/__tests__/compare-snapshots.test.ts +1 -1
- package/src/migrations/__tests__/{detect-drift.integration.ts → detect-drift.integration.test.ts} +34 -26
- package/src/migrations/__tests__/{detect-projections-to-rebuild.integration.ts → detect-projections-to-rebuild.integration.test.ts} +1 -1
- package/src/migrations/__tests__/rebuild-marker.test.ts +1 -1
- package/src/migrations/projection-detection.ts +12 -1
- package/src/migrations/schema-drift.ts +7 -23
- package/src/observability/__tests__/console-provider.test.ts +1 -1
- package/src/observability/__tests__/metric-validator.test.ts +1 -1
- package/src/observability/__tests__/noop-provider.test.ts +1 -1
- package/src/observability/__tests__/{observability.integration.ts → observability.integration.test.ts} +5 -8
- package/src/observability/__tests__/prometheus-meter.test.ts +1 -1
- package/src/observability/__tests__/recording-meter.test.ts +1 -1
- package/src/observability/__tests__/recording-tracer.test.ts +1 -1
- package/src/observability/__tests__/sensitive-filter.test.ts +1 -1
- package/src/pipeline/__tests__/{archive-stream.integration.ts → archive-stream.integration.test.ts} +3 -3
- package/src/pipeline/__tests__/auth-claims-resolver.test.ts +9 -9
- package/src/pipeline/__tests__/{cascade-handler.integration.ts → cascade-handler.integration.test.ts} +18 -15
- package/src/pipeline/__tests__/cascade-handler.test.ts +1 -1
- package/src/pipeline/__tests__/{causation-chain.integration.ts → causation-chain.integration.test.ts} +12 -13
- package/src/pipeline/__tests__/{ctx-bridge.integration.ts → ctx-bridge.integration.test.ts} +12 -11
- package/src/pipeline/__tests__/dispatcher.test.ts +2 -2
- package/src/pipeline/__tests__/{distributed-lock.integration.ts → distributed-lock.integration.test.ts} +1 -1
- package/src/pipeline/__tests__/{domain-events-projections.integration.ts → domain-events-projections.integration.test.ts} +13 -15
- package/src/pipeline/__tests__/{event-dedup.integration.ts → event-dedup.integration.test.ts} +1 -1
- package/src/pipeline/__tests__/{event-define-event-strict.integration.ts → event-define-event-strict.integration.test.ts} +6 -16
- package/src/pipeline/__tests__/{event-dispatcher-lifecycle.integration.ts → event-dispatcher-lifecycle.integration.test.ts} +1 -1
- package/src/pipeline/__tests__/{event-dispatcher-multi-instance.integration.ts → event-dispatcher-multi-instance.integration.test.ts} +3 -2
- package/src/pipeline/__tests__/{event-dispatcher-pg-listen.integration.ts → event-dispatcher-pg-listen.integration.test.ts} +1 -1
- package/src/pipeline/__tests__/{event-dispatcher-recovery.integration.ts → event-dispatcher-recovery.integration.test.ts} +2 -2
- package/src/pipeline/__tests__/{event-dispatcher-second-audit.integration.ts → event-dispatcher-second-audit.integration.test.ts} +17 -16
- package/src/pipeline/__tests__/event-dispatcher-strict.test.ts +14 -12
- package/src/pipeline/__tests__/{event-dispatcher.integration.ts → event-dispatcher.integration.test.ts} +8 -15
- package/src/pipeline/__tests__/{event-retention.integration.ts → event-retention.integration.test.ts} +28 -25
- package/src/pipeline/__tests__/{fetch-for-writing.integration.ts → fetch-for-writing.integration.test.ts} +6 -6
- package/src/pipeline/__tests__/lifecycle-pipeline.test.ts +4 -4
- package/src/pipeline/__tests__/{load-aggregate-query.integration.ts → load-aggregate-query.integration.test.ts} +9 -5
- package/src/pipeline/__tests__/{msp-error-mode.integration.ts → msp-error-mode.integration.test.ts} +1 -1
- package/src/pipeline/__tests__/{msp-multi-hop.integration.ts → msp-multi-hop.integration.test.ts} +9 -8
- package/src/pipeline/__tests__/{msp-rebuild.integration.ts → msp-rebuild.integration.test.ts} +47 -55
- package/src/pipeline/__tests__/{multi-stream-projection.integration.ts → multi-stream-projection.integration.test.ts} +19 -53
- package/src/pipeline/__tests__/{perf-rebuild.integration.ts → perf-rebuild.integration.test.ts} +36 -34
- package/src/pipeline/__tests__/{post-query-hook.integration.ts → post-query-hook.integration.test.ts} +1 -1
- package/src/pipeline/__tests__/{projection-rebuild.integration.ts → projection-rebuild.integration.test.ts} +21 -30
- package/src/pipeline/__tests__/{query-projection.integration.ts → query-projection.integration.test.ts} +6 -5
- package/src/pipeline/__tests__/{redis-pipeline.integration.ts → redis-pipeline.integration.test.ts} +3 -1
- package/src/pipeline/cascade-handler.ts +13 -21
- package/src/pipeline/dispatcher.ts +43 -48
- package/src/pipeline/event-consumer-state.ts +11 -2
- package/src/pipeline/event-dispatcher.ts +86 -146
- package/src/pipeline/event-retention.ts +14 -24
- package/src/pipeline/msp-rebuild.ts +54 -78
- package/src/pipeline/projection-rebuild.ts +65 -67
- package/src/pipeline/projection-state.ts +2 -2
- package/src/random/__tests__/generate.test.ts +13 -13
- package/src/rate-limit/__tests__/{dispatcher-l3.integration.ts → dispatcher-l3.integration.test.ts} +1 -1
- package/src/rate-limit/__tests__/{middleware.integration.ts → middleware.integration.test.ts} +1 -1
- package/src/rate-limit/__tests__/{resolver.integration.ts → resolver.integration.test.ts} +1 -1
- package/src/redis/__tests__/redis-options.test.ts +1 -1
- package/src/search/__tests__/{meilisearch-adapter.integration.ts → meilisearch-adapter.integration.test.ts} +1 -1
- package/src/search/__tests__/search-adapter.test.ts +1 -1
- package/src/secrets/__tests__/dek-cache.test.ts +1 -3
- package/src/secrets/__tests__/env-master-key-provider.test.ts +1 -1
- package/src/secrets/__tests__/envelope.test.ts +1 -1
- package/src/secrets/__tests__/leak-guard.test.ts +1 -1
- package/src/secrets/__tests__/rotation.test.ts +1 -1
- package/src/stack/db.ts +25 -48
- package/src/stack/push-entity-projection-tables.ts +2 -4
- package/src/stack/table-helpers.ts +98 -61
- package/src/stack/test-stack.ts +8 -7
- package/src/testing/__tests__/db-cleanup.test.ts +40 -0
- package/src/testing/__tests__/e2e-generator.test.ts +1 -1
- package/src/testing/__tests__/{ensure-entity-table.integration.ts → ensure-entity-table.integration.test.ts} +7 -14
- package/src/testing/db-cleanup.ts +44 -0
- package/src/testing/expect-error.ts +1 -1
- package/src/testing/index.ts +2 -0
- package/src/testing/multipart-helper.ts +94 -0
- package/src/testing/shared-entities.ts +5 -5
- package/src/time/__tests__/polyfill.test.ts +1 -1
- package/src/time/__tests__/tz-context.test.ts +1 -1
- package/src/utils/__tests__/assert.test.ts +1 -1
- package/src/utils/__tests__/env-parse.test.ts +1 -1
- package/CHANGELOG.md +0 -472
- package/src/db/__tests__/cursor.test.ts +0 -41
- package/src/db/__tests__/db-helpers.test.ts +0 -369
- package/src/db/__tests__/drizzle-helpers.integration.ts +0 -186
- package/src/db/__tests__/row-helpers.test.ts +0 -59
- package/src/engine/steps/_drizzle-boundary.ts +0 -19
- package/src/files/__tests__/file-field-column.integration.ts +0 -103
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { eq } from "drizzle-orm";
|
|
2
1
|
import type { TableColumns } from "../db/dialect";
|
|
2
|
+
import { deleteMany, fetchOne, updateMany } from "../db/query";
|
|
3
3
|
import { OnDeleteStrategies, SystemHookNames, SystemHookPriorities } from "../engine/constants";
|
|
4
4
|
import type { PreDeleteHookFn, Registry } from "../engine/types";
|
|
5
5
|
import { ConflictError, FrameworkReasons } from "../errors";
|
|
@@ -44,12 +44,8 @@ export function createCascadeDeleteHook(
|
|
|
44
44
|
if (!targetTable) continue;
|
|
45
45
|
|
|
46
46
|
if (strategy === OnDeleteStrategies.restrict) {
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
.from(targetTable)
|
|
50
|
-
.where(eq(targetTable[relation.foreignKey], payload.id))
|
|
51
|
-
.limit(1);
|
|
52
|
-
if (rows.length > 0) {
|
|
47
|
+
const row = await fetchOne(db, targetTable, { [relation.foreignKey]: payload.id });
|
|
48
|
+
if (row) {
|
|
53
49
|
throw new ConflictError({
|
|
54
50
|
message: `${relation.target} has records referencing ${entityName}#${payload.id}`,
|
|
55
51
|
i18nKey: "errors.deleteRestricted",
|
|
@@ -64,14 +60,16 @@ export function createCascadeDeleteHook(
|
|
|
64
60
|
}
|
|
65
61
|
|
|
66
62
|
if (strategy === OnDeleteStrategies.cascade) {
|
|
67
|
-
await db
|
|
63
|
+
await deleteMany(db, targetTable, { [relation.foreignKey]: payload.id });
|
|
68
64
|
}
|
|
69
65
|
|
|
70
66
|
if (strategy === OnDeleteStrategies.setNull) {
|
|
71
|
-
await
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
67
|
+
await updateMany(
|
|
68
|
+
db,
|
|
69
|
+
targetTable,
|
|
70
|
+
{ [relation.foreignKey]: null },
|
|
71
|
+
{ [relation.foreignKey]: payload.id },
|
|
72
|
+
);
|
|
75
73
|
}
|
|
76
74
|
}
|
|
77
75
|
|
|
@@ -79,17 +77,11 @@ export function createCascadeDeleteHook(
|
|
|
79
77
|
const throughTable = tables.get(relation.through.table);
|
|
80
78
|
if (!throughTable) continue;
|
|
81
79
|
// sourceKey points at the owner side (the entity being deleted).
|
|
82
|
-
// targetKey would point at the other side — filtering by it here
|
|
83
|
-
// would miss every through-row for this entity.
|
|
84
80
|
const sourceKey = relation.through.sourceKey;
|
|
85
81
|
|
|
86
82
|
if (strategy === OnDeleteStrategies.restrict) {
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
.from(throughTable)
|
|
90
|
-
.where(eq(throughTable[sourceKey], payload.id))
|
|
91
|
-
.limit(1);
|
|
92
|
-
if (rows.length > 0) {
|
|
83
|
+
const row = await fetchOne(db, throughTable, { [sourceKey]: payload.id });
|
|
84
|
+
if (row) {
|
|
93
85
|
throw new ConflictError({
|
|
94
86
|
message: `${relation.through.table} has records referencing ${entityName}#${payload.id}`,
|
|
95
87
|
i18nKey: "errors.deleteRestricted",
|
|
@@ -104,7 +96,7 @@ export function createCascadeDeleteHook(
|
|
|
104
96
|
}
|
|
105
97
|
|
|
106
98
|
if (strategy === OnDeleteStrategies.cascade) {
|
|
107
|
-
await db
|
|
99
|
+
await deleteMany(db, throughTable, { [sourceKey]: payload.id });
|
|
108
100
|
}
|
|
109
101
|
}
|
|
110
102
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { type AnyColumn, eq } from "drizzle-orm";
|
|
2
1
|
import { requestContext } from "../api/request-context";
|
|
3
2
|
import type { DbConnection, DbRow, DbTx } from "../db/connection";
|
|
4
|
-
import {
|
|
3
|
+
import { selectRowForUpdateById } from "../db/queries/entity-read";
|
|
4
|
+
import { selectMany, transaction } from "../db/query";
|
|
5
|
+
import { buildEntityTable, toSnakeCase } from "../db/table-builder";
|
|
5
6
|
import { createTenantDb } from "../db/tenant-db";
|
|
6
7
|
import { hasAccess } from "../engine/access";
|
|
7
8
|
import { checkWriteFieldRoles, filterReadFields } from "../engine/field-access";
|
|
@@ -173,15 +174,22 @@ export function createDispatcher(
|
|
|
173
174
|
): Dispatcher {
|
|
174
175
|
const { idempotency, lifecycle, jobRunner, effectiveFeatures } = options;
|
|
175
176
|
|
|
177
|
+
// Narrowing-helper: AppContext.db ist DbConnection|TenantDb|undefined. Die
|
|
178
|
+
// dispatch-Pfade brauchen DbConnection (oder DbTx aus Caller-Scope) für
|
|
179
|
+
// appendEvent/projection-writes; TenantDb-Branch wird hier ausgeschlossen.
|
|
180
|
+
function resolveDbSource(tx: DbTx | undefined): DbConnection | DbTx | undefined {
|
|
181
|
+
return tx ?? (context.db as DbConnection | undefined); // @cast-boundary db-operator
|
|
182
|
+
}
|
|
183
|
+
|
|
176
184
|
// Pre-build tables and transition maps for auto-guard (avoid per-request allocation)
|
|
177
|
-
const tableCache = new Map<string, ReturnType<typeof
|
|
185
|
+
const tableCache = new Map<string, ReturnType<typeof buildEntityTable>>();
|
|
178
186
|
const transitionCache = new Map<string, ReturnType<typeof defineTransitions>>();
|
|
179
187
|
|
|
180
|
-
function getTable(entityName: string): ReturnType<typeof
|
|
188
|
+
function getTable(entityName: string): ReturnType<typeof buildEntityTable> | undefined {
|
|
181
189
|
if (tableCache.has(entityName)) return tableCache.get(entityName);
|
|
182
190
|
const entity = registry.getEntity(entityName);
|
|
183
191
|
if (!entity) return undefined;
|
|
184
|
-
const table =
|
|
192
|
+
const table = buildEntityTable(entityName, entity, {
|
|
185
193
|
relations: registry.getRelations(entityName),
|
|
186
194
|
});
|
|
187
195
|
tableCache.set(entityName, table);
|
|
@@ -215,8 +223,7 @@ export function createDispatcher(
|
|
|
215
223
|
tx: DbTx | undefined,
|
|
216
224
|
callerFeature: string | undefined,
|
|
217
225
|
): Promise<void> {
|
|
218
|
-
const dbSource
|
|
219
|
-
tx ?? (context.db as DbConnection | undefined); // @cast-boundary db-operator
|
|
226
|
+
const dbSource = resolveDbSource(tx);
|
|
220
227
|
if (!dbSource) {
|
|
221
228
|
throw new InternalError({
|
|
222
229
|
message: `ctx.appendEvent("${args.type}") requires a database connection — none is configured.`,
|
|
@@ -245,8 +252,7 @@ export function createDispatcher(
|
|
|
245
252
|
// The outer dispatcher receives a DbConnection from the server/stack;
|
|
246
253
|
// AppContext's `db` union also allows TenantDb (for downstream hook calls),
|
|
247
254
|
// but at this point we're the root of the pipeline — cast is safe.
|
|
248
|
-
const dbSource
|
|
249
|
-
tx ?? (context.db as DbConnection | undefined); // @cast-boundary db-operator
|
|
255
|
+
const dbSource = resolveDbSource(tx);
|
|
250
256
|
const reqCtx = requestContext.get();
|
|
251
257
|
const db = dbSource
|
|
252
258
|
? createTenantDb(
|
|
@@ -313,8 +319,7 @@ export function createDispatcher(
|
|
|
313
319
|
await appendDomainEvent(args, user, tx, registry.getHandlerFeature(type));
|
|
314
320
|
},
|
|
315
321
|
fetchForWriting: async (args: FetchForWritingArgs): Promise<AggregateStreamHandle> => {
|
|
316
|
-
const dbSource
|
|
317
|
-
tx ?? (context.db as DbConnection | undefined); // @cast-boundary db-operator
|
|
322
|
+
const dbSource = resolveDbSource(tx);
|
|
318
323
|
if (!dbSource) {
|
|
319
324
|
throw new InternalError({
|
|
320
325
|
message: `ctx.fetchForWriting("${args.aggregateId}") requires a database connection — none is configured.`,
|
|
@@ -377,8 +382,7 @@ export function createDispatcher(
|
|
|
377
382
|
aggregateId: string,
|
|
378
383
|
loadOptions?: { readonly asOf?: Temporal.Instant },
|
|
379
384
|
): Promise<readonly StoredEvent[]> => {
|
|
380
|
-
const dbSource
|
|
381
|
-
tx ?? (context.db as DbConnection | undefined); // @cast-boundary db-operator
|
|
385
|
+
const dbSource = resolveDbSource(tx);
|
|
382
386
|
if (!dbSource) {
|
|
383
387
|
throw new InternalError({
|
|
384
388
|
message: `ctx.loadAggregate("${aggregateId}") requires a database connection — none is configured.`,
|
|
@@ -396,8 +400,7 @@ export function createDispatcher(
|
|
|
396
400
|
aggregateId: string,
|
|
397
401
|
archiveArgs: { readonly aggregateType: string; readonly reason?: string },
|
|
398
402
|
): Promise<void> => {
|
|
399
|
-
const dbSource
|
|
400
|
-
tx ?? (context.db as DbConnection | undefined); // @cast-boundary db-operator
|
|
403
|
+
const dbSource = resolveDbSource(tx);
|
|
401
404
|
if (!dbSource) {
|
|
402
405
|
throw new InternalError({
|
|
403
406
|
message: `ctx.archiveStream("${aggregateId}") requires a database connection — none is configured.`,
|
|
@@ -412,8 +415,7 @@ export function createDispatcher(
|
|
|
412
415
|
});
|
|
413
416
|
},
|
|
414
417
|
restoreStream: async (aggregateId: string): Promise<void> => {
|
|
415
|
-
const dbSource
|
|
416
|
-
tx ?? (context.db as DbConnection | undefined); // @cast-boundary db-operator
|
|
418
|
+
const dbSource = resolveDbSource(tx);
|
|
417
419
|
if (!dbSource) {
|
|
418
420
|
throw new InternalError({
|
|
419
421
|
message: `ctx.restoreStream("${aggregateId}") requires a database connection — none is configured.`,
|
|
@@ -422,8 +424,7 @@ export function createDispatcher(
|
|
|
422
424
|
await restoreStreamHelper(dbSource, user.tenantId, aggregateId);
|
|
423
425
|
},
|
|
424
426
|
isStreamArchived: async (aggregateId: string): Promise<boolean> => {
|
|
425
|
-
const dbSource
|
|
426
|
-
tx ?? (context.db as DbConnection | undefined); // @cast-boundary db-operator
|
|
427
|
+
const dbSource = resolveDbSource(tx);
|
|
427
428
|
if (!dbSource) {
|
|
428
429
|
throw new InternalError({
|
|
429
430
|
message: `ctx.isStreamArchived("${aggregateId}") requires a database connection — none is configured.`,
|
|
@@ -437,8 +438,7 @@ export function createDispatcher(
|
|
|
437
438
|
readonly version: number;
|
|
438
439
|
readonly state: Record<string, unknown>;
|
|
439
440
|
}): Promise<void> => {
|
|
440
|
-
const dbSource
|
|
441
|
-
tx ?? (context.db as DbConnection | undefined); // @cast-boundary db-operator
|
|
441
|
+
const dbSource = resolveDbSource(tx);
|
|
442
442
|
if (!dbSource) {
|
|
443
443
|
throw new InternalError({
|
|
444
444
|
message: `ctx.snapshotAggregate("${snapshotArgs.aggregateId}") requires a database connection — none is configured.`,
|
|
@@ -457,8 +457,7 @@ export function createDispatcher(
|
|
|
457
457
|
reducer: SnapshotReducer<TState>,
|
|
458
458
|
initial: TState,
|
|
459
459
|
): Promise<LoadAggregateWithSnapshotResult<TState>> => {
|
|
460
|
-
const dbSource
|
|
461
|
-
tx ?? (context.db as DbConnection | undefined); // @cast-boundary db-operator
|
|
460
|
+
const dbSource = resolveDbSource(tx);
|
|
462
461
|
if (!dbSource) {
|
|
463
462
|
throw new InternalError({
|
|
464
463
|
message: `ctx.loadAggregateWithSnapshot("${aggregateId}") requires a database connection — none is configured.`,
|
|
@@ -502,8 +501,7 @@ export function createDispatcher(
|
|
|
502
501
|
`table-less MSP (side-effect-only). Known queryable projections: ${all.join(", ") || "(none)"}`,
|
|
503
502
|
});
|
|
504
503
|
}
|
|
505
|
-
const dbSource
|
|
506
|
-
tx ?? (context.db as DbConnection | undefined); // @cast-boundary db-operator
|
|
504
|
+
const dbSource = resolveDbSource(tx);
|
|
507
505
|
if (!dbSource) {
|
|
508
506
|
throw new InternalError({
|
|
509
507
|
message: `ctx.queryProjection("${qualifiedName}") requires a database connection — none is configured.`,
|
|
@@ -513,17 +511,10 @@ export function createDispatcher(
|
|
|
513
511
|
// filter keeps cross-tenant leaks out unless the handler explicitly
|
|
514
512
|
// opts in. Works with any drizzle-table whose tenant column is named
|
|
515
513
|
// tenantId on the JS side.
|
|
516
|
-
|
|
517
|
-
const
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
rows = (await dbSource
|
|
521
|
-
.select()
|
|
522
|
-
.from(projTable)
|
|
523
|
-
.where(eq(tenantCol, user.tenantId))) as readonly Record<string, unknown>[]; // @cast-boundary db-row
|
|
524
|
-
} else {
|
|
525
|
-
rows = (await dbSource.select().from(projTable)) as readonly Record<string, unknown>[]; // @cast-boundary db-row
|
|
526
|
-
}
|
|
514
|
+
const tenantCol = (projTable as Record<string, unknown>)["tenantId"];
|
|
515
|
+
const where =
|
|
516
|
+
tenantCol && !queryOptions?.unsafeAllTenants ? { tenantId: user.tenantId } : undefined;
|
|
517
|
+
const rows = await selectMany<Record<string, unknown>>(dbSource, projTable, where);
|
|
527
518
|
return rows as readonly T[]; // @cast-boundary engine-payload
|
|
528
519
|
},
|
|
529
520
|
// Thin pass-through: one resolve impl lives on the dispatcher, the
|
|
@@ -1123,9 +1114,12 @@ export function createDispatcher(
|
|
|
1123
1114
|
// can false-pass; optimistic locking would catch it later, but with
|
|
1124
1115
|
// a less specific error. Falls back to a plain SELECT if no tx is
|
|
1125
1116
|
// active (tests without a DB connection).
|
|
1126
|
-
const
|
|
1127
|
-
|
|
1128
|
-
|
|
1117
|
+
const tableName = String(
|
|
1118
|
+
(table as { [key: symbol]: unknown })[Symbol.for("kumiko:schema:Name")],
|
|
1119
|
+
);
|
|
1120
|
+
const rows = tx
|
|
1121
|
+
? await selectRowForUpdateById(handlerContext.db, tableName, id)
|
|
1122
|
+
: await selectMany(handlerContext.db, table, { id });
|
|
1129
1123
|
const row = rows[0];
|
|
1130
1124
|
|
|
1131
1125
|
if (!row) continue;
|
|
@@ -1133,10 +1127,13 @@ export function createDispatcher(
|
|
|
1133
1127
|
// at all; a handler that wants to move a deleted row should use
|
|
1134
1128
|
// unsafeSkipTransitionGuard or restore first.
|
|
1135
1129
|
const rowAsRow = row as DbRow; // @cast-boundary engine-payload
|
|
1136
|
-
|
|
1130
|
+
const isDeleted = rowAsRow["isDeleted"] ?? rowAsRow["is_deleted"];
|
|
1131
|
+
if (entity.softDelete && isDeleted === true) {
|
|
1137
1132
|
continue;
|
|
1138
1133
|
}
|
|
1139
|
-
const currentValue =
|
|
1134
|
+
const currentValue =
|
|
1135
|
+
((row as DbRow)[fieldName] as string | undefined) ??
|
|
1136
|
+
((row as DbRow)[toSnakeCase(fieldName)] as string); // @cast-boundary engine-bridge
|
|
1140
1137
|
guardTransition(
|
|
1141
1138
|
getTransitions({ entityName, fieldName, map: transitionMap }),
|
|
1142
1139
|
currentValue,
|
|
@@ -1278,7 +1275,9 @@ export function createDispatcher(
|
|
|
1278
1275
|
}
|
|
1279
1276
|
};
|
|
1280
1277
|
|
|
1281
|
-
|
|
1278
|
+
// batch() opens its own outer transaction — needs the top-level
|
|
1279
|
+
// connection's `.begin()` (TransactionSql exposes only `.savepoint()`).
|
|
1280
|
+
const db = resolveDbSource(undefined) as DbConnection | undefined;
|
|
1282
1281
|
if (!db) {
|
|
1283
1282
|
// Without a DB connection there is no transaction to open. Fall back to
|
|
1284
1283
|
// sequential execution — useful for unit tests that don't touch the DB.
|
|
@@ -1306,7 +1305,7 @@ export function createDispatcher(
|
|
|
1306
1305
|
}
|
|
1307
1306
|
|
|
1308
1307
|
try {
|
|
1309
|
-
await
|
|
1308
|
+
await transaction(db, async (tx) => {
|
|
1310
1309
|
for (let i = 0; i < commands.length; i++) {
|
|
1311
1310
|
const cmd = commands[i];
|
|
1312
1311
|
if (!cmd) continue;
|
|
@@ -1326,10 +1325,6 @@ export function createDispatcher(
|
|
|
1326
1325
|
results,
|
|
1327
1326
|
});
|
|
1328
1327
|
}
|
|
1329
|
-
// Unexpected throw — typically a DB driver error from commit/rollback.
|
|
1330
|
-
// executeWrite already traps handler + lifecycle throws into WriteResult,
|
|
1331
|
-
// so anything reaching here is infrastructure-level. Wrap as InternalError
|
|
1332
|
-
// so the contract ("non-Kumiko → InternalError") holds uniformly.
|
|
1333
1328
|
return finalize({
|
|
1334
1329
|
isSuccess: false,
|
|
1335
1330
|
error: toWriteErrorInfo(wrapToKumiko(e)),
|
|
@@ -1368,7 +1363,7 @@ export function createDispatcher(
|
|
|
1368
1363
|
// scoped as "tenant" and no tx is threaded through. Hooks that need
|
|
1369
1364
|
// cross-tenant lookups opt in explicitly via queryAs(systemUser, ...).
|
|
1370
1365
|
function buildAuthClaimsContext(user: SessionUser): AuthClaimsContext {
|
|
1371
|
-
const dbSource
|
|
1366
|
+
const dbSource = resolveDbSource(undefined);
|
|
1372
1367
|
if (!dbSource) {
|
|
1373
1368
|
throw new InternalError({
|
|
1374
1369
|
message:
|
|
@@ -1,6 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
// sql now comes from native dialect
|
|
2
2
|
import type { DbConnection } from "../db/connection";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
bigint,
|
|
5
|
+
index,
|
|
6
|
+
instant,
|
|
7
|
+
integer,
|
|
8
|
+
table as pgTable,
|
|
9
|
+
primaryKey,
|
|
10
|
+
sql,
|
|
11
|
+
text,
|
|
12
|
+
} from "../db/dialect";
|
|
4
13
|
import { tableExists } from "../db/schema-inspection";
|
|
5
14
|
import { unsafePushTables } from "../stack";
|
|
6
15
|
|