@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/sqlite.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { chmodSync, closeSync, mkdirSync, openSync, readFileSync } from "node:fs";
|
|
8
8
|
import { dirname, resolve } from "node:path";
|
|
9
9
|
import { DatabaseSync } from "node:sqlite";
|
|
10
|
+
import { effectSqlDriver, sqlDriverEdge, sqlSync } from "./storage/sql-driver.js";
|
|
10
11
|
import { validateStorageKey } from "./storage/keys.js";
|
|
11
12
|
import { KV_SCHEMA, sqlActivityStore, sqlStorage, } from "./storage/sql.js";
|
|
12
13
|
/** Milliseconds a write waits for another process's write lock. */
|
|
@@ -58,17 +59,12 @@ function sqliteDriver(database) {
|
|
|
58
59
|
const run = (statement) => {
|
|
59
60
|
return Number(prepare(statement).run(...statement.params).changes);
|
|
60
61
|
};
|
|
61
|
-
const driver = {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
},
|
|
68
|
-
async batch(batch) {
|
|
69
|
-
// Synchronous from BEGIN to COMMIT: no other call on this connection
|
|
70
|
-
// can interleave, and IMMEDIATE takes the write lock up front so
|
|
71
|
-
// another process cannot either.
|
|
62
|
+
const driver = sqlDriverEdge(effectSqlDriver({
|
|
63
|
+
all: (statement) => sqlSync(() => prepare(statement).all(...statement.params)),
|
|
64
|
+
run: (statement) => sqlSync(() => run(statement)),
|
|
65
|
+
batch: (batch) => sqlSync(() => {
|
|
66
|
+
// One synchronous native leaf: no fiber can yield between BEGIN and
|
|
67
|
+
// COMMIT and let another caller interleave on this DatabaseSync.
|
|
72
68
|
db.exec("BEGIN IMMEDIATE");
|
|
73
69
|
try {
|
|
74
70
|
const changes = batch.map(run);
|
|
@@ -76,11 +72,16 @@ function sqliteDriver(database) {
|
|
|
76
72
|
return changes;
|
|
77
73
|
}
|
|
78
74
|
catch (error) {
|
|
79
|
-
|
|
75
|
+
try {
|
|
76
|
+
db.exec("ROLLBACK");
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
/* Preserve the original failure. */
|
|
80
|
+
}
|
|
80
81
|
throw error;
|
|
81
82
|
}
|
|
82
|
-
},
|
|
83
|
-
};
|
|
83
|
+
}),
|
|
84
|
+
}));
|
|
84
85
|
drivers.set(db, driver);
|
|
85
86
|
return driver;
|
|
86
87
|
}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
// Native copy orchestration. Only Workers KV and Web Crypto are Promise leaves.
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
import { errorLabel } from "../operator-record.js";
|
|
4
|
+
import { KvToD1CopyError } from "../d1.js";
|
|
5
|
+
import { familyOfKey, KEY_FAMILIES, KV_COPY_CURSOR_TTL_SECONDS, kvCopyKeys, kvCutoverKeys } from "./keys.js";
|
|
6
|
+
import { copyIntoSqlEffect, nativeSqlStorage } from "./sql-native.js";
|
|
7
|
+
import { nativeSqlDriver } from "./sql-driver.js";
|
|
8
|
+
import { d1Driver } from "./d1-driver.js";
|
|
9
|
+
const leaf = (operation) => Effect.tryPromise({ try: operation, catch: (error) => error });
|
|
10
|
+
// A native equivalent of a Promise try/catch. Synchronous parser/validation
|
|
11
|
+
// throws keep their original identity too; interruption is never recovered.
|
|
12
|
+
const attempt = (effect) => Effect.result(effect.pipe(Effect.catchDefect((error) => Effect.fail(error))));
|
|
13
|
+
/** D1 string and row limit, in UTF-8 bytes.
|
|
14
|
+
* https://developers.cloudflare.com/d1/platform/limits/
|
|
15
|
+
*/
|
|
16
|
+
const D1_MAX_ROW_BYTES = 2000000;
|
|
17
|
+
/** Buffered entries, excluding the single value currently being read. */
|
|
18
|
+
const COPY_BUFFER_BYTES = 4 * 1024 * 1024;
|
|
19
|
+
const COPY_GROUP_KEYS = 50;
|
|
20
|
+
const KV_LIST_LIMIT = 1000;
|
|
21
|
+
const encoder = new TextEncoder();
|
|
22
|
+
// SQLite record header, two TEXT serial types, and an eight-byte expiry.
|
|
23
|
+
// Reserve the worst-case header rather than accepting a row at the boundary.
|
|
24
|
+
const ROW_OVERHEAD_BYTES = 32;
|
|
25
|
+
const emptyCounts = () => ({
|
|
26
|
+
copied: 0,
|
|
27
|
+
unchanged: 0,
|
|
28
|
+
conflicts: 0,
|
|
29
|
+
overwritten: 0,
|
|
30
|
+
expired: 0,
|
|
31
|
+
invalid: 0,
|
|
32
|
+
verified: 0,
|
|
33
|
+
mismatches: 0,
|
|
34
|
+
});
|
|
35
|
+
const OUTCOME_COUNT = {
|
|
36
|
+
copied: "copied",
|
|
37
|
+
unchanged: "unchanged",
|
|
38
|
+
conflict: "conflicts",
|
|
39
|
+
overwritten: "overwritten",
|
|
40
|
+
};
|
|
41
|
+
function errorClass(error) {
|
|
42
|
+
const label = errorLabel(error);
|
|
43
|
+
return label ? ` (${label})` : "";
|
|
44
|
+
}
|
|
45
|
+
const valueHash = (value) => Effect.gen(function* () {
|
|
46
|
+
const hash = yield* leaf(() => crypto.subtle.digest("SHA-256", encoder.encode(value)));
|
|
47
|
+
return Array.from(new Uint8Array(hash), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
48
|
+
});
|
|
49
|
+
/** Mark cutover before reopening traffic. The marker stays in D1 permanently. */
|
|
50
|
+
export function markKvToD1LiveEffect(db, source) {
|
|
51
|
+
return Effect.gen(function* () {
|
|
52
|
+
if (typeof source !== "string" || !source || source.includes("\0")) {
|
|
53
|
+
throw new TypeError("copyKvToD1 source must be a namespace id");
|
|
54
|
+
}
|
|
55
|
+
const cutover = yield* attempt(nativeSqlStorage(nativeSqlDriver(d1Driver(db))).set(kvCutoverKeys.source(source), "live"));
|
|
56
|
+
if (cutover._tag === "Failure") {
|
|
57
|
+
const error = cutover.failure;
|
|
58
|
+
throw new KvToD1CopyError(`Workers KV to D1 copy stopped: recording cutover failed${errorClass(error)}`, undefined);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Copy live KV entries verbatim while all writers and traffic are stopped.
|
|
64
|
+
* A live D1 row is kept unless its family is explicitly allowed to overwrite.
|
|
65
|
+
* `verify` reads hashes and absolute expiries without changing copied entries.
|
|
66
|
+
* Results contain counts only. Resume tokens are source-bound atomic claims.
|
|
67
|
+
*/
|
|
68
|
+
export function copyKvToD1Effect(kv, db, options) {
|
|
69
|
+
return Effect.gen(function* () {
|
|
70
|
+
if (!options?.source || typeof options.source !== "string" || options.source.includes("\0")) {
|
|
71
|
+
throw new TypeError("copyKvToD1 source must be a namespace id");
|
|
72
|
+
}
|
|
73
|
+
const maxKeys = options.maxKeys ?? 500;
|
|
74
|
+
if (!Number.isSafeInteger(maxKeys) || maxKeys < 1) {
|
|
75
|
+
throw new TypeError("copyKvToD1 maxKeys must be a positive integer");
|
|
76
|
+
}
|
|
77
|
+
const allowed = new Set([...KEY_FAMILIES.map((family) => family.name), "connector-owned", "unclassified"]);
|
|
78
|
+
if (options.overwriteFamilies?.some((family) => !allowed.has(family))) {
|
|
79
|
+
throw new TypeError("copyKvToD1 overwriteFamilies contains an unknown family");
|
|
80
|
+
}
|
|
81
|
+
const overwrite = new Set(options.overwriteFamilies ?? []);
|
|
82
|
+
const driver = nativeSqlDriver(d1Driver(db));
|
|
83
|
+
const storage = nativeSqlStorage(driver);
|
|
84
|
+
const remember = (kvCursor) => Effect.gen(function* () {
|
|
85
|
+
const token = crypto.randomUUID();
|
|
86
|
+
yield* storage.set(kvCopyKeys.cursor(token), JSON.stringify({ source: options.source, cursor: kvCursor }), {
|
|
87
|
+
ttlSeconds: KV_COPY_CURSOR_TTL_SECONDS,
|
|
88
|
+
});
|
|
89
|
+
return token;
|
|
90
|
+
});
|
|
91
|
+
let cursor;
|
|
92
|
+
let pageCursor;
|
|
93
|
+
const families = {};
|
|
94
|
+
const count = (key, field) => {
|
|
95
|
+
(families[familyOfKey(key)] ??= emptyCounts())[field] += 1;
|
|
96
|
+
};
|
|
97
|
+
const unknown = new TypeError("copyKvToD1 cursor is unknown, expired, spent, or belongs to another source; restart under maintenance");
|
|
98
|
+
const stale = new TypeError("copyKvToD1 refuses stale KV after cutover");
|
|
99
|
+
// Validate before any D1 access so a failing binding cannot return raw input
|
|
100
|
+
// as an error's resume point.
|
|
101
|
+
if (options.cursor !== undefined &&
|
|
102
|
+
!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(options.cursor)) {
|
|
103
|
+
throw unknown;
|
|
104
|
+
}
|
|
105
|
+
const failures = new WeakSet();
|
|
106
|
+
const failure = (message) => {
|
|
107
|
+
const error = new KvToD1CopyError(message, undefined);
|
|
108
|
+
failures.add(error);
|
|
109
|
+
return error;
|
|
110
|
+
};
|
|
111
|
+
const claim = yield* attempt(Effect.gen(function* () {
|
|
112
|
+
if (!options.allowStale && (yield* storage.get(kvCutoverKeys.source(options.source))) !== null) {
|
|
113
|
+
throw stale;
|
|
114
|
+
}
|
|
115
|
+
if (options.cursor !== undefined) {
|
|
116
|
+
const key = kvCopyKeys.cursor(options.cursor);
|
|
117
|
+
const stored = yield* storage.get(key);
|
|
118
|
+
let record = null;
|
|
119
|
+
try {
|
|
120
|
+
record = stored === null ? null : JSON.parse(stored);
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
/* refused below */
|
|
124
|
+
}
|
|
125
|
+
if (!record || record.source !== options.source || typeof record.cursor !== "string") {
|
|
126
|
+
throw unknown;
|
|
127
|
+
}
|
|
128
|
+
// Delete only the exact record read: concurrent consumers cannot both win.
|
|
129
|
+
if (!(yield* storage.compareAndSet(key, stored, null)))
|
|
130
|
+
throw unknown;
|
|
131
|
+
cursor = record.cursor;
|
|
132
|
+
}
|
|
133
|
+
}));
|
|
134
|
+
if (claim._tag === "Failure") {
|
|
135
|
+
const error = claim.failure;
|
|
136
|
+
if (error === unknown || error === stale)
|
|
137
|
+
throw error;
|
|
138
|
+
throw new KvToD1CopyError(`Workers KV to D1 copy stopped: claiming the resume point in D1 failed${errorClass(error)}`, options.cursor);
|
|
139
|
+
}
|
|
140
|
+
const flush = (buffer) => Effect.gen(function* () {
|
|
141
|
+
const entries = buffer.filter((entry) => {
|
|
142
|
+
if (entry.expiresAtMs !== null && entry.expiresAtMs <= Date.now()) {
|
|
143
|
+
count(entry.key, "expired");
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
return true;
|
|
147
|
+
});
|
|
148
|
+
if (!entries.length)
|
|
149
|
+
return;
|
|
150
|
+
const flushed = yield* attempt(Effect.gen(function* () {
|
|
151
|
+
if (options.verify) {
|
|
152
|
+
for (const entry of entries) {
|
|
153
|
+
const [row] = yield* driver.all({
|
|
154
|
+
// Read bytes, including NUL, and hash in JS. D1 has no SHA-256 function.
|
|
155
|
+
sql: "SELECT CAST(value AS BLOB) AS value_bytes, expires_at_ms FROM connecta_kv WHERE key = ?",
|
|
156
|
+
params: [entry.key],
|
|
157
|
+
});
|
|
158
|
+
const bytes = row ? Uint8Array.from(row.value_bytes) : undefined;
|
|
159
|
+
const hash = bytes ? yield* leaf(() => crypto.subtle.digest("SHA-256", bytes)) : undefined;
|
|
160
|
+
const hex = hash
|
|
161
|
+
? Array.from(new Uint8Array(hash), (byte) => byte.toString(16).padStart(2, "0")).join("")
|
|
162
|
+
: undefined;
|
|
163
|
+
count(entry.key, row && row.expires_at_ms === entry.expiresAtMs && hex === (yield* valueHash(entry.value))
|
|
164
|
+
? "verified"
|
|
165
|
+
: "mismatches");
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
// Partition only this bounded buffer by overwrite permission.
|
|
170
|
+
for (const replace of [false, true]) {
|
|
171
|
+
const group = entries.filter((entry) => overwrite.has(familyOfKey(entry.key)) === replace);
|
|
172
|
+
if (!group.length)
|
|
173
|
+
continue;
|
|
174
|
+
const outcomes = yield* copyIntoSqlEffect(driver, group, { overwrite: replace, now: Date.now() });
|
|
175
|
+
for (const [index, outcome] of outcomes.entries())
|
|
176
|
+
count(group[index].key, OUTCOME_COUNT[outcome]);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}));
|
|
180
|
+
if (flushed._tag === "Failure") {
|
|
181
|
+
const error = flushed.failure;
|
|
182
|
+
throw failure(`Workers KV to D1 copy stopped: ${options.verify ? "verifying" : "writing to"} D1 failed${errorClass(error)}`);
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
let read = 0;
|
|
186
|
+
const copied = yield* attempt(Effect.gen(function* () {
|
|
187
|
+
for (;;) {
|
|
188
|
+
pageCursor = cursor;
|
|
189
|
+
const listed = yield* attempt(leaf(() => kv.list({ limit: Math.min(KV_LIST_LIMIT, maxKeys - read), ...(cursor ? { cursor } : {}) })));
|
|
190
|
+
if (listed._tag === "Failure") {
|
|
191
|
+
const error = listed.failure;
|
|
192
|
+
throw failure(`Workers KV to D1 copy stopped: listing Workers KV failed${errorClass(error)}`);
|
|
193
|
+
}
|
|
194
|
+
const page = listed.success;
|
|
195
|
+
read += page.keys.length;
|
|
196
|
+
let entries = [];
|
|
197
|
+
let bufferedBytes = 0;
|
|
198
|
+
for (const key of page.keys) {
|
|
199
|
+
const keyBytes = encoder.encode(key.name).byteLength;
|
|
200
|
+
if (key.name.includes("\0") || keyBytes + ROW_OVERHEAD_BYTES > D1_MAX_ROW_BYTES) {
|
|
201
|
+
count(key.name, "invalid");
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
const expiresAtMs = key.expiration === undefined ? null : key.expiration * 1000;
|
|
205
|
+
if (expiresAtMs !== null && expiresAtMs <= Date.now()) {
|
|
206
|
+
count(key.name, "expired");
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
const readValue = yield* attempt(leaf(() => kv.get(key.name, "text")));
|
|
210
|
+
if (readValue._tag === "Failure") {
|
|
211
|
+
const error = readValue.failure;
|
|
212
|
+
throw failure(`Workers KV to D1 copy stopped: reading an entry of the ${familyOfKey(key.name)} family from Workers KV failed${errorClass(error)}`);
|
|
213
|
+
}
|
|
214
|
+
const value = readValue.success;
|
|
215
|
+
if (value === null || (expiresAtMs !== null && expiresAtMs <= Date.now())) {
|
|
216
|
+
count(key.name, "expired");
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
const valueBytes = encoder.encode(value).byteLength;
|
|
220
|
+
const bytes = keyBytes + valueBytes + ROW_OVERHEAD_BYTES;
|
|
221
|
+
if (valueBytes > D1_MAX_ROW_BYTES || bytes > D1_MAX_ROW_BYTES) {
|
|
222
|
+
count(key.name, "invalid");
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
if (entries.length >= COPY_GROUP_KEYS || bufferedBytes + bytes > COPY_BUFFER_BYTES) {
|
|
226
|
+
yield* flush(entries);
|
|
227
|
+
entries = [];
|
|
228
|
+
bufferedBytes = 0;
|
|
229
|
+
}
|
|
230
|
+
entries.push({ key: key.name, value, expiresAtMs });
|
|
231
|
+
bufferedBytes += bytes;
|
|
232
|
+
}
|
|
233
|
+
yield* flush(entries);
|
|
234
|
+
if (page.list_complete || !page.cursor)
|
|
235
|
+
return { done: true, families };
|
|
236
|
+
cursor = page.cursor;
|
|
237
|
+
if (read >= maxKeys)
|
|
238
|
+
return { done: false, cursor: yield* remember(cursor), families };
|
|
239
|
+
}
|
|
240
|
+
}));
|
|
241
|
+
if (copied._tag === "Failure") {
|
|
242
|
+
const error = copied.failure;
|
|
243
|
+
// The old token was claimed atomically. Replace it on failure, if D1 works.
|
|
244
|
+
const resume = pageCursor === undefined
|
|
245
|
+
? undefined
|
|
246
|
+
: yield* attempt(remember(pageCursor)).pipe(Effect.map((result) => (result._tag === "Success" ? result.success : undefined)));
|
|
247
|
+
throw new KvToD1CopyError(error instanceof KvToD1CopyError && failures.has(error)
|
|
248
|
+
? error.message
|
|
249
|
+
: `Workers KV to D1 copy stopped: recording the resume point in D1 failed${errorClass(error)}`, resume);
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
return copied.success;
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { effectSqlDriver, sqlDriverEdge, sqlPromise } from "./sql-driver.js";
|
|
2
|
+
export function d1Driver(db) {
|
|
3
|
+
const prepare = (statement) => statement.params.length > 0 ? db.prepare(statement.sql).bind(...statement.params) : db.prepare(statement.sql);
|
|
4
|
+
return sqlDriverEdge(effectSqlDriver({
|
|
5
|
+
all: (statement) => sqlPromise(() => prepare(statement)
|
|
6
|
+
.all()
|
|
7
|
+
.then((result) => result.results)),
|
|
8
|
+
run: (statement) => sqlPromise(() => prepare(statement)
|
|
9
|
+
.run()
|
|
10
|
+
.then((result) => result.meta.changes ?? 0)),
|
|
11
|
+
// D1's public binding API preserves per-statement changes, including zero;
|
|
12
|
+
// execute the whole array once. No withTransaction, RETURNING, or replay.
|
|
13
|
+
batch: (statements) => sqlPromise(() => db.batch(statements.map(prepare)).then((results) => results.map((result) => result.meta.changes ?? 0))),
|
|
14
|
+
}));
|
|
15
|
+
}
|
package/dist/storage/keys.js
CHANGED
|
@@ -74,6 +74,19 @@ export const resultKeys = {
|
|
|
74
74
|
chunk: (id, index) => validateStorageKey(index === 0 ? `result:${id}` : `result:${id}#${index}`),
|
|
75
75
|
};
|
|
76
76
|
// --- root families --------------------------------------------------------
|
|
77
|
+
/** A deployment's random HMAC key for bound continuation cursors; never expires or leaves storage. */
|
|
78
|
+
export const continuationKeys = {
|
|
79
|
+
family: {
|
|
80
|
+
name: "continuation-key",
|
|
81
|
+
scope: "root",
|
|
82
|
+
prefixes: ["continuation-key:v1:"],
|
|
83
|
+
version: { number: 1, in: "key" },
|
|
84
|
+
codec: textCodec,
|
|
85
|
+
ttl: { kind: "durable" },
|
|
86
|
+
durable: true,
|
|
87
|
+
},
|
|
88
|
+
signingKey: "continuation-key:v1:signing",
|
|
89
|
+
};
|
|
77
90
|
/**
|
|
78
91
|
* The runtime-wide result stash ledger: every live stash entry's reservation
|
|
79
92
|
* id, byte charge, and expiry. One record, swapped by compare-and-set, so the
|
|
@@ -188,6 +201,19 @@ export const accessTokenKeys = {
|
|
|
188
201
|
adopted: (legacyRecordId) => validateStorageKey(`access-token:v1:adopted:${legacyRecordId}`),
|
|
189
202
|
active: "access-token:v1:active",
|
|
190
203
|
};
|
|
204
|
+
/** Latest successful agent endpoint admission; name and timestamp only. */
|
|
205
|
+
export const agentObservationKeys = {
|
|
206
|
+
family: {
|
|
207
|
+
name: "agent-observation",
|
|
208
|
+
scope: "root",
|
|
209
|
+
prefixes: ["agent-observation:v1:"],
|
|
210
|
+
version: { number: 1, in: "key" },
|
|
211
|
+
codec: textCodec,
|
|
212
|
+
ttl: { kind: "durable" },
|
|
213
|
+
durable: true,
|
|
214
|
+
},
|
|
215
|
+
agent: (name) => validateStorageKey(`agent-observation:v1:${name}`),
|
|
216
|
+
};
|
|
191
217
|
/**
|
|
192
218
|
* A vault credential, sealed: `credential:v1` inside its connector's
|
|
193
219
|
* namespace, under the owner's principal partition when it is personal.
|
|
@@ -399,6 +425,7 @@ export const inputRetryKeys = {
|
|
|
399
425
|
* namespace, and are not listed here.
|
|
400
426
|
*/
|
|
401
427
|
export const KEY_FAMILIES = [
|
|
428
|
+
continuationKeys.family,
|
|
402
429
|
resultKeys.family,
|
|
403
430
|
stashLedgerKeys.family,
|
|
404
431
|
stashExpiryKeys.family,
|
|
@@ -406,6 +433,7 @@ export const KEY_FAMILIES = [
|
|
|
406
433
|
responseCacheKeys.family,
|
|
407
434
|
oauthHandoffKeys.family,
|
|
408
435
|
accessTokenKeys.family,
|
|
436
|
+
agentObservationKeys.family,
|
|
409
437
|
credentialKeys.family,
|
|
410
438
|
oauthGrantKeys.family,
|
|
411
439
|
oauthFlowKeys.family,
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Native SQL service, private to the /d1 and /sqlite import graphs.
|
|
2
|
+
// SqlClient services and Statement operations execute reads and writes. Atomic
|
|
3
|
+
// batches retain the public platform metadata and structural D1 compatibility.
|
|
4
|
+
import { Effect, Stream } from "effect";
|
|
5
|
+
import * as SqlClient from "effect/sql/SqlClient";
|
|
6
|
+
import * as Reactivity from "effect/reactivity/Reactivity";
|
|
7
|
+
import { SqlError, UnknownError } from "effect/sql/SqlError";
|
|
8
|
+
import * as Statement from "effect/sql/Statement";
|
|
9
|
+
import { runEdge } from "../runtime/run.js";
|
|
10
|
+
// SQL errors carry no driver cause or parameters, even inside tracing. Recover
|
|
11
|
+
// the original thrown object only at the private SQL boundary, as before.
|
|
12
|
+
const causes = new WeakMap();
|
|
13
|
+
function sqlError(cause) {
|
|
14
|
+
const error = new SqlError({ reason: new UnknownError({ cause: undefined, message: "SQL operation failed" }) });
|
|
15
|
+
causes.set(error, cause);
|
|
16
|
+
return error;
|
|
17
|
+
}
|
|
18
|
+
const original = (error) => (causes.has(error) ? causes.get(error) : error);
|
|
19
|
+
export function sqlSync(operation) {
|
|
20
|
+
return Effect.try({ try: operation, catch: sqlError });
|
|
21
|
+
}
|
|
22
|
+
/** Exactly one SDK/platform Promise leaf; no retries or shared flights. */
|
|
23
|
+
export function sqlPromise(operation) {
|
|
24
|
+
return Effect.tryPromise({ try: operation, catch: sqlError });
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* A request-local public SqlClient service executes actual Statement Effects.
|
|
28
|
+
* Native batches are deliberately separate: D1 cannot use withTransaction and
|
|
29
|
+
* SQLite must not yield between BEGIN IMMEDIATE and COMMIT. The deployment
|
|
30
|
+
* owns the database; the service owns no platform connection or cached I/O.
|
|
31
|
+
*/
|
|
32
|
+
export function effectSqlDriver(leaves) {
|
|
33
|
+
const input = (sql, params) => ({
|
|
34
|
+
sql,
|
|
35
|
+
params: params,
|
|
36
|
+
});
|
|
37
|
+
const execute = (sql, params, transform) => leaves.all(input(sql, params)).pipe(Effect.map((rows) => (transform ? transform(rows) : rows)));
|
|
38
|
+
const values = (sql, params) => leaves.all(input(sql, params)).pipe(Effect.map((rows) => rows.map((row) => Object.values(row))));
|
|
39
|
+
const connection = {
|
|
40
|
+
execute,
|
|
41
|
+
executeRaw: (sql, params) => leaves.run(input(sql, params)),
|
|
42
|
+
executeUnprepared: execute,
|
|
43
|
+
executeValues: values,
|
|
44
|
+
executeValuesUnprepared: values,
|
|
45
|
+
executeStream: () => Stream.fail(sqlError(new Error("SQL streaming is not supported"))),
|
|
46
|
+
};
|
|
47
|
+
// This Effect constructs a fresh client and its services inside every
|
|
48
|
+
// operation. No request-owned object, scope or promise is memoized here.
|
|
49
|
+
const client = SqlClient.make({
|
|
50
|
+
acquirer: Effect.succeed(connection),
|
|
51
|
+
borrower: (use) => use(connection),
|
|
52
|
+
transactionAcquirer: Effect.fail(sqlError(new Error("Use an atomic SQL batch"))),
|
|
53
|
+
compiler: Statement.makeCompilerSqlite(),
|
|
54
|
+
spanAttributes: [],
|
|
55
|
+
}).pipe(Effect.provideServiceEffect(Reactivity.Reactivity, Reactivity.make));
|
|
56
|
+
const protect = (effect) =>
|
|
57
|
+
// The yield precedes physical execution, never an atomic transaction.
|
|
58
|
+
// Statement execution creates SQL spans; disable tracing before it starts,
|
|
59
|
+
// and unwrap only after the private SQL operation has completed.
|
|
60
|
+
Effect.andThen(Effect.yieldNow, effect).pipe(Effect.withTracerEnabled(false), Effect.mapError(original), Effect.catchDefect((error) => Effect.fail(error)));
|
|
61
|
+
const operation = (use) => protect(SqlClient.SqlClient.use(use).pipe(Effect.provideServiceEffect(SqlClient.SqlClient, client)));
|
|
62
|
+
return {
|
|
63
|
+
all: (statement) => operation((sql) => Effect.map(sql.unsafe(statement.sql, statement.params), (rows) => rows)),
|
|
64
|
+
run: (statement) => operation((sql) => sql.unsafe(statement.sql, statement.params).raw),
|
|
65
|
+
// One native transaction returns exact per-statement metadata. This
|
|
66
|
+
// capability is not SqlClient.withTransaction, which D1 does not support.
|
|
67
|
+
batch: (statements) => protect(Effect.suspend(() => leaves.batch(statements))),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const natives = new WeakMap();
|
|
71
|
+
/** Promise compatibility view, including private adapter characterization. */
|
|
72
|
+
export function sqlDriverEdge(native) {
|
|
73
|
+
const driver = {
|
|
74
|
+
all: (statement) => runEdge(native.all(statement)),
|
|
75
|
+
run: (statement) => runEdge(native.run(statement)),
|
|
76
|
+
batch: (statements) => runEdge(native.batch(statements)),
|
|
77
|
+
};
|
|
78
|
+
natives.set(driver, native);
|
|
79
|
+
return driver;
|
|
80
|
+
}
|
|
81
|
+
/** Custom/private Promise drivers retain their original fallback behavior. */
|
|
82
|
+
export function nativeSqlDriver(driver) {
|
|
83
|
+
return (natives.get(driver) ?? {
|
|
84
|
+
all: (statement) => Effect.tryPromise({ try: () => Promise.resolve(driver.all(statement)), catch: (e) => e }),
|
|
85
|
+
run: (statement) => Effect.tryPromise({ try: () => Promise.resolve(driver.run(statement)), catch: (e) => e }),
|
|
86
|
+
batch: (statements) => Effect.tryPromise({ try: () => Promise.resolve(driver.batch(statements)), catch: (e) => e }),
|
|
87
|
+
});
|
|
88
|
+
}
|