@typokit/errors 0.3.3 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/index.test.ts +37 -0
- package/src/index.ts +25 -0
package/dist/index.d.ts
CHANGED
|
@@ -2,12 +2,18 @@ import type { ErrorResponse } from "@typokit/types";
|
|
|
2
2
|
/**
|
|
3
3
|
* Base error class for all TypoKit errors.
|
|
4
4
|
* Extends native Error with structured fields for status, code, and details.
|
|
5
|
+
*
|
|
6
|
+
* Stack trace capture is skipped at construction time for performance.
|
|
7
|
+
* AppError stack is never used in response serialization (toJSON() excludes it).
|
|
8
|
+
* Call captureStack() if you need the trace for debugging.
|
|
5
9
|
*/
|
|
6
10
|
export declare class AppError extends Error {
|
|
7
11
|
readonly code: string;
|
|
8
12
|
readonly status: number;
|
|
9
13
|
readonly details?: Record<string, unknown> | undefined;
|
|
10
14
|
constructor(code: string, status: number, message: string, details?: Record<string, unknown> | undefined);
|
|
15
|
+
/** Lazily capture stack trace (skipped at construction for performance) */
|
|
16
|
+
captureStack(): this;
|
|
11
17
|
/** Serialize to the ErrorResponse schema from @typokit/types */
|
|
12
18
|
toJSON(): ErrorResponse;
|
|
13
19
|
}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAapD;;;;;;;GAOG;AACH,qBAAa,QAAS,SAAQ,KAAK;aAEf,IAAI,EAAE,MAAM;aACZ,MAAM,EAAE,MAAM;aAEd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBAHjC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EAC9B,OAAO,EAAE,MAAM,EACC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,YAAA;IAWnD,2EAA2E;IAC3E,YAAY,IAAI,IAAI;IAKpB,gEAAgE;IAChE,MAAM,IAAI,aAAa;CASxB;AAED,oBAAoB;AACpB,qBAAa,aAAc,SAAQ,QAAQ;gBAEvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAKpC;AAED,mCAAmC;AACnC,qBAAa,eAAgB,SAAQ,QAAQ;gBAEzC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAKpC;AAED,uBAAuB;AACvB,qBAAa,iBAAkB,SAAQ,QAAQ;gBAE3C,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAKpC;AAED,oBAAoB;AACpB,qBAAa,cAAe,SAAQ,QAAQ;gBAExC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAKpC;AAED,mBAAmB;AACnB,qBAAa,aAAc,SAAQ,QAAQ;gBAEvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAKpC;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,QAAQ,CAeV"}
|
package/dist/index.js
CHANGED
|
@@ -1,20 +1,35 @@
|
|
|
1
1
|
// @typokit/errors — Structured Error Class Hierarchy
|
|
2
|
+
// V8/Node.js-specific Error extensions (not in standard ES typings)
|
|
3
|
+
const ErrorWithV8 = Error;
|
|
2
4
|
/**
|
|
3
5
|
* Base error class for all TypoKit errors.
|
|
4
6
|
* Extends native Error with structured fields for status, code, and details.
|
|
7
|
+
*
|
|
8
|
+
* Stack trace capture is skipped at construction time for performance.
|
|
9
|
+
* AppError stack is never used in response serialization (toJSON() excludes it).
|
|
10
|
+
* Call captureStack() if you need the trace for debugging.
|
|
5
11
|
*/
|
|
6
12
|
export class AppError extends Error {
|
|
7
13
|
code;
|
|
8
14
|
status;
|
|
9
15
|
details;
|
|
10
16
|
constructor(code, status, message, details) {
|
|
17
|
+
// Skip expensive V8 stack walk — restore limit after super()
|
|
18
|
+
const prevLimit = ErrorWithV8.stackTraceLimit;
|
|
19
|
+
ErrorWithV8.stackTraceLimit = 0;
|
|
11
20
|
super(message);
|
|
12
21
|
this.code = code;
|
|
13
22
|
this.status = status;
|
|
14
23
|
this.details = details;
|
|
24
|
+
ErrorWithV8.stackTraceLimit = prevLimit;
|
|
15
25
|
this.name = "AppError";
|
|
16
26
|
Object.setPrototypeOf(this, new.target.prototype);
|
|
17
27
|
}
|
|
28
|
+
/** Lazily capture stack trace (skipped at construction for performance) */
|
|
29
|
+
captureStack() {
|
|
30
|
+
ErrorWithV8.captureStackTrace(this);
|
|
31
|
+
return this;
|
|
32
|
+
}
|
|
18
33
|
/** Serialize to the ErrorResponse schema from @typokit/types */
|
|
19
34
|
toJSON() {
|
|
20
35
|
return {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qDAAqD;AAIrD
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"types": "./dist/index.d.ts"
|
|
7
7
|
}
|
|
8
8
|
},
|
|
9
|
-
"version": "0.3.
|
|
9
|
+
"version": "0.3.4",
|
|
10
10
|
"type": "module",
|
|
11
11
|
"files": [
|
|
12
12
|
"dist",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"main": "./dist/index.js",
|
|
16
16
|
"types": "./dist/index.d.ts",
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@typokit/types": "0.3.
|
|
18
|
+
"@typokit/types": "0.3.4"
|
|
19
19
|
},
|
|
20
20
|
"repository": {
|
|
21
21
|
"type": "git",
|
package/src/index.test.ts
CHANGED
|
@@ -166,3 +166,40 @@ describe("createAppError", () => {
|
|
|
166
166
|
expect(err.details).toEqual({ field: "name" });
|
|
167
167
|
});
|
|
168
168
|
});
|
|
169
|
+
|
|
170
|
+
describe("AppError lazy stack trace", () => {
|
|
171
|
+
it("should skip stack trace capture at construction time", () => {
|
|
172
|
+
const err = new AppError("CODE", 500, "test");
|
|
173
|
+
// Stack should be empty or minimal (no frame lines) since capture is skipped
|
|
174
|
+
const stack = err.stack ?? "";
|
|
175
|
+
const frames = stack
|
|
176
|
+
.split("\n")
|
|
177
|
+
.filter((line) => line.trim().startsWith("at "));
|
|
178
|
+
expect(frames.length).toBe(0);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("should capture stack trace on demand via captureStack()", () => {
|
|
182
|
+
const err = new AppError("CODE", 500, "test");
|
|
183
|
+
err.captureStack();
|
|
184
|
+
const stack = err.stack ?? "";
|
|
185
|
+
const frames = stack
|
|
186
|
+
.split("\n")
|
|
187
|
+
.filter((line) => line.trim().startsWith("at "));
|
|
188
|
+
expect(frames.length).toBeGreaterThan(0);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("captureStack() should return the error instance for chaining", () => {
|
|
192
|
+
const err = new AppError("CODE", 500, "test");
|
|
193
|
+
const result = err.captureStack();
|
|
194
|
+
expect(result).toBe(err);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("subclasses should also skip stack trace at construction", () => {
|
|
198
|
+
const err = new NotFoundError("NF", "not found");
|
|
199
|
+
const stack = err.stack ?? "";
|
|
200
|
+
const frames = stack
|
|
201
|
+
.split("\n")
|
|
202
|
+
.filter((line) => line.trim().startsWith("at "));
|
|
203
|
+
expect(frames.length).toBe(0);
|
|
204
|
+
});
|
|
205
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -2,9 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
import type { ErrorResponse } from "@typokit/types";
|
|
4
4
|
|
|
5
|
+
// V8/Node.js-specific Error extensions (not in standard ES typings)
|
|
6
|
+
const ErrorWithV8 = Error as unknown as {
|
|
7
|
+
stackTraceLimit: number;
|
|
8
|
+
captureStackTrace(
|
|
9
|
+
target: object,
|
|
10
|
+
constructorOpt?: (...args: unknown[]) => unknown,
|
|
11
|
+
): void;
|
|
12
|
+
new (message?: string): Error;
|
|
13
|
+
prototype: Error;
|
|
14
|
+
};
|
|
15
|
+
|
|
5
16
|
/**
|
|
6
17
|
* Base error class for all TypoKit errors.
|
|
7
18
|
* Extends native Error with structured fields for status, code, and details.
|
|
19
|
+
*
|
|
20
|
+
* Stack trace capture is skipped at construction time for performance.
|
|
21
|
+
* AppError stack is never used in response serialization (toJSON() excludes it).
|
|
22
|
+
* Call captureStack() if you need the trace for debugging.
|
|
8
23
|
*/
|
|
9
24
|
export class AppError extends Error {
|
|
10
25
|
constructor(
|
|
@@ -13,11 +28,21 @@ export class AppError extends Error {
|
|
|
13
28
|
message: string,
|
|
14
29
|
public readonly details?: Record<string, unknown>,
|
|
15
30
|
) {
|
|
31
|
+
// Skip expensive V8 stack walk — restore limit after super()
|
|
32
|
+
const prevLimit = ErrorWithV8.stackTraceLimit;
|
|
33
|
+
ErrorWithV8.stackTraceLimit = 0;
|
|
16
34
|
super(message);
|
|
35
|
+
ErrorWithV8.stackTraceLimit = prevLimit;
|
|
17
36
|
this.name = "AppError";
|
|
18
37
|
Object.setPrototypeOf(this, new.target.prototype);
|
|
19
38
|
}
|
|
20
39
|
|
|
40
|
+
/** Lazily capture stack trace (skipped at construction for performance) */
|
|
41
|
+
captureStack(): this {
|
|
42
|
+
ErrorWithV8.captureStackTrace(this);
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
|
|
21
46
|
/** Serialize to the ErrorResponse schema from @typokit/types */
|
|
22
47
|
toJSON(): ErrorResponse {
|
|
23
48
|
return {
|