@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
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
// Sprint-G-Pieces nebeneinander leben aber sich nicht treffen — Marker
|
|
9
9
|
// wäre leer, kein Rebuild würde ausgelöst.
|
|
10
10
|
|
|
11
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
11
12
|
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
12
13
|
import { tmpdir } from "node:os";
|
|
13
14
|
import { join } from "node:path";
|
|
14
|
-
import { afterEach, beforeEach, describe, expect, test } from "vitest";
|
|
15
15
|
import { createBooleanField, createEntity, createTextField, defineFeature } from "../../engine";
|
|
16
16
|
import { createRegistry } from "../../engine/registry";
|
|
17
17
|
import { detectProjectionsToRebuild } from "../projection-detection";
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
// - schemaVersion-Mismatch wirft (verhindert dass alte Markers gegen
|
|
5
5
|
// neue Lese-Logik fahren)
|
|
6
6
|
|
|
7
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
7
8
|
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
8
9
|
import { tmpdir } from "node:os";
|
|
9
10
|
import { join } from "node:path";
|
|
10
|
-
import { afterEach, beforeEach, describe, expect, test } from "vitest";
|
|
11
11
|
import { readRebuildMarker, writeRebuildMarker } from "../rebuild-marker";
|
|
12
12
|
|
|
13
13
|
let tmpDir: string;
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
// Damit muss niemand Tabellen-Namen doppelt pflegen (Truth liegt in der
|
|
12
12
|
// Projection-Definition).
|
|
13
13
|
|
|
14
|
-
import { getTableName } from "drizzle-orm";
|
|
15
14
|
import type { Registry } from "../engine/types/feature";
|
|
16
15
|
import {
|
|
17
16
|
type ColumnSpec,
|
|
@@ -90,6 +89,18 @@ function sameColumns(
|
|
|
90
89
|
return true;
|
|
91
90
|
}
|
|
92
91
|
|
|
92
|
+
const KUMIKO_NAME_SYMBOL = Symbol.for("kumiko:schema:Name");
|
|
93
|
+
function getTableName(table: unknown): string {
|
|
94
|
+
if (typeof table !== "object" || table === null) {
|
|
95
|
+
throw new Error("projection-detection: table is not a pgTable object");
|
|
96
|
+
}
|
|
97
|
+
const name = (table as Record<symbol, unknown>)[KUMIKO_NAME_SYMBOL];
|
|
98
|
+
if (typeof name !== "string") {
|
|
99
|
+
throw new Error("projection-detection: table missing drizzle name symbol");
|
|
100
|
+
}
|
|
101
|
+
return name;
|
|
102
|
+
}
|
|
103
|
+
|
|
93
104
|
/** Index `tableName → projection-name` aus der Registry. Nur Projections
|
|
94
105
|
* mit table-Definition (single-stream + multi-stream-with-table) zählen.
|
|
95
106
|
* Side-effect-only MSPs (table omitted) haben keinen Rebuild-Sinn. */
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// 3. Column-Diff: information_schema-Vergleich gegen Snapshot —
|
|
10
10
|
// missing-/extra-column, type-mismatch, nullability-mismatch. Fängt
|
|
11
11
|
// manuelle ALTER TABLEs in Prod sowie doppelte pgTable-Definitionen
|
|
12
|
-
// pro Tabelle (eine hand-written, eine via
|
|
12
|
+
// pro Tabelle (eine hand-written, eine via buildEntityTable), die
|
|
13
13
|
// stillschweigend gegen den Snapshot driften.
|
|
14
14
|
//
|
|
15
15
|
// Drizzle-kit's eigene Garantie: nach `migrate apply` ist der DB-Stand
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
|
|
20
20
|
import { readFileSync } from "node:fs";
|
|
21
21
|
import { resolve } from "node:path";
|
|
22
|
-
import { sql } from "drizzle-orm";
|
|
23
22
|
import type { DbConnection } from "../db/connection";
|
|
23
|
+
import { selectAppliedMigrations, selectPublicTableColumns } from "../db/queries/schema-drift";
|
|
24
24
|
import { tableExists } from "../db/schema-inspection";
|
|
25
25
|
import { parseJsonOrThrow } from "../utils/safe-json";
|
|
26
26
|
|
|
@@ -125,16 +125,10 @@ export async function loadAppliedMigrations(db: DbConnection): Promise<AppliedMi
|
|
|
125
125
|
? false
|
|
126
126
|
: await tableExists(db, "public.__drizzle_migrations");
|
|
127
127
|
if (!drizzleSchemaExists && !publicSchemaExists) return [];
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
: sql`public.__drizzle_migrations`;
|
|
133
|
-
const rows = await db.execute<{ hash: string; created_at: bigint | number | null }>(sql`
|
|
134
|
-
SELECT hash, created_at
|
|
135
|
-
FROM ${tableRef}
|
|
136
|
-
ORDER BY id
|
|
137
|
-
`);
|
|
128
|
+
const rows = await selectAppliedMigrations(
|
|
129
|
+
db,
|
|
130
|
+
drizzleSchemaExists ? "drizzle.__drizzle_migrations" : "public.__drizzle_migrations",
|
|
131
|
+
);
|
|
138
132
|
return rows.map((r) => ({
|
|
139
133
|
hash: r.hash,
|
|
140
134
|
createdAt: typeof r.created_at === "bigint" ? Number(r.created_at) : (r.created_at ?? 0),
|
|
@@ -143,12 +137,6 @@ export async function loadAppliedMigrations(db: DbConnection): Promise<AppliedMi
|
|
|
143
137
|
|
|
144
138
|
// --- Column-Diff (Welle 2 Boot-Gate Layer 3) ---
|
|
145
139
|
|
|
146
|
-
type DbColumnRow = {
|
|
147
|
-
readonly column_name: string;
|
|
148
|
-
readonly data_type: string;
|
|
149
|
-
readonly is_nullable: "YES" | "NO";
|
|
150
|
-
};
|
|
151
|
-
|
|
152
140
|
/** Liest information_schema.columns für eine Tabelle im public-Schema.
|
|
153
141
|
* Map by column_name. Default-Werte werden bewusst ausgelassen — die
|
|
154
142
|
* drift'en über drizzle-Versionen / PG-Reformulierungen hinweg ohne dass
|
|
@@ -158,11 +146,7 @@ async function loadDbColumns(
|
|
|
158
146
|
db: DbConnection,
|
|
159
147
|
tableName: string,
|
|
160
148
|
): Promise<ReadonlyMap<string, { type: string; notNull: boolean }>> {
|
|
161
|
-
const rows = await db
|
|
162
|
-
SELECT column_name, data_type, is_nullable
|
|
163
|
-
FROM information_schema.columns
|
|
164
|
-
WHERE table_schema = 'public' AND table_name = ${tableName}
|
|
165
|
-
`);
|
|
149
|
+
const rows = await selectPublicTableColumns(db, tableName);
|
|
166
150
|
const map = new Map<string, { type: string; notNull: boolean }>();
|
|
167
151
|
for (const r of rows) {
|
|
168
152
|
map.set(r.column_name, {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from "
|
|
1
|
+
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from "bun:test";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import {
|
|
3
|
+
import { buildEntityTable } from "../../db/table-builder";
|
|
4
4
|
import { createRegistry, defineFeature } from "../../engine";
|
|
5
5
|
import type { AppContext, SaveContext } from "../../engine/types";
|
|
6
6
|
import { createJobRunner } from "../../jobs";
|
|
@@ -65,18 +65,15 @@ const todoEntity = {
|
|
|
65
65
|
|
|
66
66
|
let postSaveInvocations = 0;
|
|
67
67
|
const todoFeature = defineFeature("todo", (r) => {
|
|
68
|
-
const todoTable =
|
|
68
|
+
const todoTable = buildEntityTable("todo", todoEntity);
|
|
69
69
|
r.entity("todo", todoEntity);
|
|
70
70
|
|
|
71
71
|
r.writeHandler(
|
|
72
72
|
"create",
|
|
73
73
|
z.object({ title: z.string() }),
|
|
74
74
|
async (event, ctx) => {
|
|
75
|
-
const rows = await ctx.db
|
|
76
|
-
|
|
77
|
-
.values({ title: event.payload.title })
|
|
78
|
-
.returning();
|
|
79
|
-
const row = rows[0] as { id: number; title: string };
|
|
75
|
+
const rows = await ctx.db.insertOne(todoTable, { title: event.payload.title });
|
|
76
|
+
const row = rows as { id: number; title: string };
|
|
80
77
|
return {
|
|
81
78
|
isSuccess: true,
|
|
82
79
|
data: {
|
package/src/pipeline/__tests__/{archive-stream.integration.ts → archive-stream.integration.test.ts}
RENAMED
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
// Kumiko carries this as a sparse kumiko_archived_streams table so active
|
|
6
6
|
// streams never pay for extra metadata writes.
|
|
7
7
|
|
|
8
|
-
import { afterAll, afterEach, beforeAll, describe, expect, test } from "
|
|
8
|
+
import { afterAll, afterEach, beforeAll, describe, expect, test } from "bun:test";
|
|
9
9
|
import { z } from "zod";
|
|
10
10
|
import { createEventStoreExecutor } from "../../db/event-store-executor";
|
|
11
|
-
import {
|
|
11
|
+
import { buildEntityTable } from "../../db/table-builder";
|
|
12
12
|
import { createEntity, createTextField, defineFeature } from "../../engine";
|
|
13
13
|
import {
|
|
14
14
|
ArchivedStreamError,
|
|
@@ -27,7 +27,7 @@ const itemEntity = createEntity({
|
|
|
27
27
|
table: "read_arch_items",
|
|
28
28
|
fields: { label: createTextField({ required: true }) },
|
|
29
29
|
});
|
|
30
|
-
const itemTable =
|
|
30
|
+
const itemTable = buildEntityTable("arch-item", itemEntity);
|
|
31
31
|
|
|
32
32
|
const archFeature = defineFeature("archtest", (r) => {
|
|
33
33
|
r.entity("arch-item", itemEntity);
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { describe, expect,
|
|
1
|
+
import { describe, expect, mock, test } from "bun:test";
|
|
2
2
|
import type { AuthClaimsContext, AuthClaimsHookDef, SessionUser } from "../../engine/types";
|
|
3
3
|
import type { Logger } from "../../logging/types";
|
|
4
4
|
import { resolveAuthClaims } from "../auth-claims-resolver";
|
|
5
5
|
|
|
6
6
|
type TestLogger = {
|
|
7
7
|
readonly log: Logger;
|
|
8
|
-
readonly warn: ReturnType<typeof
|
|
8
|
+
readonly warn: ReturnType<typeof mock>;
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
function makeTestLogger(): TestLogger {
|
|
12
|
-
const warn =
|
|
13
|
-
const info =
|
|
14
|
-
const error =
|
|
15
|
-
const debug =
|
|
12
|
+
const warn = mock();
|
|
13
|
+
const info = mock();
|
|
14
|
+
const error = mock();
|
|
15
|
+
const debug = mock();
|
|
16
16
|
const logger: Logger = {
|
|
17
17
|
warn,
|
|
18
18
|
info,
|
|
@@ -45,7 +45,7 @@ function hooks(...entries: AuthClaimsHookDef[]): readonly AuthClaimsHookDef[] {
|
|
|
45
45
|
|
|
46
46
|
describe("resolveAuthClaims — empty", () => {
|
|
47
47
|
test("zero hooks registered → empty record, contextFactory not called", async () => {
|
|
48
|
-
const factory =
|
|
48
|
+
const factory = mock();
|
|
49
49
|
const result = await resolveAuthClaims({
|
|
50
50
|
user: testUser,
|
|
51
51
|
hooks: [],
|
|
@@ -73,8 +73,8 @@ describe("resolveAuthClaims — single hook", () => {
|
|
|
73
73
|
});
|
|
74
74
|
|
|
75
75
|
test("receives the user and context handed in", async () => {
|
|
76
|
-
const fn =
|
|
77
|
-
const factory =
|
|
76
|
+
const fn = mock(async () => ({}));
|
|
77
|
+
const factory = mock(() => stubContext);
|
|
78
78
|
await resolveAuthClaims({
|
|
79
79
|
user: testUser,
|
|
80
80
|
hooks: hooks({ featureName: "any", fn }),
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { afterAll, beforeAll, describe, expect, test } from "
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
2
|
+
import { type BunTestDb, createTestDb } from "../../bun-db/__tests__/bun-test-db";
|
|
2
3
|
import type { TableColumns } from "../../db/dialect";
|
|
3
4
|
import { createEventStoreExecutor, type EventStoreExecutor } from "../../db/event-store-executor";
|
|
4
|
-
import {
|
|
5
|
+
import { buildEntityTable } from "../../db/table-builder";
|
|
5
6
|
import { createTenantDb, type TenantDb } from "../../db/tenant-db";
|
|
6
7
|
import {
|
|
7
8
|
createEntity,
|
|
@@ -11,13 +12,14 @@ import {
|
|
|
11
12
|
type Registry,
|
|
12
13
|
} from "../../engine";
|
|
13
14
|
import { createEventsTable } from "../../event-store";
|
|
14
|
-
import {
|
|
15
|
+
import { TestUsers, unsafeCreateEntityTable } from "../../stack";
|
|
16
|
+
import { ensureTemporalPolyfill } from "../../time/polyfill";
|
|
15
17
|
import { createCascadeDeleteHook } from "../cascade-handler";
|
|
16
18
|
|
|
17
19
|
// biome-ignore lint/suspicious/noExplicitAny: Drizzle dynamic tables
|
|
18
20
|
type Table = TableColumns<any>;
|
|
19
21
|
|
|
20
|
-
let testDb:
|
|
22
|
+
let testDb: BunTestDb;
|
|
21
23
|
let tdb: TenantDb;
|
|
22
24
|
let registry: Registry;
|
|
23
25
|
let departmentTable: Table;
|
|
@@ -77,6 +79,7 @@ const memberEntity = createEntity({
|
|
|
77
79
|
});
|
|
78
80
|
|
|
79
81
|
beforeAll(async () => {
|
|
82
|
+
await ensureTemporalPolyfill();
|
|
80
83
|
testDb = await createTestDb();
|
|
81
84
|
await createEventsTable(testDb.db);
|
|
82
85
|
tdb = createTenantDb(testDb.db, admin.tenantId);
|
|
@@ -90,14 +93,14 @@ beforeAll(async () => {
|
|
|
90
93
|
await unsafeCreateEntityTable(testDb.db, teamEntity);
|
|
91
94
|
await unsafeCreateEntityTable(testDb.db, memberEntity);
|
|
92
95
|
|
|
93
|
-
departmentTable =
|
|
94
|
-
userTable =
|
|
95
|
-
sessionTable =
|
|
96
|
-
groupTable =
|
|
97
|
-
userGroupRestrictTable =
|
|
98
|
-
userGroupCascadeTable =
|
|
99
|
-
teamTable =
|
|
100
|
-
memberTable =
|
|
96
|
+
departmentTable = buildEntityTable("department", departmentEntity);
|
|
97
|
+
userTable = buildEntityTable("user", userEntity);
|
|
98
|
+
sessionTable = buildEntityTable("session", sessionEntity);
|
|
99
|
+
groupTable = buildEntityTable("group", groupEntity);
|
|
100
|
+
userGroupRestrictTable = buildEntityTable("user-group-restrict", userGroupRestrictEntity);
|
|
101
|
+
userGroupCascadeTable = buildEntityTable("user-group-cascade", userGroupCascadeEntity);
|
|
102
|
+
teamTable = buildEntityTable("team", teamEntity);
|
|
103
|
+
memberTable = buildEntityTable("member", memberEntity);
|
|
101
104
|
|
|
102
105
|
const feature = defineFeature("cascade", (r) => {
|
|
103
106
|
r.entity("department", departmentEntity);
|
|
@@ -219,10 +222,10 @@ describe("cascade delete: cascade", () => {
|
|
|
219
222
|
const user = await userExecutor.create({ name: "Cascade User" }, admin, tdb);
|
|
220
223
|
if (!user.isSuccess) throw new Error("Setup failed");
|
|
221
224
|
|
|
222
|
-
await sessionExecutor.create({ userId: user.data.id, token: "abc" }, admin, tdb);
|
|
223
|
-
await sessionExecutor.create({ userId: user.data.id, token: "def" }, admin, tdb);
|
|
225
|
+
const s1 = await sessionExecutor.create({ userId: user.data.id, token: "abc" }, admin, tdb);
|
|
226
|
+
const s2 = await sessionExecutor.create({ userId: user.data.id, token: "def" }, admin, tdb);
|
|
227
|
+
if (!s1.isSuccess || !s2.isSuccess) throw new Error("Setup failed");
|
|
224
228
|
|
|
225
|
-
// Verify sessions exist
|
|
226
229
|
const before = await sessionExecutor.list({}, admin, tdb);
|
|
227
230
|
const sessionsBefore = before.rows.filter((r) => r["userId"] === user.data.id);
|
|
228
231
|
expect(sessionsBefore.length).toBe(2);
|
|
@@ -15,11 +15,12 @@
|
|
|
15
15
|
// The active propagation into cascaded writes is covered by
|
|
16
16
|
// msp-multi-hop.integration.ts.
|
|
17
17
|
|
|
18
|
-
import { afterAll, afterEach, beforeAll, describe, expect, test } from "
|
|
18
|
+
import { afterAll, afterEach, beforeAll, describe, expect, test } from "bun:test";
|
|
19
19
|
import { z } from "zod";
|
|
20
20
|
import { requestContext } from "../../api/request-context";
|
|
21
21
|
import { createEventStoreExecutor } from "../../db/event-store-executor";
|
|
22
|
-
import {
|
|
22
|
+
import { selectMany } from "../../db/query";
|
|
23
|
+
import { buildEntityTable } from "../../db/table-builder";
|
|
23
24
|
import { createEntity, createTextField, defineFeature } from "../../engine";
|
|
24
25
|
import { eventsTable } from "../../event-store";
|
|
25
26
|
import {
|
|
@@ -39,7 +40,7 @@ const orderEntity = createEntity({
|
|
|
39
40
|
},
|
|
40
41
|
});
|
|
41
42
|
|
|
42
|
-
const orderTable =
|
|
43
|
+
const orderTable = buildEntityTable("causation-order", orderEntity);
|
|
43
44
|
|
|
44
45
|
// MSP-apply observation sink — every apply run pushes its reqCtx snapshot
|
|
45
46
|
// here so the tests can assert what the event-dispatcher wrapped it with.
|
|
@@ -85,7 +86,7 @@ const causationFeature = defineFeature("causation", (r) => {
|
|
|
85
86
|
[placed.name]: async (event) => {
|
|
86
87
|
const ctx = requestContext.get();
|
|
87
88
|
applyObservations.push({
|
|
88
|
-
forEventId: String(event
|
|
89
|
+
forEventId: String(event["id"]),
|
|
89
90
|
correlationId: ctx?.correlationId,
|
|
90
91
|
causationId: ctx?.causationId,
|
|
91
92
|
});
|
|
@@ -118,11 +119,9 @@ afterEach(async () => {
|
|
|
118
119
|
|
|
119
120
|
// --- Helpers ---
|
|
120
121
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const rows = await stack.db.select().from(eventsTable);
|
|
125
|
-
return rows.filter((r) => r.type === type);
|
|
122
|
+
async function eventsByType(type: string) {
|
|
123
|
+
const rows = await selectMany(stack.db, eventsTable);
|
|
124
|
+
return rows.filter((r: Record<string, unknown>) => r["type"] === type);
|
|
126
125
|
}
|
|
127
126
|
|
|
128
127
|
// --- Tests ---
|
|
@@ -133,7 +132,7 @@ describe("Runde 2 — correlationId on root HTTP request", () => {
|
|
|
133
132
|
|
|
134
133
|
const [placedEvent] = await eventsByType("causation:event:placed");
|
|
135
134
|
expect(placedEvent).toBeDefined();
|
|
136
|
-
const meta = placedEvent?.metadata as {
|
|
135
|
+
const meta = placedEvent?.["metadata"] as {
|
|
137
136
|
requestId?: string;
|
|
138
137
|
correlationId?: string;
|
|
139
138
|
causationId?: string;
|
|
@@ -159,10 +158,10 @@ describe("Runde 2 — correlationId on root HTTP request", () => {
|
|
|
159
158
|
const crudEvent = (await eventsByType("causation-order.created"))[0];
|
|
160
159
|
const placedEvent = (await eventsByType("causation:event:placed"))[0];
|
|
161
160
|
|
|
162
|
-
expect((crudEvent?.metadata as { correlationId?: string })?.correlationId).toBe(
|
|
161
|
+
expect((crudEvent?.["metadata"] as { correlationId?: string })?.correlationId).toBe(
|
|
163
162
|
"test-chain-abc123",
|
|
164
163
|
);
|
|
165
|
-
expect((placedEvent?.metadata as { correlationId?: string })?.correlationId).toBe(
|
|
164
|
+
expect((placedEvent?.["metadata"] as { correlationId?: string })?.correlationId).toBe(
|
|
166
165
|
"test-chain-abc123",
|
|
167
166
|
);
|
|
168
167
|
});
|
|
@@ -192,7 +191,7 @@ describe("Runde 2 — event-dispatcher propagates correlation + causation to MSP
|
|
|
192
191
|
// should have seen as causationId.
|
|
193
192
|
const [placedEvent] = await eventsByType("causation:event:placed");
|
|
194
193
|
expect(placedEvent).toBeDefined();
|
|
195
|
-
const placedId = String(placedEvent?.id);
|
|
194
|
+
const placedId = String(placedEvent?.["id"]);
|
|
196
195
|
|
|
197
196
|
// Observation recorded inside the MSP apply.
|
|
198
197
|
expect(applyObservations).toHaveLength(1);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "
|
|
1
|
+
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { createEventStoreExecutor } from "../../db/event-store-executor";
|
|
4
|
-
import {
|
|
4
|
+
import { asRawClient, selectMany } from "../../db/query";
|
|
5
|
+
import { buildEntityTable } from "../../db/table-builder";
|
|
5
6
|
import {
|
|
6
7
|
access,
|
|
7
8
|
createEntity,
|
|
@@ -27,7 +28,7 @@ const bagEntity = createEntity({
|
|
|
27
28
|
counter: createNumberField({ default: 0 }),
|
|
28
29
|
},
|
|
29
30
|
});
|
|
30
|
-
const bagTable =
|
|
31
|
+
const bagTable = buildEntityTable("bag", bagEntity);
|
|
31
32
|
|
|
32
33
|
// secret has a system-only read field — proves queryAs(system) reads it,
|
|
33
34
|
// plain query doesn't.
|
|
@@ -41,7 +42,7 @@ const secretEntity = createEntity({
|
|
|
41
42
|
}),
|
|
42
43
|
},
|
|
43
44
|
});
|
|
44
|
-
const secretTable =
|
|
45
|
+
const secretTable = buildEntityTable("secret", secretEntity);
|
|
45
46
|
|
|
46
47
|
let stack: TestStack;
|
|
47
48
|
const admin = TestUsers.admin;
|
|
@@ -76,7 +77,7 @@ const bridgeFeature = defineFeature("ctxbridge", (r) => {
|
|
|
76
77
|
"secret:by-owner",
|
|
77
78
|
z.object({ owner: z.string() }),
|
|
78
79
|
async (query, ctx) => {
|
|
79
|
-
const rows = await ctx.db
|
|
80
|
+
const rows = await selectMany(ctx.db, secretTable);
|
|
80
81
|
return (
|
|
81
82
|
(rows as Array<Record<string, unknown>>).find((r) => r["owner"] === query.payload.owner) ??
|
|
82
83
|
null
|
|
@@ -154,8 +155,8 @@ afterAll(async () => {
|
|
|
154
155
|
|
|
155
156
|
beforeEach(async () => {
|
|
156
157
|
afterCommitLog.length = 0;
|
|
157
|
-
await stack.db.
|
|
158
|
-
await stack.db.
|
|
158
|
+
await asRawClient(stack.db).unsafe(`DELETE FROM "${bagTable.tableName}"`);
|
|
159
|
+
await asRawClient(stack.db).unsafe(`DELETE FROM "${secretTable.tableName}"`);
|
|
159
160
|
// Clear the event-dedup cache — tests re-use entity ids (Postgres sequences
|
|
160
161
|
// reset, each test sees id=1). Without flushing Redis the second test hits
|
|
161
162
|
// a dedup hit on the same handler:id:version:phase key and the hook is
|
|
@@ -195,8 +196,8 @@ describe("ctx.writeAs shares the outer transaction", () => {
|
|
|
195
196
|
expect(body.isSuccess).toBe(false);
|
|
196
197
|
|
|
197
198
|
// Both tables empty — outer bag + inner secret rolled back together
|
|
198
|
-
const bags = await stack.db
|
|
199
|
-
const secrets = await stack.db
|
|
199
|
+
const bags = await selectMany(stack.db, bagTable);
|
|
200
|
+
const secrets = await selectMany(stack.db, secretTable);
|
|
200
201
|
expect(bags).toHaveLength(0);
|
|
201
202
|
expect(secrets).toHaveLength(0);
|
|
202
203
|
});
|
|
@@ -209,8 +210,8 @@ describe("ctx.writeAs shares the outer transaction", () => {
|
|
|
209
210
|
);
|
|
210
211
|
expect((await res.json()).isSuccess).toBe(true);
|
|
211
212
|
|
|
212
|
-
const bags = await stack.db
|
|
213
|
-
const secrets = await stack.db
|
|
213
|
+
const bags = await selectMany(stack.db, bagTable);
|
|
214
|
+
const secrets = await selectMany(stack.db, secretTable);
|
|
214
215
|
expect(bags).toHaveLength(1);
|
|
215
216
|
expect(secrets).toHaveLength(1);
|
|
216
217
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, expect, test } from "
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { createEntity, createRegistry, createTextField, defineFeature } from "../../engine";
|
|
4
4
|
import type { TenantId } from "../../engine/types/identifiers";
|
|
@@ -97,7 +97,7 @@ describe("dispatcher.write", () => {
|
|
|
97
97
|
const res = await dispatcher.write("alias:write:item:create", { name: "x" }, user);
|
|
98
98
|
expect(res.isSuccess).toBe(true);
|
|
99
99
|
expect(captured.fromCtx).toBe(captured.fromEvent);
|
|
100
|
-
expect((captured.fromCtx as { id:
|
|
100
|
+
expect((captured.fromCtx as { id: unknown }).id).toBe(user.id);
|
|
101
101
|
});
|
|
102
102
|
|
|
103
103
|
test("runs validation hooks", async () => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { afterAll, beforeAll, describe, expect, test } from "
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
2
2
|
import { createTestRedis, type TestRedis } from "../../stack";
|
|
3
3
|
import { createDistributedLock } from "../distributed-lock";
|
|
4
4
|
|
|
@@ -9,9 +9,7 @@
|
|
|
9
9
|
// Without all three pieces wired together (registry opens defineEvent names,
|
|
10
10
|
// projections-runner fires on appendEvent, dispatcher routes appendEvent to
|
|
11
11
|
// the aggregate stream), any of the assertions below go red.
|
|
12
|
-
|
|
13
|
-
import { eq } from "drizzle-orm";
|
|
14
|
-
import { afterAll, afterEach, beforeAll, describe, expect, test } from "vitest";
|
|
12
|
+
import { afterAll, afterEach, beforeAll, describe, expect, test } from "bun:test";
|
|
15
13
|
import { z } from "zod";
|
|
16
14
|
import {
|
|
17
15
|
integer as pgInteger,
|
|
@@ -20,7 +18,8 @@ import {
|
|
|
20
18
|
uuid as pgUuid,
|
|
21
19
|
} from "../../db/dialect";
|
|
22
20
|
import { createEventStoreExecutor } from "../../db/event-store-executor";
|
|
23
|
-
import {
|
|
21
|
+
import { insertOne, selectMany, updateMany } from "../../db/query";
|
|
22
|
+
import { buildEntityTable } from "../../db/table-builder";
|
|
24
23
|
import { createEntity, createTextField, defineFeature } from "../../engine";
|
|
25
24
|
import { loadAggregate } from "../../event-store";
|
|
26
25
|
import {
|
|
@@ -41,7 +40,7 @@ const shipmentEntity = createEntity({
|
|
|
41
40
|
},
|
|
42
41
|
});
|
|
43
42
|
|
|
44
|
-
const shipmentTable =
|
|
43
|
+
const shipmentTable = buildEntityTable("domain-shipment", shipmentEntity);
|
|
45
44
|
|
|
46
45
|
// --- Read-model table (fed by the projection below) ---
|
|
47
46
|
|
|
@@ -69,7 +68,7 @@ const shippingFeature = defineFeature("shipping", (r) => {
|
|
|
69
68
|
// Auto CRUD event — fires on shipment create.
|
|
70
69
|
"domain-shipment.created": async (event, tx) => {
|
|
71
70
|
const payload = event.payload as { cargo?: string };
|
|
72
|
-
await tx
|
|
71
|
+
await insertOne(tx, billingTable, {
|
|
73
72
|
shipmentId: event.aggregateId,
|
|
74
73
|
tenantId: event.tenantId,
|
|
75
74
|
cargo: payload.cargo ?? "",
|
|
@@ -82,10 +81,12 @@ const shippingFeature = defineFeature("shipping", (r) => {
|
|
|
82
81
|
// create-apply just inserted.
|
|
83
82
|
[shipmentBilled.name]: async (event, tx) => {
|
|
84
83
|
const payload = event.payload as { cost: number };
|
|
85
|
-
await
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
.
|
|
84
|
+
await updateMany(
|
|
85
|
+
tx,
|
|
86
|
+
billingTable,
|
|
87
|
+
{ totalCost: payload.cost, billedMarker: "billed" },
|
|
88
|
+
{ shipmentId: event.aggregateId },
|
|
89
|
+
);
|
|
89
90
|
},
|
|
90
91
|
},
|
|
91
92
|
});
|
|
@@ -196,7 +197,7 @@ describe("Marten gold-standard: domain events → inline projections", () => {
|
|
|
196
197
|
admin,
|
|
197
198
|
);
|
|
198
199
|
|
|
199
|
-
const rows = await stack.db
|
|
200
|
+
const rows = await selectMany(stack.db, billingTable);
|
|
200
201
|
expect(rows).toHaveLength(1);
|
|
201
202
|
expect(rows[0]?.shipmentId).toBe(data.id);
|
|
202
203
|
expect(rows[0]?.billedMarker).toBe("pending");
|
|
@@ -212,10 +213,7 @@ describe("Marten gold-standard: domain events → inline projections", () => {
|
|
|
212
213
|
|
|
213
214
|
await stack.http.writeOk("shipping:write:shipment:bill", { id: created.id, cost: 1500 }, admin);
|
|
214
215
|
|
|
215
|
-
const [row] = await stack.db
|
|
216
|
-
.select()
|
|
217
|
-
.from(billingTable)
|
|
218
|
-
.where(eq(billingTable.shipmentId, created.id));
|
|
216
|
+
const [row] = await selectMany(stack.db, billingTable, { shipmentId: created.id });
|
|
219
217
|
expect(row).toBeDefined();
|
|
220
218
|
expect(row?.billedMarker).toBe("billed");
|
|
221
219
|
expect(row?.totalCost).toBe(1500);
|
package/src/pipeline/__tests__/{event-dedup.integration.ts → event-dedup.integration.test.ts}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "
|
|
1
|
+
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { createEventStoreExecutor } from "../../db/event-store-executor";
|
|
4
4
|
import { defineFeature, type SaveContext } from "../../engine";
|