@ggui-ai/iframe-runtime 0.1.0-rc.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.
- package/LICENSE +201 -0
- package/README.md +33 -0
- package/dist/bootstrap.d.ts +72 -0
- package/dist/bootstrap.js +500 -0
- package/dist/canvas/animator/animator-host.d.ts +63 -0
- package/dist/canvas/animator/animator-host.js +105 -0
- package/dist/canvas/animator/animator-pill.d.ts +42 -0
- package/dist/canvas/animator/animator-pill.js +119 -0
- package/dist/canvas/animator/state-machine.d.ts +106 -0
- package/dist/canvas/animator/state-machine.js +150 -0
- package/dist/canvas/canvas-shell.d.ts +77 -0
- package/dist/canvas/canvas-shell.js +117 -0
- package/dist/canvas/display-mode-policy.d.ts +104 -0
- package/dist/canvas/display-mode-policy.js +98 -0
- package/dist/canvas/mount.d.ts +150 -0
- package/dist/canvas/mount.js +202 -0
- package/dist/canvas/nav-stack.d.ts +133 -0
- package/dist/canvas/nav-stack.js +172 -0
- package/dist/channel-transport.d.ts +182 -0
- package/dist/channel-transport.js +344 -0
- package/dist/channels/channel-payload.d.ts +20 -0
- package/dist/channels/channel-payload.js +34 -0
- package/dist/channels/data.d.ts +48 -0
- package/dist/channels/data.js +103 -0
- package/dist/channels/drain-ack.d.ts +13 -0
- package/dist/channels/drain-ack.js +15 -0
- package/dist/channels/feedback.d.ts +14 -0
- package/dist/channels/feedback.js +19 -0
- package/dist/channels/index.d.ts +7 -0
- package/dist/channels/index.js +7 -0
- package/dist/channels/props-update.d.ts +53 -0
- package/dist/channels/props-update.js +130 -0
- package/dist/channels/push.d.ts +47 -0
- package/dist/channels/push.js +54 -0
- package/dist/channels/system.d.ts +26 -0
- package/dist/channels/system.js +44 -0
- package/dist/compiled-validators.d.ts +40 -0
- package/dist/compiled-validators.js +74 -0
- package/dist/context-observer.d.ts +205 -0
- package/dist/context-observer.js +312 -0
- package/dist/gadget-loader.d.ts +118 -0
- package/dist/gadget-loader.js +136 -0
- package/dist/globals.d.ts +234 -0
- package/dist/globals.js +101 -0
- package/dist/host-context-emitter.d.ts +91 -0
- package/dist/host-context-emitter.js +213 -0
- package/dist/iframe-runtime.js +261 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +4 -0
- package/dist/lifecycle.d.ts +66 -0
- package/dist/lifecycle.js +49 -0
- package/dist/mcp-app-iframe-host.d.ts +69 -0
- package/dist/mcp-app-iframe-host.js +214 -0
- package/dist/observability.d.ts +225 -0
- package/dist/observability.js +28 -0
- package/dist/protocol-error.d.ts +199 -0
- package/dist/protocol-error.js +116 -0
- package/dist/provisional-renderer.d.ts +62 -0
- package/dist/provisional-renderer.js +323 -0
- package/dist/react-renderer.d.ts +95 -0
- package/dist/react-renderer.js +343 -0
- package/dist/registry-subscribe.d.ts +102 -0
- package/dist/registry-subscribe.js +319 -0
- package/dist/runtime.d.ts +531 -0
- package/dist/runtime.js +2623 -0
- package/dist/server.d.ts +36 -0
- package/dist/server.js +72 -0
- package/dist/stack-item-renderer.d.ts +103 -0
- package/dist/stack-item-renderer.js +270 -0
- package/dist/stack.d.ts +90 -0
- package/dist/stack.js +118 -0
- package/dist/status-dom.d.ts +72 -0
- package/dist/status-dom.js +51 -0
- package/dist/system-cards/NoCredentialsCard.d.ts +33 -0
- package/dist/system-cards/NoCredentialsCard.js +189 -0
- package/dist/system-cards/ProtocolProbeCard.d.ts +64 -0
- package/dist/system-cards/ProtocolProbeCard.js +463 -0
- package/dist/system-cards/QrCode.d.ts +46 -0
- package/dist/system-cards/QrCode.js +55 -0
- package/dist/system-cards/host-detect.d.ts +31 -0
- package/dist/system-cards/host-detect.js +108 -0
- package/dist/system-cards/host-intents.d.ts +85 -0
- package/dist/system-cards/host-intents.js +170 -0
- package/dist/system-cards/index.d.ts +70 -0
- package/dist/system-cards/index.js +134 -0
- package/dist/types.d.ts +69 -0
- package/dist/types.js +3 -0
- package/dist/validation.d.ts +83 -0
- package/dist/validation.js +106 -0
- package/dist/wire-config.d.ts +214 -0
- package/dist/wire-config.js +290 -0
- package/package.json +81 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { ClientContractViolationError, buildActionEnvelope, } from '@ggui-ai/wire';
|
|
2
|
+
import { validateOutboundActionEnvelope } from './validation.js';
|
|
3
|
+
import { defaultProtocolErrorEmitter, fromClientContractViolation, } from './protocol-error.js';
|
|
4
|
+
// =============================================================================
|
|
5
|
+
// StreamBus — the in-renderer bridge between inbound `data` frames
|
|
6
|
+
// and per-component `useStream(channel)` subscribers.
|
|
7
|
+
// =============================================================================
|
|
8
|
+
/**
|
|
9
|
+
* Reserved-channel namespace prefix (mirror of
|
|
10
|
+
* `@ggui-ai/protocol::RESERVED_CHANNEL_PREFIX`). Inlined to avoid
|
|
11
|
+
* widening the protocol import surface here — the constant is
|
|
12
|
+
* load-bearing for the late-subscriber replay rule below; equality
|
|
13
|
+
* with the protocol export is locked by the StreamBus tests.
|
|
14
|
+
*/
|
|
15
|
+
const RESERVED_CHANNEL_PREFIX = '_ggui:';
|
|
16
|
+
/**
|
|
17
|
+
* Per-channel ring cap for late-subscriber replay on reserved channels.
|
|
18
|
+
* Mirrors the server-side `DEFAULT_SESSION_STREAM_BUFFER_MAX` posture:
|
|
19
|
+
* bounded so a long-lived iframe can't grow memory unbounded if a
|
|
20
|
+
* reserved channel emits in a hot loop.
|
|
21
|
+
*
|
|
22
|
+
* 256 is enough headroom for the deterministic A2UI emitter (one frame
|
|
23
|
+
* per fragment, ~5–15 frames per push) plus several refresh cycles, and
|
|
24
|
+
* still fits comfortably in memory.
|
|
25
|
+
*/
|
|
26
|
+
const RESERVED_CHANNEL_REPLAY_MAX = 256;
|
|
27
|
+
/**
|
|
28
|
+
* Tiny fan-out bus keyed by channel name. `subscribe.ts`'s inbound-
|
|
29
|
+
* message handler pushes validated `data` envelopes here; wire's
|
|
30
|
+
* `useStream(channel)` subscribes per-component via the config's
|
|
31
|
+
* `subscribe()` method.
|
|
32
|
+
*
|
|
33
|
+
* Late-subscriber replay for reserved channels:
|
|
34
|
+
*
|
|
35
|
+
* The renderer iframe boots in a strict ordering:
|
|
36
|
+
* `subscribe()` → first `ack` → render stack items → mount
|
|
37
|
+
* `mountProvisional` → it then calls `streamBus.subscribe('_ggui:
|
|
38
|
+
* preview', …)`. Server-side replay frames for `_ggui:preview` (the
|
|
39
|
+
* provisional A2UI preamble fired during the agent's `ggui_push`
|
|
40
|
+
* BEFORE the user's browser navigated to the viewer) arrive over the
|
|
41
|
+
* WS in the window between ack-resolve and the provisional mount —
|
|
42
|
+
* they hit `emit()` before any listener has subscribed. Without a
|
|
43
|
+
* bounded reserved-channel ring, those frames vanish and the preview
|
|
44
|
+
* surface stays stuck on the spinner.
|
|
45
|
+
*
|
|
46
|
+
* Server-owned `_ggui:*` channels are buffered in a per-channel ring
|
|
47
|
+
* capped at {@link RESERVED_CHANNEL_REPLAY_MAX}. New subscribers
|
|
48
|
+
* receive the buffered envelopes synchronously before the unsubscribe
|
|
49
|
+
* handle returns — same mental model as the server-side
|
|
50
|
+
* `SessionStreamBuffer.replay(...)` walk over reserved channels at
|
|
51
|
+
* ack time, but mirrored at the inner bus boundary so the host
|
|
52
|
+
* transport stays portable (Claude Desktop / ChatGPT / Cursor /
|
|
53
|
+
* `<McpAppIframe>` all behave the same).
|
|
54
|
+
*
|
|
55
|
+
* Agent-declared (non-reserved) channels are NOT buffered here. Their
|
|
56
|
+
* replay is the server's job — the renderer's `subscribe()` handshake
|
|
57
|
+
* pulls history per `streamSpec.replay` policy when reconnecting with
|
|
58
|
+
* `fromSeq`. Buffering them at this layer would double-count and
|
|
59
|
+
* change the semantics of agent contracts.
|
|
60
|
+
*
|
|
61
|
+
* No observable mutation outside the renderer boundary — the bus is
|
|
62
|
+
* internal plumbing.
|
|
63
|
+
*/
|
|
64
|
+
export class StreamBus {
|
|
65
|
+
listeners = new Map();
|
|
66
|
+
/**
|
|
67
|
+
* Per-channel bounded ring of envelopes for reserved (`_ggui:*`)
|
|
68
|
+
* channels only. FIFO eviction at `RESERVED_CHANNEL_REPLAY_MAX`.
|
|
69
|
+
* Replayed to every new subscriber for that channel.
|
|
70
|
+
*/
|
|
71
|
+
reservedReplay = new Map();
|
|
72
|
+
subscribe(channel, listener) {
|
|
73
|
+
let bucket = this.listeners.get(channel);
|
|
74
|
+
if (bucket === undefined) {
|
|
75
|
+
bucket = new Set();
|
|
76
|
+
this.listeners.set(channel, bucket);
|
|
77
|
+
}
|
|
78
|
+
bucket.add(listener);
|
|
79
|
+
// Replay buffered reserved-channel envelopes BEFORE returning the
|
|
80
|
+
// unsubscribe handle so the new listener is fully caught up by the
|
|
81
|
+
// time `subscribe()` returns. Order matches arrival order at
|
|
82
|
+
// `emit()` (FIFO ring).
|
|
83
|
+
if (channel.startsWith(RESERVED_CHANNEL_PREFIX)) {
|
|
84
|
+
const ring = this.reservedReplay.get(channel);
|
|
85
|
+
if (ring !== undefined) {
|
|
86
|
+
for (const env of ring) {
|
|
87
|
+
listener(env);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return () => {
|
|
92
|
+
const current = this.listeners.get(channel);
|
|
93
|
+
if (current === undefined)
|
|
94
|
+
return;
|
|
95
|
+
current.delete(listener);
|
|
96
|
+
if (current.size === 0)
|
|
97
|
+
this.listeners.delete(channel);
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
emit(envelope) {
|
|
101
|
+
if (envelope.channel.startsWith(RESERVED_CHANNEL_PREFIX)) {
|
|
102
|
+
let ring = this.reservedReplay.get(envelope.channel);
|
|
103
|
+
if (ring === undefined) {
|
|
104
|
+
ring = [];
|
|
105
|
+
this.reservedReplay.set(envelope.channel, ring);
|
|
106
|
+
}
|
|
107
|
+
ring.push(envelope);
|
|
108
|
+
if (ring.length > RESERVED_CHANNEL_REPLAY_MAX) {
|
|
109
|
+
// FIFO drop — keeps the most recent
|
|
110
|
+
// `RESERVED_CHANNEL_REPLAY_MAX` frames. Late subscribers may
|
|
111
|
+
// miss the createSurface fragment if the ring overflows (would
|
|
112
|
+
// render as Spinner-stuck), but that's an upper-bound contract
|
|
113
|
+
// on a bounded buffer, not a silent failure mode in practice.
|
|
114
|
+
ring.shift();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
const bucket = this.listeners.get(envelope.channel);
|
|
118
|
+
if (bucket === undefined)
|
|
119
|
+
return;
|
|
120
|
+
for (const listener of bucket) {
|
|
121
|
+
listener(envelope);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Build the unscoped root `WireConfig` + its scope-factory closure.
|
|
127
|
+
* Bootstraps the renderer's outbound emission + inbound subscription
|
|
128
|
+
* seams.
|
|
129
|
+
*
|
|
130
|
+
* Returns a {@link RootWireConfigBundle} rather than a bare
|
|
131
|
+
* `WireConfig` — the scope factory is paired with the root so
|
|
132
|
+
* `dispatchByItem` internals don't leak onto the public WireConfig
|
|
133
|
+
* shape. `scopeWireConfig` (the exported standalone) is the low-level
|
|
134
|
+
* primitive; `buildScopedConfig` is the pre-bound convenience.
|
|
135
|
+
*/
|
|
136
|
+
export function buildRootWireConfig(opts) {
|
|
137
|
+
const clientSeqBox = { current: 0 };
|
|
138
|
+
function nextSeq() {
|
|
139
|
+
clientSeqBox.current += 1;
|
|
140
|
+
return clientSeqBox.current;
|
|
141
|
+
}
|
|
142
|
+
const emitProtocolError = opts.onProtocolError ?? defaultProtocolErrorEmitter;
|
|
143
|
+
const emitObserve = opts.onObserve ?? (() => { });
|
|
144
|
+
function surfaceViolation(err) {
|
|
145
|
+
// Dual emission — the narrow `onContractViolation` sink stays
|
|
146
|
+
// for in-renderer tests that assert the raw class shape; the
|
|
147
|
+
// typed `onProtocolError` sink receives the widened
|
|
148
|
+
// ProtocolError ('kind: protocol' / code: CLIENT_CONTRACT_VIOLATION)
|
|
149
|
+
// that the `<McpAppIframe>` host wrapper surfaces via `onError`.
|
|
150
|
+
if (opts.onContractViolation) {
|
|
151
|
+
opts.onContractViolation(err);
|
|
152
|
+
}
|
|
153
|
+
else if (opts.onProtocolError === undefined) {
|
|
154
|
+
// No caller-supplied sink at all → operator-visible fallback so
|
|
155
|
+
// dev consoles see the violation. Matches
|
|
156
|
+
// `GguiSession.surfaceContractViolation`'s console.warn posture.
|
|
157
|
+
// eslint-disable-next-line no-console
|
|
158
|
+
console.warn('[ggui:contract] ' + err.message, {
|
|
159
|
+
direction: err.direction,
|
|
160
|
+
violations: err.violations,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
emitProtocolError(fromClientContractViolation(err));
|
|
164
|
+
}
|
|
165
|
+
function dispatchByItem(actionName, data, ctx) {
|
|
166
|
+
const envelope = buildActionEnvelope({
|
|
167
|
+
sessionId: opts.sessionId,
|
|
168
|
+
type: 'data:submit',
|
|
169
|
+
payload: {
|
|
170
|
+
action: actionName,
|
|
171
|
+
data: data,
|
|
172
|
+
...(ctx.tool ? { tool: ctx.tool } : {}),
|
|
173
|
+
},
|
|
174
|
+
stackIndex: ctx.stackIndex,
|
|
175
|
+
...(ctx.stackItemId ? { stackItemId: ctx.stackItemId } : {}),
|
|
176
|
+
clientSeq: nextSeq(),
|
|
177
|
+
});
|
|
178
|
+
const result = validateOutboundActionEnvelope(ctx.actionSpec, envelope);
|
|
179
|
+
if (!result.valid) {
|
|
180
|
+
surfaceViolation(new ClientContractViolationError('outbound-action', result.violations));
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
sendActionEnvelope(opts.manager, envelope);
|
|
184
|
+
// Observability: a wired-tool dispatch is a `data:submit` whose
|
|
185
|
+
// resolved action has a `tool` binding. Plain agent-routed actions
|
|
186
|
+
// (no `tool` on the actionSpec) fire a `dispatch` activity row in
|
|
187
|
+
// the console via the session-side ring buffer; only wired tools
|
|
188
|
+
// get this observability event. The server separately emits the
|
|
189
|
+
// operational telemetry variant on its TelemetrySink.
|
|
190
|
+
if (ctx.tool !== undefined) {
|
|
191
|
+
emitObserve({
|
|
192
|
+
kind: 'wired-tool-invoked',
|
|
193
|
+
toolName: ctx.tool,
|
|
194
|
+
actionName,
|
|
195
|
+
dispatchedAt: new Date().toISOString(),
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
const root = {
|
|
200
|
+
app: { appId: opts.appId, appName: opts.appId },
|
|
201
|
+
session: { sessionId: opts.sessionId, isConnected: true },
|
|
202
|
+
auth: { isAuthenticated: false },
|
|
203
|
+
dispatch: (actionName, data) => {
|
|
204
|
+
// Unscoped fallback — resolve from top of stack. Matches
|
|
205
|
+
// `GguiSession.wireConfig.dispatch` (the non-scoped path).
|
|
206
|
+
const stack = opts.getStack();
|
|
207
|
+
const activeItem = stack[stack.length - 1];
|
|
208
|
+
const activeIndex = stack.length > 0 ? stack.length - 1 : 0;
|
|
209
|
+
// McpApps + system items never carry `actionSpec` (their wire is
|
|
210
|
+
// owned by their own host) — narrow before reading.
|
|
211
|
+
const activeActionSpec = activeItem !== undefined &&
|
|
212
|
+
activeItem.type !== 'mcpApps' &&
|
|
213
|
+
activeItem.type !== 'system'
|
|
214
|
+
? activeItem.actionSpec
|
|
215
|
+
: undefined;
|
|
216
|
+
const entry = activeActionSpec?.[actionName];
|
|
217
|
+
const tool = entry?.nextStep;
|
|
218
|
+
dispatchByItem(actionName, data, {
|
|
219
|
+
stackItemId: activeItem?.id,
|
|
220
|
+
stackIndex: activeIndex,
|
|
221
|
+
...(tool !== undefined ? { tool } : {}),
|
|
222
|
+
...(activeActionSpec !== undefined
|
|
223
|
+
? { actionSpec: activeActionSpec }
|
|
224
|
+
: {}),
|
|
225
|
+
});
|
|
226
|
+
},
|
|
227
|
+
subscribe: (channelName, handler) => {
|
|
228
|
+
return opts.streamBus.subscribe(channelName, (env) => {
|
|
229
|
+
// `WireConfig<DataContract>.subscribe`'s handler expects a
|
|
230
|
+
// `StreamDelivery<unknown>`; the bus ships the raw envelope
|
|
231
|
+
// payload unmodified. The type-level `unknown` narrowing
|
|
232
|
+
// lives on the caller's generic boundary (useStream /
|
|
233
|
+
// useContract).
|
|
234
|
+
handler({
|
|
235
|
+
payload: env.payload,
|
|
236
|
+
mode: env.mode,
|
|
237
|
+
...(env.complete !== undefined ? { complete: env.complete } : {}),
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
},
|
|
241
|
+
// `callWiredTool` is retired — `agentTools` is now a catalog the
|
|
242
|
+
// AGENT invokes; the component never reaches the underlying tool
|
|
243
|
+
// from inside the renderer. Cross-refs surface via
|
|
244
|
+
// `actionSpec[*].nextStep` (event metadata) and
|
|
245
|
+
// `streamSpec[*].source.tool` (channel data source).
|
|
246
|
+
};
|
|
247
|
+
// `WireConfig` carries no `scope(item)` method.
|
|
248
|
+
// Callers that want a per-item config use `buildScopedConfig(item)`
|
|
249
|
+
// on the returned bundle, which bakes in the `dispatchByItem` +
|
|
250
|
+
// `getStack` internals so they never leak onto the public
|
|
251
|
+
// WireConfig shape.
|
|
252
|
+
const buildScopedConfig = (item) => scopeWireConfig(root, item, {
|
|
253
|
+
getStack: opts.getStack,
|
|
254
|
+
dispatchByItem,
|
|
255
|
+
});
|
|
256
|
+
return { config: root, buildScopedConfig };
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Produce a per-item scoped `WireConfig`. The only override is
|
|
260
|
+
* `dispatch` — every other seam (subscribe) stays shared.
|
|
261
|
+
*/
|
|
262
|
+
export function scopeWireConfig(root, item, internals) {
|
|
263
|
+
return {
|
|
264
|
+
...root,
|
|
265
|
+
dispatch: (actionName, data) => {
|
|
266
|
+
const entry = item.actionSpec?.[actionName];
|
|
267
|
+
const tool = entry?.nextStep;
|
|
268
|
+
const stack = internals.getStack();
|
|
269
|
+
const idx = stack.findIndex((s) => s.id === item.stackItemId);
|
|
270
|
+
internals.dispatchByItem(actionName, data, {
|
|
271
|
+
...(item.stackItemId !== undefined ? { stackItemId: item.stackItemId } : {}),
|
|
272
|
+
stackIndex: idx >= 0 ? idx : 0,
|
|
273
|
+
...(tool !== undefined ? { tool } : {}),
|
|
274
|
+
...(item.actionSpec !== undefined ? { actionSpec: item.actionSpec } : {}),
|
|
275
|
+
});
|
|
276
|
+
},
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
// =============================================================================
|
|
280
|
+
// Outbound envelope emission
|
|
281
|
+
// =============================================================================
|
|
282
|
+
/**
|
|
283
|
+
* Send a validated action envelope over the live channel. The WS frame shape
|
|
284
|
+
* is `{type:'action', payload: envelope}` — matches today's
|
|
285
|
+
* `useWebSocket.sendAction` exactly, so wire-emitted dispatches from
|
|
286
|
+
* the renderer are byte-equivalent to `GguiSession`-emitted ones.
|
|
287
|
+
*/
|
|
288
|
+
function sendActionEnvelope(manager, envelope) {
|
|
289
|
+
manager.send({ type: 'action', payload: envelope });
|
|
290
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ggui-ai/iframe-runtime",
|
|
3
|
+
"version": "0.1.0-rc.1",
|
|
4
|
+
"description": "The iframe-local ggui runtime: a self-contained ESM bundle that boots inside an MCP Apps host iframe, runs the protocol-version handshake, opens the live-channel WebSocket, and renders the session stack. Bundles React, ReactDOM, and the ggui design system so generated component code has a single seam to read from.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ggui",
|
|
7
|
+
"mcp",
|
|
8
|
+
"mcp-apps",
|
|
9
|
+
"iframe",
|
|
10
|
+
"runtime",
|
|
11
|
+
"react"
|
|
12
|
+
],
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"type": "module",
|
|
15
|
+
"main": "dist/index.js",
|
|
16
|
+
"types": "dist/index.d.ts",
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"import": "./dist/index.js",
|
|
25
|
+
"default": "./dist/index.js"
|
|
26
|
+
},
|
|
27
|
+
"./server": {
|
|
28
|
+
"types": "./dist/server.d.ts",
|
|
29
|
+
"import": "./dist/server.js",
|
|
30
|
+
"default": "./dist/server.js"
|
|
31
|
+
},
|
|
32
|
+
"./runtime.js": {
|
|
33
|
+
"default": "./dist/iframe-runtime.js"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"qrcode-generator": "^2.0.4",
|
|
38
|
+
"react": "^19.0.0",
|
|
39
|
+
"react-dom": "^19.0.0",
|
|
40
|
+
"@ggui-ai/channel-client": "0.1.0-rc.1",
|
|
41
|
+
"@ggui-ai/gadgets": "0.1.0-rc.1",
|
|
42
|
+
"@ggui-ai/preview-a2ui": "0.1.0-rc.1",
|
|
43
|
+
"@ggui-ai/protocol": "0.1.0-rc.1",
|
|
44
|
+
"@ggui-ai/design": "0.1.0-rc.1",
|
|
45
|
+
"@ggui-ai/wire": "0.1.0-rc.1"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@testing-library/react": "^16.0.0",
|
|
49
|
+
"@types/node": "^24.0.0",
|
|
50
|
+
"@types/react": "^19.0.0",
|
|
51
|
+
"@types/react-dom": "^19.0.0",
|
|
52
|
+
"esbuild": "^0.25.12",
|
|
53
|
+
"jsdom": "^24.0.0",
|
|
54
|
+
"tsx": "^4.21.0",
|
|
55
|
+
"typescript": "^5.0.0",
|
|
56
|
+
"vitest": "^3.0.0"
|
|
57
|
+
},
|
|
58
|
+
"repository": {
|
|
59
|
+
"type": "git",
|
|
60
|
+
"url": "https://github.com/ggui-ai/ggui.git",
|
|
61
|
+
"directory": "packages/iframe-runtime"
|
|
62
|
+
},
|
|
63
|
+
"homepage": "https://github.com/ggui-ai/ggui/tree/main/packages/iframe-runtime",
|
|
64
|
+
"bugs": {
|
|
65
|
+
"url": "https://github.com/ggui-ai/ggui/issues"
|
|
66
|
+
},
|
|
67
|
+
"publishConfig": {
|
|
68
|
+
"access": "public"
|
|
69
|
+
},
|
|
70
|
+
"engines": {
|
|
71
|
+
"node": ">=20.0.0"
|
|
72
|
+
},
|
|
73
|
+
"author": "ggui contributors <hello@ggui.ai>",
|
|
74
|
+
"scripts": {
|
|
75
|
+
"build": "node esbuild.config.mjs && tsc -p tsconfig.types.json && pnpm run check:bundle-size",
|
|
76
|
+
"check:bundle-size": "tsx scripts/check-bundle-size.ts",
|
|
77
|
+
"typecheck": "tsc --noEmit",
|
|
78
|
+
"test": "vitest run",
|
|
79
|
+
"test:watch": "vitest"
|
|
80
|
+
}
|
|
81
|
+
}
|