@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,635 +0,0 @@
1
- /**
2
- * Payload contracts + narrowing validators for the CLOSED first-party
3
- * {@link SurfaceKind} set.
4
- *
5
- * Every validator is total and NEVER throws: it returns the narrowed payload or
6
- * `null`, and `null` routes the envelope to `SurfaceFallbackCard` with
7
- * `ContributionFallbackReason.InvalidPayload`. That is the contract the
8
- * renderable registry depends on — a malformed payload degrades visibly, it is
9
- * never coerced into a half-rendered surface.
10
- *
11
- * ── File-backed vs. inline ──────────────────────────────────────────────────
12
- * Text/binary surfaces accept EITHER an inline `content`/`url` OR a workspace
13
- * `path` resolved through the host-supplied {@link VistaFileSource}. Exactly one
14
- * must be present — supplying both is a contradiction and is rejected, not
15
- * silently preferred one way.
16
- */
17
- import { validateCaptureFields } from '../ui/capture/field-spec-validate';
18
-
19
- import type { CaptureFieldSpec } from '../ui/capture/field-spec';
20
- import type { PreviewDevice } from '../ui/primitives/preview-device-frame';
21
-
22
- /** A record with unknown values — the shape every validator starts from. */
23
- type UnknownRecord = Readonly<Record<string, unknown>>;
24
-
25
- function asRecord(value: unknown): UnknownRecord | null {
26
- return value !== null && typeof value === 'object' && !Array.isArray(value)
27
- ? (value as UnknownRecord)
28
- : null;
29
- }
30
-
31
- function optionalString(value: unknown): string | undefined | null {
32
- if (value === undefined) {
33
- return undefined;
34
- }
35
- return typeof value === 'string' ? value : null;
36
- }
37
-
38
- /**
39
- * Narrow a "exactly one of `a` / `b`" pair of optional strings. Returns the
40
- * pair when exactly one is a string, else `null`.
41
- */
42
- function exactlyOne(
43
- a: unknown,
44
- b: unknown,
45
- ): Readonly<{ a?: string; b?: string }> | null {
46
- const left = typeof a === 'string' ? a : undefined;
47
- const right = typeof b === 'string' ? b : undefined;
48
- if ((left === undefined) === (right === undefined)) {
49
- return null;
50
- }
51
- return left === undefined ? { b: right } : { a: left };
52
- }
53
-
54
- /** Where a text-backed surface reads its body from. */
55
- export interface VistaTextPayload {
56
- /** Inline body. Mutually exclusive with {@link path}. */
57
- readonly content?: string;
58
- /** Workspace-relative path resolved through the host `VistaFileSource`. */
59
- readonly path?: string;
60
- /** Optional language hint for a `code` surface (presentation only). */
61
- readonly language?: string;
62
- }
63
-
64
- export function validateTextPayload(raw: unknown): VistaTextPayload | null {
65
- const record = asRecord(raw);
66
- if (record === null) {
67
- return null;
68
- }
69
- const source = exactlyOne(record.content, record.path);
70
- if (source === null) {
71
- return null;
72
- }
73
- const language = optionalString(record.language);
74
- if (language === null) {
75
- return null;
76
- }
77
- const base: VistaTextPayload =
78
- source.a === undefined ? { path: source.b } : { content: source.a };
79
- return language === undefined ? base : { ...base, language };
80
- }
81
-
82
- /** Where a binary surface (image / media / pdf) reads its bytes from. */
83
- export interface VistaBlobPayload {
84
- /** Already-resolved fetchable URL (`https:`, `blob:`, `data:`). */
85
- readonly url?: string;
86
- /** Workspace-relative path resolved through the host `VistaFileSource`. */
87
- readonly path?: string;
88
- /** Alt text / accessible label. */
89
- readonly alt?: string;
90
- /** MIME type. Required by `media` (audio vs. video); optional elsewhere. */
91
- readonly contentType?: string;
92
- }
93
-
94
- export function validateBlobPayload(raw: unknown): VistaBlobPayload | null {
95
- const record = asRecord(raw);
96
- if (record === null) {
97
- return null;
98
- }
99
- const source = exactlyOne(record.url, record.path);
100
- if (source === null) {
101
- return null;
102
- }
103
- const alt = optionalString(record.alt);
104
- if (alt === null) {
105
- return null;
106
- }
107
- const contentType = optionalString(record.contentType);
108
- if (contentType === null) {
109
- return null;
110
- }
111
- const payload: {
112
- url?: string;
113
- path?: string;
114
- alt?: string;
115
- contentType?: string;
116
- } = source.a === undefined ? { path: source.b } : { url: source.a };
117
- if (alt !== undefined) {
118
- payload.alt = alt;
119
- }
120
- if (contentType !== undefined) {
121
- payload.contentType = contentType;
122
- }
123
- return payload;
124
- }
125
-
126
- /** `SurfaceKind.Url` — a live external URL inside mock browser chrome. */
127
- export interface VistaUrlPayload {
128
- readonly url: string;
129
- /** Device bezel to render the frame in. Defaults to `desktop`. */
130
- readonly device?: PreviewDevice;
131
- /** Bump to force the frame to reload without changing the URL. */
132
- readonly reloadNonce?: number;
133
- }
134
-
135
- const PREVIEW_DEVICES: readonly PreviewDevice[] = [
136
- 'desktop',
137
- 'tablet',
138
- 'mobile',
139
- 'presentation',
140
- 'a4',
141
- ];
142
-
143
- export function validateUrlPayload(raw: unknown): VistaUrlPayload | null {
144
- const record = asRecord(raw);
145
- if (record === null) {
146
- return null;
147
- }
148
- if (typeof record.url !== 'string' || record.url.length === 0) {
149
- return null;
150
- }
151
- const payload: { url: string; device?: PreviewDevice; reloadNonce?: number } =
152
- { url: record.url };
153
- if (record.device !== undefined) {
154
- if (!PREVIEW_DEVICES.includes(record.device as PreviewDevice)) {
155
- return null;
156
- }
157
- payload.device = record.device as PreviewDevice;
158
- }
159
- if (record.reloadNonce !== undefined) {
160
- if (typeof record.reloadNonce !== 'number') {
161
- return null;
162
- }
163
- payload.reloadNonce = record.reloadNonce;
164
- }
165
- return payload;
166
- }
167
-
168
- /**
169
- * `SurfaceKind.Html` — UNTRUSTED HTML. Two mutually-exclusive forms:
170
- *
171
- * • `document` — an agent-authored HTML document. Rendered with
172
- * `script-src 'none'`: markup and styles render, script NEVER runs.
173
- * • `compiledOutput` + `integrity` — a server-compiled, SRI-pinned custom-UI
174
- * chunk (App Forge Wave-12). Rendered with `script-src '<sha384-…>'`: ONLY
175
- * those exact bytes execute.
176
- *
177
- * Both run in an opaque-origin, `allow-scripts`-only sandbox frame.
178
- */
179
- export type VistaHtmlPayload =
180
- | { readonly document: string }
181
- | {
182
- readonly compiledOutput: string;
183
- readonly integrity: string;
184
- readonly styleCss?: string;
185
- };
186
-
187
- /** `sha384-<base64>` — the only SRI token form the frame CSP accepts. */
188
- const SRI_TOKEN = /^sha384-[A-Za-z0-9+/]+={0,2}$/;
189
-
190
- export function validateHtmlPayload(raw: unknown): VistaHtmlPayload | null {
191
- const record = asRecord(raw);
192
- if (record === null) {
193
- return null;
194
- }
195
- const hasDocument = typeof record.document === 'string';
196
- const hasChunk = typeof record.compiledOutput === 'string';
197
- if (hasDocument === hasChunk) {
198
- return null;
199
- }
200
- if (hasDocument) {
201
- return { document: record.document as string };
202
- }
203
- // A compiled chunk WITHOUT a well-formed integrity token is rejected: the
204
- // CSP hash source is what makes executing it safe, so there is no
205
- // "run it unpinned" path.
206
- if (
207
- typeof record.integrity !== 'string' ||
208
- !SRI_TOKEN.test(record.integrity)
209
- ) {
210
- return null;
211
- }
212
- const styleCss = optionalString(record.styleCss);
213
- if (styleCss === null) {
214
- return null;
215
- }
216
- const payload = {
217
- compiledOutput: record.compiledOutput as string,
218
- integrity: record.integrity,
219
- };
220
- return styleCss === undefined ? payload : { ...payload, styleCss };
221
- }
222
-
223
- /** `SurfaceKind.Json` — an inspectable JSON tree. */
224
- export interface VistaJsonPayload {
225
- readonly data: unknown;
226
- }
227
-
228
- export function validateJsonPayload(raw: unknown): VistaJsonPayload | null {
229
- const record = asRecord(raw);
230
- if (record === null) {
231
- return null;
232
- }
233
- if (!('data' in record)) {
234
- return null;
235
- }
236
- return { data: record.data };
237
- }
238
-
239
- /** `SurfaceKind.Table` — generic columns + rows. */
240
- export interface VistaTablePayload {
241
- readonly columns: readonly string[];
242
- readonly rows: readonly (readonly unknown[])[];
243
- }
244
-
245
- export function validateTablePayload(raw: unknown): VistaTablePayload | null {
246
- const record = asRecord(raw);
247
- if (record === null) {
248
- return null;
249
- }
250
- if (!Array.isArray(record.columns) || !Array.isArray(record.rows)) {
251
- return null;
252
- }
253
- if (!record.columns.every((c) => typeof c === 'string')) {
254
- return null;
255
- }
256
- if (!record.rows.every((r) => Array.isArray(r))) {
257
- return null;
258
- }
259
- return {
260
- columns: record.columns,
261
- rows: record.rows as readonly (readonly unknown[])[],
262
- };
263
- }
264
-
265
- /** Chart shapes the `chart` surface draws. Closed set. */
266
- export enum VistaChartKind {
267
- Bar = 'bar',
268
- Line = 'line',
269
- Donut = 'donut',
270
- }
271
-
272
- /** One labelled point. Value-identical to the kernel `ChartDatum`. */
273
- export interface VistaChartDatum {
274
- readonly label: string;
275
- readonly value: number;
276
- }
277
-
278
- /** One named series. */
279
- export interface VistaChartSeries {
280
- readonly name: string;
281
- readonly points: readonly VistaChartDatum[];
282
- }
283
-
284
- /**
285
- * `SurfaceKind.Chart`. At least one series is REQUIRED — `bar`/`donut` render
286
- * the first one, so an empty `series` would have no defined rendering.
287
- */
288
- export interface VistaChartPayload {
289
- readonly kind: VistaChartKind;
290
- readonly title: string;
291
- readonly series: readonly [VistaChartSeries, ...VistaChartSeries[]];
292
- }
293
-
294
- const CHART_KINDS: readonly string[] = Object.values(VistaChartKind);
295
-
296
- export function validateChartPayload(raw: unknown): VistaChartPayload | null {
297
- const record = asRecord(raw);
298
- if (record === null) {
299
- return null;
300
- }
301
- if (typeof record.kind !== 'string' || !CHART_KINDS.includes(record.kind)) {
302
- return null;
303
- }
304
- if (typeof record.title !== 'string' || record.title.length === 0) {
305
- return null;
306
- }
307
- if (!Array.isArray(record.series) || record.series.length === 0) {
308
- return null;
309
- }
310
- const series: VistaChartSeries[] = [];
311
- for (const entry of record.series) {
312
- const row = asRecord(entry);
313
- if (row === null || typeof row.name !== 'string') {
314
- return null;
315
- }
316
- if (!Array.isArray(row.points)) {
317
- return null;
318
- }
319
- const points: VistaChartDatum[] = [];
320
- for (const point of row.points) {
321
- const p = asRecord(point);
322
- if (p === null || typeof p.label !== 'string') {
323
- return null;
324
- }
325
- if (typeof p.value !== 'number') {
326
- return null;
327
- }
328
- points.push({ label: p.label, value: p.value });
329
- }
330
- series.push({ name: row.name, points });
331
- }
332
- return {
333
- kind: record.kind as VistaChartKind,
334
- title: record.title,
335
- series: series as [VistaChartSeries, ...VistaChartSeries[]],
336
- };
337
- }
338
-
339
- /** `SurfaceKind.Diff` — a unified diff, inline or file-backed. */
340
- export type VistaDiffPayload = VistaTextPayload;
341
- export const validateDiffPayload = validateTextPayload;
342
-
343
- /** One row in the {@link SurfaceKind.Files} browser. */
344
- export interface VistaFileEntry {
345
- /** Workspace-relative path (also the row key). */
346
- readonly path: string;
347
- /** Lines added (present only for changed files). */
348
- readonly add?: number;
349
- /** Lines deleted (present only for changed files). */
350
- readonly del?: number;
351
- }
352
-
353
- /** `SurfaceKind.Files` — a file tree over a workspace / artifact set. */
354
- export interface VistaFilesPayload {
355
- readonly files: readonly VistaFileEntry[];
356
- }
357
-
358
- export function validateFilesPayload(raw: unknown): VistaFilesPayload | null {
359
- const record = asRecord(raw);
360
- if (record === null) {
361
- return null;
362
- }
363
- if (!Array.isArray(record.files)) {
364
- return null;
365
- }
366
- const files: VistaFileEntry[] = [];
367
- for (const entry of record.files) {
368
- const row = asRecord(entry);
369
- if (row === null || typeof row.path !== 'string') {
370
- return null;
371
- }
372
- const file: { path: string; add?: number; del?: number } = {
373
- path: row.path,
374
- };
375
- if (row.add !== undefined) {
376
- if (typeof row.add !== 'number') {
377
- return null;
378
- }
379
- file.add = row.add;
380
- }
381
- if (row.del !== undefined) {
382
- if (typeof row.del !== 'number') {
383
- return null;
384
- }
385
- file.del = row.del;
386
- }
387
- files.push(file);
388
- }
389
- return { files };
390
- }
391
-
392
- /**
393
- * `SurfaceKind.BiomeRoute` — a biome's REAL React route, addressed by the
394
- * existing `xema://biome/<biomeId>/<route>` deeplink. Validation here is
395
- * structural only; the HOST parses the deeplink and enforces route access.
396
- */
397
- export interface VistaBiomeRoutePayload {
398
- readonly deeplink: string;
399
- }
400
-
401
- export function validateBiomeRoutePayload(
402
- raw: unknown,
403
- ): VistaBiomeRoutePayload | null {
404
- const record = asRecord(raw);
405
- if (record === null) {
406
- return null;
407
- }
408
- return typeof record.deeplink === 'string' && record.deeplink.length > 0
409
- ? { deeplink: record.deeplink }
410
- : null;
411
- }
412
-
413
- /** `SurfaceKind.Object` — a `xema://<scope>/<kind>/<slug>` entity. */
414
- export interface VistaObjectPayload {
415
- readonly ref: string;
416
- }
417
-
418
- export function validateObjectPayload(raw: unknown): VistaObjectPayload | null {
419
- const record = asRecord(raw);
420
- if (record === null) {
421
- return null;
422
- }
423
- return typeof record.ref === 'string' && record.ref.length > 0
424
- ? { ref: record.ref }
425
- : null;
426
- }
427
-
428
- /** `SurfaceKind.Graph` — the capability graph, optionally anchored. */
429
- export interface VistaGraphPayload {
430
- /** Anchor the view on a resource/capability ref. Absent = whole snapshot. */
431
- readonly anchorRef?: string;
432
- /** Traversal depth from the anchor. */
433
- readonly depth?: number;
434
- }
435
-
436
- export function validateGraphPayload(raw: unknown): VistaGraphPayload | null {
437
- const record = asRecord(raw);
438
- if (record === null) {
439
- return null;
440
- }
441
- const anchorRef = optionalString(record.anchorRef);
442
- if (anchorRef === null) {
443
- return null;
444
- }
445
- if (record.depth !== undefined && typeof record.depth !== 'number') {
446
- return null;
447
- }
448
- const payload: { anchorRef?: string; depth?: number } = {};
449
- if (anchorRef !== undefined) {
450
- payload.anchorRef = anchorRef;
451
- }
452
- if (record.depth !== undefined) {
453
- payload.depth = record.depth;
454
- }
455
- return payload;
456
- }
457
-
458
- /** `SurfaceKind.Web` — a first-party in-app route rendered inside the tab. */
459
- export interface VistaWebPayload {
460
- /** Host-relative path (leading `/`). */
461
- readonly href: string;
462
- }
463
-
464
- export function validateWebPayload(raw: unknown): VistaWebPayload | null {
465
- const record = asRecord(raw);
466
- if (record === null) {
467
- return null;
468
- }
469
- return typeof record.href === 'string' && record.href.startsWith('/')
470
- ? { href: record.href }
471
- : null;
472
- }
473
-
474
- /**
475
- * The consent / install handoff of a {@link VistaFormPayload}.
476
- *
477
- * Present when the connector's app auth is `oauth2` or `app_install`: there is
478
- * no field form to fill, only a link the user follows in another window. It is
479
- * fully generic — the owning service supplies a path under the host-configured
480
- * trusted service origin, so no provider is special-cased in the renderer and
481
- * an agent-controlled payload never selects a network authority.
482
- */
483
- export interface VistaFormLaunch {
484
- /** Root-relative consent / install path on the trusted elicitation service. */
485
- readonly path: string;
486
- /** Button copy, e.g. "Install Acme" / "Continue to Acme". */
487
- readonly label: string;
488
- /** Optional explanation rendered above the button. */
489
- readonly hint?: string;
490
- }
491
-
492
- /**
493
- * `SurfaceKind.Form` — the SECURE ELICITATION surface.
494
- *
495
- * The agent opens it to walk a user through providing a credential it must
496
- * never see. Two mutually-exclusive modes, chosen by the presence of
497
- * {@link launch}:
498
- *
499
- * • FIELD mode — render `fields`, POST them through the host's trusted
500
- * elicitation-service base URL with the user's own JWT;
501
- * • LAUNCH mode — render the consent/install link, then confirm completion
502
- * through that same trusted service.
503
- *
504
- * Both settle into the same `{ submitted, ref }` shape, so the agent's view of
505
- * the world does not depend on which mode ran.
506
- */
507
- export interface VistaFormPayload {
508
- /** Opaque, non-secret elicitation reference. The agent polls this. */
509
- readonly ref: string;
510
- /** Why the credential is being asked for — shown to the user verbatim. */
511
- readonly purpose: string;
512
- /** The onboarding form's fields. MAY be empty — the service is the authority. */
513
- readonly fields: readonly CaptureFieldSpec[];
514
- /** Optional heading override (defaults to the tab title). */
515
- readonly heading?: string;
516
- /** Submit-button copy for field mode. */
517
- readonly submitLabel?: string;
518
- /** Present ⇒ LAUNCH mode (oauth2 / app_install). */
519
- readonly launch?: VistaFormLaunch;
520
- }
521
-
522
- const VISTA_FORM_REF_PATTERN = /^[A-Za-z0-9_-]{1,256}$/;
523
-
524
- /** Whether a value is one opaque base64url elicitation path segment. */
525
- export function isValidVistaFormRef(value: unknown): value is string {
526
- return typeof value === 'string' && VISTA_FORM_REF_PATTERN.test(value);
527
- }
528
-
529
- export function validateFormPayload(raw: unknown): VistaFormPayload | null {
530
- const record = asRecord(raw);
531
- if (record === null) {
532
- return null;
533
- }
534
- // The service generates base64url refs. Keeping the accepted alphabet closed
535
- // makes the ref safe as exactly one URL path segment; dot segments, slashes,
536
- // percent escapes and Unicode lookalikes are all rejected.
537
- if (!isValidVistaFormRef(record.ref)) {
538
- return null;
539
- }
540
- if (typeof record.purpose !== 'string') {
541
- return null;
542
- }
543
- // Deliberately reject the old contract rather than silently ignoring its
544
- // payload-selected network targets.
545
- if ('submitUrl' in record || 'statusUrl' in record) {
546
- return null;
547
- }
548
-
549
- const fields = validateCaptureFields(record.fields);
550
- if (fields === null) {
551
- return null;
552
- }
553
-
554
- const heading = optionalString(record.heading);
555
- if (heading === null) {
556
- return null;
557
- }
558
- const submitLabel = optionalString(record.submitLabel);
559
- if (submitLabel === null) {
560
- return null;
561
- }
562
-
563
- let launch: VistaFormLaunch | undefined;
564
- if (record.launch !== undefined) {
565
- const raw_ = asRecord(record.launch);
566
- if (raw_ === null) {
567
- return null;
568
- }
569
- if ('url' in raw_) {
570
- return null;
571
- }
572
- if (
573
- typeof raw_.path !== 'string' ||
574
- !raw_.path.startsWith('/') ||
575
- raw_.path.startsWith('//') ||
576
- raw_.path.includes('\\')
577
- ) {
578
- return null;
579
- }
580
- if (typeof raw_.label !== 'string' || raw_.label.length === 0) {
581
- return null;
582
- }
583
- const hint = optionalString(raw_.hint);
584
- if (hint === null) {
585
- return null;
586
- }
587
- launch =
588
- hint === undefined
589
- ? { path: raw_.path, label: raw_.label }
590
- : { path: raw_.path, label: raw_.label, hint };
591
- }
592
-
593
- const payload: {
594
- ref: string;
595
- purpose: string;
596
- fields: readonly CaptureFieldSpec[];
597
- heading?: string;
598
- submitLabel?: string;
599
- launch?: VistaFormLaunch;
600
- } = { ref: record.ref, purpose: record.purpose, fields };
601
- if (heading !== undefined) {
602
- payload.heading = heading;
603
- }
604
- if (submitLabel !== undefined) {
605
- payload.submitLabel = submitLabel;
606
- }
607
- if (launch !== undefined) {
608
- payload.launch = launch;
609
- }
610
- return payload;
611
- }
612
-
613
- /** `SurfaceKind.App` — a runtime App-Platform app rendered in its own frame. */
614
- export interface VistaAppPayload {
615
- readonly appId: string;
616
- /** In-app route, defaults to the app's entry route. */
617
- readonly path?: string;
618
- }
619
-
620
- export function validateAppPayload(raw: unknown): VistaAppPayload | null {
621
- const record = asRecord(raw);
622
- if (record === null) {
623
- return null;
624
- }
625
- if (typeof record.appId !== 'string' || record.appId.length === 0) {
626
- return null;
627
- }
628
- const path = optionalString(record.path);
629
- if (path === null) {
630
- return null;
631
- }
632
- return path === undefined
633
- ? { appId: record.appId }
634
- : { appId: record.appId, path };
635
- }