@med1802/repository-manager 1.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.
- package/README.md +176 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +68 -0
- package/dist/logger.d.ts +10 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +26 -0
- package/dist/repositoryInstance.d.ts +8 -0
- package/dist/repositoryInstance.d.ts.map +1 -0
- package/dist/repositoryInstance.js +27 -0
- package/dist/store.d.ts +10 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +21 -0
- package/dist/types.d.ts +10 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/package.json +15 -0
- package/src/index.ts +85 -0
- package/src/logger.ts +46 -0
- package/src/repositoryInstance.ts +30 -0
- package/src/store.ts +22 -0
- package/src/types.ts +10 -0
- package/tsconfig.json +9 -0
- package/tsconfig.tsbuildinfo +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# 🔄 Repository Manager
|
|
2
|
+
|
|
3
|
+
A lightweight, type-safe repository manager with dependency injection and lifecycle management for TypeScript/JavaScript applications.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ✅ **Dependency Injection** - Inject infrastructure dependencies into repositories
|
|
8
|
+
- ✅ **Lifecycle Management** - Automatic connection/disconnection with reference counting
|
|
9
|
+
- ✅ **Type Safety** - Full TypeScript support with generics
|
|
10
|
+
- ✅ **Lazy Initialization** - Repository instances are created only when needed
|
|
11
|
+
- ✅ **Logging** - Built-in logging with colored console output
|
|
12
|
+
- ✅ **Memory Efficient** - Automatic cleanup when no connections remain
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @med1802/repository-manager
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { repositoryManager } from "@med1802/repository-manager";
|
|
24
|
+
|
|
25
|
+
// Define your infrastructure
|
|
26
|
+
interface IInfrastructure {
|
|
27
|
+
httpClient: {
|
|
28
|
+
get(url: string): Promise<any>;
|
|
29
|
+
post(url: string, data: any): Promise<any>;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Create container with infrastructure
|
|
34
|
+
const manager = repositoryManager();
|
|
35
|
+
const app = manager.createContainer<IInfrastructure>({
|
|
36
|
+
httpClient: {
|
|
37
|
+
get: async (url) => fetch(url).then((r) => r.json()),
|
|
38
|
+
post: async (url, data) =>
|
|
39
|
+
fetch(url, { method: "POST", body: JSON.stringify(data) }),
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Define repository
|
|
44
|
+
app.defineRepository("user-repo", (infrastructure) => {
|
|
45
|
+
return {
|
|
46
|
+
async getUsers() {
|
|
47
|
+
return infrastructure.httpClient.get("/api/users");
|
|
48
|
+
},
|
|
49
|
+
async createUser(user: any) {
|
|
50
|
+
return infrastructure.httpClient.post("/api/users", user);
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Use repository
|
|
56
|
+
const { repository, disconnect } = app.queryRepository("user-repo");
|
|
57
|
+
const users = await repository.getUsers();
|
|
58
|
+
|
|
59
|
+
// Cleanup when done
|
|
60
|
+
disconnect();
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## API
|
|
64
|
+
|
|
65
|
+
### `repositoryManager()`
|
|
66
|
+
|
|
67
|
+
Creates a new repository manager instance.
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
const manager = repositoryManager();
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### `createContainer<I>(infrastructure: I, config?: IConfiguration)`
|
|
74
|
+
|
|
75
|
+
Creates a container with infrastructure dependencies.
|
|
76
|
+
|
|
77
|
+
**Parameters:**
|
|
78
|
+
|
|
79
|
+
- `infrastructure` - Object containing all infrastructure dependencies
|
|
80
|
+
- `config` - Optional configuration object
|
|
81
|
+
- `logging?: boolean` - Enable/disable logging (default: `false`)
|
|
82
|
+
|
|
83
|
+
**Returns:** Container object with `defineRepository` and `queryRepository` methods.
|
|
84
|
+
|
|
85
|
+
### `defineRepository(id: string, definition: (infrastructure: I) => T)`
|
|
86
|
+
|
|
87
|
+
Defines a repository with a unique ID.
|
|
88
|
+
|
|
89
|
+
**Parameters:**
|
|
90
|
+
|
|
91
|
+
- `id` - Unique identifier for the repository
|
|
92
|
+
- `definition` - Function that receives infrastructure and returns repository object
|
|
93
|
+
|
|
94
|
+
### `queryRepository<T>(id: string)`
|
|
95
|
+
|
|
96
|
+
Queries a repository by ID and returns it with disconnect method.
|
|
97
|
+
|
|
98
|
+
**Parameters:**
|
|
99
|
+
|
|
100
|
+
- `id` - Repository identifier
|
|
101
|
+
|
|
102
|
+
**Returns:** Object with:
|
|
103
|
+
|
|
104
|
+
- `repository: T` - The repository instance
|
|
105
|
+
- `disconnect: () => void` - Method to disconnect and cleanup
|
|
106
|
+
|
|
107
|
+
## Advanced Usage
|
|
108
|
+
|
|
109
|
+
### With Configuration
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
const app = manager.createContainer(infrastructure, {
|
|
113
|
+
logging: true, // Enable colored console logging
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Multiple Repositories
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
app.defineRepository("user-repo", (infrastructure) => ({
|
|
121
|
+
getUsers: () => infrastructure.httpClient.get("/users"),
|
|
122
|
+
}));
|
|
123
|
+
|
|
124
|
+
app.defineRepository("post-repo", (infrastructure) => ({
|
|
125
|
+
getPosts: () => infrastructure.httpClient.get("/posts"),
|
|
126
|
+
}));
|
|
127
|
+
|
|
128
|
+
const userRepo = app.queryRepository("user-repo");
|
|
129
|
+
const postRepo = app.queryRepository("post-repo");
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Lifecycle Management
|
|
133
|
+
|
|
134
|
+
Repositories use reference counting. The instance is created on first `queryRepository` call and destroyed when all connections are disconnected.
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
const repo1 = app.queryRepository("user-repo"); // Creates instance
|
|
138
|
+
const repo2 = app.queryRepository("user-repo"); // Reuses instance
|
|
139
|
+
const repo3 = app.queryRepository("user-repo"); // Reuses instance
|
|
140
|
+
|
|
141
|
+
repo1.disconnect(); // Still active (2 connections remain)
|
|
142
|
+
repo2.disconnect(); // Still active (1 connection remains)
|
|
143
|
+
repo3.disconnect(); // Instance destroyed
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Dependency Injection Pattern
|
|
147
|
+
|
|
148
|
+
This package follows the Dependency Inversion Principle (DIP):
|
|
149
|
+
|
|
150
|
+
- **High-level modules** (repositories) depend on abstractions (infrastructure interface)
|
|
151
|
+
- **Low-level modules** (infrastructure implementations) are injected
|
|
152
|
+
- Easy to test with mock infrastructure
|
|
153
|
+
- Easy to swap implementations
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
// Define infrastructure interface
|
|
157
|
+
interface IInfrastructure {
|
|
158
|
+
database: IDatabase;
|
|
159
|
+
cache: ICache;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Inject concrete implementations
|
|
163
|
+
const app = manager.createContainer<IInfrastructure>({
|
|
164
|
+
database: new PostgreSQL(),
|
|
165
|
+
cache: new RedisCache(),
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// Repository depends only on interface
|
|
169
|
+
app.defineRepository("user-repo", (infrastructure) => ({
|
|
170
|
+
// Uses infrastructure.database and infrastructure.cache
|
|
171
|
+
}));
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## License
|
|
175
|
+
|
|
176
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { IConfiguration } from "./types";
|
|
2
|
+
declare const repositoryManager: () => {
|
|
3
|
+
createContainer<I extends Record<string, any>>(infrastructure: I, config?: IConfiguration): {
|
|
4
|
+
defineRepository(id: string, repositoryDefinition: (infrastructure: I) => void): void;
|
|
5
|
+
queryRepository<R = any>(id: string): {
|
|
6
|
+
repository: R;
|
|
7
|
+
disconnect: () => void;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
export { repositoryManager };
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC9C,QAAA,MAAM,iBAAiB;oBAEH,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,kBAC3B,CAAC,WACR,cAAc;6BAmBf,MAAM,wBACY,CAAC,cAAc,EAAE,CAAC,KAAK,IAAI;wBAuBnC,CAAC,YAAY,MAAM;wBAeU,CAAC;;;;CAgBrD,CAAC;AAEF,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { createRepositoryInstance } from "./repositoryInstance";
|
|
2
|
+
import { createStore } from "./store";
|
|
3
|
+
import { createLogger } from "./logger";
|
|
4
|
+
const repositoryManager = () => {
|
|
5
|
+
return {
|
|
6
|
+
createContainer(infrastructure, config) {
|
|
7
|
+
const defaultConfig = {
|
|
8
|
+
logging: false,
|
|
9
|
+
...config,
|
|
10
|
+
};
|
|
11
|
+
const store = createStore();
|
|
12
|
+
const logger = createLogger(defaultConfig);
|
|
13
|
+
const getRepository = (id) => store.getRepository(id);
|
|
14
|
+
const hasRepository = (id) => store.hasRepository(id);
|
|
15
|
+
const allRepositories = () => Array.from(store.entries()).map(([id, repository]) => ({
|
|
16
|
+
repository: id,
|
|
17
|
+
connections: repository.getConnections(),
|
|
18
|
+
}));
|
|
19
|
+
return {
|
|
20
|
+
defineRepository(id, repositoryDefinition) {
|
|
21
|
+
if (hasRepository(id))
|
|
22
|
+
return;
|
|
23
|
+
logger.log(() => {
|
|
24
|
+
store.setRepository(id, createRepositoryInstance(repositoryDefinition, infrastructure));
|
|
25
|
+
}, {
|
|
26
|
+
type: "repository.define",
|
|
27
|
+
scope: id,
|
|
28
|
+
metadata: () => {
|
|
29
|
+
return {
|
|
30
|
+
repositories: allRepositories().map(({ repository }) => ({
|
|
31
|
+
repository,
|
|
32
|
+
})),
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
},
|
|
37
|
+
queryRepository(id) {
|
|
38
|
+
const repository = getRepository(id);
|
|
39
|
+
if (!repository) {
|
|
40
|
+
throw new Error(`Repository "${id}" not found`);
|
|
41
|
+
}
|
|
42
|
+
logger.log(() => repository.connect(), {
|
|
43
|
+
type: "repository.connect",
|
|
44
|
+
scope: id,
|
|
45
|
+
metadata: () => {
|
|
46
|
+
return {
|
|
47
|
+
connections: allRepositories(),
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
return {
|
|
52
|
+
repository: repository.getReference(),
|
|
53
|
+
disconnect: () => logger.log(() => repository.disconnect(), {
|
|
54
|
+
type: "repository.disconnect",
|
|
55
|
+
scope: id,
|
|
56
|
+
metadata: () => {
|
|
57
|
+
return {
|
|
58
|
+
connections: allRepositories(),
|
|
59
|
+
};
|
|
60
|
+
},
|
|
61
|
+
}),
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
export { repositoryManager };
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { IConfiguration } from "./types";
|
|
2
|
+
declare const createLogger: (config: IConfiguration) => {
|
|
3
|
+
log: (callback: () => void, { type, scope, metadata, }: {
|
|
4
|
+
type: string;
|
|
5
|
+
scope: string;
|
|
6
|
+
metadata: () => any;
|
|
7
|
+
}) => void;
|
|
8
|
+
};
|
|
9
|
+
export { createLogger };
|
|
10
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,QAAA,MAAM,YAAY,GAAI,QAAQ,cAAc;oBAI5B,MAAM,IAAI,8BAKjB;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,GAAG,CAAA;KAAE;CAgC5D,CAAC;AAEF,OAAO,EAAE,YAAY,EAAE,CAAC"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const createLogger = (config) => {
|
|
2
|
+
const { logging } = config;
|
|
3
|
+
return {
|
|
4
|
+
log: (callback, { type, scope, metadata, }) => {
|
|
5
|
+
callback();
|
|
6
|
+
if (!logging)
|
|
7
|
+
return;
|
|
8
|
+
const groupTitle = `${type} ${scope ? `(${scope})` : ""}`;
|
|
9
|
+
console.group(`%c${groupTitle}`, "color: #4CAF50; font-weight: bold; font-size: 14px;");
|
|
10
|
+
if (metadata) {
|
|
11
|
+
const metadataValue = metadata();
|
|
12
|
+
const { connections, repositories } = metadataValue;
|
|
13
|
+
if (Array.isArray(connections) && connections.length > 0) {
|
|
14
|
+
console.log("%cConnections:", "color: #2196F3; font-weight: bold; font-size: 12px;");
|
|
15
|
+
console.table(connections);
|
|
16
|
+
}
|
|
17
|
+
if (Array.isArray(repositories) && repositories.length > 0) {
|
|
18
|
+
console.log("%cRepositories:", "color: #FF9800; font-weight: bold; font-size: 12px;");
|
|
19
|
+
console.table(repositories);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
console.groupEnd();
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
export { createLogger };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
declare function createRepositoryInstance<I extends Record<string, any>>(definition: (infrastructure: I) => unknown, infrastructure: I): {
|
|
2
|
+
connect(): void;
|
|
3
|
+
disconnect(): void;
|
|
4
|
+
getReference(): unknown;
|
|
5
|
+
getConnections(): number;
|
|
6
|
+
};
|
|
7
|
+
export { createRepositoryInstance };
|
|
8
|
+
//# sourceMappingURL=repositoryInstance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repositoryInstance.d.ts","sourceRoot":"","sources":["../src/repositoryInstance.ts"],"names":[],"mappings":"AAAA,iBAAS,wBAAwB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC7D,UAAU,EAAE,CAAC,cAAc,EAAE,CAAC,KAAK,OAAO,EAC1C,cAAc,EAAE,CAAC;;;;;EAyBlB;AAED,OAAO,EAAE,wBAAwB,EAAE,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
function createRepositoryInstance(definition, infrastructure) {
|
|
2
|
+
let reference = undefined;
|
|
3
|
+
let connections = 0;
|
|
4
|
+
return {
|
|
5
|
+
connect() {
|
|
6
|
+
if (connections === 0) {
|
|
7
|
+
reference = definition(infrastructure);
|
|
8
|
+
}
|
|
9
|
+
connections += 1;
|
|
10
|
+
},
|
|
11
|
+
disconnect() {
|
|
12
|
+
if (connections === 0)
|
|
13
|
+
return;
|
|
14
|
+
connections -= 1;
|
|
15
|
+
if (connections === 0) {
|
|
16
|
+
reference = undefined;
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
getReference() {
|
|
20
|
+
return reference;
|
|
21
|
+
},
|
|
22
|
+
getConnections() {
|
|
23
|
+
return connections;
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export { createRepositoryInstance };
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { IRepositoryInstance } from "./types";
|
|
2
|
+
declare function createStore(): {
|
|
3
|
+
setRepository(id: string, repository: IRepositoryInstance): void;
|
|
4
|
+
getRepository(id: string): IRepositoryInstance | undefined;
|
|
5
|
+
hasRepository(id: string): boolean;
|
|
6
|
+
deleteRepository(id: string): void;
|
|
7
|
+
entries(): MapIterator<[string, IRepositoryInstance]>;
|
|
8
|
+
};
|
|
9
|
+
export { createStore };
|
|
10
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AACnD,iBAAS,WAAW;sBAGE,MAAM,cAAc,mBAAmB;sBAGvC,MAAM;sBAGN,MAAM;yBAGH,MAAM;;EAO9B;AACD,OAAO,EAAE,WAAW,EAAE,CAAC"}
|
package/dist/store.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
function createStore() {
|
|
2
|
+
const state = new Map();
|
|
3
|
+
return {
|
|
4
|
+
setRepository(id, repository) {
|
|
5
|
+
state.set(id, repository);
|
|
6
|
+
},
|
|
7
|
+
getRepository(id) {
|
|
8
|
+
return state.get(id);
|
|
9
|
+
},
|
|
10
|
+
hasRepository(id) {
|
|
11
|
+
return state.has(id);
|
|
12
|
+
},
|
|
13
|
+
deleteRepository(id) {
|
|
14
|
+
state.delete(id);
|
|
15
|
+
},
|
|
16
|
+
entries() {
|
|
17
|
+
return state.entries();
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export { createStore };
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,IAAI,IAAI,CAAC;IAChB,UAAU,IAAI,IAAI,CAAC;IACnB,YAAY,IAAI,OAAO,CAAC;IACxB,cAAc,IAAI,MAAM,CAAC;CAC1B"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@med1802/repository-manager",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/medanmilos1831/repository-manager.git",
|
|
9
|
+
"directory": "med1802/repository-manager"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/medanmilos1831/pnpm-monorepo-med1802-packages/tree/main/med1802/repository-manager#readme",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc -p tsconfig.json"
|
|
14
|
+
}
|
|
15
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { createRepositoryInstance } from "./repositoryInstance";
|
|
2
|
+
import { createStore } from "./store";
|
|
3
|
+
import { createLogger } from "./logger";
|
|
4
|
+
import type { IConfiguration } from "./types";
|
|
5
|
+
const repositoryManager = () => {
|
|
6
|
+
return {
|
|
7
|
+
createContainer<I extends Record<string, any>>(
|
|
8
|
+
infrastructure: I,
|
|
9
|
+
config?: IConfiguration
|
|
10
|
+
) {
|
|
11
|
+
const defaultConfig: IConfiguration = {
|
|
12
|
+
logging: false,
|
|
13
|
+
...config,
|
|
14
|
+
};
|
|
15
|
+
const store = createStore();
|
|
16
|
+
const logger = createLogger(defaultConfig);
|
|
17
|
+
|
|
18
|
+
const getRepository = (id: string) => store.getRepository(id);
|
|
19
|
+
const hasRepository = (id: string) => store.hasRepository(id);
|
|
20
|
+
const allRepositories = () =>
|
|
21
|
+
Array.from(store.entries()).map(([id, repository]) => ({
|
|
22
|
+
repository: id,
|
|
23
|
+
connections: repository.getConnections(),
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
defineRepository(
|
|
28
|
+
id: string,
|
|
29
|
+
repositoryDefinition: (infrastructure: I) => void
|
|
30
|
+
) {
|
|
31
|
+
if (hasRepository(id)) return;
|
|
32
|
+
logger.log(
|
|
33
|
+
() => {
|
|
34
|
+
store.setRepository(
|
|
35
|
+
id,
|
|
36
|
+
createRepositoryInstance(repositoryDefinition, infrastructure)
|
|
37
|
+
);
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
type: "repository.define",
|
|
41
|
+
scope: id,
|
|
42
|
+
metadata: () => {
|
|
43
|
+
return {
|
|
44
|
+
repositories: allRepositories().map(({ repository }) => ({
|
|
45
|
+
repository,
|
|
46
|
+
})),
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
},
|
|
52
|
+
queryRepository<R = any>(id: string) {
|
|
53
|
+
const repository = getRepository(id);
|
|
54
|
+
if (!repository) {
|
|
55
|
+
throw new Error(`Repository "${id}" not found`);
|
|
56
|
+
}
|
|
57
|
+
logger.log(() => repository.connect(), {
|
|
58
|
+
type: "repository.connect",
|
|
59
|
+
scope: id,
|
|
60
|
+
metadata: () => {
|
|
61
|
+
return {
|
|
62
|
+
connections: allRepositories(),
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
return {
|
|
67
|
+
repository: repository.getReference() as R,
|
|
68
|
+
disconnect: () =>
|
|
69
|
+
logger.log(() => repository.disconnect(), {
|
|
70
|
+
type: "repository.disconnect",
|
|
71
|
+
scope: id,
|
|
72
|
+
metadata: () => {
|
|
73
|
+
return {
|
|
74
|
+
connections: allRepositories(),
|
|
75
|
+
};
|
|
76
|
+
},
|
|
77
|
+
}),
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export { repositoryManager };
|
package/src/logger.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { IConfiguration } from "./types";
|
|
2
|
+
|
|
3
|
+
const createLogger = (config: IConfiguration) => {
|
|
4
|
+
const { logging } = config;
|
|
5
|
+
return {
|
|
6
|
+
log: (
|
|
7
|
+
callback: () => void,
|
|
8
|
+
{
|
|
9
|
+
type,
|
|
10
|
+
scope,
|
|
11
|
+
metadata,
|
|
12
|
+
}: { type: string; scope: string; metadata: () => any }
|
|
13
|
+
) => {
|
|
14
|
+
callback();
|
|
15
|
+
if (!logging) return;
|
|
16
|
+
const groupTitle = `${type} ${scope ? `(${scope})` : ""}`;
|
|
17
|
+
console.group(
|
|
18
|
+
`%c${groupTitle}`,
|
|
19
|
+
"color: #4CAF50; font-weight: bold; font-size: 14px;"
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
if (metadata) {
|
|
23
|
+
const metadataValue = metadata();
|
|
24
|
+
const { connections, repositories } = metadataValue;
|
|
25
|
+
if (Array.isArray(connections) && connections.length > 0) {
|
|
26
|
+
console.log(
|
|
27
|
+
"%cConnections:",
|
|
28
|
+
"color: #2196F3; font-weight: bold; font-size: 12px;"
|
|
29
|
+
);
|
|
30
|
+
console.table(connections);
|
|
31
|
+
}
|
|
32
|
+
if (Array.isArray(repositories) && repositories.length > 0) {
|
|
33
|
+
console.log(
|
|
34
|
+
"%cRepositories:",
|
|
35
|
+
"color: #FF9800; font-weight: bold; font-size: 12px;"
|
|
36
|
+
);
|
|
37
|
+
console.table(repositories);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
console.groupEnd();
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export { createLogger };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
function createRepositoryInstance<I extends Record<string, any>>(
|
|
2
|
+
definition: (infrastructure: I) => unknown,
|
|
3
|
+
infrastructure: I
|
|
4
|
+
) {
|
|
5
|
+
let reference = undefined as unknown;
|
|
6
|
+
let connections = 0;
|
|
7
|
+
return {
|
|
8
|
+
connect() {
|
|
9
|
+
if (connections === 0) {
|
|
10
|
+
reference = definition(infrastructure);
|
|
11
|
+
}
|
|
12
|
+
connections += 1;
|
|
13
|
+
},
|
|
14
|
+
disconnect() {
|
|
15
|
+
if (connections === 0) return;
|
|
16
|
+
connections -= 1;
|
|
17
|
+
if (connections === 0) {
|
|
18
|
+
reference = undefined;
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
getReference() {
|
|
22
|
+
return reference;
|
|
23
|
+
},
|
|
24
|
+
getConnections() {
|
|
25
|
+
return connections;
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export { createRepositoryInstance };
|
package/src/store.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { IRepositoryInstance } from "./types";
|
|
2
|
+
function createStore() {
|
|
3
|
+
const state = new Map<string, IRepositoryInstance>();
|
|
4
|
+
return {
|
|
5
|
+
setRepository(id: string, repository: IRepositoryInstance) {
|
|
6
|
+
state.set(id, repository);
|
|
7
|
+
},
|
|
8
|
+
getRepository(id: string) {
|
|
9
|
+
return state.get(id);
|
|
10
|
+
},
|
|
11
|
+
hasRepository(id: string) {
|
|
12
|
+
return state.has(id);
|
|
13
|
+
},
|
|
14
|
+
deleteRepository(id: string) {
|
|
15
|
+
state.delete(id);
|
|
16
|
+
},
|
|
17
|
+
entries() {
|
|
18
|
+
return state.entries();
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export { createStore };
|
package/src/types.ts
ADDED
package/tsconfig.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"fileNames":["../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.dom.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.dom.iterable.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.dom.asynciterable.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.webworker.importscripts.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.scripthost.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2016.intl.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/lib/lib.es2019.full.d.ts","../../node_modules/.pnpm/@types+react@18.3.23/node_modules/@types/react/global.d.ts","../../node_modules/.pnpm/csstype@3.1.3/node_modules/csstype/index.d.ts","../../node_modules/.pnpm/@types+prop-types@15.7.15/node_modules/@types/prop-types/index.d.ts","../../node_modules/.pnpm/@types+react@18.3.23/node_modules/@types/react/index.d.ts","../../node_modules/.pnpm/@types+react@18.3.23/node_modules/@types/react/jsx-runtime.d.ts","./src/repositoryinstance.ts","./src/types.ts","./src/store.ts","./src/logger.ts","./src/index.ts","../../node_modules/.pnpm/@types+react-dom@18.3.7_@types+react@18.3.23/node_modules/@types/react-dom/index.d.ts"],"fileIdsList":[[47,48,49,50,51],[47,49],[47],[46],[43,44,45]],"fileInfos":[{"version":"69684132aeb9b5642cbcd9e22dff7818ff0ee1aa831728af0ecf97d3364d5546","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"092c2bfe125ce69dbb1223c85d68d4d2397d7d8411867b5cc03cec902c233763","affectsGlobalScope":true,"impliedFormat":1},{"version":"07f073f19d67f74d732b1adea08e1dc66b1b58d77cb5b43931dee3d798a2fd53","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7a3c8b952931daebdfc7a2897c53c0a1c73624593fa070e46bd537e64dcd20a","affectsGlobalScope":true,"impliedFormat":1},{"version":"80e18897e5884b6723488d4f5652167e7bb5024f946743134ecc4aa4ee731f89","affectsGlobalScope":true,"impliedFormat":1},{"version":"cd034f499c6cdca722b60c04b5b1b78e058487a7085a8e0d6fb50809947ee573","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"936e80ad36a2ee83fc3caf008e7c4c5afe45b3cf3d5c24408f039c1d47bdc1df","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"fef8cfad2e2dc5f5b3d97a6f4f2e92848eb1b88e897bb7318cef0e2820bceaab","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"08f6861df84fba9719c14d5adc3ba40be9f0c687639e6c4df3c05b9301b8ff94","impliedFormat":1},{"version":"eb5b19b86227ace1d29ea4cf81387279d04bb34051e944bc53df69f58914b788","affectsGlobalScope":true,"impliedFormat":1},{"version":"8a8eb4ebffd85e589a1cc7c178e291626c359543403d58c9cd22b81fab5b1fb9","impliedFormat":1},{"version":"87d9d29dbc745f182683f63187bf3d53fd8673e5fca38ad5eaab69798ed29fbc","impliedFormat":1},{"version":"472f5aab7edc498a0a761096e8e254c5bc3323d07a1e7f5f8b8ec0d6395b60a0","affectsGlobalScope":true,"impliedFormat":1},{"version":"42c169fb8c2d42f4f668c624a9a11e719d5d07dacbebb63cbcf7ef365b0a75b3","impliedFormat":1},{"version":"ace4a119abe4ca7ea58ca5e0b89420d791a9c68ff5fcb3d32187ffa495f47d36","signature":"9aad1a780fa42fe11f3209e60c109f32b00cd0661629e4faa909c43b80850a82"},{"version":"f3d695638d86fc0e49aa2923963c5491b0bef20f8fb1b582ff813364d3a22dfb","signature":"abbe52d6fc94ab7de123cc0eaf9c83a8b9b0b63d55e24c83188ccd145860cc6e"},{"version":"f5067e271313e63a819ff1c077910638e1475cc4f6be4fcf690d1b928fcf582c","signature":"c15a174d71579221241c22ceb238a46fcad2df8b873dc5c9450fd545f6416dfe"},{"version":"492c075c93e7422319653338cad79622e19a08cc9269f62600805c1fb52b1a36","signature":"935c0760e874c9d96997126152eb9b3b8d7104025b942bf0a92202583276ddbd"},{"version":"82f94351ad2096c90d036a069c887c8e08dce7f118d977eab88034d4a264c219","signature":"29a079aacb8d621cdf086d8325c3c6c92783dcc0119ef27893e9ba1486effd7e"},{"version":"17ed71200119e86ccef2d96b73b02ce8854b76ad6bd21b5021d4269bec527b5f","impliedFormat":1}],"root":[[48,52]],"options":{"composite":true,"declaration":true,"declarationMap":true,"esModuleInterop":true,"jsx":4,"module":99,"outDir":"./dist","rootDir":"./src","skipLibCheck":true,"strict":true,"target":6},"referencedMap":[[52,1],[51,2],[48,3],[50,2],[49,3],[53,4],[46,5],[47,4]],"latestChangedDtsFile":"./dist/index.d.ts","version":"5.8.3"}
|