@cosmicdrift/kumiko-framework 0.387.0 → 0.389.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/AGENTS.md +9 -1
- package/agents/examples/anonymous-access.md +1 -1
- package/agents/examples/apex-landing.md +204 -0
- package/agents/examples/api-worker-split.md +64 -0
- package/agents/examples/app-config.md +14 -0
- package/agents/examples/auth-mfa.md +115 -0
- package/agents/examples/env-composition.md +28 -1
- package/agents/examples/golden-path.md +13 -1
- package/agents/examples/legal-pages.md +1 -1
- package/agents/examples/lifecycle-hooks.md +55 -2
- package/agents/examples/list-table-options.md +466 -0
- package/agents/examples/pdf-audit-export.md +4 -2
- package/agents/examples/prod-boot-options.md +16 -0
- package/agents/examples/rate-limiting.md +48 -0
- package/agents/examples/record-detail-layout.md +692 -0
- package/agents/examples/seed-migration.md +212 -0
- package/agents/examples/state-machine.md +3 -2
- package/agents/examples/tenant-isolation.md +73 -1
- package/agents/examples/wizard-form.md +941 -0
- package/agents/examples/writeform-section.md +548 -0
- package/agents/examples.md +1 -0
- package/agents/features.md +19 -2
- package/agents/widgets.md +2 -0
- package/dist/api/api-constants.d.ts +1 -0
- package/dist/api/api-constants.js +2 -0
- package/dist/api/auth-routes-shared.d.ts +2 -0
- package/dist/api/auth-routes-shared.js +5 -0
- package/dist/api/client-error-route.js +10 -5
- package/dist/api/entity-read-access.d.ts +2 -1
- package/dist/api/entity-read-access.js +14 -0
- package/dist/api/export/export-cells-reference.d.ts +9 -0
- package/dist/api/export/export-cells-reference.js +21 -0
- package/dist/api/export/export-cells.d.ts +11 -0
- package/dist/api/export/export-cells.js +136 -0
- package/dist/api/export/export-ciphertext-guard.d.ts +2 -0
- package/dist/api/export/export-ciphertext-guard.js +27 -0
- package/dist/api/export/export-columns.d.ts +29 -0
- package/dist/api/export/export-columns.js +85 -0
- package/dist/api/export/export-errors.d.ts +4 -0
- package/dist/api/export/export-errors.js +14 -0
- package/dist/api/export/export-route.d.ts +4 -0
- package/dist/api/export/export-route.js +74 -0
- package/dist/api/export/export-rows.d.ts +13 -0
- package/dist/api/export/export-rows.js +62 -0
- package/dist/api/export/export-screen.d.ts +12 -0
- package/dist/api/export/export-screen.js +47 -0
- package/dist/api/export/export-xlsx-writer.d.ts +4 -0
- package/dist/api/export/export-xlsx-writer.js +21 -0
- package/dist/api/extra-route.d.ts +4 -0
- package/dist/api/index.d.ts +3 -1
- package/dist/api/index.js +3 -1
- package/dist/api/pii-leak-guard.d.ts +3 -0
- package/dist/api/pii-leak-guard.js +3 -2
- package/dist/api/request-context.d.ts +1 -1
- package/dist/api/request-context.js +1 -1
- package/dist/api/routes.d.ts +16 -0
- package/dist/api/routes.js +2 -2
- package/dist/api/server-boot-checks.d.ts +10 -0
- package/dist/api/server-boot-checks.js +157 -0
- package/dist/api/server-event-dispatcher.d.ts +26 -0
- package/dist/api/server-event-dispatcher.js +208 -0
- package/dist/api/server-extra-routes.d.ts +11 -0
- package/dist/api/server-extra-routes.js +206 -0
- package/dist/api/server-middleware.d.ts +20 -0
- package/dist/api/server-middleware.js +211 -0
- package/dist/api/server-routes.d.ts +19 -0
- package/dist/api/server-routes.js +299 -0
- package/dist/api/server-websocket-routes.d.ts +4 -0
- package/dist/api/server-websocket-routes.js +108 -0
- package/dist/api/server-wiring.d.ts +32 -0
- package/dist/api/server-wiring.js +238 -0
- package/dist/api/server.d.ts +10 -15
- package/dist/api/server.js +48 -1251
- package/dist/api/session-cookies.js +4 -4
- package/dist/api/sse-route.d.ts +2 -1
- package/dist/api/sse-route.js +27 -13
- package/dist/config/index.d.ts +3 -1
- package/dist/crypto/owner-transition-rekey.d.ts +5 -1
- package/dist/crypto/owner-transition-rekey.js +1 -1
- package/dist/crypto/pg-kms-adapter.d.ts +1 -0
- package/dist/crypto/pg-kms-adapter.js +12 -18
- package/dist/crypto/pii-field-encryption.d.ts +5 -1
- package/dist/crypto/pii-field-encryption.js +3 -1
- package/dist/db/aggregate-sql.d.ts +23 -0
- package/dist/db/aggregate-sql.js +165 -0
- package/dist/db/closed-connection.d.ts +9 -0
- package/dist/db/closed-connection.js +88 -0
- package/dist/db/connection.d.ts +4 -5
- package/dist/db/connection.js +29 -20
- package/dist/db/dialect.js +1 -1
- package/dist/db/distinct-on.d.ts +1 -1
- package/dist/db/driver-row-coercion.d.ts +2 -0
- package/dist/db/driver-row-coercion.js +186 -0
- package/dist/db/driver-value-preparation.d.ts +16 -0
- package/dist/db/driver-value-preparation.js +101 -0
- package/dist/db/entity-field-encryption.d.ts +1 -0
- package/dist/db/entity-field-encryption.js +1 -1
- package/dist/db/entity-table-meta.js +103 -110
- package/dist/db/event-store-executor-context.d.ts +2 -1
- package/dist/db/event-store-executor-read-aggregate-currencies.d.ts +17 -0
- package/dist/db/event-store-executor-read-aggregate-currencies.js +40 -0
- package/dist/db/event-store-executor-read-aggregate.d.ts +8 -0
- package/dist/db/event-store-executor-read-aggregate.js +143 -0
- package/dist/db/event-store-executor-read-filter.d.ts +31 -0
- package/dist/db/event-store-executor-read-filter.js +206 -0
- package/dist/db/event-store-executor-read-paging.d.ts +14 -0
- package/dist/db/event-store-executor-read-paging.js +99 -0
- package/dist/db/event-store-executor-read-rows.d.ts +6 -0
- package/dist/db/event-store-executor-read-rows.js +32 -0
- package/dist/db/event-store-executor-read-search.d.ts +28 -0
- package/dist/db/event-store-executor-read-search.js +221 -0
- package/dist/db/event-store-executor-read-sort.d.ts +41 -0
- package/dist/db/event-store-executor-read-sort.js +130 -0
- package/dist/db/event-store-executor-read-where.d.ts +24 -0
- package/dist/db/event-store-executor-read-where.js +81 -0
- package/dist/db/event-store-executor-read.d.ts +2 -9
- package/dist/db/event-store-executor-read.js +48 -701
- package/dist/db/event-store-executor-write-atomic.d.ts +4 -0
- package/dist/db/event-store-executor-write-atomic.js +41 -0
- package/dist/db/event-store-executor-write-steps.d.ts +17 -0
- package/dist/db/event-store-executor-write-steps.js +95 -0
- package/dist/db/event-store-executor-write.js +405 -509
- package/dist/db/event-store-executor.js +2 -1
- package/dist/db/executor-managed-tables.js +1 -1
- package/dist/db/index.d.ts +7 -3
- package/dist/db/index.js +6 -2
- package/dist/db/list-aggregate-labels.d.ts +14 -0
- package/dist/db/list-aggregate-labels.js +26 -0
- package/dist/db/migrate-generator.js +71 -86
- package/dist/db/migrate-runner.js +7 -4
- package/dist/db/pg-error.js +26 -21
- package/dist/db/queries/backfill-pii.js +3 -6
- package/dist/db/queries/database-now.js +2 -1
- package/dist/db/queries/shadow-swap.js +2 -3
- package/dist/db/query.d.ts +16 -15
- package/dist/db/query.js +76 -804
- package/dist/db/reference-data.js +19 -2
- package/dist/db/statement-timeout.js +2 -1
- package/dist/db/table-builder.js +113 -166
- package/dist/db/table-info.d.ts +10 -0
- package/dist/db/table-info.js +45 -0
- package/dist/db/temporal-value-guards.d.ts +6 -0
- package/dist/db/temporal-value-guards.js +15 -0
- package/dist/db/tenant-db-runner.d.ts +1 -0
- package/dist/db/tenant-db-runner.js +3 -0
- package/dist/db/tenant-db-upsert.d.ts +5 -0
- package/dist/db/tenant-db-upsert.js +91 -0
- package/dist/db/tenant-db.js +50 -10
- package/dist/db/where-clause.d.ts +6 -0
- package/dist/db/where-clause.js +236 -0
- package/dist/derivatives/delete-stored-file.js +2 -1
- package/dist/engine/boot-validator/boot-check.js +1 -1
- package/dist/engine/boot-validator/bundled-lists-table.d.ts +2 -0
- package/dist/engine/boot-validator/bundled-lists-table.js +36 -0
- package/dist/engine/boot-validator/detail-screens.js +2 -2
- package/dist/engine/boot-validator/entity-handler.d.ts +1 -0
- package/dist/engine/boot-validator/entity-handler.js +17 -0
- package/dist/engine/boot-validator/entity-list-aggregate-options.d.ts +3 -0
- package/dist/engine/boot-validator/entity-list-aggregate-options.js +23 -0
- package/dist/engine/boot-validator/form-derivations.js +35 -1
- package/dist/engine/boot-validator/i18n-keys.js +5 -3
- package/dist/engine/boot-validator/index.js +2 -0
- package/dist/engine/boot-validator/list-bulk-actions.d.ts +3 -0
- package/dist/engine/boot-validator/list-bulk-actions.js +49 -0
- package/dist/engine/boot-validator/list-column-layout.d.ts +8 -0
- package/dist/engine/boot-validator/list-column-layout.js +41 -0
- package/dist/engine/boot-validator/list-table-aggregate-options.d.ts +24 -0
- package/dist/engine/boot-validator/list-table-aggregate-options.js +145 -0
- package/dist/engine/boot-validator/list-table-aggregate-query.d.ts +10 -0
- package/dist/engine/boot-validator/list-table-aggregate-query.js +31 -0
- package/dist/engine/boot-validator/list-table-export-options.d.ts +1 -0
- package/dist/engine/boot-validator/list-table-export-options.js +27 -0
- package/dist/engine/boot-validator/list-table-options.d.ts +3 -0
- package/dist/engine/boot-validator/list-table-options.js +77 -0
- package/dist/engine/boot-validator/list-table-reject-unknown-keys.d.ts +1 -0
- package/dist/engine/boot-validator/list-table-reject-unknown-keys.js +7 -0
- package/dist/engine/boot-validator/pii-retention.js +233 -155
- package/dist/engine/boot-validator/projection-list-screens.d.ts +1 -1
- package/dist/engine/boot-validator/projection-list-screens.js +3 -13
- package/dist/engine/boot-validator/related-list-table-rules.d.ts +4 -0
- package/dist/engine/boot-validator/related-list-table-rules.js +42 -0
- package/dist/engine/boot-validator/screens-actions.d.ts +1 -0
- package/dist/engine/boot-validator/screens-actions.js +8 -1
- package/dist/engine/boot-validator/screens-dashboard.js +2 -5
- package/dist/engine/boot-validator/screens-forms.js +2 -6
- package/dist/engine/boot-validator/screens-kind-config-edit.d.ts +3 -0
- package/dist/engine/boot-validator/screens-kind-config-edit.js +88 -0
- package/dist/engine/boot-validator/screens-kind-entity-edit.d.ts +3 -0
- package/dist/engine/boot-validator/screens-kind-entity-edit.js +55 -0
- package/dist/engine/boot-validator/screens-kind-entity-list.d.ts +3 -0
- package/dist/engine/boot-validator/screens-kind-entity-list.js +235 -0
- package/dist/engine/boot-validator/screens-kind-projection-detail.d.ts +3 -0
- package/dist/engine/boot-validator/screens-kind-projection-detail.js +235 -0
- package/dist/engine/boot-validator/screens-kind-projection-list.d.ts +3 -0
- package/dist/engine/boot-validator/screens-kind-projection-list.js +56 -0
- package/dist/engine/boot-validator/screens-kind-secret-mint.d.ts +3 -0
- package/dist/engine/boot-validator/screens-kind-secret-mint.js +28 -0
- package/dist/engine/boot-validator/screens-kind-shared.d.ts +37 -0
- package/dist/engine/boot-validator/screens-kind-shared.js +142 -0
- package/dist/engine/boot-validator/screens-lists.d.ts +2 -1
- package/dist/engine/boot-validator/screens-lists.js +24 -11
- package/dist/engine/boot-validator/screens.d.ts +0 -2
- package/dist/engine/boot-validator/screens.js +99 -860
- package/dist/engine/build-app-schema.d.ts +2 -1
- package/dist/engine/build-app-schema.js +65 -97
- package/dist/engine/build-config-feature-schema.js +6 -1
- package/dist/engine/define-feature.js +13 -2
- package/dist/engine/define-handler.js +1 -0
- package/dist/engine/entity-handlers.d.ts +13 -0
- package/dist/engine/entity-handlers.js +10 -21
- package/dist/engine/entity-list-runtime-options.d.ts +8 -0
- package/dist/engine/entity-list-runtime-options.js +18 -0
- package/dist/engine/feature-ast/extractors/handlers.js +1 -0
- package/dist/engine/feature-ast/extractors/index.d.ts +1 -1
- package/dist/engine/feature-ast/extractors/index.js +1 -1
- package/dist/engine/feature-ast/extractors/round1.d.ts +2 -1
- package/dist/engine/feature-ast/extractors/round1.js +6 -0
- package/dist/engine/feature-ast/extractors/round2.js +25 -6
- package/dist/engine/feature-ast/index.d.ts +1 -1
- package/dist/engine/feature-ast/parse.js +3 -1
- package/dist/engine/feature-ast/patch.d.ts +2 -0
- package/dist/engine/feature-ast/patch.js +5 -182
- package/dist/engine/feature-ast/pattern-change-schema.d.ts +10 -245
- package/dist/engine/feature-ast/pattern-change-schema.js +10 -163
- package/dist/engine/feature-ast/pattern-id-matchers.d.ts +7 -0
- package/dist/engine/feature-ast/pattern-id-matchers.js +211 -0
- package/dist/engine/feature-ast/pattern-id-schema.d.ts +251 -0
- package/dist/engine/feature-ast/pattern-id-schema.js +166 -0
- package/dist/engine/feature-ast/patterns.d.ts +14 -1
- package/dist/engine/feature-ast/patterns.js +44 -51
- package/dist/engine/feature-ast/render.js +52 -87
- package/dist/engine/feature-builder-state.d.ts +1 -0
- package/dist/engine/feature-builder-state.js +1 -0
- package/dist/engine/feature-entity-handlers.js +3 -0
- package/dist/engine/feature-manifest.d.ts +1 -0
- package/dist/engine/feature-manifest.js +1 -0
- package/dist/engine/field-access.d.ts +1 -0
- package/dist/engine/field-access.js +12 -0
- package/dist/engine/form-derivations.js +18 -7
- package/dist/engine/handler-field-references.js +1 -1
- package/dist/engine/index.d.ts +2 -2
- package/dist/engine/index.js +1 -1
- package/dist/engine/pattern-library/library.js +2 -1
- package/dist/engine/pattern-library/static-schemas.d.ts +1 -0
- package/dist/engine/pattern-library/static-schemas.js +9 -0
- package/dist/engine/project-app-schema-for-roles.d.ts +2 -0
- package/dist/engine/project-app-schema-for-roles.js +6 -4
- package/dist/engine/registry-ingest.js +1 -1
- package/dist/engine/schema-builder.js +228 -212
- package/dist/engine/screen-filter-ops.js +2 -0
- package/dist/engine/screen-helpers.js +1 -1
- package/dist/engine/screen-kind.d.ts +7 -0
- package/dist/engine/screen-kind.js +1 -0
- package/dist/engine/strip-disabled-features-from-app-schema.js +58 -17
- package/dist/engine/types/feature.d.ts +1 -0
- package/dist/engine/types/index.d.ts +4 -3
- package/dist/engine/types/screen.d.ts +1 -1
- package/dist/engine/types/screen.js +1 -1
- package/dist/engine/validate-projection-allowlist.js +2 -1
- package/dist/entrypoint/index.d.ts +6 -1
- package/dist/entrypoint/index.js +10 -1
- package/dist/errors/docs-url.d.ts +1 -1
- package/dist/errors/docs-url.js +22 -2
- package/dist/es-ops/context.js +1 -1
- package/dist/event-store/admin-api.js +1 -1
- package/dist/event-store/event-store.d.ts +1 -0
- package/dist/event-store/event-store.js +17 -8
- package/dist/event-store/provenance-append.js +1 -1
- package/dist/files/bind-pending-file-refs.js +3 -3
- package/dist/files/create-file-ref-from-bytes.js +7 -1
- package/dist/files/create-file-ref.d.ts +3 -0
- package/dist/files/create-file-ref.js +11 -2
- package/dist/files/file-handle.js +2 -3
- package/dist/files/file-routes.d.ts +2 -0
- package/dist/files/file-routes.js +40 -10
- package/dist/files/provider-resolver.d.ts +1 -0
- package/dist/files/provider-resolver.js +1 -1
- package/dist/files/record-write-check.d.ts +6 -0
- package/dist/files/record-write-check.js +13 -0
- package/dist/files/resolve-content-type.js +43 -0
- package/dist/files/upload-ledger.d.ts +2 -2
- package/dist/files/upload-ledger.js +11 -4
- package/dist/i18n/required-surface-keys.js +189 -208
- package/dist/internal/stack-support.d.ts +2 -1
- package/dist/internal/stack-support.js +1 -1
- package/dist/internal/testing.js +1 -1
- package/dist/jobs/job-runner-context.d.ts +32 -0
- package/dist/jobs/job-runner-context.js +305 -0
- package/dist/jobs/job-runner-execution.d.ts +7 -0
- package/dist/jobs/job-runner-execution.js +160 -0
- package/dist/jobs/job-runner-gates.d.ts +19 -0
- package/dist/jobs/job-runner-gates.js +198 -0
- package/dist/jobs/job-runner-helpers.d.ts +17 -3
- package/dist/jobs/job-runner-helpers.js +61 -2
- package/dist/jobs/job-runner-scope.d.ts +44 -0
- package/dist/jobs/job-runner-scope.js +102 -0
- package/dist/jobs/job-runner-types.d.ts +12 -0
- package/dist/jobs/job-runner.d.ts +0 -1
- package/dist/jobs/job-runner.js +50 -657
- package/dist/observability/escape-hatch-report.d.ts +3 -0
- package/dist/observability/escape-hatch-report.js +21 -3
- package/dist/pipeline/after-rollback-sink.d.ts +6 -0
- package/dist/pipeline/after-rollback-sink.js +32 -0
- package/dist/pipeline/cascade-handler.js +165 -138
- package/dist/pipeline/dispatch-batch.js +8 -1
- package/dist/pipeline/dispatch-query.js +10 -3
- package/dist/pipeline/dispatch-shared.d.ts +13 -3
- package/dist/pipeline/dispatch-shared.js +62 -710
- package/dist/pipeline/dispatch-write.js +296 -189
- package/dist/pipeline/event-dispatcher-admin.js +2 -1
- package/dist/pipeline/event-dispatcher-delivery.js +6 -6
- package/dist/pipeline/event-dispatcher.d.ts +1 -0
- package/dist/pipeline/event-dispatcher.js +6 -9
- package/dist/pipeline/handler-context-auth.d.ts +9 -0
- package/dist/pipeline/handler-context-auth.js +54 -0
- package/dist/pipeline/handler-context-config.d.ts +14 -0
- package/dist/pipeline/handler-context-config.js +113 -0
- package/dist/pipeline/handler-context-db.d.ts +24 -0
- package/dist/pipeline/handler-context-db.js +149 -0
- package/dist/pipeline/handler-context-dispatch.d.ts +23 -0
- package/dist/pipeline/handler-context-dispatch.js +101 -0
- package/dist/pipeline/handler-context-events.d.ts +41 -0
- package/dist/pipeline/handler-context-events.js +239 -0
- package/dist/pipeline/handler-context-notify.d.ts +12 -0
- package/dist/pipeline/handler-context-notify.js +55 -0
- package/dist/pipeline/handler-context-observability.d.ts +7 -0
- package/dist/pipeline/handler-context-observability.js +21 -0
- package/dist/pipeline/handler-context-scope.d.ts +48 -0
- package/dist/pipeline/handler-context-scope.js +88 -0
- package/dist/pipeline/notify-scope.js +12 -1
- package/dist/pipeline/pre-handler-gates.js +20 -4
- package/dist/pipeline/pre-transaction-reservations.d.ts +1 -0
- package/dist/pipeline/pre-transaction-reservations.js +9 -3
- package/dist/pipeline/projection-rebuild.js +2 -1
- package/dist/pipeline/system-hooks.d.ts +3 -1
- package/dist/pipeline/system-hooks.js +55 -6
- package/dist/pipeline/write-result-masking.js +13 -10
- package/dist/schema-cli/apply-command.d.ts +2 -0
- package/dist/schema-cli/apply-command.js +97 -0
- package/dist/schema-cli/baseline-command.d.ts +2 -0
- package/dist/schema-cli/baseline-command.js +33 -0
- package/dist/schema-cli/generate-command.d.ts +2 -0
- package/dist/schema-cli/generate-command.js +90 -0
- package/dist/schema-cli/shared.d.ts +39 -0
- package/dist/schema-cli/shared.js +95 -0
- package/dist/schema-cli/status-command.d.ts +2 -0
- package/dist/schema-cli/status-command.js +73 -0
- package/dist/schema-cli/validate-boot-input.d.ts +5 -0
- package/dist/schema-cli/validate-boot-input.js +130 -0
- package/dist/schema-cli/validate-command.d.ts +2 -0
- package/dist/schema-cli/validate-command.js +130 -0
- package/dist/schema-cli.d.ts +2 -18
- package/dist/schema-cli.js +47 -604
- package/dist/search/meilisearch-adapter.js +2 -1
- package/dist/search/reindex-entity.js +15 -5
- package/dist/ui-types/index.d.ts +2 -2
- package/dist/ui-types/index.js +1 -1
- package/dist/upgrade-changelog.d.ts +2 -0
- package/dist/upgrade-changelog.js +14 -0
- package/dist/upgrade-cli.d.ts +3 -12
- package/dist/upgrade-cli.js +171 -197
- package/dist/upgrade-marker-parse.d.ts +32 -0
- package/dist/upgrade-marker-parse.js +73 -0
- package/package.json +9 -6
- package/src/changes.json +555 -0
- package/src/scripts/codemod/codemod-support.ts +1 -1
- package/src/scripts/codemod/db-factory.ts +1 -1
- package/src/scripts/codemod/feature-layout.ts +10 -2
- package/src/scripts/codemod/object-form.ts +41 -4
- package/src/scripts/codemod/package-merge.ts +58 -8
- package/src/scripts/codemod/pii-personal-migration.ts +175 -145
- package/src/scripts/codemod/testing-injection.ts +122 -42
- package/src/scripts/codemod/testing-move.ts +29 -7
- package/dist/engine/provider-plugin-context.d.ts +0 -3
- package/dist/engine/provider-plugin-context.js +0 -28
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { AppSchema } from "../ui-types/index.ts";
|
|
1
|
+
import type { AppSchema, WorkspaceSchema } from "../ui-types/index.ts";
|
|
2
2
|
import type { Registry } from "./types/feature.ts";
|
|
3
|
+
export declare function workspaceOwnerOf(definition: WorkspaceSchema["definition"]): string | undefined;
|
|
3
4
|
export type BuildAppSchemaOptions = {
|
|
4
5
|
/** Dev-server authoring hints (Settings-Hub placement). Default off — only
|
|
5
6
|
* `createKumikoServer` opts in; prod boot + unit tests stay silent. */
|
|
@@ -31,6 +31,12 @@ import { isEncryptedAtRest } from "./config-helpers.js";
|
|
|
31
31
|
import { isListQueryWithoutSearchableFields } from "./entity-list-searchability.js";
|
|
32
32
|
import { QnTypes, qualifyEntityName } from "./qualified-name.js";
|
|
33
33
|
const log = createFallbackLogger("kumiko");
|
|
34
|
+
// Workspace ids are only unique per feature, and the schema carries the short id. The owner stays
|
|
35
|
+
// off the serialized schema; the tenant-level feature strip reads it from here by object identity.
|
|
36
|
+
const workspaceOwnerByDefinition = new WeakMap();
|
|
37
|
+
export function workspaceOwnerOf(definition) {
|
|
38
|
+
return workspaceOwnerByDefinition.get(definition);
|
|
39
|
+
}
|
|
34
40
|
export function buildAppSchema(registry, options = {}) {
|
|
35
41
|
const features = [];
|
|
36
42
|
const urlPrefillFieldsByScreenQn = collectUrlPrefillFieldsByScreenQn([
|
|
@@ -74,8 +80,10 @@ export function buildAppSchema(registry, options = {}) {
|
|
|
74
80
|
for (const [featureName, feature] of registry.features) {
|
|
75
81
|
for (const [shortId, definition] of Object.entries(feature.workspaces)) {
|
|
76
82
|
const qualified = `${featureName}:workspace:${shortId}`;
|
|
83
|
+
const projectedDefinition = { ...definition, id: shortId };
|
|
84
|
+
workspaceOwnerByDefinition.set(projectedDefinition, featureName);
|
|
77
85
|
workspaces.push({
|
|
78
|
-
definition:
|
|
86
|
+
definition: projectedDefinition,
|
|
79
87
|
navMembers: registry.getWorkspaceNavs(qualified),
|
|
80
88
|
});
|
|
81
89
|
}
|
|
@@ -111,7 +119,7 @@ export function buildAppSchema(registry, options = {}) {
|
|
|
111
119
|
// instead so a leaked function renderer is actually caught.
|
|
112
120
|
const offender = findNonJsonSafePath(schema, "schema");
|
|
113
121
|
if (offender !== null) {
|
|
114
|
-
log.error(`buildAppSchema:
|
|
122
|
+
log.error(`buildAppSchema: output is not JSON-safe, non-serializable value at "${offender}" (a function renderer or class instance in the schema?).`, { offender });
|
|
115
123
|
}
|
|
116
124
|
}
|
|
117
125
|
return schema;
|
|
@@ -446,136 +454,96 @@ function assertValidScreenMultilineRows(featureName, shortId, screen) {
|
|
|
446
454
|
check(screen.confirm.fields);
|
|
447
455
|
}
|
|
448
456
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
//
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
// cast bridges the variant inference TS can't recompute from a generic
|
|
462
|
-
// Record.
|
|
463
|
-
// kumiko-lint-ignore complexity-budget flat per-property whitelist walk, one independent `if` per FieldDefinition property — same shape as schema-builder.ts's field→zod switch
|
|
464
|
-
function projectField(fieldDef) {
|
|
465
|
-
const def = fieldDef; // @cast-boundary schema-walk
|
|
466
|
-
const out = {};
|
|
467
|
-
if (typeof def["type"] === "string")
|
|
468
|
-
out["type"] = def["type"];
|
|
469
|
-
if (typeof def["required"] === "boolean")
|
|
470
|
-
out["required"] = def["required"];
|
|
471
|
-
if (typeof def["sortable"] === "boolean")
|
|
472
|
-
out["sortable"] = def["sortable"];
|
|
457
|
+
const isStringValue = (value) => typeof value === "string";
|
|
458
|
+
const isBooleanValue = (value) => typeof value === "boolean";
|
|
459
|
+
const isNumberValue = (value) => typeof value === "number";
|
|
460
|
+
const isTrueValue = (value) => value === true;
|
|
461
|
+
const isNumberOrStringValue = (value) => typeof value === "number" || typeof value === "string";
|
|
462
|
+
const isBooleanOrJsonSafeObject = (value) => typeof value === "boolean" || isJsonSafeObject(value);
|
|
463
|
+
const isUnitSpec = (value) => typeof value === "string" || (isPlainObject(value) && typeof value["field"] === "string");
|
|
464
|
+
// Forwarded in this order, so the client schema keeps its key order.
|
|
465
|
+
const FORWARDED_FIELD_PROPERTIES = [
|
|
466
|
+
["type", isStringValue],
|
|
467
|
+
["required", isBooleanValue],
|
|
468
|
+
["sortable", isBooleanValue],
|
|
473
469
|
// filterable controls the faceted filter dropdowns in the renderer (select/
|
|
474
470
|
// boolean), so it must be included in the client schema.
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
out["searchable"] = def["searchable"];
|
|
479
|
-
if (isJsonSafeValue(def["default"]))
|
|
480
|
-
out["default"] = def["default"];
|
|
471
|
+
["filterable", isBooleanValue],
|
|
472
|
+
["searchable", isBooleanValue],
|
|
473
|
+
["default", isJsonSafeValue],
|
|
481
474
|
// Select: the options list is plain JSON, so forward it.
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
if (isJsonSafeObject(def["optionTones"]))
|
|
485
|
-
out["optionTones"] = def["optionTones"];
|
|
475
|
+
["options", Array.isArray],
|
|
476
|
+
["optionTones", isJsonSafeObject],
|
|
486
477
|
// Reference: entity target, labelField, and multiple are required by the
|
|
487
478
|
// renderer. ReferenceInput builds the options query from refEntity/refFeature
|
|
488
479
|
// and resolves the label through labelField; without these properties, the
|
|
489
480
|
// dropdown is empty (the QN becomes `<feature>:query::list` → 404).
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
if (typeof def["labelField"] === "string")
|
|
493
|
-
out["labelField"] = def["labelField"];
|
|
481
|
+
["entity", isStringValue],
|
|
482
|
+
["labelField", isStringValue],
|
|
494
483
|
// Author-supplied picker source — without it the client falls back to the list handler.
|
|
495
|
-
|
|
496
|
-
out["optionsQuery"] = def["optionsQuery"];
|
|
484
|
+
["optionsQuery", isStringValue],
|
|
497
485
|
// Select: tier/tenant availability of the static options, loaded by the renderer.
|
|
498
|
-
|
|
499
|
-
out["optionsAvailabilityQuery"] = def["optionsAvailabilityQuery"];
|
|
486
|
+
["optionsAvailabilityQuery", isStringValue],
|
|
500
487
|
// Select: options only offered while a sibling-field condition holds; the renderer filters, the write path enforces.
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
if (typeof def["multiple"] === "boolean")
|
|
504
|
-
out["multiple"] = def["multiple"];
|
|
488
|
+
["conditionalOptions", Array.isArray],
|
|
489
|
+
["multiple", isBooleanValue],
|
|
505
490
|
// MultiSelect: display picks checkboxes vs. combobox in the renderer,
|
|
506
491
|
// columns/maxRows size the checkbox grid — without these the renderer
|
|
507
492
|
// always falls back to the combobox. Select: display picks
|
|
508
493
|
// "radio" | "dropdown" the same way.
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
out["columns"] = def["columns"];
|
|
513
|
-
if (typeof def["maxRows"] === "number")
|
|
514
|
-
out["maxRows"] = def["maxRows"];
|
|
494
|
+
["display", isStringValue],
|
|
495
|
+
["columns", isNumberValue],
|
|
496
|
+
["maxRows", isNumberValue],
|
|
515
497
|
// text/longText: textarea row count — DefaultInput renders a single-line
|
|
516
498
|
// input otherwise.
|
|
517
|
-
|
|
518
|
-
out["multiline"] = def["multiline"];
|
|
499
|
+
["multiline", isBooleanOrJsonSafeObject],
|
|
519
500
|
// number: Zod write-boundary bounds. date/timestamp/locatedTimestamp:
|
|
520
501
|
// ISO-string picker bounds — same keys, different literal type.
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
if (typeof def["max"] === "number" || typeof def["max"] === "string")
|
|
524
|
-
out["max"] = def["max"];
|
|
502
|
+
["min", isNumberOrStringValue],
|
|
503
|
+
["max", isNumberOrStringValue],
|
|
525
504
|
// date/timestamp/locatedTimestamp: display/parsing locale override.
|
|
526
|
-
|
|
527
|
-
out["locale"] = def["locale"];
|
|
505
|
+
["locale", isStringValue],
|
|
528
506
|
// image/images: which camera a mobile capture opens.
|
|
529
|
-
|
|
530
|
-
out["capture"] = def["capture"];
|
|
507
|
+
["capture", isStringValue],
|
|
531
508
|
// number: display-only suffix, static or read from a sibling field of the row.
|
|
532
|
-
|
|
533
|
-
if (typeof unit === "string" || (isPlainObject(unit) && typeof unit["field"] === "string"))
|
|
534
|
-
out["unit"] = unit;
|
|
509
|
+
["unit", isUnitSpec],
|
|
535
510
|
// number/decimal/bigInt: `false` drops thousands separators (e.g. a year).
|
|
536
|
-
|
|
537
|
-
out["grouping"] = def["grouping"];
|
|
511
|
+
["grouping", isBooleanValue],
|
|
538
512
|
// text: "password" masks the input and blocks URL prefill in the renderer.
|
|
539
|
-
|
|
540
|
-
out["format"] = def["format"];
|
|
513
|
+
["format", isStringValue],
|
|
541
514
|
// Write-response redaction stays server-side; the renderer needs the flag to
|
|
542
515
|
// refuse any prefill (URL or handoff) into the field.
|
|
543
|
-
|
|
544
|
-
out["sensitive"] = true;
|
|
516
|
+
["sensitive", isTrueValue],
|
|
545
517
|
// Without it the renderer shows a plain text input for a field whose value never leaves the server.
|
|
546
|
-
|
|
547
|
-
out["writeOnly"] = true;
|
|
518
|
+
["writeOnly", isTrueValue],
|
|
548
519
|
// timestamp: the edit view-model derives its wall-clock input mode from this.
|
|
549
|
-
|
|
550
|
-
out["locatedBy"] = def["locatedBy"];
|
|
520
|
+
["locatedBy", isStringValue],
|
|
551
521
|
// file/image/images: upload picker constraints; the first variant key picks
|
|
552
522
|
// the preview variant.
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
out["maxSize"] = def["maxSize"];
|
|
557
|
-
if (isJsonSafeObject(def["variants"]))
|
|
558
|
-
out["variants"] = def["variants"];
|
|
523
|
+
["accept", isJsonSafeArray],
|
|
524
|
+
["maxSize", isStringValue],
|
|
525
|
+
["variants", isJsonSafeObject],
|
|
559
526
|
// decimal, incl. embedded sub-fields: rounding of derived embedded-list cells.
|
|
560
|
-
|
|
561
|
-
out["scale"] = def["scale"];
|
|
527
|
+
["scale", isNumberValue],
|
|
562
528
|
// money: declared currency source (MoneyCurrencySource) — without
|
|
563
529
|
// it the renderer can't tell a "currency: { kind: 'tenant' }" field apart
|
|
564
530
|
// from an undeclared one and always falls back to entity.defaultCurrency.
|
|
565
|
-
|
|
566
|
-
out["currency"] = def["currency"];
|
|
531
|
+
["currency", isJsonSafeObject],
|
|
567
532
|
// embedded lists: row-count bounds, computed cells, totals row, and the
|
|
568
533
|
// sibling-money-field totals check.
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
534
|
+
["minItems", isNumberValue],
|
|
535
|
+
["maxItems", isNumberValue],
|
|
536
|
+
["derived", isJsonSafeObject],
|
|
537
|
+
["totals", isJsonSafeArray],
|
|
538
|
+
["totalsMatch", isJsonSafeObject],
|
|
539
|
+
];
|
|
540
|
+
function projectField(fieldDef) {
|
|
541
|
+
const def = fieldDef; // @cast-boundary schema-walk
|
|
542
|
+
const out = {};
|
|
543
|
+
for (const [key, isForwarded] of FORWARDED_FIELD_PROPERTIES) {
|
|
544
|
+
if (isForwarded(def[key]))
|
|
545
|
+
out[key] = def[key];
|
|
546
|
+
}
|
|
579
547
|
// embedded lists: the sub-field map itself — without it the client-side
|
|
580
548
|
// edit view-model iterates `undefined` and the screen crashes.
|
|
581
549
|
// Recursive per sub-field, NOT a blanket isJsonSafeValue gate: a single
|
|
@@ -656,8 +656,13 @@ function buildScreen(shortId, scope, feature, keys, access, hub, options = {}) {
|
|
|
656
656
|
// feature's group (100% of today's apps — byte-identical output). Only a
|
|
657
657
|
// cross-feature `group` (feature !== ownerFeature) needs the owner prefix,
|
|
658
658
|
// to keep two features sharing a group from clobbering the same shortKey.
|
|
659
|
+
// A selector's option labels hang on its field id in one global key space
|
|
660
|
+
// (`config:entity:__config-edit__:field:<id>:option:<value>`), so two owners
|
|
661
|
+
// whose selector is both named `provider` need distinct ids.
|
|
659
662
|
const fieldId = options.fieldIdOf ??
|
|
660
|
-
((k) =>
|
|
663
|
+
((k) => k.feature === k.ownerFeature && !hub.selectorOptions.has(k.qn)
|
|
664
|
+
? k.shortKey
|
|
665
|
+
: qualifiedFieldId(k));
|
|
661
666
|
const seenFieldIds = new Map();
|
|
662
667
|
for (const k of keys) {
|
|
663
668
|
const id = fieldId(k);
|
|
@@ -48,9 +48,16 @@ export function defineFeature(name, setup, settings) {
|
|
|
48
48
|
},
|
|
49
49
|
requires: (() => {
|
|
50
50
|
const fn = (...args) => {
|
|
51
|
-
|
|
51
|
+
const [first, ...rest] = args;
|
|
52
|
+
if (rest.length > 0 || !isObjectArgument(first)) {
|
|
52
53
|
throwObjectArgumentRequired(name, "requires");
|
|
53
|
-
|
|
54
|
+
}
|
|
55
|
+
// Untyped callers can pass `{ feature: [...] }`; without this the object would be
|
|
56
|
+
// registered as a dependency name.
|
|
57
|
+
if (!Array.isArray(first.features) || !first.features.every((f) => typeof f === "string")) {
|
|
58
|
+
throw new Error(`[Feature ${name}] r.requires() needs { features: string[] }`);
|
|
59
|
+
}
|
|
60
|
+
state.requires.push(...first.features);
|
|
54
61
|
};
|
|
55
62
|
return Object.assign(fn, {
|
|
56
63
|
projection: (tableName) => {
|
|
@@ -70,6 +77,9 @@ export function defineFeature(name, setup, settings) {
|
|
|
70
77
|
}
|
|
71
78
|
state.toggleableDefault = options.default;
|
|
72
79
|
},
|
|
80
|
+
adoptsBundledLists() {
|
|
81
|
+
state.adoptsBundledLists = true;
|
|
82
|
+
},
|
|
73
83
|
uiHints(hints) {
|
|
74
84
|
if (state.uiHints !== undefined) {
|
|
75
85
|
throw new Error(`[Feature ${name}] r.uiHints() called twice — UI hints are declared once`);
|
|
@@ -91,6 +101,7 @@ export function defineFeature(name, setup, settings) {
|
|
|
91
101
|
requiredProjections: state.requiredProjections,
|
|
92
102
|
requiredSteps: state.requiredSteps,
|
|
93
103
|
...(state.toggleableDefault !== undefined && { toggleableDefault: state.toggleableDefault }),
|
|
104
|
+
...(state.adoptsBundledLists && { adoptsBundledLists: true }),
|
|
94
105
|
...(state.uiHints !== undefined && { uiHints: state.uiHints }),
|
|
95
106
|
entities: state.entities,
|
|
96
107
|
entityTables: state.entityTables,
|
|
@@ -57,6 +57,7 @@ export function defineWriteHandler(def,
|
|
|
57
57
|
...(def.unsafeSkipTransitionGuard && { unsafeSkipTransitionGuard: true }),
|
|
58
58
|
...(def.rateLimit && { rateLimit: def.rateLimit }),
|
|
59
59
|
...(def.additionalRateLimits && { additionalRateLimits: def.additionalRateLimits }),
|
|
60
|
+
...(def.rateLimitCost && { rateLimitCost: def.rateLimitCost }),
|
|
60
61
|
...(def.escapeHatch && { escapeHatch: def.escapeHatch }),
|
|
61
62
|
...pickPreTransactionPhases(def),
|
|
62
63
|
...(def.tenantlessAnonymous && { tenantlessAnonymous: true }),
|
|
@@ -44,6 +44,19 @@ export declare const entityListSchema: z.ZodObject<{
|
|
|
44
44
|
}>;
|
|
45
45
|
value: z.ZodUnknown;
|
|
46
46
|
}, z.core.$strip>>>;
|
|
47
|
+
aggregate: z.ZodOptional<z.ZodObject<{
|
|
48
|
+
groupBy: z.ZodOptional<z.ZodString>;
|
|
49
|
+
measures: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
50
|
+
field: z.ZodString;
|
|
51
|
+
kind: z.ZodEnum<{
|
|
52
|
+
avg: "avg";
|
|
53
|
+
count: "count";
|
|
54
|
+
max: "max";
|
|
55
|
+
min: "min";
|
|
56
|
+
sum: "sum";
|
|
57
|
+
}>;
|
|
58
|
+
}, z.core.$strip>>>;
|
|
59
|
+
}, z.core.$strip>>;
|
|
47
60
|
}, z.core.$strip>;
|
|
48
61
|
export declare function defineEntityWriteHandler(name: string, entity: EntityDefinition, options: EntityWriteHandlerOptions): WriteHandlerDef;
|
|
49
62
|
export declare function defineEntityQueryHandler(name: string, entity: EntityDefinition, options: EntityQueryHandlerOptions): QueryHandlerDef;
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { ENTITY_CONVENTION_QUERY_BRAND } from "@cosmicdrift/kumiko-types/handlers";
|
|
2
|
+
import { listAggregatePayloadSchema, } from "@cosmicdrift/kumiko-types/list-aggregate-types";
|
|
2
3
|
import * as z from "zod";
|
|
3
4
|
import { collectReferenceFields, enrichRowWithReferences, enrichWithReferences, } from "../db/eagerload.js";
|
|
4
5
|
import { createEventStoreExecutor } from "../db/event-store-executor.js";
|
|
6
|
+
import { answerListAggregate } from "../db/list-aggregate-labels.js";
|
|
5
7
|
import { buildEntityTable } from "../db/table-builder.js";
|
|
6
8
|
import { acknowledgeConventionCrossTenant, reportConventionCrossTenantUse, } from "../db/tenant-db.js";
|
|
7
9
|
import { InternalError } from "../errors/index.js";
|
|
8
10
|
import { isSystemIdentity } from "../pipeline/system-identity-switch.js";
|
|
9
11
|
import { assertUnreachable } from "../utils/index.js";
|
|
10
12
|
import { PAGED_QUERY_HANDLER_BRAND } from "./define-handler.js";
|
|
13
|
+
import { entityListRuntime } from "./entity-list-runtime-options.js";
|
|
11
14
|
import { assertReason } from "./escape-hatch-reason.js";
|
|
12
15
|
import { dropEmptyWriteOnlyValues } from "./field-access.js";
|
|
13
16
|
import { instructionFieldNames } from "./instruction-fields.js";
|
|
@@ -105,6 +108,7 @@ export const entityListSchema = z.object({
|
|
|
105
108
|
value: z.unknown(),
|
|
106
109
|
}))
|
|
107
110
|
.optional(),
|
|
111
|
+
aggregate: listAggregatePayloadSchema.optional(),
|
|
108
112
|
});
|
|
109
113
|
function parseHandlerName(name, validVerbs) {
|
|
110
114
|
const colonIdx = name.indexOf(":");
|
|
@@ -390,28 +394,13 @@ export function defineEntityQueryHandler(name, entity, options) {
|
|
|
390
394
|
// runtime override supplies it.
|
|
391
395
|
const listPayload = query.payload; // @cast-boundary engine-payload
|
|
392
396
|
const db = dbFor(ctx);
|
|
393
|
-
const
|
|
394
|
-
|
|
395
|
-
...
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
// same runtime-override extension point as searchAdapter above.
|
|
399
|
-
referenceSearch: {
|
|
400
|
-
fields: ctx.registry.getSearchableReferences(entityName),
|
|
401
|
-
resolveEntity: (name) => ctx.registry.getEntity(name),
|
|
402
|
-
},
|
|
403
|
-
referenceSort: {
|
|
404
|
-
fields: ctx.registry.getSortableReferences(entityName),
|
|
405
|
-
resolveEntity: (name) => ctx.registry.getEntity(name),
|
|
406
|
-
},
|
|
407
|
-
parentVisibility: { entities: ctx.registry.getAllEntities() },
|
|
408
|
-
});
|
|
409
|
-
const eagerLoadViewer = {
|
|
410
|
-
user: query.user,
|
|
411
|
-
parentVisibility: { entities: ctx.registry.getAllEntities() },
|
|
412
|
-
};
|
|
397
|
+
const { runtimeOptions, eagerLoadViewer, resolveEntity } = entityListRuntime(ctx, entityName, query.user);
|
|
398
|
+
if (listPayload.aggregate !== undefined) {
|
|
399
|
+
return answerListAggregate(executor, { ...listPayload, aggregate: listPayload.aggregate }, query.user, db, runtimeOptions, { entity, resolveEntity, viewer: eagerLoadViewer });
|
|
400
|
+
}
|
|
401
|
+
const result = await executor.list(listPayload, query.user, db, runtimeOptions);
|
|
413
402
|
const enrichedRows = hasRefFields
|
|
414
|
-
? await enrichWithReferences(result.rows, entity,
|
|
403
|
+
? await enrichWithReferences(result.rows, entity, resolveEntity, db, eagerLoadViewer)
|
|
415
404
|
: result.rows;
|
|
416
405
|
return { ...result, rows: augmentDerivedFields(enrichedRows, entity) };
|
|
417
406
|
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ListRuntimeOptions } from "@cosmicdrift/kumiko-types/event-store-executor-types";
|
|
2
|
+
import type { EagerLoadEntityResolver, EagerLoadViewer } from "../db/eagerload.ts";
|
|
3
|
+
import type { HandlerContext, SessionUser } from "./types/index.ts";
|
|
4
|
+
export declare function entityListRuntime(ctx: HandlerContext, entityName: string, user: SessionUser): {
|
|
5
|
+
readonly runtimeOptions: ListRuntimeOptions;
|
|
6
|
+
readonly eagerLoadViewer: EagerLoadViewer;
|
|
7
|
+
readonly resolveEntity: EagerLoadEntityResolver;
|
|
8
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Registry access only exists at request time, so the searchable/sortable-reference
|
|
2
|
+
// caches, the entity resolver and the join-row read gate travel through the
|
|
3
|
+
// runtime-override extension point of the executor verbs.
|
|
4
|
+
export function entityListRuntime(ctx, entityName, user) {
|
|
5
|
+
const parentVisibility = { entities: ctx.registry.getAllEntities() };
|
|
6
|
+
const resolveEntity = (name) => ctx.registry.getEntity(name);
|
|
7
|
+
return {
|
|
8
|
+
runtimeOptions: {
|
|
9
|
+
...(ctx.searchAdapter !== undefined && { searchAdapter: ctx.searchAdapter }),
|
|
10
|
+
...(ctx.includeDeleted === true && { includeDeleted: true }),
|
|
11
|
+
referenceSearch: { fields: ctx.registry.getSearchableReferences(entityName), resolveEntity },
|
|
12
|
+
referenceSort: { fields: ctx.registry.getSortableReferences(entityName), resolveEntity },
|
|
13
|
+
parentVisibility,
|
|
14
|
+
},
|
|
15
|
+
eagerLoadViewer: { user, parentVisibility },
|
|
16
|
+
resolveEntity,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -33,6 +33,7 @@ const WRITE_HANDLER_KEY_KINDS = {
|
|
|
33
33
|
unsafeSkipTransitionGuard: "modeled",
|
|
34
34
|
rateLimit: "modeled",
|
|
35
35
|
additionalRateLimits: "modeled",
|
|
36
|
+
rateLimitCost: "opaque",
|
|
36
37
|
escapeHatch: "modeled",
|
|
37
38
|
tenantlessAnonymous: "opaque",
|
|
38
39
|
reserveBeforeTransaction: "opaque",
|
|
@@ -5,7 +5,7 @@ export { extractAuthClaims, extractHook, isHookType, readOptionalAccessRule, rea
|
|
|
5
5
|
export { extractHttpRoute, extractJob, isHttpRouteMethod, } from "./jobs-routes.ts";
|
|
6
6
|
export { collectScreenOpaqueProps, extractMultiStreamProjection, extractProjection, extractScreen, readApplyBodies, readScreenStatic, } from "./projections-screens.ts";
|
|
7
7
|
export { findImportBindingForLocalName, resolveModuleFile, } from "./resolve-import.ts";
|
|
8
|
-
export { extractDescribe, extractOptionalRequires, extractReadsConfig, extractRequires, extractSystemScope, extractToggleable, extractUiHints, } from "./round1.ts";
|
|
8
|
+
export { extractAdoptsBundledLists, extractDescribe, extractOptionalRequires, extractReadsConfig, extractRequires, extractSystemScope, extractToggleable, extractUiHints, } from "./round1.ts";
|
|
9
9
|
export { extractEntity, extractNav, extractRelation, extractWorkspace, } from "./round2.ts";
|
|
10
10
|
export { extractClaimKey, extractConfig, extractMetric, extractReferenceData, extractSecret, extractSecretNamespace, extractTranslations, extractUseExtension, isClaimKeyType, type NamedOptionsResult, readNamedOptions, } from "./round3.ts";
|
|
11
11
|
export { extractBootCheck, extractEnvSchema, extractExposesApi, extractExtendsRegistrar, extractStoreTable, extractUsesApi, } from "./round5.ts";
|
|
@@ -5,7 +5,7 @@ export { extractAuthClaims, extractHook, isHookType, readOptionalAccessRule, rea
|
|
|
5
5
|
export { extractHttpRoute, extractJob, isHttpRouteMethod, } from "./jobs-routes.js";
|
|
6
6
|
export { collectScreenOpaqueProps, extractMultiStreamProjection, extractProjection, extractScreen, readApplyBodies, readScreenStatic, } from "./projections-screens.js";
|
|
7
7
|
export { findImportBindingForLocalName, resolveModuleFile, } from "./resolve-import.js";
|
|
8
|
-
export { extractDescribe, extractOptionalRequires, extractReadsConfig, extractRequires, extractSystemScope, extractToggleable, extractUiHints, } from "./round1.js";
|
|
8
|
+
export { extractAdoptsBundledLists, extractDescribe, extractOptionalRequires, extractReadsConfig, extractRequires, extractSystemScope, extractToggleable, extractUiHints, } from "./round1.js";
|
|
9
9
|
export { extractEntity, extractNav, extractRelation, extractWorkspace, } from "./round2.js";
|
|
10
10
|
export { extractClaimKey, extractConfig, extractMetric, extractReferenceData, extractSecret, extractSecretNamespace, extractTranslations, extractUseExtension, isClaimKeyType, readNamedOptions, } from "./round3.js";
|
|
11
11
|
export { extractBootCheck, extractEnvSchema, extractExposesApi, extractExtendsRegistrar, extractStoreTable, extractUsesApi, } from "./round5.js";
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { CallExpression, SourceFile } from "ts-morph";
|
|
2
|
-
import type { DescribePattern, OptionalRequiresPattern, ReadsConfigPattern, RequiresPattern, SystemScopePattern, ToggleablePattern, UiHintsPattern } from "../patterns.ts";
|
|
2
|
+
import type { AdoptsBundledListsPattern, DescribePattern, OptionalRequiresPattern, ReadsConfigPattern, RequiresPattern, SystemScopePattern, ToggleablePattern, UiHintsPattern } from "../patterns.ts";
|
|
3
3
|
import { type ExtractOutput } from "./shared.ts";
|
|
4
4
|
export declare function extractRequires(call: CallExpression, sourceFile: SourceFile): ExtractOutput<RequiresPattern>;
|
|
5
5
|
export declare function extractOptionalRequires(call: CallExpression, sourceFile: SourceFile): ExtractOutput<OptionalRequiresPattern>;
|
|
6
6
|
export declare function extractReadsConfig(call: CallExpression, sourceFile: SourceFile): ExtractOutput<ReadsConfigPattern>;
|
|
7
7
|
export declare function extractSystemScope(call: CallExpression, sourceFile: SourceFile): ExtractOutput<SystemScopePattern>;
|
|
8
|
+
export declare function extractAdoptsBundledLists(call: CallExpression, sourceFile: SourceFile): ExtractOutput<AdoptsBundledListsPattern>;
|
|
8
9
|
export declare function extractUiHints(call: CallExpression, sourceFile: SourceFile): ExtractOutput<UiHintsPattern>;
|
|
9
10
|
export declare function extractDescribe(call: CallExpression, sourceFile: SourceFile): ExtractOutput<DescribePattern>;
|
|
10
11
|
export declare function extractToggleable(call: CallExpression, sourceFile: SourceFile): ExtractOutput<ToggleablePattern>;
|
|
@@ -39,6 +39,12 @@ export function extractSystemScope(call, sourceFile) {
|
|
|
39
39
|
source: sourceLocationFromNode(call, sourceFile),
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
|
+
export function extractAdoptsBundledLists(call, sourceFile) {
|
|
43
|
+
return ok({
|
|
44
|
+
kind: "adoptsBundledLists",
|
|
45
|
+
source: sourceLocationFromNode(call, sourceFile),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
42
48
|
export function extractUiHints(call, sourceFile) {
|
|
43
49
|
return ok({
|
|
44
50
|
kind: "uiHints",
|
|
@@ -2,19 +2,36 @@ import { SyntaxKind } from "ts-morph";
|
|
|
2
2
|
import { describeUnknownFieldType, findUnknownEntityFieldTypes } from "../entity-field-types.js";
|
|
3
3
|
import { sourceLocationFromNode } from "../source-location.js";
|
|
4
4
|
import { fail, isPlainObject, isRawRefSentinel, ok, readDataLiteralNode, readNameLiteral, readNameOrRef, } from "./shared.js";
|
|
5
|
+
function readBackingTableRef(property) {
|
|
6
|
+
const initializer = property.asKind(SyntaxKind.PropertyAssignment)?.getInitializer() ??
|
|
7
|
+
property.asKind(SyntaxKind.ShorthandPropertyAssignment)?.getNameNode();
|
|
8
|
+
const reference = initializer ? readDataLiteralNode(initializer) : undefined;
|
|
9
|
+
return isRawRefSentinel(reference) ? reference : undefined;
|
|
10
|
+
}
|
|
5
11
|
// `{ name: "x", ...xEntity }` — the definition is a reference the parser cannot
|
|
6
12
|
// inline, so it is kept as a raw-ref sentinel and re-rendered as the same spread.
|
|
7
13
|
// `backingTable` is runtime wiring (a table identifier), not part of the
|
|
8
|
-
// definition data, so it
|
|
14
|
+
// definition data, so it is carried next to the definition and skipped by the shape check.
|
|
9
15
|
function readSpreadOnlyDefinition(obj) {
|
|
10
|
-
const
|
|
11
|
-
.
|
|
12
|
-
|
|
16
|
+
const isBackingTable = (property) => {
|
|
17
|
+
const name = property.asKind(SyntaxKind.PropertyAssignment)?.getName() ??
|
|
18
|
+
property.asKind(SyntaxKind.ShorthandPropertyAssignment)?.getName();
|
|
19
|
+
return name === "backingTable";
|
|
20
|
+
};
|
|
21
|
+
const allProperties = obj.getProperties();
|
|
22
|
+
const properties = allProperties.filter((property) => !isBackingTable(property));
|
|
13
23
|
const spread = properties.length === 2 ? properties[1]?.asKind(SyntaxKind.SpreadAssignment) : undefined;
|
|
14
24
|
if (!spread)
|
|
15
25
|
return undefined;
|
|
16
26
|
const reference = readDataLiteralNode(spread.getExpression());
|
|
17
|
-
|
|
27
|
+
if (!isRawRefSentinel(reference))
|
|
28
|
+
return undefined;
|
|
29
|
+
const backingTableProperty = allProperties.find(isBackingTable);
|
|
30
|
+
const backingTable = backingTableProperty ? readBackingTableRef(backingTableProperty) : undefined;
|
|
31
|
+
// A backingTable that is not a plain reference cannot be re-rendered; fall back to the data reader.
|
|
32
|
+
if (backingTableProperty && !backingTable)
|
|
33
|
+
return undefined;
|
|
34
|
+
return { definition: reference, backingTable };
|
|
18
35
|
}
|
|
19
36
|
export function extractEntity(call, sourceFile) {
|
|
20
37
|
const args = call.getArguments();
|
|
@@ -32,7 +49,8 @@ export function extractEntity(call, sourceFile) {
|
|
|
32
49
|
if (!nameInit) {
|
|
33
50
|
return fail("entity", sourceLocationFromNode(call, sourceFile), "object form requires a string-literal `name` property");
|
|
34
51
|
}
|
|
35
|
-
const
|
|
52
|
+
const spreadOnly = readSpreadOnlyDefinition(obj);
|
|
53
|
+
const definition = spreadOnly?.definition ?? readDataLiteralNode(obj);
|
|
36
54
|
if (!isPlainObject(definition)) {
|
|
37
55
|
return fail("entity", sourceLocationFromNode(call, sourceFile), "definition could not be read as a plain object (contains functions or identifiers)");
|
|
38
56
|
}
|
|
@@ -49,6 +67,7 @@ export function extractEntity(call, sourceFile) {
|
|
|
49
67
|
// Field-type membership is checked above; the cast is the extractor's
|
|
50
68
|
// existing narrowing contract (readDataLiteralNode returns unknown).
|
|
51
69
|
definition: defWithoutName,
|
|
70
|
+
...(spreadOnly?.backingTable && { backingTable: spreadOnly.backingTable }),
|
|
52
71
|
});
|
|
53
72
|
}
|
|
54
73
|
const entityName = readNameLiteral(first);
|
|
@@ -8,7 +8,7 @@ export type { AddAuthClaimsArgs, AddClaimKeyArgs, AddConfigArgs, AddDefineEventA
|
|
|
8
8
|
export { createFeaturePatcher } from "./patcher.ts";
|
|
9
9
|
export type { PatternChangeIssue, PatternChangesParseResult } from "./pattern-change-schema.ts";
|
|
10
10
|
export { parsePatternChanges } from "./pattern-change-schema.ts";
|
|
11
|
-
export type { AuthClaimsPattern, ClaimKeyPattern, ConfigPattern, DefineEventPattern, Editability, EntityPattern, ExtendsRegistrarPattern, FeaturePattern, FeaturePatternKind, HookPattern, HttpRoutePattern, JobPattern, MetricPattern, MultiStreamProjectionPattern, NavPattern, NotificationPattern, OptionalRequiresPattern, ProjectionPattern, QueryHandlerPattern, ReadsConfigPattern, ReferenceDataPattern, RelationPattern, RequiresPattern, ScreenPattern, SecretNamespacePattern, SecretPattern, StreamHandlerPattern, SystemScopePattern, ToggleablePattern, TranslationsPattern, UnknownPattern, UseExtensionPattern, WorkspacePattern, WriteHandlerPattern, } from "./patterns.ts";
|
|
11
|
+
export type { AdoptsBundledListsPattern, AuthClaimsPattern, ClaimKeyPattern, ConfigPattern, DefineEventPattern, Editability, EntityPattern, ExtendsRegistrarPattern, FeaturePattern, FeaturePatternKind, HookPattern, HttpRoutePattern, JobPattern, MetricPattern, MultiStreamProjectionPattern, NavPattern, NotificationPattern, OptionalRequiresPattern, ProjectionPattern, QueryHandlerPattern, ReadsConfigPattern, ReferenceDataPattern, RelationPattern, RequiresPattern, ScreenPattern, SecretNamespacePattern, SecretPattern, StreamHandlerPattern, SystemScopePattern, ToggleablePattern, TranslationsPattern, UnknownPattern, UseExtensionPattern, WorkspacePattern, WriteHandlerPattern, } from "./patterns.ts";
|
|
12
12
|
export { getEditability } from "./patterns.ts";
|
|
13
13
|
export type { RenderFeatureFileInput } from "./render.ts";
|
|
14
14
|
export { FEATURE_FILE_VERSION, renderFeatureFile, renderPattern, renderValue, VERSION_HEADER, } from "./render.ts";
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
// Per-pattern extractors fill in iteratively — each iteration adds
|
|
22
22
|
// one extractor + a focused test.
|
|
23
23
|
import { Project, SyntaxKind } from "ts-morph";
|
|
24
|
-
import { extractAiClassify, extractAiExtract, extractAiGenerate, extractAuthClaims, extractBootCheck, extractClaimKey, extractConfig, extractDefineEvent, extractDescribe, extractEntity, extractEnvSchema, extractExposesApi, extractExtendsRegistrar, extractHook, extractHttpRoute, extractJob, extractMetric, extractMultiStreamProjection, extractNav, extractNotification, extractOptionalRequires, extractProjection, extractQueryHandler, extractReadsConfig, extractReferenceData, extractRelation, extractRequires, extractScreen, extractSecret, extractSecretNamespace, extractStoreTable, extractStreamHandler, extractSystemScope, extractToggleable, extractTranslations, extractTreeActions, extractUiHints, extractUseExtension, extractUsesApi, extractWorkspace, extractWriteHandler, findFunctionLiteral, findImportBindingForLocalName, readObjectPropertyInitializer, resolveModuleFile, resolveSameFileObjectLiteral, } from "./extractors/index.js";
|
|
24
|
+
import { extractAdoptsBundledLists, extractAiClassify, extractAiExtract, extractAiGenerate, extractAuthClaims, extractBootCheck, extractClaimKey, extractConfig, extractDefineEvent, extractDescribe, extractEntity, extractEnvSchema, extractExposesApi, extractExtendsRegistrar, extractHook, extractHttpRoute, extractJob, extractMetric, extractMultiStreamProjection, extractNav, extractNotification, extractOptionalRequires, extractProjection, extractQueryHandler, extractReadsConfig, extractReferenceData, extractRelation, extractRequires, extractScreen, extractSecret, extractSecretNamespace, extractStoreTable, extractStreamHandler, extractSystemScope, extractToggleable, extractTranslations, extractTreeActions, extractUiHints, extractUseExtension, extractUsesApi, extractWorkspace, extractWriteHandler, findFunctionLiteral, findImportBindingForLocalName, readObjectPropertyInitializer, resolveModuleFile, resolveSameFileObjectLiteral, } from "./extractors/index.js";
|
|
25
25
|
import { sourceLocationFromNode } from "./source-location.js";
|
|
26
26
|
/**
|
|
27
27
|
* Parse the given feature file and return all recognised r.* calls
|
|
@@ -397,6 +397,8 @@ function dispatchExtractor(methodName, call, sourceFile) {
|
|
|
397
397
|
return extractDescribe(call, sourceFile);
|
|
398
398
|
case "uiHints":
|
|
399
399
|
return extractUiHints(call, sourceFile);
|
|
400
|
+
case "adoptsBundledLists":
|
|
401
|
+
return extractAdoptsBundledLists(call, sourceFile);
|
|
400
402
|
// Object-literal-based static patterns
|
|
401
403
|
case "entity":
|
|
402
404
|
return extractEntity(call, sourceFile);
|