@venizia/ignis-docs 0.2.1-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.
Files changed (145) hide show
  1. package/content/best-practices/architectural-patterns.md +3 -3
  2. package/content/best-practices/code-style-standards/naming-conventions.md +1 -1
  3. package/content/best-practices/contribution-workflow.md +2 -2
  4. package/content/best-practices/error-handling.md +94 -89
  5. package/content/best-practices/security-guidelines.md +5 -5
  6. package/content/extensions/components/api-reference.md +22 -21
  7. package/content/extensions/components/authentication/api.md +64 -28
  8. package/content/extensions/components/authentication/errors.md +19 -5
  9. package/content/extensions/components/authentication/index.md +19 -18
  10. package/content/extensions/components/authentication/usage.md +55 -30
  11. package/content/extensions/components/authorization/api.md +351 -84
  12. package/content/extensions/components/authorization/errors.md +51 -17
  13. package/content/extensions/components/authorization/getting-started.md +227 -0
  14. package/content/extensions/components/authorization/index.md +24 -16
  15. package/content/extensions/components/authorization/usage.md +45 -21
  16. package/content/extensions/components/health-check.md +15 -9
  17. package/content/extensions/components/index.md +24 -90
  18. package/content/extensions/components/mail/api.md +105 -54
  19. package/content/extensions/components/mail/errors.md +12 -10
  20. package/content/extensions/components/mail/index.md +32 -13
  21. package/content/extensions/components/mail/usage.md +26 -18
  22. package/content/extensions/components/request-tracker.md +18 -14
  23. package/content/extensions/components/socket-io/api.md +377 -882
  24. package/content/extensions/components/socket-io/errors.md +49 -51
  25. package/content/extensions/components/socket-io/index.md +72 -88
  26. package/content/extensions/components/socket-io/usage.md +107 -117
  27. package/content/extensions/components/static-asset/api.md +83 -31
  28. package/content/extensions/components/static-asset/errors.md +18 -7
  29. package/content/extensions/components/static-asset/index.md +18 -11
  30. package/content/extensions/components/static-asset/usage.md +11 -6
  31. package/content/extensions/components/template/index.md +3 -3
  32. package/content/extensions/components/websocket/api.md +58 -27
  33. package/content/extensions/components/websocket/errors.md +3 -3
  34. package/content/extensions/components/websocket/index.md +8 -7
  35. package/content/extensions/components/websocket/usage.md +21 -8
  36. package/content/extensions/helpers/cron/index.md +8 -7
  37. package/content/extensions/helpers/crypto/index.md +16 -8
  38. package/content/extensions/helpers/crypto/reference.md +96 -24
  39. package/content/extensions/helpers/env/index.md +14 -10
  40. package/content/extensions/helpers/error/index.md +99 -23
  41. package/content/extensions/helpers/index.md +61 -47
  42. package/content/extensions/helpers/inversion/index.md +23 -6
  43. package/content/extensions/helpers/inversion/reference.md +30 -22
  44. package/content/extensions/helpers/kafka/admin.md +3 -2
  45. package/content/extensions/helpers/kafka/compile-binary.md +69 -44
  46. package/content/extensions/helpers/kafka/consumer.md +24 -21
  47. package/content/extensions/helpers/kafka/examples.md +22 -234
  48. package/content/extensions/helpers/kafka/index.md +30 -62
  49. package/content/extensions/helpers/kafka/producer.md +31 -26
  50. package/content/extensions/helpers/kafka/schema-registry.md +19 -14
  51. package/content/extensions/helpers/logger/hf-logger.md +49 -22
  52. package/content/extensions/helpers/logger/index.md +37 -12
  53. package/content/extensions/helpers/logger/pino.md +31 -11
  54. package/content/extensions/helpers/logger/reference.md +243 -52
  55. package/content/extensions/helpers/network/api.md +65 -30
  56. package/content/extensions/helpers/network/index.md +32 -11
  57. package/content/extensions/helpers/queue/index.md +17 -6
  58. package/content/extensions/helpers/queue/reference.md +52 -25
  59. package/content/extensions/helpers/redis/index.md +29 -11
  60. package/content/extensions/helpers/redis/reference.md +85 -28
  61. package/content/extensions/helpers/secrets/index.md +82 -12
  62. package/content/extensions/helpers/socket-io/api.md +40 -21
  63. package/content/extensions/helpers/socket-io/index.md +26 -10
  64. package/content/extensions/helpers/storage/api.md +42 -24
  65. package/content/extensions/helpers/storage/index.md +10 -7
  66. package/content/extensions/helpers/types/index.md +20 -7
  67. package/content/extensions/helpers/types/reference.md +53 -14
  68. package/content/extensions/helpers/uid/index.md +166 -10
  69. package/content/extensions/helpers/websocket/api.md +52 -13
  70. package/content/extensions/helpers/websocket/index.md +7 -4
  71. package/content/extensions/helpers/worker-thread/index.md +9 -5
  72. package/content/extensions/helpers/worker-thread/reference.md +20 -20
  73. package/content/extensions/index.md +38 -39
  74. package/content/extensions/src-details/mcp-server.md +96 -548
  75. package/content/guides/core-concepts/persistent/datasources.md +2 -2
  76. package/content/guides/core-concepts/persistent/index.md +5 -1
  77. package/content/guides/core-concepts/persistent/pglite.md +218 -0
  78. package/content/guides/core-concepts/persistent/postgres-drivers.md +21 -15
  79. package/content/guides/core-concepts/persistent/search-meilisearch.md +22 -12
  80. package/content/guides/core-concepts/persistent/search-typesense.md +26 -14
  81. package/content/guides/core-concepts/persistent/sqlite.md +296 -0
  82. package/content/guides/core-concepts/persistent/transactions.md +12 -11
  83. package/content/guides/get-started/5-minute-quickstart.md +59 -206
  84. package/content/guides/get-started/philosophy.md +135 -670
  85. package/content/guides/get-started/setup.md +53 -74
  86. package/content/guides/migrations/redis-helpers-migration.md +4 -3
  87. package/content/guides/migrations/scoped-rbac-migration.md +5 -5
  88. package/content/guides/migrations/unified-connectors-migration.md +7 -6
  89. package/content/guides/tutorials/realtime-chat.md +1 -1
  90. package/content/references/base/application.md +63 -21
  91. package/content/references/base/components.md +3 -3
  92. package/content/references/base/connectors.md +14 -14
  93. package/content/references/base/controllers.md +12 -12
  94. package/content/references/base/datasources-reference.md +32 -31
  95. package/content/references/base/datasources.md +6 -6
  96. package/content/references/base/dependency-injection.md +12 -11
  97. package/content/references/base/filter-system/application-usage.md +54 -30
  98. package/content/references/base/filter-system/array-operators.md +24 -46
  99. package/content/references/base/filter-system/comparison-operators.md +47 -67
  100. package/content/references/base/filter-system/default-filter.md +59 -53
  101. package/content/references/base/filter-system/fields-order-pagination.md +92 -146
  102. package/content/references/base/filter-system/index.md +25 -13
  103. package/content/references/base/filter-system/json-filtering.md +45 -184
  104. package/content/references/base/filter-system/list-operators.md +23 -53
  105. package/content/references/base/filter-system/logical-operators.md +63 -121
  106. package/content/references/base/filter-system/null-operators.md +34 -104
  107. package/content/references/base/filter-system/pattern-matching.md +40 -55
  108. package/content/references/base/filter-system/quick-reference.md +86 -198
  109. package/content/references/base/filter-system/range-operators.md +18 -46
  110. package/content/references/base/filter-system/tips.md +6 -6
  111. package/content/references/base/filter-system/use-cases.md +33 -15
  112. package/content/references/base/grpc-controllers.md +53 -17
  113. package/content/references/base/index.md +5 -3
  114. package/content/references/base/middlewares.md +11 -10
  115. package/content/references/base/models-reference.md +17 -17
  116. package/content/references/base/models.md +4 -3
  117. package/content/references/base/providers.md +8 -8
  118. package/content/references/base/repositories/advanced.md +224 -326
  119. package/content/references/base/repositories/index.md +19 -6
  120. package/content/references/base/repositories/mixins.md +5 -5
  121. package/content/references/base/repositories/relations.md +160 -293
  122. package/content/references/base/repositories/soft-deletable.md +16 -6
  123. package/content/references/base/secrets.md +17 -13
  124. package/content/references/base/services.md +6 -4
  125. package/content/references/configuration/environment-variables.md +31 -23
  126. package/content/references/configuration/index.md +6 -4
  127. package/content/references/index.md +1 -1
  128. package/content/references/utilities/duration.md +85 -0
  129. package/content/references/utilities/index.md +5 -1
  130. package/content/references/utilities/jsx-reference.md +11 -11
  131. package/content/references/utilities/jsx.md +2 -2
  132. package/content/references/utilities/module.md +78 -25
  133. package/content/references/utilities/request.md +2 -1
  134. package/content/references/utilities/retry.md +139 -0
  135. package/content/references/utilities/schema.md +2 -2
  136. package/content/references/utilities/statuses-reference.md +4 -4
  137. package/content/references/utilities/statuses.md +5 -5
  138. package/dist/mcp-server/index.js +0 -0
  139. package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
  140. package/dist/mcp-server/tools/github/list-project-files.tool.d.ts.map +1 -1
  141. package/dist/mcp-server/tools/github/list-project-files.tool.js +3 -3
  142. package/dist/mcp-server/tools/github/search-code.tool.js +1 -1
  143. package/dist/mcp-server/tools/github/verify-dependencies.tool.js +1 -1
  144. package/dist/mcp-server/tools/github/view-source-file.tool.js +1 -1
  145. package/package.json +17 -16
@@ -117,7 +117,7 @@ REST controllers extend `BaseRestController`, while gRPC controllers extend `Bas
117
117
 
118
118
  ## 3. Component-Based Modularity
119
119
 
120
- Components bundle a group of related, reusable, and pluggable features into self-contained modules. A single component can encapsulate multiple providers, services, controllers, and repositories, essentially functioning as a mini-application that can be easily "plugged in" to any IGNIS project.
120
+ Components bundle a group of related, reusable, and pluggable features into self-contained modules. A single component can encapsulate multiple providers, services, controllers, and repositories. It functions as a mini-application that plugs into any IGNIS project.
121
121
 
122
122
  **Built-in Components:**
123
123
  - `AuthenticateComponent` - JWT authentication
@@ -140,7 +140,7 @@ export class Application extends BaseApplication {
140
140
  }
141
141
  }
142
142
  ```
143
- This architecture keeps the main `Application` class clean and focused on high-level assembly, while the details of each feature are neatly encapsulated within their respective components.
143
+ This architecture keeps the main `Application` class clean and focused on high-level assembly. The details of each feature stay neatly encapsulated within their respective components.
144
144
 
145
145
  ## 4. Custom Components
146
146
 
@@ -303,7 +303,7 @@ service<Base extends IService, Args extends AnyObject = any>(
303
303
  }
304
304
  ```
305
305
 
306
- Every registration method takes the same optional second argument - `opts.binding` overrides the derived `{ namespace, key }` when you need to register two classes under one contract.
306
+ Every registration method takes the same optional second argument. `opts.binding` overrides the derived `{ namespace, key }` when you need to register two classes under one contract.
307
307
 
308
308
  **Capability interfaces:**
309
309
 
@@ -115,7 +115,7 @@ interface IAuthService {
115
115
 
116
116
  // Type aliases use 'T' prefix
117
117
  type TSignInRequest = z.infer<typeof SignInRequestSchema>;
118
- type TAuthStrategy = TConstValue<typeof AuthenticateStrategy>;
118
+ type TJWKSMode = TConstValue<typeof JWKSModes>;
119
119
 
120
120
  // ❌ Never a bare string-literal union for an enumerable set - it has no runtime
121
121
  // values to validate against. Use a const class + TConstValue instead.
@@ -161,8 +161,8 @@ make lint-all
161
161
  # Build all packages (from root)
162
162
  make build
163
163
 
164
- # Run tests (from a package directory, e.g. packages/core or packages/boot)
165
- cd packages/core && bun test
164
+ # Run tests (from a package directory, e.g. packages/core-server or packages/boot)
165
+ cd packages/core-server && bun test
166
166
  ```
167
167
 
168
168
  > [!WARNING]
@@ -1,28 +1,37 @@
1
1
  # Error Handling
2
2
 
3
- Comprehensive guide to handling errors gracefully in IGNIS applications.
4
-
5
- ## Error Handling Philosophy
6
-
7
- | Principle | Description |
8
- |-----------|-------------|
9
- | **Fail Fast** | Detect and report errors as early as possible |
10
- | **Don't Swallow** | Never catch errors without logging or re-throwing |
11
- | **User-Friendly** | Return clear, actionable messages to clients |
12
- | **Debuggable** | Include context for debugging in logs |
13
-
14
- ## 1. Using `getError` Helper
15
-
16
- IGNIS provides `getError` for creating consistent, structured errors.
3
+ Every error in IGNIS ends up as one shape: `statusCode`, `message`, `normalized`, `requestId`, and `details`. `getError` builds that shape at the throw site. A global handler catches whatever you don't.
17
4
 
18
5
  ```typescript
19
6
  import { getError, HTTP } from '@venizia/ignis-helpers';
20
7
 
21
- // Basic error
22
8
  throw getError({
23
9
  statusCode: HTTP.ResultCodes.RS_4.NotFound,
24
10
  message: 'User not found',
25
11
  });
12
+ ```
13
+
14
+ ## Find what you need
15
+
16
+ | You want to | Go to |
17
+ |---|---|
18
+ | Throw an error with debugging context | [Throw a structured error](#throw-a-structured-error) |
19
+ | Add an i18n error a client can branch on | [Catalog a domain error](#catalog-a-domain-error) |
20
+ | Pick the right HTTP status code | [Choose the right status code](#choose-the-right-status-code) |
21
+ | Handle errors in a service, controller, or repository | [Handle errors by layer](#handle-errors-by-layer) |
22
+ | Customize the global error response | [Customize the global handler](#customize-the-global-handler) |
23
+ | Read the exact JSON a client receives | [The error response shape](#the-error-response-shape) |
24
+ | Log an error without losing the stack | [Log errors](#log-errors) |
25
+ | Handle a rejected promise or a fire-and-forget call | [Handle async errors](#handle-async-errors) |
26
+ | Roll back a transaction safely | [Roll back a transaction on failure](#roll-back-a-transaction-on-failure) |
27
+ | Parse an error response on the client | [Parse errors on the client](#parse-errors-on-the-client) |
28
+
29
+ ## Throw a structured error
30
+
31
+ `getError` is the one function every throw in IGNIS goes through. Give it a status code and a message, and it returns an `ApplicationError` ready to throw.
32
+
33
+ ```typescript
34
+ import { getError, HTTP } from '@venizia/ignis-helpers';
26
35
 
27
36
  // Error with context - any key the framework does not model lands in `extra`
28
37
  throw getError({
@@ -48,14 +57,16 @@ throw getError({
48
57
  });
49
58
  ```
50
59
 
60
+ Any key `getError` does not model rides into `extra`. That's how a throw site attaches context the framework knows nothing about.
61
+
51
62
  > [!NOTE]
52
- > Any key `getError` does not model rides into `extra` - that is how a throw site attaches context the framework knows nothing about. The trade is that a **misspelling** goes the same way: `getError({ message, statuscode: 503 })` compiles, `statusCode` stays `400`, and `503` sits in `extra.statuscode`. The framework cannot tell your context from your typo.
63
+ > The trade-off: a **misspelling** rides the same path. `getError({ message, statuscode: 503 })` compiles. `statusCode` stays `400`, and `503` sits in `extra.statuscode`. The framework can't tell your context from your typo - spell option keys carefully.
53
64
 
54
- ### Catalogue a domain failure, raise the rest free-form
65
+ ## Catalog a domain error
55
66
 
56
- The form above is right for a failure that carries no i18n code: an invariant, a misconfiguration, a seed guard. Nobody translates `'[UserService][create] Database connection failed'`.
67
+ A free-form `getError` call like that is right for a failure with no i18n code: an invariant, a misconfiguration, a seed guard. Nobody translates `'[UserService][create] Database connection failed'`.
57
68
 
58
- A **domain** failure - one a client localizes and branches on - belongs in a catalog instead. Retyping its code and status at each throw is how two call sites end up raising `category.create.duplicate_name` and `category.duplicate_name` for the same thing:
69
+ But a **domain** failure - one a client localizes and branches on - belongs in a catalog instead. Retyping its code and status at each throw is how two call sites end up raising `category.create.duplicate_name` and `category.duplicate_name` for the same thing.
59
70
 
60
71
  ```typescript
61
72
  import { ErrorScopes, getError, HTTP } from '@venizia/ignis-helpers';
@@ -81,15 +92,15 @@ declare module '@venizia/ignis-helpers' {
81
92
  throw getError({ error: UserErrors.CREATE_DUPLICATE_EMAIL, messageArgs: { email } });
82
93
  ```
83
94
 
84
- Pass the definition as `error` - **never spread it**. `getError({ ...UserErrors.CREATE_DUPLICATE_EMAIL, messageArgs: { email } })` reads naturally and is wrong: spreading skips the `error:` field entirely, so `category` and `description` - fields only modeled inside a definition - fall through into `extra` instead of staying structured. `statusCode` and `message` happen to still resolve correctly only because their shapes collide with what `getError` expects standalone; nothing catches the rest for you.
95
+ Pass the definition as `error` - never spread it. `getError({ ...UserErrors.CREATE_DUPLICATE_EMAIL, messageArgs: { email } })` looks equivalent. It isn't.
85
96
 
86
- See the [Error helper reference](/extensions/helpers/error/) for the full surface.
97
+ Spreading skips the `error:` field entirely. `category` and `description` are fields only a definition models, so they fall into `extra` instead of staying structured. `statusCode` and `message` still resolve correctly, but only because their shapes happen to match what `getError` expects standalone - nothing catches the rest for you.
87
98
 
88
- ## 2. HTTP Status Code Reference
99
+ See the [Error helper reference](/extensions/helpers/error/) for the full surface.
89
100
 
90
- Use the correct status code for each error type:
101
+ ## Choose the right status code
91
102
 
92
- | Code | Constant | Use When |
103
+ | Code | Constant | Use when |
93
104
  |------|----------|----------|
94
105
  | 400 | `RS_4.BadRequest` | Invalid input format, missing required fields, database constraint violations (auto-handled) |
95
106
  | 401 | `RS_4.Unauthorized` | Missing or invalid authentication |
@@ -102,13 +113,15 @@ Use the correct status code for each error type:
102
113
  | 502 | `RS_5.BadGateway` | External service failed |
103
114
  | 503 | `RS_5.ServiceUnavailable` | Service temporarily down |
104
115
 
105
- :::tip Automatic Database Error Handling
106
- Database errors in SQLSTATE classes `22` (data exception), `23` (integrity constraint - unique, foreign key, not null, check, exclusion), and `44` (WITH CHECK OPTION violation) are automatically converted to HTTP 400 by the global error middleware. Transient conflicts (`40001` serialization failure, `40P01` deadlock) become HTTP 409 with a retryable message. You don't need to catch these manually. Other classes (e.g. syntax / undefined column) stay 500, and production responses are sanitized - see [Repository Layer Errors](#repository-layer-errors).
116
+ :::tip Automatic database error handling
117
+ The global error middleware converts constraint violations to HTTP 400 on its own, no try/catch needed - SQLSTATE class `22` (data exception), `23` (integrity constraint: unique, foreign key, not null, check, exclusion), and `44` (WITH CHECK OPTION violation). Transient conflicts (`40001` serialization failure, `40P01` deadlock) become HTTP 409 with a retryable message instead. Other classes (for example, class `42` undefined column) stay 500, and production responses are sanitized - see [Repository layer](#repository-layer).
107
118
  :::
108
119
 
109
- ## 3. Error Handling Patterns
120
+ ## Handle errors by layer
110
121
 
111
- ### Service Layer Errors
122
+ ### Service layer
123
+
124
+ A service decides what's wrong and throws with `getError`. It doesn't catch what it can't handle.
112
125
 
113
126
  ```typescript
114
127
  import { BaseService } from '@venizia/ignis';
@@ -160,9 +173,11 @@ export class UserService extends BaseService {
160
173
  }
161
174
  ```
162
175
 
163
- ### Controller Layer Errors
176
+ Notice `findOne` and `findById` return the record or `null` - there's no separate "not found" exception to catch. You check for `null` and throw.
177
+
178
+ ### Controller layer
164
179
 
165
- Controllers should delegate to services and let the global error handler catch exceptions:
180
+ Controllers stay thin. Call the service, return the response, and let the global handler catch what the service throws.
166
181
 
167
182
  ```typescript
168
183
  import { BaseRestController, controller, get, post } from '@venizia/ignis';
@@ -192,9 +207,9 @@ export class UserController extends BaseRestController {
192
207
  }
193
208
  ```
194
209
 
195
- ### Repository Layer Errors
210
+ ### Repository layer
196
211
 
197
- Database errors in SQLSTATE classes `22` (data exception), `23` (integrity constraint - unique, foreign key, not null, check, exclusion), and `44` (WITH CHECK OPTION violation) are **automatically handled** by the global error middleware and return HTTP 400. Transient conflicts (`40001` serialization failure, `40P01` deadlock) return HTTP 409 with a generic retryable message. Codes outside those classes (e.g. class `42` undefined column - an application/SQL bug) correctly stay 500.
212
+ The global middleware already converts constraint violations for you (see [Choose the right status code](#choose-the-right-status-code)), so most repository methods need no try/catch at all. Skip it unless you want a message tailored to one specific constraint.
198
213
 
199
214
  **Non-production** returns the full driver context for debugging:
200
215
 
@@ -217,7 +232,7 @@ Database errors in SQLSTATE classes `22` (data exception), `23` (integrity const
217
232
  ```
218
233
 
219
234
  :::warning Production sanitizes database internals
220
- In production the message is the **base message only** - `Detail:` (which echoes row values like emails), `Table:`, and `Constraint:` are stripped, and `details.stack`/`details.cause` are omitted. Unexpected (non-client) database errors and connection failures return a generic `"Internal Server Error"`, so SQL, schema names, and connection host/port never leak. Use `requestId` + server logs to diagnose.
235
+ In production the message is the **base message only**. `Detail:` (which echoes row values like emails), `Table:`, and `Constraint:` are stripped, and `details.stack`/`details.cause` are omitted. Unexpected (non-client) database errors and connection failures return a generic `"Internal Server Error"`, so SQL, schema names, and connection host/port never leak. Use `requestId` and server logs to diagnose.
221
236
 
222
237
  ```json
223
238
  {
@@ -230,13 +245,13 @@ In production the message is the **base message only** - `Detail:` (which echoes
230
245
  ```
231
246
  :::
232
247
 
233
- You don't need to wrap repository calls in try-catch for constraint errors. If you need custom error messages, you can still handle them explicitly:
248
+ If you need a custom message for one constraint, catch it explicitly and re-throw everything else:
234
249
 
235
250
  ```typescript
236
- import { DefaultRelationalRepository, type TCount } from '@venizia/ignis';
251
+ import { DefaultCRUDRepository, type TCount } from '@venizia/ignis';
237
252
  import { getError, HTTP } from '@venizia/ignis-helpers';
238
253
 
239
- export class UserRepository extends DefaultRelationalRepository<typeof User.schema> {
254
+ export class UserRepository extends DefaultCRUDRepository<typeof User.schema> {
240
255
  async createWithCustomError(data: TCreateUser): Promise<TCount & { data: TUser }> {
241
256
  try {
242
257
  return await this.create({ data });
@@ -254,9 +269,9 @@ export class UserRepository extends DefaultRelationalRepository<typeof User.sche
254
269
  }
255
270
  ```
256
271
 
257
- ## 4. Global Error Handler
272
+ ## Customize the global handler
258
273
 
259
- IGNIS wires a built-in handler by default - `AppErrorMiddleware` from `@venizia/ignis` is a class, registered as `new AppErrorMiddleware({ logger, rootKey }).value()`, and `value()` returns the Hono `ErrorHandler`. You rarely need to replace it; when you do, keep the same response contract:
274
+ IGNIS wires a built-in handler by default. `AppErrorMiddleware` from `@venizia/ignis` is a class, registered as `new AppErrorMiddleware({ logger, rootKey }).value()`, and `value()` returns the Hono `ErrorHandler`. You rarely need to replace it. When you do, keep the same response contract:
260
275
 
261
276
  ```typescript
262
277
  import { BaseApplication } from '@venizia/ignis';
@@ -309,9 +324,7 @@ export class Application extends BaseApplication {
309
324
  }
310
325
  ```
311
326
 
312
- ## 5. Error Response Format
313
-
314
- All errors should follow a consistent format:
327
+ ## The error response shape
315
328
 
316
329
  ```typescript
317
330
  interface ErrorResponse {
@@ -334,12 +347,11 @@ interface ErrorResponse {
334
347
  }
335
348
  ```
336
349
 
337
- There is no top-level `messageCode` - read `normalized.code`. `extra` never mirrors `messageArgs`; the resolved interpolation values live at `normalized.args`.
350
+ There's no top-level `messageCode` - read `normalized.code`. `extra` never mirrors `messageArgs`; the resolved interpolation values live at `normalized.args`.
338
351
 
339
- **Example Responses:**
352
+ **400 Bad Request:**
340
353
 
341
354
  ```json
342
- // 400 Bad Request
343
355
  {
344
356
  "message": "Invalid request body",
345
357
  "statusCode": 400,
@@ -347,10 +359,11 @@ There is no top-level `messageCode` - read `normalized.code`. `extra` never mirr
347
359
  "requestId": "abc123",
348
360
  "details": { "url": "http://localhost:3000/users", "path": "/users" }
349
361
  }
362
+ ```
350
363
 
351
- // 404 Not Found
352
- // Extra keys passed to getError(...) (e.g. `details`) surface under `extra`;
353
- // the top-level `details` object is reserved for middleware context (url, path, stack, cause).
364
+ **404 Not Found:** extra keys passed to `getError(...)` (for example `details`) surface under the top-level `extra`. The top-level `details` object is reserved for middleware context (url, path, stack, cause) - the two never share a key.
365
+
366
+ ```json
354
367
  {
355
368
  "message": "User not found",
356
369
  "statusCode": 404,
@@ -359,11 +372,11 @@ There is no top-level `messageCode` - read `normalized.code`. `extra` never mirr
359
372
  "extra": { "details": { "id": "user-uuid" } },
360
373
  "details": { "url": "http://localhost:3000/users/user-uuid", "path": "/users/:id" }
361
374
  }
375
+ ```
376
+
377
+ **422 Validation Error:** `message` and `normalized.code` come from the first failing issue - its `params.code` if the schema set one, otherwise the raw Zod code (for example `invalid_type`, `too_small`). `normalized.args` is always empty for a Zod issue; the full list of issues stays in `details.cause`.
362
378
 
363
- // 422 Validation Error
364
- // `message`/`normalized.code` come from the first failing issue - its `params.code` if the schema
365
- // set one, otherwise the raw Zod code (e.g. `invalid_type`, `too_small`). `normalized.args` is
366
- // always empty for a Zod issue; the full list of issues stays in `details.cause`.
379
+ ```json
367
380
  {
368
381
  "message": "Invalid email format",
369
382
  "statusCode": 422,
@@ -381,53 +394,44 @@ There is no top-level `messageCode` - read `normalized.code`. `extra` never mirr
381
394
  ]
382
395
  }
383
396
  }
384
-
385
- // 500 Internal Error (production)
386
- {
387
- "message": "Internal server error",
388
- "statusCode": 500,
389
- "normalized": { "text": "Internal server error", "code": "core.system_error", "args": {} },
390
- "requestId": "abc123",
391
- "details": { "url": "http://localhost:3000/orders", "path": "/orders" }
392
- }
393
397
  ```
394
398
 
395
- ## 6. Logging Errors
399
+ ## Log errors
396
400
 
397
- ### `%s`, Never `%j`, for an `Error`
401
+ ### Use `%s`, never `%j`, for an Error
398
402
 
399
403
  `message` and `stack` are non-enumerable properties on a native `Error` (and on `ApplicationError`, which extends it). `%j` serializes via `JSON.stringify`, which only visits enumerable own properties - so `logger.error('... | error: %j', error)` silently drops both. Always use `%s` to log an `Error` instance; reserve `%j`/`%o` for plain data objects.
400
404
 
401
405
  ```typescript
402
- // Good - %s prints message + stack
406
+ // Good - %s prints message + stack
403
407
  this.logger.error('[createOrder] Failed | error: %s', error);
404
408
 
405
- // Bad - %j drops the stack
409
+ // Bad - %j drops the stack
406
410
  this.logger.error('[createOrder] Failed | error: %j', error);
407
411
  ```
408
412
 
409
413
  > [!NOTE]
410
- > An `ApplicationError` logged with `%j` does show its message text, because the text rides inside the enumerable `normalized.text`. That is incidental, not a reprieve: the **stack** is still gone, which is the reason the rule exists. A plain `Error` under `%j` still logs little more than `{}`.
414
+ > An `ApplicationError` logged with `%j` does show its message text, because the text rides inside the enumerable `normalized.text`. That's incidental, not a reprieve - the **stack** is still gone, which is the reason the rule exists. A plain `Error` under `%j` still logs little more than `{}`.
411
415
 
412
- ### What to Log
416
+ ### What to log
413
417
 
414
418
  ```typescript
415
- // Good - Context for debugging. `%s` on the error itself carries message + stack
419
+ // Good - context for debugging. `%s` on the error itself carries message + stack
416
420
  this.logger.error('[createOrder] Failed | userId: %s | orderId: %s | error: %s',
417
421
  userId, orderId, error);
418
422
 
419
- // Bad - No context, and `.message` throws the stack away
423
+ // Bad - no context, and `.message` throws the stack away
420
424
  this.logger.error(error.message);
421
425
 
422
- // Bad - Sensitive data
426
+ // Bad - sensitive data
423
427
  this.logger.error('Login failed for user | password: %s', password);
424
428
  ```
425
429
 
426
- ### Log Levels
430
+ ### Log levels
427
431
 
428
- `ILogger` has exactly five levels, each a direct method. `alert`, `http`, `verbose` and `silly` do not exist.
432
+ `ILogger` has exactly five levels, each a direct method. `alert`, `http`, `verbose`, and `silly` don't exist.
429
433
 
430
- | Level | Use For |
434
+ | Level | Use for |
431
435
  |-------|---------|
432
436
  | `emerg` | The process cannot continue - unrecoverable |
433
437
  | `error` | Exceptions that need attention |
@@ -449,18 +453,20 @@ this.logger.info('[order] Created | orderId: %s | userId: %s', orderId, userId);
449
453
  this.logger.debug('[query] Executing | sql: %s | params: %j', sql, params);
450
454
  ```
451
455
 
452
- ## 7. Async Error Handling
456
+ ## Handle async errors
453
457
 
454
458
  ### Promises
455
459
 
460
+ `async`/`await` propagates errors on its own - most of the time, you write no error handling at all.
461
+
456
462
  ```typescript
457
- // Good - Errors propagate naturally with async/await
463
+ // Good - errors propagate naturally with async/await
458
464
  const processOrder = async (orderId: string) => {
459
465
  const order = await orderRepository.findById({ id: orderId }); // Throws if fails
460
466
  return paymentService.charge(order); // Throws if fails
461
467
  };
462
468
 
463
- // Good - Explicit catch when you need to handle
469
+ // Good - explicit catch when you need to handle
464
470
  const processOrderWithFallback = async (order: TOrder) => {
465
471
  try {
466
472
  return await paymentService.charge(order);
@@ -470,7 +476,7 @@ const processOrderWithFallback = async (order: TOrder) => {
470
476
  }
471
477
  };
472
478
 
473
- // Bad - Swallowing errors
479
+ // Bad - swallowing errors
474
480
  const processOrderSilently = async () => {
475
481
  try {
476
482
  await dangerousOperation();
@@ -480,22 +486,24 @@ const processOrderSilently = async () => {
480
486
  };
481
487
  ```
482
488
 
483
- ### Fire-and-Forget with Error Handling
489
+ ### Fire-and-forget
490
+
491
+ But a call you don't `await` needs its own `.catch()`, or a rejection crashes the process as an unhandled rejection.
484
492
 
485
493
  ```typescript
486
- // Good - Log errors from fire-and-forget operations
494
+ // Good - log errors from fire-and-forget operations
487
495
  this.sendNotification(userId).catch(error => {
488
496
  this.logger.error('[notify] Failed | userId: %s | error: %s', userId, error);
489
497
  });
490
498
 
491
- // Good - Use void to indicate intentional fire-and-forget
499
+ // Good - use void to indicate intentional fire-and-forget
492
500
  void this.analytics.track('order_created', { orderId });
493
501
 
494
- // Bad - Unhandled promise rejection
502
+ // Bad - unhandled promise rejection
495
503
  this.sendNotification(userId); // If this rejects, crash!
496
504
  ```
497
505
 
498
- ## 8. Transaction Error Handling
506
+ ## Roll back a transaction on failure
499
507
 
500
508
  ```typescript
501
509
  import { getError, HTTP } from '@venizia/ignis-helpers';
@@ -525,13 +533,11 @@ const transferFunds = async (opts: { from: string; to: string; amount: number })
525
533
  ```
526
534
 
527
535
  > [!NOTE]
528
- > `rollback()` throws on failure, so it belongs in the `catch` exactly as above - never after a
529
- > `commit()` you already awaited outside one. A rollback that follows a **failed** commit is a
530
- > deliberate no-op: the transaction is already torn down, so this canonical shape stays safe.
536
+ > `rollback()` throws on failure, so it belongs in the `catch` block exactly as shown here - never after a `commit()` you already awaited outside one. A rollback that follows a **failed** commit is a deliberate no-op: the transaction is already torn down, so this canonical shape stays safe.
531
537
 
532
- ## 9. Client-Side Error Handling
538
+ ## Parse errors on the client
533
539
 
534
- Guide for API consumers:
540
+ Branch on `normalized.code` - it's always present. There's no top-level `messageCode`.
535
541
 
536
542
  ```typescript
537
543
  // TypeScript client example
@@ -545,7 +551,6 @@ const createUser = async (data: TCreateUserRequest): Promise<TUser> => {
545
551
  if (!response.ok) {
546
552
  const error = await response.json();
547
553
 
548
- // Branch on `normalized.code` - it is always present. There is no top-level `messageCode`.
549
554
  switch (response.status) {
550
555
  case 400: {
551
556
  // Context passed to getError(...) arrives under `extra`, not `details`
@@ -579,7 +584,7 @@ const createUser = async (data: TCreateUserRequest): Promise<TUser> => {
579
584
  };
580
585
  ```
581
586
 
582
- ## Error Handling Checklist
587
+ ## Checklist
583
588
 
584
589
  | Category | Check |
585
590
  |----------|-------|
@@ -592,7 +597,7 @@ const createUser = async (data: TCreateUserRequest): Promise<TUser> => {
592
597
  | **Responses** | Consistent error format returned |
593
598
  | **Security** | No sensitive data in error messages |
594
599
 
595
- ## See Also
600
+ ## See also
596
601
 
597
602
  - [Common Pitfalls](./common-pitfalls) - Error handling mistakes
598
603
  - [Testing Strategies](./testing-strategies) - Testing error scenarios
@@ -25,12 +25,12 @@ bun -e "console.log(Buffer.from(crypto.getRandomValues(new Uint8Array(32))).toSt
25
25
 
26
26
  ### Redaction at Log Time
27
27
 
28
- Never hard-coding a secret is not enough on its own - an options object holding one still ends up in a log line the moment it is passed to `logger.info('...: %s', opts)`. `@venizia/ignis-helpers` provides two primitives for exactly this:
28
+ Never hard-coding a secret is not enough on its own. An options object holding one still ends up in a log line the moment it is passed to `logger.info('...: %s', opts)`. `@venizia/ignis-helpers` provides two primitives for exactly this:
29
29
 
30
30
  | Function | Use For | Behavior |
31
31
  |----------|---------|----------|
32
32
  | `redactSecrets(value)` | Any object/array being logged | Recursively replaces every value whose key matches a secret-looking name with `'[REDACTED]'` |
33
- | `redactUrlCredentials(url)` | A connection/broker URL string | Strips the password out of a URL's authority section (`mqtts://user:hunter2@broker:8883` becomes `mqtts://user:[REDACTED]@broker:8883`); a value that doesn't parse as a URL, or one with no password, is returned unchanged |
33
+ | `redactUrlCredentials(url)` | A connection/broker URL string | Strips the password out of a URL's authority section: `mqtts://user:hunter2@broker:8883` becomes `mqtts://user:[REDACTED]@broker:8883`. A value that doesn't parse as a URL, or one with no password, is returned unchanged |
34
34
 
35
35
  ```typescript
36
36
  import { redactSecrets, redactUrlCredentials } from '@venizia/ignis-helpers';
@@ -46,9 +46,9 @@ this.logger.info('[connect] Broker: %s', redactUrlCredentials(brokerUrl));
46
46
  - Vault wire keys: `client_token`, `secret_id`, `role_id`
47
47
  - HTTP header spellings: `x-api-key`, `x-vault-token`, `cookie`, `set-cookie`, `proxy-authorization`, `www-authenticate`
48
48
 
49
- It also handles the shapes naive redaction breaks on: an `Error` is reprojected so its non-enumerable `message`/`stack` survive, cycles become `'[Circular]'`, and buffers/typed arrays are summarized as `[Binary N bytes]` instead of serialized.
49
+ It also handles the shapes naive redaction breaks on. An `Error` is reprojected so its non-enumerable `message`/`stack` survive. Cycles become `'[Circular]'`, and buffers/typed arrays are summarized as `[Binary N bytes]` instead of serialized.
50
50
 
51
- These are the primitives the framework itself uses - outbound HTTP request configs (`NodeFetcher`/`AxiosFetcher`, see [Network Helper](/extensions/helpers/network/)) and MQTT broker URLs (`MQTTClientHelper`, see [Queue Helper](/extensions/helpers/queue/)) are both redacted this way before they reach a log line.
51
+ These are the primitives the framework itself uses. Outbound HTTP request configs (`NodeFetcher`/`AxiosFetcher`, see [Network Helper](/extensions/helpers/network/)) and MQTT broker URLs (`MQTTClientHelper`, see [Queue Helper](/extensions/helpers/queue/)) are both redacted this way before they reach a log line.
52
52
 
53
53
  > [!WARNING]
54
54
  > `APP_ENV_LOGGER_DO_REDACT=false` turns both functions into the identity function. It is a local-debugging kill-switch and must never be set in production. The check is fail-closed - only the literal string `false` disables redaction - and is read per call, so it can be flipped at runtime.
@@ -495,7 +495,7 @@ Deliberate `getError` messages are always returned verbatim, in every environmen
495
495
  - Admin actions
496
496
 
497
497
  > [!NOTE]
498
- > When logging a request or connection config that might carry credentials, wrap it in `redactSecrets()` (or `redactUrlCredentials()` for a URL) rather than logging it raw - see [Redaction at Log Time](#redaction-at-log-time) above. This is what the framework's own outbound HTTP and MQTT logging already does automatically.
498
+ > When logging a request or connection config that might carry credentials, wrap it in `redactSecrets()` (or `redactUrlCredentials()` for a URL) rather than logging it raw. See [Redaction at Log Time](#redaction-at-log-time) above. This is what the framework's own outbound HTTP and MQTT logging already does automatically.
499
499
 
500
500
  ## Security Checklist
501
501
 
@@ -1,9 +1,9 @@
1
1
  # API Reference
2
2
 
3
- Automatic interactive API documentation generated from OpenAPI specs, rendered by a pluggable UI provider - Scalar by default, or classic Swagger UI.
3
+ Automatic interactive API documentation generated from your OpenAPI spec. A pluggable UI provider renders it - Scalar by default, or classic Swagger UI.
4
4
 
5
5
  > [!NOTE] Renamed from SwaggerComponent
6
- > Swagger UI is just one of the pluggable UI providers, so the component carries a vendor-neutral name. `SwaggerComponent`, `ISwaggerOptions`, and `SwaggerBindingKeys` remain available as deprecated aliases - existing applications keep working unchanged.
6
+ > Swagger UI is one of the pluggable UI providers, not the only one, so the component carries a vendor-neutral name. The deprecated `Swagger*` aliases are **removed**: use `ApiReferenceComponent`, `IApiReferenceOptions` and `ApiReferenceBindingKeys.API_REFERENCE_OPTIONS`.
7
7
 
8
8
  ## Quick Reference
9
9
 
@@ -27,7 +27,7 @@ import type { IApiReferenceOptions, IUIProvider, IUIConfig, IGetProviderParams }
27
27
 
28
28
  ## In one example
29
29
 
30
- Register the component - the docs UI comes up at `/doc/explorer`, the raw spec at `/doc/openapi.json`. No configuration required.
30
+ Register the component - no configuration required. The docs UI comes up at `<app base path>/doc/explorer`, the raw spec at `<app base path>/doc/openapi.json`. With the `/api` base path used throughout the getting-started guide, that's `/api/doc/explorer`.
31
31
 
32
32
  ```typescript
33
33
  // src/application.ts
@@ -79,13 +79,14 @@ export class HelloController extends BaseRestController {
79
79
 
80
80
  ## How it works
81
81
 
82
- - **Options merge group by group.** `binding()` reads the bound `IApiReferenceOptions`, then shallow-merges `base`, `doc`, and `ui` each against their own defaults - overriding `ui.type` alone still keeps `ui.path` and every `base`/`doc` field.
83
- - **`explorer.info` is always overwritten.** The component unconditionally reads your `package.json` (via `application.getAppInfo()`) and replaces `explorer.info` with `{ title, version, description, contact }` - any `explorer.info` you bind is discarded. Edit `package.json` instead.
84
- - **`explorer.servers` fills in only when empty.** A supplied server entry is kept as-is; otherwise the component builds one from `application.getServerAddress()` plus the base path.
85
- - **UI type resolution uses `??`, not `||`.** The source is `restOptions.ui.type ?? DocumentUITypes.SWAGGER` - only `null`/`undefined` falls back, and it falls back to `'swagger'`, not the configured default `'scalar'`. An explicit empty string is NOT repaired by this fallback - it fails `DocumentUITypes.isValid()` and the component throws `Invalid document UI Type` immediately.
86
- - **UI libraries load lazily.** `SwaggerUIProvider`/`ScalarUIProvider` each `await import()` their rendering library inside `render()`, on the first request to the docs UI - not at application startup. Only the configured provider's library is ever loaded.
87
- - **`ScalarUIProvider` renames `title` to `pageTitle`.** A quirk to know if you inspect the rendered output or write a custom UI provider: Scalar's own API takes `pageTitle`, not `title`.
88
- - **Security schemes are always registered.** JWT (`bearer`) and Basic security schemes are added to the OpenAPI registry unconditionally, so routes using `authenticate: { strategies: ['jwt'] }` or `['basic']` render the correct auth UI.
82
+ - **Options merge group by group.** `binding()` reads the bound `IApiReferenceOptions`, then shallow-merges `base`, `doc`, and `ui` each against their own defaults. Overriding `ui.type` alone still keeps `ui.path` and every `base`/`doc` field.
83
+ - **`explorer.info` is always overwritten.** The component reads your `package.json` via `application.getAppInfo()`. It replaces `explorer.info` with `{ title, version, description, contact }` - any `explorer.info` you bind is discarded. Edit `package.json` instead.
84
+ - **`explorer.servers` fills in only when empty.** A supplied server entry is kept as-is. Otherwise, the component builds one from `application.getServerAddress()` plus the base path.
85
+ - **UI type resolution uses `??`, not `||`.** The source is `restOptions.ui.type ?? DocumentUITypes.SWAGGER`. Only `null`/`undefined` falls back, and it falls back to `'swagger'` - not the configured default `'scalar'`.
86
+ - An explicit empty string is NOT repaired by this fallback: it fails `DocumentUITypes.isValid()` and the component throws `Invalid document UI Type` immediately.
87
+ - **UI libraries load lazily.** `SwaggerUIProvider`/`ScalarUIProvider` each `await import()` their rendering library inside `render()`. That happens on the first request to the docs UI, not at application startup. Only the configured provider's library is ever loaded.
88
+ - **`ScalarUIProvider` renames `title` to `pageTitle`.** Scalar's own render API takes `pageTitle`, not `title` - worth knowing if you inspect the rendered output or write a custom UI provider.
89
+ - **Security schemes are always registered.** JWT (`bearer`) and Basic security schemes are added to the OpenAPI registry unconditionally. Routes using `authenticate: { strategies: ['jwt'] }` or `['basic']` render the correct auth UI as a result.
89
90
 
90
91
  ## Common tasks
91
92
 
@@ -102,10 +103,10 @@ this.bind<IApiReferenceOptions>({
102
103
  key: ApiReferenceBindingKeys.API_REFERENCE_OPTIONS,
103
104
  }).toValue({ restOptions: { base: { path: '/api-docs' } } });
104
105
  ```
105
- Result: UI at `/api-docs/explorer`, spec at `/api-docs/openapi.json` - the group merge keeps `doc.path`/`ui.path` defaults.
106
+ Result: UI at `<app base path>/api-docs/explorer`, spec at `<app base path>/api-docs/openapi.json`. The group merge keeps `doc.path`/`ui.path` defaults.
106
107
 
107
108
  ### Set the info block shown in the UI
108
- `explorer.info` always comes from `package.json` - update `name`, `version`, `description`, and `author` there; binding `explorer.info` directly has no effect.
109
+ `explorer.info` always comes from `package.json`. Update `name`, `version`, `description`, and `author` there - binding `explorer.info` directly has no effect.
109
110
 
110
111
  ### Register a custom UI provider
111
112
  `UIProviderFactory.register()` only understands `'swagger'`/`'scalar'`. Register a custom provider directly on the factory before `ApiReferenceComponent.binding()` runs:
@@ -154,7 +155,7 @@ export interface IApiReferenceOptions {
154
155
  |-----|----------|------|----------|---------|
155
156
  | `@app/api-reference/options` | `ApiReferenceBindingKeys.API_REFERENCE_OPTIONS` | `IApiReferenceOptions` | No | See Options table |
156
157
 
157
- `SwaggerBindingKeys.SWAGGER_OPTIONS` is a deprecated alias whose VALUE is the same `'@app/api-reference/options'` string - there is no separate binding under the literal `'@app/swagger/options'`.
158
+ `SwaggerBindingKeys.SWAGGER_OPTIONS` is removed. It was only ever an alias for the key above - there was never a separate binding under the literal `'@app/swagger/options'`, so nothing needs rebinding.
158
159
 
159
160
  **Default value:**
160
161
  ```typescript
@@ -179,12 +180,12 @@ const DEFAULT_API_REFERENCE_OPTIONS: IApiReferenceOptions = {
179
180
  > The `explorer.info` values above are never used at runtime - `binding()` unconditionally overwrites `explorer.info` from `package.json`. They exist only as structural defaults.
180
181
 
181
182
  ### API endpoints
182
- | Method | Path (default) | Description |
183
+ | Method | Path (default, relative to app base) | Description |
183
184
  |--------|-----------------|-------------|
184
185
  | `GET` | `/doc/explorer` | Documentation UI (Scalar by default) |
185
186
  | `GET` | `/doc/openapi.json` | Raw OpenAPI specification |
186
187
 
187
- Actual paths shift with `restOptions.base.path`, `restOptions.ui.path`, and `restOptions.doc.path`.
188
+ These paths are mounted under your application's own base path - `path.base` in `IApplicationConfigs`. With the `/api` base path from the getting-started guide, that's `GET /api/doc/explorer`. They also shift with `restOptions.base.path`, `restOptions.ui.path`, and `restOptions.doc.path`.
188
189
 
189
190
  ### UIProviderFactory
190
191
  | Method | Signature | Description |
@@ -208,7 +209,7 @@ class DocumentUITypes {
208
209
  }
209
210
  ```
210
211
 
211
- `TDocumentUIType` is derived via `TConstValue`, which extracts the union of every `static readonly` string on `DocumentUITypes` - the type stays in sync with the constants automatically.
212
+ `TDocumentUIType` is derived via `TConstValue`, which extracts the union of every `static readonly` string on `DocumentUITypes`. The type stays in sync with the constants automatically.
212
213
 
213
214
  ### Component lifecycle (`binding()`)
214
215
  1. **Resolve options** - reads `ApiReferenceBindingKeys.API_REFERENCE_OPTIONS` with `isOptional: true`, then merges `base`/`doc`/`ui` each against `DEFAULT_API_REFERENCE_OPTIONS`
@@ -260,8 +261,8 @@ class DocumentUITypes {
260
261
 
261
262
  **Files:**
262
263
 
263
- - [`packages/core/src/components/api-reference/component.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/api-reference/component.ts) - `ApiReferenceComponent`
264
- - [`packages/core/src/components/api-reference/ui-factory.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/api-reference/ui-factory.ts) - `UIProviderFactory`, `SwaggerUIProvider`, `ScalarUIProvider`
265
- - [`packages/core/src/components/api-reference/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/api-reference/common/types.ts) - `IApiReferenceOptions`, `IUIProvider`, `IUIConfig`
266
- - [`packages/core/src/components/api-reference/common/keys.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/api-reference/common/keys.ts) - `ApiReferenceBindingKeys`
267
- - [`packages/core/src/components/api-reference/common/constants.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/api-reference/common/constants.ts) - `DocumentUITypes`
264
+ - [`packages/core-server/src/components/api-reference/component.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/api-reference/component.ts) - `ApiReferenceComponent`
265
+ - [`packages/core-server/src/components/api-reference/ui-factory.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/api-reference/ui-factory.ts) - `UIProviderFactory`, `SwaggerUIProvider`, `ScalarUIProvider`
266
+ - [`packages/core-server/src/components/api-reference/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/api-reference/common/types.ts) - `IApiReferenceOptions`, `IUIProvider`, `IUIConfig`
267
+ - [`packages/core-server/src/components/api-reference/common/keys.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/api-reference/common/keys.ts) - `ApiReferenceBindingKeys`
268
+ - [`packages/core-server/src/components/api-reference/common/constants.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/api-reference/common/constants.ts) - `DocumentUITypes`