@venizia/ignis-docs 0.2.0 → 0.2.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/README.md +14 -14
- package/content/best-practices/api-usage-examples.md +39 -19
- package/content/best-practices/architectural-patterns.md +24 -13
- package/content/best-practices/architecture-decisions.md +29 -16
- package/content/best-practices/code-style-standards/advanced-patterns.md +43 -31
- package/content/best-practices/code-style-standards/constants-configuration.md +19 -4
- package/content/best-practices/code-style-standards/control-flow.md +33 -1
- package/content/best-practices/code-style-standards/documentation.md +28 -8
- package/content/best-practices/code-style-standards/function-patterns.md +15 -4
- package/content/best-practices/code-style-standards/index.md +7 -2
- package/content/best-practices/code-style-standards/naming-conventions.md +27 -3
- package/content/best-practices/code-style-standards/route-definitions.md +9 -5
- package/content/best-practices/code-style-standards/tooling.md +14 -1
- package/content/best-practices/code-style-standards/type-safety.md +39 -6
- package/content/best-practices/common-pitfalls.md +59 -35
- package/content/best-practices/contribution-workflow.md +8 -4
- package/content/best-practices/data-modeling.md +78 -62
- package/content/best-practices/deployment-strategies.md +56 -19
- package/content/best-practices/error-handling.md +247 -153
- package/content/best-practices/index.md +6 -0
- package/content/best-practices/performance-optimization.md +26 -13
- package/content/best-practices/security-guidelines.md +35 -9
- package/content/best-practices/testing-strategies.md +7 -2
- package/content/best-practices/troubleshooting-tips.md +27 -17
- package/content/extensions/components/api-reference.md +109 -323
- package/content/extensions/components/authentication/api.md +489 -602
- package/content/extensions/components/authentication/errors.md +135 -498
- package/content/extensions/components/authentication/index.md +89 -801
- package/content/extensions/components/authentication/usage.md +231 -955
- package/content/extensions/components/authorization/api.md +991 -644
- package/content/extensions/components/authorization/errors.md +204 -208
- package/content/extensions/components/authorization/getting-started.md +227 -0
- package/content/extensions/components/authorization/index.md +88 -795
- package/content/extensions/components/authorization/usage.md +219 -528
- package/content/extensions/components/health-check.md +77 -243
- package/content/extensions/components/index.md +24 -90
- package/content/extensions/components/mail/api.md +553 -285
- package/content/extensions/components/mail/errors.md +76 -62
- package/content/extensions/components/mail/index.md +111 -463
- package/content/extensions/components/mail/usage.md +139 -173
- package/content/extensions/components/request-tracker.md +70 -173
- package/content/extensions/components/socket-io/api.md +462 -785
- package/content/extensions/components/socket-io/errors.md +49 -51
- package/content/extensions/components/socket-io/index.md +69 -372
- package/content/extensions/components/socket-io/usage.md +212 -105
- package/content/extensions/components/static-asset/api.md +461 -141
- package/content/extensions/components/static-asset/errors.md +121 -53
- package/content/extensions/components/static-asset/index.md +84 -606
- package/content/extensions/components/static-asset/usage.md +184 -299
- package/content/extensions/components/template/index.md +3 -3
- package/content/extensions/components/websocket/api.md +311 -404
- package/content/extensions/components/websocket/errors.md +47 -56
- package/content/extensions/components/websocket/index.md +75 -407
- package/content/extensions/components/websocket/usage.md +120 -338
- package/content/extensions/helpers/cron/index.md +52 -160
- package/content/extensions/helpers/crypto/index.md +67 -480
- package/content/extensions/helpers/crypto/reference.md +528 -0
- package/content/extensions/helpers/env/index.md +64 -178
- package/content/extensions/helpers/error/index.md +286 -196
- package/content/extensions/helpers/index.md +61 -47
- package/content/extensions/helpers/inversion/index.md +76 -550
- package/content/extensions/helpers/inversion/reference.md +530 -0
- package/content/extensions/helpers/kafka/admin.md +23 -3
- package/content/extensions/helpers/kafka/compile-binary.md +83 -52
- package/content/extensions/helpers/kafka/consumer.md +65 -28
- package/content/extensions/helpers/kafka/examples.md +46 -253
- package/content/extensions/helpers/kafka/index.md +55 -617
- package/content/extensions/helpers/kafka/producer.md +156 -22
- package/content/extensions/helpers/kafka/schema-registry.md +59 -79
- package/content/extensions/helpers/logger/hf-logger.md +220 -0
- package/content/extensions/helpers/logger/index.md +78 -552
- package/content/extensions/helpers/logger/pino.md +105 -0
- package/content/extensions/helpers/logger/reference.md +937 -0
- package/content/extensions/helpers/network/api.md +276 -195
- package/content/extensions/helpers/network/index.md +87 -524
- package/content/extensions/helpers/queue/index.md +80 -897
- package/content/extensions/helpers/queue/reference.md +494 -0
- package/content/extensions/helpers/redis/index.md +86 -640
- package/content/extensions/helpers/redis/reference.md +784 -0
- package/content/extensions/helpers/secrets/index.md +136 -0
- package/content/extensions/helpers/socket-io/api.md +325 -204
- package/content/extensions/helpers/socket-io/index.md +79 -429
- package/content/extensions/helpers/storage/api.md +584 -464
- package/content/extensions/helpers/storage/index.md +80 -573
- package/content/extensions/helpers/types/index.md +75 -495
- package/content/extensions/helpers/types/reference.md +689 -0
- package/content/extensions/helpers/uid/index.md +176 -189
- package/content/extensions/helpers/websocket/api.md +366 -214
- package/content/extensions/helpers/websocket/index.md +68 -503
- package/content/extensions/helpers/worker-thread/index.md +62 -396
- package/content/extensions/helpers/worker-thread/reference.md +428 -0
- package/content/extensions/index.md +38 -39
- package/content/extensions/src-details/mcp-server.md +96 -548
- package/content/guides/core-concepts/persistent/datasources.md +2 -2
- package/content/guides/core-concepts/persistent/index.md +5 -1
- package/content/guides/core-concepts/persistent/models.md +1 -1
- package/content/guides/core-concepts/persistent/pglite.md +218 -0
- package/content/guides/core-concepts/persistent/postgres-drivers.md +21 -15
- package/content/guides/core-concepts/persistent/search-meilisearch.md +22 -12
- package/content/guides/core-concepts/persistent/search-typesense.md +28 -16
- package/content/guides/core-concepts/persistent/sqlite.md +296 -0
- package/content/guides/core-concepts/persistent/transactions.md +12 -11
- package/content/guides/core-concepts/secrets-vault.md +177 -0
- package/content/guides/core-concepts/services.md +1 -1
- package/content/guides/get-started/5-minute-quickstart.md +59 -206
- package/content/guides/get-started/philosophy.md +135 -670
- package/content/guides/get-started/setup.md +53 -74
- package/content/guides/migrations/redis-helpers-migration.md +5 -4
- package/content/guides/migrations/scoped-rbac-migration.md +5 -5
- package/content/guides/migrations/unified-connectors-migration.md +8 -7
- package/content/guides/tutorials/ecommerce-api.md +3 -8
- package/content/guides/tutorials/realtime-chat.md +1 -1
- package/content/references/base/application.md +64 -22
- package/content/references/base/components.md +3 -3
- package/content/references/base/connectors.md +79 -136
- package/content/references/base/controllers.md +12 -12
- package/content/references/base/datasources-reference.md +600 -0
- package/content/references/base/datasources.md +84 -444
- package/content/references/base/dependency-injection.md +25 -46
- package/content/references/base/filter-system/application-usage.md +95 -123
- package/content/references/base/filter-system/array-operators.md +33 -43
- package/content/references/base/filter-system/comparison-operators.md +55 -63
- package/content/references/base/filter-system/default-filter.md +144 -350
- package/content/references/base/filter-system/fields-order-pagination.md +116 -148
- package/content/references/base/filter-system/index.md +114 -253
- package/content/references/base/filter-system/json-filtering.md +52 -181
- package/content/references/base/filter-system/list-operators.md +28 -44
- package/content/references/base/filter-system/logical-operators.md +69 -114
- package/content/references/base/filter-system/null-operators.md +41 -98
- package/content/references/base/filter-system/pattern-matching.md +48 -51
- package/content/references/base/filter-system/quick-reference.md +93 -196
- package/content/references/base/filter-system/range-operators.md +22 -38
- package/content/references/base/filter-system/tips.md +70 -133
- package/content/references/base/filter-system/use-cases.md +173 -232
- package/content/references/base/grpc-controllers.md +53 -17
- package/content/references/base/index.md +5 -3
- package/content/references/base/middlewares.md +43 -28
- package/content/references/base/models-reference.md +886 -0
- package/content/references/base/models.md +81 -1452
- package/content/references/base/providers.md +8 -8
- package/content/references/base/repositories/advanced.md +281 -419
- package/content/references/base/repositories/index.md +84 -644
- package/content/references/base/repositories/mixins.md +25 -21
- package/content/references/base/repositories/relations.md +194 -375
- package/content/references/base/repositories/soft-deletable.md +67 -55
- package/content/references/base/secrets.md +267 -0
- package/content/references/base/services.md +8 -6
- package/content/references/configuration/environment-variables.md +73 -21
- package/content/references/configuration/index.md +51 -31
- package/content/references/index.md +1 -1
- package/content/references/quick-reference.md +3 -16
- package/content/references/utilities/crypto.md +35 -76
- package/content/references/utilities/date.md +33 -73
- package/content/references/utilities/duration.md +85 -0
- package/content/references/utilities/index.md +6 -2
- package/content/references/utilities/jsx-reference.md +298 -0
- package/content/references/utilities/jsx.md +82 -525
- package/content/references/utilities/module.md +81 -61
- package/content/references/utilities/parse.md +34 -64
- package/content/references/utilities/performance.md +33 -58
- package/content/references/utilities/promise.md +28 -62
- package/content/references/utilities/request.md +58 -218
- package/content/references/utilities/retry.md +139 -0
- package/content/references/utilities/schema.md +43 -137
- package/content/references/utilities/statuses-reference.md +361 -0
- package/content/references/utilities/statuses.md +63 -667
- package/dist/mcp-server/index.js +0 -0
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.js +3 -3
- package/dist/mcp-server/tools/github/search-code.tool.js +1 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.js +1 -1
- package/dist/mcp-server/tools/github/view-source-file.tool.js +1 -1
- package/package.json +24 -23
|
@@ -1,27 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
---
|
|
2
|
+
title: Error
|
|
3
|
+
description: ApplicationError, the getError factory, and a catalog pattern for machine-readable error codes
|
|
4
|
+
difficulty: beginner
|
|
5
|
+
---
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|------|-------|
|
|
9
|
-
| **Package** | `@venizia/ignis-helpers` |
|
|
10
|
-
| **Class** | `ApplicationError` |
|
|
11
|
-
| **Extends** | `Error` (native) |
|
|
12
|
-
| **Runtimes** | Both |
|
|
13
|
-
|
|
14
|
-
#### Import Paths
|
|
15
|
-
|
|
16
|
-
```typescript
|
|
17
|
-
import { ApplicationError, getError, isApplicationError } from '@venizia/ignis-helpers';
|
|
18
|
-
import { ErrorSchema } from '@venizia/ignis-helpers';
|
|
19
|
-
import type { TError } from '@venizia/ignis-helpers';
|
|
20
|
-
```
|
|
7
|
+
# Error
|
|
21
8
|
|
|
22
|
-
|
|
9
|
+
`getError()` builds an `ApplicationError` carrying an HTTP status and a machine-readable code - the house rule is `getError`, never `new Error`.
|
|
23
10
|
|
|
24
|
-
|
|
11
|
+
## In one example
|
|
25
12
|
|
|
26
13
|
```typescript
|
|
27
14
|
import { getError, HTTP } from '@venizia/ignis-helpers';
|
|
@@ -33,70 +20,163 @@ throw getError({
|
|
|
33
20
|
});
|
|
34
21
|
```
|
|
35
22
|
|
|
36
|
-
|
|
23
|
+
The framework's `AppErrorMiddleware` catches `ApplicationError` instances and formats them into a consistent JSON response.
|
|
24
|
+
|
|
25
|
+
## Find what you need
|
|
26
|
+
|
|
27
|
+
| You want to | Go to |
|
|
28
|
+
|---|---|
|
|
29
|
+
| Throw a one-off error with a status code | [Throw a free-form error](#throw-a-free-form-error) |
|
|
30
|
+
| Re-throw an error you already caught and shaped | [Recognize an already-shaped error in a catch block](#recognize-an-already-shaped-error-in-a-catch-block) |
|
|
31
|
+
| Declare a reusable, i18n-ready error once | [Catalog a reusable error](#catalog-a-reusable-error) |
|
|
32
|
+
| Get autocomplete on `messageCode` | [Register catalog keys for messageCode autocomplete](#register-catalog-keys-for-messagecode-autocomplete) |
|
|
33
|
+
| Build a message code outside a catalog | [Build a code outside a catalog](#build-a-code-outside-a-catalog) |
|
|
34
|
+
| See the exact JSON shape a client receives | [Read the error response shape](#read-the-error-response-shape) |
|
|
35
|
+
| Read or rehydrate a server error in a browser app | [Consume the error response from a browser client](#consume-the-error-response-from-a-browser-client) |
|
|
36
|
+
| Look up what a specific input produces | [Every shape and its output](#every-shape-and-its-output) |
|
|
37
|
+
| Confirm you're checking errors the safe way | [How it works](#how-it-works) - `isApplicationError()`, never `instanceof` |
|
|
38
|
+
|
|
39
|
+
## How it works
|
|
40
|
+
|
|
41
|
+
- **Three equivalent entry points.** `getError(opts)`, `new ApplicationError(opts)`, and the static `ApplicationError.getError(opts)` all build the same object from the same input. Use the class form only when a direct reference reads better.
|
|
42
|
+
- **Two input shapes.** Free-form covers one-off failures - most throw sites. Catalogued raises a failure declared once at module scope, so its code, status, and default text can't drift across the call sites that raise it.
|
|
37
43
|
|
|
38
|
-
|
|
44
|
+
| Shape | Input |
|
|
45
|
+
|---|---|
|
|
46
|
+
| Free-form | `{ message, statusCode?, messageCode? }` |
|
|
47
|
+
| Catalogued | `{ error: TErrorDefinition }` |
|
|
39
48
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
49
|
+
- **One message shape everywhere.** `message` is either the historical string (with sibling `messageCode?`/`messageArgs?`), or an object mirroring `normalized`: `{ text, code?, args? }`. Both resolve to the same `normalized`:
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
getError({ message: 'Only %{n} left', messageCode: 'stock.low', messageArgs: { n: 2 } }); // flat
|
|
53
|
+
getError({ message: { text: 'Only %{n} left', code: 'stock.low', args: { n: 2 } } }); // nested
|
|
54
|
+
getError({ error: StockErrors.LOW, messageArgs: { n: 2 } }); // catalogued
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
On the catalogued form, `message` is a **partial** override. `{ message: { args } }` amends just the args and keeps the definition's `text`/`code`.
|
|
58
|
+
|
|
59
|
+
- **Precedence resolves most-specific-first.** See the [full precedence table](#every-shape-and-its-output) below - a definition's own `message.code` beats a flat `messageCode`.
|
|
60
|
+
- **`messageCode` always resolves to something.** `MessageCode.resolve()` lower-cases it and falls back to `MessageCode.DEFAULT` (`'core.system_error'`) when none is given or empty. `error.normalized.code` is never `undefined`.
|
|
61
|
+
- **`normalized` is the single source - there's no flat duplicate.** It's `{ text, code, args }`. `text` defaults to `message`; `code` and `args` resolve per the precedence table.
|
|
62
|
+
- **`args` is always populated, so no consumer needs a null check.** One lookup renders any error: `translate(error.normalized.code, error.normalized.args)`.
|
|
63
|
+
- **`messageCode` and `messageArgs` are INPUTS only.** There's no `error.messageCode` field, and `extra` never mirrors `messageArgs`. Pass `transform` to build `normalized` yourself in place of the default.
|
|
64
|
+
- **Any key the input doesn't declare rides into `extra`.** Attach whatever context your clients need: `getError({ message, transaction: {...} })` lands at `error.extra.transaction`. Passing `extra` explicitly works too - the two merge, and the explicit one wins on a clash.
|
|
65
|
+
- **`extra` carries caller context only.** It's `undefined` when there is nothing to carry.
|
|
66
|
+
- **`cause` reaches the native `Error.cause`, not `extra`.** Wrap a lower-level failure with `getError({ message, cause: originalError })`, and every tool that reads `.cause` sees it.
|
|
67
|
+
- **`error` is refused on the free-form branch (`error?: never`).** This makes `getError({ message, error: caughtError })` fail to compile, so the mistake is caught before runtime - use `cause` instead.
|
|
68
|
+
|
|
69
|
+
> [!IMPORTANT]
|
|
70
|
+
> **Use `isApplicationError()`, never `instanceof ApplicationError`.** There is one `ApplicationError` class, defined in `@venizia/ignis-inversion`. `helpers` re-exports it, so a browser app can raise and read the same errors the server does. But `instanceof` still fails across a package boundary: inversion ships dual CJS+ESM builds, so one source class has two runtime constructors. `isApplicationError()` tests shape, not identity, so it works everywhere.
|
|
71
|
+
|
|
72
|
+
**Options shared by both forms**
|
|
73
|
+
|
|
74
|
+
| Option | Type | Description |
|
|
75
|
+
| --------------- | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
|
|
76
|
+
| `message` | `string \| { text, code?, args? }` | Required on the free-form branch; a **partial** override on the catalogued branch (definition supplies what's omitted) |
|
|
77
|
+
| `messageCode` | `string` | Free-form only, sibling to a string `message`. Lowest precedence - `message.code` and the definition's `message.code` both win over it |
|
|
78
|
+
| `statusCode` | `number` | Defaults to `400`, or the definition's `statusCode` for the catalogued form |
|
|
79
|
+
| `messageArgs` | `Record<string, unknown>` | Interpolation values. Reaches `normalized.args` - never `extra`. Lowest precedence, same rule as `messageCode` |
|
|
80
|
+
| `cause` | `unknown` | The wrapped failure - reaches `Error.cause`. Use this to wrap a caught error; `error` is refused on the free-form branch for exactly this case |
|
|
81
|
+
| `extra` | `Record<string, unknown>` | Explicit context, merged with any swept keys - and it wins on a clash |
|
|
82
|
+
| `transform` | `TErrorNormalizeTransformFn` | Builds `normalized` in place of the default. Receives `{ message: TErrorNormalized, statusCode, extra? }` - `message` is the default normalized being replaced, so `s => ({ ...s.message, text: 'x' })` amends one field |
|
|
83
|
+
| `logLevel` | `error \| emerg \| warn \| info \| debug` | The level the error handler logs this at. Defaults to `error`; lower it for an expected failure (`getError({ message, statusCode: 404, logLevel: 'warn' })`), or raise it to `emerg`. Steers the server log only - never the response |
|
|
84
|
+
| _anything else_ | `unknown` | Rides into `extra` under its own name. `getError({ message, transaction })` lands at `error.extra.transaction` |
|
|
46
85
|
|
|
47
86
|
> [!TIP]
|
|
48
|
-
>
|
|
87
|
+
> Spreading a definition now resolves identically to passing it as `error`: `getError({ ...CategoryErrors.CREATE_DUPLICATE_NAME })` and `getError({ error: CategoryErrors.CREATE_DUPLICATE_NAME })` build the same `ApplicationError`. A definition's `message` is `{ text, code, args? }` - the same shape the free-form input accepts - so the spread degrades to nothing. Prefer `{ error: DEF }` anyway. It reads as "raise this catalogued error", not "raise these loose fields."
|
|
49
88
|
|
|
50
|
-
|
|
89
|
+
## Every shape and its output
|
|
51
90
|
|
|
52
|
-
|
|
91
|
+
Every row below is the real output, and the catalogued rows all use this definition:
|
|
53
92
|
|
|
54
93
|
```typescript
|
|
55
|
-
|
|
94
|
+
const DEF = {
|
|
95
|
+
message: {
|
|
96
|
+
text: 'A category named "%{name}" already exists.',
|
|
97
|
+
code: 'server.commerce.category.duplicate',
|
|
98
|
+
args: { name: '?' },
|
|
99
|
+
},
|
|
100
|
+
statusCode: 409,
|
|
101
|
+
} as const satisfies TErrorDefinition;
|
|
102
|
+
```
|
|
56
103
|
|
|
57
|
-
|
|
58
|
-
const error = new ApplicationError({
|
|
59
|
-
message: 'Configuration missing',
|
|
60
|
-
statusCode: HTTP.ResultCodes.RS_5.InternalServerError,
|
|
61
|
-
});
|
|
104
|
+
**Free-form, flat** - the historical shape, unchanged:
|
|
62
105
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
```
|
|
106
|
+
| Input | `message` | `statusCode` | `normalized` |
|
|
107
|
+
|-------|-----------|--------------|--------------|
|
|
108
|
+
| `{ message: 'Broke' }` | `Broke` | `400` | `{ text: 'Broke', code: 'core.system_error', args: {} }` |
|
|
109
|
+
| `{ message: 'Broke', messageCode: 'a.b' }` | `Broke` | `400` | `{ text: 'Broke', code: 'a.b', args: {} }` |
|
|
110
|
+
| `{ message: 'Only %{n} left', messageArgs: { n: 2 } }` | `Only %{n} left` | `400` | `{ text: 'Only %{n} left', code: 'core.system_error', args: { n: 2 } }` |
|
|
111
|
+
| `{ message, messageCode: 'stock.low', messageArgs: { n: 2 }, statusCode: 409 }` | `Only %{n} left` | `409` | `{ text: 'Only %{n} left', code: 'stock.low', args: { n: 2 } }` |
|
|
70
112
|
|
|
71
|
-
|
|
113
|
+
**Free-form, object** - `text` is the only required field. Each row is identical to its flat twin above:
|
|
72
114
|
|
|
73
|
-
|
|
115
|
+
| Input | `normalized` |
|
|
116
|
+
|-------|--------------|
|
|
117
|
+
| `{ message: { text: 'Broke' } }` | `{ text: 'Broke', code: 'core.system_error', args: {} }` |
|
|
118
|
+
| `{ message: { text: 'Broke', code: 'a.b' } }` | `{ text: 'Broke', code: 'a.b', args: {} }` |
|
|
119
|
+
| `{ message: { text: 'Only %{n} left', code: 'stock.low', args: { n: 2 } } }` | `{ text: 'Only %{n} left', code: 'stock.low', args: { n: 2 } }` |
|
|
74
120
|
|
|
75
|
-
|
|
76
|
-
import { MessageCode } from '@venizia/ignis-helpers';
|
|
121
|
+
**Catalogued** - omit a field and the definition supplies it:
|
|
77
122
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
123
|
+
| Input | `message` | `statusCode` | `normalized.code` | `normalized.args` |
|
|
124
|
+
|-------|-----------|--------------|-------------------|-------------------|
|
|
125
|
+
| `{ error: DEF }` | the definition's text | `409` | `server.commerce.category.duplicate` | `{ name: '?' }` |
|
|
126
|
+
| `{ error: DEF, messageArgs: { name: 'Vé' } }` | the definition's text | `409` | `server.commerce.category.duplicate` | `{ name: 'Vé' }` |
|
|
127
|
+
| `{ error: DEF, message: { args: { name: 'Vé' } } }` | the definition's text | `409` | `server.commerce.category.duplicate` | `{ name: 'Vé' }` |
|
|
128
|
+
| `{ error: DEF, message: { text: 'Custom' } }` | `Custom` | `409` | `server.commerce.category.duplicate` | `{ name: '?' }` |
|
|
129
|
+
| `{ error: DEF, message: { code: 'override.code' } }` | the definition's text | `409` | `override.code` | `{ name: '?' }` |
|
|
130
|
+
| `{ error: DEF, message: 'Custom' }` | `Custom` | `409` | `server.commerce.category.duplicate` | `{ name: '?' }` |
|
|
131
|
+
| `{ error: DEF, statusCode: 410 }` | the definition's text | `410` | `server.commerce.category.duplicate` | `{ name: '?' }` |
|
|
132
|
+
| `{ ...DEF }` (spread) | the definition's text | `409` | `server.commerce.category.duplicate` | `{ name: '?' }` |
|
|
133
|
+
|
|
134
|
+
**Context and cause:**
|
|
135
|
+
|
|
136
|
+
| Input | Output |
|
|
137
|
+
|-------|--------|
|
|
138
|
+
| `{ message, extra: { categoryId: 42 } }` | `extra: { categoryId: 42 }` |
|
|
139
|
+
| `{ message, userId: 7, transaction: { id: 12 } }` | `extra: { userId: 7, transaction: { id: 12 } }` - swept |
|
|
140
|
+
| `{ message, userId: 7, extra: { userId: 9 } }` | `extra: { userId: 9 }` - explicit wins |
|
|
141
|
+
| `{ message, cause: err }` | `Error.cause = err`; `extra` stays `undefined` |
|
|
142
|
+
| `{ message, error: caughtError }` | **does not compile** - use `cause` |
|
|
143
|
+
|
|
144
|
+
**Transform** - `message` in the snapshot IS the default being replaced:
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
getError({
|
|
148
|
+
message: { text: 'Only %{n} left', code: 'stock.low', args: { n: 2 } },
|
|
149
|
+
transform: snapshot => ({ ...snapshot.message, text: 'Chỉ còn 2 vé.' }),
|
|
150
|
+
});
|
|
151
|
+
// error.message -> 'Only %{n} left' (the raw text stays)
|
|
152
|
+
// error.normalized.text -> 'Chỉ còn 2 vé.'
|
|
153
|
+
// error.normalized.code -> 'stock.low'
|
|
154
|
+
// error.normalized.args -> { n: 2 }
|
|
82
155
|
```
|
|
83
156
|
|
|
84
|
-
|
|
85
|
-
|--------|------|--------------------|-------------|
|
|
86
|
-
| `DEFAULT` | `string` | `'core.system_error'` | The code `ApplicationError` falls back to when no `messageCode` is supplied |
|
|
87
|
-
| `SEPARATOR` | `string` | `'.'` | Joins segments into a dotted code (e.g. `core.mail.send_failed`) |
|
|
88
|
-
| `SEGMENT_PATTERN` | `RegExp` | `/^[a-z0-9]+(_[a-z0-9]+)*$/` | Each segment must be lower snake_case -- `a-z`, `0-9`, `_` |
|
|
89
|
-
| `MIN_SEGMENTS` | `number` | `2` | A code needs at least a namespace and a reason (e.g. `core.not_found` is valid, `not_found` alone is not) |
|
|
90
|
-
| `build(opts: { parts: Array<string> })` | `string` | -- | Joins `parts` with `SEPARATOR` and lower-cases the result. Throws (via `getError`) if `parts.length < MIN_SEGMENTS`, or if any segment fails `SEGMENT_PATTERN` |
|
|
91
|
-
| `isValid(code: string)` | `boolean` | -- | Cheap structural check for a code arriving from outside the process |
|
|
92
|
-
| `resolve(code?: string)` | `string` | -- | Normalizes an absent or empty code to `DEFAULT`; otherwise lower-cases `code` |
|
|
157
|
+
**Precedence,** most specific first - note a definition's `message.code` beats a flat `messageCode`:
|
|
93
158
|
|
|
94
|
-
|
|
95
|
-
|
|
159
|
+
| Resolves | Order |
|
|
160
|
+
|----------|-------|
|
|
161
|
+
| `normalized.code` | `message.code` -> the definition's `message.code` -> `messageCode` -> `MessageCode.DEFAULT` |
|
|
162
|
+
| `normalized.args` | `message.args` -> `messageArgs` -> the definition's `message.args` -> `{}` |
|
|
163
|
+
| `normalized.text` | `message.text` (or a string `message`) -> the definition's `message.text` -> `''` |
|
|
164
|
+
| `statusCode` | `statusCode` -> the definition's `statusCode` -> `400` |
|
|
165
|
+
|
|
166
|
+
## Common tasks
|
|
96
167
|
|
|
97
|
-
|
|
168
|
+
### Throw a free-form error
|
|
98
169
|
|
|
99
|
-
|
|
170
|
+
The most common shape - a `message` and a status.
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
throw getError({
|
|
174
|
+
statusCode: HTTP.ResultCodes.RS_4.Conflict,
|
|
175
|
+
message: 'Username already exists',
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Recognize an already-shaped error in a catch block
|
|
100
180
|
|
|
101
181
|
```typescript
|
|
102
182
|
import { isApplicationError } from '@venizia/ignis-helpers';
|
|
@@ -105,179 +185,189 @@ try {
|
|
|
105
185
|
await someOperation();
|
|
106
186
|
} catch (error) {
|
|
107
187
|
if (isApplicationError(error)) {
|
|
108
|
-
// already shaped
|
|
109
|
-
throw error;
|
|
188
|
+
throw error; // already shaped - surface as-is
|
|
110
189
|
}
|
|
111
|
-
|
|
112
|
-
|
|
190
|
+
throw getError({
|
|
191
|
+
message: 'Operation failed',
|
|
192
|
+
statusCode: HTTP.ResultCodes.RS_5.InternalServerError,
|
|
193
|
+
});
|
|
113
194
|
}
|
|
114
195
|
```
|
|
115
196
|
|
|
116
|
-
|
|
117
|
-
> Never compare `ApplicationError` with `instanceof` across a package boundary. `inversion` ships **dual CJS + ESM** builds (its DI powers frontend libraries), so its error class deliberately has more than one runtime identity, and `helpers` keeps its own `ApplicationError` for the backend stack. Two objects that are both "an application error" can be instances of different classes, so `instanceof` gives false negatives. `isApplicationError` checks the shape and works regardless of which package threw. The search connectors use it to decide what is already shaped versus what must be sanitized as a `503`.
|
|
118
|
-
|
|
119
|
-
## Usage
|
|
120
|
-
|
|
121
|
-
### Throwing Errors in Services
|
|
197
|
+
### Catalog a reusable error
|
|
122
198
|
|
|
123
|
-
|
|
199
|
+
Declare it once; every call site raises it by reference instead of retyping the code and status.
|
|
124
200
|
|
|
125
201
|
```typescript
|
|
126
|
-
import { getError, HTTP } from '@venizia/ignis-helpers';
|
|
202
|
+
import { ErrorScopes, getError, HTTP } from '@venizia/ignis-helpers';
|
|
203
|
+
import type { TErrorDefinition } from '@venizia/ignis-helpers';
|
|
204
|
+
|
|
205
|
+
const CategoryErrors = {
|
|
206
|
+
CREATE_DUPLICATE_NAME: {
|
|
207
|
+
message: {
|
|
208
|
+
text: 'A category named "%{name}" already exists.',
|
|
209
|
+
code: 'server.commerce.category.create.duplicate_name',
|
|
210
|
+
},
|
|
211
|
+
statusCode: HTTP.ResultCodes.RS_4.Conflict,
|
|
212
|
+
category: ErrorScopes.VALIDATION,
|
|
213
|
+
},
|
|
214
|
+
} as const satisfies Record<string, TErrorDefinition>;
|
|
127
215
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
if (existingUser) {
|
|
132
|
-
throw getError({
|
|
133
|
-
statusCode: HTTP.ResultCodes.RS_4.Conflict,
|
|
134
|
-
message: 'Username already exists',
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
// ...
|
|
138
|
-
}
|
|
139
|
-
}
|
|
216
|
+
throw getError({ error: CategoryErrors.CREATE_DUPLICATE_NAME, messageArgs: { name: 'Vé' } });
|
|
217
|
+
// Equivalent, using the catalogued form's partial override instead:
|
|
218
|
+
throw getError({ error: CategoryErrors.CREATE_DUPLICATE_NAME, message: { args: { name: 'Vé' } } });
|
|
140
219
|
```
|
|
141
220
|
|
|
142
|
-
|
|
221
|
+
`ErrorScopes` groups a failure by intent - `AUTH`, `VALIDATION`, `BUSINESS`, `SYSTEM`, `INTEGRATION`. `statusCode` can't do this job: a `409` is a business conflict in one place and a validation clash in another.
|
|
143
222
|
|
|
144
|
-
|
|
223
|
+
> [!WARNING]
|
|
224
|
+
> `category` is catalog **metadata only** - it does not reach the error response. `getError` reads `message.text`, `message.code` and `statusCode` off a definition and ignores the rest. Use it to group and filter catalogs (ops dashboards, translator exports). Don't expect a client to receive it.
|
|
225
|
+
|
|
226
|
+
### Register catalog keys for `messageCode` autocomplete
|
|
227
|
+
|
|
228
|
+
Augment the module the file already imports from. `IErrorKeyRegistry` is declared in `@venizia/ignis-inversion` and re-exported by `helpers`. Merging follows the re-export, so either name populates the same registry.
|
|
145
229
|
|
|
146
230
|
```typescript
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
231
|
+
import type { TRegisterErrors } from '@venizia/ignis-helpers';
|
|
232
|
+
|
|
233
|
+
declare module '@venizia/ignis-helpers' {
|
|
234
|
+
interface IErrorKeyRegistry extends TRegisterErrors<typeof CategoryErrors> {}
|
|
235
|
+
}
|
|
152
236
|
```
|
|
153
237
|
|
|
154
|
-
|
|
238
|
+
> [!WARNING]
|
|
239
|
+
> TypeScript only treats `declare module` as an **augmentation** when the file imports that module. Name a module the file never imports and it silently becomes an inert ambient declaration - no error, no keys registered, autocomplete quietly empty.
|
|
155
240
|
|
|
156
|
-
|
|
241
|
+
Declare `message.code` as a literal string, not through `MessageCode.build()` - `build()` returns `string`, which would widen the registry to `Record<string, true>` and destroy the autocomplete.
|
|
157
242
|
|
|
158
|
-
|
|
243
|
+
### Build a code outside a catalog
|
|
159
244
|
|
|
160
|
-
|
|
245
|
+
`MessageCode.build()` validates at import time instead of shipping a malformed code into production.
|
|
161
246
|
|
|
162
|
-
|
|
247
|
+
```typescript
|
|
248
|
+
import { MessageCode } from '@venizia/ignis-helpers';
|
|
163
249
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
"message": "User not found",
|
|
167
|
-
"messageCode": "core.user.not_found",
|
|
168
|
-
"statusCode": 404,
|
|
169
|
-
"requestId": "abc-123-def",
|
|
170
|
-
"details": {
|
|
171
|
-
"url": "http://localhost:3000/api/users/123",
|
|
172
|
-
"path": "/api/users/123"
|
|
173
|
-
}
|
|
174
|
-
}
|
|
250
|
+
const NOT_FOUND = MessageCode.build({ parts: ['core', 'user', 'not_found'] });
|
|
251
|
+
// 'core.user.not_found' - throws if a segment isn't lower snake_case, or fewer than 2 parts
|
|
175
252
|
```
|
|
176
253
|
|
|
177
|
-
|
|
254
|
+
### Read the error response shape
|
|
255
|
+
|
|
256
|
+
`AppErrorMiddleware` (from `@venizia/ignis`) routes every thrown value into one of five shapes. All five carry `message`, `statusCode`, `normalized` and `details`. Only an intentional error can carry `extra`. The code lives at `normalized.code` - there is no flat `messageCode` on the response.
|
|
257
|
+
|
|
258
|
+
| What was thrown | Status | `normalized.code` | `message` | `extra` |
|
|
259
|
+
| ----------------------------------------- | ------- | ------------------------------------------------------ | --------------------------------------------------------------------- | ----------------------------------------------------- |
|
|
260
|
+
| `ZodError` (validation) | 422 | the first issue's `params.code`, else its raw Zod code | that issue's message; per-field list in `details.cause` | never |
|
|
261
|
+
| DB client error (SQLSTATE class 22/23/44) | 400 | `core.system_error` | a fixed, safe summary - never the driver's text | never |
|
|
262
|
+
| Transient DB conflict (40001/40P01) | 409 | `database.conflict` | a fixed retry message | never |
|
|
263
|
+
| `getError(...)` - intentional | its own | its own | its own | when the throw site attached `extra` or unknown keys |
|
|
264
|
+
| Anything else | 500 | `core.system_error` | `Internal Server Error` in production; the raw message in development | never |
|
|
265
|
+
|
|
266
|
+
Only the intentional branch reports what the throw site wrote. The other four **replace** the message - a driver error can carry SQL, schema, and constraint names. `normalized` is built from that replacement, so it can never leak what `message` just scrubbed.
|
|
178
267
|
|
|
179
|
-
|
|
268
|
+
`rootKey` (e.g. `new AppErrorMiddleware({ logger, rootKey: 'error' }).value()`) nests any of these under that key.
|
|
269
|
+
|
|
270
|
+
The handler is fail-closed on environment. It exposes `stack` and `cause` in `details` only for `Environment.DEVELOPMENT_ENVS`: `local`, `debug`, `development`, `dev`, `sit`. Everything else - including `alpha`, `staging`, a typo, or an unset `NODE_ENV` - gets the sanitized shape:
|
|
180
271
|
|
|
181
272
|
```json
|
|
182
273
|
{
|
|
183
|
-
"message": "
|
|
184
|
-
"
|
|
185
|
-
"
|
|
274
|
+
"message": "Only %{available} left of %{variantId}.",
|
|
275
|
+
"statusCode": 409,
|
|
276
|
+
"normalized": {
|
|
277
|
+
"text": "Only %{available} left of %{variantId}.",
|
|
278
|
+
"code": "server.core.stock_reservation.reserve.unavailable",
|
|
279
|
+
"args": { "variantId": "V1", "available": 2 }
|
|
280
|
+
},
|
|
281
|
+
"extra": {
|
|
282
|
+
"details": { "locationId": "L9" }
|
|
283
|
+
},
|
|
186
284
|
"requestId": "abc-123-def",
|
|
187
|
-
"details": {
|
|
188
|
-
"url": "http://localhost:3000/api/users/123",
|
|
189
|
-
"path": "/api/users/123",
|
|
190
|
-
"stack": "Error: User not found\n at ...",
|
|
191
|
-
"cause": "..."
|
|
192
|
-
}
|
|
285
|
+
"details": { "url": "http://localhost:3000/reservations", "path": "/reservations" }
|
|
193
286
|
}
|
|
194
287
|
```
|
|
195
288
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
`ErrorSchema` is a Zod object schema used for OpenAPI response documentation. It is typically referenced in route definitions to describe error responses.
|
|
289
|
+
`extra` is absent entirely when the throw site attached no context of its own.
|
|
199
290
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
const responses = {
|
|
205
|
-
[HTTP.ResultCodes.RS_4.NotFound]: {
|
|
206
|
-
description: 'Resource not found',
|
|
207
|
-
content: {
|
|
208
|
-
'application/json': { schema: ErrorSchema },
|
|
209
|
-
},
|
|
210
|
-
},
|
|
211
|
-
};
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
The schema shape:
|
|
291
|
+
> [!IMPORTANT]
|
|
292
|
+
> **`messageCode` and `extra.messageArgs` are GONE from the response.** They duplicated `normalized.code` and `normalized.args`. Read `normalized` - it is the only source. A client still reading either must migrate: `translate(error.messageCode, error.extra?.messageArgs)` becomes `translate(error.normalized.code, error.normalized.args)`.
|
|
293
|
+
>
|
|
294
|
+
> Note the two `details`. The inner one is context the throw site attached - it went through `extra`. The outer one is the middleware's own request info. They're unrelated despite sharing a name.
|
|
215
295
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
.object({
|
|
219
|
-
name: z.string().optional(),
|
|
220
|
-
statusCode: z.number().optional(),
|
|
221
|
-
messageCode: z.string().optional(),
|
|
222
|
-
message: z.string(),
|
|
223
|
-
})
|
|
224
|
-
.catchall(z.any());
|
|
225
|
-
```
|
|
296
|
+
> [!NOTE]
|
|
297
|
+
> `message` and `normalized.text` are the same string, unless a `transform` deliberately makes them differ. `message` stays the raw text the throw site wrote. `normalized.text` is what a client shows. Most errors never set `transform`, so most of the time the two match.
|
|
226
298
|
|
|
227
|
-
###
|
|
299
|
+
### Consume the error response from a browser client
|
|
228
300
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
| Insufficient permissions | 403 | `RS_4.Forbidden` |
|
|
234
|
-
| Resource not found | 404 | `RS_4.NotFound` |
|
|
235
|
-
| Duplicate resource | 409 | `RS_4.Conflict` |
|
|
236
|
-
| Validation error | 422 | `RS_4.UnprocessableEntity` |
|
|
237
|
-
| Server failure | 500 | `RS_5.InternalServerError` |
|
|
301
|
+
The error layer lives in `@venizia/ignis-inversion`, not in helpers, precisely so a browser app can
|
|
302
|
+
share it. It depends only on `lodash`, ships dual CJS+ESM, and pulls in no server module. A frontend
|
|
303
|
+
throws its own failures with the same `getError` the server uses, and reads the server's with the
|
|
304
|
+
same field names.
|
|
238
305
|
|
|
239
|
-
|
|
306
|
+
**Reading is all most clients need.** `normalized` is on every error response:
|
|
240
307
|
|
|
241
|
-
|
|
308
|
+
- `getError` always builds one.
|
|
309
|
+
- A foreign error gets one synthesized.
|
|
310
|
+
- A `ZodError` builds its own.
|
|
242
311
|
|
|
243
|
-
|
|
312
|
+
So there's no null-check and no parsing step: one lookup handles every case.
|
|
244
313
|
|
|
245
|
-
|
|
314
|
+
```ts
|
|
315
|
+
const { error } = await response.json(); // `error` is the rootKey, if one is configured
|
|
246
316
|
|
|
247
|
-
|
|
248
|
-
throw getError({
|
|
249
|
-
message: 'Resource not found',
|
|
250
|
-
statusCode: HTTP.ResultCodes.RS_4.NotFound,
|
|
251
|
-
});
|
|
317
|
+
translate(error.normalized.code, error.normalized.args);
|
|
252
318
|
```
|
|
253
319
|
|
|
254
|
-
|
|
320
|
+
**Rehydrating** is for the client that wants one `catch` block for both a server failure and a
|
|
321
|
+
locally thrown one. `fromError` inverts the response the middleware emitted:
|
|
255
322
|
|
|
256
|
-
|
|
323
|
+
```ts
|
|
324
|
+
import { fromError, isApplicationError } from '@venizia/ignis-inversion';
|
|
257
325
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
### Errors returning 500 instead of expected status code
|
|
261
|
-
|
|
262
|
-
**Cause:** A plain `Error` (not `ApplicationError`) was thrown. The `appErrorHandler` middleware only reads `statusCode` from errors that have that property. Native `Error` instances default to `500`.
|
|
263
|
-
|
|
264
|
-
**Fix:** Use `getError()` or `new ApplicationError()` instead of `new Error()`:
|
|
265
|
-
|
|
266
|
-
```typescript
|
|
267
|
-
// Incorrect -- will return 500
|
|
268
|
-
throw new Error('Not found');
|
|
269
|
-
|
|
270
|
-
// Correct -- will return 404
|
|
271
|
-
throw getError({
|
|
272
|
-
message: 'Not found',
|
|
273
|
-
statusCode: HTTP.ResultCodes.RS_4.NotFound,
|
|
274
|
-
});
|
|
326
|
+
const { error } = await response.json();
|
|
327
|
+
throw fromError({ error }); // now an ApplicationError - isApplicationError() is true
|
|
275
328
|
```
|
|
276
329
|
|
|
277
|
-
|
|
330
|
+
| Wire field | Where it lands |
|
|
331
|
+
| ------------ | --------------------------------------------------------------------------------- |
|
|
332
|
+
| `normalized` | `normalized`, verbatim - `text`, `code` and `args` round-trip unchanged |
|
|
333
|
+
| `message` | `normalized.text`, but only when `normalized` is missing entirely |
|
|
334
|
+
| `statusCode` | `statusCode`; `400` when the payload carries none |
|
|
335
|
+
| `extra` | `extra`, verbatim |
|
|
336
|
+
| `requestId` | `extra.requestId` - it is the identifier a support ticket quotes, so it survives |
|
|
337
|
+
| `details` | dropped - `url` and `path` the client already knows, and `stack` is the server's |
|
|
278
338
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
339
|
+
Every field of `TResponsedError` is optional by design: a client parses what a gateway, a proxy or an
|
|
340
|
+
older server actually sent. A body that is not an IGNIS error at all still yields an
|
|
341
|
+
`ApplicationError`, degraded to `MessageCode.DEFAULT` and status `400`. No call site branches on
|
|
342
|
+
a parse failure.
|
|
343
|
+
|
|
344
|
+
> [!TIP]
|
|
345
|
+
> Same rule here: prefer `isApplicationError()` over `instanceof ApplicationError`. See the [callout above](#how-it-works) for why - a browser app bundles its own copy of the class, so `instanceof` fails across the boundary.
|
|
346
|
+
|
|
347
|
+
**Common status codes**
|
|
348
|
+
|
|
349
|
+
| Scenario | Status | `HTTP.ResultCodes` path |
|
|
350
|
+
| ------------------------ | ------ | -------------------------- |
|
|
351
|
+
| Invalid input | 400 | `RS_4.BadRequest` |
|
|
352
|
+
| Missing/invalid auth | 401 | `RS_4.Unauthorized` |
|
|
353
|
+
| Insufficient permissions | 403 | `RS_4.Forbidden` |
|
|
354
|
+
| Resource not found | 404 | `RS_4.NotFound` |
|
|
355
|
+
| Duplicate resource | 409 | `RS_4.Conflict` |
|
|
356
|
+
| Server failure | 500 | `RS_5.InternalServerError` |
|
|
357
|
+
|
|
358
|
+
## See also
|
|
359
|
+
|
|
360
|
+
- [Controllers](/references/base/controllers) - throwing errors in route handlers
|
|
361
|
+
- [Services](/references/base/services) - error handling in business logic
|
|
362
|
+
- [Middlewares](/references/base/middlewares) - the `AppErrorMiddleware` handler
|
|
363
|
+
- [Environment](/extensions/helpers/env/) - `Environment.DEVELOPMENT_ENVS`, the error-detail boundary
|
|
364
|
+
- [Helpers Overview](/extensions/helpers/) - all available helpers
|
|
365
|
+
|
|
366
|
+
**Files:**
|
|
367
|
+
|
|
368
|
+
- [`packages/helpers/src/modules/error/index.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/error/index.ts) - module barrel
|
|
369
|
+
- [`packages/helpers/src/modules/error/schemas.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/error/schemas.ts) - `ErrorSchema`, `TErrorResponse` (the RESPONSE schema, for OpenAPI)
|
|
370
|
+
- [`packages/inversion/src/modules/error/app-error.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/error/app-error.ts) - `ApplicationError`, `getError`, `fromError`, `isApplicationError`
|
|
371
|
+
- [`packages/inversion/src/modules/error/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/error/types.ts) - `TError`, `TErrorDefinition`, `TErrorNormalized`, `TResponsedError`, `IErrorKeyRegistry`, `TRegisterErrors`
|
|
372
|
+
- [`packages/inversion/src/modules/error/definition.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/error/definition.ts) - `ErrorScopes`, `TErrorScope`
|
|
373
|
+
- [`packages/inversion/src/modules/error/message-code.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/inversion/src/modules/error/message-code.ts) - `MessageCode`
|