@zackbart/connecta 0.34.0 → 0.35.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 (428) hide show
  1. package/CHANGELOG.md +393 -0
  2. package/README.md +62 -105
  3. package/SECURITY.md +3 -2
  4. package/bin/connecta.mjs +41 -16
  5. package/bin/version.mjs +1 -1
  6. package/dist/access-tokens.d.ts +2 -1
  7. package/dist/access-tokens.js +66 -30
  8. package/dist/activity.d.ts +1 -1
  9. package/dist/activity.js +2 -0
  10. package/dist/agent-config.d.ts +23 -0
  11. package/dist/agent-config.js +59 -0
  12. package/dist/agent-description.js +16 -0
  13. package/dist/agent-identity.js +4 -4
  14. package/dist/agent-observation.js +39 -0
  15. package/dist/auth/clerk-sdk/client.d.ts +2 -0
  16. package/dist/auth/clerk-sdk/generated.js +554 -563
  17. package/dist/auth/clerk-transport.js +70 -3
  18. package/dist/auth/clerk.d.ts +13 -0
  19. package/dist/auth/clerk.js +653 -246
  20. package/dist/auth/cloudflare-access.js +46 -42
  21. package/dist/auth/downstream-client-metadata.js +2 -2
  22. package/dist/auth/downstream-oauth.js +2051 -1160
  23. package/dist/auth/downstream-revocation.js +88 -88
  24. package/dist/auth/native-call.js +20 -0
  25. package/dist/auth/native.js +184 -0
  26. package/dist/auth/oauth-start-reset.js +11 -5
  27. package/dist/auth/oauth-token-response.js +121 -102
  28. package/dist/auth/oauth-v2-migration.js +97 -78
  29. package/dist/auth/renewable-grant.js +10 -0
  30. package/dist/auth/static-oauth.js +663 -271
  31. package/dist/auth/vercel-agent.js +266 -0
  32. package/dist/auth-admission.js +204 -0
  33. package/dist/auth-elicitation.js +350 -241
  34. package/dist/authorization-handoff.js +164 -90
  35. package/dist/call-admission-context.js +3 -10
  36. package/dist/call-admission.js +2 -0
  37. package/dist/call-classification.js +9 -0
  38. package/dist/call-recovery.js +32 -13
  39. package/dist/canonical-json.js +8 -0
  40. package/dist/catalog-cache.js +369 -213
  41. package/dist/catalog-service.js +659 -530
  42. package/dist/catalog.js +5 -1
  43. package/dist/concurrency.js +0 -25
  44. package/dist/config-defaults.d.ts +1 -0
  45. package/dist/config-defaults.js +1 -0
  46. package/dist/config-schema.d.ts +3 -1
  47. package/dist/config-schema.js +13 -3
  48. package/dist/config.d.ts +40 -6
  49. package/dist/config.js +40 -26
  50. package/dist/connector-caller.d.ts +4 -0
  51. package/dist/connector-caller.js +17 -4
  52. package/dist/connectors/api-connector.d.ts +15 -7
  53. package/dist/connectors/api-connector.js +147 -57
  54. package/dist/connectors/guarded-fetch.d.ts +51 -17
  55. package/dist/connectors/guarded-fetch.js +215 -121
  56. package/dist/connectors/negotiation-cache.js +20 -10
  57. package/dist/connectors/option-shapes.js +1 -1
  58. package/dist/connectors/remote-mcp.d.ts +12 -30
  59. package/dist/connectors/remote-mcp.js +960 -564
  60. package/dist/d1.js +10 -243
  61. package/dist/derived-context.js +5 -0
  62. package/dist/describe-config.d.ts +5 -1
  63. package/dist/describe-config.js +3 -0
  64. package/dist/downstream-input.js +347 -260
  65. package/dist/errors.d.ts +87 -6
  66. package/dist/errors.js +114 -4
  67. package/dist/execute.js +87 -50
  68. package/dist/executor-admission.js +3 -0
  69. package/dist/executors/quickjs.js +163 -112
  70. package/dist/guarded-transport.js +50 -0
  71. package/dist/guest-runtime.js +1 -1
  72. package/dist/http/client.js +439 -0
  73. package/dist/http/errors.js +558 -0
  74. package/dist/http/fields.js +49 -0
  75. package/dist/http/hatch-paging.js +318 -0
  76. package/dist/http/hatch.js +1279 -0
  77. package/dist/http/json-schema.js +267 -0
  78. package/dist/http/node-transport.js +241 -0
  79. package/dist/http/oauth.js +162 -0
  80. package/dist/http/paging.js +228 -0
  81. package/dist/http/provider.js +221 -0
  82. package/dist/http/safety.js +82 -0
  83. package/dist/http/services.js +79 -0
  84. package/dist/http/tools.js +383 -0
  85. package/dist/http/vendor-index.js +138 -0
  86. package/dist/http/vendor.js +448 -0
  87. package/dist/http/write-request.js +66 -0
  88. package/dist/http-policy.d.ts +11 -0
  89. package/dist/http-policy.js +45 -0
  90. package/dist/inbound-credential.js +1 -1
  91. package/dist/index.d.ts +2 -2
  92. package/dist/index.js +4 -0
  93. package/dist/invocation-auth.js +30 -19
  94. package/dist/invocation.js +221 -87
  95. package/dist/mcp-result.js +0 -4
  96. package/dist/membership.d.ts +4 -0
  97. package/dist/meta-output.js +1 -1
  98. package/dist/meta-tools.js +534 -408
  99. package/dist/native-recovery.js +52 -0
  100. package/dist/native-tools.js +382 -0
  101. package/dist/node.d.ts +4 -3
  102. package/dist/node.js +45 -8
  103. package/dist/oauth-handoff.js +177 -104
  104. package/dist/oauth-partition.js +6 -20
  105. package/dist/oauth-sealing.js +6 -7
  106. package/dist/operation-vocabulary.js +101 -0
  107. package/dist/operator-record.d.ts +2 -2
  108. package/dist/operator-record.js +17 -4
  109. package/dist/operator-ui/agents.d.ts +5 -4
  110. package/dist/operator-ui/agents.js +17 -7
  111. package/dist/operator-ui/config-summary.js +8 -4
  112. package/dist/operator-ui/connection-map.js +9 -6
  113. package/dist/operator-ui/contract.d.ts +7 -3
  114. package/dist/operator-ui/endpoints.js +5 -14
  115. package/dist/operator-ui/fix-prompts.d.ts +1 -1
  116. package/dist/operator-ui/fix-prompts.js +0 -8
  117. package/dist/operator-ui/generated.js +3 -3
  118. package/dist/operator-ui/health.js +52 -0
  119. package/dist/operator-ui/model.d.ts +2 -3
  120. package/dist/operator-ui/overview.js +11 -19
  121. package/dist/operator-ui/setup-commands.js +0 -4
  122. package/dist/operator-ui/view.d.ts +5 -29
  123. package/dist/operator-ui/view.js +3 -59
  124. package/dist/program-writes.js +47 -26
  125. package/dist/provider-call-facts.d.ts +115 -0
  126. package/dist/provider-call-facts.js +182 -0
  127. package/dist/provider-call.d.ts +112 -0
  128. package/dist/provider-call.js +271 -0
  129. package/dist/provider.d.ts +71 -32
  130. package/dist/provider.js +134 -40
  131. package/dist/providers/_shared/google/hatch.js +91 -0
  132. package/dist/providers/_shared/google/kit.js +537 -0
  133. package/dist/providers/_shared/google/result-size.js +15 -2
  134. package/dist/providers/_shared/google/service-account.d.ts +2 -1
  135. package/dist/providers/_shared/google/service-account.js +8 -4
  136. package/dist/providers/_shared/google/workspace.d.ts +8 -209
  137. package/dist/providers/_shared/google/workspace.js +7 -426
  138. package/dist/providers/_shared/rest/compact-index.js +86 -0
  139. package/dist/providers/_shared/rest/dispatch.js +3 -23
  140. package/dist/providers/_shared/rest/kit.js +546 -0
  141. package/dist/providers/_shared/rest/operation-index.js +230 -14
  142. package/dist/providers/_shared/rest/response-media.js +11 -0
  143. package/dist/providers/_shared/rest/tools.js +101 -78
  144. package/dist/providers/_shared/rest/value-safety.js +353 -195
  145. package/dist/providers/_shared/sensitive-fields.js +27 -0
  146. package/dist/providers/breeze/api.js +584 -0
  147. package/dist/providers/breeze/index.d.ts +3 -3
  148. package/dist/providers/breeze/index.js +67 -1420
  149. package/dist/providers/breeze/openapi.generated.js +60 -0
  150. package/dist/providers/breeze/skill.generated.js +2 -6
  151. package/dist/providers/breeze/tools.js +696 -0
  152. package/dist/providers/ccb/api.js +496 -0
  153. package/dist/providers/ccb/index.d.ts +17 -37
  154. package/dist/providers/ccb/index.js +77 -1702
  155. package/dist/providers/ccb/lib/constants.d.ts +34 -0
  156. package/dist/providers/ccb/lib/constants.js +74 -0
  157. package/dist/providers/ccb/lib/guide.js +9 -0
  158. package/dist/providers/ccb/lib/verdicts.js +387 -0
  159. package/dist/providers/ccb/openapi.generated.js +397 -0
  160. package/dist/providers/ccb/safety.js +295 -0
  161. package/dist/providers/ccb/skill.generated.js +2 -6
  162. package/dist/providers/ccb/tools.js +853 -0
  163. package/dist/providers/cloudflare/api.js +1066 -0
  164. package/dist/providers/cloudflare/index.d.ts +7 -22
  165. package/dist/providers/cloudflare/index.js +80 -194
  166. package/dist/providers/cloudflare/lib/config.d.ts +16 -0
  167. package/dist/providers/cloudflare/lib/config.js +2 -0
  168. package/dist/providers/cloudflare/lib/discovery.js +29 -0
  169. package/dist/providers/cloudflare/{graphql.js → lib/graphql.js} +1 -1
  170. package/dist/providers/cloudflare/lib/hatch.js +103 -0
  171. package/dist/providers/cloudflare/lib/path-bounds.js +28 -0
  172. package/dist/providers/cloudflare/lib/response-media.js +75 -0
  173. package/dist/providers/cloudflare/openapi.generated.js +3299 -3208
  174. package/dist/providers/cloudflare/{value-safety.js → safety.js} +538 -18
  175. package/dist/providers/cloudflare/skill.generated.js +2 -10
  176. package/dist/providers/cloudflare/tools.js +360 -0
  177. package/dist/providers/docs/api.js +51 -0
  178. package/dist/providers/docs/index.d.ts +1 -12
  179. package/dist/providers/docs/index.js +53 -1165
  180. package/dist/providers/docs/lib/constants.d.ts +18 -0
  181. package/dist/providers/docs/lib/constants.js +18 -0
  182. package/dist/providers/docs/lib/discovery.js +26 -0
  183. package/dist/providers/docs/lib/requests.js +48 -0
  184. package/dist/providers/docs/lib/schemas.js +168 -0
  185. package/dist/providers/docs/openapi.generated.js +16 -0
  186. package/dist/providers/docs/safety.js +54 -0
  187. package/dist/providers/docs/skill.generated.js +2 -6
  188. package/dist/providers/docs/tools.js +802 -0
  189. package/dist/providers/drive/api.js +177 -0
  190. package/dist/providers/drive/index.d.ts +1 -12
  191. package/dist/providers/drive/index.js +38 -1448
  192. package/dist/providers/drive/lib/constants.d.ts +6 -0
  193. package/dist/providers/drive/lib/constants.js +6 -0
  194. package/dist/providers/drive/lib/contracts.js +532 -0
  195. package/dist/providers/drive/lib/hatch.js +197 -0
  196. package/dist/providers/drive/openapi.generated.js +77 -0
  197. package/dist/providers/drive/safety.js +90 -0
  198. package/dist/providers/drive/skill.generated.js +2 -6
  199. package/dist/providers/drive/tools.js +1290 -0
  200. package/dist/providers/forms/api.js +71 -0
  201. package/dist/providers/forms/index.d.ts +1 -12
  202. package/dist/providers/forms/index.js +49 -1145
  203. package/dist/providers/forms/lib/constants.d.ts +14 -0
  204. package/dist/providers/forms/lib/constants.js +19 -0
  205. package/dist/providers/forms/lib/hatch.js +72 -0
  206. package/dist/providers/forms/openapi.generated.js +23 -0
  207. package/dist/providers/forms/safety.js +34 -0
  208. package/dist/providers/forms/skill.generated.js +2 -8
  209. package/dist/providers/forms/tools.js +1024 -0
  210. package/dist/providers/github/api.js +150 -0
  211. package/dist/providers/github/index.d.ts +4 -5
  212. package/dist/providers/github/index.js +30 -87
  213. package/dist/providers/github/{auth.d.ts → lib/auth.d.ts} +5 -3
  214. package/dist/providers/github/{auth.js → lib/auth.js} +40 -43
  215. package/dist/providers/github/lib/discovery.js +132 -0
  216. package/dist/providers/github/lib/operations.js +58 -0
  217. package/dist/providers/github/{scope.d.ts → lib/scope.d.ts} +2 -0
  218. package/dist/providers/github/{scope.js → lib/scope.js} +25 -1
  219. package/dist/providers/github/openapi.generated.js +1216 -0
  220. package/dist/providers/github/safety.js +216 -0
  221. package/dist/providers/github/skill.generated.js +2 -5
  222. package/dist/providers/github/tools.js +506 -0
  223. package/dist/providers/gmail/api.js +114 -0
  224. package/dist/providers/gmail/index.d.ts +1 -12
  225. package/dist/providers/gmail/index.js +73 -1621
  226. package/dist/providers/gmail/lib/constants.d.ts +13 -0
  227. package/dist/providers/gmail/lib/constants.js +16 -0
  228. package/dist/providers/gmail/lib/index.js +173 -0
  229. package/dist/providers/gmail/lib/schemas.js +176 -0
  230. package/dist/providers/gmail/lib/threading.js +120 -0
  231. package/dist/providers/gmail/openapi.generated.js +92 -0
  232. package/dist/providers/gmail/safety.js +21 -0
  233. package/dist/providers/gmail/skill.generated.js +2 -6
  234. package/dist/providers/gmail/tools.js +1435 -0
  235. package/dist/providers/overflow/api.js +1008 -0
  236. package/dist/providers/overflow/index.d.ts +3 -17
  237. package/dist/providers/overflow/index.js +60 -1488
  238. package/dist/providers/overflow/skill.generated.js +2 -5
  239. package/dist/providers/overflow/tools.js +873 -0
  240. package/dist/providers/planning-center/api.js +467 -0
  241. package/dist/providers/planning-center/index.d.ts +6 -35
  242. package/dist/providers/planning-center/index.js +69 -2445
  243. package/dist/providers/planning-center/lib/constants.d.ts +58 -0
  244. package/dist/providers/planning-center/lib/constants.js +83 -0
  245. package/dist/providers/planning-center/lib/discovery.js +40 -0
  246. package/dist/providers/planning-center/lib/guide.js +39 -0
  247. package/dist/providers/planning-center/lib/json-api.js +83 -0
  248. package/dist/providers/planning-center/lib/verdicts.js +1758 -0
  249. package/dist/providers/planning-center/openapi.generated.js +1764 -0
  250. package/dist/providers/planning-center/safety.js +188 -0
  251. package/dist/providers/planning-center/skill.generated.js +2 -27
  252. package/dist/providers/planning-center/tools.js +1010 -0
  253. package/dist/providers/sheets/api.js +133 -0
  254. package/dist/providers/sheets/index.d.ts +4 -16
  255. package/dist/providers/sheets/index.js +61 -1172
  256. package/dist/providers/sheets/lib/constants.d.ts +14 -0
  257. package/dist/providers/sheets/lib/constants.js +14 -0
  258. package/dist/providers/sheets/lib/hatch.js +163 -0
  259. package/dist/providers/sheets/lib/requests.js +105 -0
  260. package/dist/providers/sheets/lib/schemas.js +138 -0
  261. package/dist/providers/sheets/openapi.generated.js +30 -0
  262. package/dist/providers/sheets/safety.js +27 -0
  263. package/dist/providers/sheets/skill.generated.js +2 -7
  264. package/dist/providers/sheets/tools.js +734 -0
  265. package/dist/providers/slides/api.js +147 -0
  266. package/dist/providers/slides/index.d.ts +2 -10
  267. package/dist/providers/slides/index.js +48 -2555
  268. package/dist/providers/slides/lib/constants.d.ts +11 -0
  269. package/dist/providers/slides/lib/constants.js +11 -0
  270. package/dist/providers/slides/lib/requests.js +60 -0
  271. package/dist/providers/slides/lib/schemas.js +565 -0
  272. package/dist/providers/slides/openapi.generated.js +18 -0
  273. package/dist/providers/slides/skill.generated.js +2 -6
  274. package/dist/providers/slides/tools.js +1968 -0
  275. package/dist/providers/stripe/api.js +401 -0
  276. package/dist/providers/stripe/index.d.ts +7 -27
  277. package/dist/providers/stripe/index.js +75 -191
  278. package/dist/providers/stripe/lib/config.d.ts +4 -0
  279. package/dist/providers/stripe/lib/config.js +2 -0
  280. package/dist/providers/stripe/openapi.generated.js +4 -3
  281. package/dist/providers/stripe/{value-safety.js → safety.js} +5 -5
  282. package/dist/providers/stripe/skill.generated.js +2 -10
  283. package/dist/providers/stripe/tools.js +77 -0
  284. package/dist/providers/tithely/api.js +531 -0
  285. package/dist/providers/tithely/index.d.ts +19 -0
  286. package/dist/providers/tithely/index.js +86 -965
  287. package/dist/providers/tithely/skill.generated.js +2 -5
  288. package/dist/providers/tithely/tools.js +426 -0
  289. package/dist/providers/vercel/api.js +551 -0
  290. package/dist/providers/vercel/index.d.ts +11 -25
  291. package/dist/providers/vercel/index.js +67 -261
  292. package/dist/providers/vercel/lib/config.d.ts +2 -0
  293. package/dist/providers/vercel/lib/config.js +2 -0
  294. package/dist/providers/vercel/lib/index.js +117 -0
  295. package/dist/providers/vercel/lib/logs.js +100 -0
  296. package/dist/providers/vercel/lib/pin.js +270 -0
  297. package/dist/providers/vercel/openapi.generated.js +398 -376
  298. package/dist/providers/vercel/{value-safety.js → safety.js} +261 -42
  299. package/dist/providers/vercel/skill.generated.js +2 -7
  300. package/dist/providers/vercel/tools.js +642 -0
  301. package/dist/redaction-identity.js +47 -0
  302. package/dist/redaction-marker.js +125 -0
  303. package/dist/registry.d.ts +30 -28
  304. package/dist/registry.js +446 -413
  305. package/dist/routes/access-tokens.js +1 -1
  306. package/dist/routes/actor-labels.js +1 -1
  307. package/dist/routes/connect.js +1 -1
  308. package/dist/routes/dispatch.js +103 -0
  309. package/dist/routes/mcp.js +170 -79
  310. package/dist/routes/oauth.js +3 -1
  311. package/dist/routes/operator.js +2 -2
  312. package/dist/routes/shared.d.ts +5 -4
  313. package/dist/routes/shared.js +244 -177
  314. package/dist/routes/skills.js +10 -8
  315. package/dist/routes/ui-config.js +27 -3
  316. package/dist/routes/ui-data.js +29 -22
  317. package/dist/routes/ui.js +1 -1
  318. package/dist/runtime/call-admission.js +0 -26
  319. package/dist/runtime/call-entry.js +30 -0
  320. package/dist/runtime/call.js +556 -0
  321. package/dist/runtime/connector-scope.js +7 -0
  322. package/dist/runtime/credential-probe.js +34 -0
  323. package/dist/runtime/executor.js +40 -0
  324. package/dist/runtime/native-storage.js +63 -0
  325. package/dist/runtime/registry.js +27 -0
  326. package/dist/runtime/request-scope.js +72 -0
  327. package/dist/runtime/run.js +15 -7
  328. package/dist/runtime/shared-read.js +34 -5
  329. package/dist/runtime/storage.js +34 -21
  330. package/dist/sent-secrets.d.ts +194 -37
  331. package/dist/sent-secrets.js +1743 -340
  332. package/dist/server.js +5 -56
  333. package/dist/skills.js +330 -224
  334. package/dist/sqlite.js +15 -14
  335. package/dist/storage/d1-copy.js +255 -0
  336. package/dist/storage/d1-driver.js +15 -0
  337. package/dist/storage/keys.js +28 -0
  338. package/dist/storage/sql-driver.js +88 -0
  339. package/dist/storage/sql-native.js +544 -0
  340. package/dist/storage/sql-schema.d.ts +6 -0
  341. package/dist/storage/sql-schema.js +15 -0
  342. package/dist/storage/sql.d.ts +14 -20
  343. package/dist/storage/sql.js +29 -535
  344. package/dist/timeout.js +0 -26
  345. package/dist/tool-safety.js +20 -10
  346. package/dist/types.d.ts +11 -99
  347. package/dist/upward.js +3 -0
  348. package/dist/usage-guide.js +3 -1
  349. package/dist/validate.d.ts +4 -2
  350. package/dist/validate.js +86 -9
  351. package/dist/version.d.ts +1 -1
  352. package/dist/version.js +1 -1
  353. package/dist/worker.js +312 -292
  354. package/dist/workspace-subject.js +5 -1
  355. package/dist/write-outcome.js +454 -34
  356. package/documentation/README.md +27 -7
  357. package/documentation/architecture.md +2550 -186
  358. package/documentation/auth.md +821 -98
  359. package/documentation/code-mode.md +56 -21
  360. package/documentation/deploying.md +164 -20
  361. package/documentation/hosted-mcp-migration.md +460 -0
  362. package/documentation/integrating.md +144 -105
  363. package/documentation/meta-tools.md +411 -34
  364. package/documentation/operating.md +28 -4
  365. package/documentation/operator-tests.md +11 -2
  366. package/documentation/operator-ui.md +103 -33
  367. package/documentation/provider-auth-migration.md +38 -63
  368. package/documentation/provider-migration-0.29.md +10 -5
  369. package/documentation/provider-migration-0.35.md +975 -0
  370. package/documentation/providers.md +965 -0
  371. package/examples/worker/AGENTS.md +23 -9
  372. package/examples/worker/README.md +254 -135
  373. package/examples/worker/alchemy.run.ts +116 -0
  374. package/examples/worker/gitignore +10 -0
  375. package/examples/worker/src/connecta.config.ts +23 -21
  376. package/examples/worker/wrangler.jsonc +14 -5
  377. package/guides/connecting-agents.md +157 -0
  378. package/guides/how-it-works.md +156 -0
  379. package/guides/safety-and-trust.md +153 -0
  380. package/package.json +27 -42
  381. package/templates/node/.env.example +3 -0
  382. package/templates/node/README.md +22 -2
  383. package/templates/node/docker-compose.yml +1 -0
  384. package/templates/node/package.json +3 -2
  385. package/templates/node/src/connecta.config.ts +8 -0
  386. package/dist/catalog-drift.d.ts +0 -134
  387. package/dist/catalog-drift.js +0 -493
  388. package/dist/providers/_shared/request-token.js +0 -83
  389. package/dist/providers/_shared/rest/operation-index.d.ts +0 -133
  390. package/dist/providers/_shared/rest/tools.d.ts +0 -141
  391. package/dist/providers/_shared/rest/value-safety.d.ts +0 -201
  392. package/dist/providers/basecamp/index.d.ts +0 -43
  393. package/dist/providers/basecamp/index.js +0 -997
  394. package/dist/providers/basecamp/skill.generated.js +0 -9
  395. package/dist/providers/cloudflare/rest.d.ts +0 -37
  396. package/dist/providers/cloudflare/rest.js +0 -1078
  397. package/dist/providers/github/hosted.js +0 -218
  398. package/dist/providers/github/rest.js +0 -321
  399. package/dist/providers/infisical/index.d.ts +0 -7
  400. package/dist/providers/infisical/index.js +0 -713
  401. package/dist/providers/infisical/skill.generated.js +0 -8
  402. package/dist/providers/linear/index.d.ts +0 -55
  403. package/dist/providers/linear/index.js +0 -352
  404. package/dist/providers/linear/skill.generated.js +0 -8
  405. package/dist/providers/mixpanel/index.d.ts +0 -57
  406. package/dist/providers/mixpanel/index.js +0 -468
  407. package/dist/providers/mixpanel/operations.js +0 -20
  408. package/dist/providers/mixpanel/rest.js +0 -603
  409. package/dist/providers/mixpanel/skill.generated.js +0 -10
  410. package/dist/providers/mixpanel/value-safety.js +0 -16
  411. package/dist/providers/notion/index.d.ts +0 -65
  412. package/dist/providers/notion/index.js +0 -368
  413. package/dist/providers/notion/openapi.generated.js +0 -75
  414. package/dist/providers/notion/rest.d.ts +0 -24
  415. package/dist/providers/notion/rest.js +0 -1226
  416. package/dist/providers/notion/skill.generated.js +0 -11
  417. package/dist/providers/notion/value-safety.js +0 -56
  418. package/dist/providers/revenuecat/index.d.ts +0 -49
  419. package/dist/providers/revenuecat/index.js +0 -557
  420. package/dist/providers/revenuecat/skill.generated.js +0 -11
  421. package/dist/providers/stripe/rest.d.ts +0 -14
  422. package/dist/providers/stripe/rest.js +0 -402
  423. package/dist/providers/vercel/rest.d.ts +0 -20
  424. package/dist/providers/vercel/rest.js +0 -1020
  425. package/dist/providers/wispr-flow/index.d.ts +0 -14
  426. package/dist/providers/wispr-flow/index.js +0 -117
  427. package/dist/providers/wispr-flow/skill.generated.js +0 -8
  428. /package/dist/providers/github/{key.js → lib/key.js} +0 -0
@@ -0,0 +1,52 @@
1
+ /** Adapt only Connecta error envelopes; successful downstream payloads stay untouched. */
2
+ export function nativeRecovery(result, executeCode, wireName) {
3
+ const response = result;
4
+ const body = response?.structuredContent;
5
+ if (!response?.isError || !body || typeof body.error !== "object" || !body.error)
6
+ return result;
7
+ const error = { ...body.error };
8
+ const action = error.nextAction;
9
+ if (action?.tool === "search_tools" || (!action && error.code === "unknown_tool")) {
10
+ error.nextAction = {
11
+ host: "search",
12
+ arguments: { query: action?.arguments?.query ?? wireName },
13
+ purpose: action?.purpose,
14
+ };
15
+ }
16
+ else if (action?.tool === "authorize_connector") {
17
+ const url = error.authorizationUrl ?? error.operatorUrl;
18
+ error.nextAction = url
19
+ ? { url, purpose: "Give this handoff to the user or operator." }
20
+ : { operator: "Check connector authentication in deployment configuration." };
21
+ }
22
+ else if (action?.tool === "call_tool" || action?.tool === "call_destructive_tool") {
23
+ error.nextAction = wireName
24
+ ? {
25
+ tool: wireName,
26
+ arguments: action.arguments?.args ?? {},
27
+ purpose: `${action.purpose ?? "Retry the original native call."}${action.arguments?.argsRedacted ? " Resend the original arguments; sensitive fields were omitted." : ""}`,
28
+ }
29
+ : { host: "search", purpose: action.purpose };
30
+ }
31
+ // These are Connecta-authored recovery fields, never arbitrary downstream data.
32
+ const rewrite = (text) => text.replace(/authorize_connector|search_tools|call_(?:destructive_)?tool|execute_code/g, (tool) => tool === "authorize_connector"
33
+ ? "the returned authorization handoff"
34
+ : tool.startsWith("call_")
35
+ ? "the original native tool"
36
+ : tool === "execute_code" && executeCode
37
+ ? tool
38
+ : "your host's tool search");
39
+ for (const key of ["message", "instructions", "retry"])
40
+ if (typeof error[key] === "string")
41
+ error[key] = rewrite(error[key]);
42
+ if (wireName && typeof error.operation === "string" && typeof error.retry === "string")
43
+ error.retry = error.retry.replaceAll(rewrite(error.operation), wireName);
44
+ if (!executeCode && typeof error.instructions === "string") {
45
+ error.instructions = error.instructions.replace(/; connecta\.search[\s\S]*$/, ". Retry the original native call after recovery.");
46
+ }
47
+ return {
48
+ ...response,
49
+ structuredContent: { ...body, error },
50
+ content: [{ type: "text", text: JSON.stringify({ ...body, error }) }],
51
+ };
52
+ }
@@ -0,0 +1,382 @@
1
+ import { duringViewEffect } from "./runtime/call.js";
2
+ import { RequestScope, requestOwner } from "./runtime/request-scope.js";
3
+ import { Effect } from "effect";
4
+ import { upwardStep } from "./upward.js";
5
+ import { authCall, authInvoke, authFlow, authMethod, registerAuth, registerAuthMethod, authOwnMethod, } from "./auth/native.js";
6
+ import { runEdge } from "./runtime/run.js";
7
+ import { ProtocolError, } from "@modelcontextprotocol/server";
8
+ import { withAuthorizationHandoff } from "./authorization-handoff.js";
9
+ import { classifyCallError } from "./errors.js";
10
+ import { nativeRecovery } from "./native-recovery.js";
11
+ import { CatalogService } from "./catalog-service.js";
12
+ import { jsonResult } from "./meta-tools.js";
13
+ import { failureRecord, logFailure } from "./operator-record.js";
14
+ /**
15
+ * Longest native name. A client prefixes its own connection name, and common
16
+ * tool-name limits are 64 characters: Eve's `connecta__` and Claude Code's
17
+ * `mcp__connecta__` both fit beside 48.
18
+ */
19
+ export const NATIVE_NAME_MAX = 48;
20
+ /** One page, no cursor: Eve 0.83 reads only the first `tools/list` page. */
21
+ const MAX_NATIVE_TOOLS = 1_000;
22
+ /** Native `tools/list` cache hint. Shorter than the meta surface's hour: the list follows downstream catalogs. */
23
+ export const NATIVE_TOOLS_LIST_TTL_MS = 300_000;
24
+ const HASH_CHARS = 6;
25
+ const SEPARATOR = "__";
26
+ /** No `__`, no leading `_`: the last `__` of a plain name is then always its separator. */
27
+ const PLAIN_TOOL = /^[A-Za-z0-9-](?:[A-Za-z0-9-]|_(?!_))*$/;
28
+ const NATIVE_NAME = new RegExp(`^[A-Za-z][A-Za-z0-9_-]{0,${NATIVE_NAME_MAX - 1}}$`);
29
+ /** Connecta's own tools on a native endpoint. Their names never contain `__`. */
30
+ const NATIVE_OWN_TOOLS = ["execute_code", "skills", "read_result"];
31
+ const enc = new TextEncoder();
32
+ function shortHash(text) {
33
+ return runEdge(shortHashNative(text));
34
+ }
35
+ const shortHashNative = /* @__PURE__ */ registerAuth(shortHash, function (text) {
36
+ return authFlow(function* () {
37
+ const digest = new Uint8Array(yield* upwardStep(authInvoke(crypto.subtle, "digest", ["SHA-256", enc.encode(text)])));
38
+ return [...digest.subarray(0, HASH_CHARS / 2)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
39
+ });
40
+ });
41
+ /**
42
+ * The connector half of a native name. Connector ids are `[a-z0-9_-]+`; one
43
+ * that does not start with a letter gets an uppercase `C`, which no connector
44
+ * id can contain, so the prefix never collides with another id.
45
+ */
46
+ function connectorPart(connectorId) {
47
+ return /^[a-z]/.test(connectorId) ? connectorId : `C${connectorId}`;
48
+ }
49
+ /**
50
+ * A pure function of the connector id and downstream tool name, so it is
51
+ * stable across catalog refreshes: `<connector>__<tool>` when that is exact,
52
+ * legal and short, otherwise its head plus a six-hex SHA-256 suffix of the
53
+ * original pair.
54
+ */
55
+ export function nativeToolName(connectorId, toolName) {
56
+ return runEdge(nativeToolNameNative(connectorId, toolName));
57
+ }
58
+ const nativeToolNameNative = /* @__PURE__ */ registerAuth(nativeToolName, function (connectorId, toolName) {
59
+ return authFlow(function* () {
60
+ const tool = toolName.replace(/[^A-Za-z0-9_-]/g, "_");
61
+ const plain = `${connectorPart(connectorId)}${SEPARATOR}${tool}`;
62
+ if (tool === toolName && PLAIN_TOOL.test(tool) && plain.length <= NATIVE_NAME_MAX)
63
+ return plain;
64
+ const head = plain.slice(0, NATIVE_NAME_MAX - HASH_CHARS - 1).replace(/_+$/, "");
65
+ return `${head}_${yield* upwardStep(authCall(shortHash, [`${connectorId}.${toolName}`]))}`;
66
+ });
67
+ });
68
+ /** Read or write, from the served classification only. */
69
+ function annotationsFor(tool) {
70
+ return tool.classification === "read"
71
+ ? { readOnlyHint: true, destructiveHint: false, openWorldHint: true }
72
+ : { readOnlyHint: false, destructiveHint: true, openWorldHint: true };
73
+ }
74
+ /** Object arguments retain every applicable constraint, including local refs. */
75
+ function nativeInputSchema(schema) {
76
+ function supportsObject(value, seen = new Set()) {
77
+ if (value === true)
78
+ return true;
79
+ if (!value || typeof value !== "object" || Array.isArray(value) || seen.has(value))
80
+ return false;
81
+ const node = value;
82
+ const next = new Set(seen).add(value);
83
+ if (node.type !== undefined &&
84
+ node.type !== "object" &&
85
+ !(Array.isArray(node.type) && node.type.includes("object")))
86
+ return false;
87
+ if (node.$ref !== undefined) {
88
+ if (typeof node.$ref !== "string" || !node.$ref.startsWith("#/"))
89
+ return false;
90
+ let target = schema;
91
+ for (const part of node.$ref.slice(2).split("/")) {
92
+ if (!target || typeof target !== "object")
93
+ return false;
94
+ target = target[part.replace(/~1/g, "/").replace(/~0/g, "~")];
95
+ }
96
+ if (!supportsObject(target, next))
97
+ return false;
98
+ }
99
+ for (const key of ["anyOf", "oneOf", "allOf"]) {
100
+ const branches = node[key];
101
+ if (Array.isArray(branches) &&
102
+ !(key === "allOf"
103
+ ? branches.every((branch) => supportsObject(branch, next))
104
+ : branches.some((branch) => supportsObject(branch, next))))
105
+ return false;
106
+ }
107
+ return true;
108
+ }
109
+ if (!supportsObject(schema))
110
+ return undefined;
111
+ return schema.type === "object" ? schema : { ...schema, type: "object" };
112
+ }
113
+ /**
114
+ * The downstream input schema, advertised verbatim. Validation accepts
115
+ * anything: invocation validates against the same catalog definition and
116
+ * returns its structured `invalid_args` with repair, as call_tool does.
117
+ */
118
+ function passThroughSchema(schema) {
119
+ // Listing has already excluded connectors with unrepresentable schemas.
120
+ const json = schema === undefined ? { type: "object" } : nativeInputSchema(schema);
121
+ return {
122
+ "~standard": {
123
+ version: 1,
124
+ vendor: "connecta",
125
+ validate: (value) => ({ value }),
126
+ jsonSchema: { input: () => json, output: () => json },
127
+ },
128
+ };
129
+ }
130
+ function describe(entry, executeCode) {
131
+ const lines = [entry.tool.description?.trim() || entry.tool.title || entry.tool.name];
132
+ if (executeCode)
133
+ lines.push(`Program address: ${entry.connector.id}.${entry.tool.name}`);
134
+ return lines.join("\n\n");
135
+ }
136
+ export class NativeSurface {
137
+ registry;
138
+ options;
139
+ catalog;
140
+ constructor(registry, options) {
141
+ this.registry = registry;
142
+ this.options = options;
143
+ this.catalog = new CatalogService(registry, options.baseUrl, {
144
+ requestScope: options.requestScope,
145
+ requestSignal: options.requestSignal,
146
+ probeTimeoutMs: options.probeTimeoutMs,
147
+ concurrency: options.discoveryConcurrency,
148
+ // Listing omits a read-only endpoint's writes, as search does.
149
+ readOnly: options.readOnly,
150
+ defer: options.defer,
151
+ });
152
+ }
153
+ /**
154
+ * Every listable native tool. A connector whose catalog fails is omitted
155
+ * whole, never partially, with an operator warning; two tools claiming one
156
+ * name are both omitted and stay reachable by address in execute_code.
157
+ */
158
+ claims(connectors = this.registry.listConnectors()) {
159
+ return runEdge(authOwnMethod(NativeSurface.prototype, this, "claims", [connectors]));
160
+ }
161
+ list() {
162
+ return runEdge(authOwnMethod(NativeSurface.prototype, this, "list", []));
163
+ }
164
+ /**
165
+ * The downstream tool behind a native name, from the catalogs whose
166
+ * connector prefix the name could carry, including truncated prefixes. Resolution sees
167
+ * writes on a read-only endpoint, so invocation refuses them by code.
168
+ */
169
+ resolve(name) {
170
+ return runEdge(authOwnMethod(NativeSurface.prototype, this, "resolve", [name]));
171
+ }
172
+ /** A native call: the existing route its current verdict selects. */
173
+ call(name, args, request) {
174
+ return runEdge(authOwnMethod(NativeSurface.prototype, this, "call", [name, args, request]));
175
+ }
176
+ registerTool(server, name, entry) {
177
+ server.registerTool(name, {
178
+ ...(entry?.tool.title ? { title: entry.tool.title } : {}),
179
+ ...(entry ? { description: describe(entry, this.options.executeCode) } : {}),
180
+ inputSchema: passThroughSchema(entry?.tool.inputSchema),
181
+ ...(entry ? { annotations: annotationsFor(entry.tool) } : {}),
182
+ ...(entry ? { _meta: { "dev.connecta/address": `${entry.connector.id}.${entry.tool.name}` } } : {}),
183
+ }, authMethod((args, request) => Effect.gen({ self: this }, function* () {
184
+ const result = yield* authInvoke(this, "call", [name, args ?? {}, request]);
185
+ return nativeRecovery(result, this.options.executeCode, name);
186
+ })));
187
+ }
188
+ /**
189
+ * Register what this request needs before the SDK dispatches it: the whole
190
+ * listing for `tools/list`, the one called name for `tools/call` (resolved
191
+ * when it runs, so a catalog failure comes back as Connecta's structured
192
+ * error rather than "tool not found"), nothing otherwise.
193
+ */
194
+ register(server, hint) {
195
+ return runEdge(authOwnMethod(NativeSurface.prototype, this, "register", [server, hint]));
196
+ }
197
+ static {
198
+ registerAuthMethod(NativeSurface.prototype, "register", function (server, hint) {
199
+ const self = this;
200
+ return duringViewEffect({
201
+ requestScope: this.options.requestScope,
202
+ signal: this.options.requestSignal,
203
+ }, () => authFlow(function* () {
204
+ if (hint.method === "tools/call") {
205
+ if (NATIVE_NAME.test(hint.name) && !NATIVE_OWN_TOOLS.includes(hint.name))
206
+ self.registerTool(server, hint.name);
207
+ return;
208
+ }
209
+ if (hint.method !== "tools/list")
210
+ return;
211
+ const tools = yield* upwardStep(authInvoke(self, "list", []));
212
+ if (tools.length > MAX_NATIVE_TOOLS) {
213
+ logFailure(self.options.logger, "native tools/list refused a pool over the 1,000-tool native cap", failureRecord({}));
214
+ server.server.setRequestHandler("tools/list", () => {
215
+ throw new ProtocolError(-32603, `This endpoint has ${tools.length} tools, over the ${MAX_NATIVE_TOOLS}-tool native listing cap. Ask the operator to narrow the pool or use the meta surface.`);
216
+ });
217
+ return;
218
+ }
219
+ for (const entry of tools)
220
+ self.registerTool(server, entry.name, entry);
221
+ })).pipe(Effect.provideService(RequestScope, requestOwner(this.options.requestScope)));
222
+ }, NativeSurface.prototype.register);
223
+ registerAuthMethod(NativeSurface.prototype, "call", function (name, args, request) {
224
+ const self = this;
225
+ return duringViewEffect({
226
+ requestScope: this.options.requestScope,
227
+ signal: this.options.requestSignal,
228
+ }, () => authFlow(function* () {
229
+ self.options.bind(request);
230
+ const target = yield* upwardStep(authInvoke(self, "resolve", [name]));
231
+ if (target.kind !== "found") {
232
+ const failure = target.kind === "missing" ? target.failure : undefined;
233
+ const error = failure
234
+ ? {
235
+ ...classifyCallError(failure.cause, "catalog_lookup_failed"),
236
+ connector: failure.connector.id,
237
+ message: `Connector "${failure.connector.id}" catalog lookup failed.`,
238
+ }
239
+ : {
240
+ code: "unknown_tool",
241
+ message: target.kind === "ambiguous"
242
+ ? `Ambiguous native name "${name}". Ask the operator to rename a claimant.`
243
+ : `Unknown native tool "${name}".`,
244
+ retryable: false,
245
+ };
246
+ if (failure && (error.code === "auth_required" || error.code === "downstream_oauth_required")) {
247
+ error.nextAction = {
248
+ tool: "authorize_connector",
249
+ arguments: { connector: failure.connector.id },
250
+ operatorHandoff: "Give the returned handoff to the operator.",
251
+ };
252
+ }
253
+ const result = jsonResult({
254
+ ok: false,
255
+ error: yield* upwardStep(authCall(withAuthorizationHandoff, [self.options.requestScope, error])),
256
+ });
257
+ result.isError = true;
258
+ return result;
259
+ }
260
+ const address = `${target.entry.connector.id}.${target.entry.tool.name}`;
261
+ return yield* upwardStep(authInvoke(self.options, "route", [
262
+ target.entry.tool.classification === "read" ? "call_tool" : "call_destructive_tool",
263
+ { address, args },
264
+ request,
265
+ ]));
266
+ })).pipe(Effect.provideService(RequestScope, requestOwner(this.options.requestScope)));
267
+ }, NativeSurface.prototype.call);
268
+ registerAuthMethod(NativeSurface.prototype, "resolve", function (name) {
269
+ const self = this;
270
+ return duringViewEffect({
271
+ requestScope: this.options.requestScope,
272
+ signal: this.options.requestSignal,
273
+ }, () => authFlow(function* () {
274
+ const prefixed = self.registry.listConnectors().filter((connector) => {
275
+ const prefix = `${connectorPart(connector.id)}${SEPARATOR}`;
276
+ // A hashed name can truncate even the connector prefix, and strips
277
+ // trailing underscores from its head. Include every possible claimant.
278
+ const head = prefix.slice(0, NATIVE_NAME_MAX - HASH_CHARS - 1).replace(/_+$/, "");
279
+ // A hashed name carries a stripped head only as exactly `${head}_` + six hex digits.
280
+ return (name.startsWith(prefix) ||
281
+ (name.length === head.length + 1 + HASH_CHARS &&
282
+ name.startsWith(`${head}_`) &&
283
+ /^[0-9a-f]+$/.test(name.slice(-HASH_CHARS))));
284
+ });
285
+ const { loaded, byName } = yield* upwardStep(authInvoke(self, "claims", [prefixed]));
286
+ const found = byName.get(name);
287
+ if (found === null)
288
+ return { kind: "ambiguous" };
289
+ // An unavailable possible claimant cannot prove uniqueness.
290
+ for (const entry of loaded)
291
+ if ("error" in entry)
292
+ return { kind: "missing", failure: { connector: entry.connector, cause: entry.error } };
293
+ return found ? { kind: "found", entry: found } : { kind: "missing" };
294
+ })).pipe(Effect.provideService(RequestScope, requestOwner(this.options.requestScope)));
295
+ }, NativeSurface.prototype.resolve);
296
+ registerAuthMethod(NativeSurface.prototype, "list", function () {
297
+ const self = this;
298
+ return duringViewEffect({
299
+ requestScope: this.options.requestScope,
300
+ signal: this.options.requestSignal,
301
+ }, () => authFlow(function* () {
302
+ const { loaded, byName } = yield* upwardStep(authInvoke(self, "claims", []));
303
+ for (const entry of loaded) {
304
+ // Validate the whole connector before registering any of its tools.
305
+ const tool = "tools" in entry
306
+ ? entry.tools.find((tool) => tool.inputSchema !== undefined && !nativeInputSchema(tool.inputSchema))
307
+ : undefined;
308
+ if (!("error" in entry) && !tool)
309
+ continue;
310
+ self.options.catalogErrors.push(entry.connector.id);
311
+ logFailure(self.options.logger, "native catalog unavailable", failureRecord({ connector: entry.connector.id, ...(tool ? { tool } : {}) }, "error" in entry ? entry.error : undefined));
312
+ }
313
+ return [...byName.values()].filter((entry) => entry !== null &&
314
+ !self.options.catalogErrors.includes(entry.connector.id) &&
315
+ (!(self.options.readOnly || entry.connector.readOnly) || entry.tool.classification === "read"));
316
+ })).pipe(Effect.provideService(RequestScope, requestOwner(this.options.requestScope)));
317
+ }, NativeSurface.prototype.list);
318
+ registerAuthMethod(NativeSurface.prototype, "claims", function (connectors) {
319
+ const self = this;
320
+ return duringViewEffect({
321
+ requestScope: this.options.requestScope,
322
+ signal: this.options.requestSignal,
323
+ }, () => authFlow(function* () {
324
+ const loaded = yield* upwardStep(authInvoke(self.catalog, "listCatalogs", [true, connectors ?? self.registry.listConnectors()]));
325
+ const byName = new Map();
326
+ for (const entry of loaded) {
327
+ if (!("tools" in entry))
328
+ continue;
329
+ for (const tool of entry.tools) {
330
+ const name = yield* upwardStep(authCall(nativeToolName, [entry.connector.id, tool.name]));
331
+ if (byName.has(name)) {
332
+ byName.set(name, null);
333
+ logFailure(self.options.logger, "native name collision", failureRecord({ connector: entry.connector.id, tool }));
334
+ }
335
+ else
336
+ byName.set(name, { name, connector: entry.connector, tool });
337
+ }
338
+ }
339
+ return { loaded, byName };
340
+ })).pipe(Effect.provideService(RequestScope, requestOwner(this.options.requestScope)));
341
+ }, NativeSurface.prototype.claims);
342
+ }
343
+ }
344
+ /** Read the method and tool name a request carries, for {@link NativeSurface.register}. */
345
+ export function nativeRequestHint(request, modern) {
346
+ return runEdge(nativeRequestHintNative(request, modern));
347
+ }
348
+ const nativeRequestHintNative = /* @__PURE__ */ registerAuth(nativeRequestHint, function (request, modern) {
349
+ return authFlow(function* () {
350
+ let method;
351
+ let name;
352
+ if (modern) {
353
+ // The SDK checked both headers against the body before calling the factory.
354
+ method = request.headers.get("Mcp-Method")?.trim();
355
+ const header = request.headers.get("Mcp-Name")?.trim();
356
+ const encoded = header && /^=\?base64\?(.*)\?=$/.exec(header);
357
+ try {
358
+ name = encoded
359
+ ? new TextDecoder().decode(Uint8Array.from(atob(encoded[1]), (c) => c.charCodeAt(0)))
360
+ : header;
361
+ }
362
+ catch {
363
+ name = undefined;
364
+ }
365
+ }
366
+ else {
367
+ try {
368
+ const body = (yield* upwardStep(authInvoke(request.clone(), "json", [])));
369
+ method = body?.method;
370
+ name = body?.params?.name;
371
+ }
372
+ catch {
373
+ return { method: "other" };
374
+ }
375
+ }
376
+ if (method === "tools/list")
377
+ return { method };
378
+ if (method === "tools/call" && typeof name === "string")
379
+ return { method, name };
380
+ return { method: "other" };
381
+ });
382
+ });
package/dist/node.d.ts CHANGED
@@ -2,9 +2,11 @@ import type { Server } from "node:http";
2
2
  import type { Connecta } from "./index.js";
3
3
  export interface ListenOptions {
4
4
  port: number;
5
+ /** Explicit HTTP(S) CONNECT proxy for owned outbound sends. Never read from the environment. */
6
+ proxy?: string;
5
7
  /** Interface to bind. Defaults to Node's own (all interfaces). */
6
8
  host?: string;
7
- /** Reject request bodies larger than this with 413. Default 10 MiB. */
9
+ /** Pre-auth buffer cap, independent of the authenticated MCP cap. Default 4 MiB. */
8
10
  maxBodyBytes?: number;
9
11
  /**
10
12
  * Stop accepting connections on SIGTERM/SIGINT, let in-flight requests
@@ -19,7 +21,6 @@ export interface ListenOptions {
19
21
  /**
20
22
  * Serve a Connecta over node:http. Thin adapter: IncomingMessage → Request,
21
23
  * Response → ServerResponse, plus the process-level concerns a long-running
22
- * container needs (body cap, response streaming, graceful shutdown). No
23
- * dependencies beyond node core.
24
+ * container needs (body cap, response streaming, graceful shutdown). Outbound HTTP uses an owned undici dispatcher configured here.
24
25
  */
25
26
  export declare function listen(connecta: Connecta, portOrOptions: number | ListenOptions): Server;
package/dist/node.js CHANGED
@@ -2,8 +2,11 @@ import { createServer } from "node:http";
2
2
  import { Readable } from "node:stream";
3
3
  import { pipeline } from "node:stream/promises";
4
4
  import { failureRecord, logFailure } from "./operator-record.js";
5
- /** 10 MiB. Tool arguments are JSON; nothing legitimate approaches this. */
6
- const DEFAULT_MAX_BODY_BYTES = 10 * 1024 * 1024;
5
+ import { configureGuardedTransport } from "./guarded-transport.js";
6
+ import { createNodeGuardedTransport } from "./http/node-transport.js";
7
+ import { CONFIG_DEFAULTS } from "./config-defaults.js";
8
+ /** The adapter buffers before auth, bounded by the same default as the core. */
9
+ const DEFAULT_MAX_BODY_BYTES = CONFIG_DEFAULTS.admission.requests.maxBodyBytes;
7
10
  const BODY_TOO_LARGE = Symbol("body-too-large");
8
11
  async function toRequest(req, maxBodyBytes, signal) {
9
12
  const host = req.headers.host ?? "localhost";
@@ -55,11 +58,11 @@ async function writeResponse(res, response) {
55
58
  /**
56
59
  * Serve a Connecta over node:http. Thin adapter: IncomingMessage → Request,
57
60
  * Response → ServerResponse, plus the process-level concerns a long-running
58
- * container needs (body cap, response streaming, graceful shutdown). No
59
- * dependencies beyond node core.
61
+ * container needs (body cap, response streaming, graceful shutdown). Outbound HTTP uses an owned undici dispatcher configured here.
60
62
  */
61
63
  export function listen(connecta, portOrOptions) {
62
64
  const opts = typeof portOrOptions === "number" ? { port: portOrOptions } : portOrOptions;
65
+ configureGuardedTransport(createNodeGuardedTransport(opts.proxy));
63
66
  const maxBodyBytes = opts.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
64
67
  // Node has no ExecutionContext, so deferred work (activity sinks) would
65
68
  // otherwise be an untracked floating promise. Track it here and drain it on
@@ -71,7 +74,31 @@ export function listen(connecta, portOrOptions) {
71
74
  void promise.finally(() => pending.delete(promise));
72
75
  },
73
76
  };
77
+ const awaitingRequest = new Set();
78
+ const activeResponses = new Map();
79
+ let shuttingDown = false;
74
80
  const server = createServer((req, res) => {
81
+ awaitingRequest.delete(req.socket);
82
+ const socket = req.socket;
83
+ activeResponses.set(socket, (activeResponses.get(socket) ?? 0) + 1);
84
+ const finished = () => {
85
+ res.removeListener("finish", finished);
86
+ res.removeListener("close", finished);
87
+ const remaining = (activeResponses.get(socket) ?? 1) - 1;
88
+ if (remaining > 0)
89
+ activeResponses.set(socket, remaining);
90
+ else {
91
+ activeResponses.delete(socket);
92
+ // finish means the response was handed to the socket; destroySoon
93
+ // flushes its queued bytes before closing, including an SSE trailer.
94
+ // Count pipelined responses so an earlier finish cannot cut a later
95
+ // admitted response off. Before shutdown Node's keepalive is unchanged.
96
+ if (shuttingDown)
97
+ socket.destroySoon();
98
+ }
99
+ };
100
+ res.once("finish", finished);
101
+ res.once("close", finished);
75
102
  void (async () => {
76
103
  const controller = new AbortController();
77
104
  const abortRequest = () => {
@@ -133,7 +160,17 @@ export function listen(connecta, portOrOptions) {
133
160
  });
134
161
  if (opts.gracefulShutdown !== false) {
135
162
  const timeoutMs = opts.shutdownTimeoutMs ?? 10_000;
136
- let shuttingDown = false;
163
+ // closeIdleConnections() only knows sockets that have served a request.
164
+ // A client's spare connection (or incomplete first headers) must not hold
165
+ // shutdown open without ever having been admitted to the application.
166
+ server.on("connection", (socket) => {
167
+ if (shuttingDown) {
168
+ socket.destroy();
169
+ return;
170
+ }
171
+ awaitingRequest.add(socket);
172
+ socket.once("close", () => awaitingRequest.delete(socket));
173
+ });
137
174
  const shutdown = (signal) => {
138
175
  if (shuttingDown)
139
176
  return;
@@ -147,15 +184,15 @@ export function listen(connecta, portOrOptions) {
147
184
  // Stop queued/running sandbox work now, not after server.close has
148
185
  // waited for the very requests those children are holding open.
149
186
  const executorClose = connecta.close();
150
- // close() alone waits on idle keep-alive sockets, so a single browser
151
- // tab would stall every shutdown until the force-exit deadline.
152
- server.closeIdleConnections();
153
187
  server.close(() => {
154
188
  void Promise.allSettled([...pending, executorClose]).then(() => {
155
189
  clearTimeout(forced);
156
190
  process.exit(0);
157
191
  });
158
192
  });
193
+ server.closeIdleConnections();
194
+ for (const socket of awaitingRequest)
195
+ socket.destroy();
159
196
  };
160
197
  process.on("SIGTERM", () => shutdown("SIGTERM"));
161
198
  process.on("SIGINT", () => shutdown("SIGINT"));