@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
|
@@ -10,10 +10,9 @@
|
|
|
10
10
|
// it hits the events-table. Mismatches throw ValidationError.
|
|
11
11
|
// 3. r.defineEvent returns `{ name: qualifiedName, schema }` — callers
|
|
12
12
|
// pass `def.name` to ctx.appendEvent without building the qn manually.
|
|
13
|
-
|
|
14
|
-
import { eq } from "drizzle-orm";
|
|
15
|
-
import { afterEach, beforeAll, describe, expect, test } from "vitest";
|
|
13
|
+
import { afterEach, beforeAll, describe, expect, test } from "bun:test";
|
|
16
14
|
import { z } from "zod";
|
|
15
|
+
import { selectMany } from "../../db/query";
|
|
17
16
|
import { defineFeature } from "../../engine";
|
|
18
17
|
import { eventsTable } from "../../event-store";
|
|
19
18
|
import {
|
|
@@ -146,10 +145,7 @@ describe("E.3 — ctx.appendEvent strict validation", () => {
|
|
|
146
145
|
);
|
|
147
146
|
expect(res.status).toBe(200);
|
|
148
147
|
|
|
149
|
-
const stored = await stack.db
|
|
150
|
-
.select()
|
|
151
|
-
.from(eventsTable)
|
|
152
|
-
.where(eq(eventsTable.type, welcomeEventName));
|
|
148
|
+
const stored = await selectMany(stack.db, eventsTable, { type: welcomeEventName });
|
|
153
149
|
expect(stored).toHaveLength(1);
|
|
154
150
|
expect(stored[0]?.payload).toEqual({ userId, email: "welcome@test.de" });
|
|
155
151
|
expect(stored[0]?.aggregateType).toBe("user");
|
|
@@ -164,7 +160,7 @@ describe("E.3 — ctx.appendEvent strict validation", () => {
|
|
|
164
160
|
// Non-Kumiko throw inside a handler → wrapped as InternalError → 500.
|
|
165
161
|
expect(res.status).toBe(500);
|
|
166
162
|
|
|
167
|
-
const stored = await stack.db
|
|
163
|
+
const stored = await selectMany(stack.db, eventsTable);
|
|
168
164
|
// TX rolled back: no event landed.
|
|
169
165
|
expect(stored).toHaveLength(0);
|
|
170
166
|
});
|
|
@@ -175,10 +171,7 @@ describe("E.3 — ctx.appendEvent strict validation", () => {
|
|
|
175
171
|
// ValidationError is a first-class Kumiko error → 400.
|
|
176
172
|
expect(res.status).toBe(400);
|
|
177
173
|
|
|
178
|
-
const stored = await stack.db
|
|
179
|
-
.select()
|
|
180
|
-
.from(eventsTable)
|
|
181
|
-
.where(eq(eventsTable.type, welcomeEventName));
|
|
174
|
+
const stored = await selectMany(stack.db, eventsTable, { type: welcomeEventName });
|
|
182
175
|
expect(stored).toHaveLength(0);
|
|
183
176
|
});
|
|
184
177
|
});
|
|
@@ -193,10 +186,7 @@ describe("E.3 — cross-feature ownership guard", () => {
|
|
|
193
186
|
const res = await stack.http.write("emitter:write:emit:foreign-event", { userId }, admin);
|
|
194
187
|
expect(res.status).toBe(500);
|
|
195
188
|
|
|
196
|
-
const stored = await stack.db
|
|
197
|
-
.select()
|
|
198
|
-
.from(eventsTable)
|
|
199
|
-
.where(eq(eventsTable.type, foreignEventName));
|
|
189
|
+
const stored = await selectMany(stack.db, eventsTable, { type: foreignEventName });
|
|
200
190
|
expect(stored).toHaveLength(0);
|
|
201
191
|
});
|
|
202
192
|
});
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// via payload, not via a wrapped DB handle. Tenant-isolation-via-MSP is
|
|
13
13
|
// tested in multi-stream-projection.integration.ts.
|
|
14
14
|
|
|
15
|
-
import { afterEach, beforeAll, describe, expect, test } from "
|
|
15
|
+
import { afterEach, beforeAll, describe, expect, test } from "bun:test";
|
|
16
16
|
import { createEventStoreExecutor } from "../../db/event-store-executor";
|
|
17
17
|
import { createTenantDb, type TenantDb } from "../../db/tenant-db";
|
|
18
18
|
import { defineFeature } from "../../engine";
|
|
@@ -18,8 +18,9 @@
|
|
|
18
18
|
// single-instance runs. Any regression in the locking strategy shows up
|
|
19
19
|
// here first.
|
|
20
20
|
|
|
21
|
-
import { afterEach, beforeAll, describe, expect, test } from "
|
|
21
|
+
import { afterEach, beforeAll, describe, expect, test } from "bun:test";
|
|
22
22
|
import { createEventStoreExecutor } from "../../db/event-store-executor";
|
|
23
|
+
import { insertMany } from "../../db/query";
|
|
23
24
|
import { createTenantDb, type TenantDb } from "../../db/tenant-db";
|
|
24
25
|
import { defineFeature } from "../../engine";
|
|
25
26
|
import { eventsTable, type StoredEvent } from "../../event-store";
|
|
@@ -91,7 +92,7 @@ async function bulkSeedWidgetCreated(count: number, namePrefix: string): Promise
|
|
|
91
92
|
metadata: { userId: admin.id },
|
|
92
93
|
createdBy: admin.id,
|
|
93
94
|
}));
|
|
94
|
-
await stack.db
|
|
95
|
+
await insertMany(stack.db, eventsTable, rows);
|
|
95
96
|
}
|
|
96
97
|
|
|
97
98
|
function buildDispatcherWith(consumers: readonly EventConsumer[]): EventDispatcher {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// 2. The dispatcher starts cleanly when pgClient is wired and stops
|
|
12
12
|
// without leaking the LISTEN connection.
|
|
13
13
|
|
|
14
|
-
import { afterAll, beforeAll, describe, expect, test } from "
|
|
14
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
15
15
|
import { createEventStoreExecutor } from "../../db/event-store-executor";
|
|
16
16
|
import { createTenantDb, type TenantDb } from "../../db/tenant-db";
|
|
17
17
|
import { defineFeature } from "../../engine";
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// will never succeed (broken payload, removed code).
|
|
15
15
|
// (list/status are read-only; covered by event-dispatcher wiring tests.)
|
|
16
16
|
|
|
17
|
-
import { afterEach, beforeAll, describe, expect, test } from "
|
|
17
|
+
import { afterEach, beforeAll, describe, expect, test } from "bun:test";
|
|
18
18
|
import { createEventStoreExecutor } from "../../db/event-store-executor";
|
|
19
19
|
import { createTenantDb, type TenantDb } from "../../db/tenant-db";
|
|
20
20
|
import { defineFeature } from "../../engine";
|
|
@@ -110,7 +110,7 @@ describe("E.9 — restartConsumer", () => {
|
|
|
110
110
|
expect(after.attempts).toBe(0);
|
|
111
111
|
expect(after.lastError).toBeNull();
|
|
112
112
|
// Cursor unchanged — next pass retries the SAME failing event.
|
|
113
|
-
expect(after.lastProcessedEventId).toBe(cursorBefore);
|
|
113
|
+
expect(after.lastProcessedEventId).toBe(cursorBefore!);
|
|
114
114
|
|
|
115
115
|
// Retry still poisoned (handler still throws) — attempts climbs again.
|
|
116
116
|
await stack.eventDispatcher?.runOnce();
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
// moment delivery latency regresses from TCP-round-trip to
|
|
15
15
|
// pollIntervalMs.
|
|
16
16
|
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
17
|
+
import { afterEach, beforeAll, describe, expect, test } from "bun:test";
|
|
18
|
+
import { asRawClient, insertOne, selectMany, updateMany } from "../../db/query";
|
|
19
19
|
import { defineFeature } from "../../engine";
|
|
20
20
|
import { eventsTable } from "../../event-store";
|
|
21
21
|
import {
|
|
@@ -70,7 +70,7 @@ afterEach(async () => {
|
|
|
70
70
|
});
|
|
71
71
|
|
|
72
72
|
async function seedOldWidgetEvent(createdAt: Temporal.Instant): Promise<void> {
|
|
73
|
-
await stack.db
|
|
73
|
+
await insertOne(stack.db, eventsTable, {
|
|
74
74
|
aggregateId: generateId(),
|
|
75
75
|
aggregateType: "widget",
|
|
76
76
|
tenantId: admin.tenantId,
|
|
@@ -94,7 +94,7 @@ describe("Second audit — consumer pre-registration on start()", () => {
|
|
|
94
94
|
// every consumer at cursor=0, refuses to prune past them.
|
|
95
95
|
await stack.eventDispatcher?.start();
|
|
96
96
|
try {
|
|
97
|
-
const rows = await stack.db
|
|
97
|
+
const rows = await selectMany(stack.db, eventConsumerStateTable);
|
|
98
98
|
const names = new Set(rows.map((r) => r.name));
|
|
99
99
|
|
|
100
100
|
// The test-stack wires only feature MSP consumers (systemHooks: []),
|
|
@@ -138,17 +138,18 @@ describe("Second audit — consumer pre-registration on start()", () => {
|
|
|
138
138
|
|
|
139
139
|
// Advance the cursor explicitly so we can prove the second start
|
|
140
140
|
// doesn't clobber it back to 0.
|
|
141
|
-
await
|
|
142
|
-
.
|
|
143
|
-
|
|
144
|
-
|
|
141
|
+
await updateMany(
|
|
142
|
+
stack.db,
|
|
143
|
+
eventConsumerStateTable,
|
|
144
|
+
{ lastProcessedEventId: 42n },
|
|
145
|
+
{ name: "audit:projection:default-scope" },
|
|
146
|
+
);
|
|
145
147
|
|
|
146
148
|
await stack.eventDispatcher?.start();
|
|
147
149
|
try {
|
|
148
|
-
const [row] = await stack.db
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
.where(eq(eventConsumerStateTable.name, "audit:projection:default-scope"));
|
|
150
|
+
const [row] = await selectMany(stack.db, eventConsumerStateTable, {
|
|
151
|
+
name: "audit:projection:default-scope",
|
|
152
|
+
});
|
|
152
153
|
expect(row?.lastProcessedEventId).toBe(42n);
|
|
153
154
|
} finally {
|
|
154
155
|
await stack.eventDispatcher?.stop();
|
|
@@ -255,13 +256,13 @@ describe("Second audit — LISTEN gauge", () => {
|
|
|
255
256
|
// `LISTEN "kumiko_events_new"` and is now idle. pg_terminate_backend
|
|
256
257
|
// on it closes the TCP; postgres.js's onclose handler re-subscribes
|
|
257
258
|
// and fires onlisten again.
|
|
258
|
-
await
|
|
259
|
-
|
|
259
|
+
await asRawClient(
|
|
260
|
+
recStack.db,
|
|
261
|
+
).unsafe(`SELECT pg_terminate_backend(pid) FROM pg_stat_activity
|
|
260
262
|
WHERE datname = current_database()
|
|
261
263
|
AND query ILIKE 'listen%'
|
|
262
264
|
AND state = 'idle'
|
|
263
|
-
AND pid <> pg_backend_pid()
|
|
264
|
-
);
|
|
265
|
+
AND pid <> pg_backend_pid()`);
|
|
265
266
|
|
|
266
267
|
// Wait for the SECOND gauge.set(1) — the reconnect. Generous timeout
|
|
267
268
|
// because postgres.js's reconnect loop includes backoff.
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// Unit-level because the check happens before any DB call — no pgClient,
|
|
9
9
|
// no event-store schema, no setupTestStack needed.
|
|
10
10
|
|
|
11
|
-
import { describe, expect, test } from "
|
|
11
|
+
import { describe, expect, test } from "bun:test";
|
|
12
12
|
import type { AppContext, Registry } from "../../engine/types";
|
|
13
13
|
import { createEventDispatcher, type EventConsumer } from "../event-dispatcher";
|
|
14
14
|
|
|
@@ -35,18 +35,20 @@ describe("event-dispatcher — strict runOnce precondition", () => {
|
|
|
35
35
|
test("ensureRegistered() is a valid alternative to start() — runOnce no longer throws", async () => {
|
|
36
36
|
const consumers: EventConsumer[] = [{ name: "noop", handler: async () => {} }];
|
|
37
37
|
let insertCalls = 0;
|
|
38
|
+
// bun-db path: dispatcher uses db/queries/ for transition guard + transaction().
|
|
39
|
+
// INSERT/SELECT/UPDATE. Match by SQL substring so we count INSERTs and
|
|
40
|
+
// hand back empty rows for SELECT.
|
|
41
|
+
const unsafe = async (sqlText: string): Promise<unknown[]> => {
|
|
42
|
+
if (/INSERT INTO "kumiko_event_consumers"/.test(sqlText)) {
|
|
43
|
+
insertCalls += 1;
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
return [];
|
|
47
|
+
};
|
|
38
48
|
const stubDb = {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
transaction: async (fn: (tx: unknown) => Promise<unknown>) =>
|
|
43
|
-
fn({
|
|
44
|
-
select: () => ({
|
|
45
|
-
from: () => ({ where: () => ({ for: () => [] }) }),
|
|
46
|
-
}),
|
|
47
|
-
execute: async () => [],
|
|
48
|
-
update: () => ({ set: () => ({ where: () => Promise.resolve() }) }),
|
|
49
|
-
}),
|
|
49
|
+
unsafe,
|
|
50
|
+
begin: async (fn: (tx: unknown) => Promise<unknown>) => fn(stubDb),
|
|
51
|
+
transaction: async (fn: (tx: unknown) => Promise<unknown>) => fn(stubDb),
|
|
50
52
|
};
|
|
51
53
|
const dispatcher = createEventDispatcher({
|
|
52
54
|
db: stubDb as never,
|
|
@@ -13,14 +13,10 @@
|
|
|
13
13
|
// production would take once ops wires CreateApp. No createEventDispatcher
|
|
14
14
|
// calls in the test — only the registry round-trip.
|
|
15
15
|
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
integer as drizzleInteger,
|
|
20
|
-
table as drizzlePgTable,
|
|
21
|
-
uuid as drizzleUuid,
|
|
22
|
-
} from "../../db/dialect";
|
|
16
|
+
import { afterEach, beforeAll, describe, expect, test } from "bun:test";
|
|
17
|
+
import { integer, table as pgTable, uuid } from "../../db/dialect";
|
|
23
18
|
import { createEventStoreExecutor } from "../../db/event-store-executor";
|
|
19
|
+
import { selectMany } from "../../db/query";
|
|
24
20
|
import { createTenantDb, type TenantDb } from "../../db/tenant-db";
|
|
25
21
|
import { defineFeature, type FeatureDefinition } from "../../engine";
|
|
26
22
|
import type { StoredEvent } from "../../event-store";
|
|
@@ -40,10 +36,10 @@ import { sharedWidgetEntity, sharedWidgetTable } from "../../testing";
|
|
|
40
36
|
// A tiny state table a subscriber mutates so we can observe "the handler was
|
|
41
37
|
// called with this event" without relying on in-memory arrays — the state row
|
|
42
38
|
// survives even if the test framework resets process state.
|
|
43
|
-
const subscriberLogTable =
|
|
44
|
-
id:
|
|
45
|
-
eventId:
|
|
46
|
-
eventType:
|
|
39
|
+
const subscriberLogTable = pgTable("read_dispatcher_subscriber_log", {
|
|
40
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
41
|
+
eventId: integer("event_id").notNull(),
|
|
42
|
+
eventType: uuid("event_type"), // unused, kept to avoid another drizzle type import
|
|
47
43
|
});
|
|
48
44
|
|
|
49
45
|
// Per-test capture. The subscriber handlers push here; beforeEach resets.
|
|
@@ -195,10 +191,7 @@ describe("event-dispatcher — isolation between consumers", () => {
|
|
|
195
191
|
// the per-consumer transaction boundary holds.
|
|
196
192
|
// Pre-registered state rows exist from boot (strict Sprint-E mode) — at
|
|
197
193
|
// this point they're at cursor=0 / status=idle for both observers.
|
|
198
|
-
const state = await stack.db
|
|
199
|
-
.select()
|
|
200
|
-
.from(eventConsumerStateTable)
|
|
201
|
-
.where(sql`${eventConsumerStateTable.name} = ${qnA}`);
|
|
194
|
+
const state = await selectMany(stack.db, eventConsumerStateTable, { name: qnA });
|
|
202
195
|
expect(state).toHaveLength(1);
|
|
203
196
|
expect(state[0]?.lastProcessedEventId).toBe(0n);
|
|
204
197
|
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
// 4. olderThanDays / olderThan convenience: both resolve to the same
|
|
11
11
|
// cutoff semantics (createdAt < cutoff).
|
|
12
12
|
|
|
13
|
-
import {
|
|
14
|
-
import { afterEach, beforeAll, describe, expect, test } from "vitest";
|
|
13
|
+
import { afterEach, beforeAll, describe, expect, test } from "bun:test";
|
|
15
14
|
import { createEventStoreExecutor } from "../../db/event-store-executor";
|
|
15
|
+
import { asRawClient, insertOne, selectMany, updateMany } from "../../db/query";
|
|
16
16
|
import { createTenantDb, type TenantDb } from "../../db/tenant-db";
|
|
17
17
|
import { defineFeature } from "../../engine";
|
|
18
18
|
import { eventsTable } from "../../event-store";
|
|
@@ -77,20 +77,17 @@ async function seedOldAggregateEvent(
|
|
|
77
77
|
type: string,
|
|
78
78
|
aggregateType = "widget",
|
|
79
79
|
): Promise<bigint> {
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
createdBy: admin.id,
|
|
92
|
-
})
|
|
93
|
-
.returning({ id: eventsTable.id });
|
|
80
|
+
const row = await insertOne<{ id: bigint }>(stack.db, eventsTable, {
|
|
81
|
+
aggregateId: generateId(),
|
|
82
|
+
aggregateType,
|
|
83
|
+
tenantId: admin.tenantId,
|
|
84
|
+
version: 1,
|
|
85
|
+
type,
|
|
86
|
+
payload: {},
|
|
87
|
+
metadata: { userId: admin.id },
|
|
88
|
+
createdAt,
|
|
89
|
+
createdBy: admin.id,
|
|
90
|
+
});
|
|
94
91
|
if (!row) throw new Error("seed failed");
|
|
95
92
|
return row.id;
|
|
96
93
|
}
|
|
@@ -121,7 +118,7 @@ describe("E.2 — explicit-aggregateTypes pruning", () => {
|
|
|
121
118
|
expect(result.deletedCount).toBe(1);
|
|
122
119
|
expect(result.aggregateTypes).toEqual(["obsolete"]);
|
|
123
120
|
|
|
124
|
-
const remaining = await stack.db
|
|
121
|
+
const remaining = await selectMany(stack.db, eventsTable);
|
|
125
122
|
const ids = remaining.map((r) => r.id);
|
|
126
123
|
expect(ids).toContain(widgetId);
|
|
127
124
|
expect(ids).not.toContain(obsoleteId);
|
|
@@ -146,7 +143,7 @@ describe("E.2 — explicit-aggregateTypes pruning", () => {
|
|
|
146
143
|
});
|
|
147
144
|
expect(result.deletedCount).toBe(1);
|
|
148
145
|
|
|
149
|
-
const remaining = await stack.db
|
|
146
|
+
const remaining = await selectMany(stack.db, eventsTable);
|
|
150
147
|
const ids = remaining.map((r) => r.id).sort();
|
|
151
148
|
expect(ids).toEqual([freshId]);
|
|
152
149
|
expect(ids.includes(staleId)).toBe(false);
|
|
@@ -165,7 +162,7 @@ describe("E.2 — explicit-aggregateTypes pruning", () => {
|
|
|
165
162
|
expect(result.deletedCount).toBe(1);
|
|
166
163
|
expect(result.dryRun).toBe(true);
|
|
167
164
|
|
|
168
|
-
const remaining = await stack.db
|
|
165
|
+
const remaining = await selectMany(stack.db, eventsTable);
|
|
169
166
|
expect(remaining).toHaveLength(1);
|
|
170
167
|
});
|
|
171
168
|
});
|
|
@@ -182,13 +179,17 @@ describe("E.2 — consumer-lag guard", () => {
|
|
|
182
179
|
// Only let the first one through.
|
|
183
180
|
await stack.eventDispatcher?.runOnce();
|
|
184
181
|
// Force cursor to 1 so the guard sees "consumer at 1, max candidate 3".
|
|
185
|
-
await
|
|
186
|
-
.
|
|
187
|
-
|
|
188
|
-
|
|
182
|
+
await updateMany(
|
|
183
|
+
stack.db,
|
|
184
|
+
eventConsumerStateTable,
|
|
185
|
+
{ lastProcessedEventId: 1n, status: "idle" },
|
|
186
|
+
{ name: observerQn },
|
|
187
|
+
);
|
|
189
188
|
|
|
190
189
|
// Age all three events past the cutoff.
|
|
191
|
-
await stack.db.
|
|
190
|
+
await asRawClient(stack.db).unsafe(
|
|
191
|
+
`UPDATE kumiko_events SET created_at = now() - interval '30 days'`,
|
|
192
|
+
);
|
|
192
193
|
|
|
193
194
|
await expect(
|
|
194
195
|
pruneEvents(stack.db, {
|
|
@@ -204,7 +205,9 @@ describe("E.2 — consumer-lag guard", () => {
|
|
|
204
205
|
await disableConsumer(stack.db, observerQn);
|
|
205
206
|
|
|
206
207
|
// Cursor is at 1 but consumer is disabled — should be skipped.
|
|
207
|
-
await stack.db.
|
|
208
|
+
await asRawClient(stack.db).unsafe(
|
|
209
|
+
`UPDATE kumiko_events SET created_at = now() - interval '30 days'`,
|
|
210
|
+
);
|
|
208
211
|
|
|
209
212
|
const result = await pruneEvents(stack.db, {
|
|
210
213
|
olderThanDays: 7,
|
|
@@ -7,11 +7,11 @@
|
|
|
7
7
|
// the stream version internally — a sequence of appendOne calls writes
|
|
8
8
|
// consecutive versions without re-reading the DB.
|
|
9
9
|
|
|
10
|
-
import {
|
|
11
|
-
import { afterAll, afterEach, beforeAll, describe, expect, test } from "vitest";
|
|
10
|
+
import { afterAll, afterEach, beforeAll, describe, expect, test } from "bun:test";
|
|
12
11
|
import { z } from "zod";
|
|
13
12
|
import { createEventStoreExecutor } from "../../db/event-store-executor";
|
|
14
|
-
import {
|
|
13
|
+
import { asRawClient } from "../../db/query-api";
|
|
14
|
+
import { buildEntityTable } from "../../db/table-builder";
|
|
15
15
|
import { createEntity, createTextField, defineFeature } from "../../engine";
|
|
16
16
|
import { UnprocessableError, writeFailure } from "../../errors";
|
|
17
17
|
import { loadAggregate } from "../../event-store";
|
|
@@ -26,7 +26,7 @@ const cartEntity = createEntity({
|
|
|
26
26
|
},
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
-
const cartTable =
|
|
29
|
+
const cartTable = buildEntityTable("f4wCart", cartEntity);
|
|
30
30
|
|
|
31
31
|
const cartFeature = defineFeature("f4w", (r) => {
|
|
32
32
|
r.entity("f4wCart", cartEntity);
|
|
@@ -144,8 +144,8 @@ afterAll(async () => {
|
|
|
144
144
|
});
|
|
145
145
|
|
|
146
146
|
afterEach(async () => {
|
|
147
|
-
await stack.db.
|
|
148
|
-
|
|
147
|
+
await asRawClient(stack.db).unsafe(
|
|
148
|
+
`TRUNCATE kumiko_events, read_f4w_carts, kumiko_event_consumers RESTART IDENTITY CASCADE`,
|
|
149
149
|
);
|
|
150
150
|
await stack.eventDispatcher?.ensureRegistered();
|
|
151
151
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, expect,
|
|
1
|
+
import { describe, expect, spyOn, test } from "bun:test";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import {
|
|
4
4
|
createEntity,
|
|
@@ -200,7 +200,7 @@ describe("runPostSave", () => {
|
|
|
200
200
|
|
|
201
201
|
test("postSave errors don't throw — logged and continued", async () => {
|
|
202
202
|
const calls: string[] = [];
|
|
203
|
-
const consoleSpy =
|
|
203
|
+
const consoleSpy = spyOn(console, "error").mockImplementation(() => {});
|
|
204
204
|
|
|
205
205
|
const registry = makeRegistry({
|
|
206
206
|
postSave: [
|
|
@@ -234,7 +234,7 @@ describe("runPostSave", () => {
|
|
|
234
234
|
|
|
235
235
|
test("system hook failure doesn't block other system hooks", async () => {
|
|
236
236
|
const calls: string[] = [];
|
|
237
|
-
const consoleSpy =
|
|
237
|
+
const consoleSpy = spyOn(console, "error").mockImplementation(() => {});
|
|
238
238
|
|
|
239
239
|
const registry = makeRegistry();
|
|
240
240
|
|
|
@@ -334,7 +334,7 @@ describe("runPostSave phase routing", () => {
|
|
|
334
334
|
});
|
|
335
335
|
|
|
336
336
|
test("afterCommit phase: hook errors are logged, never thrown", async () => {
|
|
337
|
-
const consoleSpy =
|
|
337
|
+
const consoleSpy = spyOn(console, "error").mockImplementation(() => {});
|
|
338
338
|
const afterRan: string[] = [];
|
|
339
339
|
const feature = defineFeature("phases", (r) => {
|
|
340
340
|
r.entity("user", createEntity({ table: "Users", fields: {} }));
|
|
@@ -5,11 +5,15 @@
|
|
|
5
5
|
// returned events into whatever domain-state shape the feature wants.
|
|
6
6
|
// Events are upcasted by the dispatcher, so the reducer sees the current
|
|
7
7
|
// payload shape even for old v1 events.
|
|
8
|
+
//
|
|
9
|
+
// Bun.SQL-only setup. KEIN postgres-js, KEIN setupTestStack.
|
|
8
10
|
|
|
9
|
-
import { afterAll, afterEach, beforeAll, describe, expect, test } from "
|
|
11
|
+
import { afterAll, afterEach, beforeAll, describe, expect, test } from "bun:test";
|
|
10
12
|
import { z } from "zod";
|
|
13
|
+
import type { DbConnection, DbTx } from "../../db/connection";
|
|
11
14
|
import { createEventStoreExecutor } from "../../db/event-store-executor";
|
|
12
|
-
import {
|
|
15
|
+
import { insertOne } from "../../db/query";
|
|
16
|
+
import { buildEntityTable } from "../../db/table-builder";
|
|
13
17
|
import { createEntity, createTextField, defineFeature } from "../../engine";
|
|
14
18
|
import { append, loadAggregate as loadAggregateRaw } from "../../event-store";
|
|
15
19
|
import {
|
|
@@ -29,7 +33,7 @@ const invoiceEntity = createEntity({
|
|
|
29
33
|
status: createTextField({ required: true }),
|
|
30
34
|
},
|
|
31
35
|
});
|
|
32
|
-
const invoiceTable =
|
|
36
|
+
const invoiceTable = buildEntityTable("asof-invoice", invoiceEntity);
|
|
33
37
|
|
|
34
38
|
// --- Feature ---
|
|
35
39
|
|
|
@@ -214,8 +218,8 @@ describe("ctx.loadAggregate via queryHandler — Marten AggregateStreamAsync equ
|
|
|
214
218
|
// against v2 (integer cents) — without upcasting it would blow up or
|
|
215
219
|
// produce garbage.
|
|
216
220
|
const invoiceId = "00000000-0000-4000-8000-000000000042";
|
|
217
|
-
await stack.db.
|
|
218
|
-
await tx
|
|
221
|
+
await (stack.db as DbConnection).begin(async (tx: DbTx) => {
|
|
222
|
+
await insertOne(tx, invoiceTable, {
|
|
219
223
|
id: invoiceId,
|
|
220
224
|
tenantId: admin.tenantId,
|
|
221
225
|
customer: "LegacyCo",
|
package/src/pipeline/__tests__/{msp-error-mode.integration.ts → msp-error-mode.integration.test.ts}
RENAMED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// error on the skip counter, advances the cursor, and keeps delivering. The
|
|
10
10
|
// consumer stays "idle".
|
|
11
11
|
|
|
12
|
-
import { afterAll, afterEach, beforeAll, describe, expect, test } from "
|
|
12
|
+
import { afterAll, afterEach, beforeAll, describe, expect, test } from "bun:test";
|
|
13
13
|
import { createEventStoreExecutor } from "../../db/event-store-executor";
|
|
14
14
|
import { createTenantDb, type TenantDb } from "../../db/tenant-db";
|
|
15
15
|
import { defineFeature } from "../../engine";
|
package/src/pipeline/__tests__/{msp-multi-hop.integration.ts → msp-multi-hop.integration.test.ts}
RENAMED
|
@@ -10,10 +10,11 @@
|
|
|
10
10
|
// a three-hop causal chain (order.placed → order.confirmed → order.shipped).
|
|
11
11
|
// 5. ctx.loadAggregate reads the triggering stream's full history.
|
|
12
12
|
|
|
13
|
-
import { afterAll, afterEach, beforeAll, describe, expect, test } from "
|
|
13
|
+
import { afterAll, afterEach, beforeAll, describe, expect, test } from "bun:test";
|
|
14
14
|
import { z } from "zod";
|
|
15
15
|
import { createEventStoreExecutor } from "../../db/event-store-executor";
|
|
16
|
-
import {
|
|
16
|
+
import { selectMany } from "../../db/query";
|
|
17
|
+
import { buildEntityTable } from "../../db/table-builder";
|
|
17
18
|
import { createEntity, createTextField, defineFeature } from "../../engine";
|
|
18
19
|
import { eventsTable } from "../../event-store";
|
|
19
20
|
import {
|
|
@@ -33,7 +34,7 @@ const orderEntity = createEntity({
|
|
|
33
34
|
},
|
|
34
35
|
});
|
|
35
36
|
|
|
36
|
-
const orderTable =
|
|
37
|
+
const orderTable = buildEntityTable("mmh-order", orderEntity);
|
|
37
38
|
|
|
38
39
|
// Snapshot what each MSP-apply observed via ctx.loadAggregate.
|
|
39
40
|
const confirmLoadCounts: number[] = [];
|
|
@@ -132,7 +133,7 @@ async function postWrite(correlationId: string, item: string) {
|
|
|
132
133
|
async function drainUntilShipped(aggregateId: string, maxPasses = 10): Promise<void> {
|
|
133
134
|
for (let i = 0; i < maxPasses; i++) {
|
|
134
135
|
await stack.eventDispatcher?.runOnce();
|
|
135
|
-
const rows = await stack.db
|
|
136
|
+
const rows = await selectMany(stack.db, eventsTable);
|
|
136
137
|
if (rows.some((r) => r.aggregateId === aggregateId && r.type === "mmh:event:shipped")) return;
|
|
137
138
|
}
|
|
138
139
|
throw new Error(`drainUntilShipped: never saw shipped event for ${aggregateId}`);
|
|
@@ -147,7 +148,7 @@ describe("Runde 3 / C.2b — MSP-apply ctx cascades", () => {
|
|
|
147
148
|
|
|
148
149
|
await stack.eventDispatcher?.runOnce();
|
|
149
150
|
|
|
150
|
-
const rows = await stack.db
|
|
151
|
+
const rows = await selectMany(stack.db, eventsTable);
|
|
151
152
|
const types = rows.map((r) => r.type).sort();
|
|
152
153
|
// Order: CRUD create, placed, confirmed (hop 1 fired).
|
|
153
154
|
expect(types).toContain("mmh-order.created");
|
|
@@ -160,7 +161,7 @@ describe("Runde 3 / C.2b — MSP-apply ctx cascades", () => {
|
|
|
160
161
|
|
|
161
162
|
// Find the aggregateId from the first placed event.
|
|
162
163
|
await stack.eventDispatcher?.runOnce();
|
|
163
|
-
const placedRow = (await stack.db
|
|
164
|
+
const placedRow = (await selectMany(stack.db, eventsTable)).find(
|
|
164
165
|
(r) => r.type === "mmh:event:placed",
|
|
165
166
|
);
|
|
166
167
|
expect(placedRow).toBeDefined();
|
|
@@ -168,7 +169,7 @@ describe("Runde 3 / C.2b — MSP-apply ctx cascades", () => {
|
|
|
168
169
|
|
|
169
170
|
await drainUntilShipped(aggregateId);
|
|
170
171
|
|
|
171
|
-
const rows = (await stack.db
|
|
172
|
+
const rows = (await selectMany(stack.db, eventsTable))
|
|
172
173
|
.filter((r) => r.aggregateId === aggregateId)
|
|
173
174
|
.sort((a, b) => Number(a.id - b.id));
|
|
174
175
|
|
|
@@ -220,7 +221,7 @@ describe("Runde 3 / C.2b — MSP-apply ctx cascades", () => {
|
|
|
220
221
|
await stack.eventDispatcher?.runOnce();
|
|
221
222
|
|
|
222
223
|
// Every event written on this chain belongs to the admin's tenant.
|
|
223
|
-
const rows = await stack.db
|
|
224
|
+
const rows = await selectMany(stack.db, eventsTable);
|
|
224
225
|
for (const row of rows) {
|
|
225
226
|
expect(row.tenantId).toBe(admin.tenantId);
|
|
226
227
|
}
|