@ggui-ai/iframe-runtime 0.13.0 → 0.14.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/connection.d.ts +20 -0
- package/dist/connection.js +20 -0
- package/dist/iframe-runtime.js +89 -87
- package/dist/iframe-runtime.meta.json +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/observability.d.ts +127 -14
- package/dist/observability.js +59 -0
- package/dist/react-renderer.d.ts +2 -5
- package/dist/react-renderer.js +20 -4
- package/dist/render-item.d.ts +2 -6
- package/dist/runtime.d.ts +19 -0
- package/dist/runtime.js +245 -55
- 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/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,26 +178,41 @@ 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 (ggui#599 cycle-2):
|
|
183
|
+
* `'confirmed-refusal'` — the relay answered a declared refusal code
|
|
184
|
+
* (helper-minted; outranks any positive advertisement), vs
|
|
185
|
+
* `'advert-silent'` — the host never advertised `serverTools` and the
|
|
186
|
+
* attempt failed relay-shaped.
|
|
187
|
+
*
|
|
188
|
+
* @public
|
|
189
|
+
*/
|
|
190
|
+
export type RelayLatchTrigger = 'confirmed-refusal' | 'advert-silent';
|
|
181
191
|
/**
|
|
182
192
|
* Fired at the two transition edges of the renderer's
|
|
183
193
|
* relay-incapability latch — the runtime's confirmed determination
|
|
184
194
|
* that the host cannot relay `tools/call` to the MCP server:
|
|
185
195
|
*
|
|
186
|
-
* - `'latched'` — a real user gesture just failed relay-shaped
|
|
187
|
-
*
|
|
188
|
-
*
|
|
196
|
+
* - `'latched'` — a real user gesture just failed relay-shaped on a
|
|
197
|
+
* host whose captured capability handshake never advertised
|
|
198
|
+
* `serverTools`, or the relay answered a declared refusal code.
|
|
189
199
|
* The runtime now treats relay as confirmed-unavailable: it shows
|
|
190
|
-
* one persistent explanation
|
|
191
|
-
* and channel polls fail fast without a transport
|
|
200
|
+
* one persistent explanation, arms the dead-zone cue for every
|
|
201
|
+
* later gesture, and channel polls fail fast without a transport
|
|
202
|
+
* round-trip.
|
|
192
203
|
* - `'cleared'` — a later well-formed result envelope arrived
|
|
193
204
|
* (`ok:true` and `ok:false` alike — either proves the host relayed
|
|
194
|
-
* the call there and back), so the determination no longer holds
|
|
195
|
-
*
|
|
205
|
+
* the call there and back), so the determination no longer holds.
|
|
206
|
+
* Carries the dead zone's summary: how long it stood and how many
|
|
207
|
+
* gestures were attempted inside it.
|
|
196
208
|
*
|
|
197
|
-
* Emitted once per edge, never per channel poll tick
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
209
|
+
* Emitted once per edge, never per channel poll tick. Gestures
|
|
210
|
+
* attempted while latched are NOT silent on this stream: each one is a
|
|
211
|
+
* {@link RelayDeadTapEvent} (ggui#670 Phase 3) — one per real user
|
|
212
|
+
* gesture, never per tick — so a host can count dead taps and measure
|
|
213
|
+
* dead-tap-to-recovery without watching the render. A boot that finds
|
|
214
|
+
* a latch standing from a prior mount closes it with a `'cleared'`
|
|
215
|
+
* edge before the new session starts.
|
|
201
216
|
*
|
|
202
217
|
* Always emitted via the postMessage-to-parent default — the emission
|
|
203
218
|
* sites live in module-level gesture-dispatch code outside the boot
|
|
@@ -205,9 +220,61 @@ export interface UiFeedbackEvent {
|
|
|
205
220
|
*
|
|
206
221
|
* @public
|
|
207
222
|
*/
|
|
208
|
-
export
|
|
223
|
+
export type RelayIncapabilityEvent = {
|
|
209
224
|
readonly kind: 'relay-incapability';
|
|
210
|
-
readonly state: 'latched'
|
|
225
|
+
readonly state: 'latched';
|
|
226
|
+
readonly trigger: RelayLatchTrigger;
|
|
227
|
+
/** GguiSession id of the render, when the latching gesture carried one. */
|
|
228
|
+
readonly sessionId?: string;
|
|
229
|
+
/** App id of the render, when the latching gesture carried one. */
|
|
230
|
+
readonly appId?: string;
|
|
231
|
+
} | {
|
|
232
|
+
readonly kind: 'relay-incapability';
|
|
233
|
+
readonly state: 'cleared';
|
|
234
|
+
/** How long the dead zone stood, in milliseconds. */
|
|
235
|
+
readonly latchedForMs: number;
|
|
236
|
+
/**
|
|
237
|
+
* Gestures attempted inside the zone — equals the last
|
|
238
|
+
* {@link RelayDeadTapEvent} `ordinal` this edge closes (0 when
|
|
239
|
+
* none was attempted).
|
|
240
|
+
*/
|
|
241
|
+
readonly deadTaps: number;
|
|
242
|
+
readonly sessionId?: string;
|
|
243
|
+
readonly appId?: string;
|
|
244
|
+
};
|
|
245
|
+
/**
|
|
246
|
+
* A user gesture attempted while the relay-incapability latch stands
|
|
247
|
+
* (ggui#670 Phase 3). The runtime never suppresses the attempt — the
|
|
248
|
+
* attempt is the self-heal sensor (ggui#443) — and presents it in the
|
|
249
|
+
* document (pulse, spoken cue, fallback toast); this event makes the
|
|
250
|
+
* attempt COUNTABLE by the host.
|
|
251
|
+
*
|
|
252
|
+
* Contract: exactly one per gesture attempted while latched whose
|
|
253
|
+
* attempt comes back undelivered (relay-shaped failure or a declared
|
|
254
|
+
* refusal); never emitted off-latch, and never from the channel
|
|
255
|
+
* router's fail-fast ticks. Counted at the outcome, not the tap: the
|
|
256
|
+
* gesture that latched the zone is the `'latched'` edge and the gesture
|
|
257
|
+
* that heals it is the `'cleared'` edge — neither is a dead tap.
|
|
258
|
+
* `ordinal` counts from 1 within one dead zone; the `'cleared'` edge
|
|
259
|
+
* reports the total as `deadTaps`. `latchAgeMs` is measured when the
|
|
260
|
+
* outcome lands. Hosts MUST tolerate the event being absent (an older
|
|
261
|
+
* renderer) — absence means no attempt was observed, not that none
|
|
262
|
+
* happened.
|
|
263
|
+
*
|
|
264
|
+
* @public
|
|
265
|
+
*/
|
|
266
|
+
export interface RelayDeadTapEvent {
|
|
267
|
+
readonly kind: 'relay-dead-tap';
|
|
268
|
+
/** The gesture's intent — the action name the component dispatched. */
|
|
269
|
+
readonly intent: string;
|
|
270
|
+
/** Milliseconds since the latch set. */
|
|
271
|
+
readonly latchAgeMs: number;
|
|
272
|
+
/** 1-based position of this attempt within the current dead zone. */
|
|
273
|
+
readonly ordinal: number;
|
|
274
|
+
/** The evidence that latched the zone this attempt landed in. */
|
|
275
|
+
readonly trigger: RelayLatchTrigger;
|
|
276
|
+
readonly sessionId?: string;
|
|
277
|
+
readonly appId?: string;
|
|
211
278
|
}
|
|
212
279
|
/**
|
|
213
280
|
* Catch-all branch for event kinds the host's typings don't recognize.
|
|
@@ -245,6 +312,52 @@ export interface ObservabilityMessage {
|
|
|
245
312
|
* @public
|
|
246
313
|
*/
|
|
247
314
|
export type ObservabilityEmitter = (event: ObservabilityEvent) => void;
|
|
315
|
+
/**
|
|
316
|
+
* Type guard for the `ggui:observe` envelope as it arrives on a host's
|
|
317
|
+
* `message` listener — narrows `event.data` to {@link ObservabilityMessage}.
|
|
318
|
+
* Read fields through the per-kind guards, never through
|
|
319
|
+
* `switch (event.kind)`: the union's open tail (`kind: string & {}`)
|
|
320
|
+
* keeps TypeScript from using `kind` as a discriminant, so a `case`
|
|
321
|
+
* body sees the whole union. Unknown kinds stay in that tail: hosts
|
|
322
|
+
* MUST ignore them, never throw.
|
|
323
|
+
*
|
|
324
|
+
* @example
|
|
325
|
+
* ```ts
|
|
326
|
+
* import {
|
|
327
|
+
* isObservabilityMessage,
|
|
328
|
+
* isRelayDeadTapEvent,
|
|
329
|
+
* isRelayIncapabilityEvent,
|
|
330
|
+
* } from '@ggui-ai/iframe-runtime/observability';
|
|
331
|
+
*
|
|
332
|
+
* window.addEventListener('message', ({ data, source }) => {
|
|
333
|
+
* if (source !== iframe.contentWindow || !isObservabilityMessage(data)) return;
|
|
334
|
+
* const { event } = data;
|
|
335
|
+
* if (isRelayDeadTapEvent(event)) count(event.intent, event.latchAgeMs);
|
|
336
|
+
* else if (isRelayIncapabilityEvent(event) && event.state === 'cleared') recovered(event.deadTaps);
|
|
337
|
+
* // any other kind: ignore
|
|
338
|
+
* });
|
|
339
|
+
* ```
|
|
340
|
+
*
|
|
341
|
+
* @public
|
|
342
|
+
*/
|
|
343
|
+
export declare function isObservabilityMessage(value: unknown): value is ObservabilityMessage;
|
|
344
|
+
/**
|
|
345
|
+
* Narrows to {@link RelayDeadTapEvent}. The union's open tail
|
|
346
|
+
* (`kind: string & {}`) keeps TypeScript from using `kind` as a
|
|
347
|
+
* discriminant, so `switch (event.kind)` never narrows across
|
|
348
|
+
* {@link ObservabilityEvent} — hosts read fields through the per-kind
|
|
349
|
+
* guards (first-consumer finding, ggui#670 Phase 3).
|
|
350
|
+
*
|
|
351
|
+
* @public
|
|
352
|
+
*/
|
|
353
|
+
export declare function isRelayDeadTapEvent(event: ObservabilityEvent): event is RelayDeadTapEvent;
|
|
354
|
+
/**
|
|
355
|
+
* Narrows to {@link RelayIncapabilityEvent}; inside it `state`
|
|
356
|
+
* discriminates the `'latched'` / `'cleared'` edges normally.
|
|
357
|
+
*
|
|
358
|
+
* @public
|
|
359
|
+
*/
|
|
360
|
+
export declare function isRelayIncapabilityEvent(event: ObservabilityEvent): event is RelayIncapabilityEvent;
|
|
248
361
|
/**
|
|
249
362
|
* Default emitter — posts an {@link ObservabilityMessage} to
|
|
250
363
|
* `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`
|
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';
|
|
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:
|
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';
|
|
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
|
@@ -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
|
} | {
|
|
@@ -660,6 +669,16 @@ interface ToastLiveRegions {
|
|
|
660
669
|
* @internal — exported for unit tests.
|
|
661
670
|
*/
|
|
662
671
|
export declare function ensureToastAnnouncer(doc: Document): ToastLiveRegions | null;
|
|
672
|
+
/**
|
|
673
|
+
* Boot-time reset of the relay latch (ggui#670 Phase 3). A latch
|
|
674
|
+
* standing from a prior mount in a re-booted document is closed through
|
|
675
|
+
* the ONE writer — the host gets its `cleared` edge with the zone's
|
|
676
|
+
* summary — and the prior mount's standing notice is removed rather
|
|
677
|
+
* than left describing a session that no longer exists.
|
|
678
|
+
*
|
|
679
|
+
* @internal — exported for unit tests.
|
|
680
|
+
*/
|
|
681
|
+
export declare function resetRelayLatchForBoot(): void;
|
|
663
682
|
/** @internal — exported for unit tests to reset module state. */
|
|
664
683
|
export declare function __resetRelayNoticeForTest(): void;
|
|
665
684
|
/**
|