@zackbart/connecta 0.34.1 → 0.35.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 +363 -0
- package/README.md +62 -106
- package/SECURITY.md +3 -2
- package/bin/connecta.mjs +41 -16
- package/bin/version.mjs +1 -1
- package/dist/access-tokens.d.ts +2 -1
- package/dist/access-tokens.js +66 -30
- package/dist/activity.d.ts +1 -1
- package/dist/activity.js +2 -0
- package/dist/agent-config.d.ts +23 -0
- package/dist/agent-config.js +59 -0
- package/dist/agent-description.js +16 -0
- package/dist/agent-identity.js +4 -4
- package/dist/agent-observation.js +39 -0
- package/dist/auth/clerk-sdk/client.d.ts +2 -0
- package/dist/auth/clerk-sdk/generated.js +554 -563
- package/dist/auth/clerk-transport.js +70 -3
- package/dist/auth/clerk.d.ts +13 -0
- package/dist/auth/clerk.js +653 -246
- package/dist/auth/cloudflare-access.js +46 -42
- package/dist/auth/downstream-client-metadata.js +2 -2
- package/dist/auth/downstream-oauth.js +2051 -1160
- package/dist/auth/downstream-revocation.js +88 -88
- package/dist/auth/native-call.js +20 -0
- package/dist/auth/native.js +184 -0
- package/dist/auth/oauth-start-reset.js +11 -5
- package/dist/auth/oauth-token-response.js +121 -102
- package/dist/auth/oauth-v2-migration.js +97 -78
- package/dist/auth/renewable-grant.js +10 -0
- package/dist/auth/static-oauth.js +663 -271
- package/dist/auth/vercel-agent.js +266 -0
- package/dist/auth-admission.js +204 -0
- package/dist/auth-elicitation.js +350 -241
- package/dist/authorization-handoff.js +164 -90
- package/dist/call-admission-context.js +3 -10
- package/dist/call-admission.js +2 -0
- package/dist/call-classification.js +9 -0
- package/dist/call-recovery.js +32 -13
- package/dist/canonical-json.js +8 -0
- package/dist/catalog-cache.js +369 -213
- package/dist/catalog-service.js +659 -530
- package/dist/catalog.js +5 -1
- package/dist/concurrency.js +0 -25
- package/dist/config-defaults.d.ts +1 -0
- package/dist/config-defaults.js +1 -0
- package/dist/config-schema.d.ts +3 -1
- package/dist/config-schema.js +13 -3
- package/dist/config.d.ts +40 -6
- package/dist/config.js +40 -26
- package/dist/connector-caller.d.ts +4 -0
- package/dist/connector-caller.js +17 -4
- package/dist/connectors/api-connector.d.ts +12 -7
- package/dist/connectors/api-connector.js +142 -56
- package/dist/connectors/guarded-fetch.d.ts +51 -17
- package/dist/connectors/guarded-fetch.js +215 -121
- package/dist/connectors/negotiation-cache.js +20 -10
- package/dist/connectors/remote-mcp.d.ts +10 -30
- package/dist/connectors/remote-mcp.js +955 -563
- package/dist/d1.js +10 -243
- package/dist/derived-context.js +5 -0
- package/dist/describe-config.d.ts +3 -1
- package/dist/describe-config.js +2 -0
- package/dist/downstream-input.js +347 -260
- package/dist/errors.d.ts +87 -6
- package/dist/errors.js +114 -4
- package/dist/execute.js +87 -50
- package/dist/executor-admission.js +3 -0
- package/dist/executors/quickjs.js +163 -112
- package/dist/guarded-transport.js +50 -0
- package/dist/guest-runtime.js +1 -1
- package/dist/http/client.js +439 -0
- package/dist/http/errors.js +558 -0
- package/dist/http/fields.js +49 -0
- package/dist/http/hatch-paging.js +318 -0
- package/dist/http/hatch.js +1279 -0
- package/dist/http/json-schema.js +267 -0
- package/dist/http/node-transport.js +241 -0
- package/dist/http/oauth.js +162 -0
- package/dist/http/paging.js +228 -0
- package/dist/http/provider.js +221 -0
- package/dist/http/safety.js +82 -0
- package/dist/http/services.js +79 -0
- package/dist/http/tools.js +383 -0
- package/dist/http/vendor-index.js +138 -0
- package/dist/http/vendor.js +448 -0
- package/dist/http/write-request.js +66 -0
- package/dist/http-policy.d.ts +11 -0
- package/dist/http-policy.js +45 -0
- package/dist/inbound-credential.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -0
- package/dist/invocation-auth.js +30 -19
- package/dist/invocation.js +218 -85
- package/dist/mcp-result.js +0 -4
- package/dist/membership.d.ts +4 -0
- package/dist/meta-output.js +1 -1
- package/dist/meta-tools.js +531 -406
- package/dist/native-recovery.js +52 -0
- package/dist/native-tools.js +382 -0
- package/dist/node.d.ts +4 -3
- package/dist/node.js +45 -8
- package/dist/oauth-handoff.js +177 -104
- package/dist/oauth-partition.js +6 -20
- package/dist/oauth-sealing.js +6 -7
- package/dist/operation-vocabulary.js +101 -0
- package/dist/operator-record.d.ts +2 -2
- package/dist/operator-record.js +17 -4
- package/dist/operator-ui/agents.d.ts +5 -4
- package/dist/operator-ui/agents.js +17 -7
- package/dist/operator-ui/config-summary.js +5 -4
- package/dist/operator-ui/connection-map.js +7 -5
- package/dist/operator-ui/contract.d.ts +7 -3
- package/dist/operator-ui/endpoints.js +4 -13
- package/dist/operator-ui/fix-prompts.d.ts +1 -1
- package/dist/operator-ui/fix-prompts.js +0 -8
- package/dist/operator-ui/generated.js +3 -3
- package/dist/operator-ui/model.d.ts +2 -3
- package/dist/operator-ui/overview.js +5 -2
- package/dist/operator-ui/setup-commands.js +0 -4
- package/dist/operator-ui/view.d.ts +2 -25
- package/dist/operator-ui/view.js +2 -76
- package/dist/program-writes.js +47 -26
- package/dist/provider-call-facts.d.ts +115 -0
- package/dist/provider-call-facts.js +182 -0
- package/dist/provider-call.d.ts +112 -0
- package/dist/provider-call.js +271 -0
- package/dist/provider.d.ts +65 -31
- package/dist/provider.js +116 -39
- package/dist/providers/_shared/google/hatch.js +91 -0
- package/dist/providers/_shared/google/kit.js +537 -0
- package/dist/providers/_shared/google/result-size.js +15 -2
- package/dist/providers/_shared/google/service-account.d.ts +2 -1
- package/dist/providers/_shared/google/service-account.js +8 -4
- package/dist/providers/_shared/google/workspace.d.ts +6 -210
- package/dist/providers/_shared/google/workspace.js +6 -425
- package/dist/providers/_shared/rest/compact-index.js +86 -0
- package/dist/providers/_shared/rest/dispatch.js +3 -23
- package/dist/providers/_shared/rest/kit.js +546 -0
- package/dist/providers/_shared/rest/operation-index.js +230 -14
- package/dist/providers/_shared/rest/response-media.js +11 -0
- package/dist/providers/_shared/rest/tools.js +101 -78
- package/dist/providers/_shared/rest/value-safety.js +353 -195
- package/dist/providers/_shared/sensitive-fields.js +27 -0
- package/dist/providers/breeze/api.js +584 -0
- package/dist/providers/breeze/index.d.ts +1 -3
- package/dist/providers/breeze/index.js +67 -1420
- package/dist/providers/breeze/openapi.generated.js +60 -0
- package/dist/providers/breeze/skill.generated.js +2 -6
- package/dist/providers/breeze/tools.js +696 -0
- package/dist/providers/ccb/api.js +496 -0
- package/dist/providers/ccb/index.d.ts +15 -37
- package/dist/providers/ccb/index.js +77 -1702
- package/dist/providers/ccb/lib/constants.d.ts +34 -0
- package/dist/providers/ccb/lib/constants.js +74 -0
- package/dist/providers/ccb/lib/guide.js +9 -0
- package/dist/providers/ccb/lib/verdicts.js +387 -0
- package/dist/providers/ccb/openapi.generated.js +397 -0
- package/dist/providers/ccb/safety.js +295 -0
- package/dist/providers/ccb/skill.generated.js +2 -6
- package/dist/providers/ccb/tools.js +853 -0
- package/dist/providers/cloudflare/api.js +1066 -0
- package/dist/providers/cloudflare/index.d.ts +5 -22
- package/dist/providers/cloudflare/index.js +79 -197
- package/dist/providers/cloudflare/lib/config.d.ts +16 -0
- package/dist/providers/cloudflare/lib/config.js +2 -0
- package/dist/providers/cloudflare/lib/discovery.js +29 -0
- package/dist/providers/cloudflare/{graphql.js → lib/graphql.js} +1 -1
- package/dist/providers/cloudflare/lib/hatch.js +103 -0
- package/dist/providers/cloudflare/lib/path-bounds.js +28 -0
- package/dist/providers/cloudflare/lib/response-media.js +75 -0
- package/dist/providers/cloudflare/openapi.generated.js +4 -3
- package/dist/providers/cloudflare/{value-safety.js → safety.js} +487 -0
- package/dist/providers/cloudflare/skill.generated.js +2 -10
- package/dist/providers/cloudflare/tools.js +360 -0
- package/dist/providers/docs/api.js +51 -0
- package/dist/providers/docs/index.d.ts +1 -12
- package/dist/providers/docs/index.js +53 -1165
- package/dist/providers/docs/lib/constants.d.ts +18 -0
- package/dist/providers/docs/lib/constants.js +18 -0
- package/dist/providers/docs/lib/discovery.js +26 -0
- package/dist/providers/docs/lib/requests.js +48 -0
- package/dist/providers/docs/lib/schemas.js +168 -0
- package/dist/providers/docs/openapi.generated.js +16 -0
- package/dist/providers/docs/safety.js +54 -0
- package/dist/providers/docs/skill.generated.js +2 -6
- package/dist/providers/docs/tools.js +802 -0
- package/dist/providers/drive/api.js +177 -0
- package/dist/providers/drive/index.d.ts +1 -12
- package/dist/providers/drive/index.js +38 -1448
- package/dist/providers/drive/lib/constants.d.ts +6 -0
- package/dist/providers/drive/lib/constants.js +6 -0
- package/dist/providers/drive/lib/contracts.js +532 -0
- package/dist/providers/drive/lib/hatch.js +197 -0
- package/dist/providers/drive/openapi.generated.js +77 -0
- package/dist/providers/drive/safety.js +90 -0
- package/dist/providers/drive/skill.generated.js +2 -6
- package/dist/providers/drive/tools.js +1290 -0
- package/dist/providers/forms/api.js +71 -0
- package/dist/providers/forms/index.d.ts +1 -12
- package/dist/providers/forms/index.js +49 -1145
- package/dist/providers/forms/lib/constants.d.ts +14 -0
- package/dist/providers/forms/lib/constants.js +19 -0
- package/dist/providers/forms/lib/hatch.js +72 -0
- package/dist/providers/forms/openapi.generated.js +23 -0
- package/dist/providers/forms/safety.js +34 -0
- package/dist/providers/forms/skill.generated.js +2 -8
- package/dist/providers/forms/tools.js +1024 -0
- package/dist/providers/github/api.js +150 -0
- package/dist/providers/github/index.d.ts +4 -5
- package/dist/providers/github/index.js +30 -87
- package/dist/providers/github/{auth.d.ts → lib/auth.d.ts} +5 -3
- package/dist/providers/github/{auth.js → lib/auth.js} +40 -43
- package/dist/providers/github/lib/discovery.js +132 -0
- package/dist/providers/github/lib/operations.js +58 -0
- package/dist/providers/github/{scope.d.ts → lib/scope.d.ts} +2 -0
- package/dist/providers/github/{scope.js → lib/scope.js} +25 -1
- package/dist/providers/github/openapi.generated.js +1216 -0
- package/dist/providers/github/safety.js +216 -0
- package/dist/providers/github/skill.generated.js +2 -5
- package/dist/providers/github/tools.js +506 -0
- package/dist/providers/gmail/api.js +114 -0
- package/dist/providers/gmail/index.d.ts +1 -12
- package/dist/providers/gmail/index.js +73 -1621
- package/dist/providers/gmail/lib/constants.d.ts +13 -0
- package/dist/providers/gmail/lib/constants.js +16 -0
- package/dist/providers/gmail/lib/index.js +173 -0
- package/dist/providers/gmail/lib/schemas.js +176 -0
- package/dist/providers/gmail/lib/threading.js +120 -0
- package/dist/providers/gmail/openapi.generated.js +92 -0
- package/dist/providers/gmail/safety.js +21 -0
- package/dist/providers/gmail/skill.generated.js +2 -6
- package/dist/providers/gmail/tools.js +1435 -0
- package/dist/providers/overflow/api.js +1008 -0
- package/dist/providers/overflow/index.d.ts +1 -17
- package/dist/providers/overflow/index.js +60 -1488
- package/dist/providers/overflow/skill.generated.js +2 -5
- package/dist/providers/overflow/tools.js +873 -0
- package/dist/providers/planning-center/api.js +467 -0
- package/dist/providers/planning-center/index.d.ts +4 -35
- package/dist/providers/planning-center/index.js +69 -2445
- package/dist/providers/planning-center/lib/constants.d.ts +58 -0
- package/dist/providers/planning-center/lib/constants.js +83 -0
- package/dist/providers/planning-center/lib/discovery.js +40 -0
- package/dist/providers/planning-center/lib/guide.js +39 -0
- package/dist/providers/planning-center/lib/json-api.js +83 -0
- package/dist/providers/planning-center/lib/verdicts.js +1758 -0
- package/dist/providers/planning-center/openapi.generated.js +1764 -0
- package/dist/providers/planning-center/safety.js +188 -0
- package/dist/providers/planning-center/skill.generated.js +2 -27
- package/dist/providers/planning-center/tools.js +1010 -0
- package/dist/providers/sheets/api.js +133 -0
- package/dist/providers/sheets/index.d.ts +4 -16
- package/dist/providers/sheets/index.js +61 -1172
- package/dist/providers/sheets/lib/constants.d.ts +14 -0
- package/dist/providers/sheets/lib/constants.js +14 -0
- package/dist/providers/sheets/lib/hatch.js +163 -0
- package/dist/providers/sheets/lib/requests.js +105 -0
- package/dist/providers/sheets/lib/schemas.js +138 -0
- package/dist/providers/sheets/openapi.generated.js +30 -0
- package/dist/providers/sheets/safety.js +27 -0
- package/dist/providers/sheets/skill.generated.js +2 -7
- package/dist/providers/sheets/tools.js +734 -0
- package/dist/providers/slides/api.js +147 -0
- package/dist/providers/slides/index.d.ts +2 -10
- package/dist/providers/slides/index.js +48 -2555
- package/dist/providers/slides/lib/constants.d.ts +11 -0
- package/dist/providers/slides/lib/constants.js +11 -0
- package/dist/providers/slides/lib/requests.js +60 -0
- package/dist/providers/slides/lib/schemas.js +565 -0
- package/dist/providers/slides/openapi.generated.js +18 -0
- package/dist/providers/slides/skill.generated.js +2 -6
- package/dist/providers/slides/tools.js +1968 -0
- package/dist/providers/stripe/api.js +401 -0
- package/dist/providers/stripe/index.d.ts +5 -27
- package/dist/providers/stripe/index.js +74 -210
- package/dist/providers/stripe/lib/config.d.ts +4 -0
- package/dist/providers/stripe/lib/config.js +2 -0
- package/dist/providers/stripe/openapi.generated.js +4 -3
- package/dist/providers/stripe/{value-safety.js → safety.js} +5 -5
- package/dist/providers/stripe/skill.generated.js +2 -11
- package/dist/providers/stripe/tools.js +77 -0
- package/dist/providers/tithely/api.js +531 -0
- package/dist/providers/tithely/index.d.ts +17 -0
- package/dist/providers/tithely/index.js +86 -965
- package/dist/providers/tithely/skill.generated.js +2 -5
- package/dist/providers/tithely/tools.js +426 -0
- package/dist/providers/vercel/api.js +551 -0
- package/dist/providers/vercel/index.d.ts +9 -25
- package/dist/providers/vercel/index.js +66 -260
- package/dist/providers/vercel/lib/config.d.ts +2 -0
- package/dist/providers/vercel/lib/config.js +2 -0
- package/dist/providers/vercel/lib/index.js +117 -0
- package/dist/providers/vercel/lib/logs.js +100 -0
- package/dist/providers/vercel/lib/pin.js +270 -0
- package/dist/providers/vercel/openapi.generated.js +10 -5
- package/dist/providers/vercel/{value-safety.js → safety.js} +247 -38
- package/dist/providers/vercel/skill.generated.js +2 -7
- package/dist/providers/vercel/tools.js +642 -0
- package/dist/redaction-identity.js +47 -0
- package/dist/redaction-marker.js +125 -0
- package/dist/registry.d.ts +21 -15
- package/dist/registry.js +409 -376
- package/dist/routes/access-tokens.js +1 -1
- package/dist/routes/actor-labels.js +1 -1
- package/dist/routes/connect.js +1 -1
- package/dist/routes/dispatch.js +103 -0
- package/dist/routes/mcp.js +170 -79
- package/dist/routes/oauth.js +3 -1
- package/dist/routes/operator.js +2 -2
- package/dist/routes/shared.d.ts +5 -4
- package/dist/routes/shared.js +244 -177
- package/dist/routes/skills.js +10 -8
- package/dist/routes/ui-config.js +27 -3
- package/dist/routes/ui-data.js +21 -20
- package/dist/routes/ui.js +1 -1
- package/dist/runtime/call-admission.js +0 -26
- package/dist/runtime/call-entry.js +30 -0
- package/dist/runtime/call.js +556 -0
- package/dist/runtime/connector-scope.js +7 -0
- package/dist/runtime/credential-probe.js +34 -0
- package/dist/runtime/executor.js +40 -0
- package/dist/runtime/native-storage.js +63 -0
- package/dist/runtime/registry.js +27 -0
- package/dist/runtime/request-scope.js +72 -0
- package/dist/runtime/run.js +15 -7
- package/dist/runtime/shared-read.js +34 -5
- package/dist/runtime/storage.js +34 -21
- package/dist/sent-secrets.d.ts +194 -37
- package/dist/sent-secrets.js +1743 -340
- package/dist/server.js +5 -56
- package/dist/skills.js +322 -222
- package/dist/sqlite.js +15 -14
- package/dist/storage/d1-copy.js +255 -0
- package/dist/storage/d1-driver.js +15 -0
- package/dist/storage/keys.js +28 -0
- package/dist/storage/sql-driver.js +88 -0
- package/dist/storage/sql-native.js +544 -0
- package/dist/storage/sql-schema.d.ts +6 -0
- package/dist/storage/sql-schema.js +15 -0
- package/dist/storage/sql.d.ts +14 -20
- package/dist/storage/sql.js +29 -535
- package/dist/timeout.js +0 -26
- package/dist/tool-safety.js +20 -10
- package/dist/types.d.ts +7 -109
- package/dist/upward.js +3 -0
- package/dist/usage-guide.js +3 -1
- package/dist/validate.d.ts +4 -2
- package/dist/validate.js +86 -9
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worker.js +312 -292
- package/dist/workspace-subject.js +5 -1
- package/dist/write-outcome.js +454 -34
- package/documentation/README.md +27 -7
- package/documentation/architecture.md +2547 -226
- package/documentation/auth.md +821 -98
- package/documentation/code-mode.md +49 -16
- package/documentation/deploying.md +164 -20
- package/documentation/hosted-mcp-migration.md +460 -0
- package/documentation/integrating.md +129 -144
- package/documentation/meta-tools.md +409 -32
- package/documentation/operating.md +27 -3
- package/documentation/operator-tests.md +3 -0
- package/documentation/operator-ui.md +68 -45
- package/documentation/provider-auth-migration.md +16 -63
- package/documentation/provider-migration-0.29.md +10 -5
- package/documentation/provider-migration-0.35.md +975 -0
- package/documentation/providers.md +965 -0
- package/examples/worker/AGENTS.md +23 -9
- package/examples/worker/README.md +254 -135
- package/examples/worker/alchemy.run.ts +116 -0
- package/examples/worker/gitignore +10 -0
- package/examples/worker/src/connecta.config.ts +23 -21
- package/examples/worker/wrangler.jsonc +14 -5
- package/guides/connecting-agents.md +157 -0
- package/guides/how-it-works.md +156 -0
- package/guides/safety-and-trust.md +153 -0
- package/package.json +27 -46
- package/templates/node/.env.example +3 -0
- package/templates/node/README.md +22 -2
- package/templates/node/docker-compose.yml +1 -0
- package/templates/node/package.json +3 -2
- package/templates/node/src/connecta.config.ts +8 -0
- package/dist/catalog-drift.d.ts +0 -138
- package/dist/catalog-drift.js +0 -578
- package/dist/providers/_shared/request-token.js +0 -83
- package/dist/providers/_shared/rest/operation-index.d.ts +0 -133
- package/dist/providers/_shared/rest/tools.d.ts +0 -141
- package/dist/providers/_shared/rest/value-safety.d.ts +0 -201
- package/dist/providers/basecamp/index.d.ts +0 -45
- package/dist/providers/basecamp/index.js +0 -997
- package/dist/providers/basecamp/skill.generated.js +0 -9
- package/dist/providers/cloudflare/rest.d.ts +0 -37
- package/dist/providers/cloudflare/rest.js +0 -1097
- package/dist/providers/github/hosted.js +0 -218
- package/dist/providers/github/rest.js +0 -321
- package/dist/providers/infisical/index.d.ts +0 -7
- package/dist/providers/infisical/index.js +0 -713
- package/dist/providers/infisical/skill.generated.js +0 -8
- package/dist/providers/intercom/index.d.ts +0 -24
- package/dist/providers/intercom/index.js +0 -121
- package/dist/providers/intercom/skill.generated.js +0 -8
- package/dist/providers/linear/index.d.ts +0 -55
- package/dist/providers/linear/index.js +0 -537
- package/dist/providers/linear/skill.generated.js +0 -8
- package/dist/providers/mixpanel/index.d.ts +0 -59
- package/dist/providers/mixpanel/index.js +0 -472
- package/dist/providers/mixpanel/operations.js +0 -20
- package/dist/providers/mixpanel/rest.js +0 -603
- package/dist/providers/mixpanel/skill.generated.js +0 -10
- package/dist/providers/mixpanel/value-safety.js +0 -16
- package/dist/providers/notion/index.d.ts +0 -67
- package/dist/providers/notion/index.js +0 -368
- package/dist/providers/notion/openapi.generated.js +0 -75
- package/dist/providers/notion/rest.d.ts +0 -24
- package/dist/providers/notion/rest.js +0 -1226
- package/dist/providers/notion/skill.generated.js +0 -11
- package/dist/providers/notion/value-safety.js +0 -56
- package/dist/providers/revenuecat/index.d.ts +0 -51
- package/dist/providers/revenuecat/index.js +0 -697
- package/dist/providers/revenuecat/skill.generated.js +0 -11
- package/dist/providers/stripe/rest.d.ts +0 -14
- package/dist/providers/stripe/rest.js +0 -402
- package/dist/providers/vercel/rest.d.ts +0 -20
- package/dist/providers/vercel/rest.js +0 -1020
- package/dist/providers/wispr-flow/index.d.ts +0 -14
- package/dist/providers/wispr-flow/index.js +0 -117
- package/dist/providers/wispr-flow/skill.generated.js +0 -8
- /package/dist/providers/github/{key.js → lib/key.js} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ConnectaConfigDescription } from "../describe-config.js";
|
|
2
|
+
import type { CatalogAccessObservation, ResourceTemplateRefusalCode } from "../types.js";
|
|
2
3
|
import type { OperatorConnectorOverlay, OperatorTool } from "./contract.js";
|
|
3
|
-
import type { CatalogAccessObservation, CatalogDriftReport, ResourceTemplateRefusalCode } from "../types.js";
|
|
4
4
|
/** Tool verdicts, independent of whether the selected pool is read-only. */
|
|
5
5
|
export type UiToolSafety = "runs_in_programs" | "needs_approval";
|
|
6
6
|
export interface UiTool extends Pick<OperatorTool, "name" | "address" | "description"> {
|
|
@@ -91,7 +91,6 @@ export interface UiConnector {
|
|
|
91
91
|
* drifted — which is why the UI renders that as its own state rather than as
|
|
92
92
|
* a clean one.
|
|
93
93
|
*/
|
|
94
|
-
catalogDrift?: CatalogDriftReport;
|
|
95
94
|
/** Last agent-facing catalog read in this runtime; never persisted. */
|
|
96
95
|
catalogAccess?: CatalogAccessObservation;
|
|
97
96
|
resourceTemplateRefusals?: ResourceTemplateRefusalCode[];
|
|
@@ -114,7 +113,7 @@ export interface UiData {
|
|
|
114
113
|
*/
|
|
115
114
|
pools?: string[];
|
|
116
115
|
}
|
|
117
|
-
|
|
116
|
+
interface FilteredUiConnector {
|
|
118
117
|
connector: UiConnector;
|
|
119
118
|
tools: UiTool[];
|
|
120
119
|
}
|
|
@@ -73,11 +73,14 @@ export function attentionItems(contract, options = {}) {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
const agents = contract.agents
|
|
76
|
-
.filter((agent) => agent.pools.length &&
|
|
76
|
+
.filter((agent) => agent.pools.length &&
|
|
77
|
+
!agent.credentialTypes.includes("vercel_oidc") &&
|
|
78
|
+
agent.token &&
|
|
79
|
+
agent.token.state !== "issued")
|
|
77
80
|
.map((agent) => {
|
|
78
81
|
// An agent connects only at a pool's agent URL.
|
|
79
82
|
const paths = agent.pools.map((name) => contract.pools.find((pool) => pool.name === name)?.agentPath ?? `/agent/${name}`);
|
|
80
|
-
const revoked = agent.token
|
|
83
|
+
const revoked = agent.token?.state === "revoked";
|
|
81
84
|
return {
|
|
82
85
|
key: `agent:${agent.name}`,
|
|
83
86
|
kind: "agent",
|
|
@@ -22,10 +22,6 @@ export function clientServerName(serverName, pool) {
|
|
|
22
22
|
.slice(0, 48) || "connecta";
|
|
23
23
|
return pool ? `${base}-${pool}` : base;
|
|
24
24
|
}
|
|
25
|
-
/** The URL for a pool: `/mcp` plus its name, which config limits to `[a-z0-9_-]`. */
|
|
26
|
-
export function poolEndpointUrl(mcpUrl, pool) {
|
|
27
|
-
return `${mcpUrl.replace(/\/+$/, "")}/${encodeURIComponent(pool)}`;
|
|
28
|
-
}
|
|
29
25
|
/** POSIX single-quoting, only when the value needs it. */
|
|
30
26
|
function shellWord(value) {
|
|
31
27
|
return /^[A-Za-z0-9_./:@%+=,~-]+$/.test(value) ? value : `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
+
import type { AgentSlot } from "./agents.js";
|
|
1
2
|
import type { OperatorRole, OperatorUiContractV2 } from "./contract.js";
|
|
2
|
-
import type { CatalogDriftReport } from "../types.js";
|
|
3
|
-
import type { CredentialManagementCapability, UiConnector, UiData, UiProblem } from "./model.js";
|
|
4
3
|
import type { FixPromptKind } from "./fix-prompts.js";
|
|
5
|
-
import type {
|
|
4
|
+
import type { UiConnector, UiData, UiProblem } from "./model.js";
|
|
6
5
|
export declare function registrationPathLabel(path: NonNullable<UiConnector["registrationPath"]>): string;
|
|
7
6
|
export type OperatorPage = "overview" | "endpoints" | "settings" | "connector" | "tokens" | "connections" | "activity";
|
|
8
7
|
/** Pages the nav lists, in dashboard order. */
|
|
@@ -302,7 +301,6 @@ export declare function resetIdentity(state: OperatorState, gate?: Notice | null
|
|
|
302
301
|
* typed credential, and the notices that answered the page just left.
|
|
303
302
|
*/
|
|
304
303
|
export declare function withPage(state: OperatorState, page: OperatorPage): OperatorState;
|
|
305
|
-
export declare function credentialUnavailableCopy(capability?: CredentialManagementCapability): string;
|
|
306
304
|
/**
|
|
307
305
|
* The status badge. An auth-needed connector is named by what it needs, so a
|
|
308
306
|
* row whose fix is "Add credential" does not say "Authorization needed".
|
|
@@ -342,27 +340,6 @@ export declare function connectorVerdict(live: {
|
|
|
342
340
|
status: string;
|
|
343
341
|
problem?: UiProblem;
|
|
344
342
|
}, signals?: ConnectorSignals): ConnectorVerdict;
|
|
345
|
-
/**
|
|
346
|
-
* Hosted-provider catalog drift, as an operator reads it
|
|
347
|
-
* ([#343](https://github.com/zackbart/connecta/issues/343)).
|
|
348
|
-
*
|
|
349
|
-
* - `unavailable` — no refresh has been observed in this runtime, so there is
|
|
350
|
-
* nothing to report. Deliberately not `clean`: "we have not looked" and "we
|
|
351
|
-
* looked and it matches" are different answers, and only one of them is a
|
|
352
|
-
* reason to stop worrying.
|
|
353
|
-
* - `clean` — a refresh happened and every category counted zero.
|
|
354
|
-
* - `warning` — a refresh happened and at least one category did not.
|
|
355
|
-
*/
|
|
356
|
-
export type DriftState = "clean" | "warning" | "unavailable";
|
|
357
|
-
export declare function driftState(drift?: CatalogDriftReport): DriftState;
|
|
358
|
-
/** Every category with its count, so a clean report still shows its zeros. */
|
|
359
|
-
export declare function driftCounts(drift?: CatalogDriftReport): Array<{
|
|
360
|
-
key: string;
|
|
361
|
-
label: string;
|
|
362
|
-
count: number;
|
|
363
|
-
}>;
|
|
364
|
-
/** One line naming the state and when it was observed. Never what drifted. */
|
|
365
|
-
export declare function driftSummary(drift?: CatalogDriftReport): string;
|
|
366
343
|
/**
|
|
367
344
|
* Only http/https may become a clickable href — the browser half of the gate
|
|
368
345
|
* `src/ui.ts` applies before an authorizationUrl is ever serialized. A hostile
|
package/dist/operator-ui/view.js
CHANGED
|
@@ -345,15 +345,6 @@ export function withPage(state, page) {
|
|
|
345
345
|
confirming: null,
|
|
346
346
|
};
|
|
347
347
|
}
|
|
348
|
-
export function credentialUnavailableCopy(capability) {
|
|
349
|
-
if (capability === "no_slots") {
|
|
350
|
-
return "No connector declares a credential slot. Credentials stay in code.";
|
|
351
|
-
}
|
|
352
|
-
if (capability === "vault_not_configured") {
|
|
353
|
-
return "No credential vault is configured.";
|
|
354
|
-
}
|
|
355
|
-
return "Managing credentials needs an interactive sign-in. A bearer token can only view them.";
|
|
356
|
-
}
|
|
357
348
|
/**
|
|
358
349
|
* The status badge. An auth-needed connector is named by what it needs, so a
|
|
359
350
|
* row whose fix is "Add credential" does not say "Authorization needed".
|
|
@@ -445,73 +436,6 @@ export function connectorVerdict(live, signals = {}) {
|
|
|
445
436
|
}
|
|
446
437
|
return { tone: "ok", label: "Connected", action: null };
|
|
447
438
|
}
|
|
448
|
-
/**
|
|
449
|
-
* The categories, in the order an operator should read them: what the
|
|
450
|
-
* deployment refuses to call, what it can no longer call, what contradicts a
|
|
451
|
-
* vetted verdict, and what changed shape underneath a reviewed schema. Counts
|
|
452
|
-
* only — a name or a schema on this path would be the payload leak the whole
|
|
453
|
-
* drift model exists to avoid.
|
|
454
|
-
*/
|
|
455
|
-
const DRIFT_CATEGORIES = [
|
|
456
|
-
{ key: "unclassifiedTools", label: "Unclassified" },
|
|
457
|
-
{ key: "unservedTools", label: "Unserved" },
|
|
458
|
-
{ key: "annotationConflicts", label: "Annotation conflicts" },
|
|
459
|
-
{ key: "schemaChanges", label: "Schema changes" },
|
|
460
|
-
{ key: "droppedTools", label: "Dropped tool names" },
|
|
461
|
-
];
|
|
462
|
-
function driftTotal(drift) {
|
|
463
|
-
if (!drift)
|
|
464
|
-
return 0;
|
|
465
|
-
return DRIFT_CATEGORIES.reduce((sum, { key }) => sum + (drift[key] || 0), 0);
|
|
466
|
-
}
|
|
467
|
-
export function driftState(drift) {
|
|
468
|
-
if (!drift)
|
|
469
|
-
return "unavailable";
|
|
470
|
-
if (driftTotal(drift) > 0)
|
|
471
|
-
return "warning";
|
|
472
|
-
if (drift.reviewedBaseline !== true ||
|
|
473
|
-
drift.verification !== "complete" ||
|
|
474
|
-
!drift.schemaCoverage ||
|
|
475
|
-
drift.schemaCoverage.unpinned > 0 ||
|
|
476
|
-
drift.schemaCoverage.pinned === 0)
|
|
477
|
-
return "unavailable";
|
|
478
|
-
return "clean";
|
|
479
|
-
}
|
|
480
|
-
/** Every category with its count, so a clean report still shows its zeros. */
|
|
481
|
-
export function driftCounts(drift) {
|
|
482
|
-
if (!drift)
|
|
483
|
-
return [];
|
|
484
|
-
return DRIFT_CATEGORIES.filter(({ key }) => key !== "droppedTools" || drift.droppedTools !== undefined).map(({ key, label }) => ({
|
|
485
|
-
key,
|
|
486
|
-
label,
|
|
487
|
-
count: drift[key] || 0,
|
|
488
|
-
}));
|
|
489
|
-
}
|
|
490
|
-
/** One line naming the state and when it was observed. Never what drifted. */
|
|
491
|
-
export function driftSummary(drift) {
|
|
492
|
-
if (!drift)
|
|
493
|
-
return "No catalog refresh yet.";
|
|
494
|
-
const observed = formatDate(drift.observedAt);
|
|
495
|
-
const when = observed ? ` · observed ${observed}` : "";
|
|
496
|
-
const total = driftTotal(drift);
|
|
497
|
-
const difference = total
|
|
498
|
-
? `${total} difference${total === 1 ? "" : "s"}${drift.reviewedBaseline === false ? "" : " from the reviewed manifest"} · `
|
|
499
|
-
: "";
|
|
500
|
-
if (drift.reviewedBaseline === false)
|
|
501
|
-
return `${difference}No reviewed baseline${when}`;
|
|
502
|
-
if (drift.verification === "unavailable")
|
|
503
|
-
return `${difference}Schema verification unavailable${when}`;
|
|
504
|
-
const coverage = drift.schemaCoverage;
|
|
505
|
-
if (!coverage || coverage.pinned === 0)
|
|
506
|
-
return `${difference}Schemas not pinned${when}`;
|
|
507
|
-
if (coverage.unpinned > 0)
|
|
508
|
-
return `${difference}Partial schema coverage (${coverage.pinned} pinned, ${coverage.unpinned} not pinned)${when}`;
|
|
509
|
-
if (driftState(drift) === "clean")
|
|
510
|
-
return `Matches the reviewed manifest${when}`;
|
|
511
|
-
if (!total)
|
|
512
|
-
return `Schema verification unavailable${when}`;
|
|
513
|
-
return `${difference.replace(/ · $/, "")}${when}`;
|
|
514
|
-
}
|
|
515
439
|
/**
|
|
516
440
|
* Only http/https may become a clickable href — the browser half of the gate
|
|
517
441
|
* `src/ui.ts` applies before an authorizationUrl is ever serialized. A hostile
|
|
@@ -546,6 +470,7 @@ const ACTOR_KINDS = {
|
|
|
546
470
|
"cloudflare-access": "Cloudflare Access",
|
|
547
471
|
anonymous: "Anonymous",
|
|
548
472
|
access_token: "Agent token",
|
|
473
|
+
vercel_oidc: "Vercel workload",
|
|
549
474
|
};
|
|
550
475
|
/** How a caller signed in, as a person reads it. An unknown kind is shown as sent. */
|
|
551
476
|
function actorKindLabel(kind) {
|
|
@@ -628,6 +553,7 @@ export function activityOutcomeBadge(outcome) {
|
|
|
628
553
|
return OUTCOME_BADGE[outcome] ?? { label: "Failed", tone: "danger" };
|
|
629
554
|
}
|
|
630
555
|
const SOURCE_LABELS = {
|
|
556
|
+
native: "Native tool call",
|
|
631
557
|
execute_code: "In a program",
|
|
632
558
|
call_tool: "Direct call",
|
|
633
559
|
call_destructive_tool: "Direct call, approved by the host",
|
package/dist/program-writes.js
CHANGED
|
@@ -17,28 +17,38 @@ export function writeStateOf(outcome) {
|
|
|
17
17
|
error: outcome.error,
|
|
18
18
|
...(outcome.answered !== undefined ? { answered: outcome.answered } : {}),
|
|
19
19
|
});
|
|
20
|
-
|
|
20
|
+
if (state !== "unknown" || outcome.ok)
|
|
21
|
+
return state;
|
|
22
|
+
const { error } = outcome;
|
|
23
|
+
const handoff = (error.code === "auth_required" || error.code === "downstream_oauth_required") &&
|
|
24
|
+
error.nextAction &&
|
|
25
|
+
"tool" in error.nextAction &&
|
|
26
|
+
error.nextAction.tool === "authorize_connector"
|
|
21
27
|
? {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
...(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
...(outcome.error.details.operation !== undefined
|
|
28
|
-
? { operation: outcome.error.details.operation }
|
|
29
|
-
: {}),
|
|
30
|
-
stage: outcome.error.details.stage,
|
|
31
|
-
...(outcome.error.details.elapsedMs !== undefined
|
|
32
|
-
? { elapsedMs: outcome.error.details.elapsedMs }
|
|
33
|
-
: {}),
|
|
34
|
-
...(outcome.error.details.deadlineMs !== undefined
|
|
35
|
-
? { deadlineMs: outcome.error.details.deadlineMs }
|
|
36
|
-
: {}),
|
|
37
|
-
},
|
|
38
|
-
}
|
|
39
|
-
: {}),
|
|
28
|
+
code: error.code,
|
|
29
|
+
...(error.connector !== undefined ? { connector: error.connector } : {}),
|
|
30
|
+
...(error.recovery !== undefined ? { recovery: error.recovery } : {}),
|
|
31
|
+
nextAction: error.nextAction,
|
|
32
|
+
...(error.retry !== undefined ? { retry: error.retry } : {}),
|
|
40
33
|
}
|
|
41
|
-
:
|
|
34
|
+
: undefined;
|
|
35
|
+
if (!error.uncertainCall && !handoff)
|
|
36
|
+
return state;
|
|
37
|
+
return {
|
|
38
|
+
state,
|
|
39
|
+
...(error.uncertainCall ? { uncertainCall: error.uncertainCall } : {}),
|
|
40
|
+
...(error.uncertainCall && error.details?.stage !== undefined
|
|
41
|
+
? {
|
|
42
|
+
deadline: {
|
|
43
|
+
...(error.details.operation !== undefined ? { operation: error.details.operation } : {}),
|
|
44
|
+
stage: error.details.stage,
|
|
45
|
+
...(error.details.elapsedMs !== undefined ? { elapsedMs: error.details.elapsedMs } : {}),
|
|
46
|
+
...(error.details.deadlineMs !== undefined ? { deadlineMs: error.details.deadlineMs } : {}),
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
: {}),
|
|
50
|
+
...(handoff ? { handoff } : {}),
|
|
51
|
+
};
|
|
42
52
|
}
|
|
43
53
|
/**
|
|
44
54
|
* The writes one program sends. The play closes this when the
|
|
@@ -55,6 +65,7 @@ export class ProgramWrites {
|
|
|
55
65
|
uncertainCalls = [];
|
|
56
66
|
uncertainCallsTruncated = false;
|
|
57
67
|
deadlines = [];
|
|
68
|
+
handoff;
|
|
58
69
|
/** Whether the program has settled: a write gated now is not sent. */
|
|
59
70
|
get isClosed() {
|
|
60
71
|
return this.closed;
|
|
@@ -80,12 +91,15 @@ export class ProgramWrites {
|
|
|
80
91
|
recorded = true;
|
|
81
92
|
const state = typeof completion === "string" ? completion : completion.state;
|
|
82
93
|
if (typeof completion !== "string") {
|
|
83
|
-
if (
|
|
84
|
-
this.uncertainCalls.
|
|
85
|
-
|
|
86
|
-
|
|
94
|
+
if (completion.uncertainCall) {
|
|
95
|
+
if (this.uncertainCalls.length < 10)
|
|
96
|
+
this.uncertainCalls.push(completion.uncertainCall);
|
|
97
|
+
else
|
|
98
|
+
this.uncertainCallsTruncated = true;
|
|
99
|
+
}
|
|
87
100
|
if (completion.deadline && this.deadlines.length < 10)
|
|
88
101
|
this.deadlines.push(completion.deadline);
|
|
102
|
+
this.handoff ??= completion.handoff;
|
|
89
103
|
}
|
|
90
104
|
this.states.push(state);
|
|
91
105
|
this.inFlight.delete(settled);
|
|
@@ -108,10 +122,17 @@ export class ProgramWrites {
|
|
|
108
122
|
unknown: this.states.filter((state) => state === "unknown").length,
|
|
109
123
|
};
|
|
110
124
|
if (writes.unknown > 0) {
|
|
125
|
+
// Caught or not, an authorization verdict a write met after it left is
|
|
126
|
+
// the result, as a direct call reports it: its code and handoff, never
|
|
127
|
+
// retryable, with the write's outcome unknown.
|
|
128
|
+
const handoff = this.handoff;
|
|
111
129
|
return errorEnvelope({
|
|
112
|
-
code: "write_outcome_unknown",
|
|
113
|
-
message:
|
|
130
|
+
code: handoff?.code ?? "write_outcome_unknown",
|
|
131
|
+
message: handoff
|
|
132
|
+
? "A write this program sent failed authorization after it left, so whether it took effect is unknown, and that is the result rather than what the program returned. It will not be sent again. Check its target before doing anything that depends on it, and give nextAction to the operator to recover the connector. Argument echoes may be partial or absent; use the original arguments if reconciliation requires another call."
|
|
133
|
+
: "A write this program sent has no known outcome, so that is the result rather than what the program returned. It will not be sent again. Check its target before doing anything that depends on it. Argument echoes may be partial or absent; use the original arguments if reconciliation requires another call.",
|
|
114
134
|
retryable: false,
|
|
135
|
+
...(handoff ? { ...handoff, reconciliationRequired: true, writeOutcome: "unknown" } : {}),
|
|
115
136
|
...(this.deadlines.length > 0 ? { details: this.deadlines[0] } : {}),
|
|
116
137
|
...(this.deadlines.length > 1 ? { timeouts: this.deadlines } : {}),
|
|
117
138
|
...(this.uncertainCalls.length === 1
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { ConnectorCallError } from "./errors.js";
|
|
2
|
+
import type { Connector } from "./types.js";
|
|
3
|
+
export interface ProviderRequest {
|
|
4
|
+
readonly dispatched: boolean;
|
|
5
|
+
readonly status?: number;
|
|
6
|
+
auxiliary: boolean;
|
|
7
|
+
/** A kit auxiliary declared as a read lacked physical GET/HEAD proof at dispatch. */
|
|
8
|
+
readonly blocksAuxiliaryProof?: true;
|
|
9
|
+
provider: string;
|
|
10
|
+
/** The HTTP method it was sent with, when its channel knows it. */
|
|
11
|
+
readonly method?: string;
|
|
12
|
+
/** Positive operation/tool evidence; an HTTP method alone proves no read. */
|
|
13
|
+
classification?: "read" | "write" | undefined;
|
|
14
|
+
/** Remote MCP's source class said write, recorded at physical dispatch. */
|
|
15
|
+
readonly sourceWrite?: true;
|
|
16
|
+
/** The genuine, legal idempotency key the vendor honors that it carried; nothing else. */
|
|
17
|
+
key?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Its answer was a 401 that the transport's reviewed `authBeforeExecution`
|
|
20
|
+
* evidence covers: the vendor rejected the credential before it acted on
|
|
21
|
+
* the request. Only that makes a 401 a refusal (`servedRefusal`).
|
|
22
|
+
*/
|
|
23
|
+
authBeforeExecution?: true;
|
|
24
|
+
/**
|
|
25
|
+
* Its answer was a 401, and a renewal then replaced the credential it sent
|
|
26
|
+
* with a different one ({@link renewedAfterUnauthorized}). The 401 no
|
|
27
|
+
* longer needs the operator's recovery. The single `settleWrite` decider
|
|
28
|
+
* still reports unknown, without the handoff (Q8).
|
|
29
|
+
*/
|
|
30
|
+
readonly renewed?: true;
|
|
31
|
+
}
|
|
32
|
+
export type CallTool = Connector["callTool"];
|
|
33
|
+
interface Boundary {
|
|
34
|
+
/** The api() or remoteMcp() object whose own code enters the logical call. */
|
|
35
|
+
boundary: object;
|
|
36
|
+
own: CallTool;
|
|
37
|
+
}
|
|
38
|
+
export declare function originalCallIdentity(connector: object): object;
|
|
39
|
+
export declare function boundaryFor(connector: object): Boundary | undefined;
|
|
40
|
+
export declare function delegatorFor(connector: object): CallTool | undefined;
|
|
41
|
+
/** A physical send owns its fields permanently; its own answer is recorded once. */
|
|
42
|
+
export declare function recordRequestField(request: ProviderRequest, field: keyof ProviderRequest, value: unknown): void;
|
|
43
|
+
export declare function recordProviderResponse(request: ProviderRequest, status: number): void;
|
|
44
|
+
/**
|
|
45
|
+
* Declare that every request the connector's handlers send goes through a
|
|
46
|
+
* channel the call ledger records: a guarded transport, `ctx.fetch`, or
|
|
47
|
+
* `ctx.oauth.fetch`. Only then does an empty ledger prove that a failed
|
|
48
|
+
* write never left. Maintained providers declare it; an arbitrary `api()`
|
|
49
|
+
* handler can reach the network some other way, so its ledger proves nothing.
|
|
50
|
+
*/
|
|
51
|
+
export declare function tracksEveryRequest<T extends object>(connector: T): T;
|
|
52
|
+
export declare function tracksRequests(connector: object): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Declare a maintained connector whose `callTool` hands each call to at most
|
|
55
|
+
* one api() or remoteMcp() boundary and sends nothing else that could apply
|
|
56
|
+
* it (GitHub). Only then may that boundary's verdict stand for the call. The
|
|
57
|
+
* object and its function are recorded now, at construction: a later
|
|
58
|
+
* assignment to the property, or a copy of the object, declares nothing.
|
|
59
|
+
*/
|
|
60
|
+
export declare function delegatesEachCall<T extends Connector>(connector: T): T;
|
|
61
|
+
/**
|
|
62
|
+
* Record a just-built api() or remoteMcp() object as a boundary, with its
|
|
63
|
+
* published `callTool`. Its own code then names the same object, from its
|
|
64
|
+
* closure, in {@link enterProviderBoundary}.
|
|
65
|
+
*/
|
|
66
|
+
export declare function providerBoundary(connector: Connector): void;
|
|
67
|
+
/**
|
|
68
|
+
* `alias` serves `base` itself (`defineProvider`'s inheriting stamp), so it
|
|
69
|
+
* takes `base`'s recorded identities. Only construction code calls this.
|
|
70
|
+
*/
|
|
71
|
+
export declare function aliasCallIdentity(alias: object, base: object): void;
|
|
72
|
+
/**
|
|
73
|
+
* Whether a served HTTP status says the request was refused, not applied: a
|
|
74
|
+
* 4xx other than 408. A 408 is a timeout, whose request may have been acted
|
|
75
|
+
* on; a 2xx or 5xx never proves a write unapplied. A 401 passes here, and
|
|
76
|
+
* `servedRefusal` still asks for the vendor's reviewed evidence.
|
|
77
|
+
*/
|
|
78
|
+
export declare function refusedStatus(status: number | undefined): boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Refusal provenance, recorded where the answer is observed: the request was
|
|
81
|
+
* served a refusing status (`refusedStatus`) and the mapper failed on it. An
|
|
82
|
+
* error code alone is never this evidence.
|
|
83
|
+
*/
|
|
84
|
+
export declare function vendorRefusal<T>(error: T, request: ProviderRequest): T;
|
|
85
|
+
/** An authorization verdict, the kind that keeps the `authorize_connector` handoff. */
|
|
86
|
+
export declare function authorizationFailure(error: unknown): error is ConnectorCallError;
|
|
87
|
+
/**
|
|
88
|
+
* The authorization verdict `request`'s own 401 answer was mapped to, as
|
|
89
|
+
* {@link vendorRefusal} recorded it. Undefined when nothing mapped that
|
|
90
|
+
* answer, such as a body past the ceiling.
|
|
91
|
+
*/
|
|
92
|
+
export declare function unauthorizedAnswer(request: ProviderRequest): ConnectorCallError | undefined;
|
|
93
|
+
/**
|
|
94
|
+
* A renewal answered `request`'s own 401 (a refresh, a login, a fresh token
|
|
95
|
+
* minted) with `fresh`, a credential other than `sent`, the one the request
|
|
96
|
+
* carried: that 401 no longer needs the operator's recovery (Q8). It names
|
|
97
|
+
* the one request it answered and never marks another. A renewal that hands
|
|
98
|
+
* back the credential the request already sent (an earlier recovery reused)
|
|
99
|
+
* renewed nothing.
|
|
100
|
+
*/
|
|
101
|
+
export declare function renewedAfterUnauthorized(request: ProviderRequest | undefined, sent: string, fresh: string): void;
|
|
102
|
+
export declare function refusalRequest(error: unknown): ProviderRequest | undefined;
|
|
103
|
+
export declare function knownProviderFailure<T>(error: T): T;
|
|
104
|
+
export declare function isKnownProviderFailure(error: unknown): boolean;
|
|
105
|
+
/** Withdraw a verdict that does not hold for the call that reports it. */
|
|
106
|
+
export declare function forgetProviderFailure(error: object): void;
|
|
107
|
+
/** Preserve internal verdicts and resend advice through redaction and provider recovery wording. */
|
|
108
|
+
export declare function carryProviderFailure<T>(from: unknown, to: T): T;
|
|
109
|
+
/** Mark a verdict that already accounts for a write's 401 in its own words. */
|
|
110
|
+
export declare function explainedUnauthorizedVerdict<T>(error: T): T;
|
|
111
|
+
export declare function explainsUnauthorized(error: unknown): boolean;
|
|
112
|
+
/** Mark a verdict the Q8 decision made, final for every step after it. */
|
|
113
|
+
export declare function settledWrite<T>(error: T): T;
|
|
114
|
+
export declare function isSettledWrite(error: unknown): boolean;
|
|
115
|
+
export {};
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// Pure physical-request facts, failure provenance and construction identities.
|
|
2
|
+
// No operation/call services or transport graph: provider definitions and
|
|
3
|
+
// operator sinks can preserve provenance without acquiring Effect.
|
|
4
|
+
import { carryResendAdvice, ConnectorCallError } from "./errors.js";
|
|
5
|
+
import { followRedactedCopies } from "./redaction-identity.js";
|
|
6
|
+
// A redacted copy of a failure is the same failure: its verdict follows it.
|
|
7
|
+
const refusals = followRedactedCopies(new WeakMap());
|
|
8
|
+
const knownFailures = followRedactedCopies(new WeakSet());
|
|
9
|
+
// Verdicts that already account for a write's 401 in words of their own: a
|
|
10
|
+
// renewal's (`unsentAfterUnauthorized`) or Q8's own. Q8 adds no sentence to them.
|
|
11
|
+
const explainedUnauthorized = followRedactedCopies(new WeakSet());
|
|
12
|
+
// Verdicts the one Q8 decision (`settleWrite`) made. They are final: nothing
|
|
13
|
+
// after it may add retry, resend, key-reuse or wait advice to them.
|
|
14
|
+
const settledWrites = followRedactedCopies(new WeakSet());
|
|
15
|
+
// The authorization verdict a request's own 401 was mapped to, kept for the
|
|
16
|
+
// call's verdict whatever failure surfaces after it (Q8).
|
|
17
|
+
const unauthorizedAnswers = new WeakMap();
|
|
18
|
+
const trackedConnectors = new WeakSet();
|
|
19
|
+
const boundaries = new WeakMap();
|
|
20
|
+
const delegators = new WeakMap();
|
|
21
|
+
const aliases = new WeakMap();
|
|
22
|
+
export function originalCallIdentity(connector) {
|
|
23
|
+
return aliases.get(connector) ?? connector;
|
|
24
|
+
}
|
|
25
|
+
export function boundaryFor(connector) {
|
|
26
|
+
return boundaries.get(connector);
|
|
27
|
+
}
|
|
28
|
+
export function delegatorFor(connector) {
|
|
29
|
+
return delegators.get(connector);
|
|
30
|
+
}
|
|
31
|
+
/** A physical send owns its fields permanently; its own answer is recorded once. */
|
|
32
|
+
export function recordRequestField(request, field, value) {
|
|
33
|
+
Object.defineProperty(request, field, { value, enumerable: true, writable: false, configurable: false });
|
|
34
|
+
}
|
|
35
|
+
export function recordProviderResponse(request, status) {
|
|
36
|
+
if (request.status !== undefined)
|
|
37
|
+
throw new Error("Provider request already answered.");
|
|
38
|
+
recordRequestField(request, "status", status);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Declare that every request the connector's handlers send goes through a
|
|
42
|
+
* channel the call ledger records: a guarded transport, `ctx.fetch`, or
|
|
43
|
+
* `ctx.oauth.fetch`. Only then does an empty ledger prove that a failed
|
|
44
|
+
* write never left. Maintained providers declare it; an arbitrary `api()`
|
|
45
|
+
* handler can reach the network some other way, so its ledger proves nothing.
|
|
46
|
+
*/
|
|
47
|
+
export function tracksEveryRequest(connector) {
|
|
48
|
+
trackedConnectors.add(connector);
|
|
49
|
+
return connector;
|
|
50
|
+
}
|
|
51
|
+
export function tracksRequests(connector) {
|
|
52
|
+
return trackedConnectors.has(connector);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Declare a maintained connector whose `callTool` hands each call to at most
|
|
56
|
+
* one api() or remoteMcp() boundary and sends nothing else that could apply
|
|
57
|
+
* it (GitHub). Only then may that boundary's verdict stand for the call. The
|
|
58
|
+
* object and its function are recorded now, at construction: a later
|
|
59
|
+
* assignment to the property, or a copy of the object, declares nothing.
|
|
60
|
+
*/
|
|
61
|
+
export function delegatesEachCall(connector) {
|
|
62
|
+
delegators.set(connector, connector.callTool);
|
|
63
|
+
return connector;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Record a just-built api() or remoteMcp() object as a boundary, with its
|
|
67
|
+
* published `callTool`. Its own code then names the same object, from its
|
|
68
|
+
* closure, in {@link enterProviderBoundary}.
|
|
69
|
+
*/
|
|
70
|
+
export function providerBoundary(connector) {
|
|
71
|
+
boundaries.set(connector, { boundary: connector, own: connector.callTool });
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* `alias` serves `base` itself (`defineProvider`'s inheriting stamp), so it
|
|
75
|
+
* takes `base`'s recorded identities. Only construction code calls this.
|
|
76
|
+
*/
|
|
77
|
+
export function aliasCallIdentity(alias, base) {
|
|
78
|
+
aliases.set(alias, originalCallIdentity(base));
|
|
79
|
+
const boundary = boundaries.get(base);
|
|
80
|
+
const delegator = delegators.get(base);
|
|
81
|
+
if (boundary)
|
|
82
|
+
boundaries.set(alias, boundary);
|
|
83
|
+
if (delegator)
|
|
84
|
+
delegators.set(alias, delegator);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Whether a served HTTP status says the request was refused, not applied: a
|
|
88
|
+
* 4xx other than 408. A 408 is a timeout, whose request may have been acted
|
|
89
|
+
* on; a 2xx or 5xx never proves a write unapplied. A 401 passes here, and
|
|
90
|
+
* `servedRefusal` still asks for the vendor's reviewed evidence.
|
|
91
|
+
*/
|
|
92
|
+
export function refusedStatus(status) {
|
|
93
|
+
return status !== undefined && status >= 400 && status < 500 && status !== 408;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Refusal provenance, recorded where the answer is observed: the request was
|
|
97
|
+
* served a refusing status (`refusedStatus`) and the mapper failed on it. An
|
|
98
|
+
* error code alone is never this evidence.
|
|
99
|
+
*/
|
|
100
|
+
export function vendorRefusal(error, request) {
|
|
101
|
+
if (error !== null && typeof error === "object" && refusedStatus(request.status)) {
|
|
102
|
+
refusals.set(error, request);
|
|
103
|
+
if (request.status === 401 && authorizationFailure(error) && !unauthorizedAnswers.has(request))
|
|
104
|
+
unauthorizedAnswers.set(request, error);
|
|
105
|
+
}
|
|
106
|
+
return error;
|
|
107
|
+
}
|
|
108
|
+
/** An authorization verdict, the kind that keeps the `authorize_connector` handoff. */
|
|
109
|
+
export function authorizationFailure(error) {
|
|
110
|
+
return (error instanceof ConnectorCallError &&
|
|
111
|
+
(error.code === "auth_required" || error.code === "downstream_oauth_required"));
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The authorization verdict `request`'s own 401 answer was mapped to, as
|
|
115
|
+
* {@link vendorRefusal} recorded it. Undefined when nothing mapped that
|
|
116
|
+
* answer, such as a body past the ceiling.
|
|
117
|
+
*/
|
|
118
|
+
export function unauthorizedAnswer(request) {
|
|
119
|
+
return unauthorizedAnswers.get(request);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* A renewal answered `request`'s own 401 (a refresh, a login, a fresh token
|
|
123
|
+
* minted) with `fresh`, a credential other than `sent`, the one the request
|
|
124
|
+
* carried: that 401 no longer needs the operator's recovery (Q8). It names
|
|
125
|
+
* the one request it answered and never marks another. A renewal that hands
|
|
126
|
+
* back the credential the request already sent (an earlier recovery reused)
|
|
127
|
+
* renewed nothing.
|
|
128
|
+
*/
|
|
129
|
+
export function renewedAfterUnauthorized(request, sent, fresh) {
|
|
130
|
+
if (request?.status === 401 && fresh !== sent && !request.renewed)
|
|
131
|
+
recordRequestField(request, "renewed", true);
|
|
132
|
+
}
|
|
133
|
+
export function refusalRequest(error) {
|
|
134
|
+
return error !== null && typeof error === "object" ? refusals.get(error) : undefined;
|
|
135
|
+
}
|
|
136
|
+
export function knownProviderFailure(error) {
|
|
137
|
+
if (error !== null && typeof error === "object")
|
|
138
|
+
knownFailures.add(error);
|
|
139
|
+
return error;
|
|
140
|
+
}
|
|
141
|
+
export function isKnownProviderFailure(error) {
|
|
142
|
+
return error !== null && typeof error === "object" && knownFailures.has(error);
|
|
143
|
+
}
|
|
144
|
+
/** Withdraw a verdict that does not hold for the call that reports it. */
|
|
145
|
+
export function forgetProviderFailure(error) {
|
|
146
|
+
knownFailures.delete(error);
|
|
147
|
+
refusals.delete(error);
|
|
148
|
+
}
|
|
149
|
+
/** Preserve internal verdicts and resend advice through redaction and provider recovery wording. */
|
|
150
|
+
export function carryProviderFailure(from, to) {
|
|
151
|
+
if (to !== null && typeof to === "object") {
|
|
152
|
+
const refusal = refusalRequest(from);
|
|
153
|
+
if (refusal)
|
|
154
|
+
refusals.set(to, refusal);
|
|
155
|
+
if (isKnownProviderFailure(from))
|
|
156
|
+
knownFailures.add(to);
|
|
157
|
+
if (explainsUnauthorized(from))
|
|
158
|
+
explainedUnauthorized.add(to);
|
|
159
|
+
if (isSettledWrite(from))
|
|
160
|
+
settledWrites.add(to);
|
|
161
|
+
carryResendAdvice(from, to);
|
|
162
|
+
}
|
|
163
|
+
return to;
|
|
164
|
+
}
|
|
165
|
+
/** Mark a verdict that already accounts for a write's 401 in its own words. */
|
|
166
|
+
export function explainedUnauthorizedVerdict(error) {
|
|
167
|
+
if (error !== null && typeof error === "object")
|
|
168
|
+
explainedUnauthorized.add(error);
|
|
169
|
+
return error;
|
|
170
|
+
}
|
|
171
|
+
export function explainsUnauthorized(error) {
|
|
172
|
+
return error !== null && typeof error === "object" && explainedUnauthorized.has(error);
|
|
173
|
+
}
|
|
174
|
+
/** Mark a verdict the Q8 decision made, final for every step after it. */
|
|
175
|
+
export function settledWrite(error) {
|
|
176
|
+
if (error !== null && typeof error === "object")
|
|
177
|
+
settledWrites.add(error);
|
|
178
|
+
return error;
|
|
179
|
+
}
|
|
180
|
+
export function isSettledWrite(error) {
|
|
181
|
+
return error !== null && typeof error === "object" && settledWrites.has(error);
|
|
182
|
+
}
|