@zackbart/connecta 0.15.1 → 0.16.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 (332) hide show
  1. package/AGENTS.md +28 -15
  2. package/CHANGELOG.md +466 -0
  3. package/README.md +19 -4
  4. package/bin/connecta.mjs +44 -3
  5. package/dist/access-tokens.d.ts +0 -1
  6. package/dist/access-tokens.js +0 -1
  7. package/dist/activity.d.ts +50 -2
  8. package/dist/activity.js +34 -1
  9. package/dist/apps-shell.d.ts +0 -1
  10. package/dist/apps-shell.js +0 -1
  11. package/dist/auth/bearer.d.ts +0 -1
  12. package/dist/auth/bearer.js +0 -1
  13. package/dist/auth/clerk.d.ts +0 -1
  14. package/dist/auth/clerk.js +45 -9
  15. package/dist/auth/downstream-oauth.d.ts +0 -1
  16. package/dist/auth/downstream-oauth.js +0 -1
  17. package/dist/call-admission.d.ts +0 -1
  18. package/dist/call-admission.js +0 -1
  19. package/dist/catalog-drift.d.ts +99 -0
  20. package/dist/catalog-drift.js +251 -0
  21. package/dist/catalog-fingerprint.d.ts +0 -1
  22. package/dist/catalog-fingerprint.js +0 -1
  23. package/dist/catalog-limits.d.ts +0 -1
  24. package/dist/catalog-limits.js +0 -1
  25. package/dist/catalog-service.d.ts +0 -1
  26. package/dist/catalog-service.js +0 -1
  27. package/dist/catalog.d.ts +0 -1
  28. package/dist/catalog.js +0 -1
  29. package/dist/concurrency.d.ts +0 -1
  30. package/dist/concurrency.js +0 -1
  31. package/dist/connector-scope.d.ts +0 -1
  32. package/dist/connector-scope.js +0 -1
  33. package/dist/connectors/api.d.ts +29 -21
  34. package/dist/connectors/api.js +45 -19
  35. package/dist/connectors/guarded-fetch.d.ts +106 -0
  36. package/dist/connectors/guarded-fetch.js +289 -0
  37. package/dist/connectors/remote-mcp.d.ts +0 -1
  38. package/dist/connectors/remote-mcp.js +0 -1
  39. package/dist/credentials.d.ts +0 -1
  40. package/dist/credentials.js +0 -1
  41. package/dist/errors.d.ts +0 -1
  42. package/dist/errors.js +0 -1
  43. package/dist/execute.d.ts +0 -1
  44. package/dist/execute.js +0 -1
  45. package/dist/executor-admission.d.ts +11 -1
  46. package/dist/executor-admission.js +28 -1
  47. package/dist/executor-result.d.ts +0 -1
  48. package/dist/executor-result.js +0 -1
  49. package/dist/executors/quickjs-child.d.ts +0 -1
  50. package/dist/executors/quickjs-child.js +0 -1
  51. package/dist/executors/quickjs-protocol.d.ts +0 -1
  52. package/dist/executors/quickjs-protocol.js +0 -1
  53. package/dist/executors/quickjs-runtime.d.ts +0 -1
  54. package/dist/executors/quickjs-runtime.js +0 -1
  55. package/dist/executors/quickjs.d.ts +0 -1
  56. package/dist/executors/quickjs.js +2 -1
  57. package/dist/favicon.d.ts +0 -1
  58. package/dist/favicon.js +0 -1
  59. package/dist/index.d.ts +2 -3
  60. package/dist/index.js +24 -7
  61. package/dist/invocation.d.ts +0 -1
  62. package/dist/invocation.js +0 -1
  63. package/dist/json-schema.d.ts +0 -1
  64. package/dist/json-schema.js +0 -1
  65. package/dist/mcp-result.d.ts +0 -1
  66. package/dist/mcp-result.js +0 -1
  67. package/dist/meta-tools.d.ts +0 -1
  68. package/dist/meta-tools.js +0 -1
  69. package/dist/node.d.ts +0 -1
  70. package/dist/node.js +0 -1
  71. package/dist/operator-ui/generated.d.ts +2 -3
  72. package/dist/operator-ui/generated.js +3 -4
  73. package/dist/operator-ui/model.d.ts +10 -1
  74. package/dist/operator-ui/model.js +0 -1
  75. package/dist/operator-ui/view.d.ts +167 -0
  76. package/dist/operator-ui/view.js +270 -0
  77. package/dist/providers/cloudflare.d.ts +0 -1
  78. package/dist/providers/cloudflare.js +250 -276
  79. package/dist/providers/linear.d.ts +26 -5
  80. package/dist/providers/linear.js +32 -61
  81. package/dist/providers/mixpanel.d.ts +35 -4
  82. package/dist/providers/mixpanel.js +53 -79
  83. package/dist/providers/notion.d.ts +0 -1
  84. package/dist/providers/notion.js +87 -42
  85. package/dist/providers/stripe.d.ts +13 -1
  86. package/dist/providers/stripe.js +31 -60
  87. package/dist/registry.d.ts +34 -2
  88. package/dist/registry.js +85 -5
  89. package/dist/retired-toolkits.d.ts +0 -1
  90. package/dist/retired-toolkits.js +0 -1
  91. package/dist/routes/access-tokens.d.ts +0 -1
  92. package/dist/routes/access-tokens.js +0 -1
  93. package/dist/routes/activity.d.ts +0 -1
  94. package/dist/routes/activity.js +0 -1
  95. package/dist/routes/credentials.d.ts +0 -1
  96. package/dist/routes/credentials.js +0 -1
  97. package/dist/routes/mcp.d.ts +0 -1
  98. package/dist/routes/mcp.js +0 -1
  99. package/dist/routes/oauth.d.ts +0 -1
  100. package/dist/routes/oauth.js +0 -1
  101. package/dist/routes/shared.d.ts +2 -1
  102. package/dist/routes/shared.js +0 -1
  103. package/dist/routes/ui.d.ts +0 -1
  104. package/dist/routes/ui.js +0 -1
  105. package/dist/server.d.ts +0 -1
  106. package/dist/server.js +11 -1
  107. package/dist/skills.d.ts +0 -1
  108. package/dist/skills.js +0 -1
  109. package/dist/storage/file.d.ts +0 -1
  110. package/dist/storage/file.js +0 -1
  111. package/dist/storage/memory.d.ts +0 -1
  112. package/dist/storage/memory.js +0 -1
  113. package/dist/timeout.d.ts +0 -1
  114. package/dist/timeout.js +0 -1
  115. package/dist/tool-safety.d.ts +0 -1
  116. package/dist/tool-safety.js +0 -1
  117. package/dist/types.d.ts +45 -1
  118. package/dist/types.js +0 -1
  119. package/dist/ui.d.ts +0 -1
  120. package/dist/ui.js +13 -137
  121. package/dist/validate.d.ts +13 -15
  122. package/dist/validate.js +24 -11
  123. package/dist/version.d.ts +1 -2
  124. package/dist/version.js +1 -2
  125. package/documentation/architecture.md +186 -5
  126. package/documentation/auth.md +11 -0
  127. package/documentation/call-admission.md +142 -6
  128. package/documentation/cloudflare.md +58 -8
  129. package/documentation/code-mode.md +12 -12
  130. package/documentation/connector-guides.md +172 -5
  131. package/documentation/connectors.md +89 -0
  132. package/documentation/linear.md +20 -2
  133. package/documentation/mcp-ui-design.md +2 -2
  134. package/documentation/mixpanel.md +42 -9
  135. package/documentation/notion.md +16 -0
  136. package/documentation/operations.md +283 -5
  137. package/documentation/operator-ui.md +120 -5
  138. package/documentation/provider-audit.md +160 -0
  139. package/documentation/provider-conventions.md +631 -0
  140. package/documentation/request-admission.md +167 -5
  141. package/documentation/rich-output-design.md +1 -2
  142. package/documentation/stripe.md +15 -0
  143. package/ethos.md +13 -8
  144. package/examples/worker/README.md +96 -12
  145. package/examples/worker/src/index.ts +46 -1
  146. package/examples/worker/wrangler.jsonc +14 -1
  147. package/package.json +4 -5
  148. package/templates/node/.dockerignore +10 -0
  149. package/templates/node/.env.example +40 -3
  150. package/templates/node/AGENTS.md +11 -1
  151. package/templates/node/Dockerfile +49 -0
  152. package/templates/node/README.md +117 -2
  153. package/templates/node/docker-compose.yml +39 -0
  154. package/templates/node/package.json +1 -1
  155. package/templates/node/src/file-activity.ts +182 -0
  156. package/templates/node/src/index.ts +80 -4
  157. package/assets/connecta-clay-hero.png +0 -0
  158. package/dist/access-tokens.d.ts.map +0 -1
  159. package/dist/access-tokens.js.map +0 -1
  160. package/dist/activity.d.ts.map +0 -1
  161. package/dist/activity.js.map +0 -1
  162. package/dist/apps-shell.d.ts.map +0 -1
  163. package/dist/apps-shell.js.map +0 -1
  164. package/dist/auth/bearer.d.ts.map +0 -1
  165. package/dist/auth/bearer.js.map +0 -1
  166. package/dist/auth/clerk.d.ts.map +0 -1
  167. package/dist/auth/clerk.js.map +0 -1
  168. package/dist/auth/downstream-oauth.d.ts.map +0 -1
  169. package/dist/auth/downstream-oauth.js.map +0 -1
  170. package/dist/call-admission.d.ts.map +0 -1
  171. package/dist/call-admission.js.map +0 -1
  172. package/dist/catalog-fingerprint.d.ts.map +0 -1
  173. package/dist/catalog-fingerprint.js.map +0 -1
  174. package/dist/catalog-limits.d.ts.map +0 -1
  175. package/dist/catalog-limits.js.map +0 -1
  176. package/dist/catalog-service.d.ts.map +0 -1
  177. package/dist/catalog-service.js.map +0 -1
  178. package/dist/catalog.d.ts.map +0 -1
  179. package/dist/catalog.js.map +0 -1
  180. package/dist/concurrency.d.ts.map +0 -1
  181. package/dist/concurrency.js.map +0 -1
  182. package/dist/connector-scope.d.ts.map +0 -1
  183. package/dist/connector-scope.js.map +0 -1
  184. package/dist/connectors/api.d.ts.map +0 -1
  185. package/dist/connectors/api.js.map +0 -1
  186. package/dist/connectors/remote-mcp.d.ts.map +0 -1
  187. package/dist/connectors/remote-mcp.js.map +0 -1
  188. package/dist/credentials.d.ts.map +0 -1
  189. package/dist/credentials.js.map +0 -1
  190. package/dist/errors.d.ts.map +0 -1
  191. package/dist/errors.js.map +0 -1
  192. package/dist/execute.d.ts.map +0 -1
  193. package/dist/execute.js.map +0 -1
  194. package/dist/executor-admission.d.ts.map +0 -1
  195. package/dist/executor-admission.js.map +0 -1
  196. package/dist/executor-result.d.ts.map +0 -1
  197. package/dist/executor-result.js.map +0 -1
  198. package/dist/executors/quickjs-child.d.ts.map +0 -1
  199. package/dist/executors/quickjs-child.js.map +0 -1
  200. package/dist/executors/quickjs-protocol.d.ts.map +0 -1
  201. package/dist/executors/quickjs-protocol.js.map +0 -1
  202. package/dist/executors/quickjs-runtime.d.ts.map +0 -1
  203. package/dist/executors/quickjs-runtime.js.map +0 -1
  204. package/dist/executors/quickjs.d.ts.map +0 -1
  205. package/dist/executors/quickjs.js.map +0 -1
  206. package/dist/favicon.d.ts.map +0 -1
  207. package/dist/favicon.js.map +0 -1
  208. package/dist/index.d.ts.map +0 -1
  209. package/dist/index.js.map +0 -1
  210. package/dist/invocation.d.ts.map +0 -1
  211. package/dist/invocation.js.map +0 -1
  212. package/dist/json-schema.d.ts.map +0 -1
  213. package/dist/json-schema.js.map +0 -1
  214. package/dist/mcp-result.d.ts.map +0 -1
  215. package/dist/mcp-result.js.map +0 -1
  216. package/dist/meta-tools.d.ts.map +0 -1
  217. package/dist/meta-tools.js.map +0 -1
  218. package/dist/node.d.ts.map +0 -1
  219. package/dist/node.js.map +0 -1
  220. package/dist/operator-ui/generated.d.ts.map +0 -1
  221. package/dist/operator-ui/generated.js.map +0 -1
  222. package/dist/operator-ui/model.d.ts.map +0 -1
  223. package/dist/operator-ui/model.js.map +0 -1
  224. package/dist/providers/cloudflare.d.ts.map +0 -1
  225. package/dist/providers/cloudflare.js.map +0 -1
  226. package/dist/providers/linear.d.ts.map +0 -1
  227. package/dist/providers/linear.js.map +0 -1
  228. package/dist/providers/mixpanel.d.ts.map +0 -1
  229. package/dist/providers/mixpanel.js.map +0 -1
  230. package/dist/providers/notion.d.ts.map +0 -1
  231. package/dist/providers/notion.js.map +0 -1
  232. package/dist/providers/stripe.d.ts.map +0 -1
  233. package/dist/providers/stripe.js.map +0 -1
  234. package/dist/registry.d.ts.map +0 -1
  235. package/dist/registry.js.map +0 -1
  236. package/dist/retired-toolkits.d.ts.map +0 -1
  237. package/dist/retired-toolkits.js.map +0 -1
  238. package/dist/routes/access-tokens.d.ts.map +0 -1
  239. package/dist/routes/access-tokens.js.map +0 -1
  240. package/dist/routes/activity.d.ts.map +0 -1
  241. package/dist/routes/activity.js.map +0 -1
  242. package/dist/routes/credentials.d.ts.map +0 -1
  243. package/dist/routes/credentials.js.map +0 -1
  244. package/dist/routes/mcp.d.ts.map +0 -1
  245. package/dist/routes/mcp.js.map +0 -1
  246. package/dist/routes/oauth.d.ts.map +0 -1
  247. package/dist/routes/oauth.js.map +0 -1
  248. package/dist/routes/shared.d.ts.map +0 -1
  249. package/dist/routes/shared.js.map +0 -1
  250. package/dist/routes/ui.d.ts.map +0 -1
  251. package/dist/routes/ui.js.map +0 -1
  252. package/dist/server.d.ts.map +0 -1
  253. package/dist/server.js.map +0 -1
  254. package/dist/skills.d.ts.map +0 -1
  255. package/dist/skills.js.map +0 -1
  256. package/dist/storage/file.d.ts.map +0 -1
  257. package/dist/storage/file.js.map +0 -1
  258. package/dist/storage/memory.d.ts.map +0 -1
  259. package/dist/storage/memory.js.map +0 -1
  260. package/dist/timeout.d.ts.map +0 -1
  261. package/dist/timeout.js.map +0 -1
  262. package/dist/tool-safety.d.ts.map +0 -1
  263. package/dist/tool-safety.js.map +0 -1
  264. package/dist/types.d.ts.map +0 -1
  265. package/dist/types.js.map +0 -1
  266. package/dist/ui.d.ts.map +0 -1
  267. package/dist/ui.js.map +0 -1
  268. package/dist/validate.d.ts.map +0 -1
  269. package/dist/validate.js.map +0 -1
  270. package/dist/version.d.ts.map +0 -1
  271. package/dist/version.js.map +0 -1
  272. package/examples/node/README.md +0 -52
  273. package/examples/node/src/index.ts +0 -71
  274. package/src/access-tokens.ts +0 -289
  275. package/src/activity.ts +0 -234
  276. package/src/apps-shell.ts +0 -370
  277. package/src/auth/bearer.ts +0 -61
  278. package/src/auth/clerk.ts +0 -553
  279. package/src/auth/downstream-oauth.ts +0 -575
  280. package/src/call-admission.ts +0 -521
  281. package/src/catalog-fingerprint.ts +0 -52
  282. package/src/catalog-limits.ts +0 -11
  283. package/src/catalog-service.ts +0 -1153
  284. package/src/catalog.ts +0 -790
  285. package/src/concurrency.ts +0 -39
  286. package/src/connector-scope.ts +0 -66
  287. package/src/connectors/api.ts +0 -159
  288. package/src/connectors/remote-mcp.ts +0 -1090
  289. package/src/credentials.ts +0 -428
  290. package/src/errors.ts +0 -364
  291. package/src/execute.ts +0 -1406
  292. package/src/executor-admission.ts +0 -328
  293. package/src/executor-result.ts +0 -107
  294. package/src/executors/quickjs-child.ts +0 -172
  295. package/src/executors/quickjs-protocol.ts +0 -99
  296. package/src/executors/quickjs-runtime.ts +0 -470
  297. package/src/executors/quickjs.ts +0 -776
  298. package/src/favicon.ts +0 -53
  299. package/src/index.ts +0 -666
  300. package/src/invocation.ts +0 -655
  301. package/src/json-schema.ts +0 -11
  302. package/src/mcp-result.ts +0 -43
  303. package/src/meta-tools.ts +0 -1607
  304. package/src/node.ts +0 -206
  305. package/src/operator-ui/browser.css +0 -423
  306. package/src/operator-ui/browser.ts +0 -1281
  307. package/src/operator-ui/generated.ts +0 -4
  308. package/src/operator-ui/model.ts +0 -111
  309. package/src/providers/cloudflare.ts +0 -3999
  310. package/src/providers/linear.ts +0 -302
  311. package/src/providers/mixpanel.ts +0 -229
  312. package/src/providers/notion.ts +0 -1879
  313. package/src/providers/stripe.ts +0 -307
  314. package/src/registry.ts +0 -1085
  315. package/src/retired-toolkits.ts +0 -14
  316. package/src/routes/access-tokens.ts +0 -115
  317. package/src/routes/activity.ts +0 -215
  318. package/src/routes/credentials.ts +0 -254
  319. package/src/routes/mcp.ts +0 -429
  320. package/src/routes/oauth.ts +0 -322
  321. package/src/routes/shared.ts +0 -247
  322. package/src/routes/ui.ts +0 -152
  323. package/src/server.ts +0 -195
  324. package/src/skills.ts +0 -271
  325. package/src/storage/file.ts +0 -123
  326. package/src/storage/memory.ts +0 -44
  327. package/src/timeout.ts +0 -84
  328. package/src/tool-safety.ts +0 -15
  329. package/src/types.ts +0 -523
  330. package/src/ui.ts +0 -744
  331. package/src/validate.ts +0 -387
  332. package/src/version.ts +0 -7
@@ -0,0 +1,289 @@
1
+ /**
2
+ * The mechanical half of a hand-written connector's HTTP transport.
3
+ *
4
+ * Every `api()` surface that speaks HTTP re-derives the same handful of safety
5
+ * properties: the request lands inside the base URL and nowhere else, the
6
+ * credential rides exactly one origin, an unreachable provider becomes a typed
7
+ * failure instead of a raw `TypeError`, and the response is read with a
8
+ * ceiling on it. Cloudflare and Notion each grew a private copy of that
9
+ * machinery, subtly different in ways neither author intended, and a third
10
+ * author would have grown a third.
11
+ *
12
+ * What this deliberately does not own is *meaning*. It never reads a status
13
+ * code, never decides a 403 is recoverable, and never invents an
14
+ * authentication scheme: `authenticate` supplies the headers, and the caller's
15
+ * mapper reads the response. That split is not fastidiousness — Notion's 403
16
+ * (a capability the integration was never granted, which re-authorizing cannot
17
+ * fix) and Cloudflare's 403 (a token scope) want opposite next moves, and no
18
+ * shared helper can tell them apart without provider knowledge it has no
19
+ * business holding.
20
+ *
21
+ * Web APIs only: this is reachable from the root entry and stays that way.
22
+ */
23
+ import { ConnectorCallError } from "../errors.js";
24
+ /** Statuses that instruct a client to re-send somewhere else. Never followed. */
25
+ const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
26
+ /** Statuses the HTTP spec defines as carrying no body at all. */
27
+ const BODILESS_STATUSES = new Set([204, 205, 304]);
28
+ const decoder = new TextDecoder();
29
+ const encoder = new TextEncoder();
30
+ /**
31
+ * A base URL is deployment configuration, so a bad one is a structural mistake
32
+ * and throws where it is written rather than on the first call that uses it.
33
+ */
34
+ function confinementBase(provider, baseUrl) {
35
+ let base;
36
+ try {
37
+ base = new URL(baseUrl);
38
+ }
39
+ catch {
40
+ throw new Error(`${provider} baseUrl must be an absolute URL: ${baseUrl}`);
41
+ }
42
+ const loopback = base.hostname === "localhost" ||
43
+ base.hostname === "127.0.0.1" ||
44
+ base.hostname === "[::1]";
45
+ if (base.protocol !== "https:" && !(base.protocol === "http:" && loopback)) {
46
+ throw new Error(`${provider} baseUrl must be https (http is allowed only for a loopback proxy or test double): ${baseUrl}`);
47
+ }
48
+ if (base.username || base.password) {
49
+ throw new Error(`${provider} baseUrl must not embed URL credentials; authentication belongs in headers.`);
50
+ }
51
+ if (base.search || base.hash) {
52
+ throw new Error(`${provider} baseUrl must not carry a query or fragment: ${baseUrl}`);
53
+ }
54
+ return base;
55
+ }
56
+ /**
57
+ * Resolve a provider-relative path beneath the base and prove it stayed there.
58
+ *
59
+ * The proof is the point. `new URL` normalizes `..` and percent-escapes for
60
+ * us, which is convenient and also exactly how a path escapes its prefix, so
61
+ * the origin and prefix are re-checked *after* normalization rather than
62
+ * before it.
63
+ */
64
+ function confinedUrl(provider, base, basePath, request) {
65
+ const path = request.path;
66
+ if (!path.startsWith("/")) {
67
+ throw new ConnectorCallError("invalid_args", `A ${provider} request path is provider-relative and must begin with "/".`);
68
+ }
69
+ if (path.includes("?") || path.includes("#")) {
70
+ throw new ConnectorCallError("invalid_args", `A ${provider} request path carries no query or fragment; put query parameters in the query argument.`);
71
+ }
72
+ let url;
73
+ try {
74
+ url = new URL(`${base.origin}${basePath}${path}`);
75
+ }
76
+ catch {
77
+ throw new ConnectorCallError("invalid_args", `A ${provider} request path did not resolve to a valid URL.`);
78
+ }
79
+ if (url.origin !== base.origin ||
80
+ !`${url.pathname}/`.startsWith(`${basePath}/`)) {
81
+ throw new ConnectorCallError("invalid_args", `A ${provider} request path escaped the connector's base URL.`);
82
+ }
83
+ for (const [key, value] of Object.entries(request.query ?? {})) {
84
+ if (value === undefined)
85
+ continue;
86
+ url.searchParams.set(key, String(value));
87
+ }
88
+ return url;
89
+ }
90
+ function oversized(provider, limit, detail) {
91
+ return new ConnectorCallError("connector_call_failed", `${provider} returned ${detail}, past this connector's ${limit}-byte response ceiling.`, { retryable: false });
92
+ }
93
+ /** The response body as a `ReadableStream`, or null when there is none to read. */
94
+ function readableBody(response) {
95
+ const body = response.body;
96
+ return body && typeof body.getReader === "function"
97
+ ? body
98
+ : null;
99
+ }
100
+ /** Read a stream to the ceiling and stop there — never past it. */
101
+ async function drain(provider, stream, limit) {
102
+ const reader = stream.getReader();
103
+ const chunks = [];
104
+ let total = 0;
105
+ try {
106
+ while (true) {
107
+ const { done, value } = await reader.read();
108
+ if (done)
109
+ break;
110
+ if (!value)
111
+ continue;
112
+ total += value.byteLength;
113
+ if (total > limit) {
114
+ await reader.cancel().catch(() => { });
115
+ throw oversized(provider, limit, "more bytes than it may");
116
+ }
117
+ chunks.push(value);
118
+ }
119
+ }
120
+ finally {
121
+ reader.releaseLock();
122
+ }
123
+ const body = new Uint8Array(total);
124
+ let offset = 0;
125
+ for (const chunk of chunks) {
126
+ body.set(chunk, offset);
127
+ offset += chunk.byteLength;
128
+ }
129
+ return body;
130
+ }
131
+ /**
132
+ * Wrap a `Response` in the bounded read surface.
133
+ *
134
+ * Three paths, for one honest reason. A status the spec says carries no body
135
+ * is answered as empty without touching the response at all. Otherwise, when
136
+ * the runtime hands back a readable body — every real response on Node and on
137
+ * Workers — the ceiling is enforced *while* reading, so an oversized payload
138
+ * is abandoned rather than buffered. When it does not, there is nothing to
139
+ * meter mid-flight: `bytes()` and `text()` read the body whole and check the
140
+ * ceiling against what came back, and `json()` — with no bytes of its own to
141
+ * count — takes the stand-in at its word. That last path is the weaker
142
+ * guarantee and says so, but a real `fetch` Response with a body always
143
+ * streams, so it is not a path a provider takes in production; it is what a
144
+ * hand-built test double gets.
145
+ */
146
+ function boundedResponse(provider, response, limit) {
147
+ if (BODILESS_STATUSES.has(response.status)) {
148
+ return {
149
+ status: response.status,
150
+ ok: response.ok,
151
+ headers: response.headers,
152
+ bytes: async () => new Uint8Array(),
153
+ text: async () => "",
154
+ json: async () => undefined,
155
+ };
156
+ }
157
+ const stream = readableBody(response);
158
+ let read;
159
+ const bytes = () => {
160
+ read ??= stream
161
+ ? drain(provider, stream, limit)
162
+ : response.arrayBuffer().then((buffer) => {
163
+ if (buffer.byteLength > limit) {
164
+ throw oversized(provider, limit, `${buffer.byteLength} bytes`);
165
+ }
166
+ return new Uint8Array(buffer);
167
+ });
168
+ return read;
169
+ };
170
+ return {
171
+ status: response.status,
172
+ ok: response.ok,
173
+ headers: response.headers,
174
+ bytes,
175
+ async text() {
176
+ if (stream)
177
+ return decoder.decode(await bytes());
178
+ const body = await response.text();
179
+ const size = encoder.encode(body).length;
180
+ if (size > limit)
181
+ throw oversized(provider, limit, `${size} bytes`);
182
+ return body;
183
+ },
184
+ async json() {
185
+ // No stream means no bytes to count: a stand-in that answers `json()`
186
+ // directly is taken at its word, which is the one accessor on the one
187
+ // path where the ceiling cannot be applied.
188
+ if (!stream)
189
+ return await response.json();
190
+ const body = decoder.decode(await bytes());
191
+ return body.trim() === "" ? undefined : JSON.parse(body);
192
+ },
193
+ };
194
+ }
195
+ /**
196
+ * Build the guarded transport one hand-written connector sends every request
197
+ * through.
198
+ *
199
+ * ```ts
200
+ * const send = guardedFetch({
201
+ * provider: "Billing",
202
+ * baseUrl: "https://billing.internal.example/v1",
203
+ * maxResponseBytes: 4 * 1024 * 1024,
204
+ * headers: { Accept: "application/json" },
205
+ * authenticate: async (ctx) => {
206
+ * const token = await ctx.credential?.get();
207
+ * if (!token) throw new ConnectorCallError("auth_required", "…");
208
+ * return { Authorization: `Bearer ${token}` };
209
+ * },
210
+ * });
211
+ *
212
+ * const invoice = await send({ method: "GET", path: `/invoices/${id}` }, ctx, (response) => {
213
+ * if (!response.ok) throw billingFailure(response.status);
214
+ * return response.json();
215
+ * });
216
+ * ```
217
+ */
218
+ export function guardedFetch(options) {
219
+ const { provider, maxResponseBytes: limit } = options;
220
+ if (!Number.isInteger(limit) || limit < 1) {
221
+ throw new Error(`${provider} maxResponseBytes must be a whole number of bytes >= 1; received ${String(limit)}.`);
222
+ }
223
+ const base = confinementBase(provider, options.baseUrl);
224
+ // "" for a root base, so joining never doubles the separator.
225
+ const basePath = base.pathname.replace(/\/+$/, "");
226
+ const constantHeaders = { ...options.headers };
227
+ return async function send(request, ctx, map) {
228
+ if (request.body !== undefined && request.rawBody !== undefined) {
229
+ throw new Error(`A ${provider} request cannot carry both a JSON body and a raw body.`);
230
+ }
231
+ const url = confinedUrl(provider, base, basePath, request);
232
+ const headers = { ...constantHeaders };
233
+ for (const [name, value] of Object.entries(request.headers ?? {})) {
234
+ if (value !== undefined)
235
+ headers[name] = value;
236
+ }
237
+ if (request.body !== undefined && !hasHeader(headers, "content-type")) {
238
+ headers["Content-Type"] = "application/json";
239
+ }
240
+ // Authentication is applied last and may not be shadowed. A caller-shaped
241
+ // header that reaches this point wearing the credential's name is a bug
242
+ // worth failing on, not a precedence question worth resolving quietly.
243
+ for (const [name, value] of Object.entries(await options.authenticate(ctx))) {
244
+ const shadow = hasHeader(headers, name);
245
+ if (shadow) {
246
+ throw new ConnectorCallError("invalid_args", `A ${provider} request may not set the ${shadow} header; authentication is connector-owned.`);
247
+ }
248
+ headers[name] = value;
249
+ }
250
+ let response;
251
+ try {
252
+ response = await fetch(url.toString(), {
253
+ method: request.method,
254
+ headers,
255
+ ...(request.body !== undefined
256
+ ? { body: JSON.stringify(request.body) }
257
+ : request.rawBody !== undefined
258
+ ? { body: request.rawBody }
259
+ : {}),
260
+ // Never follow a redirect. A 3xx is an instruction to re-send the
261
+ // connector's credential to whatever origin the Location names, and a
262
+ // confinement a redirect can undo was never a confinement. There is no
263
+ // ambient credential to omit besides that — neither runtime's `fetch`
264
+ // keeps a cookie jar — so the headers `authenticate` returned are the
265
+ // only authority the request carries.
266
+ redirect: "manual",
267
+ ...(ctx.signal ? { signal: ctx.signal } : {}),
268
+ });
269
+ }
270
+ catch (cause) {
271
+ throw new ConnectorCallError("unavailable", `Could not reach the ${provider} API: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
272
+ }
273
+ if (REDIRECT_STATUSES.has(response.status)) {
274
+ await response.body?.cancel().catch(() => { });
275
+ throw new ConnectorCallError("connector_call_failed", `${provider} answered HTTP ${response.status} with a redirect; this connector talks to exactly one origin and never forwards its credential to another.`, { retryable: false });
276
+ }
277
+ const declared = Number(response.headers.get("content-length"));
278
+ if (Number.isFinite(declared) && declared > limit) {
279
+ await response.body?.cancel().catch(() => { });
280
+ throw oversized(provider, limit, `a declared ${declared} bytes`);
281
+ }
282
+ return await map(boundedResponse(provider, response, limit), ctx);
283
+ };
284
+ }
285
+ /** The stored spelling of a header already present, case-insensitively. */
286
+ function hasHeader(headers, name) {
287
+ const wanted = name.toLowerCase();
288
+ return Object.keys(headers).find((key) => key.toLowerCase() === wanted);
289
+ }
@@ -90,4 +90,3 @@ export declare function redirectSafeFetch(connectorId: string, policy?: RemoteMc
90
90
  * server or hide other connectors).
91
91
  */
92
92
  export declare function remoteMcp(id: string, opts: RemoteMcpOptions): Connector;
93
- //# sourceMappingURL=remote-mcp.d.ts.map
@@ -848,4 +848,3 @@ export function remoteMcp(id, opts) {
848
848
  }
849
849
  return connector;
850
850
  }
851
- //# sourceMappingURL=remote-mcp.js.map
@@ -115,4 +115,3 @@ export declare class CredentialVault {
115
115
  delete(connectorId: string): Promise<void>;
116
116
  }
117
117
  export {};
118
- //# sourceMappingURL=credentials.d.ts.map
@@ -286,4 +286,3 @@ export class CredentialVault {
286
286
  await this.storage.delete(storageKey(connectorId));
287
287
  }
288
288
  }
289
- //# sourceMappingURL=credentials.js.map
package/dist/errors.d.ts CHANGED
@@ -146,4 +146,3 @@ export declare function framingError(code: string, message: string): CallErrorDe
146
146
  * heuristic.
147
147
  */
148
148
  export declare function classifyCallError(err: unknown, fallbackCode?: string): CallErrorDetails;
149
- //# sourceMappingURL=errors.d.ts.map
package/dist/errors.js CHANGED
@@ -220,4 +220,3 @@ export function classifyCallError(err, fallbackCode = "connector_call_failed") {
220
220
  retryable: RETRYABLE_MESSAGE_RE.test(message),
221
221
  };
222
222
  }
223
- //# sourceMappingURL=errors.js.map
package/dist/execute.d.ts CHANGED
@@ -191,4 +191,3 @@ export declare function registerExecuteTool(server: McpServer, registry: Registr
191
191
  maxEmittedBlocks?: number;
192
192
  }): void;
193
193
  export {};
194
- //# sourceMappingURL=execute.d.ts.map
package/dist/execute.js CHANGED
@@ -1019,4 +1019,3 @@ export function registerExecuteTool(server, registry, ctx) {
1019
1019
  }
1020
1020
  });
1021
1021
  }
1022
- //# sourceMappingURL=execute.js.map
@@ -69,10 +69,20 @@ export declare class AdmissionController {
69
69
  }
70
70
  /** Preserve the one-method Workers seam while recognizing richer Node executors. */
71
71
  export declare function isAdmittingExecutor(executor: Executor): executor is AdmittingExecutor;
72
+ /**
73
+ * Best-effort name for the configured sandbox, for `/health` and through it
74
+ * `connecta doctor` — which otherwise has to guess, and guessed QuickJS at
75
+ * every deployment including the Workers one ([#368]). The executor seam is
76
+ * structural, so this reads what is already there: an explicit `name`, else
77
+ * the constructor name a class-shaped executor carries for free. The value is
78
+ * a stranger's string bound for a public response body and an operator's
79
+ * terminal, so it is sanitized rather than trusted; nothing identifiable
80
+ * reports nothing, and doctor says so instead of naming a sandbox.
81
+ */
82
+ export declare function executorName(executor: Executor): string | undefined;
72
83
  /**
73
84
  * Give a structurally-compatible but otherwise unbounded executor the same
74
85
  * admission contract as the built-in Node executor. The wrapper owns only the
75
86
  * queue; closing the underlying runtime remains the Connecta lifecycle's job.
76
87
  */
77
88
  export declare function withExecutorAdmission(executor: Executor, admission: AdmissionController): AdmittingExecutor;
78
- //# sourceMappingURL=executor-admission.d.ts.map
@@ -205,6 +205,34 @@ export function isAdmittingExecutor(executor) {
205
205
  return ("acquire" in executor &&
206
206
  typeof executor.acquire === "function");
207
207
  }
208
+ /** Terminal- and JSON-safe upper bound for an executor's self-reported name. */
209
+ const MAX_EXECUTOR_NAME_LENGTH = 40;
210
+ /**
211
+ * Best-effort name for the configured sandbox, for `/health` and through it
212
+ * `connecta doctor` — which otherwise has to guess, and guessed QuickJS at
213
+ * every deployment including the Workers one ([#368]). The executor seam is
214
+ * structural, so this reads what is already there: an explicit `name`, else
215
+ * the constructor name a class-shaped executor carries for free. The value is
216
+ * a stranger's string bound for a public response body and an operator's
217
+ * terminal, so it is sanitized rather than trusted; nothing identifiable
218
+ * reports nothing, and doctor says so instead of naming a sandbox.
219
+ */
220
+ export function executorName(executor) {
221
+ const declared = executor.name;
222
+ const ctor = executor.constructor;
223
+ const raw = typeof declared === "string" && declared.trim()
224
+ ? declared
225
+ : typeof ctor?.name === "string" && ctor.name !== "Object"
226
+ ? ctor.name
227
+ : "";
228
+ const cleaned = raw
229
+ .replace(/[^\w .+-]+/g, " ")
230
+ .replace(/\s+/g, " ")
231
+ .trim()
232
+ .slice(0, MAX_EXECUTOR_NAME_LENGTH)
233
+ .trim();
234
+ return cleaned || undefined;
235
+ }
208
236
  /**
209
237
  * Give a structurally-compatible but otherwise unbounded executor the same
210
238
  * admission contract as the built-in Node executor. The wrapper owns only the
@@ -238,4 +266,3 @@ export function withExecutorAdmission(executor, admission) {
238
266
  admissionSnapshot: () => admission.snapshot(),
239
267
  };
240
268
  }
241
- //# sourceMappingURL=executor-admission.js.map
@@ -7,4 +7,3 @@ export declare function truncateExecuteText(text: string, max: number): string;
7
7
  * IPC. The parent repeats the guard for third-party Executor implementations.
8
8
  */
9
9
  export declare function prepareExecuteResultForTransport(outcome: ExecuteResult): ExecuteResult;
10
- //# sourceMappingURL=executor-result.d.ts.map
@@ -85,4 +85,3 @@ export function prepareExecuteResultForTransport(outcome) {
85
85
  };
86
86
  }
87
87
  }
88
- //# sourceMappingURL=executor-result.js.map
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=quickjs-child.d.ts.map
@@ -128,4 +128,3 @@ process.on("disconnect", () => process.exit(0));
128
128
  // child that never becomes ready.
129
129
  await prepareQuickJs();
130
130
  send({ type: "ready" });
131
- //# sourceMappingURL=quickjs-child.js.map
@@ -68,4 +68,3 @@ export declare function hostCallLabel(payload: {
68
68
  }): string;
69
69
  export declare function serializedBytes(text: string): number;
70
70
  export declare function stringifyBounded(value: unknown, label: string, limit?: number): string;
71
- //# sourceMappingURL=quickjs-protocol.d.ts.map
@@ -36,4 +36,3 @@ export function stringifyBounded(value, label, limit = MAX_QUICKJS_IPC_BYTES) {
36
36
  }
37
37
  return json;
38
38
  }
39
- //# sourceMappingURL=quickjs-protocol.js.map
@@ -23,4 +23,3 @@ export interface QuickJsExecutionResult extends ExecuteResult {
23
23
  * driving QuickJS, so a slow downstream does not consume the short CPU budget.
24
24
  */
25
25
  export declare function executeQuickJs(code: string, providers: ExecutorProvider[], options: QuickJsRuntimeOptions): Promise<QuickJsExecutionResult>;
26
- //# sourceMappingURL=quickjs-runtime.d.ts.map
@@ -401,4 +401,3 @@ export async function executeQuickJs(code, providers, options) {
401
401
  }
402
402
  return finish(outcome);
403
403
  }
404
- //# sourceMappingURL=quickjs-runtime.js.map
@@ -28,4 +28,3 @@ export interface QuickJsExecutorOptions {
28
28
  * double-acquire deadlock at concurrency 1.
29
29
  */
30
30
  export declare function quickJsExecutor(options?: QuickJsExecutorOptions): AdmittingExecutor;
31
- //# sourceMappingURL=quickjs.d.ts.map
@@ -102,6 +102,8 @@ function waitForReady(ready, signal) {
102
102
  });
103
103
  }
104
104
  class QuickJsChildPool {
105
+ /** What `/health` and `connecta doctor` call this sandbox (#368). */
106
+ name = "QuickJS";
105
107
  admission;
106
108
  slots;
107
109
  available;
@@ -535,4 +537,3 @@ class QuickJsChildPool {
535
537
  export function quickJsExecutor(options = {}) {
536
538
  return new QuickJsChildPool(options);
537
539
  }
538
- //# sourceMappingURL=quickjs.js.map
package/dist/favicon.d.ts CHANGED
@@ -1,2 +1 @@
1
1
  export declare const CONNECTA_FAVICON_ICO: Uint8Array<ArrayBufferLike>;
2
- //# sourceMappingURL=favicon.d.ts.map
package/dist/favicon.js CHANGED
@@ -46,4 +46,3 @@ function buildIco() {
46
46
  return ico;
47
47
  }
48
48
  export const CONNECTA_FAVICON_ICO = buildIco();
49
- //# sourceMappingURL=favicon.js.map
package/dist/index.d.ts CHANGED
@@ -192,7 +192,6 @@ export { CONNECTA_VERSION } from "./version.js";
192
192
  export type { Registry } from "./registry.js";
193
193
  export type { RemoteMcpOptions, RemoteMcpAuth, RemoteMcpRedirectPolicy, } from "./connectors/remote-mcp.js";
194
194
  export type { ApiOptions, ApiTool } from "./connectors/api.js";
195
- export type { Connector, ConnectorCallAdmissionInput, ConnectorCallAdmissionPolicy, ConnectorCallAdmissionRule, ConnectorRollingWindowBudget, ConnectaBranding, ConnectorCredentialAccess, ConnectorCredentialConfig, ConnectorCredentialFieldConfig, ConnectorCredentialValues, ConnectorContext, ConnectorUsageGuide, ConnectorStatus, CredentialTestResult, AdmittingExecutor, AdmissionSnapshot, ExecuteResult, Executor, ExecutorLease, ExecutorProvider, InboundAuth, UiAuthConfig, AuthResult, JsonSchema, KVStorage, Logger, ToolDef, ToolAnnotations, } from "./types.js";
196
- export type { ActivityActor, ActivityCallSource, ActivityOutcome, ActivityPage, ActivityReadActor, ActivityReadEvent, ActivityReader, ActivityReadGate, ActivityReadPage, ActivitySink, ActivityStore, AgentFriction, ToolCallActivityEvent, } from "./activity.js";
195
+ export type { CatalogDriftCounts, CatalogDriftReport, Connector, ConnectorCallAdmissionInput, ConnectorCallAdmissionPolicy, ConnectorCallAdmissionRule, ConnectorRollingWindowBudget, ConnectaBranding, ConnectorCredentialAccess, ConnectorCredentialConfig, ConnectorCredentialFieldConfig, ConnectorCredentialValues, ConnectorContext, ConnectorUsageGuide, ConnectorStatus, CredentialTestResult, AdmittingExecutor, AdmissionSnapshot, ExecuteResult, Executor, ExecutorLease, ExecutorProvider, InboundAuth, UiAuthConfig, AuthResult, JsonSchema, KVStorage, Logger, ToolDef, ToolAnnotations, } from "./types.js";
196
+ export type { ActivityActor, ActivityCallSource, ActivityOutcome, ActivityPage, ActivityReadActor, ActivityReadEvent, ActivityReader, ActivityReadGate, ActivityReadPage, ActivitySink, ActivityStore, AgentFriction, CatalogDriftActivityEvent, ToolCallActivityEvent, } from "./activity.js";
197
197
  export { InvalidActivityCursorError } from "./activity.js";
198
- //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import { createFetchHandler } from "./server.js";
5
5
  import { droppedBrandingUrls, droppedUiAuthUrls } from "./ui.js";
6
6
  import { memoryStorage } from "./storage/memory.js";
7
7
  import { CONNECTA_VERSION } from "./version.js";
8
- import { AdmissionController, isAdmittingExecutor, withExecutorAdmission, } from "./executor-admission.js";
8
+ import { AdmissionController, executorName, isAdmittingExecutor, withExecutorAdmission, } from "./executor-admission.js";
9
9
  const REQUEST_ADMISSION_DEFAULTS = {
10
10
  concurrency: 16,
11
11
  maxQueueSize: 32,
@@ -225,10 +225,26 @@ export function createConnecta(config) {
225
225
  throw new Error("accessTokens requires a Clerk auth provider: only an eligible Clerk " +
226
226
  "operator may create, rename, or revoke deployment access tokens");
227
227
  }
228
+ const serverInfo = {
229
+ ...config.serverInfo,
230
+ name: config.serverInfo?.name ?? "connecta",
231
+ version: config.serverInfo?.version ?? CONNECTA_VERSION,
232
+ };
228
233
  const registry = new Registry(config.connectors, {
229
234
  storage,
230
235
  logger,
231
236
  ...(credentialVault !== undefined ? { credentialVault } : {}),
237
+ ...(config.activity?.store !== undefined
238
+ ? {
239
+ catalogDriftActivity: {
240
+ sink: config.activity.store,
241
+ serverInfo,
242
+ ...(config.activity.deploymentId !== undefined
243
+ ? { deploymentId: config.activity.deploymentId }
244
+ : {}),
245
+ },
246
+ }
247
+ : {}),
232
248
  ...(config.discovery?.catalogTtlSeconds !== undefined
233
249
  ? { toolCacheTtlSeconds: config.discovery.catalogTtlSeconds }
234
250
  : {}),
@@ -248,6 +264,9 @@ export function createConnecta(config) {
248
264
  const configuredCodeAdmission = admissionController(config.admission?.code, CODE_ADMISSION_DEFAULTS);
249
265
  let codeAdmission;
250
266
  let executor = config.executor;
267
+ // Read the identity off the configured executor, before any wrapper hides
268
+ // it behind an anonymous object literal.
269
+ const configuredExecutorName = executorName(executor);
251
270
  if (!isAdmittingExecutor(executor)) {
252
271
  codeAdmission = configuredCodeAdmission;
253
272
  executor = withExecutorAdmission(executor, codeAdmission);
@@ -261,11 +280,7 @@ export function createConnecta(config) {
261
280
  registry,
262
281
  auth: inboundAuth,
263
282
  ...(config.publicUrl !== undefined ? { publicUrl: config.publicUrl } : {}),
264
- serverInfo: {
265
- ...config.serverInfo,
266
- name: config.serverInfo?.name ?? "connecta",
267
- version: config.serverInfo?.version ?? CONNECTA_VERSION,
268
- },
283
+ serverInfo,
269
284
  logger,
270
285
  ...(config.activity?.store !== undefined
271
286
  ? { activity: config.activity.store }
@@ -277,6 +292,9 @@ export function createConnecta(config) {
277
292
  ? { activityDeploymentId: config.activity.deploymentId }
278
293
  : {}),
279
294
  executor,
295
+ ...(configuredExecutorName !== undefined
296
+ ? { executorName: configuredExecutorName }
297
+ : {}),
280
298
  requestAdmission,
281
299
  ...(config.calls?.defaultTimeoutMs !== undefined
282
300
  ? { defaultToolTimeoutMs: config.calls.defaultTimeoutMs }
@@ -328,4 +346,3 @@ export { bearerToken } from "./auth/bearer.js";
328
346
  export { memoryStorage } from "./storage/memory.js";
329
347
  export { CONNECTA_VERSION } from "./version.js";
330
348
  export { InvalidActivityCursorError } from "./activity.js";
331
- //# sourceMappingURL=index.js.map
@@ -105,4 +105,3 @@ export declare class InvocationService {
105
105
  private invokeWithResolution;
106
106
  }
107
107
  export {};
108
- //# sourceMappingURL=invocation.d.ts.map
@@ -457,4 +457,3 @@ export class InvocationService {
457
457
  }
458
458
  }
459
459
  }
460
- //# sourceMappingURL=invocation.js.map
@@ -1,3 +1,2 @@
1
1
  export { Validator } from "@cfworker/json-schema";
2
2
  export type { OutputUnit, Schema, SchemaDraft, ValidationResult, } from "@cfworker/json-schema";
3
- //# sourceMappingURL=json-schema.d.ts.map
@@ -3,4 +3,3 @@
3
3
  // its own output, say) resolves the same implementation and version through an
4
4
  // explicit subpath rather than through npm hoisting.
5
5
  export { Validator } from "@cfworker/json-schema";
6
- //# sourceMappingURL=json-schema.js.map
@@ -6,4 +6,3 @@ import type { Connector } from "./types.js";
6
6
  * Non-MCP connectors already return plain values.
7
7
  */
8
8
  export declare function unwrapMcpResult(kind: Connector["kind"], result: unknown): unknown;
9
- //# sourceMappingURL=mcp-result.d.ts.map
@@ -32,4 +32,3 @@ export function unwrapMcpResult(kind, result) {
32
32
  }
33
33
  return result;
34
34
  }
35
- //# sourceMappingURL=mcp-result.js.map
@@ -136,4 +136,3 @@ export declare function registerMetaTools(server: McpServer, registry: RegistryV
136
136
  activity?: ActivityRequestContext;
137
137
  requestSignal?: AbortSignal;
138
138
  }): void;
139
- //# sourceMappingURL=meta-tools.d.ts.map
@@ -1178,4 +1178,3 @@ export function registerMetaTools(server, registry, ctx) {
1178
1178
  _meta: { ui: { visibility: ["model"] } },
1179
1179
  }, async (args) => mt.getResult(args));
1180
1180
  }
1181
- //# sourceMappingURL=meta-tools.js.map
package/dist/node.d.ts CHANGED
@@ -25,4 +25,3 @@ export interface ListenOptions {
25
25
  * dependencies beyond node core.
26
26
  */
27
27
  export declare function listen(connecta: Connecta, portOrOptions: number | ListenOptions): Server;
28
- //# sourceMappingURL=node.d.ts.map
package/dist/node.js CHANGED
@@ -166,4 +166,3 @@ export function listen(connecta, portOrOptions) {
166
166
  server.listen(opts.port);
167
167
  return server;
168
168
  }
169
- //# sourceMappingURL=node.js.map