@cosmicdrift/kumiko-framework 0.14.0 → 0.16.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 +6 -6
- 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/auth-routes.ts +2 -5
- 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 +842 -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/compliance/profiles.ts +1 -4
- 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__/cursor.test.ts +8 -32
- 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__/migrate-generator.test.ts +71 -0
- package/src/db/__tests__/migrate-runner.test.ts +19 -0
- 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__/pg-error.test.ts +43 -0
- 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 +54 -46
- 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__/duration-utils.test.ts +16 -0
- 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-access.test.ts +38 -0
- 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__/no-return-guard.test.ts +17 -0
- 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__/unmanaged-table.test.ts +98 -0
- 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 +37 -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/feature-ast/extractors/shared.ts +2 -3
- 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 +21 -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 +47 -2
- package/src/engine/types/fields.ts +4 -5
- package/src/engine/types/index.ts +2 -0
- 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__/error-helpers.test.ts +44 -0
- package/src/errors/__tests__/field-issue-compat.test.ts +16 -0
- package/src/errors/__tests__/write-failures.test.ts +1 -1
- package/src/errors/classes.ts +5 -19
- package/src/errors/field-issue.ts +11 -0
- package/src/errors/index.ts +1 -0
- package/src/errors/zod-bridge.ts +3 -2
- 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 +11 -56
- 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-utils.test.ts +107 -0
- 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-keys.test.ts +12 -0
- 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-utils.ts +8 -7
- 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 +10 -9
- 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__/case.test.ts +16 -0
- package/src/utils/__tests__/env-parse.test.ts +1 -1
- package/src/utils/__tests__/is-plain-object.test.ts +16 -0
- package/src/utils/__tests__/parse-string-array-json.test.ts +16 -0
- package/src/utils/__tests__/safe-json.test.ts +22 -0
- package/src/utils/case.ts +6 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/is-plain-object.ts +4 -0
- package/src/utils/parse-string-array-json.ts +14 -0
- package/CHANGELOG.md +0 -474
- 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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-framework",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Framework core — engine, pipeline, API, DB, and every other bit that makes Kumiko go.",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
@@ -20,7 +20,6 @@
|
|
|
20
20
|
"command-based",
|
|
21
21
|
"typescript",
|
|
22
22
|
"hono",
|
|
23
|
-
"drizzle",
|
|
24
23
|
"zod"
|
|
25
24
|
],
|
|
26
25
|
"type": "module",
|
|
@@ -60,6 +59,10 @@
|
|
|
60
59
|
"types": "./src/errors/index.ts",
|
|
61
60
|
"default": "./src/errors/index.ts"
|
|
62
61
|
},
|
|
62
|
+
"./bun-db": {
|
|
63
|
+
"types": "./src/bun-db/index.ts",
|
|
64
|
+
"default": "./src/bun-db/index.ts"
|
|
65
|
+
},
|
|
63
66
|
"./db": {
|
|
64
67
|
"types": "./src/db/index.ts",
|
|
65
68
|
"default": "./src/db/index.ts"
|
|
@@ -157,8 +160,6 @@
|
|
|
157
160
|
"dependencies": {
|
|
158
161
|
"bullmq": "^5.76.7",
|
|
159
162
|
"bun-types": "^1.3.13",
|
|
160
|
-
"drizzle-kit": "^0.31.10",
|
|
161
|
-
"drizzle-orm": "^0.45.2",
|
|
162
163
|
"hono": "^4.12.18",
|
|
163
164
|
"i18next": "^26.1.0",
|
|
164
165
|
"ioredis": "^5.10.1",
|
|
@@ -175,7 +176,6 @@
|
|
|
175
176
|
"@cosmicdrift/kumiko-dispatcher-live": "0.14.0",
|
|
176
177
|
"@types/uuid": "^11.0.0",
|
|
177
178
|
"bun-types": "^1.3.13",
|
|
178
|
-
"drizzle-kit": "^0.31.10",
|
|
179
179
|
"pino-pretty": "^13.1.3"
|
|
180
180
|
},
|
|
181
181
|
"publishConfig": {
|
|
@@ -187,4 +187,4 @@
|
|
|
187
187
|
"README.md",
|
|
188
188
|
"LICENSE"
|
|
189
189
|
]
|
|
190
|
-
}
|
|
190
|
+
}
|
package/src/__tests__/{anonymous-access.integration.ts → anonymous-access.integration.test.ts}
RENAMED
|
@@ -3,11 +3,14 @@
|
|
|
3
3
|
// authentication. Covers the resolution chain (defaultTenantId, X-Tenant
|
|
4
4
|
// header, kumiko_tenant cookie, custom resolver) plus the rejection paths
|
|
5
5
|
// (no tenant, unknown tenant, openToAll-protected).
|
|
6
|
+
//
|
|
7
|
+
// Bun.SQL-only setup. KEIN postgres-js, KEIN setupTestStack.
|
|
6
8
|
|
|
7
|
-
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "
|
|
9
|
+
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
|
|
8
10
|
import { z } from "zod";
|
|
9
11
|
import { createEventStoreExecutor } from "../db/event-store-executor";
|
|
10
|
-
import {
|
|
12
|
+
import { asRawClient, selectMany } from "../db/query";
|
|
13
|
+
import { buildEntityTable } from "../db/table-builder";
|
|
11
14
|
import {
|
|
12
15
|
ANONYMOUS_USER_ID,
|
|
13
16
|
createEntity,
|
|
@@ -28,7 +31,7 @@ const productEntity = createEntity({
|
|
|
28
31
|
name: createTextField({ required: true }),
|
|
29
32
|
},
|
|
30
33
|
});
|
|
31
|
-
const productTable =
|
|
34
|
+
const productTable = buildEntityTable("product", productEntity);
|
|
32
35
|
|
|
33
36
|
const orderEntity = createEntity({
|
|
34
37
|
table: "anon_orders",
|
|
@@ -37,7 +40,7 @@ const orderEntity = createEntity({
|
|
|
37
40
|
placedBy: createTextField({ default: "" }),
|
|
38
41
|
},
|
|
39
42
|
});
|
|
40
|
-
const orderTable =
|
|
43
|
+
const orderTable = buildEntityTable("order", orderEntity);
|
|
41
44
|
|
|
42
45
|
const shopFeature = defineFeature("anonshop", (r) => {
|
|
43
46
|
r.entity("product", productEntity);
|
|
@@ -48,7 +51,7 @@ const shopFeature = defineFeature("anonshop", (r) => {
|
|
|
48
51
|
"product:list",
|
|
49
52
|
z.object({}),
|
|
50
53
|
async (_event, ctx) => {
|
|
51
|
-
const rows = await ctx.db
|
|
54
|
+
const rows = await selectMany(ctx.db, productTable);
|
|
52
55
|
return rows;
|
|
53
56
|
},
|
|
54
57
|
{ access: { roles: ["anonymous", "User", "Admin"] } },
|
|
@@ -59,7 +62,7 @@ const shopFeature = defineFeature("anonshop", (r) => {
|
|
|
59
62
|
"product:list-auth-only",
|
|
60
63
|
z.object({}),
|
|
61
64
|
async (_event, ctx) => {
|
|
62
|
-
const rows = await ctx.db
|
|
65
|
+
const rows = await selectMany(ctx.db, productTable);
|
|
63
66
|
return rows;
|
|
64
67
|
},
|
|
65
68
|
{ access: { openToAll: true } },
|
|
@@ -111,8 +114,8 @@ describe("anonymous access — single-tenant default", () => {
|
|
|
111
114
|
afterAll(() => stack.cleanup());
|
|
112
115
|
|
|
113
116
|
beforeEach(async () => {
|
|
114
|
-
await stack.db.
|
|
115
|
-
await stack.db.
|
|
117
|
+
await asRawClient(stack.db).unsafe(`DELETE FROM "${productTable.tableName}"`);
|
|
118
|
+
await asRawClient(stack.db).unsafe(`DELETE FROM "${orderTable.tableName}"`);
|
|
116
119
|
});
|
|
117
120
|
|
|
118
121
|
test("anonymous query succeeds without any auth headers", async () => {
|
|
@@ -146,7 +149,7 @@ describe("anonymous access — single-tenant default", () => {
|
|
|
146
149
|
|
|
147
150
|
// Verify the row landed with placedBy=anonymous in the DB. Confirms the
|
|
148
151
|
// synthesised SessionUser actually flows through to the handler.
|
|
149
|
-
const rows = await stack.db
|
|
152
|
+
const rows = await selectMany(stack.db, orderTable);
|
|
150
153
|
expect(rows).toHaveLength(1);
|
|
151
154
|
expect(rows[0]?.["placedBy"]).toBe(ANONYMOUS_USER_ID);
|
|
152
155
|
});
|
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
// come back with a stable code + i18nKey and the shape that the client SDK
|
|
4
4
|
// and docs promise. If you change the contract, this is the file that moves.
|
|
5
5
|
|
|
6
|
-
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "
|
|
6
|
+
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
import { createEventStoreExecutor } from "../db/event-store-executor";
|
|
9
|
-
import {
|
|
9
|
+
import { asRawClient } from "../db/query";
|
|
10
|
+
import { buildEntityTable } from "../db/table-builder";
|
|
10
11
|
import {
|
|
11
12
|
createEntity,
|
|
12
13
|
createNumberField,
|
|
@@ -38,7 +39,7 @@ const itemEntity = createEntity({
|
|
|
38
39
|
stock: createNumberField({ default: 0 }),
|
|
39
40
|
},
|
|
40
41
|
});
|
|
41
|
-
const itemTable =
|
|
42
|
+
const itemTable = buildEntityTable("item", itemEntity);
|
|
42
43
|
|
|
43
44
|
const errorFeature = defineFeature("errctr", (r) => {
|
|
44
45
|
r.entity("item", itemEntity);
|
|
@@ -192,7 +193,7 @@ beforeAll(async () => {
|
|
|
192
193
|
afterAll(async () => stack.cleanup());
|
|
193
194
|
beforeEach(async () => {
|
|
194
195
|
stack.events.reset();
|
|
195
|
-
await stack.db.
|
|
196
|
+
await asRawClient(stack.db).unsafe(`DELETE FROM "${itemTable.tableName}"`);
|
|
196
197
|
});
|
|
197
198
|
|
|
198
199
|
// --- Helpers ---
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { afterAll, beforeAll, describe, expect, test } from "
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { buildServer } from "../api/server";
|
|
4
4
|
import { createEventStoreExecutor } from "../db/event-store-executor";
|
|
5
|
-
import {
|
|
5
|
+
import { buildEntityTable } from "../db/table-builder";
|
|
6
6
|
import {
|
|
7
7
|
createEntity,
|
|
8
8
|
createNumberField,
|
|
@@ -33,7 +33,7 @@ const employeeEntity = createEntity({
|
|
|
33
33
|
},
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
-
const employeeTable =
|
|
36
|
+
const employeeTable = buildEntityTable("employee", employeeEntity);
|
|
37
37
|
|
|
38
38
|
// --- Test infra ---
|
|
39
39
|
|
|
@@ -1,6 +1,7 @@
|
|
|
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 { selectMany, updateMany } from "../db/query";
|
|
4
5
|
import { defineFeature, type EntityId, type HandlerContext, type SaveContext } from "../engine";
|
|
5
6
|
import { UnprocessableError, writeFailure } from "../errors";
|
|
6
7
|
import { eventsTable } from "../event-store";
|
|
@@ -714,11 +715,7 @@ describe("full stack: entity cache", () => {
|
|
|
714
715
|
await stack.http.queryOk("users:query:user:detail", { id }, adminUser);
|
|
715
716
|
|
|
716
717
|
// Raw DB update — bypasses cache invalidation
|
|
717
|
-
|
|
718
|
-
await stack.db
|
|
719
|
-
.update(userTable)
|
|
720
|
-
.set({ firstName: "RawDbChange" })
|
|
721
|
-
.where(eq(userTable["id"], id));
|
|
718
|
+
await updateMany(stack.db, userTable, { firstName: "RawDbChange" }, { id: id });
|
|
722
719
|
|
|
723
720
|
// Detail still returns cached (old) value
|
|
724
721
|
const stale = await stack.http.queryOk<Record<string, unknown>>(
|
|
@@ -789,16 +786,10 @@ describe("full stack: ctx.appendEvent via event-dispatcher", () => {
|
|
|
789
786
|
// events table is shared across tests so we pick out just the ones this
|
|
790
787
|
// test appended.
|
|
791
788
|
async function domainEventsForEmail(email: string) {
|
|
792
|
-
const rows = await stack.db
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
// eq + and via a lazy dynamic import keeps the top-level imports lean.
|
|
797
|
-
(await import("drizzle-orm")).and(
|
|
798
|
-
(await import("drizzle-orm")).eq(eventsTable.aggregateType, "user"),
|
|
799
|
-
(await import("drizzle-orm")).eq(eventsTable.type, USER_CREATED_EVENT),
|
|
800
|
-
),
|
|
801
|
-
);
|
|
789
|
+
const rows = await selectMany(stack.db, eventsTable, {
|
|
790
|
+
aggregateType: "user",
|
|
791
|
+
type: USER_CREATED_EVENT,
|
|
792
|
+
});
|
|
802
793
|
return rows.filter((r) => (r.payload as { email?: string }).email === email);
|
|
803
794
|
}
|
|
804
795
|
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
// entity-write, field-level) into one file with shared fixtures. Each
|
|
5
5
|
// `describe` block maps to a cell of the core-auth.md Policy-Matrix.
|
|
6
6
|
|
|
7
|
-
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "
|
|
7
|
+
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
|
|
8
|
+
import { asRawClient } from "../db/query";
|
|
8
9
|
import {
|
|
9
10
|
createEntity,
|
|
10
11
|
createTextField,
|
|
@@ -134,7 +135,7 @@ let engRow: { id: string; version: number };
|
|
|
134
135
|
let opsRow: { id: string; version: number };
|
|
135
136
|
|
|
136
137
|
beforeEach(async () => {
|
|
137
|
-
await stack.db.
|
|
138
|
+
await asRawClient(stack.db).unsafe("DELETE FROM h2_contracts");
|
|
138
139
|
const eng = await stack.http.writeOk<{ id: string; data: { version: number } }>(
|
|
139
140
|
"h2contracts:write:contract:create",
|
|
140
141
|
{
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
// INSERT/SELECT against the real DB roundtrip. Plan reference:
|
|
4
4
|
// kumiko-platform/docs/plans/architecture/table-ddl-guard.md (Stufe 3).
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
6
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
7
|
+
import { table, text, timestamp } from "../db/dialect";
|
|
8
|
+
import { asRawClient, insertOne, selectMany } from "../db/query";
|
|
9
9
|
import { defineFeature } from "../engine";
|
|
10
10
|
import { setupTestStack, type TestStack, unsafePushTables } from "../stack";
|
|
11
11
|
|
|
@@ -13,7 +13,7 @@ import { setupTestStack, type TestStack, unsafePushTables } from "../stack";
|
|
|
13
13
|
// write-only by an integration handler, read-only by a query, never
|
|
14
14
|
// event-sourced (the data isn't a domain fact, it's a side-effect
|
|
15
15
|
// snapshot).
|
|
16
|
-
const stripeWebhookCache =
|
|
16
|
+
const stripeWebhookCache = table("rt_int_stripe_webhook_cache", {
|
|
17
17
|
eventId: text("event_id").primaryKey(),
|
|
18
18
|
payload: text("payload").notNull(),
|
|
19
19
|
receivedAt: timestamp("received_at", { withTimezone: true }).notNull().defaultNow(),
|
|
@@ -22,7 +22,7 @@ const stripeWebhookCache = pgTable("rt_int_stripe_webhook_cache", {
|
|
|
22
22
|
// A second physical table reachable through two distinct r.rawTable
|
|
23
23
|
// registrations — pins the seenTables-by-reference dedupe at push time.
|
|
24
24
|
// Two logical names, one CREATE.
|
|
25
|
-
const sharedSyncCache =
|
|
25
|
+
const sharedSyncCache = table("rt_int_shared_sync_cache", {
|
|
26
26
|
syncId: text("sync_id").primaryKey(),
|
|
27
27
|
payload: text("payload").notNull(),
|
|
28
28
|
});
|
|
@@ -54,16 +54,13 @@ describe("r.rawTable — DB roundtrip via setupTestStack", () => {
|
|
|
54
54
|
const eventId = "evt_test_123";
|
|
55
55
|
const payload = JSON.stringify({ type: "invoice.paid", amount: 4200 });
|
|
56
56
|
|
|
57
|
-
await stack.db
|
|
57
|
+
await insertOne(stack.db, stripeWebhookCache, { eventId, payload });
|
|
58
58
|
|
|
59
|
-
const rows = await stack.db
|
|
60
|
-
.select()
|
|
61
|
-
.from(stripeWebhookCache)
|
|
62
|
-
.where(eq(stripeWebhookCache.eventId, eventId));
|
|
59
|
+
const rows = await selectMany(stack.db, stripeWebhookCache, { eventId: eventId });
|
|
63
60
|
|
|
64
61
|
expect(rows).toHaveLength(1);
|
|
65
62
|
expect(rows[0]?.payload).toBe(payload);
|
|
66
|
-
expect(rows[0]?.receivedAt).toBeInstanceOf(
|
|
63
|
+
expect(rows[0]?.receivedAt).toBeInstanceOf(Temporal.Instant);
|
|
67
64
|
});
|
|
68
65
|
|
|
69
66
|
test("registry exposes the raw table with its reason and featureName", () => {
|
|
@@ -80,18 +77,18 @@ describe("r.rawTable — DB roundtrip via setupTestStack", () => {
|
|
|
80
77
|
// a write to it shouldn't append anything to kumiko_events. If a
|
|
81
78
|
// future regression accidentally routed raw-table writes through
|
|
82
79
|
// the executor, a row would show up here.
|
|
83
|
-
const before = await stack.db.
|
|
84
|
-
|
|
80
|
+
const before = await asRawClient(stack.db).unsafe<{ count: string }>(
|
|
81
|
+
`SELECT COUNT(*)::text AS count FROM kumiko_events`,
|
|
85
82
|
);
|
|
86
83
|
const beforeCount = Number(before[0]?.count ?? 0);
|
|
87
84
|
|
|
88
|
-
await stack.db
|
|
85
|
+
await insertOne(stack.db, stripeWebhookCache, {
|
|
89
86
|
eventId: "evt_no_event_emitted",
|
|
90
87
|
payload: "{}",
|
|
91
88
|
});
|
|
92
89
|
|
|
93
|
-
const after = await stack.db.
|
|
94
|
-
|
|
90
|
+
const after = await asRawClient(stack.db).unsafe<{ count: string }>(
|
|
91
|
+
`SELECT COUNT(*)::text AS count FROM kumiko_events`,
|
|
95
92
|
);
|
|
96
93
|
const afterCount = Number(after[0]?.count ?? 0);
|
|
97
94
|
|
|
@@ -103,11 +100,8 @@ describe("r.rawTable — DB roundtrip via setupTestStack", () => {
|
|
|
103
100
|
// setupTestStack dedupe (seenTables-by-table-reference) had silently
|
|
104
101
|
// broken, beforeAll's setupTestStack would have raised a 42P07 on
|
|
105
102
|
// the second push and never reached this test.
|
|
106
|
-
await stack.db
|
|
107
|
-
const rows = await stack.db
|
|
108
|
-
.select()
|
|
109
|
-
.from(sharedSyncCache)
|
|
110
|
-
.where(eq(sharedSyncCache.syncId, "sync_1"));
|
|
103
|
+
await insertOne(stack.db, sharedSyncCache, { syncId: "sync_1", payload: "{}" });
|
|
104
|
+
const rows = await selectMany(stack.db, sharedSyncCache, { syncId: "sync_1" });
|
|
111
105
|
expect(rows).toHaveLength(1);
|
|
112
106
|
// Both registrations are visible in the registry — same physical
|
|
113
107
|
// target, different logical handles.
|
|
@@ -115,14 +109,8 @@ describe("r.rawTable — DB roundtrip via setupTestStack", () => {
|
|
|
115
109
|
expect(stack.registry.getAllRawTables().get("secondary-sync")?.table).toBe(sharedSyncCache);
|
|
116
110
|
});
|
|
117
111
|
|
|
118
|
-
test("a second push on the same rawTable
|
|
119
|
-
//
|
|
120
|
-
|
|
121
|
-
// strict — that's the contract of the unsafe-prefix). Pin the
|
|
122
|
-
// failure mode of the unfiltered call: a direct second push on
|
|
123
|
-
// the same Drizzle schema raises the underlying PG error. This
|
|
124
|
-
// is the negative form of the idempotency contract — without the
|
|
125
|
-
// filter, a re-boot against a persistent dev DB would crash here.
|
|
126
|
-
await expect(unsafePushTables(stack.db, { idem: stripeWebhookCache })).rejects.toThrow();
|
|
112
|
+
test("a second push on the same rawTable is idempotent — CREATE IF NOT EXISTS", async () => {
|
|
113
|
+
// unsafePushTables uses CREATE TABLE IF NOT EXISTS — idempotent by design.
|
|
114
|
+
await expect(unsafePushTables(stack.db, { idem: stripeWebhookCache })).resolves.toBeUndefined();
|
|
127
115
|
});
|
|
128
116
|
});
|
|
@@ -1,8 +1,11 @@
|
|
|
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 { integer, table as pgTable, serial, text } from "../db/dialect";
|
|
4
|
+
import { selectMany } from "../db/query";
|
|
3
5
|
import { seedReferenceData } from "../db/reference-data";
|
|
4
6
|
import type { ReferenceDataDef } from "../engine/types";
|
|
5
|
-
import {
|
|
7
|
+
import { unsafePushTables } from "../stack";
|
|
8
|
+
import { ensureTemporalPolyfill } from "../time/polyfill";
|
|
6
9
|
|
|
7
10
|
// --- Tables ---
|
|
8
11
|
|
|
@@ -21,9 +24,10 @@ const statusTable = pgTable("ref_statuses", {
|
|
|
21
24
|
|
|
22
25
|
// --- Test state ---
|
|
23
26
|
|
|
24
|
-
let testDb:
|
|
27
|
+
let testDb: BunTestDb;
|
|
25
28
|
|
|
26
29
|
beforeAll(async () => {
|
|
30
|
+
await ensureTemporalPolyfill();
|
|
27
31
|
testDb = await createTestDb();
|
|
28
32
|
await unsafePushTables(testDb.db, { countryTable, statusTable });
|
|
29
33
|
});
|
|
@@ -34,13 +38,13 @@ afterAll(async () => {
|
|
|
34
38
|
|
|
35
39
|
// Helper: read all rows from a table
|
|
36
40
|
async function readCountries() {
|
|
37
|
-
const rows = await testDb.db
|
|
38
|
-
return rows.
|
|
41
|
+
const rows = await selectMany(testDb.db, countryTable);
|
|
42
|
+
return rows.toSorted((a, b) => a.code.localeCompare(b.code));
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
async function readStatuses() {
|
|
42
|
-
const rows = await testDb.db
|
|
43
|
-
return rows.
|
|
46
|
+
const rows = await selectMany(testDb.db, statusTable);
|
|
47
|
+
return rows.toSorted((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0));
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
describe("seedReferenceData", () => {
|
|
@@ -132,7 +136,10 @@ describe("seedReferenceData", () => {
|
|
|
132
136
|
|
|
133
137
|
const rows = await readCountries();
|
|
134
138
|
expect(rows).toHaveLength(4);
|
|
135
|
-
expect(rows.find((r) => r
|
|
139
|
+
expect(rows.find((r: Record<string, unknown>) => r["code"] === "CH")).toMatchObject({
|
|
140
|
+
name: "Schweiz",
|
|
141
|
+
region: "Europe",
|
|
142
|
+
});
|
|
136
143
|
});
|
|
137
144
|
|
|
138
145
|
test("custom upsertKey — matches on specified field instead of first", async () => {
|
|
@@ -167,9 +174,15 @@ describe("seedReferenceData", () => {
|
|
|
167
174
|
expect(updateResult).toEqual({ inserted: 0, updated: 1 });
|
|
168
175
|
|
|
169
176
|
const rows = await readStatuses();
|
|
170
|
-
expect(rows.find((r) => r
|
|
171
|
-
|
|
172
|
-
|
|
177
|
+
expect(rows.find((r: Record<string, unknown>) => r["slug"] === "draft")).toMatchObject({
|
|
178
|
+
label: "Entwurf",
|
|
179
|
+
});
|
|
180
|
+
expect(rows.find((r: Record<string, unknown>) => r["slug"] === "active")).toMatchObject({
|
|
181
|
+
label: "Active",
|
|
182
|
+
});
|
|
183
|
+
expect(rows.find((r: Record<string, unknown>) => r["slug"] === "archived")).toMatchObject({
|
|
184
|
+
label: "Archived",
|
|
185
|
+
});
|
|
173
186
|
});
|
|
174
187
|
|
|
175
188
|
test("skips unknown entity names gracefully", async () => {
|
package/src/__tests__/{transition-guard.integration.ts → transition-guard.integration.test.ts}
RENAMED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { afterAll, beforeAll, describe, expect, test } from "
|
|
1
|
+
import { afterAll, beforeAll, 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 { updateMany } from "../db/query";
|
|
5
|
+
import { buildEntityTable } from "../db/table-builder";
|
|
5
6
|
import {
|
|
6
7
|
createBooleanField,
|
|
7
8
|
createEntity,
|
|
@@ -67,9 +68,9 @@ const ticketEntity = createEntity({
|
|
|
67
68
|
},
|
|
68
69
|
});
|
|
69
70
|
|
|
70
|
-
const invoiceTable =
|
|
71
|
-
const orderTable =
|
|
72
|
-
const ticketTable =
|
|
71
|
+
const invoiceTable = buildEntityTable("invoice", invoiceEntity);
|
|
72
|
+
const orderTable = buildEntityTable("order", orderEntity);
|
|
73
|
+
const ticketTable = buildEntityTable("ticket", ticketEntity);
|
|
73
74
|
|
|
74
75
|
const feature = defineFeature("txguard", (r) => {
|
|
75
76
|
r.entity("invoice", invoiceEntity);
|
|
@@ -267,11 +268,12 @@ describe("auto transition guard: per-entity transition map (cache key includes e
|
|
|
267
268
|
// Raw-DB-mark-deleted — we need a soft-deleted row whose status is a
|
|
268
269
|
// terminal state. If the guard fired, any status write would throw
|
|
269
270
|
// "Invalid transition: closed → <x>". We want it silently skipped.
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
271
|
+
await updateMany(
|
|
272
|
+
stack.db,
|
|
273
|
+
ticketTable,
|
|
274
|
+
{ status: "closed", isDeleted: true },
|
|
275
|
+
{ id: ticket["id"] },
|
|
276
|
+
);
|
|
275
277
|
|
|
276
278
|
// Attempting to move a deleted ticket to "open" would normally violate
|
|
277
279
|
// "closed → []" (no allowed targets). With the softDelete skip, the
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// against a hand-rolled Hono app — no DB, no dispatcher. Exercises the
|
|
3
3
|
// transport-extraction path that drives the csrf-middleware downstream.
|
|
4
4
|
|
|
5
|
+
import { describe, expect, test } from "bun:test";
|
|
5
6
|
import { Hono } from "hono";
|
|
6
|
-
import { describe, expect, test } from "vitest";
|
|
7
7
|
import { TestUsers } from "../../stack";
|
|
8
8
|
import { AUTH_COOKIE_NAME, authMiddleware, getAuthTransport, getUser } from "../auth-middleware";
|
|
9
9
|
import { createJwtHelper } from "../jwt";
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
// logic — full-stack login via real loginHandler is covered by the
|
|
6
6
|
// auth-cookie sample integration test.
|
|
7
7
|
|
|
8
|
+
import { describe, expect, test } from "bun:test";
|
|
8
9
|
import type { Hono } from "hono";
|
|
9
10
|
import { Hono as HonoCtor } from "hono";
|
|
10
|
-
import { describe, expect, test } from "vitest";
|
|
11
11
|
import type { SessionUser } from "../../engine/types";
|
|
12
12
|
import type { BatchResult, Dispatcher, WriteResult } from "../../pipeline/dispatcher";
|
|
13
13
|
import { TestUsers } from "../../stack";
|