@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
|
@@ -341,14 +341,20 @@ export type ScreenPattern = {
|
|
|
341
341
|
export type WriteHandlerPattern = {
|
|
342
342
|
readonly kind: "writeHandler";
|
|
343
343
|
readonly source: SourceLocation;
|
|
344
|
-
|
|
344
|
+
// handlerName/schemaSource/handlerBody are set together, or all left
|
|
345
|
+
// undefined for a single reference standing in for the whole handler
|
|
346
|
+
// (`r.writeHandler(handlerRef)`) that couldn't be resolved to an object
|
|
347
|
+
// literal — see #1007. An opaque pattern re-emits `source.raw` verbatim
|
|
348
|
+
// and, like UnknownPattern, has no PatternId variant (not individually
|
|
349
|
+
// patchable).
|
|
350
|
+
readonly handlerName?: string;
|
|
345
351
|
// schemaSource: the Zod call as source text (e.g. "z.object({...})").
|
|
346
352
|
// We keep it as an opaque block instead of decoding it back to JSON
|
|
347
353
|
// schema — Zod's full surface is too rich for a faithful round-trip.
|
|
348
|
-
readonly schemaSource
|
|
354
|
+
readonly schemaSource?: SourceLocation;
|
|
349
355
|
// handlerBody: the closure body as source text. Always opaque — AI
|
|
350
356
|
// generates raw TypeScript, no DSL interpretation.
|
|
351
|
-
readonly handlerBody
|
|
357
|
+
readonly handlerBody?: SourceLocation;
|
|
352
358
|
readonly access?: AccessRule;
|
|
353
359
|
readonly rateLimit?: RateLimitOption;
|
|
354
360
|
readonly unsafeSkipTransitionGuard?: boolean;
|
|
@@ -356,43 +362,48 @@ export type WriteHandlerPattern = {
|
|
|
356
362
|
|
|
357
363
|
// `r.queryHandler(...)` — registers a read handler: name, Zod input schema,
|
|
358
364
|
// handler closure, plus optional `access` and `rateLimit` rules. Read-side
|
|
359
|
-
// counterpart of `r.writeHandler` with the same header/body split.
|
|
365
|
+
// counterpart of `r.writeHandler` with the same header/body split. Opaque
|
|
366
|
+
// (no handlerName) for the same single-reference case as WriteHandlerPattern.
|
|
360
367
|
export type QueryHandlerPattern = {
|
|
361
368
|
readonly kind: "queryHandler";
|
|
362
369
|
readonly source: SourceLocation;
|
|
363
|
-
readonly handlerName
|
|
364
|
-
readonly schemaSource
|
|
365
|
-
readonly handlerBody
|
|
370
|
+
readonly handlerName?: string;
|
|
371
|
+
readonly schemaSource?: SourceLocation;
|
|
372
|
+
readonly handlerBody?: SourceLocation;
|
|
373
|
+
readonly access?: AccessRule;
|
|
374
|
+
readonly rateLimit?: RateLimitOption;
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
// `r.streamHandler(...)` — registers a streaming read handler: name, Zod
|
|
378
|
+
// input schema, async-generator handler closure, plus optional `access` and
|
|
379
|
+
// `rateLimit` rules. Same header/body split and opaque single-reference
|
|
380
|
+
// case as QueryHandlerPattern.
|
|
381
|
+
export type StreamHandlerPattern = {
|
|
382
|
+
readonly kind: "streamHandler";
|
|
383
|
+
readonly source: SourceLocation;
|
|
384
|
+
readonly handlerName?: string;
|
|
385
|
+
readonly schemaSource?: SourceLocation;
|
|
386
|
+
readonly handlerBody?: SourceLocation;
|
|
366
387
|
readonly access?: AccessRule;
|
|
367
388
|
readonly rateLimit?: RateLimitOption;
|
|
368
389
|
};
|
|
369
390
|
|
|
370
391
|
// `r.hook(type, target, fn, options?)` — attaches a lifecycle hook
|
|
371
392
|
// (`validation`, `preSave`, `postSave`, `preDelete`, `postDelete`,
|
|
372
|
-
// `preQuery`, `postQuery`) to one or more target handlers
|
|
373
|
-
//
|
|
374
|
-
//
|
|
393
|
+
// `preQuery`, `postQuery`) to one or more target handlers, or — for
|
|
394
|
+
// postSave/preDelete/postDelete/postQuery — to `{ allOf: entityRef }`
|
|
395
|
+
// ("every write/query handler of this entity", replacing the old
|
|
396
|
+
// `r.entityHook(type, entity, fn)`). Post-hooks accept a `phase` option;
|
|
397
|
+
// `preDelete` always runs in-transaction — it guards the delete. The hook
|
|
398
|
+
// body is an opaque code span.
|
|
375
399
|
export type HookPattern = {
|
|
376
400
|
readonly kind: "hook";
|
|
377
401
|
readonly source: SourceLocation;
|
|
378
402
|
readonly hookType: LifecycleHookType | "validation";
|
|
379
|
-
// r.hook accepts a single target
|
|
380
|
-
// the Designer can render the
|
|
381
|
-
|
|
382
|
-
readonly
|
|
383
|
-
readonly phase?: HookPhase;
|
|
384
|
-
};
|
|
385
|
-
|
|
386
|
-
// `r.entityHook(type, entity, fn, options?)` — like `r.hook`, but bound to
|
|
387
|
-
// an entity instead of individual handlers: `postSave`, `preDelete`, and
|
|
388
|
-
// `postDelete` fire on every matching write. The runtime API additionally
|
|
389
|
-
// accepts `postQuery` (fires for all query-handlers of the entity), but
|
|
390
|
-
// this pattern type only represents the three write-side hooks.
|
|
391
|
-
export type EntityHookPattern = {
|
|
392
|
-
readonly kind: "entityHook";
|
|
393
|
-
readonly source: SourceLocation;
|
|
394
|
-
readonly hookType: "postSave" | "preDelete" | "postDelete";
|
|
395
|
-
readonly entityName: string;
|
|
403
|
+
// r.hook accepts a single target, a list, or an entity-wide { allOf }
|
|
404
|
+
// target; we keep all three shapes so the Designer can render the
|
|
405
|
+
// original author intent.
|
|
406
|
+
readonly target: string | readonly string[] | { readonly allOf: string };
|
|
396
407
|
readonly fnBody: SourceLocation;
|
|
397
408
|
readonly phase?: HookPhase;
|
|
398
409
|
};
|
|
@@ -445,18 +456,6 @@ export type AuthClaimsPattern = {
|
|
|
445
456
|
readonly fnBody: SourceLocation;
|
|
446
457
|
};
|
|
447
458
|
|
|
448
|
-
// `r.tree(provider)` — the feature's top-level tree provider: a subscribe
|
|
449
|
-
// function (emit-fn in, unsubscribe-fn out) that feeds workspaces with
|
|
450
|
-
// `navigation: "tree"`. Features without `r.tree()` are invisible there —
|
|
451
|
-
// provider presence IS the filter, there is no workspace mapping.
|
|
452
|
-
// Closure-only, no header form: the Designer renders a read-only code
|
|
453
|
-
// block, the AI patcher overwrites the span verbatim.
|
|
454
|
-
export type TreePattern = {
|
|
455
|
-
readonly kind: "tree";
|
|
456
|
-
readonly source: SourceLocation;
|
|
457
|
-
readonly providerBody: SourceLocation;
|
|
458
|
-
};
|
|
459
|
-
|
|
460
459
|
// `r.httpRoute(definition)` — mounts an HTTP route owned by the feature,
|
|
461
460
|
// outside the dispatcher pipeline (not under `/api/write|query|batch`) —
|
|
462
461
|
// for RSS/Atom feeds, OG images, OpenAPI specs and similar. Duplicate
|
|
@@ -506,29 +505,22 @@ export type MultiStreamProjectionPattern = {
|
|
|
506
505
|
// `r.defineEvent(name, schema, options?)` — registers an event payload
|
|
507
506
|
// shape and returns the qualified `EventDef`, so callers pass `.name` to
|
|
508
507
|
// `ctx.appendEvent` instead of hand-building `<feature>:event:<short>`.
|
|
509
|
-
// `options.version` declares the CURRENT schema generation (default 1)
|
|
510
|
-
//
|
|
511
|
-
//
|
|
508
|
+
// `options.version` declares the CURRENT schema generation (default 1).
|
|
509
|
+
// `options.migrations` is a step-wise upcast chain — keyed by fromVersion
|
|
510
|
+
// (toVersion is always fromVersion + 1, enforced at registration, so it is
|
|
511
|
+
// not stored separately); the framework refuses to boot if the chain from
|
|
512
|
+
// 1 to `version` has gaps. Formerly a separate `r.eventMigration()` call
|
|
513
|
+
// per step, folded in here (#1082 step 8) — an event and its schema
|
|
514
|
+
// evolution are one lifecycle, not two registrar concepts.
|
|
512
515
|
export type DefineEventPattern = {
|
|
513
516
|
readonly kind: "defineEvent";
|
|
514
517
|
readonly source: SourceLocation;
|
|
515
518
|
readonly eventName: string;
|
|
516
519
|
readonly schemaSource: SourceLocation;
|
|
517
520
|
readonly version?: number;
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
// registers a step-wise payload upcast for event-schema evolution.
|
|
522
|
-
// `toVersion` must be `fromVersion + 1`; chain larger jumps step by step.
|
|
523
|
-
// Transforms are pure old-payload-in/new-payload-out functions and run once
|
|
524
|
-
// per READ, not once per event persisted — keep them cheap.
|
|
525
|
-
export type EventMigrationPattern = {
|
|
526
|
-
readonly kind: "eventMigration";
|
|
527
|
-
readonly source: SourceLocation;
|
|
528
|
-
readonly eventName: string;
|
|
529
|
-
readonly fromVersion: number;
|
|
530
|
-
readonly toVersion: number;
|
|
531
|
-
readonly transformBody: SourceLocation;
|
|
521
|
+
// Map fromVersion (as string, e.g. "1") → SourceLocation of the transform
|
|
522
|
+
// closure for the fromVersion → fromVersion+1 step.
|
|
523
|
+
readonly migrations?: Readonly<Record<string, SourceLocation>>;
|
|
532
524
|
};
|
|
533
525
|
|
|
534
526
|
// `r.extendsRegistrar(extensionName, def)` — declares a named, globally
|
|
@@ -614,8 +606,8 @@ export type FeaturePattern =
|
|
|
614
606
|
| ScreenPattern
|
|
615
607
|
| WriteHandlerPattern
|
|
616
608
|
| QueryHandlerPattern
|
|
609
|
+
| StreamHandlerPattern
|
|
617
610
|
| HookPattern
|
|
618
|
-
| EntityHookPattern
|
|
619
611
|
| JobPattern
|
|
620
612
|
| NotificationPattern
|
|
621
613
|
| AuthClaimsPattern
|
|
@@ -623,9 +615,7 @@ export type FeaturePattern =
|
|
|
623
615
|
| ProjectionPattern
|
|
624
616
|
| MultiStreamProjectionPattern
|
|
625
617
|
| DefineEventPattern
|
|
626
|
-
| EventMigrationPattern
|
|
627
618
|
| ExtendsRegistrarPattern
|
|
628
|
-
| TreePattern
|
|
629
619
|
| EnvSchemaPattern
|
|
630
620
|
// Catch-all
|
|
631
621
|
| UnknownPattern;
|
|
@@ -672,19 +662,17 @@ export function getEditability(pattern: FeaturePattern): Editability {
|
|
|
672
662
|
case "screen":
|
|
673
663
|
case "writeHandler":
|
|
674
664
|
case "queryHandler":
|
|
665
|
+
case "streamHandler":
|
|
675
666
|
case "hook":
|
|
676
|
-
case "entityHook":
|
|
677
667
|
case "job":
|
|
678
668
|
case "notification":
|
|
679
669
|
case "httpRoute":
|
|
680
670
|
case "projection":
|
|
681
671
|
case "multiStreamProjection":
|
|
682
672
|
case "defineEvent":
|
|
683
|
-
case "eventMigration":
|
|
684
673
|
return "mixed";
|
|
685
674
|
case "authClaims":
|
|
686
675
|
case "extendsRegistrar":
|
|
687
|
-
case "tree":
|
|
688
676
|
case "envSchema":
|
|
689
677
|
case "uiHints":
|
|
690
678
|
case "unknown":
|
|
@@ -16,16 +16,15 @@
|
|
|
16
16
|
// `// kumiko-feature-version: 1`. Future format bumps run a dedicated
|
|
17
17
|
// migrator over the version comment.
|
|
18
18
|
|
|
19
|
+
import { isRawRefSentinel } from "./extractors/shared";
|
|
19
20
|
import type {
|
|
20
21
|
AuthClaimsPattern,
|
|
21
22
|
ClaimKeyPattern,
|
|
22
23
|
ConfigPattern,
|
|
23
24
|
DefineEventPattern,
|
|
24
25
|
DescribePattern,
|
|
25
|
-
EntityHookPattern,
|
|
26
26
|
EntityPattern,
|
|
27
27
|
EnvSchemaPattern,
|
|
28
|
-
EventMigrationPattern,
|
|
29
28
|
ExposesApiPattern,
|
|
30
29
|
ExtendsRegistrarPattern,
|
|
31
30
|
FeaturePattern,
|
|
@@ -45,11 +44,11 @@ import type {
|
|
|
45
44
|
RequiresPattern,
|
|
46
45
|
ScreenPattern,
|
|
47
46
|
SecretPattern,
|
|
47
|
+
StreamHandlerPattern,
|
|
48
48
|
SystemScopePattern,
|
|
49
49
|
ToggleablePattern,
|
|
50
50
|
TranslationsPattern,
|
|
51
51
|
TreeActionsPattern,
|
|
52
|
-
TreePattern,
|
|
53
52
|
UiHintsPattern,
|
|
54
53
|
UnknownPattern,
|
|
55
54
|
UseExtensionPattern,
|
|
@@ -111,10 +110,10 @@ export function renderPattern(pattern: FeaturePattern): string {
|
|
|
111
110
|
return renderWriteHandler(pattern);
|
|
112
111
|
case "queryHandler":
|
|
113
112
|
return renderQueryHandler(pattern);
|
|
113
|
+
case "streamHandler":
|
|
114
|
+
return renderStreamHandler(pattern);
|
|
114
115
|
case "hook":
|
|
115
116
|
return renderHook(pattern);
|
|
116
|
-
case "entityHook":
|
|
117
|
-
return renderEntityHook(pattern);
|
|
118
117
|
case "job":
|
|
119
118
|
return renderJob(pattern);
|
|
120
119
|
case "notification":
|
|
@@ -129,8 +128,6 @@ export function renderPattern(pattern: FeaturePattern): string {
|
|
|
129
128
|
return renderMultiStreamProjection(pattern);
|
|
130
129
|
case "defineEvent":
|
|
131
130
|
return renderDefineEvent(pattern);
|
|
132
|
-
case "eventMigration":
|
|
133
|
-
return renderEventMigration(pattern);
|
|
134
131
|
case "extendsRegistrar":
|
|
135
132
|
return renderExtendsRegistrar(pattern);
|
|
136
133
|
case "usesApi":
|
|
@@ -139,8 +136,6 @@ export function renderPattern(pattern: FeaturePattern): string {
|
|
|
139
136
|
return renderExposesApi(pattern);
|
|
140
137
|
case "treeActions":
|
|
141
138
|
return renderTreeActions(pattern);
|
|
142
|
-
case "tree":
|
|
143
|
-
return renderTree(pattern);
|
|
144
139
|
case "envSchema":
|
|
145
140
|
return renderEnvSchema(pattern);
|
|
146
141
|
case "unknown":
|
|
@@ -177,6 +172,7 @@ const SINGLE_LINE_WIDTH = 80;
|
|
|
177
172
|
* multi-line otherwise — biome-stable in both branches.
|
|
178
173
|
*/
|
|
179
174
|
export function renderValue(value: unknown, indent = 0): string {
|
|
175
|
+
if (isRawRefSentinel(value)) return value.__raw;
|
|
180
176
|
if (value === null) return "null";
|
|
181
177
|
if (typeof value === "string") return JSON.stringify(value);
|
|
182
178
|
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
@@ -243,6 +239,13 @@ function renderDescribe(p: DescribePattern): string {
|
|
|
243
239
|
}
|
|
244
240
|
|
|
245
241
|
function renderEntity(p: EntityPattern): string {
|
|
242
|
+
// A whole-value raw-ref (`r.entity("x", eventEntity)`) can't be spread
|
|
243
|
+
// into the merged Object-Form without losing `name` to the sentinel
|
|
244
|
+
// shortcut in renderValue — fall back to the classic positional form,
|
|
245
|
+
// which keeps the reference verbatim alongside the name.
|
|
246
|
+
if (isRawRefSentinel(p.definition)) {
|
|
247
|
+
return `r.entity(${JSON.stringify(p.entityName)}, ${p.definition.__raw});`;
|
|
248
|
+
}
|
|
246
249
|
// Inline `name` into the definition object — canonical Object-Form
|
|
247
250
|
// is a single arg with name-as-property.
|
|
248
251
|
const merged = { name: p.entityName, ...p.definition };
|
|
@@ -250,6 +253,9 @@ function renderEntity(p: EntityPattern): string {
|
|
|
250
253
|
}
|
|
251
254
|
|
|
252
255
|
function renderRelation(p: RelationPattern): string {
|
|
256
|
+
if (isRawRefSentinel(p.definition)) {
|
|
257
|
+
return `r.relation(${JSON.stringify(p.entityName)}, ${JSON.stringify(p.relationName)}, ${p.definition.__raw});`;
|
|
258
|
+
}
|
|
253
259
|
const merged = { entity: p.entityName, name: p.relationName, ...p.definition };
|
|
254
260
|
return `r.relation(${renderValue(merged)});`;
|
|
255
261
|
}
|
|
@@ -271,11 +277,17 @@ function renderTranslations(p: TranslationsPattern): string {
|
|
|
271
277
|
}
|
|
272
278
|
|
|
273
279
|
function renderMetric(p: MetricPattern): string {
|
|
280
|
+
if (isRawRefSentinel(p.options)) {
|
|
281
|
+
return `r.metric(${JSON.stringify(p.shortName)}, ${p.options.__raw});`;
|
|
282
|
+
}
|
|
274
283
|
const merged = { name: p.shortName, ...p.options };
|
|
275
284
|
return `r.metric(${renderValue(merged)});`;
|
|
276
285
|
}
|
|
277
286
|
|
|
278
287
|
function renderSecret(p: SecretPattern): string {
|
|
288
|
+
if (isRawRefSentinel(p.options)) {
|
|
289
|
+
return `r.secret(${JSON.stringify(p.shortName)}, ${p.options.__raw});`;
|
|
290
|
+
}
|
|
279
291
|
const merged = { name: p.shortName, ...p.options };
|
|
280
292
|
return `r.secret(${renderValue(merged)});`;
|
|
281
293
|
}
|
|
@@ -294,6 +306,9 @@ function renderReferenceData(p: ReferenceDataPattern): string {
|
|
|
294
306
|
}
|
|
295
307
|
|
|
296
308
|
function renderUseExtension(p: UseExtensionPattern): string {
|
|
309
|
+
if (isRawRefSentinel(p.options)) {
|
|
310
|
+
return `r.useExtension(${JSON.stringify(p.extensionName)}, ${JSON.stringify(p.entityName)}, ${p.options.__raw});`;
|
|
311
|
+
}
|
|
297
312
|
const merged: Record<string, unknown> = {
|
|
298
313
|
name: p.extensionName,
|
|
299
314
|
entity: p.entityName,
|
|
@@ -359,10 +374,11 @@ function reindentBody(raw: string, newIndent: string): string {
|
|
|
359
374
|
}
|
|
360
375
|
|
|
361
376
|
function renderWriteHandler(p: WriteHandlerPattern): string {
|
|
377
|
+
if (p.handlerName === undefined) return p.source.raw;
|
|
362
378
|
const lines: string[] = ["r.writeHandler({"];
|
|
363
379
|
lines.push(` name: ${JSON.stringify(p.handlerName)},`);
|
|
364
|
-
lines.push(` schema: ${reindentBody(p.schemaSource
|
|
365
|
-
lines.push(` handler: ${reindentBody(p.handlerBody
|
|
380
|
+
lines.push(` schema: ${reindentBody(p.schemaSource?.raw ?? "", PATTERN_INDENT)},`);
|
|
381
|
+
lines.push(` handler: ${reindentBody(p.handlerBody?.raw ?? "", PATTERN_INDENT)},`);
|
|
366
382
|
if (p.access !== undefined) lines.push(` access: ${renderValue(p.access)},`);
|
|
367
383
|
if (p.rateLimit !== undefined) lines.push(` rateLimit: ${renderValue(p.rateLimit)},`);
|
|
368
384
|
if (p.unsafeSkipTransitionGuard === true) lines.push(" unsafeSkipTransitionGuard: true,");
|
|
@@ -371,30 +387,39 @@ function renderWriteHandler(p: WriteHandlerPattern): string {
|
|
|
371
387
|
}
|
|
372
388
|
|
|
373
389
|
function renderQueryHandler(p: QueryHandlerPattern): string {
|
|
390
|
+
if (p.handlerName === undefined) return p.source.raw;
|
|
374
391
|
const lines: string[] = ["r.queryHandler({"];
|
|
375
392
|
lines.push(` name: ${JSON.stringify(p.handlerName)},`);
|
|
376
|
-
lines.push(` schema: ${reindentBody(p.schemaSource
|
|
377
|
-
lines.push(` handler: ${reindentBody(p.handlerBody
|
|
393
|
+
lines.push(` schema: ${reindentBody(p.schemaSource?.raw ?? "", PATTERN_INDENT)},`);
|
|
394
|
+
lines.push(` handler: ${reindentBody(p.handlerBody?.raw ?? "", PATTERN_INDENT)},`);
|
|
378
395
|
if (p.access !== undefined) lines.push(` access: ${renderValue(p.access)},`);
|
|
379
396
|
if (p.rateLimit !== undefined) lines.push(` rateLimit: ${renderValue(p.rateLimit)},`);
|
|
380
397
|
lines.push("});");
|
|
381
398
|
return lines.join("\n");
|
|
382
399
|
}
|
|
383
400
|
|
|
384
|
-
function
|
|
385
|
-
|
|
386
|
-
lines
|
|
387
|
-
lines.push(`
|
|
388
|
-
lines.push(`
|
|
389
|
-
|
|
401
|
+
function renderStreamHandler(p: StreamHandlerPattern): string {
|
|
402
|
+
if (p.handlerName === undefined) return p.source.raw;
|
|
403
|
+
const lines: string[] = ["r.streamHandler({"];
|
|
404
|
+
lines.push(` name: ${JSON.stringify(p.handlerName)},`);
|
|
405
|
+
lines.push(` schema: ${reindentBody(p.schemaSource?.raw ?? "", PATTERN_INDENT)},`);
|
|
406
|
+
lines.push(` handler: ${reindentBody(p.handlerBody?.raw ?? "", PATTERN_INDENT)},`);
|
|
407
|
+
if (p.access !== undefined) lines.push(` access: ${renderValue(p.access)},`);
|
|
408
|
+
if (p.rateLimit !== undefined) lines.push(` rateLimit: ${renderValue(p.rateLimit)},`);
|
|
390
409
|
lines.push("});");
|
|
391
410
|
return lines.join("\n");
|
|
392
411
|
}
|
|
393
412
|
|
|
394
|
-
function
|
|
395
|
-
|
|
413
|
+
function renderHookTarget(target: HookPattern["target"]): string {
|
|
414
|
+
if (typeof target === "string") return renderValue(target);
|
|
415
|
+
if ("allOf" in target) return `{ allOf: ${JSON.stringify(target.allOf)} }`;
|
|
416
|
+
return renderValue([...target]);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function renderHook(p: HookPattern): string {
|
|
420
|
+
const lines: string[] = ["r.hook({"];
|
|
396
421
|
lines.push(` type: ${JSON.stringify(p.hookType)},`);
|
|
397
|
-
lines.push(`
|
|
422
|
+
lines.push(` target: ${renderHookTarget(p.target)},`);
|
|
398
423
|
lines.push(` handler: ${reindentBody(p.fnBody.raw, PATTERN_INDENT)},`);
|
|
399
424
|
if (p.phase !== undefined) lines.push(` phase: ${JSON.stringify(p.phase)},`);
|
|
400
425
|
lines.push("});");
|
|
@@ -433,16 +458,11 @@ function renderAuthClaims(p: AuthClaimsPattern): string {
|
|
|
433
458
|
return `r.authClaims(${p.fnBody.raw});`;
|
|
434
459
|
}
|
|
435
460
|
|
|
436
|
-
//
|
|
437
|
-
// renderWorkspace), tree is opaque-only (mirrors renderAuthClaims).
|
|
461
|
+
// treeActions is a static object-literal (mirrors renderWorkspace).
|
|
438
462
|
function renderTreeActions(p: TreeActionsPattern): string {
|
|
439
463
|
return `r.treeActions(${renderValue(p.definitions)});`;
|
|
440
464
|
}
|
|
441
465
|
|
|
442
|
-
function renderTree(p: TreePattern): string {
|
|
443
|
-
return `r.tree(${p.providerBody.raw});`;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
466
|
function renderHttpRoute(p: HttpRoutePattern): string {
|
|
447
467
|
const lines: string[] = ["r.httpRoute({"];
|
|
448
468
|
lines.push(` method: ${JSON.stringify(p.method)},`);
|
|
@@ -486,20 +506,25 @@ function renderMultiStreamProjection(p: MultiStreamProjectionPattern): string {
|
|
|
486
506
|
}
|
|
487
507
|
|
|
488
508
|
function renderDefineEvent(p: DefineEventPattern): string {
|
|
489
|
-
const
|
|
490
|
-
|
|
491
|
-
|
|
509
|
+
const migrationEntries = p.migrations !== undefined ? Object.entries(p.migrations) : [];
|
|
510
|
+
const hasOptions = p.version !== undefined || migrationEntries.length > 0;
|
|
511
|
+
if (!hasOptions) {
|
|
512
|
+
return `r.defineEvent(${JSON.stringify(p.eventName)}, ${p.schemaSource.raw});`;
|
|
513
|
+
}
|
|
514
|
+
const lines: string[] = [
|
|
515
|
+
`r.defineEvent(${JSON.stringify(p.eventName)}, ${p.schemaSource.raw}, {`,
|
|
516
|
+
];
|
|
492
517
|
if (p.version !== undefined) lines.push(` version: ${p.version},`);
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
518
|
+
if (migrationEntries.length > 0) {
|
|
519
|
+
lines.push(" migrations: [");
|
|
520
|
+
for (const [fromVersion, transformBody] of migrationEntries) {
|
|
521
|
+
const from = Number(fromVersion);
|
|
522
|
+
lines.push(
|
|
523
|
+
` { fromVersion: ${from}, toVersion: ${from + 1}, transform: ${transformBody.raw} },`,
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
lines.push(" ],");
|
|
527
|
+
}
|
|
503
528
|
lines.push("});");
|
|
504
529
|
return lines.join("\n");
|
|
505
530
|
}
|
|
@@ -571,9 +596,7 @@ function weaveOpaque(
|
|
|
571
596
|
}
|
|
572
597
|
|
|
573
598
|
function renderValueWithRawSlots(value: WovenValue, indent: number): string {
|
|
574
|
-
if (value
|
|
575
|
-
return (value as { __raw: string }).__raw;
|
|
576
|
-
}
|
|
599
|
+
if (isRawRefSentinel(value)) return value.__raw;
|
|
577
600
|
if (Array.isArray(value)) {
|
|
578
601
|
if (value.length === 0) return "[]";
|
|
579
602
|
const inner = value
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import type { ZodType, z } from "zod";
|
|
2
|
+
import { LifecycleHookTypes } from "./constants";
|
|
3
|
+
import type {
|
|
4
|
+
AuthClaimsFn,
|
|
5
|
+
BootCheckFn,
|
|
6
|
+
ClaimKeyDefinition,
|
|
7
|
+
ConfigKeyDefinition,
|
|
8
|
+
ConfigSeedDef,
|
|
9
|
+
EntityDefinition,
|
|
10
|
+
EntityProjectionExtension,
|
|
11
|
+
EventMigrationDef,
|
|
12
|
+
ExtensionSelectorDef,
|
|
13
|
+
FeatureMetricDef,
|
|
14
|
+
JobDefinition,
|
|
15
|
+
LifecycleHookFn,
|
|
16
|
+
MultiStreamProjectionDefinition,
|
|
17
|
+
NotificationDefinition,
|
|
18
|
+
OwnedFn,
|
|
19
|
+
PhasedHook,
|
|
20
|
+
PostDeleteHookFn,
|
|
21
|
+
PostQueryHookFn,
|
|
22
|
+
PostSaveHookFn,
|
|
23
|
+
PreDeleteHookFn,
|
|
24
|
+
ProjectionDefinition,
|
|
25
|
+
QueryHandlerDef,
|
|
26
|
+
ReferenceDataDef,
|
|
27
|
+
RegistrarExtensionDef,
|
|
28
|
+
RegistrarExtensionRegistration,
|
|
29
|
+
RelationDefinition,
|
|
30
|
+
SearchPayloadContributorFn,
|
|
31
|
+
SecretKeyDefinition,
|
|
32
|
+
StoreTableEntry,
|
|
33
|
+
StreamHandlerDef,
|
|
34
|
+
TranslationKeys,
|
|
35
|
+
TreeActionDef,
|
|
36
|
+
UiHints,
|
|
37
|
+
ValidationHookFn,
|
|
38
|
+
WriteHandlerDef,
|
|
39
|
+
} from "./types";
|
|
40
|
+
import type { HttpRouteDefinition } from "./types/http-route";
|
|
41
|
+
import type { NavDefinition } from "./types/nav";
|
|
42
|
+
import type { ScreenDefinition } from "./types/screen";
|
|
43
|
+
import type { WorkspaceDefinition } from "./types/workspace";
|
|
44
|
+
|
|
45
|
+
const LIFECYCLE_TYPES = Object.values(LifecycleHookTypes);
|
|
46
|
+
|
|
47
|
+
// Bundles every Record/Set/array/scalar defineFeature populates while the
|
|
48
|
+
// registrar's ~40 methods run — hoisted out of defineFeature's closure so a
|
|
49
|
+
// future move-diff (extracting each method into its own module) can thread
|
|
50
|
+
// it explicitly. Every field is held BY REFERENCE — no destructured copies.
|
|
51
|
+
export type FeatureBuilderState = {
|
|
52
|
+
requires: string[];
|
|
53
|
+
optionalRequires: string[];
|
|
54
|
+
requiredProjections: Set<string>;
|
|
55
|
+
requiredSteps: Set<string>;
|
|
56
|
+
entities: Record<string, EntityDefinition>;
|
|
57
|
+
entityTables: Record<string, unknown>;
|
|
58
|
+
relations: Record<string, Record<string, RelationDefinition>>;
|
|
59
|
+
writeHandlers: Record<string, WriteHandlerDef>;
|
|
60
|
+
queryHandlers: Record<string, QueryHandlerDef>;
|
|
61
|
+
streamHandlers: Record<string, StreamHandlerDef>;
|
|
62
|
+
validationHooks: Record<string, ValidationHookFn>;
|
|
63
|
+
lifecycleHooks: Record<string, Record<string, OwnedFn<LifecycleHookFn>[]>>;
|
|
64
|
+
phasedLifecycleHooks: Record<
|
|
65
|
+
"postSave" | "preDelete" | "postDelete",
|
|
66
|
+
Record<string, PhasedHook<LifecycleHookFn>[]>
|
|
67
|
+
>;
|
|
68
|
+
configKeys: Record<string, ConfigKeyDefinition>;
|
|
69
|
+
configSeeds: ConfigSeedDef[];
|
|
70
|
+
jobs: Record<string, JobDefinition>;
|
|
71
|
+
events: Record<string, { name: string; schema: ZodType; version: number }>;
|
|
72
|
+
eventMigrations: Record<string, EventMigrationDef[]>;
|
|
73
|
+
configReads: string[];
|
|
74
|
+
entityPostSave: Record<string, PhasedHook<PostSaveHookFn>[]>;
|
|
75
|
+
entityPreDelete: Record<string, PhasedHook<PreDeleteHookFn>[]>;
|
|
76
|
+
entityPostDelete: Record<string, PhasedHook<PostDeleteHookFn>[]>;
|
|
77
|
+
entityPostQuery: Record<string, OwnedFn<PostQueryHookFn>[]>;
|
|
78
|
+
searchPayloadExtensions: Record<string, OwnedFn<SearchPayloadContributorFn>[]>;
|
|
79
|
+
notifications: Record<string, NotificationDefinition>;
|
|
80
|
+
registrarExtensions: Record<string, RegistrarExtensionDef>;
|
|
81
|
+
extensionUsages: RegistrarExtensionRegistration[];
|
|
82
|
+
extensionSelectors: ExtensionSelectorDef[];
|
|
83
|
+
exposedApis: Set<string>;
|
|
84
|
+
usedApis: Set<string>;
|
|
85
|
+
bootChecks: BootCheckFn[];
|
|
86
|
+
referenceData: ReferenceDataDef[];
|
|
87
|
+
handlerEntityMappings: Record<string, string>;
|
|
88
|
+
metrics: Record<string, FeatureMetricDef>;
|
|
89
|
+
secretKeys: Record<string, SecretKeyDefinition>;
|
|
90
|
+
projections: Record<string, ProjectionDefinition>;
|
|
91
|
+
multiStreamProjections: Record<string, MultiStreamProjectionDefinition>;
|
|
92
|
+
entityProjectionExtensions: Record<string, EntityProjectionExtension[]>;
|
|
93
|
+
storeTables: Record<string, StoreTableEntry>;
|
|
94
|
+
authClaimsHooks: AuthClaimsFn[];
|
|
95
|
+
claimKeys: Record<string, ClaimKeyDefinition>;
|
|
96
|
+
screens: Record<string, ScreenDefinition>;
|
|
97
|
+
navs: Record<string, NavDefinition>;
|
|
98
|
+
workspaces: Record<string, WorkspaceDefinition>;
|
|
99
|
+
httpRoutes: Record<string, HttpRouteDefinition>;
|
|
100
|
+
translations: TranslationKeys;
|
|
101
|
+
isSystemScoped: boolean;
|
|
102
|
+
toggleableDefault: boolean | undefined;
|
|
103
|
+
description: string | undefined;
|
|
104
|
+
uiHints: UiHints | undefined;
|
|
105
|
+
treeActions: Readonly<Record<string, TreeActionDef>> | undefined;
|
|
106
|
+
envSchema: z.ZodObject<z.ZodRawShape> | undefined;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export function createInitialFeatureBuilderState(): FeatureBuilderState {
|
|
110
|
+
const lifecycleHooks: Record<string, Record<string, OwnedFn<LifecycleHookFn>[]>> = {};
|
|
111
|
+
for (const t of LIFECYCLE_TYPES) {
|
|
112
|
+
lifecycleHooks[t] = {};
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
requires: [],
|
|
116
|
+
optionalRequires: [],
|
|
117
|
+
requiredProjections: new Set<string>(),
|
|
118
|
+
requiredSteps: new Set<string>(),
|
|
119
|
+
entities: {},
|
|
120
|
+
entityTables: {},
|
|
121
|
+
relations: {},
|
|
122
|
+
writeHandlers: {},
|
|
123
|
+
queryHandlers: {},
|
|
124
|
+
streamHandlers: {},
|
|
125
|
+
validationHooks: {},
|
|
126
|
+
lifecycleHooks,
|
|
127
|
+
phasedLifecycleHooks: { postSave: {}, preDelete: {}, postDelete: {} },
|
|
128
|
+
configKeys: {},
|
|
129
|
+
configSeeds: [],
|
|
130
|
+
jobs: {},
|
|
131
|
+
events: {},
|
|
132
|
+
eventMigrations: {},
|
|
133
|
+
configReads: [],
|
|
134
|
+
entityPostSave: {},
|
|
135
|
+
entityPreDelete: {},
|
|
136
|
+
entityPostDelete: {},
|
|
137
|
+
entityPostQuery: {},
|
|
138
|
+
searchPayloadExtensions: {},
|
|
139
|
+
notifications: {},
|
|
140
|
+
registrarExtensions: {},
|
|
141
|
+
extensionUsages: [],
|
|
142
|
+
extensionSelectors: [],
|
|
143
|
+
exposedApis: new Set(),
|
|
144
|
+
usedApis: new Set(),
|
|
145
|
+
bootChecks: [],
|
|
146
|
+
referenceData: [],
|
|
147
|
+
handlerEntityMappings: {},
|
|
148
|
+
metrics: {},
|
|
149
|
+
secretKeys: {},
|
|
150
|
+
projections: {},
|
|
151
|
+
multiStreamProjections: {},
|
|
152
|
+
entityProjectionExtensions: {},
|
|
153
|
+
storeTables: {},
|
|
154
|
+
authClaimsHooks: [],
|
|
155
|
+
claimKeys: {},
|
|
156
|
+
screens: {},
|
|
157
|
+
navs: {},
|
|
158
|
+
workspaces: {},
|
|
159
|
+
httpRoutes: {},
|
|
160
|
+
translations: {},
|
|
161
|
+
isSystemScoped: false,
|
|
162
|
+
toggleableDefault: undefined,
|
|
163
|
+
description: undefined,
|
|
164
|
+
uiHints: undefined,
|
|
165
|
+
treeActions: undefined,
|
|
166
|
+
envSchema: undefined,
|
|
167
|
+
};
|
|
168
|
+
}
|