@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
|
@@ -24,7 +24,7 @@ export interface ValidationResult {
|
|
|
24
24
|
* pre-injection wrapper.
|
|
25
25
|
*
|
|
26
26
|
* Shared by {@link validatePropsData} (server-side runtime check) and
|
|
27
|
-
* {@link compileContractValidators} (
|
|
27
|
+
* {@link compileContractValidators} (render-time standalone emission) so
|
|
28
28
|
* the precompiled in-iframe validator enforces byte-identical
|
|
29
29
|
* semantics to the runtime validator — one synthesis, no drift.
|
|
30
30
|
*/
|
|
@@ -42,7 +42,7 @@ export declare function buildPropsWrapperSchema(spec: PropsSpec): JsonSchema;
|
|
|
42
42
|
*
|
|
43
43
|
* Load-bearing for `ggui_update kind:'merge'` (RFC 7396): a patch
|
|
44
44
|
* adding a key absent from `propsSpec.properties` would silently
|
|
45
|
-
* land on the
|
|
45
|
+
* land on the render without this gate. Same rule applies to
|
|
46
46
|
* the `done`-vs-declared-`completed` class of bug inside array
|
|
47
47
|
* items — Ajv rejects with the exact path (`todos[0].done`).
|
|
48
48
|
*/
|
|
@@ -75,18 +75,18 @@ export declare function validatePropsData(props: Record<string, unknown>, spec:
|
|
|
75
75
|
* validator for `_ggui:preview`. Consulted FIRST so callers can
|
|
76
76
|
* override or extend built-ins.
|
|
77
77
|
* 2. `BUILTIN_RESERVED_VALIDATORS` — protocol-owned, always active.
|
|
78
|
-
* Ships the {@link
|
|
79
|
-
* `_ggui:
|
|
78
|
+
* Ships the {@link validateGguiLifecyclePayload} for
|
|
79
|
+
* `_ggui:lifecycle`.
|
|
80
80
|
* 3. Fall-through: if no validator is registered for the known
|
|
81
81
|
* reserved channel, return `{valid: true}`. Preserves backward
|
|
82
82
|
* compatibility for any future reserved channel the runtime
|
|
83
83
|
* adds before its validator is authored.
|
|
84
84
|
*
|
|
85
|
-
* Without this structure, a `_ggui:preview` emission into a
|
|
86
|
-
* whose active
|
|
85
|
+
* Without this structure, a `_ggui:preview` emission into a render
|
|
86
|
+
* whose active render carries ANY user streamSpec would
|
|
87
87
|
* synthesize a false "Unknown channel" violation, blocking the
|
|
88
88
|
* provisional preview runtime. Symmetric with the client-side
|
|
89
|
-
* handling in `
|
|
89
|
+
* handling in `GguiRender`.
|
|
90
90
|
*
|
|
91
91
|
* Crucially narrow by design — the known-reserved path is a CLOSED
|
|
92
92
|
* SET, not a prefix check. A typo inside the reserved namespace
|
|
@@ -118,7 +118,7 @@ export declare function validateStreamData(channelName: string, payload: unknown
|
|
|
118
118
|
*/
|
|
119
119
|
export declare function validateContextData(slotName: string, value: unknown, spec: ContextSpec, precompiledSlots?: ReadonlyMap<string, ValidateFunction>): ValidationResult;
|
|
120
120
|
/**
|
|
121
|
-
* Validate an inbound user-action payload against the
|
|
121
|
+
* Validate an inbound user-action payload against the render's ActionSpec.
|
|
122
122
|
*
|
|
123
123
|
* Symmetric with {@link validatePropsData} / {@link validateStreamData}, but for
|
|
124
124
|
* live-channel INBOUND user → core traffic. Enforces the action contract at the
|
|
@@ -140,24 +140,25 @@ export declare function validateContextData(slotName: string, value: unknown, sp
|
|
|
140
140
|
*/
|
|
141
141
|
export declare function validateActionData(value: unknown, spec: ActionSpec, precompiledActions?: ReadonlyMap<string, ValidateFunction>): ValidationResult;
|
|
142
142
|
/**
|
|
143
|
-
* Validate an inbound {@link ActionEnvelope} against the target
|
|
144
|
-
*
|
|
145
|
-
* inbound enforcement — the
|
|
146
|
-
*
|
|
147
|
-
*
|
|
143
|
+
* Validate an inbound {@link ActionEnvelope} against the target
|
|
144
|
+
* render's {@link ActionSpec}. Payload-contract layer of live-channel
|
|
145
|
+
* inbound enforcement — the ONLY gate on inbound actions today (the
|
|
146
|
+
* pre-Phase-B `subscription.events` allowlist gate was deleted with
|
|
147
|
+
* the session-stack collapse).
|
|
148
148
|
*
|
|
149
149
|
* Semantics:
|
|
150
150
|
* - `envelope.type !== 'data:submit'` → `{valid: true, violations: []}`.
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
151
|
+
* {@link EventType} has exactly one member, so a TYPED caller never
|
|
152
|
+
* hits this branch — it is a wire-trust guard: a rogue client's
|
|
153
|
+
* envelope claiming an unknown type string is ledger-only upstream
|
|
154
|
+
* and gets no payload enforcement on this layer.
|
|
155
|
+
* - `spec === undefined` → `{valid: true, violations: []}`. Renders
|
|
156
|
+
* without an actionSpec have no contract; legacy renders keep
|
|
156
157
|
* flowing.
|
|
157
158
|
* - Otherwise `envelope.payload` is validated against `spec` via
|
|
158
159
|
* {@link validateActionData}. Same rules, same output shape.
|
|
159
160
|
*
|
|
160
|
-
* This helper does NOT enforce allowlist,
|
|
161
|
+
* This helper does NOT enforce allowlist, render binding, or render
|
|
161
162
|
* routing — those are ingress-plumbing concerns. Pure payload-shape
|
|
162
163
|
* check; returns `ValidationResult` rather than throwing so callers
|
|
163
164
|
* can decide whether to surface as a wire error, log, etc.
|
|
@@ -171,7 +172,7 @@ export declare function validateActionEnvelope(envelope: ActionEnvelope, spec: A
|
|
|
171
172
|
*
|
|
172
173
|
* The renderer iframe runs under a strict CSP with no `'unsafe-eval'`,
|
|
173
174
|
* so it cannot call `ajv.compile()` (which builds validators via
|
|
174
|
-
* `new Function`). Compilation therefore happens server-side at
|
|
175
|
+
* `new Function`). Compilation therefore happens server-side at render
|
|
175
176
|
* time — where the contract schema is fixed and codegen is legal — and
|
|
176
177
|
* the iframe loads each emitted module via a `blob:` dynamic import.
|
|
177
178
|
*
|
|
@@ -216,7 +217,7 @@ export declare function compileContractValidators(specs: {
|
|
|
216
217
|
* + Node — the producer's iteration order is preserved, so a given
|
|
217
218
|
* contract always serializes to identical bytes. {@link computeContractBundle}
|
|
218
219
|
* leans on that determinism so the resulting hash is stable across
|
|
219
|
-
*
|
|
220
|
+
* renders of the same contract.
|
|
220
221
|
*
|
|
221
222
|
* @public
|
|
222
223
|
*/
|
|
@@ -224,7 +225,7 @@ export declare function bundleCompiledValidatorsAsModule(compiled: CompiledContr
|
|
|
224
225
|
/**
|
|
225
226
|
* Convenience over {@link compileContractValidators} +
|
|
226
227
|
* {@link bundleCompiledValidatorsAsModule} + sha256 — produces the
|
|
227
|
-
* `{contractHash, bundleSource, validators}` triple the emitter (
|
|
228
|
+
* `{contractHash, bundleSource, validators}` triple the emitter (render.ts
|
|
228
229
|
* / update.ts in #109 C4) writes to the content-addressable store and
|
|
229
230
|
* emits as `_meta["ai.ggui/contract"] = {contractHash, validatorsUrl}`.
|
|
230
231
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract-validator.d.ts","sourceRoot":"","sources":["../../src/validation/contract-validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEnI,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAO3E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAItD,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"contract-validator.d.ts","sourceRoot":"","sources":["../../src/validation/contract-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import { deriveContextDefault } from '../types/data-contract.js';
|
|
|
2
2
|
import { compileForValidation, compileValidatorModule, mapAjvErrorsToViolations, prefixViolations, } from './ajv-runtime.js';
|
|
3
3
|
import { checkCrossReferences } from './cross-references.js';
|
|
4
4
|
import { checkNameInvariants } from './name-invariants.js';
|
|
5
|
+
import { isRecord } from './is-record.js';
|
|
5
6
|
import { checkSchemaCompat } from './schema-compat-invariants.js';
|
|
6
7
|
import { BUILTIN_RESERVED_VALIDATORS, RESERVED_CHANNEL_PREFIX, isKnownReservedChannel, isReservedChannelName, } from './reserved-channels.js';
|
|
7
8
|
/**
|
|
@@ -14,7 +15,7 @@ import { BUILTIN_RESERVED_VALIDATORS, RESERVED_CHANNEL_PREFIX, isKnownReservedCh
|
|
|
14
15
|
* pre-injection wrapper.
|
|
15
16
|
*
|
|
16
17
|
* Shared by {@link validatePropsData} (server-side runtime check) and
|
|
17
|
-
* {@link compileContractValidators} (
|
|
18
|
+
* {@link compileContractValidators} (render-time standalone emission) so
|
|
18
19
|
* the precompiled in-iframe validator enforces byte-identical
|
|
19
20
|
* semantics to the runtime validator — one synthesis, no drift.
|
|
20
21
|
*/
|
|
@@ -44,7 +45,7 @@ export function buildPropsWrapperSchema(spec) {
|
|
|
44
45
|
*
|
|
45
46
|
* Load-bearing for `ggui_update kind:'merge'` (RFC 7396): a patch
|
|
46
47
|
* adding a key absent from `propsSpec.properties` would silently
|
|
47
|
-
* land on the
|
|
48
|
+
* land on the render without this gate. Same rule applies to
|
|
48
49
|
* the `done`-vs-declared-`completed` class of bug inside array
|
|
49
50
|
* items — Ajv rejects with the exact path (`todos[0].done`).
|
|
50
51
|
*/
|
|
@@ -89,18 +90,18 @@ export function validatePropsData(props, spec, precompiled) {
|
|
|
89
90
|
* validator for `_ggui:preview`. Consulted FIRST so callers can
|
|
90
91
|
* override or extend built-ins.
|
|
91
92
|
* 2. `BUILTIN_RESERVED_VALIDATORS` — protocol-owned, always active.
|
|
92
|
-
* Ships the {@link
|
|
93
|
-
* `_ggui:
|
|
93
|
+
* Ships the {@link validateGguiLifecyclePayload} for
|
|
94
|
+
* `_ggui:lifecycle`.
|
|
94
95
|
* 3. Fall-through: if no validator is registered for the known
|
|
95
96
|
* reserved channel, return `{valid: true}`. Preserves backward
|
|
96
97
|
* compatibility for any future reserved channel the runtime
|
|
97
98
|
* adds before its validator is authored.
|
|
98
99
|
*
|
|
99
|
-
* Without this structure, a `_ggui:preview` emission into a
|
|
100
|
-
* whose active
|
|
100
|
+
* Without this structure, a `_ggui:preview` emission into a render
|
|
101
|
+
* whose active render carries ANY user streamSpec would
|
|
101
102
|
* synthesize a false "Unknown channel" violation, blocking the
|
|
102
103
|
* provisional preview runtime. Symmetric with the client-side
|
|
103
|
-
* handling in `
|
|
104
|
+
* handling in `GguiRender`.
|
|
104
105
|
*
|
|
105
106
|
* Crucially narrow by design — the known-reserved path is a CLOSED
|
|
106
107
|
* SET, not a prefix check. A typo inside the reserved namespace
|
|
@@ -190,7 +191,7 @@ export function validateContextData(slotName, value, spec, precompiledSlots) {
|
|
|
190
191
|
return { valid: violations.length === 0, violations };
|
|
191
192
|
}
|
|
192
193
|
/**
|
|
193
|
-
* Validate an inbound user-action payload against the
|
|
194
|
+
* Validate an inbound user-action payload against the render's ActionSpec.
|
|
194
195
|
*
|
|
195
196
|
* Symmetric with {@link validatePropsData} / {@link validateStreamData}, but for
|
|
196
197
|
* live-channel INBOUND user → core traffic. Enforces the action contract at the
|
|
@@ -212,7 +213,7 @@ export function validateContextData(slotName, value, spec, precompiledSlots) {
|
|
|
212
213
|
*/
|
|
213
214
|
export function validateActionData(value, spec, precompiledActions) {
|
|
214
215
|
const violations = [];
|
|
215
|
-
if (
|
|
216
|
+
if (!isRecord(value)) {
|
|
216
217
|
violations.push({
|
|
217
218
|
field: 'value',
|
|
218
219
|
message: 'Action payload must be an object with an `action` field',
|
|
@@ -261,24 +262,25 @@ function getJsonType(value) {
|
|
|
261
262
|
return typeof value;
|
|
262
263
|
}
|
|
263
264
|
/**
|
|
264
|
-
* Validate an inbound {@link ActionEnvelope} against the target
|
|
265
|
-
*
|
|
266
|
-
* inbound enforcement — the
|
|
267
|
-
*
|
|
268
|
-
*
|
|
265
|
+
* Validate an inbound {@link ActionEnvelope} against the target
|
|
266
|
+
* render's {@link ActionSpec}. Payload-contract layer of live-channel
|
|
267
|
+
* inbound enforcement — the ONLY gate on inbound actions today (the
|
|
268
|
+
* pre-Phase-B `subscription.events` allowlist gate was deleted with
|
|
269
|
+
* the session-stack collapse).
|
|
269
270
|
*
|
|
270
271
|
* Semantics:
|
|
271
272
|
* - `envelope.type !== 'data:submit'` → `{valid: true, violations: []}`.
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
*
|
|
273
|
+
* {@link EventType} has exactly one member, so a TYPED caller never
|
|
274
|
+
* hits this branch — it is a wire-trust guard: a rogue client's
|
|
275
|
+
* envelope claiming an unknown type string is ledger-only upstream
|
|
276
|
+
* and gets no payload enforcement on this layer.
|
|
277
|
+
* - `spec === undefined` → `{valid: true, violations: []}`. Renders
|
|
278
|
+
* without an actionSpec have no contract; legacy renders keep
|
|
277
279
|
* flowing.
|
|
278
280
|
* - Otherwise `envelope.payload` is validated against `spec` via
|
|
279
281
|
* {@link validateActionData}. Same rules, same output shape.
|
|
280
282
|
*
|
|
281
|
-
* This helper does NOT enforce allowlist,
|
|
283
|
+
* This helper does NOT enforce allowlist, render binding, or render
|
|
282
284
|
* routing — those are ingress-plumbing concerns. Pure payload-shape
|
|
283
285
|
* check; returns `ValidationResult` rather than throwing so callers
|
|
284
286
|
* can decide whether to surface as a wire error, log, etc.
|
|
@@ -298,7 +300,7 @@ export function validateActionEnvelope(envelope, spec, precompiledActions) {
|
|
|
298
300
|
*
|
|
299
301
|
* The renderer iframe runs under a strict CSP with no `'unsafe-eval'`,
|
|
300
302
|
* so it cannot call `ajv.compile()` (which builds validators via
|
|
301
|
-
* `new Function`). Compilation therefore happens server-side at
|
|
303
|
+
* `new Function`). Compilation therefore happens server-side at render
|
|
302
304
|
* time — where the contract schema is fixed and codegen is legal — and
|
|
303
305
|
* the iframe loads each emitted module via a `blob:` dynamic import.
|
|
304
306
|
*
|
|
@@ -369,7 +371,7 @@ export function compileContractValidators(specs) {
|
|
|
369
371
|
* + Node — the producer's iteration order is preserved, so a given
|
|
370
372
|
* contract always serializes to identical bytes. {@link computeContractBundle}
|
|
371
373
|
* leans on that determinism so the resulting hash is stable across
|
|
372
|
-
*
|
|
374
|
+
* renders of the same contract.
|
|
373
375
|
*
|
|
374
376
|
* @public
|
|
375
377
|
*/
|
|
@@ -399,7 +401,7 @@ function canonicalJsonStringify(value) {
|
|
|
399
401
|
if (Array.isArray(value)) {
|
|
400
402
|
return `[${value.map(canonicalJsonStringify).join(',')}]`;
|
|
401
403
|
}
|
|
402
|
-
if (
|
|
404
|
+
if (isRecord(value)) {
|
|
403
405
|
const keys = Object.keys(value).sort();
|
|
404
406
|
const parts = keys.map((k) => `${JSON.stringify(k)}:${canonicalJsonStringify(value[k])}`);
|
|
405
407
|
return `{${parts.join(',')}}`;
|
|
@@ -410,7 +412,7 @@ function canonicalJsonStringify(value) {
|
|
|
410
412
|
/**
|
|
411
413
|
* Convenience over {@link compileContractValidators} +
|
|
412
414
|
* {@link bundleCompiledValidatorsAsModule} + sha256 — produces the
|
|
413
|
-
* `{contractHash, bundleSource, validators}` triple the emitter (
|
|
415
|
+
* `{contractHash, bundleSource, validators}` triple the emitter (render.ts
|
|
414
416
|
* / update.ts in #109 C4) writes to the content-addressable store and
|
|
415
417
|
* emits as `_meta["ai.ggui/contract"] = {contractHash, validatorsUrl}`.
|
|
416
418
|
*
|
|
@@ -573,7 +575,7 @@ export function validateContractStructure(contract) {
|
|
|
573
575
|
* Slot-key identifier check for contextSpec. Slot keys are surfaced
|
|
574
576
|
* as React Context names by the boilerplate generator (`currentStep`
|
|
575
577
|
* → `CurrentStepContext`); a non-identifier here would break the
|
|
576
|
-
* generation step at runtime, so we reject at
|
|
578
|
+
* generation step at runtime, so we reject at render-time instead.
|
|
577
579
|
*/
|
|
578
580
|
const CONTEXT_SLOT_KEY_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
579
581
|
/**
|
|
@@ -582,7 +584,7 @@ const CONTEXT_SLOT_KEY_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
|
582
584
|
* context map (e.g., `obj['__proto__'] = …` in pre-frozen
|
|
583
585
|
* environments would mutate the prototype chain rather than set a
|
|
584
586
|
* slot). Defensive — the runtime uses a frozen spec lookup, but the
|
|
585
|
-
*
|
|
587
|
+
* render-time gate keeps the invariant load-bearing for any future
|
|
586
588
|
* implementation that materializes the spec into a plain object.
|
|
587
589
|
*/
|
|
588
590
|
const CONTEXT_RESERVED_KEYS = new Set([
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* own `agentCapabilities.tools` catalog — same-MCP and cross-MCP both
|
|
14
14
|
* funnel through this single resolution path (the catalog is the
|
|
15
15
|
* declarative source of truth for every referenced tool). Violations
|
|
16
|
-
* are author-recoverable at
|
|
16
|
+
* are author-recoverable at render time.
|
|
17
17
|
*/
|
|
18
18
|
import type { DataContract, ActionSpec, StreamSpec, AgentCapabilitiesSpec } from '../types/data-contract';
|
|
19
19
|
import type { ContractViolation } from './contract-validator';
|
|
@@ -83,7 +83,7 @@ export declare function checkCrossReferences(contract: DataContract): CrossRefer
|
|
|
83
83
|
/**
|
|
84
84
|
* Throwable form of {@link checkCrossReferences}. Use at protocol
|
|
85
85
|
* boundaries where an unresolved cross-reference is a contract bug
|
|
86
|
-
* the caller must fix (
|
|
86
|
+
* the caller must fix (render handler, blueprint registration).
|
|
87
87
|
*
|
|
88
88
|
* Carries the full violation list so error renderers can show every
|
|
89
89
|
* dangling reference in one pass instead of fix-and-retry per-field.
|
|
@@ -97,7 +97,7 @@ export declare class CrossReferenceError extends Error {
|
|
|
97
97
|
* Throw-on-violation wrapper around {@link checkCrossReferences}.
|
|
98
98
|
* No-op when the contract is internally consistent.
|
|
99
99
|
*
|
|
100
|
-
* Invoked at handshake AND
|
|
100
|
+
* Invoked at handshake AND render time: contract-internal mistakes
|
|
101
101
|
* surface at the earliest possible boundary so the agent can fix and
|
|
102
102
|
* retry on the SAME handshakeId.
|
|
103
103
|
*/
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* own `agentCapabilities.tools` catalog — same-MCP and cross-MCP both
|
|
14
14
|
* funnel through this single resolution path (the catalog is the
|
|
15
15
|
* declarative source of truth for every referenced tool). Violations
|
|
16
|
-
* are author-recoverable at
|
|
16
|
+
* are author-recoverable at render time.
|
|
17
17
|
*/
|
|
18
18
|
/**
|
|
19
19
|
* Stable error code emitted when an `actionSpec[*].nextStep` value
|
|
@@ -131,7 +131,7 @@ export function checkCrossReferences(contract) {
|
|
|
131
131
|
/**
|
|
132
132
|
* Throwable form of {@link checkCrossReferences}. Use at protocol
|
|
133
133
|
* boundaries where an unresolved cross-reference is a contract bug
|
|
134
|
-
* the caller must fix (
|
|
134
|
+
* the caller must fix (render handler, blueprint registration).
|
|
135
135
|
*
|
|
136
136
|
* Carries the full violation list so error renderers can show every
|
|
137
137
|
* dangling reference in one pass instead of fix-and-retry per-field.
|
|
@@ -152,7 +152,7 @@ export class CrossReferenceError extends Error {
|
|
|
152
152
|
* Throw-on-violation wrapper around {@link checkCrossReferences}.
|
|
153
153
|
* No-op when the contract is internally consistent.
|
|
154
154
|
*
|
|
155
|
-
* Invoked at handshake AND
|
|
155
|
+
* Invoked at handshake AND render time: contract-internal mistakes
|
|
156
156
|
* surface at the earliest possible boundary so the agent can fix and
|
|
157
157
|
* retry on the SAME handshakeId.
|
|
158
158
|
*/
|
|
@@ -102,7 +102,7 @@ export declare const FATAL_CATALOG_LINT_CODES: ReadonlySet<string>;
|
|
|
102
102
|
* - `broadcast` → `streamSpec[ch].source`
|
|
103
103
|
* - `capabilities` → `agentCapabilities` + `clientCapabilities`
|
|
104
104
|
*
|
|
105
|
-
*
|
|
105
|
+
* Render-gate handlers re-use this list to hard-reject; surfacing it
|
|
106
106
|
* here keeps the wire vocabulary single-sourced.
|
|
107
107
|
*/
|
|
108
108
|
export declare const RETIRED_CONTRACT_FIELDS: Readonly<Record<string, string>>;
|
|
@@ -147,7 +147,7 @@ export declare function checkOrphanAgentTools(contract: DataContract): HygieneWa
|
|
|
147
147
|
* is intentionally NOT linted here: `GadgetExportUse.usage` is an
|
|
148
148
|
* OPTIONAL intent-OVERRIDE, and the SPEC-documented canonical wire
|
|
149
149
|
* form is the bare identity reference `gadgets[<pkg>][<export>] = {}`.
|
|
150
|
-
*
|
|
150
|
+
* Render-time resolution inherits the registered descriptor's `usage`,
|
|
151
151
|
* and the registry-side `lintGadgetCatalog` (via
|
|
152
152
|
* `strictGadgetExportSchema`) already enforces real teaching text at
|
|
153
153
|
* registration time. Flagging an empty wire-side use object would
|
|
@@ -169,7 +169,7 @@ export declare function checkMissingExample(contract: DataContract): HygieneWarn
|
|
|
169
169
|
*
|
|
170
170
|
* Third-party packages (any `package !== DEFAULT_GADGET_PACKAGE`) are
|
|
171
171
|
* NOT checked here — the lint can't know an operator's own hook
|
|
172
|
-
* names. The registry-side {@link lintGadgetCatalog} + the
|
|
172
|
+
* names. The registry-side {@link lintGadgetCatalog} + the render-time
|
|
173
173
|
* {@link assertGadgetsRegistered} gate cover third-party resolution.
|
|
174
174
|
*
|
|
175
175
|
* Permission checks live on the registry-side `lintGadgetCatalog`
|
|
@@ -189,9 +189,9 @@ export declare function checkGadgetHookNames(contract: DataContract): HygieneWar
|
|
|
189
189
|
* imports of the same name — from different packages — produce an
|
|
190
190
|
* unresolvable identifier collision in the generated module scope.
|
|
191
191
|
*
|
|
192
|
-
* Keys on the export name alone, matching the
|
|
192
|
+
* Keys on the export name alone, matching the render-time hard gate
|
|
193
193
|
* `assertNoDuplicateGadgetHooks`. Soft mirror of that gate so
|
|
194
|
-
* authoring tools surface the issue before a
|
|
194
|
+
* authoring tools surface the issue before a render round-trip.
|
|
195
195
|
*/
|
|
196
196
|
export declare function checkDuplicateGadgetHooks(contract: DataContract): HygieneWarning[];
|
|
197
197
|
/**
|
|
@@ -228,10 +228,10 @@ export declare function lintGadgetCatalog(descriptors: readonly GadgetDescriptor
|
|
|
228
228
|
* Find top-level retired-field carriers on the contract. The schema
|
|
229
229
|
* is `.passthrough()`, so a stray `libraries`/`dispatch`/`wiredTools`/
|
|
230
230
|
* `clientTools`/`broadcast`/`capabilities` slips through silently. The
|
|
231
|
-
*
|
|
231
|
+
* render-gate hard-rejects these (see
|
|
232
232
|
* `mcp-server-handlers/.../assert-contract-no-retired-fields.ts`); this
|
|
233
233
|
* lint surface keeps authoring tools symmetric — show the warning before
|
|
234
|
-
* the
|
|
234
|
+
* the render call so the author can fix it without a server round-trip.
|
|
235
235
|
*/
|
|
236
236
|
export declare function checkRetiredContractFields(contract: DataContract): HygieneWarning[];
|
|
237
237
|
/**
|
|
@@ -241,11 +241,11 @@ export declare function checkRetiredContractFields(contract: DataContract): Hygi
|
|
|
241
241
|
* checklist. Retired-field detection is NOT here — it is promoted to an
|
|
242
242
|
* ERROR phase (`phaseRetired` in lint-contract.ts); the detector
|
|
243
243
|
* `checkRetiredContractFields` stays exported for the author-time
|
|
244
|
-
* surface and the
|
|
244
|
+
* surface and the render-gate assert.
|
|
245
245
|
*
|
|
246
246
|
* Registry-side gadget lints (`lintGadgetCatalog`) are NOT run here:
|
|
247
247
|
* they need an `App.gadgets` descriptor array, not a contract, and
|
|
248
|
-
* fire at registration time rather than
|
|
248
|
+
* fire at registration time rather than render time.
|
|
249
249
|
* Call {@link lintGadgetCatalog} separately at the registration
|
|
250
250
|
* boundary.
|
|
251
251
|
*/
|
|
@@ -109,7 +109,7 @@ export const FATAL_CATALOG_LINT_CODES = new Set([
|
|
|
109
109
|
* - `broadcast` → `streamSpec[ch].source`
|
|
110
110
|
* - `capabilities` → `agentCapabilities` + `clientCapabilities`
|
|
111
111
|
*
|
|
112
|
-
*
|
|
112
|
+
* Render-gate handlers re-use this list to hard-reject; surfacing it
|
|
113
113
|
* here keeps the wire vocabulary single-sourced.
|
|
114
114
|
*/
|
|
115
115
|
export const RETIRED_CONTRACT_FIELDS = {
|
|
@@ -124,12 +124,12 @@ export const RETIRED_CONTRACT_FIELDS = {
|
|
|
124
124
|
* Sourced from {@link STDLIB_GADGET_HOOKS} — the canonical
|
|
125
125
|
* hook-name set the first-party `@ggui-ai/gadgets` package
|
|
126
126
|
* exports. Local alias keeps existing call sites stable while the
|
|
127
|
-
* source of truth lives in `
|
|
127
|
+
* source of truth lives in `gadgets/stdlib-gadgets.ts`.
|
|
128
128
|
*/
|
|
129
129
|
const KNOWN_STDLIB_HOOKS = STDLIB_GADGET_HOOKS;
|
|
130
130
|
/**
|
|
131
131
|
* Default package for gadget hooks. Sourced from the
|
|
132
|
-
* stdlib-
|
|
132
|
+
* stdlib-gadgets registry — when an entry's `package` is omitted,
|
|
133
133
|
* the hygiene linter assumes it resolves to the first-party
|
|
134
134
|
* `@ggui-ai/gadgets` package and runs hook-registry +
|
|
135
135
|
* permission checks against the stdlib catalog. Third-party packages
|
|
@@ -248,7 +248,7 @@ export function checkOrphanAgentTools(contract) {
|
|
|
248
248
|
* is intentionally NOT linted here: `GadgetExportUse.usage` is an
|
|
249
249
|
* OPTIONAL intent-OVERRIDE, and the SPEC-documented canonical wire
|
|
250
250
|
* form is the bare identity reference `gadgets[<pkg>][<export>] = {}`.
|
|
251
|
-
*
|
|
251
|
+
* Render-time resolution inherits the registered descriptor's `usage`,
|
|
252
252
|
* and the registry-side `lintGadgetCatalog` (via
|
|
253
253
|
* `strictGadgetExportSchema`) already enforces real teaching text at
|
|
254
254
|
* registration time. Flagging an empty wire-side use object would
|
|
@@ -307,7 +307,7 @@ export function checkMissingExample(contract) {
|
|
|
307
307
|
*
|
|
308
308
|
* Third-party packages (any `package !== DEFAULT_GADGET_PACKAGE`) are
|
|
309
309
|
* NOT checked here — the lint can't know an operator's own hook
|
|
310
|
-
* names. The registry-side {@link lintGadgetCatalog} + the
|
|
310
|
+
* names. The registry-side {@link lintGadgetCatalog} + the render-time
|
|
311
311
|
* {@link assertGadgetsRegistered} gate cover third-party resolution.
|
|
312
312
|
*
|
|
313
313
|
* Permission checks live on the registry-side `lintGadgetCatalog`
|
|
@@ -357,9 +357,9 @@ export function checkGadgetHookNames(contract) {
|
|
|
357
357
|
* imports of the same name — from different packages — produce an
|
|
358
358
|
* unresolvable identifier collision in the generated module scope.
|
|
359
359
|
*
|
|
360
|
-
* Keys on the export name alone, matching the
|
|
360
|
+
* Keys on the export name alone, matching the render-time hard gate
|
|
361
361
|
* `assertNoDuplicateGadgetHooks`. Soft mirror of that gate so
|
|
362
|
-
* authoring tools surface the issue before a
|
|
362
|
+
* authoring tools surface the issue before a render round-trip.
|
|
363
363
|
*/
|
|
364
364
|
export function checkDuplicateGadgetHooks(contract) {
|
|
365
365
|
const seen = new Map(); // export name → first package
|
|
@@ -516,10 +516,10 @@ export function lintGadgetCatalog(descriptors) {
|
|
|
516
516
|
* Find top-level retired-field carriers on the contract. The schema
|
|
517
517
|
* is `.passthrough()`, so a stray `libraries`/`dispatch`/`wiredTools`/
|
|
518
518
|
* `clientTools`/`broadcast`/`capabilities` slips through silently. The
|
|
519
|
-
*
|
|
519
|
+
* render-gate hard-rejects these (see
|
|
520
520
|
* `mcp-server-handlers/.../assert-contract-no-retired-fields.ts`); this
|
|
521
521
|
* lint surface keeps authoring tools symmetric — show the warning before
|
|
522
|
-
* the
|
|
522
|
+
* the render call so the author can fix it without a server round-trip.
|
|
523
523
|
*/
|
|
524
524
|
export function checkRetiredContractFields(contract) {
|
|
525
525
|
// Cast to a generic record so we can probe the keys the passthrough
|
|
@@ -534,7 +534,7 @@ export function checkRetiredContractFields(contract) {
|
|
|
534
534
|
warnings.push({
|
|
535
535
|
code: LINT_CONTRACT_RETIRED_FIELD,
|
|
536
536
|
path: retired,
|
|
537
|
-
message: `contract.${retired} is retired. Use ${replacement} instead — the field rides through .passthrough() but the
|
|
537
|
+
message: `contract.${retired} is retired. Use ${replacement} instead — the field rides through .passthrough() but the render gate hard-rejects it as a structural error.`,
|
|
538
538
|
fixHint: `Delete contract.${retired}; move its data to ${replacement}.`,
|
|
539
539
|
});
|
|
540
540
|
}
|
|
@@ -547,11 +547,11 @@ export function checkRetiredContractFields(contract) {
|
|
|
547
547
|
* checklist. Retired-field detection is NOT here — it is promoted to an
|
|
548
548
|
* ERROR phase (`phaseRetired` in lint-contract.ts); the detector
|
|
549
549
|
* `checkRetiredContractFields` stays exported for the author-time
|
|
550
|
-
* surface and the
|
|
550
|
+
* surface and the render-gate assert.
|
|
551
551
|
*
|
|
552
552
|
* Registry-side gadget lints (`lintGadgetCatalog`) are NOT run here:
|
|
553
553
|
* they need an `App.gadgets` descriptor array, not a contract, and
|
|
554
|
-
* fire at registration time rather than
|
|
554
|
+
* fire at registration time rather than render time.
|
|
555
555
|
* Call {@link lintGadgetCatalog} separately at the registration
|
|
556
556
|
* boundary.
|
|
557
557
|
*/
|
|
@@ -565,6 +565,6 @@ export function checkHygiene(contract) {
|
|
|
565
565
|
// Retired-field detection is promoted to an ERROR phase
|
|
566
566
|
// (`phaseRetired` in lint-contract.ts) — not a hygiene warning.
|
|
567
567
|
// `checkRetiredContractFields` stays exported for the author-time
|
|
568
|
-
// surface + the
|
|
568
|
+
// surface + the render-gate assert.
|
|
569
569
|
];
|
|
570
570
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validating narrower for the JSON-object shape: is `value` a
|
|
3
|
+
* non-null, non-array object — the shape every wire frame, request
|
|
4
|
+
* body, and envelope must satisfy before keyed access?
|
|
5
|
+
*
|
|
6
|
+
* One definition for the whole protocol family so every trust
|
|
7
|
+
* boundary narrows with the SAME predicate — no per-package
|
|
8
|
+
* duplicates, no per-site `as Record<string, unknown>` casts. Use it
|
|
9
|
+
* wherever untrusted input (HTTP bodies, wire frames, parsed JSON)
|
|
10
|
+
* needs to become a `Record<string, unknown>` before field reads:
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* const body: Record<string, unknown> = isRecord(req.body) ? req.body : {};
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
17
|
+
//# sourceMappingURL=is-record.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-record.d.ts","sourceRoot":"","sources":["../../src/validation/is-record.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validating narrower for the JSON-object shape: is `value` a
|
|
3
|
+
* non-null, non-array object — the shape every wire frame, request
|
|
4
|
+
* body, and envelope must satisfy before keyed access?
|
|
5
|
+
*
|
|
6
|
+
* One definition for the whole protocol family so every trust
|
|
7
|
+
* boundary narrows with the SAME predicate — no per-package
|
|
8
|
+
* duplicates, no per-site `as Record<string, unknown>` casts. Use it
|
|
9
|
+
* wherever untrusted input (HTTP bodies, wire frames, parsed JSON)
|
|
10
|
+
* needs to become a `Record<string, unknown>` before field reads:
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* const body: Record<string, unknown> = isRecord(req.body) ? req.body : {};
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export function isRecord(value) {
|
|
17
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
18
|
+
}
|
|
@@ -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
|
|
@@ -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
|
|
@@ -103,7 +103,7 @@ function zodIssueCode(zodCode) {
|
|
|
103
103
|
* (an LLM correctly re-nests `wiredTools` → `agentCapabilities.tools`),
|
|
104
104
|
* and `ggui_render`'s override path rejects it. Shares the one detector
|
|
105
105
|
* (`checkRetiredContractFields`) with the author-time surface + the
|
|
106
|
-
*
|
|
106
|
+
* render-gate assert, so the retired vocabulary can't drift across sites.
|
|
107
107
|
*/
|
|
108
108
|
function phaseRetired(contract) {
|
|
109
109
|
return checkRetiredContractFields(contract).map((w) => ({
|
|
@@ -123,7 +123,7 @@ function phaseRetired(contract) {
|
|
|
123
123
|
* under Ajv strict mode. Distinct from phase-1 shape: zod validates the
|
|
124
124
|
* WRAPPER shape, but the wrapped JSON Schema rides through
|
|
125
125
|
* `.passthrough()` unvalidated. Runs before references / schema-compat,
|
|
126
|
-
* which read these schemas. This is the check the
|
|
126
|
+
* which read these schemas. This is the check the render/handshake assert
|
|
127
127
|
* set had that `validateContract` was previously missing — folding it in
|
|
128
128
|
* here is what makes the strict gate complete (and therefore safe to use
|
|
129
129
|
* as the single boundary gate).
|
|
@@ -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.
|