@@ -7,12 +7,30 @@ import z from 'zod';
77import { fromError } from 'zod-validation-error/v4' ;
88import type { ApiHandler , LogConfig , RequestContext , Response } from '../../types' ;
99import { getProcedureDef , mapProcedureArgs , PROCEDURE_ROUTE_PREFIXES } from '../common/procedures' ;
10-
11- const TRANSACTION_ROUTE_PREFIX = '$transaction' as const ;
1210import { loggerSchema } from '../common/schemas' ;
1311import { processSuperJsonRequestPayload , unmarshalQ } from '../common/utils' ;
1412import { log , registerCustomSerializers } from '../utils' ;
1513
14+ const TRANSACTION_ROUTE_PREFIX = '$transaction' as const ;
15+ const VALID_OPS = new Set ( [
16+ 'create' ,
17+ 'createMany' ,
18+ 'createManyAndReturn' ,
19+ 'upsert' ,
20+ 'findFirst' ,
21+ 'findUnique' ,
22+ 'findMany' ,
23+ 'aggregate' ,
24+ 'groupBy' ,
25+ 'count' ,
26+ 'exists' ,
27+ 'update' ,
28+ 'updateMany' ,
29+ 'updateManyAndReturn' ,
30+ 'delete' ,
31+ 'deleteMany' ,
32+ ] ) ;
33+
1634registerCustomSerializers ( ) ;
1735
1836/**
@@ -77,6 +95,7 @@ export class RPCApiHandler<Schema extends SchemaDef = SchemaDef> implements ApiH
7795 return this . handleTransaction ( {
7896 client,
7997 method : method . toUpperCase ( ) ,
98+ type : op ,
8099 requestBody,
81100 } ) ;
82101 }
@@ -198,38 +217,27 @@ export class RPCApiHandler<Schema extends SchemaDef = SchemaDef> implements ApiH
198217 private async handleTransaction ( {
199218 client,
200219 method,
220+ type,
201221 requestBody,
202222 } : {
203223 client : ClientContract < Schema > ;
204224 method : string ;
225+ type : string ;
205226 requestBody ?: unknown ;
206227 } ) : Promise < Response > {
207228 if ( method !== 'POST' ) {
208229 return this . makeBadInputErrorResponse ( 'invalid request method, only POST is supported' ) ;
209230 }
210231
232+ if ( type !== 'sequential' ) {
233+ return this . makeBadInputErrorResponse ( `unsupported transaction type: ${ type } ` ) ;
234+ }
235+
211236 if ( ! requestBody || ! Array . isArray ( requestBody ) || requestBody . length === 0 ) {
212237 return this . makeBadInputErrorResponse ( 'request body must be a non-empty array of operations' ) ;
213238 }
214239
215- const VALID_OPS = new Set ( [
216- 'create' ,
217- 'createMany' ,
218- 'createManyAndReturn' ,
219- 'upsert' ,
220- 'findFirst' ,
221- 'findUnique' ,
222- 'findMany' ,
223- 'aggregate' ,
224- 'groupBy' ,
225- 'count' ,
226- 'exists' ,
227- 'update' ,
228- 'updateMany' ,
229- 'updateManyAndReturn' ,
230- 'delete' ,
231- 'deleteMany' ,
232- ] ) ;
240+ const processedOps : Array < { model : string ; op : string ; args : unknown } > = [ ] ;
233241
234242 for ( let i = 0 ; i < requestBody . length ; i ++ ) {
235243 const item = requestBody [ i ] ;
@@ -252,16 +260,19 @@ export class RPCApiHandler<Schema extends SchemaDef = SchemaDef> implements ApiH
252260 if ( itemArgs !== undefined && itemArgs !== null && typeof itemArgs !== 'object' ) {
253261 return this . makeBadInputErrorResponse ( `operation at index ${ i } has invalid "args" field` ) ;
254262 }
255- }
256263
257- const promises = ( requestBody as any [ ] ) . map ( ( item ) => {
258- const model = lowerCaseFirst ( item . model as string ) ;
259- const op = item . op as string ;
260- const args = item . args ?? { } ;
261- return ( client as any ) [ model ] [ op ] ( args ) ;
262- } ) ;
264+ const { result : processedArgs , error : argsError } = await this . processRequestPayload ( itemArgs ?? { } ) ;
265+ if ( argsError ) {
266+ return this . makeBadInputErrorResponse ( `operation at index ${ i } : ${ argsError } ` ) ;
267+ }
268+ processedOps . push ( { model : lowerCaseFirst ( itemModel ) , op : itemOp , args : processedArgs } ) ;
269+ }
263270
264271 try {
272+ const promises = processedOps . map ( ( { model, op, args } ) => {
273+ return ( client as any ) [ model ] [ op ] ( args ) ;
274+ } ) ;
275+
265276 log ( this . options . log , 'debug' , ( ) => `handling "$transaction" request with ${ promises . length } operations` ) ;
266277
267278 const clientResult = await client . $transaction ( promises as any ) ;
0 commit comments