@zackbart/connecta 0.28.1 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +788 -5
- package/README.md +62 -42
- 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 +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 +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 +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 +84 -35
- 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 +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 +24 -256
- 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-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.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/{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 +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 +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 +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 +664 -231
- package/documentation/auth.md +936 -546
- 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 +120 -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 +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/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
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
// What an operator may read about a failure: log records and status text.
|
|
2
|
+
// Web-API only — no node: imports here.
|
|
3
|
+
//
|
|
4
|
+
// Inbound identity-provider text never enters operator logs or status, even
|
|
5
|
+
// when it fits a grammar. Activity retains its separate typed actor fields.
|
|
6
|
+
//
|
|
7
|
+
// Threat model. INV-6 here covers records of calls and failures: logs,
|
|
8
|
+
// activity rows, status and statusFor, health, doctor output, and any native
|
|
9
|
+
// runtime output connecta triggers (workerd's console). Text a downstream
|
|
10
|
+
// server, HTTP API, or client authored, and anything derived from it, never
|
|
11
|
+
// reaches one as arbitrary text. Self-declared client name/version facts in
|
|
12
|
+
// activity use the bounded ASCII grammars in activityClientFact; invalid values are
|
|
13
|
+
// absent at recording, SQL write/read, and operator UI boundaries. Client
|
|
14
|
+
// capabilities and other metadata are never recorded. Every typed field
|
|
15
|
+
// connecta records is checked against a closed set or a grammar. Operator-
|
|
16
|
+
// authored code (custom connectors, plugin `status()`, decorators) is trusted
|
|
17
|
+
// to follow the contract, and connecta still checks
|
|
18
|
+
// the typed fields it records from it; deliberately adversarial operator code
|
|
19
|
+
// is out of scope.
|
|
20
|
+
//
|
|
21
|
+
// Catalog metadata a connector serves is configuration the operator chose to
|
|
22
|
+
// load, and agents already see it: a tool name that fits MCP's tool-name
|
|
23
|
+
// grammar, a description, and input and output schemas may appear in the
|
|
24
|
+
// authenticated operator page's catalog views, and such a name may be
|
|
25
|
+
// logged. A name outside the grammar is withheld everywhere operator-facing,
|
|
26
|
+
// the page included. Names containing C0, DEL, or C1 are dropped at catalog
|
|
27
|
+
// intake; spaces and non-ASCII names remain callable with withheld records.
|
|
28
|
+
//
|
|
29
|
+
// INV-6 says logs carry no arguments, results, code, or raw downstream error
|
|
30
|
+
// text. Filtering errors where they arise kept missing sources: a validator's
|
|
31
|
+
// diagnostic, a stream's TypeError, a JSON-RPC error the agent may see. So the
|
|
32
|
+
// rule is enforced here, at the sink. A failure reaches an operator only as
|
|
33
|
+
// the fields of a `FailureRecord`, which `failureRecord` alone builds: each
|
|
34
|
+
// one copied from an explicit list, checked against a constant table or a
|
|
35
|
+
// grammar, and never taken from an error's message, cause, stack, data,
|
|
36
|
+
// nested errors, or name. `logFailure` writes nothing else, and every status
|
|
37
|
+
// message about a failure comes from `describeFailure`
|
|
38
|
+
// (test/operator-record-sources.node.test.ts holds src/ to that).
|
|
39
|
+
//
|
|
40
|
+
// Provenance is by identity, never by shape. Text that merely looks like
|
|
41
|
+
// connecta's (an error named like one of its classes, a status sentence
|
|
42
|
+
// shaped like a record) carries no weight: a class label comes from the
|
|
43
|
+
// prototype chain, a status message from the status object connecta built.
|
|
44
|
+
//
|
|
45
|
+
// Agent-facing results are a different surface with a different rule: a
|
|
46
|
+
// downstream's own answer to a call may reach the agent that made it (see
|
|
47
|
+
// documentation/architecture.md, "Errors and records"). Core's sent-secrets
|
|
48
|
+
// boundary removes credentials used by the upstream request from those answers, including
|
|
49
|
+
// allowed diagnostics, tool results and nested error causes/data (INV-5).
|
|
50
|
+
import { classificationCode, ConnectorCallError, NETWORK_ERROR_CODES, WithheldTextError, } from "./errors.js";
|
|
51
|
+
const STEPS = new Set([
|
|
52
|
+
"MCP handshake",
|
|
53
|
+
"tools/list",
|
|
54
|
+
"tools/call",
|
|
55
|
+
"resources/read",
|
|
56
|
+
"OAuth discovery",
|
|
57
|
+
"OAuth client registration",
|
|
58
|
+
"OAuth token request",
|
|
59
|
+
"OAuth flow",
|
|
60
|
+
"handler",
|
|
61
|
+
]);
|
|
62
|
+
/**
|
|
63
|
+
* Registered OAuth `error` codes: the pinned SDK's `OAuthErrorCode` values
|
|
64
|
+
* (RFC 6749, 6750, 7591, 8707, 9449) and RFC 7591's software-statement pair.
|
|
65
|
+
*/
|
|
66
|
+
export const OAUTH_ERROR_CODES = new Set([
|
|
67
|
+
"invalid_request",
|
|
68
|
+
"invalid_client",
|
|
69
|
+
"invalid_grant",
|
|
70
|
+
"unauthorized_client",
|
|
71
|
+
"unsupported_grant_type",
|
|
72
|
+
"invalid_scope",
|
|
73
|
+
"access_denied",
|
|
74
|
+
"server_error",
|
|
75
|
+
"temporarily_unavailable",
|
|
76
|
+
"unsupported_response_type",
|
|
77
|
+
"unsupported_token_type",
|
|
78
|
+
"invalid_token",
|
|
79
|
+
"method_not_allowed",
|
|
80
|
+
"too_many_requests",
|
|
81
|
+
"invalid_client_metadata",
|
|
82
|
+
"invalid_redirect_uri",
|
|
83
|
+
"insufficient_scope",
|
|
84
|
+
"invalid_target",
|
|
85
|
+
"invalid_dpop_proof",
|
|
86
|
+
"use_dpop_nonce",
|
|
87
|
+
"invalid_software_statement",
|
|
88
|
+
"unapproved_software_statement",
|
|
89
|
+
]);
|
|
90
|
+
const SOURCES = new Set([
|
|
91
|
+
"call_tool",
|
|
92
|
+
"call_destructive_tool",
|
|
93
|
+
"batch_call",
|
|
94
|
+
"execute_code",
|
|
95
|
+
"resume_execution",
|
|
96
|
+
]);
|
|
97
|
+
const MODES = new Set(["continue", "restart"]);
|
|
98
|
+
const STATUS_STATES = new Set(["ok", "auth_required", "credential_required", "error"]);
|
|
99
|
+
/** A status state, or `failed` for a status that could not be read at all. */
|
|
100
|
+
const STATES = new Set([...STATUS_STATES, "failed"]);
|
|
101
|
+
const AUTH_DENIAL_REASONS = new Set([
|
|
102
|
+
"authentication_failed",
|
|
103
|
+
"authorization_header_invalid",
|
|
104
|
+
"token_type_mismatch",
|
|
105
|
+
"oauth_verification_failed",
|
|
106
|
+
"oauth_client_not_allowed",
|
|
107
|
+
"oauth_binding_mismatch",
|
|
108
|
+
"session_origin_mismatch",
|
|
109
|
+
"user_missing",
|
|
110
|
+
"email_lookup_failed",
|
|
111
|
+
"verified_email_invalid",
|
|
112
|
+
"email_domain_denied",
|
|
113
|
+
"gate_denied",
|
|
114
|
+
"gate_failed",
|
|
115
|
+
"pool_not_declared",
|
|
116
|
+
"pool_grant_denied",
|
|
117
|
+
"pool_grant_threw",
|
|
118
|
+
]);
|
|
119
|
+
/** The registry's connector id grammar (src/registry.ts). */
|
|
120
|
+
const CONNECTOR_ID_RE = /^[a-z0-9_-]{1,64}$/;
|
|
121
|
+
/** MCP's tool name grammar (SEP-986). */
|
|
122
|
+
const TOOL_NAME_RE = /^[A-Za-z0-9_.-]{1,128}$/;
|
|
123
|
+
const LABEL_RE = /^[A-Za-z][A-Za-z0-9]{0,63}$/;
|
|
124
|
+
/** What stands in for a name connecta could not vouch for. */
|
|
125
|
+
const UNLISTED_TOOL = "<unlisted>";
|
|
126
|
+
/**
|
|
127
|
+
* A catalog entry whose name breaks MCP's tool-name grammar. MCP does not
|
|
128
|
+
* require that grammar and real servers ship spaced or non-ASCII names, so
|
|
129
|
+
* the catalog keeps such a tool callable (src/connector-access.ts); only its
|
|
130
|
+
* name stays out of records.
|
|
131
|
+
*/
|
|
132
|
+
const WITHHELD_TOOL = "<withheld>";
|
|
133
|
+
const UNKNOWN_CONNECTOR = "<unknown>";
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
// Error class labels, by identity
|
|
136
|
+
/** Prototype → label. Labels are literals in source, never read from an error. */
|
|
137
|
+
const labels = new Map();
|
|
138
|
+
const labelNames = new Set(["DOMException", "AbortError", "TimeoutError"]);
|
|
139
|
+
/**
|
|
140
|
+
* Name `ctor`'s instances `label` in records and fixed text. Call once, at
|
|
141
|
+
* module scope, beside the class. An error whose prototype chain reaches no
|
|
142
|
+
* labelled class has no label; its `name` is never consulted.
|
|
143
|
+
*/
|
|
144
|
+
export function labelErrorClass(ctor, label) {
|
|
145
|
+
if (!LABEL_RE.test(label))
|
|
146
|
+
throw new TypeError(`Invalid error class label "${label}"`);
|
|
147
|
+
labels.set(ctor.prototype, label);
|
|
148
|
+
labelNames.add(label);
|
|
149
|
+
}
|
|
150
|
+
for (const [ctor, label] of [
|
|
151
|
+
[Error, "Error"],
|
|
152
|
+
[TypeError, "TypeError"],
|
|
153
|
+
[RangeError, "RangeError"],
|
|
154
|
+
[SyntaxError, "SyntaxError"],
|
|
155
|
+
[ReferenceError, "ReferenceError"],
|
|
156
|
+
[URIError, "URIError"],
|
|
157
|
+
[EvalError, "EvalError"],
|
|
158
|
+
[AggregateError, "AggregateError"],
|
|
159
|
+
[ConnectorCallError, "ConnectorCallError"],
|
|
160
|
+
[WithheldTextError, "WithheldTextError"],
|
|
161
|
+
]) {
|
|
162
|
+
labelErrorClass(ctor, label);
|
|
163
|
+
}
|
|
164
|
+
/** The two DOMException names a record tells apart; any other is `DOMException`. */
|
|
165
|
+
const DOM_EXCEPTION_LABELS = new Set(["AbortError", "TimeoutError"]);
|
|
166
|
+
/**
|
|
167
|
+
* The label of the nearest labelled class on `failure`'s prototype chain.
|
|
168
|
+
* A genuine DOMException is told as `AbortError` or `TimeoutError` when its
|
|
169
|
+
* name is exactly one of those, else `DOMException`.
|
|
170
|
+
*/
|
|
171
|
+
export function errorLabel(failure) {
|
|
172
|
+
if (failure === null || typeof failure !== "object")
|
|
173
|
+
return undefined;
|
|
174
|
+
try {
|
|
175
|
+
for (let proto = Object.getPrototypeOf(failure); proto !== null; proto = Object.getPrototypeOf(proto)) {
|
|
176
|
+
if (typeof DOMException === "function" && proto === DOMException.prototype) {
|
|
177
|
+
const name = failure.name;
|
|
178
|
+
return DOM_EXCEPTION_LABELS.has(name) ? name : "DOMException";
|
|
179
|
+
}
|
|
180
|
+
const label = labels.get(proto);
|
|
181
|
+
if (label)
|
|
182
|
+
return label;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
// A proxy, or a DOMException-shaped object without its internal slot.
|
|
187
|
+
}
|
|
188
|
+
return undefined;
|
|
189
|
+
}
|
|
190
|
+
function origin(value) {
|
|
191
|
+
if (typeof value !== "string")
|
|
192
|
+
return undefined;
|
|
193
|
+
try {
|
|
194
|
+
const url = new URL(value);
|
|
195
|
+
return (url.protocol === "https:" || url.protocol === "http:") && url.origin.length <= 253 ? url.origin : undefined;
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
return undefined;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
function httpStatus(value) {
|
|
202
|
+
return Number.isInteger(value) && value >= 100 && value <= 599
|
|
203
|
+
? value
|
|
204
|
+
: undefined;
|
|
205
|
+
}
|
|
206
|
+
function member(value, table) {
|
|
207
|
+
return typeof value === "string" && table.has(value) ? value : undefined;
|
|
208
|
+
}
|
|
209
|
+
function checkedFacts(facts) {
|
|
210
|
+
if (!facts)
|
|
211
|
+
return {};
|
|
212
|
+
return {
|
|
213
|
+
...defined("step", member(facts.step, STEPS)),
|
|
214
|
+
...defined("origin", origin(facts.origin)),
|
|
215
|
+
...defined("httpStatus", httpStatus(facts.httpStatus)),
|
|
216
|
+
...defined("oauthError", member(facts.oauthError, OAUTH_ERROR_CODES)),
|
|
217
|
+
...defined("errorClass", member(facts.errorClass, labelNames)),
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
function defined(key, value) {
|
|
221
|
+
return (value === undefined ? {} : { [key]: value });
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Facts attached to failures by identity, never as properties: nothing about
|
|
225
|
+
* the failure's own shape changes, and nothing a caller can see grows.
|
|
226
|
+
*/
|
|
227
|
+
const attached = new WeakMap();
|
|
228
|
+
/** Note what connecta knows about `failure` for any record made of it later. */
|
|
229
|
+
export function attachFailureFacts(failure, facts) {
|
|
230
|
+
if (failure !== null && typeof failure === "object") {
|
|
231
|
+
attached.set(failure, { ...attached.get(failure), ...checkedFacts(facts) });
|
|
232
|
+
}
|
|
233
|
+
return failure;
|
|
234
|
+
}
|
|
235
|
+
/** The facts and class label of `from`, kept for `to` (its classified form, say). */
|
|
236
|
+
export function carryFailureFacts(from, to) {
|
|
237
|
+
if (to === null || typeof to !== "object")
|
|
238
|
+
return to;
|
|
239
|
+
const facts = from !== null && typeof from === "object" ? attached.get(from) : undefined;
|
|
240
|
+
const errorClass = errorLabel(from);
|
|
241
|
+
// A class carried here already (the original behind a rebuilt error) wins.
|
|
242
|
+
const carried = { ...(errorClass ? { errorClass } : {}), ...facts };
|
|
243
|
+
attached.set(to, { ...carried, ...attached.get(to) });
|
|
244
|
+
return to;
|
|
245
|
+
}
|
|
246
|
+
const built = new WeakSet();
|
|
247
|
+
function count(value, max) {
|
|
248
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= max
|
|
249
|
+
? Math.round(value)
|
|
250
|
+
: undefined;
|
|
251
|
+
}
|
|
252
|
+
function connectorId(value) {
|
|
253
|
+
if (value === undefined)
|
|
254
|
+
return undefined;
|
|
255
|
+
return typeof value === "string" && CONNECTOR_ID_RE.test(value) ? value : UNKNOWN_CONNECTOR;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* How an operator record names a catalog entry: its name when it fits MCP's
|
|
259
|
+
* tool-name grammar, else `<withheld>`. Activity rows and the operator page's
|
|
260
|
+
* catalog use it too, so a withheld name appears nowhere an operator reads.
|
|
261
|
+
*/
|
|
262
|
+
export function recordedToolName(entry) {
|
|
263
|
+
return typeof entry.name === "string" && TOOL_NAME_RE.test(entry.name) ? entry.name : WITHHELD_TOOL;
|
|
264
|
+
}
|
|
265
|
+
function checkedSubject(subject) {
|
|
266
|
+
const tool = subject.tool;
|
|
267
|
+
return {
|
|
268
|
+
...defined("reason", member(subject.reason, AUTH_DENIAL_REASONS)),
|
|
269
|
+
...defined("connector", connectorId(subject.connector)),
|
|
270
|
+
...("tool" in subject
|
|
271
|
+
? { tool: tool === null || typeof tool !== "object" ? UNLISTED_TOOL : recordedToolName(tool) }
|
|
272
|
+
: {}),
|
|
273
|
+
...defined("source", member(subject.source, SOURCES)),
|
|
274
|
+
...defined("state", member(subject.state, STATES)),
|
|
275
|
+
...defined("mode", member(subject.mode, MODES)),
|
|
276
|
+
...defined("attempts", count(subject.attempts, 1_000)),
|
|
277
|
+
...defined("durationMs", count(subject.durationMs, 86_400_000)),
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Classifications connecta computed (`CallErrorDetails` it built), by
|
|
282
|
+
* identity. A plain object is read as one only when registered here: a thrown
|
|
283
|
+
* object shaped like a classification is just a thrown object.
|
|
284
|
+
*/
|
|
285
|
+
const classifications = new WeakSet();
|
|
286
|
+
/** Vouch for `details` as a classification connecta itself computed. */
|
|
287
|
+
export function classifiedFailure(details) {
|
|
288
|
+
classifications.add(details);
|
|
289
|
+
return details;
|
|
290
|
+
}
|
|
291
|
+
/** The typed classification `failure` carries. */
|
|
292
|
+
function classification(failure) {
|
|
293
|
+
let typed;
|
|
294
|
+
if (failure instanceof ConnectorCallError)
|
|
295
|
+
typed = failure;
|
|
296
|
+
else if (failure instanceof WithheldTextError) {
|
|
297
|
+
typed = { retryable: failure.retryable, ...(failure.timeout ? { code: "timeout" } : {}) };
|
|
298
|
+
}
|
|
299
|
+
else if (failure !== null && typeof failure === "object" && classifications.has(failure)) {
|
|
300
|
+
typed = failure;
|
|
301
|
+
}
|
|
302
|
+
const details = typed?.details !== null && typeof typed?.details === "object"
|
|
303
|
+
? typed.details
|
|
304
|
+
: undefined;
|
|
305
|
+
return {
|
|
306
|
+
...defined("code", classificationCode(typed?.code)),
|
|
307
|
+
...defined("retryable", typeof typed?.retryable === "boolean" ? typed.retryable : undefined),
|
|
308
|
+
...defined("origin", origin(details?.host)),
|
|
309
|
+
...defined("errno", member(details?.code, NETWORK_ERROR_CODES)),
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* The record of a failure: the subject's listed fields, each checked; the
|
|
314
|
+
* facts attached to the failure; its class label; and the typed
|
|
315
|
+
* classification it carries (a `ConnectorCallError`'s code, retryability,
|
|
316
|
+
* origin, and errno, or those of a `CallErrorDetails` registered with
|
|
317
|
+
* `classifiedFailure`). Never its
|
|
318
|
+
* text, and nothing else from `subject`.
|
|
319
|
+
*/
|
|
320
|
+
export function failureRecord(subject, failure) {
|
|
321
|
+
const facts = failure !== null && typeof failure === "object" ? attached.get(failure) : undefined;
|
|
322
|
+
const errorClass = errorLabel(failure);
|
|
323
|
+
const record = Object.freeze({
|
|
324
|
+
...checkedSubject(subject),
|
|
325
|
+
...classification(failure),
|
|
326
|
+
...(errorClass ? { errorClass } : {}),
|
|
327
|
+
...checkedFacts(facts),
|
|
328
|
+
});
|
|
329
|
+
built.add(record);
|
|
330
|
+
return record;
|
|
331
|
+
}
|
|
332
|
+
/** What is logged in place of a record `failureRecord` did not build. */
|
|
333
|
+
const REJECTED_RECORD = Object.freeze({ record: "<rejected>" });
|
|
334
|
+
/**
|
|
335
|
+
* Log one failure as `[connecta] <event>` and its record. A record
|
|
336
|
+
* `failureRecord` did not build is replaced, whatever its shape, by a fixed
|
|
337
|
+
* `{ record: "<rejected>" }`. Never throws: it runs on failure paths, and a
|
|
338
|
+
* logger that throws is contained here.
|
|
339
|
+
*/
|
|
340
|
+
export function logFailure(logger, event, record, level = "warn") {
|
|
341
|
+
try {
|
|
342
|
+
logger[level](`[connecta] ${event}`, built.has(record) ? record : REJECTED_RECORD);
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
// A failing logger cannot add a failure of its own.
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* A failure in connecta's words, from its record alone:
|
|
350
|
+
* `Connector "<id>" <step> with <origin> failed with HTTP <status> (<class>, <code>, <errno>).`
|
|
351
|
+
* Used for status messages, and for agent-facing text where the error's own
|
|
352
|
+
* may not pass.
|
|
353
|
+
*/
|
|
354
|
+
export function describeFailure(connectorId, failure) {
|
|
355
|
+
const record = failureRecord({ connector: connectorId }, failure);
|
|
356
|
+
const where = record.step
|
|
357
|
+
? ` ${record.step}${record.origin ? ` with ${record.origin}` : ""}`
|
|
358
|
+
: record.origin
|
|
359
|
+
? ` request to ${record.origin}`
|
|
360
|
+
: "";
|
|
361
|
+
const status = record.httpStatus ? ` with HTTP ${record.httpStatus}` : "";
|
|
362
|
+
const oauth = record.oauthError ? ` and OAuth error ${record.oauthError}` : "";
|
|
363
|
+
const kind = [record.errorClass, record.code, record.errno].filter(Boolean).join(", ");
|
|
364
|
+
return `Connector "${record.connector}"${where} failed${status}${oauth}${kind ? ` (${kind})` : ""}.`;
|
|
365
|
+
}
|
|
366
|
+
const ownStatuses = new WeakMap();
|
|
367
|
+
function snapshot(status, failure) {
|
|
368
|
+
return {
|
|
369
|
+
state: member(status.state, STATUS_STATES) ?? "error",
|
|
370
|
+
...(typeof status.message === "string" ? { message: status.message } : {}),
|
|
371
|
+
...(["cimd", "dcr", "static"].includes(status.registrationPath ?? "")
|
|
372
|
+
? { registrationPath: status.registrationPath }
|
|
373
|
+
: {}),
|
|
374
|
+
...(status.resourceTemplateRefusals
|
|
375
|
+
? {
|
|
376
|
+
resourceTemplateRefusals: [
|
|
377
|
+
...new Set(status.resourceTemplateRefusals.filter((code) => code === "resource_template_ambiguous" || code === "resource_match_budget_exceeded")),
|
|
378
|
+
],
|
|
379
|
+
}
|
|
380
|
+
: {}),
|
|
381
|
+
...(failure === undefined ? {} : { failure }),
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
/** A status whose message connecta wrote, such as an auth_required notice. */
|
|
385
|
+
export function ownStatus(status) {
|
|
386
|
+
ownStatuses.set(status, snapshot(status));
|
|
387
|
+
return status;
|
|
388
|
+
}
|
|
389
|
+
/** An error status described from `failure`'s record, remembering the failure. */
|
|
390
|
+
export function failureStatus(connectorId, failure) {
|
|
391
|
+
const status = { state: "error", message: describeFailure(connectorId, failure) };
|
|
392
|
+
ownStatuses.set(status, snapshot(status, failure));
|
|
393
|
+
return status;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* `status` rebuilt from what connecta approved. A status connecta wrote
|
|
397
|
+
* (`ownStatus`, `failureStatus`) is rebuilt from the snapshot taken then,
|
|
398
|
+
* whatever has since been assigned to it. Any other status contributes its
|
|
399
|
+
* typed state alone: a plugin `status()` seam returns its author's text,
|
|
400
|
+
* which can quote a downstream, and connecta cannot vouch for it whatever it
|
|
401
|
+
* looks like.
|
|
402
|
+
*/
|
|
403
|
+
export function boundedStatus(status) {
|
|
404
|
+
const own = status !== null && typeof status === "object" ? ownStatuses.get(status) : undefined;
|
|
405
|
+
if (own) {
|
|
406
|
+
const rebuilt = {
|
|
407
|
+
state: own.state,
|
|
408
|
+
...(own.resourceTemplateRefusals ? { resourceTemplateRefusals: [...own.resourceTemplateRefusals] } : {}),
|
|
409
|
+
...(own.message === undefined ? {} : { message: own.message }),
|
|
410
|
+
...(own.registrationPath === undefined ? {} : { registrationPath: own.registrationPath }),
|
|
411
|
+
};
|
|
412
|
+
ownStatuses.set(rebuilt, own);
|
|
413
|
+
return rebuilt;
|
|
414
|
+
}
|
|
415
|
+
return { state: member(status?.state, STATUS_STATES) ?? "error" };
|
|
416
|
+
}
|
|
417
|
+
/** The failure connecta saw behind a status it described, if any. */
|
|
418
|
+
export function statusFailure(status) {
|
|
419
|
+
return ownStatuses.get(status)?.failure;
|
|
420
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { OPERATOR_UI_ASSETS } from "./generated.js";
|
|
2
|
+
/** Web APIs only: identical bytes and cache semantics on Node and Workers. */
|
|
3
|
+
export function operatorAsset(request, path) {
|
|
4
|
+
if (request.method !== "GET" && request.method !== "HEAD") {
|
|
5
|
+
return new Response(null, { status: 405, headers: { Allow: "GET, HEAD", "Cache-Control": "no-store" } });
|
|
6
|
+
}
|
|
7
|
+
const asset = Object.hasOwn(OPERATOR_UI_ASSETS, path) ? OPERATOR_UI_ASSETS[path] : undefined;
|
|
8
|
+
if (!asset)
|
|
9
|
+
return new Response(request.method === "HEAD" ? null : "Not Found", {
|
|
10
|
+
status: 404,
|
|
11
|
+
headers: { "Cache-Control": "no-store" },
|
|
12
|
+
});
|
|
13
|
+
const headers = {
|
|
14
|
+
"Content-Type": asset.type,
|
|
15
|
+
"Cache-Control": "public, max-age=31536000, immutable",
|
|
16
|
+
"X-Content-Type-Options": "nosniff",
|
|
17
|
+
ETag: `"${path.slice(path.lastIndexOf("/") + 1)}"`,
|
|
18
|
+
};
|
|
19
|
+
if (request.headers
|
|
20
|
+
.get("If-None-Match")
|
|
21
|
+
?.split(",")
|
|
22
|
+
.some((tag) => tag.trim().replace(/^W\//, "") === headers.ETag || tag.trim() === "*")) {
|
|
23
|
+
return new Response(null, { status: 304, headers });
|
|
24
|
+
}
|
|
25
|
+
const body = request.method === "HEAD"
|
|
26
|
+
? null
|
|
27
|
+
: asset.binary
|
|
28
|
+
? Uint8Array.from(atob(asset.body), (char) => char.charCodeAt(0))
|
|
29
|
+
: asset.body;
|
|
30
|
+
return new Response(body, { headers });
|
|
31
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { ActivityOutcome } from "../activity.js";
|
|
2
|
+
import type { ConnectaConfigDescription } from "../describe-config.js";
|
|
3
|
+
import type { ConnectorStatus, ConnectorToolDescription } from "../types.js";
|
|
4
|
+
import type { UiProblem } from "./model.js";
|
|
5
|
+
/** The registry's final verdict, independent of the viewer's pool trust. */
|
|
6
|
+
export interface OperatorTool extends ConnectorToolDescription {
|
|
7
|
+
address: string;
|
|
8
|
+
classification: "read" | "write";
|
|
9
|
+
}
|
|
10
|
+
export interface OperatorLastCall {
|
|
11
|
+
at: string;
|
|
12
|
+
outcome: ActivityOutcome;
|
|
13
|
+
}
|
|
14
|
+
export interface OperatorConnectorOverlay {
|
|
15
|
+
id: string;
|
|
16
|
+
status: ConnectorStatus["state"];
|
|
17
|
+
/** Selected downstream client mechanism, when a client has been selected. */
|
|
18
|
+
auth?: {
|
|
19
|
+
registrationPath: NonNullable<ConnectorStatus["registrationPath"]>;
|
|
20
|
+
};
|
|
21
|
+
problem?: UiProblem;
|
|
22
|
+
tools: OperatorTool[];
|
|
23
|
+
/** Age of the last complete listing. Static or unobserved catalogs have no age. */
|
|
24
|
+
catalogAgeMs: number | null;
|
|
25
|
+
/** Latest visible call in the bounded activity window, or null when unknown. */
|
|
26
|
+
lastCall: OperatorLastCall | null;
|
|
27
|
+
}
|
|
28
|
+
/** Whole connector access, or exact tool grants. Guarded grants still require a live read verdict. */
|
|
29
|
+
export interface OperatorGrant {
|
|
30
|
+
connectorId: string;
|
|
31
|
+
tools: "all" | Array<{
|
|
32
|
+
name: string;
|
|
33
|
+
requireReadOnly: boolean;
|
|
34
|
+
}>;
|
|
35
|
+
}
|
|
36
|
+
export interface OperatorPool {
|
|
37
|
+
name: string;
|
|
38
|
+
path: string;
|
|
39
|
+
trust: "trusted" | "read-only";
|
|
40
|
+
/** Pool access intersected with the caller's grants. */
|
|
41
|
+
grants: OperatorGrant[];
|
|
42
|
+
}
|
|
43
|
+
export interface OperatorViewer {
|
|
44
|
+
interactive: boolean;
|
|
45
|
+
grants: OperatorGrant[];
|
|
46
|
+
/** Trust of the root /mcp endpoint. */
|
|
47
|
+
trust: "trusted" | "read-only";
|
|
48
|
+
pools: OperatorPool[];
|
|
49
|
+
permissions: {
|
|
50
|
+
activity: boolean;
|
|
51
|
+
accessTokenManagement: boolean;
|
|
52
|
+
connectors: Array<{
|
|
53
|
+
id: string;
|
|
54
|
+
use: boolean;
|
|
55
|
+
manageSharedAuth: boolean;
|
|
56
|
+
connectPersonal: boolean;
|
|
57
|
+
}>;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export interface OperatorUiContract {
|
|
61
|
+
schemaVersion: 1;
|
|
62
|
+
/** describeConfig's allowlisted snapshot, restricted to this caller's view. */
|
|
63
|
+
config: ConnectaConfigDescription;
|
|
64
|
+
/** Leaf provenance, built from the same allowlisted snapshot and scoped with it. */
|
|
65
|
+
configSources?: Record<string, "default" | "config">;
|
|
66
|
+
live: {
|
|
67
|
+
connectors: OperatorConnectorOverlay[];
|
|
68
|
+
/** Last-call lookup scans at most 1,000 recent rows. No payload or actor is returned. */
|
|
69
|
+
activity: "available" | "unconfigured" | "forbidden" | "unavailable";
|
|
70
|
+
};
|
|
71
|
+
you: OperatorViewer;
|
|
72
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { UiCredentialProblem, UiProblem } from "./model.js";
|
|
2
|
+
/**
|
|
3
|
+
* Every failure the Connections page can show, with the prompt its "Copy fix
|
|
4
|
+
* prompt" button puts on the clipboard.
|
|
5
|
+
*
|
|
6
|
+
* The signature is the guarantee. A prompt is looked up by kind and may name
|
|
7
|
+
* the connector's configured id; there is no argument an error message, a
|
|
8
|
+
* downstream body, or a credential could travel through, so none can reach a
|
|
9
|
+
* coding agent's context by way of this page. The notice beside it is fixed
|
|
10
|
+
* copy too wherever a downstream could have written the failure (see
|
|
11
|
+
* `refusedNotice` in view.ts); what remains are the page's own sentences and a
|
|
12
|
+
* credential form's field checks.
|
|
13
|
+
*/
|
|
14
|
+
export type FixPromptKind = UiProblem | UiCredentialProblem | "credential_test_failed" | "oauth_action_failed" | "catalog_drift";
|
|
15
|
+
/** The clipboard text for one failure. Fixed by kind; see `CATALOGUE`. */
|
|
16
|
+
export declare function fixPrompt(kind: FixPromptKind, connectorId?: string): string;
|
|
17
|
+
/** Every kind, so a test can walk the whole catalogue. */
|
|
18
|
+
export declare const FIX_PROMPT_KINDS: FixPromptKind[];
|