@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.
- package/CHANGELOG.md +855 -5
- package/README.md +125 -116
- package/bin/connecta.mjs +121 -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/argument-redaction.js +230 -0
- 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 +1584 -1580
- 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 +93 -71
- package/dist/auth-elicitation.js +288 -0
- package/dist/authorization-handoff.js +111 -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 +409 -225
- 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 +633 -0
- package/dist/config.js +508 -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 +59 -7
- package/dist/connectors/api-connector.js +106 -19
- package/dist/connectors/api.js +4 -1
- package/dist/connectors/guarded-fetch.d.ts +144 -0
- package/dist/connectors/guarded-fetch.js +87 -38
- 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 +1774 -320
- 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 +128 -0
- package/dist/downstream-input.js +325 -0
- package/dist/errors.d.ts +132 -31
- package/dist/errors.js +175 -87
- package/dist/execute.js +798 -318
- 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 +30 -13
- package/dist/executors/quickjs-child.js +15 -9
- package/dist/executors/quickjs-protocol.js +5 -6
- package/dist/executors/quickjs-runtime.js +152 -59
- package/dist/executors/quickjs.js +49 -39
- package/dist/favicon.js +1 -2
- package/dist/fix-prompt.js +1 -3
- package/dist/guest-runtime.js +238 -0
- package/dist/guest-types.d.ts +218 -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 +24 -256
- package/dist/index.js +65 -478
- package/dist/invocation-auth.js +69 -0
- package/dist/invocation.js +262 -79
- 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 +61 -0
- package/dist/meta-tool-names.d.ts +2 -0
- package/dist/meta-tool-names.js +3 -0
- package/dist/meta-tools.js +419 -272
- 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 +194 -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-result.js +5 -0
- package/dist/program-source.js +14 -2
- package/dist/{exempt-writes.js → program-writes.js} +60 -19
- 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/_shared/request-token.js +83 -0
- package/dist/providers/{basecamp.d.ts → basecamp/index.d.ts} +6 -28
- package/dist/providers/basecamp/index.js +997 -0
- package/dist/providers/basecamp/skill.generated.js +9 -0
- package/dist/providers/{breeze.d.ts → breeze/index.d.ts} +2 -2
- package/dist/providers/{breeze.js → breeze/index.js} +184 -140
- package/dist/providers/breeze/skill.generated.js +9 -0
- package/dist/providers/{ccb.d.ts → ccb/index.d.ts} +2 -2
- package/dist/providers/{ccb.js → ccb/index.js} +271 -116
- 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/infisical/index.d.ts +7 -0
- package/dist/providers/infisical/index.js +713 -0
- package/dist/providers/infisical/skill.generated.js +8 -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.d.ts → overflow/index.d.ts} +2 -2
- package/dist/providers/{overflow.js → overflow/index.js} +74 -111
- package/dist/providers/overflow/skill.generated.js +8 -0
- package/dist/providers/{planning-center.d.ts → planning-center/index.d.ts} +2 -2
- package/dist/providers/{planning-center.js → planning-center/index.js} +264 -104
- 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.d.ts → tithely/index.d.ts} +2 -2
- package/dist/providers/{tithely.js → tithely/index.js} +60 -91
- 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 +110 -171
- package/dist/registry.js +588 -927
- package/dist/request-state.js +21 -0
- package/dist/resource-read.js +103 -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 +365 -130
- package/dist/routes/oauth-client-metadata.js +15 -0
- package/dist/routes/oauth-management.js +45 -107
- package/dist/routes/oauth.js +110 -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 +93 -0
- package/dist/sent-secrets.js +1013 -0
- package/dist/server.js +28 -71
- package/dist/skills.js +416 -174
- package/dist/sqlite.d.ts +48 -0
- package/dist/sqlite.js +181 -0
- package/dist/storage/keys.js +443 -0
- package/dist/storage/memory.js +16 -4
- package/dist/storage/sql.d.ts +66 -0
- package/dist/storage/sql.js +543 -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 +336 -56
- 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 +146 -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 +435 -0
- package/documentation/README.md +63 -0
- package/documentation/architecture.md +696 -231
- package/documentation/auth.md +1069 -546
- package/documentation/code-mode.md +662 -356
- package/documentation/deploying.md +146 -0
- package/documentation/integrating.md +159 -0
- package/documentation/meta-tools.md +570 -216
- package/documentation/operating.md +135 -0
- package/documentation/operator-tests.md +97 -0
- package/documentation/operator-ui.md +132 -0
- package/documentation/provider-migration-0.29.md +65 -0
- package/examples/worker/AGENTS.md +34 -12
- package/examples/worker/README.md +293 -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 +126 -54
- 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 +140 -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/basecamp.js +0 -445
- 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/ui.js
CHANGED
|
@@ -1,59 +1,50 @@
|
|
|
1
|
+
import { assertKnownOptions, keys, optionsOf } from "./config-schema.js";
|
|
1
2
|
import { routeUi } from "./routes/ui.js";
|
|
2
3
|
import { routeCredentials } from "./routes/credentials.js";
|
|
3
4
|
import { routeOAuthManagement } from "./routes/oauth-management.js";
|
|
4
5
|
import { uiData } from "./routes/ui-data.js";
|
|
5
6
|
import { runEdge } from "./runtime/run.js";
|
|
6
|
-
import {
|
|
7
|
-
import { OPERATOR_UI_CSS, OPERATOR_UI_SCRIPT, } from "./operator-ui/generated.js";
|
|
7
|
+
import { OPERATOR_UI_STYLE_PATH, OPERATOR_UI_SCRIPT_PATH, OPERATOR_UI_NOTICES_PATH } from "./operator-ui/generated.js";
|
|
8
8
|
export { filterUiConnectors, } from "./operator-ui/model.js";
|
|
9
|
-
import { escapeHtml, isSafeHttpsUrl,
|
|
9
|
+
import { escapeHtml, isSafeHttpsUrl, renderPage, resolveBranding } from "./branding.js";
|
|
10
10
|
export { CONNECTA_FAVICON_SVG, resolveBranding, isSafeHttpUrl, isSafeHttpsUrl, isSafeIconHref } from "./branding.js";
|
|
11
|
-
/**
|
|
12
|
-
* A JS string literal safe to inline in a script element. Escaping `/` keeps
|
|
13
|
-
* an operator-supplied `</script>` from terminating the element early.
|
|
14
|
-
*/
|
|
15
|
-
function stringForInlineScript(value) {
|
|
16
|
-
return JSON.stringify(value).replace(/\//g, "\\/");
|
|
17
|
-
}
|
|
18
11
|
const OPERATOR_PAGE_LABELS = {
|
|
19
|
-
|
|
12
|
+
overview: "Overview",
|
|
13
|
+
connections: "Connectors",
|
|
14
|
+
connector: "Connector",
|
|
15
|
+
tools: "Tools",
|
|
16
|
+
access: "Access",
|
|
17
|
+
config: "Config",
|
|
20
18
|
tokens: "Access tokens",
|
|
21
19
|
activity: "Activity",
|
|
22
|
-
artifacts: "Artifacts",
|
|
23
|
-
artifact: "Artifact",
|
|
24
20
|
};
|
|
25
|
-
/** `/artifacts/<id>` and its snapshots, `/artifacts/<id>/v/<version>`. */
|
|
26
|
-
const ARTIFACT_PAGE = /^\/artifacts\/[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?(?:\/v\/\d{1,9})?$/;
|
|
27
21
|
export function operatorPageForPath(path) {
|
|
28
|
-
if (path === "/tokens")
|
|
29
|
-
return "tokens";
|
|
30
22
|
if (path === "/")
|
|
23
|
+
return "overview";
|
|
24
|
+
if (path === "/connectors")
|
|
31
25
|
return "connections";
|
|
26
|
+
if (/^\/connectors\/[a-z0-9_-]+$/.test(path))
|
|
27
|
+
return "connector";
|
|
28
|
+
if (path === "/tools")
|
|
29
|
+
return "tools";
|
|
30
|
+
if (path === "/access")
|
|
31
|
+
return "access";
|
|
32
|
+
if (path === "/config")
|
|
33
|
+
return "config";
|
|
34
|
+
if (path === "/tokens")
|
|
35
|
+
return "tokens";
|
|
32
36
|
if (path === "/activity")
|
|
33
37
|
return "activity";
|
|
34
|
-
if (path === "/artifacts")
|
|
35
|
-
return "artifacts";
|
|
36
|
-
if (ARTIFACT_PAGE.test(path))
|
|
37
|
-
return "artifact";
|
|
38
38
|
return undefined;
|
|
39
39
|
}
|
|
40
|
-
/** Everything artifact pages own: shells, their API, and the frame. */
|
|
41
|
-
function isArtifactPath(path) {
|
|
42
|
-
return path === "/artifacts" || path.startsWith("/artifacts/");
|
|
43
|
-
}
|
|
44
40
|
export function operatorPageTitle(page, configuredTitle) {
|
|
45
41
|
return `${OPERATOR_PAGE_LABELS[page]} — ${configuredTitle}`;
|
|
46
42
|
}
|
|
47
|
-
/**
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
* config exemption (#566), which `isApprovalExempt` already refuses to grant
|
|
51
|
-
* a read-only tool.
|
|
52
|
-
*/
|
|
53
|
-
export function uiToolSafety(definition, exempt = false) {
|
|
54
|
-
if (isExplicitlyReadOnly(definition))
|
|
43
|
+
/** Report the verdict the registry stored, independent of pool trust. */
|
|
44
|
+
export function uiToolSafety(definition) {
|
|
45
|
+
if (definition.classification === "read")
|
|
55
46
|
return "runs_in_programs";
|
|
56
|
-
return
|
|
47
|
+
return "needs_approval";
|
|
57
48
|
}
|
|
58
49
|
/**
|
|
59
50
|
* The fix-prompt key for a connector that is not usable. Chosen from the
|
|
@@ -63,6 +54,8 @@ export function uiToolSafety(definition, exempt = false) {
|
|
|
63
54
|
export function uiProblemFor(connector, status, observed) {
|
|
64
55
|
if (observed.credentialDrift)
|
|
65
56
|
return "credential_mismatch";
|
|
57
|
+
if (status === "credential_required")
|
|
58
|
+
return "credential_required";
|
|
66
59
|
if (status === "error")
|
|
67
60
|
return "connector_unavailable";
|
|
68
61
|
if (status === "auth_required") {
|
|
@@ -86,9 +79,7 @@ export function credentialManagementCapability(input) {
|
|
|
86
79
|
* isolated: they surface status "error" with an empty tool list rather than
|
|
87
80
|
* failing the whole payload.
|
|
88
81
|
*/
|
|
89
|
-
export async function buildUiData(registry, baseUrl, serverInfo, credentialVault, activityEnabled = false, credentialManagement = credentialVault
|
|
90
|
-
? "available"
|
|
91
|
-
: "requires_operator", defer, oauthManagement = false, discoveryConcurrency, personalCredentialOwner, detailOptions = {}) {
|
|
82
|
+
export async function buildUiData(registry, baseUrl, serverInfo, credentialVault, activityEnabled = false, credentialManagement = credentialVault ? "available" : "requires_operator", defer, oauthManagement = false, discoveryConcurrency, personalCredentialOwner, detailOptions = {}) {
|
|
92
83
|
return runEdge(uiData(registry, baseUrl, {
|
|
93
84
|
serverInfo,
|
|
94
85
|
credentialVault,
|
|
@@ -102,27 +93,24 @@ export async function buildUiData(registry, baseUrl, serverInfo, credentialVault
|
|
|
102
93
|
}));
|
|
103
94
|
}
|
|
104
95
|
function jsonForInlineScript(value) {
|
|
105
|
-
return JSON.stringify(value)
|
|
106
|
-
.replaceAll("<", "\\u003c")
|
|
107
|
-
.replaceAll(">", "\\u003e")
|
|
108
|
-
.replaceAll("&", "\\u0026");
|
|
96
|
+
return JSON.stringify(value).replaceAll("<", "\\u003c").replaceAll(">", "\\u003e").replaceAll("&", "\\u0026");
|
|
109
97
|
}
|
|
110
98
|
/**
|
|
111
99
|
* Every operator page serves this same data-free shell. Connector, credential,
|
|
112
100
|
* and activity data arrives only through the authenticated `/ui/*` APIs.
|
|
113
101
|
*/
|
|
114
|
-
export function renderUiHtml(uiAuth, mcpUrl = "/mcp", branding,
|
|
102
|
+
export function renderUiHtml(uiAuth, mcpUrl = "/mcp", branding,
|
|
103
|
+
/** @deprecated Scripts load from same-origin assets; ignored. */
|
|
104
|
+
_nonce, page = "overview") {
|
|
115
105
|
const clerk = uiAuth?.kind === "clerk" ? uiAuth : undefined;
|
|
116
106
|
// The Clerk loader's origin. A value that fails the gate is dropped rather
|
|
117
107
|
// than escaped into the page: the loader tag is simply not emitted, the gate
|
|
118
108
|
// reports that Clerk could not load, and the rest of the shell still renders —
|
|
119
109
|
// the same fallback-and-warn posture the branding URLs take, with the drop
|
|
120
110
|
// named in a startup warning (see `droppedUiAuthUrls`).
|
|
121
|
-
const clerkScriptOrigin = clerk && isSafeHttpsUrl(clerk.frontendApiUrl)
|
|
122
|
-
? clerk.frontendApiUrl
|
|
123
|
-
: undefined;
|
|
111
|
+
const clerkScriptOrigin = clerk && isSafeHttpsUrl(clerk.frontendApiUrl) ? clerk.frontendApiUrl : undefined;
|
|
124
112
|
// Enumerated field by field, because this object is serialized into the page's
|
|
125
|
-
//
|
|
113
|
+
// JSON config: a rejected frontendApiUrl must not reach the document through
|
|
126
114
|
// `AUTH` after being kept out of the `<script src>`, and a rejected
|
|
127
115
|
// signInUrl/signUpUrl — which `AUTH` is the only path into the page for — must
|
|
128
116
|
// not reach it at all. Dropping one leaves the key absent, so `Clerk.load`
|
|
@@ -132,20 +120,13 @@ export function renderUiHtml(uiAuth, mcpUrl = "/mcp", branding, nonce, page = "c
|
|
|
132
120
|
kind: clerk.kind,
|
|
133
121
|
publishableKey: clerk.publishableKey,
|
|
134
122
|
...(clerkScriptOrigin ? { frontendApiUrl: clerkScriptOrigin } : {}),
|
|
135
|
-
...(isSafeHttpsUrl(clerk.signInUrl)
|
|
136
|
-
|
|
137
|
-
: {}),
|
|
138
|
-
...(isSafeHttpsUrl(clerk.signUpUrl)
|
|
139
|
-
? { signUpUrl: clerk.signUpUrl }
|
|
140
|
-
: {}),
|
|
123
|
+
...(isSafeHttpsUrl(clerk.signInUrl) ? { signInUrl: clerk.signInUrl } : {}),
|
|
124
|
+
...(isSafeHttpsUrl(clerk.signUpUrl) ? { signUpUrl: clerk.signUpUrl } : {}),
|
|
141
125
|
}
|
|
142
126
|
: (uiAuth ?? { kind: "bearer" });
|
|
143
127
|
const brand = resolveBranding(branding);
|
|
144
|
-
// When an operator shell ships a nonce-based CSP, every script it emits must
|
|
145
|
-
// carry that nonce to run; without a nonce the markup is unchanged.
|
|
146
|
-
const nonceAttr = nonce ? ` nonce="${nonce}"` : "";
|
|
147
128
|
const clerkScript = clerk && clerkScriptOrigin
|
|
148
|
-
? `<script
|
|
129
|
+
? `<script crossorigin="anonymous" data-clerk-publishable-key="${escapeHtml(clerk.publishableKey)}" src="${escapeHtml(clerkScriptOrigin)}/npm/@clerk/clerk-js@6/dist/clerk.browser.js"></script>`
|
|
149
130
|
: "";
|
|
150
131
|
// The shared layout owns the head, scheme, theme, and masthead; the shell
|
|
151
132
|
// adds its own bundle (which already imports the shared tokens), the nav
|
|
@@ -153,9 +134,10 @@ export function renderUiHtml(uiAuth, mcpUrl = "/mcp", branding, nonce, page = "c
|
|
|
153
134
|
return renderPage(branding, {
|
|
154
135
|
title: operatorPageTitle(page, brand.pageTitle),
|
|
155
136
|
uiMounted: true,
|
|
156
|
-
|
|
157
|
-
styles:
|
|
158
|
-
head:
|
|
137
|
+
operatorShell: true,
|
|
138
|
+
styles: "",
|
|
139
|
+
head: `<link rel="stylesheet" href="${OPERATOR_UI_STYLE_PATH}"><link rel="license" href="${OPERATOR_UI_NOTICES_PATH}">` +
|
|
140
|
+
clerkScript,
|
|
159
141
|
skipTo: { id: "operatorContent", label: "Skip to operator page" },
|
|
160
142
|
mastheadEnd: '<div id="operatorNav"></div>',
|
|
161
143
|
body: `
|
|
@@ -170,28 +152,45 @@ export function renderUiHtml(uiAuth, mcpUrl = "/mcp", branding, nonce, page = "c
|
|
|
170
152
|
</div>
|
|
171
153
|
</main>
|
|
172
154
|
`,
|
|
173
|
-
tail: `<script
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
${OPERATOR_UI_SCRIPT}</script>`,
|
|
155
|
+
tail: `<script id="operatorConfig" type="application/json">${jsonForInlineScript({
|
|
156
|
+
auth,
|
|
157
|
+
mcpUrl,
|
|
158
|
+
initialPage: page,
|
|
159
|
+
titleSuffix: brand.pageTitle,
|
|
160
|
+
productName: brand.productName,
|
|
161
|
+
productDescription: brand.description,
|
|
162
|
+
productOperatorLabel: brand.productName + " operator",
|
|
163
|
+
})}</script><script defer src="${OPERATOR_UI_SCRIPT_PATH}"></script>`,
|
|
183
164
|
});
|
|
184
165
|
}
|
|
185
166
|
function ownsOperatorPath(reserved, path) {
|
|
186
167
|
if (path === "/activity" || path === "/tokens")
|
|
187
168
|
return true;
|
|
188
|
-
return reserved.some((pattern) => pattern.endsWith("/*")
|
|
189
|
-
? path.startsWith(pattern.slice(0, -1))
|
|
190
|
-
: path === pattern);
|
|
169
|
+
return reserved.some((pattern) => pattern.endsWith("/*") ? path.startsWith(pattern.slice(0, -1)) : path === pattern);
|
|
191
170
|
}
|
|
171
|
+
/** The closed options operatorUi() accepts; see `assertKnownOptions`. */
|
|
172
|
+
const OPERATOR_UI_OPTIONS = optionsOf()({
|
|
173
|
+
branding: optionsOf()({
|
|
174
|
+
...keys("productName", "productUrl", "ownerName", "ownerUrl", "description", "pageTitle", "themeColor"),
|
|
175
|
+
favicon: optionsOf()(keys("svg", "ico", "href")),
|
|
176
|
+
theme: optionsOf()(keys("accent", "radius", "fontFamily", "monoFamily", "colorScheme")),
|
|
177
|
+
}),
|
|
178
|
+
});
|
|
192
179
|
/** Mount the connection UI without enabling any storage or activity module. */
|
|
193
180
|
export function operatorUi(options = {}) {
|
|
194
|
-
|
|
181
|
+
options = assertKnownOptions(options, "operatorUi()", OPERATOR_UI_OPTIONS);
|
|
182
|
+
const reservedPaths = [
|
|
183
|
+
"/",
|
|
184
|
+
"/connectors",
|
|
185
|
+
"/connectors/*",
|
|
186
|
+
"/tools",
|
|
187
|
+
"/access",
|
|
188
|
+
"/config",
|
|
189
|
+
"/ui",
|
|
190
|
+
"/ui/*",
|
|
191
|
+
"/favicon.svg",
|
|
192
|
+
"/favicon.ico",
|
|
193
|
+
];
|
|
195
194
|
return {
|
|
196
195
|
...options,
|
|
197
196
|
reservedPaths,
|
|
@@ -203,25 +202,12 @@ export function operatorUi(options = {}) {
|
|
|
203
202
|
// route here, and no activity module, runs for a path this surface does
|
|
204
203
|
// not own. The Activity page is the one addition; the server reserves
|
|
205
204
|
// it only when history is readable, and routeUi checks the same thing.
|
|
206
|
-
|
|
207
|
-
const artifacts = context.opts.artifactsModule;
|
|
208
|
-
const artifactPath = Boolean(artifacts) && isArtifactPath(context.path);
|
|
209
|
-
if (!artifactPath && !ownsOperatorPath(reservedPaths, context.path))
|
|
205
|
+
if (!ownsOperatorPath(reservedPaths, context.path))
|
|
210
206
|
return null;
|
|
211
|
-
|
|
212
|
-
// The pages' JSON API and the sandboxed frame; the module owns both,
|
|
213
|
-
// and this bundle imports none of it.
|
|
214
|
-
return (await artifacts?.handle(context)) ??
|
|
215
|
-
notFoundResponse(context.request, context.opts);
|
|
216
|
-
}
|
|
217
|
-
const tokenResponse = await context.opts.accessTokens?.handle(context);
|
|
207
|
+
const tokenResponse = await context.opts.config.accessTokens?.handle(context);
|
|
218
208
|
if (tokenResponse)
|
|
219
209
|
return tokenResponse;
|
|
220
|
-
const routes = [
|
|
221
|
-
...(context.opts.credentialVault ? [routeCredentials] : []),
|
|
222
|
-
routeOAuthManagement,
|
|
223
|
-
routeUi,
|
|
224
|
-
];
|
|
210
|
+
const routes = [...(context.opts.config.vault ? [routeCredentials] : []), routeOAuthManagement, routeUi];
|
|
225
211
|
for (const route of routes) {
|
|
226
212
|
const response = await route(context);
|
|
227
213
|
if (response) {
|
|
@@ -234,7 +220,7 @@ export function operatorUi(options = {}) {
|
|
|
234
220
|
return response;
|
|
235
221
|
}
|
|
236
222
|
}
|
|
237
|
-
return context.opts.
|
|
223
|
+
return context.opts.config.activity?.handle(context) ?? null;
|
|
238
224
|
},
|
|
239
225
|
};
|
|
240
226
|
}
|
package/dist/url-safety.js
CHANGED
|
@@ -48,7 +48,7 @@ function ipv6Pieces(host) {
|
|
|
48
48
|
const pieces = (part) => {
|
|
49
49
|
if (!part)
|
|
50
50
|
return [];
|
|
51
|
-
const parsed = part.split(":").map((piece) => HEXTET.test(piece) ? Number.parseInt(piece, 16) : Number.NaN);
|
|
51
|
+
const parsed = part.split(":").map((piece) => (HEXTET.test(piece) ? Number.parseInt(piece, 16) : Number.NaN));
|
|
52
52
|
return parsed.some(Number.isNaN) ? undefined : parsed;
|
|
53
53
|
};
|
|
54
54
|
const head = pieces(halves[0]);
|
|
@@ -89,9 +89,7 @@ function classifyIpv6(pieces) {
|
|
|
89
89
|
function canonicalHost(hostname) {
|
|
90
90
|
if (/[/\\?#@]/.test(hostname))
|
|
91
91
|
return undefined;
|
|
92
|
-
const bracketed = hostname.includes(":") && !hostname.startsWith("[")
|
|
93
|
-
? `[${hostname}]`
|
|
94
|
-
: hostname;
|
|
92
|
+
const bracketed = hostname.includes(":") && !hostname.startsWith("[") ? `[${hostname}]` : hostname;
|
|
95
93
|
try {
|
|
96
94
|
return new URL(`http://${bracketed}/`).hostname;
|
|
97
95
|
}
|
|
@@ -144,8 +142,7 @@ export function learnedUrlRefusal(configured, target) {
|
|
|
144
142
|
if (target.origin === configured.origin)
|
|
145
143
|
return undefined;
|
|
146
144
|
const targetClass = classifyHost(target.hostname);
|
|
147
|
-
if (targetClass === "loopback" &&
|
|
148
|
-
classifyHost(configured.hostname) === "loopback") {
|
|
145
|
+
if (targetClass === "loopback" && classifyHost(configured.hostname) === "loopback") {
|
|
149
146
|
return undefined;
|
|
150
147
|
}
|
|
151
148
|
if (targetClass !== "public") {
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/** Self-contained content for the usage skill; independent of skill registration. */
|
|
2
|
+
export const USAGE_SKILL = `---
|
|
3
|
+
name: usage
|
|
4
|
+
description: How to route work between one execute_code program and Connecta's explicit call, authorization, and result tools.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Connecta usage
|
|
8
|
+
|
|
9
|
+
## Choose the route
|
|
10
|
+
|
|
11
|
+
| Work | Tool |
|
|
12
|
+
| --- | --- |
|
|
13
|
+
| One known-address read | call_tool |
|
|
14
|
+
| One known-address write | call_destructive_tool |
|
|
15
|
+
| Discovery, multiple or dependent calls, paging, reduction | execute_code |
|
|
16
|
+
|
|
17
|
+
Read one account with call_tool: \`{ "address": "crm.get_account", "args": { "id": "acct_42" } }\`.
|
|
18
|
+
Discover and call together when schemas suffice. search_tools covers catalog
|
|
19
|
+
inspection and write discovery in read-only pools. Programs may
|
|
20
|
+
write only in trusted pools; the tool description states this endpoint's trust.
|
|
21
|
+
Unannotated tools fail closed to writes.
|
|
22
|
+
|
|
23
|
+
## The global and the envelopes
|
|
24
|
+
|
|
25
|
+
Pass JavaScript \`async () => { ... }\`, no arguments. Do not shadow \`connecta\`.
|
|
26
|
+
No imports, require, filesystem, fetch, or timers.
|
|
27
|
+
|
|
28
|
+
Use \`connecta.call(address, args, { timeoutMs })\` or
|
|
29
|
+
\`connecta.call({ address, args, timeoutMs })\`; both return \`{ data, format }\`.
|
|
30
|
+
\`format: "json"\` carries JSON; \`format: "text"\` carries text. Parse text only
|
|
31
|
+
when documented as JSON. Verify collection roots.
|
|
32
|
+
|
|
33
|
+
\`connecta.read("resource://id/"+encodeURIComponent(uri))\` returns \`{ contents }\` for advertised URIs.
|
|
34
|
+
|
|
35
|
+
Search/describe return \`{ tools }\`, never an array. Search also returns
|
|
36
|
+
\`catalogErrors\`, pagination, and possible \`absence\`; check failures before
|
|
37
|
+
selecting a match. JSON schemas are the program default. Compact schemas have
|
|
38
|
+
\`schemaFormat: "text"\`; do not read their .properties. Select the exact tool and
|
|
39
|
+
account/environment, inspect its schema, and supply its required keys and types.
|
|
40
|
+
|
|
41
|
+
Discover an unfamiliar read and reduce its result:
|
|
42
|
+
|
|
43
|
+
\`\`\`js
|
|
44
|
+
async () => {
|
|
45
|
+
const page = await connecta.search({ connector: "ci", query: "get_run" });
|
|
46
|
+
if (page.catalogErrors.length || page.absence) return page;
|
|
47
|
+
const tool = page.tools.find(t => t.name === "get_run");
|
|
48
|
+
if (!tool) return { gap: "get_run unavailable" };
|
|
49
|
+
const result = await connecta.call(tool.address, { runId: 42 });
|
|
50
|
+
return result.format === "json"
|
|
51
|
+
? { status: result.data.status, jobId: result.data.failedJobId } : result;
|
|
52
|
+
}
|
|
53
|
+
\`\`\`
|
|
54
|
+
|
|
55
|
+
## Keep partial successes
|
|
56
|
+
|
|
57
|
+
Use Promise.allSettled to keep independent successes. Rejections retain \`code\`,
|
|
58
|
+
\`message\`, \`retryable\`, and \`details\`. Branch on fields, not prose. Repair
|
|
59
|
+
arguments before batching. Runs report hostCalls separately.
|
|
60
|
+
|
|
61
|
+
Read JSON and text after verifying addresses and schemas:
|
|
62
|
+
|
|
63
|
+
\`\`\`js
|
|
64
|
+
async () => {
|
|
65
|
+
const settled = await Promise.allSettled([
|
|
66
|
+
connecta.call("ci.get_run", { runId: 42 }),
|
|
67
|
+
connecta.call("ci.get_job_logs", { jobId: "job_7" }),
|
|
68
|
+
connecta.call("ci.get_run", { runId: "wrong-type" })
|
|
69
|
+
]);
|
|
70
|
+
return settled.map(s => s.status === "rejected"
|
|
71
|
+
? { error: s.reason.code, retryable: s.reason.retryable }
|
|
72
|
+
: s.value.format === "text"
|
|
73
|
+
? { text: s.value.data.split("\\n").filter(line => line.startsWith("ERROR")) }
|
|
74
|
+
: { status: s.value.data.status });
|
|
75
|
+
}
|
|
76
|
+
\`\`\`
|
|
77
|
+
|
|
78
|
+
Host-call budget exhaustion ends the run with budget_exceeded. Catch and
|
|
79
|
+
allSettled cannot recover it or return partial output. Bound batches before
|
|
80
|
+
starting them; search, describe, call, result, and skill spend host calls.
|
|
81
|
+
Split remaining reads. Never replay writes for their output.
|
|
82
|
+
|
|
83
|
+
## Per-connector guides
|
|
84
|
+
|
|
85
|
+
Fetch a listed guide with skills by its exact name, or \`connecta.skill(name)\`
|
|
86
|
+
inside a program; it returns \`{ name, text, format: "text" }\`.
|
|
87
|
+
\`guideRequired: true\` is a hard stop. connector_required and approval_required
|
|
88
|
+
remain after schema expansion; schema_truncated clears after exact describe.
|
|
89
|
+
Otherwise fetch for units, pagination, aliases, or sequences.
|
|
90
|
+
|
|
91
|
+
## Large results and recovery
|
|
92
|
+
|
|
93
|
+
Large direct results and program returns carry resultId when paging is available. Follow
|
|
94
|
+
nextOffset in UTF-8 bytes, reassemble and reduce inside one program. Use the
|
|
95
|
+
returned id in place of result-id below; this example assumes documented JSON.
|
|
96
|
+
|
|
97
|
+
Calls reconstruct up to 1 MiB through stash pages. Larger values return
|
|
98
|
+
\`{ format: "paged", valueFormat, resultId?, totalBytes, hint }\`. Pass the handle
|
|
99
|
+
to \`connecta.result\`. No resultId means no paging. IDs expire after
|
|
100
|
+
15 minutes; only explicit paging spends extra host calls.
|
|
101
|
+
Use zero-based \`{ page: 0 }\` or UTF-8 \`{ offset }\`, never both. Keep maxBytes
|
|
102
|
+
fixed across pages; connector caps and the 32 KiB bridge ceiling apply.
|
|
103
|
+
|
|
104
|
+
\`\`\`js
|
|
105
|
+
async () => {
|
|
106
|
+
let text = "", offset = 0, page;
|
|
107
|
+
do {
|
|
108
|
+
page = await connecta.result("result-id", { offset, maxBytes: 8000 });
|
|
109
|
+
text += page.text;
|
|
110
|
+
offset = page.nextOffset;
|
|
111
|
+
} while (page.hasMore);
|
|
112
|
+
return JSON.parse(text).items.map(item => item.id);
|
|
113
|
+
}
|
|
114
|
+
\`\`\`
|
|
115
|
+
|
|
116
|
+
Oversized returns lead with nextAction. Never rerun writes for output. write_outcome_unknown forbids retry, even if caught.
|
|
117
|
+
Recovery args may be partial (argsRedacted) or absent (argsOmitted). Reconcile
|
|
118
|
+
before retrying with the original args or repeating a program that sent writes.
|
|
119
|
+
Non-retryable errors need repair.
|
|
120
|
+
host_auth_required needs host connection repair; provider_permission_denied needs
|
|
121
|
+
resource-owner access. Auth failures carry the handoff in error.data. When an auth
|
|
122
|
+
error includes a handoff, give it to the user or operator.
|
|
123
|
+
|
|
124
|
+
## Output
|
|
125
|
+
|
|
126
|
+
Use \`connecta.emit(await connecta.call(address, args))\` for MCP rich output,
|
|
127
|
+
or \`for (const b of x.content ?? []) connecta.emit(b)\`. Both forward originals,
|
|
128
|
+
including resources and metadata; edits do not change them. Page oversized
|
|
129
|
+
native content with \`connecta.result(x.contentResult)\`.
|
|
130
|
+
Authored blocks accept text or base64 image/audio; images require canonical
|
|
131
|
+
base64 and PNG/JPEG/GIF/WebP MIME. Emit works without await, delivers on success,
|
|
132
|
+
and obeys byte/block budgets; text shares the return cap. Return reduced JSON.
|
|
133
|
+
|
|
134
|
+
`;
|
|
135
|
+
/** Kept in sync with GuestApi by the declaration test. These are type notation, not runnable JS. */
|
|
136
|
+
export const GUEST_API_DECLARATION = `search(args?: CatalogSearchArgs): Promise<CatalogSearchResult>;
|
|
137
|
+
describe(args?: CatalogDescribeArgs): Promise<{ tools: CatalogDescription[] }>;
|
|
138
|
+
call(address: string, args?: unknown, options?: { timeoutMs?: number }): Promise<GuestResult>;
|
|
139
|
+
call(request: { address: string; args?: unknown; timeoutMs?: number }): Promise<GuestResult>;
|
|
140
|
+
read(uri: string): Promise<GuestResourceResult>;
|
|
141
|
+
result(
|
|
142
|
+
id: string | GuestResultHandle,
|
|
143
|
+
options?: { page?: number; offset?: number; maxBytes?: number },
|
|
144
|
+
): Promise<GuestResultPage>;
|
|
145
|
+
skill(name: string): Promise<{ name: string; text: string; format: "text" }>;
|
|
146
|
+
emit(block: GuestNativeBlock | GuestResult): PromiseLike<void>;`;
|
package/dist/validate.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ConnectorCallError } from "./errors.js";
|
|
2
|
+
import { type FailureSubject } from "./operator-record.js";
|
|
2
3
|
import type { JsonSchema, Logger } from "./types.js";
|
|
3
4
|
export interface ValidateToolInputOptions {
|
|
4
5
|
/**
|
|
@@ -54,6 +55,12 @@ export interface CompileValidatorOptions {
|
|
|
54
55
|
* the `Connector` interface directly.
|
|
55
56
|
*/
|
|
56
57
|
export declare function validateToolInput(schema: JsonSchema, args: unknown, opts: ValidateToolInputOptions): ConnectorCallError | null;
|
|
58
|
+
/**
|
|
59
|
+
* `validateToolInput` for a tool connecta resolved in a catalog. `subject`
|
|
60
|
+
* names it in the log record when the schema is unusable; a caller's own
|
|
61
|
+
* address never reaches the log.
|
|
62
|
+
*/
|
|
63
|
+
export declare function validateCatalogToolInput(schema: JsonSchema, args: unknown, opts: ValidateToolInputOptions, subject: FailureSubject): ConnectorCallError | null;
|
|
57
64
|
/**
|
|
58
65
|
* Eagerly compile and cache a tool's inputSchema, throwing when the validator
|
|
59
66
|
* cannot use it. Reuses the same module-level cache `validateToolInput` reads,
|