@nice-code/error 0.8.0 → 0.9.0

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.
Files changed (35) hide show
  1. package/build/index.d.ts +913 -0
  2. package/build/index.js +1004 -933
  3. package/build/index.js.map +1 -0
  4. package/package.json +5 -4
  5. package/build/types/NiceError/NiceError.d.ts +0 -148
  6. package/build/types/NiceError/NiceError.enums.d.ts +0 -5
  7. package/build/types/NiceError/NiceError.types.d.ts +0 -204
  8. package/build/types/NiceError/NiceErrorHydrated.d.ts +0 -51
  9. package/build/types/NiceError/nice_error.static.d.ts +0 -2
  10. package/build/types/NiceErrorDefined/NiceErrorDefined.d.ts +0 -135
  11. package/build/types/NiceErrorDefined/defineNiceError.d.ts +0 -7
  12. package/build/types/NiceErrorDefined/err.d.ts +0 -59
  13. package/build/types/NiceErrorHandler/NiceErrorHandler.d.ts +0 -23
  14. package/build/types/NiceErrorHandler/NiceErrorHandler.types.d.ts +0 -82
  15. package/build/types/NiceErrorHandler/handleWith.d.ts +0 -8
  16. package/build/types/example/error_usage_example.d.ts +0 -41
  17. package/build/types/index.d.ts +0 -18
  18. package/build/types/internal/index.d.ts +0 -1
  19. package/build/types/internal/nice_core_errors.d.ts +0 -49
  20. package/build/types/test/helpers/nice_error_testing.static.d.ts +0 -3
  21. package/build/types/test/helpers/test_utils.d.ts +0 -1
  22. package/build/types/utils/castAndHydrate.d.ts +0 -35
  23. package/build/types/utils/castNiceError.d.ts +0 -15
  24. package/build/types/utils/inspectPotentialError/inspectPotentialError.d.ts +0 -2
  25. package/build/types/utils/inspectPotentialError/inspectPotentialError.enums.d.ts +0 -9
  26. package/build/types/utils/inspectPotentialError/inspectPotentialError.types.d.ts +0 -51
  27. package/build/types/utils/isNiceErrorObject.d.ts +0 -12
  28. package/build/types/utils/isRegularErrorObject.d.ts +0 -2
  29. package/build/types/utils/jsErrorOrCastJsError.d.ts +0 -1
  30. package/build/types/utils/logger.d.ts +0 -3
  31. package/build/types/utils/matchFirst.d.ts +0 -35
  32. package/build/types/utils/packError/causePack.d.ts +0 -2
  33. package/build/types/utils/packError/msgPack.d.ts +0 -2
  34. package/build/types/utils/packError/packError.d.ts +0 -3
  35. package/build/types/utils/packError/packError.enums.d.ts +0 -5
package/build/index.js CHANGED
@@ -1,963 +1,1034 @@
1
- // src/internal/nice_core_errors.ts
2
1
  import { StatusCodes } from "http-status-codes";
3
-
4
- // src/utils/jsErrorOrCastJsError.ts
2
+ import { Logger } from "tslog";
3
+ //#region src/utils/jsErrorOrCastJsError.ts
5
4
  function jsErrorOrCastJsError(error, logMessage = true) {
6
- if (error instanceof Error) {
7
- return Object.assign(error, {
8
- message: error.message
9
- });
10
- }
11
- const message = error?.message ?? (typeof error === "string" ? error : "No error message found");
12
- if (logMessage) {
13
- console.error(`An unknown and unstructured error was thrown: ${message}`, error);
14
- }
15
- return {
16
- ...new Error(message),
17
- ...error
18
- };
5
+ if (error instanceof Error) return Object.assign(error, { message: error.message });
6
+ const message = error?.message ?? (typeof error === "string" ? error : "No error message found");
7
+ if (logMessage) console.error(`An unknown and unstructured error was thrown: ${message}`, error);
8
+ return {
9
+ ...new Error(message),
10
+ ...error
11
+ };
19
12
  }
20
-
21
- // src/NiceError/nice_error.static.ts
22
- var DUR_OBJ_PACK_PREFIX = "NE_DUROBJ[[";
23
- var DUR_OBJ_PACK_SUFFIX = "]]NE_DUROBJ";
24
-
25
- // src/utils/packError/packError.enums.ts
26
- var EErrorPackType;
27
- ((EErrorPackType2) => {
28
- EErrorPackType2["no_pack"] = "no_pack";
29
- EErrorPackType2["msg_pack"] = "msg_pack";
30
- EErrorPackType2["cause_pack"] = "cause_pack";
31
- })(EErrorPackType ||= {});
32
-
33
- // src/utils/packError/causePack.ts
34
- var causePack = (error) => {
35
- error._packedState = { cause: error.cause, packedAs: "cause_pack" /* cause_pack */ };
36
- error.cause = `${DUR_OBJ_PACK_PREFIX}${JSON.stringify(error.toJsonObject())}${DUR_OBJ_PACK_SUFFIX}`;
37
- return error;
13
+ //#endregion
14
+ //#region src/NiceError/nice_error.static.ts
15
+ const DUR_OBJ_PACK_PREFIX = "NE_DUROBJ[[";
16
+ const DUR_OBJ_PACK_SUFFIX = "]]NE_DUROBJ";
17
+ //#endregion
18
+ //#region src/utils/packError/packError.enums.ts
19
+ let EErrorPackType = /* @__PURE__ */ function(EErrorPackType) {
20
+ EErrorPackType["no_pack"] = "no_pack";
21
+ EErrorPackType["msg_pack"] = "msg_pack";
22
+ EErrorPackType["cause_pack"] = "cause_pack";
23
+ return EErrorPackType;
24
+ }({});
25
+ //#endregion
26
+ //#region src/utils/packError/causePack.ts
27
+ const causePack = (error) => {
28
+ error._packedState = {
29
+ cause: error.cause,
30
+ packedAs: "cause_pack"
31
+ };
32
+ error.cause = `${DUR_OBJ_PACK_PREFIX}${JSON.stringify(error.toJsonObject())}${DUR_OBJ_PACK_SUFFIX}`;
33
+ return error;
38
34
  };
39
-
40
- // src/utils/packError/msgPack.ts
41
- var msgPack = (error) => {
42
- error._packedState = { message: error.cleanMessage, packedAs: "msg_pack" /* msg_pack */ };
43
- error.message = `${DUR_OBJ_PACK_PREFIX}${JSON.stringify(error.toJsonObject())}${DUR_OBJ_PACK_SUFFIX}`;
44
- return error;
35
+ //#endregion
36
+ //#region src/utils/packError/msgPack.ts
37
+ const msgPack = (error) => {
38
+ error._packedState = {
39
+ message: error.cleanMessage,
40
+ packedAs: "msg_pack"
41
+ };
42
+ error.message = `${DUR_OBJ_PACK_PREFIX}${JSON.stringify(error.toJsonObject())}${DUR_OBJ_PACK_SUFFIX}`;
43
+ return error;
45
44
  };
46
-
47
- // src/utils/packError/packError.ts
48
- var packError = (error, packType = "msg_pack") => {
49
- if (packType === "no_pack") {
50
- return error;
51
- }
52
- if (packType === "msg_pack") {
53
- return msgPack(error);
54
- }
55
- return causePack(error);
45
+ //#endregion
46
+ //#region src/utils/packError/packError.ts
47
+ const packError = (error, packType = "msg_pack") => {
48
+ if (packType === "no_pack") return error;
49
+ if (packType === "msg_pack") return msgPack(error);
50
+ return causePack(error);
56
51
  };
57
-
58
- // src/NiceError/NiceError.ts
59
- class NiceError extends Error {
60
- name = "NiceError";
61
- def;
62
- ids;
63
- wasntNice;
64
- httpStatusCode;
65
- timeCreated;
66
- cleanMessage;
67
- originError;
68
- _packedState;
69
- _errorDataMap;
70
- constructor(options) {
71
- const messagePure = options.message;
72
- const prefixedMessage = `[${options.def.domain}](${options.ids.join(",")}) ${messagePure}`;
73
- super(prefixedMessage);
74
- this.cleanMessage = messagePure;
75
- this.def = options.def;
76
- this.ids = options.ids;
77
- this._errorDataMap = options.errorData;
78
- this.wasntNice = options.wasntNice ?? false;
79
- this.httpStatusCode = options.httpStatusCode ?? 500;
80
- if (options.originError != null) {
81
- this.originError = options.originError;
82
- }
83
- this.timeCreated = options.timeCreated ?? Date.now();
84
- }
85
- hasId(id) {
86
- return id in this._errorDataMap;
87
- }
88
- hasOneOfIds(ids) {
89
- return ids.some((id) => (id in this._errorDataMap));
90
- }
91
- get hasMultiple() {
92
- return Object.keys(this._errorDataMap).length > 1;
93
- }
94
- getIds() {
95
- return Object.keys(this._errorDataMap);
96
- }
97
- getContext(id) {
98
- const errorData = this._errorDataMap[id];
99
- const state = errorData?.contextState;
100
- if (state == null) {
101
- return;
102
- }
103
- if (state.kind === "unhydrated") {
104
- throw new Error(`[NiceError.getContext] Context for id "${String(id)}" is in the "unhydrated" state. ` + `The error was reconstructed from a serialized payload but has not been deserialized yet. ` + `Call \`niceErrorDefined.hydrate(error)\` to reconstruct the typed context.`);
105
- }
106
- return state.value;
107
- }
108
- getErrorDataForId(id) {
109
- return this._errorDataMap[id];
110
- }
111
- withOriginError(error) {
112
- this.originError = jsErrorOrCastJsError(error);
113
- if (this._packedState?.packedAs !== "cause_pack" /* cause_pack */) {
114
- this.cause = this.originError;
115
- }
116
- return this;
117
- }
118
- matches(other) {
119
- const myDef = this.def;
120
- const otherDef = other.def;
121
- if (myDef.domain !== otherDef.domain)
122
- return false;
123
- const myIds = this.getIds().map(String).sort();
124
- const otherIds = other.getIds().map(String).sort();
125
- if (myIds.length !== otherIds.length)
126
- return false;
127
- return myIds.every((id, i) => id === otherIds[i]);
128
- }
129
- toJsonObject() {
130
- const originError = this.originError ? {
131
- name: this.originError.name,
132
- message: this.originError.cleanMessage ?? this.originError.message,
133
- stack: this.originError.stack,
134
- cause: this.originError.cause
135
- } : undefined;
136
- const def = {
137
- domain: this.def.domain,
138
- allDomains: this.def.allDomains
139
- };
140
- if (this.def.defaultHttpStatusCode != null) {
141
- def["defaultHttpStatusCode"] = this.def.defaultHttpStatusCode;
142
- }
143
- if (this.def.defaultMessage != null) {
144
- def["defaultMessage"] = this.def.defaultMessage;
145
- }
146
- const errorData = {};
147
- for (const rawId of Object.keys(this._errorDataMap)) {
148
- const id = rawId;
149
- const data = this._errorDataMap[id];
150
- if (data == null)
151
- continue;
152
- let contextState;
153
- if (data.contextState.kind === "hydrated" /* hydrated */) {
154
- contextState = {
155
- kind: "unhydrated" /* unhydrated */,
156
- serialized: data.contextState.serialized
157
- };
158
- } else {
159
- contextState = data.contextState;
160
- }
161
- errorData[id] = {
162
- contextState,
163
- message: data.cleanMessage ?? data.message,
164
- httpStatusCode: data.httpStatusCode,
165
- timeAdded: data.timeAdded
166
- };
167
- }
168
- return {
169
- name: "NiceError",
170
- def,
171
- ids: this.ids,
172
- errorData,
173
- wasntNice: this.wasntNice,
174
- message: this.cleanMessage,
175
- httpStatusCode: this.httpStatusCode,
176
- timeCreated: this.timeCreated,
177
- ...this.stack != null ? { stack: this.stack } : {},
178
- originError
179
- };
180
- }
181
- toJSON() {
182
- return this.toJsonObject();
183
- }
184
- toJsonString() {
185
- return JSON.stringify(this.toJsonObject());
186
- }
187
- toHttpResponse() {
188
- return new Response(this.toJsonString(), {
189
- status: this.httpStatusCode,
190
- headers: { "Content-Type": "application/json" }
191
- });
192
- }
193
- hydrate(definedNiceError) {
194
- return definedNiceError.hydrate(this);
195
- }
196
- handleWithSync(handlerInput, handlerOptions = {}) {
197
- const handlersArray = Array.isArray(handlerInput) ? handlerInput : [handlerInput];
198
- for (const handler of handlersArray) {
199
- const result = handler.handleErrorWithPromiseInspection(this, handlerOptions);
200
- if (result.matched) {
201
- if (result.isPromise) {
202
- console.warn(`[NiceError.handleWith] Handler ${result.target.identifier} returned a Promise but was called via \`handleWith\` (synchronous). ` + `The Promise will not be awaited. Use \`handleWithAsync\` for async handlers.`);
203
- }
204
- return result.isPromise ? undefined : result.handlerResponse;
205
- }
206
- }
207
- if (handlerOptions.throwOnUnhandled === true)
208
- throw this;
209
- return;
210
- }
211
- async handleWithAsync(handlerInput, handlerOptions = {}) {
212
- const handlersArray = Array.isArray(handlerInput) ? handlerInput : [handlerInput];
213
- for (const handler of handlersArray) {
214
- const result = handler.handleErrorWithPromiseInspection(this, handlerOptions);
215
- if (result.matched) {
216
- return result.isPromise ? await result.handlerPromise : result.handlerResponse;
217
- }
218
- }
219
- if (handlerOptions.throwOnUnhandled === true)
220
- throw this;
221
- return;
222
- }
223
- get isPacked() {
224
- return this._packedState != null;
225
- }
226
- pack(packType = "msg_pack") {
227
- if (this.isPacked)
228
- return this;
229
- return packError(this, packType);
230
- }
231
- unpack() {
232
- if (this._packedState == null)
233
- return this;
234
- if (this._packedState.packedAs === "msg_pack" /* msg_pack */) {
235
- this.message = this._packedState.message;
236
- }
237
- if (this._packedState.packedAs === "cause_pack" /* cause_pack */) {
238
- this.cause = this._packedState.cause;
239
- }
240
- this._packedState = undefined;
241
- delete this._packedState;
242
- return this;
243
- }
244
- }
245
-
246
- // src/NiceError/NiceErrorHydrated.ts
247
- class NiceErrorHydrated extends NiceError {
248
- def;
249
- niceErrorDefined;
250
- constructor(options) {
251
- super(options);
252
- this.def = options.def;
253
- this.niceErrorDefined = options.niceErrorDefined;
254
- }
255
- addContext(context) {
256
- const newIds = Object.keys(context);
257
- const newErrorData = {};
258
- for (const id of newIds) {
259
- newErrorData[id] = this.niceErrorDefined.reconcileErrorDataForId(id, context[id]);
260
- }
261
- const mergedErrorData = {
262
- ...this._errorDataMap,
263
- ...newErrorData
264
- };
265
- const mergedIds = Array.from(new Set([...this.getIds(), ...Object.keys(context)]));
266
- return new NiceErrorHydrated({
267
- def: this.def,
268
- niceErrorDefined: this.niceErrorDefined,
269
- ids: mergedIds,
270
- errorData: mergedErrorData,
271
- message: this.cleanMessage,
272
- wasntNice: this.wasntNice,
273
- httpStatusCode: this.httpStatusCode,
274
- originError: this.originError
275
- });
276
- }
277
- addId(...args) {
278
- const [id, context] = args;
279
- const reconciledData = this.niceErrorDefined.reconcileErrorDataForId(id, context);
280
- const errorDataMap = {};
281
- errorDataMap[id] = reconciledData;
282
- const mergedContexts = {
283
- ...this._errorDataMap,
284
- ...errorDataMap
285
- };
286
- const mergedIds = Array.from(new Set([...this.getIds(), id]));
287
- return new NiceErrorHydrated({
288
- def: this.def,
289
- niceErrorDefined: this.niceErrorDefined,
290
- ids: mergedIds,
291
- errorData: mergedContexts,
292
- message: this.cleanMessage,
293
- wasntNice: this.wasntNice,
294
- httpStatusCode: this.httpStatusCode,
295
- originError: this.originError
296
- });
297
- }
298
- }
299
-
300
- // src/NiceErrorDefined/NiceErrorDefined.ts
301
- class NiceErrorDomain {
302
- domain;
303
- allDomains;
304
- defaultHttpStatusCode;
305
- defaultMessage;
306
- _schema;
307
- _definedChildNiceErrors = [];
308
- _definedParentNiceError;
309
- _setPack;
310
- _packAsFn;
311
- constructor(definition) {
312
- this.domain = definition.domain;
313
- this.allDomains = definition.allDomains;
314
- this._schema = definition.schema;
315
- if (definition.packAs != null) {
316
- this._packAsFn = definition.packAs;
317
- }
318
- if (definition.defaultHttpStatusCode != null) {
319
- this.defaultHttpStatusCode = definition.defaultHttpStatusCode;
320
- }
321
- if (definition.defaultMessage != null) {
322
- this.defaultMessage = definition.defaultMessage;
323
- }
324
- }
325
- createChildDomain(subErrorDef) {
326
- const child = new NiceErrorDomain({
327
- domain: subErrorDef.domain,
328
- allDomains: [subErrorDef.domain, ...this.allDomains],
329
- schema: subErrorDef.schema,
330
- defaultHttpStatusCode: subErrorDef.defaultHttpStatusCode,
331
- defaultMessage: subErrorDef.defaultMessage
332
- });
333
- this.addChildNiceErrorDefined(child);
334
- child.addParentNiceErrorDefined(this);
335
- if (subErrorDef.packAs != null) {
336
- child._packAsFn = subErrorDef.packAs;
337
- } else if (this._setPack) {
338
- child.packAs(this._setPack);
339
- } else if (this._packAsFn) {
340
- child._packAsFn = this._packAsFn;
341
- }
342
- return child;
343
- }
344
- addParentNiceErrorDefined(parentError) {
345
- if (this._definedParentNiceError?.domain === parentError.domain) {
346
- return;
347
- }
348
- this._definedParentNiceError = {
349
- domain: parentError.domain,
350
- definedError: parentError
351
- };
352
- }
353
- addChildNiceErrorDefined(child) {
354
- if (this._definedChildNiceErrors.some((linked) => linked.domain === child.domain)) {
355
- return;
356
- }
357
- this._definedChildNiceErrors.push({
358
- domain: child.domain,
359
- definedError: child
360
- });
361
- if (this._definedParentNiceError) {
362
- this._definedParentNiceError.definedError.addChildNiceErrorDefined(child);
363
- }
364
- }
365
- packAs(pack) {
366
- this._setPack = pack;
367
- return this;
368
- }
369
- createError(input) {
370
- const err = new NiceErrorHydrated(input);
371
- const packType = this._setPack ?? this._packAsFn?.();
372
- if (packType != null && packType !== "no_pack") {
373
- return err.pack(packType);
374
- }
375
- return err;
376
- }
377
- hydrate(error) {
378
- const errDef = error.def;
379
- if (errDef.domain !== this.domain) {
380
- throw new Error(`[NiceErrorDefined.hydrate] Domain mismatch: this definition is "${this.domain}" ` + `but the error belongs to "${errDef.domain}". ` + `Call \`niceErrorDefined.is(error)\` before hydrating to ensure compatibility.`);
381
- }
382
- const finalError = error instanceof NiceError ? error : new NiceError(error);
383
- const reconciledErrorData = {};
384
- for (const id of finalError.getIds()) {
385
- const existingData = finalError.getErrorDataForId(id);
386
- if (existingData == null)
387
- continue;
388
- let contextState = existingData.contextState;
389
- if (contextState.kind === "unhydrated") {
390
- const entry = this._schema[id];
391
- const deserialize = entry?.context?.serialization?.fromJsonSerializable;
392
- if (deserialize != null) {
393
- contextState = {
394
- kind: "hydrated" /* hydrated */,
395
- value: deserialize(contextState.serialized),
396
- serialized: contextState.serialized
397
- };
398
- }
399
- }
400
- reconciledErrorData[id] = {
401
- contextState,
402
- message: existingData.cleanMessage ?? existingData.message,
403
- httpStatusCode: existingData.httpStatusCode,
404
- timeAdded: existingData.timeAdded
405
- };
406
- }
407
- return new NiceErrorHydrated({
408
- def: this._buildDef(),
409
- niceErrorDefined: this,
410
- ids: finalError.ids,
411
- errorData: reconciledErrorData,
412
- message: finalError.cleanMessage ?? finalError.message,
413
- httpStatusCode: finalError.httpStatusCode,
414
- wasntNice: finalError.wasntNice,
415
- originError: finalError.originError,
416
- timeCreated: finalError.timeCreated
417
- });
418
- }
419
- fromId(...args) {
420
- const [id, context] = args;
421
- const reconciledData = this.reconcileErrorDataForId(id, context);
422
- const errorData = {};
423
- errorData[id] = reconciledData;
424
- const err = this.createError({
425
- def: this._buildDef(),
426
- niceErrorDefined: this,
427
- ids: [id],
428
- errorData,
429
- message: reconciledData.cleanMessage ?? reconciledData.message,
430
- httpStatusCode: reconciledData.httpStatusCode
431
- });
432
- if (typeof Error.captureStackTrace === "function") {
433
- Error.captureStackTrace(err, this.fromId);
434
- }
435
- return err;
436
- }
437
- fromContext(context) {
438
- const ids = Object.keys(context);
439
- if (ids.length === 0) {
440
- throw new Error("[NiceErrorDefined.fromContext] context object must contain at least one error id.");
441
- }
442
- const errorData = {};
443
- for (const id of ids) {
444
- errorData[id] = this.reconcileErrorDataForId(id, context[id]);
445
- }
446
- const primaryId = ids[0];
447
- const err = this.createError({
448
- def: this._buildDef(),
449
- niceErrorDefined: this,
450
- ids,
451
- errorData,
452
- message: errorData[primaryId].cleanMessage ?? errorData[primaryId].message,
453
- httpStatusCode: errorData[primaryId].httpStatusCode
454
- });
455
- if (typeof Error.captureStackTrace === "function") {
456
- Error.captureStackTrace(err, this.fromContext);
457
- }
458
- return err;
459
- }
460
- isExact(error) {
461
- if (!(error instanceof NiceError))
462
- return false;
463
- const errDef = error.def;
464
- return errDef.domain === this.domain;
465
- }
466
- isThisOrChild(error) {
467
- if (!(error instanceof NiceError))
468
- return false;
469
- const errDef = error.def;
470
- return errDef.domain === this.domain || this.allDomains.includes(errDef.domain);
471
- }
472
- isParentOf(target) {
473
- const allDomains = target instanceof NiceError ? target.def.allDomains : target.allDomains;
474
- return Array.isArray(allDomains) && allDomains.includes(this.domain);
475
- }
476
- _buildDef() {
477
- return {
478
- domain: this.domain,
479
- allDomains: this.allDomains,
480
- schema: this._schema
481
- };
482
- }
483
- _resolveMessage(id, context) {
484
- const entry = this._schema[id];
485
- if (typeof entry?.message === "function") {
486
- return entry.message(context);
487
- }
488
- if (typeof entry?.message === "string") {
489
- return entry.message;
490
- }
491
- return this.defaultMessage ?? `[${this.domain}::${id}] An error occurred.`;
492
- }
493
- _resolveHttpStatusCode(id, context) {
494
- const entry = this._schema[id];
495
- let httpStatusCode;
496
- if (typeof entry?.httpStatusCode === "function") {
497
- httpStatusCode = entry.httpStatusCode(context);
498
- }
499
- if (typeof entry?.httpStatusCode === "number") {
500
- httpStatusCode = entry.httpStatusCode;
501
- }
502
- return typeof httpStatusCode === "number" ? httpStatusCode : this.defaultHttpStatusCode ?? 500;
503
- }
504
- reconcileErrorDataForId(id, context) {
505
- const message = this._resolveMessage(id, context);
506
- const httpStatusCode = this._resolveHttpStatusCode(id, context);
507
- const entry = this._schema[id];
508
- let contextState;
509
- if (context != null && entry?.context?.serialization != null) {
510
- const serialized = entry.context.serialization.toJsonSerializable(context);
511
- contextState = { kind: "hydrated" /* hydrated */, value: context, serialized };
512
- } else {
513
- contextState = { kind: "serde_unset" /* serde_unset */, value: context };
514
- }
515
- return { contextState, message, httpStatusCode, timeAdded: Date.now() };
516
- }
517
- }
518
-
519
- // src/NiceErrorDefined/defineNiceError.ts
520
- var defineNiceError = (definition) => {
521
- return new NiceErrorDomain({
522
- domain: definition.domain,
523
- allDomains: [definition.domain],
524
- schema: definition.schema,
525
- ...definition.packAs != null ? { packAs: definition.packAs } : {}
526
- });
52
+ //#endregion
53
+ //#region src/NiceError/NiceError.ts
54
+ var NiceError = class extends Error {
55
+ name = "NiceError";
56
+ def;
57
+ /** Primary id is first entry in ids. */
58
+ ids;
59
+ wasntNice;
60
+ httpStatusCode;
61
+ timeCreated;
62
+ cleanMessage;
63
+ originError;
64
+ _packedState;
65
+ /** Internal: all active id → reconciled data pairs. */
66
+ _errorDataMap;
67
+ constructor(options) {
68
+ const messagePure = options.message;
69
+ const prefixedMessage = `[${options.def.domain}](${options.ids.join(",")}) ${messagePure}`;
70
+ super(prefixedMessage);
71
+ this.cleanMessage = messagePure;
72
+ this.def = options.def;
73
+ this.ids = options.ids;
74
+ this._errorDataMap = options.errorData;
75
+ this.wasntNice = options.wasntNice ?? false;
76
+ this.httpStatusCode = options.httpStatusCode ?? 500;
77
+ if (options.originError != null) this.originError = options.originError;
78
+ this.timeCreated = options.timeCreated ?? Date.now();
79
+ }
80
+ /**
81
+ * Type guard: returns `true` if this error was created with (or contains) the
82
+ * given `id`. After the guard, `getContext(id)` will be strongly typed.
83
+ */
84
+ hasId(id) {
85
+ return id in this._errorDataMap;
86
+ }
87
+ /**
88
+ * Returns `true` if this error contains **at least one** of the supplied ids.
89
+ * Narrows `ACTIVE_IDS` to the matching subset of `IDS`.
90
+ */
91
+ hasOneOfIds(ids) {
92
+ return ids.some((id) => id in this._errorDataMap);
93
+ }
94
+ /** `true` when this error was created with more than one id (via `fromContext`). */
95
+ get hasMultiple() {
96
+ return Object.keys(this._errorDataMap).length > 1;
97
+ }
98
+ /** Returns all active error ids on this instance. */
99
+ getIds() {
100
+ return Object.keys(this._errorDataMap);
101
+ }
102
+ /**
103
+ * Returns the typed context value for the given error id.
104
+ *
105
+ * TypeScript will only allow you to call this with an id that is part of
106
+ * `ACTIVE_IDS` (i.e. an id confirmed via `hasId` / `hasOneOfIds`, or passed
107
+ * to `fromId` / `fromContext`).
108
+ *
109
+ * @throws If the context is in the `"unhydrated"` state — the error was
110
+ * reconstructed from a JSON payload and its context has a custom serializer
111
+ * that hasn't been run yet. Call `niceErrorDefined.hydrate(error)` first.
112
+ */
113
+ getContext(id) {
114
+ const state = this._errorDataMap[id]?.contextState;
115
+ if (state == null) return;
116
+ if (state.kind === "unhydrated") throw new Error(`[NiceError.getContext] Context for id "${String(id)}" is in the "unhydrated" state. The error was reconstructed from a serialized payload but has not been deserialized yet. Call \`niceErrorDefined.hydrate(error)\` to reconstruct the typed context.`);
117
+ return state.value;
118
+ }
119
+ getErrorDataForId(id) {
120
+ return this._errorDataMap[id];
121
+ }
122
+ withOriginError(error) {
123
+ this.originError = jsErrorOrCastJsError(error);
124
+ if (this._packedState?.packedAs !== "cause_pack") this.cause = this.originError;
125
+ return this;
126
+ }
127
+ /**
128
+ * Returns `true` if `other` has the same domain and the exact same set of
129
+ * active error ids as this error (order-independent).
130
+ *
131
+ * Useful for deduplication, retry logic, and asserting that two errors
132
+ * represent the same "kind" of problem without comparing context values.
133
+ *
134
+ * ```ts
135
+ * const a = err_auth.fromId("invalid_credentials", { username: "alice" });
136
+ * const b = err_auth.fromId("invalid_credentials", { username: "bob" });
137
+ * a.matches(b); // true — same domain + same id set
138
+ *
139
+ * const c = err_auth.fromId("account_locked");
140
+ * a.matches(c); // false — same domain, different id
141
+ * ```
142
+ */
143
+ matches(other) {
144
+ const myDef = this.def;
145
+ const otherDef = other.def;
146
+ if (myDef.domain !== otherDef.domain) return false;
147
+ const myIds = this.getIds().map(String).sort();
148
+ const otherIds = other.getIds().map(String).sort();
149
+ if (myIds.length !== otherIds.length) return false;
150
+ return myIds.every((id, i) => id === otherIds[i]);
151
+ }
152
+ toJsonObject() {
153
+ const originError = this.originError ? {
154
+ name: this.originError.name,
155
+ message: this.originError.cleanMessage ?? this.originError.message,
156
+ stack: this.originError.stack,
157
+ cause: this.originError.cause
158
+ } : void 0;
159
+ const def = {
160
+ domain: this.def.domain,
161
+ allDomains: this.def.allDomains
162
+ };
163
+ if (this.def.defaultHttpStatusCode != null) def["defaultHttpStatusCode"] = this.def.defaultHttpStatusCode;
164
+ if (this.def.defaultMessage != null) def["defaultMessage"] = this.def.defaultMessage;
165
+ const errorData = {};
166
+ for (const rawId of Object.keys(this._errorDataMap)) {
167
+ const id = rawId;
168
+ const data = this._errorDataMap[id];
169
+ if (data == null) continue;
170
+ let contextState;
171
+ if (data.contextState.kind === "hydrated") contextState = {
172
+ kind: "unhydrated",
173
+ serialized: data.contextState.serialized
174
+ };
175
+ else contextState = data.contextState;
176
+ errorData[id] = {
177
+ contextState,
178
+ message: data.cleanMessage ?? data.message,
179
+ httpStatusCode: data.httpStatusCode,
180
+ timeAdded: data.timeAdded
181
+ };
182
+ }
183
+ return {
184
+ name: "NiceError",
185
+ def,
186
+ ids: this.ids,
187
+ errorData,
188
+ wasntNice: this.wasntNice,
189
+ message: this.cleanMessage,
190
+ httpStatusCode: this.httpStatusCode,
191
+ timeCreated: this.timeCreated,
192
+ ...this.stack != null ? { stack: this.stack } : {},
193
+ originError
194
+ };
195
+ }
196
+ toJSON() {
197
+ return this.toJsonObject();
198
+ }
199
+ toJsonString() {
200
+ return JSON.stringify(this.toJsonObject());
201
+ }
202
+ toHttpResponse() {
203
+ return new Response(this.toJsonString(), {
204
+ status: this.httpStatusCode,
205
+ headers: { "Content-Type": "application/json" }
206
+ });
207
+ }
208
+ hydrate(definedNiceError) {
209
+ return definedNiceError.hydrate(this);
210
+ }
211
+ /**
212
+ * Iterates `cases` in order, finds the first whose domain matches this error
213
+ * (via `is()`), optionally further filters by active ids, hydrates the error,
214
+ * calls the handler, and returns `true`. Returns `false` if no case matched.
215
+ *
216
+ * Build cases with `forDomain` (any id in the domain) or `forIds` (specific
217
+ * id subset). Handlers are invoked synchronously — any returned Promise is
218
+ * not awaited. Use `handleWithAsync` when handlers are async.
219
+ *
220
+ * @example
221
+ * ```ts
222
+ * const handled = error.handleWith([
223
+ * forIds(err_feature, ["not_found"], (h) => {
224
+ * res.status(404).json({ missing: h.getContext("not_found").resource });
225
+ * }),
226
+ * forDomain(err_feature, (h) => {
227
+ * matchFirst(h, {
228
+ * forbidden: ({ userId }) => res.status(403).json({ userId }),
229
+ * _: () => res.status(500).end(),
230
+ * });
231
+ * }),
232
+ * forDomain(err_service, (h) => {
233
+ * res.status(h.httpStatusCode).json({ error: h.message });
234
+ * }),
235
+ * ]);
236
+ * if (!handled) next(error);
237
+ * ```
238
+ */
239
+ handleWithSync(handlerInput, handlerOptions = {}) {
240
+ const handlersArray = Array.isArray(handlerInput) ? handlerInput : [handlerInput];
241
+ for (const handler of handlersArray) {
242
+ const result = handler.handleErrorWithPromiseInspection(this, handlerOptions);
243
+ if (result.matched) {
244
+ if (result.isPromise) console.warn(`[NiceError.handleWith] Handler ${result.target.identifier} returned a Promise but was called via \`handleWith\` (synchronous). The Promise will not be awaited. Use \`handleWithAsync\` for async handlers.`);
245
+ return result.isPromise ? void 0 : result.handlerResponse;
246
+ }
247
+ }
248
+ if (handlerOptions.throwOnUnhandled === true) throw this;
249
+ }
250
+ /**
251
+ * Same matching logic as `handleWith`, but `await`s the handler's returned
252
+ * Promise before resolving. Use this when your handlers perform async work
253
+ * (database writes, HTTP calls, etc.).
254
+ *
255
+ * @example
256
+ * ```ts
257
+ * const handled = await error.handleWithAsync([
258
+ * forDomain(err_payments, async (h) => {
259
+ * await db.logFailedPayment(h);
260
+ * await notifyOps(h.message);
261
+ * }),
262
+ * ]);
263
+ * ```
264
+ */
265
+ async handleWithAsync(handlerInput, handlerOptions = {}) {
266
+ const handlersArray = Array.isArray(handlerInput) ? handlerInput : [handlerInput];
267
+ for (const handler of handlersArray) {
268
+ const result = handler.handleErrorWithPromiseInspection(this, handlerOptions);
269
+ if (result.matched) return result.isPromise ? await result.handlerPromise : result.handlerResponse;
270
+ }
271
+ if (handlerOptions.throwOnUnhandled === true) throw this;
272
+ }
273
+ get isPacked() {
274
+ return this._packedState != null;
275
+ }
276
+ pack(packType = "msg_pack") {
277
+ if (this.isPacked) return this;
278
+ return packError(this, packType);
279
+ }
280
+ unpack() {
281
+ if (this._packedState == null) return this;
282
+ if (this._packedState.packedAs === "msg_pack") this.message = this._packedState.message;
283
+ if (this._packedState.packedAs === "cause_pack") this.cause = this._packedState.cause;
284
+ this._packedState = void 0;
285
+ delete this._packedState;
286
+ return this;
287
+ }
527
288
  };
528
-
529
- // src/NiceErrorDefined/err.ts
289
+ //#endregion
290
+ //#region src/NiceError/NiceErrorHydrated.ts
291
+ var NiceErrorHydrated = class NiceErrorHydrated extends NiceError {
292
+ def;
293
+ niceErrorDefined;
294
+ constructor(options) {
295
+ super(options);
296
+ this.def = options.def;
297
+ this.niceErrorDefined = options.niceErrorDefined;
298
+ }
299
+ /**
300
+ * Returns a **new** `NiceErrorHydrated` with additional id+context entries merged in.
301
+ * The returned error's `ACTIVE_IDS` is the union of the original ids and the
302
+ * newly supplied keys.
303
+ *
304
+ * ```ts
305
+ * const err = errDef.fromId("id_a", { a: 1 })
306
+ * .addContext({ id_b: { b: "x" } });
307
+ * err.getIds(); // ["id_a", "id_b"]
308
+ * ```
309
+ */
310
+ addContext(context) {
311
+ const newIds = Object.keys(context);
312
+ const newErrorData = {};
313
+ for (const id of newIds) newErrorData[id] = this.niceErrorDefined.reconcileErrorDataForId(id, context[id]);
314
+ const mergedErrorData = {
315
+ ...this._errorDataMap,
316
+ ...newErrorData
317
+ };
318
+ const mergedIds = Array.from(new Set([...this.getIds(), ...Object.keys(context)]));
319
+ return new NiceErrorHydrated({
320
+ def: this.def,
321
+ niceErrorDefined: this.niceErrorDefined,
322
+ ids: mergedIds,
323
+ errorData: mergedErrorData,
324
+ message: this.cleanMessage,
325
+ wasntNice: this.wasntNice,
326
+ httpStatusCode: this.httpStatusCode,
327
+ originError: this.originError
328
+ });
329
+ }
330
+ /**
331
+ * Returns a **new** `NiceErrorHydrated` with an additional error id (and its context,
332
+ * if the schema requires one). Equivalent to `addContext({ [id]: context })`
333
+ * but mirrors the `fromId` ergonomics for single-id additions.
334
+ */
335
+ addId(...args) {
336
+ const [id, context] = args;
337
+ const reconciledData = this.niceErrorDefined.reconcileErrorDataForId(id, context);
338
+ const errorDataMap = {};
339
+ errorDataMap[id] = reconciledData;
340
+ const mergedContexts = {
341
+ ...this._errorDataMap,
342
+ ...errorDataMap
343
+ };
344
+ const mergedIds = Array.from(new Set([...this.getIds(), id]));
345
+ return new NiceErrorHydrated({
346
+ def: this.def,
347
+ niceErrorDefined: this.niceErrorDefined,
348
+ ids: mergedIds,
349
+ errorData: mergedContexts,
350
+ message: this.cleanMessage,
351
+ wasntNice: this.wasntNice,
352
+ httpStatusCode: this.httpStatusCode,
353
+ originError: this.originError
354
+ });
355
+ }
356
+ };
357
+ //#endregion
358
+ //#region src/NiceErrorDefined/NiceErrorDefined.ts
359
+ var NiceErrorDomain = class NiceErrorDomain {
360
+ domain;
361
+ allDomains;
362
+ defaultHttpStatusCode;
363
+ defaultMessage;
364
+ /** Kept for runtime use (message resolution, httpStatusCode, context serialization, etc.). */
365
+ _schema;
366
+ _definedChildNiceErrors = [];
367
+ _definedParentNiceError;
368
+ /** Set by `.packAs()` — explicit per-instance override, takes priority over `_packAsFn`. */
369
+ _setPack;
370
+ /** Set at definition time — called dynamically each time an error is created. */
371
+ _packAsFn;
372
+ constructor(definition) {
373
+ this.domain = definition.domain;
374
+ this.allDomains = definition.allDomains;
375
+ this._schema = definition.schema;
376
+ if (definition.packAs != null) this._packAsFn = definition.packAs;
377
+ if (definition.defaultHttpStatusCode != null) this.defaultHttpStatusCode = definition.defaultHttpStatusCode;
378
+ if (definition.defaultMessage != null) this.defaultMessage = definition.defaultMessage;
379
+ }
380
+ /**
381
+ * Creates a child domain that inherits this domain in `allDomains`.
382
+ * The child has its own schema and its own domain string.
383
+ */
384
+ createChildDomain(subErrorDef) {
385
+ const child = new NiceErrorDomain({
386
+ domain: subErrorDef.domain,
387
+ allDomains: [subErrorDef.domain, ...this.allDomains],
388
+ schema: subErrorDef.schema,
389
+ defaultHttpStatusCode: subErrorDef.defaultHttpStatusCode,
390
+ defaultMessage: subErrorDef.defaultMessage
391
+ });
392
+ this.addChildNiceErrorDefined(child);
393
+ child.addParentNiceErrorDefined(this);
394
+ if (subErrorDef.packAs != null) child._packAsFn = subErrorDef.packAs;
395
+ else if (this._setPack) child.packAs(this._setPack);
396
+ else if (this._packAsFn) child._packAsFn = this._packAsFn;
397
+ return child;
398
+ }
399
+ addParentNiceErrorDefined(parentError) {
400
+ if (this._definedParentNiceError?.domain === parentError.domain) return;
401
+ this._definedParentNiceError = {
402
+ domain: parentError.domain,
403
+ definedError: parentError
404
+ };
405
+ }
406
+ addChildNiceErrorDefined(child) {
407
+ if (this._definedChildNiceErrors.some((linked) => linked.domain === child.domain)) return;
408
+ this._definedChildNiceErrors.push({
409
+ domain: child.domain,
410
+ definedError: child
411
+ });
412
+ if (this._definedParentNiceError) this._definedParentNiceError.definedError.addChildNiceErrorDefined(child);
413
+ }
414
+ packAs(pack) {
415
+ this._setPack = pack;
416
+ return this;
417
+ }
418
+ createError(input) {
419
+ const err = new NiceErrorHydrated(input);
420
+ const packType = this._setPack ?? this._packAsFn?.();
421
+ if (packType != null && packType !== "no_pack") return err.pack(packType);
422
+ return err;
423
+ }
424
+ /**
425
+ * Promotes a plain `NiceError<ERR_DEF>` back into a `NiceErrorHydrated` so
426
+ * that builder methods (`addId`, `addContext`, etc.) are available again.
427
+ *
428
+ * For each active id, if the context is in the `"unhydrated"` state (i.e. the
429
+ * error was reconstructed from a JSON payload), `hydrate` calls
430
+ * `fromJsonSerializable` to reconstruct the typed value and advances the state
431
+ * to `"hydrated"`. Ids already in `"hydrated"` or `"raw_unset"` state
432
+ * are passed through unchanged.
433
+ *
434
+ * @throws If `error.def.domain` does not match this definition's domain. Use
435
+ * `niceErrorDefined.is(error)` before calling `hydrate` to ensure compatibility.
436
+ *
437
+ * ```ts
438
+ * const raw = castNiceError(apiResponseBody);
439
+ *
440
+ * if (err_user_auth.is(raw)) {
441
+ * const hydrated = err_user_auth.hydrate(raw);
442
+ * // hydrated.getContext("invalid_credentials") — fully typed, no throw
443
+ * // hydrated.addId / addContext — available again
444
+ * }
445
+ * ```
446
+ */
447
+ hydrate(error) {
448
+ const errDef = error.def;
449
+ if (errDef.domain !== this.domain) throw new Error(`[NiceErrorDefined.hydrate] Domain mismatch: this definition is "${this.domain}" but the error belongs to "${errDef.domain}". Call \`niceErrorDefined.is(error)\` before hydrating to ensure compatibility.`);
450
+ const finalError = error instanceof NiceError ? error : new NiceError(error);
451
+ const reconciledErrorData = {};
452
+ for (const id of finalError.getIds()) {
453
+ const existingData = finalError.getErrorDataForId(id);
454
+ if (existingData == null) continue;
455
+ let contextState = existingData.contextState;
456
+ if (contextState.kind === "unhydrated") {
457
+ const deserialize = this._schema[id]?.context?.serialization?.fromJsonSerializable;
458
+ if (deserialize != null) contextState = {
459
+ kind: "hydrated",
460
+ value: deserialize(contextState.serialized),
461
+ serialized: contextState.serialized
462
+ };
463
+ }
464
+ reconciledErrorData[id] = {
465
+ contextState,
466
+ message: existingData.cleanMessage ?? existingData.message,
467
+ httpStatusCode: existingData.httpStatusCode,
468
+ timeAdded: existingData.timeAdded
469
+ };
470
+ }
471
+ return new NiceErrorHydrated({
472
+ def: this._buildDef(),
473
+ niceErrorDefined: this,
474
+ ids: finalError.ids,
475
+ errorData: reconciledErrorData,
476
+ message: finalError.cleanMessage ?? finalError.message,
477
+ httpStatusCode: finalError.httpStatusCode,
478
+ wasntNice: finalError.wasntNice,
479
+ originError: finalError.originError,
480
+ timeCreated: finalError.timeCreated
481
+ });
482
+ }
483
+ /**
484
+ * Creates a `NiceErrorHydrated` for a single error id.
485
+ *
486
+ * - `id` autocompletes to the schema keys.
487
+ * - The second argument `context` is required / optional / absent based on
488
+ * whether the schema entry declares `context.required: true`.
489
+ * - The returned error has `ACTIVE_IDS` narrowed to exactly `K`, so
490
+ * `getContext(id)` is immediately strongly typed.
491
+ */
492
+ fromId(...args) {
493
+ const [id, context] = args;
494
+ const reconciledData = this.reconcileErrorDataForId(id, context);
495
+ const errorData = {};
496
+ errorData[id] = reconciledData;
497
+ const err = this.createError({
498
+ def: this._buildDef(),
499
+ niceErrorDefined: this,
500
+ ids: [id],
501
+ errorData,
502
+ message: reconciledData.cleanMessage ?? reconciledData.message,
503
+ httpStatusCode: reconciledData.httpStatusCode
504
+ });
505
+ if (typeof Error.captureStackTrace === "function") Error.captureStackTrace(err, this.fromId);
506
+ return err;
507
+ }
508
+ fromContext(context) {
509
+ const ids = Object.keys(context);
510
+ if (ids.length === 0) throw new Error("[NiceErrorDefined.fromContext] context object must contain at least one error id.");
511
+ const errorData = {};
512
+ for (const id of ids) errorData[id] = this.reconcileErrorDataForId(id, context[id]);
513
+ const primaryId = ids[0];
514
+ const err = this.createError({
515
+ def: this._buildDef(),
516
+ niceErrorDefined: this,
517
+ ids,
518
+ errorData,
519
+ message: errorData[primaryId].cleanMessage ?? errorData[primaryId].message,
520
+ httpStatusCode: errorData[primaryId].httpStatusCode
521
+ });
522
+ if (typeof Error.captureStackTrace === "function") Error.captureStackTrace(err, this.fromContext);
523
+ return err;
524
+ }
525
+ /**
526
+ * Returns `true` if `error` is a `NiceError` whose `def.domain` exactly matches
527
+ * this definition's domain.
528
+ *
529
+ * Use this after `castNiceError` to narrow an unknown error to this specific
530
+ * domain before accessing its typed ids/context:
531
+ *
532
+ * ```ts
533
+ * const caught = castNiceError(e);
534
+ *
535
+ * if (err_user_auth.is(caught)) {
536
+ * // caught is now NiceError<typeof err_user_auth's ERR_DEF>
537
+ * const hydrated = err_user_auth.hydrate(caught);
538
+ * const { username } = hydrated.getContext("invalid_credentials");
539
+ * }
540
+ * ```
541
+ */
542
+ isExact(error) {
543
+ if (!(error instanceof NiceError)) return false;
544
+ return error.def.domain === this.domain;
545
+ }
546
+ isThisOrChild(error) {
547
+ if (!(error instanceof NiceError)) return false;
548
+ const errDef = error.def;
549
+ return errDef.domain === this.domain || this.allDomains.includes(errDef.domain);
550
+ }
551
+ /**
552
+ * Returns `true` if this domain appears anywhere in the target's ancestry
553
+ * chain (including an exact domain match).
554
+ *
555
+ * Accepts either a `NiceErrorDefined` (domain definition) or a `NiceError`
556
+ * instance (extracts the domain from its `def`).
557
+ */
558
+ isParentOf(target) {
559
+ const allDomains = target instanceof NiceError ? target.def.allDomains : target.allDomains;
560
+ return Array.isArray(allDomains) && allDomains.includes(this.domain);
561
+ }
562
+ _buildDef() {
563
+ return {
564
+ domain: this.domain,
565
+ allDomains: this.allDomains,
566
+ schema: this._schema
567
+ };
568
+ }
569
+ _resolveMessage(id, context) {
570
+ const entry = this._schema[id];
571
+ if (typeof entry?.message === "function") return entry.message(context);
572
+ if (typeof entry?.message === "string") return entry.message;
573
+ return this.defaultMessage ?? `[${this.domain}::${id}] An error occurred.`;
574
+ }
575
+ _resolveHttpStatusCode(id, context) {
576
+ const entry = this._schema[id];
577
+ let httpStatusCode;
578
+ if (typeof entry?.httpStatusCode === "function") httpStatusCode = entry.httpStatusCode(context);
579
+ if (typeof entry?.httpStatusCode === "number") httpStatusCode = entry.httpStatusCode;
580
+ return typeof httpStatusCode === "number" ? httpStatusCode : this.defaultHttpStatusCode ?? 500;
581
+ }
582
+ reconcileErrorDataForId(id, context) {
583
+ const message = this._resolveMessage(id, context);
584
+ const httpStatusCode = this._resolveHttpStatusCode(id, context);
585
+ const entry = this._schema[id];
586
+ let contextState;
587
+ if (context != null && entry?.context?.serialization != null) contextState = {
588
+ kind: "hydrated",
589
+ value: context,
590
+ serialized: entry.context.serialization.toJsonSerializable(context)
591
+ };
592
+ else contextState = {
593
+ kind: "serde_unset",
594
+ value: context
595
+ };
596
+ return {
597
+ contextState,
598
+ message,
599
+ httpStatusCode,
600
+ timeAdded: Date.now()
601
+ };
602
+ }
603
+ };
604
+ //#endregion
605
+ //#region src/NiceErrorDefined/defineNiceError.ts
606
+ const defineNiceError = (definition) => {
607
+ return new NiceErrorDomain({
608
+ domain: definition.domain,
609
+ allDomains: [definition.domain],
610
+ schema: definition.schema,
611
+ ...definition.packAs != null ? { packAs: definition.packAs } : {}
612
+ });
613
+ };
614
+ //#endregion
615
+ //#region src/NiceErrorDefined/err.ts
530
616
  function err(meta) {
531
- return meta ?? {};
617
+ return meta ?? {};
532
618
  }
533
-
534
- // src/internal/nice_core_errors.ts
535
- var err_nice = defineNiceError({
536
- domain: "err_nice",
537
- schema: {}
619
+ //#endregion
620
+ //#region src/internal/nice_core_errors.ts
621
+ const err_nice = defineNiceError({
622
+ domain: "err_nice",
623
+ schema: {}
538
624
  });
539
- var EErrId_CastNotNice;
540
- ((EErrId_CastNotNice2) => {
541
- EErrId_CastNotNice2["js_error"] = "native_error";
542
- EErrId_CastNotNice2["js_error_like_object"] = "js_error_like_object";
543
- EErrId_CastNotNice2["nullish_value"] = "nullish_value";
544
- EErrId_CastNotNice2["js_data_type"] = "js_data_type";
545
- EErrId_CastNotNice2["js_other"] = "js_other";
546
- })(EErrId_CastNotNice ||= {});
547
- var err_cast_not_nice = err_nice.createChildDomain({
548
- domain: "err_cast_not_nice",
549
- defaultHttpStatusCode: StatusCodes.UNPROCESSABLE_ENTITY,
550
- schema: {
551
- ["native_error" /* js_error */]: err({
552
- context: {
553
- required: true
554
- },
555
- message: ({ jsError }) => `A native JavaScript Error was encountered during casting: ${jsError.message}`,
556
- httpStatusCode: StatusCodes.INTERNAL_SERVER_ERROR
557
- }),
558
- ["js_error_like_object" /* js_error_like_object */]: err({
559
- context: {
560
- required: true
561
- },
562
- message: ({ jsErrorObject }) => `An object resembling a JavaScript Error was encountered during casting: [${jsErrorObject.name}] ${jsErrorObject.message}`,
563
- httpStatusCode: StatusCodes.INTERNAL_SERVER_ERROR
564
- }),
565
- ["nullish_value" /* nullish_value */]: err({
566
- context: {
567
- required: true
568
- },
569
- message: ({ value }) => `A nullish value [${value === null ? "null" : "undefined"}] was encountered during casting`
570
- }),
571
- ["js_data_type" /* js_data_type */]: err({
572
- context: {
573
- required: true
574
- },
575
- message: ({ jsDataType, jsDataValue }) => {
576
- let inspectedValue;
577
- try {
578
- inspectedValue = JSON.stringify(jsDataValue);
579
- } catch {}
580
- return `A value of type [${jsDataType}] with value [${inspectedValue ?? "UNSERIALIZABLE"}] was encountered during casting, which is not a valid error type`;
581
- }
582
- }),
583
- ["js_other" /* js_other */]: err({
584
- context: {
585
- required: true
586
- },
587
- message: ({ jsDataValue }) => {
588
- let inspectedValue;
589
- try {
590
- inspectedValue = JSON.stringify(jsDataValue);
591
- } catch {}
592
- return `An unhandled type [${typeof jsDataValue}] with value [${inspectedValue ?? "UNSERIALIZABLE"}] was encountered during casting, which is not a valid error type`;
593
- }
594
- })
595
- }
625
+ let EErrId_CastNotNice = /* @__PURE__ */ function(EErrId_CastNotNice) {
626
+ EErrId_CastNotNice["js_error"] = "native_error";
627
+ EErrId_CastNotNice["js_error_like_object"] = "js_error_like_object";
628
+ EErrId_CastNotNice["nullish_value"] = "nullish_value";
629
+ EErrId_CastNotNice["js_data_type"] = "js_data_type";
630
+ EErrId_CastNotNice["js_other"] = "js_other";
631
+ return EErrId_CastNotNice;
632
+ }({});
633
+ const err_cast_not_nice = err_nice.createChildDomain({
634
+ domain: "err_cast_not_nice",
635
+ defaultHttpStatusCode: StatusCodes.UNPROCESSABLE_ENTITY,
636
+ schema: {
637
+ ["native_error"]: err({
638
+ context: { required: true },
639
+ message: ({ jsError }) => `A native JavaScript Error was encountered during casting: ${jsError.message}`,
640
+ httpStatusCode: StatusCodes.INTERNAL_SERVER_ERROR
641
+ }),
642
+ ["js_error_like_object"]: err({
643
+ context: { required: true },
644
+ message: ({ jsErrorObject }) => `An object resembling a JavaScript Error was encountered during casting: [${jsErrorObject.name}] ${jsErrorObject.message}`,
645
+ httpStatusCode: StatusCodes.INTERNAL_SERVER_ERROR
646
+ }),
647
+ ["nullish_value"]: err({
648
+ context: { required: true },
649
+ message: ({ value }) => `A nullish value [${value === null ? "null" : "undefined"}] was encountered during casting`
650
+ }),
651
+ ["js_data_type"]: err({
652
+ context: { required: true },
653
+ message: ({ jsDataType, jsDataValue }) => {
654
+ let inspectedValue;
655
+ try {
656
+ inspectedValue = JSON.stringify(jsDataValue);
657
+ } catch {}
658
+ return `A value of type [${jsDataType}] with value [${inspectedValue ?? "UNSERIALIZABLE"}] was encountered during casting, which is not a valid error type`;
659
+ }
660
+ }),
661
+ ["js_other"]: err({
662
+ context: { required: true },
663
+ message: ({ jsDataValue }) => {
664
+ let inspectedValue;
665
+ try {
666
+ inspectedValue = JSON.stringify(jsDataValue);
667
+ } catch {}
668
+ return `An unhandled type [${typeof jsDataValue}] with value [${inspectedValue ?? "UNSERIALIZABLE"}] was encountered during casting, which is not a valid error type`;
669
+ }
670
+ })
671
+ }
596
672
  });
597
- var err_nice_handler = err_nice.createChildDomain({
598
- domain: "err_nice_handler",
599
- schema: {}
673
+ const err_nice_handler = err_nice.createChildDomain({
674
+ domain: "err_nice_handler",
675
+ schema: {}
600
676
  });
601
- // src/NiceErrorHandler/NiceErrorHandler.types.ts
602
- var EErrorHandlerTargetType;
603
- ((EErrorHandlerTargetType2) => {
604
- EErrorHandlerTargetType2["ids"] = "ids";
605
- EErrorHandlerTargetType2["domain"] = "domain";
606
- EErrorHandlerTargetType2["default"] = "default";
607
- })(EErrorHandlerTargetType ||= {});
608
-
609
- // src/NiceErrorHandler/NiceErrorHandler.ts
610
- class NiceErrorHandler {
611
- handlerConfigs = [];
612
- _defaultRequester;
613
- handleErrorWithPromiseInspection(error, options) {
614
- for (const handlerConfig of this.handlerConfigs) {
615
- if (!handlerConfig._matcher(error))
616
- continue;
617
- const errorResult = handlerConfig._requester(error);
618
- if (errorResult instanceof Promise) {
619
- return {
620
- isPromise: true,
621
- matched: true,
622
- target: handlerConfig.target,
623
- handlerPromise: errorResult
624
- };
625
- }
626
- return {
627
- isPromise: false,
628
- matched: true,
629
- target: handlerConfig.target,
630
- handlerResponse: errorResult
631
- };
632
- }
633
- if (this._defaultRequester) {
634
- const defaultResult = this._defaultRequester(error);
635
- if (defaultResult instanceof Promise) {
636
- return {
637
- isPromise: true,
638
- matched: true,
639
- target: {
640
- type: "default" /* default */,
641
- identifier: "[matched:default]"
642
- },
643
- handlerPromise: defaultResult
644
- };
645
- }
646
- return {
647
- isPromise: false,
648
- matched: true,
649
- target: { type: "default" /* default */, identifier: "[matched:default]" },
650
- handlerResponse: defaultResult
651
- };
652
- }
653
- if (options?.throwOnUnhandled === true) {
654
- throw error;
655
- }
656
- return {
657
- matched: false,
658
- attemptedTargets: this.handlerConfigs.map((config) => config.target)
659
- };
660
- }
661
- forDomain(domain, handler) {
662
- this.handlerConfigs.push({
663
- target: {
664
- type: "domain" /* domain */,
665
- domain: domain.domain,
666
- identifier: `[matched:domain:${domain.domain}]`
667
- },
668
- _matcher: (error) => domain.isExact(error),
669
- _requester: (error) => handler(domain.hydrate(error))
670
- });
671
- return this;
672
- }
673
- forId(domain, id, handler) {
674
- this.handlerConfigs.push({
675
- target: {
676
- type: "ids" /* ids */,
677
- domain: domain.domain,
678
- ids: [id],
679
- identifier: `[matched:ids:${domain.domain}:${id}]`
680
- },
681
- _matcher: (error) => domain.isExact(error) && error.hasId(id),
682
- _requester: (error) => handler(domain.hydrate(error))
683
- });
684
- return this;
685
- }
686
- forIds(domain, ids, handler) {
687
- this.handlerConfigs.push({
688
- target: {
689
- type: "ids" /* ids */,
690
- domain: domain.domain,
691
- ids,
692
- identifier: `[matched:ids:${domain.domain}:${ids.join(",")}]`
693
- },
694
- _matcher: (error) => domain.isExact(error) && ids.some((id) => error.hasId(id)),
695
- _requester: (error) => handler(domain.hydrate(error))
696
- });
697
- return this;
698
- }
699
- setDefaultHandler(handler) {
700
- this._defaultRequester = handler;
701
- return this;
702
- }
703
- }
704
-
705
- // src/NiceErrorHandler/handleWith.ts
677
+ //#endregion
678
+ //#region src/NiceErrorHandler/NiceErrorHandler.types.ts
679
+ let EErrorHandlerTargetType = /* @__PURE__ */ function(EErrorHandlerTargetType) {
680
+ EErrorHandlerTargetType["ids"] = "ids";
681
+ EErrorHandlerTargetType["domain"] = "domain";
682
+ EErrorHandlerTargetType["default"] = "default";
683
+ return EErrorHandlerTargetType;
684
+ }({});
685
+ //#endregion
686
+ //#region src/NiceErrorHandler/NiceErrorHandler.ts
687
+ var NiceErrorHandler = class {
688
+ handlerConfigs = [];
689
+ _defaultRequester;
690
+ handleErrorWithPromiseInspection(error, options) {
691
+ for (const handlerConfig of this.handlerConfigs) {
692
+ if (!handlerConfig._matcher(error)) continue;
693
+ const errorResult = handlerConfig._requester(error);
694
+ if (errorResult instanceof Promise) return {
695
+ isPromise: true,
696
+ matched: true,
697
+ target: handlerConfig.target,
698
+ handlerPromise: errorResult
699
+ };
700
+ return {
701
+ isPromise: false,
702
+ matched: true,
703
+ target: handlerConfig.target,
704
+ handlerResponse: errorResult
705
+ };
706
+ }
707
+ if (this._defaultRequester) {
708
+ const defaultResult = this._defaultRequester(error);
709
+ if (defaultResult instanceof Promise) return {
710
+ isPromise: true,
711
+ matched: true,
712
+ target: {
713
+ type: "default",
714
+ identifier: "[matched:default]"
715
+ },
716
+ handlerPromise: defaultResult
717
+ };
718
+ return {
719
+ isPromise: false,
720
+ matched: true,
721
+ target: {
722
+ type: "default",
723
+ identifier: "[matched:default]"
724
+ },
725
+ handlerResponse: defaultResult
726
+ };
727
+ }
728
+ if (options?.throwOnUnhandled === true) throw error;
729
+ return {
730
+ matched: false,
731
+ attemptedTargets: this.handlerConfigs.map((config) => config.target)
732
+ };
733
+ }
734
+ /**
735
+ * Register a handler that fires for **any** error whose domain matches `domain`.
736
+ * The handler receives a fully hydrated error — `getContext`, `addId`, and `addContext`
737
+ * are all available. First matching case wins.
738
+ */
739
+ forDomain(domain, handler) {
740
+ this.handlerConfigs.push({
741
+ target: {
742
+ type: "domain",
743
+ domain: domain.domain,
744
+ identifier: `[matched:domain:${domain.domain}]`
745
+ },
746
+ _matcher: (error) => domain.isExact(error),
747
+ _requester: (error) => handler(domain.hydrate(error))
748
+ });
749
+ return this;
750
+ }
751
+ forId(domain, id, handler) {
752
+ this.handlerConfigs.push({
753
+ target: {
754
+ type: "ids",
755
+ domain: domain.domain,
756
+ ids: [id],
757
+ identifier: `[matched:ids:${domain.domain}:${id}]`
758
+ },
759
+ _matcher: (error) => domain.isExact(error) && error.hasId(id),
760
+ _requester: (error) => handler(domain.hydrate(error))
761
+ });
762
+ return this;
763
+ }
764
+ forIds(domain, ids, handler) {
765
+ this.handlerConfigs.push({
766
+ target: {
767
+ type: "ids",
768
+ domain: domain.domain,
769
+ ids,
770
+ identifier: `[matched:ids:${domain.domain}:${ids.join(",")}]`
771
+ },
772
+ _matcher: (error) => domain.isExact(error) && ids.some((id) => error.hasId(id)),
773
+ _requester: (error) => handler(domain.hydrate(error))
774
+ });
775
+ return this;
776
+ }
777
+ /**
778
+ * Register a fallback handler that fires when no other case matches.
779
+ * Only one default handler can be registered — calling this twice replaces the previous one.
780
+ */
781
+ setDefaultHandler(handler) {
782
+ this._defaultRequester = handler;
783
+ return this;
784
+ }
785
+ };
786
+ //#endregion
787
+ //#region src/NiceErrorHandler/handleWith.ts
706
788
  function forDomain(domain, handler) {
707
- return new NiceErrorHandler().forDomain(domain, handler);
789
+ return new NiceErrorHandler().forDomain(domain, handler);
708
790
  }
709
791
  function forId(domain, id, handler) {
710
- return new NiceErrorHandler().forId(domain, id, handler);
792
+ return new NiceErrorHandler().forId(domain, id, handler);
711
793
  }
712
794
  function forIds(domain, ids, handler) {
713
- return new NiceErrorHandler().forIds(domain, ids, handler);
795
+ return new NiceErrorHandler().forIds(domain, ids, handler);
714
796
  }
715
- // src/utils/isNiceErrorObject.ts
797
+ //#endregion
798
+ //#region src/utils/isNiceErrorObject.ts
799
+ /**
800
+ * Returns `true` if `obj` is a JSON-serialised `NiceError` object matching the
801
+ * current wire format (contextState-based errorData entries).
802
+ *
803
+ * Validates:
804
+ * - Top-level shape (`name`, `message`, `wasntNice`, `httpStatusCode`, `def`)
805
+ * - Each `errorData` entry has a `contextState` with a valid `kind` discriminant
806
+ * (`"no_serialization"` or `"unhydrated"`) — rejecting payloads in the old
807
+ * format (`context` / `serialized` fields) to prevent silent data corruption.
808
+ */
716
809
  function isNiceErrorObject(obj) {
717
- if (typeof obj !== "object" || obj == null)
718
- return false;
719
- const o = obj;
720
- if (o["name"] !== "NiceError" || typeof o["message"] !== "string" || typeof o["wasntNice"] !== "boolean" || typeof o["httpStatusCode"] !== "number") {
721
- return false;
722
- }
723
- const def = o["def"];
724
- if (typeof def !== "object" || def == null)
725
- return false;
726
- const d = def;
727
- if (typeof d["domain"] !== "string" || !Array.isArray(d["allDomains"]))
728
- return false;
729
- const errorData = o["errorData"];
730
- if (errorData != null) {
731
- if (typeof errorData !== "object")
732
- return false;
733
- for (const entry of Object.values(errorData)) {
734
- if (entry == null)
735
- continue;
736
- if (typeof entry !== "object")
737
- return false;
738
- const e = entry;
739
- const state = e["contextState"];
740
- if (state == null || typeof state !== "object")
741
- return false;
742
- const kind = state["kind"];
743
- if (kind !== "serde_unset" /* serde_unset */ && kind !== "unhydrated" /* unhydrated */)
744
- return false;
745
- }
746
- }
747
- return true;
810
+ if (typeof obj !== "object" || obj == null) return false;
811
+ const o = obj;
812
+ if (o["name"] !== "NiceError" || typeof o["message"] !== "string" || typeof o["wasntNice"] !== "boolean" || typeof o["httpStatusCode"] !== "number") return false;
813
+ const def = o["def"];
814
+ if (typeof def !== "object" || def == null) return false;
815
+ const d = def;
816
+ if (typeof d["domain"] !== "string" || !Array.isArray(d["allDomains"])) return false;
817
+ const errorData = o["errorData"];
818
+ if (errorData != null) {
819
+ if (typeof errorData !== "object") return false;
820
+ for (const entry of Object.values(errorData)) {
821
+ if (entry == null) continue;
822
+ if (typeof entry !== "object") return false;
823
+ const state = entry["contextState"];
824
+ if (state == null || typeof state !== "object") return false;
825
+ const kind = state["kind"];
826
+ if (kind !== "serde_unset" && kind !== "unhydrated") return false;
827
+ }
828
+ }
829
+ return true;
748
830
  }
749
-
750
- // src/utils/isRegularErrorObject.ts
831
+ //#endregion
832
+ //#region src/utils/isRegularErrorObject.ts
751
833
  function isRegularErrorJsonObject(obj) {
752
- if (typeof obj !== "object" || obj == null)
753
- return false;
754
- const o = obj;
755
- return typeof o["name"] === "string" && typeof o["message"] === "string";
834
+ if (typeof obj !== "object" || obj == null) return false;
835
+ const o = obj;
836
+ return typeof o["name"] === "string" && typeof o["message"] === "string";
756
837
  }
757
-
758
- // src/utils/logger.ts
759
- import { Logger } from "tslog";
760
- var logger_NiceError = new Logger({
761
- name: "NiceErrorLogger"
762
- });
763
- var logger_NiceError_testing = logger_NiceError.getSubLogger({
764
- name: "NiceErrorTestingLogger"
765
- });
766
-
767
- // src/utils/inspectPotentialError/inspectPotentialError.ts
838
+ //#endregion
839
+ //#region src/utils/logger.ts
840
+ const logger_NiceError = new Logger({ name: "NiceErrorLogger" });
841
+ logger_NiceError.getSubLogger({ name: "NiceErrorTestingLogger" });
842
+ //#endregion
843
+ //#region src/utils/inspectPotentialError/inspectPotentialError.ts
768
844
  function interpretMessagePackedError(parsedError) {
769
- let packedErrorStr;
770
- if (typeof parsedError.message === "string" && parsedError.message.includes(DUR_OBJ_PACK_PREFIX) && parsedError.message.includes(DUR_OBJ_PACK_SUFFIX)) {
771
- packedErrorStr = parsedError.message;
772
- }
773
- if (typeof parsedError.cause === "string" && parsedError.cause.includes(DUR_OBJ_PACK_PREFIX) && parsedError.cause.includes(DUR_OBJ_PACK_SUFFIX)) {
774
- packedErrorStr = parsedError.cause;
775
- }
776
- if (packedErrorStr != null) {
777
- const jsonStr = packedErrorStr.split(DUR_OBJ_PACK_PREFIX)[1].split(DUR_OBJ_PACK_SUFFIX)[0];
778
- try {
779
- const errorObj = JSON.parse(jsonStr);
780
- if (isNiceErrorObject(errorObj)) {
781
- return {
782
- type: "niceErrorObject" /* niceErrorObject */,
783
- niceErrorObject: errorObj
784
- };
785
- }
786
- } catch {}
787
- }
788
- return null;
845
+ let packedErrorStr;
846
+ if (typeof parsedError.message === "string" && parsedError.message.includes("NE_DUROBJ[[") && parsedError.message.includes("]]NE_DUROBJ")) packedErrorStr = parsedError.message;
847
+ if (typeof parsedError.cause === "string" && parsedError.cause.includes("NE_DUROBJ[[") && parsedError.cause.includes("]]NE_DUROBJ")) packedErrorStr = parsedError.cause;
848
+ if (packedErrorStr != null) {
849
+ const jsonStr = packedErrorStr.split(DUR_OBJ_PACK_PREFIX)[1].split(DUR_OBJ_PACK_SUFFIX)[0];
850
+ try {
851
+ const errorObj = JSON.parse(jsonStr);
852
+ if (isNiceErrorObject(errorObj)) return {
853
+ type: "niceErrorObject",
854
+ niceErrorObject: errorObj
855
+ };
856
+ } catch {}
857
+ }
858
+ return null;
789
859
  }
790
- var inspectPotentialError = (potentialError) => {
791
- if (potentialError == null) {
792
- return {
793
- type: "nullish" /* nullish */,
794
- value: potentialError
795
- };
796
- }
797
- if (typeof potentialError === "number") {
798
- return {
799
- type: "jsDataType" /* jsDataType */,
800
- jsDataType: "number",
801
- jsDataValue: potentialError
802
- };
803
- }
804
- if (typeof potentialError === "boolean") {
805
- return {
806
- type: "jsDataType" /* jsDataType */,
807
- jsDataType: "boolean",
808
- jsDataValue: potentialError
809
- };
810
- }
811
- let parsedError = potentialError;
812
- if (typeof potentialError === "string") {
813
- if (potentialError.includes("{") && potentialError.includes("name")) {
814
- try {
815
- parsedError = JSON.parse(potentialError);
816
- } catch {
817
- return {
818
- type: "jsDataType" /* jsDataType */,
819
- jsDataType: "string",
820
- jsDataValue: potentialError
821
- };
822
- }
823
- } else {
824
- return {
825
- type: "jsDataType" /* jsDataType */,
826
- jsDataType: "string",
827
- jsDataValue: potentialError
828
- };
829
- }
830
- }
831
- if (typeof parsedError !== "object" || parsedError == null) {
832
- logger_NiceError.warn({
833
- message: "Received a potential error that is a primitive data type other than string, number, or boolean. This is unexpected and may indicate an issue with error handling in the code.",
834
- potentialError
835
- });
836
- return {
837
- jsDataValue: potentialError,
838
- type: "jsOther" /* jsOther */
839
- };
840
- }
841
- if (parsedError instanceof NiceError) {
842
- return {
843
- type: "niceError" /* niceError */,
844
- niceError: parsedError
845
- };
846
- }
847
- if (isNiceErrorObject(parsedError)) {
848
- return {
849
- type: "niceErrorObject" /* niceErrorObject */,
850
- niceErrorObject: parsedError
851
- };
852
- }
853
- if (parsedError instanceof Error) {
854
- const durObjResult = interpretMessagePackedError(parsedError);
855
- if (durObjResult != null) {
856
- return durObjResult;
857
- }
858
- return {
859
- type: "jsError" /* jsError */,
860
- jsError: parsedError
861
- };
862
- }
863
- if (isRegularErrorJsonObject(parsedError)) {
864
- const durObjResult = interpretMessagePackedError(parsedError);
865
- if (durObjResult != null) {
866
- return durObjResult;
867
- }
868
- return {
869
- type: "jsErrorObject" /* jsErrorObject */,
870
- jsErrorObject: parsedError
871
- };
872
- }
873
- return {
874
- type: "jsDataType" /* jsDataType */,
875
- jsDataType: "object",
876
- jsDataValue: parsedError
877
- };
860
+ const inspectPotentialError = (potentialError) => {
861
+ if (potentialError == null) return {
862
+ type: "nullish",
863
+ value: potentialError
864
+ };
865
+ if (typeof potentialError === "number") return {
866
+ type: "jsDataType",
867
+ jsDataType: "number",
868
+ jsDataValue: potentialError
869
+ };
870
+ if (typeof potentialError === "boolean") return {
871
+ type: "jsDataType",
872
+ jsDataType: "boolean",
873
+ jsDataValue: potentialError
874
+ };
875
+ let parsedError = potentialError;
876
+ if (typeof potentialError === "string") if (potentialError.includes("{") && potentialError.includes("name")) try {
877
+ parsedError = JSON.parse(potentialError);
878
+ } catch {
879
+ return {
880
+ type: "jsDataType",
881
+ jsDataType: "string",
882
+ jsDataValue: potentialError
883
+ };
884
+ }
885
+ else return {
886
+ type: "jsDataType",
887
+ jsDataType: "string",
888
+ jsDataValue: potentialError
889
+ };
890
+ if (typeof parsedError !== "object" || parsedError == null) {
891
+ logger_NiceError.warn({
892
+ message: "Received a potential error that is a primitive data type other than string, number, or boolean. This is unexpected and may indicate an issue with error handling in the code.",
893
+ potentialError
894
+ });
895
+ return {
896
+ jsDataValue: potentialError,
897
+ type: "jsOther"
898
+ };
899
+ }
900
+ if (parsedError instanceof NiceError) return {
901
+ type: "niceError",
902
+ niceError: parsedError
903
+ };
904
+ if (isNiceErrorObject(parsedError)) return {
905
+ type: "niceErrorObject",
906
+ niceErrorObject: parsedError
907
+ };
908
+ if (parsedError instanceof Error) {
909
+ const durObjResult = interpretMessagePackedError(parsedError);
910
+ if (durObjResult != null) return durObjResult;
911
+ return {
912
+ type: "jsError",
913
+ jsError: parsedError
914
+ };
915
+ }
916
+ if (isRegularErrorJsonObject(parsedError)) {
917
+ const durObjResult = interpretMessagePackedError(parsedError);
918
+ if (durObjResult != null) return durObjResult;
919
+ return {
920
+ type: "jsErrorObject",
921
+ jsErrorObject: parsedError
922
+ };
923
+ }
924
+ return {
925
+ type: "jsDataType",
926
+ jsDataType: "object",
927
+ jsDataValue: parsedError
928
+ };
878
929
  };
879
-
880
- // src/utils/castNiceError.ts
881
- var castNiceError = (error) => {
882
- const inspected = inspectPotentialError(error);
883
- switch (inspected.type) {
884
- case "niceError" /* niceError */:
885
- return inspected.niceError;
886
- case "niceErrorObject" /* niceErrorObject */: {
887
- const obj = inspected.niceErrorObject;
888
- return new NiceError(obj);
889
- }
890
- case "jsError" /* jsError */: {
891
- return err_cast_not_nice.fromContext({
892
- ["native_error" /* js_error */]: inspected
893
- }).withOriginError(inspected.jsError);
894
- }
895
- case "jsErrorObject" /* jsErrorObject */: {
896
- const err2 = err_cast_not_nice.fromContext({
897
- ["js_error_like_object" /* js_error_like_object */]: inspected
898
- });
899
- err2.cause = inspected.jsErrorObject;
900
- return err2;
901
- }
902
- case "nullish" /* nullish */:
903
- return err_cast_not_nice.fromContext({
904
- ["nullish_value" /* nullish_value */]: inspected
905
- });
906
- case "jsDataType" /* jsDataType */: {
907
- return err_cast_not_nice.fromContext({
908
- ["js_data_type" /* js_data_type */]: inspected
909
- });
910
- }
911
- default:
912
- return err_cast_not_nice.fromContext({
913
- ["js_other" /* js_other */]: inspected
914
- });
915
- }
930
+ //#endregion
931
+ //#region src/utils/castNiceError.ts
932
+ /**
933
+ * Casts any unknown value into a `NiceError`.
934
+ *
935
+ * - If the value is already a `NiceError` instance, it is returned as-is.
936
+ * - If the value is a plain `Error`, it is wrapped with the original as `originError`.
937
+ * - If the value is a JSON-serialised `NiceError` object (e.g. from an API
938
+ * response), a best-effort `NiceError` is re-created from it.
939
+ * - For all other values, a generic `NiceError` is created with a descriptive
940
+ * message.
941
+ *
942
+ * After casting, use `NiceErrorDefined.is(error)` to narrow the error to a
943
+ * specific domain and access its strongly-typed ids and context.
944
+ */
945
+ const castNiceError = (error) => {
946
+ const inspected = inspectPotentialError(error);
947
+ switch (inspected.type) {
948
+ case "niceError": return inspected.niceError;
949
+ case "niceErrorObject": {
950
+ const obj = inspected.niceErrorObject;
951
+ return new NiceError(obj);
952
+ }
953
+ case "jsError": return err_cast_not_nice.fromContext({ ["native_error"]: inspected }).withOriginError(inspected.jsError);
954
+ case "jsErrorObject": {
955
+ const err = err_cast_not_nice.fromContext({ ["js_error_like_object"]: inspected });
956
+ err.cause = inspected.jsErrorObject;
957
+ return err;
958
+ }
959
+ case "nullish": return err_cast_not_nice.fromContext({ ["nullish_value"]: inspected });
960
+ case "jsDataType": return err_cast_not_nice.fromContext({ ["js_data_type"]: inspected });
961
+ default: return err_cast_not_nice.fromContext({ ["js_other"]: inspected });
962
+ }
916
963
  };
917
-
918
- // src/utils/castAndHydrate.ts
964
+ //#endregion
965
+ //#region src/utils/castAndHydrate.ts
966
+ /**
967
+ * Combines `castNiceError`, `is()`, and `hydrate()` in a single call — the
968
+ * idiomatic way to handle an unknown value arriving from a remote boundary
969
+ * (API response, message queue, IPC, etc.) when you have a specific domain in mind.
970
+ *
971
+ * - Casts `value` to a `NiceError` using `castNiceError`.
972
+ * - If the result belongs to `niceErrorDefined`'s domain (`is()` returns `true`),
973
+ * hydrates it and returns a fully-typed `NiceErrorHydrated`.
974
+ * - Otherwise returns the raw cast `NiceError` (which may be a `wasntNice` error
975
+ * if `value` was not a NiceError at all).
976
+ *
977
+ * @example
978
+ * ```ts
979
+ * // In an Express error handler:
980
+ * app.use((err, req, res, next) => {
981
+ * const error = castAndHydrate(err, err_user_auth);
982
+ *
983
+ * if (err_user_auth.is(error)) {
984
+ * // error is NiceErrorHydrated — getContext / addId available
985
+ * const result = matchFirst(error, {
986
+ * invalid_credentials: ({ username }) => res.status(401).json({ username }),
987
+ * account_locked: () => res.status(403).json({ locked: true }),
988
+ * });
989
+ * if (result) return;
990
+ * }
991
+ *
992
+ * next(err);
993
+ * });
994
+ * ```
995
+ */
919
996
  function castAndHydrate(value, niceErrorDefined) {
920
- const casted = castNiceError(value);
921
- if (niceErrorDefined.isExact(casted)) {
922
- return niceErrorDefined.hydrate(casted);
923
- }
924
- return casted;
997
+ const casted = castNiceError(value);
998
+ if (niceErrorDefined.isExact(casted)) return niceErrorDefined.hydrate(casted);
999
+ return casted;
925
1000
  }
926
- // src/utils/matchFirst.ts
1001
+ //#endregion
1002
+ //#region src/utils/matchFirst.ts
1003
+ /**
1004
+ * Pattern-matches an error against a map of id → handler functions, returning the
1005
+ * result of the first handler whose id is active on the error.
1006
+ *
1007
+ * - Ids are tested in the order returned by `error.getIds()`.
1008
+ * - If no id-specific handler matched and `_` is provided, the fallback is called.
1009
+ * - Returns `undefined` when neither any id handler nor the fallback fires.
1010
+ *
1011
+ * **Requires hydrated context.** If any matched id is in the `"unhydrated"` state,
1012
+ * `getContext` will throw. Call `niceErrorDefined.hydrate(error)` beforehand when
1013
+ * working with errors deserialized from a JSON payload.
1014
+ *
1015
+ * @example
1016
+ * ```ts
1017
+ * const result = matchFirst(error, {
1018
+ * invalid_credentials: ({ username }) => `Wrong password for ${username}`,
1019
+ * account_locked: () => "Account is locked",
1020
+ * _: () => "Unknown auth error",
1021
+ * });
1022
+ * ```
1023
+ */
927
1024
  function matchFirst(error, handlers) {
928
- for (const id of error.getIds()) {
929
- const handler = handlers[id];
930
- if (typeof handler === "function") {
931
- const context = error.getContext(id);
932
- return handler(context);
933
- }
934
- }
935
- if (typeof handlers._ === "function") {
936
- return handlers._();
937
- }
938
- return;
1025
+ for (const id of error.getIds()) {
1026
+ const handler = handlers[id];
1027
+ if (typeof handler === "function") return handler(error.getContext(id));
1028
+ }
1029
+ if (typeof handlers._ === "function") return handlers._();
939
1030
  }
940
- export {
941
- msgPack,
942
- matchFirst,
943
- isRegularErrorJsonObject,
944
- isNiceErrorObject,
945
- forIds,
946
- forId,
947
- forDomain,
948
- err_nice_handler,
949
- err_nice,
950
- err_cast_not_nice,
951
- err,
952
- defineNiceError,
953
- causePack,
954
- castNiceError,
955
- castAndHydrate,
956
- NiceErrorHydrated,
957
- NiceErrorHandler,
958
- NiceErrorDomain,
959
- NiceError,
960
- EErrorPackType,
961
- EErrorHandlerTargetType,
962
- EErrId_CastNotNice
963
- };
1031
+ //#endregion
1032
+ export { EErrId_CastNotNice, EErrorHandlerTargetType, EErrorPackType, NiceError, NiceErrorDomain, NiceErrorHandler, NiceErrorHydrated, castAndHydrate, castNiceError, causePack, defineNiceError, err, err_cast_not_nice, err_nice, err_nice_handler, forDomain, forId, forIds, isNiceErrorObject, isRegularErrorJsonObject, matchFirst, msgPack };
1033
+
1034
+ //# sourceMappingURL=index.js.map