@venizia/ignis-docs 0.0.4-2 → 0.0.4
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.
- package/dist/mcp-server/helpers/docs.helper.js +1 -1
- package/dist/mcp-server/helpers/docs.helper.js.map +1 -1
- package/package.json +3 -2
- package/wiki/best-practices/api-usage-examples.md +9 -9
- package/wiki/best-practices/code-style-standards/route-definitions.md +3 -3
- package/wiki/best-practices/common-pitfalls.md +2 -2
- package/wiki/best-practices/error-handling.md +4 -4
- package/wiki/guides/core-concepts/components-guide.md +2 -2
- package/wiki/guides/core-concepts/controllers.md +15 -14
- package/wiki/guides/core-concepts/persistent/transactions.md +2 -2
- package/wiki/guides/reference/glossary.md +5 -5
- package/wiki/guides/tutorials/building-a-crud-api.md +1 -1
- package/wiki/guides/tutorials/ecommerce-api.md +19 -19
- package/wiki/guides/tutorials/realtime-chat.md +10 -10
- package/wiki/references/base/controllers.md +26 -50
- package/wiki/references/base/datasources.md +1 -1
- package/wiki/references/base/filter-system/index.md +1 -1
- package/wiki/references/base/middlewares.md +3 -3
- package/wiki/references/components/health-check.md +4 -4
- package/wiki/references/utilities/jsx.md +13 -13
- package/wiki/changelogs/2025-12-16-initial-architecture.md +0 -145
- package/wiki/changelogs/2025-12-16-model-repo-datasource-refactor.md +0 -300
- package/wiki/changelogs/2025-12-17-refactor.md +0 -90
- package/wiki/changelogs/2025-12-18-performance-optimizations.md +0 -130
- package/wiki/changelogs/2025-12-18-repository-validation-security.md +0 -255
- package/wiki/changelogs/2025-12-26-nested-relations-and-generics.md +0 -86
- package/wiki/changelogs/2025-12-26-transaction-support.md +0 -57
- package/wiki/changelogs/2025-12-29-dynamic-binding-registration.md +0 -104
- package/wiki/changelogs/2025-12-29-snowflake-uid-helper.md +0 -100
- package/wiki/changelogs/2025-12-30-repository-enhancements.md +0 -214
- package/wiki/changelogs/2025-12-31-json-path-filtering-array-operators.md +0 -214
- package/wiki/changelogs/2025-12-31-string-id-custom-generator.md +0 -137
- package/wiki/changelogs/2026-01-02-default-filter-and-repository-mixins.md +0 -418
- package/wiki/changelogs/2026-01-05-range-queries-content-range.md +0 -184
- package/wiki/changelogs/2026-01-06-basic-authentication.md +0 -103
- package/wiki/changelogs/2026-01-07-controller-route-customization.md +0 -209
- package/wiki/changelogs/index.md +0 -44
- package/wiki/changelogs/planned-schema-migrator.md +0 -553
- package/wiki/changelogs/template.md +0 -123
- package/wiki/references/base/repositories.md +0 -62
|
@@ -26,7 +26,7 @@ class DocsHelper {
|
|
|
26
26
|
const files = await (0, fast_glob_1.default)('**/*.md', {
|
|
27
27
|
cwd: common_1.Paths.WIKI,
|
|
28
28
|
absolute: true,
|
|
29
|
-
ignore: ['node_modules'],
|
|
29
|
+
ignore: ['node_modules', 'changelogs/**'],
|
|
30
30
|
});
|
|
31
31
|
if (files.length === 0) {
|
|
32
32
|
logger_helper_1.Logger.warn(`No documentation files found in ${common_1.Paths.WIKI}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docs.helper.js","sourceRoot":"","sources":["../../../mcp-server/helpers/docs.helper.ts"],"names":[],"mappings":";;;;;;AAAA,0DAA2B;AAC3B,sDAA2B;AAC3B,8DAAiC;AACjC,gEAAkC;AAClC,0DAA6B;AAC7B,sCAA8C;AAC9C,mDAAyC;AAezC,qGAAqG;AACrG,MAAa,UAAU;aACN,UAAK,GAAW,EAAE,CAAC;aACnB,UAAK,GAAsB,IAAI,CAAC;IAE/C;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,IAAI;QACf,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAC,KAAK,CAAC;QACpB,CAAC;QAED,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,IAAA,mBAAE,EAAC,SAAS,EAAE;gBAChC,GAAG,EAAE,cAAK,CAAC,IAAI;gBACf,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,CAAC,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"docs.helper.js","sourceRoot":"","sources":["../../../mcp-server/helpers/docs.helper.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@venizia/ignis-docs",
|
|
3
|
-
"version": "0.0.4
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Documentation and MCP Server for Ignis Framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ignis",
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"LICENSE.md",
|
|
56
56
|
"dist/mcp-server",
|
|
57
57
|
"wiki",
|
|
58
|
+
"!wiki/changelogs",
|
|
58
59
|
"!**/*.tsbuildinfo"
|
|
59
60
|
],
|
|
60
61
|
"publishConfig": {
|
|
@@ -113,7 +114,7 @@
|
|
|
113
114
|
"@braintree/sanitize-url": "^7.1.1",
|
|
114
115
|
"@types/bun": "^1.3.4",
|
|
115
116
|
"@types/glob": "^8.1.0",
|
|
116
|
-
"@venizia/dev-configs": "^0.0.5
|
|
117
|
+
"@venizia/dev-configs": "^0.0.5",
|
|
117
118
|
"eslint": "^9.36.0",
|
|
118
119
|
"glob": "^10.4.2",
|
|
119
120
|
"prettier": "^3.6.2",
|
|
@@ -42,7 +42,7 @@ export const RouteConfigs = {
|
|
|
42
42
|
} as const;
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
Then, use the decorators in your controller class.
|
|
45
|
+
Then, use the decorators in your controller class.
|
|
46
46
|
|
|
47
47
|
**`src/controllers/test/controller.ts`**
|
|
48
48
|
```typescript
|
|
@@ -61,15 +61,15 @@ export class TestController extends BaseController {
|
|
|
61
61
|
// ...
|
|
62
62
|
|
|
63
63
|
@get({ configs: RouteConfigs.GET_TEST })
|
|
64
|
-
getWithDecorator(context: TRouteContext
|
|
64
|
+
getWithDecorator(context: TRouteContext) {
|
|
65
65
|
// context is fully typed!
|
|
66
66
|
return context.json({ message: 'Hello from decorator', method: 'GET' }, HTTP.ResultCodes.RS_2.Ok);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
@post({ configs: RouteConfigs.CREATE_ITEM })
|
|
70
|
-
createWithDecorator(context: TRouteContext
|
|
71
|
-
// context.req.valid('json')
|
|
72
|
-
const body = context.req.valid('json');
|
|
70
|
+
createWithDecorator(context: TRouteContext) {
|
|
71
|
+
// context.req.valid('json') can be explicitly typed
|
|
72
|
+
const body = context.req.valid<{ name: string; age: number }>('json');
|
|
73
73
|
|
|
74
74
|
// The response is validated against the schema
|
|
75
75
|
return context.json(
|
|
@@ -424,8 +424,8 @@ export class UserController extends BaseController {
|
|
|
424
424
|
}
|
|
425
425
|
|
|
426
426
|
@get({ configs: RouteConfigs.GET_USER_WITH_ORDERS })
|
|
427
|
-
async getUserWithOrders(c: TRouteContext
|
|
428
|
-
const { id } = c.req.valid('param');
|
|
427
|
+
async getUserWithOrders(c: TRouteContext) {
|
|
428
|
+
const { id } = c.req.valid<{ id: string }>('param');
|
|
429
429
|
const result = await this.userService.getUserWithOrders(id);
|
|
430
430
|
|
|
431
431
|
if (!result) {
|
|
@@ -520,8 +520,8 @@ throw getError({
|
|
|
520
520
|
|
|
521
521
|
```typescript
|
|
522
522
|
@get({ configs: RouteConfigs.GET_USER })
|
|
523
|
-
async getUser(c: TRouteContext
|
|
524
|
-
const { id } = c.req.valid('param');
|
|
523
|
+
async getUser(c: TRouteContext) {
|
|
524
|
+
const { id } = c.req.valid<{ id: string }>('param');
|
|
525
525
|
|
|
526
526
|
const user = await this.userRepository.findById({ id });
|
|
527
527
|
|
|
@@ -44,13 +44,13 @@ export const RouteConfigs = {
|
|
|
44
44
|
export class UserController extends BaseController {
|
|
45
45
|
|
|
46
46
|
@api({ configs: RouteConfigs.GET_USERS })
|
|
47
|
-
list(context: TRouteContext
|
|
47
|
+
list(context: TRouteContext) {
|
|
48
48
|
return context.json({ users: [] }, HTTP.ResultCodes.RS_2.Ok);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
@api({ configs: RouteConfigs.GET_USER_BY_ID })
|
|
52
|
-
getById(context: TRouteContext
|
|
53
|
-
const { id } = context.req.valid('param');
|
|
52
|
+
getById(context: TRouteContext) {
|
|
53
|
+
const { id } = context.req.valid<{ id: string }>('param');
|
|
54
54
|
return context.json({ id, name: 'User' }, HTTP.ResultCodes.RS_2.Ok);
|
|
55
55
|
}
|
|
56
56
|
}
|
|
@@ -125,7 +125,7 @@ APP_ENV_POSTGRES_DATABASE=db
|
|
|
125
125
|
|
|
126
126
|
## 5. Not Using `as const` for Route Definitions
|
|
127
127
|
|
|
128
|
-
**Pitfall:** When using the decorator-based routing with a shared `RouteConfigs` object, you forget to add `as const` to the object definition. TypeScript will infer the types too broadly
|
|
128
|
+
**Pitfall:** When using the decorator-based routing with a shared `RouteConfigs` object, you forget to add `as const` to the object definition. TypeScript will infer the types too broadly.
|
|
129
129
|
|
|
130
130
|
**Solution:** Always use `as const` when exporting a shared route configuration object.
|
|
131
131
|
|
|
@@ -136,7 +136,7 @@ export const RouteConfigs = {
|
|
|
136
136
|
GET_USER_BY_ID: { /* ... */ },
|
|
137
137
|
} as const; // <-- This is crucial!
|
|
138
138
|
```
|
|
139
|
-
This ensures that
|
|
139
|
+
This ensures that the route configuration object is treated as a readonly literal, which is important for type safety throughout your application.
|
|
140
140
|
|
|
141
141
|
## 6. Bulk Operations Without WHERE Clause
|
|
142
142
|
|
|
@@ -124,8 +124,8 @@ import { BaseController, controller, get, post } from '@venizia/ignis';
|
|
|
124
124
|
export class UserController extends BaseController {
|
|
125
125
|
|
|
126
126
|
@post({ configs: RouteConfigs.CREATE_USER })
|
|
127
|
-
async createUser(c:
|
|
128
|
-
const data = c.req.valid('json');
|
|
127
|
+
async createUser(c: TRouteContext) {
|
|
128
|
+
const data = c.req.valid<{ name: string; email: string }>('json');
|
|
129
129
|
|
|
130
130
|
// Service throws appropriate errors
|
|
131
131
|
const user = await this.userService.createUser(data);
|
|
@@ -134,8 +134,8 @@ export class UserController extends BaseController {
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
@get({ configs: RouteConfigs.GET_USER })
|
|
137
|
-
async getUser(c:
|
|
138
|
-
const { id } = c.req.valid('param');
|
|
137
|
+
async getUser(c: TRouteContext) {
|
|
138
|
+
const { id } = c.req.valid<{ id: string }>('param');
|
|
139
139
|
|
|
140
140
|
// Service throws 404 if not found
|
|
141
141
|
const user = await this.userService.getUserOrFail(id);
|
|
@@ -169,8 +169,8 @@ export class NotificationController extends BaseController {
|
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
@post({ configs: NotificationRoutes.SEND })
|
|
172
|
-
async send(c: TRouteContext
|
|
173
|
-
const body = c.req.valid('json');
|
|
172
|
+
async send(c: TRouteContext) {
|
|
173
|
+
const body = c.req.valid<{ userId: string; message: string }>('json');
|
|
174
174
|
const result = await this._notificationService.send({
|
|
175
175
|
userId: body.userId,
|
|
176
176
|
message: body.message,
|
|
@@ -106,17 +106,18 @@ export class MyItemsController extends BaseController {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
@get({ configs: TestRoutes.GET_DATA })
|
|
109
|
-
getData(c: TRouteContext
|
|
109
|
+
getData(c: TRouteContext) {
|
|
110
110
|
// 'c' is fully typed here, including c.req.valid and c.json return type
|
|
111
111
|
return c.json({ message: 'Hello from decorator', method: 'GET' }, HTTP.ResultCodes.RS_2.Ok);
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
@post({ configs: TestRoutes.CREATE_ITEM })
|
|
115
|
-
createItem(c: TRouteContext
|
|
116
|
-
// c.req.valid('json') is automatically typed based on CREATE_ITEM.request.body.content['application/json']
|
|
117
|
-
|
|
115
|
+
createItem(c: TRouteContext) {
|
|
116
|
+
// c.req.valid('json') is automatically typed based on CREATE_ITEM.request.body.content['application/json']['schema']
|
|
117
|
+
// You can also provide an explicit type for stricter checking:
|
|
118
|
+
const body = c.req.valid<{ name: string; value: number }>('json');
|
|
118
119
|
|
|
119
|
-
// Return type is automatically validated against CREATE_ITEM.responses[200].content['application/json']
|
|
120
|
+
// Return type is automatically validated against CREATE_ITEM.responses[200].content['application/json']['schema']
|
|
120
121
|
return c.json(
|
|
121
122
|
{
|
|
122
123
|
id: 'some-uuid',
|
|
@@ -176,7 +177,7 @@ const GetUsersRoute = {
|
|
|
176
177
|
|
|
177
178
|
this.defineRoute({
|
|
178
179
|
configs: GetUsersRoute,
|
|
179
|
-
handler: (c: TRouteContext
|
|
180
|
+
handler: (c: TRouteContext) => {
|
|
180
181
|
return c.json([{ id: 1, name: 'John Doe' }], HTTP.ResultCodes.RS_2.Ok);
|
|
181
182
|
},
|
|
182
183
|
});
|
|
@@ -203,8 +204,8 @@ const GetUserByIdRoute = {
|
|
|
203
204
|
this.bindRoute({
|
|
204
205
|
configs: GetUserByIdRoute,
|
|
205
206
|
}).to({
|
|
206
|
-
handler: (c: TRouteContext
|
|
207
|
-
const { id } = c.req.valid('param'); // Use valid() for type-safe validated params
|
|
207
|
+
handler: (c: TRouteContext) => {
|
|
208
|
+
const { id } = c.req.valid<{ id: string }>('param'); // Use valid<T>() for type-safe validated params
|
|
208
209
|
return c.json({ id: id, name: 'John Doe' }, HTTP.ResultCodes.RS_2.Ok);
|
|
209
210
|
},
|
|
210
211
|
});
|
|
@@ -423,11 +424,11 @@ const UpdateUserConfig = {
|
|
|
423
424
|
} as const; // Use 'as const' for strict type inference
|
|
424
425
|
|
|
425
426
|
@put({ configs: UpdateUserConfig })
|
|
426
|
-
updateUser(c: TRouteContext
|
|
427
|
-
// Access validated data from the request
|
|
428
|
-
const { id } = c.req.valid('param');
|
|
429
|
-
const { notify } = c.req.valid('query');
|
|
430
|
-
const userUpdateData = c.req.valid('json'); // for body
|
|
427
|
+
updateUser(c: TRouteContext) {
|
|
428
|
+
// Access validated data from the request with explicit types
|
|
429
|
+
const { id } = c.req.valid<{ id: string }>('param');
|
|
430
|
+
const { notify } = c.req.valid<{ notify?: string }>('query');
|
|
431
|
+
const userUpdateData = c.req.valid<{ name: string; email: string }>('json'); // for body
|
|
431
432
|
|
|
432
433
|
console.log(`Updating user ${id} with data:`, userUpdateData);
|
|
433
434
|
if (notify) {
|
|
@@ -438,7 +439,7 @@ updateUser(c: TRouteContext<typeof UpdateUserConfig>) {
|
|
|
438
439
|
}
|
|
439
440
|
```
|
|
440
441
|
|
|
441
|
-
Using `TRouteContext` provides
|
|
442
|
+
Using `TRouteContext` provides a typed context object. By using `c.req.valid<T>()`, you ensure that the data you are accessing matches your expectations and provides autocomplete in your editor.
|
|
442
443
|
|
|
443
444
|
## See Also
|
|
444
445
|
|
|
@@ -120,8 +120,8 @@ export class OrderController extends BaseController {
|
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
@post({ configs: OrderRoutes.CREATE })
|
|
123
|
-
async createOrder(c: TRouteContext
|
|
124
|
-
const body = c.req.valid('json');
|
|
123
|
+
async createOrder(c: TRouteContext) {
|
|
124
|
+
const body = c.req.valid<{ order: any; items: any[] }>('json'); // Use explicit types for better safety
|
|
125
125
|
|
|
126
126
|
const tx = await this._orderRepository.beginTransaction({
|
|
127
127
|
isolationLevel: 'SERIALIZABLE',
|
|
@@ -38,7 +38,7 @@ const TodoRoutes = {
|
|
|
38
38
|
@controller({ path: '/todos' })
|
|
39
39
|
export class TodoController extends BaseController {
|
|
40
40
|
@get({ configs: TodoRoutes.GET_ALL })
|
|
41
|
-
async getAll(c: TRouteContext
|
|
41
|
+
async getAll(c: TRouteContext) {
|
|
42
42
|
const todos = await this.repository.find({});
|
|
43
43
|
return c.json(todos, HTTP.ResultCodes.RS_2.Ok);
|
|
44
44
|
}
|
|
@@ -196,16 +196,16 @@ const TodoRoutes = {
|
|
|
196
196
|
@controller({ path: '/todos' })
|
|
197
197
|
class TodoController {
|
|
198
198
|
@get({ configs: TodoRoutes.GET_ALL })
|
|
199
|
-
async getAll(c: TRouteContext
|
|
199
|
+
async getAll(c: TRouteContext) { ... }
|
|
200
200
|
|
|
201
201
|
@get({ configs: TodoRoutes.GET_BY_ID })
|
|
202
|
-
async getById(c: TRouteContext
|
|
203
|
-
const { id } = c.req.valid('param');
|
|
202
|
+
async getById(c: TRouteContext) {
|
|
203
|
+
const { id } = c.req.valid<{ id: string }>('param');
|
|
204
204
|
...
|
|
205
205
|
}
|
|
206
206
|
|
|
207
207
|
@post({ configs: TodoRoutes.CREATE })
|
|
208
|
-
async create(c: TRouteContext
|
|
208
|
+
async create(c: TRouteContext) {
|
|
209
209
|
const data = c.req.valid('json');
|
|
210
210
|
...
|
|
211
211
|
}
|
|
@@ -289,7 +289,7 @@ export class TodoRepository extends DefaultCRUDRepository<typeof Todo.schema> {
|
|
|
289
289
|
| `deleteAll()` | Delete multiple records |
|
|
290
290
|
| `count()` | Count matching records |
|
|
291
291
|
|
|
292
|
-
> **Deep Dive:** See [Repositories Reference](/references/base/repositories) for query options and advanced filtering.
|
|
292
|
+
> **Deep Dive:** See [Repositories Reference](/references/base/repositories/) for query options and advanced filtering.
|
|
293
293
|
|
|
294
294
|
## Step 5: Create the Controller
|
|
295
295
|
|
|
@@ -979,8 +979,8 @@ export class ProductController extends BaseController {
|
|
|
979
979
|
override binding() {}
|
|
980
980
|
|
|
981
981
|
@get({ configs: ProductRoutes.LIST })
|
|
982
|
-
async listProducts(c: TRouteContext
|
|
983
|
-
const { category, limit, offset } = c.req.valid('query');
|
|
982
|
+
async listProducts(c: TRouteContext) {
|
|
983
|
+
const { category, limit, offset } = c.req.valid<{ category?: string; limit?: string; offset?: string }>('query');
|
|
984
984
|
|
|
985
985
|
const products = await this._productService.getActiveProducts({
|
|
986
986
|
categoryId: category,
|
|
@@ -992,8 +992,8 @@ export class ProductController extends BaseController {
|
|
|
992
992
|
}
|
|
993
993
|
|
|
994
994
|
@get({ configs: ProductRoutes.GET_BY_ID })
|
|
995
|
-
async getProduct(c: TRouteContext
|
|
996
|
-
const { id } = c.req.valid('param');
|
|
995
|
+
async getProduct(c: TRouteContext) {
|
|
996
|
+
const { id } = c.req.valid<{ id: string }>('param');
|
|
997
997
|
const product = await this._productService.getProductById({ id });
|
|
998
998
|
return c.json(product);
|
|
999
999
|
}
|
|
@@ -1094,7 +1094,7 @@ export class CartController extends BaseController {
|
|
|
1094
1094
|
override binding() {}
|
|
1095
1095
|
|
|
1096
1096
|
@get({ configs: CartRoutes.GET })
|
|
1097
|
-
async getCart(c: TRouteContext
|
|
1097
|
+
async getCart(c: TRouteContext) {
|
|
1098
1098
|
const sessionId = c.req.header('X-Session-ID') ?? 'guest';
|
|
1099
1099
|
const cart = await this._cartService.getOrCreateCart({ sessionId });
|
|
1100
1100
|
const cartWithItems = await this._cartService.getCartWithItems({ cartId: cart.id });
|
|
@@ -1102,9 +1102,9 @@ export class CartController extends BaseController {
|
|
|
1102
1102
|
}
|
|
1103
1103
|
|
|
1104
1104
|
@post({ configs: CartRoutes.ADD_ITEM })
|
|
1105
|
-
async addToCart(c: TRouteContext
|
|
1105
|
+
async addToCart(c: TRouteContext) {
|
|
1106
1106
|
const sessionId = c.req.header('X-Session-ID') ?? 'guest';
|
|
1107
|
-
const { productId, quantity } = c.req.valid('json');
|
|
1107
|
+
const { productId, quantity } = c.req.valid<{ productId: string; quantity: number }>('json');
|
|
1108
1108
|
|
|
1109
1109
|
const cart = await this._cartService.getOrCreateCart({ sessionId });
|
|
1110
1110
|
await this._cartService.addItem({ cartId: cart.id, productId, quantity });
|
|
@@ -1114,10 +1114,10 @@ export class CartController extends BaseController {
|
|
|
1114
1114
|
}
|
|
1115
1115
|
|
|
1116
1116
|
@put({ configs: CartRoutes.UPDATE_ITEM })
|
|
1117
|
-
async updateCartItem(c: TRouteContext
|
|
1117
|
+
async updateCartItem(c: TRouteContext) {
|
|
1118
1118
|
const sessionId = c.req.header('X-Session-ID') ?? 'guest';
|
|
1119
|
-
const { productId } = c.req.valid('param');
|
|
1120
|
-
const { quantity } = c.req.valid('json');
|
|
1119
|
+
const { productId } = c.req.valid<{ productId: string }>('param');
|
|
1120
|
+
const { quantity } = c.req.valid<{ quantity: number }>('json');
|
|
1121
1121
|
|
|
1122
1122
|
const cart = await this._cartService.getOrCreateCart({ sessionId });
|
|
1123
1123
|
await this._cartService.updateItemQuantity({ cartId: cart.id, productId, quantity });
|
|
@@ -1127,9 +1127,9 @@ export class CartController extends BaseController {
|
|
|
1127
1127
|
}
|
|
1128
1128
|
|
|
1129
1129
|
@del({ configs: CartRoutes.REMOVE_ITEM })
|
|
1130
|
-
async removeFromCart(c: TRouteContext
|
|
1130
|
+
async removeFromCart(c: TRouteContext) {
|
|
1131
1131
|
const sessionId = c.req.header('X-Session-ID') ?? 'guest';
|
|
1132
|
-
const { productId } = c.req.valid('param');
|
|
1132
|
+
const { productId } = c.req.valid<{ productId: string }>('param');
|
|
1133
1133
|
|
|
1134
1134
|
const cart = await this._cartService.getOrCreateCart({ sessionId });
|
|
1135
1135
|
await this._cartService.removeItem({ cartId: cart.id, productId });
|
|
@@ -1234,24 +1234,24 @@ export class OrderController extends BaseController {
|
|
|
1234
1234
|
override binding() {}
|
|
1235
1235
|
|
|
1236
1236
|
@post({ configs: OrderRoutes.CREATE })
|
|
1237
|
-
async createOrder(c: TRouteContext
|
|
1238
|
-
const body = c.req.valid('json');
|
|
1237
|
+
async createOrder(c: TRouteContext) {
|
|
1238
|
+
const body = c.req.valid<any>('json'); // Use explicit type if available
|
|
1239
1239
|
const result = await this._orderService.createOrder({ input: body });
|
|
1240
1240
|
return c.json(result, HTTP.ResultCodes.RS_2.Created);
|
|
1241
1241
|
}
|
|
1242
1242
|
|
|
1243
1243
|
@post({ configs: OrderRoutes.CONFIRM })
|
|
1244
|
-
async confirmOrder(c: TRouteContext
|
|
1245
|
-
const { id: orderId } = c.req.valid('param');
|
|
1246
|
-
const { paymentIntentId } = c.req.valid('json');
|
|
1244
|
+
async confirmOrder(c: TRouteContext) {
|
|
1245
|
+
const { id: orderId } = c.req.valid<{ id: string }>('param');
|
|
1246
|
+
const { paymentIntentId } = c.req.valid<{ paymentIntentId: string }>('json');
|
|
1247
1247
|
|
|
1248
1248
|
const order = await this._orderService.confirmPayment({ orderId, paymentIntentId });
|
|
1249
1249
|
return c.json(order);
|
|
1250
1250
|
}
|
|
1251
1251
|
|
|
1252
1252
|
@get({ configs: OrderRoutes.GET_BY_ID })
|
|
1253
|
-
async getOrder(c: TRouteContext
|
|
1254
|
-
const { id: orderId } = c.req.valid('param');
|
|
1253
|
+
async getOrder(c: TRouteContext) {
|
|
1254
|
+
const { id: orderId } = c.req.valid<{ id: string }>('param');
|
|
1255
1255
|
const order = await this._orderService.getOrderById({ orderId });
|
|
1256
1256
|
return c.json(order);
|
|
1257
1257
|
}
|
|
@@ -1073,16 +1073,16 @@ export class ChatController extends BaseController {
|
|
|
1073
1073
|
override binding() {}
|
|
1074
1074
|
|
|
1075
1075
|
@get({ configs: ChatRoutes.GET_ROOMS })
|
|
1076
|
-
async getRooms(c: TRouteContext
|
|
1076
|
+
async getRooms(c: TRouteContext) {
|
|
1077
1077
|
const userId = c.get('userId');
|
|
1078
1078
|
const rooms = await this._chatService.getUserRooms({ userId });
|
|
1079
1079
|
return c.json(rooms);
|
|
1080
1080
|
}
|
|
1081
1081
|
|
|
1082
1082
|
@post({ configs: ChatRoutes.CREATE_ROOM })
|
|
1083
|
-
async createRoom(c: TRouteContext
|
|
1083
|
+
async createRoom(c: TRouteContext) {
|
|
1084
1084
|
const userId = c.get('userId');
|
|
1085
|
-
const data = c.req.valid('json');
|
|
1085
|
+
const data = c.req.valid<{ name: string; description?: string; isPrivate: boolean }>('json');
|
|
1086
1086
|
|
|
1087
1087
|
const room = await this._chatService.createRoom({
|
|
1088
1088
|
...data,
|
|
@@ -1093,9 +1093,9 @@ export class ChatController extends BaseController {
|
|
|
1093
1093
|
}
|
|
1094
1094
|
|
|
1095
1095
|
@get({ configs: ChatRoutes.GET_MESSAGES })
|
|
1096
|
-
async getMessages(c: TRouteContext
|
|
1097
|
-
const { roomId } = c.req.valid('param');
|
|
1098
|
-
const { limit, before } = c.req.valid('query');
|
|
1096
|
+
async getMessages(c: TRouteContext) {
|
|
1097
|
+
const { roomId } = c.req.valid<{ roomId: string }>('param');
|
|
1098
|
+
const { limit, before } = c.req.valid<{ limit?: string; before?: string }>('query');
|
|
1099
1099
|
|
|
1100
1100
|
const messages = await this._chatService.getMessages({
|
|
1101
1101
|
roomId,
|
|
@@ -1107,17 +1107,17 @@ export class ChatController extends BaseController {
|
|
|
1107
1107
|
}
|
|
1108
1108
|
|
|
1109
1109
|
@get({ configs: ChatRoutes.GET_CONVERSATIONS })
|
|
1110
|
-
async getConversations(c: TRouteContext
|
|
1110
|
+
async getConversations(c: TRouteContext) {
|
|
1111
1111
|
const userId = c.get('userId');
|
|
1112
1112
|
const conversations = await this._chatService.getConversations({ userId });
|
|
1113
1113
|
return c.json(conversations);
|
|
1114
1114
|
}
|
|
1115
1115
|
|
|
1116
1116
|
@get({ configs: ChatRoutes.GET_DIRECT_MESSAGES })
|
|
1117
|
-
async getDirectMessages(c: TRouteContext
|
|
1117
|
+
async getDirectMessages(c: TRouteContext) {
|
|
1118
1118
|
const currentUserId = c.get('userId');
|
|
1119
|
-
const { userId: otherUserId } = c.req.valid('param');
|
|
1120
|
-
const { limit, before } = c.req.valid('query');
|
|
1119
|
+
const { userId: otherUserId } = c.req.valid<{ userId: string }>('param');
|
|
1120
|
+
const { limit, before } = c.req.valid<{ limit?: string; before?: string }>('query');
|
|
1121
1121
|
|
|
1122
1122
|
const messages = await this._chatService.getDirectMessages({
|
|
1123
1123
|
userId1: currentUserId,
|
|
@@ -70,7 +70,7 @@ const MyRouteConfig = {
|
|
|
70
70
|
export class MyFeatureController extends BaseController {
|
|
71
71
|
|
|
72
72
|
@api({ configs: MyRouteConfig })
|
|
73
|
-
getData(c: TRouteContext
|
|
73
|
+
getData(c: TRouteContext) {
|
|
74
74
|
return c.json({ success: true }, HTTP.ResultCodes.RS_2.Ok);
|
|
75
75
|
}
|
|
76
76
|
}
|
|
@@ -86,12 +86,12 @@ For convenience, `Ignis` provides decorator shortcuts for each HTTP method: Thes
|
|
|
86
86
|
- `@patch(opts)`
|
|
87
87
|
- `@del(opts)`
|
|
88
88
|
|
|
89
|
-
**Example using `@get` and `@post
|
|
89
|
+
**Example using `@get` and `@post`:**
|
|
90
90
|
|
|
91
91
|
```typescript
|
|
92
92
|
import { get, post, z, jsonContent, jsonResponse, Authentication, TRouteContext, HTTP } from '@venizia/ignis';
|
|
93
93
|
|
|
94
|
-
// Define route configs as const
|
|
94
|
+
// Define route configs as const
|
|
95
95
|
const UserRoutes = {
|
|
96
96
|
LIST_USERS: {
|
|
97
97
|
path: '/',
|
|
@@ -125,26 +125,26 @@ const UserRoutes = {
|
|
|
125
125
|
schema: z.object({ id: z.string(), name: z.string() }),
|
|
126
126
|
}),
|
|
127
127
|
},
|
|
128
|
-
} as const;
|
|
128
|
+
} as const;
|
|
129
129
|
|
|
130
130
|
// ... inside a controller class
|
|
131
131
|
|
|
132
132
|
@get({ configs: UserRoutes.LIST_USERS })
|
|
133
|
-
getAllUsers(c: TRouteContext
|
|
133
|
+
getAllUsers(c: TRouteContext) {
|
|
134
134
|
return c.json([{ id: '1', name: 'John Doe' }], HTTP.ResultCodes.RS_2.Ok);
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
@get({ configs: UserRoutes.GET_USER })
|
|
138
|
-
getUserById(c: TRouteContext
|
|
139
|
-
const { id } = c.req.valid('param'); //
|
|
138
|
+
getUserById(c: TRouteContext) {
|
|
139
|
+
const { id } = c.req.valid<{ id: string }>('param'); // Explicitly typed
|
|
140
140
|
return c.json({ id, name: 'John Doe' }, HTTP.ResultCodes.RS_2.Ok);
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
@post({ configs: UserRoutes.CREATE_USER })
|
|
144
|
-
createUser(c: TRouteContext
|
|
145
|
-
const { name } = c.req.valid('json'); //
|
|
144
|
+
createUser(c: TRouteContext) {
|
|
145
|
+
const { name } = c.req.valid<{ name: string }>('json'); // Explicitly typed
|
|
146
146
|
const newUser = { id: '2', name };
|
|
147
|
-
return c.json(newUser, HTTP.ResultCodes.RS_2.Created);
|
|
147
|
+
return c.json(newUser, HTTP.ResultCodes.RS_2.Created);
|
|
148
148
|
}
|
|
149
149
|
```
|
|
150
150
|
|
|
@@ -175,8 +175,8 @@ const RouteConfigs = {
|
|
|
175
175
|
export class HealthCheckController extends BaseController {
|
|
176
176
|
|
|
177
177
|
@api({ configs: RouteConfigs.PING })
|
|
178
|
-
ping(c: TRouteContext
|
|
179
|
-
const { message } = c.req.valid('json');
|
|
178
|
+
ping(c: TRouteContext) {
|
|
179
|
+
const { message } = c.req.valid<{ message: string }>('json');
|
|
180
180
|
return c.json({ pong: message }, HTTP.ResultCodes.RS_2.Ok);
|
|
181
181
|
}
|
|
182
182
|
}
|
|
@@ -527,14 +527,7 @@ By leveraging these structured configuration options and the `ControllerFactory`
|
|
|
527
527
|
|
|
528
528
|
### Overriding CRUD Methods with Strong Typing
|
|
529
529
|
|
|
530
|
-
When extending a generated CRUD controller, you can override methods
|
|
531
|
-
|
|
532
|
-
#### Helper Types
|
|
533
|
-
|
|
534
|
-
| Type | Purpose |
|
|
535
|
-
| :--- | :--- |
|
|
536
|
-
| `THandlerContext<Definitions, Key>` | Extracts the strongly-typed Hono context for a specific route |
|
|
537
|
-
| `TInferSchema<ZodSchema>` | Extracts TypeScript type from a Zod schema |
|
|
530
|
+
When extending a generated CRUD controller, you can override methods using `TRouteContext` and explicit type arguments for validation.
|
|
538
531
|
|
|
539
532
|
#### Example: Full Controller Override Pattern
|
|
540
533
|
|
|
@@ -548,8 +541,7 @@ import {
|
|
|
548
541
|
controller,
|
|
549
542
|
ControllerFactory,
|
|
550
543
|
inject,
|
|
551
|
-
|
|
552
|
-
TInferSchema,
|
|
544
|
+
TRouteContext,
|
|
553
545
|
} from '@venizia/ignis';
|
|
554
546
|
import { z } from '@hono/zod-openapi';
|
|
555
547
|
|
|
@@ -562,6 +554,9 @@ const CreateConfigurationSchema = z.object({
|
|
|
562
554
|
group: z.string().min(1).max(50),
|
|
563
555
|
});
|
|
564
556
|
|
|
557
|
+
// Infer type for usage
|
|
558
|
+
type TCreateConfiguration = z.infer<typeof CreateConfigurationSchema>;
|
|
559
|
+
|
|
565
560
|
// Custom response schema
|
|
566
561
|
const CreateResponseSchema = z.object({
|
|
567
562
|
id: z.string(),
|
|
@@ -584,9 +579,6 @@ const _Controller = ControllerFactory.defineCrudController({
|
|
|
584
579
|
},
|
|
585
580
|
});
|
|
586
581
|
|
|
587
|
-
// Extract definitions type for method overrides
|
|
588
|
-
type TRouteDefinitions = InstanceType<typeof _Controller>['definitions'];
|
|
589
|
-
|
|
590
582
|
@controller({ path: BASE_PATH })
|
|
591
583
|
export class ConfigurationController extends _Controller {
|
|
592
584
|
constructor(
|
|
@@ -602,11 +594,11 @@ export class ConfigurationController extends _Controller {
|
|
|
602
594
|
}
|
|
603
595
|
|
|
604
596
|
// Override with full type safety
|
|
605
|
-
override async create(opts: { context:
|
|
597
|
+
override async create(opts: { context: TRouteContext }) {
|
|
606
598
|
const { context } = opts;
|
|
607
599
|
|
|
608
|
-
// Get typed request body using
|
|
609
|
-
const data = context.req.valid('json')
|
|
600
|
+
// Get typed request body using generic validation
|
|
601
|
+
const data = context.req.valid<TCreateConfiguration>('json');
|
|
610
602
|
|
|
611
603
|
// Access typed properties
|
|
612
604
|
this.logger.info('[create] code: %s, group: %s', data.code, data.group);
|
|
@@ -618,20 +610,20 @@ export class ConfigurationController extends _Controller {
|
|
|
618
610
|
}
|
|
619
611
|
|
|
620
612
|
// Override updateById
|
|
621
|
-
override async updateById(opts: { context:
|
|
613
|
+
override async updateById(opts: { context: TRouteContext }) {
|
|
622
614
|
const { context } = opts;
|
|
623
|
-
|
|
624
|
-
const
|
|
625
|
-
|
|
615
|
+
// Explicitly type parameters if needed, or rely on schema validation
|
|
616
|
+
const { id } = context.req.valid<{ id: string }>('param');
|
|
617
|
+
|
|
626
618
|
this.logger.info('[updateById] id: %s', id);
|
|
627
619
|
|
|
628
620
|
return super.updateById(opts);
|
|
629
621
|
}
|
|
630
622
|
|
|
631
623
|
// Override deleteById with audit logging
|
|
632
|
-
override async deleteById(opts: { context:
|
|
624
|
+
override async deleteById(opts: { context: TRouteContext }) {
|
|
633
625
|
const { context } = opts;
|
|
634
|
-
const { id } = context.req.valid('param');
|
|
626
|
+
const { id } = context.req.valid<{ id: string }>('param');
|
|
635
627
|
|
|
636
628
|
this.logger.warn('[deleteById] Deleting id: %s', id);
|
|
637
629
|
|
|
@@ -640,22 +632,6 @@ export class ConfigurationController extends _Controller {
|
|
|
640
632
|
}
|
|
641
633
|
```
|
|
642
634
|
|
|
643
|
-
#### Available Route Keys
|
|
644
|
-
|
|
645
|
-
Use these keys with `THandlerContext`:
|
|
646
|
-
|
|
647
|
-
| Key | Method | Path |
|
|
648
|
-
| :--- | :--- | :--- |
|
|
649
|
-
| `'COUNT'` | GET | /count |
|
|
650
|
-
| `'FIND'` | GET | / |
|
|
651
|
-
| `'FIND_BY_ID'` | GET | /:id |
|
|
652
|
-
| `'FIND_ONE'` | GET | /find-one |
|
|
653
|
-
| `'CREATE'` | POST | / |
|
|
654
|
-
| `'UPDATE_BY_ID'` | PATCH | /:id |
|
|
655
|
-
| `'UPDATE_BY'` | PATCH | / |
|
|
656
|
-
| `'DELETE_BY_ID'` | DELETE | /:id |
|
|
657
|
-
| `'DELETE_BY'` | DELETE | / |
|
|
658
|
-
|
|
659
635
|
---
|
|
660
636
|
|
|
661
637
|
## See Also
|
|
@@ -341,7 +341,7 @@ try {
|
|
|
341
341
|
}
|
|
342
342
|
```
|
|
343
343
|
|
|
344
|
-
> **Note:** For most use cases, prefer using `repository.beginTransaction()` which provides a higher-level API. See [Repositories Reference](./repositories
|
|
344
|
+
> **Note:** For most use cases, prefer using `repository.beginTransaction()` which provides a higher-level API. See [Repositories Reference](./repositories/.md#transactions) for details.
|
|
345
345
|
|
|
346
346
|
This architecture ensures that datasources are configured consistently and that the fully-initialized Drizzle connector, aware of all schemas and relations, is available to repositories for querying.
|
|
347
347
|
|