@med1802/repository-manager 2.2.1 → 3.0.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 (82) hide show
  1. package/README.md +430 -381
  2. package/dist/index.d.ts +2 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +1 -0
  5. package/dist/manager.d.ts +14 -0
  6. package/dist/manager.d.ts.map +1 -0
  7. package/dist/manager.js +17 -0
  8. package/dist/workspace/index.d.ts +13 -0
  9. package/dist/workspace/index.d.ts.map +1 -0
  10. package/dist/workspace/index.js +30 -0
  11. package/dist/workspace/infrastructure/index.d.ts +4 -0
  12. package/dist/workspace/infrastructure/index.d.ts.map +1 -0
  13. package/dist/workspace/infrastructure/index.js +3 -0
  14. package/dist/{logger.d.ts → workspace/infrastructure/logger.d.ts} +1 -1
  15. package/dist/workspace/infrastructure/logger.d.ts.map +1 -0
  16. package/dist/workspace/infrastructure/scope/index.d.ts +3 -0
  17. package/dist/workspace/infrastructure/scope/index.d.ts.map +1 -0
  18. package/dist/workspace/infrastructure/scope/index.js +2 -0
  19. package/dist/workspace/infrastructure/scope/scope.d.ts +7 -0
  20. package/dist/workspace/infrastructure/scope/scope.d.ts.map +1 -0
  21. package/dist/workspace/infrastructure/scope/scope.js +32 -0
  22. package/dist/workspace/infrastructure/scope/types.d.ts +8 -0
  23. package/dist/workspace/infrastructure/scope/types.d.ts.map +1 -0
  24. package/dist/workspace/infrastructure/store.d.ts.map +1 -0
  25. package/dist/workspace/modules/index.d.ts +2 -0
  26. package/dist/workspace/modules/index.d.ts.map +1 -0
  27. package/dist/workspace/modules/index.js +1 -0
  28. package/dist/workspace/modules/repository/createRepositoryModule.d.ts +10 -0
  29. package/dist/workspace/modules/repository/createRepositoryModule.d.ts.map +1 -0
  30. package/dist/{workspace.js → workspace/modules/repository/createRepositoryModule.js} +22 -23
  31. package/dist/workspace/modules/repository/index.d.ts +3 -0
  32. package/dist/workspace/modules/repository/index.d.ts.map +1 -0
  33. package/dist/workspace/modules/repository/index.js +2 -0
  34. package/dist/workspace/modules/repository/middleware.d.ts.map +1 -0
  35. package/dist/workspace/modules/repository/repositoryAccessor.d.ts +9 -0
  36. package/dist/workspace/modules/repository/repositoryAccessor.d.ts.map +1 -0
  37. package/dist/workspace/modules/repository/repositoryAccessor.js +42 -0
  38. package/dist/workspace/modules/repository/types.d.ts +22 -0
  39. package/dist/workspace/modules/repository/types.d.ts.map +1 -0
  40. package/dist/workspace/modules/repository/types.js +1 -0
  41. package/dist/workspace/providers/index.d.ts +5 -0
  42. package/dist/workspace/providers/index.d.ts.map +1 -0
  43. package/dist/workspace/providers/index.js +3 -0
  44. package/dist/workspace/types.d.ts +5 -0
  45. package/dist/workspace/types.d.ts.map +1 -0
  46. package/dist/workspace/types.js +1 -0
  47. package/package.json +1 -1
  48. package/src/index.ts +1 -0
  49. package/src/manager.ts +23 -0
  50. package/src/workspace/index.ts +38 -0
  51. package/src/workspace/infrastructure/index.ts +3 -0
  52. package/src/{logger.ts → workspace/infrastructure/logger.ts} +1 -1
  53. package/src/workspace/infrastructure/scope/index.ts +2 -0
  54. package/src/workspace/infrastructure/scope/scope.ts +35 -0
  55. package/src/workspace/infrastructure/scope/types.ts +8 -0
  56. package/src/workspace/modules/index.ts +1 -0
  57. package/src/{workspace.ts → workspace/modules/repository/createRepositoryModule.ts} +22 -35
  58. package/src/workspace/modules/repository/index.ts +2 -0
  59. package/src/{middleware.ts → workspace/modules/repository/middleware.ts} +1 -5
  60. package/src/{repositoryAccessor.ts → workspace/modules/repository/repositoryAccessor.ts} +14 -12
  61. package/src/workspace/modules/repository/types.ts +29 -0
  62. package/src/workspace/providers/index.ts +5 -0
  63. package/src/workspace/types.ts +4 -0
  64. package/tsconfig.tsbuildinfo +1 -1
  65. package/dist/logger.d.ts.map +0 -1
  66. package/dist/middleware.d.ts.map +0 -1
  67. package/dist/repositoryAccessor.d.ts +0 -9
  68. package/dist/repositoryAccessor.d.ts.map +0 -1
  69. package/dist/repositoryAccessor.js +0 -40
  70. package/dist/store.d.ts.map +0 -1
  71. package/dist/types.d.ts +0 -28
  72. package/dist/types.d.ts.map +0 -1
  73. package/dist/workspace.d.ts +0 -10
  74. package/dist/workspace.d.ts.map +0 -1
  75. package/src/types.ts +0 -37
  76. /package/dist/{logger.js → workspace/infrastructure/logger.js} +0 -0
  77. /package/dist/{types.js → workspace/infrastructure/scope/types.js} +0 -0
  78. /package/dist/{store.d.ts → workspace/infrastructure/store.d.ts} +0 -0
  79. /package/dist/{store.js → workspace/infrastructure/store.js} +0 -0
  80. /package/dist/{middleware.d.ts → workspace/modules/repository/middleware.d.ts} +0 -0
  81. /package/dist/{middleware.js → workspace/modules/repository/middleware.js} +0 -0
  82. /package/src/{store.ts → workspace/infrastructure/store.ts} +0 -0
package/README.md CHANGED
@@ -1,87 +1,166 @@
1
- # 🔄 Repository Manager
1
+ # 🔄 Repository Manager v3
2
2
 
3
- A lightweight, type-safe repository manager with dependency injection, lifecycle management, and multi-workspace support for TypeScript/JavaScript applications.
3
+ A lightweight, type-safe repository manager with dependency injection, scope management, lifecycle management, and multi-workspace support for TypeScript/JavaScript applications.
4
4
 
5
- ## Features
5
+ ## Features
6
6
 
7
7
  - ✅ **Dependency Injection** - Inject infrastructure dependencies into repositories
8
+ - ✅ **Scope Management** - Runtime scoped state management
8
9
  - ✅ **Lifecycle Management** - Automatic connection/disconnection with reference counting
9
10
  - ✅ **Multi-Workspace Support** - Manage multiple isolated workspaces with different dependencies
10
11
  - ✅ **Type Safety** - Full TypeScript support with generics
11
12
  - ✅ **Lazy Initialization** - Repository instances are created only when needed
12
- - ✅ **Imperative API** - Define workspaces and repositories as needed
13
+ - ✅ **Workspace Pattern** - `createApp` pattern for clean API
13
14
  - ✅ **Logging** - Built-in logging with colored console output
14
15
  - ✅ **Memory Efficient** - Automatic cleanup when no connections remain
15
16
  - ✅ **Middleware Support** - Intercept and modify repository method calls
16
17
 
17
- ## Installation
18
+ ## 📦 Installation
18
19
 
19
20
  ```bash
20
21
  npm install @med1802/repository-manager
21
22
  ```
22
23
 
23
- ## Quick Start
24
+ ## 🚀 Quick Start
24
25
 
25
26
  ```typescript
26
27
  import { repositoryManager } from "@med1802/repository-manager";
27
28
 
28
- // Define your dependencies interface
29
- interface IDependencies {
30
- httpClient: {
31
- get(url: string): Promise<any>;
32
- post(url: string, data: any): Promise<any>;
33
- };
29
+ // Define your repository interface
30
+ interface IUserRepository {
31
+ getUsers(): Promise<User[]>;
32
+ createUser(user: User): Promise<User>;
34
33
  }
35
34
 
36
35
  // Create manager instance
37
36
  const manager = repositoryManager();
38
37
 
39
38
  // Define infrastructure dependencies
40
- const infrastructure: IDependencies = {
39
+ const infrastructure = {
41
40
  httpClient: {
42
- get: async (url) => fetch(url).then((r) => r.json()),
43
- post: async (url, data) =>
41
+ get: async (url: string) => fetch(url).then((r) => r.json()),
42
+ post: async (url: string, data: any) =>
44
43
  fetch(url, { method: "POST", body: JSON.stringify(data) }),
45
44
  },
46
45
  };
47
46
 
48
- // Create a workspace and define repositories
49
- const { defineRepository } = manager.workspace(infrastructure, {
50
- id: "app",
51
- logging: true,
52
- });
47
+ // Create workspace (entry point for all operations)
48
+ const { defineRepository, queryRepository, createScope } = manager.workspace(
49
+ infrastructure,
50
+ {
51
+ id: "app",
52
+ logging: true,
53
+ }
54
+ );
53
55
 
54
- // Define repositories
55
- defineRepository("userRepo", (infrastructure) => ({
56
- async getUsers() {
57
- return infrastructure.httpClient.get("/api/users");
56
+ // Define repository
57
+ defineRepository<IUserRepository>({
58
+ id: "user-repo",
59
+ install({ instance }) {
60
+ const { infrastructure } = instance;
61
+ return {
62
+ async getUsers() {
63
+ return infrastructure.httpClient.get("/api/users");
64
+ },
65
+ async createUser(user) {
66
+ return infrastructure.httpClient.post("/api/users", user);
67
+ },
68
+ };
58
69
  },
59
- async createUser(user: any) {
60
- return infrastructure.httpClient.post("/api/users", user);
70
+ onConnect: () => {
71
+ console.log("User repository initialized");
61
72
  },
62
- }));
63
-
64
- defineRepository("postRepo", (infrastructure) => ({
65
- async getPosts() {
66
- return infrastructure.httpClient.get("/api/posts");
73
+ onDisconnect: () => {
74
+ console.log("User repository cleaned up");
67
75
  },
68
- }));
76
+ });
69
77
 
70
- // Use repositories with path format: "workspaceId/repositoryId"
71
- const { repository: userRepo, disconnect } = manager.query("app/userRepo");
78
+ // Query and use repository
79
+ const { repository: userRepo, disconnect } =
80
+ queryRepository<IUserRepository>("user-repo");
72
81
  const users = await userRepo.getUsers();
73
82
 
74
83
  // Cleanup when done
75
84
  disconnect();
76
85
  ```
77
86
 
78
- ## API Reference
87
+ ## 📖 Core Concepts
88
+
89
+ ### 1. Manager → Workspace → Repository
90
+
91
+ Repository Manager follows a hierarchical pattern `createApp`:
92
+
93
+ ```typescript
94
+ const manager = repositoryManager(); // Global manager
95
+ const workspace = manager.workspace(infrastructure, config); // Workspace instance
96
+ workspace.defineRepository({...}); // Define repositories
97
+ workspace.queryRepository("repo-id"); // Query repositories
98
+ ```
99
+
100
+ ### 2. Workspace Pattern
101
+
102
+ Workspace is the **entry point** for all operations. It encapsulates:
103
+
104
+ - Infrastructure dependencies
105
+ - Repository definitions
106
+ - Scope management
107
+ - Logging configuration
108
+
109
+ ```typescript
110
+ const { defineRepository, queryRepository, createScope } = manager.workspace(
111
+ infrastructure,
112
+ {
113
+ id: "app-workspace",
114
+ logging: true,
115
+ }
116
+ );
117
+ ```
118
+
119
+ ### 3. Scope Management
120
+
121
+ Scopes provide **runtime scoped state management** :
122
+
123
+ ```typescript
124
+ // Create scope
125
+ const userScope = createScope({
126
+ userId: null,
127
+ permissions: [],
128
+ });
129
+
130
+ // Use in repository
131
+ defineRepository({
132
+ id: "auth-repo",
133
+ install({ instance }) {
134
+ const { useScope } = instance;
135
+ return {
136
+ checkPermission(action: string) {
137
+ const user = useScope(userScope);
138
+ return user.permissions.includes(action);
139
+ },
140
+ };
141
+ },
142
+ });
143
+
144
+ // Provide scope value
145
+ userScope.provider({
146
+ value: {
147
+ userId: "123",
148
+ permissions: ["read", "write"],
149
+ },
150
+ children() {
151
+ const { repository } = queryRepository("auth-repo");
152
+ repository.checkPermission("write"); // Has access to scoped value
153
+ },
154
+ });
155
+ ```
156
+
157
+ ## 📚 API Reference
79
158
 
80
159
  ### `repositoryManager()`
81
160
 
82
161
  Creates a repository manager instance.
83
162
 
84
- **Returns:** Manager object with `workspace` and `query` methods
163
+ **Returns:** Manager object with `workspace` method
85
164
 
86
165
  **Example:**
87
166
 
@@ -91,398 +170,402 @@ const manager = repositoryManager();
91
170
 
92
171
  ### `manager.workspace<I>(infrastructure, config)`
93
172
 
94
- Creates a workspace with infrastructure dependencies and returns a `defineRepository` function.
173
+ Creates a workspace with infrastructure dependencies.
95
174
 
96
175
  **Parameters:**
97
176
 
98
177
  - `infrastructure: I` - Infrastructure dependencies to inject into repositories
99
- - `config: IConfiguration` - Workspace configuration
178
+ - `config: IConfiguration`
100
179
  - `id: string` - Unique identifier for the workspace
101
180
  - `logging?: boolean` - Enable/disable logging (default: `false`)
102
181
 
103
- **Returns:** Object with `defineRepository` method
182
+ **Returns:** Object with workspace methods:
183
+
184
+ - `defineRepository` - Define repositories
185
+ - `queryRepository` - Query repositories
186
+ - `createScope` - Create scoped state
104
187
 
105
188
  **Example:**
106
189
 
107
190
  ```typescript
108
- const { defineRepository } = manager.workspace(infrastructure, {
109
- id: "app",
110
- logging: true,
111
- });
191
+ const { defineRepository, queryRepository, createScope } = manager.workspace(
192
+ infrastructure,
193
+ {
194
+ id: "app",
195
+ logging: true,
196
+ }
197
+ );
112
198
  ```
113
199
 
114
- ### `defineRepository(id, factory, config?)`
200
+ ### `defineRepository<R>(config)`
115
201
 
116
202
  Defines a repository within the workspace.
117
203
 
118
204
  **Parameters:**
119
205
 
120
- - `id: string` - Unique identifier for the repository
121
- - `factory: (infrastructure: I) => R` - Factory function that receives infrastructure and returns repository instance
122
- - `config?: IRepositoryConfig` - Optional repository configuration
123
- - `lifecycle?: ILifeCycle` - Lifecycle hooks
124
- - `onConnect?: () => void` - Called when repository is first connected (when connections go from 0 to 1)
125
- - `onDisconnect?: () => void` - Called when repository is last disconnected (when connections go from 1 to 0)
126
- - `middlewares?: Middleware[]` - Array of middleware functions to intercept method calls
206
+ - `config: IRepositoryPlugin<I, R>`
207
+ - `id: string` - Unique identifier for the repository
208
+ - `install: ({ instance }) => R` - Factory function that returns repository instance
209
+ - `instance.infrastructure` - Injected infrastructure
210
+ - `instance.useScope` - Function to access scoped state
211
+ - `onConnect?: () => void` - Called when repository is first connected
212
+ - `onDisconnect?: () => void` - Called when repository is last disconnected
213
+ - `middlewares?: Middleware[]` - Array of middleware functions
127
214
 
128
215
  **Example:**
129
216
 
130
217
  ```typescript
131
- defineRepository("userRepo", (infrastructure) => ({
132
- getUsers: () => infrastructure.httpClient.get("/users"),
133
- }));
134
-
135
- // With lifecycle hooks
136
- defineRepository(
137
- "userRepo",
138
- (infrastructure) => ({
139
- getUsers: () => infrastructure.httpClient.get("/users"),
140
- }),
141
- {
142
- lifecycle: {
143
- onConnect: () => {
144
- console.log("User repository initialized");
145
- },
146
- onDisconnect: () => {
147
- console.log("User repository cleaned up");
218
+ defineRepository<IUserRepository>({
219
+ id: "user-repo",
220
+ install({ instance }) {
221
+ const { infrastructure, useScope } = instance;
222
+ return {
223
+ getUsers() {
224
+ return infrastructure.httpClient.get("/users");
148
225
  },
149
- },
150
- }
151
- );
226
+ };
227
+ },
228
+ onConnect: () => console.log("Connected"),
229
+ onDisconnect: () => console.log("Disconnected"),
230
+ });
152
231
  ```
153
232
 
154
- ### `manager.query<R>(path)`
233
+ ### `queryRepository<R>(id)`
155
234
 
156
- Queries a repository from a workspace using path format: `"workspaceId/repositoryId"`.
235
+ Queries a repository from the workspace.
157
236
 
158
237
  **Parameters:**
159
238
 
160
- - `path: string` - Path to repository in format `"workspaceId/repositoryId"`
239
+ - `id: string` - Repository identifier
161
240
 
162
241
  **Returns:** Object with:
163
242
 
164
243
  - `repository: R` - The repository instance
165
244
  - `disconnect: () => void` - Function to disconnect and cleanup
166
245
 
167
- **Throws:** `Error` if workspace or repository is not found
246
+ **Throws:** `Error` if repository is not found
168
247
 
169
248
  **Example:**
170
249
 
171
250
  ```typescript
172
- const { repository, disconnect } = manager.query<IUserRepo>("app/userRepo");
251
+ const { repository, disconnect } =
252
+ queryRepository<IUserRepository>("user-repo");
173
253
  await repository.getUsers();
174
254
  disconnect();
175
255
  ```
176
256
 
177
- ## Advanced Usage
257
+ ### `createScope<V>(defaultValue)`
178
258
 
179
- ### Multiple Workspaces
259
+ Creates a scope for runtime state management.
180
260
 
181
- You can create multiple isolated workspaces with different dependencies:
261
+ **Parameters:**
182
262
 
183
- ```typescript
184
- const manager = repositoryManager();
263
+ - `defaultValue: V` - Default value for the scope
185
264
 
186
- // API workspace
187
- const { defineRepository: defineApiRepo } = manager.workspace(
188
- {
189
- httpClient: apiHttpClient,
190
- cache: redisCache,
191
- },
192
- {
193
- id: "api",
194
- logging: true,
195
- }
196
- );
265
+ **Returns:** Scope object with:
197
266
 
198
- defineApiRepo("userRepo", (infrastructure) => ({
199
- getUsers: () => infrastructure.httpClient.get("/users"),
200
- }));
267
+ - `provider: (options) => void` - Provide scoped value
268
+ - `currentValue: V` - Current scoped value (getter)
201
269
 
202
- // Database workspace
203
- const { defineRepository: defineDbRepo } = manager.workspace(
204
- {
205
- db: postgresClient,
206
- logger: winstonLogger,
207
- },
208
- {
209
- id: "database",
210
- logging: false,
211
- }
212
- );
270
+ **Example:**
213
271
 
214
- defineDbRepo("orderRepo", (infrastructure) => ({
215
- getOrders: () => infrastructure.db.query("SELECT * FROM orders"),
216
- }));
272
+ ```typescript
273
+ const userScope = createScope({
274
+ userId: null,
275
+ role: "guest",
276
+ });
217
277
 
218
- // Access repositories from different workspaces
219
- const { repository: userRepo } = manager.query("api/userRepo");
220
- const { repository: orderRepo } = manager.query("database/orderRepo");
278
+ // Provide value
279
+ userScope.provider({
280
+ value: { userId: "123", role: "admin" },
281
+ children() {
282
+ // Code that runs with scoped value
283
+ },
284
+ });
221
285
  ```
222
286
 
223
- ### TypeScript Interfaces
287
+ ### `useScope<V>(scope)`
224
288
 
225
- Define clear interfaces for better type safety:
289
+ Access scoped state within repository methods.
226
290
 
227
- ```typescript
228
- interface IUserRepo {
229
- getUsers(): Promise<User[]>;
230
- createUser(user: User): Promise<User>;
231
- updateUser(id: string, user: Partial<User>): Promise<User>;
232
- deleteUser(id: string): Promise<void>;
233
- }
291
+ **Parameters:**
234
292
 
235
- interface IDependencies {
236
- httpClient: IHttpClient;
237
- cache: ICache;
238
- }
293
+ - `scope: IScope<V>` - Scope to access
239
294
 
240
- const manager = repositoryManager();
295
+ **Returns:** Current scoped value
241
296
 
242
- const { defineRepository } = manager.workspace<IDependencies>(
243
- {
244
- httpClient: myHttpClient,
245
- cache: myCache,
246
- },
247
- {
248
- id: "app",
249
- }
250
- );
251
-
252
- defineRepository<IUserRepo>(
253
- "userRepo",
254
- (infrastructure): IUserRepo => ({
255
- async getUsers() {
256
- /* ... */
257
- },
258
- async createUser(user) {
259
- /* ... */
260
- },
261
- async updateUser(id, user) {
262
- /* ... */
263
- },
264
- async deleteUser(id) {
265
- /* ... */
266
- },
267
- })
268
- );
297
+ **Example:**
269
298
 
270
- // TypeScript knows the exact return type
271
- const { repository } = manager.query<IUserRepo>("app/userRepo");
272
- // repository has all IUserRepo methods with correct types
299
+ ```typescript
300
+ defineRepository({
301
+ id: "auth-repo",
302
+ install({ instance }) {
303
+ const { useScope } = instance;
304
+ return {
305
+ getCurrentUser() {
306
+ return useScope(userScope);
307
+ },
308
+ };
309
+ },
310
+ });
273
311
  ```
274
312
 
275
- ### Lifecycle Management with Reference Counting
276
-
277
- Repositories use reference counting for automatic lifecycle management:
313
+ ## 🎯 Advanced Usage
278
314
 
279
- ```typescript
280
- // First query creates the repository instance
281
- const conn1 = manager.query("app/userRepo"); // Connections: 1
282
- const conn2 = manager.query("app/userRepo"); // Connections: 2 (reuses instance)
283
- const conn3 = manager.query("app/userRepo"); // Connections: 3 (reuses instance)
315
+ ### Multiple Scopes
284
316
 
285
- conn1.disconnect(); // Connections: 2 (still active)
286
- conn2.disconnect(); // Connections: 1 (still active)
287
- conn3.disconnect(); // Connections: 0 (instance destroyed)
317
+ You can create and use multiple scopes:
288
318
 
289
- // Next query will create a new instance
290
- const conn4 = manager.query("app/userRepo"); // Connections: 1 (new instance)
319
+ ```typescript
320
+ const userScope = createScope({ userId: null });
321
+ const companyScope = createScope({ companyId: null });
322
+ const featureFlagsScope = createScope({ features: [] });
323
+
324
+ defineRepository({
325
+ id: "billing-repo",
326
+ install({ instance }) {
327
+ const { useScope } = instance;
328
+ return {
329
+ getBillingInfo() {
330
+ const user = useScope(userScope);
331
+ const company = useScope(companyScope);
332
+ const flags = useScope(featureFlagsScope);
333
+
334
+ // Use all scopes
335
+ return { user, company, flags };
336
+ },
337
+ };
338
+ },
339
+ });
291
340
  ```
292
341
 
293
- ### Lifecycle Hooks
342
+ ### Nested Scopes
294
343
 
295
- You can define lifecycle hooks that are called at specific points in the repository lifecycle:
344
+ Scopes can be nested and override outer values:
345
+
346
+ ```typescript
347
+ userScope.provider({
348
+ value: { userId: "outer" },
349
+ children() {
350
+ // Inner scope overrides outer
351
+ userScope.provider({
352
+ value: { userId: "inner" },
353
+ children() {
354
+ const { repository } = queryRepository("user-repo");
355
+ // useScope(userScope) returns "inner"
356
+ },
357
+ });
358
+ },
359
+ });
360
+ ```
296
361
 
297
- - **`onConnect`** - Called only when the repository is first connected (when connections go from 0 to 1)
298
- - **`onDisconnect`** - Called only when the repository is last disconnected (when connections go from 1 to 0)
362
+ ### Multiple Workspaces
299
363
 
300
- **Example:**
364
+ Create multiple isolated workspaces with different dependencies:
301
365
 
302
366
  ```typescript
303
- defineRepository(
304
- "userRepo",
305
- (infrastructure) => ({
306
- getUsers: () => infrastructure.httpClient.get("/api/users"),
307
- }),
367
+ // API workspace
368
+ const apiWorkspace = manager.workspace(
308
369
  {
309
- lifecycle: {
310
- onConnect: () => {
311
- console.log("User repository initialized");
312
- // Perform initialization tasks (e.g., setup cache, establish connection)
313
- },
314
- onDisconnect: () => {
315
- console.log("User repository cleaned up");
316
- // Perform cleanup tasks (e.g., clear cache, close connections)
317
- },
318
- },
319
- }
370
+ httpClient: apiClient,
371
+ cache: redisCache,
372
+ },
373
+ { id: "api" }
320
374
  );
321
375
 
322
- // Usage
323
- const conn1 = manager.query("app/userRepo"); // onConnect called (first connection)
324
- const conn2 = manager.query("app/userRepo"); // onConnect NOT called (reusing instance)
376
+ // Database workspace
377
+ const dbWorkspace = manager.workspace(
378
+ {
379
+ db: postgresClient,
380
+ logger: winstonLogger,
381
+ },
382
+ { id: "database" }
383
+ );
325
384
 
326
- conn1.disconnect(); // onDisconnect NOT called (still has connections)
327
- conn2.disconnect(); // onDisconnect called (last connection removed)
385
+ // Each workspace has isolated repositories
386
+ apiWorkspace.defineRepository({...});
387
+ dbWorkspace.defineRepository({...});
328
388
  ```
329
389
 
330
- **Use Cases:**
390
+ ### TypeScript Best Practices
331
391
 
332
- - **Initialization**: Setup cache, establish database connections, initialize state
333
- - **Cleanup**: Clear cache, close connections, release resources
334
- - **Analytics**: Track repository usage and lifecycle events
335
- - **Debugging**: Monitor when repositories are created and destroyed
392
+ Define clear interfaces for type safety:
336
393
 
337
- ### Middleware
394
+ ```typescript
395
+ // Infrastructure interface
396
+ interface IInfrastructure {
397
+ httpClient: IHttpClient;
398
+ cache: ICache;
399
+ logger: ILogger;
400
+ }
338
401
 
339
- Middleware allows you to intercept and modify repository method calls before and after execution. Middleware functions are executed in sequence, allowing you to add cross-cutting concerns like logging, caching, validation, and more.
402
+ // Repository interface
403
+ interface IUserRepository {
404
+ getUsers(): Promise<User[]>;
405
+ createUser(user: User): Promise<User>;
406
+ }
340
407
 
341
- **Middleware Signature:**
408
+ // Workspace with typed infrastructure
409
+ const { defineRepository, queryRepository } =
410
+ manager.workspace<IInfrastructure>(infrastructure, { id: "app" });
411
+
412
+ // Repository with typed interface
413
+ defineRepository<IUserRepository>({
414
+ id: "user-repo",
415
+ install({ instance }) {
416
+ const { infrastructure } = instance;
417
+ return {
418
+ async getUsers() {
419
+ // TypeScript knows infrastructure type
420
+ return infrastructure.httpClient.get("/users");
421
+ },
422
+ async createUser(user) {
423
+ // TypeScript validates User type
424
+ return infrastructure.httpClient.post("/users", user);
425
+ },
426
+ };
427
+ },
428
+ });
342
429
 
343
- ```typescript
344
- type Middleware = (
345
- method: string,
346
- args: any[],
347
- next: (...nextArgs: any[]) => any
348
- ) => any;
430
+ // Query with typed repository
431
+ const { repository } = queryRepository<IUserRepository>("user-repo");
432
+ // TypeScript knows all repository methods
349
433
  ```
350
434
 
351
- **Parameters:**
352
-
353
- - `method: string` - The name of the method being called
354
- - `args: any[]` - The arguments passed to the method
355
- - `next: (...nextArgs: any[]) => any` - Function to call the next middleware or the original method
435
+ ### Lifecycle Management
356
436
 
357
- **Example:**
437
+ Repositories use reference counting for automatic lifecycle:
358
438
 
359
439
  ```typescript
360
- // Define middleware functions
361
- const loggingMiddleware: Middleware = (method, args, next) => {
362
- console.log(`[${new Date().toISOString()}] Calling ${method}`, args);
363
- const result = next();
364
- console.log(`[${new Date().toISOString()}] ${method} returned:`, result);
365
- return result;
366
- };
440
+ // First query creates instance (onConnect called)
441
+ const conn1 = queryRepository("user-repo"); // Connections: 1
367
442
 
368
- const performanceMiddleware: Middleware = (method, args, next) => {
369
- const start = performance.now();
370
- const result = next();
371
- const duration = performance.now() - start;
443
+ // Subsequent queries reuse instance (onConnect NOT called)
444
+ const conn2 = queryRepository("user-repo"); // Connections: 2
445
+ const conn3 = queryRepository("user-repo"); // Connections: 3
372
446
 
373
- if (duration > 1000) {
374
- console.warn(`Slow call: ${method} took ${duration}ms`);
375
- }
376
-
377
- return result;
378
- };
447
+ // Disconnect reduces count
448
+ conn1.disconnect(); // Connections: 2
449
+ conn2.disconnect(); // Connections: 1
379
450
 
380
- // Apply middleware to repository
381
- defineRepository(
382
- "userRepo",
383
- (infrastructure) => ({
384
- getUsers: () => infrastructure.httpClient.get("/api/users"),
385
- createUser: (user) => infrastructure.httpClient.post("/api/users", user),
386
- }),
387
- {
388
- middlewares: [loggingMiddleware, performanceMiddleware],
389
- }
390
- );
391
-
392
- // When you call repository methods, middleware intercepts them
393
- const { repository } = manager.query("app/userRepo");
394
- await repository.getUsers(); // Middleware logs and measures performance
451
+ // Last disconnect destroys instance (onDisconnect called)
452
+ conn3.disconnect(); // Connections: 0, instance destroyed
395
453
  ```
396
454
 
397
- **Middleware Execution Flow:**
398
-
399
- ```typescript
400
- // When you call: repository.getUsers("filter")
401
- // 1. loggingMiddleware - logs "Calling getUsers"
402
- // 2. performanceMiddleware - starts timer
403
- // 3. repository.getUsers("filter") - original method executes
404
- // 4. performanceMiddleware - ends timer, logs if slow
405
- // 5. loggingMiddleware - logs result
406
- // 6. Returns result to caller
407
- ```
408
-
409
- **Common Use Cases:**
410
-
411
- - **Logging**: Log all method calls and their results
412
- - **Performance Monitoring**: Measure execution time and warn about slow calls
413
- - **Caching**: Cache method results to avoid redundant calls
414
- - **Validation**: Validate arguments before method execution
415
- - **Error Handling**: Centralized error handling and retry logic
416
- - **Data Transformation**: Transform arguments or results
417
- - **Authentication**: Check permissions before method execution
418
- - **Rate Limiting**: Limit the number of calls per method
455
+ ### Middleware
419
456
 
420
- **Example: Caching Middleware**
457
+ Intercept and modify repository method calls:
421
458
 
422
459
  ```typescript
423
- const cache = new Map<string, any>();
460
+ const loggingMiddleware: Middleware = (method, args, next) => {
461
+ console.log(`Calling ${method}`, args);
462
+ const result = next();
463
+ console.log(`${method} returned:`, result);
464
+ return result;
465
+ };
424
466
 
425
467
  const cacheMiddleware: Middleware = (method, args, next) => {
426
468
  const cacheKey = `${method}-${JSON.stringify(args)}`;
469
+ if (cache.has(cacheKey)) return cache.get(cacheKey);
427
470
 
428
- if (cache.has(cacheKey)) {
429
- return cache.get(cacheKey); // Return cached result, skip method execution
430
- }
431
-
432
- const result = next(); // Execute method
433
- cache.set(cacheKey, result); // Cache result
471
+ const result = next();
472
+ cache.set(cacheKey, result);
434
473
  return result;
435
474
  };
436
475
 
437
- defineRepository(
438
- "userRepo",
439
- (infrastructure) => ({
440
- getUsers: () => infrastructure.httpClient.get("/api/users"),
441
- }),
442
- {
443
- middlewares: [cacheMiddleware],
444
- }
445
- );
476
+ defineRepository({
477
+ id: "user-repo",
478
+ install({ instance }) {
479
+ return {
480
+ getUsers: () => instance.infrastructure.httpClient.get("/users"),
481
+ };
482
+ },
483
+ middlewares: [loggingMiddleware, cacheMiddleware],
484
+ });
446
485
  ```
447
486
 
448
- **Example: Validation Middleware**
487
+ **Common Middleware Use Cases:**
449
488
 
450
- ```typescript
451
- const validationMiddleware: Middleware = (method, args, next) => {
452
- if (method === "createUser" && (!args[0] || typeof args[0] !== "object")) {
453
- throw new Error("Invalid user data");
454
- }
455
- return next();
456
- };
489
+ - **Logging** - Log all method calls and results
490
+ - **Caching** - Cache method results
491
+ - **Validation** - Validate arguments before execution
492
+ - **Performance Monitoring** - Measure execution time
493
+ - **Error Handling** - Centralized error handling and retry logic
494
+ - **Authentication** - Check permissions before execution
457
495
 
458
- defineRepository(
459
- "userRepo",
460
- (infrastructure) => ({
461
- createUser: (user) => infrastructure.httpClient.post("/api/users", user),
462
- }),
463
- {
464
- middlewares: [validationMiddleware],
465
- }
466
- );
467
- ```
468
-
469
- ### Using with React
496
+ ### Real-World Example: User Management
470
497
 
471
498
  ```typescript
472
- import { useEffect } from "react";
499
+ // Define scopes
500
+ const authScope = createScope({ token: null, user: null });
501
+ const featureFlagsScope = createScope({ features: [] });
473
502
 
474
- function UserList() {
475
- useEffect(() => {
476
- const { repository, disconnect } = manager.query<IUserRepo>("app/userRepo");
503
+ // Infrastructure
504
+ const infrastructure = {
505
+ httpClient: {
506
+ get: async (url) =>
507
+ fetch(url, {
508
+ headers: { Authorization: `Bearer ${useScope(authScope).token}` },
509
+ }).then((r) => r.json()),
510
+ post: async (url, data) =>
511
+ fetch(url, {
512
+ method: "POST",
513
+ headers: { Authorization: `Bearer ${useScope(authScope).token}` },
514
+ body: JSON.stringify(data),
515
+ }).then((r) => r.json()),
516
+ },
517
+ cache: new Map(),
518
+ };
477
519
 
478
- repository.getUsers().then(setUsers);
520
+ // Create workspace
521
+ const { defineRepository, queryRepository } = manager.workspace(
522
+ infrastructure,
523
+ { id: "app", logging: true }
524
+ );
479
525
 
480
- // Cleanup on unmount
481
- return disconnect;
482
- }, []);
526
+ // Define repositories
527
+ defineRepository<IUserRepository>({
528
+ id: "user-repo",
529
+ install({ instance }) {
530
+ const { infrastructure, useScope } = instance;
531
+ return {
532
+ async getUsers() {
533
+ const auth = useScope(authScope);
534
+ if (!auth.token) throw new Error("Not authenticated");
535
+ return infrastructure.httpClient.get("/api/users");
536
+ },
537
+ async createUser(user) {
538
+ const flags = useScope(featureFlagsScope);
539
+ if (!flags.features.includes("create-user")) {
540
+ throw new Error("Feature not enabled");
541
+ }
542
+ return infrastructure.httpClient.post("/api/users", user);
543
+ },
544
+ };
545
+ },
546
+ onConnect: () => console.log("User repo connected"),
547
+ onDisconnect: () => console.log("User repo disconnected"),
548
+ });
483
549
 
484
- return <div>{/* ... */}</div>;
485
- }
550
+ // Use with authentication
551
+ authScope.provider({
552
+ value: { token: "abc123", user: { id: "1", name: "John" } },
553
+ children() {
554
+ featureFlagsScope.provider({
555
+ value: { features: ["create-user", "delete-user"] },
556
+ async children() {
557
+ const { repository, disconnect } =
558
+ queryRepository<IUserRepository>("user-repo");
559
+
560
+ // Has access to auth and feature flags
561
+ const users = await repository.getUsers();
562
+ await repository.createUser({ name: "Jane" });
563
+
564
+ disconnect();
565
+ },
566
+ });
567
+ },
568
+ });
486
569
  ```
487
570
 
488
571
  ### Logging
@@ -490,73 +573,28 @@ function UserList() {
490
573
  Enable logging to see connection lifecycle:
491
574
 
492
575
  ```typescript
493
- const manager = repositoryManager();
494
-
495
576
  const { defineRepository } = manager.workspace(infrastructure, {
496
577
  id: "app",
497
578
  logging: true, // Enables colored console output
498
579
  });
499
580
 
500
581
  // Console output will show:
501
- // repository.connect (app/userRepo)
502
- // ┌─────────┬──────────┬─────────────┐
503
- // │ (index) │ id │ connections
504
- // ├─────────┼──────────┼─────────────┤
505
- // │ 0 │ userRepo 1 │
506
- // └─────────┴──────────┴─────────────┘
582
+ // repository.define (user-repo)
583
+ // ┌─────────┬───────────┐
584
+ // │ (index) │repository
585
+ // ├─────────┼───────────┤
586
+ // │ 0 │ user-repo
587
+ // └─────────┴───────────┘
588
+ //
589
+ // repository.connect (user-repo)
590
+ // ┌─────────┬───────────┬─────────────┐
591
+ // │ (index) │repository │ connections │
592
+ // ├─────────┼───────────┼─────────────┤
593
+ // │ 0 │ user-repo │ 1 │
594
+ // └─────────┴───────────┴─────────────┘
507
595
  ```
508
596
 
509
- ## Dependency Injection Pattern
510
-
511
- This package follows the **Dependency Inversion Principle (DIP)**:
512
-
513
- - **High-level modules** (repositories) depend on abstractions (dependencies interface)
514
- - **Low-level modules** (infrastructure implementations) are injected
515
- - Easy to test with mock dependencies
516
- - Easy to swap implementations
517
-
518
- ```typescript
519
- // Define abstractions
520
- interface IDatabase {
521
- query(sql: string): Promise<any>;
522
- }
523
-
524
- interface ICache {
525
- get(key: string): Promise<any>;
526
- set(key: string, value: any): Promise<void>;
527
- }
528
-
529
- interface IDependencies {
530
- database: IDatabase;
531
- cache: ICache;
532
- }
533
-
534
- // Inject concrete implementations
535
- const manager = repositoryManager();
536
-
537
- const { defineRepository } = manager.workspace<IDependencies>(
538
- {
539
- database: new PostgreSQLClient(),
540
- cache: new RedisCache(),
541
- },
542
- {
543
- id: "prod",
544
- }
545
- );
546
-
547
- // Easy to test with mocks
548
- const { defineRepository: defineTestRepo } = manager.workspace<IDependencies>(
549
- {
550
- database: new MockDatabase(),
551
- cache: new MockCache(),
552
- },
553
- {
554
- id: "test",
555
- }
556
- );
557
- ```
558
-
559
- ## Design Patterns
597
+ ## 🏗️ Design Patterns
560
598
 
561
599
  This library implements several design patterns:
562
600
 
@@ -564,20 +602,31 @@ This library implements several design patterns:
564
602
  - **Factory Pattern** - Repositories are created using factory functions
565
603
  - **Singleton Pattern** - Each repository is a singleton per workspace (with reference counting)
566
604
  - **Repository Pattern** - Abstracts data access logic
567
- - **Workspace Pattern** - Manages dependencies and lifecycle
605
+ - **Workspace Pattern** - Vue-like pattern for managing dependencies and lifecycle
606
+ - **Provider Pattern** - Scope management similar to React Context
568
607
 
569
- ## Error Handling
608
+ ## ⚠️ Error Handling
570
609
 
571
610
  ```typescript
572
611
  try {
573
- const { repository } = manager.query("non-existent/repo");
612
+ const { repository } = queryRepository("non-existent-repo");
574
613
  } catch (error) {
575
- console.error(error.message); // Container "non-existent" not found
614
+ console.error(error.message); // Repository "non-existent-repo" not found
576
615
  }
577
616
 
617
+ // With scope
578
618
  try {
579
- const { repository } = manager.query("app/non-existent");
619
+ const user = useScope(userScope);
620
+ if (!user) throw new Error("No user in scope");
580
621
  } catch (error) {
581
- console.error(error.message); // Repository "non-existent" not found
622
+ console.error("Scope error:", error);
582
623
  }
583
624
  ```
625
+
626
+ ## 📝 License
627
+
628
+ MIT
629
+
630
+ ## 🤝 Contributing
631
+
632
+ Contributions are welcome! Please feel free to submit a Pull Request.