@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/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,137 @@
|
|
|
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
|
+
For example, read account acct_42 with call_tool arguments
|
|
18
|
+
\`{ "address": "crm.get_account", "args": { "id": "acct_42" } }\`.
|
|
19
|
+
Discover and call in the same program when schemas suffice. Top-level search_tools
|
|
20
|
+
covers catalog inspection and write discovery in read-only pools. Programs may
|
|
21
|
+
write only in trusted pools; the tool description states this endpoint's trust.
|
|
22
|
+
Unannotated tools fail closed to writes.
|
|
23
|
+
|
|
24
|
+
## The global and the envelopes
|
|
25
|
+
|
|
26
|
+
Pass one plain JavaScript async arrow, \`async () => { ... }\`. It receives no
|
|
27
|
+
arguments. Use the supplied \`connecta\` global; do not shadow it with a parameter.
|
|
28
|
+
No imports, require, filesystem, fetch, or timers in portable programs.
|
|
29
|
+
|
|
30
|
+
\`connecta.call(address, args, { timeoutMs })\` is positional. The object overload
|
|
31
|
+
is \`connecta.call({ address, args, timeoutMs })\`. Both return \`{ data, format }\`.
|
|
32
|
+
For \`format: "json"\`, data is the JSON value. For \`format: "text"\`, data is a
|
|
33
|
+
string: parse only if the provider documents JSON text. Never guess collection roots.
|
|
34
|
+
|
|
35
|
+
\`connecta.read("resource://id/"+encodeURIComponent(uri))\` returns \`{ contents }\` for advertised URIs.
|
|
36
|
+
|
|
37
|
+
Search and describe return \`{ tools }\`, never an array. Search also returns
|
|
38
|
+
\`catalogErrors\`, pagination, and possible \`absence\`; check failures before
|
|
39
|
+
selecting a match. JSON schemas are the program default. Compact schemas have
|
|
40
|
+
\`schemaFormat: "text"\`; do not read their .properties. Select the exact tool and
|
|
41
|
+
account/environment, inspect its schema, and supply its required keys and types.
|
|
42
|
+
|
|
43
|
+
Discover an unfamiliar run lookup, then reduce its JSON result:
|
|
44
|
+
|
|
45
|
+
\`\`\`js
|
|
46
|
+
async () => {
|
|
47
|
+
const page = await connecta.search({ connector: "ci", query: "get_run", safety: "readOnly" });
|
|
48
|
+
if (page.catalogErrors.length || page.absence) return { gap: page.catalogErrors, absence: page.absence };
|
|
49
|
+
const tool = page.tools.find(t => t.name === "get_run");
|
|
50
|
+
if (!tool) return { gap: "get_run unavailable" };
|
|
51
|
+
const { tools } = await connecta.describe({ address: tool.address });
|
|
52
|
+
if (tools[0].error) return { gap: tools[0].error };
|
|
53
|
+
const result = await connecta.call(tool.address, { runId: 42 });
|
|
54
|
+
if (result.format !== "json") return { gap: "Expected JSON" };
|
|
55
|
+
return { status: result.data.status, jobId: result.data.failedJobId };
|
|
56
|
+
}
|
|
57
|
+
\`\`\`
|
|
58
|
+
|
|
59
|
+
## Keep partial successes
|
|
60
|
+
|
|
61
|
+
Await Promise.allSettled for independent calls when one failure must not discard
|
|
62
|
+
other answers. Each rejected reason keeps \`code\`, \`message\`, \`retryable\`, and
|
|
63
|
+
\`details\`. Branch on fields, never error prose. Repair one argument failure
|
|
64
|
+
before repeating it across records. Every run reports hostCalls counts separately.
|
|
65
|
+
|
|
66
|
+
After verifying these addresses and schemas, read JSON and plain text together:
|
|
67
|
+
|
|
68
|
+
\`\`\`js
|
|
69
|
+
async () => {
|
|
70
|
+
const settled = await Promise.allSettled([
|
|
71
|
+
connecta.call("ci.get_run", { runId: 42 }),
|
|
72
|
+
connecta.call("ci.get_job_logs", { jobId: "job_7" }),
|
|
73
|
+
connecta.call("ci.get_run", { runId: "wrong-type" })
|
|
74
|
+
]);
|
|
75
|
+
return settled.map(s => s.status === "rejected"
|
|
76
|
+
? { error: s.reason.code, retryable: s.reason.retryable }
|
|
77
|
+
: s.value.format === "text"
|
|
78
|
+
? { text: s.value.data.split("\\n").filter(line => line.startsWith("ERROR")) }
|
|
79
|
+
: { status: s.value.data.status });
|
|
80
|
+
}
|
|
81
|
+
\`\`\`
|
|
82
|
+
|
|
83
|
+
Host-call budget exhaustion ends the run with budget_exceeded. Catch and
|
|
84
|
+
allSettled cannot recover it or return partial output. Bound batches before
|
|
85
|
+
starting them; search, describe, call, result, and skill spend host calls.
|
|
86
|
+
Split remaining reads into another run. Never replay writes for their output.
|
|
87
|
+
|
|
88
|
+
## Per-connector guides
|
|
89
|
+
|
|
90
|
+
Fetch a listed guide with skills by its exact name, or \`connecta.skill(name)\`
|
|
91
|
+
inside a program; it returns \`{ name, text, format: "text" }\`.
|
|
92
|
+
\`guideRequired: true\` is a hard stop. connector_required and approval_required
|
|
93
|
+
remain after schema expansion; schema_truncated clears after exact describe.
|
|
94
|
+
Otherwise fetch for relevant units, pagination, aliases, or sequences.
|
|
95
|
+
|
|
96
|
+
## Large results and recovery
|
|
97
|
+
|
|
98
|
+
A truncated direct result carries a resultId when paging is available. Follow
|
|
99
|
+
nextOffset in UTF-8 bytes, reassemble and reduce inside one program. Use the
|
|
100
|
+
returned id in place of result-id below; this example assumes documented JSON.
|
|
101
|
+
|
|
102
|
+
\`\`\`js
|
|
103
|
+
async () => {
|
|
104
|
+
let text = "", offset = 0, page;
|
|
105
|
+
do {
|
|
106
|
+
page = await connecta.result("result-id", { offset, maxBytes: 8000 });
|
|
107
|
+
text += page.text;
|
|
108
|
+
offset = page.nextOffset;
|
|
109
|
+
} while (page.hasMore);
|
|
110
|
+
return JSON.parse(text).items.map(item => item.id);
|
|
111
|
+
}
|
|
112
|
+
\`\`\`
|
|
113
|
+
|
|
114
|
+
Program returns have no page handle. Reduce reads before returning. After a
|
|
115
|
+
write, use its existing result, check the target, or report the gap.
|
|
116
|
+
write_outcome_unknown means a write was sent without a known answer: check the
|
|
117
|
+
target, never resend automatically. Non-retryable errors require repair.
|
|
118
|
+
Follow typed auth recovery: host_auth_required needs host connection repair;
|
|
119
|
+
downstream_oauth_required or auth_required carries an authorize_connector
|
|
120
|
+
handoff; provider_permission_denied needs the resource owner to grant access.
|
|
121
|
+
|
|
122
|
+
## Output
|
|
123
|
+
|
|
124
|
+
Return reduced JSON. console.log is captured. connecta.emit accepts text, image,
|
|
125
|
+
or audio blocks, works without await, and delivers only after success. Images
|
|
126
|
+
need canonical base64 and image/png, image/jpeg, image/gif, or image/webp.
|
|
127
|
+
Text shares the result cap; the description states block and byte budgets.
|
|
128
|
+
`;
|
|
129
|
+
/** Kept in sync with GuestApi by the declaration test. These are type notation, not runnable JS. */
|
|
130
|
+
export const GUEST_API_DECLARATION = `search(args?: CatalogSearchArgs): Promise<CatalogSearchResult>;
|
|
131
|
+
describe(args?: CatalogDescribeArgs): Promise<{ tools: CatalogDescription[] }>;
|
|
132
|
+
call(address: string, args?: unknown, options?: { timeoutMs?: number }): Promise<GuestResult>;
|
|
133
|
+
call(request: { address: string; args?: unknown; timeoutMs?: number }): Promise<GuestResult>;
|
|
134
|
+
read(uri: string): Promise<GuestResourceResult>;
|
|
135
|
+
result(id: string, options?: { offset?: number; maxBytes?: number }): Promise<GuestResultPage>;
|
|
136
|
+
skill(name: string): Promise<{ name: string; text: string; format: "text" }>;
|
|
137
|
+
emit(block: GuestBlock): 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,
|