@fluojs/prisma 1.0.2 → 1.1.1
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/README.ko.md +134 -54
- package/README.md +134 -53
- package/dist/module.d.ts +2 -2
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +9 -14
- package/dist/prisma-service-brand.d.ts +13 -0
- package/dist/prisma-service-brand.d.ts.map +1 -0
- package/dist/prisma-service-brand.js +23 -0
- package/dist/service.d.ts +31 -0
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +114 -17
- package/dist/transaction-decorator-contract.notes.d.ts +19 -0
- package/dist/transaction-decorator-contract.notes.d.ts.map +1 -0
- package/dist/transaction-decorator-contract.notes.js +1 -0
- package/dist/transaction.d.ts +34 -10
- package/dist/transaction.d.ts.map +1 -1
- package/dist/transaction.js +86 -8
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
<p><strong><kbd>English</kbd></strong> <a href="./README.ko.md"><kbd>한국어</kbd></a></p>
|
|
4
4
|
|
|
5
|
-
Prisma lifecycle and ALS-backed transaction context for fluo applications. Connects a `PrismaClient` to the module system with automatic connection management and request-scoped transactions.
|
|
5
|
+
Node.js 20+ Prisma lifecycle and ALS-backed transaction context for fluo applications. Connects a `PrismaClient` to the module system with automatic connection management and request-scoped transactions.
|
|
6
6
|
|
|
7
7
|
## Table of Contents
|
|
8
8
|
|
|
@@ -10,10 +10,10 @@ Prisma lifecycle and ALS-backed transaction context for fluo applications. Conne
|
|
|
10
10
|
- [When to Use](#when-to-use)
|
|
11
11
|
- [Quick Start](#quick-start)
|
|
12
12
|
- [Common Patterns](#common-patterns)
|
|
13
|
-
- [
|
|
13
|
+
- [Service Transaction Boundary (@Transaction)](#service-transaction-boundary-transaction)
|
|
14
|
+
- [Request Transaction Interceptor Compatibility](#request-transaction-interceptor-compatibility)
|
|
14
15
|
- [Named Registrations for Multiple Clients](#named-registrations-for-multiple-clients)
|
|
15
|
-
- [Manual Transactions](#manual-transactions)
|
|
16
|
-
- [Automatic Request Transactions](#automatic-request-transactions)
|
|
16
|
+
- [Manual Transactions and current()](#manual-transactions-and-current)
|
|
17
17
|
- [Shutdown and Status Contracts](#shutdown-and-status-contracts)
|
|
18
18
|
- [Async Configuration and Isolation](#async-configuration-and-isolation)
|
|
19
19
|
- [Manual Module Composition](#manual-module-composition)
|
|
@@ -31,7 +31,7 @@ pnpm add @prisma/client
|
|
|
31
31
|
|
|
32
32
|
## When to Use
|
|
33
33
|
|
|
34
|
-
- When using Prisma as your ORM and you want it integrated with fluo's dependency injection and lifecycle hooks.
|
|
34
|
+
- When using Prisma as your ORM on Node.js 20+ and you want it integrated with fluo's dependency injection and lifecycle hooks.
|
|
35
35
|
- When you need a reliable way to share a transaction context across multiple services and repositories without passing a `tx` object everywhere.
|
|
36
36
|
- When you want automatic `$connect` on startup and `$disconnect` on shutdown.
|
|
37
37
|
|
|
@@ -56,33 +56,101 @@ class AppModule {}
|
|
|
56
56
|
|
|
57
57
|
## Common Patterns
|
|
58
58
|
|
|
59
|
-
###
|
|
59
|
+
### Service Transaction Boundary (@Transaction)
|
|
60
60
|
|
|
61
|
-
The `
|
|
61
|
+
The `@Transaction()` decorator is the recommended way to define transaction boundaries in your service layer. It ensures that all repository calls made within the decorated method share the same Prisma transaction.
|
|
62
62
|
|
|
63
63
|
```typescript
|
|
64
64
|
import { Inject } from '@fluojs/core';
|
|
65
|
-
import { PrismaService } from '@fluojs/prisma';
|
|
65
|
+
import { PrismaService, Transaction, type PrismaServiceFacade } from '@fluojs/prisma';
|
|
66
66
|
import { PrismaClient } from '@prisma/client';
|
|
67
|
+
import { UserRepository } from './user.repository';
|
|
68
|
+
|
|
69
|
+
export class UserService {
|
|
70
|
+
constructor(private readonly repo: UserRepository) {}
|
|
71
|
+
|
|
72
|
+
@Transaction()
|
|
73
|
+
async onboardUser(dto: CreateUserDto) {
|
|
74
|
+
const user = await this.repo.create(dto);
|
|
75
|
+
await this.repo.initProfile(user.id);
|
|
76
|
+
return user;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
67
79
|
|
|
68
80
|
@Inject(PrismaService)
|
|
69
81
|
export class UserRepository {
|
|
70
|
-
constructor(private readonly prisma:
|
|
82
|
+
constructor(private readonly prisma: PrismaServiceFacade<PrismaClient>) {}
|
|
83
|
+
|
|
84
|
+
async create(data: any) {
|
|
85
|
+
// The facade type exposes standard PrismaClient delegates.
|
|
86
|
+
// When called inside @Transaction(), they automatically participate in the ambient transaction.
|
|
87
|
+
return this.prisma.user.create({ data });
|
|
88
|
+
}
|
|
71
89
|
|
|
72
|
-
async
|
|
73
|
-
|
|
74
|
-
return this.prisma.current().user.findUnique({ where: { id } });
|
|
90
|
+
async initProfile(userId: string) {
|
|
91
|
+
return this.prisma.profile.create({ data: { userId } });
|
|
75
92
|
}
|
|
76
93
|
}
|
|
77
94
|
```
|
|
78
95
|
|
|
96
|
+
Calls to `@Transaction()` methods are reentrant. If a decorated method calls another decorated method, they share the same underlying Prisma transaction.
|
|
97
|
+
|
|
98
|
+
### Request Transaction Interceptor Compatibility
|
|
99
|
+
|
|
100
|
+
`PrismaTransactionInterceptor` is restored as a deprecated 1.x compatibility export for existing `@UseInterceptors(...)` request-wide boundaries. The unnamed `PrismaModule.forRoot(...)` and `forRootAsync(...)` registrations provide and export it. It delegates to `PrismaService.requestTransaction(...)` and forwards the request `AbortSignal`.
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { Controller, Post, UseInterceptors } from '@fluojs/http';
|
|
104
|
+
import { PrismaTransactionInterceptor } from '@fluojs/prisma';
|
|
105
|
+
|
|
106
|
+
@Controller('/orders')
|
|
107
|
+
export class OrdersController {
|
|
108
|
+
@Post('/')
|
|
109
|
+
@UseInterceptors(PrismaTransactionInterceptor)
|
|
110
|
+
createOrder() {
|
|
111
|
+
return this.orders.create();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Prefer service-layer `@Transaction()` for new business operations. Use explicit `requestTransaction(...)` when a complete request truly needs one transaction or named/multiple Prisma registrations must select a specific service; the compatibility interceptor targets only the unnamed default registration.
|
|
117
|
+
|
|
118
|
+
When request-wide atomicity is genuinely required, make the boundary and cancellation input visible in application code:
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import { Inject } from '@fluojs/core';
|
|
122
|
+
import { Controller, Post, type RequestContext } from '@fluojs/http';
|
|
123
|
+
import { PrismaService } from '@fluojs/prisma';
|
|
124
|
+
import { PrismaClient } from '@prisma/client';
|
|
125
|
+
|
|
126
|
+
@Inject(PrismaService, OrdersService)
|
|
127
|
+
@Controller('/orders')
|
|
128
|
+
export class OrdersController {
|
|
129
|
+
constructor(
|
|
130
|
+
private readonly prisma: PrismaService<PrismaClient>,
|
|
131
|
+
private readonly orders: OrdersService,
|
|
132
|
+
) {}
|
|
133
|
+
|
|
134
|
+
@Post('/checkout')
|
|
135
|
+
checkout(input: CheckoutInput, context: RequestContext) {
|
|
136
|
+
const { request } = context;
|
|
137
|
+
return this.prisma.requestTransaction(
|
|
138
|
+
() => this.orders.checkout(input),
|
|
139
|
+
request.signal,
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
This is a narrow compatibility pattern, not a replacement for service `@Transaction()`. A request-wide transaction can hold database locks for the entire HTTP operation, so keep the boundary short and explicit.
|
|
146
|
+
|
|
79
147
|
### Named Registrations for Multiple Clients
|
|
80
148
|
|
|
81
|
-
When one application container needs more than one Prisma client, register each client with an explicit `name` and inject the matching token with `getPrismaServiceToken(name)`.
|
|
149
|
+
When one application container needs more than one Prisma client, register each client with an explicit `name` and inject the matching token with `getPrismaServiceToken(name)`. For named clients, pass an accessor to `@Transaction()` to target the correct service. Default `@Transaction()` resolution only selects Prisma service/facade-shaped properties; transaction-like objects from other persistence integrations are ignored so ambiguous hosts must use an explicit accessor.
|
|
82
150
|
|
|
83
151
|
```typescript
|
|
84
152
|
import { Inject } from '@fluojs/core';
|
|
85
|
-
import { PrismaModule, PrismaService, getPrismaServiceToken } from '@fluojs/prisma';
|
|
153
|
+
import { PrismaModule, PrismaService, getPrismaServiceToken, Transaction, type PrismaServiceFacade } from '@fluojs/prisma';
|
|
86
154
|
|
|
87
155
|
const usersPrismaModule = PrismaModule.forRoot({ name: 'users', client: usersPrisma });
|
|
88
156
|
const analyticsPrismaModule = PrismaModule.forRoot({ name: 'analytics', client: analyticsPrisma });
|
|
@@ -90,64 +158,69 @@ const analyticsPrismaModule = PrismaModule.forRoot({ name: 'analytics', client:
|
|
|
90
158
|
@Inject(getPrismaServiceToken('users'), getPrismaServiceToken('analytics'))
|
|
91
159
|
export class MultiDatabaseService {
|
|
92
160
|
constructor(
|
|
93
|
-
private readonly users:
|
|
94
|
-
private readonly analytics:
|
|
161
|
+
private readonly users: PrismaServiceFacade<typeof usersPrisma>,
|
|
162
|
+
private readonly analytics: PrismaServiceFacade<typeof analyticsPrisma>,
|
|
95
163
|
) {}
|
|
96
164
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const
|
|
100
|
-
|
|
165
|
+
@Transaction((self) => self.users)
|
|
166
|
+
async updateAndLog(userId: string, data: any) {
|
|
167
|
+
const user = await this.users.user.update({ where: { id: userId }, data });
|
|
168
|
+
// This call is outside the 'users' transaction unless 'analytics' also opens one
|
|
169
|
+
await this.analytics.report.create({ data: { event: 'update', userId } });
|
|
170
|
+
return user;
|
|
101
171
|
}
|
|
102
172
|
}
|
|
103
173
|
```
|
|
104
174
|
|
|
105
|
-
Unnamed registration remains the default single-client path for `PrismaService`, `PRISMA_CLIENT`, `PRISMA_OPTIONS`, and `PrismaTransactionInterceptor`. When you register multiple Prisma clients in the same container, use names for every additional client so token resolution stays explicit.
|
|
106
175
|
|
|
107
|
-
### Manual Transactions
|
|
176
|
+
### Manual Transactions and current()
|
|
108
177
|
|
|
109
|
-
|
|
178
|
+
The `PrismaService` provides a `current()` method that returns the active transaction client if inside a transaction scope, or the root client otherwise. Use this as an escape hatch when you need to pass the client to external libraries or perform advanced manual transaction plumbing.
|
|
110
179
|
|
|
111
180
|
```typescript
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
});
|
|
116
|
-
```
|
|
181
|
+
import { Inject } from '@fluojs/core';
|
|
182
|
+
import { PrismaService } from '@fluojs/prisma';
|
|
183
|
+
import { PrismaClient } from '@prisma/client';
|
|
117
184
|
|
|
118
|
-
|
|
185
|
+
@Inject(PrismaService)
|
|
186
|
+
export class AdvancedRepository {
|
|
187
|
+
constructor(private readonly prisma: PrismaService<PrismaClient>) {}
|
|
119
188
|
|
|
120
|
-
|
|
189
|
+
async customOperation() {
|
|
190
|
+
const tx = this.prisma.current();
|
|
191
|
+
// Use tx for operations that fluo doesn't automatically wrap,
|
|
192
|
+
// or when passing to an external utility that expects a PrismaClient.
|
|
193
|
+
return tx.user.findMany();
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
```
|
|
121
197
|
|
|
122
|
-
|
|
198
|
+
Use `prisma.transaction()` for manual interactive transaction blocks:
|
|
123
199
|
|
|
124
200
|
```typescript
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
@Post()
|
|
131
|
-
async create() {
|
|
132
|
-
// All downstream repository calls via PrismaService.current() share this tx
|
|
133
|
-
}
|
|
134
|
-
}
|
|
201
|
+
await this.prisma.transaction(async () => {
|
|
202
|
+
const tx = this.prisma.current();
|
|
203
|
+
const user = await tx.user.create({ data });
|
|
204
|
+
await tx.profile.create({ data: { userId: user.id } });
|
|
205
|
+
});
|
|
135
206
|
```
|
|
136
207
|
|
|
137
|
-
`
|
|
208
|
+
When `transaction()` is called while a transaction context is already active, `PrismaService` reuses the active transaction client instead of opening a nested Prisma transaction. Nested calls must not pass transaction options such as isolation levels; providing options in an active context is rejected so the package does not silently drop caller intent while reusing the ambient transaction.
|
|
138
209
|
|
|
139
210
|
### Shutdown and Status Contracts
|
|
140
211
|
|
|
141
|
-
`PrismaService.requestTransaction(...)` is available before and during normal serving, but new request-scoped transactions are rejected once application shutdown has started. During shutdown, open request transactions are aborted, tracked until their outer transaction boundary has settled, and drained before `$disconnect()` runs. This includes nested `requestTransaction(...)` calls opened inside an existing manual `transaction(...)` boundary: they reuse the ambient Prisma transaction client, stay visible in `details.activeRequestTransactions` until the outer boundary finishes, and do not open a second Prisma transaction.
|
|
212
|
+
`PrismaService.requestTransaction(...)` is available before and during normal serving, but new request-scoped transactions are rejected once application shutdown has started. New outer manual `transaction(...)` and service `@Transaction()` boundaries are also rejected after shutdown begins; boundaries that were already open are drained before `$disconnect()` so shutdown does not race an active Prisma transaction. During shutdown, open request transactions are aborted, tracked until their outer transaction boundary has settled, and drained before `$disconnect()` runs. This includes nested `requestTransaction(...)` calls opened inside an existing manual `transaction(...)` boundary: they reuse the ambient Prisma transaction client, stay visible in `details.activeRequestTransactions` until the outer boundary finishes, and do not open a second Prisma transaction.
|
|
142
213
|
|
|
143
214
|
`createPrismaPlatformStatusSnapshot(...)` and `PrismaService.createPlatformStatusSnapshot()` expose the same lifecycle contract to diagnostics surfaces:
|
|
144
215
|
|
|
145
|
-
- `readiness.status` is `not-ready` before `onModuleInit()` connects the client, while Prisma is shutting down or stopped,
|
|
216
|
+
- `readiness.status` is `not-ready` before `onModuleInit()` connects the client, while Prisma is shutting down or stopped, when `strictTransactions` is enabled without `$transaction(...)` support, and when the host runtime does not provide `AsyncLocalStorage` while the client supports interactive transactions. In the ALS-unavailable case the readiness reason is `Prisma transaction context requires AsyncLocalStorage support from the host runtime.` and `details.transactionContext` reports `unavailable`; this state is distinct from an ordinary database readiness failure because the Prisma client itself may be connected and otherwise functional.
|
|
146
217
|
- `health.status` is `degraded` while request transactions are draining during shutdown and `unhealthy` after disconnect.
|
|
147
218
|
- `details.activeRequestTransactions`, `details.lifecycleState`, `details.strictTransactions`, `details.supportsTransaction`, and `details.transactionAbortSignalSupport` describe the current request transaction and transaction-capability state.
|
|
148
|
-
- `details.transactionContext: 'als'` identifies the async-local transaction context used by request and service transaction boundaries.
|
|
219
|
+
- `details.transactionContext: 'als'` identifies the async-local transaction context used by request and service transaction boundaries. `details.transactionContext: 'unavailable'` indicates the host runtime did not expose a usable `AsyncLocalStorage`, so `transaction()` and `requestTransaction()` reject before opening a Prisma transaction.
|
|
149
220
|
- `ownership.externallyManaged: false` and `ownership.ownsResources: true` mean the package owns the registered client's `$connect()` / `$disconnect()` lifecycle hooks inside the fluo application lifecycle.
|
|
150
221
|
|
|
222
|
+
When `details.transactionContext` is `unavailable`, the package does not fall back to a synchronous stack-based context because that would lose `current()` across async boundaries. The application owns the fallback boundary: callers that still need database access without a transaction context must invoke the raw `PrismaClient` directly (for example through the `PRISMA_CLIENT` token) and manage their own consistency semantics, or run on a host runtime that provides `AsyncLocalStorage` (Node.js 20+ is the documented path). Treat the `unavailable` readiness state as operationally actionable — surface it in health checks and route traffic away from transaction-dependent handlers until the host provides ALS or the application switches to a non-transactional access path.
|
|
223
|
+
|
|
151
224
|
### Async Configuration and Isolation
|
|
152
225
|
|
|
153
226
|
Use `PrismaModule.forRootAsync(...)` when the Prisma client must be created from injected configuration or another async source. The async factory is resolved once per application container and is not shared across separate bootstraps, even when the same module definition is reused in tests or multi-app processes.
|
|
@@ -167,7 +240,7 @@ PrismaModule.forRootAsync({
|
|
|
167
240
|
|
|
168
241
|
Within one compiled application, downstream providers share the same resolved `PrismaService`, ALS transaction context, and lifecycle-managed client. Separate application containers receive independent factory results, so `$connect` / `$disconnect` ownership and request transaction state remain isolated.
|
|
169
242
|
|
|
170
|
-
Transaction boundaries require host-provided `AsyncLocalStorage` support. `@fluojs/prisma` resolves
|
|
243
|
+
Transaction boundaries require host-provided `AsyncLocalStorage` support. The package manifest declares `engines.node >=20.0.0`, and the root wrapper is the documented Node.js 20+ Prisma integration path. `@fluojs/prisma` resolves ALS through `globalThis.AsyncLocalStorage` when a runtime exposes one, or through the host's `process.getBuiltinModule('node:async_hooks')` boundary on Node.js. If neither path is available or the host builtin lookup fails, `transaction()` and `requestTransaction()` reject before opening a Prisma transaction instead of using a synchronous stack fallback that would lose `current()` across async boundaries; `createPlatformStatusSnapshot().details.transactionContext` reports `unavailable` in that state.
|
|
171
244
|
|
|
172
245
|
### Manual Module Composition
|
|
173
246
|
|
|
@@ -175,7 +248,7 @@ Use `PrismaModule.forRoot(...)` / `forRootAsync(...)` to register Prisma. When y
|
|
|
175
248
|
|
|
176
249
|
```typescript
|
|
177
250
|
import { defineModule } from '@fluojs/runtime';
|
|
178
|
-
import { PrismaModule
|
|
251
|
+
import { PrismaModule } from '@fluojs/prisma';
|
|
179
252
|
import { PrismaClient } from '@prisma/client';
|
|
180
253
|
|
|
181
254
|
const prisma = new PrismaClient();
|
|
@@ -183,7 +256,6 @@ const prisma = new PrismaClient();
|
|
|
183
256
|
class ManualPrismaModule {}
|
|
184
257
|
|
|
185
258
|
defineModule(ManualPrismaModule, {
|
|
186
|
-
exports: [PrismaService, PrismaTransactionInterceptor],
|
|
187
259
|
imports: [PrismaModule.forRoot({ client: prisma })],
|
|
188
260
|
});
|
|
189
261
|
```
|
|
@@ -193,7 +265,7 @@ defineModule(ManualPrismaModule, {
|
|
|
193
265
|
### `PrismaModule`
|
|
194
266
|
|
|
195
267
|
- `PrismaModule.forRoot(options)` / `PrismaModule.forRootAsync(options)`
|
|
196
|
-
- `forRoot(...)` and `forRootAsync(...)` also accept `name` for named/scoped registrations.
|
|
268
|
+
- `forRoot(...)` and `forRootAsync(...)` also accept `name` for named/scoped registrations, and `global?: boolean` for unnamed registrations that should export their providers globally.
|
|
197
269
|
- `forRootAsync(...)` accepts DI-aware Prisma options whose factory returns the client and transaction settings; pass `name` or `global` on the top-level async registration so module identity and visibility are decided before the factory runs.
|
|
198
270
|
- `forRootAsync(...)` resolves options once per application container, preserving client lifecycle and request transaction isolation across separate bootstraps.
|
|
199
271
|
- Supports `strictTransactions: true` to throw if transaction support is missing.
|
|
@@ -206,13 +278,21 @@ defineModule(ManualPrismaModule, {
|
|
|
206
278
|
- `current(): TClient | PrismaTransactionClient<TClient>`
|
|
207
279
|
- Returns the ambient transaction client or the root client.
|
|
208
280
|
- `transaction(fn, options?): Promise<T>`
|
|
209
|
-
- Runs a function within an interactive transaction. If a transaction context is already active, the callback reuses that context; nested transaction options are rejected because no new Prisma transaction boundary is opened.
|
|
281
|
+
- Runs a function within an interactive transaction. If a transaction context is already active, the callback reuses that context; nested transaction options are rejected because no new Prisma transaction boundary is opened. New outer transaction boundaries are rejected once shutdown starts.
|
|
210
282
|
- `requestTransaction(fn, signal?, options?): Promise<T>`
|
|
211
283
|
- Specialized transaction boundary for HTTP request lifecycles. It is abort-aware, drains during shutdown before disconnect, and retries without `signal` when a Prisma client rejects that option. Like `transaction()`, nested calls reuse the active transaction context and reject nested options to avoid silently ignoring transaction settings.
|
|
212
284
|
|
|
213
|
-
|
|
285
|
+
Use `PrismaService<TClient>` when a provider only needs wrapper methods such as `current()`, `transaction(...)`, `requestTransaction(...)`, or `createPlatformStatusSnapshot()`. Use `PrismaServiceFacade<TClient>` for repository injections that call generated Prisma Client delegates directly; the facade forwards those calls to the active transaction client when one exists and to the root client otherwise. `PrismaService.createFacade(...)` is retained as a low-level compatibility helper for module-provider wiring; application code should prefer `PrismaModule.forRoot(...)` / `forRootAsync(...)`.
|
|
286
|
+
|
|
287
|
+
### `Transaction`
|
|
288
|
+
|
|
289
|
+
- Standard TC39 method decorator for service-layer transaction boundaries. It resolves a Prisma service/facade-shaped property by default, accepts an accessor for named clients or ambiguous hosts, and can forward Prisma transaction options to the outer boundary.
|
|
290
|
+
|
|
291
|
+
### `PrismaTransactionInterceptor` (deprecated compatibility)
|
|
214
292
|
|
|
215
|
-
- HTTP interceptor for
|
|
293
|
+
- Request-wide HTTP compatibility interceptor for existing 1.x imports.
|
|
294
|
+
- Delegates to `PrismaService.requestTransaction(...)` and forwards request cancellation.
|
|
295
|
+
- Prefer service `@Transaction()` or an explicit request boundary in new code.
|
|
216
296
|
|
|
217
297
|
### `PRISMA_CLIENT` (Token)
|
|
218
298
|
|
|
@@ -243,6 +323,7 @@ token are deliberately not exported.
|
|
|
243
323
|
- `PrismaModuleOptions`
|
|
244
324
|
- `PrismaClientLike`
|
|
245
325
|
- `PrismaHandleProvider`
|
|
326
|
+
- `PrismaServiceFacade<TClient>`
|
|
246
327
|
- `PrismaTransactionClient<TClient>`
|
|
247
328
|
- `InferPrismaTransactionClient<TClient>`
|
|
248
329
|
- `InferPrismaTransactionOptions<TClient>`
|
|
@@ -250,7 +331,7 @@ token are deliberately not exported.
|
|
|
250
331
|
## Related Packages
|
|
251
332
|
|
|
252
333
|
- `@fluojs/runtime`: Manages the application lifecycle hooks.
|
|
253
|
-
- `@fluojs/http`: Provides
|
|
334
|
+
- `@fluojs/http`: Provides request lifecycle primitives that can be paired with explicit `requestTransaction(...)` boundaries.
|
|
254
335
|
- `@fluojs/terminus`: Provides a health indicator for Prisma.
|
|
255
336
|
|
|
256
337
|
## Example Sources
|
package/dist/module.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { AsyncModuleOptions } from '@fluojs/core';
|
|
2
2
|
import { type ModuleType } from '@fluojs/runtime';
|
|
3
3
|
import type { InferPrismaTransactionClient, InferPrismaTransactionOptions, PrismaClientLike, PrismaModuleOptions } from './types.js';
|
|
4
4
|
type PrismaAsyncModuleOptions<TClient extends PrismaClientLike<TTransactionClient, TTransactionOptions>, TTransactionClient, TTransactionOptions> = AsyncModuleOptions<Omit<PrismaModuleOptions<TClient, TTransactionClient, TTransactionOptions>, 'global' | 'name'>> & {
|
|
@@ -13,7 +13,7 @@ export declare class PrismaModule {
|
|
|
13
13
|
* Registers Prisma providers from static options.
|
|
14
14
|
*
|
|
15
15
|
* @param options Prisma module options with client handle and strict transaction mode.
|
|
16
|
-
* @returns A module definition that exports `PrismaService
|
|
16
|
+
* @returns A module definition that exports `PrismaService`, compatibility interceptor, and related Prisma tokens.
|
|
17
17
|
*/
|
|
18
18
|
static forRoot<TClient extends PrismaClientLike<TTransactionClient, TTransactionOptions>, TTransactionClient = InferPrismaTransactionClient<TClient>, TTransactionOptions = InferPrismaTransactionOptions<TClient>>(options: PrismaModuleOptions<TClient, TTransactionClient, TTransactionOptions>): ModuleType;
|
|
19
19
|
/**
|
package/dist/module.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAS,MAAM,cAAc,CAAC;AAE9D,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAShE,OAAO,KAAK,EACV,4BAA4B,EAC5B,6BAA6B,EAC7B,gBAAgB,EAChB,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAapB,KAAK,wBAAwB,CAC3B,OAAO,SAAS,gBAAgB,CAAC,kBAAkB,EAAE,mBAAmB,CAAC,EACzE,kBAAkB,EAClB,mBAAmB,IACjB,kBAAkB,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC,CAAC,GAAG;IACvH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AA8MF;;GAEG;AACH,qBAAa,YAAY;IACvB;;;;;OAKG;IACH,MAAM,CAAC,OAAO,CACZ,OAAO,SAAS,gBAAgB,CAAC,kBAAkB,EAAE,mBAAmB,CAAC,EACzE,kBAAkB,GAAG,4BAA4B,CAAC,OAAO,CAAC,EAC1D,mBAAmB,GAAG,6BAA6B,CAAC,OAAO,CAAC,EAE5D,OAAO,EAAE,mBAAmB,CAAC,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,CAAC,GAC7E,UAAU;IAIb;;;;;OAKG;IACH,MAAM,CAAC,YAAY,CACjB,OAAO,SAAS,gBAAgB,CAAC,kBAAkB,EAAE,mBAAmB,CAAC,EACzE,kBAAkB,GAAG,4BAA4B,CAAC,OAAO,CAAC,EAC1D,mBAAmB,GAAG,6BAA6B,CAAC,OAAO,CAAC,EAE5D,OAAO,EAAE,wBAAwB,CAAC,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,CAAC,GAClF,UAAU;CAGd"}
|
package/dist/module.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Inject } from '@fluojs/core';
|
|
2
1
|
import { defineModule } from '@fluojs/runtime';
|
|
3
2
|
import { PrismaService } from './service.js';
|
|
4
3
|
import { getPrismaClientToken, getPrismaOptionsToken, getPrismaServiceToken } from './tokens.js';
|
|
@@ -35,16 +34,12 @@ function normalizePrismaModuleOptions(options) {
|
|
|
35
34
|
strictTransactions: options.strictTransactions ?? false
|
|
36
35
|
};
|
|
37
36
|
}
|
|
38
|
-
function
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return [NamedPrismaService, {
|
|
45
|
-
provide: serviceToken,
|
|
46
|
-
useExisting: NamedPrismaService
|
|
47
|
-
}];
|
|
37
|
+
function createPrismaServiceProvider(provide, clientToken, optionsToken) {
|
|
38
|
+
return {
|
|
39
|
+
inject: [clientToken, optionsToken],
|
|
40
|
+
provide,
|
|
41
|
+
useFactory: (client, serviceOptions) => PrismaService.createFacade(client, serviceOptions)
|
|
42
|
+
};
|
|
48
43
|
}
|
|
49
44
|
function createPrismaRuntimeProviders(normalizedOptionsProvider, name) {
|
|
50
45
|
const normalizedOptionsToken = getPrismaNormalizedOptionsToken(name);
|
|
@@ -60,10 +55,10 @@ function createPrismaRuntimeProviders(normalizedOptionsProvider, name) {
|
|
|
60
55
|
useFactory: options => ({
|
|
61
56
|
strictTransactions: options.strictTransactions
|
|
62
57
|
})
|
|
63
|
-
}, ...(name === undefined ? [PrismaService, {
|
|
58
|
+
}, ...(name === undefined ? [createPrismaServiceProvider(PrismaService, clientToken, optionsToken), {
|
|
64
59
|
provide: getPrismaServiceToken(),
|
|
65
60
|
useExisting: PrismaService
|
|
66
|
-
}, PrismaTransactionInterceptor] :
|
|
61
|
+
}, PrismaTransactionInterceptor] : [createPrismaServiceProvider(getPrismaServiceToken(name), clientToken, optionsToken)])];
|
|
67
62
|
}
|
|
68
63
|
function buildPrismaModule(options) {
|
|
69
64
|
class PrismaRootModuleDefinition {}
|
|
@@ -115,7 +110,7 @@ export class PrismaModule {
|
|
|
115
110
|
* Registers Prisma providers from static options.
|
|
116
111
|
*
|
|
117
112
|
* @param options Prisma module options with client handle and strict transaction mode.
|
|
118
|
-
* @returns A module definition that exports `PrismaService
|
|
113
|
+
* @returns A module definition that exports `PrismaService`, compatibility interceptor, and related Prisma tokens.
|
|
119
114
|
*/
|
|
120
115
|
static forRoot(options) {
|
|
121
116
|
return buildPrismaModule(options);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Marks an internal Prisma service or facade handle for default `@Transaction()` resolution.
|
|
3
|
+
*
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
export declare function markPrismaServiceHandle<THandle extends object>(handle: THandle): THandle;
|
|
7
|
+
/**
|
|
8
|
+
* Checks whether a value is an internally marked Prisma service or facade handle.
|
|
9
|
+
*
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
export declare function isPrismaServiceHandle(value: unknown): value is object;
|
|
13
|
+
//# sourceMappingURL=prisma-service-brand.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prisma-service-brand.d.ts","sourceRoot":"","sources":["../src/prisma-service-brand.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,SAAS,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAIxF;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAMrE"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const brandedPrismaServiceHandles = new WeakSet();
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Marks an internal Prisma service or facade handle for default `@Transaction()` resolution.
|
|
5
|
+
*
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export function markPrismaServiceHandle(handle) {
|
|
9
|
+
brandedPrismaServiceHandles.add(handle);
|
|
10
|
+
return handle;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Checks whether a value is an internally marked Prisma service or facade handle.
|
|
15
|
+
*
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
export function isPrismaServiceHandle(value) {
|
|
19
|
+
if (typeof value !== 'object' && typeof value !== 'function' || value === null) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
return brandedPrismaServiceHandles.has(value);
|
|
23
|
+
}
|
package/dist/service.d.ts
CHANGED
|
@@ -15,9 +15,24 @@ export declare class PrismaService<TClient extends PrismaClientLike<TTransaction
|
|
|
15
15
|
private readonly serviceOptions;
|
|
16
16
|
private readonly transactions;
|
|
17
17
|
private readonly activeRequestTransactions;
|
|
18
|
+
private readonly activeTransactionBoundaries;
|
|
18
19
|
private transactionAbortSignalSupport;
|
|
19
20
|
private lifecycleState;
|
|
20
21
|
constructor(client: TClient, serviceOptions?: PrismaServiceOptions);
|
|
22
|
+
/**
|
|
23
|
+
* Creates the low-level DI facade that forwards unknown Prisma API properties to the ambient `current()` client.
|
|
24
|
+
*
|
|
25
|
+
* @remarks
|
|
26
|
+
* This compatibility helper is used by `PrismaModule` provider wiring. Application code should prefer
|
|
27
|
+
* `PrismaModule.forRoot(...)` or `PrismaModule.forRootAsync(...)`, then type injected repository handles as
|
|
28
|
+
* `PrismaServiceFacade<TClient>` when direct generated Prisma delegates are needed.
|
|
29
|
+
*
|
|
30
|
+
* @param client Root Prisma client registered in the module.
|
|
31
|
+
* @param serviceOptions Runtime transaction options consumed by the Fluo wrapper.
|
|
32
|
+
* @returns A transaction-aware facade that exposes wrapper methods plus the root Prisma client surface.
|
|
33
|
+
*/
|
|
34
|
+
static createFacade<TClient extends PrismaClientLike<TTransactionClient, TTransactionOptions>, TTransactionClient = InferPrismaTransactionClient<TClient>, TTransactionOptions = InferPrismaTransactionOptions<TClient>>(client: TClient, serviceOptions?: PrismaServiceOptions): PrismaServiceFacade<TClient, TTransactionClient, TTransactionOptions>;
|
|
35
|
+
private installCurrentClientFacade;
|
|
21
36
|
/**
|
|
22
37
|
* Returns the active Prisma handle for the current async context.
|
|
23
38
|
*
|
|
@@ -80,6 +95,7 @@ export declare class PrismaService<TClient extends PrismaClientLike<TTransaction
|
|
|
80
95
|
private runWithRequestTransactionClient;
|
|
81
96
|
private runNestedRequestTransaction;
|
|
82
97
|
private assertRequestTransactionsAvailable;
|
|
98
|
+
private assertTransactionBoundariesAvailable;
|
|
83
99
|
private assertTransactionContextAvailable;
|
|
84
100
|
private throwIfRequestAborted;
|
|
85
101
|
private runRequestTransactionWithAbortSignal;
|
|
@@ -90,6 +106,21 @@ export declare class PrismaService<TClient extends PrismaClientLike<TTransaction
|
|
|
90
106
|
private withTransactionAbortSignal;
|
|
91
107
|
private trackActiveRequestTransaction;
|
|
92
108
|
private untrackActiveRequestTransaction;
|
|
109
|
+
private trackActiveTransactionBoundary;
|
|
110
|
+
private untrackActiveTransactionBoundary;
|
|
93
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Injection-facing Prisma facade type that combines the Fluo wrapper methods with the registered Prisma client surface.
|
|
114
|
+
*
|
|
115
|
+
* @remarks
|
|
116
|
+
* `PrismaModule` resolves `PrismaService` to a facade that forwards unknown properties to `current()`. Use this type in
|
|
117
|
+
* repositories that call generated Prisma delegates directly, and use `PrismaService<TClient>` when only wrapper methods
|
|
118
|
+
* (`current()`, `transaction(...)`, `requestTransaction(...)`, and status snapshots) are needed.
|
|
119
|
+
*
|
|
120
|
+
* @typeParam TClient Root Prisma client shape registered in the module.
|
|
121
|
+
* @typeParam TTransactionClient Transaction-scoped client resolved inside `$transaction(...)` callbacks.
|
|
122
|
+
* @typeParam TTransactionOptions Options forwarded to Prisma interactive transactions.
|
|
123
|
+
*/
|
|
124
|
+
export type PrismaServiceFacade<TClient extends PrismaClientLike<TTransactionClient, TTransactionOptions>, TTransactionClient = InferPrismaTransactionClient<TClient>, TTransactionOptions = InferPrismaTransactionOptions<TClient>> = PrismaService<TClient, TTransactionClient, TTransactionOptions> & Omit<TClient, keyof PrismaService<TClient, TTransactionClient, TTransactionOptions>>;
|
|
94
125
|
export {};
|
|
95
126
|
//# sourceMappingURL=service.d.ts.map
|
package/dist/service.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
|