@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.
@@ -1,7 +1,6 @@
1
1
  import type { TError, TErrorNormalized } from './types';
2
2
  export declare class ApplicationError extends Error {
3
3
  statusCode: number;
4
- messageCode: string;
5
4
  normalized: TErrorNormalized;
6
5
  extra?: Record<string, unknown>;
7
6
  constructor(opts: TError);
@@ -1 +1 @@
1
- {"version":3,"file":"app-error.d.ts","sourceRoot":"","sources":["../../../../src/modules/error/app-error.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAexD,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,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,gBAEvC,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,gBAE5D,CAAC"}
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
- /** Keys the constructor consumes. Everything else is context and rides into `extra`. */
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
- // The index signature makes `'error' in opts` useless for narrowing - every key exists on both
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 message = opts.message ?? definition?.message ?? '';
28
- const messageCode = definition?.key ?? opts.messageCode;
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
- this.messageCode = message_code_1.MessageCode.resolve(messageCode);
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
- message,
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;AAI7C,wFAAwF;AACxF,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;IAMzC,YAAY,IAAY;QACtB,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;QAElE,+FAA+F;QAC/F,+CAA+C;QAC/C,MAAM,UAAU,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAiC,CAAC;QAC9F,MAAM,OAAO,GAAI,IAAI,CAAC,OAA8B,IAAI,UAAU,EAAE,OAAO,IAAI,EAAE,CAAC;QAClF,MAAM,WAAW,GAAG,UAAU,EAAE,GAAG,IAAK,IAAI,CAAC,WAAkC,CAAC;QAEhF,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;QAC9D,IAAI,CAAC,WAAW,GAAG,0BAAW,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAEpD,MAAM,IAAI,GAAG,WAAW,IAAI,UAAU,EAAE,WAAW,CAAC;QAEpD,4FAA4F;QAC5F,yDAAyD;QACzD,MAAM,MAAM,GAAG;YACb,GAAG,IAAA,cAAI,EAAC,IAAI,EAAE,UAAU,CAAC;YACzB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACtC,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,IAAI,CAAC,UAAU,GAAG,SAAS;YACzB,CAAC,CAAC,SAAS,CAAC;gBACR,OAAO;gBACP,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,KAAK,EAAE,IAAI,CAAC,KAAK;aAClB,CAAC;YACJ,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;IAClE,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,IAAY;QAC1B,OAAO,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;CACF;AA5CD,4CA4CC;AAEM,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAoB,EAAE;IACzD,OAAO,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC,CAAC;AAFW,QAAA,QAAQ,YAEnB;AAEK,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"}
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;AAE1D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,2EAA2E;IAC3E,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;CAAG;AAErC,MAAM,MAAM,SAAS,GAAG,CAAC,MAAM,iBAAiB,CAAC,SAAS,CAAC,KAAK,CAAC,GAC7D,MAAM,GACN,OAAO,CAAC,MAAM,iBAAiB,EAAE,MAAM,CAAC,CAAC;AAE7C;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,IAAI,MAAM,CAC9E,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EACjB,IAAI,CACL,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
- /** True when `code` is well-formed. Cheap guard for a code that arrives from outside. */
14
- static isValid(code: string): boolean;
15
- /** Normalizes an absent or empty code to {@link DEFAULT} - an empty string is not a code. */
16
- static resolve(code?: string): string;
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":"AAEA,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,yFAAyF;IACzF,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IASrC,6FAA6F;IAC7F,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM;CAGtC"}
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
- /** True when `code` is well-formed. Cheap guard for a code that arrives from outside. */
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 empty code to {@link DEFAULT} - an empty string is not a code. */
44
+ /** Normalizes an absent, empty or non-string code to {@link DEFAULT}. */
39
45
  static resolve(code) {
40
- return code?.length ? code.toLowerCase() : this.DEFAULT.toLowerCase();
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":";;;AAAA,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,yFAAyF;IACzF,MAAM,CAAC,OAAO,CAAC,IAAY;QACzB,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,6FAA6F;IAC7F,MAAM,CAAC,OAAO,CAAC,IAAa;QAC1B,OAAO,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IACxE,CAAC;;AA7CH,kCA8CC"}
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 { TErrorDefinition, TErrorKey } from './definition';
2
- /** The client-facing message: `translate(normalized.code, normalized.args)`. */
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
- * Builds {@link TErrorNormalized} in place of the default. Receives a flat snapshot, never the
10
- * half-built instance. Its `text` may differ from `message`: `message` is what the throw site
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: string;
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
- /** Catalogued form. `message` and `statusCode` override the definition's defaults. */
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?: string;
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: string;
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,gBAAgB,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEhE,gFAAgF;AAChF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,0BAA0B,GAAG,CAAC,IAAI,EAAE;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC,KAAK,gBAAgB,CAAC;AAEvB;;;GAGG;AACH,KAAK,YAAY,GAAG;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,6DAA6D;IAC7D,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,SAAS,CAAC,EAAE,0BAA0B,CAAC;CACxC,CAAC;AAEF,sFAAsF;AACtF,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG;IAC9C,KAAK,EAAE,gBAAgB,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,SAAS,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IAC1D,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG,kBAAkB,GAAG,aAAa,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/modules/error/types.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,6 @@
1
1
  import type { TError, TErrorNormalized } from './types';
2
2
  export declare class ApplicationError extends Error {
3
3
  statusCode: number;
4
- messageCode: string;
5
4
  normalized: TErrorNormalized;
6
5
  extra?: Record<string, unknown>;
7
6
  constructor(opts: TError);
@@ -1 +1 @@
1
- {"version":3,"file":"app-error.d.ts","sourceRoot":"","sources":["../../../../src/modules/error/app-error.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAexD,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,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,gBAEvC,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,gBAE5D,CAAC"}
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
- /** Keys the constructor consumes. Everything else is context and rides into `extra`. */
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
- // The index signature makes `'error' in opts` useless for narrowing - every key exists on both
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 message = opts.message ?? definition?.message ?? '';
22
- const messageCode = definition?.key ?? opts.messageCode;
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
- this.messageCode = MessageCode.resolve(messageCode);
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
- message,
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;AAI7C,wFAAwF;AACxF,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;IAMzC,YAAY,IAAY;QACtB,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;QAElE,+FAA+F;QAC/F,+CAA+C;QAC/C,MAAM,UAAU,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAiC,CAAC;QAC9F,MAAM,OAAO,GAAI,IAAI,CAAC,OAA8B,IAAI,UAAU,EAAE,OAAO,IAAI,EAAE,CAAC;QAClF,MAAM,WAAW,GAAG,UAAU,EAAE,GAAG,IAAK,IAAI,CAAC,WAAkC,CAAC;QAEhF,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;QAC9D,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAEpD,MAAM,IAAI,GAAG,WAAW,IAAI,UAAU,EAAE,WAAW,CAAC;QAEpD,4FAA4F;QAC5F,yDAAyD;QACzD,MAAM,MAAM,GAAG;YACb,GAAG,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC;YACzB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACtC,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,IAAI,CAAC,UAAU,GAAG,SAAS;YACzB,CAAC,CAAC,SAAS,CAAC;gBACR,OAAO;gBACP,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,KAAK,EAAE,IAAI,CAAC,KAAK;aAClB,CAAC;YACJ,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;IAClE,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;IACzD,OAAO,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC,CAAC;AAEF,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"}
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;AAE1D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,2EAA2E;IAC3E,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;CAAG;AAErC,MAAM,MAAM,SAAS,GAAG,CAAC,MAAM,iBAAiB,CAAC,SAAS,CAAC,KAAK,CAAC,GAC7D,MAAM,GACN,OAAO,CAAC,MAAM,iBAAiB,EAAE,MAAM,CAAC,CAAC;AAE7C;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,IAAI,MAAM,CAC9E,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EACjB,IAAI,CACL,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
- /** True when `code` is well-formed. Cheap guard for a code that arrives from outside. */
14
- static isValid(code: string): boolean;
15
- /** Normalizes an absent or empty code to {@link DEFAULT} - an empty string is not a code. */
16
- static resolve(code?: string): string;
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":"AAEA,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,yFAAyF;IACzF,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IASrC,6FAA6F;IAC7F,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM;CAGtC"}
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
- /** True when `code` is well-formed. Cheap guard for a code that arrives from outside. */
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 empty code to {@link DEFAULT} - an empty string is not a code. */
41
+ /** Normalizes an absent, empty or non-string code to {@link DEFAULT}. */
36
42
  static resolve(code) {
37
- return code?.length ? code.toLowerCase() : this.DEFAULT.toLowerCase();
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":"AAAA,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,yFAAyF;IACzF,MAAM,CAAC,OAAO,CAAC,IAAY;QACzB,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,6FAA6F;IAC7F,MAAM,CAAC,OAAO,CAAC,IAAa;QAC1B,OAAO,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IACxE,CAAC"}
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 { TErrorDefinition, TErrorKey } from './definition';
2
- /** The client-facing message: `translate(normalized.code, normalized.args)`. */
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
- * Builds {@link TErrorNormalized} in place of the default. Receives a flat snapshot, never the
10
- * half-built instance. Its `text` may differ from `message`: `message` is what the throw site
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: string;
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
- /** Catalogued form. `message` and `statusCode` override the definition's defaults. */
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?: string;
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: string;
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,gBAAgB,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEhE,gFAAgF;AAChF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,0BAA0B,GAAG,CAAC,IAAI,EAAE;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC,KAAK,gBAAgB,CAAC;AAEvB;;;GAGG;AACH,KAAK,YAAY,GAAG;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,6DAA6D;IAC7D,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,SAAS,CAAC,EAAE,0BAA0B,CAAC;CACxC,CAAC;AAEF,sFAAsF;AACtF,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG;IAC9C,KAAK,EAAE,gBAAgB,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,SAAS,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IAC1D,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG,kBAAkB,GAAG,aAAa,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/modules/error/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,SAAS,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IACnD,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,kBAAkB,EAAE,MAAM,CAAC,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1F,kEAAkE;AAClE,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,kBAAkB,CAAC;AAExD,qGAAqG;AACrG,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAEzE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,uBAAuB,CAAC;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,yFAAyF;AACzF,MAAM,WAAW,iBAAiB;CAAG;AAErC,MAAM,MAAM,SAAS,GAAG,CAAC,MAAM,iBAAiB,CAAC,SAAS,CAAC,KAAK,CAAC,GAC7D,MAAM,GACN,OAAO,CAAC,MAAM,iBAAiB,EAAE,MAAM,CAAC,CAAC;AAE7C,qGAAqG;AACrG,MAAM,MAAM,0BAA0B,GAAG,CAAC,IAAI,EAAE;IAC9C,OAAO,EAAE,gBAAgB,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC,KAAK,gBAAgB,CAAC;AAEvB;;;GAGG;AACH,KAAK,YAAY,GAAG;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,SAAS,CAAC,EAAE,0BAA0B,CAAC;CACxC,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG;IAC9C,KAAK,EAAE,gBAAgB,CAAC;IACxB,OAAO,CAAC,EAAE,qBAAqB,CAAC;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG;IACzC,OAAO,EAAE,aAAa,CAAC;IACvB,WAAW,CAAC,EAAE,SAAS,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IAC1D;;;;OAIG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG,kBAAkB,GAAG,aAAa,CAAC;AAExD;;;;;;;;GAQG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,IAAI,MAAM,CAC9E,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,EAC7B,IAAI,CACL,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@venizia/ignis-inversion",
3
- "version": "0.1.1-0",
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",