@cosmicdrift/kumiko-framework 0.385.0 → 0.387.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/LICENSE +21 -57
- package/README.md +2 -2
- package/agents/widgets.md +39 -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-ip.js +3 -1
- package/dist/api/extra-route.js +1 -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 +2 -0
- package/dist/api/request-context.js +16 -7
- package/dist/api/routes.js +2 -2
- package/dist/api/server.js +34 -33
- package/dist/api/sse-broker.js +1 -1
- package/dist/api/sse-route.d.ts +13 -13
- package/dist/api/sse-route.js +15 -15
- 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/pg-kms-adapter.js +2 -6
- package/dist/crypto/pii-field-encryption.js +4 -4
- package/dist/crypto/subject-resolver.d.ts +1 -1
- package/dist/crypto/subject-resolver.js +2 -2
- 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/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/cross-tenant-reads.d.ts +8 -0
- package/dist/db/cross-tenant-reads.js +23 -0
- package/dist/db/cursor.js +3 -4
- package/dist/db/dialect.d.ts +2 -2
- package/dist/db/dialect.js +2 -2
- package/dist/db/eagerload.d.ts +3 -3
- package/dist/db/eagerload.js +21 -12
- package/dist/db/entity-table-meta.d.ts +2 -2
- package/dist/db/entity-table-meta.js +4 -4
- package/dist/db/event-store-executor-context.d.ts +1 -1
- package/dist/db/event-store-executor-context.js +13 -13
- package/dist/db/event-store-executor-read.js +27 -28
- package/dist/db/event-store-executor-write.js +65 -70
- 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 +26 -19
- package/dist/db/migrate-runner.js +25 -25
- 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/queries/test-stack.d.ts +4 -1
- package/dist/db/queries/test-stack.js +15 -2
- package/dist/db/query.d.ts +1 -1
- package/dist/db/query.js +6 -6
- package/dist/db/rebuild-marker.js +20 -21
- 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 +82 -82
- package/dist/db/tenant-db.d.ts +2 -2
- package/dist/db/tenant-db.js +9 -2
- package/dist/derivatives/delete-stored-file.js +5 -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/config-deps.js +7 -6
- package/dist/engine/boot-validator/detail-screens.js +3 -3
- package/dist/engine/boot-validator/entity-handler.js +60 -61
- package/dist/engine/boot-validator/gdpr-storage.js +4 -4
- package/dist/engine/boot-validator/i18n-keys.js +1 -1
- package/dist/engine/boot-validator/index.d.ts +2 -2
- package/dist/engine/boot-validator/index.js +20 -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 +50 -57
- 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.js +15 -16
- package/dist/engine/boot-validator/screens-forms.js +10 -11
- package/dist/engine/boot-validator/screens-lists.js +14 -15
- package/dist/engine/boot-validator/screens.js +34 -40
- 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 +75 -75
- 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 +12 -11
- package/dist/engine/define-handler.js +12 -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.js +13 -14
- 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 +1 -1
- package/dist/engine/feature-ast/extractors/hooks.js +1 -1
- 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 +1 -1
- package/dist/engine/feature-ast/pattern-change-schema.d.ts +8 -0
- package/dist/engine/feature-ast/pattern-change-schema.js +1 -1
- package/dist/engine/feature-ast/patterns.d.ts +2 -2
- package/dist/engine/feature-ast/render.js +2 -2
- package/dist/engine/feature-config-events-jobs.js +15 -12
- package/dist/engine/feature-entity-handlers.js +9 -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/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.js +1 -1
- 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 +12 -12
- 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 +40 -38
- package/dist/engine/screen-filter-ops.js +17 -20
- package/dist/engine/screen-helpers.js +4 -3
- 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/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 +7 -27
- 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.js +3 -3
- package/dist/env/index.d.ts +7 -6
- package/dist/env/index.js +10 -9
- 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 +28 -28
- 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 +6 -7
- package/dist/event-store/errors.js +1 -1
- package/dist/event-store/event-store.js +2 -2
- package/dist/event-store/rebuild-dead-letter.js +1 -1
- package/dist/files/feature.js +9 -10
- package/dist/files/file-handle.js +5 -6
- 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 +11 -5
- 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/storage-tracking.js +2 -2
- 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 +8 -8
- package/dist/internal/stack-support.d.ts +1 -1
- package/dist/internal/stack-support.js +1 -1
- package/dist/jobs/job-runner-helpers.d.ts +1 -2
- package/dist/jobs/job-runner-helpers.js +8 -18
- package/dist/jobs/job-runner-schedulers.d.ts +1 -1
- package/dist/jobs/job-runner-schedulers.js +3 -4
- package/dist/jobs/job-runner.js +17 -18
- 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/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/dispatch-batch.js +2 -2
- package/dist/pipeline/dispatch-query.js +10 -10
- package/dist/pipeline/dispatch-shared.d.ts +1 -0
- package/dist/pipeline/dispatch-shared.js +42 -19
- package/dist/pipeline/dispatch-stream.js +1 -1
- package/dist/pipeline/dispatch-write.js +3 -3
- 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-delivery.js +1 -1
- package/dist/pipeline/event-dispatcher.js +17 -28
- 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/projection-rebuild.js +13 -12
- 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.js +116 -22
- package/dist/search/index.js +4 -4
- 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 +10 -9
- package/dist/utils/compare.js +1 -1
- package/package.json +4 -4
- package/src/changes.json +54 -0
- package/src/scripts/codemod/crypto-shredding-testing-move.ts +2 -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/pii-personal-migration.ts +17 -8
- package/src/scripts/codemod/unprocessable-error-details-reason.ts +2 -2
|
@@ -8,14 +8,14 @@ import type { UserDataExtensionOptions } from "./extensions/user-data.ts";
|
|
|
8
8
|
import type { AssignableFromRole } from "./role-assignment.ts";
|
|
9
9
|
import { TENANT_TIER_RESOLVER_EXT, type TierResolverPlugin } from "./tier-resolver-extension.ts";
|
|
10
10
|
/**
|
|
11
|
-
* `userData` —
|
|
11
|
+
* `userData` — user-data rights hooks (GDPR Articles 15, 17, and 20).
|
|
12
12
|
*
|
|
13
|
-
*
|
|
13
|
+
* Expected hook methods:
|
|
14
14
|
* - `export(userId, ctx) => Promise<UserDataExport>`
|
|
15
15
|
* - `delete(userId, strategy: "delete" | "anonymize", ctx) => Promise<void>`
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
17
|
+
* Registered by: `user-data-rights`.
|
|
18
|
+
* Used by: every feature with user references (tasks, comments, files, ...).
|
|
19
19
|
*/
|
|
20
20
|
export declare const EXT_USER_DATA: "userData";
|
|
21
21
|
export declare const EXT_USER_DATA_ORDER: {
|
|
@@ -41,17 +41,16 @@ export declare const EXT_TENANT_DATA: "tenantData";
|
|
|
41
41
|
*/
|
|
42
42
|
export declare const EXT_STORAGE_PROVIDER: "storageProvider";
|
|
43
43
|
/**
|
|
44
|
-
* `fileProvider` —
|
|
44
|
+
* `fileProvider` — file-storage provider plugin selection (file-foundation).
|
|
45
45
|
*
|
|
46
|
-
* Provider
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
46
|
+
* Provider features (file-provider-s3, -inmemory, -s3-env) register an
|
|
47
|
+
* implementation via `r.useExtension(EXT_FILE_PROVIDER, "<name>", { build })`;
|
|
48
|
+
* the per-tenant config key `provider` selects one at runtime. The framework
|
|
49
|
+
* resolver (`createFileProviderForTenant`) reads it so upload routes,
|
|
50
|
+
* `ctx.files`, and GDPR jobs all use the same store.
|
|
51
51
|
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* registrieren.
|
|
52
|
+
* The framework owns this contract to prevent string drift — file-foundation
|
|
53
|
+
* MUST register the extension point and config key under exactly these names.
|
|
55
54
|
*/
|
|
56
55
|
export declare const EXT_FILE_PROVIDER: "fileProvider";
|
|
57
56
|
export declare const FILE_PROVIDER_CONFIG_KEY: "file-foundation:config:provider";
|
|
@@ -85,7 +84,7 @@ export declare const EXT_DERIVATIVE_RENDERER: "derivativeRenderer";
|
|
|
85
84
|
* serves nothing for that entityType, not even a 403 (404, so existence isn't
|
|
86
85
|
* confirmed to an unauthorised caller).
|
|
87
86
|
*
|
|
88
|
-
* Registered/consumed by: `file-derivatives`' public variant route
|
|
87
|
+
* Registered/consumed by: `file-derivatives`' public variant route.
|
|
89
88
|
*/
|
|
90
89
|
export declare const EXT_DERIVATIVE_PUBLIC_PREDICATE: "derivativePublicPredicate";
|
|
91
90
|
/**
|
|
@@ -150,9 +149,9 @@ export declare const EXT_TENANT_LIFECYCLE_STATUS: "tenantLifecycleStatus";
|
|
|
150
149
|
export declare const EXT_ASSIGNABLE_ROLE: "assignableRole";
|
|
151
150
|
export declare const TENANT_MEMBERSHIPS_QUERY: "tenant:query:memberships";
|
|
152
151
|
/**
|
|
153
|
-
* Union
|
|
154
|
-
*
|
|
155
|
-
*
|
|
152
|
+
* Union of standardized extension names for the privacy surface.
|
|
153
|
+
* Not every extension in the system is included — other features can still
|
|
154
|
+
* register their own extension names.
|
|
156
155
|
*/
|
|
157
156
|
export type KumikoExtensionName = typeof EXT_USER_DATA | typeof EXT_TENANT_DATA | typeof EXT_STORAGE_PROVIDER | typeof EXT_SEARCH_ADAPTER | typeof EXT_EXTERNAL_RESOURCE | typeof EXT_INFRA_RESOURCE | typeof EXT_FILE_PROVIDER | typeof EXT_DERIVATIVE_RENDERER | typeof EXT_DERIVATIVE_PUBLIC_PREDICATE | typeof EXT_DERIVATIVE_OVERLAY_RESOLVER | typeof EXT_PRINCIPAL_STATUS | typeof EXT_TENANT_LIFECYCLE_STATUS | typeof EXT_ASSIGNABLE_ROLE;
|
|
158
157
|
/** The four `destroyTenant(tenantId, ctx)`-only resource-cleanup extension points. */
|
|
@@ -1,42 +1,42 @@
|
|
|
1
1
|
import { TENANT_TIER_RESOLVER_EXT } from "./tier-resolver-extension.js";
|
|
2
|
-
//
|
|
2
|
+
// Standardized extension names for privacy-hook axes.
|
|
3
3
|
//
|
|
4
|
-
// Features
|
|
4
|
+
// Features register extensions via:
|
|
5
5
|
// r.extendsRegistrar(EXT_USER_DATA, { hooks: { ... } });
|
|
6
6
|
//
|
|
7
|
-
//
|
|
7
|
+
// Other features attach to them via:
|
|
8
8
|
// r.useExtension(EXT_USER_DATA, "myEntity", { ...hookImpls });
|
|
9
9
|
//
|
|
10
|
-
//
|
|
11
|
-
// text-content
|
|
12
|
-
// Constants
|
|
13
|
-
//
|
|
14
|
-
// (validateExtensionUsages)
|
|
15
|
-
//
|
|
16
|
-
//
|
|
10
|
+
// Background: magic strings drift between bundled features (for example,
|
|
11
|
+
// text-content uses "Admin" as a role, while tenant-handler uses
|
|
12
|
+
// "TenantAdmin"). Constants are the single source of truth; string literals
|
|
13
|
+
// are gradually replaced at the relevant integration points. The boot
|
|
14
|
+
// validator (validateExtensionUsages) checks that every useExtension has a
|
|
15
|
+
// matching extendsRegistrar, so typos in constants cause a compile-time
|
|
16
|
+
// failure.
|
|
17
17
|
//
|
|
18
|
-
// Hook
|
|
19
|
-
//
|
|
20
|
-
// userData / tenantData →
|
|
21
|
-
// storageProvider →
|
|
22
|
-
// searchAdapter / external / →
|
|
18
|
+
// Hook signatures and boot validation for each extension axis are added by
|
|
19
|
+
// the feature that registers that axis:
|
|
20
|
+
// userData / tenantData → (user-data-rights, retention)
|
|
21
|
+
// storageProvider → (storage-encryption)
|
|
22
|
+
// searchAdapter / external / → (tenant-lifecycle)
|
|
23
23
|
// infraResource
|
|
24
24
|
/**
|
|
25
|
-
* `userData` —
|
|
25
|
+
* `userData` — user-data rights hooks (GDPR Articles 15, 17, and 20).
|
|
26
26
|
*
|
|
27
|
-
*
|
|
27
|
+
* Expected hook methods:
|
|
28
28
|
* - `export(userId, ctx) => Promise<UserDataExport>`
|
|
29
29
|
* - `delete(userId, strategy: "delete" | "anonymize", ctx) => Promise<void>`
|
|
30
30
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
31
|
+
* Registered by: `user-data-rights`.
|
|
32
|
+
* Used by: every feature with user references (tasks, comments, files, ...).
|
|
33
33
|
*/
|
|
34
34
|
export const EXT_USER_DATA = "userData";
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
// user-data-rights)
|
|
38
|
-
//
|
|
39
|
-
// (
|
|
35
|
+
// Ordering bands for EXT_USER_DATA hooks (forget pipeline). The contract was
|
|
36
|
+
// implicit across two packages (-100 in custom-fields, 0 in
|
|
37
|
+
// user-data-rights), so a host hook with order < REDACT_BEFORE_OWNER would run
|
|
38
|
+
// BEFORE the redactors and reintroduce the strip-after-owner-null bug
|
|
39
|
+
// (GDPR Article 17 regression). Rule: redactors < 0 <= owner-mutating hooks.
|
|
40
40
|
export const EXT_USER_DATA_ORDER = {
|
|
41
41
|
REDACT_BEFORE_OWNER: -100,
|
|
42
42
|
DEFAULT: 0,
|
|
@@ -60,23 +60,22 @@ export const EXT_TENANT_DATA = "tenantData";
|
|
|
60
60
|
*/
|
|
61
61
|
export const EXT_STORAGE_PROVIDER = "storageProvider";
|
|
62
62
|
/**
|
|
63
|
-
* `fileProvider` —
|
|
63
|
+
* `fileProvider` — file-storage provider plugin selection (file-foundation).
|
|
64
64
|
*
|
|
65
|
-
* Provider
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
65
|
+
* Provider features (file-provider-s3, -inmemory, -s3-env) register an
|
|
66
|
+
* implementation via `r.useExtension(EXT_FILE_PROVIDER, "<name>", { build })`;
|
|
67
|
+
* the per-tenant config key `provider` selects one at runtime. The framework
|
|
68
|
+
* resolver (`createFileProviderForTenant`) reads it so upload routes,
|
|
69
|
+
* `ctx.files`, and GDPR jobs all use the same store.
|
|
70
70
|
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
* registrieren.
|
|
71
|
+
* The framework owns this contract to prevent string drift — file-foundation
|
|
72
|
+
* MUST register the extension point and config key under exactly these names.
|
|
74
73
|
*/
|
|
75
74
|
export const EXT_FILE_PROVIDER = "fileProvider";
|
|
76
|
-
//
|
|
77
|
-
// (
|
|
78
|
-
//
|
|
79
|
-
//
|
|
75
|
+
// Qualified config key registered by the file-foundation feature
|
|
76
|
+
// (format `<feature>:config:<key>`). This coupling is intentional: the
|
|
77
|
+
// framework resolver is below the feature and reads the key by string. Renaming
|
|
78
|
+
// the file-foundation feature MUST be accompanied by changing this constant.
|
|
80
79
|
export const FILE_PROVIDER_CONFIG_KEY = "file-foundation:config:provider";
|
|
81
80
|
// Two roles: boot gate (validateBoot requires its presence once file/image
|
|
82
81
|
// fields are in use) AND the ENV source of the config key above, bridged via
|
|
@@ -114,7 +113,7 @@ export const EXT_DERIVATIVE_RENDERER = "derivativeRenderer";
|
|
|
114
113
|
* serves nothing for that entityType, not even a 403 (404, so existence isn't
|
|
115
114
|
* confirmed to an unauthorised caller).
|
|
116
115
|
*
|
|
117
|
-
* Registered/consumed by: `file-derivatives`' public variant route
|
|
116
|
+
* Registered/consumed by: `file-derivatives`' public variant route.
|
|
118
117
|
*/
|
|
119
118
|
export const EXT_DERIVATIVE_PUBLIC_PREDICATE = "derivativePublicPredicate";
|
|
120
119
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// reads the { escapeHatch: { reason } } convention off a
|
|
2
2
|
// `r.useExtension(...)` registration's untyped options bag. Registration-time
|
|
3
3
|
// validation (feature-ui-extensions.ts's useExtension) already rejects an
|
|
4
4
|
// empty reason, but options stays `Record<string, unknown>`, so orchestrators
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
// Hook
|
|
1
|
+
// Hook signature types for EXT_TENANT_DATA (GDPR tenant-scoped destruction).
|
|
2
2
|
//
|
|
3
3
|
// Mirror of engine/extensions/user-data.ts at tenant granularity.
|
|
4
|
-
// tenant-lifecycle orchestrates
|
|
4
|
+
// tenant-lifecycle orchestrates destruction via registry.getExtensionUsages(EXT_TENANT_DATA).
|
|
5
5
|
export function isTenantDataExtensionHooks(o) {
|
|
6
6
|
return typeof o === "object" && o !== null && "destroy" in o && typeof o.destroy === "function";
|
|
7
7
|
}
|
|
@@ -2,15 +2,15 @@ import type { TenantDb } from "../../db/tenant-db.ts";
|
|
|
2
2
|
import type { Registry, TenantId } from "../types/index.ts";
|
|
3
3
|
type UserId = string;
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
* - "delete":
|
|
7
|
-
* - "anonymize":
|
|
8
|
-
* "[Geloescht]" —
|
|
9
|
-
*
|
|
5
|
+
* Strategy for the forget path per entity:
|
|
6
|
+
* - "delete": Physically remove the row (profile, personal notes, sessions).
|
|
7
|
+
* - "anonymize": Set the user reference to null and display fields to
|
|
8
|
+
* "[Geloescht]" — typical for shared data (tasks,
|
|
9
|
+
* comments) so other users do not lose the history.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* The cleanup job applies the retention policy per entity to select the
|
|
12
|
+
* strategy. blockDelete entries ALWAYS use `anonymize` to respect retention
|
|
13
|
+
* obligations.
|
|
14
14
|
*/
|
|
15
15
|
export type UserDataDeleteStrategy = "delete" | "anonymize";
|
|
16
16
|
/**
|
|
@@ -27,7 +27,7 @@ export type UserDataDeleteStrategy = "delete" | "anonymize";
|
|
|
27
27
|
*/
|
|
28
28
|
export type TenantUserModel = "single-user" | "multi-user";
|
|
29
29
|
/**
|
|
30
|
-
*
|
|
30
|
+
* `db` is a tenant-filtered `TenantDb`, bound to `tenantId`
|
|
31
31
|
* (or the per-user sub-tx in the forget path). Unfiltered access needs
|
|
32
32
|
* `escapeHatch: { reason }` on the `r.useExtension(...)` registration,
|
|
33
33
|
* then `ctx.db.unsafeRaw()`.
|
|
@@ -82,15 +82,15 @@ export interface UserDataHookCtx {
|
|
|
82
82
|
readonly userEmailBeforeDelete?: string | null;
|
|
83
83
|
}
|
|
84
84
|
/**
|
|
85
|
-
*
|
|
86
|
-
*
|
|
85
|
+
* Feature/entity snippet included in the export bundle. The export job
|
|
86
|
+
* orchestrates JSON serialization; hooks return plain records.
|
|
87
87
|
*/
|
|
88
88
|
export interface UserDataExportSnippet {
|
|
89
89
|
readonly entity: string;
|
|
90
90
|
readonly rows: ReadonlyArray<Record<string, unknown>>;
|
|
91
91
|
/**
|
|
92
|
-
* Optional
|
|
93
|
-
*
|
|
92
|
+
* Optional signed URLs for file references. user-data-rights puts them
|
|
93
|
+
* separately in the ZIP under `files/`. Other hooks leave this empty.
|
|
94
94
|
*/
|
|
95
95
|
readonly fileRefs?: ReadonlyArray<{
|
|
96
96
|
readonly fileRefId: string;
|
|
@@ -99,22 +99,21 @@ export interface UserDataExportSnippet {
|
|
|
99
99
|
}>;
|
|
100
100
|
}
|
|
101
101
|
/**
|
|
102
|
-
* Export
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
* Side-Effects.
|
|
102
|
+
* Export hook: collects all data belonging to a user for an entity. It is
|
|
103
|
+
* called once per registered entity by the data export job. Idempotent — it
|
|
104
|
+
* can be called multiple times without side effects.
|
|
106
105
|
*
|
|
107
|
-
*
|
|
108
|
-
* `r.useExtension(EXT_USER_DATA, ...)
|
|
106
|
+
* The data-rights runner invokes this by iterating over all
|
|
107
|
+
* `r.useExtension(EXT_USER_DATA, ...)` registrations.
|
|
109
108
|
*/
|
|
110
109
|
export type UserDataExportHook = (ctx: UserDataHookCtx) => Promise<UserDataExportSnippet | null>;
|
|
111
110
|
/**
|
|
112
|
-
* Forget
|
|
113
|
-
*
|
|
114
|
-
*
|
|
111
|
+
* Forget hook: deletes or anonymizes entity rows belonging to a user. The
|
|
112
|
+
* cleanup job supplies the strategy, which may differ by entity because of
|
|
113
|
+
* the retention policy.
|
|
115
114
|
*
|
|
116
|
-
* Idempotent —
|
|
117
|
-
*
|
|
115
|
+
* Idempotent — if the job runs twice during crash recovery, the hook must not
|
|
116
|
+
* crash.
|
|
118
117
|
*
|
|
119
118
|
* Return additive to `void`: a hook can return `{status:"ok"}` or
|
|
120
119
|
* `{status:"incomplete", reason}` to signal a partial success to the
|
|
@@ -7,13 +7,13 @@ export declare function createTextField<R extends true | false = false>(override
|
|
|
7
7
|
};
|
|
8
8
|
/**
|
|
9
9
|
* Long-form text field for source-code, markdown, blog-posts, email-
|
|
10
|
-
* templates — anything that can be megabytes large.
|
|
11
|
-
* from `text`:
|
|
12
|
-
* DB
|
|
10
|
+
* templates — anything that can be megabytes large. Its type-level API
|
|
11
|
+
* differs from `text`: it has no sortable/searchable/filterable/format options.
|
|
12
|
+
* The DB mapping is identical to text (`PG text` is unbounded).
|
|
13
13
|
*
|
|
14
|
-
* Soft-cap default:
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* Soft-cap default: no maxLength (`PG text` has a 1 GB hard limit).
|
|
15
|
+
* Set an explicit `maxLength` to reject an accidental browser paste early
|
|
16
|
+
* (for example, `1_000_000 = 1 MB`).
|
|
17
17
|
*/
|
|
18
18
|
/**
|
|
19
19
|
* Read-time computed field for `EntityDefinition.derivedFields` (NOT `fields`).
|
|
@@ -112,12 +112,12 @@ export declare function createDateField<R extends true | false = false>(override
|
|
|
112
112
|
required: R;
|
|
113
113
|
};
|
|
114
114
|
/**
|
|
115
|
-
* UTC
|
|
116
|
-
* (createdAt, loginAt, actualPickupAt). Temporal.Instant
|
|
115
|
+
* UTC instant for events occurring at a specific point in time
|
|
116
|
+
* (createdAt, loginAt, actualPickupAt). Uses Temporal.Instant internally.
|
|
117
117
|
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
118
|
+
* With `locatedBy: "<name>Tz"`, the field becomes a wall-clock pair for an
|
|
119
|
+
* appointment at a location — prefer `createLocatedTimestampField()` instead,
|
|
120
|
+
* which creates one atomic field rather than a loosely connected pair.
|
|
121
121
|
*/
|
|
122
122
|
export declare function createTimestampField<R extends true | false = false>(overrides?: Partial<Omit<TimestampFieldDef, "type" | "required" | keyof ResolvedPiiFlags>> & PersonalAnnotationsNoFind & {
|
|
123
123
|
required?: R;
|
|
@@ -125,8 +125,9 @@ export declare function createTimestampField<R extends true | false = false>(ove
|
|
|
125
125
|
required: R;
|
|
126
126
|
};
|
|
127
127
|
/**
|
|
128
|
-
* IANA-
|
|
129
|
-
*
|
|
128
|
+
* IANA time-zone name (for example, "Europe/Berlin"). The boot/schema
|
|
129
|
+
* validator checks it using `Intl.supportedValuesOf("timeZone")` during the
|
|
130
|
+
* Zod step.
|
|
130
131
|
*/
|
|
131
132
|
export declare function createTzField<R extends true | false = false>(overrides?: Partial<Omit<TzFieldDef, "type" | "required" | keyof ResolvedPiiFlags>> & PersonalAnnotationsNoFind & {
|
|
132
133
|
required?: R;
|
package/dist/engine/factories.js
CHANGED
|
@@ -24,7 +24,7 @@ function resolvePersonalFlags(personal, reason) {
|
|
|
24
24
|
userOwned: { ownerField: personal.of, ...(whenAbsent !== undefined && { whenAbsent }) },
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
|
-
// Resolves the author-facing `personal`/`find` annotations
|
|
27
|
+
// Resolves the author-facing `personal`/`find` annotations
|
|
28
28
|
// into the internal ResolvedPiiFlags every factory below merges into its
|
|
29
29
|
// return value. `personal`, `find`, `reason` never survive into the field def.
|
|
30
30
|
function expandPersonalAnnotations(overrides) {
|
|
@@ -73,7 +73,7 @@ function missingTextFieldStanceError(factoryName) {
|
|
|
73
73
|
function isNonEmptyString(value) {
|
|
74
74
|
return typeof value === "string" && value.trim().length > 0;
|
|
75
75
|
}
|
|
76
|
-
// Fail-closed stance gate
|
|
76
|
+
// Fail-closed stance gate for the two text-shaped
|
|
77
77
|
// factories — runs before expandPersonalAnnotations so an untyped JS caller
|
|
78
78
|
// (no compiler to stop it) can't slip an unannotated text field past the
|
|
79
79
|
// type layer either. The typed signature above already rejects a
|
|
@@ -109,13 +109,12 @@ function assertTextFieldStance(factoryName, overrides) {
|
|
|
109
109
|
throw missingTextFieldStanceError(factoryName);
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
|
-
//
|
|
113
|
-
// `createTextField({ required: true })` literal `required: true`
|
|
114
|
-
//
|
|
115
|
-
// Mapped-Type
|
|
116
|
-
// `
|
|
117
|
-
//
|
|
118
|
-
// in jeder required-bearing factory unten.
|
|
112
|
+
// Use generic `R extends true | false` instead of `boolean` so
|
|
113
|
+
// `createTextField({ required: true })` preserves the literal `required: true`
|
|
114
|
+
// in the return type. Widening to `boolean` would prevent EntityTable<E>'s
|
|
115
|
+
// Mapped-Type from distinguishing `required: true` from `required: false`,
|
|
116
|
+
// making every column nullable. Default `R = false` matches the runtime
|
|
117
|
+
// default. This pattern is used in every required-bearing factory below.
|
|
119
118
|
export function createTextField(overrides) {
|
|
120
119
|
assertTextFieldStance("createTextField", overrides);
|
|
121
120
|
return {
|
|
@@ -129,13 +128,13 @@ export function createTextField(overrides) {
|
|
|
129
128
|
}
|
|
130
129
|
/**
|
|
131
130
|
* Long-form text field for source-code, markdown, blog-posts, email-
|
|
132
|
-
* templates — anything that can be megabytes large.
|
|
133
|
-
* from `text`:
|
|
134
|
-
* DB
|
|
131
|
+
* templates — anything that can be megabytes large. Its type-level API
|
|
132
|
+
* differs from `text`: it has no sortable/searchable/filterable/format options.
|
|
133
|
+
* The DB mapping is identical to text (`PG text` is unbounded).
|
|
135
134
|
*
|
|
136
|
-
* Soft-cap default:
|
|
137
|
-
*
|
|
138
|
-
*
|
|
135
|
+
* Soft-cap default: no maxLength (`PG text` has a 1 GB hard limit).
|
|
136
|
+
* Set an explicit `maxLength` to reject an accidental browser paste early
|
|
137
|
+
* (for example, `1_000_000 = 1 MB`).
|
|
139
138
|
*/
|
|
140
139
|
/**
|
|
141
140
|
* Read-time computed field for `EntityDefinition.derivedFields` (NOT `fields`).
|
|
@@ -277,10 +276,10 @@ export function createEmbeddedListField(schema, overrides) {
|
|
|
277
276
|
multiple: true,
|
|
278
277
|
};
|
|
279
278
|
}
|
|
280
|
-
// Free-form jsonb
|
|
281
|
-
// `{}`, NOT NULL.
|
|
282
|
-
// `customFields
|
|
283
|
-
// inferred
|
|
279
|
+
// Free-form jsonb column — see the `JsonbFieldDef` documentation. Schema-less,
|
|
280
|
+
// defaults to `{}`, and is NOT NULL. Primarily used by the custom-fields
|
|
281
|
+
// bundle for the host entity's `customFields` column; other valid uses include
|
|
282
|
+
// tenant configuration blobs, AI-inferred metadata, and future tag arrays.
|
|
284
283
|
export function createJsonbField(overrides) {
|
|
285
284
|
return {
|
|
286
285
|
type: "jsonb",
|
|
@@ -295,17 +294,17 @@ export function createDateField(overrides) {
|
|
|
295
294
|
}; // @cast-boundary engine-payload
|
|
296
295
|
}
|
|
297
296
|
/**
|
|
298
|
-
* UTC
|
|
299
|
-
* (createdAt, loginAt, actualPickupAt). Temporal.Instant
|
|
297
|
+
* UTC instant for events occurring at a specific point in time
|
|
298
|
+
* (createdAt, loginAt, actualPickupAt). Uses Temporal.Instant internally.
|
|
300
299
|
*
|
|
301
|
-
*
|
|
302
|
-
*
|
|
303
|
-
*
|
|
300
|
+
* With `locatedBy: "<name>Tz"`, the field becomes a wall-clock pair for an
|
|
301
|
+
* appointment at a location — prefer `createLocatedTimestampField()` instead,
|
|
302
|
+
* which creates one atomic field rather than a loosely connected pair.
|
|
304
303
|
*/
|
|
305
304
|
export function createTimestampField(overrides) {
|
|
306
|
-
//
|
|
307
|
-
//
|
|
308
|
-
//
|
|
305
|
+
// Building the object this way avoids hardcoding `required: false` in the
|
|
306
|
+
// literal, which would make TypeScript widen R to `boolean` instead of
|
|
307
|
+
// inferring the `true`/`false` literal from the overrides argument.
|
|
309
308
|
return {
|
|
310
309
|
...expandPersonalAnnotations(overrides),
|
|
311
310
|
type: "timestamp",
|
|
@@ -313,8 +312,9 @@ export function createTimestampField(overrides) {
|
|
|
313
312
|
};
|
|
314
313
|
}
|
|
315
314
|
/**
|
|
316
|
-
* IANA-
|
|
317
|
-
*
|
|
315
|
+
* IANA time-zone name (for example, "Europe/Berlin"). The boot/schema
|
|
316
|
+
* validator checks it using `Intl.supportedValuesOf("timeZone")` during the
|
|
317
|
+
* Zod step.
|
|
318
318
|
*/
|
|
319
319
|
export function createTzField(overrides) {
|
|
320
320
|
return {
|
|
@@ -372,14 +372,15 @@ export function createFilesField(overrides) {
|
|
|
372
372
|
export function createImagesField(overrides) {
|
|
373
373
|
return { type: "images", ...expandPersonalAnnotations(overrides) };
|
|
374
374
|
}
|
|
375
|
-
// `F`
|
|
376
|
-
//
|
|
377
|
-
// boolean).
|
|
378
|
-
//
|
|
379
|
-
//
|
|
380
|
-
//
|
|
381
|
-
// `const F
|
|
382
|
-
// `type`
|
|
375
|
+
// Leave `F` unconstrained so TypeScript preserves the literal types of
|
|
376
|
+
// individual field definitions (`required: true` remains `true`, not
|
|
377
|
+
// `boolean`). Constraining it to FieldsMap would widen them — see the
|
|
378
|
+
// TypeScript issue concerning constraint inference for structural records.
|
|
379
|
+
// Instead, conformance is validated through the conditional return type: if F
|
|
380
|
+
// is not compatible with FieldsMap, the return type collapses to `never`.
|
|
381
|
+
// `const F` preserves the `type` literal in inline field literals
|
|
382
|
+
// (`{ type: "reference", ... }`) without `as const`; otherwise it widens to
|
|
383
|
+
// string and produces `never`.
|
|
383
384
|
export function createEntity(def) {
|
|
384
385
|
return {
|
|
385
386
|
softDelete: false,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Shared field-type validation for EntityDefinition. Used by both the
|
|
2
2
|
// static extractor (extractEntity, parse-time ParseError) and the runtime
|
|
3
3
|
// PatternChange validator (pattern-change-schema.ts) so the two never drift
|
|
4
|
-
// into reporting different "unknown field type" catalogues
|
|
4
|
+
// into reporting different "unknown field type" catalogues.
|
|
5
5
|
import { FIELD_TYPE_NAMES } from "@cosmicdrift/kumiko-types/fields";
|
|
6
6
|
import { isPlainObject, isRawRefSentinel } from "./extractors/shared.js";
|
|
7
7
|
/**
|
|
@@ -256,7 +256,7 @@ export function parseHandlerCall(call, sourceFile, methodName) {
|
|
|
256
256
|
// (`r.writeHandler(eventCreateHandler)`, `r.queryHandler(someQuery())`)
|
|
257
257
|
// that resolveObjectLiteralArg above couldn't turn into an object literal
|
|
258
258
|
// (imported binding, factory call, ...). Keep it recognised as this kind
|
|
259
|
-
// instead of ParseErroring
|
|
259
|
+
// instead of ParseErroring. Opaque: renderWriteHandler/
|
|
260
260
|
// renderQueryHandler re-emit `source.raw` verbatim when handlerName is
|
|
261
261
|
// undefined.
|
|
262
262
|
if (args.length === 1 && isRawRefSentinel(readDataLiteralNode(first))) {
|
|
@@ -230,7 +230,7 @@ export function extractHook(call, sourceFile) {
|
|
|
230
230
|
...escapeHatchOutcome,
|
|
231
231
|
});
|
|
232
232
|
}
|
|
233
|
-
// guard:dup-ok —
|
|
233
|
+
// guard:dup-ok — intentional parallel to extractTree; different Feature-AST extractors by design
|
|
234
234
|
export function extractAuthClaims(call, sourceFile) {
|
|
235
235
|
const arg = call.getArguments()[0];
|
|
236
236
|
if (!arg) {
|
|
@@ -47,8 +47,7 @@ export declare function readStringOrRaw(node: Node): string | RawRefSentinel | u
|
|
|
47
47
|
* Like readStringLiteralArgs, but an argument that resolves to a raw-ref
|
|
48
48
|
* sentinel is kept as that sentinel instead of failing the whole call. Used
|
|
49
49
|
* where a value stands in for a single name/key and inlining its resolved
|
|
50
|
-
* string would corrupt the render roundtrip (e.g. `r.requires(someFeature.name)`
|
|
51
|
-
* — see #1009).
|
|
50
|
+
* string would corrupt the render roundtrip (e.g. `r.requires(someFeature.name)`).
|
|
52
51
|
*/
|
|
53
52
|
export declare function readStringOrRawArgs(call: CallExpression): readonly (string | RawRefSentinel)[] | undefined;
|
|
54
53
|
export { isPlainObject } from "../../../utils/is-plain-object.ts";
|
|
@@ -67,7 +66,7 @@ export type NameLiteralRef = {
|
|
|
67
66
|
};
|
|
68
67
|
/**
|
|
69
68
|
* Like `readNameLiteral`, but for callers that must preserve an
|
|
70
|
-
* identifier-authored name across a render → parse round-trip
|
|
69
|
+
* identifier-authored name across a render → parse round-trip.
|
|
71
70
|
* `raw` is populated only when the node resolved via an identifier — a
|
|
72
71
|
* string-literal node has nothing worth preserving beyond its value, and
|
|
73
72
|
* setting `raw` for it too would make `JSON.stringify(value)` and
|
|
@@ -147,8 +147,7 @@ export function readStringOrRaw(node) {
|
|
|
147
147
|
* Like readStringLiteralArgs, but an argument that resolves to a raw-ref
|
|
148
148
|
* sentinel is kept as that sentinel instead of failing the whole call. Used
|
|
149
149
|
* where a value stands in for a single name/key and inlining its resolved
|
|
150
|
-
* string would corrupt the render roundtrip (e.g. `r.requires(someFeature.name)`
|
|
151
|
-
* — see #1009).
|
|
150
|
+
* string would corrupt the render roundtrip (e.g. `r.requires(someFeature.name)`).
|
|
152
151
|
*/
|
|
153
152
|
export function readStringOrRawArgs(call) {
|
|
154
153
|
const out = [];
|
|
@@ -229,7 +228,7 @@ function resolveIdentifierToStringLiteral(identifier) {
|
|
|
229
228
|
}
|
|
230
229
|
/**
|
|
231
230
|
* Like `readNameLiteral`, but for callers that must preserve an
|
|
232
|
-
* identifier-authored name across a render → parse round-trip
|
|
231
|
+
* identifier-authored name across a render → parse round-trip.
|
|
233
232
|
* `raw` is populated only when the node resolved via an identifier — a
|
|
234
233
|
* string-literal node has nothing worth preserving beyond its value, and
|
|
235
234
|
* setting `raw` for it too would make `JSON.stringify(value)` and
|