@ggui-ai/mcp-server 0.25.0 → 0.26.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/README.md +2 -2
- package/dist/api-renders-routes.d.ts +46 -5
- package/dist/api-renders-routes.d.ts.map +1 -1
- package/dist/api-renders-routes.js +98 -39
- package/dist/api-renders-stream-route.d.ts +2 -1
- package/dist/api-renders-stream-route.d.ts.map +1 -1
- package/dist/api-renders-stream-route.js +14 -2
- package/dist/build-mcp.d.ts +16 -0
- package/dist/build-mcp.d.ts.map +1 -1
- package/dist/build-mcp.js +48 -20
- package/dist/console-auth.d.ts +10 -10
- package/dist/console-auth.d.ts.map +1 -1
- package/dist/first-seen.d.ts +14 -0
- package/dist/first-seen.d.ts.map +1 -0
- package/dist/first-seen.js +19 -0
- package/dist/ggui-session-channel/action-ingress.d.ts.map +1 -1
- package/dist/ggui-session-channel/action-ingress.js +96 -8
- package/dist/ggui-session-channel/channel-subscriptions.d.ts +0 -1
- package/dist/ggui-session-channel/channel-subscriptions.d.ts.map +1 -1
- package/dist/ggui-session-channel/channel-subscriptions.js +4 -1
- package/dist/ggui-session-channel/internal-types.d.ts +20 -12
- package/dist/ggui-session-channel/internal-types.d.ts.map +1 -1
- package/dist/ggui-session-channel/outbound.d.ts.map +1 -1
- package/dist/ggui-session-channel/outbound.js +18 -6
- package/dist/ggui-session-channel/stream-epoch.d.ts +61 -0
- package/dist/ggui-session-channel/stream-epoch.d.ts.map +1 -0
- package/dist/ggui-session-channel/stream-epoch.js +47 -0
- package/dist/ggui-session-channel/subscribe.d.ts +29 -17
- package/dist/ggui-session-channel/subscribe.d.ts.map +1 -1
- package/dist/ggui-session-channel/subscribe.js +247 -124
- package/dist/ggui-session-channel/subscriber-lifecycle.d.ts.map +1 -1
- package/dist/ggui-session-channel/subscriber-lifecycle.js +17 -7
- package/dist/ggui-session-channel.d.ts +13 -5
- package/dist/ggui-session-channel.d.ts.map +1 -1
- package/dist/ggui-session-channel.js +2 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/instructions-presets.d.ts +22 -21
- package/dist/instructions-presets.d.ts.map +1 -1
- package/dist/instructions-presets.js +38 -38
- package/dist/llm-backed-negotiator.d.ts +1 -36
- package/dist/llm-backed-negotiator.d.ts.map +1 -1
- package/dist/llm-backed-negotiator.js +0 -196
- package/dist/mcp-apps-outbound.d.ts +39 -90
- package/dist/mcp-apps-outbound.d.ts.map +1 -1
- package/dist/mcp-apps-outbound.js +45 -3
- package/dist/mcp-endpoint-routes.d.ts.map +1 -1
- package/dist/mcp-endpoint-routes.js +4 -1
- package/dist/server.d.ts +108 -33
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +181 -48
- package/dist/storage.d.ts +9 -1
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +4 -3
- package/dist/view-proof-gate.d.ts +96 -0
- package/dist/view-proof-gate.d.ts.map +1 -0
- package/dist/view-proof-gate.js +167 -0
- package/package.json +14 -15
package/dist/server.js
CHANGED
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
*/
|
|
40
40
|
import { CONSOLE_DIST_DIR } from "@ggui-ai/console/server";
|
|
41
41
|
import { RUNTIME_BUNDLE_FILE, RUNTIME_BUNDLE_URL_PATH, RUNTIME_SHIMS_DIR, RUNTIME_SHIMS_URL_PREFIX, } from "@ggui-ai/iframe-runtime/server";
|
|
42
|
-
import {
|
|
42
|
+
import { isTokenRegisteringAuthAdapter, DEFAULT_WS_TOKEN_REFRESH_WINDOW_MULTIPLIER, DEFAULT_WS_TOKEN_TTL_SEC, mintViewRoot, mintWsToken, verifyWsTokenSignature, verifyToken, } from "@ggui-ai/mcp-server-core";
|
|
43
43
|
import { createInMemoryBlueprintSearch, createInMemoryGeneratorRegistry, FixedWindowRateLimiter, InMemoryActiveConsumerRegistry, InMemoryAppMetadataStore, InMemoryAuthAdapter, InMemoryBlueprintIndex, InMemoryBlueprintStore, InMemoryKeyValueStore, InMemoryPairingService, InMemoryPendingEventConsumer, InMemoryQuotaStore, InMemoryGguiSessionStore, InMemoryGguiSessionStreamBuffer, InMemoryVectorStore, MockEmbeddingProvider, NoopAuditSink, NoopRateLimiter, NoopTelemetrySink, } from "@ggui-ai/mcp-server-core/in-memory";
|
|
44
44
|
import { createGguiListGadgetsHandler, createGguiListThemesHandler, } from "@ggui-ai/mcp-server-handlers/app-discovery";
|
|
45
45
|
import { createDescribeBlueprintFormatHandler, createDescribeDataContractFormatHandler, createGetBlueprintBoilerplateHandler, createGetExampleBlueprintsHandler, createListAvailablePrimitivesHandler, createListFeaturedBlueprintsHandler, createRenderBlueprintHandler, createSearchBlueprintsHandler, createValidateBlueprintHandler, } from "@ggui-ai/mcp-server-handlers/blueprints";
|
|
@@ -68,10 +68,11 @@ import { BoundedValidatorTraceSink, mountConsoleValidatorRoutes } from "./consol
|
|
|
68
68
|
// `ggui_ops_get_credit_balance`'s pattern).
|
|
69
69
|
import { createCreateAppHandler, createDeleteAppHandler, createListAppsHandler, createSetAppThemeHandler, createSetDefaultAppHandler, createUpdateAppHandler, } from "@ggui-ai/mcp-server-handlers/ops-apps";
|
|
70
70
|
import { fontFaceRules, validateOverlayCoverage } from "@ggui-ai/design/themes";
|
|
71
|
-
import { createGguiConsumeHandler, createGguiDeclareToolCatalogHandler, createGguiEmitHandler, createGguiGetRenderSourceHandler, createGguiGetSessionHandler, createGguiHandshakeHandler, createGguiListSessionsHandler, createGguiRefreshWsTokenHandler, createGguiRenderHandler, createGguiRuntimePullHandler, createGguiRuntimeTelemetryHandler, createGguiSubmitActionHandler, createGguiSyncContextHandler, createGguiUpdateHandler, createGguiAmendHandler, InMemoryToolIdentityCatalogStore, createInMemoryProvisionalPreviewRegistry, } from "@ggui-ai/mcp-server-handlers/renders";
|
|
71
|
+
import { createGguiConsumeHandler, createGguiDeclareToolCatalogHandler, createGguiEmitHandler, createGguiGetRenderSourceHandler, createGguiGetSessionHandler, createGguiHandshakeHandler, createGguiListSessionsHandler, createGguiRefreshWsTokenHandler, createGguiRenderHandler, createGguiReportRenderFailureHandler, createGguiRuntimePullHandler, createGguiRuntimeTelemetryHandler, createGguiSubmitActionHandler, createGguiSyncContextHandler, createGguiUpdateHandler, createGguiAmendHandler, InMemoryToolIdentityCatalogStore, createInMemoryProvisionalPreviewRegistry, } from "@ggui-ai/mcp-server-handlers/renders";
|
|
72
72
|
import { DEFAULT_ADMIN_BLUEPRINTS_PATH, mountAdminBlueprintsTransport, } from "./admin-blueprints-transport.js";
|
|
73
73
|
import { mountAdminOAuthProvidersTransport } from "./admin-oauth-providers-transport.js";
|
|
74
74
|
import { DEFAULT_BUILDER_APP_ID, defaultAppIdFromIdentity } from "./auth.js";
|
|
75
|
+
import { assertViewProofDeclarations, createViewProofGate, unverifiableViewProofTools, } from "./view-proof-gate.js";
|
|
75
76
|
import { mountMcpEndpoints } from "./mcp-endpoint-routes.js";
|
|
76
77
|
import { mountApiRendersRoutes } from "./api-renders-routes.js";
|
|
77
78
|
import { mountApiRendersStreamRoute } from "./api-renders-stream-route.js";
|
|
@@ -96,7 +97,7 @@ import { computeRuntimeBundleHash, insertRuntimeBundleHash, } from "./runtime-bu
|
|
|
96
97
|
import { createCsrfMiddleware, mountCsrfTokenRoute } from "./csrf-middleware.js";
|
|
97
98
|
import { mountEmailLoginRoutes } from "./email-login.js";
|
|
98
99
|
import { resolveMcpInstructions } from "./instructions-presets.js";
|
|
99
|
-
import {
|
|
100
|
+
import { createLlmBackedHandshakeNegotiator } from "./llm-backed-negotiator.js";
|
|
100
101
|
import { createConsoleLogger } from "./logger.js";
|
|
101
102
|
import { buildControlService, CONTROL_PATH } from "./control-service.js";
|
|
102
103
|
import { createBrowserCorsMiddleware, createPreflightFallback } from "./browser-cors.js";
|
|
@@ -230,6 +231,9 @@ export function buildOpsBlueprintHandlers(input) {
|
|
|
230
231
|
}));
|
|
231
232
|
handlers.push(createGguiOpsDeleteBlueprintHandler({
|
|
232
233
|
blueprintStore: bundle.blueprintStore,
|
|
234
|
+
// ggui#1541 — the registry generate and register mirror into, so a
|
|
235
|
+
// delete takes the blueprint out of the handshake's reuse too.
|
|
236
|
+
...(bundle.cacheRegistry ? { cacheRegistry: bundle.cacheRegistry } : {}),
|
|
233
237
|
authorizeAppAccess: bundle.authorizeAppAccess,
|
|
234
238
|
}));
|
|
235
239
|
return handlers;
|
|
@@ -362,6 +366,15 @@ export function defaultHandlers(deps) {
|
|
|
362
366
|
handlers.push(createGguiRuntimeTelemetryHandler({
|
|
363
367
|
...(deps.logger ? { logger: deps.logger } : {}),
|
|
364
368
|
}));
|
|
369
|
+
// `ggui_runtime_report_render_failure` (ggui#1609) — a card whose render
|
|
370
|
+
// failed says so, for the session its view proof binds. Unlike
|
|
371
|
+
// telemetry it is recorded, so its session is proven, never claimed;
|
|
372
|
+
// this server names each proven report (`render_failed`) and stores
|
|
373
|
+
// nothing — a deployment that keeps a per-session mark supplies
|
|
374
|
+
// `recordRenderFailure` when it composes its own handler set.
|
|
375
|
+
handlers.push(createGguiReportRenderFailureHandler({
|
|
376
|
+
renderStore: deps.render.renderStore,
|
|
377
|
+
}));
|
|
365
378
|
// `ggui_runtime_refresh_ws_token` — the authorized re-mint of a
|
|
366
379
|
// view's live credential (ggui#1496 part B). Registered only when the
|
|
367
380
|
// deployment can both verify an envelope and mint a credential;
|
|
@@ -450,7 +463,13 @@ export function defaultHandlers(deps) {
|
|
|
450
463
|
// Bootstrap-emission deps mirror render so MCP Apps hosts that
|
|
451
464
|
// forward `ui/notifications/tool-result` via postMessage can
|
|
452
465
|
// re-apply patched props on the live mount without a WS round-trip.
|
|
453
|
-
|
|
466
|
+
// The result door issues a view key when a key-issuing minter is
|
|
467
|
+
// wired (ggui#1415); otherwise it mints the live credential alone.
|
|
468
|
+
...(deps.update.mintViewRoot
|
|
469
|
+
? { mintWsToken: deps.update.mintViewRoot }
|
|
470
|
+
: deps.update.mintBootstrap
|
|
471
|
+
? { mintWsToken: deps.update.mintBootstrap }
|
|
472
|
+
: {}),
|
|
454
473
|
...(deps.update.runtimeUrl !== undefined ? { runtimeUrl: deps.update.runtimeUrl } : {}),
|
|
455
474
|
...(deps.update.sessionApiBaseUrl !== undefined
|
|
456
475
|
? { sessionApiBaseUrl: deps.update.sessionApiBaseUrl }
|
|
@@ -634,7 +653,13 @@ export function defaultHandlers(deps) {
|
|
|
634
653
|
...(deps.render.streamWebSocketLocalTools !== undefined
|
|
635
654
|
? { streamWebSocketLocalTools: deps.render.streamWebSocketLocalTools }
|
|
636
655
|
: {}),
|
|
637
|
-
|
|
656
|
+
// The result door issues a view key when a key-issuing minter is
|
|
657
|
+
// wired (ggui#1415); otherwise it mints the live credential alone.
|
|
658
|
+
...(deps.render.mintViewRoot
|
|
659
|
+
? { mintWsToken: deps.render.mintViewRoot }
|
|
660
|
+
: deps.render.mintBootstrap
|
|
661
|
+
? { mintWsToken: deps.render.mintBootstrap }
|
|
662
|
+
: {}),
|
|
638
663
|
...(deps.render.runtimeUrl !== undefined ? { runtimeUrl: deps.render.runtimeUrl } : {}),
|
|
639
664
|
...(deps.render.sessionApiBaseUrl !== undefined
|
|
640
665
|
? { sessionApiBaseUrl: deps.render.sessionApiBaseUrl }
|
|
@@ -750,6 +775,35 @@ export function buildOpsBundleHandlers(deps) {
|
|
|
750
775
|
}
|
|
751
776
|
return handlers;
|
|
752
777
|
}
|
|
778
|
+
/**
|
|
779
|
+
* How long {@link GguiServer.close} lets active connections finish before
|
|
780
|
+
* it ends them (ggui#1631), in milliseconds.
|
|
781
|
+
*/
|
|
782
|
+
export const DEFAULT_CLOSE_GRACE_MS = 5000;
|
|
783
|
+
/**
|
|
784
|
+
* The ws-token TTL and refresh window a server mints with (ggui#1496 part
|
|
785
|
+
* B). Both are positive whole seconds, and the window is at least the TTL:
|
|
786
|
+
* then every token this server mints, root and renewal alike, is past its
|
|
787
|
+
* `exp` by `rootIat + window`, so every gate refuses it in the same second.
|
|
788
|
+
* (A token minted while the window was longer, or by a server sharing the
|
|
789
|
+
* secret with a longer window, can outlive that second on the other gates;
|
|
790
|
+
* only `/state` refuses it.)
|
|
791
|
+
*/
|
|
792
|
+
function resolveWsTokenLifetimes(opts) {
|
|
793
|
+
const wholePositive = (v) => Number.isInteger(v) && v > 0;
|
|
794
|
+
const ttlSec = opts.wsTokenTtlSec ?? DEFAULT_WS_TOKEN_TTL_SEC;
|
|
795
|
+
if (!wholePositive(ttlSec)) {
|
|
796
|
+
throw new Error(`createGguiServer: wsTokenTtlSec must be a positive whole number of seconds (got ${String(ttlSec)}).`);
|
|
797
|
+
}
|
|
798
|
+
const windowSec = opts.wsTokenRefreshWindowSec ?? DEFAULT_WS_TOKEN_REFRESH_WINDOW_MULTIPLIER * ttlSec;
|
|
799
|
+
if (!wholePositive(windowSec)) {
|
|
800
|
+
throw new Error(`createGguiServer: wsTokenRefreshWindowSec must be a positive whole number of seconds (got ${String(windowSec)}).`);
|
|
801
|
+
}
|
|
802
|
+
if (windowSec < ttlSec) {
|
|
803
|
+
throw new Error(`createGguiServer: wsTokenRefreshWindowSec (${windowSec}) must be at least wsTokenTtlSec (${ttlSec}); a shorter window would let a root token outlive its own renewal chain.`);
|
|
804
|
+
}
|
|
805
|
+
return { ttlSec, windowSec };
|
|
806
|
+
}
|
|
753
807
|
/**
|
|
754
808
|
* Build a runnable OSS MCP server. Every option has a sensible default
|
|
755
809
|
* so `createGguiServer()` with no arguments boots a working in-memory
|
|
@@ -759,6 +813,11 @@ export function createGguiServer(opts = {}) {
|
|
|
759
813
|
if ((opts.perAppRouting?.perAppOnlySources?.length ?? 0) > 0 && !opts.perAppRouting?.authorize) {
|
|
760
814
|
throw new Error("createGguiServer: perAppRouting.perAppOnlySources lists credential sources that are valid only at their app's endpoint, but perAppRouting.authorize is not wired");
|
|
761
815
|
}
|
|
816
|
+
const { ttlSec: wsTokenTtlSec, windowSec: wsTokenRefreshWindowSec } = resolveWsTokenLifetimes(opts);
|
|
817
|
+
const keyedSince = opts.viewProof?.keyedSince;
|
|
818
|
+
if (keyedSince !== undefined && (!Number.isFinite(keyedSince) || keyedSince < 0)) {
|
|
819
|
+
throw new Error(`createGguiServer: viewProof.keyedSince must be a finite, non-negative epoch in milliseconds (got ${String(keyedSince)}).`);
|
|
820
|
+
}
|
|
762
821
|
const info = { ...DEFAULT_INFO, ...opts.info };
|
|
763
822
|
const logger = opts.logger ?? createConsoleLogger({ server: info.name });
|
|
764
823
|
const bodyLimit = opts.bodyLimit ?? "4mb";
|
|
@@ -973,12 +1032,23 @@ export function createGguiServer(opts = {}) {
|
|
|
973
1032
|
// (which always call this on the live-mode path) get clean strings
|
|
974
1033
|
// without per-callsite narrowing.
|
|
975
1034
|
let mintBootstrap;
|
|
1035
|
+
// The key-issuing doors' minters (ggui#1415): a root ws token stamped
|
|
1036
|
+
// with the secret's key id and the door, and the view key rooted in it.
|
|
1037
|
+
// Only the render/update results (`result`) and the data-plane read door
|
|
1038
|
+
// (`read`), on a read that issues the key, use them; every bearer door,
|
|
1039
|
+
// and every read that issues no key, mints through `mintBootstrap`.
|
|
1040
|
+
let mintResultViewRoot;
|
|
1041
|
+
let mintReadViewRoot;
|
|
1042
|
+
// `/state`'s one minter (ggui#1496 part B, slice 2): a possession renewal
|
|
1043
|
+
// that carries its chain's root forward. Every other door mints a root
|
|
1044
|
+
// through `mintBootstrap`.
|
|
1045
|
+
let mintChainedBootstrap;
|
|
976
1046
|
let channelBootstrap;
|
|
977
1047
|
// The authorized refresh's envelope check (ggui#1496 part B): signature,
|
|
978
1048
|
// shape and kind at ANY age, over the same secret the minter signs with.
|
|
979
1049
|
let wsTokenVerify;
|
|
980
|
-
// Shared HMAC secret for server-minted creds (bootstrap tokens,
|
|
981
|
-
//
|
|
1050
|
+
// Shared HMAC secret for server-minted creds (ws bootstrap tokens,
|
|
1051
|
+
// console cookies). Distinct `kind` claims
|
|
982
1052
|
// prevent cross-kind confusion; sharing the secret keeps the
|
|
983
1053
|
// config surface small and means operators rotate ONE value.
|
|
984
1054
|
// Resolved here so both the MCP Apps block and the console
|
|
@@ -999,7 +1069,7 @@ export function createGguiServer(opts = {}) {
|
|
|
999
1069
|
// from `@ggui-ai/mcp-server-core` for callers that need explicit
|
|
1000
1070
|
// single-use semantics (one-time-link share, etc.).
|
|
1001
1071
|
const syncMinter = (sessionId, appId) => {
|
|
1002
|
-
const { token, claims } = mintWsToken({ sessionId, appId }, secret);
|
|
1072
|
+
const { token, claims } = mintWsToken({ sessionId, appId, ttlSec: wsTokenTtlSec }, secret);
|
|
1003
1073
|
return {
|
|
1004
1074
|
wsUrl,
|
|
1005
1075
|
token,
|
|
@@ -1007,6 +1077,36 @@ export function createGguiServer(opts = {}) {
|
|
|
1007
1077
|
};
|
|
1008
1078
|
};
|
|
1009
1079
|
mintBootstrap = syncMinter;
|
|
1080
|
+
const viewRootMinter = (src) => (sessionId, appId) => {
|
|
1081
|
+
const minted = mintViewRoot({ sessionId, appId, ttlSec: wsTokenTtlSec, src }, secret);
|
|
1082
|
+
if (minted.viewKeyNotIssued !== undefined) {
|
|
1083
|
+
logger.info("view_key_not_issued", { sessionId, src, reason: minted.viewKeyNotIssued });
|
|
1084
|
+
}
|
|
1085
|
+
return {
|
|
1086
|
+
wsUrl,
|
|
1087
|
+
token: minted.token,
|
|
1088
|
+
expiresAt: new Date(minted.claims.exp * 1000).toISOString(),
|
|
1089
|
+
viewKey: minted.viewKey,
|
|
1090
|
+
};
|
|
1091
|
+
};
|
|
1092
|
+
mintResultViewRoot = viewRootMinter("result");
|
|
1093
|
+
mintReadViewRoot = viewRootMinter("read");
|
|
1094
|
+
// The renewal's `exp` is capped at `rootIat + window` by the mint
|
|
1095
|
+
// itself (`notAfter`), from the same clock read that stamps its `iat`.
|
|
1096
|
+
// No second left means nothing to renew (`undefined`, answered as the
|
|
1097
|
+
// ordinary expiry). That happens when the bound's second arrives between
|
|
1098
|
+
// the route's expiry check and this mint (the route awaits the store in
|
|
1099
|
+
// between), or for a token minted while the window was longer.
|
|
1100
|
+
mintChainedBootstrap = (sessionId, appId, rootIat) => {
|
|
1101
|
+
const { token, claims } = mintWsToken({ sessionId, appId, ttlSec: wsTokenTtlSec, rootIat, notAfter: rootIat + wsTokenRefreshWindowSec }, secret);
|
|
1102
|
+
if (claims.exp <= claims.iat)
|
|
1103
|
+
return undefined;
|
|
1104
|
+
return {
|
|
1105
|
+
wsUrl,
|
|
1106
|
+
token,
|
|
1107
|
+
expiresAt: new Date(claims.exp * 1000).toISOString(),
|
|
1108
|
+
};
|
|
1109
|
+
};
|
|
1010
1110
|
channelBootstrap = {
|
|
1011
1111
|
verify: (token) => {
|
|
1012
1112
|
const result = verifyToken(token, secret, "ws");
|
|
@@ -1025,15 +1125,16 @@ export function createGguiServer(opts = {}) {
|
|
|
1025
1125
|
}
|
|
1026
1126
|
return { ok: false, reason: "invalid" };
|
|
1027
1127
|
},
|
|
1028
|
-
issueSessionToken: (sessionId, appId) => {
|
|
1029
|
-
const { token } = mintSessionToken({ sessionId, appId }, secret);
|
|
1030
|
-
return token;
|
|
1031
|
-
},
|
|
1032
1128
|
};
|
|
1033
1129
|
wsTokenVerify = (envelope) => {
|
|
1034
1130
|
const result = verifyWsTokenSignature(envelope, secret);
|
|
1035
1131
|
return result.ok
|
|
1036
|
-
? {
|
|
1132
|
+
? {
|
|
1133
|
+
ok: true,
|
|
1134
|
+
sessionId: result.claims.sessionId,
|
|
1135
|
+
appId: result.claims.appId,
|
|
1136
|
+
rootIat: result.claims.rootIat ?? result.claims.iat,
|
|
1137
|
+
}
|
|
1037
1138
|
: { ok: false };
|
|
1038
1139
|
};
|
|
1039
1140
|
}
|
|
@@ -1140,7 +1241,6 @@ export function createGguiServer(opts = {}) {
|
|
|
1140
1241
|
new InMemoryBlueprintStore({
|
|
1141
1242
|
embeddingProvider: opts.embedding,
|
|
1142
1243
|
});
|
|
1143
|
-
const blueprintSelector = opts.blueprintSelector ?? createDeterministicBlueprintSelector();
|
|
1144
1244
|
// Auto-seed the multi-axis search against the resolved store.
|
|
1145
1245
|
// Type-narrowed at the call site: when the caller passed
|
|
1146
1246
|
// their own store we can't assume it implements `listAllForApp`,
|
|
@@ -1423,6 +1523,7 @@ export function createGguiServer(opts = {}) {
|
|
|
1423
1523
|
? { postFailureHook: opts.renderPostFailureHook }
|
|
1424
1524
|
: {}),
|
|
1425
1525
|
...(mintBootstrap ? { mintBootstrap } : {}),
|
|
1526
|
+
...(mintResultViewRoot ? { mintViewRoot: mintResultViewRoot } : {}),
|
|
1426
1527
|
// The authorized refresh's envelope check (ggui#1496 part B),
|
|
1427
1528
|
// over the same secret as `mintBootstrap`. Absent when MCP
|
|
1428
1529
|
// Apps isn't enabled; the tool isn't registered then.
|
|
@@ -1499,25 +1600,7 @@ export function createGguiServer(opts = {}) {
|
|
|
1499
1600
|
// every story-path render + emits `cache.hit /
|
|
1500
1601
|
// similarity / cachedBlueprintId / llmCallsAvoided` on
|
|
1501
1602
|
// structuredContent.
|
|
1502
|
-
...(generationWithCache
|
|
1503
|
-
? {
|
|
1504
|
-
generation: {
|
|
1505
|
-
...generationWithCache,
|
|
1506
|
-
// Thread an LLMCaller resolver into
|
|
1507
|
-
// render so the registry-based three-tier matcher
|
|
1508
|
-
// can fire its rerank step. Per-call resolution
|
|
1509
|
-
// because BYOK creds depend on ctx.
|
|
1510
|
-
resolveLlmCaller: async (ctx) => {
|
|
1511
|
-
if (!generationWithCache.resolveLlm)
|
|
1512
|
-
return null;
|
|
1513
|
-
const creds = await generationWithCache.resolveLlm(ctx);
|
|
1514
|
-
if (!creds)
|
|
1515
|
-
return null;
|
|
1516
|
-
return buildLlmCaller(creds.selection, creds.providerKey);
|
|
1517
|
-
},
|
|
1518
|
-
},
|
|
1519
|
-
}
|
|
1520
|
-
: {}),
|
|
1603
|
+
...(generationWithCache ? { generation: generationWithCache } : {}),
|
|
1521
1604
|
// Live-subscriber notifier. Late-binds to the
|
|
1522
1605
|
// GguiSessionChannelServer created further down (`channel`
|
|
1523
1606
|
// / `channelForHealth`) — the channel doesn't exist yet
|
|
@@ -1651,6 +1734,7 @@ export function createGguiServer(opts = {}) {
|
|
|
1651
1734
|
// resolvers keeps the two transports byte-identical at the
|
|
1652
1735
|
// bootstrap-projection boundary.
|
|
1653
1736
|
...(mintBootstrap ? { mintBootstrap } : {}),
|
|
1737
|
+
...(mintResultViewRoot ? { mintViewRoot: mintResultViewRoot } : {}),
|
|
1654
1738
|
// Function form: matches render so ggui_update emits the
|
|
1655
1739
|
// same absolute URL when the server sits behind a tunnel
|
|
1656
1740
|
// / reverse proxy.
|
|
@@ -1762,6 +1846,30 @@ export function createGguiServer(opts = {}) {
|
|
|
1762
1846
|
// construction instead of at first `tools/call`. The actual route
|
|
1763
1847
|
// mounting happens below alongside the canonical routes.
|
|
1764
1848
|
const mcpServices = validateMcpServices(opts.mcpServices);
|
|
1849
|
+
// ggui#1415 — the view-origin proof's measuring gate, over every handler
|
|
1850
|
+
// this server serves (the data and control planes, mounts, and isolated
|
|
1851
|
+
// services). Every declared proof must be one a view can sign (refused at
|
|
1852
|
+
// boot otherwise). The gate runs where views are keyed (MCP Apps on);
|
|
1853
|
+
// without it, a declared call's line says `viewProofUnverifiable`, named
|
|
1854
|
+
// once here.
|
|
1855
|
+
const servedHandlers = [...handlers, ...mcpServices.flatMap((service) => service.handlers)];
|
|
1856
|
+
assertViewProofDeclarations(servedHandlers);
|
|
1857
|
+
const viewProofGate = mcpAppsEnabled && sharedTokenSecret !== undefined
|
|
1858
|
+
? createViewProofGate({
|
|
1859
|
+
secret: sharedTokenSecret,
|
|
1860
|
+
sessionStore: renderStore,
|
|
1861
|
+
...(keyedSince !== undefined ? { keyedSince } : {}),
|
|
1862
|
+
})
|
|
1863
|
+
: undefined;
|
|
1864
|
+
if (viewProofGate === undefined) {
|
|
1865
|
+
const unverifiable = unverifiableViewProofTools(servedHandlers);
|
|
1866
|
+
if (unverifiable.length > 0) {
|
|
1867
|
+
logger.warn("view_proof_unverifiable", {
|
|
1868
|
+
tools: unverifiable,
|
|
1869
|
+
hint: "These tools declare a view proof. MCP Apps is off, so this server keys no view and does not verify proofs.",
|
|
1870
|
+
});
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1765
1873
|
// The control plane — every `protocol`- and `ops`-tagged handler,
|
|
1766
1874
|
// projected onto one anonymous-capable route with per-tool auth and
|
|
1767
1875
|
// confirmation gates. Built from the SAME composed `handlers` array
|
|
@@ -1860,10 +1968,12 @@ export function createGguiServer(opts = {}) {
|
|
|
1860
1968
|
// pass a stable `csrfSecret` so tokens survive a restart.
|
|
1861
1969
|
app.use(createSecurityHeadersMiddleware());
|
|
1862
1970
|
// Resolved once at boot — every per-request `buildMcpServer` call
|
|
1863
|
-
// receives the same string, so
|
|
1864
|
-
//
|
|
1865
|
-
//
|
|
1866
|
-
//
|
|
1971
|
+
// receives the same string, so every `initialize` result carries the
|
|
1972
|
+
// same instructions for the life of the process. Operators opt in via
|
|
1973
|
+
// `mcpInstructions: 'default' | 'aggressive' | 'always' | 'minimal'` or
|
|
1974
|
+
// a custom string; unset or `'off'` sends none (ggui#1579). The boot
|
|
1975
|
+
// line says what is SENT, so it can never again name text no host got.
|
|
1976
|
+
// See `instructions-presets.ts` for the copy.
|
|
1867
1977
|
const resolvedInstructions = resolveMcpInstructions(opts.mcpInstructions);
|
|
1868
1978
|
if (resolvedInstructions) {
|
|
1869
1979
|
logger.info("mcp_instructions_set", {
|
|
@@ -1874,15 +1984,19 @@ export function createGguiServer(opts = {}) {
|
|
|
1874
1984
|
opts.mcpInstructions === "minimal" ||
|
|
1875
1985
|
opts.mcpInstructions === "off")
|
|
1876
1986
|
? opts.mcpInstructions
|
|
1877
|
-
:
|
|
1878
|
-
? "default (no-preset fallback)"
|
|
1879
|
-
: "custom",
|
|
1987
|
+
: "custom",
|
|
1880
1988
|
length: resolvedInstructions.length,
|
|
1989
|
+
sentInInitialize: true,
|
|
1881
1990
|
});
|
|
1882
1991
|
}
|
|
1883
1992
|
else {
|
|
1884
1993
|
logger.info("mcp_instructions_off", {
|
|
1885
|
-
reason: opts.mcpInstructions ===
|
|
1994
|
+
reason: opts.mcpInstructions === undefined
|
|
1995
|
+
? "unset (the default is off)"
|
|
1996
|
+
: opts.mcpInstructions === "off"
|
|
1997
|
+
? "preset=off"
|
|
1998
|
+
: "empty custom string",
|
|
1999
|
+
sentInInitialize: false,
|
|
1886
2000
|
});
|
|
1887
2001
|
}
|
|
1888
2002
|
const csrfSecret = opts.csrfSecret && opts.csrfSecret.length >= 32
|
|
@@ -2026,6 +2140,7 @@ export function createGguiServer(opts = {}) {
|
|
|
2026
2140
|
// endpoint family spreads a fresh copy per request.
|
|
2027
2141
|
const buildMcpOptions = {
|
|
2028
2142
|
mcpAppsOutbound: mcpAppsEnabled,
|
|
2143
|
+
...(viewProofGate !== undefined ? { viewProofGate } : {}),
|
|
2029
2144
|
// Caller-provided `shellHtml` overrides the default (and the
|
|
2030
2145
|
// inline-runtime shell); `installMcpAppsOutbound` falls back to
|
|
2031
2146
|
// its baked `GGUI_RENDER_SHELL_HTML` constant when both are
|
|
@@ -2198,6 +2313,10 @@ export function createGguiServer(opts = {}) {
|
|
|
2198
2313
|
// Mirrors the per-tool `mintBootstrap` plumbed into
|
|
2199
2314
|
// the handler factory above.
|
|
2200
2315
|
...(mintBootstrap ? { mintWsToken: mintBootstrap } : {}),
|
|
2316
|
+
// The data-plane read door issues a view key (ggui#1415); every
|
|
2317
|
+
// other mount, and an anonymous caller, mints through
|
|
2318
|
+
// `mintBootstrap` alone.
|
|
2319
|
+
...(mintReadViewRoot ? { mintViewRoot: mintReadViewRoot } : {}),
|
|
2201
2320
|
},
|
|
2202
2321
|
}
|
|
2203
2322
|
: {}),
|
|
@@ -2267,9 +2386,10 @@ export function createGguiServer(opts = {}) {
|
|
|
2267
2386
|
// R6 /state snapshot + R7 /events cursor-replay reads — see
|
|
2268
2387
|
// `./api-renders-routes.ts` for the wsToken auth posture, binding +
|
|
2269
2388
|
// app-scope gates, and response taxonomy. Mounted only when MCP Apps is on,
|
|
2270
|
-
// a render store is resolved, and a token secret exists
|
|
2271
|
-
//
|
|
2272
|
-
|
|
2389
|
+
// a render store is resolved, and a token secret exists. MCP Apps being on
|
|
2390
|
+
// is also what assigns the two minters, so the last conjunct only narrows
|
|
2391
|
+
// the type: it never keeps a deployment from mounting.
|
|
2392
|
+
if (mcpAppsEnabled && renderStore && sharedTokenSecret !== undefined && mintChainedBootstrap) {
|
|
2273
2393
|
mountApiRendersRoutes({
|
|
2274
2394
|
app,
|
|
2275
2395
|
renderStore,
|
|
@@ -2287,7 +2407,7 @@ export function createGguiServer(opts = {}) {
|
|
|
2287
2407
|
// composes (ggui#522) — session-API URLs keep the public origin.
|
|
2288
2408
|
...(opts.codeBaseUrl !== undefined ? { codeBaseUrl: opts.codeBaseUrl } : {}),
|
|
2289
2409
|
...(mintCodeModuleUrl !== undefined ? { mintCodeModuleUrl } : {}),
|
|
2290
|
-
|
|
2410
|
+
mintChainedBootstrap,
|
|
2291
2411
|
resolveRuntimeUrl: resolveRuntimeUrlForResultMeta,
|
|
2292
2412
|
logger,
|
|
2293
2413
|
});
|
|
@@ -3138,7 +3258,6 @@ export function createGguiServer(opts = {}) {
|
|
|
3138
3258
|
adminToken: resolvedAdminToken,
|
|
3139
3259
|
generators: generators ?? null,
|
|
3140
3260
|
blueprintStore,
|
|
3141
|
-
blueprintSelector,
|
|
3142
3261
|
blueprintSearch,
|
|
3143
3262
|
async listen(port = 0, host = opts.host ?? "127.0.0.1") {
|
|
3144
3263
|
// The Origin/Host validation policy (ggui#438a) was built above
|
|
@@ -3222,14 +3341,28 @@ export function createGguiServer(opts = {}) {
|
|
|
3222
3341
|
}
|
|
3223
3342
|
});
|
|
3224
3343
|
},
|
|
3225
|
-
async close() {
|
|
3344
|
+
async close(options = {}) {
|
|
3226
3345
|
if (channel)
|
|
3227
3346
|
await channel.close();
|
|
3228
3347
|
const server = httpServer;
|
|
3229
3348
|
if (!server)
|
|
3230
3349
|
return;
|
|
3350
|
+
const graceMs = options.graceMs ?? DEFAULT_CLOSE_GRACE_MS;
|
|
3231
3351
|
await new Promise((resolve, reject) => {
|
|
3232
|
-
|
|
3352
|
+
// ggui#1631: after the grace, end what is still open. The timer is
|
|
3353
|
+
// unref'd so it never keeps the process alive on its own.
|
|
3354
|
+
const deadline = Number.isFinite(graceMs)
|
|
3355
|
+
? setTimeout(() => server.closeAllConnections(), Math.max(0, graceMs))
|
|
3356
|
+
: undefined;
|
|
3357
|
+
deadline?.unref();
|
|
3358
|
+
server.close((err) => {
|
|
3359
|
+
if (deadline !== undefined)
|
|
3360
|
+
clearTimeout(deadline);
|
|
3361
|
+
if (err)
|
|
3362
|
+
reject(err);
|
|
3363
|
+
else
|
|
3364
|
+
resolve();
|
|
3365
|
+
});
|
|
3233
3366
|
});
|
|
3234
3367
|
httpServer = null;
|
|
3235
3368
|
},
|
package/dist/storage.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { GguiSessionStore, ThreadStore, VectorStore } from '@ggui-ai/mcp-server-core';
|
|
1
|
+
import type { GguiSessionStore, GguiSessionStreamBuffer, ThreadStore, VectorStore } from '@ggui-ai/mcp-server-core';
|
|
2
2
|
import type { StorageConfig } from '@ggui-ai/project-config';
|
|
3
3
|
export interface ResolveStorageFromConfigOptions {
|
|
4
4
|
/**
|
|
@@ -49,6 +49,14 @@ export interface ResolvedStorageStores {
|
|
|
49
49
|
* `/ggui/health` advertisement matches the active store.
|
|
50
50
|
*/
|
|
51
51
|
readonly threadDurability?: 'durable' | 'ephemeral';
|
|
52
|
+
/**
|
|
53
|
+
* The live channel's stream buffer, present iff `renders` declares
|
|
54
|
+
* sqlite: a `SqliteGguiSessionStreamBuffer` on the same database file,
|
|
55
|
+
* so a session that survives a restart also keeps its stream `seq`, its
|
|
56
|
+
* epoch and its retained envelopes (ggui#1534). Absent otherwise, and
|
|
57
|
+
* `createGguiServer` keeps its in-memory buffer.
|
|
58
|
+
*/
|
|
59
|
+
readonly streamBuffer?: GguiSessionStreamBuffer;
|
|
52
60
|
}
|
|
53
61
|
/**
|
|
54
62
|
* Instantiate the concrete storage adapters declared in a parsed
|
package/dist/storage.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAqDA,OAAO,KAAK,EACV,gBAAgB,EAChB,WAAW,EACX,WAAW,EACZ,MAAM,0BAA0B,CAAC;AAQlC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D,MAAM,WAAW,+BAA+B;IAC9C;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,qBAAqB;IACpC;oEACgE;IAChE,QAAQ,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAC;IACxC;oEACgE;IAChE,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC;IAC/B;;;;;;;;;;;;;;;;;yCAiBqC;IACrC,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;IACnC;;;;;;OAMG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,GAAG,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAqDA,OAAO,KAAK,EACV,gBAAgB,EAChB,uBAAuB,EACvB,WAAW,EACX,WAAW,EACZ,MAAM,0BAA0B,CAAC;AAQlC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D,MAAM,WAAW,+BAA+B;IAC9C;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,qBAAqB;IACpC;oEACgE;IAChE,QAAQ,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAC;IACxC;oEACgE;IAChE,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC;IAC/B;;;;;;;;;;;;;;;;;yCAiBqC;IACrC,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;IACnC;;;;;;OAMG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,GAAG,WAAW,CAAC;IACpD;;;;;;OAMG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,uBAAuB,CAAC;CACjD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,aAAa,GAAG,SAAS,EACjC,IAAI,GAAE,+BAAoC,GACzC,OAAO,CAAC,qBAAqB,CAAC,CAkDhC"}
|
package/dist/storage.js
CHANGED
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
* who want storage from config write:
|
|
42
42
|
*
|
|
43
43
|
* ```ts
|
|
44
|
-
* const { renderStore, vectors } =
|
|
44
|
+
* const { renderStore, vectors, streamBuffer } =
|
|
45
45
|
* await resolveStorageFromConfig(manifest.storage, { baseDir: projectRoot });
|
|
46
|
-
* const server = createGguiServer({ renderStore, vectors });
|
|
46
|
+
* const server = createGguiServer({ renderStore, vectors, streamBuffer });
|
|
47
47
|
* ```
|
|
48
48
|
*
|
|
49
49
|
* Explicit instances passed to `createGguiServer` still win — this
|
|
@@ -113,11 +113,12 @@ export async function resolveStorageFromConfig(config, opts = {}) {
|
|
|
113
113
|
// Single dynamic import serves every sqlite adapter — better-sqlite3's
|
|
114
114
|
// N-API binding loads once even if the import lands twice; the
|
|
115
115
|
// subpath barrel is cached by Node's module loader.
|
|
116
|
-
const { SqliteGguiSessionStore, SqliteVectorStore, SqliteThreadStore } = await import('@ggui-ai/mcp-server-core/sqlite');
|
|
116
|
+
const { SqliteGguiSessionStore, SqliteGguiSessionStreamBuffer, SqliteVectorStore, SqliteThreadStore } = await import('@ggui-ai/mcp-server-core/sqlite');
|
|
117
117
|
if (config.renders && config.renders.driver === 'sqlite') {
|
|
118
118
|
const filename = resolveStoragePath(config.renders.path, opts.baseDir);
|
|
119
119
|
ensureParentDir(filename);
|
|
120
120
|
result.renderStore = new SqliteGguiSessionStore({ filename });
|
|
121
|
+
result.streamBuffer = new SqliteGguiSessionStreamBuffer({ filename });
|
|
121
122
|
}
|
|
122
123
|
if (config.vectors && config.vectors.driver === 'sqlite') {
|
|
123
124
|
const filename = resolveStoragePath(config.vectors.path, opts.baseDir);
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The view-origin proof's measuring gate (ggui#1415, release N): for a tool
|
|
3
|
+
* that declares a view proof, verify the call's proof before the handler
|
|
4
|
+
* runs, put the verdict on the handler context, and name it on the
|
|
5
|
+
* `tool_invoked` line. It never refuses a call and never fails one: at this
|
|
6
|
+
* release the proof is measured, not enforced.
|
|
7
|
+
*
|
|
8
|
+
* Built once per server (`createViewProofGate`, holding the secret the ws
|
|
9
|
+
* envelopes are signed with) and run per call (`runViewProofGate`) from
|
|
10
|
+
* `buildMcpServer`'s per-tool callback.
|
|
11
|
+
*/
|
|
12
|
+
import { ViewProofRepeatCache, type GguiSessionStore, type ViewProofVerdict, type VerifyViewProofInput } from '@ggui-ai/mcp-server-core';
|
|
13
|
+
import { type HandlerContext, type SharedHandler } from '@ggui-ai/mcp-server-handlers';
|
|
14
|
+
import { type ViewRootSrc } from '@ggui-ai/protocol/integrations/mcp-apps';
|
|
15
|
+
import type { ZodRawShape } from 'zod';
|
|
16
|
+
/**
|
|
17
|
+
* Which era a call's session belongs to, for a `required` call whose proof
|
|
18
|
+
* is not valid; the first match wins. `row_absent`: no store, no row, or
|
|
19
|
+
* the read failed. `foreign`: another app owns the row. `unkeyed`: the
|
|
20
|
+
* session's ids are too long for a view key. `legacy`: created before
|
|
21
|
+
* `keyedSince`, or `keyedSince` is unset. `current`: everything else.
|
|
22
|
+
*/
|
|
23
|
+
export type ViewProofEra = 'current' | 'legacy' | 'unkeyed' | 'foreign' | 'row_absent';
|
|
24
|
+
/** How old the proof's root is on the server's clock (`now − rootIat`). */
|
|
25
|
+
export type ViewProofRootAge = 'lt_3m' | 'lt_1h' | 'lt_1d' | 'lt_7d' | 'lt_30d' | 'ge_30d';
|
|
26
|
+
/**
|
|
27
|
+
* The view clock against the server's (`vtime − now`), bucketed at 30 s,
|
|
28
|
+
* 5 min and 1 h on each side. Relay latency makes it negative (`behind`),
|
|
29
|
+
* so `ahead` can only be the view's clock running ahead.
|
|
30
|
+
*/
|
|
31
|
+
export type ViewProofSkew = 'behind_ge_1h' | 'behind_lt_1h' | 'behind_lt_5m' | 'within_30s' | 'ahead_lt_5m' | 'ahead_lt_1h' | 'ahead_ge_1h';
|
|
32
|
+
/**
|
|
33
|
+
* The proof's fields on a `tool_invoked` line: ids, flags and buckets only.
|
|
34
|
+
* Never the proof, its root, its nonce, its tags, the view key or any
|
|
35
|
+
* argument.
|
|
36
|
+
*/
|
|
37
|
+
export interface ViewProofLineFields {
|
|
38
|
+
readonly viewProof?: ViewProofVerdict['verdict'];
|
|
39
|
+
readonly viewProofReason?: string;
|
|
40
|
+
readonly viewProofErrorClass?: string;
|
|
41
|
+
/** Valid only: the session the proof's root names (it equals the call's). */
|
|
42
|
+
readonly viewProofSessionId?: string;
|
|
43
|
+
/** Not valid: the call's session as the caller claims it, capped. */
|
|
44
|
+
readonly claimedSessionId?: string;
|
|
45
|
+
readonly claimedSessionIdTruncated?: true;
|
|
46
|
+
readonly viewProofRootAge?: ViewProofRootAge;
|
|
47
|
+
readonly viewProofRootSrc?: ViewRootSrc;
|
|
48
|
+
readonly viewProofSkew?: ViewProofSkew;
|
|
49
|
+
/** Dispatch only: the gesture's user-activation flag, self-asserted by any key holder. */
|
|
50
|
+
readonly viewProofActivation?: boolean;
|
|
51
|
+
/** This replica saw the same `(session, nonce)` within the repeat window. */
|
|
52
|
+
readonly viewProofRepeat?: true;
|
|
53
|
+
readonly viewProofEra?: ViewProofEra;
|
|
54
|
+
/** The tool declares a proof and the server has no verifier. */
|
|
55
|
+
readonly viewProofUnverifiable?: true;
|
|
56
|
+
}
|
|
57
|
+
/** A server's gate: its verifier, and what it reads to classify an era. */
|
|
58
|
+
export interface ViewProofGate {
|
|
59
|
+
verify(input: VerifyViewProofInput): ViewProofVerdict;
|
|
60
|
+
/** Whether a session's ids fit a view key's root. */
|
|
61
|
+
keyable(sessionId: string, appId: string): boolean;
|
|
62
|
+
readonly sessionStore: GguiSessionStore | undefined;
|
|
63
|
+
/** Epoch ms from which every replica of this deployment issues view keys. */
|
|
64
|
+
readonly keyedSince: number | undefined;
|
|
65
|
+
readonly repeatCache: ViewProofRepeatCache;
|
|
66
|
+
now(): number;
|
|
67
|
+
}
|
|
68
|
+
export interface CreateViewProofGateOptions {
|
|
69
|
+
/** The secret the server's ws envelopes are signed with. */
|
|
70
|
+
readonly secret: string;
|
|
71
|
+
readonly sessionStore: GguiSessionStore | undefined;
|
|
72
|
+
readonly keyedSince?: number;
|
|
73
|
+
readonly now?: () => number;
|
|
74
|
+
}
|
|
75
|
+
/** Build a server's gate once; the secret stays in its closures. */
|
|
76
|
+
export declare function createViewProofGate(opts: CreateViewProofGateOptions): ViewProofGate;
|
|
77
|
+
/**
|
|
78
|
+
* Refuse, at boot, a handler that declares a view proof on a tool the
|
|
79
|
+
* proof's bound-argument table does not name: no view can sign a call to
|
|
80
|
+
* it, so every call would read `missing` for a reason no one could find.
|
|
81
|
+
*/
|
|
82
|
+
export declare function assertViewProofDeclarations(handlers: ReadonlyArray<Pick<SharedHandler<ZodRawShape, ZodRawShape>, 'name' | 'viewProof'>>): void;
|
|
83
|
+
/** The tools whose declared proof a server without a verifier cannot check. */
|
|
84
|
+
export declare function unverifiableViewProofTools(handlers: ReadonlyArray<Pick<SharedHandler<ZodRawShape, ZodRawShape>, 'name' | 'viewProof'>>): string[];
|
|
85
|
+
/** What the gate hands back: the context the handler runs with, and the line fields. */
|
|
86
|
+
export interface ViewProofGateResult {
|
|
87
|
+
readonly ctx: HandlerContext;
|
|
88
|
+
readonly fields: ViewProofLineFields;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Run the gate for one call. `gate` is undefined on a server with no
|
|
92
|
+
* verifier. Total: it never throws, and never changes what the handler
|
|
93
|
+
* answers; a declaration it cannot read leaves the call as it came.
|
|
94
|
+
*/
|
|
95
|
+
export declare function runViewProofGate(gate: ViewProofGate | undefined, handler: Pick<SharedHandler<ZodRawShape, ZodRawShape>, 'name' | 'viewProof'>, input: Record<string, unknown>, ctx: HandlerContext): Promise<ViewProofGateResult>;
|
|
96
|
+
//# sourceMappingURL=view-proof-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view-proof-gate.d.ts","sourceRoot":"","sources":["../src/view-proof-gate.ts"],"names":[],"mappings":"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"}
|