@xemahq/ui-kernel 0.11.0 → 0.11.2

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 (237) hide show
  1. package/dist/ui/chrome/page-shell.d.ts +1 -1
  2. package/dist/ui/chrome/page-shell.d.ts.map +1 -1
  3. package/dist/ui/chrome/page-shell.js +9 -4
  4. package/dist/ui/chrome/page-shell.js.map +1 -1
  5. package/package.json +6 -4
  6. package/src/index.ts +0 -17
  7. package/src/lib/biome-host/agent-validation.ts +0 -239
  8. package/src/lib/biome-host/biome-builders.ts +0 -112
  9. package/src/lib/biome-host/biome-mode.ts +0 -6
  10. package/src/lib/biome-host/biome-navigation.ts +0 -37
  11. package/src/lib/biome-host/biome-registry.ts +0 -299
  12. package/src/lib/biome-host/biome-scope-hooks.ts +0 -41
  13. package/src/lib/biome-host/biome-scope.tsx +0 -52
  14. package/src/lib/biome-host/biome-scoped-query.ts +0 -134
  15. package/src/lib/biome-host/create-biome-orval-config.ts +0 -82
  16. package/src/lib/biome-host/define-web-biome.spec.ts +0 -221
  17. package/src/lib/biome-host/define-web-biome.ts +0 -222
  18. package/src/lib/biome-host/errors.ts +0 -220
  19. package/src/lib/biome-host/frontend-biome.ts +0 -256
  20. package/src/lib/biome-host/host-bridge.ts +0 -281
  21. package/src/lib/biome-host/host-sources.ts +0 -54
  22. package/src/lib/biome-host/i18n-hooks.ts +0 -51
  23. package/src/lib/biome-host/i18n-port.test.ts +0 -50
  24. package/src/lib/biome-host/i18n-port.ts +0 -96
  25. package/src/lib/biome-host/index.ts +0 -35
  26. package/src/lib/biome-host/realtime-hooks.ts +0 -75
  27. package/src/lib/biome-host/realtime-port.ts +0 -115
  28. package/src/lib/biome-host/session-contributions.ts +0 -296
  29. package/src/lib/biome-host/use-mutation-with-error-toast.ts +0 -90
  30. package/src/lib/biome-host/use-page-state.ts +0 -248
  31. package/src/lib/capabilities/capability-context.ts +0 -25
  32. package/src/lib/capabilities/capability-provider.tsx +0 -73
  33. package/src/lib/capabilities/index.ts +0 -17
  34. package/src/lib/capabilities/types.ts +0 -69
  35. package/src/lib/capabilities/use-capability.ts +0 -79
  36. package/src/lib/contribution-registry/contribution-registry.spec.ts +0 -141
  37. package/src/lib/contribution-registry/contribution-registry.ts +0 -204
  38. package/src/lib/contribution-registry/index.ts +0 -9
  39. package/src/lib/contribution-registry/renderable-registry.ts +0 -142
  40. package/src/lib/system-bus/capability-invoke.ts +0 -92
  41. package/src/lib/system-bus/deeplink.ts +0 -210
  42. package/src/lib/system-bus/enums.ts +0 -86
  43. package/src/lib/system-bus/host-ports.ts +0 -93
  44. package/src/lib/system-bus/index.ts +0 -16
  45. package/src/lib/system-bus/intent-registry.ts +0 -109
  46. package/src/lib/system-bus/intents.ts +0 -113
  47. package/src/lib/system-bus/palette.ts +0 -78
  48. package/src/lib/system-bus/system-bus-builder.ts +0 -159
  49. package/src/lib/system-bus/system-bus.ts +0 -37
  50. package/src/lib/system-bus/windows.ts +0 -51
  51. package/src/offline/id.ts +0 -16
  52. package/src/offline/index.ts +0 -54
  53. package/src/offline/mutation.ts +0 -75
  54. package/src/offline/offline-status-badge.tsx +0 -51
  55. package/src/offline/online-controller.ts +0 -105
  56. package/src/offline/outbox.test.ts +0 -172
  57. package/src/offline/outbox.ts +0 -348
  58. package/src/offline/react-hooks.ts +0 -40
  59. package/src/offline/react.tsx +0 -32
  60. package/src/offline/storage.ts +0 -112
  61. package/src/offline/types.ts +0 -77
  62. package/src/org-db/components/DbResultTable.tsx +0 -176
  63. package/src/org-db/index.ts +0 -1
  64. package/src/pdf/index.ts +0 -11
  65. package/src/registry/index.ts +0 -9
  66. package/src/registry/lib/agent-validation-host.ts +0 -36
  67. package/src/registry/lib/biome-slot.tsx +0 -50
  68. package/src/registry/lib/biomes-enabled-context.ts +0 -20
  69. package/src/registry/lib/extension-points.ts +0 -134
  70. package/src/registry/lib/primitives/SessionEventCard.tsx +0 -164
  71. package/src/registry/lib/primitives/SessionEventTimeline.tsx +0 -95
  72. package/src/registry/lib/primitives/SessionMutationBar.tsx +0 -76
  73. package/src/registry/lib/primitives/SessionTabbedDrawer.tsx +0 -165
  74. package/src/registry/lib/primitives/index.ts +0 -18
  75. package/src/registry/lib/session-context-builder.ts +0 -84
  76. package/src/registry/lib/session-context-provider.tsx +0 -33
  77. package/src/registry/lib/session-context.ts +0 -21
  78. package/src/registry/lib/session-selectors.ts +0 -272
  79. package/src/session/comments/CommentRail.tsx +0 -164
  80. package/src/session/index.ts +0 -3
  81. package/src/session/lib/cn.ts +0 -11
  82. package/src/session/shell/SessionWorkspaceShell.tsx +0 -147
  83. package/src/session-kit/approvals/ApprovalButton.tsx +0 -89
  84. package/src/session-kit/approvals/ApprovalCard.tsx +0 -341
  85. package/src/session-kit/approvals/ApprovalsCenter.tsx +0 -336
  86. package/src/session-kit/approvals/CapabilityApprovalStickyBar.tsx +0 -118
  87. package/src/session-kit/approvals/Obligation.tsx +0 -111
  88. package/src/session-kit/approvals/ScopedBody.tsx +0 -392
  89. package/src/session-kit/approvals/approval-icons.ts +0 -31
  90. package/src/session-kit/approvals/approval-model.ts +0 -204
  91. package/src/session-kit/approvals/index.ts +0 -22
  92. package/src/session-kit/approvals/obligation-display.ts +0 -100
  93. package/src/session-kit/approvals/risk-accent.ts +0 -47
  94. package/src/session-kit/approvals/scope-icons.ts +0 -19
  95. package/src/session-kit/combobox/Combobox.tsx +0 -358
  96. package/src/session-kit/combobox/use-click-outside.ts +0 -21
  97. package/src/session-kit/display/ContextHeader.tsx +0 -148
  98. package/src/session-kit/display/FileDiffCard.tsx +0 -140
  99. package/src/session-kit/display/MD.tsx +0 -162
  100. package/src/session-kit/display/MessageTurn.tsx +0 -157
  101. package/src/session-kit/display/ThinkingPanel.tsx +0 -81
  102. package/src/session-kit/display/TodoChecklist.tsx +0 -120
  103. package/src/session-kit/display/TokenMeter.tsx +0 -89
  104. package/src/session-kit/display/ToolStrip.tsx +0 -278
  105. package/src/session-kit/display/TypingDots.tsx +0 -24
  106. package/src/session-kit/index.ts +0 -44
  107. package/src/session-kit/lib/enums.ts +0 -66
  108. package/src/session-kit/lib/portal-accent.ts +0 -30
  109. package/src/session-kit/lib/status-dot.ts +0 -68
  110. package/src/session-kit/primitives/Avatar.tsx +0 -44
  111. package/src/session-kit/primitives/PortalGlyph.tsx +0 -51
  112. package/src/session-kit/primitives/RiskPill.tsx +0 -95
  113. package/src/session-kit/primitives/ScopeDot.tsx +0 -47
  114. package/src/session-kit/primitives/Segmented.tsx +0 -71
  115. package/src/ui/branding/app-branding-context.ts +0 -20
  116. package/src/ui/branding/app-branding-provider.tsx +0 -123
  117. package/src/ui/branding/sanitize.ts +0 -89
  118. package/src/ui/breakpoints.ts +0 -14
  119. package/src/ui/capture/document-preview.tsx +0 -166
  120. package/src/ui/capture/field-spec-to-zod.test.ts +0 -81
  121. package/src/ui/capture/field-spec-to-zod.ts +0 -174
  122. package/src/ui/capture/field-spec-validate.ts +0 -236
  123. package/src/ui/capture/field-spec.test.ts +0 -49
  124. package/src/ui/capture/field-spec.ts +0 -274
  125. package/src/ui/capture/index.ts +0 -51
  126. package/src/ui/capture/schema-field-input.tsx +0 -620
  127. package/src/ui/capture/schema-form.tsx +0 -149
  128. package/src/ui/capture/submit-values.test.ts +0 -70
  129. package/src/ui/capture/submit-values.ts +0 -63
  130. package/src/ui/capture/use-prefill.ts +0 -186
  131. package/src/ui/capture/use-schema-validation.ts +0 -145
  132. package/src/ui/capture/use-wizard.ts +0 -180
  133. package/src/ui/capture/value-format.ts +0 -32
  134. package/src/ui/capture/wizard.tsx +0 -105
  135. package/src/ui/charts/bar-chart.tsx +0 -139
  136. package/src/ui/charts/chart-frame.tsx +0 -125
  137. package/src/ui/charts/chart-types.ts +0 -52
  138. package/src/ui/charts/chart-utils.ts +0 -190
  139. package/src/ui/charts/charts.test.tsx +0 -204
  140. package/src/ui/charts/donut-chart.tsx +0 -129
  141. package/src/ui/charts/index.ts +0 -27
  142. package/src/ui/charts/line-chart.tsx +0 -202
  143. package/src/ui/charts/sparkline.tsx +0 -109
  144. package/src/ui/chrome/AsyncBoundary.tsx +0 -74
  145. package/src/ui/chrome/EmptyState.tsx +0 -257
  146. package/src/ui/chrome/ErrorCard.tsx +0 -63
  147. package/src/ui/chrome/LoadingState.tsx +0 -61
  148. package/src/ui/chrome/PageHeader.tsx +0 -137
  149. package/src/ui/chrome/RecordCardList.tsx +0 -98
  150. package/src/ui/chrome/StateCard.tsx +0 -150
  151. package/src/ui/chrome/confirm-delete-dialog.tsx +0 -59
  152. package/src/ui/chrome/page-shell.tsx +0 -189
  153. package/src/ui/chrome/scope-badge.tsx +0 -40
  154. package/src/ui/chrome/status-badge.tsx +0 -79
  155. package/src/ui/cn.ts +0 -32
  156. package/src/ui/design-tokens.ts +0 -372
  157. package/src/ui/hooks/use-debounced-value.ts +0 -16
  158. package/src/ui/hooks/use-is-mobile.ts +0 -28
  159. package/src/ui/index.ts +0 -110
  160. package/src/ui/pdf/pdf-preview.tsx +0 -122
  161. package/src/ui/primitives/alert-dialog.tsx +0 -104
  162. package/src/ui/primitives/async-combobox.tsx +0 -182
  163. package/src/ui/primitives/badge-variants.ts +0 -21
  164. package/src/ui/primitives/badge.tsx +0 -25
  165. package/src/ui/primitives/button-variants.ts +0 -31
  166. package/src/ui/primitives/button.tsx +0 -29
  167. package/src/ui/primitives/card.tsx +0 -43
  168. package/src/ui/primitives/checkbox.tsx +0 -26
  169. package/src/ui/primitives/collapsible.tsx +0 -9
  170. package/src/ui/primitives/dialog.tsx +0 -103
  171. package/src/ui/primitives/dropdown-menu.tsx +0 -179
  172. package/src/ui/primitives/form-stepper.tsx +0 -94
  173. package/src/ui/primitives/form-stepper.types.ts +0 -15
  174. package/src/ui/primitives/input.tsx +0 -22
  175. package/src/ui/primitives/label.tsx +0 -17
  176. package/src/ui/primitives/overflow-tabs.tsx +0 -331
  177. package/src/ui/primitives/popover.tsx +0 -33
  178. package/src/ui/primitives/preview-device-frame.tsx +0 -213
  179. package/src/ui/primitives/radio-group.tsx +0 -36
  180. package/src/ui/primitives/resizable.tsx +0 -67
  181. package/src/ui/primitives/scroll-area.tsx +0 -38
  182. package/src/ui/primitives/select.tsx +0 -143
  183. package/src/ui/primitives/separator.tsx +0 -20
  184. package/src/ui/primitives/sheet.tsx +0 -107
  185. package/src/ui/primitives/skeleton.tsx +0 -99
  186. package/src/ui/primitives/switch.tsx +0 -27
  187. package/src/ui/primitives/table.tsx +0 -72
  188. package/src/ui/primitives/tabs.tsx +0 -53
  189. package/src/ui/primitives/tag-multi-select.tsx +0 -261
  190. package/src/ui/primitives/textarea.tsx +0 -21
  191. package/src/ui/primitives/tooltip.tsx +0 -30
  192. package/src/ui/primitives/url-preview-chrome.tsx +0 -103
  193. package/src/vista/GenericCatalogueSurface.tsx +0 -179
  194. package/src/vista/SurfaceFallbackCard.tsx +0 -109
  195. package/src/vista/VistaPanel.tsx +0 -163
  196. package/src/vista/form-payload.spec.ts +0 -139
  197. package/src/vista/html/CustomUiFrame.spec.tsx +0 -127
  198. package/src/vista/html/CustomUiFrame.tsx +0 -206
  199. package/src/vista/html/custom-ui-frame-bridge.spec.ts +0 -191
  200. package/src/vista/html/custom-ui-frame-bridge.ts +0 -98
  201. package/src/vista/html/custom-ui-frame-contract.ts +0 -88
  202. package/src/vista/html/custom-ui-intents.spec.ts +0 -135
  203. package/src/vista/html/custom-ui-intents.ts +0 -155
  204. package/src/vista/html/custom-ui-srcdoc.spec.ts +0 -151
  205. package/src/vista/html/custom-ui-srcdoc.ts +0 -193
  206. package/src/vista/html/index.ts +0 -13
  207. package/src/vista/index.ts +0 -52
  208. package/src/vista/surface-catalogue.spec.ts +0 -140
  209. package/src/vista/surface-catalogue.ts +0 -90
  210. package/src/vista/surface-icons.ts +0 -57
  211. package/src/vista/surface-registry.ts +0 -56
  212. package/src/vista/surfaces/ChartSurface.tsx +0 -34
  213. package/src/vista/surfaces/FilesSurface.tsx +0 -202
  214. package/src/vista/surfaces/FormSurface.tsx +0 -380
  215. package/src/vista/surfaces/HtmlSurface.tsx +0 -43
  216. package/src/vista/surfaces/TableSurface.tsx +0 -100
  217. package/src/vista/surfaces/UrlSurface.tsx +0 -40
  218. package/src/vista/surfaces/blob-surfaces.tsx +0 -139
  219. package/src/vista/surfaces/elicitation-transport.spec.ts +0 -369
  220. package/src/vista/surfaces/elicitation-transport.ts +0 -367
  221. package/src/vista/surfaces/file-surface-utils.ts +0 -69
  222. package/src/vista/surfaces/index.ts +0 -24
  223. package/src/vista/surfaces/register-surfaces.tsx +0 -139
  224. package/src/vista/surfaces/text-surfaces.tsx +0 -132
  225. package/src/vista/use-vista-tabs.ts +0 -196
  226. package/src/vista/vista-code-renderer-context.ts +0 -16
  227. package/src/vista/vista-code-renderer.tsx +0 -35
  228. package/src/vista/vista-file-context.ts +0 -14
  229. package/src/vista/vista-file-source.tsx +0 -141
  230. package/src/vista/vista-form-context.ts +0 -20
  231. package/src/vista/vista-form-host.tsx +0 -48
  232. package/src/vista/vista-model.ts +0 -137
  233. package/src/vista/vista-open-context.tsx +0 -27
  234. package/src/vista/vista-open-state.ts +0 -11
  235. package/src/vista/vista-payloads.ts +0 -635
  236. package/src/vista/vista-tabs-manifest.ts +0 -138
  237. 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
- });