@zackbart/connecta 0.28.0 → 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.
- package/CHANGELOG.md +961 -5
- package/README.md +62 -39
- package/bin/connecta.mjs +110 -139
- package/bin/meta-tool-names.d.mts +2 -0
- package/bin/meta-tool-names.mjs +9 -0
- package/bin/version.mjs +3 -0
- package/dist/access-tokens.js +53 -63
- package/dist/activity-request.js +8 -0
- package/dist/activity.d.ts +76 -42
- package/dist/activity.js +110 -42
- package/dist/auth/clerk-sdk/client.d.ts +65 -0
- package/dist/auth/clerk-sdk/client.js +5 -0
- package/dist/auth/clerk-sdk/generated.js +1845 -0
- package/dist/auth/clerk-transport.js +19 -0
- package/dist/auth/clerk.d.ts +17 -7
- package/dist/auth/clerk.js +189 -107
- package/dist/auth/cloudflare-access.js +25 -26
- package/dist/auth/downstream-client-metadata.d.ts +29 -0
- package/dist/auth/downstream-client-metadata.js +133 -0
- package/dist/auth/downstream-oauth.js +1632 -1509
- package/dist/auth/downstream-revocation.js +106 -0
- package/dist/auth/oauth-token-response.js +231 -0
- package/dist/auth/oauth-v2-migration.js +116 -0
- package/dist/auth/static-oauth.js +526 -0
- package/dist/auth-elicitation.js +283 -0
- package/dist/branding.d.ts +8 -16
- package/dist/branding.js +26 -59
- package/dist/byte-read-response.js +39 -0
- package/dist/call-admission.js +12 -16
- package/dist/catalog-cache.js +739 -0
- package/dist/catalog-drift.d.ts +50 -15
- package/dist/catalog-drift.js +365 -128
- package/dist/catalog-fingerprint.js +2 -4
- package/dist/catalog-freshness.js +13 -0
- package/dist/catalog-limits.js +2 -2
- package/dist/catalog-service.js +368 -224
- package/dist/catalog.js +43 -84
- package/dist/concurrency.js +3 -4
- package/dist/config-defaults.d.ts +39 -0
- package/dist/config-defaults.js +46 -0
- package/dist/config-schema.d.ts +181 -0
- package/dist/config-schema.js +435 -0
- package/dist/config-value-sources.js +102 -0
- package/dist/config.d.ts +631 -0
- package/dist/config.js +503 -0
- package/dist/connector-access.d.ts +1 -0
- package/dist/connector-access.js +13 -15
- package/dist/connector-caller.d.ts +8 -0
- package/dist/connector-caller.js +15 -6
- package/dist/connector-scope.js +1 -1
- package/dist/connectors/api-connector.d.ts +220 -0
- package/dist/connectors/api-connector.js +214 -0
- package/dist/connectors/api.d.ts +8 -71
- package/dist/connectors/api.js +13 -99
- package/dist/connectors/guarded-fetch.d.ts +144 -0
- package/dist/connectors/guarded-fetch.js +108 -25
- package/dist/connectors/negotiation-cache.js +46 -0
- package/dist/connectors/option-shapes.js +27 -0
- package/dist/connectors/remote-mcp.d.ts +30 -4
- package/dist/connectors/remote-mcp.js +1780 -351
- package/dist/connectors/resource-uri.js +335 -0
- package/dist/credential-contract.d.ts +10 -0
- package/dist/credential-rules.js +1 -3
- package/dist/credential-url.js +108 -0
- package/dist/credentials.d.ts +6 -1
- package/dist/credentials.js +27 -18
- package/dist/d1.d.ts +130 -0
- package/dist/d1.js +290 -0
- package/dist/describe-config.d.ts +165 -0
- package/dist/describe-config.js +315 -0
- package/dist/described.js +106 -0
- package/dist/downstream-input-context.js +119 -0
- package/dist/downstream-input.js +323 -0
- package/dist/errors.d.ts +97 -20
- package/dist/errors.js +158 -80
- package/dist/execute.js +453 -305
- package/dist/executor-admission.d.ts +1 -0
- package/dist/executor-admission.js +11 -15
- package/dist/executor-contract.d.ts +20 -0
- package/dist/executor-contract.js +48 -0
- package/dist/executor-result.js +24 -9
- package/dist/executors/quickjs-child.js +3 -4
- package/dist/executors/quickjs-runtime.js +147 -59
- package/dist/executors/quickjs.js +29 -35
- package/dist/favicon.js +1 -2
- package/dist/fix-prompt.js +1 -3
- package/dist/guest-runtime.js +188 -0
- package/dist/guest-types.d.ts +176 -0
- package/dist/guest-types.js +1 -0
- package/dist/html-security.js +24 -0
- package/dist/identity.js +1 -3
- package/dist/inbound-credential.js +52 -0
- package/dist/index.d.ts +25 -257
- package/dist/index.js +65 -478
- package/dist/invocation-auth.js +69 -0
- package/dist/invocation.js +230 -73
- package/dist/json-schema.d.ts +1 -1
- package/dist/mcp-client-context.js +35 -0
- package/dist/mcp-result.js +11 -7
- package/dist/meta-output.js +76 -0
- package/dist/meta-tool-names.d.ts +2 -0
- package/dist/meta-tool-names.js +3 -0
- package/dist/meta-tools.js +285 -209
- package/dist/module-contracts.d.ts +8 -23
- package/dist/node.d.ts +0 -2
- package/dist/node.js +2 -2
- package/dist/oauth-callback-outcome.js +1 -3
- package/dist/oauth-handoff.js +117 -0
- package/dist/oauth-partition.js +17 -0
- package/dist/oauth-sealing.js +20 -0
- package/dist/operator-record.d.ts +137 -0
- package/dist/operator-record.js +420 -0
- package/dist/operator-ui/assets.js +31 -0
- package/dist/operator-ui/contract.d.ts +72 -0
- package/dist/operator-ui/contract.js +1 -0
- package/dist/operator-ui/fix-prompts.d.ts +18 -0
- package/dist/operator-ui/generated.js +5 -4
- package/dist/operator-ui/model.d.ts +12 -87
- package/dist/operator-ui/model.js +2 -9
- package/dist/operator-ui/setup-commands.js +1 -3
- package/dist/operator-ui/view.d.ts +323 -0
- package/dist/operator-ui/view.js +62 -189
- package/dist/page-styles.js +2 -3
- package/dist/program-source.js +14 -2
- package/dist/{exempt-writes.js → program-writes.js} +55 -18
- package/dist/provider.d.ts +142 -0
- package/dist/provider.js +187 -0
- package/dist/providers/_shared/google/result-size.js +57 -0
- package/dist/providers/_shared/google/service-account.d.ts +58 -0
- package/dist/providers/_shared/google/service-account.js +500 -0
- package/dist/providers/_shared/google/workspace.d.ts +276 -0
- package/dist/providers/_shared/google/workspace.js +518 -0
- package/dist/providers/basecamp/index.d.ts +43 -0
- package/dist/providers/basecamp/index.js +997 -0
- package/dist/providers/basecamp/skill.generated.js +9 -0
- package/dist/providers/breeze/index.d.ts +34 -0
- package/dist/providers/breeze/index.js +1446 -0
- package/dist/providers/breeze/skill.generated.js +9 -0
- package/dist/providers/ccb/index.d.ts +103 -0
- package/dist/providers/ccb/index.js +1725 -0
- package/dist/providers/ccb/skill.generated.js +9 -0
- package/dist/providers/{cloudflare.d.ts → cloudflare/index.d.ts} +8 -7
- package/dist/providers/{cloudflare.js → cloudflare/index.js} +171 -738
- package/dist/providers/cloudflare/skill.generated.js +10 -0
- package/dist/providers/docs/index.d.ts +54 -0
- package/dist/providers/docs/index.js +1237 -0
- package/dist/providers/docs/skill.generated.js +9 -0
- package/dist/providers/drive/index.d.ts +53 -0
- package/dist/providers/drive/index.js +1523 -0
- package/dist/providers/drive/skill.generated.js +9 -0
- package/dist/providers/forms/index.d.ts +54 -0
- package/dist/providers/forms/index.js +1217 -0
- package/dist/providers/forms/skill.generated.js +11 -0
- package/dist/providers/github/auth.d.ts +32 -0
- package/dist/providers/github/auth.js +361 -0
- package/dist/providers/github/hosted.js +218 -0
- package/dist/providers/github/index.d.ts +13 -0
- package/dist/providers/github/index.js +140 -0
- package/dist/providers/github/key.js +100 -0
- package/dist/providers/github/rest.js +321 -0
- package/dist/providers/github/scope.d.ts +29 -0
- package/dist/providers/github/scope.js +124 -0
- package/dist/providers/github/skill.generated.js +8 -0
- package/dist/providers/gmail/index.d.ts +51 -0
- package/dist/providers/gmail/index.js +1436 -0
- package/dist/providers/gmail/skill.generated.js +9 -0
- package/dist/providers/{linear.d.ts → linear/index.d.ts} +11 -14
- package/dist/providers/linear/index.js +352 -0
- package/dist/providers/linear/skill.generated.js +8 -0
- package/dist/providers/{mixpanel.d.ts → mixpanel/index.d.ts} +5 -10
- package/dist/providers/mixpanel/index.js +416 -0
- package/dist/providers/mixpanel/skill.generated.js +9 -0
- package/dist/providers/{notion.d.ts → notion/index.d.ts} +8 -8
- package/dist/providers/{notion.js → notion/index.js} +226 -239
- package/dist/providers/notion/skill.generated.js +10 -0
- package/dist/providers/overflow/index.d.ts +60 -0
- package/dist/providers/overflow/index.js +1535 -0
- package/dist/providers/overflow/skill.generated.js +8 -0
- package/dist/providers/planning-center/index.d.ts +59 -0
- package/dist/providers/planning-center/index.js +2199 -0
- package/dist/providers/planning-center/skill.generated.js +10 -0
- package/dist/providers/{revenuecat.d.ts → revenuecat/index.d.ts} +5 -10
- package/dist/providers/revenuecat/index.js +557 -0
- package/dist/providers/revenuecat/skill.generated.js +11 -0
- package/dist/providers/sheets/index.d.ts +54 -0
- package/dist/providers/sheets/index.js +1237 -0
- package/dist/providers/sheets/skill.generated.js +10 -0
- package/dist/providers/slides/index.d.ts +53 -0
- package/dist/providers/slides/index.js +2645 -0
- package/dist/providers/slides/skill.generated.js +9 -0
- package/dist/providers/{stripe.d.ts → stripe/index.d.ts} +5 -12
- package/dist/providers/stripe/index.js +266 -0
- package/dist/providers/stripe/skill.generated.js +11 -0
- package/dist/providers/tithely/index.d.ts +49 -0
- package/dist/providers/tithely/index.js +1003 -0
- package/dist/providers/tithely/skill.generated.js +8 -0
- package/dist/providers/{vercel.d.ts → vercel/index.d.ts} +8 -8
- package/dist/providers/vercel/index.js +1038 -0
- package/dist/providers/vercel/mcp-ownership.js +212 -0
- package/dist/providers/vercel/skill.generated.js +11 -0
- package/dist/registry.d.ts +108 -171
- package/dist/registry.js +513 -925
- package/dist/request-state.js +21 -0
- package/dist/resource-read.js +100 -0
- package/dist/result-shapes.js +17 -49
- package/dist/retired-toolkits.js +1 -1
- package/dist/routes/access-tokens.js +3 -6
- package/dist/routes/activity-context.js +21 -0
- package/dist/routes/activity-disclosure.js +40 -0
- package/dist/routes/activity.js +59 -21
- package/dist/routes/actor-labels.js +3 -50
- package/dist/routes/connect.js +221 -0
- package/dist/routes/credentials.js +15 -27
- package/dist/routes/mcp.js +356 -130
- package/dist/routes/oauth-client-metadata.js +15 -0
- package/dist/routes/oauth-management.js +45 -107
- package/dist/routes/oauth.js +136 -57
- package/dist/routes/operator.js +3 -3
- package/dist/routes/shared.d.ts +25 -64
- package/dist/routes/shared.js +160 -80
- package/dist/routes/skills.js +30 -0
- package/dist/routes/ui-config.js +225 -0
- package/dist/routes/ui-data.js +40 -35
- package/dist/routes/ui.js +66 -56
- package/dist/runtime/admission.js +4 -2
- package/dist/runtime/call-admission.js +3 -1
- package/dist/runtime/connector-scope.js +1 -4
- package/dist/runtime/run.js +10 -39
- package/dist/runtime/services.js +12 -117
- package/dist/runtime/shared-read.js +1 -3
- package/dist/runtime/storage.js +8 -1
- package/dist/sent-secrets.d.ts +52 -0
- package/dist/sent-secrets.js +474 -0
- package/dist/server.js +28 -71
- package/dist/skills.js +406 -174
- package/dist/sqlite.d.ts +48 -0
- package/dist/sqlite.js +166 -0
- package/dist/storage/keys.js +428 -0
- package/dist/storage/memory.js +7 -0
- package/dist/storage/sql.d.ts +66 -0
- package/dist/storage/sql.js +534 -0
- package/dist/timeout.js +4 -2
- package/dist/tool-name.js +17 -0
- package/dist/tool-safety.d.ts +9 -35
- package/dist/tool-safety.js +20 -40
- package/dist/types.d.ts +320 -54
- package/dist/types.js +0 -1
- package/dist/ui.d.ts +7 -19
- package/dist/ui.js +76 -90
- package/dist/url-safety.js +3 -6
- package/dist/usage-guide.js +137 -0
- package/dist/validate.d.ts +7 -0
- package/dist/validate.js +309 -47
- package/dist/version.d.ts +1 -7
- package/dist/version.js +3 -7
- package/dist/worker.d.ts +11 -0
- package/dist/worker.js +434 -0
- package/documentation/architecture.md +665 -230
- package/documentation/auth.md +962 -458
- package/documentation/code-mode.md +501 -312
- package/documentation/meta-tools.md +449 -200
- package/documentation/operator-tests.md +93 -0
- package/documentation/provider-migration-0.29.md +60 -0
- package/examples/worker/AGENTS.md +34 -12
- package/examples/worker/README.md +286 -255
- package/examples/worker/kv-to-d1.wrangler.jsonc +26 -0
- package/examples/worker/scripts/copy-kv-to-d1.mjs +162 -0
- package/examples/worker/src/connecta.config.ts +151 -0
- package/examples/worker/src/index.ts +14 -197
- package/examples/worker/wrangler.jsonc +15 -35
- package/package.json +125 -35
- package/templates/node/.dockerignore +1 -2
- package/templates/node/.env.example +20 -21
- package/templates/node/AGENTS.md +21 -17
- package/templates/node/Dockerfile +3 -5
- package/templates/node/README.md +133 -58
- package/templates/node/docker-compose.yml +11 -12
- package/templates/node/package.json +4 -2
- package/templates/node/src/connecta.config.ts +119 -0
- package/templates/node/src/index.ts +9 -154
- package/templates/node/src/provision-token.ts +17 -0
- package/AGENTS.md +0 -170
- package/dist/artifacts/connector.d.ts +0 -58
- package/dist/artifacts/connector.js +0 -730
- package/dist/artifacts/document.js +0 -86
- package/dist/artifacts/guide.js +0 -140
- package/dist/artifacts/html-scan.js +0 -329
- package/dist/artifacts/json.js +0 -78
- package/dist/artifacts/kv-store.d.ts +0 -20
- package/dist/artifacts/kv-store.js +0 -140
- package/dist/artifacts/markdown.js +0 -478
- package/dist/artifacts/module.d.ts +0 -37
- package/dist/artifacts/module.js +0 -66
- package/dist/artifacts/operations.d.ts +0 -197
- package/dist/artifacts/operations.js +0 -1002
- package/dist/artifacts/refresh.d.ts +0 -55
- package/dist/artifacts/refresh.js +0 -236
- package/dist/artifacts/routes.js +0 -206
- package/dist/artifacts/types.d.ts +0 -214
- package/dist/artifacts/types.js +0 -22
- package/dist/artifacts/validate.d.ts +0 -62
- package/dist/artifacts/validate.js +0 -651
- package/dist/artifacts.d.ts +0 -6
- package/dist/artifacts.js +0 -9
- package/dist/auth/bearer.d.ts +0 -11
- package/dist/auth/bearer.js +0 -50
- package/dist/providers/linear.js +0 -217
- package/dist/providers/mixpanel.js +0 -247
- package/dist/providers/revenuecat.js +0 -317
- package/dist/providers/stripe.js +0 -253
- package/dist/providers/vercel.js +0 -1253
- package/dist/storage/file.d.ts +0 -15
- package/dist/storage/file.js +0 -455
- package/ethos.md +0 -93
- package/examples/worker/src/cloudflare-kv.ts +0 -43
- package/examples/worker/src/d1-activity-row.ts +0 -155
- package/examples/worker/src/d1-activity.ts +0 -147
- package/examples/worker/src/d1-storage.ts +0 -138
- package/examples/worker/src/r2-artifact-blobs.ts +0 -29
- 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
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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,
|
|
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,
|
|
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
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
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.0";
|
|
1
|
+
export declare const CONNECTA_VERSION = "0.29.0";
|
package/dist/version.js
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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.0";
|
|
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";
|
package/dist/worker.d.ts
ADDED
|
@@ -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 {};
|