@flyingrobots/bijou 4.4.1 → 7.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 (249) hide show
  1. package/README.md +71 -1
  2. package/dist/adapters/test/index.d.ts.map +1 -1
  3. package/dist/adapters/test/index.js +1 -3
  4. package/dist/adapters/test/index.js.map +1 -1
  5. package/dist/adapters/test/runtime.d.ts.map +1 -1
  6. package/dist/adapters/test/runtime.js +4 -3
  7. package/dist/adapters/test/runtime.js.map +1 -1
  8. package/dist/context-theme.d.ts +25 -0
  9. package/dist/context-theme.d.ts.map +1 -1
  10. package/dist/context-theme.js +19 -0
  11. package/dist/context-theme.js.map +1 -1
  12. package/dist/context.d.ts +13 -1
  13. package/dist/context.d.ts.map +1 -1
  14. package/dist/context.js +24 -3
  15. package/dist/context.js.map +1 -1
  16. package/dist/core/active-binding-collection.d.ts +49 -0
  17. package/dist/core/active-binding-collection.d.ts.map +1 -0
  18. package/dist/core/active-binding-collection.js +264 -0
  19. package/dist/core/active-binding-collection.js.map +1 -0
  20. package/dist/core/app-shell-composition.d.ts +44 -0
  21. package/dist/core/app-shell-composition.d.ts.map +1 -0
  22. package/dist/core/app-shell-composition.js +123 -0
  23. package/dist/core/app-shell-composition.js.map +1 -0
  24. package/dist/core/binding-frame-update.d.ts +18 -0
  25. package/dist/core/binding-frame-update.d.ts.map +1 -0
  26. package/dist/core/binding-frame-update.js +133 -0
  27. package/dist/core/binding-frame-update.js.map +1 -0
  28. package/dist/core/binding-lifecycle.d.ts +65 -0
  29. package/dist/core/binding-lifecycle.d.ts.map +1 -0
  30. package/dist/core/binding-lifecycle.js +357 -0
  31. package/dist/core/binding-lifecycle.js.map +1 -0
  32. package/dist/core/binding.d.ts +192 -0
  33. package/dist/core/binding.d.ts.map +1 -0
  34. package/dist/core/binding.js +587 -0
  35. package/dist/core/binding.js.map +1 -0
  36. package/dist/core/block-metadata.d.ts +113 -0
  37. package/dist/core/block-metadata.d.ts.map +1 -0
  38. package/dist/core/block-metadata.js +376 -0
  39. package/dist/core/block-metadata.js.map +1 -0
  40. package/dist/core/block-tree-render.d.ts +17 -0
  41. package/dist/core/block-tree-render.d.ts.map +1 -0
  42. package/dist/core/block-tree-render.js +186 -0
  43. package/dist/core/block-tree-render.js.map +1 -0
  44. package/dist/core/component-metadata.d.ts +63 -0
  45. package/dist/core/component-metadata.d.ts.map +1 -0
  46. package/dist/core/component-metadata.js +158 -0
  47. package/dist/core/component-metadata.js.map +1 -0
  48. package/dist/core/components/alert-v3.d.ts.map +1 -1
  49. package/dist/core/components/alert-v3.js +5 -4
  50. package/dist/core/components/alert-v3.js.map +1 -1
  51. package/dist/core/components/alert.d.ts.map +1 -1
  52. package/dist/core/components/alert.js +7 -8
  53. package/dist/core/components/alert.js.map +1 -1
  54. package/dist/core/components/badge.d.ts.map +1 -1
  55. package/dist/core/components/badge.js +19 -18
  56. package/dist/core/components/badge.js.map +1 -1
  57. package/dist/core/components/box-v3.d.ts.map +1 -1
  58. package/dist/core/components/box-v3.js +29 -29
  59. package/dist/core/components/box-v3.js.map +1 -1
  60. package/dist/core/components/dag-edges.d.ts +28 -5
  61. package/dist/core/components/dag-edges.d.ts.map +1 -1
  62. package/dist/core/components/dag-edges.js +116 -22
  63. package/dist/core/components/dag-edges.js.map +1 -1
  64. package/dist/core/components/dag-layout.d.ts +3 -4
  65. package/dist/core/components/dag-layout.d.ts.map +1 -1
  66. package/dist/core/components/dag-layout.js +42 -9
  67. package/dist/core/components/dag-layout.js.map +1 -1
  68. package/dist/core/components/dag-render.d.ts +4 -3
  69. package/dist/core/components/dag-render.d.ts.map +1 -1
  70. package/dist/core/components/dag-render.js +209 -105
  71. package/dist/core/components/dag-render.js.map +1 -1
  72. package/dist/core/components/dag-source.d.ts +4 -0
  73. package/dist/core/components/dag-source.d.ts.map +1 -1
  74. package/dist/core/components/dag-source.js +10 -0
  75. package/dist/core/components/dag-source.js.map +1 -1
  76. package/dist/core/components/dag.d.ts +20 -4
  77. package/dist/core/components/dag.d.ts.map +1 -1
  78. package/dist/core/components/dag.js.map +1 -1
  79. package/dist/core/components/explainability.d.ts.map +1 -1
  80. package/dist/core/components/explainability.js +30 -87
  81. package/dist/core/components/explainability.js.map +1 -1
  82. package/dist/core/components/guided-flow.d.ts +32 -0
  83. package/dist/core/components/guided-flow.d.ts.map +1 -0
  84. package/dist/core/components/guided-flow.js +131 -0
  85. package/dist/core/components/guided-flow.js.map +1 -0
  86. package/dist/core/components/hyperlink.d.ts.map +1 -1
  87. package/dist/core/components/hyperlink.js +7 -4
  88. package/dist/core/components/hyperlink.js.map +1 -1
  89. package/dist/core/components/index.d.ts +5 -3
  90. package/dist/core/components/index.d.ts.map +1 -1
  91. package/dist/core/components/index.js +1 -0
  92. package/dist/core/components/index.js.map +1 -1
  93. package/dist/core/components/markdown-parse.d.ts +4 -0
  94. package/dist/core/components/markdown-parse.d.ts.map +1 -1
  95. package/dist/core/components/markdown-parse.js +66 -2
  96. package/dist/core/components/markdown-parse.js.map +1 -1
  97. package/dist/core/components/markdown-render.d.ts.map +1 -1
  98. package/dist/core/components/markdown-render.js +220 -14
  99. package/dist/core/components/markdown-render.js.map +1 -1
  100. package/dist/core/components/markdown.d.ts +4 -3
  101. package/dist/core/components/markdown.d.ts.map +1 -1
  102. package/dist/core/components/markdown.js +6 -5
  103. package/dist/core/components/markdown.js.map +1 -1
  104. package/dist/core/components/paginator.d.ts.map +1 -1
  105. package/dist/core/components/paginator.js +5 -3
  106. package/dist/core/components/paginator.js.map +1 -1
  107. package/dist/core/components/perf-overlay.d.ts.map +1 -1
  108. package/dist/core/components/perf-overlay.js +3 -2
  109. package/dist/core/components/perf-overlay.js.map +1 -1
  110. package/dist/core/components/preference-list.d.ts.map +1 -1
  111. package/dist/core/components/preference-list.js +75 -37
  112. package/dist/core/components/preference-list.js.map +1 -1
  113. package/dist/core/components/progress.d.ts.map +1 -1
  114. package/dist/core/components/progress.js +4 -3
  115. package/dist/core/components/progress.js.map +1 -1
  116. package/dist/core/components/separator-v3.d.ts.map +1 -1
  117. package/dist/core/components/separator-v3.js +11 -11
  118. package/dist/core/components/separator-v3.js.map +1 -1
  119. package/dist/core/components/separator.d.ts.map +1 -1
  120. package/dist/core/components/separator.js +4 -1
  121. package/dist/core/components/separator.js.map +1 -1
  122. package/dist/core/components/skeleton.d.ts.map +1 -1
  123. package/dist/core/components/skeleton.js +3 -2
  124. package/dist/core/components/skeleton.js.map +1 -1
  125. package/dist/core/components/surface-text.d.ts +7 -0
  126. package/dist/core/components/surface-text.d.ts.map +1 -1
  127. package/dist/core/components/surface-text.js +33 -25
  128. package/dist/core/components/surface-text.js.map +1 -1
  129. package/dist/core/components/table-v3.d.ts +5 -2
  130. package/dist/core/components/table-v3.d.ts.map +1 -1
  131. package/dist/core/components/table-v3.js +162 -37
  132. package/dist/core/components/table-v3.js.map +1 -1
  133. package/dist/core/components/table.d.ts +51 -7
  134. package/dist/core/components/table.d.ts.map +1 -1
  135. package/dist/core/components/table.js +655 -81
  136. package/dist/core/components/table.js.map +1 -1
  137. package/dist/core/fixture-promotion.d.ts +33 -0
  138. package/dist/core/fixture-promotion.d.ts.map +1 -0
  139. package/dist/core/fixture-promotion.js +62 -0
  140. package/dist/core/fixture-promotion.js.map +1 -0
  141. package/dist/core/forms/filter-interactive.d.ts.map +1 -1
  142. package/dist/core/forms/filter-interactive.js +2 -4
  143. package/dist/core/forms/filter-interactive.js.map +1 -1
  144. package/dist/core/forms/multiselect.d.ts.map +1 -1
  145. package/dist/core/forms/multiselect.js +2 -4
  146. package/dist/core/forms/multiselect.js.map +1 -1
  147. package/dist/core/forms/note.d.ts.map +1 -1
  148. package/dist/core/forms/note.js +2 -1
  149. package/dist/core/forms/note.js.map +1 -1
  150. package/dist/core/forms/select.d.ts.map +1 -1
  151. package/dist/core/forms/select.js +2 -4
  152. package/dist/core/forms/select.js.map +1 -1
  153. package/dist/core/forms/textarea-editor.d.ts.map +1 -1
  154. package/dist/core/forms/textarea-editor.js +7 -5
  155. package/dist/core/forms/textarea-editor.js.map +1 -1
  156. package/dist/core/layout/envelope.d.ts +174 -0
  157. package/dist/core/layout/envelope.d.ts.map +1 -0
  158. package/dist/core/layout/envelope.js +336 -0
  159. package/dist/core/layout/envelope.js.map +1 -0
  160. package/dist/core/layout/geometry.d.ts +39 -0
  161. package/dist/core/layout/geometry.d.ts.map +1 -0
  162. package/dist/core/layout/geometry.js +201 -0
  163. package/dist/core/layout/geometry.js.map +1 -0
  164. package/dist/core/mode-lowering.d.ts +48 -0
  165. package/dist/core/mode-lowering.d.ts.map +1 -0
  166. package/dist/core/mode-lowering.js +176 -0
  167. package/dist/core/mode-lowering.js.map +1 -0
  168. package/dist/core/numeric.d.ts +16 -0
  169. package/dist/core/numeric.d.ts.map +1 -0
  170. package/dist/core/numeric.js +37 -0
  171. package/dist/core/numeric.js.map +1 -0
  172. package/dist/core/render/differ.d.ts.map +1 -1
  173. package/dist/core/render/differ.js +15 -13
  174. package/dist/core/render/differ.js.map +1 -1
  175. package/dist/core/runtime-viewport.d.ts.map +1 -1
  176. package/dist/core/runtime-viewport.js +2 -3
  177. package/dist/core/runtime-viewport.js.map +1 -1
  178. package/dist/core/schema-block.d.ts +63 -0
  179. package/dist/core/schema-block.d.ts.map +1 -0
  180. package/dist/core/schema-block.js +361 -0
  181. package/dist/core/schema-block.js.map +1 -0
  182. package/dist/core/selection.d.ts +127 -0
  183. package/dist/core/selection.d.ts.map +1 -0
  184. package/dist/core/selection.js +350 -0
  185. package/dist/core/selection.js.map +1 -0
  186. package/dist/core/standard-blocks.d.ts +264 -0
  187. package/dist/core/standard-blocks.d.ts.map +1 -0
  188. package/dist/core/standard-blocks.js +2518 -0
  189. package/dist/core/standard-blocks.js.map +1 -0
  190. package/dist/core/story-capture.d.ts +48 -0
  191. package/dist/core/story-capture.d.ts.map +1 -0
  192. package/dist/core/story-capture.js +64 -0
  193. package/dist/core/story-capture.js.map +1 -0
  194. package/dist/core/text/grapheme.d.ts +51 -0
  195. package/dist/core/text/grapheme.d.ts.map +1 -1
  196. package/dist/core/text/grapheme.js +68 -0
  197. package/dist/core/text/grapheme.js.map +1 -1
  198. package/dist/core/text/icon-presentation.d.ts +10 -0
  199. package/dist/core/text/icon-presentation.d.ts.map +1 -0
  200. package/dist/core/text/icon-presentation.js +12 -0
  201. package/dist/core/text/icon-presentation.js.map +1 -0
  202. package/dist/core/text/index.d.ts +2 -1
  203. package/dist/core/text/index.d.ts.map +1 -1
  204. package/dist/core/text/index.js +2 -1
  205. package/dist/core/text/index.js.map +1 -1
  206. package/dist/core/text/wrap.d.ts.map +1 -1
  207. package/dist/core/text/wrap.js +37 -20
  208. package/dist/core/text/wrap.js.map +1 -1
  209. package/dist/core/theme/color.d.ts +32 -0
  210. package/dist/core/theme/color.d.ts.map +1 -1
  211. package/dist/core/theme/color.js +68 -0
  212. package/dist/core/theme/color.js.map +1 -1
  213. package/dist/core/theme/doctor.d.ts +37 -0
  214. package/dist/core/theme/doctor.d.ts.map +1 -0
  215. package/dist/core/theme/doctor.js +175 -0
  216. package/dist/core/theme/doctor.js.map +1 -0
  217. package/dist/core/theme/dtcg.d.ts.map +1 -1
  218. package/dist/core/theme/dtcg.js +10 -1
  219. package/dist/core/theme/dtcg.js.map +1 -1
  220. package/dist/core/theme/graph-types.d.ts +5 -0
  221. package/dist/core/theme/graph-types.d.ts.map +1 -1
  222. package/dist/core/theme/graph.d.ts.map +1 -1
  223. package/dist/core/theme/graph.js +52 -5
  224. package/dist/core/theme/graph.js.map +1 -1
  225. package/dist/core/theme/index.d.ts +4 -1
  226. package/dist/core/theme/index.d.ts.map +1 -1
  227. package/dist/core/theme/index.js +3 -1
  228. package/dist/core/theme/index.js.map +1 -1
  229. package/dist/core/theme/presets.d.ts +3 -2
  230. package/dist/core/theme/presets.d.ts.map +1 -1
  231. package/dist/core/theme/presets.js +22 -29
  232. package/dist/core/theme/presets.js.map +1 -1
  233. package/dist/core/theme/tokens.d.ts +1 -1
  234. package/dist/core/theme/tokens.d.ts.map +1 -1
  235. package/dist/factory.d.ts +3 -0
  236. package/dist/factory.d.ts.map +1 -1
  237. package/dist/factory.js +4 -6
  238. package/dist/factory.js.map +1 -1
  239. package/dist/index.d.ts +23 -6
  240. package/dist/index.d.ts.map +1 -1
  241. package/dist/index.js +25 -6
  242. package/dist/index.js.map +1 -1
  243. package/dist/ports/context.d.ts +6 -1
  244. package/dist/ports/context.d.ts.map +1 -1
  245. package/dist/ports/surface.d.ts +6 -4
  246. package/dist/ports/surface.d.ts.map +1 -1
  247. package/dist/ports/surface.js +40 -23
  248. package/dist/ports/surface.js.map +1 -1
  249. package/package.json +2 -2
package/README.md CHANGED
@@ -45,10 +45,18 @@ const panel = boxSurface(
45
45
 
46
46
  Select the family based on the interaction semantic, not just the visual shape.
47
47
 
48
+ Render-path naming follows one house rule: the base family name is the public
49
+ component, and a `*Surface()` companion means “the same family on the composable
50
+ surface path.” If there is no `*Surface()` companion, the family is either
51
+ already surface-native, intentionally string-first, or both paths would be
52
+ fake duplication rather than a real second API.
53
+
48
54
  ### Status and Feedback
49
55
  - **`badge()`**: Compact, inline status.
50
56
  - **`note()`**: Non-urgent explanation.
51
57
  - **`alert()`**: Persistent, in-flow message.
58
+ - **`guidedFlow()`**: Calm multi-step assistance with one explicit next action.
59
+ - **`explainability()`**: AI- or machine-mediated recommendation with visible provenance and evidence.
52
60
  - *Use `@flyingrobots/bijou-tui` notifications for stacking, history, or active routing.*
53
61
 
54
62
  ### Selection and Prompts
@@ -68,11 +76,73 @@ Select the family based on the interaction semantic, not just the visual shape.
68
76
  - **`breadcrumb()`**: Path context.
69
77
  - **`stepper()`**: Ordered stages in a linear process.
70
78
 
79
+ ### Theme Authoring
80
+ - **`extendTheme()`**: Build a custom theme from a known-good preset.
81
+ - **`doctorTheme()`**: Structured checks for invalid colors, weak contrast,
82
+ and suspicious token reuse.
83
+ - **`themeContrastRatio()`**: Deterministic foreground/background contrast
84
+ calculation for token-pair tests.
85
+
86
+ ### Mode-Aware Authoring
87
+ - **`renderByMode()`**: Dispatch a component to the current output contract.
88
+ - **`lintModeLowering()`**: Compare explicit semantic facts across output modes.
89
+ - **`modeLoweringReportText()`**: Render a compact lowering report for tests,
90
+ docs, and review comments.
91
+ - **`defineComponentMetadata()`**: Declare validated package, family, mode,
92
+ arg, variant, invariant, example, and source facts for tooling.
93
+ - **`componentMetadataSummary()`**: Render compact metadata for docs, MCP
94
+ payloads, and agent-facing reports.
95
+ - **`defineBlock()`**: Declare a validated reusable block with package, family,
96
+ scale, mode, slot, variant, config, component, story, semantic facts, optional
97
+ view data contracts, and command intents.
98
+ - **`standardBlocks` / standard block exports**: Import the first-party
99
+ standard block definitions for AppShell, ReaderSurface, InspectorPanel,
100
+ inline status, in-flow status, transient overlay feedback, activity stream,
101
+ shortcut cues, and progress. These expose contracts, stories, data
102
+ requirements, command intents, and schema-bound posture, with deterministic
103
+ first-proof render output across all output modes. Production AppShell
104
+ behavior remains a later runtime slice.
105
+ - **`defineBlockPackage()`**: Declare exported blocks, docs, tags, version, and
106
+ Bijou peer compatibility for ordinary NPM block packages.
107
+ - **`defineBlockSchemaAdapter()` / `defineSchemaBlock()`**: Validate unknown
108
+ boundary data before producing immutable block render input and binding facts,
109
+ without fetching, subscribing, dispatching, or rendering AppShell.
110
+ - **`blockMetadataSummary()`**: Render compact block metadata for docs, MCP
111
+ payloads, and agent-facing reports.
112
+ - **`defineAppShellComposition()`**: Compose runtime-backed blocks into logical
113
+ AppShell slots with an explicit provider scope, without rendering or
114
+ subscribing.
115
+ - **`blockRenderNode()` / `renderBlockTree()`**: Explicitly render nested block
116
+ declarations into parent slots when a preview or host intentionally wants a
117
+ block tree, while ordinary `block.render()` remains a local single-block
118
+ render contract.
119
+ - **`defineDataRequirement()` / `defineDataProvider()` / `providerScope()`**:
120
+ Declare data requirements and explicit local provider availability without
121
+ hidden global registration.
122
+ - **`defineViewData()`**: Group named data requirements for a view or block
123
+ without binding them to providers.
124
+ - **`resolveProviderRequirement()`**: Resolve a requirement against an explicit
125
+ local provider scope as frozen metadata, without subscribing or fetching.
126
+ - **`bindingFrameFromSnapshots()`**: Assemble read-only render frames from
127
+ resolved provider metadata and already-created immutable snapshots.
128
+ - **`bindingSnapshot()` / `bindingFrame()`**: Model provider-delivered plain
129
+ data as copied, versioned immutable snapshots and read-only render frames.
130
+ - **`commandIntent()`**: Declare user intent outputs as inspectable metadata,
131
+ without business-logic callbacks or provider mutation handles.
132
+ - **`captureStoryMatrix()`**: Capture every profile/variant pair from a story
133
+ renderer.
134
+ - **`storyCaptureMatrixText()`**: Render a deterministic multi-mode story
135
+ matrix for docs and tests.
136
+ - **`createFixturePromotionRecord()`**: Preserve provenance when a fixture,
137
+ docs page, story, example, or MCP payload is promoted into another surface.
138
+ - **`fixturePromotionText()`**: Render that promotion record for review and
139
+ agent output.
140
+
71
141
  ## Documentation
72
142
 
73
143
  - **[GUIDE.md](./GUIDE.md)**: Productive-fast path.
74
144
  - **[ADVANCED_GUIDE.md](./ADVANCED_GUIDE.md)**: Rendering doctrine, themes, and testing.
75
- - **[Design System](../../docs/design-system/README.md)**: Semantic guidance and component families.
145
+ - **[Design System](../../docs/design-system/README.md)**: Foundations, token vocabulary, and component families.
76
146
 
77
147
  ---
78
148
  Built with 💎 by [FLYING ROBOTS](https://github.com/flyingrobots)
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/test/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACxE,OAAO,EAAe,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAU,KAAK,aAAa,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAa,KAAK,gBAAgB,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAC9E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAOtD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AAGxD,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACpF,OAAO,EACL,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,GACd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAE,8BAA8B,EAAE,MAAM,kBAAkB,CAAC;AAElE;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,sEAAsE;IACtE,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,wEAAwE;IACxE,EAAE,CAAC,EAAE,aAAa,CAAC;IACnB,oDAAoD;IACpD,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,wDAAwD;IACxD,KAAK,CAAC,EAAE,gBAAgB,GAAG,SAAS,GAAG,SAAS,CAAC;IACjD,gDAAgD;IAChD,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,2EAA2E;IAC3E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,8DAA8D;IAC9D,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AASD;;;GAGG;AACH,MAAM,WAAW,WAAY,SAAQ,YAAY;IAC/C,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,kBAAuB,GAAG,WAAW,CAyB/E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/test/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACxE,OAAO,EAAe,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAU,KAAK,aAAa,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAa,KAAK,gBAAgB,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAC9E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAKtD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AAGxD,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACpF,OAAO,EACL,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,GACd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAE,8BAA8B,EAAE,MAAM,kBAAkB,CAAC;AAElE;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,sEAAsE;IACtE,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,wEAAwE;IACxE,EAAE,CAAC,EAAE,aAAa,CAAC;IACnB,oDAAoD;IACpD,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,wDAAwD;IACxD,KAAK,CAAC,EAAE,gBAAgB,GAAG,SAAS,GAAG,SAAS,CAAC;IACjD,gDAAgD;IAChD,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,2EAA2E;IAC3E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,8DAA8D;IAC9D,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AASD;;;GAGG;AACH,MAAM,WAAW,WAAY,SAAQ,YAAY;IAC/C,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,kBAAuB,GAAG,WAAW,CAwB/E"}
@@ -5,7 +5,6 @@ import { plainStyle } from './style.js';
5
5
  import { createResolved } from '../../core/theme/resolve.js';
6
6
  import { CYAN_MAGENTA } from '../../core/theme/presets.js';
7
7
  import { createThemeAccessors } from '../../core/theme/accessors.js';
8
- import { createTokenGraph } from '../../core/theme/graph.js';
9
8
  import { systemClock } from '../../core/clock.js';
10
9
  export { mockRuntime } from './runtime.js';
11
10
  export { mockIO } from './io.js';
@@ -44,7 +43,6 @@ export function createTestContext(options = {}) {
44
43
  : options.io);
45
44
  const style = options.style ?? plainStyle();
46
45
  const theme = createResolved(options.theme ?? CYAN_MAGENTA, options.noColor ?? false, options.colorScheme ?? 'dark');
47
- const tokenGraph = createTokenGraph((options.theme ?? CYAN_MAGENTA));
48
46
  const mode = options.mode ?? 'interactive';
49
47
  return {
50
48
  theme,
@@ -53,7 +51,7 @@ export function createTestContext(options = {}) {
53
51
  io,
54
52
  clock,
55
53
  style,
56
- tokenGraph,
54
+ tokenGraph: theme.tokenGraph,
57
55
  resolveBCSS: () => ({}),
58
56
  ...createThemeAccessors(theme),
59
57
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/test/index.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,WAAW,EAA2B,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,MAAM,EAAmC,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,SAAS,EAAyC,MAAM,YAAY,CAAC;AAG9E,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAG7D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAElD,OAAO,EAAE,WAAW,EAA2B,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,MAAM,EAAmC,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,SAAS,EAAyC,MAAM,YAAY,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,UAAU,EAAwC,MAAM,kBAAkB,CAAC;AACpF,OAAO,EACL,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,GACd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAE,8BAA8B,EAAE,MAAM,kBAAkB,CAAC;AAwBlE,SAAS,WAAW,CAAC,KAA2D;IAC9E,OAAO,OAAO,KAAK,KAAK,QAAQ;WAC3B,KAAK,KAAK,IAAI;WACd,KAAK,IAAI,KAAK;WACd,OAAO,KAAK,CAAC,GAAG,KAAK,UAAU,CAAC;AACvC,CAAC;AAWD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAA8B,EAAE;IAChE,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7C,MAAM,cAAc,GAAG,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,EAAE,EAAE,KAAK,CAAC;IAC1D,MAAM,KAAK,GAAG,cAAc,KAAK,SAAS;QACxC,CAAC,CAAC,WAAW,EAAE;QACf,CAAC,CAAC,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC;IAC/E,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,KAAK,KAAK,SAAS;QAC/C,CAAC,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE;QAClC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAChB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,EAAE,CAAC;IAC5C,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,CAAC,KAAK,IAAI,YAAY,EAAE,OAAO,CAAC,OAAO,IAAI,KAAK,EAAE,OAAO,CAAC,WAAW,IAAI,MAAM,CAAC,CAAC;IACrH,MAAM,UAAU,GAAG,gBAAgB,CAAC,CAAC,OAAO,CAAC,KAAK,IAAI,YAAY,CAAgC,CAAC,CAAC;IACpG,MAAM,IAAI,GAAe,OAAO,CAAC,IAAI,IAAI,aAAa,CAAC;IAEvD,OAAO;QACL,KAAK;QACL,IAAI;QACJ,OAAO;QACP,EAAE;QACF,KAAK;QACL,KAAK;QACL,UAAU;QACV,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;QACvB,GAAG,oBAAoB,CAAC,KAAK,CAAC;KAC/B,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/test/index.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,WAAW,EAA2B,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,MAAM,EAAmC,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,SAAS,EAAyC,MAAM,YAAY,CAAC;AAG9E,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAElD,OAAO,EAAE,WAAW,EAA2B,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,MAAM,EAAmC,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,SAAS,EAAyC,MAAM,YAAY,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,UAAU,EAAwC,MAAM,kBAAkB,CAAC;AACpF,OAAO,EACL,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,GACd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAE,8BAA8B,EAAE,MAAM,kBAAkB,CAAC;AAwBlE,SAAS,WAAW,CAAC,KAA2D;IAC9E,OAAO,OAAO,KAAK,KAAK,QAAQ;WAC3B,KAAK,KAAK,IAAI;WACd,KAAK,IAAI,KAAK;WACd,OAAO,KAAK,CAAC,GAAG,KAAK,UAAU,CAAC;AACvC,CAAC;AAWD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAA8B,EAAE;IAChE,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7C,MAAM,cAAc,GAAG,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,EAAE,EAAE,KAAK,CAAC;IAC1D,MAAM,KAAK,GAAG,cAAc,KAAK,SAAS;QACxC,CAAC,CAAC,WAAW,EAAE;QACf,CAAC,CAAC,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC;IAC/E,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,KAAK,KAAK,SAAS;QAC/C,CAAC,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE;QAClC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAChB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,EAAE,CAAC;IAC5C,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,CAAC,KAAK,IAAI,YAAY,EAAE,OAAO,CAAC,OAAO,IAAI,KAAK,EAAE,OAAO,CAAC,WAAW,IAAI,MAAM,CAAC,CAAC;IACrH,MAAM,IAAI,GAAe,OAAO,CAAC,IAAI,IAAI,aAAa,CAAC;IAEvD,OAAO;QACL,KAAK;QACL,IAAI;QACJ,OAAO;QACP,EAAE;QACF,KAAK;QACL,KAAK;QACL,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;QACvB,GAAG,oBAAoB,CAAC,KAAK,CAAC;KAC/B,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/adapters/test/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,oEAAoE;IACpE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,mDAAmD;IACnD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kDAAkD;IAClD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,WAAW,CAiBzE"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/adapters/test/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAG1D;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,oEAAoE;IACpE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,mDAAmD;IACnD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kDAAkD;IAClD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,WAAW,CAiBzE"}
@@ -1,3 +1,4 @@
1
+ import { sanitizePositiveInt } from '../../core/numeric.js';
1
2
  /**
2
3
  * Create an in-memory {@link RuntimePort} for tests.
3
4
  *
@@ -20,9 +21,9 @@ export function mockRuntime(options = {}) {
20
21
  },
21
22
  stdoutIsTTY: options.stdoutIsTTY ?? true,
22
23
  stdinIsTTY: options.stdinIsTTY ?? true,
23
- columns: options.columns ?? 80,
24
- rows: options.rows ?? 24,
25
- refreshRate: options.refreshRate ?? 60,
24
+ columns: sanitizePositiveInt(options.columns, 80),
25
+ rows: sanitizePositiveInt(options.rows, 24),
26
+ refreshRate: sanitizePositiveInt(options.refreshRate, 60),
26
27
  };
27
28
  }
28
29
  //# sourceMappingURL=runtime.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/adapters/test/runtime.ts"],"names":[],"mappings":"AAoBA;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,UAA8B,EAAE;IAC1D,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,IAAI,EAAE,CAAC;IACjC,OAAO;QACL;;;;WAIG;QACH,GAAG,CAAC,GAAW;YACb,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;QACrB,CAAC;QACD,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,IAAI;QACxC,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,IAAI;QACtC,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,EAAE;QAC9B,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,EAAE;QACxB,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,EAAE;KACvC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/adapters/test/runtime.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAoB5D;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,UAA8B,EAAE;IAC1D,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,IAAI,EAAE,CAAC;IACjC,OAAO;QACL;;;;WAIG;QACH,GAAG,CAAC,GAAW;YACb,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;QACrB,CAAC;QACD,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,IAAI;QACxC,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,IAAI;QACtC,OAAO,EAAE,mBAAmB,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;QACjD,IAAI,EAAE,mBAAmB,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;QAC3C,WAAW,EAAE,mBAAmB,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;KAC1D,CAAC;AACJ,CAAC"}
@@ -1,6 +1,20 @@
1
1
  import type { BijouContext } from './ports/context.js';
2
2
  import { type ResolvedTheme } from './core/theme/resolve.js';
3
3
  import type { Theme } from './core/theme/tokens.js';
4
+ /** Notification emitted when the observed theme graph changes. */
5
+ export interface ThemeChange {
6
+ /** The context whose theme graph emitted the change. */
7
+ readonly ctx: BijouContext;
8
+ /** Token path that changed. `'*'` means broad invalidation after import. */
9
+ readonly path: string;
10
+ /** True when the underlying graph requested a full recompute. */
11
+ readonly fullReload: boolean;
12
+ }
13
+ /** Disposable subscription returned by {@link observeTheme}. */
14
+ export interface ThemeObservation {
15
+ /** Stop observing future theme changes. */
16
+ dispose(): void;
17
+ }
4
18
  /**
5
19
  * Clone a Bijou context with a different already-resolved theme.
6
20
  *
@@ -12,4 +26,15 @@ export declare function cloneContextWithResolvedTheme(ctx: BijouContext, theme:
12
26
  * Clone a Bijou context with a different theme definition.
13
27
  */
14
28
  export declare function cloneContextWithTheme(ctx: BijouContext, theme: Theme): BijouContext;
29
+ /**
30
+ * Observe theme/token updates for a context.
31
+ *
32
+ * This is the supported third-party authoring seam for reacting to in-place
33
+ * token-graph updates. Handlers should invalidate any cached theme-derived
34
+ * work and re-read tokens through the accessor layer on the provided context.
35
+ *
36
+ * When a caller replaces the entire context object, dispose the old
37
+ * observation and subscribe to the new context instead.
38
+ */
39
+ export declare function observeTheme(ctx: BijouContext, handler: (change: ThemeChange) => void): ThemeObservation;
15
40
  //# sourceMappingURL=context-theme.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context-theme.d.ts","sourceRoot":"","sources":["../src/context-theme.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7E,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAEpD;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,GAAG,EAAE,YAAY,EACjB,KAAK,EAAE,aAAa,GACnB,YAAY,CAOd;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,YAAY,EACjB,KAAK,EAAE,KAAK,GACX,YAAY,CAKd"}
1
+ {"version":3,"file":"context-theme.d.ts","sourceRoot":"","sources":["../src/context-theme.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7E,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAEpD,kEAAkE;AAClE,MAAM,WAAW,WAAW;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC;IAC3B,4EAA4E;IAC5E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,iEAAiE;IACjE,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC9B;AAED,gEAAgE;AAChE,MAAM,WAAW,gBAAgB;IAC/B,2CAA2C;IAC3C,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,GAAG,EAAE,YAAY,EACjB,KAAK,EAAE,aAAa,GACnB,YAAY,CAOd;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,YAAY,EACjB,KAAK,EAAE,KAAK,GACX,YAAY,CAKd;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,YAAY,EACjB,OAAO,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,GACrC,gBAAgB,CAQlB"}
@@ -20,4 +20,23 @@ export function cloneContextWithResolvedTheme(ctx, theme) {
20
20
  export function cloneContextWithTheme(ctx, theme) {
21
21
  return cloneContextWithResolvedTheme(ctx, createResolved(theme, ctx.theme.noColor, ctx.theme.colorScheme));
22
22
  }
23
+ /**
24
+ * Observe theme/token updates for a context.
25
+ *
26
+ * This is the supported third-party authoring seam for reacting to in-place
27
+ * token-graph updates. Handlers should invalidate any cached theme-derived
28
+ * work and re-read tokens through the accessor layer on the provided context.
29
+ *
30
+ * When a caller replaces the entire context object, dispose the old
31
+ * observation and subscribe to the new context instead.
32
+ */
33
+ export function observeTheme(ctx, handler) {
34
+ return ctx.tokenGraph.on((path) => {
35
+ handler({
36
+ ctx,
37
+ path,
38
+ fullReload: path === '*',
39
+ });
40
+ });
41
+ }
23
42
  //# sourceMappingURL=context-theme.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"context-theme.js","sourceRoot":"","sources":["../src/context-theme.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAsB,MAAM,yBAAyB,CAAC;AAG7E;;;;;GAKG;AACH,MAAM,UAAU,6BAA6B,CAC3C,GAAiB,EACjB,KAAoB;IAEpB,OAAO;QACL,GAAG,GAAG;QACN,KAAK;QACL,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,GAAG,oBAAoB,CAAC,KAAK,CAAC;KAC/B,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CACnC,GAAiB,EACjB,KAAY;IAEZ,OAAO,6BAA6B,CAClC,GAAG,EACH,cAAc,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAChE,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"context-theme.js","sourceRoot":"","sources":["../src/context-theme.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAsB,MAAM,yBAAyB,CAAC;AAmB7E;;;;;GAKG;AACH,MAAM,UAAU,6BAA6B,CAC3C,GAAiB,EACjB,KAAoB;IAEpB,OAAO;QACL,GAAG,GAAG;QACN,KAAK;QACL,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,GAAG,oBAAoB,CAAC,KAAK,CAAC;KAC/B,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CACnC,GAAiB,EACjB,KAAY;IAEZ,OAAO,6BAA6B,CAClC,GAAG,EACH,cAAc,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAChE,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY,CAC1B,GAAiB,EACjB,OAAsC;IAEtC,OAAO,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE;QAChC,OAAO,CAAC;YACN,GAAG;YACH,IAAI;YACJ,UAAU,EAAE,IAAI,KAAK,GAAG;SACzB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
package/dist/context.d.ts CHANGED
@@ -18,7 +18,19 @@ export declare function getDefaultContext(): BijouContext;
18
18
  */
19
19
  export declare function setDefaultContext(ctx: BijouContext): void;
20
20
  /**
21
- * Reset the default context to `null`.
21
+ * Register a lazy initializer for the global default {@link BijouContext}.
22
+ *
23
+ * Host adapters can use this to provide ambient context bootstrapping without
24
+ * forcing higher-level runtime packages to depend on host-specific modules.
25
+ *
26
+ * The initializer is invoked only when {@link getDefaultContext} is called and
27
+ * no explicit default has been set yet.
28
+ *
29
+ * @param initializer - Lazy factory for the default context, or `null` to clear it.
30
+ */
31
+ export declare function setDefaultContextInitializer(initializer: (() => BijouContext) | null): void;
32
+ /**
33
+ * Reset the default context and lazy initializer.
22
34
  *
23
35
  * **Test-only** — ensures isolation between test cases.
24
36
  */
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIvD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,IAAI,YAAY,CAShD;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CAEzD;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,IAAI,IAAI,CAErD"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAKvD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,IAAI,YAAY,CAchD;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CAEzD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,4BAA4B,CAC1C,WAAW,EAAE,CAAC,MAAM,YAAY,CAAC,GAAG,IAAI,GACvC,IAAI,CAEN;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,IAAI,IAAI,CAGrD"}
package/dist/context.js CHANGED
@@ -1,4 +1,5 @@
1
1
  let defaultContext = null;
2
+ let defaultContextInitializer = null;
2
3
  /**
3
4
  * Retrieve the global default {@link BijouContext}.
4
5
  *
@@ -8,9 +9,14 @@ let defaultContext = null;
8
9
  */
9
10
  export function getDefaultContext() {
10
11
  if (defaultContext === null) {
12
+ if (defaultContextInitializer != null) {
13
+ defaultContext = defaultContextInitializer();
14
+ return defaultContext;
15
+ }
11
16
  throw new Error('[bijou] No default context configured. ' +
12
- 'Import @flyingrobots/bijou-node to auto-configure, ' +
13
- 'or call setDefaultContext() explicitly.');
17
+ 'Import @flyingrobots/bijou-node to register Node auto-init, ' +
18
+ 'call startApp(app), or call setDefaultContext() explicitly. ' +
19
+ 'Guide: https://github.com/flyingrobots/bijou/tree/main/packages/bijou-node/GUIDE.md#basic-setup');
14
20
  }
15
21
  return defaultContext;
16
22
  }
@@ -27,11 +33,26 @@ export function setDefaultContext(ctx) {
27
33
  defaultContext = ctx;
28
34
  }
29
35
  /**
30
- * Reset the default context to `null`.
36
+ * Register a lazy initializer for the global default {@link BijouContext}.
37
+ *
38
+ * Host adapters can use this to provide ambient context bootstrapping without
39
+ * forcing higher-level runtime packages to depend on host-specific modules.
40
+ *
41
+ * The initializer is invoked only when {@link getDefaultContext} is called and
42
+ * no explicit default has been set yet.
43
+ *
44
+ * @param initializer - Lazy factory for the default context, or `null` to clear it.
45
+ */
46
+ export function setDefaultContextInitializer(initializer) {
47
+ defaultContextInitializer = initializer;
48
+ }
49
+ /**
50
+ * Reset the default context and lazy initializer.
31
51
  *
32
52
  * **Test-only** — ensures isolation between test cases.
33
53
  */
34
54
  export function _resetDefaultContextForTesting() {
35
55
  defaultContext = null;
56
+ defaultContextInitializer = null;
36
57
  }
37
58
  //# sourceMappingURL=context.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAEA,IAAI,cAAc,GAAwB,IAAI,CAAC;AAE/C;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB;IAC/B,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CACb,yCAAyC;YACzC,qDAAqD;YACrD,yCAAyC,CAC1C,CAAC;IACJ,CAAC;IACD,OAAO,cAAc,CAAC;AACxB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAiB;IACjD,cAAc,GAAG,GAAG,CAAC;AACvB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,8BAA8B;IAC5C,cAAc,GAAG,IAAI,CAAC;AACxB,CAAC"}
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAEA,IAAI,cAAc,GAAwB,IAAI,CAAC;AAC/C,IAAI,yBAAyB,GAAgC,IAAI,CAAC;AAElE;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB;IAC/B,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;QAC5B,IAAI,yBAAyB,IAAI,IAAI,EAAE,CAAC;YACtC,cAAc,GAAG,yBAAyB,EAAE,CAAC;YAC7C,OAAO,cAAc,CAAC;QACxB,CAAC;QACD,MAAM,IAAI,KAAK,CACb,yCAAyC;YACzC,8DAA8D;YAC9D,8DAA8D;YAC9D,iGAAiG,CAClG,CAAC;IACJ,CAAC;IACD,OAAO,cAAc,CAAC;AACxB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAiB;IACjD,cAAc,GAAG,GAAG,CAAC;AACvB,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,4BAA4B,CAC1C,WAAwC;IAExC,yBAAyB,GAAG,WAAW,CAAC;AAC1C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,8BAA8B;IAC5C,cAAc,GAAG,IAAI,CAAC;IACtB,yBAAyB,GAAG,IAAI,CAAC;AACnC,CAAC"}
@@ -0,0 +1,49 @@
1
+ import { type DataRequirement, type ProviderId, type ViewDataContract } from './binding.js';
2
+ import { type BindingLifecycleOwner, type BindingLifecycleRecord } from './binding-lifecycle.js';
3
+ declare const ACTIVE_BINDING_ENTRY_BRAND: unique symbol;
4
+ declare const ACTIVE_BINDING_COLLECTION_BRAND: unique symbol;
5
+ export interface ActiveBindingEntryInput {
6
+ readonly owner: BindingLifecycleOwner;
7
+ readonly requirement: DataRequirement;
8
+ readonly providerId?: string;
9
+ }
10
+ export interface ActiveBindingEntry {
11
+ readonly [ACTIVE_BINDING_ENTRY_BRAND]: true;
12
+ readonly owner: BindingLifecycleOwner;
13
+ readonly requirement: DataRequirement;
14
+ readonly providerId?: ProviderId;
15
+ }
16
+ export interface ActiveBindingProviderAssignment {
17
+ readonly requirementId: string;
18
+ readonly providerId: string;
19
+ }
20
+ export interface ActiveBindingContractInput {
21
+ readonly owner: BindingLifecycleOwner;
22
+ readonly contract: ViewDataContract;
23
+ readonly providerIds?: readonly ActiveBindingProviderAssignment[];
24
+ }
25
+ export interface CollectActiveBindingsInput {
26
+ readonly entries?: readonly ActiveBindingEntry[];
27
+ readonly contracts?: readonly ActiveBindingContractInput[];
28
+ }
29
+ export declare class ActiveBindingCollection {
30
+ #private;
31
+ readonly [ACTIVE_BINDING_COLLECTION_BRAND]: true;
32
+ constructor(entries: readonly ActiveBindingEntry[]);
33
+ entries(): readonly ActiveBindingEntry[];
34
+ requirements(): readonly DataRequirement[];
35
+ owners(): readonly BindingLifecycleOwner[];
36
+ lifecycleRecords(): readonly BindingLifecycleRecord[];
37
+ get(ownerId: string, requirementId: string): ActiveBindingEntry | undefined;
38
+ has(ownerId: string, requirementId: string): boolean;
39
+ byOwner(ownerId: string): readonly ActiveBindingEntry[];
40
+ byRequirement(requirementId: string): readonly ActiveBindingEntry[];
41
+ with(entry: ActiveBindingEntry): ActiveBindingCollection;
42
+ }
43
+ export declare function activeBindingEntry(input: ActiveBindingEntryInput): ActiveBindingEntry;
44
+ export declare function isActiveBindingEntry(value: unknown): value is ActiveBindingEntry;
45
+ export declare function activeBindingCollection(entries: readonly ActiveBindingEntry[]): ActiveBindingCollection;
46
+ export declare function isActiveBindingCollection(value: unknown): value is ActiveBindingCollection;
47
+ export declare function collectActiveBindings(input: CollectActiveBindingsInput): ActiveBindingCollection;
48
+ export {};
49
+ //# sourceMappingURL=active-binding-collection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"active-binding-collection.d.ts","sourceRoot":"","sources":["../../src/core/active-binding-collection.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,UAAU,EAEf,KAAK,gBAAgB,EACtB,MAAM,cAAc,CAAC;AACtB,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC5B,MAAM,wBAAwB,CAAC;AAEhC,QAAA,MAAM,0BAA0B,EAAE,OAAO,MAAqC,CAAC;AAC/E,QAAA,MAAM,+BAA+B,EAAE,OAAO,MAA0C,CAAC;AAEzF,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,KAAK,EAAE,qBAAqB,CAAC;IACtC,QAAQ,CAAC,WAAW,EAAE,eAAe,CAAC;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,CAAC,0BAA0B,CAAC,EAAE,IAAI,CAAC;IAC5C,QAAQ,CAAC,KAAK,EAAE,qBAAqB,CAAC;IACtC,QAAQ,CAAC,WAAW,EAAE,eAAe,CAAC;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;CAClC;AAED,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,KAAK,EAAE,qBAAqB,CAAC;IACtC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,+BAA+B,EAAE,CAAC;CACnE;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACjD,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,0BAA0B,EAAE,CAAC;CAC5D;AAED,qBAAa,uBAAuB;;IAClC,QAAQ,CAAC,CAAC,+BAA+B,CAAC,EAAG,IAAI,CAAC;gBAItC,OAAO,EAAE,SAAS,kBAAkB,EAAE;IA6ClD,OAAO,IAAI,SAAS,kBAAkB,EAAE;IAIxC,YAAY,IAAI,SAAS,eAAe,EAAE;IAW1C,MAAM,IAAI,SAAS,qBAAqB,EAAE;IAW1C,gBAAgB,IAAI,SAAS,sBAAsB,EAAE;IAWrD,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAe3E,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO;IAIpD,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,kBAAkB,EAAE;IAYvD,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,kBAAkB,EAAE;IAYnE,IAAI,CAAC,KAAK,EAAE,kBAAkB,GAAG,uBAAuB;CAGzD;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,GAAG,kBAAkB,CAwBrF;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,kBAAkB,CAOhF;AAED,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,SAAS,kBAAkB,EAAE,GACrC,uBAAuB,CAEzB;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,uBAAuB,CAO1F;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,0BAA0B,GAChC,uBAAuB,CAiBzB"}
@@ -0,0 +1,264 @@
1
+ import { isDataRequirement, isViewDataContract, } from './binding.js';
2
+ import { bindingLifecycleRecord, isBindingLifecycleOwner, } from './binding-lifecycle.js';
3
+ const ACTIVE_BINDING_ENTRY_BRAND = Symbol('ActiveBindingEntry');
4
+ const ACTIVE_BINDING_COLLECTION_BRAND = Symbol('ActiveBindingCollection');
5
+ export class ActiveBindingCollection {
6
+ [ACTIVE_BINDING_COLLECTION_BRAND];
7
+ #entries;
8
+ #entriesByKey;
9
+ constructor(entries) {
10
+ if (!Array.isArray(entries)) {
11
+ throw new Error('active binding collection: entries must be an array');
12
+ }
13
+ Object.defineProperty(this, ACTIVE_BINDING_COLLECTION_BRAND, { value: true });
14
+ const entriesByKey = new Map();
15
+ const entryIndexesByKey = new Map();
16
+ const normalizedEntries = [];
17
+ entries.forEach((entry, index) => {
18
+ if (!isActiveBindingEntry(entry)) {
19
+ throw new Error(`active binding collection: entry at index ${index} was not created by activeBindingEntry()`);
20
+ }
21
+ const key = activeBindingKey(entry.owner.id, entry.requirement.id);
22
+ const existingEntry = entriesByKey.get(key);
23
+ if (existingEntry !== undefined) {
24
+ const mergedEntry = mergeDuplicateEntry(existingEntry, entry);
25
+ const existingIndex = entryIndexesByKey.get(key);
26
+ if (existingIndex === undefined) {
27
+ throw new Error(`active binding collection: missing index for owner ${entry.owner.id} `
28
+ + `requirement ${entry.requirement.id}`);
29
+ }
30
+ entriesByKey.set(key, mergedEntry);
31
+ normalizedEntries[existingIndex] = mergedEntry;
32
+ return;
33
+ }
34
+ entriesByKey.set(key, entry);
35
+ entryIndexesByKey.set(key, normalizedEntries.length);
36
+ normalizedEntries.push(entry);
37
+ });
38
+ this.#entries = Object.freeze(normalizedEntries);
39
+ this.#entriesByKey = entriesByKey;
40
+ Object.freeze(this);
41
+ }
42
+ entries() {
43
+ return Object.freeze([...this.#entries]);
44
+ }
45
+ requirements() {
46
+ const requirementsById = new Map();
47
+ this.#entries.forEach((entry) => {
48
+ if (!requirementsById.has(entry.requirement.id)) {
49
+ requirementsById.set(entry.requirement.id, entry.requirement);
50
+ }
51
+ });
52
+ return Object.freeze([...requirementsById.values()]);
53
+ }
54
+ owners() {
55
+ const ownersById = new Map();
56
+ this.#entries.forEach((entry) => {
57
+ if (!ownersById.has(entry.owner.id)) {
58
+ ownersById.set(entry.owner.id, entry.owner);
59
+ }
60
+ });
61
+ return Object.freeze([...ownersById.values()]);
62
+ }
63
+ lifecycleRecords() {
64
+ return Object.freeze(this.#entries.map((entry) => bindingLifecycleRecord({
65
+ owner: entry.owner,
66
+ requirementId: entry.requirement.id,
67
+ providerId: entry.providerId,
68
+ facts: entry.requirement.facts,
69
+ })));
70
+ }
71
+ get(ownerId, requirementId) {
72
+ return this.#entriesByKey.get(activeBindingKey(normalizeRequiredText({
73
+ scope: 'active binding collection',
74
+ field: 'ownerId',
75
+ value: ownerId,
76
+ }), normalizeRequiredText({
77
+ scope: 'active binding collection',
78
+ field: 'requirementId',
79
+ value: requirementId,
80
+ })));
81
+ }
82
+ has(ownerId, requirementId) {
83
+ return this.get(ownerId, requirementId) !== undefined;
84
+ }
85
+ byOwner(ownerId) {
86
+ const normalizedOwnerId = normalizeRequiredText({
87
+ scope: 'active binding collection',
88
+ field: 'ownerId',
89
+ value: ownerId,
90
+ });
91
+ return Object.freeze(this.#entries.filter((entry) => entry.owner.id === normalizedOwnerId));
92
+ }
93
+ byRequirement(requirementId) {
94
+ const normalizedRequirementId = normalizeRequiredText({
95
+ scope: 'active binding collection',
96
+ field: 'requirementId',
97
+ value: requirementId,
98
+ });
99
+ return Object.freeze(this.#entries.filter((entry) => entry.requirement.id === normalizedRequirementId));
100
+ }
101
+ with(entry) {
102
+ return new ActiveBindingCollection([...this.#entries, entry]);
103
+ }
104
+ }
105
+ export function activeBindingEntry(input) {
106
+ if (!isBindingLifecycleOwner(input.owner)) {
107
+ throw new Error('active binding entry: owner was not created by defineBindingLifecycleOwner()');
108
+ }
109
+ if (!isDataRequirement(input.requirement)) {
110
+ throw new Error('active binding entry: requirement was not created by defineDataRequirement()');
111
+ }
112
+ const entry = {
113
+ owner: input.owner,
114
+ requirement: input.requirement,
115
+ providerId: optionalRequiredText({
116
+ scope: 'active binding entry',
117
+ field: 'providerId',
118
+ value: input.providerId,
119
+ }),
120
+ };
121
+ Object.defineProperty(entry, ACTIVE_BINDING_ENTRY_BRAND, { value: true });
122
+ return Object.freeze(entry);
123
+ }
124
+ export function isActiveBindingEntry(value) {
125
+ return Boolean(value
126
+ && typeof value === 'object'
127
+ && Object.prototype.hasOwnProperty.call(value, ACTIVE_BINDING_ENTRY_BRAND)
128
+ && value[ACTIVE_BINDING_ENTRY_BRAND] === true);
129
+ }
130
+ export function activeBindingCollection(entries) {
131
+ return new ActiveBindingCollection(entries);
132
+ }
133
+ export function isActiveBindingCollection(value) {
134
+ return Boolean(value
135
+ && typeof value === 'object'
136
+ && Object.prototype.hasOwnProperty.call(value, ACTIVE_BINDING_COLLECTION_BRAND)
137
+ && value[ACTIVE_BINDING_COLLECTION_BRAND] === true);
138
+ }
139
+ export function collectActiveBindings(input) {
140
+ if (input === undefined || input === null || typeof input !== 'object' || Array.isArray(input)) {
141
+ throw new Error('active binding collection: input must be an object');
142
+ }
143
+ if (input.entries !== undefined && !Array.isArray(input.entries)) {
144
+ throw new Error('active binding collection: entries must be an array');
145
+ }
146
+ if (input.contracts !== undefined && !Array.isArray(input.contracts)) {
147
+ throw new Error('active binding collection: contracts must be an array');
148
+ }
149
+ const entries = [...(input.entries ?? [])];
150
+ (input.contracts ?? []).forEach((source, index) => {
151
+ entries.push(...activeBindingEntriesFromContract(source, index));
152
+ });
153
+ return new ActiveBindingCollection(entries);
154
+ }
155
+ function activeBindingEntriesFromContract(source, index) {
156
+ if (!isObjectRecord(source)) {
157
+ throw new Error(`active binding collection: contract ${index} must be an object`);
158
+ }
159
+ if (!isBindingLifecycleOwner(source.owner)) {
160
+ throw new Error(`active binding collection: contract ${index} owner was not created by defineBindingLifecycleOwner()`);
161
+ }
162
+ if (!isViewDataContract(source.contract)) {
163
+ throw new Error(`active binding collection: contract ${index} was not created by defineViewData()`);
164
+ }
165
+ const providerIds = providerAssignmentsByRequirementId(source.providerIds);
166
+ const requirementIds = new Set(source.contract.requirementIds());
167
+ providerIds.forEach((_, requirementId) => {
168
+ if (!requirementIds.has(requirementId)) {
169
+ throw new Error(`active binding collection: provider assignment ${requirementId} `
170
+ + `does not match contract ${index}`);
171
+ }
172
+ });
173
+ const requirements = source.contract.requirements().map((requirement, requirementIndex) => {
174
+ if (!isDataRequirement(requirement)) {
175
+ throw new Error(`active binding collection: contract ${index} requirement ${requirementIndex} `
176
+ + 'was not created by defineDataRequirement()');
177
+ }
178
+ return requirement;
179
+ });
180
+ return Object.freeze(requirements.map((requirement) => activeBindingEntry({
181
+ owner: source.owner,
182
+ requirement,
183
+ providerId: providerIds.get(requirement.id),
184
+ })));
185
+ }
186
+ function providerAssignmentsByRequirementId(assignments) {
187
+ if (assignments === undefined) {
188
+ return new Map();
189
+ }
190
+ if (!Array.isArray(assignments)) {
191
+ throw new Error('active binding collection: providerIds must be an array');
192
+ }
193
+ if (assignments.length === 0) {
194
+ return new Map();
195
+ }
196
+ const providerIds = new Map();
197
+ assignments.forEach((assignment, index) => {
198
+ if (!isObjectRecord(assignment)) {
199
+ throw new Error(`active binding collection: provider assignment ${index} must be an object`);
200
+ }
201
+ if (typeof assignment['requirementId'] !== 'string') {
202
+ throw new Error(`active binding collection: provider assignment ${index} `
203
+ + 'requirementId must be a string');
204
+ }
205
+ if (typeof assignment['providerId'] !== 'string') {
206
+ throw new Error(`active binding collection: provider assignment ${index} providerId must be a string`);
207
+ }
208
+ const requirementId = normalizeRequiredText({
209
+ scope: 'active binding collection',
210
+ field: 'requirementId',
211
+ value: assignment['requirementId'],
212
+ });
213
+ if (providerIds.has(requirementId)) {
214
+ throw new Error(`active binding collection: duplicate provider assignment ${requirementId}`);
215
+ }
216
+ providerIds.set(requirementId, normalizeRequiredText({
217
+ scope: 'active binding collection',
218
+ field: 'providerId',
219
+ value: assignment['providerId'],
220
+ }));
221
+ });
222
+ return providerIds;
223
+ }
224
+ function activeBindingKey(ownerId, requirementId) {
225
+ return `${ownerId}\u0000${requirementId}`;
226
+ }
227
+ function isObjectRecord(value) {
228
+ return Boolean(value && typeof value === 'object' && !Array.isArray(value));
229
+ }
230
+ function mergeDuplicateEntry(existingEntry, incomingEntry) {
231
+ if (existingEntry.providerId !== undefined
232
+ && incomingEntry.providerId !== undefined
233
+ && existingEntry.providerId !== incomingEntry.providerId) {
234
+ throw new Error(`active binding collection: conflicting providers for owner ${incomingEntry.owner.id} `
235
+ + `requirement ${incomingEntry.requirement.id}`);
236
+ }
237
+ const providerId = existingEntry.providerId ?? incomingEntry.providerId;
238
+ if (providerId === existingEntry.providerId) {
239
+ return existingEntry;
240
+ }
241
+ return activeBindingEntry({
242
+ owner: existingEntry.owner,
243
+ requirement: existingEntry.requirement,
244
+ providerId,
245
+ });
246
+ }
247
+ function normalizeRequiredText(options) {
248
+ const normalized = options.value.trim();
249
+ if (normalized === '') {
250
+ throw new Error(`${options.scope}: ${options.field} is required`);
251
+ }
252
+ return normalized;
253
+ }
254
+ function optionalRequiredText(options) {
255
+ if (options.value === undefined) {
256
+ return undefined;
257
+ }
258
+ return normalizeRequiredText({
259
+ scope: options.scope,
260
+ field: options.field,
261
+ value: options.value,
262
+ });
263
+ }
264
+ //# sourceMappingURL=active-binding-collection.js.map