@glubean/sdk 0.2.1 → 0.2.3
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/dist/bootstrap-registry.d.ts +38 -0
- package/dist/bootstrap-registry.d.ts.map +1 -0
- package/dist/bootstrap-registry.js +54 -0
- package/dist/bootstrap-registry.js.map +1 -0
- package/dist/configure/http.d.ts +25 -0
- package/dist/configure/http.d.ts.map +1 -0
- package/dist/configure/http.js +88 -0
- package/dist/configure/http.js.map +1 -0
- package/dist/configure/index.d.ts +78 -0
- package/dist/configure/index.d.ts.map +1 -0
- package/dist/configure/index.js +78 -0
- package/dist/configure/index.js.map +1 -0
- package/dist/configure/plugin.d.ts +23 -0
- package/dist/configure/plugin.d.ts.map +1 -0
- package/dist/configure/plugin.js +81 -0
- package/dist/configure/plugin.js.map +1 -0
- package/dist/configure/runtime.d.ts +24 -0
- package/dist/configure/runtime.d.ts.map +1 -0
- package/dist/configure/runtime.js +45 -0
- package/dist/configure/runtime.js.map +1 -0
- package/dist/configure/template.d.ts +22 -0
- package/dist/configure/template.d.ts.map +1 -0
- package/dist/configure/template.js +34 -0
- package/dist/configure/template.js.map +1 -0
- package/dist/configure/vars.d.ts +20 -0
- package/dist/configure/vars.d.ts.map +1 -0
- package/dist/configure/vars.js +48 -0
- package/dist/configure/vars.js.map +1 -0
- package/dist/configure.d.ts +2 -133
- package/dist/configure.d.ts.map +1 -1
- package/dist/configure.js +2 -436
- package/dist/configure.js.map +1 -1
- package/dist/contract-artifacts.d.ts +268 -0
- package/dist/contract-artifacts.d.ts.map +1 -0
- package/dist/contract-artifacts.js +402 -0
- package/dist/contract-artifacts.js.map +1 -0
- package/dist/contract-core.d.ts +43 -1
- package/dist/contract-core.d.ts.map +1 -1
- package/dist/contract-core.js +376 -5
- package/dist/contract-core.js.map +1 -1
- package/dist/contract-http/adapter.d.ts +1 -7
- package/dist/contract-http/adapter.d.ts.map +1 -1
- package/dist/contract-http/adapter.js +221 -199
- package/dist/contract-http/adapter.js.map +1 -1
- package/dist/contract-http/factory.d.ts.map +1 -1
- package/dist/contract-http/factory.js +13 -14
- package/dist/contract-http/factory.js.map +1 -1
- package/dist/contract-http/index.d.ts +1 -0
- package/dist/contract-http/index.d.ts.map +1 -1
- package/dist/contract-http/index.js +1 -0
- package/dist/contract-http/index.js.map +1 -1
- package/dist/contract-http/openapi.d.ts +56 -7
- package/dist/contract-http/openapi.d.ts.map +1 -1
- package/dist/contract-http/openapi.js +371 -21
- package/dist/contract-http/openapi.js.map +1 -1
- package/dist/contract-http/types.d.ts +72 -24
- package/dist/contract-http/types.d.ts.map +1 -1
- package/dist/contract-http/types.js +45 -1
- package/dist/contract-http/types.js.map +1 -1
- package/dist/contract-types.d.ts +270 -30
- package/dist/contract-types.d.ts.map +1 -1
- package/dist/expect.d.ts +13 -0
- package/dist/expect.d.ts.map +1 -1
- package/dist/expect.js +18 -0
- package/dist/expect.js.map +1 -1
- package/dist/index.d.ts +57 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -8
- package/dist/index.js.map +1 -1
- package/dist/install-plugin.d.ts +94 -0
- package/dist/install-plugin.d.ts.map +1 -0
- package/dist/install-plugin.js +222 -0
- package/dist/install-plugin.js.map +1 -0
- package/dist/internal.d.ts +2 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +8 -0
- package/dist/internal.js.map +1 -1
- package/dist/plugin.d.ts +45 -34
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +47 -34
- package/dist/plugin.js.map +1 -1
- package/dist/runner-input-channel.d.ts +95 -0
- package/dist/runner-input-channel.d.ts.map +1 -0
- package/dist/runner-input-channel.js +110 -0
- package/dist/runner-input-channel.js.map +1 -0
- package/dist/{test-builder.d.ts → test/builder.d.ts} +2 -2
- package/dist/test/builder.d.ts.map +1 -0
- package/dist/{test-builder.js → test/builder.js} +3 -3
- package/dist/{test-builder.js.map → test/builder.js.map} +1 -1
- package/dist/{each-builder.d.ts → test/each-builder.d.ts} +1 -1
- package/dist/test/each-builder.d.ts.map +1 -0
- package/dist/{each-builder.js → test/each-builder.js} +3 -3
- package/dist/test/each-builder.js.map +1 -0
- package/dist/{test-extend.d.ts → test/extend.d.ts} +3 -3
- package/dist/test/extend.d.ts.map +1 -0
- package/dist/{test-extend.js → test/extend.js} +5 -5
- package/dist/test/extend.js.map +1 -0
- package/dist/{test-utils.d.ts → test/utils.d.ts} +2 -2
- package/dist/test/utils.d.ts.map +1 -0
- package/dist/{test-utils.js → test/utils.js} +1 -1
- package/dist/test/utils.js.map +1 -0
- package/dist/types.d.ts +78 -7
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/contract-http/flow-helpers.d.ts +0 -12
- package/dist/contract-http/flow-helpers.d.ts.map +0 -1
- package/dist/contract-http/flow-helpers.js +0 -34
- package/dist/contract-http/flow-helpers.js.map +0 -1
- package/dist/contract-http/markdown.d.ts +0 -10
- package/dist/contract-http/markdown.d.ts.map +0 -1
- package/dist/contract-http/markdown.js +0 -21
- package/dist/contract-http/markdown.js.map +0 -1
- package/dist/each-builder.d.ts.map +0 -1
- package/dist/each-builder.js.map +0 -1
- package/dist/test-builder.d.ts.map +0 -1
- package/dist/test-extend.d.ts.map +0 -1
- package/dist/test-extend.js.map +0 -1
- package/dist/test-utils.d.ts.map +0 -1
- package/dist/test-utils.js.map +0 -1
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* ContractCase, ContractExpect, etc.).
|
|
11
11
|
*/
|
|
12
12
|
import type { HttpClient, SchemaLike, TestContext } from "../types.js";
|
|
13
|
-
import type {
|
|
13
|
+
import type { BaseCaseSpec, Extensions } from "../contract-types.js";
|
|
14
14
|
/**
|
|
15
15
|
* HTTP security scheme declaration for contract instances.
|
|
16
16
|
* Maps to OpenAPI `securitySchemes`. Authoritative metadata, not docs-only.
|
|
@@ -69,7 +69,64 @@ export interface ContractExpect<T = unknown> {
|
|
|
69
69
|
/** Named response examples (OpenAPI docs). */
|
|
70
70
|
examples?: Record<string, ContractExample<T>>;
|
|
71
71
|
}
|
|
72
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Static-body shape for HTTP case `body` field. Excludes `unknown` (which
|
|
74
|
+
* would swallow the function branch in a union and lose `Needs` typing for
|
|
75
|
+
* function-valued bodies). Function-form `body: (input: Needs) => ...` only
|
|
76
|
+
* matches when the static-form types reject the value.
|
|
77
|
+
*/
|
|
78
|
+
export type HttpStaticBody = Record<string, unknown> | unknown[] | string | number | boolean | null | FormData | URLSearchParams | Blob;
|
|
79
|
+
/**
|
|
80
|
+
* v0 HTTP case factory — closes the v3 P2 known-open ("HTTP body Needs
|
|
81
|
+
* drift"). Inside a contract spec literal, TypeScript can't correlate
|
|
82
|
+
* `needs: SchemaLike<X>` and `body: (input: Y) => ...` from sibling
|
|
83
|
+
* fields — author can write drift between them and TS won't flag it
|
|
84
|
+
* (`body` runs with `input.email` undefined when `body` destructures
|
|
85
|
+
* a key that isn't on Needs).
|
|
86
|
+
*
|
|
87
|
+
* `defineHttpCase<Needs, T>` captures `Needs` once via the explicit
|
|
88
|
+
* generic; the case literal is then checked against
|
|
89
|
+
* `ContractCase<T, Needs>` so all action fields (`body`, `params`,
|
|
90
|
+
* `query`, `headers`) are constrained to `(input: Needs) => ...`. Drift
|
|
91
|
+
* between `needs` and any action field becomes a compile error.
|
|
92
|
+
*
|
|
93
|
+
* Use it for cases that declare `needs` AND have function-valued action
|
|
94
|
+
* fields. Cases without `needs` (or with only static action fields)
|
|
95
|
+
* don't need the factory; the runtime invariants are unaffected either
|
|
96
|
+
* way (this is a typing improvement only).
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```ts
|
|
100
|
+
* import { defineHttpCase } from "@glubean/sdk";
|
|
101
|
+
* import { z } from "zod";
|
|
102
|
+
*
|
|
103
|
+
* const successCase = defineHttpCase<{ email: string }>({
|
|
104
|
+
* description: "creates a user",
|
|
105
|
+
* needs: z.object({ email: z.string() }),
|
|
106
|
+
* // body, params, query, headers params now type-checked against
|
|
107
|
+
* // { email: string } — author can NOT write `({wrongKey}) => ...`.
|
|
108
|
+
* body: ({ email }) => ({ email }),
|
|
109
|
+
* expect: { status: 201 },
|
|
110
|
+
* });
|
|
111
|
+
*
|
|
112
|
+
* const api = contract.http.with("users", { client });
|
|
113
|
+
* export const createUser = api("user.create", {
|
|
114
|
+
* endpoint: "POST /users",
|
|
115
|
+
* cases: { success: successCase },
|
|
116
|
+
* });
|
|
117
|
+
* ```
|
|
118
|
+
*
|
|
119
|
+
* @param c The case spec to validate. Returned verbatim.
|
|
120
|
+
*/
|
|
121
|
+
export declare function defineHttpCase<Needs = void, T = unknown>(c: ContractCase<T, Needs>): ContractCase<T, Needs>;
|
|
122
|
+
export interface ContractCase<T = unknown, Needs = void> extends BaseCaseSpec {
|
|
123
|
+
/**
|
|
124
|
+
* Per-case logical input schema. Redeclares the `BaseCaseSpec.needs` field
|
|
125
|
+
* with the case-specific `Needs` parameter so author-provided schema and
|
|
126
|
+
* function-valued action field parameter types stay locked together —
|
|
127
|
+
* preventing drift between `needs: SchemaLike<X>` and `body: ({wrong}) => ...`.
|
|
128
|
+
*/
|
|
129
|
+
needs?: SchemaLike<Needs>;
|
|
73
130
|
/** Per-case HTTP client override. */
|
|
74
131
|
client?: HttpClient;
|
|
75
132
|
/** Why this case exists — required. */
|
|
@@ -77,35 +134,26 @@ export interface ContractCase<T = unknown, S = void> {
|
|
|
77
134
|
/** Expected response. */
|
|
78
135
|
expect: ContractExpect<T>;
|
|
79
136
|
/**
|
|
80
|
-
* Request body (for POST/PUT/PATCH).
|
|
81
|
-
*
|
|
137
|
+
* Request body (for POST/PUT/PATCH). Either a static value (HttpStaticBody)
|
|
138
|
+
* or a function of the case's logical input (matching `needs`). v10
|
|
139
|
+
* attachment model: no more setup state — input comes from overlay
|
|
140
|
+
* bootstrap, explicit `--input-json`, or flow `.step() in` lens.
|
|
141
|
+
*
|
|
142
|
+
* The static branch deliberately uses concrete types (not `unknown`)
|
|
143
|
+
* because `unknown` in a union swallows the function branch — `Needs`
|
|
144
|
+
* typing on the function param would then be silently bypassed.
|
|
82
145
|
*/
|
|
83
|
-
body?:
|
|
146
|
+
body?: HttpStaticBody | ((input: Needs) => unknown);
|
|
84
147
|
/** Request content type override for this case. */
|
|
85
148
|
contentType?: string;
|
|
86
149
|
/** URL params. Values can be `ParamValue` objects for OpenAPI metadata. */
|
|
87
|
-
params?: Record<string, ParamValue> | ((
|
|
150
|
+
params?: Record<string, ParamValue> | ((input: Needs) => Record<string, string>);
|
|
88
151
|
/** Query parameters. */
|
|
89
|
-
query?: Record<string, ParamValue> | ((
|
|
152
|
+
query?: Record<string, ParamValue> | ((input: Needs) => Record<string, string>);
|
|
90
153
|
/** Request headers merged with client headers. */
|
|
91
|
-
headers?: Record<string, string> | ((
|
|
92
|
-
/** Setup runs before the request. Return value goes to param/query/body/headers functions + teardown. */
|
|
93
|
-
setup?: (ctx: TestContext) => Promise<S>;
|
|
94
|
-
/** Teardown runs after verify, even on failure. */
|
|
95
|
-
teardown?: (ctx: TestContext, state: S) => Promise<void>;
|
|
154
|
+
headers?: Record<string, string> | ((input: Needs) => Record<string, string>);
|
|
96
155
|
/** Business-logic verify — runs after status and schema validation. */
|
|
97
156
|
verify?: (ctx: TestContext, res: T) => Promise<void>;
|
|
98
|
-
/** Not yet executable; reason shown in skip message. */
|
|
99
|
-
deferred?: string;
|
|
100
|
-
/** Deprecated; value is the reason. */
|
|
101
|
-
deprecated?: string;
|
|
102
|
-
/** Additional tags (merged with contract-level tags). */
|
|
103
|
-
tags?: string[];
|
|
104
|
-
severity?: CaseSeverity;
|
|
105
|
-
requires?: CaseRequires;
|
|
106
|
-
defaultRun?: CaseDefaultRun;
|
|
107
|
-
/** Per-case OpenAPI extensions. */
|
|
108
|
-
extensions?: Extensions;
|
|
109
157
|
}
|
|
110
158
|
/**
|
|
111
159
|
* Structured request specification. Can be a bare SchemaLike (JSON body
|
|
@@ -239,7 +287,7 @@ export interface HttpFlowCaseOutput {
|
|
|
239
287
|
* `contract.http.with("name", defaults)`.
|
|
240
288
|
*/
|
|
241
289
|
export interface HttpContractFactory {
|
|
242
|
-
<Cases extends Record<string, ContractCase<any, any>>>(id: string, spec: HttpContractSpec<Cases>): import("../contract-types.js").ProtocolContract<HttpContractSpec
|
|
290
|
+
<Cases extends Record<string, ContractCase<any, any>>>(id: string, spec: HttpContractSpec<Cases>): import("../contract-types.js").ProtocolContract<HttpContractSpec<Cases>, HttpPayloadSchemas, HttpContractMeta, Cases>;
|
|
243
291
|
with(name: string, defaults: HttpContractDefaults): HttpContractFactory;
|
|
244
292
|
}
|
|
245
293
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/contract-http/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,KAAK,EACV,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/contract-http/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,5 +9,49 @@
|
|
|
9
9
|
* Source-of-truth for user-facing authoring types (HttpContractSpec,
|
|
10
10
|
* ContractCase, ContractExpect, etc.).
|
|
11
11
|
*/
|
|
12
|
-
|
|
12
|
+
/**
|
|
13
|
+
* v0 HTTP case factory — closes the v3 P2 known-open ("HTTP body Needs
|
|
14
|
+
* drift"). Inside a contract spec literal, TypeScript can't correlate
|
|
15
|
+
* `needs: SchemaLike<X>` and `body: (input: Y) => ...` from sibling
|
|
16
|
+
* fields — author can write drift between them and TS won't flag it
|
|
17
|
+
* (`body` runs with `input.email` undefined when `body` destructures
|
|
18
|
+
* a key that isn't on Needs).
|
|
19
|
+
*
|
|
20
|
+
* `defineHttpCase<Needs, T>` captures `Needs` once via the explicit
|
|
21
|
+
* generic; the case literal is then checked against
|
|
22
|
+
* `ContractCase<T, Needs>` so all action fields (`body`, `params`,
|
|
23
|
+
* `query`, `headers`) are constrained to `(input: Needs) => ...`. Drift
|
|
24
|
+
* between `needs` and any action field becomes a compile error.
|
|
25
|
+
*
|
|
26
|
+
* Use it for cases that declare `needs` AND have function-valued action
|
|
27
|
+
* fields. Cases without `needs` (or with only static action fields)
|
|
28
|
+
* don't need the factory; the runtime invariants are unaffected either
|
|
29
|
+
* way (this is a typing improvement only).
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* import { defineHttpCase } from "@glubean/sdk";
|
|
34
|
+
* import { z } from "zod";
|
|
35
|
+
*
|
|
36
|
+
* const successCase = defineHttpCase<{ email: string }>({
|
|
37
|
+
* description: "creates a user",
|
|
38
|
+
* needs: z.object({ email: z.string() }),
|
|
39
|
+
* // body, params, query, headers params now type-checked against
|
|
40
|
+
* // { email: string } — author can NOT write `({wrongKey}) => ...`.
|
|
41
|
+
* body: ({ email }) => ({ email }),
|
|
42
|
+
* expect: { status: 201 },
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* const api = contract.http.with("users", { client });
|
|
46
|
+
* export const createUser = api("user.create", {
|
|
47
|
+
* endpoint: "POST /users",
|
|
48
|
+
* cases: { success: successCase },
|
|
49
|
+
* });
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* @param c The case spec to validate. Returned verbatim.
|
|
53
|
+
*/
|
|
54
|
+
export function defineHttpCase(c) {
|
|
55
|
+
return c;
|
|
56
|
+
}
|
|
13
57
|
//# sourceMappingURL=types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/contract-http/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/contract-http/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AA6GH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,MAAM,UAAU,cAAc,CAC5B,CAAyB;IAEzB,OAAO,CAAC,CAAC;AACX,CAAC"}
|
package/dist/contract-types.d.ts
CHANGED
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
* See `internal/40-discovery/proposals/contract-generics-complete.md` v5
|
|
18
18
|
* and `internal/40-discovery/proposals/contract-flow.md` v9 for design.
|
|
19
19
|
*/
|
|
20
|
-
import type { Test, TestContext } from "./types.js";
|
|
20
|
+
import type { SchemaLike, Test, TestContext } from "./types.js";
|
|
21
|
+
import type { KnownArtifacts, KnownArtifactParts, KnownArtifactOptions } from "./index.js";
|
|
21
22
|
/**
|
|
22
23
|
* Case lifecycle.
|
|
23
24
|
*
|
|
@@ -73,6 +74,89 @@ export interface FailureClassification {
|
|
|
73
74
|
retryable?: boolean;
|
|
74
75
|
message?: string;
|
|
75
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Minimum shape every case spec must satisfy. Adapter-specific case specs
|
|
79
|
+
* (HttpContractCase / GrpcContractCase / GraphqlContractCase / ...) extend
|
|
80
|
+
* this with protocol-specific fields.
|
|
81
|
+
*
|
|
82
|
+
* Core (`dispatchContract`) reads these fields directly from `spec.cases[key]`.
|
|
83
|
+
* Adapter-specific fields are opaque to core and passed through to the adapter.
|
|
84
|
+
*
|
|
85
|
+
* @see contract-attachment-model.md v1.3 for `needs` / `given` / `runnability` semantics.
|
|
86
|
+
*/
|
|
87
|
+
export interface BaseCaseSpec {
|
|
88
|
+
description?: string;
|
|
89
|
+
/**
|
|
90
|
+
* Logical input schema for the case. The only public input contract.
|
|
91
|
+
* Protocol action fields (HTTP body/headers/params/query etc.) receive
|
|
92
|
+
* this typed input as their argument.
|
|
93
|
+
*
|
|
94
|
+
* Typed as `SchemaLike<unknown>` at the base to accept any concrete
|
|
95
|
+
* schema. The specific type is extracted per-case via `InferCaseInput<C>`
|
|
96
|
+
* when `ProtocolContract.case<K>()` types its return — TS infers the
|
|
97
|
+
* concrete T from the literal `SchemaLike<T>` the author wrote.
|
|
98
|
+
*
|
|
99
|
+
* This avoids a generic on `BaseCaseSpec<Needs>` which would force every
|
|
100
|
+
* adapter's case type (ContractCase / GrpcContractCase / GraphqlContractCase)
|
|
101
|
+
* to thread a Needs parameter through — too invasive for the authoring API.
|
|
102
|
+
*/
|
|
103
|
+
needs?: SchemaLike<unknown>;
|
|
104
|
+
/**
|
|
105
|
+
* World-state precondition this case assumes. Projected as part of the
|
|
106
|
+
* contract because it changes what `expect` means (see §0.9 of the
|
|
107
|
+
* attachment model proposal). Bootstrap may *satisfy* `given` at
|
|
108
|
+
* runtime, but it must not be the only place where a semantically
|
|
109
|
+
* relevant precondition is declared.
|
|
110
|
+
*/
|
|
111
|
+
given?: string;
|
|
112
|
+
/**
|
|
113
|
+
* Runnability metadata — grouped under `runnability` to make the
|
|
114
|
+
* "not contract semantic" stance structurally visible. Fields here
|
|
115
|
+
* do NOT enter contract projection; they enter runnable inventory.
|
|
116
|
+
*/
|
|
117
|
+
runnability?: {
|
|
118
|
+
requireAttachment?: boolean;
|
|
119
|
+
};
|
|
120
|
+
deferred?: string;
|
|
121
|
+
deprecated?: string;
|
|
122
|
+
severity?: CaseSeverity;
|
|
123
|
+
requires?: CaseRequires;
|
|
124
|
+
defaultRun?: CaseDefaultRun;
|
|
125
|
+
tags?: string[];
|
|
126
|
+
extensions?: Extensions;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Context passed to `bootstrap.run(ctx, params)`. Extends TestContext with
|
|
130
|
+
* cleanup registration — cleanups run LIFO after standalone case execution,
|
|
131
|
+
* even if case expect/verify fails.
|
|
132
|
+
*
|
|
133
|
+
* Flow NEVER invokes bootstrap, so StandaloneBootstrapContext only exists
|
|
134
|
+
* for the standalone execution path.
|
|
135
|
+
*/
|
|
136
|
+
export interface StandaloneBootstrapContext extends TestContext {
|
|
137
|
+
cleanup(fn: () => Promise<void> | void): void;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Bootstrap spec. Plain function form is shorthand for structured form
|
|
141
|
+
* with no `params`.
|
|
142
|
+
*
|
|
143
|
+
* Body is opaque (§4.2 attachment model); only `params` schema is projectable.
|
|
144
|
+
*/
|
|
145
|
+
export type Bootstrap<Params, Output> = ((ctx: StandaloneBootstrapContext) => Promise<Output>) | {
|
|
146
|
+
params?: SchemaLike<Params>;
|
|
147
|
+
run: (ctx: StandaloneBootstrapContext, params: Params) => Promise<Output>;
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* Runtime marker carried by a registered bootstrap overlay. Scanner reads
|
|
151
|
+
* the __glubean_type discriminator; runner consults the registry at
|
|
152
|
+
* runnable resolution time.
|
|
153
|
+
*/
|
|
154
|
+
export interface BootstrapAttachment<Needs = void, Params = void> {
|
|
155
|
+
readonly __glubean_type: "bootstrap-attachment";
|
|
156
|
+
readonly testId: string;
|
|
157
|
+
readonly __phantom_needs?: Needs;
|
|
158
|
+
readonly __phantom_params?: Params;
|
|
159
|
+
}
|
|
76
160
|
/**
|
|
77
161
|
* Protocol-agnostic case metadata. `schemas` is plugin-defined payload shape,
|
|
78
162
|
* opaque to core.
|
|
@@ -97,6 +181,39 @@ export interface CaseMeta<PayloadSchemas = unknown, Meta = unknown> {
|
|
|
97
181
|
schemas?: PayloadSchemas;
|
|
98
182
|
/** Plugin-defined free-form metadata. Opaque to core. */
|
|
99
183
|
meta?: Meta;
|
|
184
|
+
/**
|
|
185
|
+
* World-state precondition (contract-attachment-model.md §0.9). Projected
|
|
186
|
+
* as part of the contract because it changes what `expect` means.
|
|
187
|
+
* Adapter-independent — threaded verbatim from `BaseCaseSpec.given`.
|
|
188
|
+
*/
|
|
189
|
+
given?: string;
|
|
190
|
+
/**
|
|
191
|
+
* Runnability metadata (contract-attachment-model.md §7.2). Not contract
|
|
192
|
+
* semantic; drives runnable inventory (e.g. `requireAttachment` blocks
|
|
193
|
+
* raw execution). Threaded verbatim from `BaseCaseSpec.runnability`.
|
|
194
|
+
*/
|
|
195
|
+
runnability?: {
|
|
196
|
+
requireAttachment?: boolean;
|
|
197
|
+
};
|
|
198
|
+
/**
|
|
199
|
+
* v10 attachment-model — the case's logical-input (`needs`) schema in
|
|
200
|
+
* JSON-safe form. Populated by adapter.normalize() when the case's
|
|
201
|
+
* `needs` schema can be projected (`schemaToJsonSchema` returns
|
|
202
|
+
* something). Absent when the case has no `needs` OR when the schema
|
|
203
|
+
* shape isn't projectable (custom `safeParse`-only validator).
|
|
204
|
+
*
|
|
205
|
+
* To decide whether `rawBypass` is available, consumers should check
|
|
206
|
+
* `hasNeeds` below — it is true whenever the case declared `needs`
|
|
207
|
+
* regardless of whether the schema survives projection.
|
|
208
|
+
*/
|
|
209
|
+
needsSchema?: unknown;
|
|
210
|
+
/**
|
|
211
|
+
* True iff the case declares `needs`. Independent from `needsSchema`
|
|
212
|
+
* (which may be undefined even when `hasNeeds` is true, e.g. opaque
|
|
213
|
+
* `safeParse`-only schemas). Inventory uses this to decide whether
|
|
214
|
+
* the `rawBypass` execution path should appear on an overlay.
|
|
215
|
+
*/
|
|
216
|
+
hasNeeds?: boolean;
|
|
100
217
|
}
|
|
101
218
|
/**
|
|
102
219
|
* Runtime contract projection — adapter.project() output.
|
|
@@ -157,8 +274,45 @@ export interface ContractProtocolAdapter<Spec = unknown, RuntimeSchemas = unknow
|
|
|
157
274
|
* Execute a single case. Called by the core dispatcher for each spec case.
|
|
158
275
|
* Adapter does the full case lifecycle: setup → request/invoke → expect →
|
|
159
276
|
* verify → teardown.
|
|
277
|
+
*
|
|
278
|
+
* **Legacy path** — uses case-local `setup` / `teardown` fields.
|
|
279
|
+
* Replaced by `executeCase` in v10 attachment model (setup/teardown are
|
|
280
|
+
* removed from contract case surface; state is provided via bootstrap
|
|
281
|
+
* overlay or explicit input). Kept for backward compat during migration;
|
|
282
|
+
* removed in Spike 2 Phase 2c.
|
|
160
283
|
*/
|
|
161
284
|
execute: (ctx: TestContext, caseSpec: unknown, contractSpec: Spec) => Promise<void>;
|
|
285
|
+
/**
|
|
286
|
+
* Execute a single case in **standalone mode** with an already-resolved
|
|
287
|
+
* logical input.
|
|
288
|
+
*
|
|
289
|
+
* Scope note: this method is **standalone-only**. Flow dispatch continues
|
|
290
|
+
* to use `executeCaseInFlow` (below). The two paths coexist because flow
|
|
291
|
+
* never invokes bootstrap (attachment model §14.0 non-negotiable invariant)
|
|
292
|
+
* — if executeCase took `mode: "flow"`, it would imply flow could route
|
|
293
|
+
* through here, which contradicts the invariant.
|
|
294
|
+
*
|
|
295
|
+
* v10 attachment model entry point. Core dispatcher calls this after:
|
|
296
|
+
* - resolving bootstrap overlay (if registered) to produce `resolvedInput`
|
|
297
|
+
* - OR receiving explicit `--input-json` / `input` from runner
|
|
298
|
+
* - validating against the case's `needs` schema
|
|
299
|
+
*
|
|
300
|
+
* Adapter responsibilities:
|
|
301
|
+
* 1. Receive already-validated `resolvedInput` (no re-validation needed)
|
|
302
|
+
* 2. Call function-valued action fields (body / headers / etc.) with the input
|
|
303
|
+
* 3. Execute request / expect / verify
|
|
304
|
+
* 4. No setup / teardown — those are gone in v10
|
|
305
|
+
*
|
|
306
|
+
* @see contract-attachment-model.md v1.3 §10.1
|
|
307
|
+
* @see single-case-execution-api.md v1 §5
|
|
308
|
+
*/
|
|
309
|
+
executeCase?: (options: {
|
|
310
|
+
ctx: TestContext;
|
|
311
|
+
contract: ProtocolContract<Spec, SafeSchemas, SafeMeta>;
|
|
312
|
+
caseKey: string;
|
|
313
|
+
/** Logical input already validated against `needs`. `void` when case has no needs. */
|
|
314
|
+
resolvedInput: unknown;
|
|
315
|
+
}) => Promise<void>;
|
|
162
316
|
/**
|
|
163
317
|
* Project the spec to a Runtime projection (may contain live schemas).
|
|
164
318
|
*
|
|
@@ -182,7 +336,17 @@ export interface ContractProtocolAdapter<Spec = unknown, RuntimeSchemas = unknow
|
|
|
182
336
|
* protocol-agnostic skeleton (no `schemas` / `meta`). See `contract-flow.md`
|
|
183
337
|
* §3.5.3 rule 3.
|
|
184
338
|
*/
|
|
185
|
-
|
|
339
|
+
/**
|
|
340
|
+
* Convert the runtime projection (may contain live refs like Zod schemas)
|
|
341
|
+
* into the JSON-safe `Extracted` form consumed by downstream (scanner /
|
|
342
|
+
* MCP / CLI / cloud). SDK's `dispatchContract` calls this unconditionally
|
|
343
|
+
* at contract construction and stores the result on the carrier as
|
|
344
|
+
* `_extracted` — scanner reads that directly. Adapter is responsible for
|
|
345
|
+
* knowing which fields are schemas (convert Zod → JSON Schema) vs literal
|
|
346
|
+
* example data (pass through) vs protocol-specific metadata that must
|
|
347
|
+
* survive normalize (e.g. HTTP `security`).
|
|
348
|
+
*/
|
|
349
|
+
normalize: (projection: ContractProjection<RuntimeSchemas, RuntimeMeta> & {
|
|
186
350
|
id: string;
|
|
187
351
|
}) => ExtractedContractProjection<SafeSchemas, SafeMeta>;
|
|
188
352
|
/**
|
|
@@ -197,16 +361,23 @@ export interface ContractProtocolAdapter<Spec = unknown, RuntimeSchemas = unknow
|
|
|
197
361
|
}>;
|
|
198
362
|
}) => FailureClassification | undefined;
|
|
199
363
|
/**
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
364
|
+
* Artifact producers declared by this adapter. Each entry is a
|
|
365
|
+
* per-contract renderer for a registered artifact kind (see
|
|
366
|
+
* `@glubean/sdk`'s `ArtifactKind` + `renderArtifact` / `KnownArtifacts`).
|
|
367
|
+
* Producers return the kind's Part type; cross-contract merging is the
|
|
368
|
+
* kind's responsibility.
|
|
369
|
+
*
|
|
370
|
+
* Keyed by `ArtifactKind.name`. Third-party plugins add new keys by
|
|
371
|
+
* augmenting `KnownArtifacts` / `KnownArtifactParts` / `KnownArtifactOptions`
|
|
372
|
+
* at the package root via `declare module "@glubean/sdk"`.
|
|
373
|
+
*
|
|
374
|
+
* Replaces the deprecated per-adapter `toMarkdown?` / `toOpenApi?` hooks
|
|
375
|
+
* (removed after v0.2.x) which polluted the generic interface with
|
|
376
|
+
* protocol-specific artifacts (OpenAPI is HTTP-only).
|
|
208
377
|
*/
|
|
209
|
-
|
|
378
|
+
artifacts?: {
|
|
379
|
+
[K in keyof KnownArtifacts]?: (projection: ExtractedContractProjection<SafeSchemas, SafeMeta>, options?: KnownArtifactOptions[K]) => KnownArtifactParts[K];
|
|
380
|
+
};
|
|
210
381
|
/**
|
|
211
382
|
* Optional: render the `target` string for display. HTTP: "POST /users"
|
|
212
383
|
* stays as-is. gRPC: "Greeter/SayHello" might become "Greeter.SayHello()".
|
|
@@ -222,16 +393,23 @@ export interface ContractProtocolAdapter<Spec = unknown, RuntimeSchemas = unknow
|
|
|
222
393
|
* Optional: execute a single case as a flow step.
|
|
223
394
|
*
|
|
224
395
|
* Core has already:
|
|
225
|
-
* 1. Computed `resolvedInputs` via `step.bindings.in(state)`
|
|
396
|
+
* 1. Computed `resolvedInputs` via `step.bindings.in(state)`
|
|
226
397
|
* 2. Prepared current flow state
|
|
227
|
-
* 3.
|
|
398
|
+
* 3. **v10 (for migrated protocols)**: validated `resolvedInputs` against
|
|
399
|
+
* the case's `needs` schema via `runFlow` → `validateNeedsOutput`, so
|
|
400
|
+
* the adapter receives already-validated logical input.
|
|
401
|
+
* 4. Passed the live contract instance (access merged scoped-factory state
|
|
228
402
|
* via `contract._spec`)
|
|
229
403
|
*
|
|
230
|
-
* Adapter
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
404
|
+
* Adapter responsibility (post-Spike-4; uniform across HTTP / gRPC /
|
|
405
|
+
* GraphQL): treat `resolvedInputs` as the case's **logical input**
|
|
406
|
+
* matching `needs`. Call function-valued action fields (HTTP:
|
|
407
|
+
* `body`/`params`/`query`/`headers`; gRPC: `request`/`metadata`;
|
|
408
|
+
* GraphQL: `variables`/`headers`) with it. The contract case has no
|
|
409
|
+
* lifecycle in v10 — setup-style work belongs to a
|
|
410
|
+
* `contract.bootstrap()` overlay, NOT to the case itself. Return an
|
|
411
|
+
* adapter-specific CaseOutput (HTTP: `{ status, headers, body }`;
|
|
412
|
+
* gRPC: `GrpcCaseResult`; GraphQL: `GraphqlCaseResult`).
|
|
235
413
|
*
|
|
236
414
|
* Not implemented = this protocol cannot be referenced in a flow.
|
|
237
415
|
*/
|
|
@@ -242,11 +420,21 @@ export interface ContractProtocolAdapter<Spec = unknown, RuntimeSchemas = unknow
|
|
|
242
420
|
resolvedInputs: unknown;
|
|
243
421
|
}) => Promise<unknown>;
|
|
244
422
|
/**
|
|
245
|
-
* Optional: validate that a case can be referenced in a flow.
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
423
|
+
* Optional: validate that a case can be referenced in a flow.
|
|
424
|
+
*
|
|
425
|
+
* v10 call-site: `FlowBuilder.step(ref, bindings)` — fires at
|
|
426
|
+
* step-declaration time, NOT at `ProtocolContract.case(key)` time.
|
|
427
|
+
* Case-ref creation is pure in v10 (attachment model §4.1);
|
|
428
|
+
* flow-safety is a step-declaration concern.
|
|
429
|
+
*
|
|
430
|
+
* Post-Spike-4 reality: NO built-in adapter implements this hook
|
|
431
|
+
* anymore. The v9 rule "function-valued action fields can't resolve
|
|
432
|
+
* in flow" is semantically reversed in v10 — function fields ARE the
|
|
433
|
+
* canonical flow input channel, receiving `resolvedInputs` via
|
|
434
|
+
* logical input. The hook is kept on the interface for protocol-
|
|
435
|
+
* adapter authors who have legitimate per-protocol flow constraints
|
|
436
|
+
* (e.g. streaming-only methods rejected from non-streaming flows in
|
|
437
|
+
* a future plugin).
|
|
250
438
|
*
|
|
251
439
|
* Throws on invalid case; returns undefined on success.
|
|
252
440
|
*/
|
|
@@ -270,13 +458,26 @@ export interface PayloadDescriptor {
|
|
|
270
458
|
* @template PayloadSchemas Runtime (live) payload shape.
|
|
271
459
|
* @template Meta Runtime free-form meta.
|
|
272
460
|
*/
|
|
273
|
-
export interface ProtocolContract<Spec = unknown, PayloadSchemas = unknown, Meta = unknown> extends Array<Test> {
|
|
461
|
+
export interface ProtocolContract<Spec = unknown, PayloadSchemas = unknown, Meta = unknown, Cases extends Record<string, unknown> = Record<string, unknown>> extends Array<Test> {
|
|
274
462
|
/**
|
|
275
463
|
* Runtime projection with `id` injected by core. Consumers duck-type this.
|
|
276
464
|
*/
|
|
277
465
|
readonly _projection: ContractProjection<PayloadSchemas, Meta> & {
|
|
278
466
|
id: string;
|
|
279
467
|
};
|
|
468
|
+
/**
|
|
469
|
+
* JSON-safe extracted projection — result of `adapter.normalize(_projection)`,
|
|
470
|
+
* computed by the dispatcher at contract construction. Scanner / MCP / CLI
|
|
471
|
+
* / cloud read this field directly as the canonical safe form. Never
|
|
472
|
+
* contains live refs (Zod schemas converted to plain JSON Schema etc.).
|
|
473
|
+
*
|
|
474
|
+
* Typed with the same generic slot as `_projection` for structural
|
|
475
|
+
* compatibility; at runtime it is always the Safe shape produced by
|
|
476
|
+
* the adapter's `normalize`.
|
|
477
|
+
*/
|
|
478
|
+
readonly _extracted: ExtractedContractProjection<PayloadSchemas, Meta> & {
|
|
479
|
+
id: string;
|
|
480
|
+
};
|
|
280
481
|
/**
|
|
281
482
|
* Adapter-private runtime spec carrier. Holds the merged executable spec
|
|
282
483
|
* (scoped-factory defaults + contract spec) used by `executeCaseInFlow`
|
|
@@ -294,7 +495,7 @@ export interface ProtocolContract<Spec = unknown, PayloadSchemas = unknown, Meta
|
|
|
294
495
|
* headers as functions). Function fields reference case-local setup state
|
|
295
496
|
* which is not available in flow mode. See contract-flow §5.1.1.
|
|
296
497
|
*/
|
|
297
|
-
case(key:
|
|
498
|
+
case<K extends keyof Cases & string>(key: K): ContractCaseRef<InferCaseInput<Cases[K]>, InferOutput<PayloadSchemas>>;
|
|
298
499
|
}
|
|
299
500
|
/**
|
|
300
501
|
* Adapter-defined helper: extract the "case inputs" shape from PayloadSchemas.
|
|
@@ -308,6 +509,23 @@ export interface ProtocolContract<Spec = unknown, PayloadSchemas = unknown, Meta
|
|
|
308
509
|
* direct typing of their own ContractCaseRef.
|
|
309
510
|
*/
|
|
310
511
|
export type InferInputs<_PayloadSchemas> = unknown;
|
|
512
|
+
/**
|
|
513
|
+
* Extract per-case logical input type from a case spec's `needs` field.
|
|
514
|
+
*
|
|
515
|
+
* Works for any case spec that extends `BaseCaseSpec<Needs>` and declares
|
|
516
|
+
* `needs: SchemaLike<T>`. Returns `void` for cases without `needs`.
|
|
517
|
+
*
|
|
518
|
+
* Used by `ProtocolContract.case<K>()` to infer `ContractCaseRef<Needs, ...>`
|
|
519
|
+
* per-case, so `contract.bootstrap(ref, { run: ... })` can type-check the
|
|
520
|
+
* run return against the specific case's Needs.
|
|
521
|
+
*
|
|
522
|
+
* @see contract-attachment-model.md v1.3 §4.1 / §5.3
|
|
523
|
+
* @see Spike 0 Finding 2 — requires `any` (not `unknown`) in don't-care slot
|
|
524
|
+
* for contravariant positions.
|
|
525
|
+
*/
|
|
526
|
+
export type InferCaseInput<C> = C extends {
|
|
527
|
+
needs?: SchemaLike<infer N>;
|
|
528
|
+
} ? unknown extends N ? void : N : void;
|
|
311
529
|
/** Adapter-defined helper: extract the "case output" shape from PayloadSchemas. */
|
|
312
530
|
export type InferOutput<_PayloadSchemas> = unknown;
|
|
313
531
|
/**
|
|
@@ -468,12 +686,34 @@ export interface FlowBuilder<State = unknown> {
|
|
|
468
686
|
* lens functions (select / repack only; no I/O, no method calls, no
|
|
469
687
|
* branching). Lens purity is enforced at Proxy dry-run time during
|
|
470
688
|
* projection extraction.
|
|
689
|
+
*
|
|
690
|
+
* Single signature with rest-parameter conditional tuple (Spike 0 Finding 3).
|
|
691
|
+
* Two-overload form (historically tried) has a subtle hole: overload 1
|
|
692
|
+
* (void-input, no `in`) excess-property-fails when `in` is passed → TS
|
|
693
|
+
* falls through to overload 2, which accepts because `() => X` is
|
|
694
|
+
* bivariant-assignable to `() => void`. Conditional tuple is a single
|
|
695
|
+
* signature so TS doesn't get a second chance:
|
|
696
|
+
* - void-input case → `bindings` optional; `in` not present in the
|
|
697
|
+
* allowed shape
|
|
698
|
+
* - typed-input case → `bindings.in` REQUIRED
|
|
699
|
+
*
|
|
700
|
+
* In v10, `in` returns LOGICAL case input (matches the case's `needs`),
|
|
701
|
+
* NOT an adapter patch. HTTP adapter's `executeCaseInFlow` calls
|
|
702
|
+
* function-valued body/headers/params/query with this logical input
|
|
703
|
+
* (same mechanism as standalone `executeStandaloneCase`).
|
|
471
704
|
*/
|
|
472
|
-
step<CaseInputs, CaseOutput, NewState = State>(ref: ContractCaseRef<CaseInputs, CaseOutput>,
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
705
|
+
step<CaseInputs, CaseOutput, NewState = State>(ref: ContractCaseRef<CaseInputs, CaseOutput>, ...args: [CaseInputs] extends [void] ? [
|
|
706
|
+
bindings?: {
|
|
707
|
+
out?: (state: State, response: CaseOutput) => NewState;
|
|
708
|
+
name?: string;
|
|
709
|
+
}
|
|
710
|
+
] : [
|
|
711
|
+
bindings: {
|
|
712
|
+
in: (state: State) => CaseInputs;
|
|
713
|
+
out?: (state: State, response: CaseOutput) => NewState;
|
|
714
|
+
name?: string;
|
|
715
|
+
}
|
|
716
|
+
]): FlowBuilder<NewState>;
|
|
477
717
|
/**
|
|
478
718
|
* Add a pure synchronous data-transform step. Accepts any synchronous TS
|
|
479
719
|
* expression (template literals, method calls, .map()). Projection records
|