@zackbart/connecta 0.28.1 → 0.29.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 (319) hide show
  1. package/CHANGELOG.md +788 -5
  2. package/README.md +62 -42
  3. package/bin/connecta.mjs +110 -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/auth/clerk-sdk/client.d.ts +65 -0
  12. package/dist/auth/clerk-sdk/client.js +5 -0
  13. package/dist/auth/clerk-sdk/generated.js +1845 -0
  14. package/dist/auth/clerk-transport.js +19 -0
  15. package/dist/auth/clerk.d.ts +17 -7
  16. package/dist/auth/clerk.js +189 -107
  17. package/dist/auth/cloudflare-access.js +25 -26
  18. package/dist/auth/downstream-client-metadata.d.ts +29 -0
  19. package/dist/auth/downstream-client-metadata.js +133 -0
  20. package/dist/auth/downstream-oauth.js +1584 -1580
  21. package/dist/auth/downstream-revocation.js +106 -0
  22. package/dist/auth/oauth-token-response.js +231 -0
  23. package/dist/auth/oauth-v2-migration.js +116 -0
  24. package/dist/auth/static-oauth.js +93 -71
  25. package/dist/auth-elicitation.js +283 -0
  26. package/dist/branding.d.ts +8 -16
  27. package/dist/branding.js +26 -59
  28. package/dist/byte-read-response.js +39 -0
  29. package/dist/call-admission.js +12 -16
  30. package/dist/catalog-cache.js +739 -0
  31. package/dist/catalog-drift.d.ts +50 -15
  32. package/dist/catalog-drift.js +365 -128
  33. package/dist/catalog-fingerprint.js +2 -4
  34. package/dist/catalog-freshness.js +13 -0
  35. package/dist/catalog-limits.js +2 -2
  36. package/dist/catalog-service.js +368 -224
  37. package/dist/catalog.js +43 -84
  38. package/dist/concurrency.js +3 -4
  39. package/dist/config-defaults.d.ts +39 -0
  40. package/dist/config-defaults.js +46 -0
  41. package/dist/config-schema.d.ts +181 -0
  42. package/dist/config-schema.js +435 -0
  43. package/dist/config-value-sources.js +102 -0
  44. package/dist/config.d.ts +631 -0
  45. package/dist/config.js +503 -0
  46. package/dist/connector-access.d.ts +1 -0
  47. package/dist/connector-access.js +13 -15
  48. package/dist/connector-caller.d.ts +8 -0
  49. package/dist/connector-caller.js +15 -6
  50. package/dist/connector-scope.js +1 -1
  51. package/dist/connectors/api-connector.d.ts +59 -7
  52. package/dist/connectors/api-connector.js +106 -19
  53. package/dist/connectors/api.js +4 -1
  54. package/dist/connectors/guarded-fetch.d.ts +144 -0
  55. package/dist/connectors/guarded-fetch.js +84 -35
  56. package/dist/connectors/negotiation-cache.js +46 -0
  57. package/dist/connectors/option-shapes.js +27 -0
  58. package/dist/connectors/remote-mcp.d.ts +30 -4
  59. package/dist/connectors/remote-mcp.js +1774 -320
  60. package/dist/connectors/resource-uri.js +335 -0
  61. package/dist/credential-contract.d.ts +10 -0
  62. package/dist/credential-rules.js +1 -3
  63. package/dist/credential-url.js +108 -0
  64. package/dist/credentials.d.ts +6 -1
  65. package/dist/credentials.js +27 -18
  66. package/dist/d1.d.ts +130 -0
  67. package/dist/d1.js +290 -0
  68. package/dist/describe-config.d.ts +165 -0
  69. package/dist/describe-config.js +315 -0
  70. package/dist/described.js +106 -0
  71. package/dist/downstream-input-context.js +119 -0
  72. package/dist/downstream-input.js +323 -0
  73. package/dist/errors.d.ts +97 -20
  74. package/dist/errors.js +158 -80
  75. package/dist/execute.js +453 -305
  76. package/dist/executor-admission.d.ts +1 -0
  77. package/dist/executor-admission.js +11 -15
  78. package/dist/executor-contract.d.ts +20 -0
  79. package/dist/executor-contract.js +48 -0
  80. package/dist/executor-result.js +24 -9
  81. package/dist/executors/quickjs-child.js +3 -4
  82. package/dist/executors/quickjs-runtime.js +147 -59
  83. package/dist/executors/quickjs.js +29 -35
  84. package/dist/favicon.js +1 -2
  85. package/dist/fix-prompt.js +1 -3
  86. package/dist/guest-runtime.js +188 -0
  87. package/dist/guest-types.d.ts +176 -0
  88. package/dist/guest-types.js +1 -0
  89. package/dist/html-security.js +24 -0
  90. package/dist/identity.js +1 -3
  91. package/dist/inbound-credential.js +52 -0
  92. package/dist/index.d.ts +24 -256
  93. package/dist/index.js +65 -478
  94. package/dist/invocation-auth.js +69 -0
  95. package/dist/invocation.js +230 -73
  96. package/dist/json-schema.d.ts +1 -1
  97. package/dist/mcp-client-context.js +35 -0
  98. package/dist/mcp-result.js +11 -7
  99. package/dist/meta-output.js +76 -0
  100. package/dist/meta-tool-names.d.ts +2 -0
  101. package/dist/meta-tool-names.js +3 -0
  102. package/dist/meta-tools.js +285 -209
  103. package/dist/module-contracts.d.ts +8 -23
  104. package/dist/node.d.ts +0 -2
  105. package/dist/node.js +2 -2
  106. package/dist/oauth-callback-outcome.js +1 -3
  107. package/dist/oauth-handoff.js +117 -0
  108. package/dist/oauth-sealing.js +20 -0
  109. package/dist/operator-record.d.ts +137 -0
  110. package/dist/operator-record.js +420 -0
  111. package/dist/operator-ui/assets.js +31 -0
  112. package/dist/operator-ui/contract.d.ts +72 -0
  113. package/dist/operator-ui/contract.js +1 -0
  114. package/dist/operator-ui/fix-prompts.d.ts +18 -0
  115. package/dist/operator-ui/generated.js +5 -4
  116. package/dist/operator-ui/model.d.ts +12 -87
  117. package/dist/operator-ui/model.js +2 -9
  118. package/dist/operator-ui/setup-commands.js +1 -3
  119. package/dist/operator-ui/view.d.ts +323 -0
  120. package/dist/operator-ui/view.js +62 -189
  121. package/dist/page-styles.js +2 -3
  122. package/dist/program-source.js +14 -2
  123. package/dist/{exempt-writes.js → program-writes.js} +55 -18
  124. package/dist/provider.d.ts +142 -0
  125. package/dist/provider.js +187 -0
  126. package/dist/providers/_shared/google/result-size.js +57 -0
  127. package/dist/providers/_shared/google/service-account.d.ts +58 -0
  128. package/dist/providers/_shared/google/service-account.js +500 -0
  129. package/dist/providers/_shared/google/workspace.d.ts +276 -0
  130. package/dist/providers/_shared/google/workspace.js +518 -0
  131. package/dist/providers/{basecamp.d.ts → basecamp/index.d.ts} +6 -28
  132. package/dist/providers/basecamp/index.js +997 -0
  133. package/dist/providers/basecamp/skill.generated.js +9 -0
  134. package/dist/providers/{breeze.d.ts → breeze/index.d.ts} +2 -2
  135. package/dist/providers/{breeze.js → breeze/index.js} +184 -140
  136. package/dist/providers/breeze/skill.generated.js +9 -0
  137. package/dist/providers/{ccb.d.ts → ccb/index.d.ts} +2 -2
  138. package/dist/providers/{ccb.js → ccb/index.js} +271 -116
  139. package/dist/providers/ccb/skill.generated.js +9 -0
  140. package/dist/providers/{cloudflare.d.ts → cloudflare/index.d.ts} +8 -7
  141. package/dist/providers/{cloudflare.js → cloudflare/index.js} +171 -738
  142. package/dist/providers/cloudflare/skill.generated.js +10 -0
  143. package/dist/providers/docs/index.d.ts +54 -0
  144. package/dist/providers/docs/index.js +1237 -0
  145. package/dist/providers/docs/skill.generated.js +9 -0
  146. package/dist/providers/drive/index.d.ts +53 -0
  147. package/dist/providers/drive/index.js +1523 -0
  148. package/dist/providers/drive/skill.generated.js +9 -0
  149. package/dist/providers/forms/index.d.ts +54 -0
  150. package/dist/providers/forms/index.js +1217 -0
  151. package/dist/providers/forms/skill.generated.js +11 -0
  152. package/dist/providers/github/auth.d.ts +32 -0
  153. package/dist/providers/github/auth.js +361 -0
  154. package/dist/providers/github/hosted.js +218 -0
  155. package/dist/providers/github/index.d.ts +13 -0
  156. package/dist/providers/github/index.js +140 -0
  157. package/dist/providers/github/key.js +100 -0
  158. package/dist/providers/github/rest.js +321 -0
  159. package/dist/providers/github/scope.d.ts +29 -0
  160. package/dist/providers/github/scope.js +124 -0
  161. package/dist/providers/github/skill.generated.js +8 -0
  162. package/dist/providers/gmail/index.d.ts +51 -0
  163. package/dist/providers/gmail/index.js +1436 -0
  164. package/dist/providers/gmail/skill.generated.js +9 -0
  165. package/dist/providers/{linear.d.ts → linear/index.d.ts} +11 -14
  166. package/dist/providers/linear/index.js +352 -0
  167. package/dist/providers/linear/skill.generated.js +8 -0
  168. package/dist/providers/{mixpanel.d.ts → mixpanel/index.d.ts} +5 -10
  169. package/dist/providers/mixpanel/index.js +416 -0
  170. package/dist/providers/mixpanel/skill.generated.js +9 -0
  171. package/dist/providers/{notion.d.ts → notion/index.d.ts} +8 -8
  172. package/dist/providers/{notion.js → notion/index.js} +226 -239
  173. package/dist/providers/notion/skill.generated.js +10 -0
  174. package/dist/providers/{overflow.d.ts → overflow/index.d.ts} +2 -2
  175. package/dist/providers/{overflow.js → overflow/index.js} +74 -111
  176. package/dist/providers/overflow/skill.generated.js +8 -0
  177. package/dist/providers/{planning-center.d.ts → planning-center/index.d.ts} +2 -2
  178. package/dist/providers/{planning-center.js → planning-center/index.js} +264 -104
  179. package/dist/providers/planning-center/skill.generated.js +10 -0
  180. package/dist/providers/{revenuecat.d.ts → revenuecat/index.d.ts} +5 -10
  181. package/dist/providers/revenuecat/index.js +557 -0
  182. package/dist/providers/revenuecat/skill.generated.js +11 -0
  183. package/dist/providers/sheets/index.d.ts +54 -0
  184. package/dist/providers/sheets/index.js +1237 -0
  185. package/dist/providers/sheets/skill.generated.js +10 -0
  186. package/dist/providers/slides/index.d.ts +53 -0
  187. package/dist/providers/slides/index.js +2645 -0
  188. package/dist/providers/slides/skill.generated.js +9 -0
  189. package/dist/providers/{stripe.d.ts → stripe/index.d.ts} +5 -12
  190. package/dist/providers/stripe/index.js +266 -0
  191. package/dist/providers/stripe/skill.generated.js +11 -0
  192. package/dist/providers/{tithely.d.ts → tithely/index.d.ts} +2 -2
  193. package/dist/providers/{tithely.js → tithely/index.js} +60 -91
  194. package/dist/providers/tithely/skill.generated.js +8 -0
  195. package/dist/providers/{vercel.d.ts → vercel/index.d.ts} +8 -8
  196. package/dist/providers/vercel/index.js +1038 -0
  197. package/dist/providers/vercel/mcp-ownership.js +212 -0
  198. package/dist/providers/vercel/skill.generated.js +11 -0
  199. package/dist/registry.d.ts +108 -171
  200. package/dist/registry.js +513 -925
  201. package/dist/request-state.js +21 -0
  202. package/dist/resource-read.js +100 -0
  203. package/dist/result-shapes.js +17 -49
  204. package/dist/retired-toolkits.js +1 -1
  205. package/dist/routes/access-tokens.js +3 -6
  206. package/dist/routes/activity-context.js +21 -0
  207. package/dist/routes/activity-disclosure.js +40 -0
  208. package/dist/routes/activity.js +59 -21
  209. package/dist/routes/actor-labels.js +3 -50
  210. package/dist/routes/connect.js +221 -0
  211. package/dist/routes/credentials.js +15 -27
  212. package/dist/routes/mcp.js +356 -130
  213. package/dist/routes/oauth-client-metadata.js +15 -0
  214. package/dist/routes/oauth-management.js +45 -107
  215. package/dist/routes/oauth.js +110 -57
  216. package/dist/routes/operator.js +3 -3
  217. package/dist/routes/shared.d.ts +25 -64
  218. package/dist/routes/shared.js +160 -80
  219. package/dist/routes/skills.js +30 -0
  220. package/dist/routes/ui-config.js +225 -0
  221. package/dist/routes/ui-data.js +40 -35
  222. package/dist/routes/ui.js +66 -56
  223. package/dist/runtime/admission.js +4 -2
  224. package/dist/runtime/call-admission.js +3 -1
  225. package/dist/runtime/connector-scope.js +1 -4
  226. package/dist/runtime/run.js +10 -39
  227. package/dist/runtime/services.js +12 -117
  228. package/dist/runtime/shared-read.js +1 -3
  229. package/dist/runtime/storage.js +8 -1
  230. package/dist/sent-secrets.d.ts +52 -0
  231. package/dist/sent-secrets.js +474 -0
  232. package/dist/server.js +28 -71
  233. package/dist/skills.js +406 -174
  234. package/dist/sqlite.d.ts +48 -0
  235. package/dist/sqlite.js +166 -0
  236. package/dist/storage/keys.js +428 -0
  237. package/dist/storage/memory.js +7 -0
  238. package/dist/storage/sql.d.ts +66 -0
  239. package/dist/storage/sql.js +534 -0
  240. package/dist/timeout.js +4 -2
  241. package/dist/tool-name.js +17 -0
  242. package/dist/tool-safety.d.ts +9 -35
  243. package/dist/tool-safety.js +20 -40
  244. package/dist/types.d.ts +320 -54
  245. package/dist/types.js +0 -1
  246. package/dist/ui.d.ts +7 -19
  247. package/dist/ui.js +76 -90
  248. package/dist/url-safety.js +3 -6
  249. package/dist/usage-guide.js +137 -0
  250. package/dist/validate.d.ts +7 -0
  251. package/dist/validate.js +309 -47
  252. package/dist/version.d.ts +1 -7
  253. package/dist/version.js +3 -7
  254. package/dist/worker.d.ts +11 -0
  255. package/dist/worker.js +434 -0
  256. package/documentation/architecture.md +664 -231
  257. package/documentation/auth.md +936 -546
  258. package/documentation/code-mode.md +501 -312
  259. package/documentation/meta-tools.md +449 -200
  260. package/documentation/operator-tests.md +93 -0
  261. package/documentation/provider-migration-0.29.md +60 -0
  262. package/examples/worker/AGENTS.md +34 -12
  263. package/examples/worker/README.md +286 -255
  264. package/examples/worker/kv-to-d1.wrangler.jsonc +26 -0
  265. package/examples/worker/scripts/copy-kv-to-d1.mjs +162 -0
  266. package/examples/worker/src/connecta.config.ts +151 -0
  267. package/examples/worker/src/index.ts +14 -197
  268. package/examples/worker/wrangler.jsonc +15 -35
  269. package/package.json +120 -54
  270. package/templates/node/.dockerignore +1 -2
  271. package/templates/node/.env.example +20 -21
  272. package/templates/node/AGENTS.md +21 -17
  273. package/templates/node/Dockerfile +3 -5
  274. package/templates/node/README.md +133 -58
  275. package/templates/node/docker-compose.yml +11 -12
  276. package/templates/node/package.json +4 -2
  277. package/templates/node/src/connecta.config.ts +119 -0
  278. package/templates/node/src/index.ts +9 -154
  279. package/templates/node/src/provision-token.ts +17 -0
  280. package/AGENTS.md +0 -170
  281. package/dist/artifacts/connector.d.ts +0 -58
  282. package/dist/artifacts/connector.js +0 -730
  283. package/dist/artifacts/document.js +0 -86
  284. package/dist/artifacts/guide.js +0 -140
  285. package/dist/artifacts/html-scan.js +0 -329
  286. package/dist/artifacts/json.js +0 -78
  287. package/dist/artifacts/kv-store.d.ts +0 -20
  288. package/dist/artifacts/kv-store.js +0 -140
  289. package/dist/artifacts/markdown.js +0 -478
  290. package/dist/artifacts/module.d.ts +0 -37
  291. package/dist/artifacts/module.js +0 -66
  292. package/dist/artifacts/operations.d.ts +0 -197
  293. package/dist/artifacts/operations.js +0 -1002
  294. package/dist/artifacts/refresh.d.ts +0 -55
  295. package/dist/artifacts/refresh.js +0 -236
  296. package/dist/artifacts/routes.js +0 -206
  297. package/dist/artifacts/types.d.ts +0 -214
  298. package/dist/artifacts/types.js +0 -22
  299. package/dist/artifacts/validate.d.ts +0 -62
  300. package/dist/artifacts/validate.js +0 -651
  301. package/dist/artifacts.d.ts +0 -6
  302. package/dist/artifacts.js +0 -9
  303. package/dist/auth/bearer.d.ts +0 -11
  304. package/dist/auth/bearer.js +0 -50
  305. package/dist/providers/basecamp.js +0 -445
  306. package/dist/providers/linear.js +0 -217
  307. package/dist/providers/mixpanel.js +0 -247
  308. package/dist/providers/revenuecat.js +0 -317
  309. package/dist/providers/stripe.js +0 -253
  310. package/dist/providers/vercel.js +0 -1253
  311. package/dist/storage/file.d.ts +0 -15
  312. package/dist/storage/file.js +0 -455
  313. package/ethos.md +0 -93
  314. package/examples/worker/src/cloudflare-kv.ts +0 -43
  315. package/examples/worker/src/d1-activity-row.ts +0 -155
  316. package/examples/worker/src/d1-activity.ts +0 -147
  317. package/examples/worker/src/d1-storage.ts +0 -138
  318. package/examples/worker/src/r2-artifact-blobs.ts +0 -29
  319. 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.29.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.29.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 {};