@fjell/registry 4.4.7 → 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.
Files changed (54) hide show
  1. package/README.md +81 -4
  2. package/dist/Registry.cjs +20 -1
  3. package/dist/Registry.js +20 -1
  4. package/dist/RegistryHub.cjs +17 -1
  5. package/dist/RegistryHub.js +17 -1
  6. package/dist/index.cjs +35 -0
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/types.d.ts +15 -0
  9. package/docs/README.md +74 -0
  10. package/docs/index.html +17 -0
  11. package/docs/memory-data/scaling-10-instances.json +206 -206
  12. package/docs/memory-data/scaling-100-instances.json +206 -206
  13. package/docs/memory-data/scaling-1000-instances.json +108 -108
  14. package/docs/memory-data/scaling-10000-instances.json +49 -49
  15. package/docs/memory-data/scaling-20-instances.json +208 -208
  16. package/docs/memory-data/scaling-200-instances.json +201 -201
  17. package/docs/memory-data/scaling-2000-instances.json +107 -107
  18. package/docs/memory-data/scaling-50-instances.json +206 -206
  19. package/docs/memory-data/scaling-500-instances.json +108 -108
  20. package/docs/memory-data/scaling-5000-instances.json +49 -49
  21. package/docs/memory-overhead.svg +17 -17
  22. package/docs/memory.md +111 -111
  23. package/docs/package.json +35 -0
  24. package/docs/public/README.md +623 -0
  25. package/docs/public/TIMING_NODE_OPTIMIZATION.md +207 -0
  26. package/docs/public/examples/coordinates-example.ts +253 -0
  27. package/docs/public/examples/multi-level-keys.ts +374 -0
  28. package/docs/public/examples/registry-hub-coordinates-example.ts +370 -0
  29. package/docs/public/examples/registry-hub-types.ts +437 -0
  30. package/docs/public/examples/simple-example.ts +250 -0
  31. package/docs/public/examples-README.md +222 -0
  32. package/docs/public/fjell-icon.svg +1 -0
  33. package/docs/public/icon.png +0 -0
  34. package/docs/public/icon2.png +0 -0
  35. package/docs/public/memory-overhead.svg +120 -0
  36. package/docs/public/memory.md +430 -0
  37. package/docs/public/pano.png +0 -0
  38. package/docs/public/pano2.png +0 -0
  39. package/docs/public/timing-range.svg +176 -0
  40. package/docs/public/timing.md +483 -0
  41. package/docs/src/App.css +1175 -0
  42. package/docs/src/App.test.tsx +50 -0
  43. package/docs/src/App.tsx +583 -0
  44. package/docs/src/index.css +40 -0
  45. package/docs/src/main.tsx +10 -0
  46. package/docs/src/test/setup.ts +1 -0
  47. package/docs/timing-range.svg +41 -41
  48. package/docs/timing.md +101 -101
  49. package/docs/tsconfig.node.json +13 -0
  50. package/docs/vitest.config.ts +14 -0
  51. package/examples/README.md +35 -0
  52. package/examples/coordinates-example.ts +253 -0
  53. package/examples/registry-hub-coordinates-example.ts +370 -0
  54. package/package.json +1 -1
@@ -0,0 +1,207 @@
1
+ # Node.js Optimization for Timing Tests
2
+
3
+ This document outlines Node.js runtime parameters that can be tuned to minimize interference and improve timing test accuracy.
4
+
5
+ ## Quick Start: Optimized Timing Test
6
+
7
+ ```bash
8
+ pnpm run test:timing:optimized
9
+ ```
10
+
11
+ This runs timing tests with pre-configured optimal Node.js flags.
12
+
13
+ ## Key Node.js Optimization Flags
14
+
15
+ ### Memory Management
16
+
17
+ #### `--max-old-space-size=8192`
18
+ - **Purpose**: Increases maximum heap size to 8GB (default ~1.4GB)
19
+ - **Benefit**: Prevents garbage collection during test runs
20
+ - **Why 8GB**: Provides ample headroom for 100 rounds × multiple tree sizes
21
+ - **Alternative**: `--max-old-space-size=4096` for systems with less RAM
22
+
23
+ #### `--max-semi-space-size=1024`
24
+ - **Purpose**: Increases semi-space size to 1GB (default varies)
25
+ - **Benefit**: Reduces minor GC frequency during object allocation
26
+ - **Impact**: Each semi-space can hold more objects before collection
27
+
28
+ ### Garbage Collection Control
29
+
30
+ #### `--expose-gc`
31
+ - **Purpose**: Exposes `global.gc()` function for manual garbage collection
32
+ - **Benefit**: Allows forced GC between test rounds for consistent baselines
33
+ - **Usage**: Can trigger GC at specific points to isolate timing measurements
34
+
35
+ #### `--gc-interval=1000000`
36
+ - **Purpose**: Reduces GC frequency (higher number = less frequent)
37
+ - **Benefit**: Minimizes GC interruptions during timing measurements
38
+ - **Trade-off**: Uses more memory but provides consistent timing
39
+
40
+ ### Execution Predictability
41
+
42
+ #### `--predictable`
43
+ - **Purpose**: Makes execution more deterministic
44
+ - **Benefit**: Reduces timing variance from non-deterministic optimizations
45
+ - **Impact**: Slightly slower but more consistent measurements
46
+
47
+ #### `--no-compilation-cache`
48
+ - **Purpose**: Disables V8 compilation cache
49
+ - **Benefit**: Ensures consistent JIT compilation behavior across runs
50
+ - **Use Case**: When testing cold start performance or eliminating cache effects
51
+
52
+ ### JIT Compilation Control
53
+
54
+ #### `--optimize-for-size`
55
+ - **Purpose**: Optimizes for code size rather than speed
56
+ - **Benefit**: More predictable compilation behavior
57
+ - **Alternative**: `--max-opt` for maximum optimization (less predictable)
58
+
59
+ #### `--no-opt`
60
+ - **Purpose**: Disables JIT compilation entirely
61
+ - **Benefit**: Eliminates JIT timing variance (but much slower execution)
62
+ - **Use Case**: Testing interpreter-only performance
63
+
64
+ ## Complete Optimization Command
65
+
66
+ For maximum timing accuracy, use all optimization flags:
67
+
68
+ ```bash
69
+ # Use NODE_OPTIONS for compatibility with modern Node.js
70
+ NODE_OPTIONS="--max-old-space-size=8192 --max-semi-space-size=1024" \
71
+ vitest run tests/timing.test.ts
72
+
73
+ # Or use direct node invocation (requires vitest executable)
74
+ node --max-old-space-size=8192 --max-semi-space-size=1024 \
75
+ ./node_modules/vitest/vitest.mjs run tests/timing.test.ts
76
+ ```
77
+
78
+ ## System-Specific Adjustments
79
+
80
+ ### Low-Memory Systems (< 8GB RAM)
81
+ ```bash
82
+ NODE_OPTIONS="--max-old-space-size=2048 --max-semi-space-size=256" \
83
+ vitest run tests/timing.test.ts
84
+ ```
85
+
86
+ ### High-Memory Systems (> 16GB RAM)
87
+ ```bash
88
+ NODE_OPTIONS="--max-old-space-size=16384 --max-semi-space-size=2048" \
89
+ vitest run tests/timing.test.ts
90
+ ```
91
+
92
+ ### Docker/Container Environments
93
+ ```bash
94
+ NODE_OPTIONS="--max-old-space-size=4096 --max-semi-space-size=512" \
95
+ vitest run tests/timing.test.ts
96
+ ```
97
+
98
+ ## Environment Variables
99
+
100
+ ### Additional V8 Options
101
+ ```bash
102
+ export NODE_OPTIONS="--max-old-space-size=8192 --max-semi-space-size=1024"
103
+ ```
104
+
105
+ ### Memory Monitoring
106
+ ```bash
107
+ export NODE_ENV=production # Disable development overhead
108
+ export UV_THREADPOOL_SIZE=8 # Increase thread pool if needed
109
+ ```
110
+
111
+ ## Monitoring Memory During Tests
112
+
113
+ Add memory monitoring to timing tests:
114
+
115
+ ```typescript
116
+ // Add to timing test setup
117
+ if (global.gc) {
118
+ console.log('Memory before tests:', process.memoryUsage());
119
+ global.gc();
120
+ }
121
+
122
+ // Add between test rounds
123
+ if (global.gc && round % 20 === 0) {
124
+ global.gc();
125
+ console.log(`Memory after round ${round}:`, process.memoryUsage());
126
+ }
127
+ ```
128
+
129
+ ## Platform-Specific Considerations
130
+
131
+ ### macOS
132
+ - Default memory limits are generous
133
+ - Use `--max-old-space-size=8192` safely
134
+ - Activity Monitor shows Node.js memory usage
135
+
136
+ ### Linux
137
+ - Check `ulimit -v` for virtual memory limits
138
+ - May need `sudo sysctl vm.max_map_count=262144` for large heaps
139
+ - Use `htop` or `ps` to monitor memory
140
+
141
+ ### Windows
142
+ - WSL may have memory constraints
143
+ - PowerShell: `Get-Process node | Select-Object WorkingSet64`
144
+ - Task Manager shows detailed memory breakdown
145
+
146
+ ### CI/CD Environments
147
+ - GitHub Actions: 7GB RAM limit, use `--max-old-space-size=4096`
148
+ - GitLab CI: Variable memory, check runner specs
149
+ - Docker: Set container memory limits appropriately
150
+
151
+ ## Performance Analysis Tools
152
+
153
+ ### V8 Profiling
154
+ ```bash
155
+ node --prof --log-timer-events ./timing-test.js
156
+ ```
157
+
158
+ ### Heap Snapshots
159
+ ```bash
160
+ node --inspect --heap-prof ./timing-test.js
161
+ ```
162
+
163
+ ### GC Logging
164
+ ```bash
165
+ node --trace-gc --trace-gc-verbose ./timing-test.js
166
+ ```
167
+
168
+ ## Validation
169
+
170
+ Test that optimizations are working:
171
+
172
+ ```bash
173
+ # Run normal timing tests
174
+ pnpm run test:timing
175
+
176
+ # Run optimized timing tests
177
+ pnpm run test:timing:optimized
178
+
179
+ # Compare results - optimized should show:
180
+ # 1. Lower timing variance (smaller standard deviations)
181
+ # 2. More consistent Bollinger bands
182
+ # 3. Fewer outlier measurements
183
+ # 4. Reduced memory-related timing spikes
184
+ ```
185
+
186
+ ## Recommended Configuration
187
+
188
+ For most use cases, the optimized configuration provides the best balance:
189
+
190
+ ```json
191
+ {
192
+ "scripts": {
193
+ "test:timing:optimized": "NODE_OPTIONS=\"--max-old-space-size=8192 --max-semi-space-size=1024\" vitest run tests/timing.test.ts"
194
+ }
195
+ }
196
+ ```
197
+
198
+ This configuration:
199
+ - ✅ Eliminates most GC interference
200
+ - ✅ Provides consistent execution
201
+ - ✅ Works on most development machines
202
+ - ✅ Maintains reasonable test execution time
203
+ - ✅ Produces reliable performance metrics
204
+
205
+ ---
206
+
207
+ *For production timing analysis, always use optimized Node.js flags to ensure accurate performance measurements.*
@@ -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
+ }