@fjell/registry 4.4.5 → 4.4.6

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 (52) hide show
  1. package/README.md +546 -0
  2. package/dist/Coordinate.cjs +8 -5
  3. package/dist/Coordinate.d.ts +1 -1
  4. package/dist/Coordinate.js +8 -5
  5. package/dist/Instance.cjs +1 -1
  6. package/dist/Instance.d.ts +1 -1
  7. package/dist/Instance.js +1 -1
  8. package/dist/Registry.cjs +99 -90
  9. package/dist/Registry.d.ts +3 -42
  10. package/dist/Registry.js +99 -90
  11. package/dist/RegistryHub.cjs +78 -0
  12. package/dist/RegistryHub.d.ts +3 -0
  13. package/dist/RegistryHub.js +74 -0
  14. package/dist/errors/CoordinateError.cjs +70 -0
  15. package/dist/errors/CoordinateError.d.ts +28 -0
  16. package/dist/errors/CoordinateError.js +63 -0
  17. package/dist/errors/InstanceError.cjs +101 -0
  18. package/dist/errors/InstanceError.d.ts +42 -0
  19. package/dist/errors/InstanceError.js +92 -0
  20. package/dist/errors/RegistryError.cjs +82 -0
  21. package/dist/errors/RegistryError.d.ts +31 -0
  22. package/dist/errors/RegistryError.js +75 -0
  23. package/dist/errors/RegistryHubError.cjs +92 -0
  24. package/dist/errors/RegistryHubError.d.ts +39 -0
  25. package/dist/errors/RegistryHubError.js +84 -0
  26. package/dist/errors/index.d.ts +4 -0
  27. package/dist/index.cjs +501 -101
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.ts +3 -0
  30. package/dist/index.js +6 -1
  31. package/dist/types.d.ts +90 -0
  32. package/docs/TIMING_NODE_OPTIMIZATION.md +207 -0
  33. package/docs/TIMING_README.md +170 -0
  34. package/docs/memory-data/scaling-10-instances.json +526 -0
  35. package/docs/memory-data/scaling-100-instances.json +526 -0
  36. package/docs/memory-data/scaling-1000-instances.json +276 -0
  37. package/docs/memory-data/scaling-10000-instances.json +126 -0
  38. package/docs/memory-data/scaling-20-instances.json +526 -0
  39. package/docs/memory-data/scaling-200-instances.json +526 -0
  40. package/docs/memory-data/scaling-2000-instances.json +276 -0
  41. package/docs/memory-data/scaling-50-instances.json +526 -0
  42. package/docs/memory-data/scaling-500-instances.json +276 -0
  43. package/docs/memory-data/scaling-5000-instances.json +126 -0
  44. package/docs/memory-overhead.svg +120 -0
  45. package/docs/memory.md +430 -0
  46. package/docs/timing-range.svg +174 -0
  47. package/docs/timing.md +483 -0
  48. package/examples/README.md +187 -0
  49. package/examples/multi-level-keys.ts +374 -0
  50. package/examples/registry-hub-types.ts +437 -0
  51. package/examples/simple-example.ts +250 -0
  52. package/package.json +5 -3
package/README.md ADDED
@@ -0,0 +1,546 @@
1
+ # Fjell Registry
2
+
3
+ A comprehensive dependency injection and service location system for the Fjell ecosystem. The Registry provides a centralized way to register, scope, and retrieve service instances based on type hierarchies and contextual scopes.
4
+
5
+ ## Core Concepts
6
+
7
+ ### Instance
8
+ An `Instance` represents any registered service or component in the system. It consists of:
9
+ - **Coordinate**: Defines the service's identity (key types + scopes)
10
+ - **Registry**: Reference to the registry managing this instance
11
+
12
+ ```typescript
13
+ interface Instance<S extends string, L1 extends string = never, ...> {
14
+ coordinate: Coordinate<S, L1, L2, L3, L4, L5>;
15
+ registry: Registry;
16
+ }
17
+ ```
18
+
19
+ ### Coordinate
20
+ A `Coordinate` uniquely identifies an instance using:
21
+ - **Key Type Array (KTA)**: Hierarchical type identifiers (e.g., `['User', 'Profile']`)
22
+ - **Scopes**: Context qualifiers (e.g., `['firestore']`, `['postgresql']`)
23
+
24
+ This allows multiple implementations of the same service:
25
+ ```typescript
26
+ // Same User service, different storage backends
27
+ const firestoreUser = createCoordinate(['User'], ['firestore']);
28
+ const postgresUser = createCoordinate(['User'], ['postgresql']);
29
+ ```
30
+
31
+ ### Registry
32
+ The central service locator that:
33
+ - **Has a mandatory type identifier** (e.g., 'services', 'data', 'cache')
34
+ - Creates and registers instances atomically (no circular dependencies)
35
+ - Retrieves instances by type and scope
36
+ - Maintains a hierarchical tree of services
37
+
38
+ ```typescript
39
+ interface Registry {
40
+ readonly type: string; // Mandatory type identifier
41
+ createInstance: <...>(...) => Instance<...>;
42
+ register: (...) => void; // Deprecated
43
+ get: (...) => Instance | null;
44
+ instanceTree: InstanceTree;
45
+ }
46
+
47
+ // Create registries with their type
48
+ const serviceRegistry = createRegistry('services');
49
+ const dataRegistry = createRegistry('data');
50
+ const cacheRegistry = createRegistry('cache');
51
+ ```
52
+
53
+ ### RegistryHub
54
+ A higher-level registry that manages multiple Registry instances. The RegistryHub serves as a central hub where different registries can be organized automatically using their type property.
55
+
56
+ **Key Features:**
57
+ - **Automatic Registry Organization**: Registers registries using their built-in type property
58
+ - **Unified Access**: Single point of access to instances across all registries
59
+ - **Type Safety**: Maintains type safety while providing cross-registry access
60
+ - **Lifecycle Management**: Register, unregister, and manage multiple registries
61
+
62
+ ```typescript
63
+ interface RegistryHub {
64
+ registerRegistry: (registry: Registry) => void; // Uses registry.type automatically
65
+ get: (type: string, kta: string[], options?: { scopes?: string[] }) => Instance | null;
66
+ getRegistry: (type: string) => Registry | null;
67
+ getRegisteredTypes: () => string[];
68
+ unregisterRegistry: (type: string) => boolean;
69
+ }
70
+ ```
71
+
72
+ **Architecture:**
73
+ ```
74
+ RegistryHub
75
+ ├── Registry (type: 'services') → Auth, User, Payment services
76
+ ├── Registry (type: 'data') → Repositories, Data layers
77
+ ├── Registry (type: 'cache') → Cache implementations
78
+ └── Registry (type: 'integrations') → External APIs, webhooks
79
+ ```
80
+
81
+ ### InstanceFactory
82
+ A factory function that creates instances:
83
+ ```typescript
84
+ type InstanceFactory<S extends string, L1, L2, L3, L4, L5> = (
85
+ registry: Registry,
86
+ coordinate: Coordinate<S, L1, L2, L3, L4, L5>
87
+ ) => Instance<S, L1, L2, L3, L4, L5>;
88
+ ```
89
+
90
+ **Benefits:**
91
+ - ✅ No circular dependencies (factory receives populated registry + coordinate)
92
+ - ✅ Dependency injection friendly (factory can access other services)
93
+ - ✅ Atomic creation and registration
94
+ - ✅ Type-safe instance creation
95
+
96
+ ## Architecture
97
+
98
+ ```
99
+ createRegistry('services').createInstance(['User'], ['firestore'], factory)
100
+
101
+ 1. Creates Coordinate { kta: ['User'], scopes: ['firestore'] }
102
+ 2. Calls factory(registry, coordinate)
103
+ 3. Validates returned instance
104
+ 4. Registers instance automatically
105
+ 5. Returns ready-to-use instance
106
+ ```
107
+
108
+ **Registry Structure:**
109
+ ```
110
+ Registry (type: 'services')
111
+ ├── Instance Tree (by Key Types)
112
+ │ ├── User
113
+ │ │ ├── [ScopedInstance] scope: ['firestore'] ← Created via factory
114
+ │ │ └── [ScopedInstance] scope: ['postgresql'] ← Created via factory
115
+ │ └── User.Profile
116
+ │ ├── [ScopedInstance] scope: ['firestore']
117
+ │ └── [ScopedInstance] scope: ['postgresql']
118
+ └── Atomic Create+Register Logic
119
+ ```
120
+
121
+ **RegistryHub Structure:**
122
+ ```
123
+ RegistryHub
124
+ ├── Registry (type: 'services')
125
+ │ ├── User (multiple scopes)
126
+ │ ├── Auth (multiple scopes)
127
+ │ └── Payment (multiple scopes)
128
+ ├── Registry (type: 'data')
129
+ │ ├── UserRepository (multiple scopes)
130
+ │ └── OrderRepository (multiple scopes)
131
+ └── Registry (type: 'cache')
132
+ ├── UserCache (multiple scopes)
133
+ └── SessionCache (multiple scopes)
134
+ ```
135
+
136
+ ## Usage Patterns
137
+
138
+ ### 1. **Recommended: Registry-Managed Creation** ✅
139
+ ```typescript
140
+ const registry = createRegistry('services');
141
+
142
+ // Create and register instances atomically - no circular dependency!
143
+ const userService = registry.createInstance(['User'], ['firestore'], (registry, coordinate) => {
144
+ // Your instance implementation here
145
+ return {
146
+ coordinate,
147
+ registry,
148
+ // ... your service implementation
149
+ };
150
+ });
151
+
152
+ // Instance is automatically registered and ready to use
153
+ const retrievedService = registry.get(['User'], { scopes: ['firestore'] });
154
+ console.log(userService === retrievedService); // true
155
+ ```
156
+
157
+ ### 2. **RegistryHub: Managing Multiple Registries** ✅
158
+ ```typescript
159
+ const hub = createRegistryHub();
160
+
161
+ // Create domain-specific registries with their types
162
+ const serviceRegistry = createRegistry('services');
163
+ const dataRegistry = createRegistry('data');
164
+ const cacheRegistry = createRegistry('cache');
165
+
166
+ // Register registries in the hub - no type parameter needed!
167
+ hub.registerRegistry(serviceRegistry); // Uses 'services' from registry.type
168
+ hub.registerRegistry(dataRegistry); // Uses 'data' from registry.type
169
+ hub.registerRegistry(cacheRegistry); // Uses 'cache' from registry.type
170
+
171
+ // Create instances in specific registries
172
+ const authService = serviceRegistry.createInstance(['Auth'], ['jwt'], authFactory);
173
+ const userRepo = dataRegistry.createInstance(['User'], ['firestore'], repoFactory);
174
+ const userCache = cacheRegistry.createInstance(['User'], ['redis'], cacheFactory);
175
+
176
+ // Access instances through the hub - unified interface
177
+ const auth = hub.get('services', ['Auth'], { scopes: ['jwt'] });
178
+ const user = hub.get('data', ['User'], { scopes: ['firestore'] });
179
+ const cache = hub.get('cache', ['User'], { scopes: ['redis'] });
180
+
181
+ // Hub management
182
+ console.log(hub.getRegisteredTypes()); // ['services', 'data', 'cache']
183
+ const specificRegistry = hub.getRegistry('services');
184
+ hub.unregisterRegistry('cache'); // Remove if needed
185
+ ```
186
+
187
+ ### 3. Multiple Implementations with Scopes
188
+ ```typescript
189
+ const registry = createRegistry('data');
190
+
191
+ // Firestore implementation
192
+ const firestoreUser = registry.createInstance(['User'], ['firestore'], (registry, coordinate) => ({
193
+ coordinate,
194
+ registry,
195
+ save: async (user) => { /* firestore logic */ },
196
+ find: async (query) => { /* firestore logic */ }
197
+ }));
198
+
199
+ // PostgreSQL implementation
200
+ const postgresUser = registry.createInstance(['User'], ['postgresql'], (registry, coordinate) => ({
201
+ coordinate,
202
+ registry,
203
+ save: async (user) => { /* postgresql logic */ },
204
+ find: async (query) => { /* postgresql logic */ }
205
+ }));
206
+
207
+ // Context-aware retrieval
208
+ const prodService = registry.get(['User'], { scopes: ['firestore'] });
209
+ const devService = registry.get(['User'], { scopes: ['postgresql'] });
210
+ ```
211
+
212
+ ### 4. Hierarchical Services
213
+ ```typescript
214
+ const registry = createRegistry('services');
215
+
216
+ // Register nested services
217
+ const profileService = registry.createInstance(['User', 'Profile'], ['firestore'], factoryFunction);
218
+ const settingsService = registry.createInstance(['User', 'Settings'], ['postgresql'], factoryFunction);
219
+
220
+ // Retrieve nested services
221
+ const userProfile = registry.get(['User', 'Profile'], { scopes: ['firestore'] });
222
+ ```
223
+
224
+ ### 5. **Cross-Registry Dependencies with RegistryHub**
225
+ ```typescript
226
+ const hub = createRegistryHub();
227
+ const serviceRegistry = createRegistry('services');
228
+ const dataRegistry = createRegistry('data');
229
+
230
+ // Registries automatically use their type property
231
+ hub.registerRegistry(serviceRegistry); // → 'services'
232
+ hub.registerRegistry(dataRegistry); // → 'data'
233
+
234
+ // Service that depends on data layer
235
+ const orderService = serviceRegistry.createInstance(['Order'], ['business'], (registry, coordinate) => {
236
+ // Access data layer through hub
237
+ const userRepo = hub.get('data', ['User'], { scopes: ['firestore'] });
238
+ const orderRepo = hub.get('data', ['Order'], { scopes: ['firestore'] });
239
+
240
+ return {
241
+ coordinate,
242
+ registry,
243
+ createOrder: async (orderData) => {
244
+ const user = await userRepo.operations.findOne(orderData.userId);
245
+ return orderRepo.operations.create({ ...orderData, user });
246
+ }
247
+ };
248
+ });
249
+ ```
250
+
251
+ ### 6. ~~Legacy Registration~~ (Deprecated)
252
+ ```typescript
253
+ // OLD WAY - has circular dependency issue
254
+ const registry = createRegistry('legacy');
255
+ const userService = createInstance(registry, createCoordinate(['User'], ['firestore'])); // ❌ Circular!
256
+ registry.register(['User'], userService, { scopes: ['firestore'] });
257
+
258
+ // Use registry.createInstance() instead! ✅
259
+ ```
260
+
261
+ ### 7. Cascade Pattern
262
+ The Registry enables automatic service discovery:
263
+ ```typescript
264
+ // System receives an item and automatically finds the right service
265
+ function saveItem(item: Item) {
266
+ const registry = createRegistry('services');
267
+ const service = registry.get(item.getKeyTypes(), {
268
+ scopes: ['cache', 'fast']
269
+ }) || registry.get(item.getKeyTypes(), {
270
+ scopes: ['database']
271
+ });
272
+
273
+ return service.operations.save(item);
274
+ }
275
+ ```
276
+
277
+ ## RegistryHub Patterns
278
+
279
+ ### 1. **Domain-Driven Registry Organization**
280
+ ```typescript
281
+ const hub = createRegistryHub();
282
+
283
+ // Domain registries with explicit types
284
+ const userDomainRegistry = createRegistry('user-domain');
285
+ const orderDomainRegistry = createRegistry('order-domain');
286
+ const paymentDomainRegistry = createRegistry('payment-domain');
287
+ const notificationDomainRegistry = createRegistry('notification-domain');
288
+
289
+ // Register using their built-in types
290
+ hub.registerRegistry(userDomainRegistry); // → 'user-domain'
291
+ hub.registerRegistry(orderDomainRegistry); // → 'order-domain'
292
+ hub.registerRegistry(paymentDomainRegistry); // → 'payment-domain'
293
+ hub.registerRegistry(notificationDomainRegistry); // → 'notification-domain'
294
+
295
+ // Each domain manages its own services
296
+ const userService = hub.get('user-domain', ['User'], { scopes: ['api'] });
297
+ const orderService = hub.get('order-domain', ['Order'], { scopes: ['business'] });
298
+ const paymentGateway = hub.get('payment-domain', ['Gateway'], { scopes: ['stripe'] });
299
+ ```
300
+
301
+ ### 2. **Environment-Based Registry Management**
302
+ ```typescript
303
+ const hub = createRegistryHub();
304
+
305
+ if (process.env.NODE_ENV === 'production') {
306
+ const prodDataRegistry = createRegistry('data');
307
+ const redisRegistry = createRegistry('cache');
308
+ hub.registerRegistry(prodDataRegistry);
309
+ hub.registerRegistry(redisRegistry);
310
+ } else {
311
+ const devDataRegistry = createRegistry('data');
312
+ const memoryRegistry = createRegistry('cache');
313
+ hub.registerRegistry(devDataRegistry);
314
+ hub.registerRegistry(memoryRegistry);
315
+ }
316
+
317
+ // Same code works across environments
318
+ const userRepo = hub.get('data', ['User']);
319
+ const userCache = hub.get('cache', ['User']);
320
+ ```
321
+
322
+ ### 3. **Module-Based Registry Organization**
323
+ ```typescript
324
+ // Each module/library provides its own typed registry
325
+ import { createUserModuleRegistry } from '@myapp/user-module';
326
+ import { createOrderModuleRegistry } from '@myapp/order-module';
327
+ import { createPaymentModuleRegistry } from '@myapp/payment-module';
328
+
329
+ const hub = createRegistryHub();
330
+
331
+ // These functions return registries with proper types
332
+ const userRegistry = createUserModuleRegistry(); // Registry with type 'users'
333
+ const orderRegistry = createOrderModuleRegistry(); // Registry with type 'orders'
334
+ const paymentRegistry = createPaymentModuleRegistry(); // Registry with type 'payments'
335
+
336
+ // Auto-register using their types
337
+ hub.registerRegistry(userRegistry); // → 'users'
338
+ hub.registerRegistry(orderRegistry); // → 'orders'
339
+ hub.registerRegistry(paymentRegistry); // → 'payments'
340
+
341
+ // Cross-module integration
342
+ const orderService = hub.get('orders', ['OrderService']);
343
+ const paymentProcessor = hub.get('payments', ['Processor'], { scopes: ['stripe'] });
344
+ ```
345
+
346
+ ## Library Integration Patterns
347
+
348
+ ### fjell-lib Integration
349
+ ```typescript
350
+ // In fjell-lib
351
+ export const createServiceRegistry = () => createRegistry('fjell-lib');
352
+
353
+ // In applications
354
+ import { createServiceRegistry } from '@fjell/lib';
355
+ const hub = createRegistryHub();
356
+ hub.registerRegistry(createServiceRegistry()); // → 'fjell-lib'
357
+ ```
358
+
359
+ ### fjell-cache Integration
360
+ ```typescript
361
+ // In fjell-cache
362
+ export const createCacheRegistry = () => createRegistry('fjell-cache');
363
+
364
+ // In applications
365
+ import { createCacheRegistry } from '@fjell/cache';
366
+ const hub = createRegistryHub();
367
+ hub.registerRegistry(createCacheRegistry()); // → 'fjell-cache'
368
+ ```
369
+
370
+ ### fjell-client-api Integration
371
+ ```typescript
372
+ // In fjell-client-api
373
+ export const createClientApiRegistry = () => createRegistry('fjell-client-api');
374
+
375
+ // In applications
376
+ import { createClientApiRegistry } from '@fjell/client-api';
377
+ const hub = createRegistryHub();
378
+ hub.registerRegistry(createClientApiRegistry()); // → 'fjell-client-api'
379
+ ```
380
+
381
+ ## Design Benefits
382
+
383
+ 1. **Unified Service Location**: Single pattern across all Fjell libraries
384
+ 2. **Multiple Implementations**: Support Firestore, PostgreSQL, etc. for same types
385
+ 3. **Contextual Scoping**: Environment-aware service selection
386
+ 4. **Hierarchical Organization**: Natural type hierarchy support
387
+ 5. **Dependency Injection**: Clean separation of configuration and usage
388
+ 6. **Self-Documenting Registries**: Registry type is built-in, no external tracking needed
389
+ 7. **Cross-Registry Access**: Unified interface for accessing instances across multiple registries
390
+ 8. **Error Prevention**: Impossible to register a registry under the wrong type
391
+
392
+ ## Migration Strategy
393
+
394
+ ### Phase 1: Core Libraries
395
+ - ✅ fjell-registry (base implementation + RegistryHub with typed registries)
396
+ - 🔄 fjell-lib (create registry with type 'fjell-lib')
397
+ - 🔄 fjell-lib-sequelize (create registry with type 'fjell-lib-sequelize')
398
+ - 🔄 fjell-lib-firestore (create registry with type 'fjell-lib-firestore')
399
+
400
+ ### Phase 2: Service Libraries
401
+ - 🔄 fjell-cache (create registry with type 'fjell-cache')
402
+ - 🔄 fjell-client-api (create registry with type 'fjell-client-api')
403
+
404
+ ### Phase 3: UI Libraries (Future)
405
+ - fjell-express-router (create registry with type 'fjell-express-router')
406
+ - fjell-providers (create registry with type 'fjell-providers')
407
+
408
+ ### Phase 4: RegistryHub Integration
409
+ - Applications use RegistryHub to organize all typed registries
410
+ - Libraries export factory functions that create properly typed registries
411
+ - Cross-module dependency management through hub
412
+
413
+ ## Configuration Examples
414
+
415
+ ### Multi-Database Setup with RegistryHub
416
+ ```typescript
417
+ const hub = createRegistryHub();
418
+
419
+ // Create typed registries
420
+ const servicesRegistry = createRegistry('services');
421
+ const firestoreDataRegistry = createRegistry('firestore-data');
422
+ const postgresDataRegistry = createRegistry('postgres-data');
423
+
424
+ // Register Firestore services
425
+ firestoreDataRegistry.createInstance(['User'], ['production'], firestoreUserFactory);
426
+ firestoreDataRegistry.createInstance(['Order'], ['production'], firestoreOrderFactory);
427
+
428
+ // Register PostgreSQL services
429
+ postgresDataRegistry.createInstance(['User'], ['development'], postgresUserFactory);
430
+ postgresDataRegistry.createInstance(['Analytics'], [], postgresAnalyticsFactory);
431
+
432
+ // Register business services
433
+ servicesRegistry.createInstance(['UserService'], ['business'], userServiceFactory);
434
+ servicesRegistry.createInstance(['OrderService'], ['business'], orderServiceFactory);
435
+
436
+ // Register all typed registries
437
+ hub.registerRegistry(servicesRegistry); // → 'services'
438
+ hub.registerRegistry(firestoreDataRegistry); // → 'firestore-data'
439
+ hub.registerRegistry(postgresDataRegistry); // → 'postgres-data'
440
+
441
+ // Context-aware retrieval through hub
442
+ const userService = hub.get('services', ['UserService']);
443
+ const userRepo = hub.get('firestore-data', ['User'], { scopes: ['production'] });
444
+ const analyticsRepo = hub.get('postgres-data', ['Analytics']);
445
+ ```
446
+
447
+ ### Service Composition with RegistryHub
448
+ ```typescript
449
+ const hub = createRegistryHub();
450
+
451
+ // Create and register typed registries
452
+ const dataRegistry = createRegistry('data');
453
+ const servicesRegistry = createRegistry('services');
454
+ const integrationsRegistry = createRegistry('integrations');
455
+
456
+ hub.registerRegistry(dataRegistry); // → 'data'
457
+ hub.registerRegistry(servicesRegistry); // → 'services'
458
+ hub.registerRegistry(integrationsRegistry); // → 'integrations'
459
+
460
+ // Complex service with cross-registry dependencies
461
+ const orderService = servicesRegistry.createInstance(['Order'], ['business'], (registry, coordinate) => {
462
+ return {
463
+ coordinate,
464
+ registry,
465
+ createOrder: async (orderData) => {
466
+ const userRepo = hub.get('data', ['User']);
467
+ const paymentService = hub.get('integrations', ['Payment']);
468
+ const inventoryService = hub.get('services', ['Inventory']);
469
+
470
+ // Business logic using services from different typed registries
471
+ const user = await userRepo.operations.findOne(orderData.userId);
472
+ const payment = await paymentService.processPayment(orderData.payment);
473
+ const inventory = await inventoryService.reserveItems(orderData.items);
474
+
475
+ return { user, payment, inventory };
476
+ }
477
+ };
478
+ });
479
+ ```
480
+
481
+ This architecture provides the foundation for a scalable, maintainable service ecosystem where components can be developed independently but work together seamlessly. The RegistryHub with typed registries extends this capability by enabling better organization and automatic management of multiple registries across different domains or modules.
482
+
483
+ ## Memory Profiling and Performance
484
+
485
+ ### Memory Overhead Testing
486
+
487
+ The Fjell Registry includes comprehensive memory profiling to ensure optimal performance in production environments. The memory tests measure the actual memory footprint of core infrastructure components and provide automated documentation.
488
+
489
+ #### Running Memory Tests
490
+
491
+ ```bash
492
+ # Run memory tests and generate documentation
493
+ pnpm run test:memory
494
+ ```
495
+
496
+ #### Memory Test Coverage
497
+
498
+ The memory tests analyze:
499
+
500
+ - **Registry Infrastructure**: Memory overhead of creating Registry and RegistryHub instances
501
+ - **Instance Creation**: Memory cost per instance including coordinates and storage
502
+ - **Tree Structure**: Memory efficiency of the instance tree data structures
503
+ - **Scoped Instances**: Additional memory overhead for scoped instance management
504
+ - **Scaling Behavior**: Memory usage from 10 to 100,000 instances with detailed scaling analysis
505
+
506
+ #### Comprehensive Scaling Tests
507
+
508
+ Memory tests include scaling analysis across multiple instance counts:
509
+
510
+ - **Small Scale**: 10, 20, 50, 100, 200 instances
511
+ - **Medium Scale**: 500, 1,000, 2,000, 5,000 instances
512
+ - **Large Scale**: 10,000, 20,000, 50,000, 100,000 instances
513
+
514
+ #### Memory Constraints
515
+
516
+ Current memory constraints ensure optimal performance:
517
+
518
+ - **Registry Creation**: ≤ 83 kB per registry
519
+ - **Instance Creation**: ≤ 2.4 kB per instance
520
+ - **Coordinate Objects**: ≤ 1.5 kB per coordinate
521
+ - **Tree Nodes**: ≤ 3.9 kB per tree node
522
+ - **Complex Instances**: ≤ 4.9 kB for multi-level instances
523
+
524
+ #### Generated Documentation
525
+
526
+ Memory tests automatically generate `./docs/memory.md` with:
527
+
528
+ - Detailed memory usage analysis with human-readable units (kB, MB)
529
+ - Comprehensive scaling analysis from 10 to 100,000 instances
530
+ - Performance characteristics and scaling efficiency metrics
531
+ - Memory growth patterns and per-instance consistency analysis
532
+ - Efficiency metrics and optimization recommendations
533
+ - Troubleshooting guide for memory issues
534
+ - Constraint definitions and thresholds
535
+
536
+ #### Key Performance Characteristics
537
+
538
+ - **Linear Scaling**: Memory usage scales predictably from 10 to 100,000 instances
539
+ - **Consistent Per-Instance Cost**: ~1.9-2.4 kB per instance across all scales
540
+ - **Efficient Storage**: Optimized tree structures minimize overhead
541
+ - **High-Volume Performance**: 100,000 instances use only ~189 MB (excellent memory efficiency)
542
+ - **Scope Efficiency**: Minimal additional memory for scoped instances
543
+ - **Fast Creation**: Instance creation remains fast even at large scales
544
+ - **Human-Readable Reporting**: All memory measurements displayed in kB/MB format
545
+
546
+ Use these metrics to monitor memory usage in production and ensure the registry infrastructure remains performant as your application scales from prototype to enterprise levels.
@@ -5,25 +5,28 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
5
5
  const logger$1 = require('./logger.cjs');
6
6
 
7
7
  const logger = logger$1.default.get("Coordinate");
8
- const createCoordinate = (kta, scopes)=>{
8
+ const createCoordinate = (kta, scopes = [])=>{
9
+ const ktArray = Array.isArray(kta) ? kta : [
10
+ kta
11
+ ];
9
12
  const toString = ()=>{
10
13
  logger.debug("toString", {
11
14
  kta,
12
15
  scopes
13
16
  });
14
- return `${kta.join(', ')} - ${scopes.join(', ')}`;
17
+ return `${ktArray.join(', ')} - ${scopes.join(', ')}`;
15
18
  };
16
19
  logger.debug("createCoordinate", {
17
- kta,
20
+ kta: ktArray,
18
21
  scopes,
19
22
  toString
20
23
  });
21
24
  return {
22
- kta,
25
+ kta: ktArray,
23
26
  scopes,
24
27
  toString
25
28
  };
26
29
  };
27
30
 
28
31
  exports.createCoordinate = createCoordinate;
29
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29vcmRpbmF0ZS5janMiLCJzb3VyY2VzIjpbXSwic291cmNlc0NvbnRlbnQiOltdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzsifQ==
32
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29vcmRpbmF0ZS5janMiLCJzb3VyY2VzIjpbXSwic291cmNlc0NvbnRlbnQiOltdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzsifQ==
@@ -4,4 +4,4 @@ export interface Coordinate<S extends string, L1 extends string = never, L2 exte
4
4
  scopes: string[];
5
5
  toString: () => string;
6
6
  }
7
- export declare const createCoordinate: <S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never>(kta: ItemTypeArray<S, L1, L2, L3, L4, L5>, scopes: string[]) => Coordinate<S, L1, L2, L3, L4, L5>;
7
+ export declare const createCoordinate: <S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never>(kta: ItemTypeArray<S, L1, L2, L3, L4, L5> | S, scopes?: string[]) => Coordinate<S, L1, L2, L3, L4, L5>;
@@ -1,25 +1,28 @@
1
1
  import LibLogger from './logger.js';
2
2
 
3
3
  const logger = LibLogger.get("Coordinate");
4
- const createCoordinate = (kta, scopes)=>{
4
+ const createCoordinate = (kta, scopes = [])=>{
5
+ const ktArray = Array.isArray(kta) ? kta : [
6
+ kta
7
+ ];
5
8
  const toString = ()=>{
6
9
  logger.debug("toString", {
7
10
  kta,
8
11
  scopes
9
12
  });
10
- return `${kta.join(', ')} - ${scopes.join(', ')}`;
13
+ return `${ktArray.join(', ')} - ${scopes.join(', ')}`;
11
14
  };
12
15
  logger.debug("createCoordinate", {
13
- kta,
16
+ kta: ktArray,
14
17
  scopes,
15
18
  toString
16
19
  });
17
20
  return {
18
- kta,
21
+ kta: ktArray,
19
22
  scopes,
20
23
  toString
21
24
  };
22
25
  };
23
26
 
24
27
  export { createCoordinate };
25
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29vcmRpbmF0ZS5qcyIsInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W10sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7In0=
28
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29vcmRpbmF0ZS5qcyIsInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W10sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7In0=
package/dist/Instance.cjs CHANGED
@@ -5,7 +5,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
5
5
  const logger$1 = require('./logger.cjs');
6
6
 
7
7
  const logger = logger$1.default.get("Instance");
8
- const createInstance = (coordinate, registry)=>{
8
+ const createInstance = (registry, coordinate)=>{
9
9
  logger.debug("createInstance", {
10
10
  coordinate,
11
11
  registry
@@ -21,5 +21,5 @@ export interface Instance<S extends string, L1 extends string = never, L2 extend
21
21
  /** The registry object that manages the registration and lookup of model instances */
22
22
  registry: Registry;
23
23
  }
24
- export declare const createInstance: <S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never>(coordinate: Coordinate<S, L1, L2, L3, L4, L5>, registry: Registry) => Instance<S, L1, L2, L3, L4, L5>;
24
+ export declare const createInstance: <S extends string, L1 extends string = never, L2 extends string = never, L3 extends string = never, L4 extends string = never, L5 extends string = never>(registry: Registry, coordinate: Coordinate<S, L1, L2, L3, L4, L5>) => Instance<S, L1, L2, L3, L4, L5>;
25
25
  export declare const isInstance: (instance: any) => instance is Instance<any, any, any, any, any, any>;
package/dist/Instance.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import LibLogger from './logger.js';
2
2
 
3
3
  const logger = LibLogger.get("Instance");
4
- const createInstance = (coordinate, registry)=>{
4
+ const createInstance = (registry, coordinate)=>{
5
5
  logger.debug("createInstance", {
6
6
  coordinate,
7
7
  registry