@zackbart/connecta 0.34.0 → 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 +393 -0
- package/README.md +62 -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 +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 +15 -7
- package/dist/connectors/api-connector.js +147 -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/option-shapes.js +1 -1
- package/dist/connectors/remote-mcp.d.ts +12 -30
- package/dist/connectors/remote-mcp.js +960 -564
- package/dist/d1.js +10 -243
- package/dist/derived-context.js +5 -0
- package/dist/describe-config.d.ts +5 -1
- package/dist/describe-config.js +3 -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 +221 -87
- 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 +534 -408
- 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 +8 -4
- package/dist/operator-ui/connection-map.js +9 -6
- package/dist/operator-ui/contract.d.ts +7 -3
- package/dist/operator-ui/endpoints.js +5 -14
- 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/health.js +52 -0
- package/dist/operator-ui/model.d.ts +2 -3
- package/dist/operator-ui/overview.js +11 -19
- package/dist/operator-ui/setup-commands.js +0 -4
- package/dist/operator-ui/view.d.ts +5 -29
- package/dist/operator-ui/view.js +3 -59
- 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 +71 -32
- package/dist/provider.js +134 -40
- 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 +8 -209
- package/dist/providers/_shared/google/workspace.js +7 -426
- 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 +3 -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 +17 -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 +7 -22
- package/dist/providers/cloudflare/index.js +80 -194
- 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 +3299 -3208
- package/dist/providers/cloudflare/{value-safety.js → safety.js} +538 -18
- 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 +3 -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 +6 -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 +7 -27
- package/dist/providers/stripe/index.js +75 -191
- 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 -10
- package/dist/providers/stripe/tools.js +77 -0
- package/dist/providers/tithely/api.js +531 -0
- package/dist/providers/tithely/index.d.ts +19 -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 +11 -25
- package/dist/providers/vercel/index.js +67 -261
- 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 +398 -376
- package/dist/providers/vercel/{value-safety.js → safety.js} +261 -42
- 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 +30 -28
- package/dist/registry.js +446 -413
- 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 +29 -22
- 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 +330 -224
- 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 +11 -99
- 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 +2550 -186
- package/documentation/auth.md +821 -98
- package/documentation/code-mode.md +56 -21
- package/documentation/deploying.md +164 -20
- package/documentation/hosted-mcp-migration.md +460 -0
- package/documentation/integrating.md +144 -105
- package/documentation/meta-tools.md +411 -34
- package/documentation/operating.md +28 -4
- package/documentation/operator-tests.md +11 -2
- package/documentation/operator-ui.md +103 -33
- package/documentation/provider-auth-migration.md +38 -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 -42
- 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 -134
- package/dist/catalog-drift.js +0 -493
- 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 -43
- 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 -1078
- 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/linear/index.d.ts +0 -55
- package/dist/providers/linear/index.js +0 -352
- package/dist/providers/linear/skill.generated.js +0 -8
- package/dist/providers/mixpanel/index.d.ts +0 -57
- package/dist/providers/mixpanel/index.js +0 -468
- 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 -65
- 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 -49
- package/dist/providers/revenuecat/index.js +0 -557
- 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
package/dist/provider.d.ts
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
import { type Field } from "./config-schema.js";
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
* How a provider reaches its vendor: the vendor's hosted MCP server, an
|
|
5
|
-
* `api()` connector over the vendor's HTTP API, one connector composing both
|
|
6
|
-
* with an explicit operation ownership map, or `"dual"`: configuration selects the implementation, usually by `auth.type`. Mixpanel
|
|
7
|
-
* uses explicit `via` because service accounts reach both implementations.
|
|
8
|
-
*/
|
|
9
|
-
export type ProviderKind = "mcp" | "api" | "composed" | "dual";
|
|
2
|
+
import { type ConnectorCallErrorCode } from "./errors.js";
|
|
3
|
+
import type { Connector, ConnectorCallAdmissionPolicy, ConnectorUsageGuide } from "./types.js";
|
|
10
4
|
/** Options every provider accepts, validated before `create` runs. */
|
|
11
5
|
export interface ProviderOptions {
|
|
12
6
|
/** What this connection is for and which decisions it answers. Required. */
|
|
@@ -19,6 +13,8 @@ export interface ProviderOptions {
|
|
|
19
13
|
authScope?: "shared" | "personal";
|
|
20
14
|
/** Connector-specific inline result limit; omit to inherit the deployment. */
|
|
21
15
|
maxResultBytes?: number;
|
|
16
|
+
/** Serve only read-classified tools on every endpoint. Defaults to false. */
|
|
17
|
+
readOnly?: boolean;
|
|
22
18
|
/** Optional per-runtime downstream call-admission policy. */
|
|
23
19
|
callAdmission?: ConnectorCallAdmissionPolicy;
|
|
24
20
|
}
|
|
@@ -82,8 +78,11 @@ export declare const CALL_ADMISSION: Omit<Field<unknown, ConnectorCallAdmissionP
|
|
|
82
78
|
parse(value: unknown, path: string): ConnectorCallAdmissionPolicy;
|
|
83
79
|
readonly shape: typeof admissionPolicy.shape;
|
|
84
80
|
};
|
|
81
|
+
/** Validate the common connector policy before a deployment can serve. */
|
|
82
|
+
export declare const READ_ONLY: Field<boolean, boolean | undefined, true>;
|
|
85
83
|
/** Options every maintained provider shares. */
|
|
86
84
|
export declare const PROVIDER_COMMON: {
|
|
85
|
+
readOnly: Field<boolean, boolean | undefined, true>;
|
|
87
86
|
callAdmission: Omit<Field<unknown, ConnectorCallAdmissionPolicy | undefined, true>, "parse"> & {
|
|
88
87
|
parse(value: unknown, path: string): ConnectorCallAdmissionPolicy;
|
|
89
88
|
readonly shape: typeof admissionPolicy.shape;
|
|
@@ -91,15 +90,18 @@ export declare const PROVIDER_COMMON: {
|
|
|
91
90
|
instructions: Field<unknown, unknown, true>;
|
|
92
91
|
title: Field<unknown, unknown, true>;
|
|
93
92
|
authScope: Field<unknown, unknown, true>;
|
|
94
|
-
maxResultBytes: Field<unknown, unknown, true>;
|
|
95
93
|
purpose: Field<unknown, unknown, true>;
|
|
94
|
+
maxResultBytes: Field<unknown, unknown, true>;
|
|
96
95
|
};
|
|
97
96
|
/** The provider's maintained, connection-independent usage guide. */
|
|
98
97
|
export interface ProviderSkill {
|
|
99
98
|
/**
|
|
100
99
|
* Markdown rendered after the heading and the connection context. It states
|
|
101
100
|
* conventions the vendor's schemas cannot carry, and never varies by
|
|
102
|
-
* deployment.
|
|
101
|
+
* deployment. A standard guide (decision 0011, G) is `SKILL.md`'s body
|
|
102
|
+
* followed by its generated `## Conventions`; text that differs by
|
|
103
|
+
* implementation or option stands in `<!-- when: <key> -->` …
|
|
104
|
+
* `<!-- end -->` blocks the definition's `blocks` selects.
|
|
103
105
|
*/
|
|
104
106
|
content: string;
|
|
105
107
|
/** Heading for deployment instructions, such as `"Workspace instructions"`. */
|
|
@@ -107,6 +109,56 @@ export interface ProviderSkill {
|
|
|
107
109
|
/** Exact generated guide fragments used by existing renderers. */
|
|
108
110
|
fragments?: Readonly<Record<string, string>>;
|
|
109
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* The closed key set of a guide's `<!-- when: <key> -->` blocks and the pure
|
|
114
|
+
* selector that picks a connection's keys from its options (decision 0011,
|
|
115
|
+
* G2). Select only the blocks this API configuration uses.
|
|
116
|
+
*/
|
|
117
|
+
export interface ProviderGuideBlocks<O> {
|
|
118
|
+
readonly keys: readonly string[];
|
|
119
|
+
/** The keys whose blocks this connection renders, in any order. */
|
|
120
|
+
select(options: Readonly<O>): readonly string[];
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Facts the provider kit (decision 0010) declares for `providers:generate`:
|
|
124
|
+
* `drift.json`'s `generated.operations` and the guide's Conventions. Plain
|
|
125
|
+
* data, never read at runtime. The kit's `defineApiProvider` sets them.
|
|
126
|
+
*/
|
|
127
|
+
export interface ProviderKitFacts {
|
|
128
|
+
/** `manifest(vendor)`: every operation the provider's tools send, as `"METHOD /path"`. */
|
|
129
|
+
readonly operations: readonly string[];
|
|
130
|
+
/** The `limit` default and maximum every paged read declares. */
|
|
131
|
+
readonly pageSize?: {
|
|
132
|
+
readonly default: number;
|
|
133
|
+
readonly max: number;
|
|
134
|
+
};
|
|
135
|
+
/** The hatch's tool prefix and its reviewed verdict per `"METHOD /path"`. */
|
|
136
|
+
readonly hatch?: {
|
|
137
|
+
readonly name: string;
|
|
138
|
+
readonly verdicts: Readonly<Record<string, "read" | "write" | "destructive" | "refuse">>;
|
|
139
|
+
/** Separate-cursor paging opts into the generated hatch paging convention. */
|
|
140
|
+
readonly paging?: "argument" | "parameter";
|
|
141
|
+
readonly fieldsRoot?: string;
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* The vendor's declared error meanings, for the Errors convention: the code
|
|
145
|
+
* an unknown id fails with, whether it proves absence, and each documented
|
|
146
|
+
* conflict source.
|
|
147
|
+
*/
|
|
148
|
+
readonly errors?: {
|
|
149
|
+
readonly unknownId: ConnectorCallErrorCode;
|
|
150
|
+
readonly provesAbsence: boolean;
|
|
151
|
+
readonly conflicts: readonly string[];
|
|
152
|
+
};
|
|
153
|
+
/** Whether a write takes an idempotency key the vendor honors, checked against the built tools. */
|
|
154
|
+
readonly idempotencyKey?: boolean;
|
|
155
|
+
/**
|
|
156
|
+
* Set only when the hatch refuses a write carrying a withheld placeholder
|
|
157
|
+
* value; the Withheld values convention promises exactly that. The kit sets
|
|
158
|
+
* it for its standard hatch; kit write builders refuse the same markers.
|
|
159
|
+
*/
|
|
160
|
+
readonly refusesWithheld?: true;
|
|
161
|
+
}
|
|
110
162
|
/** Connection facts a provider renders around its maintained guide. */
|
|
111
163
|
export interface ProviderGuideInput {
|
|
112
164
|
/**
|
|
@@ -123,13 +175,11 @@ export interface ProviderGuideInput {
|
|
|
123
175
|
}
|
|
124
176
|
/** What `defineProvider()` hands `create` after validating its options. */
|
|
125
177
|
export interface ProviderContext {
|
|
126
|
-
/** The definition's reviewed classification, for `remoteMcp({ classify })`. */
|
|
127
|
-
readonly classify?: ToolClassification;
|
|
128
178
|
/**
|
|
129
179
|
* Common connector options the deployment set, and only those, ready to
|
|
130
180
|
* spread into `remoteMcp()` or `api()` options.
|
|
131
181
|
*/
|
|
132
|
-
readonly connectorOptions: Readonly<Pick<ProviderOptions, "authScope" | "maxResultBytes" | "callAdmission">>;
|
|
182
|
+
readonly connectorOptions: Readonly<Pick<ProviderOptions, "authScope" | "maxResultBytes" | "callAdmission" | "readOnly">>;
|
|
133
183
|
/**
|
|
134
184
|
* Render the maintained skill with this connection's context and the
|
|
135
185
|
* deployment's instructions. Instructions are appended; they never replace
|
|
@@ -145,26 +195,23 @@ export interface ProviderDefinition<O extends ProviderOptions> {
|
|
|
145
195
|
name: string;
|
|
146
196
|
/** Vendor display name, and the default guide heading. */
|
|
147
197
|
title: string;
|
|
148
|
-
kind:
|
|
198
|
+
kind: "api";
|
|
149
199
|
skill: ProviderSkill;
|
|
150
200
|
/** Maintained display name in the generated README inventory. */
|
|
151
201
|
readme?: string;
|
|
152
|
-
/** Reviewed build facts
|
|
202
|
+
/** Reviewed build facts: the bundle report's baseline, never a cap. */
|
|
153
203
|
bundle?: {
|
|
154
204
|
baselineGzip: number;
|
|
155
|
-
|
|
205
|
+
/** @deprecated Ignored: provider entries are reported, not capped. */
|
|
206
|
+
maxGzip?: number;
|
|
156
207
|
note?: string;
|
|
157
208
|
};
|
|
158
209
|
/** Closed factory options, declared with `optionsOf<O>()` for key parity. */
|
|
159
210
|
options: Field<unknown, unknown>;
|
|
160
|
-
/**
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
* the record a drift check reads cannot disagree. `api()` providers annotate
|
|
165
|
-
* each tool they author and must omit it.
|
|
166
|
-
*/
|
|
167
|
-
classify?: ToolClassification;
|
|
211
|
+
/** Required when the guide holds `<!-- when: <key> -->` blocks. */
|
|
212
|
+
blocks?: ProviderGuideBlocks<O>;
|
|
213
|
+
/** Set by the provider kit; see `ProviderKitFacts`. */
|
|
214
|
+
kit?: ProviderKitFacts;
|
|
168
215
|
/**
|
|
169
216
|
* Build the connector. Runs synchronously at construction after its closed
|
|
170
217
|
* options and common values are validated. Throw here for provider-specific
|
|
@@ -185,12 +232,4 @@ export interface ProviderFactory<O extends ProviderOptions> {
|
|
|
185
232
|
* so a deployment never boots in the wrong shape (INV-11).
|
|
186
233
|
*/
|
|
187
234
|
export declare function defineProvider<O extends ProviderOptions>(definition: ProviderDefinition<O>): ProviderFactory<O>;
|
|
188
|
-
/**
|
|
189
|
-
* Attach the same validated definition to an existing provider constructor.
|
|
190
|
-
* Its option policy stays in its builder during the mechanical folder move;
|
|
191
|
-
* adopting defineProvider's common-value policy is a separate conversion.
|
|
192
|
-
*/
|
|
193
|
-
export declare function asProviderFactory<O extends ProviderOptions>(definition: Omit<ProviderDefinition<O>, "create"> & {
|
|
194
|
-
create(id: string, options: Readonly<O>): Connector;
|
|
195
|
-
}): ProviderFactory<O>;
|
|
196
235
|
export {};
|
package/dist/provider.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
//
|
|
2
|
-
// it imports neither `remoteMcp()` nor `api()`, so an `api()` provider does not
|
|
3
|
-
// acquire the MCP client, OAuth, or Effect graph by using it, and a hosted
|
|
4
|
-
// provider does not acquire `api()`. Its runtime imports validate plain
|
|
5
|
-
// options and reviewed classification, with no I/O.
|
|
1
|
+
// Transport-free maintained API provider definitions and construction validation.
|
|
6
2
|
import { array, assertKnownOptions, ConfigError, fn, keys, object, opaque, required, whole, } from "./config-schema.js";
|
|
7
|
-
import {
|
|
3
|
+
import { aliasCallIdentity } from "./provider-call-facts.js";
|
|
4
|
+
import { isConnectorCallErrorCode } from "./errors.js";
|
|
8
5
|
const budget = {
|
|
9
6
|
...object({
|
|
10
7
|
kind: required(opaque({
|
|
@@ -50,16 +47,89 @@ export const CALL_ADMISSION = {
|
|
|
50
47
|
return policy;
|
|
51
48
|
},
|
|
52
49
|
};
|
|
50
|
+
/** Validate the common connector policy before a deployment can serve. */
|
|
51
|
+
export const READ_ONLY = opaque({
|
|
52
|
+
check(value, path) {
|
|
53
|
+
if (typeof value !== "boolean")
|
|
54
|
+
throw new ConfigError(`${path} must be a boolean.`);
|
|
55
|
+
},
|
|
56
|
+
});
|
|
53
57
|
/** Options every maintained provider shares. */
|
|
54
58
|
export const PROVIDER_COMMON = {
|
|
55
59
|
...keys("title", "authScope", "purpose", "instructions", "maxResultBytes"),
|
|
60
|
+
readOnly: READ_ONLY,
|
|
56
61
|
callAdmission: CALL_ADMISSION,
|
|
57
62
|
};
|
|
58
63
|
const PROVIDER_NAME = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
59
|
-
const
|
|
64
|
+
const BLOCK_KEY = /^[a-z][a-z0-9:-]*$/;
|
|
65
|
+
/** A when-block marker, alone on its line. */
|
|
66
|
+
const BLOCK_MARKER = /^<!--\s*(?:when:\s*([a-z][a-z0-9:-]*)|end)\s*-->$/;
|
|
60
67
|
function nonEmpty(value) {
|
|
61
68
|
return typeof value === "string" && value.trim() !== "";
|
|
62
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Render a guide's selected when-blocks, or, with no selection, check them
|
|
72
|
+
* and return their keys. Markers stand alone on their lines and never nest.
|
|
73
|
+
* Removing an unselected block also removes the blank line it leaves, so
|
|
74
|
+
* paragraphs and tight lists keep their spacing.
|
|
75
|
+
*/
|
|
76
|
+
function guideBlocks(content, selected) {
|
|
77
|
+
const keys = new Set();
|
|
78
|
+
const kept = [];
|
|
79
|
+
let open;
|
|
80
|
+
let seam = false;
|
|
81
|
+
for (const line of content.split("\n")) {
|
|
82
|
+
const marker = BLOCK_MARKER.exec(line.trim());
|
|
83
|
+
if (marker) {
|
|
84
|
+
if (marker[1] !== undefined ? open !== undefined : open === undefined) {
|
|
85
|
+
throw new Error("when-blocks must open and close in turn, unnested");
|
|
86
|
+
}
|
|
87
|
+
if (marker[1] !== undefined)
|
|
88
|
+
keys.add((open = marker[1]));
|
|
89
|
+
else {
|
|
90
|
+
seam = selected !== undefined && !selected.has(open);
|
|
91
|
+
open = undefined;
|
|
92
|
+
}
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (/<!--\s*(?:when:|end\s*-->)/.test(line))
|
|
96
|
+
throw new Error("a when-block marker stands alone on its line");
|
|
97
|
+
if (open !== undefined && !selected?.has(open))
|
|
98
|
+
continue;
|
|
99
|
+
if (seam && !line.trim() && (kept.length === 0 || !kept.at(-1).trim()))
|
|
100
|
+
continue;
|
|
101
|
+
seam = false;
|
|
102
|
+
kept.push(line);
|
|
103
|
+
}
|
|
104
|
+
if (open !== undefined)
|
|
105
|
+
throw new Error(`the when-block "${open}" is never closed`);
|
|
106
|
+
return { text: kept.join("\n").trim(), keys };
|
|
107
|
+
}
|
|
108
|
+
/** A frozen copy: kit facts are review evidence `providers:generate` reads. */
|
|
109
|
+
function kitFacts(kit) {
|
|
110
|
+
if (kit.errors && !isConnectorCallErrorCode(kit.errors.unknownId)) {
|
|
111
|
+
throw new Error("Provider kit errors.unknownId must be a ConnectorCallErrorCode.");
|
|
112
|
+
}
|
|
113
|
+
return Object.freeze({
|
|
114
|
+
operations: Object.freeze([...kit.operations]),
|
|
115
|
+
...(kit.pageSize ? { pageSize: Object.freeze({ ...kit.pageSize }) } : {}),
|
|
116
|
+
...(kit.hatch
|
|
117
|
+
? {
|
|
118
|
+
hatch: Object.freeze({
|
|
119
|
+
name: kit.hatch.name,
|
|
120
|
+
verdicts: Object.freeze({ ...kit.hatch.verdicts }),
|
|
121
|
+
...(kit.hatch.paging ? { paging: kit.hatch.paging } : {}),
|
|
122
|
+
...(kit.hatch.fieldsRoot ? { fieldsRoot: kit.hatch.fieldsRoot } : {}),
|
|
123
|
+
}),
|
|
124
|
+
}
|
|
125
|
+
: {}),
|
|
126
|
+
...(kit.errors
|
|
127
|
+
? { errors: Object.freeze({ ...kit.errors, conflicts: Object.freeze([...kit.errors.conflicts]) }) }
|
|
128
|
+
: {}),
|
|
129
|
+
...(kit.idempotencyKey !== undefined ? { idempotencyKey: kit.idempotencyKey } : {}),
|
|
130
|
+
...(kit.refusesWithheld ? { refusesWithheld: true } : {}),
|
|
131
|
+
});
|
|
132
|
+
}
|
|
63
133
|
/**
|
|
64
134
|
* Define a maintained provider: one validated description and one factory.
|
|
65
135
|
*
|
|
@@ -75,23 +145,37 @@ export function defineProvider(definition) {
|
|
|
75
145
|
if (!nonEmpty(definition.title)) {
|
|
76
146
|
throw new Error(`${label} requires a non-empty title.`);
|
|
77
147
|
}
|
|
78
|
-
if (
|
|
79
|
-
throw new Error(`${label} kind must be "
|
|
80
|
-
}
|
|
148
|
+
if (definition.kind !== "api")
|
|
149
|
+
throw new Error(`${label} kind must be "api".`);
|
|
81
150
|
if (!nonEmpty(definition.skill?.content) || !nonEmpty(definition.skill.instructionsHeading)) {
|
|
82
151
|
throw new Error(`${label} skill requires non-empty content and instructionsHeading.`);
|
|
83
152
|
}
|
|
84
|
-
if (
|
|
85
|
-
throw new Error(`${label}
|
|
86
|
-
}
|
|
153
|
+
if (Object.hasOwn(definition, "classify"))
|
|
154
|
+
throw new Error(`${label} classify was removed; use ConnectaConfig.classification.`);
|
|
87
155
|
if (!definition.options?.shape && !definition.options?.variants) {
|
|
88
156
|
throw new Error(`${label} requires a closed options shape from optionsOf().`);
|
|
89
157
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
158
|
+
const blocks = definition.blocks;
|
|
159
|
+
if (blocks !== undefined &&
|
|
160
|
+
(!Array.isArray(blocks.keys) ||
|
|
161
|
+
blocks.keys.length === 0 ||
|
|
162
|
+
!blocks.keys.every((key) => typeof key === "string" && BLOCK_KEY.test(key)) ||
|
|
163
|
+
new Set(blocks.keys).size !== blocks.keys.length ||
|
|
164
|
+
typeof blocks.select !== "function")) {
|
|
165
|
+
throw new Error(`${label} blocks require unique lowercase keys and a select function.`);
|
|
166
|
+
}
|
|
167
|
+
let used;
|
|
168
|
+
try {
|
|
169
|
+
used = guideBlocks(definition.skill.content).keys;
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
throw new Error(`${label} skill: ${error instanceof Error ? error.message : String(error)}.`, { cause: error });
|
|
173
|
+
}
|
|
174
|
+
for (const key of used) {
|
|
175
|
+
if (!blocks?.keys.includes(key))
|
|
176
|
+
throw new Error(`${label} skill uses the when-block "${key}" its blocks omit.`);
|
|
177
|
+
}
|
|
178
|
+
// Freeze definition facts consumed by construction, generation and checks.
|
|
95
179
|
if (typeof definition.create !== "function") {
|
|
96
180
|
throw new Error(`${label} requires a create function.`);
|
|
97
181
|
}
|
|
@@ -102,7 +186,8 @@ export function defineProvider(definition) {
|
|
|
102
186
|
...(definition.skill.fragments ? { fragments: Object.freeze(definition.skill.fragments) } : {}),
|
|
103
187
|
}),
|
|
104
188
|
...(definition.bundle ? { bundle: Object.freeze({ ...definition.bundle }) } : {}),
|
|
105
|
-
...(
|
|
189
|
+
...(blocks ? { blocks: Object.freeze({ keys: Object.freeze([...blocks.keys]), select: blocks.select }) } : {}),
|
|
190
|
+
...(definition.kit ? { kit: kitFacts(definition.kit) } : {}),
|
|
106
191
|
});
|
|
107
192
|
const factoryName = `${frozen.name.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase())}()`;
|
|
108
193
|
const factory = (id, options) => asProvider(frozen.name, frozen.options, id, options, (id, options) => {
|
|
@@ -125,15 +210,28 @@ export function defineProvider(definition) {
|
|
|
125
210
|
const resolved = { ...options, purpose: options.purpose.trim() };
|
|
126
211
|
const instructions = options.instructions?.trim();
|
|
127
212
|
const connector = frozen.create(id, resolved, {
|
|
128
|
-
...(frozen.classify !== undefined ? { classify: frozen.classify } : {}),
|
|
129
213
|
connectorOptions: {
|
|
214
|
+
...(options.readOnly !== undefined ? { readOnly: options.readOnly } : {}),
|
|
130
215
|
...(options.authScope !== undefined ? { authScope: options.authScope } : {}),
|
|
131
216
|
...(options.maxResultBytes !== undefined ? { maxResultBytes: options.maxResultBytes } : {}),
|
|
132
217
|
...(options.callAdmission !== undefined ? { callAdmission: options.callAdmission } : {}),
|
|
133
218
|
},
|
|
134
219
|
usageGuide(input) {
|
|
135
220
|
const heading = input.heading ?? `${frozen.title} usage`;
|
|
136
|
-
|
|
221
|
+
let guide = frozen.skill.content.trim();
|
|
222
|
+
if (frozen.blocks) {
|
|
223
|
+
const { keys, select } = frozen.blocks;
|
|
224
|
+
const selected = select(resolved);
|
|
225
|
+
if (!Array.isArray(selected))
|
|
226
|
+
throw new Error(`${at} requires blocks.select() to return an array of keys.`);
|
|
227
|
+
for (const key of selected) {
|
|
228
|
+
if (!keys.includes(key)) {
|
|
229
|
+
throw new Error(`${at} requires blocks.select() to return declared keys; it returned ${String(key)}.`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
guide = guideBlocks(frozen.skill.content, new Set(selected)).text;
|
|
233
|
+
}
|
|
234
|
+
const body = [...input.context, guide].join("\n\n");
|
|
137
235
|
return {
|
|
138
236
|
content: `# ${heading}\n\n${body}\n` +
|
|
139
237
|
(instructions ? `\n## ${frozen.skill.instructionsHeading}\n\n${instructions}\n` : ""),
|
|
@@ -147,28 +245,13 @@ export function defineProvider(definition) {
|
|
|
147
245
|
}
|
|
148
246
|
return connector;
|
|
149
247
|
});
|
|
150
|
-
//
|
|
151
|
-
// factory classifies, so neither replacing nor deleting it may take effect.
|
|
152
|
-
return Object.freeze(Object.assign(factory, { definition: frozen }));
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* Attach the same validated definition to an existing provider constructor.
|
|
156
|
-
* Its option policy stays in its builder during the mechanical folder move;
|
|
157
|
-
* adopting defineProvider's common-value policy is a separate conversion.
|
|
158
|
-
*/
|
|
159
|
-
export function asProviderFactory(definition) {
|
|
160
|
-
const frozen = defineProvider(definition).definition;
|
|
161
|
-
const create = definition.create;
|
|
162
|
-
const factory = (id, options) => asProvider(frozen.name, frozen.options, id, options, create);
|
|
163
|
-
Object.defineProperty(factory, "name", {
|
|
164
|
-
value: frozen.name.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()),
|
|
165
|
-
});
|
|
248
|
+
// Build and check tools rely on this definition remaining attached.
|
|
166
249
|
return Object.freeze(Object.assign(factory, { definition: frozen }));
|
|
167
250
|
}
|
|
168
251
|
/**
|
|
169
252
|
* Build a maintained provider's connector: refuse unknown options and
|
|
170
253
|
* accessors by path before the builder reads any of them, then stamp the
|
|
171
|
-
* provider onto its description, so the operator surface can say "
|
|
254
|
+
* provider onto its description, so the operator surface can say "Stripe"
|
|
172
255
|
* rather than "remote MCP". This is the same construction path defineProvider
|
|
173
256
|
* uses; existing constructors retain their provider-specific option policy.
|
|
174
257
|
*/
|
|
@@ -178,6 +261,8 @@ function asProvider(provider, shape, id, options, build) {
|
|
|
178
261
|
let connector;
|
|
179
262
|
try {
|
|
180
263
|
options = assertKnownOptions(options, `${factory}(${JSON.stringify(id)})`, shape);
|
|
264
|
+
if (options?.readOnly !== undefined)
|
|
265
|
+
READ_ONLY.parse(options.readOnly, `${factory}(${JSON.stringify(id)}).readOnly`);
|
|
181
266
|
const admission = options == null ? undefined : options.callAdmission;
|
|
182
267
|
if (admission !== undefined)
|
|
183
268
|
CALL_ADMISSION.parse(admission, `${factory}(${JSON.stringify(id)}).callAdmission`);
|
|
@@ -188,12 +273,21 @@ function asProvider(provider, shape, id, options, build) {
|
|
|
188
273
|
}
|
|
189
274
|
const describe = connector.describe?.bind(connector);
|
|
190
275
|
const ownDescribe = Object.getOwnPropertyDescriptor(connector, "describe");
|
|
276
|
+
const ownReadOnly = Object.getOwnPropertyDescriptor(connector, "readOnly");
|
|
191
277
|
// Keep the receiver of prototype methods (including private fields). When
|
|
192
278
|
// the description cannot be replaced, inherit the whole connector instead
|
|
193
|
-
// of copying it: decorators may inherit their id
|
|
194
|
-
const stamped = Object.isExtensible(connector) &&
|
|
279
|
+
// of copying it: decorators may inherit their id and methods.
|
|
280
|
+
const stamped = Object.isExtensible(connector) &&
|
|
281
|
+
(!ownDescribe || ownDescribe.configurable) &&
|
|
282
|
+
(options.readOnly === undefined || !ownReadOnly || ownReadOnly.configurable)
|
|
195
283
|
? connector
|
|
196
284
|
: Object.create(connector);
|
|
285
|
+
// An inheriting stamp serves the connector itself, so it keeps its call identity.
|
|
286
|
+
if (stamped !== connector)
|
|
287
|
+
aliasCallIdentity(stamped, connector);
|
|
288
|
+
if (options.readOnly !== undefined) {
|
|
289
|
+
Object.defineProperty(stamped, "readOnly", { value: options.readOnly, enumerable: true, configurable: true });
|
|
290
|
+
}
|
|
197
291
|
Object.defineProperty(stamped, "describe", {
|
|
198
292
|
configurable: true,
|
|
199
293
|
enumerable: false,
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// Opt-in plumbing only. Product PRs supply their reviewed literal verdicts.
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
import { ConnectorCallError } from "../../../errors.js";
|
|
4
|
+
export function requireGoogleIndex(index) {
|
|
5
|
+
if (!index)
|
|
6
|
+
throw new Error("Google requests require their reviewed operation index.");
|
|
7
|
+
if (index.pathMatching !== "uri-template")
|
|
8
|
+
throw new Error('Google indexes require pathMatching: "uri-template".');
|
|
9
|
+
}
|
|
10
|
+
/** Independent of compact schema depth: only reviewed batch kinds can execute. */
|
|
11
|
+
export function googleBatchGuard(body, options) {
|
|
12
|
+
if (!body || typeof body !== "object" || Array.isArray(body))
|
|
13
|
+
return "A Google batch body must be an object.";
|
|
14
|
+
const value = body;
|
|
15
|
+
const requests = value["requests"];
|
|
16
|
+
if (!Array.isArray(requests) || !requests.length || requests.length > (options.max ?? 100))
|
|
17
|
+
return `A Google batch needs 1–${options.max ?? 100} requests.`;
|
|
18
|
+
if (requests.some((request) => !request ||
|
|
19
|
+
typeof request !== "object" ||
|
|
20
|
+
Array.isArray(request) ||
|
|
21
|
+
Object.keys(request).length !== 1 ||
|
|
22
|
+
!options.kinds.includes(Object.keys(request)[0])))
|
|
23
|
+
return "Each Google batch request must contain exactly one reviewed request kind.";
|
|
24
|
+
const control = value["writeControl"];
|
|
25
|
+
if (options.revision &&
|
|
26
|
+
(!control || typeof control["requiredRevisionId"] !== "string" || !control["requiredRevisionId"].trim()))
|
|
27
|
+
return "This Google batch needs a nonempty writeControl.requiredRevisionId from a current read.";
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
/** Ensure a substituted named id still reaches the endpoint the tool declared. */
|
|
31
|
+
export function googleNamedOperation(index, method, path, template) {
|
|
32
|
+
requireGoogleIndex(index);
|
|
33
|
+
if (index.resolve(method, path).op.path !== template)
|
|
34
|
+
throw new ConnectorCallError("invalid_args", "This Google id resolves to a different operation; no request was sent.");
|
|
35
|
+
}
|
|
36
|
+
export function googleHatchBinding(connection, options) {
|
|
37
|
+
requireGoogleIndex(options.index);
|
|
38
|
+
return {
|
|
39
|
+
index: options.index,
|
|
40
|
+
...(options.wrapSend ? { warnings: true } : {}),
|
|
41
|
+
review: options.review,
|
|
42
|
+
...(options.refusal ? { refusal: options.refusal } : {}),
|
|
43
|
+
refuse: (call) => {
|
|
44
|
+
for (const match of call.path.matchAll(/%([a-f0-9]{2})/gi))
|
|
45
|
+
if (/^[-A-Za-z0-9._~:]$/.test(String.fromCharCode(parseInt(match[1], 16))))
|
|
46
|
+
return "Google paths must spell unreserved characters and action separators literally.";
|
|
47
|
+
if (call.headers && Object.keys(call.headers).length)
|
|
48
|
+
return "Google hatches do not accept caller headers.";
|
|
49
|
+
for (const key of Object.keys(call.query))
|
|
50
|
+
if ([
|
|
51
|
+
"access_token",
|
|
52
|
+
"oauth_token",
|
|
53
|
+
"key",
|
|
54
|
+
"callback",
|
|
55
|
+
"upload_protocol",
|
|
56
|
+
"uploadType",
|
|
57
|
+
"userId",
|
|
58
|
+
"quotaUser",
|
|
59
|
+
].includes(key))
|
|
60
|
+
return `Google query.${key} is owned by the deployment and cannot be selected by a caller.`;
|
|
61
|
+
if (call.query["alt"] !== undefined && call.query["alt"] !== "json")
|
|
62
|
+
return "Google hatches return JSON only; use a named content tool for media.";
|
|
63
|
+
return options.refuse?.(call);
|
|
64
|
+
},
|
|
65
|
+
send: (call, sendOptions) => Effect.suspend(() => {
|
|
66
|
+
// Capture the admitted wire request before the wrapper can inspect its copy.
|
|
67
|
+
const request = {
|
|
68
|
+
method: call.method,
|
|
69
|
+
path: call.path,
|
|
70
|
+
template: call.op.path,
|
|
71
|
+
query: Object.entries(call.query).flatMap(([name, value]) => value === undefined
|
|
72
|
+
? []
|
|
73
|
+
: (Array.isArray(value) ? value : [value]).map((item) => [name, String(item)])),
|
|
74
|
+
headers: { accept: "application/json" },
|
|
75
|
+
...(call.body === undefined ? {} : { json: JSON.stringify(call.body) }),
|
|
76
|
+
};
|
|
77
|
+
const optionsForSend = {
|
|
78
|
+
...sendOptions,
|
|
79
|
+
...(options.revisionGuarded?.(call) ? { flags: { revisionGuarded: true } } : {}),
|
|
80
|
+
};
|
|
81
|
+
let sent = false;
|
|
82
|
+
const send = () => Effect.suspend(() => {
|
|
83
|
+
if (sent)
|
|
84
|
+
return Effect.die(new Error("A Google hatch wrapper may send its admitted request only once."));
|
|
85
|
+
sent = true;
|
|
86
|
+
return connection.sendPath(request, optionsForSend);
|
|
87
|
+
});
|
|
88
|
+
return options.wrapSend ? options.wrapSend(structuredClone(call), send) : send();
|
|
89
|
+
}),
|
|
90
|
+
};
|
|
91
|
+
}
|