@prisma/orm-mongo 8.0.0-rc.18-dev.17 → 8.0.0-rc.18-dev.18
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-mongo",
|
|
3
|
-
"version": "8.0.0-rc.18-dev.
|
|
3
|
+
"version": "8.0.0-rc.18-dev.18",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -10,18 +10,18 @@
|
|
|
10
10
|
"skills"
|
|
11
11
|
],
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@prisma/orm-family-mongo": "8.0.0-rc.18-dev.
|
|
14
|
-
"@prisma/orm-framework": "8.0.0-rc.18-dev.
|
|
15
|
-
"@prisma/orm-target-mongo": "8.0.0-rc.18-dev.
|
|
16
|
-
"@prisma/orm-toolchain": "8.0.0-rc.18-dev.
|
|
13
|
+
"@prisma/orm-family-mongo": "8.0.0-rc.18-dev.18",
|
|
14
|
+
"@prisma/orm-framework": "8.0.0-rc.18-dev.18",
|
|
15
|
+
"@prisma/orm-target-mongo": "8.0.0-rc.18-dev.18",
|
|
16
|
+
"@prisma/orm-toolchain": "8.0.0-rc.18-dev.18",
|
|
17
17
|
"mongodb-connection-string-url": "^7.0.1",
|
|
18
18
|
"pathe": "^2.0.3",
|
|
19
19
|
"tinyglobby": "^0.2.17"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
|
-
"@internal/mongo": "8.0.0-rc.18-dev.
|
|
23
|
-
"@repo/tsconfig": "8.0.0-rc.18-dev.
|
|
24
|
-
"@repo/tsdown": "8.0.0-rc.18-dev.
|
|
22
|
+
"@internal/mongo": "8.0.0-rc.18-dev.18",
|
|
23
|
+
"@repo/tsconfig": "8.0.0-rc.18-dev.18",
|
|
24
|
+
"@repo/tsdown": "8.0.0-rc.18-dev.18",
|
|
25
25
|
"tsdown": "0.22.14",
|
|
26
26
|
"typescript": "5.9.3"
|
|
27
27
|
},
|
package/skills/prisma-8/SKILL.md
CHANGED
|
@@ -130,7 +130,7 @@ Servers (HTTP handlers, workers in a request loop) **do not call `db.close()`**
|
|
|
130
130
|
|
|
131
131
|
- **`close()` is idempotent.** Calling it twice is a no-op.
|
|
132
132
|
- **`close()` is terminal.** There is no reconnect on a closed `db` — construct a new client if you need to reach the database again. After close, `db.runtime()`, `db.connect(...)`, `db.transaction(...)`, and `db.prepare(...)` reject with `Error('<target> client is closed')` (e.g. `'Postgres client is closed'`, `'SQLite client is closed'`, `'Mongo client is closed'`).
|
|
133
|
-
- **`close()` waits for work already running and refuses new work.** On a Postgres client built from `{ url }`, `close()` refuses every new call at once with `DRIVER.NOT_CONNECTED` ("Postgres client is closed"), and a runtime captured with `db.runtime()` before `close()` is refused at once with "Runtime is closed"; it waits for the queries and
|
|
133
|
+
- **`close()` waits for work already running and refuses new work.** On a Postgres client built from `{ url }`, `close()` refuses every new call at once with `DRIVER.NOT_CONNECTED` ("Postgres client is closed"), and a runtime captured with `db.runtime()` before `close()` is refused at once with "Runtime is closed"; it waits for the queries, transactions and ORM calls already in flight, then ends the pool. An ORM call that resolves to one value, such as `first()`, `create()` or a nested create with its reload, starts when it is called, so `close()` waits for it and it completes. On a serverless connection, `close()` waits until the runtime has been idle for one turn of the event loop, so a chain of queries that keeps it busy from the close onward completes, then ends the `pg.Client`; work that starts after that rejects with `DRIVER.NOT_CONNECTED` ("Runtime is closed"). A lazy result such as `db.orm...all()` or `db.runtime().query(plan)` starts when it is awaited or iterated, not when it is built; awaited after `close()`, an ORM `all()` is refused with "Postgres client is closed". A Postgres client given a caller's `pg.Pool` or `pg.Client` does not close its runtime, so work through a runtime taken before `close()` keeps running on the caller's pool. `await` outstanding work before calling `close()`.
|
|
134
134
|
- **Ownership.** `close()` releases only what the façade constructed (`pg.Pool` from `{ url }`, `MongoClient` from `{ url }` / `{ uri, dbName }`, SQLite handle from `{ path }`). If you supplied your own `pg.Pool` / `pg.Client` (Postgres `pg:` option), `mongodb.MongoClient` (Mongo `mongoClient:` option), or a pre-built `binding`, `db.close()` does **not** touch those — you own their lifecycle.
|
|
135
135
|
|
|
136
136
|
**`db.end()` does not exist.** The universal `node-postgres` name is `pool.end()` on a `pg.Pool`; the Prisma 8 runtime client is not a `pg.Pool`. The right call is `await db.close()`.
|
|
@@ -174,9 +174,9 @@ How connections read rows, and the `cursor` option on the serverless client (wit
|
|
|
174
174
|
|
|
175
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
176
|
|
|
177
|
-
- Lifecycle events, for every activity: `activityStarted(activity, ctx)`, `activityEnded(activity, result, ctx)` and `activityFinalized(activity, result, ctx)`. Check `activity.kind` (`'statement'` or `'
|
|
177
|
+
- Lifecycle events, for every activity: `activityStarted(activity, ctx)`, `activityEnded(activity, result, ctx)` and `activityFinalized(activity, result, ctx)`. Check `activity.kind` (`'statement'`, `'transaction'`, or a client kind such as `'orm-call'`) 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
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
|
-
- Client activities: a client library can start an activity of its own kind, which contains a hyphen,
|
|
179
|
+
- Client activities: a client library can start an activity of its own kind, which contains a hyphen, and send its statements beneath it. The SQL ORM runs every terminal method as one `orm-call` activity: `db.orm.public.User.first(...)` is one `orm-call`, with its statements, its own transaction and its read-backs beneath it. A middleware sees it through the same lifecycle events, with `activity.kind` set to that kind and `ctx.parent` of its statements pointing at it, and can supply its result through `intercept.onActivity(activity, ctx)`; the ORM then sends no statement. **The annotations of an ORM call are on the `orm-call` activity**, read with `handle.read(activity)` in `activityStarted`; the statements it sends carry none, so reading them from `plan.meta.annotations` finds nothing. `activity.contentHash()` gives the call's digest, computed only when asked. Outside a transaction it is finalized right after it ends; inside one, when the transaction ends, after its statements. A middleware that handles only some kinds should ignore the others rather than fail on them.
|
|
180
180
|
|
|
181
181
|
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:
|
|
182
182
|
|
|
@@ -247,7 +247,7 @@ For the full option surface, read the source: `packages/2-sql/5-runtime/src/midd
|
|
|
247
247
|
|
|
248
248
|
## Workflow — Cache middleware
|
|
249
249
|
|
|
250
|
-
The concept: `@prisma/orm-extension-middleware-cache` ships an opt-in read cache
|
|
250
|
+
The concept: `@prisma/orm-extension-middleware-cache` ships an opt-in read cache. An annotated ORM call is cached as a whole, through `intercept.onActivity`: on a hit the ORM sends no statement; on a miss the value the call returned is stored. An annotated SQL builder query is cached as rows, through `intercept.onQuery`: on a hit the driver is never called; on a miss the rows are buffered and stored when the query completes. Only a read carrying `cacheAnnotation` is cached; `cacheAnnotation({ bypass: true })` skips the cache for one call. Cache keys default to the content hash of the ORM call or of the plan (`key` overrides), and reads inside a transaction or on a pinned connection are neither served nor stored. 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`.
|
|
251
251
|
|
|
252
252
|
```typescript
|
|
253
253
|
import {
|
|
@@ -277,7 +277,7 @@ await cache.invalidate({ keys: ['user-1'] });
|
|
|
277
277
|
|
|
278
278
|
**Invalidate after the commit, not inside the transaction.** A read from another request can refill the cache with the old rows before the commit lands. A read that missed before the `invalidate` and finishes after it does not store its rows: the store moves the key's version on `unset`, and the read's `set` is conditional on the version it saw. This holds across processes that share a store.
|
|
279
279
|
|
|
280
|
-
**The cache key carries no identity.** The default key is
|
|
280
|
+
**The cache key carries no identity.** The default key is a content hash of the statement — contract hash, SQL text, and bound parameters — or, for an ORM call, of the terminal method and the statement it sends first, so two callers issuing the same read share one entry regardless of who they are. Never annotate a read whose rows depend on the caller (per-user, per-tenant, or RLS-filtered data) on the plain `postgres()` façade unless the identity is part of the key: `cacheAnnotation({ key: `user:${userId}:profile` })`, or a `where` clause that binds the identity as a parameter (the parameter is in the hash). Reads that run on a pinned connection or inside a transaction bypass the cache entirely (`ctx.scope !== 'runtime'` or `ctx.inTransaction()`), which is why a Supabase `RoleBoundDb` read — executed on a connection with the role bound via `set_config` — is never served from cache; the plain façade has no such protection.
|
|
281
281
|
|
|
282
282
|
## Workflow — Compose multiple middleware
|
|
283
283
|
|
|
@@ -290,7 +290,7 @@ middleware: [
|
|
|
290
290
|
],
|
|
291
291
|
```
|
|
292
292
|
|
|
293
|
-
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.
|
|
293
|
+
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. A cached ORM call is answered before any statement exists, so lints and budgets see no statement for a hit.
|
|
294
294
|
|
|
295
295
|
## Workflow — Configure the connection
|
|
296
296
|
|
|
@@ -398,7 +398,7 @@ The runtime side (this skill) is the same regardless: `db.ts` reads `contract.js
|
|
|
398
398
|
1. **Hardcoding `DATABASE_URL` in `prisma.config.ts`.** Leaks credentials; bypasses per-environment overrides. Use `.env`.
|
|
399
399
|
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.
|
|
400
400
|
3. **Forgetting `with { type: 'json' }` on the contract import.** Required by Node's ESM JSON-import-attribute spec.
|
|
401
|
-
4. **Middleware order matters.** Registration order is hook order; put the cache first so its `intercept.onQuery`
|
|
401
|
+
4. **Middleware order matters.** Registration order is hook order; put the cache first so its `intercept.onActivity` and `intercept.onQuery` are consulted first.
|
|
402
402
|
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).
|
|
403
403
|
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.
|
|
404
404
|
7. **Switching targets without re-emitting.** The contract artefacts are target-shaped; emit after the target change.
|