@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,574 +1,131 @@
1
1
  ---
2
- title: JSX/HTML Utilities Reference
3
- description: Utilities for HTML and JSX responses in OpenAPI routes
2
+ title: JSX/HTML Utility
3
+ description: Render server-side HTML pages with Hono JSX and document them for OpenAPI
4
4
  difficulty: beginner
5
- lastUpdated: 2026-01-03
6
5
  ---
7
6
 
8
7
  # JSX/HTML Utility
9
8
 
10
- The JSX utility provides helper functions for defining HTML/JSX response schemas in OpenAPI routes. These utilities are companions to `jsonContent` and `jsonResponse` but for HTML content type.
9
+ IGNIS renders HTML pages server-side with Hono's built-in JSX support, and documents those routes for OpenAPI with `htmlContent()` / `htmlResponse()`.
11
10
 
12
- **File:** `packages/core/src/utilities/jsx.utility.ts`
11
+ ## In one example
13
12
 
14
- ## Quick Reference
13
+ The smallest real JSX route: a controller that renders a component through `defineJSXRoute`.
15
14
 
16
- | Function | Purpose | Returns |
17
- |----------|---------|---------|
18
- | `htmlContent()` | Create HTML content configuration | OpenAPI content object |
19
- | `htmlResponse()` | Create HTML response with error handling | OpenAPI response object |
20
-
21
- ## When to Use
22
-
23
- Use these utilities when creating routes that:
24
- - Render HTML pages using Hono JSX
25
- - Return server-side rendered content
26
- - Serve HTML documentation or views
27
- - Generate HTML emails or reports
28
-
29
- ## htmlContent()
30
-
31
- Creates a standard OpenAPI content object for `text/html` responses.
32
-
33
- ### Signature
34
-
35
- ```typescript
36
- function htmlContent(opts: {
37
- description: string;
38
- required?: boolean;
39
- }): {
40
- description: string;
41
- content: {
42
- 'text/html': {
43
- schema: ZodString;
44
- };
45
- };
46
- required: boolean;
47
- }
48
- ```
49
-
50
- ### Parameters
51
-
52
- | Parameter | Type | Required | Default | Description |
53
- |-----------|------|----------|---------|-------------|
54
- | `description` | `string` | Yes | - | Description of the HTML content |
55
- | `required` | `boolean` | No | `false` | Whether the content is required |
56
-
57
- ### Returns
58
-
59
- Returns an OpenAPI content configuration object with:
60
- - `description`: The provided description
61
- - `content`: Content type configuration for `text/html`
62
- - `required`: Whether the content is required
63
-
64
- ### Example
65
-
66
- ```typescript
67
- import { htmlContent } from '@venizia/ignis';
68
-
69
- const pageContent = htmlContent({
70
- description: 'HTML page content',
71
- required: true,
72
- });
73
-
74
- // Result:
75
- // {
76
- // description: 'HTML page content',
77
- // content: {
78
- // 'text/html': {
79
- // schema: z.string().openapi({
80
- // description: 'HTML content',
81
- // example: '<!DOCTYPE html><html>...</html>',
82
- // }),
83
- // },
84
- // },
85
- // required: true,
86
- // }
87
- ```
88
-
89
-
90
- ## htmlResponse()
91
-
92
- Creates a standard OpenAPI response object for HTML endpoints, including a success (200 OK) HTML response and a JSON error response for `4xx | 5xx` status codes using the `ErrorSchema`.
93
-
94
- ### Signature
95
-
96
- ```typescript
97
- function htmlResponse(opts: {
98
- description: string;
99
- required?: boolean;
100
- }): {
101
- 200: typeof htmlContent;
102
- '4xx | 5xx': {
103
- description: 'Error Response';
104
- content: {
105
- 'application/json': {
106
- schema: ErrorSchema;
107
- };
108
- };
109
- };
110
- }
111
- ```
112
-
113
- ### Parameters
114
-
115
- | Parameter | Type | Required | Default | Description |
116
- |-----------|------|----------|---------|-------------|
117
- | `description` | `string` | Yes | - | Description of the successful HTML response |
118
- | `required` | `boolean` | No | `false` | Whether the content is required |
119
-
120
- ### Returns
121
-
122
- Returns an OpenAPI responses object with:
123
- - `200`: Success response with HTML content (via `htmlContent()`)
124
- - `4xx | 5xx`: Error responses with JSON error schema
125
-
126
- ### Example
127
-
128
- ```typescript
129
- import { htmlResponse } from '@venizia/ignis';
130
-
131
- this.defineRoute({
132
- configs: {
133
- path: '/dashboard',
134
- method: 'get',
135
- responses: htmlResponse({
136
- description: 'Dashboard HTML page',
137
- }),
138
- },
139
- handler: async (context) => {
140
- return context.html(
141
- <html>
142
- <head>
143
- <title>Dashboard</title>
144
- </head>
145
- <body>
146
- <h1>Welcome to Dashboard</h1>
147
- </body>
148
- </html>
149
- );
150
- },
151
- });
152
- ```
153
-
154
-
155
- ## Usage Examples
156
-
157
- ### Basic HTML Route
158
-
159
- ```typescript
160
- import { BaseRestController, get, htmlResponse } from '@venizia/ignis';
161
-
162
- export class PageController extends BaseRestController {
163
- @get({
164
- configs: {
165
- path: '/home',
166
- responses: htmlResponse({
167
- description: 'Home page HTML',
168
- }),
169
- },
170
- })
171
- async getHomePage() {
172
- return this.context.html(
173
- <html>
174
- <head>
175
- <title>Home</title>
176
- </head>
177
- <body>
178
- <h1>Welcome Home</h1>
179
- </body>
180
- </html>
181
- );
182
- }
183
- }
184
- ```
185
-
186
- ### HTML Email Preview
187
-
188
- ```typescript
189
- import { BaseRestController, get, htmlResponse, TRouteContext } from '@venizia/ignis';
190
- import { z } from '@hono/zod-openapi';
191
- import { HTTP } from '@venizia/ignis-helpers';
192
-
193
- const EmailRoutes = {
194
- PREVIEW: {
195
- method: HTTP.Methods.GET,
196
- path: '/preview/:templateId',
197
- request: {
198
- params: z.object({ templateId: z.string() }),
199
- },
200
- responses: htmlResponse({
201
- description: 'Email template preview',
202
- }),
203
- },
204
- } as const;
205
-
206
- export class EmailController extends BaseRestController {
207
- @get({ configs: EmailRoutes.PREVIEW })
208
- async previewTemplate(c: TRouteContext) {
209
- const { templateId } = c.req.valid<{ templateId: string }>('param');
210
- const template = await this.emailService.getTemplate(templateId);
211
-
212
- return c.html(
213
- <html>
214
- <head>
215
- <title>Email Preview: {template.subject}</title>
216
- </head>
217
- <body>
218
- <div dangerouslySetInnerHTML={{ __html: template.html }} />
219
- </body>
220
- </html>
221
- );
222
- }
223
- }
224
- ```
225
-
226
- ### Documentation Page
227
-
228
- ```typescript
229
- import { BaseRestController, get, htmlResponse, TRouteContext } from '@venizia/ignis';
230
- import { z } from '@hono/zod-openapi';
15
+ ```tsx
16
+ import { BaseRestController, controller, htmlContent, type IControllerOptions } from '@venizia/ignis';
231
17
  import { HTTP } from '@venizia/ignis-helpers';
232
18
 
233
- const DocsRoutes = {
234
- GET_SECTION: {
235
- method: HTTP.Methods.GET,
236
- path: '/docs/:section',
237
- request: {
238
- params: z.object({ section: z.string() }),
239
- },
240
- responses: htmlResponse({
241
- description: 'API documentation page',
242
- }),
243
- },
244
- } as const;
245
-
246
- export class DocsController extends BaseRestController {
247
- @get({ configs: DocsRoutes.GET_SECTION })
248
- async getDocumentation(c: TRouteContext) {
249
- const { section } = c.req.valid<{ section: string }>('param');
250
- const content = await this.docsService.getSection(section);
251
-
252
- return c.html(
253
- <html>
254
- <head>
255
- <title>Docs - {content.title}</title>
256
- <link rel="stylesheet" href="/styles/docs.css" />
257
- </head>
258
- <body>
259
- <nav>
260
- <a href="/docs/getting-started">Getting Started</a>
261
- <a href="/docs/api">API Reference</a>
262
- </nav>
263
- <main>
264
- <h1>{content.title}</h1>
265
- <div dangerouslySetInnerHTML={{ __html: content.html }} />
266
- </main>
267
- </body>
268
- </html>
269
- );
19
+ @controller({ path: '/' })
20
+ export class ViewController extends BaseRestController {
21
+ constructor(opts: IControllerOptions) {
22
+ super({ ...opts, scope: ViewController.name, path: '/' });
270
23
  }
271
- }
272
- ```
273
24
 
274
- ### Admin Dashboard
275
-
276
- ```typescript
277
- import { BaseRestController, get, htmlResponse } from '@venizia/ignis';
278
-
279
- export class AdminController extends BaseRestController {
280
- @get({
281
- configs: {
282
- path: '/admin',
283
- middleware: [authenticate({ role: 'admin' })],
284
- responses: htmlResponse({
285
- description: 'Admin dashboard',
286
- }),
287
- },
288
- })
289
- async getDashboard() {
290
- const stats = await this.statsService.getAdminStats();
291
-
292
- return this.context.html(
293
- <html>
294
- <head>
295
- <title>Admin Dashboard</title>
296
- <script src="/js/dashboard.js" defer />
297
- </head>
298
- <body>
299
- <div class="dashboard">
300
- <h1>Admin Dashboard</h1>
301
- <div class="stats">
302
- <div class="stat-card">
303
- <h3>Total Users</h3>
304
- <p>{stats.totalUsers}</p>
305
- </div>
306
- <div class="stat-card">
307
- <h3>Active Sessions</h3>
308
- <p>{stats.activeSessions}</p>
309
- </div>
310
- </div>
311
- </div>
312
- </body>
313
- </html>
314
- );
25
+ override binding() {
26
+ this.defineJSXRoute({
27
+ configs: {
28
+ path: '/',
29
+ method: 'get',
30
+ responses: {
31
+ [HTTP.ResultCodes.RS_2.Ok]: htmlContent({ description: 'Home page HTML' }),
32
+ },
33
+ },
34
+ handler: c => c.html(<h1>Welcome to IGNIS</h1>),
35
+ });
315
36
  }
316
37
  }
317
38
  ```
318
39
 
40
+ No separate JSX renderer is registered - the handler builds a JSX tree and hands it to Hono's own `c.html()`.
319
41
 
320
- ## Comparison with JSON Utilities
42
+ ## How it works
321
43
 
322
- ### htmlContent vs jsonContent
44
+ - **Hono JSX renders to HTML.** A handler returns `c.html(<Component />)`; Hono's built-in JSX runtime turns the tree into an HTML string. IGNIS adds nothing on top of that renderer.
45
+ - **`defineJSXRoute` is `defineRoute` with an HTML default.** It builds route configs through `getJSXRouteConfigs` instead of `getRouteConfigs`, which merges a default `htmlResponse({ description: 'HTML page' })` under whatever `responses` you declare - your own `200` entry overrides the default description.
46
+ - **`htmlContent()` / `htmlResponse()` document `text/html`.** They mirror `jsonContent()` / `jsonResponse()` (see [Schema Utility](./schema.md)) but for HTML: `htmlContent()` builds one OpenAPI content object, `htmlResponse()` wraps it into a full `200` success response plus a JSON `4xx | 5xx` error response.
47
+ - **The tsconfig switch is required.** Compiling `.tsx` files with Hono's JSX needs `"jsx": "react-jsx"` and `"jsxImportSource": "hono/jsx"` in `tsconfig.json`.
323
48
 
324
- | Aspect | `htmlContent()` | `jsonContent()` |
325
- |--------|----------------|-----------------|
326
- | **Content-Type** | `text/html` | `application/json` |
327
- | **Schema** | `z.string()` | Custom Zod schema |
328
- | **Use Case** | HTML pages, JSX rendering | API responses, data |
329
- | **Example** | HTML document string | JSON object |
49
+ ## Common tasks
330
50
 
331
- ### htmlResponse vs jsonResponse
51
+ ### Build a reusable layout
332
52
 
333
- | Aspect | `htmlResponse()` | `jsonResponse()` |
334
- |--------|------------------|------------------|
335
- | **Success Type** | `text/html` (200) | `application/json` (200) |
336
- | **Error Type** | `application/json` (4xx/5xx) | `application/json` (4xx/5xx) |
337
- | **Use Case** | Web pages | REST APIs |
53
+ Compose pages from a shared layout using `FC` and `PropsWithChildren`, re-exported from `@venizia/ignis-helpers` (sourced from `hono/jsx`).
338
54
 
55
+ ```tsx
56
+ import type { FC, PropsWithChildren } from '@venizia/ignis-helpers';
339
57
 
340
- ## Best Practices
341
-
342
- ### 1. Use for Server-Side Rendering
343
-
344
- ```typescript
345
- // Good: Use htmlResponse for SSR routes
346
- const ProfileConfig = {
347
- method: HTTP.Methods.GET,
348
- path: '/profile/:userId',
349
- request: { params: z.object({ userId: z.string() }) },
350
- responses: htmlResponse({ description: 'User profile page' }),
351
- } as const;
352
-
353
- @get({ configs: ProfileConfig })
354
- async getUserProfile(c: TRouteContext) {
355
- const { userId } = c.req.valid<{ userId: string }>('param');
356
- const user = await this.userService.getUser(userId);
357
- return c.html(<UserProfile user={user} />);
358
- }
359
-
360
- // Bad: Don't use htmlResponse for API endpoints - use jsonResponse instead
58
+ export const MainLayout: FC<PropsWithChildren<{ title: string }>> = ({ title, children }) => (
59
+ <html>
60
+ <head>
61
+ <title>{title}</title>
62
+ </head>
63
+ <body>{children}</body>
64
+ </html>
65
+ );
361
66
  ```
362
67
 
363
- ### 2. Combine with Authentication
364
-
365
- ```typescript
366
- const SettingsConfig = {
367
- method: HTTP.Methods.GET,
368
- path: '/admin/settings',
369
- authenticate: { strategies: ['jwt'] },
370
- responses: htmlResponse({ description: 'Settings page' }),
371
- } as const;
372
-
373
- @get({ configs: SettingsConfig })
374
- async getSettings(c: TRouteContext) {
375
- return c.html(<SettingsPage />);
376
- }
377
- ```
378
-
379
- ### 3. Error Handling
380
-
381
- HTML routes automatically return JSON errors for 4xx/5xx:
382
-
383
- ```typescript
384
- const ArticleConfig = {
385
- method: HTTP.Methods.GET,
386
- path: '/article/:id',
387
- request: { params: z.object({ id: z.string() }) },
388
- responses: htmlResponse({ description: 'Article page' }),
389
- } as const;
390
-
391
- @get({ configs: ArticleConfig })
392
- async getArticle(c: TRouteContext) {
393
- const { id } = c.req.valid<{ id: string }>('param');
394
- const article = await this.articleService.findById(id);
68
+ ### Pass props into a page component
395
69
 
396
- if (!article) {
397
- // Returns JSON error: { message: 'Not found', statusCode: 404 }
398
- throw new NotFoundError('Article not found');
399
- }
70
+ Page components take a typed props object like any other Hono JSX component.
400
71
 
401
- return c.html(<ArticlePage article={article} />);
72
+ ```tsx
73
+ interface HomePageProps {
74
+ timestamp?: string;
402
75
  }
403
- ```
404
76
 
405
- ### 4. SEO-Friendly Metadata
406
-
407
- ```typescript
408
- const BlogConfig = {
409
- method: HTTP.Methods.GET,
410
- path: '/blog/:slug',
411
- request: { params: z.object({ slug: z.string() }) },
412
- responses: htmlResponse({ description: 'Blog post page' }),
413
- } as const;
414
-
415
- @get({ configs: BlogConfig })
416
- async getBlogPost(c: TRouteContext) {
417
- const { slug } = c.req.valid<{ slug: string }>('param');
418
- const post = await this.blogService.getBySlug(slug);
419
-
420
- return c.html(
421
- <html>
422
- <head>
423
- <title>{post.title} | My Blog</title>
424
- <meta name="description" content={post.excerpt} />
425
- <meta property="og:title" content={post.title} />
426
- <meta property="og:description" content={post.excerpt} />
427
- <meta property="og:image" content={post.coverImage} />
428
- </head>
429
- <body>
430
- <article>
431
- <h1>{post.title}</h1>
432
- <div dangerouslySetInnerHTML={{ __html: post.content }} />
433
- </article>
434
- </body>
435
- </html>
436
- );
437
- }
77
+ export const HomePage: FC<HomePageProps> = ({ timestamp }) => (
78
+ <MainLayout title="Home">
79
+ <h1>Welcome</h1>
80
+ {timestamp && <p>Rendered at {timestamp}</p>}
81
+ </MainLayout>
82
+ );
438
83
  ```
439
84
 
85
+ ### Render trusted raw HTML
440
86
 
441
- ## Integration with Hono JSX
442
-
443
- IGNIS uses Hono's built-in JSX support. Make sure to configure your `tsconfig.json`:
87
+ Use `dangerouslySetInnerHTML` for content that is already HTML, such as a stored email or blog template - never for unsanitized user input.
444
88
 
445
- ```json
446
- {
447
- "compilerOptions": {
448
- "jsx": "react-jsx",
449
- "jsxImportSource": "hono/jsx"
450
- }
451
- }
89
+ ```tsx
90
+ <div dangerouslySetInnerHTML={{ __html: template.html }} />
452
91
  ```
453
92
 
454
- ### JSX Components
455
-
456
- ```typescript
457
- // components/Layout.tsx
458
- export const Layout = (props: { title: string; children: any }) => {
459
- return (
460
- <html>
461
- <head>
462
- <title>{props.title}</title>
463
- <link rel="stylesheet" href="/styles/main.css" />
464
- </head>
465
- <body>
466
- <header>
467
- <nav>
468
- <a href="/">Home</a>
469
- <a href="/about">About</a>
470
- </nav>
471
- </header>
472
- <main>{props.children}</main>
473
- <footer>
474
- <p>&copy; 2026 My App</p>
475
- </footer>
476
- </body>
477
- </html>
478
- );
479
- };
480
-
481
- // controller.ts
482
- import { Layout } from './components/Layout';
483
-
484
- @get({
485
- configs: {
486
- path: '/',
487
- responses: htmlResponse({ description: 'Home page' }),
488
- },
489
- })
490
- async getHome() {
491
- return this.context.html(
492
- <Layout title="Home">
493
- <h1>Welcome to My App</h1>
494
- <p>This is the home page.</p>
495
- </Layout>
496
- );
497
- }
498
- ```
499
-
500
-
501
- ## Common Pitfalls
502
-
503
- ### Pitfall 1: Missing HTML Wrapper
93
+ ### Give the response a custom description
504
94
 
505
- ```typescript
506
- // Bad: Incomplete HTML
507
- @get({
508
- configs: {
509
- path: '/page',
510
- responses: htmlResponse({ description: 'Page' }),
511
- },
512
- })
513
- async getPage() {
514
- return this.context.html(<div>Hello</div>); // Missing <html>, <head>, <body>
515
- }
95
+ Pass your own `200` entry in `responses` - it overrides the `defineJSXRoute` default description.
516
96
 
517
- // Good: Complete HTML document
518
- @get({
519
- configs: {
520
- path: '/page',
521
- responses: htmlResponse({ description: 'Page' }),
522
- },
523
- })
524
- async getPage() {
525
- return this.context.html(
526
- <html>
527
- <head><title>Page</title></head>
528
- <body><div>Hello</div></body>
529
- </html>
530
- );
531
- }
97
+ ```tsx
98
+ responses: {
99
+ [HTTP.ResultCodes.RS_2.Ok]: htmlContent({ description: 'Dashboard HTML page' }),
100
+ },
532
101
  ```
533
102
 
534
- ### Pitfall 2: Using htmlResponse for APIs
103
+ ### Guard a page with authentication
535
104
 
536
- ```typescript
537
- // Bad: HTML response for API
538
- @get({
539
- configs: {
540
- path: '/api/users',
541
- responses: htmlResponse({ description: 'Users' }),
542
- },
543
- })
544
- async getUsers() {
545
- return { users: [...] }; // Should return HTML or use jsonResponse
546
- }
105
+ JSX routes accept the same `authenticate` config as JSON routes.
547
106
 
548
- // Good: Use jsonResponse for APIs
549
- @get({
107
+ ```tsx
108
+ this.defineJSXRoute({
550
109
  configs: {
551
- path: '/api/users',
552
- responses: jsonResponse({
553
- description: 'Users list',
554
- schema: z.object({ users: z.array(UserSchema) }),
555
- }),
110
+ path: '/admin',
111
+ method: 'get',
112
+ authenticate: { strategies: ['jwt'] },
113
+ responses: {
114
+ [HTTP.ResultCodes.RS_2.Ok]: htmlContent({ description: 'Admin dashboard' }),
115
+ },
556
116
  },
557
- })
558
- async getUsers() {
559
- return { users: await this.userService.findAll() };
560
- }
117
+ handler: c => c.html(<AdminDashboard />),
118
+ });
561
119
  ```
562
120
 
121
+ ## See also
563
122
 
564
- ## See Also
123
+ - [Full reference](/references/utilities/jsx-reference) - every function, `defineJSXRoute` behavior, and component patterns
124
+ - [Schema Utility](./schema.md) - the JSON-side helpers (`jsonContent`, `jsonResponse`) this pairs with
125
+ - [Controllers](../base/controllers.md) - `defineRoute`/`bindRoute`, `authenticate`/`authorize` config
126
+ - **External:** [Hono JSX Documentation](https://hono.dev/docs/guides/jsx)
565
127
 
566
- - **Related References:**
567
- - [Schema Utility](./schema.md) - JSON content and response helpers
568
- - [Controllers](../base/controllers.md) - Defining routes and handlers
569
- - [OpenAPI Component](/extensions/components/api-reference) - API documentation
128
+ **Files:**
570
129
 
571
- - **External Resources:**
572
- - [Hono JSX Documentation](https://hono.dev/guides/jsx)
573
- - [OpenAPI Specification](https://swagger.io/specification/)
574
- - [React JSX (for reference)](https://react.dev/learn/writing-markup-with-jsx)
130
+ - [`packages/core-server/src/utilities/jsx.utility.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/utilities/jsx.utility.ts) - `htmlContent`, `htmlResponse`
131
+ - [`packages/core-server/src/base/controllers/rest/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/base/controllers/rest/base.ts) - `defineJSXRoute`