@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,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/src/utilities/jsx.utility.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/utilities/jsx.utility.ts) - `htmlContent`, `htmlResponse`
131
+ - [`packages/core/src/base/controllers/rest/base.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/base/controllers/rest/base.ts) - `defineJSXRoute`