@ggui-ai/iframe-runtime 0.2.0-alpha.4 → 0.4.0-rc.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/channel-transport.d.ts +20 -30
- package/dist/channel-transport.js +24 -24
- package/dist/channels/data.d.ts +5 -20
- package/dist/channels/data.js +4 -52
- package/dist/channels/index.d.ts +0 -1
- package/dist/channels/index.js +0 -1
- package/dist/channels/props-update.d.ts +9 -9
- package/dist/channels/props-update.js +9 -9
- package/dist/channels/render-frame.d.ts +5 -5
- package/dist/channels/render-frame.js +5 -5
- package/dist/compiled-validators.d.ts +2 -2
- package/dist/compiled-validators.js +1 -1
- package/dist/context-observer.d.ts +4 -4
- package/dist/context-observer.js +3 -3
- package/dist/events-polling.d.ts +7 -7
- package/dist/events-polling.js +5 -5
- package/dist/globals.d.ts +1 -1
- package/dist/host-context-emitter.d.ts +4 -4
- package/dist/host-context-emitter.js +9 -9
- package/dist/iframe-runtime.js +68 -78
- package/dist/iframe-runtime.meta.json +1 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1 -1
- package/dist/lifecycle.d.ts +3 -3
- package/dist/lifecycle.js +29 -6
- package/dist/mcp-app-iframe-host.d.ts +8 -8
- package/dist/mcp-app-iframe-host.js +4 -4
- package/dist/meta-parse.d.ts +3 -4
- package/dist/meta-parse.js +17 -44
- package/dist/observability.d.ts +14 -36
- package/dist/observability.js +2 -1
- package/dist/protocol-error.d.ts +38 -48
- package/dist/protocol-error.js +5 -23
- package/dist/provisional-renderer.js +3 -3
- package/dist/react-renderer.d.ts +16 -6
- package/dist/react-renderer.js +22 -40
- package/dist/registry-subscribe.d.ts +7 -7
- package/dist/registry-subscribe.js +28 -14
- package/dist/render-item.d.ts +22 -15
- package/dist/render-item.js +7 -14
- package/dist/runtime.d.ts +79 -105
- package/dist/runtime.js +219 -269
- package/dist/status-dom.d.ts +12 -12
- package/dist/status-dom.js +11 -11
- package/dist/system-cards/NoCredentialsCard.d.ts +1 -1
- package/dist/system-cards/NoCredentialsCard.js +1 -1
- package/dist/system-cards/ProtocolProbeCard.d.ts +13 -17
- package/dist/system-cards/ProtocolProbeCard.js +21 -25
- package/dist/system-cards/index.d.ts +5 -5
- package/dist/system-cards/index.js +5 -5
- package/dist/types.d.ts +29 -34
- package/dist/validation.d.ts +4 -5
- package/dist/validation.js +5 -6
- package/dist/wire-config.d.ts +43 -106
- package/dist/wire-config.js +29 -195
- package/package.json +14 -12
- package/dist/channels/feedback.d.ts +0 -14
- package/dist/channels/feedback.js +0 -19
|
@@ -116,10 +116,10 @@ export declare function installContextRegistry(registry: GguiContextRegistry, re
|
|
|
116
116
|
*
|
|
117
117
|
* Post-render-identity-collapse (2026-05-27): the previous
|
|
118
118
|
* `{sessionId, appId, stackItemId}` tuple collapsed to
|
|
119
|
-
* `{
|
|
119
|
+
* `{sessionId, appId}` — render is the single identity key.
|
|
120
120
|
*/
|
|
121
121
|
export interface ContextPostIdentity {
|
|
122
|
-
readonly
|
|
122
|
+
readonly sessionId: string;
|
|
123
123
|
readonly appId: string;
|
|
124
124
|
}
|
|
125
125
|
/**
|
|
@@ -174,7 +174,7 @@ export interface ContextSnapshotPoster {
|
|
|
174
174
|
* mirror.
|
|
175
175
|
*/
|
|
176
176
|
readonly postContextMirror: (params: {
|
|
177
|
-
readonly
|
|
177
|
+
readonly sessionId: string;
|
|
178
178
|
readonly appId: string;
|
|
179
179
|
readonly snapshot: Record<string, unknown>;
|
|
180
180
|
}) => void;
|
|
@@ -238,7 +238,7 @@ export declare function createContextStateHost(deps: {
|
|
|
238
238
|
readonly consoleWarn?: (...args: unknown[]) => void;
|
|
239
239
|
/** Identity bundle for the server-mirror destination. Threaded
|
|
240
240
|
* unchanged into `createSingleSlotProvider` so every slot's debounced
|
|
241
|
-
* post carries the same authoritative
|
|
241
|
+
* post carries the same authoritative render binding. */
|
|
242
242
|
readonly identity?: ContextPostIdentity;
|
|
243
243
|
}): (props: {
|
|
244
244
|
readonly slots: ReadonlyArray<ResolvedContextSlot>;
|
package/dist/context-observer.js
CHANGED
|
@@ -82,7 +82,7 @@ function specFor(slot) {
|
|
|
82
82
|
* — the existing path; agent's LLM reads these via
|
|
83
83
|
* `read_widget_context` for in-turn awareness.
|
|
84
84
|
* 2. `tools/call` for `ggui_runtime_sync_context` — the server mirror.
|
|
85
|
-
* Server stores the snapshot on the active
|
|
85
|
+
* Server stores the snapshot on the active GguiSession; chat-
|
|
86
86
|
* history rehydrate seeds `contextSlots[i].default` with the
|
|
87
87
|
* snapshotted values, restoring the user's last-known state.
|
|
88
88
|
*
|
|
@@ -95,7 +95,7 @@ function specFor(slot) {
|
|
|
95
95
|
* (`[ggui:context-slot] {slot,value}`). Empirical: claude.ai's host
|
|
96
96
|
* treats each `ui/update-model-context` post as a REPLACE of the
|
|
97
97
|
* widget's tracked context, not a per-slot merge. Server mirror
|
|
98
|
-
* matches: REPLACE-per-
|
|
98
|
+
* matches: REPLACE-per-sessionId, last-write-wins. Both destinations
|
|
99
99
|
* therefore stay structurally consistent.
|
|
100
100
|
*
|
|
101
101
|
* Server-mirror skipped when `identity` is undefined — dev/test code
|
|
@@ -117,7 +117,7 @@ function postContextSnapshot(poster, snapshot, identity) {
|
|
|
117
117
|
// (dev / test paths without a real bootstrap).
|
|
118
118
|
if (identity) {
|
|
119
119
|
poster.postContextMirror({
|
|
120
|
-
|
|
120
|
+
sessionId: identity.sessionId,
|
|
121
121
|
appId: identity.appId,
|
|
122
122
|
snapshot,
|
|
123
123
|
});
|
package/dist/events-polling.d.ts
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
* Registry-level events-polling composition for the iframe-runtime (R7).
|
|
3
3
|
*
|
|
4
4
|
* The R7 cursor-replay model — paired transport of the
|
|
5
|
-
* `/api/
|
|
5
|
+
* `/api/sessions/:sessionId/events?sinceSequence=N&limit=100` HTTP endpoint
|
|
6
6
|
* + the WS subscribe `sinceSequence` cursor. Both transports replay
|
|
7
|
-
* from the same
|
|
7
|
+
* from the same GguiSessionEvent ledger; the polling client uses HTTP, the
|
|
8
8
|
* live client uses WS, and they SHARE the cursor model. Switching
|
|
9
9
|
* transports does not lose events.
|
|
10
10
|
*
|
|
11
11
|
* Semantics (vs. R6 snapshot-polling):
|
|
12
|
-
* - **URL** — `/api/
|
|
12
|
+
* - **URL** — `/api/sessions/<sessionId>/events?wsToken=<token>` with
|
|
13
13
|
* `sinceSequence` and `limit` added per tick.
|
|
14
14
|
* - **Interval** — fixed 2000ms (mirrors R6's default).
|
|
15
15
|
* - **parseSnapshot** — reads the `EventsResponse` envelope, dispatches
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* Iframes mounted inside the Anthropic SDK lose `__GGUI_META__` because
|
|
28
28
|
* the SDK strips `_meta` from `tools/call` responses before forwarding
|
|
29
29
|
* the structured-content shell to the iframe. R5's documented gap was
|
|
30
|
-
* that the first
|
|
30
|
+
* that the first render's payload never reached the iframe.
|
|
31
31
|
*
|
|
32
32
|
* R7's principled fix: the same /events endpoint that powers polling
|
|
33
33
|
* ALSO serves the cold-mount path. An iframe booting without inline
|
|
@@ -43,7 +43,7 @@ export interface BuildEventsPollingOptions {
|
|
|
43
43
|
/**
|
|
44
44
|
* Base URL the polling tick reads from. The composer appends
|
|
45
45
|
* `&sinceSequence=<cursor>&limit=<limit>` per tick. Typically the
|
|
46
|
-
* `/api/
|
|
46
|
+
* `/api/sessions/<sessionId>/events?wsToken=<token>` URL the iframe
|
|
47
47
|
* derived from the render slice. Must already include a `?` or `&`
|
|
48
48
|
* separator-ready terminator; we add the cursor params with
|
|
49
49
|
* `&` if the URL contains `?`, else `?`.
|
|
@@ -70,8 +70,8 @@ export interface BuildEventsPollingOptions {
|
|
|
70
70
|
}
|
|
71
71
|
/**
|
|
72
72
|
* Build a {@link RegistryPollingOptions} descriptor that reads
|
|
73
|
-
* `/api/
|
|
74
|
-
* each `
|
|
73
|
+
* `/api/sessions/:sessionId/events?sinceSequence=N&limit=M` and dispatches
|
|
74
|
+
* each `GguiSessionEvent` by `event.type` to the registry's matching
|
|
75
75
|
* channel handler. Cursor advances per-tick to the server's
|
|
76
76
|
* `lastSequence`.
|
|
77
77
|
*
|
package/dist/events-polling.js
CHANGED
|
@@ -27,9 +27,9 @@ function isEventsResponse(body) {
|
|
|
27
27
|
return true;
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
|
-
* Type guard for one
|
|
30
|
+
* Type guard for one GguiSessionEvent in the events array.
|
|
31
31
|
*/
|
|
32
|
-
function
|
|
32
|
+
function isGguiSessionEvent(value) {
|
|
33
33
|
if (value === null || typeof value !== 'object')
|
|
34
34
|
return false;
|
|
35
35
|
const obj = value;
|
|
@@ -45,8 +45,8 @@ function isRenderEvent(value) {
|
|
|
45
45
|
}
|
|
46
46
|
/**
|
|
47
47
|
* Build a {@link RegistryPollingOptions} descriptor that reads
|
|
48
|
-
* `/api/
|
|
49
|
-
* each `
|
|
48
|
+
* `/api/sessions/:sessionId/events?sinceSequence=N&limit=M` and dispatches
|
|
49
|
+
* each `GguiSessionEvent` by `event.type` to the registry's matching
|
|
50
50
|
* channel handler. Cursor advances per-tick to the server's
|
|
51
51
|
* `lastSequence`.
|
|
52
52
|
*
|
|
@@ -129,7 +129,7 @@ export function buildEventsPolling(opts) {
|
|
|
129
129
|
// the dispatch shape to a list per type.
|
|
130
130
|
const frames = {};
|
|
131
131
|
for (const event of body.events) {
|
|
132
|
-
if (!
|
|
132
|
+
if (!isGguiSessionEvent(event))
|
|
133
133
|
continue;
|
|
134
134
|
frames[event.type] = {
|
|
135
135
|
type: event.type,
|
package/dist/globals.d.ts
CHANGED
|
@@ -146,7 +146,7 @@ export interface GguiGlobalRegistry {
|
|
|
146
146
|
* in `<CurrentStepContext.Provider value={…}>` and the runtime
|
|
147
147
|
* observer reads values back via `useContext`.
|
|
148
148
|
*
|
|
149
|
-
* Mutable across re-mounts: on a second `
|
|
149
|
+
* Mutable across re-mounts: on a re-mount (a second `applyRender`),
|
|
150
150
|
* the registry is REUSED (entries are keyed by contextName and
|
|
151
151
|
* skipped on re-create) so the LLM's destructured Context
|
|
152
152
|
* references stay live across re-mounts. Only NEW context names
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* `ui/notifications/host-context-changed` postMessage from the host.
|
|
10
10
|
* 2. Echo each fresh value as a `type: 'host_context_observed'`
|
|
11
11
|
* WebSocket envelope so the server can persist it on
|
|
12
|
-
* `
|
|
12
|
+
* `GguiSessionRecord.hostContext` for agent visibility.
|
|
13
13
|
* 3. Suppress no-op re-emissions (via deep-equality on the projection
|
|
14
14
|
* shape) — avoids server-side write traffic when a notification
|
|
15
15
|
* arrives but no projection-visible field actually changed (e.g.,
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
*
|
|
27
27
|
* Lifecycle:
|
|
28
28
|
*
|
|
29
|
-
* - Initial seed: `seed(projection,
|
|
29
|
+
* - Initial seed: `seed(projection, sessionId)` called from
|
|
30
30
|
* `bootProduction` right after the WS transport is attached and we
|
|
31
31
|
* know the initial projection from `projectHostContext(app.getHostContext())`.
|
|
32
32
|
* {@link applyHostContextStyling} fires separately from
|
|
@@ -76,12 +76,12 @@ export type HostContextSendFn = (msg: {
|
|
|
76
76
|
* the same projection) suppresses the duplicate emission via the
|
|
77
77
|
* equality check.
|
|
78
78
|
*
|
|
79
|
-
* Re-seeding with a DIFFERENT `
|
|
79
|
+
* Re-seeding with a DIFFERENT `sessionId` is undefined behavior; the
|
|
80
80
|
* iframe-runtime is one-render-per-mount by construction. Tests
|
|
81
81
|
* exercising multi-render flows MUST call `detach()` between seeds.
|
|
82
82
|
*/
|
|
83
83
|
export declare function seed(args: {
|
|
84
|
-
readonly
|
|
84
|
+
readonly sessionId: string;
|
|
85
85
|
readonly send: HostContextSendFn;
|
|
86
86
|
readonly initial: HostContextProjection;
|
|
87
87
|
}): void;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* `ui/notifications/host-context-changed` postMessage from the host.
|
|
10
10
|
* 2. Echo each fresh value as a `type: 'host_context_observed'`
|
|
11
11
|
* WebSocket envelope so the server can persist it on
|
|
12
|
-
* `
|
|
12
|
+
* `GguiSessionRecord.hostContext` for agent visibility.
|
|
13
13
|
* 3. Suppress no-op re-emissions (via deep-equality on the projection
|
|
14
14
|
* shape) — avoids server-side write traffic when a notification
|
|
15
15
|
* arrives but no projection-visible field actually changed (e.g.,
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
*
|
|
27
27
|
* Lifecycle:
|
|
28
28
|
*
|
|
29
|
-
* - Initial seed: `seed(projection,
|
|
29
|
+
* - Initial seed: `seed(projection, sessionId)` called from
|
|
30
30
|
* `bootProduction` right after the WS transport is attached and we
|
|
31
31
|
* know the initial projection from `projectHostContext(app.getHostContext())`.
|
|
32
32
|
* {@link applyHostContextStyling} fires separately from
|
|
@@ -64,7 +64,7 @@ let state = null;
|
|
|
64
64
|
* the same projection) suppresses the duplicate emission via the
|
|
65
65
|
* equality check.
|
|
66
66
|
*
|
|
67
|
-
* Re-seeding with a DIFFERENT `
|
|
67
|
+
* Re-seeding with a DIFFERENT `sessionId` is undefined behavior; the
|
|
68
68
|
* iframe-runtime is one-render-per-mount by construction. Tests
|
|
69
69
|
* exercising multi-render flows MUST call `detach()` between seeds.
|
|
70
70
|
*/
|
|
@@ -72,7 +72,7 @@ export function seed(args) {
|
|
|
72
72
|
// First seed — record state + emit initial.
|
|
73
73
|
if (state === null) {
|
|
74
74
|
state = {
|
|
75
|
-
|
|
75
|
+
sessionId: args.sessionId,
|
|
76
76
|
send: args.send,
|
|
77
77
|
current: args.initial,
|
|
78
78
|
listener: null,
|
|
@@ -167,7 +167,7 @@ export function _peekCurrent() {
|
|
|
167
167
|
}
|
|
168
168
|
/**
|
|
169
169
|
* Subscribe to local projection updates so
|
|
170
|
-
* iframe-side consumers (
|
|
170
|
+
* iframe-side consumers (e.g. display-mode state on the mount handle)
|
|
171
171
|
* can react to `host-context-changed` notifications without re-
|
|
172
172
|
* parsing the postMessage envelope themselves.
|
|
173
173
|
*
|
|
@@ -178,7 +178,7 @@ export function _peekCurrent() {
|
|
|
178
178
|
* `state.current` (post-projection, post-equality-check).
|
|
179
179
|
*
|
|
180
180
|
* Returns an unsubscribe function. Multi-subscriber by design —
|
|
181
|
-
* tests + production
|
|
181
|
+
* tests + the production mount can coexist.
|
|
182
182
|
*/
|
|
183
183
|
const localSubscribers = new Set();
|
|
184
184
|
export function subscribeLocal(listener) {
|
|
@@ -316,7 +316,7 @@ function emit() {
|
|
|
316
316
|
state.send({
|
|
317
317
|
type: 'host_context_observed',
|
|
318
318
|
payload: {
|
|
319
|
-
|
|
319
|
+
sessionId: state.sessionId,
|
|
320
320
|
hostContext: state.current,
|
|
321
321
|
},
|
|
322
322
|
});
|
|
@@ -328,8 +328,8 @@ function emit() {
|
|
|
328
328
|
// eventually-consistent, not transactional.
|
|
329
329
|
}
|
|
330
330
|
// Fan out to local iframe-side subscribers
|
|
331
|
-
// (
|
|
332
|
-
// WS-send try/catch above — a send failure must not skip the
|
|
331
|
+
// (e.g. display-mode state on the mount handle). Independent from
|
|
332
|
+
// the WS-send try/catch above — a send failure must not skip the
|
|
333
333
|
// local fan-out, and a subscriber throwing must not skip other
|
|
334
334
|
// subscribers.
|
|
335
335
|
for (const listener of localSubscribers) {
|