@venizia/ignis-inversion 0.1.1-0 → 0.1.1-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/modules/error/app-error.d.ts +0 -1
- package/dist/cjs/modules/error/app-error.d.ts.map +1 -1
- package/dist/cjs/modules/error/app-error.js +14 -20
- package/dist/cjs/modules/error/app-error.js.map +1 -1
- package/dist/cjs/modules/error/definition.d.ts +0 -33
- package/dist/cjs/modules/error/definition.d.ts.map +1 -1
- package/dist/cjs/modules/error/message-code.d.ts +8 -4
- package/dist/cjs/modules/error/message-code.d.ts.map +1 -1
- package/dist/cjs/modules/error/message-code.js +11 -3
- package/dist/cjs/modules/error/message-code.js.map +1 -1
- package/dist/cjs/modules/error/types.d.ts +60 -12
- package/dist/cjs/modules/error/types.d.ts.map +1 -1
- package/dist/esm/modules/error/app-error.d.ts +0 -1
- package/dist/esm/modules/error/app-error.d.ts.map +1 -1
- package/dist/esm/modules/error/app-error.js +14 -20
- package/dist/esm/modules/error/app-error.js.map +1 -1
- package/dist/esm/modules/error/definition.d.ts +0 -33
- package/dist/esm/modules/error/definition.d.ts.map +1 -1
- package/dist/esm/modules/error/message-code.d.ts +8 -4
- package/dist/esm/modules/error/message-code.d.ts.map +1 -1
- package/dist/esm/modules/error/message-code.js +11 -3
- package/dist/esm/modules/error/message-code.js.map +1 -1
- package/dist/esm/modules/error/types.d.ts +60 -12
- package/dist/esm/modules/error/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-error.d.ts","sourceRoot":"","sources":["../../../../src/modules/error/app-error.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"app-error.d.ts","sourceRoot":"","sources":["../../../../src/modules/error/app-error.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAwC,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAe9F,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAEpB,IAAI,EAAE,MAAM;IAmCxB,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM;CAG7B;AAED,eAAO,MAAM,QAAQ,GAAI,MAAM,MAAM,KAAG,gBAAmD,CAAC;AAE5F,eAAO,MAAM,kBAAkB,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,gBAE5D,CAAC"}
|
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.isApplicationError = exports.getError = exports.ApplicationError = void 0;
|
|
7
7
|
const omit_1 = __importDefault(require("lodash/omit"));
|
|
8
8
|
const message_code_1 = require("./message-code");
|
|
9
|
-
/**
|
|
9
|
+
/** Consumed keys. Everything else rides into `extra`. */
|
|
10
10
|
const KNOWN_KEYS = [
|
|
11
11
|
'error',
|
|
12
12
|
'message',
|
|
@@ -21,40 +21,34 @@ const KNOWN_KEYS = [
|
|
|
21
21
|
class ApplicationError extends Error {
|
|
22
22
|
constructor(opts) {
|
|
23
23
|
const { statusCode, messageArgs, cause, extra, transform } = opts;
|
|
24
|
-
//
|
|
25
|
-
// members - so read the discriminant and cast.
|
|
24
|
+
// Index signature defeats `in` narrowing - read the discriminant and cast.
|
|
26
25
|
const definition = ('error' in opts ? opts.error : undefined);
|
|
27
|
-
const
|
|
28
|
-
const
|
|
26
|
+
const input = opts.message;
|
|
27
|
+
const override = typeof input === 'string' ? { text: input } : input;
|
|
28
|
+
// `?.message?.` - the optional chain has to guard BOTH: `error` reaches here from an untyped
|
|
29
|
+
// call site as anything at all, and a bare `definition?.message.text` throws on a malformed one.
|
|
30
|
+
const message = override?.text ?? definition?.message?.text ?? '';
|
|
31
|
+
const messageCode = message_code_1.MessageCode.resolve(override?.code ?? definition?.message?.code ?? opts.messageCode);
|
|
32
|
+
const args = override?.args ?? messageArgs ?? definition?.message?.args;
|
|
29
33
|
super(message, cause === undefined ? undefined : { cause });
|
|
30
34
|
this.statusCode = statusCode ?? definition?.statusCode ?? 400;
|
|
31
|
-
|
|
32
|
-
const args = messageArgs ?? definition?.messageArgs;
|
|
33
|
-
// Unknown keys sweep in first, then the `messageArgs` mirror, then explicit `extra` - so an
|
|
34
|
-
// explicit value wins over one that arrived by accident.
|
|
35
|
+
// Explicit `extra` wins over swept keys.
|
|
35
36
|
const merged = {
|
|
36
37
|
...(0, omit_1.default)(opts, KNOWN_KEYS),
|
|
37
|
-
...(args ? { messageArgs: args } : {}),
|
|
38
38
|
...extra,
|
|
39
39
|
};
|
|
40
40
|
this.extra = Object.keys(merged).length > 0 ? merged : undefined;
|
|
41
|
+
const normalized = { text: message, code: messageCode, args: args ?? {} };
|
|
41
42
|
this.normalized = transform
|
|
42
|
-
? transform({
|
|
43
|
-
|
|
44
|
-
messageCode: this.messageCode,
|
|
45
|
-
statusCode: this.statusCode,
|
|
46
|
-
extra: this.extra,
|
|
47
|
-
})
|
|
48
|
-
: { text: message, code: this.messageCode, args: args ?? {} };
|
|
43
|
+
? transform({ message: normalized, statusCode: this.statusCode, extra: this.extra })
|
|
44
|
+
: normalized;
|
|
49
45
|
}
|
|
50
46
|
static getError(opts) {
|
|
51
47
|
return new ApplicationError(opts);
|
|
52
48
|
}
|
|
53
49
|
}
|
|
54
50
|
exports.ApplicationError = ApplicationError;
|
|
55
|
-
const getError = (opts) =>
|
|
56
|
-
return new ApplicationError(opts);
|
|
57
|
-
};
|
|
51
|
+
const getError = (opts) => ApplicationError.getError(opts);
|
|
58
52
|
exports.getError = getError;
|
|
59
53
|
const isApplicationError = (error) => {
|
|
60
54
|
return error instanceof Error && typeof error.statusCode === 'number';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-error.js","sourceRoot":"","sources":["../../../../src/modules/error/app-error.ts"],"names":[],"mappings":";;;;;;AAAA,uDAA+B;AAE/B,iDAA6C;
|
|
1
|
+
{"version":3,"file":"app-error.js","sourceRoot":"","sources":["../../../../src/modules/error/app-error.ts"],"names":[],"mappings":";;;;;;AAAA,uDAA+B;AAE/B,iDAA6C;AAG7C,yDAAyD;AACzD,MAAM,UAAU,GAAG;IACjB,OAAO;IACP,SAAS;IACT,aAAa;IACb,YAAY;IACZ,aAAa;IACb,OAAO;IACP,OAAO;IACP,WAAW;IACX,MAAM;CACP,CAAC;AAEF,MAAa,gBAAiB,SAAQ,KAAK;IAKzC,YAAY,IAAY;QACtB,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;QAElE,2EAA2E;QAC3E,MAAM,UAAU,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAgC,CAAC;QAE7F,MAAM,KAAK,GAAG,IAAI,CAAC,OAA0D,CAAC;QAC9E,MAAM,QAAQ,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;QAErE,6FAA6F;QAC7F,iGAAiG;QACjG,MAAM,OAAO,GAAG,QAAQ,EAAE,IAAI,IAAI,UAAU,EAAE,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC;QAClE,MAAM,WAAW,GAAG,0BAAW,CAAC,OAAO,CACrC,QAAQ,EAAE,IAAI,IAAI,UAAU,EAAE,OAAO,EAAE,IAAI,IAAK,IAAI,CAAC,WAAiC,CACvF,CAAC;QACF,MAAM,IAAI,GAAG,QAAQ,EAAE,IAAI,IAAI,WAAW,IAAI,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC;QAExE,KAAK,CAAC,OAAO,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAE5D,IAAI,CAAC,UAAU,GAAG,UAAU,IAAI,UAAU,EAAE,UAAU,IAAI,GAAG,CAAC;QAE9D,yCAAyC;QACzC,MAAM,MAAM,GAAG;YACb,GAAG,IAAA,cAAI,EAAC,IAAI,EAAE,UAAU,CAAC;YACzB,GAAG,KAAK;SACT,CAAC;QACF,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;QAEjE,MAAM,UAAU,GAAqB,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;QAE5F,IAAI,CAAC,UAAU,GAAG,SAAS;YACzB,CAAC,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;YACpF,CAAC,CAAC,UAAU,CAAC;IACjB,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,IAAY;QAC1B,OAAO,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;CACF;AA3CD,4CA2CC;AAEM,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAoB,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAA/E,QAAA,QAAQ,YAAuE;AAErF,MAAM,kBAAkB,GAAG,CAAC,KAAc,EAA6B,EAAE;IAC9E,OAAO,KAAK,YAAY,KAAK,IAAI,OAAQ,KAAiB,CAAC,UAAU,KAAK,QAAQ,CAAC;AACrF,CAAC,CAAC;AAFW,QAAA,kBAAkB,sBAE7B"}
|
|
@@ -7,37 +7,4 @@ export declare class ErrorScopes {
|
|
|
7
7
|
static readonly INTEGRATION = "integration";
|
|
8
8
|
}
|
|
9
9
|
export type TErrorScope = TConstValue<typeof ErrorScopes>;
|
|
10
|
-
export type TErrorDefinition = {
|
|
11
|
-
/** Dot-notated i18n key, the machine-readable identity of this failure. */
|
|
12
|
-
key: string;
|
|
13
|
-
statusCode: number;
|
|
14
|
-
message: string;
|
|
15
|
-
messageArgs?: Record<string, unknown>;
|
|
16
|
-
category?: TErrorScope;
|
|
17
|
-
description?: string;
|
|
18
|
-
};
|
|
19
|
-
/**
|
|
20
|
-
* Augmented per-package via declaration merging, driving `messageCode` autocomplete.
|
|
21
|
-
*
|
|
22
|
-
* When nothing augments it - the framework compiling on its own - {@link TErrorKey} falls back to
|
|
23
|
-
* `string`, so a consumer that keeps no catalog is not forced to build one.
|
|
24
|
-
*/
|
|
25
|
-
export interface IErrorKeyRegistry {
|
|
26
|
-
}
|
|
27
|
-
export type TErrorKey = [keyof IErrorKeyRegistry] extends [never] ? string : Extract<keyof IErrorKeyRegistry, string>;
|
|
28
|
-
/**
|
|
29
|
-
* Registers a catalog's keys with {@link IErrorKeyRegistry}:
|
|
30
|
-
*
|
|
31
|
-
* ```ts
|
|
32
|
-
* declare module '@venizia/ignis-helpers' {
|
|
33
|
-
* interface IErrorKeyRegistry extends TRegisterErrors<typeof CategoryErrors> {}
|
|
34
|
-
* }
|
|
35
|
-
* ```
|
|
36
|
-
*
|
|
37
|
-
* The `extends Record<string, TErrorDefinition>` bound is load-bearing: without it TypeScript does
|
|
38
|
-
* not know every value of `T` carries a `key`, and `T[keyof T]['key']` fails to compile. It costs
|
|
39
|
-
* nothing in precision - `T` is still the type of an `as const` catalog, so the indexed access
|
|
40
|
-
* yields the union of literal keys rather than `string`.
|
|
41
|
-
*/
|
|
42
|
-
export type TRegisterErrors<T extends Record<string, TErrorDefinition>> = Record<T[keyof T]['key'], true>;
|
|
43
10
|
//# sourceMappingURL=definition.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../../../src/modules/error/definition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,qBAAa,WAAW;IACtB,MAAM,CAAC,QAAQ,CAAC,IAAI,UAAU;IAC9B,MAAM,CAAC,QAAQ,CAAC,UAAU,gBAAgB;IAC1C,MAAM,CAAC,QAAQ,CAAC,QAAQ,cAAc;IACtC,MAAM,CAAC,QAAQ,CAAC,MAAM,YAAY;IAClC,MAAM,CAAC,QAAQ,CAAC,WAAW,iBAAiB;CAC7C;AAED,MAAM,MAAM,WAAW,GAAG,WAAW,CAAC,OAAO,WAAW,CAAC,CAAC
|
|
1
|
+
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../../../src/modules/error/definition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,qBAAa,WAAW;IACtB,MAAM,CAAC,QAAQ,CAAC,IAAI,UAAU;IAC9B,MAAM,CAAC,QAAQ,CAAC,UAAU,gBAAgB;IAC1C,MAAM,CAAC,QAAQ,CAAC,QAAQ,cAAc;IACtC,MAAM,CAAC,QAAQ,CAAC,MAAM,YAAY;IAClC,MAAM,CAAC,QAAQ,CAAC,WAAW,iBAAiB;CAC7C;AAED,MAAM,MAAM,WAAW,GAAG,WAAW,CAAC,OAAO,WAAW,CAAC,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { TNullable } from '../../common/types';
|
|
1
2
|
export declare class MessageCode {
|
|
2
3
|
static readonly SEPARATOR = ".";
|
|
3
4
|
static readonly SEGMENT_PATTERN: RegExp;
|
|
@@ -10,9 +11,12 @@ export declare class MessageCode {
|
|
|
10
11
|
static build(opts: {
|
|
11
12
|
parts: Array<string>;
|
|
12
13
|
}): string;
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
/**
|
|
15
|
+
* True when `code` is well-formed. A guard for a code arriving from outside, so it takes
|
|
16
|
+
* `unknown`: one that throws on the very input it exists to screen is not a guard.
|
|
17
|
+
*/
|
|
18
|
+
static isValid(code: unknown): boolean;
|
|
19
|
+
/** Normalizes an absent, empty or non-string code to {@link DEFAULT}. */
|
|
20
|
+
static resolve(code?: TNullable<string>): string;
|
|
17
21
|
}
|
|
18
22
|
//# sourceMappingURL=message-code.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-code.d.ts","sourceRoot":"","sources":["../../../../src/modules/error/message-code.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"message-code.d.ts","sourceRoot":"","sources":["../../../../src/modules/error/message-code.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhD,qBAAa,WAAW;IACtB,MAAM,CAAC,QAAQ,CAAC,SAAS,OAAO;IAChC,MAAM,CAAC,QAAQ,CAAC,eAAe,SAA8B;IAC7D,MAAM,CAAC,QAAQ,CAAC,YAAY,KAAK;IACjC,MAAM,CAAC,QAAQ,CAAC,OAAO,uBAAuB;IAE9C;;;OAGG;IACH,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;KAAE,GAAG,MAAM;IAsBpD;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO;IAatC,yEAAyE;IACzE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,MAAM;CAKjD"}
|
|
@@ -29,15 +29,23 @@ class MessageCode {
|
|
|
29
29
|
}
|
|
30
30
|
return parts.join(this.SEPARATOR).toLowerCase();
|
|
31
31
|
}
|
|
32
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* True when `code` is well-formed. A guard for a code arriving from outside, so it takes
|
|
34
|
+
* `unknown`: one that throws on the very input it exists to screen is not a guard.
|
|
35
|
+
*/
|
|
33
36
|
static isValid(code) {
|
|
37
|
+
if (typeof code !== 'string') {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
34
40
|
const segments = code.split(this.SEPARATOR);
|
|
35
41
|
return (segments.length >= this.MIN_SEGMENTS &&
|
|
36
42
|
segments.every(segment => this.SEGMENT_PATTERN.test(segment)));
|
|
37
43
|
}
|
|
38
|
-
/** Normalizes an absent or
|
|
44
|
+
/** Normalizes an absent, empty or non-string code to {@link DEFAULT}. */
|
|
39
45
|
static resolve(code) {
|
|
40
|
-
return code
|
|
46
|
+
return typeof code === 'string' && code.length
|
|
47
|
+
? code.toLowerCase()
|
|
48
|
+
: this.DEFAULT.toLowerCase();
|
|
41
49
|
}
|
|
42
50
|
}
|
|
43
51
|
exports.MessageCode = MessageCode;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-code.js","sourceRoot":"","sources":["../../../../src/modules/error/message-code.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"message-code.js","sourceRoot":"","sources":["../../../../src/modules/error/message-code.ts"],"names":[],"mappings":";;;AACA,2CAAuC;AAEvC,MAAa,WAAW;aACN,cAAS,GAAG,GAAG,CAAC;aAChB,oBAAe,GAAG,0BAA0B,CAAC;aAC7C,iBAAY,GAAG,CAAC,CAAC;aACjB,YAAO,GAAG,mBAAmB,CAAC;IAE9C;;;OAGG;IACH,MAAM,CAAC,KAAK,CAAC,IAA8B;QACzC,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;QAEvB,IAAI,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;YACrC,MAAM,IAAA,oBAAQ,EAAC;gBACb,WAAW,EAAE,yCAAyC;gBACtD,OAAO,EAAE,8CAA8C,IAAI,CAAC,YAAY,yCAAyC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE;aACzI,CAAC,CAAC;QACL,CAAC;QAED,KAAK,MAAM,OAAO,IAAI,KAAK,EAAE,CAAC;YAC5B,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBACxC,MAAM,IAAA,oBAAQ,EAAC;oBACb,WAAW,EAAE,0CAA0C;oBACvD,OAAO,EAAE,yCAAyC,OAAO,yDAAyD,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE;iBAC1I,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;IAClD,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,IAAa;QAC1B,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7B,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAE5C,OAAO,CACL,QAAQ,CAAC,MAAM,IAAI,IAAI,CAAC,YAAY;YACpC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAC9D,CAAC;IACJ,CAAC;IAED,yEAAyE;IACzE,MAAM,CAAC,OAAO,CAAC,IAAwB;QACrC,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM;YAC5C,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE;YACpB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IACjC,CAAC;;AAtDH,kCAuDC"}
|
|
@@ -1,18 +1,49 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
/**
|
|
1
|
+
import type { TErrorScope } from './definition';
|
|
2
|
+
/**
|
|
3
|
+
* The RESOLVED message a client renders: `translate(code, args)`. Every field is always present -
|
|
4
|
+
* the constructor defaults `code` to {@link MessageCode.DEFAULT} and `args` to `{}` - so no consumer
|
|
5
|
+
* has to null-check what it reads.
|
|
6
|
+
*/
|
|
3
7
|
export type TErrorNormalized = {
|
|
4
8
|
text: string;
|
|
5
9
|
code: string;
|
|
6
10
|
args: Record<string, unknown>;
|
|
7
11
|
};
|
|
8
12
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* wrote, `text` is what a client shows.
|
|
13
|
+
* The message a CALLER supplies. Only `text` is required; the rest is what {@link TErrorNormalized}
|
|
14
|
+
* resolves. Every other message shape below is derived from this one.
|
|
12
15
|
*/
|
|
16
|
+
export type TErrorMessageInput = {
|
|
17
|
+
text: string;
|
|
18
|
+
code?: TErrorKey | (string & Record<never, never>);
|
|
19
|
+
args?: Record<string, unknown>;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* A catalogued message - a `code` is the whole reason the catalog exists, so it is required here.
|
|
23
|
+
*
|
|
24
|
+
* `code` is a plain `string`, NOT {@link TErrorKey}: a catalog DECLARES the keys the registry is
|
|
25
|
+
* built from, so typing it against that registry would make `IErrorKeyRegistry` define itself.
|
|
26
|
+
*/
|
|
27
|
+
export type TErrorDefinitionMessage = Omit<TErrorMessageInput, 'code'> & {
|
|
28
|
+
code: string;
|
|
29
|
+
};
|
|
30
|
+
/** The free-form input: a bare string is the historical shape. */
|
|
31
|
+
export type TErrorMessage = string | TErrorMessageInput;
|
|
32
|
+
/** The catalogued form's override - every field optional, since the definition supplies the rest. */
|
|
33
|
+
export type TErrorMessageOverride = string | Partial<TErrorMessageInput>;
|
|
34
|
+
export type TErrorDefinition = {
|
|
35
|
+
message: TErrorDefinitionMessage;
|
|
36
|
+
statusCode: number;
|
|
37
|
+
category?: TErrorScope;
|
|
38
|
+
description?: string;
|
|
39
|
+
};
|
|
40
|
+
/** Augmented per-package via declaration merging, driving `messageCode` autocomplete. */
|
|
41
|
+
export interface IErrorKeyRegistry {
|
|
42
|
+
}
|
|
43
|
+
export type TErrorKey = [keyof IErrorKeyRegistry] extends [never] ? string : Extract<keyof IErrorKeyRegistry, string>;
|
|
44
|
+
/** Builds {@link TErrorNormalized} in place of the default; `message` is the default it replaces. */
|
|
13
45
|
export type TErrorNormalizeTransformFn = (opts: {
|
|
14
|
-
message:
|
|
15
|
-
messageCode: string;
|
|
46
|
+
message: TErrorNormalized;
|
|
16
47
|
statusCode: number;
|
|
17
48
|
extra?: Record<string, unknown>;
|
|
18
49
|
}) => TErrorNormalized;
|
|
@@ -23,16 +54,17 @@ export type TErrorNormalizeTransformFn = (opts: {
|
|
|
23
54
|
type TErrorCommon = {
|
|
24
55
|
statusCode?: number;
|
|
25
56
|
messageArgs?: Record<string, unknown>;
|
|
26
|
-
/** The wrapped failure. Reaches the native `Error.cause`. */
|
|
27
57
|
cause?: unknown;
|
|
28
|
-
/** Explicit context. Merges with whatever the index signature swept in. */
|
|
29
58
|
extra?: Record<string, unknown>;
|
|
30
59
|
transform?: TErrorNormalizeTransformFn;
|
|
31
60
|
};
|
|
32
|
-
/**
|
|
61
|
+
/**
|
|
62
|
+
* Catalogued form. `message` and `statusCode` override the definition's defaults; the object form is
|
|
63
|
+
* partial, so `{ message: { args } }` amends the args and keeps the definition's text and code.
|
|
64
|
+
*/
|
|
33
65
|
export type TErrorByDefinition = TErrorCommon & {
|
|
34
66
|
error: TErrorDefinition;
|
|
35
|
-
message?:
|
|
67
|
+
message?: TErrorMessageOverride;
|
|
36
68
|
[key: string]: unknown;
|
|
37
69
|
};
|
|
38
70
|
/**
|
|
@@ -40,10 +72,26 @@ export type TErrorByDefinition = TErrorCommon & {
|
|
|
40
72
|
* only required field - most throw sites legitimately fall back to `MessageCode.DEFAULT`.
|
|
41
73
|
*/
|
|
42
74
|
export type TErrorByField = TErrorCommon & {
|
|
43
|
-
message:
|
|
75
|
+
message: TErrorMessage;
|
|
44
76
|
messageCode?: TErrorKey | (string & Record<never, never>);
|
|
77
|
+
/**
|
|
78
|
+
* Never valid here - `error` is the catalogued form's discriminant. Without this the index
|
|
79
|
+
* signature accepts `{ message, error: caughtError }`, a natural way to write "wrap this", and
|
|
80
|
+
* `error` is a CONSUMED key: the wrapped failure would vanish. Use `cause`.
|
|
81
|
+
*/
|
|
82
|
+
error?: never;
|
|
45
83
|
[key: string]: unknown;
|
|
46
84
|
};
|
|
47
85
|
export type TError = TErrorByDefinition | TErrorByField;
|
|
86
|
+
/**
|
|
87
|
+
* Registers a catalog's keys with {@link IErrorKeyRegistry}:
|
|
88
|
+
*
|
|
89
|
+
* ```ts
|
|
90
|
+
* declare module '@venizia/ignis-helpers' {
|
|
91
|
+
* interface IErrorKeyRegistry extends TRegisterErrors<typeof CategoryErrors> {}
|
|
92
|
+
* }
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
export type TRegisterErrors<T extends Record<string, TErrorDefinition>> = Record<T[keyof T]['message']['code'], true>;
|
|
48
96
|
export {};
|
|
49
97
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/modules/error/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/modules/error/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-error.d.ts","sourceRoot":"","sources":["../../../../src/modules/error/app-error.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"app-error.d.ts","sourceRoot":"","sources":["../../../../src/modules/error/app-error.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAwC,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAe9F,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAEpB,IAAI,EAAE,MAAM;IAmCxB,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM;CAG7B;AAED,eAAO,MAAM,QAAQ,GAAI,MAAM,MAAM,KAAG,gBAAmD,CAAC;AAE5F,eAAO,MAAM,kBAAkB,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,gBAE5D,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import omit from 'lodash/omit';
|
|
2
2
|
import { MessageCode } from './message-code';
|
|
3
|
-
/**
|
|
3
|
+
/** Consumed keys. Everything else rides into `extra`. */
|
|
4
4
|
const KNOWN_KEYS = [
|
|
5
5
|
'error',
|
|
6
6
|
'message',
|
|
@@ -15,39 +15,33 @@ const KNOWN_KEYS = [
|
|
|
15
15
|
export class ApplicationError extends Error {
|
|
16
16
|
constructor(opts) {
|
|
17
17
|
const { statusCode, messageArgs, cause, extra, transform } = opts;
|
|
18
|
-
//
|
|
19
|
-
// members - so read the discriminant and cast.
|
|
18
|
+
// Index signature defeats `in` narrowing - read the discriminant and cast.
|
|
20
19
|
const definition = ('error' in opts ? opts.error : undefined);
|
|
21
|
-
const
|
|
22
|
-
const
|
|
20
|
+
const input = opts.message;
|
|
21
|
+
const override = typeof input === 'string' ? { text: input } : input;
|
|
22
|
+
// `?.message?.` - the optional chain has to guard BOTH: `error` reaches here from an untyped
|
|
23
|
+
// call site as anything at all, and a bare `definition?.message.text` throws on a malformed one.
|
|
24
|
+
const message = override?.text ?? definition?.message?.text ?? '';
|
|
25
|
+
const messageCode = MessageCode.resolve(override?.code ?? definition?.message?.code ?? opts.messageCode);
|
|
26
|
+
const args = override?.args ?? messageArgs ?? definition?.message?.args;
|
|
23
27
|
super(message, cause === undefined ? undefined : { cause });
|
|
24
28
|
this.statusCode = statusCode ?? definition?.statusCode ?? 400;
|
|
25
|
-
|
|
26
|
-
const args = messageArgs ?? definition?.messageArgs;
|
|
27
|
-
// Unknown keys sweep in first, then the `messageArgs` mirror, then explicit `extra` - so an
|
|
28
|
-
// explicit value wins over one that arrived by accident.
|
|
29
|
+
// Explicit `extra` wins over swept keys.
|
|
29
30
|
const merged = {
|
|
30
31
|
...omit(opts, KNOWN_KEYS),
|
|
31
|
-
...(args ? { messageArgs: args } : {}),
|
|
32
32
|
...extra,
|
|
33
33
|
};
|
|
34
34
|
this.extra = Object.keys(merged).length > 0 ? merged : undefined;
|
|
35
|
+
const normalized = { text: message, code: messageCode, args: args ?? {} };
|
|
35
36
|
this.normalized = transform
|
|
36
|
-
? transform({
|
|
37
|
-
|
|
38
|
-
messageCode: this.messageCode,
|
|
39
|
-
statusCode: this.statusCode,
|
|
40
|
-
extra: this.extra,
|
|
41
|
-
})
|
|
42
|
-
: { text: message, code: this.messageCode, args: args ?? {} };
|
|
37
|
+
? transform({ message: normalized, statusCode: this.statusCode, extra: this.extra })
|
|
38
|
+
: normalized;
|
|
43
39
|
}
|
|
44
40
|
static getError(opts) {
|
|
45
41
|
return new ApplicationError(opts);
|
|
46
42
|
}
|
|
47
43
|
}
|
|
48
|
-
export const getError = (opts) =>
|
|
49
|
-
return new ApplicationError(opts);
|
|
50
|
-
};
|
|
44
|
+
export const getError = (opts) => ApplicationError.getError(opts);
|
|
51
45
|
export const isApplicationError = (error) => {
|
|
52
46
|
return error instanceof Error && typeof error.statusCode === 'number';
|
|
53
47
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-error.js","sourceRoot":"","sources":["../../../../src/modules/error/app-error.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,aAAa,CAAC;AAE/B,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"app-error.js","sourceRoot":"","sources":["../../../../src/modules/error/app-error.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,aAAa,CAAC;AAE/B,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG7C,yDAAyD;AACzD,MAAM,UAAU,GAAG;IACjB,OAAO;IACP,SAAS;IACT,aAAa;IACb,YAAY;IACZ,aAAa;IACb,OAAO;IACP,OAAO;IACP,WAAW;IACX,MAAM;CACP,CAAC;AAEF,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAKzC,YAAY,IAAY;QACtB,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;QAElE,2EAA2E;QAC3E,MAAM,UAAU,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAgC,CAAC;QAE7F,MAAM,KAAK,GAAG,IAAI,CAAC,OAA0D,CAAC;QAC9E,MAAM,QAAQ,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;QAErE,6FAA6F;QAC7F,iGAAiG;QACjG,MAAM,OAAO,GAAG,QAAQ,EAAE,IAAI,IAAI,UAAU,EAAE,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC;QAClE,MAAM,WAAW,GAAG,WAAW,CAAC,OAAO,CACrC,QAAQ,EAAE,IAAI,IAAI,UAAU,EAAE,OAAO,EAAE,IAAI,IAAK,IAAI,CAAC,WAAiC,CACvF,CAAC;QACF,MAAM,IAAI,GAAG,QAAQ,EAAE,IAAI,IAAI,WAAW,IAAI,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC;QAExE,KAAK,CAAC,OAAO,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAE5D,IAAI,CAAC,UAAU,GAAG,UAAU,IAAI,UAAU,EAAE,UAAU,IAAI,GAAG,CAAC;QAE9D,yCAAyC;QACzC,MAAM,MAAM,GAAG;YACb,GAAG,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC;YACzB,GAAG,KAAK;SACT,CAAC;QACF,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;QAEjE,MAAM,UAAU,GAAqB,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;QAE5F,IAAI,CAAC,UAAU,GAAG,SAAS;YACzB,CAAC,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;YACpF,CAAC,CAAC,UAAU,CAAC;IACjB,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,IAAY;QAC1B,OAAO,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;CACF;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAoB,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAE5F,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,KAAc,EAA6B,EAAE;IAC9E,OAAO,KAAK,YAAY,KAAK,IAAI,OAAQ,KAAiB,CAAC,UAAU,KAAK,QAAQ,CAAC;AACrF,CAAC,CAAC"}
|
|
@@ -7,37 +7,4 @@ export declare class ErrorScopes {
|
|
|
7
7
|
static readonly INTEGRATION = "integration";
|
|
8
8
|
}
|
|
9
9
|
export type TErrorScope = TConstValue<typeof ErrorScopes>;
|
|
10
|
-
export type TErrorDefinition = {
|
|
11
|
-
/** Dot-notated i18n key, the machine-readable identity of this failure. */
|
|
12
|
-
key: string;
|
|
13
|
-
statusCode: number;
|
|
14
|
-
message: string;
|
|
15
|
-
messageArgs?: Record<string, unknown>;
|
|
16
|
-
category?: TErrorScope;
|
|
17
|
-
description?: string;
|
|
18
|
-
};
|
|
19
|
-
/**
|
|
20
|
-
* Augmented per-package via declaration merging, driving `messageCode` autocomplete.
|
|
21
|
-
*
|
|
22
|
-
* When nothing augments it - the framework compiling on its own - {@link TErrorKey} falls back to
|
|
23
|
-
* `string`, so a consumer that keeps no catalog is not forced to build one.
|
|
24
|
-
*/
|
|
25
|
-
export interface IErrorKeyRegistry {
|
|
26
|
-
}
|
|
27
|
-
export type TErrorKey = [keyof IErrorKeyRegistry] extends [never] ? string : Extract<keyof IErrorKeyRegistry, string>;
|
|
28
|
-
/**
|
|
29
|
-
* Registers a catalog's keys with {@link IErrorKeyRegistry}:
|
|
30
|
-
*
|
|
31
|
-
* ```ts
|
|
32
|
-
* declare module '@venizia/ignis-helpers' {
|
|
33
|
-
* interface IErrorKeyRegistry extends TRegisterErrors<typeof CategoryErrors> {}
|
|
34
|
-
* }
|
|
35
|
-
* ```
|
|
36
|
-
*
|
|
37
|
-
* The `extends Record<string, TErrorDefinition>` bound is load-bearing: without it TypeScript does
|
|
38
|
-
* not know every value of `T` carries a `key`, and `T[keyof T]['key']` fails to compile. It costs
|
|
39
|
-
* nothing in precision - `T` is still the type of an `as const` catalog, so the indexed access
|
|
40
|
-
* yields the union of literal keys rather than `string`.
|
|
41
|
-
*/
|
|
42
|
-
export type TRegisterErrors<T extends Record<string, TErrorDefinition>> = Record<T[keyof T]['key'], true>;
|
|
43
10
|
//# sourceMappingURL=definition.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../../../src/modules/error/definition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,qBAAa,WAAW;IACtB,MAAM,CAAC,QAAQ,CAAC,IAAI,UAAU;IAC9B,MAAM,CAAC,QAAQ,CAAC,UAAU,gBAAgB;IAC1C,MAAM,CAAC,QAAQ,CAAC,QAAQ,cAAc;IACtC,MAAM,CAAC,QAAQ,CAAC,MAAM,YAAY;IAClC,MAAM,CAAC,QAAQ,CAAC,WAAW,iBAAiB;CAC7C;AAED,MAAM,MAAM,WAAW,GAAG,WAAW,CAAC,OAAO,WAAW,CAAC,CAAC
|
|
1
|
+
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../../../src/modules/error/definition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,qBAAa,WAAW;IACtB,MAAM,CAAC,QAAQ,CAAC,IAAI,UAAU;IAC9B,MAAM,CAAC,QAAQ,CAAC,UAAU,gBAAgB;IAC1C,MAAM,CAAC,QAAQ,CAAC,QAAQ,cAAc;IACtC,MAAM,CAAC,QAAQ,CAAC,MAAM,YAAY;IAClC,MAAM,CAAC,QAAQ,CAAC,WAAW,iBAAiB;CAC7C;AAED,MAAM,MAAM,WAAW,GAAG,WAAW,CAAC,OAAO,WAAW,CAAC,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { TNullable } from '../../common/types';
|
|
1
2
|
export declare class MessageCode {
|
|
2
3
|
static readonly SEPARATOR = ".";
|
|
3
4
|
static readonly SEGMENT_PATTERN: RegExp;
|
|
@@ -10,9 +11,12 @@ export declare class MessageCode {
|
|
|
10
11
|
static build(opts: {
|
|
11
12
|
parts: Array<string>;
|
|
12
13
|
}): string;
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
/**
|
|
15
|
+
* True when `code` is well-formed. A guard for a code arriving from outside, so it takes
|
|
16
|
+
* `unknown`: one that throws on the very input it exists to screen is not a guard.
|
|
17
|
+
*/
|
|
18
|
+
static isValid(code: unknown): boolean;
|
|
19
|
+
/** Normalizes an absent, empty or non-string code to {@link DEFAULT}. */
|
|
20
|
+
static resolve(code?: TNullable<string>): string;
|
|
17
21
|
}
|
|
18
22
|
//# sourceMappingURL=message-code.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-code.d.ts","sourceRoot":"","sources":["../../../../src/modules/error/message-code.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"message-code.d.ts","sourceRoot":"","sources":["../../../../src/modules/error/message-code.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhD,qBAAa,WAAW;IACtB,MAAM,CAAC,QAAQ,CAAC,SAAS,OAAO;IAChC,MAAM,CAAC,QAAQ,CAAC,eAAe,SAA8B;IAC7D,MAAM,CAAC,QAAQ,CAAC,YAAY,KAAK;IACjC,MAAM,CAAC,QAAQ,CAAC,OAAO,uBAAuB;IAE9C;;;OAGG;IACH,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;KAAE,GAAG,MAAM;IAsBpD;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO;IAatC,yEAAyE;IACzE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,MAAM;CAKjD"}
|
|
@@ -26,15 +26,23 @@ export class MessageCode {
|
|
|
26
26
|
}
|
|
27
27
|
return parts.join(this.SEPARATOR).toLowerCase();
|
|
28
28
|
}
|
|
29
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* True when `code` is well-formed. A guard for a code arriving from outside, so it takes
|
|
31
|
+
* `unknown`: one that throws on the very input it exists to screen is not a guard.
|
|
32
|
+
*/
|
|
30
33
|
static isValid(code) {
|
|
34
|
+
if (typeof code !== 'string') {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
31
37
|
const segments = code.split(this.SEPARATOR);
|
|
32
38
|
return (segments.length >= this.MIN_SEGMENTS &&
|
|
33
39
|
segments.every(segment => this.SEGMENT_PATTERN.test(segment)));
|
|
34
40
|
}
|
|
35
|
-
/** Normalizes an absent or
|
|
41
|
+
/** Normalizes an absent, empty or non-string code to {@link DEFAULT}. */
|
|
36
42
|
static resolve(code) {
|
|
37
|
-
return code
|
|
43
|
+
return typeof code === 'string' && code.length
|
|
44
|
+
? code.toLowerCase()
|
|
45
|
+
: this.DEFAULT.toLowerCase();
|
|
38
46
|
}
|
|
39
47
|
}
|
|
40
48
|
//# sourceMappingURL=message-code.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-code.js","sourceRoot":"","sources":["../../../../src/modules/error/message-code.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"message-code.js","sourceRoot":"","sources":["../../../../src/modules/error/message-code.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,MAAM,OAAO,WAAW;aACN,cAAS,GAAG,GAAG,CAAC;aAChB,oBAAe,GAAG,0BAA0B,CAAC;aAC7C,iBAAY,GAAG,CAAC,CAAC;aACjB,YAAO,GAAG,mBAAmB,CAAC;IAE9C;;;OAGG;IACH,MAAM,CAAC,KAAK,CAAC,IAA8B;QACzC,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;QAEvB,IAAI,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;YACrC,MAAM,QAAQ,CAAC;gBACb,WAAW,EAAE,yCAAyC;gBACtD,OAAO,EAAE,8CAA8C,IAAI,CAAC,YAAY,yCAAyC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE;aACzI,CAAC,CAAC;QACL,CAAC;QAED,KAAK,MAAM,OAAO,IAAI,KAAK,EAAE,CAAC;YAC5B,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBACxC,MAAM,QAAQ,CAAC;oBACb,WAAW,EAAE,0CAA0C;oBACvD,OAAO,EAAE,yCAAyC,OAAO,yDAAyD,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE;iBAC1I,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;IAClD,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,IAAa;QAC1B,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7B,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAE5C,OAAO,CACL,QAAQ,CAAC,MAAM,IAAI,IAAI,CAAC,YAAY;YACpC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAC9D,CAAC;IACJ,CAAC;IAED,yEAAyE;IACzE,MAAM,CAAC,OAAO,CAAC,IAAwB;QACrC,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM;YAC5C,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE;YACpB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IACjC,CAAC"}
|
|
@@ -1,18 +1,49 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
/**
|
|
1
|
+
import type { TErrorScope } from './definition';
|
|
2
|
+
/**
|
|
3
|
+
* The RESOLVED message a client renders: `translate(code, args)`. Every field is always present -
|
|
4
|
+
* the constructor defaults `code` to {@link MessageCode.DEFAULT} and `args` to `{}` - so no consumer
|
|
5
|
+
* has to null-check what it reads.
|
|
6
|
+
*/
|
|
3
7
|
export type TErrorNormalized = {
|
|
4
8
|
text: string;
|
|
5
9
|
code: string;
|
|
6
10
|
args: Record<string, unknown>;
|
|
7
11
|
};
|
|
8
12
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* wrote, `text` is what a client shows.
|
|
13
|
+
* The message a CALLER supplies. Only `text` is required; the rest is what {@link TErrorNormalized}
|
|
14
|
+
* resolves. Every other message shape below is derived from this one.
|
|
12
15
|
*/
|
|
16
|
+
export type TErrorMessageInput = {
|
|
17
|
+
text: string;
|
|
18
|
+
code?: TErrorKey | (string & Record<never, never>);
|
|
19
|
+
args?: Record<string, unknown>;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* A catalogued message - a `code` is the whole reason the catalog exists, so it is required here.
|
|
23
|
+
*
|
|
24
|
+
* `code` is a plain `string`, NOT {@link TErrorKey}: a catalog DECLARES the keys the registry is
|
|
25
|
+
* built from, so typing it against that registry would make `IErrorKeyRegistry` define itself.
|
|
26
|
+
*/
|
|
27
|
+
export type TErrorDefinitionMessage = Omit<TErrorMessageInput, 'code'> & {
|
|
28
|
+
code: string;
|
|
29
|
+
};
|
|
30
|
+
/** The free-form input: a bare string is the historical shape. */
|
|
31
|
+
export type TErrorMessage = string | TErrorMessageInput;
|
|
32
|
+
/** The catalogued form's override - every field optional, since the definition supplies the rest. */
|
|
33
|
+
export type TErrorMessageOverride = string | Partial<TErrorMessageInput>;
|
|
34
|
+
export type TErrorDefinition = {
|
|
35
|
+
message: TErrorDefinitionMessage;
|
|
36
|
+
statusCode: number;
|
|
37
|
+
category?: TErrorScope;
|
|
38
|
+
description?: string;
|
|
39
|
+
};
|
|
40
|
+
/** Augmented per-package via declaration merging, driving `messageCode` autocomplete. */
|
|
41
|
+
export interface IErrorKeyRegistry {
|
|
42
|
+
}
|
|
43
|
+
export type TErrorKey = [keyof IErrorKeyRegistry] extends [never] ? string : Extract<keyof IErrorKeyRegistry, string>;
|
|
44
|
+
/** Builds {@link TErrorNormalized} in place of the default; `message` is the default it replaces. */
|
|
13
45
|
export type TErrorNormalizeTransformFn = (opts: {
|
|
14
|
-
message:
|
|
15
|
-
messageCode: string;
|
|
46
|
+
message: TErrorNormalized;
|
|
16
47
|
statusCode: number;
|
|
17
48
|
extra?: Record<string, unknown>;
|
|
18
49
|
}) => TErrorNormalized;
|
|
@@ -23,16 +54,17 @@ export type TErrorNormalizeTransformFn = (opts: {
|
|
|
23
54
|
type TErrorCommon = {
|
|
24
55
|
statusCode?: number;
|
|
25
56
|
messageArgs?: Record<string, unknown>;
|
|
26
|
-
/** The wrapped failure. Reaches the native `Error.cause`. */
|
|
27
57
|
cause?: unknown;
|
|
28
|
-
/** Explicit context. Merges with whatever the index signature swept in. */
|
|
29
58
|
extra?: Record<string, unknown>;
|
|
30
59
|
transform?: TErrorNormalizeTransformFn;
|
|
31
60
|
};
|
|
32
|
-
/**
|
|
61
|
+
/**
|
|
62
|
+
* Catalogued form. `message` and `statusCode` override the definition's defaults; the object form is
|
|
63
|
+
* partial, so `{ message: { args } }` amends the args and keeps the definition's text and code.
|
|
64
|
+
*/
|
|
33
65
|
export type TErrorByDefinition = TErrorCommon & {
|
|
34
66
|
error: TErrorDefinition;
|
|
35
|
-
message?:
|
|
67
|
+
message?: TErrorMessageOverride;
|
|
36
68
|
[key: string]: unknown;
|
|
37
69
|
};
|
|
38
70
|
/**
|
|
@@ -40,10 +72,26 @@ export type TErrorByDefinition = TErrorCommon & {
|
|
|
40
72
|
* only required field - most throw sites legitimately fall back to `MessageCode.DEFAULT`.
|
|
41
73
|
*/
|
|
42
74
|
export type TErrorByField = TErrorCommon & {
|
|
43
|
-
message:
|
|
75
|
+
message: TErrorMessage;
|
|
44
76
|
messageCode?: TErrorKey | (string & Record<never, never>);
|
|
77
|
+
/**
|
|
78
|
+
* Never valid here - `error` is the catalogued form's discriminant. Without this the index
|
|
79
|
+
* signature accepts `{ message, error: caughtError }`, a natural way to write "wrap this", and
|
|
80
|
+
* `error` is a CONSUMED key: the wrapped failure would vanish. Use `cause`.
|
|
81
|
+
*/
|
|
82
|
+
error?: never;
|
|
45
83
|
[key: string]: unknown;
|
|
46
84
|
};
|
|
47
85
|
export type TError = TErrorByDefinition | TErrorByField;
|
|
86
|
+
/**
|
|
87
|
+
* Registers a catalog's keys with {@link IErrorKeyRegistry}:
|
|
88
|
+
*
|
|
89
|
+
* ```ts
|
|
90
|
+
* declare module '@venizia/ignis-helpers' {
|
|
91
|
+
* interface IErrorKeyRegistry extends TRegisterErrors<typeof CategoryErrors> {}
|
|
92
|
+
* }
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
export type TRegisterErrors<T extends Record<string, TErrorDefinition>> = Record<T[keyof T]['message']['code'], true>;
|
|
48
96
|
export {};
|
|
49
97
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/modules/error/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/modules/error/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@venizia/ignis-inversion",
|
|
3
|
-
"version": "0.1.1-
|
|
3
|
+
"version": "0.1.1-1",
|
|
4
4
|
"description": "Lightweight, high-performance Dependency Injection and Inversion of Control container for TypeScript (~350 lines). Features decorator-based constructor and property injection, fluent Binding API, singleton/transient scoping, namespace auto-tagging, Provider pattern, tag-based discovery, and reflect-metadata integration. Inspired by LoopBack 4 and InversifyJS but simpler. Zero framework lock-in — works standalone or with Ignis.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"architecture",
|