64 lines
2.3 KiB
Markdown
64 lines
2.3 KiB
Markdown
# 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.
|
|
|
|
```typescript
|
|
// 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.
|
|
|
|
```typescript
|
|
// 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`:
|
|
|
|
```typescript
|
|
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 | Email | AI categorization |
|