@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,256 +0,0 @@
1
- import type { HostBridge } from './host-bridge';
2
- import type { SessionContributions } from './session-contributions';
3
- import type { ComponentType, ReactNode } from 'react';
4
-
5
- /**
6
- * Runtime contribution types a `target: 'web'` biome composes. Web
7
- * biomes default-export a `FrontendBiomeFactory` from their package
8
- * (the import specifier is `xema-biome.json#name`); the SPA's
9
- * auto-generated `xema:web-biome-loaders` virtual module imports each
10
- * factory at bootstrap, calls it with the host's `HostBridge`, and
11
- * registers the resulting `FrontendBiome` into the singleton
12
- * `biomeRegistry`.
13
- */
14
-
15
- export interface NavItemContribution {
16
- /** Stable id used for active-state matching + analytics. */
17
- readonly id: string;
18
- /** Displayed label. */
19
- readonly label: string;
20
- /** Route path the nav item links to. */
21
- readonly route: string;
22
- /**
23
- * Optional icon component. Typed with `className: string | undefined` so
24
- * any host icon kit whose props include `className` (lucide-react,
25
- * heroicons, custom SVG components) is assignable under
26
- * `exactOptionalPropertyTypes: true`. The host renders with whatever
27
- * className it computes from its own theme.
28
- */
29
- readonly icon?: ComponentType<{ className?: string | undefined }>;
30
- /**
31
- * Semantic menu category the biome declares its INTENT to live in (e.g.
32
- * `build`, `operate`, `knowledge`, `account`). The HOST owns the menu
33
- * information-architecture: it maps a category to a concrete rail group,
34
- * heading, and order. Authors declare WHAT a surface is, not WHERE in the
35
- * global menu it renders — so the platform can re-organise the menu without
36
- * editing every biome. When omitted, the host falls back to its own
37
- * taxonomy (keyed on the nav-item id).
38
- */
39
- readonly category?: string;
40
- }
41
-
42
- /**
43
- * Access tier required to render a route. The host resolver enforces it
44
- * declaratively — nav-hide is NOT a security boundary, a deeplink bypasses it.
45
- * Precedence (least → most privileged): `member` < `org-admin` <
46
- * `platform-admin`. Defaults to `member` when a route omits the field.
47
- *
48
- * `public` is NOT a privilege tier — it is the *no-auth* marker: a `public`
49
- * route requires no Keycloak session at all and mounts OUTSIDE the host's
50
- * authenticated route group. It is value-locked to `RouteScope` `'public'`
51
- * (`defineWebBiome` rejects any other pairing at define time), so a route is
52
- * public in BOTH senses or in neither. Closed set — a new member is a
53
- * one-line change to {@link ROUTE_ACCESS_VALUES} and one `case` in the host
54
- * resolver's exhaustive `hasRouteAccess` switch (the switch has no `default`,
55
- * so an unhandled member is a compile error, never a silent allow).
56
- *
57
- * The tuple below is the SINGLE source of truth: the type is derived from it,
58
- * so a member cannot exist in the type without also being enumerable at
59
- * runtime — which is what lets a host prove exhaustiveness in a test rather
60
- * than by inspection. Order is least → most privileged; `public` is the
61
- * no-auth marker and is deliberately last.
62
- */
63
- export const ROUTE_ACCESS_VALUES = [
64
- 'member',
65
- 'org-admin',
66
- 'platform-admin',
67
- 'public',
68
- ] as const;
69
-
70
- /** Access tier required to render a route. See {@link ROUTE_ACCESS_VALUES}. */
71
- export type RouteAccess = (typeof ROUTE_ACCESS_VALUES)[number];
72
-
73
- /**
74
- * Where a route mounts in the host's URL/auth topology. Closed set — adding a
75
- * member is a one-line change here (and the single mapping in `defineWebBiome`
76
- * plus one resolver partition in the host).
77
- *
78
- * - `org` — mounts at the org root, inside the authenticated group.
79
- * - `project` — mounts under the project-scoped route prefix, inside the
80
- * authenticated group.
81
- * - `public` — mounts OUTSIDE the authenticated group; no Keycloak session,
82
- * no login redirect, no org switcher. Locked to `RouteAccess` `'public'`.
83
- *
84
- * Single source of truth for the closed set; the type is derived from it.
85
- */
86
- export const ROUTE_SCOPE_VALUES = ['org', 'project', 'public'] as const;
87
-
88
- /** Where a route mounts. See {@link ROUTE_SCOPE_VALUES}. */
89
- export type RouteScope = (typeof ROUTE_SCOPE_VALUES)[number];
90
-
91
- /**
92
- * Whether a page renders wrapped in the host application shell (app rail,
93
- * topbar, org switcher) or standalone. Closed set — a new member is a one-line
94
- * change here. Defaults to `'host'` when a page omits it.
95
- *
96
- * - `host` — the default; the host renders its chrome around the page.
97
- * - `none` — the host renders the page with NO app rail, topbar, or org
98
- * switcher (a full-bleed surface). `public` routes are structurally
99
- * chromeless (their route group ships no shell); `none` also lets an
100
- * authenticated route opt out of the shell.
101
- *
102
- * Single source of truth for the closed set; the type is derived from it.
103
- * Chrome is ORTHOGONAL to access: `chrome: 'none'` on an authenticated route
104
- * is the embedded-app case and grants no privilege change whatsoever.
105
- */
106
- export const PAGE_CHROME_VALUES = ['host', 'none'] as const;
107
-
108
- /** Host-shell mode a page renders in. See {@link PAGE_CHROME_VALUES}. */
109
- export type PageChrome = (typeof PAGE_CHROME_VALUES)[number];
110
-
111
- export interface RouteContribution {
112
- /** React-router path. May include params. */
113
- readonly path: string;
114
- /** Element factory — host calls it inside the route tree. */
115
- readonly element: () => ReactNode;
116
- /**
117
- * Whether the route is project-scoped (mounted under /projects/:projectId)
118
- * or org-scoped (mounted at the org root). REQUIRED — the host nav resolver
119
- * partitions the rail strictly by this flag and drops any nav item whose
120
- * route can't be matched (fail-loud). A silent default would re-introduce the
121
- * "project pages showing at org level" class of bug, so every route MUST
122
- * declare its scope explicitly.
123
- */
124
- readonly projectScoped: boolean;
125
- /**
126
- * Access tier required to render this route. The host resolver enforces it
127
- * declaratively. Defaults to `'member'` when omitted. `'public'` marks a
128
- * no-auth route the host mounts outside its authenticated group.
129
- */
130
- readonly access?: RouteAccess;
131
- /**
132
- * Whether the host wraps this route in its application shell. Defaults to
133
- * `'host'` when omitted; `'none'` renders the page with no app rail,
134
- * topbar, or org switcher. See {@link PageChrome}.
135
- */
136
- readonly chrome?: PageChrome;
137
- }
138
-
139
- /**
140
- * Slot fillers — biomes contribute UI fragments rendered by named
141
- * `<BiomeSlot name="…">` boundaries placed in the host app shell.
142
- * Initial slots: 'org-header-actions', 'project-overview-cards',
143
- * 'run-detail-side-panel', 'settings-tabs', 'session-actions'.
144
- */
145
- export interface PanelContribution {
146
- /** Slot name the contribution renders into. */
147
- readonly slot: string;
148
- /** Stable id for ordering + replacement. */
149
- readonly id: string;
150
- /** React node factory — host calls it inside the slot. */
151
- readonly render: () => ReactNode;
152
- /** Sort weight within the slot (lower first). Defaults to 100. */
153
- readonly weight?: number;
154
- }
155
-
156
- /**
157
- * Lifecycle context passed to `FrontendBiome.init`. The host invokes
158
- * `init()` exactly once after the biome's factory returns and before
159
- * any session contribution is read. Biomes use it to wire any
160
- * imperative one-time work (Orval client setup, feature-flag registration,
161
- * background-cache prefetch) — declarative contributions go on the
162
- * `FrontendBiome` itself, not here.
163
- */
164
- export interface BiomeInitContext {
165
- readonly bridge: HostBridge;
166
- /** Biome id, mirrored from `FrontendBiome.id` for convenience. */
167
- readonly biomeId: string;
168
- }
169
-
170
- export interface FrontendBiome {
171
- /** Stable biome id; matches xema-biome.json `xema.id`. */
172
- readonly id: string;
173
- /** Displayed name. */
174
- readonly displayName: string;
175
- /**
176
- * One-shot initializer invoked after registration. Used for imperative
177
- * setup that doesn't fit a declarative contribution (e.g. seeding a
178
- * shared cache, mounting a side-effect listener). Idempotent: the
179
- * registry guarantees `init()` runs at most once per biome per SPA
180
- * session, even across HMR reloads.
181
- */
182
- readonly init?: (ctx: BiomeInitContext) => void | Promise<void>;
183
- /**
184
- * Optional teardown counterpart to `init()`. Invoked when the biome
185
- * is explicitly unregistered (admin disable flow). Biomes MUST NOT
186
- * rely on `dispose()` running on tab close — browsers don't guarantee
187
- * it. Use it for live-subscription cleanup, not for persistence.
188
- */
189
- readonly dispose?: () => void | Promise<void>;
190
- readonly navItems?: readonly NavItemContribution[];
191
- readonly routes?: readonly RouteContribution[];
192
- readonly panels?: readonly PanelContribution[];
193
- /**
194
- * Declarative contributions to the agent-session shell. See
195
- * `session-contributions.ts` for the full taxonomy. Each contribution
196
- * is a small data object; the host's session components read them
197
- * through typed selector hooks and render the matching primitives.
198
- */
199
- readonly session?: SessionContributions;
200
- /**
201
- * Output renderer contributions. Each entry binds a biome-defined
202
- * artifact `OutputKind` (e.g. `catalog_entity_info`) to the React
203
- * component that renders it inside `<OutputCard>`. The host's renderer
204
- * registry overlays biome contributions on top of the built-in set —
205
- * built-in kinds (`markdown_doc`, `json_payload`, …) cannot be
206
- * overridden, but new kinds light up the moment the biome's frontend
207
- * loads.
208
- *
209
- * See `packages/output-contracts` for the `OutputKind` taxonomy and
210
- * `submodules/xema-host-web/src/components/outputs/renderer-registry.tsx`
211
- * for the resolver. Biome renderers receive the same `OutputItem`
212
- * shape as built-ins.
213
- */
214
- readonly outputRenderers?: readonly OutputRendererContribution[];
215
- }
216
-
217
- /**
218
- * One biome → one renderer for a biome-defined `OutputKind`. The
219
- * `outputKind` string MUST be unique across all biomes; the renderer
220
- * registry refuses to register a duplicate at bootstrap (fail-fast,
221
- * surfaced in the dev console + biome admin UI).
222
- *
223
- * The `render` factory mirrors `RouteContribution.element` /
224
- * `PanelContribution.render` — typed as a thunk so the host can defer
225
- * import-cost until the renderer actually fires.
226
- */
227
- export interface OutputRendererContribution {
228
- /**
229
- * The artifact `OutputKind` this renderer handles. Free-form string
230
- * because biome-defined kinds are not in the built-in enum; the
231
- * registry validates it doesn't collide with a built-in kind at
232
- * registration time.
233
- */
234
- readonly outputKind: string;
235
- /**
236
- * React component that renders the artifact body inside `<OutputCard>`.
237
- * Receives the resolved `OutputItem` as a prop. Biomes import the
238
- * `OutputRendererProps` type from
239
- * `submodules/xema-host-web/src/components/outputs/renderer-registry.tsx`
240
- * (re-exported through the host's biome SDK barrel).
241
- */
242
- readonly render: () => ComponentType<{ readonly output: unknown }>;
243
- }
244
-
245
- /**
246
- * Biome module export contract. Each biome's entry module exports a
247
- * default function of this shape; the host bootstrap calls it with its
248
- * concrete `HostBridge` implementation, then registers the returned
249
- * `FrontendBiome` with `biomeRegistry`.
250
- *
251
- * This factory shape keeps biome code free of any direct dependency
252
- * on host-shell primitives (router, auth client, toast library), which
253
- * is what allows the same biome package to load into one host runtime
254
- * today and a different host runtime tomorrow.
255
- */
256
- export type FrontendBiomeFactory = (bridge: HostBridge) => FrontendBiome;
@@ -1,281 +0,0 @@
1
- import { createContext, useContext, type ReactNode } from 'react';
2
-
3
- import type { CapabilityPort } from '../capabilities';
4
- import type { SystemBus } from '../system-bus';
5
- import type { I18nSource } from './i18n-port';
6
- import type { RealtimeSource } from './realtime-port';
7
- import type { QueryClient } from '@tanstack/react-query';
8
-
9
- /**
10
- * `HostBridge` is the host-agnostic abstraction every frontend biome
11
- * receives at registration time. It decouples biome code from any
12
- * particular React shell (Vite SPA today, Next.js tomorrow) and from
13
- * any particular auth / toast / router primitive.
14
- *
15
- * Each concrete host (e.g. `submodules/xema-host-web`) implements this
16
- * interface once, against its router (`react-router-dom`), its auth
17
- * client (`keycloak-js`), its toast library (`sonner`), its `QueryClient`,
18
- * and its request-context store. Biome code is identical across hosts.
19
- */
20
- export interface HostBridgeNavigation {
21
- /** Push a new entry on the navigation stack. */
22
- push(path: string): void;
23
- /** Replace the current entry. */
24
- replace(path: string): void;
25
- /**
26
- * Hook returning the current location. Must be a stable React hook
27
- * implemented by the host (e.g. `react-router-dom`'s `useLocation`).
28
- */
29
- useLocation(): HostLocation;
30
- /**
31
- * Hook returning the params bound by the host's route matcher for the
32
- * currently-rendered biome route (the `:param` segments declared on the
33
- * biome's `RouteContribution.path`, plus `projectId` for project-scoped
34
- * routes). Must be a stable React hook implemented by the host against
35
- * its router (`react-router-dom`'s `useParams`, the App Router's
36
- * matcher-bound params context, …).
37
- *
38
- * Biomes call this INSTEAD of importing a router primitive directly, so
39
- * biome code stays decoupled from any particular host shell — the same
40
- * decoupling `useLocation` / `push` / `replace` already provide. Values
41
- * are `string | undefined` because a param is absent until the route that
42
- * declares it is the matched route.
43
- */
44
- useRouteParams<
45
- T extends Record<string, string | undefined> = Record<
46
- string,
47
- string | undefined
48
- >,
49
- >(): T;
50
- /**
51
- * Hook returning the current URL query string as a read-only
52
- * `URLSearchParams`. Must be a stable React hook implemented by the host
53
- * against its router (`react-router-dom`'s `useSearchParams`, the App
54
- * Router's `useSearchParams`, …).
55
- *
56
- * This is the router primitive biomes could not previously reach through
57
- * the bridge — without it they were forced to import `next/navigation`
58
- * directly, defeating the host decoupling that `useLocation` /
59
- * `useRouteParams` already provide. Read-only on purpose: query mutation
60
- * goes through `push` / `replace` so the host owns history semantics.
61
- */
62
- useSearchParams(): URLSearchParams;
63
- }
64
-
65
- export interface HostLocation {
66
- readonly pathname: string;
67
- readonly search: string;
68
- }
69
-
70
- export interface HostBridgeAuth {
71
- /** Returns the current actor's bearer token, or null if unauthenticated. */
72
- getActorToken(): string | null;
73
- /** Returns the current actor's organization id, or null if not selected. */
74
- getOrgId(): string | null;
75
- /** Returns the current actor's project id, or null if not selected. */
76
- getProjectId(): string | null;
77
- /** Returns the current actor's user id (subject), or null. */
78
- getUserId(): string | null;
79
- /**
80
- * Proactively refresh the actor token if it is within `minValiditySeconds`
81
- * of expiry, then return a guaranteed-valid bearer. The refresh + any
82
- * redirect-on-failure stays HOST-owned (the host owns the auth client and
83
- * the single-flight login guard) — biomes only reach it through this method
84
- * so an Orval client's `getAuthToken` can be wired against the SAME refresh
85
- * path the host uses, instead of each biome re-implementing token freshness.
86
- *
87
- * @param minValiditySeconds Refresh when fewer than this many seconds of
88
- * validity remain. Defaults to a host-chosen safe window.
89
- * @returns A valid bearer token string. Implementations that cannot produce
90
- * one (session expired) trigger the host login redirect and reject.
91
- */
92
- ensureFreshToken(minValiditySeconds?: number): Promise<string>;
93
- /**
94
- * Handle a 401 from a downstream API call: force-refresh the token and, if
95
- * that fails, redirect to login. HOST-owned for the same reason as
96
- * {@link HostBridgeAuth.ensureFreshToken} — there is ONE login-redirect
97
- * single-flight guard and one refresh-dedup path in the host; biomes funnel
98
- * 401 recovery through here rather than forking that logic.
99
- */
100
- onUnauthorized(): Promise<void>;
101
- }
102
-
103
- export interface HostBridgeToast {
104
- /**
105
- * Success toast. `detail` is an optional secondary line (rendered as the
106
- * toast description) — use it to echo what succeeded (e.g. the deeplink
107
- * that was copied) or to carry a load-bearing consequence note. Mirrors
108
- * {@link HostBridgeToast.error}'s two-arg shape.
109
- */
110
- success(message: string, detail?: string): void;
111
- error(message: string, detail?: string): void;
112
- /** Info toast with an optional secondary description line. */
113
- info(message: string, detail?: string): void;
114
- }
115
-
116
- export interface HostBridgeRequestContext {
117
- readonly correlationId: string;
118
- }
119
-
120
- /**
121
- * Error-decoding surface — the canonical "turn a thrown value into a
122
- * user-facing message" decoder, exposed on the bridge so biomes use ONE
123
- * implementation instead of each re-deriving envelope/status-code copy.
124
- *
125
- * The decoder is a PURE function (no host context), so the kernel also ships it
126
- * directly as {@link getUserFacingErrorMessage} and {@link ErrorCard} defaults
127
- * to it. It is ALSO hung off the bridge so a host can override it with a
128
- * shell-specific decoder (extra error codes, i18n) without every biome wiring a
129
- * prop — the bridge value is the single override point.
130
- */
131
- export interface HostBridgeErrors {
132
- /**
133
- * Decode any thrown value into a user-facing message. `fallback` is returned
134
- * when nothing better can be extracted. Defaults (in the kernel default
135
- * bridge wiring) to {@link getUserFacingErrorMessage}.
136
- */
137
- getUserFacingErrorMessage(error: unknown, fallback?: string): string;
138
- }
139
-
140
- /**
141
- * Where the topbar's leading back-button takes you. Pages that have a
142
- * meaningful "parent context" register this; pages without one omit it
143
- * and no back button is shown. `to` is an internal route; `label` is a
144
- * screen-reader label (the button itself is icon-only).
145
- */
146
- export interface PageBackTarget {
147
- readonly to: string;
148
- /** Screen-reader label. Defaults to "Back". */
149
- readonly label?: string;
150
- }
151
-
152
- /**
153
- * Page chrome registered by a page into the host's topbar store. The host
154
- * `AppTopbar` renders the active meta as the single page-chrome bar. This
155
- * is the host-agnostic mirror of the host's page-meta store payload —
156
- * biomes register through {@link HostBridgePageMeta.usePageMeta} so the
157
- * meta reaches the host topbar across a Module-Federation boundary (the
158
- * bridge is a shared singleton; a remotely-bundled module store is not).
159
- */
160
- export interface PageMeta {
161
- /** Short title rendered in the topbar. e.g. "Sessions", "Documents". */
162
- readonly title: string;
163
- /** Optional eyebrow rendered before the title (small mono caption). */
164
- readonly eyebrow?: string;
165
- /** Long-form description shown inside the info popover. */
166
- readonly description?: string;
167
- /** Optional bullet list of "what you can do here" shown in the info popover. */
168
- readonly actions?: readonly string[];
169
- /** Leftmost back affordance, rendered as an icon-only button. */
170
- readonly backTo?: PageBackTarget;
171
- /** Right-aligned action cluster rendered in the topbar (1-3 small buttons). */
172
- readonly topbarActions?: ReactNode;
173
- /** Short secondary line rendered inline with the title in the topbar. */
174
- readonly topbarMeta?: ReactNode;
175
- }
176
-
177
- /**
178
- * The page-meta surface — how a biome page drives the host topbar's title,
179
- * description, help-actions, back affordance, and action cluster.
180
- *
181
- * Exposed as a hook (mirroring `navigation.useLocation` / `useRouteParams`)
182
- * because registration is lifecycle-bound: the host pushes the meta on mount
183
- * and pops it on unmount, restoring the outer page's meta. Biomes call this
184
- * INSTEAD of importing the host's page-meta module directly, so the page
185
- * component bundles cleanly into an MF remote and still updates the one
186
- * host-owned store via the shared bridge singleton.
187
- */
188
- export interface HostBridgePageMeta {
189
- /**
190
- * Register the current page's meta with the host topbar. Stable React hook
191
- * implemented by the host against its page-meta store. Call it from a stable
192
- * place at the top of the page component.
193
- */
194
- usePageMeta(meta: PageMeta): void;
195
- }
196
-
197
- export interface HostBridge {
198
- readonly navigation: HostBridgeNavigation;
199
- readonly auth: HostBridgeAuth;
200
- readonly toast: HostBridgeToast;
201
- readonly queryClient: QueryClient;
202
- readonly requestContext: HostBridgeRequestContext;
203
- /**
204
- * Page chrome surface — how a biome page drives the host topbar (title,
205
- * description, help-actions, back, action cluster). Backed by the host's
206
- * single page-meta store so the topbar is the one source of truth, while
207
- * pages stay portable into MF remotes (no module-singleton import).
208
- */
209
- readonly pageMeta: HostBridgePageMeta;
210
- /**
211
- * The OS-orchestration plane — capability invocation, cross-biome
212
- * intents, command palette, `xema://` deeplinks, and windowing. Every
213
- * frontend biome reaches the platform's orchestration surface through
214
- * here. Pure orchestration: the SystemBus NEVER authorizes — the
215
- * backend capability-router is the single authority on auth / tenancy /
216
- * policy / audit (see {@link SystemBus}).
217
- */
218
- readonly system: SystemBus;
219
- /**
220
- * Server-authoritative capability port — how a biome UI gates on the
221
- * caller's effective capability set (`GET /bff/me/capabilities`) instead of
222
- * cosmetic role booleans. The HOST implements this against its Orval client
223
- * and maps the response onto the kernel's `MeCapabilitiesSnapshot` shape so
224
- * the kernel stays fetch-free and host-agnostic. Consumed by
225
- * `<CapabilityProvider>` + `useCapability()` (see `../capabilities`).
226
- */
227
- readonly capabilities: CapabilityPort;
228
- /**
229
- * Realtime (CloudEvents over SSE) port. The HOST injects a concrete
230
- * {@link RealtimeSource} backed by its realtime transport
231
- * (`@xemahq/realtime-client`); biomes reach it through the kernel
232
- * `useCloudEvent` / `useRealtimeStatus` / `useEventScope` hooks so biome code
233
- * never imports the SSE client directly — same decoupling as `navigation`.
234
- *
235
- * OPTIONAL: a host without a realtime transport simply omits it; the kernel
236
- * `useCloudEvent`/`useRealtimeStatus`/`useEventScope` hooks fail fast with an
237
- * actionable error if a biome uses them before the host wires `bridge.realtime`.
238
- */
239
- readonly realtime?: RealtimeSource;
240
- /**
241
- * Localization port. The HOST injects a concrete {@link I18nSource} backed by
242
- * its locale provider (authoritative locale from org/app/user settings +
243
- * catalog loading); biomes reach it through the kernel `useT` / `useLocale`
244
- * hooks so biome code never imports an i18n library directly — same decoupling
245
- * as `navigation` / `realtime`.
246
- *
247
- * OPTIONAL: a host without localization omits it; the kernel `useT`/`useLocale`
248
- * hooks fail fast with an actionable error if a biome uses them before the host
249
- * wires `bridge.i18n`.
250
- */
251
- readonly i18n?: I18nSource;
252
- /**
253
- * Error-decoding surface — the canonical user-facing error decoder. Defaults
254
- * (in the kernel default bridge wiring) to {@link getUserFacingErrorMessage};
255
- * a host MAY override it. Biomes + {@link ErrorCard} read ONE decoder instead
256
- * of each re-deriving message extraction.
257
- *
258
- * OPTIONAL: when omitted, consumers fall back to the kernel default
259
- * {@link getUserFacingErrorMessage} (which ErrorCard already uses directly).
260
- */
261
- readonly errors?: HostBridgeErrors;
262
- }
263
-
264
- export const HostBridgeContext = createContext<HostBridge | null>(null);
265
- HostBridgeContext.displayName = 'HostBridgeContext';
266
-
267
- /**
268
- * Hook biome components use to reach the host. Throws fail-fast if no
269
- * `<HostBridgeContext.Provider>` is mounted above — biomes must never
270
- * import host primitives directly, so a missing bridge is a wiring bug.
271
- */
272
- export function useHostBridge(): HostBridge {
273
- const bridge = useContext(HostBridgeContext);
274
- if (!bridge) {
275
- throw new Error(
276
- '[xema-ui-kernel] useHostBridge() called outside <HostBridgeContext.Provider>. ' +
277
- 'The host app must wrap biome-rendered subtrees with the bridge provider.',
278
- );
279
- }
280
- return bridge;
281
- }
@@ -1,54 +0,0 @@
1
- /**
2
- * Pluggable host sources — keep the kernel independent of any specific
3
- * auth or toast library. The concrete host adapter (Next.js, React-Router,
4
- * …) implements each getter/method against whatever client it uses and
5
- * passes them in when building the `HostBridge` + `SystemBus`.
6
- *
7
- * Framework-agnostic: pure interface contracts, no React, no router.
8
- */
9
-
10
- /**
11
- * Pluggable auth source — keeps the kernel independent of any specific
12
- * auth library (keycloak-js, auth0, custom OIDC, …). The host implements
13
- * each getter against whatever auth client it uses.
14
- *
15
- * Only the four call-sites a typical biome needs are exposed; if a host
16
- * has no concept of "org id" or "project id" it returns `null`. Biomes
17
- * tolerate `null` per the `HostBridge` contract.
18
- */
19
- export interface AuthSource {
20
- /** Bearer token for outbound API calls, or null when unauthenticated. */
21
- getActorToken(): string | null;
22
- /** Active organization id, or null when none is selected. */
23
- getOrgId(): string | null;
24
- /** Active project id, or null when none is selected. */
25
- getProjectId(): string | null;
26
- /** Subject (user) id of the actor, or null when unauthenticated. */
27
- getUserId(): string | null;
28
- /**
29
- * Proactively refresh the token if it is within `minValiditySeconds` of
30
- * expiry and return a valid bearer. Backed by the host's auth client
31
- * (keycloak-js `updateToken`, …) and its single-flight login redirect.
32
- * Mirrors {@link HostBridgeAuth.ensureFreshToken} — the bridge delegates
33
- * straight through to this source.
34
- */
35
- ensureFreshToken(minValiditySeconds?: number): Promise<string>;
36
- /**
37
- * Force-refresh on a 401 and redirect to login on failure. Backed by the
38
- * host's auth-guard. Mirrors {@link HostBridgeAuth.onUnauthorized}.
39
- */
40
- onUnauthorized(): Promise<void>;
41
- }
42
-
43
- /**
44
- * Pluggable toast source — keeps the kernel independent of any specific
45
- * toast library (sonner, react-hot-toast, custom). The host wires the three
46
- * call-sites the `HostBridge` exposes against whatever it uses.
47
- */
48
- export interface ToastSource {
49
- /** Success toast with an optional secondary description line. */
50
- success(message: string, detail?: string): void;
51
- error(message: string, detail?: string): void;
52
- /** Info toast with an optional secondary description line. */
53
- info(message: string, detail?: string): void;
54
- }
@@ -1,51 +0,0 @@
1
- /**
2
- * Kernel-side i18n hooks. Biomes call these INSTEAD of importing an i18n library
3
- * or the host's locale provider directly, so biome code stays decoupled from the
4
- * i18n implementation — the same decoupling `useHostBridge` provides for
5
- * navigation / auth / realtime / capabilities.
6
- *
7
- * Each hook reads the host-injected {@link I18nSource} off `bridge.i18n` and
8
- * delegates straight through. The host owns the authoritative locale + catalog
9
- * loading; the kernel owns only the contract + this thin delegation.
10
- */
11
-
12
- import { useHostBridge } from './host-bridge';
13
-
14
- import type { I18nSource, Translator } from './i18n-port';
15
-
16
- /**
17
- * Resolve the host-injected i18n source, failing fast with an actionable message
18
- * if the host has not wired `bridge.i18n`. `bridge.i18n` is an optional port (a
19
- * host without localization omits it), so the kernel hooks must not silently
20
- * no-op — a biome that calls them expects translated copy.
21
- */
22
- function requireI18n(i18n: I18nSource | undefined): I18nSource {
23
- if (!i18n) {
24
- throw new Error(
25
- 'useT/useLocale require an i18n source, but the host has not wired ' +
26
- '`bridge.i18n`. The host must provide an I18nSource (locale + catalogs) ' +
27
- 'on the HostBridge to use kernel i18n hooks.',
28
- );
29
- }
30
- return i18n;
31
- }
32
-
33
- /**
34
- * A {@link Translator} for the active locale, scoped to an optional namespace.
35
- * Call at render; the returned `t(key, params?)` interpolates `{name}` tokens.
36
- *
37
- * @example
38
- * const t = useT('radar');
39
- * return <h1>{t('title')}</h1>; // radar.title
40
- * return <p>{t('greeting', { name })}</p>; // "Hello, {name}"
41
- */
42
- export function useT(namespace?: string): Translator {
43
- const bridge = useHostBridge();
44
- return requireI18n(bridge.i18n).useTranslator(namespace);
45
- }
46
-
47
- /** The active BCP-47 locale tag (e.g. `"pt-PT"`) for date/number formatting. */
48
- export function useLocale(): string {
49
- const bridge = useHostBridge();
50
- return requireI18n(bridge.i18n).useLocale();
51
- }