@xemahq/ui-kernel 0.9.1 → 0.9.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/README.md +2 -2
- package/dist/lib/biome-host/biome-builders.d.ts.map +1 -1
- package/dist/lib/biome-host/biome-builders.js +3 -1
- package/dist/lib/biome-host/biome-builders.js.map +1 -1
- package/dist/lib/biome-host/biome-registry.d.ts.map +1 -1
- package/dist/lib/biome-host/biome-registry.js.map +1 -1
- package/dist/lib/biome-host/biome-scope-hooks.d.ts +11 -0
- package/dist/lib/biome-host/biome-scope-hooks.d.ts.map +1 -0
- package/dist/lib/biome-host/biome-scope-hooks.js +25 -0
- package/dist/lib/biome-host/biome-scope-hooks.js.map +1 -0
- package/dist/lib/biome-host/biome-scope.d.ts +1 -10
- package/dist/lib/biome-host/biome-scope.d.ts.map +1 -1
- package/dist/lib/biome-host/biome-scope.js +1 -24
- package/dist/lib/biome-host/biome-scope.js.map +1 -1
- package/dist/lib/biome-host/biome-scoped-query.d.ts +1 -1
- package/dist/lib/biome-host/biome-scoped-query.d.ts.map +1 -1
- package/dist/lib/biome-host/biome-scoped-query.js +1 -1
- package/dist/lib/biome-host/biome-scoped-query.js.map +1 -1
- package/dist/lib/biome-host/create-biome-orval-config.js +2 -2
- package/dist/lib/biome-host/create-biome-orval-config.js.map +1 -1
- package/dist/lib/biome-host/errors.js.map +1 -1
- package/dist/lib/biome-host/index.d.ts +1 -1
- package/dist/lib/biome-host/index.d.ts.map +1 -1
- package/dist/lib/biome-host/index.js +1 -1
- package/dist/lib/biome-host/index.js.map +1 -1
- package/dist/lib/biome-host/session-profiles.d.ts.map +1 -1
- package/dist/lib/biome-host/session-profiles.js +4 -1
- package/dist/lib/biome-host/session-profiles.js.map +1 -1
- package/dist/lib/capabilities/capability-context.d.ts +9 -0
- package/dist/lib/capabilities/capability-context.d.ts.map +1 -0
- package/dist/lib/capabilities/capability-context.js +13 -0
- package/dist/lib/capabilities/capability-context.js.map +1 -0
- package/dist/lib/capabilities/capability-provider.d.ts +2 -8
- package/dist/lib/capabilities/capability-provider.d.ts.map +1 -1
- package/dist/lib/capabilities/capability-provider.js +1 -12
- package/dist/lib/capabilities/capability-provider.js.map +1 -1
- package/dist/lib/capabilities/index.d.ts +1 -0
- package/dist/lib/capabilities/index.d.ts.map +1 -1
- package/dist/lib/capabilities/index.js +1 -0
- package/dist/lib/capabilities/index.js.map +1 -1
- package/dist/lib/capabilities/use-capability.d.ts.map +1 -1
- package/dist/lib/capabilities/use-capability.js +1 -1
- package/dist/lib/capabilities/use-capability.js.map +1 -1
- package/dist/lib/system-bus/deeplink.js.map +1 -1
- package/dist/lib/system-bus/host-ports.d.ts +2 -1
- package/dist/lib/system-bus/host-ports.d.ts.map +1 -1
- package/dist/lib/system-bus/intent-registry.d.ts.map +1 -1
- package/dist/lib/system-bus/intent-registry.js.map +1 -1
- package/dist/offline/index.d.ts +2 -1
- package/dist/offline/index.d.ts.map +1 -1
- package/dist/offline/index.js +2 -1
- package/dist/offline/index.js.map +1 -1
- package/dist/offline/offline-status-badge.js +1 -1
- package/dist/offline/offline-status-badge.js.map +1 -1
- package/dist/offline/outbox.js.map +1 -1
- package/dist/offline/react-hooks.d.ts +7 -0
- package/dist/offline/react-hooks.d.ts.map +1 -0
- package/dist/offline/react-hooks.js +25 -0
- package/dist/offline/react-hooks.js.map +1 -0
- package/dist/offline/react.d.ts +0 -4
- package/dist/offline/react.d.ts.map +1 -1
- package/dist/offline/react.js +2 -24
- package/dist/offline/react.js.map +1 -1
- package/dist/offline/storage.d.ts.map +1 -1
- package/dist/offline/storage.js +8 -5
- package/dist/offline/storage.js.map +1 -1
- package/dist/registry/index.d.ts +1 -0
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/index.js +1 -0
- package/dist/registry/index.js.map +1 -1
- package/dist/registry/lib/primitives/SessionEventCard.d.ts.map +1 -1
- package/dist/registry/lib/primitives/SessionEventCard.js +1 -1
- package/dist/registry/lib/primitives/SessionEventCard.js.map +1 -1
- package/dist/registry/lib/session-context-provider.d.ts +1 -3
- package/dist/registry/lib/session-context-provider.d.ts.map +1 -1
- package/dist/registry/lib/session-context-provider.js +2 -15
- package/dist/registry/lib/session-context-provider.js.map +1 -1
- package/dist/registry/lib/session-context.d.ts +5 -0
- package/dist/registry/lib/session-context.d.ts.map +1 -0
- package/dist/registry/lib/session-context.js +15 -0
- package/dist/registry/lib/session-context.js.map +1 -0
- package/dist/registry/lib/session-selectors.d.ts.map +1 -1
- package/dist/registry/lib/session-selectors.js +3 -1
- package/dist/registry/lib/session-selectors.js.map +1 -1
- package/dist/ui/branding/app-branding-context.d.ts +9 -0
- package/dist/ui/branding/app-branding-context.d.ts.map +1 -0
- package/dist/ui/branding/app-branding-context.js +10 -0
- package/dist/ui/branding/app-branding-context.js.map +1 -0
- package/dist/ui/branding/app-branding-provider.d.ts +0 -6
- package/dist/ui/branding/app-branding-provider.d.ts.map +1 -1
- package/dist/ui/branding/app-branding-provider.js +1 -8
- package/dist/ui/branding/app-branding-provider.js.map +1 -1
- package/dist/ui/capture/schema-field-input.js +1 -1
- package/dist/ui/capture/schema-field-input.js.map +1 -1
- package/dist/ui/capture/use-prefill.d.ts.map +1 -1
- package/dist/ui/capture/use-prefill.js +3 -1
- package/dist/ui/capture/use-prefill.js.map +1 -1
- package/dist/ui/capture/use-wizard.d.ts +1 -1
- package/dist/ui/capture/use-wizard.d.ts.map +1 -1
- package/dist/ui/capture/use-wizard.js +1 -1
- package/dist/ui/capture/use-wizard.js.map +1 -1
- package/dist/ui/capture/wizard.d.ts.map +1 -1
- package/dist/ui/capture/wizard.js.map +1 -1
- package/dist/ui/index.d.ts +5 -1
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +5 -1
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/primitives/alert-dialog.js +1 -1
- package/dist/ui/primitives/alert-dialog.js.map +1 -1
- package/dist/ui/primitives/badge-variants.d.ts +4 -0
- package/dist/ui/primitives/badge-variants.d.ts.map +1 -0
- package/dist/ui/primitives/badge-variants.js +15 -0
- package/dist/ui/primitives/badge-variants.js.map +1 -0
- package/dist/ui/primitives/badge.d.ts +3 -5
- package/dist/ui/primitives/badge.d.ts.map +1 -1
- package/dist/ui/primitives/badge.js +2 -15
- package/dist/ui/primitives/badge.js.map +1 -1
- package/dist/ui/primitives/button-variants.d.ts +5 -0
- package/dist/ui/primitives/button-variants.d.ts.map +1 -0
- package/dist/ui/primitives/button-variants.js +24 -0
- package/dist/ui/primitives/button-variants.js.map +1 -0
- package/dist/ui/primitives/button.d.ts +3 -6
- package/dist/ui/primitives/button.d.ts.map +1 -1
- package/dist/ui/primitives/button.js +2 -24
- package/dist/ui/primitives/button.js.map +1 -1
- package/dist/ui/primitives/form-stepper.d.ts +1 -13
- package/dist/ui/primitives/form-stepper.d.ts.map +1 -1
- package/dist/ui/primitives/form-stepper.js +1 -6
- package/dist/ui/primitives/form-stepper.js.map +1 -1
- package/dist/ui/primitives/form-stepper.types.d.ts +14 -0
- package/dist/ui/primitives/form-stepper.types.d.ts.map +1 -0
- package/dist/ui/primitives/form-stepper.types.js +7 -0
- package/dist/ui/primitives/form-stepper.types.js.map +1 -0
- package/dist/ui/primitives/preview-device-frame.js +1 -1
- package/dist/ui/primitives/preview-device-frame.js.map +1 -1
- package/dist/ui/primitives/tag-multi-select.d.ts.map +1 -1
- package/dist/ui/primitives/tag-multi-select.js +1 -1
- package/dist/ui/primitives/tag-multi-select.js.map +1 -1
- package/dist/vista/index.d.ts +4 -0
- package/dist/vista/index.d.ts.map +1 -1
- package/dist/vista/index.js +4 -0
- package/dist/vista/index.js.map +1 -1
- package/dist/vista/surfaces/FilesSurface.d.ts +1 -12
- package/dist/vista/surfaces/FilesSurface.d.ts.map +1 -1
- package/dist/vista/surfaces/FilesSurface.js +2 -46
- package/dist/vista/surfaces/FilesSurface.js.map +1 -1
- package/dist/vista/surfaces/FormSurface.d.ts.map +1 -1
- package/dist/vista/surfaces/FormSurface.js +39 -12
- package/dist/vista/surfaces/FormSurface.js.map +1 -1
- package/dist/vista/surfaces/elicitation-transport.d.ts +12 -3
- package/dist/vista/surfaces/elicitation-transport.d.ts.map +1 -1
- package/dist/vista/surfaces/elicitation-transport.js +96 -3
- package/dist/vista/surfaces/elicitation-transport.js.map +1 -1
- package/dist/vista/surfaces/file-surface-utils.d.ts +13 -0
- package/dist/vista/surfaces/file-surface-utils.d.ts.map +1 -0
- package/dist/vista/surfaces/file-surface-utils.js +46 -0
- package/dist/vista/surfaces/file-surface-utils.js.map +1 -0
- package/dist/vista/surfaces/index.d.ts +4 -3
- package/dist/vista/surfaces/index.d.ts.map +1 -1
- package/dist/vista/surfaces/index.js +4 -81
- package/dist/vista/surfaces/index.js.map +1 -1
- package/dist/vista/surfaces/register-surfaces.d.ts +2 -0
- package/dist/vista/surfaces/register-surfaces.d.ts.map +1 -0
- package/dist/vista/surfaces/register-surfaces.js +80 -0
- package/dist/vista/surfaces/register-surfaces.js.map +1 -0
- package/dist/vista/surfaces/text-surfaces.js +1 -1
- package/dist/vista/surfaces/text-surfaces.js.map +1 -1
- package/dist/vista/vista-code-renderer-context.d.ts +9 -0
- package/dist/vista/vista-code-renderer-context.d.ts.map +1 -0
- package/dist/vista/vista-code-renderer-context.js +6 -0
- package/dist/vista/vista-code-renderer-context.js.map +1 -0
- package/dist/vista/vista-code-renderer.d.ts +1 -6
- package/dist/vista/vista-code-renderer.d.ts.map +1 -1
- package/dist/vista/vista-code-renderer.js +1 -5
- package/dist/vista/vista-code-renderer.js.map +1 -1
- package/dist/vista/vista-file-context.d.ts +8 -0
- package/dist/vista/vista-file-context.d.ts.map +1 -0
- package/dist/vista/vista-file-context.js +6 -0
- package/dist/vista/vista-file-context.js.map +1 -0
- package/dist/vista/vista-file-source.d.ts +1 -6
- package/dist/vista/vista-file-source.d.ts.map +1 -1
- package/dist/vista/vista-file-source.js +2 -5
- package/dist/vista/vista-file-source.js.map +1 -1
- package/dist/vista/vista-form-context.d.ts +13 -0
- package/dist/vista/vista-form-context.d.ts.map +1 -0
- package/dist/vista/vista-form-context.js +6 -0
- package/dist/vista/vista-form-context.js.map +1 -0
- package/dist/vista/vista-form-host.d.ts +1 -10
- package/dist/vista/vista-form-host.d.ts.map +1 -1
- package/dist/vista/vista-form-host.js +1 -5
- package/dist/vista/vista-form-host.js.map +1 -1
- package/dist/vista/vista-open-context.d.ts +1 -3
- package/dist/vista/vista-open-context.d.ts.map +1 -1
- package/dist/vista/vista-open-context.js +1 -5
- package/dist/vista/vista-open-context.js.map +1 -1
- package/dist/vista/vista-open-state.d.ts +5 -0
- package/dist/vista/vista-open-state.d.ts.map +1 -0
- package/dist/vista/vista-open-state.js +6 -0
- package/dist/vista/vista-open-state.js.map +1 -0
- package/dist/vista/vista-payloads.d.ts +2 -3
- package/dist/vista/vista-payloads.d.ts.map +1 -1
- package/dist/vista/vista-payloads.js +18 -21
- package/dist/vista/vista-payloads.js.map +1 -1
- package/dist/vista/vista-tools.d.ts.map +1 -1
- package/dist/vista/vista-tools.js.map +1 -1
- package/package.json +3 -3
- package/src/lib/biome-host/biome-builders.ts +4 -1
- package/src/lib/biome-host/biome-registry.ts +0 -1
- package/src/lib/biome-host/biome-scope-hooks.ts +39 -0
- package/src/lib/biome-host/biome-scope.tsx +1 -68
- package/src/lib/biome-host/biome-scoped-query.ts +4 -1
- package/src/lib/biome-host/create-biome-orval-config.ts +2 -2
- package/src/lib/biome-host/errors.ts +1 -1
- package/src/lib/biome-host/index.ts +1 -1
- package/src/lib/biome-host/session-profiles.ts +7 -1
- package/src/lib/capabilities/capability-context.ts +25 -0
- package/src/lib/capabilities/capability-provider.tsx +5 -34
- package/src/lib/capabilities/index.ts +1 -0
- package/src/lib/capabilities/use-capability.ts +4 -1
- package/src/lib/system-bus/deeplink.ts +1 -1
- package/src/lib/system-bus/host-ports.ts +2 -1
- package/src/lib/system-bus/intent-registry.ts +1 -2
- package/src/offline/index.ts +4 -2
- package/src/offline/offline-status-badge.tsx +1 -1
- package/src/offline/outbox.test.ts +23 -16
- package/src/offline/outbox.ts +1 -1
- package/src/offline/react-hooks.ts +37 -0
- package/src/offline/react.tsx +1 -40
- package/src/offline/storage.ts +11 -6
- package/src/registry/index.ts +1 -0
- package/src/registry/lib/primitives/SessionEventCard.tsx +4 -2
- package/src/registry/lib/session-context-provider.tsx +8 -25
- package/src/registry/lib/session-context.ts +21 -0
- package/src/registry/lib/session-selectors.ts +3 -1
- package/src/ui/branding/app-branding-context.ts +20 -0
- package/src/ui/branding/app-branding-provider.tsx +5 -27
- package/src/ui/capture/schema-field-input.tsx +7 -1
- package/src/ui/capture/use-prefill.ts +4 -1
- package/src/ui/capture/use-wizard.ts +2 -2
- package/src/ui/capture/wizard.tsx +2 -1
- package/src/ui/index.ts +7 -2
- package/src/ui/primitives/alert-dialog.tsx +1 -1
- package/src/ui/primitives/badge-variants.ts +21 -0
- package/src/ui/primitives/badge.tsx +3 -19
- package/src/ui/primitives/button-variants.ts +31 -0
- package/src/ui/primitives/button.tsx +3 -28
- package/src/ui/primitives/form-stepper.tsx +1 -16
- package/src/ui/primitives/form-stepper.types.ts +15 -0
- package/src/ui/primitives/preview-device-frame.tsx +1 -1
- package/src/ui/primitives/tag-multi-select.tsx +3 -4
- package/src/vista/form-payload.spec.ts +71 -25
- package/src/vista/index.ts +4 -0
- package/src/vista/surfaces/FilesSurface.tsx +2 -68
- package/src/vista/surfaces/FormSurface.tsx +125 -26
- package/src/vista/surfaces/elicitation-transport.spec.ts +205 -23
- package/src/vista/surfaces/elicitation-transport.ts +192 -14
- package/src/vista/surfaces/file-surface-utils.ts +62 -0
- package/src/vista/surfaces/index.ts +24 -0
- package/src/vista/surfaces/{index.tsx → register-surfaces.tsx} +1 -21
- package/src/vista/surfaces/text-surfaces.tsx +1 -1
- package/src/vista/vista-code-renderer-context.ts +16 -0
- package/src/vista/vista-code-renderer.tsx +4 -16
- package/src/vista/vista-file-context.ts +14 -0
- package/src/vista/vista-file-source.tsx +5 -28
- package/src/vista/vista-form-context.ts +20 -0
- package/src/vista/vista-form-host.tsx +11 -36
- package/src/vista/vista-open-context.tsx +4 -14
- package/src/vista/vista-open-state.ts +11 -0
- package/src/vista/vista-payloads.ts +44 -46
- package/src/vista/vista-tools.ts +2 -2
- package/dist/lib/biome-host/response-envelope.d.ts +0 -3
- package/dist/lib/biome-host/response-envelope.d.ts.map +0 -1
- package/dist/lib/biome-host/response-envelope.js +0 -21
- package/dist/lib/biome-host/response-envelope.js.map +0 -1
- package/src/lib/biome-host/response-envelope.ts +0 -69
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import './register-surfaces';
|
|
2
|
+
|
|
3
|
+
export { ChartSurface } from './ChartSurface';
|
|
4
|
+
export { FilesSurface } from './FilesSurface';
|
|
5
|
+
export {
|
|
6
|
+
fileExtMeta,
|
|
7
|
+
groupFilesByFolder,
|
|
8
|
+
type VistaFileGroup,
|
|
9
|
+
} from './file-surface-utils';
|
|
10
|
+
export { FormSurface } from './FormSurface';
|
|
11
|
+
export {
|
|
12
|
+
extractServiceMessage,
|
|
13
|
+
readElicitationStatus,
|
|
14
|
+
resolveTrustedElicitationEndpoints,
|
|
15
|
+
resolveTrustedElicitationLaunchUrl,
|
|
16
|
+
submitElicitationFields,
|
|
17
|
+
VistaFormSubmitError,
|
|
18
|
+
VistaFormTransportConfigError,
|
|
19
|
+
} from './elicitation-transport';
|
|
20
|
+
export { HtmlSurface } from './HtmlSurface';
|
|
21
|
+
export { TableSurface } from './TableSurface';
|
|
22
|
+
export { UrlSurface } from './UrlSurface';
|
|
23
|
+
export { CodeSurface, DiffSurface, JsonSurface } from './text-surfaces';
|
|
24
|
+
export { ImageSurface, MediaSurface, PdfSurface } from './blob-surfaces';
|
|
@@ -29,11 +29,7 @@
|
|
|
29
29
|
*/
|
|
30
30
|
import { SurfaceKind } from '@xemahq/kernel-contracts/surface';
|
|
31
31
|
|
|
32
|
-
import {
|
|
33
|
-
ImageSurface,
|
|
34
|
-
MediaSurface,
|
|
35
|
-
PdfSurface,
|
|
36
|
-
} from './blob-surfaces';
|
|
32
|
+
import { ImageSurface, MediaSurface, PdfSurface } from './blob-surfaces';
|
|
37
33
|
import { ChartSurface } from './ChartSurface';
|
|
38
34
|
import { FilesSurface } from './FilesSurface';
|
|
39
35
|
import { FormSurface } from './FormSurface';
|
|
@@ -139,19 +135,3 @@ vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Form, {
|
|
|
139
135
|
validate: validateFormPayload,
|
|
140
136
|
render: (payload) => <FormSurface {...payload} />,
|
|
141
137
|
});
|
|
142
|
-
|
|
143
|
-
export { ChartSurface } from './ChartSurface';
|
|
144
|
-
export { FilesSurface, fileExtMeta, groupFilesByFolder } from './FilesSurface';
|
|
145
|
-
export { FormSurface } from './FormSurface';
|
|
146
|
-
export {
|
|
147
|
-
submitElicitationFields,
|
|
148
|
-
readElicitationStatus,
|
|
149
|
-
extractServiceMessage,
|
|
150
|
-
VistaFormSubmitError,
|
|
151
|
-
} from './elicitation-transport';
|
|
152
|
-
export { HtmlSurface } from './HtmlSurface';
|
|
153
|
-
export { TableSurface } from './TableSurface';
|
|
154
|
-
export { UrlSurface } from './UrlSurface';
|
|
155
|
-
export { CodeSurface, DiffSurface, JsonSurface } from './text-surfaces';
|
|
156
|
-
export { ImageSurface, MediaSurface, PdfSurface } from './blob-surfaces';
|
|
157
|
-
export type { VistaFileGroup } from './FilesSurface';
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* `plain` tab kind was collapsed into it; one kind, one renderer, no alias).
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { useVistaCodeRenderer } from '../vista-code-renderer';
|
|
12
|
+
import { useVistaCodeRenderer } from '../vista-code-renderer-context';
|
|
13
13
|
import { VistaFileText } from '../vista-file-source';
|
|
14
14
|
|
|
15
15
|
import type { VistaTextPayload } from '../vista-payloads';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
|
|
3
|
+
import type { ReactNode } from 'react';
|
|
4
|
+
|
|
5
|
+
export type VistaCodeRenderer = (args: {
|
|
6
|
+
readonly content: string;
|
|
7
|
+
readonly path?: string;
|
|
8
|
+
readonly language?: string;
|
|
9
|
+
}) => ReactNode;
|
|
10
|
+
|
|
11
|
+
export const VistaCodeRendererContext =
|
|
12
|
+
createContext<VistaCodeRenderer | null>(null);
|
|
13
|
+
|
|
14
|
+
export function useVistaCodeRenderer(): VistaCodeRenderer | null {
|
|
15
|
+
return useContext(VistaCodeRendererContext);
|
|
16
|
+
}
|
|
@@ -14,20 +14,13 @@
|
|
|
14
14
|
* the intended rendering. Neither is an error path.
|
|
15
15
|
*/
|
|
16
16
|
import {
|
|
17
|
-
createContext,
|
|
18
|
-
useContext,
|
|
19
17
|
type ReactElement,
|
|
20
18
|
type ReactNode,
|
|
21
19
|
} from 'react';
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
readonly path?: string;
|
|
27
|
-
readonly language?: string;
|
|
28
|
-
}) => ReactNode;
|
|
29
|
-
|
|
30
|
-
const VistaCodeRendererContext = createContext<VistaCodeRenderer | null>(null);
|
|
20
|
+
import {
|
|
21
|
+
VistaCodeRendererContext,
|
|
22
|
+
type VistaCodeRenderer,
|
|
23
|
+
} from './vista-code-renderer-context';
|
|
31
24
|
|
|
32
25
|
export function VistaCodeRendererProvider({
|
|
33
26
|
renderer,
|
|
@@ -39,8 +32,3 @@ export function VistaCodeRendererProvider({
|
|
|
39
32
|
</VistaCodeRendererContext.Provider>
|
|
40
33
|
);
|
|
41
34
|
}
|
|
42
|
-
|
|
43
|
-
/** The host's code renderer, or `null` for the built-in mono pane. */
|
|
44
|
-
export function useVistaCodeRenderer(): VistaCodeRenderer | null {
|
|
45
|
-
return useContext(VistaCodeRendererContext);
|
|
46
|
-
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface VistaFileSource {
|
|
4
|
+
readText(path: string): Promise<string>;
|
|
5
|
+
resolveUrl(path: string): Promise<string>;
|
|
6
|
+
readonly revision?: string | number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const VistaFileSourceContext =
|
|
10
|
+
createContext<VistaFileSource | null>(null);
|
|
11
|
+
|
|
12
|
+
export function useVistaFileSource(): VistaFileSource | null {
|
|
13
|
+
return useContext(VistaFileSourceContext);
|
|
14
|
+
}
|
|
@@ -13,34 +13,16 @@
|
|
|
13
13
|
* "content unavailable".
|
|
14
14
|
*/
|
|
15
15
|
import {
|
|
16
|
-
createContext,
|
|
17
|
-
useContext,
|
|
18
16
|
useEffect,
|
|
19
17
|
useState,
|
|
20
18
|
type ReactElement,
|
|
21
19
|
type ReactNode,
|
|
22
20
|
} from 'react';
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Resolve a workspace-relative path to a fetchable URL (`blob:`, `data:`, or
|
|
30
|
-
* a durable `https:` URL) for binary surfaces. Rejects on failure.
|
|
31
|
-
*
|
|
32
|
-
* The host owns the lifetime of anything it creates (e.g. revoking an object
|
|
33
|
-
* URL); the surface only reads.
|
|
34
|
-
*/
|
|
35
|
-
resolveUrl(path: string): Promise<string>;
|
|
36
|
-
/**
|
|
37
|
-
* Opaque revision token. Change it to make every mounted path-backed surface
|
|
38
|
-
* re-read (the host bumps it on a workspace file-change event).
|
|
39
|
-
*/
|
|
40
|
-
readonly revision?: string | number;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const VistaFileSourceContext = createContext<VistaFileSource | null>(null);
|
|
21
|
+
import {
|
|
22
|
+
VistaFileSourceContext,
|
|
23
|
+
useVistaFileSource,
|
|
24
|
+
type VistaFileSource,
|
|
25
|
+
} from './vista-file-context';
|
|
44
26
|
|
|
45
27
|
export function VistaFileSourceProvider({
|
|
46
28
|
source,
|
|
@@ -53,11 +35,6 @@ export function VistaFileSourceProvider({
|
|
|
53
35
|
);
|
|
54
36
|
}
|
|
55
37
|
|
|
56
|
-
/** The active file source, or `null` when no provider is mounted. */
|
|
57
|
-
export function useVistaFileSource(): VistaFileSource | null {
|
|
58
|
-
return useContext(VistaFileSourceContext);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
38
|
/** Async load state for a path-backed surface. */
|
|
62
39
|
type LoadState =
|
|
63
40
|
| { readonly status: 'loading' }
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface VistaFormOutcome {
|
|
4
|
+
readonly submitted: true;
|
|
5
|
+
readonly ref: string;
|
|
6
|
+
readonly connectionId: string | null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface VistaFormHost {
|
|
10
|
+
readonly elicitationApiBaseUrl: string;
|
|
11
|
+
getAccessToken(): Promise<string>;
|
|
12
|
+
onOutcome(outcome: VistaFormOutcome): void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const VistaFormHostContext =
|
|
16
|
+
createContext<VistaFormHost | null>(null);
|
|
17
|
+
|
|
18
|
+
export function useVistaFormHost(): VistaFormHost | null {
|
|
19
|
+
return useContext(VistaFormHostContext);
|
|
20
|
+
}
|
|
@@ -18,16 +18,22 @@
|
|
|
18
18
|
* 2. `getAccessToken` returns the SUBJECT's token. The host binds it to the
|
|
19
19
|
* logged-in user's session; it is never a service token and never the
|
|
20
20
|
* agent's token, so the service authorizes the human, not the model.
|
|
21
|
-
* 3.
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* app's own BFF/chat transport.
|
|
21
|
+
* 3. `elicitationApiBaseUrl` is supplied by trusted host configuration, never
|
|
22
|
+
* by the agent-controlled payload. The kernel validates its scheme and
|
|
23
|
+
* canonical authority/path before deriving the status/submit endpoints.
|
|
25
24
|
*
|
|
26
25
|
* There is deliberately NO default host: a `form` surface mounted without a
|
|
27
26
|
* provider renders a visible refusal and cannot submit. Fail-closed — a form
|
|
28
27
|
* that silently posts nowhere would be worse than one that says it cannot.
|
|
29
28
|
*/
|
|
30
|
-
import {
|
|
29
|
+
import {
|
|
30
|
+
type ReactElement,
|
|
31
|
+
type ReactNode,
|
|
32
|
+
} from 'react';
|
|
33
|
+
import {
|
|
34
|
+
VistaFormHostContext,
|
|
35
|
+
type VistaFormHost,
|
|
36
|
+
} from './vista-form-context';
|
|
31
37
|
|
|
32
38
|
/**
|
|
33
39
|
* Everything a settled elicitation reports. Closed, scalar-only, and
|
|
@@ -35,32 +41,6 @@ import { createContext, useContext, type ReactElement, type ReactNode } from 're
|
|
|
35
41
|
* persistence layer behind it has no column able to hold a field value, and
|
|
36
42
|
* neither does this type.
|
|
37
43
|
*/
|
|
38
|
-
export interface VistaFormOutcome {
|
|
39
|
-
/** Always `true`: an unsettled elicitation produces no outcome at all. */
|
|
40
|
-
readonly submitted: true;
|
|
41
|
-
/** The elicitation reference the agent polls. Opaque, non-secret. */
|
|
42
|
-
readonly ref: string;
|
|
43
|
-
/** The connection the submission provisioned, when the service reported one. */
|
|
44
|
-
readonly connectionId: string | null;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** Host-supplied capabilities for the `form` surface. */
|
|
48
|
-
export interface VistaFormHost {
|
|
49
|
-
/**
|
|
50
|
-
* The SUBJECT's own access token. Called once per request so a refreshed
|
|
51
|
-
* token is picked up without remounting the surface.
|
|
52
|
-
*/
|
|
53
|
-
getAccessToken(): Promise<string>;
|
|
54
|
-
/**
|
|
55
|
-
* Called exactly once when the elicitation settles. The host relays this to
|
|
56
|
-
* whatever needs to know (cache invalidation, the agent session). By type it
|
|
57
|
-
* can carry nothing but the outcome.
|
|
58
|
-
*/
|
|
59
|
-
onOutcome(outcome: VistaFormOutcome): void;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const VistaFormHostContext = createContext<VistaFormHost | null>(null);
|
|
63
|
-
|
|
64
44
|
export function VistaFormHostProvider({
|
|
65
45
|
host,
|
|
66
46
|
children,
|
|
@@ -71,8 +51,3 @@ export function VistaFormHostProvider({
|
|
|
71
51
|
</VistaFormHostContext.Provider>
|
|
72
52
|
);
|
|
73
53
|
}
|
|
74
|
-
|
|
75
|
-
/** The active form host, or `null` when no provider is mounted. */
|
|
76
|
-
export function useVistaFormHost(): VistaFormHost | null {
|
|
77
|
-
return useContext(VistaFormHostContext);
|
|
78
|
-
}
|
|
@@ -12,18 +12,13 @@
|
|
|
12
12
|
* silently does nothing.
|
|
13
13
|
*/
|
|
14
14
|
import {
|
|
15
|
-
createContext,
|
|
16
|
-
useContext,
|
|
17
15
|
type ReactElement,
|
|
18
16
|
type ReactNode,
|
|
19
17
|
} from 'react';
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
export type VistaOpenFn = (surface: VistaTab) => string;
|
|
25
|
-
|
|
26
|
-
const VistaOpenContext = createContext<VistaOpenFn | null>(null);
|
|
18
|
+
import {
|
|
19
|
+
VistaOpenContext,
|
|
20
|
+
type VistaOpenFn,
|
|
21
|
+
} from './vista-open-state';
|
|
27
22
|
|
|
28
23
|
export function VistaOpenProvider({
|
|
29
24
|
open,
|
|
@@ -35,8 +30,3 @@ export function VistaOpenProvider({
|
|
|
35
30
|
</VistaOpenContext.Provider>
|
|
36
31
|
);
|
|
37
32
|
}
|
|
38
|
-
|
|
39
|
-
/** The panel's `open`, or `null` when no panel is mounted above. */
|
|
40
|
-
export function useVistaOpen(): VistaOpenFn | null {
|
|
41
|
-
return useContext(VistaOpenContext);
|
|
42
|
-
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
|
|
3
|
+
import type { VistaTab } from './vista-model';
|
|
4
|
+
|
|
5
|
+
export type VistaOpenFn = (surface: VistaTab) => string;
|
|
6
|
+
|
|
7
|
+
export const VistaOpenContext = createContext<VistaOpenFn | null>(null);
|
|
8
|
+
|
|
9
|
+
export function useVistaOpen(): VistaOpenFn | null {
|
|
10
|
+
return useContext(VistaOpenContext);
|
|
11
|
+
}
|
|
@@ -199,7 +199,8 @@ export interface VistaTablePayload {
|
|
|
199
199
|
export function validateTablePayload(raw: unknown): VistaTablePayload | null {
|
|
200
200
|
const record = asRecord(raw);
|
|
201
201
|
if (record === null) return null;
|
|
202
|
-
if (!Array.isArray(record.columns) || !Array.isArray(record.rows))
|
|
202
|
+
if (!Array.isArray(record.columns) || !Array.isArray(record.rows))
|
|
203
|
+
return null;
|
|
203
204
|
if (!record.columns.every((c) => typeof c === 'string')) return null;
|
|
204
205
|
if (!record.rows.every((r) => Array.isArray(r))) return null;
|
|
205
206
|
return {
|
|
@@ -244,7 +245,8 @@ export function validateChartPayload(raw: unknown): VistaChartPayload | null {
|
|
|
244
245
|
if (record === null) return null;
|
|
245
246
|
if (typeof record.kind !== 'string' || !CHART_KINDS.includes(record.kind))
|
|
246
247
|
return null;
|
|
247
|
-
if (typeof record.title !== 'string' || record.title.length === 0)
|
|
248
|
+
if (typeof record.title !== 'string' || record.title.length === 0)
|
|
249
|
+
return null;
|
|
248
250
|
if (!Array.isArray(record.series) || record.series.length === 0) return null;
|
|
249
251
|
const series: VistaChartSeries[] = [];
|
|
250
252
|
for (const entry of record.series) {
|
|
@@ -377,37 +379,18 @@ export function validateWebPayload(raw: unknown): VistaWebPayload | null {
|
|
|
377
379
|
: null;
|
|
378
380
|
}
|
|
379
381
|
|
|
380
|
-
/**
|
|
381
|
-
* An `http(s)` ABSOLUTE URL, or `null`.
|
|
382
|
-
*
|
|
383
|
-
* Every URL on a {@link VistaFormPayload} must be absolute. That is the
|
|
384
|
-
* structural half of "the value goes browser → service and never through the
|
|
385
|
-
* agent": a relative path would resolve against the HOST app's origin — i.e.
|
|
386
|
-
* its BFF, where the chat transport lives — so a relative submit target is
|
|
387
|
-
* rejected outright rather than normalised.
|
|
388
|
-
*/
|
|
389
|
-
function absoluteHttpUrl(value: unknown): string | null {
|
|
390
|
-
if (typeof value !== 'string' || value.length === 0) return null;
|
|
391
|
-
let parsed: URL;
|
|
392
|
-
try {
|
|
393
|
-
parsed = new URL(value);
|
|
394
|
-
} catch {
|
|
395
|
-
return null;
|
|
396
|
-
}
|
|
397
|
-
return parsed.protocol === 'https:' || parsed.protocol === 'http:' ? value : null;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
382
|
/**
|
|
401
383
|
* The consent / install handoff of a {@link VistaFormPayload}.
|
|
402
384
|
*
|
|
403
385
|
* Present when the connector's app auth is `oauth2` or `app_install`: there is
|
|
404
386
|
* no field form to fill, only a link the user follows in another window. It is
|
|
405
|
-
* fully generic — the
|
|
406
|
-
*
|
|
387
|
+
* fully generic — the owning service supplies a path under the host-configured
|
|
388
|
+
* trusted service origin, so no provider is special-cased in the renderer and
|
|
389
|
+
* an agent-controlled payload never selects a network authority.
|
|
407
390
|
*/
|
|
408
391
|
export interface VistaFormLaunch {
|
|
409
|
-
/**
|
|
410
|
-
readonly
|
|
392
|
+
/** Root-relative consent / install path on the trusted elicitation service. */
|
|
393
|
+
readonly path: string;
|
|
411
394
|
/** Button copy, e.g. "Install Acme" / "Continue to Acme". */
|
|
412
395
|
readonly label: string;
|
|
413
396
|
/** Optional explanation rendered above the button. */
|
|
@@ -421,10 +404,10 @@ export interface VistaFormLaunch {
|
|
|
421
404
|
* never see. Two mutually-exclusive modes, chosen by the presence of
|
|
422
405
|
* {@link launch}:
|
|
423
406
|
*
|
|
424
|
-
* • FIELD mode — render `fields`, POST them
|
|
425
|
-
* own JWT;
|
|
407
|
+
* • FIELD mode — render `fields`, POST them through the host's trusted
|
|
408
|
+
* elicitation-service base URL with the user's own JWT;
|
|
426
409
|
* • LAUNCH mode — render the consent/install link, then confirm completion
|
|
427
|
-
*
|
|
410
|
+
* through that same trusted service.
|
|
428
411
|
*
|
|
429
412
|
* Both settle into the same `{ submitted, ref }` shape, so the agent's view of
|
|
430
413
|
* the world does not depend on which mode ran.
|
|
@@ -434,10 +417,6 @@ export interface VistaFormPayload {
|
|
|
434
417
|
readonly ref: string;
|
|
435
418
|
/** Why the credential is being asked for — shown to the user verbatim. */
|
|
436
419
|
readonly purpose: string;
|
|
437
|
-
/** ABSOLUTE service URL the captured fields are POSTed to. */
|
|
438
|
-
readonly submitUrl: string;
|
|
439
|
-
/** ABSOLUTE service URL reporting whether the elicitation has settled. */
|
|
440
|
-
readonly statusUrl: string;
|
|
441
420
|
/** The onboarding form's fields. MAY be empty — the service is the authority. */
|
|
442
421
|
readonly fields: readonly CaptureFieldSpec[];
|
|
443
422
|
/** Optional heading override (defaults to the tab title). */
|
|
@@ -448,16 +427,26 @@ export interface VistaFormPayload {
|
|
|
448
427
|
readonly launch?: VistaFormLaunch;
|
|
449
428
|
}
|
|
450
429
|
|
|
430
|
+
const VISTA_FORM_REF_PATTERN = /^[A-Za-z0-9_-]{1,256}$/;
|
|
431
|
+
|
|
432
|
+
/** Whether a value is one opaque base64url elicitation path segment. */
|
|
433
|
+
export function isValidVistaFormRef(value: unknown): value is string {
|
|
434
|
+
return typeof value === 'string' && VISTA_FORM_REF_PATTERN.test(value);
|
|
435
|
+
}
|
|
436
|
+
|
|
451
437
|
export function validateFormPayload(raw: unknown): VistaFormPayload | null {
|
|
452
438
|
const record = asRecord(raw);
|
|
453
439
|
if (record === null) return null;
|
|
454
|
-
|
|
440
|
+
// The service generates base64url refs. Keeping the accepted alphabet closed
|
|
441
|
+
// makes the ref safe as exactly one URL path segment; dot segments, slashes,
|
|
442
|
+
// percent escapes and Unicode lookalikes are all rejected.
|
|
443
|
+
if (!isValidVistaFormRef(record.ref)) {
|
|
444
|
+
return null;
|
|
445
|
+
}
|
|
455
446
|
if (typeof record.purpose !== 'string') return null;
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
if (submitUrl
|
|
459
|
-
const statusUrl = absoluteHttpUrl(record.statusUrl);
|
|
460
|
-
if (statusUrl === null) return null;
|
|
447
|
+
// Deliberately reject the old contract rather than silently ignoring its
|
|
448
|
+
// payload-selected network targets.
|
|
449
|
+
if ('submitUrl' in record || 'statusUrl' in record) return null;
|
|
461
450
|
|
|
462
451
|
const fields = validateCaptureFields(record.fields);
|
|
463
452
|
if (fields === null) return null;
|
|
@@ -471,24 +460,32 @@ export function validateFormPayload(raw: unknown): VistaFormPayload | null {
|
|
|
471
460
|
if (record.launch !== undefined) {
|
|
472
461
|
const raw_ = asRecord(record.launch);
|
|
473
462
|
if (raw_ === null) return null;
|
|
474
|
-
|
|
475
|
-
if (
|
|
463
|
+
if ('url' in raw_) return null;
|
|
464
|
+
if (
|
|
465
|
+
typeof raw_.path !== 'string' ||
|
|
466
|
+
!raw_.path.startsWith('/') ||
|
|
467
|
+
raw_.path.startsWith('//') ||
|
|
468
|
+
raw_.path.includes('\\')
|
|
469
|
+
) {
|
|
470
|
+
return null;
|
|
471
|
+
}
|
|
476
472
|
if (typeof raw_.label !== 'string' || raw_.label.length === 0) return null;
|
|
477
473
|
const hint = optionalString(raw_.hint);
|
|
478
474
|
if (hint === null) return null;
|
|
479
|
-
launch =
|
|
475
|
+
launch =
|
|
476
|
+
hint === undefined
|
|
477
|
+
? { path: raw_.path, label: raw_.label }
|
|
478
|
+
: { path: raw_.path, label: raw_.label, hint };
|
|
480
479
|
}
|
|
481
480
|
|
|
482
481
|
const payload: {
|
|
483
482
|
ref: string;
|
|
484
483
|
purpose: string;
|
|
485
|
-
submitUrl: string;
|
|
486
|
-
statusUrl: string;
|
|
487
484
|
fields: readonly CaptureFieldSpec[];
|
|
488
485
|
heading?: string;
|
|
489
486
|
submitLabel?: string;
|
|
490
487
|
launch?: VistaFormLaunch;
|
|
491
|
-
} = { ref: record.ref, purpose: record.purpose,
|
|
488
|
+
} = { ref: record.ref, purpose: record.purpose, fields };
|
|
492
489
|
if (heading !== undefined) payload.heading = heading;
|
|
493
490
|
if (submitLabel !== undefined) payload.submitLabel = submitLabel;
|
|
494
491
|
if (launch !== undefined) payload.launch = launch;
|
|
@@ -505,7 +502,8 @@ export interface VistaAppPayload {
|
|
|
505
502
|
export function validateAppPayload(raw: unknown): VistaAppPayload | null {
|
|
506
503
|
const record = asRecord(raw);
|
|
507
504
|
if (record === null) return null;
|
|
508
|
-
if (typeof record.appId !== 'string' || record.appId.length === 0)
|
|
505
|
+
if (typeof record.appId !== 'string' || record.appId.length === 0)
|
|
506
|
+
return null;
|
|
509
507
|
const path = optionalString(record.path);
|
|
510
508
|
if (path === null) return null;
|
|
511
509
|
return path === undefined
|
package/src/vista/vista-tools.ts
CHANGED
|
@@ -120,7 +120,7 @@ export const VistaToolResultSchema: z.ZodType<VistaToolResult> = z.union([
|
|
|
120
120
|
error: z.nativeEnum(VistaToolError),
|
|
121
121
|
detail: z.string().optional(),
|
|
122
122
|
}),
|
|
123
|
-
])
|
|
123
|
+
]);
|
|
124
124
|
|
|
125
125
|
/**
|
|
126
126
|
* Perform a relayed Vista tool call against a mounted panel's controller.
|
|
@@ -151,7 +151,7 @@ export function dispatchVistaTool(
|
|
|
151
151
|
const { tabId, ...patch } = parsed.data;
|
|
152
152
|
const refusal = refusalFor(controller, tabId);
|
|
153
153
|
if (refusal !== null) return refusal;
|
|
154
|
-
if (!controller.update(tabId, patch
|
|
154
|
+
if (!controller.update(tabId, patch)) {
|
|
155
155
|
// The tab is listed but not opened-tab-owned: it is a HOST tab, and a
|
|
156
156
|
// patch to it would be overwritten by the host's next reconcile.
|
|
157
157
|
return {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"response-envelope.d.ts","sourceRoot":"","sources":["../../../src/lib/biome-host/response-envelope.ts"],"names":[],"mappings":"AA+BA,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,GAAG,CAAC,EAAE,CAYjD;AAeD,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,GAAG,CAAC,CAU/C"}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
export function unwrapList(value) {
|
|
2
|
-
if (Array.isArray(value)) {
|
|
3
|
-
return value;
|
|
4
|
-
}
|
|
5
|
-
if (value !== null &&
|
|
6
|
-
typeof value === 'object' &&
|
|
7
|
-
Array.isArray(value.data)) {
|
|
8
|
-
return value.data;
|
|
9
|
-
}
|
|
10
|
-
return [];
|
|
11
|
-
}
|
|
12
|
-
export function unwrapData(value) {
|
|
13
|
-
if (value !== null &&
|
|
14
|
-
typeof value === 'object' &&
|
|
15
|
-
'data' in value &&
|
|
16
|
-
!('pagination' in value)) {
|
|
17
|
-
return value.data;
|
|
18
|
-
}
|
|
19
|
-
return value;
|
|
20
|
-
}
|
|
21
|
-
//# sourceMappingURL=response-envelope.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"response-envelope.js","sourceRoot":"","sources":["../../../src/lib/biome-host/response-envelope.ts"],"names":[],"mappings":"AA+BA,MAAM,UAAU,UAAU,CAAI,KAAc;IAC1C,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAY,CAAC;IACtB,CAAC;IACD,IACE,KAAK,KAAK,IAAI;QACd,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,CAAC,OAAO,CAAE,KAA4B,CAAC,IAAI,CAAC,EACjD,CAAC;QACD,OAAQ,KAAuB,CAAC,IAAI,CAAC;IACvC,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAeD,MAAM,UAAU,UAAU,CAAI,KAAc;IAC1C,IACE,KAAK,KAAK,IAAI;QACd,OAAO,KAAK,KAAK,QAAQ;QACzB,MAAM,IAAK,KAAiC;QAC5C,CAAC,CAAC,YAAY,IAAK,KAAiC,CAAC,EACrD,CAAC;QACD,OAAQ,KAAqB,CAAC,IAAI,CAAC;IACrC,CAAC;IACD,OAAO,KAAU,CAAC;AACpB,CAAC"}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Frontend mirror of the backend `ResponseEnvelopeInterceptor`.
|
|
3
|
-
*
|
|
4
|
-
* Every 2xx body the platform returns is wrapped as `{ data: T }`, or
|
|
5
|
-
* `{ data: T[], pagination }` for a paginated list (single source of truth:
|
|
6
|
-
* `@xemahq/platform-common`'s `ResponseEnvelopeInterceptor`). Orval's
|
|
7
|
-
* `custom-fetch` mutators usually peel that envelope at the HTTP boundary, but
|
|
8
|
-
* spec drift (a controller typed `T[]` that emits `{ data }`), public clients
|
|
9
|
-
* that DON'T peel, and transient partial responses leave a `.data`-wrapped or
|
|
10
|
-
* mis-shaped value where biome code expects a bare value/array — and a raw
|
|
11
|
-
* `.map` on it white-screens the route.
|
|
12
|
-
*
|
|
13
|
-
* These are the ONE shared, pure unwrap helpers — no host context, no fetch.
|
|
14
|
-
* Biomes (and the host shell's own `unwrap-list.ts`) should adopt these instead
|
|
15
|
-
* of re-implementing the guard. This is the shared helper only; adopters are
|
|
16
|
-
* migrated incrementally, not in a blanket rewrite.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Resilient list unwrap for DISPLAY surfaces — normalises a React-Query `.data`
|
|
21
|
-
* to an array so the page renders its empty/error state instead of crashing:
|
|
22
|
-
*
|
|
23
|
-
* - already an array → returned as-is
|
|
24
|
-
* - `{ data: T[] }` envelope → `value.data`
|
|
25
|
-
* - anything else → `[]`
|
|
26
|
-
*
|
|
27
|
-
* Deliberately NON-throwing: the query's own `isError`/`isLoading` flags drive
|
|
28
|
-
* the visible error/empty UI; this only guards the render path. For
|
|
29
|
-
* mutation/single-resource flows where an unexpected shape is a real bug, use
|
|
30
|
-
* {@link unwrapData} (fail-fast) instead.
|
|
31
|
-
*/
|
|
32
|
-
export function unwrapList<T>(value: unknown): T[] {
|
|
33
|
-
if (Array.isArray(value)) {
|
|
34
|
-
return value as T[];
|
|
35
|
-
}
|
|
36
|
-
if (
|
|
37
|
-
value !== null &&
|
|
38
|
-
typeof value === 'object' &&
|
|
39
|
-
Array.isArray((value as { data?: unknown }).data)
|
|
40
|
-
) {
|
|
41
|
-
return (value as { data: T[] }).data;
|
|
42
|
-
}
|
|
43
|
-
return [];
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Fail-fast single-resource unwrap. Returns `value.data` when the value is a
|
|
48
|
-
* `{ data }` envelope; returns the value unchanged when it is already the
|
|
49
|
-
* unwrapped resource (an Orval client that peeled the envelope at the boundary).
|
|
50
|
-
*
|
|
51
|
-
* Use this on mutation / single-resource flows where the response SHOULD be a
|
|
52
|
-
* concrete object — unlike {@link unwrapList}, it does not silently coerce, so
|
|
53
|
-
* a genuinely-unexpected shape surfaces as the value rather than being masked.
|
|
54
|
-
*
|
|
55
|
-
* A paginated envelope (`{ data, pagination }`) is returned INTACT — callers
|
|
56
|
-
* that need both fields read them off the returned object; peeling only `data`
|
|
57
|
-
* would drop the pagination cursor.
|
|
58
|
-
*/
|
|
59
|
-
export function unwrapData<T>(value: unknown): T {
|
|
60
|
-
if (
|
|
61
|
-
value !== null &&
|
|
62
|
-
typeof value === 'object' &&
|
|
63
|
-
'data' in (value as Record<string, unknown>) &&
|
|
64
|
-
!('pagination' in (value as Record<string, unknown>))
|
|
65
|
-
) {
|
|
66
|
-
return (value as { data: T }).data;
|
|
67
|
-
}
|
|
68
|
-
return value as T;
|
|
69
|
-
}
|