Discovered while resolving #1622 (event-scoped DB connections for connection-backed adapters).
Problem
Sandboxed plugins on the production Cloudflare runner talk to the database through the PluginBridge Durable Object (packages/cloudflare/src/sandbox/bridge.ts). That bridge is hardcoded to D1:
const db = new Kysely<unknown>({ dialect: new D1Dialect({ database: this.env.DB }) });
// ...and many this.env.DB.prepare(...) calls
It constructs its own D1 connection from env.DB, completely independent of the adapter the site configured (d1(), hyperdrive(), durableObjects(), ...). Consequences:
- On a
hyperdrive() deployment there may be no env.DB binding at all, so sandboxed plugins that read/write content, media, or plugin storage fail or hit the wrong database.
- Even where a D1 binding coexists, sandboxed plugins would read/write a different database than the rest of the site.
So sandboxed plugins are effectively D1-only. This is a pre-existing constraint, independent of the connection-scoping work in #1622 (which covered cron, plugin hook contexts, and media providers in core).
Why #1622 did not fix this
#1622 threaded an event-scoped DB resolver through core subsystems (cron executor, plugin context factory, media providers). The sandbox bridge does not use the runtime db at all; it stands up its own D1 connection inside the DO, so there was nothing for the resolver to flow into. Fixing it requires teaching the bridge to use the configured adapter.
Proposed direction
Acceptance
Discovered while resolving #1622 (event-scoped DB connections for connection-backed adapters).
Problem
Sandboxed plugins on the production Cloudflare runner talk to the database through the
PluginBridgeDurable Object (packages/cloudflare/src/sandbox/bridge.ts). That bridge is hardcoded to D1:It constructs its own D1 connection from
env.DB, completely independent of the adapter the site configured (d1(),hyperdrive(),durableObjects(), ...). Consequences:hyperdrive()deployment there may be noenv.DBbinding at all, so sandboxed plugins that read/write content, media, or plugin storage fail or hit the wrong database.So sandboxed plugins are effectively D1-only. This is a pre-existing constraint, independent of the connection-scoping work in #1622 (which covered cron, plugin hook contexts, and media providers in core).
Why #1622 did not fix this
#1622 threaded an event-scoped DB resolver through core subsystems (cron executor, plugin context factory, media providers). The sandbox bridge does not use the runtime db at all; it stands up its own D1 connection inside the DO, so there was nothing for the resolver to flow into. Fixing it requires teaching the bridge to use the configured adapter.
Proposed direction
PluginBridgeDO access to the configured adapter rather than a hardcodedD1Dialect. For connection-backed adapters (Hyperdrive/pg) the DO must open its own event-scoped connection inside each bridge request (the same cross-event constraint as feat(cloudflare): Hyperdrive Postgres database adapter #1614/Thread an event-scoped DB connection through cron, plugin contexts, media providers, and sandbox runner #1622), not reuse a singleton.packages/workerd/src/sandbox/runner.tsusesoptions.dbdirectly; fine on Node, but should stay consistent).Acceptance
d1(),hyperdrive(), and DO SQL adapters.hyperdrive()JSDoc and adapter module header.