Skip to content
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
9f61ae8
docs(projects): shape cloudflare-hyperdrive-runtime project (TML-2369)
wmadden May 1, 2026
fd0a576
docs(projects): draft cloudflare-hyperdrive-runtime plan + correct st…
wmadden May 1, 2026
c9044d2
docs(projects): land cloudflare-hyperdrive-runtime M1 audit (TML-2369)
wmadden May 1, 2026
e79bc07
docs(projects): reframe cloudflare-hyperdrive-runtime around postgres…
wmadden May 1, 2026
22bed6d
docs(projects): lock postgres/serverless entrypoint shape (TML-2369)
wmadden May 1, 2026
ebe1289
feat(postgres): add postgresServerless facade for per-request runtime…
wmadden May 1, 2026
74bbbc0
feat(postgres): expose ./serverless entrypoint (TML-2369)
wmadden May 1, 2026
730900e
docs(postgres): document both facades in package README (TML-2369)
wmadden May 1, 2026
8ab2b4f
docs(projects): plan amendments from m2 R1 triage (TML-2369)
wmadden May 1, 2026
b035113
test(postgres): annotate runtime-key probe cast (TML-2369)
wmadden May 1, 2026
a21d240
docs(postgres): correct pre-existing Node-facade README drift (TML-2369)
wmadden May 1, 2026
27981e0
docs(postgres): correct pre-existing Node-facade README Dependencies …
wmadden May 1, 2026
e7b5e35
docs(postgres): relocate misplaced Node-factory prose under correct h…
wmadden May 1, 2026
b1fc6b0
docs(projects): record m3 setup decisions (prisma dev, no pgvector, v…
wmadden May 1, 2026
d549e6f
feat(examples): scaffold prisma-next-cloudflare-worker example (TML-2…
wmadden May 1, 2026
a91aa93
feat(examples): wire postgresServerless and Worker fetch handler (TML…
wmadden May 1, 2026
692dea9
feat(examples): wire local prisma dev workflow + fixtures parity (TML…
wmadden May 1, 2026
73343c4
docs(examples): write cloudflare-worker README and fix local-dev wiri…
wmadden May 1, 2026
f470470
docs(projects): renegotiate m3 local origin to Docker Postgres (TML-2…
wmadden May 1, 2026
1a50697
feat(examples): switch cloudflare-worker local origin to Docker Postg…
wmadden May 1, 2026
f17d73b
test(examples): add vitest-pool-workers integration suite (TML-2369)
wmadden May 1, 2026
de5d0dd
docs(examples): rewrite cloudflare-worker README for Docker + cold-st…
wmadden May 1, 2026
7e0e87b
examples/cloudflare-worker: prove cursor streaming via pg_stat_statem…
wmadden May 1, 2026
2b4900b
examples/cloudflare-worker: wire integration test into CI (F3)
wmadden May 1, 2026
78a1dd9
docs(adr): record ADR 207 — per-environment facade asymmetry
wmadden May 1, 2026
fa67a03
docs: add Serverless Deployment Guide (4.1, AC-14)
wmadden May 1, 2026
67b4ea2
project(cf-hyperdrive-runtime): m4 R1 Stream A close-out artifacts
wmadden May 1, 2026
b3f32c2
docs(adr): rewrite ADR 207 to lead with decision and a grounding example
wmadden May 4, 2026
ecfa1d0
project(cf-hyperdrive-runtime): mark M1-M3 + M4 Stream A complete in …
wmadden May 5, 2026
30d4c6e
project(cf-hyperdrive-runtime): add HANDOVER.md for the next maker
wmadden May 5, 2026
48df22a
project(cloudflare-hyperdrive-runtime): close out (TML-2369)
saevarb May 6, 2026
28039c3
fix(postgres-serverless): release driver if createRuntime throws afte…
saevarb May 6, 2026
0ef020a
chore(examples): regenerate cloudflare-worker contract fixture
saevarb May 6, 2026
922bb68
refactor(examples): hoist ProvidedContext type import in cloudflare-w…
saevarb May 6, 2026
dfcefd9
docs(serverless): front-load Hyperdrive cursor caveat in deployment g…
saevarb May 6, 2026
1f90ff9
fix(ci): pass Hyperdrive local connection string env var through turbo
saevarb May 6, 2026
597f1ab
Merge branch 'main' into tml-2369-ppg-add-a-hyperdrive-driver
saevarb May 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ jobs:
runs-on: ubuntu-latest
env:
TEST_TIMEOUT_MULTIPLIER: 2
# Used by examples/prisma-next-cloudflare-worker's vitest-pool-workers
# integration test. Mirrors the .env.example pattern; the container is
# brought up by `pnpm db:up` below (docker-compose, not a service
# container, because GitHub Actions service containers can't override
# the postgres CMD to enable shared_preload_libraries=pg_stat_statements).
WRANGLER_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE: postgres://postgres:postgres@127.0.0.1:5433/prisma_next_cloudflare_worker
services:
postgres:
image: postgres:15
Expand All @@ -114,6 +120,8 @@ jobs:
run: pnpm build
- name: Link bins
run: pnpm install --frozen-lockfile
- name: Start cloudflare-worker Postgres (5433, pg_stat_statements)
run: pnpm --filter prisma-next-cloudflare-worker db:up
- name: Test packages
run: pnpm test:packages
- name: Test examples
Expand Down
4 changes: 4 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ This directory contains the primary documentation for the repository.
- [Getting Started](./onboarding/Getting-Started.md) — build, test, and run the demo
- [Testing Guide](./Testing%20Guide.md) — testing philosophy and commands

## Deploying

- [Serverless Deployment Guide](./Serverless%20Deployment%20Guide.md) — deploying to per-request runtimes (Cloudflare Workers + Hyperdrive worked example, with pointers for AWS Lambda, Vercel, Deno, Bun)

## Architecture deep dives

- [ADRs](./architecture%20docs/adrs/) — decisions (append-only)
Expand Down
292 changes: 292 additions & 0 deletions docs/Serverless Deployment Guide.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/architecture docs/ADR-INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ This document provides a comprehensive index of all Architectural Decision Recor
|-----|-------|-------------|------|
| 065 | Adapter capability schema & negotiation v1 | Defines adapter capability schema and negotiation protocol | [ADR 065 - Adapter capability schema & negotiation v1.md](adrs/ADR%20065%20-%20Adapter%20capability%20schema%20&%20negotiation%20v1.md) |
| 068 | Error mapping to RuntimeError | Establishes stable mapping from engine/driver errors to RuntimeError envelope | [ADR 068 - Error mapping to RuntimeError.md](adrs/ADR%20068%20-%20Error%20mapping%20to%20RuntimeError.md) |
| 207 | Per-environment facade asymmetry | Records why `postgres()` (long-lived) and `postgresServerless()` (per-request) ship asymmetric runtime-bound surfaces — same authoring surface, different lifecycle ergonomics — and rejects AsyncLocalStorage / single-facade / per-product alternatives | [ADR 207 - Per-environment facade asymmetry.md](adrs/ADR%20207%20-%20Per-environment%20facade%20asymmetry.md) |

## Development & Tooling

Expand Down

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions examples/prisma-next-cloudflare-worker/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Local Postgres TCP URL for the Hyperdrive binding "HYPERDRIVE".
# Wrangler reads this from .env (NOT .dev.vars) for local dev. See:
# https://developers.cloudflare.com/hyperdrive/configuration/local-development
#
# Bring up the local container with `pnpm db:up` (Docker Postgres on port 5433),
# then copy this file to `.env` (gitignored). Schema/seed via:
# pnpm db:init && pnpm seed
WRANGLER_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE="postgres://postgres:postgres@127.0.0.1:5433/prisma_next_cloudflare_worker"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove quote characters in .env.example value

Line 8 includes quotes around the URL, which triggers the reported dotenv-linter QuoteCharacter warning. The value can be unquoted without changing behavior.

Suggested patch
-WRANGLER_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE="postgres://postgres:postgres@127.0.0.1:5433/prisma_next_cloudflare_worker"
+WRANGLER_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE=postgres://postgres:postgres@127.0.0.1:5433/prisma_next_cloudflare_worker
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
WRANGLER_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE="postgres://postgres:postgres@127.0.0.1:5433/prisma_next_cloudflare_worker"
WRANGLER_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE=postgres://postgres:postgres@127.0.0.1:5433/prisma_next_cloudflare_worker
🧰 Tools
🪛 dotenv-linter (4.0.0)

[warning] 8-8: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/prisma-next-cloudflare-worker/.env.example` at line 8, Remove the
surrounding double quotes from the environment variable value in .env.example
for WRANGLER_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE so the line reads
WRANGLER_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE=postgres://postgres:postgres@127.0.0.1:5433/prisma_next_cloudflare_worker;
this eliminates the dotenv-linter QuoteCharacter warning while preserving the
same connection string.

7 changes: 7 additions & 0 deletions examples/prisma-next-cloudflare-worker/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules
dist
.wrangler
.env
.env.local
*.tsbuildinfo
.turbo
162 changes: 162 additions & 0 deletions examples/prisma-next-cloudflare-worker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# prisma-next-cloudflare-worker

End-to-end example for the `@prisma-next/postgres/serverless` facade, running on a Cloudflare Worker against a Hyperdrive-fronted Postgres origin.

This example mirrors `examples/prisma-next-demo` (the Node demo), minus pgvector — the Worker example exists to exercise the per-request `postgresServerless` lifecycle, not vector search.

## What this example demonstrates

- **Module-scope `db`** built once per isolate via `postgresServerless<Contract>({ contractJson, middleware })`.
- **Per-request `runtime`** via `await using runtime = await db.connect({ url: env.HYPERDRIVE.connectionString })`. The `[Symbol.asyncDispose]` ensures the underlying `pg.Client` is `end()`-ed when the `fetch` handler returns.
- **All three query surfaces** through `Runtime`:
- SQL DSL: `runtime.execute(db.sql.user.select(...).build())`
- ORM client: `createOrmClient(runtime).User.newestFirst().take(10).all()`
- Transactions: `withTransaction(runtime, async (tx) => …)`
- **Cursor early-break** over a streamed result set (`for await … break`), exercising the cursor path that `postgresServerless` enables by default.

Routes implemented in [`src/worker.ts`](src/worker.ts):

| Route | Surface | Notes |
| ------------------- | ----------------- | -------------------------------------------------------- |
| `GET /health` | — | DB-free liveness check |
| `GET /sql/users` | SQL DSL | `db.sql.user.select(...).limit(?)` |
| `GET /orm/users` | ORM client | `User.newestFirst().take(?)` |
| `GET /orm/posts` | ORM client | `Post.forUser(?).orderBy(...).take(?)` |
| `GET /tx/commit` | `withTransaction` | INSERT post + UPDATE user atomically |
| `GET /tx/rollback` | `withTransaction` | Throws inside the body; verifies ROLLBACK propagates |
| `GET /cursor/large` | Cursor stream | `for await … break` after N rows; cursor cancels cleanly |

## Layout

```
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add language identifiers to fenced code blocks.

Both fences are missing a language tag (text is fine), which triggers markdownlint MD040.

🛠️ Proposed fix
-```
+```text
 examples/prisma-next-cloudflare-worker/
 ...

- +text
Total Upload: 1289.96 KiB / gzip: 254.14 KiB

Also applies to: 103-103

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 31-31: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/prisma-next-cloudflare-worker/README.md` at line 31, The README.md
has two fenced code blocks missing a language identifier (triggering
markdownlint MD040); update both code fences referenced in the diff (the example
directory listing block and the "Total Upload" block) to include a language tag
such as "text" (i.e., replace the opening triple backticks with ```text for
those two blocks) so the blocks are properly annotated for markdownlint.

examples/prisma-next-cloudflare-worker/
├── prisma/schema.prisma # Demo schema minus pgvector
├── src/
│ ├── worker.ts # `fetch` handler — all routes
│ ├── prisma/db.ts # Module-scope postgresServerless client
│ ├── prisma/contract.{json,d.ts} # Emitted by `pnpm emit`
│ └── orm-client/ # ORM extensions (collections + factory)
├── scripts/
│ ├── setup-schema.ts # `prisma-next db init`
│ └── seed.ts # Insert sample users + posts
├── test/
│ ├── global-setup.ts # Connects to Docker Postgres, applies schema, seeds
│ ├── worker.integration.test.ts # vitest-pool-workers integration suite
│ └── cloudflare-test.d.ts # Pulls in `cloudflare:test` ambient types
├── docker-compose.yml # Local Postgres origin (port 5433)
├── wrangler.jsonc # Hyperdrive binding declaration
├── prisma-next.config.ts # Contract emit config
├── vitest.config.ts # cloudflareTest plugin + globalSetup
└── .env.example # Copy → .env (Hyperdrive local URL)
```

## Setup (local development)

### Prerequisites

- Node satisfying the root `package.json` `engines.node` (`>=24`).
- `pnpm`. Install workspace deps from the repo root with `pnpm install`.
- `docker` + `docker compose` (Docker Desktop, OrbStack, Colima, or Rancher Desktop). The local Postgres origin runs in a container — see [why not `prisma dev`](#why-not-prisma-dev) below.

### One-time bootstrap

```bash
cd examples/prisma-next-cloudflare-worker
pnpm emit # generate src/prisma/contract.{json,d.ts}
cp .env.example .env # gitignored
```

`.env` ships preset to the docker-compose URL (`postgres://postgres:postgres@127.0.0.1:5433/prisma_next_cloudflare_worker`). Wrangler reads `WRANGLER_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE` to populate the `HYPERDRIVE` binding's local connection string ([Cloudflare docs](https://developers.cloudflare.com/hyperdrive/configuration/local-development)). Note: this goes in **`.env`**, not `.dev.vars` — `.dev.vars` is for runtime worker secrets, not Wrangler configuration. The `WRANGLER_*` prefix is being deprecated in favour of `CLOUDFLARE_*` in newer Wrangler; either works as of `wrangler@4.87`.

### Per-session: bring up Postgres, init schema, seed

```bash
pnpm db:up # docker compose up -d --wait (postgres:16 on :5433)
pnpm db:init # prisma-next db init → CREATE TABLE …
pnpm seed # Insert Alice + Bob + 50 posts
```
Comment on lines +74 to +77
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix seeded post-count in setup docs.

Line 76 says seed inserts 50 posts, but examples/prisma-next-cloudflare-worker/scripts/seed.ts currently inserts 8 total (5 Alice, 3 Bob).

🛠️ Proposed fix
-pnpm seed                        # Insert Alice + Bob + 50 posts
+pnpm seed                        # Insert Alice + Bob + 8 posts
As per coding guidelines `**/*.md`: Keep docs current (READMEs, rules, links) as defined in `.cursor/rules/doc-maintenance.mdc`.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/prisma-next-cloudflare-worker/README.md` around lines 74 - 77, The
README example incorrectly states the seed script inserts 50 posts; update the
docs to reflect the actual seeded count from
examples/prisma-next-cloudflare-worker/scripts/seed.ts (which inserts 8 posts
total: 5 for Alice and 3 for Bob) by changing the "pnpm seed" description to
"Insert Alice + Bob + 8 posts" (or equivalent wording listing 5 Alice, 3 Bob) so
the README matches the seed.ts behavior.


Tear down with `pnpm db:down` (drops the container + volume — data is `tmpfs`-backed for fast restarts), or `pnpm db:reset` to do everything in one command.

### Run the Worker locally

```bash
pnpm dev # wrangler dev → http://localhost:8787
curl http://localhost:8787/health
curl http://localhost:8787/orm/users?limit=5
```

## Deploy

`wrangler.jsonc` carries a placeholder Hyperdrive `id` (`00000000…`). To deploy to a real Cloudflare account, provision a Hyperdrive config first:

```bash
pnpm exec wrangler hyperdrive create my-hyperdrive --connection-string="postgres://…"
# Replace the "id" in wrangler.jsonc with the printed binding id.
pnpm run deploy
```

> Use `pnpm run deploy` (not `pnpm deploy`). The latter collides with pnpm's built-in `deploy` command and fails with `ERR_PNPM_INVALID_DEPLOY_TARGET`.

> If your origin sits behind Cloudflare Hyperdrive, also pass `cursor: { disabled: true }` to `postgresServerless({...})` in `src/prisma/db.ts`. Hyperdrive currently rejects the `Close portal` message that `pg-cursor` (the default streaming path) sends after an extended-query Execute, leaving the connection wedged. See the deployment guide's "Known limitations" for details.
Comment thread
saevarb marked this conversation as resolved.

## Bundle size

`pnpm deploy:dry-run` (`wrangler deploy --dry-run --outdir dist`) reports:

```
Total Upload: 1289.96 KiB / gzip: 254.14 KiB
```

(254 KiB compressed, well under the 1 MB AC-19 budget.)

The bundle includes `pg`, `pg-protocol`, `pg-types`, `pg-cursor`, `pg-pool` (statically imported by `@prisma-next/driver-postgres` even though `postgresServerless` does not construct a `Pool` at runtime), `pg-cloudflare` (auto-pulled by `pg` when `navigator.userAgent === 'Cloudflare-Workers'`), and `@cloudflare/unenv-preset` polyfills.

## Cold-start benchmark (AC-20 / TC-23)

Best-effort `wrangler dev` benchmark against the local Docker Postgres origin (`GET /orm/users?limit=10`):

| Run | Latency |
| ---------------------- | -------- |
| Cold start (run 0) | ~35 ms |
| Warm p50 (runs 1–5) | ~13 ms |

Both well inside the 200 ms ceiling in AC-20. Production cold-start over a real Hyperdrive will be slower (TLS handshake, region-vs-origin RTT) — re-measure during M4 deployment validation.

## Integration tests (`vitest-pool-workers`)

The suite under `test/` boots the Worker under `workerd` via `vitest-pool-workers`, points the Hyperdrive binding at the local Docker Postgres, and exercises the SQL DSL, ORM, transactions, and cursor early-break paths.

```bash
pnpm db:up # ensure container is running
pnpm test # vitest run --config vitest.config.ts
```

The test's `globalSetup` (`test/global-setup.ts`) reads `.env`, asserts the container is reachable, applies the schema (idempotent — uses the same `prisma-next db init` as the dev workflow), truncates and reseeds. There is no per-test isolation: the suite is read-mostly, the `/tx/commit` test mutates `Bob`'s display name and the next test's reseed restores it on the next `pnpm test`.

The canonical workspace invocation is `pnpm test:examples --filter prisma-next-cloudflare-worker` from the repo root (depends on the container being up — that's a local-dev precondition, not a CI one).

### `pg` resolution under Vite 8

`vitest.config.ts` includes a `test.deps.optimizer.ssr.{include, rolldownOptions.external}` workaround for [`cloudflare/workers-sdk#12984`](https://github.com/cloudflare/workers-sdk/issues/12984), which mis-resolves `pg`'s dual ESM/CJS exports under Vite 8 when loaded by `vitest-pool-workers`. Pre-bundling `pg`/`pg-protocol`/`pg-cursor`/`pg-cloudflare` and externalising Node built-ins keeps `workerd`'s loader on the right entries.

### Why not `prisma dev`?

The first attempt at the local origin used `@prisma/dev` (PGlite-backed Postgres reachable over TCP) — same pattern as `examples/prisma-next-demo` for everything else. It hung in both `wrangler dev` and `vitest-pool-workers`: every DB-touching route would call `pg.Client.connect()` through miniflare's Hyperdrive emulator, the `pg-cloudflare` socket reported "Connection terminated unexpectedly", and the runtime never recovered. The hang reproduces in plain `wrangler dev`, so it's not a test-infra problem — it appears to be specific to PGlite's TCP shim interacting with `pg-cloudflare`'s socket layer in `workerd`. The third sub-issue in [`cloudflare/workers-sdk#12984`](https://github.com/cloudflare/workers-sdk/issues/12984) ("Cannot perform I/O on behalf of a different Durable Object") may be the same root cause; upstream PR #13062 covers the bundling regressions but not this one.

The M1 audit's "this works in `wrangler dev`" claim was empirically validated against a real Postgres on `localhost`, not against `prisma dev` — so the audit's conclusion still holds for real-Postgres origins. M3 uses Docker Postgres for that reason. The PPg-on-Workers story will pick back up in M4 against a real deployed Hyperdrive + PPg.

## Troubleshooting

- **`pnpm db:up` fails with `Cannot connect to the Docker daemon`.** Start your container runtime (Docker Desktop, OrbStack, …) and retry.
- **`pnpm db:init` fails with a connection error.** Confirm `pnpm db:up` succeeded and the container is healthy: `docker compose ps`. Port 5433 (not 5432) — port collision with `examples/prisma-next-demo`'s Postgres.app would surface here.
- **`wrangler dev` boots but `/orm/users` returns `500 / connection error`.** The container probably stopped (or you forgot `pnpm db:up`). `pnpm db:reset` brings everything back from a clean slate.
- **Bundle includes `pg-cloudflare` even though I'm running on Node.** Expected — `pg` static-imports `pg-cloudflare` via `lib/stream.js`, and runtime detection (`navigator.userAgent === 'Cloudflare-Workers'`) picks the right socket implementation.

## Known limitations

- **Transaction affinity** — every `withTransaction` body must run on the same `runtime` instance (the per-request one). Crossing `runtime` boundaries inside a transaction body is undefined.
- **Isolate memory** — large result sets bound through cursor by default (`postgresServerless` enables cursor unconditionally). For ORM `findMany`-style operations the result set is materialised; size your `take(...)` accordingly.
- **`pg.Pool` not used** — the serverless facade routes through `PostgresDirectDriverImpl` (`pgClient` binding kind). No connection pooling within the isolate; that's Hyperdrive's job in production.
- **Production `id`** — the committed `wrangler.jsonc` has a zero-stuffed Hyperdrive `id`. Deploy will fail until a real id is wired in (M4).
- **Class-table-inheritance ORM queries** — the schema declares `Bug` and `Feature` as `@@base(Task)` discriminator variants for parity with `examples/prisma-next-demo`, but `Task.take(...)` (and `Task.bugs()` / `Task.features()`) currently fail with `column "bug.id" does not exist` against the generated SQL. Pre-existing framework drift surfaced during M3 R2; not exercised by the integration test. The `User` and `Post` collections work normally.
4 changes: 4 additions & 0 deletions examples/prisma-next-cloudflare-worker/biome.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"$schema": "https://biomejs.dev/schemas/2.3.11/schema.json",
"extends": "//"
}
31 changes: 31 additions & 0 deletions examples/prisma-next-cloudflare-worker/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Local Postgres origin for the Cloudflare Worker example.
#
# Port 5433 (not the default 5432) so this doesn't clash with
# `examples/prisma-next-demo`'s Postgres.app expectation on the standard port.
#
# Bring it up with `pnpm db:up`. Schema/seed via `pnpm db:init && pnpm seed`.
# The matching connection string for `.env` is in `.env.example`.
services:
postgres:
image: postgres:16
container_name: prisma-next-cloudflare-worker-pg
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: prisma_next_cloudflare_worker
# pg_stat_statements lets the cursor integration test assert how many
# rows the server transmitted per logical statement — the only signal
# that distinguishes cursor-streamed from buffered execution from the
# test side. Loaded in shared_preload_libraries here so the extension
# can be CREATEd in test/global-setup.ts.
command: postgres -c shared_preload_libraries=pg_stat_statements
ports:
- '5433:5432'
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U postgres -d prisma_next_cloudflare_worker']
interval: 1s
timeout: 3s
retries: 30
tmpfs:
# Keep data ephemeral (faster restarts; tests are seed-from-empty anyway).
- /var/lib/postgresql/data
54 changes: 54 additions & 0 deletions examples/prisma-next-cloudflare-worker/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"name": "prisma-next-cloudflare-worker",
"private": true,
"type": "module",
"engines": {
"node": ">=24"
},
"scripts": {
"emit": "prisma-next contract emit",
"emit:check": "pnpm emit && git diff --exit-code src/prisma/contract.json src/prisma/contract.d.ts",
"db:up": "docker compose up -d --wait",
"db:down": "docker compose down -v",
"db:reset": "pnpm db:down && pnpm db:up && pnpm db:init && pnpm seed",
"db:init": "tsx scripts/setup-schema.ts",
"seed": "tsx scripts/seed.ts",
"dev": "wrangler dev",
"deploy": "wrangler deploy",
"deploy:dry-run": "wrangler deploy --dry-run --outdir dist",
"test": "vitest run --config vitest.config.ts",
"typecheck": "tsc --project tsconfig.json --noEmit",
"lint": "biome check . --error-on-warnings"
},
"dependencies": {
"@prisma-next/adapter-postgres": "workspace:*",
"@prisma-next/contract": "workspace:*",
"@prisma-next/driver-postgres": "workspace:*",
"@prisma-next/family-sql": "workspace:*",
"@prisma-next/middleware-telemetry": "workspace:*",
"@prisma-next/postgres": "workspace:*",
"@prisma-next/sql-builder": "workspace:*",
"@prisma-next/sql-contract": "workspace:*",
"@prisma-next/sql-orm-client": "workspace:*",
"@prisma-next/sql-relational-core": "workspace:*",
"@prisma-next/sql-runtime": "workspace:*",
"@prisma-next/target-postgres": "workspace:*",
"arktype": "catalog:",
"pg": "catalog:"
},
"devDependencies": {
"@cloudflare/vitest-pool-workers": "0.15.2",
"@cloudflare/workers-types": "4.20260430.1",
"@prisma-next/cli": "workspace:*",
"@prisma-next/sql-contract-psl": "workspace:*",
"@prisma-next/test-utils": "workspace:*",
"@prisma-next/tsconfig": "workspace:*",
"@types/node": "catalog:",
"@types/pg": "catalog:",
"dotenv": "^16.4.5",
"tsx": "^4.19.2",
"typescript": "catalog:",
"vitest": "^4.1.0",
"wrangler": "4.87.0"
}
}
22 changes: 22 additions & 0 deletions examples/prisma-next-cloudflare-worker/prisma-next.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import 'dotenv/config';
import postgresAdapter from '@prisma-next/adapter-postgres/control';
import { defineConfig } from '@prisma-next/cli/config-types';
import postgresDriver from '@prisma-next/driver-postgres/control';
import sql from '@prisma-next/family-sql/control';
import { prismaContract } from '@prisma-next/sql-contract-psl/provider';
import postgres from '@prisma-next/target-postgres/control';

export default defineConfig({
family: sql,
target: postgres,
driver: postgresDriver,
adapter: postgresAdapter,
contract: prismaContract('./prisma/schema.prisma', {
output: 'src/prisma/contract.json',
target: postgres,
}),
db: {
// biome-ignore lint/style/noNonNullAssertion: loaded from .env
connection: process.env['DATABASE_URL']!,
},
});
Loading
Loading