@venizia/ignis-docs 0.0.7 → 0.0.8-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. package/dist/mcp-server/common/paths.d.ts +4 -2
  2. package/dist/mcp-server/common/paths.d.ts.map +1 -1
  3. package/dist/mcp-server/common/paths.js +8 -6
  4. package/dist/mcp-server/common/paths.js.map +1 -1
  5. package/dist/mcp-server/helpers/docs.helper.d.ts.map +1 -1
  6. package/dist/mcp-server/helpers/docs.helper.js +1 -1
  7. package/dist/mcp-server/helpers/docs.helper.js.map +1 -1
  8. package/dist/mcp-server/tools/base.tool.d.ts +1 -1
  9. package/dist/mcp-server/tools/docs/get-document-content.tool.d.ts +1 -1
  10. package/dist/mcp-server/tools/docs/get-document-content.tool.d.ts.map +1 -1
  11. package/dist/mcp-server/tools/docs/get-document-content.tool.js +7 -7
  12. package/dist/mcp-server/tools/docs/get-document-metadata.tool.js +3 -3
  13. package/dist/mcp-server/tools/docs/get-package-overview.tool.d.ts +1 -1
  14. package/dist/mcp-server/tools/docs/get-package-overview.tool.js +1 -1
  15. package/dist/mcp-server/tools/docs/search-documents.tool.d.ts +1 -1
  16. package/dist/mcp-server/tools/docs/search-documents.tool.js +1 -1
  17. package/dist/mcp-server/tools/docs/search-documents.tool.js.map +1 -1
  18. package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
  19. package/dist/mcp-server/tools/github/list-project-files.tool.js +1 -1
  20. package/dist/mcp-server/tools/github/list-project-files.tool.js.map +1 -1
  21. package/dist/mcp-server/tools/github/search-code.tool.d.ts +1 -1
  22. package/dist/mcp-server/tools/github/search-code.tool.js +1 -1
  23. package/dist/mcp-server/tools/github/search-code.tool.js.map +1 -1
  24. package/package.json +9 -9
  25. package/wiki/best-practices/api-usage-examples.md +9 -9
  26. package/wiki/best-practices/architectural-patterns.md +19 -3
  27. package/wiki/best-practices/architecture-decisions.md +6 -6
  28. package/wiki/best-practices/code-style-standards/advanced-patterns.md +1 -1
  29. package/wiki/best-practices/code-style-standards/control-flow.md +1 -1
  30. package/wiki/best-practices/code-style-standards/function-patterns.md +2 -2
  31. package/wiki/best-practices/code-style-standards/index.md +2 -2
  32. package/wiki/best-practices/code-style-standards/naming-conventions.md +1 -1
  33. package/wiki/best-practices/code-style-standards/route-definitions.md +4 -4
  34. package/wiki/best-practices/data-modeling.md +1 -1
  35. package/wiki/best-practices/deployment-strategies.md +1 -1
  36. package/wiki/best-practices/error-handling.md +2 -2
  37. package/wiki/best-practices/performance-optimization.md +3 -3
  38. package/wiki/best-practices/security-guidelines.md +2 -2
  39. package/wiki/best-practices/troubleshooting-tips.md +1 -1
  40. package/wiki/{references → extensions}/components/authentication/api.md +12 -20
  41. package/wiki/{references → extensions}/components/authentication/errors.md +1 -1
  42. package/wiki/{references → extensions}/components/authentication/index.md +5 -8
  43. package/wiki/{references → extensions}/components/authentication/usage.md +20 -36
  44. package/wiki/{references → extensions}/components/authorization/api.md +62 -13
  45. package/wiki/{references → extensions}/components/authorization/errors.md +12 -7
  46. package/wiki/{references → extensions}/components/authorization/index.md +93 -6
  47. package/wiki/{references → extensions}/components/authorization/usage.md +42 -4
  48. package/wiki/{references → extensions}/components/health-check.md +5 -4
  49. package/wiki/{references → extensions}/components/index.md +2 -0
  50. package/wiki/{references → extensions}/components/mail/index.md +1 -1
  51. package/wiki/{references → extensions}/components/request-tracker.md +1 -1
  52. package/wiki/{references → extensions}/components/socket-io/api.md +2 -2
  53. package/wiki/{references → extensions}/components/socket-io/errors.md +2 -0
  54. package/wiki/{references → extensions}/components/socket-io/index.md +24 -20
  55. package/wiki/{references → extensions}/components/socket-io/usage.md +2 -2
  56. package/wiki/{references → extensions}/components/static-asset/api.md +14 -15
  57. package/wiki/{references → extensions}/components/static-asset/errors.md +3 -1
  58. package/wiki/{references → extensions}/components/static-asset/index.md +158 -89
  59. package/wiki/{references → extensions}/components/static-asset/usage.md +8 -5
  60. package/wiki/{references → extensions}/components/swagger.md +3 -3
  61. package/wiki/{references → extensions}/components/template/index.md +4 -4
  62. package/wiki/{references → extensions}/components/template/setup-page.md +1 -1
  63. package/wiki/{references → extensions}/components/template/single-page.md +1 -1
  64. package/wiki/{references → extensions}/components/websocket/api.md +7 -6
  65. package/wiki/{references → extensions}/components/websocket/errors.md +17 -3
  66. package/wiki/{references → extensions}/components/websocket/index.md +17 -11
  67. package/wiki/{references → extensions}/components/websocket/usage.md +2 -2
  68. package/wiki/{references → extensions}/helpers/crypto/index.md +1 -1
  69. package/wiki/{references → extensions}/helpers/env/index.md +9 -5
  70. package/wiki/{references → extensions}/helpers/error/index.md +2 -7
  71. package/wiki/{references → extensions}/helpers/index.md +18 -6
  72. package/wiki/{references → extensions}/helpers/kafka/admin.md +13 -1
  73. package/wiki/{references → extensions}/helpers/kafka/consumer.md +32 -31
  74. package/wiki/{references → extensions}/helpers/kafka/examples.md +20 -20
  75. package/wiki/{references → extensions}/helpers/kafka/index.md +61 -54
  76. package/wiki/{references → extensions}/helpers/kafka/producer.md +21 -20
  77. package/wiki/{references → extensions}/helpers/kafka/schema-registry.md +25 -25
  78. package/wiki/{references → extensions}/helpers/logger/index.md +2 -2
  79. package/wiki/{references → extensions}/helpers/queue/index.md +400 -4
  80. package/wiki/{references → extensions}/helpers/storage/api.md +170 -10
  81. package/wiki/{references → extensions}/helpers/storage/index.md +44 -8
  82. package/wiki/{references → extensions}/helpers/template/index.md +1 -1
  83. package/wiki/{references → extensions}/helpers/testing/index.md +4 -4
  84. package/wiki/{references → extensions}/helpers/types/index.md +63 -16
  85. package/wiki/{references → extensions}/helpers/websocket/index.md +1 -1
  86. package/wiki/extensions/index.md +48 -0
  87. package/wiki/guides/core-concepts/application/bootstrapping.md +55 -37
  88. package/wiki/guides/core-concepts/application/index.md +95 -35
  89. package/wiki/guides/core-concepts/components-guide.md +23 -19
  90. package/wiki/guides/core-concepts/components.md +34 -10
  91. package/wiki/guides/core-concepts/dependency-injection.md +99 -34
  92. package/wiki/guides/core-concepts/grpc-controllers.md +295 -0
  93. package/wiki/guides/core-concepts/persistent/datasources.md +37 -19
  94. package/wiki/guides/core-concepts/persistent/index.md +6 -6
  95. package/wiki/guides/core-concepts/persistent/models.md +50 -6
  96. package/wiki/guides/core-concepts/persistent/repositories.md +83 -8
  97. package/wiki/guides/core-concepts/persistent/transactions.md +39 -8
  98. package/wiki/guides/core-concepts/{controllers.md → rest-controllers.md} +32 -35
  99. package/wiki/guides/core-concepts/services.md +19 -6
  100. package/wiki/guides/get-started/5-minute-quickstart.md +17 -17
  101. package/wiki/guides/get-started/philosophy.md +1 -1
  102. package/wiki/guides/index.md +2 -2
  103. package/wiki/guides/reference/glossary.md +7 -7
  104. package/wiki/guides/reference/mcp-docs-server.md +1 -1
  105. package/wiki/guides/tutorials/building-a-crud-api.md +45 -39
  106. package/wiki/guides/tutorials/complete-installation.md +74 -51
  107. package/wiki/guides/tutorials/ecommerce-api.md +39 -30
  108. package/wiki/guides/tutorials/realtime-chat.md +12 -13
  109. package/wiki/guides/tutorials/testing.md +2 -2
  110. package/wiki/index.md +4 -3
  111. package/wiki/references/base/application.md +341 -21
  112. package/wiki/references/base/bootstrapping.md +43 -13
  113. package/wiki/references/base/components.md +259 -8
  114. package/wiki/references/base/controllers.md +556 -253
  115. package/wiki/references/base/datasources.md +159 -79
  116. package/wiki/references/base/dependency-injection.md +299 -48
  117. package/wiki/references/base/filter-system/application-usage.md +18 -2
  118. package/wiki/references/base/filter-system/array-operators.md +14 -6
  119. package/wiki/references/base/filter-system/comparison-operators.md +9 -3
  120. package/wiki/references/base/filter-system/default-filter.md +28 -3
  121. package/wiki/references/base/filter-system/fields-order-pagination.md +17 -13
  122. package/wiki/references/base/filter-system/index.md +169 -11
  123. package/wiki/references/base/filter-system/json-filtering.md +51 -18
  124. package/wiki/references/base/filter-system/list-operators.md +4 -3
  125. package/wiki/references/base/filter-system/logical-operators.md +7 -2
  126. package/wiki/references/base/filter-system/null-operators.md +50 -0
  127. package/wiki/references/base/filter-system/quick-reference.md +82 -243
  128. package/wiki/references/base/filter-system/range-operators.md +7 -1
  129. package/wiki/references/base/filter-system/tips.md +34 -7
  130. package/wiki/references/base/filter-system/use-cases.md +6 -5
  131. package/wiki/references/base/grpc-controllers.md +984 -0
  132. package/wiki/references/base/index.md +32 -24
  133. package/wiki/references/base/middleware.md +347 -0
  134. package/wiki/references/base/models.md +390 -46
  135. package/wiki/references/base/providers.md +14 -14
  136. package/wiki/references/base/repositories/advanced.md +195 -69
  137. package/wiki/references/base/repositories/index.md +447 -12
  138. package/wiki/references/base/repositories/mixins.md +103 -98
  139. package/wiki/references/base/repositories/relations.md +129 -45
  140. package/wiki/references/base/repositories/soft-deletable.md +104 -23
  141. package/wiki/references/base/services.md +94 -14
  142. package/wiki/references/index.md +12 -10
  143. package/wiki/references/quick-reference.md +98 -65
  144. package/wiki/references/utilities/crypto.md +21 -4
  145. package/wiki/references/utilities/date.md +25 -7
  146. package/wiki/references/utilities/index.md +26 -24
  147. package/wiki/references/utilities/jsx.md +54 -54
  148. package/wiki/references/utilities/module.md +8 -6
  149. package/wiki/references/utilities/parse.md +16 -9
  150. package/wiki/references/utilities/performance.md +22 -7
  151. package/wiki/references/utilities/promise.md +19 -16
  152. package/wiki/references/utilities/request.md +48 -26
  153. package/wiki/references/utilities/schema.md +69 -6
  154. package/wiki/references/utilities/statuses.md +131 -140
  155. /package/wiki/{references → extensions}/components/mail/api.md +0 -0
  156. /package/wiki/{references → extensions}/components/mail/errors.md +0 -0
  157. /package/wiki/{references → extensions}/components/mail/usage.md +0 -0
  158. /package/wiki/{references → extensions}/components/template/api-page.md +0 -0
  159. /package/wiki/{references → extensions}/components/template/errors-page.md +0 -0
  160. /package/wiki/{references → extensions}/components/template/usage-page.md +0 -0
  161. /package/wiki/{references → extensions}/helpers/cron/index.md +0 -0
  162. /package/wiki/{references → extensions}/helpers/inversion/index.md +0 -0
  163. /package/wiki/{references → extensions}/helpers/network/api.md +0 -0
  164. /package/wiki/{references → extensions}/helpers/network/index.md +0 -0
  165. /package/wiki/{references → extensions}/helpers/redis/index.md +0 -0
  166. /package/wiki/{references → extensions}/helpers/socket-io/api.md +0 -0
  167. /package/wiki/{references → extensions}/helpers/socket-io/index.md +0 -0
  168. /package/wiki/{references → extensions}/helpers/template/single-page.md +0 -0
  169. /package/wiki/{references → extensions}/helpers/uid/index.md +0 -0
  170. /package/wiki/{references → extensions}/helpers/websocket/api.md +0 -0
  171. /package/wiki/{references → extensions}/helpers/worker-thread/index.md +0 -0
  172. /package/wiki/{references → extensions}/src-details/mcp-server.md +0 -0
@@ -9,19 +9,24 @@ difficulty: advanced
9
9
  Technical reference for the DI system in Ignis - managing resource lifecycles and dependency resolution.
10
10
 
11
11
  **Files:**
12
- - `packages/inversion/src/container.ts` (base Container and Binding classes)
13
- - `packages/core/src/helpers/inversion/container.ts` (extended Container with ApplicationLogger)
14
- - `packages/core/src/base/metadata/injectors.ts` (@inject, @injectable decorators)
15
- - `packages/core/src/helpers/inversion/registry.ts` (MetadataRegistry)
12
+ - `packages/inversion/src/container.ts` Base `Container` and `Binding` classes
13
+ - `packages/inversion/src/registry.ts` Base `MetadataRegistry`
14
+ - `packages/inversion/src/metadata/injectors.ts` — Base `@inject` and `@injectable` decorators
15
+ - `packages/inversion/src/common/types.ts` — `BindingScopes`, `BindingValueTypes`, `BindingKeys`, `IProvider`
16
+ - `packages/core/src/helpers/inversion/container.ts` — Extended `Container` with `ApplicationLogger`
17
+ - `packages/core/src/helpers/inversion/registry.ts` — Extended `MetadataRegistry` (singleton, with model/repository/datasource mixins)
18
+ - `packages/core/src/base/metadata/injectors.ts` — Core `@inject` and `@injectable` (wired to extended registry)
16
19
 
17
20
  ## Quick Reference
18
21
 
19
22
  | Component | Purpose | Key Methods |
20
23
  |-----------|---------|-------------|
21
- | **Container** | DI registry managing resource lifecycles | `bind()`, `get()`, `instantiate()`, `findByTag()` |
22
- | **Binding** | Single registered dependency configuration | `toClass()`, `toValue()`, `toProvider()`, `setScope()`, `setTags()` |
23
- | **@inject** | Decorator marking injection points | Applied to constructor parameters/properties |
24
- | **MetadataRegistry** | Stores decorator metadata | Singleton accessed via `getInstance()` |
24
+ | **Container** | DI registry managing resource lifecycles | `bind()`, `get()`, `gets()`, `instantiate()`, `resolve()`, `findByTag()`, `isBound()`, `unbind()`, `clear()`, `reset()` |
25
+ | **Binding** | Single registered dependency configuration | `toClass()`, `toValue()`, `toProvider()`, `setScope()`, `setTags()`, `getValue()`, `clearCache()` |
26
+ | **@inject** | Decorator marking injection points | Applied to constructor parameters and class properties |
27
+ | **@injectable** | Decorator marking a class as injectable | Stores scope and tag metadata |
28
+ | **MetadataRegistry** | Stores decorator metadata | Singleton — base via `metadataRegistry` export, core via `MetadataRegistry.getInstance()` |
29
+ | **BindingKeys** | Utility for building namespaced keys | `BindingKeys.build({ namespace, key })` |
25
30
  | **Boot System** | Automatic artifact discovery and binding | Integrates with Container via tags and bindings |
26
31
 
27
32
  ## Prerequisites
@@ -30,7 +35,7 @@ Before reading this document, you should understand:
30
35
 
31
36
  - [TypeScript Decorators](https://www.typescriptlang.org/docs/handbook/decorators.html) - How decorators work in TypeScript
32
37
  - [IGNIS Application basics](./application.md) - Application lifecycle and initialization
33
- - [Services](./services.md) and [Controllers](./controllers.md) - Basic understanding of IGNIS architecture
38
+ - [Services](./services.md) and [Controllers](./controllers.md) - Basic understanding of IGNIS architecture (REST controllers)
34
39
  - Inversion of Control (IoC) pattern - [Martin Fowler's article](https://martinfowler.com/articles/injection.html)
35
40
 
36
41
  ## `Container` Class
@@ -39,65 +44,311 @@ Heart of the DI system - registry managing all application resources.
39
44
 
40
45
  **File:** `packages/inversion/src/container.ts` (Base) & `packages/core/src/helpers/inversion/container.ts` (Extended)
41
46
 
47
+ The base `Container` extends `BaseHelper` (which provides `scope` and `identifier` properties). The core `Container` extends the base and adds a `Logger` instance.
48
+
49
+ ### Constructor
50
+
51
+ ```typescript
52
+ const container = new Container({ scope: 'MyApp' }); // scope is optional, defaults to "Container"
53
+ ```
54
+
42
55
  ### Key Methods
43
56
 
44
- | Method | Description |
45
- | :--- | :--- |
46
- | **`bind<T>({ key })`** | Starts a new binding for a given key. It returns a `Binding` instance that you can use to configure the dependency. |
47
- | **`get<T>({ key, isOptional })`** | Retrieves a dependency from the container. The `key` can be a string, a symbol, or an object like `{ namespace: 'services', key: 'MyService' }`. If the dependency is not found and `isOptional` is `false` (the default), it will throw an error. |
48
- | **`instantiate<T>(cls)`** | Creates a new instance of a class, automatically injecting any dependencies specified in its constructor or on its properties. This is the method the container uses internally to create your controllers, services, etc. |
49
- | **`findByTag({ tag })`** | Finds all bindings that have been tagged with a specific tag (e.g., `'controllers'`, `'components'`). This is used by the application to discover and initialize all registered resources of a certain type. |
57
+ | Method | Signature | Description |
58
+ | :--- | :--- | :--- |
59
+ | **`bind`** | `bind<T>({ key: string \| symbol }): Binding<T>` | Creates and registers a new `Binding` for the given key. Returns the `Binding` for fluent configuration. |
60
+ | **`get`** | `get<T>({ key, isOptional? }): T` | Retrieves a resolved dependency. `key` can be a `string`, `symbol`, or `{ namespace, key }` object. Throws if not found and `isOptional` is `false` (default). Returns `undefined` if `isOptional` is `true` and not found. |
61
+ | **`gets`** | `gets<T>({ bindings }): T[]` | Resolves multiple dependencies at once. Each entry in `bindings` accepts `{ key, isOptional? }`. All lookups are treated as optional (returns `undefined` for missing). |
62
+ | **`getBinding`** | `getBinding<T>({ key }): Binding<T> \| undefined` | Returns the raw `Binding` object without resolving it. `key` accepts `string`, `symbol`, or `{ namespace, key }`. |
63
+ | **`set`** | `set<T>({ binding: Binding<T> }): void` | Directly sets a pre-built `Binding` into the container. |
64
+ | **`isBound`** | `isBound({ key: string \| symbol }): boolean` | Checks if a binding exists for the given key. |
65
+ | **`unbind`** | `unbind({ key: string \| symbol }): boolean` | Removes a binding. Returns `true` if it existed. |
66
+ | **`resolve`** | `resolve<T>(cls: TClass<T>): T` | Alias for `instantiate()`. Creates a new instance of the class with DI. |
67
+ | **`instantiate`** | `instantiate<T>(cls: TClass<T>): T` | Creates a new instance of a class, injecting constructor parameters and property dependencies from the container. |
68
+ | **`findByTag`** | `findByTag<T>({ tag, exclude? }): Binding<T>[]` | Finds all bindings tagged with `tag`. Optionally exclude specific binding keys via `exclude` (accepts `Array<string>` or `Set<string>`). |
69
+ | **`clear`** | `clear(): void` | Clears cached singleton values on all bindings (does not remove bindings). |
70
+ | **`reset`** | `reset(): void` | Removes all bindings entirely. |
71
+ | **`getMetadataRegistry`** | `getMetadataRegistry(): MetadataRegistry` | Returns the metadata registry. The core `Container` overrides this to return `MetadataRegistry.getInstance()`. |
72
+
73
+ ### Instantiation Algorithm (Two-Phase)
74
+
75
+ When `container.instantiate(MyClass)` is called:
76
+
77
+ 1. **Constructor injection** — Reads `@inject` metadata from the class, sorts by parameter index, resolves each dependency from the container, and passes them as constructor arguments.
78
+ 2. **Property injection** — After the instance is created, reads property metadata, resolves each dependency, and assigns them directly to the instance properties.
79
+
80
+ ```typescript
81
+ // Both constructor and property injection in action
82
+ class UserController {
83
+ @inject({ key: 'services.NotificationService' })
84
+ private notificationService!: NotificationService; // Property injection
85
+
86
+ constructor(
87
+ @inject({ key: 'services.UserService' })
88
+ private userService: UserService, // Constructor injection
89
+ ) {}
90
+ }
91
+ ```
50
92
 
51
93
  ## `Binding` Class
52
94
 
53
- A `Binding` represents a single registered dependency in the container. It's a fluent API that allows you to specify *how* a dependency should be created and managed.
95
+ A `Binding` represents a single registered dependency in the container. It provides a fluent API to configure *how* a dependency should be created and managed.
96
+
97
+ **File:** `packages/inversion/src/container.ts`
98
+
99
+ The `Binding` class extends `BaseHelper`.
54
100
 
55
- - **File:** `packages/inversion/src/container.ts`
101
+ ### Constructor
102
+
103
+ ```typescript
104
+ const binding = new Binding<MyService>({ key: 'services.MyService' });
105
+ ```
106
+
107
+ When a binding key contains a dot (e.g., `services.MyService`), the namespace portion (`services`) is automatically added as a tag. This enables `findByTag({ tag: 'services' })` to work without manual tagging.
56
108
 
57
109
  ### Configuration Methods
58
110
 
59
- | Method | Description |
60
- | :--- | :--- |
61
- | **`toClass(MyClass)`** | Binds the key to a class. The container will instantiate this class (and resolve its dependencies) when the key is requested. |
62
- | **`toValue(someValue)`** | Binds the key to a constant value (e.g., a configuration object, a string, a number). |
63
- | **`toProvider(MyProvider)`**| Binds the key to a provider class or function. This is for dependencies that require complex creation logic. |
64
- | **`setScope(scope)`** | Sets the lifecycle scope of the binding. See "Binding Scopes" below. |
111
+ | Method | Signature | Description |
112
+ | :--- | :--- | :--- |
113
+ | **`toClass`** | `toClass(value: TClass<T>): this` | Binds to a class. The container will instantiate it (resolving constructor and property dependencies) when requested. |
114
+ | **`toValue`** | `toValue(value: T): this` | Binds to a constant value (e.g., a config object, string, number). |
115
+ | **`toProvider`** | `toProvider(value: ((container) => T) \| TClass<IProvider<T>>): this` | Binds to a factory function or a class implementing `IProvider<T>`. |
116
+ | **`setScope`** | `setScope(scope: TBindingScope): this` | Sets the lifecycle scope (`'singleton'` or `'transient'`). |
117
+ | **`setTags`** | `setTags(...tags: string[]): this` | Adds one or more tags to the binding. Tags are additive — calling this multiple times adds more tags. |
118
+ | **`getValue`** | `getValue(container?: Container): T` | Resolves the binding's value. For `CLASS` and `PROVIDER` types, a `container` argument is required. Respects singleton caching. |
119
+ | **`clearCache`** | `clearCache(): void` | Clears the cached singleton instance (if any). Next `getValue()` call will re-create it. |
120
+ | **`hasTag`** | `hasTag(tag: string): boolean` | Checks if the binding has a specific tag. |
121
+ | **`getTags`** | `getTags(): string[]` | Returns all tags as an array. |
122
+ | **`getScope`** | `getScope(): TBindingScope` | Returns the current scope setting. |
123
+ | **`getBindingMeta`** | `getBindingMeta({ type }): TClass<T> \| T \| ...` | Returns the raw resolver value. Throws if the requested type does not match the binding's actual type. |
124
+
125
+ ### Fluent API Example
126
+
127
+ ```typescript
128
+ container
129
+ .bind<UserService>({ key: 'services.UserService' })
130
+ .toClass(UserService)
131
+ .setScope(BindingScopes.SINGLETON)
132
+ .setTags('core');
133
+ ```
134
+
135
+ ### Provider Bindings
136
+
137
+ Providers allow complex creation logic. Two forms are supported:
138
+
139
+ **Function provider:**
140
+ ```typescript
141
+ container.bind({ key: 'config.db' }).toProvider((container) => {
142
+ const env = container.get<EnvConfig>({ key: 'config.env' });
143
+ return { host: env.DB_HOST, port: env.DB_PORT };
144
+ });
145
+ ```
146
+
147
+ **Class provider** (must implement `IProvider<T>`):
148
+ ```typescript
149
+ class DbConfigProvider implements IProvider<DbConfig> {
150
+ value(container: Container): DbConfig {
151
+ const env = container.get<EnvConfig>({ key: 'config.env' });
152
+ return { host: env.DB_HOST, port: env.DB_PORT };
153
+ }
154
+ }
155
+
156
+ container.bind({ key: 'config.db' }).toProvider(DbConfigProvider);
157
+ ```
65
158
 
66
159
  ### Binding Scopes
67
160
 
68
- | Scope | Description |
69
- | :--- | :--- |
70
- | **`BindingScopes.TRANSIENT`** | (Default) A new instance of the dependency is created every time it is injected or requested from the container. |
71
- | **`BindingScopes.SINGLETON`** | A single instance is created the first time it is requested, and that same instance is reused for all subsequent requests. DataSources and Components are typically singletons. |
161
+ | Scope | Value | Description |
162
+ | :--- | :--- | :--- |
163
+ | **`BindingScopes.TRANSIENT`** | `'transient'` | (Default) A new instance is created every time the dependency is requested. |
164
+ | **`BindingScopes.SINGLETON`** | `'singleton'` | A single instance is created on first request and reused for all subsequent requests. The cache is per-Binding, not per-Container. |
165
+
166
+ ### Binding Value Types
167
+
168
+ | Type | Value | Description |
169
+ | :--- | :--- | :--- |
170
+ | **`BindingValueTypes.CLASS`** | `'class'` | Bound via `toClass()`. Container instantiates with DI. |
171
+ | **`BindingValueTypes.VALUE`** | `'value'` | Bound via `toValue()`. Direct value return. |
172
+ | **`BindingValueTypes.PROVIDER`** | `'provider'` | Bound via `toProvider()`. Factory function or `IProvider` class. |
173
+
174
+ ## `BindingKeys` Utility
175
+
176
+ Builds namespaced binding keys from structured objects.
177
+
178
+ **File:** `packages/inversion/src/common/types.ts`
179
+
180
+ ```typescript
181
+ BindingKeys.build({ namespace: 'services', key: 'UserService' });
182
+ // → 'services.UserService'
183
+
184
+ BindingKeys.build({ namespace: '', key: 'AppConfig' });
185
+ // → 'AppConfig'
186
+
187
+ BindingKeys.build({ namespace: 'services', key: '' });
188
+ // → Throws error: key is required
189
+ ```
190
+
191
+ This is also used internally by `container.get()` and `container.getBinding()` when you pass a `{ namespace, key }` object as the key.
72
192
 
73
193
  ## `@inject` Decorator
74
194
 
75
- The `@inject` decorator is used to mark where dependencies should be injected.
195
+ The `@inject` decorator marks where dependencies should be injected — either on constructor parameters or class properties.
76
196
 
77
- - **File:** `packages/core/src/base/metadata/injectors.ts`
197
+ **File:** `packages/inversion/src/metadata/injectors.ts` (base) & `packages/core/src/base/metadata/injectors.ts` (core wrapper)
198
+
199
+ ### Signature
200
+
201
+ ```typescript
202
+ @inject({ key: string | symbol; isOptional?: boolean })
203
+ ```
204
+
205
+ | Parameter | Type | Default | Description |
206
+ | :--- | :--- | :--- | :--- |
207
+ | `key` | `string \| symbol` | — | The binding key to resolve from the container. |
208
+ | `isOptional` | `boolean` | `false` | If `true`, returns `undefined` instead of throwing when the binding is not found. |
209
+
210
+ ### Constructor Parameter Injection
211
+
212
+ ```typescript
213
+ class UserController {
214
+ constructor(
215
+ @inject({ key: 'services.UserService' })
216
+ private userService: UserService,
217
+
218
+ @inject({ key: 'services.CacheService', isOptional: true })
219
+ private cacheService?: CacheService, // Won't throw if not registered
220
+ ) {}
221
+ }
222
+ ```
223
+
224
+ ### Property Injection
225
+
226
+ ```typescript
227
+ class UserController {
228
+ @inject({ key: 'services.UserService' })
229
+ private userService!: UserService;
230
+
231
+ @inject({ key: 'services.CacheService', isOptional: true })
232
+ private cacheService?: CacheService;
233
+ }
234
+ ```
78
235
 
79
236
  ### How It Works
80
237
 
81
- 1. When you apply the `@inject` decorator to a constructor parameter or a class property, it uses `Reflect.metadata` to attach metadata to the class.
82
- 2. The metadata includes the **binding key** of the dependency to be injected.
83
- 3. When the `container.instantiate(MyClass)` method is called, it reads this metadata.
84
- 4. It then calls `container.get({ key })` for each decorated parameter/property to resolve the dependency.
85
- 5. Finally, it creates the instance of `MyClass`, passing the resolved dependencies to the constructor or setting them on the instance properties.
238
+ 1. When `@inject` is applied to a **constructor parameter**, it stores `IInjectMetadata` (key, index, isOptional) on the class via the `MetadataRegistry`.
239
+ 2. When `@inject` is applied to a **property**, it stores `IPropertyMetadata` (bindingKey, isOptional) on the class prototype via the `MetadataRegistry`.
240
+ 3. When `container.instantiate(MyClass)` is called, it reads both metadata sets, resolves each dependency from the container, and injects them.
241
+
242
+ ### Base vs Core Decorators
243
+
244
+ The `@venizia/ignis-inversion` package exports base decorators that use the module-level `metadataRegistry` singleton. The `@venizia/ignis` (core) package re-exports wrappers that use the core `MetadataRegistry.getInstance()` singleton instead, which includes model/repository/datasource metadata support.
245
+
246
+ **Always import from `@venizia/ignis` in application code:**
247
+ ```typescript
248
+ import { inject, injectable } from '@venizia/ignis';
249
+ ```
250
+
251
+ ## `@injectable` Decorator
252
+
253
+ Marks a class as injectable and attaches optional metadata.
86
254
 
87
- This entire process is managed by the framework when your application starts up, ensuring that all your registered classes are created with their required dependencies.
255
+ **File:** `packages/inversion/src/metadata/injectors.ts` (base) & `packages/core/src/base/metadata/injectors.ts` (core wrapper)
256
+
257
+ ### Signature
258
+
259
+ ```typescript
260
+ @injectable({ scope?: TBindingScope; tags?: Record<string, any> })
261
+ ```
262
+
263
+ | Parameter | Type | Default | Description |
264
+ | :--- | :--- | :--- | :--- |
265
+ | `scope` | `'singleton' \| 'transient'` | — | Optional scope hint for the binding. |
266
+ | `tags` | `Record<string, any>` | — | Optional metadata tags. |
267
+
268
+ ### Example
269
+
270
+ ```typescript
271
+ @injectable({ scope: BindingScopes.SINGLETON })
272
+ class UserService extends BaseService {
273
+ constructor(
274
+ @inject({ key: 'repositories.UserRepository' })
275
+ private userRepo: UserRepository,
276
+ ) {
277
+ super({ scope: UserService.name });
278
+ }
279
+ }
280
+ ```
88
281
 
89
282
  ## `MetadataRegistry`
90
283
 
91
- The `MetadataRegistry` is a crucial part of the DI and routing systems. It's a singleton class responsible for storing and retrieving all the metadata attached by decorators like `@inject`, `@controller`, `@get`, etc.
284
+ The `MetadataRegistry` stores and retrieves all metadata attached by decorators (`@inject`, `@injectable`, `@controller`, `@model`, etc.).
285
+
286
+ ### Base MetadataRegistry
92
287
 
93
- - **File:** `packages/core/src/helpers/inversion/registry.ts`
288
+ **File:** `packages/inversion/src/registry.ts`
94
289
 
95
- ### Role in DI
290
+ A singleton exported as `metadataRegistry`. Extends `BaseHelper`.
96
291
 
97
- - When you use a decorator (e.g., `@inject`), it calls a method on the `MetadataRegistry.getInstance()` to store information about the injection (like the binding key and target property/parameter).
98
- - When the `Container` instantiates a class, it queries the `MetadataRegistry` to find out which dependencies need to be injected and where.
292
+ | Method | Description |
293
+ | :--- | :--- |
294
+ | `define({ target, key, value })` | Stores arbitrary metadata on a target using `Reflect.defineMetadata`. |
295
+ | `get({ target, key })` | Retrieves metadata by key from a target. |
296
+ | `has({ target, key })` | Checks if metadata exists. |
297
+ | `delete({ target, key })` | Removes metadata. Returns `true` if it existed. |
298
+ | `getKeys({ target })` | Returns all metadata keys on a target. |
299
+ | `getMethodNames({ target })` | Returns all method names on a class prototype (excluding `constructor`). |
300
+ | `clearMetadata({ target })` | Removes all metadata from a target. |
301
+ | `setInjectMetadata({ target, index, metadata })` | Stores constructor parameter injection metadata (`IInjectMetadata`). |
302
+ | `getInjectMetadata({ target })` | Returns all constructor injection metadata for a class. |
303
+ | `setPropertyMetadata({ target, propertyName, metadata })` | Stores property injection metadata (`IPropertyMetadata`). |
304
+ | `getPropertiesMetadata({ target })` | Returns a `Map<string \| symbol, IPropertyMetadata>` for all injected properties. |
305
+ | `getPropertyMetadata({ target, propertyName })` | Returns property metadata for a specific property. |
306
+ | `setInjectableMetadata({ target, metadata })` | Stores `@injectable` metadata on a class. |
307
+ | `getInjectableMetadata({ target })` | Returns `@injectable` metadata for a class. |
308
+
309
+ ### Core MetadataRegistry
310
+
311
+ **File:** `packages/core/src/helpers/inversion/registry.ts`
312
+
313
+ Extends the base with controller, repository, model, and datasource metadata support via mixins. Accessed as a singleton via `MetadataRegistry.getInstance()`.
314
+
315
+ Additional capabilities include:
316
+ - Controller metadata (route configs, path mappings)
317
+ - REST and gRPC controller metadata
318
+ - Repository binding metadata
319
+ - Model registry (schema, settings)
320
+ - DataSource metadata and schema auto-discovery
321
+
322
+ ### Metadata Keys
323
+
324
+ Defined in `packages/inversion/src/common/keys.ts`:
99
325
 
100
- You typically won't interact with the `MetadataRegistry` directly, but it's the underlying mechanism that makes the decorator-based DI and routing systems work seamlessly.
326
+ ```typescript
327
+ MetadataKeys.PROPERTIES = Symbol.for('ignis:properties')
328
+ MetadataKeys.INJECT = Symbol.for('ignis:inject')
329
+ MetadataKeys.INJECTABLE = Symbol.for('ignis:injectable')
330
+ ```
331
+
332
+ ### Key Types
333
+
334
+ ```typescript
335
+ interface IInjectMetadata {
336
+ key: string | symbol;
337
+ index: number;
338
+ isOptional?: boolean;
339
+ }
340
+
341
+ interface IPropertyMetadata {
342
+ bindingKey: string | symbol;
343
+ isOptional?: boolean;
344
+ [key: string]: any;
345
+ }
346
+
347
+ interface IInjectableMetadata {
348
+ scope?: TBindingScope;
349
+ tags?: Record<string, any>;
350
+ }
351
+ ```
101
352
 
102
353
  ## Boot System Integration
103
354
 
@@ -136,19 +387,19 @@ This pattern allows the `Bootstrapper` to automatically discover and execute all
136
387
 
137
388
  ### Artifact Bindings
138
389
 
139
- Once artifacts are discovered and loaded, they're bound using consistent patterns:
390
+ Once artifacts are discovered and loaded, they're bound using consistent namespace patterns:
140
391
 
141
392
  ```typescript
142
- // Controllers
393
+ // Controllers — auto-tagged with 'controllers'
143
394
  this.bind({ key: 'controllers.UserController' }).toClass(UserController);
144
395
 
145
- // Services
396
+ // Services — auto-tagged with 'services'
146
397
  this.bind({ key: 'services.UserService' }).toClass(UserService);
147
398
 
148
- // Repositories
399
+ // Repositories — auto-tagged with 'repositories'
149
400
  this.bind({ key: 'repositories.UserRepository' }).toClass(UserRepository);
150
401
 
151
- // Datasources
402
+ // Datasources — auto-tagged with 'datasources'
152
403
  this.bind({ key: 'datasources.PostgresDataSource' }).toClass(PostgresDataSource);
153
404
  ```
154
405
 
@@ -227,12 +478,12 @@ class MyApp extends BaseApplication {
227
478
  - **Related Concepts:**
228
479
  - [Dependency Injection Guide](/guides/core-concepts/dependency-injection) - DI fundamentals tutorial
229
480
  - [Application](/guides/core-concepts/application/) - Application extends Container
230
- - [Controllers](/guides/core-concepts/controllers) - Use DI for injecting services
481
+ - [Controllers](/guides/core-concepts/rest-controllers) - Use DI for injecting services
231
482
  - [Services](/guides/core-concepts/services) - Use DI for injecting repositories
232
483
  - [Providers](/references/base/providers) - Factory pattern for dynamic injection
233
484
 
234
485
  - **References:**
235
- - [Inversion Helper](/references/helpers/inversion/) - DI container utilities
486
+ - [Inversion Helper](/extensions/helpers/inversion/) - DI container utilities
236
487
  - [Bootstrapping API](/references/base/bootstrapping) - Auto-discovery and DI
237
488
  - [Glossary](/guides/reference/glossary#dependency-injection-di) - DI concepts explained
238
489
 
@@ -35,7 +35,8 @@ How filters flow through the application layers.
35
35
  v
36
36
  +-----------------------------------------------------------------+
37
37
  | Repository Layer |
38
- | - FilterBuilder transforms Filter -> SQL |
38
+ | - DefaultFilterMixin merges default filter |
39
+ | - FilterBuilder transforms Filter -> Drizzle query options |
39
40
  | - Executes query via Drizzle ORM |
40
41
  | - Returns typed results |
41
42
  +-----------------------------------------------------------------+
@@ -102,7 +103,7 @@ export class ProductController extends _Controller {
102
103
 
103
104
  ```typescript
104
105
  @controller({ path: '/products' })
105
- export class ProductController extends BaseController {
106
+ export class ProductController extends BaseRestController {
106
107
  constructor(
107
108
  @inject({ key: 'repositories.ProductRepository' })
108
109
  private _productRepo: ProductRepository,
@@ -130,6 +131,21 @@ export class ProductController extends BaseController {
130
131
  ```
131
132
 
132
133
 
134
+ ## Filter Schema Validation
135
+
136
+ The `FilterSchema` (Zod) accepts both object and JSON string formats:
137
+
138
+ ```typescript
139
+ // Object format (from parsed query params)
140
+ { where: { status: 'active' }, limit: 10 }
141
+
142
+ // JSON string format (from URL query string)
143
+ '{"where":{"status":"active"},"limit":10}'
144
+ ```
145
+
146
+ The `WhereSchema` also accepts both formats independently, useful for the `count` endpoint which takes `where` directly.
147
+
148
+
133
149
  ## Service Layer
134
150
 
135
151
  Services can modify filters before passing to repositories:
@@ -27,8 +27,9 @@ Find rows where the array column contains **all** specified elements.
27
27
  { where: { tags: { contains: ['electronics', 'featured'] } } }
28
28
  // SQL: "tags"::text[] @> ARRAY['electronics', 'featured']::text[]
29
29
 
30
- // Single element
30
+ // Single element (can pass single value or array)
31
31
  { where: { tags: { contains: ['featured'] } } }
32
+ { where: { tags: { contains: 'featured' } } } // Also works
32
33
  // Matches: ['featured'], ['featured', 'sale'], ['a', 'featured', 'b']
33
34
  ```
34
35
 
@@ -85,11 +86,14 @@ Find rows where the arrays share at least one common element.
85
86
 
86
87
  ## Empty Array Behavior
87
88
 
88
- | Operator | Empty Value `[]` | Behavior |
89
- |----------|------------------|----------|
90
- | `contains: []` | Returns **ALL** rows | Everything contains empty set |
91
- | `containedBy: []` | Returns only rows with **empty arrays** | Only `[]` is subset of `[]` |
92
- | `overlaps: []` | Returns **NO** rows | Nothing overlaps with empty |
89
+ | Operator | Empty Value `[]` | SQL Generated | Behavior |
90
+ |----------|------------------|---------------|----------|
91
+ | `contains: []` | `WHERE true` | Returns **ALL** rows |
92
+ | `containedBy: []` | `WHERE "col" = '{}'` | Returns only rows with **empty arrays** |
93
+ | `overlaps: []` | `WHERE false` | Returns **NO** rows |
94
+
95
+ > [!NOTE]
96
+ > Single values are automatically wrapped in an array: `{ contains: 'value' }` is treated as `{ contains: ['value'] }`.
93
97
 
94
98
 
95
99
  ## Type Handling
@@ -100,12 +104,16 @@ Find rows where the arrays share at least one common element.
100
104
  // SQL: "tags"::text[] @> ARRAY['a', 'b']::text[]
101
105
  ```
102
106
 
107
+ Both the column and the array literal are cast to `text[]` for compatibility.
108
+
103
109
  **Numeric Arrays** (`integer[]`, `numeric[]`):
104
110
  ```typescript
105
111
  { where: { scores: { contains: [100, 200] } } }
106
112
  // SQL: "scores" @> ARRAY[100, 200]
107
113
  ```
108
114
 
115
+ No casting needed for numeric arrays.
116
+
109
117
  **Boolean Arrays**:
110
118
  ```typescript
111
119
  { where: { flags: { contains: [true, false] } } }
@@ -33,12 +33,16 @@ Matches records where field equals the value.
33
33
  // Array shorthand (becomes IN)
34
34
  { where: { id: [1, 2, 3] } }
35
35
  // SQL: WHERE "id" IN (1, 2, 3)
36
+
37
+ // Empty array shorthand
38
+ { where: { id: [] } }
39
+ // SQL: WHERE false (no results)
36
40
  ```
37
41
 
38
42
 
39
43
  ## ne / neq - Not Equal To
40
44
 
41
- Matches records where field does NOT equal the value.
45
+ Matches records where field does NOT equal the value. Both `ne` and `neq` are aliases and behave identically.
42
46
 
43
47
  ```typescript
44
48
  { where: { status: { ne: 'deleted' } } }
@@ -48,6 +52,7 @@ Matches records where field does NOT equal the value.
48
52
 
49
53
  // Null handling
50
54
  { where: { deletedAt: { ne: null } } }
55
+ { where: { deletedAt: { neq: null } } }
51
56
  // SQL: WHERE "deleted_at" IS NOT NULL
52
57
  ```
53
58
 
@@ -101,8 +106,9 @@ Matches records where field does NOT equal the value.
101
106
 
102
107
  | Operator | SQL | Description |
103
108
  |----------|-----|-------------|
104
- | `eq` | `=` | Equal to |
105
- | `ne` / `neq` | `!=` | Not equal to |
109
+ | `eq` | `=` / `IS NULL` | Equal to (handles null) |
110
+ | `ne` | `!=` / `IS NOT NULL` | Not equal to (handles null) |
111
+ | `neq` | `!=` / `IS NOT NULL` | Alias for `ne` |
106
112
  | `gt` | `>` | Greater than |
107
113
  | `gte` | `>=` | Greater than or equal |
108
114
  | `lt` | `<` | Less than |
@@ -2,7 +2,7 @@
2
2
  title: Default Filter
3
3
  description: Automatically apply filter conditions to all repository queries
4
4
  difficulty: intermediate
5
- lastUpdated: 2026-01-02
5
+ lastUpdated: 2026-03-15
6
6
  ---
7
7
 
8
8
  # Default Filter <Badge type="tip" text="v0.0.5+" />
@@ -93,11 +93,11 @@ export class User extends BaseEntity<typeof User.schema> {}
93
93
 
94
94
  ## Merge Behavior
95
95
 
96
- When a user provides a filter, it is merged with the default filter:
96
+ When a user provides a filter, it is merged with the default filter using `FilterBuilder.mergeFilter()`:
97
97
 
98
98
  | Property | Merge Strategy |
99
99
  |----------|----------------|
100
- | `where` | **Deep merge** - user values override matching keys |
100
+ | `where` | **Deep merge** (via lodash `merge`) -- user values override matching keys |
101
101
  | `limit` | User replaces default (if provided) |
102
102
  | `offset`/`skip` | User replaces default (if provided) |
103
103
  | `order` | User replaces default (if provided) |
@@ -316,6 +316,28 @@ await logRepo.find({ filter: { limit: 50 } }); // LIMIT 50
316
316
  ```
317
317
 
318
318
 
319
+ ## Relation Include Default Filters
320
+
321
+ When using `include` to load relations, the default filter of the related model is also applied. You can bypass it per-relation:
322
+
323
+ ```typescript
324
+ await repo.find({
325
+ filter: {
326
+ include: [
327
+ // Default filter of related model applies
328
+ { relation: 'posts' },
329
+
330
+ // Skip default filter for this specific relation
331
+ { relation: 'comments', shouldSkipDefaultFilter: true },
332
+
333
+ // Apply a custom scope (merged with relation's default filter)
334
+ { relation: 'tags', scope: { limit: 10, order: ['name ASC'] } },
335
+ ]
336
+ }
337
+ });
338
+ ```
339
+
340
+
319
341
  ## IExtraOptions Interface
320
342
 
321
343
  The `shouldSkipDefaultFilter` option is part of the `IExtraOptions` interface:
@@ -392,6 +414,8 @@ applyDefaultFilter(opts: {
392
414
  }): TFilter
393
415
  ```
394
416
 
417
+ The default filter is resolved from `MetadataRegistry` on first access and cached for subsequent calls.
418
+
395
419
  ### FilterBuilder.mergeFilter()
396
420
 
397
421
  The merge logic is implemented in `FilterBuilder`:
@@ -415,6 +439,7 @@ const merged = filterBuilder.mergeFilter({
415
439
  |------------|------|
416
440
  | Configure default filter | `@model({ settings: { defaultFilter: { ... } } })` |
417
441
  | Bypass default filter | `options: { shouldSkipDefaultFilter: true }` |
442
+ | Bypass for relation | `include: [{ relation: 'x', shouldSkipDefaultFilter: true }]` |
418
443
  | Combine with transaction | `options: { transaction: tx, shouldSkipDefaultFilter: true }` |
419
444
  | Check if model has default | `repo.hasDefaultFilter()` |
420
445
  | Get raw default filter | `repo.getDefaultFilter()` |