@@ -155,6 +155,9 @@ export class DefaultPrismaProxyHandler implements PrismaProxyHandler {
155155 }
156156}
157157
158+ // a marker for filtering error stack trace
159+ const ERROR_MARKER = '__error_marker__' ;
160+
158161/**
159162 * Makes a Prisma client proxy.
160163 */
@@ -216,9 +219,71 @@ export function makeProxy<T extends PrismaProxyHandler>(
216219 return undefined ;
217220 }
218221
219- return makeHandler ( target , prop ) ;
222+ return createHandlerProxy ( makeHandler ( target , prop ) ) ;
220223 } ,
221224 } ) ;
222225
223226 return proxy ;
224227}
228+
229+ // A proxy for capturing errors and processing stack trace
230+ function createHandlerProxy < T extends PrismaProxyHandler > ( handler : T ) : T {
231+ return new Proxy ( handler , {
232+ get ( target , propKey ) {
233+ const prop = target [ propKey as keyof T ] ;
234+ if ( typeof prop !== 'function' ) {
235+ return prop ;
236+ }
237+
238+ // eslint-disable-next-line @typescript-eslint/ban-types
239+ const origMethod = prop as Function ;
240+ return async function ( ...args : any [ ] ) {
241+ const _err = new Error ( ERROR_MARKER ) ;
242+ try {
243+ return await origMethod . apply ( handler , args ) ;
244+ } catch ( err ) {
245+ if ( _err . stack && err instanceof Error ) {
246+ ( err as any ) . internalStack = err . stack ;
247+ err . stack = cleanCallStack ( _err . stack , propKey . toString ( ) , err . message ) ;
248+ }
249+ throw err ;
250+ }
251+ } ;
252+ } ,
253+ } ) ;
254+ }
255+
256+ // Filter out @zenstackhq /runtime stack (generated by proxy) from stack trace
257+ function cleanCallStack ( stack : string , method : string , message : string ) {
258+ // message line
259+ let resultStack = `Error calling enhanced Prisma method \`${ method } \`: ${ message } ` ;
260+
261+ const lines = stack . split ( '\n' ) ;
262+ let foundMarker = false ;
263+
264+ for ( let i = 0 ; i < lines . length ; i ++ ) {
265+ const line = lines [ i ] ;
266+
267+ if ( ! foundMarker ) {
268+ // find marker, then stack trace lines follow
269+ if ( line . includes ( ERROR_MARKER ) ) {
270+ foundMarker = true ;
271+ }
272+ continue ;
273+ }
274+
275+ // skip leading zenstack and anonymous lines
276+ if ( line . includes ( '@zenstackhq/runtime' ) || line . includes ( '<anonymous>' ) ) {
277+ continue ;
278+ }
279+
280+ // capture remaining lines
281+ resultStack += lines
282+ . slice ( i )
283+ . map ( ( l ) => '\n' + l )
284+ . join ( ) ;
285+ break ;
286+ }
287+
288+ return resultStack ;
289+ }
0 commit comments