@cosmicdrift/kumiko-framework 1.0.0 → 2.0.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/README.md +9 -38
- package/package.json +21 -2
- package/src/__tests__/anonymous-access.integration.test.ts +185 -0
- package/src/__tests__/consumer-cli.integration.test.ts +172 -0
- package/src/__tests__/entity-permalink-open.integration.test.ts +94 -0
- package/src/__tests__/full-stack.integration.test.ts +1 -1
- package/src/__tests__/schema-cli-temporal-polyfill.test.ts +48 -0
- package/src/__tests__/schema-cli.integration.test.ts +50 -0
- package/src/__tests__/store-table.integration.test.ts +93 -0
- package/src/api/__tests__/api.test.ts +373 -0
- package/src/api/__tests__/auth-middleware-anonymous-access-boot.test.ts +40 -0
- package/src/api/__tests__/auth-routes-cookie.test.ts +17 -1
- package/src/api/__tests__/auth-routes-invalid-body-invite.test.ts +253 -0
- package/src/api/__tests__/auth-routes-mfa-preauth-confirm.test.ts +222 -0
- package/src/api/__tests__/auth-routes-mfa-preauth-enable-start.test.ts +249 -0
- package/src/api/__tests__/auth-routes-mfa-verify.test.ts +202 -0
- package/src/api/__tests__/auth-routes-trusted-proxy.test.ts +135 -0
- package/src/api/__tests__/batch.integration.test.ts +101 -11
- package/src/api/__tests__/csrf-constants-sync.test.ts +20 -0
- package/src/api/__tests__/dispatcher-live.integration.test.ts +74 -0
- package/src/api/__tests__/jwt.test.ts +200 -1
- package/src/api/__tests__/login-rate-limiter-sweep.test.ts +50 -0
- package/src/api/__tests__/pat-scope.test.ts +36 -0
- package/src/api/__tests__/pii-leak-guard.integration.test.ts +103 -0
- package/src/api/__tests__/redis-login-rate-limiter.integration.test.ts +138 -0
- package/src/api/__tests__/request-id-middleware.test.ts +51 -0
- package/src/api/__tests__/server-boot-guards.test.ts +71 -0
- package/src/api/__tests__/server-jwt-ttl.test.ts +58 -0
- package/src/api/__tests__/sse-broker.test.ts +57 -0
- package/src/api/__tests__/sse-route.test.ts +4 -0
- package/src/api/api-constants.ts +11 -0
- package/src/api/auth-middleware.ts +248 -40
- package/src/api/auth-routes.ts +576 -95
- package/src/api/index.ts +13 -4
- package/src/api/jwt.ts +170 -11
- package/src/api/pat-scope.ts +14 -0
- package/src/api/pii-leak-guard.ts +47 -0
- package/src/api/request-context.ts +3 -0
- package/src/api/request-id-middleware.ts +2 -0
- package/src/api/routes.ts +169 -2
- package/src/api/server.ts +112 -16
- package/src/api/sse-broker.ts +39 -0
- package/src/bun-db/__tests__/PATTERN.md +0 -1
- package/src/bun-db/__tests__/coerce-row-temporal.test.ts +41 -0
- package/src/bun-db/__tests__/select-many-retry.test.ts +79 -0
- package/src/bun-db/__tests__/write-brand.test.ts +21 -0
- package/src/bun-db/connection.ts +3 -3
- package/src/bun-db/index.ts +2 -0
- package/src/bun-db/query.ts +105 -32
- package/src/consumer-cli.ts +134 -0
- package/src/crypto/__tests__/blind-index.test.ts +130 -0
- package/src/crypto/__tests__/event-pii.test.ts +161 -0
- package/src/crypto/__tests__/kek-rotation.integration.test.ts +180 -0
- package/src/crypto/__tests__/kms-adapter-contract.ts +134 -0
- package/src/crypto/__tests__/kms-adapter.contract.test.ts +4 -0
- package/src/crypto/__tests__/pg-kms-adapter.integration.test.ts +117 -0
- package/src/crypto/__tests__/pii-field-encryption.test.ts +376 -0
- package/src/crypto/__tests__/request-kms-cache.test.ts +74 -0
- package/src/crypto/__tests__/subject-resolver.test.ts +108 -0
- package/src/crypto/blind-index.ts +118 -0
- package/src/crypto/event-pii.ts +70 -0
- package/src/crypto/in-memory-kms-adapter.ts +50 -0
- package/src/crypto/index.ts +67 -0
- package/src/crypto/kms-adapter.ts +2 -0
- package/src/crypto/pg-kms-adapter.ts +295 -0
- package/src/crypto/pii-field-encryption.ts +248 -0
- package/src/crypto/request-kms-cache.ts +38 -0
- package/src/crypto/subject-resolver.ts +91 -0
- package/src/db/__tests__/assert-no-unreachable-live-rows.integration.test.ts +191 -0
- package/src/db/__tests__/blind-index.integration.test.ts +248 -0
- package/src/db/__tests__/build-filter-where.test.ts +34 -0
- package/src/db/__tests__/collect-table-metas.test.ts +10 -10
- package/src/db/__tests__/config-seed.integration.test.ts +13 -5
- package/src/db/__tests__/dialect-instant.test.ts +1 -4
- package/src/db/__tests__/entity-field-encryption.test.ts +7 -7
- package/src/db/__tests__/entity-table-meta-source.test.ts +50 -0
- package/src/db/__tests__/event-store-executor-context.pii-roundtrip.test.ts +67 -0
- package/src/db/__tests__/event-store-executor-write-verbs.integration.test.ts +402 -0
- package/src/db/__tests__/event-store-executor.integration.test.ts +299 -29
- package/src/db/__tests__/feature-table-sources.test.ts +34 -0
- package/src/db/__tests__/implicit-projection-equivalence.integration.test.ts +118 -39
- package/src/db/__tests__/instant-to-driver-temporal.test.ts +21 -0
- package/src/db/__tests__/located-timestamp.test.ts +19 -0
- package/src/db/__tests__/migrate-generator.test.ts +21 -0
- package/src/db/__tests__/migrate-runner.test.ts +61 -0
- package/src/db/__tests__/number-field-fractional.integration.test.ts +58 -0
- package/src/db/__tests__/rebuild-marker.test.ts +13 -3
- package/src/db/__tests__/replay-migration-sql.test.ts +384 -0
- package/src/db/__tests__/schema-inspection.test.ts +7 -0
- package/src/db/__tests__/schema-migration.integration.test.ts +1 -1
- package/src/db/__tests__/table-builder-meta-lockstep.test.ts +39 -0
- package/src/db/__tests__/tenant-db-where-merge.test.ts +49 -3
- package/src/db/__tests__/tenant-db.integration.test.ts +6 -2
- package/src/db/api.ts +2 -2
- package/src/db/apply-entity-event.ts +18 -14
- package/src/db/blind-index-cleanup.ts +55 -0
- package/src/db/bun-provider.ts +2 -2
- package/src/db/collect-table-metas.ts +6 -7
- package/src/db/config-seed.ts +9 -9
- package/src/db/connection.ts +7 -12
- package/src/db/cursor.ts +1 -18
- package/src/db/dialect.ts +20 -26
- package/src/db/entity-field-encryption.ts +81 -24
- package/src/db/entity-table-meta-types.ts +2 -0
- package/src/db/entity-table-meta.ts +63 -90
- package/src/db/event-store-executor-context.ts +404 -0
- package/src/db/event-store-executor-read.ts +275 -0
- package/src/db/event-store-executor-write.ts +644 -0
- package/src/db/event-store-executor.ts +28 -1155
- package/src/db/feature-table-sources.ts +6 -5
- package/src/db/index.ts +20 -3
- package/src/db/located-timestamp.ts +4 -0
- package/src/db/migrate-generator.ts +39 -6
- package/src/db/migrate-runner.ts +107 -11
- package/src/db/pg-error.ts +9 -1
- package/src/db/postgres-provider.ts +2 -2
- package/src/db/queries/__tests__/event-store-idempotency-index.integration.test.ts +80 -0
- package/src/db/queries/backfill-pii.ts +277 -0
- package/src/db/queries/ddl.ts +45 -0
- package/src/db/queries/event-consumer.ts +35 -2
- package/src/db/queries/event-store.ts +126 -19
- package/src/db/queries/projection-rebuild.ts +22 -8
- package/src/db/queries/shadow-swap.ts +183 -0
- package/src/db/queries/test-stack.ts +4 -30
- package/src/db/query-api.ts +1 -0
- package/src/db/query.ts +1 -0
- package/src/db/rebuild-marker.ts +18 -2
- package/src/db/reference-data.ts +2 -3
- package/src/db/replay-migration-sql.ts +257 -0
- package/src/db/schema-inspection.ts +1 -1
- package/src/db/table-builder.ts +102 -71
- package/src/db/tenant-db.ts +15 -53
- package/src/engine/__tests__/boot-validator-action-wiring.test.ts +242 -0
- package/src/engine/__tests__/boot-validator-boot-check.test.ts +99 -0
- package/src/engine/__tests__/boot-validator-dashboard.test.ts +237 -0
- package/src/engine/__tests__/boot-validator-entity-list.test.ts +104 -0
- package/src/engine/__tests__/boot-validator-gdpr-storage.test.ts +7 -69
- package/src/engine/__tests__/boot-validator-i18n-keys.test.ts +26 -5
- package/src/engine/__tests__/boot-validator-located-timestamps.test.ts +3 -19
- package/src/engine/__tests__/boot-validator-pii-retention.test.ts +246 -4
- package/src/engine/__tests__/boot-validator.test.ts +219 -15
- package/src/engine/__tests__/build-app-schema.test.ts +82 -0
- package/src/engine/__tests__/build-config-feature-schema.test.ts +125 -0
- package/src/engine/__tests__/build-target.test.ts +3 -11
- package/src/engine/__tests__/codemod-pipeline.test.ts +152 -21
- package/src/engine/__tests__/config-helpers.test.ts +16 -0
- package/src/engine/__tests__/define-feature-entity-mapping.test.ts +6 -0
- package/src/engine/__tests__/define-roles.test.ts +21 -0
- package/src/engine/__tests__/engine.test.ts +163 -1
- package/src/engine/__tests__/entity-handlers.test.ts +80 -0
- package/src/engine/__tests__/event-migration-declarative.test.ts +65 -0
- package/src/engine/__tests__/event-type-map-augmentation.test.ts +24 -0
- package/src/engine/__tests__/extend-entity-projection.test.ts +123 -0
- package/src/engine/__tests__/factories-time.test.ts +2 -66
- package/src/engine/__tests__/feature-crud-shorthand.test.ts +28 -0
- package/src/engine/__tests__/feature-manifest.test.ts +31 -1
- package/src/engine/__tests__/field-access.test.ts +23 -1
- package/src/engine/__tests__/hook-phases.test.ts +5 -5
- package/src/engine/__tests__/membership-roles.test.ts +4 -10
- package/src/engine/__tests__/nav.test.ts +86 -1
- package/src/engine/__tests__/pipeline-engine.test.ts +9 -9
- package/src/engine/__tests__/pipeline-handler.integration.test.ts +18 -18
- package/src/engine/__tests__/pipeline-observability.integration.test.ts +2 -2
- package/src/engine/__tests__/pipeline-performance.integration.test.ts +3 -3
- package/src/engine/__tests__/pipeline-sub-pipelines.test.ts +9 -9
- package/src/engine/__tests__/post-query-hook.test.ts +7 -7
- package/src/engine/__tests__/registrar-object-form.test.ts +141 -0
- package/src/engine/__tests__/registry.test.ts +144 -0
- package/src/engine/__tests__/schema-builder.test.ts +18 -0
- package/src/engine/__tests__/screen.test.ts +147 -1
- package/src/engine/__tests__/soft-delete-cleanup.test.ts +3 -0
- package/src/engine/__tests__/store-table.test.ts +229 -0
- package/src/engine/__tests__/tier-resolver-extension.test.ts +19 -1
- package/src/engine/__tests__/{visual-tree-patterns.test.ts → tree-actions-patterns.test.ts} +7 -95
- package/src/engine/__tests__/validate-projection-allowlist.test.ts +15 -15
- package/src/engine/boot-validator/__tests__/config-deps.test.ts +92 -0
- package/src/engine/boot-validator/action-wiring.ts +149 -0
- package/src/engine/boot-validator/boot-check.ts +21 -0
- package/src/engine/boot-validator/config-deps.ts +40 -4
- package/src/engine/boot-validator/entity-handler.ts +20 -21
- package/src/engine/boot-validator/entity-list-screens.ts +88 -0
- package/src/engine/boot-validator/gdpr-storage.ts +0 -20
- package/src/engine/boot-validator/i18n-keys.ts +58 -4
- package/src/engine/boot-validator/index.ts +33 -12
- package/src/engine/boot-validator/nav.ts +125 -0
- package/src/engine/boot-validator/pii-retention.ts +95 -10
- package/src/engine/boot-validator/{screens-nav.ts → screens.ts} +214 -191
- package/src/engine/boot-validator/workspaces.ts +68 -0
- package/src/engine/build-app-schema.ts +16 -0
- package/src/engine/build-config-feature-schema.ts +44 -7
- package/src/engine/codemod/pipeline-codemod.ts +5 -5
- package/src/engine/config-helpers.ts +15 -0
- package/src/engine/constants.ts +32 -6
- package/src/engine/create-app.ts +11 -0
- package/src/engine/define-feature.ts +95 -947
- package/src/engine/define-handler.ts +28 -94
- package/src/engine/define-workflow.ts +1 -1
- package/src/engine/effective-features.ts +12 -2
- package/src/engine/entity-handlers.ts +76 -11
- package/src/engine/extensions/tenant-data.ts +19 -0
- package/src/engine/extensions/user-data.ts +29 -2
- package/src/engine/factories.ts +8 -49
- package/src/engine/feature-ast/__tests__/canonical-form.test.ts +26 -29
- package/src/engine/feature-ast/__tests__/fixtures/cross-file-registrar/feature.ts +9 -0
- package/src/engine/feature-ast/__tests__/fixtures/cross-file-registrar/screens.ts +4 -0
- package/src/engine/feature-ast/__tests__/parse-happy-path.test.ts +1 -2
- package/src/engine/feature-ast/__tests__/parse-real-features.test.ts +18 -8
- package/src/engine/feature-ast/__tests__/parse.test.ts +1640 -160
- package/src/engine/feature-ast/__tests__/patch.test.ts +206 -12
- package/src/engine/feature-ast/__tests__/patcher.test.ts +20 -23
- package/src/engine/feature-ast/__tests__/render-roundtrip.test.ts +380 -5
- package/src/engine/feature-ast/extractors/events.ts +322 -0
- package/src/engine/feature-ast/extractors/handlers.ts +234 -0
- package/src/engine/feature-ast/extractors/hooks.ts +243 -0
- package/src/engine/feature-ast/extractors/index.ts +34 -31
- package/src/engine/feature-ast/extractors/jobs-routes.ts +221 -0
- package/src/engine/feature-ast/extractors/projections-screens.ts +269 -0
- package/src/engine/feature-ast/extractors/round1.ts +3 -3
- package/src/engine/feature-ast/extractors/round5.ts +3 -3
- package/src/engine/feature-ast/extractors/round6.ts +2 -36
- package/src/engine/feature-ast/extractors/shared.ts +64 -6
- package/src/engine/feature-ast/index.ts +2 -4
- package/src/engine/feature-ast/parse.ts +130 -23
- package/src/engine/feature-ast/patch.ts +39 -50
- package/src/engine/feature-ast/patcher.ts +37 -38
- package/src/engine/feature-ast/patterns.ts +50 -62
- package/src/engine/feature-ast/render.ts +67 -44
- package/src/engine/feature-builder-state.ts +168 -0
- package/src/engine/feature-config-events-jobs.ts +403 -0
- package/src/engine/feature-entity-handlers.ts +208 -0
- package/src/engine/feature-manifest.ts +2 -1
- package/src/engine/feature-ui-extensions.ts +500 -0
- package/src/engine/field-access.ts +13 -2
- package/src/engine/field-helpers.ts +31 -0
- package/src/engine/handler-helpers.ts +26 -0
- package/src/engine/hook-helpers.ts +16 -0
- package/src/engine/index.ts +23 -7
- package/src/engine/membership-roles.ts +13 -0
- package/src/engine/object-form.ts +27 -0
- package/src/engine/ownership.ts +26 -79
- package/src/engine/pattern-library/__tests__/library.test.ts +7 -20
- package/src/engine/pattern-library/library.ts +44 -1152
- package/src/engine/pattern-library/mixed-schemas.ts +450 -0
- package/src/engine/pattern-library/opaque-schemas.ts +124 -0
- package/src/engine/pattern-library/shared-fields.ts +75 -0
- package/src/engine/pattern-library/static-schemas.ts +456 -0
- package/src/engine/pipeline.ts +6 -11
- package/src/engine/registry-facade.ts +362 -0
- package/src/engine/registry-ingest.ts +478 -0
- package/src/engine/registry-state.ts +388 -0
- package/src/engine/registry-validate.ts +642 -0
- package/src/engine/registry.ts +78 -1658
- package/src/engine/run-pipeline.ts +1 -1
- package/src/engine/schema-builder.ts +1 -0
- package/src/engine/screen-helpers.ts +54 -0
- package/src/engine/soft-delete-cleanup.ts +6 -2
- package/src/engine/steps/__tests__/duration-utils.test.ts +20 -0
- package/src/engine/steps/_duration-utils.ts +2 -0
- package/src/engine/steps/unsafe-projection-upsert.ts +1 -4
- package/src/engine/tier-resolver-extension.ts +3 -2
- package/src/engine/types/config.ts +2 -482
- package/src/engine/types/define-handler.ts +2 -0
- package/src/engine/types/entity-handlers.ts +2 -0
- package/src/engine/types/event-type-map.ts +1 -37
- package/src/engine/types/feature.ts +2 -972
- package/src/engine/types/fields.ts +2 -675
- package/src/engine/types/handlers.ts +2 -774
- package/src/engine/types/hooks.ts +2 -184
- package/src/engine/types/http-route.ts +1 -54
- package/src/engine/types/identifiers.ts +1 -47
- package/src/engine/types/index.ts +86 -40
- package/src/engine/types/nav.ts +2 -63
- package/src/engine/types/ownership.ts +2 -0
- package/src/engine/types/projection.ts +2 -138
- package/src/engine/types/relations.ts +1 -51
- package/src/engine/types/screen.ts +2 -574
- package/src/engine/types/step.ts +2 -334
- package/src/engine/types/target-ref.ts +1 -21
- package/src/engine/types/tree-node.ts +1 -132
- package/src/engine/types/workspace.ts +2 -49
- package/src/engine/validate-projection-allowlist.ts +6 -6
- package/src/entrypoint/__tests__/entrypoint-job-wiring.integration.test.ts +120 -1
- package/src/entrypoint/index.ts +49 -6
- package/src/errors/classes.ts +22 -1
- package/src/errors/field-issue.ts +0 -3
- package/src/errors/index.ts +1 -1
- package/src/errors/write-error-info.ts +10 -22
- package/src/es-ops/README.md +1 -1
- package/src/es-ops/__tests__/runner.integration.test.ts +74 -0
- package/src/es-ops/context.ts +4 -2
- package/src/es-ops/types.ts +8 -1
- package/src/event-store/__tests__/admin-api.integration.test.ts +27 -1
- package/src/event-store/__tests__/backfill-pii.integration.test.ts +279 -0
- package/src/event-store/__tests__/event-store.integration.test.ts +201 -0
- package/src/event-store/__tests__/row-to-stored-event.test.ts +2 -2
- package/src/event-store/__tests__/snapshot.integration.test.ts +86 -0
- package/src/event-store/__tests__/unscoped-stream-primitives.guard.test.ts +58 -0
- package/src/event-store/__tests__/upcaster.integration.test.ts +77 -45
- package/src/event-store/admin-api.ts +11 -4
- package/src/event-store/errors.ts +2 -35
- package/src/event-store/event-store.ts +64 -78
- package/src/event-store/events-schema.ts +11 -13
- package/src/event-store/index.ts +18 -3
- package/src/event-store/rebuild-dead-letter.ts +111 -0
- package/src/event-store/snapshot.ts +63 -40
- package/src/event-store/types.ts +2 -0
- package/src/files/__tests__/build-storage-key.test.ts +28 -0
- package/src/files/__tests__/file-ref-entity.test.ts +8 -0
- package/src/files/__tests__/files.integration.test.ts +24 -0
- package/src/files/__tests__/in-memory-provider.contract.test.ts +4 -0
- package/src/files/__tests__/local-provider.test.ts +31 -0
- package/src/files/__tests__/provider-resolver.test.ts +70 -0
- package/src/files/__tests__/write-stream.test.ts +13 -0
- package/src/files/file-handle.ts +2 -19
- package/src/files/file-ref-entity.ts +2 -2
- package/src/files/file-routes.ts +13 -0
- package/src/files/index.ts +1 -1
- package/src/files/local-provider.ts +27 -8
- package/src/files/provider-resolver.ts +31 -20
- package/src/files/types.ts +13 -55
- package/src/i18n/__tests__/required-surface-keys.test.ts +17 -0
- package/src/i18n/required-surface-keys.ts +120 -1
- package/src/jobs/__tests__/job-queue-depth.integration.test.ts +82 -0
- package/src/jobs/__tests__/jobs.integration.test.ts +329 -3
- package/src/jobs/job-runner.ts +82 -12
- package/src/logging/types.ts +1 -7
- package/src/migrations/pending-rebuilds.ts +1 -1
- package/src/observability/__tests__/observability.integration.test.ts +4 -1
- package/src/observability/__tests__/recording-tracer.test.ts +6 -4
- package/src/observability/index.ts +2 -0
- package/src/observability/noop-provider.ts +0 -9
- package/src/observability/recording-tracer.ts +0 -12
- package/src/observability/standard-metrics.ts +64 -2
- package/src/observability/types/index.ts +1 -29
- package/src/observability/types/metric.ts +1 -56
- package/src/observability/types/provider.ts +1 -32
- package/src/observability/types/span.ts +1 -64
- package/src/pipeline/__tests__/ctx-bridge.integration.test.ts +2 -2
- package/src/pipeline/__tests__/dispatcher.test.ts +366 -1
- package/src/pipeline/__tests__/event-consumer-state.integration.test.ts +31 -0
- package/src/pipeline/__tests__/event-dispatcher-delivery-max-attempts.test.ts +126 -0
- package/src/pipeline/__tests__/event-dispatcher-rearm.integration.test.ts +263 -0
- package/src/pipeline/__tests__/event-dispatcher.integration.test.ts +10 -0
- package/src/pipeline/__tests__/job-trigger-consumer.integration.test.ts +106 -0
- package/src/pipeline/__tests__/lifecycle-pipeline.test.ts +308 -77
- package/src/pipeline/__tests__/load-aggregate-query.integration.test.ts +16 -8
- package/src/pipeline/__tests__/post-query-hook.integration.test.ts +3 -3
- package/src/pipeline/__tests__/projection-rebuild.integration.test.ts +80 -2
- package/src/pipeline/__tests__/rebuild-poison-quarantine.integration.test.ts +274 -0
- package/src/pipeline/__tests__/try-append-event.integration.test.ts +166 -0
- package/src/pipeline/dispatch-batch.ts +187 -0
- package/src/pipeline/dispatch-query.ts +165 -0
- package/src/pipeline/dispatch-shared.ts +826 -0
- package/src/pipeline/dispatch-stream.ts +90 -0
- package/src/pipeline/dispatch-write.ts +451 -0
- package/src/pipeline/dispatcher-utils.ts +1 -1
- package/src/pipeline/dispatcher.ts +44 -1372
- package/src/pipeline/entity-cache.ts +2 -33
- package/src/pipeline/event-consumer-state.ts +30 -2
- package/src/pipeline/event-dispatcher-admin.ts +293 -0
- package/src/pipeline/event-dispatcher-delivery.ts +305 -0
- package/src/pipeline/event-dispatcher.ts +85 -542
- package/src/pipeline/index.ts +2 -0
- package/src/pipeline/msp-rebuild.ts +42 -3
- package/src/pipeline/multi-stream-apply-context.ts +4 -42
- package/src/pipeline/projection-rebuild.ts +105 -3
- package/src/pipeline/system-hooks.ts +144 -1
- package/src/rate-limit/__tests__/resolver.integration.test.ts +18 -0
- package/src/rate-limit/resolver.ts +16 -32
- package/src/schema-cli.ts +76 -16
- package/src/search/__tests__/meilisearch-adapter.integration.test.ts +207 -185
- package/src/search/__tests__/meilisearch-ids.test.ts +30 -0
- package/src/search/__tests__/reindex-entity.integration.test.ts +144 -0
- package/src/search/index.ts +6 -0
- package/src/search/meilisearch-adapter.ts +13 -12
- package/src/search/reindex-entity.ts +177 -0
- package/src/search/types.ts +1 -39
- package/src/secrets/__tests__/contains-secret.test.ts +34 -0
- package/src/secrets/__tests__/envelope-cipher.test.ts +59 -0
- package/src/secrets/__tests__/envelope.test.ts +1 -1
- package/src/secrets/dek-cache.ts +26 -5
- package/src/secrets/envelope-cipher.ts +53 -0
- package/src/secrets/envelope.ts +5 -3
- package/src/secrets/index.ts +13 -1
- package/src/secrets/stored-envelope.ts +46 -0
- package/src/secrets/types.ts +2 -162
- package/src/stack/__tests__/event-collector.test.ts +42 -0
- package/src/stack/__tests__/setup-test-stack-jobs.integration.test.ts +125 -0
- package/src/stack/db.ts +2 -1
- package/src/stack/push-entity-projection-tables.ts +4 -3
- package/src/stack/redis.ts +8 -0
- package/src/stack/request-helper.ts +38 -2
- package/src/stack/table-helpers.ts +6 -4
- package/src/stack/test-stack.ts +249 -131
- package/src/testing/__tests__/late-bound.test.ts +32 -0
- package/src/testing/__tests__/wait-for.test.ts +59 -0
- package/src/testing/boot-validator-fixture.ts +121 -0
- package/src/testing/e2e-generator.ts +8 -0
- package/src/testing/file-provider-contract.ts +104 -0
- package/src/testing/handler-context.ts +3 -1
- package/src/testing/index.ts +5 -0
- package/src/testing/late-bound.ts +5 -3
- package/src/testing/mutable-master-key-provider.ts +29 -3
- package/src/testing/wait-for.ts +3 -0
- package/src/testing/without-ambient-temporal.ts +14 -0
- package/src/time/__tests__/tz-dateline.test.ts +8 -10
- package/src/time/geo-tz.ts +1 -32
- package/src/time/index.ts +1 -0
- package/src/time/legacy-date.ts +18 -0
- package/src/time/polyfill.ts +21 -38
- package/src/time/tz-context.ts +44 -85
- package/src/ui-types/app-schema.ts +12 -0
- package/src/ui-types/index.ts +20 -7
- package/src/utils/__tests__/safe-json-temporal.test.ts +18 -0
- package/src/utils/safe-json.ts +13 -1
- package/src/__tests__/raw-table.integration.test.ts +0 -116
- package/src/bun-db/__tests__/bun-test-stack.ts +0 -6
- package/src/db/__tests__/encryption.test.ts +0 -39
- package/src/db/encryption.ts +0 -39
- package/src/db/row-helpers.ts +0 -4
- package/src/engine/__tests__/raw-table.test.ts +0 -150
- package/src/engine/__tests__/unmanaged-table.test.ts +0 -127
- package/src/engine/feature-ast/__tests__/visual-tree-parse.test.ts +0 -184
- package/src/engine/feature-ast/extractors/round4.ts +0 -1366
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
// up at canonical positions). We compare every other field.
|
|
10
10
|
|
|
11
11
|
import { describe, expect, test } from "bun:test";
|
|
12
|
-
import
|
|
12
|
+
import * as path from "node:path";
|
|
13
|
+
import { Project, ts } from "ts-morph";
|
|
13
14
|
import { parseSourceFile } from "../parse";
|
|
14
15
|
import type { FeaturePattern } from "../patterns";
|
|
15
16
|
import { renderFeatureFile, renderPattern } from "../render";
|
|
@@ -29,10 +30,10 @@ defineFeature("inventory", (r) => {
|
|
|
29
30
|
},
|
|
30
31
|
});
|
|
31
32
|
|
|
32
|
-
r.relation("item", "supplier", {
|
|
33
|
+
r.relation("item", "supplier", { type: "belongsTo", target: "user", foreignKey: "supplierId" });
|
|
33
34
|
|
|
34
35
|
r.metric("created", { type: "counter" });
|
|
35
|
-
r.secret("apiKey", {
|
|
36
|
+
r.secret("apiKey", { label: { en: "Stripe API Key" }, scope: "tenant" });
|
|
36
37
|
r.claimKey("teamId", { type: "string" });
|
|
37
38
|
|
|
38
39
|
r.referenceData(
|
|
@@ -44,7 +45,16 @@ defineFeature("inventory", (r) => {
|
|
|
44
45
|
{ upsertKey: "id" },
|
|
45
46
|
);
|
|
46
47
|
|
|
47
|
-
r.config({
|
|
48
|
+
r.config({
|
|
49
|
+
keys: {
|
|
50
|
+
maxRows: {
|
|
51
|
+
type: "number",
|
|
52
|
+
default: 50,
|
|
53
|
+
scope: "tenant",
|
|
54
|
+
access: { read: ["user"], write: ["admin"] },
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
});
|
|
48
58
|
});
|
|
49
59
|
`;
|
|
50
60
|
|
|
@@ -114,7 +124,7 @@ function stripLocations(value: unknown): unknown {
|
|
|
114
124
|
out[k] = { raw: normalizeBodyRaw((v as { raw: string }).raw) };
|
|
115
125
|
continue;
|
|
116
126
|
}
|
|
117
|
-
if (k === "opaqueProps" && v && typeof v === "object") {
|
|
127
|
+
if ((k === "opaqueProps" || k === "migrations") && v && typeof v === "object") {
|
|
118
128
|
const op: Record<string, unknown> = {};
|
|
119
129
|
for (const [pk, pv] of Object.entries(v as Record<string, unknown>)) {
|
|
120
130
|
if (pv && typeof pv === "object" && "raw" in pv) {
|
|
@@ -196,6 +206,15 @@ defineFeature("workflow", (r) => {
|
|
|
196
206
|
{ access: { openToAll: true } },
|
|
197
207
|
);
|
|
198
208
|
|
|
209
|
+
r.streamHandler(
|
|
210
|
+
"step:stream",
|
|
211
|
+
z.object({ prompt: z.string() }),
|
|
212
|
+
async function* (input, ctx) {
|
|
213
|
+
yield "token";
|
|
214
|
+
},
|
|
215
|
+
{ access: { roles: ["user"] } },
|
|
216
|
+
);
|
|
217
|
+
|
|
199
218
|
r.hook("postSave", "step", async (event, ctx) => {
|
|
200
219
|
console.log("step saved");
|
|
201
220
|
});
|
|
@@ -237,6 +256,83 @@ describe("render → parse roundtrip — mixed patterns (header data + opaque bo
|
|
|
237
256
|
// guarantee than parse → render → parse, because it pins that the renderer
|
|
238
257
|
// never depends on the input file's whitespace — its output is deterministic
|
|
239
258
|
// from the parsed FeaturePattern shape alone.
|
|
259
|
+
const RAW_REF_FEATURE = `
|
|
260
|
+
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
261
|
+
import { chatCompleteHandler } from "./handlers";
|
|
262
|
+
|
|
263
|
+
const eventEntity = {
|
|
264
|
+
fields: { name: { type: "text", required: true } },
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
function buildFields() {
|
|
268
|
+
return { title: { type: "text" } };
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const someFeature = { name: "mail-foundation" };
|
|
272
|
+
|
|
273
|
+
const eventListScreen = {
|
|
274
|
+
id: "event-list",
|
|
275
|
+
type: "entityList",
|
|
276
|
+
entity: "event",
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
function makeHandler() {
|
|
280
|
+
return { name: "task:create", schema: null, handler: () => {} };
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
defineFeature("refs", (r) => {
|
|
284
|
+
r.requires(someFeature.name, "config");
|
|
285
|
+
r.entity("event", eventEntity);
|
|
286
|
+
r.entity("task", { fields: buildFields() });
|
|
287
|
+
r.writeHandler(makeHandler());
|
|
288
|
+
r.streamHandler(chatCompleteHandler);
|
|
289
|
+
r.screen(eventListScreen);
|
|
290
|
+
});
|
|
291
|
+
`;
|
|
292
|
+
|
|
293
|
+
describe("render → parse roundtrip — unresolved references (raw-ref sentinel)", () => {
|
|
294
|
+
const initial = parse(RAW_REF_FEATURE);
|
|
295
|
+
|
|
296
|
+
test("parses requires + both entities + the opaque handler without error, keeping references unresolved", () => {
|
|
297
|
+
expect(initial.patterns).toMatchObject([
|
|
298
|
+
{ kind: "requires", featureNames: [{ __raw: "someFeature.name" }, "config"] },
|
|
299
|
+
{ kind: "entity", entityName: "event", definition: { __raw: "eventEntity" } },
|
|
300
|
+
{ kind: "entity", entityName: "task", definition: { fields: { __raw: "buildFields()" } } },
|
|
301
|
+
{ kind: "writeHandler", handlerName: undefined },
|
|
302
|
+
{ kind: "streamHandler", handlerName: undefined },
|
|
303
|
+
{ kind: "screen", definition: { __raw: "eventListScreen" } },
|
|
304
|
+
]);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
test("rendered output re-emits references verbatim, never inlines them", () => {
|
|
308
|
+
const rendered = renderFeatureFile({
|
|
309
|
+
featureName: initial.featureName ?? "",
|
|
310
|
+
patterns: initial.patterns,
|
|
311
|
+
});
|
|
312
|
+
expect(rendered).toContain("someFeature.name");
|
|
313
|
+
expect(rendered).toContain("eventEntity");
|
|
314
|
+
expect(rendered).toContain("buildFields()");
|
|
315
|
+
expect(rendered).toContain("r.writeHandler(makeHandler())");
|
|
316
|
+
expect(rendered).toContain("r.streamHandler(chatCompleteHandler)");
|
|
317
|
+
expect(rendered).toContain("r.screen(eventListScreen);");
|
|
318
|
+
// Would only appear if buildFields()'s return value got inlined.
|
|
319
|
+
expect(rendered).not.toContain("title:");
|
|
320
|
+
expect(rendered).not.toContain("mail-foundation");
|
|
321
|
+
expect(rendered).not.toContain("task:create");
|
|
322
|
+
// Would only appear if the screen ref got resolved/inlined.
|
|
323
|
+
expect(rendered).not.toContain("entityList");
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
test("pattern shape survives a full render → reparse cycle", () => {
|
|
327
|
+
const rendered = renderFeatureFile({
|
|
328
|
+
featureName: initial.featureName ?? "",
|
|
329
|
+
patterns: initial.patterns,
|
|
330
|
+
});
|
|
331
|
+
const reparsed = parse(rendered);
|
|
332
|
+
expect(reparsed.patterns.map(stripLocations)).toEqual(initial.patterns.map(stripLocations));
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
|
|
240
336
|
describe("render idempotence", () => {
|
|
241
337
|
test("rendered file → parse → render === rendered file", () => {
|
|
242
338
|
const initial = parse(STATIC_FEATURE);
|
|
@@ -285,3 +381,282 @@ describe("renderPattern — single-pattern shape", () => {
|
|
|
285
381
|
expect(out).toBe('r.metric({ name: "requests", type: "counter" });');
|
|
286
382
|
});
|
|
287
383
|
});
|
|
384
|
+
|
|
385
|
+
// Regression guard for the class of bug the r.exposesApi/r.usesApi fold
|
|
386
|
+
// hit: a registrar-shape change must survive the Designer's parse→render→
|
|
387
|
+
// parse cycle, not just a TS compile of the framework itself. r.hook()'s
|
|
388
|
+
// `{ allOf: entity }` target (replacing r.entityHook) reuses HookPattern's
|
|
389
|
+
// already-generic target field, so this is the cheap case — but proving it
|
|
390
|
+
// beats assuming it.
|
|
391
|
+
const HOOK_ALL_OF_FEATURE = `
|
|
392
|
+
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
393
|
+
|
|
394
|
+
defineFeature("shop", (r) => {
|
|
395
|
+
r.entity("product", { fields: { name: { type: "text" } } });
|
|
396
|
+
r.hook("postSave", { allOf: "product" }, async (result) => {
|
|
397
|
+
console.log(result);
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
`;
|
|
401
|
+
|
|
402
|
+
describe("render → parse roundtrip — r.hook({ allOf }) entity-wide target", () => {
|
|
403
|
+
test("allOf target survives parse → render → parse unchanged", () => {
|
|
404
|
+
const initial = parse(HOOK_ALL_OF_FEATURE);
|
|
405
|
+
const rendered = renderFeatureFile({
|
|
406
|
+
featureName: initial.featureName ?? "",
|
|
407
|
+
patterns: initial.patterns,
|
|
408
|
+
});
|
|
409
|
+
const reparsed = parse(rendered);
|
|
410
|
+
expect(reparsed.patterns.map(stripLocations)).toEqual(initial.patterns.map(stripLocations));
|
|
411
|
+
|
|
412
|
+
const hookPattern = reparsed.patterns.find((p) => p.kind === "hook");
|
|
413
|
+
expect(hookPattern?.kind).toBe("hook");
|
|
414
|
+
if (hookPattern?.kind === "hook") {
|
|
415
|
+
expect(hookPattern.target).toEqual({ allOf: "product" });
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
// Regression guard for the class of bug the r.exposesApi/r.usesApi fold
|
|
421
|
+
// hit: a registrar-shape change (there, removing a method; here, adding a
|
|
422
|
+
// nested optional field) must survive the Designer's parse→render→parse
|
|
423
|
+
// cycle, not just a TS compile of the framework itself. r.screen()'s `nav`
|
|
424
|
+
// sugar is a generic nested object on an already-generic pattern (no
|
|
425
|
+
// per-field extractor/renderer), so this is the cheap case — but proving
|
|
426
|
+
// it beats assuming it.
|
|
427
|
+
const SCREEN_WITH_NAV_FEATURE = `
|
|
428
|
+
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
429
|
+
|
|
430
|
+
defineFeature("shop", (r) => {
|
|
431
|
+
r.entity("product", { fields: { name: { type: "text" } } });
|
|
432
|
+
r.screen({
|
|
433
|
+
id: "products",
|
|
434
|
+
type: "entityList",
|
|
435
|
+
entity: "product",
|
|
436
|
+
columns: ["name"],
|
|
437
|
+
nav: { label: "shop:nav.products", icon: "box", order: 5 },
|
|
438
|
+
});
|
|
439
|
+
});
|
|
440
|
+
`;
|
|
441
|
+
|
|
442
|
+
describe("render → parse roundtrip — r.screen({ nav }) inline sugar", () => {
|
|
443
|
+
test("nested nav object survives parse → render → parse unchanged", () => {
|
|
444
|
+
const initial = parse(SCREEN_WITH_NAV_FEATURE);
|
|
445
|
+
const rendered = renderFeatureFile({
|
|
446
|
+
featureName: initial.featureName ?? "",
|
|
447
|
+
patterns: initial.patterns,
|
|
448
|
+
});
|
|
449
|
+
const reparsed = parse(rendered);
|
|
450
|
+
expect(reparsed.patterns.map(stripLocations)).toEqual(initial.patterns.map(stripLocations));
|
|
451
|
+
|
|
452
|
+
const screenPattern = reparsed.patterns.find((p) => p.kind === "screen");
|
|
453
|
+
expect(screenPattern?.kind).toBe("screen");
|
|
454
|
+
if (screenPattern?.kind === "screen") {
|
|
455
|
+
expect(screenPattern.definition).toMatchObject({
|
|
456
|
+
nav: { label: "shop:nav.products", icon: "box", order: 5 },
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
});
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
const DEFINE_EVENT_WITH_MIGRATIONS_FEATURE = `
|
|
463
|
+
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
464
|
+
import { z } from "zod";
|
|
465
|
+
|
|
466
|
+
defineFeature("billing", (r) => {
|
|
467
|
+
r.defineEvent("invoicePaid", z.object({ totalCents: z.number() }), {
|
|
468
|
+
version: 2,
|
|
469
|
+
migrations: [
|
|
470
|
+
{
|
|
471
|
+
fromVersion: 1,
|
|
472
|
+
toVersion: 2,
|
|
473
|
+
transform: (payload: unknown) => ({ totalCents: Math.round((payload as { total: number }).total * 100) }),
|
|
474
|
+
},
|
|
475
|
+
],
|
|
476
|
+
});
|
|
477
|
+
});
|
|
478
|
+
`;
|
|
479
|
+
|
|
480
|
+
describe("render → parse roundtrip — r.defineEvent({ migrations }) fold", () => {
|
|
481
|
+
test("migrations array survives parse → render → parse unchanged", () => {
|
|
482
|
+
const initial = parse(DEFINE_EVENT_WITH_MIGRATIONS_FEATURE);
|
|
483
|
+
const rendered = renderFeatureFile({
|
|
484
|
+
featureName: initial.featureName ?? "",
|
|
485
|
+
patterns: initial.patterns,
|
|
486
|
+
});
|
|
487
|
+
const reparsed = parse(rendered);
|
|
488
|
+
expect(reparsed.patterns.map(stripLocations)).toEqual(initial.patterns.map(stripLocations));
|
|
489
|
+
|
|
490
|
+
const eventPattern = reparsed.patterns.find((p) => p.kind === "defineEvent");
|
|
491
|
+
expect(eventPattern?.kind).toBe("defineEvent");
|
|
492
|
+
if (eventPattern?.kind === "defineEvent") {
|
|
493
|
+
expect(eventPattern.version).toBe(2);
|
|
494
|
+
expect(Object.keys(eventPattern.migrations ?? {})).toEqual(["1"]);
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
// --- Real-compile check ---------------------------------------------------
|
|
500
|
+
//
|
|
501
|
+
// Everything above proves parse(render(patterns)) is structurally faithful.
|
|
502
|
+
// It does NOT prove the rendered code actually compiles against the real
|
|
503
|
+
// FeatureRegistrar type — parse() runs against a bare in-memory Project with
|
|
504
|
+
// no lib/module resolution, so a rendered call can be well-formed AST and
|
|
505
|
+
// still be a type error against the real registrar (e.g. a removed method).
|
|
506
|
+
// That gap let the r.usesApi removal (folded into r.requires({apis})) pass
|
|
507
|
+
// the full 4960-test suite silently; only the visual Designer would have hit
|
|
508
|
+
// the broken shape.
|
|
509
|
+
//
|
|
510
|
+
// This Project resolves `@cosmicdrift/kumiko-framework/*` against the real
|
|
511
|
+
// framework source (unlike parse()'s Project, dependency resolution is NOT
|
|
512
|
+
// skipped), so `r` in a compiled fixture is the real FeatureRegistrar, not a
|
|
513
|
+
// structural stand-in.
|
|
514
|
+
const FRAMEWORK_TSCONFIG_PATH = path.join(import.meta.dir, "../../../../tsconfig.json");
|
|
515
|
+
|
|
516
|
+
const compileProject = new Project({
|
|
517
|
+
tsConfigFilePath: FRAMEWORK_TSCONFIG_PATH,
|
|
518
|
+
skipAddingFilesFromTsConfig: true,
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
let compileCheckCounter = 0;
|
|
522
|
+
|
|
523
|
+
function compileAgainstRegistrar(source: string): readonly string[] {
|
|
524
|
+
compileCheckCounter += 1;
|
|
525
|
+
const filePath = path.join(
|
|
526
|
+
import.meta.dir,
|
|
527
|
+
`__generated__/compile-check-${compileCheckCounter}.gen.ts`,
|
|
528
|
+
);
|
|
529
|
+
const sourceFile = compileProject.createSourceFile(filePath, source, { overwrite: true });
|
|
530
|
+
const diagnostics = sourceFile.getPreEmitDiagnostics().map((d) => {
|
|
531
|
+
const text = ts.flattenDiagnosticMessageText(d.compilerObject.messageText, "\n");
|
|
532
|
+
return `${d.getLineNumber()}: ${text}`;
|
|
533
|
+
});
|
|
534
|
+
sourceFile.forget();
|
|
535
|
+
return diagnostics;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
function renderAndCompile(source: string): readonly string[] {
|
|
539
|
+
const { featureName, patterns } = parse(source);
|
|
540
|
+
const rendered = renderFeatureFile({ featureName: featureName ?? "", patterns });
|
|
541
|
+
return compileAgainstRegistrar(rendered);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
describe("render → compiles against the real FeatureRegistrar type", () => {
|
|
545
|
+
test("compile check has teeth: an unknown registrar method is reported", () => {
|
|
546
|
+
const diagnostics = compileAgainstRegistrar(`
|
|
547
|
+
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
548
|
+
|
|
549
|
+
defineFeature("teeth-check", (r) => {
|
|
550
|
+
r.methodThatDoesNotExist({ nope: true });
|
|
551
|
+
});
|
|
552
|
+
`);
|
|
553
|
+
expect(diagnostics.length).toBeGreaterThan(0);
|
|
554
|
+
expect(diagnostics.join("\n")).toContain("methodThatDoesNotExist");
|
|
555
|
+
}, 20_000);
|
|
556
|
+
|
|
557
|
+
test("positive control: a minimal always-matched-the-real-shape fixture compiles clean", () => {
|
|
558
|
+
const diagnostics = compileAgainstRegistrar(`
|
|
559
|
+
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
560
|
+
|
|
561
|
+
defineFeature("teeth-check-positive", (r) => {
|
|
562
|
+
r.systemScope();
|
|
563
|
+
r.describe("Minimal fixture proving the harness returns [] on real success.");
|
|
564
|
+
r.toggleable({ default: true });
|
|
565
|
+
});
|
|
566
|
+
`);
|
|
567
|
+
expect(diagnostics).toEqual([]);
|
|
568
|
+
}, 20_000);
|
|
569
|
+
|
|
570
|
+
test("STATIC_FEATURE's rendered header-data patterns compile clean", () => {
|
|
571
|
+
expect(renderAndCompile(STATIC_FEATURE)).toEqual([]);
|
|
572
|
+
}, 20_000);
|
|
573
|
+
|
|
574
|
+
test("r.defineEvent's rendered migrations array compiles against the real registrar", () => {
|
|
575
|
+
expect(renderAndCompile(DEFINE_EVENT_WITH_MIGRATIONS_FEATURE)).toEqual([]);
|
|
576
|
+
}, 20_000);
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
// One self-contained, compile-clean fixture per remaining pattern kind not
|
|
580
|
+
// already exercised above (STATIC_FEATURE / MIXED_FEATURE / HOOK_ALL_OF /
|
|
581
|
+
// SCREEN_WITH_NAV / DEFINE_EVENT_WITH_MIGRATIONS). Deliberately separate
|
|
582
|
+
// from the parse-roundtrip fixtures above: those were written to test
|
|
583
|
+
// parse/render symmetry, not to be type-correct (e.g. DEFINE_EVENT_WITH_
|
|
584
|
+
// MIGRATIONS_FEATURE uses `z` without importing it) — reusing them here
|
|
585
|
+
// would produce diagnostics unrelated to the registrar shape and defeat the
|
|
586
|
+
// point of an exact-match assertion.
|
|
587
|
+
//
|
|
588
|
+
// RAW_REF_FEATURE and the "unknown" pattern kind are excluded on purpose:
|
|
589
|
+
// raw-ref sentinels reference symbols that don't exist by design, and
|
|
590
|
+
// "unknown" is the parser's catch-all bucket for unrecognized r.calls, not
|
|
591
|
+
// a real user-authored pattern.
|
|
592
|
+
const MANIFEST_AND_CONFIG_FEATURE = `
|
|
593
|
+
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
594
|
+
import { z } from "zod";
|
|
595
|
+
|
|
596
|
+
defineFeature("catalog", (r) => {
|
|
597
|
+
r.systemScope();
|
|
598
|
+
r.describe("Product catalog and pricing.");
|
|
599
|
+
r.optionalRequires("promotions");
|
|
600
|
+
r.uiHints({ displayLabel: "Catalog", category: "Commerce", recommended: true });
|
|
601
|
+
r.readsConfig("auth.smtpHost");
|
|
602
|
+
r.translations({ keys: { en: { title: "Catalog" } } });
|
|
603
|
+
r.useExtension("audit-log", "item");
|
|
604
|
+
r.extendsRegistrar("audit-log", {});
|
|
605
|
+
r.envSchema(z.object({ CATALOG_API_KEY: z.string() }));
|
|
606
|
+
r.usesApi("compliance.forTenant");
|
|
607
|
+
r.exposesApi("catalog.pricingFor");
|
|
608
|
+
});
|
|
609
|
+
`;
|
|
610
|
+
|
|
611
|
+
// r.projection is deliberately excluded here: its `table` field (a Drizzle
|
|
612
|
+
// table reference) is dropped by the feature-ast renderer independent of
|
|
613
|
+
// the object-form/positional-form issue this fixture targets — a
|
|
614
|
+
// pre-existing, separately tracked gap (public-api-registrar-consolidation
|
|
615
|
+
// plan doc, kumiko-platform). multiStreamProjection below covers the
|
|
616
|
+
// `apply`-map shape without hitting it (its `table` is optional).
|
|
617
|
+
const INTEGRATION_FEATURE = `
|
|
618
|
+
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
619
|
+
|
|
620
|
+
defineFeature("fulfillment", (r) => {
|
|
621
|
+
r.job("reconcile-counts", { trigger: { manual: true } }, async (payload, context) => {
|
|
622
|
+
console.log(payload, context);
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
r.notification("itemLowStock", {
|
|
626
|
+
trigger: { on: "item:lowStock" },
|
|
627
|
+
recipient: () => null,
|
|
628
|
+
data: () => ({}),
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
r.authClaims(async () => ({}));
|
|
632
|
+
|
|
633
|
+
r.httpRoute({
|
|
634
|
+
method: "GET",
|
|
635
|
+
path: "/fulfillment/feed.xml",
|
|
636
|
+
handler: (c) => c.text("ok"),
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
r.multiStreamProjection({
|
|
640
|
+
name: "item-audit",
|
|
641
|
+
apply: {
|
|
642
|
+
"item.created": async (event, tx, ctx) => {
|
|
643
|
+
console.log(event, tx, ctx);
|
|
644
|
+
},
|
|
645
|
+
},
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
r.workspace({ id: "ops", label: "fulfillment:workspace.ops" });
|
|
649
|
+
|
|
650
|
+
r.treeActions({ list: {} });
|
|
651
|
+
});
|
|
652
|
+
`;
|
|
653
|
+
|
|
654
|
+
describe("render → compiles against the real FeatureRegistrar type — full pattern-kind coverage", () => {
|
|
655
|
+
test("manifest/config-only patterns compile clean", () => {
|
|
656
|
+
expect(renderAndCompile(MANIFEST_AND_CONFIG_FEATURE)).toEqual([]);
|
|
657
|
+
}, 20_000);
|
|
658
|
+
|
|
659
|
+
test("job/notification/httpRoute/projection/workspace patterns compile clean", () => {
|
|
660
|
+
expect(renderAndCompile(INTEGRATION_FEATURE)).toEqual([]);
|
|
661
|
+
}, 20_000);
|
|
662
|
+
});
|