@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.
Files changed (262) hide show
  1. package/dist/__tests__/a2a/a2a-bearer.spec.d.ts +2 -0
  2. package/dist/__tests__/a2a/a2a-bearer.spec.d.ts.map +1 -0
  3. package/dist/__tests__/a2a/a2a-bearer.spec.js +58 -0
  4. package/dist/__tests__/a2a/a2a-bearer.spec.js.map +1 -0
  5. package/dist/__tests__/a2a/a2a-client.spec.d.ts +2 -0
  6. package/dist/__tests__/a2a/a2a-client.spec.d.ts.map +1 -0
  7. package/dist/__tests__/a2a/a2a-client.spec.js +334 -0
  8. package/dist/__tests__/a2a/a2a-client.spec.js.map +1 -0
  9. package/dist/__tests__/a2a/a2a-job.spec.d.ts +2 -0
  10. package/dist/__tests__/a2a/a2a-job.spec.d.ts.map +1 -0
  11. package/dist/__tests__/a2a/a2a-job.spec.js +255 -0
  12. package/dist/__tests__/a2a/a2a-job.spec.js.map +1 -0
  13. package/dist/__tests__/a2a/a2a-stream.spec.d.ts +2 -0
  14. package/dist/__tests__/a2a/a2a-stream.spec.d.ts.map +1 -0
  15. package/dist/__tests__/a2a/a2a-stream.spec.js +278 -0
  16. package/dist/__tests__/a2a/a2a-stream.spec.js.map +1 -0
  17. package/dist/__tests__/a2a/agent-a2a-config.spec.d.ts +2 -0
  18. package/dist/__tests__/a2a/agent-a2a-config.spec.d.ts.map +1 -0
  19. package/dist/__tests__/a2a/agent-a2a-config.spec.js +262 -0
  20. package/dist/__tests__/a2a/agent-a2a-config.spec.js.map +1 -0
  21. package/dist/__tests__/a2a/producer/auth-filter.spec.d.ts +2 -0
  22. package/dist/__tests__/a2a/producer/auth-filter.spec.d.ts.map +1 -0
  23. package/dist/__tests__/a2a/producer/auth-filter.spec.js +127 -0
  24. package/dist/__tests__/a2a/producer/auth-filter.spec.js.map +1 -0
  25. package/dist/__tests__/a2a/producer/card-builder.spec.d.ts +2 -0
  26. package/dist/__tests__/a2a/producer/card-builder.spec.d.ts.map +1 -0
  27. package/dist/__tests__/a2a/producer/card-builder.spec.js +113 -0
  28. package/dist/__tests__/a2a/producer/card-builder.spec.js.map +1 -0
  29. package/dist/__tests__/a2a/producer/dispatcher.spec.d.ts +2 -0
  30. package/dist/__tests__/a2a/producer/dispatcher.spec.d.ts.map +1 -0
  31. package/dist/__tests__/a2a/producer/dispatcher.spec.js +850 -0
  32. package/dist/__tests__/a2a/producer/dispatcher.spec.js.map +1 -0
  33. package/dist/__tests__/a2a/producer/mount-surface-push.spec.d.ts +2 -0
  34. package/dist/__tests__/a2a/producer/mount-surface-push.spec.d.ts.map +1 -0
  35. package/dist/__tests__/a2a/producer/mount-surface-push.spec.js +164 -0
  36. package/dist/__tests__/a2a/producer/mount-surface-push.spec.js.map +1 -0
  37. package/dist/__tests__/a2a/producer/mount.spec.d.ts +2 -0
  38. package/dist/__tests__/a2a/producer/mount.spec.d.ts.map +1 -0
  39. package/dist/__tests__/a2a/producer/mount.spec.js +433 -0
  40. package/dist/__tests__/a2a/producer/mount.spec.js.map +1 -0
  41. package/dist/__tests__/a2a/producer/public-url-cache.spec.d.ts +2 -0
  42. package/dist/__tests__/a2a/producer/public-url-cache.spec.d.ts.map +1 -0
  43. package/dist/__tests__/a2a/producer/public-url-cache.spec.js +116 -0
  44. package/dist/__tests__/a2a/producer/public-url-cache.spec.js.map +1 -0
  45. package/dist/__tests__/a2a/producer/sse-emitter.spec.d.ts +2 -0
  46. package/dist/__tests__/a2a/producer/sse-emitter.spec.d.ts.map +1 -0
  47. package/dist/__tests__/a2a/producer/sse-emitter.spec.js +754 -0
  48. package/dist/__tests__/a2a/producer/sse-emitter.spec.js.map +1 -0
  49. package/dist/__tests__/a2a/producer/state-translator.spec.d.ts +2 -0
  50. package/dist/__tests__/a2a/producer/state-translator.spec.d.ts.map +1 -0
  51. package/dist/__tests__/a2a/producer/state-translator.spec.js +124 -0
  52. package/dist/__tests__/a2a/producer/state-translator.spec.js.map +1 -0
  53. package/dist/__tests__/a2a/producer/task-store.spec.d.ts +2 -0
  54. package/dist/__tests__/a2a/producer/task-store.spec.d.ts.map +1 -0
  55. package/dist/__tests__/a2a/producer/task-store.spec.js +180 -0
  56. package/dist/__tests__/a2a/producer/task-store.spec.js.map +1 -0
  57. package/dist/__tests__/agent-add-tool.spec.d.ts +2 -0
  58. package/dist/__tests__/agent-add-tool.spec.d.ts.map +1 -0
  59. package/dist/__tests__/agent-add-tool.spec.js +483 -0
  60. package/dist/__tests__/agent-add-tool.spec.js.map +1 -0
  61. package/dist/__tests__/api-runtime-race.spec.d.ts +2 -0
  62. package/dist/__tests__/api-runtime-race.spec.d.ts.map +1 -0
  63. package/dist/__tests__/api-runtime-race.spec.js +193 -0
  64. package/dist/__tests__/api-runtime-race.spec.js.map +1 -0
  65. package/dist/__tests__/claim-dispatcher.spec.d.ts +2 -0
  66. package/dist/__tests__/claim-dispatcher.spec.d.ts.map +1 -0
  67. package/dist/__tests__/claim-dispatcher.spec.js +408 -0
  68. package/dist/__tests__/claim-dispatcher.spec.js.map +1 -0
  69. package/dist/__tests__/inbound-job-dispatch.spec.d.ts +2 -0
  70. package/dist/__tests__/inbound-job-dispatch.spec.d.ts.map +1 -0
  71. package/dist/__tests__/inbound-job-dispatch.spec.js +185 -0
  72. package/dist/__tests__/inbound-job-dispatch.spec.js.map +1 -0
  73. package/dist/__tests__/job-controller-progress.spec.d.ts +2 -0
  74. package/dist/__tests__/job-controller-progress.spec.d.ts.map +1 -0
  75. package/dist/__tests__/job-controller-progress.spec.js +85 -0
  76. package/dist/__tests__/job-controller-progress.spec.js.map +1 -0
  77. package/dist/__tests__/jobs-cancel-route.spec.d.ts +2 -0
  78. package/dist/__tests__/jobs-cancel-route.spec.d.ts.map +1 -0
  79. package/dist/__tests__/jobs-cancel-route.spec.js +88 -0
  80. package/dist/__tests__/jobs-cancel-route.spec.js.map +1 -0
  81. package/dist/__tests__/llm-agent-stream.test.d.ts +14 -0
  82. package/dist/__tests__/llm-agent-stream.test.d.ts.map +1 -0
  83. package/dist/__tests__/llm-agent-stream.test.js +341 -0
  84. package/dist/__tests__/llm-agent-stream.test.js.map +1 -0
  85. package/dist/__tests__/llm-provider.test.js +22 -1
  86. package/dist/__tests__/llm-provider.test.js.map +1 -1
  87. package/dist/__tests__/media-resolver.test.js +40 -0
  88. package/dist/__tests__/media-resolver.test.js.map +1 -1
  89. package/dist/__tests__/mesh-job-submitter.spec.d.ts +2 -0
  90. package/dist/__tests__/mesh-job-submitter.spec.d.ts.map +1 -0
  91. package/dist/__tests__/mesh-job-submitter.spec.js +110 -0
  92. package/dist/__tests__/mesh-job-submitter.spec.js.map +1 -0
  93. package/dist/__tests__/proxy-stream.test.d.ts +9 -0
  94. package/dist/__tests__/proxy-stream.test.d.ts.map +1 -0
  95. package/dist/__tests__/proxy-stream.test.js +347 -0
  96. package/dist/__tests__/proxy-stream.test.js.map +1 -0
  97. package/dist/__tests__/resolver-meshjob.spec.d.ts +26 -0
  98. package/dist/__tests__/resolver-meshjob.spec.d.ts.map +1 -0
  99. package/dist/__tests__/resolver-meshjob.spec.js +201 -0
  100. package/dist/__tests__/resolver-meshjob.spec.js.map +1 -0
  101. package/dist/__tests__/schema-verdict-policy.test.d.ts +6 -0
  102. package/dist/__tests__/schema-verdict-policy.test.d.ts.map +1 -0
  103. package/dist/__tests__/schema-verdict-policy.test.js +126 -0
  104. package/dist/__tests__/schema-verdict-policy.test.js.map +1 -0
  105. package/dist/__tests__/sse-stream.test.d.ts +12 -0
  106. package/dist/__tests__/sse-stream.test.d.ts.map +1 -0
  107. package/dist/__tests__/sse-stream.test.js +170 -0
  108. package/dist/__tests__/sse-stream.test.js.map +1 -0
  109. package/dist/a2a/a2a-bearer.d.ts +27 -0
  110. package/dist/a2a/a2a-bearer.d.ts.map +1 -0
  111. package/dist/a2a/a2a-bearer.js +63 -0
  112. package/dist/a2a/a2a-bearer.js.map +1 -0
  113. package/dist/a2a/a2a-client.d.ts +114 -0
  114. package/dist/a2a/a2a-client.d.ts.map +1 -0
  115. package/dist/a2a/a2a-client.js +405 -0
  116. package/dist/a2a/a2a-client.js.map +1 -0
  117. package/dist/a2a/a2a-event.d.ts +25 -0
  118. package/dist/a2a/a2a-event.d.ts.map +1 -0
  119. package/dist/a2a/a2a-event.js +9 -0
  120. package/dist/a2a/a2a-event.js.map +1 -0
  121. package/dist/a2a/a2a-job.d.ts +58 -0
  122. package/dist/a2a/a2a-job.d.ts.map +1 -0
  123. package/dist/a2a/a2a-job.js +264 -0
  124. package/dist/a2a/a2a-job.js.map +1 -0
  125. package/dist/a2a/a2a-stream.d.ts +39 -0
  126. package/dist/a2a/a2a-stream.d.ts.map +1 -0
  127. package/dist/a2a/a2a-stream.js +290 -0
  128. package/dist/a2a/a2a-stream.js.map +1 -0
  129. package/dist/a2a/errors.d.ts +29 -0
  130. package/dist/a2a/errors.d.ts.map +1 -0
  131. package/dist/a2a/errors.js +48 -0
  132. package/dist/a2a/errors.js.map +1 -0
  133. package/dist/a2a/index.d.ts +12 -0
  134. package/dist/a2a/index.d.ts.map +1 -0
  135. package/dist/a2a/index.js +11 -0
  136. package/dist/a2a/index.js.map +1 -0
  137. package/dist/a2a/producer/auth-filter.d.ts +34 -0
  138. package/dist/a2a/producer/auth-filter.d.ts.map +1 -0
  139. package/dist/a2a/producer/auth-filter.js +39 -0
  140. package/dist/a2a/producer/auth-filter.js.map +1 -0
  141. package/dist/a2a/producer/card-builder.d.ts +59 -0
  142. package/dist/a2a/producer/card-builder.d.ts.map +1 -0
  143. package/dist/a2a/producer/card-builder.js +59 -0
  144. package/dist/a2a/producer/card-builder.js.map +1 -0
  145. package/dist/a2a/producer/dispatcher.d.ts +276 -0
  146. package/dist/a2a/producer/dispatcher.d.ts.map +1 -0
  147. package/dist/a2a/producer/dispatcher.js +896 -0
  148. package/dist/a2a/producer/dispatcher.js.map +1 -0
  149. package/dist/a2a/producer/index.d.ts +26 -0
  150. package/dist/a2a/producer/index.d.ts.map +1 -0
  151. package/dist/a2a/producer/index.js +23 -0
  152. package/dist/a2a/producer/index.js.map +1 -0
  153. package/dist/a2a/producer/mount.d.ts +75 -0
  154. package/dist/a2a/producer/mount.d.ts.map +1 -0
  155. package/dist/a2a/producer/mount.js +422 -0
  156. package/dist/a2a/producer/mount.js.map +1 -0
  157. package/dist/a2a/producer/public-url-cache.d.ts +73 -0
  158. package/dist/a2a/producer/public-url-cache.d.ts.map +1 -0
  159. package/dist/a2a/producer/public-url-cache.js +0 -0
  160. package/dist/a2a/producer/public-url-cache.js.map +1 -0
  161. package/dist/a2a/producer/registry.d.ts +138 -0
  162. package/dist/a2a/producer/registry.d.ts.map +1 -0
  163. package/dist/a2a/producer/registry.js +117 -0
  164. package/dist/a2a/producer/registry.js.map +1 -0
  165. package/dist/a2a/producer/sse-emitter.d.ts +85 -0
  166. package/dist/a2a/producer/sse-emitter.d.ts.map +1 -0
  167. package/dist/a2a/producer/sse-emitter.js +405 -0
  168. package/dist/a2a/producer/sse-emitter.js.map +1 -0
  169. package/dist/a2a/producer/state-translator.d.ts +63 -0
  170. package/dist/a2a/producer/state-translator.d.ts.map +1 -0
  171. package/dist/a2a/producer/state-translator.js +108 -0
  172. package/dist/a2a/producer/state-translator.js.map +1 -0
  173. package/dist/a2a/producer/task-store.d.ts +128 -0
  174. package/dist/a2a/producer/task-store.d.ts.map +1 -0
  175. package/dist/a2a/producer/task-store.js +128 -0
  176. package/dist/a2a/producer/task-store.js.map +1 -0
  177. package/dist/agent.d.ts +99 -0
  178. package/dist/agent.d.ts.map +1 -1
  179. package/dist/agent.js +754 -19
  180. package/dist/agent.js.map +1 -1
  181. package/dist/api-runtime.d.ts +25 -0
  182. package/dist/api-runtime.d.ts.map +1 -1
  183. package/dist/api-runtime.js +75 -2
  184. package/dist/api-runtime.js.map +1 -1
  185. package/dist/claim-dispatcher.d.ts +126 -0
  186. package/dist/claim-dispatcher.d.ts.map +1 -0
  187. package/dist/claim-dispatcher.js +478 -0
  188. package/dist/claim-dispatcher.js.map +1 -0
  189. package/dist/express.d.ts.map +1 -1
  190. package/dist/express.js +33 -6
  191. package/dist/express.js.map +1 -1
  192. package/dist/inbound-job-dispatch.d.ts +105 -0
  193. package/dist/inbound-job-dispatch.d.ts.map +1 -0
  194. package/dist/inbound-job-dispatch.js +335 -0
  195. package/dist/inbound-job-dispatch.js.map +1 -0
  196. package/dist/index.d.ts +40 -4
  197. package/dist/index.d.ts.map +1 -1
  198. package/dist/index.js +40 -3
  199. package/dist/index.js.map +1 -1
  200. package/dist/job-context.d.ts +107 -0
  201. package/dist/job-context.d.ts.map +1 -0
  202. package/dist/job-context.js +95 -0
  203. package/dist/job-context.js.map +1 -0
  204. package/dist/jobs-cancel-route.d.ts +36 -0
  205. package/dist/jobs-cancel-route.d.ts.map +1 -0
  206. package/dist/jobs-cancel-route.js +60 -0
  207. package/dist/jobs-cancel-route.js.map +1 -0
  208. package/dist/jobs-helper-tools.d.ts +48 -0
  209. package/dist/jobs-helper-tools.d.ts.map +1 -0
  210. package/dist/jobs-helper-tools.js +133 -0
  211. package/dist/jobs-helper-tools.js.map +1 -0
  212. package/dist/llm-agent.d.ts +62 -53
  213. package/dist/llm-agent.d.ts.map +1 -1
  214. package/dist/llm-agent.js +211 -292
  215. package/dist/llm-agent.js.map +1 -1
  216. package/dist/llm-provider.d.ts +11 -4
  217. package/dist/llm-provider.d.ts.map +1 -1
  218. package/dist/llm-provider.js +57 -4
  219. package/dist/llm-provider.js.map +1 -1
  220. package/dist/llm.d.ts +4 -1
  221. package/dist/llm.d.ts.map +1 -1
  222. package/dist/llm.js +7 -17
  223. package/dist/llm.js.map +1 -1
  224. package/dist/media/resolver.d.ts.map +1 -1
  225. package/dist/media/resolver.js +3 -2
  226. package/dist/media/resolver.js.map +1 -1
  227. package/dist/mesh-job-submitter.d.ts +83 -0
  228. package/dist/mesh-job-submitter.d.ts.map +1 -0
  229. package/dist/mesh-job-submitter.js +143 -0
  230. package/dist/mesh-job-submitter.js.map +1 -0
  231. package/dist/provider-handlers/gemini-handler.js +5 -0
  232. package/dist/provider-handlers/gemini-handler.js.map +1 -1
  233. package/dist/proxy.d.ts +40 -0
  234. package/dist/proxy.d.ts.map +1 -1
  235. package/dist/proxy.js +375 -2
  236. package/dist/proxy.js.map +1 -1
  237. package/dist/resolver-meshjob.d.ts +170 -0
  238. package/dist/resolver-meshjob.d.ts.map +1 -0
  239. package/dist/resolver-meshjob.js +159 -0
  240. package/dist/resolver-meshjob.js.map +1 -0
  241. package/dist/route.d.ts +4 -0
  242. package/dist/route.d.ts.map +1 -1
  243. package/dist/route.js.map +1 -1
  244. package/dist/schema-normalize.d.ts +62 -0
  245. package/dist/schema-normalize.d.ts.map +1 -0
  246. package/dist/schema-normalize.js +128 -0
  247. package/dist/schema-normalize.js.map +1 -0
  248. package/dist/sse-stream.d.ts +44 -0
  249. package/dist/sse-stream.d.ts.map +1 -0
  250. package/dist/sse-stream.js +173 -0
  251. package/dist/sse-stream.js.map +1 -0
  252. package/dist/tool-worker-entry.d.ts +21 -0
  253. package/dist/tool-worker-entry.d.ts.map +1 -0
  254. package/dist/tool-worker-entry.js +162 -0
  255. package/dist/tool-worker-entry.js.map +1 -0
  256. package/dist/tool-worker-pool.d.ts +49 -0
  257. package/dist/tool-worker-pool.d.ts.map +1 -0
  258. package/dist/tool-worker-pool.js +272 -0
  259. package/dist/tool-worker-pool.js.map +1 -0
  260. package/dist/types.d.ts +351 -9
  261. package/dist/types.d.ts.map +1 -1
  262. package/package.json +5 -3
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Regression test for PR #938 W2 — race window in `ApiRuntime.start()`.
3
+ *
4
+ * `start()` does async work (TLS prep, tracing init) between the moment
5
+ * `scheduleStart()` flips `this.starting = true` and the moment
6
+ * `this.handle = startAgent(spec)` lands. A `mesh.a2a.mount(...)` fired
7
+ * during that gap was previously dropped on the floor:
8
+ *
9
+ * - `pushSurfacesUpdate()` early-returned on `!this.handle`
10
+ * - The startup-time spec was already built (snapshot of the registry
11
+ * BEFORE the deferred mount landed), so `startAgent(spec)` registered
12
+ * a stale surfaces[] payload
13
+ *
14
+ * The fix: `pushSurfacesUpdate()` sets a `pendingSurfacesPush` flag when
15
+ * `start()` is in flight (handle still null, `starting === true`).
16
+ * `start()` flushes the flag right after `this.handle = startAgent(spec)`.
17
+ * Smart-diffed inside the Rust runtime so the redundant push is a no-op
18
+ * when the snapshot already captured the mount.
19
+ *
20
+ * We mock `@mcpmesh/core` so this test never binds the real napi runtime,
21
+ * and we mock `prepareTls`/`initTracing` so `start()` doesn't touch the
22
+ * filesystem or Redis. The race fixture introduces a controlled
23
+ * `setImmediate` gap inside the mocked `initTracing` so we can fire
24
+ * `pushSurfacesUpdate()` at the exact race window.
25
+ */
26
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
27
+ // ─── Mock @mcpmesh/core BEFORE importing api-runtime ────────────────────
28
+ const updateSurfacesSpy = vi.fn().mockResolvedValue(true);
29
+ const startAgentSpy = vi.fn();
30
+ const nextEventBlocker = new Promise(() => { }); // never resolves
31
+ vi.mock("@mcpmesh/core", async (importOriginal) => {
32
+ const actual = await importOriginal();
33
+ return {
34
+ ...actual,
35
+ startAgent: (spec) => startAgentSpy(spec),
36
+ autoDetectIp: () => "127.0.0.1",
37
+ resolveConfig: (key, fallback) => {
38
+ // Minimal config resolution — return fallback or null for everything
39
+ // so `start()` proceeds with defaults.
40
+ if (key === "agent_name")
41
+ return "test-api";
42
+ return fallback ?? null;
43
+ },
44
+ resolveConfigInt: (_key, fallback) => fallback ?? null,
45
+ };
46
+ });
47
+ // Mock tls-config so prepareTls/cleanupTls don't touch the filesystem.
48
+ vi.mock("../tls-config.js", () => ({
49
+ getTlsConfigCached: () => ({ enabled: false }),
50
+ prepareTls: vi.fn(),
51
+ cleanupTls: vi.fn(),
52
+ }));
53
+ // Mock tracing so initTracing doesn't try to bind Redis. Crucially, we
54
+ // inject a `setImmediate` boundary INSIDE initTracing so the test can
55
+ // schedule a `pushSurfacesUpdate()` call at the precise race window —
56
+ // after `scheduleStart` flips `this.starting = true` but before
57
+ // `this.handle = startAgent(spec)` runs.
58
+ let initTracingResolve = null;
59
+ vi.mock("../tracing.js", () => ({
60
+ initTracing: vi.fn(async () => {
61
+ // Park here — the test resolves us once it has fired the racing
62
+ // `pushSurfacesUpdate()`. This deterministically holds the gap
63
+ // open instead of relying on real-world async timing.
64
+ await new Promise((resolve) => {
65
+ initTracingResolve = resolve;
66
+ });
67
+ }),
68
+ }));
69
+ import { ApiRuntime } from "../api-runtime.js";
70
+ import { A2AProducerRegistry } from "../a2a/producer/registry.js";
71
+ import { RouteRegistry } from "../route.js";
72
+ describe("ApiRuntime — pushSurfacesUpdate race window (#938 W2)", () => {
73
+ let sigintBefore;
74
+ let sigtermBefore;
75
+ beforeEach(() => {
76
+ sigintBefore = process.listeners("SIGINT");
77
+ sigintBefore = [...sigintBefore];
78
+ sigtermBefore = process.listeners("SIGTERM");
79
+ sigtermBefore = [...sigtermBefore];
80
+ A2AProducerRegistry.reset();
81
+ RouteRegistry.reset();
82
+ updateSurfacesSpy.mockClear();
83
+ startAgentSpy.mockReset();
84
+ initTracingResolve = null;
85
+ // Build a stub handle that captures updateSurfaces calls. nextEvent
86
+ // returns a never-resolving promise so the event loop parks
87
+ // immediately — we don't exercise it here.
88
+ startAgentSpy.mockImplementation(() => ({
89
+ updateSurfaces: updateSurfacesSpy,
90
+ updatePort: vi.fn().mockResolvedValue(true),
91
+ updateTools: vi.fn().mockResolvedValue(true),
92
+ nextEvent: () => nextEventBlocker,
93
+ shutdown: vi.fn().mockResolvedValue(undefined),
94
+ isShutdownRequested: () => false,
95
+ }));
96
+ // Reset the singleton so each test gets a clean ApiRuntime.
97
+ ApiRuntime.reset();
98
+ });
99
+ afterEach(() => {
100
+ // Unblock any parked initTracing in case a test bailed early.
101
+ if (initTracingResolve) {
102
+ initTracingResolve();
103
+ }
104
+ ApiRuntime.reset();
105
+ // Strip signal listeners we registered (see snapshot in beforeEach).
106
+ const currentSigint = process.listeners("SIGINT");
107
+ for (const l of currentSigint) {
108
+ if (!sigintBefore.includes(l)) {
109
+ process.removeListener("SIGINT", l);
110
+ }
111
+ }
112
+ const currentSigterm = process.listeners("SIGTERM");
113
+ for (const l of currentSigterm) {
114
+ if (!sigtermBefore.includes(l)) {
115
+ process.removeListener("SIGTERM", l);
116
+ }
117
+ }
118
+ });
119
+ it("flushes a pushSurfacesUpdate fired during the start() async gap", async () => {
120
+ const runtime = ApiRuntime.getInstance();
121
+ // Kick off start(). It will park inside the mocked initTracing,
122
+ // holding the race window open until we resolve `initTracingResolve`.
123
+ const startPromise = runtime.start();
124
+ // Yield the event loop so start() advances past `this.starting = true`
125
+ // and into the `await initTracing(...)` await point.
126
+ await new Promise((r) => setImmediate(r));
127
+ // Sanity: handle still null (start is parked inside initTracing),
128
+ // and startAgent has NOT been called yet.
129
+ expect(startAgentSpy).not.toHaveBeenCalled();
130
+ // Simulate a deferred mount landing in the race window — register
131
+ // a surface in the producer registry, then fire pushSurfacesUpdate.
132
+ A2AProducerRegistry.getInstance().register({
133
+ path: "/agents/late",
134
+ skillId: "late-skill",
135
+ skillName: "Late Skill",
136
+ description: "",
137
+ tags: [],
138
+ dependencies: [],
139
+ auth: "",
140
+ routeId: "route-late",
141
+ });
142
+ runtime.pushSurfacesUpdate();
143
+ // Without the W2 fix, this push is silently dropped:
144
+ // - `handle === null` so the early-return triggers
145
+ // - `pendingSurfacesPush` doesn't exist, so no flush
146
+ //
147
+ // With the fix, the push is queued via `pendingSurfacesPush = true`
148
+ // and replayed after `this.handle = startAgent(spec)` is set.
149
+ // Unblock initTracing so start() proceeds to startAgent + flush.
150
+ initTracingResolve();
151
+ initTracingResolve = null;
152
+ await startPromise;
153
+ // The startup-time snapshot would have included the late-mounted
154
+ // surface (it landed BEFORE startAgent was called in our fixture
155
+ // here — the gap is between scheduleStart and startAgent). So the
156
+ // initial startAgent call already advertises the late surface AND
157
+ // the W2 flush replays it (smart-diffed by the Rust runtime).
158
+ //
159
+ // The behavior we assert is the FLUSH — `updateSurfaces` is called
160
+ // exactly once after the handle is set, with the late surface in
161
+ // the payload.
162
+ expect(updateSurfacesSpy).toHaveBeenCalledTimes(1);
163
+ const [agentType, surfacesJson] = updateSurfacesSpy.mock.calls[0];
164
+ expect(agentType).toBe("a2a");
165
+ const parsed = JSON.parse(surfacesJson);
166
+ expect(parsed).toHaveLength(1);
167
+ expect(parsed[0]).toMatchObject({
168
+ path: "/agents/late",
169
+ skill_id: "late-skill",
170
+ });
171
+ });
172
+ it("does NOT flush when no pushSurfacesUpdate fired during the gap", async () => {
173
+ const runtime = ApiRuntime.getInstance();
174
+ const startPromise = runtime.start();
175
+ await new Promise((r) => setImmediate(r));
176
+ // No racing push — just let start() complete.
177
+ initTracingResolve();
178
+ initTracingResolve = null;
179
+ await startPromise;
180
+ // `pendingSurfacesPush` stayed false, so no flush after handle is set.
181
+ expect(updateSurfacesSpy).not.toHaveBeenCalled();
182
+ });
183
+ it("is a no-op when called BEFORE scheduleStart (starting=false, handle=null)", () => {
184
+ const runtime = ApiRuntime.getInstance();
185
+ // Cold runtime — neither started nor starting. Push is a true no-op:
186
+ // the eventual `start()` will pick up the registry state via
187
+ // `buildAgentSpecContribution()` at startup time.
188
+ runtime.pushSurfacesUpdate();
189
+ expect(updateSurfacesSpy).not.toHaveBeenCalled();
190
+ expect(startAgentSpy).not.toHaveBeenCalled();
191
+ });
192
+ });
193
+ //# sourceMappingURL=api-runtime-race.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-runtime-race.spec.js","sourceRoot":"","sources":["../../src/__tests__/api-runtime-race.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=claim-dispatcher.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claim-dispatcher.spec.d.ts","sourceRoot":"","sources":["../../src/__tests__/claim-dispatcher.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,408 @@
1
+ /**
2
+ * Tests for ClaimDispatcher (Phase 1 — MeshJob substrate).
3
+ *
4
+ * The dispatcher polls `POST /jobs/claim` periodically and dispatches
5
+ * claimed work via the local handler. Heavy on side effects, so tests
6
+ * use a stubbed `fetch` and a minimal handler — we exercise:
7
+ *
8
+ * - Empty-claim behaviour (HTTP 204 → backoff, no handler call).
9
+ * - Successful claim → handler invoked with payload, controller
10
+ * constructed via napi.
11
+ * - The claim-then-acquire ordering: even with an immediate claim,
12
+ * the dispatcher must hold a permit before issuing the POST so
13
+ * it never owns more jobs than it can run.
14
+ * - Stop semantics: a long-running handler doesn't block stop().
15
+ *
16
+ * The napi `JobController` constructor is real — it doesn't reach out
17
+ * to the registry until `complete()`/`updateProgress()` is called, so
18
+ * the test stays in-process.
19
+ */
20
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
21
+ import { ClaimDispatcher } from "../claim-dispatcher.js";
22
+ import { getCurrentPropagatedHeaders } from "../proxy.js";
23
+ import * as inboundDispatch from "../inbound-job-dispatch.js";
24
+ // Mock @mcpmesh/core so the real JobController/withJobAsync don't
25
+ // actually try to reach the registry. The dispatcher uses `fetch`
26
+ // directly for /jobs/claim (mocked separately below).
27
+ vi.mock("@mcpmesh/core", async () => {
28
+ const actual = await vi.importActual("@mcpmesh/core");
29
+ return {
30
+ ...actual,
31
+ // The dispatcher constructs JobController via makeJobController
32
+ // (which calls `new JobController(...)`). Replace with a stub so
33
+ // the constructor doesn't spawn the per-controller batching tick
34
+ // (which would keep the test process alive past the test).
35
+ JobController: class {
36
+ jobId;
37
+ constructor(jobId, _instanceId, _registryUrl) {
38
+ this.jobId = jobId;
39
+ }
40
+ isTerminal = vi.fn().mockResolvedValue(true);
41
+ complete = vi.fn().mockResolvedValue(undefined);
42
+ fail = vi.fn().mockResolvedValue(undefined);
43
+ updateProgress = vi.fn().mockResolvedValue(undefined);
44
+ },
45
+ // withJobAsync just runs the body without binding the Rust
46
+ // task-local — fine for a test.
47
+ withJobAsync: vi.fn(async (_jobId, _deadline, body) => body),
48
+ };
49
+ });
50
+ const originalFetch = globalThis.fetch;
51
+ describe("ClaimDispatcher", () => {
52
+ beforeEach(() => {
53
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
54
+ globalThis.fetch = vi.fn();
55
+ });
56
+ afterEach(() => {
57
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
58
+ globalThis.fetch = originalFetch;
59
+ });
60
+ it("polls /jobs/claim and skips when registry returns 204 (no work)", async () => {
61
+ const fetchMock = globalThis.fetch;
62
+ fetchMock.mockResolvedValue({
63
+ status: 204,
64
+ json: async () => ({}),
65
+ });
66
+ const handler = vi.fn().mockResolvedValue("ok");
67
+ const d = new ClaimDispatcher("cap", "agent-instance", "http://reg", handler);
68
+ d.start();
69
+ await new Promise((r) => setTimeout(r, 50));
70
+ await d.stop();
71
+ expect(fetchMock).toHaveBeenCalled();
72
+ expect(handler).not.toHaveBeenCalled();
73
+ // Check the URL + body the dispatcher used to claim.
74
+ const [url, init] = fetchMock.mock.calls[0];
75
+ expect(url).toBe("http://reg/jobs/claim");
76
+ expect(init.method).toBe("POST");
77
+ const body = JSON.parse(init.body);
78
+ expect(body.capability).toBe("cap");
79
+ expect(body.instance_id).toBe("agent-instance");
80
+ });
81
+ it("dispatches a claimed job to the handler with the submitted payload", async () => {
82
+ const fetchMock = globalThis.fetch;
83
+ let calls = 0;
84
+ fetchMock.mockImplementation(async () => {
85
+ calls += 1;
86
+ // First poll returns one claim; subsequent polls return empty
87
+ // so the dispatcher backs off and the test can stop cleanly.
88
+ if (calls === 1) {
89
+ return {
90
+ status: 200,
91
+ json: async () => ({
92
+ claimed: [
93
+ {
94
+ id: "job-uuid-1",
95
+ submitted_payload: { user_id: "u", n: 5 },
96
+ max_duration: 30,
97
+ },
98
+ ],
99
+ }),
100
+ };
101
+ }
102
+ return { status: 204, json: async () => ({}) };
103
+ });
104
+ const handler = vi.fn().mockResolvedValue({ done: true });
105
+ const d = new ClaimDispatcher("cap", "agent-instance", "http://reg", handler);
106
+ d.start();
107
+ await new Promise((r) => setTimeout(r, 100));
108
+ await d.stop();
109
+ expect(handler).toHaveBeenCalledOnce();
110
+ const [payload, ctrl] = handler.mock.calls[0];
111
+ expect(payload).toEqual({ user_id: "u", n: 5 });
112
+ expect(ctrl).toBeDefined();
113
+ // Stub controller exposes jobId.
114
+ expect(ctrl.jobId).toBe("job-uuid-1");
115
+ });
116
+ it("treats malformed claim responses as no work (no crash, no handler call)", async () => {
117
+ const fetchMock = globalThis.fetch;
118
+ fetchMock.mockResolvedValue({
119
+ status: 200,
120
+ json: async () => ({ claimed: "not-a-list" }),
121
+ });
122
+ const handler = vi.fn();
123
+ const d = new ClaimDispatcher("cap", "i", "http://r", handler);
124
+ d.start();
125
+ await new Promise((r) => setTimeout(r, 50));
126
+ await d.stop();
127
+ expect(handler).not.toHaveBeenCalled();
128
+ });
129
+ it("filters out claimed entries without an id", async () => {
130
+ const fetchMock = globalThis.fetch;
131
+ let calls = 0;
132
+ fetchMock.mockImplementation(async () => {
133
+ calls += 1;
134
+ if (calls === 1) {
135
+ return {
136
+ status: 200,
137
+ json: async () => ({
138
+ claimed: [
139
+ { not_an_id: true },
140
+ { id: "" },
141
+ { id: "real-job", submitted_payload: {} },
142
+ ],
143
+ }),
144
+ };
145
+ }
146
+ return { status: 204, json: async () => ({}) };
147
+ });
148
+ const handler = vi.fn().mockResolvedValue("done");
149
+ const d = new ClaimDispatcher("cap", "i", "http://r", handler);
150
+ d.start();
151
+ await new Promise((r) => setTimeout(r, 100));
152
+ await d.stop();
153
+ expect(handler).toHaveBeenCalledOnce();
154
+ expect(handler.mock.calls[0][1].jobId).toBe("real-job");
155
+ });
156
+ it("seeds the propagated-headers ALS with x-mesh-job-id (and x-mesh-timeout when present)", async () => {
157
+ // Verifies follow-up #2: claim-path dispatches must seed the
158
+ // propagated-headers AsyncLocalStorage so outbound calls made by
159
+ // the handler continue the submitter's trace tree (Python parity
160
+ // — see `_mcp_mesh.engine.claim_dispatcher.PythonClaimDispatcher
161
+ // ._dispatch`'s `TraceContext.set_propagated_headers` block).
162
+ const fetchMock = globalThis.fetch;
163
+ let calls = 0;
164
+ fetchMock.mockImplementation(async () => {
165
+ calls += 1;
166
+ if (calls === 1) {
167
+ return {
168
+ status: 200,
169
+ json: async () => ({
170
+ claimed: [
171
+ {
172
+ id: "job-trace-1",
173
+ submitted_payload: { foo: "bar" },
174
+ max_duration: 45,
175
+ },
176
+ ],
177
+ }),
178
+ };
179
+ }
180
+ return { status: 204, json: async () => ({}) };
181
+ });
182
+ let observed = null;
183
+ const handler = vi.fn(async () => {
184
+ // Snapshot the ALS view from inside the user handler — exactly
185
+ // where outbound proxy calls would read it.
186
+ observed = { ...getCurrentPropagatedHeaders() };
187
+ return { ok: true };
188
+ });
189
+ const d = new ClaimDispatcher("cap-trace", "agent-1", "http://reg", handler);
190
+ d.start();
191
+ await new Promise((r) => setTimeout(r, 100));
192
+ await d.stop();
193
+ expect(handler).toHaveBeenCalledOnce();
194
+ expect(observed).not.toBeNull();
195
+ expect(observed["x-mesh-job-id"]).toBe("job-trace-1");
196
+ expect(observed["x-mesh-timeout"]).toBe("45");
197
+ });
198
+ it("omits x-mesh-timeout when claim has no max_duration", async () => {
199
+ // Defensive: a claim without max_duration must not seed an empty
200
+ // / zero-valued timeout header (downstream parsers would reject it).
201
+ const fetchMock = globalThis.fetch;
202
+ let calls = 0;
203
+ fetchMock.mockImplementation(async () => {
204
+ calls += 1;
205
+ if (calls === 1) {
206
+ return {
207
+ status: 200,
208
+ json: async () => ({
209
+ claimed: [{ id: "job-no-timeout", submitted_payload: {} }],
210
+ }),
211
+ };
212
+ }
213
+ return { status: 204, json: async () => ({}) };
214
+ });
215
+ let observed = null;
216
+ const handler = vi.fn(async () => {
217
+ observed = { ...getCurrentPropagatedHeaders() };
218
+ return null;
219
+ });
220
+ const d = new ClaimDispatcher("cap-no-timeout", "i", "http://r", handler);
221
+ d.start();
222
+ await new Promise((r) => setTimeout(r, 100));
223
+ await d.stop();
224
+ expect(handler).toHaveBeenCalledOnce();
225
+ expect(observed).not.toBeNull();
226
+ expect(observed["x-mesh-job-id"]).toBe("job-no-timeout");
227
+ expect(observed["x-mesh-timeout"]).toBeUndefined();
228
+ });
229
+ it("stop() closes the keep-alive http agent (no leaked sockets)", async () => {
230
+ // Verifies follow-up #3: each ClaimDispatcher owns an undici Agent
231
+ // for connection reuse on /jobs/claim polls; stop() must close
232
+ // it so long-lived test harnesses don't leak sockets across
233
+ // agent restarts.
234
+ const fetchMock = globalThis.fetch;
235
+ fetchMock.mockResolvedValue({
236
+ status: 204,
237
+ json: async () => ({}),
238
+ });
239
+ const d = new ClaimDispatcher("cap-stop", "i", "http://r", vi.fn());
240
+ // The Agent is private; reach in to verify close-state transitions.
241
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
242
+ const agent = d._httpAgent;
243
+ const closeSpy = vi.spyOn(agent, "close");
244
+ d.start();
245
+ await new Promise((r) => setTimeout(r, 30));
246
+ await d.stop();
247
+ // We invoke close() once from stop(); undici's DispatcherBase
248
+ // re-enters close(callback) internally, which the spy records as
249
+ // a second call. We only care that it was invoked (and that the
250
+ // agent is now in the closed state).
251
+ expect(closeSpy).toHaveBeenCalled();
252
+ expect(agent.closed || agent.destroyed).toBe(true);
253
+ });
254
+ it("stop() drains in-flight handlers before closing the keep-alive pool", async () => {
255
+ // Verifies the F7 follow-up: stop() must await any handler
256
+ // dispatches that are still mid-fetch before it tears down the
257
+ // shared `_httpAgent`. Without the drain, controller.complete /
258
+ // controller.fail HTTP calls would race with Agent.close() and
259
+ // surface as cryptic socket-closed errors — worse, the terminal
260
+ // delta might never reach the registry, leaving the row stuck.
261
+ const fetchMock = globalThis.fetch;
262
+ let calls = 0;
263
+ fetchMock.mockImplementation(async () => {
264
+ calls += 1;
265
+ if (calls === 1) {
266
+ return {
267
+ status: 200,
268
+ json: async () => ({
269
+ claimed: [{ id: "long", submitted_payload: {} }],
270
+ }),
271
+ };
272
+ }
273
+ return { status: 204, json: async () => ({}) };
274
+ });
275
+ let resolveHandler;
276
+ let handlerObservedFinish = false;
277
+ const handler = vi.fn(() => new Promise((resolve) => {
278
+ resolveHandler = () => {
279
+ handlerObservedFinish = true;
280
+ resolve("done");
281
+ };
282
+ }));
283
+ const d = new ClaimDispatcher("cap", "i", "http://r", handler);
284
+ // The Agent is private; verify close ordering relative to handler
285
+ // resolution. eslint-disable-next-line @typescript-eslint/no-explicit-any
286
+ const httpAgent = d._httpAgent;
287
+ let closedAt = 0;
288
+ const closeSpy = vi.spyOn(httpAgent, "close").mockImplementation(async () => {
289
+ closedAt = Date.now();
290
+ });
291
+ d.start();
292
+ await new Promise((r) => setTimeout(r, 50));
293
+ // Kick off stop(); resolve the handler ~20ms later.
294
+ const stopStart = Date.now();
295
+ const stopPromise = d.stop();
296
+ let resolvedAt = 0;
297
+ setTimeout(() => {
298
+ resolvedAt = Date.now();
299
+ resolveHandler();
300
+ }, 20);
301
+ await stopPromise;
302
+ expect(handler).toHaveBeenCalledOnce();
303
+ expect(handlerObservedFinish).toBe(true);
304
+ // The keep-alive pool must close STRICTLY AFTER the handler
305
+ // resolved — that's the whole point of the drain.
306
+ expect(closeSpy).toHaveBeenCalled();
307
+ expect(resolvedAt).toBeGreaterThan(0);
308
+ expect(closedAt).toBeGreaterThanOrEqual(resolvedAt);
309
+ // Sanity: stop() should still be quick — the bounded timeout is
310
+ // 30s default, but we resolved at 20ms, so total wall < 1s.
311
+ expect(Date.now() - stopStart).toBeLessThan(1000);
312
+ closeSpy.mockRestore();
313
+ });
314
+ it("stop(timeoutMs=0) skips the drain when the caller asks for an immediate close", async () => {
315
+ // Defensive: the bounded-drain default is 30s, but the caller can
316
+ // pass `0` to force-close (e.g. tests that stub a long-running
317
+ // handler and don't want to wait for it). Verify the path doesn't
318
+ // hang on the in-flight handler.
319
+ const fetchMock = globalThis.fetch;
320
+ let calls = 0;
321
+ fetchMock.mockImplementation(async () => {
322
+ calls += 1;
323
+ if (calls === 1) {
324
+ return {
325
+ status: 200,
326
+ json: async () => ({
327
+ claimed: [{ id: "never-finishes", submitted_payload: {} }],
328
+ }),
329
+ };
330
+ }
331
+ return { status: 204, json: async () => ({}) };
332
+ });
333
+ let resolveHandler;
334
+ const handler = vi.fn(() => new Promise((resolve) => {
335
+ resolveHandler = () => resolve("done");
336
+ }));
337
+ const d = new ClaimDispatcher("cap", "i", "http://r", handler);
338
+ d.start();
339
+ await new Promise((r) => setTimeout(r, 50));
340
+ const t0 = Date.now();
341
+ await d.stop(0);
342
+ expect(Date.now() - t0).toBeLessThan(500);
343
+ // Cleanup: resolve the dangling handler so it doesn't keep the
344
+ // event loop alive past the test.
345
+ resolveHandler();
346
+ });
347
+ it("posts a `failed` /jobs/batch delta when JobController construction throws (W2)", async () => {
348
+ // Review finding W2: previously a `console.warn` + early return left
349
+ // the registry believing this replica owned the job until lease
350
+ // expiry, leaving the row stuck in `working`. The fix is to fire a
351
+ // POST /jobs/batch failed delta directly (bypassing the controller
352
+ // we couldn't construct) so the row flips terminal immediately and
353
+ // unblocks retry.
354
+ const ctorSpy = vi
355
+ .spyOn(inboundDispatch, "makeJobController")
356
+ .mockImplementation(() => {
357
+ throw new Error("boom: napi binding refused");
358
+ });
359
+ const fetchMock = globalThis.fetch;
360
+ let calls = 0;
361
+ const claimUrl = "http://reg/jobs/claim";
362
+ const batchUrl = "http://reg/jobs/batch";
363
+ fetchMock.mockImplementation(async (url) => {
364
+ calls += 1;
365
+ if (url === claimUrl && calls === 1) {
366
+ return {
367
+ status: 200,
368
+ json: async () => ({
369
+ claimed: [
370
+ {
371
+ id: "job-broken-ctor",
372
+ submitted_payload: { x: 1 },
373
+ },
374
+ ],
375
+ }),
376
+ };
377
+ }
378
+ if (url === batchUrl) {
379
+ return { status: 200, json: async () => ({}) };
380
+ }
381
+ return { status: 204, json: async () => ({}) };
382
+ });
383
+ const handler = vi.fn();
384
+ const d = new ClaimDispatcher("cap-broken", "agent-x", "http://reg", handler);
385
+ d.start();
386
+ await new Promise((r) => setTimeout(r, 100));
387
+ await d.stop();
388
+ // Handler must NOT have been invoked — the dispatcher bailed before
389
+ // calling it because we couldn't build a controller.
390
+ expect(handler).not.toHaveBeenCalled();
391
+ // The fail-fast path must have POSTed a `failed` delta to /jobs/batch.
392
+ const batchCall = fetchMock.mock.calls.find((call) => call[0] === batchUrl);
393
+ expect(batchCall, "expected a POST /jobs/batch fail-fast call").toBeDefined();
394
+ const init = batchCall[1];
395
+ expect(init.method).toBe("POST");
396
+ const body = JSON.parse(init.body);
397
+ expect(body.instance_id).toBe("agent-x");
398
+ expect(body.deltas).toHaveLength(1);
399
+ const delta = body.deltas[0];
400
+ expect(delta.id).toBe("job-broken-ctor");
401
+ expect(delta.status).toBe("failed");
402
+ expect(typeof delta.error).toBe("string");
403
+ expect(delta.error).toContain("controller construction failed");
404
+ expect(delta.error).toContain("boom: napi binding refused");
405
+ ctorSpy.mockRestore();
406
+ });
407
+ });
408
+ //# sourceMappingURL=claim-dispatcher.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claim-dispatcher.spec.js","sourceRoot":"","sources":["../../src/__tests__/claim-dispatcher.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=inbound-job-dispatch.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbound-job-dispatch.spec.d.ts","sourceRoot":"","sources":["../../src/__tests__/inbound-job-dispatch.spec.ts"],"names":[],"mappings":""}