2.3 KiB
2.3 KiB
Service Integration Patterns
Two patterns for extensions to provide services to core. Both ensure core compiles without the extension.
Pattern A: Interface Registration
Best for single-implementation services (e.g., email). Core defines interface + noop default; extension registers at load time.
// Core: lib/email/service.ts
let emailService: EmailService = new NoopEmailService()
export function getEmailService(): EmailService { return emailService }
export function registerEmailService(svc: EmailService): void { emailService = svc }
// Extension: extensions/general/email/index.ts
import { registerEmailService } from '@/lib/email/service'
registerEmailService(new ResendEmailService()) // Registers at module load
export const emailExtension: Extension = { id: 'email', name: 'Email', version: '1.0.0' }
// Core consumption:
const svc = getEmailService()
if (svc.isConfigured()) await svc.sendEmail({ to, subject, html })
Pattern B: Services Record
Best for multiple named functions (e.g., AI categorization). Extension exposes via services; core discovers via registry.
// Extension:
services: {
findSimilarTemplates: async (...args: unknown[]) => {
const { findSimilarTemplates } = await import('./lib/template-embeddings')
return findSimilarTemplates(args[0] as Transaction, args[1] as EntityType)
},
},
// Core facade (lib/bookkeeping/template-embeddings.ts):
const aiExt = extensionRegistry.get('ai-categorization')
if (aiExt?.services?.findSimilarTemplates) {
return aiExt.services.findSimilarTemplates(transaction, entityType)
}
return findMatchingTemplates(transaction, entityType) // Fallback
Pattern C: Core Services for Extensions
Extensions consume core services via ctx.services:
await ctx?.services.ingestTransactions(ctx.supabase, ctx.userId, rawTransactions)
Comparison
| Aspect | Interface Registration | Services Record |
|---|---|---|
| Defined in | Core (lib/) |
Extension (index.ts) |
| Discovery | get*() getter |
extensionRegistry.get().services |
| Functions | Single interface | Multiple named |
| Lazy imports | No | Yes (inside service fns) |
| Fallback | Noop default | Core provides fallback |
| Example | AI categorization |