968a90bdb9
RouteService (createBinding/listBindings/simulate/listDecisions/approve/deny/ execute/flushDigest); approve REVIEW→ALLOW + route.approved event → execute via P5 OutboundService (sandbox, idempotent per decision); deny never executes. 7 route endpoints; PORTAL adapter registered. 5 route tests green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
43 lines
1.4 KiB
TypeScript
43 lines
1.4 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
|
import type { ScopeVector } from '@insignia/iios-contracts';
|
|
import { WebhookAdapter, type ChannelAdapter } from '@insignia/iios-adapter-sdk';
|
|
|
|
export interface AdapterConfig {
|
|
secret: string;
|
|
scope: ScopeVector;
|
|
}
|
|
|
|
/**
|
|
* Registers channel adapters + their per-channel config (secret + scope). In P5
|
|
* one reference WebhookAdapter backs several channelTypes (WEBHOOK/EMAIL/WHATSAPP)
|
|
* so the fixtures exercise the same anti-corruption pipeline. Secrets come from
|
|
* ADAPTER_SECRETS (JSON map); scope defaults to the demo scope.
|
|
*/
|
|
@Injectable()
|
|
export class AdapterRegistry {
|
|
private readonly adapters = new Map<string, { adapter: ChannelAdapter; config: AdapterConfig }>();
|
|
|
|
constructor() {
|
|
let secrets: Record<string, string> = {};
|
|
try {
|
|
secrets = JSON.parse(process.env.ADAPTER_SECRETS ?? '{}');
|
|
} catch {
|
|
secrets = {};
|
|
}
|
|
const scope: ScopeVector = {
|
|
orgId: process.env.ADAPTER_ORG ?? 'org_portal-demo',
|
|
appId: process.env.ADAPTER_APP ?? 'portal-demo',
|
|
};
|
|
for (const channelType of ['WEBHOOK', 'EMAIL', 'WHATSAPP', 'PORTAL']) {
|
|
this.adapters.set(channelType, {
|
|
adapter: new WebhookAdapter(channelType),
|
|
config: { secret: secrets[channelType] ?? 'dev-adapter-secret', scope },
|
|
});
|
|
}
|
|
}
|
|
|
|
get(channelType: string): { adapter: ChannelAdapter; config: AdapterConfig } | undefined {
|
|
return this.adapters.get(channelType);
|
|
}
|
|
}
|