@xemahq/ui-kernel 0.11.1 → 0.12.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 (257) hide show
  1. package/dist/errors/http-error-status.d.ts +17 -0
  2. package/dist/errors/http-error-status.d.ts.map +1 -0
  3. package/dist/errors/http-error-status.js +59 -0
  4. package/dist/errors/http-error-status.js.map +1 -0
  5. package/dist/errors/index.d.ts +2 -0
  6. package/dist/errors/index.d.ts.map +1 -0
  7. package/dist/errors/index.js +2 -0
  8. package/dist/errors/index.js.map +1 -0
  9. package/dist/index.d.ts +1 -0
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +1 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/lib/biome-host/errors.d.ts.map +1 -1
  14. package/dist/lib/biome-host/errors.js +1 -19
  15. package/dist/lib/biome-host/errors.js.map +1 -1
  16. package/dist/offline/index.d.ts.map +1 -1
  17. package/dist/offline/index.js.map +1 -1
  18. package/dist/offline/online-controller.d.ts.map +1 -1
  19. package/dist/offline/online-controller.js +6 -1
  20. package/dist/offline/online-controller.js.map +1 -1
  21. package/dist/offline/outbox.d.ts.map +1 -1
  22. package/dist/offline/outbox.js +2 -24
  23. package/dist/offline/outbox.js.map +1 -1
  24. package/package.json +1 -2
  25. package/src/index.ts +0 -17
  26. package/src/lib/biome-host/agent-validation.ts +0 -239
  27. package/src/lib/biome-host/biome-builders.ts +0 -112
  28. package/src/lib/biome-host/biome-mode.ts +0 -6
  29. package/src/lib/biome-host/biome-navigation.ts +0 -37
  30. package/src/lib/biome-host/biome-registry.ts +0 -299
  31. package/src/lib/biome-host/biome-scope-hooks.ts +0 -41
  32. package/src/lib/biome-host/biome-scope.tsx +0 -52
  33. package/src/lib/biome-host/biome-scoped-query.ts +0 -134
  34. package/src/lib/biome-host/create-biome-orval-config.ts +0 -82
  35. package/src/lib/biome-host/define-web-biome.spec.ts +0 -221
  36. package/src/lib/biome-host/define-web-biome.ts +0 -222
  37. package/src/lib/biome-host/errors.ts +0 -220
  38. package/src/lib/biome-host/frontend-biome.ts +0 -256
  39. package/src/lib/biome-host/host-bridge.ts +0 -281
  40. package/src/lib/biome-host/host-sources.ts +0 -54
  41. package/src/lib/biome-host/i18n-hooks.ts +0 -51
  42. package/src/lib/biome-host/i18n-port.test.ts +0 -50
  43. package/src/lib/biome-host/i18n-port.ts +0 -96
  44. package/src/lib/biome-host/index.ts +0 -35
  45. package/src/lib/biome-host/realtime-hooks.ts +0 -75
  46. package/src/lib/biome-host/realtime-port.ts +0 -115
  47. package/src/lib/biome-host/session-contributions.ts +0 -296
  48. package/src/lib/biome-host/use-mutation-with-error-toast.ts +0 -90
  49. package/src/lib/biome-host/use-page-state.ts +0 -248
  50. package/src/lib/capabilities/capability-context.ts +0 -25
  51. package/src/lib/capabilities/capability-provider.tsx +0 -73
  52. package/src/lib/capabilities/index.ts +0 -17
  53. package/src/lib/capabilities/types.ts +0 -69
  54. package/src/lib/capabilities/use-capability.ts +0 -79
  55. package/src/lib/contribution-registry/contribution-registry.spec.ts +0 -141
  56. package/src/lib/contribution-registry/contribution-registry.ts +0 -204
  57. package/src/lib/contribution-registry/index.ts +0 -9
  58. package/src/lib/contribution-registry/renderable-registry.ts +0 -142
  59. package/src/lib/system-bus/capability-invoke.ts +0 -92
  60. package/src/lib/system-bus/deeplink.ts +0 -210
  61. package/src/lib/system-bus/enums.ts +0 -86
  62. package/src/lib/system-bus/host-ports.ts +0 -93
  63. package/src/lib/system-bus/index.ts +0 -16
  64. package/src/lib/system-bus/intent-registry.ts +0 -109
  65. package/src/lib/system-bus/intents.ts +0 -113
  66. package/src/lib/system-bus/palette.ts +0 -78
  67. package/src/lib/system-bus/system-bus-builder.ts +0 -159
  68. package/src/lib/system-bus/system-bus.ts +0 -37
  69. package/src/lib/system-bus/windows.ts +0 -51
  70. package/src/offline/id.ts +0 -16
  71. package/src/offline/index.ts +0 -54
  72. package/src/offline/mutation.ts +0 -75
  73. package/src/offline/offline-status-badge.tsx +0 -51
  74. package/src/offline/online-controller.ts +0 -105
  75. package/src/offline/outbox.test.ts +0 -172
  76. package/src/offline/outbox.ts +0 -348
  77. package/src/offline/react-hooks.ts +0 -40
  78. package/src/offline/react.tsx +0 -32
  79. package/src/offline/storage.ts +0 -112
  80. package/src/offline/types.ts +0 -77
  81. package/src/org-db/components/DbResultTable.tsx +0 -176
  82. package/src/org-db/index.ts +0 -1
  83. package/src/pdf/index.ts +0 -11
  84. package/src/registry/index.ts +0 -9
  85. package/src/registry/lib/agent-validation-host.ts +0 -36
  86. package/src/registry/lib/biome-slot.tsx +0 -50
  87. package/src/registry/lib/biomes-enabled-context.ts +0 -20
  88. package/src/registry/lib/extension-points.ts +0 -134
  89. package/src/registry/lib/primitives/SessionEventCard.tsx +0 -164
  90. package/src/registry/lib/primitives/SessionEventTimeline.tsx +0 -95
  91. package/src/registry/lib/primitives/SessionMutationBar.tsx +0 -76
  92. package/src/registry/lib/primitives/SessionTabbedDrawer.tsx +0 -165
  93. package/src/registry/lib/primitives/index.ts +0 -18
  94. package/src/registry/lib/session-context-builder.ts +0 -84
  95. package/src/registry/lib/session-context-provider.tsx +0 -33
  96. package/src/registry/lib/session-context.ts +0 -21
  97. package/src/registry/lib/session-selectors.ts +0 -272
  98. package/src/session/comments/CommentRail.tsx +0 -164
  99. package/src/session/index.ts +0 -3
  100. package/src/session/lib/cn.ts +0 -11
  101. package/src/session/shell/SessionWorkspaceShell.tsx +0 -147
  102. package/src/session-kit/approvals/ApprovalButton.tsx +0 -89
  103. package/src/session-kit/approvals/ApprovalCard.tsx +0 -341
  104. package/src/session-kit/approvals/ApprovalsCenter.tsx +0 -336
  105. package/src/session-kit/approvals/CapabilityApprovalStickyBar.tsx +0 -118
  106. package/src/session-kit/approvals/Obligation.tsx +0 -111
  107. package/src/session-kit/approvals/ScopedBody.tsx +0 -392
  108. package/src/session-kit/approvals/approval-icons.ts +0 -31
  109. package/src/session-kit/approvals/approval-model.ts +0 -204
  110. package/src/session-kit/approvals/index.ts +0 -22
  111. package/src/session-kit/approvals/obligation-display.ts +0 -100
  112. package/src/session-kit/approvals/risk-accent.ts +0 -47
  113. package/src/session-kit/approvals/scope-icons.ts +0 -19
  114. package/src/session-kit/combobox/Combobox.tsx +0 -358
  115. package/src/session-kit/combobox/use-click-outside.ts +0 -21
  116. package/src/session-kit/display/ContextHeader.tsx +0 -148
  117. package/src/session-kit/display/FileDiffCard.tsx +0 -140
  118. package/src/session-kit/display/MD.tsx +0 -162
  119. package/src/session-kit/display/MessageTurn.tsx +0 -157
  120. package/src/session-kit/display/ThinkingPanel.tsx +0 -81
  121. package/src/session-kit/display/TodoChecklist.tsx +0 -120
  122. package/src/session-kit/display/TokenMeter.tsx +0 -89
  123. package/src/session-kit/display/ToolStrip.tsx +0 -278
  124. package/src/session-kit/display/TypingDots.tsx +0 -24
  125. package/src/session-kit/index.ts +0 -44
  126. package/src/session-kit/lib/enums.ts +0 -66
  127. package/src/session-kit/lib/portal-accent.ts +0 -30
  128. package/src/session-kit/lib/status-dot.ts +0 -68
  129. package/src/session-kit/primitives/Avatar.tsx +0 -44
  130. package/src/session-kit/primitives/PortalGlyph.tsx +0 -51
  131. package/src/session-kit/primitives/RiskPill.tsx +0 -95
  132. package/src/session-kit/primitives/ScopeDot.tsx +0 -47
  133. package/src/session-kit/primitives/Segmented.tsx +0 -71
  134. package/src/ui/branding/app-branding-context.ts +0 -20
  135. package/src/ui/branding/app-branding-provider.tsx +0 -123
  136. package/src/ui/branding/sanitize.ts +0 -89
  137. package/src/ui/breakpoints.ts +0 -14
  138. package/src/ui/capture/document-preview.tsx +0 -166
  139. package/src/ui/capture/field-spec-to-zod.test.ts +0 -81
  140. package/src/ui/capture/field-spec-to-zod.ts +0 -174
  141. package/src/ui/capture/field-spec-validate.ts +0 -236
  142. package/src/ui/capture/field-spec.test.ts +0 -49
  143. package/src/ui/capture/field-spec.ts +0 -274
  144. package/src/ui/capture/index.ts +0 -51
  145. package/src/ui/capture/schema-field-input.tsx +0 -620
  146. package/src/ui/capture/schema-form.tsx +0 -149
  147. package/src/ui/capture/submit-values.test.ts +0 -70
  148. package/src/ui/capture/submit-values.ts +0 -63
  149. package/src/ui/capture/use-prefill.ts +0 -186
  150. package/src/ui/capture/use-schema-validation.ts +0 -145
  151. package/src/ui/capture/use-wizard.ts +0 -180
  152. package/src/ui/capture/value-format.ts +0 -32
  153. package/src/ui/capture/wizard.tsx +0 -105
  154. package/src/ui/charts/bar-chart.tsx +0 -139
  155. package/src/ui/charts/chart-frame.tsx +0 -125
  156. package/src/ui/charts/chart-types.ts +0 -52
  157. package/src/ui/charts/chart-utils.ts +0 -190
  158. package/src/ui/charts/charts.test.tsx +0 -204
  159. package/src/ui/charts/donut-chart.tsx +0 -129
  160. package/src/ui/charts/index.ts +0 -27
  161. package/src/ui/charts/line-chart.tsx +0 -202
  162. package/src/ui/charts/sparkline.tsx +0 -109
  163. package/src/ui/chrome/AsyncBoundary.tsx +0 -74
  164. package/src/ui/chrome/EmptyState.tsx +0 -257
  165. package/src/ui/chrome/ErrorCard.tsx +0 -63
  166. package/src/ui/chrome/LoadingState.tsx +0 -61
  167. package/src/ui/chrome/PageHeader.tsx +0 -137
  168. package/src/ui/chrome/RecordCardList.tsx +0 -98
  169. package/src/ui/chrome/StateCard.tsx +0 -150
  170. package/src/ui/chrome/confirm-delete-dialog.tsx +0 -59
  171. package/src/ui/chrome/page-shell.spec.tsx +0 -117
  172. package/src/ui/chrome/page-shell.tsx +0 -221
  173. package/src/ui/chrome/scope-badge.tsx +0 -40
  174. package/src/ui/chrome/status-badge.tsx +0 -79
  175. package/src/ui/cn.ts +0 -32
  176. package/src/ui/design-tokens.ts +0 -372
  177. package/src/ui/hooks/use-debounced-value.ts +0 -16
  178. package/src/ui/hooks/use-is-mobile.ts +0 -28
  179. package/src/ui/index.ts +0 -110
  180. package/src/ui/pdf/pdf-preview.tsx +0 -122
  181. package/src/ui/primitives/alert-dialog.tsx +0 -104
  182. package/src/ui/primitives/async-combobox.tsx +0 -182
  183. package/src/ui/primitives/badge-variants.ts +0 -21
  184. package/src/ui/primitives/badge.tsx +0 -25
  185. package/src/ui/primitives/button-variants.ts +0 -31
  186. package/src/ui/primitives/button.tsx +0 -29
  187. package/src/ui/primitives/card.tsx +0 -43
  188. package/src/ui/primitives/checkbox.tsx +0 -26
  189. package/src/ui/primitives/collapsible.tsx +0 -9
  190. package/src/ui/primitives/dialog.tsx +0 -103
  191. package/src/ui/primitives/dropdown-menu.tsx +0 -179
  192. package/src/ui/primitives/form-stepper.tsx +0 -94
  193. package/src/ui/primitives/form-stepper.types.ts +0 -15
  194. package/src/ui/primitives/input.tsx +0 -22
  195. package/src/ui/primitives/label.tsx +0 -17
  196. package/src/ui/primitives/overflow-tabs.tsx +0 -331
  197. package/src/ui/primitives/popover.tsx +0 -33
  198. package/src/ui/primitives/preview-device-frame.tsx +0 -213
  199. package/src/ui/primitives/radio-group.tsx +0 -36
  200. package/src/ui/primitives/resizable.tsx +0 -67
  201. package/src/ui/primitives/scroll-area.tsx +0 -38
  202. package/src/ui/primitives/select.tsx +0 -143
  203. package/src/ui/primitives/separator.tsx +0 -20
  204. package/src/ui/primitives/sheet.tsx +0 -107
  205. package/src/ui/primitives/skeleton.tsx +0 -99
  206. package/src/ui/primitives/switch.tsx +0 -27
  207. package/src/ui/primitives/table.tsx +0 -72
  208. package/src/ui/primitives/tabs.tsx +0 -53
  209. package/src/ui/primitives/tag-multi-select.tsx +0 -261
  210. package/src/ui/primitives/textarea.tsx +0 -21
  211. package/src/ui/primitives/tooltip.tsx +0 -30
  212. package/src/ui/primitives/url-preview-chrome.tsx +0 -103
  213. package/src/vista/GenericCatalogueSurface.tsx +0 -179
  214. package/src/vista/SurfaceFallbackCard.tsx +0 -109
  215. package/src/vista/VistaPanel.tsx +0 -163
  216. package/src/vista/form-payload.spec.ts +0 -139
  217. package/src/vista/html/CustomUiFrame.spec.tsx +0 -127
  218. package/src/vista/html/CustomUiFrame.tsx +0 -206
  219. package/src/vista/html/custom-ui-frame-bridge.spec.ts +0 -191
  220. package/src/vista/html/custom-ui-frame-bridge.ts +0 -98
  221. package/src/vista/html/custom-ui-frame-contract.ts +0 -88
  222. package/src/vista/html/custom-ui-intents.spec.ts +0 -135
  223. package/src/vista/html/custom-ui-intents.ts +0 -155
  224. package/src/vista/html/custom-ui-srcdoc.spec.ts +0 -151
  225. package/src/vista/html/custom-ui-srcdoc.ts +0 -193
  226. package/src/vista/html/index.ts +0 -13
  227. package/src/vista/index.ts +0 -52
  228. package/src/vista/surface-catalogue.spec.ts +0 -140
  229. package/src/vista/surface-catalogue.ts +0 -90
  230. package/src/vista/surface-icons.ts +0 -57
  231. package/src/vista/surface-registry.ts +0 -56
  232. package/src/vista/surfaces/ChartSurface.tsx +0 -34
  233. package/src/vista/surfaces/FilesSurface.tsx +0 -202
  234. package/src/vista/surfaces/FormSurface.tsx +0 -380
  235. package/src/vista/surfaces/HtmlSurface.tsx +0 -43
  236. package/src/vista/surfaces/TableSurface.tsx +0 -100
  237. package/src/vista/surfaces/UrlSurface.tsx +0 -40
  238. package/src/vista/surfaces/blob-surfaces.tsx +0 -139
  239. package/src/vista/surfaces/elicitation-transport.spec.ts +0 -369
  240. package/src/vista/surfaces/elicitation-transport.ts +0 -367
  241. package/src/vista/surfaces/file-surface-utils.ts +0 -69
  242. package/src/vista/surfaces/index.ts +0 -24
  243. package/src/vista/surfaces/register-surfaces.tsx +0 -139
  244. package/src/vista/surfaces/text-surfaces.tsx +0 -132
  245. package/src/vista/use-vista-tabs.ts +0 -196
  246. package/src/vista/vista-code-renderer-context.ts +0 -16
  247. package/src/vista/vista-code-renderer.tsx +0 -35
  248. package/src/vista/vista-file-context.ts +0 -14
  249. package/src/vista/vista-file-source.tsx +0 -141
  250. package/src/vista/vista-form-context.ts +0 -20
  251. package/src/vista/vista-form-host.tsx +0 -48
  252. package/src/vista/vista-model.ts +0 -137
  253. package/src/vista/vista-open-context.tsx +0 -27
  254. package/src/vista/vista-open-state.ts +0 -11
  255. package/src/vista/vista-payloads.ts +0 -635
  256. package/src/vista/vista-tabs-manifest.ts +0 -138
  257. package/src/vista/vista-tools.ts +0 -232
@@ -1,367 +0,0 @@
1
- // ═══════════════════════════════════════════════════════════════════════════
2
- // The `form` surface's transport — browser → owning service, direct.
3
- //
4
- // This module is the ONLY code that ever reads a captured field value out of
5
- // the form surface, and it does exactly one thing with it: put it in the body
6
- // of a `fetch` to an endpoint derived from the HOST-CONFIGURED trusted
7
- // elicitation-service base URL, bearing the SUBJECT's own JWT.
8
- //
9
- // Three properties make "the agent cannot receive the value" structural:
10
- //
11
- // • the value is a PARAMETER, never a return: every exported function returns
12
- // `VistaFormOutcome | null`, a closed scalar-only shape (see
13
- // `../vista-form-host`). The values object is not reachable from any
14
- // return, any thrown error, or any callback;
15
- // • the response is PROJECTED, not passed through: `toOutcome` constructs a
16
- // fresh object with exactly three keys, so a service that echoed a secret
17
- // back could still not leak one through this boundary;
18
- // • the payload carries only an opaque ref. It has NO network authority. This
19
- // module validates the host-configured base URL and derives the exact
20
- // status/submit paths before a bearer token or field value reaches fetch.
21
- //
22
- // Errors carry the SERVICE's message verbatim (that is how the backend's hard
23
- // 400 on an empty credential form becomes readable UI copy) and never the
24
- // request body.
25
- // ═══════════════════════════════════════════════════════════════════════════
26
- import { isValidVistaFormRef } from '../vista-payloads';
27
-
28
- import type { VistaFormOutcome } from '../vista-form-context';
29
-
30
- /** A non-2xx answer from the owning service, carrying its message verbatim. */
31
- export class VistaFormSubmitError extends Error {
32
- constructor(
33
- readonly status: number,
34
- message: string,
35
- ) {
36
- super(message);
37
- this.name = 'VistaFormSubmitError';
38
- }
39
- }
40
-
41
- /** Invalid trusted-host transport configuration or unsafe path input. */
42
- export class VistaFormTransportConfigError extends Error {
43
- constructor(message: string) {
44
- super(message);
45
- this.name = 'VistaFormTransportConfigError';
46
- }
47
- }
48
-
49
- export interface TrustedElicitationEndpoints {
50
- readonly statusUrl: string;
51
- readonly submitUrl: string;
52
- }
53
-
54
- type UnknownRecord = Readonly<Record<string, unknown>>;
55
-
56
- function asRecord(value: unknown): UnknownRecord | null {
57
- return value !== null && typeof value === 'object' && !Array.isArray(value)
58
- ? (value as UnknownRecord)
59
- : null;
60
- }
61
-
62
- /**
63
- * Unwrap the platform `{ data: … }` envelope when present. Total: a flat body
64
- * is returned as-is, so the transport works against either wire shape without
65
- * a second code path.
66
- */
67
- function unwrapEnvelope(body: unknown): UnknownRecord | null {
68
- const record = asRecord(body);
69
- if (record === null) {
70
- return null;
71
- }
72
- const inner = asRecord(record.data);
73
- return inner ?? record;
74
- }
75
-
76
- /**
77
- * Best-effort extraction of the SERVICE's error message. Falls back to a
78
- * status-derived sentence — never to an empty string, because an empty error is
79
- * indistinguishable from success in the UI.
80
- */
81
- export function extractServiceMessage(body: unknown, status: number): string {
82
- const record = asRecord(body);
83
- const candidate =
84
- record === null
85
- ? undefined
86
- : (record.message ?? asRecord(record.error)?.message ?? record.error);
87
- if (typeof candidate === 'string' && candidate.length > 0) {
88
- return candidate;
89
- }
90
- if (Array.isArray(candidate)) {
91
- const joined = candidate
92
- .filter((m): m is string => typeof m === 'string')
93
- .join(' ');
94
- if (joined.length > 0) {
95
- return joined;
96
- }
97
- }
98
- if (typeof body === 'string' && body.length > 0) {
99
- return body;
100
- }
101
- return `The service rejected the submission (HTTP ${status}).`;
102
- }
103
-
104
- async function readBody(response: Response): Promise<unknown> {
105
- const contentType = response.headers.get('content-type');
106
- try {
107
- if (contentType !== null && contentType.includes('application/json')) {
108
- return await response.json();
109
- }
110
- return await response.text();
111
- } catch {
112
- return null;
113
- }
114
- }
115
-
116
- /**
117
- * Project a service response onto {@link VistaFormOutcome}. Constructs a FRESH
118
- * object with exactly three keys — nothing else from the response survives.
119
- * Returns `null` when the service reports the elicitation is not settled.
120
- */
121
- function toOutcome(body: unknown, ref: string): VistaFormOutcome | null {
122
- const record = unwrapEnvelope(body);
123
- if (record === null) {
124
- return null;
125
- }
126
- const submitted =
127
- record.submitted === true ||
128
- (typeof record.status === 'string' && record.status === 'submitted');
129
- if (!submitted) {
130
- return null;
131
- }
132
- const connectionId =
133
- typeof record.connectionId === 'string' && record.connectionId.length > 0
134
- ? record.connectionId
135
- : null;
136
- return { submitted: true, ref, connectionId };
137
- }
138
-
139
- /** The `Authorization`/`Content-Type` pair every request here carries. */
140
- function authHeaders(
141
- accessToken: string,
142
- json: boolean,
143
- ): Record<string, string> {
144
- const headers: Record<string, string> = {
145
- Authorization: `Bearer ${accessToken}`,
146
- Accept: 'application/json',
147
- };
148
- if (json) {
149
- headers['Content-Type'] = 'application/json';
150
- }
151
- return headers;
152
- }
153
-
154
- function browserOrigin(): string | undefined {
155
- return typeof globalThis.location === 'undefined'
156
- ? undefined
157
- : globalThis.location.origin;
158
- }
159
-
160
- function isLoopbackHostname(hostname: string): boolean {
161
- return (
162
- hostname === 'localhost' ||
163
- hostname.endsWith('.localhost') ||
164
- hostname === '127.0.0.1' ||
165
- hostname === '[::1]'
166
- );
167
- }
168
-
169
- /**
170
- * Parse the host's deploy-time trust anchor. It must be a canonical absolute
171
- * HTTP(S) URL without credentials/query/fragment. HTTPS is mandatory except
172
- * for loopback or same-host HTTP when the page itself is also served over HTTP.
173
- */
174
- function trustedApiBaseUrl(
175
- raw: string,
176
- activeBrowserOrigin: string | undefined,
177
- ): URL {
178
- if (raw.length === 0 || raw.trim() !== raw) {
179
- throw new VistaFormTransportConfigError(
180
- 'The trusted elicitation API base URL is empty or contains whitespace.',
181
- );
182
- }
183
-
184
- let url: URL;
185
- try {
186
- url = new URL(raw);
187
- } catch {
188
- throw new VistaFormTransportConfigError(
189
- 'The trusted elicitation API base URL must be absolute.',
190
- );
191
- }
192
-
193
- if (
194
- (url.protocol !== 'https:' && url.protocol !== 'http:') ||
195
- url.username.length > 0 ||
196
- url.password.length > 0 ||
197
- url.search.length > 0 ||
198
- url.hash.length > 0
199
- ) {
200
- throw new VistaFormTransportConfigError(
201
- 'The trusted elicitation API base URL must use HTTP(S) and contain no credentials, query, or fragment.',
202
- );
203
- }
204
-
205
- const canonicalPath =
206
- url.pathname === '/' ? '' : url.pathname.replace(/\/+$/, '');
207
- const canonical = `${url.origin}${canonicalPath}`;
208
- const suppliedWithoutOneTrailingSlash = raw.endsWith('/')
209
- ? raw.slice(0, -1)
210
- : raw;
211
- if (suppliedWithoutOneTrailingSlash !== canonical) {
212
- throw new VistaFormTransportConfigError(
213
- 'The trusted elicitation API base URL must be canonical and contain no traversal or ambiguous path.',
214
- );
215
- }
216
-
217
- if (url.protocol === 'http:' && !isLoopbackHostname(url.hostname)) {
218
- let page: URL | null = null;
219
- if (activeBrowserOrigin !== undefined) {
220
- try {
221
- page = new URL(activeBrowserOrigin);
222
- } catch {
223
- page = null;
224
- }
225
- }
226
- if (
227
- page === null ||
228
- page.protocol !== 'http:' ||
229
- page.hostname !== url.hostname
230
- ) {
231
- throw new VistaFormTransportConfigError(
232
- 'Insecure elicitation HTTP is allowed only on loopback or the same host as an HTTP development page.',
233
- );
234
- }
235
- }
236
-
237
- return new URL(canonical);
238
- }
239
-
240
- /**
241
- * Derive the only two authenticated endpoints from trusted host configuration
242
- * plus one opaque path segment. Calling this directly remains safe even if a
243
- * caller bypasses the surface-payload validator.
244
- */
245
- export function resolveTrustedElicitationEndpoints(
246
- apiBaseUrl: string,
247
- ref: string,
248
- activeBrowserOrigin: string | undefined = browserOrigin(),
249
- ): TrustedElicitationEndpoints {
250
- if (!isValidVistaFormRef(ref)) {
251
- throw new VistaFormTransportConfigError(
252
- 'The elicitation reference is not a valid opaque base64url path segment.',
253
- );
254
- }
255
- const base = trustedApiBaseUrl(apiBaseUrl, activeBrowserOrigin)
256
- .toString()
257
- .replace(/\/$/, '');
258
- const statusUrl = `${base}/${ref}`;
259
- return { statusUrl, submitUrl: `${statusUrl}/submit` };
260
- }
261
-
262
- /**
263
- * Resolve an unauthenticated launch path under the SAME trusted service origin.
264
- * Absolute/network-path URLs and dot-segment traversal fail closed.
265
- */
266
- export function resolveTrustedElicitationLaunchUrl(
267
- apiBaseUrl: string,
268
- path: string,
269
- activeBrowserOrigin: string | undefined = browserOrigin(),
270
- ): string {
271
- const base = trustedApiBaseUrl(apiBaseUrl, activeBrowserOrigin);
272
- if (
273
- !path.startsWith('/') ||
274
- path.startsWith('//') ||
275
- path.includes('\\') ||
276
- path.includes('#')
277
- ) {
278
- throw new VistaFormTransportConfigError(
279
- 'The elicitation launch target must be a root-relative service path.',
280
- );
281
- }
282
- const resolved = new URL(path, `${base.origin}/`);
283
- if (
284
- resolved.origin !== base.origin ||
285
- `${resolved.pathname}${resolved.search}` !== path
286
- ) {
287
- throw new VistaFormTransportConfigError(
288
- 'The elicitation launch path contains traversal or an ambiguous encoding.',
289
- );
290
- }
291
- return resolved.toString();
292
- }
293
-
294
- /**
295
- * POST the captured fields to the owning service.
296
- *
297
- * @throws {VistaFormSubmitError} on a non-2xx answer, carrying the service's
298
- * own message so a hard 400 (e.g. "no credential form is declared") is what the
299
- * user reads.
300
- */
301
- export async function submitElicitationFields(args: {
302
- readonly apiBaseUrl: string;
303
- readonly ref: string;
304
- readonly accessToken: string;
305
- readonly fields: Readonly<Record<string, string>>;
306
- }): Promise<VistaFormOutcome> {
307
- const { submitUrl } = resolveTrustedElicitationEndpoints(
308
- args.apiBaseUrl,
309
- args.ref,
310
- );
311
- const response = await fetch(submitUrl, {
312
- method: 'POST',
313
- headers: authHeaders(args.accessToken, true),
314
- body: JSON.stringify({ fields: args.fields }),
315
- credentials: 'omit',
316
- // A 307/308 could otherwise replay the credential body to a different
317
- // origin. Authenticated elicitation endpoints must never redirect.
318
- redirect: 'error',
319
- });
320
- const body = await readBody(response);
321
- if (!response.ok) {
322
- throw new VistaFormSubmitError(
323
- response.status,
324
- extractServiceMessage(body, response.status),
325
- );
326
- }
327
- const outcome = toOutcome(body, args.ref);
328
- if (outcome === null) {
329
- throw new VistaFormSubmitError(
330
- response.status,
331
- 'The service accepted the request but did not report the elicitation as submitted.',
332
- );
333
- }
334
- return outcome;
335
- }
336
-
337
- /**
338
- * Read the elicitation's current state. Used by the OAuth / app-install handoff,
339
- * where completion happens in another window and the only signal available to
340
- * this tab is the service's own record.
341
- *
342
- * Returns `null` while still pending — an explicit "not yet", never a guess.
343
- */
344
- export async function readElicitationStatus(args: {
345
- readonly apiBaseUrl: string;
346
- readonly ref: string;
347
- readonly accessToken: string;
348
- }): Promise<VistaFormOutcome | null> {
349
- const { statusUrl } = resolveTrustedElicitationEndpoints(
350
- args.apiBaseUrl,
351
- args.ref,
352
- );
353
- const response = await fetch(statusUrl, {
354
- method: 'GET',
355
- headers: authHeaders(args.accessToken, false),
356
- credentials: 'omit',
357
- redirect: 'error',
358
- });
359
- const body = await readBody(response);
360
- if (!response.ok) {
361
- throw new VistaFormSubmitError(
362
- response.status,
363
- extractServiceMessage(body, response.status),
364
- );
365
- }
366
- return toOutcome(body, args.ref);
367
- }
@@ -1,69 +0,0 @@
1
- import type { VistaFileEntry } from '../vista-payloads';
2
-
3
- interface FileExtMeta {
4
- readonly color: string;
5
- readonly tag: string;
6
- }
7
-
8
- const EXT_META: Readonly<Record<string, FileExtMeta>> = {
9
- ts: { color: 'hsl(var(--info))', tag: 'TS' },
10
- tsx: { color: 'hsl(var(--info))', tag: 'TSX' },
11
- js: { color: 'hsl(var(--warning))', tag: 'JS' },
12
- jsx: { color: 'hsl(var(--warning))', tag: 'JSX' },
13
- json: { color: 'hsl(var(--ink-3))', tag: 'JSON' },
14
- md: { color: 'hsl(var(--p-people))', tag: 'MD' },
15
- css: { color: 'hsl(var(--p-sales))', tag: 'CSS' },
16
- html: { color: 'hsl(var(--p-sales))', tag: 'HTML' },
17
- yaml: { color: 'hsl(var(--ink-3))', tag: 'YAML' },
18
- yml: { color: 'hsl(var(--ink-3))', tag: 'YAML' },
19
- };
20
-
21
- export function fileExtMeta(name: string): FileExtMeta {
22
- if (/\.test\.[tj]sx?$/.test(name) || /\.spec\.[tj]sx?$/.test(name)) {
23
- return { color: 'hsl(var(--success))', tag: 'TEST' };
24
- }
25
- const ext = name.split('.').pop() ?? '';
26
- return (
27
- EXT_META[ext] ?? {
28
- color: 'hsl(var(--ink-4))',
29
- tag: (ext || 'FILE').toUpperCase().slice(0, 4),
30
- }
31
- );
32
- }
33
-
34
- export interface VistaFileGroup {
35
- readonly dir: string;
36
- readonly files: readonly VistaFileEntry[];
37
- }
38
-
39
- function compareDirs(a: string, b: string): number {
40
- if (a === '') {
41
- return -1;
42
- }
43
- if (b === '') {
44
- return 1;
45
- }
46
- return a.localeCompare(b);
47
- }
48
-
49
- export function groupFilesByFolder(
50
- files: readonly VistaFileEntry[],
51
- ): VistaFileGroup[] {
52
- const groups = new Map<string, VistaFileEntry[]>();
53
- for (const file of files) {
54
- const slash = file.path.lastIndexOf('/');
55
- const dir = slash < 0 ? '' : file.path.slice(0, slash);
56
- const bucket = groups.get(dir);
57
- if (bucket) {
58
- bucket.push(file);
59
- } else {
60
- groups.set(dir, [file]);
61
- }
62
- }
63
- return [...groups.keys()].sort(compareDirs).map((dir) => ({
64
- dir,
65
- files: [...(groups.get(dir) ?? [])].sort((a, b) =>
66
- a.path.localeCompare(b.path),
67
- ),
68
- }));
69
- }
@@ -1,24 +0,0 @@
1
- import './register-surfaces';
2
-
3
- export { ChartSurface } from './ChartSurface';
4
- export { FilesSurface } from './FilesSurface';
5
- export {
6
- fileExtMeta,
7
- groupFilesByFolder,
8
- type VistaFileGroup,
9
- } from './file-surface-utils';
10
- export { FormSurface } from './FormSurface';
11
- export {
12
- extractServiceMessage,
13
- readElicitationStatus,
14
- resolveTrustedElicitationEndpoints,
15
- resolveTrustedElicitationLaunchUrl,
16
- submitElicitationFields,
17
- VistaFormSubmitError,
18
- VistaFormTransportConfigError,
19
- } from './elicitation-transport';
20
- export { HtmlSurface } from './HtmlSurface';
21
- export { TableSurface } from './TableSurface';
22
- export { UrlSurface } from './UrlSurface';
23
- export { CodeSurface, DiffSurface, JsonSurface } from './text-surfaces';
24
- export { ImageSurface, MediaSurface, PdfSurface } from './blob-surfaces';
@@ -1,139 +0,0 @@
1
- /**
2
- * Registration of the first-party surface renderers the UI KERNEL owns.
3
- *
4
- * ── The partition (deliberate, and the reason there is no slot-soup) ─────────
5
- * A kind is registered HERE when the kernel can render it standalone from its
6
- * payload (plus, for a file-backed kind, the host's injected `VistaFileSource`):
7
- *
8
- * url · html · code · json · diff · table · chart · files · image · media ·
9
- * pdf · form
10
- *
11
- * `form` (secure elicitation) belongs here even though it talks to a service:
12
- * it does so through the host-supplied `VistaFormHost` seam, exactly the way a
13
- * file-backed surface reads through `VistaFileSource`. The kernel owns the
14
- * renderer; the host owns only the token and the outcome sink.
15
- *
16
- * The remaining first-party kinds are HOST-COUPLED — they need the host's
17
- * router, its object views, its markdown renderer, or its biome registry — so
18
- * the HOST registers them with
19
- * `vistaSurfaceRegistry.registerFirstParty(...)`:
20
- *
21
- * markdown · web · biome-route · object · graph · app
22
- *
23
- * Every unregistered kind resolves to `SurfaceFallbackCard` with
24
- * `unknown-kind` — visible, typed, never blank.
25
- *
26
- * Importing this module REGISTERS. It is imported for its side effect by
27
- * `../index.ts`, so any consumer of `@xemahq/ui-kernel/vista` gets the kernel
28
- * builtins wired without an explicit call.
29
- */
30
- import { SurfaceKind } from '@xemahq/kernel-contracts/surface';
31
-
32
- import { ImageSurface, MediaSurface, PdfSurface } from './blob-surfaces';
33
- import { ChartSurface } from './ChartSurface';
34
- import { FilesSurface } from './FilesSurface';
35
- import { FormSurface } from './FormSurface';
36
- import { HtmlSurface } from './HtmlSurface';
37
- import { TableSurface } from './TableSurface';
38
- import { CodeSurface, DiffSurface, JsonSurface } from './text-surfaces';
39
- import { UrlSurface } from './UrlSurface';
40
- import { vistaSurfaceRegistry } from '../surface-registry';
41
- import { VISTA_SURFACE_VERSION } from '../vista-model';
42
- import {
43
- validateBlobPayload,
44
- validateChartPayload,
45
- validateDiffPayload,
46
- validateFilesPayload,
47
- validateFormPayload,
48
- validateHtmlPayload,
49
- validateJsonPayload,
50
- validateTablePayload,
51
- validateTextPayload,
52
- validateUrlPayload,
53
- type VistaBlobPayload,
54
- } from '../vista-payloads';
55
-
56
- /**
57
- * `media` additionally REQUIRES `contentType`: choosing between `<audio>` and
58
- * `<video>` from a URL would be a heuristic that fails on an extension-less
59
- * URL, and this plane does not ship heuristics that can be wrong.
60
- */
61
- function validateMediaPayload(raw: unknown): VistaBlobPayload | null {
62
- const payload = validateBlobPayload(raw);
63
- if (payload === null) {
64
- return null;
65
- }
66
- return payload.contentType === undefined ? null : payload;
67
- }
68
-
69
- vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Url, {
70
- version: VISTA_SURFACE_VERSION,
71
- validate: validateUrlPayload,
72
- render: (payload) => <UrlSurface {...payload} />,
73
- });
74
-
75
- vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Html, {
76
- version: VISTA_SURFACE_VERSION,
77
- validate: validateHtmlPayload,
78
- render: (payload) => <HtmlSurface {...payload} />,
79
- });
80
-
81
- vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Code, {
82
- version: VISTA_SURFACE_VERSION,
83
- validate: validateTextPayload,
84
- render: (payload) => <CodeSurface {...payload} />,
85
- });
86
-
87
- vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Json, {
88
- version: VISTA_SURFACE_VERSION,
89
- validate: validateJsonPayload,
90
- render: (payload) => <JsonSurface data={payload.data} />,
91
- });
92
-
93
- vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Diff, {
94
- version: VISTA_SURFACE_VERSION,
95
- validate: validateDiffPayload,
96
- render: (payload) => <DiffSurface {...payload} />,
97
- });
98
-
99
- vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Table, {
100
- version: VISTA_SURFACE_VERSION,
101
- validate: validateTablePayload,
102
- render: (payload) => <TableSurface {...payload} />,
103
- });
104
-
105
- vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Chart, {
106
- version: VISTA_SURFACE_VERSION,
107
- validate: validateChartPayload,
108
- render: (payload) => <ChartSurface {...payload} />,
109
- });
110
-
111
- vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Files, {
112
- version: VISTA_SURFACE_VERSION,
113
- validate: validateFilesPayload,
114
- render: (payload) => <FilesSurface {...payload} />,
115
- });
116
-
117
- vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Image, {
118
- version: VISTA_SURFACE_VERSION,
119
- validate: validateBlobPayload,
120
- render: (payload) => <ImageSurface {...payload} />,
121
- });
122
-
123
- vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Media, {
124
- version: VISTA_SURFACE_VERSION,
125
- validate: validateMediaPayload,
126
- render: (payload) => <MediaSurface {...payload} />,
127
- });
128
-
129
- vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Pdf, {
130
- version: VISTA_SURFACE_VERSION,
131
- validate: validateBlobPayload,
132
- render: (payload) => <PdfSurface {...payload} />,
133
- });
134
-
135
- vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Form, {
136
- version: VISTA_SURFACE_VERSION,
137
- validate: validateFormPayload,
138
- render: (payload) => <FormSurface {...payload} />,
139
- });