@zackbart/connecta 0.34.1 → 0.36.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 +418 -0
- package/README.md +65 -105
- 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 +2044 -1161
- 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 +751 -281
- 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 +29 -7
- package/dist/connectors/api-connector.js +145 -57
- 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 +227 -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 +379 -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/contract.d.ts +8 -3
- package/dist/operator-ui/generated.js +4 -4
- package/dist/operator-ui/model.d.ts +2 -3
- 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 +427 -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/kit.js +146 -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/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 +801 -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 +1023 -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/quickbooks/api.js +299 -0
- package/dist/providers/quickbooks/index.d.ts +13 -0
- package/dist/providers/quickbooks/index.js +93 -0
- package/dist/providers/quickbooks/lib/query.js +118 -0
- package/dist/providers/quickbooks/lib/writes.js +168 -0
- package/dist/providers/quickbooks/safety.js +222 -0
- package/dist/providers/quickbooks/skill.generated.js +5 -0
- package/dist/providers/quickbooks/tools.js +117 -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 +733 -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 +65 -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 +6 -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 +552 -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 -223
- 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 +9 -109
- package/dist/ui.d.ts +1 -1
- package/dist/ui.js +0 -1
- 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 +28 -7
- package/documentation/architecture.md +2409 -255
- package/documentation/auth.md +867 -114
- 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 +84 -48
- 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 +1347 -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 +30 -50
- 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/operator-ui/agents.d.ts +0 -74
- package/dist/operator-ui/agents.js +0 -104
- package/dist/operator-ui/config-summary.js +0 -565
- package/dist/operator-ui/connection-map.js +0 -376
- package/dist/operator-ui/endpoints.js +0 -221
- package/dist/operator-ui/fix-prompts.d.ts +0 -18
- package/dist/operator-ui/fix-prompts.js +0 -87
- package/dist/operator-ui/health.js +0 -52
- package/dist/operator-ui/member-page.js +0 -97
- package/dist/operator-ui/overview.js +0 -123
- package/dist/operator-ui/setup-commands.js +0 -51
- package/dist/operator-ui/view.d.ts +0 -401
- package/dist/operator-ui/view.js +0 -705
- package/dist/providers/_shared/request-token.js +0 -83
- package/dist/providers/_shared/rest/dispatch.js +0 -41
- 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/tools.js +0 -569
- 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,104 +0,0 @@
|
|
|
1
|
-
import { failure } from "./view.js";
|
|
2
|
-
/** Why a row's controls are disabled when its slot is not in the live list. */
|
|
3
|
-
const SLOT_UNAVAILABLE = "Token state unknown. Refresh.";
|
|
4
|
-
/** Why a row's controls are disabled until a fresh list read resolves its slot. */
|
|
5
|
-
const SLOT_UNRESOLVED = "Refresh to continue";
|
|
6
|
-
export function slotActions(slot) {
|
|
7
|
-
return slot.state === "issued" ? ["rotate", "revoke"] : ["issue"];
|
|
8
|
-
}
|
|
9
|
-
function contractSlot(agent) {
|
|
10
|
-
return { name: agent.name, ...agent.token };
|
|
11
|
-
}
|
|
12
|
-
function maintainerAgents(contract) {
|
|
13
|
-
return contract?.role === "maintainer" ? contract.agents : [];
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* One agent's slot, resolved once for both what the row shows and what an
|
|
17
|
-
* action may do. The live slot list is authoritative; the contract's copy is
|
|
18
|
-
* shown only for an agent the list does not have, and is never acted on.
|
|
19
|
-
*/
|
|
20
|
-
export function resolveSlot(contract, slots, name) {
|
|
21
|
-
const listed = slots.find((slot) => slot.name === name);
|
|
22
|
-
if (listed)
|
|
23
|
-
return { slot: listed, live: true };
|
|
24
|
-
const agent = maintainerAgents(contract).find((candidate) => candidate.name === name);
|
|
25
|
-
return agent ? { slot: contractSlot(agent), live: false } : null;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* One row per declared agent, in the slot list's order, then any agent only
|
|
29
|
-
* the contract lists. The contract adds pools and last seen.
|
|
30
|
-
*/
|
|
31
|
-
export function agentRows(contract, slots, unresolved = []) {
|
|
32
|
-
const agents = maintainerAgents(contract);
|
|
33
|
-
const declared = new Map(agents.map((agent) => [agent.name, agent]));
|
|
34
|
-
const names = [...slots.map((slot) => slot.name), ...agents.map((agent) => agent.name)];
|
|
35
|
-
return [...new Set(names)].map((name) => {
|
|
36
|
-
const { slot, live } = resolveSlot(contract, slots, name);
|
|
37
|
-
const agent = declared.get(name);
|
|
38
|
-
return {
|
|
39
|
-
name,
|
|
40
|
-
pools: agent?.pools ?? [],
|
|
41
|
-
slot,
|
|
42
|
-
live,
|
|
43
|
-
blocked: !live ? SLOT_UNAVAILABLE : unresolved.includes(name) || !slot.revision ? SLOT_UNRESOLVED : null,
|
|
44
|
-
lastSeenAt: agent?.lastSeenAt ?? null,
|
|
45
|
-
actions: slotActions(slot),
|
|
46
|
-
};
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
export function slotBadge(slot) {
|
|
50
|
-
if (slot.state === "issued")
|
|
51
|
-
return { label: "Issued", tone: "ok" };
|
|
52
|
-
if (slot.state === "revoked")
|
|
53
|
-
return { label: "Revoked", tone: "warn" };
|
|
54
|
-
return { label: "No token", tone: "neutral" };
|
|
55
|
-
}
|
|
56
|
-
/** When the slot last changed, issued or revoked (its badge says which); a dash when it never has. */
|
|
57
|
-
export function slotSince(slot, format) {
|
|
58
|
-
if (slot.state === "issued")
|
|
59
|
-
return format(slot.issuedAt);
|
|
60
|
-
if (slot.state === "revoked")
|
|
61
|
-
return format(slot.revokedAt);
|
|
62
|
-
return "—";
|
|
63
|
-
}
|
|
64
|
-
export function lastSeenLabel(lastSeenAt, format) {
|
|
65
|
-
return lastSeenAt ? format(lastSeenAt) : "never";
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Why a token operation did not land, in fixed sentences keyed by status.
|
|
69
|
-
* `outcome_unknown` (503) and `aborted` (499) are failures like any other and
|
|
70
|
-
* are never retried for the operator: an unknown rotation returned no secret,
|
|
71
|
-
* and only a new, deliberate rotation produces one.
|
|
72
|
-
*/
|
|
73
|
-
export function tokenFailureNotice(action, name, facts, productName) {
|
|
74
|
-
if (facts.kind === "session")
|
|
75
|
-
return failure("Session ended. Sign in again.");
|
|
76
|
-
if (facts.kind === "forbidden")
|
|
77
|
-
return failure("You can't manage agent tokens.");
|
|
78
|
-
if (facts.kind === "stale") {
|
|
79
|
-
return failure(`${name}'s token changed, so nothing was sent. Try again.`);
|
|
80
|
-
}
|
|
81
|
-
if (facts.kind === "network") {
|
|
82
|
-
return failure(`Couldn't reach ${productName}. Refresh to check ${name}'s token.`);
|
|
83
|
-
}
|
|
84
|
-
if (facts.status === 503) {
|
|
85
|
-
return failure(action === "revoke"
|
|
86
|
-
? `Revoke result unknown for ${name}. Revoke again to be sure.`
|
|
87
|
-
: `${action === "issue" ? "Issue" : "Rotate"} result unknown for ${name}. No secret came back, so rotate again.`);
|
|
88
|
-
}
|
|
89
|
-
if (facts.status === 499) {
|
|
90
|
-
return failure(action === "revoke"
|
|
91
|
-
? `The request ended before ${name}'s revoke finished. Refresh to check its token.`
|
|
92
|
-
: `The request ended before ${name}'s token arrived. Refresh to check its token.`);
|
|
93
|
-
}
|
|
94
|
-
// The route's compare-and-swap refused it: the slot moved after the list was read.
|
|
95
|
-
if (facts.status === 409 && facts.code === "slot_changed")
|
|
96
|
-
return failure("Changed since you looked. Refresh.");
|
|
97
|
-
if (facts.status === 409)
|
|
98
|
-
return failure(`${name}'s token changed. Reload and try again.`);
|
|
99
|
-
if (facts.status === 404)
|
|
100
|
-
return failure(`${name} is no longer declared in code. Reload the page.`);
|
|
101
|
-
return action === "revoke"
|
|
102
|
-
? failure(`Couldn't revoke ${name}'s token. Reload and try again.`)
|
|
103
|
-
: failure(`Couldn't issue a token for ${name}. Reload and try again.`);
|
|
104
|
-
}
|
|
@@ -1,565 +0,0 @@
|
|
|
1
|
-
// The configuration snapshot as glanceable tiles for Settings and a
|
|
2
|
-
// connector's Configuration card. Pure: it maps `describeConfig()` and its
|
|
3
|
-
// provenance to labels and formatted values, and the components in
|
|
4
|
-
// app/config-tiles.tsx only draw them. A key this file does not know still
|
|
5
|
-
// becomes a tile with a label made from its name, so nothing in the snapshot
|
|
6
|
-
// disappears when the serializer grows a field.
|
|
7
|
-
const NUMBER = new Intl.NumberFormat("en-US", { maximumFractionDigits: 1 });
|
|
8
|
-
/** Bytes in decimal units throughout, so 24,000 reads "24 KB" and 8 MiB reads "8.4 MB". */
|
|
9
|
-
function formatBytes(bytes) {
|
|
10
|
-
for (const [unit, size] of [
|
|
11
|
-
["GB", 1e9],
|
|
12
|
-
["MB", 1e6],
|
|
13
|
-
["KB", 1e3],
|
|
14
|
-
])
|
|
15
|
-
if (bytes >= size)
|
|
16
|
-
return `${NUMBER.format(bytes / size)} ${unit}`;
|
|
17
|
-
return `${NUMBER.format(bytes)} B`;
|
|
18
|
-
}
|
|
19
|
-
/** The exact count behind a rounded size, for a tooltip. */
|
|
20
|
-
export function exactBytes(bytes) {
|
|
21
|
-
return `${bytes.toLocaleString("en-US")} bytes`;
|
|
22
|
-
}
|
|
23
|
-
const DURATIONS = [
|
|
24
|
-
[86_400_000, "day", "days"],
|
|
25
|
-
[3_600_000, "hr", "hr"],
|
|
26
|
-
[60_000, "min", "min"],
|
|
27
|
-
[1_000, "s", "s"],
|
|
28
|
-
];
|
|
29
|
-
/** A duration in the largest unit it fills: 60000 is "1 min", 90000 is "90 s". */
|
|
30
|
-
function formatMs(ms) {
|
|
31
|
-
if (ms === 0)
|
|
32
|
-
return "0 s";
|
|
33
|
-
for (const [size, one, many] of DURATIONS)
|
|
34
|
-
if (ms >= size && ms % size === 0)
|
|
35
|
-
return `${NUMBER.format(ms / size)} ${ms === size ? one : many}`;
|
|
36
|
-
for (const [size, , many] of DURATIONS)
|
|
37
|
-
if (ms >= size)
|
|
38
|
-
return `${NUMBER.format(ms / size)} ${many}`;
|
|
39
|
-
return `${NUMBER.format(ms)} ms`;
|
|
40
|
-
}
|
|
41
|
-
/** Format one value. Booleans read On or Off, never true or false; null reads None. */
|
|
42
|
-
export function formatValue(value, format) {
|
|
43
|
-
if (value === null || value === undefined)
|
|
44
|
-
return "None";
|
|
45
|
-
if (typeof value === "boolean")
|
|
46
|
-
return value ? "On" : "Off";
|
|
47
|
-
if (Array.isArray(value))
|
|
48
|
-
return value.length === 0
|
|
49
|
-
? "None"
|
|
50
|
-
: value.every((item) => typeof item === "string" || typeof item === "number")
|
|
51
|
-
? value.join(", ")
|
|
52
|
-
: `${NUMBER.format(value.length)} items`;
|
|
53
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
54
|
-
if (format === "bytes")
|
|
55
|
-
return formatBytes(value);
|
|
56
|
-
if (format === "ms")
|
|
57
|
-
return formatMs(value);
|
|
58
|
-
if (format === "seconds")
|
|
59
|
-
return formatMs(value * 1000);
|
|
60
|
-
if (format === "days")
|
|
61
|
-
return `${NUMBER.format(value)} ${value === 1 ? "day" : "days"}`;
|
|
62
|
-
return NUMBER.format(value);
|
|
63
|
-
}
|
|
64
|
-
if (typeof value === "object")
|
|
65
|
-
return `${NUMBER.format(Object.keys(value).length)} items`;
|
|
66
|
-
return String(value);
|
|
67
|
-
}
|
|
68
|
-
const UNIT_SUFFIX = /(Ms|Seconds|Bytes|Days)$/;
|
|
69
|
-
/** The format a key's name implies: `probeTimeoutMs` is a duration, `maxStashBytes` a size. */
|
|
70
|
-
export function inferFormat(key, value) {
|
|
71
|
-
if (typeof value === "boolean")
|
|
72
|
-
return "toggle";
|
|
73
|
-
if (typeof value !== "number")
|
|
74
|
-
return "text";
|
|
75
|
-
const unit = UNIT_SUFFIX.exec(key)?.[1];
|
|
76
|
-
return unit === "Ms"
|
|
77
|
-
? "ms"
|
|
78
|
-
: unit === "Seconds"
|
|
79
|
-
? "seconds"
|
|
80
|
-
: unit === "Bytes"
|
|
81
|
-
? "bytes"
|
|
82
|
-
: unit === "Days"
|
|
83
|
-
? "days"
|
|
84
|
-
: "count";
|
|
85
|
-
}
|
|
86
|
-
/** `maxStashEntries` reads "Max stash entries"; a unit suffix drops because the value carries it. */
|
|
87
|
-
export function humanizeKey(key) {
|
|
88
|
-
// A word with two capitals is an acronym (OAuth, URL) and keeps its case.
|
|
89
|
-
const words = key
|
|
90
|
-
.replace(UNIT_SUFFIX, "")
|
|
91
|
-
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
92
|
-
.split(/[\s_.-]+/)
|
|
93
|
-
.filter(Boolean)
|
|
94
|
-
.map((word) => (/[A-Z].*[A-Z]/.test(word) ? word : word.toLowerCase()))
|
|
95
|
-
.join(" ");
|
|
96
|
-
return words ? words[0].toUpperCase() + words.slice(1) : key;
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Labels for every limit the snapshot carries today, by `group.key`. Headline
|
|
100
|
-
* limits draw large in this order; the rest fold into a group card under
|
|
101
|
-
* `short`, a label the card's title makes unambiguous.
|
|
102
|
-
*/
|
|
103
|
-
const LIMITS = {
|
|
104
|
-
"calls.defaultTimeoutMs": { label: "Tool timeout", headline: 1 },
|
|
105
|
-
"calls.maxResultBytes": { label: "Result cap", headline: 2 },
|
|
106
|
-
"execute.watchdogMs": { label: "Program timeout", headline: 3 },
|
|
107
|
-
"discovery.catalogTtlSeconds": { label: "Catalog refresh", headline: 4 },
|
|
108
|
-
"execute.maxHostCalls": { label: "Calls per program", headline: 6 },
|
|
109
|
-
"execute.maxWrites": { label: "Writes per program", headline: 7 },
|
|
110
|
-
"requests.concurrency": { label: "Concurrent requests", headline: 8 },
|
|
111
|
-
"discovery.concurrency": { label: "Probe concurrency", short: "Concurrency" },
|
|
112
|
-
"discovery.catalogMinTtlSeconds": { label: "Min refresh" },
|
|
113
|
-
"discovery.catalogMaxTtlSeconds": { label: "Max refresh" },
|
|
114
|
-
"discovery.probeTimeoutMs": { label: "Probe timeout" },
|
|
115
|
-
"results.maxStashBytes": { label: "Stash size" },
|
|
116
|
-
"results.maxStashEntries": { label: "Stash entries" },
|
|
117
|
-
"execute.maxEmittedBytes": { label: "Program output", short: "Output" },
|
|
118
|
-
"execute.maxEmittedBlocks": { label: "Output blocks" },
|
|
119
|
-
"execute.hostCallTimeoutMs": { label: "Host call timeout", short: "Call timeout" },
|
|
120
|
-
"requests.maxQueueSize": { label: "Request queue", short: "Queue" },
|
|
121
|
-
"requests.queueTimeoutMs": { label: "Request queue wait", short: "Queue wait" },
|
|
122
|
-
"requests.retryAfterMs": { label: "Request retry after", short: "Retry after" },
|
|
123
|
-
"requests.maxDurationMs": { label: "Request lifetime", short: "Lifetime" },
|
|
124
|
-
"admission.concurrency": { label: "Concurrent programs", short: "Concurrency" },
|
|
125
|
-
"admission.maxQueueSize": { label: "Program queue", short: "Queue" },
|
|
126
|
-
"admission.queueTimeoutMs": { label: "Program queue wait", short: "Queue wait" },
|
|
127
|
-
"admission.retryAfterMs": { label: "Program retry after", short: "Retry after" },
|
|
128
|
-
};
|
|
129
|
-
/** The card a default limit folds into, by its snapshot group. */
|
|
130
|
-
const DEFAULT_GROUPS = {
|
|
131
|
-
discovery: "Discovery",
|
|
132
|
-
calls: "Results",
|
|
133
|
-
results: "Results",
|
|
134
|
-
execute: "Programs",
|
|
135
|
-
admission: "Programs",
|
|
136
|
-
requests: "Requests",
|
|
137
|
-
};
|
|
138
|
-
function isLimit(value) {
|
|
139
|
-
return (typeof value === "object" &&
|
|
140
|
-
value !== null &&
|
|
141
|
-
"value" in value &&
|
|
142
|
-
"source" in value &&
|
|
143
|
-
Object.keys(value).length === 2);
|
|
144
|
-
}
|
|
145
|
-
/** A limit's tile. A byte size carries its exact count as a title. */
|
|
146
|
-
function limitTile(path, key, limit, sources, label) {
|
|
147
|
-
const id = `config.${path}`;
|
|
148
|
-
const format = inferFormat(key, limit.value);
|
|
149
|
-
return {
|
|
150
|
-
id,
|
|
151
|
-
label: label ?? humanizeKey(key),
|
|
152
|
-
value: limit.value === null ? "No limit" : formatValue(limit.value, format),
|
|
153
|
-
set: (sources[id] ?? limit.source) === "config",
|
|
154
|
-
...(format === "bytes" && typeof limit.value === "number" ? { title: exactBytes(limit.value) } : {}),
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
const SIGN_IN = {
|
|
158
|
-
clerk: { label: "Clerk", mark: "clerk" },
|
|
159
|
-
"cloudflare-access": { label: "Cloudflare Access", mark: "access" },
|
|
160
|
-
access_token: { label: "Agent tokens", mark: "tokens" },
|
|
161
|
-
};
|
|
162
|
-
const STORE = { memory: "Memory", d1: "D1", sqlite: "SQLite", custom: "Custom" };
|
|
163
|
-
/** Known modules; any other `modules.<name>.enabled` becomes a tile named from its key. */
|
|
164
|
-
const MODULES = {
|
|
165
|
-
vault: { label: "Vault", icon: "lock" },
|
|
166
|
-
activity: { label: "Activity", icon: "activity" },
|
|
167
|
-
accessTokens: { label: "Agent tokens", icon: "key" },
|
|
168
|
-
};
|
|
169
|
-
/**
|
|
170
|
-
* Snapshot paths Settings draws, or leaves to the page that owns them
|
|
171
|
-
* (branding to the shell, pools to Endpoints, connectors to their pages,
|
|
172
|
-
* activity reads to Activity). Everything else is "other".
|
|
173
|
-
*/
|
|
174
|
-
const KNOWN = [
|
|
175
|
-
"schemaVersion",
|
|
176
|
-
"connectaVersion",
|
|
177
|
-
"server.name",
|
|
178
|
-
"server.version",
|
|
179
|
-
"server.title",
|
|
180
|
-
"server.websiteUrl",
|
|
181
|
-
"server.icons",
|
|
182
|
-
"urls.publicUrl",
|
|
183
|
-
"urls.mcpPath",
|
|
184
|
-
"urls.allowedOrigins",
|
|
185
|
-
"executor",
|
|
186
|
-
"limits",
|
|
187
|
-
"readOnly",
|
|
188
|
-
"maintainers",
|
|
189
|
-
"classification",
|
|
190
|
-
"auth",
|
|
191
|
-
"agents",
|
|
192
|
-
"pools",
|
|
193
|
-
"modules.vault.sealsOAuth",
|
|
194
|
-
"modules.activity.readable",
|
|
195
|
-
"modules.activity.deploymentId",
|
|
196
|
-
"modules.activity.store",
|
|
197
|
-
"storage.configured",
|
|
198
|
-
"storage.kind",
|
|
199
|
-
"branding",
|
|
200
|
-
"deploymentInfo",
|
|
201
|
-
"connectors",
|
|
202
|
-
];
|
|
203
|
-
function known(path, prefixes) {
|
|
204
|
-
return prefixes.some((prefix) => path === prefix || path.startsWith(`${prefix}.`));
|
|
205
|
-
}
|
|
206
|
-
/** Leaves under `value`, a described limit counting as one leaf and an array as one value. */
|
|
207
|
-
function leaves(value, path) {
|
|
208
|
-
if (value === null || typeof value !== "object" || Array.isArray(value) || isLimit(value))
|
|
209
|
-
return [[path, value]];
|
|
210
|
-
const entries = Object.entries(value);
|
|
211
|
-
return entries.length ? entries.flatMap(([key, item]) => leaves(item, path ? `${path}.${key}` : key)) : [];
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* A tile for a key nobody mapped: its own name, or its parent's and its own
|
|
215
|
-
* when the name alone is vague. It reads as set only when the snapshot itself
|
|
216
|
-
* says so: the server reports an unknown path as "config" by default.
|
|
217
|
-
*/
|
|
218
|
-
function otherTile(path, value, prefix) {
|
|
219
|
-
const parts = path.split(".");
|
|
220
|
-
const key = parts.at(-1);
|
|
221
|
-
const parent = parts.length > 1 ? parts.at(-2) : undefined;
|
|
222
|
-
const inner = isLimit(value) ? value : null;
|
|
223
|
-
const raw = inner ? inner.value : value;
|
|
224
|
-
const format = inferFormat(key, raw);
|
|
225
|
-
return {
|
|
226
|
-
id: `${prefix}.${path}`,
|
|
227
|
-
label: parent && /^(enabled|value|kind|mode|name)$/.test(key)
|
|
228
|
-
? `${humanizeKey(parent)} ${humanizeKey(key).toLowerCase()}`
|
|
229
|
-
: humanizeKey(key),
|
|
230
|
-
value: formatValue(raw, format),
|
|
231
|
-
set: inner?.source === "config",
|
|
232
|
-
...(format === "bytes" && typeof raw === "number" ? { title: exactBytes(raw) } : {}),
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
function hostOf(url) {
|
|
236
|
-
return url.replace(/^https?:\/\//, "");
|
|
237
|
-
}
|
|
238
|
-
function endpointText(endpoint) {
|
|
239
|
-
if (!endpoint)
|
|
240
|
-
return undefined;
|
|
241
|
-
const host = hostOf(endpoint.origin);
|
|
242
|
-
return endpoint.path && endpoint.path !== "/" ? `${host}${endpoint.path}` : host;
|
|
243
|
-
}
|
|
244
|
-
const plural = (count, one, many = `${one}s`) => `${formatValue(count, "count")} ${count === 1 ? one : many}`;
|
|
245
|
-
/** Settings, as tiles. */
|
|
246
|
-
export function configSummary(config, sources = {}) {
|
|
247
|
-
const name = config.server.title ?? config.server.name;
|
|
248
|
-
const version = config.server.version;
|
|
249
|
-
const deployment = [
|
|
250
|
-
{ id: "name", label: "Name", value: version ? `${name} · ${/^v/i.test(version) ? version : `v${version}`}` : name },
|
|
251
|
-
{ id: "mode", label: "Mode", value: config.readOnly ? "Read-only" : "Writes allowed" },
|
|
252
|
-
{ id: "connecta", label: "Connecta", value: config.connectaVersion, mono: true },
|
|
253
|
-
];
|
|
254
|
-
const url = endpointText(config.urls.publicUrl);
|
|
255
|
-
if (url)
|
|
256
|
-
deployment.push({ id: "url", label: "URL", value: url, mono: true });
|
|
257
|
-
const origins = config.urls.allowedOrigins;
|
|
258
|
-
deployment.push({
|
|
259
|
-
id: "origins",
|
|
260
|
-
label: "Origins",
|
|
261
|
-
value: origins === "default"
|
|
262
|
-
? "Default"
|
|
263
|
-
: origins === "*"
|
|
264
|
-
? "Any"
|
|
265
|
-
: origins.length === 1
|
|
266
|
-
? hostOf(origins[0])
|
|
267
|
-
: `${origins.length}`,
|
|
268
|
-
mono: Array.isArray(origins) && origins.length === 1,
|
|
269
|
-
});
|
|
270
|
-
if (config.executor.name)
|
|
271
|
-
deployment.push({ id: "sandbox", label: "Sandbox", value: config.executor.name });
|
|
272
|
-
// Unconfigured memory storage loses tokens, credentials and OAuth state on restart.
|
|
273
|
-
const volatile = !config.storage.configured && config.storage.kind === "memory";
|
|
274
|
-
deployment.push({
|
|
275
|
-
id: "storage",
|
|
276
|
-
label: "Storage",
|
|
277
|
-
value: volatile ? "Memory · default" : (STORE[config.storage.kind] ?? config.storage.kind),
|
|
278
|
-
...(volatile ? { tone: "warn", title: "Lost on restart" } : {}),
|
|
279
|
-
});
|
|
280
|
-
if (config.modules.activity.enabled && config.modules.activity.store)
|
|
281
|
-
deployment.push({
|
|
282
|
-
id: "history",
|
|
283
|
-
label: "History",
|
|
284
|
-
value: STORE[config.modules.activity.store.kind] ?? config.modules.activity.store.kind,
|
|
285
|
-
});
|
|
286
|
-
if (config.modules.activity.deploymentId)
|
|
287
|
-
deployment.push({
|
|
288
|
-
id: "deploymentId",
|
|
289
|
-
label: "Deployment ID",
|
|
290
|
-
value: config.modules.activity.deploymentId,
|
|
291
|
-
mono: true,
|
|
292
|
-
});
|
|
293
|
-
const website = endpointText(config.server.websiteUrl);
|
|
294
|
-
if (website)
|
|
295
|
-
deployment.push({ id: "website", label: "Website", value: website, mono: true });
|
|
296
|
-
if (config.server.icons > 0)
|
|
297
|
-
deployment.push({ id: "icons", label: "Icons", value: formatValue(config.server.icons, "count") });
|
|
298
|
-
if (config.deploymentInfo.length)
|
|
299
|
-
deployment.push({ id: "info", label: "Info", value: config.deploymentInfo.join(", "), mono: true });
|
|
300
|
-
const signIn = config.auth.map((provider, index) => {
|
|
301
|
-
const knownProvider = SIGN_IN[provider.kind];
|
|
302
|
-
const mark = knownProvider?.mark ?? "other";
|
|
303
|
-
return {
|
|
304
|
-
id: `${provider.kind}-${index}`,
|
|
305
|
-
label: knownProvider?.label ?? humanizeKey(provider.kind),
|
|
306
|
-
mark,
|
|
307
|
-
interactive: provider.interactive,
|
|
308
|
-
...(mark === "tokens" ? { count: plural(config.agents.length, "agent") } : {}),
|
|
309
|
-
};
|
|
310
|
-
});
|
|
311
|
-
// The UI module is on whenever this page draws, so it has no tile.
|
|
312
|
-
const features = [];
|
|
313
|
-
for (const [id, module] of Object.entries(config.modules)) {
|
|
314
|
-
if (id === "ui" || typeof module?.enabled !== "boolean")
|
|
315
|
-
continue;
|
|
316
|
-
const meta = MODULES[id] ?? { label: humanizeKey(id), icon: "box" };
|
|
317
|
-
features.push({
|
|
318
|
-
id,
|
|
319
|
-
label: meta.label,
|
|
320
|
-
icon: meta.icon,
|
|
321
|
-
on: module.enabled,
|
|
322
|
-
...(id === "vault" && config.modules.vault.sealsOAuth ? { detail: "Seals OAuth" } : {}),
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
const all = [];
|
|
326
|
-
const hostCall = config.limits.execute.hostCallTimeoutMs;
|
|
327
|
-
for (const [group, values] of Object.entries(config.limits))
|
|
328
|
-
for (const [key, value] of Object.entries(values)) {
|
|
329
|
-
if (!isLimit(value))
|
|
330
|
-
continue;
|
|
331
|
-
const meta = LIMITS[`${group}.${key}`];
|
|
332
|
-
const path = `limits.${group}.${key}`;
|
|
333
|
-
// A null tool timeout falls back to the host-call timeout at runtime.
|
|
334
|
-
const fallback = group === "calls" && key === "defaultTimeoutMs" && value.value === null && hostCall;
|
|
335
|
-
const tile = fallback
|
|
336
|
-
? { ...limitTile(path, key, { value: hostCall.value, source: "default" }, {}, meta?.label), set: false }
|
|
337
|
-
: limitTile(path, key, value, sources, meta?.label);
|
|
338
|
-
all.push({ ...tile, headline: meta?.headline ?? 0, group, short: meta?.short });
|
|
339
|
-
}
|
|
340
|
-
if (config.executor.admission !== "executor")
|
|
341
|
-
for (const [key, limit] of Object.entries(config.executor.admission)) {
|
|
342
|
-
if (!isLimit(limit))
|
|
343
|
-
continue;
|
|
344
|
-
const meta = LIMITS[`admission.${key}`];
|
|
345
|
-
all.push({
|
|
346
|
-
...limitTile(`executor.admission.${key}`, key, limit, sources, meta?.label),
|
|
347
|
-
headline: 0,
|
|
348
|
-
group: "admission",
|
|
349
|
-
short: meta?.short,
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
const retention = config.modules.activity.enabled ? config.modules.activity.store?.retentionDays : undefined;
|
|
353
|
-
if (retention !== undefined) {
|
|
354
|
-
// The source map reads "config" only when the store reports its own option as set.
|
|
355
|
-
const id = "config.modules.activity.store.retentionDays";
|
|
356
|
-
all.push({
|
|
357
|
-
id,
|
|
358
|
-
label: "Activity kept",
|
|
359
|
-
value: formatValue(retention, "days"),
|
|
360
|
-
set: sources[id] === "config",
|
|
361
|
-
headline: 5,
|
|
362
|
-
group: "activity",
|
|
363
|
-
short: undefined,
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
const strip = ({ headline: _, group: __, short: ___, ...tile }) => tile;
|
|
367
|
-
// Headline limits in a fixed order, then any other limit code set.
|
|
368
|
-
const limits = [
|
|
369
|
-
...all.filter((tile) => tile.headline).sort((a, b) => a.headline - b.headline),
|
|
370
|
-
...all.filter((tile) => !tile.headline && tile.set),
|
|
371
|
-
].map(strip);
|
|
372
|
-
const defaults = [];
|
|
373
|
-
for (const tile of all.filter((item) => !item.headline && !item.set)) {
|
|
374
|
-
const title = DEFAULT_GROUPS[tile.group] ?? humanizeKey(tile.group);
|
|
375
|
-
let group = defaults.find((item) => item.title === title);
|
|
376
|
-
if (!group)
|
|
377
|
-
defaults.push((group = { id: title.toLowerCase().replace(/\W+/g, "-"), title, tiles: [] }));
|
|
378
|
-
group.tiles.push({ ...strip(tile), label: tile.short ?? tile.label });
|
|
379
|
-
}
|
|
380
|
-
const overrides = Object.entries(config.classification).flatMap(([connector, tools]) => Object.entries(tools).map(([tool, classification]) => ({ address: `${connector}.${tool}`, classification })));
|
|
381
|
-
const other = leaves(config, "")
|
|
382
|
-
.filter(([path]) => !known(path, KNOWN) && !/^modules\.[^.]+\.enabled$/.test(path))
|
|
383
|
-
.map(([path, value]) => otherTile(path, value, "config"));
|
|
384
|
-
return { deployment, signIn, features, limits, defaults, overrides, other };
|
|
385
|
-
}
|
|
386
|
-
const SOURCE_KIND = {
|
|
387
|
-
"remote-mcp": { label: "Remote MCP", icon: "plug" },
|
|
388
|
-
api: { label: "HTTP API", icon: "globe" },
|
|
389
|
-
custom: { label: "Custom", icon: "box" },
|
|
390
|
-
};
|
|
391
|
-
const AUTH_MODE = {
|
|
392
|
-
none: "No auth",
|
|
393
|
-
headers: "Headers",
|
|
394
|
-
credential: "API key",
|
|
395
|
-
oauth: "OAuth",
|
|
396
|
-
request: "Request token",
|
|
397
|
-
};
|
|
398
|
-
/**
|
|
399
|
-
* Connector leaves the card draws, plus those the page leaves to another tab:
|
|
400
|
-
* prose (description, guide summary, credential help) and the Tools tab's
|
|
401
|
-
* catalog. Anything else becomes a tile, so a new field is never hidden.
|
|
402
|
-
*/
|
|
403
|
-
const CONNECTOR_KNOWN = [
|
|
404
|
-
"readOnly",
|
|
405
|
-
"id",
|
|
406
|
-
"title",
|
|
407
|
-
"description",
|
|
408
|
-
"authScope",
|
|
409
|
-
"source.kind",
|
|
410
|
-
"source.provider",
|
|
411
|
-
"endpoint.origin",
|
|
412
|
-
"endpoint.path",
|
|
413
|
-
"auth.mode",
|
|
414
|
-
"auth.headerNames",
|
|
415
|
-
"auth.header",
|
|
416
|
-
"auth.scheme",
|
|
417
|
-
"auth.scope",
|
|
418
|
-
"auth.clientMetadataUrl",
|
|
419
|
-
"auth.authorizationEndpoint.origin",
|
|
420
|
-
"auth.authorizationEndpoint.path",
|
|
421
|
-
"auth.tokenEndpoint.origin",
|
|
422
|
-
"auth.tokenEndpoint.path",
|
|
423
|
-
"auth.apiOrigins",
|
|
424
|
-
"auth.tokenEndpointAuthMethod",
|
|
425
|
-
"auth.confidentialClient",
|
|
426
|
-
"auth.pkce",
|
|
427
|
-
"auth.authorizationParamNames",
|
|
428
|
-
"auth.tokenRequestHeaderNames",
|
|
429
|
-
"credential.label",
|
|
430
|
-
"credential.description",
|
|
431
|
-
"credential.fields",
|
|
432
|
-
"transport.versionNegotiation",
|
|
433
|
-
"transport.redirects",
|
|
434
|
-
"transport.requireHttps",
|
|
435
|
-
"maxResultBytes",
|
|
436
|
-
"callAdmission",
|
|
437
|
-
"usageGuide.summary",
|
|
438
|
-
"usageGuide.required",
|
|
439
|
-
"tools",
|
|
440
|
-
];
|
|
441
|
-
/** How a connector authenticates, as one mode badge and mono badges for its headers, origins and OAuth facts. */
|
|
442
|
-
function authBadges(connector) {
|
|
443
|
-
const auth = connector.auth;
|
|
444
|
-
const mode = auth?.mode ?? (connector.credential ? "credential" : undefined);
|
|
445
|
-
if (!mode)
|
|
446
|
-
return [];
|
|
447
|
-
const badges = [
|
|
448
|
-
{
|
|
449
|
-
id: "auth",
|
|
450
|
-
label: connector.credential?.label ?? AUTH_MODE[mode] ?? humanizeKey(mode),
|
|
451
|
-
...(mode === "none" ? {} : { icon: mode === "oauth" ? "lock" : "key" }),
|
|
452
|
-
},
|
|
453
|
-
];
|
|
454
|
-
const mono = (id, label, extra = {}) => badges.push({ id, label, mono: true, ...extra });
|
|
455
|
-
const fields = connector.credential?.fields ?? [];
|
|
456
|
-
if (fields.length > 1)
|
|
457
|
-
for (const field of fields)
|
|
458
|
-
mono(`field.${field.name}`, field.name, { title: field.label });
|
|
459
|
-
if (auth?.header)
|
|
460
|
-
mono("header", auth.scheme ? `${auth.header}: ${auth.scheme}` : auth.header);
|
|
461
|
-
for (const name of auth?.headerNames ?? [])
|
|
462
|
-
mono(`headerNames.${name}`, name);
|
|
463
|
-
if (auth?.scope)
|
|
464
|
-
mono("scope", auth.scope, { prefix: "Scope" });
|
|
465
|
-
for (const origin of auth?.apiOrigins ?? [])
|
|
466
|
-
mono(`apiOrigins.${origin}`, `→ ${hostOf(origin)}`, { title: origin });
|
|
467
|
-
const authorize = endpointText(auth?.authorizationEndpoint);
|
|
468
|
-
if (authorize)
|
|
469
|
-
mono("authorize", authorize, { prefix: "Authorize" });
|
|
470
|
-
const token = endpointText(auth?.tokenEndpoint);
|
|
471
|
-
if (token)
|
|
472
|
-
mono("token", token, { prefix: "Token" });
|
|
473
|
-
if (auth?.clientMetadataUrl)
|
|
474
|
-
mono("client", hostOf(auth.clientMetadataUrl), { prefix: "Client" });
|
|
475
|
-
if (auth?.tokenEndpointAuthMethod)
|
|
476
|
-
mono("clientAuth", auth.tokenEndpointAuthMethod);
|
|
477
|
-
if (auth?.confidentialClient)
|
|
478
|
-
badges.push({ id: "secret", label: "Client secret" });
|
|
479
|
-
if (auth?.pkce)
|
|
480
|
-
badges.push({ id: "pkce", label: "PKCE" });
|
|
481
|
-
for (const name of auth?.authorizationParamNames ?? [])
|
|
482
|
-
mono(`param.${name}`, `?${name}`);
|
|
483
|
-
for (const name of auth?.tokenRequestHeaderNames ?? [])
|
|
484
|
-
mono(`tokenHeader.${name}`, name);
|
|
485
|
-
return badges;
|
|
486
|
-
}
|
|
487
|
-
/** A connector's Configuration card: what it is and how it signs in as badges, its limits as tiles. */
|
|
488
|
-
export function connectorSummary(connector, sources = {}) {
|
|
489
|
-
const base = `config.connectors.${connector.id}`;
|
|
490
|
-
const kind = SOURCE_KIND[connector.source.kind] ?? SOURCE_KIND.custom;
|
|
491
|
-
const badges = [{ id: "kind", label: kind.label, icon: kind.icon }];
|
|
492
|
-
if (connector.readOnly)
|
|
493
|
-
badges.push({ id: "readOnly", label: "Read-only" });
|
|
494
|
-
if (connector.source.provider)
|
|
495
|
-
badges.push({ id: "provider", label: connector.source.provider, icon: "box" });
|
|
496
|
-
badges.push(connector.authScope === "personal"
|
|
497
|
-
? { id: "scope", label: "Per person", icon: "user" }
|
|
498
|
-
: { id: "scope", label: "Shared account", icon: "users" });
|
|
499
|
-
const endpoint = endpointText(connector.endpoint);
|
|
500
|
-
if (endpoint)
|
|
501
|
-
badges.push({ id: "endpoint", label: endpoint, mono: true });
|
|
502
|
-
if (connector.usageGuide)
|
|
503
|
-
badges.push({ id: "guide", label: connector.usageGuide.required ? "Guide required" : "Guide", icon: "book" });
|
|
504
|
-
const set = (path, fallback) => (sources[`${base}.${path}`] ?? (fallback ? "config" : "default")) === "config";
|
|
505
|
-
const tiles = [
|
|
506
|
-
{
|
|
507
|
-
id: `${base}.maxResultBytes`,
|
|
508
|
-
label: "Result cap",
|
|
509
|
-
value: formatValue(connector.maxResultBytes.value, "bytes"),
|
|
510
|
-
set: set("maxResultBytes", connector.maxResultBytes.source === "connector"),
|
|
511
|
-
title: exactBytes(connector.maxResultBytes.value),
|
|
512
|
-
},
|
|
513
|
-
];
|
|
514
|
-
const admission = connector.callAdmission;
|
|
515
|
-
if (admission?.maxPartitions !== undefined)
|
|
516
|
-
tiles.push({
|
|
517
|
-
id: `${base}.callAdmission.maxPartitions`,
|
|
518
|
-
label: "Partitions",
|
|
519
|
-
value: formatValue(admission.maxPartitions, "count"),
|
|
520
|
-
set: true,
|
|
521
|
-
});
|
|
522
|
-
admission?.rules.forEach((rule, index) => {
|
|
523
|
-
const suffix = admission.rules.length > 1 ? ` ${index + 1}` : "";
|
|
524
|
-
const id = `${base}.callAdmission.rules.${index}`;
|
|
525
|
-
const add = (key, label, value) => tiles.push({ id: `${id}.${key}`, label: `${label}${suffix}`, value, set: true });
|
|
526
|
-
if (rule.maxConcurrency !== undefined)
|
|
527
|
-
add("maxConcurrency", "Concurrency", formatValue(rule.maxConcurrency, "count"));
|
|
528
|
-
if (rule.maxQueueSize !== undefined)
|
|
529
|
-
add("maxQueueSize", "Queue", formatValue(rule.maxQueueSize, "count"));
|
|
530
|
-
if (rule.queueTimeoutMs !== undefined)
|
|
531
|
-
add("queueTimeoutMs", "Queue wait", formatValue(rule.queueTimeoutMs, "ms"));
|
|
532
|
-
if (rule.retryAfterMs !== undefined)
|
|
533
|
-
add("retryAfterMs", "Retry after", formatValue(rule.retryAfterMs, "ms"));
|
|
534
|
-
if (rule.budget)
|
|
535
|
-
add("budget", "Call budget", `${formatValue(rule.budget.maxCalls, "count")} / ${formatValue(rule.budget.windowMs, "ms")}`);
|
|
536
|
-
if (rule.partitioned)
|
|
537
|
-
add("partitioned", "Per caller", "On");
|
|
538
|
-
});
|
|
539
|
-
const transport = connector.transport;
|
|
540
|
-
if (transport?.versionNegotiation)
|
|
541
|
-
tiles.push({
|
|
542
|
-
id: `${base}.transport.versionNegotiation`,
|
|
543
|
-
label: "Protocol",
|
|
544
|
-
value: transport.versionNegotiation === "auto" ? "Auto" : "Legacy",
|
|
545
|
-
set: set("transport.versionNegotiation", false),
|
|
546
|
-
});
|
|
547
|
-
if (transport?.redirects)
|
|
548
|
-
tiles.push({
|
|
549
|
-
id: `${base}.transport.redirects`,
|
|
550
|
-
label: "Redirects",
|
|
551
|
-
value: transport.redirects === "none" ? "None" : "Same origin",
|
|
552
|
-
set: set("transport.redirects", false),
|
|
553
|
-
});
|
|
554
|
-
if (transport?.requireHttps !== undefined)
|
|
555
|
-
tiles.push({
|
|
556
|
-
id: `${base}.transport.requireHttps`,
|
|
557
|
-
label: "HTTPS only",
|
|
558
|
-
value: formatValue(transport.requireHttps, "toggle"),
|
|
559
|
-
set: set("transport.requireHttps", false),
|
|
560
|
-
});
|
|
561
|
-
const other = leaves(connector, "")
|
|
562
|
-
.filter(([path]) => !known(path, CONNECTOR_KNOWN))
|
|
563
|
-
.map(([path, value]) => otherTile(path, value, base));
|
|
564
|
-
return { badges, auth: authBadges(connector), tiles: [...tiles, ...other] };
|
|
565
|
-
}
|