createHttpFinLinkClient(baseUrl) for the live router.
createInProcessFinLinkClient() short-circuits to the sandbox module, so unit tests don't need an HTTP hop.
getFinLinkClient() picks HTTP when FIN_SANDBOX_URL is set, else in-process.
services/finLink/index.ts — public surface.
src/index.ts — mounts /fin-sandbox only when FIN_SANDBOX_ENABLED=true. Off by default so production builds don't expose the fake.
Why not wire it into the ExecutionCoordinator in this PR
The coordinator rework is its own thread of changes — wiring the SWIFT generators (services/swift/*) through a configurable transport needs to touch bankInstructionPhase, the pay phase, and camt.025/054 ingestion together. This PR ships the transport + client surface so that rework can land as a focused follow-up.
both client adapters (in-process + live ephemeral-port HTTP round-trip)
Closes gap-analysis v2 §7.1 (no FIN-link adapter — SWIFT generators produce strings but have no transport) and §10.6 (stand up sandbox transport).
## What
- `services/finLink/sandbox.ts` — in-process FIN-link sandbox.
- `POST /dispatch` — accepts a SWIFT/ISO payload, assigns a `FIN-XXXXXXXXXXXX` reference, returns a 202.
- `POST /advance/:ref` — deterministic lifecycle: `received → acknowledged → accepted → settled`.
- `POST /reject/:ref` — terminal fork with a rejection reason.
- `GET /messages/:ref` and `GET /messages?planId=…` for polling.
- Optional per-message webhook; `x-fin-sandbox-signature` header is HMAC-SHA256 over the body, keyed by `FIN_SANDBOX_SECRET`.
- `startAutoProgress(intervalMs)` opt-in timer ticks messages forward; `unref()`ed so Node exits cleanly.
- `services/finLink/client.ts` — two adapters:
- `createHttpFinLinkClient(baseUrl)` for the live router.
- `createInProcessFinLinkClient()` short-circuits to the sandbox module, so unit tests don't need an HTTP hop.
- `getFinLinkClient()` picks HTTP when `FIN_SANDBOX_URL` is set, else in-process.
- `services/finLink/index.ts` — public surface.
- `src/index.ts` — mounts `/fin-sandbox` only when `FIN_SANDBOX_ENABLED=true`. Off by default so production builds don't expose the fake.
## Why not wire it into the ExecutionCoordinator in this PR
The coordinator rework is its own thread of changes — wiring the SWIFT generators (`services/swift/*`) through a configurable transport needs to touch bankInstructionPhase, the pay phase, and camt.025/054 ingestion together. This PR ships the transport + client surface so that rework can land as a focused follow-up.
## Verification
- `npx tsc --noEmit` clean.
- `npx jest` 92/92 passing (8 suites).
- 12 new tests covering:
- in-memory lifecycle (received → acknowledged → accepted → settled)
- rejection as a terminal state
- `listMessages` filtering by `planId`
- deterministic HMAC signature
- HTTP endpoints (dispatch 202, dispatch 400, advance walk, filter, 404)
- both client adapters (in-process + live ephemeral-port HTTP round-trip)
Closes gap-analysis v2 §7.1 (no FIN-link adapter; SWIFT generators
produce strings but no transport) + §10.6 (stand up sandbox transport).
- services/finLink/sandbox.ts — in-process FIN-link sandbox.
Accepts POST /dispatch with a SWIFT/ISO payload, assigns a FIN
reference, and advances messages deterministically through
received -> acknowledged -> accepted -> settled (with reject as a
terminal fork). Optional webhook per-message (x-fin-sandbox-signature
header, HMAC-SHA256). Timer-driven auto-progress opt-in via
startAutoProgress().
- services/finLink/client.ts — two client adapters:
createHttpFinLinkClient(baseUrl) - for the live router
createInProcessFinLinkClient() - for unit tests that skip
the HTTP hop
getFinLinkClient() picks HTTP when FIN_SANDBOX_URL is set, else
falls back to in-process.
- services/finLink/index.ts — public surface.
- src/index.ts — mounts /fin-sandbox only when
FIN_SANDBOX_ENABLED=true; off by default to keep prod surface clean.
- tests/unit/finLinkSandbox.test.ts — 12 tests covering lifecycle,
rejection, listing, signature determinism, HTTP endpoints
(dispatch/advance/messages/filtering), and both client adapters
(including a live ephemeral-port HTTP round-trip).
- Verification: tsc --noEmit clean; full jest 92/92 passing
(8 suites).
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes gap-analysis v2 §7.1 (no FIN-link adapter — SWIFT generators produce strings but have no transport) and §10.6 (stand up sandbox transport).
What
services/finLink/sandbox.ts— in-process FIN-link sandbox.POST /dispatch— accepts a SWIFT/ISO payload, assigns aFIN-XXXXXXXXXXXXreference, returns a 202.POST /advance/:ref— deterministic lifecycle:received → acknowledged → accepted → settled.POST /reject/:ref— terminal fork with a rejection reason.GET /messages/:refandGET /messages?planId=…for polling.x-fin-sandbox-signatureheader is HMAC-SHA256 over the body, keyed byFIN_SANDBOX_SECRET.startAutoProgress(intervalMs)opt-in timer ticks messages forward;unref()ed so Node exits cleanly.services/finLink/client.ts— two adapters:createHttpFinLinkClient(baseUrl)for the live router.createInProcessFinLinkClient()short-circuits to the sandbox module, so unit tests don't need an HTTP hop.getFinLinkClient()picks HTTP whenFIN_SANDBOX_URLis set, else in-process.services/finLink/index.ts— public surface.src/index.ts— mounts/fin-sandboxonly whenFIN_SANDBOX_ENABLED=true. Off by default so production builds don't expose the fake.Why not wire it into the ExecutionCoordinator in this PR
The coordinator rework is its own thread of changes — wiring the SWIFT generators (
services/swift/*) through a configurable transport needs to touch bankInstructionPhase, the pay phase, and camt.025/054 ingestion together. This PR ships the transport + client surface so that rework can land as a focused follow-up.Verification
npx tsc --noEmitclean.npx jest92/92 passing (8 suites).listMessagesfiltering byplanIdCloses gap-analysis v2 §7.1 (no FIN-link adapter; SWIFT generators produce strings but no transport) + §10.6 (stand up sandbox transport). - services/finLink/sandbox.ts — in-process FIN-link sandbox. Accepts POST /dispatch with a SWIFT/ISO payload, assigns a FIN reference, and advances messages deterministically through received -> acknowledged -> accepted -> settled (with reject as a terminal fork). Optional webhook per-message (x-fin-sandbox-signature header, HMAC-SHA256). Timer-driven auto-progress opt-in via startAutoProgress(). - services/finLink/client.ts — two client adapters: createHttpFinLinkClient(baseUrl) - for the live router createInProcessFinLinkClient() - for unit tests that skip the HTTP hop getFinLinkClient() picks HTTP when FIN_SANDBOX_URL is set, else falls back to in-process. - services/finLink/index.ts — public surface. - src/index.ts — mounts /fin-sandbox only when FIN_SANDBOX_ENABLED=true; off by default to keep prod surface clean. - tests/unit/finLinkSandbox.test.ts — 12 tests covering lifecycle, rejection, listing, signature determinism, HTTP endpoints (dispatch/advance/messages/filtering), and both client adapters (including a live ephemeral-port HTTP round-trip). - Verification: tsc --noEmit clean; full jest 92/92 passing (8 suites).