A TypeScript service discovery library for your application architecture.
@asgard/hermod
is a lightweight, type-safe service discovery library for TypeScript applications. Named after the Norse god who served as the messenger between the realms, this package facilitates communication between different services in your application, making it simple to register, discover, and consume services with full type safety.
# Using npm npm install @asgard/hermod # Using pnpm pnpm add @asgard/hermod # Using yarn yarn add @asgard/hermod # Using JSR npx jsr add @asgard/hermod
import { HermodServiceDiscovery, HermodService } from '@asgard/hermod'; // Define your service types interface Services { logger: Logger; database: Database; } // Create a service discovery instance const serviceDiscovery = HermodServiceDiscovery.getInstance<Services>(); // Create and register services class LoggerService extends HermodService<'logger', Logger> { serviceName = 'logger' as const; register() { return new Logger(); } } // Register the service new LoggerService(serviceDiscovery).discover(); // Access the service elsewhere in your code const logger = await serviceDiscovery.get('logger');
// Define service interfaces interface Logger { log(message: string): void; } interface Database { query(sql: string): Promise<unknown[]>; } // Define service types interface Services { logger: Logger; database: Database; } // Get service discovery instance const serviceDiscovery = HermodServiceDiscovery.getInstance<Services>(); // Create logger service class LoggerService extends HermodService<'logger', Logger> { serviceName = 'logger' as const; register() { return { log: (message: string) => console.log(`[LOG]: ${message}`) }; } } // Create database service class DatabaseService extends HermodService<'database', Database> { serviceName = 'database' as const; async register() { // Simulate async initialization await new Promise(resolve => setTimeout(resolve, 100)); return { query: async (sql: string) => { console.log(`Executing query: ${sql}`); return []; } }; } } // Register services new LoggerService(serviceDiscovery).discover(); new DatabaseService(serviceDiscovery).discover(); // Use services together async function main() { // Get individual services const logger = await serviceDiscovery.get('logger'); logger.log('Application started'); // Get multiple services at once const { logger: log, database } = await serviceDiscovery.getMany(['logger', 'database']); log.log('Querying database...'); const results = await database.query('SELECT * FROM users'); }
class ConfigService extends HermodService<'config', Record<string, any>> { serviceName = 'config' as const; register() { return { apiUrl: 'https://api.example.com', timeout: 5000 }; } } class ApiService extends HermodService<'api', ApiClient> { serviceName = 'api' as const; async register() { // Get config service const config = await this.serviceDiscovery.get('config'); // Use config to set up API client return new ApiClient(config.apiUrl, config.timeout); } } // Register in correct order new ConfigService(serviceDiscovery).discover(); new ApiService(serviceDiscovery).discover();
The has
method allows you to check if a service exists before attempting to retrieve it:
// Check if a service exists if (serviceDiscovery.has('logger')) { // Service exists, safe to get const logger = await serviceDiscovery.get('logger'); logger.log('System started'); } else { // Handle missing service console.warn('Logger service not available, using console'); console.log('System started'); } // Using with optional services async function getAnalytics() { // Analytics might be optional if (serviceDiscovery.has('analytics')) { const analytics = await serviceDiscovery.get('analytics'); return analytics.getStats(); } // Return default empty data if service isn't available return { pageViews: 0, visitors: 0 }; } // Checking multiple services const requiredServices = ['database', 'auth', 'cache']; const missingServices = requiredServices.filter( service => !serviceDiscovery.has(service) ); if (missingServices.length > 0) { console.error(`Missing required services: ${missingServices.join(', ')}`); } else { // All services available, safe to start application startApp(); }
Add Package
deno add jsr:@asgard/hermod
Import symbol
import * as hermod from "@asgard/hermod";
Import directly with a jsr specifier
import * as hermod from "jsr:@asgard/hermod";
Add Package
pnpm i jsr:@asgard/hermod
pnpm dlx jsr add @asgard/hermod
Import symbol
import * as hermod from "@asgard/hermod";
Add Package
yarn add jsr:@asgard/hermod
yarn dlx jsr add @asgard/hermod
Import symbol
import * as hermod from "@asgard/hermod";
Add Package
npx jsr add @asgard/hermod
Import symbol
import * as hermod from "@asgard/hermod";
Add Package
bunx jsr add @asgard/hermod
Import symbol
import * as hermod from "@asgard/hermod";