@zackbart/connecta 0.34.0 → 0.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (428) hide show
  1. package/CHANGELOG.md +393 -0
  2. package/README.md +62 -105
  3. package/SECURITY.md +3 -2
  4. package/bin/connecta.mjs +41 -16
  5. package/bin/version.mjs +1 -1
  6. package/dist/access-tokens.d.ts +2 -1
  7. package/dist/access-tokens.js +66 -30
  8. package/dist/activity.d.ts +1 -1
  9. package/dist/activity.js +2 -0
  10. package/dist/agent-config.d.ts +23 -0
  11. package/dist/agent-config.js +59 -0
  12. package/dist/agent-description.js +16 -0
  13. package/dist/agent-identity.js +4 -4
  14. package/dist/agent-observation.js +39 -0
  15. package/dist/auth/clerk-sdk/client.d.ts +2 -0
  16. package/dist/auth/clerk-sdk/generated.js +554 -563
  17. package/dist/auth/clerk-transport.js +70 -3
  18. package/dist/auth/clerk.d.ts +13 -0
  19. package/dist/auth/clerk.js +653 -246
  20. package/dist/auth/cloudflare-access.js +46 -42
  21. package/dist/auth/downstream-client-metadata.js +2 -2
  22. package/dist/auth/downstream-oauth.js +2051 -1160
  23. package/dist/auth/downstream-revocation.js +88 -88
  24. package/dist/auth/native-call.js +20 -0
  25. package/dist/auth/native.js +184 -0
  26. package/dist/auth/oauth-start-reset.js +11 -5
  27. package/dist/auth/oauth-token-response.js +121 -102
  28. package/dist/auth/oauth-v2-migration.js +97 -78
  29. package/dist/auth/renewable-grant.js +10 -0
  30. package/dist/auth/static-oauth.js +663 -271
  31. package/dist/auth/vercel-agent.js +266 -0
  32. package/dist/auth-admission.js +204 -0
  33. package/dist/auth-elicitation.js +350 -241
  34. package/dist/authorization-handoff.js +164 -90
  35. package/dist/call-admission-context.js +3 -10
  36. package/dist/call-admission.js +2 -0
  37. package/dist/call-classification.js +9 -0
  38. package/dist/call-recovery.js +32 -13
  39. package/dist/canonical-json.js +8 -0
  40. package/dist/catalog-cache.js +369 -213
  41. package/dist/catalog-service.js +659 -530
  42. package/dist/catalog.js +5 -1
  43. package/dist/concurrency.js +0 -25
  44. package/dist/config-defaults.d.ts +1 -0
  45. package/dist/config-defaults.js +1 -0
  46. package/dist/config-schema.d.ts +3 -1
  47. package/dist/config-schema.js +13 -3
  48. package/dist/config.d.ts +40 -6
  49. package/dist/config.js +40 -26
  50. package/dist/connector-caller.d.ts +4 -0
  51. package/dist/connector-caller.js +17 -4
  52. package/dist/connectors/api-connector.d.ts +15 -7
  53. package/dist/connectors/api-connector.js +147 -57
  54. package/dist/connectors/guarded-fetch.d.ts +51 -17
  55. package/dist/connectors/guarded-fetch.js +215 -121
  56. package/dist/connectors/negotiation-cache.js +20 -10
  57. package/dist/connectors/option-shapes.js +1 -1
  58. package/dist/connectors/remote-mcp.d.ts +12 -30
  59. package/dist/connectors/remote-mcp.js +960 -564
  60. package/dist/d1.js +10 -243
  61. package/dist/derived-context.js +5 -0
  62. package/dist/describe-config.d.ts +5 -1
  63. package/dist/describe-config.js +3 -0
  64. package/dist/downstream-input.js +347 -260
  65. package/dist/errors.d.ts +87 -6
  66. package/dist/errors.js +114 -4
  67. package/dist/execute.js +87 -50
  68. package/dist/executor-admission.js +3 -0
  69. package/dist/executors/quickjs.js +163 -112
  70. package/dist/guarded-transport.js +50 -0
  71. package/dist/guest-runtime.js +1 -1
  72. package/dist/http/client.js +439 -0
  73. package/dist/http/errors.js +558 -0
  74. package/dist/http/fields.js +49 -0
  75. package/dist/http/hatch-paging.js +318 -0
  76. package/dist/http/hatch.js +1279 -0
  77. package/dist/http/json-schema.js +267 -0
  78. package/dist/http/node-transport.js +241 -0
  79. package/dist/http/oauth.js +162 -0
  80. package/dist/http/paging.js +228 -0
  81. package/dist/http/provider.js +221 -0
  82. package/dist/http/safety.js +82 -0
  83. package/dist/http/services.js +79 -0
  84. package/dist/http/tools.js +383 -0
  85. package/dist/http/vendor-index.js +138 -0
  86. package/dist/http/vendor.js +448 -0
  87. package/dist/http/write-request.js +66 -0
  88. package/dist/http-policy.d.ts +11 -0
  89. package/dist/http-policy.js +45 -0
  90. package/dist/inbound-credential.js +1 -1
  91. package/dist/index.d.ts +2 -2
  92. package/dist/index.js +4 -0
  93. package/dist/invocation-auth.js +30 -19
  94. package/dist/invocation.js +221 -87
  95. package/dist/mcp-result.js +0 -4
  96. package/dist/membership.d.ts +4 -0
  97. package/dist/meta-output.js +1 -1
  98. package/dist/meta-tools.js +534 -408
  99. package/dist/native-recovery.js +52 -0
  100. package/dist/native-tools.js +382 -0
  101. package/dist/node.d.ts +4 -3
  102. package/dist/node.js +45 -8
  103. package/dist/oauth-handoff.js +177 -104
  104. package/dist/oauth-partition.js +6 -20
  105. package/dist/oauth-sealing.js +6 -7
  106. package/dist/operation-vocabulary.js +101 -0
  107. package/dist/operator-record.d.ts +2 -2
  108. package/dist/operator-record.js +17 -4
  109. package/dist/operator-ui/agents.d.ts +5 -4
  110. package/dist/operator-ui/agents.js +17 -7
  111. package/dist/operator-ui/config-summary.js +8 -4
  112. package/dist/operator-ui/connection-map.js +9 -6
  113. package/dist/operator-ui/contract.d.ts +7 -3
  114. package/dist/operator-ui/endpoints.js +5 -14
  115. package/dist/operator-ui/fix-prompts.d.ts +1 -1
  116. package/dist/operator-ui/fix-prompts.js +0 -8
  117. package/dist/operator-ui/generated.js +3 -3
  118. package/dist/operator-ui/health.js +52 -0
  119. package/dist/operator-ui/model.d.ts +2 -3
  120. package/dist/operator-ui/overview.js +11 -19
  121. package/dist/operator-ui/setup-commands.js +0 -4
  122. package/dist/operator-ui/view.d.ts +5 -29
  123. package/dist/operator-ui/view.js +3 -59
  124. package/dist/program-writes.js +47 -26
  125. package/dist/provider-call-facts.d.ts +115 -0
  126. package/dist/provider-call-facts.js +182 -0
  127. package/dist/provider-call.d.ts +112 -0
  128. package/dist/provider-call.js +271 -0
  129. package/dist/provider.d.ts +71 -32
  130. package/dist/provider.js +134 -40
  131. package/dist/providers/_shared/google/hatch.js +91 -0
  132. package/dist/providers/_shared/google/kit.js +537 -0
  133. package/dist/providers/_shared/google/result-size.js +15 -2
  134. package/dist/providers/_shared/google/service-account.d.ts +2 -1
  135. package/dist/providers/_shared/google/service-account.js +8 -4
  136. package/dist/providers/_shared/google/workspace.d.ts +8 -209
  137. package/dist/providers/_shared/google/workspace.js +7 -426
  138. package/dist/providers/_shared/rest/compact-index.js +86 -0
  139. package/dist/providers/_shared/rest/dispatch.js +3 -23
  140. package/dist/providers/_shared/rest/kit.js +546 -0
  141. package/dist/providers/_shared/rest/operation-index.js +230 -14
  142. package/dist/providers/_shared/rest/response-media.js +11 -0
  143. package/dist/providers/_shared/rest/tools.js +101 -78
  144. package/dist/providers/_shared/rest/value-safety.js +353 -195
  145. package/dist/providers/_shared/sensitive-fields.js +27 -0
  146. package/dist/providers/breeze/api.js +584 -0
  147. package/dist/providers/breeze/index.d.ts +3 -3
  148. package/dist/providers/breeze/index.js +67 -1420
  149. package/dist/providers/breeze/openapi.generated.js +60 -0
  150. package/dist/providers/breeze/skill.generated.js +2 -6
  151. package/dist/providers/breeze/tools.js +696 -0
  152. package/dist/providers/ccb/api.js +496 -0
  153. package/dist/providers/ccb/index.d.ts +17 -37
  154. package/dist/providers/ccb/index.js +77 -1702
  155. package/dist/providers/ccb/lib/constants.d.ts +34 -0
  156. package/dist/providers/ccb/lib/constants.js +74 -0
  157. package/dist/providers/ccb/lib/guide.js +9 -0
  158. package/dist/providers/ccb/lib/verdicts.js +387 -0
  159. package/dist/providers/ccb/openapi.generated.js +397 -0
  160. package/dist/providers/ccb/safety.js +295 -0
  161. package/dist/providers/ccb/skill.generated.js +2 -6
  162. package/dist/providers/ccb/tools.js +853 -0
  163. package/dist/providers/cloudflare/api.js +1066 -0
  164. package/dist/providers/cloudflare/index.d.ts +7 -22
  165. package/dist/providers/cloudflare/index.js +80 -194
  166. package/dist/providers/cloudflare/lib/config.d.ts +16 -0
  167. package/dist/providers/cloudflare/lib/config.js +2 -0
  168. package/dist/providers/cloudflare/lib/discovery.js +29 -0
  169. package/dist/providers/cloudflare/{graphql.js → lib/graphql.js} +1 -1
  170. package/dist/providers/cloudflare/lib/hatch.js +103 -0
  171. package/dist/providers/cloudflare/lib/path-bounds.js +28 -0
  172. package/dist/providers/cloudflare/lib/response-media.js +75 -0
  173. package/dist/providers/cloudflare/openapi.generated.js +3299 -3208
  174. package/dist/providers/cloudflare/{value-safety.js → safety.js} +538 -18
  175. package/dist/providers/cloudflare/skill.generated.js +2 -10
  176. package/dist/providers/cloudflare/tools.js +360 -0
  177. package/dist/providers/docs/api.js +51 -0
  178. package/dist/providers/docs/index.d.ts +1 -12
  179. package/dist/providers/docs/index.js +53 -1165
  180. package/dist/providers/docs/lib/constants.d.ts +18 -0
  181. package/dist/providers/docs/lib/constants.js +18 -0
  182. package/dist/providers/docs/lib/discovery.js +26 -0
  183. package/dist/providers/docs/lib/requests.js +48 -0
  184. package/dist/providers/docs/lib/schemas.js +168 -0
  185. package/dist/providers/docs/openapi.generated.js +16 -0
  186. package/dist/providers/docs/safety.js +54 -0
  187. package/dist/providers/docs/skill.generated.js +2 -6
  188. package/dist/providers/docs/tools.js +802 -0
  189. package/dist/providers/drive/api.js +177 -0
  190. package/dist/providers/drive/index.d.ts +1 -12
  191. package/dist/providers/drive/index.js +38 -1448
  192. package/dist/providers/drive/lib/constants.d.ts +6 -0
  193. package/dist/providers/drive/lib/constants.js +6 -0
  194. package/dist/providers/drive/lib/contracts.js +532 -0
  195. package/dist/providers/drive/lib/hatch.js +197 -0
  196. package/dist/providers/drive/openapi.generated.js +77 -0
  197. package/dist/providers/drive/safety.js +90 -0
  198. package/dist/providers/drive/skill.generated.js +2 -6
  199. package/dist/providers/drive/tools.js +1290 -0
  200. package/dist/providers/forms/api.js +71 -0
  201. package/dist/providers/forms/index.d.ts +1 -12
  202. package/dist/providers/forms/index.js +49 -1145
  203. package/dist/providers/forms/lib/constants.d.ts +14 -0
  204. package/dist/providers/forms/lib/constants.js +19 -0
  205. package/dist/providers/forms/lib/hatch.js +72 -0
  206. package/dist/providers/forms/openapi.generated.js +23 -0
  207. package/dist/providers/forms/safety.js +34 -0
  208. package/dist/providers/forms/skill.generated.js +2 -8
  209. package/dist/providers/forms/tools.js +1024 -0
  210. package/dist/providers/github/api.js +150 -0
  211. package/dist/providers/github/index.d.ts +4 -5
  212. package/dist/providers/github/index.js +30 -87
  213. package/dist/providers/github/{auth.d.ts → lib/auth.d.ts} +5 -3
  214. package/dist/providers/github/{auth.js → lib/auth.js} +40 -43
  215. package/dist/providers/github/lib/discovery.js +132 -0
  216. package/dist/providers/github/lib/operations.js +58 -0
  217. package/dist/providers/github/{scope.d.ts → lib/scope.d.ts} +2 -0
  218. package/dist/providers/github/{scope.js → lib/scope.js} +25 -1
  219. package/dist/providers/github/openapi.generated.js +1216 -0
  220. package/dist/providers/github/safety.js +216 -0
  221. package/dist/providers/github/skill.generated.js +2 -5
  222. package/dist/providers/github/tools.js +506 -0
  223. package/dist/providers/gmail/api.js +114 -0
  224. package/dist/providers/gmail/index.d.ts +1 -12
  225. package/dist/providers/gmail/index.js +73 -1621
  226. package/dist/providers/gmail/lib/constants.d.ts +13 -0
  227. package/dist/providers/gmail/lib/constants.js +16 -0
  228. package/dist/providers/gmail/lib/index.js +173 -0
  229. package/dist/providers/gmail/lib/schemas.js +176 -0
  230. package/dist/providers/gmail/lib/threading.js +120 -0
  231. package/dist/providers/gmail/openapi.generated.js +92 -0
  232. package/dist/providers/gmail/safety.js +21 -0
  233. package/dist/providers/gmail/skill.generated.js +2 -6
  234. package/dist/providers/gmail/tools.js +1435 -0
  235. package/dist/providers/overflow/api.js +1008 -0
  236. package/dist/providers/overflow/index.d.ts +3 -17
  237. package/dist/providers/overflow/index.js +60 -1488
  238. package/dist/providers/overflow/skill.generated.js +2 -5
  239. package/dist/providers/overflow/tools.js +873 -0
  240. package/dist/providers/planning-center/api.js +467 -0
  241. package/dist/providers/planning-center/index.d.ts +6 -35
  242. package/dist/providers/planning-center/index.js +69 -2445
  243. package/dist/providers/planning-center/lib/constants.d.ts +58 -0
  244. package/dist/providers/planning-center/lib/constants.js +83 -0
  245. package/dist/providers/planning-center/lib/discovery.js +40 -0
  246. package/dist/providers/planning-center/lib/guide.js +39 -0
  247. package/dist/providers/planning-center/lib/json-api.js +83 -0
  248. package/dist/providers/planning-center/lib/verdicts.js +1758 -0
  249. package/dist/providers/planning-center/openapi.generated.js +1764 -0
  250. package/dist/providers/planning-center/safety.js +188 -0
  251. package/dist/providers/planning-center/skill.generated.js +2 -27
  252. package/dist/providers/planning-center/tools.js +1010 -0
  253. package/dist/providers/sheets/api.js +133 -0
  254. package/dist/providers/sheets/index.d.ts +4 -16
  255. package/dist/providers/sheets/index.js +61 -1172
  256. package/dist/providers/sheets/lib/constants.d.ts +14 -0
  257. package/dist/providers/sheets/lib/constants.js +14 -0
  258. package/dist/providers/sheets/lib/hatch.js +163 -0
  259. package/dist/providers/sheets/lib/requests.js +105 -0
  260. package/dist/providers/sheets/lib/schemas.js +138 -0
  261. package/dist/providers/sheets/openapi.generated.js +30 -0
  262. package/dist/providers/sheets/safety.js +27 -0
  263. package/dist/providers/sheets/skill.generated.js +2 -7
  264. package/dist/providers/sheets/tools.js +734 -0
  265. package/dist/providers/slides/api.js +147 -0
  266. package/dist/providers/slides/index.d.ts +2 -10
  267. package/dist/providers/slides/index.js +48 -2555
  268. package/dist/providers/slides/lib/constants.d.ts +11 -0
  269. package/dist/providers/slides/lib/constants.js +11 -0
  270. package/dist/providers/slides/lib/requests.js +60 -0
  271. package/dist/providers/slides/lib/schemas.js +565 -0
  272. package/dist/providers/slides/openapi.generated.js +18 -0
  273. package/dist/providers/slides/skill.generated.js +2 -6
  274. package/dist/providers/slides/tools.js +1968 -0
  275. package/dist/providers/stripe/api.js +401 -0
  276. package/dist/providers/stripe/index.d.ts +7 -27
  277. package/dist/providers/stripe/index.js +75 -191
  278. package/dist/providers/stripe/lib/config.d.ts +4 -0
  279. package/dist/providers/stripe/lib/config.js +2 -0
  280. package/dist/providers/stripe/openapi.generated.js +4 -3
  281. package/dist/providers/stripe/{value-safety.js → safety.js} +5 -5
  282. package/dist/providers/stripe/skill.generated.js +2 -10
  283. package/dist/providers/stripe/tools.js +77 -0
  284. package/dist/providers/tithely/api.js +531 -0
  285. package/dist/providers/tithely/index.d.ts +19 -0
  286. package/dist/providers/tithely/index.js +86 -965
  287. package/dist/providers/tithely/skill.generated.js +2 -5
  288. package/dist/providers/tithely/tools.js +426 -0
  289. package/dist/providers/vercel/api.js +551 -0
  290. package/dist/providers/vercel/index.d.ts +11 -25
  291. package/dist/providers/vercel/index.js +67 -261
  292. package/dist/providers/vercel/lib/config.d.ts +2 -0
  293. package/dist/providers/vercel/lib/config.js +2 -0
  294. package/dist/providers/vercel/lib/index.js +117 -0
  295. package/dist/providers/vercel/lib/logs.js +100 -0
  296. package/dist/providers/vercel/lib/pin.js +270 -0
  297. package/dist/providers/vercel/openapi.generated.js +398 -376
  298. package/dist/providers/vercel/{value-safety.js → safety.js} +261 -42
  299. package/dist/providers/vercel/skill.generated.js +2 -7
  300. package/dist/providers/vercel/tools.js +642 -0
  301. package/dist/redaction-identity.js +47 -0
  302. package/dist/redaction-marker.js +125 -0
  303. package/dist/registry.d.ts +30 -28
  304. package/dist/registry.js +446 -413
  305. package/dist/routes/access-tokens.js +1 -1
  306. package/dist/routes/actor-labels.js +1 -1
  307. package/dist/routes/connect.js +1 -1
  308. package/dist/routes/dispatch.js +103 -0
  309. package/dist/routes/mcp.js +170 -79
  310. package/dist/routes/oauth.js +3 -1
  311. package/dist/routes/operator.js +2 -2
  312. package/dist/routes/shared.d.ts +5 -4
  313. package/dist/routes/shared.js +244 -177
  314. package/dist/routes/skills.js +10 -8
  315. package/dist/routes/ui-config.js +27 -3
  316. package/dist/routes/ui-data.js +29 -22
  317. package/dist/routes/ui.js +1 -1
  318. package/dist/runtime/call-admission.js +0 -26
  319. package/dist/runtime/call-entry.js +30 -0
  320. package/dist/runtime/call.js +556 -0
  321. package/dist/runtime/connector-scope.js +7 -0
  322. package/dist/runtime/credential-probe.js +34 -0
  323. package/dist/runtime/executor.js +40 -0
  324. package/dist/runtime/native-storage.js +63 -0
  325. package/dist/runtime/registry.js +27 -0
  326. package/dist/runtime/request-scope.js +72 -0
  327. package/dist/runtime/run.js +15 -7
  328. package/dist/runtime/shared-read.js +34 -5
  329. package/dist/runtime/storage.js +34 -21
  330. package/dist/sent-secrets.d.ts +194 -37
  331. package/dist/sent-secrets.js +1743 -340
  332. package/dist/server.js +5 -56
  333. package/dist/skills.js +330 -224
  334. package/dist/sqlite.js +15 -14
  335. package/dist/storage/d1-copy.js +255 -0
  336. package/dist/storage/d1-driver.js +15 -0
  337. package/dist/storage/keys.js +28 -0
  338. package/dist/storage/sql-driver.js +88 -0
  339. package/dist/storage/sql-native.js +544 -0
  340. package/dist/storage/sql-schema.d.ts +6 -0
  341. package/dist/storage/sql-schema.js +15 -0
  342. package/dist/storage/sql.d.ts +14 -20
  343. package/dist/storage/sql.js +29 -535
  344. package/dist/timeout.js +0 -26
  345. package/dist/tool-safety.js +20 -10
  346. package/dist/types.d.ts +11 -99
  347. package/dist/upward.js +3 -0
  348. package/dist/usage-guide.js +3 -1
  349. package/dist/validate.d.ts +4 -2
  350. package/dist/validate.js +86 -9
  351. package/dist/version.d.ts +1 -1
  352. package/dist/version.js +1 -1
  353. package/dist/worker.js +312 -292
  354. package/dist/workspace-subject.js +5 -1
  355. package/dist/write-outcome.js +454 -34
  356. package/documentation/README.md +27 -7
  357. package/documentation/architecture.md +2550 -186
  358. package/documentation/auth.md +821 -98
  359. package/documentation/code-mode.md +56 -21
  360. package/documentation/deploying.md +164 -20
  361. package/documentation/hosted-mcp-migration.md +460 -0
  362. package/documentation/integrating.md +144 -105
  363. package/documentation/meta-tools.md +411 -34
  364. package/documentation/operating.md +28 -4
  365. package/documentation/operator-tests.md +11 -2
  366. package/documentation/operator-ui.md +103 -33
  367. package/documentation/provider-auth-migration.md +38 -63
  368. package/documentation/provider-migration-0.29.md +10 -5
  369. package/documentation/provider-migration-0.35.md +975 -0
  370. package/documentation/providers.md +965 -0
  371. package/examples/worker/AGENTS.md +23 -9
  372. package/examples/worker/README.md +254 -135
  373. package/examples/worker/alchemy.run.ts +116 -0
  374. package/examples/worker/gitignore +10 -0
  375. package/examples/worker/src/connecta.config.ts +23 -21
  376. package/examples/worker/wrangler.jsonc +14 -5
  377. package/guides/connecting-agents.md +157 -0
  378. package/guides/how-it-works.md +156 -0
  379. package/guides/safety-and-trust.md +153 -0
  380. package/package.json +27 -42
  381. package/templates/node/.env.example +3 -0
  382. package/templates/node/README.md +22 -2
  383. package/templates/node/docker-compose.yml +1 -0
  384. package/templates/node/package.json +3 -2
  385. package/templates/node/src/connecta.config.ts +8 -0
  386. package/dist/catalog-drift.d.ts +0 -134
  387. package/dist/catalog-drift.js +0 -493
  388. package/dist/providers/_shared/request-token.js +0 -83
  389. package/dist/providers/_shared/rest/operation-index.d.ts +0 -133
  390. package/dist/providers/_shared/rest/tools.d.ts +0 -141
  391. package/dist/providers/_shared/rest/value-safety.d.ts +0 -201
  392. package/dist/providers/basecamp/index.d.ts +0 -43
  393. package/dist/providers/basecamp/index.js +0 -997
  394. package/dist/providers/basecamp/skill.generated.js +0 -9
  395. package/dist/providers/cloudflare/rest.d.ts +0 -37
  396. package/dist/providers/cloudflare/rest.js +0 -1078
  397. package/dist/providers/github/hosted.js +0 -218
  398. package/dist/providers/github/rest.js +0 -321
  399. package/dist/providers/infisical/index.d.ts +0 -7
  400. package/dist/providers/infisical/index.js +0 -713
  401. package/dist/providers/infisical/skill.generated.js +0 -8
  402. package/dist/providers/linear/index.d.ts +0 -55
  403. package/dist/providers/linear/index.js +0 -352
  404. package/dist/providers/linear/skill.generated.js +0 -8
  405. package/dist/providers/mixpanel/index.d.ts +0 -57
  406. package/dist/providers/mixpanel/index.js +0 -468
  407. package/dist/providers/mixpanel/operations.js +0 -20
  408. package/dist/providers/mixpanel/rest.js +0 -603
  409. package/dist/providers/mixpanel/skill.generated.js +0 -10
  410. package/dist/providers/mixpanel/value-safety.js +0 -16
  411. package/dist/providers/notion/index.d.ts +0 -65
  412. package/dist/providers/notion/index.js +0 -368
  413. package/dist/providers/notion/openapi.generated.js +0 -75
  414. package/dist/providers/notion/rest.d.ts +0 -24
  415. package/dist/providers/notion/rest.js +0 -1226
  416. package/dist/providers/notion/skill.generated.js +0 -11
  417. package/dist/providers/notion/value-safety.js +0 -56
  418. package/dist/providers/revenuecat/index.d.ts +0 -49
  419. package/dist/providers/revenuecat/index.js +0 -557
  420. package/dist/providers/revenuecat/skill.generated.js +0 -11
  421. package/dist/providers/stripe/rest.d.ts +0 -14
  422. package/dist/providers/stripe/rest.js +0 -402
  423. package/dist/providers/vercel/rest.d.ts +0 -20
  424. package/dist/providers/vercel/rest.js +0 -1020
  425. package/dist/providers/wispr-flow/index.d.ts +0 -14
  426. package/dist/providers/wispr-flow/index.js +0 -117
  427. package/dist/providers/wispr-flow/skill.generated.js +0 -8
  428. /package/dist/providers/github/{key.js → lib/key.js} +0 -0
@@ -0,0 +1,537 @@
1
+ // Google Workspace on the provider kit (decision 0010; C.7 step 1 under 0011).
2
+ // Shared by every Workspace product; never its own export. `workspace.ts`
3
+ // keeps shared options, connection parsing and subject resolution;
4
+ // `service-account.ts` keeps the private token exchange and cache.
5
+ // This module adds what every product needs: the Google error
6
+ // table, the delegated machine grant, a value-safety resolver over the
7
+ // product's own operations, a request adapter that keeps the legacy request
8
+ // bytes and write wording, and the step-1 catalog bridge.
9
+ import { Effect, Option, Schema } from "effect";
10
+ import { callClassification } from "../../../call-classification.js";
11
+ import { deriveContext } from "../../../derived-context.js";
12
+ import { ConnectorCallError } from "../../../errors.js";
13
+ import { attachFailureFacts } from "../../../operator-record.js";
14
+ import { Refusal, StatusFailure, toConnectorCallError, } from "../../../http/errors.js";
15
+ import { Classification, Dispatches, Signal } from "../../../http/services.js";
16
+ import { read, write } from "../../../http/tools.js";
17
+ import { callMemo, Operation } from "../../../runtime/call.js";
18
+ import { providerFailureMessage, unsentAfterUnauthorized } from "../../../write-outcome.js";
19
+ import { delegatedToken, forgetDelegatedToken } from "./service-account.js";
20
+ import { subjectFor, workspaceConnection } from "./workspace.js";
21
+ import { tagWorkspaceSubject } from "../../../workspace-subject.js";
22
+ import { googleNamedOperation, requireGoogleIndex } from "./hatch.js";
23
+ function asRecord(value) {
24
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
25
+ }
26
+ function asArray(value) {
27
+ return Array.isArray(value) ? value : [];
28
+ }
29
+ function reasonsOf(tokens) {
30
+ const error = asRecord(asRecord(tokens)["error"]);
31
+ const reasons = new Set();
32
+ for (const entry of [...asArray(error["errors"]), ...asArray(error["details"])]) {
33
+ const reason = asRecord(entry)["reason"];
34
+ if (typeof reason === "string")
35
+ reasons.add(reason);
36
+ }
37
+ if (typeof error["status"] === "string")
38
+ reasons.add(error["status"]);
39
+ return [...reasons];
40
+ }
41
+ /** Public reason spellings shared by classification and the pre-redaction vocabulary. */
42
+ const REASONS = {
43
+ disabled: ["accessNotConfigured", "SERVICE_DISABLED"],
44
+ rateLimited: ["rateLimitExceeded", "userRateLimitExceeded", "RATE_LIMIT_EXCEEDED"],
45
+ insufficientScope: ["insufficientPermissions", "ACCESS_TOKEN_SCOPE_INSUFFICIENT"],
46
+ exportSize: ["exportSizeLimitExceeded"],
47
+ domainPolicy: ["domainPolicy"],
48
+ filePermission: ["insufficientFilePermissions", "forbidden"],
49
+ precondition: ["FAILED_PRECONDITION", "failedPrecondition"],
50
+ aborted: ["ABORTED", "aborted"],
51
+ };
52
+ /**
53
+ * Google's failure table, in the legacy client's order: Google's own
54
+ * specific reasons decide first, whatever the status; only a refused
55
+ * precondition or an abort with nothing more specific to say is left for
56
+ * the revision guard (the `revisionGuarded` request flag), then the status.
57
+ * Each verdict's words are the legacy client's, so the messages stay.
58
+ */
59
+ export function googleErrors(product, options = {}) {
60
+ const { provider, api, scopes, notFound } = product;
61
+ const has = (facts, names) => names.some((name) => facts.reasons.includes(name));
62
+ return {
63
+ provider,
64
+ facts: (tokens) => ({ reasons: reasonsOf(tokens) }),
65
+ factVocabulary: { reasons: Object.values(REASONS).flat() },
66
+ numericFacts: {
67
+ retryAfterMs: {
68
+ header: "retry-after",
69
+ format: "retry-after",
70
+ review: "HTTP Retry-After delay for failure recovery.",
71
+ },
72
+ },
73
+ detail: ({ status, body }) => {
74
+ const message = asRecord(asRecord(body)["error"])["message"];
75
+ // The body arrives redacted whole, before anything here cuts it.
76
+ const said = typeof message === "string" ? message.trim().slice(0, 500) : "";
77
+ return said ? `${provider}: ${said}${/[.!?]$/.test(said) ? "" : "."}` : `${provider} returned HTTP ${status}.`;
78
+ },
79
+ classify: [
80
+ // Every 3xx the transport lets through (300, 304, 305, 306) is a redirect first.
81
+ ({ status }) => status >= 300 && status < 400
82
+ ? {
83
+ code: "connector_call_failed",
84
+ retryable: false,
85
+ words: () => `${provider} answered HTTP ${status} with a redirect; this connection talks to exactly one origin and never forwards its credential to another.`,
86
+ }
87
+ : undefined,
88
+ ({ status }) => status === 401
89
+ ? {
90
+ code: "auth_required",
91
+ words: (detail) => `${detail} Google rejected a freshly minted delegated token. The domain-wide delegation grant or the service account may have been revoked.`,
92
+ }
93
+ : undefined,
94
+ ({ facts }) => has(facts, REASONS.disabled)
95
+ ? {
96
+ code: "connector_call_failed",
97
+ retryable: false,
98
+ words: (detail) => `${detail} The ${api} is not enabled in the service account's Google Cloud project; an operator enables it there.`,
99
+ }
100
+ : undefined,
101
+ ({ status, facts, retryAfterMs }) => (status === 429 && !options.standard) || has(facts, REASONS.rateLimited)
102
+ ? {
103
+ code: "rate_limited",
104
+ retryAfterMs,
105
+ words: (detail) => `${detail} Google meters this API per user and per project.`,
106
+ advice: "; wait before retrying",
107
+ }
108
+ : undefined,
109
+ ({ facts }) => has(facts, REASONS.insufficientScope)
110
+ ? {
111
+ code: "provider_permission_denied",
112
+ words: (detail) => `${detail} The delegated token lacks a scope this call needs. The Admin console's domain-wide delegation entry must list exactly: ${scopes.join(",")}.`,
113
+ }
114
+ : undefined,
115
+ ({ facts }) => has(facts, REASONS.exportSize)
116
+ ? {
117
+ code: "connector_call_failed",
118
+ retryable: false,
119
+ words: (detail) => `${detail} The item is larger than Google will export in this format. Download the original file instead, or export a smaller part.`,
120
+ }
121
+ : undefined,
122
+ ({ facts }) => has(facts, REASONS.domainPolicy)
123
+ ? {
124
+ code: "provider_permission_denied",
125
+ retryable: false,
126
+ words: (detail) => `${detail} A Workspace domain policy forbids this action for this account; only a Workspace administrator can change that.`,
127
+ }
128
+ : undefined,
129
+ ({ facts }) => has(facts, REASONS.filePermission)
130
+ ? {
131
+ code: "provider_permission_denied",
132
+ retryable: false,
133
+ words: (detail) => `${detail} This account does not have the permission on this item that the action needs — it may be shared view-only, or not shared with this user. Its owner can grant more.`,
134
+ }
135
+ : undefined,
136
+ // A write that named the revision it was made against hears "the item
137
+ // moved on" as a refused precondition or an abort. Fixed words, so no
138
+ // provider ever matches on Google's prose.
139
+ ({ status, facts, operation }) => operation.flags?.["revisionGuarded"] === true &&
140
+ (status === 400 || status === 409) &&
141
+ has(facts, [...REASONS.precondition, ...REASONS.aborted])
142
+ ? {
143
+ code: "conflict",
144
+ words: () => `${provider} refused the write because the item changed after the revision it named.`,
145
+ advice: " Re-read it for the current revision, reapply the change, and retry.",
146
+ }
147
+ : undefined,
148
+ // Google uses the same reason for a product switched off for this user
149
+ // and for a stale write, so the classification asserts neither.
150
+ ({ status, facts }) => status === 400 && has(facts, REASONS.precondition)
151
+ ? {
152
+ code: "connector_call_failed",
153
+ retryable: false,
154
+ words: (detail) => `${detail} Google refused the request's precondition; its message says which.`,
155
+ }
156
+ : undefined,
157
+ ],
158
+ statuses: {
159
+ 401: () => ({ code: "auth_required" }),
160
+ 403: () => ({
161
+ code: "provider_permission_denied",
162
+ retryable: false,
163
+ words: (detail) => `${detail} Google refused the request; the account may lack access to this item, or a Workspace policy may block it. Google does not say which. Ask the item owner to grant access or a Workspace administrator to review the policy.`,
164
+ }),
165
+ 404: () => notFound === "absent"
166
+ ? { code: "not_found", words: (detail) => `${detail} Re-read the id from a list or search tool.` }
167
+ : {
168
+ code: "connector_call_failed",
169
+ retryable: false,
170
+ words: (detail) => `${detail} The id is unknown or not visible to this account; Google does not distinguish them.`,
171
+ },
172
+ 400: () => ({ code: "invalid_args" }),
173
+ 422: () => ({ code: "invalid_args" }),
174
+ serverError: ({ retryAfterMs }) => ({
175
+ code: "unavailable",
176
+ retryAfterMs,
177
+ words: (detail) => `${detail} Google is failing upstream.`,
178
+ }),
179
+ otherwise: () => ({ code: "connector_call_failed", retryable: false }),
180
+ },
181
+ unreadable: `${provider} returned a successful response that is not JSON.`,
182
+ ...(options.standard
183
+ ? {
184
+ meanings: {
185
+ unknownId: notFound === "absent" ? "not_found" : "connector_call_failed",
186
+ provesAbsence: notFound === "absent",
187
+ conflicts: options.revisionConflicts
188
+ ? ["A revision-guarded batch update returned ABORTED or FAILED_PRECONDITION with HTTP 400 or 409"]
189
+ : [],
190
+ },
191
+ bodyFailures: {
192
+ review: "An incomplete Google response cannot establish the requested result, including named binary reads.",
193
+ statusOnly: [],
194
+ readFailed: `${provider}'s response could not be read completely.`,
195
+ },
196
+ statuses: {
197
+ 401: () => ({ code: "auth_required" }),
198
+ 403: () => ({
199
+ code: "provider_permission_denied",
200
+ retryable: false,
201
+ words: (detail) => `${detail} The account may lack access, or a Workspace policy may block this request.`,
202
+ }),
203
+ 404: () => notFound === "absent"
204
+ ? { code: "not_found" }
205
+ : {
206
+ code: "connector_call_failed",
207
+ retryable: false,
208
+ words: (detail) => `${detail} The id is unknown or not visible to this account; Google does not distinguish them.`,
209
+ },
210
+ },
211
+ }
212
+ : {}),
213
+ };
214
+ }
215
+ // --- Value safety ------------------------------------------------------------------
216
+ /** One declared operation as a matcher over actual paths: `:name` matches one encoded segment. */
217
+ function templateMatcher(template) {
218
+ const segments = template.split("/").map((segment) => {
219
+ const parameter = /^:([A-Za-z0-9_]+)(.*)$/.exec(segment);
220
+ const literal = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
221
+ return parameter ? `[^/]+${literal(parameter[2])}` : literal(segment);
222
+ });
223
+ return new RegExp(`^${segments.join("/")}$`);
224
+ }
225
+ /**
226
+ * Google's value safety. Workspace answers are the user's own documents and
227
+ * mail, returned to the user who can open them; no response carries a
228
+ * credential or a stored secret, and the token a request sent is redacted by
229
+ * the kit's sent-secret pass before anything reads a body. So no field is
230
+ * rewritten and failures keep Google's (redacted) message, as they did on the
231
+ * legacy client. Every request resolves to one of the product's declared
232
+ * operations, so a path no tool declares never reaches the network.
233
+ */
234
+ export function googleSafety(provider, operations) {
235
+ const declared = operations.map((operation) => {
236
+ const { method, path } = operation;
237
+ return { method, template: path, matcher: templateMatcher(path) };
238
+ });
239
+ return {
240
+ reviewed: {
241
+ resolve: (method, path) => {
242
+ const found = declared.find((entry) => entry.method === method && entry.matcher.test(path));
243
+ if (!found)
244
+ throw new ConnectorCallError("invalid_args", `This ${provider} operation is not one the connection declares.`);
245
+ return { method: found.method, template: found.template };
246
+ },
247
+ redact: (data) => data,
248
+ withholdsErrors: () => false,
249
+ },
250
+ sensitiveFields: { names: [], choice: "drop" },
251
+ };
252
+ }
253
+ // --- The delegated grant -----------------------------------------------------------
254
+ const connections = new WeakMap();
255
+ /**
256
+ * The checked shared options, parsed once per construction: every definition
257
+ * callback receives the same validated options object, and the key is
258
+ * decoded and checked only the first time.
259
+ */
260
+ export function workspaceOf(factory, options) {
261
+ let connection = connections.get(options);
262
+ if (!connection) {
263
+ connection = workspaceConnection(factory, options);
264
+ connections.set(options, connection);
265
+ }
266
+ return connection;
267
+ }
268
+ /**
269
+ * A machine grant over the service account's delegated tokens. Built at
270
+ * construction, outside every caller context (INV-7); each send evaluates it
271
+ * with that call's services. The subject resolves once per call, from
272
+ * deployment config and the admitted caller only, before any token is
273
+ * minted. Tokens are the shared in-memory cache's: only token strings and
274
+ * expiries cross requests.
275
+ */
276
+ export function googleGrant(product, connection) {
277
+ const { provider, scopes } = product;
278
+ const errors = googleErrors(product);
279
+ const subjectKey = {};
280
+ return Effect.gen(function* () {
281
+ const operation = yield* Effect.serviceOption(Operation);
282
+ const ctx = Option.isSome(operation) ? operation.value : undefined;
283
+ if (!ctx)
284
+ return yield* Effect.die(new Error(`${provider} needs the call's connector context to resolve its subject.`));
285
+ const callSignal = yield* Signal;
286
+ // One resolution per call: a tool that sends several requests acts as one account throughout.
287
+ const tokenRequest = async () => ({
288
+ account: connection.account,
289
+ subject: await callMemo(ctx, subjectKey, () => subjectFor(provider, connection.subject, ctx)),
290
+ scopes,
291
+ });
292
+ const use = (work) => Effect.tryPromise({
293
+ try: (interrupted) => work(deriveContext(ctx, { signal: callSignal ? AbortSignal.any([callSignal, interrupted]) : interrupted })),
294
+ catch: (error) => error,
295
+ }).pipe(Effect.catch((error) => error instanceof ConnectorCallError ? Effect.fail(new Refusal({ error })) : Effect.die(error)));
296
+ return {
297
+ token: use(async (view) => delegatedToken(await tokenRequest(), view)),
298
+ // The token a 401 refused is forgotten, never a newer one, then minted anew.
299
+ refresh: (stale) => use(async (view) => {
300
+ const request = await tokenRequest();
301
+ await forgetDelegatedToken(request, stale);
302
+ return delegatedToken(request, view);
303
+ }),
304
+ // Unreachable with GOOGLE_GRANT_RENEWAL, which answers a replay's 401 from its body.
305
+ rejected: Effect.suspend(() => Effect.fail(new Refusal({
306
+ error: toConnectorCallError(new StatusFailure({
307
+ status: 401,
308
+ headers: new Headers(),
309
+ body: undefined,
310
+ operation: { method: "GET", template: "" },
311
+ }), errors, { classification: "read", dispatches: [] }),
312
+ }))),
313
+ discard: (rejected) => use(async () => forgetDelegatedToken(await tokenRequest(), rejected)).pipe(Effect.ignore),
314
+ };
315
+ });
316
+ }
317
+ /**
318
+ * Renewal as the legacy client did it: a read's 401 earns one fresh token
319
+ * and one replay, and a second 401 is answered from its own body; a write's
320
+ * 401 forgets its token and is never sent again, and the next call mints.
321
+ */
322
+ export const GOOGLE_GRANT_RENEWAL = { replayRejection: "answer", writeRenewal: "discard" };
323
+ /** Tag the built connector with whose account it acts as (#837, decisions/0006). */
324
+ export function tagWorkspace(factory) {
325
+ return (connector, options) => {
326
+ tagWorkspaceSubject(connector, workspaceOf(factory, options).subject);
327
+ };
328
+ }
329
+ const outcomes = new WeakMap();
330
+ /** The phase of a failure a Google request returned; undefined for anything else. */
331
+ export function googleOutcomeOf(failure) {
332
+ return failure !== null && typeof failure === "object" ? outcomes.get(failure) : undefined;
333
+ }
334
+ function noted(failure, outcome) {
335
+ outcomes.set(failure, Object.freeze({ ...outcome }));
336
+ return failure;
337
+ }
338
+ /** Query pairs as the legacy transport encoded them: undefined dropped, arrays repeated, values stringified. */
339
+ function queryPairs(query) {
340
+ const pairs = [];
341
+ for (const [key, value] of Object.entries(query ?? {})) {
342
+ if (value === undefined)
343
+ continue;
344
+ if (Array.isArray(value))
345
+ for (const item of value)
346
+ pairs.push([key, String(item)]);
347
+ else
348
+ pairs.push([key, String(value)]);
349
+ }
350
+ return pairs;
351
+ }
352
+ /**
353
+ * Words the legacy client gave a served write whose answer proves nothing:
354
+ * no answer, a 5xx, a redirect, or a 2xx whose reply could not be read. Only
355
+ * the message and retry flag are its; the core still decides the outcome,
356
+ * which for each of these is unknown.
357
+ */
358
+ function unknownWrite(message, status) {
359
+ return new Refusal({
360
+ error: attachFailureFacts(new ConnectorCallError("connector_call_failed", message, { retryable: false }), status === undefined ? {} : { httpStatus: status }),
361
+ });
362
+ }
363
+ export function googleClient(connection, provider, configuration = {}) {
364
+ if (configuration.standard || configuration.index)
365
+ requireGoogleIndex(configuration.index);
366
+ const send = (request, accept, options, binary = false) => Effect.gen(function* () {
367
+ if (configuration.index) {
368
+ yield* Effect.try({
369
+ try: () => {
370
+ if (!request.template)
371
+ throw new ConnectorCallError("invalid_args", "This indexed Google named request needs its declared operation template.");
372
+ googleNamedOperation(configuration.index, request.method, request.path, request.template);
373
+ },
374
+ catch: (error) => new Refusal({ error: error }),
375
+ });
376
+ }
377
+ const active = yield* Effect.serviceOption(Operation);
378
+ const callWrite = (yield* Classification) === "write";
379
+ const dispatches = yield* Dispatches;
380
+ const signal = yield* Signal;
381
+ // Match the legacy wording rule even for direct calls: their GET
382
+ // lookups have no served verdict. Physical write accounting stays the
383
+ // core's Classification; only these Google-specific words use this.
384
+ const served = Option.isSome(active) && active.value ? callClassification(active.value) : undefined;
385
+ const write = (served ?? (request.method === "GET" ? "read" : "write")) === "write";
386
+ const operation = yield* connection.safety.resolve(request.method, request.path);
387
+ return yield* connection
388
+ .sendPath({
389
+ method: request.method,
390
+ path: request.path,
391
+ template: operation.template,
392
+ query: queryPairs(request.query),
393
+ headers: { accept, ...request.headers },
394
+ ...(request.body !== undefined ? { json: JSON.stringify(request.body) } : {}),
395
+ ...(request.rawBody !== undefined ? { rawBody: request.rawBody } : {}),
396
+ }, {
397
+ ...(options?.revisionGuarded || binary
398
+ ? {
399
+ flags: {
400
+ ...(options?.revisionGuarded ? { revisionGuarded: true } : {}),
401
+ ...(binary ? { googleBytes: true } : {}),
402
+ },
403
+ }
404
+ : {}),
405
+ ...(binary && options?.maxBytes !== undefined ? { prefix: { maxBytes: options.maxBytes } } : {}),
406
+ ...(options?.effect ? { effect: options.effect } : {}),
407
+ ...(options?.step ? { step: options.step } : {}),
408
+ })
409
+ .pipe(Effect.catch((failure) => Effect.fail(settled(failure, dispatches.find((entry) => entry.failure === failure), write, callWrite, signal))));
410
+ });
411
+ function settled(failure, own, write, callWrite, signal) {
412
+ // A lookup inside a write call has not sent the write. Keep the lookup's
413
+ // own verdict; only a call-owned request gets uncertain-write wording.
414
+ write = write && own?.request?.auxiliary !== true;
415
+ const status = own?.status;
416
+ const dispatched = own?.request?.dispatched === true;
417
+ const at = (phase, code = status) => ({ dispatched, phase, ...(code === undefined ? {} : { status: code }) });
418
+ if (!dispatched)
419
+ return noted(failure, { dispatched: false, phase: "before-send" });
420
+ if (configuration.standard) {
421
+ // Preserve phase evidence for partial-create recovery; settlement and
422
+ // reconciliation wording belong to the kit in standard mode.
423
+ const phase = failure._tag === "TransportFailure"
424
+ ? "awaiting-response"
425
+ : failure._tag === "UnreadableBody" || failure._tag === "ResponseTooLarge"
426
+ ? "reading-body"
427
+ : failure._tag === "RedirectRefused" || (status !== undefined && status >= 300 && status < 400)
428
+ ? "redirected"
429
+ : status === 401
430
+ ? "unauthorized"
431
+ : status !== undefined && status >= 500
432
+ ? "server-error"
433
+ : "refused";
434
+ return noted(failure, at(phase));
435
+ }
436
+ switch (failure._tag) {
437
+ case "StatusFailure": {
438
+ const code = failure.status;
439
+ if (code >= 300 && code < 400)
440
+ return noted(write
441
+ ? unknownWrite(`${provider} answered HTTP ${code} with a redirect, which this connection does not follow, so whether the request was applied is unknown. Re-read its target before repeating it.`, status)
442
+ : failure, at("redirected", code));
443
+ if (write && code >= 500)
444
+ return noted(unknownWrite(`${provider} answered HTTP ${code} after receiving the request, so its outcome is unknown — it may have been applied. Re-read its target before repeating it.`, status), at("server-error", code));
445
+ if (callWrite && own?.request?.auxiliary !== true && code === 401) {
446
+ // Never sent again (INV-9); the next call mints a fresh token.
447
+ const refusal = toConnectorCallError(failure, connection.errors, {
448
+ classification: "write",
449
+ dispatches: [own],
450
+ withholds: connection.safety.withholdsErrors,
451
+ signal,
452
+ });
453
+ return noted(new Refusal({ error: unsentAfterUnauthorized(provider, refusal) }), at("unauthorized", 401));
454
+ }
455
+ return noted(failure, at("refused", code));
456
+ }
457
+ case "RedirectRefused":
458
+ return noted(write
459
+ ? unknownWrite(`${provider} answered HTTP ${failure.status} with a redirect, which this connection does not follow, so whether the request was applied is unknown. Re-read its target before repeating it.`, status)
460
+ : failure, at("redirected", failure.status));
461
+ case "TransportFailure":
462
+ return noted(write
463
+ ? unknownWrite(`${provider} was sent the request but no answer came back, so it may or may not have been applied. Re-read its target before repeating it.`, status)
464
+ : failure, at("awaiting-response", undefined));
465
+ case "ResponseTooLarge":
466
+ case "UnreadableBody":
467
+ // An error status keeps its meaning whatever went wrong reading it.
468
+ if (status !== undefined && status >= 400)
469
+ return noted(failure, at(write && status >= 500 ? "server-error" : "refused"));
470
+ return noted(write
471
+ ? unknownWrite(`${provider} accepted the request but its reply could not be read; the change probably applied. Re-read before repeating it.`, status)
472
+ : failure, at("reading-body"));
473
+ default:
474
+ return noted(failure, at("refused"));
475
+ }
476
+ }
477
+ return {
478
+ json: (request, options) => Effect.map(send(request, "application/json", options), (answer) => answer.data),
479
+ bytes: (request, accept = "*/*", options) => send(request, accept, options, true),
480
+ };
481
+ }
482
+ /**
483
+ * Reword a failure a Google request returned, keeping its verdict, its
484
+ * provenance and its phase: what a product adds after an uncertain create.
485
+ */
486
+ export function googleFailureMessage(connection, failure, message) {
487
+ return Effect.gen(function* () {
488
+ const error = toConnectorCallError(failure, connection.errors, {
489
+ classification: yield* Classification,
490
+ dispatches: yield* Dispatches,
491
+ withholds: connection.safety.withholdsErrors,
492
+ signal: yield* Signal,
493
+ });
494
+ const reworded = new Refusal({ error: providerFailureMessage(error, message(error.message)) });
495
+ const outcome = googleOutcomeOf(failure);
496
+ return yield* Effect.fail(outcome ? noted(reworded, outcome) : reworded);
497
+ });
498
+ }
499
+ /** Arguments arrive validated against the exact legacy `inputSchema` by `api()` before any handler runs. */
500
+ const ARGUMENTS = Schema.Record(Schema.String, Schema.Unknown);
501
+ /**
502
+ * The step-1 catalog bridge. The tool is a kit `read` or `write` (its
503
+ * lease, write capacity, transport, failure mapping and result safety are
504
+ * the kit's), but its catalog keeps the legacy declaration's bytes:
505
+ * annotations, input and output schemas. `api()` validates every call, from
506
+ * every entry path, against that exact input schema before the handler runs
507
+ * (`callTool` in `src/connectors/api-connector.ts`, fail-closed), so the
508
+ * decoder accepts whatever reaches it and keeps the caller's key order. Step
509
+ * 2 replaces these schemas with Effect declarations (0011).
510
+ */
511
+ export function googleTool(connection, declaration) {
512
+ const { annotations } = declaration;
513
+ const spec = {
514
+ name: declaration.name,
515
+ description: declaration.description,
516
+ input: ARGUMENTS,
517
+ output: Schema.Unknown,
518
+ ...(declaration.writeSteps ? { writeSteps: declaration.writeSteps } : {}),
519
+ run: (args) => Effect.gen(function* () {
520
+ const operation = yield* Effect.serviceOption(Operation);
521
+ const ctx = Option.isSome(operation) ? operation.value : undefined;
522
+ if (!ctx)
523
+ return yield* Effect.die(new Error(`${declaration.name} needs the call's connector context.`));
524
+ return yield* declaration.run(args, ctx);
525
+ }).pipe(
526
+ // A product's own refusals are thrown ConnectorCallErrors, as on the legacy client.
527
+ Effect.catchDefect((defect) => defect instanceof ConnectorCallError ? Effect.fail(new Refusal({ error: defect })) : Effect.die(defect))),
528
+ };
529
+ const built = annotations.readOnlyHint === true && annotations.destructiveHint !== true
530
+ ? read(connection, spec)
531
+ : write(connection, { ...spec, destructive: annotations.destructiveHint === true });
532
+ return Object.assign(built, {
533
+ annotations: declaration.annotations,
534
+ inputSchema: declaration.inputSchema,
535
+ outputSchema: declaration.outputSchema,
536
+ });
537
+ }
@@ -12,6 +12,7 @@
12
12
  * around its rows — page objects, counts, ids — so a product sizes its rows
13
13
  * against this and its envelope never needs measuring.
14
14
  */
15
+ import { redactBeforeCut } from "../../../sent-secrets.js";
15
16
  /** The size one Workspace result is built to stay under, in UTF-8 JSON bytes. */
16
17
  export const RESULT_BUDGET_BYTES = 192 * 1024;
17
18
  const encoder = new TextEncoder();
@@ -24,9 +25,21 @@ export function jsonBytes(value) {
24
25
  * `text` cut so that its JSON string encoding — quotes and escapes included —
25
26
  * takes at most `maxBytes` UTF-8 bytes, with `marker(dropped)` appended when
26
27
  * anything was cut. The cut never splits a surrogate pair, and the marker is
27
- * counted inside the bound, so the result always fits.
28
+ * counted inside the bound, so the result always fits. Text that must be cut
29
+ * has every secret the call's request sent replaced first: a cut through an
30
+ * echo would leave a fragment no later redaction can find.
28
31
  */
29
- export function clampText(text, maxBytes, marker) {
32
+ export function clampText(ctx, original, maxBytes, marker) {
33
+ if (jsonBytes(original) <= maxBytes)
34
+ return original;
35
+ return clampRedactedText(redactBeforeCut(ctx, original), maxBytes, marker);
36
+ }
37
+ /**
38
+ * {@link clampText} for text whose sent secrets the caller already replaced,
39
+ * whole, before cutting any of it: a reader that pages one text from offsets
40
+ * must count every page in the same redacted text.
41
+ */
42
+ export function clampRedactedText(text, maxBytes, marker) {
30
43
  if (jsonBytes(text) <= maxBytes)
31
44
  return text;
32
45
  const fits = (length) => {
@@ -47,7 +47,8 @@ export interface DelegatedTokenRequest {
47
47
  * what happened inside its own request — a token, Google's refusal, or
48
48
  * `abandoned` for anything else — and a follower that hears `abandoned`, or
49
49
  * reaches the deadline first, mints for itself. A refusal is rebuilt for each
50
- * follower from its code and message, never handed over as the owner's object.
50
+ * follower from its code, message and resend advice, never handed over as the
51
+ * owner's object.
51
52
  */
52
53
  export declare function delegatedToken(request: DelegatedTokenRequest, ctx: ConnectorContext): Promise<string>;
53
54
  /**
@@ -23,7 +23,7 @@
23
23
  * and never the material that proves it.
24
24
  */
25
25
  import { guardedFetch, retryAfterMs } from "../../../connectors/guarded-fetch.js";
26
- import { ConnectorCallError } from "../../../errors.js";
26
+ import { ConnectorCallError, resendAdvice, resendAdviceOf } from "../../../errors.js";
27
27
  /** Google's OAuth 2.0 token endpoint, and the JWT audience it requires. */
28
28
  const GOOGLE_TOKEN_ORIGIN = "https://oauth2.googleapis.com";
29
29
  const GOOGLE_TOKEN_URL = `${GOOGLE_TOKEN_ORIGIN}/token`;
@@ -259,6 +259,7 @@ async function signAssertion(account, subject, scopes, nowSeconds) {
259
259
  }
260
260
  // --- Token exchange --------------------------------------------------------------
261
261
  const tokenTransport = guardedFetch({
262
+ auxiliary: true,
262
263
  provider: "Google OAuth",
263
264
  baseUrl: GOOGLE_TOKEN_ORIGIN,
264
265
  headers: { Accept: "application/json" },
@@ -309,7 +310,7 @@ function tokenFailure(account, scopes, status, headers, payload) {
309
310
  return new ConnectorCallError("provider_permission_denied", `Google refused domain-wide delegation for ${account.clientEmail}.${said} A Workspace super admin must authorize ${client} in the Admin console (Security → Access and data control → API controls → Manage Domain Wide Delegation) with exactly these scopes: ${scopes.join(",")}. A new or changed grant can take up to 24 hours to apply.`);
310
311
  }
311
312
  if (code === "invalid_grant") {
312
- return new ConnectorCallError("auth_required", `Google refused the delegated token.${said} The mapped Workspace user may not exist, may be suspended, or may be outside the domain that granted delegation; the service account key may have been deleted or disabled; or this host's clock may be minutes off. Check the deployment's subject mapping and the key before retrying.`);
313
+ return resendAdvice(new ConnectorCallError("auth_required", `Google refused the delegated token.${said} The mapped Workspace user may not exist, may be suspended, or may be outside the domain that granted delegation; the service account key may have been deleted or disabled; or this host's clock may be minutes off. Check the deployment's subject mapping and the key.`), " before retrying");
313
314
  }
314
315
  if (code === "invalid_client" || code === "disabled_client") {
315
316
  return new ConnectorCallError("auth_required", `Google rejected service account ${account.clientEmail} itself.${said} The account or its key may be disabled or deleted; create a new JSON key and redeploy.`);
@@ -436,7 +437,8 @@ function follow(flight, signal) {
436
437
  * what happened inside its own request — a token, Google's refusal, or
437
438
  * `abandoned` for anything else — and a follower that hears `abandoned`, or
438
439
  * reaches the deadline first, mints for itself. A refusal is rebuilt for each
439
- * follower from its code and message, never handed over as the owner's object.
440
+ * follower from its code, message and resend advice, never handed over as the
441
+ * owner's object.
440
442
  */
441
443
  export async function delegatedToken(request, ctx) {
442
444
  const key = await cacheKey(request);
@@ -451,7 +453,8 @@ export async function delegatedToken(request, ctx) {
451
453
  if (outcome.kind === "token")
452
454
  return outcome.minted.accessToken;
453
455
  if (outcome.kind === "refused") {
454
- throw new ConnectorCallError(outcome.code, outcome.message, outcome.retryAfterMs === undefined ? {} : { retryAfterMs: outcome.retryAfterMs });
456
+ const refused = new ConnectorCallError(outcome.code, outcome.message, outcome.retryAfterMs === undefined ? {} : { retryAfterMs: outcome.retryAfterMs });
457
+ throw outcome.advice === undefined ? refused : resendAdvice(refused, outcome.advice);
455
458
  }
456
459
  if (flights.get(key) === flight)
457
460
  flights.delete(key);
@@ -478,6 +481,7 @@ export async function delegatedToken(request, ctx) {
478
481
  code: error.code,
479
482
  message: error.message,
480
483
  retryAfterMs: error.retryAfterMs,
484
+ advice: resendAdviceOf(error),
481
485
  }
482
486
  : { kind: "abandoned" });
483
487
  throw error;