@ggui-ai/protocol-conformance 0.1.0-rc.1
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/LICENSE +201 -0
- package/README.md +89 -0
- package/dist/cli.d.ts +15 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +193 -0
- package/dist/conformance-host.d.ts +155 -0
- package/dist/conformance-host.d.ts.map +1 -0
- package/dist/conformance-host.js +45 -0
- package/dist/fixtures/bootstrap-protocol/bootstrap-bundle-fetch-failed.json +26 -0
- package/dist/fixtures/bootstrap-protocol/bootstrap-meta-missing.json +32 -0
- package/dist/fixtures/bootstrap-protocol/bootstrap-success.json +17 -0
- package/dist/fixtures/bootstrap-protocol/index.d.ts +5 -0
- package/dist/fixtures/bootstrap-protocol/index.d.ts.map +1 -0
- package/dist/fixtures/bootstrap-protocol/index.js +24 -0
- package/dist/fixtures/canvas-mode-wire-shapes/canvas-bootstrap-mutual-exclusion.json +25 -0
- package/dist/fixtures/canvas-mode-wire-shapes/canvas-lifecycle-channel-emits-handshake-started.json +30 -0
- package/dist/fixtures/canvas-mode-wire-shapes/canvas-navigated-updates-active-stack-item.json +30 -0
- package/dist/fixtures/canvas-mode-wire-shapes/host-context-observed-persists.json +22 -0
- package/dist/fixtures/canvas-mode-wire-shapes/index.d.ts +5 -0
- package/dist/fixtures/canvas-mode-wire-shapes/index.d.ts.map +1 -0
- package/dist/fixtures/canvas-mode-wire-shapes/index.js +47 -0
- package/dist/fixtures/index.d.ts +78 -0
- package/dist/fixtures/index.d.ts.map +1 -0
- package/dist/fixtures/index.js +87 -0
- package/dist/fixtures/observability-events/index.d.ts +5 -0
- package/dist/fixtures/observability-events/index.d.ts.map +1 -0
- package/dist/fixtures/observability-events/index.js +22 -0
- package/dist/fixtures/observability-events/observability-contract-error-emitted.json +29 -0
- package/dist/fixtures/observability-events/observability-wired-tool-invoked.json +28 -0
- package/dist/fixtures/refresh-semantics/index.d.ts +5 -0
- package/dist/fixtures/refresh-semantics/index.d.ts.map +1 -0
- package/dist/fixtures/refresh-semantics/index.js +19 -0
- package/dist/fixtures/refresh-semantics/stream-refresh-success.json +40 -0
- package/dist/fixtures/reserved-channel-authority/index.d.ts +4 -0
- package/dist/fixtures/reserved-channel-authority/index.d.ts.map +1 -0
- package/dist/fixtures/reserved-channel-authority/index.js +21 -0
- package/dist/fixtures/reserved-channel-authority/props-update-roundtrip.json +34 -0
- package/dist/fixtures/reserved-channel-authority/stream-schema-violation.json +45 -0
- package/dist/fixtures/schema-version-handshake/index.d.ts +4 -0
- package/dist/fixtures/schema-version-handshake/index.d.ts.map +1 -0
- package/dist/fixtures/schema-version-handshake/index.js +20 -0
- package/dist/fixtures/schema-version-handshake/version-match.json +16 -0
- package/dist/fixtures/schema-version-handshake/version-mismatch.json +26 -0
- package/dist/fixtures/wired-action-dispatch/index.d.ts +5 -0
- package/dist/fixtures/wired-action-dispatch/index.d.ts.map +1 -0
- package/dist/fixtures/wired-action-dispatch/index.js +29 -0
- package/dist/fixtures/wired-action-dispatch/wired-action-success.json +36 -0
- package/dist/fixtures/wired-action-dispatch/wired-action-tool-not-found.json +31 -0
- package/dist/fixtures/wired-action-dispatch/wired-action-tool-threw.json +32 -0
- package/dist/fixtures/wired-action-dispatch/wired-action-tool-timeout.json +32 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/loader.d.ts +19 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +46 -0
- package/dist/match-behavior.d.ts +121 -0
- package/dist/match-behavior.d.ts.map +1 -0
- package/dist/match-behavior.js +385 -0
- package/dist/registration-conformance/cases/gate-export-not-registered.json +19 -0
- package/dist/registration-conformance/cases/gate-no-gadgets-accept.json +13 -0
- package/dist/registration-conformance/cases/gate-package-mismatch.json +19 -0
- package/dist/registration-conformance/cases/gate-priority-not-registered-outranks-mismatch.json +20 -0
- package/dist/registration-conformance/cases/gate-registered-resolves-accept.json +25 -0
- package/dist/registration-conformance/cases/gate-stdlib-hook-accept.json +27 -0
- package/dist/registration-conformance/cases/gate-typo-classifies-as-not-registered.json +27 -0
- package/dist/registration-conformance/index.d.ts +114 -0
- package/dist/registration-conformance/index.d.ts.map +1 -0
- package/dist/registration-conformance/index.js +63 -0
- package/dist/reporter.d.ts +32 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +151 -0
- package/dist/resolution-conformance/cases/resolve-bundle-host-computed.json +13 -0
- package/dist/resolution-conformance/cases/resolve-default-host.json +12 -0
- package/dist/resolution-conformance/cases/resolve-explicit-bundle-and-style-url.json +14 -0
- package/dist/resolution-conformance/cases/resolve-explicit-bundle-url.json +12 -0
- package/dist/resolution-conformance/cases/resolve-loopback-host-http-scheme.json +13 -0
- package/dist/resolution-conformance/cases/resolve-package-only-no-version.json +8 -0
- package/dist/resolution-conformance/cases/resolve-stdlib-no-urls.json +10 -0
- package/dist/resolution-conformance/index.d.ts +76 -0
- package/dist/resolution-conformance/index.d.ts.map +1 -0
- package/dist/resolution-conformance/index.js +81 -0
- package/dist/run-conformance.d.ts +58 -0
- package/dist/run-conformance.d.ts.map +1 -0
- package/dist/run-conformance.js +286 -0
- package/dist/schema-conformance/cases/wire-bad-export-name-reject.json +11 -0
- package/dist/schema-conformance/cases/wire-bad-package-name-reject.json +11 -0
- package/dist/schema-conformance/cases/wire-component-export-accept.json +10 -0
- package/dist/schema-conformance/cases/wire-empty-package-reject.json +11 -0
- package/dist/schema-conformance/cases/wire-minimal-accept.json +10 -0
- package/dist/schema-conformance/cases/wire-multi-package-accept.json +14 -0
- package/dist/schema-conformance/cases/wire-prose-accept.json +15 -0
- package/dist/schema-conformance/cases/wire-registry-metadata-reject.json +13 -0
- package/dist/schema-conformance/cases/wire-stale-libraries-reject.json +14 -0
- package/dist/schema-conformance/cases/wire-stdlib-accept.json +10 -0
- package/dist/schema-conformance/cases/wire-transport-field-reject.json +15 -0
- package/dist/schema-conformance/cases/wire-version-field-reject.json +13 -0
- package/dist/schema-conformance/index.d.ts +71 -0
- package/dist/schema-conformance/index.d.ts.map +1 -0
- package/dist/schema-conformance/index.js +103 -0
- package/dist/types.d.ts +434 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +62 -0
- package/dist/ws-transport.d.ts +42 -0
- package/dist/ws-transport.d.ts.map +1 -0
- package/dist/ws-transport.js +135 -0
- package/package.json +83 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema-conformance catalog — pure-schema accept / reject cases for
|
|
3
|
+
* the gadget WIRE shape (`DataContract.clientCapabilities`, SPEC
|
|
4
|
+
* §7.7.2).
|
|
5
|
+
*
|
|
6
|
+
* ## Why this is SEPARATE from the `./fixtures` behavioral catalog
|
|
7
|
+
*
|
|
8
|
+
* The `./fixtures` catalog asserts *behavioral* obligations — what a
|
|
9
|
+
* live implementation DOES when driven by an input envelope (a
|
|
10
|
+
* push-gate rejection, a bootstrap projection). Those need a host, a
|
|
11
|
+
* transport, and a runner.
|
|
12
|
+
*
|
|
13
|
+
* This catalog asserts a *structural* obligation: which
|
|
14
|
+
* `clientCapabilities` payloads a spec-conformant parser MUST accept
|
|
15
|
+
* and which it MUST reject — a property of the schema alone, with no
|
|
16
|
+
* session, no transport, no host. Folding it into the behavioral
|
|
17
|
+
* fixture shape (`TestCase`) would mean inventing a no-op
|
|
18
|
+
* `inputEnvelope` and a fake behavior kind for every case. Keeping it
|
|
19
|
+
* a distinct, smaller artifact is the honest modeling.
|
|
20
|
+
*
|
|
21
|
+
* ## Polyglot, decoupled
|
|
22
|
+
*
|
|
23
|
+
* Each case ships as raw JSON under `./cases/` so a non-TypeScript
|
|
24
|
+
* implementer (Python, Go, Rust) can read the catalog and grade their
|
|
25
|
+
* own `clientCapabilities` parser. {@link runSchemaConformance} takes
|
|
26
|
+
* the validator as a callback — the kit never imports a concrete
|
|
27
|
+
* schema here, so adopters drive their OWN parser. The reference
|
|
28
|
+
* binding (the kit's own meta-test) wires `@ggui-ai/protocol`'s
|
|
29
|
+
* `clientCapabilitiesSpecSchema`; see `./schema-conformance.test.ts`.
|
|
30
|
+
*
|
|
31
|
+
* The authored vocabulary is pinned here, deliberately decoupled from
|
|
32
|
+
* the live `@ggui-ai/protocol` source tree — the same drift discipline
|
|
33
|
+
* `../types.ts` applies to the behavioral fixture surface.
|
|
34
|
+
*/
|
|
35
|
+
import wireBadExportNameReject from './cases/wire-bad-export-name-reject.json' with { type: 'json' };
|
|
36
|
+
import wireBadPackageNameReject from './cases/wire-bad-package-name-reject.json' with { type: 'json' };
|
|
37
|
+
import wireComponentExportAccept from './cases/wire-component-export-accept.json' with { type: 'json' };
|
|
38
|
+
import wireEmptyPackageReject from './cases/wire-empty-package-reject.json' with { type: 'json' };
|
|
39
|
+
import wireMinimalAccept from './cases/wire-minimal-accept.json' with { type: 'json' };
|
|
40
|
+
import wireMultiPackageAccept from './cases/wire-multi-package-accept.json' with { type: 'json' };
|
|
41
|
+
import wireProseAccept from './cases/wire-prose-accept.json' with { type: 'json' };
|
|
42
|
+
import wireRegistryMetadataReject from './cases/wire-registry-metadata-reject.json' with { type: 'json' };
|
|
43
|
+
import wireStaleLibrariesReject from './cases/wire-stale-libraries-reject.json' with { type: 'json' };
|
|
44
|
+
import wireStdlibAccept from './cases/wire-stdlib-accept.json' with { type: 'json' };
|
|
45
|
+
import wireTransportFieldReject from './cases/wire-transport-field-reject.json' with { type: 'json' };
|
|
46
|
+
import wireVersionFieldReject from './cases/wire-version-field-reject.json' with { type: 'json' };
|
|
47
|
+
/**
|
|
48
|
+
* Every gadget-wire schema-conformance case the kit ships, in
|
|
49
|
+
* deterministic order — accepts first, then rejects, each group
|
|
50
|
+
* lexicographic by `name`.
|
|
51
|
+
*/
|
|
52
|
+
export const gadgetWireSchemaCases = [
|
|
53
|
+
wireComponentExportAccept,
|
|
54
|
+
wireMinimalAccept,
|
|
55
|
+
wireMultiPackageAccept,
|
|
56
|
+
wireProseAccept,
|
|
57
|
+
wireStdlibAccept,
|
|
58
|
+
wireBadExportNameReject,
|
|
59
|
+
wireBadPackageNameReject,
|
|
60
|
+
wireEmptyPackageReject,
|
|
61
|
+
wireRegistryMetadataReject,
|
|
62
|
+
wireStaleLibrariesReject,
|
|
63
|
+
wireTransportFieldReject,
|
|
64
|
+
wireVersionFieldReject,
|
|
65
|
+
];
|
|
66
|
+
/**
|
|
67
|
+
* Grade a `clientCapabilities` validator against the gadget-wire
|
|
68
|
+
* schema-conformance catalog.
|
|
69
|
+
*
|
|
70
|
+
* `validate` MUST return `true` iff its parser accepts the input as a
|
|
71
|
+
* well-formed `DataContract.clientCapabilities`, `false` otherwise.
|
|
72
|
+
* The kit deliberately does NOT import a concrete schema — adopters
|
|
73
|
+
* pass their own parser (a zod `safeParse`, a Go struct decode, a
|
|
74
|
+
* pydantic model) and the catalog grades it. A conformant validator
|
|
75
|
+
* produces an empty `failed` array.
|
|
76
|
+
*
|
|
77
|
+
* `validate` is invoked exactly once per case; it MUST be pure and
|
|
78
|
+
* MUST NOT throw (a throwing parser is itself non-conformant — wrap
|
|
79
|
+
* it). Cases are graded in {@link gadgetWireSchemaCases} order.
|
|
80
|
+
*/
|
|
81
|
+
export function runSchemaConformance(validate) {
|
|
82
|
+
const passed = [];
|
|
83
|
+
const failed = [];
|
|
84
|
+
for (const testCase of gadgetWireSchemaCases) {
|
|
85
|
+
const actual = validate(testCase.clientCapabilities)
|
|
86
|
+
? 'accept'
|
|
87
|
+
: 'reject';
|
|
88
|
+
if (actual === testCase.expect) {
|
|
89
|
+
passed.push(testCase.name);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
failed.push({
|
|
93
|
+
name: testCase.name,
|
|
94
|
+
expected: testCase.expect,
|
|
95
|
+
actual,
|
|
96
|
+
...(testCase.rejectReason !== undefined
|
|
97
|
+
? { rejectReason: testCase.rejectReason }
|
|
98
|
+
: {}),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return { passed, failed };
|
|
103
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@ggui-ai/protocol-conformance` fixture format — the authoring
|
|
3
|
+
* contract third-party implementers compile against.
|
|
4
|
+
*
|
|
5
|
+
* This module is the public, wire-stable shape of every fixture case
|
|
6
|
+
* under `./fixtures/**`. These declarations are the single source of
|
|
7
|
+
* truth for the fixture-authoring vocabulary; other consumers in the
|
|
8
|
+
* project re-export from this package rather than redefining it.
|
|
9
|
+
*
|
|
10
|
+
* ## Naming-load-bearing rule
|
|
11
|
+
*
|
|
12
|
+
* The shape of {@link TestCase}, {@link SetupStep},
|
|
13
|
+
* {@link TeardownStep}, and {@link ExpectedBehavior} IS the public
|
|
14
|
+
* API. Renaming a field breaks every third-party consumer of the
|
|
15
|
+
* conformance kit. Treat this file the way `@ggui-ai/protocol`'s
|
|
16
|
+
* type declarations get treated: additive changes only, extensibility
|
|
17
|
+
* via `(string & {})` tails.
|
|
18
|
+
*
|
|
19
|
+
* ## Extensibly-closed unions
|
|
20
|
+
*
|
|
21
|
+
* Every discriminator in this module carries a `(string & {})` tail —
|
|
22
|
+
* see SPEC §extensibility and `ContractErrorCode` in
|
|
23
|
+
* `@ggui-ai/protocol`. Third-party conformance-host implementations
|
|
24
|
+
* MAY introduce setup / teardown / expectation kinds the reference
|
|
25
|
+
* kit doesn't recognize; the runner SHOULD skip such cases with a
|
|
26
|
+
* warning rather than failing loudly, exactly the way
|
|
27
|
+
* `ContractErrorCode`'s extensibility works.
|
|
28
|
+
*
|
|
29
|
+
* Only these discriminators are extensibly closed:
|
|
30
|
+
* - `SetupStep['type']`
|
|
31
|
+
* - `TeardownStep['type']`
|
|
32
|
+
* - `ExpectedBehavior['kind']`
|
|
33
|
+
* - `ExpectedObservabilityEvent['kind']`
|
|
34
|
+
* - `TransportConfig['kind']`
|
|
35
|
+
*
|
|
36
|
+
* Everything else — tool names, envelope field names, contract error
|
|
37
|
+
* codes — is passed verbatim and the implementation under test owns
|
|
38
|
+
* the recognition set.
|
|
39
|
+
*
|
|
40
|
+
* ## Why JSON + a loader, not pure TS
|
|
41
|
+
*
|
|
42
|
+
* Third-party consumers of the conformance kit are not all
|
|
43
|
+
* TypeScript. The JSON format means a Python / Go / Rust implementer
|
|
44
|
+
* can parse the same fixture catalog without shipping a TS compiler.
|
|
45
|
+
* The loader exists so in-process TS consumers don't re-invent the
|
|
46
|
+
* parser.
|
|
47
|
+
*
|
|
48
|
+
* ## Why inline authored vocabulary (not `import type` from `@ggui-ai/protocol`)
|
|
49
|
+
*
|
|
50
|
+
* The conformance kit is the AUTHORED artifact — its vocabulary is
|
|
51
|
+
* pinned here, deliberately decoupled from the live source tree. A
|
|
52
|
+
* drift check between these authored unions and the live protocol /
|
|
53
|
+
* renderer types belongs in the kit's own meta-tests, NOT in this
|
|
54
|
+
* file's import graph. If `@ggui-ai/protocol` adds a new
|
|
55
|
+
* `ContractErrorCode` canonical member tomorrow, conformance kit
|
|
56
|
+
* consumers MUST NOT be forced to recompile — their fixtures
|
|
57
|
+
* continue to reference the value they authored, and the runner's
|
|
58
|
+
* extensible `(string & {})` tail handles recognition. This mirrors
|
|
59
|
+
* the protocol's own evolution discipline: authored shapes stay
|
|
60
|
+
* additive.
|
|
61
|
+
*/
|
|
62
|
+
/**
|
|
63
|
+
* Transport binding the kit uses to reach the implementation under
|
|
64
|
+
* test. v1.0 ships WS-only — WebSocket is the canonical ggui
|
|
65
|
+
* transport.
|
|
66
|
+
*
|
|
67
|
+
* The union is extensibly-closed (`(string & {})` tail) so post-v1.1
|
|
68
|
+
* transports (stdio MCP, HTTP long-poll) can land without breaking
|
|
69
|
+
* the kit's public API. The known arm is the full config object;
|
|
70
|
+
* unknown arms are accepted as opaque records so third-party runners
|
|
71
|
+
* can extend without a package bump.
|
|
72
|
+
*
|
|
73
|
+
* Pattern mirrored from `ContractErrorCode` in
|
|
74
|
+
* `@ggui-ai/protocol/types/data-contract`.
|
|
75
|
+
*/
|
|
76
|
+
export type TransportConfig = WebSocketTransportConfig | UnknownTransportConfig;
|
|
77
|
+
export interface WebSocketTransportConfig {
|
|
78
|
+
readonly kind: 'ws';
|
|
79
|
+
/** Fully-qualified WebSocket URL, e.g. `ws://localhost:3000/ws`. */
|
|
80
|
+
readonly url: string;
|
|
81
|
+
/** Auth carried on the upgrade request. See {@link AuthConfig}. */
|
|
82
|
+
readonly auth: AuthConfig;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Future-compat catch. Runners that receive a transport `kind` they
|
|
86
|
+
* don't recognize MUST fail loudly — an unrecognized transport is a
|
|
87
|
+
* configuration error, not a runtime extension point.
|
|
88
|
+
*/
|
|
89
|
+
export interface UnknownTransportConfig {
|
|
90
|
+
readonly kind: string & {};
|
|
91
|
+
readonly [field: string]: unknown;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Authentication carried to the implementation under test. v1.0 names
|
|
95
|
+
* two concrete shapes. Extensibility follows the transport pattern —
|
|
96
|
+
* new auth shapes land as additional arms, not as a free-form record.
|
|
97
|
+
*/
|
|
98
|
+
export type AuthConfig = {
|
|
99
|
+
readonly kind: 'bearer';
|
|
100
|
+
readonly token: string;
|
|
101
|
+
} | {
|
|
102
|
+
readonly kind: 'session-cookie';
|
|
103
|
+
readonly cookie: string;
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Directive a conformance host interprets BEFORE driving a fixture's
|
|
107
|
+
* `inputEnvelope`. The runner dispatches each step against the host's
|
|
108
|
+
* injected `ConformanceHost` interface (see `./conformance-host`) —
|
|
109
|
+
* this module authors the declarative intent; the host owns the
|
|
110
|
+
* implementation.
|
|
111
|
+
*
|
|
112
|
+
* Discriminator is extensibly closed: unknown `type` values skip the
|
|
113
|
+
* fixture with a warning rather than erroring. Third-party hosts MAY
|
|
114
|
+
* extend the setup vocabulary without a kit version bump.
|
|
115
|
+
*/
|
|
116
|
+
export type SetupStep = CreateSessionStep | RegisterToolStep | EmitEnvelopeStep | SeedChannelStep | UnknownSetupStep;
|
|
117
|
+
export interface CreateSessionStep {
|
|
118
|
+
readonly type: 'create-session';
|
|
119
|
+
/** Opaque session id the host allocates. Downstream steps + the
|
|
120
|
+
* fixture's `inputEnvelope` reference it by value. */
|
|
121
|
+
readonly sessionId: string;
|
|
122
|
+
/** Optional app (tenant) id the session scopes to. Defaults to the
|
|
123
|
+
* host's implementation-defined "default app". */
|
|
124
|
+
readonly appId?: string;
|
|
125
|
+
}
|
|
126
|
+
export interface RegisterToolStep {
|
|
127
|
+
readonly type: 'register-tool';
|
|
128
|
+
readonly toolName: string;
|
|
129
|
+
/** Handler identifier the host maps to a real implementation. The
|
|
130
|
+
* kit is authoring-only — it doesn't ship handler bodies. Known
|
|
131
|
+
* values the reference `@ggui-ai/mcp-server`-backed host supports:
|
|
132
|
+
*
|
|
133
|
+
* - `'echo'` — returns `{received: args}`.
|
|
134
|
+
* - `'throw'` — rejects with `Error('tool_threw_for_fixture')`.
|
|
135
|
+
* - `'timeout'`— never resolves (host enforces its own timeout).
|
|
136
|
+
* - `'malformed-stream'` — returns `{wrong:'shape'}`.
|
|
137
|
+
*
|
|
138
|
+
* Third-party hosts MAY recognize additional handlers; the kit
|
|
139
|
+
* records the string verbatim. */
|
|
140
|
+
readonly handler: string;
|
|
141
|
+
}
|
|
142
|
+
export interface EmitEnvelopeStep {
|
|
143
|
+
readonly type: 'emit-envelope';
|
|
144
|
+
/** Reserved-channel or declared-channel name. */
|
|
145
|
+
readonly channel: string;
|
|
146
|
+
/** Raw envelope body. Host is responsible for wrapping in the wire
|
|
147
|
+
* format (sequence stamp, timestamp, etc.). */
|
|
148
|
+
readonly payload: unknown;
|
|
149
|
+
}
|
|
150
|
+
export interface SeedChannelStep {
|
|
151
|
+
readonly type: 'seed-channel';
|
|
152
|
+
readonly sessionId: string;
|
|
153
|
+
readonly channel: string;
|
|
154
|
+
readonly value: unknown;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Future-compat catch. Hosts that do not recognize the `type` SHOULD
|
|
158
|
+
* skip the case with a warning.
|
|
159
|
+
*/
|
|
160
|
+
export interface UnknownSetupStep {
|
|
161
|
+
readonly type: string & {};
|
|
162
|
+
readonly [field: string]: unknown;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Teardown directive — mirrors {@link SetupStep}'s vocabulary, scoped
|
|
166
|
+
* to cleanup.
|
|
167
|
+
*/
|
|
168
|
+
export type TeardownStep = CloseSessionStep | UnregisterToolStep | UnknownTeardownStep;
|
|
169
|
+
export interface CloseSessionStep {
|
|
170
|
+
readonly type: 'close-session';
|
|
171
|
+
readonly sessionId: string;
|
|
172
|
+
}
|
|
173
|
+
export interface UnregisterToolStep {
|
|
174
|
+
readonly type: 'unregister-tool';
|
|
175
|
+
readonly toolName: string;
|
|
176
|
+
}
|
|
177
|
+
export interface UnknownTeardownStep {
|
|
178
|
+
readonly type: string & {};
|
|
179
|
+
readonly [field: string]: unknown;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* What the test asserts after the input envelope drives the host.
|
|
183
|
+
*
|
|
184
|
+
* Discriminator is extensibly closed via `(string & {})`. Each arm
|
|
185
|
+
* carries only the fields the assertion semantically requires — no
|
|
186
|
+
* optional-everything-bags. Cross-cuts (e.g. every failure-path case
|
|
187
|
+
* also expects a matching observability event) are authored as
|
|
188
|
+
* {@link TestCase.expectedBehavior} of one kind PLUS
|
|
189
|
+
* {@link TestCase.expectedObservability} alongside, not as nested
|
|
190
|
+
* unions.
|
|
191
|
+
*/
|
|
192
|
+
export type ExpectedBehavior = ContractErrorBehavior | StreamUpdateBehavior | ObservabilityBehavior | BootstrapFailureBehavior | BootstrapSuccessBehavior | VersionMismatchBehavior | PropsUpdateBehavior | NoOpBehavior | UnknownBehavior;
|
|
193
|
+
/**
|
|
194
|
+
* Expect a `_ggui:contract-error` envelope with the given code + tool
|
|
195
|
+
* + optional actionName + optional sourceAction.type. Matches the
|
|
196
|
+
* renderer's {@link ProtocolError} kind `'contract'` variant AND the
|
|
197
|
+
* server-wire `ContractErrorPayload` shape.
|
|
198
|
+
*/
|
|
199
|
+
export interface ContractErrorBehavior {
|
|
200
|
+
readonly kind: 'contract-error';
|
|
201
|
+
readonly code: ContractErrorCode;
|
|
202
|
+
readonly toolName: string;
|
|
203
|
+
readonly actionName?: string;
|
|
204
|
+
readonly sourceAction?: 'wired-action' | 'refresh-stream' | (string & {});
|
|
205
|
+
/**
|
|
206
|
+
* Optional observability co-assertion. Most contract-error paths
|
|
207
|
+
* also emit a `contract-error-emitted` observability event with the
|
|
208
|
+
* same `code` + `toolName`. Authoring this here keeps the
|
|
209
|
+
* cross-cut in one place.
|
|
210
|
+
*/
|
|
211
|
+
readonly observability?: ExpectedObservabilityEvent;
|
|
212
|
+
}
|
|
213
|
+
/** Expect a stream-update on the named channel matching the given value
|
|
214
|
+
* shape (deep-equal, via the host's matcher). */
|
|
215
|
+
export interface StreamUpdateBehavior {
|
|
216
|
+
readonly kind: 'stream-update';
|
|
217
|
+
readonly channel: string;
|
|
218
|
+
readonly value: unknown;
|
|
219
|
+
}
|
|
220
|
+
/** Expect a standalone observability event (no wired-action / refresh
|
|
221
|
+
* side-effect paired). Mostly used by happy-path rows + the
|
|
222
|
+
* `wired-tool-invoked` event. */
|
|
223
|
+
export interface ObservabilityBehavior {
|
|
224
|
+
readonly kind: 'observability-event';
|
|
225
|
+
readonly event: ExpectedObservabilityEvent;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Expect a bootstrap-failure postMessage envelope + the renderer's
|
|
229
|
+
* {@link ProtocolError} of kind `'bootstrap'` with the matching
|
|
230
|
+
* reason. Post-wire paths (`BUNDLE_FETCH_FAILED`,
|
|
231
|
+
* `BOOTSTRAP_META_MISSING`) are pre-WS — they surface via
|
|
232
|
+
* `postMessage({type:'ggui:bootstrap-failed', …})` only, NOT on
|
|
233
|
+
* the live channel.
|
|
234
|
+
*/
|
|
235
|
+
export interface BootstrapFailureBehavior {
|
|
236
|
+
readonly kind: 'bootstrap-failure';
|
|
237
|
+
readonly reason: BootstrapFailureReason;
|
|
238
|
+
/** Optional substring the renderer's `message` field should contain.
|
|
239
|
+
* Keeps assertions resilient to message copy edits. */
|
|
240
|
+
readonly messageContains?: string;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Expect the renderer to reach the "ready to accept actions" state —
|
|
244
|
+
* no bootstrap failure, no version rejection, the first stack item
|
|
245
|
+
* rendered with `data-ggui-code-ready="true"` (or the host's
|
|
246
|
+
* equivalent signal).
|
|
247
|
+
*/
|
|
248
|
+
export interface BootstrapSuccessBehavior {
|
|
249
|
+
readonly kind: 'bootstrap-success';
|
|
250
|
+
/** Optional: observability events the host MUST emit in order. */
|
|
251
|
+
readonly observabilitySequence?: readonly ExpectedObservabilityEvent[];
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Expect a version-handshake rejection. Maps to the
|
|
255
|
+
* `{type:'ggui:upgrade-required', server, client}` postMessage
|
|
256
|
+
* envelope + the renderer's {@link ProtocolError} kind `'version'`.
|
|
257
|
+
*/
|
|
258
|
+
export interface VersionMismatchBehavior {
|
|
259
|
+
readonly kind: 'version-mismatch';
|
|
260
|
+
readonly serverVersion: string;
|
|
261
|
+
readonly clientAccepts: readonly string[];
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Expect a `props_update` round-trip — hosts deliver new props via
|
|
265
|
+
* channel 0, the iframe DOM reflects the update within `timeoutMs`.
|
|
266
|
+
*/
|
|
267
|
+
export interface PropsUpdateBehavior {
|
|
268
|
+
readonly kind: 'props-update';
|
|
269
|
+
readonly channel: string;
|
|
270
|
+
/** Props values the host MUST deliver. */
|
|
271
|
+
readonly props: Record<string, unknown>;
|
|
272
|
+
/** DOM-level attribute / text evidence the update landed. */
|
|
273
|
+
readonly evidence: {
|
|
274
|
+
readonly selector: string;
|
|
275
|
+
readonly attribute?: string;
|
|
276
|
+
readonly expected: string;
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* No observable side-effect expected. Used for inputs the protocol
|
|
281
|
+
* intentionally drops (malformed envelopes, unrecognized JSON-RPC
|
|
282
|
+
* methods). The host SHOULD warn internally; the wire stays silent.
|
|
283
|
+
*/
|
|
284
|
+
export interface NoOpBehavior {
|
|
285
|
+
readonly kind: 'no-op';
|
|
286
|
+
/** Human-readable justification — why silence is the correct
|
|
287
|
+
* outcome. Surfaces in the reporter so operators can audit it. */
|
|
288
|
+
readonly reason: string;
|
|
289
|
+
}
|
|
290
|
+
/** Future-compat catch. Runner skips with a warning. */
|
|
291
|
+
export interface UnknownBehavior {
|
|
292
|
+
readonly kind: string & {};
|
|
293
|
+
readonly [field: string]: unknown;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Narrowed observability-event shape for fixture assertions. Parallel
|
|
297
|
+
* to `@ggui-ai/iframe-runtime`'s `ObservabilityEvent` but with every field
|
|
298
|
+
* optional-by-default so fixtures can assert "at least these values"
|
|
299
|
+
* without over-specifying (e.g. `latencyMs` is nondeterministic).
|
|
300
|
+
*/
|
|
301
|
+
export interface ExpectedObservabilityEvent {
|
|
302
|
+
readonly kind: 'wired-tool-invoked' | 'contract-error-emitted' | 'schema-version-mismatch' | 'subscribe-failed' | (string & {});
|
|
303
|
+
readonly toolName?: string;
|
|
304
|
+
readonly actionName?: string;
|
|
305
|
+
readonly code?: string;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* One conformance-kit fixture. Authored as JSON under `./fixtures/**`,
|
|
309
|
+
* consumed via the kit's loader, driven by either this package's
|
|
310
|
+
* runner or third-party consumers of the JSON catalog.
|
|
311
|
+
*/
|
|
312
|
+
export interface TestCase {
|
|
313
|
+
/**
|
|
314
|
+
* Unique fixture name. MUST match the JSON filename without `.json`.
|
|
315
|
+
* Reporter output uses this as the primary identifier.
|
|
316
|
+
*/
|
|
317
|
+
readonly name: string;
|
|
318
|
+
/** Human-readable description of what this fixture proves. */
|
|
319
|
+
readonly description: string;
|
|
320
|
+
/**
|
|
321
|
+
* If non-null, the runner SKIPS this fixture and prints the reason.
|
|
322
|
+
* Used for fixtures authored against a `ConformanceHost` directive
|
|
323
|
+
* the implementation under test hasn't wired yet.
|
|
324
|
+
*/
|
|
325
|
+
readonly skipReason: string | null;
|
|
326
|
+
/**
|
|
327
|
+
* Setup directives the host executes BEFORE the input envelope. May
|
|
328
|
+
* be empty. See {@link SetupStep}.
|
|
329
|
+
*/
|
|
330
|
+
readonly setup: readonly SetupStep[];
|
|
331
|
+
/**
|
|
332
|
+
* The envelope the runner feeds to the system under test. Opaque
|
|
333
|
+
* shape — the runner passes it verbatim to the host's transport.
|
|
334
|
+
*
|
|
335
|
+
* Typically an object like
|
|
336
|
+
* `{type: 'action', channel: 0, sessionId: 'test-s1', action: {…}}`
|
|
337
|
+
* (channel 0 = wired-action dispatch) or
|
|
338
|
+
* `{type: 'render', sessionId: 'test-s1', resource: {…}}` for
|
|
339
|
+
* bootstrap-path fixtures.
|
|
340
|
+
*
|
|
341
|
+
* `unknown` rather than a typed union because the kit may drive
|
|
342
|
+
* fixtures over multiple transport kinds post-v1.1 (stdio, HTTP
|
|
343
|
+
* long-poll) and each transport's envelope shape is its own.
|
|
344
|
+
*/
|
|
345
|
+
readonly inputEnvelope: unknown;
|
|
346
|
+
/** What the runner asserts after the envelope is dispatched. */
|
|
347
|
+
readonly expectedBehavior: ExpectedBehavior;
|
|
348
|
+
/**
|
|
349
|
+
* Optional observability assertion, independent of
|
|
350
|
+
* {@link expectedBehavior}. When `expectedBehavior.kind ===
|
|
351
|
+
* 'contract-error'` and `expectedBehavior.observability` is set,
|
|
352
|
+
* this field SHOULD be omitted — the nested one is canonical.
|
|
353
|
+
*/
|
|
354
|
+
readonly expectedObservability?: readonly ExpectedObservabilityEvent[];
|
|
355
|
+
/** Cleanup directives the host executes AFTER the assertion. */
|
|
356
|
+
readonly teardown: readonly TeardownStep[];
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Canonical contract-error codes. Mirrors `@ggui-ai/protocol`'s
|
|
360
|
+
* `ContractErrorCode` at the time this kit version was authored. The
|
|
361
|
+
* `(string & {})` tail lets fixtures reference codes introduced by
|
|
362
|
+
* later protocol revisions without a kit bump — the runner's
|
|
363
|
+
* recognition set is its own concern.
|
|
364
|
+
*
|
|
365
|
+
* Drift discipline: the kit ships a meta-test that walks
|
|
366
|
+
* `@ggui-ai/protocol`'s `ContractErrorCode` union against this
|
|
367
|
+
* declaration and warns when a new canonical member appears. The
|
|
368
|
+
* runner's behaviour on unknown codes (skip with warning) is
|
|
369
|
+
* additive-safe: adding a code here is a kit minor; removing one is
|
|
370
|
+
* a major.
|
|
371
|
+
*/
|
|
372
|
+
export type ContractErrorCode = 'TOOL_NOT_FOUND' | 'TOOL_THREW' | 'TOOL_TIMEOUT' | 'SCHEMA_VIOLATION' | 'SCHEMA_MISMATCH_ERROR' | 'SESSION_NOT_FOUND' | 'AUTH_REJECTED' | (string & {});
|
|
373
|
+
/**
|
|
374
|
+
* Boot-path failure reasons. Mirrors `@ggui-ai/iframe-runtime`'s
|
|
375
|
+
* `BootstrapFailureReason` — combines parse-time, post-parse
|
|
376
|
+
* orchestration, and pre-WS transport-observable failures. Authored
|
|
377
|
+
* copy for the same drift-decoupling reason as
|
|
378
|
+
* {@link ContractErrorCode}.
|
|
379
|
+
*/
|
|
380
|
+
export type BootstrapFailureReason = 'MISSING_TOOL_OUTPUT' | 'MISSING_META_GGUI_BOOTSTRAP' | 'BOOTSTRAP_META_MISSING' | 'MALFORMED_BOOTSTRAP' | 'EXPIRED_BOOTSTRAP' | 'UI_INITIALIZE_FAILED' | 'WS_HANDSHAKE_FAILED' | 'UPGRADE_REQUIRED' | 'BUNDLE_FETCH_FAILED' | 'CSP_VIOLATION' | 'SESSION_NOT_FOUND' | 'AUTH_REJECTED' | (string & {});
|
|
381
|
+
/**
|
|
382
|
+
* Narrow ProtocolError shape mirroring `@ggui-ai/iframe-runtime`'s public
|
|
383
|
+
* union at the time this kit version was authored. Fixture authors
|
|
384
|
+
* do NOT typically reference this type — it's exported so conformance
|
|
385
|
+
* runners can assert on the typed shape the host under test emits.
|
|
386
|
+
* Every member mirrors the renderer's canonical arm; the kit freezes
|
|
387
|
+
* the shape at this kit version and evolves additively per the
|
|
388
|
+
* drift-decoupling posture above.
|
|
389
|
+
*/
|
|
390
|
+
export type ProtocolError = {
|
|
391
|
+
readonly kind: 'transport';
|
|
392
|
+
readonly code: 'DISCONNECTED' | 'TIMEOUT';
|
|
393
|
+
readonly retryable: boolean;
|
|
394
|
+
readonly message?: string;
|
|
395
|
+
} | {
|
|
396
|
+
readonly kind: 'auth';
|
|
397
|
+
readonly code: 'SESSION_NOT_FOUND' | 'TOKEN_EXPIRED' | 'AUTH_REJECTED';
|
|
398
|
+
readonly message?: string;
|
|
399
|
+
} | {
|
|
400
|
+
readonly kind: 'protocol';
|
|
401
|
+
readonly code: 'SESSION_MISMATCH' | 'APP_MISMATCH' | 'MALFORMED_ENVELOPE' | (string & {});
|
|
402
|
+
readonly message?: string;
|
|
403
|
+
readonly details?: unknown;
|
|
404
|
+
} | {
|
|
405
|
+
readonly kind: 'contract';
|
|
406
|
+
readonly payload: {
|
|
407
|
+
readonly toolName: string;
|
|
408
|
+
readonly actionName?: string;
|
|
409
|
+
readonly sourceAction?: {
|
|
410
|
+
readonly type: 'wired-action' | 'refresh-stream' | (string & {});
|
|
411
|
+
readonly dispatchedAt: string;
|
|
412
|
+
};
|
|
413
|
+
readonly error: {
|
|
414
|
+
readonly code: ContractErrorCode;
|
|
415
|
+
readonly message: string;
|
|
416
|
+
readonly causedBy?: string;
|
|
417
|
+
};
|
|
418
|
+
readonly timestamp: string;
|
|
419
|
+
readonly schemaVersion?: string;
|
|
420
|
+
};
|
|
421
|
+
} | {
|
|
422
|
+
readonly kind: 'bootstrap';
|
|
423
|
+
readonly reason: BootstrapFailureReason;
|
|
424
|
+
readonly message: string;
|
|
425
|
+
} | {
|
|
426
|
+
readonly kind: 'version';
|
|
427
|
+
readonly serverVersion?: string;
|
|
428
|
+
readonly clientSupports: readonly string[];
|
|
429
|
+
readonly message?: string;
|
|
430
|
+
} | {
|
|
431
|
+
readonly kind: 'unknown';
|
|
432
|
+
readonly raw: unknown;
|
|
433
|
+
};
|
|
434
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@ggui-ai/protocol-conformance` fixture format — the authoring
|
|
3
|
+
* contract third-party implementers compile against.
|
|
4
|
+
*
|
|
5
|
+
* This module is the public, wire-stable shape of every fixture case
|
|
6
|
+
* under `./fixtures/**`. These declarations are the single source of
|
|
7
|
+
* truth for the fixture-authoring vocabulary; other consumers in the
|
|
8
|
+
* project re-export from this package rather than redefining it.
|
|
9
|
+
*
|
|
10
|
+
* ## Naming-load-bearing rule
|
|
11
|
+
*
|
|
12
|
+
* The shape of {@link TestCase}, {@link SetupStep},
|
|
13
|
+
* {@link TeardownStep}, and {@link ExpectedBehavior} IS the public
|
|
14
|
+
* API. Renaming a field breaks every third-party consumer of the
|
|
15
|
+
* conformance kit. Treat this file the way `@ggui-ai/protocol`'s
|
|
16
|
+
* type declarations get treated: additive changes only, extensibility
|
|
17
|
+
* via `(string & {})` tails.
|
|
18
|
+
*
|
|
19
|
+
* ## Extensibly-closed unions
|
|
20
|
+
*
|
|
21
|
+
* Every discriminator in this module carries a `(string & {})` tail —
|
|
22
|
+
* see SPEC §extensibility and `ContractErrorCode` in
|
|
23
|
+
* `@ggui-ai/protocol`. Third-party conformance-host implementations
|
|
24
|
+
* MAY introduce setup / teardown / expectation kinds the reference
|
|
25
|
+
* kit doesn't recognize; the runner SHOULD skip such cases with a
|
|
26
|
+
* warning rather than failing loudly, exactly the way
|
|
27
|
+
* `ContractErrorCode`'s extensibility works.
|
|
28
|
+
*
|
|
29
|
+
* Only these discriminators are extensibly closed:
|
|
30
|
+
* - `SetupStep['type']`
|
|
31
|
+
* - `TeardownStep['type']`
|
|
32
|
+
* - `ExpectedBehavior['kind']`
|
|
33
|
+
* - `ExpectedObservabilityEvent['kind']`
|
|
34
|
+
* - `TransportConfig['kind']`
|
|
35
|
+
*
|
|
36
|
+
* Everything else — tool names, envelope field names, contract error
|
|
37
|
+
* codes — is passed verbatim and the implementation under test owns
|
|
38
|
+
* the recognition set.
|
|
39
|
+
*
|
|
40
|
+
* ## Why JSON + a loader, not pure TS
|
|
41
|
+
*
|
|
42
|
+
* Third-party consumers of the conformance kit are not all
|
|
43
|
+
* TypeScript. The JSON format means a Python / Go / Rust implementer
|
|
44
|
+
* can parse the same fixture catalog without shipping a TS compiler.
|
|
45
|
+
* The loader exists so in-process TS consumers don't re-invent the
|
|
46
|
+
* parser.
|
|
47
|
+
*
|
|
48
|
+
* ## Why inline authored vocabulary (not `import type` from `@ggui-ai/protocol`)
|
|
49
|
+
*
|
|
50
|
+
* The conformance kit is the AUTHORED artifact — its vocabulary is
|
|
51
|
+
* pinned here, deliberately decoupled from the live source tree. A
|
|
52
|
+
* drift check between these authored unions and the live protocol /
|
|
53
|
+
* renderer types belongs in the kit's own meta-tests, NOT in this
|
|
54
|
+
* file's import graph. If `@ggui-ai/protocol` adds a new
|
|
55
|
+
* `ContractErrorCode` canonical member tomorrow, conformance kit
|
|
56
|
+
* consumers MUST NOT be forced to recompile — their fixtures
|
|
57
|
+
* continue to reference the value they authored, and the runner's
|
|
58
|
+
* extensible `(string & {})` tail handles recognition. This mirrors
|
|
59
|
+
* the protocol's own evolution discipline: authored shapes stay
|
|
60
|
+
* additive.
|
|
61
|
+
*/
|
|
62
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { WebSocketTransportConfig } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* One observed frame. Preserves the raw bytes + the parsed shape so
|
|
4
|
+
* matchers can assert on either. Parse errors surface as `kind:
|
|
5
|
+
* 'unparseable'` — the kit never swallows them.
|
|
6
|
+
*/
|
|
7
|
+
export type ObservedFrame = {
|
|
8
|
+
readonly kind: 'frame';
|
|
9
|
+
readonly raw: string;
|
|
10
|
+
readonly parsed: Record<string, unknown>;
|
|
11
|
+
} | {
|
|
12
|
+
readonly kind: 'unparseable';
|
|
13
|
+
readonly raw: string;
|
|
14
|
+
readonly error: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Opaque handle returned by {@link openWsTransport}. Closed explicitly
|
|
18
|
+
* via {@link WsTransport.close} — the runner closes after each
|
|
19
|
+
* fixture so sessions don't leak between cases.
|
|
20
|
+
*/
|
|
21
|
+
export interface WsTransport {
|
|
22
|
+
/** Send one frame over the wire. Serializes `frame` as JSON. */
|
|
23
|
+
send(frame: unknown): void;
|
|
24
|
+
/**
|
|
25
|
+
* Collect every frame that arrives within `timeoutMs`. Resolves
|
|
26
|
+
* with the buffered frames when the timeout elapses, or earlier if
|
|
27
|
+
* `predicate` is provided and matches a frame.
|
|
28
|
+
*/
|
|
29
|
+
observe(options: {
|
|
30
|
+
readonly timeoutMs: number;
|
|
31
|
+
readonly predicate?: (frame: ObservedFrame) => boolean;
|
|
32
|
+
}): Promise<readonly ObservedFrame[]>;
|
|
33
|
+
/** Close the socket. Idempotent. */
|
|
34
|
+
close(): Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Open a WS transport against `config.url`, wait for the socket to
|
|
38
|
+
* reach `OPEN` state, and return the transport handle. Throws if the
|
|
39
|
+
* socket errors or closes before reaching OPEN.
|
|
40
|
+
*/
|
|
41
|
+
export declare function openWsTransport(config: WebSocketTransportConfig): Promise<WsTransport>;
|
|
42
|
+
//# sourceMappingURL=ws-transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ws-transport.d.ts","sourceRoot":"","sources":["../src/ws-transport.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAc,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAEvE;;;;GAIG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAC1F;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnF;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,gEAAgE;IAChE,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3B;;;;OAIG;IACH,OAAO,CAAC,OAAO,EAAE;QACf,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC;KACxD,GAAG,OAAO,CAAC,SAAS,aAAa,EAAE,CAAC,CAAC;IACtC,oCAAoC;IACpC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,wBAAwB,GAC/B,OAAO,CAAC,WAAW,CAAC,CA6FtB"}
|