@fjell/registry 4.4.6 ā 4.4.9
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 +81 -4
- package/dist/Registry.cjs +20 -1
- package/dist/Registry.js +20 -1
- package/dist/RegistryHub.cjs +17 -1
- package/dist/RegistryHub.js +17 -1
- package/dist/index.cjs +35 -0
- package/dist/index.cjs.map +1 -1
- package/dist/types.d.ts +15 -0
- package/docs/README.md +74 -0
- package/docs/index.html +17 -0
- package/docs/memory-data/scaling-10-instances.json +206 -206
- package/docs/memory-data/scaling-100-instances.json +206 -206
- package/docs/memory-data/scaling-1000-instances.json +108 -108
- package/docs/memory-data/scaling-10000-instances.json +49 -49
- package/docs/memory-data/scaling-20-instances.json +208 -208
- package/docs/memory-data/scaling-200-instances.json +201 -201
- package/docs/memory-data/scaling-2000-instances.json +107 -107
- package/docs/memory-data/scaling-50-instances.json +206 -206
- package/docs/memory-data/scaling-500-instances.json +108 -108
- package/docs/memory-data/scaling-5000-instances.json +49 -49
- package/docs/memory-overhead.svg +17 -17
- package/docs/memory.md +111 -111
- package/docs/package.json +35 -0
- package/docs/public/README.md +623 -0
- package/docs/public/TIMING_NODE_OPTIMIZATION.md +207 -0
- package/docs/public/examples/coordinates-example.ts +253 -0
- package/docs/public/examples/multi-level-keys.ts +374 -0
- package/docs/public/examples/registry-hub-coordinates-example.ts +370 -0
- package/docs/public/examples/registry-hub-types.ts +437 -0
- package/docs/public/examples/simple-example.ts +250 -0
- package/docs/public/examples-README.md +222 -0
- package/docs/public/fjell-icon.svg +1 -0
- package/docs/public/icon.png +0 -0
- package/docs/public/icon2.png +0 -0
- package/docs/public/memory-overhead.svg +120 -0
- package/docs/public/memory.md +430 -0
- package/docs/public/pano.png +0 -0
- package/docs/public/pano2.png +0 -0
- package/docs/public/timing-range.svg +176 -0
- package/docs/public/timing.md +483 -0
- package/docs/src/App.css +1175 -0
- package/docs/src/App.test.tsx +50 -0
- package/docs/src/App.tsx +583 -0
- package/docs/src/index.css +40 -0
- package/docs/src/main.tsx +10 -0
- package/docs/src/test/setup.ts +1 -0
- package/docs/timing-range.svg +41 -41
- package/docs/timing.md +101 -101
- package/docs/tsconfig.node.json +13 -0
- package/docs/vitest.config.ts +14 -0
- package/examples/README.md +35 -0
- package/examples/coordinates-example.ts +253 -0
- package/examples/registry-hub-coordinates-example.ts +370 -0
- package/package.json +2 -2
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coordinates Discovery Example
|
|
3
|
+
*
|
|
4
|
+
* This example demonstrates how to use the getCoordinates() method to:
|
|
5
|
+
* - Discover all registered instances in a registry
|
|
6
|
+
* - Inspect coordinates and their scopes
|
|
7
|
+
* - Monitor registry state for debugging
|
|
8
|
+
* - Implement discovery mechanisms
|
|
9
|
+
*
|
|
10
|
+
* Run this example with: npx tsx examples/coordinates-example.ts
|
|
11
|
+
*
|
|
12
|
+
* Note: In a real application, import from the built package:
|
|
13
|
+
* import { createRegistry, createInstance } from '@fjell/registry';
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
// Import the actual registry functionality
|
|
17
|
+
import { createRegistry } from '../src/Registry';
|
|
18
|
+
import { createInstance } from '../src/Instance';
|
|
19
|
+
|
|
20
|
+
// ===== Service Examples =====
|
|
21
|
+
|
|
22
|
+
class DatabaseService {
|
|
23
|
+
constructor(private type: string, private environment: string) { }
|
|
24
|
+
|
|
25
|
+
connect() {
|
|
26
|
+
console.log(`Connected to ${this.type} database in ${this.environment}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
getInfo() {
|
|
30
|
+
return `${this.type} (${this.environment})`;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
class CacheService {
|
|
35
|
+
constructor(private type: string) { }
|
|
36
|
+
|
|
37
|
+
get(key: string) {
|
|
38
|
+
console.log(`Getting ${key} from ${this.type} cache`);
|
|
39
|
+
return `cached_${key}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
getInfo() {
|
|
43
|
+
return this.type;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
class LoggingService {
|
|
48
|
+
constructor(private level: string) { }
|
|
49
|
+
|
|
50
|
+
log(message: string) {
|
|
51
|
+
console.log(`[${this.level.toUpperCase()}] ${message}`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
getInfo() {
|
|
55
|
+
return `Logging at ${this.level} level`;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ===== Main Example =====
|
|
60
|
+
|
|
61
|
+
async function runCoordinatesExample() {
|
|
62
|
+
console.log('š Registry Coordinates Discovery Example\n');
|
|
63
|
+
|
|
64
|
+
// Step 1: Create a registry
|
|
65
|
+
console.log('1. Creating registry...');
|
|
66
|
+
const registry = createRegistry('services');
|
|
67
|
+
console.log(' ā
Registry created\n');
|
|
68
|
+
|
|
69
|
+
// Step 2: Register multiple instances with different scopes
|
|
70
|
+
console.log('2. Registering instances with various configurations...\n');
|
|
71
|
+
|
|
72
|
+
// Database services for different environments
|
|
73
|
+
registry.createInstance(
|
|
74
|
+
['database'],
|
|
75
|
+
['production', 'postgres'],
|
|
76
|
+
(coordinate, context) => {
|
|
77
|
+
const service = new DatabaseService('PostgreSQL', 'production');
|
|
78
|
+
const instance = createInstance(context.registry, coordinate);
|
|
79
|
+
(instance as any).connect = service.connect.bind(service);
|
|
80
|
+
(instance as any).getInfo = service.getInfo.bind(service);
|
|
81
|
+
return instance;
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
console.log(' ā
PostgreSQL database (production) registered');
|
|
85
|
+
|
|
86
|
+
registry.createInstance(
|
|
87
|
+
['database'],
|
|
88
|
+
['development', 'sqlite'],
|
|
89
|
+
(coordinate, context) => {
|
|
90
|
+
const service = new DatabaseService('SQLite', 'development');
|
|
91
|
+
const instance = createInstance(context.registry, coordinate);
|
|
92
|
+
(instance as any).connect = service.connect.bind(service);
|
|
93
|
+
(instance as any).getInfo = service.getInfo.bind(service);
|
|
94
|
+
return instance;
|
|
95
|
+
}
|
|
96
|
+
);
|
|
97
|
+
console.log(' ā
SQLite database (development) registered');
|
|
98
|
+
|
|
99
|
+
// Cache services
|
|
100
|
+
registry.createInstance(
|
|
101
|
+
['cache', 'redis'],
|
|
102
|
+
['production'],
|
|
103
|
+
(coordinate, context) => {
|
|
104
|
+
const service = new CacheService('Redis');
|
|
105
|
+
const instance = createInstance(context.registry, coordinate);
|
|
106
|
+
(instance as any).get = service.get.bind(service);
|
|
107
|
+
(instance as any).getInfo = service.getInfo.bind(service);
|
|
108
|
+
return instance;
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
console.log(' ā
Redis cache (production) registered');
|
|
112
|
+
|
|
113
|
+
registry.createInstance(
|
|
114
|
+
['cache', 'memory'],
|
|
115
|
+
['development', 'testing'],
|
|
116
|
+
(coordinate, context) => {
|
|
117
|
+
const service = new CacheService('In-Memory');
|
|
118
|
+
const instance = createInstance(context.registry, coordinate);
|
|
119
|
+
(instance as any).get = service.get.bind(service);
|
|
120
|
+
(instance as any).getInfo = service.getInfo.bind(service);
|
|
121
|
+
return instance;
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
console.log(' ā
Memory cache (development/testing) registered');
|
|
125
|
+
|
|
126
|
+
// Logging services
|
|
127
|
+
registry.createInstance(
|
|
128
|
+
['logging'],
|
|
129
|
+
['production'],
|
|
130
|
+
(coordinate, context) => {
|
|
131
|
+
const service = new LoggingService('error');
|
|
132
|
+
const instance = createInstance(context.registry, coordinate);
|
|
133
|
+
(instance as any).log = service.log.bind(service);
|
|
134
|
+
(instance as any).getInfo = service.getInfo.bind(service);
|
|
135
|
+
return instance;
|
|
136
|
+
}
|
|
137
|
+
);
|
|
138
|
+
console.log(' ā
Error logging (production) registered');
|
|
139
|
+
|
|
140
|
+
registry.createInstance(
|
|
141
|
+
['logging'],
|
|
142
|
+
['development'],
|
|
143
|
+
(coordinate, context) => {
|
|
144
|
+
const service = new LoggingService('debug');
|
|
145
|
+
const instance = createInstance(context.registry, coordinate);
|
|
146
|
+
(instance as any).log = service.log.bind(service);
|
|
147
|
+
(instance as any).getInfo = service.getInfo.bind(service);
|
|
148
|
+
return instance;
|
|
149
|
+
}
|
|
150
|
+
);
|
|
151
|
+
console.log(' ā
Debug logging (development) registered\n');
|
|
152
|
+
|
|
153
|
+
// Step 3: Demonstrate getCoordinates functionality
|
|
154
|
+
console.log('3. Discovering all registered coordinates...\n');
|
|
155
|
+
|
|
156
|
+
const coordinates = registry.getCoordinates();
|
|
157
|
+
console.log(`š Total registered coordinates: ${coordinates.length}\n`);
|
|
158
|
+
|
|
159
|
+
// Display all coordinates with their details
|
|
160
|
+
console.log('š Registered Coordinates:');
|
|
161
|
+
console.log('ā'.repeat(60));
|
|
162
|
+
coordinates.forEach((coord, index) => {
|
|
163
|
+
console.log(`${index + 1}. ${coord.toString()}`);
|
|
164
|
+
console.log(` Key Path: [${coord.kta.join(' ā ')}]`);
|
|
165
|
+
console.log(` Scopes: ${coord.scopes.length > 0 ? coord.scopes.join(', ') : 'none'}`);
|
|
166
|
+
console.log('');
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Step 4: Demonstrate filtering and analysis
|
|
170
|
+
console.log('4. Analyzing coordinate patterns...\n');
|
|
171
|
+
|
|
172
|
+
// Group by environment
|
|
173
|
+
const byEnvironment = {
|
|
174
|
+
production: coordinates.filter(c => c.scopes.includes('production')),
|
|
175
|
+
development: coordinates.filter(c => c.scopes.includes('development')),
|
|
176
|
+
testing: coordinates.filter(c => c.scopes.includes('testing')),
|
|
177
|
+
unscoped: coordinates.filter(c => c.scopes.length === 0)
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
console.log('š¢ Coordinates by Environment:');
|
|
181
|
+
Object.entries(byEnvironment).forEach(([env, coords]) => {
|
|
182
|
+
if (coords.length > 0) {
|
|
183
|
+
console.log(` ${env}: ${coords.length} instance(s)`);
|
|
184
|
+
coords.forEach(coord => {
|
|
185
|
+
console.log(` - ${coord.kta.join('.')}`);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// Group by service type (first element of kta)
|
|
191
|
+
const byServiceType = coordinates.reduce((acc, coord) => {
|
|
192
|
+
const serviceType = coord.kta[0];
|
|
193
|
+
if (!acc[serviceType]) acc[serviceType] = [];
|
|
194
|
+
acc[serviceType].push(coord);
|
|
195
|
+
return acc;
|
|
196
|
+
}, {} as Record<string, typeof coordinates>);
|
|
197
|
+
|
|
198
|
+
console.log('\nš§ Coordinates by Service Type:');
|
|
199
|
+
Object.entries(byServiceType).forEach(([type, coords]) => {
|
|
200
|
+
console.log(` ${type}: ${coords.length} instance(s)`);
|
|
201
|
+
coords.forEach(coord => {
|
|
202
|
+
const scopeInfo = coord.scopes.length > 0 ? ` (${coord.scopes.join(', ')})` : '';
|
|
203
|
+
console.log(` - ${coord.kta.join('.')}${scopeInfo}`);
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// Step 5: Demonstrate practical usage scenarios
|
|
208
|
+
console.log('\n5. Practical usage scenarios...\n');
|
|
209
|
+
|
|
210
|
+
// Scenario 1: Health check - verify all expected services are registered
|
|
211
|
+
console.log('š„ Health Check Example:');
|
|
212
|
+
const expectedServices = ['database', 'cache', 'logging'];
|
|
213
|
+
const registeredServices = [...new Set(coordinates.map(c => c.kta[0]))];
|
|
214
|
+
|
|
215
|
+
expectedServices.forEach(service => {
|
|
216
|
+
const isRegistered = registeredServices.includes(service);
|
|
217
|
+
console.log(` ${service}: ${isRegistered ? 'ā
Registered' : 'ā Missing'}`);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// Scenario 2: Environment validation
|
|
221
|
+
console.log('\nš Environment Validation:');
|
|
222
|
+
const productionServices = coordinates.filter(c => c.scopes.includes('production'));
|
|
223
|
+
const developmentServices = coordinates.filter(c => c.scopes.includes('development'));
|
|
224
|
+
|
|
225
|
+
console.log(` Production environment has ${productionServices.length} service(s) registered`);
|
|
226
|
+
console.log(` Development environment has ${developmentServices.length} service(s) registered`);
|
|
227
|
+
|
|
228
|
+
// Scenario 3: Discovery mechanism
|
|
229
|
+
console.log('\nš Service Discovery Example:');
|
|
230
|
+
console.log(' Available cache services:');
|
|
231
|
+
coordinates
|
|
232
|
+
.filter(c => c.kta.includes('cache'))
|
|
233
|
+
.forEach(coord => {
|
|
234
|
+
console.log(` - ${coord.kta.join('.')} (${coord.scopes.join(', ') || 'any scope'})`);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
console.log('\n⨠Coordinates discovery example completed!');
|
|
238
|
+
|
|
239
|
+
return {
|
|
240
|
+
totalCoordinates: coordinates.length,
|
|
241
|
+
coordinates: coordinates,
|
|
242
|
+
byEnvironment,
|
|
243
|
+
byServiceType
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Export for testing
|
|
248
|
+
export { runCoordinatesExample };
|
|
249
|
+
|
|
250
|
+
// Run the example if this file is executed directly
|
|
251
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
252
|
+
runCoordinatesExample().catch(console.error);
|
|
253
|
+
}
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RegistryHub Coordinates Discovery Example
|
|
3
|
+
*
|
|
4
|
+
* This example demonstrates how to use the getAllCoordinates() method on RegistryHub to:
|
|
5
|
+
* - Discover all registered instances across multiple registries
|
|
6
|
+
* - See which registry type contains each coordinate
|
|
7
|
+
* - Analyze cross-registry service architecture
|
|
8
|
+
* - Implement system-wide monitoring and discovery
|
|
9
|
+
* - Validate service deployment across different domains
|
|
10
|
+
*
|
|
11
|
+
* Run this example with: npx tsx examples/registry-hub-coordinates-example.ts
|
|
12
|
+
*
|
|
13
|
+
* Note: In a real application, import from the built package:
|
|
14
|
+
* import { createRegistryHub, createRegistry, createInstance } from '@fjell/registry';
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
// Import the actual registry functionality
|
|
18
|
+
import { createRegistryHub } from '../src/RegistryHub';
|
|
19
|
+
import { createRegistry } from '../src/Registry';
|
|
20
|
+
import { createInstance } from '../src/Instance';
|
|
21
|
+
|
|
22
|
+
// ===== Service Examples =====
|
|
23
|
+
|
|
24
|
+
class AuthService {
|
|
25
|
+
constructor(private provider: string, private environment: string) { }
|
|
26
|
+
|
|
27
|
+
authenticate(token: string) { // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
28
|
+
console.log(`Authenticating with ${this.provider} in ${this.environment}`);
|
|
29
|
+
return { userId: 'user123', provider: this.provider };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
getInfo() {
|
|
33
|
+
return `${this.provider} Auth (${this.environment})`;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
class DataRepository {
|
|
38
|
+
constructor(private database: string, private table: string) { }
|
|
39
|
+
|
|
40
|
+
save(data: any) {
|
|
41
|
+
console.log(`Saving to ${this.database}.${this.table}:`, data);
|
|
42
|
+
return { id: 'saved123', database: this.database };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
getInfo() {
|
|
46
|
+
return `${this.database} Repository for ${this.table}`;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
class CacheStore {
|
|
51
|
+
constructor(private type: string, private ttl: number) { }
|
|
52
|
+
|
|
53
|
+
set(key: string, value: any) { // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
54
|
+
console.log(`Caching ${key} in ${this.type} for ${this.ttl}s`);
|
|
55
|
+
return { cached: true, type: this.type };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
getInfo() {
|
|
59
|
+
return `${this.type} Cache (TTL: ${this.ttl}s)`;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
class IntegrationService {
|
|
64
|
+
constructor(private provider: string, private version: string) { }
|
|
65
|
+
|
|
66
|
+
call(endpoint: string, data: any) { // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
67
|
+
console.log(`Calling ${this.provider} v${this.version} at ${endpoint}`);
|
|
68
|
+
return { success: true, provider: this.provider };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
getInfo() {
|
|
72
|
+
return `${this.provider} Integration v${this.version}`;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ===== Main Example =====
|
|
77
|
+
|
|
78
|
+
async function runRegistryHubCoordinatesExample() {
|
|
79
|
+
console.log('š RegistryHub Coordinates Discovery Example\n');
|
|
80
|
+
|
|
81
|
+
// Step 1: Create RegistryHub and multiple registries
|
|
82
|
+
console.log('1. Creating RegistryHub and domain-specific registries...');
|
|
83
|
+
const hub = createRegistryHub();
|
|
84
|
+
|
|
85
|
+
const authRegistry = createRegistry('auth');
|
|
86
|
+
const dataRegistry = createRegistry('data');
|
|
87
|
+
const cacheRegistry = createRegistry('cache');
|
|
88
|
+
const integrationsRegistry = createRegistry('integrations');
|
|
89
|
+
|
|
90
|
+
console.log(' ā
RegistryHub created');
|
|
91
|
+
console.log(' ā
4 domain registries created\n');
|
|
92
|
+
|
|
93
|
+
// Step 2: Register all registries in the hub
|
|
94
|
+
console.log('2. Registering registries in the hub...');
|
|
95
|
+
hub.registerRegistry(authRegistry);
|
|
96
|
+
hub.registerRegistry(dataRegistry);
|
|
97
|
+
hub.registerRegistry(cacheRegistry);
|
|
98
|
+
hub.registerRegistry(integrationsRegistry);
|
|
99
|
+
|
|
100
|
+
console.log(' ā
All registries registered in hub');
|
|
101
|
+
console.log(` š Registered registry types: ${hub.getRegisteredTypes().join(', ')}\n`);
|
|
102
|
+
|
|
103
|
+
// Step 3: Create instances across different registries and environments
|
|
104
|
+
console.log('3. Creating instances across multiple registries and environments...\n');
|
|
105
|
+
|
|
106
|
+
// Auth Registry - Different authentication providers
|
|
107
|
+
authRegistry.createInstance(
|
|
108
|
+
['Auth', 'JWT'],
|
|
109
|
+
['production', 'oauth'],
|
|
110
|
+
(coordinate, context) => {
|
|
111
|
+
const service = new AuthService('JWT', 'production');
|
|
112
|
+
const instance = createInstance(context.registry, coordinate);
|
|
113
|
+
(instance as any).authenticate = service.authenticate.bind(service);
|
|
114
|
+
(instance as any).getInfo = service.getInfo.bind(service);
|
|
115
|
+
return instance;
|
|
116
|
+
}
|
|
117
|
+
);
|
|
118
|
+
console.log(' ā
JWT Auth (production) registered in auth registry');
|
|
119
|
+
|
|
120
|
+
authRegistry.createInstance(
|
|
121
|
+
['Auth', 'SAML'],
|
|
122
|
+
['production', 'enterprise'],
|
|
123
|
+
(coordinate, context) => {
|
|
124
|
+
const service = new AuthService('SAML', 'production');
|
|
125
|
+
const instance = createInstance(context.registry, coordinate);
|
|
126
|
+
(instance as any).authenticate = service.authenticate.bind(service);
|
|
127
|
+
(instance as any).getInfo = service.getInfo.bind(service);
|
|
128
|
+
return instance;
|
|
129
|
+
}
|
|
130
|
+
);
|
|
131
|
+
console.log(' ā
SAML Auth (production) registered in auth registry');
|
|
132
|
+
|
|
133
|
+
authRegistry.createInstance(
|
|
134
|
+
['Auth', 'Local'],
|
|
135
|
+
['development', 'testing'],
|
|
136
|
+
(coordinate, context) => {
|
|
137
|
+
const service = new AuthService('Local', 'development');
|
|
138
|
+
const instance = createInstance(context.registry, coordinate);
|
|
139
|
+
(instance as any).authenticate = service.authenticate.bind(service);
|
|
140
|
+
(instance as any).getInfo = service.getInfo.bind(service);
|
|
141
|
+
return instance;
|
|
142
|
+
}
|
|
143
|
+
);
|
|
144
|
+
console.log(' ā
Local Auth (development) registered in auth registry');
|
|
145
|
+
|
|
146
|
+
// Data Registry - Different databases and entities
|
|
147
|
+
dataRegistry.createInstance(
|
|
148
|
+
['Repository', 'User'],
|
|
149
|
+
['production', 'firestore'],
|
|
150
|
+
(coordinate, context) => {
|
|
151
|
+
const repo = new DataRepository('Firestore', 'users');
|
|
152
|
+
const instance = createInstance(context.registry, coordinate);
|
|
153
|
+
(instance as any).save = repo.save.bind(repo);
|
|
154
|
+
(instance as any).getInfo = repo.getInfo.bind(repo);
|
|
155
|
+
return instance;
|
|
156
|
+
}
|
|
157
|
+
);
|
|
158
|
+
console.log(' ā
User Repository (Firestore/production) registered in data registry');
|
|
159
|
+
|
|
160
|
+
dataRegistry.createInstance(
|
|
161
|
+
['Repository', 'User'],
|
|
162
|
+
['development', 'postgresql'],
|
|
163
|
+
(coordinate, context) => {
|
|
164
|
+
const repo = new DataRepository('PostgreSQL', 'users');
|
|
165
|
+
const instance = createInstance(context.registry, coordinate);
|
|
166
|
+
(instance as any).save = repo.save.bind(repo);
|
|
167
|
+
(instance as any).getInfo = repo.getInfo.bind(repo);
|
|
168
|
+
return instance;
|
|
169
|
+
}
|
|
170
|
+
);
|
|
171
|
+
console.log(' ā
User Repository (PostgreSQL/development) registered in data registry');
|
|
172
|
+
|
|
173
|
+
dataRegistry.createInstance(
|
|
174
|
+
['Repository', 'Order'],
|
|
175
|
+
['production', 'firestore'],
|
|
176
|
+
(coordinate, context) => {
|
|
177
|
+
const repo = new DataRepository('Firestore', 'orders');
|
|
178
|
+
const instance = createInstance(context.registry, coordinate);
|
|
179
|
+
(instance as any).save = repo.save.bind(repo);
|
|
180
|
+
(instance as any).getInfo = repo.getInfo.bind(repo);
|
|
181
|
+
return instance;
|
|
182
|
+
}
|
|
183
|
+
);
|
|
184
|
+
console.log(' ā
Order Repository (Firestore/production) registered in data registry');
|
|
185
|
+
|
|
186
|
+
// Cache Registry - Different cache implementations
|
|
187
|
+
cacheRegistry.createInstance(
|
|
188
|
+
['Cache', 'Session'],
|
|
189
|
+
['production', 'redis'],
|
|
190
|
+
(coordinate, context) => {
|
|
191
|
+
const cache = new CacheStore('Redis', 3600);
|
|
192
|
+
const instance = createInstance(context.registry, coordinate);
|
|
193
|
+
(instance as any).set = cache.set.bind(cache);
|
|
194
|
+
(instance as any).getInfo = cache.getInfo.bind(cache);
|
|
195
|
+
return instance;
|
|
196
|
+
}
|
|
197
|
+
);
|
|
198
|
+
console.log(' ā
Session Cache (Redis/production) registered in cache registry');
|
|
199
|
+
|
|
200
|
+
cacheRegistry.createInstance(
|
|
201
|
+
['Cache', 'Query'],
|
|
202
|
+
['production', 'memcached'],
|
|
203
|
+
(coordinate, context) => {
|
|
204
|
+
const cache = new CacheStore('Memcached', 1800);
|
|
205
|
+
const instance = createInstance(context.registry, coordinate);
|
|
206
|
+
(instance as any).set = cache.set.bind(cache);
|
|
207
|
+
(instance as any).getInfo = cache.getInfo.bind(cache);
|
|
208
|
+
return instance;
|
|
209
|
+
}
|
|
210
|
+
);
|
|
211
|
+
console.log(' ā
Query Cache (Memcached/production) registered in cache registry');
|
|
212
|
+
|
|
213
|
+
cacheRegistry.createInstance(
|
|
214
|
+
['Cache', 'Memory'],
|
|
215
|
+
['development', 'local'],
|
|
216
|
+
(coordinate, context) => {
|
|
217
|
+
const cache = new CacheStore('In-Memory', 300);
|
|
218
|
+
const instance = createInstance(context.registry, coordinate);
|
|
219
|
+
(instance as any).set = cache.set.bind(cache);
|
|
220
|
+
(instance as any).getInfo = cache.getInfo.bind(cache);
|
|
221
|
+
return instance;
|
|
222
|
+
}
|
|
223
|
+
);
|
|
224
|
+
console.log(' ā
Memory Cache (local/development) registered in cache registry');
|
|
225
|
+
|
|
226
|
+
// Integrations Registry - External service integrations
|
|
227
|
+
integrationsRegistry.createInstance(
|
|
228
|
+
['Payment', 'Stripe'],
|
|
229
|
+
['production', 'live'],
|
|
230
|
+
(coordinate, context) => {
|
|
231
|
+
const integration = new IntegrationService('Stripe', '2023-10');
|
|
232
|
+
const instance = createInstance(context.registry, coordinate);
|
|
233
|
+
(instance as any).call = integration.call.bind(integration);
|
|
234
|
+
(instance as any).getInfo = integration.getInfo.bind(integration);
|
|
235
|
+
return instance;
|
|
236
|
+
}
|
|
237
|
+
);
|
|
238
|
+
console.log(' ā
Stripe Payment (production) registered in integrations registry');
|
|
239
|
+
|
|
240
|
+
integrationsRegistry.createInstance(
|
|
241
|
+
['Email', 'SendGrid'],
|
|
242
|
+
['production', 'v3'],
|
|
243
|
+
(coordinate, context) => {
|
|
244
|
+
const integration = new IntegrationService('SendGrid', '3.0');
|
|
245
|
+
const instance = createInstance(context.registry, coordinate);
|
|
246
|
+
(instance as any).call = integration.call.bind(integration);
|
|
247
|
+
(instance as any).getInfo = integration.getInfo.bind(integration);
|
|
248
|
+
return instance;
|
|
249
|
+
}
|
|
250
|
+
);
|
|
251
|
+
console.log(' ā
SendGrid Email (production) registered in integrations registry');
|
|
252
|
+
|
|
253
|
+
// Step 4: Demonstrate getAllCoordinates functionality
|
|
254
|
+
console.log('\n4. Discovering all coordinates across the entire system...\n');
|
|
255
|
+
|
|
256
|
+
const allCoordinates = hub.getAllCoordinates();
|
|
257
|
+
console.log(`š Total coordinates discovered: ${allCoordinates.length}`);
|
|
258
|
+
console.log(`š¦ Across ${hub.getRegisteredTypes().length} registry types\n`);
|
|
259
|
+
|
|
260
|
+
// Display all coordinates grouped by registry type
|
|
261
|
+
console.log('š All Registered Coordinates by Registry Type:');
|
|
262
|
+
console.log('ā'.repeat(80));
|
|
263
|
+
|
|
264
|
+
const coordinatesByRegistry = allCoordinates.reduce((acc, item) => {
|
|
265
|
+
if (!acc[item.registryType]) acc[item.registryType] = [];
|
|
266
|
+
acc[item.registryType].push(item);
|
|
267
|
+
return acc;
|
|
268
|
+
}, {} as Record<string, typeof allCoordinates>);
|
|
269
|
+
|
|
270
|
+
Object.entries(coordinatesByRegistry).forEach(([registryType, coords]) => {
|
|
271
|
+
console.log(`\nš ${registryType.toUpperCase()} REGISTRY (${coords.length} instances):`);
|
|
272
|
+
console.log('ā'.repeat(60));
|
|
273
|
+
coords.forEach((item, index) => {
|
|
274
|
+
const coord = item.coordinate;
|
|
275
|
+
console.log(` ${index + 1}. ${coord.kta.join(' ā ')}`);
|
|
276
|
+
console.log(` Scopes: ${coord.scopes.length > 0 ? coord.scopes.join(', ') : 'none'}`);
|
|
277
|
+
console.log(` Full: ${coord.toString()}`);
|
|
278
|
+
console.log('');
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// Step 5: Demonstrate cross-registry analysis
|
|
283
|
+
console.log('5. Cross-Registry Architecture Analysis...\n');
|
|
284
|
+
|
|
285
|
+
// Environment analysis
|
|
286
|
+
const environments = ['production', 'development', 'testing'];
|
|
287
|
+
console.log('š Environment Distribution:');
|
|
288
|
+
environments.forEach(env => {
|
|
289
|
+
const envCoords = allCoordinates.filter(c => c.coordinate.scopes.includes(env));
|
|
290
|
+
console.log(` ${env}: ${envCoords.length} service(s) across ${new Set(envCoords.map(c => c.registryType)).size} registry type(s)`);
|
|
291
|
+
|
|
292
|
+
const registryBreakdown = envCoords.reduce((acc, c) => {
|
|
293
|
+
acc[c.registryType] = (acc[c.registryType] || 0) + 1;
|
|
294
|
+
return acc;
|
|
295
|
+
}, {} as Record<string, number>);
|
|
296
|
+
|
|
297
|
+
Object.entries(registryBreakdown).forEach(([regType, count]) => {
|
|
298
|
+
console.log(` - ${regType}: ${count}`);
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// Service type analysis
|
|
303
|
+
console.log('\nš§ Service Architecture Overview:');
|
|
304
|
+
const serviceTypes = [...new Set(allCoordinates.map(c => c.coordinate.kta[0]))];
|
|
305
|
+
serviceTypes.forEach(serviceType => {
|
|
306
|
+
const serviceCoords = allCoordinates.filter(c => c.coordinate.kta[0] === serviceType);
|
|
307
|
+
const registries = [...new Set(serviceCoords.map(c => c.registryType))];
|
|
308
|
+
console.log(` ${serviceType}: ${serviceCoords.length} implementation(s) in ${registries.join(', ')} registr${registries.length === 1 ? 'y' : 'ies'}`);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
// Step 6: Demonstrate practical usage scenarios
|
|
312
|
+
console.log('\n6. Practical Usage Scenarios...\n');
|
|
313
|
+
|
|
314
|
+
// Scenario 1: System health check
|
|
315
|
+
console.log('š„ System Health Check:');
|
|
316
|
+
const criticalServices = ['Auth', 'Repository', 'Cache', 'Payment'];
|
|
317
|
+
criticalServices.forEach(service => {
|
|
318
|
+
const implementations = allCoordinates.filter(c => c.coordinate.kta.includes(service));
|
|
319
|
+
const status = implementations.length > 0 ? 'ā
Available' : 'ā Missing';
|
|
320
|
+
const details = implementations.length > 0 ? `(${implementations.length} implementation(s))` : '';
|
|
321
|
+
console.log(` ${service}: ${status} ${details}`);
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
// Scenario 2: Production readiness check
|
|
325
|
+
console.log('\nš Production Readiness Check:');
|
|
326
|
+
const productionCoords = allCoordinates.filter(c => c.coordinate.scopes.includes('production'));
|
|
327
|
+
const productionByRegistry = productionCoords.reduce((acc, c) => {
|
|
328
|
+
acc[c.registryType] = (acc[c.registryType] || 0) + 1;
|
|
329
|
+
return acc;
|
|
330
|
+
}, {} as Record<string, number>);
|
|
331
|
+
|
|
332
|
+
console.log(` Total production services: ${productionCoords.length}`);
|
|
333
|
+
Object.entries(productionByRegistry).forEach(([regType, count]) => {
|
|
334
|
+
console.log(` - ${regType}: ${count} production service(s)`);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
// Scenario 3: Development environment completeness
|
|
338
|
+
console.log('\nš» Development Environment Check:');
|
|
339
|
+
const devCoords = allCoordinates.filter(c => c.coordinate.scopes.includes('development'));
|
|
340
|
+
console.log(` Development services available: ${devCoords.length}`);
|
|
341
|
+
|
|
342
|
+
// Check if we have dev equivalents for production services
|
|
343
|
+
const prodServiceKeys = productionCoords.map(c => c.coordinate.kta.join('.'));
|
|
344
|
+
const devServiceKeys = devCoords.map(c => c.coordinate.kta.join('.'));
|
|
345
|
+
|
|
346
|
+
const missingDevServices = prodServiceKeys.filter(key => !devServiceKeys.includes(key));
|
|
347
|
+
if (missingDevServices.length > 0) {
|
|
348
|
+
console.log(' ā ļø Missing development equivalents for:');
|
|
349
|
+
missingDevServices.forEach(service => console.log(` - ${service}`));
|
|
350
|
+
} else {
|
|
351
|
+
console.log(' ā
All production services have development equivalents');
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
console.log('\n⨠RegistryHub coordinates discovery example completed!');
|
|
355
|
+
|
|
356
|
+
return {
|
|
357
|
+
totalCoordinates: allCoordinates.length,
|
|
358
|
+
coordinatesByRegistry,
|
|
359
|
+
registryTypes: hub.getRegisteredTypes(),
|
|
360
|
+
allCoordinates
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Export for testing
|
|
365
|
+
export { runRegistryHubCoordinatesExample };
|
|
366
|
+
|
|
367
|
+
// Run the example if this file is executed directly
|
|
368
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
369
|
+
runRegistryHubCoordinatesExample().catch(console.error);
|
|
370
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fjell/registry",
|
|
3
|
-
"version": "4.4.
|
|
3
|
+
"version": "4.4.9",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"registry",
|
|
6
6
|
"fjell"
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@eslint/eslintrc": "^3.3.1",
|
|
30
30
|
"@eslint/js": "^9.31.0",
|
|
31
|
-
"@swc/core": "^1.13.
|
|
31
|
+
"@swc/core": "^1.13.1",
|
|
32
32
|
"@tsconfig/recommended": "^1.0.10",
|
|
33
33
|
"@types/multer": "^2.0.0",
|
|
34
34
|
"@types/node": "^24.0.15",
|