1+ // https://github.com/nodejs/node/blob/360f7cc7867b43344aac00564286b895e15f21d7/lib/internal/errors.js#L246C1-L261C2
2+ function isErrorStackTraceLimitWritable ( ) {
3+ const desc = Object . getOwnPropertyDescriptor ( Error , "stackTraceLimit" ) ;
4+ if ( desc === undefined ) {
5+ return Object . isExtensible ( Error ) ;
6+ }
7+
8+ return Object . prototype . hasOwnProperty . call ( desc , "writable" )
9+ ? desc . writable
10+ : desc . set !== undefined ;
11+ }
12+
13+ class ErrorWithStack extends Error {
14+ constructor ( ) {
15+ super ( ) ;
16+ this . name = "ErrorWithStack" ;
17+ }
18+ }
19+
20+ /**
21+ * Hide internal stack frames from the error stack trace.
22+ */
23+ function hideInternalStackFrames ( stack : string ) : string {
24+ const lines = stack . split ( "\n at " ) ;
25+ if ( lines . length <= 1 ) {
26+ return stack ;
27+ }
28+ lines . splice ( 1 , 1 ) ;
29+ return lines . join ( "\n at " ) ;
30+ }
31+
32+ // https://github.com/nodejs/node/blob/360f7cc7867b43344aac00564286b895e15f21d7/lib/internal/errors.js#L411-L432
33+ function makeErrorForHideStackFrame < B extends new ( ...args : any [ ] ) => Error > (
34+ Base : B ,
35+ clazz : any ,
36+ ) : {
37+ new ( ...args : ConstructorParameters < B > ) : InstanceType < B > & { errorWithStack : ErrorWithStack } ;
38+ } {
39+ class HideStackFramesError extends Base {
40+ #errorWithStack: ErrorWithStack ;
41+
42+ constructor ( ...args : any [ ] ) {
43+ if ( isErrorStackTraceLimitWritable ( ) ) {
44+ const limit = Error . stackTraceLimit ;
45+ Error . stackTraceLimit = 0 ;
46+ super ( ...args ) ;
47+ Error . stackTraceLimit = limit ;
48+ } else {
49+ super ( ...args ) ;
50+ }
51+ this . #errorWithStack = new ErrorWithStack ( ) ;
52+ this . #errorWithStack. stack = hideInternalStackFrames ( this . #errorWithStack. stack ?? "" ) ;
53+ }
54+
55+ // use `getter` here to avoid the stack trace being captured by loggers
56+ get errorWithStack ( ) {
57+ return this . #errorWithStack;
58+ }
59+
60+ // This is a workaround for wpt tests that expect that the error
61+ // constructor has a `name` property of the base class.
62+ get [ "constructor" ] ( ) {
63+ return clazz ;
64+ }
65+ }
66+
67+ return HideStackFramesError as any ;
68+ }
69+
170export const _statusCode = {
271 OK : 200 ,
372 CREATED : 201 ,
@@ -116,19 +185,27 @@ export type Status =
116185 | 510
117186 | 511 ;
118187
119- export class APIError extends Error {
188+ class InternalAPIError extends Error {
120189 constructor (
121190 public status : keyof typeof _statusCode | Status = "INTERNAL_SERVER_ERROR" ,
122191 public body :
123192 | ( {
124193 message ?: string ;
125194 code ?: string ;
195+ cause ?: unknown ;
126196 } & Record < string , any > )
127197 | undefined = undefined ,
128198 public headers : HeadersInit = { } ,
129199 public statusCode = typeof status === "number" ? status : _statusCode [ status ] ,
130200 ) {
131- super ( body ?. message ) ;
201+ super (
202+ body ?. message ,
203+ body ?. cause
204+ ? {
205+ cause : body . cause ,
206+ }
207+ : undefined ,
208+ ) ;
132209 this . name = "APIError" ;
133210 this . status = status ;
134211 this . headers = headers ;
@@ -142,6 +219,7 @@ export class APIError extends Error {
142219 ...body ,
143220 }
144221 : undefined ;
145- this . stack = "" ;
146222 }
147223}
224+
225+ export const APIError = makeErrorForHideStackFrame ( InternalAPIError , Error ) ;
0 commit comments