@zackbart/connecta 0.28.1 → 0.30.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 (332) hide show
  1. package/CHANGELOG.md +855 -5
  2. package/README.md +125 -116
  3. package/bin/connecta.mjs +121 -139
  4. package/bin/meta-tool-names.d.mts +2 -0
  5. package/bin/meta-tool-names.mjs +9 -0
  6. package/bin/version.mjs +3 -0
  7. package/dist/access-tokens.js +53 -63
  8. package/dist/activity-request.js +8 -0
  9. package/dist/activity.d.ts +76 -42
  10. package/dist/activity.js +110 -42
  11. package/dist/argument-redaction.js +230 -0
  12. package/dist/auth/clerk-sdk/client.d.ts +65 -0
  13. package/dist/auth/clerk-sdk/client.js +5 -0
  14. package/dist/auth/clerk-sdk/generated.js +1845 -0
  15. package/dist/auth/clerk-transport.js +19 -0
  16. package/dist/auth/clerk.d.ts +17 -7
  17. package/dist/auth/clerk.js +189 -107
  18. package/dist/auth/cloudflare-access.js +25 -26
  19. package/dist/auth/downstream-client-metadata.d.ts +29 -0
  20. package/dist/auth/downstream-client-metadata.js +133 -0
  21. package/dist/auth/downstream-oauth.js +1584 -1580
  22. package/dist/auth/downstream-revocation.js +106 -0
  23. package/dist/auth/oauth-token-response.js +231 -0
  24. package/dist/auth/oauth-v2-migration.js +116 -0
  25. package/dist/auth/static-oauth.js +93 -71
  26. package/dist/auth-elicitation.js +288 -0
  27. package/dist/authorization-handoff.js +111 -0
  28. package/dist/branding.d.ts +8 -16
  29. package/dist/branding.js +26 -59
  30. package/dist/byte-read-response.js +39 -0
  31. package/dist/call-admission.js +12 -16
  32. package/dist/catalog-cache.js +739 -0
  33. package/dist/catalog-drift.d.ts +50 -15
  34. package/dist/catalog-drift.js +365 -128
  35. package/dist/catalog-fingerprint.js +2 -4
  36. package/dist/catalog-freshness.js +13 -0
  37. package/dist/catalog-limits.js +2 -2
  38. package/dist/catalog-service.js +409 -225
  39. package/dist/catalog.js +43 -84
  40. package/dist/concurrency.js +3 -4
  41. package/dist/config-defaults.d.ts +39 -0
  42. package/dist/config-defaults.js +46 -0
  43. package/dist/config-schema.d.ts +181 -0
  44. package/dist/config-schema.js +435 -0
  45. package/dist/config-value-sources.js +102 -0
  46. package/dist/config.d.ts +633 -0
  47. package/dist/config.js +508 -0
  48. package/dist/connector-access.d.ts +1 -0
  49. package/dist/connector-access.js +13 -15
  50. package/dist/connector-caller.d.ts +8 -0
  51. package/dist/connector-caller.js +15 -6
  52. package/dist/connector-scope.js +1 -1
  53. package/dist/connectors/api-connector.d.ts +59 -7
  54. package/dist/connectors/api-connector.js +106 -19
  55. package/dist/connectors/api.js +4 -1
  56. package/dist/connectors/guarded-fetch.d.ts +144 -0
  57. package/dist/connectors/guarded-fetch.js +87 -38
  58. package/dist/connectors/negotiation-cache.js +46 -0
  59. package/dist/connectors/option-shapes.js +27 -0
  60. package/dist/connectors/remote-mcp.d.ts +30 -4
  61. package/dist/connectors/remote-mcp.js +1774 -320
  62. package/dist/connectors/resource-uri.js +335 -0
  63. package/dist/credential-contract.d.ts +10 -0
  64. package/dist/credential-rules.js +1 -3
  65. package/dist/credential-url.js +108 -0
  66. package/dist/credentials.d.ts +6 -1
  67. package/dist/credentials.js +27 -18
  68. package/dist/d1.d.ts +130 -0
  69. package/dist/d1.js +290 -0
  70. package/dist/describe-config.d.ts +165 -0
  71. package/dist/describe-config.js +315 -0
  72. package/dist/described.js +106 -0
  73. package/dist/downstream-input-context.js +128 -0
  74. package/dist/downstream-input.js +325 -0
  75. package/dist/errors.d.ts +132 -31
  76. package/dist/errors.js +175 -87
  77. package/dist/execute.js +798 -318
  78. package/dist/executor-admission.d.ts +1 -0
  79. package/dist/executor-admission.js +11 -15
  80. package/dist/executor-contract.d.ts +20 -0
  81. package/dist/executor-contract.js +48 -0
  82. package/dist/executor-result.js +30 -13
  83. package/dist/executors/quickjs-child.js +15 -9
  84. package/dist/executors/quickjs-protocol.js +5 -6
  85. package/dist/executors/quickjs-runtime.js +152 -59
  86. package/dist/executors/quickjs.js +49 -39
  87. package/dist/favicon.js +1 -2
  88. package/dist/fix-prompt.js +1 -3
  89. package/dist/guest-runtime.js +238 -0
  90. package/dist/guest-types.d.ts +218 -0
  91. package/dist/guest-types.js +1 -0
  92. package/dist/html-security.js +24 -0
  93. package/dist/identity.js +1 -3
  94. package/dist/inbound-credential.js +52 -0
  95. package/dist/index.d.ts +24 -256
  96. package/dist/index.js +65 -478
  97. package/dist/invocation-auth.js +69 -0
  98. package/dist/invocation.js +262 -79
  99. package/dist/json-schema.d.ts +1 -1
  100. package/dist/mcp-client-context.js +35 -0
  101. package/dist/mcp-result.js +11 -7
  102. package/dist/meta-output.js +61 -0
  103. package/dist/meta-tool-names.d.ts +2 -0
  104. package/dist/meta-tool-names.js +3 -0
  105. package/dist/meta-tools.js +419 -272
  106. package/dist/module-contracts.d.ts +8 -23
  107. package/dist/node.d.ts +0 -2
  108. package/dist/node.js +2 -2
  109. package/dist/oauth-callback-outcome.js +1 -3
  110. package/dist/oauth-handoff.js +194 -0
  111. package/dist/oauth-sealing.js +20 -0
  112. package/dist/operator-record.d.ts +137 -0
  113. package/dist/operator-record.js +420 -0
  114. package/dist/operator-ui/assets.js +31 -0
  115. package/dist/operator-ui/contract.d.ts +72 -0
  116. package/dist/operator-ui/contract.js +1 -0
  117. package/dist/operator-ui/fix-prompts.d.ts +18 -0
  118. package/dist/operator-ui/generated.js +5 -4
  119. package/dist/operator-ui/model.d.ts +12 -87
  120. package/dist/operator-ui/model.js +2 -9
  121. package/dist/operator-ui/setup-commands.js +1 -3
  122. package/dist/operator-ui/view.d.ts +323 -0
  123. package/dist/operator-ui/view.js +62 -189
  124. package/dist/page-styles.js +2 -3
  125. package/dist/program-result.js +5 -0
  126. package/dist/program-source.js +14 -2
  127. package/dist/{exempt-writes.js → program-writes.js} +60 -19
  128. package/dist/provider.d.ts +142 -0
  129. package/dist/provider.js +187 -0
  130. package/dist/providers/_shared/google/result-size.js +57 -0
  131. package/dist/providers/_shared/google/service-account.d.ts +58 -0
  132. package/dist/providers/_shared/google/service-account.js +500 -0
  133. package/dist/providers/_shared/google/workspace.d.ts +276 -0
  134. package/dist/providers/_shared/google/workspace.js +518 -0
  135. package/dist/providers/_shared/request-token.js +83 -0
  136. package/dist/providers/{basecamp.d.ts → basecamp/index.d.ts} +6 -28
  137. package/dist/providers/basecamp/index.js +997 -0
  138. package/dist/providers/basecamp/skill.generated.js +9 -0
  139. package/dist/providers/{breeze.d.ts → breeze/index.d.ts} +2 -2
  140. package/dist/providers/{breeze.js → breeze/index.js} +184 -140
  141. package/dist/providers/breeze/skill.generated.js +9 -0
  142. package/dist/providers/{ccb.d.ts → ccb/index.d.ts} +2 -2
  143. package/dist/providers/{ccb.js → ccb/index.js} +271 -116
  144. package/dist/providers/ccb/skill.generated.js +9 -0
  145. package/dist/providers/{cloudflare.d.ts → cloudflare/index.d.ts} +8 -7
  146. package/dist/providers/{cloudflare.js → cloudflare/index.js} +171 -738
  147. package/dist/providers/cloudflare/skill.generated.js +10 -0
  148. package/dist/providers/docs/index.d.ts +54 -0
  149. package/dist/providers/docs/index.js +1237 -0
  150. package/dist/providers/docs/skill.generated.js +9 -0
  151. package/dist/providers/drive/index.d.ts +53 -0
  152. package/dist/providers/drive/index.js +1523 -0
  153. package/dist/providers/drive/skill.generated.js +9 -0
  154. package/dist/providers/forms/index.d.ts +54 -0
  155. package/dist/providers/forms/index.js +1217 -0
  156. package/dist/providers/forms/skill.generated.js +11 -0
  157. package/dist/providers/github/auth.d.ts +32 -0
  158. package/dist/providers/github/auth.js +361 -0
  159. package/dist/providers/github/hosted.js +218 -0
  160. package/dist/providers/github/index.d.ts +13 -0
  161. package/dist/providers/github/index.js +140 -0
  162. package/dist/providers/github/key.js +100 -0
  163. package/dist/providers/github/rest.js +321 -0
  164. package/dist/providers/github/scope.d.ts +29 -0
  165. package/dist/providers/github/scope.js +124 -0
  166. package/dist/providers/github/skill.generated.js +8 -0
  167. package/dist/providers/gmail/index.d.ts +51 -0
  168. package/dist/providers/gmail/index.js +1436 -0
  169. package/dist/providers/gmail/skill.generated.js +9 -0
  170. package/dist/providers/infisical/index.d.ts +7 -0
  171. package/dist/providers/infisical/index.js +713 -0
  172. package/dist/providers/infisical/skill.generated.js +8 -0
  173. package/dist/providers/{linear.d.ts → linear/index.d.ts} +11 -14
  174. package/dist/providers/linear/index.js +352 -0
  175. package/dist/providers/linear/skill.generated.js +8 -0
  176. package/dist/providers/{mixpanel.d.ts → mixpanel/index.d.ts} +5 -10
  177. package/dist/providers/mixpanel/index.js +416 -0
  178. package/dist/providers/mixpanel/skill.generated.js +9 -0
  179. package/dist/providers/{notion.d.ts → notion/index.d.ts} +8 -8
  180. package/dist/providers/{notion.js → notion/index.js} +226 -239
  181. package/dist/providers/notion/skill.generated.js +10 -0
  182. package/dist/providers/{overflow.d.ts → overflow/index.d.ts} +2 -2
  183. package/dist/providers/{overflow.js → overflow/index.js} +74 -111
  184. package/dist/providers/overflow/skill.generated.js +8 -0
  185. package/dist/providers/{planning-center.d.ts → planning-center/index.d.ts} +2 -2
  186. package/dist/providers/{planning-center.js → planning-center/index.js} +264 -104
  187. package/dist/providers/planning-center/skill.generated.js +10 -0
  188. package/dist/providers/{revenuecat.d.ts → revenuecat/index.d.ts} +5 -10
  189. package/dist/providers/revenuecat/index.js +557 -0
  190. package/dist/providers/revenuecat/skill.generated.js +11 -0
  191. package/dist/providers/sheets/index.d.ts +54 -0
  192. package/dist/providers/sheets/index.js +1237 -0
  193. package/dist/providers/sheets/skill.generated.js +10 -0
  194. package/dist/providers/slides/index.d.ts +53 -0
  195. package/dist/providers/slides/index.js +2645 -0
  196. package/dist/providers/slides/skill.generated.js +9 -0
  197. package/dist/providers/{stripe.d.ts → stripe/index.d.ts} +5 -12
  198. package/dist/providers/stripe/index.js +266 -0
  199. package/dist/providers/stripe/skill.generated.js +11 -0
  200. package/dist/providers/{tithely.d.ts → tithely/index.d.ts} +2 -2
  201. package/dist/providers/{tithely.js → tithely/index.js} +60 -91
  202. package/dist/providers/tithely/skill.generated.js +8 -0
  203. package/dist/providers/{vercel.d.ts → vercel/index.d.ts} +8 -8
  204. package/dist/providers/vercel/index.js +1038 -0
  205. package/dist/providers/vercel/mcp-ownership.js +212 -0
  206. package/dist/providers/vercel/skill.generated.js +11 -0
  207. package/dist/registry.d.ts +110 -171
  208. package/dist/registry.js +588 -927
  209. package/dist/request-state.js +21 -0
  210. package/dist/resource-read.js +103 -0
  211. package/dist/result-shapes.js +17 -49
  212. package/dist/retired-toolkits.js +1 -1
  213. package/dist/routes/access-tokens.js +3 -6
  214. package/dist/routes/activity-context.js +21 -0
  215. package/dist/routes/activity-disclosure.js +40 -0
  216. package/dist/routes/activity.js +59 -21
  217. package/dist/routes/actor-labels.js +3 -50
  218. package/dist/routes/connect.js +221 -0
  219. package/dist/routes/credentials.js +15 -27
  220. package/dist/routes/mcp.js +365 -130
  221. package/dist/routes/oauth-client-metadata.js +15 -0
  222. package/dist/routes/oauth-management.js +45 -107
  223. package/dist/routes/oauth.js +110 -57
  224. package/dist/routes/operator.js +3 -3
  225. package/dist/routes/shared.d.ts +25 -64
  226. package/dist/routes/shared.js +160 -80
  227. package/dist/routes/skills.js +30 -0
  228. package/dist/routes/ui-config.js +225 -0
  229. package/dist/routes/ui-data.js +40 -35
  230. package/dist/routes/ui.js +66 -56
  231. package/dist/runtime/admission.js +4 -2
  232. package/dist/runtime/call-admission.js +3 -1
  233. package/dist/runtime/connector-scope.js +1 -4
  234. package/dist/runtime/run.js +10 -39
  235. package/dist/runtime/services.js +12 -117
  236. package/dist/runtime/shared-read.js +1 -3
  237. package/dist/runtime/storage.js +8 -1
  238. package/dist/sent-secrets.d.ts +93 -0
  239. package/dist/sent-secrets.js +1013 -0
  240. package/dist/server.js +28 -71
  241. package/dist/skills.js +416 -174
  242. package/dist/sqlite.d.ts +48 -0
  243. package/dist/sqlite.js +181 -0
  244. package/dist/storage/keys.js +443 -0
  245. package/dist/storage/memory.js +16 -4
  246. package/dist/storage/sql.d.ts +66 -0
  247. package/dist/storage/sql.js +543 -0
  248. package/dist/timeout.js +4 -2
  249. package/dist/tool-name.js +17 -0
  250. package/dist/tool-safety.d.ts +9 -35
  251. package/dist/tool-safety.js +20 -40
  252. package/dist/types.d.ts +336 -56
  253. package/dist/types.js +0 -1
  254. package/dist/ui.d.ts +7 -19
  255. package/dist/ui.js +76 -90
  256. package/dist/url-safety.js +3 -6
  257. package/dist/usage-guide.js +146 -0
  258. package/dist/validate.d.ts +7 -0
  259. package/dist/validate.js +309 -47
  260. package/dist/version.d.ts +1 -7
  261. package/dist/version.js +3 -7
  262. package/dist/worker.d.ts +11 -0
  263. package/dist/worker.js +435 -0
  264. package/documentation/README.md +63 -0
  265. package/documentation/architecture.md +696 -231
  266. package/documentation/auth.md +1069 -546
  267. package/documentation/code-mode.md +662 -356
  268. package/documentation/deploying.md +146 -0
  269. package/documentation/integrating.md +159 -0
  270. package/documentation/meta-tools.md +570 -216
  271. package/documentation/operating.md +135 -0
  272. package/documentation/operator-tests.md +97 -0
  273. package/documentation/operator-ui.md +132 -0
  274. package/documentation/provider-migration-0.29.md +65 -0
  275. package/examples/worker/AGENTS.md +34 -12
  276. package/examples/worker/README.md +293 -255
  277. package/examples/worker/kv-to-d1.wrangler.jsonc +26 -0
  278. package/examples/worker/scripts/copy-kv-to-d1.mjs +162 -0
  279. package/examples/worker/src/connecta.config.ts +151 -0
  280. package/examples/worker/src/index.ts +14 -197
  281. package/examples/worker/wrangler.jsonc +15 -35
  282. package/package.json +126 -54
  283. package/templates/node/.dockerignore +1 -2
  284. package/templates/node/.env.example +20 -21
  285. package/templates/node/AGENTS.md +21 -17
  286. package/templates/node/Dockerfile +3 -5
  287. package/templates/node/README.md +140 -58
  288. package/templates/node/docker-compose.yml +11 -12
  289. package/templates/node/package.json +4 -2
  290. package/templates/node/src/connecta.config.ts +119 -0
  291. package/templates/node/src/index.ts +9 -154
  292. package/templates/node/src/provision-token.ts +17 -0
  293. package/AGENTS.md +0 -170
  294. package/dist/artifacts/connector.d.ts +0 -58
  295. package/dist/artifacts/connector.js +0 -730
  296. package/dist/artifacts/document.js +0 -86
  297. package/dist/artifacts/guide.js +0 -140
  298. package/dist/artifacts/html-scan.js +0 -329
  299. package/dist/artifacts/json.js +0 -78
  300. package/dist/artifacts/kv-store.d.ts +0 -20
  301. package/dist/artifacts/kv-store.js +0 -140
  302. package/dist/artifacts/markdown.js +0 -478
  303. package/dist/artifacts/module.d.ts +0 -37
  304. package/dist/artifacts/module.js +0 -66
  305. package/dist/artifacts/operations.d.ts +0 -197
  306. package/dist/artifacts/operations.js +0 -1002
  307. package/dist/artifacts/refresh.d.ts +0 -55
  308. package/dist/artifacts/refresh.js +0 -236
  309. package/dist/artifacts/routes.js +0 -206
  310. package/dist/artifacts/types.d.ts +0 -214
  311. package/dist/artifacts/types.js +0 -22
  312. package/dist/artifacts/validate.d.ts +0 -62
  313. package/dist/artifacts/validate.js +0 -651
  314. package/dist/artifacts.d.ts +0 -6
  315. package/dist/artifacts.js +0 -9
  316. package/dist/auth/bearer.d.ts +0 -11
  317. package/dist/auth/bearer.js +0 -50
  318. package/dist/providers/basecamp.js +0 -445
  319. package/dist/providers/linear.js +0 -217
  320. package/dist/providers/mixpanel.js +0 -247
  321. package/dist/providers/revenuecat.js +0 -317
  322. package/dist/providers/stripe.js +0 -253
  323. package/dist/providers/vercel.js +0 -1253
  324. package/dist/storage/file.d.ts +0 -15
  325. package/dist/storage/file.js +0 -455
  326. package/ethos.md +0 -93
  327. package/examples/worker/src/cloudflare-kv.ts +0 -43
  328. package/examples/worker/src/d1-activity-row.ts +0 -155
  329. package/examples/worker/src/d1-activity.ts +0 -147
  330. package/examples/worker/src/d1-storage.ts +0 -138
  331. package/examples/worker/src/r2-artifact-blobs.ts +0 -29
  332. package/templates/node/src/file-activity.ts +0 -182
package/dist/validate.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Validator } from "@cfworker/json-schema";
2
2
  import { boundedEchoText, ConnectorCallError } from "./errors.js";
3
3
  import { MAX_ARGUMENT_VALIDATION_ISSUES } from "./errors.js";
4
+ import { failureRecord, logFailure } from "./operator-record.js";
4
5
  // Lazy validator cache keyed by the schema object itself; null marks a schema
5
6
  // the validator rejected (warned once, then passed through rather than
6
7
  // breaking a working tool). A WeakMap so schemas belonging to a discarded
@@ -43,12 +44,7 @@ function argumentPath(location) {
43
44
  return location.startsWith("#") ? location.slice(1) || "/" : "/";
44
45
  }
45
46
  function validationUnitKey(unit) {
46
- return JSON.stringify([
47
- unit.keyword,
48
- unit.keywordLocation,
49
- unit.instanceLocation,
50
- unit.error,
51
- ]);
47
+ return JSON.stringify([unit.keyword, unit.keywordLocation, unit.instanceLocation, unit.error]);
52
48
  }
53
49
  function childPropertyName(parentLocation, childLocation) {
54
50
  const prefix = parentLocation === "#" ? "#/" : `${parentLocation}/`;
@@ -70,9 +66,7 @@ function schemaDeclaresProperty(schema, property) {
70
66
  return true;
71
67
  }
72
68
  const patterns = record.patternProperties;
73
- if (patterns === null ||
74
- typeof patterns !== "object" ||
75
- Array.isArray(patterns)) {
69
+ if (patterns === null || typeof patterns !== "object" || Array.isArray(patterns)) {
76
70
  return false;
77
71
  }
78
72
  for (const pattern of Object.keys(patterns)) {
@@ -116,32 +110,26 @@ function normalizedValidationUnits(schema, units) {
116
110
  return true;
117
111
  });
118
112
  }
119
- function agentFacingValidationError(unit) {
120
- return unit.keyword === "false"
121
- ? "Value is not allowed by the declared schema."
122
- : unit.error;
113
+ const JSON_TYPES = new Set(["string", "number", "integer", "boolean", "object", "array", "null"]);
114
+ /** A schema's `type`, when it names JSON types and nothing else. */
115
+ function declaredType(value) {
116
+ const types = typeof value === "string" ? [value] : value;
117
+ return Array.isArray(types) &&
118
+ types.length > 0 &&
119
+ types.every((item) => typeof item === "string" && JSON_TYPES.has(item))
120
+ ? types.join(" | ")
121
+ : undefined;
123
122
  }
124
123
  function expectedType(schema, unit) {
125
124
  if (unit.keyword === "type") {
126
- const value = pointerValue(schema, unit.keywordLocation);
127
- if (typeof value === "string")
128
- return value;
129
- if (Array.isArray(value) && value.every((item) => typeof item === "string")) {
130
- return value.join(" | ");
131
- }
125
+ return declaredType(pointerValue(schema, unit.keywordLocation));
132
126
  }
133
127
  if (unit.keyword === "required") {
134
128
  const missing = REQUIRED_PROPERTY_RE.exec(unit.error)?.[1];
135
129
  if (!missing)
136
130
  return undefined;
137
131
  const parentLocation = unit.keywordLocation.replace(/\/required$/, "");
138
- const value = pointerValue(schema, `${parentLocation}/properties/${encodePointerPart(missing)}/type`);
139
- if (typeof value === "string")
140
- return value;
141
- if (Array.isArray(value) && value.every((item) => typeof item === "string")) {
142
- return value.join(" | ");
143
- }
144
- return "present";
132
+ return (declaredType(pointerValue(schema, `${parentLocation}/properties/${encodePointerPart(missing)}/type`)) ?? "present");
145
133
  }
146
134
  const fixed = {
147
135
  additionalProperties: "no additional properties",
@@ -158,29 +146,288 @@ function expectedType(schema, unit) {
158
146
  function validationDetails(schema, units) {
159
147
  const issues = [];
160
148
  for (const unit of units) {
161
- const missing = unit.keyword === "required"
162
- ? REQUIRED_PROPERTY_RE.exec(unit.error)?.[1]
163
- : undefined;
149
+ const missing = unit.keyword === "required" ? REQUIRED_PROPERTY_RE.exec(unit.error)?.[1] : undefined;
164
150
  const path = missing !== undefined
165
151
  ? `${argumentPath(unit.instanceLocation).replace(/\/$/, "")}/${encodePointerPart(missing)}`
166
152
  : argumentPath(unit.instanceLocation);
167
153
  const code = unit.keyword === "false" ? "additionalProperties" : unit.keyword;
168
154
  const expected = expectedType(schema, unit) ??
169
- (code === "additionalProperties"
170
- ? "no additional properties"
171
- : "the declared schema constraint");
155
+ (code === "additionalProperties" ? "no additional properties" : "the declared schema constraint");
172
156
  const issue = { path, code, expected };
173
- if (!issues.some((existing) => existing.path === issue.path &&
174
- existing.code === issue.code &&
175
- existing.expected === issue.expected)) {
157
+ if (!issues.some((existing) => existing.path === issue.path && existing.code === issue.code && existing.expected === issue.expected)) {
176
158
  issues.push(issue);
177
159
  }
178
160
  }
179
161
  return {
180
162
  issues: issues.slice(0, MAX_ARGUMENT_VALIDATION_ISSUES),
181
- ...(issues.length > MAX_ARGUMENT_VALIDATION_ISSUES
182
- ? { truncated: true }
183
- : {}),
163
+ ...(issues.length > MAX_ARGUMENT_VALIDATION_ISSUES ? { truncated: true } : {}),
164
+ };
165
+ }
166
+ function schemaObject(value) {
167
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
168
+ }
169
+ function receivedType(value) {
170
+ return value === undefined ? "missing" : value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
171
+ }
172
+ const BOUND_KEYWORDS = [
173
+ "minimum",
174
+ "maximum",
175
+ "exclusiveMinimum",
176
+ "exclusiveMaximum",
177
+ "multipleOf",
178
+ "minLength",
179
+ "maxLength",
180
+ "minItems",
181
+ "maxItems",
182
+ "minProperties",
183
+ "maxProperties",
184
+ ];
185
+ /** No caller values are used to invent an example. A candidate must validate. */
186
+ function exampleCandidate(schema, root, depth = 0, budget = { remaining: 128, active: new Set() }) {
187
+ if (--budget.remaining < 0)
188
+ throw new Error("Example synthesis budget exhausted");
189
+ if (depth > 12 || schema === false)
190
+ return undefined;
191
+ const node = schemaObject(schema);
192
+ if (budget.active.has(node))
193
+ throw new Error("Recursive schema cannot produce a bounded example");
194
+ budget.active.add(node);
195
+ try {
196
+ if (typeof node.$ref === "string") {
197
+ return exampleCandidate(pointerValue(root, node.$ref), root, depth + 1, budget);
198
+ }
199
+ if (Object.hasOwn(node, "const"))
200
+ return node.const;
201
+ if (Array.isArray(node.enum))
202
+ return node.enum[0];
203
+ const type = Array.isArray(node.type) ? node.type[0] : node.type;
204
+ const variants = Array.isArray(node.oneOf) ? node.oneOf : node.anyOf;
205
+ if (Array.isArray(variants) && variants.length) {
206
+ return mergeExample(exampleCandidate({ ...node, oneOf: undefined, anyOf: undefined }, root, depth + 1, budget), exampleCandidate(variants[0], root, depth + 1, budget));
207
+ }
208
+ if (Array.isArray(node.examples) && node.examples.length)
209
+ return node.examples[0];
210
+ if (Object.hasOwn(node, "default"))
211
+ return node.default;
212
+ let candidate;
213
+ if (type === "object" || node.properties || node.required || node.allOf) {
214
+ const properties = schemaObject(node.properties);
215
+ const required = Array.isArray(node.required) ? node.required : [];
216
+ candidate = Object.fromEntries(required
217
+ .filter((key) => typeof key === "string")
218
+ .slice(0, 30)
219
+ .map((key) => [key, exampleCandidate(properties[key], root, depth + 1, budget)]));
220
+ if (Array.isArray(node.allOf)) {
221
+ for (const branch of node.allOf.slice(0, 20)) {
222
+ candidate = mergeExample(candidate, exampleCandidate(branch, root, depth + 1, budget));
223
+ }
224
+ }
225
+ const object = schemaObject(candidate);
226
+ const dependencies = schemaObject(node.dependentRequired ?? node.dependencies);
227
+ for (const [key, needs] of Object.entries(dependencies)) {
228
+ if (Object.hasOwn(object, key) && Array.isArray(needs)) {
229
+ for (const need of needs.slice(0, 30)) {
230
+ if (typeof need === "string" && !Object.hasOwn(object, need)) {
231
+ Object.defineProperty(object, need, {
232
+ value: exampleCandidate(properties[need], root, depth + 1, budget),
233
+ enumerable: true,
234
+ configurable: true,
235
+ writable: true,
236
+ });
237
+ }
238
+ }
239
+ }
240
+ }
241
+ if (node.if) {
242
+ try {
243
+ const matches = new Validator(node.if, "2020-12", false).validate(candidate).valid;
244
+ candidate = mergeExample(candidate, exampleCandidate(matches ? node.then : node.else, root, depth + 1, budget));
245
+ }
246
+ catch {
247
+ // An unevaluable branch cannot establish a valid example.
248
+ }
249
+ }
250
+ // Branches may declare required keys while their types live on the parent.
251
+ for (const key of Object.keys(schemaObject(candidate))) {
252
+ if (schemaObject(candidate)[key] === undefined) {
253
+ schemaObject(candidate)[key] = exampleCandidate(properties[key], root, depth + 1, budget);
254
+ }
255
+ }
256
+ }
257
+ else if (type === "array") {
258
+ const count = typeof node.minItems === "number" ? node.minItems : 0;
259
+ candidate = Array.from({ length: Math.min(count, 20) }, (_, index) => exampleCandidate(Array.isArray(node.prefixItems) ? node.prefixItems[index] : node.items, root, depth + 1, budget));
260
+ }
261
+ else if (type === "number" || type === "integer") {
262
+ let number = typeof node.minimum === "number" ? node.minimum : 0;
263
+ if (typeof node.exclusiveMinimum === "number")
264
+ number = node.exclusiveMinimum + (type === "integer" ? 1 : 0.5);
265
+ if (typeof node.maximum === "number")
266
+ number = Math.min(number, node.maximum);
267
+ if (typeof node.exclusiveMaximum === "number")
268
+ number = Math.min(number, node.exclusiveMaximum - 1);
269
+ if (typeof node.multipleOf === "number" && node.multipleOf > 0)
270
+ number = Math.ceil(number / node.multipleOf) * node.multipleOf;
271
+ candidate = type === "integer" ? Math.ceil(number) : number;
272
+ }
273
+ else if (type === "boolean")
274
+ candidate = false;
275
+ else if (type === "null")
276
+ candidate = null;
277
+ else if (type === "string") {
278
+ const formats = {
279
+ date: "2000-01-01",
280
+ "date-time": "2000-01-01T00:00:00Z",
281
+ email: "a@example.com",
282
+ uri: "https://example.com",
283
+ uuid: "00000000-0000-4000-8000-000000000000",
284
+ };
285
+ candidate =
286
+ typeof node.format === "string" && formats[node.format]
287
+ ? formats[node.format]
288
+ : "x".repeat(Math.min(typeof node.minLength === "number" ? node.minLength : 0, 128));
289
+ }
290
+ return candidate;
291
+ }
292
+ finally {
293
+ budget.active.delete(node);
294
+ }
295
+ }
296
+ function mergeExample(a, b) {
297
+ if (a !== null &&
298
+ b !== null &&
299
+ typeof a === "object" &&
300
+ typeof b === "object" &&
301
+ !Array.isArray(a) &&
302
+ !Array.isArray(b)) {
303
+ return { ...a, ...b };
304
+ }
305
+ return b === undefined ? a : b;
306
+ }
307
+ /** Remove optional sample fields only when the complete example stays valid. */
308
+ function minimizeExample(example, validator) {
309
+ let attempts = 0;
310
+ const valid = () => {
311
+ try {
312
+ return validator.validate(example).valid;
313
+ }
314
+ catch {
315
+ return false;
316
+ }
317
+ };
318
+ const visit = (value, depth) => {
319
+ if (depth > 12 || value === null || typeof value !== "object" || attempts >= 60)
320
+ return;
321
+ if (Array.isArray(value)) {
322
+ for (const item of value.slice(0, 20))
323
+ visit(item, depth + 1);
324
+ while (value.length > 0 && attempts++ < 60) {
325
+ const last = value.pop();
326
+ if (!valid()) {
327
+ value.push(last);
328
+ break;
329
+ }
330
+ }
331
+ return;
332
+ }
333
+ const object = value;
334
+ for (const key of Object.keys(object)) {
335
+ if (attempts++ >= 60)
336
+ break;
337
+ const original = object[key];
338
+ delete object[key];
339
+ if (!valid()) {
340
+ Object.defineProperty(object, key, { value: original, enumerable: true, configurable: true, writable: true });
341
+ visit(original, depth + 1);
342
+ }
343
+ }
344
+ };
345
+ visit(example, 0);
346
+ }
347
+ function repairDetails(schema, args, units, validator) {
348
+ const root = schemaObject(schema);
349
+ const keys = (node) => Object.entries(schemaObject(node.properties))
350
+ .filter(([, value]) => value !== false)
351
+ .map(([key]) => key);
352
+ const issues = units.slice(0, MAX_ARGUMENT_VALIDATION_ISSUES).map((unit) => {
353
+ const missing = unit.keyword === "required" ? REQUIRED_PROPERTY_RE.exec(unit.error)?.[1] : undefined;
354
+ const location = missing === undefined ? unit.instanceLocation : `${unit.instanceLocation}/${encodePointerPart(missing)}`;
355
+ const parentLocation = unit.keywordLocation.replace(/\/[^/]+$/, "");
356
+ const parent = schemaObject(pointerValue(schema, parentLocation));
357
+ const node = missing === undefined ? parent : schemaObject(schemaObject(parent.properties)[missing]);
358
+ const bounds = Object.fromEntries(BOUND_KEYWORDS.flatMap((key) => (typeof node[key] === "number" ? [[key, node[key]]] : [])));
359
+ // A false subschema under additionalProperties names its parent object's keys.
360
+ const closedParent = unit.keyword === "false" && unit.keywordLocation.endsWith("/additionalProperties")
361
+ ? schemaObject(pointerValue(schema, unit.keywordLocation.slice(0, -"/additionalProperties".length)))
362
+ : node;
363
+ const acceptedKeys = keys(closedParent);
364
+ return {
365
+ path: argumentPath(location),
366
+ receivedType: receivedType(pointerValue(args, location)),
367
+ ...(acceptedKeys.length ? { acceptedKeys } : {}),
368
+ ...(Array.isArray(node.enum) ? { enumValues: node.enum } : {}),
369
+ ...(Object.keys(bounds).length ? { bounds } : {}),
370
+ };
371
+ });
372
+ const conditionalRequirements = [];
373
+ const visit = (value, path, depth) => {
374
+ if (depth > 12 || conditionalRequirements.length >= 20)
375
+ return;
376
+ const node = schemaObject(value);
377
+ for (const [key, required] of Object.entries(schemaObject(node.dependentRequired ?? node.dependencies))) {
378
+ if (Array.isArray(required) && required.every((key) => typeof key === "string")) {
379
+ conditionalRequirements.push({ path, condition: { required: [key] }, required });
380
+ }
381
+ }
382
+ for (const [key, branch] of Object.entries(schemaObject(node.dependentSchemas))) {
383
+ const required = schemaObject(branch).required;
384
+ if (Array.isArray(required) && required.every((key) => typeof key === "string")) {
385
+ conditionalRequirements.push({ path, condition: { required: [key] }, required });
386
+ }
387
+ }
388
+ for (const [branch, condition] of [
389
+ [node.then, node.if],
390
+ [node.else, node.if ? { not: node.if } : undefined],
391
+ ]) {
392
+ const required = schemaObject(branch).required;
393
+ if (condition && Array.isArray(required) && required.every((key) => typeof key === "string")) {
394
+ conditionalRequirements.push({ path, condition, required });
395
+ }
396
+ }
397
+ for (const [key, child] of Object.entries(schemaObject(node.properties)))
398
+ visit(child, `${path === "/" ? "" : path}/${encodePointerPart(key)}`, depth + 1);
399
+ // Alternatives can make a dependency branch-specific. Do not state its
400
+ // requirements without proving the complete branch condition.
401
+ for (const key of ["allOf"]) {
402
+ if (Array.isArray(node[key]))
403
+ for (const child of node[key])
404
+ visit(child, path, depth + 1);
405
+ }
406
+ };
407
+ visit(schema, "/", 0);
408
+ let example;
409
+ let valid = false;
410
+ try {
411
+ // Serialization makes the validation cover exactly what the agent receives.
412
+ example = JSON.parse(JSON.stringify(exampleCandidate(schema, schema)));
413
+ valid = validator.validate(example).valid;
414
+ if (valid) {
415
+ minimizeExample(example, validator);
416
+ valid = validator.validate(example).valid;
417
+ }
418
+ }
419
+ catch {
420
+ valid = false;
421
+ // Unsatisfiable or complex schemas do not get a made-up valid example.
422
+ }
423
+ return {
424
+ ...(root.properties ? { acceptedKeys: keys(root) } : {}),
425
+ issues,
426
+ ...(conditionalRequirements.length ? { conditionalRequirements } : {}),
427
+ ...(valid
428
+ ? { example }
429
+ : { exampleUnavailable: "No valid example could be synthesized. Inspect the published inputSchema." }),
430
+ ...(units.length > MAX_ARGUMENT_VALIDATION_ISSUES ? { truncated: true } : {}),
184
431
  };
185
432
  }
186
433
  function unevaluableSchema(address) {
@@ -191,9 +438,15 @@ function unusableSchema(address, detail) {
191
438
  `(${detail}) — fix the schema or drop it; a schema that cannot be ` +
192
439
  "enforced must not ship as one that can.");
193
440
  }
194
- function disableValidation(schema, address, logger, err) {
441
+ /**
442
+ * The validator's account of an unusable schema quotes the schema (an
443
+ * unresolvable `$ref`, an invalid `pattern`), and a downstream wrote that
444
+ * schema, so the log records only the tool's catalog entry and the error's
445
+ * class.
446
+ */
447
+ function disableValidation(schema, subject, logger, err) {
195
448
  validators.set(schema, null);
196
- logger.warn(`[connecta] tool "${address}" has an inputSchema the validator cannot use (${err instanceof Error ? err.message : String(err)}) — arguments are not validated`);
449
+ logFailure(logger, "input schema unusable; arguments are not validated", failureRecord(subject, err));
197
450
  }
198
451
  /**
199
452
  * Validate call arguments against a tool's JSON Schema.
@@ -221,6 +474,14 @@ function disableValidation(schema, address, logger, err) {
221
474
  * the `Connector` interface directly.
222
475
  */
223
476
  export function validateToolInput(schema, args, opts) {
477
+ return validateCatalogToolInput(schema, args, opts, {});
478
+ }
479
+ /**
480
+ * `validateToolInput` for a tool connecta resolved in a catalog. `subject`
481
+ * names it in the log record when the schema is unusable; a caller's own
482
+ * address never reaches the log.
483
+ */
484
+ export function validateCatalogToolInput(schema, args, opts, subject) {
224
485
  const logger = opts.logger ?? console;
225
486
  let validator = validators.get(schema);
226
487
  if (validator === undefined) {
@@ -229,7 +490,7 @@ export function validateToolInput(schema, args, opts) {
229
490
  validators.set(schema, validator);
230
491
  }
231
492
  catch (err) {
232
- disableValidation(schema, opts.address, logger, err);
493
+ disableValidation(schema, subject, logger, err);
233
494
  validator = null;
234
495
  }
235
496
  }
@@ -244,17 +505,18 @@ export function validateToolInput(schema, args, opts) {
244
505
  }
245
506
  catch (err) {
246
507
  // e.g. an unresolvable $ref — surfaces on first validate, not compile.
247
- disableValidation(schema, opts.address, logger, err);
508
+ disableValidation(schema, subject, logger, err);
248
509
  return opts.failClosed ? unevaluableSchema(opts.address) : null;
249
510
  }
250
511
  if (result && !result.valid) {
251
512
  const units = normalizedValidationUnits(schema, result.errors);
252
513
  const nestedUnits = units.filter((unit) => unit.instanceLocation !== "#");
253
- const detail = boundedEchoText((nestedUnits.length > 0 ? nestedUnits : units)
254
- .slice(0, MAX_ARGUMENT_VALIDATION_ISSUES)
255
- .map((unit) => `${unit.instanceLocation}: ${agentFacingValidationError(unit)}`)
256
- .join("; "), 256);
257
- return new ConnectorCallError("invalid_args", `Invalid arguments for "${opts.address}": ${detail || "input does not match the tool's inputSchema"}`, { validation: validationDetails(schema, units) });
514
+ // Told from the reviewed findings, never the validator's own sentences,
515
+ // which quote the schema's types, enums, and patterns.
516
+ const validation = validationDetails(schema, units);
517
+ const shown = nestedUnits.length > 0 ? validationDetails(schema, nestedUnits) : validation;
518
+ const detail = boundedEchoText(shown.issues.map((issue) => `${issue.path}: expected ${issue.expected} (${issue.code})`).join("; "), 256);
519
+ return new ConnectorCallError("invalid_args", `Invalid arguments for "${opts.address}": ${detail || "input does not match the tool's inputSchema"}`, { validation, repair: repairDetails(schema, args, units, validator) });
258
520
  }
259
521
  return null;
260
522
  }
package/dist/version.d.ts CHANGED
@@ -1,7 +1 @@
1
- /**
2
- * The package version, as a Workers-safe constant — no filesystem read, no
3
- * import assertion. `test/version.test.ts` asserts it matches package.json, so
4
- * a bump that forgets this file fails the build rather than shipping a stale
5
- * version to `/health` and to downstream MCP handshakes.
6
- */
7
- export declare const CONNECTA_VERSION = "0.28.1";
1
+ export declare const CONNECTA_VERSION = "0.30.0";
package/dist/version.js CHANGED
@@ -1,7 +1,3 @@
1
- /**
2
- * The package version, as a Workers-safe constant — no filesystem read, no
3
- * import assertion. `test/version.test.ts` asserts it matches package.json, so
4
- * a bump that forgets this file fails the build rather than shipping a stale
5
- * version to `/health` and to downstream MCP handshakes.
6
- */
7
- export const CONNECTA_VERSION = "0.28.1";
1
+ // Generated from package.json by scripts/generate-version.mjs.
2
+ // Workers-safe: no runtime filesystem read or deployment override.
3
+ export const CONNECTA_VERSION = "0.30.0";
@@ -0,0 +1,11 @@
1
+ import { type DynamicWorkerExecutorOptions } from "@cloudflare/codemode";
2
+ import { type AdmissionControllerOptions } from "./executor-admission.js";
3
+ import type { AdmittingExecutor } from "./types.js";
4
+ interface WorkerExecutorOptions {
5
+ loader: DynamicWorkerExecutorOptions["loader"];
6
+ timeout?: number;
7
+ admission?: AdmissionControllerOptions;
8
+ }
9
+ /** Loader-only upstream sandbox whose lease disposes handles at run end. */
10
+ export declare function workerExecutor(options: WorkerExecutorOptions): AdmittingExecutor;
11
+ export {};