@mcpmesh/sdk 1.4.1 → 2.0.0-beta.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/dist/__tests__/a2a/a2a-bearer.spec.d.ts +2 -0
- package/dist/__tests__/a2a/a2a-bearer.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/a2a-bearer.spec.js +58 -0
- package/dist/__tests__/a2a/a2a-bearer.spec.js.map +1 -0
- package/dist/__tests__/a2a/a2a-client.spec.d.ts +2 -0
- package/dist/__tests__/a2a/a2a-client.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/a2a-client.spec.js +334 -0
- package/dist/__tests__/a2a/a2a-client.spec.js.map +1 -0
- package/dist/__tests__/a2a/a2a-job.spec.d.ts +2 -0
- package/dist/__tests__/a2a/a2a-job.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/a2a-job.spec.js +255 -0
- package/dist/__tests__/a2a/a2a-job.spec.js.map +1 -0
- package/dist/__tests__/a2a/a2a-stream.spec.d.ts +2 -0
- package/dist/__tests__/a2a/a2a-stream.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/a2a-stream.spec.js +278 -0
- package/dist/__tests__/a2a/a2a-stream.spec.js.map +1 -0
- package/dist/__tests__/a2a/agent-a2a-config.spec.d.ts +2 -0
- package/dist/__tests__/a2a/agent-a2a-config.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/agent-a2a-config.spec.js +262 -0
- package/dist/__tests__/a2a/agent-a2a-config.spec.js.map +1 -0
- package/dist/__tests__/a2a/producer/auth-filter.spec.d.ts +2 -0
- package/dist/__tests__/a2a/producer/auth-filter.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/producer/auth-filter.spec.js +127 -0
- package/dist/__tests__/a2a/producer/auth-filter.spec.js.map +1 -0
- package/dist/__tests__/a2a/producer/card-builder.spec.d.ts +2 -0
- package/dist/__tests__/a2a/producer/card-builder.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/producer/card-builder.spec.js +113 -0
- package/dist/__tests__/a2a/producer/card-builder.spec.js.map +1 -0
- package/dist/__tests__/a2a/producer/dispatcher.spec.d.ts +2 -0
- package/dist/__tests__/a2a/producer/dispatcher.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/producer/dispatcher.spec.js +850 -0
- package/dist/__tests__/a2a/producer/dispatcher.spec.js.map +1 -0
- package/dist/__tests__/a2a/producer/mount-surface-push.spec.d.ts +2 -0
- package/dist/__tests__/a2a/producer/mount-surface-push.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/producer/mount-surface-push.spec.js +164 -0
- package/dist/__tests__/a2a/producer/mount-surface-push.spec.js.map +1 -0
- package/dist/__tests__/a2a/producer/mount.spec.d.ts +2 -0
- package/dist/__tests__/a2a/producer/mount.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/producer/mount.spec.js +433 -0
- package/dist/__tests__/a2a/producer/mount.spec.js.map +1 -0
- package/dist/__tests__/a2a/producer/public-url-cache.spec.d.ts +2 -0
- package/dist/__tests__/a2a/producer/public-url-cache.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/producer/public-url-cache.spec.js +116 -0
- package/dist/__tests__/a2a/producer/public-url-cache.spec.js.map +1 -0
- package/dist/__tests__/a2a/producer/sse-emitter.spec.d.ts +2 -0
- package/dist/__tests__/a2a/producer/sse-emitter.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/producer/sse-emitter.spec.js +754 -0
- package/dist/__tests__/a2a/producer/sse-emitter.spec.js.map +1 -0
- package/dist/__tests__/a2a/producer/state-translator.spec.d.ts +2 -0
- package/dist/__tests__/a2a/producer/state-translator.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/producer/state-translator.spec.js +124 -0
- package/dist/__tests__/a2a/producer/state-translator.spec.js.map +1 -0
- package/dist/__tests__/a2a/producer/task-store.spec.d.ts +2 -0
- package/dist/__tests__/a2a/producer/task-store.spec.d.ts.map +1 -0
- package/dist/__tests__/a2a/producer/task-store.spec.js +180 -0
- package/dist/__tests__/a2a/producer/task-store.spec.js.map +1 -0
- package/dist/__tests__/agent-add-tool.spec.d.ts +2 -0
- package/dist/__tests__/agent-add-tool.spec.d.ts.map +1 -0
- package/dist/__tests__/agent-add-tool.spec.js +483 -0
- package/dist/__tests__/agent-add-tool.spec.js.map +1 -0
- package/dist/__tests__/api-runtime-race.spec.d.ts +2 -0
- package/dist/__tests__/api-runtime-race.spec.d.ts.map +1 -0
- package/dist/__tests__/api-runtime-race.spec.js +193 -0
- package/dist/__tests__/api-runtime-race.spec.js.map +1 -0
- package/dist/__tests__/claim-dispatcher.spec.d.ts +2 -0
- package/dist/__tests__/claim-dispatcher.spec.d.ts.map +1 -0
- package/dist/__tests__/claim-dispatcher.spec.js +408 -0
- package/dist/__tests__/claim-dispatcher.spec.js.map +1 -0
- package/dist/__tests__/inbound-job-dispatch.spec.d.ts +2 -0
- package/dist/__tests__/inbound-job-dispatch.spec.d.ts.map +1 -0
- package/dist/__tests__/inbound-job-dispatch.spec.js +185 -0
- package/dist/__tests__/inbound-job-dispatch.spec.js.map +1 -0
- package/dist/__tests__/job-controller-progress.spec.d.ts +2 -0
- package/dist/__tests__/job-controller-progress.spec.d.ts.map +1 -0
- package/dist/__tests__/job-controller-progress.spec.js +85 -0
- package/dist/__tests__/job-controller-progress.spec.js.map +1 -0
- package/dist/__tests__/jobs-cancel-route.spec.d.ts +2 -0
- package/dist/__tests__/jobs-cancel-route.spec.d.ts.map +1 -0
- package/dist/__tests__/jobs-cancel-route.spec.js +88 -0
- package/dist/__tests__/jobs-cancel-route.spec.js.map +1 -0
- package/dist/__tests__/llm-agent-stream.test.d.ts +14 -0
- package/dist/__tests__/llm-agent-stream.test.d.ts.map +1 -0
- package/dist/__tests__/llm-agent-stream.test.js +341 -0
- package/dist/__tests__/llm-agent-stream.test.js.map +1 -0
- package/dist/__tests__/mesh-job-submitter.spec.d.ts +2 -0
- package/dist/__tests__/mesh-job-submitter.spec.d.ts.map +1 -0
- package/dist/__tests__/mesh-job-submitter.spec.js +110 -0
- package/dist/__tests__/mesh-job-submitter.spec.js.map +1 -0
- package/dist/__tests__/proxy-stream.test.d.ts +9 -0
- package/dist/__tests__/proxy-stream.test.d.ts.map +1 -0
- package/dist/__tests__/proxy-stream.test.js +347 -0
- package/dist/__tests__/proxy-stream.test.js.map +1 -0
- package/dist/__tests__/resolver-meshjob.spec.d.ts +26 -0
- package/dist/__tests__/resolver-meshjob.spec.d.ts.map +1 -0
- package/dist/__tests__/resolver-meshjob.spec.js +201 -0
- package/dist/__tests__/resolver-meshjob.spec.js.map +1 -0
- package/dist/__tests__/schema-verdict-policy.test.d.ts +6 -0
- package/dist/__tests__/schema-verdict-policy.test.d.ts.map +1 -0
- package/dist/__tests__/schema-verdict-policy.test.js +126 -0
- package/dist/__tests__/schema-verdict-policy.test.js.map +1 -0
- package/dist/__tests__/sse-stream.test.d.ts +12 -0
- package/dist/__tests__/sse-stream.test.d.ts.map +1 -0
- package/dist/__tests__/sse-stream.test.js +170 -0
- package/dist/__tests__/sse-stream.test.js.map +1 -0
- package/dist/a2a/a2a-bearer.d.ts +27 -0
- package/dist/a2a/a2a-bearer.d.ts.map +1 -0
- package/dist/a2a/a2a-bearer.js +63 -0
- package/dist/a2a/a2a-bearer.js.map +1 -0
- package/dist/a2a/a2a-client.d.ts +114 -0
- package/dist/a2a/a2a-client.d.ts.map +1 -0
- package/dist/a2a/a2a-client.js +405 -0
- package/dist/a2a/a2a-client.js.map +1 -0
- package/dist/a2a/a2a-event.d.ts +25 -0
- package/dist/a2a/a2a-event.d.ts.map +1 -0
- package/dist/a2a/a2a-event.js +9 -0
- package/dist/a2a/a2a-event.js.map +1 -0
- package/dist/a2a/a2a-job.d.ts +58 -0
- package/dist/a2a/a2a-job.d.ts.map +1 -0
- package/dist/a2a/a2a-job.js +264 -0
- package/dist/a2a/a2a-job.js.map +1 -0
- package/dist/a2a/a2a-stream.d.ts +39 -0
- package/dist/a2a/a2a-stream.d.ts.map +1 -0
- package/dist/a2a/a2a-stream.js +290 -0
- package/dist/a2a/a2a-stream.js.map +1 -0
- package/dist/a2a/errors.d.ts +29 -0
- package/dist/a2a/errors.d.ts.map +1 -0
- package/dist/a2a/errors.js +48 -0
- package/dist/a2a/errors.js.map +1 -0
- package/dist/a2a/index.d.ts +12 -0
- package/dist/a2a/index.d.ts.map +1 -0
- package/dist/a2a/index.js +11 -0
- package/dist/a2a/index.js.map +1 -0
- package/dist/a2a/producer/auth-filter.d.ts +34 -0
- package/dist/a2a/producer/auth-filter.d.ts.map +1 -0
- package/dist/a2a/producer/auth-filter.js +39 -0
- package/dist/a2a/producer/auth-filter.js.map +1 -0
- package/dist/a2a/producer/card-builder.d.ts +59 -0
- package/dist/a2a/producer/card-builder.d.ts.map +1 -0
- package/dist/a2a/producer/card-builder.js +59 -0
- package/dist/a2a/producer/card-builder.js.map +1 -0
- package/dist/a2a/producer/dispatcher.d.ts +276 -0
- package/dist/a2a/producer/dispatcher.d.ts.map +1 -0
- package/dist/a2a/producer/dispatcher.js +896 -0
- package/dist/a2a/producer/dispatcher.js.map +1 -0
- package/dist/a2a/producer/index.d.ts +26 -0
- package/dist/a2a/producer/index.d.ts.map +1 -0
- package/dist/a2a/producer/index.js +23 -0
- package/dist/a2a/producer/index.js.map +1 -0
- package/dist/a2a/producer/mount.d.ts +75 -0
- package/dist/a2a/producer/mount.d.ts.map +1 -0
- package/dist/a2a/producer/mount.js +422 -0
- package/dist/a2a/producer/mount.js.map +1 -0
- package/dist/a2a/producer/public-url-cache.d.ts +73 -0
- package/dist/a2a/producer/public-url-cache.d.ts.map +1 -0
- package/dist/a2a/producer/public-url-cache.js +0 -0
- package/dist/a2a/producer/public-url-cache.js.map +1 -0
- package/dist/a2a/producer/registry.d.ts +138 -0
- package/dist/a2a/producer/registry.d.ts.map +1 -0
- package/dist/a2a/producer/registry.js +117 -0
- package/dist/a2a/producer/registry.js.map +1 -0
- package/dist/a2a/producer/sse-emitter.d.ts +85 -0
- package/dist/a2a/producer/sse-emitter.d.ts.map +1 -0
- package/dist/a2a/producer/sse-emitter.js +405 -0
- package/dist/a2a/producer/sse-emitter.js.map +1 -0
- package/dist/a2a/producer/state-translator.d.ts +63 -0
- package/dist/a2a/producer/state-translator.d.ts.map +1 -0
- package/dist/a2a/producer/state-translator.js +108 -0
- package/dist/a2a/producer/state-translator.js.map +1 -0
- package/dist/a2a/producer/task-store.d.ts +128 -0
- package/dist/a2a/producer/task-store.d.ts.map +1 -0
- package/dist/a2a/producer/task-store.js +128 -0
- package/dist/a2a/producer/task-store.js.map +1 -0
- package/dist/agent.d.ts +72 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +618 -13
- package/dist/agent.js.map +1 -1
- package/dist/api-runtime.d.ts +25 -0
- package/dist/api-runtime.d.ts.map +1 -1
- package/dist/api-runtime.js +75 -2
- package/dist/api-runtime.js.map +1 -1
- package/dist/claim-dispatcher.d.ts +126 -0
- package/dist/claim-dispatcher.d.ts.map +1 -0
- package/dist/claim-dispatcher.js +478 -0
- package/dist/claim-dispatcher.js.map +1 -0
- package/dist/express.d.ts.map +1 -1
- package/dist/express.js +33 -6
- package/dist/express.js.map +1 -1
- package/dist/inbound-job-dispatch.d.ts +105 -0
- package/dist/inbound-job-dispatch.d.ts.map +1 -0
- package/dist/inbound-job-dispatch.js +335 -0
- package/dist/inbound-job-dispatch.js.map +1 -0
- package/dist/index.d.ts +37 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -3
- package/dist/index.js.map +1 -1
- package/dist/job-context.d.ts +107 -0
- package/dist/job-context.d.ts.map +1 -0
- package/dist/job-context.js +95 -0
- package/dist/job-context.js.map +1 -0
- package/dist/jobs-cancel-route.d.ts +36 -0
- package/dist/jobs-cancel-route.d.ts.map +1 -0
- package/dist/jobs-cancel-route.js +60 -0
- package/dist/jobs-cancel-route.js.map +1 -0
- package/dist/jobs-helper-tools.d.ts +48 -0
- package/dist/jobs-helper-tools.d.ts.map +1 -0
- package/dist/jobs-helper-tools.js +133 -0
- package/dist/jobs-helper-tools.js.map +1 -0
- package/dist/llm-agent.d.ts +62 -53
- package/dist/llm-agent.d.ts.map +1 -1
- package/dist/llm-agent.js +211 -292
- package/dist/llm-agent.js.map +1 -1
- package/dist/llm-provider.d.ts +4 -4
- package/dist/llm.d.ts +4 -1
- package/dist/llm.d.ts.map +1 -1
- package/dist/llm.js +7 -17
- package/dist/llm.js.map +1 -1
- package/dist/mesh-job-submitter.d.ts +83 -0
- package/dist/mesh-job-submitter.d.ts.map +1 -0
- package/dist/mesh-job-submitter.js +143 -0
- package/dist/mesh-job-submitter.js.map +1 -0
- package/dist/proxy.d.ts +30 -0
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +351 -1
- package/dist/proxy.js.map +1 -1
- package/dist/resolver-meshjob.d.ts +170 -0
- package/dist/resolver-meshjob.d.ts.map +1 -0
- package/dist/resolver-meshjob.js +159 -0
- package/dist/resolver-meshjob.js.map +1 -0
- package/dist/route.d.ts +4 -0
- package/dist/route.d.ts.map +1 -1
- package/dist/route.js.map +1 -1
- package/dist/schema-normalize.d.ts +62 -0
- package/dist/schema-normalize.d.ts.map +1 -0
- package/dist/schema-normalize.js +128 -0
- package/dist/schema-normalize.js.map +1 -0
- package/dist/sse-stream.d.ts +44 -0
- package/dist/sse-stream.d.ts.map +1 -0
- package/dist/sse-stream.js +173 -0
- package/dist/sse-stream.js.map +1 -0
- package/dist/types.d.ts +351 -9
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -3
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for streamMcpTool / proxy.stream() in proxy.ts
|
|
3
|
+
*
|
|
4
|
+
* Mocks ``fetch`` to return a Response whose body is a ReadableStream emitting
|
|
5
|
+
* hand-crafted SSE events (``notifications/progress`` followed by a final
|
|
6
|
+
* ``result``). Verifies the wire-protocol contract documented in #854.
|
|
7
|
+
*/
|
|
8
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
9
|
+
import { createProxy, streamMcpTool, DEFAULT_CALL_OPTIONS } from "../proxy.js";
|
|
10
|
+
// Mock @mcpmesh/core so trace injection / dispatcher pieces don't need a Rust build
|
|
11
|
+
vi.mock("@mcpmesh/core", () => ({
|
|
12
|
+
generateTraceId: () => "trace-mock",
|
|
13
|
+
generateSpanId: () => "span-mock",
|
|
14
|
+
injectTraceContext: (argsJson) => argsJson,
|
|
15
|
+
publishSpan: vi.fn(async () => false),
|
|
16
|
+
parseSseResponse: (s) => s,
|
|
17
|
+
parseSseResponseToObject: (s) => JSON.parse(s),
|
|
18
|
+
}));
|
|
19
|
+
vi.mock("../http-pool.js", () => ({
|
|
20
|
+
getDispatcher: () => undefined,
|
|
21
|
+
}));
|
|
22
|
+
/**
|
|
23
|
+
* Build a ReadableStream<Uint8Array> that emits the given SSE event blocks
|
|
24
|
+
* one chunk at a time. Each block should already include the trailing blank
|
|
25
|
+
* line per SSE spec.
|
|
26
|
+
*/
|
|
27
|
+
function makeSseStream(blocks) {
|
|
28
|
+
const encoder = new TextEncoder();
|
|
29
|
+
let i = 0;
|
|
30
|
+
return new ReadableStream({
|
|
31
|
+
pull(controller) {
|
|
32
|
+
if (i < blocks.length) {
|
|
33
|
+
controller.enqueue(encoder.encode(blocks[i]));
|
|
34
|
+
i += 1;
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
controller.close();
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function sseEvent(payload) {
|
|
43
|
+
return `event: message\ndata: ${JSON.stringify(payload)}\n\n`;
|
|
44
|
+
}
|
|
45
|
+
function makeMockResponse(blocks, opts = {}) {
|
|
46
|
+
return {
|
|
47
|
+
ok: opts.ok ?? true,
|
|
48
|
+
status: opts.status ?? 200,
|
|
49
|
+
statusText: "OK",
|
|
50
|
+
body: makeSseStream(blocks),
|
|
51
|
+
headers: {
|
|
52
|
+
get: (name) => (name.toLowerCase() === "content-type" ? "text/event-stream" : null),
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const ENDPOINT = "http://producer.local:9000";
|
|
57
|
+
const TOOL = "stream_chunks";
|
|
58
|
+
const CAPABILITY = "streamer";
|
|
59
|
+
describe("streamMcpTool", () => {
|
|
60
|
+
let originalFetch;
|
|
61
|
+
beforeEach(() => {
|
|
62
|
+
originalFetch = globalThis.fetch;
|
|
63
|
+
});
|
|
64
|
+
afterEach(() => {
|
|
65
|
+
globalThis.fetch = originalFetch;
|
|
66
|
+
vi.restoreAllMocks();
|
|
67
|
+
});
|
|
68
|
+
it("yields each progress chunk in order", async () => {
|
|
69
|
+
let capturedBody;
|
|
70
|
+
const fetchMock = vi.fn(async (_url, init) => {
|
|
71
|
+
capturedBody = init.body;
|
|
72
|
+
const reqId = JSON.parse(capturedBody).id;
|
|
73
|
+
const token = JSON.parse(capturedBody).params._meta.progressToken;
|
|
74
|
+
return makeMockResponse([
|
|
75
|
+
sseEvent({
|
|
76
|
+
jsonrpc: "2.0",
|
|
77
|
+
method: "notifications/progress",
|
|
78
|
+
params: { progressToken: token, progress: 1, message: "alpha" },
|
|
79
|
+
}),
|
|
80
|
+
sseEvent({
|
|
81
|
+
jsonrpc: "2.0",
|
|
82
|
+
method: "notifications/progress",
|
|
83
|
+
params: { progressToken: token, progress: 2, message: "beta" },
|
|
84
|
+
}),
|
|
85
|
+
sseEvent({
|
|
86
|
+
jsonrpc: "2.0",
|
|
87
|
+
method: "notifications/progress",
|
|
88
|
+
params: { progressToken: token, progress: 3, message: "gamma" },
|
|
89
|
+
}),
|
|
90
|
+
sseEvent({ jsonrpc: "2.0", id: reqId, result: { content: [{ type: "text", text: "alphabetagamma" }] } }),
|
|
91
|
+
]);
|
|
92
|
+
});
|
|
93
|
+
globalThis.fetch = fetchMock;
|
|
94
|
+
const chunks = [];
|
|
95
|
+
for await (const chunk of streamMcpTool(ENDPOINT, TOOL, { foo: 1 }, DEFAULT_CALL_OPTIONS, CAPABILITY)) {
|
|
96
|
+
chunks.push(chunk);
|
|
97
|
+
}
|
|
98
|
+
expect(chunks).toEqual(["alpha", "beta", "gamma"]);
|
|
99
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
100
|
+
// Verify the request body has _meta.progressToken
|
|
101
|
+
const body = JSON.parse(capturedBody);
|
|
102
|
+
expect(body.method).toBe("tools/call");
|
|
103
|
+
expect(body.params.name).toBe(TOOL);
|
|
104
|
+
expect(typeof body.params._meta.progressToken).toBe("string");
|
|
105
|
+
expect(body.params._meta.progressToken.length).toBeGreaterThan(0);
|
|
106
|
+
// Verify Accept header
|
|
107
|
+
const headers = fetchMock.mock.calls[0][1].headers;
|
|
108
|
+
// FastMCP requires both content types in Accept (or it returns 406)
|
|
109
|
+
expect(headers["Accept"]).toBe("application/json, text/event-stream");
|
|
110
|
+
});
|
|
111
|
+
it("does not yield the final result message content", async () => {
|
|
112
|
+
const fetchMock = vi.fn(async (_url, init) => {
|
|
113
|
+
const body = JSON.parse(init.body);
|
|
114
|
+
return makeMockResponse([
|
|
115
|
+
sseEvent({
|
|
116
|
+
jsonrpc: "2.0",
|
|
117
|
+
method: "notifications/progress",
|
|
118
|
+
params: { progressToken: body.params._meta.progressToken, progress: 1, message: "only-chunk" },
|
|
119
|
+
}),
|
|
120
|
+
// Final result with content that must NOT be yielded
|
|
121
|
+
sseEvent({
|
|
122
|
+
jsonrpc: "2.0",
|
|
123
|
+
id: body.id,
|
|
124
|
+
result: { content: [{ type: "text", text: "FINAL-RESULT-DO-NOT-YIELD" }] },
|
|
125
|
+
}),
|
|
126
|
+
]);
|
|
127
|
+
});
|
|
128
|
+
globalThis.fetch = fetchMock;
|
|
129
|
+
const chunks = [];
|
|
130
|
+
for await (const chunk of streamMcpTool(ENDPOINT, TOOL, undefined, DEFAULT_CALL_OPTIONS, CAPABILITY)) {
|
|
131
|
+
chunks.push(chunk);
|
|
132
|
+
}
|
|
133
|
+
expect(chunks).toEqual(["only-chunk"]);
|
|
134
|
+
expect(chunks).not.toContain("FINAL-RESULT-DO-NOT-YIELD");
|
|
135
|
+
});
|
|
136
|
+
it("ignores progress notifications with a mismatched progressToken", async () => {
|
|
137
|
+
const fetchMock = vi.fn(async (_url, init) => {
|
|
138
|
+
const body = JSON.parse(init.body);
|
|
139
|
+
return makeMockResponse([
|
|
140
|
+
// Notification from a DIFFERENT in-flight call (unlikely but defensive)
|
|
141
|
+
sseEvent({
|
|
142
|
+
jsonrpc: "2.0",
|
|
143
|
+
method: "notifications/progress",
|
|
144
|
+
params: { progressToken: "some-other-token", progress: 1, message: "ignored" },
|
|
145
|
+
}),
|
|
146
|
+
sseEvent({
|
|
147
|
+
jsonrpc: "2.0",
|
|
148
|
+
method: "notifications/progress",
|
|
149
|
+
params: { progressToken: body.params._meta.progressToken, progress: 1, message: "kept" },
|
|
150
|
+
}),
|
|
151
|
+
sseEvent({ jsonrpc: "2.0", id: body.id, result: {} }),
|
|
152
|
+
]);
|
|
153
|
+
});
|
|
154
|
+
globalThis.fetch = fetchMock;
|
|
155
|
+
const chunks = [];
|
|
156
|
+
for await (const chunk of streamMcpTool(ENDPOINT, TOOL, undefined, DEFAULT_CALL_OPTIONS, CAPABILITY)) {
|
|
157
|
+
chunks.push(chunk);
|
|
158
|
+
}
|
|
159
|
+
expect(chunks).toEqual(["kept"]);
|
|
160
|
+
});
|
|
161
|
+
it("throws when the JSON-RPC final message contains an error", async () => {
|
|
162
|
+
const fetchMock = vi.fn(async (_url, init) => {
|
|
163
|
+
const body = JSON.parse(init.body);
|
|
164
|
+
return makeMockResponse([
|
|
165
|
+
sseEvent({
|
|
166
|
+
jsonrpc: "2.0",
|
|
167
|
+
method: "notifications/progress",
|
|
168
|
+
params: { progressToken: body.params._meta.progressToken, progress: 1, message: "partial" },
|
|
169
|
+
}),
|
|
170
|
+
sseEvent({
|
|
171
|
+
jsonrpc: "2.0",
|
|
172
|
+
id: body.id,
|
|
173
|
+
error: { code: -32000, message: "tool blew up" },
|
|
174
|
+
}),
|
|
175
|
+
]);
|
|
176
|
+
});
|
|
177
|
+
globalThis.fetch = fetchMock;
|
|
178
|
+
const collect = async () => {
|
|
179
|
+
const out = [];
|
|
180
|
+
for await (const chunk of streamMcpTool(ENDPOINT, TOOL, undefined, DEFAULT_CALL_OPTIONS, CAPABILITY)) {
|
|
181
|
+
out.push(chunk);
|
|
182
|
+
}
|
|
183
|
+
return out;
|
|
184
|
+
};
|
|
185
|
+
await expect(collect()).rejects.toThrow(/tool blew up/);
|
|
186
|
+
});
|
|
187
|
+
it("throws on non-2xx HTTP response", async () => {
|
|
188
|
+
const fetchMock = vi.fn(async () => {
|
|
189
|
+
return {
|
|
190
|
+
ok: false,
|
|
191
|
+
status: 503,
|
|
192
|
+
statusText: "Service Unavailable",
|
|
193
|
+
body: makeSseStream([]),
|
|
194
|
+
headers: { get: () => null },
|
|
195
|
+
};
|
|
196
|
+
});
|
|
197
|
+
globalThis.fetch = fetchMock;
|
|
198
|
+
const collect = async () => {
|
|
199
|
+
for await (const _ of streamMcpTool(ENDPOINT, TOOL, undefined, DEFAULT_CALL_OPTIONS, CAPABILITY)) {
|
|
200
|
+
// no-op
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
await expect(collect()).rejects.toThrow(/503 Service Unavailable/);
|
|
204
|
+
});
|
|
205
|
+
it("releases the underlying reader when the consumer breaks early", async () => {
|
|
206
|
+
let reader;
|
|
207
|
+
const fetchMock = vi.fn(async (_url, init) => {
|
|
208
|
+
const body = JSON.parse(init.body);
|
|
209
|
+
const stream = makeSseStream([
|
|
210
|
+
sseEvent({
|
|
211
|
+
jsonrpc: "2.0",
|
|
212
|
+
method: "notifications/progress",
|
|
213
|
+
params: { progressToken: body.params._meta.progressToken, progress: 1, message: "first" },
|
|
214
|
+
}),
|
|
215
|
+
sseEvent({
|
|
216
|
+
jsonrpc: "2.0",
|
|
217
|
+
method: "notifications/progress",
|
|
218
|
+
params: { progressToken: body.params._meta.progressToken, progress: 2, message: "second" },
|
|
219
|
+
}),
|
|
220
|
+
sseEvent({ jsonrpc: "2.0", id: body.id, result: {} }),
|
|
221
|
+
]);
|
|
222
|
+
// Wrap stream so we can spy on the reader after getReader is called
|
|
223
|
+
const origGetReader = stream.getReader.bind(stream);
|
|
224
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
225
|
+
stream.getReader = function (...rargs) {
|
|
226
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
227
|
+
reader = origGetReader(...rargs);
|
|
228
|
+
return reader;
|
|
229
|
+
};
|
|
230
|
+
return {
|
|
231
|
+
ok: true,
|
|
232
|
+
status: 200,
|
|
233
|
+
statusText: "OK",
|
|
234
|
+
body: stream,
|
|
235
|
+
headers: { get: () => "text/event-stream" },
|
|
236
|
+
};
|
|
237
|
+
});
|
|
238
|
+
globalThis.fetch = fetchMock;
|
|
239
|
+
const iter = streamMcpTool(ENDPOINT, TOOL, undefined, DEFAULT_CALL_OPTIONS, CAPABILITY);
|
|
240
|
+
const out = [];
|
|
241
|
+
for await (const chunk of iter) {
|
|
242
|
+
out.push(chunk);
|
|
243
|
+
// Break on first chunk
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
expect(out).toEqual(["first"]);
|
|
247
|
+
// Wait a tick so finally{} can run
|
|
248
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
249
|
+
expect(reader).toBeDefined();
|
|
250
|
+
// After cancel(), reads should resolve with done:true
|
|
251
|
+
const post = await reader.read();
|
|
252
|
+
expect(post.done).toBe(true);
|
|
253
|
+
});
|
|
254
|
+
it("yields nothing when the producer emits no progress notifications (TS soft-fallback skipped)", async () => {
|
|
255
|
+
// Per #854: TS Stage 1 does NOT implement Python's soft-fallback. If the
|
|
256
|
+
// producer didn't emit progress, the iterable yields nothing.
|
|
257
|
+
const fetchMock = vi.fn(async (_url, init) => {
|
|
258
|
+
const body = JSON.parse(init.body);
|
|
259
|
+
return makeMockResponse([
|
|
260
|
+
sseEvent({
|
|
261
|
+
jsonrpc: "2.0",
|
|
262
|
+
id: body.id,
|
|
263
|
+
result: { content: [{ type: "text", text: "buffered final" }] },
|
|
264
|
+
}),
|
|
265
|
+
]);
|
|
266
|
+
});
|
|
267
|
+
globalThis.fetch = fetchMock;
|
|
268
|
+
const out = [];
|
|
269
|
+
for await (const chunk of streamMcpTool(ENDPOINT, TOOL, undefined, DEFAULT_CALL_OPTIONS, CAPABILITY)) {
|
|
270
|
+
out.push(chunk);
|
|
271
|
+
}
|
|
272
|
+
expect(out).toEqual([]);
|
|
273
|
+
});
|
|
274
|
+
it("handles SSE events split across multiple network chunks", async () => {
|
|
275
|
+
// Split a single SSE event in the middle of its payload to verify the
|
|
276
|
+
// \n\n boundary parser correctly buffers partial reads.
|
|
277
|
+
const fetchMock = vi.fn(async (_url, init) => {
|
|
278
|
+
const body = JSON.parse(init.body);
|
|
279
|
+
const ev1 = sseEvent({
|
|
280
|
+
jsonrpc: "2.0",
|
|
281
|
+
method: "notifications/progress",
|
|
282
|
+
params: { progressToken: body.params._meta.progressToken, progress: 1, message: "one" },
|
|
283
|
+
});
|
|
284
|
+
const ev2 = sseEvent({
|
|
285
|
+
jsonrpc: "2.0",
|
|
286
|
+
method: "notifications/progress",
|
|
287
|
+
params: { progressToken: body.params._meta.progressToken, progress: 2, message: "two" },
|
|
288
|
+
});
|
|
289
|
+
const final = sseEvent({ jsonrpc: "2.0", id: body.id, result: {} });
|
|
290
|
+
const all = ev1 + ev2 + final;
|
|
291
|
+
const mid = Math.floor(all.length / 2);
|
|
292
|
+
return makeMockResponse([all.slice(0, mid), all.slice(mid)]);
|
|
293
|
+
});
|
|
294
|
+
globalThis.fetch = fetchMock;
|
|
295
|
+
const out = [];
|
|
296
|
+
for await (const chunk of streamMcpTool(ENDPOINT, TOOL, undefined, DEFAULT_CALL_OPTIONS, CAPABILITY)) {
|
|
297
|
+
out.push(chunk);
|
|
298
|
+
}
|
|
299
|
+
expect(out).toEqual(["one", "two"]);
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
describe("createProxy.stream() integration", () => {
|
|
303
|
+
let originalFetch;
|
|
304
|
+
beforeEach(() => {
|
|
305
|
+
originalFetch = globalThis.fetch;
|
|
306
|
+
});
|
|
307
|
+
afterEach(() => {
|
|
308
|
+
globalThis.fetch = originalFetch;
|
|
309
|
+
vi.restoreAllMocks();
|
|
310
|
+
});
|
|
311
|
+
it("attaches a non-enumerable stream method that yields progress chunks", async () => {
|
|
312
|
+
const fetchMock = vi.fn(async (_url, init) => {
|
|
313
|
+
const body = JSON.parse(init.body);
|
|
314
|
+
const token = body.params._meta.progressToken;
|
|
315
|
+
return makeMockResponse([
|
|
316
|
+
sseEvent({
|
|
317
|
+
jsonrpc: "2.0",
|
|
318
|
+
method: "notifications/progress",
|
|
319
|
+
params: { progressToken: token, progress: 1, message: "x" },
|
|
320
|
+
}),
|
|
321
|
+
sseEvent({
|
|
322
|
+
jsonrpc: "2.0",
|
|
323
|
+
method: "notifications/progress",
|
|
324
|
+
params: { progressToken: token, progress: 2, message: "y" },
|
|
325
|
+
}),
|
|
326
|
+
sseEvent({ jsonrpc: "2.0", id: body.id, result: {} }),
|
|
327
|
+
]);
|
|
328
|
+
});
|
|
329
|
+
globalThis.fetch = fetchMock;
|
|
330
|
+
const proxy = createProxy(ENDPOINT, CAPABILITY, TOOL);
|
|
331
|
+
expect(typeof proxy.stream).toBe("function");
|
|
332
|
+
// Non-enumerable: JSON.stringify on a function returns undefined entirely,
|
|
333
|
+
// which is the strongest possible guarantee that no internal field leaks.
|
|
334
|
+
// Also verify the property descriptor is non-enumerable explicitly.
|
|
335
|
+
const json = JSON.stringify(proxy);
|
|
336
|
+
expect(json).toBeUndefined();
|
|
337
|
+
const desc = Object.getOwnPropertyDescriptor(proxy, "stream");
|
|
338
|
+
expect(desc).toBeDefined();
|
|
339
|
+
expect(desc?.enumerable).toBe(false);
|
|
340
|
+
const chunks = [];
|
|
341
|
+
for await (const chunk of proxy.stream({ foo: "bar" })) {
|
|
342
|
+
chunks.push(chunk);
|
|
343
|
+
}
|
|
344
|
+
expect(chunks).toEqual(["x", "y"]);
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
//# sourceMappingURL=proxy-stream.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy-stream.test.js","sourceRoot":"","sources":["../../src/__tests__/proxy-stream.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DDDI resolver tests for the `MeshJob` injectable (Phase 1).
|
|
3
|
+
*
|
|
4
|
+
* These tests are the TypeScript instance of the cross-runtime test
|
|
5
|
+
* seam specified in `MESHJOB_DDDI_CONTRACT.md` → "Equivalence across
|
|
6
|
+
* SDKs". The same scenarios MUST be covered by the Python and Java
|
|
7
|
+
* SDKs in their corresponding files
|
|
8
|
+
* (`tests/test_resolver_meshjob.py` and `MeshJobResolverTest.java`).
|
|
9
|
+
*
|
|
10
|
+
* If any behaviour here changes, update the contract first, then
|
|
11
|
+
* mirror across both other SDK test files. Each numbered scenario maps
|
|
12
|
+
* to the checklist in the contract document.
|
|
13
|
+
*
|
|
14
|
+
* # TS-shape note
|
|
15
|
+
*
|
|
16
|
+
* Python's resolver classifies parameters by reflection on
|
|
17
|
+
* `inspect.signature` + `typing.get_type_hints`. TypeScript erases
|
|
18
|
+
* types at runtime, so the TS resolver's input is the explicit
|
|
19
|
+
* `addTool({ dependencies, meshJobParamIndex })` declaration. The
|
|
20
|
+
* scenarios below translate the contract's signature-shape examples
|
|
21
|
+
* into the equivalent declarative form, then assert the same
|
|
22
|
+
* `meshToolDeps[*].signaturePosition` and `meshJobParamIndex` outputs
|
|
23
|
+
* the contract requires.
|
|
24
|
+
*/
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=resolver-meshjob.spec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolver-meshjob.spec.d.ts","sourceRoot":"","sources":["../../src/__tests__/resolver-meshjob.spec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DDDI resolver tests for the `MeshJob` injectable (Phase 1).
|
|
3
|
+
*
|
|
4
|
+
* These tests are the TypeScript instance of the cross-runtime test
|
|
5
|
+
* seam specified in `MESHJOB_DDDI_CONTRACT.md` → "Equivalence across
|
|
6
|
+
* SDKs". The same scenarios MUST be covered by the Python and Java
|
|
7
|
+
* SDKs in their corresponding files
|
|
8
|
+
* (`tests/test_resolver_meshjob.py` and `MeshJobResolverTest.java`).
|
|
9
|
+
*
|
|
10
|
+
* If any behaviour here changes, update the contract first, then
|
|
11
|
+
* mirror across both other SDK test files. Each numbered scenario maps
|
|
12
|
+
* to the checklist in the contract document.
|
|
13
|
+
*
|
|
14
|
+
* # TS-shape note
|
|
15
|
+
*
|
|
16
|
+
* Python's resolver classifies parameters by reflection on
|
|
17
|
+
* `inspect.signature` + `typing.get_type_hints`. TypeScript erases
|
|
18
|
+
* types at runtime, so the TS resolver's input is the explicit
|
|
19
|
+
* `addTool({ dependencies, meshJobParamIndex })` declaration. The
|
|
20
|
+
* scenarios below translate the contract's signature-shape examples
|
|
21
|
+
* into the equivalent declarative form, then assert the same
|
|
22
|
+
* `meshToolDeps[*].signaturePosition` and `meshJobParamIndex` outputs
|
|
23
|
+
* the contract requires.
|
|
24
|
+
*/
|
|
25
|
+
import { describe, it, expect } from "vitest";
|
|
26
|
+
import { resolveMeshJobSignature, ResolverError, } from "../resolver-meshjob.js";
|
|
27
|
+
// ===========================================================================
|
|
28
|
+
// Contract scenarios 1-5 (must mirror across all three SDK test seams)
|
|
29
|
+
// ===========================================================================
|
|
30
|
+
describe("Resolver contract scenarios", () => {
|
|
31
|
+
it("scenario 1: MeshTool only — unchanged behaviour", () => {
|
|
32
|
+
// Python equivalent: fn(name, dep_a: McpMeshTool, dep_b: McpMeshTool)
|
|
33
|
+
// → mesh_tool_positions == [1, 2], no MeshJob.
|
|
34
|
+
//
|
|
35
|
+
// TS declarative form: dependencies ["dep_a", "dep_b"], no
|
|
36
|
+
// meshJobParamIndex. `args` lives at signature position 0; deps
|
|
37
|
+
// start at position 1.
|
|
38
|
+
const result = resolveMeshJobSignature({
|
|
39
|
+
dependencies: ["dep_a", "dep_b"],
|
|
40
|
+
});
|
|
41
|
+
expect(result.meshToolDeps).toEqual([
|
|
42
|
+
{ depIndex: 0, signaturePosition: 1 },
|
|
43
|
+
{ depIndex: 1, signaturePosition: 2 },
|
|
44
|
+
]);
|
|
45
|
+
expect(result.meshJobParamIndex).toBeUndefined();
|
|
46
|
+
});
|
|
47
|
+
it("scenario 2: MeshJob only — no tools, MeshJob index recorded", () => {
|
|
48
|
+
// Python: fn(user_id, job: MeshJob) → mesh_tool_positions == [],
|
|
49
|
+
// mesh_job_param_index == 1.
|
|
50
|
+
const result = resolveMeshJobSignature({
|
|
51
|
+
dependencies: [],
|
|
52
|
+
meshJobParamIndex: 1,
|
|
53
|
+
});
|
|
54
|
+
expect(result.meshToolDeps).toEqual([]);
|
|
55
|
+
expect(result.meshJobParamIndex).toBe(1);
|
|
56
|
+
});
|
|
57
|
+
it("scenario 3: both, MeshJob in middle — MeshTool positions skip MeshJob", () => {
|
|
58
|
+
// Python: plan_trip(
|
|
59
|
+
// user_id: str, # pos 0
|
|
60
|
+
// weather_lookup: McpMeshTool, # pos 1 — MeshTool[0]
|
|
61
|
+
// job: MeshJob, # pos 2 — orthogonal
|
|
62
|
+
// flight_search: McpMeshTool, # pos 3 — MeshTool[1]
|
|
63
|
+
// )
|
|
64
|
+
// → mesh_tool_positions == [1, 3] (NOT [1, 2]); the resolver MUST
|
|
65
|
+
// NOT renumber tool slots when MeshJob is interleaved.
|
|
66
|
+
const result = resolveMeshJobSignature({
|
|
67
|
+
dependencies: ["weather_lookup", "flight_search"],
|
|
68
|
+
meshJobParamIndex: 2,
|
|
69
|
+
});
|
|
70
|
+
expect(result.meshToolDeps).toEqual([
|
|
71
|
+
{ depIndex: 0, signaturePosition: 1 },
|
|
72
|
+
{ depIndex: 1, signaturePosition: 3 }, // 3, not 2 — MeshJob skipped
|
|
73
|
+
]);
|
|
74
|
+
expect(result.meshJobParamIndex).toBe(2);
|
|
75
|
+
});
|
|
76
|
+
it("scenario 4: neither — no DDDI metadata", () => {
|
|
77
|
+
// Python: fn(a, b) → empty resolution.
|
|
78
|
+
const result = resolveMeshJobSignature({ dependencies: [] });
|
|
79
|
+
expect(result.meshToolDeps).toEqual([]);
|
|
80
|
+
expect(result.meshJobParamIndex).toBeUndefined();
|
|
81
|
+
});
|
|
82
|
+
it("scenario 5: MeshJob trailing — index = last signature position", () => {
|
|
83
|
+
// Python: fn(a, b, tool: McpMeshTool, job: MeshJob)
|
|
84
|
+
// → mesh_tool_positions == [2], mesh_job_param_index == 3.
|
|
85
|
+
//
|
|
86
|
+
// TS form: one dep, MeshJob at the end. Note: in TS the user-arg
|
|
87
|
+
// shape is a single `args` object, so positions a/b are inside
|
|
88
|
+
// args (signature pos 0). The MeshTool dep takes pos 1 and the
|
|
89
|
+
// MeshJob takes pos 2 (the last slot).
|
|
90
|
+
const result = resolveMeshJobSignature({
|
|
91
|
+
dependencies: ["tool"],
|
|
92
|
+
meshJobParamIndex: 2,
|
|
93
|
+
});
|
|
94
|
+
expect(result.meshToolDeps).toEqual([
|
|
95
|
+
{ depIndex: 0, signaturePosition: 1 },
|
|
96
|
+
]);
|
|
97
|
+
expect(result.meshJobParamIndex).toBe(2);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
// ===========================================================================
|
|
101
|
+
// Contract edge cases — "Edge cases (REQUIRED)" in MESHJOB_DDDI_CONTRACT.md
|
|
102
|
+
// ===========================================================================
|
|
103
|
+
describe("Resolver edge cases", () => {
|
|
104
|
+
it("multiple MeshJob params raises ResolverError with the contract wording", () => {
|
|
105
|
+
// Phase 1: a tool function may declare at most one MeshJob param.
|
|
106
|
+
// The resolver MUST reject with the exact wording the contract
|
|
107
|
+
// specifies so the developer sees the misuse at registration time.
|
|
108
|
+
expect(() => resolveMeshJobSignature({
|
|
109
|
+
dependencies: [],
|
|
110
|
+
meshJobParamIndex: 1,
|
|
111
|
+
meshJobParamNames: ["firstJob", "secondJob"],
|
|
112
|
+
})).toThrow(ResolverError);
|
|
113
|
+
try {
|
|
114
|
+
resolveMeshJobSignature({
|
|
115
|
+
dependencies: [],
|
|
116
|
+
meshJobParamIndex: 1,
|
|
117
|
+
meshJobParamNames: ["firstJob", "secondJob"],
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
const msg = err.message.toLowerCase();
|
|
122
|
+
// Contract wording: "a tool function may declare at most one MeshJob parameter"
|
|
123
|
+
expect(msg).toContain("at most one");
|
|
124
|
+
expect(msg).toContain("meshjob");
|
|
125
|
+
// Both offending names should appear so the developer can fix it.
|
|
126
|
+
expect(msg).toContain("firstjob");
|
|
127
|
+
expect(msg).toContain("secondjob");
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
it("MeshJob first position — orthogonal at any signature index", () => {
|
|
131
|
+
// Per contract: "MeshJob mixed with MeshTool at any position —
|
|
132
|
+
// permitted". The resolver MUST NOT enforce a trailing-position
|
|
133
|
+
// rule.
|
|
134
|
+
const result = resolveMeshJobSignature({
|
|
135
|
+
dependencies: ["dep_a"],
|
|
136
|
+
meshJobParamIndex: 1, // MeshJob at sig pos 1, dep slides to pos 2
|
|
137
|
+
});
|
|
138
|
+
expect(result.meshToolDeps).toEqual([
|
|
139
|
+
{ depIndex: 0, signaturePosition: 2 },
|
|
140
|
+
]);
|
|
141
|
+
expect(result.meshJobParamIndex).toBe(1);
|
|
142
|
+
});
|
|
143
|
+
it("explicit meshToolPositions — collision with MeshJob throws", () => {
|
|
144
|
+
// Defensive: if the caller supplies both meshToolPositions and
|
|
145
|
+
// meshJobParamIndex and they overlap, that's a contract violation
|
|
146
|
+
// — fail loudly rather than silently overwrite.
|
|
147
|
+
expect(() => resolveMeshJobSignature({
|
|
148
|
+
dependencies: ["x"],
|
|
149
|
+
meshToolPositions: [2],
|
|
150
|
+
meshJobParamIndex: 2,
|
|
151
|
+
})).toThrow(ResolverError);
|
|
152
|
+
});
|
|
153
|
+
it("explicit meshToolPositions — length mismatch throws", () => {
|
|
154
|
+
expect(() => resolveMeshJobSignature({
|
|
155
|
+
dependencies: ["a", "b"],
|
|
156
|
+
meshToolPositions: [1], // length 1 vs deps length 2
|
|
157
|
+
})).toThrow(ResolverError);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
// ===========================================================================
|
|
161
|
+
// Surface tests — the public exports + JS-side contextvar (job-context.ts)
|
|
162
|
+
// ===========================================================================
|
|
163
|
+
describe("MeshJob public surface", () => {
|
|
164
|
+
it("MeshJob type marker is importable from the package types module", async () => {
|
|
165
|
+
// Smoke test the export so a typo doesn't silently break the
|
|
166
|
+
// public API. We dynamic-import to assert it parses; the
|
|
167
|
+
// type-only import at the top of this file would be erased by
|
|
168
|
+
// tsc and not fail at runtime if the export disappeared.
|
|
169
|
+
const types = await import("../types.js");
|
|
170
|
+
// MeshJob is an interface (erased at runtime) — verify it's at
|
|
171
|
+
// least a key on the module type so consumers can `import type`
|
|
172
|
+
// it. The runtime presence we care about is the resolver +
|
|
173
|
+
// job-context, exercised by the other suites.
|
|
174
|
+
expect(types).toBeDefined();
|
|
175
|
+
});
|
|
176
|
+
it("currentJob() returns null outside any active job scope", async () => {
|
|
177
|
+
const { currentJob, remainingSeconds } = await import("../job-context.js");
|
|
178
|
+
expect(currentJob()).toBeNull();
|
|
179
|
+
expect(remainingSeconds()).toBeNull();
|
|
180
|
+
});
|
|
181
|
+
it("withJobAsync sets CURRENT_JOB visible to currentJob() inside the scope", async () => {
|
|
182
|
+
const { currentJob, remainingSeconds, withJobAsync } = await import("../job-context.js");
|
|
183
|
+
const inside = await withJobAsync({ jobId: "job-set", deadlineSecsRemaining: 12.5 }, async () => {
|
|
184
|
+
const cur = currentJob();
|
|
185
|
+
expect(cur).not.toBeNull();
|
|
186
|
+
expect(cur?.jobId).toBe("job-set");
|
|
187
|
+
expect(remainingSeconds()).toBe(12.5);
|
|
188
|
+
return "done";
|
|
189
|
+
});
|
|
190
|
+
expect(inside).toBe("done");
|
|
191
|
+
// Outside the scope: gone again.
|
|
192
|
+
expect(currentJob()).toBeNull();
|
|
193
|
+
});
|
|
194
|
+
it("snapshot with no deadline returns null remainingSeconds", async () => {
|
|
195
|
+
const { remainingSeconds, withJobAsync } = await import("../job-context.js");
|
|
196
|
+
await withJobAsync({ jobId: "job-no-deadline", deadlineSecsRemaining: null }, async () => {
|
|
197
|
+
expect(remainingSeconds()).toBeNull();
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
//# sourceMappingURL=resolver-meshjob.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolver-meshjob.spec.js","sourceRoot":"","sources":["../../src/__tests__/resolver-meshjob.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-verdict-policy.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/schema-verdict-policy.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|