@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/catalog-cache.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
import { detach, runEdge } from "./runtime/run.js";
|
|
2
|
+
import { Deferred, Effect } from "effect";
|
|
3
|
+
import { authFlow, authCall, authInvoke, authValue, authMethod, authProgram, registerAuth, authStorage, authMap, authAwait, } from "./auth/native.js";
|
|
1
4
|
import { MAX_CACHE_TTL_MS, specTypeSchemas } from "@modelcontextprotocol/client";
|
|
2
5
|
import { callerOf } from "./connector-caller.js";
|
|
3
6
|
import { CONFIG_DEFAULTS } from "./config-defaults.js";
|
|
7
|
+
import { Context } from "effect";
|
|
8
|
+
import { RequestScope } from "./runtime/request-scope.js";
|
|
9
|
+
import { serviceFor, setViewService, viewServices } from "./runtime/call.js";
|
|
4
10
|
import { ConnectorCallError } from "./errors.js";
|
|
5
11
|
import { fingerprintSerializedCatalog } from "./catalog-fingerprint.js";
|
|
6
12
|
import { MAX_CATALOG_CHUNK_BYTES, MAX_CATALOG_TOOLS, MAX_SERIALIZED_CATALOG_BYTES } from "./catalog-limits.js";
|
|
@@ -8,21 +14,32 @@ import { redactCatalog, sentSecretsForRequest } from "./sent-secrets.js";
|
|
|
8
14
|
import { failureRecord, logFailure } from "./operator-record.js";
|
|
9
15
|
import { responseCacheKeys } from "./storage/keys.js";
|
|
10
16
|
/** Publish one accepted catalog refresh, with its partitioned drift baseline. */
|
|
11
|
-
export
|
|
12
|
-
|
|
17
|
+
export function observeCompletedCatalogRefresh(ctx, refresh) {
|
|
18
|
+
return runEdge(authProgram(observeCompletedCatalogRefreshNative, [ctx, refresh]));
|
|
13
19
|
}
|
|
20
|
+
const observeCompletedCatalogRefreshNative = /* @__PURE__ */ registerAuth(observeCompletedCatalogRefresh, (ctx, refresh) => authFlow(function* () {
|
|
21
|
+
(yield authValue(() => serviceFor(ctx, CatalogPolicy)?.onCompletedCatalogRefresh?.(refresh, ctx)));
|
|
22
|
+
}));
|
|
14
23
|
/** Hash-only facts preserve change counts without storing tool names or schemas. */
|
|
15
|
-
|
|
24
|
+
function catalogFingerprints(tools) {
|
|
25
|
+
return runEdge(authProgram(catalogFingerprintsNative, [tools]));
|
|
26
|
+
}
|
|
27
|
+
const catalogFingerprintsNative = /* @__PURE__ */ registerAuth(catalogFingerprints, (tools) => authFlow(function* () {
|
|
16
28
|
const facts = [];
|
|
17
29
|
for (let offset = 0; offset < tools.length; offset += 128) {
|
|
18
|
-
facts.push(...(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
30
|
+
facts.push(...(yield authMap(tools.slice(offset, offset + 128), (value) => authCall(authMethod((tool) => authFlow(function* () {
|
|
31
|
+
return {
|
|
32
|
+
name: (yield authCall(fingerprintSerializedCatalog, [tool.name])).fingerprint,
|
|
33
|
+
fact: (yield authCall(fingerprintSerializedCatalog, [JSON.stringify(tool)])).fingerprint,
|
|
34
|
+
};
|
|
35
|
+
})), [value]), false)));
|
|
22
36
|
}
|
|
23
37
|
return facts;
|
|
38
|
+
}));
|
|
39
|
+
function refreshBaseline(storage, key, raw, io) {
|
|
40
|
+
return runEdge(authProgram(refreshBaselineNative, [storage, key, raw, io]));
|
|
24
41
|
}
|
|
25
|
-
|
|
42
|
+
const refreshBaselineNative = /* @__PURE__ */ registerAuth(refreshBaseline, (storage, key, raw, io) => authFlow(function* () {
|
|
26
43
|
if (!raw)
|
|
27
44
|
return;
|
|
28
45
|
try {
|
|
@@ -37,13 +54,15 @@ async function refreshBaseline(storage, key, raw, io) {
|
|
|
37
54
|
return;
|
|
38
55
|
const chunks = [];
|
|
39
56
|
for (let index = 0; index < value.chunkCount; index++) {
|
|
40
|
-
const chunk =
|
|
57
|
+
const chunk = (yield authCall(io, [
|
|
58
|
+
authMethod(() => authStorage(storage, "get", [responseCacheKeys.chunk(key, value.revision, index)])),
|
|
59
|
+
]));
|
|
41
60
|
if (chunk === null || new TextEncoder().encode(chunk).byteLength > MAX_CATALOG_CHUNK_BYTES)
|
|
42
61
|
return;
|
|
43
62
|
chunks.push(chunk);
|
|
44
63
|
}
|
|
45
64
|
const serialized = chunks.join("");
|
|
46
|
-
if ((
|
|
65
|
+
if ((yield authCall(fingerprintSerializedCatalog, [serialized])).fingerprint !== value.fingerprint)
|
|
47
66
|
return;
|
|
48
67
|
const tools = JSON.parse(serialized);
|
|
49
68
|
if (Array.isArray(tools) &&
|
|
@@ -51,34 +70,57 @@ async function refreshBaseline(storage, key, raw, io) {
|
|
|
51
70
|
tools.every((tool) => tool && hash(tool.name) && hash(tool.fact)))
|
|
52
71
|
return { digest: value.digest, tools };
|
|
53
72
|
}
|
|
54
|
-
catch {
|
|
55
|
-
|
|
56
|
-
|
|
73
|
+
catch { }
|
|
74
|
+
}));
|
|
75
|
+
function acceptCatalogRefresh(storage, key, connectorId, digest, tools, privateCatalog, current, io) {
|
|
76
|
+
return runEdge(authProgram(acceptCatalogRefreshNative, [
|
|
77
|
+
storage,
|
|
78
|
+
key,
|
|
79
|
+
connectorId,
|
|
80
|
+
digest,
|
|
81
|
+
tools,
|
|
82
|
+
privateCatalog,
|
|
83
|
+
current,
|
|
84
|
+
io,
|
|
85
|
+
]));
|
|
57
86
|
}
|
|
58
|
-
|
|
59
|
-
const next =
|
|
87
|
+
const acceptCatalogRefreshNative = /* @__PURE__ */ registerAuth(acceptCatalogRefresh, (storage, key, connectorId, digest, tools, privateCatalog, current, io) => authFlow(function* () {
|
|
88
|
+
const next = (yield authCall(catalogFingerprints, [tools]));
|
|
60
89
|
const serialized = JSON.stringify(next);
|
|
61
90
|
const revision = crypto.randomUUID();
|
|
62
|
-
const fingerprint = (
|
|
63
|
-
// Fingerprints are ASCII. Chunk them under the same platform value ceiling
|
|
64
|
-
// as catalogs, then publish their manifest in one compare-and-set.
|
|
91
|
+
const fingerprint = (yield authCall(fingerprintSerializedCatalog, [serialized])).fingerprint;
|
|
65
92
|
const chunkCount = Math.ceil(serialized.length / MAX_CATALOG_CHUNK_BYTES);
|
|
66
93
|
for (let index = 0; index < chunkCount; index++) {
|
|
67
|
-
if (!(
|
|
94
|
+
if (!(yield authCall(current, [])))
|
|
68
95
|
return;
|
|
69
96
|
const chunk = serialized.slice(index * MAX_CATALOG_CHUNK_BYTES, (index + 1) * MAX_CATALOG_CHUNK_BYTES);
|
|
70
|
-
|
|
97
|
+
(yield authCall(io, [
|
|
98
|
+
authMethod(() => authStorage(storage, "set", [
|
|
99
|
+
responseCacheKeys.chunk(key, revision, index),
|
|
100
|
+
chunk,
|
|
101
|
+
{ ttlSeconds: GENERATION_TTL_SECONDS + 300 },
|
|
102
|
+
])),
|
|
103
|
+
]));
|
|
71
104
|
}
|
|
72
105
|
const manifest = { digest, revision, chunkCount, fingerprint };
|
|
73
106
|
for (let attempt = 0; attempt < 16; attempt++) {
|
|
74
|
-
if (!(
|
|
107
|
+
if (!(yield authCall(current, [])))
|
|
75
108
|
return;
|
|
76
|
-
const raw =
|
|
77
|
-
|
|
78
|
-
|
|
109
|
+
const raw = (yield authCall(io, [
|
|
110
|
+
authMethod(() => authStorage(storage, "get", [key])),
|
|
111
|
+
]));
|
|
112
|
+
const previous = (yield authCall(refreshBaseline, [storage, key, raw, io]));
|
|
113
|
+
if (!(yield authCall(current, [])))
|
|
79
114
|
return;
|
|
80
|
-
const published =
|
|
81
|
-
|
|
115
|
+
const published = (yield authCall(io, [
|
|
116
|
+
authMethod(() => authStorage(storage, "compareAndSet", [
|
|
117
|
+
key,
|
|
118
|
+
raw,
|
|
119
|
+
JSON.stringify(manifest),
|
|
120
|
+
{ ttlSeconds: GENERATION_TTL_SECONDS },
|
|
121
|
+
])),
|
|
122
|
+
]));
|
|
123
|
+
if (!(yield authCall(current, [])))
|
|
82
124
|
return;
|
|
83
125
|
if (published)
|
|
84
126
|
return {
|
|
@@ -90,20 +132,33 @@ async function acceptCatalogRefresh(storage, key, connectorId, digest, tools, pr
|
|
|
90
132
|
};
|
|
91
133
|
}
|
|
92
134
|
throw new Error("Catalog refresh baseline is busy.");
|
|
93
|
-
}
|
|
135
|
+
}));
|
|
94
136
|
/** Custom dynamic connectors have no SDK cache; publish their complete intake here. */
|
|
95
|
-
export
|
|
96
|
-
|
|
137
|
+
export function observeUncachedCatalogRefresh(ctx, connectorId, tools) {
|
|
138
|
+
return runEdge(authProgram(observeUncachedCatalogRefreshNative, [ctx, connectorId, tools]));
|
|
139
|
+
}
|
|
140
|
+
const observeUncachedCatalogRefreshNative = /* @__PURE__ */ registerAuth(observeUncachedCatalogRefresh, (ctx, connectorId, tools) => authFlow(function* () {
|
|
141
|
+
const policy = serviceFor(ctx, CatalogPolicy);
|
|
97
142
|
if (!policy?.onCompletedCatalogRefresh)
|
|
98
143
|
return;
|
|
99
|
-
const config = (
|
|
100
|
-
const partition = (
|
|
101
|
-
.
|
|
102
|
-
|
|
103
|
-
const
|
|
144
|
+
const config = (yield authCall(fingerprintSerializedCatalog, ["custom-connector"])).fingerprint;
|
|
145
|
+
const partition = (yield authCall(fingerprintSerializedCatalog, [
|
|
146
|
+
JSON.stringify([policy.partition, ctx.baseUrl, ctx.publicUrl]),
|
|
147
|
+
])).fingerprint;
|
|
148
|
+
const digest = (yield authCall(fingerprintSerializedCatalog, [JSON.stringify(tools)])).fingerprint;
|
|
149
|
+
const refresh = (yield authCall(acceptCatalogRefresh, [
|
|
150
|
+
policy.storage,
|
|
151
|
+
responseCacheKeys.refreshDigest(connectorId, config, partition),
|
|
152
|
+
connectorId,
|
|
153
|
+
digest,
|
|
154
|
+
tools,
|
|
155
|
+
true,
|
|
156
|
+
authMethod(() => Effect.sync(() => !ctx.signal?.aborted)),
|
|
157
|
+
authMethod((read) => authCall(read, [])),
|
|
158
|
+
]));
|
|
104
159
|
if (refresh)
|
|
105
|
-
|
|
106
|
-
}
|
|
160
|
+
(yield authCall(observeCompletedCatalogRefresh, [ctx, refresh]));
|
|
161
|
+
}));
|
|
107
162
|
export function catalogItems(method, result) {
|
|
108
163
|
if (method === "tools/list")
|
|
109
164
|
return result.tools;
|
|
@@ -118,42 +173,46 @@ function catalogSchema(method) {
|
|
|
118
173
|
? specTypeSchemas.ListResourcesResult
|
|
119
174
|
: specTypeSchemas.ListResourceTemplatesResult;
|
|
120
175
|
}
|
|
121
|
-
|
|
122
|
-
|
|
176
|
+
class CatalogExpiryService extends Context.Service()("connecta/operation/CatalogExpiryService") {
|
|
177
|
+
}
|
|
178
|
+
class CatalogFetches extends Context.Service()("connecta/operation/CatalogFetches") {
|
|
179
|
+
}
|
|
123
180
|
export function observeCatalogFetch(ctx, at, method = "tools/list") {
|
|
124
|
-
const methods =
|
|
181
|
+
const methods = serviceFor(ctx, CatalogFetches) ?? new Map();
|
|
125
182
|
methods.set(method, at);
|
|
126
|
-
|
|
183
|
+
setViewService(ctx, CatalogFetches, methods);
|
|
127
184
|
}
|
|
128
185
|
export function catalogFetchedAt(ctx, method = "tools/list") {
|
|
129
|
-
return
|
|
186
|
+
return serviceFor(ctx, CatalogFetches)?.get(method);
|
|
130
187
|
}
|
|
131
188
|
export function catalogExpiry(ctx, method = "tools/list") {
|
|
132
|
-
return
|
|
189
|
+
return serviceFor(ctx, CatalogExpiryService)?.get(method);
|
|
133
190
|
}
|
|
134
191
|
export function observeCatalogExpiry(ctx, method, ttlMs, expiresAt, staleFallback = false) {
|
|
135
192
|
const fetchedAt = catalogFetchedAt(ctx, method) ?? Date.now();
|
|
136
|
-
const methods =
|
|
193
|
+
const methods = serviceFor(ctx, CatalogExpiryService) ?? new Map();
|
|
137
194
|
methods.set(method, {
|
|
138
195
|
fetchedAt,
|
|
139
196
|
ttlMs,
|
|
140
197
|
expiresAt: Math.min(expiresAt ?? Infinity, fetchedAt + ttlMs),
|
|
141
198
|
staleFallback,
|
|
142
199
|
});
|
|
143
|
-
|
|
200
|
+
setViewService(ctx, CatalogExpiryService, methods);
|
|
144
201
|
}
|
|
145
202
|
// Tool facts remain available for ordinary calls after a transient listing
|
|
146
203
|
// failure for five minutes. Resources never use stale inventories. A fallback
|
|
147
204
|
// carries its original expired deadline and cannot authorize auth recovery.
|
|
148
205
|
const STALE_FALLBACK_MS = 300_000;
|
|
149
|
-
|
|
206
|
+
class CatalogPolicy extends Context.Service()("connecta/operation/CatalogPolicy") {
|
|
207
|
+
}
|
|
150
208
|
export function attachCatalogCache(ctx, value) {
|
|
151
|
-
|
|
209
|
+
setViewService(ctx, CatalogPolicy, value);
|
|
152
210
|
}
|
|
153
211
|
const defaultOwner = {};
|
|
154
212
|
const scopes = new WeakMap();
|
|
155
213
|
function cacheScope(ctx, connectorId, owner = defaultOwner) {
|
|
156
|
-
const
|
|
214
|
+
const request = Context.get(viewServices(ctx), RequestScope);
|
|
215
|
+
const key = request;
|
|
157
216
|
let connectors = scopes.get(key);
|
|
158
217
|
if (!connectors) {
|
|
159
218
|
connectors = new Map();
|
|
@@ -168,6 +227,11 @@ function cacheScope(ctx, connectorId, owner = defaultOwner) {
|
|
|
168
227
|
if (!scope) {
|
|
169
228
|
scope = { closed: false, abort: new AbortController() };
|
|
170
229
|
owners.set(owner, scope);
|
|
230
|
+
const owned = scope;
|
|
231
|
+
request.own(() => {
|
|
232
|
+
owned.closed = true;
|
|
233
|
+
owned.abort.abort();
|
|
234
|
+
});
|
|
171
235
|
}
|
|
172
236
|
return scope;
|
|
173
237
|
}
|
|
@@ -176,20 +240,26 @@ export function observeCatalogChange(ctx, connectorId, connectionSignal, owner)
|
|
|
176
240
|
const scope = cacheScope(ctx, connectorId, owner);
|
|
177
241
|
if (scope.closed || connectionSignal?.aborted)
|
|
178
242
|
return;
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
243
|
+
const previous = scope.invalidating;
|
|
244
|
+
const settled = Deferred.makeUnsafe();
|
|
245
|
+
scope.invalidating = settled;
|
|
246
|
+
const writing = authCall(invalidateCatalogCache, [
|
|
247
|
+
serviceFor(ctx, CatalogPolicy)?.storage ?? ctx.storage,
|
|
248
|
+
connectorId,
|
|
249
|
+
]).pipe(Effect.catch((error) => Effect.sync(() => logFailure(ctx.logger, "catalog invalidation failed", failureRecord({ connector: connectorId }, error)))));
|
|
250
|
+
// Start the fence in this SDK callback's request, and retain only its native
|
|
251
|
+
// settlement for teardown. Concurrent notifications still begin immediately.
|
|
252
|
+
detach(Effect.all([previous ? Deferred.await(previous) : Effect.void, writing], { concurrency: "unbounded" }).pipe(Effect.asVoid, Effect.provideService(RequestScope, Context.get(viewServices(ctx), RequestScope)), Effect.onExit((exit) => Deferred.done(settled, exit))));
|
|
183
253
|
}
|
|
184
254
|
export function closeCatalogCacheScope(ctx, connectorId, owner) {
|
|
185
255
|
const scope = cacheScope(ctx, connectorId, owner);
|
|
186
256
|
scope.closed = true;
|
|
187
257
|
scope.abort.abort();
|
|
188
|
-
return scope.invalidating;
|
|
258
|
+
return scope.invalidating ? runEdge(Deferred.await(scope.invalidating)) : undefined;
|
|
189
259
|
}
|
|
190
260
|
/** Zero is an explicit refusal to reuse. Positive hints use the configured bounds. */
|
|
191
261
|
function catalogTtlMs(ctx, hint) {
|
|
192
|
-
const policy =
|
|
262
|
+
const policy = serviceFor(ctx, CatalogPolicy);
|
|
193
263
|
const ttl = hint === undefined ? Math.floor(policy?.defaultTtlMs ?? CONFIG_DEFAULTS.discovery.catalogTtlSeconds * 1000) : hint;
|
|
194
264
|
if (typeof ttl !== "number" || !Number.isSafeInteger(ttl) || ttl <= 0)
|
|
195
265
|
return 0;
|
|
@@ -279,14 +349,37 @@ function catalogCeiling() {
|
|
|
279
349
|
});
|
|
280
350
|
}
|
|
281
351
|
const GENERATION_TTL_SECONDS = (MAX_CACHE_TTL_MS * 2) / 1000;
|
|
282
|
-
export
|
|
283
|
-
|
|
284
|
-
ttlSeconds: GENERATION_TTL_SECONDS,
|
|
285
|
-
});
|
|
352
|
+
export function invalidateCatalogCache(storage, connectorId) {
|
|
353
|
+
return runEdge(authProgram(invalidateCatalogCacheNative, [storage, connectorId]));
|
|
286
354
|
}
|
|
355
|
+
const invalidateCatalogCacheNative = /* @__PURE__ */ registerAuth(invalidateCatalogCache, (storage, connectorId) => authFlow(function* () {
|
|
356
|
+
(yield authStorage(storage, "set", [
|
|
357
|
+
responseCacheKeys.generation(connectorId),
|
|
358
|
+
crypto.randomUUID(),
|
|
359
|
+
{
|
|
360
|
+
ttlSeconds: GENERATION_TTL_SECONDS,
|
|
361
|
+
},
|
|
362
|
+
]));
|
|
363
|
+
}));
|
|
287
364
|
/** Keys ignore self-reported serverInfo and bind the configured connector instead. */
|
|
288
|
-
export
|
|
289
|
-
|
|
365
|
+
export function catalogClientOptions(ctx, connectorId, config, authPartition, connectionSignal, owner, sharing = "private", resolveCredentialIdentity) {
|
|
366
|
+
return runEdge(authProgram(catalogClientOptionsNative, [
|
|
367
|
+
ctx,
|
|
368
|
+
connectorId,
|
|
369
|
+
config,
|
|
370
|
+
authPartition,
|
|
371
|
+
connectionSignal,
|
|
372
|
+
owner,
|
|
373
|
+
sharing,
|
|
374
|
+
resolveCredentialIdentity,
|
|
375
|
+
]));
|
|
376
|
+
}
|
|
377
|
+
const catalogClientOptionsNative = /* @__PURE__ */ registerAuth(catalogClientOptions, (ctx, connectorId, config, authPartition, connectionSignal, owner, sharing = "private", resolveCredentialIdentity) => authFlow(function* () {
|
|
378
|
+
const request = Context.get(viewServices(ctx), RequestScope);
|
|
379
|
+
// SDK callbacks start at their own Promise edge. Reprovide only their
|
|
380
|
+
// canonical request owner, never the initiating call's live services.
|
|
381
|
+
const cacheMethod = (program) => authMethod((...args) => program(...args).pipe(Effect.provideService(RequestScope, request)));
|
|
382
|
+
const policy = serviceFor(ctx, CatalogPolicy);
|
|
290
383
|
const partition = JSON.stringify([
|
|
291
384
|
policy?.partition ?? JSON.stringify(callerOf(ctx) ?? null),
|
|
292
385
|
ctx.baseUrl,
|
|
@@ -299,18 +392,18 @@ export async function catalogClientOptions(ctx, connectorId, config, authPartiti
|
|
|
299
392
|
authPartition,
|
|
300
393
|
]);
|
|
301
394
|
const storage = policy?.storage ?? ctx.storage;
|
|
302
|
-
const configHash = (
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
395
|
+
const configHash = (yield authCall(fingerprintSerializedCatalog, [
|
|
396
|
+
JSON.stringify([
|
|
397
|
+
config,
|
|
398
|
+
policy?.defaultTtlMs ?? 300000,
|
|
399
|
+
policy?.minTtlMs ?? 0,
|
|
400
|
+
policy?.maxTtlMs ?? MAX_CACHE_TTL_MS,
|
|
401
|
+
]),
|
|
402
|
+
])).fingerprint;
|
|
308
403
|
const scope = cacheScope(ctx, connectorId, owner);
|
|
309
404
|
let unavailable = false;
|
|
310
405
|
const connectionGeneration = {};
|
|
311
406
|
let active;
|
|
312
|
-
// ResponseCacheStore has no per-call options. A method snapshots its binding
|
|
313
|
-
// before any await; an abandoned storage promise never adopts a later listing.
|
|
314
407
|
const capture = (listing = active) => {
|
|
315
408
|
const signals = [scope.abort.signal, connectionSignal, listing?.ctx.signal].filter((signal) => signal !== undefined);
|
|
316
409
|
const ended = () => scope.closed || listing?.ended === true || signals.some((signal) => signal.aborted);
|
|
@@ -322,73 +415,57 @@ export async function catalogClientOptions(ctx, connectorId, config, authPartiti
|
|
|
322
415
|
credentialIdentity: listing?.credentialIdentity,
|
|
323
416
|
listing,
|
|
324
417
|
stopped: () => unavailable || ended(),
|
|
325
|
-
io: (read) =>
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
const abort = () => {
|
|
331
|
-
cleanup();
|
|
332
|
-
reject(reason());
|
|
333
|
-
};
|
|
334
|
-
if (ended()) {
|
|
335
|
-
abort();
|
|
336
|
-
return;
|
|
337
|
-
}
|
|
338
|
-
for (const signal of signals)
|
|
339
|
-
signal.addEventListener("abort", abort, { once: true });
|
|
340
|
-
// Storage cannot cancel dispatched I/O. Stop waiting, but attach both
|
|
341
|
-
// outcomes so its eventual completion cannot continue cache publication.
|
|
342
|
-
try {
|
|
343
|
-
read().then((value) => {
|
|
344
|
-
cleanup();
|
|
345
|
-
resolve(value);
|
|
346
|
-
}, (error) => {
|
|
347
|
-
cleanup();
|
|
348
|
-
reject(error);
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
catch (error) {
|
|
352
|
-
cleanup();
|
|
353
|
-
reject(error);
|
|
354
|
-
}
|
|
355
|
-
}),
|
|
418
|
+
io: cacheMethod((read) => authFlow(function* () {
|
|
419
|
+
if (ended())
|
|
420
|
+
throw reason();
|
|
421
|
+
return yield authAwait(authCall(read, []), AbortSignal.any(signals));
|
|
422
|
+
})),
|
|
356
423
|
};
|
|
357
424
|
};
|
|
358
425
|
let lastStamp = 0;
|
|
359
426
|
let staleTools;
|
|
360
|
-
const currentGeneration =
|
|
427
|
+
const currentGeneration = cacheMethod(({ stopped, io, generation }) => authFlow(function* () {
|
|
361
428
|
const key = responseCacheKeys.generation(connectorId);
|
|
362
429
|
for (let attempt = 0; attempt < 16; attempt++) {
|
|
363
430
|
if (stopped())
|
|
364
431
|
return undefined;
|
|
365
|
-
const current =
|
|
432
|
+
const current = (yield authCall(io, [
|
|
433
|
+
cacheMethod(() => authStorage(storage, "get", [key])),
|
|
434
|
+
]));
|
|
366
435
|
if (stopped())
|
|
367
436
|
return undefined;
|
|
368
437
|
if (current)
|
|
369
438
|
return current;
|
|
370
439
|
const next = generation.value ?? crypto.randomUUID();
|
|
371
|
-
const claimed =
|
|
440
|
+
const claimed = (yield authCall(io, [
|
|
441
|
+
cacheMethod(() => authStorage(storage, "compareAndSet", [
|
|
442
|
+
key,
|
|
443
|
+
null,
|
|
444
|
+
next,
|
|
445
|
+
{ ttlSeconds: GENERATION_TTL_SECONDS },
|
|
446
|
+
])),
|
|
447
|
+
]));
|
|
372
448
|
if (stopped())
|
|
373
449
|
return undefined;
|
|
374
450
|
if (claimed)
|
|
375
451
|
return next;
|
|
376
452
|
}
|
|
377
453
|
throw new Error("Catalog cache generation is busy.");
|
|
378
|
-
};
|
|
379
|
-
const namespace =
|
|
454
|
+
}));
|
|
455
|
+
const namespace = cacheMethod((operation) => authFlow(function* () {
|
|
380
456
|
const { stopped, generation, io } = operation;
|
|
381
|
-
if (resolveCredentialIdentity &&
|
|
457
|
+
if (resolveCredentialIdentity &&
|
|
458
|
+
(yield authCall(io, [resolveCredentialIdentity])) !== operation.credentialIdentity)
|
|
382
459
|
return undefined;
|
|
383
|
-
const current =
|
|
460
|
+
const current = (yield authCall(currentGeneration, [operation]));
|
|
384
461
|
if (!current || stopped())
|
|
385
462
|
return undefined;
|
|
386
463
|
generation.value ??= current;
|
|
387
464
|
return generation.value === current
|
|
388
465
|
? responseCacheKeys.namespace(connectorId, configHash, generation.value)
|
|
389
466
|
: undefined;
|
|
390
|
-
};
|
|
391
|
-
const address =
|
|
467
|
+
}));
|
|
468
|
+
const address = cacheMethod((key, operation) => authFlow(function* () {
|
|
392
469
|
const { stopped } = operation;
|
|
393
470
|
if (stopped() || !isCatalogMethod(key.method) || key.params)
|
|
394
471
|
return undefined;
|
|
@@ -403,17 +480,18 @@ export async function catalogClientOptions(ctx, connectorId, config, authPartiti
|
|
|
403
480
|
pair.length !== 2 ||
|
|
404
481
|
(pair[1] !== partition && (pair[1] !== "" || sharing !== "shared")))
|
|
405
482
|
return undefined;
|
|
406
|
-
const prefix =
|
|
483
|
+
const prefix = (yield authCall(namespace, [operation]));
|
|
407
484
|
if (!prefix || stopped())
|
|
408
485
|
return undefined;
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
486
|
+
const digest = (yield authCall(fingerprintSerializedCatalog, [
|
|
487
|
+
JSON.stringify([
|
|
488
|
+
key.method,
|
|
489
|
+
pair[1] === "" ? sharedPartition : partition,
|
|
490
|
+
operation.credentialIdentity ?? null,
|
|
491
|
+
]),
|
|
492
|
+
])).fingerprint;
|
|
415
493
|
return stopped() ? undefined : responseCacheKeys.entry(prefix, digest);
|
|
416
|
-
};
|
|
494
|
+
}));
|
|
417
495
|
const manifest = (raw) => {
|
|
418
496
|
if (!raw)
|
|
419
497
|
return undefined;
|
|
@@ -456,53 +534,71 @@ export async function catalogClientOptions(ctx, connectorId, config, authPartiti
|
|
|
456
534
|
cacheScope: body.cacheScope === "public" ? "public" : "private",
|
|
457
535
|
};
|
|
458
536
|
};
|
|
459
|
-
const completeCatalogRefresh =
|
|
537
|
+
const completeCatalogRefresh = cacheMethod((result) => authFlow(function* () {
|
|
460
538
|
const listing = active;
|
|
461
539
|
const operation = capture();
|
|
462
540
|
const { stopped, io } = operation;
|
|
463
541
|
if (!listing || stopped())
|
|
464
542
|
return;
|
|
465
543
|
const clean = intake(listing.ctx, "tools/list", result);
|
|
466
|
-
const digest = (
|
|
467
|
-
const partitionDigest = (
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
544
|
+
const digest = (yield authCall(fingerprintSerializedCatalog, [JSON.stringify(clean)])).fingerprint;
|
|
545
|
+
const partitionDigest = (yield authCall(fingerprintSerializedCatalog, [
|
|
546
|
+
JSON.stringify([
|
|
547
|
+
clean.cacheScope === "public" ? sharedPartition : partition,
|
|
548
|
+
operation.credentialIdentity ?? null,
|
|
549
|
+
]),
|
|
550
|
+
])).fingerprint;
|
|
471
551
|
try {
|
|
472
|
-
return
|
|
552
|
+
return (yield authCall(acceptCatalogRefresh, [
|
|
553
|
+
storage,
|
|
554
|
+
responseCacheKeys.refreshDigest(connectorId, configHash, partitionDigest),
|
|
555
|
+
connectorId,
|
|
556
|
+
digest,
|
|
557
|
+
clean.tools,
|
|
558
|
+
clean.cacheScope !== "public",
|
|
559
|
+
cacheMethod(() => authFlow(function* () {
|
|
560
|
+
return !stopped() && !!(yield authCall(namespace, [operation])) && !stopped();
|
|
561
|
+
})),
|
|
562
|
+
io,
|
|
563
|
+
]));
|
|
473
564
|
}
|
|
474
565
|
catch (error) {
|
|
475
566
|
if (!stopped())
|
|
476
567
|
logFailure(listing.ctx.logger, "catalog refresh observation failed", failureRecord({ connector: connectorId }, error));
|
|
477
568
|
}
|
|
478
|
-
};
|
|
569
|
+
}));
|
|
479
570
|
const store = {
|
|
480
|
-
|
|
571
|
+
get: cacheMethod((key) => authFlow(function* () {
|
|
481
572
|
const operation = capture();
|
|
482
573
|
const { ctx, stopped, io } = operation;
|
|
483
|
-
const root =
|
|
574
|
+
const root = (yield authCall(address, [key, operation]));
|
|
484
575
|
if (!root || stopped())
|
|
485
576
|
return undefined;
|
|
486
|
-
const m = manifest(
|
|
577
|
+
const m = manifest((yield authCall(io, [
|
|
578
|
+
cacheMethod(() => authStorage(storage, "get", [root])),
|
|
579
|
+
])));
|
|
487
580
|
if (stopped() ||
|
|
488
581
|
!m ||
|
|
489
|
-
(m.expiresAt <= Date.now() &&
|
|
582
|
+
(m.expiresAt <= Date.now() &&
|
|
583
|
+
(key.method !== "tools/list" || m.expiresAt + STALE_FALLBACK_MS <= Date.now())))
|
|
490
584
|
return undefined;
|
|
491
585
|
const chunks = [];
|
|
492
586
|
for (let i = 0; i < m.chunkCount; i++) {
|
|
493
587
|
if (stopped())
|
|
494
588
|
return undefined;
|
|
495
|
-
const chunk =
|
|
589
|
+
const chunk = (yield authCall(io, [
|
|
590
|
+
cacheMethod(() => authStorage(storage, "get", [responseCacheKeys.chunk(root, m.revision, i)])),
|
|
591
|
+
]));
|
|
496
592
|
if (stopped() || chunk === null || new TextEncoder().encode(chunk).byteLength > MAX_CATALOG_CHUNK_BYTES)
|
|
497
593
|
return undefined;
|
|
498
594
|
chunks.push(chunk);
|
|
499
595
|
}
|
|
500
596
|
const value = chunks.join("");
|
|
501
|
-
const fingerprint =
|
|
597
|
+
const fingerprint = (yield authCall(fingerprintSerializedCatalog, [value]));
|
|
502
598
|
if (stopped() ||
|
|
503
599
|
fingerprint.byteLength > MAX_SERIALIZED_CATALOG_BYTES ||
|
|
504
600
|
fingerprint.fingerprint !== m.fingerprint ||
|
|
505
|
-
!(
|
|
601
|
+
!(yield authCall(namespace, [operation])) ||
|
|
506
602
|
stopped())
|
|
507
603
|
return undefined;
|
|
508
604
|
const result = JSON.parse(value);
|
|
@@ -513,7 +609,7 @@ export async function catalogClientOptions(ctx, connectorId, config, authPartiti
|
|
|
513
609
|
"nextCursor" in result ||
|
|
514
610
|
(result.resultType !== undefined && result.resultType !== "complete"))
|
|
515
611
|
return undefined;
|
|
516
|
-
const validated =
|
|
612
|
+
const validated = (yield authInvoke(catalogSchema(method)["~standard"], "validate", [result]));
|
|
517
613
|
if (stopped() || validated.issues)
|
|
518
614
|
return undefined;
|
|
519
615
|
const clean = intake(ctx, method, validated.value);
|
|
@@ -525,30 +621,33 @@ export async function catalogClientOptions(ctx, connectorId, config, authPartiti
|
|
|
525
621
|
observeCatalogFetch(ctx, m.fetchedAt, method);
|
|
526
622
|
observeCatalogExpiry(ctx, method, clean.ttlMs, m.expiresAt);
|
|
527
623
|
return { value: JSON.stringify(clean), stamp: m.stamp, expiresAt: m.expiresAt, scope: m.scope };
|
|
528
|
-
},
|
|
529
|
-
|
|
624
|
+
})),
|
|
625
|
+
set: cacheMethod((key, entry) => authFlow(function* () {
|
|
530
626
|
const operation = capture();
|
|
531
627
|
const { ctx, stopped, io } = operation;
|
|
532
|
-
const root =
|
|
628
|
+
const root = (yield authCall(address, [key, operation]));
|
|
533
629
|
if (!root || stopped())
|
|
534
630
|
return 0;
|
|
535
631
|
const result = JSON.parse(entry.value);
|
|
536
632
|
const method = key.method;
|
|
537
633
|
if (catalogTtlMs(ctx, result.ttlMs) === 0) {
|
|
538
|
-
if (!stopped() && (
|
|
539
|
-
|
|
634
|
+
if (!stopped() && (yield authCall(namespace, [operation])) && !stopped())
|
|
635
|
+
(yield authCall(io, [
|
|
636
|
+
cacheMethod(() => authStorage(storage, "delete", [root])),
|
|
637
|
+
]));
|
|
540
638
|
return 0;
|
|
541
639
|
}
|
|
542
640
|
if (!Array.isArray(catalogItems(method, result)) ||
|
|
543
641
|
"nextCursor" in result ||
|
|
544
642
|
(result.resultType !== undefined && result.resultType !== "complete"))
|
|
545
643
|
return 0;
|
|
546
|
-
// Defence in depth: the SDK catches store failures, so intake also runs on
|
|
547
|
-
// the request path, where a secret-bearing name refuses the entire list.
|
|
548
644
|
const value = JSON.stringify(intake(ctx, method, result));
|
|
549
|
-
const fingerprint =
|
|
645
|
+
const fingerprint = (yield authCall(fingerprintSerializedCatalog, [value]));
|
|
550
646
|
const expiresAt = Math.min(entry.expiresAt ?? Date.now(), (catalogFetchedAt(ctx, method) ?? Date.now()) + catalogTtlMs(ctx, result.ttlMs));
|
|
551
|
-
if (stopped() ||
|
|
647
|
+
if (stopped() ||
|
|
648
|
+
expiresAt <= Date.now() ||
|
|
649
|
+
!(yield authCall(namespace, [operation])) ||
|
|
650
|
+
stopped())
|
|
552
651
|
return 0;
|
|
553
652
|
const revision = crypto.randomUUID();
|
|
554
653
|
const bytes = new TextEncoder().encode(value);
|
|
@@ -560,18 +659,29 @@ export async function catalogClientOptions(ctx, connectorId, config, authPartiti
|
|
|
560
659
|
if (stopped() || expiresAt <= Date.now())
|
|
561
660
|
return 0;
|
|
562
661
|
let end = Math.min(offset + MAX_CATALOG_CHUNK_BYTES, bytes.length);
|
|
563
|
-
while (end < bytes.length && (bytes[end] &
|
|
662
|
+
while (end < bytes.length && (bytes[end] & 192) === 128)
|
|
564
663
|
end--;
|
|
565
664
|
const chunk = responseCacheKeys.chunk(root, revision, chunkCount++);
|
|
566
|
-
|
|
665
|
+
(yield authCall(io, [
|
|
666
|
+
cacheMethod(() => authStorage(storage, "set", [
|
|
667
|
+
chunk,
|
|
668
|
+
decoder.decode(bytes.subarray(offset, end)),
|
|
669
|
+
{ ttlSeconds: ttlSeconds() },
|
|
670
|
+
])),
|
|
671
|
+
]));
|
|
567
672
|
if (stopped())
|
|
568
673
|
return 0;
|
|
569
674
|
offset = end;
|
|
570
675
|
}
|
|
571
676
|
for (let attempt = 0; attempt < 16; attempt++) {
|
|
572
|
-
if (stopped() ||
|
|
677
|
+
if (stopped() ||
|
|
678
|
+
expiresAt <= Date.now() ||
|
|
679
|
+
!(yield authCall(namespace, [operation])) ||
|
|
680
|
+
stopped())
|
|
573
681
|
return 0;
|
|
574
|
-
const previous =
|
|
682
|
+
const previous = (yield authCall(io, [
|
|
683
|
+
cacheMethod(() => authStorage(storage, "get", [root])),
|
|
684
|
+
]));
|
|
575
685
|
if (stopped() || expiresAt <= Date.now())
|
|
576
686
|
return 0;
|
|
577
687
|
const stamp = Math.max(Date.now(), (manifest(previous)?.stamp ?? 0) + 1, lastStamp + 1);
|
|
@@ -584,7 +694,14 @@ export async function catalogClientOptions(ctx, connectorId, config, authPartiti
|
|
|
584
694
|
chunkCount,
|
|
585
695
|
fingerprint: fingerprint.fingerprint,
|
|
586
696
|
};
|
|
587
|
-
const published =
|
|
697
|
+
const published = (yield authCall(io, [
|
|
698
|
+
cacheMethod(() => authStorage(storage, "compareAndSet", [
|
|
699
|
+
root,
|
|
700
|
+
previous,
|
|
701
|
+
JSON.stringify(m),
|
|
702
|
+
{ ttlSeconds: ttlSeconds() },
|
|
703
|
+
])),
|
|
704
|
+
]));
|
|
588
705
|
if (stopped())
|
|
589
706
|
return 0;
|
|
590
707
|
if (published) {
|
|
@@ -593,31 +710,33 @@ export async function catalogClientOptions(ctx, connectorId, config, authPartiti
|
|
|
593
710
|
}
|
|
594
711
|
}
|
|
595
712
|
throw new Error("Catalog cache publication is busy.");
|
|
596
|
-
},
|
|
597
|
-
|
|
713
|
+
})),
|
|
714
|
+
delete: cacheMethod((key) => authFlow(function* () {
|
|
598
715
|
const operation = capture();
|
|
599
|
-
const root =
|
|
716
|
+
const root = (yield authCall(address, [key, operation]));
|
|
600
717
|
if (root && !operation.stopped())
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
718
|
+
(yield authInvoke(operation, "io", [
|
|
719
|
+
cacheMethod(() => authStorage(storage, "delete", [root])),
|
|
720
|
+
]));
|
|
721
|
+
})),
|
|
722
|
+
evict: cacheMethod((method) => authFlow(function* () {
|
|
604
723
|
if (isCatalogMethod(method))
|
|
605
|
-
|
|
606
|
-
},
|
|
607
|
-
|
|
724
|
+
(yield authInvoke(store, "clear", []));
|
|
725
|
+
})),
|
|
726
|
+
clear: cacheMethod(() => authFlow(function* () {
|
|
608
727
|
const operation = capture();
|
|
609
728
|
if (!operation.stopped())
|
|
610
|
-
|
|
611
|
-
|
|
729
|
+
(yield authInvoke(operation, "io", [
|
|
730
|
+
cacheMethod(() => authCall(invalidateCatalogCache, [storage, connectorId])),
|
|
731
|
+
]));
|
|
732
|
+
})),
|
|
612
733
|
};
|
|
613
|
-
// Refresh/bypass listings may never call get(). Pin before any wire I/O so
|
|
614
|
-
// their first late publication cannot adopt a post-notification generation.
|
|
615
|
-
// Reading an absent generation pins a nonce without mutating storage before
|
|
616
|
-
// negotiation/auth succeeds. The first cache operation may claim that nonce.
|
|
617
734
|
try {
|
|
618
735
|
const { stopped, io } = capture({ ctx, generation: connectionGeneration, ended: false });
|
|
619
736
|
if (!stopped()) {
|
|
620
|
-
const current =
|
|
737
|
+
const current = (yield authCall(io, [
|
|
738
|
+
cacheMethod(() => authStorage(storage, "get", [responseCacheKeys.generation(connectorId)])),
|
|
739
|
+
]));
|
|
621
740
|
if (!stopped())
|
|
622
741
|
connectionGeneration.value = current ?? crypto.randomUUID();
|
|
623
742
|
}
|
|
@@ -626,54 +745,67 @@ export async function catalogClientOptions(ctx, connectorId, config, authPartiti
|
|
|
626
745
|
unavailable = true;
|
|
627
746
|
logFailure(ctx.logger, "catalog read failed", failureRecord({ connector: connectorId }, error));
|
|
628
747
|
}
|
|
748
|
+
// The queue retains only a Promise turn. Awaiting it in this caller's
|
|
749
|
+
// request preserves workerd I/O ownership; the listing program stays native.
|
|
629
750
|
let tail = Promise.resolve();
|
|
630
|
-
const withListing = (listingCtx, read) => {
|
|
631
|
-
const
|
|
751
|
+
const withListing = cacheMethod((listingCtx, read) => authFlow(function* () {
|
|
752
|
+
const previous = tail;
|
|
753
|
+
let release;
|
|
754
|
+
tail = new Promise((resolve) => {
|
|
755
|
+
release = resolve;
|
|
756
|
+
});
|
|
757
|
+
let entered = false;
|
|
758
|
+
try {
|
|
759
|
+
yield authValue(() => previous);
|
|
760
|
+
entered = true;
|
|
632
761
|
if (scope.closed || connectionSignal?.aborted)
|
|
633
762
|
throw new ConnectorCallError("connector_call_failed", "Catalog cache scope ended.");
|
|
634
763
|
if (listingCtx.signal?.aborted)
|
|
635
764
|
throw listingCtx.signal.reason;
|
|
636
|
-
if (policy &&
|
|
637
|
-
|
|
765
|
+
if (policy && serviceFor(listingCtx, CatalogPolicy) === undefined)
|
|
766
|
+
setViewService(listingCtx, CatalogPolicy, policy);
|
|
638
767
|
const listing = { ctx: listingCtx, generation: {}, ended: false };
|
|
639
768
|
active = listing;
|
|
640
769
|
staleTools = undefined;
|
|
641
770
|
const operation = capture();
|
|
642
771
|
try {
|
|
643
772
|
if (resolveCredentialIdentity)
|
|
644
|
-
listing.credentialIdentity =
|
|
645
|
-
// Each new listing pins before even a refresh's first wire page. A
|
|
646
|
-
// notification fences this listing, while a later listing can refresh.
|
|
773
|
+
listing.credentialIdentity = yield authInvoke(operation, "io", [resolveCredentialIdentity]);
|
|
647
774
|
if (!operation.stopped()) {
|
|
648
775
|
try {
|
|
649
|
-
|
|
650
|
-
(
|
|
651
|
-
|
|
776
|
+
const generation = (yield authInvoke(operation, "io", [
|
|
777
|
+
cacheMethod(() => authStorage(storage, "get", [responseCacheKeys.generation(connectorId)])),
|
|
778
|
+
])) ?? crypto.randomUUID();
|
|
779
|
+
listing.generation.value = generation;
|
|
780
|
+
connectionGeneration.value = generation;
|
|
652
781
|
}
|
|
653
782
|
catch (error) {
|
|
654
783
|
if (operation.stopped())
|
|
655
784
|
throw error;
|
|
656
785
|
unavailable = true;
|
|
657
|
-
logFailure(
|
|
786
|
+
logFailure(listingCtx.logger, "catalog read failed", failureRecord({ connector: connectorId }, error));
|
|
658
787
|
}
|
|
659
788
|
}
|
|
660
|
-
return
|
|
789
|
+
return yield authCall(read, []);
|
|
661
790
|
}
|
|
662
791
|
finally {
|
|
663
792
|
listing.ended = true;
|
|
664
793
|
active = undefined;
|
|
665
794
|
}
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
795
|
+
}
|
|
796
|
+
finally {
|
|
797
|
+
// A cancelled queued waiter cannot unlock the listing ahead of it.
|
|
798
|
+
if (entered)
|
|
799
|
+
release();
|
|
800
|
+
else
|
|
801
|
+
void previous.then(release);
|
|
802
|
+
}
|
|
803
|
+
}));
|
|
804
|
+
const fallbackTools = cacheMethod(() => authFlow(function* () {
|
|
673
805
|
const operation = capture();
|
|
674
806
|
if (!staleTools ||
|
|
675
807
|
operation.stopped() ||
|
|
676
|
-
!(
|
|
808
|
+
!(yield authCall(namespace, [operation])) ||
|
|
677
809
|
operation.stopped() ||
|
|
678
810
|
staleTools.manifest.expiresAt + STALE_FALLBACK_MS <= Date.now())
|
|
679
811
|
return;
|
|
@@ -681,7 +813,7 @@ export async function catalogClientOptions(ctx, connectorId, config, authPartiti
|
|
|
681
813
|
observeCatalogFetch(operation.ctx, manifest.fetchedAt);
|
|
682
814
|
observeCatalogExpiry(operation.ctx, "tools/list", typeof result.ttlMs === "number" ? result.ttlMs : 0, manifest.expiresAt, true);
|
|
683
815
|
return result;
|
|
684
|
-
};
|
|
816
|
+
}));
|
|
685
817
|
return {
|
|
686
818
|
intake,
|
|
687
819
|
completeCatalogRefresh,
|
|
@@ -692,48 +824,72 @@ export async function catalogClientOptions(ctx, connectorId, config, authPartiti
|
|
|
692
824
|
withListing,
|
|
693
825
|
currentContext: () => active?.ctx ?? ctx,
|
|
694
826
|
};
|
|
695
|
-
}
|
|
827
|
+
}));
|
|
696
828
|
function isCatalogMethod(method) {
|
|
697
829
|
return method === "tools/list" || method === "resources/list" || method === "resources/templates/list";
|
|
698
830
|
}
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
return { cache, key };
|
|
831
|
+
function customCatalogCache(ctx, connectorId) {
|
|
832
|
+
return runEdge(authProgram(customCatalogCacheNative, [
|
|
833
|
+
ctx,
|
|
834
|
+
connectorId,
|
|
835
|
+
]));
|
|
705
836
|
}
|
|
837
|
+
const customCatalogCacheNative = /* @__PURE__ */ registerAuth(customCatalogCache, (ctx, connectorId) => authFlow(function* () {
|
|
838
|
+
const credential = (yield authValue(() => ctx.credential?.getAll()));
|
|
839
|
+
const auth = (yield authCall(fingerprintSerializedCatalog, [JSON.stringify(credential ?? null)])).fingerprint;
|
|
840
|
+
const cache = (yield authCall(catalogClientOptions, [ctx, connectorId, "custom-connector", auth]));
|
|
841
|
+
const key = {
|
|
842
|
+
method: "tools/list",
|
|
843
|
+
partition: JSON.stringify(["custom-connector", cache.cachePartition]),
|
|
844
|
+
};
|
|
845
|
+
return { cache, key };
|
|
846
|
+
}));
|
|
706
847
|
/** Custom listings always fetch. Only an authenticated owner may retain a
|
|
707
848
|
* complete private fallback; unscoped/operator reads start no cache I/O. */
|
|
708
|
-
export
|
|
849
|
+
export function storeCustomCatalogFallback(ctx, connectorId, tools) {
|
|
850
|
+
return runEdge(authProgram(storeCustomCatalogFallbackNative, [ctx, connectorId, tools]));
|
|
851
|
+
}
|
|
852
|
+
const storeCustomCatalogFallbackNative = /* @__PURE__ */ registerAuth(storeCustomCatalogFallback, (ctx, connectorId, tools) => authFlow(function* () {
|
|
709
853
|
const ttlMs = catalogTtlMs(ctx, undefined);
|
|
710
854
|
observeCatalogFetch(ctx, Date.now());
|
|
711
855
|
observeCatalogExpiry(ctx, "tools/list", ttlMs);
|
|
712
856
|
if (!ttlMs || !callerOf(ctx)?.authenticated)
|
|
713
857
|
return;
|
|
714
|
-
const { cache, key } =
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
858
|
+
const { cache, key } = (yield authCall(customCatalogCache, [ctx, connectorId]));
|
|
859
|
+
(yield authInvoke(cache, "withListing", [
|
|
860
|
+
ctx,
|
|
861
|
+
authMethod(() => authFlow(function* () {
|
|
862
|
+
const result = catalogIntake(ctx, {
|
|
863
|
+
tools: tools.map((tool) => ({
|
|
864
|
+
...tool,
|
|
865
|
+
inputSchema: tool.inputSchema ?? { type: "object" },
|
|
866
|
+
})),
|
|
867
|
+
ttlMs,
|
|
868
|
+
cacheScope: "private",
|
|
869
|
+
});
|
|
870
|
+
(yield authInvoke(cache.responseCacheStore, "set", [
|
|
871
|
+
key,
|
|
872
|
+
{
|
|
873
|
+
value: JSON.stringify(result),
|
|
874
|
+
expiresAt: catalogExpiry(ctx).expiresAt,
|
|
875
|
+
scope: "private",
|
|
876
|
+
},
|
|
877
|
+
]));
|
|
878
|
+
})),
|
|
879
|
+
]));
|
|
880
|
+
}));
|
|
881
|
+
export function customCatalogFallback(ctx, connectorId) {
|
|
882
|
+
return runEdge(authProgram(customCatalogFallbackNative, [ctx, connectorId]));
|
|
730
883
|
}
|
|
731
|
-
|
|
884
|
+
const customCatalogFallbackNative = /* @__PURE__ */ registerAuth(customCatalogFallback, (ctx, connectorId) => authFlow(function* () {
|
|
732
885
|
if (!callerOf(ctx)?.authenticated)
|
|
733
886
|
return;
|
|
734
|
-
const { cache, key } =
|
|
735
|
-
return
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
887
|
+
const { cache, key } = (yield authCall(customCatalogCache, [ctx, connectorId]));
|
|
888
|
+
return (yield authInvoke(cache, "withListing", [
|
|
889
|
+
ctx,
|
|
890
|
+
authMethod(() => authFlow(function* () {
|
|
891
|
+
(yield authInvoke(cache.responseCacheStore, "get", [key]));
|
|
892
|
+
return (yield authInvoke(cache, "fallbackTools", []))?.tools;
|
|
893
|
+
})),
|
|
894
|
+
]));
|
|
895
|
+
}));
|