@zackbart/connecta 0.34.1 → 0.36.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 (441) hide show
  1. package/CHANGELOG.md +418 -0
  2. package/README.md +65 -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 +2044 -1161
  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 +751 -281
  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 +29 -7
  53. package/dist/connectors/api-connector.js +145 -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/remote-mcp.d.ts +10 -30
  58. package/dist/connectors/remote-mcp.js +955 -563
  59. package/dist/d1.js +10 -243
  60. package/dist/derived-context.js +5 -0
  61. package/dist/describe-config.d.ts +3 -1
  62. package/dist/describe-config.js +2 -0
  63. package/dist/downstream-input.js +347 -260
  64. package/dist/errors.d.ts +87 -6
  65. package/dist/errors.js +114 -4
  66. package/dist/execute.js +87 -50
  67. package/dist/executor-admission.js +3 -0
  68. package/dist/executors/quickjs.js +163 -112
  69. package/dist/guarded-transport.js +50 -0
  70. package/dist/guest-runtime.js +1 -1
  71. package/dist/http/client.js +439 -0
  72. package/dist/http/errors.js +558 -0
  73. package/dist/http/fields.js +49 -0
  74. package/dist/http/hatch-paging.js +318 -0
  75. package/dist/http/hatch.js +1279 -0
  76. package/dist/http/json-schema.js +267 -0
  77. package/dist/http/node-transport.js +241 -0
  78. package/dist/http/oauth.js +162 -0
  79. package/dist/http/paging.js +227 -0
  80. package/dist/http/provider.js +221 -0
  81. package/dist/http/safety.js +82 -0
  82. package/dist/http/services.js +79 -0
  83. package/dist/http/tools.js +379 -0
  84. package/dist/http/vendor-index.js +138 -0
  85. package/dist/http/vendor.js +448 -0
  86. package/dist/http/write-request.js +66 -0
  87. package/dist/http-policy.d.ts +11 -0
  88. package/dist/http-policy.js +45 -0
  89. package/dist/inbound-credential.js +1 -1
  90. package/dist/index.d.ts +2 -2
  91. package/dist/index.js +4 -0
  92. package/dist/invocation-auth.js +30 -19
  93. package/dist/invocation.js +218 -85
  94. package/dist/mcp-result.js +0 -4
  95. package/dist/membership.d.ts +4 -0
  96. package/dist/meta-output.js +1 -1
  97. package/dist/meta-tools.js +531 -406
  98. package/dist/native-recovery.js +52 -0
  99. package/dist/native-tools.js +382 -0
  100. package/dist/node.d.ts +4 -3
  101. package/dist/node.js +45 -8
  102. package/dist/oauth-handoff.js +177 -104
  103. package/dist/oauth-partition.js +6 -20
  104. package/dist/oauth-sealing.js +6 -7
  105. package/dist/operation-vocabulary.js +101 -0
  106. package/dist/operator-record.d.ts +2 -2
  107. package/dist/operator-record.js +17 -4
  108. package/dist/operator-ui/contract.d.ts +8 -3
  109. package/dist/operator-ui/generated.js +4 -4
  110. package/dist/operator-ui/model.d.ts +2 -3
  111. package/dist/program-writes.js +47 -26
  112. package/dist/provider-call-facts.d.ts +115 -0
  113. package/dist/provider-call-facts.js +182 -0
  114. package/dist/provider-call.d.ts +112 -0
  115. package/dist/provider-call.js +271 -0
  116. package/dist/provider.d.ts +65 -31
  117. package/dist/provider.js +116 -39
  118. package/dist/providers/_shared/google/hatch.js +91 -0
  119. package/dist/providers/_shared/google/kit.js +427 -0
  120. package/dist/providers/_shared/google/result-size.js +15 -2
  121. package/dist/providers/_shared/google/service-account.d.ts +2 -1
  122. package/dist/providers/_shared/google/service-account.js +8 -4
  123. package/dist/providers/_shared/google/workspace.d.ts +6 -210
  124. package/dist/providers/_shared/google/workspace.js +6 -425
  125. package/dist/providers/_shared/rest/compact-index.js +86 -0
  126. package/dist/providers/_shared/rest/kit.js +146 -0
  127. package/dist/providers/_shared/rest/operation-index.js +230 -14
  128. package/dist/providers/_shared/rest/response-media.js +11 -0
  129. package/dist/providers/_shared/rest/value-safety.js +353 -195
  130. package/dist/providers/_shared/sensitive-fields.js +27 -0
  131. package/dist/providers/breeze/api.js +584 -0
  132. package/dist/providers/breeze/index.d.ts +1 -3
  133. package/dist/providers/breeze/index.js +67 -1420
  134. package/dist/providers/breeze/openapi.generated.js +60 -0
  135. package/dist/providers/breeze/skill.generated.js +2 -6
  136. package/dist/providers/breeze/tools.js +696 -0
  137. package/dist/providers/ccb/api.js +496 -0
  138. package/dist/providers/ccb/index.d.ts +15 -37
  139. package/dist/providers/ccb/index.js +77 -1702
  140. package/dist/providers/ccb/lib/constants.d.ts +34 -0
  141. package/dist/providers/ccb/lib/constants.js +74 -0
  142. package/dist/providers/ccb/lib/guide.js +9 -0
  143. package/dist/providers/ccb/lib/verdicts.js +387 -0
  144. package/dist/providers/ccb/openapi.generated.js +397 -0
  145. package/dist/providers/ccb/safety.js +295 -0
  146. package/dist/providers/ccb/skill.generated.js +2 -6
  147. package/dist/providers/ccb/tools.js +853 -0
  148. package/dist/providers/cloudflare/api.js +1066 -0
  149. package/dist/providers/cloudflare/index.d.ts +5 -22
  150. package/dist/providers/cloudflare/index.js +79 -197
  151. package/dist/providers/cloudflare/lib/config.d.ts +16 -0
  152. package/dist/providers/cloudflare/lib/config.js +2 -0
  153. package/dist/providers/cloudflare/lib/discovery.js +29 -0
  154. package/dist/providers/cloudflare/{graphql.js → lib/graphql.js} +1 -1
  155. package/dist/providers/cloudflare/lib/hatch.js +103 -0
  156. package/dist/providers/cloudflare/lib/path-bounds.js +28 -0
  157. package/dist/providers/cloudflare/lib/response-media.js +75 -0
  158. package/dist/providers/cloudflare/openapi.generated.js +4 -3
  159. package/dist/providers/cloudflare/{value-safety.js → safety.js} +487 -0
  160. package/dist/providers/cloudflare/skill.generated.js +2 -10
  161. package/dist/providers/cloudflare/tools.js +360 -0
  162. package/dist/providers/docs/api.js +51 -0
  163. package/dist/providers/docs/index.d.ts +1 -12
  164. package/dist/providers/docs/index.js +53 -1165
  165. package/dist/providers/docs/lib/constants.d.ts +18 -0
  166. package/dist/providers/docs/lib/constants.js +18 -0
  167. package/dist/providers/docs/lib/discovery.js +26 -0
  168. package/dist/providers/docs/lib/requests.js +48 -0
  169. package/dist/providers/docs/lib/schemas.js +168 -0
  170. package/dist/providers/docs/openapi.generated.js +16 -0
  171. package/dist/providers/docs/safety.js +54 -0
  172. package/dist/providers/docs/skill.generated.js +2 -6
  173. package/dist/providers/docs/tools.js +801 -0
  174. package/dist/providers/drive/api.js +177 -0
  175. package/dist/providers/drive/index.d.ts +1 -12
  176. package/dist/providers/drive/index.js +38 -1448
  177. package/dist/providers/drive/lib/constants.d.ts +6 -0
  178. package/dist/providers/drive/lib/constants.js +6 -0
  179. package/dist/providers/drive/lib/contracts.js +532 -0
  180. package/dist/providers/drive/lib/hatch.js +197 -0
  181. package/dist/providers/drive/openapi.generated.js +77 -0
  182. package/dist/providers/drive/safety.js +90 -0
  183. package/dist/providers/drive/skill.generated.js +2 -6
  184. package/dist/providers/drive/tools.js +1290 -0
  185. package/dist/providers/forms/api.js +71 -0
  186. package/dist/providers/forms/index.d.ts +1 -12
  187. package/dist/providers/forms/index.js +49 -1145
  188. package/dist/providers/forms/lib/constants.d.ts +14 -0
  189. package/dist/providers/forms/lib/constants.js +19 -0
  190. package/dist/providers/forms/lib/hatch.js +72 -0
  191. package/dist/providers/forms/openapi.generated.js +23 -0
  192. package/dist/providers/forms/safety.js +34 -0
  193. package/dist/providers/forms/skill.generated.js +2 -8
  194. package/dist/providers/forms/tools.js +1023 -0
  195. package/dist/providers/github/api.js +150 -0
  196. package/dist/providers/github/index.d.ts +4 -5
  197. package/dist/providers/github/index.js +30 -87
  198. package/dist/providers/github/{auth.d.ts → lib/auth.d.ts} +5 -3
  199. package/dist/providers/github/{auth.js → lib/auth.js} +40 -43
  200. package/dist/providers/github/lib/discovery.js +132 -0
  201. package/dist/providers/github/lib/operations.js +58 -0
  202. package/dist/providers/github/{scope.d.ts → lib/scope.d.ts} +2 -0
  203. package/dist/providers/github/{scope.js → lib/scope.js} +25 -1
  204. package/dist/providers/github/openapi.generated.js +1216 -0
  205. package/dist/providers/github/safety.js +216 -0
  206. package/dist/providers/github/skill.generated.js +2 -5
  207. package/dist/providers/github/tools.js +506 -0
  208. package/dist/providers/gmail/api.js +114 -0
  209. package/dist/providers/gmail/index.d.ts +1 -12
  210. package/dist/providers/gmail/index.js +73 -1621
  211. package/dist/providers/gmail/lib/constants.d.ts +13 -0
  212. package/dist/providers/gmail/lib/constants.js +16 -0
  213. package/dist/providers/gmail/lib/index.js +173 -0
  214. package/dist/providers/gmail/lib/schemas.js +176 -0
  215. package/dist/providers/gmail/lib/threading.js +120 -0
  216. package/dist/providers/gmail/openapi.generated.js +92 -0
  217. package/dist/providers/gmail/safety.js +21 -0
  218. package/dist/providers/gmail/skill.generated.js +2 -6
  219. package/dist/providers/gmail/tools.js +1435 -0
  220. package/dist/providers/overflow/api.js +1008 -0
  221. package/dist/providers/overflow/index.d.ts +1 -17
  222. package/dist/providers/overflow/index.js +60 -1488
  223. package/dist/providers/overflow/skill.generated.js +2 -5
  224. package/dist/providers/overflow/tools.js +873 -0
  225. package/dist/providers/planning-center/api.js +467 -0
  226. package/dist/providers/planning-center/index.d.ts +4 -35
  227. package/dist/providers/planning-center/index.js +69 -2445
  228. package/dist/providers/planning-center/lib/constants.d.ts +58 -0
  229. package/dist/providers/planning-center/lib/constants.js +83 -0
  230. package/dist/providers/planning-center/lib/discovery.js +40 -0
  231. package/dist/providers/planning-center/lib/guide.js +39 -0
  232. package/dist/providers/planning-center/lib/json-api.js +83 -0
  233. package/dist/providers/planning-center/lib/verdicts.js +1758 -0
  234. package/dist/providers/planning-center/openapi.generated.js +1764 -0
  235. package/dist/providers/planning-center/safety.js +188 -0
  236. package/dist/providers/planning-center/skill.generated.js +2 -27
  237. package/dist/providers/planning-center/tools.js +1010 -0
  238. package/dist/providers/quickbooks/api.js +299 -0
  239. package/dist/providers/quickbooks/index.d.ts +13 -0
  240. package/dist/providers/quickbooks/index.js +93 -0
  241. package/dist/providers/quickbooks/lib/query.js +118 -0
  242. package/dist/providers/quickbooks/lib/writes.js +168 -0
  243. package/dist/providers/quickbooks/safety.js +222 -0
  244. package/dist/providers/quickbooks/skill.generated.js +5 -0
  245. package/dist/providers/quickbooks/tools.js +117 -0
  246. package/dist/providers/sheets/api.js +133 -0
  247. package/dist/providers/sheets/index.d.ts +4 -16
  248. package/dist/providers/sheets/index.js +61 -1172
  249. package/dist/providers/sheets/lib/constants.d.ts +14 -0
  250. package/dist/providers/sheets/lib/constants.js +14 -0
  251. package/dist/providers/sheets/lib/hatch.js +163 -0
  252. package/dist/providers/sheets/lib/requests.js +105 -0
  253. package/dist/providers/sheets/lib/schemas.js +138 -0
  254. package/dist/providers/sheets/openapi.generated.js +30 -0
  255. package/dist/providers/sheets/safety.js +27 -0
  256. package/dist/providers/sheets/skill.generated.js +2 -7
  257. package/dist/providers/sheets/tools.js +733 -0
  258. package/dist/providers/slides/api.js +147 -0
  259. package/dist/providers/slides/index.d.ts +2 -10
  260. package/dist/providers/slides/index.js +48 -2555
  261. package/dist/providers/slides/lib/constants.d.ts +11 -0
  262. package/dist/providers/slides/lib/constants.js +11 -0
  263. package/dist/providers/slides/lib/requests.js +60 -0
  264. package/dist/providers/slides/lib/schemas.js +565 -0
  265. package/dist/providers/slides/openapi.generated.js +18 -0
  266. package/dist/providers/slides/skill.generated.js +2 -6
  267. package/dist/providers/slides/tools.js +1968 -0
  268. package/dist/providers/stripe/api.js +401 -0
  269. package/dist/providers/stripe/index.d.ts +5 -27
  270. package/dist/providers/stripe/index.js +74 -210
  271. package/dist/providers/stripe/lib/config.d.ts +4 -0
  272. package/dist/providers/stripe/lib/config.js +2 -0
  273. package/dist/providers/stripe/openapi.generated.js +4 -3
  274. package/dist/providers/stripe/{value-safety.js → safety.js} +5 -5
  275. package/dist/providers/stripe/skill.generated.js +2 -11
  276. package/dist/providers/stripe/tools.js +77 -0
  277. package/dist/providers/tithely/api.js +531 -0
  278. package/dist/providers/tithely/index.d.ts +17 -0
  279. package/dist/providers/tithely/index.js +86 -965
  280. package/dist/providers/tithely/skill.generated.js +2 -5
  281. package/dist/providers/tithely/tools.js +426 -0
  282. package/dist/providers/vercel/api.js +551 -0
  283. package/dist/providers/vercel/index.d.ts +9 -25
  284. package/dist/providers/vercel/index.js +65 -260
  285. package/dist/providers/vercel/lib/config.d.ts +2 -0
  286. package/dist/providers/vercel/lib/config.js +2 -0
  287. package/dist/providers/vercel/lib/index.js +117 -0
  288. package/dist/providers/vercel/lib/logs.js +100 -0
  289. package/dist/providers/vercel/lib/pin.js +270 -0
  290. package/dist/providers/vercel/openapi.generated.js +10 -5
  291. package/dist/providers/vercel/{value-safety.js → safety.js} +247 -38
  292. package/dist/providers/vercel/skill.generated.js +2 -7
  293. package/dist/providers/vercel/tools.js +642 -0
  294. package/dist/redaction-identity.js +47 -0
  295. package/dist/redaction-marker.js +125 -0
  296. package/dist/registry.d.ts +21 -15
  297. package/dist/registry.js +409 -376
  298. package/dist/routes/access-tokens.js +1 -1
  299. package/dist/routes/actor-labels.js +1 -1
  300. package/dist/routes/connect.js +1 -1
  301. package/dist/routes/dispatch.js +103 -0
  302. package/dist/routes/mcp.js +170 -79
  303. package/dist/routes/oauth.js +6 -1
  304. package/dist/routes/operator.js +2 -2
  305. package/dist/routes/shared.d.ts +5 -4
  306. package/dist/routes/shared.js +244 -177
  307. package/dist/routes/skills.js +10 -8
  308. package/dist/routes/ui-config.js +27 -3
  309. package/dist/routes/ui-data.js +21 -20
  310. package/dist/routes/ui.js +1 -1
  311. package/dist/runtime/call-admission.js +0 -26
  312. package/dist/runtime/call-entry.js +30 -0
  313. package/dist/runtime/call.js +552 -0
  314. package/dist/runtime/connector-scope.js +7 -0
  315. package/dist/runtime/credential-probe.js +34 -0
  316. package/dist/runtime/executor.js +40 -0
  317. package/dist/runtime/native-storage.js +63 -0
  318. package/dist/runtime/registry.js +27 -0
  319. package/dist/runtime/request-scope.js +72 -0
  320. package/dist/runtime/run.js +15 -7
  321. package/dist/runtime/shared-read.js +34 -5
  322. package/dist/runtime/storage.js +34 -21
  323. package/dist/sent-secrets.d.ts +194 -37
  324. package/dist/sent-secrets.js +1743 -340
  325. package/dist/server.js +5 -56
  326. package/dist/skills.js +322 -223
  327. package/dist/sqlite.js +15 -14
  328. package/dist/storage/d1-copy.js +255 -0
  329. package/dist/storage/d1-driver.js +15 -0
  330. package/dist/storage/keys.js +28 -0
  331. package/dist/storage/sql-driver.js +88 -0
  332. package/dist/storage/sql-native.js +544 -0
  333. package/dist/storage/sql-schema.d.ts +6 -0
  334. package/dist/storage/sql-schema.js +15 -0
  335. package/dist/storage/sql.d.ts +14 -20
  336. package/dist/storage/sql.js +29 -535
  337. package/dist/timeout.js +0 -26
  338. package/dist/tool-safety.js +20 -10
  339. package/dist/types.d.ts +9 -109
  340. package/dist/ui.d.ts +1 -1
  341. package/dist/ui.js +0 -1
  342. package/dist/upward.js +3 -0
  343. package/dist/usage-guide.js +3 -1
  344. package/dist/validate.d.ts +4 -2
  345. package/dist/validate.js +86 -9
  346. package/dist/version.d.ts +1 -1
  347. package/dist/version.js +1 -1
  348. package/dist/worker.js +312 -292
  349. package/dist/workspace-subject.js +5 -1
  350. package/dist/write-outcome.js +454 -34
  351. package/documentation/README.md +28 -7
  352. package/documentation/architecture.md +2409 -255
  353. package/documentation/auth.md +867 -114
  354. package/documentation/code-mode.md +49 -16
  355. package/documentation/deploying.md +164 -20
  356. package/documentation/hosted-mcp-migration.md +460 -0
  357. package/documentation/integrating.md +129 -144
  358. package/documentation/meta-tools.md +409 -32
  359. package/documentation/operating.md +27 -3
  360. package/documentation/operator-tests.md +3 -0
  361. package/documentation/operator-ui.md +84 -48
  362. package/documentation/provider-auth-migration.md +16 -63
  363. package/documentation/provider-migration-0.29.md +10 -5
  364. package/documentation/provider-migration-0.35.md +975 -0
  365. package/documentation/providers.md +1347 -0
  366. package/examples/worker/AGENTS.md +23 -9
  367. package/examples/worker/README.md +254 -135
  368. package/examples/worker/alchemy.run.ts +116 -0
  369. package/examples/worker/gitignore +10 -0
  370. package/examples/worker/src/connecta.config.ts +23 -21
  371. package/examples/worker/wrangler.jsonc +14 -5
  372. package/guides/connecting-agents.md +157 -0
  373. package/guides/how-it-works.md +156 -0
  374. package/guides/safety-and-trust.md +153 -0
  375. package/package.json +30 -50
  376. package/templates/node/.env.example +3 -0
  377. package/templates/node/README.md +22 -2
  378. package/templates/node/docker-compose.yml +1 -0
  379. package/templates/node/package.json +3 -2
  380. package/templates/node/src/connecta.config.ts +8 -0
  381. package/dist/catalog-drift.d.ts +0 -138
  382. package/dist/catalog-drift.js +0 -578
  383. package/dist/operator-ui/agents.d.ts +0 -74
  384. package/dist/operator-ui/agents.js +0 -104
  385. package/dist/operator-ui/config-summary.js +0 -565
  386. package/dist/operator-ui/connection-map.js +0 -376
  387. package/dist/operator-ui/endpoints.js +0 -221
  388. package/dist/operator-ui/fix-prompts.d.ts +0 -18
  389. package/dist/operator-ui/fix-prompts.js +0 -87
  390. package/dist/operator-ui/health.js +0 -52
  391. package/dist/operator-ui/member-page.js +0 -97
  392. package/dist/operator-ui/overview.js +0 -123
  393. package/dist/operator-ui/setup-commands.js +0 -51
  394. package/dist/operator-ui/view.d.ts +0 -401
  395. package/dist/operator-ui/view.js +0 -705
  396. package/dist/providers/_shared/request-token.js +0 -83
  397. package/dist/providers/_shared/rest/dispatch.js +0 -41
  398. package/dist/providers/_shared/rest/operation-index.d.ts +0 -133
  399. package/dist/providers/_shared/rest/tools.d.ts +0 -141
  400. package/dist/providers/_shared/rest/tools.js +0 -569
  401. package/dist/providers/_shared/rest/value-safety.d.ts +0 -201
  402. package/dist/providers/basecamp/index.d.ts +0 -45
  403. package/dist/providers/basecamp/index.js +0 -997
  404. package/dist/providers/basecamp/skill.generated.js +0 -9
  405. package/dist/providers/cloudflare/rest.d.ts +0 -37
  406. package/dist/providers/cloudflare/rest.js +0 -1097
  407. package/dist/providers/github/hosted.js +0 -218
  408. package/dist/providers/github/rest.js +0 -321
  409. package/dist/providers/infisical/index.d.ts +0 -7
  410. package/dist/providers/infisical/index.js +0 -713
  411. package/dist/providers/infisical/skill.generated.js +0 -8
  412. package/dist/providers/intercom/index.d.ts +0 -24
  413. package/dist/providers/intercom/index.js +0 -121
  414. package/dist/providers/intercom/skill.generated.js +0 -8
  415. package/dist/providers/linear/index.d.ts +0 -55
  416. package/dist/providers/linear/index.js +0 -537
  417. package/dist/providers/linear/skill.generated.js +0 -8
  418. package/dist/providers/mixpanel/index.d.ts +0 -59
  419. package/dist/providers/mixpanel/index.js +0 -472
  420. package/dist/providers/mixpanel/operations.js +0 -20
  421. package/dist/providers/mixpanel/rest.js +0 -603
  422. package/dist/providers/mixpanel/skill.generated.js +0 -10
  423. package/dist/providers/mixpanel/value-safety.js +0 -16
  424. package/dist/providers/notion/index.d.ts +0 -67
  425. package/dist/providers/notion/index.js +0 -368
  426. package/dist/providers/notion/openapi.generated.js +0 -75
  427. package/dist/providers/notion/rest.d.ts +0 -24
  428. package/dist/providers/notion/rest.js +0 -1226
  429. package/dist/providers/notion/skill.generated.js +0 -11
  430. package/dist/providers/notion/value-safety.js +0 -56
  431. package/dist/providers/revenuecat/index.d.ts +0 -51
  432. package/dist/providers/revenuecat/index.js +0 -697
  433. package/dist/providers/revenuecat/skill.generated.js +0 -11
  434. package/dist/providers/stripe/rest.d.ts +0 -14
  435. package/dist/providers/stripe/rest.js +0 -402
  436. package/dist/providers/vercel/rest.d.ts +0 -20
  437. package/dist/providers/vercel/rest.js +0 -1020
  438. package/dist/providers/wispr-flow/index.d.ts +0 -14
  439. package/dist/providers/wispr-flow/index.js +0 -117
  440. package/dist/providers/wispr-flow/skill.generated.js +0 -8
  441. /package/dist/providers/github/{key.js → lib/key.js} +0 -0
@@ -0,0 +1,558 @@
1
+ // Internal HTTP failure contract (decision 0010, B.3). Unreachable from src/index.ts.
2
+ //
3
+ // Every way a kit request can fail, as a tagged error, and the one mapping
4
+ // from those to the wire `ConnectorCallError`. A provider supplies meaning
5
+ // only where meaning differs by vendor: what 401, 403, and 404 say (required,
6
+ // because the same 403 is an ungranted capability at one vendor and a token
7
+ // scope at another), which machine-readable facts its error bodies and
8
+ // headers carry, rules that cut across statuses, and its wording.
9
+ //
10
+ // Classification and wording are two steps. A vendor's `facts` reads a copy
11
+ // of the error body that keeps only tokens, finite numbers, and booleans.
12
+ // Declared public fact values and parsed numeric sources are captured before sent-secret redaction;
13
+ // wording reads a separate extraction from the redacted body. The vendor's
14
+ // rules read those facts and the reviewed `headers` allowlist, nothing
15
+ // else, and return a `Verdict`: a code and retry advice. Only after that does
16
+ // the kit build the vendor's detail line, and the verdict's `words` render
17
+ // the message from it. A rule's input has no prose to read, and when a rule
18
+ // runs, this failure's prose does not exist yet.
19
+ //
20
+ // This file decides no write's outcome. The core does (src/write-outcome.ts):
21
+ // the transport records every request in the core ledger as it leaves, and
22
+ // `api()`'s boundary hands the call's failure to `providerCallFailure`, which
23
+ // reads that ledger over the whole logical call (INV-9). What the kit adds is
24
+ // provenance, recorded where it was observed: a failure that is its own
25
+ // request's served answer is marked as that request's (`vendorRefusal`), so a
26
+ // refusing status counts only for the request that received it. Advice to
27
+ // send a call again is a segment of its own (`resendAdvice`), never part of
28
+ // the message, so output composes it only where the outcome allows.
29
+ // Q8 policy is decided once by the core's `settleWrite` (#917), from the
30
+ // ledger entries this kit forwards its matched proof and renewals to. A
31
+ // write answered 401 stays unknown; only renewal removes its handoff, and
32
+ // only a reviewed authentication-before-execution declaration proves refusal.
33
+ import { Data } from "effect";
34
+ import { ConnectorCallError, isConnectorCallErrorCode, resendAdvice, unavailableCallError, } from "../errors.js";
35
+ import { attachFailureFacts } from "../operator-record.js";
36
+ import { vendorRefusal } from "../provider-call.js";
37
+ import { providerFailureMessage } from "../write-outcome.js";
38
+ /** A request the kit refused before sending: confinement, a shadowed credential header. */
39
+ export class RequestRefused extends Data.TaggedError("RequestRefused") {
40
+ }
41
+ /** `fetch` rejected. `failure` is read for its errno only and never surfaces. */
42
+ export class TransportFailure extends Data.TaggedError("TransportFailure") {
43
+ }
44
+ /** The vendor answered with a redirect; the credential is never forwarded. */
45
+ export class RedirectRefused extends Data.TaggedError("RedirectRefused") {
46
+ }
47
+ /** The body crossed the connector's byte ceiling, declared or streamed. */
48
+ export class ResponseTooLarge extends Data.TaggedError("ResponseTooLarge") {
49
+ }
50
+ /**
51
+ * A logical write was about to be handed to `fetch` a second time in one
52
+ * call, by any path (an Effect retry, a redirect follower, a renewal that
53
+ * replays, a reconnect, a retry under a new request id). Raised below all of
54
+ * them, before anything leaves; `first` is the permanent reservation, which may still be preparing.
55
+ */
56
+ export class ResendRefused extends Data.TaggedError("ResendRefused") {
57
+ }
58
+ /** A non-2xx answer (or an in-band refusal mapped as one), with the body parsed when it was JSON. */
59
+ export class StatusFailure extends Data.TaggedError("StatusFailure") {
60
+ }
61
+ /** A successful status whose body is not JSON. Its text never surfaces. */
62
+ export class UnreadableBody extends Data.TaggedError("UnreadableBody") {
63
+ constructor(options = {}) {
64
+ super(options);
65
+ }
66
+ }
67
+ /** The vendor's own typed verdict: an in-band refusal, a missing credential. */
68
+ export class Refusal extends Data.TaggedError("Refusal") {
69
+ }
70
+ // One completeness-checked vocabulary for the typed client boundary.
71
+ const TAGS = {
72
+ RequestRefused: true,
73
+ TransportFailure: true,
74
+ RedirectRefused: true,
75
+ ResponseTooLarge: true,
76
+ ResendRefused: true,
77
+ StatusFailure: true,
78
+ UnreadableBody: true,
79
+ Refusal: true,
80
+ };
81
+ export function isHttpFailure(error) {
82
+ if (typeof error !== "object" || error === null || !("_tag" in error))
83
+ return false;
84
+ return typeof error._tag === "string" && Object.hasOwn(TAGS, error._tag);
85
+ }
86
+ /** Refuse empty evidence at connection construction (INV-11); prose is never proof by itself. */
87
+ export function validateVendorErrors(vendor) {
88
+ errorMeanings(vendor);
89
+ captureErrorReviews(vendor);
90
+ const proof = vendor.authBeforeExecution;
91
+ if (proof && (typeof proof.evidence !== "string" || !proof.evidence.trim() || typeof proof.matches !== "function")) {
92
+ throw new Error("An authBeforeExecution declaration requires nonempty evidence and a narrow raw-fact predicate.");
93
+ }
94
+ }
95
+ // No 409 default: only a vendor that documents its meaning may name a conflict.
96
+ // The core decides refusal from the served answer's provenance, never this code.
97
+ const DEFAULTS = {
98
+ 400: () => ({ code: "invalid_args" }),
99
+ 422: () => ({ code: "invalid_args" }),
100
+ 429: ({ retryAfterMs: wait }) => ({ code: "rate_limited", retryAfterMs: wait }),
101
+ };
102
+ const serverErrorDefault = ({ retryAfterMs: wait }) => ({ code: "unavailable", retryAfterMs: wait });
103
+ const otherwiseDefault = () => ({ code: "connector_call_failed", retryable: false });
104
+ const TOKEN = /^[A-Za-z0-9_.:[\]-]{1,128}$/;
105
+ /** How many entries of a list the detail line sees. Classification sees them all. */
106
+ const DISPLAYED = 8;
107
+ const MAX_HEADER = 128;
108
+ const MAX_DEPTH = 32;
109
+ const MAX_WAIT_MS = 86_400_000;
110
+ const errorReviews = new WeakMap();
111
+ /** Metadata snapshots contain no request data, promises or services. */
112
+ function captureErrorReviews(vendor) {
113
+ const previous = errorReviews.get(vendor);
114
+ if (previous)
115
+ return previous;
116
+ const presence = {};
117
+ for (const [name, review] of Object.entries(vendor.presence ?? {})) {
118
+ if (!TOKEN.test(name) ||
119
+ !Array.isArray(review.path) ||
120
+ review.path.length === 0 ||
121
+ review.path.length > MAX_DEPTH ||
122
+ review.path.some((part) => typeof part !== "string" || !part) ||
123
+ !["string", "text"].includes(review.content))
124
+ throw new Error("Error presence reviews need a name, a bounded property path and string or text content.");
125
+ presence[name] = Object.freeze({ path: Object.freeze([...review.path]), content: review.content });
126
+ }
127
+ const display = {};
128
+ for (const [name, review] of Object.entries(vendor.displayFacts ?? {})) {
129
+ if (!TOKEN.test(name) || !Number.isSafeInteger(review.maxItems) || review.maxItems < 1 || !review.review.trim())
130
+ throw new Error("Displayed error facts need a positive whole maxItems and a nonempty review.");
131
+ display[name] = review.maxItems;
132
+ }
133
+ const numbers = {};
134
+ for (const [name, review] of Object.entries(vendor.numericFacts ?? {})) {
135
+ const path = review.path;
136
+ const header = review.header;
137
+ if (!TOKEN.test(name) ||
138
+ (header === undefined
139
+ ? !Array.isArray(path) ||
140
+ path.length === 0 ||
141
+ path.length > MAX_DEPTH ||
142
+ path.some((part) => typeof part !== "string" || !part)
143
+ : path !== undefined ||
144
+ typeof header !== "string" ||
145
+ !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(header) ||
146
+ header.length > MAX_HEADER) ||
147
+ (review.format !== undefined &&
148
+ !["integer", "seconds", "epoch-seconds", "retry-after"].includes(review.format)) ||
149
+ (name === "retryAfterMs" && (review.format === undefined || review.format === "integer")) ||
150
+ typeof review.review !== "string" ||
151
+ !review.review.trim())
152
+ throw new Error("Numeric error facts need a name, an exact path or lowercase header, a numeric format and a nonempty review.");
153
+ numbers[name] = Object.freeze({
154
+ ...(header === undefined ? { path: Object.freeze([...path]) } : { header }),
155
+ format: review.format ?? "integer",
156
+ review: review.review,
157
+ });
158
+ }
159
+ const captured = {
160
+ ...(vendor.bodyFailures
161
+ ? {
162
+ bodyFailures: (() => {
163
+ const review = vendor.bodyFailures;
164
+ if (!review.review?.trim() ||
165
+ !review.readFailed?.trim() ||
166
+ !Array.isArray(review.statusOnly) ||
167
+ review.statusOnly.some((status) => !Number.isInteger(status) || status < 400 || status > 599 || status === 401))
168
+ throw new Error("Body-failure handling needs a review, fixed wording and reviewed error statuses other than 401.");
169
+ return Object.freeze({ ...review, statusOnly: Object.freeze([...review.statusOnly]) });
170
+ })(),
171
+ }
172
+ : {}),
173
+ presence: Object.freeze(presence),
174
+ display: Object.freeze(display),
175
+ numbers: Object.freeze(numbers),
176
+ vocabulary: Object.freeze(Object.fromEntries(Object.entries(vendor.factVocabulary ?? {}).map(([name, values]) => {
177
+ if (!TOKEN.test(name) || !Array.isArray(values) || values.some((value) => boundedFact(value) === undefined))
178
+ throw new Error("Error fact vocabularies need token names and finite public token, number or boolean values.");
179
+ return [name, new Set(values)];
180
+ }))),
181
+ };
182
+ errorReviews.set(vendor, captured);
183
+ return captured;
184
+ }
185
+ /**
186
+ * The body as a vendor's `facts` may read it: tokens, finite numbers,
187
+ * booleans, and null, under keys that are tokens. Prose, URLs, and anything
188
+ * deeper than 32 levels are gone before any vendor code runs.
189
+ */
190
+ function tokensOf(value, depth = 0) {
191
+ if (typeof value === "string")
192
+ return TOKEN.test(value) ? value : undefined;
193
+ if (typeof value === "number")
194
+ return Number.isFinite(value) ? value : undefined;
195
+ if (typeof value === "boolean" || value === null)
196
+ return value;
197
+ if (typeof value !== "object" || depth >= MAX_DEPTH)
198
+ return undefined;
199
+ if (Array.isArray(value))
200
+ return value.map((entry) => tokensOf(entry, depth + 1));
201
+ return Object.fromEntries(Object.entries(value).flatMap(([key, entry]) => (TOKEN.test(key) ? [[key, tokensOf(entry, depth + 1)]] : [])));
202
+ }
203
+ function boundedFact(value) {
204
+ if (typeof value === "string")
205
+ return TOKEN.test(value) ? value : undefined;
206
+ if (typeof value === "number")
207
+ return Number.isFinite(value) ? value : undefined;
208
+ return typeof value === "boolean" ? value : undefined;
209
+ }
210
+ /** Keep tokens, finite numbers, and booleans, in complete lists; anything else is dropped. */
211
+ function bounded(facts) {
212
+ return Object.fromEntries(Object.entries(facts)
213
+ .filter(([name]) => TOKEN.test(name))
214
+ .map(([name, value]) => [
215
+ name,
216
+ Array.isArray(value)
217
+ ? value.map(boundedFact).filter((fact) => fact !== undefined)
218
+ : boundedFact(value),
219
+ ]));
220
+ }
221
+ const classifierFacts = new WeakMap();
222
+ function vocabularyFacts(facts, vendor) {
223
+ return Object.fromEntries(Object.entries(captureErrorReviews(vendor).vocabulary).map(([name, values]) => {
224
+ const value = facts[name];
225
+ return [
226
+ name,
227
+ Array.isArray(value)
228
+ ? Object.freeze(value.filter((entry) => values.has(entry)))
229
+ : value !== undefined && values.has(value)
230
+ ? value
231
+ : undefined,
232
+ ];
233
+ }));
234
+ }
235
+ /** Read only declared public facts before redaction; never retain the original body or an unreviewed value. */
236
+ export function captureClassifierFacts(body, vendor, headers = new Headers()) {
237
+ const review = captureErrorReviews(vendor);
238
+ const vocabulary = Object.keys(review.vocabulary).length > 0;
239
+ if (!vocabulary && !Object.keys(review.numbers).length)
240
+ return undefined;
241
+ return {
242
+ vendor,
243
+ facts: vocabulary ? vocabularyFacts(bounded(vendor.facts(tokensOf(body))), vendor) : {},
244
+ numbers: numericFacts(body, headers, review.numbers),
245
+ };
246
+ }
247
+ /** Reject coercions and unbounded text; only parsed integers or bounded wait windows leave this function. */
248
+ function numericValue(value, format) {
249
+ if (typeof value === "string") {
250
+ if (value.length > MAX_HEADER)
251
+ return undefined;
252
+ const raw = value.trim();
253
+ if (format === "retry-after" && /^[A-Za-z]{3}, \d{2} [A-Za-z]{3} \d{4} \d{2}:\d{2}:\d{2} GMT$/.test(raw)) {
254
+ const date = Date.parse(raw);
255
+ return Number.isFinite(date) ? Math.min(MAX_WAIT_MS, Math.max(0, date - Date.now())) : undefined;
256
+ }
257
+ if (!/^\d+$/.test(raw))
258
+ return undefined;
259
+ value = Number(raw);
260
+ }
261
+ if (typeof value !== "number" || !Number.isFinite(value) || !Number.isInteger(value) || value < 0)
262
+ return undefined;
263
+ const integer = Math.min(Number.MAX_SAFE_INTEGER, value);
264
+ if (format === "integer")
265
+ return integer;
266
+ const milliseconds = integer * 1000 - (format === "epoch-seconds" ? Date.now() : 0);
267
+ return Math.min(MAX_WAIT_MS, Math.max(0, milliseconds));
268
+ }
269
+ function numericFacts(body, headers, reviews) {
270
+ return Object.freeze(Object.fromEntries(Object.entries(reviews).map(([name, review]) => {
271
+ let value = review.header === undefined ? body : headers.get(review.header);
272
+ for (const part of review.path ?? [])
273
+ value =
274
+ value !== null && typeof value === "object" && Object.hasOwn(value, part)
275
+ ? value[part]
276
+ : undefined;
277
+ return [name, numericValue(value, review.format ?? "integer")];
278
+ })));
279
+ }
280
+ /** Keep classification facts off the failure's enumerable data and its redacted detail body. */
281
+ export function withClassifierFacts(failure, captured) {
282
+ if (captured)
283
+ classifierFacts.set(failure, captured);
284
+ return failure;
285
+ }
286
+ /** The detail line gets eight list entries by default; reviewed recovery fields retain their fixed bound. */
287
+ function displayed(facts, vendor) {
288
+ const { display } = captureErrorReviews(vendor);
289
+ return Object.fromEntries(Object.entries(facts).map(([name, value]) => [
290
+ name,
291
+ Array.isArray(value) ? value.slice(0, display[name] ?? DISPLAYED) : value,
292
+ ]));
293
+ }
294
+ function visibleHeaders(headers, allowed) {
295
+ const out = Object.create(null);
296
+ for (const name of allowed ?? []) {
297
+ const value = headers.get(name);
298
+ if (value !== null && value.length <= MAX_HEADER && !hasControl(value))
299
+ out[name.toLowerCase()] = value;
300
+ }
301
+ return out;
302
+ }
303
+ function hasControl(value) {
304
+ for (let index = 0; index < value.length; index++) {
305
+ const code = value.charCodeAt(index);
306
+ if (code < 0x20 || code === 0x7f)
307
+ return true;
308
+ }
309
+ return false;
310
+ }
311
+ /** Shed a defect's text and typed identity when any request withholds vendor text. */
312
+ export function withheldDefect(defect, options,
313
+ // Custom probe programs may send outside this ledger, so always withhold their defects.
314
+ always = false) {
315
+ try {
316
+ if (!always && !options.dispatches.some(({ operation }) => operation && options.withholds(operation)))
317
+ return defect;
318
+ }
319
+ catch {
320
+ // A broken visibility hook cannot authorize exposing a defect's text.
321
+ }
322
+ return new Error("A provider hook withholding vendor text failed.");
323
+ }
324
+ /**
325
+ * The single mapping from a kit failure to what an agent reads. It decides
326
+ * no write: the core does, from its ledger (`providerCallFailure` at the
327
+ * `api()` boundary, and Q8's `settleWrite` once per logical call). A failure
328
+ * that is its own request's served answer carries that request as its
329
+ * provenance (`vendorRefusal`, which holds only for a refusing status: a 4xx
330
+ * other than 408). A write call records each 401 its requests met
331
+ * ({@link recordUnauthorized}) and words a blocked resend.
332
+ */
333
+ export function toConnectorCallError(failure, vendor, options) {
334
+ if (options.classification === "write")
335
+ recordUnauthorized(vendor, options);
336
+ // A served read can still issue a physical write (POST or a method override).
337
+ // A blocked resend always reports that reservation's original attempt.
338
+ return failure._tag === "ResendRefused"
339
+ ? resent(failure.first, vendor, options)
340
+ : answered(failure, verdict(failure, vendor, options), options.dispatches);
341
+ }
342
+ /**
343
+ * Provenance (b), recorded where it was observed: `error` is its own
344
+ * request's answer, so it carries that request's core ledger entry. The core
345
+ * counts a refusal only for a refusing status on that entry, and only when it
346
+ * is the one request the whole logical call sent.
347
+ */
348
+ function answered(failure, error, dispatches) {
349
+ const own = dispatches.find((dispatch) => dispatch.failure === failure);
350
+ return own?.request ? vendorRefusal(error, own.request) : error;
351
+ }
352
+ const RESEND = "A second attempt to send it was stopped before it left: connecta sends a write once.";
353
+ /**
354
+ * The transport stopped a second dispatch of a write. The call reports what
355
+ * the first attempt was answered, with that attempt's provenance, so the
356
+ * core keeps a sole served refusal known and anything else that left unknown.
357
+ * A first attempt that never left reports its own failure.
358
+ */
359
+ function resent(first, vendor, options) {
360
+ const own = first.failure ?? (first.state === "answered" && !ok(first.status) ? answerOf(first) : undefined);
361
+ if (own === undefined) {
362
+ return new ConnectorCallError("connector_call_failed", !first.write || first.request?.auxiliary
363
+ ? `The ${JSON.stringify(first.step ?? "write")} write step's slot is already taken. ` +
364
+ `Declare a separate writeSteps entry for each request the tool must send. ${RESEND}`
365
+ : `This call had already sent its write to ${vendor.provider}` +
366
+ `${first.state === "answered" ? `, which answered HTTP ${first.status}` : ""}. ${RESEND}`, { retryable: false });
367
+ }
368
+ const error = verdict(own, vendor, options, first);
369
+ const marked = first.request ? vendorRefusal(error, first.request) : error;
370
+ return providerFailureMessage(marked, `${marked.message} ${RESEND}`);
371
+ }
372
+ /**
373
+ * Record, on the core ledger entry of each write request answered 401, the
374
+ * facts Q8 is decided from (`settleWrite`): that answer's own vendor verdict
375
+ * (`vendorRefusal`, from its recorded answer even when no body was read), and
376
+ * whether the vendor's reviewed `authBeforeExecution` evidence covers it
377
+ * (`ProviderRequest.authBeforeExecution`). It decides nothing: a write's
378
+ * outcome, its code and its handoff are the core's.
379
+ */
380
+ export function recordUnauthorized(vendor, options) {
381
+ const proof = vendor.authBeforeExecution;
382
+ for (const dispatch of options.dispatches) {
383
+ if (!dispatch.write || dispatch.state !== "answered" || dispatch.status !== 401 || !dispatch.request)
384
+ continue;
385
+ const recorded = recordedAnswer(dispatch);
386
+ if (proof !== undefined &&
387
+ proof.evidence.trim().length > 0 &&
388
+ proof.matches(classificationInput(recorded, vendor, options.withholds?.(recorded.operation) === true)))
389
+ dispatch.request.authBeforeExecution = true;
390
+ vendorRefusal(verdict(recorded, vendor, options), dispatch.request);
391
+ }
392
+ }
393
+ /** Use a parsed body only when it belongs to this recorded status; ceilings and later failures cannot supply its code. */
394
+ function recordedAnswer(dispatch) {
395
+ return dispatch.failure?._tag === "StatusFailure" && dispatch.failure.status === dispatch.status
396
+ ? dispatch.failure
397
+ : answerOf(dispatch);
398
+ }
399
+ /** A recorded answer as the failure it was, from the facts the ledger kept (its body is gone). */
400
+ function answerOf(dispatch) {
401
+ return new StatusFailure({
402
+ status: dispatch.status ?? 0,
403
+ headers: dispatch.headers ?? new Headers(),
404
+ body: undefined,
405
+ operation: dispatch.operation ?? { method: "", template: "" },
406
+ });
407
+ }
408
+ function ok(status) {
409
+ return status !== undefined && status >= 200 && status <= 299;
410
+ }
411
+ function verdict(failure, vendor, options, dispatch = options.dispatches.find((entry) => entry.failure === failure)) {
412
+ switch (failure._tag) {
413
+ case "Refusal":
414
+ return failure.error;
415
+ case "RequestRefused":
416
+ return new ConnectorCallError("invalid_args", failure.message);
417
+ case "TransportFailure":
418
+ return unavailableCallError(failure.failure, failure.host, `Could not reach the ${vendor.provider} API.`, options.signal);
419
+ case "RedirectRefused":
420
+ return new ConnectorCallError("connector_call_failed", `${vendor.provider} answered HTTP ${failure.status} with a redirect; this connector talks to exactly one origin and never forwards its credential to another.`, { retryable: false });
421
+ case "ResponseTooLarge": {
422
+ if (dispatch?.status !== undefined &&
423
+ captureErrorReviews(vendor).bodyFailures?.statusOnly.includes(dispatch.status)) {
424
+ // The ceiling discarded the body, not the answered status. Only opted-in
425
+ // statuses use the vendor's status-only rules; 401/Q8 stays unchanged.
426
+ const mapped = statusVerdict(new StatusFailure({
427
+ status: dispatch.status,
428
+ headers: new Headers(),
429
+ body: undefined,
430
+ unreadable: true,
431
+ operation: dispatch.operation ?? { method: "", template: "" },
432
+ }), vendor, options.withholds?.(dispatch.operation ?? { method: "", template: "" }) === true, !dispatch.write);
433
+ return providerFailureMessage(mapped, failure.detail);
434
+ }
435
+ const uncertainWrite = options.classification === "write" &&
436
+ dispatch?.request?.auxiliary !== true &&
437
+ dispatch?.status !== undefined &&
438
+ Number.isInteger(dispatch.status) &&
439
+ ok(dispatch.status);
440
+ return attachFailureFacts(new ConnectorCallError("connector_call_failed", uncertainWrite
441
+ ? `${failure.detail} Whether the write took effect is unknown; check the target before repeating it.`
442
+ : failure.detail, { retryable: false }), dispatch?.status === undefined ? {} : { httpStatus: dispatch.status });
443
+ }
444
+ case "ResendRefused":
445
+ return new ConnectorCallError("connector_call_failed", `This call already sent a write to ${vendor.provider}; a second attempt was stopped before it left.`, { retryable: false });
446
+ case "UnreadableBody": {
447
+ const unreadable = failure.readFailed
448
+ ? (captureErrorReviews(vendor).bodyFailures?.readFailed ?? vendor.unreadable)
449
+ : failure.unexpectedText
450
+ ? `${vendor.provider} returned unexpected text/HTML for a JSON response.`
451
+ : vendor.unreadable;
452
+ return new ConnectorCallError("connector_call_failed", options.classification === "write" && dispatch?.request?.auxiliary !== true
453
+ ? (!failure.unexpectedText && vendor.unreadableWrite) ||
454
+ `${unreadable} Whether the write took effect is unknown; check the target before repeating it.`
455
+ : unreadable, { retryable: false });
456
+ }
457
+ case "StatusFailure":
458
+ return statusVerdict(failure, vendor, options.withholds?.(failure.operation) === true, options.dispatches.some((dispatch) => dispatch.failure === failure && !dispatch.write));
459
+ }
460
+ }
461
+ function statusVerdict(failure, vendor, withheld, read) {
462
+ const input = classificationInput(failure, vendor, withheld);
463
+ const { headers, presence } = input;
464
+ // Classification first, over facts and headers only.
465
+ const decided = classified(input, vendor);
466
+ // The transport already applied the core's positive-read method/header rule.
467
+ // A 421 advises an explicit retry only for that request; no resend happens here.
468
+ const { code, retryable, retryAfterMs: wait, current, words, advice, } = failure.status === 421 && read ? { ...decided, code: "unavailable", retryable: true } : decided;
469
+ // Then the wording. The body reaches `detail` only when this operation's
470
+ // value-safety review lets its vendor text through.
471
+ const detail = vendor.detail({
472
+ status: failure.status,
473
+ facts: displayed(bounded(vendor.facts(tokensOf(failure.body))), vendor),
474
+ presence,
475
+ numbers: numericFacts(failure.body, failure.headers, captureErrorReviews(vendor).numbers),
476
+ headers,
477
+ withheld,
478
+ ...(withheld ? {} : { body: failure.body }),
479
+ });
480
+ const error = new ConnectorCallError(code, words ? words(detail) : detail, {
481
+ ...(retryable === undefined ? {} : { retryable }),
482
+ ...(wait === undefined ? {} : { retryAfterMs: wait }),
483
+ ...(current ? { current } : {}),
484
+ });
485
+ attachFailureFacts(error, { httpStatus: failure.status });
486
+ return advice === undefined ? error : resendAdvice(error, advice);
487
+ }
488
+ /** Only membership and whitespace are examined; no text is copied into classification. */
489
+ function structuralPresence(body, reviews) {
490
+ return Object.fromEntries(Object.entries(reviews ?? {}).map(([name, review]) => {
491
+ let value = body;
492
+ for (const part of review.path) {
493
+ value =
494
+ value !== null && typeof value === "object" && Object.hasOwn(value, part)
495
+ ? value[part]
496
+ : undefined;
497
+ }
498
+ const strings = typeof value === "string"
499
+ ? [value]
500
+ : review.content === "text" && Array.isArray(value)
501
+ ? value.filter((entry) => typeof entry === "string")
502
+ : [];
503
+ return [
504
+ name,
505
+ { present: strings.some((text) => text.length > 0), nonBlank: strings.some((text) => text.trim().length > 0) },
506
+ ];
507
+ }));
508
+ }
509
+ function classificationInput(failure, vendor, withheld) {
510
+ const redacted = bounded(vendor.facts(tokensOf(failure.body)));
511
+ const captured = classifierFacts.get(failure);
512
+ const numbers = captured?.vendor === vendor
513
+ ? captured.numbers
514
+ : numericFacts(failure.body, failure.headers, captureErrorReviews(vendor).numbers);
515
+ return {
516
+ status: failure.status,
517
+ facts: { ...redacted, ...(captured?.vendor === vendor ? captured.facts : vocabularyFacts(redacted, vendor)) },
518
+ presence: structuralPresence(failure.body, captureErrorReviews(vendor).presence),
519
+ numbers,
520
+ headers: visibleHeaders(failure.headers, vendor.headers),
521
+ retryAfterMs: numbers["retryAfterMs"],
522
+ operation: failure.operation,
523
+ withheld,
524
+ };
525
+ }
526
+ /**
527
+ * A frozen copy of a vendor's declared meanings, refused when inconsistent
528
+ * (INV-11): `not_found` exactly when the vendor tells absence from a
529
+ * permission gap, and each conflict source a one-line documented fact.
530
+ */
531
+ export function errorMeanings(vendor) {
532
+ const declared = vendor.meanings;
533
+ if (declared === undefined)
534
+ return undefined;
535
+ const { unknownId, provesAbsence, conflicts } = declared;
536
+ if (!isConnectorCallErrorCode(unknownId) ||
537
+ typeof provesAbsence !== "boolean" ||
538
+ (unknownId === "not_found") !== provesAbsence ||
539
+ !Array.isArray(conflicts) ||
540
+ conflicts.some((fact) => typeof fact !== "string" || !fact.trim() || /[\r\n]/.test(fact))) {
541
+ throw new Error(`${vendor.provider} error meanings need unknownId "not_found" exactly when provesAbsence is true, and one-line conflict facts.`);
542
+ }
543
+ return Object.freeze({ unknownId, provesAbsence, conflicts: Object.freeze([...conflicts]) });
544
+ }
545
+ function classified(input, vendor) {
546
+ for (const rule of vendor.classify ?? []) {
547
+ const decided = rule(input);
548
+ if (decided)
549
+ return decided;
550
+ }
551
+ const table = vendor.statuses;
552
+ const rule = table[input.status] ??
553
+ (input.status >= 500 && input.status <= 599 ? (table.serverError ?? serverErrorDefault) : undefined) ??
554
+ DEFAULTS[input.status] ??
555
+ table.otherwise ??
556
+ otherwiseDefault;
557
+ return rule(input);
558
+ }
@@ -0,0 +1,49 @@
1
+ // Internal provider kit (decision 0011 S5). Unreachable from src/index.ts.
2
+ //
3
+ // `fields` narrows a result to the dot paths an agent names. It runs on the
4
+ // result a tool already built (after value safety, the privacy projection and
5
+ // any named projection), so it can only remove. A list narrows each item.
6
+ import { Schema } from "effect";
7
+ import { ConnectorCallError } from "../errors.js";
8
+ import { isMaxChars, isMinChars } from "./json-schema.js";
9
+ const MAX_FIELDS = 50;
10
+ /** The `fields` argument: at most 50 dot paths of 1 to 200 characters. */
11
+ export function fieldsInput(description) {
12
+ return Schema.Array(Schema.String.check(isMinChars(1), isMaxChars(200)))
13
+ .check(Schema.isMaxLength(MAX_FIELDS))
14
+ .annotate({ description });
15
+ }
16
+ function record(value) {
17
+ return value !== null && typeof value === "object" && !Array.isArray(value);
18
+ }
19
+ /**
20
+ * The refusal for a path whose first segment is not a property the result can
21
+ * carry, if any. Named tools pass their output Schema's property names and
22
+ * the hatch its operation's declared response roots, so a bad path fails
23
+ * before anything is sent.
24
+ */
25
+ export function fieldsProblem(fields, names, of) {
26
+ const bad = fields?.find((field) => !names.has(field.replace(/\[\](?=\.|$)/g, "").split(".")[0]));
27
+ if (bad === undefined)
28
+ return undefined;
29
+ const choices = names.size > 0 && names.size <= 40 ? `: one of ${[...names].join(", ")}` : "";
30
+ return new ConnectorCallError("invalid_args", `fields path ${bad} does not begin with a property of ${of}${choices}.`);
31
+ }
32
+ /** Keep only the named dot paths; arrays are narrowed item by item. */
33
+ export function selectFields(data, fields) {
34
+ if (!fields?.length)
35
+ return data;
36
+ const pick = (value, paths) => {
37
+ if (Array.isArray(value))
38
+ return value.map((item) => pick(item, paths));
39
+ if (!record(value))
40
+ return value;
41
+ const children = new Map();
42
+ for (const path of paths) {
43
+ const [key, ...tail] = path.replace(/\[\](?=\.|$)/g, "").split(".");
44
+ children.set(key, [...(children.get(key) ?? []), tail.join(".")]);
45
+ }
46
+ return Object.fromEntries([...children].flatMap(([key, tails]) => Object.hasOwn(value, key) ? [[key, tails.includes("") ? value[key] : pick(value[key], tails)]] : []));
47
+ };
48
+ return pick(data, fields);
49
+ }