@fjell/registry 4.4.52 โ†’ 4.4.54

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 (51) hide show
  1. package/package.json +4 -4
  2. package/API.md +0 -62
  3. package/GETTING_STARTED.md +0 -69
  4. package/build.js +0 -38
  5. package/docs/README.md +0 -74
  6. package/docs/TIMING_NODE_OPTIMIZATION.md +0 -207
  7. package/docs/TIMING_README.md +0 -170
  8. package/docs/docs.config.ts +0 -114
  9. package/docs/index.html +0 -26
  10. package/docs/package-lock.json +0 -5129
  11. package/docs/package.json +0 -34
  12. package/docs/public/404.html +0 -53
  13. package/docs/public/GETTING_STARTED.md +0 -69
  14. package/docs/public/README.md +0 -623
  15. package/docs/public/TIMING_NODE_OPTIMIZATION.md +0 -207
  16. package/docs/public/api.md +0 -62
  17. package/docs/public/client-api-overview.md +0 -137
  18. package/docs/public/configuration.md +0 -759
  19. package/docs/public/error-handling/README.md +0 -356
  20. package/docs/public/error-handling/network-errors.md +0 -485
  21. package/docs/public/examples/coordinates-example.ts +0 -253
  22. package/docs/public/examples/multi-level-keys.ts +0 -374
  23. package/docs/public/examples/registry-hub-coordinates-example.ts +0 -370
  24. package/docs/public/examples/registry-hub-types.ts +0 -437
  25. package/docs/public/examples/simple-example.ts +0 -250
  26. package/docs/public/examples-README.md +0 -241
  27. package/docs/public/fjell-icon.svg +0 -1
  28. package/docs/public/icon.png +0 -0
  29. package/docs/public/icon2.png +0 -0
  30. package/docs/public/memory-overhead.svg +0 -120
  31. package/docs/public/memory.md +0 -430
  32. package/docs/public/operations/README.md +0 -121
  33. package/docs/public/operations/all.md +0 -325
  34. package/docs/public/operations/create.md +0 -415
  35. package/docs/public/operations/get.md +0 -389
  36. package/docs/public/package.json +0 -63
  37. package/docs/public/pano.png +0 -0
  38. package/docs/public/pano2.png +0 -0
  39. package/docs/public/timing-range.svg +0 -176
  40. package/docs/public/timing.md +0 -483
  41. package/docs/timing-range.svg +0 -174
  42. package/docs/vitest.config.ts +0 -14
  43. package/examples/README.md +0 -241
  44. package/examples/coordinates-example.ts +0 -253
  45. package/examples/multi-level-keys.ts +0 -382
  46. package/examples/registry-hub-coordinates-example.ts +0 -370
  47. package/examples/registry-hub-types.ts +0 -437
  48. package/examples/registry-statistics-example.ts +0 -264
  49. package/examples/simple-example.ts +0 -250
  50. package/tsconfig.docs.json +0 -28
  51. package/vitest.config.ts +0 -22
@@ -1,253 +0,0 @@
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
- }
@@ -1,374 +0,0 @@
1
- /**
2
- * Multi-Level Key Type Arrays - Working Example
3
- *
4
- * This example demonstrates how Registry supports hierarchical key paths with actual implementations:
5
- * - ['user'] - Single level (SQL vs NoSQL implementations)
6
- * - ['user', 'profile'] - Two levels (S3 vs Local storage implementations)
7
- * - ['user', 'profile', 'preference'] - Three levels (Redis implementation)
8
- * - ['task'] - Another single level (PostgreSQL vs MongoDB implementations)
9
- *
10
- * Run this example with: npx tsx examples/multi-level-keys.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
- import type { Registry } from '../src/types';
20
-
21
- // Helper function to require a service (throw if not found)
22
- function requireService(registry: Registry, keyPath: string[], options?: { scopes?: string[] }): any {
23
- const result = registry.get(keyPath, options);
24
- if (!result) {
25
- throw new Error(`Required service '${keyPath.join('.')}' not found`);
26
- }
27
- return result;
28
- }
29
-
30
- // ===== Service Interface Definitions =====
31
-
32
- interface UserService {
33
- id: string;
34
- name: string;
35
- email: string;
36
- save(): Promise<void>;
37
- findById(id: string): Promise<UserService | null>;
38
- }
39
-
40
- interface UserProfileService {
41
- userId: string;
42
- avatar: string;
43
- bio: string;
44
- updateProfile(data: Partial<UserProfileService>): Promise<void>;
45
- }
46
-
47
- interface UserPreferenceService {
48
- userId: string;
49
- theme: 'light' | 'dark';
50
- notifications: boolean;
51
- updatePreferences(prefs: Partial<UserPreferenceService>): Promise<void>;
52
- }
53
-
54
- interface TaskService {
55
- id: string;
56
- title: string;
57
- completed: boolean;
58
- markComplete(): Promise<void>;
59
- createTask(data: { title: string; completed?: boolean }): Promise<TaskService>;
60
- }
61
-
62
- // ===== Service Interface Map (for documentation) =====
63
- // In a real app, these would map key paths to their interface types:
64
- // ['user'] -> UserService
65
- // ['user', 'profile'] -> UserProfileService
66
- // ['user', 'profile', 'preference'] -> UserPreferenceService
67
- // ['task'] -> TaskService
68
-
69
- // ===== Service Implementations =====
70
-
71
- class SqlUserService implements UserService {
72
- constructor(public id: string, public name: string, public email: string) { }
73
-
74
- async save(): Promise<void> {
75
- console.log(`[SQL] Saving user ${this.name} to database`);
76
- }
77
-
78
- async findById(id: string): Promise<UserService | null> {
79
- console.log(`[SQL] Finding user by ID: ${id}`);
80
- if (id === this.id) return this;
81
- return null;
82
- }
83
- }
84
-
85
- class NoSqlUserService implements UserService {
86
- constructor(public id: string, public name: string, public email: string) { }
87
-
88
- async save(): Promise<void> {
89
- console.log(`[NoSQL] Saving user ${this.name} to document store`);
90
- }
91
-
92
- async findById(id: string): Promise<UserService | null> {
93
- console.log(`[NoSQL] Finding user by ID: ${id}`);
94
- if (id === this.id) return this;
95
- return null;
96
- }
97
- }
98
-
99
- class S3ProfileService implements UserProfileService {
100
- constructor(public userId: string, public avatar: string, public bio: string) { }
101
-
102
- async updateProfile(data: Partial<UserProfileService>): Promise<void> {
103
- console.log(`[S3] Updating profile for user ${this.userId}:`, data);
104
- Object.assign(this, data);
105
- }
106
- }
107
-
108
- class LocalProfileService implements UserProfileService {
109
- constructor(public userId: string, public avatar: string, public bio: string) { }
110
-
111
- async updateProfile(data: Partial<UserProfileService>): Promise<void> {
112
- console.log(`[Local] Updating profile for user ${this.userId}:`, data);
113
- Object.assign(this, data);
114
- }
115
- }
116
-
117
- class RedisPreferenceService implements UserPreferenceService {
118
- constructor(
119
- public userId: string,
120
- public theme: 'light' | 'dark' = 'light',
121
- public notifications: boolean = true
122
- ) { }
123
-
124
- async updatePreferences(prefs: Partial<UserPreferenceService>): Promise<void> {
125
- console.log(`[Redis] Updating preferences for user ${this.userId}:`, prefs);
126
- Object.assign(this, prefs);
127
- }
128
- }
129
-
130
- class PostgreSqlTaskService implements TaskService {
131
- constructor(public id: string, public title: string, public completed: boolean = false) { }
132
-
133
- async markComplete(): Promise<void> {
134
- console.log(`[PostgreSQL] Marking task "${this.title}" as complete`);
135
- this.completed = true;
136
- }
137
-
138
- async createTask(data: { title: string; completed?: boolean }): Promise<TaskService> {
139
- console.log(`[PostgreSQL] Creating new task: ${data.title}`);
140
- const newId = Math.random().toString(36).substr(2, 9);
141
- return new PostgreSqlTaskService(newId, data.title, data.completed ?? false);
142
- }
143
- }
144
-
145
- class MongoTaskService implements TaskService {
146
- constructor(public id: string, public title: string, public completed: boolean = false) { }
147
-
148
- async markComplete(): Promise<void> {
149
- console.log(`[MongoDB] Marking task "${this.title}" as complete`);
150
- this.completed = true;
151
- }
152
-
153
- async createTask(data: { title: string; completed?: boolean }): Promise<TaskService> {
154
- console.log(`[MongoDB] Creating new task: ${data.title}`);
155
- const newId = Math.random().toString(36).substr(2, 9);
156
- return new MongoTaskService(newId, data.title, data.completed ?? false);
157
- }
158
- }
159
-
160
- // ===== Working Example =====
161
-
162
- export async function runMultiLevelKeysExample(): Promise<void> {
163
- console.log('๐Ÿš€ Registry Multi-Level Keys - Working Example');
164
- console.log('');
165
-
166
- // Create real registry for demonstration
167
- const registry = createRegistry('multi-level-demo');
168
-
169
- // ===== Register implementations with different scopes =====
170
-
171
- console.log('๐Ÿ“ Registering services...');
172
- console.log('');
173
-
174
- // Single level - User service with different database implementations
175
- registry.createInstance(['user'], ['sql', 'prod'], (coordinate, context) => {
176
- const service = new SqlUserService('1', 'John Doe', 'john@example.com');
177
- const instance = createInstance(context.registry, coordinate);
178
- (instance as any).save = service.save.bind(service);
179
- (instance as any).findById = service.findById.bind(service);
180
- (instance as any).id = service.id;
181
- (instance as any).name = service.name;
182
- (instance as any).email = service.email;
183
- return instance;
184
- });
185
-
186
- registry.createInstance(['user'], ['nosql', 'dev'], (coordinate, context) => {
187
- const service = new NoSqlUserService('1', 'John Doe', 'john@example.com');
188
- const instance = createInstance(context.registry, coordinate);
189
- (instance as any).save = service.save.bind(service);
190
- (instance as any).findById = service.findById.bind(service);
191
- (instance as any).id = service.id;
192
- (instance as any).name = service.name;
193
- (instance as any).email = service.email;
194
- return instance;
195
- });
196
-
197
- // Two levels - Profile service with different storage implementations
198
- registry.createInstance(['user', 'profile'], ['s3', 'prod'], (coordinate, context) => {
199
- const service = new S3ProfileService('1', 'avatar.jpg', 'Software developer');
200
- const instance = createInstance(context.registry, coordinate);
201
- (instance as any).updateProfile = service.updateProfile.bind(service);
202
- (instance as any).userId = service.userId;
203
- (instance as any).avatar = service.avatar;
204
- (instance as any).bio = service.bio;
205
- return instance;
206
- });
207
-
208
- registry.createInstance(['user', 'profile'], ['local', 'dev'], (coordinate, context) => {
209
- const service = new LocalProfileService('1', 'avatar.jpg', 'Software developer');
210
- const instance = createInstance(context.registry, coordinate);
211
- (instance as any).updateProfile = service.updateProfile.bind(service);
212
- (instance as any).userId = service.userId;
213
- (instance as any).avatar = service.avatar;
214
- (instance as any).bio = service.bio;
215
- return instance;
216
- });
217
-
218
- // Three levels - Preferences (single implementation)
219
- registry.createInstance(['user', 'profile', 'preference'], [], (coordinate, context) => {
220
- const service = new RedisPreferenceService('1', 'dark', true);
221
- const instance = createInstance(context.registry, coordinate);
222
- (instance as any).updatePreferences = service.updatePreferences.bind(service);
223
- (instance as any).userId = service.userId;
224
- (instance as any).theme = service.theme;
225
- (instance as any).notifications = service.notifications;
226
- return instance;
227
- });
228
-
229
- // Single level - Task service with different database implementations
230
- registry.createInstance(['task'], ['postgresql'], (coordinate, context) => {
231
- const service = new PostgreSqlTaskService('task-1', 'Write documentation', false);
232
- const instance = createInstance(context.registry, coordinate);
233
- (instance as any).markComplete = service.markComplete.bind(service);
234
- (instance as any).createTask = service.createTask.bind(service);
235
- (instance as any).id = service.id;
236
- (instance as any).title = service.title;
237
- (instance as any).completed = service.completed;
238
- return instance;
239
- });
240
-
241
- registry.createInstance(['task'], ['mongodb'], (coordinate, context) => {
242
- const service = new MongoTaskService('task-1', 'Write documentation', false);
243
- const instance = createInstance(context.registry, coordinate);
244
- (instance as any).markComplete = service.markComplete.bind(service);
245
- (instance as any).createTask = service.createTask.bind(service);
246
- (instance as any).id = service.id;
247
- (instance as any).title = service.title;
248
- (instance as any).completed = service.completed;
249
- return instance;
250
- });
251
-
252
- console.log('โœ… All services registered successfully!');
253
- console.log('');
254
-
255
- // ===== Demonstrate environment-based selection =====
256
-
257
- console.log('๐Ÿ”„ Environment-based service selection:');
258
- console.log('');
259
-
260
- // Production environment
261
- const prodUser = registry.get(['user'], { scopes: ['prod'] });
262
- const prodProfile = registry.get(['user', 'profile'], { scopes: ['prod'] });
263
-
264
- if (prodUser && prodProfile) {
265
- console.log('๐Ÿญ Production Environment:');
266
- await (prodUser as any).save();
267
- await (prodProfile as any).updateProfile({ bio: 'Senior developer' });
268
- console.log('');
269
- }
270
-
271
- // Development environment
272
- const devUser = registry.get(['user'], { scopes: ['dev'] });
273
- const devProfile = registry.get(['user', 'profile'], { scopes: ['dev'] });
274
-
275
- if (devUser && devProfile) {
276
- console.log('๐Ÿงช Development Environment:');
277
- await (devUser as any).save();
278
- await (devProfile as any).updateProfile({ bio: 'Junior developer' });
279
- console.log('');
280
- }
281
-
282
- // ===== Demonstrate multi-level access =====
283
-
284
- console.log('๐Ÿ—๏ธ Multi-level service access:');
285
- console.log('');
286
-
287
- // Three-level access - preferences (no scope needed, single implementation)
288
- const preferences = requireService(registry, ['user', 'profile', 'preference']);
289
- console.log('๐Ÿ“ฑ User preferences:');
290
- console.log(` Theme: ${(preferences as any).theme}, Notifications: ${(preferences as any).notifications}`);
291
- await (preferences as any).updatePreferences({ theme: 'light' });
292
- console.log('');
293
-
294
- // ===== Demonstrate different implementations for same interface =====
295
-
296
- console.log('๐Ÿ’พ Database implementation selection:');
297
- console.log('');
298
-
299
- const pgTask = registry.get(['task'], { scopes: ['postgresql'] });
300
- const mongoTask = registry.get(['task'], { scopes: ['mongodb'] });
301
-
302
- if (pgTask) {
303
- console.log('๐Ÿ˜ PostgreSQL Task Implementation:');
304
- await (pgTask as any).markComplete();
305
- const newTask = await (pgTask as any).createTask({ title: 'Add tests', completed: false });
306
- console.log(` Created task: ${(newTask as any).title} (ID: ${(newTask as any).id})`);
307
- console.log('');
308
- }
309
-
310
- if (mongoTask) {
311
- console.log('๐Ÿƒ MongoDB Task Implementation:');
312
- await (mongoTask as any).markComplete();
313
- const newTask = await (mongoTask as any).createTask({ title: 'Deploy app', completed: false });
314
- console.log(` Created task: ${(newTask as any).title} (ID: ${(newTask as any).id})`);
315
- console.log('');
316
- }
317
-
318
- // ===== Demonstrate type safety =====
319
-
320
- console.log('๐Ÿ”’ Type Safety in Action:');
321
- console.log('');
322
-
323
- // In a real app, TypeScript would know the exact return types
324
- const typedUser = registry.get(['user'], { scopes: ['sql'] });
325
- const typedProfile = registry.get(['user', 'profile'], { scopes: ['s3'] });
326
- const typedPrefs = requireService(registry, ['user', 'profile', 'preference']);
327
- const typedTask = registry.get(['task'], { scopes: ['postgresql'] });
328
-
329
- console.log('โœ… All services retrieved successfully!');
330
- console.log(` User service type: ${typedUser?.constructor.name}`);
331
- console.log(` Profile service type: ${typedProfile?.constructor.name}`);
332
- console.log(` Preference service type: ${typedPrefs.constructor.name}`);
333
- console.log(` Task service type: ${typedTask?.constructor.name}`);
334
- console.log('');
335
-
336
- // ===== Demonstrate error handling =====
337
-
338
- console.log('โš ๏ธ Error handling:');
339
- console.log('');
340
-
341
- // This will throw an error (not found)
342
- try {
343
- const missingService = registry.get(['user'], { scopes: ['nonexistent'] });
344
- console.log(`Missing service with wrong scope: ${missingService}`);
345
- } catch (error: any) {
346
- console.log(`โŒ Service with wrong scope throws error: ${error.message}`);
347
- }
348
-
349
- // This will throw an error
350
- try {
351
- requireService(registry, ['nonexistent', 'service']);
352
- } catch (error: any) {
353
- console.log(`โŒ Caught expected error: ${error.message}`);
354
- }
355
-
356
- console.log('');
357
- console.log('๐ŸŽ‰ Multi-level keys example completed successfully!');
358
- console.log('');
359
- console.log('Key takeaways:');
360
- console.log('โ€ข Each key path has its own consistent interface type');
361
- console.log('โ€ข Scopes allow multiple implementations of the same interface');
362
- console.log('โ€ข TypeScript provides full type safety for all operations');
363
- console.log('โ€ข Services can be organized hierarchically while remaining independent');
364
- console.log('โ€ข Perfect for microservices, A/B testing, and environment-specific implementations');
365
- }
366
-
367
- // Run the example when executed directly
368
- if (typeof process !== 'undefined' && process.argv?.[1]?.includes('multi-level-keys')) {
369
- runMultiLevelKeysExample().catch(console.error);
370
- }
371
-
372
- export default {
373
- runMultiLevelKeysExample
374
- };