@zackbart/connecta 0.14.2 → 0.15.1

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 (54) hide show
  1. package/CHANGELOG.md +89 -0
  2. package/dist/catalog-service.d.ts.map +1 -1
  3. package/dist/catalog-service.js +104 -56
  4. package/dist/catalog-service.js.map +1 -1
  5. package/dist/catalog.d.ts +8 -2
  6. package/dist/catalog.d.ts.map +1 -1
  7. package/dist/catalog.js +58 -9
  8. package/dist/catalog.js.map +1 -1
  9. package/dist/connectors/api.d.ts +4 -4
  10. package/dist/connectors/api.js +4 -4
  11. package/dist/execute.d.ts.map +1 -1
  12. package/dist/execute.js +8 -7
  13. package/dist/execute.js.map +1 -1
  14. package/dist/meta-tools.js +1 -1
  15. package/dist/meta-tools.js.map +1 -1
  16. package/dist/providers/cloudflare.d.ts +5 -1
  17. package/dist/providers/cloudflare.d.ts.map +1 -1
  18. package/dist/providers/cloudflare.js +203 -70
  19. package/dist/providers/cloudflare.js.map +1 -1
  20. package/dist/providers/linear.d.ts.map +1 -1
  21. package/dist/providers/linear.js +4 -3
  22. package/dist/providers/linear.js.map +1 -1
  23. package/dist/providers/mixpanel.d.ts.map +1 -1
  24. package/dist/providers/mixpanel.js +4 -3
  25. package/dist/providers/mixpanel.js.map +1 -1
  26. package/dist/providers/stripe.d.ts.map +1 -1
  27. package/dist/providers/stripe.js +4 -3
  28. package/dist/providers/stripe.js.map +1 -1
  29. package/dist/validate.d.ts.map +1 -1
  30. package/dist/validate.js +97 -17
  31. package/dist/validate.js.map +1 -1
  32. package/dist/version.d.ts +1 -1
  33. package/dist/version.js +1 -1
  34. package/documentation/cloudflare.md +37 -19
  35. package/documentation/code-mode.md +9 -9
  36. package/documentation/connectors.md +9 -7
  37. package/documentation/linear.md +6 -7
  38. package/documentation/meta-tools.md +56 -13
  39. package/documentation/mixpanel.md +6 -7
  40. package/documentation/stripe.md +12 -12
  41. package/ethos.md +2 -1
  42. package/package.json +1 -1
  43. package/src/catalog-service.ts +93 -29
  44. package/src/catalog.ts +71 -8
  45. package/src/connectors/api.ts +4 -4
  46. package/src/execute.ts +8 -7
  47. package/src/meta-tools.ts +1 -1
  48. package/src/providers/cloudflare.ts +275 -79
  49. package/src/providers/linear.ts +4 -3
  50. package/src/providers/mixpanel.ts +4 -3
  51. package/src/providers/stripe.ts +4 -3
  52. package/src/validate.ts +125 -20
  53. package/src/version.ts +1 -1
  54. package/templates/node/package.json +1 -1
package/src/validate.ts CHANGED
@@ -57,6 +57,18 @@ interface ValidationUnit {
57
57
  error: string;
58
58
  }
59
59
 
60
+ const CONTAINER_VALIDATION_KEYWORDS = new Set([
61
+ "properties",
62
+ "items",
63
+ "allOf",
64
+ "anyOf",
65
+ "oneOf",
66
+ "if",
67
+ "not",
68
+ "patternProperties",
69
+ "additionalProperties",
70
+ ]);
71
+
60
72
  function decodePointerPart(value: string): string {
61
73
  return value.replaceAll("~1", "/").replaceAll("~0", "~");
62
74
  }
@@ -81,6 +93,110 @@ function argumentPath(location: string): string {
81
93
  return location.startsWith("#") ? location.slice(1) || "/" : "/";
82
94
  }
83
95
 
96
+ function validationUnitKey(unit: ValidationUnit): string {
97
+ return JSON.stringify([
98
+ unit.keyword,
99
+ unit.keywordLocation,
100
+ unit.instanceLocation,
101
+ unit.error,
102
+ ]);
103
+ }
104
+
105
+ function childPropertyName(
106
+ parentLocation: string,
107
+ childLocation: string,
108
+ ): string | undefined {
109
+ const prefix = parentLocation === "#" ? "#/" : `${parentLocation}/`;
110
+ if (!childLocation.startsWith(prefix)) return undefined;
111
+ const encoded = childLocation.slice(prefix.length);
112
+ return !encoded.includes("/") ? decodePointerPart(encoded) : undefined;
113
+ }
114
+
115
+ function schemaDeclaresProperty(schema: unknown, property: string): boolean {
116
+ if (schema === null || typeof schema !== "object" || Array.isArray(schema)) {
117
+ return false;
118
+ }
119
+ const record = schema as Record<string, unknown>;
120
+ const properties = record.properties;
121
+ if (
122
+ properties !== null &&
123
+ typeof properties === "object" &&
124
+ !Array.isArray(properties) &&
125
+ Object.hasOwn(properties, property)
126
+ ) {
127
+ return true;
128
+ }
129
+ const patterns = record.patternProperties;
130
+ if (
131
+ patterns === null ||
132
+ typeof patterns !== "object" ||
133
+ Array.isArray(patterns)
134
+ ) {
135
+ return false;
136
+ }
137
+ for (const pattern of Object.keys(patterns)) {
138
+ try {
139
+ if (new RegExp(pattern).test(property)) return true;
140
+ } catch {
141
+ // The validator owns schema support. An unusable pattern cannot prove
142
+ // that this additional-properties branch is a duplicate.
143
+ }
144
+ }
145
+ return false;
146
+ }
147
+
148
+ function isDuplicateAdditionalPropertiesBranch(
149
+ schema: JsonSchema,
150
+ units: ValidationUnit[],
151
+ index: number,
152
+ ): boolean {
153
+ const unit = units[index];
154
+ const wrapper = units[index - 1];
155
+ if (
156
+ unit?.keyword !== "false" ||
157
+ wrapper?.keyword !== "additionalProperties" ||
158
+ !wrapper.keywordLocation.endsWith("/additionalProperties")
159
+ ) {
160
+ return false;
161
+ }
162
+ const property = childPropertyName(
163
+ wrapper.instanceLocation,
164
+ unit.instanceLocation,
165
+ );
166
+ if (property === undefined) return false;
167
+ const parentSchemaLocation = wrapper.keywordLocation.slice(
168
+ 0,
169
+ -"/additionalProperties".length,
170
+ );
171
+ return schemaDeclaresProperty(
172
+ pointerValue(schema, parentSchemaLocation || "#"),
173
+ property,
174
+ );
175
+ }
176
+
177
+ function normalizedValidationUnits(
178
+ schema: JsonSchema,
179
+ units: ValidationUnit[],
180
+ ): ValidationUnit[] {
181
+ const seen = new Set<string>();
182
+ return units.filter((unit, index) => {
183
+ if (CONTAINER_VALIDATION_KEYWORDS.has(unit.keyword)) return false;
184
+ if (isDuplicateAdditionalPropertiesBranch(schema, units, index)) {
185
+ return false;
186
+ }
187
+ const key = validationUnitKey(unit);
188
+ if (seen.has(key)) return false;
189
+ seen.add(key);
190
+ return true;
191
+ });
192
+ }
193
+
194
+ function agentFacingValidationError(unit: ValidationUnit): string {
195
+ return unit.keyword === "false"
196
+ ? "Value is not allowed by the declared schema."
197
+ : unit.error;
198
+ }
199
+
84
200
  function expectedType(schema: JsonSchema, unit: ValidationUnit): string | undefined {
85
201
  if (unit.keyword === "type") {
86
202
  const value = pointerValue(schema, unit.keywordLocation);
@@ -120,22 +236,8 @@ function validationDetails(
120
236
  schema: JsonSchema,
121
237
  units: ValidationUnit[],
122
238
  ): ArgumentValidationDetails {
123
- const leafUnits = units.filter(
124
- (unit) =>
125
- ![
126
- "properties",
127
- "items",
128
- "allOf",
129
- "anyOf",
130
- "oneOf",
131
- "if",
132
- "not",
133
- "patternProperties",
134
- "additionalProperties",
135
- ].includes(unit.keyword),
136
- );
137
239
  const issues: ArgumentValidationIssue[] = [];
138
- for (const unit of leafUnits) {
240
+ for (const unit of units) {
139
241
  const missing =
140
242
  unit.keyword === "required"
141
243
  ? REQUIRED_PROPERTY_RE.exec(unit.error)?.[1]
@@ -246,15 +348,18 @@ export function validateToolInput(
246
348
  return opts.failClosed ? unevaluableSchema(opts.address) : null;
247
349
  }
248
350
  if (result && !result.valid) {
249
- const units = result.errors.filter((u) => u.instanceLocation !== "#");
250
- const detail = (units.length > 0 ? units : result.errors)
251
- .slice(0, 3)
252
- .map((u) => `${u.instanceLocation}: ${u.error}`)
351
+ const units = normalizedValidationUnits(schema, result.errors);
352
+ const nestedUnits = units.filter((unit) => unit.instanceLocation !== "#");
353
+ const detail = (nestedUnits.length > 0 ? nestedUnits : units)
354
+ .slice(0, MAX_ARGUMENT_VALIDATION_ISSUES)
355
+ .map((unit) =>
356
+ `${unit.instanceLocation}: ${agentFacingValidationError(unit)}`,
357
+ )
253
358
  .join("; ");
254
359
  return new ConnectorCallError(
255
360
  "invalid_args",
256
361
  `Invalid arguments for "${opts.address}": ${detail || "input does not match the tool's inputSchema"}`,
257
- { validation: validationDetails(schema, result.errors) },
362
+ { validation: validationDetails(schema, units) },
258
363
  );
259
364
  }
260
365
  return null;
package/src/version.ts CHANGED
@@ -4,4 +4,4 @@
4
4
  * a bump that forgets this file fails the build rather than shipping a stale
5
5
  * version to `/health` and to downstream MCP handshakes.
6
6
  */
7
- export const CONNECTA_VERSION = "0.14.2";
7
+ export const CONNECTA_VERSION = "0.15.1";
@@ -12,7 +12,7 @@
12
12
  "typecheck": "tsc --noEmit"
13
13
  },
14
14
  "dependencies": {
15
- "@zackbart/connecta": "0.14.2",
15
+ "@zackbart/connecta": "0.15.1",
16
16
  "quickjs-emscripten": "0.32.0"
17
17
  },
18
18
  "devDependencies": {