@zackbart/connecta 0.34.1 → 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 (429) hide show
  1. package/CHANGELOG.md +363 -0
  2. package/README.md +62 -106
  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 +12 -7
  53. package/dist/connectors/api-connector.js +142 -56
  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 +228 -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 +383 -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/agents.d.ts +5 -4
  109. package/dist/operator-ui/agents.js +17 -7
  110. package/dist/operator-ui/config-summary.js +5 -4
  111. package/dist/operator-ui/connection-map.js +7 -5
  112. package/dist/operator-ui/contract.d.ts +7 -3
  113. package/dist/operator-ui/endpoints.js +4 -13
  114. package/dist/operator-ui/fix-prompts.d.ts +1 -1
  115. package/dist/operator-ui/fix-prompts.js +0 -8
  116. package/dist/operator-ui/generated.js +3 -3
  117. package/dist/operator-ui/model.d.ts +2 -3
  118. package/dist/operator-ui/overview.js +5 -2
  119. package/dist/operator-ui/setup-commands.js +0 -4
  120. package/dist/operator-ui/view.d.ts +2 -25
  121. package/dist/operator-ui/view.js +2 -76
  122. package/dist/program-writes.js +47 -26
  123. package/dist/provider-call-facts.d.ts +115 -0
  124. package/dist/provider-call-facts.js +182 -0
  125. package/dist/provider-call.d.ts +112 -0
  126. package/dist/provider-call.js +271 -0
  127. package/dist/provider.d.ts +65 -31
  128. package/dist/provider.js +116 -39
  129. package/dist/providers/_shared/google/hatch.js +91 -0
  130. package/dist/providers/_shared/google/kit.js +537 -0
  131. package/dist/providers/_shared/google/result-size.js +15 -2
  132. package/dist/providers/_shared/google/service-account.d.ts +2 -1
  133. package/dist/providers/_shared/google/service-account.js +8 -4
  134. package/dist/providers/_shared/google/workspace.d.ts +6 -210
  135. package/dist/providers/_shared/google/workspace.js +6 -425
  136. package/dist/providers/_shared/rest/compact-index.js +86 -0
  137. package/dist/providers/_shared/rest/dispatch.js +3 -23
  138. package/dist/providers/_shared/rest/kit.js +546 -0
  139. package/dist/providers/_shared/rest/operation-index.js +230 -14
  140. package/dist/providers/_shared/rest/response-media.js +11 -0
  141. package/dist/providers/_shared/rest/tools.js +101 -78
  142. package/dist/providers/_shared/rest/value-safety.js +353 -195
  143. package/dist/providers/_shared/sensitive-fields.js +27 -0
  144. package/dist/providers/breeze/api.js +584 -0
  145. package/dist/providers/breeze/index.d.ts +1 -3
  146. package/dist/providers/breeze/index.js +67 -1420
  147. package/dist/providers/breeze/openapi.generated.js +60 -0
  148. package/dist/providers/breeze/skill.generated.js +2 -6
  149. package/dist/providers/breeze/tools.js +696 -0
  150. package/dist/providers/ccb/api.js +496 -0
  151. package/dist/providers/ccb/index.d.ts +15 -37
  152. package/dist/providers/ccb/index.js +77 -1702
  153. package/dist/providers/ccb/lib/constants.d.ts +34 -0
  154. package/dist/providers/ccb/lib/constants.js +74 -0
  155. package/dist/providers/ccb/lib/guide.js +9 -0
  156. package/dist/providers/ccb/lib/verdicts.js +387 -0
  157. package/dist/providers/ccb/openapi.generated.js +397 -0
  158. package/dist/providers/ccb/safety.js +295 -0
  159. package/dist/providers/ccb/skill.generated.js +2 -6
  160. package/dist/providers/ccb/tools.js +853 -0
  161. package/dist/providers/cloudflare/api.js +1066 -0
  162. package/dist/providers/cloudflare/index.d.ts +5 -22
  163. package/dist/providers/cloudflare/index.js +79 -197
  164. package/dist/providers/cloudflare/lib/config.d.ts +16 -0
  165. package/dist/providers/cloudflare/lib/config.js +2 -0
  166. package/dist/providers/cloudflare/lib/discovery.js +29 -0
  167. package/dist/providers/cloudflare/{graphql.js → lib/graphql.js} +1 -1
  168. package/dist/providers/cloudflare/lib/hatch.js +103 -0
  169. package/dist/providers/cloudflare/lib/path-bounds.js +28 -0
  170. package/dist/providers/cloudflare/lib/response-media.js +75 -0
  171. package/dist/providers/cloudflare/openapi.generated.js +4 -3
  172. package/dist/providers/cloudflare/{value-safety.js → safety.js} +487 -0
  173. package/dist/providers/cloudflare/skill.generated.js +2 -10
  174. package/dist/providers/cloudflare/tools.js +360 -0
  175. package/dist/providers/docs/api.js +51 -0
  176. package/dist/providers/docs/index.d.ts +1 -12
  177. package/dist/providers/docs/index.js +53 -1165
  178. package/dist/providers/docs/lib/constants.d.ts +18 -0
  179. package/dist/providers/docs/lib/constants.js +18 -0
  180. package/dist/providers/docs/lib/discovery.js +26 -0
  181. package/dist/providers/docs/lib/requests.js +48 -0
  182. package/dist/providers/docs/lib/schemas.js +168 -0
  183. package/dist/providers/docs/openapi.generated.js +16 -0
  184. package/dist/providers/docs/safety.js +54 -0
  185. package/dist/providers/docs/skill.generated.js +2 -6
  186. package/dist/providers/docs/tools.js +802 -0
  187. package/dist/providers/drive/api.js +177 -0
  188. package/dist/providers/drive/index.d.ts +1 -12
  189. package/dist/providers/drive/index.js +38 -1448
  190. package/dist/providers/drive/lib/constants.d.ts +6 -0
  191. package/dist/providers/drive/lib/constants.js +6 -0
  192. package/dist/providers/drive/lib/contracts.js +532 -0
  193. package/dist/providers/drive/lib/hatch.js +197 -0
  194. package/dist/providers/drive/openapi.generated.js +77 -0
  195. package/dist/providers/drive/safety.js +90 -0
  196. package/dist/providers/drive/skill.generated.js +2 -6
  197. package/dist/providers/drive/tools.js +1290 -0
  198. package/dist/providers/forms/api.js +71 -0
  199. package/dist/providers/forms/index.d.ts +1 -12
  200. package/dist/providers/forms/index.js +49 -1145
  201. package/dist/providers/forms/lib/constants.d.ts +14 -0
  202. package/dist/providers/forms/lib/constants.js +19 -0
  203. package/dist/providers/forms/lib/hatch.js +72 -0
  204. package/dist/providers/forms/openapi.generated.js +23 -0
  205. package/dist/providers/forms/safety.js +34 -0
  206. package/dist/providers/forms/skill.generated.js +2 -8
  207. package/dist/providers/forms/tools.js +1024 -0
  208. package/dist/providers/github/api.js +150 -0
  209. package/dist/providers/github/index.d.ts +4 -5
  210. package/dist/providers/github/index.js +30 -87
  211. package/dist/providers/github/{auth.d.ts → lib/auth.d.ts} +5 -3
  212. package/dist/providers/github/{auth.js → lib/auth.js} +40 -43
  213. package/dist/providers/github/lib/discovery.js +132 -0
  214. package/dist/providers/github/lib/operations.js +58 -0
  215. package/dist/providers/github/{scope.d.ts → lib/scope.d.ts} +2 -0
  216. package/dist/providers/github/{scope.js → lib/scope.js} +25 -1
  217. package/dist/providers/github/openapi.generated.js +1216 -0
  218. package/dist/providers/github/safety.js +216 -0
  219. package/dist/providers/github/skill.generated.js +2 -5
  220. package/dist/providers/github/tools.js +506 -0
  221. package/dist/providers/gmail/api.js +114 -0
  222. package/dist/providers/gmail/index.d.ts +1 -12
  223. package/dist/providers/gmail/index.js +73 -1621
  224. package/dist/providers/gmail/lib/constants.d.ts +13 -0
  225. package/dist/providers/gmail/lib/constants.js +16 -0
  226. package/dist/providers/gmail/lib/index.js +173 -0
  227. package/dist/providers/gmail/lib/schemas.js +176 -0
  228. package/dist/providers/gmail/lib/threading.js +120 -0
  229. package/dist/providers/gmail/openapi.generated.js +92 -0
  230. package/dist/providers/gmail/safety.js +21 -0
  231. package/dist/providers/gmail/skill.generated.js +2 -6
  232. package/dist/providers/gmail/tools.js +1435 -0
  233. package/dist/providers/overflow/api.js +1008 -0
  234. package/dist/providers/overflow/index.d.ts +1 -17
  235. package/dist/providers/overflow/index.js +60 -1488
  236. package/dist/providers/overflow/skill.generated.js +2 -5
  237. package/dist/providers/overflow/tools.js +873 -0
  238. package/dist/providers/planning-center/api.js +467 -0
  239. package/dist/providers/planning-center/index.d.ts +4 -35
  240. package/dist/providers/planning-center/index.js +69 -2445
  241. package/dist/providers/planning-center/lib/constants.d.ts +58 -0
  242. package/dist/providers/planning-center/lib/constants.js +83 -0
  243. package/dist/providers/planning-center/lib/discovery.js +40 -0
  244. package/dist/providers/planning-center/lib/guide.js +39 -0
  245. package/dist/providers/planning-center/lib/json-api.js +83 -0
  246. package/dist/providers/planning-center/lib/verdicts.js +1758 -0
  247. package/dist/providers/planning-center/openapi.generated.js +1764 -0
  248. package/dist/providers/planning-center/safety.js +188 -0
  249. package/dist/providers/planning-center/skill.generated.js +2 -27
  250. package/dist/providers/planning-center/tools.js +1010 -0
  251. package/dist/providers/sheets/api.js +133 -0
  252. package/dist/providers/sheets/index.d.ts +4 -16
  253. package/dist/providers/sheets/index.js +61 -1172
  254. package/dist/providers/sheets/lib/constants.d.ts +14 -0
  255. package/dist/providers/sheets/lib/constants.js +14 -0
  256. package/dist/providers/sheets/lib/hatch.js +163 -0
  257. package/dist/providers/sheets/lib/requests.js +105 -0
  258. package/dist/providers/sheets/lib/schemas.js +138 -0
  259. package/dist/providers/sheets/openapi.generated.js +30 -0
  260. package/dist/providers/sheets/safety.js +27 -0
  261. package/dist/providers/sheets/skill.generated.js +2 -7
  262. package/dist/providers/sheets/tools.js +734 -0
  263. package/dist/providers/slides/api.js +147 -0
  264. package/dist/providers/slides/index.d.ts +2 -10
  265. package/dist/providers/slides/index.js +48 -2555
  266. package/dist/providers/slides/lib/constants.d.ts +11 -0
  267. package/dist/providers/slides/lib/constants.js +11 -0
  268. package/dist/providers/slides/lib/requests.js +60 -0
  269. package/dist/providers/slides/lib/schemas.js +565 -0
  270. package/dist/providers/slides/openapi.generated.js +18 -0
  271. package/dist/providers/slides/skill.generated.js +2 -6
  272. package/dist/providers/slides/tools.js +1968 -0
  273. package/dist/providers/stripe/api.js +401 -0
  274. package/dist/providers/stripe/index.d.ts +5 -27
  275. package/dist/providers/stripe/index.js +74 -210
  276. package/dist/providers/stripe/lib/config.d.ts +4 -0
  277. package/dist/providers/stripe/lib/config.js +2 -0
  278. package/dist/providers/stripe/openapi.generated.js +4 -3
  279. package/dist/providers/stripe/{value-safety.js → safety.js} +5 -5
  280. package/dist/providers/stripe/skill.generated.js +2 -11
  281. package/dist/providers/stripe/tools.js +77 -0
  282. package/dist/providers/tithely/api.js +531 -0
  283. package/dist/providers/tithely/index.d.ts +17 -0
  284. package/dist/providers/tithely/index.js +86 -965
  285. package/dist/providers/tithely/skill.generated.js +2 -5
  286. package/dist/providers/tithely/tools.js +426 -0
  287. package/dist/providers/vercel/api.js +551 -0
  288. package/dist/providers/vercel/index.d.ts +9 -25
  289. package/dist/providers/vercel/index.js +66 -260
  290. package/dist/providers/vercel/lib/config.d.ts +2 -0
  291. package/dist/providers/vercel/lib/config.js +2 -0
  292. package/dist/providers/vercel/lib/index.js +117 -0
  293. package/dist/providers/vercel/lib/logs.js +100 -0
  294. package/dist/providers/vercel/lib/pin.js +270 -0
  295. package/dist/providers/vercel/openapi.generated.js +10 -5
  296. package/dist/providers/vercel/{value-safety.js → safety.js} +247 -38
  297. package/dist/providers/vercel/skill.generated.js +2 -7
  298. package/dist/providers/vercel/tools.js +642 -0
  299. package/dist/redaction-identity.js +47 -0
  300. package/dist/redaction-marker.js +125 -0
  301. package/dist/registry.d.ts +21 -15
  302. package/dist/registry.js +409 -376
  303. package/dist/routes/access-tokens.js +1 -1
  304. package/dist/routes/actor-labels.js +1 -1
  305. package/dist/routes/connect.js +1 -1
  306. package/dist/routes/dispatch.js +103 -0
  307. package/dist/routes/mcp.js +170 -79
  308. package/dist/routes/oauth.js +3 -1
  309. package/dist/routes/operator.js +2 -2
  310. package/dist/routes/shared.d.ts +5 -4
  311. package/dist/routes/shared.js +244 -177
  312. package/dist/routes/skills.js +10 -8
  313. package/dist/routes/ui-config.js +27 -3
  314. package/dist/routes/ui-data.js +21 -20
  315. package/dist/routes/ui.js +1 -1
  316. package/dist/runtime/call-admission.js +0 -26
  317. package/dist/runtime/call-entry.js +30 -0
  318. package/dist/runtime/call.js +556 -0
  319. package/dist/runtime/connector-scope.js +7 -0
  320. package/dist/runtime/credential-probe.js +34 -0
  321. package/dist/runtime/executor.js +40 -0
  322. package/dist/runtime/native-storage.js +63 -0
  323. package/dist/runtime/registry.js +27 -0
  324. package/dist/runtime/request-scope.js +72 -0
  325. package/dist/runtime/run.js +15 -7
  326. package/dist/runtime/shared-read.js +34 -5
  327. package/dist/runtime/storage.js +34 -21
  328. package/dist/sent-secrets.d.ts +194 -37
  329. package/dist/sent-secrets.js +1743 -340
  330. package/dist/server.js +5 -56
  331. package/dist/skills.js +322 -222
  332. package/dist/sqlite.js +15 -14
  333. package/dist/storage/d1-copy.js +255 -0
  334. package/dist/storage/d1-driver.js +15 -0
  335. package/dist/storage/keys.js +28 -0
  336. package/dist/storage/sql-driver.js +88 -0
  337. package/dist/storage/sql-native.js +544 -0
  338. package/dist/storage/sql-schema.d.ts +6 -0
  339. package/dist/storage/sql-schema.js +15 -0
  340. package/dist/storage/sql.d.ts +14 -20
  341. package/dist/storage/sql.js +29 -535
  342. package/dist/timeout.js +0 -26
  343. package/dist/tool-safety.js +20 -10
  344. package/dist/types.d.ts +7 -109
  345. package/dist/upward.js +3 -0
  346. package/dist/usage-guide.js +3 -1
  347. package/dist/validate.d.ts +4 -2
  348. package/dist/validate.js +86 -9
  349. package/dist/version.d.ts +1 -1
  350. package/dist/version.js +1 -1
  351. package/dist/worker.js +312 -292
  352. package/dist/workspace-subject.js +5 -1
  353. package/dist/write-outcome.js +454 -34
  354. package/documentation/README.md +27 -7
  355. package/documentation/architecture.md +2547 -226
  356. package/documentation/auth.md +821 -98
  357. package/documentation/code-mode.md +49 -16
  358. package/documentation/deploying.md +164 -20
  359. package/documentation/hosted-mcp-migration.md +460 -0
  360. package/documentation/integrating.md +129 -144
  361. package/documentation/meta-tools.md +409 -32
  362. package/documentation/operating.md +27 -3
  363. package/documentation/operator-tests.md +3 -0
  364. package/documentation/operator-ui.md +68 -45
  365. package/documentation/provider-auth-migration.md +16 -63
  366. package/documentation/provider-migration-0.29.md +10 -5
  367. package/documentation/provider-migration-0.35.md +975 -0
  368. package/documentation/providers.md +965 -0
  369. package/examples/worker/AGENTS.md +23 -9
  370. package/examples/worker/README.md +254 -135
  371. package/examples/worker/alchemy.run.ts +116 -0
  372. package/examples/worker/gitignore +10 -0
  373. package/examples/worker/src/connecta.config.ts +23 -21
  374. package/examples/worker/wrangler.jsonc +14 -5
  375. package/guides/connecting-agents.md +157 -0
  376. package/guides/how-it-works.md +156 -0
  377. package/guides/safety-and-trust.md +153 -0
  378. package/package.json +27 -46
  379. package/templates/node/.env.example +3 -0
  380. package/templates/node/README.md +22 -2
  381. package/templates/node/docker-compose.yml +1 -0
  382. package/templates/node/package.json +3 -2
  383. package/templates/node/src/connecta.config.ts +8 -0
  384. package/dist/catalog-drift.d.ts +0 -138
  385. package/dist/catalog-drift.js +0 -578
  386. package/dist/providers/_shared/request-token.js +0 -83
  387. package/dist/providers/_shared/rest/operation-index.d.ts +0 -133
  388. package/dist/providers/_shared/rest/tools.d.ts +0 -141
  389. package/dist/providers/_shared/rest/value-safety.d.ts +0 -201
  390. package/dist/providers/basecamp/index.d.ts +0 -45
  391. package/dist/providers/basecamp/index.js +0 -997
  392. package/dist/providers/basecamp/skill.generated.js +0 -9
  393. package/dist/providers/cloudflare/rest.d.ts +0 -37
  394. package/dist/providers/cloudflare/rest.js +0 -1097
  395. package/dist/providers/github/hosted.js +0 -218
  396. package/dist/providers/github/rest.js +0 -321
  397. package/dist/providers/infisical/index.d.ts +0 -7
  398. package/dist/providers/infisical/index.js +0 -713
  399. package/dist/providers/infisical/skill.generated.js +0 -8
  400. package/dist/providers/intercom/index.d.ts +0 -24
  401. package/dist/providers/intercom/index.js +0 -121
  402. package/dist/providers/intercom/skill.generated.js +0 -8
  403. package/dist/providers/linear/index.d.ts +0 -55
  404. package/dist/providers/linear/index.js +0 -537
  405. package/dist/providers/linear/skill.generated.js +0 -8
  406. package/dist/providers/mixpanel/index.d.ts +0 -59
  407. package/dist/providers/mixpanel/index.js +0 -472
  408. package/dist/providers/mixpanel/operations.js +0 -20
  409. package/dist/providers/mixpanel/rest.js +0 -603
  410. package/dist/providers/mixpanel/skill.generated.js +0 -10
  411. package/dist/providers/mixpanel/value-safety.js +0 -16
  412. package/dist/providers/notion/index.d.ts +0 -67
  413. package/dist/providers/notion/index.js +0 -368
  414. package/dist/providers/notion/openapi.generated.js +0 -75
  415. package/dist/providers/notion/rest.d.ts +0 -24
  416. package/dist/providers/notion/rest.js +0 -1226
  417. package/dist/providers/notion/skill.generated.js +0 -11
  418. package/dist/providers/notion/value-safety.js +0 -56
  419. package/dist/providers/revenuecat/index.d.ts +0 -51
  420. package/dist/providers/revenuecat/index.js +0 -697
  421. package/dist/providers/revenuecat/skill.generated.js +0 -11
  422. package/dist/providers/stripe/rest.d.ts +0 -14
  423. package/dist/providers/stripe/rest.js +0 -402
  424. package/dist/providers/vercel/rest.d.ts +0 -20
  425. package/dist/providers/vercel/rest.js +0 -1020
  426. package/dist/providers/wispr-flow/index.d.ts +0 -14
  427. package/dist/providers/wispr-flow/index.js +0 -117
  428. package/dist/providers/wispr-flow/skill.generated.js +0 -8
  429. /package/dist/providers/github/{key.js → lib/key.js} +0 -0
@@ -0,0 +1,228 @@
1
+ // Provider kit (decision 0010, B.4). Unreachable from src/index.ts.
2
+ //
3
+ // Paging is a strategy plus one cursor codec. A strategy turns "the next page
4
+ // after this cursor" into a vendor request and reads back rows and the next
5
+ // vendor cursor; tools take one page, and `allRows` walks every page as a
6
+ // Stream for programs and the hatch. The codec is the only place a cursor is
7
+ // minted: `plain` hands the vendor's cursor through (what shipped providers
8
+ // promise today, so goldens hold), `bound` ties it to the tool and its
9
+ // arguments so a cursor from another call is refused instead of silently
10
+ // reading the wrong list.
11
+ import { Effect, Option, Schema, Stream } from "effect";
12
+ import { ConnectorCallError } from "../errors.js";
13
+ import { Refusal } from "./errors.js";
14
+ import { confinementBase } from "../http-policy.js";
15
+ import { canonicalJson } from "../canonical-json.js";
16
+ import { ContinuationBinding, ContinuationStorage } from "../runtime/call.js";
17
+ import { continuationKeys } from "../storage/keys.js";
18
+ /** The `page` object every list tool returns. */
19
+ export const PageInfo = Schema.Struct({
20
+ hasMore: Schema.Boolean,
21
+ nextCursor: Schema.NullOr(Schema.String),
22
+ });
23
+ /**
24
+ * The standard `page` (decision 0011 S2): `nextCursor` is present exactly
25
+ * when `hasMore` is true and continuation is safe. A hatch adapter can report
26
+ * more data without a cursor when its continuation cannot be confined.
27
+ * Step-1 lists keep `PageInfo` until their step 2.
28
+ */
29
+ export const StandardPage = Schema.Struct({
30
+ hasMore: Schema.Boolean,
31
+ nextCursor: Schema.optionalKey(Schema.String),
32
+ });
33
+ /** The input field that carries a cursor back. */
34
+ export const Cursor = Schema.String.check(Schema.isMinLength(1)).annotate({
35
+ description: "Opaque nextCursor from the previous page. Pass it back unchanged.",
36
+ });
37
+ /**
38
+ * Lookahead paging, for a vendor that returns no `has_more`: ask for one row
39
+ * more than wanted, keep `limit`, and address the next page by the last kept
40
+ * row's id. A full page proves nothing; the extra row does.
41
+ */
42
+ export function lookahead(options) {
43
+ return Effect.gen(function* () {
44
+ const all = yield* options.fetch(options.limit + 1);
45
+ const rows = all.slice(0, options.limit);
46
+ const hasMore = all.length > options.limit;
47
+ if (!hasMore)
48
+ return { rows, page: { hasMore, nextCursor: null } };
49
+ const last = rows[rows.length - 1];
50
+ const id = last?.[options.idKey];
51
+ if (typeof id !== "string" || id === "") {
52
+ return yield* Effect.fail(new Refusal({
53
+ error: new ConnectorCallError("connector_call_failed", `${options.provider} returned a page whose last row has no ${options.idKey}, so the next page cannot be addressed.`, { retryable: false }),
54
+ }));
55
+ }
56
+ return { rows, page: { hasMore, nextCursor: id } };
57
+ });
58
+ }
59
+ /** Vendor-supplied continuation, read only after the connection made its data safe. */
60
+ export function token(options) {
61
+ return Effect.flatMap(Effect.suspend(options.fetch), ({ rows, hasMore, nextCursor }) => {
62
+ if (hasMore && !nextCursor)
63
+ return badPage("The vendor reported another page without a next cursor.");
64
+ return Effect.succeed({ rows, page: { hasMore, nextCursor: hasMore ? nextCursor : null } });
65
+ });
66
+ }
67
+ /** Offset paging advances by the rows actually returned, with a total when supplied. */
68
+ export function offset(options) {
69
+ return Effect.gen(function* () {
70
+ yield* position(options.offset, 0);
71
+ yield* position(options.limit, 1);
72
+ return yield* Effect.map(options.fetch(options.offset, options.limit), ({ rows, total }) => {
73
+ const next = options.offset + rows.length;
74
+ const hasMore = rows.length > 0 && (total === undefined ? rows.length >= options.limit : next < total);
75
+ return { rows, page: { hasMore, nextCursor: hasMore ? String(next) : null } };
76
+ });
77
+ });
78
+ }
79
+ /** Page numbers from a vendor's safe body or headers, with full-page fallback. */
80
+ export function page(options) {
81
+ return Effect.gen(function* () {
82
+ yield* position(options.page, 1);
83
+ yield* position(options.limit, 1);
84
+ return yield* Effect.map(options.fetch(options.page, options.limit), ({ rows, hasMore, totalPages }) => {
85
+ const more = hasMore ?? (totalPages === undefined ? rows.length >= options.limit : options.page < totalPages);
86
+ return { rows, page: { hasMore: more, nextCursor: more ? String(options.page + 1) : null } };
87
+ });
88
+ });
89
+ }
90
+ /** Extract only a cursor from a next URL confined to this connection's origin and path. */
91
+ export function link(options) {
92
+ const base = confinementBase("Paging", options.baseUrl);
93
+ const prefix = base.pathname.replace(/\/+$/, "");
94
+ if (!options.param)
95
+ throw new Error("Link paging needs a cursor parameter.");
96
+ return Effect.flatMap(Effect.suspend(options.fetch), ({ rows, next }) => {
97
+ if (!next)
98
+ return Effect.succeed({ rows, page: { hasMore: false, nextCursor: null } });
99
+ let url;
100
+ try {
101
+ url = new URL(next, base);
102
+ }
103
+ catch {
104
+ return badPage("The vendor returned an invalid next-page URL.");
105
+ }
106
+ if (url.origin !== base.origin ||
107
+ !`${url.pathname}/`.startsWith(`${prefix}/`) ||
108
+ url.username ||
109
+ url.password ||
110
+ url.hash)
111
+ return badPage("The vendor returned a next-page URL outside this connection.");
112
+ const cursors = url.searchParams.getAll(options.param);
113
+ if (cursors.length !== 1 || !cursors[0])
114
+ return badPage("The vendor returned no unique next-page cursor.");
115
+ return Effect.succeed({ rows, page: { hasMore: true, nextCursor: cursors[0] } });
116
+ });
117
+ }
118
+ function position(value, minimum) {
119
+ return Number.isSafeInteger(value) && value >= minimum
120
+ ? Effect.void
121
+ : Effect.fail(new Refusal({
122
+ error: new ConnectorCallError("invalid_args", "Paging positions and limits must be whole numbers within their bounds."),
123
+ }));
124
+ }
125
+ function badPage(message) {
126
+ return Effect.fail(new Refusal({ error: new ConnectorCallError("connector_call_failed", message, { retryable: false }) }));
127
+ }
128
+ /** Every row of every page, fetched as the stream is pulled. */
129
+ export function allRows(fetchPage) {
130
+ return Stream.paginate(undefined, (cursor) => Effect.map(fetchPage(cursor), ({ rows, page }) => [rows, Option.fromNullishOr(page.hasMore ? page.nextCursor : null)]));
131
+ }
132
+ const STRAY_CURSOR = "This cursor belongs to a different call. Pass back the nextCursor from the previous page of this same call, with the same arguments.";
133
+ /** Resolved, nonextractable keys only: no request promise is retained between calls. */
134
+ const signingKeys = new WeakMap();
135
+ async function signingKey(storage) {
136
+ const cached = signingKeys.get(storage);
137
+ if (cached)
138
+ return cached;
139
+ let raw = await storage.get(continuationKeys.signingKey);
140
+ if (raw === null) {
141
+ const candidate = Array.from(crypto.getRandomValues(new Uint8Array(32)), (byte) => byte.toString(16).padStart(2, "0")).join("");
142
+ raw = (await storage.compareAndSet(continuationKeys.signingKey, null, candidate))
143
+ ? candidate
144
+ : await storage.get(continuationKeys.signingKey);
145
+ }
146
+ if (raw === null || !/^[a-f0-9]{64}$/.test(raw))
147
+ throw new Error("The continuation signing key is unavailable.");
148
+ const key = await crypto.subtle.importKey("raw", Uint8Array.from(raw.match(/../g), (byte) => Number.parseInt(byte, 16)), { name: "HMAC", hash: "SHA-256" }, false, ["sign", "verify"]);
149
+ signingKeys.set(storage, key);
150
+ return key;
151
+ }
152
+ const keyUnavailable = () => new Refusal({
153
+ error: new ConnectorCallError("unavailable", "The cursor signing key is unavailable. Retry after storage recovers; a corrupt key requires operator recovery.", { retryable: true }),
154
+ });
155
+ const keyForCall = ContinuationStorage.use((storage) => storage
156
+ ? Effect.tryPromise({ try: () => signingKey(storage), catch: keyUnavailable })
157
+ : Effect.fail(keyUnavailable()));
158
+ /**
159
+ * Authenticated base64url JSON `{v, d, c, m}`: the MAC covers the version,
160
+ * connection/owner/caller binding, tool/argument digest and continuation
161
+ * payload in a canonical tuple and envelope. The deployment store owns
162
+ * the key across isolates/restarts; limit and cursor are excluded from args.
163
+ */
164
+ export const boundCursor = {
165
+ encode(tool, args, cursor, encode = base64url) {
166
+ return Effect.gen(function* () {
167
+ const d = yield* digest(tool, args);
168
+ const key = yield* keyForCall;
169
+ const binding = yield* ContinuationBinding;
170
+ const claims = new TextEncoder().encode(canonicalJson([2, binding.connection, binding.principal, d, cursor]));
171
+ const mac = yield* Effect.promise(() => crypto.subtle.sign("HMAC", key, claims));
172
+ const m = base64urlBytes(new Uint8Array(mac));
173
+ return encode(JSON.stringify({ v: 2, d, c: cursor, m }));
174
+ });
175
+ },
176
+ decode(tool, args, token) {
177
+ return Effect.gen(function* () {
178
+ const expected = yield* digest(tool, args);
179
+ let parsed;
180
+ try {
181
+ parsed = JSON.parse(new TextDecoder().decode(fromBase64url(token)));
182
+ }
183
+ catch {
184
+ parsed = undefined;
185
+ }
186
+ const record = parsed;
187
+ if (record?.v !== 2 ||
188
+ record.d !== expected ||
189
+ typeof record.c !== "string" ||
190
+ typeof record.m !== "string" ||
191
+ !/^[A-Za-z0-9_-]{43}$/.test(record.m)) {
192
+ return yield* Effect.fail(new Refusal({ error: new ConnectorCallError("invalid_args", STRAY_CURSOR) }));
193
+ }
194
+ if (token !== base64url(JSON.stringify({ v: record.v, d: record.d, c: record.c, m: record.m })))
195
+ return yield* Effect.fail(new Refusal({ error: new ConnectorCallError("invalid_args", STRAY_CURSOR) }));
196
+ const key = yield* keyForCall;
197
+ const mac = fromBase64url(record.m);
198
+ const binding = yield* ContinuationBinding;
199
+ const claims = new TextEncoder().encode(canonicalJson([record.v, binding.connection, binding.principal, record.d, record.c]));
200
+ const valid = yield* Effect.promise(() => crypto.subtle.verify("HMAC", key, mac, claims));
201
+ if (!valid || base64urlBytes(mac) !== record.m) {
202
+ return yield* Effect.fail(new Refusal({ error: new ConnectorCallError("invalid_args", STRAY_CURSOR) }));
203
+ }
204
+ return record.c;
205
+ });
206
+ },
207
+ };
208
+ function digest(tool, args) {
209
+ const shape = Object.keys(args)
210
+ .filter((key) => key !== "cursor" && key !== "limit" && args[key] !== undefined)
211
+ .sort()
212
+ .map((key) => [key, args[key]]);
213
+ const bytes = new TextEncoder().encode(canonicalJson([tool, shape]));
214
+ return Effect.promise(() => crypto.subtle.digest("SHA-256", bytes)).pipe(Effect.map((hash) => Array.from(new Uint8Array(hash).slice(0, 16), (byte) => byte.toString(16).padStart(2, "0")).join("")));
215
+ }
216
+ function base64url(text) {
217
+ return base64urlBytes(new TextEncoder().encode(text));
218
+ }
219
+ function base64urlBytes(bytes) {
220
+ let binary = "";
221
+ for (const byte of bytes)
222
+ binary += String.fromCharCode(byte);
223
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
224
+ }
225
+ function fromBase64url(token) {
226
+ const binary = atob(token.replace(/-/g, "+").replace(/_/g, "/"));
227
+ return Uint8Array.from(binary, (char) => char.charCodeAt(0));
228
+ }
@@ -0,0 +1,221 @@
1
+ // Internal provider kit (decision 0010, B.4). Unreachable from src/index.ts.
2
+ import { Context, Effect, Option } from "effect";
3
+ import { api } from "../connectors/api.js";
4
+ import { OAUTH_CHALLENGE_MAX_BYTES } from "../auth/renewable-grant.js";
5
+ import { ConnectorCallError } from "../errors.js";
6
+ import { defineProvider, } from "../provider.js";
7
+ import { tracksEveryRequest } from "../provider-call.js";
8
+ import { unsentAfterUnauthorized } from "../write-outcome.js";
9
+ import { Operation } from "../runtime/call.js";
10
+ import { runEdge } from "../runtime/run.js";
11
+ import { guardedClient } from "./client.js";
12
+ import { errorMeanings, Refusal, toConnectorCallError, withheldDefect, } from "./errors.js";
13
+ import { hatch } from "./hatch.js";
14
+ import { takesIdempotencyKey } from "./tools.js";
15
+ import { Grant, grantFromOAuth, refreshOnce } from "./oauth.js";
16
+ import { resultSafety } from "./safety.js";
17
+ import { Classification, Dispatches, Signal, WriteCapacity, fromConnectorContext, } from "./services.js";
18
+ import { connect, operations } from "./vendor.js";
19
+ /** A declared hatch for one connection: its notes resolved from that connection's options. */
20
+ function hatchDeclaration(declared, options, connection) {
21
+ const { notes, binding, writeEnabled, ...rest } = declared;
22
+ return {
23
+ ...rest,
24
+ ...(notes ? { notes: notes(options) } : {}),
25
+ ...(writeEnabled ? { writeEnabled: writeEnabled(options) } : {}),
26
+ ...(binding ? { binding: binding({ connection, options }) } : {}),
27
+ };
28
+ }
29
+ /** Bind the Promise OAuth facade belonging to this call, never a connection-wide grant. */
30
+ const callGrant = Effect.gen(function* () {
31
+ // Operation is bridge metadata, not a service a provider program supplies.
32
+ const operation = yield* Effect.serviceOption(Operation);
33
+ const oauth = Option.isSome(operation) ? operation.value?.oauth : undefined;
34
+ return oauth ? grantFromOAuth(oauth) : missingGrant;
35
+ });
36
+ const noGrant = Effect.fail(new Refusal({
37
+ error: new ConnectorCallError("auth_required", "This connection has no OAuth grant."),
38
+ }));
39
+ const missingGrant = {
40
+ token: noGrant,
41
+ refresh: () => noGrant,
42
+ rejected: noGrant,
43
+ };
44
+ /** An ordinary Promise connector factory; Effect remains inside the kit. */
45
+ export function defineApiProvider(definition) {
46
+ const { displayTitle, description, authScope, vendor, baseUrl, maxResponseBytes, timeoutMs, headers, admit, transport, defaultCallAdmission, pageSize: declaredPageSize, idempotencyKey, credential, oauth, oauthWrite401, grant, grantRenewal, authenticate, errors, safety, result, inBandRefusals, probe, guide, transformGuide, hatch: declaredHatch, tools, tagConnector, ...metadata } = definition;
47
+ if (credential !== undefined && oauth !== undefined) {
48
+ throw new Error(`${metadata.title} declares both credential and oauth; declare one authentication method.`);
49
+ }
50
+ if (oauthWrite401 && !oauth)
51
+ throw new Error("oauthWrite401 requires a static OAuth declaration.");
52
+ if (grant && oauth)
53
+ throw new Error("A provider declares either a machine grant or static OAuth, never both.");
54
+ if (grantRenewal && !grant)
55
+ throw new Error("grantRenewal requires a machine grant declaration.");
56
+ const renewalModes = grantRenewal ? { ...grantRenewal } : undefined;
57
+ if (!Number.isInteger(maxResponseBytes) || maxResponseBytes < 1) {
58
+ throw new Error(`${metadata.title} maxResponseBytes must be a whole number of bytes >= 1.`);
59
+ }
60
+ const pageSize = declaredPageSize === undefined ? undefined : { ...declaredPageSize };
61
+ if (pageSize &&
62
+ (!Number.isSafeInteger(pageSize.default) ||
63
+ !Number.isSafeInteger(pageSize.max) ||
64
+ pageSize.default < 1 ||
65
+ pageSize.max < pageSize.default)) {
66
+ throw new Error(`${metadata.title} pageSize needs positive whole default and max values, with default <= max.`);
67
+ }
68
+ const meanings = errorMeanings(errors);
69
+ if (idempotencyKey !== undefined && typeof idempotencyKey !== "boolean")
70
+ throw new Error(`${metadata.title} idempotencyKey must be true or false when declared.`);
71
+ const hatchOptions = declaredHatch
72
+ ? {
73
+ ...declaredHatch,
74
+ verdicts: { ...declaredHatch.verdicts },
75
+ ...(declaredHatch.named ? { named: { ...declaredHatch.named } } : {}),
76
+ }
77
+ : undefined;
78
+ return defineProvider({
79
+ ...metadata,
80
+ kind: "api",
81
+ kit: {
82
+ operations: operations(vendor),
83
+ ...(pageSize ? { pageSize } : {}),
84
+ ...(hatchOptions
85
+ ? {
86
+ hatch: {
87
+ name: hatchOptions.name,
88
+ verdicts: hatchOptions.verdicts,
89
+ ...(hatchOptions.fieldsRoot ? { fieldsRoot: hatchOptions.fieldsRoot } : {}),
90
+ ...(hatchOptions.pageCursor && Object.keys(hatchOptions.pages ?? {}).length
91
+ ? { paging: hatchOptions.pageCursor }
92
+ : {}),
93
+ },
94
+ refusesWithheld: true,
95
+ }
96
+ : {}),
97
+ ...(meanings ? { errors: meanings } : {}),
98
+ ...(idempotencyKey === undefined ? {} : { idempotencyKey }),
99
+ },
100
+ create(id, options, provider) {
101
+ const connectionCredential = typeof credential === "function" ? credential(options) : credential;
102
+ const override = "defaultPageSize" in options ? options.defaultPageSize : undefined;
103
+ if (override !== undefined &&
104
+ (!pageSize ||
105
+ typeof override !== "number" ||
106
+ !Number.isSafeInteger(override) ||
107
+ override < 1 ||
108
+ override > pageSize.max)) {
109
+ throw new Error(`defaultPageSize must be a whole number from 1 to ${pageSize?.max ?? "a declared pageSize maximum"}.`);
110
+ }
111
+ const configured = transport?.(options);
112
+ const machineGrant = grant?.(options);
113
+ const guarded = guardedClient({
114
+ provider: errors.provider,
115
+ baseUrl: baseUrl(options),
116
+ maxResponseBytes,
117
+ ...(timeoutMs === undefined ? {} : { timeoutMs }),
118
+ ...(oauthWrite401 ? { maxUnauthorizedResponseBytes: OAUTH_CHALLENGE_MAX_BYTES } : {}),
119
+ ...(headers === undefined ? {} : { headers }),
120
+ ...(admit === undefined ? {} : { admit }),
121
+ authenticate: typeof authenticate === "function" ? authenticate(options) : authenticate,
122
+ ...configured,
123
+ });
124
+ const connected = connect(vendor, oauth || machineGrant
125
+ ? refreshOnce(guarded, oauthWrite401
126
+ ? {
127
+ challengeMaxBytes: OAUTH_CHALLENGE_MAX_BYTES,
128
+ writeUnauthorized: (renewal) => unsentAfterUnauthorized(`Connector "${id}"'s API`, renewal._tag === "Renewed"
129
+ ? undefined
130
+ : renewal._tag === "Failed"
131
+ ? renewal.failure
132
+ : new ConnectorCallError("downstream_oauth_required", `Connector "${id}" requires authorization — call authorize_connector({ connector: "${id}" }) and open the returned URL.`), "downstream_oauth_required"),
133
+ }
134
+ : renewalModes)
135
+ : guarded, {
136
+ errors,
137
+ safety: resultSafety(safety(options)),
138
+ ...(inBandRefusals ? { inBandRefusals } : {}),
139
+ ...(result ? { result } : {}),
140
+ });
141
+ const authorize = (work) => work.pipe(Effect.provideServiceEffect(Grant, machineGrant ?? (oauth ? callGrant : Effect.succeed(missingGrant))));
142
+ const connection = {
143
+ ...connected,
144
+ send: (...args) => authorize(connected.send(...args)),
145
+ sendPath: (...args) => authorize(connected.sendPath(...args)),
146
+ sendItem: (...args) => authorize(connected.sendItem(...args)),
147
+ };
148
+ // Construct programs outside every caller context; only execution receives candidate services.
149
+ const probeProgram = probe.run
150
+ ? probe.run(connection, options)
151
+ : connection
152
+ .send(probe.operation, (typeof probe.request === "function" ? probe.request(options) : probe.request))
153
+ .pipe(Effect.map(({ data }) => data));
154
+ const test = (values, ctx) => {
155
+ const problem = probe.check?.(values, options);
156
+ if (problem !== undefined)
157
+ return Promise.resolve({ ok: false, message: problem });
158
+ // api() has already installed anonymous, uncharged candidate services.
159
+ // Bridge those services directly; never copy the supplied context.
160
+ const lease = fromConnectorContext(ctx, "read");
161
+ const signal = Context.get(lease.services, Signal);
162
+ const map = {
163
+ classification: Context.get(lease.services, Classification),
164
+ dispatches: Context.get(lease.services, Dispatches),
165
+ withholds: connection.safety.withholdsErrors,
166
+ signal,
167
+ };
168
+ return runEdge(probeProgram.pipe(Effect.provideService(WriteCapacity, new Map()), Effect.flatMap((data) => Effect.try({
169
+ try: () => {
170
+ const described = probe.describe(data, options);
171
+ return typeof described === "string" ? { ok: true, message: described } : described;
172
+ },
173
+ catch: (error) => error,
174
+ }).pipe(Effect.catch((error) => error instanceof ConnectorCallError ? Effect.fail(new Refusal({ error })) : Effect.die(error)))), Effect.catch((failure) => Effect.sync(() => {
175
+ const error = toConnectorCallError(failure, errors, map);
176
+ return probe.failure?.(error, options) ?? { ok: false, message: error.message };
177
+ })), Effect.catchDefect((defect) => Effect.die(withheldDefect(defect, map, !!probe.run))), Effect.provideContext(lease.services), Effect.ensuring(Effect.sync(lease.close))), { signal: ctx.signal });
178
+ };
179
+ const builtTools = tools({
180
+ connection,
181
+ options,
182
+ get pageSize() {
183
+ if (!pageSize)
184
+ throw new Error("Declare pageSize before using the kit's pageSize.");
185
+ return typeof override === "number" ? override : pageSize.default;
186
+ },
187
+ });
188
+ const hatchTools = hatchOptions
189
+ ? hatch({ ...hatchDeclaration(hatchOptions, options, connection), connection })
190
+ : [];
191
+ // The declared fact the Writes convention states must match what the write builders send.
192
+ if (idempotencyKey !== undefined && [...builtTools, ...hatchTools].some(takesIdempotencyKey) !== idempotencyKey)
193
+ throw new Error(`${metadata.title} declares idempotencyKey: ${idempotencyKey}, but its write tools ${idempotencyKey ? "send no" : "send an"} idempotency key.`);
194
+ const usageGuide = guide(options);
195
+ const renderedGuide = "content" in usageGuide ? usageGuide : provider.usageGuide(usageGuide);
196
+ const connector = tracksEveryRequest(api(id, {
197
+ ...(defaultCallAdmission
198
+ ? {
199
+ callAdmission: typeof defaultCallAdmission === "function" ? defaultCallAdmission(options) : defaultCallAdmission,
200
+ }
201
+ : {}),
202
+ ...provider.connectorOptions,
203
+ ...(authScope ? { authScope: authScope(options) } : {}),
204
+ title: options.title ?? displayTitle?.(options) ?? metadata.title,
205
+ ...(description ? { description: description(options) } : {}),
206
+ usageGuide: transformGuide ? transformGuide(renderedGuide, options) : renderedGuide,
207
+ ...(connectionCredential
208
+ ? {
209
+ credential: connectionCredential,
210
+ testCredential: (value, ctx) => test({ value }, ctx),
211
+ testCredentials: (values, ctx) => test(values, ctx),
212
+ }
213
+ : {}),
214
+ ...(oauth ? { oauth: oauth(options) } : {}),
215
+ tools: [...builtTools, ...hatchTools],
216
+ }));
217
+ tagConnector?.(connector, options);
218
+ return connector;
219
+ },
220
+ });
221
+ }
@@ -0,0 +1,82 @@
1
+ // Provider kit (decision 0010, B.4). Unreachable from src/index.ts.
2
+ //
3
+ // The one value-safety boundary of a kit connection. `connect` requires it,
4
+ // and `Send` hands a provider nothing it has not passed: a named tool, a
5
+ // hatch, a paging strategy, and a projection all read an answer only after
6
+ // the vendor's reviewed redaction and the deployment's sensitive-field
7
+ // choice ran on it. Nothing upstream of it reaches a cursor or a result.
8
+ //
9
+ // The same boundary answers, per operation and before any detail is
10
+ // extracted, whether a failure may quote the vendor's text. A stored secret
11
+ // a request never sent can still sit in a vendor's error prose, so
12
+ // sent-secret redaction cannot stand in for it.
13
+ import { Effect } from "effect";
14
+ import { ConnectorCallError } from "../errors.js";
15
+ import { Refusal } from "./errors.js";
16
+ /** Refuses at construction a connection with neither a reviewed table nor a reason (INV-11). */
17
+ export function resultSafety(options) {
18
+ const review = options.review?.trim();
19
+ if (!options.reviewed && !review) {
20
+ throw new Error("A kit connection needs a reviewed value-safety table, or a review saying why it has none.");
21
+ }
22
+ const { choice, names } = options.sensitiveFields;
23
+ if (choice !== "drop" && choice !== "return")
24
+ throw new Error('sensitiveFields must be "drop" or "return".');
25
+ const dropped = new Set(choice === "drop" ? names : []);
26
+ const strip = (value) => {
27
+ if (Array.isArray(value))
28
+ return value.map(strip);
29
+ if (!value || typeof value !== "object")
30
+ return value;
31
+ return Object.fromEntries(Object.entries(value)
32
+ .filter(([name]) => !dropped.has(name))
33
+ .map(([name, entry]) => [name, strip(entry)]));
34
+ };
35
+ const reviewed = options.reviewed;
36
+ return {
37
+ refusal: (operation) => reviewed?.refusal?.(operation),
38
+ resolve: (method, path) => Effect.try({
39
+ try: () => {
40
+ if (reviewed?.resolve)
41
+ return reviewed.resolve(method, path);
42
+ if (!reviewed && review)
43
+ return { method, template: path };
44
+ throw new ConnectorCallError("invalid_args", "A reviewed path request needs a canonical operation index.");
45
+ },
46
+ catch: (error) => error,
47
+ }).pipe(Effect.catch((error) => error instanceof ConnectorCallError ? Effect.fail(new Refusal({ error })) : Effect.die(error))),
48
+ redact: (data, operation) => {
49
+ const safe = reviewed ? reviewed.redact(data, operation) : data;
50
+ return dropped.size > 0 ? strip(safe) : safe;
51
+ },
52
+ withholdsErrors: (operation) => reviewed?.withholdsErrors(operation) === true,
53
+ };
54
+ }
55
+ /** Bind the REST value-safety table to its pinned index; unknown operations never bypass its review. */
56
+ export function restSafety(reviewed, index) {
57
+ const indexed = (operation) => index.operation(operation.method, operation.template) ??
58
+ index.operation(operation.method, operation.template.replace(/\/:([^/]+)/g, "/{$1}"));
59
+ return {
60
+ refusal: (operation) => {
61
+ const op = indexed(operation);
62
+ return op ? reviewed.refusal(op.method, op.path) : undefined;
63
+ },
64
+ resolve: (method, path) => {
65
+ const { op } = index.resolve(method, path);
66
+ const refusal = reviewed.refusal(op.method, op.path);
67
+ if (refusal)
68
+ throw new ConnectorCallError("invalid_args", refusal);
69
+ return { method: op.method, template: op.path };
70
+ },
71
+ redact: (data, operation) => {
72
+ const op = indexed(operation);
73
+ if (!op)
74
+ throw new Error("A reviewed answer has no canonical operation in its index.");
75
+ return reviewed.redact(data, op.method, op.path);
76
+ },
77
+ withholdsErrors: (operation) => {
78
+ const op = indexed(operation);
79
+ return op ? reviewed.withholdsErrors(op) : true;
80
+ },
81
+ };
82
+ }
@@ -0,0 +1,79 @@
1
+ // HTTP request facts and fixed write reservations (B.2/B.4).
2
+ import { Context, Effect } from "effect";
3
+ import { dispatchProviderRequest, providerRequest } from "../provider-call.js";
4
+ import { callClassification } from "../call-classification.js";
5
+ import { fromSignal } from "../runtime/run.js";
6
+ import { callFromContext, ContinuationBinding, ContinuationStorage, openCall as openCoreCall, serviceFor, Signal, } from "../runtime/call.js";
7
+ import { RequestRefused, ResendRefused } from "./errors.js";
8
+ export { writeRequestKey } from "./write-request.js";
9
+ export { Caller, Credentials, Secrets, RequestSecrets, Budget, Recovery, Signal, Classification, Ledger, openRequest, operationView, deriveView, viewCaller, callView, chargeView, } from "../runtime/call.js";
10
+ /** Permanent write reservations plus resource dispatches, in reservation order. */
11
+ export class Dispatches extends Context.Service()("connecta/http/Dispatches") {
12
+ }
13
+ /** A genuine idempotency key the vendor honors, and the header that carries it, for the call's one write. */
14
+ export const IdempotencyKey = Context.Reference("connecta/http/IdempotencyKey", { defaultValue: () => undefined });
15
+ /** The authored read's review; served classification remains the call's own. */
16
+ export const ReadTool = Context.Reference("connecta/http/ReadTool", {
17
+ defaultValue: () => undefined,
18
+ });
19
+ /** Closed capacity and the requests bound to bulk items, snapshotted before the program runs. */
20
+ export class WriteCapacity extends Context.Service()("connecta/http/WriteCapacity") {
21
+ }
22
+ /** No await or fiber yield between the check and insertion. Reservations are never released. */
23
+ export function reserveWrite(ledger, capacity, facts) {
24
+ const step = facts.step ?? "write";
25
+ if (!capacity.get(step)?.has(facts.item)) {
26
+ return new RequestRefused({ message: "This write step/item was not declared by the tool for this call." });
27
+ }
28
+ const first = ledger.find((entry) => entry.write && entry.step === step && entry.item === facts.item);
29
+ if (first)
30
+ return new ResendRefused({ first });
31
+ const slot = {
32
+ write: true,
33
+ step,
34
+ ...(facts.item === undefined ? {} : { item: facts.item }),
35
+ ...(facts.operation ? { operation: facts.operation } : {}),
36
+ state: "reserved",
37
+ };
38
+ ledger.push(slot);
39
+ return slot;
40
+ }
41
+ /**
42
+ * What one request inside a call is: the call's own effect, or an auxiliary
43
+ * request inside a write tool, and which logical write. Auxiliary ownership
44
+ * does not itself prove a physical read. Set by `Send`, read by
45
+ * the transport and the OAuth middleware. `sent` is filled by the transport
46
+ * with the request it handed to `fetch`, so `Send` can record that request's
47
+ * own failure in the ledger.
48
+ */
49
+ export const RequestFacts = Context.Reference("connecta/http/RequestFacts", { defaultValue: () => ({ effect: "call" }) });
50
+ /** A call's use of renewal ends on close; a submitted claim remains coordinator-owned. */
51
+ export function duringCall(work) {
52
+ return Signal.use((signal) => {
53
+ const closed = () => new RequestRefused({ message: "This call has ended; no renewal work may continue." });
54
+ if (!signal)
55
+ return work;
56
+ if (signal.aborted)
57
+ return Effect.fail(closed());
58
+ return Effect.raceFirst(work, fromSignal(signal).pipe(Effect.mapError(closed)));
59
+ });
60
+ }
61
+ export function fromConnectorContext(ctx, fallback) {
62
+ const lease = callFromContext(ctx, callClassification(ctx) ?? fallback, {
63
+ ledger: {
64
+ open: ({ auxiliary, provider, method, key }) => providerRequest(ctx, auxiliary, provider, { method, ...(key === undefined ? {} : { key }) }),
65
+ dispatch: (entry, headers, method) => dispatchProviderRequest(ctx, entry, headers, method),
66
+ },
67
+ });
68
+ return {
69
+ ...lease,
70
+ services: lease.services.pipe(Context.add(ContinuationStorage, serviceFor(ctx, ContinuationStorage) ?? ctx.storage), Context.add(ContinuationBinding, serviceFor(ctx, ContinuationBinding) ?? { connection: "", principal: null }), Context.add(Dispatches, []), Context.add(WriteCapacity, new Map([["write", new Map([[undefined, undefined]])]]))),
71
+ };
72
+ }
73
+ export function openCall(inputs) {
74
+ const lease = openCoreCall(inputs);
75
+ return {
76
+ ...lease,
77
+ services: lease.services.pipe(Context.add(Dispatches, []), Context.add(WriteCapacity, new Map([["write", new Map([[undefined, undefined]])]]))),
78
+ };
79
+ }