@tai42/studio-sdk 0.2.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 (422) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +15 -0
  3. package/README.md +318 -0
  4. package/SECURITY.md +51 -0
  5. package/dist/components/badge.d.ts +13 -0
  6. package/dist/components/badge.d.ts.map +1 -0
  7. package/dist/components/badge.js +14 -0
  8. package/dist/components/badge.js.map +1 -0
  9. package/dist/components/checkbox.d.ts +24 -0
  10. package/dist/components/checkbox.d.ts.map +1 -0
  11. package/dist/components/checkbox.js +31 -0
  12. package/dist/components/checkbox.js.map +1 -0
  13. package/dist/components/code-block.d.ts +7 -0
  14. package/dist/components/code-block.d.ts.map +1 -0
  15. package/dist/components/code-block.js +23 -0
  16. package/dist/components/code-block.js.map +1 -0
  17. package/dist/components/completion-input.d.ts +31 -0
  18. package/dist/components/completion-input.d.ts.map +1 -0
  19. package/dist/components/completion-input.js +61 -0
  20. package/dist/components/completion-input.js.map +1 -0
  21. package/dist/components/components.css +2212 -0
  22. package/dist/components/confirm-dialog.d.ts +40 -0
  23. package/dist/components/confirm-dialog.d.ts.map +1 -0
  24. package/dist/components/confirm-dialog.js +11 -0
  25. package/dist/components/confirm-dialog.js.map +1 -0
  26. package/dist/components/control-styles.d.ts +12 -0
  27. package/dist/components/control-styles.d.ts.map +1 -0
  28. package/dist/components/control-styles.js +14 -0
  29. package/dist/components/control-styles.js.map +1 -0
  30. package/dist/components/copy-field.d.ts +8 -0
  31. package/dist/components/copy-field.d.ts.map +1 -0
  32. package/dist/components/copy-field.js +106 -0
  33. package/dist/components/copy-field.js.map +1 -0
  34. package/dist/components/dialog.d.ts +21 -0
  35. package/dist/components/dialog.d.ts.map +1 -0
  36. package/dist/components/dialog.js +25 -0
  37. package/dist/components/dialog.js.map +1 -0
  38. package/dist/components/drawer.d.ts +22 -0
  39. package/dist/components/drawer.d.ts.map +1 -0
  40. package/dist/components/drawer.js +32 -0
  41. package/dist/components/drawer.js.map +1 -0
  42. package/dist/components/error-boundary.d.ts +33 -0
  43. package/dist/components/error-boundary.d.ts.map +1 -0
  44. package/dist/components/error-boundary.js +36 -0
  45. package/dist/components/error-boundary.js.map +1 -0
  46. package/dist/components/extension-combo-builder.d.ts +70 -0
  47. package/dist/components/extension-combo-builder.d.ts.map +1 -0
  48. package/dist/components/extension-combo-builder.js +154 -0
  49. package/dist/components/extension-combo-builder.js.map +1 -0
  50. package/dist/components/extension-grouping.d.ts +65 -0
  51. package/dist/components/extension-grouping.d.ts.map +1 -0
  52. package/dist/components/extension-grouping.js +78 -0
  53. package/dist/components/extension-grouping.js.map +1 -0
  54. package/dist/components/extension-picker.d.ts +35 -0
  55. package/dist/components/extension-picker.d.ts.map +1 -0
  56. package/dist/components/extension-picker.js +31 -0
  57. package/dist/components/extension-picker.js.map +1 -0
  58. package/dist/components/external-link.d.ts +19 -0
  59. package/dist/components/external-link.d.ts.map +1 -0
  60. package/dist/components/external-link.js +12 -0
  61. package/dist/components/external-link.js.map +1 -0
  62. package/dist/components/field.d.ts +64 -0
  63. package/dist/components/field.d.ts.map +1 -0
  64. package/dist/components/field.js +56 -0
  65. package/dist/components/field.js.map +1 -0
  66. package/dist/components/fleet-report.d.ts +39 -0
  67. package/dist/components/fleet-report.d.ts.map +1 -0
  68. package/dist/components/fleet-report.js +50 -0
  69. package/dist/components/fleet-report.js.map +1 -0
  70. package/dist/components/fonts.css +22 -0
  71. package/dist/components/icons.d.ts +142 -0
  72. package/dist/components/icons.d.ts.map +1 -0
  73. package/dist/components/icons.js +139 -0
  74. package/dist/components/icons.js.map +1 -0
  75. package/dist/components/inputs.d.ts +52 -0
  76. package/dist/components/inputs.d.ts.map +1 -0
  77. package/dist/components/inputs.js +35 -0
  78. package/dist/components/inputs.js.map +1 -0
  79. package/dist/components/json-diff.d.ts +40 -0
  80. package/dist/components/json-diff.d.ts.map +1 -0
  81. package/dist/components/json-diff.js +119 -0
  82. package/dist/components/json-diff.js.map +1 -0
  83. package/dist/components/json-tree.d.ts +8 -0
  84. package/dist/components/json-tree.d.ts.map +1 -0
  85. package/dist/components/json-tree.js +70 -0
  86. package/dist/components/json-tree.js.map +1 -0
  87. package/dist/components/modal-focus.d.ts +15 -0
  88. package/dist/components/modal-focus.d.ts.map +1 -0
  89. package/dist/components/modal-focus.js +136 -0
  90. package/dist/components/modal-focus.js.map +1 -0
  91. package/dist/components/page-header.d.ts +56 -0
  92. package/dist/components/page-header.d.ts.map +1 -0
  93. package/dist/components/page-header.js +24 -0
  94. package/dist/components/page-header.js.map +1 -0
  95. package/dist/components/primitives.d.ts +186 -0
  96. package/dist/components/primitives.d.ts.map +1 -0
  97. package/dist/components/primitives.js +204 -0
  98. package/dist/components/primitives.js.map +1 -0
  99. package/dist/components/progress-bar.d.ts +29 -0
  100. package/dist/components/progress-bar.d.ts.map +1 -0
  101. package/dist/components/progress-bar.js +48 -0
  102. package/dist/components/progress-bar.js.map +1 -0
  103. package/dist/components/radio-group.d.ts +37 -0
  104. package/dist/components/radio-group.d.ts.map +1 -0
  105. package/dist/components/radio-group.js +56 -0
  106. package/dist/components/radio-group.js.map +1 -0
  107. package/dist/components/reveal-input.d.ts +13 -0
  108. package/dist/components/reveal-input.d.ts.map +1 -0
  109. package/dist/components/reveal-input.js +31 -0
  110. package/dist/components/reveal-input.js.map +1 -0
  111. package/dist/components/scroll-region.d.ts +85 -0
  112. package/dist/components/scroll-region.d.ts.map +1 -0
  113. package/dist/components/scroll-region.js +574 -0
  114. package/dist/components/scroll-region.js.map +1 -0
  115. package/dist/components/select.d.ts +53 -0
  116. package/dist/components/select.d.ts.map +1 -0
  117. package/dist/components/select.js +33 -0
  118. package/dist/components/select.js.map +1 -0
  119. package/dist/components/table.d.ts +59 -0
  120. package/dist/components/table.d.ts.map +1 -0
  121. package/dist/components/table.js +20 -0
  122. package/dist/components/table.js.map +1 -0
  123. package/dist/components/tabs.d.ts +15 -0
  124. package/dist/components/tabs.d.ts.map +1 -0
  125. package/dist/components/tabs.js +13 -0
  126. package/dist/components/tabs.js.map +1 -0
  127. package/dist/components/tags.d.ts +46 -0
  128. package/dist/components/tags.d.ts.map +1 -0
  129. package/dist/components/tags.js +68 -0
  130. package/dist/components/tags.js.map +1 -0
  131. package/dist/components/tokens.css +392 -0
  132. package/dist/components/tokens.d.ts +15 -0
  133. package/dist/components/tokens.d.ts.map +1 -0
  134. package/dist/components/tokens.js +101 -0
  135. package/dist/components/tokens.js.map +1 -0
  136. package/dist/components/tool-picker.d.ts +24 -0
  137. package/dist/components/tool-picker.d.ts.map +1 -0
  138. package/dist/components/tool-picker.js +97 -0
  139. package/dist/components/tool-picker.js.map +1 -0
  140. package/dist/components/tooltip.d.ts +17 -0
  141. package/dist/components/tooltip.d.ts.map +1 -0
  142. package/dist/components/tooltip.js +18 -0
  143. package/dist/components/tooltip.js.map +1 -0
  144. package/dist/components/version-history-panel.d.ts +71 -0
  145. package/dist/components/version-history-panel.d.ts.map +1 -0
  146. package/dist/components/version-history-panel.js +148 -0
  147. package/dist/components/version-history-panel.js.map +1 -0
  148. package/dist/download.d.ts +7 -0
  149. package/dist/download.d.ts.map +1 -0
  150. package/dist/download.js +18 -0
  151. package/dist/download.js.map +1 -0
  152. package/dist/element-slot.d.ts +4 -0
  153. package/dist/element-slot.d.ts.map +1 -0
  154. package/dist/element-slot.js +20 -0
  155. package/dist/element-slot.js.map +1 -0
  156. package/dist/elicitation/ElicitationForm.d.ts +34 -0
  157. package/dist/elicitation/ElicitationForm.d.ts.map +1 -0
  158. package/dist/elicitation/ElicitationForm.js +24 -0
  159. package/dist/elicitation/ElicitationForm.js.map +1 -0
  160. package/dist/errors.d.ts +9 -0
  161. package/dist/errors.d.ts.map +1 -0
  162. package/dist/errors.js +15 -0
  163. package/dist/errors.js.map +1 -0
  164. package/dist/extension-combos.d.ts +13 -0
  165. package/dist/extension-combos.d.ts.map +1 -0
  166. package/dist/extension-combos.js +9 -0
  167. package/dist/extension-combos.js.map +1 -0
  168. package/dist/hooks/useApi.d.ts +1222 -0
  169. package/dist/hooks/useApi.d.ts.map +1 -0
  170. package/dist/hooks/useApi.js +22 -0
  171. package/dist/hooks/useApi.js.map +1 -0
  172. package/dist/hooks/useAuth.d.ts +13 -0
  173. package/dist/hooks/useAuth.d.ts.map +1 -0
  174. package/dist/hooks/useAuth.js +53 -0
  175. package/dist/hooks/useAuth.js.map +1 -0
  176. package/dist/hooks/useBreakpoint.d.ts +10 -0
  177. package/dist/hooks/useBreakpoint.d.ts.map +1 -0
  178. package/dist/hooks/useBreakpoint.js +66 -0
  179. package/dist/hooks/useBreakpoint.js.map +1 -0
  180. package/dist/hooks/useCapabilities.d.ts +88 -0
  181. package/dist/hooks/useCapabilities.d.ts.map +1 -0
  182. package/dist/hooks/useCapabilities.js +203 -0
  183. package/dist/hooks/useCapabilities.js.map +1 -0
  184. package/dist/hooks/useSse.d.ts +13 -0
  185. package/dist/hooks/useSse.d.ts.map +1 -0
  186. package/dist/hooks/useSse.js +298 -0
  187. package/dist/hooks/useSse.js.map +1 -0
  188. package/dist/hooks/useTheme.d.ts +20 -0
  189. package/dist/hooks/useTheme.d.ts.map +1 -0
  190. package/dist/hooks/useTheme.js +97 -0
  191. package/dist/hooks/useTheme.js.map +1 -0
  192. package/dist/hooks/useUnauthorized.d.ts +3 -0
  193. package/dist/hooks/useUnauthorized.d.ts.map +1 -0
  194. package/dist/hooks/useUnauthorized.js +18 -0
  195. package/dist/hooks/useUnauthorized.js.map +1 -0
  196. package/dist/host.d.ts +11 -0
  197. package/dist/host.d.ts.map +1 -0
  198. package/dist/host.js +10 -0
  199. package/dist/host.js.map +1 -0
  200. package/dist/index.d.ts +118 -0
  201. package/dist/index.d.ts.map +1 -0
  202. package/dist/index.js +91 -0
  203. package/dist/index.js.map +1 -0
  204. package/dist/navigation/context.d.ts +25 -0
  205. package/dist/navigation/context.d.ts.map +1 -0
  206. package/dist/navigation/context.js +45 -0
  207. package/dist/navigation/context.js.map +1 -0
  208. package/dist/navigation/index.d.ts +4 -0
  209. package/dist/navigation/index.d.ts.map +1 -0
  210. package/dist/navigation/index.js +2 -0
  211. package/dist/navigation/index.js.map +1 -0
  212. package/dist/navigation/types.d.ts +97 -0
  213. package/dist/navigation/types.d.ts.map +1 -0
  214. package/dist/navigation/types.js +16 -0
  215. package/dist/navigation/types.js.map +1 -0
  216. package/dist/plugin/host-state.d.ts +45 -0
  217. package/dist/plugin/host-state.d.ts.map +1 -0
  218. package/dist/plugin/host-state.js +62 -0
  219. package/dist/plugin/host-state.js.map +1 -0
  220. package/dist/plugin/registry.d.ts +35 -0
  221. package/dist/plugin/registry.d.ts.map +1 -0
  222. package/dist/plugin/registry.js +129 -0
  223. package/dist/plugin/registry.js.map +1 -0
  224. package/dist/plugin/types.d.ts +165 -0
  225. package/dist/plugin/types.d.ts.map +1 -0
  226. package/dist/plugin/types.js +2 -0
  227. package/dist/plugin/types.js.map +1 -0
  228. package/dist/plugin/version.d.ts +34 -0
  229. package/dist/plugin/version.d.ts.map +1 -0
  230. package/dist/plugin/version.js +37 -0
  231. package/dist/plugin/version.js.map +1 -0
  232. package/dist/query-keys.d.ts +31 -0
  233. package/dist/query-keys.d.ts.map +1 -0
  234. package/dist/query-keys.js +31 -0
  235. package/dist/query-keys.js.map +1 -0
  236. package/dist/schema-editor/SchemaEditor.d.ts +43 -0
  237. package/dist/schema-editor/SchemaEditor.d.ts.map +1 -0
  238. package/dist/schema-editor/SchemaEditor.js +106 -0
  239. package/dist/schema-editor/SchemaEditor.js.map +1 -0
  240. package/dist/schema-editor/index.d.ts +10 -0
  241. package/dist/schema-editor/index.d.ts.map +1 -0
  242. package/dist/schema-editor/index.js +8 -0
  243. package/dist/schema-editor/index.js.map +1 -0
  244. package/dist/schema-editor/lint.d.ts +37 -0
  245. package/dist/schema-editor/lint.d.ts.map +1 -0
  246. package/dist/schema-editor/lint.js +49 -0
  247. package/dist/schema-editor/lint.js.map +1 -0
  248. package/dist/schema-form/SchemaForm.d.ts +70 -0
  249. package/dist/schema-form/SchemaForm.d.ts.map +1 -0
  250. package/dist/schema-form/SchemaForm.js +13 -0
  251. package/dist/schema-form/SchemaForm.js.map +1 -0
  252. package/dist/schema-form/array-field.d.ts +20 -0
  253. package/dist/schema-form/array-field.d.ts.map +1 -0
  254. package/dist/schema-form/array-field.js +39 -0
  255. package/dist/schema-form/array-field.js.map +1 -0
  256. package/dist/schema-form/classify.d.ts +87 -0
  257. package/dist/schema-form/classify.d.ts.map +1 -0
  258. package/dist/schema-form/classify.js +199 -0
  259. package/dist/schema-form/classify.js.map +1 -0
  260. package/dist/schema-form/context.d.ts +4 -0
  261. package/dist/schema-form/context.d.ts.map +1 -0
  262. package/dist/schema-form/context.js +14 -0
  263. package/dist/schema-form/context.js.map +1 -0
  264. package/dist/schema-form/default-value.d.ts +8 -0
  265. package/dist/schema-form/default-value.d.ts.map +1 -0
  266. package/dist/schema-form/default-value.js +64 -0
  267. package/dist/schema-form/default-value.js.map +1 -0
  268. package/dist/schema-form/enum-field.d.ts +19 -0
  269. package/dist/schema-form/enum-field.d.ts.map +1 -0
  270. package/dist/schema-form/enum-field.js +26 -0
  271. package/dist/schema-form/enum-field.js.map +1 -0
  272. package/dist/schema-form/field-group.d.ts +9 -0
  273. package/dist/schema-form/field-group.d.ts.map +1 -0
  274. package/dist/schema-form/field-group.js +32 -0
  275. package/dist/schema-form/field-group.js.map +1 -0
  276. package/dist/schema-form/field-node.d.ts +24 -0
  277. package/dist/schema-form/field-node.d.ts.map +1 -0
  278. package/dist/schema-form/field-node.js +51 -0
  279. package/dist/schema-form/field-node.js.map +1 -0
  280. package/dist/schema-form/index.d.ts +13 -0
  281. package/dist/schema-form/index.d.ts.map +1 -0
  282. package/dist/schema-form/index.js +11 -0
  283. package/dist/schema-form/index.js.map +1 -0
  284. package/dist/schema-form/media-field.d.ts +24 -0
  285. package/dist/schema-form/media-field.d.ts.map +1 -0
  286. package/dist/schema-form/media-field.js +169 -0
  287. package/dist/schema-form/media-field.js.map +1 -0
  288. package/dist/schema-form/media.d.ts +40 -0
  289. package/dist/schema-form/media.d.ts.map +1 -0
  290. package/dist/schema-form/media.js +65 -0
  291. package/dist/schema-form/media.js.map +1 -0
  292. package/dist/schema-form/object-fields.d.ts +20 -0
  293. package/dist/schema-form/object-fields.d.ts.map +1 -0
  294. package/dist/schema-form/object-fields.js +24 -0
  295. package/dist/schema-form/object-fields.js.map +1 -0
  296. package/dist/schema-form/resolve.d.ts +41 -0
  297. package/dist/schema-form/resolve.d.ts.map +1 -0
  298. package/dist/schema-form/resolve.js +102 -0
  299. package/dist/schema-form/resolve.js.map +1 -0
  300. package/dist/schema-form/string-field.d.ts +20 -0
  301. package/dist/schema-form/string-field.d.ts.map +1 -0
  302. package/dist/schema-form/string-field.js +68 -0
  303. package/dist/schema-form/string-field.js.map +1 -0
  304. package/dist/schema-form/styles.d.ts +18 -0
  305. package/dist/schema-form/styles.d.ts.map +1 -0
  306. package/dist/schema-form/styles.js +18 -0
  307. package/dist/schema-form/styles.js.map +1 -0
  308. package/dist/schema-form/types.d.ts +67 -0
  309. package/dist/schema-form/types.d.ts.map +1 -0
  310. package/dist/schema-form/types.js +10 -0
  311. package/dist/schema-form/types.js.map +1 -0
  312. package/dist/schema-form/union-field.d.ts +24 -0
  313. package/dist/schema-form/union-field.d.ts.map +1 -0
  314. package/dist/schema-form/union-field.js +55 -0
  315. package/dist/schema-form/union-field.js.map +1 -0
  316. package/dist/schema-form/union.d.ts +4 -0
  317. package/dist/schema-form/union.d.ts.map +1 -0
  318. package/dist/schema-form/union.js +68 -0
  319. package/dist/schema-form/union.js.map +1 -0
  320. package/dist/schema-form/unsupported-notice.d.ts +18 -0
  321. package/dist/schema-form/unsupported-notice.d.ts.map +1 -0
  322. package/dist/schema-form/unsupported-notice.js +8 -0
  323. package/dist/schema-form/unsupported-notice.js.map +1 -0
  324. package/dist/schema-form/validate.d.ts +18 -0
  325. package/dist/schema-form/validate.d.ts.map +1 -0
  326. package/dist/schema-form/validate.js +162 -0
  327. package/dist/schema-form/validate.js.map +1 -0
  328. package/dist/structured-output/StructuredOutput.d.ts +27 -0
  329. package/dist/structured-output/StructuredOutput.d.ts.map +1 -0
  330. package/dist/structured-output/StructuredOutput.js +41 -0
  331. package/dist/structured-output/StructuredOutput.js.map +1 -0
  332. package/dist/testing.d.ts +80 -0
  333. package/dist/testing.d.ts.map +1 -0
  334. package/dist/testing.js +207 -0
  335. package/dist/testing.js.map +1 -0
  336. package/package.json +101 -0
  337. package/src/components/badge.tsx +31 -0
  338. package/src/components/checkbox.tsx +93 -0
  339. package/src/components/code-block.tsx +37 -0
  340. package/src/components/completion-input.tsx +137 -0
  341. package/src/components/components.css +2212 -0
  342. package/src/components/confirm-dialog.tsx +77 -0
  343. package/src/components/control-styles.ts +14 -0
  344. package/src/components/copy-field.tsx +178 -0
  345. package/src/components/dialog.tsx +76 -0
  346. package/src/components/drawer.tsx +83 -0
  347. package/src/components/error-boundary.tsx +56 -0
  348. package/src/components/extension-combo-builder.tsx +305 -0
  349. package/src/components/extension-grouping.ts +116 -0
  350. package/src/components/extension-picker.tsx +97 -0
  351. package/src/components/external-link.tsx +40 -0
  352. package/src/components/field.tsx +169 -0
  353. package/src/components/fleet-report.tsx +136 -0
  354. package/src/components/fonts.css +22 -0
  355. package/src/components/icons.tsx +504 -0
  356. package/src/components/inputs.tsx +125 -0
  357. package/src/components/json-diff.tsx +192 -0
  358. package/src/components/json-tree.tsx +129 -0
  359. package/src/components/modal-focus.ts +150 -0
  360. package/src/components/page-header.tsx +107 -0
  361. package/src/components/primitives.tsx +489 -0
  362. package/src/components/progress-bar.tsx +100 -0
  363. package/src/components/radio-group.tsx +160 -0
  364. package/src/components/reveal-input.tsx +87 -0
  365. package/src/components/scroll-region.tsx +703 -0
  366. package/src/components/select.tsx +149 -0
  367. package/src/components/table.tsx +94 -0
  368. package/src/components/tabs.tsx +51 -0
  369. package/src/components/tags.tsx +137 -0
  370. package/src/components/tokens.css +392 -0
  371. package/src/components/tokens.ts +102 -0
  372. package/src/components/tool-picker.tsx +175 -0
  373. package/src/components/tooltip.tsx +46 -0
  374. package/src/components/version-history-panel.tsx +407 -0
  375. package/src/css.d.ts +2 -0
  376. package/src/download.ts +17 -0
  377. package/src/element-slot.ts +22 -0
  378. package/src/elicitation/ElicitationForm.tsx +87 -0
  379. package/src/errors.ts +12 -0
  380. package/src/extension-combos.ts +18 -0
  381. package/src/hooks/useApi.ts +27 -0
  382. package/src/hooks/useAuth.ts +67 -0
  383. package/src/hooks/useBreakpoint.ts +78 -0
  384. package/src/hooks/useCapabilities.ts +242 -0
  385. package/src/hooks/useSse.ts +314 -0
  386. package/src/hooks/useTheme.ts +133 -0
  387. package/src/hooks/useUnauthorized.ts +20 -0
  388. package/src/host.ts +15 -0
  389. package/src/index.ts +267 -0
  390. package/src/navigation/context.tsx +90 -0
  391. package/src/navigation/index.ts +9 -0
  392. package/src/navigation/types.ts +90 -0
  393. package/src/plugin/host-state.ts +93 -0
  394. package/src/plugin/registry.ts +174 -0
  395. package/src/plugin/types.ts +178 -0
  396. package/src/plugin/version.ts +44 -0
  397. package/src/query-keys.ts +34 -0
  398. package/src/schema-editor/SchemaEditor.tsx +186 -0
  399. package/src/schema-editor/index.ts +9 -0
  400. package/src/schema-editor/lint.ts +70 -0
  401. package/src/schema-form/SchemaForm.tsx +107 -0
  402. package/src/schema-form/array-field.tsx +110 -0
  403. package/src/schema-form/classify.ts +302 -0
  404. package/src/schema-form/context.ts +17 -0
  405. package/src/schema-form/default-value.ts +65 -0
  406. package/src/schema-form/enum-field.tsx +65 -0
  407. package/src/schema-form/field-group.tsx +71 -0
  408. package/src/schema-form/field-node.tsx +161 -0
  409. package/src/schema-form/index.ts +12 -0
  410. package/src/schema-form/media-field.tsx +281 -0
  411. package/src/schema-form/media.ts +69 -0
  412. package/src/schema-form/object-fields.tsx +74 -0
  413. package/src/schema-form/resolve.ts +114 -0
  414. package/src/schema-form/string-field.tsx +161 -0
  415. package/src/schema-form/styles.ts +20 -0
  416. package/src/schema-form/types.ts +71 -0
  417. package/src/schema-form/union-field.tsx +122 -0
  418. package/src/schema-form/union.ts +78 -0
  419. package/src/schema-form/unsupported-notice.tsx +39 -0
  420. package/src/schema-form/validate.ts +183 -0
  421. package/src/structured-output/StructuredOutput.tsx +81 -0
  422. package/src/testing.ts +235 -0
@@ -0,0 +1,67 @@
1
+ /**
2
+ * `useAuth` — the API-key credential, held IN MEMORY by default (lost on reload →
3
+ * re-enter). An explicit "remember on this device" opt-in persists to
4
+ * sessionStorage. localStorage is NEVER written: the README documents the
5
+ * XSS trade-off and why localStorage persistence is not offered.
6
+ */
7
+ import { createContext, useCallback, useContext, useMemo, useState } from 'react';
8
+ import type { ReactNode } from 'react';
9
+ import { createElement } from 'react';
10
+
11
+ const SESSION_KEY = 'tai-studio.apiKey';
12
+
13
+ export interface AuthState {
14
+ readonly token: string | null;
15
+ readonly isAuthenticated: boolean;
16
+ /** Store the key; `remember` persists to sessionStorage for this device. */
17
+ readonly login: (token: string, remember: boolean) => void;
18
+ readonly logout: () => void;
19
+ }
20
+
21
+ const AuthContext = createContext<AuthState | null>(null);
22
+
23
+ function readSession(): string | null {
24
+ try {
25
+ return globalThis.sessionStorage.getItem(SESSION_KEY);
26
+ } catch {
27
+ return null;
28
+ }
29
+ }
30
+
31
+ export function AuthProvider({ children }: { children: ReactNode }) {
32
+ // Seed from sessionStorage (a prior "remember" opt-in) if present.
33
+ const [token, setToken] = useState<string | null>(() => readSession());
34
+
35
+ const login = useCallback((next: string, remember: boolean) => {
36
+ setToken(next);
37
+ try {
38
+ if (remember) globalThis.sessionStorage.setItem(SESSION_KEY, next);
39
+ else globalThis.sessionStorage.removeItem(SESSION_KEY);
40
+ // localStorage is intentionally never touched.
41
+ } catch {
42
+ // Storage unavailable (private mode) — the in-memory token still works.
43
+ }
44
+ }, []);
45
+
46
+ const logout = useCallback(() => {
47
+ setToken(null);
48
+ try {
49
+ globalThis.sessionStorage.removeItem(SESSION_KEY);
50
+ } catch {
51
+ /* ignore */
52
+ }
53
+ }, []);
54
+
55
+ const value = useMemo<AuthState>(
56
+ () => ({ token, isAuthenticated: token !== null, login, logout }),
57
+ [token, login, logout],
58
+ );
59
+
60
+ return createElement(AuthContext.Provider, { value }, children);
61
+ }
62
+
63
+ export function useAuth(): AuthState {
64
+ const state = useContext(AuthContext);
65
+ if (state === null) throw new Error('useAuth must be used within an <AuthProvider>');
66
+ return state;
67
+ }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * `useBreakpoint` — the JS half of the responsive layer, reporting which of the
3
+ * four viewport bands is current and keeping the boundaries in lockstep with the
4
+ * `max-width` media queries in `components.css`. Layout that CSS can express
5
+ * stays in CSS; this hook is for the decisions CSS cannot make, where a surface
6
+ * must render DIFFERENT markup per band rather than restyle the same markup —
7
+ * mounting one pane of a master/detail split instead of two, say, rather than
8
+ * hiding the second.
9
+ *
10
+ * The queries are `max-width` on purpose: when nothing matches, the band
11
+ * resolves to `full`. That is also the answer in a DOM without `matchMedia`
12
+ * (jsdom), where a desktop default is the only safe assumption — a phone
13
+ * default would silently change what every feature's tests render.
14
+ */
15
+ import { useMemo, useSyncExternalStore } from 'react';
16
+
17
+ export type Breakpoint = 'phone' | 'compact' | 'medium' | 'full';
18
+
19
+ export interface BreakpointState {
20
+ readonly band: Breakpoint;
21
+ /** True below 640 — the `phone` band, where a surface has one column to work in. */
22
+ readonly isPhone: boolean;
23
+ /** True below 1024 — too narrow for two panes side by side. */
24
+ readonly isSinglePane: boolean;
25
+ }
26
+
27
+ const PHONE_QUERY = '(max-width: 639px)';
28
+ const COMPACT_QUERY = '(max-width: 1023px)';
29
+ const MEDIUM_QUERY = '(max-width: 1279px)';
30
+
31
+ const BAND_QUERIES = [PHONE_QUERY, COMPACT_QUERY, MEDIUM_QUERY] as const;
32
+
33
+ /**
34
+ * `matchMedia` is feature-detected rather than guarded by a swallowed
35
+ * exception, so a real failure inside the media-query layer still throws.
36
+ */
37
+ function hasMatchMedia(): boolean {
38
+ return typeof globalThis.matchMedia === 'function';
39
+ }
40
+
41
+ function readBand(): Breakpoint {
42
+ if (!hasMatchMedia()) return 'full';
43
+ if (globalThis.matchMedia(PHONE_QUERY).matches) return 'phone';
44
+ if (globalThis.matchMedia(COMPACT_QUERY).matches) return 'compact';
45
+ if (globalThis.matchMedia(MEDIUM_QUERY).matches) return 'medium';
46
+ return 'full';
47
+ }
48
+
49
+ /**
50
+ * Subscribes to the three band boundaries. A `MediaQueryList` notifies only when
51
+ * its match state flips, so a resize inside a band never reaches React.
52
+ */
53
+ function subscribe(onBandChange: () => void): () => void {
54
+ if (!hasMatchMedia()) {
55
+ return () => {
56
+ // No `matchMedia`: the band is fixed at `full` and can never change.
57
+ };
58
+ }
59
+ const lists = BAND_QUERIES.map((query) => globalThis.matchMedia(query));
60
+ for (const list of lists) list.addEventListener('change', onBandChange);
61
+ return () => {
62
+ for (const list of lists) list.removeEventListener('change', onBandChange);
63
+ };
64
+ }
65
+
66
+ export function useBreakpoint(): BreakpointState {
67
+ // The snapshot is a plain string, so React re-renders only when the BAND
68
+ // changes even though several boundaries can notify for one resize.
69
+ const band = useSyncExternalStore(subscribe, readBand, readBand);
70
+ return useMemo<BreakpointState>(
71
+ () => ({
72
+ band,
73
+ isPhone: band === 'phone',
74
+ isSinglePane: band === 'phone' || band === 'compact',
75
+ }),
76
+ [band],
77
+ );
78
+ }
@@ -0,0 +1,242 @@
1
+ /**
2
+ * `useCapabilities` — the caller's capability projection (`GET /api/auth/me`),
3
+ * fetched once per auth flip and held as SDK state. The UI is a projection of
4
+ * this: nav, pages, and plugin loading filter on what the projection says the
5
+ * caller can reach, and the server stays the sole authority (projection ⊆ gate).
6
+ *
7
+ * A PLAIN fetch state machine (`loading` / `ready` / `failed`), NOT TanStack
8
+ * Query, and for the same reason the login page fetches its methods with plain
9
+ * `fetch`: the shell wipes the query cache around auth flips, so a
10
+ * query-cached projection would be dropped underneath the components that gate
11
+ * on it. This provider owns the projection lifecycle instead.
12
+ *
13
+ * FAILED IS LOUD AND BLOCKING: on a `/me` failure the shell renders an
14
+ * `ErrorState` with `retry` in the nav region — never an optimistic full nav on
15
+ * error. The UI fails closed exactly as the server would.
16
+ */
17
+ import {
18
+ createContext,
19
+ useCallback,
20
+ useContext,
21
+ useEffect,
22
+ useMemo,
23
+ useRef,
24
+ useState,
25
+ } from 'react';
26
+ import type { ReactNode } from 'react';
27
+ import { createElement } from 'react';
28
+ import type { MeProjection } from '@tai42/api-client';
29
+
30
+ import { useApi } from './useApi';
31
+ import { useAuth } from './useAuth';
32
+ import { useOnUnauthorized } from './useUnauthorized';
33
+
34
+ export type CapabilityState =
35
+ | { readonly status: 'loading' }
36
+ | { readonly status: 'ready'; readonly projection: MeProjection }
37
+ | { readonly status: 'failed'; readonly error: unknown };
38
+
39
+ export interface CapabilityContextValue {
40
+ readonly state: CapabilityState;
41
+ /** Re-fetch the projection (the nav-region `ErrorState`'s retry action). */
42
+ readonly retry: () => void;
43
+ }
44
+
45
+ const CapabilityContext = createContext<CapabilityContextValue | null>(null);
46
+
47
+ export function CapabilityProvider({ children }: { children: ReactNode }) {
48
+ const { isAuthenticated, token } = useAuth();
49
+ const api = useApi();
50
+ const onUnauthorized = useOnUnauthorized();
51
+ const [state, setState] = useState<CapabilityState>({ status: 'loading' });
52
+ const [attempt, setAttempt] = useState(0);
53
+
54
+ // Re-project when the ACTIVE CREDENTIAL changes, not only on the authenticated
55
+ // flip: a credential swap that stays authenticated (a fresh key pasted over a
56
+ // live session) must drop the prior identity's projection. Track the token via a
57
+ // ref and expose only a monotonic version to the fetch effect, so the raw secret
58
+ // never rides the effect's dependency array.
59
+ const tokenRef = useRef(token);
60
+ const [credentialVersion, setCredentialVersion] = useState(0);
61
+ if (tokenRef.current !== token) {
62
+ tokenRef.current = token;
63
+ setCredentialVersion((v) => v + 1);
64
+ }
65
+
66
+ const retry = useCallback(() => {
67
+ setAttempt((n) => n + 1);
68
+ }, []);
69
+
70
+ useEffect(() => {
71
+ if (!isAuthenticated) {
72
+ // No credential → nothing to project. Reset to the neutral `loading` state
73
+ // so the next sign-in re-fetches cleanly; the shell renders the login page
74
+ // (not the capability-gated nav) while unauthenticated.
75
+ setState({ status: 'loading' });
76
+ return;
77
+ }
78
+ const controller = new AbortController();
79
+ setState({ status: 'loading' });
80
+ api.getMe(controller.signal).then(
81
+ (projection) => {
82
+ if (controller.signal.aborted) return;
83
+ setState({ status: 'ready', projection });
84
+ },
85
+ (error: unknown) => {
86
+ if (controller.signal.aborted) return;
87
+ // A 401 means the stored credential is dead: route to login through the
88
+ // app's unauthorized handler (the same seam the api-client's 401 path
89
+ // drives) rather than settling into the retryable `failed` state against a
90
+ // known-bad key. Every other error stays a loud, retryable failure.
91
+ if (error instanceof Error && error.name === 'ApiUnauthorizedError') {
92
+ onUnauthorized();
93
+ return;
94
+ }
95
+ setState({ status: 'failed', error });
96
+ console.error(error);
97
+ },
98
+ );
99
+ return () => {
100
+ controller.abort();
101
+ };
102
+ }, [api, isAuthenticated, credentialVersion, attempt, onUnauthorized]);
103
+
104
+ const value = useMemo<CapabilityContextValue>(() => ({ state, retry }), [state, retry]);
105
+
106
+ return createElement(CapabilityContext.Provider, { value }, children);
107
+ }
108
+
109
+ export function useCapabilities(): CapabilityContextValue {
110
+ const value = useContext(CapabilityContext);
111
+ if (value === null) {
112
+ throw new Error('useCapabilities must be used within a <CapabilityProvider>');
113
+ }
114
+ return value;
115
+ }
116
+
117
+ /**
118
+ * Whether the projection is the synthetic TOTAL projection — the admin session
119
+ * (the condition-free ownerless `"*"` discriminator) and the gate-off local-dev
120
+ * projection alike. This is `projection.admin === true` and NOTHING else: a
121
+ * seeded editor/viewer carries `["*"]` scopes PLUS a jq fence, so keying on `"*"`
122
+ * scopes would hand every editor/viewer the unfiltered nav and a wall of 403s on
123
+ * the admin routes their fence denies. Keying on `admin` makes editor/viewer
124
+ * SCOPED sessions whose nav is filtered by their jq-exact `routes`, which is
125
+ * exactly right — and the gate-off synthetic projection (`admin: true`, empty
126
+ * `routes`) still reads as full, so an AC-disabled deployment shows everything.
127
+ */
128
+ export function isFullProjection(projection: MeProjection): boolean {
129
+ return projection.admin;
130
+ }
131
+
132
+ /**
133
+ * Whether a concrete path is `prefix` itself or nested beneath it at a PATH-SEGMENT
134
+ * boundary — the client mirror of the server's segment-aware coverage rule
135
+ * (access_control/settings.py: `a == b or a.startswith(b + '/')`). Matching on a
136
+ * bare `startsWith` would let a sibling route like `/api/tools-schema` satisfy the
137
+ * `/api/tools` token; the boundary keeps them distinct.
138
+ */
139
+ function pathUnderPrefix(path: string, prefix: string): boolean {
140
+ return path === prefix || path.startsWith(`${prefix}/`);
141
+ }
142
+
143
+ /**
144
+ * Whether the projection reaches ANY route under one of `prefixes` — the
145
+ * declarative test behind nav filtering and plugin `requiredCapabilities`. A
146
+ * concrete `routes[].path` covers a prefix when it is that prefix or a
147
+ * segment-nested descendant of it; a dynamic `route_patterns[].pattern` covers a
148
+ * prefix only when it is a simple anchored open-wildcard pattern (`^<literal>.*$`)
149
+ * whose open literal overlaps the prefix at a segment boundary.
150
+ *
151
+ * Under-showing is safe (projection is UX; the server is the authority);
152
+ * over-showing is the bug. So any non-anchored or otherwise complex pattern
153
+ * (alternation, char class, bounded quantifier) is conservatively treated as NOT
154
+ * covering — its matched set is not a clean prefix, so we never infer reach from
155
+ * it.
156
+ */
157
+ export function coversAnyRoute(projection: MeProjection, prefixes: readonly string[]): boolean {
158
+ return prefixes.some(
159
+ (prefix) =>
160
+ projection.routes.some((route) => pathUnderPrefix(route.path, prefix)) ||
161
+ projection.route_patterns.some((entry) => {
162
+ const open = patternOpenPrefix(entry.pattern);
163
+ // The open literal L means "every path starting with L is reachable". That
164
+ // set reaches something under `prefix` when the prefix itself lies in it
165
+ // (`prefix.startsWith(open)`) or when the literal already dives under the
166
+ // prefix at a segment boundary (`pathUnderPrefix(open, prefix)`).
167
+ return open !== null && (prefix.startsWith(open) || pathUnderPrefix(open, prefix));
168
+ }),
169
+ );
170
+ }
171
+
172
+ /**
173
+ * Whether the projection reaches a specific WRITE route — an EXACT `path` whose
174
+ * admitted `methods` include `method`. This is the method-aware companion to
175
+ * {@link coversAnyRoute}: a read/nav surface gates path-only (any method reaching a
176
+ * prefix means the surface is navigable), but an action that issues `method path`
177
+ * must gate on the method too, or a caller whose jq fence admits only GET on `path`
178
+ * would be shown a control that 403s on submit (projection ⊆ gate).
179
+ *
180
+ * Only concrete `routes` are consulted: dynamic `route_patterns` carry no method, so
181
+ * no write capability can be soundly inferred from them, and a synthetic TOTAL
182
+ * (admin) projection carries no concrete `routes` at all — callers short-circuit it
183
+ * with {@link isFullProjection} before reaching here. Under-showing is safe (the
184
+ * server stays the authority); over-showing an action the gate denies is the bug.
185
+ */
186
+ export function coversRoute(projection: MeProjection, path: string, method: string): boolean {
187
+ return projection.routes.some((route) => route.path === path && route.methods.includes(method));
188
+ }
189
+
190
+ /**
191
+ * Whether a WRITE control may be shown/enabled for this caller — the fail-closed,
192
+ * method-aware gate the features fold together with any deployment-level read-only flag
193
+ * (the projection ⊆ gate invariant, in one place). It is `true` ONLY once the projection
194
+ * is `ready` AND either it is a full (admin / gate-off) projection or it reaches
195
+ * `method path`. While the projection is loading/failed it is `false` — a write control
196
+ * never enables before the gate is known (fail closed; not-ready ⇒ disabled/read-only).
197
+ *
198
+ * Only concrete `routes` carry methods, so a DYNAMIC (templated) write route — one the
199
+ * projection can represent only as a method-less `route_patterns` row — reads `false` for
200
+ * every non-admin caller and degrades that control to read-only. Under-showing is safe
201
+ * (the server stays the authority); over-showing a write the gate denies is the bug.
202
+ */
203
+ export function coversWrite(state: CapabilityState, path: string, method: string): boolean {
204
+ return (
205
+ state.status === 'ready' &&
206
+ (isFullProjection(state.projection) || coversRoute(state.projection, path, method))
207
+ );
208
+ }
209
+
210
+ /**
211
+ * Whether a WRITE control may be shown for the current caller — the single boundary
212
+ * primitive a feature calls to hide a control whose `method path` the caller's
213
+ * projection cannot reach. It reads the live capability state and folds it through
214
+ * {@link coversWrite}: `true` only once the projection is `ready` AND it is a full
215
+ * (admin / gate-off) projection or it reaches `method path`; while the projection is
216
+ * loading/failed it is `false` (fail closed — no write control before the gate is
217
+ * known). `method` defaults to `POST`, the common write verb; pass the exact verb for
218
+ * a PUT/PATCH/DELETE control.
219
+ */
220
+ export function useCanWrite(path: string, method = 'POST'): boolean {
221
+ const { state } = useCapabilities();
222
+ return coversWrite(state, path, method);
223
+ }
224
+
225
+ const REGEX_METACHARACTERS = /[.*+?()[\]{}|\\^$]/;
226
+
227
+ /**
228
+ * The literal prefix of a simple anchored open-wildcard pattern (`^<literal>.*$`,
229
+ * the `$` optional), or `null` when the pattern is not exactly that shape. A
230
+ * returned literal `L` means "every path starting with `L` is reachable"; only
231
+ * that open-wildcard form yields a sound prefix, so a bare literal, an
232
+ * alternation, a char class, or any other construct declines (returns `null`).
233
+ */
234
+ function patternOpenPrefix(pattern: string): string | null {
235
+ if (!pattern.startsWith('^')) return null;
236
+ let body = pattern.slice(1);
237
+ if (body.endsWith('$')) body = body.slice(0, -1);
238
+ if (!body.endsWith('.*')) return null;
239
+ body = body.slice(0, -2);
240
+ if (body.length === 0 || REGEX_METACHARACTERS.test(body)) return null;
241
+ return body;
242
+ }