@ggui-ai/iframe-runtime 0.1.0-rc.3 → 0.2.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +7 -6
  2. package/dist/channel-transport.d.ts +15 -15
  3. package/dist/channel-transport.js +32 -35
  4. package/dist/channels/channel-payload.d.ts +2 -2
  5. package/dist/channels/channel-payload.js +1 -1
  6. package/dist/channels/data.d.ts +14 -19
  7. package/dist/channels/data.js +13 -31
  8. package/dist/channels/drain-ack.d.ts +2 -2
  9. package/dist/channels/drain-ack.js +1 -1
  10. package/dist/channels/feedback.d.ts +1 -1
  11. package/dist/channels/index.d.ts +1 -1
  12. package/dist/channels/index.js +1 -1
  13. package/dist/channels/props-update.d.ts +33 -37
  14. package/dist/channels/props-update.js +30 -106
  15. package/dist/channels/render-frame.d.ts +52 -0
  16. package/dist/channels/render-frame.js +53 -0
  17. package/dist/channels/system.d.ts +1 -1
  18. package/dist/compiled-validators.d.ts +15 -0
  19. package/dist/compiled-validators.js +31 -0
  20. package/dist/context-observer.d.ts +68 -8
  21. package/dist/context-observer.js +25 -45
  22. package/dist/events-polling.d.ts +95 -0
  23. package/dist/events-polling.js +143 -0
  24. package/dist/gadget-loader.d.ts +1 -1
  25. package/dist/globals.d.ts +4 -4
  26. package/dist/host-context-emitter.d.ts +84 -20
  27. package/dist/host-context-emitter.js +159 -29
  28. package/dist/iframe-runtime.js +98 -59
  29. package/dist/index.d.ts +18 -13
  30. package/dist/index.js +1 -1
  31. package/dist/lifecycle.d.ts +2 -2
  32. package/dist/lifecycle.js +5 -5
  33. package/dist/mcp-app-iframe-host.d.ts +9 -9
  34. package/dist/mcp-app-iframe-host.js +16 -17
  35. package/dist/meta-parse.d.ts +44 -0
  36. package/dist/meta-parse.js +390 -0
  37. package/dist/observability.d.ts +6 -6
  38. package/dist/protocol-error.d.ts +7 -7
  39. package/dist/provisional-renderer.d.ts +1 -1
  40. package/dist/provisional-renderer.js +1 -1
  41. package/dist/react-renderer.d.ts +10 -11
  42. package/dist/react-renderer.js +8 -8
  43. package/dist/registry-subscribe.d.ts +27 -9
  44. package/dist/registry-subscribe.js +32 -27
  45. package/dist/render-item.d.ts +83 -0
  46. package/dist/{stack-item-renderer.js → render-item.js} +106 -106
  47. package/dist/runtime.d.ts +183 -131
  48. package/dist/runtime.js +1264 -1330
  49. package/dist/status-dom.d.ts +52 -47
  50. package/dist/status-dom.js +51 -34
  51. package/dist/system-cards/NoCredentialsCard.d.ts +1 -1
  52. package/dist/system-cards/NoCredentialsCard.js +1 -1
  53. package/dist/system-cards/ProtocolProbeCard.js +2 -2
  54. package/dist/system-cards/index.d.ts +4 -4
  55. package/dist/system-cards/index.js +4 -4
  56. package/dist/types.d.ts +70 -34
  57. package/dist/types.js +1 -1
  58. package/dist/validation.d.ts +2 -2
  59. package/dist/validation.js +2 -2
  60. package/dist/wire-config.d.ts +54 -82
  61. package/dist/wire-config.js +61 -93
  62. package/package.json +9 -8
  63. package/dist/bootstrap.d.ts +0 -72
  64. package/dist/bootstrap.js +0 -500
  65. package/dist/canvas/animator/animator-host.d.ts +0 -63
  66. package/dist/canvas/animator/animator-host.js +0 -105
  67. package/dist/canvas/animator/animator-pill.d.ts +0 -42
  68. package/dist/canvas/animator/animator-pill.js +0 -119
  69. package/dist/canvas/animator/state-machine.d.ts +0 -106
  70. package/dist/canvas/animator/state-machine.js +0 -150
  71. package/dist/canvas/canvas-shell.d.ts +0 -77
  72. package/dist/canvas/canvas-shell.js +0 -117
  73. package/dist/canvas/display-mode-policy.d.ts +0 -104
  74. package/dist/canvas/display-mode-policy.js +0 -98
  75. package/dist/canvas/mount.d.ts +0 -150
  76. package/dist/canvas/mount.js +0 -202
  77. package/dist/canvas/nav-stack.d.ts +0 -133
  78. package/dist/canvas/nav-stack.js +0 -172
  79. package/dist/channels/push.d.ts +0 -47
  80. package/dist/channels/push.js +0 -54
  81. package/dist/stack-item-renderer.d.ts +0 -103
  82. package/dist/stack.d.ts +0 -90
  83. package/dist/stack.js +0 -118
@@ -1,72 +1,77 @@
1
1
  /**
2
- * In-iframe status DOM. Extracted from `runtime.ts` in B3b so the
3
- * channel-client handlers can import the `setStatus` + status-refs
4
- * helpers without a circular dep on the runtime module (which imports
5
- * the handlers for registration at boot).
2
+ * In-iframe runtime status surface.
6
3
  *
7
- * Operators see the boot state at a glance; failures land here with a
8
- * prefix that makes them grep-able in dev consoles.
4
+ * Used to inject a visible `<div data-ggui-status>` banner ("Initializing
5
+ * renderer…", "Connected", etc.) into the iframe body alongside the
6
+ * user-rendered React tree. End users saw it as a stray label above
7
+ * their UI — production-unfriendly. As of the displayMode-divergence
8
+ * close-out we route status transitions to `console.log` and inject ONLY
9
+ * the React mount-target div (no banner, no list-item placeholder text).
9
10
  *
10
- * The status DOM is a `<div data-ggui-status>` + `<ul data-ggui-stack>`
11
- * pair built once at boot and reused for the iframe's lifetime. The
12
- * `data-ggui-status` attribute carries a {@link StatusKind} value so
13
- * operator stylesheets + e2e specs can pin assertions against the
14
- * narrow union rather than reading the text content.
11
+ * Post-stack-removal (2026-05-27): the iframe holds exactly one mounted
12
+ * render for its lifetime. The `setConnectedStatus` helper no longer takes
13
+ * a stack-model arg — there's nothing to count — and the placeholder
14
+ * `<li data-ggui-stack-item>` render path is gone.
15
+ *
16
+ * The exported names (`setStatus`, `setConnectedStatus`, `StatusRefs`)
17
+ * are preserved so the channel handlers + runtime keep their import
18
+ * shape.
15
19
  */
16
- import type { StackModel } from './stack.js';
17
20
  /**
18
- * Closed union of values the `data-ggui-status` attribute carries.
21
+ * Closed union of values the iframe's status surface carries. Kept on
22
+ * the runtime side as the canonical state vocabulary even though it no
23
+ * longer surfaces visibly.
19
24
  *
20
- * - `idle` — initial state before any boot IO. Default text reads
21
- * "Initializing renderer…"; set by {@link ensureStatusDom}.
22
- * - `initializing` — same as `idle` (legacy alias kept for the rare
23
- * external CSS hook in `e2e/`).
25
+ * - `idle` — initial state before any boot IO.
26
+ * - `initializing` — legacy alias for `idle`.
24
27
  * - `connecting` — ui/initialize fired or WS handshake in flight.
25
28
  * - `connected` — first ack landed + every subsequent successful
26
- * push. Text shows the live stack count.
27
- * - `reconnecting` — WS dropped; the reconnect ladder is running.
28
- * - `disconnected` — terminal close + ladder exhausted, or a graceful
29
- * stop. Authors may layer reload UX here.
30
- * - `upgrade-required` — version handshake failed; operator should
31
- * upgrade the client.
32
- * - `error` — every other failure (ui/initialize, bootstrap parse,
33
- * WS handshake non-version).
29
+ * push.
30
+ * - `reconnecting` — WS dropped; reconnect ladder running.
31
+ * - `disconnected` — terminal close + ladder exhausted.
32
+ * - `upgrade-required` — version handshake failed.
33
+ * - `error` — every other failure.
34
34
  *
35
- * Closed at this layer; new values require a code change here PLUS
36
- * any e2e specs / CSS that pattern-match against the attribute.
35
+ * Surfaces on `console.log` prefixed `[ggui:<state>]`; consumers
36
+ * (operators, e2e specs) MAY install a `console.log` interceptor or
37
+ * read `notifyParent('ggui:bootstrap-failed', …)` for failure paths.
37
38
  */
38
39
  export type StatusKind = 'idle' | 'initializing' | 'connecting' | 'connected' | 'reconnecting' | 'disconnected' | 'upgrade-required' | 'error';
39
40
  /**
40
- * Refs handed back from {@link ensureStatusDom}. Stays narrow (two
41
- * elements) so the channel handlers can close over them without
42
- * pulling other runtime state.
41
+ * Refs handed back from {@link ensureStatusDom}. `status` is a detached
42
+ * element kept for backward compatibility with channel handlers that
43
+ * still pass `refs.status` through; it is NEVER appended to the
44
+ * document, so production iframes carry no diagnostic banner. `stack`
45
+ * is the React mount target — appended to `document.body` so renderer
46
+ * wiring has a container.
43
47
  */
44
48
  export interface StatusRefs {
45
49
  readonly status: HTMLElement;
46
50
  readonly stack: HTMLElement;
47
51
  }
48
52
  /**
49
- * Build the minimum viable status DOM the runtime owns. Adopters can
50
- * style via the `data-ggui-status` / `data-ggui-stack` attributes; the
51
- * bundle ships zero CSS so hosts see only the structure.
53
+ * Build the React mount target. Reuses pre-existing `[data-ggui-stack]`
54
+ * if the shell already wrote one (cf. `buildSelfContainedShell`); else
55
+ * creates a fresh `<ul data-ggui-stack>` and appends it to `<body>`.
56
+ * The companion `status` element is created detached and never
57
+ * appended — consumers that still pass it through `StatusRefs` see no
58
+ * visible effect.
59
+ *
60
+ * The `<ul>` element name is preserved (legacy from the stack-of-N
61
+ * placeholder render path) but only ever holds a single React mount
62
+ * subtree post-stack-removal.
52
63
  */
53
64
  export declare function ensureStatusDom(doc: Document): StatusRefs;
54
65
  /**
55
- * Set the status text + the `data-ggui-status` attribute. Centralised
56
- * so every caller stays consistent across the runtime + the channel
57
- * handlers (push handler keeps the count fresh on every fold).
66
+ * Log a status transition. The element is mutated for backward compat
67
+ * (some tests still hold a `refs.status` reference), but production
68
+ * users never see it because the element is detached from `document`.
58
69
  */
59
70
  export declare function setStatus(refs: StatusRefs, text: string, state: StatusKind): void;
60
71
  /**
61
- * Convenience — render the `connected (N items)` status line based on
62
- * the current stack model size. Used by the push handler on every
63
- * successful upsert + by the boot sequence on first ack.
64
- */
65
- export declare function setConnectedStatus(refs: StatusRefs, model: StackModel): void;
66
- /**
67
- * Re-render the stack DOM into the placeholder element. Wraps the
68
- * standalone {@link renderStackInto} so callers can pass refs + model
69
- * without unpacking; the standalone export stays for the legacy
70
- * callers that have only the bare element in scope.
72
+ * Log the "connected" transition. Post-stack-removal the iframe always
73
+ * holds exactly one item; the message stays bare ("Connected.") since
74
+ * there's no count to surface. Consumers (devtools, e2e specs
75
+ * intercepting `console.log`) get a stable string on every push.
71
76
  */
72
- export declare function refreshStackDom(refs: StatusRefs, model: StackModel): void;
77
+ export declare function setConnectedStatus(refs: StatusRefs): void;
@@ -1,51 +1,68 @@
1
- import { renderStackInto } from './stack.js';
2
1
  /**
3
- * Build the minimum viable status DOM the runtime owns. Adopters can
4
- * style via the `data-ggui-status` / `data-ggui-stack` attributes; the
5
- * bundle ships zero CSS so hosts see only the structure.
2
+ * In-iframe runtime status surface.
3
+ *
4
+ * Used to inject a visible `<div data-ggui-status>` banner ("Initializing
5
+ * renderer…", "Connected", etc.) into the iframe body alongside the
6
+ * user-rendered React tree. End users saw it as a stray label above
7
+ * their UI — production-unfriendly. As of the displayMode-divergence
8
+ * close-out we route status transitions to `console.log` and inject ONLY
9
+ * the React mount-target div (no banner, no list-item placeholder text).
10
+ *
11
+ * Post-stack-removal (2026-05-27): the iframe holds exactly one mounted
12
+ * render for its lifetime. The `setConnectedStatus` helper no longer takes
13
+ * a stack-model arg — there's nothing to count — and the placeholder
14
+ * `<li data-ggui-stack-item>` render path is gone.
15
+ *
16
+ * The exported names (`setStatus`, `setConnectedStatus`, `StatusRefs`)
17
+ * are preserved so the channel handlers + runtime keep their import
18
+ * shape.
19
+ */
20
+ /**
21
+ * Build the React mount target. Reuses pre-existing `[data-ggui-stack]`
22
+ * if the shell already wrote one (cf. `buildSelfContainedShell`); else
23
+ * creates a fresh `<ul data-ggui-stack>` and appends it to `<body>`.
24
+ * The companion `status` element is created detached and never
25
+ * appended — consumers that still pass it through `StatusRefs` see no
26
+ * visible effect.
27
+ *
28
+ * The `<ul>` element name is preserved (legacy from the stack-of-N
29
+ * placeholder render path) but only ever holds a single React mount
30
+ * subtree post-stack-removal.
6
31
  */
7
32
  export function ensureStatusDom(doc) {
8
- // Reuse pre-existing nodes if the thin shell wrote them — lets the
9
- // shell inline a status line if it wants to.
10
- const existingStatus = doc.querySelector('[data-ggui-status]');
11
33
  const existingStack = doc.querySelector('[data-ggui-stack]');
12
- if (existingStatus !== null && existingStack !== null) {
13
- return { status: existingStatus, stack: existingStack };
14
- }
15
- const root = doc.body;
34
+ const stack = existingStack ??
35
+ (() => {
36
+ const el = doc.createElement('ul');
37
+ el.setAttribute('data-ggui-stack', '');
38
+ doc.body.appendChild(el);
39
+ return el;
40
+ })();
41
+ // Detached placeholder so legacy `setStatus(refs, …)` calls have
42
+ // somewhere to write without touching the visible DOM. `aria-hidden`
43
+ // + zero size belt-and-braces in case any path appends it later.
16
44
  const status = doc.createElement('div');
17
45
  status.setAttribute('data-ggui-status', 'idle');
18
- status.textContent = 'Initializing renderer…';
19
- const stack = doc.createElement('ul');
20
- stack.setAttribute('data-ggui-stack', '');
21
- root.appendChild(status);
22
- root.appendChild(stack);
46
+ status.setAttribute('aria-hidden', 'true');
23
47
  return { status, stack };
24
48
  }
25
49
  /**
26
- * Set the status text + the `data-ggui-status` attribute. Centralised
27
- * so every caller stays consistent across the runtime + the channel
28
- * handlers (push handler keeps the count fresh on every fold).
50
+ * Log a status transition. The element is mutated for backward compat
51
+ * (some tests still hold a `refs.status` reference), but production
52
+ * users never see it because the element is detached from `document`.
29
53
  */
30
54
  export function setStatus(refs, text, state) {
31
55
  refs.status.textContent = text;
32
56
  refs.status.setAttribute('data-ggui-status', state);
57
+ // eslint-disable-next-line no-console
58
+ console.log(`[ggui:${state}]`, text);
33
59
  }
34
60
  /**
35
- * Convenience — render the `connected (N items)` status line based on
36
- * the current stack model size. Used by the push handler on every
37
- * successful upsert + by the boot sequence on first ack.
38
- */
39
- export function setConnectedStatus(refs, model) {
40
- const size = model.size();
41
- setStatus(refs, `Connected (${size} item${size === 1 ? '' : 's'}).`, 'connected');
42
- }
43
- /**
44
- * Re-render the stack DOM into the placeholder element. Wraps the
45
- * standalone {@link renderStackInto} so callers can pass refs + model
46
- * without unpacking; the standalone export stays for the legacy
47
- * callers that have only the bare element in scope.
61
+ * Log the "connected" transition. Post-stack-removal the iframe always
62
+ * holds exactly one item; the message stays bare ("Connected.") since
63
+ * there's no count to surface. Consumers (devtools, e2e specs
64
+ * intercepting `console.log`) get a stable string on every push.
48
65
  */
49
- export function refreshStackDom(refs, model) {
50
- renderStackInto(refs.stack, model);
66
+ export function setConnectedStatus(refs) {
67
+ setStatus(refs, 'Connected.', 'connected');
51
68
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * No-credentials system card.
3
3
  *
4
- * Rendered when the server processed a `ggui_push` for a session whose
4
+ * Rendered when the server processed a `ggui_render` for a session whose
5
5
  * LLM credentials are missing or unresolvable. The user needs to open
6
6
  * the server's `/settings` page in a real browser tab to paste an API
7
7
  * key.
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  /**
3
3
  * No-credentials system card.
4
4
  *
5
- * Rendered when the server processed a `ggui_push` for a session whose
5
+ * Rendered when the server processed a `ggui_render` for a session whose
6
6
  * LLM credentials are missing or unresolvable. The user needs to open
7
7
  * the server's `/settings` page in a real browser tab to paste an API
8
8
  * key.
@@ -211,7 +211,7 @@ function defaultParams(method) {
211
211
  intent: 'probe-click',
212
212
  data: { note: 'hello from the protocol probe' },
213
213
  },
214
- sessionId: 'probe-session',
214
+ renderId: 'probe-render',
215
215
  appId: 'probe-app',
216
216
  actionId: '00000000', // overwritten in onClick with real FNV-1a
217
217
  firedAt: new Date().toISOString(),
@@ -312,7 +312,7 @@ function ProbeButtonRow({ method, description, call, }) {
312
312
  const args = params
313
313
  .arguments ?? {};
314
314
  // New gesture-envelope shape (SPEC §4.6): `{kind, payload,
315
- // sessionId, appId, actionId, firedAt}`. For Pattern β the
315
+ // renderId, appId, actionId, firedAt}`. For Pattern β the
316
316
  // `payload` carries `{intent, data}`.
317
317
  const payload = args['payload'] ?? {};
318
318
  const intent = String(payload['intent'] ?? '?');
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * System-card registry.
3
3
  *
4
- * Central mapping from `SystemStackItem.kind` (a stable wire string)
4
+ * Central mapping from `SystemRender.kind` (a stable wire string)
5
5
  * to a real React component bundled inside the iframe-runtime. The
6
6
  * runtime's self-contained boot path looks up the kind here when it
7
- * sees a stack item with `type: 'system'`. Unknown kinds fall through
7
+ * sees a render with `type: 'system'`. Unknown kinds fall through
8
8
  * to {@link UnknownSystemCard} so an old runtime + new server still
9
9
  * surfaces something visible (vs. a blank iframe).
10
10
  *
@@ -13,7 +13,7 @@
13
13
  * 1. Author `MyNewCard.tsx` in this directory.
14
14
  * 2. Add an entry to {@link SYSTEM_CARD_REGISTRY} below.
15
15
  * 3. (Optional) Add the new kind string to
16
- * `SystemStackItemKind` in `@ggui-ai/protocol` for IDE autocomplete.
16
+ * `SystemRenderKind` in `@ggui-ai/protocol` for IDE autocomplete.
17
17
  */
18
18
  import * as React from 'react';
19
19
  import { NoCredentialsCard, type NoCredentialsCardProps } from './NoCredentialsCard.js';
@@ -28,7 +28,7 @@ import { ProtocolProbeCard, type ProtocolProbeCardProps } from './ProtocolProbeC
28
28
  export type SystemCardComponent = React.ComponentType<Record<string, unknown>>;
29
29
  /**
30
30
  * Registered system-card kinds. Keep keys aligned with
31
- * `SystemStackItemKind` in `@ggui-ai/protocol` so wire + bundle stay
31
+ * `SystemRenderKind` in `@ggui-ai/protocol` so wire + bundle stay
32
32
  * in sync. New kinds added without a registry entry render as
33
33
  * {@link UnknownSystemCard}.
34
34
  */
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * System-card registry.
3
3
  *
4
- * Central mapping from `SystemStackItem.kind` (a stable wire string)
4
+ * Central mapping from `SystemRender.kind` (a stable wire string)
5
5
  * to a real React component bundled inside the iframe-runtime. The
6
6
  * runtime's self-contained boot path looks up the kind here when it
7
- * sees a stack item with `type: 'system'`. Unknown kinds fall through
7
+ * sees a render with `type: 'system'`. Unknown kinds fall through
8
8
  * to {@link UnknownSystemCard} so an old runtime + new server still
9
9
  * surfaces something visible (vs. a blank iframe).
10
10
  *
@@ -13,7 +13,7 @@
13
13
  * 1. Author `MyNewCard.tsx` in this directory.
14
14
  * 2. Add an entry to {@link SYSTEM_CARD_REGISTRY} below.
15
15
  * 3. (Optional) Add the new kind string to
16
- * `SystemStackItemKind` in `@ggui-ai/protocol` for IDE autocomplete.
16
+ * `SystemRenderKind` in `@ggui-ai/protocol` for IDE autocomplete.
17
17
  */
18
18
  import * as React from 'react';
19
19
  import { ThemeProvider, lightTheme, darkTheme } from '@ggui-ai/design/themes';
@@ -64,7 +64,7 @@ function UnknownSystemCard({ kind, props, }) {
64
64
  }
65
65
  /**
66
66
  * Registered system-card kinds. Keep keys aligned with
67
- * `SystemStackItemKind` in `@ggui-ai/protocol` so wire + bundle stay
67
+ * `SystemRenderKind` in `@ggui-ai/protocol` so wire + bundle stay
68
68
  * in sync. New kinds added without a registry entry render as
69
69
  * {@link UnknownSystemCard}.
70
70
  */
package/dist/types.d.ts CHANGED
@@ -2,22 +2,57 @@
2
2
  * Internal types shared across the `@ggui-ai/iframe-runtime` runtime.
3
3
  *
4
4
  * These shapes describe the renderer's INTERNAL contracts — the
5
- * bootstrap-parse outcome union + the renderer-host postMessage
6
- * frames. The wire shapes consumed FROM the network
7
- * (`SubscribePayload`, `AckPayload`, `WebSocketMessage`,
8
- * `GguiBootstrapMeta`) come from `@ggui-ai/protocol` and are imported
9
- * as `type` only so esbuild emits no runtime require for the protocol
10
- * package — the bundle stays self-contained.
5
+ * slice-parse outcome union + the renderer-host postMessage frames.
6
+ * The wire shapes consumed FROM the network (`SubscribePayload`,
7
+ * `AckPayload`, `WebSocketMessage`, `McpAppAiGguiRenderMeta`) come from
8
+ * `@ggui-ai/protocol` and are imported as `type` only so esbuild
9
+ * emits no runtime require for the protocol package — the bundle
10
+ * stays self-contained.
11
11
  *
12
- * Post-B3b: the WS lifecycle lives inside `@ggui-ai/channel-client`'s
12
+ * Post-B3b: the WS lifecycle lives inside `@ggui-ai/live-channel`'s
13
13
  * `WSTransport`; the renderer no longer maintains its own manager
14
14
  * class. The `RendererWebSocketManagerOptions` type that pre-B3b
15
15
  * declared the manager's constructor bag has been retired.
16
16
  */
17
- import type { GguiBootstrapMeta } from '@ggui-ai/protocol/integrations/mcp-apps';
18
- import type { HostContextProjection } from '@ggui-ai/protocol';
17
+ import type { McpAppAiGguiRenderMeta } from '@ggui-ai/protocol/integrations/mcp-apps';
18
+ import type { HostContextProjection, ComponentRender, SystemRender } from '@ggui-ai/protocol';
19
19
  /**
20
- * Why a bootstrap parse can fail. Closed union — every value is a
20
+ * Post-Phase-B alias kept for ergonomic call sites — the wire-side
21
+ * `McpAppAiGguiRenderMeta` is the single source of truth, and the
22
+ * "validated" qualifier is a no-op now (no nested-optional-session
23
+ * narrowing left after the slice merge). Future callers SHOULD prefer
24
+ * `McpAppAiGguiRenderMeta` directly; the alias persists so the rename
25
+ * sweep can land incrementally without churn at every call site.
26
+ */
27
+ export type ValidatedMcpAppAiGguiMeta = McpAppAiGguiRenderMeta;
28
+ /**
29
+ * The four server-assigned ledger fields on every wire-delivered
30
+ * {@link Render}. They're stamped by the server's per-render event
31
+ * ledger — NOT derivable from the inline `__GGUI_META__` bootstrap.
32
+ */
33
+ type RenderLedgerFields = 'eventSequence' | 'createdAt' | 'lastActivityAt' | 'expiresAt';
34
+ /**
35
+ * The mount surface's INPUT contract — what `mountRender` / `applyRender`
36
+ * accept. It is a {@link Render} minus the four server-assigned ledger
37
+ * fields ({@link RenderLedgerFields}), so the runtime can mount the
38
+ * compiled component (or system card) carried inline by the resource
39
+ * shell BEFORE the authoritative wire `Render` arrives over the WS.
40
+ *
41
+ * A full `Render` is assignable to `RenderSeedInput` (it carries every
42
+ * field plus the ledger), so the WS-ack reconcile path passes a real
43
+ * `Render` here unchanged; the inline-seed path passes the projection
44
+ * built by `buildRenderSeedInput`. We do NOT fabricate the ledger fields
45
+ * (Strict-Typing-First / no-type-laundering) — the first ack replaces
46
+ * the seed with the authoritative `Render`.
47
+ *
48
+ * Carries the SAME contract-spec fields a full `ComponentRender` does
49
+ * (`propsSpec` / `streamSpec` / `actionSpec`), as `undefined` on a
50
+ * seed — so the channel handlers that read those after the
51
+ * `type !== 'mcpApps' && type !== 'system'` narrowing stay type-clean.
52
+ */
53
+ export type RenderSeedInput = Omit<ComponentRender, RenderLedgerFields> | Omit<SystemRender, RenderLedgerFields>;
54
+ /**
55
+ * Why a slice-meta parse can fail. Closed union — every value is a
21
56
  * canonical reason the renderer surfaces to the host via postMessage.
22
57
  *
23
58
  * This set is intentionally narrow — it covers only parse-time
@@ -28,42 +63,43 @@ import type { HostContextProjection } from '@ggui-ai/protocol';
28
63
  * - `MISSING_TOOL_OUTPUT` — host echoed `ui/initialize` without a
29
64
  * `result.toolOutput` object at all.
30
65
  * - `MISSING_META_GGUI_BOOTSTRAP` — `result.toolOutput` exists but
31
- * `_meta.ggui.bootstrap` is absent. The on-wire synonym is
32
- * `BOOTSTRAP_META_MISSING`.
33
- * - `MALFORMED_BOOTSTRAP` — `_meta.ggui.bootstrap` is present but
34
- * missing one of the four required string fields (`wsUrl`,
35
- * `token`, `sessionId`, `appId`) — i.e. it doesn't satisfy
36
- * `GguiBootstrapMeta`.
37
- * - `EXPIRED_BOOTSTRAP` — `expiresAt` is set and parses to a
38
- * timestamp in the past. UX sugar; servers reject expired tokens
39
- * anyway, but we skip the round-trip when the proof is on hand.
66
+ * `_meta["ai.ggui/render"]` is absent. The on-wire synonym is
67
+ * `BOOTSTRAP_META_MISSING`. (Name retained pre-R4 for the
68
+ * observability + host-postMessage protocol; cosmetic rename is
69
+ * deferred.)
70
+ * - `MALFORMED_BOOTSTRAP` — slice is present but fails business
71
+ * rules (no live mode and no static content, mode discriminators
72
+ * mutually exclusive, structural rejection by the combiner).
73
+ * - `EXPIRED_BOOTSTRAP` — `expiresAt` parses to a timestamp in the
74
+ * past AND there's no static content to degrade to.
40
75
  */
41
- export type BootstrapParseFailureReason = 'MISSING_TOOL_OUTPUT' | 'MISSING_META_GGUI_BOOTSTRAP' | 'MALFORMED_BOOTSTRAP' | 'EXPIRED_BOOTSTRAP';
76
+ export type McpAppAiGguiMetaParseFailureReason = 'MISSING_TOOL_OUTPUT' | 'MISSING_META_GGUI_BOOTSTRAP' | 'MALFORMED_BOOTSTRAP' | 'EXPIRED_BOOTSTRAP';
42
77
  /**
43
- * Result of a bootstrap-meta extraction attempt. Discriminated on
44
- * `ok` so call sites get exhaustive narrowing without a typed-error
45
- * class — keeps the renderer's runtime cost tiny (no class metadata
46
- * in the bundle).
78
+ * Result of a slice-meta extraction attempt. Discriminated on `ok`
79
+ * so call sites get exhaustive narrowing without a typed-error class
80
+ * — keeps the renderer's runtime cost tiny (no class metadata in the
81
+ * bundle).
47
82
  *
48
- * widening: the `ok: true` arm now also carries
49
- * an optional `hostContext: HostContextProjection`. When the bootstrap
50
- * is extracted from the `ui/initialize` response (Reading-A path), the
51
- * parser opportunistically projects the surrounding `McpUiHostContext`
52
- * into this field so the runtime can:
83
+ * The `ok: true` arm carries the validated {@link McpAppAiGguiRenderMeta}
84
+ * slice and optionally a `hostContext: HostContextProjection`. When the
85
+ * meta is extracted from the `ui/initialize` response (Reading-A path),
86
+ * the parser opportunistically projects the surrounding
87
+ * `McpUiHostContext` into this field so the runtime can:
53
88
  * - drive canvas-mode display-mode escalation
54
89
  * - echo to the server (live-channel `host_context_observed` envelope)
55
90
  * - feed the agent on next handshake/consume
56
91
  *
57
92
  * Capture is best-effort: a malformed `HostContext` never blocks the
58
- * bootstrap parse. Absent for the other extraction paths
59
- * (`__GGUI_BOOTSTRAP__` global, `ui/notifications/tool-result`) — those
93
+ * slice parse. Absent for the other extraction paths
94
+ * (`__GGUI_META__` global, `ui/notifications/tool-result`) — those
60
95
  * envelopes don't carry HostContext.
61
96
  */
62
- export type BootstrapParseResult = {
97
+ export type McpAppAiGguiMetaParseResult = {
63
98
  readonly ok: true;
64
- readonly bootstrap: GguiBootstrapMeta;
99
+ readonly meta: McpAppAiGguiRenderMeta;
65
100
  readonly hostContext?: HostContextProjection;
66
101
  } | {
67
102
  readonly ok: false;
68
- readonly reason: BootstrapParseFailureReason;
103
+ readonly reason: McpAppAiGguiMetaParseFailureReason;
69
104
  };
105
+ export {};
package/dist/types.js CHANGED
@@ -1,3 +1,3 @@
1
1
  export {};
2
2
  // `RendererWebSocketManagerOptions` retired in B3b — the WS lifecycle
3
- // moved to `@ggui-ai/channel-client`'s `WSTransport`.
3
+ // moved to `@ggui-ai/live-channel`'s `WSTransport`.
@@ -62,8 +62,8 @@ export interface RendererValidatorContext {
62
62
  export declare function validateOutboundActionEnvelope(actionSpec: ActionSpec | undefined, envelope: ActionEnvelope): ValidationResult;
63
63
  /**
64
64
  * Validate an inbound stream-channel delivery before applying it to
65
- * stack-item state. Known reserved channels (`_ggui:*`) validate even
66
- * when the target stack item has no declared `streamSpec` — the
65
+ * render state. Known reserved channels (`_ggui:*`) validate even
66
+ * when the target render has no declared `streamSpec` — the
67
67
  * payload shape is server-owned; user channels stay permissive without
68
68
  * a contract.
69
69
  */
@@ -70,8 +70,8 @@ export function validateOutboundActionEnvelope(actionSpec, envelope) {
70
70
  }
71
71
  /**
72
72
  * Validate an inbound stream-channel delivery before applying it to
73
- * stack-item state. Known reserved channels (`_ggui:*`) validate even
74
- * when the target stack item has no declared `streamSpec` — the
73
+ * render state. Known reserved channels (`_ggui:*`) validate even
74
+ * when the target render has no declared `streamSpec` — the
75
75
  * payload shape is server-owned; user channels stay permissive without
76
76
  * a contract.
77
77
  */