@yahoo/uds-create-config 5.26.0 → 5.27.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/dist/configs/react-native-system.d.ts +22 -4
- package/dist/configs/system.js +2 -0
- package/dist/entities/native/NativeToken.d.ts +22 -4
- package/dist/entities/native/NativeToken.js +2 -1
- package/dist/entities/system/LinkedSystem.js +3 -2
- package/dist/entities/system/Token.d.ts +22 -4
- package/dist/entities/system/Token.js +4 -3
- package/dist/framework/Config.d.ts +1 -1
- package/dist/framework/Config.js +33 -2
- package/dist/framework/config-ops.d.ts +1 -1
- package/dist/framework/config-ops.js +25 -4
- package/dist/framework/defineSubEntity.d.ts +7 -0
- package/dist/framework/defineSubEntity.js +9 -0
- package/dist/framework/schema-version.d.ts +1 -1
- package/dist/framework/schema-version.js +5 -5
- package/dist/framework/utils/deprecated.d.ts +18 -0
- package/dist/framework/utils/deprecated.js +12 -0
- package/dist/migrations/20261013164300_token_overrides_list.d.ts +7 -0
- package/dist/migrations/20261013164300_token_overrides_list.js +10 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
|
@@ -69,10 +69,19 @@ declare const ReactNativeSystemDefinition: ConfigClass<{
|
|
|
69
69
|
tokens: EntityClass<_$zod.ZodObject<Omit<{
|
|
70
70
|
value: _$zod.ZodType<string | number | Ref | ComposedValue, unknown, _$zod_v4_core0.$ZodTypeInternals<string | number | Ref | ComposedValue, unknown>>;
|
|
71
71
|
type: _$zod.ZodOptional<_$zod.ZodString>;
|
|
72
|
-
overrides: _$zod.ZodOptional<
|
|
72
|
+
overrides: _$zod.ZodOptional<_$zod.ZodUnion<readonly [_$zod.ZodPipe<_$zod.ZodArray<_$zod.ZodObject<{
|
|
73
73
|
on: _$zod.ZodType<OverrideCondition, unknown, _$zod_v4_core0.$ZodTypeInternals<OverrideCondition, unknown>>;
|
|
74
74
|
value: _$zod.ZodType<string | number | Ref | ComposedValue, unknown, _$zod_v4_core0.$ZodTypeInternals<string | number | Ref | ComposedValue, unknown>>;
|
|
75
|
-
}, _$zod_v4_core0.$strip
|
|
75
|
+
}, _$zod_v4_core0.$strip>>, _$zod.ZodTransform<Record<string, {
|
|
76
|
+
on: OverrideCondition;
|
|
77
|
+
value: string | number | Ref | ComposedValue;
|
|
78
|
+
}>, {
|
|
79
|
+
on: OverrideCondition;
|
|
80
|
+
value: string | number | Ref | ComposedValue;
|
|
81
|
+
}[]>>, SubEntityClass<_$zod.ZodObject<{
|
|
82
|
+
on: _$zod.ZodType<OverrideCondition, unknown, _$zod_v4_core0.$ZodTypeInternals<OverrideCondition, unknown>>;
|
|
83
|
+
value: _$zod.ZodType<string | number | Ref | ComposedValue, unknown, _$zod_v4_core0.$ZodTypeInternals<string | number | Ref | ComposedValue, unknown>>;
|
|
84
|
+
}, _$zod_v4_core0.$strip>>]>>;
|
|
76
85
|
utility: _$zod.ZodOptional<_$zod.ZodBoolean>;
|
|
77
86
|
property: _$zod.ZodOptional<_$zod.ZodObject<{
|
|
78
87
|
syntax: _$zod.ZodOptional<_$zod.ZodString>;
|
|
@@ -81,10 +90,19 @@ declare const ReactNativeSystemDefinition: ConfigClass<{
|
|
|
81
90
|
cssVariable: _$zod.ZodOptional<_$zod.ZodUnion<readonly [_$zod.ZodString, _$zod.ZodLiteral<false>]>>;
|
|
82
91
|
}, "value" | "property" | "overrides" | "cssVariable"> & {
|
|
83
92
|
value: _$zod.ZodType<string | number | boolean | Ref | DerivedColor, unknown, _$zod_v4_core0.$ZodTypeInternals<string | number | boolean | Ref | DerivedColor, unknown>>;
|
|
84
|
-
overrides: _$zod.ZodOptional<
|
|
93
|
+
overrides: _$zod.ZodOptional<_$zod.ZodUnion<readonly [_$zod.ZodPipe<_$zod.ZodArray<_$zod.ZodObject<{
|
|
94
|
+
on: _$zod.ZodType<OverrideCondition, unknown, _$zod_v4_core0.$ZodTypeInternals<OverrideCondition, unknown>>;
|
|
95
|
+
value: _$zod.ZodType<string | number | boolean | Ref | DerivedColor, unknown, _$zod_v4_core0.$ZodTypeInternals<string | number | boolean | Ref | DerivedColor, unknown>>;
|
|
96
|
+
}, _$zod_v4_core0.$strip>>, _$zod.ZodTransform<Record<string, {
|
|
97
|
+
on: OverrideCondition;
|
|
98
|
+
value: string | number | boolean | Ref | DerivedColor;
|
|
99
|
+
}>, {
|
|
100
|
+
on: OverrideCondition;
|
|
101
|
+
value: string | number | boolean | Ref | DerivedColor;
|
|
102
|
+
}[]>>, SubEntityClass<_$zod.ZodObject<{
|
|
85
103
|
on: _$zod.ZodType<OverrideCondition, unknown, _$zod_v4_core0.$ZodTypeInternals<OverrideCondition, unknown>>;
|
|
86
104
|
value: _$zod.ZodType<string | number | boolean | Ref | DerivedColor, unknown, _$zod_v4_core0.$ZodTypeInternals<string | number | boolean | Ref | DerivedColor, unknown>>;
|
|
87
|
-
}, _$zod_v4_core0.$strip
|
|
105
|
+
}, _$zod_v4_core0.$strip>>]>>;
|
|
88
106
|
}, _$zod_v4_core0.$strip>, _$zod.ZodObject<Omit<{
|
|
89
107
|
cssPrefix: _$zod.ZodOptional<_$zod.ZodString>;
|
|
90
108
|
cssVariables: _$zod.ZodOptional<_$zod.ZodBoolean>;
|
package/dist/configs/system.js
CHANGED
|
@@ -67,6 +67,7 @@ import { cssMotionStrictMigration } from "../migrations/20261009181635_css_motio
|
|
|
67
67
|
import { linkOverrideRefMigration } from "../migrations/20261009193004_link_override_ref.js";
|
|
68
68
|
import { linkedComponentModulesMigration } from "../migrations/20261012200606_linked_component_modules.js";
|
|
69
69
|
import { componentStatesMigration } from "../migrations/20261013154037_component_states.js";
|
|
70
|
+
import { tokenOverridesListMigration } from "../migrations/20261013164300_token_overrides_list.js";
|
|
70
71
|
const System = defineConfig({
|
|
71
72
|
name: WEB_CONFIG_NAME,
|
|
72
73
|
description: "A design system: the values, primitives and compositions an app is built from. A ref is written `{ \"__ref\": \"<kind>:<path>\" }`, so a token is `{ \"__ref\": \"token:<group>/<name>\" }` and a token group is `{ \"__ref\": \"token:<group>\" }`. Build it in this order. Tokens first, in groups by purpose (colors, spacing, radii, type sizes), since everything else names them. Then style properties, each with `values` holding one ref to the token group whose members it accepts (`{ \"__ref\": \"token:color\" }`), so a prop takes token names rather than raw CSS; add a string keyword only for a value no token holds. A style rule's bag holds a prop's values (`\"padding\": \"4\"`, `\"bg\": \"brand\"`), never raw CSS. Then a few primitive components, one layer each, whose props are style properties (a box for layout and surface, a text for type, a pressable for interaction). Then every other component composed from those primitives: its layers name a primitive or an element, its anatomy places them (a node renders a layer, a tag or `Slot` where a slot prop's content lands; `children` is the edge list; `visible` is `{ \"$state\": \"<prop>\" }`; a prop shown in a nested layer is a `forward` route, and `$state` never sits in a node's props), and its style rules set style-property values per layer, keyed by prop values when a variant changes them. Modes (a dark mode is `{ type: \"selector\", value: \".dark\" }`) change token values through a token's `overrides`, so a component never restyles for a mode; modifiers (hover, focus, disabled) name a state, and a style rule applies under one as a `_hover` block inside a layer bag. Composites bundle style values that recur. Last, register canvas roles: the canvas draws with them, one entity per tool (`frame` for the layout primitive, `text` for the text primitive, `image`) whose entries name the components that tool inserts, and a tool whose role is unregistered is disabled. Give each component a `preview` entry under `*` so it shows content, and never write a CSS property name where a style-property name belongs.",
|
|
@@ -145,5 +146,6 @@ if (!registeredSchemaMigrations().has(20261009181635)) registerSchemaMigrations(
|
|
|
145
146
|
if (!registeredSchemaMigrations().has(20261009193004)) registerSchemaMigrations(linkOverrideRefMigration);
|
|
146
147
|
if (!registeredSchemaMigrations().has(20261012200606)) registerSchemaMigrations(linkedComponentModulesMigration);
|
|
147
148
|
if (!registeredSchemaMigrations().has(20261013154037)) registerSchemaMigrations(componentStatesMigration);
|
|
149
|
+
if (!registeredSchemaMigrations().has(20261013164300)) registerSchemaMigrations(tokenOverridesListMigration);
|
|
148
150
|
//#endregion
|
|
149
151
|
export { System };
|
|
@@ -12,10 +12,19 @@ declare const nativeTokenValue: z.ZodType<number | boolean | string | Ref$1 | De
|
|
|
12
12
|
declare const NativeToken: EntityClass<z.ZodObject<Omit<{
|
|
13
13
|
value: z.ZodType<string | number | Ref | ComposedValue, unknown, z.core.$ZodTypeInternals<string | number | Ref | ComposedValue, unknown>>;
|
|
14
14
|
type: z.ZodOptional<z.ZodString>;
|
|
15
|
-
overrides: z.ZodOptional<
|
|
15
|
+
overrides: z.ZodOptional<z.ZodUnion<readonly [z.ZodPipe<z.ZodArray<z.ZodObject<{
|
|
16
16
|
on: z.ZodType<OverrideCondition, unknown, z.core.$ZodTypeInternals<OverrideCondition, unknown>>;
|
|
17
17
|
value: z.ZodType<string | number | Ref | ComposedValue, unknown, z.core.$ZodTypeInternals<string | number | Ref | ComposedValue, unknown>>;
|
|
18
|
-
}, z.core.$strip
|
|
18
|
+
}, z.core.$strip>>, z.ZodTransform<Record<string, {
|
|
19
|
+
on: OverrideCondition;
|
|
20
|
+
value: string | number | Ref | ComposedValue;
|
|
21
|
+
}>, {
|
|
22
|
+
on: OverrideCondition;
|
|
23
|
+
value: string | number | Ref | ComposedValue;
|
|
24
|
+
}[]>>, SubEntityClass<z.ZodObject<{
|
|
25
|
+
on: z.ZodType<OverrideCondition, unknown, z.core.$ZodTypeInternals<OverrideCondition, unknown>>;
|
|
26
|
+
value: z.ZodType<string | number | Ref | ComposedValue, unknown, z.core.$ZodTypeInternals<string | number | Ref | ComposedValue, unknown>>;
|
|
27
|
+
}, z.core.$strip>>]>>;
|
|
19
28
|
utility: z.ZodOptional<z.ZodBoolean>;
|
|
20
29
|
property: z.ZodOptional<z.ZodObject<{
|
|
21
30
|
syntax: z.ZodOptional<z.ZodString>;
|
|
@@ -24,10 +33,19 @@ declare const NativeToken: EntityClass<z.ZodObject<Omit<{
|
|
|
24
33
|
cssVariable: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodLiteral<false>]>>;
|
|
25
34
|
}, "value" | "property" | "overrides" | "cssVariable"> & {
|
|
26
35
|
value: z.ZodType<string | number | boolean | Ref | DerivedColor, unknown, z.core.$ZodTypeInternals<string | number | boolean | Ref | DerivedColor, unknown>>;
|
|
27
|
-
overrides: z.ZodOptional<
|
|
36
|
+
overrides: z.ZodOptional<z.ZodUnion<readonly [z.ZodPipe<z.ZodArray<z.ZodObject<{
|
|
37
|
+
on: z.ZodType<OverrideCondition, unknown, z.core.$ZodTypeInternals<OverrideCondition, unknown>>;
|
|
38
|
+
value: z.ZodType<string | number | boolean | Ref | DerivedColor, unknown, z.core.$ZodTypeInternals<string | number | boolean | Ref | DerivedColor, unknown>>;
|
|
39
|
+
}, z.core.$strip>>, z.ZodTransform<Record<string, {
|
|
40
|
+
on: OverrideCondition;
|
|
41
|
+
value: string | number | boolean | Ref | DerivedColor;
|
|
42
|
+
}>, {
|
|
43
|
+
on: OverrideCondition;
|
|
44
|
+
value: string | number | boolean | Ref | DerivedColor;
|
|
45
|
+
}[]>>, SubEntityClass<z.ZodObject<{
|
|
28
46
|
on: z.ZodType<OverrideCondition, unknown, z.core.$ZodTypeInternals<OverrideCondition, unknown>>;
|
|
29
47
|
value: z.ZodType<string | number | boolean | Ref | DerivedColor, unknown, z.core.$ZodTypeInternals<string | number | boolean | Ref | DerivedColor, unknown>>;
|
|
30
|
-
}, z.core.$strip
|
|
48
|
+
}, z.core.$strip>>]>>;
|
|
31
49
|
}, z.core.$strip>, z.ZodObject<Omit<{
|
|
32
50
|
cssPrefix: z.ZodOptional<z.ZodString>;
|
|
33
51
|
cssVariables: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { refSchema } from "../../framework/utils/refs.js";
|
|
2
2
|
import { oklchColor } from "../system/color.js";
|
|
3
|
+
import { orList } from "../../framework/defineSubEntity.js";
|
|
3
4
|
import { Font } from "../system/Font.js";
|
|
4
5
|
import { NATIVE_CONFIG_NAME } from "../../configs/platform.js";
|
|
5
6
|
import { prepareLinkedTokenBody } from "../system/linked-token-values.js";
|
|
@@ -66,7 +67,7 @@ const NativeToken = Token.extend({
|
|
|
66
67
|
entityName: "NativeToken",
|
|
67
68
|
fields: {
|
|
68
69
|
value: nativeTokenValue,
|
|
69
|
-
overrides: NativeOverride.optional(),
|
|
70
|
+
overrides: orList(NativeOverride).optional(),
|
|
70
71
|
cssVariable: null,
|
|
71
72
|
property: null
|
|
72
73
|
},
|
|
@@ -753,8 +753,9 @@ displayName: ({ member, path }) => typeof member.name === "string" && member.nam
|
|
|
753
753
|
bulkOverlayWrite: ({ accessor, path, overlay }) => ({ [`options.${accessor}.${path}`]: overlay })
|
|
754
754
|
});
|
|
755
755
|
/** An `override` or `extend` body with its `styles` as a list, in the stored form: the record keyed by
|
|
756
|
-
* each rule's condition, as `Component.item` stores one. Only a component
|
|
757
|
-
*
|
|
756
|
+
* each rule's condition, as `Component.item` stores one. Only a component has `styles`, so a list
|
|
757
|
+
* there is a rule list whatever accessor it sits under. A token's `overrides` list is stored as
|
|
758
|
+
* written and keyed where the overlay is read. */
|
|
758
759
|
function storedPinBody(body) {
|
|
759
760
|
if (!isPlainObject(body) || !Array.isArray(body.styles)) return body;
|
|
760
761
|
return {
|
|
@@ -44,10 +44,19 @@ declare function defineOverride<TValue extends z.ZodTypeAny>(value: TValue): Sub
|
|
|
44
44
|
declare const tokenFields: z.ZodObject<{
|
|
45
45
|
value: z.ZodType<string | number | Ref | ComposedValue, unknown, z.core.$ZodTypeInternals<string | number | Ref | ComposedValue, unknown>>;
|
|
46
46
|
type: z.ZodOptional<z.ZodString>;
|
|
47
|
-
overrides: z.ZodOptional<
|
|
47
|
+
overrides: z.ZodOptional<z.ZodUnion<readonly [z.ZodPipe<z.ZodArray<z.ZodObject<{
|
|
48
48
|
on: z.ZodType<OverrideCondition, unknown, z.core.$ZodTypeInternals<OverrideCondition, unknown>>;
|
|
49
49
|
value: z.ZodType<string | number | Ref | ComposedValue, unknown, z.core.$ZodTypeInternals<string | number | Ref | ComposedValue, unknown>>;
|
|
50
|
-
}, z.core.$strip
|
|
50
|
+
}, z.core.$strip>>, z.ZodTransform<Record<string, {
|
|
51
|
+
on: OverrideCondition;
|
|
52
|
+
value: string | number | Ref | ComposedValue;
|
|
53
|
+
}>, {
|
|
54
|
+
on: OverrideCondition;
|
|
55
|
+
value: string | number | Ref | ComposedValue;
|
|
56
|
+
}[]>>, SubEntityClass<z.ZodObject<{
|
|
57
|
+
on: z.ZodType<OverrideCondition, unknown, z.core.$ZodTypeInternals<OverrideCondition, unknown>>;
|
|
58
|
+
value: z.ZodType<string | number | Ref | ComposedValue, unknown, z.core.$ZodTypeInternals<string | number | Ref | ComposedValue, unknown>>;
|
|
59
|
+
}, z.core.$strip>>]>>;
|
|
51
60
|
utility: z.ZodOptional<z.ZodBoolean>;
|
|
52
61
|
property: z.ZodOptional<z.ZodObject<{
|
|
53
62
|
syntax: z.ZodOptional<z.ZodString>;
|
|
@@ -61,10 +70,19 @@ type TokenBody = z.infer<typeof tokenFields>;
|
|
|
61
70
|
declare const TokenEntity: EntityClass<z.ZodObject<{
|
|
62
71
|
value: z.ZodType<string | number | Ref | ComposedValue, unknown, z.core.$ZodTypeInternals<string | number | Ref | ComposedValue, unknown>>;
|
|
63
72
|
type: z.ZodOptional<z.ZodString>;
|
|
64
|
-
overrides: z.ZodOptional<
|
|
73
|
+
overrides: z.ZodOptional<z.ZodUnion<readonly [z.ZodPipe<z.ZodArray<z.ZodObject<{
|
|
74
|
+
on: z.ZodType<OverrideCondition, unknown, z.core.$ZodTypeInternals<OverrideCondition, unknown>>;
|
|
75
|
+
value: z.ZodType<string | number | Ref | ComposedValue, unknown, z.core.$ZodTypeInternals<string | number | Ref | ComposedValue, unknown>>;
|
|
76
|
+
}, z.core.$strip>>, z.ZodTransform<Record<string, {
|
|
77
|
+
on: OverrideCondition;
|
|
78
|
+
value: string | number | Ref | ComposedValue;
|
|
79
|
+
}>, {
|
|
80
|
+
on: OverrideCondition;
|
|
81
|
+
value: string | number | Ref | ComposedValue;
|
|
82
|
+
}[]>>, SubEntityClass<z.ZodObject<{
|
|
65
83
|
on: z.ZodType<OverrideCondition, unknown, z.core.$ZodTypeInternals<OverrideCondition, unknown>>;
|
|
66
84
|
value: z.ZodType<string | number | Ref | ComposedValue, unknown, z.core.$ZodTypeInternals<string | number | Ref | ComposedValue, unknown>>;
|
|
67
|
-
}, z.core.$strip
|
|
85
|
+
}, z.core.$strip>>]>>;
|
|
68
86
|
utility: z.ZodOptional<z.ZodBoolean>;
|
|
69
87
|
property: z.ZodOptional<z.ZodObject<{
|
|
70
88
|
syntax: z.ZodOptional<z.ZodString>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isRef, kindOf, pathOf, ref, refKey, sourceOf } from "../../framework/utils/refs.js";
|
|
2
2
|
import { composedValueSchemas } from "./composed-values.js";
|
|
3
3
|
import { defineEntity } from "../../framework/defineEntity.js";
|
|
4
|
-
import { defineSubEntity } from "../../framework/defineSubEntity.js";
|
|
4
|
+
import { defineSubEntity, orList } from "../../framework/defineSubEntity.js";
|
|
5
5
|
import { Font } from "./Font.js";
|
|
6
6
|
import { Modifier } from "./Modifier.js";
|
|
7
7
|
import { spellTokenRead } from "./token-values.js";
|
|
@@ -112,7 +112,8 @@ function defineOverride(value) {
|
|
|
112
112
|
on: config ? declaredCondition(config) : overrideConditionSchema,
|
|
113
113
|
value
|
|
114
114
|
}),
|
|
115
|
-
key: (override) => overrideKey(override.on)
|
|
115
|
+
key: (override) => overrideKey(override.on),
|
|
116
|
+
listed: true
|
|
116
117
|
});
|
|
117
118
|
}
|
|
118
119
|
const Override = defineOverride(tokenValue);
|
|
@@ -128,7 +129,7 @@ const TokenEntity = defineEntity({
|
|
|
128
129
|
fields: z.object({
|
|
129
130
|
value: tokenValue.describe("The base value: a literal, a ref to another token, or a composed value such as a gradient."),
|
|
130
131
|
type: z.string().optional().describe("The CSS value type, when the value alone does not say it."),
|
|
131
|
-
overrides: Override.optional().describe("Per-mode values, keyed by the condition
|
|
132
|
+
overrides: orList(Override).optional().describe("Per-mode values, a list of `{ on, value }`. Stored keyed by the condition each applies under."),
|
|
132
133
|
utility: z.boolean().optional().describe("`false` keeps the token out of its group's values, so a style prop that takes the group writes no class for it — `spacing/scale` powers `--spacing` without becoming a `p-scale`. A ref naming the token still resolves."),
|
|
133
134
|
property: z.strictObject({
|
|
134
135
|
syntax: z.string().optional().describe("The `@property` syntax, as `<length>`. Defaults to `*`."),
|
|
@@ -73,7 +73,7 @@ interface RecordedSource {
|
|
|
73
73
|
* The dense-counter `2` a short-lived scheme stamped before the chain existed reads as the mint
|
|
74
74
|
* that replaced it (see `detectedWireVersion`).
|
|
75
75
|
*/
|
|
76
|
-
declare const SERIALIZED_CONFIG_VERSION =
|
|
76
|
+
declare const SERIALIZED_CONFIG_VERSION = 20261013164300;
|
|
77
77
|
interface SerializedConfig {
|
|
78
78
|
/** See {@link SERIALIZED_CONFIG_VERSION}. Always written; a stored artifact may lack it. */
|
|
79
79
|
readonly version: number;
|
package/dist/framework/Config.js
CHANGED
|
@@ -318,6 +318,37 @@ function leafOf(field) {
|
|
|
318
318
|
function wholeBodySchema(entry, ctx = {}) {
|
|
319
319
|
return dataSchema(entry.schemas, "create", ctx) ?? dataSchema(entry.schemas, "replace", ctx);
|
|
320
320
|
}
|
|
321
|
+
/**
|
|
322
|
+
* An overlay whose bodies hold a list for a collection keyed by its members (`defineSubEntity({ key })`),
|
|
323
|
+
* with each list written as the record that collection is stored as. A pin stores its bodies as
|
|
324
|
+
* authored, and the overlay is laid onto the source key by key, so a list left as written would
|
|
325
|
+
* replace the source's record rather than add to it. A later member wins over an earlier one with
|
|
326
|
+
* the same key.
|
|
327
|
+
*/
|
|
328
|
+
function keyedOverlay(entry, overlay) {
|
|
329
|
+
if (!entry) return overlay;
|
|
330
|
+
const keyed = (body) => {
|
|
331
|
+
if (!body) return body;
|
|
332
|
+
let out;
|
|
333
|
+
for (const [field, sub] of Object.entries(entry.subEntities)) {
|
|
334
|
+
const members = body[field];
|
|
335
|
+
if (!sub.key || !Array.isArray(members)) continue;
|
|
336
|
+
const record = {};
|
|
337
|
+
for (const member of members) record[sub.key(member)] = member;
|
|
338
|
+
out ??= { ...body };
|
|
339
|
+
out[field] = record;
|
|
340
|
+
}
|
|
341
|
+
return out ?? body;
|
|
342
|
+
};
|
|
343
|
+
const override = keyed(overlay.override);
|
|
344
|
+
const extend = keyed(overlay.extend);
|
|
345
|
+
if (override === overlay.override && extend === overlay.extend) return overlay;
|
|
346
|
+
return {
|
|
347
|
+
...overlay,
|
|
348
|
+
override,
|
|
349
|
+
extend
|
|
350
|
+
};
|
|
351
|
+
}
|
|
321
352
|
/** The sub-entity a field path names, at either depth. */
|
|
322
353
|
function subEntityAt(entry, field) {
|
|
323
354
|
const slash = field.indexOf("/");
|
|
@@ -3764,7 +3795,7 @@ var Config = class Config {
|
|
|
3764
3795
|
const overlay = entry.bulkOverlay?.(args);
|
|
3765
3796
|
if (overlay !== void 0) return {
|
|
3766
3797
|
claimed,
|
|
3767
|
-
overlay
|
|
3798
|
+
overlay: keyedOverlay(this.entityOf(kind), overlay)
|
|
3768
3799
|
};
|
|
3769
3800
|
if (claimed) return { claimed: true };
|
|
3770
3801
|
}
|
|
@@ -5749,7 +5780,7 @@ var Config = class Config {
|
|
|
5749
5780
|
* links from the provided sources. A declared `linkedKind` with no provided source throws. */
|
|
5750
5781
|
hydrateFrom(stored, options) {
|
|
5751
5782
|
const claimed = schemaVersionOf(stored);
|
|
5752
|
-
if (claimed >
|
|
5783
|
+
if (claimed > 20261013164300) throw new SchemaVersionTooNew(claimed);
|
|
5753
5784
|
const wire = upgradeSerializedConfig(stored);
|
|
5754
5785
|
if (!Array.isArray(wire.ownedKinds) || typeof wire.items !== "object" || wire.items === null) throw new ConfigFormatError(`Config "${stored.name ?? "system-config"}" cannot be hydrated: this is not a serialized config-v2 config (no "ownedKinds"/"items"). A pre-cutover build artifact converts through the registered cutover migration — import the config type's module (e.g. \`configs/system\`) before hydrating, or port the repo once with \`uds migrate\`.`);
|
|
5755
5786
|
const leftover = wire.options;
|
|
@@ -16,7 +16,7 @@ interface KindSignature {
|
|
|
16
16
|
readonly collections: Record<string, string>;
|
|
17
17
|
/** The group node's own fields, when the kind carries any. */
|
|
18
18
|
readonly group?: string;
|
|
19
|
-
/** A real entry from this config,
|
|
19
|
+
/** A real entry from this config, as it is authored. */
|
|
20
20
|
readonly example?: unknown;
|
|
21
21
|
}
|
|
22
22
|
interface AuthoringSignatureOptions {
|
|
@@ -75,6 +75,19 @@ function authoringSignature(schema, options) {
|
|
|
75
75
|
const json = jsonSchema(schema);
|
|
76
76
|
return json === void 0 ? void 0 : renderSignature(withoutMetadata(json), options);
|
|
77
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* A real entry, spelled the way it is authored. A collection whose schema offers only a list (see
|
|
80
|
+
* `withDeprecated`) is stored as the record keyed by its members, so the example writes its members
|
|
81
|
+
* as that list, and a reader copying it never learns the deprecated record.
|
|
82
|
+
*/
|
|
83
|
+
function authoredExample({ item, fields }) {
|
|
84
|
+
const body = item.toJSON();
|
|
85
|
+
const properties = fields?.properties;
|
|
86
|
+
if (!properties) return { [item.path]: body };
|
|
87
|
+
const authored = { ...body };
|
|
88
|
+
for (const [field, value] of Object.entries(body)) if (properties[field]?.type === "array" && value && typeof value === "object" && !Array.isArray(value)) authored[field] = Object.values(value);
|
|
89
|
+
return { [item.path]: authored };
|
|
90
|
+
}
|
|
78
91
|
/** Every owned kind's authoring shape as signatures, with a real example where the config has one. */
|
|
79
92
|
function authoringSignatures(config, { depth, memberDepth = depth } = {}) {
|
|
80
93
|
return config.ownedKinds().flatMap((kind) => {
|
|
@@ -87,14 +100,18 @@ function authoringSignatures(config, { depth, memberDepth = depth } = {}) {
|
|
|
87
100
|
if (signature) collections[field] = singleton ? `one section, no key (\`sub-update/${field}\`): ${signature}` : signature;
|
|
88
101
|
}
|
|
89
102
|
const first = config.list(kind)[0];
|
|
103
|
+
const create = dataSchemaOf(config, entity.schemas.create);
|
|
90
104
|
return [{
|
|
91
105
|
kind,
|
|
92
106
|
label: entity.label,
|
|
93
107
|
refHelper: entity.entityName,
|
|
94
|
-
create: authoringSignature(
|
|
108
|
+
create: authoringSignature(create, { depth }),
|
|
95
109
|
collections,
|
|
96
110
|
group: authoringSignature(entity.groupCreateSchema, { depth }),
|
|
97
|
-
example: first ? {
|
|
111
|
+
example: first ? authoredExample({
|
|
112
|
+
item: first,
|
|
113
|
+
fields: jsonSchema(create)
|
|
114
|
+
}) : void 0
|
|
98
115
|
}];
|
|
99
116
|
});
|
|
100
117
|
}
|
|
@@ -137,14 +154,18 @@ function authoringReference(config) {
|
|
|
137
154
|
collections[field] = jsonSchema(dataSchemaOf(config, entity.schemas[`sub-create/${field}`]));
|
|
138
155
|
}
|
|
139
156
|
const first = config.list(kind)[0];
|
|
157
|
+
const fields = jsonSchema(dataSchemaOf(config, entity.schemas.create));
|
|
140
158
|
return [{
|
|
141
159
|
kind,
|
|
142
160
|
label: entity.label,
|
|
143
161
|
refHelper: entity.entityName,
|
|
144
|
-
fields
|
|
162
|
+
fields,
|
|
145
163
|
collections,
|
|
146
164
|
groupFields: jsonSchema(entity.groupCreateSchema),
|
|
147
|
-
example: first ? {
|
|
165
|
+
example: first ? authoredExample({
|
|
166
|
+
item: first,
|
|
167
|
+
fields
|
|
168
|
+
}) : void 0
|
|
148
169
|
}];
|
|
149
170
|
}) };
|
|
150
171
|
}
|
|
@@ -36,6 +36,9 @@ type SubEntityClass<F extends z.ZodTypeAny = z.ZodTypeAny> = CollectionSchema<F>
|
|
|
36
36
|
* caller, so key and value can't drift, two members with the same identity can't both exist, and
|
|
37
37
|
* an edit that changes the identity moves the entry. Omit when the key is arbitrary. */
|
|
38
38
|
readonly key?: (member: unknown) => string;
|
|
39
|
+
/** The collection is authored as a list of its members, which carry their own `key`. The keyed
|
|
40
|
+
* record it is stored as is still read but no longer offered: see {@link orList}. */
|
|
41
|
+
readonly listed?: true;
|
|
39
42
|
/** Whether a member DECLARES nothing — a style rule whose every layer bag is empty. Asked only
|
|
40
43
|
* when a \`sub-update\` would bring the member into being: a delta made entirely of removals has
|
|
41
44
|
* nothing to remove from a member that is not there, so creating one files an entry that emits
|
|
@@ -143,6 +146,7 @@ declare function defineSubEntity<F extends z.ZodTypeAny>(spec: {
|
|
|
143
146
|
*/
|
|
144
147
|
base?: z.ZodTypeAny;
|
|
145
148
|
key?: (member: unknown) => string;
|
|
149
|
+
listed?: true;
|
|
146
150
|
vacant?: (member: unknown) => boolean;
|
|
147
151
|
schemas?: UserSchemas;
|
|
148
152
|
namespaces?: string;
|
|
@@ -161,6 +165,9 @@ declare function defineSubEntity<F extends z.ZodTypeAny>(spec: {
|
|
|
161
165
|
* Two members with the same key are one member, the later one, as the key derivation on write
|
|
162
166
|
* already treats a record whose keys disagree with their members — unless `merge` says how the two
|
|
163
167
|
* combine, in which case the member is `merge(earlier, later)`, placed where the later one was.
|
|
168
|
+
*
|
|
169
|
+
* A collection declared `listed` still takes the keyed record but offers only the list, see
|
|
170
|
+
* {@link withDeprecated}.
|
|
164
171
|
*/
|
|
165
172
|
declare function orList<F extends z.ZodTypeAny>(collection: SubEntityClass<F>, {
|
|
166
173
|
merge
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { kindOf, memberOf, memberRef, pathOf } from "./utils/refs.js";
|
|
2
2
|
import { resolveSchema } from "./schemas.js";
|
|
3
3
|
import { titleCase } from "./registry.js";
|
|
4
|
+
import { withDeprecated } from "./utils/deprecated.js";
|
|
4
5
|
import { z } from "zod";
|
|
5
6
|
//#region src/framework/defineSubEntity.ts
|
|
6
7
|
/**
|
|
@@ -78,6 +79,7 @@ function defineSubEntity(spec) {
|
|
|
78
79
|
fields: spec.fields,
|
|
79
80
|
base: spec.base,
|
|
80
81
|
key: spec.key,
|
|
82
|
+
...spec.listed ? { listed: true } : {},
|
|
81
83
|
vacant: spec.vacant,
|
|
82
84
|
schemas: spec.schemas,
|
|
83
85
|
namespaces: spec.namespaces,
|
|
@@ -126,6 +128,9 @@ function defineSubEntity(spec) {
|
|
|
126
128
|
* Two members with the same key are one member, the later one, as the key derivation on write
|
|
127
129
|
* already treats a record whose keys disagree with their members — unless `merge` says how the two
|
|
128
130
|
* combine, in which case the member is `merge(earlier, later)`, placed where the later one was.
|
|
131
|
+
*
|
|
132
|
+
* A collection declared `listed` still takes the keyed record but offers only the list, see
|
|
133
|
+
* {@link withDeprecated}.
|
|
129
134
|
*/
|
|
130
135
|
function orList(collection, { merge } = {}) {
|
|
131
136
|
const key = collection.key;
|
|
@@ -142,6 +147,10 @@ function orList(collection, { merge } = {}) {
|
|
|
142
147
|
}
|
|
143
148
|
return keyed;
|
|
144
149
|
});
|
|
150
|
+
if (collection.listed) return withDeprecated({
|
|
151
|
+
offered: listed,
|
|
152
|
+
deprecated: collection
|
|
153
|
+
});
|
|
145
154
|
return z.union([listed, collection]);
|
|
146
155
|
}
|
|
147
156
|
//#endregion
|
|
@@ -15,7 +15,7 @@ import { Patch, SerializedConfig } from "./Config.js";
|
|
|
15
15
|
* sets this constant to its own older timestamp; the merge ref then carries a registered migration
|
|
16
16
|
* newer than the constant, and the assertion fails until the author re-mints.
|
|
17
17
|
*/
|
|
18
|
-
declare const CURRENT_SCHEMA_VERSION =
|
|
18
|
+
declare const CURRENT_SCHEMA_VERSION = 20261013164300;
|
|
19
19
|
/** What the walkers need to see of an envelope — loose on purpose, so a typed `SerializedConfig`
|
|
20
20
|
* and a raw old-shape record both flow in without casts. */
|
|
21
21
|
interface VersionStamped {
|
|
@@ -13,7 +13,7 @@ import { ConfigFormatError } from "./rejection.js";
|
|
|
13
13
|
* sets this constant to its own older timestamp; the merge ref then carries a registered migration
|
|
14
14
|
* newer than the constant, and the assertion fails until the author re-mints.
|
|
15
15
|
*/
|
|
16
|
-
const CURRENT_SCHEMA_VERSION =
|
|
16
|
+
const CURRENT_SCHEMA_VERSION = 20261013164300;
|
|
17
17
|
/** The mint that moved `options` into the `settings` kind — restated here, rather than imported
|
|
18
18
|
* from the migration that owns it, because that migration imports this module. */
|
|
19
19
|
const SETTINGS_AS_KIND_VERSION = 20260908171448;
|
|
@@ -45,7 +45,7 @@ function registerSchemaMigrations(...migrations) {
|
|
|
45
45
|
for (const migration of migrations) {
|
|
46
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
47
|
if (REGISTERED.has(migration.version)) throw new Error(`A schema migration at version ${migration.version} is already registered.`);
|
|
48
|
-
if (migration.version >
|
|
48
|
+
if (migration.version > 20261013164300) 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
49
|
REGISTERED.set(migration.version, migration);
|
|
50
50
|
}
|
|
51
51
|
}
|
|
@@ -102,7 +102,7 @@ function pendingFor(version, target, options) {
|
|
|
102
102
|
* Already-current input passes through untouched — same reference, so hot paths pay nothing.
|
|
103
103
|
*/
|
|
104
104
|
function upgradeSerializedConfig(json, options) {
|
|
105
|
-
const target = options?.target ??
|
|
105
|
+
const target = options?.target ?? 20261013164300;
|
|
106
106
|
const version = detectedWireVersion(json);
|
|
107
107
|
if (version > target) throw new SchemaVersionTooNew(version, target);
|
|
108
108
|
const raw = json;
|
|
@@ -160,7 +160,7 @@ function upgradedSources(json, options) {
|
|
|
160
160
|
* meaning under the current schema and replay skips it — reported by the caller, not swallowed here.
|
|
161
161
|
*/
|
|
162
162
|
function upgradePatch(patch, writtenAt, options) {
|
|
163
|
-
const target = options?.target ??
|
|
163
|
+
const target = options?.target ?? 20261013164300;
|
|
164
164
|
if (writtenAt > target) throw new SchemaVersionTooNew(writtenAt, target);
|
|
165
165
|
let current = patch;
|
|
166
166
|
for (const migration of pendingFor(writtenAt, target, options)) {
|
|
@@ -179,7 +179,7 @@ function upgradePatch(patch, writtenAt, options) {
|
|
|
179
179
|
* stamp would cause.
|
|
180
180
|
*/
|
|
181
181
|
function upgradeDraftEntries(draft, options) {
|
|
182
|
-
const target = options?.target ??
|
|
182
|
+
const target = options?.target ?? 20261013164300;
|
|
183
183
|
const entries = [];
|
|
184
184
|
const held = [];
|
|
185
185
|
const retired = [];
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A schema that still takes a deprecated form but no longer offers it.
|
|
3
|
+
*
|
|
4
|
+
* Parsing accepts `offered` or `deprecated`, so stored data and older config files keep loading.
|
|
5
|
+
* Rendered as JSON Schema, which is what tool signatures, `config/api`, the MCP's input schemas and
|
|
6
|
+
* the docs are built from, it shows only `offered`, so nothing that reads a schema learns the old
|
|
7
|
+
* form.
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
/**
|
|
11
|
+
* `read` with every deprecated form shown in the JSON Schema it renders. The schema-version tripwire
|
|
12
|
+
* reads through this, since it guards everything a client accepts, offered or not.
|
|
13
|
+
*/
|
|
14
|
+
export declare function includingDeprecated<T>(read: () => T): T;
|
|
15
|
+
export declare function withDeprecated<O extends z.ZodTypeAny, D extends z.ZodTypeAny>({ offered, deprecated, }: {
|
|
16
|
+
offered: O;
|
|
17
|
+
deprecated: D;
|
|
18
|
+
}): z.ZodUnion<readonly [O, D]>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
function withDeprecated({ offered, deprecated }) {
|
|
3
|
+
const schema = z.union([offered, deprecated]);
|
|
4
|
+
const offeredOnly = () => {
|
|
5
|
+
const { $schema: _dialect, ...json } = z.toJSONSchema(offered, { io: "input" });
|
|
6
|
+
return json;
|
|
7
|
+
};
|
|
8
|
+
schema._zod.toJSONSchema = () => offeredOnly();
|
|
9
|
+
return schema;
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { withDeprecated };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A token's `overrides` also takes a list of `{ on, value }`, which is stored as the record keyed by
|
|
3
|
+
* each override's condition. The stored form is unchanged, so the hop is identity.
|
|
4
|
+
*/
|
|
5
|
+
import type { SchemaMigration } from '../framework/schema-version';
|
|
6
|
+
export declare const TOKEN_OVERRIDES_LIST_VERSION = 20261013164300;
|
|
7
|
+
export declare const tokenOverridesListMigration: SchemaMigration;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/migrations/20261013164300_token_overrides_list.ts
|
|
2
|
+
const TOKEN_OVERRIDES_LIST_VERSION = 20261013164300;
|
|
3
|
+
const tokenOverridesListMigration = {
|
|
4
|
+
version: TOKEN_OVERRIDES_LIST_VERSION,
|
|
5
|
+
up(json) {
|
|
6
|
+
return json;
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
//#endregion
|
|
10
|
+
export { TOKEN_OVERRIDES_LIST_VERSION, tokenOverridesListMigration };
|