@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,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
- }
@@ -1,50 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
-
3
- import { makeTranslator } from './i18n-port';
4
-
5
- const en = {
6
- title: 'Dashboard',
7
- greeting: 'Hello, {name}',
8
- radar: { title: 'Radar', empty: 'No leads yet' },
9
- } as const;
10
-
11
- describe('makeTranslator', () => {
12
- it('resolves flat and nested dot-path keys', () => {
13
- const t = makeTranslator(en);
14
- expect(t('title')).toBe('Dashboard');
15
- expect(t('radar.title')).toBe('Radar');
16
- });
17
-
18
- it('interpolates {name} placeholders', () => {
19
- const t = makeTranslator(en);
20
- expect(t('greeting', { name: 'Ada' })).toBe('Hello, Ada');
21
- });
22
-
23
- it('leaves an unknown placeholder verbatim (visible authoring bug)', () => {
24
- const t = makeTranslator({ msg: 'Hi {who}' });
25
- expect(t('msg', {})).toBe('Hi {who}');
26
- });
27
-
28
- it('applies a namespace prefix', () => {
29
- const t = makeTranslator(en, { namespace: 'radar' });
30
- expect(t('title')).toBe('Radar');
31
- expect(t('empty')).toBe('No leads yet');
32
- });
33
-
34
- it('returns the raw key for a missing message (never blank, never throws)', () => {
35
- const t = makeTranslator(en);
36
- expect(t('does.not.exist')).toBe('does.not.exist');
37
- });
38
-
39
- it('falls back message-by-message to the default-locale catalog', () => {
40
- const pt = { title: 'Painel' }; // partial locale — no greeting
41
- const t = makeTranslator(pt, { fallback: en });
42
- expect(t('title')).toBe('Painel'); // primary wins
43
- expect(t('greeting', { name: 'Ada' })).toBe('Hello, Ada'); // fallback fills the gap
44
- });
45
-
46
- it('coerces numeric params to strings', () => {
47
- const t = makeTranslator({ count: '{n} items' });
48
- expect(t('count', { n: 3 })).toBe('3 items');
49
- });
50
- });
@@ -1,96 +0,0 @@
1
- /**
2
- * Kernel i18n contract + a framework-free translator core.
3
- *
4
- * Xema's locale is DATA-driven (per-org / per-app / per-user settings), not
5
- * URL-driven, so the kernel deliberately does NOT depend on next-intl / react-
6
- * intl. A biome localises its UI through the host-injected {@link I18nSource}
7
- * (reached via the `useT` / `useLocale` kernel hooks) exactly the way it reaches
8
- * realtime / navigation — the biome never imports an i18n library, and the host
9
- * owns catalog loading + the authoritative locale source.
10
- *
11
- * The {@link makeTranslator} core here is pure and host-agnostic: a host (or a
12
- * biome, or a test) builds a `Translator` from a nested-JSON catalog with no
13
- * framework in the loop.
14
- */
15
-
16
- /** Interpolation values for a message's `{name}` placeholders. */
17
- export type TranslateParams = Readonly<Record<string, string | number>>;
18
-
19
- /**
20
- * Resolve one message key to a localized string, interpolating `{name}`
21
- * placeholders. Missing keys return the key itself (visible, never a throw or a
22
- * blank) — the standard i18n contract, not a silent business-logic fallback.
23
- */
24
- export type Translator = (key: string, params?: TranslateParams) => string;
25
-
26
- /** A nested message catalog: dot-path keys map to strings (or sub-catalogs). */
27
- export interface Catalog {
28
- readonly [segment: string]: string | Catalog;
29
- }
30
-
31
- export interface MakeTranslatorOptions {
32
- /** Prefix every lookup with this namespace path (e.g. `"radar"`). */
33
- readonly namespace?: string;
34
- /**
35
- * Default-locale catalog consulted per-key when the primary catalog lacks a
36
- * message — so a partially-translated locale falls back message-by-message
37
- * instead of dropping to the raw key.
38
- */
39
- readonly fallback?: Catalog;
40
- }
41
-
42
- function lookup(catalog: Catalog, path: readonly string[]): string | undefined {
43
- let node: string | Catalog | undefined = catalog;
44
- for (const segment of path) {
45
- if (node === undefined || typeof node === 'string') {
46
- return undefined;
47
- }
48
- node = node[segment];
49
- }
50
- return typeof node === 'string' ? node : undefined;
51
- }
52
-
53
- function interpolate(message: string, params?: TranslateParams): string {
54
- if (!params) {
55
- return message;
56
- }
57
- // Replace `{name}` tokens; an unknown token is left verbatim (visible), never
58
- // blanked — a missing param is an authoring bug that should be obvious.
59
- return message.replaceAll(/\{(\w+)\}/g, (whole, name: string) =>
60
- Object.prototype.hasOwnProperty.call(params, name) ? String(params[name]) : whole,
61
- );
62
- }
63
-
64
- /**
65
- * Build a {@link Translator} over a catalog. Pure — no React, no framework, no
66
- * global state. Resolution order per key: primary catalog → fallback catalog →
67
- * the key itself.
68
- */
69
- export function makeTranslator(
70
- catalog: Catalog,
71
- options?: MakeTranslatorOptions,
72
- ): Translator {
73
- const prefix = options?.namespace ? options.namespace.split('.') : [];
74
- const fallback = options?.fallback;
75
- return (key, params) => {
76
- const path = [...prefix, ...key.split('.')];
77
- const message =
78
- lookup(catalog, path) ?? (fallback ? lookup(fallback, path) : undefined) ?? key;
79
- return interpolate(message, params);
80
- };
81
- }
82
-
83
- /**
84
- * Host-implemented i18n source. The host wires these against its locale provider
85
- * (authoritative locale from org/app/user settings + catalog loading); biomes
86
- * reach them through the kernel {@link useT} / {@link useLocale} hooks.
87
- *
88
- * Every method is a React hook (reads locale/catalog context), so it MUST be
89
- * called from a component's render.
90
- */
91
- export interface I18nSource {
92
- /** A {@link Translator} for the active locale, optionally namespaced. */
93
- useTranslator(namespace?: string): Translator;
94
- /** The active BCP-47 locale tag (e.g. `"pt-PT"`). */
95
- useLocale(): string;
96
- }
@@ -1,35 +0,0 @@
1
- /**
2
- * Biome-host contract surface — the framework-agnostic shape every
3
- * frontend biome composes against, plus the singleton runtime registry
4
- * that hosts populate at bootstrap.
5
- *
6
- * Host-framework-agnostic: no Vite, no Next.js, no React-Router. React
7
- * itself IS used (it is the shared component model for any host) — the
8
- * contracts traffic in `ReactNode`/`ComponentType`, expose a React
9
- * context (`HostBridgeContext`/`useHostBridge`), and the registry ships
10
- * a `useSyncExternalStore` revision hook. The concrete host adapter only
11
- * wires framework-specific navigation against these contracts (e.g. the
12
- * Next.js App Router host); the agnostic host sources (`AuthSource`,
13
- * `ToastSource`), nav merging, and the `SystemBus` builder all live here.
14
- */
15
- export * from './frontend-biome';
16
- export * from './host-bridge';
17
- export * from './biome-navigation';
18
- export * from './biome-scope';
19
- export * from './biome-scope-hooks';
20
- export * from './biome-scoped-query';
21
- export * from './biome-builders';
22
- export * from './define-web-biome';
23
- export * from './create-biome-orval-config';
24
- export * from './biome-registry';
25
- export * from './session-contributions';
26
- export * from './host-sources';
27
- export * from './biome-mode';
28
- export * from './agent-validation';
29
- export * from './realtime-port';
30
- export * from './realtime-hooks';
31
- export * from './i18n-port';
32
- export * from './i18n-hooks';
33
- export * from './errors';
34
- export * from './use-mutation-with-error-toast';
35
- export * from './use-page-state';
@@ -1,75 +0,0 @@
1
- /**
2
- * Kernel-side realtime hooks. Biomes call these INSTEAD of importing the host's
3
- * realtime client (`@xemahq/realtime-client`) directly, so biome code stays
4
- * decoupled from the SSE transport — the same decoupling `useHostBridge`
5
- * already provides for navigation / auth / capabilities.
6
- *
7
- * Each hook reads the host-injected {@link RealtimeSource} off
8
- * `bridge.realtime` and delegates straight through. The host owns the transport
9
- * (connection, token refresh, org header, scope refcounting); the kernel owns
10
- * only the contract + this thin delegation.
11
- */
12
-
13
- import { useHostBridge } from './host-bridge';
14
-
15
- import type {
16
- RealtimeCloudEvent,
17
- RealtimeConnectionState,
18
- RealtimeScope,
19
- RealtimeSource,
20
- } from './realtime-port';
21
-
22
- /**
23
- * Resolve the host-injected realtime transport, failing fast with an actionable
24
- * message if the host has not wired `bridge.realtime`. `bridge.realtime` is an
25
- * optional port (a host without a realtime transport omits it), so the kernel
26
- * hooks must not silently no-op — a biome that calls them expects live events.
27
- */
28
- function requireRealtime(realtime: RealtimeSource | undefined): RealtimeSource {
29
- if (!realtime) {
30
- throw new Error(
31
- 'useCloudEvent/useRealtimeStatus/useEventScope require a realtime ' +
32
- 'transport, but the host has not wired `bridge.realtime`. The host ' +
33
- 'must provide a RealtimeSource (e.g. backed by @xemahq/realtime-client) ' +
34
- 'on the HostBridge to use kernel realtime hooks.',
35
- );
36
- }
37
- return realtime;
38
- }
39
-
40
- /**
41
- * Subscribe to delivered CloudEvents of a given `type` for the lifetime of the
42
- * calling component. Pass a stable `handler` (e.g. via `useCallback`) — the
43
- * host re-subscribes when the handler identity changes. Narrow `event.data`
44
- * inside the handler; the kernel does not parse payloads.
45
- *
46
- * @example
47
- * useCloudEvent('session.lifecycle.changed', (event) => {
48
- * const data = event.data as { sessionId?: string } | undefined;
49
- * if (data?.sessionId !== sessionId) return;
50
- * refetch();
51
- * });
52
- */
53
- export function useCloudEvent(
54
- eventType: string,
55
- handler: (event: RealtimeCloudEvent) => void,
56
- ): void {
57
- const bridge = useHostBridge();
58
- requireRealtime(bridge.realtime).useCloudEvent(eventType, handler);
59
- }
60
-
61
- /** Coarse realtime connection state for a status indicator. */
62
- export function useRealtimeStatus(): RealtimeConnectionState {
63
- const bridge = useHostBridge();
64
- return requireRealtime(bridge.realtime).useRealtimeStatus();
65
- }
66
-
67
- /**
68
- * Subscribe the connection to a project/session {@link RealtimeScope} while the
69
- * calling component is mounted. Scopes are reference-counted by the host, so
70
- * multiple components asking for the same scope share one server subscription.
71
- */
72
- export function useEventScope(scope: RealtimeScope): void {
73
- const bridge = useHostBridge();
74
- requireRealtime(bridge.realtime).useEventScope(scope);
75
- }