@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.
- package/package.json +1 -2
- package/src/index.ts +0 -17
- package/src/lib/biome-host/agent-validation.ts +0 -239
- package/src/lib/biome-host/biome-builders.ts +0 -112
- package/src/lib/biome-host/biome-mode.ts +0 -6
- package/src/lib/biome-host/biome-navigation.ts +0 -37
- package/src/lib/biome-host/biome-registry.ts +0 -299
- package/src/lib/biome-host/biome-scope-hooks.ts +0 -41
- package/src/lib/biome-host/biome-scope.tsx +0 -52
- package/src/lib/biome-host/biome-scoped-query.ts +0 -134
- package/src/lib/biome-host/create-biome-orval-config.ts +0 -82
- package/src/lib/biome-host/define-web-biome.spec.ts +0 -221
- package/src/lib/biome-host/define-web-biome.ts +0 -222
- package/src/lib/biome-host/errors.ts +0 -220
- package/src/lib/biome-host/frontend-biome.ts +0 -256
- package/src/lib/biome-host/host-bridge.ts +0 -281
- package/src/lib/biome-host/host-sources.ts +0 -54
- package/src/lib/biome-host/i18n-hooks.ts +0 -51
- package/src/lib/biome-host/i18n-port.test.ts +0 -50
- package/src/lib/biome-host/i18n-port.ts +0 -96
- package/src/lib/biome-host/index.ts +0 -35
- package/src/lib/biome-host/realtime-hooks.ts +0 -75
- package/src/lib/biome-host/realtime-port.ts +0 -115
- package/src/lib/biome-host/session-contributions.ts +0 -296
- package/src/lib/biome-host/use-mutation-with-error-toast.ts +0 -90
- package/src/lib/biome-host/use-page-state.ts +0 -248
- package/src/lib/capabilities/capability-context.ts +0 -25
- package/src/lib/capabilities/capability-provider.tsx +0 -73
- package/src/lib/capabilities/index.ts +0 -17
- package/src/lib/capabilities/types.ts +0 -69
- package/src/lib/capabilities/use-capability.ts +0 -79
- package/src/lib/contribution-registry/contribution-registry.spec.ts +0 -141
- package/src/lib/contribution-registry/contribution-registry.ts +0 -204
- package/src/lib/contribution-registry/index.ts +0 -9
- package/src/lib/contribution-registry/renderable-registry.ts +0 -142
- package/src/lib/system-bus/capability-invoke.ts +0 -92
- package/src/lib/system-bus/deeplink.ts +0 -210
- package/src/lib/system-bus/enums.ts +0 -86
- package/src/lib/system-bus/host-ports.ts +0 -93
- package/src/lib/system-bus/index.ts +0 -16
- package/src/lib/system-bus/intent-registry.ts +0 -109
- package/src/lib/system-bus/intents.ts +0 -113
- package/src/lib/system-bus/palette.ts +0 -78
- package/src/lib/system-bus/system-bus-builder.ts +0 -159
- package/src/lib/system-bus/system-bus.ts +0 -37
- package/src/lib/system-bus/windows.ts +0 -51
- package/src/offline/id.ts +0 -16
- package/src/offline/index.ts +0 -54
- package/src/offline/mutation.ts +0 -75
- package/src/offline/offline-status-badge.tsx +0 -51
- package/src/offline/online-controller.ts +0 -105
- package/src/offline/outbox.test.ts +0 -172
- package/src/offline/outbox.ts +0 -348
- package/src/offline/react-hooks.ts +0 -40
- package/src/offline/react.tsx +0 -32
- package/src/offline/storage.ts +0 -112
- package/src/offline/types.ts +0 -77
- package/src/org-db/components/DbResultTable.tsx +0 -176
- package/src/org-db/index.ts +0 -1
- package/src/pdf/index.ts +0 -11
- package/src/registry/index.ts +0 -9
- package/src/registry/lib/agent-validation-host.ts +0 -36
- package/src/registry/lib/biome-slot.tsx +0 -50
- package/src/registry/lib/biomes-enabled-context.ts +0 -20
- package/src/registry/lib/extension-points.ts +0 -134
- package/src/registry/lib/primitives/SessionEventCard.tsx +0 -164
- package/src/registry/lib/primitives/SessionEventTimeline.tsx +0 -95
- package/src/registry/lib/primitives/SessionMutationBar.tsx +0 -76
- package/src/registry/lib/primitives/SessionTabbedDrawer.tsx +0 -165
- package/src/registry/lib/primitives/index.ts +0 -18
- package/src/registry/lib/session-context-builder.ts +0 -84
- package/src/registry/lib/session-context-provider.tsx +0 -33
- package/src/registry/lib/session-context.ts +0 -21
- package/src/registry/lib/session-selectors.ts +0 -272
- package/src/session/comments/CommentRail.tsx +0 -164
- package/src/session/index.ts +0 -3
- package/src/session/lib/cn.ts +0 -11
- package/src/session/shell/SessionWorkspaceShell.tsx +0 -147
- package/src/session-kit/approvals/ApprovalButton.tsx +0 -89
- package/src/session-kit/approvals/ApprovalCard.tsx +0 -341
- package/src/session-kit/approvals/ApprovalsCenter.tsx +0 -336
- package/src/session-kit/approvals/CapabilityApprovalStickyBar.tsx +0 -118
- package/src/session-kit/approvals/Obligation.tsx +0 -111
- package/src/session-kit/approvals/ScopedBody.tsx +0 -392
- package/src/session-kit/approvals/approval-icons.ts +0 -31
- package/src/session-kit/approvals/approval-model.ts +0 -204
- package/src/session-kit/approvals/index.ts +0 -22
- package/src/session-kit/approvals/obligation-display.ts +0 -100
- package/src/session-kit/approvals/risk-accent.ts +0 -47
- package/src/session-kit/approvals/scope-icons.ts +0 -19
- package/src/session-kit/combobox/Combobox.tsx +0 -358
- package/src/session-kit/combobox/use-click-outside.ts +0 -21
- package/src/session-kit/display/ContextHeader.tsx +0 -148
- package/src/session-kit/display/FileDiffCard.tsx +0 -140
- package/src/session-kit/display/MD.tsx +0 -162
- package/src/session-kit/display/MessageTurn.tsx +0 -157
- package/src/session-kit/display/ThinkingPanel.tsx +0 -81
- package/src/session-kit/display/TodoChecklist.tsx +0 -120
- package/src/session-kit/display/TokenMeter.tsx +0 -89
- package/src/session-kit/display/ToolStrip.tsx +0 -278
- package/src/session-kit/display/TypingDots.tsx +0 -24
- package/src/session-kit/index.ts +0 -44
- package/src/session-kit/lib/enums.ts +0 -66
- package/src/session-kit/lib/portal-accent.ts +0 -30
- package/src/session-kit/lib/status-dot.ts +0 -68
- package/src/session-kit/primitives/Avatar.tsx +0 -44
- package/src/session-kit/primitives/PortalGlyph.tsx +0 -51
- package/src/session-kit/primitives/RiskPill.tsx +0 -95
- package/src/session-kit/primitives/ScopeDot.tsx +0 -47
- package/src/session-kit/primitives/Segmented.tsx +0 -71
- package/src/ui/branding/app-branding-context.ts +0 -20
- package/src/ui/branding/app-branding-provider.tsx +0 -123
- package/src/ui/branding/sanitize.ts +0 -89
- package/src/ui/breakpoints.ts +0 -14
- package/src/ui/capture/document-preview.tsx +0 -166
- package/src/ui/capture/field-spec-to-zod.test.ts +0 -81
- package/src/ui/capture/field-spec-to-zod.ts +0 -174
- package/src/ui/capture/field-spec-validate.ts +0 -236
- package/src/ui/capture/field-spec.test.ts +0 -49
- package/src/ui/capture/field-spec.ts +0 -274
- package/src/ui/capture/index.ts +0 -51
- package/src/ui/capture/schema-field-input.tsx +0 -620
- package/src/ui/capture/schema-form.tsx +0 -149
- package/src/ui/capture/submit-values.test.ts +0 -70
- package/src/ui/capture/submit-values.ts +0 -63
- package/src/ui/capture/use-prefill.ts +0 -186
- package/src/ui/capture/use-schema-validation.ts +0 -145
- package/src/ui/capture/use-wizard.ts +0 -180
- package/src/ui/capture/value-format.ts +0 -32
- package/src/ui/capture/wizard.tsx +0 -105
- package/src/ui/charts/bar-chart.tsx +0 -139
- package/src/ui/charts/chart-frame.tsx +0 -125
- package/src/ui/charts/chart-types.ts +0 -52
- package/src/ui/charts/chart-utils.ts +0 -190
- package/src/ui/charts/charts.test.tsx +0 -204
- package/src/ui/charts/donut-chart.tsx +0 -129
- package/src/ui/charts/index.ts +0 -27
- package/src/ui/charts/line-chart.tsx +0 -202
- package/src/ui/charts/sparkline.tsx +0 -109
- package/src/ui/chrome/AsyncBoundary.tsx +0 -74
- package/src/ui/chrome/EmptyState.tsx +0 -257
- package/src/ui/chrome/ErrorCard.tsx +0 -63
- package/src/ui/chrome/LoadingState.tsx +0 -61
- package/src/ui/chrome/PageHeader.tsx +0 -137
- package/src/ui/chrome/RecordCardList.tsx +0 -98
- package/src/ui/chrome/StateCard.tsx +0 -150
- package/src/ui/chrome/confirm-delete-dialog.tsx +0 -59
- package/src/ui/chrome/page-shell.spec.tsx +0 -117
- package/src/ui/chrome/page-shell.tsx +0 -221
- package/src/ui/chrome/scope-badge.tsx +0 -40
- package/src/ui/chrome/status-badge.tsx +0 -79
- package/src/ui/cn.ts +0 -32
- package/src/ui/design-tokens.ts +0 -372
- package/src/ui/hooks/use-debounced-value.ts +0 -16
- package/src/ui/hooks/use-is-mobile.ts +0 -28
- package/src/ui/index.ts +0 -110
- package/src/ui/pdf/pdf-preview.tsx +0 -122
- package/src/ui/primitives/alert-dialog.tsx +0 -104
- package/src/ui/primitives/async-combobox.tsx +0 -182
- package/src/ui/primitives/badge-variants.ts +0 -21
- package/src/ui/primitives/badge.tsx +0 -25
- package/src/ui/primitives/button-variants.ts +0 -31
- package/src/ui/primitives/button.tsx +0 -29
- package/src/ui/primitives/card.tsx +0 -43
- package/src/ui/primitives/checkbox.tsx +0 -26
- package/src/ui/primitives/collapsible.tsx +0 -9
- package/src/ui/primitives/dialog.tsx +0 -103
- package/src/ui/primitives/dropdown-menu.tsx +0 -179
- package/src/ui/primitives/form-stepper.tsx +0 -94
- package/src/ui/primitives/form-stepper.types.ts +0 -15
- package/src/ui/primitives/input.tsx +0 -22
- package/src/ui/primitives/label.tsx +0 -17
- package/src/ui/primitives/overflow-tabs.tsx +0 -331
- package/src/ui/primitives/popover.tsx +0 -33
- package/src/ui/primitives/preview-device-frame.tsx +0 -213
- package/src/ui/primitives/radio-group.tsx +0 -36
- package/src/ui/primitives/resizable.tsx +0 -67
- package/src/ui/primitives/scroll-area.tsx +0 -38
- package/src/ui/primitives/select.tsx +0 -143
- package/src/ui/primitives/separator.tsx +0 -20
- package/src/ui/primitives/sheet.tsx +0 -107
- package/src/ui/primitives/skeleton.tsx +0 -99
- package/src/ui/primitives/switch.tsx +0 -27
- package/src/ui/primitives/table.tsx +0 -72
- package/src/ui/primitives/tabs.tsx +0 -53
- package/src/ui/primitives/tag-multi-select.tsx +0 -261
- package/src/ui/primitives/textarea.tsx +0 -21
- package/src/ui/primitives/tooltip.tsx +0 -30
- package/src/ui/primitives/url-preview-chrome.tsx +0 -103
- package/src/vista/GenericCatalogueSurface.tsx +0 -179
- package/src/vista/SurfaceFallbackCard.tsx +0 -109
- package/src/vista/VistaPanel.tsx +0 -163
- package/src/vista/form-payload.spec.ts +0 -139
- package/src/vista/html/CustomUiFrame.spec.tsx +0 -127
- package/src/vista/html/CustomUiFrame.tsx +0 -206
- package/src/vista/html/custom-ui-frame-bridge.spec.ts +0 -191
- package/src/vista/html/custom-ui-frame-bridge.ts +0 -98
- package/src/vista/html/custom-ui-frame-contract.ts +0 -88
- package/src/vista/html/custom-ui-intents.spec.ts +0 -135
- package/src/vista/html/custom-ui-intents.ts +0 -155
- package/src/vista/html/custom-ui-srcdoc.spec.ts +0 -151
- package/src/vista/html/custom-ui-srcdoc.ts +0 -193
- package/src/vista/html/index.ts +0 -13
- package/src/vista/index.ts +0 -52
- package/src/vista/surface-catalogue.spec.ts +0 -140
- package/src/vista/surface-catalogue.ts +0 -90
- package/src/vista/surface-icons.ts +0 -57
- package/src/vista/surface-registry.ts +0 -56
- package/src/vista/surfaces/ChartSurface.tsx +0 -34
- package/src/vista/surfaces/FilesSurface.tsx +0 -202
- package/src/vista/surfaces/FormSurface.tsx +0 -380
- package/src/vista/surfaces/HtmlSurface.tsx +0 -43
- package/src/vista/surfaces/TableSurface.tsx +0 -100
- package/src/vista/surfaces/UrlSurface.tsx +0 -40
- package/src/vista/surfaces/blob-surfaces.tsx +0 -139
- package/src/vista/surfaces/elicitation-transport.spec.ts +0 -369
- package/src/vista/surfaces/elicitation-transport.ts +0 -367
- package/src/vista/surfaces/file-surface-utils.ts +0 -69
- package/src/vista/surfaces/index.ts +0 -24
- package/src/vista/surfaces/register-surfaces.tsx +0 -139
- package/src/vista/surfaces/text-surfaces.tsx +0 -132
- package/src/vista/use-vista-tabs.ts +0 -196
- package/src/vista/vista-code-renderer-context.ts +0 -16
- package/src/vista/vista-code-renderer.tsx +0 -35
- package/src/vista/vista-file-context.ts +0 -14
- package/src/vista/vista-file-source.tsx +0 -141
- package/src/vista/vista-form-context.ts +0 -20
- package/src/vista/vista-form-host.tsx +0 -48
- package/src/vista/vista-model.ts +0 -137
- package/src/vista/vista-open-context.tsx +0 -27
- package/src/vista/vista-open-state.ts +0 -11
- package/src/vista/vista-payloads.ts +0 -635
- package/src/vista/vista-tabs-manifest.ts +0 -138
- 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
|
-
}
|