Files
CurrenciCombo/orchestrator/src/services/bank.ts
nsatoshi 3787362406
Some checks failed
CI / Frontend Lint (push) Has been cancelled
CI / Frontend Type Check (push) Has been cancelled
CI / Frontend Build (push) Has been cancelled
CI / Frontend E2E Tests (push) Has been cancelled
CI / Orchestrator Build (push) Has been cancelled
CI / Orchestrator Unit Tests (push) Has been cancelled
CI / Orchestrator E2E (Testcontainers) (push) Has been cancelled
CI / Contracts Compile (push) Has been cancelled
CI / Contracts Test (push) Has been cancelled
Security Scan / Dependency Vulnerability Scan (push) Has been cancelled
Security Scan / OWASP ZAP Scan (push) Has been cancelled
PR #28 (squash-merged via Gitea API)
2026-04-22 21:58:55 +00:00

113 lines
2.9 KiB
TypeScript

import type { Plan } from "../types/plan";
import { generatePacs008 } from "./iso20022";
import { logger } from "../logging/logger";
/**
* Bank-instruction client — two-phase-commit adapter for the payment
* leg (arch §4.3 Payment Messaging / Settlement Layer).
*
* Until `d-bis/dbis_core` is reachable as a live API, every call here
* is a deterministic mock. That corresponds to blocker EXT-DBIS-CORE
* in proxmox/docs/03-deployment/EXTERNAL_DEPENDENCY_BLOCKERS.md and
* flips to real once DBIS_CORE_URL is set (see services/dbisCore/).
*/
const BLOCKER_ID = "EXT-DBIS-CORE";
function bankMode(): "live" | "mock" {
return process.env.DBIS_CORE_URL ? "live" : "mock";
}
/**
* Prepare bank instruction (2PC prepare phase)
* Sends provisional ISO-20022 message
*/
export async function prepareBankInstruction(plan: Plan): Promise<boolean> {
const mode = bankMode();
logger.info(
{
planId: plan.plan_id,
mode,
...(mode === "mock" ? { blockerId: BLOCKER_ID } : {}),
},
"[Bank] prepareBankInstruction()",
);
// Mock: In real implementation, this would:
// 1. Generate provisional ISO-20022 message (pacs.008 with conditional settlement)
// 2. Send to bank connector
// 3. Receive provisional acceptance
await new Promise((resolve) => setTimeout(resolve, 100));
return true;
}
/**
* Commit bank instruction (2PC commit phase)
* Confirms final settlement
*/
export async function commitBankInstruction(plan: Plan): Promise<{
success: boolean;
isoMessageId?: string;
error?: string;
}> {
const mode = bankMode();
logger.info(
{
planId: plan.plan_id,
mode,
...(mode === "mock" ? { blockerId: BLOCKER_ID } : {}),
},
"[Bank] commitBankInstruction()",
);
try {
// Generate final ISO-20022 message
const isoMessage = await generatePacs008(plan);
// Mock: In real implementation, this would:
// 1. Send ISO message to bank connector
// 2. Receive confirmation and message ID
// 3. Store message ID for audit trail
const isoMessageId = `MSG-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
// Simulate processing delay
await new Promise((resolve) => setTimeout(resolve, 300));
return {
success: true,
isoMessageId,
};
} catch (err) {
const error = err instanceof Error ? err.message : String(err);
return {
success: false,
error,
};
}
}
/**
* Abort bank instruction (2PC abort phase)
* Cancels provisional instruction
*/
export async function abortBankInstruction(planId: string): Promise<void> {
const mode = bankMode();
logger.info(
{
planId,
mode,
...(mode === "mock" ? { blockerId: BLOCKER_ID } : {}),
},
"[Bank] abortBankInstruction()",
);
// Mock: In real implementation, this would:
// 1. Generate cancellation message (camt.056)
// 2. Send to bank connector
// 3. Confirm cancellation
await new Promise((resolve) => setTimeout(resolve, 100));
}