Skip to content

TML-2955: A client-safe static surface — @prisma-next/<target>/static#888

Open
wmadden-electric wants to merge 11 commits into
mainfrom
slice/expose-static-execution-context
Open

TML-2955: A client-safe static surface — @prisma-next/<target>/static#888
wmadden-electric wants to merge 11 commits into
mainfrom
slice/expose-static-execution-context

Conversation

@wmadden-electric

@wmadden-electric wmadden-electric commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

At a glance

You can now use a contract's enums, query builder, and generated types in a 'use client' component — with no database driver in the browser bundle:

'use client';
import mongoStatic from '@prisma-next/mongo/static';
import contractJson from './contract.json' with { type: 'json' };
import type { Contract } from './contract';

const { enums } = mongoStatic<Contract>({ contractJson });

export function OrderTypePicker() {
  // fully typed from the contract — enums.OrderType.members.Delivery, .Pickup, …
  return <RadioGroup options={Object.values(enums.OrderType.members)} />;
}

The same call shape exists on every target (postgresStatic, sqliteStatic), and the same object is exposed on a connected client as db.context / db.contract.

The decision

Expose the ExecutionContext as a first-class, client-safe surface — a new @prisma-next/<target>/static entrypoint — symmetrically on all three target facades.

The ExecutionContext is the driver-free core every query is built against: the contract, its codecs, the query operations, and the derived types. Enums, the query builder, and raw are all just views over it. It needs no connection and no driver to construct — so in principle it's usable anywhere, including the browser. This PR makes that real and uniform.

Why it wasn't already usable

The context existed but you couldn't get at it cleanly from client code:

  • Postgres built it upfront and exposed it as db.context — but only on a fully-wired, driver-carrying client.
  • Mongo built the equivalent lazily inside the connect path, never exposed it, and typed its contract as unknown.
  • There was no driver-free entrypoint on any target, so importing the facade to reach enums also imported the DB driver.

So when an app needed typed enums in a 'use client' form, it fell back to an interim: hand-calling the low-level buildNamespacedEnums(...) and casting the untyped result in application code. That worked but was a narrow, per-consumer workaround, not the abstraction.

What this PR does

  • Adds @prisma-next/<target>/static with <target>Static({ contractJson }), returning the ExecutionContext plus the surface derived from it (enums, query builder, raw, contract). It's driver-free by construction, and a test walks the entrypoint's import graph to keep it that way.
  • Builds the Mongo context upfront, types it MongoExecutionContext<TContract>, and exposes db.context / db.contract — matching Postgres, so the shape is the same across targets.
  • Routes each facade and its /static twin through one shared builder, so the enum typing lives in framework code once instead of a cast in every app.
  • Migrates examples/retail-store off the interim: src/enums.ts now derives from mongoStatic(...), consumed by the 'use client' checkout form — which doubles as the next build "no driver in the client bundle" acceptance test.

One cross-cutting change worth a look

Making the static context truly driver-free reached one layer deeper than the facades. Building the context aggregates the target's codecs, and the Mongo codec imported ObjectId from mongodb (a value import), which drags the whole driver into a client bundle. ObjectId is really a bson class that mongodb re-exports, so the codec now imports it from the standalone bson package. It's a one-line change but it lives in packages/3-mongo-target/2-mongo-adapter, and it's what lets next build succeed with zero driver code client-side.

Extension packs (postgis, pgvector, …) are unaffected: the facade still builds its context from the full stack including options.extensions; only the client-safe /static path is target+adapter-only.

Testing

Full local gate green (build, typecheck, lint incl. lint:deps/lint:casts, check:upgrade-coverage, fixtures:check, test:packages/integration/e2e) and CI green. retail-store next build produces no mongodb in the client bundle. Upgrade instructions recorded as additive/incidental for 0.14→0.15.

Alternatives considered

  • Keep the app-code interim (buildNamespacedEnums + a cast). Rejected: untyped without a per-call cast, duplicated per consumer, and it leaks a framework detail into every app.
  • An enums-only helper — the mongoEnums / @prisma-next/mongo/enums point-solution prototyped in Exercise Mongo enums in retail-store; add raw/execute/mongoEnums to the Mongo client #880 and pulled back out. Rejected: it solved one symptom (enums) rather than exposing the abstraction they derive from. Exposing the whole ExecutionContext gives enums, query building, raw, and types from one surface, symmetrically.
  • Make the existing /runtime entrypoint tree-shakeable instead of adding /static. Rejected: the driver is imported at module scope, so bundlers can't reliably drop it. A separate driver-free module is a hard boundary — and the client-safety test enforces it.

Spec: projects/expose-static-execution-context/spec.md. Closes TML-2955.

🤖 Generated with Claude Code

@wmadden-electric wmadden-electric requested a review from a team as a code owner June 29, 2026 13:38
@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@wmadden-electric, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 4 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 0f19fdd4-e591-4704-b39c-2faec1ac7f9e

📥 Commits

Reviewing files that changed from the base of the PR and between d987376 and e6a3e03.

⛔ Files ignored due to path filters (3)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • projects/expose-static-execution-context/plan.md is excluded by !projects/**
  • projects/expose-static-execution-context/spec.md is excluded by !projects/**
📒 Files selected for processing (36)
  • examples/retail-store/src/enums.ts
  • packages/2-mongo-family/7-runtime/src/mongo-execution-stack.ts
  • packages/2-mongo-family/7-runtime/test/mongo-execution-stack.test.ts
  • packages/3-extensions/mongo/package.json
  • packages/3-extensions/mongo/src/exports/static.ts
  • packages/3-extensions/mongo/src/runtime/mongo.ts
  • packages/3-extensions/mongo/src/static/mongo-static.ts
  • packages/3-extensions/mongo/test/mongo.static.client-safety.test.ts
  • packages/3-extensions/mongo/test/mongo.static.test.ts
  • packages/3-extensions/mongo/test/mongo.test.ts
  • packages/3-extensions/mongo/test/mongo.types.test-d.ts
  • packages/3-extensions/mongo/tsdown.config.ts
  • packages/3-extensions/postgres/package.json
  • packages/3-extensions/postgres/src/exports/static.ts
  • packages/3-extensions/postgres/src/runtime/postgres.ts
  • packages/3-extensions/postgres/src/static/postgres-static.ts
  • packages/3-extensions/postgres/src/static/postgres-surface.ts
  • packages/3-extensions/postgres/test/postgres.extensions.test.ts
  • packages/3-extensions/postgres/test/postgres.static.client-safety.test.ts
  • packages/3-extensions/postgres/test/postgres.static.test.ts
  • packages/3-extensions/postgres/test/postgres.test.ts
  • packages/3-extensions/postgres/tsdown.config.ts
  • packages/3-extensions/sqlite/package.json
  • packages/3-extensions/sqlite/src/exports/static.ts
  • packages/3-extensions/sqlite/src/runtime/sqlite.ts
  • packages/3-extensions/sqlite/src/static/sqlite-static.ts
  • packages/3-extensions/sqlite/src/static/sqlite-surface.ts
  • packages/3-extensions/sqlite/test/sqlite.extensions.test.ts
  • packages/3-extensions/sqlite/test/sqlite.static.client-safety.test.ts
  • packages/3-extensions/sqlite/test/sqlite.static.test.ts
  • packages/3-extensions/sqlite/tsdown.config.ts
  • packages/3-mongo-target/2-mongo-adapter/package.json
  • packages/3-mongo-target/2-mongo-adapter/src/core/codecs.ts
  • packages/3-mongo-target/2-mongo-adapter/test/codecs.test.ts
  • skills/extension-author/prisma-next-extension-upgrade/upgrades/0.14-to-0.15/instructions.md
  • skills/upgrade/prisma-next-upgrade/upgrades/0.14-to-0.15/instructions.md
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch slice/expose-static-execution-context

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Captures the design for surfacing the execution-plane ExecutionContext
(contract + codecs + operations + types, driver-free) symmetrically on the
Mongo and Postgres facades: build it upfront, expose db.context, type
MongoExecutionContext<TContract>, and offer a client-safe per-target static
factory that supersedes the interim mongoEnums/@prisma-next/mongo/enums
shipped in PR #880. Planning artifact only; no code changes.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
The interim mongoEnums/@prisma-next/mongo/enums prototype was stripped from
#880; the example now uses buildNamespacedEnums + a blindCast. Reword the spec
so the slice replaces that example-level interim rather than retiring a shipped
framework surface.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…dispatch plan

The named consumer (retail-store/src/enums.ts) never existed on main and
#880's enum machinery was pulled, so step 4 becomes "add a fresh client
consumer" and the real blindCast leak (in the facades) is folded in. Adds a
three-dispatch plan grounding the entrypoint + driverless-context boundaries.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…isma-next/mongo/static

Type MongoExecutionContext<TContract> (was contract: unknown), build it once
upfront from the driver-free stack, reuse it in buildRuntime, and expose it as
db.context. Add a client-safe @prisma-next/mongo/static entrypoint whose
mongoStatic({contractJson}) returns { context, contract, enums, query }; the
facade and the static path share one buildMongoStaticContext, removing the
per-facade enum blindCast. A source import-graph test asserts the /static graph
pulls in no mongodb/driver-mongo.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…se db.contract

Mirror the Mongo static surface on the SQL side. Add driver-free
buildPostgres/SqliteStaticContext builders (adapter-only stack, no driver
import) exposed via @prisma-next/<target>/static as postgresStatic/sqliteStatic
returning { context, contract, enums, sql, raw }. The facades now derive their
static surface through the shared builder and expose readonly contract, removing
the per-facade enum blindCast. Source import-graph tests assert the /static
graphs pull in no pg/@prisma-next/driver-* packages. Building the context from a
driverless stack is behaviour-preserving: the facades never passed the driver as
a capability source to createExecutionContext.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Reconcile #880 (raw/execute on the Mongo facade + retail-store enums) with the
static-ExecutionContext work: the merged MongoClient exposes orm, query, raw,
contract, enums, context, and execute. enums/query/context come from the shared
buildMongoStaticContext; raw/execute are kept from #880. Mongo suites green
(108 + 174 tests).

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…s driver-free

The mongo adapter codec value-imported ObjectId from mongodb, so building the
ExecutionContext (mongoStatic) dragged the full driver into the client bundle —
next build of retail-store failed with 19 errors. ObjectId is a bson class that
mongodb re-exports; import it from the standalone browser-safe bson package
instead. The client-safety tests previously passed vacuously (off-by-one ROOT so
the graph walk read nothing); rewrite the walk to traverse workspace packages and
distinguish value from `import type`, catching this leak (red before, green
after) for all three targets.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…drop the blindCast

Reduce src/enums.ts to a single framework-typed derivation via mongoStatic,
removing the interim buildNamespacedEnums + blindCast (TML-2955 step 5). The
`use client` checkout-form consumes it, so this is the next-build client-safety
acceptance path. Reconcile the spec with what actually shipped.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
… extensions survive

The facades sourced db.context from the client-safe static builder (target +
adapter only), so options.extensions never reached the context and
createExecutionContext threw RUNTIME.MISSING_EXTENSION_PACK for any app using an
extension pack (postgis/pgvector/paradedb demos all broke). Split out a shared
surface helper (enums/sql/raw from an already-built context) so the enum cast
stays centralized, and have each facade build its own context from its full
stack (target + adapter + driver-as-capability-source + options.extensions). The
/static entrypoints keep their target+adapter-only, driver-free stack. Adds
extension-pack facade tests (red before, green after).

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…or 0.14→0.15

Additive client-safe static entrypoints + db.context/db.contract on the facades,
and the internal mongo-adapter ObjectId→bson change. No user or extension-author
action required; recorded as incidental per the per-pr-declaration check.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…ort shapes

The walk stopped at object-form exports and dist/exports/ layouts (silently
dropping e.g. mongo-query-ast) and missed require()/dynamic import(), so its
driver-free guarantee was weaker than claimed. Resolve object-condition exports,
map dist/exports/<name> back to source, and match require/await-import. Add a
vacuous-walk guard (files.size > 100) so a zero-file walk can never pass silently
again. mongo 115->127, postgres 257->317, sqlite 161->184 files walked; still no
driver reachable.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
@wmadden-electric wmadden-electric force-pushed the slice/expose-static-execution-context branch from c31d3e7 to e6a3e03 Compare July 1, 2026 09:45
@wmadden-electric wmadden-electric changed the title Orphan slice: expose the static execution context symmetrically TML-2955: Expose the static ExecutionContext symmetrically via client-safe @prisma-next/<target>/static Jul 1, 2026
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown

size-limit report 📦

Path Size
postgres / no-emit 160.5 KB (+0.1% 🔺)
postgres / emit 147.73 KB (+0.13% 🔺)
mongo / no-emit 96.22 KB (+20.49% 🔺)
mongo / emit 88.91 KB (+22.33% 🔺)
cf-worker / no-emit 188.11 KB (0%)
cf-worker / emit 173.57 KB (0%)

@pkg-pr-new

pkg-pr-new Bot commented Jul 1, 2026

Copy link
Copy Markdown

Open in StackBlitz

@prisma-next/extension-author-tools

npm i https://pkg.pr.new/@prisma-next/extension-author-tools@888

@prisma-next/mongo-runtime

npm i https://pkg.pr.new/@prisma-next/mongo-runtime@888

@prisma-next/family-mongo

npm i https://pkg.pr.new/@prisma-next/family-mongo@888

@prisma-next/sql-runtime

npm i https://pkg.pr.new/@prisma-next/sql-runtime@888

@prisma-next/family-sql

npm i https://pkg.pr.new/@prisma-next/family-sql@888

@prisma-next/extension-arktype-json

npm i https://pkg.pr.new/@prisma-next/extension-arktype-json@888

@prisma-next/middleware-cache

npm i https://pkg.pr.new/@prisma-next/middleware-cache@888

@prisma-next/mongo

npm i https://pkg.pr.new/@prisma-next/mongo@888

@prisma-next/extension-paradedb

npm i https://pkg.pr.new/@prisma-next/extension-paradedb@888

@prisma-next/extension-pgvector

npm i https://pkg.pr.new/@prisma-next/extension-pgvector@888

@prisma-next/extension-postgis

npm i https://pkg.pr.new/@prisma-next/extension-postgis@888

@prisma-next/postgres

npm i https://pkg.pr.new/@prisma-next/postgres@888

@prisma-next/sql-orm-client

npm i https://pkg.pr.new/@prisma-next/sql-orm-client@888

@prisma-next/sqlite

npm i https://pkg.pr.new/@prisma-next/sqlite@888

@prisma-next/extension-supabase

npm i https://pkg.pr.new/@prisma-next/extension-supabase@888

@prisma-next/target-mongo

npm i https://pkg.pr.new/@prisma-next/target-mongo@888

@prisma-next/adapter-mongo

npm i https://pkg.pr.new/@prisma-next/adapter-mongo@888

@prisma-next/driver-mongo

npm i https://pkg.pr.new/@prisma-next/driver-mongo@888

@prisma-next/contract

npm i https://pkg.pr.new/@prisma-next/contract@888

@prisma-next/utils

npm i https://pkg.pr.new/@prisma-next/utils@888

@prisma-next/config

npm i https://pkg.pr.new/@prisma-next/config@888

@prisma-next/errors

npm i https://pkg.pr.new/@prisma-next/errors@888

@prisma-next/framework-components

npm i https://pkg.pr.new/@prisma-next/framework-components@888

@prisma-next/operations

npm i https://pkg.pr.new/@prisma-next/operations@888

@prisma-next/ts-render

npm i https://pkg.pr.new/@prisma-next/ts-render@888

@prisma-next/contract-authoring

npm i https://pkg.pr.new/@prisma-next/contract-authoring@888

@prisma-next/ids

npm i https://pkg.pr.new/@prisma-next/ids@888

@prisma-next/psl-parser

npm i https://pkg.pr.new/@prisma-next/psl-parser@888

@prisma-next/psl-printer

npm i https://pkg.pr.new/@prisma-next/psl-printer@888

@prisma-next/cli

npm i https://pkg.pr.new/@prisma-next/cli@888

@prisma-next/cli-telemetry

npm i https://pkg.pr.new/@prisma-next/cli-telemetry@888

@prisma-next/config-loader

npm i https://pkg.pr.new/@prisma-next/config-loader@888

@prisma-next/emitter

npm i https://pkg.pr.new/@prisma-next/emitter@888

@prisma-next/language-server

npm i https://pkg.pr.new/@prisma-next/language-server@888

@prisma-next/migration-tools

npm i https://pkg.pr.new/@prisma-next/migration-tools@888

prisma-next

npm i https://pkg.pr.new/prisma-next@888

@prisma-next/vite-plugin-contract-emit

npm i https://pkg.pr.new/@prisma-next/vite-plugin-contract-emit@888

@prisma-next/mongo-codec

npm i https://pkg.pr.new/@prisma-next/mongo-codec@888

@prisma-next/mongo-contract

npm i https://pkg.pr.new/@prisma-next/mongo-contract@888

@prisma-next/mongo-value

npm i https://pkg.pr.new/@prisma-next/mongo-value@888

@prisma-next/mongo-contract-psl

npm i https://pkg.pr.new/@prisma-next/mongo-contract-psl@888

@prisma-next/mongo-contract-ts

npm i https://pkg.pr.new/@prisma-next/mongo-contract-ts@888

@prisma-next/mongo-emitter

npm i https://pkg.pr.new/@prisma-next/mongo-emitter@888

@prisma-next/mongo-schema-ir

npm i https://pkg.pr.new/@prisma-next/mongo-schema-ir@888

@prisma-next/mongo-query-ast

npm i https://pkg.pr.new/@prisma-next/mongo-query-ast@888

@prisma-next/mongo-orm

npm i https://pkg.pr.new/@prisma-next/mongo-orm@888

@prisma-next/mongo-query-builder

npm i https://pkg.pr.new/@prisma-next/mongo-query-builder@888

@prisma-next/mongo-lowering

npm i https://pkg.pr.new/@prisma-next/mongo-lowering@888

@prisma-next/mongo-wire

npm i https://pkg.pr.new/@prisma-next/mongo-wire@888

@prisma-next/sql-contract

npm i https://pkg.pr.new/@prisma-next/sql-contract@888

@prisma-next/sql-errors

npm i https://pkg.pr.new/@prisma-next/sql-errors@888

@prisma-next/sql-operations

npm i https://pkg.pr.new/@prisma-next/sql-operations@888

@prisma-next/sql-schema-ir

npm i https://pkg.pr.new/@prisma-next/sql-schema-ir@888

@prisma-next/sql-contract-psl

npm i https://pkg.pr.new/@prisma-next/sql-contract-psl@888

@prisma-next/sql-contract-ts

npm i https://pkg.pr.new/@prisma-next/sql-contract-ts@888

@prisma-next/sql-contract-emitter

npm i https://pkg.pr.new/@prisma-next/sql-contract-emitter@888

@prisma-next/sql-lane-query-builder

npm i https://pkg.pr.new/@prisma-next/sql-lane-query-builder@888

@prisma-next/sql-relational-core

npm i https://pkg.pr.new/@prisma-next/sql-relational-core@888

@prisma-next/sql-builder

npm i https://pkg.pr.new/@prisma-next/sql-builder@888

@prisma-next/target-postgres

npm i https://pkg.pr.new/@prisma-next/target-postgres@888

@prisma-next/target-sqlite

npm i https://pkg.pr.new/@prisma-next/target-sqlite@888

@prisma-next/adapter-postgres

npm i https://pkg.pr.new/@prisma-next/adapter-postgres@888

@prisma-next/adapter-sqlite

npm i https://pkg.pr.new/@prisma-next/adapter-sqlite@888

@prisma-next/driver-postgres

npm i https://pkg.pr.new/@prisma-next/driver-postgres@888

@prisma-next/driver-sqlite

npm i https://pkg.pr.new/@prisma-next/driver-sqlite@888

commit: e6a3e03

@wmadden-electric wmadden-electric changed the title TML-2955: Expose the static ExecutionContext symmetrically via client-safe @prisma-next/<target>/static TML-2955: A client-safe static surface — @prisma-next/<target>/static Jul 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant