@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,448 @@
1
+ // Provider kit (decision 0010, B.4). Unreachable from src/index.ts.
2
+ //
3
+ // A vendor is an `HttpApi`: endpoints with Schemas for path params, query,
4
+ // and payload, from which requests are encoded and the endpoint manifest is
5
+ // derived. This is the only kit module that imports effect/http-api, which
6
+ // 4.0.5 annotates unstable; providers declare operations through the names
7
+ // re-exported here, so an upstream change is absorbed in this file.
8
+ // Re-exporting confines those modules; it does not make them stable.
9
+ //
10
+ // The typed client runs in `response-only` mode, and `Send` hands providers an
11
+ // `Answer`, never a response. HttpApiClient's own decoding would read the
12
+ // whole body without a ceiling, quote the body in a SchemaError, and fail an
13
+ // empty 200. Every answer, from a declared operation or a hatch's path, takes
14
+ // one route: bounded read, JSON, closed public classifier facts captured,
15
+ // the request's sent secrets redacted from
16
+ // every value of the whole body before anything can cut or extract from it
17
+ // (#911), its keys kept for value safety to match by name, status (with
18
+ // its operation, so value safety decides what a failure may quote), the
19
+ // vendor's `result` hook, then the connection's ResultSafety. A provider
20
+ // cannot reach a body earlier. A Content-Type redaction altered selects the
21
+ // format the vendor reads as JSON, so no altered type routes a body around
22
+ // ResultSafety as text or bytes (#703).
23
+ import { Context, Effect } from "effect";
24
+ import * as HttpClientRequest from "effect/http/HttpClientRequest";
25
+ import * as HttpApi from "effect/http-api/HttpApi";
26
+ import * as HttpApiClient from "effect/http-api/HttpApiClient";
27
+ import * as HttpApiEndpoint from "effect/http-api/HttpApiEndpoint";
28
+ import * as HttpApiGroup from "effect/http-api/HttpApiGroup";
29
+ import * as HttpApiSchema from "effect/http-api/HttpApiSchema";
30
+ import * as OpenApi from "effect/http-api/OpenApi";
31
+ import { redactionAltered } from "../redaction-marker.js";
32
+ import { ConnectorCallError } from "../errors.js";
33
+ import { refuseWithheldValues } from "../providers/_shared/rest/value-safety.js";
34
+ import { parameterPairs } from "./write-request.js";
35
+ import { validateVendorErrors, captureClassifierFacts, withClassifierFacts, isHttpFailure, RequestRefused, Refusal, ResendRefused, StatusFailure, UnreadableBody, } from "./errors.js";
36
+ import { Classification, Dispatches, RequestFacts, RequestSecrets, ReadTool, WriteCapacity, reserveWrite, } from "./services.js";
37
+ /** Declare a GET operation: `get("getCharge", "/charges/:chargeId", { params, query, success })`. */
38
+ export const get = HttpApiEndpoint.get;
39
+ export const head = HttpApiEndpoint.head;
40
+ export const post = HttpApiEndpoint.post;
41
+ export const put = HttpApiEndpoint.put;
42
+ export const patch = HttpApiEndpoint.patch;
43
+ export const del = HttpApiEndpoint.delete;
44
+ /** A form-encoded request payload: `post("createCharge", "/charges", { payload: form(Schema.Struct(…)) })`. */
45
+ export function form(schema) {
46
+ return HttpApiSchema.asFormUrlEncoded()(schema);
47
+ }
48
+ /** The vendor's one-line operation summary, for the manifest and a hatch index: `get(…).annotate(Summary, "…")`. */
49
+ export const Summary = OpenApi.Summary;
50
+ const encodedProvenance = new WeakMap();
51
+ /** Result hooks alone may inspect byte counts and redaction flags for an exact decoded JSON field. */
52
+ export function encodedFieldProvenance(answer, path) {
53
+ return answer !== null && typeof answer === "object"
54
+ ? encodedProvenance.get(answer)?.get(JSON.stringify(path))
55
+ : undefined;
56
+ }
57
+ function encodedPath(path) {
58
+ if (typeof path !== "string" || !/^[A-Za-z0-9_]+(?:\[\*\])?(?:\.[A-Za-z0-9_]+(?:\[\*\])?)*$/.test(path))
59
+ throw new Error("Encoded fields require exact JSON paths with only whole array wildcards.");
60
+ return Object.freeze(path.split(".").flatMap((part) => (part.endsWith("[*]") ? [part.slice(0, -3), "*"] : [part])));
61
+ }
62
+ function decodedBase64url(value) {
63
+ try {
64
+ // Linear checks: a repeated-group pattern overflows the regex stack on multi-MiB fields.
65
+ const units = value.replace(/={1,2}$/, "");
66
+ if (!/^[A-Za-z0-9_+/-]*$/.test(units) || units.length % 4 === 1)
67
+ return undefined;
68
+ if (units.length !== value.length && value.length % 4 !== 0)
69
+ return undefined;
70
+ const binary = atob(value.replace(/-/g, "+").replace(/_/g, "/"));
71
+ const bytes = new Uint8Array(binary.length);
72
+ for (let i = 0; i < binary.length; i++)
73
+ bytes[i] = binary.charCodeAt(i);
74
+ return bytes;
75
+ }
76
+ catch {
77
+ return undefined;
78
+ }
79
+ }
80
+ function encodedFieldsReview(fields) {
81
+ const seen = new Set();
82
+ return Object.freeze((fields ?? []).map((field) => {
83
+ if (field.encoding !== "base64url" ||
84
+ typeof field.review !== "string" ||
85
+ !field.review.trim() ||
86
+ /[\r\n]/.test(field.review) ||
87
+ seen.has(field.path))
88
+ throw new Error("Encoded fields require unique paths, base64url encoding and a one-line review reason.");
89
+ seen.add(field.path);
90
+ const path = encodedPath(field.path);
91
+ const sizePath = field.sizePath === undefined ? undefined : encodedPath(field.sizePath);
92
+ // Wildcards refer to the same array elements; a size cannot come from another lane.
93
+ if (sizePath &&
94
+ (sizePath.filter((part) => part === "*").length !== path.filter((part) => part === "*").length ||
95
+ sizePath.some((part, index) => part === "*" && path.slice(0, index + 1).join(".") !== sizePath.slice(0, index + 1).join("."))))
96
+ throw new Error("An encoded field's size path must address the same array elements.");
97
+ return Object.freeze({ path, ...(sizePath ? { sizePath } : {}) });
98
+ }));
99
+ }
100
+ function normalizeEncodedFields(value, fields, secrets) {
101
+ const provenance = new Map();
102
+ for (const field of fields) {
103
+ const visit = (node, index, concrete) => {
104
+ if (node === null || typeof node !== "object")
105
+ return;
106
+ const segment = field.path[index];
107
+ const keys = segment === "*" ? (Array.isArray(node) ? node.map((_, i) => i) : []) : [segment];
108
+ for (const key of keys) {
109
+ if (!Object.hasOwn(node, key))
110
+ continue;
111
+ const record = node;
112
+ const next = [...concrete, key];
113
+ if (index + 1 < field.path.length) {
114
+ visit(record[key], index + 1, next);
115
+ continue;
116
+ }
117
+ const encoded = record[key];
118
+ if (typeof encoded !== "string")
119
+ continue;
120
+ const bytes = decodedBase64url(encoded);
121
+ if (!bytes)
122
+ continue;
123
+ let sizeValid;
124
+ if (field.sizePath) {
125
+ let declared = value;
126
+ for (const [i, part] of field.sizePath.entries()) {
127
+ const sizeKey = part === "*" ? next[i] : part;
128
+ declared =
129
+ declared !== null && typeof declared === "object" && Object.hasOwn(declared, sizeKey)
130
+ ? declared[sizeKey]
131
+ : undefined;
132
+ }
133
+ sizeValid = typeof declared === "number" && Number.isSafeInteger(declared) && declared === bytes.length;
134
+ }
135
+ let changed = false;
136
+ if (sizeValid !== false) {
137
+ let sanitized;
138
+ try {
139
+ const text = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
140
+ const redacted = secrets.redact(text);
141
+ sanitized = redacted === text ? bytes : new TextEncoder().encode(redacted);
142
+ }
143
+ catch {
144
+ // Preserve arbitrary bytes; encode's byte path also checks UTF-8 and nested encodings.
145
+ let binary = "";
146
+ for (const byte of bytes)
147
+ binary += String.fromCharCode(byte);
148
+ sanitized = Uint8Array.from(secrets.redact(binary), (unit) => unit.charCodeAt(0));
149
+ }
150
+ const url = !/[+/]/.test(encoded);
151
+ let safe = secrets.encode(sanitized, { url });
152
+ safe = /=+$/.test(encoded) ? safe + "=".repeat((4 - (safe.length % 4)) % 4) : safe.replace(/=+$/, "");
153
+ const safeBytes = decodedBase64url(safe);
154
+ changed = safeBytes.length !== bytes.length || safeBytes.some((byte, i) => byte !== bytes[i]);
155
+ // Preserve untouched spelling, including padding. The ordinary JSON pass still checks it.
156
+ if (changed)
157
+ record[key] = safe;
158
+ }
159
+ provenance.set(JSON.stringify(next), Object.freeze({ originalLength: bytes.length, ...(sizeValid === undefined ? {} : { sizeValid }), changed }));
160
+ }
161
+ };
162
+ visit(value, 0, []);
163
+ }
164
+ return provenance;
165
+ }
166
+ /** Group a vendor's operations into one API, the source of its client and its manifest. */
167
+ export function vendor(declaration, ...operations) {
168
+ const name = typeof declaration === "string" ? declaration : declaration.name;
169
+ const manifestBase = typeof declaration === "string" ? undefined : declaration.manifestBase;
170
+ if (manifestBase !== undefined &&
171
+ (!/^\/(?:[A-Za-z0-9._~-]+|\{[A-Za-z0-9_]+\})(?:\/(?:[A-Za-z0-9._~-]+|\{[A-Za-z0-9_]+\}))*$/.test(manifestBase) ||
172
+ manifestBase.split("/").some((segment) => segment === "." || segment === "..")))
173
+ throw new Error("A vendor manifestBase must be an absolute path prefix without dot segments or a trailing slash.");
174
+ if (!name.trim() ||
175
+ operations.length === 0 ||
176
+ new Set(operations.map((op) => op.identifier)).size !== operations.length)
177
+ throw new Error("A vendor needs a name and operations with unique identifiers.");
178
+ return {
179
+ api: HttpApi.make(name).add(HttpApiGroup.make("operations", { topLevel: true }).add(...operations)),
180
+ ...(manifestBase === undefined ? {} : { manifestBase }),
181
+ };
182
+ }
183
+ /**
184
+ * Bind a vendor to one connection's guarded client. The typed client is built
185
+ * once, on first use, and lives as long as the connection.
186
+ */
187
+ export function connect(vendor, guarded, options) {
188
+ validateVendorErrors(options.errors);
189
+ const textBodies = vendor.textBodies ? { ...vendor.textBodies } : undefined;
190
+ const binaryBodies = vendor.binaryBodies ? { ...vendor.binaryBodies } : undefined;
191
+ const encodedFields = encodedFieldsReview(vendor.encodedFields);
192
+ if (binaryBodies && (!binaryBodies.review.trim() || typeof binaryBodies.forResponse !== "function"))
193
+ throw new Error("Binary bodies require a nonempty vendor review and a response contract selector.");
194
+ if (textBodies && (!textBodies.review.trim() || typeof textBodies.forResponse !== "function"))
195
+ throw new Error("Text bodies require a nonempty vendor review and a response contract selector.");
196
+ let built;
197
+ // HttpApiClient closes over the services it is built in (its middleware
198
+ // lookup), and the client outlives every call. Build it with none, so it
199
+ // holds no caller's context, signal, credentials or request scope (INV-7);
200
+ // its endpoints read each call's services when they run.
201
+ const construct = HttpApiClient.makeWith(vendor.api, { httpClient: guarded.client }).pipe(Effect.setContext(Context.empty()));
202
+ const client = Effect.suspend(() => built
203
+ ? Effect.succeed(built)
204
+ : construct.pipe(Effect.map((made) => (built = made))));
205
+ const settle = (operation, response, sendOptions) => Effect.suspend(() => {
206
+ // The transport names the request it handed to `fetch` here; whatever
207
+ // its answer settles into is recorded on it in the ledger, so the
208
+ // write-outcome rule can tell the write's own failure from a later one.
209
+ const sent = {};
210
+ return Effect.gen(function* () {
211
+ const authored = yield* ReadTool;
212
+ if (authored !== undefined && operation.method !== "GET" && operation.method !== "HEAD" && !authored.review)
213
+ return yield* Effect.die(new Error("A read tool sending a method other than GET or HEAD requires a review."));
214
+ if ((yield* Classification) === "write" && sendOptions?.effect !== "read") {
215
+ const ledger = yield* Dispatches;
216
+ const capacity = yield* WriteCapacity;
217
+ // Reserve before request encoding, authentication, or any asynchronous preparation.
218
+ const slot = yield* Effect.sync(() => reserveWrite(ledger, capacity, { ...sendOptions, operation }));
219
+ if (slot instanceof RequestRefused || slot instanceof ResendRefused)
220
+ return yield* Effect.fail(slot);
221
+ sent.reservation = slot;
222
+ }
223
+ const secrets = yield* RequestSecrets;
224
+ const reply = yield* Effect.flatMap(response, (response) => {
225
+ const contentType = formatType(secrets.redact(String(response.headers["content-type"] ?? "")));
226
+ const binary = response.status >= 200 &&
227
+ response.status <= 299 &&
228
+ binaryBodies?.forResponse(response.status, operation, contentType) === true;
229
+ return guarded
230
+ .read(response, undefined, binary ? "bytes" : undefined, sendOptions?.prefix)
231
+ .pipe(Effect.catchDefect((defect) => Effect.die(sendOptions?.prefix && options.safety.withholdsErrors(operation)
232
+ ? new Error("A prefix hook withholding vendor text failed.")
233
+ : defect)));
234
+ });
235
+ // Header-derived format decisions see only redacted Content-Type. Names are protocol
236
+ // constants `Headers` must accept, so only the values are redacted, together (#703).
237
+ const entries = [...reply.headers];
238
+ const values = secrets.redact(entries.map(([, value]) => value));
239
+ const headers = new Headers(entries.map(([name], index) => [name, values[index]]));
240
+ // Whole, before a detail line trims it or a projection extracts from it. Values only:
241
+ // result safety and projections match fields by their vendor names (#703).
242
+ let classifierFacts;
243
+ const parsed = reply.bytes !== undefined
244
+ ? {
245
+ value: reply.bytes.length === 0
246
+ ? null
247
+ : {
248
+ contentType: secrets.redact(reply.headers.get("content-type") ?? "").toLowerCase(),
249
+ bytes: reply.bytes.length,
250
+ base64: secrets.encode(reply.bytes),
251
+ },
252
+ format: "json",
253
+ }
254
+ : parse(reply.text, (value, format) => {
255
+ if (reply.status < 200 || reply.status > 299 || options.inBandRefusals)
256
+ classifierFacts = captureClassifierFacts(value, options.errors, reply.headers);
257
+ const provenance = format === "json" && encodedFields.length > 0
258
+ ? normalizeEncodedFields(value, encodedFields, secrets)
259
+ : undefined;
260
+ const redacted = reply.prefix?.truncated && typeof value === "string"
261
+ ? secrets.redactOpenTail(value)
262
+ : secrets.redact(value, "values");
263
+ if (provenance?.size && redacted !== null && typeof redacted === "object")
264
+ encodedProvenance.set(redacted, provenance);
265
+ return redacted;
266
+ }, textBodies?.forResponse(reply.status, operation, formatType(headers.get("content-type") ?? "")));
267
+ // Empty and malformed bodies still carry declared numeric response headers.
268
+ if ((reply.status < 200 || reply.status > 299 || options.inBandRefusals) && !classifierFacts)
269
+ classifierFacts = captureClassifierFacts(undefined, options.errors, reply.headers);
270
+ if (reply.status < 200 || reply.status > 299) {
271
+ return yield* Effect.fail(withClassifierFacts(new StatusFailure({
272
+ status: reply.status,
273
+ headers,
274
+ body: parsed?.value,
275
+ ...(parsed ? {} : { unreadable: true }),
276
+ operation,
277
+ }), classifierFacts));
278
+ }
279
+ if (!parsed)
280
+ return yield* Effect.fail(new UnreadableBody(reply.readFailed
281
+ ? { readFailed: true }
282
+ : formatType(headers.get("content-type") ?? "")
283
+ .split(";", 1)[0]
284
+ .trim() === "text/html" && !/^[\t\r\n ]*[[{]/.test(reply.text ?? "")
285
+ ? { unexpectedText: true }
286
+ : {}));
287
+ const withheld = options.safety.withholdsErrors(operation);
288
+ const kept = options.result
289
+ ? yield* Effect.suspend(() => options.result(parsed.value, {
290
+ status: reply.status,
291
+ bodyFormat: parsed.format,
292
+ headers,
293
+ operation: { ...operation },
294
+ withheld,
295
+ ...(reply.prefix ? { prefix: reply.prefix } : {}),
296
+ })).pipe(Effect.catch((failure) => {
297
+ if (failure._tag === "StatusFailure")
298
+ return Effect.fail(withClassifierFacts(new StatusFailure({ ...failure, operation }), classifierFacts));
299
+ if (!withheld || failure._tag === "UnreadableBody")
300
+ return Effect.fail(failure);
301
+ return Effect.die(new Error("A result hook withholding vendor text must report an in-band refusal as StatusFailure."));
302
+ }))
303
+ : parsed.value;
304
+ return {
305
+ status: reply.status,
306
+ data: options.safety.redact(kept, operation),
307
+ ...(sendOptions?.responseHeaders?.length
308
+ ? {
309
+ headers: Object.fromEntries(sendOptions.responseHeaders.flatMap((name) => {
310
+ const value = headers.get(name);
311
+ return value === null ? [] : [[name.toLowerCase(), value]];
312
+ })),
313
+ }
314
+ : {}),
315
+ ...(reply.prefix ? { prefix: reply.prefix } : {}),
316
+ };
317
+ }).pipe(Effect.tapError((failure) => Effect.sync(() => {
318
+ const slot = sent.dispatch ?? sent.reservation;
319
+ if (slot && slot.failure === undefined && failure._tag !== "ResendRefused")
320
+ slot.failure = failure;
321
+ })), Effect.provideService(RequestFacts, {
322
+ effect: sendOptions?.effect === "read" ? "read" : "call",
323
+ ...(sendOptions?.step === undefined ? {} : { step: sendOptions.step }),
324
+ ...(sendOptions?.item === undefined ? {} : { item: sendOptions.item }),
325
+ operation,
326
+ ...(sendOptions?.prefix ? { successPrefix: true } : {}),
327
+ sent,
328
+ }));
329
+ });
330
+ const admitAddress = (value) => Effect.try({
331
+ try: () => refuseWithheldValues(value, guarded.provider, true),
332
+ catch: (error) => error,
333
+ }).pipe(Effect.catch((error) => error instanceof ConnectorCallError ? Effect.fail(new Refusal({ error })) : Effect.die(error)));
334
+ const connection = {
335
+ provider: guarded.provider,
336
+ errors: options.errors,
337
+ safety: options.safety,
338
+ send: (operation, request, sendOptions) => {
339
+ // Every endpoint carries both; the constraint type erases them.
340
+ const declared = operation;
341
+ const ref = {
342
+ method: declared.method,
343
+ template: declared.path,
344
+ ...(sendOptions?.flags ? { flags: sendOptions.flags } : {}),
345
+ };
346
+ return Effect.flatMap(admitAddress({
347
+ params: request.params,
348
+ query: request.query,
349
+ }), () => settle(ref, client.pipe(Effect.flatMap((methods) => {
350
+ const method = methods[operation.identifier];
351
+ return method
352
+ ? method({ ...request, responseMode: "response-only" })
353
+ : Effect.fail(new RequestRefused({ message: "This operation is not a named vendor endpoint." }));
354
+ }),
355
+ // The guarded client fails only with HttpFailure. Anything else is a
356
+ // request the vendor's own Schemas could not encode: a provider bug.
357
+ Effect.catch((error) => (isHttpFailure(error) ? Effect.fail(error) : Effect.die(error)))), sendOptions));
358
+ },
359
+ sendItem: (step, item) => Effect.gen(function* () {
360
+ const request = (yield* WriteCapacity).get(step)?.get(item);
361
+ if (!request)
362
+ return yield* Effect.fail(new RequestRefused({ message: "This write item has no declared request." }));
363
+ return yield* connection.sendPath(request, { step, item });
364
+ }),
365
+ sendPath: (request, sendOptions) => {
366
+ const { method, path } = request;
367
+ if (request.rawBody !== undefined &&
368
+ (sendOptions?.item !== undefined ||
369
+ request.json !== undefined ||
370
+ request.form !== undefined ||
371
+ request.emptyForm))
372
+ return Effect.fail(new RequestRefused({ message: "A raw body cannot accompany a bulk item or another body encoding." }));
373
+ return Effect.flatMap(admitAddress({ path, query: request.query }), () => Effect.flatMap(options.safety.resolve(method, path), (operation) => settle({ ...operation, ...(sendOptions?.flags ? { flags: sendOptions.flags } : {}) }, Effect.suspend(() => {
374
+ let built = HttpClientRequest.make(method)(path, request.query ? { urlParams: parameterPairs(request.query) } : {});
375
+ if (request.headers)
376
+ built = HttpClientRequest.setHeaders(built, request.headers);
377
+ if (request.form !== undefined && (Object.keys(request.form).length > 0 || request.emptyForm === true)) {
378
+ built = HttpClientRequest.bodyText(built, new URLSearchParams(parameterPairs(request.form)).toString(), "application/x-www-form-urlencoded");
379
+ }
380
+ if (request.json !== undefined)
381
+ built = HttpClientRequest.bodyText(built, request.json, "application/json");
382
+ if (request.rawBody !== undefined) {
383
+ const type = new Headers(request.headers).get("content-type") ?? undefined;
384
+ built =
385
+ typeof request.rawBody === "string"
386
+ ? HttpClientRequest.bodyText(built, request.rawBody, type)
387
+ : request.rawBody instanceof Uint8Array
388
+ ? HttpClientRequest.bodyUint8Array(built, request.rawBody, type)
389
+ : HttpClientRequest.bodyFormData(built, request.rawBody);
390
+ // Body combinators supply defaults; an explicit reviewed media type wins.
391
+ if (type !== undefined)
392
+ built = HttpClientRequest.setHeader(built, "content-type", type);
393
+ }
394
+ return guarded.client.execute(built);
395
+ }), sendOptions)));
396
+ },
397
+ };
398
+ return connection;
399
+ }
400
+ /**
401
+ * The Content-Type a format decision reads. One redaction altered reads as
402
+ * `application/json`: a vendor's text or binary choice for it would hand
403
+ * result safety a body it cannot read field by field (#703).
404
+ */
405
+ function formatType(redacted) {
406
+ return redactionAltered(redacted) ? "application/json" : redacted.toLowerCase();
407
+ }
408
+ function parse(text, redact, format) {
409
+ if (text === undefined)
410
+ return undefined;
411
+ if (format === "text")
412
+ return { value: redact(text, "text"), format: "text" };
413
+ if (text.trim() === "")
414
+ return format === "json-or-text"
415
+ ? { value: redact(text, "text"), format: "text" }
416
+ : { value: undefined, format: "empty" };
417
+ let value;
418
+ try {
419
+ value = JSON.parse(text);
420
+ }
421
+ catch {
422
+ return format === "json-or-text" ? { value: redact(text, "text"), format: "text" } : undefined;
423
+ }
424
+ return { value: redact(value, "json"), format: "json" };
425
+ }
426
+ /** The endpoint manifest drift checks compare against the vendor's published contract. */
427
+ export function manifest(vendor) {
428
+ const document = OpenApi.fromApi(vendor.indexed?.api() ?? vendor.api);
429
+ return vendor.manifestBase === undefined
430
+ ? document
431
+ : {
432
+ ...document,
433
+ paths: Object.fromEntries(Object.entries(document.paths).map(([path, operation]) => [vendor.manifestBase + path, operation])),
434
+ };
435
+ }
436
+ const METHODS = ["get", "head", "post", "put", "patch", "delete"];
437
+ /**
438
+ * Every operation of `manifest(vendor)` as `"METHOD /path"`, sorted: the
439
+ * `operations` of decision 0011's `ProviderKitFacts`, which
440
+ * `providers:generate` writes into `drift.json`'s `generated.operations`.
441
+ */
442
+ export function operations(vendor) {
443
+ if (vendor.indexed)
444
+ return [...vendor.indexed.operations];
445
+ return Object.entries(manifest(vendor).paths)
446
+ .flatMap(([path, item]) => METHODS.filter((method) => item[method] !== undefined).map((method) => `${method.toUpperCase()} ${path}`))
447
+ .sort();
448
+ }
@@ -0,0 +1,66 @@
1
+ // Lossless identifying content for bulk reservations. In particular, never
2
+ // turn wire parameters or JSON properties into an Object: vendors disagree
3
+ // about first/last-value semantics, so duplicate keys require an explicit
4
+ // per-key contract and their value order always remains significant.
5
+ import { parseExpressionAt } from "acorn";
6
+ export function parameterPairs(parameters) {
7
+ return Array.isArray(parameters) ? parameters.map(([key, value]) => [key, value]) : Object.entries(parameters ?? {});
8
+ }
9
+ /** Sort distinct names only; stable sorting preserves every repeated value's order. */
10
+ function ordered(pairs, allowed = []) {
11
+ const seen = new Set();
12
+ for (const [key] of pairs) {
13
+ if (seen.has(key) && !allowed.includes(key))
14
+ throw new Error("Duplicate identifying keys need declared multi-value semantics.");
15
+ seen.add(key);
16
+ }
17
+ return pairs.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
18
+ }
19
+ function jsonContent(text, allowed = []) {
20
+ // Validate the JSON grammar first. Acorn retains every property, including
21
+ // escaped duplicate names; JSON.parse alone would silently discard them.
22
+ JSON.parse(text);
23
+ const visit = (node, path) => {
24
+ switch (node.type) {
25
+ case "ObjectExpression": {
26
+ const pairs = node.properties.map((property) => {
27
+ if (property.type !== "Property" || property.key.type !== "Literal")
28
+ throw new Error("Invalid JSON property.");
29
+ const key = String(property.key.value);
30
+ const pointer = `${path}/${key.replace(/~/g, "~0").replace(/\//g, "~1")}`;
31
+ return [key, visit(property.value, pointer)];
32
+ });
33
+ return [
34
+ "object",
35
+ ordered(pairs, pairs.flatMap(([key]) => {
36
+ const pointer = `${path}/${key.replace(/~/g, "~0").replace(/\//g, "~1")}`;
37
+ return allowed.includes(pointer) ? [key] : [];
38
+ })),
39
+ ];
40
+ }
41
+ case "ArrayExpression":
42
+ return ["array", node.elements.map((element, index) => visit(element, `${path}/${index}`))];
43
+ default: {
44
+ const raw = text.slice(node.start, node.end);
45
+ // Never round large identifiers, coerce -0, or collapse overflow to
46
+ // null while making the key. Retain numeric lexemes losslessly.
47
+ return /^[-0-9]/.test(raw) ? ["number", raw] : ["value", JSON.parse(raw)];
48
+ }
49
+ }
50
+ };
51
+ return visit(parseExpressionAt(text, 0, { ecmaVersion: "latest" }), "");
52
+ }
53
+ /** Canonical ordered multimaps, including JSON structure and paths; no credentials. */
54
+ export function writeRequestKey(request) {
55
+ if ("rawBody" in request && request.rawBody !== undefined)
56
+ throw new Error("A bulk write item cannot declare a raw body.");
57
+ if (request.form !== undefined && request.json !== undefined)
58
+ throw new Error("A write item declares one body encoding.");
59
+ return JSON.stringify([
60
+ request.method,
61
+ new URL(`https://request.example${request.path}`).pathname,
62
+ ordered(parameterPairs(request.query), request.multiValue?.query),
63
+ ordered(parameterPairs(request.form), request.multiValue?.form),
64
+ request.json === undefined ? null : jsonContent(request.json, request.multiValue?.json),
65
+ ]);
66
+ }
@@ -0,0 +1,11 @@
1
+ /** Statuses that instruct a client to re-send somewhere else. Never followed. */
2
+ export declare const REDIRECT_STATUSES: Set<number>;
3
+ /** Statuses the HTTP spec defines as carrying no body at all. */
4
+ export declare const BODILESS_STATUSES: Set<number>;
5
+ /**
6
+ * A base URL is deployment configuration, so a bad one is a structural mistake
7
+ * and throws where it is written rather than on the first call that uses it.
8
+ */
9
+ export declare function confinementBase(provider: string, baseUrl: string): URL;
10
+ /** Parse delta-seconds or an HTTP-date into a non-negative wait window. */
11
+ export declare function retryAfterMs(headers: Headers): number | undefined;
@@ -0,0 +1,45 @@
1
+ // Pure policy shared by the Promise and Effect transports. No runtime or kit imports.
2
+ /** Statuses that instruct a client to re-send somewhere else. Never followed. */
3
+ export const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
4
+ /** Statuses the HTTP spec defines as carrying no body at all. */
5
+ export const BODILESS_STATUSES = new Set([204, 205, 304]);
6
+ /**
7
+ * A base URL is deployment configuration, so a bad one is a structural mistake
8
+ * and throws where it is written rather than on the first call that uses it.
9
+ */
10
+ export function confinementBase(provider, baseUrl) {
11
+ let base;
12
+ try {
13
+ base = new URL(baseUrl);
14
+ }
15
+ catch {
16
+ throw new Error(`${provider} baseUrl must be an absolute URL.`);
17
+ }
18
+ const loopback = base.hostname === "localhost" || base.hostname === "127.0.0.1" || base.hostname === "[::1]";
19
+ if (base.protocol !== "https:" && !(base.protocol === "http:" && loopback)) {
20
+ throw new Error(`${provider} baseUrl must be https (http is allowed only for a loopback proxy or test double).`);
21
+ }
22
+ if (base.username || base.password) {
23
+ throw new Error(`${provider} baseUrl must not embed URL credentials; authentication belongs in headers.`);
24
+ }
25
+ if (base.search || base.hash) {
26
+ throw new Error(`${provider} baseUrl must not carry a query or fragment.`);
27
+ }
28
+ return base;
29
+ }
30
+ /** Parse delta-seconds or an HTTP-date into a non-negative wait window. */
31
+ export function retryAfterMs(headers) {
32
+ const raw = headers.get("retry-after");
33
+ if (!raw)
34
+ return undefined;
35
+ const seconds = Number(raw.trim());
36
+ if (Number.isFinite(seconds)) {
37
+ return seconds < 0 ? undefined : Math.trunc(seconds * 1000);
38
+ }
39
+ // Require the HTTP-date shape, so Date.parse cannot reinterpret "-1" as
40
+ // a calendar date on runtimes that accept loose date strings.
41
+ if (!/^[A-Za-z]{3}, \d{2} [A-Za-z]{3} \d{4} \d{2}:\d{2}:\d{2} GMT$/.test(raw.trim()))
42
+ return undefined;
43
+ const date = Date.parse(raw);
44
+ return Number.isFinite(date) ? Math.max(0, date - Date.now()) : undefined;
45
+ }
@@ -45,7 +45,7 @@ export function authorizationRequest(request) {
45
45
  parsed.set(normalized, { header: headers.get("authorization"), credential });
46
46
  return normalized;
47
47
  }
48
- /** Reserved machine syntax, even when the optional verifier is not installed. */
48
+ /** Reserved token syntax, even when the optional verifier is not installed. */
49
49
  export function isMachineCredential(request) {
50
50
  const credential = authorizationCredential(request);
51
51
  return credential.kind === "bearer" && credential.token.startsWith("cta_");
package/dist/index.d.ts CHANGED
@@ -29,7 +29,7 @@ export { remoteMcp } from "./connectors/remote-mcp.js";
29
29
  export { api } from "./connectors/api.js";
30
30
  export { keys, optionsOf, array, opaque, instance, strings, variants } from "./config-schema.js";
31
31
  export { defineProvider, PROVIDER_COMMON } from "./provider.js";
32
- export type { ProviderContext, ProviderDefinition, ProviderFactory, ProviderGuideInput, ProviderKind, ProviderOptions, ProviderSkill, } from "./provider.js";
32
+ export type { ProviderContext, ProviderDefinition, ProviderFactory, ProviderGuideBlocks, ProviderGuideInput, ProviderKitFacts, ProviderOptions, ProviderSkill, } from "./provider.js";
33
33
  export { ConnectorCallError } from "./errors.js";
34
34
  export type { ConnectorCallErrorCode, CallErrorDetails } from "./errors.js";
35
35
  export { validateToolInput } from "./validate.js";
@@ -40,6 +40,6 @@ export type { GuestApi, GuestResourceResult, GuestResult, GuestResultPage, Guest
40
40
  export type { Registry } from "./registry.js";
41
41
  export type { RemoteMcpOptions, RemoteMcpAuth, RemoteMcpRedirectPolicy } from "./connectors/remote-mcp.js";
42
42
  export type { ApiHandlerContext, ApiOAuthAccess, ApiOAuthClientAuthentication, ApiOAuthConfig, ApiOptions, ApiTool, } from "./connectors/api.js";
43
- export type { CatalogDriftCounts, CatalogDriftReport, ConnectaBranding, ConnectaTheme, Connector, ConnectorCallAdmissionInput, ConnectorCallAdmissionPolicy, ConnectorCallAdmissionRule, ConnectorRollingWindowBudget, ConnectorCredentialAccess, ConnectorCredentialConfig, ConnectorCredentialFieldConfig, ConnectorCredentialValues, ConnectorContext, ConnectorAuthDescription, ConnectorDescription, ConnectorToolDescription, ConnectorUsageGuide, ConnectorSkill, ConnectorSkillResourceContents, DescribedEndpoint, ConnectorStatus, CredentialTestResult, AdmittingExecutor, AdmissionSnapshot, ExecuteResult, Executor, ExecutorLease, ExecutorProvider, InboundAuth, InboundAuthRuntimeContext, UiAuthConfig, AuthResult, AuthenticatedIdentity, IdentityReference, JsonSchema, KVStorage, Logger, ReviewedTool, ToolClassification, ToolDef, ToolAnnotations, ToolVerdict, } from "./types.js";
43
+ export type { ConnectaBranding, ConnectaTheme, Connector, ConnectorCallAdmissionInput, ConnectorCallAdmissionPolicy, ConnectorCallAdmissionRule, ConnectorRollingWindowBudget, ConnectorCredentialAccess, ConnectorCredentialConfig, ConnectorCredentialFieldConfig, ConnectorCredentialValues, ConnectorContext, ConnectorAuthDescription, ConnectorDescription, ConnectorToolDescription, ConnectorUsageGuide, ConnectorSkill, ConnectorSkillResourceContents, DescribedEndpoint, ConnectorStatus, CredentialTestResult, AdmittingExecutor, AdmissionSnapshot, ExecuteResult, Executor, ExecutorLease, ExecutorProvider, InboundAuth, InboundAuthRuntimeContext, UiAuthConfig, AuthResult, AuthenticatedIdentity, IdentityReference, JsonSchema, KVStorage, Logger, ToolDef, ToolAnnotations, } from "./types.js";
44
44
  export type { ActivityActor, ActivityCatalogChange, ActivityCallSource, ActivityOutcome, ActivityPage, ActivityReadActor, ActivityReadEvent, ActivityReader, ActivityReadGate, ActivityReadPage, ActivitySink, ActivityStore, AgentFriction, ToolCallActivityEvent, } from "./activity.js";
45
45
  export { META_TOOL_NAMES } from "./meta-tool-names.js";
package/dist/index.js CHANGED
@@ -61,6 +61,9 @@ function resolvePools(pools, readOnly, registry, members) {
61
61
  if (pool.members.length === 0) {
62
62
  throw new ConfigError(`${path} is empty; a pool serves only its members, so list at least one.`);
63
63
  }
64
+ if (pool.executeCode !== undefined && pool.surface !== "native") {
65
+ throw new ConfigError(`ConnectaConfig.pools.${name}.executeCode needs surface: "native"; the meta surface always includes execute_code.`);
66
+ }
64
67
  // A pool inherits the deployment value unless it sets its own, either way.
65
68
  resolved.set(name, Object.freeze({
66
69
  access,
@@ -68,6 +71,7 @@ function resolvePools(pools, readOnly, registry, members) {
68
71
  members: Object.freeze(resolveMembers(pool.members, path, members)),
69
72
  ...(pool.owner !== undefined ? { owner: pool.owner.trim() } : {}),
70
73
  ...(pool.description !== undefined ? { description: pool.description.trim() } : {}),
74
+ ...(pool.surface === "native" ? { native: { executeCode: pool.executeCode ?? true } } : {}),
71
75
  }));
72
76
  }
73
77
  return resolved;