@tai42/studio-sdk 16.0.0 → 17.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 (486) hide show
  1. package/dist/components/code-block.js +1 -1
  2. package/dist/components/code-block.js.map +1 -1
  3. package/dist/components/confirm-dialog.js +1 -1
  4. package/dist/components/confirm-dialog.js.map +1 -1
  5. package/dist/components/copy-field.js +1 -1
  6. package/dist/components/copy-field.js.map +1 -1
  7. package/dist/components/date-range-picker.d.ts.map +1 -1
  8. package/dist/components/date-range-picker.js.map +1 -1
  9. package/dist/components/dialog.d.ts.map +1 -1
  10. package/dist/components/dialog.js.map +1 -1
  11. package/dist/components/dirty-guard.d.ts.map +1 -1
  12. package/dist/components/dirty-guard.js +1 -1
  13. package/dist/components/dirty-guard.js.map +1 -1
  14. package/dist/components/explorer-body.d.ts +49 -0
  15. package/dist/components/explorer-body.d.ts.map +1 -0
  16. package/dist/components/explorer-body.js +67 -0
  17. package/dist/components/explorer-body.js.map +1 -0
  18. package/dist/components/explorer-page-size.d.ts +4 -0
  19. package/dist/components/explorer-page-size.d.ts.map +1 -0
  20. package/dist/components/explorer-page-size.js +36 -0
  21. package/dist/components/explorer-page-size.js.map +1 -0
  22. package/dist/components/explorer-tag-filter.d.ts +17 -0
  23. package/dist/components/explorer-tag-filter.d.ts.map +1 -0
  24. package/dist/components/explorer-tag-filter.js +29 -0
  25. package/dist/components/explorer-tag-filter.js.map +1 -0
  26. package/dist/components/explorer-tags.d.ts +22 -0
  27. package/dist/components/explorer-tags.d.ts.map +1 -0
  28. package/dist/components/explorer-tags.js +51 -0
  29. package/dist/components/explorer-tags.js.map +1 -0
  30. package/dist/components/explorer-view.d.ts +3 -17
  31. package/dist/components/explorer-view.d.ts.map +1 -1
  32. package/dist/components/explorer-view.js +53 -170
  33. package/dist/components/explorer-view.js.map +1 -1
  34. package/dist/components/extension-combo-builder.d.ts +1 -6
  35. package/dist/components/extension-combo-builder.d.ts.map +1 -1
  36. package/dist/components/extension-combo-builder.js +4 -79
  37. package/dist/components/extension-combo-builder.js.map +1 -1
  38. package/dist/components/extension-combo-parts.d.ts +44 -0
  39. package/dist/components/extension-combo-parts.d.ts.map +1 -0
  40. package/dist/components/extension-combo-parts.js +52 -0
  41. package/dist/components/extension-combo-parts.js.map +1 -0
  42. package/dist/components/field.d.ts +8 -0
  43. package/dist/components/field.d.ts.map +1 -1
  44. package/dist/components/field.js +0 -8
  45. package/dist/components/field.js.map +1 -1
  46. package/dist/components/fleet-report.d.ts +1 -1
  47. package/dist/components/fleet-report.d.ts.map +1 -1
  48. package/dist/components/fleet-report.js +51 -37
  49. package/dist/components/fleet-report.js.map +1 -1
  50. package/dist/components/folder-nav.d.ts.map +1 -1
  51. package/dist/components/folder-nav.js +1 -1
  52. package/dist/components/folder-nav.js.map +1 -1
  53. package/dist/components/form-dialog.d.ts.map +1 -1
  54. package/dist/components/form-dialog.js +1 -1
  55. package/dist/components/form-dialog.js.map +1 -1
  56. package/dist/components/icons/chrome-marks.d.ts +50 -0
  57. package/dist/components/icons/chrome-marks.d.ts.map +1 -0
  58. package/dist/components/icons/chrome-marks.js +51 -0
  59. package/dist/components/icons/chrome-marks.js.map +1 -0
  60. package/dist/components/icons/icon-frame.d.ts +29 -0
  61. package/dist/components/icons/icon-frame.d.ts.map +1 -0
  62. package/dist/components/icons/icon-frame.js +19 -0
  63. package/dist/components/icons/icon-frame.js.map +1 -0
  64. package/dist/components/icons/index.d.ts +40 -0
  65. package/dist/components/icons/index.d.ts.map +1 -0
  66. package/dist/components/icons/index.js +39 -0
  67. package/dist/components/icons/index.js.map +1 -0
  68. package/dist/components/icons/nav-map.d.ts +14 -0
  69. package/dist/components/icons/nav-map.d.ts.map +1 -0
  70. package/dist/components/icons/nav-map.js +28 -0
  71. package/dist/components/icons/nav-map.js.map +1 -0
  72. package/dist/components/icons/nav-marks.d.ts +44 -0
  73. package/dist/components/icons/nav-marks.d.ts.map +1 -0
  74. package/dist/components/icons/nav-marks.js +45 -0
  75. package/dist/components/icons/nav-marks.js.map +1 -0
  76. package/dist/components/icons/status-marks.d.ts +21 -0
  77. package/dist/components/icons/status-marks.d.ts.map +1 -0
  78. package/dist/components/icons/status-marks.js +22 -0
  79. package/dist/components/icons/status-marks.js.map +1 -0
  80. package/dist/components/icons/theme-marks.d.ts +9 -0
  81. package/dist/components/icons/theme-marks.d.ts.map +1 -0
  82. package/dist/components/icons/theme-marks.js +10 -0
  83. package/dist/components/icons/theme-marks.js.map +1 -0
  84. package/dist/components/inputs.js.map +1 -1
  85. package/dist/components/json-diff.d.ts.map +1 -1
  86. package/dist/components/json-diff.js +1 -3
  87. package/dist/components/json-diff.js.map +1 -1
  88. package/dist/components/json-tree-context.d.ts +13 -0
  89. package/dist/components/json-tree-context.d.ts.map +1 -0
  90. package/dist/components/json-tree-context.js +15 -0
  91. package/dist/components/json-tree-context.js.map +1 -0
  92. package/dist/components/json-tree-model.d.ts +56 -0
  93. package/dist/components/json-tree-model.d.ts.map +1 -0
  94. package/dist/components/json-tree-model.js +125 -0
  95. package/dist/components/json-tree-model.js.map +1 -0
  96. package/dist/components/json-tree-nodes.d.ts +35 -0
  97. package/dist/components/json-tree-nodes.d.ts.map +1 -0
  98. package/dist/components/json-tree-nodes.js +113 -0
  99. package/dist/components/json-tree-nodes.js.map +1 -0
  100. package/dist/components/json-tree.d.ts +20 -0
  101. package/dist/components/json-tree.d.ts.map +1 -1
  102. package/dist/components/json-tree.js +7 -315
  103. package/dist/components/json-tree.js.map +1 -1
  104. package/dist/components/json-value-format.d.ts +20 -0
  105. package/dist/components/json-value-format.d.ts.map +1 -0
  106. package/dist/components/json-value-format.js +63 -0
  107. package/dist/components/json-value-format.js.map +1 -0
  108. package/dist/components/markdown-blocks.d.ts +38 -0
  109. package/dist/components/markdown-blocks.d.ts.map +1 -0
  110. package/dist/components/markdown-blocks.js +168 -0
  111. package/dist/components/markdown-blocks.js.map +1 -0
  112. package/dist/components/markdown-inline.d.ts +24 -0
  113. package/dist/components/markdown-inline.d.ts.map +1 -0
  114. package/dist/components/markdown-inline.js +257 -0
  115. package/dist/components/markdown-inline.js.map +1 -0
  116. package/dist/components/markdown.d.ts +3 -52
  117. package/dist/components/markdown.d.ts.map +1 -1
  118. package/dist/components/markdown.js +4 -376
  119. package/dist/components/markdown.js.map +1 -1
  120. package/dist/components/observer-registry.d.ts +38 -0
  121. package/dist/components/observer-registry.d.ts.map +1 -0
  122. package/dist/components/observer-registry.js +131 -0
  123. package/dist/components/observer-registry.js.map +1 -0
  124. package/dist/components/overflow-measure.d.ts +38 -0
  125. package/dist/components/overflow-measure.d.ts.map +1 -0
  126. package/dist/components/overflow-measure.js +54 -0
  127. package/dist/components/overflow-measure.js.map +1 -0
  128. package/dist/components/page-fill.d.ts.map +1 -1
  129. package/dist/components/page-fill.js.map +1 -1
  130. package/dist/components/prose-regions.d.ts +81 -0
  131. package/dist/components/prose-regions.d.ts.map +1 -0
  132. package/dist/components/prose-regions.js +128 -0
  133. package/dist/components/prose-regions.js.map +1 -0
  134. package/dist/components/radio-group.d.ts.map +1 -1
  135. package/dist/components/radio-group.js.map +1 -1
  136. package/dist/components/scroll-region.d.ts +24 -0
  137. package/dist/components/scroll-region.d.ts.map +1 -1
  138. package/dist/components/scroll-region.js +3 -322
  139. package/dist/components/scroll-region.js.map +1 -1
  140. package/dist/components/tab-stop-parse.d.ts +53 -0
  141. package/dist/components/tab-stop-parse.d.ts.map +1 -0
  142. package/dist/components/tab-stop-parse.js +202 -0
  143. package/dist/components/tab-stop-parse.js.map +1 -0
  144. package/dist/components/table.d.ts +1 -1
  145. package/dist/components/table.d.ts.map +1 -1
  146. package/dist/components/tags.d.ts.map +1 -1
  147. package/dist/components/tags.js +1 -1
  148. package/dist/components/tags.js.map +1 -1
  149. package/dist/components/templated-text-field.d.ts +1 -1
  150. package/dist/components/templated-text-field.d.ts.map +1 -1
  151. package/dist/components/templated-text-field.js +10 -174
  152. package/dist/components/templated-text-field.js.map +1 -1
  153. package/dist/components/templated-text-kwargs-editor.d.ts +24 -0
  154. package/dist/components/templated-text-kwargs-editor.d.ts.map +1 -0
  155. package/dist/components/templated-text-kwargs-editor.js +48 -0
  156. package/dist/components/templated-text-kwargs-editor.js.map +1 -0
  157. package/dist/components/templated-text-kwargs.d.ts +37 -0
  158. package/dist/components/templated-text-kwargs.d.ts.map +1 -0
  159. package/dist/components/templated-text-kwargs.js +66 -0
  160. package/dist/components/templated-text-kwargs.js.map +1 -0
  161. package/dist/components/templated-text-source.d.ts +33 -0
  162. package/dist/components/templated-text-source.d.ts.map +1 -0
  163. package/dist/components/templated-text-source.js +53 -0
  164. package/dist/components/templated-text-source.js.map +1 -0
  165. package/dist/components/tool-picker-parts.d.ts +39 -0
  166. package/dist/components/tool-picker-parts.d.ts.map +1 -0
  167. package/dist/components/tool-picker-parts.js +87 -0
  168. package/dist/components/tool-picker-parts.js.map +1 -0
  169. package/dist/components/tool-picker.d.ts +1 -2
  170. package/dist/components/tool-picker.d.ts.map +1 -1
  171. package/dist/components/tool-picker.js +4 -66
  172. package/dist/components/tool-picker.js.map +1 -1
  173. package/dist/components/version-history-panel.d.ts.map +1 -1
  174. package/dist/components/version-history-panel.js +7 -34
  175. package/dist/components/version-history-panel.js.map +1 -1
  176. package/dist/components/version-history-rows.d.ts +48 -0
  177. package/dist/components/version-history-rows.d.ts.map +1 -0
  178. package/dist/components/version-history-rows.js +51 -0
  179. package/dist/components/version-history-rows.js.map +1 -0
  180. package/dist/components/view-toggle.d.ts.map +1 -1
  181. package/dist/components/view-toggle.js.map +1 -1
  182. package/dist/element-slot.d.ts +11 -0
  183. package/dist/element-slot.d.ts.map +1 -1
  184. package/dist/element-slot.js +0 -11
  185. package/dist/element-slot.js.map +1 -1
  186. package/dist/guards.d.ts +6 -0
  187. package/dist/guards.d.ts.map +1 -0
  188. package/dist/guards.js +8 -0
  189. package/dist/guards.js.map +1 -0
  190. package/dist/hooks/interactions-connection.d.ts +43 -0
  191. package/dist/hooks/interactions-connection.d.ts.map +1 -0
  192. package/dist/hooks/interactions-connection.js +171 -0
  193. package/dist/hooks/interactions-connection.js.map +1 -0
  194. package/dist/hooks/interactions-stream.d.ts +80 -0
  195. package/dist/hooks/interactions-stream.d.ts.map +1 -0
  196. package/dist/hooks/interactions-stream.js +233 -0
  197. package/dist/hooks/interactions-stream.js.map +1 -0
  198. package/dist/hooks/useApi.d.ts +2259 -2189
  199. package/dist/hooks/useApi.d.ts.map +1 -1
  200. package/dist/hooks/useApi.js +0 -11
  201. package/dist/hooks/useApi.js.map +1 -1
  202. package/dist/hooks/useAuth.d.ts +6 -0
  203. package/dist/hooks/useAuth.d.ts.map +1 -1
  204. package/dist/hooks/useAuth.js +0 -6
  205. package/dist/hooks/useAuth.js.map +1 -1
  206. package/dist/hooks/useCapabilities.d.ts +18 -2
  207. package/dist/hooks/useCapabilities.d.ts.map +1 -1
  208. package/dist/hooks/useCapabilities.js +1 -17
  209. package/dist/hooks/useCapabilities.js.map +1 -1
  210. package/dist/hooks/useSse.d.ts +34 -6
  211. package/dist/hooks/useSse.d.ts.map +1 -1
  212. package/dist/hooks/useSse.js +27 -471
  213. package/dist/hooks/useSse.js.map +1 -1
  214. package/dist/hooks/useSystemKinds.d.ts +1 -1
  215. package/dist/hooks/useSystemKinds.d.ts.map +1 -1
  216. package/dist/hooks/useSystemKinds.js +0 -18
  217. package/dist/hooks/useSystemKinds.js.map +1 -1
  218. package/dist/hooks/useTheme.d.ts +15 -0
  219. package/dist/hooks/useTheme.d.ts.map +1 -1
  220. package/dist/hooks/useTheme.js +0 -15
  221. package/dist/hooks/useTheme.js.map +1 -1
  222. package/dist/hooks/useToolDisplayNames.d.ts +0 -14
  223. package/dist/hooks/useToolDisplayNames.d.ts.map +1 -1
  224. package/dist/hooks/useToolDisplayNames.js +0 -14
  225. package/dist/hooks/useToolDisplayNames.js.map +1 -1
  226. package/dist/host.d.ts +3 -3
  227. package/dist/host.d.ts.map +1 -1
  228. package/dist/host.js +2 -9
  229. package/dist/host.js.map +1 -1
  230. package/dist/index.d.ts +103 -103
  231. package/dist/index.d.ts.map +1 -1
  232. package/dist/index.js +49 -62
  233. package/dist/index.js.map +1 -1
  234. package/dist/navigation/app-link.d.ts +25 -0
  235. package/dist/navigation/app-link.d.ts.map +1 -0
  236. package/dist/navigation/app-link.js +33 -0
  237. package/dist/navigation/app-link.js.map +1 -0
  238. package/dist/navigation/context.d.ts +3 -20
  239. package/dist/navigation/context.d.ts.map +1 -1
  240. package/dist/navigation/context.js +7 -267
  241. package/dist/navigation/context.js.map +1 -1
  242. package/dist/navigation/entry-state.d.ts +23 -0
  243. package/dist/navigation/entry-state.d.ts.map +1 -0
  244. package/dist/navigation/entry-state.js +39 -0
  245. package/dist/navigation/entry-state.js.map +1 -0
  246. package/dist/navigation/guard-registry.d.ts +30 -0
  247. package/dist/navigation/guard-registry.d.ts.map +1 -0
  248. package/dist/navigation/guard-registry.js +46 -0
  249. package/dist/navigation/guard-registry.js.map +1 -0
  250. package/dist/navigation/guarded-navigation.d.ts +24 -0
  251. package/dist/navigation/guarded-navigation.d.ts.map +1 -0
  252. package/dist/navigation/guarded-navigation.js +102 -0
  253. package/dist/navigation/guarded-navigation.js.map +1 -0
  254. package/dist/navigation/index.d.ts +5 -4
  255. package/dist/navigation/index.d.ts.map +1 -1
  256. package/dist/navigation/index.js +2 -1
  257. package/dist/navigation/index.js.map +1 -1
  258. package/dist/navigation/types.d.ts +8 -11
  259. package/dist/navigation/types.d.ts.map +1 -1
  260. package/dist/navigation/use-back-forward-guard.d.ts +12 -0
  261. package/dist/navigation/use-back-forward-guard.d.ts.map +1 -0
  262. package/dist/navigation/use-back-forward-guard.js +75 -0
  263. package/dist/navigation/use-back-forward-guard.js.map +1 -0
  264. package/dist/navigation/use-search-commit.d.ts.map +1 -1
  265. package/dist/navigation/use-search-commit.js.map +1 -1
  266. package/dist/plugin/host-state.d.ts.map +1 -1
  267. package/dist/plugin/host-state.js.map +1 -1
  268. package/dist/plugin/registry.d.ts +6 -15
  269. package/dist/plugin/registry.d.ts.map +1 -1
  270. package/dist/plugin/registry.js +83 -75
  271. package/dist/plugin/registry.js.map +1 -1
  272. package/dist/schema-editor/SchemaEditor.d.ts.map +1 -1
  273. package/dist/schema-editor/SchemaEditor.js.map +1 -1
  274. package/dist/schema-editor/index.d.ts +3 -3
  275. package/dist/schema-editor/index.d.ts.map +1 -1
  276. package/dist/schema-editor/index.js +1 -6
  277. package/dist/schema-editor/index.js.map +1 -1
  278. package/dist/schema-form/SecretRefField.d.ts +18 -3
  279. package/dist/schema-form/SecretRefField.d.ts.map +1 -1
  280. package/dist/schema-form/SecretRefField.js +21 -26
  281. package/dist/schema-form/SecretRefField.js.map +1 -1
  282. package/dist/schema-form/classify.d.ts +1 -113
  283. package/dist/schema-form/classify.d.ts.map +1 -1
  284. package/dist/schema-form/classify.js +174 -246
  285. package/dist/schema-form/classify.js.map +1 -1
  286. package/dist/schema-form/context.d.ts +6 -0
  287. package/dist/schema-form/context.d.ts.map +1 -1
  288. package/dist/schema-form/context.js +0 -6
  289. package/dist/schema-form/context.js.map +1 -1
  290. package/dist/schema-form/default-value.d.ts.map +1 -1
  291. package/dist/schema-form/default-value.js +42 -19
  292. package/dist/schema-form/default-value.js.map +1 -1
  293. package/dist/schema-form/enum-field.d.ts +1 -1
  294. package/dist/schema-form/enum-field.d.ts.map +1 -1
  295. package/dist/schema-form/field-group.d.ts +6 -0
  296. package/dist/schema-form/field-group.d.ts.map +1 -1
  297. package/dist/schema-form/field-group.js +0 -6
  298. package/dist/schema-form/field-group.js.map +1 -1
  299. package/dist/schema-form/field-model.d.ts +121 -0
  300. package/dist/schema-form/field-model.d.ts.map +1 -0
  301. package/dist/schema-form/field-model.js +2 -0
  302. package/dist/schema-form/field-model.js.map +1 -0
  303. package/dist/schema-form/field-node.d.ts.map +1 -1
  304. package/dist/schema-form/field-node.js +25 -14
  305. package/dist/schema-form/field-node.js.map +1 -1
  306. package/dist/schema-form/index.d.ts +8 -8
  307. package/dist/schema-form/index.d.ts.map +1 -1
  308. package/dist/schema-form/index.js +3 -34
  309. package/dist/schema-form/index.js.map +1 -1
  310. package/dist/schema-form/json-field.d.ts +19 -0
  311. package/dist/schema-form/json-field.d.ts.map +1 -1
  312. package/dist/schema-form/json-field.js +0 -19
  313. package/dist/schema-form/json-field.js.map +1 -1
  314. package/dist/schema-form/media-field.d.ts +1 -1
  315. package/dist/schema-form/media-field.d.ts.map +1 -1
  316. package/dist/schema-form/media-field.js +49 -30
  317. package/dist/schema-form/media-field.js.map +1 -1
  318. package/dist/schema-form/record-field.d.ts +12 -0
  319. package/dist/schema-form/record-field.d.ts.map +1 -1
  320. package/dist/schema-form/record-field.js +1 -13
  321. package/dist/schema-form/record-field.js.map +1 -1
  322. package/dist/schema-form/string-annotations.d.ts +20 -0
  323. package/dist/schema-form/string-annotations.d.ts.map +1 -0
  324. package/dist/schema-form/string-annotations.js +105 -0
  325. package/dist/schema-form/string-annotations.js.map +1 -0
  326. package/dist/schema-form/string-field.d.ts +1 -1
  327. package/dist/schema-form/string-field.d.ts.map +1 -1
  328. package/dist/schema-form/string-field.js +1 -1
  329. package/dist/schema-form/string-field.js.map +1 -1
  330. package/dist/schema-form/union-field.d.ts +1 -1
  331. package/dist/schema-form/union-field.d.ts.map +1 -1
  332. package/dist/schema-form/union-field.js.map +1 -1
  333. package/dist/schema-form/union.d.ts +8 -1
  334. package/dist/schema-form/union.d.ts.map +1 -1
  335. package/dist/schema-form/union.js +0 -7
  336. package/dist/schema-form/union.js.map +1 -1
  337. package/dist/schema-form/validate.d.ts.map +1 -1
  338. package/dist/schema-form/validate.js +126 -105
  339. package/dist/schema-form/validate.js.map +1 -1
  340. package/dist/state-binding/AdapterMapping.d.ts.map +1 -1
  341. package/dist/state-binding/AdapterMapping.js +0 -0
  342. package/dist/state-binding/AdapterMapping.js.map +1 -1
  343. package/dist/state-binding/BindingJqField.d.ts.map +1 -1
  344. package/dist/state-binding/BindingJqField.js +2 -2
  345. package/dist/state-binding/BindingJqField.js.map +1 -1
  346. package/dist/state-binding/InputInjectionRow.d.ts.map +1 -1
  347. package/dist/state-binding/InputInjectionRow.js +3 -3
  348. package/dist/state-binding/InputInjectionRow.js.map +1 -1
  349. package/dist/state-binding/StateAttachRow.d.ts.map +1 -1
  350. package/dist/state-binding/StateAttachRow.js +57 -41
  351. package/dist/state-binding/StateAttachRow.js.map +1 -1
  352. package/dist/state-binding/StateBindingSection.d.ts.map +1 -1
  353. package/dist/state-binding/StateBindingSection.js.map +1 -1
  354. package/dist/state-binding/SubjectScopeFields.d.ts.map +1 -1
  355. package/dist/state-binding/SubjectScopeFields.js.map +1 -1
  356. package/dist/state-binding/UpdateRow.d.ts.map +1 -1
  357. package/dist/state-binding/UpdateRow.js +2 -2
  358. package/dist/state-binding/UpdateRow.js.map +1 -1
  359. package/dist/state-binding/adapter-mapping-row.d.ts +17 -0
  360. package/dist/state-binding/adapter-mapping-row.d.ts.map +1 -0
  361. package/dist/state-binding/adapter-mapping-row.js +87 -0
  362. package/dist/state-binding/adapter-mapping-row.js.map +1 -0
  363. package/dist/state-binding/index.d.ts +21 -21
  364. package/dist/state-binding/index.d.ts.map +1 -1
  365. package/dist/state-binding/index.js +9 -15
  366. package/dist/state-binding/index.js.map +1 -1
  367. package/dist/state-binding/templated-text-catalog.d.ts.map +1 -1
  368. package/dist/state-binding/templated-text-catalog.js.map +1 -1
  369. package/dist/state-binding/types.d.ts +2 -2
  370. package/dist/state-binding/types.d.ts.map +1 -1
  371. package/dist/structured-output/StructuredOutput.d.ts.map +1 -1
  372. package/dist/structured-output/StructuredOutput.js +1 -3
  373. package/dist/structured-output/StructuredOutput.js.map +1 -1
  374. package/package.json +2 -2
  375. package/src/components/code-block.tsx +1 -1
  376. package/src/components/confirm-dialog.tsx +1 -1
  377. package/src/components/copy-field.tsx +1 -1
  378. package/src/components/date-range-picker.tsx +1 -1
  379. package/src/components/dialog.tsx +1 -1
  380. package/src/components/dirty-guard.tsx +3 -3
  381. package/src/components/explorer-body.tsx +239 -0
  382. package/src/components/explorer-page-size.ts +39 -0
  383. package/src/components/explorer-tag-filter.tsx +80 -0
  384. package/src/components/explorer-tags.ts +64 -0
  385. package/src/components/explorer-view.tsx +115 -367
  386. package/src/components/extension-combo-builder.tsx +35 -153
  387. package/src/components/extension-combo-parts.tsx +236 -0
  388. package/src/components/field.tsx +1 -1
  389. package/src/components/fleet-report.tsx +98 -55
  390. package/src/components/folder-nav.tsx +2 -2
  391. package/src/components/form-dialog.tsx +2 -2
  392. package/src/components/icons/chrome-marks.tsx +195 -0
  393. package/src/components/icons/icon-frame.tsx +50 -0
  394. package/src/components/icons/index.ts +84 -0
  395. package/src/components/icons/nav-map.ts +55 -0
  396. package/src/components/icons/nav-marks.tsx +205 -0
  397. package/src/components/icons/status-marks.tsx +46 -0
  398. package/src/components/icons/theme-marks.tsx +33 -0
  399. package/src/components/inputs.tsx +1 -1
  400. package/src/components/json-diff.tsx +1 -4
  401. package/src/components/json-tree-context.ts +26 -0
  402. package/src/components/json-tree-model.ts +139 -0
  403. package/src/components/json-tree-nodes.tsx +224 -0
  404. package/src/components/json-tree.tsx +15 -434
  405. package/src/components/json-value-format.ts +64 -0
  406. package/src/components/markdown-blocks.ts +198 -0
  407. package/src/components/markdown-inline.tsx +365 -0
  408. package/src/components/markdown.tsx +6 -472
  409. package/src/components/observer-registry.ts +139 -0
  410. package/src/components/overflow-measure.ts +69 -0
  411. package/src/components/page-fill.tsx +1 -1
  412. package/src/components/prose-regions.ts +153 -0
  413. package/src/components/radio-group.tsx +1 -1
  414. package/src/components/scroll-region.tsx +22 -361
  415. package/src/components/tab-stop-parse.ts +217 -0
  416. package/src/components/table.tsx +1 -1
  417. package/src/components/tags.tsx +2 -2
  418. package/src/components/templated-text-field.tsx +39 -332
  419. package/src/components/templated-text-kwargs-editor.tsx +147 -0
  420. package/src/components/templated-text-kwargs.ts +92 -0
  421. package/src/components/templated-text-source.tsx +226 -0
  422. package/src/components/tool-picker-parts.tsx +184 -0
  423. package/src/components/tool-picker.tsx +22 -114
  424. package/src/components/version-history-panel.tsx +39 -143
  425. package/src/components/version-history-rows.tsx +220 -0
  426. package/src/components/view-toggle.tsx +1 -1
  427. package/src/element-slot.ts +1 -1
  428. package/src/guards.ts +7 -0
  429. package/src/hooks/interactions-connection.ts +227 -0
  430. package/src/hooks/interactions-stream.ts +274 -0
  431. package/src/hooks/useApi.ts +1 -1
  432. package/src/hooks/useAuth.ts +1 -1
  433. package/src/hooks/useCapabilities.ts +3 -3
  434. package/src/hooks/useSse.ts +51 -478
  435. package/src/hooks/useSystemKinds.tsx +2 -2
  436. package/src/hooks/useTheme.ts +1 -1
  437. package/src/hooks/useToolDisplayNames.tsx +2 -2
  438. package/src/host.ts +7 -7
  439. package/src/index.ts +292 -292
  440. package/src/navigation/app-link.tsx +70 -0
  441. package/src/navigation/context.tsx +12 -331
  442. package/src/navigation/entry-state.ts +42 -0
  443. package/src/navigation/guard-registry.ts +65 -0
  444. package/src/navigation/guarded-navigation.ts +147 -0
  445. package/src/navigation/index.ts +14 -14
  446. package/src/navigation/types.ts +8 -11
  447. package/src/navigation/use-back-forward-guard.ts +90 -0
  448. package/src/navigation/use-search-commit.ts +1 -1
  449. package/src/plugin/host-state.ts +1 -1
  450. package/src/plugin/registry.ts +111 -90
  451. package/src/schema-editor/SchemaEditor.tsx +1 -1
  452. package/src/schema-editor/index.ts +3 -3
  453. package/src/schema-form/SecretRefField.tsx +122 -72
  454. package/src/schema-form/classify.ts +245 -396
  455. package/src/schema-form/context.ts +1 -1
  456. package/src/schema-form/default-value.ts +48 -17
  457. package/src/schema-form/enum-field.tsx +1 -1
  458. package/src/schema-form/field-group.tsx +1 -1
  459. package/src/schema-form/field-model.ts +133 -0
  460. package/src/schema-form/field-node.tsx +95 -39
  461. package/src/schema-form/index.ts +10 -10
  462. package/src/schema-form/json-field.tsx +1 -1
  463. package/src/schema-form/media-field.tsx +136 -67
  464. package/src/schema-form/record-field.tsx +2 -2
  465. package/src/schema-form/string-annotations.ts +111 -0
  466. package/src/schema-form/string-field.tsx +2 -2
  467. package/src/schema-form/union-field.tsx +3 -2
  468. package/src/schema-form/union.ts +1 -1
  469. package/src/schema-form/validate.ts +185 -104
  470. package/src/state-binding/AdapterMapping.tsx +0 -0
  471. package/src/state-binding/BindingJqField.tsx +3 -3
  472. package/src/state-binding/InputInjectionRow.tsx +4 -4
  473. package/src/state-binding/StateAttachRow.tsx +229 -154
  474. package/src/state-binding/StateBindingSection.tsx +1 -1
  475. package/src/state-binding/SubjectScopeFields.tsx +1 -1
  476. package/src/state-binding/UpdateRow.tsx +3 -3
  477. package/src/state-binding/adapter-mapping-row.tsx +232 -0
  478. package/src/state-binding/index.ts +43 -43
  479. package/src/state-binding/templated-text-catalog.ts +0 -1
  480. package/src/state-binding/types.ts +2 -2
  481. package/src/structured-output/StructuredOutput.tsx +1 -4
  482. package/dist/components/icons.d.ts +0 -160
  483. package/dist/components/icons.d.ts.map +0 -1
  484. package/dist/components/icons.js +0 -160
  485. package/dist/components/icons.js.map +0 -1
  486. package/src/components/icons.tsx +0 -586
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Wrap a shell-supplied {@link NavigationContextValue} so every SDK-controlled
3
+ * transition consults the armed guards before it commits, and — on approval —
4
+ * advances the committed-entry mirror to the resolved destination. With no guard
5
+ * armed each call stays synchronous, identical to the raw shell value.
6
+ */
7
+ import type { RefObject } from 'react';
8
+
9
+ import { mergeEntryState, reconstructEntryState } from './entry-state';
10
+ import type { NavigationGuardRegistry } from './guard-registry';
11
+ import type { NavigationContextValue } from './types';
12
+
13
+ /** The last committed history entry the SDK observed: what a canceled back/forward restores to. */
14
+ export interface CommittedEntry {
15
+ href: string;
16
+ state: unknown;
17
+ }
18
+
19
+ type CommittedRef = RefObject<CommittedEntry | null>;
20
+
21
+ // navigate: forwarded as a REST tuple so the shell's `navigate` is called with
22
+ // exactly the arguments the caller passed — a caller wanting the default history
23
+ // behaviour never turns into one that passed an explicit `undefined` for it.
24
+ function buildNavigate(
25
+ value: NavigationContextValue,
26
+ registry: NavigationGuardRegistry,
27
+ committedRef: CommittedRef,
28
+ ): NavigationContextValue['navigate'] {
29
+ return (...args) => {
30
+ const [token, search] = args;
31
+ if (!registry.hasArmedGuards()) {
32
+ value.navigate(...args);
33
+ return;
34
+ }
35
+ void registry.run().then((allowed) => {
36
+ if (!allowed) return;
37
+ value.navigate(...args);
38
+ // Advance the committed entry to the resolved destination (the router may commit
39
+ // async, so `window.location` would be stale). Router state is unobservable here.
40
+ if (committedRef.current !== null) {
41
+ committedRef.current = { href: value.resolvePath(token, search), state: null };
42
+ }
43
+ });
44
+ };
45
+ }
46
+
47
+ function buildNavigatePlugin(
48
+ value: NavigationContextValue,
49
+ registry: NavigationGuardRegistry,
50
+ committedRef: CommittedRef,
51
+ ): NavigationContextValue['navigatePlugin'] {
52
+ return (pluginId, pagePath, params, search) => {
53
+ if (!registry.hasArmedGuards()) {
54
+ value.navigatePlugin(pluginId, pagePath, params, search);
55
+ return;
56
+ }
57
+ void registry.run().then((allowed) => {
58
+ if (!allowed) return;
59
+ value.navigatePlugin(pluginId, pagePath, params, search);
60
+ if (committedRef.current !== null) {
61
+ committedRef.current = {
62
+ href: value.resolvePluginPath(pluginId, pagePath, params, search),
63
+ state: null,
64
+ };
65
+ }
66
+ });
67
+ };
68
+ }
69
+
70
+ // navigatePluginWithOptions: guard-gated exactly like navigatePlugin (a veto never
71
+ // reaches the host member). On approval, refresh the committed entry with the
72
+ // reconstructed state bag so a subsequent vetoed Back restores the slot this
73
+ // navigation just wrote, not null.
74
+ function buildNavigateWithOptions(
75
+ hostNavigateWithOptions: NonNullable<NavigationContextValue['navigatePluginWithOptions']>,
76
+ value: NavigationContextValue,
77
+ registry: NavigationGuardRegistry,
78
+ committedRef: CommittedRef,
79
+ ): NonNullable<NavigationContextValue['navigatePluginWithOptions']> {
80
+ return (pluginId, pagePath, params, search, options) => {
81
+ if (!registry.hasArmedGuards()) {
82
+ hostNavigateWithOptions(pluginId, pagePath, params, search, options);
83
+ return;
84
+ }
85
+ void registry.run().then((allowed) => {
86
+ if (!allowed) return;
87
+ hostNavigateWithOptions(pluginId, pagePath, params, search, options);
88
+ if (committedRef.current !== null) {
89
+ committedRef.current = {
90
+ href: value.resolvePluginPath(pluginId, pagePath, params, search),
91
+ state:
92
+ options?.state !== undefined ? reconstructEntryState(pluginId, options.state) : null,
93
+ };
94
+ }
95
+ });
96
+ };
97
+ }
98
+
99
+ // updatePluginEntryState: guard-FREE — rewriting the current entry's state is not a
100
+ // navigation away. The SDK still wraps it to refresh the committed entry with the
101
+ // merged slot, so a later vetoed Back restores the UPDATED state. URL is unchanged.
102
+ function buildUpdateEntryState(
103
+ hostUpdateEntryState: NonNullable<NavigationContextValue['updatePluginEntryState']>,
104
+ committedRef: CommittedRef,
105
+ ): NonNullable<NavigationContextValue['updatePluginEntryState']> {
106
+ return (pluginId, state) => {
107
+ hostUpdateEntryState(pluginId, state);
108
+ if (committedRef.current !== null) {
109
+ committedRef.current = {
110
+ href: committedRef.current.href,
111
+ state: mergeEntryState(committedRef.current.state, pluginId, state),
112
+ };
113
+ }
114
+ };
115
+ }
116
+
117
+ /**
118
+ * Build the guarded navigation value. The two host-optional members
119
+ * (`navigatePluginWithOptions`, `updatePluginEntryState`) are wrapped only when the
120
+ * host provides them; an older host leaves them undefined and the plugin-facing hook
121
+ * throws loudly.
122
+ */
123
+ export function buildGuardedNavigation(
124
+ value: NavigationContextValue,
125
+ registry: NavigationGuardRegistry,
126
+ committedRef: CommittedRef,
127
+ ): NavigationContextValue {
128
+ const result: NavigationContextValue = {
129
+ ...value,
130
+ navigate: buildNavigate(value, registry, committedRef),
131
+ navigatePlugin: buildNavigatePlugin(value, registry, committedRef),
132
+ };
133
+ const hostNavigateWithOptions = value.navigatePluginWithOptions;
134
+ if (hostNavigateWithOptions !== undefined) {
135
+ result.navigatePluginWithOptions = buildNavigateWithOptions(
136
+ hostNavigateWithOptions,
137
+ value,
138
+ registry,
139
+ committedRef,
140
+ );
141
+ }
142
+ const hostUpdateEntryState = value.updatePluginEntryState;
143
+ if (hostUpdateEntryState !== undefined) {
144
+ result.updatePluginEntryState = buildUpdateEntryState(hostUpdateEntryState, committedRef);
145
+ }
146
+ return result;
147
+ }
@@ -1,24 +1,24 @@
1
+ export type { AppLinkProps } from './app-link';
2
+ export { AppLink } from './app-link';
1
3
  export {
2
4
  NavigationProvider,
3
- AppLink,
4
5
  useAppNavigate,
5
- useResolvePath,
6
- usePluginNavigation,
7
- usePluginEntryNavigation,
8
- useNavigationGuard,
9
6
  useNavigationGate,
7
+ useNavigationGuard,
8
+ usePluginEntryNavigation,
9
+ usePluginNavigation,
10
+ useResolvePath,
10
11
  } from './context';
11
- export type { AppLinkProps } from './context';
12
- export { useSearchCommit } from './use-search-commit';
13
- export type { SearchCommitParams } from './use-search-commit';
14
12
  export type {
15
- RouteToken,
16
- RouteSearch,
17
- RouteSearchByToken,
18
- PageProps,
19
- NavigationContextValue,
20
13
  NavigateOptions,
14
+ NavigationContextValue,
15
+ NavigationGuardHandler,
16
+ PageProps,
21
17
  PluginNavigateOptions,
22
18
  PluginSearch,
23
- NavigationGuardHandler,
19
+ RouteSearch,
20
+ RouteSearchByToken,
21
+ RouteToken,
24
22
  } from './types';
23
+ export type { SearchCommitParams } from './use-search-commit';
24
+ export { useSearchCommit } from './use-search-commit';
@@ -193,21 +193,18 @@ export interface NavigationContextValue {
193
193
  ) => string;
194
194
  /**
195
195
  * ADDITIVE plugin-page navigation that also carries per-history-entry
196
- * {@link PluginNavigateOptions}. OPTIONAL because a Studio host built before this
197
- * feature does not provide it; plugins reach it — and require a host that does —
198
- * through {@link usePluginEntryNavigation}, which throws loudly on an older host.
196
+ * {@link PluginNavigateOptions}. OPTIONAL because a host that does not implement it
197
+ * leaves it undefined; plugins reach it — and require a host that provides it —
198
+ * through {@link usePluginEntryNavigation}, which throws loudly when it is absent.
199
199
  * It behaves exactly like {@link navigatePlugin} for path / params / search, and in
200
200
  * addition writes `options.state` onto the DESTINATION entry under the plugin's own
201
201
  * namespace slot (see {@link PluginPageProps.entryState}).
202
202
  *
203
- * NEXT-MAJOR (9.0) CONSOLIDATION NOTE: fold `options` into {@link navigatePlugin}'s
204
- * own signature and RETIRE this sibling. It exists as a separate optional member
205
- * ONLY to stay additive under the plugin-API equality gate — a new optional member
206
- * does not move {@link STUDIO_PLUGIN_API_VERSION}, so every existing plugin keeps
207
- * loading. Cutting a MAJOR now purely to rename one method onto another is the
208
- * disproportion anti-pattern: a breaking change for a cosmetic merge. The merge
209
- * therefore waits for the next major that carries real breaks; until then both
210
- * coexist and {@link navigatePlugin} stays byte-for-byte stable.
203
+ * It is a separate optional member rather than an extra parameter on
204
+ * {@link navigatePlugin} so it stays additive under the plugin-API equality gate: a
205
+ * new optional member does not move {@link STUDIO_PLUGIN_API_VERSION}, so every
206
+ * existing plugin keeps loading and {@link navigatePlugin}'s own signature stays
207
+ * stable.
211
208
  */
212
209
  navigatePluginWithOptions?: (
213
210
  pluginId: string,
@@ -0,0 +1,90 @@
1
+ /**
2
+ * The browser back/forward and full-unload arm of the navigation guard. While any
3
+ * guard is armed it intercepts `popstate` — canceling the move by re-pushing the
4
+ * committed entry, consulting the guards once, and replaying the move on approval —
5
+ * and installs a `beforeunload` prompt. It attaches the listeners only while armed,
6
+ * mirroring the registry's armed state into React.
7
+ */
8
+ import type { RefObject } from 'react';
9
+ import { useEffect, useState } from 'react';
10
+
11
+ import type { NavigationGuardRegistry } from './guard-registry';
12
+ import type { CommittedEntry } from './guarded-navigation';
13
+
14
+ export function useBackForwardGuard(
15
+ registry: NavigationGuardRegistry,
16
+ committedRef: RefObject<CommittedEntry | null>,
17
+ ): void {
18
+ // Mirror the registry's armed state into React so the browser listeners attach only
19
+ // while at least one guard is armed.
20
+ const [armed, setArmed] = useState(false);
21
+ useEffect(() => {
22
+ setArmed(registry.hasArmedGuards());
23
+ return registry.subscribe(() => {
24
+ setArmed(registry.hasArmedGuards());
25
+ });
26
+ }, [registry]);
27
+
28
+ useEffect(() => {
29
+ if (!armed) return;
30
+
31
+ // The protected entry (URL + state); a back/forward landing elsewhere is first
32
+ // canceled back to here while the guard is consulted.
33
+ committedRef.current = { href: window.location.href, state: window.history.state };
34
+ // Set while replaying a guard-approved back/forward, so its `popstate` passes
35
+ // through instead of being re-intercepted.
36
+ let bypass = false;
37
+ // Latched while a decision is pending, so a second Back mid-decision keeps canceling
38
+ // without starting a concurrent `registry.run()` — one gesture, one dialog.
39
+ let pending = false;
40
+ // Restore pushes stacked for the pending decision, so an approved replay unwinds
41
+ // exactly that far in one `go(-depth)`. Reset per decision.
42
+ let restores = 0;
43
+
44
+ const onPopState = () => {
45
+ if (bypass) {
46
+ bypass = false;
47
+ committedRef.current = { href: window.location.href, state: window.history.state };
48
+ return;
49
+ }
50
+ if (!registry.hasArmedGuards()) {
51
+ committedRef.current = { href: window.location.href, state: window.history.state };
52
+ return;
53
+ }
54
+ const committed = committedRef.current;
55
+ if (committed === null) return;
56
+ // Cancel the browser's move by pushing the committed entry on top of wherever it
57
+ // landed. popstate exposes no direction/distance and the router owns
58
+ // `history.state`, so restore can only push, not delete. A vetoed forward thus
59
+ // strands a stub entry — an accepted limit the next pushState truncates.
60
+ window.history.pushState(committed.state, '', committed.href);
61
+ restores += 1;
62
+ if (pending) return;
63
+ pending = true;
64
+ void registry.run().then((allowed) => {
65
+ pending = false;
66
+ const depth = restores;
67
+ restores = 0;
68
+ if (!allowed) return;
69
+ bypass = true;
70
+ window.history.go(-depth);
71
+ });
72
+ };
73
+
74
+ const onBeforeUnload = (event: BeforeUnloadEvent) => {
75
+ event.preventDefault();
76
+ // Browsers below the floor (Chrome 108) gate the prompt on a set `returnValue`,
77
+ // not `preventDefault` alone; the string is ignored. Typed deprecated, still required.
78
+ // eslint-disable-next-line @typescript-eslint/no-deprecated -- required beforeunload trigger for the supported browser range.
79
+ event.returnValue = '';
80
+ };
81
+
82
+ window.addEventListener('popstate', onPopState);
83
+ window.addEventListener('beforeunload', onBeforeUnload);
84
+ return () => {
85
+ committedRef.current = null;
86
+ window.removeEventListener('popstate', onPopState);
87
+ window.removeEventListener('beforeunload', onBeforeUnload);
88
+ };
89
+ }, [armed, registry, committedRef]);
90
+ }
@@ -1,4 +1,4 @@
1
- import { useCallback, useEffect, useRef, type RefObject } from 'react';
1
+ import { type RefObject, useCallback, useEffect, useRef } from 'react';
2
2
 
3
3
  import { useAppNavigate } from './context';
4
4
  import type { RouteSearch, RouteToken } from './types';
@@ -13,8 +13,8 @@
13
13
  */
14
14
  import { useSyncExternalStore } from 'react';
15
15
 
16
- import type { PluginContributions } from './types';
17
16
  import { getContributions } from './registry';
17
+ import type { PluginContributions } from './types';
18
18
 
19
19
  /**
20
20
  * Identity of a successfully-loaded plugin, for host chrome that must attribute a
@@ -24,117 +24,115 @@ const pages: RegisteredPage[] = [];
24
24
  const settingsTabs: RegisteredSettingsTab[] = [];
25
25
  const navEntries: RegisteredNavEntry[] = [];
26
26
 
27
+ /** The contributions one plugin stages before they commit as a batch. */
28
+ interface StagedContributions {
29
+ readonly pages: RegisteredPage[];
30
+ readonly toolPanels: Map<string, ToolPanelContribution>;
31
+ readonly settingsTabs: RegisteredSettingsTab[];
32
+ readonly tabIds: Set<string>;
33
+ readonly navEntries: RegisteredNavEntry[];
34
+ }
35
+
27
36
  /**
28
- * Load one plugin: call its `register` entry with a context bound to `pluginId`,
29
- * then commit everything it staged into the global registry.
30
- *
31
- * Contributions are STAGED into local arrays (identity captured in the closure,
32
- * never read from ambient state) and only committed after `entry` settles
33
- * successfully. `entry` is AWAITED before commit, so a synchronous or an `async`
34
- * entry is fully done first: a post-`await` throw skips the commit (atomicity
35
- * holds for async too) and a post-`await` registration cannot slip past the batch.
36
- * The seal is set after `entry` has SETTLED — for a sync entry, after it returns
37
- * and the `await` continuation runs; for an async entry, after its returned promise
38
- * resolves. A registration attempted from that point on (a deferred timer, a
39
- * callback scheduled after settle) throws loudly instead of pushing into an
40
- * orphaned staged array that never commits. Registrations made during `entry`'s
41
- * synchronous body — including a microtask it enqueues then, which runs before the
42
- * `await` continuation — are still captured and committed with the batch. A
43
- * `register` that throws commits nothing and leaves the registry untouched.
44
- * Duplicate guards run against BOTH the staged contributions and what is already
45
- * committed, and fail loudly.
37
+ * A mutable seal flag passed BY REFERENCE into the staging context, so the seal set
38
+ * in {@link loadPlugin}'s `finally` is seen by every `register*` method's closure.
46
39
  */
47
- export async function loadPlugin(pluginId: string, entry: PluginEntry): Promise<void> {
48
- const stagedPages: RegisteredPage[] = [];
49
- const stagedToolPanels = new Map<string, ToolPanelContribution>();
50
- const stagedSettingsTabs: RegisteredSettingsTab[] = [];
51
- const stagedTabIds = new Set<string>();
52
- const stagedNavEntries: RegisteredNavEntry[] = [];
53
- let sealed = false;
40
+ interface Seal {
41
+ closed: boolean;
42
+ }
54
43
 
55
- const context: PluginContext = {
44
+ function emptyStaged(): StagedContributions {
45
+ return {
46
+ pages: [],
47
+ toolPanels: new Map(),
48
+ settingsTabs: [],
49
+ tabIds: new Set(),
50
+ navEntries: [],
51
+ };
52
+ }
53
+
54
+ /**
55
+ * Build the {@link PluginContext} a plugin's `register` entry contributes through.
56
+ * Every method stages into `staged` (never ambient state) and refuses once `seal` is
57
+ * closed — a registration after `entry` settles (a deferred timer, a post-settle
58
+ * callback) throws loudly rather than pushing into an orphaned array that never
59
+ * commits. Duplicate guards run against BOTH the staged set and what is already
60
+ * committed, and fail loudly.
61
+ */
62
+ function makeStagingContext(
63
+ pluginId: string,
64
+ staged: StagedContributions,
65
+ seal: Seal,
66
+ ): PluginContext {
67
+ const assertOpen = (): void => {
68
+ if (seal.closed) {
69
+ throw new Error(
70
+ 'registration is closed: a plugin must register during register(), not after it resolves',
71
+ );
72
+ }
73
+ };
74
+ return {
56
75
  registerPage(contribution: PageContribution): void {
57
- if (sealed) {
58
- throw new Error(
59
- 'registration is closed: a plugin must register during register(), not after it resolves',
60
- );
61
- }
62
- const staged = stagedPages.some((p) => p.path === contribution.path);
63
- const committed = pages.some((p) => p.pluginId === pluginId && p.path === contribution.path);
64
- if (staged || committed) {
76
+ assertOpen();
77
+ const duplicate =
78
+ staged.pages.some((p) => p.path === contribution.path) ||
79
+ pages.some((p) => p.pluginId === pluginId && p.path === contribution.path);
80
+ if (duplicate) {
65
81
  // A duplicate path within one plugin is an author mistake that would
66
82
  // leave one page unreachable — fail loudly, as registerToolPanel does.
67
83
  throw new Error(`plugin “${pluginId}” already registered a page at “${contribution.path}”`);
68
84
  }
69
- stagedPages.push({ ...contribution, pluginId });
85
+ staged.pages.push({ ...contribution, pluginId });
70
86
  },
71
87
  registerToolPanel(contribution: ToolPanelContribution): void {
72
- if (sealed) {
73
- throw new Error(
74
- 'registration is closed: a plugin must register during register(), not after it resolves',
75
- );
76
- }
77
- if (stagedToolPanels.has(contribution.toolName) || toolPanels.has(contribution.toolName)) {
88
+ assertOpen();
89
+ if (staged.toolPanels.has(contribution.toolName) || toolPanels.has(contribution.toolName)) {
78
90
  throw new Error(`a tool panel is already registered for ${contribution.toolName}`);
79
91
  }
80
- stagedToolPanels.set(contribution.toolName, contribution);
92
+ staged.toolPanels.set(contribution.toolName, contribution);
81
93
  },
82
94
  registerSettingsTab(contribution: SettingsTabContribution): void {
83
- if (sealed) {
84
- throw new Error(
85
- 'registration is closed: a plugin must register during register(), not after it resolves',
86
- );
87
- }
95
+ assertOpen();
88
96
  const committed = settingsTabs.some(
89
97
  (t) => t.pluginId === pluginId && t.id === contribution.id,
90
98
  );
91
- if (stagedTabIds.has(contribution.id) || committed) {
99
+ if (staged.tabIds.has(contribution.id) || committed) {
92
100
  // A duplicate tab id within one plugin would leave one tab unreachable —
93
101
  // fail loudly, mirroring the page-path guard.
94
102
  throw new Error(
95
103
  `plugin “${pluginId}” already registered a settings tab “${contribution.id}”`,
96
104
  );
97
105
  }
98
- stagedTabIds.add(contribution.id);
99
- stagedSettingsTabs.push({ ...contribution, pluginId });
106
+ staged.tabIds.add(contribution.id);
107
+ staged.settingsTabs.push({ ...contribution, pluginId });
100
108
  },
101
109
  registerNavEntry(contribution: NavEntryContribution): void {
102
- if (sealed) {
103
- throw new Error(
104
- 'registration is closed: a plugin must register during register(), not after it resolves',
105
- );
106
- }
107
- const staged = stagedNavEntries.some((e) => e.path === contribution.path);
108
- const committed = navEntries.some(
109
- (e) => e.pluginId === pluginId && e.path === contribution.path,
110
- );
111
- if (staged || committed) {
110
+ assertOpen();
111
+ const duplicate =
112
+ staged.navEntries.some((e) => e.path === contribution.path) ||
113
+ navEntries.some((e) => e.pluginId === pluginId && e.path === contribution.path);
114
+ if (duplicate) {
112
115
  // A duplicate nav path within one plugin is an author mistake — two
113
116
  // entries pointing at the same page — so fail loudly like the page guard.
114
117
  throw new Error(
115
118
  `plugin “${pluginId}” already registered a nav entry at “${contribution.path}”`,
116
119
  );
117
120
  }
118
- stagedNavEntries.push({ ...contribution, pluginId });
121
+ staged.navEntries.push({ ...contribution, pluginId });
119
122
  },
120
123
  };
124
+ }
121
125
 
122
- try {
123
- await entry(context);
124
- } finally {
125
- // Whether `entry` resolved or threw, no further registration is valid — seal
126
- // so a deferred call fails loudly rather than pushing into an orphaned array.
127
- sealed = true;
128
- }
129
-
130
- // Every nav entry must link to a page THIS plugin registers — staged in this
131
- // call or already committed. A nav entry with no matching page is a guaranteed
132
- // dead link (the plugin page surface renders "Page not found"), so reject it
133
- // loudly. This throws BEFORE the commit loops, so it propagates out of
134
- // `loadPlugin` and NOTHING (pages, panels, tabs, nav) commits — atomicity holds.
135
- for (const navEntry of stagedNavEntries) {
126
+ /**
127
+ * Every nav entry must link to a page THIS plugin registers — staged in this call or
128
+ * already committed. A nav entry with no matching page is a guaranteed dead link (the
129
+ * plugin page surface renders "Page not found"), so reject it loudly. Throwing here —
130
+ * BEFORE any commit — keeps atomicity: nothing (pages, panels, tabs, nav) commits.
131
+ */
132
+ function assertNavEntriesHavePages(pluginId: string, staged: StagedContributions): void {
133
+ for (const navEntry of staged.navEntries) {
136
134
  const hasPage =
137
- stagedPages.some((p) => p.path === navEntry.path) ||
135
+ staged.pages.some((p) => p.path === navEntry.path) ||
138
136
  pages.some((p) => p.pluginId === pluginId && p.path === navEntry.path);
139
137
  if (!hasPage) {
140
138
  throw new Error(
@@ -142,22 +140,45 @@ export async function loadPlugin(pluginId: string, entry: PluginEntry): Promise<
142
140
  );
143
141
  }
144
142
  }
143
+ }
145
144
 
146
- // `entry` resolved without throwing: commit the staged contributions as one
147
- // batch, so the registry only ever holds a plugin's complete set — never a
148
- // partial set left behind by a mid-registration failure.
149
- for (const page of stagedPages) {
150
- pages.push(page);
151
- }
152
- for (const [toolName, contribution] of stagedToolPanels) {
153
- toolPanels.set(toolName, contribution);
154
- }
155
- for (const tab of stagedSettingsTabs) {
156
- settingsTabs.push(tab);
157
- }
158
- for (const navEntry of stagedNavEntries) {
159
- navEntries.push(navEntry);
145
+ /**
146
+ * Commit the staged contributions as one batch, so the registry only ever holds a
147
+ * plugin's complete set — never a partial set left behind by a mid-registration failure.
148
+ */
149
+ function commitStaged(staged: StagedContributions): void {
150
+ for (const page of staged.pages) pages.push(page);
151
+ for (const [toolName, contribution] of staged.toolPanels) toolPanels.set(toolName, contribution);
152
+ for (const tab of staged.settingsTabs) settingsTabs.push(tab);
153
+ for (const navEntry of staged.navEntries) navEntries.push(navEntry);
154
+ }
155
+
156
+ /**
157
+ * Load one plugin: call its `register` entry with a context bound to `pluginId`,
158
+ * then commit everything it staged into the global registry.
159
+ *
160
+ * `entry` is AWAITED before commit, so a synchronous or an `async` entry is fully
161
+ * done first: a post-`await` throw skips the commit (atomicity holds for async too)
162
+ * and a post-`await` registration cannot slip past the batch. The seal is set after
163
+ * `entry` has SETTLED, so a later registration throws loudly; registrations made
164
+ * during `entry`'s synchronous body — including a microtask it enqueues then — are
165
+ * still captured and committed. A `register` that throws commits nothing.
166
+ */
167
+ export async function loadPlugin(pluginId: string, entry: PluginEntry): Promise<void> {
168
+ const staged = emptyStaged();
169
+ const seal: Seal = { closed: false };
170
+ const context = makeStagingContext(pluginId, staged, seal);
171
+
172
+ try {
173
+ await entry(context);
174
+ } finally {
175
+ // Whether `entry` resolved or threw, no further registration is valid — seal
176
+ // so a deferred call fails loudly rather than pushing into an orphaned array.
177
+ seal.closed = true;
160
178
  }
179
+
180
+ assertNavEntriesHavePages(pluginId, staged);
181
+ commitStaged(staged);
161
182
  }
162
183
 
163
184
  /** The shell reads this after loading every installed plugin bundle. */
@@ -19,7 +19,7 @@
19
19
  * SAFETY: the schema text is operator-authored and every derived value renders as
20
20
  * React TEXT (through the DS controls / `JsonTree` / `SchemaForm`), never an HTML sink.
21
21
  */
22
- import { Component, useMemo, useState, type ReactNode } from 'react';
22
+ import { Component, type ReactNode, useMemo, useState } from 'react';
23
23
 
24
24
  import { Field } from '../components/field';
25
25
  import { Textarea } from '../components/inputs';
@@ -3,7 +3,7 @@
3
3
  * surface: the `SchemaEditor` component, its change type, and the pure lint helper
4
4
  * consumers reuse to pre-check a stored schema.
5
5
  */
6
- export { SchemaEditor } from './SchemaEditor';
7
- export type { SchemaEditorProps, SchemaEditorChange } from './SchemaEditor';
8
- export { lintSchemaText } from './lint';
9
6
  export type { SchemaLintResult } from './lint';
7
+ export { lintSchemaText } from './lint';
8
+ export type { SchemaEditorChange, SchemaEditorProps } from './SchemaEditor';
9
+ export { SchemaEditor } from './SchemaEditor';