@venizia/ignis-docs 0.0.8 → 0.2.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 (180) hide show
  1. package/README.md +7 -7
  2. package/content/best-practices/api-usage-examples.md +15 -12
  3. package/content/best-practices/architectural-patterns.md +70 -78
  4. package/content/best-practices/architecture-decisions.md +91 -60
  5. package/content/best-practices/code-style-standards/advanced-patterns.md +56 -44
  6. package/content/best-practices/code-style-standards/constants-configuration.md +11 -11
  7. package/content/best-practices/code-style-standards/control-flow.md +5 -2
  8. package/content/best-practices/code-style-standards/documentation.md +13 -13
  9. package/content/best-practices/code-style-standards/function-patterns.md +9 -10
  10. package/content/best-practices/code-style-standards/index.md +1 -1
  11. package/content/best-practices/code-style-standards/naming-conventions.md +10 -8
  12. package/content/best-practices/code-style-standards/route-definitions.md +30 -12
  13. package/content/best-practices/code-style-standards/tooling.md +8 -5
  14. package/content/best-practices/code-style-standards/type-safety.md +13 -12
  15. package/content/best-practices/common-pitfalls.md +56 -37
  16. package/content/best-practices/contribution-workflow.md +13 -14
  17. package/content/best-practices/data-modeling.md +46 -22
  18. package/content/best-practices/deployment-strategies.md +28 -27
  19. package/content/best-practices/error-handling.md +48 -24
  20. package/content/best-practices/index.md +5 -5
  21. package/content/best-practices/performance-optimization.md +40 -31
  22. package/content/best-practices/security-guidelines.md +52 -23
  23. package/content/best-practices/testing-strategies.md +65 -51
  24. package/content/best-practices/troubleshooting-tips.md +24 -24
  25. package/content/extensions/components/{swagger.md → api-reference.md} +40 -31
  26. package/content/extensions/components/authentication/api.md +19 -19
  27. package/content/extensions/components/authentication/errors.md +7 -7
  28. package/content/extensions/components/authentication/index.md +10 -8
  29. package/content/extensions/components/authentication/usage.md +101 -6
  30. package/content/extensions/components/authorization/api.md +45 -25
  31. package/content/extensions/components/authorization/errors.md +6 -6
  32. package/content/extensions/components/authorization/index.md +11 -10
  33. package/content/extensions/components/authorization/usage.md +21 -21
  34. package/content/extensions/components/health-check.md +1 -1
  35. package/content/extensions/components/index.md +5 -5
  36. package/content/extensions/components/mail/errors.md +15 -15
  37. package/content/extensions/components/mail/index.md +1 -2
  38. package/content/extensions/components/mail/usage.md +1 -1
  39. package/content/extensions/components/request-tracker.md +1 -1
  40. package/content/extensions/components/socket-io/api.md +9 -9
  41. package/content/extensions/components/socket-io/errors.md +5 -5
  42. package/content/extensions/components/socket-io/index.md +8 -8
  43. package/content/extensions/components/socket-io/usage.md +1 -1
  44. package/content/extensions/components/static-asset/api.md +17 -4
  45. package/content/extensions/components/static-asset/errors.md +4 -4
  46. package/content/extensions/components/static-asset/index.md +26 -28
  47. package/content/extensions/components/static-asset/usage.md +13 -12
  48. package/content/extensions/components/template/index.md +2 -2
  49. package/content/extensions/components/template/setup-page.md +1 -1
  50. package/content/extensions/components/websocket/api.md +3 -3
  51. package/content/extensions/components/websocket/errors.md +5 -5
  52. package/content/extensions/components/websocket/index.md +5 -5
  53. package/content/extensions/components/websocket/usage.md +3 -3
  54. package/content/extensions/helpers/cron/index.md +2 -2
  55. package/content/extensions/helpers/crypto/index.md +1 -1
  56. package/content/extensions/helpers/env/index.md +27 -12
  57. package/content/extensions/helpers/error/index.md +81 -25
  58. package/content/extensions/helpers/index.md +2 -3
  59. package/content/extensions/helpers/inversion/index.md +15 -7
  60. package/content/extensions/helpers/kafka/compile-binary.md +92 -0
  61. package/content/extensions/helpers/kafka/examples.md +1 -1
  62. package/content/extensions/helpers/kafka/index.md +3 -0
  63. package/content/extensions/helpers/logger/index.md +32 -2
  64. package/content/extensions/helpers/network/index.md +6 -0
  65. package/content/extensions/helpers/queue/index.md +14 -17
  66. package/content/extensions/helpers/redis/index.md +548 -323
  67. package/content/extensions/helpers/socket-io/index.md +14 -10
  68. package/content/extensions/helpers/storage/api.md +44 -8
  69. package/content/extensions/helpers/storage/index.md +43 -7
  70. package/content/extensions/helpers/template/index.md +6 -3
  71. package/content/extensions/helpers/types/index.md +11 -8
  72. package/content/extensions/helpers/websocket/api.md +9 -9
  73. package/content/extensions/helpers/websocket/index.md +7 -7
  74. package/content/extensions/helpers/worker-thread/index.md +2 -2
  75. package/content/extensions/index.md +3 -4
  76. package/content/extensions/src-details/mcp-server.md +18 -24
  77. package/content/guides/core-concepts/application/bootstrapping.md +11 -14
  78. package/content/guides/core-concepts/application/index.md +3 -3
  79. package/content/guides/core-concepts/components.md +19 -10
  80. package/content/guides/core-concepts/dependency-injection.md +6 -3
  81. package/content/guides/core-concepts/grpc-controllers.md +6 -5
  82. package/content/guides/core-concepts/persistent/datasources.md +42 -43
  83. package/content/guides/core-concepts/persistent/index.md +16 -7
  84. package/content/guides/core-concepts/persistent/models.md +24 -20
  85. package/content/guides/core-concepts/persistent/postgres-drivers.md +201 -0
  86. package/content/guides/core-concepts/persistent/repositories.md +40 -23
  87. package/content/guides/core-concepts/persistent/search-meilisearch.md +185 -0
  88. package/content/guides/core-concepts/persistent/search-typesense.md +431 -0
  89. package/content/guides/core-concepts/persistent/transactions.md +61 -25
  90. package/content/guides/core-concepts/rest-controllers.md +12 -9
  91. package/content/guides/core-concepts/services.md +330 -60
  92. package/content/guides/get-started/5-minute-quickstart.md +15 -15
  93. package/content/guides/get-started/philosophy.md +36 -36
  94. package/content/guides/get-started/setup.md +3 -3
  95. package/content/guides/index.md +3 -3
  96. package/content/guides/migrations/redis-helpers-migration.md +177 -0
  97. package/content/guides/migrations/scoped-rbac-migration.md +17 -17
  98. package/content/guides/migrations/unified-connectors-migration.md +113 -0
  99. package/content/guides/reference/glossary.md +19 -12
  100. package/content/guides/reference/mcp-docs-server.md +22 -18
  101. package/content/guides/tutorials/building-a-crud-api.md +37 -44
  102. package/content/guides/tutorials/complete-installation.md +17 -17
  103. package/content/guides/tutorials/ecommerce-api.md +163 -124
  104. package/content/guides/tutorials/realtime-chat.md +181 -135
  105. package/content/guides/tutorials/testing.md +65 -523
  106. package/content/index.md +2 -180
  107. package/content/public/apple-touch-icon.png +0 -0
  108. package/content/public/og-image.png +0 -0
  109. package/content/public/site.webmanifest +11 -0
  110. package/content/references/base/application.md +4 -5
  111. package/content/references/base/bootstrapping.md +18 -5
  112. package/content/references/base/components.md +149 -120
  113. package/content/references/base/connectors.md +178 -0
  114. package/content/references/base/controllers.md +41 -30
  115. package/content/references/base/datasources.md +163 -92
  116. package/content/references/base/dependency-injection.md +34 -22
  117. package/content/references/base/filter-system/application-usage.md +17 -14
  118. package/content/references/base/filter-system/array-operators.md +7 -2
  119. package/content/references/base/filter-system/comparison-operators.md +3 -0
  120. package/content/references/base/filter-system/default-filter.md +89 -71
  121. package/content/references/base/filter-system/fields-order-pagination.md +22 -22
  122. package/content/references/base/filter-system/index.md +6 -3
  123. package/content/references/base/filter-system/json-filtering.md +20 -1
  124. package/content/references/base/filter-system/list-operators.md +1 -1
  125. package/content/references/base/filter-system/logical-operators.md +33 -1
  126. package/content/references/base/filter-system/null-operators.md +30 -1
  127. package/content/references/base/filter-system/quick-reference.md +23 -4
  128. package/content/references/base/filter-system/tips.md +5 -5
  129. package/content/references/base/filter-system/use-cases.md +12 -12
  130. package/content/references/base/grpc-controllers.md +13 -13
  131. package/content/references/base/index.md +24 -12
  132. package/content/references/base/middlewares.md +265 -327
  133. package/content/references/base/models.md +63 -49
  134. package/content/references/base/providers.md +136 -130
  135. package/content/references/base/repositories/advanced.md +59 -58
  136. package/content/references/base/repositories/index.md +115 -91
  137. package/content/references/base/repositories/mixins.md +55 -291
  138. package/content/references/base/repositories/relations.md +54 -64
  139. package/content/references/base/repositories/soft-deletable.md +31 -30
  140. package/content/references/base/services.md +296 -93
  141. package/content/references/configuration/environment-variables.md +49 -31
  142. package/content/references/configuration/index.md +6 -6
  143. package/content/references/index.md +17 -12
  144. package/content/references/quick-reference.md +65 -106
  145. package/content/references/utilities/crypto.md +65 -23
  146. package/content/references/utilities/index.md +3 -3
  147. package/content/references/utilities/jsx.md +6 -4
  148. package/content/references/utilities/module.md +68 -20
  149. package/content/references/utilities/parse.md +4 -14
  150. package/content/references/utilities/promise.md +9 -7
  151. package/content/references/utilities/schema.md +5 -3
  152. package/dist/mcp-server/common/guards.d.ts +8 -0
  153. package/dist/mcp-server/common/guards.d.ts.map +1 -0
  154. package/dist/mcp-server/common/guards.js +14 -0
  155. package/dist/mcp-server/common/guards.js.map +1 -0
  156. package/dist/mcp-server/common/index.d.ts +1 -0
  157. package/dist/mcp-server/common/index.d.ts.map +1 -1
  158. package/dist/mcp-server/common/index.js +1 -0
  159. package/dist/mcp-server/common/index.js.map +1 -1
  160. package/dist/mcp-server/helpers/docs.helper.d.ts.map +1 -1
  161. package/dist/mcp-server/helpers/docs.helper.js +4 -2
  162. package/dist/mcp-server/helpers/docs.helper.js.map +1 -1
  163. package/dist/mcp-server/helpers/github.helper.js +1 -1
  164. package/dist/mcp-server/index.js +7 -2
  165. package/dist/mcp-server/index.js.map +1 -1
  166. package/dist/mcp-server/tools/base.tool.d.ts +6 -2
  167. package/dist/mcp-server/tools/base.tool.d.ts.map +1 -1
  168. package/dist/mcp-server/tools/base.tool.js.map +1 -1
  169. package/dist/mcp-server/tools/docs/search-documents.tool.d.ts +1 -1
  170. package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
  171. package/dist/mcp-server/tools/github/search-code.tool.d.ts +1 -1
  172. package/dist/mcp-server/tools/github/search-code.tool.d.ts.map +1 -1
  173. package/dist/mcp-server/tools/github/search-code.tool.js +4 -1
  174. package/dist/mcp-server/tools/github/search-code.tool.js.map +1 -1
  175. package/dist/mcp-server/tools/github/verify-dependencies.tool.d.ts.map +1 -1
  176. package/dist/mcp-server/tools/github/verify-dependencies.tool.js +3 -1
  177. package/dist/mcp-server/tools/github/verify-dependencies.tool.js.map +1 -1
  178. package/package.json +9 -9
  179. package/content/extensions/helpers/testing/index.md +0 -510
  180. package/content/references/base/middleware.md +0 -347
@@ -28,7 +28,7 @@ cd ecommerce-api
28
28
  bun init -y
29
29
 
30
30
  # Install dependencies
31
- bun add hono @hono/zod-openapi @venizia/ignis @venizia/ignis-helpers
31
+ bun add hono @hono/zod-openapi @scalar/hono-api-reference @venizia/ignis @venizia/ignis-helpers
32
32
  bun add drizzle-orm drizzle-zod pg stripe
33
33
  bun add -d typescript @types/bun @venizia/dev-configs drizzle-kit @types/pg
34
34
  ```
@@ -85,10 +85,11 @@ Models in IGNIS combine Drizzle ORM schemas with Entity classes.
85
85
  // src/models/category.model.ts
86
86
  import {
87
87
  BaseEntity,
88
- createRelations,
89
88
  generateIdColumnDefs,
90
89
  generateTzColumnDefs,
91
90
  model,
91
+ RelationTypes,
92
+ TRelationConfig,
92
93
  TTableObject,
93
94
  } from '@venizia/ignis';
94
95
  import { pgTable, text, varchar } from 'drizzle-orm/pg-core';
@@ -102,21 +103,28 @@ export const categoryTable = pgTable('Category', {
102
103
  parentId: text('parent_id'),
103
104
  });
104
105
 
105
- export const categoryRelations = createRelations({
106
- source: categoryTable,
107
- relations: [
108
- { type: 'one', name: 'parent', target: () => categoryTable, fields: ['parentId'], references: ['id'] },
109
- { type: 'many', name: 'children', target: () => categoryTable, fields: ['id'], references: ['parentId'] },
110
- ],
111
- });
112
-
113
106
  export type TCategorySchema = typeof categoryTable;
114
107
  export type TCategory = TTableObject<TCategorySchema>;
115
108
 
116
109
  @model({ type: 'entity' })
117
110
  export class Category extends BaseEntity<typeof Category.schema> {
118
111
  static override schema = categoryTable;
119
- static override relations = () => categoryRelations.definitions;
112
+
113
+ static override relations = (): TRelationConfig[] => [
114
+ {
115
+ name: 'parent',
116
+ type: RelationTypes.ONE,
117
+ schema: categoryTable,
118
+ metadata: { fields: [categoryTable.parentId], references: [categoryTable.id] },
119
+ },
120
+ {
121
+ name: 'children',
122
+ type: RelationTypes.MANY,
123
+ schema: categoryTable,
124
+ metadata: { fields: [categoryTable.id], references: [categoryTable.parentId] },
125
+ },
126
+ ];
127
+
120
128
  static override TABLE_NAME = 'Category';
121
129
  }
122
130
  ```
@@ -127,14 +135,15 @@ export class Category extends BaseEntity<typeof Category.schema> {
127
135
  // src/models/product.model.ts
128
136
  import {
129
137
  BaseEntity,
130
- createRelations,
131
138
  generateIdColumnDefs,
132
139
  generateTzColumnDefs,
133
140
  model,
141
+ RelationTypes,
142
+ TRelationConfig,
134
143
  TTableObject,
135
144
  } from '@venizia/ignis';
136
145
  import { pgTable, text, varchar, decimal, integer, boolean } from 'drizzle-orm/pg-core';
137
- import { categoryTable, Category } from './category.model';
146
+ import { categoryTable } from './category.model';
138
147
 
139
148
  export const productTable = pgTable('Product', {
140
149
  ...generateIdColumnDefs({ id: { dataType: 'string' } }),
@@ -150,20 +159,22 @@ export const productTable = pgTable('Product', {
150
159
  imageUrl: text('image_url'),
151
160
  });
152
161
 
153
- export const productRelations = createRelations({
154
- source: productTable,
155
- relations: [
156
- { type: 'one', name: 'category', target: () => categoryTable, fields: ['categoryId'], references: ['id'] },
157
- ],
158
- });
159
-
160
162
  export type TProductSchema = typeof productTable;
161
163
  export type TProduct = TTableObject<TProductSchema>;
162
164
 
163
165
  @model({ type: 'entity' })
164
166
  export class Product extends BaseEntity<typeof Product.schema> {
165
167
  static override schema = productTable;
166
- static override relations = () => productRelations.definitions;
168
+
169
+ static override relations = (): TRelationConfig[] => [
170
+ {
171
+ name: 'category',
172
+ type: RelationTypes.ONE,
173
+ schema: categoryTable,
174
+ metadata: { fields: [productTable.categoryId], references: [categoryTable.id] },
175
+ },
176
+ ];
177
+
167
178
  static override TABLE_NAME = 'Product';
168
179
  }
169
180
  ```
@@ -174,10 +185,11 @@ export class Product extends BaseEntity<typeof Product.schema> {
174
185
  // src/models/cart.model.ts
175
186
  import {
176
187
  BaseEntity,
177
- createRelations,
178
188
  generateIdColumnDefs,
179
189
  generateTzColumnDefs,
180
190
  model,
191
+ RelationTypes,
192
+ TRelationConfig,
181
193
  TTableObject,
182
194
  } from '@venizia/ignis';
183
195
  import { pgTable, text, varchar, integer } from 'drizzle-orm/pg-core';
@@ -198,21 +210,6 @@ export const cartItemTable = pgTable('CartItem', {
198
210
  quantity: integer('quantity').default(1).notNull(),
199
211
  });
200
212
 
201
- export const cartRelations = createRelations({
202
- source: cartTable,
203
- relations: [
204
- { type: 'many', name: 'items', target: () => cartItemTable, fields: ['id'], references: ['cartId'] },
205
- ],
206
- });
207
-
208
- export const cartItemRelations = createRelations({
209
- source: cartItemTable,
210
- relations: [
211
- { type: 'one', name: 'cart', target: () => cartTable, fields: ['cartId'], references: ['id'] },
212
- { type: 'one', name: 'product', target: () => productTable, fields: ['productId'], references: ['id'] },
213
- ],
214
- });
215
-
216
213
  export type TCartSchema = typeof cartTable;
217
214
  export type TCart = TTableObject<TCartSchema>;
218
215
  export type TCartItemSchema = typeof cartItemTable;
@@ -221,14 +218,38 @@ export type TCartItem = TTableObject<TCartItemSchema>;
221
218
  @model({ type: 'entity' })
222
219
  export class Cart extends BaseEntity<typeof Cart.schema> {
223
220
  static override schema = cartTable;
224
- static override relations = () => cartRelations.definitions;
221
+
222
+ static override relations = (): TRelationConfig[] => [
223
+ {
224
+ name: 'items',
225
+ type: RelationTypes.MANY,
226
+ schema: cartItemTable,
227
+ metadata: { fields: [cartTable.id], references: [cartItemTable.cartId] },
228
+ },
229
+ ];
230
+
225
231
  static override TABLE_NAME = 'Cart';
226
232
  }
227
233
 
228
234
  @model({ type: 'entity' })
229
235
  export class CartItem extends BaseEntity<typeof CartItem.schema> {
230
236
  static override schema = cartItemTable;
231
- static override relations = () => cartItemRelations.definitions;
237
+
238
+ static override relations = (): TRelationConfig[] => [
239
+ {
240
+ name: 'cart',
241
+ type: RelationTypes.ONE,
242
+ schema: cartTable,
243
+ metadata: { fields: [cartItemTable.cartId], references: [cartTable.id] },
244
+ },
245
+ {
246
+ name: 'product',
247
+ type: RelationTypes.ONE,
248
+ schema: productTable,
249
+ metadata: { fields: [cartItemTable.productId], references: [productTable.id] },
250
+ },
251
+ ];
252
+
232
253
  static override TABLE_NAME = 'CartItem';
233
254
  }
234
255
  ```
@@ -239,10 +260,11 @@ export class CartItem extends BaseEntity<typeof CartItem.schema> {
239
260
  // src/models/order.model.ts
240
261
  import {
241
262
  BaseEntity,
242
- createRelations,
243
263
  generateIdColumnDefs,
244
264
  generateTzColumnDefs,
245
265
  model,
266
+ RelationTypes,
267
+ TRelationConfig,
246
268
  TTableObject,
247
269
  } from '@venizia/ignis';
248
270
  import { pgTable, text, varchar, decimal, integer, jsonb } from 'drizzle-orm/pg-core';
@@ -272,21 +294,6 @@ export const orderItemTable = pgTable('OrderItem', {
272
294
  quantity: integer('quantity').notNull(),
273
295
  });
274
296
 
275
- export const orderRelations = createRelations({
276
- source: orderTable,
277
- relations: [
278
- { type: 'many', name: 'items', target: () => orderItemTable, fields: ['id'], references: ['orderId'] },
279
- ],
280
- });
281
-
282
- export const orderItemRelations = createRelations({
283
- source: orderItemTable,
284
- relations: [
285
- { type: 'one', name: 'order', target: () => orderTable, fields: ['orderId'], references: ['id'] },
286
- { type: 'one', name: 'product', target: () => productTable, fields: ['productId'], references: ['id'] },
287
- ],
288
- });
289
-
290
297
  export type TOrderSchema = typeof orderTable;
291
298
  export type TOrder = TTableObject<TOrderSchema>;
292
299
  export type TOrderItemSchema = typeof orderItemTable;
@@ -295,14 +302,38 @@ export type TOrderItem = TTableObject<TOrderItemSchema>;
295
302
  @model({ type: 'entity' })
296
303
  export class Order extends BaseEntity<typeof Order.schema> {
297
304
  static override schema = orderTable;
298
- static override relations = () => orderRelations.definitions;
305
+
306
+ static override relations = (): TRelationConfig[] => [
307
+ {
308
+ name: 'items',
309
+ type: RelationTypes.MANY,
310
+ schema: orderItemTable,
311
+ metadata: { fields: [orderTable.id], references: [orderItemTable.orderId] },
312
+ },
313
+ ];
314
+
299
315
  static override TABLE_NAME = 'Order';
300
316
  }
301
317
 
302
318
  @model({ type: 'entity' })
303
319
  export class OrderItem extends BaseEntity<typeof OrderItem.schema> {
304
320
  static override schema = orderItemTable;
305
- static override relations = () => orderItemRelations.definitions;
321
+
322
+ static override relations = (): TRelationConfig[] => [
323
+ {
324
+ name: 'order',
325
+ type: RelationTypes.ONE,
326
+ schema: orderTable,
327
+ metadata: { fields: [orderItemTable.orderId], references: [orderTable.id] },
328
+ },
329
+ {
330
+ name: 'product',
331
+ type: RelationTypes.ONE,
332
+ schema: productTable,
333
+ metadata: { fields: [orderItemTable.productId], references: [productTable.id] },
334
+ },
335
+ ];
336
+
306
337
  static override TABLE_NAME = 'OrderItem';
307
338
  }
308
339
  ```
@@ -326,7 +357,7 @@ import {
326
357
  datasource,
327
358
  ValueOrPromise,
328
359
  } from '@venizia/ignis';
329
- import { drizzle } from 'drizzle-orm/node-postgres';
360
+ import { NodePostgresDriver } from '@venizia/ignis/postgres/node-postgres';
330
361
  import { Pool } from 'pg';
331
362
 
332
363
  interface IDSConfigs {
@@ -337,7 +368,7 @@ interface IDSConfigs {
337
368
  password: string;
338
369
  }
339
370
 
340
- @datasource({ driver: 'node-postgres' })
371
+ @datasource({ driver: NodePostgresDriver })
341
372
  export class PostgresDataSource extends BaseDataSource<IDSConfigs> {
342
373
  constructor() {
343
374
  super({
@@ -353,16 +384,18 @@ export class PostgresDataSource extends BaseDataSource<IDSConfigs> {
353
384
  }
354
385
 
355
386
  override configure(): ValueOrPromise<void> {
356
- const schema = this.getSchema();
387
+ const schema = Object.keys(this.getSchema());
357
388
 
358
389
  this.logger.debug(
359
390
  '[configure] Auto-discovered schema | Schema + Relations (%s): %o',
360
- Object.keys(schema).length,
361
- Object.keys(schema),
391
+ schema.length,
392
+ schema,
362
393
  );
363
394
 
364
- const client = new Pool(this.settings);
365
- this.connector = drizzle({ client, schema });
395
+ // The client must land on this.client - a local would leave beginTransaction() with nothing
396
+ // to resolve a driver from, and it would throw `No driver and no client`. NodePostgresDriver
397
+ // named in @datasource above is what wires the driver and Drizzle connector from it.
398
+ this.client = new Pool(this.settings);
366
399
  }
367
400
  }
368
401
  ```
@@ -420,24 +453,25 @@ export class CartRepository extends DefaultCRUDRepository<typeof Cart.schema> {
420
453
 
421
454
  async findCartItem(opts: { cartId: string; productId: string }) {
422
455
  return this._cartItemRepo.findOne({
423
- where: { cartId: opts.cartId, productId: opts.productId },
456
+ filter: { where: { cartId: opts.cartId, productId: opts.productId } },
424
457
  });
425
458
  }
426
459
 
427
460
  async addCartItem(opts: { cartId: string; productId: string; quantity: number }) {
428
- return this._cartItemRepo.create(opts);
461
+ const rs = await this._cartItemRepo.create({ data: opts });
462
+ return rs.data;
429
463
  }
430
464
 
431
465
  async updateCartItem(opts: { itemId: string; data: { quantity: number } }) {
432
- return this._cartItemRepo.updateById(opts.itemId, opts.data);
466
+ return this._cartItemRepo.updateById({ id: opts.itemId, data: opts.data });
433
467
  }
434
468
 
435
469
  async deleteCartItem(opts: { itemId: string }) {
436
- return this._cartItemRepo.deleteById(opts.itemId);
470
+ return this._cartItemRepo.deleteById({ id: opts.itemId });
437
471
  }
438
472
 
439
473
  async getCartItems(opts: { cartId: string }) {
440
- return this._cartItemRepo.find({ where: { cartId: opts.cartId } });
474
+ return this._cartItemRepo.find({ filter: { where: { cartId: opts.cartId } } });
441
475
  }
442
476
 
443
477
  async clearCart(opts: { cartId: string }) {
@@ -478,11 +512,12 @@ export class OrderRepository extends DefaultCRUDRepository<typeof Order.schema>
478
512
  price: string;
479
513
  quantity: number;
480
514
  }) {
481
- return this._orderItemRepo.create(opts);
515
+ const rs = await this._orderItemRepo.create({ data: opts });
516
+ return rs.data;
482
517
  }
483
518
 
484
519
  async getOrderItems(opts: { orderId: string }) {
485
- return this._orderItemRepo.find({ where: { orderId: opts.orderId } });
520
+ return this._orderItemRepo.find({ filter: { where: { orderId: opts.orderId } } });
486
521
  }
487
522
  }
488
523
  ```
@@ -496,7 +531,7 @@ import { BaseService } from '@venizia/ignis';
496
531
  import { ProductRepository } from '../repositories/product.repository';
497
532
  import { getError } from '@venizia/ignis-helpers';
498
533
 
499
- @injectable()
534
+ @injectable({})
500
535
  export class ProductService extends BaseService {
501
536
  constructor(
502
537
  @inject({ key: 'repositories.ProductRepository' })
@@ -507,18 +542,20 @@ export class ProductService extends BaseService {
507
542
 
508
543
  async getActiveProducts(opts: { categoryId?: string; limit?: number; offset?: number }) {
509
544
  return this._productRepo.find({
510
- where: {
511
- isActive: true,
512
- ...(opts.categoryId && { categoryId: opts.categoryId }),
545
+ filter: {
546
+ where: {
547
+ isActive: true,
548
+ ...(opts.categoryId && { categoryId: opts.categoryId }),
549
+ },
550
+ order: ['createdAt DESC'],
551
+ limit: opts.limit ?? 20,
552
+ offset: opts.offset ?? 0,
513
553
  },
514
- orderBy: { createdAt: 'desc' },
515
- limit: opts.limit ?? 20,
516
- offset: opts.offset ?? 0,
517
554
  });
518
555
  }
519
556
 
520
557
  async getProductById(opts: { id: string }) {
521
- const product = await this._productRepo.findById(opts.id);
558
+ const product = await this._productRepo.findById({ id: opts.id });
522
559
  if (!product) {
523
560
  throw getError({ statusCode: 404, message: 'Product not found' });
524
561
  }
@@ -540,16 +577,16 @@ export class ProductService extends BaseService {
540
577
  });
541
578
  }
542
579
 
543
- await this._productRepo.updateById(opts.productId, {
580
+ await this._productRepo.updateById({ id: opts.productId, data: {
544
581
  stock: product.stock - opts.quantity,
545
- });
582
+ } });
546
583
  }
547
584
 
548
585
  async releaseStock(opts: { productId: string; quantity: number }) {
549
586
  const product = await this.getProductById({ id: opts.productId });
550
- await this._productRepo.updateById(opts.productId, {
587
+ await this._productRepo.updateById({ id: opts.productId, data: {
551
588
  stock: product.stock + opts.quantity,
552
- });
589
+ } });
553
590
  }
554
591
  }
555
592
  ```
@@ -569,7 +606,7 @@ interface ICartItem {
569
606
  quantity: number;
570
607
  }
571
608
 
572
- @injectable()
609
+ @injectable({})
573
610
  export class CartService extends BaseService {
574
611
  constructor(
575
612
  @inject({ key: 'repositories.CartRepository' })
@@ -583,16 +620,14 @@ export class CartService extends BaseService {
583
620
  async getOrCreateCart(opts: { userId?: string; sessionId?: string }) {
584
621
  // Try to find existing cart
585
622
  let cart = await this._cartRepo.findOne({
586
- where: opts.userId
623
+ filter: { where: opts.userId
587
624
  ? { userId: opts.userId }
588
- : { sessionId: opts.sessionId },
625
+ : { sessionId: opts.sessionId } },
589
626
  });
590
627
 
591
628
  if (!cart) {
592
- cart = await this._cartRepo.create({
593
- userId: opts.userId,
594
- sessionId: opts.sessionId,
595
- });
629
+ const rs = await this._cartRepo.create({ data: { userId: opts.userId, sessionId: opts.sessionId } });
630
+ cart = rs.data;
596
631
  }
597
632
 
598
633
  return cart;
@@ -657,7 +692,7 @@ export class CartService extends BaseService {
657
692
  }
658
693
 
659
694
  async getCartWithItems(opts: { cartId: string }) {
660
- const cart = await this._cartRepo.findById(opts.cartId);
695
+ const cart = await this._cartRepo.findById({ id: opts.cartId });
661
696
  if (!cart) {
662
697
  throw getError({ statusCode: 404, message: 'Cart not found' });
663
698
  }
@@ -706,22 +741,24 @@ import { ProductService } from './product.service';
706
741
  import { PaymentService } from './payment.service';
707
742
  import { getError } from '@venizia/ignis-helpers';
708
743
 
744
+ interface IOrderAddress {
745
+ name: string;
746
+ line1: string;
747
+ line2?: string;
748
+ city: string;
749
+ state: string;
750
+ postalCode: string;
751
+ country: string;
752
+ }
753
+
709
754
  interface ICreateOrderInput {
710
755
  cartId: string;
711
756
  email: string;
712
- shippingAddress: {
713
- name: string;
714
- line1: string;
715
- line2?: string;
716
- city: string;
717
- state: string;
718
- postalCode: string;
719
- country: string;
720
- };
721
- billingAddress?: typeof shippingAddress;
757
+ shippingAddress: IOrderAddress;
758
+ billingAddress?: IOrderAddress;
722
759
  }
723
760
 
724
- @injectable()
761
+ @injectable({})
725
762
  export class OrderService extends BaseService {
726
763
  constructor(
727
764
  @inject({ key: 'repositories.OrderRepository' })
@@ -769,13 +806,13 @@ export class OrderService extends BaseService {
769
806
  amount: Math.round(total * 100), // Stripe uses cents
770
807
  currency: 'usd',
771
808
  metadata: {
772
- cartId: input.cartId,
773
- email: input.email,
809
+ cartId: opts.input.cartId,
810
+ email: opts.input.email,
774
811
  },
775
812
  });
776
813
 
777
814
  // Create order
778
- const order = await this._orderRepo.create({
815
+ const { data: order } = await this._orderRepo.create({ data: {
779
816
  email: opts.input.email,
780
817
  status: 'pending_payment',
781
818
  subtotal: subtotal.toString(),
@@ -785,7 +822,7 @@ export class OrderService extends BaseService {
785
822
  shippingAddress: opts.input.shippingAddress,
786
823
  billingAddress: opts.input.billingAddress ?? opts.input.shippingAddress,
787
824
  paymentIntentId: paymentIntent.id,
788
- });
825
+ } });
789
826
 
790
827
  // Create order items
791
828
  for (const item of cart.items) {
@@ -805,7 +842,7 @@ export class OrderService extends BaseService {
805
842
  }
806
843
 
807
844
  async confirmPayment(opts: { orderId: string; paymentIntentId: string }) {
808
- const order = await this._orderRepo.findById(opts.orderId);
845
+ const order = await this._orderRepo.findById({ id: opts.orderId });
809
846
 
810
847
  if (!order) {
811
848
  throw getError({ statusCode: 404, message: 'Order not found' });
@@ -823,7 +860,7 @@ export class OrderService extends BaseService {
823
860
  }
824
861
 
825
862
  // Update order status
826
- await this._orderRepo.updateById(opts.orderId, { status: 'paid' });
863
+ await this._orderRepo.updateById({ id: opts.orderId, data: { status: 'paid' } });
827
864
 
828
865
  // Reserve stock for all items
829
866
  const orderItems = await this._orderRepo.getOrderItems({ orderId: opts.orderId });
@@ -831,18 +868,20 @@ export class OrderService extends BaseService {
831
868
  await this._productService.reserveStock({ productId: item.productId, quantity: item.quantity });
832
869
  }
833
870
 
834
- return this._orderRepo.findById(opts.orderId);
871
+ return this._orderRepo.findById({ id: opts.orderId });
835
872
  }
836
873
 
837
874
  async getOrdersByUser(opts: { userId: string }) {
838
875
  return this._orderRepo.find({
839
- where: { userId: opts.userId },
840
- orderBy: { createdAt: 'desc' },
876
+ filter: {
877
+ where: { userId: opts.userId },
878
+ order: ['createdAt DESC'],
879
+ },
841
880
  });
842
881
  }
843
882
 
844
883
  async getOrderById(opts: { orderId: string }) {
845
- const order = await this._orderRepo.findById(opts.orderId);
884
+ const order = await this._orderRepo.findById({ id: opts.orderId });
846
885
  if (!order) {
847
886
  throw getError({ statusCode: 404, message: 'Order not found' });
848
887
  }
@@ -858,7 +897,7 @@ export class OrderService extends BaseService {
858
897
  throw getError({ statusCode: 400, message: 'Invalid status' });
859
898
  }
860
899
 
861
- return this._orderRepo.updateById(opts.orderId, { status: opts.status });
900
+ return this._orderRepo.updateById({ id: opts.orderId, data: { status: opts.status } });
862
901
  }
863
902
  }
864
903
  ```
@@ -870,16 +909,16 @@ export class OrderService extends BaseService {
870
909
  import { injectable } from '@venizia/ignis';
871
910
  import { BaseService } from '@venizia/ignis';
872
911
  import Stripe from 'stripe';
873
- import { EnvHelper } from '@venizia/ignis-helpers';
912
+ import { applicationEnvironment } from '@venizia/ignis-helpers';
874
913
 
875
- @injectable()
914
+ @injectable({})
876
915
  export class PaymentService extends BaseService {
877
916
  private _stripe: Stripe;
878
917
 
879
918
  constructor() {
880
919
  super({ scope: PaymentService.name });
881
920
 
882
- const secretKey = EnvHelper.get('APP_ENV_STRIPE_SECRET_KEY');
921
+ const secretKey = applicationEnvironment.get<string>('APP_ENV_STRIPE_SECRET_KEY');
883
922
  this._stripe = new Stripe(secretKey, {
884
923
  apiVersion: '2023-10-16',
885
924
  });
@@ -913,7 +952,7 @@ export class PaymentService extends BaseService {
913
952
  }
914
953
 
915
954
  async createWebhookEvent(opts: { payload: string; signature: string }) {
916
- const webhookSecret = EnvHelper.get('APP_ENV_STRIPE_WEBHOOK_SECRET');
955
+ const webhookSecret = applicationEnvironment.get<string>('APP_ENV_STRIPE_WEBHOOK_SECRET');
917
956
  return this._stripe.webhooks.constructEvent(opts.payload, opts.signature, webhookSecret);
918
957
  }
919
958
  }
@@ -961,7 +1000,7 @@ const ProductRoutes = {
961
1000
  },
962
1001
  GET_BY_ID: {
963
1002
  method: HTTP.Methods.GET,
964
- path: '/:id',
1003
+ path: '/{id}',
965
1004
  request: {
966
1005
  params: z.object({ id: z.string().uuid() }),
967
1006
  },
@@ -1059,7 +1098,7 @@ const CartRoutes = {
1059
1098
  },
1060
1099
  UPDATE_ITEM: {
1061
1100
  method: HTTP.Methods.PUT,
1062
- path: '/items/:productId',
1101
+ path: '/items/{productId}',
1063
1102
  request: {
1064
1103
  params: z.object({ productId: z.string().uuid() }),
1065
1104
  body: jsonContent({
@@ -1077,7 +1116,7 @@ const CartRoutes = {
1077
1116
  },
1078
1117
  REMOVE_ITEM: {
1079
1118
  method: HTTP.Methods.DELETE,
1080
- path: '/items/:productId',
1119
+ path: '/items/{productId}',
1081
1120
  request: {
1082
1121
  params: z.object({ productId: z.string().uuid() }),
1083
1122
  },
@@ -1198,7 +1237,7 @@ const OrderRoutes = {
1198
1237
  },
1199
1238
  CONFIRM: {
1200
1239
  method: HTTP.Methods.POST,
1201
- path: '/:id/confirm',
1240
+ path: '/{id}/confirm',
1202
1241
  request: {
1203
1242
  params: z.object({ id: z.string().uuid() }),
1204
1243
  body: jsonContent({
@@ -1216,7 +1255,7 @@ const OrderRoutes = {
1216
1255
  },
1217
1256
  GET_BY_ID: {
1218
1257
  method: HTTP.Methods.GET,
1219
- path: '/:id',
1258
+ path: '/{id}',
1220
1259
  request: {
1221
1260
  params: z.object({ id: z.string().uuid() }),
1222
1261
  },
@@ -1272,7 +1311,7 @@ export class OrderController extends BaseRestController {
1272
1311
  ```typescript
1273
1312
  // src/application.ts
1274
1313
  import { BaseApplication, IApplicationInfo } from '@venizia/ignis';
1275
- import { HealthCheckComponent, SwaggerComponent } from '@venizia/ignis';
1314
+ import { HealthCheckComponent, ApiReferenceComponent } from '@venizia/ignis';
1276
1315
 
1277
1316
  import { ProductController } from './controllers/product';
1278
1317
  import { CartController } from './controllers/cart';
@@ -1318,7 +1357,7 @@ export class EcommerceApp extends BaseApplication {
1318
1357
 
1319
1358
  // Components
1320
1359
  this.component(HealthCheckComponent);
1321
- this.component(SwaggerComponent);
1360
+ this.component(ApiReferenceComponent);
1322
1361
  }
1323
1362
 
1324
1363
  postConfigure() {}