@ggui-ai/protocol 0.2.0-alpha.3 → 0.3.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 +64 -0
- package/dist/registry/portable-blueprint.d.ts.map +1 -0
- package/dist/registry/portable-blueprint.js +103 -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 +240 -58
- package/dist/schemas/mcp.d.ts.map +1 -1
- package/dist/schemas/mcp.js +285 -93
- 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 +60 -40
- 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.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 +55 -176
- package/dist/types/mcp.d.ts.map +1 -1
- package/dist/types/mcp.js +2 -2
- 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 +53 -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 +5 -46
- 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 +13 -10
- package/dist/validation/hygiene-rules.d.ts.map +1 -1
- package/dist/validation/hygiene-rules.js +20 -14
- 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 +9 -8
- package/dist/validation/lint-contract.d.ts.map +1 -1
- package/dist/validation/lint-contract.js +89 -26
- 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 +21 -8
- package/dist/validation/schema-meta-validation.d.ts.map +1 -1
- package/dist/validation/schema-meta-validation.js +28 -14
- 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 +783 -9
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +782 -8
- package/package.json +2 -2
- 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
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* - {@link validateContract} — strict; runs phased validation and
|
|
7
7
|
* throws {@link ContractValidationError} on the FIRST phase that
|
|
8
|
-
* produces errors. Used at every protocol boundary (
|
|
8
|
+
* produces errors. Used at every protocol boundary (render handler,
|
|
9
9
|
* blueprint registration, future synth output gate).
|
|
10
10
|
*
|
|
11
11
|
* - {@link lintContract} — graded; runs ALL phases unconditionally
|
|
@@ -17,9 +17,11 @@
|
|
|
17
17
|
*
|
|
18
18
|
* ```
|
|
19
19
|
* phase 1: shape (zod wire-shape validation)
|
|
20
|
-
* phase 2:
|
|
21
|
-
* phase 3: schema
|
|
22
|
-
* phase 4:
|
|
20
|
+
* phase 2: retired (CTR_RETIRED_FIELD — dead top-level fields)
|
|
21
|
+
* phase 3: schema-meta (CTR_SCHEMA_META_INVALID — Ajv strict on inner schemas)
|
|
22
|
+
* phase 4: references (CTR_REF_*, CTR_DUP_NAME, CTR_RESERVED_NAME)
|
|
23
|
+
* phase 5: schema compat (CTR_SCHEMA_INCOMPAT)
|
|
24
|
+
* phase 6: hygiene (LINT_* — graded, warnings only)
|
|
23
25
|
* ```
|
|
24
26
|
*
|
|
25
27
|
* Errors are reported one phase at a time during strict validation so
|
|
@@ -32,7 +34,8 @@ import { dataContractSchema } from '../schemas/data-contract.js';
|
|
|
32
34
|
import { checkCrossReferences, } from './cross-references.js';
|
|
33
35
|
import { checkNameInvariants, } from './name-invariants.js';
|
|
34
36
|
import { checkSchemaCompat, } from './schema-compat-invariants.js';
|
|
35
|
-
import {
|
|
37
|
+
import { checkContractSchemasValid } from './schema-meta-validation.js';
|
|
38
|
+
import { checkHygiene, checkRetiredContractFields, } from './hygiene-rules.js';
|
|
36
39
|
/**
|
|
37
40
|
* Strict-mode failure. Carries the offending phase + every issue
|
|
38
41
|
* the failing phase produced so error renderers can show every fix
|
|
@@ -60,8 +63,8 @@ export class ContractValidationError extends Error {
|
|
|
60
63
|
function phaseShape(contract) {
|
|
61
64
|
const parsed = dataContractSchema.safeParse(contract);
|
|
62
65
|
if (parsed.success)
|
|
63
|
-
return [];
|
|
64
|
-
return zodErrorToIssues(parsed.error);
|
|
66
|
+
return { issues: [], parsed: parsed.data };
|
|
67
|
+
return { issues: zodErrorToIssues(parsed.error), parsed: null };
|
|
65
68
|
}
|
|
66
69
|
function zodErrorToIssues(error) {
|
|
67
70
|
return error.issues.map((issue) => ({
|
|
@@ -89,6 +92,52 @@ function zodIssueCode(zodCode) {
|
|
|
89
92
|
}
|
|
90
93
|
}
|
|
91
94
|
// =============================================================================
|
|
95
|
+
// Phase — retired fields (CTR_RETIRED_FIELD)
|
|
96
|
+
// =============================================================================
|
|
97
|
+
/**
|
|
98
|
+
* Retired top-level field carriers (`wiredTools`, `libraries`,
|
|
99
|
+
* `dispatch`, …) are a fatal contract bug: the field rides through the
|
|
100
|
+
* `.passthrough()` schema but names dead protocol surface. Promoted
|
|
101
|
+
* from a hygiene WARNING to an ERROR so it routes through the same gate
|
|
102
|
+
* as every other contract error — the handshake repair loop remaps it
|
|
103
|
+
* (an LLM correctly re-nests `wiredTools` → `agentCapabilities.tools`),
|
|
104
|
+
* and `ggui_render`'s override path rejects it. Shares the one detector
|
|
105
|
+
* (`checkRetiredContractFields`) with the author-time surface + the
|
|
106
|
+
* render-gate assert, so the retired vocabulary can't drift across sites.
|
|
107
|
+
*/
|
|
108
|
+
function phaseRetired(contract) {
|
|
109
|
+
return checkRetiredContractFields(contract).map((w) => ({
|
|
110
|
+
code: 'CTR_RETIRED_FIELD',
|
|
111
|
+
severity: 'error',
|
|
112
|
+
phase: 'retired',
|
|
113
|
+
path: w.path,
|
|
114
|
+
message: w.message,
|
|
115
|
+
...(w.fixHint !== undefined ? { fixHint: w.fixHint } : {}),
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
118
|
+
// =============================================================================
|
|
119
|
+
// Phase — schema-meta (CTR_SCHEMA_META_INVALID, Ajv strict meta-validation)
|
|
120
|
+
// =============================================================================
|
|
121
|
+
/**
|
|
122
|
+
* Inner JSON Schema meta-validation — each `schema:` field must compile
|
|
123
|
+
* under Ajv strict mode. Distinct from phase-1 shape: zod validates the
|
|
124
|
+
* WRAPPER shape, but the wrapped JSON Schema rides through
|
|
125
|
+
* `.passthrough()` unvalidated. Runs before references / schema-compat,
|
|
126
|
+
* which read these schemas. This is the check the render/handshake assert
|
|
127
|
+
* set had that `validateContract` was previously missing — folding it in
|
|
128
|
+
* here is what makes the strict gate complete (and therefore safe to use
|
|
129
|
+
* as the single boundary gate).
|
|
130
|
+
*/
|
|
131
|
+
function phaseSchemaMeta(contract) {
|
|
132
|
+
return checkContractSchemasValid(contract).map((v) => ({
|
|
133
|
+
code: 'CTR_SCHEMA_META_INVALID',
|
|
134
|
+
severity: 'error',
|
|
135
|
+
phase: 'schema-meta',
|
|
136
|
+
path: v.field,
|
|
137
|
+
message: v.message,
|
|
138
|
+
}));
|
|
139
|
+
}
|
|
140
|
+
// =============================================================================
|
|
92
141
|
// Phase 2 — references (CTR_REF_*, CTR_DUP_NAME, CTR_RESERVED_NAME)
|
|
93
142
|
// =============================================================================
|
|
94
143
|
function phaseReferences(contract) {
|
|
@@ -171,18 +220,29 @@ function hygieneWarningToIssue(w) {
|
|
|
171
220
|
* gate. Use {@link lintContract} when warnings matter.
|
|
172
221
|
*/
|
|
173
222
|
export function validateContract(contract) {
|
|
174
|
-
const
|
|
175
|
-
if (
|
|
176
|
-
throw new ContractValidationError('shape',
|
|
223
|
+
const shape = phaseShape(contract);
|
|
224
|
+
if (shape.issues.length > 0) {
|
|
225
|
+
throw new ContractValidationError('shape', shape.issues);
|
|
226
|
+
}
|
|
227
|
+
// Shape passed ⇒ a parsed DataContract is available for the deeper,
|
|
228
|
+
// type-dependent phases. The null check narrows `c` to DataContract
|
|
229
|
+
// without a cast (unreachable: no shape issues ⇒ parsed present).
|
|
230
|
+
const c = shape.parsed;
|
|
231
|
+
if (c === null)
|
|
232
|
+
return;
|
|
233
|
+
const retiredIssues = phaseRetired(c);
|
|
234
|
+
if (retiredIssues.length > 0) {
|
|
235
|
+
throw new ContractValidationError('retired', retiredIssues);
|
|
236
|
+
}
|
|
237
|
+
const schemaMetaIssues = phaseSchemaMeta(c);
|
|
238
|
+
if (schemaMetaIssues.length > 0) {
|
|
239
|
+
throw new ContractValidationError('schema-meta', schemaMetaIssues);
|
|
177
240
|
}
|
|
178
|
-
|
|
179
|
-
// cast through into the phase-2 / phase-3 helpers (they accept
|
|
180
|
-
// `DataContract` directly).
|
|
181
|
-
const refIssues = phaseReferences(contract);
|
|
241
|
+
const refIssues = phaseReferences(c);
|
|
182
242
|
if (refIssues.length > 0) {
|
|
183
243
|
throw new ContractValidationError('references', refIssues);
|
|
184
244
|
}
|
|
185
|
-
const compatIssues = phaseSchemaCompat(
|
|
245
|
+
const compatIssues = phaseSchemaCompat(c);
|
|
186
246
|
if (compatIssues.length > 0) {
|
|
187
247
|
throw new ContractValidationError('schema-compat', compatIssues);
|
|
188
248
|
}
|
|
@@ -201,18 +261,21 @@ export function validateContract(contract) {
|
|
|
201
261
|
*/
|
|
202
262
|
export function lintContract(contract) {
|
|
203
263
|
const issues = [];
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
//
|
|
207
|
-
//
|
|
208
|
-
//
|
|
209
|
-
// "fix shape first" via the shape issues
|
|
210
|
-
//
|
|
211
|
-
if (issues.length === 0) {
|
|
212
|
-
|
|
213
|
-
issues.push(...
|
|
264
|
+
const shape = phaseShape(contract);
|
|
265
|
+
issues.push(...shape.issues);
|
|
266
|
+
// Phases beyond shape are shape-dependent and need a parsed
|
|
267
|
+
// DataContract. When shape failed, skip them (the contract may not
|
|
268
|
+
// match the type signatures these phases assume); authoring tools see
|
|
269
|
+
// "fix shape first" via the shape issues, and the next run reaches the
|
|
270
|
+
// deeper phases once shape is clean.
|
|
271
|
+
if (shape.issues.length === 0 && shape.parsed !== null) {
|
|
272
|
+
const c = shape.parsed;
|
|
273
|
+
issues.push(...phaseRetired(c));
|
|
274
|
+
issues.push(...phaseSchemaMeta(c));
|
|
275
|
+
issues.push(...phaseReferences(c));
|
|
276
|
+
issues.push(...phaseSchemaCompat(c));
|
|
277
|
+
issues.push(...phaseHygiene(c));
|
|
214
278
|
}
|
|
215
|
-
issues.push(...phaseHygiene(contract));
|
|
216
279
|
const errors = [];
|
|
217
280
|
const warnings = [];
|
|
218
281
|
for (const issue of issues) {
|
|
@@ -41,7 +41,7 @@ import type { ContractViolation } from './contract-validator';
|
|
|
41
41
|
* Stable error code for collisions across the three inbound spec maps
|
|
42
42
|
* (`actionSpec` / `streamSpec` / `contextSpec`). The boilerplate
|
|
43
43
|
* generator emits identifiers from these keys; a collision is an
|
|
44
|
-
* author bug that the protocol catches at
|
|
44
|
+
* author bug that the protocol catches at render.
|
|
45
45
|
*/
|
|
46
46
|
export declare const CTR_DUP_NAME = "CTR_DUP_NAME";
|
|
47
47
|
/**
|
|
@@ -72,7 +72,7 @@ export declare function checkNameCollisions(contract: DataContract): NameInvaria
|
|
|
72
72
|
* Validate that no `actionSpec` or `contextSpec` key uses the
|
|
73
73
|
* `_ggui:` reserved namespace. `streamSpec` reserved-channel rejection
|
|
74
74
|
* lives in `validateContractStructure` (the reserved namespace there
|
|
75
|
-
* carries server-side semantics like the `_ggui:
|
|
75
|
+
* carries server-side semantics like the `_ggui:lifecycle`
|
|
76
76
|
* channel); this invariant extends the rule uniformly across the
|
|
77
77
|
* other two inbound spec maps.
|
|
78
78
|
*
|
|
@@ -93,7 +93,7 @@ export declare function checkNameInvariants(contract: DataContract): NameInvaria
|
|
|
93
93
|
/**
|
|
94
94
|
* Throwable form of {@link checkNameInvariants}. Use at protocol
|
|
95
95
|
* boundaries where a name collision or reserved-namespace use is a
|
|
96
|
-
* contract bug the caller must fix (
|
|
96
|
+
* contract bug the caller must fix (render handler, blueprint
|
|
97
97
|
* registration).
|
|
98
98
|
*
|
|
99
99
|
* Carries the full violation list so error renderers can show every
|
|
@@ -108,7 +108,7 @@ export declare class NameInvariantError extends Error {
|
|
|
108
108
|
* Throw-on-violation wrapper around {@link checkNameInvariants}.
|
|
109
109
|
* No-op when the contract's names are consistent.
|
|
110
110
|
*
|
|
111
|
-
* Designed to slot alongside `assertCrossReferences` at
|
|
111
|
+
* Designed to slot alongside `assertCrossReferences` at render time:
|
|
112
112
|
* cross-reference invariants catch dangling pointers between specs;
|
|
113
113
|
* name invariants catch malformed name spaces within specs. Both
|
|
114
114
|
* surface author-recoverable failures before any state mutation.
|
|
@@ -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"}
|