@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/storage/sql.js
CHANGED
|
@@ -1,547 +1,41 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
//
|
|
8
|
-
// Atomicity. Every compare-and-set is one statement. SQLite executes a
|
|
9
|
-
// statement atomically against the database file, and D1 runs one database's
|
|
10
|
-
// statements one at a time against its primary, so a comparison and its write
|
|
11
|
-
// cannot interleave with another request's: of fifty concurrent claims on an
|
|
12
|
-
// absent key, exactly one changes a row.
|
|
13
|
-
//
|
|
14
|
-
// The database clock creates and checks KV expiry inside each statement.
|
|
15
|
-
// Isolate clock skew cannot shorten another holder's TTL. An expired row reads
|
|
16
|
-
// as absent at once and is removed
|
|
17
|
-
// physically by later writes, a bounded batch at a time, so no request starts
|
|
18
|
-
// a background job and no cron is required.
|
|
19
|
-
//
|
|
20
|
-
// Schema. Each store creates its own tables and indexes the first time one of
|
|
21
|
-
// its methods runs in an isolate or process, with idempotent statements, so a
|
|
22
|
-
// deployment applies no migration by hand. The flag that records it is a
|
|
23
|
-
// boolean, never a shared promise: a request that sees it unset runs the
|
|
24
|
-
// statements itself (INV-7).
|
|
25
|
-
import { activityBehaviorFacts, activityPackageVersion, activityClientFact, InvalidActivityCursorError, } from "../activity.js";
|
|
26
|
-
import { assertKnownOptions, ConfigError, keys, optionsOf } from "../config-schema.js";
|
|
27
|
-
import { agentFrictionForCode } from "../activity-friction.js";
|
|
28
|
-
import { validateStorageKey } from "./keys.js";
|
|
29
|
-
const sql = (text, ...params) => ({
|
|
30
|
-
sql: text,
|
|
31
|
-
params,
|
|
32
|
-
});
|
|
33
|
-
/** Select `column`, and beside it `<column>_bytes` when it holds a NUL. */
|
|
34
|
-
const textColumn = (column) => `${column}, CASE WHEN instr(CAST(${column} AS BLOB), x'00') > 0
|
|
35
|
-
THEN CAST(${column} AS BLOB) END AS ${column}_bytes`;
|
|
36
|
-
// Everything written here was a JavaScript string, so the bytes are UTF-8;
|
|
37
|
-
// a stored row that is not is refused rather than read wrong. A leading
|
|
38
|
-
// U+FEFF is part of the value, not a byte order mark.
|
|
39
|
-
const utf8 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
|
|
40
|
-
/** A text column's value, from its bytes when the read selected them. */
|
|
41
|
-
function textOf(text, bytes, what) {
|
|
42
|
-
if (bytes == null)
|
|
43
|
-
return text;
|
|
44
|
-
try {
|
|
45
|
-
return utf8.decode(bytes instanceof Uint8Array ? bytes : Uint8Array.from(bytes));
|
|
46
|
-
}
|
|
47
|
-
catch {
|
|
48
|
-
throw new TypeError(`${what} is not valid UTF-8`);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
/** Run `ddl` once per store object; a failure leaves it to the next call. */
|
|
52
|
-
function schemaOnce(driver, ddl) {
|
|
53
|
-
let ready = false;
|
|
54
|
-
return async () => {
|
|
55
|
-
if (ready)
|
|
56
|
-
return;
|
|
57
|
-
await ddl(driver);
|
|
58
|
-
ready = true;
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
// --- key-value ----------------------------------------------------------
|
|
62
|
-
/**
|
|
63
|
-
* The key-value table. Its shape is the one the 0.28 Worker example's
|
|
64
|
-
* `d1-storage.ts` documented, so a D1 database that already holds it is read
|
|
65
|
-
* as is.
|
|
66
|
-
*/
|
|
67
|
-
export const KV_SCHEMA = [
|
|
68
|
-
`CREATE TABLE IF NOT EXISTS connecta_kv (
|
|
69
|
-
key TEXT PRIMARY KEY,
|
|
70
|
-
value TEXT NOT NULL,
|
|
71
|
-
expires_at_ms INTEGER
|
|
72
|
-
)`,
|
|
73
|
-
`CREATE INDEX IF NOT EXISTS connecta_kv_expiry
|
|
74
|
-
ON connecta_kv (expires_at_ms)`,
|
|
75
|
-
];
|
|
76
|
-
/** Expired rows one write removes on its way. */
|
|
77
|
-
const SWEEP_ROWS = 16;
|
|
78
|
-
function ttlMillis(ttlSeconds) {
|
|
79
|
-
if (ttlSeconds !== undefined && !Number.isFinite(ttlSeconds)) {
|
|
80
|
-
throw new RangeError("ttlSeconds must produce a finite expiration timestamp");
|
|
81
|
-
}
|
|
82
|
-
if (!ttlSeconds)
|
|
83
|
-
return null;
|
|
84
|
-
const expiry = ttlSeconds * 1000;
|
|
85
|
-
if (!Number.isFinite(expiry)) {
|
|
86
|
-
throw new RangeError("ttlSeconds must produce a finite expiration timestamp");
|
|
87
|
-
}
|
|
88
|
-
return Math.ceil(expiry);
|
|
89
|
-
}
|
|
1
|
+
import { runEdge } from "../runtime/run.js";
|
|
2
|
+
import { registerNativeStorage, registerNativeActivity } from "../runtime/native-storage.js";
|
|
3
|
+
import { nativeSqlDriver } from "./sql-driver.js";
|
|
4
|
+
import { nativeSqlStorage, nativeSqlActivityStore, copyIntoSqlEffect } from "./sql-native.js";
|
|
5
|
+
/** The 0.28-compatible key-value table and expiry index. */
|
|
6
|
+
export { KV_SCHEMA } from "./sql-schema.js";
|
|
90
7
|
/** `KVStorage` over one `connecta_kv` table. */
|
|
91
8
|
export function sqlStorage(driver, kind) {
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
});
|
|
95
|
-
// SQLite and D1 evaluate 'now' in the database, never in a caller isolate.
|
|
96
|
-
const now = "CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER)";
|
|
97
|
-
const live = `(expires_at_ms IS NULL OR expires_at_ms > ${now})`;
|
|
98
|
-
const expiryOptions = (opts) => {
|
|
99
|
-
if (opts?.expiresAtMs !== undefined) {
|
|
100
|
-
if (!Number.isSafeInteger(opts.expiresAtMs) || opts.ttlSeconds !== undefined) {
|
|
101
|
-
throw new RangeError("expiresAtMs must be a safe integer epoch timestamp without ttlSeconds");
|
|
102
|
-
}
|
|
103
|
-
return { value: opts.expiresAtMs, expression: "?" };
|
|
104
|
-
}
|
|
105
|
-
return { value: ttlMillis(opts?.ttlSeconds), expression: `(${now} + ?)` };
|
|
106
|
-
};
|
|
107
|
-
const current = async (key) => {
|
|
108
|
-
const [row] = await driver.all(sql(`SELECT ${textColumn("value")} FROM connecta_kv WHERE key = ? AND ${live}`, key));
|
|
109
|
-
return row ? textOf(row.value, row.value_bytes, `the stored value of ${JSON.stringify(key)}`) : null;
|
|
110
|
-
};
|
|
111
|
-
return {
|
|
9
|
+
const native = nativeSqlStorage(nativeSqlDriver(driver));
|
|
10
|
+
return registerNativeStorage({
|
|
112
11
|
capabilities: { absoluteExpiry: true },
|
|
113
12
|
describe: () => ({ kind }),
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
validateStorageKey(key);
|
|
121
|
-
await ensure();
|
|
122
|
-
const expiry = expiryOptions(opts);
|
|
123
|
-
await driver.batch([
|
|
124
|
-
sql(`DELETE FROM connecta_kv WHERE key IN (
|
|
125
|
-
SELECT key FROM connecta_kv WHERE expires_at_ms <= ${now} LIMIT ${SWEEP_ROWS}
|
|
126
|
-
)`),
|
|
127
|
-
sql(`INSERT INTO connecta_kv (key, value, expires_at_ms)
|
|
128
|
-
VALUES (?, ?, ${expiry.expression})
|
|
129
|
-
ON CONFLICT (key) DO UPDATE SET
|
|
130
|
-
value = excluded.value, expires_at_ms = excluded.expires_at_ms`, key, value, expiry.value),
|
|
131
|
-
]);
|
|
132
|
-
},
|
|
133
|
-
async delete(key) {
|
|
134
|
-
validateStorageKey(key);
|
|
135
|
-
await ensure();
|
|
136
|
-
await driver.run(sql("DELETE FROM connecta_kv WHERE key = ?", key));
|
|
137
|
-
},
|
|
138
|
-
async list(prefix) {
|
|
139
|
-
validateStorageKey(prefix);
|
|
140
|
-
await ensure();
|
|
141
|
-
const rows = await driver.all(sql(`SELECT key FROM connecta_kv
|
|
142
|
-
WHERE key >= ?
|
|
143
|
-
AND substr(CAST(key AS BLOB), 1, length(CAST(? AS BLOB))) = CAST(? AS BLOB)
|
|
144
|
-
AND ${live}`, prefix, prefix, prefix));
|
|
145
|
-
// Sort in JavaScript: SQLite orders UTF-8 bytes, the contract orders
|
|
146
|
-
// the UTF-16 code units every other adapter sorts by.
|
|
147
|
-
return rows.map((row) => row.key).sort();
|
|
148
|
-
},
|
|
149
|
-
async compareAndSet(key, expected, next, opts) {
|
|
150
|
-
validateStorageKey(key);
|
|
151
|
-
await ensure();
|
|
152
|
-
if (next === null && expected === null) {
|
|
153
|
-
// Nothing to write; the claim holds exactly when no live row exists.
|
|
154
|
-
return (await current(key)) === null;
|
|
155
|
-
}
|
|
156
|
-
if (next === null) {
|
|
157
|
-
return ((await driver.run(sql(`DELETE FROM connecta_kv WHERE key = ? AND ${live} AND value = ?`, key, expected))) > 0);
|
|
158
|
-
}
|
|
159
|
-
let expiry;
|
|
160
|
-
try {
|
|
161
|
-
expiry = expiryOptions(opts);
|
|
162
|
-
}
|
|
163
|
-
catch (error) {
|
|
164
|
-
// Invalid write options do not change a failed comparison's result.
|
|
165
|
-
// Ordinary claims still use one atomic statement without this read.
|
|
166
|
-
if ((await current(key)) !== expected)
|
|
167
|
-
return false;
|
|
168
|
-
throw error;
|
|
169
|
-
}
|
|
170
|
-
if (expected === null) {
|
|
171
|
-
// Insert, or take over a row that has expired. A live row makes the
|
|
172
|
-
// upsert's WHERE false, so nothing changes and the claim is refused.
|
|
173
|
-
return ((await driver.run(sql(`INSERT INTO connecta_kv (key, value, expires_at_ms)
|
|
174
|
-
VALUES (?, ?, ${expiry.expression})
|
|
175
|
-
ON CONFLICT (key) DO UPDATE SET
|
|
176
|
-
value = excluded.value, expires_at_ms = excluded.expires_at_ms
|
|
177
|
-
WHERE connecta_kv.expires_at_ms IS NOT NULL
|
|
178
|
-
AND connecta_kv.expires_at_ms <= ${now}`, key, next, expiry.value))) > 0);
|
|
179
|
-
}
|
|
180
|
-
return ((await driver.run(sql(`UPDATE connecta_kv SET value = ?, expires_at_ms = ${expiry.expression}
|
|
181
|
-
WHERE key = ? AND ${live} AND value = ?`, next, expiry.value, key, expected))) > 0);
|
|
182
|
-
},
|
|
183
|
-
};
|
|
13
|
+
get: (key) => runEdge(native.get(key)),
|
|
14
|
+
set: (key, value, options) => runEdge(native.set(key, value, options)),
|
|
15
|
+
delete: (key) => runEdge(native.delete(key)),
|
|
16
|
+
list: (prefix) => runEdge(native.list(prefix)),
|
|
17
|
+
compareAndSet: (key, expected, next, options) => runEdge(native.compareAndSet(key, expected, next, options)),
|
|
18
|
+
}, native);
|
|
184
19
|
}
|
|
185
|
-
/** Keys one read compares: D1 binds at most 100 parameters, one is `now`. */
|
|
186
|
-
const COPY_READ_KEYS = 99;
|
|
187
|
-
/** Writes one transaction carries, by count and by UTF-8 bytes. */
|
|
188
|
-
const COPY_BATCH_STATEMENTS = 50;
|
|
189
|
-
const COPY_BATCH_BYTES = 4 * 1024 * 1024;
|
|
190
|
-
/**
|
|
191
|
-
* Copy entries into the key-value table, verbatim: same key, same value,
|
|
192
|
-
* same absolute expiry. A live row holding a different value is kept unless
|
|
193
|
-
* `overwrite` is set, so a second copy of the same entries writes nothing.
|
|
194
|
-
* Writes go out in bounded transactions; the outcomes follow `entries`.
|
|
195
|
-
*/
|
|
196
|
-
export async function copyIntoSql(driver, entries, options) {
|
|
197
|
-
const { overwrite, now } = options;
|
|
198
|
-
for (const entry of entries)
|
|
199
|
-
validateStorageKey(entry.key);
|
|
200
|
-
await driver.batch(KV_SCHEMA.map((statement) => sql(statement)));
|
|
201
|
-
const live = "(expires_at_ms IS NULL OR expires_at_ms > ?)";
|
|
202
|
-
const currentValues = async (keys) => {
|
|
203
|
-
const values = new Map();
|
|
204
|
-
for (let start = 0; start < keys.length; start += COPY_READ_KEYS) {
|
|
205
|
-
const chunk = keys.slice(start, start + COPY_READ_KEYS);
|
|
206
|
-
const rows = await driver.all(sql(`SELECT key, ${textColumn("value")}, expires_at_ms FROM connecta_kv
|
|
207
|
-
WHERE key IN (${chunk.map(() => "?").join(", ")}) AND ${live}`, ...chunk, now));
|
|
208
|
-
// The message names no key: a copy's errors reach operator output.
|
|
209
|
-
for (const row of rows) {
|
|
210
|
-
values.set(row.key, {
|
|
211
|
-
value: textOf(row.value, row.value_bytes, "a stored value") ?? "",
|
|
212
|
-
expiresAtMs: row.expires_at_ms,
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
return values;
|
|
217
|
-
};
|
|
218
|
-
const outcomes = Array.from({ length: entries.length });
|
|
219
|
-
const writes = [];
|
|
220
|
-
const existing = await currentValues(entries.map((entry) => entry.key));
|
|
221
|
-
for (const [index, entry] of entries.entries()) {
|
|
222
|
-
const current = existing.get(entry.key);
|
|
223
|
-
if (current?.value === entry.value && current.expiresAtMs === entry.expiresAtMs) {
|
|
224
|
-
outcomes[index] = "unchanged";
|
|
225
|
-
}
|
|
226
|
-
else if (current !== undefined && !overwrite) {
|
|
227
|
-
outcomes[index] = "conflict";
|
|
228
|
-
}
|
|
229
|
-
else {
|
|
230
|
-
outcomes[index] = current === undefined ? "copied" : "overwritten";
|
|
231
|
-
writes.push({
|
|
232
|
-
index,
|
|
233
|
-
bytes: new TextEncoder().encode(entry.key).byteLength + new TextEncoder().encode(entry.value).byteLength + 32,
|
|
234
|
-
statement: overwrite
|
|
235
|
-
? sql(`INSERT INTO connecta_kv (key, value, expires_at_ms)
|
|
236
|
-
VALUES (?, ?, ?)
|
|
237
|
-
ON CONFLICT (key) DO UPDATE SET
|
|
238
|
-
value = excluded.value, expires_at_ms = excluded.expires_at_ms`, entry.key, entry.value, entry.expiresAtMs)
|
|
239
|
-
: // Absent when read; a live row written since is kept, not replaced.
|
|
240
|
-
sql(`INSERT INTO connecta_kv (key, value, expires_at_ms)
|
|
241
|
-
VALUES (?, ?, ?)
|
|
242
|
-
ON CONFLICT (key) DO UPDATE SET
|
|
243
|
-
value = excluded.value, expires_at_ms = excluded.expires_at_ms
|
|
244
|
-
WHERE connecta_kv.expires_at_ms IS NOT NULL
|
|
245
|
-
AND connecta_kv.expires_at_ms <= ?`, entry.key, entry.value, entry.expiresAtMs, now),
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
const raced = [];
|
|
250
|
-
let batch = [];
|
|
251
|
-
let batchBytes = 0;
|
|
252
|
-
const flush = async () => {
|
|
253
|
-
if (batch.length === 0)
|
|
254
|
-
return;
|
|
255
|
-
const changes = await driver.batch(batch.map((write) => write.statement));
|
|
256
|
-
for (const [position, write] of batch.entries()) {
|
|
257
|
-
if (!(changes[position] > 0))
|
|
258
|
-
raced.push(write.index);
|
|
259
|
-
}
|
|
260
|
-
batch = [];
|
|
261
|
-
batchBytes = 0;
|
|
262
|
-
};
|
|
263
|
-
for (const write of writes) {
|
|
264
|
-
if (batch.length > 0 && (batch.length >= COPY_BATCH_STATEMENTS || batchBytes + write.bytes > COPY_BATCH_BYTES)) {
|
|
265
|
-
await flush();
|
|
266
|
-
}
|
|
267
|
-
batch.push(write);
|
|
268
|
-
batchBytes += write.bytes;
|
|
269
|
-
}
|
|
270
|
-
await flush();
|
|
271
|
-
// A row another writer added between the read and the write: report what
|
|
272
|
-
// it holds, and leave it.
|
|
273
|
-
if (raced.length > 0) {
|
|
274
|
-
const after = await currentValues(raced.map((index) => entries[index].key));
|
|
275
|
-
for (const index of raced) {
|
|
276
|
-
const entry = entries[index];
|
|
277
|
-
const current = after.get(entry.key);
|
|
278
|
-
outcomes[index] =
|
|
279
|
-
current?.value === entry.value && current.expiresAtMs === entry.expiresAtMs ? "unchanged" : "conflict";
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
return outcomes;
|
|
283
|
-
}
|
|
284
|
-
// --- activity -----------------------------------------------------------
|
|
285
|
-
/**
|
|
286
|
-
* The activity table, with keyset paging on `(occurred_at_ms, id)`. Its shape
|
|
287
|
-
* is the 0.28 Worker example's `tool_call_activity`; a table created before
|
|
288
|
-
* later actor, friction, approval, client, or package columns existed gets
|
|
289
|
-
* those columns added without changing old rows.
|
|
290
|
-
*/
|
|
291
|
-
const ACTIVITY_SCHEMA = [
|
|
292
|
-
`CREATE TABLE IF NOT EXISTS tool_call_activity (
|
|
293
|
-
id TEXT PRIMARY KEY,
|
|
294
|
-
occurred_at_ms INTEGER NOT NULL,
|
|
295
|
-
request_id TEXT NOT NULL,
|
|
296
|
-
actor_kind TEXT NOT NULL,
|
|
297
|
-
actor_id TEXT,
|
|
298
|
-
actor_namespace TEXT,
|
|
299
|
-
connector_id TEXT NOT NULL,
|
|
300
|
-
tool_name TEXT NOT NULL,
|
|
301
|
-
source TEXT NOT NULL,
|
|
302
|
-
outcome TEXT NOT NULL,
|
|
303
|
-
duration_ms INTEGER NOT NULL,
|
|
304
|
-
attempts INTEGER NOT NULL,
|
|
305
|
-
error_code TEXT,
|
|
306
|
-
friction TEXT,
|
|
307
|
-
approval TEXT,
|
|
308
|
-
package_version TEXT,
|
|
309
|
-
server_name TEXT NOT NULL,
|
|
310
|
-
server_version TEXT NOT NULL,
|
|
311
|
-
client_name TEXT,
|
|
312
|
-
client_version TEXT,
|
|
313
|
-
deployment_id TEXT,
|
|
314
|
-
classification TEXT,
|
|
315
|
-
result_bytes INTEGER,
|
|
316
|
-
event_kind TEXT,
|
|
317
|
-
drift_kind TEXT,
|
|
318
|
-
added_tools INTEGER,
|
|
319
|
-
removed_tools INTEGER,
|
|
320
|
-
changed_tools INTEGER,
|
|
321
|
-
pool_name TEXT,
|
|
322
|
-
actor_basis TEXT
|
|
323
|
-
)`,
|
|
324
|
-
`CREATE INDEX IF NOT EXISTS tool_call_activity_recent
|
|
325
|
-
ON tool_call_activity (occurred_at_ms DESC, id DESC)`,
|
|
326
|
-
];
|
|
327
|
-
/** Columns added after the table first shipped, in the order they arrived. */
|
|
328
|
-
const LATER_ACTIVITY_COLUMNS = [
|
|
329
|
-
"actor_namespace",
|
|
330
|
-
"friction",
|
|
331
|
-
"approval",
|
|
332
|
-
"client_name",
|
|
333
|
-
"client_version",
|
|
334
|
-
"package_version",
|
|
335
|
-
"classification",
|
|
336
|
-
"result_bytes",
|
|
337
|
-
"event_kind",
|
|
338
|
-
"drift_kind",
|
|
339
|
-
"added_tools",
|
|
340
|
-
"removed_tools",
|
|
341
|
-
"changed_tools",
|
|
342
|
-
"pool_name",
|
|
343
|
-
"actor_basis",
|
|
344
|
-
];
|
|
345
|
-
/** Every activity column but the three integers, read through `textOf`. */
|
|
346
|
-
const ACTIVITY_TEXT_COLUMNS = [
|
|
347
|
-
"id",
|
|
348
|
-
"request_id",
|
|
349
|
-
"actor_kind",
|
|
350
|
-
"actor_id",
|
|
351
|
-
"actor_namespace",
|
|
352
|
-
"connector_id",
|
|
353
|
-
"tool_name",
|
|
354
|
-
"source",
|
|
355
|
-
"outcome",
|
|
356
|
-
"error_code",
|
|
357
|
-
"friction",
|
|
358
|
-
"approval",
|
|
359
|
-
"package_version",
|
|
360
|
-
"server_name",
|
|
361
|
-
"server_version",
|
|
362
|
-
"client_name",
|
|
363
|
-
"client_version",
|
|
364
|
-
"deployment_id",
|
|
365
|
-
"classification",
|
|
366
|
-
"event_kind",
|
|
367
|
-
"drift_kind",
|
|
368
|
-
"pool_name",
|
|
369
|
-
"actor_basis",
|
|
370
|
-
];
|
|
371
|
-
const ACTIVITY_SELECT = `SELECT occurred_at_ms, duration_ms, attempts, result_bytes, added_tools, removed_tools, changed_tools,
|
|
372
|
-
${ACTIVITY_TEXT_COLUMNS.map(textColumn).join(",\n ")}
|
|
373
|
-
FROM tool_call_activity`;
|
|
374
|
-
function activityRow(read) {
|
|
375
|
-
const row = {
|
|
376
|
-
occurred_at_ms: read.occurred_at_ms,
|
|
377
|
-
duration_ms: read.duration_ms,
|
|
378
|
-
attempts: read.attempts,
|
|
379
|
-
result_bytes: read.result_bytes,
|
|
380
|
-
added_tools: read.added_tools,
|
|
381
|
-
removed_tools: read.removed_tools,
|
|
382
|
-
changed_tools: read.changed_tools,
|
|
383
|
-
};
|
|
384
|
-
for (const column of ACTIVITY_TEXT_COLUMNS) {
|
|
385
|
-
row[column] = textOf(read[column], read[`${column}_bytes`], `activity column ${column}`);
|
|
386
|
-
}
|
|
387
|
-
return row;
|
|
388
|
-
}
|
|
389
|
-
function rowToEvent(row) {
|
|
390
|
-
// Rows written before `friction` had a column derive it from the code.
|
|
391
|
-
// Friction without a code — an oversized but successful result — exists
|
|
392
|
-
// only in the column, which is why the column exists.
|
|
393
|
-
const friction = row.friction ?? agentFrictionForCode(row.error_code ?? undefined);
|
|
394
|
-
const packageVersion = activityPackageVersion(row.package_version);
|
|
395
|
-
const clientName = activityClientFact(row.client_name, "name");
|
|
396
|
-
const clientVersion = activityClientFact(row.client_version, "version");
|
|
397
|
-
return {
|
|
398
|
-
schemaVersion: 1,
|
|
399
|
-
id: row.id,
|
|
400
|
-
occurredAt: new Date(row.occurred_at_ms).toISOString(),
|
|
401
|
-
requestId: row.request_id,
|
|
402
|
-
...activityBehaviorFacts({
|
|
403
|
-
classification: row.classification,
|
|
404
|
-
resultBytes: row.result_bytes,
|
|
405
|
-
kind: row.event_kind,
|
|
406
|
-
pool: row.pool_name,
|
|
407
|
-
actorBasis: row.actor_basis,
|
|
408
|
-
drift: {
|
|
409
|
-
kind: row.drift_kind,
|
|
410
|
-
addedTools: row.added_tools,
|
|
411
|
-
removedTools: row.removed_tools,
|
|
412
|
-
changedTools: row.changed_tools,
|
|
413
|
-
},
|
|
414
|
-
}),
|
|
415
|
-
actor: {
|
|
416
|
-
kind: row.actor_kind,
|
|
417
|
-
...(row.actor_id ? { id: row.actor_id } : {}),
|
|
418
|
-
...(row.actor_namespace ? { namespace: row.actor_namespace } : {}),
|
|
419
|
-
},
|
|
420
|
-
connectorId: row.connector_id,
|
|
421
|
-
toolName: row.tool_name,
|
|
422
|
-
address: `${row.connector_id}.${row.tool_name}`,
|
|
423
|
-
source: row.source,
|
|
424
|
-
outcome: row.outcome,
|
|
425
|
-
durationMs: row.duration_ms,
|
|
426
|
-
attempts: row.attempts,
|
|
427
|
-
...(row.error_code ? { errorCode: row.error_code } : {}),
|
|
428
|
-
...(friction ? { friction } : {}),
|
|
429
|
-
...(row.approval ? { approval: row.approval } : {}),
|
|
430
|
-
...(packageVersion !== undefined ? { packageVersion } : {}),
|
|
431
|
-
serverName: row.server_name,
|
|
432
|
-
serverVersion: row.server_version,
|
|
433
|
-
...(clientName !== undefined ? { clientName } : {}),
|
|
434
|
-
...(clientVersion !== undefined ? { clientVersion } : {}),
|
|
435
|
-
...(row.deployment_id ? { deploymentId: row.deployment_id } : {}),
|
|
436
|
-
};
|
|
437
|
-
}
|
|
438
|
-
function encodeCursor(row) {
|
|
439
|
-
return btoa(`${row.occurred_at_ms}:${row.id}`);
|
|
440
|
-
}
|
|
441
|
-
function decodeCursor(value) {
|
|
442
|
-
let decoded;
|
|
443
|
-
try {
|
|
444
|
-
decoded = atob(value);
|
|
445
|
-
}
|
|
446
|
-
catch {
|
|
447
|
-
throw new InvalidActivityCursorError();
|
|
448
|
-
}
|
|
449
|
-
const separator = decoded.indexOf(":");
|
|
450
|
-
const occurredAtMs = Number(decoded.slice(0, separator));
|
|
451
|
-
const id = decoded.slice(separator + 1);
|
|
452
|
-
if (separator < 1 || !Number.isSafeInteger(occurredAtMs) || occurredAtMs < 0 || !/^[0-9a-f-]{36}$/i.test(id)) {
|
|
453
|
-
throw new InvalidActivityCursorError();
|
|
454
|
-
}
|
|
455
|
-
return { occurredAtMs, id };
|
|
456
|
-
}
|
|
457
|
-
/** The closed options both activity factories accept; see `assertKnownOptions`. */
|
|
458
|
-
const SQL_ACTIVITY_OPTIONS = optionsOf()(keys("retentionDays"));
|
|
459
|
-
/** Older rows one write removes on its way. Above one: writes catch up. */
|
|
460
|
-
const RETENTION_SWEEP_ROWS = 16;
|
|
461
20
|
/**
|
|
462
21
|
* One append-only row per completed downstream call. Rows carry no arguments,
|
|
463
22
|
* results, generated code, or raw error messages — the store never has a
|
|
464
23
|
* payload to leak.
|
|
465
24
|
*/
|
|
466
25
|
export function sqlActivityStore(driver, kind, options = {}) {
|
|
467
|
-
const
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
if (present.has(name))
|
|
483
|
-
continue;
|
|
484
|
-
try {
|
|
485
|
-
await d.run(sql(`ALTER TABLE tool_call_activity ADD COLUMN ${name} ${["result_bytes", "added_tools", "removed_tools", "changed_tools"].includes(name) ? "INTEGER" : "TEXT"}`));
|
|
486
|
-
}
|
|
487
|
-
catch (error) {
|
|
488
|
-
present = await columns();
|
|
489
|
-
if (!present.has(name))
|
|
490
|
-
throw error;
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
});
|
|
494
|
-
return {
|
|
495
|
-
describe: () => ({
|
|
496
|
-
kind,
|
|
497
|
-
retentionDays,
|
|
498
|
-
optionSources: { retentionDays: options.retentionDays === undefined ? "default" : "config" },
|
|
499
|
-
}),
|
|
500
|
-
async record(event) {
|
|
501
|
-
await ensure();
|
|
502
|
-
const occurredAtMs = Date.parse(event.occurredAt);
|
|
503
|
-
const facts = activityBehaviorFacts(event);
|
|
504
|
-
await driver.batch([
|
|
505
|
-
sql(`INSERT INTO tool_call_activity (
|
|
506
|
-
id, occurred_at_ms, request_id, actor_kind, actor_id,
|
|
507
|
-
actor_namespace, connector_id, tool_name, source, outcome,
|
|
508
|
-
duration_ms, attempts, error_code, friction, approval,
|
|
509
|
-
package_version, server_name, server_version, client_name, client_version, deployment_id,
|
|
510
|
-
classification, result_bytes, event_kind, drift_kind, added_tools, removed_tools, changed_tools, pool_name, actor_basis
|
|
511
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, event.id, occurredAtMs, event.requestId, event.actor.kind, event.actor.id ?? null, event.actor.namespace ?? null, event.connectorId, event.toolName, event.source, event.outcome, event.durationMs, event.attempts, event.errorCode ?? null,
|
|
512
|
-
// Stored beside the code rather than derived from it: a truncated
|
|
513
|
-
// result is friction on a call that succeeded, and
|
|
514
|
-
// `error_code IS NOT NULL` stays an honest count of failures.
|
|
515
|
-
event.friction ?? null, event.approval ?? null, activityPackageVersion(event.packageVersion) ?? null, event.serverName, event.serverVersion, activityClientFact(event.clientName, "name") ?? null, activityClientFact(event.clientVersion, "version") ?? null, event.deploymentId ?? null, facts.classification ?? null, facts.resultBytes ?? null, facts.kind ?? null, facts.drift?.kind ?? null, facts.drift?.addedTools ?? null, facts.drift?.removedTools ?? null, facts.drift?.changedTools ?? null, facts.pool ?? null, facts.actorBasis ?? null),
|
|
516
|
-
sql(`DELETE FROM tool_call_activity WHERE id IN (
|
|
517
|
-
SELECT id FROM tool_call_activity
|
|
518
|
-
WHERE occurred_at_ms < ?
|
|
519
|
-
ORDER BY occurred_at_ms ASC
|
|
520
|
-
LIMIT ${RETENTION_SWEEP_ROWS}
|
|
521
|
-
)`, Date.now() - retentionMs),
|
|
522
|
-
]);
|
|
523
|
-
},
|
|
524
|
-
async list({ cursor, limit }) {
|
|
525
|
-
const boundedLimit = Math.min(100, Math.max(1, Math.trunc(limit)));
|
|
526
|
-
const pageSize = boundedLimit + 1;
|
|
527
|
-
const position = cursor ? decodeCursor(cursor) : undefined;
|
|
528
|
-
await ensure();
|
|
529
|
-
const rows = (await driver.all(position
|
|
530
|
-
? sql(`${ACTIVITY_SELECT}
|
|
531
|
-
WHERE occurred_at_ms < ?
|
|
532
|
-
OR (occurred_at_ms = ? AND id < ?)
|
|
533
|
-
ORDER BY occurred_at_ms DESC, id DESC
|
|
534
|
-
LIMIT ?`, position.occurredAtMs, position.occurredAtMs, position.id, pageSize)
|
|
535
|
-
: sql(`${ACTIVITY_SELECT}
|
|
536
|
-
ORDER BY occurred_at_ms DESC, id DESC
|
|
537
|
-
LIMIT ?`, pageSize))).map(activityRow);
|
|
538
|
-
const hasMore = rows.length > boundedLimit;
|
|
539
|
-
const visible = hasMore ? rows.slice(0, boundedLimit) : rows;
|
|
540
|
-
const last = visible.at(-1);
|
|
541
|
-
return {
|
|
542
|
-
events: visible.map(rowToEvent),
|
|
543
|
-
...(hasMore && last ? { nextCursor: encodeCursor(last) } : {}),
|
|
544
|
-
};
|
|
545
|
-
},
|
|
546
|
-
};
|
|
26
|
+
const native = nativeSqlActivityStore(nativeSqlDriver(driver), kind, options);
|
|
27
|
+
return registerNativeActivity({
|
|
28
|
+
describe: native.describe,
|
|
29
|
+
record: (event) => runEdge(native.record(event)),
|
|
30
|
+
list: (options) => runEdge(native.list(options)),
|
|
31
|
+
}, native);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Copy entries into the key-value table, verbatim: same key, same value,
|
|
35
|
+
* same absolute expiry. A live row holding a different value is kept unless
|
|
36
|
+
* `overwrite` is set, so a second copy of the same entries writes nothing.
|
|
37
|
+
* Writes go out in bounded transactions; the outcomes follow `entries`.
|
|
38
|
+
*/
|
|
39
|
+
export function copyIntoSql(driver, entries, options) {
|
|
40
|
+
return runEdge(copyIntoSqlEffect(nativeSqlDriver(driver), entries, options));
|
|
547
41
|
}
|
package/dist/timeout.js
CHANGED
|
@@ -33,32 +33,6 @@ export function withDeadline(operation, options) {
|
|
|
33
33
|
catch: (error) => error,
|
|
34
34
|
}), options));
|
|
35
35
|
}
|
|
36
|
-
/**
|
|
37
|
-
* Run `operation` under one signal that aborts when any of `signals` does —
|
|
38
|
-
* the MCP call's own and the inbound request's, for the program tools — and
|
|
39
|
-
* detach every listener afterwards, however it ends.
|
|
40
|
-
*/
|
|
41
|
-
export async function underAnySignal(signals, operation) {
|
|
42
|
-
const controller = new AbortController();
|
|
43
|
-
const forwarders = signals
|
|
44
|
-
.filter((signal) => signal !== undefined)
|
|
45
|
-
.map((signal) => {
|
|
46
|
-
const forward = () => controller.abort(signal.reason);
|
|
47
|
-
if (signal.aborted)
|
|
48
|
-
forward();
|
|
49
|
-
else
|
|
50
|
-
signal.addEventListener("abort", forward, { once: true });
|
|
51
|
-
return { signal, forward };
|
|
52
|
-
});
|
|
53
|
-
try {
|
|
54
|
-
return await operation(controller.signal);
|
|
55
|
-
}
|
|
56
|
-
finally {
|
|
57
|
-
for (const { signal, forward } of forwarders) {
|
|
58
|
-
signal.removeEventListener("abort", forward);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
36
|
/**
|
|
63
37
|
* Give one operation a caller-facing deadline and the matching cancellation
|
|
64
38
|
* signal. The timeout rejects with the stable, labelled error while aborting
|
package/dist/tool-safety.js
CHANGED
|
@@ -1,19 +1,29 @@
|
|
|
1
|
-
/** Deployment override, then
|
|
2
|
-
export function classifyTool(definition, override
|
|
1
|
+
/** Deployment override, then fail-closed annotations. */
|
|
2
|
+
export function classifyTool(definition, override) {
|
|
3
3
|
if (override !== undefined)
|
|
4
4
|
return override;
|
|
5
|
-
if (review) {
|
|
6
|
-
if (review.stale || review.verdict !== "read")
|
|
7
|
-
return "write";
|
|
8
|
-
// An explicit downstream contradiction invalidates a reviewed read (#721).
|
|
9
|
-
if (definition.annotations?.readOnlyHint === false || definition.annotations?.destructiveHint === true)
|
|
10
|
-
return "write";
|
|
11
|
-
return "read";
|
|
12
|
-
}
|
|
13
5
|
return definition.annotations?.readOnlyHint === true && definition.annotations?.destructiveHint !== true
|
|
14
6
|
? "read"
|
|
15
7
|
: "write";
|
|
16
8
|
}
|
|
9
|
+
// Source policy is fail-closed annotations.
|
|
10
|
+
// Deployment overrides never enter it. It is private metadata, not catalog data.
|
|
11
|
+
// Keep it through host-owned clones without exposing it to tools or storage.
|
|
12
|
+
const sourceClassifications = new WeakMap();
|
|
13
|
+
export function sourceClassification(tool) {
|
|
14
|
+
return sourceClassifications.get(tool) ?? classifyTool(tool);
|
|
15
|
+
}
|
|
16
|
+
export function carryToolClassification(source, served) {
|
|
17
|
+
sourceClassifications.set(served, sourceClassification(source));
|
|
18
|
+
return served;
|
|
19
|
+
}
|
|
20
|
+
/** Replay and outcome policy only; admission and presentation use the served class. */
|
|
21
|
+
export function isWriteLike(tool) {
|
|
22
|
+
return tool.classification !== "read" || sourceClassification(tool) === "write";
|
|
23
|
+
}
|
|
24
|
+
export function cloneTool(tool) {
|
|
25
|
+
return carryToolClassification(tool, structuredClone(tool));
|
|
26
|
+
}
|
|
17
27
|
/**
|
|
18
28
|
* The only permission decision for a connector call. Approval is client-owned.
|
|
19
29
|
* A read-only endpoint refuses every write on every surface; a writable one
|