@cosmicdrift/kumiko-framework 0.386.0 → 0.388.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 +6 -1
- package/LICENSE +21 -57
- package/README.md +2 -2
- 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/legal-pages.md +1 -1
- 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/wizard-form.md +941 -0
- package/agents/examples/writeform-section.md +548 -0
- package/agents/features.md +19 -2
- package/agents/widgets.md +40 -39
- package/dist/api/api-constants.js +2 -2
- package/dist/api/auth-middleware.js +7 -7
- package/dist/api/auth-rate-limiters.js +7 -3
- package/dist/api/auth-routes-mfa.js +1 -1
- package/dist/api/auth-routes-session.js +1 -1
- package/dist/api/auth-routes-shared.js +7 -3
- package/dist/api/auth-routes-signup.js +1 -1
- package/dist/api/client-error-route.js +8 -2
- package/dist/api/client-ip.js +3 -1
- package/dist/api/extra-route.js +1 -1
- package/dist/api/index.d.ts +3 -1
- package/dist/api/index.js +3 -1
- package/dist/api/pii-leak-guard.js +4 -2
- package/dist/api/readiness.js +5 -5
- package/dist/api/redis-sse-broker.js +8 -6
- package/dist/api/request-context.d.ts +1 -1
- package/dist/api/request-context.js +1 -1
- 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 +203 -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 +293 -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 +236 -0
- package/dist/api/server.d.ts +10 -15
- package/dist/api/server.js +48 -1250
- package/dist/api/session-cookies.js +4 -4
- package/dist/api/sse-broker.js +1 -1
- package/dist/api/sse-route.d.ts +13 -13
- package/dist/api/sse-route.js +31 -27
- package/dist/auth/index.js +4 -4
- package/dist/auth/roles.d.ts +4 -4
- package/dist/auth/roles.js +24 -24
- package/dist/compliance/duration-spec.js +18 -20
- package/dist/compliance/index.js +2 -3
- package/dist/compliance/override-schema.d.ts +4 -4
- package/dist/compliance/override-schema.js +19 -22
- package/dist/compliance/profiles.d.ts +26 -29
- package/dist/compliance/profiles.js +62 -69
- package/dist/compliance/sub-processors.d.ts +28 -30
- package/dist/compliance/sub-processors.js +17 -21
- package/dist/consumer-cli.js +4 -4
- package/dist/crypto/blind-index.js +18 -17
- package/dist/crypto/ciphertext-pattern.js +1 -1
- package/dist/crypto/event-pii.js +3 -3
- package/dist/crypto/kek-source.d.ts +1 -1
- package/dist/crypto/kek-source.js +3 -2
- package/dist/crypto/kms-adapter.d.ts +1 -1
- package/dist/crypto/kms-adapter.js +4 -6
- package/dist/crypto/kms-wiring.d.ts +1 -2
- package/dist/crypto/kms-wiring.js +2 -2
- 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.js +2 -6
- package/dist/crypto/pii-field-encryption.d.ts +5 -1
- package/dist/crypto/pii-field-encryption.js +7 -5
- package/dist/crypto/subject-resolver.d.ts +1 -1
- package/dist/crypto/subject-resolver.js +2 -2
- package/dist/db/aggregate-sql.d.ts +21 -0
- package/dist/db/aggregate-sql.js +155 -0
- package/dist/db/apply-entity-event.d.ts +6 -6
- package/dist/db/apply-entity-event.js +55 -55
- package/dist/db/blind-index-cleanup.js +7 -7
- package/dist/db/closed-connection.d.ts +9 -0
- package/dist/db/closed-connection.js +95 -0
- package/dist/db/collect-table-metas.js +10 -11
- package/dist/db/compound-types.d.ts +1 -1
- package/dist/db/compound-types.js +12 -12
- package/dist/db/cursor.js +3 -4
- package/dist/db/dialect.d.ts +2 -2
- package/dist/db/dialect.js +3 -3
- 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 +99 -0
- package/dist/db/eagerload.d.ts +3 -3
- package/dist/db/eagerload.js +21 -12
- 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.d.ts +2 -2
- package/dist/db/entity-table-meta.js +105 -112
- package/dist/db/event-store-executor-context.d.ts +3 -2
- package/dist/db/event-store-executor-context.js +13 -13
- package/dist/db/event-store-executor-read-aggregate.d.ts +8 -0
- package/dist/db/event-store-executor-read-aggregate.js +112 -0
- package/dist/db/event-store-executor-read-filter.d.ts +31 -0
- package/dist/db/event-store-executor-read-filter.js +203 -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 +50 -704
- package/dist/db/event-store-executor-write-steps.d.ts +20 -0
- package/dist/db/event-store-executor-write-steps.js +100 -0
- package/dist/db/event-store-executor-write.js +401 -510
- package/dist/db/index.d.ts +6 -2
- package/dist/db/index.js +5 -1
- package/dist/db/list-aggregate-labels.d.ts +14 -0
- package/dist/db/list-aggregate-labels.js +26 -0
- package/dist/db/located-timestamp.d.ts +11 -11
- package/dist/db/located-timestamp.js +29 -30
- package/dist/db/migrate-generator.d.ts +1 -1
- package/dist/db/migrate-generator.js +97 -105
- package/dist/db/migrate-runner.js +29 -26
- package/dist/db/money.d.ts +6 -6
- package/dist/db/money.js +29 -27
- package/dist/db/queries/backfill-pii.js +5 -5
- package/dist/db/queries/ddl.js +1 -1
- package/dist/db/queries/es-ops.d.ts +1 -1
- package/dist/db/queries/es-ops.js +1 -1
- package/dist/db/queries/event-consumer.js +3 -3
- package/dist/db/queries/event-store.js +4 -2
- package/dist/db/queries/projection-rebuild.js +3 -3
- package/dist/db/queries/raw-sql.d.ts +2 -2
- package/dist/db/queries/raw-sql.js +2 -2
- package/dist/db/queries/shadow-swap.js +19 -19
- package/dist/db/query.d.ts +3 -16
- package/dist/db/query.js +8 -761
- package/dist/db/rebuild-marker.js +20 -21
- package/dist/db/reference-data.js +6 -1
- package/dist/db/replay-migration-sql.js +2 -2
- package/dist/db/schema-inspection.js +4 -5
- package/dist/db/table-builder.d.ts +1 -2
- package/dist/db/table-builder.js +137 -190
- 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.d.ts +2 -2
- package/dist/db/tenant-db.js +48 -11
- package/dist/db/where-clause.d.ts +6 -0
- package/dist/db/where-clause.js +236 -0
- package/dist/derivatives/delete-stored-file.js +6 -2
- package/dist/derivatives/derivatives-context.js +1 -1
- package/dist/engine/boot-validator/access-roles.js +4 -3
- package/dist/engine/boot-validator/api-ext.js +14 -14
- package/dist/engine/boot-validator/boot-check.js +1 -1
- package/dist/engine/boot-validator/config-deps.js +7 -6
- package/dist/engine/boot-validator/detail-screens.js +4 -4
- package/dist/engine/boot-validator/entity-handler.d.ts +1 -0
- package/dist/engine/boot-validator/entity-handler.js +77 -61
- package/dist/engine/boot-validator/form-derivations.js +35 -1
- package/dist/engine/boot-validator/gdpr-storage.js +4 -4
- package/dist/engine/boot-validator/i18n-keys.js +6 -4
- package/dist/engine/boot-validator/index.d.ts +2 -2
- package/dist/engine/boot-validator/index.js +22 -20
- package/dist/engine/boot-validator/nav.js +5 -5
- package/dist/engine/boot-validator/ownership.js +12 -9
- package/dist/engine/boot-validator/parent-ref.js +1 -1
- package/dist/engine/boot-validator/pii-retention.js +258 -187
- package/dist/engine/boot-validator/projection-list-screens.js +7 -7
- package/dist/engine/boot-validator/query-refs.js +1 -1
- package/dist/engine/boot-validator/screens-actions.d.ts +1 -0
- package/dist/engine/boot-validator/screens-actions.js +23 -17
- package/dist/engine/boot-validator/screens-dashboard.js +2 -5
- package/dist/engine/boot-validator/screens-forms.js +12 -17
- 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 +228 -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 +52 -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 +26 -24
- package/dist/engine/boot-validator/screens.d.ts +0 -2
- package/dist/engine/boot-validator/screens.js +102 -869
- package/dist/engine/boot-validator/security-baseline.js +3 -2
- package/dist/engine/boot-validator/transfer-graph.js +2 -2
- package/dist/engine/boot-validator/workspaces.js +3 -3
- package/dist/engine/bridge-stub.js +3 -4
- package/dist/engine/build-app-schema.js +130 -170
- package/dist/engine/build-config-feature-schema.js +50 -50
- package/dist/engine/build-target.js +20 -23
- package/dist/engine/codemod/pipeline-codemod.js +20 -13
- package/dist/engine/config-helpers.js +4 -4
- package/dist/engine/constants.js +2 -2
- package/dist/engine/create-app.js +2 -2
- package/dist/engine/define-feature.js +21 -13
- package/dist/engine/define-handler.js +13 -11
- package/dist/engine/define-step.js +1 -1
- package/dist/engine/define-workflow.d.ts +5 -5
- package/dist/engine/define-workflow.js +6 -6
- package/dist/engine/entity-handlers.d.ts +13 -0
- package/dist/engine/entity-handlers.js +22 -34
- package/dist/engine/entity-list-runtime-options.d.ts +8 -0
- package/dist/engine/entity-list-runtime-options.js +18 -0
- package/dist/engine/event-def.js +2 -2
- package/dist/engine/extension-names.d.ts +16 -17
- package/dist/engine/extension-names.js +37 -38
- package/dist/engine/extensions/escape-hatch-usage.js +1 -1
- package/dist/engine/extensions/tenant-data.js +2 -2
- package/dist/engine/extensions/user-data.d.ts +23 -24
- package/dist/engine/factories.d.ts +14 -13
- package/dist/engine/factories.js +38 -37
- package/dist/engine/feature-ast/entity-field-types.js +1 -1
- package/dist/engine/feature-ast/extractors/handlers.js +2 -1
- package/dist/engine/feature-ast/extractors/hooks.js +1 -1
- package/dist/engine/feature-ast/extractors/round2.js +25 -6
- package/dist/engine/feature-ast/extractors/shared.d.ts +2 -3
- package/dist/engine/feature-ast/extractors/shared.js +2 -3
- package/dist/engine/feature-ast/parse.js +13 -13
- package/dist/engine/feature-ast/patch.js +4 -182
- package/dist/engine/feature-ast/pattern-change-schema.d.ts +3 -0
- package/dist/engine/feature-ast/pattern-change-schema.js +2 -1
- package/dist/engine/feature-ast/pattern-id-matchers.d.ts +7 -0
- package/dist/engine/feature-ast/pattern-id-matchers.js +210 -0
- package/dist/engine/feature-ast/patterns.d.ts +11 -2
- package/dist/engine/feature-ast/patterns.js +43 -51
- package/dist/engine/feature-ast/render.js +50 -89
- package/dist/engine/feature-config-events-jobs.js +15 -12
- package/dist/engine/feature-entity-handlers.js +12 -5
- package/dist/engine/feature-manifest.d.ts +9 -9
- package/dist/engine/feature-manifest.js +6 -7
- package/dist/engine/feature-ui-extensions.d.ts +3 -3
- package/dist/engine/feature-ui-extensions.js +30 -22
- package/dist/engine/field-access.js +5 -6
- package/dist/engine/form-derivations.js +18 -7
- package/dist/engine/handler-field-references.js +1 -1
- package/dist/engine/index.d.ts +1 -0
- package/dist/engine/index.js +4 -4
- package/dist/engine/object-form.d.ts +1 -0
- package/dist/engine/object-form.js +14 -4
- package/dist/engine/ownership.js +3 -3
- package/dist/engine/parse-ref-target.js +5 -7
- package/dist/engine/pattern-library/index.js +2 -2
- package/dist/engine/pattern-library/library.js +2 -2
- package/dist/engine/pattern-library/types.js +3 -3
- package/dist/engine/pipeline.js +2 -2
- package/dist/engine/project-app-schema-for-roles.d.ts +2 -0
- package/dist/engine/project-app-schema-for-roles.js +7 -5
- package/dist/engine/projection-helpers.js +9 -9
- package/dist/engine/qualified-name.js +2 -2
- package/dist/engine/registry-facade.js +1 -1
- package/dist/engine/registry-ingest.js +13 -13
- package/dist/engine/registry-state.js +17 -19
- package/dist/engine/registry-validate.js +12 -12
- package/dist/engine/run-in.js +2 -2
- package/dist/engine/run-pipeline.js +7 -0
- package/dist/engine/schema-builder.js +251 -233
- package/dist/engine/screen-filter-ops.js +17 -20
- package/dist/engine/screen-helpers.js +4 -3
- package/dist/engine/screen-kind.d.ts +7 -0
- package/dist/engine/screen-kind.js +1 -0
- package/dist/engine/state-machine.d.ts +12 -12
- package/dist/engine/state-machine.js +7 -7
- package/dist/engine/steps/_resolver-utils.js +4 -3
- package/dist/engine/steps/for-each.js +4 -4
- package/dist/engine/steps/unsafe-projection-delete.js +1 -1
- package/dist/engine/steps/unsafe-projection-upsert.js +4 -4
- package/dist/engine/steps/wait-for-event.js +4 -4
- package/dist/engine/steps/workflow-system-events.js +3 -3
- package/dist/engine/strip-disabled-features-from-app-schema.js +51 -14
- package/dist/engine/tier-resolver-extension.d.ts +29 -27
- package/dist/engine/tier-resolver-extension.js +26 -26
- package/dist/engine/transfer-adjacency.js +2 -2
- package/dist/engine/validate-projection-allowlist.js +9 -28
- package/dist/engine/walk-step-instances.d.ts +2 -0
- package/dist/engine/walk-step-instances.js +38 -0
- package/dist/engine/where-rule-lint.js +1 -1
- package/dist/engine/write-handler-qn-extract.js +1 -1
- package/dist/entrypoint/index.d.ts +4 -1
- package/dist/entrypoint/index.js +10 -4
- package/dist/env/index.d.ts +7 -6
- package/dist/env/index.js +10 -9
- package/dist/errors/docs-url.d.ts +1 -1
- package/dist/errors/docs-url.js +22 -2
- package/dist/errors/transition-details.js +7 -7
- package/dist/errors/write-error-info.d.ts +6 -6
- package/dist/errors/write-error-info.js +6 -6
- package/dist/es-ops/context.d.ts +9 -9
- package/dist/es-ops/context.js +29 -29
- package/dist/es-ops/index.js +7 -9
- package/dist/es-ops/operations-schema.js +4 -10
- package/dist/es-ops/runner.d.ts +11 -11
- package/dist/es-ops/runner.js +49 -53
- package/dist/es-ops/types.d.ts +55 -55
- package/dist/es-ops/types.js +11 -11
- package/dist/event-store/admin-api.js +7 -8
- package/dist/event-store/errors.js +1 -1
- package/dist/event-store/event-store.js +12 -6
- package/dist/event-store/rebuild-dead-letter.js +1 -1
- package/dist/files/bind-pending-file-refs.js +3 -3
- package/dist/files/create-file-ref-from-bytes.js +4 -1
- package/dist/files/feature.js +9 -10
- package/dist/files/file-handle.js +7 -9
- package/dist/files/file-ref-entity.js +15 -15
- package/dist/files/file-ref-table.js +7 -8
- package/dist/files/file-routes.d.ts +7 -0
- package/dist/files/file-routes.js +22 -13
- package/dist/files/in-memory-provider.js +8 -9
- package/dist/files/local-provider.js +18 -25
- package/dist/files/provider-resolver.d.ts +7 -7
- package/dist/files/resolve-content-type.js +43 -0
- package/dist/files/storage-tracking.js +2 -2
- package/dist/files/upload-ledger.js +7 -0
- package/dist/files/zip-stream.d.ts +12 -19
- package/dist/files/zip-stream.js +44 -63
- package/dist/i18n/required-surface-keys.d.ts +1 -1
- package/dist/i18n/required-surface-keys.js +188 -212
- package/dist/internal/stack-support.d.ts +2 -1
- package/dist/internal/stack-support.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 +69 -4
- package/dist/jobs/job-runner-schedulers.d.ts +1 -1
- package/dist/jobs/job-runner-schedulers.js +3 -4
- 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 +57 -669
- package/dist/lifecycle/lifecycle.js +3 -5
- package/dist/lifecycle/signal-handlers.js +5 -4
- package/dist/logging/utils.d.ts +2 -1
- package/dist/logging/utils.js +38 -10
- package/dist/migrations/index.js +1 -1
- package/dist/migrations/kumiko-drift.js +14 -13
- package/dist/migrations/pending-rebuilds.d.ts +21 -20
- package/dist/migrations/pending-rebuilds.js +27 -27
- package/dist/migrations/projection-table-index.d.ts +3 -3
- package/dist/migrations/projection-table-index.js +8 -8
- package/dist/observability/escape-hatch-report.d.ts +3 -0
- package/dist/observability/escape-hatch-report.js +12 -1
- package/dist/observability/metric-validator.js +1 -1
- package/dist/observability/metrics-handle.js +3 -3
- package/dist/pipeline/append-event-core.js +11 -2
- package/dist/pipeline/cascade-handler.d.ts +1 -1
- package/dist/pipeline/cascade-handler.js +165 -138
- package/dist/pipeline/dispatch-batch.js +2 -2
- package/dist/pipeline/dispatch-query.js +20 -13
- package/dist/pipeline/dispatch-shared.d.ts +14 -3
- package/dist/pipeline/dispatch-shared.js +67 -721
- package/dist/pipeline/dispatch-stream.js +1 -1
- package/dist/pipeline/dispatch-write.js +297 -190
- package/dist/pipeline/dispatcher-utils.d.ts +1 -1
- package/dist/pipeline/dispatcher-utils.js +1 -1
- package/dist/pipeline/event-consumer-state.js +2 -2
- package/dist/pipeline/event-dispatcher-admin.js +2 -1
- package/dist/pipeline/event-dispatcher-delivery.js +4 -6
- package/dist/pipeline/event-dispatcher.js +17 -28
- 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 +21 -0
- package/dist/pipeline/handler-context-dispatch.js +89 -0
- package/dist/pipeline/handler-context-events.d.ts +43 -0
- package/dist/pipeline/handler-context-events.js +237 -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/irreversible-operation-gate.js +1 -1
- package/dist/pipeline/lifecycle-pipeline.js +9 -9
- package/dist/pipeline/member-read-only-transaction.js +1 -3
- package/dist/pipeline/msp-rebuild.js +1 -1
- 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 +15 -13
- package/dist/pipeline/system-hooks.js +39 -41
- package/dist/pipeline/system-identity-switch.js +1 -3
- package/dist/pipeline/tenant-timezone-cache.js +1 -1
- package/dist/random/generate.d.ts +29 -29
- package/dist/random/generate.js +30 -30
- package/dist/random/words.js +20 -20
- package/dist/rate-limit/middleware.js +9 -5
- package/dist/redis/client.js +2 -2
- package/dist/redis/pubsub-signal.js +14 -17
- 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 -510
- package/dist/search/index.js +4 -4
- package/dist/search/meilisearch-adapter.js +2 -1
- package/dist/search/purge-subject.js +4 -5
- package/dist/search/reindex-entity.js +6 -9
- package/dist/time/boot-tz-warning.d.ts +2 -2
- package/dist/time/boot-tz-warning.js +8 -8
- package/dist/time/iana.js +10 -10
- package/dist/time/index.js +9 -9
- package/dist/time/legacy-date.d.ts +2 -2
- package/dist/time/legacy-date.js +6 -8
- package/dist/time/polyfill.js +1 -1
- package/dist/time/tz-context.d.ts +1 -1
- package/dist/time/tz-context.js +1 -1
- package/dist/ui-types/app-schema.js +7 -7
- package/dist/ui-types/list-row-meta.js +4 -4
- package/dist/upgrade-cli.js +159 -130
- package/dist/utils/compare.js +1 -1
- package/package.json +5 -5
- package/src/changes.json +358 -0
- package/src/scripts/codemod/crypto-shredding-testing-move.ts +2 -2
- package/src/scripts/codemod/feature-layout.ts +10 -2
- package/src/scripts/codemod/migrate-cross-tenant.ts +1 -1
- package/src/scripts/codemod/migrate-open-to-all.ts +1 -1
- 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 +192 -153
- package/src/scripts/codemod/testing-injection.ts +122 -42
- package/src/scripts/codemod/testing-move.ts +29 -7
- package/src/scripts/codemod/unprocessable-error-details-reason.ts +2 -2
package/dist/db/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { isTimestamptzType } from "./aggregate-sql.ts";
|
|
1
2
|
export { applyEntityEvent } from "./apply-entity-event.ts";
|
|
2
3
|
export { assertExistsIn } from "./assert-exists-in.ts";
|
|
3
4
|
export { nullBlindIndexesForSubject, recordEventsOwnedExclusivelyByTenant, recordRowExistsInTenant, recordRowOwningTenantId, subjectRowExistsInTenant, } from "./blind-index-cleanup.ts";
|
|
@@ -10,6 +11,7 @@ export type { CursorQueryOptions, CursorResult, DecodedKeysetCursor } from "./cu
|
|
|
10
11
|
export { decodeCursor, decodeKeysetCursor, encodeCursor, encodeKeysetCursor } from "./cursor.ts";
|
|
11
12
|
export type { SchemaTable, SelectQuery, TableColumns } from "./dialect.ts";
|
|
12
13
|
export { bigint, bigserial, boolean, extractTableName, index, instant, instantToDriver, integer, jsonb, moneyAmount, numeric, primaryKey, serial, sql, table, text, timestamp, uniqueIndex, uuid, } from "./dialect.ts";
|
|
14
|
+
export { instantToTimestamptzParam } from "./driver-value-preparation.ts";
|
|
13
15
|
export type { EagerLoadEntityResolver, EagerLoadViewer, EagerloadedRow } from "./eagerload.ts";
|
|
14
16
|
export { collectReferenceFields, enrichRowWithReferences, enrichWithReferences, } from "./eagerload.ts";
|
|
15
17
|
export { collectEncryptedFieldNames, configuredEntityFieldEncryption, configureEntityFieldEncryption, decryptEntityFieldValues, encryptEntityFieldValues, } from "./entity-field-encryption.ts";
|
|
@@ -19,6 +21,7 @@ export { defineUnmanagedTable, deriveEntityTableMeta, } from "./entity-table-met
|
|
|
19
21
|
export type { EntityLifecycleVerb, EventStoreExecutor, EventStoreExecutorOptions, LockGuardOption, WritePurpose, } from "./event-store-executor.ts";
|
|
20
22
|
export { createEventStoreExecutor, entityEventName, WritePurposes, } from "./event-store-executor.ts";
|
|
21
23
|
export { enumerateFeatureTableSources, type FeatureTableSource, } from "./feature-table-sources.ts";
|
|
24
|
+
export { answerListAggregate, labelListAggregateGroups } from "./list-aggregate-labels.ts";
|
|
22
25
|
export { flattenLocatedTimestamp, type LocatedTimestampRead, rehydrateLocatedTimestamp, } from "./located-timestamp.ts";
|
|
23
26
|
export { assertUniqueTableNames, assertValidMigrationName, diffSnapshots, type GenerateMigrationInput, type GenerateMigrationOutput, generateMigration, loadSnapshotJson, renderMigrationSql, type SchemaDiff, type Snapshot, snapshotFromMetas, writeSnapshotJson, } from "./migrate-generator.ts";
|
|
24
27
|
export { type AppliedMigration, type ApplyResult, type BaselineResult, baselineMigrations, fetchAppliedMigrations, loadMigrationsFromDir, type Migration, MigrationChecksumMismatchError, readMigrationSqlTexts, runMigrations, runMigrationsFromDir, splitSqlStatements, } from "./migrate-runner.ts";
|
|
@@ -28,8 +31,8 @@ export { acquireNamespacedAdvisoryLock } from "./queries/advisory-lock.ts";
|
|
|
28
31
|
export { readDatabaseNow } from "./queries/database-now.ts";
|
|
29
32
|
export { toPostgresArrayLiteral } from "./queries/postgres-array-literal.ts";
|
|
30
33
|
export { executeRawQuery, executeRawQueryRead } from "./queries/raw-sql.ts";
|
|
31
|
-
export type { DeleteManyBatchedOptions, DeleteManyBatchedResult, IncrementCounterOptions, InnerJoinRow, InnerJoinSpec, InsertOnConflictDoNothingOptions, JoinColumnPair, JsonTextMatch, SelectOptions,
|
|
32
|
-
export { aggregateWhere, asEntityTableMeta, asRawClient, countWhere, deleteMany, deleteManyBatched,
|
|
34
|
+
export type { DeleteManyBatchedOptions, DeleteManyBatchedResult, IncrementCounterOptions, InnerJoinRow, InnerJoinSpec, InsertOnConflictDoNothingOptions, JoinColumnPair, JsonTextMatch, SelectOptions, UpsertOnConflictOptions, WhereObject, WhereOperator, WhereValue, } from "./query.ts";
|
|
35
|
+
export { aggregateWhere, asEntityTableMeta, asRawClient, countWhere, deleteMany, deleteManyBatched, fetchOne, incrementCounter, insertMany, insertOnConflictDoNothing, insertOne, requireEntityTableMeta, runInSavepoint, runInSavepointIfSupported, runnerCanBeginTransaction, selectInnerJoin, selectMany, transaction, unsafeReadRetrying, updateMany, upsertByPk, upsertOnConflict, } from "./query.ts";
|
|
33
36
|
export { readRebuildMarker, rebuildTablesFromDiff, writeRebuildMarker, } from "./rebuild-marker.ts";
|
|
34
37
|
export { seedReferenceData } from "./reference-data.ts";
|
|
35
38
|
export { renderTableDdl, renderTablesDdl } from "./render-ddl.ts";
|
|
@@ -38,5 +41,6 @@ export { findCommentedDropTables, isRetiredFrameworkTable, type RetiredFramework
|
|
|
38
41
|
export { tableExists } from "./schema-inspection.ts";
|
|
39
42
|
export { withoutStatementTimeout } from "./statement-timeout.ts";
|
|
40
43
|
export { buildBaseColumns, buildEntityTable, declareGlobalTenancy, type EntityRow, type EntityTable, type ExecutorManagedRunner, type ExecutorManagedWriteCapability, physicalColumnName, toSnakeCase, toTableName, type Writable, type WritableSchemaTable, type WritableTable, } from "./table-builder.ts";
|
|
44
|
+
export { extractTableInfo, type TableInfo } from "./table-info.ts";
|
|
41
45
|
export type { CreateTenantDbOptions, ExecutorManagedTenantDb, OutsideTransactionContext, TenantDb, TenantDbGrants, TenantDbMode, UncheckedSystemDb, } from "./tenant-db.ts";
|
|
42
46
|
export { castTenantRows, createSystemDbView, createTenantDataDestroyDb, createTenantDb, hasOutsideTransactionDb, requireOutsideTransactionDb, runInOwnTransaction, SYSTEM_SCOPE_CHECK_BRAND, scopeTenantDbToTenant, } from "./tenant-db.ts";
|
package/dist/db/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { isTimestamptzType } from "./aggregate-sql.js";
|
|
1
2
|
export { applyEntityEvent } from "./apply-entity-event.js";
|
|
2
3
|
export { assertExistsIn } from "./assert-exists-in.js";
|
|
3
4
|
export { nullBlindIndexesForSubject, recordEventsOwnedExclusivelyByTenant, recordRowExistsInTenant, recordRowOwningTenantId, subjectRowExistsInTenant, } from "./blind-index-cleanup.js";
|
|
@@ -7,12 +8,14 @@ export { seedConfigValues } from "./config-seed.js";
|
|
|
7
8
|
export { createDbConnection, DEFAULT_OUTSIDE_TRANSACTION_POOL_MAX, dbConnectionOptionsFromEnv, outsideTransactionPoolOptionsFromEnv, serverTimeoutOptionsFromEnv, } from "./connection.js";
|
|
8
9
|
export { decodeCursor, decodeKeysetCursor, encodeCursor, encodeKeysetCursor } from "./cursor.js";
|
|
9
10
|
export { bigint, bigserial, boolean, extractTableName, index, instant, instantToDriver, integer, jsonb, moneyAmount, numeric, primaryKey, serial, sql, table, text, timestamp, uniqueIndex, uuid, } from "./dialect.js";
|
|
11
|
+
export { instantToTimestamptzParam } from "./driver-value-preparation.js";
|
|
10
12
|
export { collectReferenceFields, enrichRowWithReferences, enrichWithReferences, } from "./eagerload.js";
|
|
11
13
|
export { collectEncryptedFieldNames, configuredEntityFieldEncryption, configureEntityFieldEncryption, decryptEntityFieldValues, encryptEntityFieldValues, } from "./entity-field-encryption.js";
|
|
12
14
|
export { entityTableFromRegistry } from "./entity-table-from-registry.js";
|
|
13
15
|
export { defineUnmanagedTable, deriveEntityTableMeta, } from "./entity-table-meta.js";
|
|
14
16
|
export { createEventStoreExecutor, entityEventName, WritePurposes, } from "./event-store-executor.js";
|
|
15
17
|
export { enumerateFeatureTableSources, } from "./feature-table-sources.js";
|
|
18
|
+
export { answerListAggregate, labelListAggregateGroups } from "./list-aggregate-labels.js";
|
|
16
19
|
export { flattenLocatedTimestamp, rehydrateLocatedTimestamp, } from "./located-timestamp.js";
|
|
17
20
|
export { assertUniqueTableNames, assertValidMigrationName, diffSnapshots, generateMigration, loadSnapshotJson, renderMigrationSql, snapshotFromMetas, writeSnapshotJson, } from "./migrate-generator.js";
|
|
18
21
|
export { baselineMigrations, fetchAppliedMigrations, loadMigrationsFromDir, MigrationChecksumMismatchError, readMigrationSqlTexts, runMigrations, runMigrationsFromDir, splitSqlStatements, } from "./migrate-runner.js";
|
|
@@ -22,7 +25,7 @@ export { acquireNamespacedAdvisoryLock } from "./queries/advisory-lock.js";
|
|
|
22
25
|
export { readDatabaseNow } from "./queries/database-now.js";
|
|
23
26
|
export { toPostgresArrayLiteral } from "./queries/postgres-array-literal.js";
|
|
24
27
|
export { executeRawQuery, executeRawQueryRead } from "./queries/raw-sql.js";
|
|
25
|
-
export { aggregateWhere, asEntityTableMeta, asRawClient, countWhere, deleteMany, deleteManyBatched,
|
|
28
|
+
export { aggregateWhere, asEntityTableMeta, asRawClient, countWhere, deleteMany, deleteManyBatched, fetchOne, incrementCounter, insertMany, insertOnConflictDoNothing, insertOne, requireEntityTableMeta, runInSavepoint, runInSavepointIfSupported, runnerCanBeginTransaction, selectInnerJoin, selectMany, transaction, unsafeReadRetrying, updateMany, upsertByPk, upsertOnConflict, } from "./query.js";
|
|
26
29
|
export { readRebuildMarker, rebuildTablesFromDiff, writeRebuildMarker, } from "./rebuild-marker.js";
|
|
27
30
|
export { seedReferenceData } from "./reference-data.js";
|
|
28
31
|
export { renderTableDdl, renderTablesDdl } from "./render-ddl.js";
|
|
@@ -31,4 +34,5 @@ export { findCommentedDropTables, isRetiredFrameworkTable, retiredFrameworkTable
|
|
|
31
34
|
export { tableExists } from "./schema-inspection.js";
|
|
32
35
|
export { withoutStatementTimeout } from "./statement-timeout.js";
|
|
33
36
|
export { buildBaseColumns, buildEntityTable, declareGlobalTenancy, physicalColumnName, toSnakeCase, toTableName, } from "./table-builder.js";
|
|
37
|
+
export { extractTableInfo } from "./table-info.js";
|
|
34
38
|
export { castTenantRows, createSystemDbView, createTenantDataDestroyDb, createTenantDb, hasOutsideTransactionDb, requireOutsideTransactionDb, runInOwnTransaction, SYSTEM_SCOPE_CHECK_BRAND, scopeTenantDbToTenant, } from "./tenant-db.js";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ListAggregateResult } from "@cosmicdrift/kumiko-types/list-aggregate-types";
|
|
2
|
+
import type { EntityDefinition } from "../engine/types/index.ts";
|
|
3
|
+
import type { EagerLoadEntityResolver, EagerLoadViewer } from "./eagerload.ts";
|
|
4
|
+
import type { EventStoreExecutor } from "./event-store-executor.ts";
|
|
5
|
+
import type { TenantDb } from "./tenant-db.ts";
|
|
6
|
+
type LabelDeps = {
|
|
7
|
+
readonly entity: EntityDefinition;
|
|
8
|
+
readonly resolveEntity: EagerLoadEntityResolver;
|
|
9
|
+
readonly viewer: EagerLoadViewer;
|
|
10
|
+
};
|
|
11
|
+
export declare function labelListAggregateGroups(result: ListAggregateResult, groupByField: string | undefined, deps: LabelDeps, db: TenantDb): Promise<ListAggregateResult>;
|
|
12
|
+
type AggregateRequest = Parameters<EventStoreExecutor["aggregate"]>[0];
|
|
13
|
+
export declare function answerListAggregate(executor: Pick<EventStoreExecutor, "aggregate">, request: AggregateRequest, user: Parameters<EventStoreExecutor["aggregate"]>[1], db: TenantDb, runtimeOptions: Parameters<EventStoreExecutor["aggregate"]>[3], labelDeps: LabelDeps): Promise<ListAggregateResult>;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { enrichWithReferences } from "./eagerload.js";
|
|
2
|
+
function labelOf(ref, labelField) {
|
|
3
|
+
if (typeof ref !== "object" || ref === null || Array.isArray(ref))
|
|
4
|
+
return null;
|
|
5
|
+
const value = Reflect.get(ref, labelField);
|
|
6
|
+
return typeof value === "string" ? value : null;
|
|
7
|
+
}
|
|
8
|
+
// Labels come from the same eager-load path as list rows, so they carry its
|
|
9
|
+
// ownership and field-read gating instead of a second label query.
|
|
10
|
+
export async function labelListAggregateGroups(result, groupByField, deps, db) {
|
|
11
|
+
if (groupByField === undefined || result.groups.length === 0)
|
|
12
|
+
return result;
|
|
13
|
+
const def = deps.entity.fields[groupByField];
|
|
14
|
+
if (def?.type !== "reference" || def.multiple === true)
|
|
15
|
+
return result;
|
|
16
|
+
const enriched = await enrichWithReferences(result.groups.map((g) => ({ [groupByField]: g.key })), deps.entity, deps.resolveEntity, db, deps.viewer);
|
|
17
|
+
const groups = result.groups.map((group, i) => {
|
|
18
|
+
const ref = Reflect.get(enriched[i]?.["_refs"] ?? {}, groupByField);
|
|
19
|
+
return { ...group, label: labelOf(ref, def.labelField ?? "id") };
|
|
20
|
+
});
|
|
21
|
+
return { ...result, groups };
|
|
22
|
+
}
|
|
23
|
+
export async function answerListAggregate(executor, request, user, db, runtimeOptions, labelDeps) {
|
|
24
|
+
const result = await executor.aggregate(request, user, db, runtimeOptions);
|
|
25
|
+
return labelListAggregateGroups(result, request.aggregate.groupBy, labelDeps, db);
|
|
26
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { EntityDefinition } from "../engine/types/index.ts";
|
|
2
2
|
/**
|
|
3
|
-
* API → DB: locatedTimestamp
|
|
3
|
+
* API → DB: flatten locatedTimestamp fields into two flat columns.
|
|
4
4
|
*
|
|
5
|
-
* - `{ at, tz }` (UI
|
|
6
|
-
* - `{ utc, tz }` (
|
|
7
|
-
* - `{ at, tz, utc }` → utc
|
|
8
|
-
*
|
|
5
|
+
* - `{ at, tz }` (UI form) → `{ <name>Utc, <name>Tz }` (`utc` calculated via Temporal)
|
|
6
|
+
* - `{ utc, tz }` (server form) → `utc` takes precedence
|
|
7
|
+
* - `{ at, tz, utc }` → `utc` takes precedence; `at` is ignored (the caller is
|
|
8
|
+
* responsible for the consistency check)
|
|
9
9
|
*
|
|
10
|
-
* Pure —
|
|
10
|
+
* Pure — does not mutate.
|
|
11
11
|
*/
|
|
12
12
|
export declare function flattenLocatedTimestamp(payload: Record<string, unknown>, entity: EntityDefinition): Record<string, unknown>;
|
|
13
13
|
/** Shape of a single rehydrated locatedTimestamp field. `at` is the wall clock in `tz`
|
|
@@ -18,12 +18,12 @@ export type LocatedTimestampRead = {
|
|
|
18
18
|
readonly utc: string;
|
|
19
19
|
};
|
|
20
20
|
/**
|
|
21
|
-
* DB → API:
|
|
21
|
+
* DB → API: rehydrate two flat columns into combined { at, tz, utc }.
|
|
22
22
|
*
|
|
23
|
-
* `at`
|
|
24
|
-
*
|
|
25
|
-
*
|
|
23
|
+
* `at` is always the wall-clock time in the stored `tz` (local to the pickup
|
|
24
|
+
* location). To obtain a user-specific view, derive it from `utc` yourself —
|
|
25
|
+
* the server does not know the user's time zone.
|
|
26
26
|
*
|
|
27
|
-
* Pure —
|
|
27
|
+
* Pure — does not mutate.
|
|
28
28
|
*/
|
|
29
29
|
export declare function rehydrateLocatedTimestamp(row: Record<string, unknown>, entity: EntityDefinition): Record<string, unknown>;
|
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Automatically converts locatedTimestamp fields in the DB layer.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
// API
|
|
5
|
-
// DB
|
|
6
|
-
// Read
|
|
3
|
+
// Contract (see also db/money.ts — the same compound-type pattern):
|
|
4
|
+
// API form: { at, tz } | { utc, tz }
|
|
5
|
+
// DB form: <name>Utc TIMESTAMPTZ + <name>Tz TEXT
|
|
6
|
+
// Read form: { at, tz, utc }
|
|
7
7
|
//
|
|
8
|
-
// `at
|
|
9
|
-
//
|
|
10
|
-
//
|
|
8
|
+
// Default `at` view on read: local to the pickup location (`utc` projected into
|
|
9
|
+
// the stored `tz`). The server does not know the user's time zone, so
|
|
10
|
+
// user-specific display is derived from `utc` on the client.
|
|
11
11
|
// Static import, not the ambient global: Bun doesn't expose Temporal on
|
|
12
12
|
// globalThis, so this crashed with "Temporal is not defined" outside boot
|
|
13
|
-
// paths that install it
|
|
13
|
+
// paths that install it.
|
|
14
14
|
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
// Legacy-Code-Pfade die noch Strings durchreichen (z.B. raw SQL).
|
|
15
|
+
// The <name>Utc column uses instant() (see dialect.ts), so Drizzle returns Temporal.Instant.
|
|
16
|
+
// Previously, a PostgreSQL wire-format string "2026-04-15 09:00:00+00" had to be
|
|
17
|
+
// converted to ISO 8601 through string manipulation. The customType now handles
|
|
18
|
+
// DB↔Instant conversion, so this function is only defensive glue for legacy code
|
|
19
|
+
// paths that still pass strings (for example, raw SQL).
|
|
21
20
|
function toInstant(value) {
|
|
22
21
|
if (value instanceof Temporal.Instant)
|
|
23
22
|
return value;
|
|
@@ -27,14 +26,14 @@ function toInstant(value) {
|
|
|
27
26
|
return Temporal.Instant.from(iso);
|
|
28
27
|
}
|
|
29
28
|
/**
|
|
30
|
-
* API → DB: locatedTimestamp
|
|
29
|
+
* API → DB: flatten locatedTimestamp fields into two flat columns.
|
|
31
30
|
*
|
|
32
|
-
* - `{ at, tz }` (UI
|
|
33
|
-
* - `{ utc, tz }` (
|
|
34
|
-
* - `{ at, tz, utc }` → utc
|
|
35
|
-
*
|
|
31
|
+
* - `{ at, tz }` (UI form) → `{ <name>Utc, <name>Tz }` (`utc` calculated via Temporal)
|
|
32
|
+
* - `{ utc, tz }` (server form) → `utc` takes precedence
|
|
33
|
+
* - `{ at, tz, utc }` → `utc` takes precedence; `at` is ignored (the caller is
|
|
34
|
+
* responsible for the consistency check)
|
|
36
35
|
*
|
|
37
|
-
* Pure —
|
|
36
|
+
* Pure — does not mutate.
|
|
38
37
|
*/
|
|
39
38
|
export function flattenLocatedTimestamp(payload, entity) {
|
|
40
39
|
const T = Temporal;
|
|
@@ -53,10 +52,10 @@ export function flattenLocatedTimestamp(payload, entity) {
|
|
|
53
52
|
if (pair.tz === undefined)
|
|
54
53
|
continue;
|
|
55
54
|
const tz = pair.tz;
|
|
56
|
-
//
|
|
57
|
-
// Temporal.Instant.
|
|
58
|
-
// toInstant() (
|
|
59
|
-
// Temporal
|
|
55
|
+
// The <name>Utc column uses instant(); Drizzle expects
|
|
56
|
+
// Temporal.Instant. Conversion from pair.utc string → Instant goes through
|
|
57
|
+
// toInstant() (which handles strings and Instant values); pair.at + tz →
|
|
58
|
+
// Instant uses Temporal math.
|
|
60
59
|
const instant = pair.utc !== undefined
|
|
61
60
|
? toInstant(pair.utc)
|
|
62
61
|
: pair.at !== undefined
|
|
@@ -70,13 +69,13 @@ export function flattenLocatedTimestamp(payload, entity) {
|
|
|
70
69
|
return result;
|
|
71
70
|
}
|
|
72
71
|
/**
|
|
73
|
-
* DB → API:
|
|
72
|
+
* DB → API: rehydrate two flat columns into combined { at, tz, utc }.
|
|
74
73
|
*
|
|
75
|
-
* `at`
|
|
76
|
-
*
|
|
77
|
-
*
|
|
74
|
+
* `at` is always the wall-clock time in the stored `tz` (local to the pickup
|
|
75
|
+
* location). To obtain a user-specific view, derive it from `utc` yourself —
|
|
76
|
+
* the server does not know the user's time zone.
|
|
78
77
|
*
|
|
79
|
-
* Pure —
|
|
78
|
+
* Pure — does not mutate.
|
|
80
79
|
*/
|
|
81
80
|
export function rehydrateLocatedTimestamp(row, entity) {
|
|
82
81
|
const result = { ...row };
|
|
@@ -3,7 +3,7 @@ import { type RetiredFrameworkTable } from "./retired-framework-tables.ts";
|
|
|
3
3
|
declare const SNAPSHOT_VERSION: 1;
|
|
4
4
|
export type Snapshot = {
|
|
5
5
|
readonly version: typeof SNAPSHOT_VERSION;
|
|
6
|
-
readonly generatedAt
|
|
6
|
+
readonly generatedAt?: string;
|
|
7
7
|
readonly tables: readonly EntityTableMeta[];
|
|
8
8
|
};
|
|
9
9
|
export type ColumnChange = {
|
|
@@ -1,31 +1,36 @@
|
|
|
1
|
-
// Build-time
|
|
2
|
-
//
|
|
1
|
+
// Build-time generator: EntityTableMeta[] → reviewable SQL migration file.
|
|
2
|
+
// Replacement for `drizzle-kit generate`.
|
|
3
3
|
//
|
|
4
|
-
// **NO-MAGIC-ON-DATA
|
|
5
|
-
// -
|
|
6
|
-
// -
|
|
7
|
-
// -
|
|
8
|
-
// (BRIN
|
|
9
|
-
// - Append-only:
|
|
10
|
-
//
|
|
11
|
-
// Sequence-Number.
|
|
4
|
+
// **NO-MAGIC-ON-DATA core principle** (see drizzle-replacement.md):
|
|
5
|
+
// - The generator emits SQL files for PR review/editing.
|
|
6
|
+
// - The generator is NEVER called at app runtime.
|
|
7
|
+
// - The output is a starting point; app authors may hand-edit the SQL
|
|
8
|
+
// (BRIN index, partial index, performance tuning) before committing.
|
|
9
|
+
// - Append-only: existing migration files are NEVER overwritten.
|
|
10
|
+
// New schema diffs go into a NEW file with an incremented sequence number.
|
|
12
11
|
//
|
|
13
|
-
// **DESTRUCTIVE
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
12
|
+
// **DESTRUCTIVE operations** (DROP TABLE/COLUMN, index removal) are emitted
|
|
13
|
+
// as commented-out statements — reviewers must explicitly uncomment them
|
|
14
|
+
// and may need to add a data-backup step beforehand. Default:
|
|
15
|
+
// never drop automatically.
|
|
17
16
|
import { readFileSync, writeFileSync } from "node:fs";
|
|
18
17
|
import { errorCodeOf, isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
|
|
19
18
|
import { compareByCodepoint } from "../utils/index.js";
|
|
20
19
|
import { renderIndex, renderTableDdl } from "./render-ddl.js";
|
|
21
20
|
import { findRetiredTableDrops } from "./retired-framework-tables.js";
|
|
22
21
|
const SNAPSHOT_VERSION = 1;
|
|
22
|
+
function isSnapshot(value) {
|
|
23
|
+
return (isPlainObject(value) &&
|
|
24
|
+
value["version"] === SNAPSHOT_VERSION &&
|
|
25
|
+
(value["generatedAt"] === undefined || typeof value["generatedAt"] === "string") &&
|
|
26
|
+
Array.isArray(value["tables"]));
|
|
27
|
+
}
|
|
23
28
|
export function snapshotFromMetas(metas) {
|
|
24
29
|
// Stable ordering by tableName so the snapshot.json diff in PRs is
|
|
25
30
|
// meaningful (table-add isn't a noisy re-sort of everything). Codepoint, not
|
|
26
31
|
// localeCompare: the snapshot is serialized to byte-exact JSON and the table
|
|
27
32
|
// order carries into the generated migration SQL — locale-dependent ordering
|
|
28
|
-
// would drift between macOS-dev and Linux-CI
|
|
33
|
+
// would drift between macOS-dev and Linux-CI.
|
|
29
34
|
const sorted = [...metas].sort((a, b) => compareByCodepoint(a.tableName, b.tableName));
|
|
30
35
|
return {
|
|
31
36
|
version: SNAPSHOT_VERSION,
|
|
@@ -41,6 +46,9 @@ export function loadSnapshotJson(path) {
|
|
|
41
46
|
if (version !== SNAPSHOT_VERSION) {
|
|
42
47
|
throw new Error(`Snapshot at ${path} has version ${String(version)}, expected ${SNAPSHOT_VERSION}`);
|
|
43
48
|
}
|
|
49
|
+
if (!isSnapshot(parsed)) {
|
|
50
|
+
throw new Error(`Snapshot at ${path} is malformed: expected a tables list`);
|
|
51
|
+
}
|
|
44
52
|
return parsed;
|
|
45
53
|
}
|
|
46
54
|
catch (err) {
|
|
@@ -53,7 +61,7 @@ export function writeSnapshotJson(path, snapshot) {
|
|
|
53
61
|
writeFileSync(path, `${JSON.stringify(snapshot, null, 2)}\n`);
|
|
54
62
|
}
|
|
55
63
|
function indexMetaKey(idx) {
|
|
56
|
-
// Index
|
|
64
|
+
// Index identity is based on its name (PostgreSQL constraint: unique within the database).
|
|
57
65
|
return idx.name;
|
|
58
66
|
}
|
|
59
67
|
function indexColumnsEqual(a, b) {
|
|
@@ -71,100 +79,85 @@ function indexesByName(meta) {
|
|
|
71
79
|
m.set(indexMetaKey(i), i);
|
|
72
80
|
return m;
|
|
73
81
|
}
|
|
74
|
-
function
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
if (
|
|
88
|
-
|
|
89
|
-
nullabilityChanged: { from: prevCol.notNull, to: nextCol.notNull },
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
if (prevCol.defaultSql !== nextCol.defaultSql) {
|
|
93
|
-
Object.assign(change, {
|
|
94
|
-
defaultChanged: { from: prevCol.defaultSql, to: nextCol.defaultSql },
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
if (prevCol.pgType !== nextCol.pgType) {
|
|
98
|
-
Object.assign(change, {
|
|
99
|
-
typeChanged: { from: prevCol.pgType, to: nextCol.pgType },
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
if (change.nullabilityChanged || change.defaultChanged || change.typeChanged) {
|
|
103
|
-
changedColumns.push(change);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
for (const name of prevCols.keys()) {
|
|
107
|
-
if (!nextCols.has(name))
|
|
108
|
-
droppedColumns.push(name);
|
|
109
|
-
}
|
|
110
|
-
const prevIdx = indexesByName(prev);
|
|
111
|
-
const nextIdx = indexesByName(next);
|
|
112
|
-
const newIndexes = [];
|
|
113
|
-
const droppedIndexes = [];
|
|
114
|
-
const changedIndexes = [];
|
|
115
|
-
for (const [name, idx] of nextIdx) {
|
|
116
|
-
const prevI = prevIdx.get(name);
|
|
117
|
-
if (!prevI) {
|
|
118
|
-
newIndexes.push(idx);
|
|
82
|
+
function strictEqual(a, b) {
|
|
83
|
+
return a === b;
|
|
84
|
+
}
|
|
85
|
+
function fromToWhenDifferent(from, to, isEqual = strictEqual) {
|
|
86
|
+
return isEqual(from, to) ? undefined : { from, to };
|
|
87
|
+
}
|
|
88
|
+
// added and changed follow next's order, dropped follows prev's order; the
|
|
89
|
+
// rendered migration depends on both.
|
|
90
|
+
function diffByName(prev, next, compare) {
|
|
91
|
+
const added = [];
|
|
92
|
+
const changed = [];
|
|
93
|
+
for (const [name, nextItem] of next) {
|
|
94
|
+
const prevItem = prev.get(name);
|
|
95
|
+
if (prevItem === undefined) {
|
|
96
|
+
added.push(nextItem);
|
|
119
97
|
continue;
|
|
120
98
|
}
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const uniqueChanged = (prevI.unique ?? false) === (idx.unique ?? false)
|
|
125
|
-
? undefined
|
|
126
|
-
: { from: prevI.unique ?? false, to: idx.unique ?? false };
|
|
127
|
-
// Whitespace-only re-rendering of the predicate must not drop and rebuild a large index.
|
|
128
|
-
const whereSqlChanged = whereSqlEqual(prevI.whereSql, idx.whereSql)
|
|
129
|
-
? undefined
|
|
130
|
-
: { from: prevI.whereSql, to: idx.whereSql };
|
|
131
|
-
const needsManualWhereChanged = (prevI.needsManualWhere ?? false) === (idx.needsManualWhere ?? false)
|
|
132
|
-
? undefined
|
|
133
|
-
: { from: prevI.needsManualWhere ?? false, to: idx.needsManualWhere ?? false };
|
|
134
|
-
if (columnsChanged || uniqueChanged || whereSqlChanged || needsManualWhereChanged) {
|
|
135
|
-
// Single literal typed as IndexChange so a misspelled key fails to compile instead of silently dropping the change.
|
|
136
|
-
const change = {
|
|
137
|
-
name,
|
|
138
|
-
...(columnsChanged && { columnsChanged }),
|
|
139
|
-
...(uniqueChanged && { uniqueChanged }),
|
|
140
|
-
...(whereSqlChanged && { whereSqlChanged }),
|
|
141
|
-
...(needsManualWhereChanged && { needsManualWhereChanged }),
|
|
142
|
-
};
|
|
143
|
-
changedIndexes.push(change);
|
|
144
|
-
}
|
|
99
|
+
const change = compare(name, prevItem, nextItem);
|
|
100
|
+
if (change !== undefined)
|
|
101
|
+
changed.push(change);
|
|
145
102
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
103
|
+
const dropped = [...prev.keys()].filter((name) => !next.has(name));
|
|
104
|
+
return { added, dropped, changed };
|
|
105
|
+
}
|
|
106
|
+
function compareColumns(name, prevCol, nextCol) {
|
|
107
|
+
const nullabilityChanged = fromToWhenDifferent(prevCol.notNull, nextCol.notNull);
|
|
108
|
+
const defaultChanged = fromToWhenDifferent(prevCol.defaultSql, nextCol.defaultSql);
|
|
109
|
+
const typeChanged = fromToWhenDifferent(prevCol.pgType, nextCol.pgType);
|
|
110
|
+
if (!nullabilityChanged && !defaultChanged && !typeChanged)
|
|
111
|
+
return undefined;
|
|
112
|
+
return {
|
|
113
|
+
name,
|
|
114
|
+
...(nullabilityChanged && { nullabilityChanged }),
|
|
115
|
+
...(defaultChanged && { defaultChanged }),
|
|
116
|
+
...(typeChanged && { typeChanged }),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function compareIndexes(name, prevIndex, nextIndex) {
|
|
120
|
+
const columnsChanged = fromToWhenDifferent(prevIndex.columns, nextIndex.columns, indexColumnsEqual);
|
|
121
|
+
const uniqueChanged = fromToWhenDifferent(prevIndex.unique ?? false, nextIndex.unique ?? false);
|
|
122
|
+
// Whitespace-only re-rendering of the predicate must not drop and rebuild a large index.
|
|
123
|
+
const whereSqlChanged = fromToWhenDifferent(prevIndex.whereSql, nextIndex.whereSql, whereSqlEqual);
|
|
124
|
+
const needsManualWhereChanged = fromToWhenDifferent(prevIndex.needsManualWhere ?? false, nextIndex.needsManualWhere ?? false);
|
|
125
|
+
if (!columnsChanged && !uniqueChanged && !whereSqlChanged && !needsManualWhereChanged) {
|
|
126
|
+
return undefined;
|
|
149
127
|
}
|
|
150
|
-
|
|
151
|
-
droppedColumns.length === 0 &&
|
|
152
|
-
changedColumns.length === 0 &&
|
|
153
|
-
newIndexes.length === 0 &&
|
|
154
|
-
droppedIndexes.length === 0 &&
|
|
155
|
-
changedIndexes.length === 0;
|
|
156
|
-
if (isEmpty)
|
|
157
|
-
return null;
|
|
128
|
+
// Single literal typed as IndexChange so a misspelled key fails to compile instead of silently dropping the change.
|
|
158
129
|
return {
|
|
130
|
+
name,
|
|
131
|
+
...(columnsChanged && { columnsChanged }),
|
|
132
|
+
...(uniqueChanged && { uniqueChanged }),
|
|
133
|
+
...(whereSqlChanged && { whereSqlChanged }),
|
|
134
|
+
...(needsManualWhereChanged && { needsManualWhereChanged }),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function hasNoTableChanges(diff) {
|
|
138
|
+
return [
|
|
139
|
+
diff.newColumns,
|
|
140
|
+
diff.droppedColumns,
|
|
141
|
+
diff.changedColumns,
|
|
142
|
+
diff.newIndexes,
|
|
143
|
+
diff.droppedIndexes,
|
|
144
|
+
diff.changedIndexes,
|
|
145
|
+
].every((list) => list.length === 0);
|
|
146
|
+
}
|
|
147
|
+
function diffOneTable(prev, next) {
|
|
148
|
+
const columns = diffByName(columnsByName(prev), columnsByName(next), compareColumns);
|
|
149
|
+
const indexes = diffByName(indexesByName(prev), indexesByName(next), compareIndexes);
|
|
150
|
+
const diff = {
|
|
159
151
|
tableName: prev.tableName,
|
|
160
|
-
newColumns,
|
|
161
|
-
droppedColumns,
|
|
162
|
-
changedColumns,
|
|
163
|
-
newIndexes,
|
|
164
|
-
droppedIndexes,
|
|
165
|
-
changedIndexes,
|
|
152
|
+
newColumns: columns.added,
|
|
153
|
+
droppedColumns: columns.dropped,
|
|
154
|
+
changedColumns: columns.changed,
|
|
155
|
+
newIndexes: indexes.added,
|
|
156
|
+
droppedIndexes: indexes.dropped,
|
|
157
|
+
changedIndexes: indexes.changed,
|
|
166
158
|
nextMeta: next,
|
|
167
159
|
};
|
|
160
|
+
return hasNoTableChanges(diff) ? null : diff;
|
|
168
161
|
}
|
|
169
162
|
export function diffSnapshots(prev, next) {
|
|
170
163
|
const prevByName = new Map();
|
|
@@ -273,8 +266,7 @@ function renderColumnChange(tableName, change) {
|
|
|
273
266
|
// timestamptz → date: PG's implicit ::date cast (what a bare ALTER ...
|
|
274
267
|
// TYPE without USING falls back to) reads the session TimeZone, so the
|
|
275
268
|
// same row migrates to a different calendar day depending on who/where
|
|
276
|
-
// runs it
|
|
277
|
-
// Anchor explicitly at UTC instead of trusting the session.
|
|
269
|
+
// runs it. Anchor explicitly at UTC instead of trusting the session.
|
|
278
270
|
if ((from === "timestamptz" || from === "timestamptz(3)") && to === "date") {
|
|
279
271
|
out.push(`-- ${from} → date: explicit UTC anchor — a bare cast would use the session TimeZone (non-deterministic).`);
|
|
280
272
|
out.push(`ALTER TABLE ${tbl} ALTER COLUMN ${col} TYPE date USING (${col} AT TIME ZONE 'UTC')::date;`);
|
|
@@ -383,7 +375,7 @@ export function renderMigrationSql(diff, options) {
|
|
|
383
375
|
// needsManualWhere renders CREATE as a commented WARN (renderIndex),
|
|
384
376
|
// since the generator can't express the new WHERE — the DROP has to
|
|
385
377
|
// stay commented too, or the live index gets dropped with no
|
|
386
|
-
// executable replacement
|
|
378
|
+
// executable replacement.
|
|
387
379
|
lines.push(nextIdxMeta.needsManualWhere === true
|
|
388
380
|
? `-- (review) DROP INDEX IF EXISTS ${quoteIdent(idxChange.name)};`
|
|
389
381
|
: `DROP INDEX IF EXISTS ${quoteIdent(idxChange.name)};`);
|