import { I as InvoiceEngine } from '../invoice-engine-CfV5UZLo.js'; export { O as OutboxEvent, b as OutboxRecord, c as OutboxStatus, W as WebhookSink } from '../invoice-engine-CfV5UZLo.js'; export { D as DeadLetter, O as OutboxWebhookSink, W as WebhookDeliveryWorker, a as WebhookDeliveryWorkerConfig, b as WebhookOutbox, d as deriveDeliveryId, c as deriveDiscriminator, s as storeSupportsOutbox } from '../delivery-id-T_gtNnpE.js'; import '../wallet-rpc-sY1qJ24S.js'; import '../rpc/index.js'; import '../manager-BG_G7s9X.js'; import '../types-Bsy2LUTI.js'; /** * Bridge configuration: a JSON file overlaid by environment variables, with * loopback-only defaults. Zero new dependencies (no TOML/yaml). * * Fails closed: a durable store path is required (an in-memory store would * silently drop the outbox on restart — the exact failure the bridge exists to * prevent), and the webhook URL + secret are mandatory. */ type BridgeConfig = { walletRpcUrl: string; daemonRpcUrl: string; rpcAuth?: { username: string; password: string; }; /** Path to the durable SQLite file. ":memory:" is rejected (fail-closed). */ storePath: string; webhookUrl: string; webhookSecret: string; pollIntervalMs: number; defaultRequiredConfirmations: number; /** Worker tuning. */ deliveryIntervalMs: number; maxAttempts: number; /** Heartbeat file path (atomic tmp+rename); no inbound port. */ heartbeatPath: string; heartbeatIntervalMs: number; }; /** Whether a wallet/daemon URL points at loopback (used for a posture warning). */ declare function isLoopbackUrl(url: string): boolean; /** * The webhook leg leaves the host carrying the full payment payload + the HMAC * signature. HMAC gives integrity but NOT confidentiality, so cleartext http:// * over a real network would expose all payment data to an on-path observer. We * therefore REQUIRE https:// — UNLESS the target is loopback (a local test * receiver / same-host sidecar, where the bytes never hit the wire). */ declare function isAcceptableWebhookUrl(url: string): boolean; type LoadConfigResult = { config: BridgeConfig; /** Non-fatal posture warnings (e.g. non-loopback RPC URL). */ warnings: string[]; }; /** * Load + validate config. Throws on a fatal misconfiguration (fail-closed). */ declare function loadConfig(opts?: { configPath?: string; env?: NodeJS.ProcessEnv; }): LoadConfigResult; /** * PayoutBridge — the long-lived, outbound-only host-side daemon. * * Composes InvoiceEngine (with a durable webhookSink) + WebhookOutbox + * WebhookDeliveryWorker, plus a port-free heartbeat. It binds NO inbound * listener: it only makes loopback JSON-RPC calls to a local wallet/daemon and * outbound HTTPS POSTs to the merchant. */ declare class PayoutBridge { private readonly config; private store; private engine; private outbox; private worker; private heartbeatTimer; private deadLetterCount; private started; constructor(config: BridgeConfig); /** * Boot order: open store -> assert durable+outbox-capable -> build sink + * worker -> engine.start() (which re-hydrates tracked invoices AND, on its * first tick, the worker re-claims undelivered rows) -> start worker -> * heartbeat. A failure here throws and the process exits nonzero. */ start(): Promise; /** Graceful drain: stop intake, stop worker, close store. */ stop(): Promise; /** Install SIGINT/SIGTERM handlers for a clean shutdown. */ installSignalHandlers(): void; get engineRef(): InvoiceEngine; private onDeadLetter; private refreshHeartbeat; } /** * Port-free liveness: an atomically-written heartbeat file. * * The bridge's defining property is that it binds NO inbound listener — so it * cannot expose an HTTP /health endpoint without rebuilding the very surface it * exists to eliminate. Instead it writes a small JSON heartbeat (tmp file + * rename = atomic, no torn reads) that a `deropay-bridge status` subcommand or * a Docker HEALTHCHECK can read off disk. */ type Heartbeat = { /** ISO timestamp of the last write. */ ts: string; /** epoch ms, for staleness math without parsing the ISO string. */ epochMs: number; pid: number; /** Durable dead-letter count — nonzero means undelivered webhooks are parked. */ deadLetters: number; pending: number; delivering: number; }; declare function writeHeartbeat(path: string, hb: Heartbeat): void; declare function readHeartbeat(path: string): Heartbeat | null; /** * Healthy = heartbeat exists, is fresh (within `maxAgeMs`), and has zero parked * dead-letters. Returns a reason on failure for the CLI to print. */ declare function evaluateHealth(hb: Heartbeat | null, nowMs: number, maxAgeMs: number): { healthy: boolean; reason?: string; }; /** * Outbound-only posture guard. * * Wraps the inbound-binding entry points (net.Server.prototype.listen, * http/http2.createServer, dgram socket bind) so that ANY attempt to open an * inbound listener throws. The bridge installs this at startup; the honest * claim it backs is "binds no inbound TCP/UDP listener" for the current * dependency graph (a JS spy cannot see a native socket opened below Node, so * CI additionally runs an OS-level lsof/ss check — see the README). */ type NoListenerGuard = { uninstall(): void; }; declare function assertNoInboundListeners(): NoListenerGuard; export { type BridgeConfig, type Heartbeat, type LoadConfigResult, type NoListenerGuard, PayoutBridge, assertNoInboundListeners, evaluateHealth, isAcceptableWebhookUrl, isLoopbackUrl, loadConfig, readHeartbeat, writeHeartbeat };