@yahoo/uds-create-config 2.44.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +129 -0
- package/dist/ai-lanes.d.ts +23 -0
- package/dist/ai-lanes.js +34 -0
- package/dist/authoring/define-component.d.ts +85 -0
- package/dist/configs/CanvasConfig.d.ts +3237 -0
- package/dist/configs/CanvasConfig.js +332 -0
- package/dist/configs/build-options.d.ts +10 -0
- package/dist/configs/build-options.js +68 -0
- package/dist/configs/platform.d.ts +15 -0
- package/dist/configs/platform.js +17 -0
- package/dist/configs/react-native-system.d.ts +3026 -0
- package/dist/configs/react-native-system.js +64 -0
- package/dist/configs/system.d.ts +2771 -0
- package/dist/configs/system.js +74 -0
- package/dist/css/properties.generated.d.ts +14 -0
- package/dist/css/properties.generated.js +6260 -0
- package/dist/css/value-type.d.ts +48 -0
- package/dist/css/value-type.js +131 -0
- package/dist/css/values.d.ts +33 -0
- package/dist/css/values.js +116 -0
- package/dist/entities/native/NativeModifier.d.ts +25 -0
- package/dist/entities/native/NativeModifier.js +41 -0
- package/dist/entities/native/NativeSettings.d.ts +44 -0
- package/dist/entities/native/NativeSettings.js +39 -0
- package/dist/entities/native/NativeStyleProperty.d.ts +355 -0
- package/dist/entities/native/NativeStyleProperty.js +28 -0
- package/dist/entities/native/NativeToken.d.ts +31 -0
- package/dist/entities/native/NativeToken.js +49 -0
- package/dist/entities/system/CanvasRole.d.ts +34 -0
- package/dist/entities/system/CanvasRole.js +45 -0
- package/dist/entities/system/Component.d.ts +1287 -0
- package/dist/entities/system/Component.js +1840 -0
- package/dist/entities/system/Composite.d.ts +12 -0
- package/dist/entities/system/Composite.js +26 -0
- package/dist/entities/system/Device.d.ts +11 -0
- package/dist/entities/system/Device.js +18 -0
- package/dist/entities/system/File.d.ts +72 -0
- package/dist/entities/system/File.js +136 -0
- package/dist/entities/system/Font.d.ts +48 -0
- package/dist/entities/system/Font.js +56 -0
- package/dist/entities/system/GlobalStyle.d.ts +26 -0
- package/dist/entities/system/GlobalStyle.js +54 -0
- package/dist/entities/system/Guidance.d.ts +85 -0
- package/dist/entities/system/Guidance.js +59 -0
- package/dist/entities/system/GuidanceStyle.d.ts +14 -0
- package/dist/entities/system/GuidanceStyle.js +8 -0
- package/dist/entities/system/Icon.d.ts +46 -0
- package/dist/entities/system/Icon.js +46 -0
- package/dist/entities/system/LinkedSystem.d.ts +504 -0
- package/dist/entities/system/LinkedSystem.js +814 -0
- package/dist/entities/system/Modifier.d.ts +92 -0
- package/dist/entities/system/Modifier.js +120 -0
- package/dist/entities/system/Motion.d.ts +28 -0
- package/dist/entities/system/Motion.js +48 -0
- package/dist/entities/system/Operation.d.ts +100 -0
- package/dist/entities/system/Operation.js +236 -0
- package/dist/entities/system/Package.d.ts +42 -0
- package/dist/entities/system/Package.js +75 -0
- package/dist/entities/system/Settings.d.ts +94 -0
- package/dist/entities/system/Settings.js +166 -0
- package/dist/entities/system/StyleProperty.d.ts +135 -0
- package/dist/entities/system/StyleProperty.js +438 -0
- package/dist/entities/system/Token.d.ts +67 -0
- package/dist/entities/system/Token.js +129 -0
- package/dist/entities/system/Tool.d.ts +134 -0
- package/dist/entities/system/Tool.js +124 -0
- package/dist/entities/system/color.d.ts +64 -0
- package/dist/entities/system/color.js +123 -0
- package/dist/entities/system/component-module.d.ts +63 -0
- package/dist/entities/system/component-module.js +258 -0
- package/dist/entities/system/copy-plan.d.ts +98 -0
- package/dist/entities/system/copy-plan.js +451 -0
- package/dist/entities/system/defineComponent.d.ts +428 -0
- package/dist/entities/system/defineComponent.js +337 -0
- package/dist/entities/system/element.d.ts +101 -0
- package/dist/entities/system/element.js +171 -0
- package/dist/entities/system/icon-library.d.ts +64 -0
- package/dist/entities/system/icon-library.js +112 -0
- package/dist/entities/system/icon-metadata.d.ts +72 -0
- package/dist/entities/system/icon-metadata.js +111 -0
- package/dist/entities/system/link-declaration.d.ts +27 -0
- package/dist/entities/system/link-declaration.js +64 -0
- package/dist/entities/system/link-plan.d.ts +160 -0
- package/dist/entities/system/link-plan.js +770 -0
- package/dist/entities/system/runtime-modules.d.ts +25 -0
- package/dist/entities/system/runtime-modules.js +38 -0
- package/dist/entities/system/style-bag.d.ts +20 -0
- package/dist/entities/system/style-bag.js +246 -0
- package/dist/entities/system/token-index.d.ts +89 -0
- package/dist/entities/system/token-index.js +112 -0
- package/dist/framework/Config.d.ts +2472 -0
- package/dist/framework/Config.js +5023 -0
- package/dist/framework/Entity.d.ts +127 -0
- package/dist/framework/Entity.js +125 -0
- package/dist/framework/authoring.d.ts +24 -0
- package/dist/framework/authoring.js +7 -0
- package/dist/framework/change-hooks.d.ts +119 -0
- package/dist/framework/change-hooks.js +131 -0
- package/dist/framework/changes.d.ts +88 -0
- package/dist/framework/changes.js +246 -0
- package/dist/framework/class-names.d.ts +260 -0
- package/dist/framework/class-names.js +630 -0
- package/dist/framework/coalesce.d.ts +25 -0
- package/dist/framework/coalesce.js +60 -0
- package/dist/framework/config-op.d.ts +76 -0
- package/dist/framework/config-op.js +43 -0
- package/dist/framework/config-operation-kind.d.ts +14 -0
- package/dist/framework/config-operation-kind.js +14 -0
- package/dist/framework/config-ops.d.ts +34 -0
- package/dist/framework/config-ops.js +187 -0
- package/dist/framework/defineConfig.d.ts +196 -0
- package/dist/framework/defineConfig.js +100 -0
- package/dist/framework/defineDerivedEntity.d.ts +74 -0
- package/dist/framework/defineDerivedEntity.js +83 -0
- package/dist/framework/defineEntity.d.ts +318 -0
- package/dist/framework/defineEntity.js +183 -0
- package/dist/framework/defineSubEntity.d.ts +148 -0
- package/dist/framework/defineSubEntity.js +121 -0
- package/dist/framework/derived-mutations.d.ts +20 -0
- package/dist/framework/derived-mutations.js +38 -0
- package/dist/framework/entity-search.d.ts +29 -0
- package/dist/framework/entity-search.js +117 -0
- package/dist/framework/inline-sources.d.ts +49 -0
- package/dist/framework/inline-sources.js +388 -0
- package/dist/framework/layer-styles.d.ts +25 -0
- package/dist/framework/layer-styles.js +49 -0
- package/dist/framework/memo.d.ts +48 -0
- package/dist/framework/memo.js +84 -0
- package/dist/framework/overlay.d.ts +49 -0
- package/dist/framework/overlay.js +17 -0
- package/dist/framework/plan.d.ts +49 -0
- package/dist/framework/plan.js +73 -0
- package/dist/framework/projections.d.ts +480 -0
- package/dist/framework/projections.js +974 -0
- package/dist/framework/prop-surface.d.ts +132 -0
- package/dist/framework/prop-surface.js +278 -0
- package/dist/framework/ref-graph.d.ts +71 -0
- package/dist/framework/ref-graph.js +158 -0
- package/dist/framework/ref-integrity.d.ts +55 -0
- package/dist/framework/ref-integrity.js +171 -0
- package/dist/framework/registered.d.ts +95 -0
- package/dist/framework/registry-dir.d.ts +42 -0
- package/dist/framework/registry-dir.js +48 -0
- package/dist/framework/registry.d.ts +300 -0
- package/dist/framework/registry.js +104 -0
- package/dist/framework/rejection.d.ts +58 -0
- package/dist/framework/rejection.js +111 -0
- package/dist/framework/rename-inference.d.ts +26 -0
- package/dist/framework/rename-inference.js +50 -0
- package/dist/framework/render-spec.d.ts +296 -0
- package/dist/framework/render-spec.js +809 -0
- package/dist/framework/schema-version.d.ts +140 -0
- package/dist/framework/schema-version.js +214 -0
- package/dist/framework/schemas.d.ts +109 -0
- package/dist/framework/schemas.js +615 -0
- package/dist/framework/session.d.ts +196 -0
- package/dist/framework/session.js +367 -0
- package/dist/framework/signature.d.ts +15 -0
- package/dist/framework/signature.js +83 -0
- package/dist/framework/snapshot.d.ts +115 -0
- package/dist/framework/snapshot.js +277 -0
- package/dist/framework/source-integrity.d.ts +226 -0
- package/dist/framework/source-integrity.js +478 -0
- package/dist/framework/sources.d.ts +211 -0
- package/dist/framework/sources.js +89 -0
- package/dist/framework/utils/compiled-schema.d.ts +23 -0
- package/dist/framework/utils/compiled-schema.js +46 -0
- package/dist/framework/utils/content-key.d.ts +15 -0
- package/dist/framework/utils/content-key.js +33 -0
- package/dist/framework/utils/enumerated.d.ts +13 -0
- package/dist/framework/utils/enumerated.js +19 -0
- package/dist/framework/utils/field-path.d.ts +95 -0
- package/dist/framework/utils/field-path.js +136 -0
- package/dist/framework/utils/field-schema.d.ts +55 -0
- package/dist/framework/utils/field-schema.js +183 -0
- package/dist/framework/utils/group.d.ts +37 -0
- package/dist/framework/utils/group.js +13 -0
- package/dist/framework/utils/package-path.d.ts +37 -0
- package/dist/framework/utils/package-path.js +61 -0
- package/dist/framework/utils/refs.d.ts +194 -0
- package/dist/framework/utils/refs.js +403 -0
- package/dist/framework/validate-spec.d.ts +27 -0
- package/dist/framework/validate-spec.js +45 -0
- package/dist/framework/value-domain.d.ts +26 -0
- package/dist/framework/value-domain.js +202 -0
- package/dist/framework/views-facade.d.ts +15 -0
- package/dist/framework/views-facade.js +19 -0
- package/dist/index.d.ts +90 -42
- package/dist/index.js +86 -37
- package/dist/migrations/2.0.0/raw-css.d.ts +11 -0
- package/dist/migrations/2.0.0/raw-css.js +72 -0
- package/dist/migrations/2.0.0/v1-artifact.d.ts +1559 -0
- package/dist/migrations/2.0.0/v1-artifact.js +1018 -0
- package/dist/migrations/20260908171448_settings_as_kind.d.ts +22 -0
- package/dist/migrations/20260908171448_settings_as_kind.js +89 -0
- package/dist/migrations/20260908194245_visible_state_pointer.d.ts +19 -0
- package/dist/migrations/20260908194245_visible_state_pointer.js +115 -0
- package/dist/migrations/20260909183001_icon_knockout_variants.d.ts +18 -0
- package/dist/migrations/20260909183001_icon_knockout_variants.js +8 -0
- package/dist/migrations/20260910212453_linked_system_link_ops.d.ts +13 -0
- package/dist/migrations/20260910212453_linked_system_link_ops.js +8 -0
- package/dist/migrations/index.d.ts +2 -0
- package/dist/migrations/index.js +2 -0
- package/dist/react-native/style-keys.generated.d.ts +10 -0
- package/dist/react-native/style-keys.generated.js +167 -0
- package/dist/renderer/RendererErrorBoundary.d.ts +32 -5
- package/dist/renderer/RendererErrorBoundary.js +59 -10
- package/dist/renderer/UdsRenderer.d.ts +11 -10
- package/dist/renderer/UdsRenderer.js +1 -1
- package/dist/renderer/assetEntries.d.ts +37 -0
- package/dist/renderer/assetEntries.js +39 -0
- package/dist/renderer/assetRenderable.d.ts +14 -6
- package/dist/renderer/assetRenderable.js +8 -2
- package/dist/renderer/componentEntry.d.ts +58 -0
- package/dist/renderer/componentEntry.js +71 -0
- package/dist/renderer/icon-library.d.ts +20 -0
- package/dist/renderer/index.d.ts +7 -7
- package/dist/renderer/index.js +5 -5
- package/dist/renderer/primitives/SlotRenderer.d.ts +1 -1
- package/dist/renderer/primitives/SlotRenderer.js +1 -1
- package/dist/renderer/runtimeComponent.d.ts +33 -0
- package/dist/renderer/runtimeComponent.js +113 -0
- package/dist/renderer/spec-content.d.ts +43 -0
- package/dist/renderer/spec-content.js +95 -0
- package/dist/renderer/wrapRegistry.d.ts +22 -37
- package/dist/renderer/wrapRegistry.js +10 -20
- package/dist/renderer/wrappers/event-bridge.js +6 -5
- package/dist/renderer/wrappers/hex-normalize.js +6 -5
- package/dist/renderer/wrappers/html-aliases.d.ts +7 -2
- package/dist/renderer/wrappers/html-aliases.js +36 -19
- package/dist/renderer/wrappers/inline-styles.js +7 -6
- package/dist/spec/asset-jsx.d.ts +18 -5
- package/dist/spec/asset-jsx.js +27 -16
- package/dist/spec/collapse-text-labels.d.ts +5 -15
- package/dist/spec/collapse-text-labels.js +26 -19
- package/dist/spec/empty-node-slots.d.ts +56 -34
- package/dist/spec/empty-node-slots.js +87 -47
- package/dist/spec/index.d.ts +21 -10
- package/dist/spec/index.js +21 -10
- package/dist/spec/jsxToSpec.d.ts +14 -9
- package/dist/spec/jsxToSpec.js +20 -3
- package/dist/spec/preview-elements.d.ts +63 -0
- package/dist/spec/preview-elements.js +89 -0
- package/dist/spec/rewrite-refs.d.ts +58 -0
- package/dist/spec/rewrite-refs.js +250 -0
- package/dist/spec/specToJsx.js +18 -29
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +39 -52
- package/dist/AssetGroup.d.ts +0 -77
- package/dist/AssetGroup.js +0 -125
- package/dist/Component.d.ts +0 -333
- package/dist/Component.js +0 -1061
- package/dist/ComponentGroup.d.ts +0 -22
- package/dist/ComponentGroup.js +0 -51
- package/dist/CompositeStyle.d.ts +0 -30
- package/dist/CompositeStyle.js +0 -59
- package/dist/Config.d.ts +0 -528
- package/dist/Config.js +0 -1712
- package/dist/Mode.d.ts +0 -41
- package/dist/Mode.js +0 -81
- package/dist/Modifier.d.ts +0 -51
- package/dist/Modifier.js +0 -97
- package/dist/MotionDef.d.ts +0 -81
- package/dist/MotionDef.js +0 -212
- package/dist/Props.d.ts +0 -332
- package/dist/Props.js +0 -35
- package/dist/Provider.d.ts +0 -20
- package/dist/Provider.js +0 -14
- package/dist/StyleProp.d.ts +0 -145
- package/dist/StyleProp.js +0 -239
- package/dist/Token.d.ts +0 -76
- package/dist/Token.js +0 -133
- package/dist/TokenGroup.d.ts +0 -33
- package/dist/TokenGroup.js +0 -69
- package/dist/asset-kind.d.ts +0 -55
- package/dist/asset-kind.js +0 -29
- package/dist/asset-value.d.ts +0 -23
- package/dist/asset-value.js +0 -40
- package/dist/brands.d.ts +0 -30
- package/dist/brands.js +0 -20
- package/dist/captureCallerPath.d.ts +0 -48
- package/dist/captureCallerPath.js +0 -95
- package/dist/colorExpressions.d.ts +0 -131
- package/dist/colorExpressions.js +0 -148
- package/dist/component-referrers.d.ts +0 -30
- package/dist/component-referrers.js +0 -40
- package/dist/config-diagnostics.d.ts +0 -21
- package/dist/config-diagnostics.js +0 -12
- package/dist/defineAssetGroup.d.ts +0 -200
- package/dist/defineAssetGroup.js +0 -323
- package/dist/defineProvider.d.ts +0 -29
- package/dist/defineProvider.js +0 -60
- package/dist/element-marker.d.ts +0 -63
- package/dist/element-marker.js +0 -113
- package/dist/entity-utils.d.ts +0 -56
- package/dist/entity-utils.js +0 -105
- package/dist/extension.d.ts +0 -55
- package/dist/extension.js +0 -214
- package/dist/factories.d.ts +0 -863
- package/dist/factories.js +0 -475
- package/dist/font-face.d.ts +0 -25
- package/dist/font-face.js +0 -72
- package/dist/foreign-component-name.d.ts +0 -21
- package/dist/foreign-component-name.js +0 -42
- package/dist/interpolate.d.ts +0 -20
- package/dist/interpolate.js +0 -10
- package/dist/jsx/__fixtures__/cross-component-preview.d.ts +0 -3
- package/dist/jsx/__fixtures__/cross-component-preview.js +0 -15
- package/dist/jsx/jsx-dev-runtime.d.ts +0 -15
- package/dist/jsx/jsx-dev-runtime.js +0 -11
- package/dist/jsx/jsx-runtime.d.ts +0 -48
- package/dist/jsx/jsx-runtime.js +0 -305
- package/dist/linked-system-pins.d.ts +0 -30
- package/dist/linked-system-pins.js +0 -45
- package/dist/linkedNodePrefixes.d.ts +0 -73
- package/dist/linkedNodePrefixes.js +0 -99
- package/dist/markers.d.ts +0 -235
- package/dist/markers.js +0 -70
- package/dist/motion-constants.d.ts +0 -37
- package/dist/motion-constants.js +0 -61
- package/dist/native/NativeConfig.d.ts +0 -56
- package/dist/native/NativeConfig.js +0 -162
- package/dist/native/assets.d.ts +0 -20
- package/dist/native/assets.js +0 -17
- package/dist/native/components.d.ts +0 -139
- package/dist/native/components.js +0 -67
- package/dist/native/index.d.ts +0 -18
- package/dist/native/index.js +0 -17
- package/dist/native/modes.d.ts +0 -10
- package/dist/native/modes.js +0 -11
- package/dist/native/types.d.ts +0 -95
- package/dist/native/types.js +0 -0
- package/dist/native/validation.d.ts +0 -8
- package/dist/native/validation.js +0 -885
- package/dist/native/values.d.ts +0 -7
- package/dist/native/values.js +0 -15
- package/dist/native.d.ts +0 -12
- package/dist/native.js +0 -10
- package/dist/refs.d.ts +0 -204
- package/dist/refs.js +0 -129
- package/dist/registry-aliases.d.ts +0 -33
- package/dist/registry-aliases.js +0 -35
- package/dist/registry-dir.d.ts +0 -22
- package/dist/registry-dir.js +0 -10
- package/dist/renderer/makeRegistry.d.ts +0 -34
- package/dist/renderer/makeRegistry.js +0 -52
- package/dist/renderer/makeUdsRenderer.d.ts +0 -13
- package/dist/renderer/makeUdsRenderer.js +0 -51
- package/dist/renderer/wrappers/component-slots.d.ts +0 -41
- package/dist/renderer/wrappers/component-slots.js +0 -66
- package/dist/renderer/wrappers/slot-resolution.d.ts +0 -25
- package/dist/renderer/wrappers/slot-resolution.js +0 -68
- package/dist/renderer/wrappers/void-elements.d.ts +0 -37
- package/dist/renderer/wrappers/void-elements.js +0 -40
- package/dist/spec/layer-props.d.ts +0 -52
- package/dist/spec/layer-props.js +0 -149
- package/dist/spec/preview-controls.d.ts +0 -44
- package/dist/spec/preview-controls.js +0 -139
- package/dist/spec/slot-refs.d.ts +0 -39
- package/dist/spec/slot-refs.js +0 -56
- package/dist/token-override-rows.d.ts +0 -68
- package/dist/token-override-rows.js +0 -233
- package/dist/tokenValueType.d.ts +0 -34
- package/dist/tokenValueType.js +0 -138
- package/dist/types/css-properties.d.ts +0 -233
- package/dist/types/css-properties.js +0 -14
- package/dist/types/css-property-keywords.d.ts +0 -156
- package/dist/types/css-property-keywords.js +0 -616
- package/dist/types/css-values.d.ts +0 -63
- package/dist/types/css-values.js +0 -16
- package/dist/types.d.ts +0 -1138
- package/dist/types.js +0 -12
- package/dist/units.d.ts +0 -14
- package/dist/units.js +0 -16
- package/dist/utils/index.d.ts +0 -4
- package/dist/utils/index.js +0 -4
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { ConfigFormatError } from "./rejection.js";
|
|
2
|
+
import { Patch, SerializedConfig } from "./Config.js";
|
|
3
|
+
|
|
4
|
+
//#region src/framework/schema-version.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* The schema version this build of the package writes and reads natively — the newest registered
|
|
7
|
+
* migration's version, restated as a constant so writers need no registry at hand.
|
|
8
|
+
*
|
|
9
|
+
* 1 is the baseline: the entire pre-versioning corpus, before any migration exists. The first
|
|
10
|
+
* migration replaces this with its own mint timestamp, and every bump after that does the same.
|
|
11
|
+
*
|
|
12
|
+
* Two tests in `schema-version.test.ts` guard it: the hash tripwire (any schema edit fails until
|
|
13
|
+
* this bumps and a migration registers), and the max-registered assertion — which is also what
|
|
14
|
+
* catches an OUT-OF-DATE PR. A branch that minted its migration before a newer one landed on main
|
|
15
|
+
* sets this constant to its own older timestamp; the merge ref then carries a registered migration
|
|
16
|
+
* newer than the constant, and the assertion fails until the author re-mints.
|
|
17
|
+
*/
|
|
18
|
+
declare const CURRENT_SCHEMA_VERSION = 20260910212453;
|
|
19
|
+
/** What the walkers need to see of an envelope — loose on purpose, so a typed `SerializedConfig`
|
|
20
|
+
* and a raw old-shape record both flow in without casts. */
|
|
21
|
+
interface VersionStamped {
|
|
22
|
+
readonly version?: unknown;
|
|
23
|
+
readonly sources?: unknown;
|
|
24
|
+
}
|
|
25
|
+
/** A wire-form envelope as a migration sees it — raw, because its shape is some PAST version's, and
|
|
26
|
+
* only the terminal `hydrateFrom` parse speaks the current one. */
|
|
27
|
+
type RawWireConfig = Record<string, unknown>;
|
|
28
|
+
/** What the walker hands back: current-shaped, so typed callers read it as the wire form, and raw
|
|
29
|
+
* enough that a test or migration can reach any field. */
|
|
30
|
+
type UpgradedWire = SerializedConfig & RawWireConfig;
|
|
31
|
+
/** A zod-like validator — what a frozen historical schema needs to expose. Structural rather than a
|
|
32
|
+
* `z.ZodType` so the frozen copies stay decoupled from the live zod major. */
|
|
33
|
+
interface FrozenSchema {
|
|
34
|
+
safeParse(data: unknown): {
|
|
35
|
+
success: boolean;
|
|
36
|
+
error?: {
|
|
37
|
+
message: string;
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* One migration: everything below `version` comes up to `version`'s shape through `up`.
|
|
43
|
+
*
|
|
44
|
+
* Filed as `migrations/{version}_{slug}.ts` — mint the version with `date +%Y%m%d%H%M%S`, exactly
|
|
45
|
+
* like a `supabase/migrations` file. There is no `from`: the chain is the registered versions in
|
|
46
|
+
* ascending order, and data stamped V walks every migration newer than V.
|
|
47
|
+
*
|
|
48
|
+
* `up` transforms the envelope's OWN fields and must not descend into `sources` — the walker owns
|
|
49
|
+
* that recursion, upgrading each recorded closure by its own stamp before the envelope's chain runs.
|
|
50
|
+
*
|
|
51
|
+
* Frozen schemas are declared only when `up` actually transforms (see the two-tier rule in the
|
|
52
|
+
* migrations folder): an identity migration has nothing to validate, and a transforming one
|
|
53
|
+
* validates both sides so a transform that mangles fails HERE, named, rather than downstream as a
|
|
54
|
+
* hydrate refusal.
|
|
55
|
+
*/
|
|
56
|
+
interface SchemaMigration {
|
|
57
|
+
/** Mint timestamp, `YYYYMMDDHHMMSS` as an integer. */
|
|
58
|
+
readonly version: number;
|
|
59
|
+
/** Bring an envelope from the PREVIOUS registered version's shape to this one's. Identity for an
|
|
60
|
+
* additive bump. */
|
|
61
|
+
up(json: RawWireConfig): RawWireConfig;
|
|
62
|
+
/** Upgrade one stored patch. Absent = patches unaffected (identity). `null` = the patch has no
|
|
63
|
+
* meaning under this version and is dropped from replay. */
|
|
64
|
+
upPatch?(patch: Patch): Patch | null;
|
|
65
|
+
/** Frozen copy of the shape BEFORE this migration — input validation for a transforming one. */
|
|
66
|
+
readonly fromSchema?: FrozenSchema;
|
|
67
|
+
/** Frozen copy of the shape this migration produces — output validation. */
|
|
68
|
+
readonly toSchema?: FrozenSchema;
|
|
69
|
+
}
|
|
70
|
+
/** Data from a FUTURE schema — written by a newer package/deploy than the one reading it. The remedy
|
|
71
|
+
* is always upgrading the reader; message says which side is behind. A `ConfigFormatError`, so the
|
|
72
|
+
* surfaces that report an unreadable artifact by name report this one too. */
|
|
73
|
+
declare class SchemaVersionTooNew extends ConfigFormatError {
|
|
74
|
+
readonly found: number;
|
|
75
|
+
readonly supported: number;
|
|
76
|
+
constructor(found: number, supported?: number);
|
|
77
|
+
}
|
|
78
|
+
/** Register migrations. Refuses a duplicate version or a non-timestamp one — the whole point of the
|
|
79
|
+
* mint convention is that two branches cannot claim the same slot. The single exception is the
|
|
80
|
+
* reserved {@link CUTOVER_VERSION} baseline. */
|
|
81
|
+
declare function registerSchemaMigrations(...migrations: SchemaMigration[]): void;
|
|
82
|
+
/**
|
|
83
|
+
* The version a wire form claims. Absent means 1 — the corpus written before versioning existed is
|
|
84
|
+
* retroactively version 1, and nothing needs backfilling for that to be true. The legacy counter
|
|
85
|
+
* `2` reads as the mint that carries the same shape.
|
|
86
|
+
*/
|
|
87
|
+
declare function schemaVersionOf(json: VersionStamped): number;
|
|
88
|
+
/**
|
|
89
|
+
* What the WALKER treats a wire form as — {@link schemaVersionOf}, plus pre-cutover detection.
|
|
90
|
+
*
|
|
91
|
+
* An unstamped envelope that is not v2-shaped but carries v1 markers is version 0: the flat bag a
|
|
92
|
+
* pre-config-v2 build wrote. Nothing ever writes a 0 stamp, so the cutover migration runs for
|
|
93
|
+
* exactly this corpus and nothing else. An unstamped shape matching NEITHER stays 1 — the hydrate
|
|
94
|
+
* guard refuses it by name, rather than the cutover reader best-efforting garbage into an empty
|
|
95
|
+
* config (the silent failure the guard exists to prevent).
|
|
96
|
+
*/
|
|
97
|
+
declare function detectedWireVersion(json: VersionStamped): number;
|
|
98
|
+
interface WalkOptions {
|
|
99
|
+
/** Test seam — the walkers read the registered chain when absent. */
|
|
100
|
+
readonly migrations?: ReadonlyMap<number, SchemaMigration>;
|
|
101
|
+
/** Test seam for exercising the walk without touching the real constant. */
|
|
102
|
+
readonly target?: number;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* One envelope brought up to the current version — the read-time half of the whole design.
|
|
106
|
+
*
|
|
107
|
+
* Recorded sources upgrade FIRST, each by its own stamp (a pinned closure was serialized at ITS
|
|
108
|
+
* write time, not the envelope's), then the envelope walks every migration newer than its own
|
|
109
|
+
* stamp, oldest first. A migration's `up` therefore never sees or touches `sources`.
|
|
110
|
+
* Already-current input passes through untouched — same reference, so hot paths pay nothing.
|
|
111
|
+
*/
|
|
112
|
+
declare function upgradeSerializedConfig(json: VersionStamped, options?: WalkOptions): UpgradedWire;
|
|
113
|
+
/**
|
|
114
|
+
* One stored patch brought up from the version it was written at. `null` means the patch has no
|
|
115
|
+
* meaning under the current schema and replay skips it — reported by the caller, not swallowed here.
|
|
116
|
+
*/
|
|
117
|
+
declare function upgradePatch(patch: Patch, writtenAt: number, options?: WalkOptions): Patch | null;
|
|
118
|
+
/** What {@link upgradeDraftEntries} did with a shared draft — the entries a session can replay,
|
|
119
|
+
* plus what it could not: `held` (stamped newer than this build; valid for newer readers) and
|
|
120
|
+
* `retired` (a migration answered `null`; the patch has no meaning under the current schema). */
|
|
121
|
+
interface UpgradedDraft<E> {
|
|
122
|
+
readonly entries: E[];
|
|
123
|
+
readonly held: E[];
|
|
124
|
+
readonly retired: E[];
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* A shared draft's entries, each brought up from the version it was written at — the replay-side
|
|
128
|
+
* counterpart of {@link upgradeSerializedConfig}, over the patch log instead of the envelope.
|
|
129
|
+
*
|
|
130
|
+
* Current entries pass through by reference (the hot path after any bump settles). An upgraded
|
|
131
|
+
* entry is re-stamped at the target: the transform has run, and replaying it again through the same
|
|
132
|
+
* chain — the double application `upPatch` does not promise to survive — is exactly what a stale
|
|
133
|
+
* stamp would cause.
|
|
134
|
+
*/
|
|
135
|
+
declare function upgradeDraftEntries<E extends {
|
|
136
|
+
readonly patch: Patch;
|
|
137
|
+
readonly schemaVersion?: number;
|
|
138
|
+
}>(draft: readonly E[], options?: WalkOptions): UpgradedDraft<E>;
|
|
139
|
+
//#endregion
|
|
140
|
+
export { CURRENT_SCHEMA_VERSION, SchemaMigration, SchemaVersionTooNew, UpgradedDraft, type WalkOptions, detectedWireVersion, registerSchemaMigrations, schemaVersionOf, upgradeDraftEntries, upgradePatch, upgradeSerializedConfig };
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { ConfigFormatError } from "./rejection.js";
|
|
2
|
+
//#region src/framework/schema-version.ts
|
|
3
|
+
/**
|
|
4
|
+
* The schema version this build of the package writes and reads natively — the newest registered
|
|
5
|
+
* migration's version, restated as a constant so writers need no registry at hand.
|
|
6
|
+
*
|
|
7
|
+
* 1 is the baseline: the entire pre-versioning corpus, before any migration exists. The first
|
|
8
|
+
* migration replaces this with its own mint timestamp, and every bump after that does the same.
|
|
9
|
+
*
|
|
10
|
+
* Two tests in `schema-version.test.ts` guard it: the hash tripwire (any schema edit fails until
|
|
11
|
+
* this bumps and a migration registers), and the max-registered assertion — which is also what
|
|
12
|
+
* catches an OUT-OF-DATE PR. A branch that minted its migration before a newer one landed on main
|
|
13
|
+
* sets this constant to its own older timestamp; the merge ref then carries a registered migration
|
|
14
|
+
* newer than the constant, and the assertion fails until the author re-mints.
|
|
15
|
+
*/
|
|
16
|
+
const CURRENT_SCHEMA_VERSION = 20260910212453;
|
|
17
|
+
/** The mint that moved `options` into the `settings` kind — restated here, rather than imported
|
|
18
|
+
* from the migration that owns it, because that migration imports this module. */
|
|
19
|
+
const SETTINGS_AS_KIND_VERSION = 20260908171448;
|
|
20
|
+
/** Data from a FUTURE schema — written by a newer package/deploy than the one reading it. The remedy
|
|
21
|
+
* is always upgrading the reader; message says which side is behind. A `ConfigFormatError`, so the
|
|
22
|
+
* surfaces that report an unreadable artifact by name report this one too. */
|
|
23
|
+
var SchemaVersionTooNew = class extends ConfigFormatError {
|
|
24
|
+
found;
|
|
25
|
+
supported;
|
|
26
|
+
constructor(found, supported = CURRENT_SCHEMA_VERSION) {
|
|
27
|
+
super(`This config was written at schema version ${found}, but this build understands up to ${supported}. Upgrade to read it: \`npm install @yahoo/uds-create-cli@latest\` in a repo, or reload Studio.`);
|
|
28
|
+
this.name = "SchemaVersionTooNew";
|
|
29
|
+
this.found = found;
|
|
30
|
+
this.supported = supported;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
/** A plausible mint timestamp — wide bounds, because the point is catching a counter (1, 2, 3…)
|
|
34
|
+
* or a unix-epoch value slipped in where a `YYYYMMDDHHMMSS` belongs. */
|
|
35
|
+
function isMintTimestamp(version) {
|
|
36
|
+
return Number.isInteger(version) && version >= 20240101e6 && version <= 99991231235959;
|
|
37
|
+
}
|
|
38
|
+
/** The registered migrations, keyed by version. Module-local; migration modules add themselves via
|
|
39
|
+
* {@link registerSchemaMigrations}. Empty while CURRENT_SCHEMA_VERSION is the baseline 1. */
|
|
40
|
+
const REGISTERED = /* @__PURE__ */ new Map();
|
|
41
|
+
/** Register migrations. Refuses a duplicate version or a non-timestamp one — the whole point of the
|
|
42
|
+
* mint convention is that two branches cannot claim the same slot. The single exception is the
|
|
43
|
+
* reserved {@link CUTOVER_VERSION} baseline. */
|
|
44
|
+
function registerSchemaMigrations(...migrations) {
|
|
45
|
+
for (const migration of migrations) {
|
|
46
|
+
if (migration.version !== 1 && !isMintTimestamp(migration.version)) throw new Error(`Schema migration version ${migration.version} is not a mint timestamp — mint one with \`date +%Y%m%d%H%M%S\`, like a supabase migration.`);
|
|
47
|
+
if (REGISTERED.has(migration.version)) throw new Error(`A schema migration at version ${migration.version} is already registered.`);
|
|
48
|
+
if (migration.version > 20260910212453) throw new Error(`Schema migration ${migration.version} is newer than CURRENT_SCHEMA_VERSION (${CURRENT_SCHEMA_VERSION}) — a stale branch merged, or the mint forgot to bump the constant. Re-mint: set CURRENT_SCHEMA_VERSION to the newest migration version.`);
|
|
49
|
+
REGISTERED.set(migration.version, migration);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** The registered migrations — exposed for the guard tests, not for callers. */
|
|
53
|
+
function registeredSchemaMigrations() {
|
|
54
|
+
return REGISTERED;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The version a wire form claims. Absent means 1 — the corpus written before versioning existed is
|
|
58
|
+
* retroactively version 1, and nothing needs backfilling for that to be true. The legacy counter
|
|
59
|
+
* `2` reads as the mint that carries the same shape.
|
|
60
|
+
*/
|
|
61
|
+
function schemaVersionOf(json) {
|
|
62
|
+
const version = json.version;
|
|
63
|
+
if (version === void 0) return 1;
|
|
64
|
+
if (version === 2) return SETTINGS_AS_KIND_VERSION;
|
|
65
|
+
if (typeof version === "number" && Number.isInteger(version) && version >= 1) return version;
|
|
66
|
+
throw new Error(`Config carries a malformed version (${JSON.stringify(version)}) — expected a positive integer.`);
|
|
67
|
+
}
|
|
68
|
+
/** The field names only a pre-cutover artifact spells — the flat bag `uds build` wrote before
|
|
69
|
+
* config-v2. Enough of them that no v2 envelope or foreign JSON matches by accident. */
|
|
70
|
+
const V1_MARKERS = [
|
|
71
|
+
"tokenGroups",
|
|
72
|
+
"styleProps",
|
|
73
|
+
"compositeStyles",
|
|
74
|
+
"componentGroups",
|
|
75
|
+
"assetGroups"
|
|
76
|
+
];
|
|
77
|
+
/**
|
|
78
|
+
* What the WALKER treats a wire form as — {@link schemaVersionOf}, plus pre-cutover detection.
|
|
79
|
+
*
|
|
80
|
+
* An unstamped envelope that is not v2-shaped but carries v1 markers is version 0: the flat bag a
|
|
81
|
+
* pre-config-v2 build wrote. Nothing ever writes a 0 stamp, so the cutover migration runs for
|
|
82
|
+
* exactly this corpus and nothing else. An unstamped shape matching NEITHER stays 1 — the hydrate
|
|
83
|
+
* guard refuses it by name, rather than the cutover reader best-efforting garbage into an empty
|
|
84
|
+
* config (the silent failure the guard exists to prevent).
|
|
85
|
+
*/
|
|
86
|
+
function detectedWireVersion(json) {
|
|
87
|
+
if (json.version !== void 0) return schemaVersionOf(json);
|
|
88
|
+
const raw = json;
|
|
89
|
+
if (Array.isArray(raw.ownedKinds) && typeof raw.items === "object" && raw.items !== null) return 1;
|
|
90
|
+
return V1_MARKERS.some((marker) => marker in raw) ? 0 : 1;
|
|
91
|
+
}
|
|
92
|
+
/** The migrations data at `version` still has to walk, oldest first. */
|
|
93
|
+
function pendingFor(version, target, options) {
|
|
94
|
+
return [...(options?.migrations ?? REGISTERED).values()].filter((m) => m.version > version && m.version <= target).sort((a, b) => a.version - b.version);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* One envelope brought up to the current version — the read-time half of the whole design.
|
|
98
|
+
*
|
|
99
|
+
* Recorded sources upgrade FIRST, each by its own stamp (a pinned closure was serialized at ITS
|
|
100
|
+
* write time, not the envelope's), then the envelope walks every migration newer than its own
|
|
101
|
+
* stamp, oldest first. A migration's `up` therefore never sees or touches `sources`.
|
|
102
|
+
* Already-current input passes through untouched — same reference, so hot paths pay nothing.
|
|
103
|
+
*/
|
|
104
|
+
function upgradeSerializedConfig(json, options) {
|
|
105
|
+
const target = options?.target ?? 20260910212453;
|
|
106
|
+
const version = detectedWireVersion(json);
|
|
107
|
+
if (version > target) throw new SchemaVersionTooNew(version, target);
|
|
108
|
+
const raw = json;
|
|
109
|
+
const sources = upgradedSources(raw, options);
|
|
110
|
+
let current = sources === void 0 ? raw : {
|
|
111
|
+
...raw,
|
|
112
|
+
sources
|
|
113
|
+
};
|
|
114
|
+
for (const migration of pendingFor(version, target, options)) current = applyOne(migration, current);
|
|
115
|
+
if (version === target && sources === void 0) return json;
|
|
116
|
+
return {
|
|
117
|
+
...current,
|
|
118
|
+
version: target
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function applyOne(migration, json) {
|
|
122
|
+
refuseInvalid(migration.fromSchema, json, migration, "input");
|
|
123
|
+
const out = migration.up(json);
|
|
124
|
+
refuseInvalid(migration.toSchema, out, migration, "output");
|
|
125
|
+
return out;
|
|
126
|
+
}
|
|
127
|
+
function refuseInvalid(schema, data, migration, side) {
|
|
128
|
+
if (!schema) return;
|
|
129
|
+
const result = schema.safeParse(data);
|
|
130
|
+
if (!result.success) throw new Error(`Schema migration ${migration.version} refused its ${side}: ${result.error?.message ?? "validation failed"}`);
|
|
131
|
+
}
|
|
132
|
+
/** Upgraded recorded-source closures, or undefined when nothing needed touching (so the caller can
|
|
133
|
+
* keep the original reference). Each closure is a full wire form with its own stamp. */
|
|
134
|
+
function upgradedSources(json, options) {
|
|
135
|
+
const sources = json.sources;
|
|
136
|
+
if (sources === void 0 || sources === null) return void 0;
|
|
137
|
+
if (typeof sources !== "object") return void 0;
|
|
138
|
+
let changed = false;
|
|
139
|
+
const out = {};
|
|
140
|
+
for (const [slug, recorded] of Object.entries(sources)) {
|
|
141
|
+
const closure = recorded?.config;
|
|
142
|
+
if (closure === void 0 || typeof closure !== "object") {
|
|
143
|
+
out[slug] = recorded;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
const upgraded = upgradeSerializedConfig(closure, options);
|
|
147
|
+
if (upgraded === closure) out[slug] = recorded;
|
|
148
|
+
else {
|
|
149
|
+
changed = true;
|
|
150
|
+
out[slug] = {
|
|
151
|
+
...recorded,
|
|
152
|
+
config: upgraded
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return changed ? out : void 0;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* One stored patch brought up from the version it was written at. `null` means the patch has no
|
|
160
|
+
* meaning under the current schema and replay skips it — reported by the caller, not swallowed here.
|
|
161
|
+
*/
|
|
162
|
+
function upgradePatch(patch, writtenAt, options) {
|
|
163
|
+
const target = options?.target ?? 20260910212453;
|
|
164
|
+
if (writtenAt > target) throw new SchemaVersionTooNew(writtenAt, target);
|
|
165
|
+
let current = patch;
|
|
166
|
+
for (const migration of pendingFor(writtenAt, target, options)) {
|
|
167
|
+
if (current === null) break;
|
|
168
|
+
current = migration.upPatch ? migration.upPatch(current) : current;
|
|
169
|
+
}
|
|
170
|
+
return current;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* A shared draft's entries, each brought up from the version it was written at — the replay-side
|
|
174
|
+
* counterpart of {@link upgradeSerializedConfig}, over the patch log instead of the envelope.
|
|
175
|
+
*
|
|
176
|
+
* Current entries pass through by reference (the hot path after any bump settles). An upgraded
|
|
177
|
+
* entry is re-stamped at the target: the transform has run, and replaying it again through the same
|
|
178
|
+
* chain — the double application `upPatch` does not promise to survive — is exactly what a stale
|
|
179
|
+
* stamp would cause.
|
|
180
|
+
*/
|
|
181
|
+
function upgradeDraftEntries(draft, options) {
|
|
182
|
+
const target = options?.target ?? 20260910212453;
|
|
183
|
+
const entries = [];
|
|
184
|
+
const held = [];
|
|
185
|
+
const retired = [];
|
|
186
|
+
for (const entry of draft) {
|
|
187
|
+
const writtenAt = entry.schemaVersion ?? 1;
|
|
188
|
+
if (writtenAt > target) {
|
|
189
|
+
held.push(entry);
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
if (writtenAt === target) {
|
|
193
|
+
entries.push(entry);
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
const upgraded = upgradePatch(entry.patch, writtenAt, options);
|
|
197
|
+
if (upgraded === null) {
|
|
198
|
+
retired.push(entry);
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
entries.push({
|
|
202
|
+
...entry,
|
|
203
|
+
patch: upgraded,
|
|
204
|
+
schemaVersion: target
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
entries,
|
|
209
|
+
held,
|
|
210
|
+
retired
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
//#endregion
|
|
214
|
+
export { CURRENT_SCHEMA_VERSION, SETTINGS_AS_KIND_VERSION, SchemaVersionTooNew, detectedWireVersion, registerSchemaMigrations, registeredSchemaMigrations, schemaVersionOf, upgradeDraftEntries, upgradePatch, upgradeSerializedConfig };
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { FieldsSchema } from "./utils/field-schema.js";
|
|
2
|
+
import { Config } from "./Config.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
//#region src/framework/schemas.d.ts
|
|
6
|
+
/** A tool/op handler — runs the op against a config. Default CRUD/read handlers are wired later
|
|
7
|
+
* (the Operation entity's `execute`); a custom op declares its own here. */
|
|
8
|
+
type OpHandler = (input: Record<string, unknown>, config: Config) => unknown;
|
|
9
|
+
/** What a schema is validated against, when the schema itself depends on more than the value: the
|
|
10
|
+
* `config` registry (to resolve a ref to another entity) and the `parent` item being edited (to see
|
|
11
|
+
* its sibling fields). Absent members are normal — a factory is also called with no parent when a
|
|
12
|
+
* concrete schema is needed for tool derivation. */
|
|
13
|
+
interface FieldsCtx {
|
|
14
|
+
readonly config?: Config;
|
|
15
|
+
readonly parent?: unknown;
|
|
16
|
+
/** The whole body being written, for a field whose schema depends on its siblings (a style
|
|
17
|
+
* property's values are judged against its properties). Present where a writer has the body in
|
|
18
|
+
* hand (`run`, `validateData`); absent for hydration, `register` and tool derivation, which see
|
|
19
|
+
* the storage shape. */
|
|
20
|
+
readonly body?: unknown;
|
|
21
|
+
/** The body arrived through a linked system's pin, or through a `replace` (the write that carries a
|
|
22
|
+
* body across the borrow boundary), rather than being authored here. It was authored and validated
|
|
23
|
+
* where it lives and is already what the source emits, so a check that is authoring guidance for
|
|
24
|
+
* this config's own writes does not apply; a check on the value domain still does, since that is
|
|
25
|
+
* what decides whether this kind can hold the body at all. */
|
|
26
|
+
readonly linked?: boolean;
|
|
27
|
+
/** The member being written, for a sub-entity op. An update validates the patch rather than the
|
|
28
|
+
* merged result, so a check that depends on a field the patch doesn't set — "may this node be
|
|
29
|
+
* given children", which needs its `element` — can only see it by reading the member back off
|
|
30
|
+
* `parent`. That needs to know which member. */
|
|
31
|
+
readonly key?: string;
|
|
32
|
+
}
|
|
33
|
+
/** A schema, or a factory that builds one from its context. A factory is what lets a check be part
|
|
34
|
+
* of the schema (`z.enum(the owner's layer names)`) rather than a refinement bolted beside it. */
|
|
35
|
+
type SchemaOrFactory = z.ZodTypeAny | ((ctx: FieldsCtx) => z.ZodTypeAny);
|
|
36
|
+
/** A kind's `data` override built from its context and its own fields — see `UserSchemas`. */
|
|
37
|
+
type DataFactory = (ctx: FieldsCtx & {
|
|
38
|
+
fields: FieldsSchema;
|
|
39
|
+
}) => z.ZodTypeAny;
|
|
40
|
+
/** One operation the kind exposes — its model-facing input shape, read/mutate axis, and (for a
|
|
41
|
+
* custom op) its behavior. `input` may be a factory when the op's data schema depends on the
|
|
42
|
+
* Config/parent; `opsForKind` resolves it for consumers that need a concrete schema. */
|
|
43
|
+
interface SchemaEntry {
|
|
44
|
+
readonly input: SchemaOrFactory;
|
|
45
|
+
readonly readOnly: boolean;
|
|
46
|
+
readonly handler?: OpHandler;
|
|
47
|
+
/** The verb's human name (`Create`, `Add`, `Remove`) — no entity, no field. A UI row whose folder
|
|
48
|
+
* already names the entity shows this alone. */
|
|
49
|
+
readonly label: string;
|
|
50
|
+
/** What the op does, for a model to choose it by. Written here, next to the input it describes, so
|
|
51
|
+
* a custom op is described where it's declared rather than in a switch somewhere downstream. This
|
|
52
|
+
* is the derived default — a user can override a tool's description on the Tool entity. */
|
|
53
|
+
readonly description: string;
|
|
54
|
+
/**
|
|
55
|
+
* What the op addresses — the one bit downstream display and examples need, and the reason neither
|
|
56
|
+
* has to parse a verb:
|
|
57
|
+
* `item` one member (`create`/`update`/`get`/a sub-op on one member)
|
|
58
|
+
* `collection` the whole collection (`list`, `sub-list`, `sub-reorder`) — reads plural
|
|
59
|
+
* `group` a group NODE, not an item (`group-update`)
|
|
60
|
+
* `config` the config itself, not any kind (`info`, `api`) — so a tool name carries no
|
|
61
|
+
* Entity segment and a title names the system
|
|
62
|
+
*/
|
|
63
|
+
readonly scope: 'item' | 'collection' | 'group' | 'config';
|
|
64
|
+
/** Whether the innermost address is new — `create` (a new `path`), `sub-create` (a new `key`). An
|
|
65
|
+
* example must not reuse an existing one, and `data` must be a full body rather than a patch. */
|
|
66
|
+
readonly creates?: boolean;
|
|
67
|
+
/** Mutations whose effect deserves explicit approval even on their native surface. Kept on the
|
|
68
|
+
* operation rather than inferred from its verb so custom operations carry the same policy. */
|
|
69
|
+
readonly approval?: 'destructive' | 'reference-change';
|
|
70
|
+
/** A composed title, when `<Verb> <Noun>` isn't English. `dependents` is a noun, so it reads
|
|
71
|
+
* Entity-first; `validate` takes an object, so the entity sits inside the phrase. */
|
|
72
|
+
readonly title?: (entity: string) => string;
|
|
73
|
+
/** An example invocation, for an op whose input isn't the standard `path`/`key`/`data`/`to`/`order`
|
|
74
|
+
* address shape. Declared by the op because only it knows what its own input means. */
|
|
75
|
+
readonly example?: (ctx: {
|
|
76
|
+
config: Config;
|
|
77
|
+
kind: string;
|
|
78
|
+
path: string;
|
|
79
|
+
}) => Record<string, unknown> | undefined;
|
|
80
|
+
}
|
|
81
|
+
/** The author's `schemas` param — keyed by verb. A base verb (`create`/`update`) takes `{ data }`
|
|
82
|
+
* to override just its data schema; `{ description }` changes only a derived op's presentation;
|
|
83
|
+
* a new verb takes a full custom op (`{ input, readOnly?, handler }`); `null` removes a derived op
|
|
84
|
+
* (any verb, incl. a read). */
|
|
85
|
+
type UserSchemas = Record<string, ({
|
|
86
|
+
/** The `data` half of the envelope: the body a create/update/replace takes. A factory sees
|
|
87
|
+
* the kind's own `fields` beside the context, so a variant that swapped a field is narrowed
|
|
88
|
+
* on its own fields rather than on the base's. */
|
|
89
|
+
data?: z.ZodTypeAny | DataFactory;
|
|
90
|
+
/** What a `path` of this kind may be, beyond what every path may be: parsed after the
|
|
91
|
+
* `<kind>:` marker is stripped. A kind whose path is also a name in generated code declares
|
|
92
|
+
* one — a style property's path is the JSX prop a component exposes. */
|
|
93
|
+
path?: z.ZodType<string, string>; /** The same, for a rename's `to`. */
|
|
94
|
+
to?: z.ZodType<string, string>;
|
|
95
|
+
} & Partial<Pick<SchemaEntry, 'description' | 'example'>>) | (Pick<SchemaEntry, 'description'> & Partial<Pick<SchemaEntry, 'example'>>) | ({
|
|
96
|
+
input: z.ZodTypeAny;
|
|
97
|
+
readOnly?: boolean;
|
|
98
|
+
handler: OpHandler;
|
|
99
|
+
} & Partial<Pick<SchemaEntry, 'label' | 'description' | 'scope' | 'creates' | 'approval' | 'title' | 'example'>>) | null>;
|
|
100
|
+
/** A resolved operation — a `SchemaEntry` tagged with its kind + verb, the shape `opsForKind`
|
|
101
|
+
* (registry.ts) yields and the Operation entity maps over. */
|
|
102
|
+
interface DerivedOp extends Omit<SchemaEntry, 'input'> {
|
|
103
|
+
readonly kind: string;
|
|
104
|
+
readonly verb: string;
|
|
105
|
+
/** Always concrete — `opsForKind` resolves a factory input before handing it out. */
|
|
106
|
+
readonly input: z.ZodTypeAny;
|
|
107
|
+
}
|
|
108
|
+
//#endregion
|
|
109
|
+
export { DerivedOp, FieldsCtx, OpHandler, SchemaEntry, UserSchemas };
|