11'use strict' ;
22
33const {
4+ ArrayPrototypePush,
45 RegExpPrototypeExec,
56 StringPrototypeIndexOf,
67 StringPrototypeSlice,
@@ -105,15 +106,18 @@ function evalScript(name, body, breakFirstLine, print, shouldLoadESM = false) {
105106}
106107
107108const exceptionHandlerState = {
108- captureFn : null ,
109+ captureFn : null , // Primary callback (for domain's exclusive use)
110+ auxiliaryCallbacks : [ ] , // Auxiliary callbacks (for REPL, etc.) - always called
109111 reportFlag : false ,
110112} ;
111113
112114function setUncaughtExceptionCaptureCallback ( fn ) {
113115 if ( fn === null ) {
114116 exceptionHandlerState . captureFn = fn ;
115- shouldAbortOnUncaughtToggle [ 0 ] = 1 ;
116- process . report . reportOnUncaughtException = exceptionHandlerState . reportFlag ;
117+ if ( exceptionHandlerState . auxiliaryCallbacks . length === 0 ) {
118+ shouldAbortOnUncaughtToggle [ 0 ] = 1 ;
119+ process . report . reportOnUncaughtException = exceptionHandlerState . reportFlag ;
120+ }
117121 return ;
118122 }
119123 if ( typeof fn !== 'function' ) {
@@ -129,6 +133,23 @@ function setUncaughtExceptionCaptureCallback(fn) {
129133 process . report . reportOnUncaughtException = false ;
130134}
131135
136+ // Add an auxiliary callback that coexists with the primary callback.
137+ // Auxiliary callbacks are called first; if any returns true, the error is handled.
138+ // Otherwise, the primary callback (if set) is called.
139+ function addUncaughtExceptionCaptureCallback ( fn ) {
140+ if ( typeof fn !== 'function' ) {
141+ throw new ERR_INVALID_ARG_TYPE ( 'fn' , 'Function' , fn ) ;
142+ }
143+ if ( exceptionHandlerState . auxiliaryCallbacks . length === 0 &&
144+ exceptionHandlerState . captureFn === null ) {
145+ exceptionHandlerState . reportFlag =
146+ process . report . reportOnUncaughtException === true ;
147+ process . report . reportOnUncaughtException = false ;
148+ shouldAbortOnUncaughtToggle [ 0 ] = 0 ;
149+ }
150+ ArrayPrototypePush ( exceptionHandlerState . auxiliaryCallbacks , fn ) ;
151+ }
152+
132153function hasUncaughtExceptionCaptureCallback ( ) {
133154 return exceptionHandlerState . captureFn !== null ;
134155}
@@ -154,9 +175,21 @@ function createOnGlobalUncaughtException() {
154175
155176 const type = fromPromise ? 'unhandledRejection' : 'uncaughtException' ;
156177 process . emit ( 'uncaughtExceptionMonitor' , er , type ) ;
178+ let handled = false ;
179+ // Primary callback (e.g., domain) has priority - it handles domain-specific errors
157180 if ( exceptionHandlerState . captureFn !== null ) {
158- exceptionHandlerState . captureFn ( er ) ;
159- } else if ( ! process . emit ( 'uncaughtException' , er , type ) ) {
181+ handled = exceptionHandlerState . captureFn ( er ) ;
182+ }
183+ // If primary didn't handle it, try auxiliary callbacks (e.g., REPL)
184+ if ( ! handled ) {
185+ for ( let i = exceptionHandlerState . auxiliaryCallbacks . length - 1 ; i >= 0 ; i -- ) {
186+ if ( exceptionHandlerState . auxiliaryCallbacks [ i ] ( er ) === true ) {
187+ handled = true ;
188+ break ;
189+ }
190+ }
191+ }
192+ if ( ! handled && ! process . emit ( 'uncaughtException' , er , type ) ) {
160193 // If someone handled it, then great. Otherwise, die in C++ land
161194 // since that means that we'll exit the process, emit the 'exit' event.
162195 try {
@@ -477,5 +510,6 @@ module.exports = {
477510 evalScript,
478511 onGlobalUncaughtException : createOnGlobalUncaughtException ( ) ,
479512 setUncaughtExceptionCaptureCallback,
513+ addUncaughtExceptionCaptureCallback,
480514 hasUncaughtExceptionCaptureCallback,
481515} ;
0 commit comments