@procedures/client 0.38.0 → 0.40.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/CHANGELOG.md +21 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/adapters/http/server/handler.js +2 -1
- package/dist/adapters/http/server/handler.js.map +1 -1
- package/dist/adapters/websocket/client/transport.d.ts +1 -1
- package/dist/adapters/websocket/client/transport.d.ts.map +1 -1
- package/dist/adapters/websocket/client/transport.js +18 -6
- package/dist/adapters/websocket/client/transport.js.map +1 -1
- package/dist/testing/index.d.ts +13 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +11 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/log-storage.d.ts +28 -0
- package/dist/testing/log-storage.d.ts.map +1 -0
- package/dist/testing/log-storage.js +75 -0
- package/dist/testing/log-storage.js.map +1 -0
- package/dist/testing/mcp-caller.d.ts +33 -0
- package/dist/testing/mcp-caller.d.ts.map +1 -0
- package/dist/testing/mcp-caller.js +97 -0
- package/dist/testing/mcp-caller.js.map +1 -0
- package/dist/testing/transport-contract.d.ts +167 -0
- package/dist/testing/transport-contract.d.ts.map +1 -0
- package/dist/testing/transport-contract.js +387 -0
- package/dist/testing/transport-contract.js.map +1 -0
- package/package.json +5 -1
- package/src/adapters/http/server/handler.ts +2 -1
- package/src/adapters/websocket/client/transport.ts +20 -7
- package/src/testing/index.ts +31 -0
- package/src/testing/log-storage.ts +72 -0
- package/src/testing/mcp-caller.ts +100 -0
- package/src/testing/transport-contract.ts +560 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The transport contract (roadmap CLI-85, invariant I4 of ARCHITECTURE.md): one suite of wire
|
|
3
|
+
* cases that each face of the procedures server runs. `WIRE-PROTOCOL.md` is the contract.
|
|
4
|
+
*
|
|
5
|
+
* A face gives a factory (`ContractFace`): it starts a server of the face with the procedures of
|
|
6
|
+
* the suite, and it connects callers. The suite then runs the same cases over each face:
|
|
7
|
+
*
|
|
8
|
+
* - a call and its value, on paths of 1, 2 and 4 segments, and segments with "." and "%" (D36, CLI-75)
|
|
9
|
+
* - `NOT_FOUND` for an unknown path and for an empty segment, and `VALIDATION_ERROR`
|
|
10
|
+
* - the code, the message and the retryable flag of a handler error, for a value and for a stream (CLI-58, CLI-68)
|
|
11
|
+
* - the error policy `expose: "coded"` of the server (CLI-80)
|
|
12
|
+
* - `VERSION_CONFLICT` and its conflicts (CLI-16)
|
|
13
|
+
* - the items of a stream and its end, the abort of a call and the cancel of a stream
|
|
14
|
+
* - the deadline of the caller
|
|
15
|
+
* - the token, and the principal of the request hook in the handler (CLI-1, R18)
|
|
16
|
+
* - a subscription to the change topic of a collection: the hint arrives (CLI-15, CLI-75)
|
|
17
|
+
* - the refusal of a request above the size limit of the face
|
|
18
|
+
*
|
|
19
|
+
* A face that does not have a feature by design declares it in its capabilities, and the suite
|
|
20
|
+
* skips the cases of that feature. Each skip thus is data in the test file of the face.
|
|
21
|
+
*
|
|
22
|
+
* The suite is the entry point `@procedures/client/testing`, so a face in another package (and
|
|
23
|
+
* a server of an app, for example Graph) runs the same cases with the client that it uses. The
|
|
24
|
+
* suite imports no test runner: the caller gives `describe`, `it`, `afterEach` and `expect`
|
|
25
|
+
* (`ContractRunner`). Those of Vitest fit.
|
|
26
|
+
*/
|
|
27
|
+
import type { CollectionStorage } from "../procedures/collection/storage.js";
|
|
28
|
+
import type { ProcedureRegistry } from "../procedures/registry.js";
|
|
29
|
+
import type { PrincipalOf } from "../server/types.js";
|
|
30
|
+
import type { ServerErrorPolicy } from "../server/error-policy.js";
|
|
31
|
+
import type { EventPublisherOptions } from "../events/publisher.js";
|
|
32
|
+
import type { EventTransport } from "../events/remote.js";
|
|
33
|
+
import type { Transport } from "../client/types.js";
|
|
34
|
+
/** The assertions of the suite on one value. The `expect` of Vitest gives them. */
|
|
35
|
+
export interface ContractExpectation {
|
|
36
|
+
toBe(expected: unknown): void;
|
|
37
|
+
toEqual(expected: unknown): void;
|
|
38
|
+
toMatchObject(expected: object): void;
|
|
39
|
+
toContain(expected: unknown): void;
|
|
40
|
+
toBeGreaterThan(expected: number): void;
|
|
41
|
+
toBeGreaterThanOrEqual(expected: number): void;
|
|
42
|
+
toBeLessThanOrEqual(expected: number): void;
|
|
43
|
+
readonly not: ContractExpectation;
|
|
44
|
+
}
|
|
45
|
+
/** A case of the suite. */
|
|
46
|
+
export type ContractCase = (name: string, body: () => Promise<void>) => void;
|
|
47
|
+
/** The parts of a test runner that the suite uses. Give those of Vitest: `{ describe, it, afterEach, expect }`. */
|
|
48
|
+
export interface ContractRunner {
|
|
49
|
+
describe(name: string, body: () => void): void;
|
|
50
|
+
readonly it: ContractCase & {
|
|
51
|
+
skipIf(condition: boolean): ContractCase;
|
|
52
|
+
};
|
|
53
|
+
afterEach(body: () => Promise<void>): void;
|
|
54
|
+
expect(actual: unknown, message?: string): ContractExpectation;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The features of a face. A feature that a face does not have by design is false (or undefined),
|
|
58
|
+
* and the suite skips its cases.
|
|
59
|
+
*/
|
|
60
|
+
export interface ContractCapabilities {
|
|
61
|
+
/**
|
|
62
|
+
* The face goes through `Server.handle()`, so the options of the server apply: the error policy
|
|
63
|
+
* (`errors`), the token and the request hook. `LocalTransport` calls the registry directly.
|
|
64
|
+
*/
|
|
65
|
+
readonly server: boolean;
|
|
66
|
+
/** The face carries network credentials (a bearer token) to the token check and the request hook. */
|
|
67
|
+
readonly auth: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Where the face refuses a caller without the token. `call` (the default): each call gets
|
|
70
|
+
* `UNAUTHORIZED`. `connect`: the face refuses the connection, and the caller gets an error
|
|
71
|
+
* without a code. The WebSocket face of a host refuses the upgrade with 401, and a WebSocket
|
|
72
|
+
* client cannot read the status of a refused upgrade.
|
|
73
|
+
*/
|
|
74
|
+
readonly authRefusal?: "call" | "connect" | undefined;
|
|
75
|
+
/** The face carries a subscription (`events.subscribe`) to the event bus of the server. */
|
|
76
|
+
readonly subscriptions: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* `items`: the caller reads each item of a stream when it arrives, and it can cancel the stream.
|
|
79
|
+
* `collected`: one result holds the items (MCP).
|
|
80
|
+
*/
|
|
81
|
+
readonly streams: "items" | "collected";
|
|
82
|
+
/** The face carries the deadline of the caller (`procedure-timeout`) to the handler. */
|
|
83
|
+
readonly deadline: boolean;
|
|
84
|
+
/** The caller gets the metadata of an error, for example the conflicts of `VERSION_CONFLICT`. */
|
|
85
|
+
readonly errorMetadata: boolean;
|
|
86
|
+
/**
|
|
87
|
+
* The face carries the retryable flag of an error from the handler. `LocalTransport` gives
|
|
88
|
+
* `retryable: false` to each error by design: a local call does not get a retry.
|
|
89
|
+
*/
|
|
90
|
+
readonly retryable: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* The size limit of a request of the face. The face sets `ContractSpec.sizeLimit` as its limit,
|
|
93
|
+
* and `code` is the code of the refusal. Undefined: the face has no size limit.
|
|
94
|
+
*/
|
|
95
|
+
readonly sizeLimit?: {
|
|
96
|
+
readonly code: string;
|
|
97
|
+
} | undefined;
|
|
98
|
+
}
|
|
99
|
+
/** What the server of a face serves. The face makes its server from these options. */
|
|
100
|
+
export interface ContractSpec {
|
|
101
|
+
/** The procedures of the suite, and the procedures of the collection. */
|
|
102
|
+
readonly registry: ProcedureRegistry;
|
|
103
|
+
/** The storages of the collections (`ProcedureServerOptions.collections`). */
|
|
104
|
+
readonly collections: Readonly<Record<string, CollectionStorage<unknown>>>;
|
|
105
|
+
/** The remote events of the server, with the topic rule of the collection. */
|
|
106
|
+
readonly events: EventPublisherOptions;
|
|
107
|
+
/** The token of the server. Only a face with `auth` gets it. */
|
|
108
|
+
readonly token?: string | undefined;
|
|
109
|
+
/** The request hook of the server. Only a face with `auth` gets it. */
|
|
110
|
+
readonly principalOf?: PrincipalOf | undefined;
|
|
111
|
+
/** The error policy of the server (CLI-80), and its logger. */
|
|
112
|
+
readonly errors?: ServerErrorPolicy | undefined;
|
|
113
|
+
readonly onError?: ((error: Error) => void) | undefined;
|
|
114
|
+
/** The size limit of a request, in bytes, for a face with `sizeLimit`. */
|
|
115
|
+
readonly sizeLimit?: number | undefined;
|
|
116
|
+
}
|
|
117
|
+
/** The options of one call of a caller. */
|
|
118
|
+
export interface ContractCallOptions {
|
|
119
|
+
readonly signal?: AbortSignal | undefined;
|
|
120
|
+
/** The deadline of the call, in milliseconds from now. */
|
|
121
|
+
readonly deadlineMs?: number | undefined;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* A caller of a face. An error has the fields of a `ClientError`: `code`, `message`, `retryable`
|
|
125
|
+
* and `metadata`.
|
|
126
|
+
*/
|
|
127
|
+
export interface ContractCaller {
|
|
128
|
+
call(path: readonly string[], input: unknown, options?: ContractCallOptions): Promise<unknown>;
|
|
129
|
+
stream(path: readonly string[], input: unknown, options?: ContractCallOptions): AsyncIterable<unknown>;
|
|
130
|
+
/** The transport of the remote events, for a face with `subscriptions`. */
|
|
131
|
+
readonly events?: EventTransport | undefined;
|
|
132
|
+
close?(): Promise<void>;
|
|
133
|
+
}
|
|
134
|
+
/** A started server of a face. */
|
|
135
|
+
export interface ContractServer {
|
|
136
|
+
/** A caller that presents the bearer token, or no credentials. */
|
|
137
|
+
connect(bearer?: string | undefined): Promise<ContractCaller>;
|
|
138
|
+
stop(): Promise<void>;
|
|
139
|
+
}
|
|
140
|
+
/** A face of the procedures server for the suite. */
|
|
141
|
+
export interface ContractFace {
|
|
142
|
+
readonly name: string;
|
|
143
|
+
readonly capabilities: ContractCapabilities;
|
|
144
|
+
start(spec: ContractSpec): Promise<ContractServer>;
|
|
145
|
+
}
|
|
146
|
+
/** The token of the server of a face with `auth`. */
|
|
147
|
+
export declare const CONTRACT_TOKEN = "contract-token-0123456789";
|
|
148
|
+
/** The principal that the request hook gives for the token. */
|
|
149
|
+
export declare const CONTRACT_PRINCIPAL = "contract-user";
|
|
150
|
+
/** The collection of the suite. Its name has a dot and a `%`, so the codec must keep it one segment (D36). */
|
|
151
|
+
export declare const CONTRACT_COLLECTION = "contract.tabs%";
|
|
152
|
+
/** The paths of the path case: 1, 2 and 4 segments, and segments with "." and "%" (CLI-28, CLI-75). */
|
|
153
|
+
export declare const CONTRACT_PATHS: readonly (readonly string[])[];
|
|
154
|
+
/** The description of a procedure of the suite: a face can find its tool by it. */
|
|
155
|
+
export declare function contractDescription(path: readonly string[]): string;
|
|
156
|
+
/**
|
|
157
|
+
* A caller of a `Client` over a transport of the client: HTTP, WebSocket, a message port or the
|
|
158
|
+
* local transport. Each face of the client uses it.
|
|
159
|
+
*/
|
|
160
|
+
export declare function clientCaller(transport: Transport, close?: () => Promise<void>): ContractCaller;
|
|
161
|
+
/**
|
|
162
|
+
* This function declares the cases of the transport contract for one face. Call it at the top
|
|
163
|
+
* level of the test file of the face, with the functions of the test runner:
|
|
164
|
+
* `describeTransportContract(face, { describe, it, afterEach, expect })`.
|
|
165
|
+
*/
|
|
166
|
+
export declare function describeTransportContract(face: ContractFace, runner: ContractRunner): void;
|
|
167
|
+
//# sourceMappingURL=transport-contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport-contract.d.ts","sourceRoot":"","sources":["../../src/testing/transport-contract.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The transport contract (roadmap CLI-85, invariant I4 of ARCHITECTURE.md): one suite of wire
|
|
3
|
+
* cases that each face of the procedures server runs. `WIRE-PROTOCOL.md` is the contract.
|
|
4
|
+
*
|
|
5
|
+
* A face gives a factory (`ContractFace`): it starts a server of the face with the procedures of
|
|
6
|
+
* the suite, and it connects callers. The suite then runs the same cases over each face:
|
|
7
|
+
*
|
|
8
|
+
* - a call and its value, on paths of 1, 2 and 4 segments, and segments with "." and "%" (D36, CLI-75)
|
|
9
|
+
* - `NOT_FOUND` for an unknown path and for an empty segment, and `VALIDATION_ERROR`
|
|
10
|
+
* - the code, the message and the retryable flag of a handler error, for a value and for a stream (CLI-58, CLI-68)
|
|
11
|
+
* - the error policy `expose: "coded"` of the server (CLI-80)
|
|
12
|
+
* - `VERSION_CONFLICT` and its conflicts (CLI-16)
|
|
13
|
+
* - the items of a stream and its end, the abort of a call and the cancel of a stream
|
|
14
|
+
* - the deadline of the caller
|
|
15
|
+
* - the token, and the principal of the request hook in the handler (CLI-1, R18)
|
|
16
|
+
* - a subscription to the change topic of a collection: the hint arrives (CLI-15, CLI-75)
|
|
17
|
+
* - the refusal of a request above the size limit of the face
|
|
18
|
+
*
|
|
19
|
+
* A face that does not have a feature by design declares it in its capabilities, and the suite
|
|
20
|
+
* skips the cases of that feature. Each skip thus is data in the test file of the face.
|
|
21
|
+
*
|
|
22
|
+
* The suite is the entry point `@procedures/client/testing`, so a face in another package (and
|
|
23
|
+
* a server of an app, for example Graph) runs the same cases with the client that it uses. The
|
|
24
|
+
* suite imports no test runner: the caller gives `describe`, `it`, `afterEach` and `expect`
|
|
25
|
+
* (`ContractRunner`). Those of Vitest fit.
|
|
26
|
+
*/
|
|
27
|
+
import { z } from "zod";
|
|
28
|
+
import { Client, VersionConflictError, collectionChangeTopic, collectionTopicRule, createCollectionProcedures, createProcedure, createRegistry, ms, pathToMethod, subscribeRemote, versionConflictsOf, } from "../index.js";
|
|
29
|
+
import { createOverallTimeoutMiddleware } from "../client/index.js";
|
|
30
|
+
import { LogStorage } from "./log-storage.js";
|
|
31
|
+
/** The token of the server of a face with `auth`. */
|
|
32
|
+
export const CONTRACT_TOKEN = "contract-token-0123456789";
|
|
33
|
+
/** The principal that the request hook gives for the token. */
|
|
34
|
+
export const CONTRACT_PRINCIPAL = "contract-user";
|
|
35
|
+
/** The collection of the suite. Its name has a dot and a `%`, so the codec must keep it one segment (D36). */
|
|
36
|
+
export const CONTRACT_COLLECTION = "contract.tabs%";
|
|
37
|
+
/** The paths of the path case: 1, 2 and 4 segments, and segments with "." and "%" (CLI-28, CLI-75). */
|
|
38
|
+
export const CONTRACT_PATHS = [
|
|
39
|
+
["morning"],
|
|
40
|
+
["contract", "path"],
|
|
41
|
+
["contract", "a", "b", "path"],
|
|
42
|
+
["contract", "dot.ted", "path"],
|
|
43
|
+
["contract", "100%", "path"],
|
|
44
|
+
["contract", "%2E", "path"],
|
|
45
|
+
];
|
|
46
|
+
/** The description of a procedure of the suite: a face can find its tool by it. */
|
|
47
|
+
export function contractDescription(path) {
|
|
48
|
+
return `contract ${JSON.stringify(path)}`;
|
|
49
|
+
}
|
|
50
|
+
/** The size of the request of the size case, and the limit that the face gets. */
|
|
51
|
+
const SIZE_LIMIT = 16 * 1024;
|
|
52
|
+
const CONFLICTS = [
|
|
53
|
+
{ id: "a", expected: "1", found: true, value: { n: 2 }, version: "2" },
|
|
54
|
+
{ id: "b", expected: null, found: false, version: null },
|
|
55
|
+
];
|
|
56
|
+
/** The procedures of the suite. */
|
|
57
|
+
function registryOf(seen) {
|
|
58
|
+
const read = { reads: [], writes: [] };
|
|
59
|
+
const procedure = (path) => createProcedure().path([...path]).meta({ effects: read, description: contractDescription(path) });
|
|
60
|
+
const failure = (input) => Object.assign(new Error("it failed"), input.code === undefined ? {} : { code: input.code }, input.retryable === undefined ? {} : { retryable: input.retryable });
|
|
61
|
+
return createRegistry({
|
|
62
|
+
name: "transport-contract",
|
|
63
|
+
procedures: [
|
|
64
|
+
procedure(["contract", "echo"])
|
|
65
|
+
.input(z.object({ text: z.string() }))
|
|
66
|
+
.output(z.object({ text: z.string() }))
|
|
67
|
+
.handler(async (input, ctx) => {
|
|
68
|
+
seen.echoes++;
|
|
69
|
+
const deadline = ctx.capability?.deadline;
|
|
70
|
+
if (deadline !== undefined)
|
|
71
|
+
seen.deadlineLeft.push(deadline - Date.now());
|
|
72
|
+
seen.headers.push(ctx.metadata?.["headers"]);
|
|
73
|
+
return { text: input.text };
|
|
74
|
+
})
|
|
75
|
+
.build(),
|
|
76
|
+
procedure(["contract", "whoami"])
|
|
77
|
+
.input(z.object({}))
|
|
78
|
+
.output(z.object({ principal: z.string().nullable() }))
|
|
79
|
+
.handler(async (_input, ctx) => ({ principal: ctx.principal?.id ?? null }))
|
|
80
|
+
.build(),
|
|
81
|
+
...CONTRACT_PATHS.map((path) => procedure(path)
|
|
82
|
+
.input(z.object({}).passthrough())
|
|
83
|
+
.output(z.object({ path: z.array(z.string()) }))
|
|
84
|
+
.handler(async (_input, ctx) => ({ path: [...ctx.path] }))
|
|
85
|
+
.build()),
|
|
86
|
+
procedure(["contract", "count"])
|
|
87
|
+
.input(z.object({ to: z.number() }))
|
|
88
|
+
.output(z.number())
|
|
89
|
+
.handler(async function* (input) {
|
|
90
|
+
for (let n = 1; n <= input.to; n++)
|
|
91
|
+
yield n;
|
|
92
|
+
})
|
|
93
|
+
.build(),
|
|
94
|
+
procedure(["contract", "endless"])
|
|
95
|
+
.input(z.object({}))
|
|
96
|
+
.output(z.number())
|
|
97
|
+
.handler(async function* () {
|
|
98
|
+
try {
|
|
99
|
+
for (let n = 1;; n++) {
|
|
100
|
+
yield n;
|
|
101
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
seen.streamClosed++;
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
.build(),
|
|
109
|
+
procedure(["contract", "wait"])
|
|
110
|
+
.input(z.object({}))
|
|
111
|
+
.output(z.string())
|
|
112
|
+
.handler(async (_input, ctx) => {
|
|
113
|
+
seen.waiting++;
|
|
114
|
+
await new Promise((resolve) => {
|
|
115
|
+
const timer = setTimeout(resolve, 5000);
|
|
116
|
+
ctx.signal?.addEventListener("abort", () => {
|
|
117
|
+
clearTimeout(timer);
|
|
118
|
+
seen.aborted++;
|
|
119
|
+
resolve();
|
|
120
|
+
}, { once: true });
|
|
121
|
+
});
|
|
122
|
+
return "ended";
|
|
123
|
+
})
|
|
124
|
+
.build(),
|
|
125
|
+
procedure(["contract", "fail"])
|
|
126
|
+
.input(z.object({ code: z.string().optional(), retryable: z.boolean().optional() }))
|
|
127
|
+
.output(z.string())
|
|
128
|
+
.handler(async (input) => {
|
|
129
|
+
throw failure(input);
|
|
130
|
+
})
|
|
131
|
+
.build(),
|
|
132
|
+
// A stream that fails after its items: one item, or the count of the input
|
|
133
|
+
procedure(["contract", "failStream"])
|
|
134
|
+
.input(z.object({ code: z.string().optional(), retryable: z.boolean().optional(), items: z.number().optional() }))
|
|
135
|
+
.output(z.number())
|
|
136
|
+
.handler(async function* (input) {
|
|
137
|
+
for (let n = 1; n <= (input.items ?? 1); n++)
|
|
138
|
+
yield n;
|
|
139
|
+
throw failure(input);
|
|
140
|
+
})
|
|
141
|
+
.build(),
|
|
142
|
+
procedure(["contract", "conflict"])
|
|
143
|
+
.input(z.object({}))
|
|
144
|
+
.output(z.string())
|
|
145
|
+
.handler(async () => {
|
|
146
|
+
throw new VersionConflictError(CONFLICTS);
|
|
147
|
+
})
|
|
148
|
+
.build(),
|
|
149
|
+
...createCollectionProcedures(CONTRACT_COLLECTION),
|
|
150
|
+
],
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
/** The error of a promise, or a failure when it resolves. */
|
|
154
|
+
async function errorOf(promise) {
|
|
155
|
+
try {
|
|
156
|
+
await promise;
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
return error;
|
|
160
|
+
}
|
|
161
|
+
throw new Error("The call did not fail");
|
|
162
|
+
}
|
|
163
|
+
/** The items of a stream. */
|
|
164
|
+
async function itemsOf(stream) {
|
|
165
|
+
const items = [];
|
|
166
|
+
for await (const item of stream)
|
|
167
|
+
items.push(item);
|
|
168
|
+
return items;
|
|
169
|
+
}
|
|
170
|
+
async function waitFor(check, what, limit = 3000) {
|
|
171
|
+
const end = Date.now() + limit;
|
|
172
|
+
while (!check()) {
|
|
173
|
+
if (Date.now() > end)
|
|
174
|
+
throw new Error(`waitFor: ${what}`);
|
|
175
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* A caller of a `Client` over a transport of the client: HTTP, WebSocket, a message port or the
|
|
180
|
+
* local transport. Each face of the client uses it.
|
|
181
|
+
*/
|
|
182
|
+
export function clientCaller(transport, close) {
|
|
183
|
+
const clientOf = (options) => {
|
|
184
|
+
const client = new Client({ transport, throwOnError: true });
|
|
185
|
+
return options?.deadlineMs === undefined ? client : client.use(createOverallTimeoutMiddleware({ overall: ms(options.deadlineMs) }));
|
|
186
|
+
};
|
|
187
|
+
const callOptions = (options) => (options?.signal ? { signal: options.signal } : {});
|
|
188
|
+
return {
|
|
189
|
+
call: (path, input, options) => clientOf(options).call(pathToMethod([...path]), input, callOptions(options)),
|
|
190
|
+
stream: (path, input, options) => clientOf(options).stream(pathToMethod([...path]), input, callOptions(options)),
|
|
191
|
+
events: transport,
|
|
192
|
+
...(close ? { close } : {}),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* This function declares the cases of the transport contract for one face. Call it at the top
|
|
197
|
+
* level of the test file of the face, with the functions of the test runner:
|
|
198
|
+
* `describeTransportContract(face, { describe, it, afterEach, expect })`.
|
|
199
|
+
*/
|
|
200
|
+
export function describeTransportContract(face, runner) {
|
|
201
|
+
const caps = face.capabilities;
|
|
202
|
+
const { describe, it, afterEach, expect } = runner;
|
|
203
|
+
let open = [];
|
|
204
|
+
afterEach(async () => {
|
|
205
|
+
for (const close of open.reverse())
|
|
206
|
+
await close().catch(() => undefined);
|
|
207
|
+
open = [];
|
|
208
|
+
});
|
|
209
|
+
const fresh = () => ({ deadlineLeft: [], waiting: 0, aborted: 0, streamClosed: 0, echoes: 0, headers: [] });
|
|
210
|
+
/** A server of the face, with the procedures of the suite. */
|
|
211
|
+
async function serve(seen, more = {}) {
|
|
212
|
+
const storage = new LogStorage();
|
|
213
|
+
const principalOf = (credentials) => credentials.bearer === CONTRACT_TOKEN ? { principal: { id: CONTRACT_PRINCIPAL, via: "contract" } } : undefined;
|
|
214
|
+
const spec = {
|
|
215
|
+
registry: registryOf(seen),
|
|
216
|
+
collections: { [CONTRACT_COLLECTION]: storage },
|
|
217
|
+
events: { topics: collectionTopicRule(CONTRACT_COLLECTION) },
|
|
218
|
+
...(caps.auth ? { token: CONTRACT_TOKEN, principalOf } : {}),
|
|
219
|
+
...more,
|
|
220
|
+
};
|
|
221
|
+
const server = await face.start(spec);
|
|
222
|
+
open.push(() => server.stop());
|
|
223
|
+
return { server, storage };
|
|
224
|
+
}
|
|
225
|
+
/** A caller of the face, with the token when the face has `auth`. */
|
|
226
|
+
async function connect(server, bearer = caps.auth ? CONTRACT_TOKEN : null) {
|
|
227
|
+
const caller = await server.connect(bearer ?? undefined);
|
|
228
|
+
if (caller.close)
|
|
229
|
+
open.push(() => caller.close());
|
|
230
|
+
return caller;
|
|
231
|
+
}
|
|
232
|
+
async function start(seen = fresh(), more = {}) {
|
|
233
|
+
return connect((await serve(seen, more)).server);
|
|
234
|
+
}
|
|
235
|
+
describe(`the transport contract over ${face.name} (CLI-85)`, () => {
|
|
236
|
+
it("gives the value of a call", async () => {
|
|
237
|
+
const caller = await start();
|
|
238
|
+
expect(await caller.call(["contract", "echo"], { text: "hi" })).toEqual({ text: "hi" });
|
|
239
|
+
});
|
|
240
|
+
it("calls a path of 1, 2 and 4 segments, and keeps a segment with a dot or a % as one segment (CLI-28, CLI-75)", async () => {
|
|
241
|
+
const caller = await start();
|
|
242
|
+
for (const path of CONTRACT_PATHS)
|
|
243
|
+
expect(await caller.call(path, {}), JSON.stringify(path)).toEqual({ path });
|
|
244
|
+
});
|
|
245
|
+
it("gives NOT_FOUND for an unknown path and for a path with an empty segment", async () => {
|
|
246
|
+
const caller = await start();
|
|
247
|
+
expect(await errorOf(caller.call(["contract", "missing"], {}))).toMatchObject({ code: "NOT_FOUND", retryable: false });
|
|
248
|
+
expect(await errorOf(caller.call(["contract", "dot", "path"], {}))).toMatchObject({ code: "NOT_FOUND" });
|
|
249
|
+
expect(await errorOf(caller.call(["contract", ""], {}))).toMatchObject({ code: "NOT_FOUND" });
|
|
250
|
+
});
|
|
251
|
+
it("gives VALIDATION_ERROR for an input that is not valid, and the handler does not run", async () => {
|
|
252
|
+
const seen = fresh();
|
|
253
|
+
const caller = await start(seen);
|
|
254
|
+
expect(await errorOf(caller.call(["contract", "echo"], { text: 5 }))).toMatchObject({ code: "VALIDATION_ERROR", retryable: false });
|
|
255
|
+
expect(seen.echoes).toBe(0);
|
|
256
|
+
});
|
|
257
|
+
it("keeps the code, the message and the flag of a handler error, for a value and for a stream (CLI-58, CLI-68)", async () => {
|
|
258
|
+
const caller = await start();
|
|
259
|
+
// The flag, on a face that carries it
|
|
260
|
+
const flag = (retryable) => (caps.retryable ? { retryable } : {});
|
|
261
|
+
expect(await errorOf(caller.call(["contract", "fail"], { code: "E_CUSTOM" }))).toMatchObject({ code: "E_CUSTOM", message: "it failed", retryable: false });
|
|
262
|
+
expect(await errorOf(caller.call(["contract", "fail"], { code: "E_CUSTOM", retryable: true }))).toMatchObject({ code: "E_CUSTOM", ...flag(true) });
|
|
263
|
+
expect(await errorOf(caller.call(["contract", "fail"], {}))).toMatchObject({ code: "HANDLER_ERROR", message: "it failed" });
|
|
264
|
+
// Without a flag, an error before the first item gets the flag of its code
|
|
265
|
+
expect(await errorOf(caller.call(["contract", "fail"], { code: "UNAVAILABLE" }))).toMatchObject({ code: "UNAVAILABLE", ...flag(true) });
|
|
266
|
+
expect(await errorOf(caller.call(["contract", "fail"], { code: "UNAVAILABLE", retryable: false }))).toMatchObject({ code: "UNAVAILABLE", retryable: false });
|
|
267
|
+
expect(await errorOf(itemsOf(caller.stream(["contract", "failStream"], { code: "E_CUSTOM" })))).toMatchObject({ code: "E_CUSTOM", message: "it failed" });
|
|
268
|
+
expect(await errorOf(itemsOf(caller.stream(["contract", "failStream"], {})))).toMatchObject({ code: "HANDLER_ERROR" });
|
|
269
|
+
// After an item, an end without a flag is not retryable: a retry can send the items again
|
|
270
|
+
expect(await errorOf(itemsOf(caller.stream(["contract", "failStream"], { code: "UNAVAILABLE" })))).toMatchObject({ code: "UNAVAILABLE", retryable: false });
|
|
271
|
+
expect(await errorOf(itemsOf(caller.stream(["contract", "failStream"], { code: "UNAVAILABLE", retryable: true })))).toMatchObject({ code: "UNAVAILABLE", ...flag(true) });
|
|
272
|
+
// An end in the stream before its first item gets the flag of its code, as an error before the stream (CLI-68)
|
|
273
|
+
expect(await errorOf(itemsOf(caller.stream(["contract", "failStream"], { code: "UNAVAILABLE", items: 0 })))).toMatchObject({ code: "UNAVAILABLE", ...flag(true) });
|
|
274
|
+
expect(await errorOf(itemsOf(caller.stream(["contract", "failStream"], { code: "UNAVAILABLE", retryable: false, items: 0 })))).toMatchObject({ code: "UNAVAILABLE", retryable: false });
|
|
275
|
+
// The reader gets the items before the end
|
|
276
|
+
if (caps.streams === "items") {
|
|
277
|
+
const items = [];
|
|
278
|
+
await errorOf((async () => {
|
|
279
|
+
for await (const item of caller.stream(["contract", "failStream"], { code: "UNAVAILABLE", items: 2 }))
|
|
280
|
+
items.push(item);
|
|
281
|
+
})());
|
|
282
|
+
expect(items).toEqual([1, 2]);
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
it.skipIf(!caps.server)('applies the error policy of the server: under "coded", only a known code goes out (CLI-80)', async () => {
|
|
286
|
+
const logged = [];
|
|
287
|
+
const caller = await start(fresh(), { errors: { expose: "coded", codes: ["E_APP"] }, onError: (error) => void logged.push(error) });
|
|
288
|
+
expect(await errorOf(caller.call(["contract", "fail"], { code: "E_APP" }))).toMatchObject({ code: "E_APP", message: "it failed" });
|
|
289
|
+
expect(await errorOf(caller.call(["contract", "fail"], { code: "CONFLICT", retryable: true }))).toMatchObject({ code: "CONFLICT", message: "it failed", retryable: true });
|
|
290
|
+
// Each other error is INTERNAL_ERROR with the message "internal error", and it keeps its flag
|
|
291
|
+
expect(await errorOf(caller.call(["contract", "fail"], {}))).toMatchObject({ code: "INTERNAL_ERROR", message: "internal error", retryable: false });
|
|
292
|
+
expect(await errorOf(caller.call(["contract", "fail"], { code: "ECONNREFUSED", retryable: true }))).toMatchObject({ code: "INTERNAL_ERROR", message: "internal error", retryable: true });
|
|
293
|
+
expect(await errorOf(itemsOf(caller.stream(["contract", "failStream"], { code: "ECONNREFUSED" })))).toMatchObject({ code: "INTERNAL_ERROR", message: "internal error" });
|
|
294
|
+
// The server gives each hidden error to its logger
|
|
295
|
+
expect(logged.length).toBeGreaterThanOrEqual(3);
|
|
296
|
+
});
|
|
297
|
+
it("gives VERSION_CONFLICT, and the conflicts when the caller gets the metadata of an error (CLI-16)", async () => {
|
|
298
|
+
const caller = await start();
|
|
299
|
+
const error = await errorOf(caller.call(["contract", "conflict"], {}));
|
|
300
|
+
expect(error).toMatchObject({ code: "VERSION_CONFLICT", retryable: false });
|
|
301
|
+
if (caps.errorMetadata)
|
|
302
|
+
expect(versionConflictsOf(error)).toEqual(CONFLICTS);
|
|
303
|
+
});
|
|
304
|
+
it("gives the items of a stream in order, and then the end", async () => {
|
|
305
|
+
const caller = await start();
|
|
306
|
+
expect(await itemsOf(caller.stream(["contract", "count"], { to: 3 }))).toEqual([1, 2, 3]);
|
|
307
|
+
expect(await itemsOf(caller.stream(["contract", "count"], { to: 0 }))).toEqual([]);
|
|
308
|
+
});
|
|
309
|
+
it("aborts the handler when the caller aborts the call", async () => {
|
|
310
|
+
const seen = fresh();
|
|
311
|
+
const caller = await start(seen);
|
|
312
|
+
const controller = new AbortController();
|
|
313
|
+
const call = caller.call(["contract", "wait"], {}, { signal: controller.signal });
|
|
314
|
+
// The abort comes when the handler runs: on a slow runner, a call can take more than 50 ms to arrive
|
|
315
|
+
await waitFor(() => seen.waiting === 1, "the start of the handler");
|
|
316
|
+
controller.abort();
|
|
317
|
+
await errorOf(call);
|
|
318
|
+
await waitFor(() => seen.aborted === 1, "the abort of the handler");
|
|
319
|
+
});
|
|
320
|
+
it.skipIf(caps.streams !== "items")("ends the stream of the handler when the reader stops", async () => {
|
|
321
|
+
const seen = fresh();
|
|
322
|
+
const caller = await start(seen);
|
|
323
|
+
const items = [];
|
|
324
|
+
for await (const item of caller.stream(["contract", "endless"], {})) {
|
|
325
|
+
items.push(item);
|
|
326
|
+
if (items.length === 2)
|
|
327
|
+
break;
|
|
328
|
+
}
|
|
329
|
+
expect(items).toEqual([1, 2]);
|
|
330
|
+
await waitFor(() => seen.streamClosed === 1, "the end of the stream of the handler");
|
|
331
|
+
});
|
|
332
|
+
it.skipIf(!caps.deadline)("gives the deadline of the caller to the handler", async () => {
|
|
333
|
+
const seen = fresh();
|
|
334
|
+
const caller = await start(seen);
|
|
335
|
+
await caller.call(["contract", "echo"], { text: "x" }, { deadlineMs: 3000 });
|
|
336
|
+
expect(seen.deadlineLeft[0]).toBeGreaterThan(2000);
|
|
337
|
+
expect(seen.deadlineLeft[0]).toBeLessThanOrEqual(3000);
|
|
338
|
+
});
|
|
339
|
+
it.skipIf(!caps.auth)("refuses a request without the token, and gives the principal of the request hook to the handler (CLI-1, R18)", async () => {
|
|
340
|
+
const seen = fresh();
|
|
341
|
+
const { server } = await serve(seen);
|
|
342
|
+
const refusal = caps.authRefusal === "connect" ? {} : { code: "UNAUTHORIZED" };
|
|
343
|
+
expect(await errorOf((await connect(server, null)).call(["contract", "echo"], { text: "x" }))).toMatchObject(refusal);
|
|
344
|
+
expect(await errorOf((await connect(server, "a-wrong-token-0123456789")).call(["contract", "echo"], { text: "x" }))).toMatchObject(refusal);
|
|
345
|
+
expect(seen.echoes).toBe(0);
|
|
346
|
+
const caller = await connect(server, CONTRACT_TOKEN);
|
|
347
|
+
expect(await caller.call(["contract", "whoami"], {})).toEqual({ principal: CONTRACT_PRINCIPAL });
|
|
348
|
+
expect(await caller.call(["contract", "echo"], { text: "x" })).toEqual({ text: "x" });
|
|
349
|
+
// The secret does not reach the handler
|
|
350
|
+
expect(JSON.stringify(seen.headers)).not.toContain(CONTRACT_TOKEN);
|
|
351
|
+
});
|
|
352
|
+
it.skipIf(!caps.subscriptions)("gives the change hint of a write to a subscriber of the topic of the collection (CLI-15, CLI-75)", async () => {
|
|
353
|
+
const caller = await start();
|
|
354
|
+
const topic = collectionChangeTopic(CONTRACT_COLLECTION);
|
|
355
|
+
const hints = [];
|
|
356
|
+
const topics = [];
|
|
357
|
+
const subscription = subscribeRemote(caller.events, topic, (data, event) => {
|
|
358
|
+
hints.push(data);
|
|
359
|
+
topics.push(event.topic);
|
|
360
|
+
});
|
|
361
|
+
open.push(async () => subscription());
|
|
362
|
+
await subscription.ready;
|
|
363
|
+
const collection = (operation) => ["collections", CONTRACT_COLLECTION, operation];
|
|
364
|
+
// A pull starts the chain of the events
|
|
365
|
+
await caller.call(collection("changes"), {});
|
|
366
|
+
await caller.call(collection("set"), { id: "t1", value: { title: "one" } });
|
|
367
|
+
await waitFor(() => hints.length >= 1, "the change hint");
|
|
368
|
+
expect(hints[0]).toMatchObject({ changed: ["t1"], deleted: [] });
|
|
369
|
+
expect(topics[0]).toBe(topic);
|
|
370
|
+
expect(await caller.call(collection("get"), { id: "t1" })).toEqual({ title: "one" });
|
|
371
|
+
expect(await caller.call(collection("find"), {})).toEqual([{ id: "t1", value: { title: "one" } }]);
|
|
372
|
+
await caller.call(collection("delete"), { id: "t1" });
|
|
373
|
+
await waitFor(() => hints.length >= 2, "the hint of the delete");
|
|
374
|
+
expect(hints[1]).toMatchObject({ changed: [], deleted: ["t1"] });
|
|
375
|
+
});
|
|
376
|
+
it.skipIf(!caps.sizeLimit)("refuses a request above the size limit of the face, and the handler does not run", async () => {
|
|
377
|
+
const seen = fresh();
|
|
378
|
+
const caller = await start(seen, { sizeLimit: SIZE_LIMIT });
|
|
379
|
+
const error = await errorOf(caller.call(["contract", "echo"], { text: "x".repeat(4 * SIZE_LIMIT) }));
|
|
380
|
+
expect(error).toMatchObject({ code: caps.sizeLimit.code, retryable: false });
|
|
381
|
+
expect(seen.echoes).toBe(0);
|
|
382
|
+
// A request below the limit passes
|
|
383
|
+
expect(await (await start(seen, { sizeLimit: SIZE_LIMIT })).call(["contract", "echo"], { text: "small" })).toEqual({ text: "small" });
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
//# sourceMappingURL=transport-contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport-contract.js","sourceRoot":"","sources":["../../src/testing/transport-contract.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "@procedures/client",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.40.0",
|
|
5
5
|
"description": "Procedures as data for TypeScript: define typed procedures once and call them in process, over HTTP, WebSocket, the CLI or MCP. Streaming, middleware, retries, caching and a JSON program format.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"rpc",
|
|
@@ -74,6 +74,10 @@
|
|
|
74
74
|
"./query": {
|
|
75
75
|
"types": "./dist/procedures/collection/query.d.ts",
|
|
76
76
|
"import": "./dist/procedures/collection/query.js"
|
|
77
|
+
},
|
|
78
|
+
"./testing": {
|
|
79
|
+
"types": "./dist/testing/index.d.ts",
|
|
80
|
+
"import": "./dist/testing/index.js"
|
|
77
81
|
}
|
|
78
82
|
},
|
|
79
83
|
"files": [
|
|
@@ -561,7 +561,8 @@ export function createProcedureHandler(server: RequestHandler, options: Procedur
|
|
|
561
561
|
serverRequest = toServerRequest(req, await readBody(req));
|
|
562
562
|
} catch (error) {
|
|
563
563
|
const status = error instanceof BodyError ? error.httpStatus : 400;
|
|
564
|
-
|
|
564
|
+
// A body above the limit is PAYLOAD_TOO_LARGE, as on the MCP face and the WebSocket face (CLI-85)
|
|
565
|
+
sendError(res, status, (error as Error).message, status === 413 ? "PAYLOAD_TOO_LARGE" : "INVALID_REQUEST");
|
|
565
566
|
return;
|
|
566
567
|
}
|
|
567
568
|
if (!serverRequest) {
|