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