Skip to content

feat(cloudflare): Hyperdrive Postgres database adapter - #1614

Merged
ascorbic merged 7 commits into
mainfrom
feat/hyperdrive-postgres-adapter
Jun 25, 2026
Merged

feat(cloudflare): Hyperdrive Postgres database adapter#1614
ascorbic merged 7 commits into
mainfrom
feat/hyperdrive-postgres-adapter

Conversation

@scottbuscemi

@scottbuscemi scottbuscemi commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

What does this PR do?

Adds a hyperdrive() database adapter to @emdash-cms/cloudflare so EmDash can run on Cloudflare Workers backed by a PostgreSQL (or Postgres-compatible, e.g. PlanetScale Postgres) database through a Hyperdrive binding. Hyperdrive handles connection pooling and query caching; EmDash's existing PostgreSQL dialect runs the queries.

// astro.config.mjs
import { hyperdrive, r2 } from "@emdash-cms/cloudflare";

emdash({
  database: hyperdrive({ binding: "HYPERDRIVE" }),
  storage: r2({ binding: "MEDIA" }),
});

Making this work on Workers required two small core fixes that benefit any connection-backed, request-scoped adapter (D1 and other stateless bindings are unaffected):

  1. locals.emdash.db is now a lazy getter. It was eagerly captured when locals.emdash is built — which happens before the per-request scoped DB is installed in ALS — so routes always received the per-isolate singleton. For a stateless binding (D1) that's equivalent, but for a request-bound connection (pg over Hyperdrive) the singleton belongs to the cold-start request, and reusing it from a warm request hangs on workerd's cross-request I/O guard.
  2. Request-scoped connections now close at stream-end, not before. Astro streams HTML and the Live loader issues queries while the body streams, so closing the connection in the middleware's commit() produced "driver has already been destroyed". A new optional close() hook on the request-scoped contract is invoked once the body has fully flushed (immediately for bodyless responses); commit() still runs pre-response so D1's bookmark cookie is unaffected.

The adapter is request-scoped: each request gets its own pg.Pool + Kysely, opened and closed within that request, because a Worker connection cannot be reused across requests.

⚠️ Disable Hyperdrive query caching

Hyperdrive's query cache is default-on and must be turned off for an EmDash configuration. EmDash runs its own caching layer and relies on read-after-write consistency — the admin and setup wizard write a row and immediately read it back. With caching on, Hyperdrive can serve the pre-write result within its TTL, which corrupted setup during testing ("collection already exists", then half-created tables missing columns) and would show editors stale content. Disable it:

wrangler hyperdrive update <id> --caching-disabled
# or at create time: wrangler hyperdrive create ... --caching-disabled

This is documented in the hyperdrive() JSDoc and called out in the changeset.

Verified end-to-end against a real PlanetScale Postgres database provisioned through Cloudflare + Hyperdrive: migrations, seeding (content + media to R2), and all public routes (home, posts list, post detail, RSS) render consistently with no hangs. Pairing the deploy with a Smart Placement hint (placement.region: "aws:us-east-1") co-locates the Worker with the database (cf-placement: remote-IAD).

Closes #

Type of change

  • Bug fix
  • Feature (requires maintainer-approved Discussion)
  • Refactor (no behavior change)
  • Translation
  • Documentation
  • Performance improvement
  • Tests
  • Chore (dependencies, CI, tooling)

Note: the core changes (#1 and #2 above) are strictly bug fixes required for request-scoped connection adapters to function on Workers; the new adapter is the feature.

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes
  • pnpm lint passes
  • pnpm test passes (or targeted tests for my change) — 189 cloudflare + 4105 core tests pass
  • pnpm format has been run
  • I have added/updated tests for my changes (if applicable) — config-time descriptor tests for hyperdrive()
  • User-visible strings in the admin UI are wrapped for translation (if applicable) — n/a, no admin UI strings added
  • I have added a changeset@emdash-cms/cloudflare minor, emdash patch
  • New features link to an approved Discussion — n/a, opened by a maintainer (maintainer approval stands in for the Discussion).

AI-generated code disclosure

  • This PR includes AI-generated code — model/tool: Claude Opus 4.8 (via OpenCode)

Screenshots / test output

@emdash-cms/cloudflare  Test Files  13 passed (13)   Tests  189 passed (189)
emdash                  Test Files 285 passed (285)   Tests 4105 passed (4105)
pnpm typecheck: all packages Done
pnpm lint --type-aware --deny-warnings: exit 0

Live verification (PlanetScale Postgres via Hyperdrive):

200 29379b  /
200 26234b  /posts
200 36402b  /posts/building-for-the-long-term
200  4004b  /rss.xml
cf-placement: remote-IAD   # Worker placed next to PlanetScale aws:us-east-1

Try this PR

Open a fresh playground →

A full working EmDash site, deployed from this branch. Each visit gets its own session-scoped sandbox: no login needed and no shared state. Try the admin, edit content, hit the public site.

Tracks feat/hyperdrive-postgres-adapter. Updated automatically when the playground redeploys.

@changeset-bot

changeset-bot Bot commented Jun 24, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 144abd9

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 16 packages
Name Type
@emdash-cms/cloudflare Minor
emdash Minor
@emdash-cms/fixture-perf-site Patch
@emdash-cms/perf-demo-site Patch
@emdash-cms/cache-demo-site Patch
@emdash-cms/do-demo-site Patch
@emdash-cms/do-solo-demo-site Patch
@emdash-cms/sandbox-workerd Patch
@emdash-cms/admin Minor
@emdash-cms/auth Minor
@emdash-cms/blocks Minor
@emdash-cms/gutenberg-to-portable-text Minor
@emdash-cms/x402 Minor
create-emdash Minor
@emdash-cms/auth-atproto Patch
@emdash-cms/plugin-embeds Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Jun 24, 2026

Copy link
Copy Markdown

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/@emdash-cms/admin@1614

@emdash-cms/auth

npm i https://pkg.pr.new/@emdash-cms/auth@1614

@emdash-cms/auth-atproto

npm i https://pkg.pr.new/@emdash-cms/auth-atproto@1614

@emdash-cms/blocks

npm i https://pkg.pr.new/@emdash-cms/blocks@1614

@emdash-cms/cloudflare

npm i https://pkg.pr.new/@emdash-cms/cloudflare@1614

@emdash-cms/contentful-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/contentful-to-portable-text@1614

emdash

npm i https://pkg.pr.new/emdash@1614

create-emdash

npm i https://pkg.pr.new/create-emdash@1614

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/gutenberg-to-portable-text@1614

@emdash-cms/plugin-cli

npm i https://pkg.pr.new/@emdash-cms/plugin-cli@1614

@emdash-cms/plugin-types

npm i https://pkg.pr.new/@emdash-cms/plugin-types@1614

@emdash-cms/registry-client

npm i https://pkg.pr.new/@emdash-cms/registry-client@1614

@emdash-cms/registry-lexicons

npm i https://pkg.pr.new/@emdash-cms/registry-lexicons@1614

@emdash-cms/sandbox-workerd

npm i https://pkg.pr.new/@emdash-cms/sandbox-workerd@1614

@emdash-cms/x402

npm i https://pkg.pr.new/@emdash-cms/x402@1614

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/@emdash-cms/plugin-ai-moderation@1614

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/@emdash-cms/plugin-atproto@1614

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/@emdash-cms/plugin-audit-log@1614

@emdash-cms/plugin-color

npm i https://pkg.pr.new/@emdash-cms/plugin-color@1614

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/@emdash-cms/plugin-embeds@1614

@emdash-cms/plugin-field-kit

npm i https://pkg.pr.new/@emdash-cms/plugin-field-kit@1614

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/@emdash-cms/plugin-forms@1614

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/@emdash-cms/plugin-webhook-notifier@1614

commit: 144abd9

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 24, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
docs b874c50 Jun 24 2026, 07:06 PM

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 24, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
emdash-demo-cache 144abd9 Jun 25 2026, 03:15 PM

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 24, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
emdash-playground 144abd9 Jun 25 2026, 03:13 PM

@emdashbot emdashbot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The adapter is a sensible addition and the two core changes (lazy locals.emdash.db getter and deferred close() until stream-end) are the right fixes for request-scoped connection adapters on Workers. I did not run the test suite / build / lint (no shell), so I’m taking the author’s reported results as unverified.

Approach-level concern: this is a feature PR, and AGENTS.md requires a maintainer-approved Discussion for features. The PR checklist explicitly says a Discussion has not been opened. That is a process blocker for the maintainer to resolve regardless of code quality; I am not treating it as a code defect, but it should be addressed before merge.

What I checked: the adapter contract in virtual-modules.d.ts, the new hyperdrive.ts adapter, the config-time descriptor, the middleware lifecycle refactor (finishScoped, wrapResponseForScopedClose, lazy db getter), and the existing D1 adapter for comparison.

Headline conclusion: the lifecycle plumbing looks correct, but there are real gaps:

  1. Request-scoped Hyperdrive queries lose instrumentation/metrics. createRequestScopedDb builds its Kysely without log: kyselyLogOption(). The D1 adapter passes it; the runtime singleton passes it; omitting it here means db.* Server-Timing counters and EMDASH_QUERY_LOG records won’t capture per-request Hyperdrive queries.
  2. finishScoped can leak a connection if commit() throws on the success path. On error it closes immediately, but if run() succeeds and scoped.commit() throws, close() is never called. commit() is a no-op for Hyperdrive, but the helper is generic and a future adapter could leak.
  3. The isolate-singleton connection in createDialect is retained across requests. The PR itself explains that pg sockets are bound to the request that opened them, yet createDialect creates a persistent pool that stays open for the worker lifetime (cold-start migrations and cron). Any future code path that touches this._db from inside an HTTP request — including plugin contexts and the sandbox runner built against the cold-start singleton — risks workerd’s cross-request I/O guard. Cron is not an HTTP request, but the singleton is created during the first HTTP request if scheduled tasks haven’t run yet, and it is never drained after migrations finish.
  4. No regression tests for the core request-scoping changes. The only new tests validate the config-time descriptor; finishScoped, the lazy getter, and stream-end close are not covered.

None of these are catastrophic for a D1 deployment, but #1 is an observable behavioral regression for Hyperdrive users and #3 is the exact cross-request-socket problem the PR’s own comments warn about, just shifted from the request path to the singleton path.

if (!binding?.connectionString) return null;

const pool = createPool(binding.connectionString, opts.config.max ?? DEFAULT_MAX);
const db = new Kysely<any>({ dialect: new PostgresDialect({ pool }) });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[needs fixing] The per-request Kysely is built without the log option, so request metrics (db.* Server-Timing counters) and EMDASH_QUERY_LOG recording are silently dropped for Hyperdrive. The D1 request-scoped adapter and the core runtime singleton both pass kyselyLogOption().

Suggested change
const db = new Kysely<any>({ dialect: new PostgresDialect({ pool }) });
import { kyselyLogOption } from "emdash/database/instrumentation";
// ...
const db = new Kysely<any>({
dialect: new PostgresDialect({ pool }),
log: kyselyLogOption(),
});

Comment thread packages/core/src/astro/middleware.ts Outdated
scoped.close?.();
throw error;
}
scoped.commit();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[suggestion] On the success path, if scoped.commit() throws, close() is never called and a connection-backed adapter could leak the request-scoped pool. The error path handles this, but the success path does not.

Suggested change
scoped.commit();
try {
scoped.commit();
} catch (commitError) {
scoped.close?.();
throw commitError;
}
return scoped.close ? wrapResponseForScopedClose(response, scoped.close) : response;

// The singleton only runs cold-start migrations and scheduled() tasks, both
// sequential — a single connection is enough, and keeping it to 1 leaves the
// bulk of Hyperdrive's connection budget for the per-request pools.
return new PostgresDialect({ pool: createPool(binding.connectionString, 1) });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[suggestion] createDialect creates a long-lived pg.Pool attached to the isolate-cached runtime. Because workerd sockets are bound to the request that opened them, retaining this pool across HTTP requests can hit the cross-request I/O guard. The PR correctly avoids the request path, but the singleton is also used for cron and can be reached from plugin/sandbox contexts created at cold-start. Consider draining or recreating this pool outside of migrations so an idle Hyperdrive socket does not outlive the request that created it.

@github-actions github-actions Bot added review/awaiting-author Reviewed; waiting on the author to respond overlap and removed review/needs-review No maintainer or bot review yet labels Jun 24, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Overlapping PRs

This PR modifies files that are also changed by other open PRs:

This may cause merge conflicts or duplicated work. A maintainer will coordinate.

… scoped db lifecycle

Addresses review feedback on the Hyperdrive adapter:

- Pass log: kyselyLogOption() to the request-scoped Kysely so per-request
  Postgres queries are captured by db.* Server-Timing counters and
  EMDASH_QUERY_LOG, matching the D1 adapter and the runtime singleton.
- Extract finishScoped + wrapResponseForScopedClose from middleware.ts into
  astro/middleware/scoped-db.ts so the request-scoped db lifecycle is unit
  testable without the virtual:emdash/* module graph.
- Defend commit() and close() on every error/failure path in finishScoped so a
  throwing commit or teardown can neither mask the propagating error nor leak
  the connection.
- Add regression tests for stream-end close, client-disconnect close,
  bodyless/no-close paths, and the commit/close error-masking branches.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 25, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
emdash-demo-do 144abd9 Jun 25 2026, 03:13 PM

@github-actions github-actions Bot added review/needs-rereview Author pushed changes since the last review size/XL and removed size/L review/awaiting-author Reviewed; waiting on the author to respond labels Jun 25, 2026
@ascorbic ascorbic added the bot:review Trigger an emdashbot code review on this PR label Jun 25, 2026

@emdashbot emdashbot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Second pass on #1614.

The Hyperdrive adapter is still the right approach, and the three concrete gaps from the first review are resolved:

  1. Request-scoped Hyperdrive queries are now instrumented: createRequestScopedDb passes log: kyselyLogOption(), so Server-Timing counters and EMDASH_QUERY_LOG capture those queries just like D1 and the runtime singleton (#1 fixed).
  2. finishScoped now guards commit() on the success path and closes the connection if it throws, and the close/commit error paths are also guarded so exceptions there can't mask the render error (#2 fixed).
  3. There is real unit-test coverage for finishScoped and wrapResponseForScopedClose, including commit-failure, close-failure, and ordering regressions (#4 fixed).

What remains is the same cross-request socket concern (the previous #3). The per-isolate singleton connection built by hyperdrive.ts#createDialect is cached on EmDashRuntime._db and reused by the Cloudflare scheduled() handler. Because EmDashRuntime is ordinarily created during the first HTTP request, that singleton socket is opened in an HTTP-request context and is then reused from a later Cron Trigger invocation. That violates the same workerd cross-request I/O rule the adapter warns about: "a database connection … is bound to the request that opened it — it cannot be reused by a later request." The per-request pool fixes the HTTP path, but cron is not covered.

I also don't see any new AGENTS.md violations: no interpolated SQL, no unwrapped admin strings, changesets are present for both packages, and the virtual:emdash/dialect contract is updated.

I did not run the test suite, linter, or builds (no shell); I'm taking the author's reported results as unverified.

Headline conclusion: the lifecycle plumbing is now correct for HTTP requests, but the worker-lifetime singleton still leaks a connection across event boundaries and can break Cron Triggers on Hyperdrive. That should be addressed before the feature is merged.


Findings

  • [needs fixing] packages/cloudflare/src/db/hyperdrive.ts:92-97

    createDialect builds a per-isolate pg.Pool that is never drained. That pool is cached on EmDashRuntime._db and reused by the scheduled() handler. Because the runtime is usually initialized during the first HTTP request, the singleton pool's socket is opened in that request's context and later reused from a Cron Trigger invocation on the same isolate. This is exactly the cross-request I/O hazard the module header warns about ("Cannot perform I/O on behalf of a different request"). The per-request scoping fixes HTTP handlers, but the background path still needs an event-scoped connection rather than a worker-lifetime one.

  • [needs fixing] packages/core/src/emdash-runtime.ts:554-565

    runScheduledTasks routes cron/scheduled work through this.db. In a Cron Trigger there is no per-request ALS context, so this.db falls back to the singleton this._db. If the Hyperdrive singleton was created during a prior HTTP request (the normal warm-isolate case), its socket was opened in that request context; reusing it here can hang or fail under workerd's cross-request I/O guard. The background path should use a connection created inside the cron event, or the adapter should expose a way to create a fresh background-scoped DB per scheduled() invocation.

  • [suggestion] packages/core/src/astro/middleware/stream-end-metrics.ts:32

    ASTRO_COOKIES_SYMBOL is already exported from scoped-db.ts and used by middleware.ts. Defining it again here risks drift if Astro ever changes the well-known symbol. Import the shared copy instead:

    import { ASTRO_COOKIES_SYMBOL } from "./scoped-db.js";

@github-actions github-actions Bot added review/awaiting-author Reviewed; waiting on the author to respond and removed review/needs-rereview Author pushed changes since the last review labels Jun 25, 2026
…ies symbol

Second-pass review feedback on the Hyperdrive adapter:

- Document that the adapter currently supports the content read/write path
  only. The per-isolate singleton connection is captured at construction by
  the cron handler, plugin hook contexts, media providers, and the sandbox
  runner; on a warm isolate its socket belongs to an earlier request and
  workerd refuses to reuse it across events. Call this out in the hyperdrive()
  JSDoc, the adapter module header, and the changeset, and correct the prior
  comment that implied the scheduled() cron path was safe. Closing the gap
  needs the core runtime to thread an event-scoped connection through those
  subsystems, tracked separately.
- Dedupe ASTRO_COOKIES_SYMBOL: stream-end-metrics.ts now imports the shared
  copy from scoped-db.ts instead of redefining Symbol.for("astro.cookies").
@github-actions github-actions Bot added the review/needs-rereview Author pushed changes since the last review label Jun 25, 2026
@ascorbic
ascorbic merged commit b5ea8e7 into main Jun 25, 2026
45 of 46 checks passed
@ascorbic
ascorbic deleted the feat/hyperdrive-postgres-adapter branch June 25, 2026 15:24
@emdashbot emdashbot Bot mentioned this pull request Jun 25, 2026
marcusbellamyshaw-cell pushed a commit to Emdash-Bug-Testing/emdash that referenced this pull request Jul 22, 2026
* feat(cloudflare): request-scoped Hyperdrive Postgres adapter + streaming-safe scoped db close

* docs(cloudflare): recommend Smart Placement hint with hyperdrive() adapter

* chore(cloudflare): format hyperdrive adapter

* docs(cloudflare): document disabling Hyperdrive query caching for read-after-write

* fix(cloudflare): instrument request-scoped Hyperdrive queries; harden scoped db lifecycle

Addresses review feedback on the Hyperdrive adapter:

- Pass log: kyselyLogOption() to the request-scoped Kysely so per-request
  Postgres queries are captured by db.* Server-Timing counters and
  EMDASH_QUERY_LOG, matching the D1 adapter and the runtime singleton.
- Extract finishScoped + wrapResponseForScopedClose from middleware.ts into
  astro/middleware/scoped-db.ts so the request-scoped db lifecycle is unit
  testable without the virtual:emdash/* module graph.
- Defend commit() and close() on every error/failure path in finishScoped so a
  throwing commit or teardown can neither mask the propagating error nor leak
  the connection.
- Add regression tests for stream-end close, client-disconnect close,
  bodyless/no-close paths, and the commit/close error-masking branches.

* docs(cloudflare): document Hyperdrive request-path scope; dedupe cookies symbol

Second-pass review feedback on the Hyperdrive adapter:

- Document that the adapter currently supports the content read/write path
  only. The per-isolate singleton connection is captured at construction by
  the cron handler, plugin hook contexts, media providers, and the sandbox
  runner; on a warm isolate its socket belongs to an earlier request and
  workerd refuses to reuse it across events. Call this out in the hyperdrive()
  JSDoc, the adapter module header, and the changeset, and correct the prior
  comment that implied the scheduled() cron path was safe. Closing the gap
  needs the core runtime to thread an event-scoped connection through those
  subsystems, tracked separately.
- Dedupe ASTRO_COOKIES_SYMBOL: stream-end-metrics.ts now imports the shared
  copy from scoped-db.ts instead of redefining Symbol.for("astro.cookies").

* docs(cloudflare): link Hyperdrive limitation to tracking issue emdash-cms#1622

---------

Co-authored-by: Matt Kane <mkane@cloudflare.com>
marcusbellamyshaw-cell pushed a commit to Emdash-Bug-Testing/emdash that referenced this pull request Jul 22, 2026
* feat(cloudflare): request-scoped Hyperdrive Postgres adapter + streaming-safe scoped db close

* docs(cloudflare): recommend Smart Placement hint with hyperdrive() adapter

* chore(cloudflare): format hyperdrive adapter

* docs(cloudflare): document disabling Hyperdrive query caching for read-after-write

* fix(cloudflare): instrument request-scoped Hyperdrive queries; harden scoped db lifecycle

Addresses review feedback on the Hyperdrive adapter:

- Pass log: kyselyLogOption() to the request-scoped Kysely so per-request
  Postgres queries are captured by db.* Server-Timing counters and
  EMDASH_QUERY_LOG, matching the D1 adapter and the runtime singleton.
- Extract finishScoped + wrapResponseForScopedClose from middleware.ts into
  astro/middleware/scoped-db.ts so the request-scoped db lifecycle is unit
  testable without the virtual:emdash/* module graph.
- Defend commit() and close() on every error/failure path in finishScoped so a
  throwing commit or teardown can neither mask the propagating error nor leak
  the connection.
- Add regression tests for stream-end close, client-disconnect close,
  bodyless/no-close paths, and the commit/close error-masking branches.

* docs(cloudflare): document Hyperdrive request-path scope; dedupe cookies symbol

Second-pass review feedback on the Hyperdrive adapter:

- Document that the adapter currently supports the content read/write path
  only. The per-isolate singleton connection is captured at construction by
  the cron handler, plugin hook contexts, media providers, and the sandbox
  runner; on a warm isolate its socket belongs to an earlier request and
  workerd refuses to reuse it across events. Call this out in the hyperdrive()
  JSDoc, the adapter module header, and the changeset, and correct the prior
  comment that implied the scheduled() cron path was safe. Closing the gap
  needs the core runtime to thread an event-scoped connection through those
  subsystems, tracked separately.
- Dedupe ASTRO_COOKIES_SYMBOL: stream-end-metrics.ts now imports the shared
  copy from scoped-db.ts instead of redefining Symbol.for("astro.cookies").

* docs(cloudflare): link Hyperdrive limitation to tracking issue emdash-cms#1622

---------

Co-authored-by: Matt Kane <mkane@cloudflare.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/cloudflare area/core bot:review Trigger an emdashbot code review on this PR overlap review/needs-rereview Author pushed changes since the last review size/XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants