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,21 +175,33 @@ function createOnGlobalUncaughtException() {
154175
155176 const type = fromPromise ? 'unhandledRejection' : 'uncaughtException' ;
156177 process . emit ( 'uncaughtExceptionMonitor' , er , type ) ;
178+ // Primary callback (e.g., domain) has priority and always handles the exception
157179 if ( exceptionHandlerState . captureFn !== null ) {
158180 exceptionHandlerState . captureFn ( er ) ;
159- } else if ( ! process . emit ( 'uncaughtException' , er , type ) ) {
160- // If someone handled it, then great. Otherwise, die in C++ land
161- // since that means that we'll exit the process, emit the 'exit' event.
162- try {
163- if ( ! process . _exiting ) {
164- process . _exiting = true ;
165- process . exitCode = kGenericUserError ;
166- process . emit ( 'exit' , kGenericUserError ) ;
181+ } else {
182+ // If no primary callback, try auxiliary callbacks (e.g., REPL)
183+ // They must return true to indicate handling
184+ let handled = false ;
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+ if ( ! handled && ! process . emit ( 'uncaughtException' , er , type ) ) {
192+ // If someone handled it, then great. Otherwise, die in C++ land
193+ // since that means that we'll exit the process, emit the 'exit' event.
194+ try {
195+ if ( ! process . _exiting ) {
196+ process . _exiting = true ;
197+ process . exitCode = kGenericUserError ;
198+ process . emit ( 'exit' , kGenericUserError ) ;
199+ }
200+ } catch {
201+ // Nothing to be done about it at this point.
167202 }
168- } catch {
169- // Nothing to be done about it at this point.
203+ return false ;
170204 }
171- return false ;
172205 }
173206
174207 // If we handled an error, then make sure any ticks get processed
@@ -477,5 +510,6 @@ module.exports = {
477510 evalScript,
478511 onGlobalUncaughtException : createOnGlobalUncaughtException ( ) ,
479512 setUncaughtExceptionCaptureCallback,
513+ addUncaughtExceptionCaptureCallback,
480514 hasUncaughtExceptionCaptureCallback,
481515} ;
0 commit comments