@prisma/orm-postgres 8.0.0-rc.17-dev.26 → 8.0.0-rc.17-dev.28

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma/orm-postgres",
3
- "version": "8.0.0-rc.17-dev.26",
3
+ "version": "8.0.0-rc.17-dev.28",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -10,10 +10,10 @@
10
10
  "skills"
11
11
  ],
12
12
  "dependencies": {
13
- "@prisma/orm-family-sql": "8.0.0-rc.17-dev.26",
14
- "@prisma/orm-framework": "8.0.0-rc.17-dev.26",
15
- "@prisma/orm-target-postgres": "8.0.0-rc.17-dev.26",
16
- "@prisma/orm-toolchain": "8.0.0-rc.17-dev.26",
13
+ "@prisma/orm-family-sql": "8.0.0-rc.17-dev.28",
14
+ "@prisma/orm-framework": "8.0.0-rc.17-dev.28",
15
+ "@prisma/orm-target-postgres": "8.0.0-rc.17-dev.28",
16
+ "@prisma/orm-toolchain": "8.0.0-rc.17-dev.28",
17
17
  "@types/node": "26.1.2",
18
18
  "@types/pg": "8.20.4",
19
19
  "arktype": "^2.2.2",
@@ -22,9 +22,9 @@
22
22
  "tinyglobby": "^0.2.17"
23
23
  },
24
24
  "devDependencies": {
25
- "@internal/postgres": "8.0.0-rc.17-dev.26",
26
- "@repo/tsconfig": "8.0.0-rc.17-dev.26",
27
- "@repo/tsdown": "8.0.0-rc.17-dev.26",
25
+ "@internal/postgres": "8.0.0-rc.17-dev.28",
26
+ "@repo/tsconfig": "8.0.0-rc.17-dev.28",
27
+ "@repo/tsdown": "8.0.0-rc.17-dev.28",
28
28
  "tsdown": "0.22.14",
29
29
  "typescript": "5.9.3"
30
30
  },
@@ -15,7 +15,7 @@ description: >-
15
15
  ORM 7 or earlier (schema.prisma + @prisma/client).
16
16
  metadata:
17
17
  library: '@prisma/orm-postgres'
18
- library_version: '8.0.0-rc.17-dev.26'
18
+ library_version: '8.0.0-rc.17-dev.28'
19
19
  version: '2026-09-12'
20
20
  ---
21
21
 
@@ -63,7 +63,7 @@ Open the reference whose triggers match the task. If more than one matches, open
63
63
  | Migration graph, refs, plan origin | [`references/migration-model.md`](references/migration-model.md) | migration graph, refs, `migration ref set` / `list` / `delete`, the `db` ref, `--advance-ref`, `--no-advance-ref`, `migration plan --from`, `from: (baseline)` in plan output, greenfield / from-scratch plan, baseline, first migration before deploy (Composer / CD-managed databases), chaining migrations, retrofitting migrations onto an existing database, `MIGRATION.HASH_NOT_IN_GRAPH`, `MIGRATION.PATH_UNREACHABLE` at plan/chain time |
64
64
  | Review migrations on deploy | [`references/migration-review.md`](references/migration-review.md) | "what migrations are going to run", "what runs on deploy / merge", merge conflict, diamond convergence, concurrent migrations, migration status, ref management for CI, staging / production environment refs, `MIGRATION.MARKER_NOT_IN_HISTORY`, `MIGRATION.MISSING_INVARIANTS`, `db migrate --show` |
65
65
  | Write queries | [`references/queries.md`](references/queries.md) | query, where, select, project, orderBy, limit, offset, take, skip, include, lookup, first, all, count, aggregate, groupBy, create, update, delete, upsert, returning, transaction, `db.orm`, `db.sql`, `runtime.query(plan)` vs `runtime.execute(plan)`, `db.prepare` / prepared statements, streaming / `for await`, many-to-many `include` and nested `connect`, `and` / `or` / `not` from `@prisma/orm-postgres/orm-client`, `db.query.from(...)` (Mongo pipeline), namespace-aware accessors, `.all()` Thenable, single-use iterators (`RUNTIME.ITERATOR_CONSUMED`), target-declared aggregate types (`count`, integer `sum`, and integer `avg` are `number`; `count` and integer `sum` throw outside ±(2^53 − 1) rather than round, while `avg` is a fraction already and carries no guard; `countBigInt` / `sumBigInt` / `avgDecimal` are the lossless forms, `avgDecimal` on PostgreSQL only), custom collection class (`extends Collection`), `with` and query fragments (`QueryFragment`, `Filtered`, `Ordered`), shared query fragments and scopes (`db.orm.fragment(fields, body)` for a filter on every model with given fields, `CodecField`, `db.orm.public.Post.fragment(...)` for a shared `select` / `include`, `orderByField` for an order or sort parameter from a request), drizzle-style, kysely-style. Naming types (§ *Naming model and result types*): "type of my model", "return type of a query", `ResultType`, `Scalars`, `Shape`, `models` / `Models` namespace in `contract.d.ts`, `Models.public_User`, Prisma 7 `Prisma.User` / `GetPayload` / `UserGetPayload` equivalents. Postgres/SQLite specifics: [`references/queries-postgres.md`](references/queries-postgres.md); Mongo specifics: [`references/queries-mongo.md`](references/queries-mongo.md) |
66
- | Wire the runtime | [`references/runtime.md`](references/runtime.md) | `db.ts`, `postgres<Contract>(...)` / `sqlite<Contract>(...)` / `mongo<Contract>(...)` façades, middleware composition (lints, budgets, cache via `@prisma/orm-extension-middleware-cache`, custom `afterQuery` middleware, `@prisma/orm-postgres/family-runtime`), `DATABASE_URL`, `.env`, connection pool / `poolOptions`, dev vs prod config, transactions, read replicas, multi-database, script won't exit / hangs, `db.close` / `pool.end`, `await using` / `[Symbol.asyncDispose]` |
66
+ | Wire the runtime | [`references/runtime.md`](references/runtime.md) | `db.ts`, `postgres<Contract>(...)` / `sqlite<Contract>(...)` / `mongo<Contract>(...)` façades, middleware composition (lints, budgets, cache via `@prisma/orm-extension-middleware-cache`, custom `activityEnded` middleware, `@prisma/orm-postgres/family-runtime`), `DATABASE_URL`, `.env`, connection pool / `poolOptions`, dev vs prod config, transactions, read replicas, multi-database, script won't exit / hangs, `db.close` / `pool.end`, `await using` / `[Symbol.asyncDispose]` |
67
67
  | Build-tool integration | [`references/build.md`](references/build.md) | Vite plugin (`@internal/vite-plugin-contract-emit`, Vite 7/8), `vite.config.ts`, contract emit on save, HMR / dev server, Next.js / Webpack / esbuild / Rollup / Turbopack (named gaps, not fabricated) |
68
68
  | Supabase | [`references/supabase.md`](references/supabase.md) | `@internal/extension-supabase`, RLS, row level security, policies (`policy_select` / `policy_update` / `@@rls`, `auth.uid()`), role binding (`asUser(jwt)` / `asAnon()` / `asServiceRole()`), `auth.users`, cross-space FKs to `supabase:auth.AuthUser`, JWT / JWKS (`SUPABASE_JWKS_URL`, `SUPABASE_JWT_SECRET`), `SUPABASE.JWT_INVALID`, `SUPABASE.CONFIG_INVALID`, `RoleBoundDb`, session pooler |
69
69
  | Debug an error | [`references/debug.md`](references/debug.md) | any structured error envelope (code, severity, why, fix, nextActions, meta), emit failed, query won't typecheck, query crashed, migration won't apply, `MIGRATION.HASH_MISMATCH`, `MIGRATION.RUNNER_FAILED`, `BUDGET.ROWS_EXCEEDED`, `BUDGET.TIME_EXCEEDED`, `RUNTIME.ABORTED`, `RUNTIME.TEMPORAL_UNAVAILABLE`, `PLAN.HASH_MISMATCH`, `CONTRACT.MARKER_MISSING`, `CONFIG.*` / `CLI.*` / `CONTRACT.*` / `MIGRATION.*` / `ORM.*` / `RUNTIME.*` codes, legacy `PN-*` codes, exit code 4 findings, drift, capability missing, planner conflict, EXPLAIN, query log, script won't exit / close connection |
@@ -111,7 +111,7 @@ The single source of truth: read the envelope, find the row by `code`, follow th
111
111
  | `PLAN.HASH_MISMATCH` | Runtime, executing a precompiled plan | The contract the plan was built against does not match the runtime contract. Re-emit, rebuild, redeploy. |
112
112
  | `RUNTIME.TEMPORAL_UNAVAILABLE` | Runtime, first read or write touching a Temporal-backed column (`Date`, `Timestamp(p)`, `Timestamptz(p)`, `Time(p)`) or a `temporal.updatedAt()` clock | No global `Temporal`. Node.js 26.8.2 and later ship `globalThis.Temporal`; 26.8.1 and earlier — including every 22 and 24 — do not. Either `import 'temporal-polyfill/full/global'` before the first query, or author the column as `DateString` / `TimestampString(p)` / `TimestamptzString(p)` / `TimeString(p)` to read PostgreSQL's own text. |
113
113
  | `ORM.RELATION_MUTATION_UNSUPPORTED` | ORM nested `create` / `connect` on an N:M relation whose junction has required payload columns | Write the junction table directly or use the SQL builder (`meta.junction`). |
114
- | `RUNTIME.ABORTED` (`details.phase` = `encode\|decode\|stream\|beforeExecute\|afterExecute\|onRow`) | Runtime, when an `AbortSignal` fires mid-execute | Cancellation, not a bug; surface to the caller. |
114
+ | `RUNTIME.ABORTED` (`details.phase` = `encode\|decode\|stream\|beforeEncode\|onRow`) | Runtime, when an `AbortSignal` fires mid-execute | Cancellation, not a bug; surface to the caller. |
115
115
  | `SqlQueryError` (no dotted code) | Raw-SQL paths surfacing a driver error | Inspect `sqlState` + `constraint` + `table` + `column`. Postgres `23505` = unique violation, `23503` = foreign-key violation, etc. Fix the data or the schema. |
116
116
  | TypeScript error mentioning a capability (e.g. `returning()` not on the type, `include` of a many-relation off a many-load) | Authoring-time, before any envelope fires | Capability gates are declared in the **contract** (`capabilities` block, namespaced by target/family), not in `prisma.config.ts`. Route to `references/contract.md` for capability declaration and to `references/queries.md` for which method gates on which capability. Re-emit (`pnpm prisma contract emit`) after enabling. |
117
117
  | TypeScript error mentioning a missing field/method on `db.orm.<ns>.<Model>` or a stale `Contract` shape | Authoring-time | Re-emit (`pnpm prisma contract emit`); confirm `db.ts` instantiates with `postgres<Contract>(...)` (the single type parameter propagates the contract types). See `references/runtime.md` and `references/contract.md`. |
@@ -30,7 +30,7 @@ This skill covers the **runtime entry point** — `db.ts` — and how to compose
30
30
  - **`db.ts` is the runtime entry point.** Imports the runtime factory from the `@internal/<target>` façade (`@internal/postgres/runtime`, `@internal/sqlite/runtime`, or `@internal/mongo/runtime`), the contract artefacts (`contract.json` + the `Contract` type from `contract.d.ts`), and any middleware. Exports a `db` value the rest of your app imports. On a per-request runtime, `db.ts` imports `postgresServerless` from `@internal/postgres/serverless` instead and exports the serverless client `postgres`; see *Workflow — Serverless and per-request runtimes*.
31
31
  - **The façade's runtime factory is the only surface user-authored `db.ts` imports from.** Each factory is a *default* export. For Postgres: `import postgres from '@internal/postgres/runtime'`; SQLite: `import sqlite from '@internal/sqlite/runtime'`; Mongo: `import mongo from '@internal/mongo/runtime'`. The factory signature is `<Target><Contract>(options)` — a single type parameter (the `Contract` type from `contract.d.ts`), and one options object.
32
32
  - **Lazy connect.** The factory does not connect to the database synchronously. `db.sql` and `db.orm` are available immediately; the driver / pool is instantiated on the first call that needs a runtime (or when you explicitly call `await db.connect({ url })`, which binds the client to that URL), and the pool opens its first database connection on the first query. This is why `db.ts` can be imported in modules that load before the env is ready.
33
- - **Middleware composes in order.** The first middleware in the `middleware: [...]` array runs *outermost* — its `beforeQuery` sees the operation first, and `interceptQuery` hooks are consulted in registration order with the first non-`undefined` result winning. Register a cache first so it gets first claim on a hit. Every middleware's `afterQuery` still fires on a cache hit, with `result.source: 'middleware'`.
33
+ - **Middleware composes in order.** Every hook runs in the order of the `middleware: [...]` array — the first middleware's `beforeEncode` sees the statement first, and `intercept.onQuery` handlers are consulted in registration order with the first non-`undefined` result winning. Register a cache first so it gets first claim on a hit. Every middleware's `activityEnded` still fires on a cache hit, with `result.source: 'middleware'`.
34
34
  - **`prisma.config.ts` vs `.env`.** The config (`definePrismaConfig({ orm: ormConfig({ contract, db, extensions, migrations }) })` — see `references/contract.md`) is for static project shape: contract path, installed extensions, migrations directory, default connection string. `.env` is for per-environment values (`DATABASE_URL`, secrets). Nothing reads `.env` on its own: the scaffolded `prisma.config.ts` starts with `import 'dotenv/config'`, and that import is what loads `.env` into `process.env` before the config (and the CLI running it) reads `process.env['DATABASE_URL']`. Keep the import; a config without it sees no `.env` values. Hardcoding `DATABASE_URL` in the config file leaks credentials and bypasses per-env overrides.
35
35
  - **Build-system / dev-server integration is a separate skill.** `vite dev` auto-emit lives in `references/build.md`. The runtime side (this skill) reads `contract.json` / `contract.d.ts` regardless of how they got onto disk, so the two skills compose cleanly.
36
36
 
@@ -172,22 +172,32 @@ How connections read rows, and the `cursor` option on the serverless client (wit
172
172
 
173
173
  ## Workflow — Custom middleware (query log, slow-query warning)
174
174
 
175
- The concept: a middleware is a plain object with `name`, `familyId: 'sql'`, and any of the hooks `beforeQuery`, `interceptQuery`, `afterQuery`, `beforeExecute`, `afterExecute`, `afterTransaction`. Row queries fire `afterQuery`; count-style writes fire `afterExecute`. `afterTransaction(plan, result, ctx)` is the last hook of every query whose before-hooks and parameter encoding succeeded (a query that fails in a before-hook or while encoding its parameters gets none), and fires once, when its effects are final: when the query ends outside a transaction, or when the enclosing transaction ends. `result.outcome` is `'committed'`, `'rolled-back'`, or `'unknown'` (a commit or statement that failed and may have landed, a row stream the caller stopped reading outside a transaction, or a committed transaction in which one of the queries failed). There is no separate telemetry package — observe queries with `afterQuery`, which fires once per execution after the rows are consumed, with `result.latencyMs`, `result.rowCount`, and `result.source` (`'driver'` or `'middleware'` for a cache hit). The `SqlMiddleware` type comes from `@prisma/orm-postgres/family-runtime`. `examples/prisma-8-demo/src/prisma/slow-query-warning.ts` is the canonical example:
175
+ The concept: the runtime runs every statement and every transaction as an **activity**, and a middleware is a plain object with `name`, `familyId: 'sql'`, and any of these hooks:
176
+
177
+ - Lifecycle events, for every activity: `activityStarted(activity, ctx)`, `activityEnded(activity, result, ctx)` and `activityFinalized(activity, result, ctx)`. Check `activity.kind` (`'statement'` or `'transaction'`) at the top. `activityEnded` fires when the act ends: for a statement with `result.outcome` (`'succeeded'`, `'failed'`, or `'stopped'` when the caller stopped reading), `result.latencyMs`, `result.source` (`'driver'`, or `'middleware'` for a cache hit) and `result.rowCount` or `result.stats` according to `result.returns`. `activityFinalized` fires once the effects are final, with `result.outcome` `'committed'`, `'rolled-back'` or `'unknown'`: right after the end outside a transaction, and when the transaction ends inside one. Every statement that started is finalized, even one blocked before it ran.
178
+ - Interceptors, for statements: `beforeEncode(plan, ctx, params)` before parameters are encoded (throw to block the statement), `intercept.onQuery` / `intercept.onExecute` to supply a result instead of running it, and `onRow(row, plan, ctx)` for each driver row.
179
+
180
+ Every hook of one activity receives the same `ctx`. Keep per-statement state in `ctx.state(key)` (use a `Symbol()` key); `activity.id` identifies the activity, and `ctx.parent` is the enclosing transaction's context. There is no separate telemetry package — observe statements with `activityEnded`. The `SqlMiddleware` type comes from `@prisma/orm-postgres/family-runtime`. `examples/prisma-8-demo/src/prisma/slow-query-warning.ts` is the canonical example:
176
181
 
177
182
  ```typescript
178
183
  import type { SqlMiddleware } from '@prisma/orm-postgres/family-runtime';
179
184
 
185
+ const statementSql = Symbol('slow-query-warning.sql');
186
+
180
187
  export function slowQueryWarning(options?: { readonly thresholdMs?: number }): SqlMiddleware {
181
188
  const thresholdMs = options?.thresholdMs ?? 250;
182
189
  return {
183
190
  name: 'slow-query-warning',
184
191
  familyId: 'sql',
185
- async afterQuery(plan, result, ctx) {
186
- if (result.latencyMs <= thresholdMs) return;
192
+ async beforeEncode(plan, ctx) {
193
+ ctx.state(statementSql)['sql'] = plan.sql;
194
+ },
195
+ async activityEnded(activity, result, ctx) {
196
+ if (result.kind !== 'statement' || result.latencyMs <= thresholdMs) return;
187
197
  ctx.log.warn({
188
198
  code: 'APP.SLOW_QUERY',
189
199
  message: `Query took ${result.latencyMs}ms (threshold: ${thresholdMs}ms)`,
190
- details: { sql: plan.sql, rowCount: result.rowCount, source: result.source },
200
+ details: { sql: ctx.state(statementSql)['sql'], source: result.source, activityId: activity.id },
191
201
  });
192
202
  },
193
203
  };
@@ -236,7 +246,7 @@ For the full option surface, read the source: `packages/2-sql/5-runtime/src/midd
236
246
 
237
247
  ## Workflow — Cache middleware
238
248
 
239
- The concept: `@prisma/orm-extension-middleware-cache` ships an opt-in read cache built on the `interceptQuery` hook. On a hit the driver is never called; on a miss the rows are buffered and stored when the query completes. Only a plan carrying `cacheAnnotation` is cached; `cacheAnnotation({ bypass: true })` skips the cache for one call. Cache keys default to the runtime's content hash of the plan (`key` overrides), and queries inside a transaction or pinned connection bypass the cache. How long an entry lives is the store's policy: the default store keeps up to 1000 entries for 60 seconds each, and `createInMemoryCacheStore({ maxEntries, ttlMs })` changes that (`ttlMs: Infinity` never expires). `CacheStore` is the interface for a Redis-style backend. The cache never sees writes: after the write commits, call `cache.invalidate({ keys })` for reads annotated with a `key`. `cacheAnnotation({ meta })` hands any value to the store with the entry, and `cache.invalidate({ meta })` hands one to its `unset`; only a custom store that indexes `meta` can act on it, and the default store throws `RUNTIME.CACHE_STORE_META_UNSUPPORTED`.
249
+ The concept: `@prisma/orm-extension-middleware-cache` ships an opt-in read cache built on the `intercept.onQuery` handler. On a hit the driver is never called; on a miss the rows are buffered and stored when the query completes. Only a plan carrying `cacheAnnotation` is cached; `cacheAnnotation({ bypass: true })` skips the cache for one call. Cache keys default to the runtime's content hash of the plan (`key` overrides), and queries inside a transaction or pinned connection bypass the cache. How long an entry lives is the store's policy: the default store keeps up to 1000 entries for 60 seconds each, and `createInMemoryCacheStore({ maxEntries, ttlMs })` changes that (`ttlMs: Infinity` never expires). `CacheStore` is the interface for a Redis-style backend. The cache never sees writes: after the write commits, call `cache.invalidate({ keys })` for reads annotated with a `key`. `cacheAnnotation({ meta })` hands any value to the store with the entry, and `cache.invalidate({ meta })` hands one to its `unset`; only a custom store that indexes `meta` can act on it, and the default store throws `RUNTIME.CACHE_STORE_META_UNSUPPORTED`.
240
250
 
241
251
  ```typescript
242
252
  import {
@@ -272,14 +282,14 @@ await cache.invalidate({ keys: ['user-1'] });
272
282
 
273
283
  ```typescript
274
284
  middleware: [
275
- createCacheMiddleware(), // first — gets first claim on an interceptQuery hit
285
+ createCacheMiddleware(), // first — gets first claim on an intercept.onQuery hit
276
286
  lints({ severities: { noLimit: 'error' } }),
277
287
  budgets({ maxLatencyMs: 5_000 }),
278
- slowQueryWarning({ thresholdMs: 250 }), // afterQuery fires for cache hits too (source: 'middleware')
288
+ slowQueryWarning({ thresholdMs: 250 }), // activityEnded fires for cache hits too (source: 'middleware')
279
289
  ],
280
290
  ```
281
291
 
282
- Order matters: `beforeQuery` runs in registration order for every middleware before any `interceptQuery` is consulted, so lints and budgets still check a query the cache then answers; `afterQuery` fires for all of them either way.
292
+ Order matters: `beforeEncode` runs in registration order for every middleware before any `intercept.onQuery` is consulted, so lints and budgets still check a query the cache then answers; `activityEnded` fires for all of them either way.
283
293
 
284
294
  ## Workflow — Configure the connection
285
295
 
@@ -386,18 +396,18 @@ The runtime side (this skill) is the same regardless: `db.ts` reads `contract.js
386
396
  1. **Hardcoding `DATABASE_URL` in `prisma.config.ts`.** Leaks credentials; bypasses per-environment overrides. Use `.env`.
387
397
  2. **Omitting the `<Contract>` type parameter** in `postgres<Contract>(...)`. Without it, static surfaces collapse to a generic shape and you lose autocomplete for models. There is no second type parameter — the older two-param signature (`postgres<Contract, TypeMaps>`) is gone.
388
398
  3. **Forgetting `with { type: 'json' }` on the contract import.** Required by Node's ESM JSON-import-attribute spec.
389
- 4. **Middleware order matters.** Registration order is hook order; put the cache first so its `interceptQuery` is consulted first.
390
- 5. **Importing middleware from a non-existent package or subpath.** There is no `@internal/postgres/middleware` subpath and no `@internal/middleware-telemetry` package. `lints` / `budgets` / `SqlMiddleware` come from `@prisma/orm-postgres/family-runtime`; the cache comes from `@prisma/orm-extension-middleware-cache`; a query log or telemetry hook is a custom `afterQuery` middleware (above).
399
+ 4. **Middleware order matters.** Registration order is hook order; put the cache first so its `intercept.onQuery` is consulted first.
400
+ 5. **Importing middleware from a non-existent package or subpath.** There is no `@internal/postgres/middleware` subpath and no `@internal/middleware-telemetry` package. `lints` / `budgets` / `SqlMiddleware` come from `@prisma/orm-postgres/family-runtime`; the cache comes from `@prisma/orm-extension-middleware-cache`; a query log or telemetry hook is a custom `activityEnded` middleware (above).
391
401
  6. **Confabulating lint / budget option names.** Lints take `severities` (with the five keys above), not `requireWhere` / `maxRowsWithoutLimit`. Budgets use `maxLatencyMs` (not `maxDurationMs`) plus `maxRows` / `defaultTableRows` / `tableRows`. When in doubt, read the source.
392
402
  7. **Switching targets without re-emitting.** The contract artefacts are target-shaped; emit after the target change.
393
403
  8. **Script hangs after queries finish on Postgres.** The `pg.Pool` keeps Node's event loop alive. Solution: `await db.close()` before the script returns, or `await using db = postgres<Contract>(...)` at the top of a script module. Do not put `await using db = postgres(...)` inside a request handler — it's block-scoped and would close the pool after every request. The right server pattern is a module-level singleton in `db.ts` that lives for the process lifetime. On a per-request runtime, use `postgresServerless()` and `await using db = await postgres.connect({ url })` in the handler instead (see *Workflow — Serverless and per-request runtimes*).
394
404
 
395
405
  ## What Prisma 8 doesn't do yet
396
406
 
397
- - **A `/middleware` subpath or a telemetry package.** Neither exists. The middleware surface is `lints`, `budgets`, and the `SqlMiddleware` type on `@prisma/orm-postgres/family-runtime`, plus the separately installed `@prisma/orm-extension-middleware-cache`. Anything else (query log, tracing spans, metrics) is a custom `afterQuery` middleware you write. File additional gaps you hit via `references/feedback.md`.
407
+ - **A `/middleware` subpath or a telemetry package.** Neither exists. The middleware surface is `lints`, `budgets`, and the `SqlMiddleware` type on `@prisma/orm-postgres/family-runtime`, plus the separately installed `@prisma/orm-extension-middleware-cache`. Anything else (query log, tracing spans, metrics) is a custom middleware you write on the lifecycle events. File additional gaps you hit via `references/feedback.md`.
398
408
  - **Multi-database routing / read replicas.** Prisma 8 doesn't ship a built-in primary/replica router or shard-aware client. Workaround: configure separate `db.ts` instances per data store and call the right one in your application code. If you need first-class multi-database routing, file a feature request via the `references/feedback.md` skill.
399
409
  - **Connection pooling as a first-class config field.** `poolOptions.connectionTimeoutMillis` and `poolOptions.idleTimeoutMillis` are wired through, but the rest of `pg.Pool`'s tuning surface (max connections, `allowExitOnIdle`, ssl options, …) is not exposed by name. Workaround: construct the `pg.Pool` yourself and pass it via `pg:`. If you need more pool fields surfaced on the façade, file a feature request via the `references/feedback.md` skill.
400
- - **Query logger middleware as a built-in.** Prisma 8 doesn't ship a "log every query" middleware. Workaround: a custom `afterQuery` middleware (see *Workflow — Custom middleware*). If you need a built-in query log, file a feature request via the `references/feedback.md` skill.
410
+ - **Query logger middleware as a built-in.** Prisma 8 doesn't ship a "log every query" middleware. Workaround: a custom `activityEnded` middleware (see *Workflow — Custom middleware*). If you need a built-in query log, file a feature request via the `references/feedback.md` skill.
401
411
 
402
412
  ## Reference Files
403
413