@yahoo/uds-create-config 2.45.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.
Files changed (376) hide show
  1. package/README.md +129 -0
  2. package/dist/ai-lanes.d.ts +23 -0
  3. package/dist/ai-lanes.js +34 -0
  4. package/dist/authoring/define-component.d.ts +85 -0
  5. package/dist/configs/CanvasConfig.d.ts +3237 -0
  6. package/dist/configs/CanvasConfig.js +332 -0
  7. package/dist/configs/build-options.d.ts +10 -0
  8. package/dist/configs/build-options.js +68 -0
  9. package/dist/configs/platform.d.ts +15 -0
  10. package/dist/configs/platform.js +17 -0
  11. package/dist/configs/react-native-system.d.ts +3026 -0
  12. package/dist/configs/react-native-system.js +64 -0
  13. package/dist/configs/system.d.ts +2771 -0
  14. package/dist/configs/system.js +74 -0
  15. package/dist/css/properties.generated.d.ts +14 -0
  16. package/dist/css/properties.generated.js +6260 -0
  17. package/dist/css/value-type.d.ts +48 -0
  18. package/dist/css/value-type.js +131 -0
  19. package/dist/css/values.d.ts +33 -0
  20. package/dist/css/values.js +116 -0
  21. package/dist/entities/native/NativeModifier.d.ts +25 -0
  22. package/dist/entities/native/NativeModifier.js +41 -0
  23. package/dist/entities/native/NativeSettings.d.ts +44 -0
  24. package/dist/entities/native/NativeSettings.js +39 -0
  25. package/dist/entities/native/NativeStyleProperty.d.ts +355 -0
  26. package/dist/entities/native/NativeStyleProperty.js +28 -0
  27. package/dist/entities/native/NativeToken.d.ts +31 -0
  28. package/dist/entities/native/NativeToken.js +49 -0
  29. package/dist/entities/system/CanvasRole.d.ts +34 -0
  30. package/dist/entities/system/CanvasRole.js +45 -0
  31. package/dist/entities/system/Component.d.ts +1287 -0
  32. package/dist/entities/system/Component.js +1840 -0
  33. package/dist/entities/system/Composite.d.ts +12 -0
  34. package/dist/entities/system/Composite.js +26 -0
  35. package/dist/entities/system/Device.d.ts +11 -0
  36. package/dist/entities/system/Device.js +18 -0
  37. package/dist/entities/system/File.d.ts +72 -0
  38. package/dist/entities/system/File.js +136 -0
  39. package/dist/entities/system/Font.d.ts +48 -0
  40. package/dist/entities/system/Font.js +56 -0
  41. package/dist/entities/system/GlobalStyle.d.ts +26 -0
  42. package/dist/entities/system/GlobalStyle.js +54 -0
  43. package/dist/entities/system/Guidance.d.ts +85 -0
  44. package/dist/entities/system/Guidance.js +59 -0
  45. package/dist/entities/system/GuidanceStyle.d.ts +14 -0
  46. package/dist/entities/system/GuidanceStyle.js +8 -0
  47. package/dist/entities/system/Icon.d.ts +46 -0
  48. package/dist/entities/system/Icon.js +46 -0
  49. package/dist/entities/system/LinkedSystem.d.ts +504 -0
  50. package/dist/entities/system/LinkedSystem.js +814 -0
  51. package/dist/entities/system/Modifier.d.ts +92 -0
  52. package/dist/entities/system/Modifier.js +120 -0
  53. package/dist/entities/system/Motion.d.ts +28 -0
  54. package/dist/entities/system/Motion.js +48 -0
  55. package/dist/entities/system/Operation.d.ts +100 -0
  56. package/dist/entities/system/Operation.js +236 -0
  57. package/dist/entities/system/Package.d.ts +42 -0
  58. package/dist/entities/system/Package.js +75 -0
  59. package/dist/entities/system/Settings.d.ts +94 -0
  60. package/dist/entities/system/Settings.js +166 -0
  61. package/dist/entities/system/StyleProperty.d.ts +135 -0
  62. package/dist/entities/system/StyleProperty.js +438 -0
  63. package/dist/entities/system/Token.d.ts +67 -0
  64. package/dist/entities/system/Token.js +129 -0
  65. package/dist/entities/system/Tool.d.ts +134 -0
  66. package/dist/entities/system/Tool.js +124 -0
  67. package/dist/entities/system/color.d.ts +64 -0
  68. package/dist/entities/system/color.js +123 -0
  69. package/dist/entities/system/component-module.d.ts +63 -0
  70. package/dist/entities/system/component-module.js +258 -0
  71. package/dist/entities/system/copy-plan.d.ts +98 -0
  72. package/dist/entities/system/copy-plan.js +451 -0
  73. package/dist/entities/system/defineComponent.d.ts +428 -0
  74. package/dist/entities/system/defineComponent.js +337 -0
  75. package/dist/entities/system/element.d.ts +101 -0
  76. package/dist/entities/system/element.js +171 -0
  77. package/dist/entities/system/icon-library.d.ts +64 -0
  78. package/dist/entities/system/icon-library.js +112 -0
  79. package/dist/entities/system/icon-metadata.d.ts +72 -0
  80. package/dist/entities/system/icon-metadata.js +111 -0
  81. package/dist/entities/system/link-declaration.d.ts +27 -0
  82. package/dist/entities/system/link-declaration.js +64 -0
  83. package/dist/entities/system/link-plan.d.ts +160 -0
  84. package/dist/entities/system/link-plan.js +770 -0
  85. package/dist/entities/system/runtime-modules.d.ts +25 -0
  86. package/dist/entities/system/runtime-modules.js +38 -0
  87. package/dist/entities/system/style-bag.d.ts +20 -0
  88. package/dist/entities/system/style-bag.js +246 -0
  89. package/dist/entities/system/token-index.d.ts +89 -0
  90. package/dist/entities/system/token-index.js +112 -0
  91. package/dist/framework/Config.d.ts +2472 -0
  92. package/dist/framework/Config.js +5023 -0
  93. package/dist/framework/Entity.d.ts +127 -0
  94. package/dist/framework/Entity.js +125 -0
  95. package/dist/framework/authoring.d.ts +24 -0
  96. package/dist/framework/authoring.js +7 -0
  97. package/dist/framework/change-hooks.d.ts +119 -0
  98. package/dist/framework/change-hooks.js +131 -0
  99. package/dist/framework/changes.d.ts +88 -0
  100. package/dist/framework/changes.js +246 -0
  101. package/dist/framework/class-names.d.ts +260 -0
  102. package/dist/framework/class-names.js +630 -0
  103. package/dist/framework/coalesce.d.ts +25 -0
  104. package/dist/framework/coalesce.js +60 -0
  105. package/dist/framework/config-op.d.ts +76 -0
  106. package/dist/framework/config-op.js +43 -0
  107. package/dist/framework/config-operation-kind.d.ts +14 -0
  108. package/dist/framework/config-operation-kind.js +14 -0
  109. package/dist/framework/config-ops.d.ts +34 -0
  110. package/dist/framework/config-ops.js +187 -0
  111. package/dist/framework/defineConfig.d.ts +196 -0
  112. package/dist/framework/defineConfig.js +100 -0
  113. package/dist/framework/defineDerivedEntity.d.ts +74 -0
  114. package/dist/framework/defineDerivedEntity.js +83 -0
  115. package/dist/framework/defineEntity.d.ts +318 -0
  116. package/dist/framework/defineEntity.js +183 -0
  117. package/dist/framework/defineSubEntity.d.ts +148 -0
  118. package/dist/framework/defineSubEntity.js +121 -0
  119. package/dist/framework/derived-mutations.d.ts +20 -0
  120. package/dist/framework/derived-mutations.js +38 -0
  121. package/dist/framework/entity-search.d.ts +29 -0
  122. package/dist/framework/entity-search.js +117 -0
  123. package/dist/framework/inline-sources.d.ts +49 -0
  124. package/dist/framework/inline-sources.js +388 -0
  125. package/dist/framework/layer-styles.d.ts +25 -0
  126. package/dist/framework/layer-styles.js +49 -0
  127. package/dist/framework/memo.d.ts +48 -0
  128. package/dist/framework/memo.js +84 -0
  129. package/dist/framework/overlay.d.ts +49 -0
  130. package/dist/framework/overlay.js +17 -0
  131. package/dist/framework/plan.d.ts +49 -0
  132. package/dist/framework/plan.js +73 -0
  133. package/dist/framework/projections.d.ts +480 -0
  134. package/dist/framework/projections.js +974 -0
  135. package/dist/framework/prop-surface.d.ts +132 -0
  136. package/dist/framework/prop-surface.js +278 -0
  137. package/dist/framework/ref-graph.d.ts +71 -0
  138. package/dist/framework/ref-graph.js +158 -0
  139. package/dist/framework/ref-integrity.d.ts +55 -0
  140. package/dist/framework/ref-integrity.js +171 -0
  141. package/dist/framework/registered.d.ts +95 -0
  142. package/dist/framework/registry-dir.d.ts +42 -0
  143. package/dist/framework/registry-dir.js +48 -0
  144. package/dist/framework/registry.d.ts +300 -0
  145. package/dist/framework/registry.js +104 -0
  146. package/dist/framework/rejection.d.ts +58 -0
  147. package/dist/framework/rejection.js +111 -0
  148. package/dist/framework/rename-inference.d.ts +26 -0
  149. package/dist/framework/rename-inference.js +50 -0
  150. package/dist/framework/render-spec.d.ts +296 -0
  151. package/dist/framework/render-spec.js +809 -0
  152. package/dist/framework/schema-version.d.ts +140 -0
  153. package/dist/framework/schema-version.js +214 -0
  154. package/dist/framework/schemas.d.ts +109 -0
  155. package/dist/framework/schemas.js +615 -0
  156. package/dist/framework/session.d.ts +196 -0
  157. package/dist/framework/session.js +367 -0
  158. package/dist/framework/signature.d.ts +15 -0
  159. package/dist/framework/signature.js +83 -0
  160. package/dist/framework/snapshot.d.ts +115 -0
  161. package/dist/framework/snapshot.js +277 -0
  162. package/dist/framework/source-integrity.d.ts +226 -0
  163. package/dist/framework/source-integrity.js +478 -0
  164. package/dist/framework/sources.d.ts +211 -0
  165. package/dist/framework/sources.js +89 -0
  166. package/dist/framework/utils/compiled-schema.d.ts +23 -0
  167. package/dist/framework/utils/compiled-schema.js +46 -0
  168. package/dist/framework/utils/content-key.d.ts +15 -0
  169. package/dist/framework/utils/content-key.js +33 -0
  170. package/dist/framework/utils/enumerated.d.ts +13 -0
  171. package/dist/framework/utils/enumerated.js +19 -0
  172. package/dist/framework/utils/field-path.d.ts +95 -0
  173. package/dist/framework/utils/field-path.js +136 -0
  174. package/dist/framework/utils/field-schema.d.ts +55 -0
  175. package/dist/framework/utils/field-schema.js +183 -0
  176. package/dist/framework/utils/group.d.ts +37 -0
  177. package/dist/framework/utils/group.js +13 -0
  178. package/dist/framework/utils/package-path.d.ts +37 -0
  179. package/dist/framework/utils/package-path.js +61 -0
  180. package/dist/framework/utils/refs.d.ts +194 -0
  181. package/dist/framework/utils/refs.js +403 -0
  182. package/dist/framework/validate-spec.d.ts +27 -0
  183. package/dist/framework/validate-spec.js +45 -0
  184. package/dist/framework/value-domain.d.ts +26 -0
  185. package/dist/framework/value-domain.js +202 -0
  186. package/dist/framework/views-facade.d.ts +15 -0
  187. package/dist/framework/views-facade.js +19 -0
  188. package/dist/index.d.ts +90 -42
  189. package/dist/index.js +86 -37
  190. package/dist/migrations/2.0.0/raw-css.d.ts +11 -0
  191. package/dist/migrations/2.0.0/raw-css.js +72 -0
  192. package/dist/migrations/2.0.0/v1-artifact.d.ts +1559 -0
  193. package/dist/migrations/2.0.0/v1-artifact.js +1018 -0
  194. package/dist/migrations/20260908171448_settings_as_kind.d.ts +22 -0
  195. package/dist/migrations/20260908171448_settings_as_kind.js +89 -0
  196. package/dist/migrations/20260908194245_visible_state_pointer.d.ts +19 -0
  197. package/dist/migrations/20260908194245_visible_state_pointer.js +115 -0
  198. package/dist/migrations/20260909183001_icon_knockout_variants.d.ts +18 -0
  199. package/dist/migrations/20260909183001_icon_knockout_variants.js +8 -0
  200. package/dist/migrations/20260910212453_linked_system_link_ops.d.ts +13 -0
  201. package/dist/migrations/20260910212453_linked_system_link_ops.js +8 -0
  202. package/dist/migrations/index.d.ts +2 -0
  203. package/dist/migrations/index.js +2 -0
  204. package/dist/react-native/style-keys.generated.d.ts +10 -0
  205. package/dist/react-native/style-keys.generated.js +167 -0
  206. package/dist/renderer/RendererErrorBoundary.d.ts +32 -5
  207. package/dist/renderer/RendererErrorBoundary.js +59 -10
  208. package/dist/renderer/UdsRenderer.d.ts +11 -10
  209. package/dist/renderer/UdsRenderer.js +1 -1
  210. package/dist/renderer/assetEntries.d.ts +37 -0
  211. package/dist/renderer/assetEntries.js +39 -0
  212. package/dist/renderer/assetRenderable.d.ts +14 -6
  213. package/dist/renderer/assetRenderable.js +8 -2
  214. package/dist/renderer/componentEntry.d.ts +58 -0
  215. package/dist/renderer/componentEntry.js +71 -0
  216. package/dist/renderer/icon-library.d.ts +20 -0
  217. package/dist/renderer/index.d.ts +7 -7
  218. package/dist/renderer/index.js +5 -5
  219. package/dist/renderer/primitives/SlotRenderer.d.ts +1 -1
  220. package/dist/renderer/primitives/SlotRenderer.js +1 -1
  221. package/dist/renderer/runtimeComponent.d.ts +33 -0
  222. package/dist/renderer/runtimeComponent.js +113 -0
  223. package/dist/renderer/spec-content.d.ts +43 -0
  224. package/dist/renderer/spec-content.js +95 -0
  225. package/dist/renderer/wrapRegistry.d.ts +22 -37
  226. package/dist/renderer/wrapRegistry.js +10 -20
  227. package/dist/renderer/wrappers/event-bridge.js +6 -5
  228. package/dist/renderer/wrappers/hex-normalize.js +6 -5
  229. package/dist/renderer/wrappers/html-aliases.d.ts +7 -2
  230. package/dist/renderer/wrappers/html-aliases.js +36 -19
  231. package/dist/renderer/wrappers/inline-styles.js +7 -6
  232. package/dist/spec/asset-jsx.d.ts +18 -5
  233. package/dist/spec/asset-jsx.js +27 -16
  234. package/dist/spec/collapse-text-labels.d.ts +5 -15
  235. package/dist/spec/collapse-text-labels.js +26 -19
  236. package/dist/spec/empty-node-slots.d.ts +56 -34
  237. package/dist/spec/empty-node-slots.js +87 -47
  238. package/dist/spec/index.d.ts +21 -10
  239. package/dist/spec/index.js +21 -10
  240. package/dist/spec/jsxToSpec.d.ts +14 -9
  241. package/dist/spec/jsxToSpec.js +20 -3
  242. package/dist/spec/preview-elements.d.ts +63 -0
  243. package/dist/spec/preview-elements.js +89 -0
  244. package/dist/spec/rewrite-refs.d.ts +58 -0
  245. package/dist/spec/rewrite-refs.js +250 -0
  246. package/dist/spec/specToJsx.js +18 -29
  247. package/dist/tsconfig.tsbuildinfo +1 -1
  248. package/package.json +39 -52
  249. package/dist/AssetGroup.d.ts +0 -77
  250. package/dist/AssetGroup.js +0 -125
  251. package/dist/Component.d.ts +0 -333
  252. package/dist/Component.js +0 -1061
  253. package/dist/ComponentGroup.d.ts +0 -22
  254. package/dist/ComponentGroup.js +0 -51
  255. package/dist/CompositeStyle.d.ts +0 -30
  256. package/dist/CompositeStyle.js +0 -59
  257. package/dist/Config.d.ts +0 -528
  258. package/dist/Config.js +0 -1712
  259. package/dist/Mode.d.ts +0 -41
  260. package/dist/Mode.js +0 -81
  261. package/dist/Modifier.d.ts +0 -51
  262. package/dist/Modifier.js +0 -97
  263. package/dist/MotionDef.d.ts +0 -81
  264. package/dist/MotionDef.js +0 -212
  265. package/dist/Props.d.ts +0 -332
  266. package/dist/Props.js +0 -35
  267. package/dist/Provider.d.ts +0 -20
  268. package/dist/Provider.js +0 -14
  269. package/dist/StyleProp.d.ts +0 -145
  270. package/dist/StyleProp.js +0 -239
  271. package/dist/Token.d.ts +0 -76
  272. package/dist/Token.js +0 -133
  273. package/dist/TokenGroup.d.ts +0 -33
  274. package/dist/TokenGroup.js +0 -69
  275. package/dist/asset-kind.d.ts +0 -55
  276. package/dist/asset-kind.js +0 -29
  277. package/dist/asset-value.d.ts +0 -23
  278. package/dist/asset-value.js +0 -40
  279. package/dist/brands.d.ts +0 -30
  280. package/dist/brands.js +0 -20
  281. package/dist/captureCallerPath.d.ts +0 -48
  282. package/dist/captureCallerPath.js +0 -95
  283. package/dist/colorExpressions.d.ts +0 -131
  284. package/dist/colorExpressions.js +0 -148
  285. package/dist/component-referrers.d.ts +0 -30
  286. package/dist/component-referrers.js +0 -40
  287. package/dist/config-diagnostics.d.ts +0 -21
  288. package/dist/config-diagnostics.js +0 -12
  289. package/dist/defineAssetGroup.d.ts +0 -200
  290. package/dist/defineAssetGroup.js +0 -323
  291. package/dist/defineProvider.d.ts +0 -29
  292. package/dist/defineProvider.js +0 -60
  293. package/dist/element-marker.d.ts +0 -63
  294. package/dist/element-marker.js +0 -113
  295. package/dist/entity-utils.d.ts +0 -56
  296. package/dist/entity-utils.js +0 -105
  297. package/dist/extension.d.ts +0 -55
  298. package/dist/extension.js +0 -214
  299. package/dist/factories.d.ts +0 -863
  300. package/dist/factories.js +0 -475
  301. package/dist/font-face.d.ts +0 -25
  302. package/dist/font-face.js +0 -72
  303. package/dist/foreign-component-name.d.ts +0 -21
  304. package/dist/foreign-component-name.js +0 -42
  305. package/dist/interpolate.d.ts +0 -20
  306. package/dist/interpolate.js +0 -10
  307. package/dist/jsx/__fixtures__/cross-component-preview.d.ts +0 -3
  308. package/dist/jsx/__fixtures__/cross-component-preview.js +0 -15
  309. package/dist/jsx/jsx-dev-runtime.d.ts +0 -15
  310. package/dist/jsx/jsx-dev-runtime.js +0 -11
  311. package/dist/jsx/jsx-runtime.d.ts +0 -48
  312. package/dist/jsx/jsx-runtime.js +0 -305
  313. package/dist/linked-system-pins.d.ts +0 -30
  314. package/dist/linked-system-pins.js +0 -45
  315. package/dist/linkedNodePrefixes.d.ts +0 -73
  316. package/dist/linkedNodePrefixes.js +0 -99
  317. package/dist/markers.d.ts +0 -235
  318. package/dist/markers.js +0 -70
  319. package/dist/motion-constants.d.ts +0 -37
  320. package/dist/motion-constants.js +0 -61
  321. package/dist/native/NativeConfig.d.ts +0 -56
  322. package/dist/native/NativeConfig.js +0 -162
  323. package/dist/native/assets.d.ts +0 -20
  324. package/dist/native/assets.js +0 -17
  325. package/dist/native/components.d.ts +0 -139
  326. package/dist/native/components.js +0 -67
  327. package/dist/native/index.d.ts +0 -18
  328. package/dist/native/index.js +0 -17
  329. package/dist/native/modes.d.ts +0 -10
  330. package/dist/native/modes.js +0 -11
  331. package/dist/native/types.d.ts +0 -95
  332. package/dist/native/types.js +0 -0
  333. package/dist/native/validation.d.ts +0 -8
  334. package/dist/native/validation.js +0 -885
  335. package/dist/native/values.d.ts +0 -7
  336. package/dist/native/values.js +0 -15
  337. package/dist/native.d.ts +0 -12
  338. package/dist/native.js +0 -10
  339. package/dist/refs.d.ts +0 -204
  340. package/dist/refs.js +0 -129
  341. package/dist/registry-aliases.d.ts +0 -33
  342. package/dist/registry-aliases.js +0 -35
  343. package/dist/registry-dir.d.ts +0 -22
  344. package/dist/registry-dir.js +0 -10
  345. package/dist/renderer/makeRegistry.d.ts +0 -34
  346. package/dist/renderer/makeRegistry.js +0 -52
  347. package/dist/renderer/makeUdsRenderer.d.ts +0 -13
  348. package/dist/renderer/makeUdsRenderer.js +0 -51
  349. package/dist/renderer/wrappers/component-slots.d.ts +0 -41
  350. package/dist/renderer/wrappers/component-slots.js +0 -66
  351. package/dist/renderer/wrappers/slot-resolution.d.ts +0 -25
  352. package/dist/renderer/wrappers/slot-resolution.js +0 -68
  353. package/dist/renderer/wrappers/void-elements.d.ts +0 -37
  354. package/dist/renderer/wrappers/void-elements.js +0 -40
  355. package/dist/spec/layer-props.d.ts +0 -52
  356. package/dist/spec/layer-props.js +0 -149
  357. package/dist/spec/preview-controls.d.ts +0 -44
  358. package/dist/spec/preview-controls.js +0 -139
  359. package/dist/spec/slot-refs.d.ts +0 -39
  360. package/dist/spec/slot-refs.js +0 -56
  361. package/dist/token-override-rows.d.ts +0 -68
  362. package/dist/token-override-rows.js +0 -233
  363. package/dist/tokenValueType.d.ts +0 -34
  364. package/dist/tokenValueType.js +0 -138
  365. package/dist/types/css-properties.d.ts +0 -233
  366. package/dist/types/css-properties.js +0 -14
  367. package/dist/types/css-property-keywords.d.ts +0 -156
  368. package/dist/types/css-property-keywords.js +0 -616
  369. package/dist/types/css-values.d.ts +0 -63
  370. package/dist/types/css-values.js +0 -16
  371. package/dist/types.d.ts +0 -1138
  372. package/dist/types.js +0 -12
  373. package/dist/units.d.ts +0 -14
  374. package/dist/units.js +0 -16
  375. package/dist/utils/index.d.ts +0 -4
  376. package/dist/utils/index.js +0 -4
@@ -0,0 +1,60 @@
1
+ //#region src/framework/coalesce.ts
2
+ /**
3
+ * Run an expensive side effect for the LAST value of a burst, never for the ones it superseded.
4
+ *
5
+ * Here rather than in the app because coalescing is not a property of any one derivation: one user
6
+ * gesture reaches a config holder several times — an edit lands optimistically, comes back as a
7
+ * realtime echo, then again as the pull that trues up against what the server persisted. Each landing
8
+ * describes the same edit, so a subscriber that recomputes per landing pays for two results nobody
9
+ * ever sees, on the frames the gesture is trying to respond on. That is true of every `onChange`
10
+ * point, so {@link runChangeHooks} owns it and a hook never writes it again.
11
+ *
12
+ * Leading-edge, not a trailing debounce: the first value is handed to `schedule` right away, so a
13
+ * continuous gesture (a drag that writes per tick) keeps painting instead of going dark until it
14
+ * stops. What coalesces is everything that arrives while a run is scheduled or in flight — those
15
+ * collapse into ONE follow-up run carrying the newest value.
16
+ *
17
+ * `run` may be async; a value arriving mid-run waits for it rather than overlapping, which is what
18
+ * keeps an older result from landing after a newer one.
19
+ */
20
+ function coalesceLatest({ run, schedule }) {
21
+ let pending;
22
+ let hasPending = false;
23
+ let scheduled = false;
24
+ let running = false;
25
+ const fire = () => {
26
+ scheduled = false;
27
+ if (!hasPending || running) return;
28
+ const value = pending;
29
+ pending = void 0;
30
+ hasPending = false;
31
+ running = true;
32
+ const done = () => {
33
+ running = false;
34
+ if (hasPending) request(pending);
35
+ };
36
+ let result;
37
+ try {
38
+ result = run(value);
39
+ } catch {
40
+ done();
41
+ return;
42
+ }
43
+ if (result instanceof Promise) result.then(done, done);
44
+ else done();
45
+ };
46
+ const request = (value) => {
47
+ pending = value;
48
+ hasPending = true;
49
+ if (scheduled || running) return;
50
+ scheduled = true;
51
+ schedule(fire);
52
+ };
53
+ request.cancel = () => {
54
+ pending = void 0;
55
+ hasPending = false;
56
+ };
57
+ return request;
58
+ }
59
+ //#endregion
60
+ export { coalesceLatest };
@@ -0,0 +1,76 @@
1
+ //#region src/framework/config-op.d.ts
2
+ /**
3
+ * The address grammar — three spellings, one rule, written here once so `kind/verb`, `group/item` and
4
+ * `kind:path` are not read for one another. Other docblocks point here rather than restate a piece.
5
+ *
6
+ * | Spelling | What it is | Example |
7
+ * | ----------------------------- | -------------------- | ------------------------------------------------ |
8
+ * | `kind/verb` | an operation address | `token/create`, `component/sub-update/props` |
9
+ * | `group/item` | an entity path | `spacing/0`, `icons/Trophy` |
10
+ * | `kind:path[@source][#member]` | a ref to an entity | `token:spacing/0`, `component:actions/Button@ds` |
11
+ *
12
+ * A slash after a KIND opens an operation; a slash after a GROUP walks an entity path; a colon always
13
+ * introduces a ref, and everything after it is the ref's qualified path. So a bare `token` is a kind
14
+ * and its slash is a verb, `spacing` is a group and its slash is a path, and any `:` means a ref
15
+ * follows — the leftmost token and the colon are what tell the three apart.
16
+ *
17
+ * `addressOf` builds the operation address; {@link splitRef} in `utils/refs.ts` reads a ref. An
18
+ * operation carries an entity `path` (the second spelling) in its input, never a ref-marked one.
19
+ */
20
+ /**
21
+ * One operation, addressed the way a patch is.
22
+ *
23
+ * `kind` and `operation` name what runs; `field` names the member collection when the operation acts on
24
+ * one (`sub-update` of `props`); everything else is the operation's input, flat beside them. `run`,
25
+ * `run` and `plan` take this shape, the read and edit tools carry it, and a patch in a draft is one
26
+ * of these with its `path` spelled. The catalog addresses the same operation as `<kind>/<verb>`, where
27
+ * the verb is `operation` with `/field` appended; that string is a tool's name and the key an op is
28
+ * described under, and {@link addressOf} builds it.
29
+ */
30
+ interface ConfigOp {
31
+ readonly kind: string;
32
+ readonly operation: string;
33
+ readonly field?: string;
34
+ readonly [input: string]: unknown;
35
+ }
36
+ /**
37
+ * An op with the id its first patch lands under.
38
+ *
39
+ * Every patch a config records carries an id, and `run` mints one when nobody names it. `id` is for the
40
+ * caller that has to name it: a surface that paints an edit before the round trip stages a draft row
41
+ * under an id of its own, and the patch the commit writes has to carry that same id, or the staged row
42
+ * is never acknowledged and its undo step names a patch that does not exist. A custom op writes several
43
+ * patches; the first takes the id, and it is the changeset's too, so what was staged, what a list groups
44
+ * under and what undo drops are one identifier. It rides beside the op rather than on it, since every
45
+ * key on an op is its input.
46
+ */
47
+ interface IdentifiedOp {
48
+ readonly op: ConfigOp;
49
+ readonly id?: string;
50
+ }
51
+ /** What `run` takes as a list and what an edit surface hands around: an op, or one with its id named. */
52
+ type ConfigEdit = ConfigOp | IdentifiedOp;
53
+ /** The op an edit carries, and the id it should land under when the caller named one. */
54
+ declare function editOp(edit: ConfigEdit): {
55
+ readonly op: ConfigOp;
56
+ readonly id?: string;
57
+ };
58
+ /** The verb the catalog keys an op under: `sub-update/props`, or the bare operation. */
59
+ declare function opVerb(op: Pick<ConfigOp, 'operation' | 'field'>): string;
60
+ /** The catalog address: `component/sub-update/props`. */
61
+ declare function addressOf(op: Pick<ConfigOp, 'kind' | 'operation' | 'field'>): string;
62
+ /** The op's input: everything but its address. */
63
+ declare function inputOf(op: ConfigOp): Record<string, unknown>;
64
+ /** An op from its catalog address halves, for a caller holding `kind` and `verb` apart. A verb splits
65
+ * at its first slash: a nested collection's field keeps the rest (`sub-update/props/value`). */
66
+ declare function opOf({
67
+ kind,
68
+ verb,
69
+ input
70
+ }: {
71
+ kind: string;
72
+ verb: string;
73
+ input?: Record<string, unknown>;
74
+ }): ConfigOp;
75
+ //#endregion
76
+ export { ConfigEdit, ConfigOp, IdentifiedOp, addressOf, editOp, inputOf, opOf, opVerb };
@@ -0,0 +1,43 @@
1
+ //#region src/framework/config-op.ts
2
+ /** The op an edit carries, and the id it should land under when the caller named one. */
3
+ function editOp(edit) {
4
+ if ("op" in edit && typeof edit.op === "object" && edit.op !== null) {
5
+ const { op, id } = edit;
6
+ return {
7
+ op,
8
+ id
9
+ };
10
+ }
11
+ return { op: edit };
12
+ }
13
+ /** The verb the catalog keys an op under: `sub-update/props`, or the bare operation. */
14
+ function opVerb(op) {
15
+ return op.field === void 0 ? op.operation : `${op.operation}/${op.field}`;
16
+ }
17
+ /** The catalog address: `component/sub-update/props`. */
18
+ function addressOf(op) {
19
+ return `${op.kind}/${opVerb(op)}`;
20
+ }
21
+ /** The op's input: everything but its address. */
22
+ function inputOf(op) {
23
+ const { kind: _kind, operation: _operation, field: _field, ...input } = op;
24
+ return input;
25
+ }
26
+ /** An op from its catalog address halves, for a caller holding `kind` and `verb` apart. A verb splits
27
+ * at its first slash: a nested collection's field keeps the rest (`sub-update/props/value`). */
28
+ function opOf({ kind, verb, input = {} }) {
29
+ const slash = verb.indexOf("/");
30
+ if (slash === -1) return {
31
+ ...input,
32
+ kind,
33
+ operation: verb
34
+ };
35
+ return {
36
+ ...input,
37
+ kind,
38
+ operation: verb.slice(0, slash),
39
+ field: verb.slice(slash + 1)
40
+ };
41
+ }
42
+ //#endregion
43
+ export { addressOf, editOp, inputOf, opOf, opVerb };
@@ -0,0 +1,14 @@
1
+ //#region src/framework/config-operation-kind.d.ts
2
+ /**
3
+ * The kind segment of the config's own operations: `config/info`, `config/api`.
4
+ *
5
+ * An operation address is `<kind>/<verb>` (the address grammar is written whole in `config-op.ts`). The
6
+ * config's own operations address no entity, so they need a segment that is not a kind, and it is this
7
+ * fixed word rather than the config type's name: an address a model sends should not depend on whether
8
+ * the type is called `system-config`,
9
+ * `design-file` or `react-native-system`. No entity kind may take the word, which `defineEntity`
10
+ * refuses.
11
+ */
12
+ declare const CONFIG_OPERATION_KIND = "config";
13
+ //#endregion
14
+ export { CONFIG_OPERATION_KIND };
@@ -0,0 +1,14 @@
1
+ //#region src/framework/config-operation-kind.ts
2
+ /**
3
+ * The kind segment of the config's own operations: `config/info`, `config/api`.
4
+ *
5
+ * An operation address is `<kind>/<verb>` (the address grammar is written whole in `config-op.ts`). The
6
+ * config's own operations address no entity, so they need a segment that is not a kind, and it is this
7
+ * fixed word rather than the config type's name: an address a model sends should not depend on whether
8
+ * the type is called `system-config`,
9
+ * `design-file` or `react-native-system`. No entity kind may take the word, which `defineEntity`
10
+ * refuses.
11
+ */
12
+ const CONFIG_OPERATION_KIND = "config";
13
+ //#endregion
14
+ export { CONFIG_OPERATION_KIND };
@@ -0,0 +1,34 @@
1
+ import { Config } from "./Config.js";
2
+
3
+ //#region src/framework/config-ops.d.ts
4
+ /**
5
+ * One kind's authoring shape as one-line signatures — what a prompt carries for every kind, and what
6
+ * `api` answers unless one kind's full JSON Schema is asked for.
7
+ */
8
+ interface KindSignature {
9
+ readonly kind: string;
10
+ readonly label: string;
11
+ /** The entity a consumer imports to write a ref to this kind — `Token.ref('color/brand')`. */
12
+ readonly refHelper: string;
13
+ /** What `create` takes as `data`. */
14
+ readonly create?: string;
15
+ /** Each sub-entity collection with what its `sub-create` takes as `data`. */
16
+ readonly collections: Record<string, string>;
17
+ /** The group node's own fields, when the kind carries any. */
18
+ readonly group?: string;
19
+ /** A real entry from this config, in stored form. */
20
+ readonly example?: unknown;
21
+ }
22
+ interface AuthoringSignatureOptions {
23
+ /** Object nesting shown for a kind's own create shape. */
24
+ readonly depth?: number;
25
+ /** Object nesting shown for a sub-entity member's shape; a prompt lists many, so it collapses sooner. */
26
+ readonly memberDepth?: number;
27
+ }
28
+ /** Every owned kind's authoring shape as signatures, with a real example where the config has one. */
29
+ declare function authoringSignatures(config: Config, {
30
+ depth,
31
+ memberDepth
32
+ }?: AuthoringSignatureOptions): KindSignature[];
33
+ //#endregion
34
+ export { AuthoringSignatureOptions, KindSignature, authoringSignatures };
@@ -0,0 +1,187 @@
1
+ import { ref } from "./utils/refs.js";
2
+ import { METADATA_KEYS } from "./utils/field-schema.js";
3
+ import { resolveSchema } from "./schemas.js";
4
+ import { renderSignature } from "./signature.js";
5
+ import { z } from "zod";
6
+ //#region src/framework/config-ops.ts
7
+ /**
8
+ * The operations a CONFIG exposes about itself, rather than about one of its kinds — a summary of what
9
+ * the system contains, and the authoring reference for changing it.
10
+ *
11
+ * Every config gets both, automatically, because both are pure functions of the entities it declares.
12
+ * The old surface hand-wrote them (`uds_info`, `uds_config_api`) against a fixed idea of what a system
13
+ * holds, so a new kind was invisible to them until someone remembered to edit the tool. Here a kind
14
+ * appears in both the moment it's registered.
15
+ *
16
+ * `api` is the interesting one. The old version was largely static prose explaining a different factory
17
+ * API per concept — `defineComponent(...).config().render().preview()`, `token()`, `styleProperty()` — which
18
+ * is exactly the surface config-v2 doesn't have: authoring is uniform data, so the reference is the
19
+ * entity's own field schema plus a real example from the config. What can't be derived is prose about
20
+ * INTENT, and there's far less of it to write when every kind is authored the same way.
21
+ */
22
+ /** A ref as a model writes it, spelled from the ref itself so the prose can't drift from the shape. */
23
+ const spell = (kind, path) => JSON.stringify(ref(kind, path));
24
+ /** JSON Schema for a zod schema, or `undefined` when it can't be represented. A reference that omits
25
+ * one field beats one that throws.
26
+ *
27
+ * Read from the INPUT side, since this documents what an author WRITES — and because a schema that
28
+ * coerces (a style rule's condition stores a ref for the bare value it takes) has no output shape
29
+ * to represent, so the whole collection silently fell into the `catch` above. */
30
+ function jsonSchema(schema) {
31
+ if (schema === void 0) return void 0;
32
+ try {
33
+ return z.toJSONSchema(schema, { io: "input" });
34
+ } catch {
35
+ return;
36
+ }
37
+ }
38
+ /**
39
+ * The AUTHORING shape behind an op — the `data` half of its `{ path, data }` input.
40
+ *
41
+ * Read off the op rather than from a stored `fields` schema, because the op's `data` is the schema
42
+ * that actually validates an authored entry: a kind that narrows its `create` (a `{ data }` override)
43
+ * is documented as it really behaves, not as its raw fields would suggest.
44
+ */
45
+ function dataSchemaOf(config, entry) {
46
+ if (!entry) return void 0;
47
+ const resolved = resolveSchema(entry.input, { config });
48
+ if (!(resolved instanceof z.ZodObject)) return void 0;
49
+ return resolved.shape.data;
50
+ }
51
+ /** The universal metadata every body may carry (`label`, `description`, `copiedFrom`) dropped from an
52
+ * object schema, or from each member of a union, so a kind's signature shows the kind's own fields. */
53
+ function withoutMetadata(node) {
54
+ if (!node || typeof node !== "object") return node;
55
+ const record = node;
56
+ if (Array.isArray(record.anyOf)) return {
57
+ ...record,
58
+ anyOf: record.anyOf.map(withoutMetadata)
59
+ };
60
+ if (Array.isArray(record.oneOf)) return {
61
+ ...record,
62
+ oneOf: record.oneOf.map(withoutMetadata)
63
+ };
64
+ if (record.properties && typeof record.properties === "object") {
65
+ const properties = { ...record.properties };
66
+ for (const key of METADATA_KEYS) delete properties[key];
67
+ return {
68
+ ...record,
69
+ properties
70
+ };
71
+ }
72
+ return node;
73
+ }
74
+ function authoringSignature(schema, options) {
75
+ const json = jsonSchema(schema);
76
+ return json === void 0 ? void 0 : renderSignature(withoutMetadata(json), options);
77
+ }
78
+ /** Every owned kind's authoring shape as signatures, with a real example where the config has one. */
79
+ function authoringSignatures(config, { depth, memberDepth = depth } = {}) {
80
+ return config.ownedKinds().flatMap((kind) => {
81
+ const entity = config.entityOf(kind);
82
+ if (!entity) return [];
83
+ const collections = {};
84
+ for (const [field, sub] of Object.entries(entity.subEntities)) {
85
+ const singleton = sub.singleton === true;
86
+ const signature = authoringSignature(dataSchemaOf(config, entity.schemas[`${singleton ? "sub-update" : "sub-create"}/${field}`]), { depth: memberDepth });
87
+ if (signature) collections[field] = singleton ? `one section, no key (\`sub-update/${field}\`): ${signature}` : signature;
88
+ }
89
+ const first = config.list(kind)[0];
90
+ return [{
91
+ kind,
92
+ label: entity.label,
93
+ refHelper: entity.entityName,
94
+ create: authoringSignature(dataSchemaOf(config, entity.schemas.create), { depth }),
95
+ collections,
96
+ group: authoringSignature(entity.groupCreateSchema, { depth }),
97
+ example: first ? { [first.path]: first.toJSON() } : void 0
98
+ }];
99
+ });
100
+ }
101
+ /** What the system CONTAINS — per kind, how many entries and groups, with a sample of paths. Generic
102
+ * over `ownedKinds`, so a newly registered kind is summarized without touching this. */
103
+ function summarize(config) {
104
+ const kinds = config.ownedKinds().map((kind) => {
105
+ const items = config.list(kind);
106
+ const groups = config.groups(kind);
107
+ return {
108
+ kind,
109
+ label: config.entityLabelPlural(kind),
110
+ count: items.length,
111
+ groups: groups.map((group) => group.path),
112
+ paths: items.slice(0, 12).map((item) => item.path),
113
+ truncated: items.length > 12
114
+ };
115
+ });
116
+ return {
117
+ name: config.name,
118
+ description: config.description,
119
+ kinds: kinds.filter((entry) => entry.count > 0 || entry.groups.length > 0),
120
+ empty: kinds.filter((entry) => entry.count === 0 && entry.groups.length === 0).map((entry) => entry.kind)
121
+ };
122
+ }
123
+ /** How to AUTHOR this config — one entry per kind, derived from the entity's own schemas. */
124
+ function authoringReference(config) {
125
+ return { kinds: config.ownedKinds().flatMap((kind) => {
126
+ const entity = config.entityOf(kind);
127
+ if (!entity) return [];
128
+ const collections = {};
129
+ for (const [field, sub] of Object.entries(entity.subEntities)) {
130
+ if (sub.singleton === true) {
131
+ collections[field] = {
132
+ singleton: true,
133
+ fields: jsonSchema(dataSchemaOf(config, entity.schemas[`sub-update/${field}`]))
134
+ };
135
+ continue;
136
+ }
137
+ collections[field] = jsonSchema(dataSchemaOf(config, entity.schemas[`sub-create/${field}`]));
138
+ }
139
+ const first = config.list(kind)[0];
140
+ return [{
141
+ kind,
142
+ label: entity.label,
143
+ refHelper: entity.entityName,
144
+ fields: jsonSchema(dataSchemaOf(config, entity.schemas.create)),
145
+ collections,
146
+ groupFields: jsonSchema(entity.groupCreateSchema),
147
+ example: first ? { [first.path]: first.toJSON() } : void 0
148
+ }];
149
+ }) };
150
+ }
151
+ /**
152
+ * The config-scoped op table. Mirrors `defaultSchemas`' entry shape so these flow through `Operation`,
153
+ * `Tool` and every consumer with no special case — the only difference is `scope: 'config'`, which tells
154
+ * a tool name to leave out an entity segment it doesn't have.
155
+ */
156
+ function configSchemas(configName) {
157
+ return {
158
+ info: {
159
+ input: z.object({}),
160
+ readOnly: true,
161
+ label: "Info",
162
+ description: `What the ${configName} contains — what this kind of config is and how one is built, then every kind with its entry count, its groups, and a sample of paths. Call this first to orient; follow up with a kind's \`list\`/\`get\` for detail.`,
163
+ scope: "config",
164
+ title: () => `${configName} overview`,
165
+ handler: (_input, config) => summarize(config)
166
+ },
167
+ api: {
168
+ input: z.object({ data: z.object({ kind: z.string().optional().describe("Scope the reference to one kind; omit for every kind.") }).optional() }),
169
+ readOnly: true,
170
+ label: "Authoring API",
171
+ description: `How to AUTHOR this ${configName} — every kind's create shape as a one-line signature, its sub-entity collections, the helper that writes a ref to it, and a real example from this config, in one read. Pass \`data.kind\` for one kind's full JSON Schema instead. Use \`info\` to see what the system already contains.`,
172
+ scope: "config",
173
+ title: () => `${configName} authoring API`,
174
+ handler: (input, config) => {
175
+ const only = input.data?.kind;
176
+ if (typeof only === "string") return { kinds: authoringReference(config).kinds.filter((entry) => entry.kind === only) };
177
+ return {
178
+ ref: `A ref is written \`${spell("<kind>", "<path>")}\`, so a token is \`${spell("token", "<group>/<name>")}\`. A ref to a group (\`${spell("token", "<group>")}\`) names every member.`,
179
+ order: `Each layer is built from the one before it, by ref, so author in this order: tokens in groups (\`<group>/<name>\`); style properties whose \`values\` is the group ref (\`${spell("token", "<group>")}\`), named as the camelCase JSX prop they become; primitives — components whose layers are tags — exposing those style properties as props and a \`children\` slot where they hold content; then components whose layers are refs to the primitives (\`${spell("component", "<primitive>")}\`), styled through the primitives' props.`,
180
+ kinds: authoringSignatures(config)
181
+ };
182
+ }
183
+ }
184
+ };
185
+ }
186
+ //#endregion
187
+ export { authoringSignatures, configSchemas };
@@ -0,0 +1,196 @@
1
+ import { Ref } from "./utils/refs.js";
2
+ import { CreateInput, FieldsSchema } from "./utils/field-schema.js";
3
+ import { DerivedEntityClass } from "./defineDerivedEntity.js";
4
+ import { AuthoredEntry } from "./utils/group.js";
5
+ import { EntityClass } from "./defineEntity.js";
6
+ import { Config, HydrationOptions, ListOptions, StoredConfig, TreeNode } from "./Config.js";
7
+ import { z } from "zod";
8
+
9
+ //#region src/framework/defineConfig.d.ts
10
+ type AnyEntityClass = EntityClass<any, any, string, any, any, boolean> | DerivedEntityClass<any, any>;
11
+ /** A named map of entity classes — the shape of `entities` / `derivedEntities`. */
12
+ type EntityMap = Record<string, AnyEntityClass>;
13
+ /** One entity class's kind, as the literal it declared. Distributive on purpose, so a UNION of
14
+ * classes yields the union of their kinds. */
15
+ type KindOfEntity<E> = E extends {
16
+ readonly kind: infer K extends string;
17
+ } ? K : never;
18
+ /**
19
+ * The kinds a config TYPE owns, as a union of literals — `ConfigKind<typeof System>` is
20
+ * `'token' | 'component' | 'modifier' | …`.
21
+ *
22
+ * Every entity carries its kind as a literal (so a ref can narrow), and a config type keeps its
23
+ * `entities` map's exact types. So this union is already in the types, and anything that has to NAME
24
+ * kinds can be checked against what the config actually declares instead of spelling strings the
25
+ * compiler never sees. A memo's `kinds`, a change hook's `watches`: declared as
26
+ * `readonly ConfigKind<typeof System>[]`, a typo or a kind that was renamed out from under it stops
27
+ * compiling — where a `string[]` just silently under-declares, which is the failure that serves a
28
+ * stale result rather than throwing.
29
+ *
30
+ * OWNED kinds only. A SOURCE's data lives in its own config and is reached by a qualified ref (see
31
+ * `memo.ts`), and a derived kind is computed rather than read.
32
+ */
33
+ type ConfigKind<C> = C extends {
34
+ readonly entities: infer M;
35
+ } ? KindOfEntity<M[keyof M]> : never;
36
+ /**
37
+ * One entity's authored body as a partial at every depth — what a caller writing a delta against an
38
+ * entity of that kind may say.
39
+ *
40
+ * A ref is a leaf. `{ __ref: string }` partialized to `{ __ref?: string }` would accept `{}` as a ref,
41
+ * which is the one shape nothing downstream can resolve. An array is a leaf too: a partial of its
42
+ * elements describes no gesture anyone makes, and a caller replacing one writes the whole list.
43
+ */
44
+ type PartialBodyOf<E> = E extends EntityClass<infer F extends FieldsSchema, FieldsSchema> ? DeepPartial<CreateInput<F>> : never;
45
+ /** Optional at every depth, stopping at refs, arrays and primitives. */
46
+ type DeepPartial<T> = T extends Ref | readonly unknown[] ? T : T extends object ? { [K in keyof T]?: DeepPartial<T[K]> } : T;
47
+ /**
48
+ * The kinds one or more config types own, as VALUES — the runtime half of {@link ConfigKind}.
49
+ *
50
+ * For the declaration whose honest content is "all of them": a section of the stylesheet whose reach
51
+ * is the whole config, a scan with no smaller answer. Written out as a literal that list is a copy of
52
+ * the config type, and a copy silently stops being every kind the day a kind is added — the new one
53
+ * is simply absent, and whatever keyed on the list serves a stale answer for exactly the edits that
54
+ * touch it. Derived, it cannot be short.
55
+ *
56
+ * Variadic because a declaration can span platforms: a web system and a native one are different
57
+ * config types, and an emitter asked to describe both wants the union.
58
+ */
59
+ declare function kindsOf<T extends readonly {
60
+ readonly entities: EntityMap;
61
+ }[]>(...configTypes: T): readonly ConfigKind<T[number]>[];
62
+ /** What `register` accepts for one owned entity: an items record keyed by path segment, or for a
63
+ * singleton kind the one item's body itself — `register({ settings: { css: { prefix: 'acme' } } })`.
64
+ * A singleton has no path level to key by, so a record of paths would be a spelling with nothing to
65
+ * mean. */
66
+ type RecordFor<E> = E extends {
67
+ readonly singleton: true;
68
+ } ? E extends EntityClass<infer F, FieldsSchema, string, any, any, true> ? Partial<z.input<F>> : never : E extends EntityClass<infer F, infer G> ? Record<string, AuthoredEntry<F, G>> : never;
69
+ /**
70
+ * What a config DRAWS ON — keyed by the accessor name of the kind whose items ARE the sources, valued
71
+ * by a thunk yielding the config type each one resolves to.
72
+ *
73
+ * ```ts
74
+ * sources: { linkedSystems: () => System }
75
+ * ```
76
+ *
77
+ * One word for one thing: the declaration here, `Config.registerSources`, `Config.load`'s resolvers,
78
+ * `fromJSON`'s attachments and the `sources` key `toJSON` writes all spell it the same way, and all
79
+ * key it by the same accessor name `register` uses.
80
+ *
81
+ * Keyed by the KIND rather than by a slug, because the slugs are that kind's item paths:
82
+ * `linkedSystems: { yos: …, ds: … }` declares the slugs `yos` and `ds` that a ref qualifies with. So
83
+ * the declaration says which collection those names come from, and cardinality follows from the data —
84
+ * a system editor has n items, a design file has 1, same kind and same reader.
85
+ *
86
+ * A THUNK because of self-reference: `sources: { linkedSystems: System }` sits inside the call that
87
+ * produces `System`, where the binding is not initialised yet.
88
+ *
89
+ * **TYPING ONLY, and deliberately so.** What it buys is that a resolver is handed that kind's own
90
+ * entity and that an attached source is typed as the config type named here. It is NOT a constraint on
91
+ * what may be attached: nothing checks a source's artifact against this, and adding that check would
92
+ * break the case the design is for.
93
+ *
94
+ * That case is a native system drawing on a web one. `ReactNativeSystem` names itself here, so a `System`
95
+ * source is a declared mismatch — and it is legal, because the type named here is not who may answer,
96
+ * only who is assumed to. The real check is PER ENTITY and one layer down: `Config.resolveExtension`
97
+ * parses a borrowed body through the BORROWING config's kind, so a native config accepts a web token it
98
+ * can represent (`1rem` replaced by `16` in the local delta) and refuses one it cannot. A type-level
99
+ * refusal at attach would reject the whole source and never reach that. Asserted both ways in
100
+ * `Config.test.ts` — "the consumer kind validates the merged result".
101
+ *
102
+ * The declaration is not load-bearing at record time either — an artifact names its own type, so the
103
+ * framework can ask an attached source what it contributes rather than trusting this.
104
+ */
105
+ type SourceMap<Owned extends EntityMap> = { readonly [K in keyof Owned]?: () => unknown };
106
+ /** The source map a config type declares — for a caller naming the resolver set it must supply. */
107
+ type SourcesOf<C> = C extends {
108
+ readonly sources: infer D;
109
+ } ? D : Record<never, never>;
110
+ /** `register` arg — partial, keyed by owned accessor name; a key not in `entities` is a type error. */
111
+ type OwnedRecords<Owned extends EntityMap> = { [K in keyof Owned]?: RecordFor<Owned[K]> };
112
+ /** A read-capable window onto a kind's items in a config — the value an accessor (`system.components`)
113
+ * returns, branded by the entity CLASS type so a wrong-kind one fails to type.
114
+ *
115
+ * A read accessor and nothing more. It used to double as the handle another config borrowed a whole
116
+ * KIND through; a config draws on another by declaring a `source`, and a ref carries which source it
117
+ * points into. */
118
+ interface Collection<E extends AnyEntityClass> {
119
+ /** Phantom brand — makes `Collection<Token>` and `Collection<Component>` distinct types. */
120
+ readonly __for: E;
121
+ list(opts?: ListOptions): ReturnType<E['list']>;
122
+ get(pathOrRef: string | Ref): ReturnType<E['get']>;
123
+ dependents(path: string): string[];
124
+ tree(): TreeNode[];
125
+ }
126
+ /**
127
+ * A typed instance — `Config` plus the typed `register` and a `Collection` accessor per owned / derived
128
+ * name.
129
+ *
130
+ * The typed members come first in the intersection. Were `Config` ever to declare a member of the same
131
+ * name, the two would form an overload set that TypeScript resolves by intersection position, and an
132
+ * editor would complete against the untyped one; `config-instance-completions.test.ts` asks the
133
+ * language service what it offers inside `register({ settings: { build: { … } } })` for that reason.
134
+ *
135
+ * `Config` stays IN the intersection rather than being `Omit`ed from it. `Omit` on a class type drops
136
+ * the nominal brand its private members carry, so a `ConfigInstance` would stop being assignable to
137
+ * `Config` — and nearly every reader in the codebase takes a `Config`.
138
+ */
139
+ type ConfigInstance<Owned extends EntityMap, Derived extends EntityMap> = {
140
+ register(records: OwnedRecords<Owned>): ConfigInstance<Owned, Derived>;
141
+ } & Config & { [K in keyof Owned]: Collection<Owned[K]> } & { [K in keyof Derived]: Collection<Derived[K]> };
142
+ /**
143
+ * What `defineConfig` returns — a constructor plus a typed static `fromJSON`.
144
+ *
145
+ * Sources are always OPTIONAL. A config whose sources are unresolved is a legitimate config to
146
+ * read — its borrowed values simply do not resolve — which is what `Config.load` exists to make
147
+ * deliberate rather than accidental.
148
+ */
149
+ interface ConfigClass<Owned extends EntityMap, Derived extends EntityMap, Sources extends SourceMap<Owned> = Record<never, never>> {
150
+ new (): ConfigInstance<Owned, Derived>;
151
+ fromJSON(json: StoredConfig, options?: HydrationOptions): ConfigInstance<Owned, Derived>;
152
+ readonly configName: string;
153
+ readonly entities: Owned;
154
+ readonly derivedEntities: Derived;
155
+ /** What this type DRAWS ON — see {@link SourceMap}. Empty for a config that draws on nothing. */
156
+ readonly sources: Sources;
157
+ /**
158
+ * Extend this config type — the same config with some kinds swapped for their extensions
159
+ * (`System.extend({ tools: CliTool })`). What differs between two consumers is which entity answers
160
+ * for a kind, so that difference is a config type rather than a flag: a flag can't change what an
161
+ * entity derives or validates.
162
+ *
163
+ * Keeps the base's NAME, because it IS the same system — tool names (`uds_<name>_…`) and the wire
164
+ * `name` are unchanged, so a model calls the same tools either way. It therefore does NOT take over
165
+ * the untyped `Config.fromJSON` dispatch slot: construct the extension directly, or use its own
166
+ * `fromJSON`. (Nothing is lost — a swapped DERIVED kind never serializes, so the wire form is
167
+ * identical.)
168
+ */
169
+ extend(swaps: Partial<Record<keyof Owned | keyof Derived, unknown>>): ConfigClass<Owned, Derived, Sources>;
170
+ }
171
+ declare function defineConfig<Owned extends EntityMap, Derived extends EntityMap = Record<never, never>, Sources extends SourceMap<Owned> = Record<never, never>>(spec: {
172
+ name: string;
173
+ /**
174
+ * What this config type holds and how one is authored, for a reader arriving cold — an agent
175
+ * orienting before its first edit. Prose about intent, which nothing derives: the kinds say what
176
+ * can be written, this says what to write first and what to build from it.
177
+ */
178
+ description?: string;
179
+ entities: Owned;
180
+ derivedEntities?: Derived;
181
+ /**
182
+ * The kinds whose items are this config's sources, each naming the config type it resolves to — see
183
+ * {@link SourceMap}.
184
+ *
185
+ * Every key must name an OWNED kind that declares `sourceIdentity`, which is what makes its items
186
+ * addressable as `@slug`. Checked at definition time: a key naming a kind that isn't a source kind
187
+ * would declare a source on a collection no ref can qualify with, and the failure would surface as
188
+ * "this config borrows nothing" much later.
189
+ */
190
+ sources?: Sources;
191
+ /** Internal: built by `.extend` — it shares its base's name, so it must not take over the base's
192
+ * slot in the untyped `Config.fromJSON` dispatch registry. */
193
+ extendsBase?: boolean;
194
+ }): ConfigClass<Owned, Derived, Sources>;
195
+ //#endregion
196
+ export { Collection, ConfigClass, ConfigInstance, ConfigKind, EntityMap, OwnedRecords, PartialBodyOf, SourceMap, SourcesOf, defineConfig, kindsOf };