@ggui-ai/mcp-server 0.6.2 → 0.7.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/api-renders-routes.d.ts.map +1 -1
- package/dist/api-renders-routes.js +9 -1
- package/dist/browser-cors.d.ts +29 -0
- package/dist/browser-cors.d.ts.map +1 -0
- package/dist/browser-cors.js +64 -0
- package/dist/build-mcp.d.ts.map +1 -1
- package/dist/build-mcp.js +5 -1
- package/dist/code-store-fs.d.ts +3 -0
- package/dist/code-store-fs.d.ts.map +1 -1
- package/dist/code-store-fs.js +27 -3
- package/dist/ggui-session-channel/outbound.d.ts.map +1 -1
- package/dist/ggui-session-channel/outbound.js +12 -0
- package/dist/ggui-session-channel/socket-router.d.ts +33 -0
- package/dist/ggui-session-channel/socket-router.d.ts.map +1 -1
- package/dist/ggui-session-channel/socket-router.js +155 -0
- package/dist/ggui-session-channel/subscribe.d.ts.map +1 -1
- package/dist/ggui-session-channel/subscribe.js +43 -2
- package/dist/ggui-session-channel.d.ts +114 -0
- package/dist/ggui-session-channel.d.ts.map +1 -1
- package/dist/ggui-session-channel.js +77 -2
- package/dist/health-routes.d.ts +3 -0
- package/dist/health-routes.d.ts.map +1 -1
- package/dist/health-routes.js +11 -1
- package/dist/mcp-apps-outbound.d.ts +191 -30
- package/dist/mcp-apps-outbound.d.ts.map +1 -1
- package/dist/mcp-apps-outbound.js +843 -223
- package/dist/origin-validation.d.ts +120 -0
- package/dist/origin-validation.d.ts.map +1 -0
- package/dist/origin-validation.js +199 -0
- package/dist/render-read-gate.d.ts +50 -0
- package/dist/render-read-gate.d.ts.map +1 -0
- package/dist/render-read-gate.js +36 -0
- package/dist/server.d.ts +164 -4
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +206 -20
- package/package.json +12 -12
|
@@ -60,6 +60,54 @@ import { type GguiSessionChannelBootstrap, type GguiSessionChannelCookieAuth } f
|
|
|
60
60
|
import type { Logger } from "./logger.js";
|
|
61
61
|
/** Default URL path for the channel endpoint. Operators can override. */
|
|
62
62
|
export declare const DEFAULT_RENDER_CHANNEL_PATH = "/ws";
|
|
63
|
+
/**
|
|
64
|
+
* Coarse ws-level `maxPayload` memory backstop (1 MiB) applied to EVERY
|
|
65
|
+
* inbound frame on EVERY socket, INCLUDING already-subscribed ones —
|
|
66
|
+
* unlike the other three pre-subscribe caps in this file, this one is
|
|
67
|
+
* NOT subscriber-exempt. It bounds the absolute per-frame buffer a
|
|
68
|
+
* hostile peer can force before the frame is even assembled: a 100x
|
|
69
|
+
* reduction from the `ws` library's own ~100 MiB default, applied
|
|
70
|
+
* uniformly regardless of subscribe state.
|
|
71
|
+
*
|
|
72
|
+
* `ActionEnvelope` (the post-subscribe `action` payload) has no
|
|
73
|
+
* protocol-level max size, so this ceiling can NOT be sized to provably
|
|
74
|
+
* never clip a legitimate frame — it is a deliberately generous-but-
|
|
75
|
+
* finite backstop, not a guarantee. The closest documented protocol-
|
|
76
|
+
* level payload bound is `CONTEXT_SNAPSHOT_MAX_BYTES` (64 KiB, the
|
|
77
|
+
* `ggui_runtime_sync_context` MCP tool call — a related but distinct
|
|
78
|
+
* transport from this WS channel), which puts 1 MiB at roughly 16x
|
|
79
|
+
* headroom over the largest structured payload the protocol formally
|
|
80
|
+
* bounds. Operators whose legitimate `action` frames exceed 1 MiB
|
|
81
|
+
* (e.g. large form submissions) should raise {@link maxPayloadBytes},
|
|
82
|
+
* or set it to `0` to fall back to the `ws` library default. Distinct from
|
|
83
|
+
* the tight, pre-subscribe-only, subscriber-exempt
|
|
84
|
+
* {@link DEFAULT_PRE_SUBSCRIBE_MAX_PAYLOAD_BYTES}. Disable this one
|
|
85
|
+
* with `0`.
|
|
86
|
+
*/
|
|
87
|
+
export declare const DEFAULT_WS_MAX_PAYLOAD_BYTES = 1048576;
|
|
88
|
+
/**
|
|
89
|
+
* Per-frame byte ceiling on PRE-SUBSCRIBE frames (64 KiB). Pre-subscribe
|
|
90
|
+
* traffic is tiny (a subscribe carrying a JWT is under 1 KiB), so this
|
|
91
|
+
* is ~70x headroom yet caps a pre-auth memory-abuse frame. Enforced
|
|
92
|
+
* per-frame, keyed on "not yet a subscriber", so post-subscribe frames
|
|
93
|
+
* are exempt. Disable with `0`.
|
|
94
|
+
*/
|
|
95
|
+
export declare const DEFAULT_PRE_SUBSCRIBE_MAX_PAYLOAD_BYTES = 65536;
|
|
96
|
+
/**
|
|
97
|
+
* Grace window (30 s) an unauthenticated socket has to complete a valid
|
|
98
|
+
* subscribe before it is closed. Open→subscribe is normally sub-second;
|
|
99
|
+
* 30 s tolerates a slow bootstrap-token verify while bounding how long a
|
|
100
|
+
* credential-less socket holds a slot. Disable with `0`.
|
|
101
|
+
*/
|
|
102
|
+
export declare const DEFAULT_PRE_SUBSCRIBE_IDLE_MS = 30000;
|
|
103
|
+
/**
|
|
104
|
+
* Concurrent PENDING (pre-subscribe) socket ceiling (1024). Honest
|
|
105
|
+
* clients leave the pending state in under a second, so 1024 in-flight
|
|
106
|
+
* handshakes is far beyond any real burst yet bounds a credential-less
|
|
107
|
+
* connection flood. Counts pending sockets only — never subscribers.
|
|
108
|
+
* Disable with `0`.
|
|
109
|
+
*/
|
|
110
|
+
export declare const DEFAULT_MAX_PRE_SUBSCRIBE_CONNECTIONS = 1024;
|
|
63
111
|
export type { GguiSessionChannelLocalToolsOptions } from "./ggui-session-channel/channel-subscriptions.js";
|
|
64
112
|
export type { GguiSessionChannelBootstrap, GguiSessionChannelBootstrapRefreshResult, GguiSessionChannelBootstrapVerifyResult, GguiSessionChannelCookieAuth, } from "./ggui-session-channel/subscribe.js";
|
|
65
113
|
export interface GguiSessionChannelOptions {
|
|
@@ -228,6 +276,58 @@ export interface GguiSessionChannelOptions {
|
|
|
228
276
|
* identically in both modes.
|
|
229
277
|
*/
|
|
230
278
|
readonly versionPolicy?: "advisory" | "reject";
|
|
279
|
+
/**
|
|
280
|
+
* Coarse ws-level `maxPayload` memory backstop (bytes) applied to
|
|
281
|
+
* EVERY inbound frame on EVERY socket, INCLUDING already-subscribed
|
|
282
|
+
* ones — the largest single frame the server will assemble before
|
|
283
|
+
* rejecting it (ws closes 1009). Distinct from
|
|
284
|
+
* {@link maxPreSubscribePayloadBytes}: that one is the tight,
|
|
285
|
+
* subscriber-exempt, credential-less bound; this one is a generous-
|
|
286
|
+
* but-finite global ceiling applied uniformly regardless of subscribe
|
|
287
|
+
* state.
|
|
288
|
+
*
|
|
289
|
+
* `ActionEnvelope` (the post-subscribe `action` payload) has no
|
|
290
|
+
* protocol-level max size, so this default can NOT be sized to
|
|
291
|
+
* provably never clip a legitimate frame — see
|
|
292
|
+
* {@link DEFAULT_WS_MAX_PAYLOAD_BYTES} for the sizing rationale.
|
|
293
|
+
* Operators expecting `action` frames larger than the default should
|
|
294
|
+
* raise this value.
|
|
295
|
+
*
|
|
296
|
+
* Defaults to {@link DEFAULT_WS_MAX_PAYLOAD_BYTES} (1 MiB). `0`
|
|
297
|
+
* disables the ws-level check (falls back to the ws library's own
|
|
298
|
+
* ~100 MiB default).
|
|
299
|
+
*/
|
|
300
|
+
readonly maxPayloadBytes?: number;
|
|
301
|
+
/**
|
|
302
|
+
* Per-frame byte ceiling for PRE-SUBSCRIBE (not-yet-registered)
|
|
303
|
+
* sockets. A pre-subscribe frame larger than this closes the socket
|
|
304
|
+
* (1009) before it is parsed. Subscribed sockets are exempt — only
|
|
305
|
+
* the coarse {@link maxPayloadBytes} backstop applies to them.
|
|
306
|
+
*
|
|
307
|
+
* Defaults to {@link DEFAULT_PRE_SUBSCRIBE_MAX_PAYLOAD_BYTES}
|
|
308
|
+
* (64 KiB). `0` disables the pre-subscribe payload cap.
|
|
309
|
+
*/
|
|
310
|
+
readonly maxPreSubscribePayloadBytes?: number;
|
|
311
|
+
/**
|
|
312
|
+
* Grace window (ms) a socket has to complete a valid subscribe before
|
|
313
|
+
* it is closed (1008). Armed on connection, cleared on successful
|
|
314
|
+
* subscribe — a registered subscriber is never reaped, so long-idle
|
|
315
|
+
* and reconnecting viewers keep the existing keepalive behavior.
|
|
316
|
+
*
|
|
317
|
+
* Defaults to {@link DEFAULT_PRE_SUBSCRIBE_IDLE_MS} (30 s). `0`
|
|
318
|
+
* disables the idle timeout.
|
|
319
|
+
*/
|
|
320
|
+
readonly preSubscribeIdleMs?: number;
|
|
321
|
+
/**
|
|
322
|
+
* Concurrent PENDING (pre-subscribe) socket ceiling. A new upgrade
|
|
323
|
+
* that would exceed it is cleanly closed (1013). Counts only sockets
|
|
324
|
+
* that have not completed a valid subscribe — subscriber fan-out is
|
|
325
|
+
* never bounded here.
|
|
326
|
+
*
|
|
327
|
+
* Defaults to {@link DEFAULT_MAX_PRE_SUBSCRIBE_CONNECTIONS} (1024).
|
|
328
|
+
* `0` disables the ceiling.
|
|
329
|
+
*/
|
|
330
|
+
readonly maxPreSubscribeConnections?: number;
|
|
231
331
|
/**
|
|
232
332
|
* Optional hook fired synchronously when the local subscriber count
|
|
233
333
|
* for `sessionId` transitions 0 → 1 (the first subscriber for that
|
|
@@ -412,6 +512,20 @@ export interface GguiSessionChannelServer {
|
|
|
412
512
|
readonly subscriberCount: number;
|
|
413
513
|
/** Number of distinct renders with at least one subscriber. */
|
|
414
514
|
readonly renderCount: number;
|
|
515
|
+
/**
|
|
516
|
+
* Monotonic counts of pre-subscribe cap-driven closures/refusals
|
|
517
|
+
* (ggui#444), surfaced on `/ggui/health` for operator diagnosis of a
|
|
518
|
+
* credential-less abuse burst. Each field only ever increases over
|
|
519
|
+
* the channel's lifetime:
|
|
520
|
+
* - `payload` — oversized pre-subscribe frames rejected (1009).
|
|
521
|
+
* - `idle` — sockets closed for never subscribing in time (1008).
|
|
522
|
+
* - `connection` — upgrades refused past the pending ceiling (1013).
|
|
523
|
+
*/
|
|
524
|
+
readonly preSubscribeRejections: {
|
|
525
|
+
readonly payload: number;
|
|
526
|
+
readonly idle: number;
|
|
527
|
+
readonly connection: number;
|
|
528
|
+
};
|
|
415
529
|
/**
|
|
416
530
|
* Close every live subscriber + the underlying ws server. Idempotent.
|
|
417
531
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ggui-session-channel.d.ts","sourceRoot":"","sources":["../src/ggui-session-channel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAEH,OAAO,KAAK,EACV,WAAW,EACX,UAAU,EACV,oBAAoB,EACpB,gBAAgB,EAChB,uBAAuB,EACvB,mBAAmB,EACnB,YAAY,EACZ,aAAa,EACd,MAAM,0BAA0B,CAAC;AAKlC,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC3F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAI1C,OAAO,EAEL,KAAK,mCAAmC,EACzC,MAAM,iDAAiD,CAAC;AAIzD,OAAO,EAEL,KAAK,2BAA2B,EAChC,KAAK,4BAA4B,EAClC,MAAM,qCAAqC,CAAC;AAE7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,yEAAyE;AACzE,eAAO,MAAM,2BAA2B,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"ggui-session-channel.d.ts","sourceRoot":"","sources":["../src/ggui-session-channel.ts"],"names":[],"mappings":"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"}
|
|
@@ -61,6 +61,54 @@ import { createSubscribeHandlers, } from "./ggui-session-channel/subscribe.js";
|
|
|
61
61
|
import { createSubscriberLifecycle } from "./ggui-session-channel/subscriber-lifecycle.js";
|
|
62
62
|
/** Default URL path for the channel endpoint. Operators can override. */
|
|
63
63
|
export const DEFAULT_RENDER_CHANNEL_PATH = "/ws";
|
|
64
|
+
/**
|
|
65
|
+
* Coarse ws-level `maxPayload` memory backstop (1 MiB) applied to EVERY
|
|
66
|
+
* inbound frame on EVERY socket, INCLUDING already-subscribed ones —
|
|
67
|
+
* unlike the other three pre-subscribe caps in this file, this one is
|
|
68
|
+
* NOT subscriber-exempt. It bounds the absolute per-frame buffer a
|
|
69
|
+
* hostile peer can force before the frame is even assembled: a 100x
|
|
70
|
+
* reduction from the `ws` library's own ~100 MiB default, applied
|
|
71
|
+
* uniformly regardless of subscribe state.
|
|
72
|
+
*
|
|
73
|
+
* `ActionEnvelope` (the post-subscribe `action` payload) has no
|
|
74
|
+
* protocol-level max size, so this ceiling can NOT be sized to provably
|
|
75
|
+
* never clip a legitimate frame — it is a deliberately generous-but-
|
|
76
|
+
* finite backstop, not a guarantee. The closest documented protocol-
|
|
77
|
+
* level payload bound is `CONTEXT_SNAPSHOT_MAX_BYTES` (64 KiB, the
|
|
78
|
+
* `ggui_runtime_sync_context` MCP tool call — a related but distinct
|
|
79
|
+
* transport from this WS channel), which puts 1 MiB at roughly 16x
|
|
80
|
+
* headroom over the largest structured payload the protocol formally
|
|
81
|
+
* bounds. Operators whose legitimate `action` frames exceed 1 MiB
|
|
82
|
+
* (e.g. large form submissions) should raise {@link maxPayloadBytes},
|
|
83
|
+
* or set it to `0` to fall back to the `ws` library default. Distinct from
|
|
84
|
+
* the tight, pre-subscribe-only, subscriber-exempt
|
|
85
|
+
* {@link DEFAULT_PRE_SUBSCRIBE_MAX_PAYLOAD_BYTES}. Disable this one
|
|
86
|
+
* with `0`.
|
|
87
|
+
*/
|
|
88
|
+
export const DEFAULT_WS_MAX_PAYLOAD_BYTES = 1_048_576;
|
|
89
|
+
/**
|
|
90
|
+
* Per-frame byte ceiling on PRE-SUBSCRIBE frames (64 KiB). Pre-subscribe
|
|
91
|
+
* traffic is tiny (a subscribe carrying a JWT is under 1 KiB), so this
|
|
92
|
+
* is ~70x headroom yet caps a pre-auth memory-abuse frame. Enforced
|
|
93
|
+
* per-frame, keyed on "not yet a subscriber", so post-subscribe frames
|
|
94
|
+
* are exempt. Disable with `0`.
|
|
95
|
+
*/
|
|
96
|
+
export const DEFAULT_PRE_SUBSCRIBE_MAX_PAYLOAD_BYTES = 65_536;
|
|
97
|
+
/**
|
|
98
|
+
* Grace window (30 s) an unauthenticated socket has to complete a valid
|
|
99
|
+
* subscribe before it is closed. Open→subscribe is normally sub-second;
|
|
100
|
+
* 30 s tolerates a slow bootstrap-token verify while bounding how long a
|
|
101
|
+
* credential-less socket holds a slot. Disable with `0`.
|
|
102
|
+
*/
|
|
103
|
+
export const DEFAULT_PRE_SUBSCRIBE_IDLE_MS = 30_000;
|
|
104
|
+
/**
|
|
105
|
+
* Concurrent PENDING (pre-subscribe) socket ceiling (1024). Honest
|
|
106
|
+
* clients leave the pending state in under a second, so 1024 in-flight
|
|
107
|
+
* handshakes is far beyond any real burst yet bounds a credential-less
|
|
108
|
+
* connection flood. Counts pending sockets only — never subscribers.
|
|
109
|
+
* Disable with `0`.
|
|
110
|
+
*/
|
|
111
|
+
export const DEFAULT_MAX_PRE_SUBSCRIBE_CONNECTIONS = 1_024;
|
|
64
112
|
/**
|
|
65
113
|
* Build an OSS live-channel server. The returned object is designed to be
|
|
66
114
|
* composed into `createGguiServer` — see `server.ts` for the wire-up.
|
|
@@ -73,9 +121,25 @@ export function createGguiSessionChannelServer(opts) {
|
|
|
73
121
|
// Live-tail pub/sub. Default in-process; multi-process deployments
|
|
74
122
|
// bind a pubsub-backed StreamFanout via `opts.streamFanout`.
|
|
75
123
|
const streamFanout = opts.streamFanout ?? new InProcessStreamFanout();
|
|
124
|
+
// Pre-subscribe caps (ggui#444) — bound what a not-yet-subscribed
|
|
125
|
+
// (credential-less) socket can consume. Resolved once here; `0`
|
|
126
|
+
// disables a given cap. See the DEFAULT_* constants for rationale.
|
|
127
|
+
const wsMaxPayloadBytes = opts.maxPayloadBytes ?? DEFAULT_WS_MAX_PAYLOAD_BYTES;
|
|
128
|
+
const preSubscribeCaps = {
|
|
129
|
+
maxPayloadBytes: opts.maxPreSubscribePayloadBytes ?? DEFAULT_PRE_SUBSCRIBE_MAX_PAYLOAD_BYTES,
|
|
130
|
+
idleMs: opts.preSubscribeIdleMs ?? DEFAULT_PRE_SUBSCRIBE_IDLE_MS,
|
|
131
|
+
maxConnections: opts.maxPreSubscribeConnections ?? DEFAULT_MAX_PRE_SUBSCRIBE_CONNECTIONS,
|
|
132
|
+
};
|
|
133
|
+
// Live monotonic counters surfaced on `/ggui/health`. The router owns
|
|
134
|
+
// the increments; the health getter below reads a snapshot.
|
|
135
|
+
const preSubscribeRejections = { payload: 0, idle: 0, connection: 0 };
|
|
76
136
|
// `noServer: true` means we own the upgrade wiring (see handleUpgrade);
|
|
77
|
-
// ws won't try to bind its own port.
|
|
78
|
-
|
|
137
|
+
// ws won't try to bind its own port. `maxPayload` is the coarse global
|
|
138
|
+
// memory backstop; the tight pre-subscribe payload cap is enforced
|
|
139
|
+
// per-frame in the socket router. `0` → fall back to the ws default.
|
|
140
|
+
const wss = wsMaxPayloadBytes > 0
|
|
141
|
+
? new WebSocketServer({ noServer: true, maxPayload: wsMaxPayloadBytes })
|
|
142
|
+
: new WebSocketServer({ noServer: true });
|
|
79
143
|
/**
|
|
80
144
|
* Flat set of all live WS subscribers. Replaces the per-render
|
|
81
145
|
* `subscribersByRender` Map — routing is now StreamFanout's job;
|
|
@@ -162,6 +226,8 @@ export function createGguiSessionChannelServer(opts) {
|
|
|
162
226
|
handleInboundAction,
|
|
163
227
|
handleChannelSubscribe,
|
|
164
228
|
handleChannelUnsubscribe,
|
|
229
|
+
preSubscribeCaps,
|
|
230
|
+
preSubscribeRejections,
|
|
165
231
|
});
|
|
166
232
|
return {
|
|
167
233
|
path,
|
|
@@ -218,6 +284,15 @@ export function createGguiSessionChannelServer(opts) {
|
|
|
218
284
|
renders.add(sub.sessionId);
|
|
219
285
|
return renders.size;
|
|
220
286
|
},
|
|
287
|
+
get preSubscribeRejections() {
|
|
288
|
+
// Snapshot so callers can't mutate the live counters through the
|
|
289
|
+
// getter's return value.
|
|
290
|
+
return {
|
|
291
|
+
payload: preSubscribeRejections.payload,
|
|
292
|
+
idle: preSubscribeRejections.idle,
|
|
293
|
+
connection: preSubscribeRejections.connection,
|
|
294
|
+
};
|
|
295
|
+
},
|
|
221
296
|
async close() {
|
|
222
297
|
// Close every open socket + drain its StreamFanout subscription.
|
|
223
298
|
// `wss.close` terminates the server but not in-flight sockets,
|
package/dist/health-routes.d.ts
CHANGED
|
@@ -66,6 +66,9 @@ interface MountOptions {
|
|
|
66
66
|
readonly oauthIssuerUrl?: string;
|
|
67
67
|
/** Structured logger for unexpected auth-check failures. */
|
|
68
68
|
readonly logger: Logger;
|
|
69
|
+
/** Effective browser-origin allowlist, for operator diagnosis of CORS
|
|
70
|
+
* failures — which are otherwise invisible server-side. */
|
|
71
|
+
readonly corsOrigins?: ReadonlyArray<string>;
|
|
69
72
|
}
|
|
70
73
|
/**
|
|
71
74
|
* Mount `/ggui/live` + `/ggui/health` + `/ggui/auth-check` onto the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"health-routes.d.ts","sourceRoot":"","sources":["../src/health-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;AAE1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAC1E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAU1C,UAAU,YAAY;IACpB,iCAAiC;IACjC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,iEAAiE;IACjE,QAAQ,CAAC,eAAe,EAAE,aAAa,CAAC;QACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;KAClD,CAAC,CAAC;IACH;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,wBAAwB,GAAG,IAAI,CAAC;IAC3D;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,GAAG,WAAW,CAAA;KAAE,CAAC;IACrE,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,iEAAiE;IACjE,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,uDAAuD;IACvD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,4DAA4D;IAC5D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"health-routes.d.ts","sourceRoot":"","sources":["../src/health-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;AAE1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAC1E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAU1C,UAAU,YAAY;IACpB,iCAAiC;IACjC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,iEAAiE;IACjE,QAAQ,CAAC,eAAe,EAAE,aAAa,CAAC;QACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;KAClD,CAAC,CAAC;IACH;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,wBAAwB,GAAG,IAAI,CAAC;IAC3D;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,GAAG,WAAW,CAAA;KAAE,CAAC;IACrE,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,iEAAiE;IACjE,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,uDAAuD;IACvD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,4DAA4D;IAC5D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;gEAC4D;IAC5D,QAAQ,CAAC,WAAW,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAC9C;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAuI1D"}
|
package/dist/health-routes.js
CHANGED
|
@@ -40,7 +40,7 @@ const READINESS_CHECK_TIMEOUT_MS = 1_000;
|
|
|
40
40
|
* express app. Returns nothing — the routes self-register.
|
|
41
41
|
*/
|
|
42
42
|
export function mountHealthRoutes(opts) {
|
|
43
|
-
const { app, info, toolCount, readinessChecks, getChannel, threads, auth, oauthEnabled, logger } = opts;
|
|
43
|
+
const { app, info, toolCount, readinessChecks, getChannel, threads, auth, oauthEnabled, logger, corsOrigins, } = opts;
|
|
44
44
|
async function runReadinessChecks() {
|
|
45
45
|
if (readinessChecks.length === 0) {
|
|
46
46
|
return { allReady: true, results: {} };
|
|
@@ -86,8 +86,18 @@ export function mountHealthRoutes(opts) {
|
|
|
86
86
|
path: channel.path,
|
|
87
87
|
subscribers: channel.subscriberCount,
|
|
88
88
|
renders: channel.renderCount,
|
|
89
|
+
// Pre-subscribe cap-hit counters (ggui#444) — operator
|
|
90
|
+
// signal for a credential-less abuse burst. Monotonic; all
|
|
91
|
+
// zero on a healthy server.
|
|
92
|
+
caps: {
|
|
93
|
+
preSubscribeRejections: channel.preSubscribeRejections,
|
|
94
|
+
},
|
|
89
95
|
};
|
|
90
96
|
}
|
|
97
|
+
body.cors = {
|
|
98
|
+
loopback: true,
|
|
99
|
+
origins: corsOrigins === undefined ? [] : [...corsOrigins],
|
|
100
|
+
};
|
|
91
101
|
// Thread-transport presence + durability claim. When present,
|
|
92
102
|
// `durability` is exactly what the caller declared — 'ephemeral'
|
|
93
103
|
// by default so Portal does not silently hide its non-durable
|
|
@@ -32,8 +32,11 @@
|
|
|
32
32
|
* same `@ggui-ai/mcp-server` instance that mints the bootstrap.
|
|
33
33
|
*/
|
|
34
34
|
import type { BlueprintIndex, GguiSessionStore, VectorStore } from "@ggui-ai/mcp-server-core";
|
|
35
|
+
import { type BlueprintDurabilityDeps } from "@ggui-ai/mcp-server-handlers/renders";
|
|
35
36
|
import { type McpAppAiGguiRenderMeta } from "@ggui-ai/protocol/integrations/mcp-apps";
|
|
36
37
|
import { type McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
38
|
+
import type { HandlerContext } from "@ggui-ai/mcp-server-handlers";
|
|
39
|
+
import type { Logger } from "./logger.js";
|
|
37
40
|
export declare const GGUI_RENDER_SHELL_HTML = "<!doctype html>\n<html lang=\"en\" style=\"height:100%;background-color:var(--ggui-color-surface, #1e293b)\"><head><meta charset=\"utf-8\"><title>ggui render</title></head>\n<body style=\"margin:0;height:100%;min-height:480px;background-color:var(--ggui-color-surface, #1e293b)\"><div id=\"ggui-root\" data-ggui-shell=\"thin\" style=\"height:100%;min-height:480px\"></div>\n<script>\n(function(){'use strict';\n// MCP Apps shell. Speaks the canonical postMessage protocol from\n// @modelcontextprotocol/ext-apps:\n// 1. iframe -> host: ui/initialize\n// 2. iframe -> host: ui/notifications/initialized\n// 3. host -> iframe: ui/notifications/tool-result (per CallToolResult)\n// On tool-result, read the slice envelope from _meta (spec-canonical\n// CallToolResult _meta at the top level), set window.__GGUI_META__ to\n// the envelope, fetch runtime as blob, inject as script.\n// Runtime auto-mounts inline. No nested iframe (claudemcpcontent.com\n// CSP frame-src forbids cross-origin frames). State machine matches\n// buildSelfContainedShell so the same runtime mounts both paths.\n//\n// R5 (2026-05-26): the historic /r/<shortCode> HTTP fallback was\n// removed along with the bearer-by-obscurity model -- hosts that strip\n// _meta no longer have a recovery path here. Spec-canonical hosts\n// deliver _meta inline and are unaffected.\n//\n// Phase B (2026-05-27): the historic two-slice envelope\n// (`ai.ggui/session` + `ai.ggui/stack-item`) collapsed to ONE flat\n// `ai.ggui/render` slice. runtimeUrl now lives directly on the\n// render slice; sessionId is the canonical identity.\nvar rpcId=1,pending={};\nvar rootEl=document.getElementById('ggui-root');\nrootEl.style.cssText='display:flex;flex-direction:column;height:100%;min-height:300px;margin:0';\nvar mounted=false;\nfunction setOverlay(text){\n if(mounted)return;\n rootEl.innerHTML='<div style=\"font:14px system-ui,sans-serif;padding:24px;color:#666\">'+text+'</div>';\n}\nfunction postNotification(method,params){\n try{window.parent.postMessage({jsonrpc:'2.0',method:method,params:params||{}},'*');}catch(e){}\n}\nfunction postRpc(method,params){\n return new Promise(function(res,rej){\n var id=rpcId++;pending[id]={res:res,rej:rej};\n try{window.parent.postMessage({jsonrpc:'2.0',id:id,method:method,params:params||{}},'*');}\n catch(e){delete pending[id];rej(e);}\n });\n}\nfunction postBootstrapFailed(reason,message){\n // Surface every shell-layer bootstrap-failure path as a typed\n // RendererBootFailedMessage envelope so hosts pinning the C9\n // error pane (McpAppIframe onError, IframeErrorPane) see the\n // failure instead of staring at the inert overlay until the test\n // times out. Reason codes match BootstrapFailureReason.\n try{window.parent.postMessage({type:'ggui:bootstrap-failed',reason:reason,message:message},'*');}catch(e){}\n}\nasync function mountFromMeta(envelope){\n if(mounted)return;\n // Slice envelope shape (Phase B): { \"ai.ggui/render\": { sessionId,\n // appId, runtimeUrl, ... } }. runtimeUrl on the render slice is\n // the only load-bearing field at the shell layer \u2014 it tells us\n // which iframe-runtime bundle to fetch. Everything else is\n // optional; the runtime decides at boot time based on the meta\n // it reads from window.__GGUI_META__.\n var renderSlice=envelope&&envelope['ai.ggui/render'];\n var runtimeUrl=renderSlice&&renderSlice.runtimeUrl;\n if(!envelope||typeof runtimeUrl!=='string'){\n setOverlay('Bootstrap payload malformed.');\n postBootstrapFailed('MALFORMED_BOOTSTRAP','Bootstrap payload malformed.');\n return;\n }\n setOverlay('Loading UI\u2026');\n window.__GGUI_META__=envelope;\n // Load the runtime bundle via a direct cross-origin script tag\n // (governed by CSP script-src) instead of fetch + Blob (governed by\n // CSP connect-src). claude.ai's claudemcpcontent.com iframe CSP\n // forbids cross-origin connect-src so fetch throws TypeError\n // 'Failed to fetch', but allows cross-origin script-src when the\n // bundle responds with the right CORS headers (the iframe-runtime\n // mount sets them). The self-contained shell already uses this\n // pattern; legacy postMessage shell now matches it.\n try{\n var s=document.createElement('script');\n s.type='module';\n // crossorigin=anonymous opts into CORS-mode error reporting.\n // Without it, cross-origin script tags get a sanitized\n // \"script error\" with no details, masking the real cause\n // (CSP block, CORS reject, module-evaluation throw). With it,\n // the error event surfaces the actual message in the iframe\n // console -- the bundle ships ACAO=* so credentialed mode is\n // unnecessary.\n s.crossOrigin='anonymous';\n s.src=runtimeUrl;\n s.onload=function(){mounted=true;};\n s.onerror=function(e){\n var msg='Runtime bundle failed to load: '+(e&&e.message||'script error');\n setOverlay(msg);\n postBootstrapFailed('BUNDLE_FETCH_FAILED',msg);\n };\n rootEl.innerHTML='';\n document.body.appendChild(s);\n }catch(e){\n var msg='Runtime bundle failed to load: '+(e&&e.message||e);\n setOverlay(msg);\n postBootstrapFailed('BUNDLE_FETCH_FAILED',msg);\n }\n}\nfunction readMetaFromCallToolResult(params){\n // MCP Apps spec (specification/2026-01-26/apps.mdx:1145-1155):\n // ui/notifications/tool-result\n // params: CallToolResult // Standard MCP type\n // So params IS the CallToolResult and _meta lives at the top\n // level. Spec-compliant hosts (Claude Desktop, claude.ai\n // Connector, Claude Code) deliver slice-envelope material here.\n // Single slice-envelope key (Phase B: ai.ggui/render). Only the\n // render slice's runtimeUrl is load-bearing at the shell layer;\n // the runtime reads everything else off window.__GGUI_META__\n // after we set it.\n if(!params||typeof params!=='object')return null;\n var meta=params._meta;\n if(!meta||typeof meta!=='object')return null;\n var renderSlice=meta['ai.ggui/render'];\n if(!renderSlice||typeof renderSlice!=='object')return null;\n if(typeof renderSlice.runtimeUrl!=='string')return null;\n return meta;\n}\nwindow.addEventListener('message',function(ev){\n var m=ev&&ev.data;\n if(!m||m.jsonrpc!=='2.0')return;\n if(m.id!=null&&pending[m.id]){\n var p=pending[m.id];delete pending[m.id];\n if(m.error)p.rej(m.error);else p.res(m.result);\n return;\n }\n if(m.method==='ui/notifications/tool-result'){\n // Spec-compliant hosts: m.params IS the CallToolResult; _meta is\n // at the top level.\n var specMeta=readMetaFromCallToolResult(m.params);\n if(specMeta){mountFromMeta(specMeta);return;}\n // R5 (2026-05-26) -- the /r/<shortCode> HTTP fallback was removed\n // along with the bearer-by-obscurity model. Hosts that strip\n // _meta on the tool-result wire have no fallback path here;\n // spec-canonical hosts deliver meta inline and land in the branch\n // above.\n }\n});\nsetOverlay('Initializing\u2026');\nvar initTimer=setTimeout(function(){\n setOverlay('Host did not respond to ui/initialize within 3s.');\n},3000);\npostRpc('ui/initialize',{\n appCapabilities:{},\n appInfo:{name:'ggui-render',version:'1.0.0'},\n protocolVersion:'2026-01-26'\n}).then(function(){\n clearTimeout(initTimer);\n postNotification('ui/notifications/initialized',{});\n // Wait for the host to send ui/notifications/tool-result carrying\n // the slice envelope in _meta \u2014 the spec-canonical delivery channel.\n // The ui/initialize result itself carries no slice meta (the\n // McpUiInitializeResult schema defines no such field).\n setOverlay('Waiting for tool result\u2026');\n}).catch(function(e){\n clearTimeout(initTimer);\n setOverlay('ui/initialize failed: '+(e&&e.message||JSON.stringify(e)));\n});\n})();\n</script></body></html>";
|
|
38
41
|
/**
|
|
39
42
|
* CSP `script-src` source expression that authorises the inline
|
|
@@ -281,20 +284,6 @@ export interface SelfContainedShellInputs {
|
|
|
281
284
|
* @public
|
|
282
285
|
*/
|
|
283
286
|
export declare function buildSelfContainedShell(opts: SelfContainedShellInputs): string;
|
|
284
|
-
/**
|
|
285
|
-
* Minimal "loading" HTML served when a per-render resource is fetched
|
|
286
|
-
* for a render whose visible-bits surface has no componentCode yet
|
|
287
|
-
* (placeholder, generation in flight). Renders a tiny status surface
|
|
288
|
-
* so hosts that pin lifecycle selectors don't see a blank document.
|
|
289
|
-
*
|
|
290
|
-
* Hosts SHOULD re-fetch when they observe additional `ggui_render`
|
|
291
|
-
* results on the same render — the per-call `_meta.ui.resourceUri`
|
|
292
|
-
* value stays stable across commits for a render, so re-fetching the
|
|
293
|
-
* same URI returns fresher HTML on the second try.
|
|
294
|
-
*
|
|
295
|
-
* @public
|
|
296
|
-
*/
|
|
297
|
-
export declare function buildSelfContainedLoadingShell(sessionId: string): string;
|
|
298
287
|
/**
|
|
299
288
|
* Options for {@link registerGguiRenderResourceTemplate}.
|
|
300
289
|
*
|
|
@@ -310,10 +299,13 @@ export interface GguiRenderResourceTemplateOptions {
|
|
|
310
299
|
* Content-addressable code-blob store. When wired alongside
|
|
311
300
|
* {@link codeBaseUrl}, the resource template hashes the render's
|
|
312
301
|
* componentCode, writes it to the store, and inlines the resulting
|
|
313
|
-
* `codeUrl` into the shell bootstrap.
|
|
314
|
-
*
|
|
315
|
-
*
|
|
316
|
-
*
|
|
302
|
+
* `codeUrl` into the shell bootstrap.
|
|
303
|
+
*
|
|
304
|
+
* This is one of the two delivery channels; {@link mintWsToken} is
|
|
305
|
+
* the other, and a compiled component needs at least one of them. A
|
|
306
|
+
* read that resolves a render this server can deliver by neither
|
|
307
|
+
* fails with `NOT_MOUNTABLE` rather than returning a shell that would
|
|
308
|
+
* never paint.
|
|
317
309
|
*/
|
|
318
310
|
readonly codeStore?: import("@ggui-ai/mcp-server-core").CodeStore;
|
|
319
311
|
/**
|
|
@@ -339,6 +331,68 @@ export interface GguiRenderResourceTemplateOptions {
|
|
|
339
331
|
* at hook-mount with a clear "not provided" message).
|
|
340
332
|
*/
|
|
341
333
|
readonly appMetadataStore?: import("@ggui-ai/mcp-server-core").AppMetadataStore;
|
|
334
|
+
/**
|
|
335
|
+
* Durable per-session identity records. When wired alongside
|
|
336
|
+
* {@link durableBlueprints}, a read of a locator whose render row is
|
|
337
|
+
* GONE resolves the record instead of giving up: the render is
|
|
338
|
+
* re-created from it and mounts live, with the props it last
|
|
339
|
+
* carried.
|
|
340
|
+
*
|
|
341
|
+
* Absent ⇒ neither store is consulted, and `NOT_SUPPORTED` takes
|
|
342
|
+
* `NOT_FOUND`'s place wholesale — the honest answer for a server on
|
|
343
|
+
* which an evicted locator can never come back. Wholesale is the
|
|
344
|
+
* load-bearing word: it answers for a locator that never existed AND
|
|
345
|
+
* for one whose row exists but the caller may not read, so the choice
|
|
346
|
+
* of code says nothing about which locators exist. Reads that get far
|
|
347
|
+
* enough to fail `NOT_MOUNTABLE` still do — that verdict is about the
|
|
348
|
+
* caller's own render, not about this server's memory.
|
|
349
|
+
*
|
|
350
|
+
* Binding a store whose records do not outlive the render rows
|
|
351
|
+
* themselves buys nothing — the record is read precisely when the
|
|
352
|
+
* row is gone.
|
|
353
|
+
*/
|
|
354
|
+
readonly renderIdentityStore?: import("@ggui-ai/mcp-server-core").RenderIdentityStore;
|
|
355
|
+
/**
|
|
356
|
+
* Durable blueprint pair — row metadata plus the compiled body
|
|
357
|
+
* behind its content hash. The re-mint path needs BOTH halves: the
|
|
358
|
+
* record names a blueprint, the blueprint names a body, and the body
|
|
359
|
+
* is what a re-created render mounts. A pair carrying only
|
|
360
|
+
* `blueprintStore` persists metadata for other consumers but cannot
|
|
361
|
+
* complete a re-mint, so the path skips as if unwired.
|
|
362
|
+
*
|
|
363
|
+
* Same shape the registration path writes through, so a deployment
|
|
364
|
+
* threads one pair to both ends.
|
|
365
|
+
*/
|
|
366
|
+
readonly durableBlueprints?: BlueprintDurabilityDeps;
|
|
367
|
+
/**
|
|
368
|
+
* Render-row retention window in ms — the SAME operator knob
|
|
369
|
+
* `ggui_render` stamps new renders with. The read path spends it in
|
|
370
|
+
* two places, and both are lifecycle decisions about a row this
|
|
371
|
+
* handler is putting back into service:
|
|
372
|
+
*
|
|
373
|
+
* - a re-mint commits its reconstructed row with this lifetime;
|
|
374
|
+
* - a read of a row that is present but PAST its expiry gives the
|
|
375
|
+
* row this lifetime again, so the live-channel token minted in
|
|
376
|
+
* the same read cannot outlive the row it addresses.
|
|
377
|
+
*
|
|
378
|
+
* Absent ⇒ one hour, matching `ggui_render`'s own fallback. Setting
|
|
379
|
+
* it on a deployment whose renders live far longer than an hour is
|
|
380
|
+
* what stops a rehydrated render from being quietly demoted to a
|
|
381
|
+
* fraction of its neighbours' lifetime.
|
|
382
|
+
*/
|
|
383
|
+
readonly renderTtlMs?: number;
|
|
384
|
+
/**
|
|
385
|
+
* #457 — total-lifetime bound on RESURRECTION: an expired row's read
|
|
386
|
+
* (and a re-mint's fresh commit) may never advance `expiresAt` past
|
|
387
|
+
* `createdAt + maxRenderLifetimeMs`. Unset = unbounded, today's
|
|
388
|
+
* behavior — the knob exists because operator-set short TTLs are
|
|
389
|
+
* exactly where uncapped in-grace self-extension keeps a PII row
|
|
390
|
+
* alive forever on one poll per (TTL + grace). Live-row heartbeats
|
|
391
|
+
* are deliberately NOT capped (active-use lease renewal is intended);
|
|
392
|
+
* rows whose `createdAt` projects the legacy 0 sentinel are exempt
|
|
393
|
+
* (a cap keyed on 0 would mass-kill pre-column rows).
|
|
394
|
+
*/
|
|
395
|
+
readonly maxRenderLifetimeMs?: number;
|
|
342
396
|
/**
|
|
343
397
|
* Vector store backing the blueprint registry. When wired alongside
|
|
344
398
|
* `defaultAppIdFallback`, the resource handler runs a registry-only
|
|
@@ -346,9 +400,26 @@ export interface GguiRenderResourceTemplateOptions {
|
|
|
346
400
|
* (`ui://ggui/render/{sessionId}/{blueprintKey}`): if the render is
|
|
347
401
|
* gone but the blueprint registry still holds the entry, return the
|
|
348
402
|
* static initial render (default props + default context) instead of
|
|
349
|
-
* the
|
|
350
|
-
*
|
|
351
|
-
*
|
|
403
|
+
* failing the read.
|
|
404
|
+
*
|
|
405
|
+
* The lookup is keyed by the caller-supplied `blueprintKey` under
|
|
406
|
+
* `defaultAppIdFallback` alone — it never reads the render row — so
|
|
407
|
+
* it answers the same for a caller who may not read the row as for
|
|
408
|
+
* one probing a locator that never existed. That is what keeps it
|
|
409
|
+
* safe to run on a refused read, which it must, or refusal would
|
|
410
|
+
* become distinguishable from a miss.
|
|
411
|
+
*
|
|
412
|
+
* Leaving both options undefined does NOT return callers to a
|
|
413
|
+
* placeholder shell — there is no longer one to return. It removes
|
|
414
|
+
* the third resolution, so a read that neither the row nor a re-mint
|
|
415
|
+
* can serve fails typed: `NOT_FOUND`, or `NOT_SUPPORTED` on a
|
|
416
|
+
* deployment that also keeps no durable record, or `NOT_MOUNTABLE`
|
|
417
|
+
* where the row is the caller's own and simply has no component yet.
|
|
418
|
+
* Deployments serving
|
|
419
|
+
* more than one tenant from one registry scope are the reason the
|
|
420
|
+
* option exists at all: the fallback discloses whether a blueprint
|
|
421
|
+
* key exists under that scope, so leave it unset if that is not
|
|
422
|
+
* acceptable.
|
|
352
423
|
*/
|
|
353
424
|
readonly vectorStore?: VectorStore;
|
|
354
425
|
/**
|
|
@@ -363,10 +434,17 @@ export interface GguiRenderResourceTemplateOptions {
|
|
|
363
434
|
/**
|
|
364
435
|
* App-id used for blueprint-registry scoping when the render has
|
|
365
436
|
* been evicted. The registry is per-`appId`, but a missing render
|
|
366
|
-
* has no way to derive
|
|
367
|
-
*
|
|
368
|
-
*
|
|
369
|
-
*
|
|
437
|
+
* has no way to derive whose it was, so the fallback needs one scope
|
|
438
|
+
* named up front. Set to `'builder'` (the universal-MCP default
|
|
439
|
+
* identity) and rehydrate works across render expiry / process
|
|
440
|
+
* restart.
|
|
441
|
+
*
|
|
442
|
+
* Leaving it undefined disables the fallback entirely — the reads it
|
|
443
|
+
* would have served fail typed instead (`NOT_FOUND`, or
|
|
444
|
+
* `NOT_SUPPORTED` where no durable record is kept). That is the
|
|
445
|
+
* setting for a deployment that cannot accept the fallback answering
|
|
446
|
+
* "a blueprint with this key exists under this scope" to whoever
|
|
447
|
+
* asks; it is not a way to get a gentler response.
|
|
370
448
|
*/
|
|
371
449
|
readonly defaultAppIdFallback?: string;
|
|
372
450
|
/**
|
|
@@ -403,6 +481,21 @@ export interface GguiRenderResourceTemplateOptions {
|
|
|
403
481
|
readonly token: string;
|
|
404
482
|
readonly expiresAt: string;
|
|
405
483
|
};
|
|
484
|
+
/**
|
|
485
|
+
* Per-request handler-context accessor — the SAME AsyncLocalStorage
|
|
486
|
+
* read the tool path uses. The per-session resource handler gates
|
|
487
|
+
* reads on it (render-read-gate.ts). Absent ⇒ the handler fails
|
|
488
|
+
* closed for rows scoped to any app other than the single-tenant
|
|
489
|
+
* default (compose paths that cannot thread a context keep working
|
|
490
|
+
* for OSS single-tenant flows only).
|
|
491
|
+
*/
|
|
492
|
+
readonly getContext?: () => HandlerContext | undefined;
|
|
493
|
+
/**
|
|
494
|
+
* Structured logger for warn-level denial audit lines
|
|
495
|
+
* (`render_resource_read_denied`). Absent ⇒ denials are silent
|
|
496
|
+
* server-side (still enforced — only the log line is skipped).
|
|
497
|
+
*/
|
|
498
|
+
readonly logger?: Logger;
|
|
406
499
|
}
|
|
407
500
|
/**
|
|
408
501
|
* Register a `ui://ggui/render/{sessionId}` resource template. Each
|
|
@@ -416,11 +509,79 @@ export interface GguiRenderResourceTemplateOptions {
|
|
|
416
509
|
* legacy postMessage shell at the static URI, self-contained shell at
|
|
417
510
|
* the templated URI.
|
|
418
511
|
*
|
|
419
|
-
*
|
|
420
|
-
*
|
|
421
|
-
*
|
|
422
|
-
*
|
|
423
|
-
*
|
|
512
|
+
* # The obligation
|
|
513
|
+
*
|
|
514
|
+
* A read returns EITHER a shell carrying mount material — a static
|
|
515
|
+
* component URL, a live channel, or a system card — OR exactly one
|
|
516
|
+
* typed JSON-RPC error. There is no third outcome, and in particular no
|
|
517
|
+
* successful result wrapping a shell that can never paint anything. A
|
|
518
|
+
* host can check this without trusting the server: if it got
|
|
519
|
+
* `contents`, it got something mountable.
|
|
520
|
+
*
|
|
521
|
+
* The obligation covers outcomes this server can DECIDE. A malfunction
|
|
522
|
+
* still reaches the caller as an internal error (`-32603`) carrying
|
|
523
|
+
* none of the four codes: a template wired with an empty `runtimeUrl`,
|
|
524
|
+
* or a delivery channel that faults **and leaves the read with no other
|
|
525
|
+
* channel to mount through**. A fault the read survives — the usual
|
|
526
|
+
* case on a deployment wiring both channels — is not an outcome at all;
|
|
527
|
+
* the render mounts through whatever is left. That split is deliberate:
|
|
528
|
+
* `-32603` says "something is broken here", which the four codes must
|
|
529
|
+
* never be diluted into claiming, and equally must not be raised over a
|
|
530
|
+
* blip the server routed around.
|
|
531
|
+
*
|
|
532
|
+
* Three resolutions are tried, in this order, and any of them can
|
|
533
|
+
* produce the mount:
|
|
534
|
+
*
|
|
535
|
+
* 1. The render row itself.
|
|
536
|
+
* 2. A re-mint from the durable identity record, when the row is gone
|
|
537
|
+
* and this server keeps one ({@link GguiRenderResourceTemplateOptions.renderIdentityStore}
|
|
538
|
+
* + {@link GguiRenderResourceTemplateOptions.durableBlueprints}).
|
|
539
|
+
* 3. The blueprint registry, keyed by the locator's own `blueprintKey`
|
|
540
|
+
* — the original component with its authoring-time defaults rather
|
|
541
|
+
* than the state the render last held.
|
|
542
|
+
*
|
|
543
|
+
* # Failure modes
|
|
544
|
+
*
|
|
545
|
+
* Which code a given read produces is fully predictable from two facts:
|
|
546
|
+
* whether this server binds a durable substrate (both
|
|
547
|
+
* {@link GguiRenderResourceTemplateOptions.renderIdentityStore} and
|
|
548
|
+
* {@link GguiRenderResourceTemplateOptions.durableBlueprints} — either
|
|
549
|
+
* one alone is as good as neither), and how far the read got.
|
|
550
|
+
*
|
|
551
|
+
* - `NOT_FOUND` (`-32002`) — nothing resolved the locator, **and** the
|
|
552
|
+
* response for a caller who may not read a locator that DOES
|
|
553
|
+
* resolve. Those two are byte-identical by construction: both route
|
|
554
|
+
* through the protocol's projection, which substitutes a constant
|
|
555
|
+
* message and drops `detail`. A distinguishable refusal would turn
|
|
556
|
+
* this read into an oracle for the existence of other callers'
|
|
557
|
+
* renders, so the equality is a security property, not a courtesy.
|
|
558
|
+
* - `NOT_SUPPORTED` (`-32006`) — the same two cases, on a server with
|
|
559
|
+
* no durable substrate: an evicted locator can never be restored
|
|
560
|
+
* here, so saying "not found" would understate it. It takes
|
|
561
|
+
* `NOT_FOUND`'s place WHOLESALE on such a server rather than
|
|
562
|
+
* answering for some locators and not others — a server that said
|
|
563
|
+
* `NOT_FOUND` for a row it refused and `NOT_SUPPORTED` for one that
|
|
564
|
+
* never existed would have rebuilt the same oracle out of the two
|
|
565
|
+
* codes. Correspondingly, a server that DOES bind the substrate
|
|
566
|
+
* never emits it.
|
|
567
|
+
* - `BLUEPRINT_UNRESOLVABLE` (`-32006`) — a record named the render
|
|
568
|
+
* but its component is gone; `detail` names which link broke.
|
|
569
|
+
* Reachable only after the access check.
|
|
570
|
+
* - `NOT_MOUNTABLE` (`-32006`) — something resolved, but nothing
|
|
571
|
+
* mountable can be produced from it: no delivery channel is wired
|
|
572
|
+
* (neither {@link GguiRenderResourceTemplateOptions.codeStore} nor
|
|
573
|
+
* {@link GguiRenderResourceTemplateOptions.mintWsToken}), the row's
|
|
574
|
+
* generation has not committed a component yet, or a registry
|
|
575
|
+
* blueprint matched but cannot be delivered. Unlike the pair above,
|
|
576
|
+
* this one does NOT vary with the substrate: it is what the
|
|
577
|
+
* caller's OWN row gets on every server, because "this server
|
|
578
|
+
* cannot rehydrate" is not the useful truth for a row that is
|
|
579
|
+
* sitting right there. Reachable only after the access check, or —
|
|
580
|
+
* for the registry case — off the caller's own supplied key, so it
|
|
581
|
+
* discloses nothing either way.
|
|
582
|
+
*
|
|
583
|
+
* A URI matching neither template never reaches any of this: the
|
|
584
|
+
* transport rejects it as invalid params, outside these four codes.
|
|
424
585
|
*
|
|
425
586
|
* Returns nothing; mutates the server in place.
|
|
426
587
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-apps-outbound.d.ts","sourceRoot":"","sources":["../src/mcp-apps-outbound.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,
|
|
1
|
+
{"version":3,"file":"mcp-apps-outbound.d.ts","sourceRoot":"","sources":["../src/mcp-apps-outbound.ts"],"names":[],"mappings":"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"}
|