@ggui-ai/iframe-runtime 0.13.0 → 0.15.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 +1 -1
- package/dist/channels/channel-payload.d.ts +1 -1
- package/dist/channels/data.d.ts +1 -1
- package/dist/channels/drain-ack.d.ts +1 -1
- package/dist/channels/props-update.d.ts +1 -1
- package/dist/channels/render-frame.d.ts +1 -1
- package/dist/compiled-validators.d.ts +1 -1
- package/dist/connection.d.ts +20 -0
- package/dist/connection.js +20 -0
- package/dist/context-observer.d.ts +1 -1
- package/dist/context-observer.js +1 -1
- package/dist/events-polling.d.ts +1 -1
- package/dist/host-context-emitter.d.ts +1 -1
- package/dist/host-context-emitter.js +1 -1
- package/dist/iframe-runtime.js +87 -85
- package/dist/iframe-runtime.meta.json +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/meta-parse.js +1 -1
- package/dist/observability.d.ts +149 -17
- package/dist/observability.js +59 -0
- package/dist/provisional-renderer.d.ts +1 -1
- package/dist/react-renderer.d.ts +2 -5
- package/dist/react-renderer.js +20 -4
- package/dist/registry-subscribe.d.ts +1 -1
- package/dist/render-item.d.ts +2 -6
- package/dist/runtime-telemetry.js +1 -1
- package/dist/runtime.d.ts +44 -17
- package/dist/runtime.js +339 -82
- package/dist/types.d.ts +1 -1
- package/dist/validation.d.ts +1 -1
- package/dist/validation.js +1 -1
- package/dist/wire-config.d.ts +1 -1
- package/dist/wire-config.js +9 -3
- package/package.json +15 -10
package/dist/index.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ export { parseMetaFromGlobal, parseMetaFromToolResult, validateMeta, } from './m
|
|
|
37
37
|
export type { RendererBootFailureReason, RendererBootFailedMessage, } from './runtime.js';
|
|
38
38
|
export type { ProtocolError, ProtocolErrorEmitter, BootstrapFailureReason, } from './protocol-error.js';
|
|
39
39
|
export { defaultProtocolErrorEmitter, fromBootstrapFailure, fromClientContractViolation, fromTransportFailure, fromAuthFailure, fromUpgradeRequired, fromUnknown, } from './protocol-error.js';
|
|
40
|
-
export type { ObservabilityEvent, ObservabilityEmitter, ObservabilityMessage, SchemaVersionMismatchEvent, SubscribeFailedEvent, ChannelTransportPickedEvent, ChannelTransportFallbackEvent, ChannelTransportResubscribedEvent, ChannelPollDegradedEvent, ChannelPollRecoveredEvent, UiFeedbackEvent, RelayIncapabilityEvent, UnknownObservabilityEvent, } from './observability.js';
|
|
41
|
-
export { postObservabilityToParent } from './observability.js';
|
|
40
|
+
export type { ObservabilityEvent, ObservabilityEmitter, ObservabilityMessage, SchemaVersionMismatchEvent, SubscribeFailedEvent, ChannelTransportPickedEvent, ChannelTransportFallbackEvent, ChannelTransportResubscribedEvent, ChannelPollDegradedEvent, ChannelPollRecoveredEvent, UiFeedbackEvent, RelayDeadTapEvent, RelayIncapabilityEvent, RelayLatchTrigger, UnknownObservabilityEvent, } from './observability.js';
|
|
41
|
+
export { isObservabilityMessage, isRelayDeadTapEvent, isRelayIncapabilityEvent, postObservabilityToParent, } from './observability.js';
|
|
42
42
|
export type { LifecycleEmitter } from './lifecycle.js';
|
|
43
43
|
export { postLifecycleToParent, makeLifecycleEvent } from './lifecycle.js';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { parseMetaFromGlobal, parseMetaFromToolResult, validateMeta, } from './meta-parse.js';
|
|
2
2
|
export { defaultProtocolErrorEmitter, fromBootstrapFailure, fromClientContractViolation, fromTransportFailure, fromAuthFailure, fromUpgradeRequired, fromUnknown, } from './protocol-error.js';
|
|
3
|
-
export { postObservabilityToParent } from './observability.js';
|
|
3
|
+
export { isObservabilityMessage, isRelayDeadTapEvent, isRelayIncapabilityEvent, postObservabilityToParent, } from './observability.js';
|
|
4
4
|
export { postLifecycleToParent, makeLifecycleEvent } from './lifecycle.js';
|
package/dist/meta-parse.js
CHANGED
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
* At least one mode MUST be present. Half-live (wsUrl without wsToken)
|
|
51
51
|
* is structurally rejected by the combiner.
|
|
52
52
|
*/
|
|
53
|
-
import { PUBLIC_ENV_APP_KEY_RE } from '@ggui-ai/protocol';
|
|
53
|
+
import { PUBLIC_ENV_APP_KEY_RE } from '@ggui-ai/protocol/wire';
|
|
54
54
|
import { parseMcpAppAiGguiRenderMeta } from '@ggui-ai/protocol/integrations/mcp-apps';
|
|
55
55
|
/**
|
|
56
56
|
* Type guard — true iff `value` is a non-null, non-array plain object.
|
package/dist/observability.d.ts
CHANGED
|
@@ -33,7 +33,7 @@ import { MCP_APP_OBSERVE_TYPE } from '@ggui-ai/protocol/integrations/mcp-apps';
|
|
|
33
33
|
*
|
|
34
34
|
* @public
|
|
35
35
|
*/
|
|
36
|
-
export type ObservabilityEvent = SchemaVersionMismatchEvent | SubscribeFailedEvent | ChannelTransportPickedEvent | ChannelTransportFallbackEvent | ChannelTransportResubscribedEvent | ChannelPollDegradedEvent | ChannelPollRecoveredEvent | UiFeedbackEvent | RelayIncapabilityEvent | UnknownObservabilityEvent;
|
|
36
|
+
export type ObservabilityEvent = SchemaVersionMismatchEvent | SubscribeFailedEvent | ChannelTransportPickedEvent | ChannelTransportFallbackEvent | ChannelTransportResubscribedEvent | ChannelPollDegradedEvent | ChannelPollRecoveredEvent | UiFeedbackEvent | RelayIncapabilityEvent | RelayDeadTapEvent | UnknownObservabilityEvent;
|
|
37
37
|
/**
|
|
38
38
|
* Fired when the protocol-version handshake rejects the connection.
|
|
39
39
|
* Parallel to `UpgradeRequiredError` — the host can choose to render
|
|
@@ -178,36 +178,122 @@ export interface UiFeedbackEvent {
|
|
|
178
178
|
/** Tool that produced the render (e.g. `ggui_render`). */
|
|
179
179
|
readonly toolName?: string;
|
|
180
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* The evidence that latched a relay dead zone:
|
|
183
|
+
* - `'confirmed-refusal'` — the relay answered a declared refusal code
|
|
184
|
+
* (helper-minted; outranks any positive advertisement) (ggui#599
|
|
185
|
+
* cycle-2);
|
|
186
|
+
* - `'advert-silent'` — the host never advertised `serverTools` and
|
|
187
|
+
* the attempt failed relay-shaped;
|
|
188
|
+
* - `'boot-failed'` — the mandatory `ui/initialize` handshake did not
|
|
189
|
+
* complete (refused, timed out, or the transport failed), so
|
|
190
|
+
* nothing can ever be delivered in this document (ggui#830). Not a
|
|
191
|
+
* probe the runtime minted: the outcome of the one request every
|
|
192
|
+
* session begins with — the strongest confirmed outcome there is.
|
|
193
|
+
* It clears the only way a handshake failure can: the next boot's
|
|
194
|
+
* close edge.
|
|
195
|
+
*
|
|
196
|
+
* The union is closed per renderer version; nothing in a host branches
|
|
197
|
+
* on the trigger (the first-party host passes it through untouched) —
|
|
198
|
+
* the edge is the fact, the trigger is why. A host that does branch on
|
|
199
|
+
* it should treat a value it does not know as "latched, reason
|
|
200
|
+
* unknown", never as "not latched".
|
|
201
|
+
*
|
|
202
|
+
* @public
|
|
203
|
+
*/
|
|
204
|
+
export type RelayLatchTrigger = 'confirmed-refusal' | 'advert-silent' | 'boot-failed';
|
|
181
205
|
/**
|
|
182
206
|
* Fired at the two transition edges of the renderer's
|
|
183
207
|
* relay-incapability latch — the runtime's confirmed determination
|
|
184
208
|
* that the host cannot relay `tools/call` to the MCP server:
|
|
185
209
|
*
|
|
186
|
-
* - `'latched'` — a real user gesture just failed relay-shaped
|
|
187
|
-
*
|
|
188
|
-
*
|
|
210
|
+
* - `'latched'` — a real user gesture just failed relay-shaped on a
|
|
211
|
+
* host whose captured capability handshake never advertised
|
|
212
|
+
* `serverTools`, or the relay answered a declared refusal code, or
|
|
213
|
+
* the host refused `ui/initialize` itself (`'boot-failed'`,
|
|
214
|
+
* ggui#830 — no gesture is needed to know nothing can be delivered).
|
|
189
215
|
* The runtime now treats relay as confirmed-unavailable: it shows
|
|
190
|
-
* one persistent explanation
|
|
191
|
-
* and channel polls fail fast without a transport
|
|
216
|
+
* one persistent explanation, arms the dead-zone cue for every
|
|
217
|
+
* later gesture, and channel polls fail fast without a transport
|
|
218
|
+
* round-trip.
|
|
192
219
|
* - `'cleared'` — a later well-formed result envelope arrived
|
|
193
220
|
* (`ok:true` and `ok:false` alike — either proves the host relayed
|
|
194
|
-
* the call there and back), so the determination no longer holds
|
|
195
|
-
*
|
|
221
|
+
* the call there and back), so the determination no longer holds.
|
|
222
|
+
* Carries the dead zone's summary: how long it stood and how many
|
|
223
|
+
* gestures were attempted inside it.
|
|
196
224
|
*
|
|
197
|
-
* Emitted once per edge, never per channel poll tick
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
225
|
+
* Emitted once per edge, never per channel poll tick. Gestures
|
|
226
|
+
* attempted while latched are NOT silent on this stream: each one is a
|
|
227
|
+
* {@link RelayDeadTapEvent} (ggui#670 Phase 3) — one per real user
|
|
228
|
+
* gesture, never per tick — so a host can count dead taps and measure
|
|
229
|
+
* dead-tap-to-recovery without watching the render. A boot that finds
|
|
230
|
+
* a latch standing from a prior mount closes it with a `'cleared'`
|
|
231
|
+
* edge before the new session starts.
|
|
201
232
|
*
|
|
202
|
-
* Always emitted via the postMessage-to-parent default — the
|
|
203
|
-
*
|
|
204
|
-
* graph
|
|
233
|
+
* Always emitted via the postMessage-to-parent default, by rule — the
|
|
234
|
+
* gesture-dispatch emission sites run outside any given boot call, and
|
|
235
|
+
* the boot-graph site (the `boot-failed` edge, ggui#830) follows the
|
|
236
|
+
* same rule — so these edges never flow through an injected
|
|
237
|
+
* `onObserve` sink and a host reads every edge the same way.
|
|
205
238
|
*
|
|
206
239
|
* @public
|
|
207
240
|
*/
|
|
208
|
-
export
|
|
241
|
+
export type RelayIncapabilityEvent = {
|
|
242
|
+
readonly kind: 'relay-incapability';
|
|
243
|
+
readonly state: 'latched';
|
|
244
|
+
readonly trigger: RelayLatchTrigger;
|
|
245
|
+
/** GguiSession id of the render, when the latching gesture carried one. */
|
|
246
|
+
readonly sessionId?: string;
|
|
247
|
+
/** App id of the render, when the latching gesture carried one. */
|
|
248
|
+
readonly appId?: string;
|
|
249
|
+
} | {
|
|
209
250
|
readonly kind: 'relay-incapability';
|
|
210
|
-
readonly state: '
|
|
251
|
+
readonly state: 'cleared';
|
|
252
|
+
/** How long the dead zone stood, in milliseconds. */
|
|
253
|
+
readonly latchedForMs: number;
|
|
254
|
+
/**
|
|
255
|
+
* Gestures attempted inside the zone — equals the last
|
|
256
|
+
* {@link RelayDeadTapEvent} `ordinal` this edge closes (0 when
|
|
257
|
+
* none was attempted).
|
|
258
|
+
*/
|
|
259
|
+
readonly deadTaps: number;
|
|
260
|
+
readonly sessionId?: string;
|
|
261
|
+
readonly appId?: string;
|
|
262
|
+
};
|
|
263
|
+
/**
|
|
264
|
+
* A user gesture attempted while the relay-incapability latch stands
|
|
265
|
+
* (ggui#670 Phase 3). The runtime never suppresses the attempt — the
|
|
266
|
+
* attempt is the self-heal sensor (ggui#443) — and presents it in the
|
|
267
|
+
* document (pulse, spoken cue, fallback toast); this event makes the
|
|
268
|
+
* attempt COUNTABLE by the host.
|
|
269
|
+
*
|
|
270
|
+
* Contract: exactly one per gesture whose UNDELIVERED outcome
|
|
271
|
+
* (relay-shaped failure or a declared refusal) lands while the latch
|
|
272
|
+
* stands — an in-flight gesture that raced the latching one counts;
|
|
273
|
+
* never emitted off-latch, and never from the channel
|
|
274
|
+
* router's fail-fast ticks. Counted at the outcome, not the tap: the
|
|
275
|
+
* gesture that latched the zone is the `'latched'` edge and the gesture
|
|
276
|
+
* that heals it is the `'cleared'` edge — neither is a dead tap.
|
|
277
|
+
* `ordinal` counts from 1 within one dead zone; the `'cleared'` edge
|
|
278
|
+
* reports the total as `deadTaps`. `latchAgeMs` is measured when the
|
|
279
|
+
* outcome lands. Hosts MUST tolerate the event being absent (an older
|
|
280
|
+
* renderer) — absence means no attempt was observed, not that none
|
|
281
|
+
* happened.
|
|
282
|
+
*
|
|
283
|
+
* @public
|
|
284
|
+
*/
|
|
285
|
+
export interface RelayDeadTapEvent {
|
|
286
|
+
readonly kind: 'relay-dead-tap';
|
|
287
|
+
/** The gesture's intent — the action name the component dispatched. */
|
|
288
|
+
readonly intent: string;
|
|
289
|
+
/** Milliseconds since the latch set. */
|
|
290
|
+
readonly latchAgeMs: number;
|
|
291
|
+
/** 1-based position of this attempt within the current dead zone. */
|
|
292
|
+
readonly ordinal: number;
|
|
293
|
+
/** The evidence that latched the zone this attempt landed in. */
|
|
294
|
+
readonly trigger: RelayLatchTrigger;
|
|
295
|
+
readonly sessionId?: string;
|
|
296
|
+
readonly appId?: string;
|
|
211
297
|
}
|
|
212
298
|
/**
|
|
213
299
|
* Catch-all branch for event kinds the host's typings don't recognize.
|
|
@@ -245,6 +331,52 @@ export interface ObservabilityMessage {
|
|
|
245
331
|
* @public
|
|
246
332
|
*/
|
|
247
333
|
export type ObservabilityEmitter = (event: ObservabilityEvent) => void;
|
|
334
|
+
/**
|
|
335
|
+
* Type guard for the `ggui:observe` envelope as it arrives on a host's
|
|
336
|
+
* `message` listener — narrows `event.data` to {@link ObservabilityMessage}.
|
|
337
|
+
* Read fields through the per-kind guards, never through
|
|
338
|
+
* `switch (event.kind)`: the union's open tail (`kind: string & {}`)
|
|
339
|
+
* keeps TypeScript from using `kind` as a discriminant, so a `case`
|
|
340
|
+
* body sees the whole union. Unknown kinds stay in that tail: hosts
|
|
341
|
+
* MUST ignore them, never throw.
|
|
342
|
+
*
|
|
343
|
+
* @example
|
|
344
|
+
* ```ts
|
|
345
|
+
* import {
|
|
346
|
+
* isObservabilityMessage,
|
|
347
|
+
* isRelayDeadTapEvent,
|
|
348
|
+
* isRelayIncapabilityEvent,
|
|
349
|
+
* } from '@ggui-ai/iframe-runtime/observability';
|
|
350
|
+
*
|
|
351
|
+
* window.addEventListener('message', ({ data, source }) => {
|
|
352
|
+
* if (source !== iframe.contentWindow || !isObservabilityMessage(data)) return;
|
|
353
|
+
* const { event } = data;
|
|
354
|
+
* if (isRelayDeadTapEvent(event)) count(event.intent, event.latchAgeMs);
|
|
355
|
+
* else if (isRelayIncapabilityEvent(event) && event.state === 'cleared') recovered(event.deadTaps);
|
|
356
|
+
* // any other kind: ignore
|
|
357
|
+
* });
|
|
358
|
+
* ```
|
|
359
|
+
*
|
|
360
|
+
* @public
|
|
361
|
+
*/
|
|
362
|
+
export declare function isObservabilityMessage(value: unknown): value is ObservabilityMessage;
|
|
363
|
+
/**
|
|
364
|
+
* Narrows to {@link RelayDeadTapEvent}. The union's open tail
|
|
365
|
+
* (`kind: string & {}`) keeps TypeScript from using `kind` as a
|
|
366
|
+
* discriminant, so `switch (event.kind)` never narrows across
|
|
367
|
+
* {@link ObservabilityEvent} — hosts read fields through the per-kind
|
|
368
|
+
* guards (first-consumer finding, ggui#670 Phase 3).
|
|
369
|
+
*
|
|
370
|
+
* @public
|
|
371
|
+
*/
|
|
372
|
+
export declare function isRelayDeadTapEvent(event: ObservabilityEvent): event is RelayDeadTapEvent;
|
|
373
|
+
/**
|
|
374
|
+
* Narrows to {@link RelayIncapabilityEvent}; inside it `state`
|
|
375
|
+
* discriminates the `'latched'` / `'cleared'` edges normally.
|
|
376
|
+
*
|
|
377
|
+
* @public
|
|
378
|
+
*/
|
|
379
|
+
export declare function isRelayIncapabilityEvent(event: ObservabilityEvent): event is RelayIncapabilityEvent;
|
|
248
380
|
/**
|
|
249
381
|
* Default emitter — posts an {@link ObservabilityMessage} to
|
|
250
382
|
* `window.parent`. Mirrors `postBootFailure` / `postRendererReady`
|
package/dist/observability.js
CHANGED
|
@@ -1,4 +1,63 @@
|
|
|
1
1
|
import { MCP_APP_OBSERVE_TYPE } from '@ggui-ai/protocol/integrations/mcp-apps';
|
|
2
|
+
/**
|
|
3
|
+
* Type guard for the `ggui:observe` envelope as it arrives on a host's
|
|
4
|
+
* `message` listener — narrows `event.data` to {@link ObservabilityMessage}.
|
|
5
|
+
* Read fields through the per-kind guards, never through
|
|
6
|
+
* `switch (event.kind)`: the union's open tail (`kind: string & {}`)
|
|
7
|
+
* keeps TypeScript from using `kind` as a discriminant, so a `case`
|
|
8
|
+
* body sees the whole union. Unknown kinds stay in that tail: hosts
|
|
9
|
+
* MUST ignore them, never throw.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import {
|
|
14
|
+
* isObservabilityMessage,
|
|
15
|
+
* isRelayDeadTapEvent,
|
|
16
|
+
* isRelayIncapabilityEvent,
|
|
17
|
+
* } from '@ggui-ai/iframe-runtime/observability';
|
|
18
|
+
*
|
|
19
|
+
* window.addEventListener('message', ({ data, source }) => {
|
|
20
|
+
* if (source !== iframe.contentWindow || !isObservabilityMessage(data)) return;
|
|
21
|
+
* const { event } = data;
|
|
22
|
+
* if (isRelayDeadTapEvent(event)) count(event.intent, event.latchAgeMs);
|
|
23
|
+
* else if (isRelayIncapabilityEvent(event) && event.state === 'cleared') recovered(event.deadTaps);
|
|
24
|
+
* // any other kind: ignore
|
|
25
|
+
* });
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
30
|
+
export function isObservabilityMessage(value) {
|
|
31
|
+
if (typeof value !== 'object' || value === null)
|
|
32
|
+
return false;
|
|
33
|
+
const probe = value;
|
|
34
|
+
if (probe.type !== MCP_APP_OBSERVE_TYPE)
|
|
35
|
+
return false;
|
|
36
|
+
if (typeof probe.event !== 'object' || probe.event === null)
|
|
37
|
+
return false;
|
|
38
|
+
return typeof probe.event.kind === 'string';
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Narrows to {@link RelayDeadTapEvent}. The union's open tail
|
|
42
|
+
* (`kind: string & {}`) keeps TypeScript from using `kind` as a
|
|
43
|
+
* discriminant, so `switch (event.kind)` never narrows across
|
|
44
|
+
* {@link ObservabilityEvent} — hosts read fields through the per-kind
|
|
45
|
+
* guards (first-consumer finding, ggui#670 Phase 3).
|
|
46
|
+
*
|
|
47
|
+
* @public
|
|
48
|
+
*/
|
|
49
|
+
export function isRelayDeadTapEvent(event) {
|
|
50
|
+
return event.kind === 'relay-dead-tap';
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Narrows to {@link RelayIncapabilityEvent}; inside it `state`
|
|
54
|
+
* discriminates the `'latched'` / `'cleared'` edges normally.
|
|
55
|
+
*
|
|
56
|
+
* @public
|
|
57
|
+
*/
|
|
58
|
+
export function isRelayIncapabilityEvent(event) {
|
|
59
|
+
return event.kind === 'relay-incapability';
|
|
60
|
+
}
|
|
2
61
|
/**
|
|
3
62
|
* Default emitter — posts an {@link ObservabilityMessage} to
|
|
4
63
|
* `window.parent`. Mirrors `postBootFailure` / `postRendererReady`
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
* while suspended, matching host-SDK behavior.
|
|
32
32
|
*/
|
|
33
33
|
import React, { type ReactNode } from 'react';
|
|
34
|
-
import type { StreamEnvelope } from '@ggui-ai/protocol';
|
|
34
|
+
import type { StreamEnvelope } from '@ggui-ai/protocol/wire';
|
|
35
35
|
export interface ProvisionalMount {
|
|
36
36
|
/**
|
|
37
37
|
* Feed a stream envelope. Ignores non-PREVIEW_CHANNEL envelopes
|
package/dist/react-renderer.d.ts
CHANGED
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
* TypeScript config doesn't need a JSX runtime plumbing.
|
|
31
31
|
*/
|
|
32
32
|
import React, { type ReactNode } from 'react';
|
|
33
|
+
import type { AppTheme } from '@ggui-ai/protocol/wire';
|
|
33
34
|
export interface ReactRootMountOptions {
|
|
34
35
|
/**
|
|
35
36
|
* GguiSession whose componentCode + props drive the mount. Only
|
|
@@ -98,11 +99,7 @@ export interface ReactRootMountOptions {
|
|
|
98
99
|
* painted ladder to its registration record); the renderer
|
|
99
100
|
* carries it but exposes no observability surface for it today.
|
|
100
101
|
*/
|
|
101
|
-
readonly base?:
|
|
102
|
-
readonly documentHash: string;
|
|
103
|
-
readonly light: Readonly<Record<string, string>>;
|
|
104
|
-
readonly dark: Readonly<Record<string, string>>;
|
|
105
|
-
};
|
|
102
|
+
readonly base?: NonNullable<AppTheme['base']>;
|
|
106
103
|
};
|
|
107
104
|
/**
|
|
108
105
|
* Host-announced palette, already translated onto `--ggui-*` tokens
|
package/dist/react-renderer.js
CHANGED
|
@@ -329,7 +329,15 @@ export async function mountReactRoot(container, opts) {
|
|
|
329
329
|
// ladder gets — base inherits, derived gradient/effect tokens
|
|
330
330
|
// (color-mix fallback split), box-sizing, font-inherit — from
|
|
331
331
|
// ONE shared builder, so the two paths cannot drift.
|
|
332
|
-
assembleDeliveredThemeCss(scopeClass, opts.themeMode === 'dark' ? deliveredBase.dark : deliveredBase.light
|
|
332
|
+
assembleDeliveredThemeCss(scopeClass, opts.themeMode === 'dark' ? deliveredBase.dark : deliveredBase.light, {
|
|
333
|
+
// ggui#613 residual 2 — the two former v1 deltas ride:
|
|
334
|
+
// the active mode's keyframes block + the frameless
|
|
335
|
+
// silhouette suppression, both same-rule as compiled.
|
|
336
|
+
keyframes: opts.themeMode === 'dark'
|
|
337
|
+
? deliveredBase.keyframes?.dark
|
|
338
|
+
: deliveredBase.keyframes?.light,
|
|
339
|
+
frameless: deliveredBase.frameless,
|
|
340
|
+
})
|
|
333
341
|
: opts.themeId
|
|
334
342
|
? getScopedThemeCss(opts.themeId, scopeClass, opts.themeMode)
|
|
335
343
|
: getScopedCssTokens(scopeClass, opts.themeMode);
|
|
@@ -367,9 +375,17 @@ export async function mountReactRoot(container, opts) {
|
|
|
367
375
|
// `ThemeProvider` so a Studio/Portal context with both runtime + RP
|
|
368
376
|
// active doesn't double-stack.
|
|
369
377
|
if (typeof document !== 'undefined') {
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
378
|
+
// ggui#613 residual 5: under a DELIVERED base the body-chrome
|
|
379
|
+
// ladder is the delivered set too — mirroring the scoped ternary
|
|
380
|
+
// above — so the standalone viewer's body chrome and its tree
|
|
381
|
+
// content resolve the same values. Pre-fix this started from the
|
|
382
|
+
// compiled/default ladder regardless, and body chrome painted the
|
|
383
|
+
// default brand under a registered theme.
|
|
384
|
+
let rootCss = deliveredBase !== undefined
|
|
385
|
+
? `:root{${toCssDecls(opts.themeMode === 'dark' ? deliveredBase.dark : deliveredBase.light)}}`
|
|
386
|
+
: opts.themeId
|
|
387
|
+
? getThemeCss(opts.themeId, opts.themeMode)
|
|
388
|
+
: getCssTokens(opts.themeMode);
|
|
373
389
|
if (opts.hostPalette) {
|
|
374
390
|
// BODY-CHROME ONLY, same as the appTheme `:root` append below —
|
|
375
391
|
// and beneath it, mirroring the scoped-block order (#573:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AckPayload } from '@ggui-ai/protocol';
|
|
1
|
+
import type { AckPayload } from '@ggui-ai/protocol/wire';
|
|
2
2
|
import type { ConnectionStatus } from '@ggui-ai/protocol/transport/websocket';
|
|
3
3
|
import type { McpAppAiGguiRenderMeta } from '@ggui-ai/protocol/integrations/mcp-apps';
|
|
4
4
|
import type { AnyTransportHandle, ChannelLogger, ChannelRegistry, RegistryPollingOptions, RegistrySseOptions, WsTransportHandle } from '@ggui-ai/live-channel';
|
package/dist/render-item.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
|
-
import type { GguiSession } from '@ggui-ai/protocol';
|
|
2
|
+
import type { AppTheme, GguiSession } from '@ggui-ai/protocol/wire';
|
|
3
3
|
import type { GguiSessionSeedInput } from './types.js';
|
|
4
4
|
import { type WireConfig } from '@ggui-ai/wire';
|
|
5
5
|
import type { StreamBus } from './wire-config.js';
|
|
@@ -59,11 +59,7 @@ export interface RenderItemOptions {
|
|
|
59
59
|
readonly appTheme?: {
|
|
60
60
|
readonly mode: 'light' | 'dark';
|
|
61
61
|
readonly cssVariables: Record<string, string>;
|
|
62
|
-
readonly base?:
|
|
63
|
-
readonly documentHash: string;
|
|
64
|
-
readonly light: Readonly<Record<string, string>>;
|
|
65
|
-
readonly dark: Readonly<Record<string, string>>;
|
|
66
|
-
};
|
|
62
|
+
readonly base?: NonNullable<AppTheme['base']>;
|
|
67
63
|
};
|
|
68
64
|
/**
|
|
69
65
|
* Host-announced palette, pre-mapped onto `--ggui-*` tokens by the
|
package/dist/runtime.d.ts
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* wrapper, which routes it to the host's `onError` callback.
|
|
26
26
|
*/
|
|
27
27
|
import './zod-jitless.js';
|
|
28
|
-
import type { DrainAckPayload, JsonValue, JsonObject, GguiSession } from '@ggui-ai/protocol';
|
|
28
|
+
import type { DrainAckPayload, JsonValue, JsonObject, GguiSession } from '@ggui-ai/protocol/wire';
|
|
29
29
|
import type { WebSocketMessage } from '@ggui-ai/protocol/transport/websocket';
|
|
30
30
|
import { type McpAppAiGguiRenderMeta, type McpAppBootstrapFailedMessage, type McpAppRendererReadyMessage } from '@ggui-ai/protocol/integrations/mcp-apps';
|
|
31
31
|
import type { GguiSessionSeedInput } from './types.js';
|
|
@@ -56,6 +56,15 @@ import { type LifecycleEmitter } from './lifecycle.js';
|
|
|
56
56
|
*/
|
|
57
57
|
type DrainAckListener = (payload: DrainAckPayload) => boolean | void;
|
|
58
58
|
export declare function subscribeDrainAck(listener: DrainAckListener): () => void;
|
|
59
|
+
/**
|
|
60
|
+
* The `drain_ack` ingress — fans a frame out to subscribers until one
|
|
61
|
+
* claims it.
|
|
62
|
+
*
|
|
63
|
+
* @internal — exported for unit tests: a late ack for an earlier
|
|
64
|
+
* delivered gesture is the path that retires the standing relay notice
|
|
65
|
+
* without any user click (ggui#670 Phase 3, truth-2).
|
|
66
|
+
*/
|
|
67
|
+
export declare function dispatchDrainAck(payload: DrainAckPayload): void;
|
|
59
68
|
export type ConnectAppResult = {
|
|
60
69
|
readonly ok: true;
|
|
61
70
|
} | {
|
|
@@ -270,10 +279,12 @@ export interface BootSequenceOptions {
|
|
|
270
279
|
* entirely (matches the ProtocolError posture; the `<McpAppIframe>`
|
|
271
280
|
* host wrapper decides whether to bind this via its `onObserve`
|
|
272
281
|
* prop). Exception: `relay-incapability` events do NOT flow through
|
|
273
|
-
* this seam — they
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
*
|
|
282
|
+
* this seam — by rule they always ride the postMessage-to-parent
|
|
283
|
+
* default, whether or not this option is bound: most emission sites
|
|
284
|
+
* are module-level gesture-dispatch code that runs independently of
|
|
285
|
+
* any given boot call, and the one inside the boot graph (the
|
|
286
|
+
* `boot-failed` edge, ggui#830) follows the same rule so a host reads
|
|
287
|
+
* every edge the same way.
|
|
277
288
|
*/
|
|
278
289
|
readonly onObserve?: ObservabilityEmitter;
|
|
279
290
|
/**
|
|
@@ -660,6 +671,16 @@ interface ToastLiveRegions {
|
|
|
660
671
|
* @internal — exported for unit tests.
|
|
661
672
|
*/
|
|
662
673
|
export declare function ensureToastAnnouncer(doc: Document): ToastLiveRegions | null;
|
|
674
|
+
/**
|
|
675
|
+
* Boot-time reset of the relay latch (ggui#670 Phase 3). A latch
|
|
676
|
+
* standing from a prior mount in a re-booted document is closed through
|
|
677
|
+
* the ONE writer — the host gets its `cleared` edge with the zone's
|
|
678
|
+
* summary — and the prior mount's standing notice is removed rather
|
|
679
|
+
* than left describing a session that no longer exists.
|
|
680
|
+
*
|
|
681
|
+
* @internal — exported for unit tests.
|
|
682
|
+
*/
|
|
683
|
+
export declare function resetRelayLatchForBoot(): void;
|
|
663
684
|
/** @internal — exported for unit tests to reset module state. */
|
|
664
685
|
export declare function __resetRelayNoticeForTest(): void;
|
|
665
686
|
/**
|
|
@@ -685,19 +706,22 @@ export declare function dispatchSubmitAction(args: {
|
|
|
685
706
|
/**
|
|
686
707
|
* Channel-transport router's `tools/call` invoker (ggui#440) —
|
|
687
708
|
* iframe-polling transport, `tools/call` against the parent MCP host
|
|
688
|
-
* via `app.callServerTool` (spec-canonical)
|
|
689
|
-
*
|
|
709
|
+
* via `app.callServerTool` (spec-canonical); with no App bound the
|
|
710
|
+
* call answers a code-less error envelope — never a raw postMessage.
|
|
690
711
|
* Direct call (no LLM consent loop). Returns the tool's
|
|
691
712
|
* structuredContent (or `content[0]` if that's where the payload
|
|
692
713
|
* landed) as a `JsonValue`. On RPC error we throw — the router
|
|
693
714
|
* catches and silently retries on the next tick.
|
|
694
715
|
*
|
|
695
|
-
* Once
|
|
696
|
-
*
|
|
697
|
-
*
|
|
698
|
-
* capabilities already captured
|
|
699
|
-
*
|
|
700
|
-
*
|
|
716
|
+
* Once this document has confirmed it cannot relay (the latch above —
|
|
717
|
+
* set through the ONE writer on exactly three paths: a REAL gesture
|
|
718
|
+
* that failed relay-shaped on a host that never advertised
|
|
719
|
+
* `serverTools`, with capabilities already captured (`advert-silent`);
|
|
720
|
+
* a declared refusal code answered under a positive advertisement
|
|
721
|
+
* (`confirmed-refusal`); or the host's own failure of the mandatory
|
|
722
|
+
* `ui/initialize` handshake, before any gesture (`boot-failed`,
|
|
723
|
+
* ggui#830) — never a well-formed `{ok:false}` result; see
|
|
724
|
+
* `isRelayShapedFailure`), every subsequent poll will fail identically.
|
|
701
725
|
*
|
|
702
726
|
* This guard does NOT stop the router's poll loop, and nothing here
|
|
703
727
|
* should ever be written so that it could (ggui#443). It does two
|
|
@@ -723,10 +747,13 @@ export declare function dispatchSubmitAction(args: {
|
|
|
723
747
|
* (ggui's own embed host pre-Task-2 is exactly this case) — silently
|
|
724
748
|
* killing working channel polls forever. That is "absence of a
|
|
725
749
|
* capability blocks an attempt", which the fail-safe constraint
|
|
726
|
-
* forbids. The latch
|
|
727
|
-
*
|
|
728
|
-
*
|
|
729
|
-
*
|
|
750
|
+
* forbids. The latch is set only by a CONFIRMED OUTCOME — a failed
|
|
751
|
+
* real gesture (the advert-silent leg, or a confirmed refusal under a
|
|
752
|
+
* positive advertisement, ggui#599 cycle-2) or a failed handshake
|
|
753
|
+
* (ggui#830), never by an advertisement's absence — so testing the
|
|
754
|
+
* latch alone is sufficient: a host that answers its handshake and
|
|
755
|
+
* never fails a real gesture never latches, and its channels keep
|
|
756
|
+
* working.
|
|
730
757
|
*
|
|
731
758
|
* Extracted to a named export (rather than an inline closure inside
|
|
732
759
|
* `bootProduction`) so unit tests can drive it directly through the
|