@cosmicdrift/kumiko-renderer 0.374.0 → 0.377.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 (455) hide show
  1. package/README.md +2 -2
  2. package/dist/app/action-form-support.d.ts +9 -2
  3. package/dist/app/action-form-support.js +24 -2
  4. package/dist/app/client-actions.d.ts +2 -2
  5. package/dist/app/column-renderers.js +1 -1
  6. package/dist/app/config-edit-shim.js +1 -1
  7. package/dist/app/content-preview.js +1 -6
  8. package/dist/app/custom-screens.js +1 -1
  9. package/dist/app/dashboard-body.d.ts +1 -1
  10. package/dist/app/entity-list-expanded-row.d.ts +1 -1
  11. package/dist/app/form-schema.d.ts +1 -1
  12. package/dist/app/form-schema.js +2 -2
  13. package/dist/app/kumiko-screen.d.ts +1 -1
  14. package/dist/app/kumiko-screen.js +7 -6
  15. package/dist/app/list-empty-content.d.ts +1 -1
  16. package/dist/app/list-facets.d.ts +1 -1
  17. package/dist/app/nav.js +2 -2
  18. package/dist/app/query-state-banners.d.ts +1 -1
  19. package/dist/app/reference-link.d.ts +1 -1
  20. package/dist/app/row-actions.d.ts +1 -1
  21. package/dist/app/secret-mint-body.d.ts +1 -1
  22. package/dist/app/secrets-edit-body.d.ts +1 -1
  23. package/dist/app/use-record-actions.d.ts +1 -1
  24. package/dist/app/write-failed-error.d.ts +1 -1
  25. package/dist/components/availability-options-select.d.ts +1 -1
  26. package/dist/components/embedded-list-field.d.ts +1 -1
  27. package/dist/components/embedded-list-field.js +1 -1
  28. package/dist/components/file-list-field.d.ts +1 -1
  29. package/dist/components/grid-cell-for-field.d.ts +1 -1
  30. package/dist/components/multi-select-checkboxes.d.ts +1 -1
  31. package/dist/components/multi-select-checkboxes.js +1 -1
  32. package/dist/components/query-options-select.d.ts +1 -1
  33. package/dist/components/related-list-section.d.ts +1 -1
  34. package/dist/components/render-edit-logic.d.ts +1 -1
  35. package/dist/components/render-edit-types.d.ts +2 -2
  36. package/dist/components/render-edit.d.ts +1 -1
  37. package/dist/components/render-edit.js +4 -2
  38. package/dist/components/render-field.d.ts +1 -1
  39. package/dist/components/render-field.js +4 -1
  40. package/dist/components/render-list.d.ts +1 -1
  41. package/dist/components/render-list.js +20 -4
  42. package/dist/components/write-form-section.d.ts +1 -1
  43. package/dist/components/write-form-section.js +1 -1
  44. package/dist/context/dispatcher-context.d.ts +1 -1
  45. package/dist/format-when.js +1 -1
  46. package/dist/headless/apex/css.d.ts +3 -0
  47. package/dist/headless/apex/css.js +298 -0
  48. package/dist/headless/apex/index.d.ts +236 -0
  49. package/dist/headless/apex/index.js +377 -0
  50. package/dist/headless/apex/lightbox.d.ts +4 -0
  51. package/dist/headless/apex/lightbox.js +81 -0
  52. package/dist/headless/contracts/asset.d.ts +15 -0
  53. package/dist/headless/contracts/asset.js +17 -0
  54. package/dist/headless/contracts/index.d.ts +3 -0
  55. package/dist/headless/contracts/index.js +1 -0
  56. package/dist/headless/contracts/locale.d.ts +7 -0
  57. package/dist/headless/contracts/locale.js +11 -0
  58. package/dist/headless/contracts/primitives.d.ts +93 -0
  59. package/dist/headless/contracts/primitives.js +21 -0
  60. package/dist/headless/dispatcher/index.d.ts +2 -0
  61. package/dist/headless/dispatcher/index.js +1 -0
  62. package/dist/headless/dispatcher/types.d.ts +86 -0
  63. package/dist/headless/dispatcher/types.js +34 -0
  64. package/dist/headless/form/form-controller.d.ts +2 -0
  65. package/dist/headless/form/form-controller.js +409 -0
  66. package/dist/headless/form/index.d.ts +3 -0
  67. package/dist/headless/form/index.js +2 -0
  68. package/dist/headless/form/types.d.ts +76 -0
  69. package/dist/headless/form/types.js +1 -0
  70. package/dist/headless/form/zod-bridge.d.ts +10 -0
  71. package/dist/headless/form/zod-bridge.js +103 -0
  72. package/dist/headless/format/document-values.d.ts +12 -0
  73. package/dist/headless/format/document-values.js +70 -0
  74. package/dist/headless/format/escape.d.ts +5 -0
  75. package/dist/headless/format/escape.js +75 -0
  76. package/dist/headless/format/html-template.d.ts +9 -0
  77. package/dist/headless/format/html-template.js +39 -0
  78. package/dist/headless/format/index.d.ts +12 -0
  79. package/dist/headless/format/index.js +237 -0
  80. package/dist/headless/format/money.d.ts +3 -0
  81. package/dist/headless/format/money.js +39 -0
  82. package/dist/headless/index.d.ts +14 -0
  83. package/dist/headless/index.js +9 -0
  84. package/dist/headless/locale-routing/index.d.ts +41 -0
  85. package/dist/headless/locale-routing/index.js +145 -0
  86. package/dist/headless/nav/index.d.ts +2 -0
  87. package/dist/headless/nav/index.js +1 -0
  88. package/dist/headless/nav/resolve.d.ts +2 -0
  89. package/dist/headless/nav/resolve.js +71 -0
  90. package/dist/headless/nav/types.d.ts +26 -0
  91. package/dist/headless/nav/types.js +1 -0
  92. package/dist/headless/store/create-store.d.ts +2 -0
  93. package/dist/headless/store/create-store.js +43 -0
  94. package/dist/headless/store/equality.d.ts +1 -0
  95. package/dist/headless/store/equality.js +34 -0
  96. package/dist/headless/store/index.d.ts +3 -0
  97. package/dist/headless/store/index.js +2 -0
  98. package/dist/headless/store/types.d.ts +7 -0
  99. package/dist/headless/store/types.js +10 -0
  100. package/dist/headless/view-model/edit.d.ts +18 -0
  101. package/dist/headless/view-model/edit.js +501 -0
  102. package/dist/headless/view-model/embedded-list.d.ts +27 -0
  103. package/dist/headless/view-model/embedded-list.js +63 -0
  104. package/dist/headless/view-model/index.d.ts +7 -0
  105. package/dist/headless/view-model/index.js +3 -0
  106. package/dist/headless/view-model/list-file-display.d.ts +3 -0
  107. package/dist/headless/view-model/list-file-display.js +27 -0
  108. package/dist/headless/view-model/list.d.ts +16 -0
  109. package/dist/headless/view-model/list.js +229 -0
  110. package/dist/headless/view-model/types.d.ts +382 -0
  111. package/dist/headless/view-model/types.js +1 -0
  112. package/dist/hooks/use-ai-text.d.ts +1 -1
  113. package/dist/hooks/use-form.d.ts +1 -1
  114. package/dist/hooks/use-form.js +1 -1
  115. package/dist/hooks/use-mutation.d.ts +1 -1
  116. package/dist/hooks/use-query.d.ts +1 -1
  117. package/dist/hooks/use-store.d.ts +1 -1
  118. package/dist/hooks/use-store.js +7 -7
  119. package/dist/hooks/use-stream-handler.d.ts +1 -1
  120. package/dist/i18n.d.ts +1 -1
  121. package/dist/i18n.js +1 -1
  122. package/dist/index.js +4 -4
  123. package/dist/live/csrf.d.ts +2 -0
  124. package/dist/live/csrf.js +60 -0
  125. package/dist/live/dispatcher-live.d.ts +7 -0
  126. package/dist/live/dispatcher-live.js +286 -0
  127. package/dist/live/envelopes.d.ts +101 -0
  128. package/dist/live/envelopes.js +35 -0
  129. package/dist/live/error-mapping.d.ts +16 -0
  130. package/dist/live/error-mapping.js +82 -0
  131. package/dist/live/index.d.ts +7 -0
  132. package/dist/live/index.js +5 -0
  133. package/dist/live/locale.d.ts +2 -0
  134. package/dist/live/locale.js +25 -0
  135. package/dist/live/sse-stream.d.ts +14 -0
  136. package/dist/live/sse-stream.js +128 -0
  137. package/dist/primitives.d.ts +35 -36
  138. package/dist/primitives.js +1 -1
  139. package/dist/session/session-ended.d.ts +1 -1
  140. package/dist/tokens.d.ts +3 -4
  141. package/dist/tokens.js +4 -5
  142. package/dist/web/app/app-schema-boot.d.ts +19 -0
  143. package/dist/web/app/app-schema-boot.js +124 -0
  144. package/dist/web/app/browser-locale.d.ts +22 -0
  145. package/dist/web/app/browser-locale.js +78 -0
  146. package/dist/web/app/client-plugin.d.ts +106 -0
  147. package/dist/web/app/client-plugin.js +12 -0
  148. package/dist/web/app/create-app.d.ts +104 -0
  149. package/dist/web/app/create-app.js +498 -0
  150. package/dist/web/app/create-public-surface.d.ts +36 -0
  151. package/dist/web/app/create-public-surface.js +40 -0
  152. package/dist/web/app/dashboard-body.d.ts +3 -0
  153. package/dist/web/app/dashboard-body.js +865 -0
  154. package/dist/web/app/dashboard-refresh.d.ts +6 -0
  155. package/dist/web/app/dashboard-refresh.js +15 -0
  156. package/dist/web/app/document-lang-sync.d.ts +4 -0
  157. package/dist/web/app/document-lang-sync.js +27 -0
  158. package/dist/web/app/draft-storage.d.ts +11 -0
  159. package/dist/web/app/draft-storage.js +53 -0
  160. package/dist/web/app/nav-providers-context.d.ts +13 -0
  161. package/dist/web/app/nav-providers-context.js +18 -0
  162. package/dist/web/app/nav.d.ts +40 -0
  163. package/dist/web/app/nav.js +231 -0
  164. package/dist/web/app/plain-content-editor.d.ts +3 -0
  165. package/dist/web/app/plain-content-editor.js +30 -0
  166. package/dist/web/app/relative-time.d.ts +10 -0
  167. package/dist/web/app/relative-time.js +56 -0
  168. package/dist/web/app/resolvers-context.d.ts +12 -0
  169. package/dist/web/app/resolvers-context.js +10 -0
  170. package/dist/web/app/rich-content-editor.d.ts +3 -0
  171. package/dist/web/app/rich-content-editor.js +15 -0
  172. package/dist/web/app/root-error-fallback.d.ts +2 -0
  173. package/dist/web/app/root-error-fallback.js +21 -0
  174. package/dist/web/app/screen-error-fallback.d.ts +6 -0
  175. package/dist/web/app/screen-error-fallback.js +17 -0
  176. package/dist/web/app/tiptap-editor.d.ts +3 -0
  177. package/dist/web/app/tiptap-editor.js +120 -0
  178. package/dist/web/app/toast-action-notifier.d.ts +5 -0
  179. package/dist/web/app/toast-action-notifier.js +17 -0
  180. package/dist/web/components/config-cascade.d.ts +13 -0
  181. package/dist/web/components/config-cascade.js +155 -0
  182. package/dist/web/components/config-source-badge.d.ts +6 -0
  183. package/dist/web/components/config-source-badge.js +55 -0
  184. package/dist/web/default-color-scheme.d.ts +2 -0
  185. package/dist/web/default-color-scheme.js +3 -0
  186. package/dist/web/icons.d.ts +94 -0
  187. package/dist/web/icons.js +100 -0
  188. package/dist/web/index.d.ts +78 -0
  189. package/dist/web/index.js +53 -0
  190. package/dist/web/layout/app-layout.d.ts +21 -0
  191. package/dist/web/layout/app-layout.js +8 -0
  192. package/dist/web/layout/avatar.d.ts +12 -0
  193. package/dist/web/layout/avatar.js +63 -0
  194. package/dist/web/layout/default-app-shell.d.ts +41 -0
  195. package/dist/web/layout/default-app-shell.js +16 -0
  196. package/dist/web/layout/editor-panel.d.ts +10 -0
  197. package/dist/web/layout/editor-panel.js +29 -0
  198. package/dist/web/layout/fill-classes.d.ts +9 -0
  199. package/dist/web/layout/fill-classes.js +15 -0
  200. package/dist/web/layout/filter-app-schema-navs.d.ts +7 -0
  201. package/dist/web/layout/filter-app-schema-navs.js +68 -0
  202. package/dist/web/layout/header-action-group.d.ts +6 -0
  203. package/dist/web/layout/header-action-group.js +8 -0
  204. package/dist/web/layout/header-overflow-menu.d.ts +4 -0
  205. package/dist/web/layout/header-overflow-menu.js +8 -0
  206. package/dist/web/layout/language-menu-items.d.ts +8 -0
  207. package/dist/web/layout/language-menu-items.js +16 -0
  208. package/dist/web/layout/language-switcher.d.ts +25 -0
  209. package/dist/web/layout/language-switcher.js +46 -0
  210. package/dist/web/layout/nav-tree.d.ts +19 -0
  211. package/dist/web/layout/nav-tree.js +536 -0
  212. package/dist/web/layout/page-header-slot.d.ts +25 -0
  213. package/dist/web/layout/page-header-slot.js +50 -0
  214. package/dist/web/layout/profile-menu.d.ts +13 -0
  215. package/dist/web/layout/profile-menu.js +6 -0
  216. package/dist/web/layout/shell-breadcrumb.d.ts +11 -0
  217. package/dist/web/layout/shell-breadcrumb.js +34 -0
  218. package/dist/web/layout/shell-header.d.ts +12 -0
  219. package/dist/web/layout/shell-header.js +159 -0
  220. package/dist/web/layout/sidebar-brand.d.ts +15 -0
  221. package/dist/web/layout/sidebar-brand.js +9 -0
  222. package/dist/web/layout/sidebar-panel.d.ts +41 -0
  223. package/dist/web/layout/sidebar-panel.js +107 -0
  224. package/dist/web/layout/sidebar-user.d.ts +8 -0
  225. package/dist/web/layout/sidebar-user.js +17 -0
  226. package/dist/web/layout/sidebar.d.ts +17 -0
  227. package/dist/web/layout/sidebar.js +11 -0
  228. package/dist/web/layout/target-resolver-stub.d.ts +13 -0
  229. package/dist/web/layout/target-resolver-stub.js +61 -0
  230. package/dist/web/layout/target-url.d.ts +12 -0
  231. package/dist/web/layout/target-url.js +77 -0
  232. package/dist/web/layout/theme-label.d.ts +15 -0
  233. package/dist/web/layout/theme-label.js +35 -0
  234. package/dist/web/layout/theme-menu-item.d.ts +12 -0
  235. package/dist/web/layout/theme-menu-item.js +16 -0
  236. package/dist/web/layout/theme-toggle.d.ts +17 -0
  237. package/dist/web/layout/theme-toggle.js +22 -0
  238. package/dist/web/layout/topbar.d.ts +8 -0
  239. package/dist/web/layout/topbar.js +4 -0
  240. package/dist/web/layout/workspace-shell.d.ts +63 -0
  241. package/dist/web/layout/workspace-shell.js +220 -0
  242. package/dist/web/layout/workspace-switcher.d.ts +15 -0
  243. package/dist/web/layout/workspace-switcher.js +36 -0
  244. package/dist/web/lib/accept-attr.d.ts +1 -0
  245. package/dist/web/lib/accept-attr.js +6 -0
  246. package/dist/web/lib/clamp.d.ts +1 -0
  247. package/dist/web/lib/clamp.js +3 -0
  248. package/dist/web/lib/cn.d.ts +6 -0
  249. package/dist/web/lib/cn.js +9 -0
  250. package/dist/web/lib/download.d.ts +2 -0
  251. package/dist/web/lib/download.js +24 -0
  252. package/dist/web/lib/file-ref-download.d.ts +15 -0
  253. package/dist/web/lib/file-ref-download.js +62 -0
  254. package/dist/web/lib/file-upload-form-data.d.ts +7 -0
  255. package/dist/web/lib/file-upload-form-data.js +11 -0
  256. package/dist/web/lib/resize-image.d.ts +1 -0
  257. package/dist/web/lib/resize-image.js +66 -0
  258. package/dist/web/lib/upload-file-ref.d.ts +9 -0
  259. package/dist/web/lib/upload-file-ref.js +29 -0
  260. package/dist/web/primitives/action-menu.d.ts +34 -0
  261. package/dist/web/primitives/action-menu.js +30 -0
  262. package/dist/web/primitives/calendar-popover.d.ts +13 -0
  263. package/dist/web/primitives/calendar-popover.js +76 -0
  264. package/dist/web/primitives/combobox.d.ts +56 -0
  265. package/dist/web/primitives/combobox.js +127 -0
  266. package/dist/web/primitives/date-field.d.ts +18 -0
  267. package/dist/web/primitives/date-field.js +74 -0
  268. package/dist/web/primitives/date-input.d.ts +1 -0
  269. package/dist/web/primitives/date-input.js +5 -0
  270. package/dist/web/primitives/date-parse.d.ts +11 -0
  271. package/dist/web/primitives/date-parse.js +159 -0
  272. package/dist/web/primitives/dialog.d.ts +3 -0
  273. package/dist/web/primitives/dialog.js +42 -0
  274. package/dist/web/primitives/drawer.d.ts +3 -0
  275. package/dist/web/primitives/drawer.js +17 -0
  276. package/dist/web/primitives/dropdown-menu.d.ts +15 -0
  277. package/dist/web/primitives/dropdown-menu.js +56 -0
  278. package/dist/web/primitives/embedded-list-input.d.ts +9 -0
  279. package/dist/web/primitives/embedded-list-input.js +382 -0
  280. package/dist/web/primitives/file-thumbnail.d.ts +25 -0
  281. package/dist/web/primitives/file-thumbnail.js +90 -0
  282. package/dist/web/primitives/file-upload.d.ts +21 -0
  283. package/dist/web/primitives/file-upload.js +56 -0
  284. package/dist/web/primitives/index.d.ts +34 -0
  285. package/dist/web/primitives/index.js +2021 -0
  286. package/dist/web/primitives/json-view.d.ts +7 -0
  287. package/dist/web/primitives/json-view.js +84 -0
  288. package/dist/web/primitives/layout.d.ts +27 -0
  289. package/dist/web/primitives/layout.js +30 -0
  290. package/dist/web/primitives/lightbox.d.ts +3 -0
  291. package/dist/web/primitives/lightbox.js +36 -0
  292. package/dist/web/primitives/locale-number.d.ts +2 -0
  293. package/dist/web/primitives/locale-number.js +54 -0
  294. package/dist/web/primitives/located-timestamp-input.d.ts +22 -0
  295. package/dist/web/primitives/located-timestamp-input.js +22 -0
  296. package/dist/web/primitives/metric.d.ts +5 -0
  297. package/dist/web/primitives/metric.js +18 -0
  298. package/dist/web/primitives/modal-shell.d.ts +17 -0
  299. package/dist/web/primitives/modal-shell.js +9 -0
  300. package/dist/web/primitives/modal.d.ts +3 -0
  301. package/dist/web/primitives/modal.js +13 -0
  302. package/dist/web/primitives/money-input.d.ts +18 -0
  303. package/dist/web/primitives/money-input.js +122 -0
  304. package/dist/web/primitives/narrow-pinned-footer.d.ts +12 -0
  305. package/dist/web/primitives/narrow-pinned-footer.js +153 -0
  306. package/dist/web/primitives/number-input.d.ts +18 -0
  307. package/dist/web/primitives/number-input.js +53 -0
  308. package/dist/web/primitives/option-groups.d.ts +11 -0
  309. package/dist/web/primitives/option-groups.js +27 -0
  310. package/dist/web/primitives/page-header.d.ts +3 -0
  311. package/dist/web/primitives/page-header.js +52 -0
  312. package/dist/web/primitives/promo-panel.d.ts +3 -0
  313. package/dist/web/primitives/promo-panel.js +11 -0
  314. package/dist/web/primitives/segmented-select.d.ts +21 -0
  315. package/dist/web/primitives/segmented-select.js +62 -0
  316. package/dist/web/primitives/share-actions.d.ts +4 -0
  317. package/dist/web/primitives/share-actions.js +56 -0
  318. package/dist/web/primitives/status-badge.d.ts +3 -0
  319. package/dist/web/primitives/status-badge.js +5 -0
  320. package/dist/web/primitives/sticky-action-bar.d.ts +5 -0
  321. package/dist/web/primitives/sticky-action-bar.js +15 -0
  322. package/dist/web/primitives/tabs.d.ts +3 -0
  323. package/dist/web/primitives/tabs.js +107 -0
  324. package/dist/web/primitives/timestamp-input.d.ts +27 -0
  325. package/dist/web/primitives/timestamp-input.js +87 -0
  326. package/dist/web/primitives/toast.d.ts +19 -0
  327. package/dist/web/primitives/toast.js +63 -0
  328. package/dist/web/primitives/tz-input.d.ts +11 -0
  329. package/dist/web/primitives/tz-input.js +8 -0
  330. package/dist/web/primitives/tz-options.d.ts +4 -0
  331. package/dist/web/primitives/tz-options.js +17 -0
  332. package/dist/web/primitives/use-keyboard-inset.d.ts +1 -0
  333. package/dist/web/primitives/use-keyboard-inset.js +28 -0
  334. package/dist/web/primitives/use-narrow-viewport.d.ts +4 -0
  335. package/dist/web/primitives/use-narrow-viewport.js +46 -0
  336. package/dist/web/react-css-custom-properties.d.ts +6 -0
  337. package/dist/web/react-css-custom-properties.js +1 -0
  338. package/dist/web/sse/live-events.d.ts +15 -0
  339. package/dist/web/sse/live-events.js +148 -0
  340. package/dist/web/theme-plugin.d.ts +41 -0
  341. package/dist/web/theme-plugin.js +123 -0
  342. package/dist/web/tokens.d.ts +24 -0
  343. package/dist/web/tokens.js +203 -0
  344. package/dist/web/ui/avatar.d.ts +11 -0
  345. package/dist/web/ui/avatar.js +25 -0
  346. package/dist/web/ui/badge.d.ts +9 -0
  347. package/dist/web/ui/badge.js +26 -0
  348. package/dist/web/ui/breadcrumb.d.ts +11 -0
  349. package/dist/web/ui/breadcrumb.js +29 -0
  350. package/dist/web/ui/button.d.ts +10 -0
  351. package/dist/web/ui/button.js +37 -0
  352. package/dist/web/ui/checkbox.d.ts +4 -0
  353. package/dist/web/ui/checkbox.js +11 -0
  354. package/dist/web/ui/input.d.ts +3 -0
  355. package/dist/web/ui/input.js +8 -0
  356. package/dist/web/ui/label.d.ts +4 -0
  357. package/dist/web/ui/label.js +10 -0
  358. package/dist/web/ui/resizable.d.ts +7 -0
  359. package/dist/web/ui/resizable.js +16 -0
  360. package/dist/web/ui/separator.d.ts +4 -0
  361. package/dist/web/ui/separator.js +10 -0
  362. package/dist/web/ui/sheet.d.ts +14 -0
  363. package/dist/web/ui/sheet.js +42 -0
  364. package/dist/web/ui/sidebar.d.ts +73 -0
  365. package/dist/web/ui/sidebar.js +211 -0
  366. package/dist/web/ui/skeleton.d.ts +2 -0
  367. package/dist/web/ui/skeleton.js +7 -0
  368. package/dist/web/ui/switch.d.ts +6 -0
  369. package/dist/web/ui/switch.js +10 -0
  370. package/dist/web/ui/table.d.ts +10 -0
  371. package/dist/web/ui/table.js +30 -0
  372. package/dist/web/ui/tabs.d.ts +11 -0
  373. package/dist/web/ui/tabs.js +31 -0
  374. package/dist/web/ui/textarea.d.ts +3 -0
  375. package/dist/web/ui/textarea.js +8 -0
  376. package/dist/web/ui/tooltip.d.ts +7 -0
  377. package/dist/web/ui/tooltip.js +19 -0
  378. package/dist/web/ui/use-mobile.d.ts +1 -0
  379. package/dist/web/ui/use-mobile.js +16 -0
  380. package/dist/web/version/update-checker.d.ts +9 -0
  381. package/dist/web/version/update-checker.js +88 -0
  382. package/dist/web/widgets/ai-text-field.d.ts +36 -0
  383. package/dist/web/widgets/ai-text-field.js +137 -0
  384. package/dist/web/widgets/chart-window.d.ts +58 -0
  385. package/dist/web/widgets/chart-window.js +190 -0
  386. package/dist/web/widgets/charts.d.ts +208 -0
  387. package/dist/web/widgets/charts.js +685 -0
  388. package/dist/web/widgets/collapsible-section.d.ts +10 -0
  389. package/dist/web/widgets/collapsible-section.js +17 -0
  390. package/dist/web/widgets/dashboard-list.d.ts +21 -0
  391. package/dist/web/widgets/dashboard-list.js +45 -0
  392. package/dist/web/widgets/detail-list.d.ts +15 -0
  393. package/dist/web/widgets/detail-list.js +8 -0
  394. package/dist/web/widgets/drawer.d.ts +65 -0
  395. package/dist/web/widgets/drawer.js +142 -0
  396. package/dist/web/widgets/feed-list.d.ts +13 -0
  397. package/dist/web/widgets/feed-list.js +9 -0
  398. package/dist/web/widgets/floating-panel.d.ts +30 -0
  399. package/dist/web/widgets/floating-panel.js +242 -0
  400. package/dist/web/widgets/form-fields.d.ts +93 -0
  401. package/dist/web/widgets/form-fields.js +50 -0
  402. package/dist/web/widgets/index.d.ts +27 -0
  403. package/dist/web/widgets/index.js +30 -0
  404. package/dist/web/widgets/infinity-list.d.ts +46 -0
  405. package/dist/web/widgets/infinity-list.js +211 -0
  406. package/dist/web/widgets/mode-switch.d.ts +21 -0
  407. package/dist/web/widgets/mode-switch.js +25 -0
  408. package/dist/web/widgets/photo-slots.d.ts +29 -0
  409. package/dist/web/widgets/photo-slots.js +52 -0
  410. package/dist/web/widgets/plan-card.d.ts +36 -0
  411. package/dist/web/widgets/plan-card.js +13 -0
  412. package/dist/web/widgets/progress-bar.d.ts +19 -0
  413. package/dist/web/widgets/progress-bar.js +24 -0
  414. package/dist/web/widgets/progress-list.d.ts +19 -0
  415. package/dist/web/widgets/progress-list.js +11 -0
  416. package/dist/web/widgets/public-shell.d.ts +22 -0
  417. package/dist/web/widgets/public-shell.js +15 -0
  418. package/dist/web/widgets/query-table.d.ts +29 -0
  419. package/dist/web/widgets/query-table.js +30 -0
  420. package/dist/web/widgets/result-panel.d.ts +69 -0
  421. package/dist/web/widgets/result-panel.js +30 -0
  422. package/dist/web/widgets/section-card.d.ts +12 -0
  423. package/dist/web/widgets/section-card.js +9 -0
  424. package/dist/web/widgets/sheet-parts.d.ts +9 -0
  425. package/dist/web/widgets/sheet-parts.js +11 -0
  426. package/dist/web/widgets/side-by-side-table.d.ts +31 -0
  427. package/dist/web/widgets/side-by-side-table.js +11 -0
  428. package/dist/web/widgets/stat.d.ts +54 -0
  429. package/dist/web/widgets/stat.js +65 -0
  430. package/dist/web/widgets/states.d.ts +23 -0
  431. package/dist/web/widgets/states.js +20 -0
  432. package/dist/web/widgets/status-badge.d.ts +15 -0
  433. package/dist/web/widgets/status-badge.js +24 -0
  434. package/dist/web/widgets/step-bar.d.ts +35 -0
  435. package/dist/web/widgets/step-bar.js +60 -0
  436. package/dist/web/widgets/upload-zone.d.ts +24 -0
  437. package/dist/web/widgets/upload-zone.js +108 -0
  438. package/dist/web/widgets/use-draft.d.ts +20 -0
  439. package/dist/web/widgets/use-draft.js +21 -0
  440. package/dist/web/widgets/use-pointer-drag.d.ts +21 -0
  441. package/dist/web/widgets/use-pointer-drag.js +53 -0
  442. package/package.json +105 -7
  443. package/src/changes.json +53 -0
  444. package/src/web/fonts/OFL.txt +93 -0
  445. package/src/web/fonts/ibm-plex-mono-latin-400.woff2 +0 -0
  446. package/src/web/fonts/ibm-plex-mono-latin-500.woff2 +0 -0
  447. package/src/web/fonts/ibm-plex-mono-latin-ext-400.woff2 +0 -0
  448. package/src/web/fonts/ibm-plex-mono-latin-ext-500.woff2 +0 -0
  449. package/src/web/fonts/ibm-plex-sans-latin-400.woff2 +0 -0
  450. package/src/web/fonts/ibm-plex-sans-latin-500.woff2 +0 -0
  451. package/src/web/fonts/ibm-plex-sans-latin-600.woff2 +0 -0
  452. package/src/web/fonts/ibm-plex-sans-latin-ext-400.woff2 +0 -0
  453. package/src/web/fonts/ibm-plex-sans-latin-ext-500.woff2 +0 -0
  454. package/src/web/fonts/ibm-plex-sans-latin-ext-600.woff2 +0 -0
  455. package/src/web/styles.css +401 -0
@@ -1,12 +1,12 @@
1
1
  import { useRef, useSyncExternalStore } from "react";
2
- // React-Bindings für Kumikos Store-Primitive (`createStore` aus
3
- // @cosmicdrift/kumiko-headless). Beide Hooks sind dünne Wrapper um React's
4
- // useSyncExternalStore — die ganze Subscribe/Notify-Mechanik lebt im
5
- // Store selbst, hier wird nur React verdrahtet.
2
+ // React bindings for Kumiko's store primitive (`createStore` from
3
+ // @cosmicdrift/kumiko-renderer/headless). Both hooks are thin wrappers around React's
4
+ // useSyncExternalStore — the whole subscribe/notify mechanism lives in the
5
+ // store itself, only React wiring happens here.
6
6
  //
7
- // useStore: gibt den ganzen Snapshot zurück. Re-rendert wenn der
8
- // Store seine Identität wechselt. Object.is-Gate im Store selbst
9
- // verhindert no-op-Updates.
7
+ // useStore: returns the whole snapshot. Re-renders when the store changes
8
+ // its identity. The Object.is gate in the store itself prevents no-op
9
+ // updates.
10
10
  //
11
11
  // useStoreSelector: gibt eine abgeleitete Sicht zurück. Selectors die
12
12
  // Object-/Array-Literale zurückgeben (z.B. `s => ({ a, b })`) erzeugen
@@ -1,4 +1,4 @@
1
- import type { DispatcherError } from "@cosmicdrift/kumiko-headless";
1
+ import type { DispatcherError } from "../headless/index.ts";
2
2
  export type StreamStatus = "idle" | "streaming" | "done" | "error";
3
3
  export type UseStreamHandlerResult<TChunk> = {
4
4
  readonly chunks: readonly TChunk[];
package/dist/i18n.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { type Formality, type TranslationValue } from "@cosmicdrift/kumiko-framework/ui-types";
2
- import type { LocaleResolver } from "@cosmicdrift/kumiko-headless";
3
2
  import { type ReactNode } from "react";
3
+ import type { LocaleResolver } from "./headless/index.ts";
4
4
  /** Map of i18n key → TranslationValue. Strings may contain `{name}`
5
5
  * placeholders (same semantics as i18next t); plural entries resolve via
6
6
  * `resolveTranslationValue`. */
package/dist/i18n.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  // Locale handling for React consumers of the Kumiko renderer. A thin layer
3
3
  // around the platform-agnostic `LocaleResolver` contract from
4
- // @cosmicdrift/kumiko-headless: provider, hooks, a default no-op resolver,
4
+ // @cosmicdrift/kumiko-renderer/headless: provider, hooks, a default no-op resolver,
5
5
  // and a fallback-bundle merge for feature-supplied translations.
6
6
  //
7
7
  // Architecture:
package/dist/index.js CHANGED
@@ -4,10 +4,10 @@
4
4
  // und reichen ihre konkreten Primitives/Nav/SSE-Impls via Provider
5
5
  // in diesen Baum.
6
6
  //
7
- // Wer diesen Layer direkt konsumiert: andere Renderer-Packages
8
- // (@cosmicdrift/kumiko-renderer-web, später -native) oder eine App die ihren
9
- // eigenen Bootstrap schreiben will. Normale Samples gehen über
10
- // @cosmicdrift/kumiko-renderer-web/createKumikoApp, das alle Provider verdrahtet.
7
+ // Direct consumers of this layer: platform bindings
8
+ // (@cosmicdrift/kumiko-renderer/web) or an app writing its own bootstrap.
9
+ // Normal samples go through createKumikoApp from
10
+ // @cosmicdrift/kumiko-renderer/web, which wires all providers.
11
11
  export { formalLocaleTag } from "@cosmicdrift/kumiko-framework/ui-types";
12
12
  export { synthesizeActionFormEntity, synthesizeActionFormScreen } from "./app/action-form-shim.js";
13
13
  export { AppFeaturesProvider, useAppFeatures } from "./app/app-features-context.js";
@@ -0,0 +1,2 @@
1
+ export declare const CSRF_HEADER_NAME = "X-CSRF-Token";
2
+ export declare function readCsrfToken(cookieSource?: string): string | undefined;
@@ -0,0 +1,60 @@
1
+ // CSRF-token extraction from document.cookie.
2
+ //
3
+ // Kumiko's auth-middleware sets two cookies on login (see Vorarbeit A):
4
+ // - `kumiko_auth` — HttpOnly, carries the JWT. Invisible to JS.
5
+ // - `kumiko_csrf` — JS-readable, carries a random token.
6
+ // Both carry the `__Host-` prefix when the server writes them Secure and
7
+ // without a Domain (see @cosmicdrift/kumiko-types/session-cookies).
8
+ //
9
+ // The double-submit CSRF pattern: every state-changing request echoes the
10
+ // `kumiko_csrf` value into an `X-CSRF-Token` header. Server compares header
11
+ // vs cookie in csrfMiddleware and rejects on mismatch. An attacker on a
12
+ // third-party origin can trigger a cross-site fetch (cookies fly with
13
+ // SameSite=Lax on top-level GETs, or Strict blocks them entirely) but
14
+ // cannot READ `document.cookie` of our origin — so they can't populate the
15
+ // header with the matching value.
16
+ import { CSRF_COOKIE_BASE, sessionCookieNameCandidates, } from "@cosmicdrift/kumiko-types/session-cookies";
17
+ import { propertyOf } from "@cosmicdrift/kumiko-types/type-guards";
18
+ // Kept here as a literal rather than imported from @cosmicdrift/kumiko-framework because this
19
+ // package must remain server-dep-free (runs in browsers and React Native).
20
+ // The framework's csrf-constants-sync test guards against drift.
21
+ export const CSRF_HEADER_NAME = "X-CSRF-Token";
22
+ const CSRF_COOKIE_NAMES = sessionCookieNameCandidates(CSRF_COOKIE_BASE);
23
+ // Reads the csrf token from document.cookie. Returns undefined when:
24
+ // - `document` isn't available (SSR, Web Worker, React Native)
25
+ // - the cookie was never set (before login, after logout)
26
+ //
27
+ // Callers ALWAYS handle undefined — the request still goes out, the server
28
+ // rejects with csrf_token_missing and the UI surfaces an auth-expired
29
+ // toast. That's the right failure mode: silently skipping the header
30
+ // would hide a broken auth state.
31
+ export function readCsrfToken(cookieSource) {
32
+ const raw = cookieSource ?? readDocumentCookie();
33
+ if (!raw)
34
+ return undefined;
35
+ // cookie format: "a=1; b=2; kumiko_csrf=<uuid>; c=3"
36
+ // Parse by splitting on "; " — cookie values never contain that
37
+ // delimiter literally (they're percent-encoded if needed).
38
+ const valuesByName = new Map();
39
+ for (const pair of raw.split(/;\s*/)) {
40
+ const eq = pair.indexOf("=");
41
+ if (eq < 0)
42
+ continue;
43
+ const name = pair.slice(0, eq);
44
+ if (!valuesByName.has(name))
45
+ valuesByName.set(name, pair.slice(eq + 1));
46
+ }
47
+ for (const name of CSRF_COOKIE_NAMES) {
48
+ const value = valuesByName.get(name);
49
+ if (value !== undefined)
50
+ return value.length > 0 ? decodeURIComponent(value) : undefined;
51
+ }
52
+ return undefined;
53
+ }
54
+ function readDocumentCookie() {
55
+ // Guard for non-browser environments. Avoid `typeof document` on the
56
+ // left so a bundler that const-folds to "document is defined" still
57
+ // compiles — the actual runtime check is what matters.
58
+ const cookie = propertyOf(propertyOf(globalThis, "document"), "cookie");
59
+ return typeof cookie === "string" ? cookie : undefined;
60
+ }
@@ -0,0 +1,7 @@
1
+ import { type Dispatcher } from "../headless/index.ts";
2
+ export type LiveDispatcherOptions = {
3
+ readonly baseUrl?: string;
4
+ readonly fetch?: typeof fetch;
5
+ readonly readCsrf?: () => string | undefined;
6
+ };
7
+ export declare function createLiveDispatcher(options?: LiveDispatcherOptions): Dispatcher;
@@ -0,0 +1,286 @@
1
+ import { propertyOf } from "@cosmicdrift/kumiko-types/type-guards";
2
+ import { createStore, } from "../headless/index.js";
3
+ import { CSRF_HEADER_NAME, readCsrfToken } from "./csrf.js";
4
+ import { batchEnvelopeSchema, errorOnlyEnvelopeSchema, queryEnvelopeSchema, writeEnvelopeSchema, } from "./envelopes.js";
5
+ import { buildAbortError, buildNetworkError, mapServerError } from "./error-mapping.js";
6
+ import { LOCALE_HEADER_NAME, readActiveLocale } from "./locale.js";
7
+ import { iterateSseChunks } from "./sse-stream.js";
8
+ // Paths — matched against the server routes (packages/framework/src/api/routes.ts).
9
+ // Kept as constants so refactors elsewhere (api-constants.ts bumped on the
10
+ // server) flag a mismatch here in a code review instead of at runtime.
11
+ const PATH_WRITE = "/api/write";
12
+ const PATH_QUERY = "/api/query";
13
+ const PATH_BATCH = "/api/batch";
14
+ const PATH_STREAM = "/api/stream";
15
+ export function createLiveDispatcher(options = {}) {
16
+ const baseUrl = options.baseUrl ?? "";
17
+ const readCsrf = options.readCsrf ?? (() => readCsrfToken());
18
+ // Status state — transitions between "online" and "offline" driven
19
+ // purely by call outcomes. "syncing" never fires here (live has
20
+ // nothing to catch up on). Initial "online": optimism — we haven't
21
+ // proven the server is unreachable, and a down-state on boot would
22
+ // show an offline-toast before the user has even clicked anything.
23
+ const statusStore = createStore("online");
24
+ // A status-flip drives network-error → "offline" and any subsequent
25
+ // success → "online". Typed server failures (400, 403, ...) don't flip
26
+ // status — the network reached the server, the server answered, we're
27
+ // online in every operational sense.
28
+ function observeNetworkOutcome(ok) {
29
+ statusStore.setState(ok ? "online" : "offline");
30
+ }
31
+ async function callJson(path, body, signal) {
32
+ const f = options.fetch ?? globalThis.fetch;
33
+ if (!f) {
34
+ return {
35
+ ok: false,
36
+ networkFailure: buildNetworkError("fetch is not available in this runtime — inject via LiveDispatcherOptions.fetch"),
37
+ };
38
+ }
39
+ const headers = {
40
+ "Content-Type": "application/json",
41
+ Accept: "application/json",
42
+ };
43
+ const csrf = readCsrf();
44
+ if (csrf !== undefined)
45
+ headers[CSRF_HEADER_NAME] = csrf;
46
+ const locale = readActiveLocale();
47
+ if (locale !== undefined)
48
+ headers[LOCALE_HEADER_NAME] = locale;
49
+ // If no CSRF token, still send the request — public / pre-login
50
+ // routes like /auth/login don't require CSRF, and POST /write/query/
51
+ // batch against a logged-out client returns 401 via auth-middleware
52
+ // which is a cleaner error than a csrf-mismatch.
53
+ let response;
54
+ try {
55
+ response = await f(`${baseUrl}${path}`, {
56
+ method: "POST",
57
+ credentials: "include",
58
+ headers,
59
+ body: JSON.stringify(body),
60
+ signal,
61
+ });
62
+ }
63
+ catch (e) {
64
+ // Abort surfaces as a DOMException with name="AbortError" in the
65
+ // standard fetch contract. Handle it distinctly so the caller
66
+ // doesn't see the user-cancellation as a network drop.
67
+ if (isAbortError(e)) {
68
+ return { ok: false, networkFailure: buildAbortError() };
69
+ }
70
+ observeNetworkOutcome(false);
71
+ return { ok: false, networkFailure: buildNetworkError(e) };
72
+ }
73
+ observeNetworkOutcome(true);
74
+ // JSON body parse. A server that returned a non-JSON body for any
75
+ // reason (HTML error page from a reverse-proxy, empty body on a
76
+ // weird 502) maps to network-error — structurally the same as a
77
+ // fetch-throw from the UI's perspective.
78
+ let parsed;
79
+ try {
80
+ parsed = await response.json();
81
+ }
82
+ catch (e) {
83
+ return {
84
+ ok: false,
85
+ networkFailure: buildNetworkError(`invalid JSON response (${response.status}): ${e instanceof Error ? e.message : String(e)}`),
86
+ };
87
+ }
88
+ return { ok: true, body: parsed, status: response.status };
89
+ }
90
+ return {
91
+ async write(type, payload, opts) {
92
+ const body = { type, payload };
93
+ // Idempotency by default (#761): without a requestId the server-side
94
+ // dedup never engages and a transport-level double-send duplicates
95
+ // events. Callers with a logical-submit id (savable queue, form
96
+ // controllers) pass their own and keep it across their retries.
97
+ body["requestId"] = opts?.requestId ?? generateRequestId();
98
+ const call = await callJson(PATH_WRITE, body, opts?.signal);
99
+ return normalizeWriteResult(call);
100
+ },
101
+ async query(type, payload, opts) {
102
+ const body = { type, payload };
103
+ const call = await callJson(PATH_QUERY, body, opts?.signal);
104
+ return normalizeQueryResponse(call);
105
+ },
106
+ async batch(commands, opts) {
107
+ const body = { commands };
108
+ // One id for the whole batch — the server caches the BatchResult
109
+ // under it, so a retried batch returns the cached outcome instead of
110
+ // re-executing the commands (#761).
111
+ body["requestId"] = opts?.requestId ?? generateRequestId();
112
+ const call = await callJson(PATH_BATCH, body, opts?.signal);
113
+ return normalizeBatchResponse(call);
114
+ },
115
+ async *stream(type, payload, opts) {
116
+ const f = options.fetch ?? globalThis.fetch;
117
+ if (!f) {
118
+ throw buildNetworkError("fetch is not available in this runtime — inject via LiveDispatcherOptions.fetch");
119
+ }
120
+ const headers = {
121
+ "Content-Type": "application/json",
122
+ Accept: "text/event-stream",
123
+ };
124
+ const csrf = readCsrf();
125
+ if (csrf !== undefined)
126
+ headers[CSRF_HEADER_NAME] = csrf;
127
+ const locale = readActiveLocale();
128
+ if (locale !== undefined)
129
+ headers[LOCALE_HEADER_NAME] = locale;
130
+ let response;
131
+ try {
132
+ response = await f(`${baseUrl}${PATH_STREAM}`, {
133
+ method: "POST",
134
+ credentials: "include",
135
+ headers,
136
+ body: JSON.stringify({ type, payload }),
137
+ signal: opts?.signal,
138
+ });
139
+ }
140
+ catch (e) {
141
+ if (isAbortError(e))
142
+ throw buildAbortError();
143
+ observeNetworkOutcome(false);
144
+ throw buildNetworkError(e);
145
+ }
146
+ observeNetworkOutcome(true);
147
+ const contentType = response.headers.get("content-type") ?? "";
148
+ // Pre-SSE gate failures (PAT deny, etc.) return a normal JSON error
149
+ // envelope — map them like /api/query before trying to read SSE.
150
+ if (!contentType.includes("text/event-stream")) {
151
+ let parsed;
152
+ try {
153
+ parsed = await response.json();
154
+ }
155
+ catch (e) {
156
+ throw buildNetworkError(`invalid stream response (${response.status}): ${e instanceof Error ? e.message : String(e)}`);
157
+ }
158
+ const gateFailure = errorOnlyEnvelopeSchema.safeParse(parsed);
159
+ if (gateFailure.success) {
160
+ throw mapServerErrorWithStatus(gateFailure.data.error, response.status);
161
+ }
162
+ throw buildNetworkError(`unexpected non-SSE stream response (${response.status})`);
163
+ }
164
+ if (!response.body) {
165
+ throw buildNetworkError("stream response has no body");
166
+ }
167
+ try {
168
+ yield* iterateSseChunks(response.body);
169
+ }
170
+ catch (e) {
171
+ // Abort can surface on the initial fetch OR while reading the SSE
172
+ // body — both must map to the same `aborted` envelope so hooks
173
+ // (useStreamHandler) can ignore user-cancel without an error toast.
174
+ if (isAbortError(e) || opts?.signal?.aborted)
175
+ throw buildAbortError();
176
+ observeNetworkOutcome(false);
177
+ throw e;
178
+ }
179
+ },
180
+ statusStore,
181
+ // Live dispatcher has no queue. Returning a constant empty array
182
+ // keeps the contract uniform with savable; UI code that renders
183
+ // pending-badges draws nothing instead of branching on dispatcher
184
+ // type.
185
+ pendingWrites: () => EMPTY_PENDING_WRITES,
186
+ pendingFiles: () => EMPTY_PENDING_FILES,
187
+ };
188
+ }
189
+ const EMPTY_PENDING_WRITES = Object.freeze([]);
190
+ const EMPTY_PENDING_FILES = Object.freeze([]);
191
+ // crypto.randomUUID where available (browser, Bun, Node); Math.random
192
+ // fallback for React-Native runtimes without the WebCrypto polyfill.
193
+ // Uniqueness only needs to hold per user within the server's dedup window —
194
+ // this is an idempotency key, not a security token.
195
+ function generateRequestId() {
196
+ const webCrypto = propertyOf(globalThis, "crypto");
197
+ const randomUUID = propertyOf(webCrypto, "randomUUID");
198
+ if (typeof randomUUID === "function") {
199
+ const id = Reflect.apply(randomUUID, webCrypto, []);
200
+ if (typeof id === "string")
201
+ return id;
202
+ }
203
+ return `req-${Math.random().toString(36).slice(2)}${Math.random().toString(36).slice(2)}`;
204
+ }
205
+ function buildUnexpectedShapeError(status) {
206
+ // The server did answer: keep its status so 401/5xx handling still applies.
207
+ return { ...buildNetworkError(`unexpected response shape (${status})`), httpStatus: status };
208
+ }
209
+ // Middleware gates (csrf, origin, auth, rate limits) answer write and batch
210
+ // calls with a bare `{ error }`, without the isSuccess envelope.
211
+ function gateOrShapeError(body, status) {
212
+ const gateFailure = errorOnlyEnvelopeSchema.safeParse(body);
213
+ return gateFailure.success
214
+ ? mapServerErrorWithStatus(gateFailure.data.error, status)
215
+ : buildUnexpectedShapeError(status);
216
+ }
217
+ // Write / Batch share the same envelope: `{ isSuccess: true, data }` on
218
+ // success, `{ isSuccess: false, error: ServerErrorInfo, ... }` on failure.
219
+ // Query uses a different envelope (see normalizeQueryResponse).
220
+ function normalizeWriteResult(call) {
221
+ if (!call.ok)
222
+ return { isSuccess: false, error: call.networkFailure };
223
+ const envelope = writeEnvelopeSchema.safeParse(call.body);
224
+ if (!envelope.success) {
225
+ return { isSuccess: false, error: gateOrShapeError(call.body, call.status) };
226
+ }
227
+ const body = envelope.data;
228
+ if (body.isSuccess)
229
+ return { isSuccess: true, data: body.data };
230
+ return { isSuccess: false, error: mapServerErrorWithStatus(body.error, call.status) };
231
+ }
232
+ function normalizeBatchResponse(call) {
233
+ if (!call.ok) {
234
+ return { isSuccess: false, error: call.networkFailure, failedIndex: -1, results: [] };
235
+ }
236
+ const envelope = batchEnvelopeSchema.safeParse(call.body);
237
+ if (!envelope.success) {
238
+ return {
239
+ isSuccess: false,
240
+ error: gateOrShapeError(call.body, call.status),
241
+ failedIndex: -1,
242
+ results: [],
243
+ };
244
+ }
245
+ const body = envelope.data;
246
+ const results = body.results.map((item) => {
247
+ if (item.isSuccess)
248
+ return { isSuccess: true, data: item.data };
249
+ return { isSuccess: false, error: mapServerErrorWithStatus(item.error, call.status) };
250
+ });
251
+ if (body.isSuccess)
252
+ return { isSuccess: true, results };
253
+ return {
254
+ isSuccess: false,
255
+ error: mapServerErrorWithStatus(body.error, call.status),
256
+ failedIndex: body.failedIndex,
257
+ results,
258
+ };
259
+ }
260
+ // Query envelope: Kumiko's /api/query returns `{ data: ... }` on success
261
+ // (no isSuccess flag) and `{ error: { code, i18nKey, message, ... } }`
262
+ // on failure. Source of truth: packages/framework/src/api/routes.ts:85
263
+ // (the query route handler that emits `c.json({ data: result })`).
264
+ function normalizeQueryResponse(call) {
265
+ if (!call.ok)
266
+ return { isSuccess: false, error: call.networkFailure };
267
+ const envelope = queryEnvelopeSchema.safeParse(call.body);
268
+ if (!envelope.success) {
269
+ return { isSuccess: false, error: buildUnexpectedShapeError(call.status) };
270
+ }
271
+ const body = envelope.data;
272
+ if (body.error) {
273
+ return { isSuccess: false, error: mapServerErrorWithStatus(body.error, call.status) };
274
+ }
275
+ return { isSuccess: true, data: body.data };
276
+ }
277
+ // The HTTP status carries the failure-status; the error body itself
278
+ // doesn't repeat it (serializeError drops httpStatus to keep the wire
279
+ // payload lean). Every envelope has to reinject it from Response.status,
280
+ // otherwise status-based checks like isSessionEndedError never match.
281
+ function mapServerErrorWithStatus(error, responseStatus) {
282
+ return mapServerError({ ...error, httpStatus: error.httpStatus ?? responseStatus });
283
+ }
284
+ function isAbortError(e) {
285
+ return !!e && typeof e === "object" && "name" in e && e.name === "AbortError";
286
+ }
@@ -0,0 +1,101 @@
1
+ import * as z from "zod";
2
+ export declare const serverErrorSchema: z.ZodObject<{
3
+ code: z.ZodString;
4
+ httpStatus: z.ZodOptional<z.ZodNumber>;
5
+ i18nKey: z.ZodDefault<z.ZodString>;
6
+ message: z.ZodString;
7
+ details: z.ZodOptional<z.ZodUnknown>;
8
+ i18nParams: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
9
+ docsUrl: z.ZodOptional<z.ZodString>;
10
+ requestId: z.ZodOptional<z.ZodString>;
11
+ }, z.core.$strip>;
12
+ export type ServerErrorLike = z.infer<typeof serverErrorSchema>;
13
+ export declare const writeEnvelopeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
14
+ isSuccess: z.ZodLiteral<true>;
15
+ data: z.ZodOptional<z.ZodUnknown>;
16
+ }, z.core.$strip>, z.ZodObject<{
17
+ isSuccess: z.ZodLiteral<false>;
18
+ error: z.ZodObject<{
19
+ code: z.ZodString;
20
+ httpStatus: z.ZodOptional<z.ZodNumber>;
21
+ i18nKey: z.ZodDefault<z.ZodString>;
22
+ message: z.ZodString;
23
+ details: z.ZodOptional<z.ZodUnknown>;
24
+ i18nParams: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
25
+ docsUrl: z.ZodOptional<z.ZodString>;
26
+ requestId: z.ZodOptional<z.ZodString>;
27
+ }, z.core.$strip>;
28
+ }, z.core.$strip>], "isSuccess">;
29
+ export declare const batchEnvelopeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
30
+ isSuccess: z.ZodLiteral<true>;
31
+ results: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
32
+ isSuccess: z.ZodLiteral<true>;
33
+ data: z.ZodOptional<z.ZodUnknown>;
34
+ }, z.core.$strip>, z.ZodObject<{
35
+ isSuccess: z.ZodLiteral<false>;
36
+ error: z.ZodObject<{
37
+ code: z.ZodString;
38
+ httpStatus: z.ZodOptional<z.ZodNumber>;
39
+ i18nKey: z.ZodDefault<z.ZodString>;
40
+ message: z.ZodString;
41
+ details: z.ZodOptional<z.ZodUnknown>;
42
+ i18nParams: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
43
+ docsUrl: z.ZodOptional<z.ZodString>;
44
+ requestId: z.ZodOptional<z.ZodString>;
45
+ }, z.core.$strip>;
46
+ }, z.core.$strip>], "isSuccess">>;
47
+ }, z.core.$strip>, z.ZodObject<{
48
+ isSuccess: z.ZodLiteral<false>;
49
+ error: z.ZodObject<{
50
+ code: z.ZodString;
51
+ httpStatus: z.ZodOptional<z.ZodNumber>;
52
+ i18nKey: z.ZodDefault<z.ZodString>;
53
+ message: z.ZodString;
54
+ details: z.ZodOptional<z.ZodUnknown>;
55
+ i18nParams: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
56
+ docsUrl: z.ZodOptional<z.ZodString>;
57
+ requestId: z.ZodOptional<z.ZodString>;
58
+ }, z.core.$strip>;
59
+ failedIndex: z.ZodNumber;
60
+ results: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
61
+ isSuccess: z.ZodLiteral<true>;
62
+ data: z.ZodOptional<z.ZodUnknown>;
63
+ }, z.core.$strip>, z.ZodObject<{
64
+ isSuccess: z.ZodLiteral<false>;
65
+ error: z.ZodObject<{
66
+ code: z.ZodString;
67
+ httpStatus: z.ZodOptional<z.ZodNumber>;
68
+ i18nKey: z.ZodDefault<z.ZodString>;
69
+ message: z.ZodString;
70
+ details: z.ZodOptional<z.ZodUnknown>;
71
+ i18nParams: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
72
+ docsUrl: z.ZodOptional<z.ZodString>;
73
+ requestId: z.ZodOptional<z.ZodString>;
74
+ }, z.core.$strip>;
75
+ }, z.core.$strip>], "isSuccess">>;
76
+ }, z.core.$strip>], "isSuccess">;
77
+ export declare const queryEnvelopeSchema: z.ZodObject<{
78
+ data: z.ZodOptional<z.ZodUnknown>;
79
+ error: z.ZodOptional<z.ZodNullable<z.ZodObject<{
80
+ code: z.ZodString;
81
+ httpStatus: z.ZodOptional<z.ZodNumber>;
82
+ i18nKey: z.ZodDefault<z.ZodString>;
83
+ message: z.ZodString;
84
+ details: z.ZodOptional<z.ZodUnknown>;
85
+ i18nParams: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
86
+ docsUrl: z.ZodOptional<z.ZodString>;
87
+ requestId: z.ZodOptional<z.ZodString>;
88
+ }, z.core.$strip>>>;
89
+ }, z.core.$strip>;
90
+ export declare const errorOnlyEnvelopeSchema: z.ZodObject<{
91
+ error: z.ZodObject<{
92
+ code: z.ZodString;
93
+ httpStatus: z.ZodOptional<z.ZodNumber>;
94
+ i18nKey: z.ZodDefault<z.ZodString>;
95
+ message: z.ZodString;
96
+ details: z.ZodOptional<z.ZodUnknown>;
97
+ i18nParams: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
98
+ docsUrl: z.ZodOptional<z.ZodString>;
99
+ requestId: z.ZodOptional<z.ZodString>;
100
+ }, z.core.$strip>;
101
+ }, z.core.$strip>;
@@ -0,0 +1,35 @@
1
+ import * as z from "zod";
2
+ // Wire envelopes of /api/{write,query,batch,stream}. Only the envelope is
3
+ // validated; `data` payloads stay unknown and are typed by the caller.
4
+ export const serverErrorSchema = z.object({
5
+ code: z.string(),
6
+ httpStatus: z.number().optional(),
7
+ // Some gates (bad-request helper in server.ts, pii-leak-guard) send no
8
+ // i18nKey; keeping their `code` beats collapsing them into network_error.
9
+ i18nKey: z.string().default("errors.unknown"),
10
+ message: z.string(),
11
+ details: z.unknown().optional(),
12
+ i18nParams: z.record(z.string(), z.unknown()).optional(),
13
+ docsUrl: z.string().optional(),
14
+ requestId: z.string().optional(),
15
+ });
16
+ const writeItemSchema = z.discriminatedUnion("isSuccess", [
17
+ z.object({ isSuccess: z.literal(true), data: z.unknown().optional() }),
18
+ z.object({ isSuccess: z.literal(false), error: serverErrorSchema }),
19
+ ]);
20
+ export const writeEnvelopeSchema = writeItemSchema;
21
+ export const batchEnvelopeSchema = z.discriminatedUnion("isSuccess", [
22
+ z.object({ isSuccess: z.literal(true), results: z.array(writeItemSchema) }),
23
+ z.object({
24
+ isSuccess: z.literal(false),
25
+ error: serverErrorSchema,
26
+ failedIndex: z.number(),
27
+ results: z.array(writeItemSchema),
28
+ }),
29
+ ]);
30
+ // `error` is nullish: a null/absent error means success, as before.
31
+ export const queryEnvelopeSchema = z.object({
32
+ data: z.unknown().optional(),
33
+ error: serverErrorSchema.nullish(),
34
+ });
35
+ export const errorOnlyEnvelopeSchema = z.object({ error: serverErrorSchema });
@@ -0,0 +1,16 @@
1
+ import type { DispatcherError } from "../headless/index.ts";
2
+ type ServerErrorInfo = {
3
+ readonly code: string;
4
+ readonly httpStatus: number;
5
+ readonly i18nKey: string;
6
+ readonly i18nParams?: Readonly<Record<string, unknown>>;
7
+ readonly message: string;
8
+ readonly details?: unknown;
9
+ readonly docsUrl?: string;
10
+ readonly requestId?: string;
11
+ readonly timestamp?: string;
12
+ };
13
+ export declare function mapServerError(serverError: ServerErrorInfo): DispatcherError;
14
+ export declare function buildNetworkError(cause: unknown): DispatcherError;
15
+ export declare function buildAbortError(): DispatcherError;
16
+ export {};
@@ -0,0 +1,82 @@
1
+ import { isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
2
+ // Narrow cast into the DispatcherError shape. Pass-through for everything
3
+ // except `details.fields`, which we normalize: the server uses
4
+ // ValidationFieldIssue (path/code/i18nKey/params), which is structurally
5
+ // identical to FieldIssue — but we re-build it so a future field-addition
6
+ // on either side forces a compile error here, the right place to update.
7
+ export function mapServerError(serverError) {
8
+ const normalizedDetails = normalizeDetails(serverError.details);
9
+ return {
10
+ code: serverError.code,
11
+ httpStatus: serverError.httpStatus,
12
+ i18nKey: serverError.i18nKey,
13
+ message: serverError.message,
14
+ ...(serverError.i18nParams && { i18nParams: serverError.i18nParams }),
15
+ ...(normalizedDetails && { details: normalizedDetails }),
16
+ ...(serverError.docsUrl && { docsUrl: serverError.docsUrl }),
17
+ ...(serverError.requestId && { requestId: serverError.requestId }),
18
+ };
19
+ }
20
+ function normalizeDetails(details) {
21
+ if (!isPlainObject(details))
22
+ return undefined;
23
+ const { fields, ...otherDetails } = details;
24
+ if (!Array.isArray(fields)) {
25
+ // Details without fields still pass through — non-validation errors
26
+ // (rate-limit, version-conflict, ...) carry their own structured
27
+ // payload here.
28
+ return otherDetails;
29
+ }
30
+ const mappedFields = [];
31
+ for (const r of fields) {
32
+ if (!isPlainObject(r)) {
33
+ // Server sent a non-object entry in details.fields — contract
34
+ // breach (ValidationFieldIssue shape is required). Warn so the
35
+ // skip doesn't hide a broken server build.
36
+ // biome-ignore lint/suspicious/noConsole: ops-visible warning when the server breaks the validation-error contract
37
+ console.warn("[dispatcher-live] dropping malformed field issue (not an object):", r);
38
+ continue;
39
+ }
40
+ if (typeof r["path"] !== "string" ||
41
+ typeof r["code"] !== "string" ||
42
+ typeof r["i18nKey"] !== "string") {
43
+ // Entry is an object but missing required keys — same reasoning.
44
+ // biome-ignore lint/suspicious/noConsole: ops-visible warning when the server breaks the validation-error contract
45
+ console.warn("[dispatcher-live] dropping malformed field issue (missing keys):", r);
46
+ continue;
47
+ }
48
+ mappedFields.push({
49
+ path: r["path"],
50
+ code: r["code"],
51
+ i18nKey: r["i18nKey"],
52
+ ...(isPlainObject(r["params"]) && { params: r["params"] }),
53
+ });
54
+ }
55
+ return { ...otherDetails, fields: mappedFields };
56
+ }
57
+ // Builds a DispatcherError for a failure that never reached the server —
58
+ // network dropped, DNS error, CORS block, fetch() threw. The UI should
59
+ // surface this differently (offline indicator, retry button) from a
60
+ // typed server-rejection; callers key off `code === "network_error"`.
61
+ export function buildNetworkError(cause) {
62
+ const message = cause instanceof Error ? cause.message : String(cause ?? "network error");
63
+ return {
64
+ code: "network_error",
65
+ // 0 is the JS fetch-failure convention (xhr.status is 0 on abort/fail
66
+ // too). Distinguishes network from typed 5xx server errors.
67
+ httpStatus: 0,
68
+ i18nKey: "dispatcher.errors.network",
69
+ message,
70
+ };
71
+ }
72
+ // Abort-specific error — used when the caller canceled via AbortSignal.
73
+ // Distinct code so a form submit that was cancelled because the user
74
+ // closed the modal doesn't toast "network error" (confusing).
75
+ export function buildAbortError() {
76
+ return {
77
+ code: "aborted",
78
+ httpStatus: 0,
79
+ i18nKey: "dispatcher.errors.aborted",
80
+ message: "request was aborted",
81
+ };
82
+ }