@venizia/ignis-docs 0.0.8-3 → 0.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 (213) hide show
  1. package/README.md +7 -7
  2. package/{wiki → content}/best-practices/api-usage-examples.md +15 -12
  3. package/{wiki → content}/best-practices/architectural-patterns.md +70 -78
  4. package/{wiki → content}/best-practices/architecture-decisions.md +91 -60
  5. package/{wiki → content}/best-practices/code-style-standards/advanced-patterns.md +56 -44
  6. package/{wiki → content}/best-practices/code-style-standards/constants-configuration.md +11 -11
  7. package/{wiki → content}/best-practices/code-style-standards/control-flow.md +5 -2
  8. package/{wiki → content}/best-practices/code-style-standards/documentation.md +13 -13
  9. package/{wiki → content}/best-practices/code-style-standards/function-patterns.md +9 -10
  10. package/{wiki → content}/best-practices/code-style-standards/index.md +1 -1
  11. package/{wiki → content}/best-practices/code-style-standards/naming-conventions.md +10 -8
  12. package/{wiki → content}/best-practices/code-style-standards/route-definitions.md +30 -12
  13. package/{wiki → content}/best-practices/code-style-standards/tooling.md +8 -5
  14. package/{wiki → content}/best-practices/code-style-standards/type-safety.md +13 -12
  15. package/{wiki → content}/best-practices/common-pitfalls.md +56 -37
  16. package/{wiki → content}/best-practices/contribution-workflow.md +13 -14
  17. package/{wiki → content}/best-practices/data-modeling.md +44 -20
  18. package/{wiki → content}/best-practices/deployment-strategies.md +28 -27
  19. package/{wiki → content}/best-practices/error-handling.md +48 -24
  20. package/{wiki → content}/best-practices/index.md +5 -5
  21. package/{wiki → content}/best-practices/performance-optimization.md +36 -28
  22. package/{wiki → content}/best-practices/security-guidelines.md +52 -23
  23. package/{wiki → content}/best-practices/testing-strategies.md +65 -51
  24. package/{wiki → content}/best-practices/troubleshooting-tips.md +24 -24
  25. package/{wiki/extensions/components/swagger.md → content/extensions/components/api-reference.md} +40 -31
  26. package/{wiki → content}/extensions/components/authentication/api.md +19 -19
  27. package/{wiki → content}/extensions/components/authentication/errors.md +7 -7
  28. package/{wiki → content}/extensions/components/authentication/index.md +10 -8
  29. package/{wiki → content}/extensions/components/authentication/usage.md +101 -6
  30. package/{wiki → content}/extensions/components/authorization/api.md +45 -25
  31. package/{wiki → content}/extensions/components/authorization/errors.md +6 -6
  32. package/{wiki → content}/extensions/components/authorization/index.md +11 -10
  33. package/{wiki → content}/extensions/components/authorization/usage.md +21 -21
  34. package/{wiki → content}/extensions/components/health-check.md +1 -1
  35. package/{wiki → content}/extensions/components/index.md +5 -5
  36. package/{wiki → content}/extensions/components/mail/errors.md +15 -15
  37. package/{wiki → content}/extensions/components/mail/index.md +1 -2
  38. package/{wiki → content}/extensions/components/mail/usage.md +1 -1
  39. package/{wiki → content}/extensions/components/request-tracker.md +1 -1
  40. package/{wiki → content}/extensions/components/socket-io/api.md +9 -9
  41. package/{wiki → content}/extensions/components/socket-io/errors.md +5 -5
  42. package/{wiki → content}/extensions/components/socket-io/index.md +8 -8
  43. package/{wiki → content}/extensions/components/socket-io/usage.md +1 -1
  44. package/{wiki → content}/extensions/components/static-asset/api.md +17 -4
  45. package/{wiki → content}/extensions/components/static-asset/errors.md +4 -4
  46. package/{wiki → content}/extensions/components/static-asset/index.md +26 -28
  47. package/{wiki → content}/extensions/components/static-asset/usage.md +13 -12
  48. package/{wiki → content}/extensions/components/template/index.md +2 -2
  49. package/{wiki → content}/extensions/components/template/setup-page.md +1 -1
  50. package/{wiki → content}/extensions/components/websocket/api.md +3 -3
  51. package/{wiki → content}/extensions/components/websocket/errors.md +5 -5
  52. package/{wiki → content}/extensions/components/websocket/index.md +5 -5
  53. package/{wiki → content}/extensions/components/websocket/usage.md +3 -3
  54. package/{wiki → content}/extensions/helpers/cron/index.md +2 -2
  55. package/{wiki → content}/extensions/helpers/crypto/index.md +1 -1
  56. package/{wiki → content}/extensions/helpers/env/index.md +27 -12
  57. package/content/extensions/helpers/error/index.md +283 -0
  58. package/{wiki → content}/extensions/helpers/index.md +2 -3
  59. package/{wiki → content}/extensions/helpers/inversion/index.md +15 -7
  60. package/{wiki → content}/extensions/helpers/kafka/examples.md +1 -1
  61. package/{wiki → content}/extensions/helpers/logger/index.md +32 -2
  62. package/{wiki → content}/extensions/helpers/network/index.md +6 -0
  63. package/{wiki → content}/extensions/helpers/queue/index.md +14 -17
  64. package/content/extensions/helpers/redis/index.md +713 -0
  65. package/{wiki → content}/extensions/helpers/socket-io/index.md +14 -10
  66. package/{wiki → content}/extensions/helpers/storage/api.md +44 -8
  67. package/{wiki → content}/extensions/helpers/storage/index.md +43 -7
  68. package/{wiki → content}/extensions/helpers/template/index.md +6 -3
  69. package/{wiki → content}/extensions/helpers/types/index.md +11 -8
  70. package/{wiki → content}/extensions/helpers/websocket/api.md +9 -9
  71. package/{wiki → content}/extensions/helpers/websocket/index.md +7 -7
  72. package/{wiki → content}/extensions/helpers/worker-thread/index.md +2 -2
  73. package/{wiki → content}/extensions/index.md +3 -4
  74. package/{wiki → content}/extensions/src-details/mcp-server.md +18 -24
  75. package/{wiki → content}/guides/core-concepts/application/bootstrapping.md +11 -14
  76. package/{wiki → content}/guides/core-concepts/application/index.md +3 -3
  77. package/{wiki → content}/guides/core-concepts/components.md +19 -10
  78. package/{wiki → content}/guides/core-concepts/dependency-injection.md +6 -3
  79. package/{wiki → content}/guides/core-concepts/grpc-controllers.md +6 -5
  80. package/{wiki → content}/guides/core-concepts/persistent/datasources.md +33 -27
  81. package/{wiki → content}/guides/core-concepts/persistent/index.md +16 -5
  82. package/{wiki → content}/guides/core-concepts/persistent/models.md +24 -20
  83. package/content/guides/core-concepts/persistent/postgres-drivers.md +167 -0
  84. package/{wiki → content}/guides/core-concepts/persistent/repositories.md +40 -23
  85. package/content/guides/core-concepts/persistent/search-meilisearch.md +183 -0
  86. package/content/guides/core-concepts/persistent/search-typesense.md +429 -0
  87. package/{wiki → content}/guides/core-concepts/persistent/transactions.md +61 -25
  88. package/{wiki → content}/guides/core-concepts/rest-controllers.md +12 -9
  89. package/content/guides/core-concepts/services.md +389 -0
  90. package/{wiki → content}/guides/get-started/5-minute-quickstart.md +19 -19
  91. package/{wiki → content}/guides/get-started/philosophy.md +36 -36
  92. package/{wiki → content}/guides/get-started/setup.md +3 -3
  93. package/{wiki → content}/guides/index.md +3 -3
  94. package/content/guides/migrations/redis-helpers-migration.md +177 -0
  95. package/{wiki → content}/guides/migrations/scoped-rbac-migration.md +17 -17
  96. package/content/guides/migrations/unified-connectors-migration.md +113 -0
  97. package/{wiki → content}/guides/reference/glossary.md +19 -12
  98. package/{wiki → content}/guides/reference/mcp-docs-server.md +22 -18
  99. package/{wiki → content}/guides/tutorials/building-a-crud-api.md +30 -33
  100. package/{wiki → content}/guides/tutorials/complete-installation.md +17 -17
  101. package/{wiki → content}/guides/tutorials/ecommerce-api.md +158 -119
  102. package/{wiki → content}/guides/tutorials/realtime-chat.md +176 -130
  103. package/content/guides/tutorials/testing.md +264 -0
  104. package/content/index.md +5 -0
  105. package/content/public/apple-touch-icon.png +0 -0
  106. package/content/public/og-image.png +0 -0
  107. package/content/public/site.webmanifest +11 -0
  108. package/{wiki → content}/references/base/application.md +4 -5
  109. package/{wiki → content}/references/base/bootstrapping.md +18 -5
  110. package/{wiki → content}/references/base/components.md +149 -120
  111. package/content/references/base/connectors.md +178 -0
  112. package/{wiki → content}/references/base/controllers.md +41 -30
  113. package/content/references/base/datasources.md +527 -0
  114. package/{wiki → content}/references/base/dependency-injection.md +34 -22
  115. package/{wiki → content}/references/base/filter-system/application-usage.md +17 -14
  116. package/{wiki → content}/references/base/filter-system/array-operators.md +7 -2
  117. package/{wiki → content}/references/base/filter-system/comparison-operators.md +3 -0
  118. package/{wiki → content}/references/base/filter-system/default-filter.md +89 -71
  119. package/{wiki → content}/references/base/filter-system/fields-order-pagination.md +22 -22
  120. package/{wiki → content}/references/base/filter-system/index.md +6 -3
  121. package/{wiki → content}/references/base/filter-system/json-filtering.md +20 -1
  122. package/{wiki → content}/references/base/filter-system/list-operators.md +1 -1
  123. package/{wiki → content}/references/base/filter-system/logical-operators.md +33 -1
  124. package/{wiki → content}/references/base/filter-system/null-operators.md +30 -1
  125. package/{wiki → content}/references/base/filter-system/quick-reference.md +23 -4
  126. package/{wiki → content}/references/base/filter-system/tips.md +5 -5
  127. package/{wiki → content}/references/base/filter-system/use-cases.md +12 -12
  128. package/{wiki → content}/references/base/grpc-controllers.md +13 -13
  129. package/{wiki → content}/references/base/index.md +24 -12
  130. package/{wiki/references/base/middleware.md → content/references/base/middlewares.md} +205 -24
  131. package/{wiki → content}/references/base/models.md +63 -49
  132. package/{wiki → content}/references/base/providers.md +136 -130
  133. package/{wiki → content}/references/base/repositories/advanced.md +59 -58
  134. package/{wiki → content}/references/base/repositories/index.md +115 -91
  135. package/content/references/base/repositories/mixins.md +99 -0
  136. package/{wiki → content}/references/base/repositories/relations.md +54 -64
  137. package/{wiki → content}/references/base/repositories/soft-deletable.md +31 -30
  138. package/content/references/base/services.md +404 -0
  139. package/{wiki → content}/references/configuration/environment-variables.md +46 -30
  140. package/{wiki → content}/references/configuration/index.md +6 -6
  141. package/{wiki → content}/references/index.md +17 -12
  142. package/{wiki → content}/references/quick-reference.md +65 -106
  143. package/content/references/utilities/crypto.md +98 -0
  144. package/{wiki → content}/references/utilities/index.md +3 -3
  145. package/{wiki → content}/references/utilities/jsx.md +6 -4
  146. package/content/references/utilities/module.md +90 -0
  147. package/{wiki → content}/references/utilities/parse.md +4 -14
  148. package/{wiki → content}/references/utilities/promise.md +9 -7
  149. package/{wiki → content}/references/utilities/schema.md +5 -3
  150. package/dist/mcp-server/common/guards.d.ts +8 -0
  151. package/dist/mcp-server/common/guards.d.ts.map +1 -0
  152. package/dist/mcp-server/common/guards.js +14 -0
  153. package/dist/mcp-server/common/guards.js.map +1 -0
  154. package/dist/mcp-server/common/index.d.ts +1 -0
  155. package/dist/mcp-server/common/index.d.ts.map +1 -1
  156. package/dist/mcp-server/common/index.js +1 -0
  157. package/dist/mcp-server/common/index.js.map +1 -1
  158. package/dist/mcp-server/common/paths.d.ts.map +1 -1
  159. package/dist/mcp-server/common/paths.js +2 -2
  160. package/dist/mcp-server/common/paths.js.map +1 -1
  161. package/dist/mcp-server/helpers/docs.helper.d.ts.map +1 -1
  162. package/dist/mcp-server/helpers/docs.helper.js +4 -2
  163. package/dist/mcp-server/helpers/docs.helper.js.map +1 -1
  164. package/dist/mcp-server/helpers/github.helper.js +1 -1
  165. package/dist/mcp-server/index.js +7 -2
  166. package/dist/mcp-server/index.js.map +1 -1
  167. package/dist/mcp-server/tools/base.tool.d.ts +6 -2
  168. package/dist/mcp-server/tools/base.tool.d.ts.map +1 -1
  169. package/dist/mcp-server/tools/base.tool.js.map +1 -1
  170. package/dist/mcp-server/tools/docs/search-documents.tool.d.ts +1 -1
  171. package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
  172. package/dist/mcp-server/tools/github/search-code.tool.d.ts +1 -1
  173. package/dist/mcp-server/tools/github/search-code.tool.d.ts.map +1 -1
  174. package/dist/mcp-server/tools/github/search-code.tool.js +4 -1
  175. package/dist/mcp-server/tools/github/search-code.tool.js.map +1 -1
  176. package/dist/mcp-server/tools/github/verify-dependencies.tool.d.ts.map +1 -1
  177. package/dist/mcp-server/tools/github/verify-dependencies.tool.js +3 -1
  178. package/dist/mcp-server/tools/github/verify-dependencies.tool.js.map +1 -1
  179. package/package.json +12 -12
  180. package/wiki/extensions/helpers/error/index.md +0 -227
  181. package/wiki/extensions/helpers/redis/index.md +0 -488
  182. package/wiki/extensions/helpers/testing/index.md +0 -510
  183. package/wiki/guides/core-concepts/services.md +0 -119
  184. package/wiki/guides/tutorials/testing.md +0 -722
  185. package/wiki/index.md +0 -183
  186. package/wiki/references/base/datasources.md +0 -454
  187. package/wiki/references/base/middlewares.md +0 -590
  188. package/wiki/references/base/repositories/mixins.md +0 -335
  189. package/wiki/references/base/services.md +0 -201
  190. package/wiki/references/utilities/crypto.md +0 -56
  191. package/wiki/references/utilities/module.md +0 -42
  192. /package/{wiki → content}/extensions/components/mail/api.md +0 -0
  193. /package/{wiki → content}/extensions/components/template/api-page.md +0 -0
  194. /package/{wiki → content}/extensions/components/template/errors-page.md +0 -0
  195. /package/{wiki → content}/extensions/components/template/single-page.md +0 -0
  196. /package/{wiki → content}/extensions/components/template/usage-page.md +0 -0
  197. /package/{wiki → content}/extensions/helpers/kafka/admin.md +0 -0
  198. /package/{wiki → content}/extensions/helpers/kafka/consumer.md +0 -0
  199. /package/{wiki → content}/extensions/helpers/kafka/index.md +0 -0
  200. /package/{wiki → content}/extensions/helpers/kafka/producer.md +0 -0
  201. /package/{wiki → content}/extensions/helpers/kafka/schema-registry.md +0 -0
  202. /package/{wiki → content}/extensions/helpers/network/api.md +0 -0
  203. /package/{wiki → content}/extensions/helpers/socket-io/api.md +0 -0
  204. /package/{wiki → content}/extensions/helpers/template/single-page.md +0 -0
  205. /package/{wiki → content}/extensions/helpers/uid/index.md +0 -0
  206. /package/{wiki → content}/guides/core-concepts/components-guide.md +0 -0
  207. /package/{wiki → content}/public/logo.svg +0 -0
  208. /package/{wiki → content}/references/base/filter-system/pattern-matching.md +0 -0
  209. /package/{wiki → content}/references/base/filter-system/range-operators.md +0 -0
  210. /package/{wiki → content}/references/utilities/date.md +0 -0
  211. /package/{wiki → content}/references/utilities/performance.md +0 -0
  212. /package/{wiki → content}/references/utilities/request.md +0 -0
  213. /package/{wiki → content}/references/utilities/statuses.md +0 -0
@@ -1,335 +0,0 @@
1
- ---
2
- title: Repository Mixins
3
- description: Composable mixins for repository functionality
4
- difficulty: intermediate
5
- lastUpdated: 2026-01-02
6
- ---
7
-
8
- # Repository Mixins <Badge type="tip" text="v0.0.5+" />
9
-
10
- Composable mixins that provide reusable functionality for repository classes.
11
-
12
- > [!NOTE] Refactored in v0.0.5
13
- > Repository mixins were extracted and refactored in v0.0.5 to provide better composition and reusability.
14
-
15
- **Files:** `packages/core/src/base/repositories/mixins/`
16
-
17
-
18
- ## Overview
19
-
20
- Ignis uses the mixin pattern to compose repository features. This enables:
21
-
22
- - **Separation of concerns** - Each mixin handles one responsibility
23
- - **Reusability** - Mixins can be applied to different base classes
24
- - **Testability** - Individual features can be tested in isolation
25
- - **Flexibility** - Create custom repositories with only needed features
26
-
27
-
28
- ## Available Mixins
29
-
30
- | Mixin | Responsibility |
31
- |-------|----------------|
32
- | `FieldsVisibilityMixin` | Hidden properties exclusion at SQL level |
33
- | `DefaultFilterMixin` | Automatic filter application from model settings |
34
-
35
-
36
- ## FieldsVisibilityMixin
37
-
38
- Provides hidden properties management for SQL-level field exclusion. Reads `hiddenProperties` from `@model` metadata settings and builds a visible columns map for Drizzle's `select()` and `returning()` calls.
39
-
40
- **File:** `packages/core/src/base/repositories/mixins/fields-visibility.ts`
41
-
42
- ### Abstract Requirements
43
-
44
- Classes using this mixin must implement:
45
-
46
- ```typescript
47
- abstract getEntity(): BaseEntity<TTableSchemaWithId>;
48
- ```
49
-
50
- ### Properties
51
-
52
- | Property | Type | Description |
53
- |----------|------|-------------|
54
- | `_hiddenProperties` | `Set<string> \| null` | Cached hidden property names (`null` = not yet computed) |
55
- | `_visibleProperties` | `Record<string, any> \| null \| undefined` | Cached visible columns (`null` = not yet computed, `undefined` = computed with no hidden props) |
56
-
57
- ### Methods
58
-
59
- | Method | Returns | Description |
60
- |--------|---------|-------------|
61
- | `get hiddenProperties` | `Set<string>` | Getter that delegates to `getHiddenProperties()` |
62
- | `set hiddenProperties` | `void` | Override hidden properties set |
63
- | `getHiddenProperties()` | `Set<string>` | Get hidden properties from model metadata (cached) |
64
- | `hasHiddenProperties()` | `boolean` | Check if model has any hidden properties |
65
- | `get visibleProperties` | `Record<string, any> \| undefined` | Getter that delegates to `getVisibleProperties()` |
66
- | `set visibleProperties` | `void` | Override visible properties |
67
- | `getVisibleProperties()` | `Record<string, any> \| undefined` | Build visible columns object for Drizzle (cached). Returns `undefined` if no hidden props. |
68
-
69
- ### Usage
70
-
71
- ```typescript
72
- import { FieldsVisibilityMixin } from '@venizia/ignis';
73
- import { BaseHelper } from '@venizia/ignis-helpers';
74
-
75
- class MyRepository extends FieldsVisibilityMixin(BaseHelper) {
76
- // Required abstract implementation
77
- abstract getEntity(): BaseEntity;
78
-
79
- // Now has access to:
80
- // - hiddenProperties (getter/setter)
81
- // - visibleProperties (getter/setter)
82
- // - getHiddenProperties()
83
- // - hasHiddenProperties()
84
- // - getVisibleProperties()
85
- }
86
- ```
87
-
88
- ### Visible Properties for Drizzle
89
-
90
- The `getVisibleProperties()` method returns a columns object for Drizzle's `select()` or `returning()`:
91
-
92
- ```typescript
93
- // Model with hiddenProperties: ['password', 'apiKey']
94
- // Schema columns: { id, email, password, apiKey, createdAt }
95
-
96
- const visibleProps = this.getVisibleProperties();
97
- // Result: { id: column, email: column, createdAt: column }
98
- // (password and apiKey excluded)
99
-
100
- // Used in Drizzle queries
101
- await connector.select(visibleProps).from(schema);
102
- // SELECT id, email, created_at FROM users
103
- ```
104
-
105
- ### How It Resolves Hidden Properties
106
-
107
- 1. Checks the cache (`_hiddenProperties`). If not `null`, returns cached value.
108
- 2. Looks up the entity name in `MetadataRegistry.getModelEntry()`.
109
- 3. Reads `metadata.settings.hiddenProperties` (array of field names).
110
- 4. Converts to a `Set<string>` and caches.
111
-
112
-
113
- ## DefaultFilterMixin
114
-
115
- Provides automatic default filter application for all repository queries. Reads `defaultFilter` from `@model` metadata settings and merges it with user-provided filters.
116
-
117
- **File:** `packages/core/src/base/repositories/mixins/default-filter.ts`
118
-
119
- ### Abstract Requirements
120
-
121
- Classes using this mixin must implement:
122
-
123
- ```typescript
124
- abstract getEntity(): BaseEntity<TTableSchemaWithId>;
125
- abstract get filterBuilder(): FilterBuilder;
126
- ```
127
-
128
- ### Properties
129
-
130
- | Property | Type | Description |
131
- |----------|------|-------------|
132
- | `_defaultFilter` | `TFilter \| null \| undefined` | Cached default filter (`null` = not yet computed, `undefined` = computed with no default filter) |
133
-
134
- ### Methods
135
-
136
- | Method | Returns | Description |
137
- |--------|---------|-------------|
138
- | `getDefaultFilter()` | `TFilter \| undefined` | Get default filter from model metadata (cached) |
139
- | `hasDefaultFilter()` | `boolean` | Check if model has a default filter configured |
140
- | `applyDefaultFilter(opts)` | `TFilter` | Merge default filter with user filter |
141
-
142
- ### Usage
143
-
144
- ```typescript
145
- import { DefaultFilterMixin } from '@venizia/ignis';
146
- import { BaseHelper } from '@venizia/ignis-helpers';
147
-
148
- class MyRepository extends DefaultFilterMixin(BaseHelper) {
149
- // Required abstract implementations
150
- abstract getEntity(): BaseEntity;
151
- abstract get filterBuilder(): FilterBuilder;
152
-
153
- // Now has access to:
154
- // - getDefaultFilter()
155
- // - hasDefaultFilter()
156
- // - applyDefaultFilter()
157
- }
158
- ```
159
-
160
- ### applyDefaultFilter Options
161
-
162
- ```typescript
163
- applyDefaultFilter<DataObject = any>(opts: {
164
- userFilter?: TFilter<DataObject>; // User-provided filter
165
- shouldSkipDefaultFilter?: boolean; // If true, bypass default filter
166
- }): TFilter<DataObject>
167
- ```
168
-
169
- **Behavior:**
170
-
171
- 1. If `shouldSkipDefaultFilter` is `true`, returns the user filter as-is (or `{}` if none).
172
- 2. If no default filter is configured, returns the user filter as-is (or `{}` if none).
173
- 3. Otherwise, delegates to `filterBuilder.mergeFilter({ defaultFilter, userFilter })` which deep-merges `where` conditions and uses user values for other filter properties (`order`, `limit`, `offset`, `skip`, `fields`, `include`).
174
-
175
-
176
- ## Mixin Composition
177
-
178
- The `AbstractRepository` composes both mixins:
179
-
180
- ```typescript
181
- export abstract class AbstractRepository<...>
182
- extends DefaultFilterMixin(FieldsVisibilityMixin(BaseHelper))
183
- implements IPersistableRepository<...>
184
- {
185
- // Inherits from both mixins:
186
- // From FieldsVisibilityMixin:
187
- // - hiddenProperties (getter/setter)
188
- // - visibleProperties (getter/setter)
189
- // - getHiddenProperties()
190
- // - hasHiddenProperties()
191
- // - getVisibleProperties()
192
- //
193
- // From DefaultFilterMixin:
194
- // - getDefaultFilter()
195
- // - hasDefaultFilter()
196
- // - applyDefaultFilter()
197
- }
198
- ```
199
-
200
- ### Composition Order
201
-
202
- Mixins are applied right-to-left:
203
-
204
- ```typescript
205
- // FieldsVisibilityMixin applied first (to BaseHelper)
206
- // DefaultFilterMixin applied second (to the result)
207
- DefaultFilterMixin(FieldsVisibilityMixin(BaseHelper))
208
- ```
209
-
210
-
211
- ## Creating Custom Mixins
212
-
213
- Follow the TypeScript mixin pattern using `TMixinTarget`:
214
-
215
- ```typescript
216
- import { TMixinTarget } from '@venizia/ignis-helpers';
217
-
218
- export const AuditLogMixin = <T extends TMixinTarget<object>>(baseClass: T) => {
219
- abstract class Mixed extends baseClass {
220
- // Properties
221
- private _auditEnabled: boolean = true;
222
-
223
- // Abstract dependencies (if needed)
224
- abstract getEntity(): BaseEntity;
225
-
226
- // Public methods
227
- enableAudit(): void {
228
- this._auditEnabled = true;
229
- }
230
-
231
- disableAudit(): void {
232
- this._auditEnabled = false;
233
- }
234
-
235
- isAuditEnabled(): boolean {
236
- return this._auditEnabled;
237
- }
238
-
239
- logOperation(operation: string, data: any): void {
240
- if (this._auditEnabled) {
241
- console.log(`[${this.getEntity().name}] ${operation}:`, data);
242
- }
243
- }
244
- }
245
-
246
- return Mixed;
247
- };
248
- ```
249
-
250
- ### Using Custom Mixins
251
-
252
- ```typescript
253
- // Compose with existing mixins
254
- class MyRepository extends AuditLogMixin(DefaultFilterMixin(BaseHelper)) {
255
- getEntity() {
256
- return this._entity;
257
- }
258
-
259
- get filterBuilder() {
260
- return this._filterBuilder;
261
- }
262
- }
263
-
264
- // Or create a composed base
265
- const AuditableRepository = AuditLogMixin(DefaultFilterMixin(FieldsVisibilityMixin(BaseHelper)));
266
-
267
- class ProductRepository extends AuditableRepository {
268
- // Has all mixin functionality
269
- }
270
- ```
271
-
272
-
273
- ## Caching Behavior
274
-
275
- Both mixins use a three-state caching pattern for performance:
276
-
277
- ```typescript
278
- // DefaultFilterMixin caching
279
- // null = not computed yet
280
- // undefined = computed, no default filter exists
281
- // TFilter = computed, has default filter
282
- _defaultFilter: TFilter | null | undefined = null;
283
-
284
- getDefaultFilter() {
285
- if (this._defaultFilter !== null) {
286
- return this._defaultFilter; // Return cached value (either TFilter or undefined)
287
- }
288
- // Compute from MetadataRegistry and cache...
289
- }
290
-
291
- // FieldsVisibilityMixin caching
292
- // null = not computed yet
293
- // Set<string> = computed (may be empty)
294
- _hiddenProperties: Set<string> | null = null;
295
-
296
- // null = not computed yet
297
- // undefined = computed, no hidden properties exist
298
- // Record<string, any> = computed, has visible column map
299
- _visibleProperties: Record<string, any> | null | undefined = null;
300
- ```
301
-
302
- This ensures metadata lookups happen only once per repository instance, with subsequent calls returning the cached value.
303
-
304
-
305
- ## Quick Reference
306
-
307
- | Mixin | Method | Purpose |
308
- |-------|--------|---------|
309
- | `FieldsVisibilityMixin` | `hasHiddenProperties()` | Check if hidden props exist |
310
- | `FieldsVisibilityMixin` | `getHiddenProperties()` | Get hidden property names as `Set<string>` |
311
- | `FieldsVisibilityMixin` | `getVisibleProperties()` | Get Drizzle columns object (excludes hidden) |
312
- | `DefaultFilterMixin` | `hasDefaultFilter()` | Check if default filter exists |
313
- | `DefaultFilterMixin` | `getDefaultFilter()` | Get raw default filter from model metadata |
314
- | `DefaultFilterMixin` | `applyDefaultFilter()` | Merge default filter with user filter |
315
-
316
-
317
- ## Next Steps
318
-
319
- - [Default Filter](../filter-system/default-filter.md) - Full default filter documentation
320
- - [Advanced Features](./advanced.md) - Hidden properties usage
321
- - [Repository Overview](./index.md) - Repository basics
322
-
323
- ## See Also
324
-
325
- - **Related Concepts:**
326
- - [Repositories Overview](./index) - Core repository operations
327
- - [Models](/guides/core-concepts/persistent/models) - Entity definitions
328
-
329
- - **Related Topics:**
330
- - [Default Filter](../filter-system/default-filter) - Automatic filtering
331
- - [Advanced Features](./advanced) - Hidden properties and transactions
332
- - [Relations & Includes](./relations) - Loading related data
333
-
334
- - **Best Practices:**
335
- - [Data Modeling](/best-practices/data-modeling) - Soft delete patterns
@@ -1,201 +0,0 @@
1
- ---
2
- title: Services Reference
3
- description: Technical reference for BaseService and business logic layer
4
- difficulty: beginner
5
- ---
6
-
7
- # Deep Dive: Services
8
-
9
- Technical reference for `BaseService` - the foundation for business logic layers in Ignis.
10
-
11
- **File:** `packages/core/src/base/services/base.ts`
12
-
13
- ## Quick Reference
14
-
15
- | Feature | Benefit |
16
- |---------|---------|
17
- | **Extends `BaseHelper`** | Auto-configured scoped logger (`this.logger`) |
18
- | **DI Integration** | Fits into framework's dependency injection system |
19
- | **Business Logic Layer** | Bridge between Controllers and Repositories |
20
- | **No built-in CRUD** | Services are for business logic, not data access — that's what Repositories are for |
21
-
22
- ## `BaseService` Class
23
-
24
- Abstract class that all application services should extend. It implements the `IService` interface (currently a marker interface with no required methods).
25
-
26
- ### Class Definition
27
-
28
- ```typescript
29
- import { BaseHelper } from '@venizia/ignis-helpers';
30
- import { IService } from './types';
31
-
32
- export abstract class BaseService extends BaseHelper implements IService {
33
- constructor(opts: { scope: string }) {
34
- super({ scope: opts.scope });
35
- }
36
- }
37
- ```
38
-
39
- ### Key Features
40
-
41
- | Feature | Description |
42
- | :--- | :--- |
43
- | **Standardization** | Common base for all services, fits framework architecture |
44
- | **Logging** | Extends `BaseHelper` from `@venizia/ignis-helpers` — auto-configured logger at `this.logger` (scope = class name) |
45
- | **Clarity** | Signals the class contains business logic |
46
-
47
- ### Constructor
48
-
49
- The constructor requires an options object with a `scope` string, which is typically set to the class name:
50
-
51
- ```typescript
52
- class UserService extends BaseService {
53
- constructor() {
54
- super({ scope: UserService.name });
55
- }
56
- }
57
- ```
58
-
59
- ## `IService` Interface
60
-
61
- The `IService` interface is a marker interface with no required methods. It exists to provide a type-level contract for services.
62
-
63
- ```typescript
64
- export interface IService {}
65
- ```
66
-
67
- ## No Built-in CRUD Service
68
-
69
- Ignis intentionally does not provide a `BaseCrudService`. CRUD operations belong in the Repository layer (`DefaultCRUDRepository`). Services are for business logic that orchestrates one or more repositories, performs validation, handles transactions, or coordinates cross-cutting concerns.
70
-
71
- ## Registration
72
-
73
- Services are registered with the DI container using the `app.service()` method or via the boot system's auto-discovery:
74
-
75
- ```typescript
76
- // Manual registration (in preConfigure or registerComponents)
77
- app.service(UserService); // Binds as 'services.UserService'
78
-
79
- // Or via boot system auto-discovery:
80
- // Place file at src/services/user.service.ts → auto-discovered and bound
81
- ```
82
-
83
- ## How Services Fit into the Architecture
84
-
85
- Services are the core of your application's logic. They act as a bridge between the presentation layer (Controllers) and the data access layer (Repositories).
86
-
87
- ### Typical Service Flow
88
-
89
- 1. **Instantiated by DI Container**: When the application starts, the DI container creates instances of your services.
90
- 2. **Dependencies Injected**: The service's constructor receives instances of any repositories or other services it depends on.
91
- 3. **Called by a Controller**: An HTTP request comes into a controller, which then calls a method on a service to handle the business logic for that request.
92
- 4. **Orchestrates Logic**: The service method executes the business logic. This may involve:
93
- - Validating input data.
94
- - Calling one or more repository methods to fetch or save data.
95
- - Calling other services to perform related tasks.
96
- - Performing calculations or data transformations.
97
- 5. **Returns Data**: The service returns the result of the operation back to the controller, which then formats it into an HTTP response.
98
-
99
- ### Example
100
-
101
- ```typescript
102
- import { BaseService, inject, injectable } from '@venizia/ignis';
103
- import { getError } from '@venizia/ignis-helpers';
104
- import { UserRepository } from '../repositories/user.repository';
105
- import { TUser } from '../models/entities';
106
-
107
- // 1. Service is decorated with @injectable (or registered via app.service())
108
- @injectable()
109
- export class UserService extends BaseService {
110
- // 2. Dependencies (like UserRepository) are injected
111
- constructor(
112
- @inject({ key: 'repositories.UserRepository' })
113
- private _userRepository: UserRepository,
114
- ) {
115
- super({ scope: UserService.name });
116
- }
117
-
118
- // 3. Method is called by a controller
119
- async getUserProfile(opts: { userId: string }): Promise<Partial<TUser>> {
120
- this.logger.info(`Fetching profile for user ${opts.userId}`);
121
-
122
- // 4. Orchestrates logic: calls the repository
123
- const user = await this._userRepository.findById({ id: opts.userId });
124
-
125
- if (!user) {
126
- throw getError({ message: 'User not found' });
127
- }
128
-
129
- // 5. Returns transformed data
130
- return {
131
- id: user.id,
132
- name: user.name,
133
- email: user.email,
134
- };
135
- }
136
- }
137
- ```
138
-
139
- ### Transaction Orchestration
140
-
141
- A common service pattern is orchestrating transactions across multiple repositories:
142
-
143
- ```typescript
144
- @injectable()
145
- export class OrderService extends BaseService {
146
- constructor(
147
- @inject({ key: 'repositories.OrderRepository' })
148
- private orderRepo: OrderRepository,
149
-
150
- @inject({ key: 'repositories.InventoryRepository' })
151
- private inventoryRepo: InventoryRepository,
152
-
153
- @inject({ key: 'datasources.PostgresDataSource' })
154
- private dataSource: PostgresDataSource,
155
- ) {
156
- super({ scope: OrderService.name });
157
- }
158
-
159
- async placeOrder(opts: { userId: string; items: OrderItem[] }) {
160
- const transaction = await this.dataSource.beginTransaction();
161
- try {
162
- const order = await this.orderRepo.create({
163
- data: { userId: opts.userId, items: opts.items },
164
- options: { transaction },
165
- });
166
-
167
- for (const item of opts.items) {
168
- await this.inventoryRepo.updateById({
169
- id: item.productId,
170
- data: { quantity: item.quantity },
171
- options: { transaction },
172
- });
173
- }
174
-
175
- await transaction.commit();
176
- return order;
177
- } catch (error) {
178
- await transaction.rollback();
179
- throw error;
180
- }
181
- }
182
- }
183
- ```
184
-
185
- By adhering to this pattern, you keep your code organized, testable, and maintainable. You can easily test `UserService` by providing a mock `UserRepository` without needing a real database connection.
186
-
187
- ## See Also
188
-
189
- - **Related References:**
190
- - [Controllers](./controllers.md) - HTTP request handlers that call services
191
- - [Repositories](./repositories/) - Data access layer used by services
192
- - [Providers](./providers.md) - Factory pattern for runtime instantiation
193
- - [Dependency Injection](./dependency-injection.md) - DI container and injection patterns
194
-
195
- - **Guides:**
196
- - [Building Services](/guides/core-concepts/services.md)
197
- - [Dependency Injection Guide](/guides/core-concepts/dependency-injection.md)
198
-
199
- - **Best Practices:**
200
- - [Architectural Patterns](/best-practices/architectural-patterns)
201
- - [Testing Guide](/guides/tutorials/testing)
@@ -1,56 +0,0 @@
1
- # Crypto Utility
2
-
3
- The Crypto utility provides simple, stateless functions for cryptographic hashing using Node.js's built-in `node:crypto` module.
4
-
5
- ## `hash`
6
-
7
- The `hash` function allows you to create a hash of a string using either `SHA256` (with a secret for HMAC) or `MD5`.
8
-
9
- ### `hash(text, options)`
10
-
11
- - `text` (string): The input string to hash.
12
- - `options` (object):
13
- - `algorithm` (`'SHA256'` | `'MD5'`): The hashing algorithm to use.
14
- - `secret` (string, optional): The secret key for HMAC-SHA256. If `algorithm` is `'SHA256'` and no `secret` is provided, the original text is returned unchanged.
15
- - `outputType` (`BinaryToTextEncoding`): The output encoding (e.g., `'hex'`, `'base64'`).
16
-
17
- ### Behavior
18
-
19
- - **SHA256**: Creates an HMAC using the provided `secret`. Returns the original text if no secret is given.
20
- - **MD5**: Creates a standard hash digest (no secret needed).
21
- - **Other algorithms**: Returns the original text unchanged.
22
-
23
- ### Examples
24
-
25
- **MD5 Hash**
26
-
27
- ```typescript
28
- import { hash } from '@venizia/ignis-helpers';
29
-
30
- const md5Hash = hash('some text', { algorithm: 'MD5', outputType: 'hex' });
31
- // => '552e21cd4cd99186789c2370c7482837'
32
- ```
33
-
34
- **SHA256 HMAC**
35
-
36
- ```typescript
37
- import { hash } from '@venizia/ignis-helpers';
38
-
39
- const sha256Hash = hash('some text', {
40
- algorithm: 'SHA256',
41
- secret: 'a-secret-key',
42
- outputType: 'hex',
43
- });
44
- // => 'b8a1c3f2... (64-character hex string)'
45
- ```
46
-
47
- **Base64 output**
48
-
49
- ```typescript
50
- import { hash } from '@venizia/ignis-helpers';
51
-
52
- const base64Hash = hash('some text', {
53
- algorithm: 'MD5',
54
- outputType: 'base64',
55
- });
56
- ```
@@ -1,42 +0,0 @@
1
- # Module Utility
2
-
3
- The Module utility provides a function to validate the existence of Node.js modules at runtime. It uses `createRequire` from `node:module` rooted at the application's `process.cwd()/node_modules`, so peer dependencies in the consuming application are properly resolved even though this utility lives inside `packages/helpers`.
4
-
5
- ## `validateModule`
6
-
7
- The `validateModule` function checks if a list of modules can be resolved. If a module is not found, it logs the error and throws a descriptive error, prompting the developer to install it. This is particularly useful for features that have optional peer dependencies.
8
-
9
- ### `validateModule(opts)`
10
-
11
- - `opts` (object):
12
- - `scope` (string, optional): A string to identify the feature or component that requires the module, making the error message more informative. Defaults to empty string.
13
- - `modules` (Array&lt;string&gt;): An array of module names to validate. Defaults to empty array.
14
-
15
- This is an `async` function, though it performs synchronous resolution internally.
16
-
17
- ### Example
18
-
19
- The `SwaggerComponent` uses `validateModule` to ensure that `@hono/swagger-ui` is installed before attempting to use it.
20
-
21
- ```typescript
22
- import { validateModule } from '@venizia/ignis-helpers';
23
-
24
- export class SwaggerComponent extends BaseComponent {
25
- // ...
26
-
27
- override async binding() {
28
- // This will throw an error if '@hono/swagger-ui' is not installed
29
- await validateModule({ scope: SwaggerComponent.name, modules: ['@hono/swagger-ui'] });
30
-
31
- const { swaggerUI } = await import('@hono/swagger-ui');
32
-
33
- // ... rest of the setup
34
- }
35
- }
36
- ```
37
-
38
- If the module is missing, the application will fail with an error message like:
39
-
40
- ```
41
- [validateModule] @hono/swagger-ui is required for SwaggerComponent. Please install '@hono/swagger-ui'
42
- ```
File without changes
File without changes