@fluojs/prisma 1.0.2 → 1.1.0

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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  <p><a href="./README.md"><kbd>English</kbd></a> <strong><kbd>한국어</kbd></strong></p>
4
4
 
5
- fluo 애플리케이션을 위한 Prisma 라이프사이클 및 ALS 기반 트랜잭션 컨텍스트 모듈입니다. Prisma 클라이언트를 모듈 시스템에 연결하여 자동 연결 관리 요청 범위 트랜잭션을 제공합니다.
5
+ fluo 애플리케이션을 위한 Prisma lifecycle 및 ALS 기반 transaction context입니다. `PrismaClient`를 모듈 시스템에 연결하고 자동 연결 관리와 요청 범위 트랜잭션을 제공합니다.
6
6
 
7
7
  ## 목차
8
8
 
@@ -10,10 +10,9 @@ fluo 애플리케이션을 위한 Prisma 라이프사이클 및 ALS 기반 트
10
10
  - [사용 시점](#사용-시점)
11
11
  - [빠른 시작](#빠른-시작)
12
12
  - [공통 패턴](#공통-패턴)
13
- - [PrismaService와 current()](#prismaservice와-current)
13
+ - [서비스 트랜잭션 경계 (@Transaction)](#서비스-트랜잭션-경계-transaction)
14
14
  - [여러 클라이언트를 위한 이름 있는 등록](#여러-클라이언트를-위한-이름-있는-등록)
15
- - [수동 트랜잭션](#수동-트랜잭션)
16
- - [자동 요청 트랜잭션](#자동-요청-트랜잭션)
15
+ - [수동 트랜잭션과 current()](#수동-트랜잭션과-current)
17
16
  - [종료와 status 계약](#종료와-status-계약)
18
17
  - [비동기 설정과 격리](#비동기-설정과-격리)
19
18
  - [수동 모듈 조합](#수동-모듈-조합)
@@ -56,33 +55,52 @@ class AppModule {}
56
55
 
57
56
  ## 공통 패턴
58
57
 
59
- ### PrismaService와 current()
58
+ ### 서비스 트랜잭션 경계 (@Transaction)
60
59
 
61
- `PrismaService`는 Prisma와 상호작용하는 기본 방법입니다. `current()` 메서드는 트랜잭션 범위 내에 있으면 자동으로 트랜잭션용 클라이언트를, 그렇지 않으면 루트 클라이언트를 반환합니다.
60
+ `@Transaction()` 데코레이터는 서비스 레이어에서 트랜잭션 경계를 정의하는 권장 방법입니다. 데코레이터가 적용된 메서드 내부에서 발생하는 모든 리포지토리 호출은 동일한 Prisma 트랜잭션을 공유합니다.
62
61
 
63
62
  ```typescript
64
63
  import { Inject } from '@fluojs/core';
65
- import { PrismaService } from '@fluojs/prisma';
64
+ import { PrismaService, Transaction, type PrismaServiceFacade } from '@fluojs/prisma';
66
65
  import { PrismaClient } from '@prisma/client';
66
+ import { UserRepository } from './user.repository';
67
+
68
+ export class UserService {
69
+ constructor(private readonly repo: UserRepository) {}
70
+
71
+ @Transaction()
72
+ async onboardUser(dto: CreateUserDto) {
73
+ const user = await this.repo.create(dto);
74
+ await this.repo.initProfile(user.id);
75
+ return user;
76
+ }
77
+ }
67
78
 
68
79
  @Inject(PrismaService)
69
80
  export class UserRepository {
70
- constructor(private readonly prisma: PrismaService<PrismaClient>) {}
81
+ constructor(private readonly prisma: PrismaServiceFacade<PrismaClient>) {}
82
+
83
+ async create(data: any) {
84
+ // facade 타입은 표준 PrismaClient delegate를 노출합니다.
85
+ // @Transaction() 내부에서 호출되면 자동으로 활성 트랜잭션에 참여합니다.
86
+ return this.prisma.user.create({ data });
87
+ }
71
88
 
72
- async findById(id: string) {
73
- // current()는 생성된 Prisma 타입과 자동완성을 그대로 유지합니다.
74
- return this.prisma.current().user.findUnique({ where: { id } });
89
+ async initProfile(userId: string) {
90
+ return this.prisma.profile.create({ data: { userId } });
75
91
  }
76
92
  }
77
93
  ```
78
94
 
95
+ `@Transaction()` 메서드 호출은 재진입(reentrant)이 가능합니다. 데코레이터가 적용된 메서드가 다른 데코레이터 적용 메서드를 호출하더라도 하나의 동일한 Prisma 트랜잭션 안에서 실행됩니다.
96
+
79
97
  ### 여러 클라이언트를 위한 이름 있는 등록
80
98
 
81
- 하나의 애플리케이션 컨테이너 안에서 여러 Prisma Client가 필요하다면 각 등록에 명시적인 `name`을 부여하고 `getPrismaServiceToken(name)`으로 대응되는 토큰을 주입하세요.
99
+ 하나의 애플리케이션 컨테이너 안에서 여러 Prisma Client가 필요하다면 각 등록에 명시적인 `name`을 부여하고 `getPrismaServiceToken(name)`으로 대응되는 토큰을 주입하세요. 이름 있는 클라이언트를 사용할 때는 `@Transaction()`에 해당 서비스로 접근할 수 있는 accessor를 전달하세요.
82
100
 
83
101
  ```typescript
84
102
  import { Inject } from '@fluojs/core';
85
- import { PrismaModule, PrismaService, getPrismaServiceToken } from '@fluojs/prisma';
103
+ import { PrismaModule, PrismaService, getPrismaServiceToken, Transaction, type PrismaServiceFacade } from '@fluojs/prisma';
86
104
 
87
105
  const usersPrismaModule = PrismaModule.forRoot({ name: 'users', client: usersPrisma });
88
106
  const analyticsPrismaModule = PrismaModule.forRoot({ name: 'analytics', client: analyticsPrisma });
@@ -90,55 +108,57 @@ const analyticsPrismaModule = PrismaModule.forRoot({ name: 'analytics', client:
90
108
  @Inject(getPrismaServiceToken('users'), getPrismaServiceToken('analytics'))
91
109
  export class MultiDatabaseService {
92
110
  constructor(
93
- private readonly users: PrismaService<typeof usersPrisma>,
94
- private readonly analytics: PrismaService<typeof analyticsPrisma>,
111
+ private readonly users: PrismaServiceFacade<typeof usersPrisma>,
112
+ private readonly analytics: PrismaServiceFacade<typeof analyticsPrisma>,
95
113
  ) {}
96
114
 
97
- async loadDashboard(userId: string) {
98
- const user = await this.users.current().user.findUnique({ where: { id: userId } });
99
- const summary = await this.analytics.current().report.findMany();
100
- return { summary, user };
115
+ @Transaction((self) => self.users)
116
+ async updateAndLog(userId: string, data: any) {
117
+ const user = await this.users.user.update({ where: { id: userId }, data });
118
+ // 호출은 'analytics'가 별도로 트랜잭션을 열지 않는 한 'users' 트랜잭션 밖에 있습니다.
119
+ await this.analytics.report.create({ data: { event: 'update', userId } });
120
+ return user;
101
121
  }
102
122
  }
103
123
  ```
104
124
 
105
- 이름 없는 등록은 `PrismaService`, `PRISMA_CLIENT`, `PRISMA_OPTIONS`, `PrismaTransactionInterceptor`를 위한 기본 단일 클라이언트 경로로 유지됩니다. 같은 컨테이너에 여러 Prisma Client를 등록할 때는 토큰 해석이 명시적으로 유지되도록 추가 클라이언트마다 이름을 사용하세요.
106
-
107
- ### 수동 트랜잭션
125
+ ### 수동 트랜잭션과 current()
108
126
 
109
- `prisma.transaction()`을 사용하여 대화형 트랜잭션 블록을 생성합니다. 블록 내부의 모든 `current()` 호출은 트랜잭션 범위의 클라이언트를 사용합니다.
127
+ `PrismaService`는 트랜잭션 범위 내에 있으면 자동으로 트랜잭션용 클라이언트를, 그렇지 않으면 루트 클라이언트를 반환하는 `current()` 메서드를 제공합니다. 외부 라이브러리에 클라이언트를 전달하거나 복잡한 수동 트랜잭션 처리가 필요한 경우 escape hatch로 사용하세요.
110
128
 
111
129
  ```typescript
112
- await this.prisma.transaction(async () => {
113
- const user = await this.prisma.current().user.create({ data });
114
- await this.prisma.current().profile.create({ data: { userId: user.id } });
115
- });
116
- ```
130
+ import { Inject } from '@fluojs/core';
131
+ import { PrismaService } from '@fluojs/prisma';
132
+ import { PrismaClient } from '@prisma/client';
117
133
 
118
- 이미 활성 트랜잭션 컨텍스트가 있는 상태에서 `transaction()`을 호출하면 `PrismaService`는 중첩 Prisma 트랜잭션을 새로 열지 않고 활성 트랜잭션 클라이언트를 재사용합니다. 중첩 호출에는 isolation level 같은 트랜잭션 옵션을 전달하면 안 됩니다. 활성 컨텍스트에서 옵션을 제공하면 ambient transaction을 재사용하는 동안 호출자의 의도를 조용히 버리지 않도록 예외로 거부합니다.
134
+ @Inject(PrismaService)
135
+ export class AdvancedRepository {
136
+ constructor(private readonly prisma: PrismaService<PrismaClient>) {}
119
137
 
120
- ### 자동 요청 트랜잭션
138
+ async customOperation() {
139
+ const tx = this.prisma.current();
140
+ // fluo가 자동으로 감싸지 않는 작업을 수행하거나,
141
+ // PrismaClient를 직접 기대하는 외부 유틸리티에 전달할 때 tx를 사용하세요.
142
+ return tx.user.findMany();
143
+ }
144
+ }
145
+ ```
121
146
 
122
- 컨트롤러나 메서드에 `PrismaTransactionInterceptor`를 적용하면 전체 요청을 자동으로 트랜잭션으로 감쌉니다.
147
+ 수동 대화형 트랜잭션 블록에는 `prisma.transaction()`을 사용하세요:
123
148
 
124
149
  ```typescript
125
- import { Post, UseInterceptors } from '@fluojs/http';
126
- import { PrismaTransactionInterceptor } from '@fluojs/prisma';
127
-
128
- @UseInterceptors(PrismaTransactionInterceptor)
129
- class UserController {
130
- @Post()
131
- async create() {
132
- // 이후 PrismaService.current()를 사용하는 모든 리포지토리 호출은 이 트랜잭션을 공유합니다.
133
- }
134
- }
150
+ await this.prisma.transaction(async () => {
151
+ const tx = this.prisma.current();
152
+ const user = await tx.user.create({ data });
153
+ await tx.profile.create({ data: { userId: user.id } });
154
+ });
135
155
  ```
136
156
 
137
- `PrismaTransactionInterceptor`는 기본 이름 없는 `PrismaService`를 대상으로 합니다. 이름 있는 다중 클라이언트 등록에서는 해당 이름의 `PrismaService`를 주입한 필요한 위치에서 명시적으로 `transaction()` / `requestTransaction()` 경계를 여세요.
157
+ 이미 활성 트랜잭션 컨텍스트가 있는 상태에서 `transaction()`을 호출하면 `PrismaService`는 중첩 Prisma 트랜잭션을 새로 열지 않고 활성 트랜잭션 클라이언트를 재사용합니다. 중첩 호출에는 isolation level 같은 트랜잭션 옵션을 전달하면 안 됩니다. 활성 컨텍스트에서 옵션을 제공하면 ambient transaction 재사용하는 동안 호출자의 의도를 조용히 버리지 않도록 예외로 거부합니다.
138
158
 
139
159
  ### 종료와 status 계약
140
160
 
141
- `PrismaService.requestTransaction(...)`은 정상 serving 전과 중에는 사용할 수 있지만, 애플리케이션 종료가 시작된 뒤에는 새 요청 범위 트랜잭션을 거부합니다. 종료 중에는 열린 요청 트랜잭션을 abort하고, 바깥 트랜잭션 경계가 settle될 때까지 추적한 뒤, 모두 drain한 다음 `$disconnect()`를 실행합니다. 기존 수동 `transaction(...)` 경계 안에서 열린 중첩 `requestTransaction(...)` 호출도 여기에 포함됩니다. 호출은 ambient Prisma transaction client를 재사용하고, 바깥 경계가 끝날 때까지 `details.activeRequestTransactions`에 남으며, 두 번째 Prisma 트랜잭션을 열지 않습니다.
161
+ `PrismaService.requestTransaction(...)`은 정상 serving 전과 중에는 사용할 수 있지만, 애플리케이션 shutdown이 시작된 뒤에는 새 요청 범위 트랜잭션을 거부합니다. 종료 중에는 열린 요청 트랜잭션을 abort하고, 가장 바깥 transaction boundary가 settle될 때까지 추적한 다음 `$disconnect()` 실행 전에 drain합니다. 기존 수동 `transaction(...)` boundary 안에서 열린 중첩 `requestTransaction(...)` 호출도 동일합니다. 해당 호출은 ambient Prisma transaction client를 재사용하고, 바깥 boundary가 끝날 때까지 `details.activeRequestTransactions`에 표시되며, 두 번째 Prisma transaction을 열지 않습니다.
142
162
 
143
163
  `createPrismaPlatformStatusSnapshot(...)`와 `PrismaService.createPlatformStatusSnapshot()`은 같은 라이프사이클 계약을 진단 surface에 노출합니다.
144
164
 
@@ -175,7 +195,7 @@ PrismaModule.forRootAsync({
175
195
 
176
196
  ```typescript
177
197
  import { defineModule } from '@fluojs/runtime';
178
- import { PrismaModule, PrismaService, PrismaTransactionInterceptor } from '@fluojs/prisma';
198
+ import { PrismaModule } from '@fluojs/prisma';
179
199
  import { PrismaClient } from '@prisma/client';
180
200
 
181
201
  const prisma = new PrismaClient();
@@ -183,7 +203,6 @@ const prisma = new PrismaClient();
183
203
  class ManualPrismaModule {}
184
204
 
185
205
  defineModule(ManualPrismaModule, {
186
- exports: [PrismaService, PrismaTransactionInterceptor],
187
206
  imports: [PrismaModule.forRoot({ client: prisma })],
188
207
  });
189
208
  ```
@@ -210,9 +229,11 @@ defineModule(ManualPrismaModule, {
210
229
  - `requestTransaction(fn, signal?, options?): Promise<T>`
211
230
  - HTTP 요청 라이프사이클에 특화된 트랜잭션 경계를 실행합니다. Abort를 인식하고, shutdown 중에는 disconnect 전에 열린 요청 트랜잭션을 drain하며, Prisma client가 `signal` 옵션을 거부하면 해당 옵션 없이 재시도합니다. `transaction()`과 마찬가지로 중첩 호출은 활성 트랜잭션 컨텍스트를 재사용하고, 트랜잭션 설정을 조용히 무시하지 않도록 중첩 옵션을 거부합니다.
212
231
 
213
- ### `PrismaTransactionInterceptor`
232
+ Provider가 `current()`, `transaction(...)`, `requestTransaction(...)`, `createPlatformStatusSnapshot()` 같은 wrapper 메서드만 필요로 한다면 `PrismaService<TClient>`를 사용하세요. 생성된 Prisma Client delegate를 직접 호출하는 repository 주입에는 `PrismaServiceFacade<TClient>`를 사용하세요. 이 facade는 활성 트랜잭션이 있으면 해당 트랜잭션 client로, 없으면 root client로 호출을 전달합니다. `PrismaService.createFacade(...)`는 module-provider wiring을 위한 저수준 compatibility helper로 유지되며, 애플리케이션 코드는 `PrismaModule.forRoot(...)` / `forRootAsync(...)`를 우선 사용해야 합니다.
233
+
234
+ ### `Transaction`
214
235
 
215
- - 기본 이름 없는 `PrismaService` 등록을 위한 HTTP interceptor입니다. 요청 handler를 `PrismaService.requestTransaction(...)`으로 감싸 downstream `current()` 호출이 같은 transaction client를 공유하게 합니다.
236
+ - 서비스 계층 트랜잭션 경계를 위한 표준 TC39 method decorator입니다. 기본적으로 ambient `PrismaService`를 resolve하고, 이름 있는 client에는 accessor를 받을 수 있으며, 외부 경계에는 Prisma transaction option을 전달할 수 있습니다.
216
237
 
217
238
  ### `PRISMA_CLIENT` (Token)
218
239
 
@@ -241,6 +262,7 @@ defineModule(ManualPrismaModule, {
241
262
  - `PrismaModuleOptions`
242
263
  - `PrismaClientLike`
243
264
  - `PrismaHandleProvider`
265
+ - `PrismaServiceFacade<TClient>`
244
266
  - `PrismaTransactionClient<TClient>`
245
267
  - `InferPrismaTransactionClient<TClient>`
246
268
  - `InferPrismaTransactionOptions<TClient>`
@@ -248,7 +270,7 @@ defineModule(ManualPrismaModule, {
248
270
  ## 관련 패키지
249
271
 
250
272
  - `@fluojs/runtime`: 애플리케이션 라이프사이클 훅을 관리합니다.
251
- - `@fluojs/http`: 인터셉터 시스템을 제공합니다.
273
+ - `@fluojs/http`: 명시적 `requestTransaction(...)` 경계와 함께 사용할 수 있는 요청 라이프사이클 primitive를 제공합니다.
252
274
  - `@fluojs/terminus`: Prisma를 위한 헬스 인디케이터를 제공합니다.
253
275
 
254
276
  ## 예제 소스
package/README.md CHANGED
@@ -10,10 +10,9 @@ 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
- - [PrismaService and current()](#prismaservice-and-current)
13
+ - [Service Transaction Boundary (@Transaction)](#service-transaction-boundary-transaction)
14
14
  - [Named Registrations for Multiple Clients](#named-registrations-for-multiple-clients)
15
- - [Manual Transactions](#manual-transactions)
16
- - [Automatic Request Transactions](#automatic-request-transactions)
15
+ - [Manual Transactions and current()](#manual-transactions-and-current)
17
16
  - [Shutdown and Status Contracts](#shutdown-and-status-contracts)
18
17
  - [Async Configuration and Isolation](#async-configuration-and-isolation)
19
18
  - [Manual Module Composition](#manual-module-composition)
@@ -56,33 +55,52 @@ class AppModule {}
56
55
 
57
56
  ## Common Patterns
58
57
 
59
- ### PrismaService and current()
58
+ ### Service Transaction Boundary (@Transaction)
60
59
 
61
- The `PrismaService` is the primary way to interact with Prisma. Its `current()` method automatically returns the active transaction client if inside a transaction scope, or the root client otherwise.
60
+ 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
61
 
63
62
  ```typescript
64
63
  import { Inject } from '@fluojs/core';
65
- import { PrismaService } from '@fluojs/prisma';
64
+ import { PrismaService, Transaction, type PrismaServiceFacade } from '@fluojs/prisma';
66
65
  import { PrismaClient } from '@prisma/client';
66
+ import { UserRepository } from './user.repository';
67
+
68
+ export class UserService {
69
+ constructor(private readonly repo: UserRepository) {}
70
+
71
+ @Transaction()
72
+ async onboardUser(dto: CreateUserDto) {
73
+ const user = await this.repo.create(dto);
74
+ await this.repo.initProfile(user.id);
75
+ return user;
76
+ }
77
+ }
67
78
 
68
79
  @Inject(PrismaService)
69
80
  export class UserRepository {
70
- constructor(private readonly prisma: PrismaService<PrismaClient>) {}
81
+ constructor(private readonly prisma: PrismaServiceFacade<PrismaClient>) {}
82
+
83
+ async create(data: any) {
84
+ // The facade type exposes standard PrismaClient delegates.
85
+ // When called inside @Transaction(), they automatically participate in the ambient transaction.
86
+ return this.prisma.user.create({ data });
87
+ }
71
88
 
72
- async findById(id: string) {
73
- // current() preserves your generated Prisma types and autocomplete
74
- return this.prisma.current().user.findUnique({ where: { id } });
89
+ async initProfile(userId: string) {
90
+ return this.prisma.profile.create({ data: { userId } });
75
91
  }
76
92
  }
77
93
  ```
78
94
 
95
+ Calls to `@Transaction()` methods are reentrant. If a decorated method calls another decorated method, they share the same underlying Prisma transaction.
96
+
79
97
  ### Named Registrations for Multiple Clients
80
98
 
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)`.
99
+ 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.
82
100
 
83
101
  ```typescript
84
102
  import { Inject } from '@fluojs/core';
85
- import { PrismaModule, PrismaService, getPrismaServiceToken } from '@fluojs/prisma';
103
+ import { PrismaModule, PrismaService, getPrismaServiceToken, Transaction, type PrismaServiceFacade } from '@fluojs/prisma';
86
104
 
87
105
  const usersPrismaModule = PrismaModule.forRoot({ name: 'users', client: usersPrisma });
88
106
  const analyticsPrismaModule = PrismaModule.forRoot({ name: 'analytics', client: analyticsPrisma });
@@ -90,51 +108,54 @@ const analyticsPrismaModule = PrismaModule.forRoot({ name: 'analytics', client:
90
108
  @Inject(getPrismaServiceToken('users'), getPrismaServiceToken('analytics'))
91
109
  export class MultiDatabaseService {
92
110
  constructor(
93
- private readonly users: PrismaService<typeof usersPrisma>,
94
- private readonly analytics: PrismaService<typeof analyticsPrisma>,
111
+ private readonly users: PrismaServiceFacade<typeof usersPrisma>,
112
+ private readonly analytics: PrismaServiceFacade<typeof analyticsPrisma>,
95
113
  ) {}
96
114
 
97
- async loadDashboard(userId: string) {
98
- const user = await this.users.current().user.findUnique({ where: { id: userId } });
99
- const summary = await this.analytics.current().report.findMany();
100
- return { summary, user };
115
+ @Transaction((self) => self.users)
116
+ async updateAndLog(userId: string, data: any) {
117
+ const user = await this.users.user.update({ where: { id: userId }, data });
118
+ // This call is outside the 'users' transaction unless 'analytics' also opens one
119
+ await this.analytics.report.create({ data: { event: 'update', userId } });
120
+ return user;
101
121
  }
102
122
  }
103
123
  ```
104
124
 
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
125
 
107
- ### Manual Transactions
126
+ ### Manual Transactions and current()
108
127
 
109
- Use `prisma.transaction()` to create an interactive transaction block. Any calls to `current()` inside the block will use the transaction-scoped client.
128
+ 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
129
 
111
130
  ```typescript
112
- await this.prisma.transaction(async () => {
113
- const user = await this.prisma.current().user.create({ data });
114
- await this.prisma.current().profile.create({ data: { userId: user.id } });
115
- });
116
- ```
131
+ import { Inject } from '@fluojs/core';
132
+ import { PrismaService } from '@fluojs/prisma';
133
+ import { PrismaClient } from '@prisma/client';
117
134
 
118
- 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.
135
+ @Inject(PrismaService)
136
+ export class AdvancedRepository {
137
+ constructor(private readonly prisma: PrismaService<PrismaClient>) {}
119
138
 
120
- ### Automatic Request Transactions
139
+ async customOperation() {
140
+ const tx = this.prisma.current();
141
+ // Use tx for operations that fluo doesn't automatically wrap,
142
+ // or when passing to an external utility that expects a PrismaClient.
143
+ return tx.user.findMany();
144
+ }
145
+ }
146
+ ```
121
147
 
122
- Apply the `PrismaTransactionInterceptor` to a controller or method to wrap the entire request in a transaction automatically.
148
+ Use `prisma.transaction()` for manual interactive transaction blocks:
123
149
 
124
150
  ```typescript
125
- import { Post, UseInterceptors } from '@fluojs/http';
126
- import { PrismaTransactionInterceptor } from '@fluojs/prisma';
127
-
128
- @UseInterceptors(PrismaTransactionInterceptor)
129
- class UserController {
130
- @Post()
131
- async create() {
132
- // All downstream repository calls via PrismaService.current() share this tx
133
- }
134
- }
151
+ await this.prisma.transaction(async () => {
152
+ const tx = this.prisma.current();
153
+ const user = await tx.user.create({ data });
154
+ await tx.profile.create({ data: { userId: user.id } });
155
+ });
135
156
  ```
136
157
 
137
- `PrismaTransactionInterceptor` targets the default unnamed `PrismaService`. For named multi-client registrations, inject the corresponding named `PrismaService` and open explicit `transaction()` / `requestTransaction()` boundaries where needed.
158
+ 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
159
 
139
160
  ### Shutdown and Status Contracts
140
161
 
@@ -175,7 +196,7 @@ Use `PrismaModule.forRoot(...)` / `forRootAsync(...)` to register Prisma. When y
175
196
 
176
197
  ```typescript
177
198
  import { defineModule } from '@fluojs/runtime';
178
- import { PrismaModule, PrismaService, PrismaTransactionInterceptor } from '@fluojs/prisma';
199
+ import { PrismaModule } from '@fluojs/prisma';
179
200
  import { PrismaClient } from '@prisma/client';
180
201
 
181
202
  const prisma = new PrismaClient();
@@ -183,7 +204,6 @@ const prisma = new PrismaClient();
183
204
  class ManualPrismaModule {}
184
205
 
185
206
  defineModule(ManualPrismaModule, {
186
- exports: [PrismaService, PrismaTransactionInterceptor],
187
207
  imports: [PrismaModule.forRoot({ client: prisma })],
188
208
  });
189
209
  ```
@@ -210,9 +230,11 @@ defineModule(ManualPrismaModule, {
210
230
  - `requestTransaction(fn, signal?, options?): Promise<T>`
211
231
  - 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
232
 
213
- ### `PrismaTransactionInterceptor`
233
+ 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(...)`.
234
+
235
+ ### `Transaction`
214
236
 
215
- - HTTP interceptor for the default unnamed `PrismaService` registration. It wraps a request handler in `PrismaService.requestTransaction(...)` so downstream `current()` calls share the same transaction client.
237
+ - Standard TC39 method decorator for service-layer transaction boundaries. It resolves the ambient `PrismaService` by default, accepts an accessor for named clients, and can forward Prisma transaction options to the outer boundary.
216
238
 
217
239
  ### `PRISMA_CLIENT` (Token)
218
240
 
@@ -243,6 +265,7 @@ token are deliberately not exported.
243
265
  - `PrismaModuleOptions`
244
266
  - `PrismaClientLike`
245
267
  - `PrismaHandleProvider`
268
+ - `PrismaServiceFacade<TClient>`
246
269
  - `PrismaTransactionClient<TClient>`
247
270
  - `InferPrismaTransactionClient<TClient>`
248
271
  - `InferPrismaTransactionOptions<TClient>`
@@ -250,7 +273,7 @@ token are deliberately not exported.
250
273
  ## Related Packages
251
274
 
252
275
  - `@fluojs/runtime`: Manages the application lifecycle hooks.
253
- - `@fluojs/http`: Provides the interceptor system.
276
+ - `@fluojs/http`: Provides request lifecycle primitives that can be paired with explicit `requestTransaction(...)` boundaries.
254
277
  - `@fluojs/terminus`: Provides a health indicator for Prisma.
255
278
 
256
279
  ## Example Sources
package/dist/module.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type AsyncModuleOptions } from '@fluojs/core';
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` and `PrismaTransactionInterceptor`.
16
+ * @returns A module definition that exports `PrismaService` 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
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,kBAAkB,EAAc,MAAM,cAAc,CAAC;AAE3E,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;AA0LF;;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"}
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;AAQhE,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;AAiMF;;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,8 +1,6 @@
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';
5
- import { PrismaTransactionInterceptor } from './transaction.js';
6
4
  const PRISMA_NORMALIZED_OPTIONS = Symbol('fluo.prisma.normalized-options');
7
5
  function isObjectLike(value) {
8
6
  return typeof value === 'object' && value !== null || typeof value === 'function';
@@ -35,16 +33,12 @@ function normalizePrismaModuleOptions(options) {
35
33
  strictTransactions: options.strictTransactions ?? false
36
34
  };
37
35
  }
38
- function createNamedPrismaServiceProvider(name) {
39
- const clientToken = getPrismaClientToken(name);
40
- const optionsToken = getPrismaOptionsToken(name);
41
- const serviceToken = getPrismaServiceToken(name);
42
- class NamedPrismaService extends PrismaService {}
43
- Inject(clientToken, optionsToken)(NamedPrismaService, {});
44
- return [NamedPrismaService, {
45
- provide: serviceToken,
46
- useExisting: NamedPrismaService
47
- }];
36
+ function createPrismaServiceProvider(provide, clientToken, optionsToken) {
37
+ return {
38
+ inject: [clientToken, optionsToken],
39
+ provide,
40
+ useFactory: (client, serviceOptions) => PrismaService.createFacade(client, serviceOptions)
41
+ };
48
42
  }
49
43
  function createPrismaRuntimeProviders(normalizedOptionsProvider, name) {
50
44
  const normalizedOptionsToken = getPrismaNormalizedOptionsToken(name);
@@ -60,10 +54,10 @@ function createPrismaRuntimeProviders(normalizedOptionsProvider, name) {
60
54
  useFactory: options => ({
61
55
  strictTransactions: options.strictTransactions
62
56
  })
63
- }, ...(name === undefined ? [PrismaService, {
57
+ }, ...(name === undefined ? [createPrismaServiceProvider(PrismaService, clientToken, optionsToken), {
64
58
  provide: getPrismaServiceToken(),
65
59
  useExisting: PrismaService
66
- }, PrismaTransactionInterceptor] : createNamedPrismaServiceProvider(name))];
60
+ }] : [createPrismaServiceProvider(getPrismaServiceToken(name), clientToken, optionsToken)])];
67
61
  }
68
62
  function buildPrismaModule(options) {
69
63
  class PrismaRootModuleDefinition {}
@@ -72,7 +66,7 @@ function buildPrismaModule(options) {
72
66
  throw new Error('Named Prisma registrations are scoped and cannot be registered globally.');
73
67
  }
74
68
  return defineModule(PrismaRootModuleDefinition, {
75
- exports: normalizedOptions.name === undefined ? [PrismaService, PrismaTransactionInterceptor, getPrismaServiceToken(), getPrismaClientToken(), getPrismaOptionsToken()] : [getPrismaServiceToken(normalizedOptions.name), getPrismaClientToken(normalizedOptions.name), getPrismaOptionsToken(normalizedOptions.name)],
69
+ exports: normalizedOptions.name === undefined ? [PrismaService, getPrismaServiceToken(), getPrismaClientToken(), getPrismaOptionsToken()] : [getPrismaServiceToken(normalizedOptions.name), getPrismaClientToken(normalizedOptions.name), getPrismaOptionsToken(normalizedOptions.name)],
76
70
  global: normalizedOptions.name === undefined ? normalizedOptions.global : false,
77
71
  providers: createPrismaRuntimeProviders({
78
72
  provide: getPrismaNormalizedOptionsToken(normalizedOptions.name),
@@ -101,7 +95,7 @@ function buildPrismaModuleAsync(options) {
101
95
  }
102
96
  };
103
97
  return defineModule(PrismaAsyncModuleDefinition, {
104
- exports: normalizedName === undefined ? [PrismaService, PrismaTransactionInterceptor, getPrismaServiceToken(), getPrismaClientToken(), getPrismaOptionsToken()] : [getPrismaServiceToken(normalizedName), getPrismaClientToken(normalizedName), getPrismaOptionsToken(normalizedName)],
98
+ exports: normalizedName === undefined ? [PrismaService, getPrismaServiceToken(), getPrismaClientToken(), getPrismaOptionsToken()] : [getPrismaServiceToken(normalizedName), getPrismaClientToken(normalizedName), getPrismaOptionsToken(normalizedName)],
105
99
  global: normalizedName === undefined ? options.global ?? false : false,
106
100
  providers: createPrismaRuntimeProviders(normalizedOptionsProvider, normalizedName)
107
101
  });
@@ -115,7 +109,7 @@ export class PrismaModule {
115
109
  * Registers Prisma providers from static options.
116
110
  *
117
111
  * @param options Prisma module options with client handle and strict transaction mode.
118
- * @returns A module definition that exports `PrismaService` and `PrismaTransactionInterceptor`.
112
+ * @returns A module definition that exports `PrismaService` and related Prisma tokens.
119
113
  */
120
114
  static forRoot(options) {
121
115
  return buildPrismaModule(options);
package/dist/service.d.ts CHANGED
@@ -18,6 +18,20 @@ export declare class PrismaService<TClient extends PrismaClientLike<TTransaction
18
18
  private transactionAbortSignalSupport;
19
19
  private lifecycleState;
20
20
  constructor(client: TClient, serviceOptions?: PrismaServiceOptions);
21
+ /**
22
+ * Creates the low-level DI facade that forwards unknown Prisma API properties to the ambient `current()` client.
23
+ *
24
+ * @remarks
25
+ * This compatibility helper is used by `PrismaModule` provider wiring. Application code should prefer
26
+ * `PrismaModule.forRoot(...)` or `PrismaModule.forRootAsync(...)`, then type injected repository handles as
27
+ * `PrismaServiceFacade<TClient>` when direct generated Prisma delegates are needed.
28
+ *
29
+ * @param client Root Prisma client registered in the module.
30
+ * @param serviceOptions Runtime transaction options consumed by the Fluo wrapper.
31
+ * @returns A transaction-aware facade that exposes wrapper methods plus the root Prisma client surface.
32
+ */
33
+ static createFacade<TClient extends PrismaClientLike<TTransactionClient, TTransactionOptions>, TTransactionClient = InferPrismaTransactionClient<TClient>, TTransactionOptions = InferPrismaTransactionOptions<TClient>>(client: TClient, serviceOptions?: PrismaServiceOptions): PrismaServiceFacade<TClient, TTransactionClient, TTransactionOptions>;
34
+ private installCurrentClientFacade;
21
35
  /**
22
36
  * Returns the active Prisma handle for the current async context.
23
37
  *
@@ -91,5 +105,18 @@ export declare class PrismaService<TClient extends PrismaClientLike<TTransaction
91
105
  private trackActiveRequestTransaction;
92
106
  private untrackActiveRequestTransaction;
93
107
  }
108
+ /**
109
+ * Injection-facing Prisma facade type that combines the Fluo wrapper methods with the registered Prisma client surface.
110
+ *
111
+ * @remarks
112
+ * `PrismaModule` resolves `PrismaService` to a facade that forwards unknown properties to `current()`. Use this type in
113
+ * repositories that call generated Prisma delegates directly, and use `PrismaService<TClient>` when only wrapper methods
114
+ * (`current()`, `transaction(...)`, `requestTransaction(...)`, and status snapshots) are needed.
115
+ *
116
+ * @typeParam TClient Root Prisma client shape registered in the module.
117
+ * @typeParam TTransactionClient Transaction-scoped client resolved inside `$transaction(...)` callbacks.
118
+ * @typeParam TTransactionOptions Options forwarded to Prisma interactive transactions.
119
+ */
120
+ 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
121
  export {};
95
122
  //# sourceMappingURL=service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAK3E,OAAO,KAAK,EACV,4BAA4B,EAC5B,6BAA6B,EAC7B,gBAAgB,EAChB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAQpB,UAAU,oBAAoB;IAC5B,kBAAkB,EAAE,OAAO,CAAC;CAC7B;AA8FD;;;;;;GAMG;AACH,qBACa,aAAa,CACxB,OAAO,SAAS,gBAAgB,CAAC,kBAAkB,EAAE,mBAAmB,CAAC,EACzE,kBAAkB,GAAG,4BAA4B,CAAC,OAAO,CAAC,EAC1D,mBAAmB,GAAG,6BAA6B,CAAC,OAAO,CAAC,CAE5D,YAAW,oBAAoB,CAAC,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,CAAC,EAAE,YAAY,EAAE,qBAAqB;IAQpH,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,cAAc;IAPjC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAuD;IACpF,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAuC;IACjF,OAAO,CAAC,6BAA6B,CAA4C;IACjF,OAAO,CAAC,cAAc,CAAgE;gBAGnE,MAAM,EAAE,OAAO,EACf,cAAc,GAAE,oBAAoD;IAGvF;;;;;;;;;OASG;IACH,OAAO,IAAI,OAAO,GAAG,kBAAkB;YAIzB,wBAAwB;IAyChC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ7B,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB5C;;;;OAIG;IACH,4BAA4B;IAa5B;;;;;;;;;;;;;;;;;OAiBG;IACG,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,CAAC,CAAC;IAQrF;;;;;;;;;;;;;;;;;;OAkBG;IACG,kBAAkB,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,CAAC,CAAC;YAkCpG,+BAA+B;YAyB/B,2BAA2B;IAqCzC,OAAO,CAAC,kCAAkC;IAM1C,OAAO,CAAC,iCAAiC;IAMzC,OAAO,CAAC,qBAAqB;IAM7B,OAAO,CAAC,oCAAoC;IAY5C,OAAO,CAAC,sCAAsC;YAYhC,qCAAqC;IAyBnD,OAAO,CAAC,6BAA6B;IAUrC,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,0BAA0B;IAWlC,OAAO,CAAC,6BAA6B;IAIrC,OAAO,CAAC,+BAA+B;CAGxC"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAK3E,OAAO,KAAK,EACV,4BAA4B,EAC5B,6BAA6B,EAC7B,gBAAgB,EAChB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAQpB,UAAU,oBAAoB;IAC5B,kBAAkB,EAAE,OAAO,CAAC;CAC7B;AA6GD;;;;;;GAMG;AACH,qBACa,aAAa,CACxB,OAAO,SAAS,gBAAgB,CAAC,kBAAkB,EAAE,mBAAmB,CAAC,EACzE,kBAAkB,GAAG,4BAA4B,CAAC,OAAO,CAAC,EAC1D,mBAAmB,GAAG,6BAA6B,CAAC,OAAO,CAAC,CAE5D,YAAW,oBAAoB,CAAC,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,CAAC,EAAE,YAAY,EAAE,qBAAqB;IAQpH,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,cAAc;IAPjC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAuD;IACpF,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAuC;IACjF,OAAO,CAAC,6BAA6B,CAA4C;IACjF,OAAO,CAAC,cAAc,CAAgE;gBAGnE,MAAM,EAAE,OAAO,EACf,cAAc,GAAE,oBAAoD;IAKvF;;;;;;;;;;;OAWG;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,MAAM,EAAE,OAAO,EACf,cAAc,GAAE,oBAAoD,GACnE,mBAAmB,CAAC,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,CAAC;IAMxE,OAAO,CAAC,0BAA0B;IAkBlC;;;;;;;;;OASG;IACH,OAAO,IAAI,OAAO,GAAG,kBAAkB;YAIzB,wBAAwB;IAyChC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ7B,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB5C;;;;OAIG;IACH,4BAA4B;IAa5B;;;;;;;;;;;;;;;;;OAiBG;IACG,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,CAAC,CAAC;IAQrF;;;;;;;;;;;;;;;;;;OAkBG;IACG,kBAAkB,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,CAAC,CAAC;YAkCpG,+BAA+B;YAyB/B,2BAA2B;IAqCzC,OAAO,CAAC,kCAAkC;IAM1C,OAAO,CAAC,iCAAiC;IAMzC,OAAO,CAAC,qBAAqB;IAM7B,OAAO,CAAC,oCAAoC;IAY5C,OAAO,CAAC,sCAAsC;YAYhC,qCAAqC;IAyBnD,OAAO,CAAC,6BAA6B;IAUrC,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,0BAA0B;IAWlC,OAAO,CAAC,6BAA6B;IAIrC,OAAO,CAAC,+BAA+B;CAGxC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,mBAAmB,CAC7B,OAAO,SAAS,gBAAgB,CAAC,kBAAkB,EAAE,mBAAmB,CAAC,EACzE,kBAAkB,GAAG,4BAA4B,CAAC,OAAO,CAAC,EAC1D,mBAAmB,GAAG,6BAA6B,CAAC,OAAO,CAAC,IAC1D,aAAa,CAAC,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,CAAC,GACjE,IAAI,CAAC,OAAO,EAAE,MAAM,aAAa,CAAC,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,CAAC,CAAC,CAAC"}
package/dist/service.js CHANGED
@@ -11,6 +11,18 @@ import { PRISMA_CLIENT, PRISMA_OPTIONS } from './tokens.js';
11
11
  const NESTED_TRANSACTION_OPTIONS_NOT_SUPPORTED_ERROR = 'Nested Prisma transaction options are not supported because the active transaction context is reused.';
12
12
  const REQUEST_TRANSACTION_UNAVAILABLE_ERROR = 'Prisma request transactions are not available during shutdown.';
13
13
  const TRANSACTION_CONTEXT_UNAVAILABLE_ERROR = 'Prisma transaction context requires AsyncLocalStorage support from the host runtime.';
14
+ function createCurrentClientPrismaFacade(target) {
15
+ return new Proxy(target, {
16
+ get(service, prop, receiver) {
17
+ if (prop in service) {
18
+ return Reflect.get(service, prop, receiver);
19
+ }
20
+ const currentClient = service.current();
21
+ const value = Reflect.get(currentClient, prop, currentClient);
22
+ return typeof value === 'function' ? value.bind(currentClient) : value;
23
+ }
24
+ });
25
+ }
14
26
  class AsyncLocalStorageTransactionContextStore {
15
27
  kind = 'als';
16
28
  storage;
@@ -68,6 +80,40 @@ class PrismaService {
68
80
  }) {
69
81
  this.client = client;
70
82
  this.serviceOptions = serviceOptions;
83
+ this.installCurrentClientFacade();
84
+ }
85
+
86
+ /**
87
+ * Creates the low-level DI facade that forwards unknown Prisma API properties to the ambient `current()` client.
88
+ *
89
+ * @remarks
90
+ * This compatibility helper is used by `PrismaModule` provider wiring. Application code should prefer
91
+ * `PrismaModule.forRoot(...)` or `PrismaModule.forRootAsync(...)`, then type injected repository handles as
92
+ * `PrismaServiceFacade<TClient>` when direct generated Prisma delegates are needed.
93
+ *
94
+ * @param client Root Prisma client registered in the module.
95
+ * @param serviceOptions Runtime transaction options consumed by the Fluo wrapper.
96
+ * @returns A transaction-aware facade that exposes wrapper methods plus the root Prisma client surface.
97
+ */
98
+ static createFacade(client, serviceOptions = {
99
+ strictTransactions: false
100
+ }) {
101
+ return createCurrentClientPrismaFacade(new _PrismaService(client, serviceOptions));
102
+ }
103
+ installCurrentClientFacade() {
104
+ for (const prop of Reflect.ownKeys(this.client)) {
105
+ if (prop in this) {
106
+ continue;
107
+ }
108
+ Object.defineProperty(this, prop, {
109
+ configurable: true,
110
+ get: () => {
111
+ const current = this.current();
112
+ const value = Reflect.get(current, prop);
113
+ return typeof value === 'function' ? value.bind(current) : value;
114
+ }
115
+ });
116
+ }
71
117
  }
72
118
 
73
119
  /**
@@ -326,4 +372,17 @@ class PrismaService {
326
372
  _initClass();
327
373
  }
328
374
  }
375
+
376
+ /**
377
+ * Injection-facing Prisma facade type that combines the Fluo wrapper methods with the registered Prisma client surface.
378
+ *
379
+ * @remarks
380
+ * `PrismaModule` resolves `PrismaService` to a facade that forwards unknown properties to `current()`. Use this type in
381
+ * repositories that call generated Prisma delegates directly, and use `PrismaService<TClient>` when only wrapper methods
382
+ * (`current()`, `transaction(...)`, `requestTransaction(...)`, and status snapshots) are needed.
383
+ *
384
+ * @typeParam TClient Root Prisma client shape registered in the module.
385
+ * @typeParam TTransactionClient Transaction-scoped client resolved inside `$transaction(...)` callbacks.
386
+ * @typeParam TTransactionOptions Options forwarded to Prisma interactive transactions.
387
+ */
329
388
  export { _PrismaService as PrismaService };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * TC39 standard method decorator — 2023-11 (Babel @babel/plugin-proposal-decorators)
3
+ * NO reflect-metadata. NO experimentalDecorators.
4
+ *
5
+ * Factory signature:
6
+ * Transaction(accessor?) returns (value, context: ClassMethodDecoratorContext) => Function
7
+ *
8
+ * Default: @Transaction() — uses `this` as the service
9
+ * Explicit: @Transaction((self) => self.analytics) — uses returned service property
10
+ *
11
+ * Nested reuse: if active context exists, reuses it (no new transaction opened)
12
+ * Nested options: if active context exists AND options passed, THROWS
13
+ */
14
+ export type TransactionAccessor<THost, TService> = (self: THost) => TService;
15
+ /**
16
+ * Standard method decorator factory signature for Prisma service transaction boundaries.
17
+ */
18
+ export type TransactionDecorator = <TService>(accessor?: TransactionAccessor<unknown, TService>) => (value: Function, context: ClassMethodDecoratorContext) => Function;
19
+ //# sourceMappingURL=transaction-decorator-contract.notes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transaction-decorator-contract.notes.d.ts","sourceRoot":"","sources":["../src/transaction-decorator-contract.notes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,mBAAmB,CAAC,KAAK,EAAE,QAAQ,IAAI,CAAC,IAAI,EAAE,KAAK,KAAK,QAAQ,CAAC;AAE7E;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,QAAQ,EAC1C,QAAQ,CAAC,EAAE,mBAAmB,CAAC,OAAO,EAAE,QAAQ,CAAC,KAC9C,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,2BAA2B,KAAK,QAAQ,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -1,25 +1,22 @@
1
- import type { Interceptor, InterceptorContext } from '@fluojs/http';
2
- import { PrismaService } from './service.js';
3
- import type { PrismaClientLike } from './types.js';
1
+ type TransactionalPrismaService<TOptions = unknown> = {
2
+ transaction<T>(fn: () => Promise<T>, options?: TOptions): Promise<T>;
3
+ };
4
+ type TransactionAccessor<THost, TOptions> = (self: THost) => TransactionalPrismaService<TOptions>;
5
+ type TransactionMethod<THost, TArgs extends unknown[], TResult> = (this: THost, ...args: TArgs) => Promise<TResult>;
4
6
  /**
5
- * HTTP interceptor that wraps a request handler in `PrismaService.requestTransaction(...)`.
7
+ * Wraps a service method in a `PrismaService.transaction(...)` boundary.
6
8
  *
7
9
  * @remarks
8
- * Pair this with repository/service code that reads `PrismaService.current()` so downstream calls share the same
9
- * request-scoped transaction client.
10
+ * This is a TC39 standard method decorator (2023-11) and does not use legacy decorator metadata or `reflect-metadata`.
11
+ * `@Transaction()` resolves a Prisma service from the decorated instance, while
12
+ * `@Transaction((self) => self.prisma)` selects an explicit service for named or multi-client registrations.
13
+ * Calls made while a transaction context is already active reuse the existing Prisma transaction through `PrismaService`.
14
+ * Passing Prisma transaction options to a nested call is rejected by `PrismaService.transaction(...)` so option intent is not
15
+ * silently ignored.
16
+ *
17
+ * @param input Optional service accessor or Prisma interactive transaction options.
18
+ * @returns A standard method decorator that runs the original method inside a Prisma transaction boundary.
10
19
  */
11
- export declare class PrismaTransactionInterceptor implements Interceptor {
12
- private readonly prisma;
13
- constructor(prisma: PrismaService<PrismaClientLike>);
14
- /**
15
- * Runs the downstream handler inside a Prisma request transaction boundary.
16
- *
17
- * @param context Interceptor context that supplies the request abort signal.
18
- * @param next Downstream handler chain.
19
- * @returns The downstream handler result after the request transaction settles.
20
- */
21
- intercept(context: InterceptorContext, next: {
22
- handle(): Promise<unknown>;
23
- }): Promise<unknown>;
24
- }
20
+ export declare function Transaction<THost, TOptions = unknown>(input?: TransactionAccessor<THost, TOptions> | TOptions): <TArgs extends unknown[], TResult>(value: TransactionMethod<THost, TArgs, TResult>, context: ClassMethodDecoratorContext<THost, TransactionMethod<THost, TArgs, TResult>>) => TransactionMethod<THost, TArgs, TResult>;
21
+ export {};
25
22
  //# sourceMappingURL=transaction.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../src/transaction.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEpE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD;;;;;;GAMG;AACH,qBACa,4BAA6B,YAAW,WAAW;IAClD,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,aAAa,CAAC,gBAAgB,CAAC;IAEpE;;;;;;OAMG;IACG,SAAS,CAAC,OAAO,EAAE,kBAAkB,EAAE,IAAI,EAAE;QAAE,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC;CAGrG"}
1
+ {"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../src/transaction.ts"],"names":[],"mappings":"AAAA,KAAK,0BAA0B,CAAC,QAAQ,GAAG,OAAO,IAAI;IACpD,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACtE,CAAC;AAEF,KAAK,mBAAmB,CAAC,KAAK,EAAE,QAAQ,IAAI,CAAC,IAAI,EAAE,KAAK,KAAK,0BAA0B,CAAC,QAAQ,CAAC,CAAC;AAElG,KAAK,iBAAiB,CAAC,KAAK,EAAE,KAAK,SAAS,OAAO,EAAE,EAAE,OAAO,IAAI,CAChE,IAAI,EAAE,KAAK,EACX,GAAG,IAAI,EAAE,KAAK,KACX,OAAO,CAAC,OAAO,CAAC,CAAC;AAwDtB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,EACnD,KAAK,CAAC,EAAE,mBAAmB,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,GACtD,CAAC,KAAK,SAAS,OAAO,EAAE,EAAE,OAAO,EAClC,KAAK,EAAE,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAC/C,OAAO,EAAE,2BAA2B,CAAC,KAAK,EAAE,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,KAClF,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAiB5C"}
@@ -1,39 +1,68 @@
1
- let _initClass;
2
- function _applyDecs(e, t, n, r, o, i) { var a, c, u, s, f, l, p, d = Symbol.metadata || Symbol.for("Symbol.metadata"), m = Object.defineProperty, h = Object.create, y = [h(null), h(null)], v = t.length; function g(t, n, r) { return function (o, i) { n && (i = o, o = e); for (var a = 0; a < t.length; a++) i = t[a].apply(o, r ? [i] : []); return r ? i : o; }; } function b(e, t, n, r) { if ("function" != typeof e && (r || void 0 !== e)) throw new TypeError(t + " must " + (n || "be") + " a function" + (r ? "" : " or undefined")); return e; } function applyDec(e, t, n, r, o, i, u, s, f, l, p) { function d(e) { if (!p(e)) throw new TypeError("Attempted to access private element on non-instance"); } var h = [].concat(t[0]), v = t[3], w = !u, D = 1 === o, S = 3 === o, j = 4 === o, E = 2 === o; function I(t, n, r) { return function (o, i) { return n && (i = o, o = e), r && r(o), P[t].call(o, i); }; } if (!w) { var P = {}, k = [], F = S ? "get" : j || D ? "set" : "value"; if (f ? (l || D ? P = { get: _setFunctionName(function () { return v(this); }, r, "get"), set: function (e) { t[4](this, e); } } : P[F] = v, l || _setFunctionName(P[F], r, E ? "" : F)) : l || (P = Object.getOwnPropertyDescriptor(e, r)), !l && !f) { if ((c = y[+s][r]) && 7 !== (c ^ o)) throw Error("Decorating two elements with the same name (" + P[F].name + ") is not supported yet"); y[+s][r] = o < 3 ? 1 : o; } } for (var N = e, O = h.length - 1; O >= 0; O -= n ? 2 : 1) { var T = b(h[O], "A decorator", "be", !0), z = n ? h[O - 1] : void 0, A = {}, H = { kind: ["field", "accessor", "method", "getter", "setter", "class"][o], name: r, metadata: a, addInitializer: function (e, t) { if (e.v) throw new TypeError("attempted to call addInitializer after decoration was finished"); b(t, "An initializer", "be", !0), i.push(t); }.bind(null, A) }; if (w) c = T.call(z, N, H), A.v = 1, b(c, "class decorators", "return") && (N = c);else if (H.static = s, H.private = f, c = H.access = { has: f ? p.bind() : function (e) { return r in e; } }, j || (c.get = f ? E ? function (e) { return d(e), P.value; } : I("get", 0, d) : function (e) { return e[r]; }), E || S || (c.set = f ? I("set", 0, d) : function (e, t) { e[r] = t; }), N = T.call(z, D ? { get: P.get, set: P.set } : P[F], H), A.v = 1, D) { if ("object" == typeof N && N) (c = b(N.get, "accessor.get")) && (P.get = c), (c = b(N.set, "accessor.set")) && (P.set = c), (c = b(N.init, "accessor.init")) && k.unshift(c);else if (void 0 !== N) throw new TypeError("accessor decorators must return an object with get, set, or init properties or undefined"); } else b(N, (l ? "field" : "method") + " decorators", "return") && (l ? k.unshift(N) : P[F] = N); } return o < 2 && u.push(g(k, s, 1), g(i, s, 0)), l || w || (f ? D ? u.splice(-1, 0, I("get", s), I("set", s)) : u.push(E ? P[F] : b.call.bind(P[F])) : m(e, r, P)), N; } function w(e) { return m(e, d, { configurable: !0, enumerable: !0, value: a }); } return void 0 !== i && (a = i[d]), a = h(null == a ? null : a), f = [], l = function (e) { e && f.push(g(e)); }, p = function (t, r) { for (var i = 0; i < n.length; i++) { var a = n[i], c = a[1], l = 7 & c; if ((8 & c) == t && !l == r) { var p = a[2], d = !!a[3], m = 16 & c; applyDec(t ? e : e.prototype, a, m, d ? "#" + p : _toPropertyKey(p), l, l < 2 ? [] : t ? s = s || [] : u = u || [], f, !!t, d, r, t && d ? function (t) { return _checkInRHS(t) === e; } : o); } } }, p(8, 0), p(0, 0), p(8, 1), p(0, 1), l(u), l(s), c = f, v || w(e), { e: c, get c() { var n = []; return v && [w(e = applyDec(e, [t], r, e.name, 5, n)), g(n, 1)]; } }; }
3
- function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
4
- function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
5
- function _setFunctionName(e, t, n) { "symbol" == typeof t && (t = (t = t.description) ? "[" + t + "]" : ""); try { Object.defineProperty(e, "name", { configurable: !0, value: n ? n + " " + t : t }); } catch (e) {} return e; }
6
- function _checkInRHS(e) { if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? typeof e : "null")); return e; }
7
- import { Inject } from '@fluojs/core';
8
- import { PrismaService } from './service.js';
9
- let _PrismaTransactionInt;
10
- /**
11
- * HTTP interceptor that wraps a request handler in `PrismaService.requestTransaction(...)`.
12
- *
13
- * @remarks
14
- * Pair this with repository/service code that reads `PrismaService.current()` so downstream calls share the same
15
- * request-scoped transaction client.
16
- */
17
- class PrismaTransactionInterceptor {
18
- static {
19
- [_PrismaTransactionInt, _initClass] = _applyDecs(this, [Inject(PrismaService)], []).c;
1
+ function hasTransaction(value) {
2
+ return typeof value === 'object' && value !== null && 'transaction' in value && typeof value.transaction === 'function';
3
+ }
4
+ function readProperty(value, property) {
5
+ if (typeof value !== 'object' && typeof value !== 'function' || value === null) {
6
+ return undefined;
20
7
  }
21
- constructor(prisma) {
22
- this.prisma = prisma;
8
+ return Reflect.get(value, property);
9
+ }
10
+ function resolveDefaultPrismaService(self) {
11
+ const directPrisma = readProperty(self, 'prisma');
12
+ if (hasTransaction(directPrisma)) {
13
+ return directPrisma;
23
14
  }
24
-
25
- /**
26
- * Runs the downstream handler inside a Prisma request transaction boundary.
27
- *
28
- * @param context Interceptor context that supplies the request abort signal.
29
- * @param next Downstream handler chain.
30
- * @returns The downstream handler result after the request transaction settles.
31
- */
32
- async intercept(context, next) {
33
- return this.prisma.requestTransaction(async () => next.handle(), context.requestContext.request.signal);
15
+ if (hasTransaction(self)) {
16
+ return self;
34
17
  }
35
- static {
36
- _initClass();
18
+ for (const value of Object.values(Object(self))) {
19
+ if (hasTransaction(value)) {
20
+ return value;
21
+ }
22
+ const nestedPrisma = readProperty(value, 'prisma');
23
+ if (hasTransaction(nestedPrisma)) {
24
+ return nestedPrisma;
25
+ }
37
26
  }
27
+ throw new Error('Unable to resolve PrismaService for @Transaction(). Provide an accessor function.');
38
28
  }
39
- export { _PrismaTransactionInt as PrismaTransactionInterceptor };
29
+ function resolveTransactionInput(input) {
30
+ if (typeof input === 'function') {
31
+ return {
32
+ accessor: input
33
+ };
34
+ }
35
+ return {
36
+ options: input
37
+ };
38
+ }
39
+
40
+ /**
41
+ * Wraps a service method in a `PrismaService.transaction(...)` boundary.
42
+ *
43
+ * @remarks
44
+ * This is a TC39 standard method decorator (2023-11) and does not use legacy decorator metadata or `reflect-metadata`.
45
+ * `@Transaction()` resolves a Prisma service from the decorated instance, while
46
+ * `@Transaction((self) => self.prisma)` selects an explicit service for named or multi-client registrations.
47
+ * Calls made while a transaction context is already active reuse the existing Prisma transaction through `PrismaService`.
48
+ * Passing Prisma transaction options to a nested call is rejected by `PrismaService.transaction(...)` so option intent is not
49
+ * silently ignored.
50
+ *
51
+ * @param input Optional service accessor or Prisma interactive transaction options.
52
+ * @returns A standard method decorator that runs the original method inside a Prisma transaction boundary.
53
+ */
54
+ export function Transaction(input) {
55
+ const {
56
+ accessor,
57
+ options
58
+ } = resolveTransactionInput(input);
59
+ return function transactionDecorator(value, context) {
60
+ if (context.kind !== 'method') {
61
+ throw new Error('@Transaction() can only decorate methods.');
62
+ }
63
+ return async function wrappedTransactionMethod(...args) {
64
+ const prisma = accessor?.(this) ?? resolveDefaultPrismaService(this);
65
+ return prisma.transaction(() => value.apply(this, args), options);
66
+ };
67
+ };
68
+ }
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "transaction",
10
10
  "als"
11
11
  ],
12
- "version": "1.0.2",
12
+ "version": "1.1.0",
13
13
  "private": false,
14
14
  "license": "MIT",
15
15
  "repository": {
@@ -37,9 +37,9 @@
37
37
  ],
38
38
  "dependencies": {
39
39
  "@fluojs/core": "^1.0.3",
40
- "@fluojs/http": "^1.1.0",
41
- "@fluojs/di": "^1.0.3",
42
- "@fluojs/runtime": "^1.1.2"
40
+ "@fluojs/http": "^1.1.2",
41
+ "@fluojs/di": "^1.1.0",
42
+ "@fluojs/runtime": "^1.1.8"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "@prisma/client": ">=5.0.0"