@venizia/ignis-docs 0.2.0 → 0.2.1-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) 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 +24 -13
  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 +27 -3
  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 +8 -4
  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 +247 -153
  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 +109 -323
  26. package/content/extensions/components/authentication/api.md +489 -602
  27. package/content/extensions/components/authentication/errors.md +135 -498
  28. package/content/extensions/components/authentication/index.md +89 -801
  29. package/content/extensions/components/authentication/usage.md +231 -955
  30. package/content/extensions/components/authorization/api.md +991 -644
  31. package/content/extensions/components/authorization/errors.md +204 -208
  32. package/content/extensions/components/authorization/getting-started.md +227 -0
  33. package/content/extensions/components/authorization/index.md +88 -795
  34. package/content/extensions/components/authorization/usage.md +219 -528
  35. package/content/extensions/components/health-check.md +77 -243
  36. package/content/extensions/components/index.md +24 -90
  37. package/content/extensions/components/mail/api.md +553 -285
  38. package/content/extensions/components/mail/errors.md +76 -62
  39. package/content/extensions/components/mail/index.md +111 -463
  40. package/content/extensions/components/mail/usage.md +139 -173
  41. package/content/extensions/components/request-tracker.md +70 -173
  42. package/content/extensions/components/socket-io/api.md +462 -785
  43. package/content/extensions/components/socket-io/errors.md +49 -51
  44. package/content/extensions/components/socket-io/index.md +69 -372
  45. package/content/extensions/components/socket-io/usage.md +212 -105
  46. package/content/extensions/components/static-asset/api.md +461 -141
  47. package/content/extensions/components/static-asset/errors.md +121 -53
  48. package/content/extensions/components/static-asset/index.md +84 -606
  49. package/content/extensions/components/static-asset/usage.md +184 -299
  50. package/content/extensions/components/template/index.md +3 -3
  51. package/content/extensions/components/websocket/api.md +311 -404
  52. package/content/extensions/components/websocket/errors.md +47 -56
  53. package/content/extensions/components/websocket/index.md +75 -407
  54. package/content/extensions/components/websocket/usage.md +120 -338
  55. package/content/extensions/helpers/cron/index.md +52 -160
  56. package/content/extensions/helpers/crypto/index.md +67 -480
  57. package/content/extensions/helpers/crypto/reference.md +528 -0
  58. package/content/extensions/helpers/env/index.md +64 -178
  59. package/content/extensions/helpers/error/index.md +286 -196
  60. package/content/extensions/helpers/index.md +61 -47
  61. package/content/extensions/helpers/inversion/index.md +76 -550
  62. package/content/extensions/helpers/inversion/reference.md +530 -0
  63. package/content/extensions/helpers/kafka/admin.md +23 -3
  64. package/content/extensions/helpers/kafka/compile-binary.md +83 -52
  65. package/content/extensions/helpers/kafka/consumer.md +65 -28
  66. package/content/extensions/helpers/kafka/examples.md +46 -253
  67. package/content/extensions/helpers/kafka/index.md +55 -617
  68. package/content/extensions/helpers/kafka/producer.md +156 -22
  69. package/content/extensions/helpers/kafka/schema-registry.md +59 -79
  70. package/content/extensions/helpers/logger/hf-logger.md +220 -0
  71. package/content/extensions/helpers/logger/index.md +78 -552
  72. package/content/extensions/helpers/logger/pino.md +105 -0
  73. package/content/extensions/helpers/logger/reference.md +937 -0
  74. package/content/extensions/helpers/network/api.md +276 -195
  75. package/content/extensions/helpers/network/index.md +87 -524
  76. package/content/extensions/helpers/queue/index.md +80 -897
  77. package/content/extensions/helpers/queue/reference.md +494 -0
  78. package/content/extensions/helpers/redis/index.md +86 -640
  79. package/content/extensions/helpers/redis/reference.md +784 -0
  80. package/content/extensions/helpers/secrets/index.md +136 -0
  81. package/content/extensions/helpers/socket-io/api.md +325 -204
  82. package/content/extensions/helpers/socket-io/index.md +79 -429
  83. package/content/extensions/helpers/storage/api.md +584 -464
  84. package/content/extensions/helpers/storage/index.md +80 -573
  85. package/content/extensions/helpers/types/index.md +75 -495
  86. package/content/extensions/helpers/types/reference.md +689 -0
  87. package/content/extensions/helpers/uid/index.md +176 -189
  88. package/content/extensions/helpers/websocket/api.md +366 -214
  89. package/content/extensions/helpers/websocket/index.md +68 -503
  90. package/content/extensions/helpers/worker-thread/index.md +62 -396
  91. package/content/extensions/helpers/worker-thread/reference.md +428 -0
  92. package/content/extensions/index.md +38 -39
  93. package/content/extensions/src-details/mcp-server.md +96 -548
  94. package/content/guides/core-concepts/persistent/datasources.md +2 -2
  95. package/content/guides/core-concepts/persistent/index.md +5 -1
  96. package/content/guides/core-concepts/persistent/models.md +1 -1
  97. package/content/guides/core-concepts/persistent/pglite.md +218 -0
  98. package/content/guides/core-concepts/persistent/postgres-drivers.md +21 -15
  99. package/content/guides/core-concepts/persistent/search-meilisearch.md +22 -12
  100. package/content/guides/core-concepts/persistent/search-typesense.md +28 -16
  101. package/content/guides/core-concepts/persistent/sqlite.md +296 -0
  102. package/content/guides/core-concepts/persistent/transactions.md +12 -11
  103. package/content/guides/core-concepts/secrets-vault.md +177 -0
  104. package/content/guides/core-concepts/services.md +1 -1
  105. package/content/guides/get-started/5-minute-quickstart.md +59 -206
  106. package/content/guides/get-started/philosophy.md +135 -670
  107. package/content/guides/get-started/setup.md +53 -74
  108. package/content/guides/migrations/redis-helpers-migration.md +5 -4
  109. package/content/guides/migrations/scoped-rbac-migration.md +5 -5
  110. package/content/guides/migrations/unified-connectors-migration.md +8 -7
  111. package/content/guides/tutorials/ecommerce-api.md +3 -8
  112. package/content/guides/tutorials/realtime-chat.md +1 -1
  113. package/content/references/base/application.md +64 -22
  114. package/content/references/base/components.md +3 -3
  115. package/content/references/base/connectors.md +79 -136
  116. package/content/references/base/controllers.md +12 -12
  117. package/content/references/base/datasources-reference.md +600 -0
  118. package/content/references/base/datasources.md +84 -444
  119. package/content/references/base/dependency-injection.md +25 -46
  120. package/content/references/base/filter-system/application-usage.md +95 -123
  121. package/content/references/base/filter-system/array-operators.md +33 -43
  122. package/content/references/base/filter-system/comparison-operators.md +55 -63
  123. package/content/references/base/filter-system/default-filter.md +144 -350
  124. package/content/references/base/filter-system/fields-order-pagination.md +116 -148
  125. package/content/references/base/filter-system/index.md +114 -253
  126. package/content/references/base/filter-system/json-filtering.md +52 -181
  127. package/content/references/base/filter-system/list-operators.md +28 -44
  128. package/content/references/base/filter-system/logical-operators.md +69 -114
  129. package/content/references/base/filter-system/null-operators.md +41 -98
  130. package/content/references/base/filter-system/pattern-matching.md +48 -51
  131. package/content/references/base/filter-system/quick-reference.md +93 -196
  132. package/content/references/base/filter-system/range-operators.md +22 -38
  133. package/content/references/base/filter-system/tips.md +70 -133
  134. package/content/references/base/filter-system/use-cases.md +173 -232
  135. package/content/references/base/grpc-controllers.md +53 -17
  136. package/content/references/base/index.md +5 -3
  137. package/content/references/base/middlewares.md +43 -28
  138. package/content/references/base/models-reference.md +886 -0
  139. package/content/references/base/models.md +81 -1452
  140. package/content/references/base/providers.md +8 -8
  141. package/content/references/base/repositories/advanced.md +281 -419
  142. package/content/references/base/repositories/index.md +84 -644
  143. package/content/references/base/repositories/mixins.md +25 -21
  144. package/content/references/base/repositories/relations.md +194 -375
  145. package/content/references/base/repositories/soft-deletable.md +67 -55
  146. package/content/references/base/secrets.md +267 -0
  147. package/content/references/base/services.md +8 -6
  148. package/content/references/configuration/environment-variables.md +73 -21
  149. package/content/references/configuration/index.md +51 -31
  150. package/content/references/index.md +1 -1
  151. package/content/references/quick-reference.md +3 -16
  152. package/content/references/utilities/crypto.md +35 -76
  153. package/content/references/utilities/date.md +33 -73
  154. package/content/references/utilities/duration.md +85 -0
  155. package/content/references/utilities/index.md +6 -2
  156. package/content/references/utilities/jsx-reference.md +298 -0
  157. package/content/references/utilities/jsx.md +82 -525
  158. package/content/references/utilities/module.md +81 -61
  159. package/content/references/utilities/parse.md +34 -64
  160. package/content/references/utilities/performance.md +33 -58
  161. package/content/references/utilities/promise.md +28 -62
  162. package/content/references/utilities/request.md +58 -218
  163. package/content/references/utilities/retry.md +139 -0
  164. package/content/references/utilities/schema.md +43 -137
  165. package/content/references/utilities/statuses-reference.md +361 -0
  166. package/content/references/utilities/statuses.md +63 -667
  167. package/dist/mcp-server/index.js +0 -0
  168. package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
  169. package/dist/mcp-server/tools/github/list-project-files.tool.d.ts.map +1 -1
  170. package/dist/mcp-server/tools/github/list-project-files.tool.js +3 -3
  171. package/dist/mcp-server/tools/github/search-code.tool.js +1 -1
  172. package/dist/mcp-server/tools/github/verify-dependencies.tool.js +1 -1
  173. package/dist/mcp-server/tools/github/view-source-file.tool.js +1 -1
  174. package/package.json +24 -23
@@ -1,9 +1,9 @@
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 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
 
@@ -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 - 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`.
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,65 @@ 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 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.
115
90
 
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.
91
+ ## Common tasks
118
92
 
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.
93
+ ### Switch to Swagger UI
94
+ ```typescript
95
+ this.bind<IApiReferenceOptions>({
96
+ key: ApiReferenceBindingKeys.API_REFERENCE_OPTIONS,
97
+ }).toValue({ restOptions: { ui: { type: 'swagger' } } });
98
+ ```
121
99
 
122
- #### IApiReferenceOptions -- Full Reference
100
+ ### Move the docs under a different base path
101
+ ```typescript
102
+ this.bind<IApiReferenceOptions>({
103
+ key: ApiReferenceBindingKeys.API_REFERENCE_OPTIONS,
104
+ }).toValue({ restOptions: { base: { path: '/api-docs' } } });
105
+ ```
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.
107
+
108
+ ### Set the info block shown in the UI
109
+ `explorer.info` always comes from `package.json`. Update `name`, `version`, `description`, and `author` there - binding `explorer.info` directly has no effect.
110
+
111
+ ### Register a custom UI provider
112
+ `UIProviderFactory.register()` only understands `'swagger'`/`'scalar'`. Register a custom provider directly on the factory before `ApiReferenceComponent.binding()` runs:
113
+
114
+ ```typescript
115
+ UIProviderFactory.getInstance().set('my-ui', new MyCustomUIProvider());
116
+ ```
117
+
118
+ ## Reference
119
+
120
+ ### Options
123
121
  ```typescript
124
122
  export interface IApiReferenceOptions {
125
- restOptions: {
126
- base: { path: string };
127
- doc: { path: string };
128
- ui: { path: string; type: TDocumentUIType };
123
+ restOptions?: {
124
+ base?: { path?: string };
125
+ doc?: { path?: string };
126
+ ui?: { path?: string; type?: TDocumentUIType };
129
127
  };
130
- explorer: {
131
- openapi: string;
128
+ explorer?: {
129
+ openapi?: string;
132
130
  info?: {
133
131
  title: string;
134
132
  version: string;
135
133
  description: string;
136
134
  contact?: { name: string; email: string };
137
135
  };
138
- servers?: Array<{
139
- url: string;
140
- description?: string;
141
- }>;
136
+ servers?: Array<{ url: string; description?: string }>;
142
137
  };
143
138
  uiConfig?: Record<string, any>;
144
139
  }
@@ -151,194 +146,18 @@ export interface IApiReferenceOptions {
151
146
  | `restOptions.ui.path` | `string` | `'/explorer'` | Path to the documentation UI (relative to base) |
152
147
  | `restOptions.ui.type` | `'swagger' \| 'scalar'` | `'scalar'` | UI provider type |
153
148
  | `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) |
149
+ | `explorer.info.title` / `.version` / `.description` / `.contact` | - | Always sourced from `package.json` | Overwritten at runtime - binding values are discarded |
158
150
  | `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
151
+ | `uiConfig` | `Record<string, any>` | `undefined` | Custom config passed through to the UI provider |
317
152
 
153
+ ### Binding keys
318
154
  | Key | Constant | Type | Required | Default |
319
155
  |-----|----------|------|----------|---------|
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.
156
+ | `@app/api-reference/options` | `ApiReferenceBindingKeys.API_REFERENCE_OPTIONS` | `IApiReferenceOptions` | No | See Options table |
323
157
 
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.
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.
339
159
 
340
160
  **Default value:**
341
-
342
161
  ```typescript
343
162
  const DEFAULT_API_REFERENCE_OPTIONS: IApiReferenceOptions = {
344
163
  restOptions: {
@@ -358,10 +177,27 @@ const DEFAULT_API_REFERENCE_OPTIONS: IApiReferenceOptions = {
358
177
  ```
359
178
 
360
179
  > [!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.
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.
362
181
 
363
- ### Type Definitions
182
+ ### API endpoints
183
+ | Method | Path (default, relative to app base) | Description |
184
+ |--------|-----------------|-------------|
185
+ | `GET` | `/doc/explorer` | Documentation UI (Scalar by default) |
186
+ | `GET` | `/doc/openapi.json` | Raw OpenAPI specification |
364
187
 
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`.
189
+
190
+ ### UIProviderFactory
191
+ | Method | Signature | Description |
192
+ |--------|-----------|-------------|
193
+ | `getInstance()` | `static () => UIProviderFactory` | Returns the singleton instance |
194
+ | `register()` | `(opts: { type: string }) => void` | Instantiates and registers a built-in provider; idempotent - warns and returns if the type is already bound |
195
+ | `getProvider()` | `(opts: IGetProviderParams) => IUIProvider` | Returns the registered provider or throws `Unknown UI Provider` |
196
+ | `getRegisteredProviders()` | `() => string[]` | Lists all registered provider type keys |
197
+
198
+ Extends `MemoryStorageHelper<{ [key: string | symbol]: IUIProvider }>`, using `isBound()` / `get()` / `set()` / `keys()` for lightweight, type-safe storage without the full DI container.
199
+
200
+ ### Type definitions
365
201
  ```typescript
366
202
  type TDocumentUIType = TConstValue<typeof DocumentUITypes>;
367
203
 
@@ -373,96 +209,38 @@ class DocumentUITypes {
373
209
  }
374
210
  ```
375
211
 
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.
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.
377
213
 
378
- ## API Endpoints
214
+ ### Component lifecycle (`binding()`)
215
+ 1. **Resolve options** - reads `ApiReferenceBindingKeys.API_REFERENCE_OPTIONS` with `isOptional: true`, then merges `base`/`doc`/`ui` each against `DEFAULT_API_REFERENCE_OPTIONS`
216
+ 2. **Overwrite info** - reads `package.json` via `application.getAppInfo()` and replaces `explorer.info`
217
+ 3. **Auto-detect servers** - builds one entry from `application.getServerAddress()` when `explorer.servers` is empty
218
+ 4. **Normalize paths** - ensures every path segment (`base.path`, `doc.path`, `ui.path`) has a leading `/`
219
+ 5. **Register the OpenAPI doc route** - `rootRouter.doc(docPath, explorer)`
220
+ 6. **Resolve `uiType`** - `restOptions.ui.type ?? DocumentUITypes.SWAGGER`
221
+ 7. **Validate and register the UI provider** - via `UIProviderFactory`, unless a provider with that type is already bound
222
+ 8. **Register the UI route** - `GET` handler at `uiPath` calling `uiProvider.render()`
223
+ 9. **Register JWT and Basic security schemes** on the OpenAPI registry
379
224
 
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
225
+ ### Tech stack
226
+ | Library | Purpose |
227
+ |---------|---------|
228
+ | `@hono/zod-openapi` | OpenAPI generation from Zod schemas |
229
+ | `@hono/swagger-ui` | Swagger UI rendering |
230
+ | `@scalar/hono-api-reference` | Scalar UI rendering |
231
+ | `zod` | Schema validation and type generation |
403
232
 
404
233
  ## Troubleshooting
405
234
 
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"
235
+ | Symptom | Cause | Fix |
236
+ |---------|-------|-----|
237
+ | `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 |
238
+ | 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 |
239
+ | `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 |
240
+ | 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()` |
241
+ | `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
242
 
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
243
+ ## See also
466
244
 
467
245
  - **Guides:**
468
246
  - [Components Overview](/guides/core-concepts/components) - Component system basics
@@ -480,3 +258,11 @@ this.defineRoute({
480
258
  - [OpenAPI Specification](https://swagger.io/specification/) - OpenAPI standard
481
259
  - [Scalar Documentation](https://github.com/scalar/scalar) - Scalar API documentation UI
482
260
  - [@hono/zod-openapi](https://github.com/honojs/middleware/tree/main/packages/zod-openapi) - Hono OpenAPI integration
261
+
262
+ **Files:**
263
+
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`