@venizia/ignis-docs 0.2.0 → 0.2.1-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/README.md +14 -14
  2. package/content/best-practices/api-usage-examples.md +39 -19
  3. package/content/best-practices/architectural-patterns.md +22 -11
  4. package/content/best-practices/architecture-decisions.md +29 -16
  5. package/content/best-practices/code-style-standards/advanced-patterns.md +43 -31
  6. package/content/best-practices/code-style-standards/constants-configuration.md +19 -4
  7. package/content/best-practices/code-style-standards/control-flow.md +33 -1
  8. package/content/best-practices/code-style-standards/documentation.md +28 -8
  9. package/content/best-practices/code-style-standards/function-patterns.md +15 -4
  10. package/content/best-practices/code-style-standards/index.md +7 -2
  11. package/content/best-practices/code-style-standards/naming-conventions.md +26 -2
  12. package/content/best-practices/code-style-standards/route-definitions.md +9 -5
  13. package/content/best-practices/code-style-standards/tooling.md +14 -1
  14. package/content/best-practices/code-style-standards/type-safety.md +39 -6
  15. package/content/best-practices/common-pitfalls.md +59 -35
  16. package/content/best-practices/contribution-workflow.md +6 -2
  17. package/content/best-practices/data-modeling.md +78 -62
  18. package/content/best-practices/deployment-strategies.md +56 -19
  19. package/content/best-practices/error-handling.md +182 -93
  20. package/content/best-practices/index.md +6 -0
  21. package/content/best-practices/performance-optimization.md +26 -13
  22. package/content/best-practices/security-guidelines.md +35 -9
  23. package/content/best-practices/testing-strategies.md +7 -2
  24. package/content/best-practices/troubleshooting-tips.md +27 -17
  25. package/content/extensions/components/api-reference.md +107 -322
  26. package/content/extensions/components/authentication/api.md +454 -603
  27. package/content/extensions/components/authentication/errors.md +121 -498
  28. package/content/extensions/components/authentication/index.md +88 -801
  29. package/content/extensions/components/authentication/usage.md +207 -956
  30. package/content/extensions/components/authorization/api.md +736 -656
  31. package/content/extensions/components/authorization/errors.md +168 -206
  32. package/content/extensions/components/authorization/index.md +82 -797
  33. package/content/extensions/components/authorization/usage.md +194 -527
  34. package/content/extensions/components/health-check.md +71 -243
  35. package/content/extensions/components/mail/api.md +504 -287
  36. package/content/extensions/components/mail/errors.md +73 -61
  37. package/content/extensions/components/mail/index.md +96 -467
  38. package/content/extensions/components/mail/usage.md +130 -172
  39. package/content/extensions/components/request-tracker.md +66 -173
  40. package/content/extensions/components/socket-io/api.md +195 -13
  41. package/content/extensions/components/socket-io/errors.md +3 -3
  42. package/content/extensions/components/socket-io/index.md +50 -337
  43. package/content/extensions/components/socket-io/usage.md +143 -26
  44. package/content/extensions/components/static-asset/api.md +410 -142
  45. package/content/extensions/components/static-asset/errors.md +110 -53
  46. package/content/extensions/components/static-asset/index.md +79 -608
  47. package/content/extensions/components/static-asset/usage.md +180 -300
  48. package/content/extensions/components/websocket/api.md +275 -399
  49. package/content/extensions/components/websocket/errors.md +47 -56
  50. package/content/extensions/components/websocket/index.md +74 -407
  51. package/content/extensions/components/websocket/usage.md +110 -341
  52. package/content/extensions/helpers/cron/index.md +51 -160
  53. package/content/extensions/helpers/crypto/index.md +62 -483
  54. package/content/extensions/helpers/crypto/reference.md +456 -0
  55. package/content/extensions/helpers/env/index.md +60 -178
  56. package/content/extensions/helpers/error/index.md +221 -207
  57. package/content/extensions/helpers/inversion/index.md +65 -556
  58. package/content/extensions/helpers/inversion/reference.md +522 -0
  59. package/content/extensions/helpers/kafka/admin.md +20 -1
  60. package/content/extensions/helpers/kafka/compile-binary.md +41 -35
  61. package/content/extensions/helpers/kafka/consumer.md +54 -20
  62. package/content/extensions/helpers/kafka/examples.md +21 -16
  63. package/content/extensions/helpers/kafka/index.md +80 -610
  64. package/content/extensions/helpers/kafka/producer.md +134 -5
  65. package/content/extensions/helpers/kafka/schema-registry.md +45 -70
  66. package/content/extensions/helpers/logger/hf-logger.md +193 -0
  67. package/content/extensions/helpers/logger/index.md +64 -563
  68. package/content/extensions/helpers/logger/pino.md +85 -0
  69. package/content/extensions/helpers/logger/reference.md +746 -0
  70. package/content/extensions/helpers/network/api.md +241 -195
  71. package/content/extensions/helpers/network/index.md +72 -530
  72. package/content/extensions/helpers/queue/index.md +72 -900
  73. package/content/extensions/helpers/queue/reference.md +467 -0
  74. package/content/extensions/helpers/redis/index.md +73 -645
  75. package/content/extensions/helpers/redis/reference.md +727 -0
  76. package/content/extensions/helpers/secrets/index.md +66 -0
  77. package/content/extensions/helpers/socket-io/api.md +305 -203
  78. package/content/extensions/helpers/socket-io/index.md +66 -432
  79. package/content/extensions/helpers/storage/api.md +564 -462
  80. package/content/extensions/helpers/storage/index.md +77 -573
  81. package/content/extensions/helpers/types/index.md +66 -499
  82. package/content/extensions/helpers/types/reference.md +650 -0
  83. package/content/extensions/helpers/uid/index.md +58 -227
  84. package/content/extensions/helpers/websocket/api.md +329 -216
  85. package/content/extensions/helpers/websocket/index.md +65 -503
  86. package/content/extensions/helpers/worker-thread/index.md +58 -396
  87. package/content/extensions/helpers/worker-thread/reference.md +428 -0
  88. package/content/guides/core-concepts/persistent/models.md +1 -1
  89. package/content/guides/core-concepts/persistent/search-typesense.md +3 -3
  90. package/content/guides/core-concepts/persistent/transactions.md +1 -1
  91. package/content/guides/core-concepts/secrets-vault.md +177 -0
  92. package/content/guides/core-concepts/services.md +1 -1
  93. package/content/guides/migrations/redis-helpers-migration.md +1 -1
  94. package/content/guides/migrations/unified-connectors-migration.md +2 -2
  95. package/content/guides/tutorials/ecommerce-api.md +3 -8
  96. package/content/references/base/application.md +1 -1
  97. package/content/references/base/connectors.md +79 -136
  98. package/content/references/base/datasources-reference.md +599 -0
  99. package/content/references/base/datasources.md +84 -444
  100. package/content/references/base/dependency-injection.md +17 -39
  101. package/content/references/base/filter-system/application-usage.md +69 -121
  102. package/content/references/base/filter-system/array-operators.md +12 -0
  103. package/content/references/base/filter-system/comparison-operators.md +12 -0
  104. package/content/references/base/filter-system/default-filter.md +136 -348
  105. package/content/references/base/filter-system/fields-order-pagination.md +38 -16
  106. package/content/references/base/filter-system/index.md +106 -257
  107. package/content/references/base/filter-system/json-filtering.md +12 -2
  108. package/content/references/base/filter-system/list-operators.md +16 -2
  109. package/content/references/base/filter-system/logical-operators.md +13 -0
  110. package/content/references/base/filter-system/null-operators.md +13 -0
  111. package/content/references/base/filter-system/pattern-matching.md +12 -0
  112. package/content/references/base/filter-system/quick-reference.md +11 -2
  113. package/content/references/base/filter-system/range-operators.md +12 -0
  114. package/content/references/base/filter-system/tips.md +70 -133
  115. package/content/references/base/filter-system/use-cases.md +156 -233
  116. package/content/references/base/middlewares.md +35 -21
  117. package/content/references/base/models-reference.md +886 -0
  118. package/content/references/base/models.md +80 -1452
  119. package/content/references/base/repositories/advanced.md +156 -192
  120. package/content/references/base/repositories/index.md +77 -650
  121. package/content/references/base/repositories/mixins.md +22 -18
  122. package/content/references/base/repositories/relations.md +123 -171
  123. package/content/references/base/repositories/soft-deletable.md +58 -56
  124. package/content/references/base/secrets.md +263 -0
  125. package/content/references/base/services.md +2 -2
  126. package/content/references/configuration/environment-variables.md +48 -4
  127. package/content/references/configuration/index.md +49 -31
  128. package/content/references/quick-reference.md +3 -16
  129. package/content/references/utilities/crypto.md +35 -76
  130. package/content/references/utilities/date.md +33 -73
  131. package/content/references/utilities/index.md +1 -1
  132. package/content/references/utilities/jsx-reference.md +298 -0
  133. package/content/references/utilities/jsx.md +82 -525
  134. package/content/references/utilities/module.md +29 -62
  135. package/content/references/utilities/parse.md +34 -64
  136. package/content/references/utilities/performance.md +33 -58
  137. package/content/references/utilities/promise.md +28 -62
  138. package/content/references/utilities/request.md +57 -218
  139. package/content/references/utilities/schema.md +43 -137
  140. package/content/references/utilities/statuses-reference.md +361 -0
  141. package/content/references/utilities/statuses.md +63 -667
  142. package/package.json +8 -8
@@ -1,6 +1,6 @@
1
1
  # API Reference
2
2
 
3
- Automatic interactive API documentation generation using OpenAPI specifications, powered by Scalar or Swagger UI.
3
+ Automatic interactive API documentation generated from OpenAPI specs, rendered by a pluggable UI provider - Scalar by default, or classic Swagger UI.
4
4
 
5
5
  > [!NOTE] Renamed from SwaggerComponent
6
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.
@@ -14,7 +14,7 @@ Automatic interactive API documentation generation using OpenAPI specifications,
14
14
  | **UI Factory** | `UIProviderFactory` |
15
15
  | **Runtimes** | Both |
16
16
 
17
- | Provider | Value | When to Use |
17
+ | Provider | Value | When to use |
18
18
  |----------|-------|-------------|
19
19
  | **Scalar** | `'scalar'` | Modern, clean UI (default) |
20
20
  | **Swagger UI** | `'swagger'` | Classic Swagger interface |
@@ -25,31 +25,9 @@ import { ApiReferenceComponent, ApiReferenceBindingKeys, UIProviderFactory } fro
25
25
  import type { IApiReferenceOptions, IUIProvider, IUIConfig, IGetProviderParams } from '@venizia/ignis';
26
26
  ```
27
27
 
28
- ## Setup
28
+ ## In one example
29
29
 
30
- ### Step 1: Bind Configuration (Optional)
31
-
32
- Skip this step to use the defaults (Scalar UI at `/doc/explorer`). To customize:
33
-
34
- ```typescript
35
- // In your Application class's preConfigure method (src/application.ts)
36
- import { ApiReferenceBindingKeys, IApiReferenceOptions } from '@venizia/ignis';
37
-
38
- this.bind<IApiReferenceOptions>({
39
- key: ApiReferenceBindingKeys.API_REFERENCE_OPTIONS,
40
- }).toValue({
41
- restOptions: {
42
- base: { path: '/doc' },
43
- doc: { path: '/openapi.json' },
44
- ui: { path: '/explorer', type: 'swagger' }, // Use Swagger UI instead of Scalar
45
- },
46
- explorer: {
47
- openapi: '3.0.0',
48
- },
49
- });
50
- ```
51
-
52
- ### Step 2: Register Component
30
+ Register the component - the docs UI comes up at `/doc/explorer`, the raw spec at `/doc/openapi.json`. No configuration required.
53
31
 
54
32
  ```typescript
55
33
  // src/application.ts
@@ -57,15 +35,12 @@ import { ApiReferenceComponent, BaseApplication, ValueOrPromise } from '@venizia
57
35
 
58
36
  export class Application extends BaseApplication {
59
37
  preConfigure(): ValueOrPromise<void> {
60
- // ...
61
38
  this.component(ApiReferenceComponent);
62
39
  }
63
40
  }
64
41
  ```
65
42
 
66
- ### Step 3: Define Routes with Zod Schemas
67
-
68
- To get the most out of the documentation, define your routes with `zod` schemas:
43
+ Define routes with Zod schemas so they show up in the generated spec:
69
44
 
70
45
  ```typescript
71
46
  // src/controllers/hello.controller.ts
@@ -100,45 +75,64 @@ export class HelloController extends BaseRestController {
100
75
  ```
101
76
 
102
77
  > [!TIP]
103
- > Controllers using `defineRoute` with Zod schemas automatically generate OpenAPI specs. The Swagger component discovers all registered controller routes and renders them in the documentation UI.
78
+ > Only routes registered through `defineRoute`, `bindRoute`, or `@api()` with `@hono/zod-openapi` schemas appear in the generated spec.
104
79
 
105
- ## Configuration
80
+ ## How it works
106
81
 
107
- | Option | Type | Default | Description |
108
- |--------|------|---------|-------------|
109
- | `restOptions.base.path` | `string` | `'/doc'` | Base path for all documentation routes |
110
- | `restOptions.doc.path` | `string` | `'/openapi.json'` | Path to the raw OpenAPI spec (relative to base) |
111
- | `restOptions.ui.path` | `string` | `'/explorer'` | Path to the documentation UI (relative to base) |
112
- | `restOptions.ui.type` | `'swagger' \| 'scalar'` | `'scalar'` | UI provider type |
113
- | `explorer.openapi` | `string` | `'3.0.0'` | OpenAPI specification version |
114
- | `uiConfig` | `Record<string, any>` | `undefined` | Custom config passed to the UI provider |
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.
115
89
 
116
- > [!IMPORTANT]
117
- > The `explorer.info` field is **always overwritten** during the component's `binding()` phase. The component unconditionally reads your application's `package.json` via `application.getAppInfo()` and sets `explorer.info` to `{ title, version, description, contact }` from that data. Any user-provided `explorer.info` values are discarded. If you need to customize these fields, update your `package.json` instead.
90
+ ## Common tasks
118
91
 
119
- > [!NOTE]
120
- > The `explorer.servers` field is auto-populated only when empty. If you provide `explorer.servers` with at least one entry, the component preserves your values. When no servers are configured, it creates a default entry from `application.getServerAddress()` plus the application base path.
92
+ ### Switch to Swagger UI
93
+ ```typescript
94
+ this.bind<IApiReferenceOptions>({
95
+ key: ApiReferenceBindingKeys.API_REFERENCE_OPTIONS,
96
+ }).toValue({ restOptions: { ui: { type: 'swagger' } } });
97
+ ```
121
98
 
122
- #### IApiReferenceOptions -- Full Reference
99
+ ### Move the docs under a different base path
100
+ ```typescript
101
+ this.bind<IApiReferenceOptions>({
102
+ key: ApiReferenceBindingKeys.API_REFERENCE_OPTIONS,
103
+ }).toValue({ restOptions: { base: { path: '/api-docs' } } });
104
+ ```
105
+ Result: UI at `/api-docs/explorer`, spec at `/api-docs/openapi.json` - the group merge keeps `doc.path`/`ui.path` defaults.
106
+
107
+ ### 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
+
110
+ ### Register a custom UI provider
111
+ `UIProviderFactory.register()` only understands `'swagger'`/`'scalar'`. Register a custom provider directly on the factory before `ApiReferenceComponent.binding()` runs:
112
+
113
+ ```typescript
114
+ UIProviderFactory.getInstance().set('my-ui', new MyCustomUIProvider());
115
+ ```
116
+
117
+ ## Reference
118
+
119
+ ### Options
123
120
  ```typescript
124
121
  export interface IApiReferenceOptions {
125
- restOptions: {
126
- base: { path: string };
127
- doc: { path: string };
128
- ui: { path: string; type: TDocumentUIType };
122
+ restOptions?: {
123
+ base?: { path?: string };
124
+ doc?: { path?: string };
125
+ ui?: { path?: string; type?: TDocumentUIType };
129
126
  };
130
- explorer: {
131
- openapi: string;
127
+ explorer?: {
128
+ openapi?: string;
132
129
  info?: {
133
130
  title: string;
134
131
  version: string;
135
132
  description: string;
136
133
  contact?: { name: string; email: string };
137
134
  };
138
- servers?: Array<{
139
- url: string;
140
- description?: string;
141
- }>;
135
+ servers?: Array<{ url: string; description?: string }>;
142
136
  };
143
137
  uiConfig?: Record<string, any>;
144
138
  }
@@ -151,194 +145,18 @@ export interface IApiReferenceOptions {
151
145
  | `restOptions.ui.path` | `string` | `'/explorer'` | Path to the documentation UI (relative to base) |
152
146
  | `restOptions.ui.type` | `'swagger' \| 'scalar'` | `'scalar'` | UI provider type |
153
147
  | `explorer.openapi` | `string` | `'3.0.0'` | OpenAPI specification version |
154
- | `explorer.info.title` | `string` | Always from `package.json` `name` | API title (overwritten at runtime) |
155
- | `explorer.info.version` | `string` | Always from `package.json` `version` | API version (overwritten at runtime) |
156
- | `explorer.info.description` | `string` | Always from `package.json` `description` | API description (overwritten at runtime) |
157
- | `explorer.info.contact` | `{ name, email }` | Always from `package.json` `author` | Contact information (overwritten at runtime) |
148
+ | `explorer.info.title` / `.version` / `.description` / `.contact` | - | Always sourced from `package.json` | Overwritten at runtime - binding values are discarded |
158
149
  | `explorer.servers` | `Array<{ url, description? }>` | Auto-detected when empty | Server URLs |
159
- | `uiConfig` | `Record<string, any>` | `undefined` | Custom config passed to the UI provider |
160
-
161
- #### IGetProviderParams Interface
162
-
163
- The `IGetProviderParams` interface is used by `UIProviderFactory.getProvider()` and `UIProviderFactory.register()`:
164
-
165
- ```typescript
166
- export interface IGetProviderParams {
167
- type: string;
168
- }
169
- ```
170
-
171
- This interface is exported for use when building custom tooling around the `UIProviderFactory` -- for example, programmatically querying which providers are available or registering providers in tests.
172
-
173
- ### Tech Stack
174
-
175
- | Library | Purpose |
176
- |---------|---------|
177
- | `@hono/zod-openapi` | OpenAPI generation from Zod schemas |
178
- | `@hono/swagger-ui` | Swagger UI rendering |
179
- | `@scalar/hono-api-reference` | Scalar UI rendering |
180
- | `zod` | Schema validation and type generation |
181
-
182
- > [!TIP]
183
- > The component also auto-registers JWT (`bearer`) and Basic security schemes in the OpenAPI spec, so authenticated endpoints display the correct auth UI in the documentation.
184
-
185
- ## Architecture
186
-
187
- ### Component Lifecycle
188
-
189
- The `ApiReferenceComponent` executes the following during `binding()`:
190
-
191
- 1. **Resolve options** -- reads `ApiReferenceBindingKeys.API_REFERENCE_OPTIONS` from DI using `application.get()` with `isOptional: true`, then deep-merges what it finds over `DEFAULT_API_REFERENCE_OPTIONS` group by group, so an application that overrides one path keeps the defaults for the rest
192
- 2. **Overwrite info** -- unconditionally reads `package.json` via `application.getAppInfo()` and overwrites `explorer.info` with `{ title: appInfo.name, version: appInfo.version, description: appInfo.description, contact: appInfo.author }`
193
- 3. **Auto-detect servers** -- if `explorer.servers` is empty or unset, creates one entry from `http://` + `application.getServerAddress()` + `configs.path.base`
194
- 4. **Normalize paths** -- all path segments (`base.path`, `doc.path`, `ui.path`) are normalized to ensure a leading `/` is present, handling both `/path` and `path` inputs
195
- 5. **Register OpenAPI doc route** -- calls `rootRouter.doc(docPath, explorer)` to register the raw JSON endpoint
196
- 6. **Resolve UI type with fallback** -- evaluates `restOptions.ui.type || DocumentUITypes.SWAGGER`. Note: this means a falsy value (empty string) falls back to `'swagger'`, not `'scalar'`
197
- 7. **Validate UI type** -- checks the resolved type against `DocumentUITypes.SCHEME_SET`, throws if invalid
198
- 8. **Register UI provider** -- calls `UIProviderFactory.register({ type })` to instantiate the UI renderer
199
- 9. **Construct docUrl** -- builds the full documentation URL by joining `configs.path.base`, `configs.basePath`, and the computed `docPath`
200
- 10. **Register UI route** -- creates `GET` handler at `uiPath` that calls `uiProvider.render()` with `{ title: appInfo.name, url: docUrl, ...uiConfig }`
201
- 11. **Register security schemes** -- auto-registers JWT (bearer) and Basic security schemes in the OpenAPI registry
202
-
203
- ### Architecture Components
204
-
205
- | Component | Class | Role |
206
- |-----------|-------|------|
207
- | **ApiReferenceComponent** | `extends BaseComponent` | Orchestrates binding, overwrites OpenAPI metadata from `package.json` |
208
- | **UIProviderFactory** | `extends MemoryStorageHelper` (singleton) | Registry for UI providers, validates and instantiates |
209
- | **SwaggerUIProvider** | `implements IUIProvider` | Renders Swagger UI via `@hono/swagger-ui` |
210
- | **ScalarUIProvider** | `implements IUIProvider` | Renders Scalar UI via `@scalar/hono-api-reference` |
211
-
212
- #### UIProviderFactory and MemoryStorageHelper
213
-
214
- `UIProviderFactory` extends `MemoryStorageHelper<{ [key: string | symbol]: IUIProvider }>`, which provides a simple in-memory key-value store with the following methods used internally:
215
-
216
- - `isBound(key)` -- checks if a provider type is already registered
217
- - `get(key)` -- retrieves a registered provider instance
218
- - `set(key, value)` -- stores a provider instance
219
- - `keys()` -- lists all registered provider type keys
220
-
221
- This gives the factory a lightweight, type-safe storage backend without requiring the full DI container.
222
-
223
- #### Lazy Dynamic Imports
224
-
225
- Both `SwaggerUIProvider` and `ScalarUIProvider` use `await import()` inside their `render()` method to load the underlying UI library:
226
-
227
- ```typescript
228
- // SwaggerUIProvider
229
- async render(context, config, next) {
230
- const { swaggerUI } = await import('@hono/swagger-ui');
231
- // ...
232
- }
233
-
234
- // ScalarUIProvider
235
- async render(context, config, next) {
236
- const { Scalar } = await import('@scalar/hono-api-reference');
237
- // ...
238
- }
239
- ```
240
-
241
- This means UI libraries are loaded on the **first HTTP request** to the documentation endpoint, not at application startup. This keeps startup time fast and avoids loading unused UI libraries (only the configured provider's library is ever imported).
242
-
243
- #### ScalarUIProvider Title Mapping
244
-
245
- The `ScalarUIProvider` maps the `title` field to `pageTitle` when calling the Scalar renderer:
246
-
247
- ```typescript
248
- const { title, url, ...customConfig } = config;
249
- return Scalar({ url, pageTitle: title, ...customConfig })(context, next);
250
- ```
251
-
252
- This is a quirk to be aware of if you are inspecting the rendered output or writing custom UI providers -- Scalar uses `pageTitle` instead of `title`.
253
-
254
- ### UIProviderFactory API
255
-
256
- | Method | Signature | Description |
257
- |--------|-----------|-------------|
258
- | `getInstance()` | `static () => UIProviderFactory` | Returns singleton instance |
259
- | `register()` | `(opts: { type: string }) => void` | Instantiates and registers a UI provider (idempotent) |
260
- | `getProvider()` | `(opts: IGetProviderParams) => IUIProvider` | Returns registered provider or throws |
261
- | `getRegisteredProviders()` | `() => string[]` | Lists all registered provider type keys |
262
-
263
- #### register() Idempotency
264
-
265
- The `register()` method is idempotent. If a provider of the given type is already registered, it logs a warning and returns without error:
266
-
267
- ```typescript
268
- register(opts: { type: string }): void {
269
- if (this.isBound(opts.type)) {
270
- this.logger
271
- .for(this.register.name)
272
- .warn('Skip registering BOUNDED Document UI | type: %s', opts.type);
273
- return;
274
- }
275
- // ... instantiate and store the provider
276
- }
277
- ```
278
-
279
- This means calling `register({ type: 'scalar' })` multiple times is safe and will not create duplicate provider instances.
280
-
281
- ### IUIProvider Interface
282
-
283
- ```typescript
284
- interface IUIProvider {
285
- render(context: Context, config: IUIConfig, next: Next): Promise<Response | void>;
286
- }
287
-
288
- interface IUIConfig {
289
- title: string; // App name from package.json
290
- url: string; // Full URL to OpenAPI JSON endpoint
291
- [key: string]: any; // Additional config from uiConfig option
292
- }
293
- ```
294
-
295
- ### Security Scheme Registration
296
-
297
- The component auto-registers two OpenAPI security schemes:
298
-
299
- ```typescript
300
- // JWT Bearer
301
- rootRouter.openAPIRegistry.registerComponent('securitySchemes', 'jwt', {
302
- type: 'http',
303
- scheme: 'bearer',
304
- bearerFormat: 'JWT',
305
- });
306
-
307
- // Basic Auth
308
- rootRouter.openAPIRegistry.registerComponent('securitySchemes', 'basic', {
309
- type: 'http',
310
- scheme: 'basic',
311
- });
312
- ```
313
-
314
- This ensures routes using `authStrategies: ['jwt']` or `authStrategies: ['basic']` display the correct auth UI (lock icon + input fields) in the documentation.
315
-
316
- ## Binding Keys
150
+ | `uiConfig` | `Record<string, any>` | `undefined` | Custom config passed through to the UI provider |
317
151
 
152
+ ### Binding keys
318
153
  | Key | Constant | Type | Required | Default |
319
154
  |-----|----------|------|----------|---------|
320
- | `@app/api-reference/options` | `ApiReferenceBindingKeys.API_REFERENCE_OPTIONS` | `IApiReferenceOptions` | No | See below |
321
-
322
- The deprecated `SwaggerBindingKeys.SWAGGER_OPTIONS` still resolves - it is an alias whose **value** is that same `'@app/api-reference/options'` string. There is no binding under the literal `'@app/swagger/options'`; binding that raw string does nothing.
155
+ | `@app/api-reference/options` | `ApiReferenceBindingKeys.API_REFERENCE_OPTIONS` | `IApiReferenceOptions` | No | See Options table |
323
156
 
324
- The constructor registers the default through `super()`, so the binding is in the container from the start:
325
-
326
- ```typescript
327
- super({
328
- scope: ApiReferenceComponent.name,
329
- initDefault: { enable: true, container: application },
330
- bindings: {
331
- [ApiReferenceBindingKeys.API_REFERENCE_OPTIONS]: Binding.bind<IApiReferenceOptions>({
332
- key: ApiReferenceBindingKeys.API_REFERENCE_OPTIONS,
333
- }).toValue(DEFAULT_API_REFERENCE_OPTIONS),
334
- },
335
- });
336
- ```
337
-
338
- `binding()` then reads the key back with `isOptional: true` and **deep-merges** whatever the application bound over the defaults, group by group (`base`, `doc`, `ui`, `explorer`) - so overriding one path does not wipe the others. The merge builds a fresh `explorer` object per application; mutating the bound one would leak this application's info into every later application in the same process.
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'`.
339
158
 
340
159
  **Default value:**
341
-
342
160
  ```typescript
343
161
  const DEFAULT_API_REFERENCE_OPTIONS: IApiReferenceOptions = {
344
162
  restOptions: {
@@ -358,10 +176,27 @@ const DEFAULT_API_REFERENCE_OPTIONS: IApiReferenceOptions = {
358
176
  ```
359
177
 
360
178
  > [!NOTE]
361
- > The `explorer.info` values in `DEFAULT_API_REFERENCE_OPTIONS` are never used at runtime because `binding()` unconditionally overwrites `explorer.info` with data from `package.json`. They exist only as structural defaults.
179
+ > The `explorer.info` values above are never used at runtime - `binding()` unconditionally overwrites `explorer.info` from `package.json`. They exist only as structural defaults.
362
180
 
363
- ### Type Definitions
181
+ ### API endpoints
182
+ | Method | Path (default) | Description |
183
+ |--------|-----------------|-------------|
184
+ | `GET` | `/doc/explorer` | Documentation UI (Scalar by default) |
185
+ | `GET` | `/doc/openapi.json` | Raw OpenAPI specification |
364
186
 
187
+ Actual paths shift with `restOptions.base.path`, `restOptions.ui.path`, and `restOptions.doc.path`.
188
+
189
+ ### UIProviderFactory
190
+ | Method | Signature | Description |
191
+ |--------|-----------|-------------|
192
+ | `getInstance()` | `static () => UIProviderFactory` | Returns the singleton instance |
193
+ | `register()` | `(opts: { type: string }) => void` | Instantiates and registers a built-in provider; idempotent - warns and returns if the type is already bound |
194
+ | `getProvider()` | `(opts: IGetProviderParams) => IUIProvider` | Returns the registered provider or throws `Unknown UI Provider` |
195
+ | `getRegisteredProviders()` | `() => string[]` | Lists all registered provider type keys |
196
+
197
+ Extends `MemoryStorageHelper<{ [key: string | symbol]: IUIProvider }>`, using `isBound()` / `get()` / `set()` / `keys()` for lightweight, type-safe storage without the full DI container.
198
+
199
+ ### Type definitions
365
200
  ```typescript
366
201
  type TDocumentUIType = TConstValue<typeof DocumentUITypes>;
367
202
 
@@ -373,96 +208,38 @@ class DocumentUITypes {
373
208
  }
374
209
  ```
375
210
 
376
- `TDocumentUIType` is derived via `TConstValue`, which extracts the union of all `static readonly` string values from `DocumentUITypes`. This ensures the type stays in sync with the constants automatically.
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.
377
212
 
378
- ## API Endpoints
213
+ ### Component lifecycle (`binding()`)
214
+ 1. **Resolve options** - reads `ApiReferenceBindingKeys.API_REFERENCE_OPTIONS` with `isOptional: true`, then merges `base`/`doc`/`ui` each against `DEFAULT_API_REFERENCE_OPTIONS`
215
+ 2. **Overwrite info** - reads `package.json` via `application.getAppInfo()` and replaces `explorer.info`
216
+ 3. **Auto-detect servers** - builds one entry from `application.getServerAddress()` when `explorer.servers` is empty
217
+ 4. **Normalize paths** - ensures every path segment (`base.path`, `doc.path`, `ui.path`) has a leading `/`
218
+ 5. **Register the OpenAPI doc route** - `rootRouter.doc(docPath, explorer)`
219
+ 6. **Resolve `uiType`** - `restOptions.ui.type ?? DocumentUITypes.SWAGGER`
220
+ 7. **Validate and register the UI provider** - via `UIProviderFactory`, unless a provider with that type is already bound
221
+ 8. **Register the UI route** - `GET` handler at `uiPath` calling `uiProvider.render()`
222
+ 9. **Register JWT and Basic security schemes** on the OpenAPI registry
379
223
 
380
- | Method | Path | Description |
381
- |--------|------|-------------|
382
- | `GET` | `/doc/explorer` | Documentation UI (Scalar by default) |
383
- | `GET` | `/doc/openapi.json` | Raw OpenAPI specification |
384
-
385
- > [!NOTE]
386
- > These paths are based on the default configuration. If you customize `restOptions.base.path`, `restOptions.ui.path`, or `restOptions.doc.path`, the actual endpoints change accordingly.
387
-
388
- ### Documentation UI Endpoint
389
-
390
- **Default path:** `/doc/explorer`
391
-
392
- Renders an interactive API documentation page using the configured UI provider (Scalar or Swagger UI). The UI fetches the OpenAPI spec from the JSON endpoint and renders it with full request/response exploration, authentication controls, and try-it-out functionality.
393
-
394
- ### OpenAPI JSON Endpoint
395
-
396
- **Default path:** `/doc/openapi.json`
397
-
398
- Returns the raw OpenAPI JSON specification generated from all registered controller routes and their Zod schemas. This endpoint can be used by:
399
- - External API testing tools (Postman, Insomnia)
400
- - CI pipelines for API contract validation
401
- - Client SDK generators (openapi-generator, orval)
402
- - API gateway configuration
224
+ ### Tech stack
225
+ | Library | Purpose |
226
+ |---------|---------|
227
+ | `@hono/zod-openapi` | OpenAPI generation from Zod schemas |
228
+ | `@hono/swagger-ui` | Swagger UI rendering |
229
+ | `@scalar/hono-api-reference` | Scalar UI rendering |
230
+ | `zod` | Schema validation and type generation |
403
231
 
404
232
  ## Troubleshooting
405
233
 
406
- ### "Invalid document UI Type"
407
-
408
- **Cause:** The `restOptions.ui.type` value is not `'swagger'` or `'scalar'`. The `UIProviderFactory` only recognizes these two built-in providers. Note that a falsy value (empty string, `undefined`) does not trigger this error -- it silently falls back to `'swagger'` due to the `||` operator, not to the default `'scalar'`.
409
-
410
- **Fix:** Use a valid UI type:
411
-
412
- ```typescript
413
- this.bind<IApiReferenceOptions>({
414
- key: ApiReferenceBindingKeys.API_REFERENCE_OPTIONS,
415
- }).toValue({
416
- restOptions: {
417
- base: { path: '/doc' },
418
- doc: { path: '/openapi.json' },
419
- ui: { path: '/explorer', type: 'scalar' }, // 'scalar' or 'swagger'
420
- },
421
- explorer: { openapi: '3.0.0' },
422
- });
423
- ```
424
-
425
- ### Documentation UI shows no routes
426
-
427
- **Cause:** Controllers are not defining routes with Zod schemas via `defineRoute` or `bindRoute`. Only routes registered through `@hono/zod-openapi` appear in the OpenAPI spec.
428
-
429
- **Fix:** Use `defineRoute` with Zod response schemas in your controllers:
430
-
431
- ```typescript
432
- this.defineRoute({
433
- configs: {
434
- path: '/',
435
- method: 'get',
436
- responses: {
437
- 200: jsonContent({
438
- description: 'Success',
439
- schema: z.object({ message: z.string() }),
440
- }),
441
- },
442
- },
443
- handler: (c) => c.json({ message: 'ok' }, 200),
444
- });
445
- ```
446
-
447
- ### "Unknown UI Provider"
234
+ | Symptom | Cause | Fix |
235
+ |---------|-------|-----|
236
+ | `Invalid document UI Type` | `restOptions.ui.type` is not `'swagger'` or `'scalar'` - an explicit empty string is NOT repaired by the `??` fallback | Use `'scalar'` or `'swagger'` explicitly |
237
+ | Documentation UI shows no routes | Controllers aren't defining routes with Zod schemas via `defineRoute`, `bindRoute`, or `@api()` | Add Zod response schemas to your route configs |
238
+ | `Unknown UI Provider` | `UIProviderFactory.getProvider()` was called with a type that was never registered - usually a failed `binding()` | Ensure `ApiReferenceComponent` is registered in `preConfigure()`; check logs for warnings during binding |
239
+ | OpenAPI spec missing authentication schemes | `AuthenticationComponent` isn't registered, so auth strategies aren't available when schemes are added | Register `AuthenticationComponent` before `ApiReferenceComponent` in `preConfigure()` |
240
+ | `explorer.info` doesn't match my binding | `explorer.info` is always overwritten from `package.json` during `binding()` | Update `package.json` fields (`name`, `version`, `description`, `author`) instead |
448
241
 
449
- **Cause:** The `UIProviderFactory.getProvider()` was called with a type that has not been registered. This typically happens if the component binding phase failed silently.
450
-
451
- **Fix:** Ensure the `ApiReferenceComponent` is registered in `preConfigure()` and that no errors occur during its `binding()` phase. Check the application logs for warnings from `UIProviderFactory`.
452
-
453
- ### OpenAPI spec missing authentication schemes
454
-
455
- **Cause:** The `ApiReferenceComponent` auto-registers JWT and Basic security schemes. If the `AuthenticationComponent` is not registered, authenticated routes will not show auth UI in the documentation.
456
-
457
- **Fix:** Register `AuthenticationComponent` before `ApiReferenceComponent` in `preConfigure()` to ensure auth strategies are available when the Swagger component configures security schemes.
458
-
459
- ### explorer.info values not matching custom configuration
460
-
461
- **Cause:** The `ApiReferenceComponent` unconditionally overwrites `explorer.info` with values from `package.json` during its `binding()` phase. Any values you set in `explorer.info` via the DI binding are discarded.
462
-
463
- **Fix:** Update your project's `package.json` fields (`name`, `version`, `description`, `author`) to control what appears in the API documentation info section. The component reads these via `application.getAppInfo()`.
464
-
465
- ## See Also
242
+ ## See also
466
243
 
467
244
  - **Guides:**
468
245
  - [Components Overview](/guides/core-concepts/components) - Component system basics
@@ -480,3 +257,11 @@ this.defineRoute({
480
257
  - [OpenAPI Specification](https://swagger.io/specification/) - OpenAPI standard
481
258
  - [Scalar Documentation](https://github.com/scalar/scalar) - Scalar API documentation UI
482
259
  - [@hono/zod-openapi](https://github.com/honojs/middleware/tree/main/packages/zod-openapi) - Hono OpenAPI integration
260
+
261
+ **Files:**
262
+
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`