@ggui-ai/protocol 0.2.0-alpha.4 → 0.4.0-rc.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 +16 -16
- package/dist/envelope-adapters.d.ts +6 -5
- package/dist/envelope-adapters.d.ts.map +1 -1
- package/dist/envelope-adapters.js +3 -3
- package/dist/envelopes/builders.d.ts +6 -32
- package/dist/envelopes/builders.d.ts.map +1 -1
- package/dist/envelopes/builders.js +3 -25
- package/dist/errors/version-mismatch.d.ts +1 -1
- package/dist/errors/version-mismatch.js +1 -1
- package/dist/gadgets/resolve-app-gadgets.d.ts +10 -0
- package/dist/gadgets/resolve-app-gadgets.d.ts.map +1 -0
- package/dist/gadgets/resolve-app-gadgets.js +19 -0
- package/dist/gadgets/resolve-contract-gadgets.d.ts +6 -6
- package/dist/gadgets/resolve-contract-gadgets.js +5 -5
- package/dist/gadgets/stdlib-gadgets.d.ts +1 -1
- package/dist/gadgets/stdlib-gadgets.d.ts.map +1 -1
- package/dist/gadgets/stdlib-gadgets.js +43 -22
- package/dist/iframe-bridge.d.ts +4 -43
- package/dist/iframe-bridge.d.ts.map +1 -1
- package/dist/iframe-bridge.js +4 -141
- package/dist/index.d.ts +60 -62
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +66 -61
- package/dist/integrations/mcp-apps.d.ts +83 -38
- package/dist/integrations/mcp-apps.d.ts.map +1 -1
- package/dist/integrations/mcp-apps.js +98 -52
- package/dist/recommended-prompts.d.ts +1 -1
- package/dist/recommended-prompts.js +1 -1
- package/dist/registry/blueprint-key.d.ts +3 -0
- package/dist/registry/blueprint-key.d.ts.map +1 -1
- package/dist/registry/blueprint-key.js +9 -0
- package/dist/registry/blueprint-stamp.d.ts +12 -0
- package/dist/registry/blueprint-stamp.d.ts.map +1 -0
- package/dist/registry/blueprint-stamp.js +12 -0
- package/dist/registry/canonicalize-contract.d.ts +31 -2
- package/dist/registry/canonicalize-contract.d.ts.map +1 -1
- package/dist/registry/canonicalize-contract.js +125 -13
- package/dist/registry/portable-blueprint.d.ts +71 -0
- package/dist/registry/portable-blueprint.d.ts.map +1 -0
- package/dist/registry/portable-blueprint.js +111 -0
- package/dist/registry/summarize-contract.d.ts +7 -2
- package/dist/registry/summarize-contract.d.ts.map +1 -1
- package/dist/registry/summarize-contract.js +12 -3
- package/dist/registry/variant-key.d.ts +17 -0
- package/dist/registry/variant-key.d.ts.map +1 -0
- package/dist/registry/variant-key.js +22 -0
- package/dist/schema-learning/derive-contract.d.ts +2 -2
- package/dist/schema-learning/derive-contract.js +2 -2
- package/dist/schema-learning/merge.d.ts.map +1 -1
- package/dist/schema-learning/merge.js +3 -2
- package/dist/schemas/app-theme.d.ts +38 -0
- package/dist/schemas/app-theme.d.ts.map +1 -0
- package/dist/schemas/app-theme.js +43 -0
- package/dist/schemas/blueprint.d.ts +30 -11
- package/dist/schemas/blueprint.d.ts.map +1 -1
- package/dist/schemas/blueprint.js +62 -26
- package/dist/schemas/data-contract.d.ts +28 -30
- package/dist/schemas/data-contract.d.ts.map +1 -1
- package/dist/schemas/data-contract.js +26 -26
- package/dist/schemas/handshake-suggestion.d.ts +2 -4
- package/dist/schemas/handshake-suggestion.d.ts.map +1 -1
- package/dist/schemas/handshake-suggestion.js +5 -14
- package/dist/schemas/mcp.d.ts +294 -59
- package/dist/schemas/mcp.d.ts.map +1 -1
- package/dist/schemas/mcp.js +350 -94
- package/dist/schemas/ops-blueprint.d.ts +12 -12
- package/dist/schemas/ops-blueprint.d.ts.map +1 -1
- package/dist/schemas/ops-blueprint.js +14 -24
- package/dist/screen-blueprints/define.d.ts +2 -2
- package/dist/screen-blueprints/match.d.ts +12 -7
- package/dist/screen-blueprints/match.d.ts.map +1 -1
- package/dist/screen-blueprints/match.js +7 -5
- package/dist/screen-blueprints/types.d.ts +14 -18
- package/dist/screen-blueprints/types.d.ts.map +1 -1
- package/dist/transport/websocket.d.ts +5 -26
- package/dist/transport/websocket.d.ts.map +1 -1
- package/dist/types/app-config.d.ts +0 -1
- package/dist/types/app-config.d.ts.map +1 -1
- package/dist/types/auth.d.ts +1 -46
- package/dist/types/auth.d.ts.map +1 -1
- package/dist/types/blueprint-source.d.ts +123 -0
- package/dist/types/blueprint-source.d.ts.map +1 -0
- package/dist/types/blueprint-source.js +126 -0
- package/dist/types/blueprint.d.ts +25 -18
- package/dist/types/blueprint.d.ts.map +1 -1
- package/dist/types/contract-inference.d.ts +2 -43
- package/dist/types/contract-inference.d.ts.map +1 -1
- package/dist/types/data-contract.d.ts +59 -344
- package/dist/types/data-contract.d.ts.map +1 -1
- package/dist/types/data-contract.js +5 -12
- package/dist/types/events.d.ts +31 -69
- package/dist/types/events.d.ts.map +1 -1
- package/dist/types/{render-event.d.ts → ggui-session-event.d.ts} +15 -15
- package/dist/types/ggui-session-event.d.ts.map +1 -0
- package/dist/types/{render-event.js → ggui-session-event.js} +5 -5
- package/dist/types/handshake-suggestion.d.ts +49 -35
- package/dist/types/handshake-suggestion.d.ts.map +1 -1
- package/dist/types/host-context.d.ts +8 -8
- package/dist/types/host-context.d.ts.map +1 -1
- package/dist/types/host-context.js +5 -5
- package/dist/types/invoke.d.ts +1 -13
- package/dist/types/invoke.d.ts.map +1 -1
- package/dist/types/{canvas-lifecycle.d.ts → lifecycle.d.ts} +35 -37
- package/dist/types/lifecycle.d.ts.map +1 -0
- package/dist/types/{canvas-lifecycle.js → lifecycle.js} +12 -14
- package/dist/types/live-channel.d.ts +48 -104
- package/dist/types/live-channel.d.ts.map +1 -1
- package/dist/types/llm-route.d.ts +4 -4
- package/dist/types/llm-route.d.ts.map +1 -1
- package/dist/types/llm-route.js +24 -2
- package/dist/types/llm.d.ts +13 -24
- package/dist/types/llm.d.ts.map +1 -1
- package/dist/types/llm.js +23 -53
- package/dist/types/mcp.d.ts +74 -177
- package/dist/types/mcp.d.ts.map +1 -1
- package/dist/types/mcp.js +11 -4
- package/dist/types/oauth-user-id.d.ts +12 -0
- package/dist/types/oauth-user-id.d.ts.map +1 -0
- package/dist/types/oauth-user-id.js +10 -0
- package/dist/types/portable-blueprint.d.ts +61 -0
- package/dist/types/portable-blueprint.d.ts.map +1 -0
- package/dist/types/portable-blueprint.js +8 -0
- package/dist/types/{session.d.ts → render.d.ts} +51 -53
- package/dist/types/render.d.ts.map +1 -0
- package/dist/types/thread.d.ts.map +1 -1
- package/dist/types/thread.js +3 -3
- package/dist/types/ui-generator.d.ts +24 -47
- package/dist/types/ui-generator.d.ts.map +1 -1
- package/dist/types/ui-generator.js +1 -53
- package/dist/validation/ajv-runtime.d.ts +3 -3
- package/dist/validation/ajv-runtime.d.ts.map +1 -1
- package/dist/validation/ajv-runtime.js +6 -5
- package/dist/validation/contract-validator.d.ts +23 -22
- package/dist/validation/contract-validator.d.ts.map +1 -1
- package/dist/validation/contract-validator.js +28 -26
- package/dist/validation/cross-references.d.ts +3 -3
- package/dist/validation/cross-references.js +3 -3
- package/dist/validation/hygiene-rules.d.ts +9 -9
- package/dist/validation/hygiene-rules.js +13 -13
- package/dist/validation/is-record.d.ts +17 -0
- package/dist/validation/is-record.d.ts.map +1 -0
- package/dist/validation/is-record.js +18 -0
- package/dist/validation/lint-contract.d.ts +1 -1
- package/dist/validation/lint-contract.js +3 -3
- package/dist/validation/name-invariants.d.ts +4 -4
- package/dist/validation/name-invariants.js +4 -4
- package/dist/validation/reserved-channels.d.ts +43 -46
- package/dist/validation/reserved-channels.d.ts.map +1 -1
- package/dist/validation/reserved-channels.js +14 -177
- package/dist/validation/resolve-stream-channel.d.ts +3 -9
- package/dist/validation/resolve-stream-channel.d.ts.map +1 -1
- package/dist/validation/resolve-stream-channel.js +3 -4
- package/dist/validation/sanitize-error.d.ts +10 -9
- package/dist/validation/sanitize-error.d.ts.map +1 -1
- package/dist/validation/sanitize-error.js +19 -18
- package/dist/validation/schema-compat-invariants.d.ts +1 -1
- package/dist/validation/schema-compat-invariants.js +3 -3
- package/dist/validation/schema-meta-validation.d.ts +4 -4
- package/dist/validation/schema-meta-validation.d.ts.map +1 -1
- package/dist/validation/schema-meta-validation.js +7 -9
- package/dist/validation/schema-subset.d.ts +9 -8
- package/dist/validation/schema-subset.d.ts.map +1 -1
- package/dist/validation/ui-security.d.ts +0 -17
- package/dist/validation/ui-security.d.ts.map +1 -1
- package/dist/validation/ui-security.js +17 -22
- package/dist/validation/zod-to-json-schema.d.ts +1 -1
- package/dist/validation/zod-to-json-schema.d.ts.map +1 -1
- package/dist/validation/zod-to-json-schema.js +4 -3
- package/dist/version.d.ts +818 -9
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +817 -8
- package/package.json +3 -3
- package/dist/bridge/invoke-agent.d.ts +0 -65
- package/dist/bridge/invoke-agent.d.ts.map +0 -1
- package/dist/bridge/invoke-agent.js +0 -113
- package/dist/stream/stream-parser.d.ts +0 -62
- package/dist/stream/stream-parser.d.ts.map +0 -1
- package/dist/stream/stream-parser.js +0 -199
- package/dist/types/canvas-lifecycle.d.ts.map +0 -1
- package/dist/types/credential.d.ts +0 -41
- package/dist/types/credential.d.ts.map +0 -1
- package/dist/types/credential.js +0 -32
- package/dist/types/data-bindings.d.ts +0 -322
- package/dist/types/data-bindings.d.ts.map +0 -1
- package/dist/types/data-bindings.js +0 -29
- package/dist/types/feedback.d.ts +0 -22
- package/dist/types/feedback.d.ts.map +0 -1
- package/dist/types/feedback.js +0 -7
- package/dist/types/mcp-proxy.d.ts +0 -67
- package/dist/types/mcp-proxy.d.ts.map +0 -1
- package/dist/types/mcp-proxy.js +0 -46
- package/dist/types/openrouter-models.d.ts +0 -23
- package/dist/types/openrouter-models.d.ts.map +0 -1
- package/dist/types/openrouter-models.js +0 -4843
- package/dist/types/region.d.ts +0 -26
- package/dist/types/region.d.ts.map +0 -1
- package/dist/types/region.js +0 -36
- package/dist/types/render-event.d.ts.map +0 -1
- package/dist/types/session.d.ts.map +0 -1
- /package/dist/types/{session.js → render.js} +0 -0
|
@@ -40,7 +40,7 @@ import { RESERVED_CHANNEL_PREFIX, isReservedChannelName, } from './reserved-chan
|
|
|
40
40
|
* Stable error code for collisions across the three inbound spec maps
|
|
41
41
|
* (`actionSpec` / `streamSpec` / `contextSpec`). The boilerplate
|
|
42
42
|
* generator emits identifiers from these keys; a collision is an
|
|
43
|
-
* author bug that the protocol catches at
|
|
43
|
+
* author bug that the protocol catches at render.
|
|
44
44
|
*/
|
|
45
45
|
export const CTR_DUP_NAME = 'CTR_DUP_NAME';
|
|
46
46
|
/**
|
|
@@ -95,7 +95,7 @@ export function checkNameCollisions(contract) {
|
|
|
95
95
|
* Validate that no `actionSpec` or `contextSpec` key uses the
|
|
96
96
|
* `_ggui:` reserved namespace. `streamSpec` reserved-channel rejection
|
|
97
97
|
* lives in `validateContractStructure` (the reserved namespace there
|
|
98
|
-
* carries server-side semantics like the `_ggui:
|
|
98
|
+
* carries server-side semantics like the `_ggui:lifecycle`
|
|
99
99
|
* channel); this invariant extends the rule uniformly across the
|
|
100
100
|
* other two inbound spec maps.
|
|
101
101
|
*
|
|
@@ -137,7 +137,7 @@ export function checkNameInvariants(contract) {
|
|
|
137
137
|
/**
|
|
138
138
|
* Throwable form of {@link checkNameInvariants}. Use at protocol
|
|
139
139
|
* boundaries where a name collision or reserved-namespace use is a
|
|
140
|
-
* contract bug the caller must fix (
|
|
140
|
+
* contract bug the caller must fix (render handler, blueprint
|
|
141
141
|
* registration).
|
|
142
142
|
*
|
|
143
143
|
* Carries the full violation list so error renderers can show every
|
|
@@ -159,7 +159,7 @@ export class NameInvariantError extends Error {
|
|
|
159
159
|
* Throw-on-violation wrapper around {@link checkNameInvariants}.
|
|
160
160
|
* No-op when the contract's names are consistent.
|
|
161
161
|
*
|
|
162
|
-
* Designed to slot alongside `assertCrossReferences` at
|
|
162
|
+
* Designed to slot alongside `assertCrossReferences` at render time:
|
|
163
163
|
* cross-reference invariants catch dangling pointers between specs;
|
|
164
164
|
* name invariants catch malformed name spaces within specs. Both
|
|
165
165
|
* surface author-recoverable failures before any state mutation.
|
|
@@ -1,3 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reserved channel namespace for server-emitted streams on the live channel.
|
|
3
|
+
*
|
|
4
|
+
* Agents may NOT declare channels whose names start with `_ggui:` in
|
|
5
|
+
* their `streamSpec`. The namespace is reserved for system
|
|
6
|
+
* channels the server emits directly — bypassing the agent's declared
|
|
7
|
+
* streamSpec because these channels are not part of the agent-authored
|
|
8
|
+
* contract.
|
|
9
|
+
*
|
|
10
|
+
* Concrete reservations today:
|
|
11
|
+
*
|
|
12
|
+
* - {@link PREVIEW_CHANNEL} — provisional A2UI assembly stream
|
|
13
|
+
* emitted during fresh-gen `ggui_render` flows. The integration
|
|
14
|
+
* surface (A2UI message types, catalog, validators) lives in the
|
|
15
|
+
* dedicated boundary package `@ggui-ai/preview-a2ui`; this module
|
|
16
|
+
* owns only the protocol-level naming rule so `@ggui-ai/protocol`
|
|
17
|
+
* stays free of A2UI-shaped types. Payload validation for this
|
|
18
|
+
* channel is delivered via the INJECTION pattern documented on
|
|
19
|
+
* {@link BUILTIN_RESERVED_VALIDATORS} — the server composes the
|
|
20
|
+
* A2UI validator into `validateStreamData`'s
|
|
21
|
+
* `extraReservedValidators` parameter.
|
|
22
|
+
* - {@link LIFECYCLE_CHANNEL} — generation-progress lifecycle
|
|
23
|
+
* envelopes the server emits for session-wide subscribers.
|
|
24
|
+
* Payload is a PROTOCOL-OWNED shape, so the structural validator
|
|
25
|
+
* ships inside this module as a built-in (see
|
|
26
|
+
* {@link validateGguiLifecyclePayload} +
|
|
27
|
+
* {@link BUILTIN_RESERVED_VALIDATORS}).
|
|
28
|
+
*
|
|
29
|
+
* Why here and not in `types/live-channel.ts`: `live-channel.ts` describes
|
|
30
|
+
* WIRE envelope shapes (`StreamEnvelope`, `SubscribePayload`). This
|
|
31
|
+
* file describes a NAMING POLICY that the contract-structure validator
|
|
32
|
+
* enforces. Separate concerns — easier to audit the boundary.
|
|
33
|
+
*/
|
|
1
34
|
import type { ValidationResult } from './contract-validator';
|
|
2
35
|
/** Prefix that marks a channel as server-owned (reserved from agents). */
|
|
3
36
|
export declare const RESERVED_CHANNEL_PREFIX = "_ggui:";
|
|
@@ -9,27 +42,14 @@ export declare const RESERVED_CHANNEL_PREFIX = "_ggui:";
|
|
|
9
42
|
*/
|
|
10
43
|
export declare const PREVIEW_CHANNEL = "_ggui:preview";
|
|
11
44
|
/**
|
|
12
|
-
* Reserved channel for
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* MUST NOT declare this channel — structural validation rejects it
|
|
16
|
-
* alongside every other reserved-prefix name.
|
|
45
|
+
* Reserved channel for generation-progress lifecycle envelopes —
|
|
46
|
+
* handshake / render / consume lifecycle signals that drive
|
|
47
|
+
* client-side progress indicators.
|
|
17
48
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*/
|
|
23
|
-
export declare const CONTRACT_ERROR_CHANNEL = "_ggui:contract-error";
|
|
24
|
-
/**
|
|
25
|
-
* Reserved channel for canvas-mode session
|
|
26
|
-
* lifecycle envelopes — handshake / push / consume lifecycle signals
|
|
27
|
-
* that drive the ggui-animator's state machine.
|
|
28
|
-
*
|
|
29
|
-
* Body shape: `CanvasLifecyclePayload` (discriminated on `kind`). The
|
|
30
|
-
* server emits; canvas iframes (subscribed session-wide) consume.
|
|
31
|
-
* Inline iframes (pinned to a single stack item) do not receive
|
|
32
|
-
* envelopes on this channel — delivery is gated by subscription scope.
|
|
49
|
+
* Body shape: `GguiLifecyclePayload` (discriminated on `kind`). The
|
|
50
|
+
* server emits; session-wide subscribers consume. Iframes pinned to a
|
|
51
|
+
* single GguiSession do not receive envelopes on this channel —
|
|
52
|
+
* delivery is gated by subscription scope.
|
|
33
53
|
*
|
|
34
54
|
* Agent-authored `streamSpec` MUST NOT declare this channel; the
|
|
35
55
|
* structural validator rejects it alongside every other reserved-
|
|
@@ -80,7 +100,7 @@ export declare function isKnownReservedChannel(name: string): boolean;
|
|
|
80
100
|
*
|
|
81
101
|
* 1. `BUILTIN_RESERVED_VALIDATORS` — the PROTOCOL-OWNED payloads.
|
|
82
102
|
* Shipped in `@ggui-ai/protocol` because the protocol defines the
|
|
83
|
-
* shape (`
|
|
103
|
+
* shape (`GguiLifecyclePayload` is authored here; the validator
|
|
84
104
|
* belongs here too). Always active, no composition needed.
|
|
85
105
|
* 2. `extraReservedValidators` — INJECTION POINT for payloads whose
|
|
86
106
|
* shape the protocol does NOT own. Primary consumer today:
|
|
@@ -98,29 +118,6 @@ export declare function isKnownReservedChannel(name: string): boolean;
|
|
|
98
118
|
* composition time.
|
|
99
119
|
*/
|
|
100
120
|
export type ReservedChannelValidator = (payload: unknown) => ValidationResult;
|
|
101
|
-
/**
|
|
102
|
-
* Structural validator for {@link ContractErrorPayload} — the body the
|
|
103
|
-
* server emits on `_ggui:contract-error`. PROTOCOL-OWNED shape; ships
|
|
104
|
-
* as a built-in (see {@link BUILTIN_RESERVED_VALIDATORS}).
|
|
105
|
-
*
|
|
106
|
-
* Semantics:
|
|
107
|
-
* - Payload MUST be a non-null object (arrays rejected).
|
|
108
|
-
* - Required fields: `toolName: string`, `error.code: string`,
|
|
109
|
-
* `error.message: string`, `timestamp: string`.
|
|
110
|
-
* - Optional fields: `actionName: string`, `sourceAction: {type:
|
|
111
|
-
* string, dispatchedAt: string}`, `error.causedBy: string`,
|
|
112
|
-
* `schemaVersion: string`.
|
|
113
|
-
* - `error.code` accepts ANY string — the {@link ContractErrorCode}
|
|
114
|
-
* type is extensibly-closed per Item 2 (`(string & {})` branch),
|
|
115
|
-
* so forward-compat codes like `BOOTSTRAP_FAILED` /
|
|
116
|
-
* `RATE_LIMIT_EXCEEDED` MUST NOT be rejected at this layer.
|
|
117
|
-
* - `sourceAction.type` accepts ANY string — per F6 extensibility
|
|
118
|
-
* (`'wired-action' | 'refresh-stream' | (string & {})`).
|
|
119
|
-
*
|
|
120
|
-
* Returns `{valid: true, violations: []}` on conformance. Reject sets
|
|
121
|
-
* `valid: false` with one violation per missing-or-mistyped field.
|
|
122
|
-
*/
|
|
123
|
-
export declare function validateContractErrorPayload(payload: unknown): ValidationResult;
|
|
124
121
|
/**
|
|
125
122
|
* The PROTOCOL-OWNED reserved-channel validator registry.
|
|
126
123
|
*
|
|
@@ -142,7 +139,7 @@ export declare const BUILTIN_RESERVED_VALIDATORS: ReadonlyMap<string, ReservedCh
|
|
|
142
139
|
/**
|
|
143
140
|
* Structural validator for {@link LIFECYCLE_CHANNEL} payloads. The
|
|
144
141
|
* wire shape is the closed discriminated union
|
|
145
|
-
* {@link
|
|
142
|
+
* {@link GguiLifecyclePayload}; we narrow on `kind` and check the
|
|
146
143
|
* required fields per variant. Defines the failure mode the protocol
|
|
147
144
|
* bar requires for reserved channels.
|
|
148
145
|
*
|
|
@@ -152,5 +149,5 @@ export declare const BUILTIN_RESERVED_VALIDATORS: ReadonlyMap<string, ReservedCh
|
|
|
152
149
|
* - unknown `kind` values (closed union — new kinds bump protocol)
|
|
153
150
|
* - missing or wrong-typed variant-specific fields
|
|
154
151
|
*/
|
|
155
|
-
export declare function
|
|
152
|
+
export declare function validateGguiLifecyclePayload(payload: unknown): ValidationResult;
|
|
156
153
|
//# sourceMappingURL=reserved-channels.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reserved-channels.d.ts","sourceRoot":"","sources":["../../src/validation/reserved-channels.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"reserved-channels.d.ts","sourceRoot":"","sources":["../../src/validation/reserved-channels.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,KAAK,EAAqB,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAGhF,0EAA0E;AAC1E,eAAO,MAAM,uBAAuB,WAAW,CAAC;AAEhD;;;;;GAKG;AACH,eAAO,MAAM,eAAe,kBAAkB,CAAC;AAE/C;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,iBAAiB,oBAAoB,CAAC;AAEnD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,MAAM,CAGtD,CAAC;AAEH;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE5D;AAMD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,MAAM,wBAAwB,GAAG,CACrC,OAAO,EAAE,OAAO,KACb,gBAAgB,CAAC;AAEtB;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,2BAA2B,EAAE,WAAW,CACnD,MAAM,EACN,wBAAwB,CAIxB,CAAC;AAEH;;;;;;;;;;;;GAYG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,OAAO,GACf,gBAAgB,CA4FlB"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isRecord } from './is-record.js';
|
|
1
2
|
/** Prefix that marks a channel as server-owned (reserved from agents). */
|
|
2
3
|
export const RESERVED_CHANNEL_PREFIX = '_ggui:';
|
|
3
4
|
/**
|
|
@@ -8,27 +9,14 @@ export const RESERVED_CHANNEL_PREFIX = '_ggui:';
|
|
|
8
9
|
*/
|
|
9
10
|
export const PREVIEW_CHANNEL = '_ggui:preview';
|
|
10
11
|
/**
|
|
11
|
-
* Reserved channel for
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* MUST NOT declare this channel — structural validation rejects it
|
|
15
|
-
* alongside every other reserved-prefix name.
|
|
12
|
+
* Reserved channel for generation-progress lifecycle envelopes —
|
|
13
|
+
* handshake / render / consume lifecycle signals that drive
|
|
14
|
+
* client-side progress indicators.
|
|
16
15
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*/
|
|
22
|
-
export const CONTRACT_ERROR_CHANNEL = '_ggui:contract-error';
|
|
23
|
-
/**
|
|
24
|
-
* Reserved channel for canvas-mode session
|
|
25
|
-
* lifecycle envelopes — handshake / push / consume lifecycle signals
|
|
26
|
-
* that drive the ggui-animator's state machine.
|
|
27
|
-
*
|
|
28
|
-
* Body shape: `CanvasLifecyclePayload` (discriminated on `kind`). The
|
|
29
|
-
* server emits; canvas iframes (subscribed session-wide) consume.
|
|
30
|
-
* Inline iframes (pinned to a single stack item) do not receive
|
|
31
|
-
* envelopes on this channel — delivery is gated by subscription scope.
|
|
16
|
+
* Body shape: `GguiLifecyclePayload` (discriminated on `kind`). The
|
|
17
|
+
* server emits; session-wide subscribers consume. Iframes pinned to a
|
|
18
|
+
* single GguiSession do not receive envelopes on this channel —
|
|
19
|
+
* delivery is gated by subscription scope.
|
|
32
20
|
*
|
|
33
21
|
* Agent-authored `streamSpec` MUST NOT declare this channel; the
|
|
34
22
|
* structural validator rejects it alongside every other reserved-
|
|
@@ -51,7 +39,6 @@ export const LIFECYCLE_CHANNEL = '_ggui:lifecycle';
|
|
|
51
39
|
*/
|
|
52
40
|
export const KNOWN_RESERVED_CHANNELS = new Set([
|
|
53
41
|
PREVIEW_CHANNEL,
|
|
54
|
-
CONTRACT_ERROR_CHANNEL,
|
|
55
42
|
LIFECYCLE_CHANNEL,
|
|
56
43
|
]);
|
|
57
44
|
/**
|
|
@@ -79,155 +66,6 @@ export function isReservedChannelName(name) {
|
|
|
79
66
|
export function isKnownReservedChannel(name) {
|
|
80
67
|
return KNOWN_RESERVED_CHANNELS.has(name);
|
|
81
68
|
}
|
|
82
|
-
/**
|
|
83
|
-
* Structural validator for {@link ContractErrorPayload} — the body the
|
|
84
|
-
* server emits on `_ggui:contract-error`. PROTOCOL-OWNED shape; ships
|
|
85
|
-
* as a built-in (see {@link BUILTIN_RESERVED_VALIDATORS}).
|
|
86
|
-
*
|
|
87
|
-
* Semantics:
|
|
88
|
-
* - Payload MUST be a non-null object (arrays rejected).
|
|
89
|
-
* - Required fields: `toolName: string`, `error.code: string`,
|
|
90
|
-
* `error.message: string`, `timestamp: string`.
|
|
91
|
-
* - Optional fields: `actionName: string`, `sourceAction: {type:
|
|
92
|
-
* string, dispatchedAt: string}`, `error.causedBy: string`,
|
|
93
|
-
* `schemaVersion: string`.
|
|
94
|
-
* - `error.code` accepts ANY string — the {@link ContractErrorCode}
|
|
95
|
-
* type is extensibly-closed per Item 2 (`(string & {})` branch),
|
|
96
|
-
* so forward-compat codes like `BOOTSTRAP_FAILED` /
|
|
97
|
-
* `RATE_LIMIT_EXCEEDED` MUST NOT be rejected at this layer.
|
|
98
|
-
* - `sourceAction.type` accepts ANY string — per F6 extensibility
|
|
99
|
-
* (`'wired-action' | 'refresh-stream' | (string & {})`).
|
|
100
|
-
*
|
|
101
|
-
* Returns `{valid: true, violations: []}` on conformance. Reject sets
|
|
102
|
-
* `valid: false` with one violation per missing-or-mistyped field.
|
|
103
|
-
*/
|
|
104
|
-
export function validateContractErrorPayload(payload) {
|
|
105
|
-
const violations = [];
|
|
106
|
-
if (typeof payload !== 'object' || payload === null || Array.isArray(payload)) {
|
|
107
|
-
return {
|
|
108
|
-
valid: false,
|
|
109
|
-
violations: [
|
|
110
|
-
{
|
|
111
|
-
field: 'payload',
|
|
112
|
-
message: `${CONTRACT_ERROR_CHANNEL} payload must be a non-null object`,
|
|
113
|
-
expected: 'object',
|
|
114
|
-
received: payload === null ? 'null' : Array.isArray(payload) ? 'array' : typeof payload,
|
|
115
|
-
},
|
|
116
|
-
],
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
const p = payload;
|
|
120
|
-
// ── Required: toolName ──
|
|
121
|
-
if (typeof p.toolName !== 'string') {
|
|
122
|
-
violations.push({
|
|
123
|
-
field: 'toolName',
|
|
124
|
-
message: "Required field 'toolName' must be a string",
|
|
125
|
-
expected: 'string',
|
|
126
|
-
received: p.toolName === undefined ? 'undefined' : typeof p.toolName,
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
// ── Optional: actionName ──
|
|
130
|
-
if (p.actionName !== undefined && typeof p.actionName !== 'string') {
|
|
131
|
-
violations.push({
|
|
132
|
-
field: 'actionName',
|
|
133
|
-
message: "Optional field 'actionName' must be a string when present",
|
|
134
|
-
expected: 'string',
|
|
135
|
-
received: typeof p.actionName,
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
// ── Optional: sourceAction ──
|
|
139
|
-
if (p.sourceAction !== undefined) {
|
|
140
|
-
if (typeof p.sourceAction !== 'object' ||
|
|
141
|
-
p.sourceAction === null ||
|
|
142
|
-
Array.isArray(p.sourceAction)) {
|
|
143
|
-
violations.push({
|
|
144
|
-
field: 'sourceAction',
|
|
145
|
-
message: "Optional field 'sourceAction' must be an object when present",
|
|
146
|
-
expected: 'object',
|
|
147
|
-
received: p.sourceAction === null ? 'null' : Array.isArray(p.sourceAction) ? 'array' : typeof p.sourceAction,
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
else {
|
|
151
|
-
const sa = p.sourceAction;
|
|
152
|
-
if (typeof sa.type !== 'string') {
|
|
153
|
-
// Accepts any string — extensibility per F6. Type presence is
|
|
154
|
-
// required, VALUE is open.
|
|
155
|
-
violations.push({
|
|
156
|
-
field: 'sourceAction.type',
|
|
157
|
-
message: "Field 'sourceAction.type' must be a string",
|
|
158
|
-
expected: 'string',
|
|
159
|
-
received: sa.type === undefined ? 'undefined' : typeof sa.type,
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
if (typeof sa.dispatchedAt !== 'string') {
|
|
163
|
-
violations.push({
|
|
164
|
-
field: 'sourceAction.dispatchedAt',
|
|
165
|
-
message: "Field 'sourceAction.dispatchedAt' must be a string (ISO 8601)",
|
|
166
|
-
expected: 'string',
|
|
167
|
-
received: sa.dispatchedAt === undefined ? 'undefined' : typeof sa.dispatchedAt,
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
// ── Required: error.code + error.message ──
|
|
173
|
-
if (typeof p.error !== 'object' || p.error === null || Array.isArray(p.error)) {
|
|
174
|
-
violations.push({
|
|
175
|
-
field: 'error',
|
|
176
|
-
message: "Required field 'error' must be a non-null object",
|
|
177
|
-
expected: 'object',
|
|
178
|
-
received: p.error === undefined ? 'undefined' : p.error === null ? 'null' : Array.isArray(p.error) ? 'array' : typeof p.error,
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
else {
|
|
182
|
-
const err = p.error;
|
|
183
|
-
if (typeof err.code !== 'string') {
|
|
184
|
-
// Accepts any string — ContractErrorCode is extensibly-closed per
|
|
185
|
-
// Item 2. Rejecting by name-set here would force a version bump
|
|
186
|
-
// every time a new code ships.
|
|
187
|
-
violations.push({
|
|
188
|
-
field: 'error.code',
|
|
189
|
-
message: "Required field 'error.code' must be a string",
|
|
190
|
-
expected: 'string',
|
|
191
|
-
received: err.code === undefined ? 'undefined' : typeof err.code,
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
if (typeof err.message !== 'string') {
|
|
195
|
-
violations.push({
|
|
196
|
-
field: 'error.message',
|
|
197
|
-
message: "Required field 'error.message' must be a string",
|
|
198
|
-
expected: 'string',
|
|
199
|
-
received: err.message === undefined ? 'undefined' : typeof err.message,
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
if (err.causedBy !== undefined && typeof err.causedBy !== 'string') {
|
|
203
|
-
violations.push({
|
|
204
|
-
field: 'error.causedBy',
|
|
205
|
-
message: "Optional field 'error.causedBy' must be a string when present",
|
|
206
|
-
expected: 'string',
|
|
207
|
-
received: typeof err.causedBy,
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
// ── Required: timestamp ──
|
|
212
|
-
if (typeof p.timestamp !== 'string') {
|
|
213
|
-
violations.push({
|
|
214
|
-
field: 'timestamp',
|
|
215
|
-
message: "Required field 'timestamp' must be a string (ISO 8601)",
|
|
216
|
-
expected: 'string',
|
|
217
|
-
received: p.timestamp === undefined ? 'undefined' : typeof p.timestamp,
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
// ── Optional: schemaVersion ──
|
|
221
|
-
if (p.schemaVersion !== undefined && typeof p.schemaVersion !== 'string') {
|
|
222
|
-
violations.push({
|
|
223
|
-
field: 'schemaVersion',
|
|
224
|
-
message: "Optional field 'schemaVersion' must be a string when present",
|
|
225
|
-
expected: 'string',
|
|
226
|
-
received: typeof p.schemaVersion,
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
|
-
return { valid: violations.length === 0, violations };
|
|
230
|
-
}
|
|
231
69
|
/**
|
|
232
70
|
* The PROTOCOL-OWNED reserved-channel validator registry.
|
|
233
71
|
*
|
|
@@ -246,14 +84,13 @@ export function validateContractErrorPayload(payload) {
|
|
|
246
84
|
* Readonly `ReadonlyMap` so consumers can't mutate the global registry.
|
|
247
85
|
*/
|
|
248
86
|
export const BUILTIN_RESERVED_VALIDATORS = new Map([
|
|
249
|
-
[
|
|
250
|
-
[LIFECYCLE_CHANNEL, validateCanvasLifecyclePayload],
|
|
87
|
+
[LIFECYCLE_CHANNEL, validateGguiLifecyclePayload],
|
|
251
88
|
// PREVIEW_CHANNEL intentionally absent — injected at composition time.
|
|
252
89
|
]);
|
|
253
90
|
/**
|
|
254
91
|
* Structural validator for {@link LIFECYCLE_CHANNEL} payloads. The
|
|
255
92
|
* wire shape is the closed discriminated union
|
|
256
|
-
* {@link
|
|
93
|
+
* {@link GguiLifecyclePayload}; we narrow on `kind` and check the
|
|
257
94
|
* required fields per variant. Defines the failure mode the protocol
|
|
258
95
|
* bar requires for reserved channels.
|
|
259
96
|
*
|
|
@@ -263,9 +100,9 @@ export const BUILTIN_RESERVED_VALIDATORS = new Map([
|
|
|
263
100
|
* - unknown `kind` values (closed union — new kinds bump protocol)
|
|
264
101
|
* - missing or wrong-typed variant-specific fields
|
|
265
102
|
*/
|
|
266
|
-
export function
|
|
103
|
+
export function validateGguiLifecyclePayload(payload) {
|
|
267
104
|
const violations = [];
|
|
268
|
-
if (
|
|
105
|
+
if (!isRecord(payload)) {
|
|
269
106
|
return {
|
|
270
107
|
valid: false,
|
|
271
108
|
violations: [
|
|
@@ -330,11 +167,11 @@ export function validateCanvasLifecyclePayload(payload) {
|
|
|
330
167
|
}
|
|
331
168
|
break;
|
|
332
169
|
case 'render_started':
|
|
333
|
-
requireString('
|
|
170
|
+
requireString('sessionId');
|
|
334
171
|
requireString('intent');
|
|
335
172
|
break;
|
|
336
173
|
case 'consume_polling':
|
|
337
|
-
requireString('
|
|
174
|
+
requireString('sessionId');
|
|
338
175
|
if (p.state !== 'open') {
|
|
339
176
|
violations.push({
|
|
340
177
|
field: 'state',
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* Returns `undefined` for two distinct cases, both of which are
|
|
24
24
|
* "nothing to enforce" at call sites:
|
|
25
25
|
*
|
|
26
|
-
* - `spec === undefined` — the
|
|
26
|
+
* - `spec === undefined` — the render has no stream contract.
|
|
27
27
|
* - `spec.channels[channelName]` is missing — the channel isn't
|
|
28
28
|
* declared. Callers MUST NOT assume this means "permissive";
|
|
29
29
|
* rejection is the downstream responsibility of
|
|
@@ -53,12 +53,6 @@ export interface ResolvedStreamChannel {
|
|
|
53
53
|
readonly description?: string;
|
|
54
54
|
/** Optional passthrough — channel's example payload. */
|
|
55
55
|
readonly example?: JsonValue;
|
|
56
|
-
/** Optional passthrough — refresh tool declared for this channel.
|
|
57
|
-
* Server-side action dispatch (WS-direct agent-less deployments)
|
|
58
|
-
* fires this after a wired action succeeds; absence means "no
|
|
59
|
-
* refresh fires." Distinct from the `source` poll/push feed on
|
|
60
|
-
* `StreamChannelEntry`. See `StreamChannelEntry.tool`. */
|
|
61
|
-
readonly tool?: string;
|
|
62
56
|
}
|
|
63
57
|
/**
|
|
64
58
|
* Look up a channel's declared semantics in a {@link StreamSpec} and
|
|
@@ -66,8 +60,8 @@ export interface ResolvedStreamChannel {
|
|
|
66
60
|
* (`mode` / `replay` / `complete`) are filled with their locked
|
|
67
61
|
* defaults.
|
|
68
62
|
*
|
|
69
|
-
* @param spec The active
|
|
70
|
-
* when the
|
|
63
|
+
* @param spec The active render's stream contract, or undefined
|
|
64
|
+
* when the render has no `streamSpec` at all.
|
|
71
65
|
* @param channelName The channel name to resolve — typically read
|
|
72
66
|
* from the outbound envelope's `channel` field.
|
|
73
67
|
* @returns `ResolvedStreamChannel` when the channel is declared;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-stream-channel.d.ts","sourceRoot":"","sources":["../../src/validation/resolve-stream-channel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,UAAU,EAChB,MAAM,2BAA2B,CAAC;AAEnC;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,oEAAoE;IACpE,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,mEAAmE;IACnE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,wDAAwD;IACxD,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"resolve-stream-channel.d.ts","sourceRoot":"","sources":["../../src/validation/resolve-stream-channel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,UAAU,EAChB,MAAM,2BAA2B,CAAC;AAEnC;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,oEAAoE;IACpE,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,mEAAmE;IACnE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,wDAAwD;IACxD,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;CAC9B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,UAAU,GAAG,SAAS,EAC5B,WAAW,EAAE,MAAM,GAClB,qBAAqB,GAAG,SAAS,CAanC"}
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* Returns `undefined` for two distinct cases, both of which are
|
|
24
24
|
* "nothing to enforce" at call sites:
|
|
25
25
|
*
|
|
26
|
-
* - `spec === undefined` — the
|
|
26
|
+
* - `spec === undefined` — the render has no stream contract.
|
|
27
27
|
* - `spec.channels[channelName]` is missing — the channel isn't
|
|
28
28
|
* declared. Callers MUST NOT assume this means "permissive";
|
|
29
29
|
* rejection is the downstream responsibility of
|
|
@@ -37,8 +37,8 @@ import { DEFAULT_STREAM_CHANNEL_COMPLETE, DEFAULT_STREAM_CHANNEL_MODE, DEFAULT_S
|
|
|
37
37
|
* (`mode` / `replay` / `complete`) are filled with their locked
|
|
38
38
|
* defaults.
|
|
39
39
|
*
|
|
40
|
-
* @param spec The active
|
|
41
|
-
* when the
|
|
40
|
+
* @param spec The active render's stream contract, or undefined
|
|
41
|
+
* when the render has no `streamSpec` at all.
|
|
42
42
|
* @param channelName The channel name to resolve — typically read
|
|
43
43
|
* from the outbound envelope's `channel` field.
|
|
44
44
|
* @returns `ResolvedStreamChannel` when the channel is declared;
|
|
@@ -59,6 +59,5 @@ export function resolveStreamChannel(spec, channelName) {
|
|
|
59
59
|
complete: entry.complete ?? DEFAULT_STREAM_CHANNEL_COMPLETE,
|
|
60
60
|
...(entry.description !== undefined ? { description: entry.description } : {}),
|
|
61
61
|
...(entry.example !== undefined ? { example: entry.example } : {}),
|
|
62
|
-
...(entry.tool !== undefined ? { tool: entry.tool } : {}),
|
|
63
62
|
};
|
|
64
63
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Patterns stripped from stringified errors before
|
|
3
|
-
*
|
|
2
|
+
* Patterns stripped from stringified errors before they ride a wire
|
|
3
|
+
* frame. The default set covers the common credential
|
|
4
4
|
* shapes that show up in stack traces by accident (URLs with token query
|
|
5
5
|
* params, Bearer headers captured by retry libraries, env-var dumps).
|
|
6
6
|
*
|
|
7
7
|
* Each regex replaces the matched span with `[REDACTED]`. Replacement is
|
|
8
8
|
* conservative — we'd rather over-redact than leak. Operators who need
|
|
9
|
-
* finer control
|
|
10
|
-
*
|
|
9
|
+
* finer control supply a custom {@link SanitizeCausedBy} function (or
|
|
10
|
+
* pass a stricter pattern set to {@link sanitizeCausedBy}).
|
|
11
11
|
*/
|
|
12
12
|
export declare const DEFAULT_CREDENTIAL_PATTERNS: readonly RegExp[];
|
|
13
13
|
/** Default max length for a sanitized `causedBy` string. */
|
|
@@ -16,7 +16,8 @@ export declare const DEFAULT_CAUSED_BY_MAX_LENGTH = 2048;
|
|
|
16
16
|
export declare const TRUNCATION_MARKER = "\n\u2026[truncated]";
|
|
17
17
|
/**
|
|
18
18
|
* Sanitize a stringified error (typically `err.stack`) before it's
|
|
19
|
-
* written to
|
|
19
|
+
* written to a wire-visible diagnostic slot (e.g. the `channel_error`
|
|
20
|
+
* frame's `details`).
|
|
20
21
|
*
|
|
21
22
|
* Applies every pattern in {@link DEFAULT_CREDENTIAL_PATTERNS} in order,
|
|
22
23
|
* replacing matches with `[REDACTED]`. If the result exceeds `maxLength`,
|
|
@@ -34,11 +35,11 @@ export declare const TRUNCATION_MARKER = "\n\u2026[truncated]";
|
|
|
34
35
|
*/
|
|
35
36
|
export declare function sanitizeCausedBy(raw: string, maxLength?: number, patterns?: readonly RegExp[]): string;
|
|
36
37
|
/**
|
|
37
|
-
* Signature of
|
|
38
|
-
* `
|
|
39
|
-
*
|
|
38
|
+
* Signature of a `causedBy` sanitizer hook. Receives the raw
|
|
39
|
+
* stringified error (typically `err.stack`) and MUST return a
|
|
40
|
+
* safe-to-emit string.
|
|
40
41
|
*
|
|
41
|
-
*
|
|
42
|
+
* {@link sanitizeCausedBy} is the canonical implementation. A
|
|
42
43
|
* pass-through function that returns `raw` unchanged is valid but
|
|
43
44
|
* discouraged — it re-enables the leak this module was added to close.
|
|
44
45
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitize-error.d.ts","sourceRoot":"","sources":["../../src/validation/sanitize-error.ts"],"names":[],"mappings":"AA0BA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,2BAA2B,EAAE,SAAS,MAAM,EAWxD,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAEjD,yEAAyE;AACzE,eAAO,MAAM,iBAAiB,wBAAmB,CAAC;AAElD
|
|
1
|
+
{"version":3,"file":"sanitize-error.d.ts","sourceRoot":"","sources":["../../src/validation/sanitize-error.ts"],"names":[],"mappings":"AA0BA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,2BAA2B,EAAE,SAAS,MAAM,EAWxD,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAEjD,yEAAyE;AACzE,eAAO,MAAM,iBAAiB,wBAAmB,CAAC;AAElD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,SAAS,GAAE,MAAqC,EAChD,QAAQ,GAAE,SAAS,MAAM,EAAgC,GACxD,MAAM,CAgBR;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC"}
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
// packages/protocol/src/validation/sanitize-error.ts
|
|
2
2
|
//
|
|
3
|
-
// Credential-leak sanitizer for
|
|
3
|
+
// Credential-leak sanitizer for stringified errors bound for the wire.
|
|
4
4
|
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
5
|
+
// A diagnostic cause string carries the stringified original error —
|
|
6
|
+
// typically `Error.stack`. Stacks frequently
|
|
7
7
|
// contain URLs with query-param tokens (`?token=...`, `?api_key=...`),
|
|
8
8
|
// Authorization header values captured by over-eager logging libraries,
|
|
9
|
-
// and env-var dumps. The
|
|
10
|
-
// `
|
|
11
|
-
//
|
|
12
|
-
// in operator tools (RenderInspector
|
|
13
|
-
// shares a bug report with that data,
|
|
9
|
+
// and env-var dumps. The primary consumer is the live channel's
|
|
10
|
+
// `channel_error` frame: a `POLL_FAILED` emission threads the polled
|
|
11
|
+
// tool's failure into the frame's `details` slot, where it is visible
|
|
12
|
+
// to the subscribed client and in operator tools (RenderInspector
|
|
13
|
+
// activity panels). If an operator shares a bug report with that data,
|
|
14
|
+
// the credential leaks externally.
|
|
14
15
|
//
|
|
15
|
-
// This module's default posture is "sanitize before emission":
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
// `createSessionChannelServer({ sanitizeCausedBy })`.
|
|
16
|
+
// This module's default posture is "sanitize before emission": every
|
|
17
|
+
// producer pipes the raw `err.stack` through {@link sanitizeCausedBy}
|
|
18
|
+
// before putting it on the wire. Producers that need stricter
|
|
19
|
+
// sanitization substitute their own {@link SanitizeCausedBy} function.
|
|
20
20
|
//
|
|
21
21
|
// Scope: this is a DEFENSE-IN-DEPTH belt, not the sole line. Libraries
|
|
22
22
|
// that handle secrets should already avoid embedding them in error
|
|
@@ -24,15 +24,15 @@
|
|
|
24
24
|
// opportunistically by code that didn't think about leaking and we'd
|
|
25
25
|
// rather redact conservatively than ship raw stacks.
|
|
26
26
|
/**
|
|
27
|
-
* Patterns stripped from stringified errors before
|
|
28
|
-
*
|
|
27
|
+
* Patterns stripped from stringified errors before they ride a wire
|
|
28
|
+
* frame. The default set covers the common credential
|
|
29
29
|
* shapes that show up in stack traces by accident (URLs with token query
|
|
30
30
|
* params, Bearer headers captured by retry libraries, env-var dumps).
|
|
31
31
|
*
|
|
32
32
|
* Each regex replaces the matched span with `[REDACTED]`. Replacement is
|
|
33
33
|
* conservative — we'd rather over-redact than leak. Operators who need
|
|
34
|
-
* finer control
|
|
35
|
-
*
|
|
34
|
+
* finer control supply a custom {@link SanitizeCausedBy} function (or
|
|
35
|
+
* pass a stricter pattern set to {@link sanitizeCausedBy}).
|
|
36
36
|
*/
|
|
37
37
|
export const DEFAULT_CREDENTIAL_PATTERNS = [
|
|
38
38
|
// Bearer / Basic header values. `Bearer <token>` / `Authorization: Basic <base64>`.
|
|
@@ -52,7 +52,8 @@ export const DEFAULT_CAUSED_BY_MAX_LENGTH = 2048;
|
|
|
52
52
|
export const TRUNCATION_MARKER = '\n…[truncated]';
|
|
53
53
|
/**
|
|
54
54
|
* Sanitize a stringified error (typically `err.stack`) before it's
|
|
55
|
-
* written to
|
|
55
|
+
* written to a wire-visible diagnostic slot (e.g. the `channel_error`
|
|
56
|
+
* frame's `details`).
|
|
56
57
|
*
|
|
57
58
|
* Applies every pattern in {@link DEFAULT_CREDENTIAL_PATTERNS} in order,
|
|
58
59
|
* replacing matches with `[REDACTED]`. If the result exceeds `maxLength`,
|
|
@@ -131,7 +131,7 @@ export declare class SchemaCompatInvariantError extends Error {
|
|
|
131
131
|
* agentCapabilities catalog.
|
|
132
132
|
*
|
|
133
133
|
* Slots alongside `assertCrossReferences` + `assertNameInvariants`
|
|
134
|
-
* at
|
|
134
|
+
* at render time. Different scope from the server-level
|
|
135
135
|
* `SchemaCompatError` thrown by `checkRenderSchemaCompat` in
|
|
136
136
|
* `@ggui-ai/mcp-server`: this check uses ONLY the contract's own
|
|
137
137
|
* catalog; the server-level check uses the runtime tool registry.
|
|
@@ -88,7 +88,7 @@ export function checkActionSchemaCompat(actionSpec, agentCapabilities) {
|
|
|
88
88
|
const tool = tools.get(toolName);
|
|
89
89
|
if (!tool)
|
|
90
90
|
continue; // CTR_REF_NEXT_STEP covers this
|
|
91
|
-
const toolInput = tool.inputSchema;
|
|
91
|
+
const toolInput = tool.toolInfo.inputSchema;
|
|
92
92
|
if (!toolInput)
|
|
93
93
|
continue; // catalog entry incomplete — no anchor
|
|
94
94
|
const actionSchema = entry.schema ?? {
|
|
@@ -143,7 +143,7 @@ export function checkStreamSchemaCompat(streamSpec, agentCapabilities) {
|
|
|
143
143
|
const tool = tools.get(toolName);
|
|
144
144
|
if (!tool)
|
|
145
145
|
continue; // CTR_REF_STREAM_SOURCE covers this
|
|
146
|
-
const toolOutput = tool.outputSchema;
|
|
146
|
+
const toolOutput = tool.toolInfo.outputSchema;
|
|
147
147
|
if (!toolOutput)
|
|
148
148
|
continue;
|
|
149
149
|
const channelSchema = entry.schema;
|
|
@@ -207,7 +207,7 @@ export class SchemaCompatInvariantError extends Error {
|
|
|
207
207
|
* agentCapabilities catalog.
|
|
208
208
|
*
|
|
209
209
|
* Slots alongside `assertCrossReferences` + `assertNameInvariants`
|
|
210
|
-
* at
|
|
210
|
+
* at render time. Different scope from the server-level
|
|
211
211
|
* `SchemaCompatError` thrown by `checkRenderSchemaCompat` in
|
|
212
212
|
* `@ggui-ai/mcp-server`: this check uses ONLY the contract's own
|
|
213
213
|
* catalog; the server-level check uses the runtime tool registry.
|