@mcpmesh/sdk 1.3.4 → 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__/llm-provider.test.js +22 -1
- package/dist/__tests__/llm-provider.test.js.map +1 -1
- package/dist/__tests__/media-resolver.test.js +40 -0
- package/dist/__tests__/media-resolver.test.js.map +1 -1
- 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 +99 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +754 -19
- 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 +40 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -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 +11 -4
- package/dist/llm-provider.d.ts.map +1 -1
- package/dist/llm-provider.js +57 -4
- package/dist/llm-provider.js.map +1 -1
- 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/media/resolver.d.ts.map +1 -1
- package/dist/media/resolver.js +3 -2
- package/dist/media/resolver.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/provider-handlers/gemini-handler.js +5 -0
- package/dist/provider-handlers/gemini-handler.js.map +1 -1
- package/dist/proxy.d.ts +40 -0
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +375 -2
- 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/tool-worker-entry.d.ts +21 -0
- package/dist/tool-worker-entry.d.ts.map +1 -0
- package/dist/tool-worker-entry.js +162 -0
- package/dist/tool-worker-entry.js.map +1 -0
- package/dist/tool-worker-pool.d.ts +49 -0
- package/dist/tool-worker-pool.d.ts.map +1 -0
- package/dist/tool-worker-pool.js +272 -0
- package/dist/tool-worker-pool.js.map +1 -0
- package/dist/types.d.ts +351 -9
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -3
|
@@ -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"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Issue #547 Phase 4: unit tests for the schema verdict policy helpers in
|
|
3
|
+
* `schema-normalize.ts`.
|
|
4
|
+
*/
|
|
5
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
6
|
+
// Mock @mcpmesh/core so we don't load the napi binding for these unit tests.
|
|
7
|
+
vi.mock("@mcpmesh/core", () => ({
|
|
8
|
+
normalizeSchema: vi.fn(),
|
|
9
|
+
}));
|
|
10
|
+
import * as core from "@mcpmesh/core";
|
|
11
|
+
import { clusterStrictEnabled, normalizeSchemaWithPolicy, shouldRefuseStartup, } from "../schema-normalize.js";
|
|
12
|
+
describe("shouldRefuseStartup", () => {
|
|
13
|
+
it("OK never refuses regardless of flags", () => {
|
|
14
|
+
expect(shouldRefuseStartup("OK", false, true)).toBe(false);
|
|
15
|
+
expect(shouldRefuseStartup("OK", true, true)).toBe(false);
|
|
16
|
+
expect(shouldRefuseStartup("OK", true, false)).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
it("BLOCK with default tool_strict refuses", () => {
|
|
19
|
+
expect(shouldRefuseStartup("BLOCK", false, true)).toBe(true);
|
|
20
|
+
});
|
|
21
|
+
it("BLOCK with per-tool override does not refuse", () => {
|
|
22
|
+
expect(shouldRefuseStartup("BLOCK", false, false)).toBe(false);
|
|
23
|
+
});
|
|
24
|
+
it("WARN with defaults does not refuse", () => {
|
|
25
|
+
expect(shouldRefuseStartup("WARN", false, true)).toBe(false);
|
|
26
|
+
});
|
|
27
|
+
it("WARN with cluster strict refuses", () => {
|
|
28
|
+
expect(shouldRefuseStartup("WARN", true, true)).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
it("per-tool override wins over cluster strict", () => {
|
|
31
|
+
expect(shouldRefuseStartup("BLOCK", true, false)).toBe(false);
|
|
32
|
+
expect(shouldRefuseStartup("WARN", true, false)).toBe(false);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
describe("clusterStrictEnabled", () => {
|
|
36
|
+
const originalEnv = process.env.MCP_MESH_SCHEMA_STRICT;
|
|
37
|
+
afterEach(() => {
|
|
38
|
+
if (originalEnv === undefined) {
|
|
39
|
+
delete process.env.MCP_MESH_SCHEMA_STRICT;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
process.env.MCP_MESH_SCHEMA_STRICT = originalEnv;
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
it.each(["1", "true", "TRUE", "True", "yes", "YES"])("truthy value %s -> true", (v) => {
|
|
46
|
+
process.env.MCP_MESH_SCHEMA_STRICT = v;
|
|
47
|
+
expect(clusterStrictEnabled()).toBe(true);
|
|
48
|
+
});
|
|
49
|
+
it.each(["", "0", "false", "no", "off", "anything-else"])("falsy value %s -> false", (v) => {
|
|
50
|
+
process.env.MCP_MESH_SCHEMA_STRICT = v;
|
|
51
|
+
expect(clusterStrictEnabled()).toBe(false);
|
|
52
|
+
});
|
|
53
|
+
it("unset -> false", () => {
|
|
54
|
+
delete process.env.MCP_MESH_SCHEMA_STRICT;
|
|
55
|
+
expect(clusterStrictEnabled()).toBe(false);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
describe("normalizeSchemaWithPolicy", () => {
|
|
59
|
+
const mockNormalize = core.normalizeSchema;
|
|
60
|
+
let warnSpy;
|
|
61
|
+
beforeEach(() => {
|
|
62
|
+
mockNormalize.mockReset();
|
|
63
|
+
warnSpy = vi.spyOn(console, "warn").mockImplementation(() => undefined);
|
|
64
|
+
});
|
|
65
|
+
afterEach(() => {
|
|
66
|
+
warnSpy.mockRestore();
|
|
67
|
+
});
|
|
68
|
+
it("OK passes through with canonical+hash", () => {
|
|
69
|
+
mockNormalize.mockReturnValue(JSON.stringify({
|
|
70
|
+
canonical: { type: "string" },
|
|
71
|
+
hash: "sha256:deadbeef",
|
|
72
|
+
verdict: "OK",
|
|
73
|
+
warnings: [],
|
|
74
|
+
}));
|
|
75
|
+
const r = normalizeSchemaWithPolicy({}, "ctx", false, true);
|
|
76
|
+
expect(r.verdict).toBe("OK");
|
|
77
|
+
expect(r.canonicalJson).toBe('{"type":"string"}');
|
|
78
|
+
expect(r.hash).toBe("sha256:deadbeef");
|
|
79
|
+
expect(r.warnings).toEqual([]);
|
|
80
|
+
});
|
|
81
|
+
it("BLOCK with toolStrict=true throws", () => {
|
|
82
|
+
mockNormalize.mockReturnValue(JSON.stringify({ verdict: "BLOCK", warnings: ["unsupported keyword"] }));
|
|
83
|
+
expect(() => normalizeSchemaWithPolicy({}, "ctx", false, true)).toThrow(/BLOCK for ctx.*unsupported keyword.*Cannot start agent/);
|
|
84
|
+
});
|
|
85
|
+
it("BLOCK with toolStrict=false does not throw, tags warnings", () => {
|
|
86
|
+
mockNormalize.mockReturnValue(JSON.stringify({
|
|
87
|
+
canonical: { type: "string" },
|
|
88
|
+
hash: "sha256:abc",
|
|
89
|
+
verdict: "BLOCK",
|
|
90
|
+
warnings: ["something bad"],
|
|
91
|
+
}));
|
|
92
|
+
const r = normalizeSchemaWithPolicy({}, "ctx", false, false);
|
|
93
|
+
expect(r.verdict).toBe("BLOCK");
|
|
94
|
+
expect(r.warnings).toEqual(["[demoted from BLOCK] something bad"]);
|
|
95
|
+
expect(r.canonicalJson).toBe('{"type":"string"}');
|
|
96
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
97
|
+
});
|
|
98
|
+
it("WARN with cluster strict + tool strict throws (promoted)", () => {
|
|
99
|
+
mockNormalize.mockReturnValue(JSON.stringify({ verdict: "WARN", warnings: ["soft issue"] }));
|
|
100
|
+
expect(() => normalizeSchemaWithPolicy({}, "ctx", true, true)).toThrow(/WARN for ctx \(MCP_MESH_SCHEMA_STRICT=true upgraded WARN.*soft issue/);
|
|
101
|
+
});
|
|
102
|
+
it("WARN with cluster strict + tool override does not throw", () => {
|
|
103
|
+
mockNormalize.mockReturnValue(JSON.stringify({
|
|
104
|
+
canonical: { type: "string" },
|
|
105
|
+
hash: "sha256:abc",
|
|
106
|
+
verdict: "WARN",
|
|
107
|
+
warnings: ["soft issue"],
|
|
108
|
+
}));
|
|
109
|
+
const r = normalizeSchemaWithPolicy({}, "ctx", true, false);
|
|
110
|
+
expect(r.verdict).toBe("WARN");
|
|
111
|
+
expect(r.warnings).toEqual(["soft issue"]);
|
|
112
|
+
});
|
|
113
|
+
it("WARN without cluster strict logs and continues", () => {
|
|
114
|
+
mockNormalize.mockReturnValue(JSON.stringify({
|
|
115
|
+
canonical: { type: "string" },
|
|
116
|
+
hash: "sha256:abc",
|
|
117
|
+
verdict: "WARN",
|
|
118
|
+
warnings: ["soft issue"],
|
|
119
|
+
}));
|
|
120
|
+
const r = normalizeSchemaWithPolicy({}, "ctx", false, true);
|
|
121
|
+
expect(r.verdict).toBe("WARN");
|
|
122
|
+
expect(r.warnings).toEqual(["soft issue"]);
|
|
123
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
//# sourceMappingURL=schema-verdict-policy.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-verdict-policy.test.js","sourceRoot":"","sources":["../../src/__tests__/schema-verdict-policy.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for sse-stream.ts (mesh.sseStream).
|
|
3
|
+
*
|
|
4
|
+
* Verifies the SSE wire format mirrors the Python ``mesh.route`` adapter:
|
|
5
|
+
* - ``data: <chunk>\n\n`` per item
|
|
6
|
+
* - ``data: [DONE]\n\n`` terminator on normal completion
|
|
7
|
+
* - ``event: error\ndata: <json>\n\n`` on per-chunk error
|
|
8
|
+
* - Standard headers (Content-Type, Cache-Control, Connection, X-Accel-Buffering)
|
|
9
|
+
* - Idempotent end()
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=sse-stream.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse-stream.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/sse-stream.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for sse-stream.ts (mesh.sseStream).
|
|
3
|
+
*
|
|
4
|
+
* Verifies the SSE wire format mirrors the Python ``mesh.route`` adapter:
|
|
5
|
+
* - ``data: <chunk>\n\n`` per item
|
|
6
|
+
* - ``data: [DONE]\n\n`` terminator on normal completion
|
|
7
|
+
* - ``event: error\ndata: <json>\n\n`` on per-chunk error
|
|
8
|
+
* - Standard headers (Content-Type, Cache-Control, Connection, X-Accel-Buffering)
|
|
9
|
+
* - Idempotent end()
|
|
10
|
+
*/
|
|
11
|
+
import { describe, it, expect, vi } from "vitest";
|
|
12
|
+
import { sseStream } from "../sse-stream.js";
|
|
13
|
+
function makeFakeRes() {
|
|
14
|
+
const res = {
|
|
15
|
+
headersSent: false,
|
|
16
|
+
writableEnded: false,
|
|
17
|
+
destroyed: false,
|
|
18
|
+
setHeader: vi.fn(),
|
|
19
|
+
write: vi.fn((data) => {
|
|
20
|
+
res._written.push(data);
|
|
21
|
+
return true;
|
|
22
|
+
}),
|
|
23
|
+
end: vi.fn(() => {
|
|
24
|
+
res.writableEnded = true;
|
|
25
|
+
}),
|
|
26
|
+
flushHeaders: vi.fn(() => {
|
|
27
|
+
res.headersSent = true;
|
|
28
|
+
}),
|
|
29
|
+
_written: [],
|
|
30
|
+
};
|
|
31
|
+
return res;
|
|
32
|
+
}
|
|
33
|
+
async function* asyncIter(items) {
|
|
34
|
+
for (const item of items) {
|
|
35
|
+
yield item;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
describe("sseStream", () => {
|
|
39
|
+
it("sets the standard SSE headers", async () => {
|
|
40
|
+
const res = makeFakeRes();
|
|
41
|
+
await sseStream(res, asyncIter(["a"]));
|
|
42
|
+
const setHeaderCalls = Object.fromEntries(res.setHeader.mock.calls.map((c) => [c[0], c[1]]));
|
|
43
|
+
expect(setHeaderCalls["Content-Type"]).toBe("text/event-stream");
|
|
44
|
+
expect(setHeaderCalls["Cache-Control"]).toBe("no-cache");
|
|
45
|
+
expect(setHeaderCalls["Connection"]).toBe("keep-alive");
|
|
46
|
+
expect(setHeaderCalls["X-Accel-Buffering"]).toBe("no");
|
|
47
|
+
expect(res.flushHeaders).toHaveBeenCalledTimes(1);
|
|
48
|
+
});
|
|
49
|
+
it("writes data: <chunk>\\n\\n per item then data: [DONE]\\n\\n and ends once", async () => {
|
|
50
|
+
const res = makeFakeRes();
|
|
51
|
+
await sseStream(res, asyncIter(["a", "b", "c"]));
|
|
52
|
+
expect(res._written).toEqual([
|
|
53
|
+
"data: a\n\n",
|
|
54
|
+
"data: b\n\n",
|
|
55
|
+
"data: c\n\n",
|
|
56
|
+
"data: [DONE]\n\n",
|
|
57
|
+
]);
|
|
58
|
+
expect(res.end).toHaveBeenCalledTimes(1);
|
|
59
|
+
});
|
|
60
|
+
it("does not double-end on already-completed response", async () => {
|
|
61
|
+
const res = makeFakeRes();
|
|
62
|
+
await sseStream(res, asyncIter([]));
|
|
63
|
+
// No items: should still write [DONE] and end exactly once
|
|
64
|
+
expect(res._written).toEqual(["data: [DONE]\n\n"]);
|
|
65
|
+
expect(res.end).toHaveBeenCalledTimes(1);
|
|
66
|
+
});
|
|
67
|
+
it("emits one data: line per newline in a multi-line chunk", async () => {
|
|
68
|
+
const res = makeFakeRes();
|
|
69
|
+
await sseStream(res, asyncIter(["line1\nline2\nline3"]));
|
|
70
|
+
// Per SSE spec, multi-line data is multiple data: prefixes inside one event
|
|
71
|
+
expect(res._written[0]).toBe("data: line1\ndata: line2\ndata: line3\n\n");
|
|
72
|
+
expect(res._written[1]).toBe("data: [DONE]\n\n");
|
|
73
|
+
expect(res.end).toHaveBeenCalledTimes(1);
|
|
74
|
+
});
|
|
75
|
+
it("emits a heartbeat-style empty data line for empty chunks", async () => {
|
|
76
|
+
const res = makeFakeRes();
|
|
77
|
+
await sseStream(res, asyncIter([""]));
|
|
78
|
+
expect(res._written[0]).toBe("data: \n\n");
|
|
79
|
+
expect(res._written[1]).toBe("data: [DONE]\n\n");
|
|
80
|
+
});
|
|
81
|
+
it("writes event: error on iterator throw and ends without sending [DONE]", async () => {
|
|
82
|
+
const res = makeFakeRes();
|
|
83
|
+
async function* throwing() {
|
|
84
|
+
yield "first";
|
|
85
|
+
throw new Error("upstream blew up");
|
|
86
|
+
}
|
|
87
|
+
await sseStream(res, throwing());
|
|
88
|
+
expect(res._written[0]).toBe("data: first\n\n");
|
|
89
|
+
// Last frame is the error; [DONE] should NOT have been sent
|
|
90
|
+
expect(res._written.at(-1)).toMatch(/^event: error\ndata: /);
|
|
91
|
+
const errFrame = res._written.at(-1);
|
|
92
|
+
const payloadJson = errFrame.replace(/^event: error\ndata: /, "").replace(/\n\n$/, "");
|
|
93
|
+
const payload = JSON.parse(payloadJson);
|
|
94
|
+
expect(payload.error).toBe("upstream blew up");
|
|
95
|
+
expect(payload.type).toBe("Error");
|
|
96
|
+
// No [DONE] anywhere
|
|
97
|
+
expect(res._written.some((s) => s === "data: [DONE]\n\n")).toBe(false);
|
|
98
|
+
expect(res.end).toHaveBeenCalledTimes(1);
|
|
99
|
+
});
|
|
100
|
+
it("writes event: error and stops on non-string chunks (TypeError)", async () => {
|
|
101
|
+
const res = makeFakeRes();
|
|
102
|
+
// Iterator yields a non-string — should be rejected with a structured error
|
|
103
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
104
|
+
async function* bad() {
|
|
105
|
+
yield "ok";
|
|
106
|
+
yield 42;
|
|
107
|
+
yield "never-reached";
|
|
108
|
+
}
|
|
109
|
+
await sseStream(res, bad());
|
|
110
|
+
expect(res._written[0]).toBe("data: ok\n\n");
|
|
111
|
+
expect(res._written[1]).toMatch(/^event: error\ndata: /);
|
|
112
|
+
const payloadJson = res._written[1].replace(/^event: error\ndata: /, "").replace(/\n\n$/, "");
|
|
113
|
+
const payload = JSON.parse(payloadJson);
|
|
114
|
+
expect(payload.type).toBe("TypeError");
|
|
115
|
+
expect(payload.error).toMatch(/expected string chunk/);
|
|
116
|
+
expect(res.end).toHaveBeenCalledTimes(1);
|
|
117
|
+
});
|
|
118
|
+
it("stops iterating and calls return() on consumer disconnect (write returns false)", async () => {
|
|
119
|
+
const res = makeFakeRes();
|
|
120
|
+
let returnCalled = false;
|
|
121
|
+
let yielded = 0;
|
|
122
|
+
const iter = {
|
|
123
|
+
[Symbol.asyncIterator]() {
|
|
124
|
+
return {
|
|
125
|
+
async next() {
|
|
126
|
+
yielded += 1;
|
|
127
|
+
if (yielded > 5)
|
|
128
|
+
return { value: undefined, done: true };
|
|
129
|
+
return { value: `chunk${yielded}`, done: false };
|
|
130
|
+
},
|
|
131
|
+
async return() {
|
|
132
|
+
returnCalled = true;
|
|
133
|
+
return { value: undefined, done: true };
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
// After first write, simulate disconnect
|
|
139
|
+
res.write = vi.fn(() => {
|
|
140
|
+
res._written.push("first-write");
|
|
141
|
+
res.writableEnded = true; // Simulate consumer disconnect
|
|
142
|
+
return false;
|
|
143
|
+
});
|
|
144
|
+
await sseStream(res, iter);
|
|
145
|
+
expect(returnCalled).toBe(true);
|
|
146
|
+
// Only one chunk was attempted, then disconnect detected
|
|
147
|
+
expect(yielded).toBe(1);
|
|
148
|
+
// [DONE] was NOT written
|
|
149
|
+
expect(res._written).not.toContain("data: [DONE]\n\n");
|
|
150
|
+
});
|
|
151
|
+
it("does not set headers if headersSent is already true", async () => {
|
|
152
|
+
const res = makeFakeRes();
|
|
153
|
+
res.headersSent = true;
|
|
154
|
+
await sseStream(res, asyncIter(["a"]));
|
|
155
|
+
expect(res.setHeader).not.toHaveBeenCalled();
|
|
156
|
+
expect(res.flushHeaders).not.toHaveBeenCalled();
|
|
157
|
+
// Still writes data + [DONE]
|
|
158
|
+
expect(res._written).toEqual(["data: a\n\n", "data: [DONE]\n\n"]);
|
|
159
|
+
});
|
|
160
|
+
it("handles synchronous res.write throwing without crashing", async () => {
|
|
161
|
+
const res = makeFakeRes();
|
|
162
|
+
res.write = vi.fn(() => {
|
|
163
|
+
throw new Error("socket closed");
|
|
164
|
+
});
|
|
165
|
+
// Should not throw out of sseStream — it swallows write errors and ends
|
|
166
|
+
await expect(sseStream(res, asyncIter(["a", "b"]))).resolves.toBeUndefined();
|
|
167
|
+
expect(res.end).toHaveBeenCalledTimes(1);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
//# sourceMappingURL=sse-stream.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse-stream.test.js","sourceRoot":"","sources":["../../src/__tests__/sse-stream.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface A2ABearerConfig {
|
|
2
|
+
/** Literal bearer token. Mutually exclusive with `tokenEnv`. */
|
|
3
|
+
token?: string;
|
|
4
|
+
/** Env-var name to read the token from on each call. Mutually exclusive with `token`. */
|
|
5
|
+
tokenEnv?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare class A2ABearer {
|
|
8
|
+
private readonly token?;
|
|
9
|
+
private readonly tokenEnv?;
|
|
10
|
+
constructor(config: A2ABearerConfig);
|
|
11
|
+
/**
|
|
12
|
+
* Build the value for the `Authorization` header at call time.
|
|
13
|
+
*
|
|
14
|
+
* Reads the env var (when configured) on every call so a rotated
|
|
15
|
+
* credential is honoured mid-process.
|
|
16
|
+
*/
|
|
17
|
+
authorizationHeader(): string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Helper: normalise the user-friendly union (`A2ABearer | A2ABearerConfig`)
|
|
21
|
+
* into a concrete `A2ABearer` instance, or `undefined` for "no auth".
|
|
22
|
+
*
|
|
23
|
+
* Lets the consumer-side `addTool({ a2aConfig: { auth: { tokenEnv: "X" } } })`
|
|
24
|
+
* shortcut work without forcing the user to `new A2ABearer(...)` every time.
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveBearer(auth: A2ABearer | A2ABearerConfig | undefined): A2ABearer | undefined;
|
|
27
|
+
//# sourceMappingURL=a2a-bearer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a2a-bearer.d.ts","sourceRoot":"","sources":["../../src/a2a/a2a-bearer.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,eAAe;IAC9B,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yFAAyF;IACzF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAS;gBAEvB,MAAM,EAAE,eAAe;IAqBnC;;;;;OAKG;IACH,mBAAmB,IAAI,MAAM;CAa9B;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,SAAS,GAAG,eAAe,GAAG,SAAS,GAC5C,SAAS,GAAG,SAAS,CAIvB"}
|