@wireio/shared 1.0.69 → 1.0.71
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/lib/cjs/errors/NestedError.d.ts +110 -6
- package/lib/cjs/errors/NestedError.d.ts.map +1 -1
- package/lib/cjs/errors/NestedError.js +139 -9
- package/lib/esm/errors/NestedError.d.ts +110 -6
- package/lib/esm/errors/NestedError.d.ts.map +1 -1
- package/lib/esm/errors/NestedError.js +139 -9
- package/lib/test-cjs/errors/NestedError.test.js +81 -34
- package/lib/test-cjs/errors/NestedError.test.js.map +1 -1
- package/lib/tsconfig.cjs.jest.tsbuildinfo +1 -1
- package/lib/tsconfig.cjs.tsbuildinfo +1 -1
- package/lib/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -1,10 +1,114 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Structured, machine-readable diagnostic context captured at a {@link NestedError}
|
|
3
|
+
* throw site — the values that make a failure diagnosable (the `text` that failed to
|
|
4
|
+
* parse, a schema / type name, an id, …). Heterogeneous by nature, so the values are
|
|
5
|
+
* `unknown` (a documented type-erased bag, not a shortcut).
|
|
6
|
+
*/
|
|
7
|
+
export type NestedErrorContext = Record<string, unknown>;
|
|
8
|
+
/**
|
|
9
|
+
* Options for {@link NestedError} — what it preserves about the failure it wraps.
|
|
10
|
+
*/
|
|
11
|
+
export interface NestedErrorOptions<Context extends NestedErrorContext = NestedErrorContext> {
|
|
12
|
+
/**
|
|
13
|
+
* The originating error(s) — the root-cause chain that must NOT be swallowed. A
|
|
14
|
+
* non-Error thrown value is coerced to an Error; the first becomes the native
|
|
15
|
+
* ES2022 `Error.cause`.
|
|
16
|
+
*/
|
|
17
|
+
cause?: unknown;
|
|
18
|
+
/** Diagnostic context captured at the throw site. */
|
|
19
|
+
context?: Context;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* An Error that PRESERVES what it wraps instead of restringing it. Given a new
|
|
23
|
+
* message string, it ALSO retains the full cause chain: the originating error(s)
|
|
24
|
+
* survive as {@link NestedError.causes} (and the native `Error.cause`) — the real
|
|
25
|
+
* Error objects, so **each cause keeps its own stack trace and message** — and a
|
|
26
|
+
* nested-exception `Caused by:` section per cause is appended to this error's
|
|
27
|
+
* {@link NestedError.stack}, so the whole chain (each cause's stack + message) is
|
|
28
|
+
* visible wherever the error is printed, not only via the programmatic accessors.
|
|
29
|
+
* The diagnostic {@link NestedError.context} (the `text`, the schema / type name, …)
|
|
30
|
+
* is BOTH a structured property AND folded into the message.
|
|
31
|
+
*
|
|
32
|
+
* Never rewrite a caught error into a bare ``new Error(`… ${err.message}`)`` — that
|
|
33
|
+
* SWALLOWS the cause and the context. Wrap it:
|
|
34
|
+
* `new NestedError("…", { cause: err, context: { … } })`.
|
|
35
|
+
*/
|
|
36
|
+
export declare class NestedError<Context extends NestedErrorContext = NestedErrorContext> extends Error {
|
|
37
|
+
/** The originating error chain (flattened + coerced to Error); `causes[0]` is the native `.cause`. */
|
|
38
|
+
readonly causes: Error[];
|
|
39
|
+
/** The diagnostic context captured at the throw site. */
|
|
40
|
+
readonly context: Context;
|
|
41
|
+
/**
|
|
42
|
+
* @param message - The high-level failure description.
|
|
43
|
+
* @param options - The {@link NestedErrorOptions.cause} to preserve + the {@link NestedErrorOptions.context} to capture.
|
|
44
|
+
*/
|
|
45
|
+
constructor(message: string, options?: NestedErrorOptions<Context>);
|
|
4
46
|
}
|
|
5
47
|
export declare namespace NestedError {
|
|
6
|
-
|
|
7
|
-
|
|
48
|
+
/** Max characters of any single context value folded into the message — long `text` is truncated. */
|
|
49
|
+
const ContextPreviewMaxChars = 200;
|
|
50
|
+
/** The marker appended when a folded context value is truncated. */
|
|
51
|
+
const TruncationSuffix = "\u2026";
|
|
52
|
+
/** Prefix marking each retained cause in the composed stack (nested-exception style). */
|
|
53
|
+
const CausedByPrefix = "Caused by: ";
|
|
54
|
+
/**
|
|
55
|
+
* Append a `Caused by:` section per cause to `stack`, so every cause's stack trace
|
|
56
|
+
* AND message stay visible in `.stack` (and any logger that prints it) — not only
|
|
57
|
+
* via the programmatic {@link NestedError.causes} / native `Error.cause`. Each
|
|
58
|
+
* cause's own `.stack` already begins with its `name: message`, so both are kept.
|
|
59
|
+
*
|
|
60
|
+
* @param stack - The wrapping error's own stack (may be undefined in exotic runtimes).
|
|
61
|
+
* @param causes - The retained cause chain.
|
|
62
|
+
* @returns The wrapping stack with one appended `Caused by:` section per cause.
|
|
63
|
+
*/
|
|
64
|
+
function composeStack(stack: string | undefined, causes: Error[]): string;
|
|
65
|
+
/**
|
|
66
|
+
* Create a {@link NestedError}.
|
|
67
|
+
*
|
|
68
|
+
* @param message - The high-level failure description.
|
|
69
|
+
* @param options - The cause to preserve + the context to capture.
|
|
70
|
+
* @returns The constructed error.
|
|
71
|
+
*/
|
|
72
|
+
function create<Context extends NestedErrorContext = NestedErrorContext>(message: string, options?: NestedErrorOptions<Context>): NestedError<Context>;
|
|
73
|
+
/**
|
|
74
|
+
* Create + throw a {@link NestedError}.
|
|
75
|
+
*
|
|
76
|
+
* @param message - The high-level failure description.
|
|
77
|
+
* @param options - The cause to preserve + the context to capture.
|
|
78
|
+
*/
|
|
79
|
+
function throwError<Context extends NestedErrorContext = NestedErrorContext>(message: string, options?: NestedErrorOptions<Context>): never;
|
|
80
|
+
/**
|
|
81
|
+
* Coerce a thrown value (an Error, an array of them, or any value) into a flat
|
|
82
|
+
* `Error[]`, so a caught `unknown` can be preserved as a cause without loss.
|
|
83
|
+
*
|
|
84
|
+
* @param cause - The caught / rejected value.
|
|
85
|
+
* @returns The coerced error chain (empty when `cause` is nullish).
|
|
86
|
+
*/
|
|
87
|
+
function toErrors(cause: unknown): Error[];
|
|
88
|
+
/**
|
|
89
|
+
* Coerce a single thrown value into an Error (Errors pass through unchanged).
|
|
90
|
+
*
|
|
91
|
+
* @param value - The caught value.
|
|
92
|
+
* @returns `value` when it is an Error, else a new Error wrapping its string form.
|
|
93
|
+
*/
|
|
94
|
+
function toError(value: unknown): Error;
|
|
95
|
+
/**
|
|
96
|
+
* Fold a compact, truncated {@link NestedErrorContext} summary into the message so
|
|
97
|
+
* it is visible wherever the message is (logs, stack traces), not only on the
|
|
98
|
+
* `.context` property.
|
|
99
|
+
*
|
|
100
|
+
* @param message - The base message.
|
|
101
|
+
* @param context - The context to summarize, if any.
|
|
102
|
+
* @returns `message` with a ` (key=value, …)` suffix when context is non-empty.
|
|
103
|
+
*/
|
|
104
|
+
function composeMessage(message: string, context?: NestedErrorContext): string;
|
|
105
|
+
/**
|
|
106
|
+
* Render one context value for the message suffix — strings verbatim, everything
|
|
107
|
+
* else via a bigint-/cycle-safe form, truncated to {@link ContextPreviewMaxChars}.
|
|
108
|
+
*
|
|
109
|
+
* @param value - The context value.
|
|
110
|
+
* @returns The truncated preview string.
|
|
111
|
+
*/
|
|
112
|
+
function previewValue(value: unknown): string;
|
|
8
113
|
}
|
|
9
|
-
export default NestedError;
|
|
10
114
|
//# sourceMappingURL=NestedError.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NestedError.d.ts","sourceRoot":"","sources":["../../../src/errors/NestedError.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"NestedError.d.ts","sourceRoot":"","sources":["../../../src/errors/NestedError.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAExD;;GAEG;AACH,MAAM,WAAW,kBAAkB,CACjC,OAAO,SAAS,kBAAkB,GAAG,kBAAkB;IAEvD;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,qDAAqD;IACrD,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,WAAW,CACtB,OAAO,SAAS,kBAAkB,GAAG,kBAAkB,CACvD,SAAQ,KAAK;IACb,sGAAsG;IACtG,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,CAAA;IAExB,yDAAyD;IACzD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IAEzB;;;OAGG;gBACS,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAkB,CAAC,OAAO,CAAM;CAcvE;AAED,yBAAiB,WAAW,CAAC;IAC3B,qGAAqG;IAC9F,MAAM,sBAAsB,MAAM,CAAA;IAEzC,oEAAoE;IAC7D,MAAM,gBAAgB,WAAM,CAAA;IAEnC,yFAAyF;IAClF,MAAM,cAAc,gBAAgB,CAAA;IAE3C;;;;;;;;;OASG;IACH,SAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAM/E;IAED;;;;;;OAMG;IACH,SAAgB,MAAM,CAAC,OAAO,SAAS,kBAAkB,GAAG,kBAAkB,EAC5E,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,kBAAkB,CAAC,OAAO,CAAM,GACxC,WAAW,CAAC,OAAO,CAAC,CAEtB;IAED;;;;;OAKG;IACH,SAAgB,UAAU,CACxB,OAAO,SAAS,kBAAkB,GAAG,kBAAkB,EACvD,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAkB,CAAC,OAAO,CAAM,GAAG,KAAK,CAEnE;IAED;;;;;;OAMG;IACH,SAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,EAAE,CAIhD;IAED;;;;;OAKG;IACH,SAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAE7C;IAED;;;;;;;;OAQG;IACH,SAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,kBAAkB,GAC3B,MAAM,CAOR;IAED;;;;;;OAMG;IACH,SAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAKnD;CACF"}
|
|
@@ -1,24 +1,154 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.NestedError = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* An Error that PRESERVES what it wraps instead of restringing it. Given a new
|
|
6
|
+
* message string, it ALSO retains the full cause chain: the originating error(s)
|
|
7
|
+
* survive as {@link NestedError.causes} (and the native `Error.cause`) — the real
|
|
8
|
+
* Error objects, so **each cause keeps its own stack trace and message** — and a
|
|
9
|
+
* nested-exception `Caused by:` section per cause is appended to this error's
|
|
10
|
+
* {@link NestedError.stack}, so the whole chain (each cause's stack + message) is
|
|
11
|
+
* visible wherever the error is printed, not only via the programmatic accessors.
|
|
12
|
+
* The diagnostic {@link NestedError.context} (the `text`, the schema / type name, …)
|
|
13
|
+
* is BOTH a structured property AND folded into the message.
|
|
14
|
+
*
|
|
15
|
+
* Never rewrite a caught error into a bare ``new Error(`… ${err.message}`)`` — that
|
|
16
|
+
* SWALLOWS the cause and the context. Wrap it:
|
|
17
|
+
* `new NestedError("…", { cause: err, context: { … } })`.
|
|
18
|
+
*/
|
|
4
19
|
class NestedError extends Error {
|
|
20
|
+
/** The originating error chain (flattened + coerced to Error); `causes[0]` is the native `.cause`. */
|
|
5
21
|
causes;
|
|
6
|
-
|
|
7
|
-
|
|
22
|
+
/** The diagnostic context captured at the throw site. */
|
|
23
|
+
context;
|
|
24
|
+
/**
|
|
25
|
+
* @param message - The high-level failure description.
|
|
26
|
+
* @param options - The {@link NestedErrorOptions.cause} to preserve + the {@link NestedErrorOptions.context} to capture.
|
|
27
|
+
*/
|
|
28
|
+
constructor(message, options = {}) {
|
|
29
|
+
const causes = NestedError.toErrors(options.cause);
|
|
30
|
+
super(NestedError.composeMessage(message, options.context), causes.length > 0 ? { cause: causes[0] } : undefined);
|
|
8
31
|
this.name = "NestedError";
|
|
9
|
-
this.causes = causes
|
|
32
|
+
this.causes = causes;
|
|
33
|
+
this.context = options.context ?? {};
|
|
34
|
+
// Retain each cause's stack + message VISIBLY: append a `Caused by:` section
|
|
35
|
+
// per cause so the full chain shows in `.stack` (and any logger that prints it),
|
|
36
|
+
// not only via the programmatic `.causes` / native `.cause`.
|
|
37
|
+
this.stack = NestedError.composeStack(this.stack, causes);
|
|
10
38
|
}
|
|
11
39
|
}
|
|
12
40
|
exports.NestedError = NestedError;
|
|
13
41
|
(function (NestedError) {
|
|
14
|
-
|
|
15
|
-
|
|
42
|
+
/** Max characters of any single context value folded into the message — long `text` is truncated. */
|
|
43
|
+
NestedError.ContextPreviewMaxChars = 200;
|
|
44
|
+
/** The marker appended when a folded context value is truncated. */
|
|
45
|
+
NestedError.TruncationSuffix = "…";
|
|
46
|
+
/** Prefix marking each retained cause in the composed stack (nested-exception style). */
|
|
47
|
+
NestedError.CausedByPrefix = "Caused by: ";
|
|
48
|
+
/**
|
|
49
|
+
* Append a `Caused by:` section per cause to `stack`, so every cause's stack trace
|
|
50
|
+
* AND message stay visible in `.stack` (and any logger that prints it) — not only
|
|
51
|
+
* via the programmatic {@link NestedError.causes} / native `Error.cause`. Each
|
|
52
|
+
* cause's own `.stack` already begins with its `name: message`, so both are kept.
|
|
53
|
+
*
|
|
54
|
+
* @param stack - The wrapping error's own stack (may be undefined in exotic runtimes).
|
|
55
|
+
* @param causes - The retained cause chain.
|
|
56
|
+
* @returns The wrapping stack with one appended `Caused by:` section per cause.
|
|
57
|
+
*/
|
|
58
|
+
function composeStack(stack, causes) {
|
|
59
|
+
return causes.reduce((composed, cause) => `${composed}\n${NestedError.CausedByPrefix}${cause.stack ?? `${cause.name}: ${cause.message}`}`, stack ?? "");
|
|
60
|
+
}
|
|
61
|
+
NestedError.composeStack = composeStack;
|
|
62
|
+
/**
|
|
63
|
+
* Create a {@link NestedError}.
|
|
64
|
+
*
|
|
65
|
+
* @param message - The high-level failure description.
|
|
66
|
+
* @param options - The cause to preserve + the context to capture.
|
|
67
|
+
* @returns The constructed error.
|
|
68
|
+
*/
|
|
69
|
+
function create(message, options = {}) {
|
|
70
|
+
return new NestedError(message, options);
|
|
16
71
|
}
|
|
17
72
|
NestedError.create = create;
|
|
18
|
-
|
|
19
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Create + throw a {@link NestedError}.
|
|
75
|
+
*
|
|
76
|
+
* @param message - The high-level failure description.
|
|
77
|
+
* @param options - The cause to preserve + the context to capture.
|
|
78
|
+
*/
|
|
79
|
+
function throwError(message, options = {}) {
|
|
80
|
+
throw create(message, options);
|
|
20
81
|
}
|
|
21
82
|
NestedError.throwError = throwError;
|
|
83
|
+
/**
|
|
84
|
+
* Coerce a thrown value (an Error, an array of them, or any value) into a flat
|
|
85
|
+
* `Error[]`, so a caught `unknown` can be preserved as a cause without loss.
|
|
86
|
+
*
|
|
87
|
+
* @param cause - The caught / rejected value.
|
|
88
|
+
* @returns The coerced error chain (empty when `cause` is nullish).
|
|
89
|
+
*/
|
|
90
|
+
function toErrors(cause) {
|
|
91
|
+
return (Array.isArray(cause) ? cause : cause == null ? [] : [cause]).map(toError);
|
|
92
|
+
}
|
|
93
|
+
NestedError.toErrors = toErrors;
|
|
94
|
+
/**
|
|
95
|
+
* Coerce a single thrown value into an Error (Errors pass through unchanged).
|
|
96
|
+
*
|
|
97
|
+
* @param value - The caught value.
|
|
98
|
+
* @returns `value` when it is an Error, else a new Error wrapping its string form.
|
|
99
|
+
*/
|
|
100
|
+
function toError(value) {
|
|
101
|
+
return value instanceof Error ? value : new Error(String(value));
|
|
102
|
+
}
|
|
103
|
+
NestedError.toError = toError;
|
|
104
|
+
/**
|
|
105
|
+
* Fold a compact, truncated {@link NestedErrorContext} summary into the message so
|
|
106
|
+
* it is visible wherever the message is (logs, stack traces), not only on the
|
|
107
|
+
* `.context` property.
|
|
108
|
+
*
|
|
109
|
+
* @param message - The base message.
|
|
110
|
+
* @param context - The context to summarize, if any.
|
|
111
|
+
* @returns `message` with a ` (key=value, …)` suffix when context is non-empty.
|
|
112
|
+
*/
|
|
113
|
+
function composeMessage(message, context) {
|
|
114
|
+
const entries = context == null ? [] : Object.entries(context);
|
|
115
|
+
return entries.length === 0
|
|
116
|
+
? message
|
|
117
|
+
: `${message} (${entries
|
|
118
|
+
.map(([key, value]) => `${key}=${previewValue(value)}`)
|
|
119
|
+
.join(", ")})`;
|
|
120
|
+
}
|
|
121
|
+
NestedError.composeMessage = composeMessage;
|
|
122
|
+
/**
|
|
123
|
+
* Render one context value for the message suffix — strings verbatim, everything
|
|
124
|
+
* else via a bigint-/cycle-safe form, truncated to {@link ContextPreviewMaxChars}.
|
|
125
|
+
*
|
|
126
|
+
* @param value - The context value.
|
|
127
|
+
* @returns The truncated preview string.
|
|
128
|
+
*/
|
|
129
|
+
function previewValue(value) {
|
|
130
|
+
const rendered = typeof value === "string" ? value : safeStringify(value);
|
|
131
|
+
return rendered.length > NestedError.ContextPreviewMaxChars
|
|
132
|
+
? `${rendered.slice(0, NestedError.ContextPreviewMaxChars)}${NestedError.TruncationSuffix}`
|
|
133
|
+
: rendered;
|
|
134
|
+
}
|
|
135
|
+
NestedError.previewValue = previewValue;
|
|
22
136
|
})(NestedError || (exports.NestedError = NestedError = {}));
|
|
23
|
-
|
|
24
|
-
|
|
137
|
+
/**
|
|
138
|
+
* A best-effort rendering of `value` for a message preview: JSON when serializable,
|
|
139
|
+
* else `String(value)`. Pure display fallback — a BigInt or a circular object makes
|
|
140
|
+
* `JSON.stringify` throw — NOT error handling, so the catch is a deliberate render
|
|
141
|
+
* fallback rather than a swallow.
|
|
142
|
+
*
|
|
143
|
+
* @param value - The value to render.
|
|
144
|
+
* @returns A single-line string form of `value`.
|
|
145
|
+
*/
|
|
146
|
+
function safeStringify(value) {
|
|
147
|
+
try {
|
|
148
|
+
return JSON.stringify(value) ?? String(value);
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return String(value);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTmVzdGVkRXJyb3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvZXJyb3JzL05lc3RlZEVycm9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQXdCQTs7Ozs7Ozs7Ozs7Ozs7R0FjRztBQUNILE1BQWEsV0FFWCxTQUFRLEtBQUs7SUFDYixzR0FBc0c7SUFDN0YsTUFBTSxDQUFTO0lBRXhCLHlEQUF5RDtJQUNoRCxPQUFPLENBQVM7SUFFekI7OztPQUdHO0lBQ0gsWUFBWSxPQUFlLEVBQUUsVUFBdUMsRUFBRTtRQUNwRSxNQUFNLE1BQU0sR0FBRyxXQUFXLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQTtRQUNsRCxLQUFLLENBQ0gsV0FBVyxDQUFDLGNBQWMsQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUNwRCxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FDckQsQ0FBQTtRQUNELElBQUksQ0FBQyxJQUFJLEdBQUcsYUFBYSxDQUFBO1FBQ3pCLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFBO1FBQ3BCLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDLE9BQU8sSUFBSyxFQUFjLENBQUE7UUFDakQsNkVBQTZFO1FBQzdFLGlGQUFpRjtRQUNqRiw2REFBNkQ7UUFDN0QsSUFBSSxDQUFDLEtBQUssR0FBRyxXQUFXLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDLENBQUE7SUFDM0QsQ0FBQztDQUNGO0FBM0JELGtDQTJCQztBQUVELFdBQWlCLFdBQVc7SUFDMUIscUdBQXFHO0lBQ3hGLGtDQUFzQixHQUFHLEdBQUcsQ0FBQTtJQUV6QyxvRUFBb0U7SUFDdkQsNEJBQWdCLEdBQUcsR0FBRyxDQUFB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QUFBO0FBQ0gsQ0FBQyxFQS9HZ0IsV0FBVywyQkFBWCxXQUFXLFFBK0czQjtBQUVEOzs7Ozs7OztHQVFHO0FBQ0gsU0FBUyxhQUFhLENBQUMsS0FBYztJQUNuQyxJQUFJLENBQUM7UUFDSCxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLElBQUksTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFBO0lBQy9DLENBQUM7SUFBQyxNQUFNLENBQUM7UUFDUCxPQUFPLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQTtJQUN0QixDQUFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogU3RydWN0dXJlZCwgbWFjaGluZS1yZWFkYWJsZSBkaWFnbm9zdGljIGNvbnRleHQgY2FwdHVyZWQgYXQgYSB7QGxpbmsgTmVzdGVkRXJyb3J9XG4gKiB0aHJvdyBzaXRlIOKAlCB0aGUgdmFsdWVzIHRoYXQgbWFrZSBhIGZhaWx1cmUgZGlhZ25vc2FibGUgKHRoZSBgdGV4dGAgdGhhdCBmYWlsZWQgdG9cbiAqIHBhcnNlLCBhIHNjaGVtYSAvIHR5cGUgbmFtZSwgYW4gaWQsIOKApikuIEhldGVyb2dlbmVvdXMgYnkgbmF0dXJlLCBzbyB0aGUgdmFsdWVzIGFyZVxuICogYHVua25vd25gIChhIGRvY3VtZW50ZWQgdHlwZS1lcmFzZWQgYmFnLCBub3QgYSBzaG9ydGN1dCkuXG4gKi9cbmV4cG9ydCB0eXBlIE5lc3RlZEVycm9yQ29udGV4dCA9IFJlY29yZDxzdHJpbmcsIHVua25vd24+XG5cbi8qKlxuICogT3B0aW9ucyBmb3Ige0BsaW5rIE5lc3RlZEVycm9yfSDigJQgd2hhdCBpdCBwcmVzZXJ2ZXMgYWJvdXQgdGhlIGZhaWx1cmUgaXQgd3JhcHMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTmVzdGVkRXJyb3JPcHRpb25zPFxuICBDb250ZXh0IGV4dGVuZHMgTmVzdGVkRXJyb3JDb250ZXh0ID0gTmVzdGVkRXJyb3JDb250ZXh0XG4+IHtcbiAgLyoqXG4gICAqIFRoZSBvcmlnaW5hdGluZyBlcnJvcihzKSDigJQgdGhlIHJvb3QtY2F1c2UgY2hhaW4gdGhhdCBtdXN0IE5PVCBiZSBzd2FsbG93ZWQuIEFcbiAgICogbm9uLUVycm9yIHRocm93biB2YWx1ZSBpcyBjb2VyY2VkIHRvIGFuIEVycm9yOyB0aGUgZmlyc3QgYmVjb21lcyB0aGUgbmF0aXZlXG4gICAqIEVTMjAyMiBgRXJyb3IuY2F1c2VgLlxuICAgKi9cbiAgY2F1c2U/OiB1bmtub3duXG4gIC8qKiBEaWFnbm9zdGljIGNvbnRleHQgY2FwdHVyZWQgYXQgdGhlIHRocm93IHNpdGUuICovXG4gIGNvbnRleHQ/OiBDb250ZXh0XG59XG5cbi8qKlxuICogQW4gRXJyb3IgdGhhdCBQUkVTRVJWRVMgd2hhdCBpdCB3cmFwcyBpbnN0ZWFkIG9mIHJlc3RyaW5naW5nIGl0LiBHaXZlbiBhIG5ld1xuICogbWVzc2FnZSBzdHJpbmcsIGl0IEFMU08gcmV0YWlucyB0aGUgZnVsbCBjYXVzZSBjaGFpbjogdGhlIG9yaWdpbmF0aW5nIGVycm9yKHMpXG4gKiBzdXJ2aXZlIGFzIHtAbGluayBOZXN0ZWRFcnJvci5jYXVzZXN9IChhbmQgdGhlIG5hdGl2ZSBgRXJyb3IuY2F1c2VgKSDigJQgdGhlIHJlYWxcbiAqIEVycm9yIG9iamVjdHMsIHNvICoqZWFjaCBjYXVzZSBrZWVwcyBpdHMgb3duIHN0YWNrIHRyYWNlIGFuZCBtZXNzYWdlKiog4oCUIGFuZCBhXG4gKiBuZXN0ZWQtZXhjZXB0aW9uIGBDYXVzZWQgYnk6YCBzZWN0aW9uIHBlciBjYXVzZSBpcyBhcHBlbmRlZCB0byB0aGlzIGVycm9yJ3NcbiAqIHtAbGluayBOZXN0ZWRFcnJvci5zdGFja30sIHNvIHRoZSB3aG9sZSBjaGFpbiAoZWFjaCBjYXVzZSdzIHN0YWNrICsgbWVzc2FnZSkgaXNcbiAqIHZpc2libGUgd2hlcmV2ZXIgdGhlIGVycm9yIGlzIHByaW50ZWQsIG5vdCBvbmx5IHZpYSB0aGUgcHJvZ3JhbW1hdGljIGFjY2Vzc29ycy5cbiAqIFRoZSBkaWFnbm9zdGljIHtAbGluayBOZXN0ZWRFcnJvci5jb250ZXh0fSAodGhlIGB0ZXh0YCwgdGhlIHNjaGVtYSAvIHR5cGUgbmFtZSwg4oCmKVxuICogaXMgQk9USCBhIHN0cnVjdHVyZWQgcHJvcGVydHkgQU5EIGZvbGRlZCBpbnRvIHRoZSBtZXNzYWdlLlxuICpcbiAqIE5ldmVyIHJld3JpdGUgYSBjYXVnaHQgZXJyb3IgaW50byBhIGJhcmUgYGBuZXcgRXJyb3IoYOKApiAke2Vyci5tZXNzYWdlfWApYGAg4oCUIHRoYXRcbiAqIFNXQUxMT1dTIHRoZSBjYXVzZSBhbmQgdGhlIGNvbnRleHQuIFdyYXAgaXQ6XG4gKiBgbmV3IE5lc3RlZEVycm9yKFwi4oCmXCIsIHsgY2F1c2U6IGVyciwgY29udGV4dDogeyDigKYgfSB9KWAuXG4gKi9cbmV4cG9ydCBjbGFzcyBOZXN0ZWRFcnJvcjxcbiAgQ29udGV4dCBleHRlbmRzIE5lc3RlZEVycm9yQ29udGV4dCA9IE5lc3RlZEVycm9yQ29udGV4dFxuPiBleHRlbmRzIEVycm9yIHtcbiAgLyoqIFRoZSBvcmlnaW5hdGluZyBlcnJvciBjaGFpbiAoZmxhdHRlbmVkICsgY29lcmNlZCB0byBFcnJvcik7IGBjYXVzZXNbMF1gIGlzIHRoZSBuYXRpdmUgYC5jYXVzZWAuICovXG4gIHJlYWRvbmx5IGNhdXNlczogRXJyb3JbXVxuXG4gIC8qKiBUaGUgZGlhZ25vc3RpYyBjb250ZXh0IGNhcHR1cmVkIGF0IHRoZSB0aHJvdyBzaXRlLiAqL1xuICByZWFkb25seSBjb250ZXh0OiBDb250ZXh0XG5cbiAgLyoqXG4gICAqIEBwYXJhbSBtZXNzYWdlIC0gVGhlIGhpZ2gtbGV2ZWwgZmFpbHVyZSBkZXNjcmlwdGlvbi5cbiAgICogQHBhcmFtIG9wdGlvbnMgLSBUaGUge0BsaW5rIE5lc3RlZEVycm9yT3B0aW9ucy5jYXVzZX0gdG8gcHJlc2VydmUgKyB0aGUge0BsaW5rIE5lc3RlZEVycm9yT3B0aW9ucy5jb250ZXh0fSB0byBjYXB0dXJlLlxuICAgKi9cbiAgY29uc3RydWN0b3IobWVzc2FnZTogc3RyaW5nLCBvcHRpb25zOiBOZXN0ZWRFcnJvck9wdGlvbnM8Q29udGV4dD4gPSB7fSkge1xuICAgIGNvbnN0IGNhdXNlcyA9IE5lc3RlZEVycm9yLnRvRXJyb3JzKG9wdGlvbnMuY2F1c2UpXG4gICAgc3VwZXIoXG4gICAgICBOZXN0ZWRFcnJvci5jb21wb3NlTWVzc2FnZShtZXNzYWdlLCBvcHRpb25zLmNvbnRleHQpLFxuICAgICAgY2F1c2VzLmxlbmd0aCA+IDAgPyB7IGNhdXNlOiBjYXVzZXNbMF0gfSA6IHVuZGVmaW5lZFxuICAgIClcbiAgICB0aGlzLm5hbWUgPSBcIk5lc3RlZEVycm9yXCJcbiAgICB0aGlzLmNhdXNlcyA9IGNhdXNlc1xuICAgIHRoaXMuY29udGV4dCA9IG9wdGlvbnMuY29udGV4dCA/PyAoe30gYXMgQ29udGV4dClcbiAgICAvLyBSZXRhaW4gZWFjaCBjYXVzZSdzIHN0YWNrICsgbWVzc2FnZSBWSVNJQkxZOiBhcHBlbmQgYSBgQ2F1c2VkIGJ5OmAgc2VjdGlvblxuICAgIC8vIHBlciBjYXVzZSBzbyB0aGUgZnVsbCBjaGFpbiBzaG93cyBpbiBgLnN0YWNrYCAoYW5kIGFueSBsb2dnZXIgdGhhdCBwcmludHMgaXQpLFxuICAgIC8vIG5vdCBvbmx5IHZpYSB0aGUgcHJvZ3JhbW1hdGljIGAuY2F1c2VzYCAvIG5hdGl2ZSBgLmNhdXNlYC5cbiAgICB0aGlzLnN0YWNrID0gTmVzdGVkRXJyb3IuY29tcG9zZVN0YWNrKHRoaXMuc3RhY2ssIGNhdXNlcylcbiAgfVxufVxuXG5leHBvcnQgbmFtZXNwYWNlIE5lc3RlZEVycm9yIHtcbiAgLyoqIE1heCBjaGFyYWN0ZXJzIG9mIGFueSBzaW5nbGUgY29udGV4dCB2YWx1ZSBmb2xkZWQgaW50byB0aGUgbWVzc2FnZSDigJQgbG9uZyBgdGV4dGAgaXMgdHJ1bmNhdGVkLiAqL1xuICBleHBvcnQgY29uc3QgQ29udGV4dFByZXZpZXdNYXhDaGFycyA9IDIwMFxuXG4gIC8qKiBUaGUgbWFya2VyIGFwcGVuZGVkIHdoZW4gYSBmb2xkZWQgY29udGV4dCB2YWx1ZSBpcyB0cnVuY2F0ZWQuICovXG4gIGV4cG9ydCBjb25zdCBUcnVuY2F0aW9uU3VmZml4ID0gXCLigKZcIlxuXG4gIC8qKiBQcmVmaXggbWFya2luZyBlYWNoIHJldGFpbmVkIGNhdXNlIGluIHRoZSBjb21wb3NlZCBzdGFjayAobmVzdGVkLWV4Y2VwdGlvbiBzdHlsZSkuICovXG4gIGV4cG9ydCBjb25zdCBDYXVzZWRCeVByZWZpeCA9IFwiQ2F1c2VkIGJ5OiBcIlxuXG4gIC8qKlxuICAgKiBBcHBlbmQgYSBgQ2F1c2VkIGJ5OmAgc2VjdGlvbiBwZXIgY2F1c2UgdG8gYHN0YWNrYCwgc28gZXZlcnkgY2F1c2UncyBzdGFjayB0cmFjZVxuICAgKiBBTkQgbWVzc2FnZSBzdGF5IHZpc2libGUgaW4gYC5zdGFja2AgKGFuZCBhbnkgbG9nZ2VyIHRoYXQgcHJpbnRzIGl0KSDigJQgbm90IG9ubHlcbiAgICogdmlhIHRoZSBwcm9ncmFtbWF0aWMge0BsaW5rIE5lc3RlZEVycm9yLmNhdXNlc30gLyBuYXRpdmUgYEVycm9yLmNhdXNlYC4gRWFjaFxuICAgKiBjYXVzZSdzIG93biBgLnN0YWNrYCBhbHJlYWR5IGJlZ2lucyB3aXRoIGl0cyBgbmFtZTogbWVzc2FnZWAsIHNvIGJvdGggYXJlIGtlcHQuXG4gICAqXG4gICAqIEBwYXJhbSBzdGFjayAtIFRoZSB3cmFwcGluZyBlcnJvcidzIG93biBzdGFjayAobWF5IGJlIHVuZGVmaW5lZCBpbiBleG90aWMgcnVudGltZXMpLlxuICAgKiBAcGFyYW0gY2F1c2VzIC0gVGhlIHJldGFpbmVkIGNhdXNlIGNoYWluLlxuICAgKiBAcmV0dXJucyBUaGUgd3JhcHBpbmcgc3RhY2sgd2l0aCBvbmUgYXBwZW5kZWQgYENhdXNlZCBieTpgIHNlY3Rpb24gcGVyIGNhdXNlLlxuICAgKi9cbiAgZXhwb3J0IGZ1bmN0aW9uIGNvbXBvc2VTdGFjayhzdGFjazogc3RyaW5nIHwgdW5kZWZpbmVkLCBjYXVzZXM6IEVycm9yW10pOiBzdHJpbmcge1xuICAgIHJldHVybiBjYXVzZXMucmVkdWNlKFxuICAgICAgKGNvbXBvc2VkLCBjYXVzZSkgPT5cbiAgICAgICAgYCR7Y29tcG9zZWR9XFxuJHtDYXVzZWRCeVByZWZpeH0ke2NhdXNlLnN0YWNrID8/IGAke2NhdXNlLm5hbWV9OiAke2NhdXNlLm1lc3NhZ2V9YH1gLFxuICAgICAgc3RhY2sgPz8gXCJcIlxuICAgIClcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSB7QGxpbmsgTmVzdGVkRXJyb3J9LlxuICAgKlxuICAgKiBAcGFyYW0gbWVzc2FnZSAtIFRoZSBoaWdoLWxldmVsIGZhaWx1cmUgZGVzY3JpcHRpb24uXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gVGhlIGNhdXNlIHRvIHByZXNlcnZlICsgdGhlIGNvbnRleHQgdG8gY2FwdHVyZS5cbiAgICogQHJldHVybnMgVGhlIGNvbnN0cnVjdGVkIGVycm9yLlxuICAgKi9cbiAgZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZTxDb250ZXh0IGV4dGVuZHMgTmVzdGVkRXJyb3JDb250ZXh0ID0gTmVzdGVkRXJyb3JDb250ZXh0PihcbiAgICBtZXNzYWdlOiBzdHJpbmcsXG4gICAgb3B0aW9uczogTmVzdGVkRXJyb3JPcHRpb25zPENvbnRleHQ+ID0ge31cbiAgKTogTmVzdGVkRXJyb3I8Q29udGV4dD4ge1xuICAgIHJldHVybiBuZXcgTmVzdGVkRXJyb3IobWVzc2FnZSwgb3B0aW9ucylcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgKyB0aHJvdyBhIHtAbGluayBOZXN0ZWRFcnJvcn0uXG4gICAqXG4gICAqIEBwYXJhbSBtZXNzYWdlIC0gVGhlIGhpZ2gtbGV2ZWwgZmFpbHVyZSBkZXNjcmlwdGlvbi5cbiAgICogQHBhcmFtIG9wdGlvbnMgLSBUaGUgY2F1c2UgdG8gcHJlc2VydmUgKyB0aGUgY29udGV4dCB0byBjYXB0dXJlLlxuICAgKi9cbiAgZXhwb3J0IGZ1bmN0aW9uIHRocm93RXJyb3I8XG4gICAgQ29udGV4dCBleHRlbmRzIE5lc3RlZEVycm9yQ29udGV4dCA9IE5lc3RlZEVycm9yQ29udGV4dFxuICA+KG1lc3NhZ2U6IHN0cmluZywgb3B0aW9uczogTmVzdGVkRXJyb3JPcHRpb25zPENvbnRleHQ+ID0ge30pOiBuZXZlciB7XG4gICAgdGhyb3cgY3JlYXRlKG1lc3NhZ2UsIG9wdGlvbnMpXG4gIH1cblxuICAvKipcbiAgICogQ29lcmNlIGEgdGhyb3duIHZhbHVlIChhbiBFcnJvciwgYW4gYXJyYXkgb2YgdGhlbSwgb3IgYW55IHZhbHVlKSBpbnRvIGEgZmxhdFxuICAgKiBgRXJyb3JbXWAsIHNvIGEgY2F1Z2h0IGB1bmtub3duYCBjYW4gYmUgcHJlc2VydmVkIGFzIGEgY2F1c2Ugd2l0aG91dCBsb3NzLlxuICAgKlxuICAgKiBAcGFyYW0gY2F1c2UgLSBUaGUgY2F1Z2h0IC8gcmVqZWN0ZWQgdmFsdWUuXG4gICAqIEByZXR1cm5zIFRoZSBjb2VyY2VkIGVycm9yIGNoYWluIChlbXB0eSB3aGVuIGBjYXVzZWAgaXMgbnVsbGlzaCkuXG4gICAqL1xuICBleHBvcnQgZnVuY3Rpb24gdG9FcnJvcnMoY2F1c2U6IHVua25vd24pOiBFcnJvcltdIHtcbiAgICByZXR1cm4gKEFycmF5LmlzQXJyYXkoY2F1c2UpID8gY2F1c2UgOiBjYXVzZSA9PSBudWxsID8gW10gOiBbY2F1c2VdKS5tYXAoXG4gICAgICB0b0Vycm9yXG4gICAgKVxuICB9XG5cbiAgLyoqXG4gICAqIENvZXJjZSBhIHNpbmdsZSB0aHJvd24gdmFsdWUgaW50byBhbiBFcnJvciAoRXJyb3JzIHBhc3MgdGhyb3VnaCB1bmNoYW5nZWQpLlxuICAgKlxuICAgKiBAcGFyYW0gdmFsdWUgLSBUaGUgY2F1Z2h0IHZhbHVlLlxuICAgKiBAcmV0dXJucyBgdmFsdWVgIHdoZW4gaXQgaXMgYW4gRXJyb3IsIGVsc2UgYSBuZXcgRXJyb3Igd3JhcHBpbmcgaXRzIHN0cmluZyBmb3JtLlxuICAgKi9cbiAgZXhwb3J0IGZ1bmN0aW9uIHRvRXJyb3IodmFsdWU6IHVua25vd24pOiBFcnJvciB7XG4gICAgcmV0dXJuIHZhbHVlIGluc3RhbmNlb2YgRXJyb3IgPyB2YWx1ZSA6IG5ldyBFcnJvcihTdHJpbmcodmFsdWUpKVxuICB9XG5cbiAgLyoqXG4gICAqIEZvbGQgYSBjb21wYWN0LCB0cnVuY2F0ZWQge0BsaW5rIE5lc3RlZEVycm9yQ29udGV4dH0gc3VtbWFyeSBpbnRvIHRoZSBtZXNzYWdlIHNvXG4gICAqIGl0IGlzIHZpc2libGUgd2hlcmV2ZXIgdGhlIG1lc3NhZ2UgaXMgKGxvZ3MsIHN0YWNrIHRyYWNlcyksIG5vdCBvbmx5IG9uIHRoZVxuICAgKiBgLmNvbnRleHRgIHByb3BlcnR5LlxuICAgKlxuICAgKiBAcGFyYW0gbWVzc2FnZSAtIFRoZSBiYXNlIG1lc3NhZ2UuXG4gICAqIEBwYXJhbSBjb250ZXh0IC0gVGhlIGNvbnRleHQgdG8gc3VtbWFyaXplLCBpZiBhbnkuXG4gICAqIEByZXR1cm5zIGBtZXNzYWdlYCB3aXRoIGEgYCAoa2V5PXZhbHVlLCDigKYpYCBzdWZmaXggd2hlbiBjb250ZXh0IGlzIG5vbi1lbXB0eS5cbiAgICovXG4gIGV4cG9ydCBmdW5jdGlvbiBjb21wb3NlTWVzc2FnZShcbiAgICBtZXNzYWdlOiBzdHJpbmcsXG4gICAgY29udGV4dD86IE5lc3RlZEVycm9yQ29udGV4dFxuICApOiBzdHJpbmcge1xuICAgIGNvbnN0IGVudHJpZXMgPSBjb250ZXh0ID09IG51bGwgPyBbXSA6IE9iamVjdC5lbnRyaWVzKGNvbnRleHQpXG4gICAgcmV0dXJuIGVudHJpZXMubGVuZ3RoID09PSAwXG4gICAgICA/IG1lc3NhZ2VcbiAgICAgIDogYCR7bWVzc2FnZX0gKCR7ZW50cmllc1xuICAgICAgICAgIC5tYXAoKFtrZXksIHZhbHVlXSkgPT4gYCR7a2V5fT0ke3ByZXZpZXdWYWx1ZSh2YWx1ZSl9YClcbiAgICAgICAgICAuam9pbihcIiwgXCIpfSlgXG4gIH1cblxuICAvKipcbiAgICogUmVuZGVyIG9uZSBjb250ZXh0IHZhbHVlIGZvciB0aGUgbWVzc2FnZSBzdWZmaXgg4oCUIHN0cmluZ3MgdmVyYmF0aW0sIGV2ZXJ5dGhpbmdcbiAgICogZWxzZSB2aWEgYSBiaWdpbnQtL2N5Y2xlLXNhZmUgZm9ybSwgdHJ1bmNhdGVkIHRvIHtAbGluayBDb250ZXh0UHJldmlld01heENoYXJzfS5cbiAgICpcbiAgICogQHBhcmFtIHZhbHVlIC0gVGhlIGNvbnRleHQgdmFsdWUuXG4gICAqIEByZXR1cm5zIFRoZSB0cnVuY2F0ZWQgcHJldmlldyBzdHJpbmcuXG4gICAqL1xuICBleHBvcnQgZnVuY3Rpb24gcHJldmlld1ZhbHVlKHZhbHVlOiB1bmtub3duKTogc3RyaW5nIHtcbiAgICBjb25zdCByZW5kZXJlZCA9IHR5cGVvZiB2YWx1ZSA9PT0gXCJzdHJpbmdcIiA/IHZhbHVlIDogc2FmZVN0cmluZ2lmeSh2YWx1ZSlcbiAgICByZXR1cm4gcmVuZGVyZWQubGVuZ3RoID4gQ29udGV4dFByZXZpZXdNYXhDaGFyc1xuICAgICAgPyBgJHtyZW5kZXJlZC5zbGljZSgwLCBDb250ZXh0UHJldmlld01heENoYXJzKX0ke1RydW5jYXRpb25TdWZmaXh9YFxuICAgICAgOiByZW5kZXJlZFxuICB9XG59XG5cbi8qKlxuICogQSBiZXN0LWVmZm9ydCByZW5kZXJpbmcgb2YgYHZhbHVlYCBmb3IgYSBtZXNzYWdlIHByZXZpZXc6IEpTT04gd2hlbiBzZXJpYWxpemFibGUsXG4gKiBlbHNlIGBTdHJpbmcodmFsdWUpYC4gUHVyZSBkaXNwbGF5IGZhbGxiYWNrIOKAlCBhIEJpZ0ludCBvciBhIGNpcmN1bGFyIG9iamVjdCBtYWtlc1xuICogYEpTT04uc3RyaW5naWZ5YCB0aHJvdyDigJQgTk9UIGVycm9yIGhhbmRsaW5nLCBzbyB0aGUgY2F0Y2ggaXMgYSBkZWxpYmVyYXRlIHJlbmRlclxuICogZmFsbGJhY2sgcmF0aGVyIHRoYW4gYSBzd2FsbG93LlxuICpcbiAqIEBwYXJhbSB2YWx1ZSAtIFRoZSB2YWx1ZSB0byByZW5kZXIuXG4gKiBAcmV0dXJucyBBIHNpbmdsZS1saW5lIHN0cmluZyBmb3JtIG9mIGB2YWx1ZWAuXG4gKi9cbmZ1bmN0aW9uIHNhZmVTdHJpbmdpZnkodmFsdWU6IHVua25vd24pOiBzdHJpbmcge1xuICB0cnkge1xuICAgIHJldHVybiBKU09OLnN0cmluZ2lmeSh2YWx1ZSkgPz8gU3RyaW5nKHZhbHVlKVxuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gU3RyaW5nKHZhbHVlKVxuICB9XG59XG4iXX0=
|
|
@@ -1,10 +1,114 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Structured, machine-readable diagnostic context captured at a {@link NestedError}
|
|
3
|
+
* throw site — the values that make a failure diagnosable (the `text` that failed to
|
|
4
|
+
* parse, a schema / type name, an id, …). Heterogeneous by nature, so the values are
|
|
5
|
+
* `unknown` (a documented type-erased bag, not a shortcut).
|
|
6
|
+
*/
|
|
7
|
+
export type NestedErrorContext = Record<string, unknown>;
|
|
8
|
+
/**
|
|
9
|
+
* Options for {@link NestedError} — what it preserves about the failure it wraps.
|
|
10
|
+
*/
|
|
11
|
+
export interface NestedErrorOptions<Context extends NestedErrorContext = NestedErrorContext> {
|
|
12
|
+
/**
|
|
13
|
+
* The originating error(s) — the root-cause chain that must NOT be swallowed. A
|
|
14
|
+
* non-Error thrown value is coerced to an Error; the first becomes the native
|
|
15
|
+
* ES2022 `Error.cause`.
|
|
16
|
+
*/
|
|
17
|
+
cause?: unknown;
|
|
18
|
+
/** Diagnostic context captured at the throw site. */
|
|
19
|
+
context?: Context;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* An Error that PRESERVES what it wraps instead of restringing it. Given a new
|
|
23
|
+
* message string, it ALSO retains the full cause chain: the originating error(s)
|
|
24
|
+
* survive as {@link NestedError.causes} (and the native `Error.cause`) — the real
|
|
25
|
+
* Error objects, so **each cause keeps its own stack trace and message** — and a
|
|
26
|
+
* nested-exception `Caused by:` section per cause is appended to this error's
|
|
27
|
+
* {@link NestedError.stack}, so the whole chain (each cause's stack + message) is
|
|
28
|
+
* visible wherever the error is printed, not only via the programmatic accessors.
|
|
29
|
+
* The diagnostic {@link NestedError.context} (the `text`, the schema / type name, …)
|
|
30
|
+
* is BOTH a structured property AND folded into the message.
|
|
31
|
+
*
|
|
32
|
+
* Never rewrite a caught error into a bare ``new Error(`… ${err.message}`)`` — that
|
|
33
|
+
* SWALLOWS the cause and the context. Wrap it:
|
|
34
|
+
* `new NestedError("…", { cause: err, context: { … } })`.
|
|
35
|
+
*/
|
|
36
|
+
export declare class NestedError<Context extends NestedErrorContext = NestedErrorContext> extends Error {
|
|
37
|
+
/** The originating error chain (flattened + coerced to Error); `causes[0]` is the native `.cause`. */
|
|
38
|
+
readonly causes: Error[];
|
|
39
|
+
/** The diagnostic context captured at the throw site. */
|
|
40
|
+
readonly context: Context;
|
|
41
|
+
/**
|
|
42
|
+
* @param message - The high-level failure description.
|
|
43
|
+
* @param options - The {@link NestedErrorOptions.cause} to preserve + the {@link NestedErrorOptions.context} to capture.
|
|
44
|
+
*/
|
|
45
|
+
constructor(message: string, options?: NestedErrorOptions<Context>);
|
|
4
46
|
}
|
|
5
47
|
export declare namespace NestedError {
|
|
6
|
-
|
|
7
|
-
|
|
48
|
+
/** Max characters of any single context value folded into the message — long `text` is truncated. */
|
|
49
|
+
const ContextPreviewMaxChars = 200;
|
|
50
|
+
/** The marker appended when a folded context value is truncated. */
|
|
51
|
+
const TruncationSuffix = "\u2026";
|
|
52
|
+
/** Prefix marking each retained cause in the composed stack (nested-exception style). */
|
|
53
|
+
const CausedByPrefix = "Caused by: ";
|
|
54
|
+
/**
|
|
55
|
+
* Append a `Caused by:` section per cause to `stack`, so every cause's stack trace
|
|
56
|
+
* AND message stay visible in `.stack` (and any logger that prints it) — not only
|
|
57
|
+
* via the programmatic {@link NestedError.causes} / native `Error.cause`. Each
|
|
58
|
+
* cause's own `.stack` already begins with its `name: message`, so both are kept.
|
|
59
|
+
*
|
|
60
|
+
* @param stack - The wrapping error's own stack (may be undefined in exotic runtimes).
|
|
61
|
+
* @param causes - The retained cause chain.
|
|
62
|
+
* @returns The wrapping stack with one appended `Caused by:` section per cause.
|
|
63
|
+
*/
|
|
64
|
+
function composeStack(stack: string | undefined, causes: Error[]): string;
|
|
65
|
+
/**
|
|
66
|
+
* Create a {@link NestedError}.
|
|
67
|
+
*
|
|
68
|
+
* @param message - The high-level failure description.
|
|
69
|
+
* @param options - The cause to preserve + the context to capture.
|
|
70
|
+
* @returns The constructed error.
|
|
71
|
+
*/
|
|
72
|
+
function create<Context extends NestedErrorContext = NestedErrorContext>(message: string, options?: NestedErrorOptions<Context>): NestedError<Context>;
|
|
73
|
+
/**
|
|
74
|
+
* Create + throw a {@link NestedError}.
|
|
75
|
+
*
|
|
76
|
+
* @param message - The high-level failure description.
|
|
77
|
+
* @param options - The cause to preserve + the context to capture.
|
|
78
|
+
*/
|
|
79
|
+
function throwError<Context extends NestedErrorContext = NestedErrorContext>(message: string, options?: NestedErrorOptions<Context>): never;
|
|
80
|
+
/**
|
|
81
|
+
* Coerce a thrown value (an Error, an array of them, or any value) into a flat
|
|
82
|
+
* `Error[]`, so a caught `unknown` can be preserved as a cause without loss.
|
|
83
|
+
*
|
|
84
|
+
* @param cause - The caught / rejected value.
|
|
85
|
+
* @returns The coerced error chain (empty when `cause` is nullish).
|
|
86
|
+
*/
|
|
87
|
+
function toErrors(cause: unknown): Error[];
|
|
88
|
+
/**
|
|
89
|
+
* Coerce a single thrown value into an Error (Errors pass through unchanged).
|
|
90
|
+
*
|
|
91
|
+
* @param value - The caught value.
|
|
92
|
+
* @returns `value` when it is an Error, else a new Error wrapping its string form.
|
|
93
|
+
*/
|
|
94
|
+
function toError(value: unknown): Error;
|
|
95
|
+
/**
|
|
96
|
+
* Fold a compact, truncated {@link NestedErrorContext} summary into the message so
|
|
97
|
+
* it is visible wherever the message is (logs, stack traces), not only on the
|
|
98
|
+
* `.context` property.
|
|
99
|
+
*
|
|
100
|
+
* @param message - The base message.
|
|
101
|
+
* @param context - The context to summarize, if any.
|
|
102
|
+
* @returns `message` with a ` (key=value, …)` suffix when context is non-empty.
|
|
103
|
+
*/
|
|
104
|
+
function composeMessage(message: string, context?: NestedErrorContext): string;
|
|
105
|
+
/**
|
|
106
|
+
* Render one context value for the message suffix — strings verbatim, everything
|
|
107
|
+
* else via a bigint-/cycle-safe form, truncated to {@link ContextPreviewMaxChars}.
|
|
108
|
+
*
|
|
109
|
+
* @param value - The context value.
|
|
110
|
+
* @returns The truncated preview string.
|
|
111
|
+
*/
|
|
112
|
+
function previewValue(value: unknown): string;
|
|
8
113
|
}
|
|
9
|
-
export default NestedError;
|
|
10
114
|
//# sourceMappingURL=NestedError.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NestedError.d.ts","sourceRoot":"","sources":["../../../src/errors/NestedError.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"NestedError.d.ts","sourceRoot":"","sources":["../../../src/errors/NestedError.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAExD;;GAEG;AACH,MAAM,WAAW,kBAAkB,CACjC,OAAO,SAAS,kBAAkB,GAAG,kBAAkB;IAEvD;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,qDAAqD;IACrD,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,WAAW,CACtB,OAAO,SAAS,kBAAkB,GAAG,kBAAkB,CACvD,SAAQ,KAAK;IACb,sGAAsG;IACtG,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,CAAA;IAExB,yDAAyD;IACzD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IAEzB;;;OAGG;gBACS,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAkB,CAAC,OAAO,CAAM;CAcvE;AAED,yBAAiB,WAAW,CAAC;IAC3B,qGAAqG;IAC9F,MAAM,sBAAsB,MAAM,CAAA;IAEzC,oEAAoE;IAC7D,MAAM,gBAAgB,WAAM,CAAA;IAEnC,yFAAyF;IAClF,MAAM,cAAc,gBAAgB,CAAA;IAE3C;;;;;;;;;OASG;IACH,SAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAM/E;IAED;;;;;;OAMG;IACH,SAAgB,MAAM,CAAC,OAAO,SAAS,kBAAkB,GAAG,kBAAkB,EAC5E,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,kBAAkB,CAAC,OAAO,CAAM,GACxC,WAAW,CAAC,OAAO,CAAC,CAEtB;IAED;;;;;OAKG;IACH,SAAgB,UAAU,CACxB,OAAO,SAAS,kBAAkB,GAAG,kBAAkB,EACvD,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAkB,CAAC,OAAO,CAAM,GAAG,KAAK,CAEnE;IAED;;;;;;OAMG;IACH,SAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,EAAE,CAIhD;IAED;;;;;OAKG;IACH,SAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAE7C;IAED;;;;;;;;OAQG;IACH,SAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,kBAAkB,GAC3B,MAAM,CAOR;IAED;;;;;;OAMG;IACH,SAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAKnD;CACF"}
|