@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.
- package/dist/errors/http-error-status.d.ts +17 -0
- package/dist/errors/http-error-status.d.ts.map +1 -0
- package/dist/errors/http-error-status.js +59 -0
- package/dist/errors/http-error-status.js.map +1 -0
- package/dist/errors/index.d.ts +2 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +2 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/biome-host/errors.d.ts.map +1 -1
- package/dist/lib/biome-host/errors.js +1 -19
- package/dist/lib/biome-host/errors.js.map +1 -1
- package/dist/offline/index.d.ts.map +1 -1
- package/dist/offline/index.js.map +1 -1
- package/dist/offline/online-controller.d.ts.map +1 -1
- package/dist/offline/online-controller.js +6 -1
- package/dist/offline/online-controller.js.map +1 -1
- package/dist/offline/outbox.d.ts.map +1 -1
- package/dist/offline/outbox.js +2 -24
- package/dist/offline/outbox.js.map +1 -1
- 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,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
|
-
}
|