@novorb/mcp-core 2.1.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/README.md +82 -161
  2. package/bin/mcp-core-jest.mjs +112 -0
  3. package/dist/auth.d.ts +57 -0
  4. package/dist/auth.d.ts.map +1 -0
  5. package/dist/auth.js +74 -0
  6. package/dist/auth.js.map +1 -0
  7. package/dist/bootstrap.d.ts +129 -0
  8. package/dist/bootstrap.d.ts.map +1 -0
  9. package/dist/bootstrap.js +206 -0
  10. package/dist/bootstrap.js.map +1 -0
  11. package/dist/client-input.d.ts +72 -0
  12. package/dist/client-input.d.ts.map +1 -0
  13. package/dist/client-input.js +109 -0
  14. package/dist/client-input.js.map +1 -0
  15. package/dist/credential-checks.d.ts +80 -0
  16. package/dist/credential-checks.d.ts.map +1 -0
  17. package/dist/credential-checks.js +189 -0
  18. package/dist/credential-checks.js.map +1 -0
  19. package/dist/credential-health.d.ts +12 -0
  20. package/dist/credential-health.d.ts.map +1 -0
  21. package/dist/credential-health.js +12 -0
  22. package/dist/credential-health.js.map +1 -0
  23. package/dist/credential-report.d.ts +46 -0
  24. package/dist/credential-report.d.ts.map +1 -0
  25. package/dist/credential-report.js +135 -0
  26. package/dist/credential-report.js.map +1 -0
  27. package/dist/credential-status-tool.d.ts +20 -0
  28. package/dist/credential-status-tool.d.ts.map +1 -0
  29. package/dist/credential-status-tool.js +33 -0
  30. package/dist/credential-status-tool.js.map +1 -0
  31. package/dist/credentials.d.ts +288 -0
  32. package/dist/credentials.d.ts.map +1 -0
  33. package/dist/credentials.js +652 -0
  34. package/dist/credentials.js.map +1 -0
  35. package/dist/express-peers.d.ts +29 -0
  36. package/dist/express-peers.d.ts.map +1 -0
  37. package/dist/express-peers.js +36 -0
  38. package/dist/express-peers.js.map +1 -0
  39. package/dist/express.d.ts +74 -0
  40. package/dist/express.d.ts.map +1 -0
  41. package/dist/express.js +164 -0
  42. package/dist/express.js.map +1 -0
  43. package/dist/http-client.d.ts +278 -43
  44. package/dist/http-client.d.ts.map +1 -1
  45. package/dist/http-client.js +620 -182
  46. package/dist/http-client.js.map +1 -1
  47. package/dist/index.d.ts +27 -6
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +49 -10
  50. package/dist/index.js.map +1 -1
  51. package/dist/limits.d.ts +28 -0
  52. package/dist/limits.d.ts.map +1 -0
  53. package/dist/limits.js +37 -0
  54. package/dist/limits.js.map +1 -0
  55. package/dist/list-pagination.d.ts +41 -0
  56. package/dist/list-pagination.d.ts.map +1 -0
  57. package/dist/list-pagination.js +104 -0
  58. package/dist/list-pagination.js.map +1 -0
  59. package/dist/net.d.ts +112 -0
  60. package/dist/net.d.ts.map +1 -0
  61. package/dist/net.js +490 -0
  62. package/dist/net.js.map +1 -0
  63. package/dist/notifications.d.ts +78 -0
  64. package/dist/notifications.d.ts.map +1 -0
  65. package/dist/notifications.js +173 -0
  66. package/dist/notifications.js.map +1 -0
  67. package/dist/pagination.d.ts +236 -5
  68. package/dist/pagination.d.ts.map +1 -1
  69. package/dist/pagination.js +393 -6
  70. package/dist/pagination.js.map +1 -1
  71. package/dist/prompts.d.ts +70 -0
  72. package/dist/prompts.d.ts.map +1 -0
  73. package/dist/prompts.js +109 -0
  74. package/dist/prompts.js.map +1 -0
  75. package/dist/protocol-errors.d.ts +15 -0
  76. package/dist/protocol-errors.d.ts.map +1 -0
  77. package/dist/protocol-errors.js +28 -0
  78. package/dist/protocol-errors.js.map +1 -0
  79. package/dist/protocol-logging.d.ts +37 -0
  80. package/dist/protocol-logging.d.ts.map +1 -0
  81. package/dist/protocol-logging.js +77 -0
  82. package/dist/protocol-logging.js.map +1 -0
  83. package/dist/rate-limiter.d.ts +36 -0
  84. package/dist/rate-limiter.d.ts.map +1 -0
  85. package/dist/rate-limiter.js +79 -0
  86. package/dist/rate-limiter.js.map +1 -0
  87. package/dist/request-state.d.ts +74 -0
  88. package/dist/request-state.d.ts.map +1 -0
  89. package/dist/request-state.js +190 -0
  90. package/dist/request-state.js.map +1 -0
  91. package/dist/resources.d.ts +181 -0
  92. package/dist/resources.d.ts.map +1 -0
  93. package/dist/resources.js +302 -0
  94. package/dist/resources.js.map +1 -0
  95. package/dist/result-limits.d.ts +80 -0
  96. package/dist/result-limits.d.ts.map +1 -0
  97. package/dist/result-limits.js +248 -0
  98. package/dist/result-limits.js.map +1 -0
  99. package/dist/retry.d.ts +79 -23
  100. package/dist/retry.d.ts.map +1 -1
  101. package/dist/retry.js +170 -57
  102. package/dist/retry.js.map +1 -1
  103. package/dist/sdk/client-stdio.d.ts +6 -0
  104. package/dist/sdk/client-stdio.d.ts.map +1 -0
  105. package/dist/sdk/client-stdio.js +6 -0
  106. package/dist/sdk/client-stdio.js.map +1 -0
  107. package/dist/sdk/client.d.ts +6 -0
  108. package/dist/sdk/client.d.ts.map +1 -0
  109. package/dist/sdk/client.js +6 -0
  110. package/dist/sdk/client.js.map +1 -0
  111. package/dist/sdk/express.d.ts +3 -0
  112. package/dist/sdk/express.d.ts.map +1 -0
  113. package/dist/sdk/express.js +11 -0
  114. package/dist/sdk/express.js.map +1 -0
  115. package/dist/sdk/node.d.ts +6 -0
  116. package/dist/sdk/node.d.ts.map +1 -0
  117. package/dist/sdk/node.js +6 -0
  118. package/dist/sdk/node.js.map +1 -0
  119. package/dist/sdk/server-stdio.d.ts +6 -0
  120. package/dist/sdk/server-stdio.d.ts.map +1 -0
  121. package/dist/sdk/server-stdio.js +6 -0
  122. package/dist/sdk/server-stdio.js.map +1 -0
  123. package/dist/sdk/server.d.ts +6 -0
  124. package/dist/sdk/server.d.ts.map +1 -0
  125. package/dist/sdk/server.js +6 -0
  126. package/dist/sdk/server.js.map +1 -0
  127. package/dist/server.d.ts +88 -36
  128. package/dist/server.d.ts.map +1 -1
  129. package/dist/server.js +98 -44
  130. package/dist/server.js.map +1 -1
  131. package/dist/task-request.d.ts +20 -0
  132. package/dist/task-request.d.ts.map +1 -0
  133. package/dist/task-request.js +43 -0
  134. package/dist/task-request.js.map +1 -0
  135. package/dist/task-store.d.ts +230 -0
  136. package/dist/task-store.d.ts.map +1 -0
  137. package/dist/task-store.js +459 -0
  138. package/dist/task-store.js.map +1 -0
  139. package/dist/task-tools.d.ts +115 -0
  140. package/dist/task-tools.d.ts.map +1 -0
  141. package/dist/task-tools.js +397 -0
  142. package/dist/task-tools.js.map +1 -0
  143. package/dist/testing/client.d.ts +25 -0
  144. package/dist/testing/client.d.ts.map +1 -0
  145. package/dist/testing/client.js +11 -0
  146. package/dist/testing/client.js.map +1 -0
  147. package/dist/testing/in-memory.d.ts +26 -0
  148. package/dist/testing/in-memory.d.ts.map +1 -0
  149. package/dist/testing/in-memory.js +41 -0
  150. package/dist/testing/in-memory.js.map +1 -0
  151. package/dist/testing/index.d.ts +20 -0
  152. package/dist/testing/index.d.ts.map +1 -0
  153. package/dist/testing/index.js +20 -0
  154. package/dist/testing/index.js.map +1 -0
  155. package/dist/testing/isolated-dirs.d.ts +27 -0
  156. package/dist/testing/isolated-dirs.d.ts.map +1 -0
  157. package/dist/testing/isolated-dirs.js +67 -0
  158. package/dist/testing/isolated-dirs.js.map +1 -0
  159. package/dist/testing/logs.d.ts +61 -0
  160. package/dist/testing/logs.d.ts.map +1 -0
  161. package/dist/testing/logs.js +113 -0
  162. package/dist/testing/logs.js.map +1 -0
  163. package/dist/testing/raw-http.d.ts +25 -0
  164. package/dist/testing/raw-http.d.ts.map +1 -0
  165. package/dist/testing/raw-http.js +41 -0
  166. package/dist/testing/raw-http.js.map +1 -0
  167. package/dist/testing/raw-peer.d.ts +43 -0
  168. package/dist/testing/raw-peer.d.ts.map +1 -0
  169. package/dist/testing/raw-peer.js +101 -0
  170. package/dist/testing/raw-peer.js.map +1 -0
  171. package/dist/testing/recording-server.d.ts +38 -0
  172. package/dist/testing/recording-server.d.ts.map +1 -0
  173. package/dist/testing/recording-server.js +38 -0
  174. package/dist/testing/recording-server.js.map +1 -0
  175. package/dist/testing/server-process.d.ts +76 -0
  176. package/dist/testing/server-process.d.ts.map +1 -0
  177. package/dist/testing/server-process.js +241 -0
  178. package/dist/testing/server-process.js.map +1 -0
  179. package/dist/testing/tools.d.ts +53 -0
  180. package/dist/testing/tools.d.ts.map +1 -0
  181. package/dist/testing/tools.js +98 -0
  182. package/dist/testing/tools.js.map +1 -0
  183. package/dist/testing/unit.d.ts +52 -0
  184. package/dist/testing/unit.d.ts.map +1 -0
  185. package/dist/testing/unit.js +95 -0
  186. package/dist/testing/unit.js.map +1 -0
  187. package/dist/tools.d.ts +205 -0
  188. package/dist/tools.d.ts.map +1 -0
  189. package/dist/tools.js +370 -0
  190. package/dist/tools.js.map +1 -0
  191. package/dist/transport.d.ts +144 -53
  192. package/dist/transport.d.ts.map +1 -1
  193. package/dist/transport.js +305 -122
  194. package/dist/transport.js.map +1 -1
  195. package/dist/url-path.d.ts +49 -0
  196. package/dist/url-path.d.ts.map +1 -0
  197. package/dist/url-path.js +165 -0
  198. package/dist/url-path.js.map +1 -0
  199. package/dist/utils/dataStore.d.ts +143 -0
  200. package/dist/utils/dataStore.d.ts.map +1 -0
  201. package/dist/utils/dataStore.js +429 -0
  202. package/dist/utils/dataStore.js.map +1 -0
  203. package/dist/utils/envLoader.d.ts +129 -0
  204. package/dist/utils/envLoader.d.ts.map +1 -0
  205. package/dist/utils/envLoader.js +399 -0
  206. package/dist/utils/envLoader.js.map +1 -0
  207. package/dist/utils/logger.d.ts +181 -0
  208. package/dist/utils/logger.d.ts.map +1 -0
  209. package/dist/utils/logger.js +664 -0
  210. package/dist/utils/logger.js.map +1 -0
  211. package/dist/utils/redact.d.ts +50 -0
  212. package/dist/utils/redact.d.ts.map +1 -0
  213. package/dist/utils/redact.js +318 -0
  214. package/dist/utils/redact.js.map +1 -0
  215. package/docs/api-reference.md +29 -0
  216. package/docs/building-a-server.md +63 -0
  217. package/docs/credentials.md +131 -0
  218. package/docs/data-store.md +37 -0
  219. package/docs/env.md +38 -0
  220. package/docs/features.md +28 -0
  221. package/docs/http-client.md +116 -0
  222. package/docs/logger.md +100 -0
  223. package/docs/migrating-to-v3.md +45 -0
  224. package/docs/outbound-urls.md +104 -0
  225. package/docs/pagination.md +45 -0
  226. package/docs/protocol-features.md +62 -0
  227. package/docs/resources-prompts-tasks.md +95 -0
  228. package/docs/sdk.md +33 -0
  229. package/docs/server.md +68 -0
  230. package/docs/testing-harness.md +139 -0
  231. package/docs/testing.md +151 -0
  232. package/docs/tools.md +88 -0
  233. package/docs/transport.md +85 -0
  234. package/examples/testing/tools.integration.test.example.ts +312 -0
  235. package/examples/testing/tools.unit.test.example.ts +149 -0
  236. package/package.json +140 -18
  237. package/dist/logger.d.ts +0 -80
  238. package/dist/logger.d.ts.map +0 -1
  239. package/dist/logger.js +0 -236
  240. package/dist/logger.js.map +0 -1
@@ -0,0 +1,76 @@
1
+ /**
2
+ * @novorb/mcp-core/testing - start a BUILT MCP server as a child process and connect a v2 client.
3
+ *
4
+ * stdio: the SDK `StdioClientTransport` spawns `node <entry>` and speaks over its stdin/stdout.
5
+ * http: the harness spawns `node <entry>` with MCP_TRANSPORT=http on a free loopback port, polls
6
+ * `GET /health` until it answers 200, then connects `StreamableHTTPClientTransport` with the
7
+ * Bearer header.
8
+ *
9
+ * The child env is EXPLICIT: the minimal OS variables node needs (the SDK's DEFAULT_INHERITED_ENV_VARS
10
+ * list), the caller's `env`, and the harness variables. The parent's own environment (a developer's
11
+ * secrets, a dotenv-loaded `.env`) never reaches the child unless `inheritEnv: true`.
12
+ */
13
+ import { type ChildProcess } from 'node:child_process';
14
+ import type { Client } from '@modelcontextprotocol/client';
15
+ import { type TestClientOptions } from './client.js';
16
+ export type HarnessMode = 'stdio' | 'http';
17
+ export interface StartBuiltServerOptions extends TestClientOptions {
18
+ /** Path of the server entry, e.g. `<repo>/dist/index.js`. Run as `node [nodeArgs] <entry>`. */
19
+ entry: string;
20
+ /** Transport to start the server in. */
21
+ mode: HarnessMode;
22
+ /** Variables for the child. Merged over the minimal OS set; the harness variables win over these. */
23
+ env?: Record<string, string>;
24
+ /** Working directory of the child (default: the parent's cwd). Use an isolated temp dir in tests. */
25
+ cwd?: string;
26
+ /**
27
+ * http only: the Bearer key. A string sets MCP_API_KEY to it; `null` starts the server open
28
+ * (MCP_AUTH_DISABLED=true, no Authorization header). Omitted: `env.MCP_API_KEY` when given, else a
29
+ * random 32-byte hex key.
30
+ */
31
+ apiKey?: string | null;
32
+ /** How long to wait for readiness: http `/health` polling and the client connect (default 20000). */
33
+ readyTimeoutMs?: number;
34
+ /** Pass the parent's full environment through (default false: explicit env only). */
35
+ inheritEnv?: boolean;
36
+ /** Extra node arguments before the entry, e.g. `['--import', 'tsx']` to run a `.ts` entry. */
37
+ nodeArgs?: string[];
38
+ /** http only: the listen port (default: a free loopback port). */
39
+ port?: number;
40
+ /**
41
+ * Sets MCP_ENV_FILE for the child: the env-file override honoured by a server that loads its env
42
+ * through mcp-core's env loader (point it at an empty file, or at the loader's documented "none"
43
+ * value, so a developer `.env` cannot fill gaps). Equivalent to `env.MCP_ENV_FILE`; this wins.
44
+ */
45
+ envFile?: string;
46
+ }
47
+ export interface BuiltServer {
48
+ /** A connected v2 client. */
49
+ client: Client;
50
+ mode: HarnessMode;
51
+ /** http only: the `/mcp` endpoint URL. */
52
+ url?: string;
53
+ /** http only: the server base URL (`http://127.0.0.1:<port>`), for `/health` and raw requests. */
54
+ baseUrl?: string;
55
+ /** http only: the Bearer key in use (undefined when started open). Never log it. */
56
+ apiKey?: string;
57
+ /** The exact environment the child was started with (useful as `findLeaks` needles). */
58
+ env: Readonly<Record<string, string>>;
59
+ /** The child pid, when known. */
60
+ pid?: number;
61
+ /** Everything the child wrote to stderr so far. */
62
+ stderr(): string;
63
+ /** http only: everything the child wrote to stdout so far (stdio mode: always ''). */
64
+ stdout(): string;
65
+ /** Close the client and kill the child, awaiting its exit. Idempotent; never throws. */
66
+ stop(): Promise<void>;
67
+ }
68
+ /** The minimal OS variables node needs to run, read from the parent (only those that are set). */
69
+ export declare function minimalOsEnv(source?: NodeJS.ProcessEnv): Record<string, string>;
70
+ /** A free TCP port on 127.0.0.1 (bound and released; a small reuse race is possible but rare). */
71
+ export declare function freePort(): Promise<number>;
72
+ /** Kill a child and await its exit (SIGTERM, then SIGKILL after a grace period). Windows-safe. */
73
+ export declare function killAndWait(child: ChildProcess, graceMs?: number): Promise<void>;
74
+ /** Start a built server in stdio or http mode and return a connected v2 client plus teardown. */
75
+ export declare function startBuiltServer(options: StartBuiltServerOptions): Promise<BuiltServer>;
76
+ //# sourceMappingURL=server-process.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-process.d.ts","sourceRoot":"","sources":["../../src/testing/server-process.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,KAAK,YAAY,EAAS,MAAM,oBAAoB,CAAC;AAG9D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAG3D,OAAO,EAAoB,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEvE,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,MAAM,CAAC;AAE3C,MAAM,WAAW,uBAAwB,SAAQ,iBAAiB;IAChE,+FAA+F;IAC/F,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,IAAI,EAAE,WAAW,CAAC;IAClB,qGAAqG;IACrG,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,qGAAqG;IACrG,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,qGAAqG;IACrG,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qFAAqF;IACrF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,WAAW,CAAC;IAClB,0CAA0C;IAC1C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,kGAAkG;IAClG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oFAAoF;IACpF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wFAAwF;IACxF,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACtC,iCAAiC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,MAAM,IAAI,MAAM,CAAC;IACjB,sFAAsF;IACtF,MAAM,IAAI,MAAM,CAAC;IACjB,wFAAwF;IACxF,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAMD,kGAAkG;AAClG,wBAAgB,YAAY,CAAC,MAAM,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAO5F;AAQD,kGAAkG;AAClG,wBAAgB,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,CAU1C;AAcD,kGAAkG;AAClG,wBAAsB,WAAW,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,SAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAW7F;AAmDD,iGAAiG;AACjG,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,WAAW,CAAC,CAU7F"}
@@ -0,0 +1,241 @@
1
+ /**
2
+ * @novorb/mcp-core/testing - start a BUILT MCP server as a child process and connect a v2 client.
3
+ *
4
+ * stdio: the SDK `StdioClientTransport` spawns `node <entry>` and speaks over its stdin/stdout.
5
+ * http: the harness spawns `node <entry>` with MCP_TRANSPORT=http on a free loopback port, polls
6
+ * `GET /health` until it answers 200, then connects `StreamableHTTPClientTransport` with the
7
+ * Bearer header.
8
+ *
9
+ * The child env is EXPLICIT: the minimal OS variables node needs (the SDK's DEFAULT_INHERITED_ENV_VARS
10
+ * list), the caller's `env`, and the harness variables. The parent's own environment (a developer's
11
+ * secrets, a dotenv-loaded `.env`) never reaches the child unless `inheritEnv: true`.
12
+ */
13
+ import { spawn } from 'node:child_process';
14
+ import { randomBytes } from 'node:crypto';
15
+ import { createServer as createNetServer } from 'node:net';
16
+ import { StreamableHTTPClientTransport } from '@modelcontextprotocol/client';
17
+ import { DEFAULT_INHERITED_ENV_VARS, StdioClientTransport } from '@modelcontextprotocol/client/stdio';
18
+ import { createTestClient } from './client.js';
19
+ const DEFAULT_READY_TIMEOUT_MS = 20_000;
20
+ const POLL_INTERVAL_MS = 50;
21
+ const EXIT_GRACE_MS = 5_000;
22
+ /** The minimal OS variables node needs to run, read from the parent (only those that are set). */
23
+ export function minimalOsEnv(source = process.env) {
24
+ const out = {};
25
+ for (const key of DEFAULT_INHERITED_ENV_VARS) {
26
+ const value = source[key];
27
+ if (value !== undefined && !value.startsWith('()'))
28
+ out[key] = value;
29
+ }
30
+ return out;
31
+ }
32
+ function stringEnv(source) {
33
+ const out = {};
34
+ for (const [k, v] of Object.entries(source))
35
+ if (v !== undefined)
36
+ out[k] = v;
37
+ return out;
38
+ }
39
+ /** A free TCP port on 127.0.0.1 (bound and released; a small reuse race is possible but rare). */
40
+ export function freePort() {
41
+ return new Promise((ok, fail) => {
42
+ const srv = createNetServer();
43
+ srv.once('error', fail);
44
+ srv.listen(0, '127.0.0.1', () => {
45
+ const addr = srv.address();
46
+ const port = typeof addr === 'object' && addr ? addr.port : 0;
47
+ srv.close(() => (port > 0 ? ok(port) : fail(new Error('freePort: no port assigned'))));
48
+ });
49
+ });
50
+ }
51
+ function delay(ms) {
52
+ return new Promise((r) => setTimeout(r, ms));
53
+ }
54
+ function tail(text, max = 4000) {
55
+ return text.length > max ? `...${text.slice(-max)}` : text;
56
+ }
57
+ function hasExited(child) {
58
+ return child.exitCode !== null || child.signalCode !== null;
59
+ }
60
+ /** Kill a child and await its exit (SIGTERM, then SIGKILL after a grace period). Windows-safe. */
61
+ export async function killAndWait(child, graceMs = EXIT_GRACE_MS) {
62
+ if (hasExited(child))
63
+ return;
64
+ const exited = new Promise((done) => child.once('exit', () => done()));
65
+ // On Windows `kill()` maps to TerminateProcess regardless of the signal; on POSIX SIGTERM lets the
66
+ // server's own shutdown path run first.
67
+ child.kill('SIGTERM');
68
+ const timer = new Promise((r) => setTimeout(() => r('timeout'), graceMs).unref());
69
+ if ((await Promise.race([exited.then(() => 'exited'), timer])) === 'timeout' && !hasExited(child)) {
70
+ child.kill('SIGKILL');
71
+ await exited;
72
+ }
73
+ }
74
+ async function waitForHealth(baseUrl, child, timeoutMs, stderr) {
75
+ const deadline = Date.now() + timeoutMs;
76
+ let lastError = 'no response';
77
+ while (Date.now() < deadline) {
78
+ if (hasExited(child)) {
79
+ throw new Error(`startBuiltServer: server exited (code ${child.exitCode ?? child.signalCode}) before /health was ready.\n` +
80
+ `stderr:\n${tail(stderr())}`);
81
+ }
82
+ try {
83
+ const res = await fetch(`${baseUrl}/health`, { signal: AbortSignal.timeout(1_000) });
84
+ if (res.status === 200)
85
+ return;
86
+ lastError = `status ${res.status}`;
87
+ }
88
+ catch (e) {
89
+ lastError = e instanceof Error ? e.message : String(e);
90
+ }
91
+ await delay(POLL_INTERVAL_MS);
92
+ }
93
+ throw new Error(`startBuiltServer: /health not ready within ${timeoutMs} ms (${lastError}).\nstderr:\n${tail(stderr())}`);
94
+ }
95
+ async function withTimeout(promise, ms, what) {
96
+ let timer;
97
+ const timeout = new Promise((_, fail) => {
98
+ timer = setTimeout(() => fail(new Error(`${what} timed out after ${ms} ms`)), ms);
99
+ });
100
+ try {
101
+ return await Promise.race([promise, timeout]);
102
+ }
103
+ finally {
104
+ if (timer)
105
+ clearTimeout(timer);
106
+ }
107
+ }
108
+ function once(fn) {
109
+ let pending;
110
+ return () => {
111
+ pending ??= fn();
112
+ return pending;
113
+ };
114
+ }
115
+ /** Start a built server in stdio or http mode and return a connected v2 client plus teardown. */
116
+ export async function startBuiltServer(options) {
117
+ const readyTimeoutMs = options.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS;
118
+ const base = options.inheritEnv ? stringEnv(process.env) : minimalOsEnv();
119
+ const callerEnv = { ...options.env };
120
+ if (options.envFile !== undefined)
121
+ callerEnv.MCP_ENV_FILE = options.envFile;
122
+ const opts = { ...options, env: callerEnv };
123
+ const args = [...(options.nodeArgs ?? []), options.entry];
124
+ return options.mode === 'stdio'
125
+ ? startStdio(opts, { ...base, ...callerEnv, MCP_TRANSPORT: 'stdio' }, args, readyTimeoutMs)
126
+ : startHttp(opts, base, args, readyTimeoutMs);
127
+ }
128
+ async function startStdio(options, env, args, readyTimeoutMs) {
129
+ let stderrText = '';
130
+ const transport = new StdioClientTransport({
131
+ command: process.execPath,
132
+ args,
133
+ env,
134
+ cwd: options.cwd,
135
+ stderr: 'pipe',
136
+ });
137
+ transport.stderr?.on('data', (chunk) => {
138
+ stderrText += chunk.toString();
139
+ });
140
+ const client = createTestClient(options);
141
+ const stop = once(async () => {
142
+ // client.close() closes the transport, which ends stdin, then SIGTERM, then SIGKILL, awaiting exit.
143
+ await client.close().catch(() => undefined);
144
+ await transport.close().catch(() => undefined);
145
+ });
146
+ try {
147
+ await withTimeout(client.connect(transport), readyTimeoutMs, 'startBuiltServer: stdio connect');
148
+ }
149
+ catch (e) {
150
+ await stop();
151
+ const message = e instanceof Error ? e.message : String(e);
152
+ throw new Error(`startBuiltServer: stdio connect failed: ${message}\nstderr:\n${tail(stderrText)}`);
153
+ }
154
+ return {
155
+ client,
156
+ mode: 'stdio',
157
+ env,
158
+ pid: transport.pid ?? undefined,
159
+ stderr: () => stderrText,
160
+ stdout: () => '',
161
+ stop,
162
+ };
163
+ }
164
+ function resolveApiKey(options) {
165
+ if (options.apiKey === null)
166
+ return undefined;
167
+ if (typeof options.apiKey === 'string')
168
+ return options.apiKey;
169
+ return options.env?.MCP_API_KEY || randomBytes(32).toString('hex');
170
+ }
171
+ async function startHttp(options, base, args, readyTimeoutMs) {
172
+ const port = options.port ?? (await freePort());
173
+ const apiKey = resolveApiKey(options);
174
+ const env = {
175
+ ...base,
176
+ ...options.env,
177
+ MCP_TRANSPORT: 'http',
178
+ MCP_HTTP_HOST: '127.0.0.1',
179
+ PORT: String(port),
180
+ };
181
+ if (apiKey === undefined) {
182
+ delete env.MCP_API_KEY;
183
+ env.MCP_AUTH_DISABLED = 'true';
184
+ }
185
+ else {
186
+ env.MCP_API_KEY = apiKey;
187
+ }
188
+ const child = spawn(process.execPath, args, {
189
+ env,
190
+ cwd: options.cwd,
191
+ stdio: ['ignore', 'pipe', 'pipe'],
192
+ shell: false,
193
+ windowsHide: true,
194
+ });
195
+ let stderrText = '';
196
+ let stdoutText = '';
197
+ child.stderr?.on('data', (chunk) => {
198
+ stderrText += chunk.toString();
199
+ });
200
+ child.stdout?.on('data', (chunk) => {
201
+ stdoutText += chunk.toString();
202
+ });
203
+ const spawnError = new Promise((_, fail) => {
204
+ child.once('error', (err) => fail(new Error(`startBuiltServer: spawn failed: ${err.message}`)));
205
+ });
206
+ spawnError.catch(() => undefined);
207
+ const baseUrl = `http://127.0.0.1:${port}`;
208
+ const url = `${baseUrl}/mcp`;
209
+ const client = createTestClient(options);
210
+ let connected = false;
211
+ const stop = once(async () => {
212
+ if (connected)
213
+ await client.close().catch(() => undefined);
214
+ await killAndWait(child);
215
+ });
216
+ try {
217
+ await Promise.race([waitForHealth(baseUrl, child, readyTimeoutMs, () => stderrText), spawnError]);
218
+ const transport = new StreamableHTTPClientTransport(new URL(url), apiKey === undefined ? {} : { requestInit: { headers: { Authorization: `Bearer ${apiKey}` } } });
219
+ await withTimeout(client.connect(transport), readyTimeoutMs, 'startBuiltServer: http connect');
220
+ connected = true;
221
+ }
222
+ catch (e) {
223
+ await stop();
224
+ throw e instanceof Error && e.message.startsWith('startBuiltServer:')
225
+ ? e
226
+ : new Error(`startBuiltServer: http connect failed: ${e instanceof Error ? e.message : String(e)}\nstderr:\n${tail(stderrText)}`);
227
+ }
228
+ return {
229
+ client,
230
+ mode: 'http',
231
+ url,
232
+ baseUrl,
233
+ apiKey,
234
+ env,
235
+ pid: child.pid,
236
+ stderr: () => stderrText,
237
+ stdout: () => stdoutText,
238
+ stop,
239
+ };
240
+ }
241
+ //# sourceMappingURL=server-process.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-process.js","sourceRoot":"","sources":["../../src/testing/server-process.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @novorb/mcp-core/testing - tool call and tool coverage helpers over a connected v2 client.
3
+ */
4
+ import type { CallToolResult, Client } from '@modelcontextprotocol/client';
5
+ export interface ToolJsonResult<T = unknown> {
6
+ /** `result.isError === true`. */
7
+ isError: boolean;
8
+ /**
9
+ * `structuredContent` when the tool returned it; otherwise the first text block parsed as JSON, or the
10
+ * raw text when it is not JSON; `undefined` when there is neither.
11
+ */
12
+ body: T;
13
+ /** The first text block ('' when there is none). */
14
+ text: string;
15
+ /** The unmodified SDK result. */
16
+ raw: CallToolResult;
17
+ }
18
+ /**
19
+ * Call a tool and decode its body. Tool-level failures come back as `isError: true` (not a throw);
20
+ * protocol errors (unknown tool, schema rejection on some servers) throw from the SDK as usual.
21
+ */
22
+ export declare function callToolJson<T = unknown>(client: Client, name: string, args?: Record<string, unknown>): Promise<ToolJsonResult<T>>;
23
+ /** Names of every tool the server lists (all pages), in server order. */
24
+ export declare function listToolNames(client: Client): Promise<string[]>;
25
+ export interface ToolCoverage {
26
+ /** Tools the server lists that have no case. */
27
+ missing: string[];
28
+ /** Cases naming a tool the server does not list. */
29
+ stale: string[];
30
+ /** Case names that appear more than once. */
31
+ duplicates: string[];
32
+ /** True when all three lists are empty. */
33
+ ok: boolean;
34
+ }
35
+ /** Compare the server's tool names with the suite's case names, both directions. Sorted output. */
36
+ export declare function toolCoverage(actualNames: readonly string[], caseNames: readonly string[]): ToolCoverage;
37
+ /** `toolCoverage`, throwing an Error that lists every gap when the sets differ. */
38
+ export declare function assertToolCoverage(actualNames: readonly string[], caseNames: readonly string[]): ToolCoverage;
39
+ export interface ToolWire {
40
+ name: string;
41
+ title?: string;
42
+ description?: string;
43
+ inputSchema: unknown;
44
+ outputSchema?: unknown;
45
+ annotations?: unknown;
46
+ execution?: unknown;
47
+ }
48
+ /**
49
+ * The server's `tools/list` surface across every page, reduced to the wire fields, sorted by name and
50
+ * round-tripped through JSON so it compares stably against a stored fixture.
51
+ */
52
+ export declare function captureToolWire(client: Client): Promise<ToolWire[]>;
53
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/testing/tools.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAE3E,MAAM,WAAW,cAAc,CAAC,CAAC,GAAG,OAAO;IACzC,iCAAiC;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,IAAI,EAAE,CAAC,CAAC;IACR,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,GAAG,EAAE,cAAc,CAAC;CACrB;AASD;;;GAGG;AACH,wBAAsB,YAAY,CAAC,CAAC,GAAG,OAAO,EAC5C,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACjC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAc5B;AAED,yEAAyE;AACzE,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAGrE;AAED,MAAM,WAAW,YAAY;IAC3B,gDAAgD;IAChD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,oDAAoD;IACpD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,6CAA6C;IAC7C,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,2CAA2C;IAC3C,EAAE,EAAE,OAAO,CAAC;CACb;AAED,mGAAmG;AACnG,wBAAgB,YAAY,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,YAAY,CAYvG;AAED,mFAAmF;AACnF,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,YAAY,CAW7G;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAID;;;GAGG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAuBzE"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * @novorb/mcp-core/testing - tool call and tool coverage helpers over a connected v2 client.
3
+ */
4
+ function firstText(result) {
5
+ for (const block of result.content ?? []) {
6
+ if (block.type === 'text')
7
+ return block.text;
8
+ }
9
+ return '';
10
+ }
11
+ /**
12
+ * Call a tool and decode its body. Tool-level failures come back as `isError: true` (not a throw);
13
+ * protocol errors (unknown tool, schema rejection on some servers) throw from the SDK as usual.
14
+ */
15
+ export async function callToolJson(client, name, args = {}) {
16
+ const raw = await client.callTool({ name, arguments: args });
17
+ const text = firstText(raw);
18
+ let body;
19
+ if (raw.structuredContent !== undefined) {
20
+ body = raw.structuredContent;
21
+ }
22
+ else if (text !== '') {
23
+ try {
24
+ body = JSON.parse(text);
25
+ }
26
+ catch {
27
+ body = text;
28
+ }
29
+ }
30
+ return { isError: raw.isError === true, body: body, text, raw };
31
+ }
32
+ /** Names of every tool the server lists (all pages), in server order. */
33
+ export async function listToolNames(client) {
34
+ const { tools } = await client.listTools();
35
+ return tools.map((t) => t.name);
36
+ }
37
+ /** Compare the server's tool names with the suite's case names, both directions. Sorted output. */
38
+ export function toolCoverage(actualNames, caseNames) {
39
+ const actual = new Set(actualNames);
40
+ const cases = new Set();
41
+ const dup = new Set();
42
+ for (const c of caseNames) {
43
+ if (cases.has(c))
44
+ dup.add(c);
45
+ cases.add(c);
46
+ }
47
+ const missing = [...actual].filter((n) => !cases.has(n)).sort();
48
+ const stale = [...cases].filter((n) => !actual.has(n)).sort();
49
+ const duplicates = [...dup].sort();
50
+ return { missing, stale, duplicates, ok: missing.length === 0 && stale.length === 0 && duplicates.length === 0 };
51
+ }
52
+ /** `toolCoverage`, throwing an Error that lists every gap when the sets differ. */
53
+ export function assertToolCoverage(actualNames, caseNames) {
54
+ const cov = toolCoverage(actualNames, caseNames);
55
+ if (!cov.ok) {
56
+ const parts = [
57
+ `tools without a case: [${cov.missing.join(', ')}]`,
58
+ `stale cases (no such tool): [${cov.stale.join(', ')}]`,
59
+ ];
60
+ if (cov.duplicates.length > 0)
61
+ parts.push(`duplicate cases: [${cov.duplicates.join(', ')}]`);
62
+ throw new Error(`Tool coverage mismatch: ${parts.join('; ')}`);
63
+ }
64
+ return cov;
65
+ }
66
+ const WIRE_KEYS = ['name', 'title', 'description', 'inputSchema', 'outputSchema', 'annotations', 'execution'];
67
+ /**
68
+ * The server's `tools/list` surface across every page, reduced to the wire fields, sorted by name and
69
+ * round-tripped through JSON so it compares stably against a stored fixture.
70
+ */
71
+ export async function captureToolWire(client) {
72
+ const wire = [];
73
+ let cursor;
74
+ const seen = new Set();
75
+ do {
76
+ const page = await client.listTools(cursor === undefined ? undefined : { cursor });
77
+ for (const tool of page.tools) {
78
+ const entry = {};
79
+ for (const key of WIRE_KEYS) {
80
+ const value = tool[key];
81
+ if (value !== undefined)
82
+ entry[key] = value;
83
+ }
84
+ wire.push(entry);
85
+ }
86
+ cursor = page.nextCursor;
87
+ if (cursor === '')
88
+ throw new Error('captureToolWire: tools/list returned an empty nextCursor');
89
+ if (cursor !== undefined) {
90
+ if (seen.has(cursor))
91
+ throw new Error('captureToolWire: tools/list returned a repeated nextCursor');
92
+ seen.add(cursor);
93
+ }
94
+ } while (cursor !== undefined);
95
+ wire.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
96
+ return JSON.parse(JSON.stringify(wire));
97
+ }
98
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/testing/tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @novorb/mcp-core/testing - in-process UNIT helpers: call a server's tools by name over the in-memory
3
+ * transport (no child process, no network) and assert on the outcome without a test-runner import.
4
+ *
5
+ * Observed SDK v2 behaviour for an McpServer (pinned by mcp-core's own tests):
6
+ * - arguments that fail the tool's inputSchema come back as a RESULT with `isError: true` and text
7
+ * starting `Input validation error:`;
8
+ * - an unknown tool name is a THROWN ProtocolError, code -32602 (InvalidParams), `Tool <name> not found`.
9
+ * Low-level `Server` consumers may surface either one either way, so the helpers accept both.
10
+ */
11
+ import type { Client } from '@modelcontextprotocol/client';
12
+ import type { ServerFactory } from '../transport.js';
13
+ import type { TestClientOptions } from './client.js';
14
+ import { type ToolJsonResult } from './tools.js';
15
+ /** JSON-RPC InvalidParams: the code the SDK uses for unknown tools (and some schema rejections). */
16
+ export declare const INVALID_PARAMS_CODE = -32602;
17
+ /** Run `fn` with a client connected in memory to `factory`; always closes. */
18
+ export declare function withInMemoryClient<R>(factory: ServerFactory, fn: (client: Client) => Promise<R>, options?: TestClientOptions): Promise<R>;
19
+ /** Build a server from `factory`, call one tool in memory, decode the result, and close. */
20
+ export declare function callToolInMemory<T = unknown>(factory: ServerFactory, name: string, args?: Record<string, unknown>, options?: TestClientOptions): Promise<ToolJsonResult<T>>;
21
+ /** The outcome of a call that may either return a result or throw a protocol error. */
22
+ export type ToolOutcome<T = unknown> = {
23
+ kind: 'result';
24
+ result: ToolJsonResult<T>;
25
+ } | {
26
+ kind: 'protocol-error';
27
+ code: number | undefined;
28
+ message: string;
29
+ };
30
+ /** Call a tool and capture a thrown protocol error as data instead of rethrowing it. */
31
+ export declare function captureToolCall<T = unknown>(client: Client, name: string, args?: Record<string, unknown>): Promise<ToolOutcome<T>>;
32
+ /** Throw unless `result.isError` is true (and its text matches `pattern`); returns the error text. */
33
+ export declare function expectToolError(result: ToolJsonResult, pattern?: string | RegExp): string;
34
+ /** Throw unless the result is a success; returns the decoded body. */
35
+ export declare function expectToolSuccess<T>(result: ToolJsonResult<T>): T;
36
+ export interface Rejection {
37
+ /** How the rejection surfaced. */
38
+ via: 'tool-error' | 'protocol-error';
39
+ message: string;
40
+ }
41
+ /**
42
+ * Call a tool with arguments its schema must reject and throw unless it was rejected: an isError result
43
+ * (`Input validation error` on McpServer) or an InvalidParams protocol error.
44
+ */
45
+ export declare function expectSchemaRejection(client: Client, name: string, args: Record<string, unknown>): Promise<Rejection>;
46
+ /**
47
+ * Call a tool name the server does not have and throw unless it was refused: a protocol error, or an
48
+ * isError result whose text says the tool is unknown / not found (any other error result, such as a
49
+ * schema rejection of an EXISTING tool, does not count).
50
+ */
51
+ export declare function expectUnknownTool(client: Client, name: string): Promise<Rejection>;
52
+ //# sourceMappingURL=unit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unit.d.ts","sourceRoot":"","sources":["../../src/testing/unit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAE/D,oGAAoG;AACpG,eAAO,MAAM,mBAAmB,SAAS,CAAC;AAE1C,8EAA8E;AAC9E,wBAAsB,kBAAkB,CAAC,CAAC,EACxC,OAAO,EAAE,aAAa,EACtB,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,EAClC,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,CAAC,CAAC,CAOZ;AAED,4FAA4F;AAC5F,wBAAsB,gBAAgB,CAAC,CAAC,GAAG,OAAO,EAChD,OAAO,EAAE,aAAa,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EAClC,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAE5B;AAED,uFAAuF;AACvF,MAAM,MAAM,WAAW,CAAC,CAAC,GAAG,OAAO,IAC/B;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1E,wFAAwF;AACxF,wBAAsB,eAAe,CAAC,CAAC,GAAG,OAAO,EAC/C,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACjC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAWzB;AAOD,sGAAsG;AACtG,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAQzF;AAED,sEAAsE;AACtE,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,CAGjE;AAED,MAAM,WAAW,SAAS;IACxB,kCAAkC;IAClC,GAAG,EAAE,YAAY,GAAG,gBAAgB,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,SAAS,CAAC,CAcpB;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAOxF"}