@ggui-ai/mcp-server 0.15.0 → 0.17.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.
Files changed (52) hide show
  1. package/dist/api-renders-routes.d.ts +0 -7
  2. package/dist/api-renders-routes.d.ts.map +1 -1
  3. package/dist/api-renders-routes.js +5 -5
  4. package/dist/api-renders-stream-route.js +4 -4
  5. package/dist/auth.d.ts +3 -3
  6. package/dist/auth.js +6 -6
  7. package/dist/build-mcp.d.ts +1 -1
  8. package/dist/console-blueprint-routes.js +2 -2
  9. package/dist/console-chat-routes.d.ts +1 -1
  10. package/dist/console-chat-routes.js +1 -1
  11. package/dist/console-keys-routes.js +2 -2
  12. package/dist/console-llm-keys-routes.d.ts +1 -1
  13. package/dist/console-llm-keys-routes.js +5 -5
  14. package/dist/console-registry-routes.d.ts +1 -1
  15. package/dist/console-registry-routes.js +1 -1
  16. package/dist/console-theme-routes.d.ts +1 -1
  17. package/dist/console-theme-routes.js +1 -1
  18. package/dist/control-service.d.ts +3 -3
  19. package/dist/control-service.js +3 -3
  20. package/dist/ggui-session-channel/socket-router.js +2 -2
  21. package/dist/ggui-session-channel/subscribe.d.ts +1 -1
  22. package/dist/ggui-session-channel/subscribe.d.ts.map +1 -1
  23. package/dist/ggui-session-channel/subscribe.js +2 -2
  24. package/dist/ggui-session-channel/subscriber-lifecycle.d.ts +1 -1
  25. package/dist/ggui-session-channel/subscriber-lifecycle.js +1 -1
  26. package/dist/ggui-session-channel.d.ts +4 -4
  27. package/dist/ggui-session-channel.js +4 -4
  28. package/dist/health-routes.d.ts +7 -6
  29. package/dist/health-routes.d.ts.map +1 -1
  30. package/dist/health-routes.js +8 -7
  31. package/dist/index.js +1 -1
  32. package/dist/instructions-presets.js +5 -5
  33. package/dist/mcp-apps-outbound.d.ts +17 -11
  34. package/dist/mcp-apps-outbound.d.ts.map +1 -1
  35. package/dist/mcp-apps-outbound.js +64 -26
  36. package/dist/mcp-endpoint-routes.d.ts.map +1 -1
  37. package/dist/mcp-endpoint-routes.js +18 -0
  38. package/dist/oauth-as-routes.d.ts +1 -1
  39. package/dist/oauth.d.ts +3 -3
  40. package/dist/oauth.js +3 -3
  41. package/dist/render-read-gate.d.ts +3 -3
  42. package/dist/render-read-gate.js +2 -2
  43. package/dist/runtime-bundle-hash.d.ts +1 -1
  44. package/dist/runtime-bundle-hash.js +1 -1
  45. package/dist/schema-compat.d.ts +2 -1
  46. package/dist/schema-compat.d.ts.map +1 -1
  47. package/dist/schema-compat.js +5 -5
  48. package/dist/server.d.ts +48 -76
  49. package/dist/server.d.ts.map +1 -1
  50. package/dist/server.js +29 -41
  51. package/dist/thread-transport.js +1 -1
  52. package/package.json +14 -14
@@ -44,7 +44,6 @@
44
44
  * or the render was reset). Clients re-mount from /state.
45
45
  */
46
46
  import type { AppMetadataStore, CodeStore, GguiSessionStore } from "@ggui-ai/mcp-server-core";
47
- import { type AppThemeBase } from "@ggui-ai/mcp-server-handlers/renders";
48
47
  import { type McpAppAiGguiRenderMeta } from "@ggui-ai/protocol/integrations/mcp-apps";
49
48
  import type { Express } from "express";
50
49
  import type { Logger } from "./logger.js";
@@ -57,12 +56,6 @@ interface MountOptions {
57
56
  readonly secret: string;
58
57
  /** Per-app metadata store for the publicEnv projection (optional). */
59
58
  readonly appMetadataStore?: AppMetadataStore;
60
- /**
61
- * Runtime theme-registration resolver (ggui#598-C) — same contract
62
- * as `RenderSliceMetaDeps.themeBaseProvider`; bound by the server
63
- * composer so /state cannot drift from the result-meta emitters.
64
- */
65
- readonly themeBaseProvider?: (appId: string, themeName: string) => Promise<AppThemeBase | null> | AppThemeBase | null;
66
59
  /** Operator-picked theme preset id stamped on /state reads. */
67
60
  readonly themeId?: string;
68
61
  /** Operator-picked theme mode stamped on /state reads. */
@@ -1 +1 @@
1
- {"version":3,"file":"api-renders-routes.d.ts","sourceRoot":"","sources":["../src/api-renders-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE9F,OAAO,EAKL,KAAK,YAAY,EAElB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAGL,KAAK,sBAAsB,EAC5B,MAAM,yCAAyC,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,UAAU,YAAY;IACpB,iCAAiC;IACjC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,+CAA+C;IAC/C,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC;IACvC,wEAAwE;IACxE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,sEAAsE;IACtE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAC7C;;;;OAIG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAC3B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,KACd,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,YAAY,GAAG,IAAI,CAAC;IACxD,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,0DAA0D;IAC1D,QAAQ,CAAC,SAAS,CAAC,EAAE,sBAAsB,CAAC,WAAW,CAAC,CAAC;IACzD,sEAAsE;IACtE,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;IAC/B,sEAAsE;IACtE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC;;;;;;;OAOG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;;OAMG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE;QAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;KACvB,KAAK,MAAM,GAAG,SAAS,CAAC;IACzB,qEAAqE;IACrE,QAAQ,CAAC,aAAa,CAAC,EAAE,CACvB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,KACV;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACzD,oEAAoE;IACpE,QAAQ,CAAC,iBAAiB,EAAE,MAAM,MAAM,CAAC;IACzC,iDAAiD;IACjD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAgX9D"}
1
+ {"version":3,"file":"api-renders-routes.d.ts","sourceRoot":"","sources":["../src/api-renders-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAQ9F,OAAO,EAGL,KAAK,sBAAsB,EAC5B,MAAM,yCAAyC,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,UAAU,YAAY;IACpB,iCAAiC;IACjC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,+CAA+C;IAC/C,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC;IACvC,wEAAwE;IACxE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,sEAAsE;IACtE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAC7C,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,0DAA0D;IAC1D,QAAQ,CAAC,SAAS,CAAC,EAAE,sBAAsB,CAAC,WAAW,CAAC,CAAC;IACzD,sEAAsE;IACtE,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;IAC/B,sEAAsE;IACtE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC;;;;;;;OAOG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;;OAMG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE;QAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;KACvB,KAAK,MAAM,GAAG,SAAS,CAAC;IACzB,qEAAqE;IACrE,QAAQ,CAAC,aAAa,CAAC,EAAE,CACvB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,KACV;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACzD,oEAAoE;IACpE,QAAQ,CAAC,iBAAiB,EAAE,MAAM,MAAM,CAAC;IACzC,iDAAiD;IACjD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAgX9D"}
@@ -44,7 +44,7 @@
44
44
  * or the render was reset). Clients re-mount from /state.
45
45
  */
46
46
  import { verifyToken } from "@ggui-ai/mcp-server-core";
47
- import { deriveContractBundle, derivePublicEnvProjection, deriveRenderMeta, withResolvedThemeBase, spreadRenderMetaViewOntoSlice, } from "@ggui-ai/mcp-server-handlers/renders";
47
+ import { deriveContractBundle, derivePublicEnvProjection, deriveRenderMeta, spreadRenderMetaViewOntoSlice, } from "@ggui-ai/mcp-server-handlers/renders";
48
48
  import { composeSessionApiUrls, MCP_APP_AI_GGUI_RENDER_META_KEY, } from "@ggui-ai/protocol/integrations/mcp-apps";
49
49
  /**
50
50
  * Mount `GET /api/sessions/:sessionId/state` +
@@ -90,7 +90,7 @@ export function mountApiRendersRoutes(opts) {
90
90
  res.status(401).type("text/plain").send("wsToken invalid");
91
91
  return;
92
92
  }
93
- // Tenancy gate: the wsToken's claimed sessionId MUST match the
93
+ // Binding gate: the wsToken's claimed sessionId MUST match the
94
94
  // URL's sessionId. A wsToken minted for render A MUST NOT read
95
95
  // render B's state.
96
96
  if (verify.claims.sessionId !== sessionId) {
@@ -116,7 +116,7 @@ export function mountApiRendersRoutes(opts) {
116
116
  res.status(404).type("text/plain").send("render not found");
117
117
  return;
118
118
  }
119
- // Tenancy gate (round 2): the wsToken's appId MUST match the
119
+ // App-scope gate (round 2): the wsToken's appId MUST match the
120
120
  // render's appId. Closes the case where a render is created
121
121
  // under a different appId than the token was minted for.
122
122
  if (verify.claims.appId !== stored.appId) {
@@ -137,7 +137,7 @@ export function mountApiRendersRoutes(opts) {
137
137
  // R6 addition: polling clients use it to initialize the R7 /events
138
138
  // cursor (`?sinceSequence=N`) aligned with the WS stream.
139
139
  const view = !isMcpApps
140
- ? await withResolvedThemeBase(deriveRenderMeta(render), opts, render.appId)
140
+ ? deriveRenderMeta(render)
141
141
  : undefined;
142
142
  let statePublicEnv;
143
143
  if (appMetadataStore && !isMcpApps) {
@@ -361,7 +361,7 @@ export function mountApiRendersRoutes(opts) {
361
361
  res.status(404).type("text/plain").send("render not found");
362
362
  return;
363
363
  }
364
- // Tenancy gate (round 2): the wsToken's appId MUST match the
364
+ // App-scope gate (round 2): the wsToken's appId MUST match the
365
365
  // render's appId. We need the render record to check — fetch
366
366
  // it. listEventsSince validated the render exists.
367
367
  const stored = await renderStore.get(sessionId);
@@ -63,7 +63,7 @@ class SseSink {
63
63
  /**
64
64
  * Invoked exactly once, from `end()`, BEFORE the response closes —
65
65
  * the route assigns its teardown (clear heartbeat + detach) here so
66
- * a channel-initiated `end` (pod shutdown, expiry probe) tears the
66
+ * a channel-initiated `end` (server shutdown, expiry probe) tears the
67
67
  * subscriber down through the same single path as a client close.
68
68
  */
69
69
  onEnd;
@@ -141,7 +141,7 @@ export function mountApiRendersStreamRoute(opts) {
141
141
  res.status(401).type("text/plain").send("wsToken invalid");
142
142
  return;
143
143
  }
144
- // Tenancy gate: the wsToken's claimed sessionId MUST match the
144
+ // Binding gate: the wsToken's claimed sessionId MUST match the
145
145
  // URL's sessionId.
146
146
  if (verify.claims.sessionId !== sessionId) {
147
147
  res.status(401).type("text/plain").send("wsToken scope mismatch");
@@ -203,7 +203,7 @@ export function mountApiRendersStreamRoute(opts) {
203
203
  res.status(404).type("text/plain").send("render not found");
204
204
  return;
205
205
  }
206
- // Tenancy gate (round 2): the wsToken's appId MUST match the
206
+ // App-scope gate (round 2): the wsToken's appId MUST match the
207
207
  // render's appId.
208
208
  if (verify.claims.appId !== stored.appId) {
209
209
  res.status(401).type("text/plain").send("wsToken scope mismatch");
@@ -229,7 +229,7 @@ export function mountApiRendersStreamRoute(opts) {
229
229
  res.write("retry: 3000\n\n");
230
230
  const sink = new SseSink(res, logger);
231
231
  // Single idempotent teardown shared by every exit path: client
232
- // close, channel-initiated sink.end (pod shutdown / expiry probe),
232
+ // close, channel-initiated sink.end (server shutdown / expiry probe),
233
233
  // attach failure.
234
234
  let detachFn = null;
235
235
  let torn = false;
package/dist/auth.d.ts CHANGED
@@ -29,10 +29,10 @@ export declare function resolveIdentity(adapter: AuthAdapter, req: Request): Pro
29
29
  * Derive a stable `appId` from an auth result.
30
30
  *
31
31
  * In OSS single-user mode every identity collapses to `{kind:'builder'}`
32
- * which doesn't carry a tenant id. We fold these into a single
32
+ * which doesn't carry an app id. We fold these into a single
33
33
  * well-known value (`DEFAULT_BUILDER_APP_ID`) so blueprint / vector
34
- * scoping still works. Multi-tenant bindings (a hosted closed runtime)
35
- * override this by passing `appIdFromIdentity` on `createGguiServer`.
34
+ * scoping still works. A multi-app production deployment overrides
35
+ * this by passing `appIdFromIdentity` on `createGguiServer`.
36
36
  */
37
37
  export declare const DEFAULT_BUILDER_APP_ID = "builder";
38
38
  export declare function defaultAppIdFromIdentity(result: AuthResult): string;
package/dist/auth.js CHANGED
@@ -47,10 +47,10 @@ export async function resolveIdentity(adapter, req) {
47
47
  * Derive a stable `appId` from an auth result.
48
48
  *
49
49
  * In OSS single-user mode every identity collapses to `{kind:'builder'}`
50
- * which doesn't carry a tenant id. We fold these into a single
50
+ * which doesn't carry an app id. We fold these into a single
51
51
  * well-known value (`DEFAULT_BUILDER_APP_ID`) so blueprint / vector
52
- * scoping still works. Multi-tenant bindings (a hosted closed runtime)
53
- * override this by passing `appIdFromIdentity` on `createGguiServer`.
52
+ * scoping still works. A multi-app production deployment overrides
53
+ * this by passing `appIdFromIdentity` on `createGguiServer`.
54
54
  */
55
55
  export const DEFAULT_BUILDER_APP_ID = 'builder';
56
56
  export function defaultAppIdFromIdentity(result) {
@@ -65,9 +65,9 @@ export function defaultAppIdFromIdentity(result) {
65
65
  result.identity.userId);
66
66
  }
67
67
  // `kind: 'app'` carries the appId directly — surfaced by API-key /
68
- // OAuth-bearer adapters (e.g. an ApiKeyAuthAdapter on a hosted
69
- // multi-tenant deployment). Falling through to DEFAULT_BUILDER_APP_ID
70
- // here would discard the very tenant id the adapter just proved.
68
+ // OAuth-bearer adapters (e.g. an API-key adapter proving an app-scoped
69
+ // bearer on a multi-app deployment). Falling through to DEFAULT_BUILDER_APP_ID
70
+ // here would discard the very app id the adapter just proved.
71
71
  if (result.identity.kind === 'app') {
72
72
  return result.identity.appId;
73
73
  }
@@ -65,7 +65,7 @@ export interface BuildMcpServerOptions {
65
65
  /**
66
66
  * Live-channel origins for the static shell's CSP declaration —
67
67
  * forwarded to `installMcpAppsOutbound`. Deployments that set no
68
- * `publicBaseUrl` (the cloud pod) pass their `wsUrl` + its ws→http
68
+ * `publicBaseUrl` (a hosted deployment) pass their `wsUrl` + its ws→http
69
69
  * origin flip here so the mounted iframe's `connect-src` covers the
70
70
  * SSE / HTTP-polling session API and the WebSocket; otherwise
71
71
  * cross-origin hosts CSP-block every network rung of the failover
@@ -121,8 +121,8 @@ export function mountConsoleBlueprintRoutes(opts) {
121
121
  code = out;
122
122
  }
123
123
  // Same default appId the CLI's pairing-authenticated /mcp
124
- // ingress resolves for single-tenant OSS — the render is
125
- // scoped to the same tenant.
124
+ // ingress resolves for single-app OSS — the render is
125
+ // scoped to the same app.
126
126
  const appId = DEFAULT_BUILDER_APP_ID;
127
127
  // Phase B: a render IS the addressable unit; the prior
128
128
  // (sessionId, stackItemId) pair collapses to a single
@@ -30,7 +30,7 @@
30
30
  * serve` instance; adding bearer auth here would block the
31
31
  * dev-page-is-usable claim without meaningful security gain.
32
32
  *
33
- * The render invocation uses `DEFAULT_BUILDER_APP_ID` for tenant
33
+ * The render invocation uses `DEFAULT_BUILDER_APP_ID` for app
34
34
  * scope — same well-known value the `/mcp` endpoint collapses to
35
35
  * in OSS single-user mode. Matches blueprint + vector scoping
36
36
  * applied by the generator / cache seams.
@@ -30,7 +30,7 @@
30
30
  * serve` instance; adding bearer auth here would block the
31
31
  * dev-page-is-usable claim without meaningful security gain.
32
32
  *
33
- * The render invocation uses `DEFAULT_BUILDER_APP_ID` for tenant
33
+ * The render invocation uses `DEFAULT_BUILDER_APP_ID` for app
34
34
  * scope — same well-known value the `/mcp` endpoint collapses to
35
35
  * in OSS single-user mode. Matches blueprint + vector scoping
36
36
  * applied by the generator / cache seams.
@@ -38,7 +38,7 @@ export function mountConsoleKeysRoutes(opts) {
38
38
  const { app, adminToken, pairing, logger } = opts;
39
39
  const requestHasAdminAuth = (req) => {
40
40
  // Header path — `Authorization: Bearer <token>`. Constant-time
41
- // compare not needed: this is single-tenant local-host with a
41
+ // compare not needed: this is single-operator local-host with a
42
42
  // local network attacker model; the token also has 72 bits of
43
43
  // entropy, so a timing-side-channel attack would still need
44
44
  // ~2^36 attempts on average to materialize. Skip the cost.
@@ -72,7 +72,7 @@ export function mountConsoleKeysRoutes(opts) {
72
72
  // For zero-config local-host, trust-proxy is OFF and req.secure
73
73
  // reflects the literal socket. Operators behind a tunnel with
74
74
  // TLS termination at the edge get the cookie WITHOUT Secure
75
- // (intended — the in-pod request is plaintext HTTP). Browsers
75
+ // (intended — the request reaching the server is plaintext HTTP). Browsers
76
76
  // still scope it to the origin via SameSite, which is the
77
77
  // primary CSRF protection here; Secure is a defense-in-depth
78
78
  // attribute, not load-bearing for this token.
@@ -4,7 +4,7 @@
4
4
  * - `gateMode: 'admin-token'` (default — OSS-personal):
5
5
  * gate accepts the admin bearer. Single global keyset; the
6
6
  * /settings UI lets the operator paste keys for everyone.
7
- * - `gateMode: 'auth-adapter'` (multi-tenant): gate
7
+ * - `gateMode: 'auth-adapter'` (multi-app): gate
8
8
  * calls the server's `AuthAdapter`. Each user's keys are
9
9
  * scoped by `scopeFromRequest` (default: `userId`/`appId`).
10
10
  *
@@ -4,7 +4,7 @@
4
4
  * - `gateMode: 'admin-token'` (default — OSS-personal):
5
5
  * gate accepts the admin bearer. Single global keyset; the
6
6
  * /settings UI lets the operator paste keys for everyone.
7
- * - `gateMode: 'auth-adapter'` (multi-tenant): gate
7
+ * - `gateMode: 'auth-adapter'` (multi-app): gate
8
8
  * calls the server's `AuthAdapter`. Each user's keys are
9
9
  * scoped by `scopeFromRequest` (default: `userId`/`appId`).
10
10
  *
@@ -103,7 +103,7 @@ export function mountConsoleLlmKeysRoutes(opts) {
103
103
  // admin-token → same shape as /keys (Bearer admin OR
104
104
  // ggui_console_admin cookie).
105
105
  // auth-adapter → calls `resolveIdentity(auth, req)`. `kind:'builder'`
106
- // is rejected with 401 — the multi-tenant posture
106
+ // is rejected with 401 — the multi-app posture
107
107
  // is meaningless without a real per-caller id.
108
108
  app.use("/ggui/console/llm-keys", (req, res, next) => {
109
109
  if (gateMode === "admin-token") {
@@ -113,14 +113,14 @@ export function mountConsoleLlmKeysRoutes(opts) {
113
113
  res.status(401).json({ error: "admin_auth_required" });
114
114
  return;
115
115
  }
116
- // 'auth-adapter' — the multi-tenant gate.
116
+ // 'auth-adapter' — the multi-app gate.
117
117
  resolveIdentity(auth, req)
118
118
  .then((identity) => {
119
119
  if (identity.identity.kind === "builder") {
120
120
  applyDevtoolSecurityHeaders(res);
121
121
  res.status(401).json({
122
- error: "tenant_required",
123
- message: "Multi-tenant /llm-keys requires an end-user or app identity. " +
122
+ error: "user_or_app_identity_required",
123
+ message: "Multi-app /llm-keys requires an end-user or app identity. " +
124
124
  'The configured AuthAdapter resolved kind:"builder" — pair a ' +
125
125
  'real user/app bearer or use providerKeysGate:"admin-token".',
126
126
  });
@@ -26,7 +26,7 @@
26
26
  * Scope: read-only on `/registry` (authoring happens on disk and the
27
27
  * server re-reads on boot; zero-config is an honest empty shape).
28
28
  * The cache/registry surfaces are scoped to `DEFAULT_BUILDER_APP_ID`
29
- * because the OSS server is single-tenant by construction — same
29
+ * because the OSS server is single-app by construction — same
30
30
  * scope the render handler writes to, so list/invalidate/clear see
31
31
  * what the real cache writes.
32
32
  *
@@ -26,7 +26,7 @@
26
26
  * Scope: read-only on `/registry` (authoring happens on disk and the
27
27
  * server re-reads on boot; zero-config is an honest empty shape).
28
28
  * The cache/registry surfaces are scoped to `DEFAULT_BUILDER_APP_ID`
29
- * because the OSS server is single-tenant by construction — same
29
+ * because the OSS server is single-app by construction — same
30
30
  * scope the render handler writes to, so list/invalidate/clear see
31
31
  * what the real cache writes.
32
32
  *
@@ -22,7 +22,7 @@
22
22
  * routes use — operator-only since the value persists to ggui.json,
23
23
  * which the OSS server treats as trusted manifest input. End-users
24
24
  * who paired into a render don't get to mutate the project's
25
- * theme. Multi-tenant deployments may relax this in a follow-up by
25
+ * theme. Multi-app deployments may relax this in a follow-up by
26
26
  * scoping overrides per user (overrides become server state, not
27
27
  * file state).
28
28
  */
@@ -22,7 +22,7 @@
22
22
  * routes use — operator-only since the value persists to ggui.json,
23
23
  * which the OSS server treats as trusted manifest input. End-users
24
24
  * who paired into a render don't get to mutate the project's
25
- * theme. Multi-tenant deployments may relax this in a follow-up by
25
+ * theme. Multi-app deployments may relax this in a follow-up by
26
26
  * scoping overrides per user (overrides become server state, not
27
27
  * file state).
28
28
  */
@@ -4,7 +4,7 @@
4
4
  * ggui serves exactly TWO MCP surfaces:
5
5
  *
6
6
  * - **Data plane** — the agent routes (`universalMcpPath`, plus the
7
- * per-tenant `${pathPrefix}/:appId` variant when configured). Carries
7
+ * per-app `${pathPrefix}/:appId` variant when configured). Carries
8
8
  * the `agent` + `runtime` audiences: the tools an agent calls while a
9
9
  * session is running.
10
10
  * - **Control plane** — this service. Carries the `protocol` + `ops`
@@ -93,7 +93,7 @@ export declare function filterHandlersByAudience(set: ReadonlyArray<AnyHandler>,
93
93
  * ruling (ggui#525, 2026-08-16). The argument that it is safe on the
94
94
  * first call: the save is idempotent under the name-collapse rule (same
95
95
  * slug ⇒ one row, a repeat is a no-op), it writes only to the CALLER's
96
- * own library (no cross-tenant or account-wide effect), and its caller
96
+ * own library (no cross-app or account-wide effect), and its caller
97
97
  * is the console helper agent auto-saving after a render — the
98
98
  * "confirm" it performed was an agent self-confirm with no human in
99
99
  * the loop, which bought no safety and cost one extra tool round trip
@@ -116,7 +116,7 @@ export declare function stripAudience<I extends ZodRawShape, O extends ZodRawSha
116
116
  * credential — or presented one the adapter rejected. An un-gated ops
117
117
  * handler would then run against that synthetic rather than refusing,
118
118
  * which is how a caller with no account would read and write a phantom
119
- * shared tenant.
119
+ * shared app.
120
120
  *
121
121
  * The gate is on `ctx.authSource`, not on which identity FIELDS are
122
122
  * populated: every deployment tier proves identity differently
@@ -4,7 +4,7 @@
4
4
  * ggui serves exactly TWO MCP surfaces:
5
5
  *
6
6
  * - **Data plane** — the agent routes (`universalMcpPath`, plus the
7
- * per-tenant `${pathPrefix}/:appId` variant when configured). Carries
7
+ * per-app `${pathPrefix}/:appId` variant when configured). Carries
8
8
  * the `agent` + `runtime` audiences: the tools an agent calls while a
9
9
  * session is running.
10
10
  * - **Control plane** — this service. Carries the `protocol` + `ops`
@@ -94,7 +94,7 @@ export function filterHandlersByAudience(set, allowed) {
94
94
  * ruling (ggui#525, 2026-08-16). The argument that it is safe on the
95
95
  * first call: the save is idempotent under the name-collapse rule (same
96
96
  * slug ⇒ one row, a repeat is a no-op), it writes only to the CALLER's
97
- * own library (no cross-tenant or account-wide effect), and its caller
97
+ * own library (no cross-app or account-wide effect), and its caller
98
98
  * is the console helper agent auto-saving after a render — the
99
99
  * "confirm" it performed was an agent self-confirm with no human in
100
100
  * the loop, which bought no safety and cost one extra tool round trip
@@ -137,7 +137,7 @@ export function stripAudience(h) {
137
137
  * credential — or presented one the adapter rejected. An un-gated ops
138
138
  * handler would then run against that synthetic rather than refusing,
139
139
  * which is how a caller with no account would read and write a phantom
140
- * shared tenant.
140
+ * shared app.
141
141
  *
142
142
  * The gate is on `ctx.authSource`, not on which identity FIELDS are
143
143
  * populated: every deployment tier proves identity differently
@@ -72,7 +72,7 @@ export function attachSocketRouter(wss, deps) {
72
72
  releasePending(ws);
73
73
  }
74
74
  /**
75
- * Tenancy guard for client-emitted observation messages
75
+ * Binding guard for client-emitted observation messages
76
76
  * (`host_context_observed` today). Returns `false`
77
77
  * AND emits the appropriate error frame when:
78
78
  *
@@ -80,7 +80,7 @@ export function attachSocketRouter(wss, deps) {
80
80
  * - payload.sessionId doesn't match the subscriber binding
81
81
  * (SESSION_MISMATCH)
82
82
  *
83
- * Subscriber binding is the authoritative tenancy scope. The wire
83
+ * Subscriber binding is the authoritative scope. The wire
84
84
  * payload's sessionId is belt-and-suspenders so the error message
85
85
  * can be specific; appId narrows transparently via the binding.
86
86
  */
@@ -138,7 +138,7 @@ export interface SubscribeDeps {
138
138
  readonly bootstrap?: GguiSessionChannelBootstrap;
139
139
  /** Console cookie plumbing — see `GguiSessionChannelOptions.cookieAuth`. */
140
140
  readonly cookieAuth?: GguiSessionChannelCookieAuth;
141
- /** Identity → tenant appId mapping — see `GguiSessionChannelOptions.appIdFromIdentity`. */
141
+ /** Identity → appId mapping — see `GguiSessionChannelOptions.appIdFromIdentity`. */
142
142
  readonly appIdFromIdentity?: (result: AuthResult) => string;
143
143
  /** Version-handshake policy — see `GguiSessionChannelOptions.versionPolicy`. */
144
144
  readonly versionPolicy?: "advisory" | "reject";
@@ -1 +1 @@
1
- {"version":3,"file":"subscribe.d.ts","sourceRoot":"","sources":["../../src/ggui-session-channel/subscribe.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"subscribe.d.ts","sourceRoot":"","sources":["../../src/ggui-session-channel/subscribe.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACV,WAAW,EACX,UAAU,EACV,gBAAgB,EAChB,uBAAuB,EACvB,iBAAiB,EACjB,YAAY,EACb,MAAM,0BAA0B,CAAC;AAGlC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAMpC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAGV,cAAc,EAEf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAErE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH;;;;;;;;;;GAUG;AACH,MAAM,MAAM,uCAAuC,GAC/C;IACE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,GACD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,CAAA;CAAE,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,MAAM,wCAAwC,GAChD;IACE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B,GACD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAAA;CAAE,CAAC;AAEzE,MAAM,WAAW,2BAA2B;IAC1C;;;;;;;;OAQG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,uCAAuC,CAAC;IAC/D;;;;OAIG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5D;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,wCAAwC,CAAC;CAClE;AAED;;;;GAIG;AACH,MAAM,WAAW,4BAA4B;IAC3C;;;;OAIG;IACH,UAAU,CAAC,OAAO,EAAE,OAAO,WAAW,EAAE,mBAAmB,GAAG,MAAM,GAAG,IAAI,CAAC;IAC5E;;;;OAIG;IACH,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAC1E;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC;IACvC,sEAAsE;IACtE,QAAQ,CAAC,YAAY,EAAE,uBAAuB,CAAC;IAC/C,mEAAmE;IACnE,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,iFAAiF;IACjF,QAAQ,CAAC,SAAS,CAAC,EAAE,2BAA2B,CAAC;IACjD,4EAA4E;IAC5E,QAAQ,CAAC,UAAU,CAAC,EAAE,4BAA4B,CAAC;IACnD,oFAAoF;IACpF,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,MAAM,CAAC;IAC5D,gFAAgF;IAChF,QAAQ,CAAC,aAAa,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAC;IAC/C,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;IAC1C,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC,UAAU,CAAC,CAAC;IACnD,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAC,YAAY,CAAC,CAAC;CACxD;AAED;;;;;;GAMG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,mDAAmD;IACnD,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,wDAAwD;IACxD,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC9B,qEAAqE;IACrE,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,+EAA+E;IAC/E,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,wEAAwE;IACxE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,uEAAuE;IACvE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,iEAAiE;IACjE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC,GAAG,CACA;IACE,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,EAAE,SAAS,CAAC;CACxB,GACD;IAAE,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAA;CAAE,CAChC,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAChC;;;;;OAKG;IACH,0BAA0B,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACtE,iEAAiE;IACjE,eAAe,CACb,EAAE,EAAE,SAAS,EACb,QAAQ,EAAE,UAAU,EACpB,OAAO,EAAE,gBAAgB,GAAG;QAAE,IAAI,EAAE,WAAW,CAAA;KAAE,EACjD,WAAW,CAAC,EAAE;QAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GACnE,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB;;;;;;;;;;;OAWG;IACH,iBAAiB,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC,CAAC;CAC1F;AAkBD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,aAAa,GAAG,iBAAiB,CA+gB9E"}
@@ -238,8 +238,8 @@ export function createSubscribeHandlers(deps) {
238
238
  // cookie binds the same pair), else the deployment's identity →
239
239
  // appId mapping (`appIdFromIdentity`, defaulting to
240
240
  // `defaultAppIdFromIdentity`). The resolved value then flows
241
- // through the EXISTING tenancy gate + provisioning below — never
242
- // an `undefined` tenant on a stored row.
241
+ // through the EXISTING app-scope gate + provisioning below — never
242
+ // an `undefined` appId on a stored row.
243
243
  const effectiveAppId = payload.appId ??
244
244
  tokenBoundAppId ??
245
245
  cookieBound?.appId ??
@@ -14,7 +14,7 @@
14
14
  * Owns the per-render subscriber counter that drives the
15
15
  * `onFirstSubscriber` / `onLastSubscriberGone` 0↔1 transition hooks —
16
16
  * no other module reads it. The hooks fire for SSE attaches too:
17
- * hosted cross-pod pubsub scoping keys on "does this pod hold any
17
+ * hosted cross-replica pubsub scoping keys on "does this replica hold any
18
18
  * subscriber for this render", regardless of transport.
19
19
  */
20
20
  import type { WebSocket } from "ws";
@@ -14,7 +14,7 @@
14
14
  * Owns the per-render subscriber counter that drives the
15
15
  * `onFirstSubscriber` / `onLastSubscriberGone` 0↔1 transition hooks —
16
16
  * no other module reads it. The hooks fire for SSE attaches too:
17
- * hosted cross-pod pubsub scoping keys on "does this pod hold any
17
+ * hosted cross-replica pubsub scoping keys on "does this replica hold any
18
18
  * subscriber for this render", regardless of transport.
19
19
  */
20
20
  export function createSubscriberLifecycle(deps) {
@@ -159,7 +159,7 @@ export interface GguiSessionChannelOptions {
159
159
  */
160
160
  readonly auth: AuthAdapter;
161
161
  /**
162
- * Maps resolved identity → tenant appId for subscribes that omit
162
+ * Maps resolved identity → the appId for subscribes that omit
163
163
  * `payload.appId` (SPEC §12.2 identity-default resolution). Defaults
164
164
  * to `defaultAppIdFromIdentity` — same mapping the `/mcp` endpoint
165
165
  * uses. Token-bound subscribes (wsToken / console cookie) never
@@ -348,12 +348,12 @@ export interface GguiSessionChannelOptions {
348
348
  * render connects to this server instance).
349
349
  *
350
350
  * Hosted deployments use this to lazily SUBSCRIBE to the per-render
351
- * cross-pod broadcast channel (e.g. Redis pub/sub); OSS has no use
351
+ * cross-replica broadcast channel (e.g. Redis pub/sub); OSS has no use
352
352
  * for it (in-process broadcasts already route via
353
353
  * {@link GguiSessionChannelServer.sendPropsUpdate}). Bounding pubsub
354
- * fan-in to only renders a pod actually holds connections for is a
354
+ * fan-in to only renders a replica actually holds connections for is a
355
355
  * correctness requirement, not an optimization — without it every
356
- * pod receives every other pod's broadcast for every active render.
356
+ * replica receives every other replica's broadcast for every active render.
357
357
  *
358
358
  * Best-effort: a thrown callback is logged and swallowed.
359
359
  * `register()` MUST NOT fail because of a hook error or the
@@ -339,18 +339,18 @@ export function createGguiSessionChannelServer(opts) {
339
339
  // Close code 1012 ("Service Restart", RFC 6455 + IANA registry)
340
340
  // signals to clients that the server is restarting and they
341
341
  // should reconnect immediately rather than treat the close as
342
- // permanent. The pod's K8s rolling update fits this exactly:
343
- // a new pod is already accepting connections behind the same
342
+ // permanent. A rolling update of the deployment fits this exactly:
343
+ // a new replica is already accepting connections behind the same
344
344
  // load balancer; iframe-runtime + console viewer should
345
345
  // reconnect on next message instead of blinking "disconnected".
346
346
  // Code 1001 (used previously) means "endpoint going away" with
347
- // no reconnect hint — semantically inaccurate for the pod-roll
347
+ // no reconnect hint — semantically inaccurate for the rolling-update
348
348
  // case and the wrong signal for client reconnect logic.
349
349
  const sessionIds = new Set();
350
350
  for (const sub of wsSubscribers) {
351
351
  sessionIds.add(sub.sessionId);
352
352
  // Transport-neutral shutdown: WS maps to close(1012), SSE ends
353
- // the response so EventSource auto-reconnects to the new pod —
353
+ // the response so EventSource auto-reconnects to the new replica —
354
354
  // exactly the 1012 semantics. `sink.end` is best-effort by
355
355
  // contract (never throws on an already-closing transport).
356
356
  sub.sink.end("service_restart");
@@ -14,16 +14,17 @@
14
14
  * 401 otherwise (with `WWW-Authenticate` when
15
15
  * OAuth is enabled).
16
16
  *
17
- * Why live and health are separate: K8s livenessProbe + readinessProbe
18
- * have distinct semantics. Liveness asks "is the process alive?" and
19
- * a failure tells the kubelet to RESTART the pod. Readiness asks "is
20
- * the pod ready to receive traffic?" and a failure tells the service
17
+ * Why live and health are separate: an orchestrator's liveness and
18
+ * readiness probes have distinct semantics. Liveness asks "is the process alive?" and
19
+ * a failure tells the orchestrator to RESTART the container. Readiness
20
+ * asks "is the replica ready to receive traffic?" and a failure tells the service
21
21
  * to STOP ROUTING. Tying both probes to a single endpoint that gates
22
22
  * on dependency health (Redis, DDB, RAG) means a transient upstream
23
- * blip kills the pod entirely instead of just removing it from
23
+ * blip kills the replica entirely instead of just removing it from
24
24
  * rotation.
25
25
  *
26
- * Self-hoster wiring (K8s):
26
+ * Self-hoster wiring (probe-spec shape; any orchestrator with separate
27
+ * liveness and readiness probes works the same way):
27
28
  *
28
29
  * livenessProbe: { httpGet: { path: '/ggui/live', port } }
29
30
  * readinessProbe: { httpGet: { path: '/ggui/health', port } }
@@ -1 +1 @@
1
- {"version":3,"file":"health-routes.d.ts","sourceRoot":"","sources":["../src/health-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;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;AAW1C,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;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,cAAc,CAAC,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,CAmJ1D"}
1
+ {"version":3,"file":"health-routes.d.ts","sourceRoot":"","sources":["../src/health-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;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;AAW1C,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;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,cAAc,CAAC,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,CAmJ1D"}
@@ -14,16 +14,17 @@
14
14
  * 401 otherwise (with `WWW-Authenticate` when
15
15
  * OAuth is enabled).
16
16
  *
17
- * Why live and health are separate: K8s livenessProbe + readinessProbe
18
- * have distinct semantics. Liveness asks "is the process alive?" and
19
- * a failure tells the kubelet to RESTART the pod. Readiness asks "is
20
- * the pod ready to receive traffic?" and a failure tells the service
17
+ * Why live and health are separate: an orchestrator's liveness and
18
+ * readiness probes have distinct semantics. Liveness asks "is the process alive?" and
19
+ * a failure tells the orchestrator to RESTART the container. Readiness
20
+ * asks "is the replica ready to receive traffic?" and a failure tells the service
21
21
  * to STOP ROUTING. Tying both probes to a single endpoint that gates
22
22
  * on dependency health (Redis, DDB, RAG) means a transient upstream
23
- * blip kills the pod entirely instead of just removing it from
23
+ * blip kills the replica entirely instead of just removing it from
24
24
  * rotation.
25
25
  *
26
- * Self-hoster wiring (K8s):
26
+ * Self-hoster wiring (probe-spec shape; any orchestrator with separate
27
+ * liveness and readiness probes works the same way):
27
28
  *
28
29
  * livenessProbe: { httpGet: { path: '/ggui/live', port } }
29
30
  * readinessProbe: { httpGet: { path: '/ggui/health', port } }
@@ -31,7 +32,7 @@
31
32
  import { resolveIdentity, UnauthenticatedError } from "./auth.js";
32
33
  import { buildWwwAuthenticate, resolveIssuerUrl } from "./oauth.js";
33
34
  /**
34
- * 1s per-check timeout — a hung dependency must not block the K8s
35
+ * 1s per-check timeout — a hung dependency must not block the orchestrator's
35
36
  * readiness probe (/ggui/health), which itself runs on a short period.
36
37
  * A timeout is treated as a failed check; the dependency is degraded
37
38
  * either way.
package/dist/index.js CHANGED
@@ -44,7 +44,7 @@ export { buildControlService, CONTROL_PATH, filterHandlersByAudience, SINGLE_CAL
44
44
  // one derivation, no drift against the route the factory mounts.
45
45
  export { computeRuntimeBundleHash, insertRuntimeBundleHash, resolveHashedRuntimeBundleUrl, resolveRuntimeBundleHash, } from './runtime-bundle-hash.js';
46
46
  // Strict-CSP module-variant delivery (ggui#522 slice 2). The minter is
47
- // exported for the same composed-handler deployments: a pod that binds
47
+ // exported for the same composed-handler deployments: a deployment that binds
48
48
  // `codeStore`/`codeBaseUrl` on its own render tool builds the minter
49
49
  // from `resolveRuntimeBundleHash()` so its `codeModuleUrl`s name the
50
50
  // exact variant family the co-resident factory routes serve.