UNPKG

@fjell/registry

Version:

Dependency injection and service location system for the Fjell ecosystem

242 lines (185 loc) 9.72 kB
# Registry Examples This directory contains examples demonstrating how to use the Registry with different key patterns and configurations. ## Examples ### 1. `simple-example.ts` ⭐ **Start Here!** **Perfect for beginners!** Demonstrates the simplest possible way to use the Registry: - **No RegistryHub required** - just call `createRegistry()` - **No scopes needed** - pass empty array `[]` or omit entirely - **Basic dependency injection** - register and retrieve services - **Service dependencies** - shows how services can depend on each other Great for simple applications that just need basic dependency injection without complexity. ### 2. `multi-level-keys.ts` **Advanced usage with scopes and multi-level keys!** Demonstrates how Registry supports hierarchical key type arrays: - **Single level**: `['user']`, `['task']` - SQL vs NoSQL implementations - **Two levels**: `['user', 'profile']` - S3 vs Local storage implementations - **Three levels**: `['user', 'profile', 'preference']` - Redis implementation - **Real scopes**: Production vs development environments - **Multiple implementations**: Same interface, different backends Shows how each key path maps to different implementations via scopes using the real library. ### 3. `registry-hub-types.ts` 🏗️ **Enterprise Architecture** **Large-scale application with service organization!** Demonstrates how RegistryHub manages multiple registries for different service types: - **Service Categories**: Business logic, data access, infrastructure, communication - **Type-based Organization**: Services organized by purpose and responsibility - **Cross-Registry Workflows**: Services from different registries working together - **Environment Configuration**: Production vs development implementations - **Centralized Discovery**: Single hub for all service types Perfect for enterprise applications that need clean separation of concerns and organized service architecture. ### 4. `registry-statistics-example.ts` 📊 **Usage Analytics** **Track and monitor registry usage patterns with scope-aware analytics!** Demonstrates advanced statistics tracking: - **Scope-Aware Tracking**: Separate statistics for each kta + scopes combination - **Total Call Monitoring**: Track overall `get()` method usage - **Detailed Coordinate Records**: Individual tracking for each service/scope pair - **Environment Analysis**: Aggregate statistics by environment (prod/dev) - **Most/Least Used Services**: Identify usage patterns and bottlenecks - **Immutable Statistics**: Safe access to tracking data without affecting internal state - **Normalized Scope Handling**: Consistent tracking regardless of scope order Perfect for monitoring, optimization, understanding service usage patterns, and analyzing environment-specific behavior in production applications. ## Key Concepts Demonstrated ### Simple Usage (simple-example.ts) ```typescript // Import the real registry functionality import { createRegistry, createInstance } from '../src/Registry'; // Create a registry - no RegistryHub needed! const registry = createRegistry('app'); // Register a service - no scopes needed! registry.createInstance(['logger'], [], (coordinate, context) => { const service = new LoggerService(); const instance = createInstance(context.registry, coordinate); (instance as any).log = service.log.bind(service); return instance; }); // Get the service - no scopes needed! const logger = registry.get(['logger']); logger.log('Hello from the registry!'); ``` ### Multi-Level Key Arrays ```typescript // Different key path levels ['user'] // → UserService implementation ['user', 'profile'] // → UserProfileService implementation ['user', 'profile', 'preference'] // → UserPreferenceService implementation ['task'] // → TaskService implementation ``` ### RegistryHub Usage (registry-hub-types.ts) ```typescript // Import RegistryHub functionality import { createRegistryHub } from '../src/RegistryHub'; import { createRegistry } from '../src/Registry'; // Create a hub to manage multiple registries const hub = createRegistryHub(); // Create specialized registries for different service types const servicesRegistry = createRegistry('services'); // Business logic const dataRegistry = createRegistry('data'); // Data access const infraRegistry = createRegistry('infrastructure'); // Infrastructure const commRegistry = createRegistry('communication'); // External services // Register all registries in the hub hub.registerRegistry(servicesRegistry); hub.registerRegistry(dataRegistry); hub.registerRegistry(infraRegistry); hub.registerRegistry(commRegistry); // Register services by type and scope servicesRegistry.createInstance(['auth'], ['prod'], (coordinate, context) => { // JWT implementation for production }); dataRegistry.createInstance(['user'], ['sql'], (coordinate, context) => { // PostgreSQL implementation }); // Retrieve services by type and scope through the hub const prodAuth = hub.get('services', ['auth'], { scopes: ['prod'] }); const sqlUser = hub.get('data', ['user'], { scopes: ['sql'] }); const cache = hub.get('infrastructure', ['cache'], { scopes: ['dev'] }); const email = hub.get('communication', ['email'], { scopes: ['prod'] }); ``` ### Scope-Based Implementation Selection - Multiple implementations per key path - Runtime selection via scopes - Environment-based switching (prod/dev/test) - Feature flags and A/B testing support ### Real-World Use Cases - **Database Abstraction**: Different implementations for PostgreSQL, MongoDB, etc. - **Environment Selection**: Different implementations for prod/dev - **Testing**: Mock implementations with 'test' scope - **Microservices**: Each key path represents a different service - **Multi-Region**: Different implementations across regions ## Using the Registry The registry provides a centralized way to manage instances in your application. Here are the main operations you can perform: ### Getting All Coordinates You can retrieve a list of all coordinates currently registered in the registry: ```typescript import { createRegistry } from '@fjell/registry'; const registry = createRegistry('myRegistry'); // Register some instances... registry.createInstance(['service'], ['production'], factory1); registry.createInstance(['cache', 'redis'], ['development'], factory2); // Get all coordinates const coordinates = registry.getCoordinates(); console.log(`Found ${coordinates.length} registered coordinates:`); coordinates.forEach(coord => { console.log(`- ${coord.toString()}`); }); ``` This is useful for debugging, monitoring, or implementing discovery mechanisms in your application. ### Basic Instance Management ## Running Examples ```bash # Start with the simple example (recommended) npx tsx examples/simple-example.ts # Run the multi-level keys example npx tsx examples/multi-level-keys.ts # Run the RegistryHub with service types example npx tsx examples/registry-hub-types.ts # Run the coordinate discovery and introspection example npx tsx examples/coordinates-example.ts # Run the RegistryHub cross-registry coordinate discovery example npx tsx examples/registry-hub-coordinates-example.ts # Run the registry statistics tracking example npx tsx examples/registry-statistics-example.ts # Or in Node.js node -r esbuild-register examples/simple-example.ts node -r esbuild-register examples/multi-level-keys.ts node -r esbuild-register examples/registry-hub-types.ts node -r esbuild-register examples/coordinates-example.ts node -r esbuild-register examples/registry-hub-coordinates-example.ts node -r esbuild-register examples/registry-statistics-example.ts ``` ## Integration with Real Fjell Registry Both examples now use the real library! In actual usage with the built package: ```typescript import { createRegistry, createInstance } from '@fjell/registry'; // Simple usage - no RegistryHub, no scopes const registry = createRegistry('app'); registry.createInstance(['user'], [], (coordinate, context) => { const service = new UserService(); const instance = createInstance(context.registry, coordinate); (instance as any).save = service.save.bind(service); return instance; }); const user = registry.get(['user']); // Advanced usage - with scopes for multiple implementations registry.createInstance(['user'], ['sql', 'prod'], (coordinate, context) => { const service = new SqlUserService(); const instance = createInstance(context.registry, coordinate); (instance as any).save = service.save.bind(service); return instance; }); const prodUser = registry.get(['user'], { scopes: ['prod'] }); ``` ## When to Use What **Use `simple-example.ts` approach when:** - You're just getting started - You have a simple application - You don't need multiple implementations per service - You want basic dependency injection **Use `multi-level-keys.ts` approach when:** - You need multiple implementations (prod/dev/test) - You have complex service hierarchies - You need environment-based switching - You're building a large, complex application **Use `registry-hub-types.ts` approach when:** - You're building enterprise-scale applications - You need to organize services by type/category - You have multiple teams working on different service layers - You want clean separation between business logic, data, and infrastructure - You need centralized service discovery across service types - You're implementing microservices or modular architecture This approach provides the foundation for the Fjell library's architecture pattern with swappable implementations and enterprise-scale service organization.