Using services
Create and use a service:
import type { Context } from 'udic';
interface UUIDService { uuid: { create: () => string; };}
const main = (c: Context<UUIDService>) => { console.log('uuid:', c.uuid.create());};
main({ uuid: { create: () => crypto.randomUUID(), },});Use multiple services that reference others:
import { impl, implAsync, linkAsync, type Context } from 'udic';import { SQL, type SQLOptions } from 'bun';
interface Config { config: { logLevel: 'DEBUG' | 'WARNING' | 'ERROR'; db: SQLOptions; };}
// Auto-infer type from implementationstype Logger = Context<typeof loggerImpl>;type Database = Context<typeof dbImpl>;
// Logger implementationconst loggerImpl = impl((c: Context<Config>) => ({ log: (...args: any[]) => { console.log(`[${c.config.logLevel}]`, ...args); },}));
// Database implementationconst dbImpl = implAsync(async (c: Context<Config>) => ({ sql: await new SQL(c.config.db).connect(),}));
{ const query = (c: Context<Database>) => c.sql`SELECT 1`;
// Auto-infer context type from other functions const main = async (c: Context<typeof query | Logger>) => { c.log('config:', c.config); c.log('query result:', await query(c)); };
// linkAsync() can link both async and sync implementations // use link() to link only sync implementations const c = await linkAsync( { config: { logLevel: 'DEBUG', db: { adapter: 'sqlite', database: ':memory:', }, }, }, loggerImpl, dbImpl, ); await main(c);}