@fiber-pay/runtime 0.1.0-rc.6 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +65 -13
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/alerts/format.ts","../src/alerts/types.ts","../src/service.ts","../src/alerts/alert-manager.ts","../src/alerts/backends/file-jsonl.ts","../src/alerts/backends/stdout.ts","../src/utils/async.ts","../src/alerts/backends/webhook.ts","../src/alerts/backends/websocket.ts","../src/config.ts","../src/jobs/retry-policy.ts","../src/jobs/job-manager.ts","../src/jobs/executors/channel-executor.ts","../src/jobs/error-classifier.ts","../src/jobs/executor-utils.ts","../src/jobs/state-machine.ts","../src/jobs/executors/invoice-executor.ts","../src/jobs/executors/payment-executor.ts","../src/jobs/types.ts","../src/monitors/channel-monitor.ts","../src/diff/channel-diff.ts","../src/monitors/base-monitor.ts","../src/monitors/health-monitor.ts","../src/monitors/tracker-utils.ts","../src/monitors/invoice-tracker.ts","../src/monitors/payment-tracker.ts","../src/diff/peer-diff.ts","../src/monitors/peer-monitor.ts","../src/proxy/rpc-proxy.ts","../src/proxy/body.ts","../src/proxy/http-utils.ts","../src/proxy/json.ts","../src/proxy/job-routes.ts","../src/proxy/jsonrpc-tracking.ts","../src/proxy/monitor-routes.ts","../src/storage/memory-store.ts","../src/storage/sqlite-store.ts","../src/bootstrap.ts","../src/storage/payment-proof.ts"],"sourcesContent":["import type { Alert } from './types.js';\n\nconst ANSI_RESET = '\\x1b[0m';\nconst ANSI_BOLD = '\\x1b[1m';\nconst ANSI_DIM = '\\x1b[2m';\nconst ANSI_RED = '\\x1b[31m';\nconst ANSI_GREEN = '\\x1b[32m';\nconst ANSI_YELLOW = '\\x1b[33m';\nconst ANSI_BLUE = '\\x1b[34m';\nconst ANSI_MAGENTA = '\\x1b[35m';\nconst ANSI_CYAN = '\\x1b[36m';\n\nexport interface FormatRuntimeAlertOptions {\n color?: 'auto' | 'always' | 'never';\n prefix?: string;\n}\n\nfunction clip(value: string, max = 120): string {\n if (value.length <= max) {\n return value;\n }\n return `${value.slice(0, max - 1)}…`;\n}\n\nfunction readStringField(record: Record<string, unknown>, key: string): string | undefined {\n const value = record[key];\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nfunction toRecord(value: unknown): Record<string, unknown> | undefined {\n if (!value || typeof value !== 'object') {\n return undefined;\n }\n return value as Record<string, unknown>;\n}\n\nfunction summarizeAlertData(data: unknown, withColor: boolean): string {\n if (data === null || data === undefined) {\n return '{}';\n }\n\n if (typeof data !== 'object') {\n return clip(String(data), 160);\n }\n\n const record = data as Record<string, unknown>;\n const parts: string[] = [];\n\n const eventType = readStringField(record, 'type');\n if (eventType) {\n parts.push(`type=${eventType}`);\n }\n\n const channel = toRecord(record.channel);\n const previousChannel = toRecord(record.previousChannel);\n\n const channelId =\n readStringField(record, 'channelId') ??\n readStringField(channel ?? {}, 'channel_id') ??\n readStringField(previousChannel ?? {}, 'channel_id');\n if (channelId) {\n parts.push(`channelId=${channelId}`);\n }\n\n const paymentHash = readStringField(record, 'paymentHash');\n if (paymentHash) {\n parts.push(`paymentHash=${paymentHash}`);\n }\n\n const invoicePaymentHash = readStringField(record, 'invoicePaymentHash');\n if (invoicePaymentHash) {\n parts.push(`invoicePaymentHash=${invoicePaymentHash}`);\n }\n\n const peerId = readStringField(record, 'peerId') ?? readStringField(channel ?? {}, 'peer_id');\n if (peerId) {\n parts.push(`peerId=${peerId}`);\n }\n\n const jobId = readStringField(record, 'jobId');\n if (jobId) {\n parts.push(`jobId=${jobId}`);\n }\n\n const previousState = readStringField(record, 'previousState');\n const currentState = readStringField(record, 'currentState');\n if (previousState && currentState) {\n parts.push(\n colorize(`state=${previousState}->${currentState}`, `${ANSI_BOLD}${ANSI_YELLOW}`, withColor),\n );\n }\n\n const channelState = toRecord(channel?.state);\n const previousChannelState = toRecord(previousChannel?.state);\n const currentStateName = readStringField(channelState ?? {}, 'state_name');\n const previousStateName = readStringField(previousChannelState ?? {}, 'state_name');\n if (!previousState && !currentState && previousStateName && currentStateName) {\n parts.push(\n colorize(\n `state=${previousStateName}->${currentStateName}`,\n `${ANSI_BOLD}${ANSI_YELLOW}`,\n withColor,\n ),\n );\n } else if (!previousState && !currentState && currentStateName) {\n parts.push(colorize(`state=${currentStateName}`, `${ANSI_BOLD}${ANSI_YELLOW}`, withColor));\n }\n\n const reason = readStringField(record, 'reason') ?? readStringField(record, 'message');\n if (reason) {\n parts.push(`reason=${clip(reason, 80)}`);\n }\n\n const error = readStringField(record, 'error');\n if (error) {\n parts.push(`error=${clip(error, 80)}`);\n }\n\n if (parts.length > 0) {\n return parts.join(' ');\n }\n\n return clip(JSON.stringify(record), 160);\n}\n\nfunction shouldUseColor(mode: NonNullable<FormatRuntimeAlertOptions['color']>): boolean {\n if (mode === 'always') {\n return true;\n }\n if (mode === 'never') {\n return false;\n }\n return process.env.NO_COLOR === undefined && process.stdout.isTTY !== false;\n}\n\nfunction colorize(text: string, color: string, enabled: boolean): string {\n if (!enabled) {\n return text;\n }\n return `${color}${text}${ANSI_RESET}`;\n}\n\nexport function formatRuntimeAlert(alert: Alert, options: FormatRuntimeAlertOptions = {}): string {\n const colorMode = options.color ?? 'auto';\n const withColor = shouldUseColor(colorMode);\n const priorityLabel = alert.priority.toUpperCase().padEnd(8, ' ');\n\n const priorityColor =\n alert.priority === 'critical'\n ? ANSI_RED\n : alert.priority === 'high'\n ? ANSI_YELLOW\n : alert.priority === 'medium'\n ? ANSI_CYAN\n : ANSI_GREEN;\n\n const typeColor = alert.type.startsWith('channel_')\n ? ANSI_BLUE\n : alert.type.startsWith('payment_') ||\n alert.type.startsWith('incoming_') ||\n alert.type.startsWith('outgoing_')\n ? ANSI_MAGENTA\n : ANSI_CYAN;\n\n const prefixLabel = options.prefix ?? '[fiber-runtime]';\n const prefix = colorize(prefixLabel, `${ANSI_BOLD}${ANSI_CYAN}`, withColor);\n const ts = colorize(alert.timestamp, ANSI_DIM, withColor);\n const priority = colorize(priorityLabel, `${ANSI_BOLD}${priorityColor}`, withColor);\n const type = colorize(alert.type, `${ANSI_BOLD}${typeColor}`, withColor);\n const data = colorize(summarizeAlertData(alert.data, withColor), ANSI_DIM, withColor);\n\n return `${prefix} ${ts} ${priority} ${type} ${data}`;\n}\n","import type { Channel, ChannelId, PaymentHash, PeerInfo } from '@fiber-pay/sdk';\n\nexport type AlertPriority = 'critical' | 'high' | 'medium' | 'low';\n\nexport type AlertType =\n | 'channel_state_changed'\n | 'new_inbound_channel_request'\n | 'channel_became_ready'\n | 'channel_closing'\n | 'incoming_payment_received'\n | 'invoice_expired'\n | 'invoice_cancelled'\n | 'outgoing_payment_completed'\n | 'outgoing_payment_failed'\n | 'channel_balance_changed'\n | 'new_pending_tlc'\n | 'peer_connected'\n | 'peer_disconnected'\n | 'node_offline'\n | 'node_online'\n // Job execution alerts\n | 'payment_job_started'\n | 'payment_job_retrying'\n | 'payment_job_succeeded'\n | 'payment_job_failed'\n | 'invoice_job_started'\n | 'invoice_job_retrying'\n | 'invoice_job_succeeded'\n | 'invoice_job_failed'\n | 'channel_job_started'\n | 'channel_job_retrying'\n | 'channel_job_succeeded'\n | 'channel_job_failed';\n\nexport const alertTypeValues: AlertType[] = [\n 'channel_state_changed',\n 'new_inbound_channel_request',\n 'channel_became_ready',\n 'channel_closing',\n 'incoming_payment_received',\n 'invoice_expired',\n 'invoice_cancelled',\n 'outgoing_payment_completed',\n 'outgoing_payment_failed',\n 'channel_balance_changed',\n 'new_pending_tlc',\n 'peer_connected',\n 'peer_disconnected',\n 'node_offline',\n 'node_online',\n 'payment_job_started',\n 'payment_job_retrying',\n 'payment_job_succeeded',\n 'payment_job_failed',\n 'invoice_job_started',\n 'invoice_job_retrying',\n 'invoice_job_succeeded',\n 'invoice_job_failed',\n 'channel_job_started',\n 'channel_job_retrying',\n 'channel_job_succeeded',\n 'channel_job_failed',\n];\n\nexport const alertPriorityOrder: Record<AlertPriority, number> = {\n low: 1,\n medium: 2,\n high: 3,\n critical: 4,\n};\n\nexport interface AlertFilter {\n limit?: number;\n minPriority?: AlertPriority;\n type?: AlertType;\n source?: string;\n}\n\nexport function isAlertPriority(value: string): value is AlertPriority {\n return value === 'critical' || value === 'high' || value === 'medium' || value === 'low';\n}\n\nexport function isAlertType(value: string): value is AlertType {\n return alertTypeValues.includes(value as AlertType);\n}\n\nexport interface Alert<T = unknown> {\n id: string;\n type: AlertType;\n priority: AlertPriority;\n timestamp: string;\n source: string;\n data: T;\n}\n\nexport interface AlertInput<T = unknown> {\n type: AlertType;\n priority: AlertPriority;\n source: string;\n data: T;\n}\n\nexport interface TrackedInvoiceState {\n paymentHash: PaymentHash;\n status: string;\n trackedAt: number;\n updatedAt: number;\n completedAt?: number;\n}\n\nexport interface TrackedPaymentState {\n paymentHash: PaymentHash;\n status: string;\n trackedAt: number;\n updatedAt: number;\n completedAt?: number;\n}\n\nexport interface ChannelBalanceChangedData {\n channelId: ChannelId;\n localBalanceBefore: string;\n localBalanceAfter: string;\n remoteBalanceBefore: string;\n remoteBalanceAfter: string;\n channel: Channel;\n}\n\nexport interface PendingTlcChangedData {\n channelId: ChannelId;\n newPendingTlcCount: number;\n previousPendingTlcCount: number;\n channel: Channel;\n}\n\nexport interface ChannelStateChangedData {\n channelId: ChannelId;\n previousState: string;\n currentState: string;\n channel: Channel;\n}\n\nexport interface PeerEventData {\n peer: PeerInfo;\n}\n\nexport interface RpcHealthData {\n message: string;\n}\n\nexport interface PaymentJobAlertData {\n jobId: string;\n idempotencyKey: string;\n retryCount: number;\n error?: string;\n fee?: string;\n}\n\nexport interface InvoiceJobAlertData {\n jobId: string;\n idempotencyKey: string;\n retryCount: number;\n action?: string;\n status?: string;\n paymentHash?: `0x${string}`;\n error?: string;\n}\n\nexport interface ChannelJobAlertData {\n jobId: string;\n idempotencyKey: string;\n retryCount: number;\n action?: string;\n peerId?: string;\n temporaryChannelId?: `0x${string}`;\n channelId?: `0x${string}`;\n fundingAmount?: string;\n error?: string;\n}\n\nexport interface AlertBackend {\n start?(): Promise<void>;\n send(alert: Alert): Promise<void>;\n stop?(): Promise<void>;\n}\n","import { EventEmitter } from 'node:events';\nimport { FiberRpcClient } from '@fiber-pay/sdk';\nimport { AlertManager } from './alerts/alert-manager.js';\nimport { DailyJsonlFileAlertBackend, JsonlFileAlertBackend } from './alerts/backends/file-jsonl.js';\nimport { StdoutAlertBackend } from './alerts/backends/stdout.js';\nimport { WebhookAlertBackend } from './alerts/backends/webhook.js';\nimport { WebsocketAlertBackend } from './alerts/backends/websocket.js';\nimport type {\n Alert,\n AlertBackend,\n AlertFilter,\n AlertType,\n ChannelJobAlertData,\n InvoiceJobAlertData,\n PaymentJobAlertData,\n} from './alerts/types.js';\nimport { createRuntimeConfig, type RuntimeConfig, type RuntimeConfigInput } from './config.js';\nimport { JobManager } from './jobs/job-manager.js';\nimport type { ChannelJob, InvoiceJob, PaymentJob, RuntimeJob } from './jobs/types.js';\nimport type { BaseMonitor } from './monitors/base-monitor.js';\nimport { ChannelMonitor } from './monitors/channel-monitor.js';\nimport { HealthMonitor } from './monitors/health-monitor.js';\nimport { InvoiceTracker } from './monitors/invoice-tracker.js';\nimport { PaymentTracker } from './monitors/payment-tracker.js';\nimport { PeerMonitor } from './monitors/peer-monitor.js';\nimport { RpcMonitorProxy } from './proxy/rpc-proxy.js';\nimport { MemoryStore } from './storage/memory-store.js';\nimport { SqliteJobStore } from './storage/sqlite-store.js';\n\nexport class FiberMonitorService extends EventEmitter {\n private readonly config: RuntimeConfig;\n private readonly startedAt: string;\n private readonly client: FiberRpcClient;\n private readonly store: MemoryStore;\n private readonly alerts: AlertManager;\n private readonly monitors: BaseMonitor[];\n private readonly proxy: RpcMonitorProxy;\n private readonly jobStore: SqliteJobStore | null;\n private readonly jobManager: JobManager | null;\n private running = false;\n\n constructor(configInput: RuntimeConfigInput = {}) {\n super();\n this.config = createRuntimeConfig(configInput);\n this.startedAt = new Date().toISOString();\n\n this.client = new FiberRpcClient({\n url: this.config.fiberRpcUrl,\n timeout: this.config.requestTimeoutMs,\n });\n\n this.store = new MemoryStore({\n stateFilePath: this.config.storage.stateFilePath,\n flushIntervalMs: this.config.storage.flushIntervalMs,\n maxAlertHistory: this.config.storage.maxAlertHistory,\n });\n\n this.alerts = new AlertManager({\n backends: this.createAlertBackends(this.config),\n store: this.store,\n });\n\n this.jobStore = this.config.jobs.enabled ? new SqliteJobStore(this.config.jobs.dbPath) : null;\n this.jobManager = this.jobStore\n ? new JobManager(this.client, this.jobStore, {\n maxConcurrentJobs: this.config.jobs.maxConcurrentJobs,\n schedulerIntervalMs: this.config.jobs.schedulerIntervalMs,\n retryPolicy: this.config.jobs.retryPolicy,\n })\n : null;\n\n this.wireJobAlerts();\n\n const hooks = {};\n\n this.monitors = [\n new ChannelMonitor({\n client: this.client,\n store: this.store,\n alerts: this.alerts,\n config: {\n intervalMs: this.config.channelPollIntervalMs,\n includeClosedChannels: this.config.includeClosedChannels,\n },\n hooks,\n }),\n new InvoiceTracker({\n client: this.client,\n store: this.store,\n alerts: this.alerts,\n config: {\n intervalMs: this.config.invoicePollIntervalMs,\n completedItemTtlSeconds: this.config.completedItemTtlSeconds,\n },\n hooks,\n }),\n new PaymentTracker({\n client: this.client,\n store: this.store,\n alerts: this.alerts,\n config: {\n intervalMs: this.config.paymentPollIntervalMs,\n completedItemTtlSeconds: this.config.completedItemTtlSeconds,\n },\n hooks,\n }),\n new PeerMonitor({\n client: this.client,\n store: this.store,\n alerts: this.alerts,\n config: { intervalMs: this.config.peerPollIntervalMs },\n hooks,\n }),\n new HealthMonitor({\n client: this.client,\n alerts: this.alerts,\n config: { intervalMs: this.config.healthPollIntervalMs },\n }),\n ];\n\n this.alerts.onEmit((alert) => {\n this.emit('alert', alert);\n });\n\n const jobManager = this.jobManager;\n const jobStore = this.jobStore;\n\n this.proxy = new RpcMonitorProxy(\n {\n listen: this.config.proxy.listen,\n targetUrl: this.config.fiberRpcUrl,\n },\n {\n onInvoiceTracked: (paymentHash) => {\n this.store.addTrackedInvoice(paymentHash as `0x${string}`);\n },\n onPaymentTracked: (paymentHash) => {\n this.store.addTrackedPayment(paymentHash as `0x${string}`);\n },\n listTrackedInvoices: () => this.store.listTrackedInvoices(),\n listTrackedPayments: () => this.store.listTrackedPayments(),\n listAlerts: (filters) => this.store.listAlerts(filters),\n getStatus: () => this.getStatus(),\n createPaymentJob: jobManager\n ? (params, options) => jobManager.ensurePayment(params, options)\n : undefined,\n createInvoiceJob: jobManager\n ? (params, options) => jobManager.manageInvoice(params, options)\n : undefined,\n createChannelJob: jobManager\n ? (params, options) => jobManager.manageChannel(params, options)\n : undefined,\n getJob: jobManager ? (id) => jobManager.getJob(id) : undefined,\n listJobs: jobManager ? (filter) => jobManager.listJobs(filter) : undefined,\n cancelJob: jobManager ? (id) => jobManager.cancelJob(id) : undefined,\n listJobEvents: jobStore ? (jobId) => jobStore.listJobEvents(jobId) : undefined,\n },\n );\n }\n\n async start(): Promise<void> {\n if (this.running) {\n return;\n }\n\n await this.store.load();\n this.store.startAutoFlush();\n await this.alerts.start();\n\n for (const monitor of this.monitors) {\n monitor.start();\n }\n\n this.jobManager?.start();\n\n if (this.config.proxy.enabled) {\n await this.proxy.start();\n }\n\n this.running = true;\n }\n\n async stop(): Promise<void> {\n if (!this.running) {\n return;\n }\n\n for (const monitor of this.monitors) {\n monitor.stop();\n }\n\n await this.jobManager?.stop();\n\n if (this.config.proxy.enabled) {\n await this.proxy.stop();\n }\n\n this.store.stopAutoFlush();\n await this.store.flush();\n await this.alerts.stop();\n this.jobStore?.close();\n this.running = false;\n }\n\n getStatus(): {\n startedAt: string;\n proxyListen: string;\n targetUrl: string;\n running: boolean;\n } {\n return {\n startedAt: this.startedAt,\n proxyListen: this.config.proxy.listen,\n targetUrl: this.config.fiberRpcUrl,\n running: this.running,\n };\n }\n\n listAlerts(filters?: AlertFilter): Alert[] {\n return this.store.listAlerts(filters);\n }\n\n listTrackedInvoices() {\n return this.store.listTrackedInvoices();\n }\n\n listTrackedPayments() {\n return this.store.listTrackedPayments();\n }\n\n trackInvoice(paymentHash: `0x${string}`): void {\n this.store.addTrackedInvoice(paymentHash);\n }\n\n trackPayment(paymentHash: `0x${string}`): void {\n this.store.addTrackedPayment(paymentHash);\n }\n\n private createAlertBackends(config: RuntimeConfig): AlertBackend[] {\n return config.alerts.map((alertConfig) => {\n if (alertConfig.type === 'stdout') {\n return new StdoutAlertBackend();\n }\n if (alertConfig.type === 'webhook') {\n return new WebhookAlertBackend({\n url: alertConfig.url,\n timeoutMs: alertConfig.timeoutMs,\n headers: alertConfig.headers,\n });\n }\n if (alertConfig.type === 'file') {\n return new JsonlFileAlertBackend(alertConfig.path);\n }\n if (alertConfig.type === 'daily-file') {\n return new DailyJsonlFileAlertBackend(alertConfig.baseLogsDir, alertConfig.filename);\n }\n const [host, portText] = alertConfig.listen.split(':');\n return new WebsocketAlertBackend({\n host,\n port: Number(portText),\n });\n });\n }\n\n private wireJobAlerts(): void {\n if (!this.jobManager) {\n return;\n }\n\n this.jobManager.on('job:created', (job) => {\n this.emitJobAlert(job, 'started', 'low');\n this.trackJobArtifacts(job);\n });\n\n this.jobManager.on('job:state_changed', (job) => {\n this.trackJobArtifacts(job);\n if (job.state === 'waiting_retry') {\n this.emitJobAlert(job, 'retrying', 'medium');\n }\n });\n\n this.jobManager.on('job:succeeded', (job) => {\n this.trackJobArtifacts(job);\n this.emitJobAlert(job, 'succeeded', 'medium');\n });\n\n this.jobManager.on('job:failed', (job) => {\n this.trackJobArtifacts(job);\n this.emitJobAlert(job, 'failed', 'high');\n });\n }\n\n private emitJobAlert(\n job: RuntimeJob,\n lifecycle: 'started' | 'retrying' | 'succeeded' | 'failed',\n priority: 'low' | 'medium' | 'high',\n ): void {\n const type = this.toJobAlertType(job.type, lifecycle);\n const data = this.toJobAlertData(job);\n void this.alerts.emit({\n type,\n priority,\n source: 'job-manager',\n data,\n });\n }\n\n private toJobAlertType(\n jobType: RuntimeJob['type'],\n lifecycle: 'started' | 'retrying' | 'succeeded' | 'failed',\n ): AlertType {\n return `${jobType}_job_${lifecycle}` as AlertType;\n }\n\n private toJobAlertData(\n job: RuntimeJob,\n ): PaymentJobAlertData | InvoiceJobAlertData | ChannelJobAlertData {\n const error = job.error?.message;\n\n if (job.type === 'payment') {\n const paymentJob = job as PaymentJob;\n return {\n jobId: paymentJob.id,\n idempotencyKey: paymentJob.idempotencyKey,\n retryCount: paymentJob.retryCount,\n error,\n fee: paymentJob.result?.fee,\n };\n }\n\n if (job.type === 'invoice') {\n const invoiceJob = job as InvoiceJob;\n return {\n jobId: invoiceJob.id,\n idempotencyKey: invoiceJob.idempotencyKey,\n retryCount: invoiceJob.retryCount,\n action: invoiceJob.params.action,\n status: invoiceJob.result?.status,\n paymentHash: this.extractInvoiceHash(invoiceJob),\n error,\n };\n }\n\n const channelJob = job as ChannelJob;\n return {\n jobId: channelJob.id,\n idempotencyKey: channelJob.idempotencyKey,\n retryCount: channelJob.retryCount,\n action: channelJob.params.action,\n peerId: this.extractChannelPeerId(channelJob),\n temporaryChannelId: this.extractTemporaryChannelId(channelJob),\n channelId: this.extractChannelId(channelJob),\n fundingAmount: this.extractChannelFundingAmount(channelJob),\n error,\n };\n }\n\n private trackJobArtifacts(job: RuntimeJob): void {\n if (job.type === 'payment') {\n const paymentHash = this.extractPaymentHash(job);\n if (paymentHash) {\n this.store.addTrackedPayment(paymentHash);\n }\n return;\n }\n\n if (job.type === 'invoice') {\n const paymentHash = this.extractInvoiceHash(job);\n if (paymentHash) {\n this.store.addTrackedInvoice(paymentHash);\n }\n }\n }\n\n private extractPaymentHash(job: PaymentJob): `0x${string}` | undefined {\n return this.normalizeHash(job.result?.paymentHash ?? job.params.sendPaymentParams.payment_hash);\n }\n\n private extractInvoiceHash(job: InvoiceJob): `0x${string}` | undefined {\n return this.normalizeHash(\n job.result?.paymentHash ??\n job.params.getInvoicePaymentHash ??\n job.params.cancelInvoiceParams?.payment_hash ??\n job.params.settleInvoiceParams?.payment_hash ??\n job.params.newInvoiceParams?.payment_hash,\n );\n }\n\n private extractChannelId(job: ChannelJob): `0x${string}` | undefined {\n return this.normalizeHash(\n job.result?.channelId ??\n job.result?.acceptedChannelId ??\n job.params.channelId ??\n job.params.shutdownChannelParams?.channel_id,\n );\n }\n\n private extractChannelPeerId(job: ChannelJob): string | undefined {\n return job.params.peerId ?? job.params.openChannelParams?.peer_id;\n }\n\n private extractTemporaryChannelId(job: ChannelJob): `0x${string}` | undefined {\n return this.normalizeHash(\n job.result?.temporaryChannelId ?? job.params.acceptChannelParams?.temporary_channel_id,\n );\n }\n\n private extractChannelFundingAmount(job: ChannelJob): string | undefined {\n return job.params.openChannelParams?.funding_amount;\n }\n\n private normalizeHash(value: string | undefined): `0x${string}` | undefined {\n if (!value || !value.startsWith('0x')) {\n return undefined;\n }\n return value as `0x${string}`;\n }\n}\n","import { randomUUID } from 'node:crypto';\nimport type { Store } from '../storage/types.js';\nimport type { Alert, AlertBackend, AlertInput } from './types.js';\n\nexport type AlertEmitListener = (alert: Alert) => void;\n\nexport class AlertManager {\n private readonly backends: AlertBackend[];\n private readonly store: Store;\n private readonly listeners: AlertEmitListener[] = [];\n\n constructor(options: { backends: AlertBackend[]; store: Store }) {\n this.backends = options.backends;\n this.store = options.store;\n }\n\n /** Register a listener that is called after every emitted alert. */\n onEmit(listener: AlertEmitListener): void {\n this.listeners.push(listener);\n }\n\n async start(): Promise<void> {\n for (const backend of this.backends) {\n if (backend.start) {\n await backend.start();\n }\n }\n }\n\n async stop(): Promise<void> {\n for (const backend of this.backends) {\n if (backend.stop) {\n await backend.stop();\n }\n }\n }\n\n async emit(input: AlertInput): Promise<Alert> {\n const alert: Alert = {\n id: randomUUID(),\n timestamp: new Date().toISOString(),\n type: input.type,\n priority: input.priority,\n source: input.source,\n data: input.data,\n };\n\n this.store.addAlert(alert);\n\n await Promise.allSettled(this.backends.map((backend) => backend.send(alert)));\n\n for (const listener of this.listeners) {\n listener(alert);\n }\n\n return alert;\n }\n}\n","import { appendFileSync, mkdirSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport type { Alert, AlertBackend } from '../types.js';\n\nexport class JsonlFileAlertBackend implements AlertBackend {\n private readonly path: string;\n\n constructor(path: string) {\n this.path = path;\n mkdirSync(dirname(path), { recursive: true });\n }\n\n async send(alert: Alert): Promise<void> {\n appendFileSync(this.path, `${JSON.stringify(alert)}\\n`, 'utf-8');\n }\n}\n\nfunction todayDateString(): string {\n const now = new Date();\n const y = now.getUTCFullYear();\n const m = String(now.getUTCMonth() + 1).padStart(2, '0');\n const d = String(now.getUTCDate()).padStart(2, '0');\n return `${y}-${m}-${d}`;\n}\n\n/**\n * Alert backend that writes JSONL to a daily-rotated file under\n * `<baseLogsDir>/<YYYY-MM-DD>/<filename>`.\n */\nexport class DailyJsonlFileAlertBackend implements AlertBackend {\n private readonly baseLogsDir: string;\n private readonly filename: string;\n\n constructor(baseLogsDir: string, filename = 'runtime.alerts.jsonl') {\n this.baseLogsDir = baseLogsDir;\n this.filename = filename;\n }\n\n async send(alert: Alert): Promise<void> {\n const dateDir = join(this.baseLogsDir, todayDateString());\n mkdirSync(dateDir, { recursive: true });\n appendFileSync(join(dateDir, this.filename), `${JSON.stringify(alert)}\\n`, 'utf-8');\n }\n}\n","import { formatRuntimeAlert } from '../format.js';\nimport type { Alert, AlertBackend } from '../types.js';\n\nexport class StdoutAlertBackend implements AlertBackend {\n async send(alert: Alert): Promise<void> {\n console.log(formatRuntimeAlert(alert));\n }\n}\n","export function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(new DOMException('Aborted', 'AbortError'));\n return;\n }\n\n const timer = setTimeout(resolve, ms);\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer);\n reject(new DOMException('Aborted', 'AbortError'));\n },\n { once: true },\n );\n });\n}\n","import { sleep } from '../../utils/async.js';\nimport type { Alert, AlertBackend } from '../types.js';\n\nexport interface WebhookAlertBackendConfig {\n url: string;\n timeoutMs?: number;\n headers?: Record<string, string>;\n}\n\nexport class WebhookAlertBackend implements AlertBackend {\n private readonly config: Required<WebhookAlertBackendConfig>;\n\n constructor(config: WebhookAlertBackendConfig) {\n this.config = {\n timeoutMs: 5000,\n headers: {},\n ...config,\n };\n }\n\n async send(alert: Alert): Promise<void> {\n let lastError: unknown;\n\n for (let attempt = 0; attempt < 3; attempt += 1) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.config.timeoutMs);\n try {\n const response = await fetch(this.config.url, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n ...this.config.headers,\n },\n body: JSON.stringify(alert),\n signal: controller.signal,\n });\n clearTimeout(timer);\n\n if (response.ok) {\n return;\n }\n\n lastError = new Error(`Webhook response status: ${response.status}`);\n } catch (error) {\n clearTimeout(timer);\n lastError = error;\n }\n\n await sleep(100 * 2 ** attempt);\n }\n\n throw new Error(`Failed to deliver webhook alert: ${String(lastError)}`);\n }\n}\n","import { createHash } from 'node:crypto';\nimport http from 'node:http';\nimport type { Duplex } from 'node:stream';\nimport type { Alert, AlertBackend } from '../types.js';\n\nexport interface WebsocketAlertBackendConfig {\n host: string;\n port: number;\n}\n\nexport class WebsocketAlertBackend implements AlertBackend {\n private readonly config: WebsocketAlertBackendConfig;\n private readonly clients = new Set<Duplex>();\n private server: http.Server | undefined;\n\n constructor(config: WebsocketAlertBackendConfig) {\n this.config = config;\n }\n\n async start(): Promise<void> {\n if (this.server) {\n return;\n }\n\n this.server = http.createServer((req, res) => {\n if (req.url === '/health') {\n res.writeHead(200, { 'content-type': 'application/json' });\n res.end(JSON.stringify({ ok: true }));\n return;\n }\n\n res.writeHead(404, { 'content-type': 'application/json' });\n res.end(JSON.stringify({ error: 'Not found' }));\n });\n\n this.server.on('upgrade', (request, socket) => {\n const key = request.headers['sec-websocket-key'];\n if (!key || typeof key !== 'string') {\n socket.destroy();\n return;\n }\n\n const accept = createHash('sha1')\n .update(`${key}258EAFA5-E914-47DA-95CA-C5AB0DC85B11`)\n .digest('base64');\n\n const headers = [\n 'HTTP/1.1 101 Switching Protocols',\n 'Upgrade: websocket',\n 'Connection: Upgrade',\n `Sec-WebSocket-Accept: ${accept}`,\n ];\n\n socket.write(`${headers.join('\\r\\n')}\\r\\n\\r\\n`);\n this.clients.add(socket);\n socket.on('close', () => this.clients.delete(socket));\n socket.on('end', () => this.clients.delete(socket));\n socket.on('error', () => this.clients.delete(socket));\n });\n\n await new Promise<void>((resolve, reject) => {\n this.server?.once('error', reject);\n this.server?.listen(this.config.port, this.config.host, () => {\n this.server?.off('error', reject);\n resolve();\n });\n });\n }\n\n async send(alert: Alert): Promise<void> {\n const payload = Buffer.from(JSON.stringify(alert), 'utf8');\n const frame = buildWebSocketFrame(payload);\n\n for (const client of this.clients) {\n try {\n client.write(frame);\n } catch {\n this.clients.delete(client);\n }\n }\n }\n\n async stop(): Promise<void> {\n for (const client of this.clients) {\n client.destroy();\n }\n this.clients.clear();\n\n if (!this.server) {\n return;\n }\n\n const server = this.server;\n this.server = undefined;\n\n await new Promise<void>((resolve) => {\n server.close(() => resolve());\n });\n }\n}\n\nfunction buildWebSocketFrame(payload: Buffer): Buffer {\n const payloadLength = payload.length;\n if (payloadLength < 126) {\n return Buffer.concat([Buffer.from([0x81, payloadLength]), payload]);\n }\n\n if (payloadLength < 65536) {\n const header = Buffer.alloc(4);\n header[0] = 0x81;\n header[1] = 126;\n header.writeUInt16BE(payloadLength, 2);\n return Buffer.concat([header, payload]);\n }\n\n const header = Buffer.alloc(10);\n header[0] = 0x81;\n header[1] = 127;\n header.writeUInt32BE(0, 2);\n header.writeUInt32BE(payloadLength, 6);\n return Buffer.concat([header, payload]);\n}\n","import { resolve } from 'node:path';\nimport { defaultPaymentRetryPolicy } from './jobs/retry-policy.js';\nimport type { RetryPolicy } from './jobs/types.js';\n\nexport interface StdoutAlertConfig {\n type: 'stdout';\n}\n\nexport interface WebhookAlertConfig {\n type: 'webhook';\n url: string;\n timeoutMs?: number;\n headers?: Record<string, string>;\n}\n\nexport interface WebsocketAlertConfig {\n type: 'websocket';\n listen: string;\n}\n\nexport interface FileAlertConfig {\n type: 'file';\n path: string;\n}\n\nexport interface DailyFileAlertConfig {\n type: 'daily-file';\n baseLogsDir: string;\n filename?: string;\n}\n\nexport type AlertBackendConfig =\n | StdoutAlertConfig\n | WebhookAlertConfig\n | WebsocketAlertConfig\n | FileAlertConfig\n | DailyFileAlertConfig;\n\nexport interface RuntimeConfig {\n fiberRpcUrl: string;\n channelPollIntervalMs: number;\n invoicePollIntervalMs: number;\n paymentPollIntervalMs: number;\n peerPollIntervalMs: number;\n healthPollIntervalMs: number;\n includeClosedChannels: boolean;\n completedItemTtlSeconds: number;\n requestTimeoutMs: number;\n alerts: AlertBackendConfig[];\n proxy: {\n enabled: boolean;\n listen: string;\n };\n storage: {\n stateFilePath: string;\n flushIntervalMs: number;\n maxAlertHistory: number;\n };\n jobs: {\n /** Enable the payment job execution engine. Default: false */\n enabled: boolean;\n /** Path to the SQLite file for job persistence. Default: derived from storage.stateFilePath */\n dbPath: string;\n maxConcurrentJobs: number;\n schedulerIntervalMs: number;\n retryPolicy: RetryPolicy;\n };\n}\n\nexport type RuntimeConfigInput = Omit<Partial<RuntimeConfig>, 'proxy' | 'storage' | 'jobs'> & {\n proxy?: Partial<RuntimeConfig['proxy']>;\n storage?: Partial<RuntimeConfig['storage']>;\n jobs?: Partial<RuntimeConfig['jobs']>;\n};\n\nexport const defaultRuntimeConfig: RuntimeConfig = {\n fiberRpcUrl: 'http://127.0.0.1:8227',\n channelPollIntervalMs: 5000,\n invoicePollIntervalMs: 3000,\n paymentPollIntervalMs: 2000,\n peerPollIntervalMs: 15000,\n healthPollIntervalMs: 10000,\n includeClosedChannels: false,\n completedItemTtlSeconds: 86400,\n requestTimeoutMs: 10000,\n alerts: [{ type: 'stdout' }],\n proxy: {\n enabled: true,\n listen: '127.0.0.1:8229',\n },\n storage: {\n stateFilePath: resolve(process.cwd(), '.fiber-pay-runtime-state.json'),\n flushIntervalMs: 30000,\n maxAlertHistory: 5000,\n },\n jobs: {\n enabled: true,\n dbPath: resolve(process.cwd(), '.fiber-pay-jobs.db'),\n maxConcurrentJobs: 5,\n schedulerIntervalMs: 1000,\n retryPolicy: defaultPaymentRetryPolicy,\n },\n};\n\nexport function createRuntimeConfig(input: RuntimeConfigInput = {}): RuntimeConfig {\n const config: RuntimeConfig = {\n fiberRpcUrl: input.fiberRpcUrl ?? defaultRuntimeConfig.fiberRpcUrl,\n channelPollIntervalMs:\n input.channelPollIntervalMs ?? defaultRuntimeConfig.channelPollIntervalMs,\n invoicePollIntervalMs:\n input.invoicePollIntervalMs ?? defaultRuntimeConfig.invoicePollIntervalMs,\n paymentPollIntervalMs:\n input.paymentPollIntervalMs ?? defaultRuntimeConfig.paymentPollIntervalMs,\n peerPollIntervalMs: input.peerPollIntervalMs ?? defaultRuntimeConfig.peerPollIntervalMs,\n healthPollIntervalMs: input.healthPollIntervalMs ?? defaultRuntimeConfig.healthPollIntervalMs,\n includeClosedChannels:\n input.includeClosedChannels ?? defaultRuntimeConfig.includeClosedChannels,\n completedItemTtlSeconds:\n input.completedItemTtlSeconds ?? defaultRuntimeConfig.completedItemTtlSeconds,\n requestTimeoutMs: input.requestTimeoutMs ?? defaultRuntimeConfig.requestTimeoutMs,\n proxy: {\n enabled: input.proxy?.enabled ?? defaultRuntimeConfig.proxy.enabled,\n listen: input.proxy?.listen ?? defaultRuntimeConfig.proxy.listen,\n },\n storage: {\n stateFilePath: input.storage?.stateFilePath ?? defaultRuntimeConfig.storage.stateFilePath,\n flushIntervalMs:\n input.storage?.flushIntervalMs ?? defaultRuntimeConfig.storage.flushIntervalMs,\n maxAlertHistory:\n input.storage?.maxAlertHistory ?? defaultRuntimeConfig.storage.maxAlertHistory,\n },\n jobs: {\n enabled: input.jobs?.enabled ?? defaultRuntimeConfig.jobs.enabled,\n dbPath: input.jobs?.dbPath ?? defaultRuntimeConfig.jobs.dbPath,\n maxConcurrentJobs:\n input.jobs?.maxConcurrentJobs ?? defaultRuntimeConfig.jobs.maxConcurrentJobs,\n schedulerIntervalMs:\n input.jobs?.schedulerIntervalMs ?? defaultRuntimeConfig.jobs.schedulerIntervalMs,\n retryPolicy: {\n maxRetries:\n input.jobs?.retryPolicy?.maxRetries ?? defaultRuntimeConfig.jobs.retryPolicy.maxRetries,\n baseDelayMs:\n input.jobs?.retryPolicy?.baseDelayMs ?? defaultRuntimeConfig.jobs.retryPolicy.baseDelayMs,\n maxDelayMs:\n input.jobs?.retryPolicy?.maxDelayMs ?? defaultRuntimeConfig.jobs.retryPolicy.maxDelayMs,\n backoffMultiplier:\n input.jobs?.retryPolicy?.backoffMultiplier ??\n defaultRuntimeConfig.jobs.retryPolicy.backoffMultiplier,\n jitterMs:\n input.jobs?.retryPolicy?.jitterMs ?? defaultRuntimeConfig.jobs.retryPolicy.jitterMs,\n },\n },\n alerts: input.alerts ?? defaultRuntimeConfig.alerts,\n };\n\n if (!config.fiberRpcUrl) {\n throw new Error('Runtime config requires fiberRpcUrl');\n }\n if (!config.proxy.listen) {\n throw new Error('Runtime config requires proxy.listen');\n }\n if (config.channelPollIntervalMs <= 0 || config.invoicePollIntervalMs <= 0) {\n throw new Error('Polling intervals must be > 0');\n }\n if (config.paymentPollIntervalMs <= 0 || config.peerPollIntervalMs <= 0) {\n throw new Error('Polling intervals must be > 0');\n }\n if (config.healthPollIntervalMs <= 0) {\n throw new Error('healthPollIntervalMs must be > 0');\n }\n if (config.completedItemTtlSeconds < 0) {\n throw new Error('completedItemTtlSeconds must be >= 0');\n }\n if (config.storage.flushIntervalMs <= 0) {\n throw new Error('storage.flushIntervalMs must be > 0');\n }\n if (config.storage.maxAlertHistory <= 0) {\n throw new Error('storage.maxAlertHistory must be > 0');\n }\n if (!config.jobs.dbPath) {\n throw new Error('jobs.dbPath is required');\n }\n if (config.jobs.maxConcurrentJobs <= 0) {\n throw new Error('jobs.maxConcurrentJobs must be > 0');\n }\n if (config.jobs.schedulerIntervalMs <= 0) {\n throw new Error('jobs.schedulerIntervalMs must be > 0');\n }\n if (config.jobs.retryPolicy.maxRetries < 0) {\n throw new Error('jobs.retryPolicy.maxRetries must be >= 0');\n }\n if (config.jobs.retryPolicy.baseDelayMs < 0) {\n throw new Error('jobs.retryPolicy.baseDelayMs must be >= 0');\n }\n if (config.jobs.retryPolicy.maxDelayMs < 0) {\n throw new Error('jobs.retryPolicy.maxDelayMs must be >= 0');\n }\n\n return config;\n}\n\nexport function parseListenAddress(listen: string): { host: string; port: number } {\n const [host, portText] = listen.split(':');\n const port = Number(portText);\n if (!host || Number.isNaN(port) || port <= 0) {\n throw new Error(`Invalid listen address: ${listen}`);\n }\n return { host, port };\n}\n","import type { ClassifiedError, RetryPolicy } from './types.js';\n\nexport const defaultPaymentRetryPolicy: RetryPolicy = {\n maxRetries: 3,\n baseDelayMs: 2_000,\n maxDelayMs: 30_000,\n backoffMultiplier: 2,\n jitterMs: 500,\n};\n\n/**\n * Decide whether a job should be retried given its error and current retry count.\n */\nexport function shouldRetry(\n error: ClassifiedError,\n retryCount: number,\n policy: RetryPolicy,\n): boolean {\n if (!error.retryable) return false;\n if (retryCount >= policy.maxRetries) return false;\n return true;\n}\n\n/**\n * Compute the next retry delay using exponential backoff with random jitter.\n * retryCount is the number of retries already attempted (0-based before this retry).\n */\nexport function computeRetryDelay(retryCount: number, policy: RetryPolicy): number {\n const base = policy.baseDelayMs * policy.backoffMultiplier ** retryCount;\n const capped = Math.min(base, policy.maxDelayMs);\n const jitter = Math.floor(Math.random() * policy.jitterMs);\n return capped + jitter;\n}\n","import { randomUUID } from 'node:crypto';\nimport { EventEmitter } from 'node:events';\nimport type { FiberRpcClient } from '@fiber-pay/sdk';\nimport type { SqliteJobStore } from '../storage/sqlite-store.js';\nimport { runChannelJob } from './executors/channel-executor.js';\nimport { runInvoiceJob } from './executors/invoice-executor.js';\nimport { runPaymentJob } from './executors/payment-executor.js';\nimport { defaultPaymentRetryPolicy } from './retry-policy.js';\nimport type {\n ChannelJob,\n ChannelJobParams,\n InvoiceJob,\n InvoiceJobParams,\n JobFilter,\n JobState,\n PaymentJob,\n PaymentJobParams,\n RetryPolicy,\n RuntimeJob,\n} from './types.js';\nimport { TERMINAL_JOB_STATES } from './types.js';\n\nfunction stableStringify(value: unknown): string {\n if (value === null || typeof value !== 'object') {\n return JSON.stringify(value);\n }\n if (Array.isArray(value)) {\n return `[${value.map((item) => stableStringify(item)).join(',')}]`;\n }\n const entries = Object.entries(value as Record<string, unknown>)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, nested]) => `${JSON.stringify(key)}:${stableStringify(nested)}`);\n return `{${entries.join(',')}}`;\n}\n\nfunction haveSameParams(left: unknown, right: unknown): boolean {\n return stableStringify(left) === stableStringify(right);\n}\n\nexport interface JobManagerEvents {\n 'job:created': [job: RuntimeJob];\n 'job:state_changed': [job: RuntimeJob, from: JobState];\n 'job:succeeded': [job: RuntimeJob];\n 'job:failed': [job: RuntimeJob];\n 'job:cancelled': [job: RuntimeJob];\n}\n\ninterface ActiveExecution {\n abortController: AbortController;\n promise: Promise<void>;\n}\n\nexport interface JobManagerConfig {\n schedulerIntervalMs?: number;\n maxConcurrentJobs?: number;\n retryPolicy?: RetryPolicy;\n}\n\nexport class JobManager extends EventEmitter<JobManagerEvents> {\n private readonly rpc: FiberRpcClient;\n private readonly store: SqliteJobStore;\n private readonly retryPolicy: RetryPolicy;\n private readonly schedulerIntervalMs: number;\n private readonly maxConcurrentJobs: number;\n\n private running = false;\n private schedulerTimer: ReturnType<typeof setInterval> | undefined;\n private readonly active = new Map<string, ActiveExecution>();\n\n constructor(rpc: FiberRpcClient, store: SqliteJobStore, config: JobManagerConfig = {}) {\n super();\n this.rpc = rpc;\n this.store = store;\n this.retryPolicy = config.retryPolicy ?? defaultPaymentRetryPolicy;\n this.schedulerIntervalMs = config.schedulerIntervalMs ?? 1000;\n this.maxConcurrentJobs = config.maxConcurrentJobs ?? 5;\n }\n\n async ensurePayment(\n params: PaymentJobParams,\n options: {\n idempotencyKey?: string;\n maxRetries?: number;\n } = {},\n ): Promise<PaymentJob> {\n const idempotencyKey =\n options.idempotencyKey ??\n (params.sendPaymentParams.payment_hash as string | undefined) ??\n randomUUID();\n\n const existing = this.store.getJobByIdempotencyKey<PaymentJobParams, PaymentJob['result']>(\n idempotencyKey,\n );\n if (existing?.type === 'payment') {\n if (!haveSameParams(existing.params, params)) {\n throw new Error(\n `Idempotency key collision with different payment params: ${idempotencyKey}. Use a new idempotency key for a new payment intent.`,\n );\n }\n if (existing.state === 'succeeded' || existing.state === 'cancelled') {\n return existing as PaymentJob;\n }\n if (!TERMINAL_JOB_STATES.has(existing.state) || existing.state === 'failed') {\n if (existing.state === 'failed' && !this.active.has(existing.id)) {\n const reset = this.store.updateJob<PaymentJobParams, PaymentJob['result']>(existing.id, {\n state: 'queued',\n params,\n result: undefined,\n error: undefined,\n retryCount: 0,\n nextRetryAt: undefined,\n completedAt: undefined,\n });\n this.schedule(reset as RuntimeJob);\n return reset as PaymentJob;\n }\n return existing as PaymentJob;\n }\n }\n\n const job = this.store.createJob<PaymentJobParams, PaymentJob['result']>({\n type: 'payment',\n state: 'queued',\n params,\n retryCount: 0,\n maxRetries: options.maxRetries ?? this.retryPolicy.maxRetries,\n idempotencyKey,\n }) as PaymentJob;\n\n this.store.addJobEvent(job.id, 'created', undefined, 'queued', this.buildEventData(job));\n this.emit('job:created', job);\n this.schedule(job);\n return job;\n }\n\n async manageInvoice(\n params: InvoiceJobParams,\n options: { idempotencyKey?: string; maxRetries?: number; reuseTerminal?: boolean } = {},\n ): Promise<InvoiceJob> {\n const idempotencyKey = options.idempotencyKey ?? deriveInvoiceKey(params) ?? randomUUID();\n return this.createOrReuseJob<InvoiceJobParams, InvoiceJob['result']>(\n 'invoice',\n params,\n idempotencyKey,\n options.maxRetries,\n options.reuseTerminal,\n ) as Promise<InvoiceJob>;\n }\n\n async manageChannel(\n params: ChannelJobParams,\n options: { idempotencyKey?: string; maxRetries?: number; reuseTerminal?: boolean } = {},\n ): Promise<ChannelJob> {\n const idempotencyKey = options.idempotencyKey ?? deriveChannelKey(params) ?? randomUUID();\n return this.createOrReuseJob<ChannelJobParams, ChannelJob['result']>(\n 'channel',\n params,\n idempotencyKey,\n options.maxRetries,\n options.reuseTerminal,\n ) as Promise<ChannelJob>;\n }\n\n getJob(id: string): RuntimeJob | undefined {\n return this.store.getJob(id) as RuntimeJob | undefined;\n }\n\n listJobs(filter: JobFilter = {}): RuntimeJob[] {\n return this.store.listJobs(filter) as RuntimeJob[];\n }\n\n cancelJob(id: string): void {\n const job = this.getJob(id);\n if (!job) throw new Error(`Job not found: ${id}`);\n if (TERMINAL_JOB_STATES.has(job.state)) return;\n\n this.active.get(id)?.abortController.abort();\n\n if (!this.active.has(id)) {\n const updated = this.store.updateJob(id, {\n state: 'cancelled',\n completedAt: Date.now(),\n }) as RuntimeJob;\n this.store.addJobEvent(id, 'cancelled', job.state, 'cancelled', this.buildEventData(updated));\n this.emit('job:cancelled', updated);\n }\n }\n\n start(): void {\n if (this.running) return;\n this.running = true;\n this.recover();\n this.schedulerTimer = setInterval(() => this.tick(), this.schedulerIntervalMs);\n }\n\n async stop(): Promise<void> {\n this.running = false;\n if (this.schedulerTimer) {\n clearInterval(this.schedulerTimer);\n this.schedulerTimer = undefined;\n }\n for (const [, exec] of this.active) {\n exec.abortController.abort();\n }\n await Promise.allSettled(Array.from(this.active.values()).map((e) => e.promise));\n }\n\n private async createOrReuseJob<P, R>(\n type: 'invoice' | 'channel',\n params: P,\n idempotencyKey: string,\n maxRetries?: number,\n reuseTerminal?: boolean,\n ): Promise<RuntimeJob> {\n const existing = this.store.getJobByIdempotencyKey<P, R>(idempotencyKey);\n if (existing?.type === type) {\n if (!haveSameParams(existing.params, params)) {\n throw new Error(\n `Idempotency key collision with different ${type} params: ${idempotencyKey}. Use a new idempotency key for a new ${type} intent.`,\n );\n }\n if (existing.state === 'succeeded' || existing.state === 'cancelled') {\n if (reuseTerminal === false) {\n const reset = this.store.updateJob<P, R>(existing.id, {\n state: 'queued',\n params,\n result: undefined,\n error: undefined,\n retryCount: 0,\n nextRetryAt: undefined,\n completedAt: undefined,\n } as unknown as Partial<import('./types.js').Job<P, R>>);\n this.store.addJobEvent(\n existing.id,\n 'created',\n existing.state,\n 'queued',\n this.buildEventData(reset as RuntimeJob),\n );\n this.emit('job:created', reset as RuntimeJob);\n this.schedule(reset as RuntimeJob);\n return reset as RuntimeJob;\n }\n return existing as RuntimeJob;\n }\n if (!TERMINAL_JOB_STATES.has(existing.state) || existing.state === 'failed') {\n if (existing.state === 'failed' && !this.active.has(existing.id)) {\n const reset = this.store.updateJob<P, R>(existing.id, {\n state: 'queued',\n params,\n result: undefined,\n error: undefined,\n retryCount: 0,\n nextRetryAt: undefined,\n completedAt: undefined,\n });\n this.schedule(reset as RuntimeJob);\n return reset as RuntimeJob;\n }\n return existing as RuntimeJob;\n }\n }\n\n const job = this.store.createJob<P, R>({\n type,\n state: 'queued',\n params,\n retryCount: 0,\n maxRetries: maxRetries ?? this.retryPolicy.maxRetries,\n idempotencyKey,\n }) as RuntimeJob;\n\n this.store.addJobEvent(job.id, 'created', undefined, 'queued', this.buildEventData(job));\n this.emit('job:created', job);\n this.schedule(job);\n return job;\n }\n\n private tick(): void {\n if (!this.running) return;\n if (this.active.size >= this.maxConcurrentJobs) return;\n\n const queued = this.store.listJobs({\n state: 'queued',\n limit: this.maxConcurrentJobs - this.active.size,\n }) as RuntimeJob[];\n\n for (const job of queued) {\n if (this.active.size >= this.maxConcurrentJobs) break;\n if (!this.active.has(job.id)) {\n this.execute(job);\n }\n }\n\n if (this.active.size < this.maxConcurrentJobs) {\n const retryable = this.store.getRetryableJobs() as RuntimeJob[];\n for (const job of retryable) {\n if (this.active.size >= this.maxConcurrentJobs) break;\n if (!this.active.has(job.id)) {\n this.execute(job);\n }\n }\n }\n }\n\n private schedule(job: RuntimeJob): void {\n if (this.running && this.active.size < this.maxConcurrentJobs && !this.active.has(job.id)) {\n this.execute(job);\n }\n }\n\n private recover(): void {\n const inProgress = this.store.getInProgressJobs() as RuntimeJob[];\n for (const job of inProgress) {\n if (this.active.size >= this.maxConcurrentJobs) break;\n let recoveredJob = job;\n if (job.type === 'payment' && (job.state === 'executing' || job.state === 'inflight')) {\n recoveredJob = this.store.updateJob<unknown, unknown>(job.id, {\n state: 'inflight',\n }) as RuntimeJob;\n }\n this.execute(recoveredJob);\n }\n }\n\n private execute(job: RuntimeJob): void {\n const abortController = new AbortController();\n\n const promise = (async () => {\n try {\n const generator =\n job.type === 'payment'\n ? runPaymentJob(job as PaymentJob, this.rpc, this.retryPolicy, abortController.signal)\n : job.type === 'invoice'\n ? runInvoiceJob(job as InvoiceJob, this.rpc, this.retryPolicy, abortController.signal)\n : runChannelJob(\n job as ChannelJob,\n this.rpc,\n this.retryPolicy,\n abortController.signal,\n );\n\n for await (const updated of generator) {\n const prev = this.getJob(updated.id);\n const fromState = prev?.state ?? job.state;\n\n this.store.updateJob<unknown, unknown>(\n updated.id,\n updated as Partial<import('./types.js').Job>,\n );\n this.store.addJobEvent(\n updated.id,\n stateToEvent(updated.state),\n fromState,\n updated.state,\n this.buildEventData(updated),\n );\n\n this.emit('job:state_changed', updated, fromState);\n\n if (updated.state === 'succeeded') this.emit('job:succeeded', updated);\n if (updated.state === 'failed') this.emit('job:failed', updated);\n if (updated.state === 'cancelled') this.emit('job:cancelled', updated);\n }\n } finally {\n this.active.delete(job.id);\n }\n })();\n\n this.active.set(job.id, { abortController, promise });\n }\n\n private buildEventData(job: RuntimeJob): Record<string, unknown> {\n const base: Record<string, unknown> = {\n type: job.type,\n idempotencyKey: job.idempotencyKey,\n retryCount: job.retryCount,\n maxRetries: job.maxRetries,\n nextRetryAt: job.nextRetryAt,\n };\n\n if (job.error) {\n base.error = {\n category: job.error.category,\n retryable: job.error.retryable,\n message: job.error.message,\n };\n }\n\n if (job.type === 'payment') {\n const paymentJob = job as PaymentJob;\n return {\n ...base,\n invoice: paymentJob.params.invoice,\n paymentHash: paymentJob.result?.paymentHash,\n paymentStatus: paymentJob.result?.status,\n };\n }\n\n if (job.type === 'invoice') {\n const invoiceJob = job as InvoiceJob;\n return {\n ...base,\n action: invoiceJob.params.action,\n paymentHash: invoiceJob.result?.paymentHash ?? invoiceJob.params.getInvoicePaymentHash,\n invoiceStatus: invoiceJob.result?.status,\n };\n }\n\n const channelJob = job as ChannelJob;\n return {\n ...base,\n action: channelJob.params.action,\n channelId:\n channelJob.params.channelId ??\n channelJob.params.shutdownChannelParams?.channel_id ??\n channelJob.result?.channelId,\n peerId: channelJob.params.peerId ?? channelJob.params.openChannelParams?.peer_id,\n channelState: channelJob.result?.state,\n };\n }\n}\n\nfunction deriveInvoiceKey(params: InvoiceJobParams): string | undefined {\n if (params.action === 'watch' && params.getInvoicePaymentHash) {\n return `invoice:watch:${params.getInvoicePaymentHash}`;\n }\n if (params.action === 'cancel' && params.cancelInvoiceParams?.payment_hash) {\n return `invoice:cancel:${params.cancelInvoiceParams.payment_hash}`;\n }\n if (params.action === 'settle' && params.settleInvoiceParams?.payment_hash) {\n return `invoice:settle:${params.settleInvoiceParams.payment_hash}`;\n }\n if (params.action === 'create' && params.newInvoiceParams?.payment_hash) {\n return `invoice:create:${params.newInvoiceParams.payment_hash}`;\n }\n return undefined;\n}\n\nfunction deriveChannelKey(params: ChannelJobParams): string | undefined {\n if (params.action === 'open') return undefined;\n if (params.acceptChannelParams?.temporary_channel_id) {\n return `channel:accept:${params.acceptChannelParams.temporary_channel_id}`;\n }\n if (params.action === 'shutdown' && params.shutdownChannelParams?.channel_id) {\n return `channel:shutdown:${params.shutdownChannelParams.channel_id}`;\n }\n if (params.action === 'abandon' && params.abandonChannelParams?.channel_id) {\n return `channel:abandon:${params.abandonChannelParams.channel_id}`;\n }\n if (params.action === 'update' && params.updateChannelParams?.channel_id) {\n const fingerprint = stableStringify(params.updateChannelParams);\n return `channel:update:${params.updateChannelParams.channel_id}:${fingerprint}`;\n }\n if (params.channelId) return `channel:${params.action}:${params.channelId}`;\n return undefined;\n}\n\nfunction stateToEvent(state: JobState): import('./types.js').JobEventType {\n switch (state) {\n case 'executing':\n return 'executing';\n case 'inflight':\n return 'inflight';\n case 'invoice_created':\n return 'invoice_created';\n case 'invoice_received':\n return 'invoice_received';\n case 'invoice_settled':\n return 'invoice_settled';\n case 'invoice_expired':\n return 'invoice_expired';\n case 'invoice_cancelled':\n return 'invoice_cancelled';\n case 'channel_opening':\n return 'channel_opening';\n case 'channel_accepting':\n return 'channel_accepting';\n case 'channel_abandoning':\n return 'channel_abandoning';\n case 'channel_updating':\n return 'channel_updating';\n case 'channel_awaiting_ready':\n return 'channel_awaiting_ready';\n case 'channel_ready':\n return 'channel_ready';\n case 'channel_closing':\n return 'channel_closing';\n case 'channel_closed':\n return 'channel_closed';\n case 'waiting_retry':\n return 'retry_scheduled';\n case 'succeeded':\n return 'succeeded';\n case 'failed':\n return 'failed';\n case 'cancelled':\n return 'cancelled';\n default:\n return 'executing';\n }\n}\n","import { ChannelState, type FiberRpcClient } from '@fiber-pay/sdk';\nimport { sleep } from '../../utils/async.js';\nimport { classifyRpcError } from '../error-classifier.js';\nimport { applyRetryOrFail, transitionJobState } from '../executor-utils.js';\nimport { channelStateMachine } from '../state-machine.js';\nimport type { ChannelJob, ClassifiedError, RetryPolicy } from '../types.js';\n\nconst DEFAULT_POLL_INTERVAL = 2_000;\n\nexport async function* runChannelJob(\n job: ChannelJob,\n rpc: FiberRpcClient,\n policy: RetryPolicy,\n signal: AbortSignal,\n): AsyncGenerator<ChannelJob> {\n let current = { ...job };\n const resumedFromRetry = job.state === 'waiting_retry';\n\n if (current.state === 'queued') {\n current = transitionJobState(current, channelStateMachine, 'send_issued');\n yield current;\n }\n\n if (current.state === 'waiting_retry') {\n const delay = current.nextRetryAt ? Math.max(0, current.nextRetryAt - Date.now()) : 0;\n if (delay > 0) {\n await sleep(delay, signal);\n if (signal.aborted) {\n current = transitionJobState(current, channelStateMachine, 'cancel');\n yield current;\n return;\n }\n }\n current = transitionJobState(current, channelStateMachine, 'retry_delay_elapsed', {\n patch: { nextRetryAt: undefined },\n });\n yield current;\n }\n\n try {\n const pollIntervalMs = current.params.pollIntervalMs ?? DEFAULT_POLL_INTERVAL;\n\n if (current.params.action === 'open') {\n if (!current.params.openChannelParams) {\n throw new Error('Channel open job requires openChannelParams');\n }\n\n const targetPeerId = current.params.peerId ?? current.params.openChannelParams.peer_id;\n let temporaryChannelId = current.result?.temporaryChannelId;\n\n if (resumedFromRetry) {\n const existing = await findTargetChannel(rpc, targetPeerId, current.params.channelId);\n if (existing && !isClosed(existing.state.state_name)) {\n current = transitionJobState(current, channelStateMachine, 'channel_opening', {\n patch: {\n result: {\n temporaryChannelId,\n channelId: existing.channel_id,\n state: existing.state.state_name,\n },\n },\n });\n yield current;\n } else {\n const opened = await rpc.openChannel(current.params.openChannelParams);\n temporaryChannelId = opened.temporary_channel_id;\n current = transitionJobState(current, channelStateMachine, 'channel_opening', {\n patch: {\n result: {\n temporaryChannelId,\n state: 'OPENING',\n },\n },\n });\n yield current;\n }\n } else {\n const opened = await rpc.openChannel(current.params.openChannelParams);\n temporaryChannelId = opened.temporary_channel_id;\n current = transitionJobState(current, channelStateMachine, 'channel_opening', {\n patch: {\n result: {\n temporaryChannelId,\n state: 'OPENING',\n },\n },\n });\n yield current;\n }\n\n if (!current.params.waitForReady) {\n current = transitionJobState(current, channelStateMachine, 'payment_success');\n yield current;\n return;\n }\n\n while (true) {\n if (signal.aborted) {\n current = transitionJobState(current, channelStateMachine, 'cancel');\n yield current;\n return;\n }\n\n const channels = await rpc.listChannels({\n peer_id: targetPeerId,\n include_closed: true,\n });\n\n const candidates = channels.channels.filter((channel) => {\n if (current.params.channelId && channel.channel_id !== current.params.channelId)\n return false;\n return channel.peer_id === targetPeerId;\n });\n\n const readyMatch = candidates.find(\n (channel) => String(channel.state.state_name).toUpperCase() === 'CHANNEL_READY',\n );\n\n const activeMatch = candidates.find((channel) => !isClosed(channel.state.state_name));\n\n const closedMatch =\n current.params.channelId && !activeMatch && candidates.length > 0\n ? candidates.find((channel) => isTerminalClosed(channel.state.state_name))\n : undefined;\n\n if (readyMatch) {\n current = transitionJobState(current, channelStateMachine, 'channel_ready', {\n patch: {\n result: {\n temporaryChannelId,\n channelId: readyMatch.channel_id,\n state: readyMatch.state.state_name,\n },\n },\n });\n yield current;\n\n current = transitionJobState(current, channelStateMachine, 'payment_success');\n yield current;\n return;\n }\n\n if (closedMatch) {\n current = transitionJobState(current, channelStateMachine, 'channel_closed', {\n patch: {\n result: {\n temporaryChannelId,\n channelId: closedMatch.channel_id,\n state: closedMatch.state.state_name,\n },\n },\n });\n yield current;\n current = transitionJobState(current, channelStateMachine, 'payment_failed_permanent');\n yield current;\n return;\n }\n\n current = transitionJobState(current, channelStateMachine, 'channel_opening');\n yield current;\n await sleep(pollIntervalMs, signal);\n }\n }\n\n if (current.params.action === 'shutdown') {\n const shutdownParams = current.params.shutdownChannelParams;\n if (!shutdownParams) {\n throw new Error('Channel shutdown job requires shutdownChannelParams');\n }\n\n await rpc.shutdownChannel(shutdownParams);\n current = transitionJobState(current, channelStateMachine, 'channel_closing', {\n patch: {\n result: {\n channelId: shutdownParams.channel_id,\n state: 'SHUTTING_DOWN',\n },\n },\n });\n yield current;\n\n const waitForClosed = current.params.waitForClosed ?? Boolean(shutdownParams.force);\n if (!waitForClosed) {\n current = transitionJobState(current, channelStateMachine, 'payment_success');\n yield current;\n return;\n }\n\n while (true) {\n if (signal.aborted) {\n current = transitionJobState(current, channelStateMachine, 'cancel');\n yield current;\n return;\n }\n\n const channels = await rpc.listChannels({ include_closed: true });\n const match = channels.channels.find(\n (channel) => channel.channel_id === shutdownParams.channel_id,\n );\n\n if (!match || isTerminalClosed(String(match.state.state_name))) {\n current = transitionJobState(current, channelStateMachine, 'channel_closed', {\n patch: {\n result: {\n channelId: shutdownParams.channel_id,\n state: 'CLOSED',\n },\n },\n });\n yield current;\n current = transitionJobState(current, channelStateMachine, 'payment_success');\n yield current;\n return;\n }\n\n await sleep(pollIntervalMs, signal);\n }\n }\n\n if (current.params.action === 'accept') {\n if (!current.params.acceptChannelParams) {\n throw new Error('Channel accept job requires acceptChannelParams');\n }\n\n const accepted = await rpc.acceptChannel(current.params.acceptChannelParams);\n current = transitionJobState(current, channelStateMachine, 'channel_accepting', {\n patch: {\n result: {\n acceptedChannelId: accepted.channel_id,\n channelId: accepted.channel_id,\n state: 'ACCEPTED',\n },\n },\n });\n yield current;\n\n current = transitionJobState(current, channelStateMachine, 'payment_success');\n yield current;\n return;\n }\n\n if (current.params.action === 'abandon') {\n if (!current.params.abandonChannelParams) {\n throw new Error('Channel abandon job requires abandonChannelParams');\n }\n\n await rpc.abandonChannel(current.params.abandonChannelParams);\n current = transitionJobState(current, channelStateMachine, 'channel_abandoning', {\n patch: {\n result: {\n channelId: current.params.abandonChannelParams.channel_id,\n state: 'ABANDONED',\n },\n },\n });\n yield current;\n\n current = transitionJobState(current, channelStateMachine, 'payment_success');\n yield current;\n return;\n }\n\n if (current.params.action === 'update') {\n if (!current.params.updateChannelParams) {\n throw new Error('Channel update job requires updateChannelParams');\n }\n\n await rpc.updateChannel(current.params.updateChannelParams);\n current = transitionJobState(current, channelStateMachine, 'channel_updating', {\n patch: {\n result: {\n channelId: current.params.updateChannelParams.channel_id,\n state: 'UPDATED',\n },\n },\n });\n yield current;\n\n current = transitionJobState(current, channelStateMachine, 'payment_success');\n yield current;\n return;\n }\n\n throw new Error(\n `Unsupported channel action: ${(current.params as { action?: string }).action}`,\n );\n } catch (error) {\n const classified = classifyChannelError(error);\n current = applyRetryOrFail(current, classified, policy, {\n machine: channelStateMachine,\n retryEvent: 'payment_failed_retryable',\n failEvent: 'payment_failed_permanent',\n });\n yield current;\n }\n}\n\nfunction classifyChannelError(error: unknown): ClassifiedError {\n const base = classifyRpcError(error);\n if (base.retryable) {\n return base;\n }\n\n const raw = base.rawError ?? base.message;\n if (\n /channel\\s+not\\s+found|no\\s+channel\\s+with\\s+.*\\s+found|no\\s+channel\\s+.*\\s+found/i.test(raw)\n ) {\n return {\n ...base,\n category: 'temporary_failure',\n retryable: true,\n rawError: raw,\n };\n }\n\n if (/invalid\\s+state|negotiatingfunding|cannot\\s+.*\\s+in\\s+.*state/i.test(raw)) {\n return {\n ...base,\n category: 'temporary_failure',\n retryable: true,\n rawError: raw,\n };\n }\n\n return base;\n}\n\nasync function findTargetChannel(rpc: FiberRpcClient, peerId: string, channelId?: `0x${string}`) {\n const channels = await rpc.listChannels({\n peer_id: peerId,\n include_closed: true,\n });\n\n return channels.channels.find((channel) => {\n if (channelId && channel.channel_id !== channelId) return false;\n return channel.peer_id === peerId;\n });\n}\n\nfunction isClosed(stateName: string): boolean {\n return (\n stateName === ChannelState.Closed ||\n stateName === 'CLOSED' ||\n stateName === ChannelState.ShuttingDown ||\n stateName === 'SHUTTING_DOWN'\n );\n}\n\nfunction isTerminalClosed(stateName: string): boolean {\n return stateName === ChannelState.Closed || stateName === 'CLOSED';\n}\n","import type { ClassifiedError, ErrorCategory } from './types.js';\n\n// Fiber node error strings seen in `failed_error` field of PaymentInfo.\n// These are best-effort matches — extend as real failure messages are observed.\nconst PATTERNS: Array<{ pattern: RegExp; category: ErrorCategory; retryable: boolean }> = [\n // Routing / topology\n { pattern: /no path found|no route|route not found/i, category: 'no_route', retryable: true },\n { pattern: /no outgoing channel|no available channel/i, category: 'no_route', retryable: true },\n // Liquidity\n {\n pattern: /insufficient (balance|capacity|funds)/i,\n category: 'insufficient_balance',\n retryable: false,\n },\n {\n pattern: /amount.*too large|exceeds.*capacity/i,\n category: 'amount_too_large',\n retryable: false,\n },\n // Invoice lifecycle\n { pattern: /invoice.*expir|expir.*invoice/i, category: 'invoice_expired', retryable: false },\n { pattern: /invoice.*cancel|cancel.*invoice/i, category: 'invoice_cancelled', retryable: false },\n {\n pattern: /payment hash.*exist|payment_hash.*exist|duplicated payment hash/i,\n category: 'invalid_payment',\n retryable: false,\n },\n // Peer / connectivity\n {\n pattern: /peer.*offline|peer.*unreachable|peer.*disconnect/i,\n category: 'peer_offline',\n retryable: true,\n },\n { pattern: /connection.*refused|connection.*reset/i, category: 'peer_offline', retryable: true },\n { pattern: /fetch failed/i, category: 'peer_offline', retryable: true },\n {\n pattern: /peer.*feature not found|waiting for peer to send init message/i,\n category: 'peer_offline',\n retryable: true,\n },\n {\n pattern: /channel.*already.*exist|duplicat(e|ed).*channel/i,\n category: 'temporary_failure',\n retryable: true,\n },\n // Timeout\n { pattern: /timeout|timed out/i, category: 'timeout', retryable: true },\n // Payment validity\n {\n pattern: /invalid.*invoice|malformed.*invoice/i,\n category: 'invalid_payment',\n retryable: false,\n },\n {\n pattern: /payment.*hash.*mismatch|preimage.*invalid/i,\n category: 'invalid_payment',\n retryable: false,\n },\n // Generic temporary\n {\n pattern: /temporary.*failure|try again|retry/i,\n category: 'temporary_failure',\n retryable: true,\n },\n];\n\n/**\n * Classify an RPC / job failure into a structured error.\n *\n * `failedError` is the raw `failed_error` string from Fiber's `get_payment` response.\n * `error` is any caught JS exception.\n */\nexport function classifyRpcError(error: unknown, failedError?: string): ClassifiedError {\n // Prefer Fiber's own error string since it is the most authoritative\n const raw = failedError ?? (error instanceof Error ? error.message : String(error));\n\n for (const { pattern, category, retryable } of PATTERNS) {\n if (pattern.test(raw)) {\n return { category, retryable, message: raw, rawError: raw };\n }\n }\n\n return {\n category: 'unknown',\n retryable: false, // safe default: don't retry unknowns\n message: raw,\n rawError: raw,\n };\n}\n","import { computeRetryDelay, shouldRetry } from './retry-policy.js';\nimport type { JobStateMachine, MachineEvent } from './state-machine.js';\nimport type { ClassifiedError, JobState, RetryPolicy } from './types.js';\n\ntype RetryableJobShape = {\n state: JobState;\n error?: ClassifiedError;\n retryCount: number;\n maxRetries: number;\n nextRetryAt?: number;\n updatedAt: number;\n completedAt?: number;\n};\n\nexport function transitionJobState<\n T extends { state: JobState; updatedAt: number; completedAt?: number },\n>(\n job: T,\n machine: JobStateMachine,\n event: MachineEvent,\n options?: {\n now?: number;\n patch?: Partial<T>;\n },\n): T {\n const nextState = machine.transition(job.state, event);\n if (!nextState) {\n throw new Error(`Invalid state transition: ${job.state} --${event}--> ?`);\n }\n\n const now = options?.now ?? Date.now();\n return {\n ...job,\n ...(options?.patch ?? {}),\n state: nextState,\n updatedAt: now,\n completedAt: machine.isTerminal(nextState) ? now : job.completedAt,\n } as T;\n}\n\nexport function applyRetryOrFail<T extends RetryableJobShape>(\n job: T,\n classifiedError: ClassifiedError,\n policy: RetryPolicy,\n options?: {\n now?: number;\n failedPatch?: Partial<T>;\n machine?: JobStateMachine;\n retryEvent?: MachineEvent;\n failEvent?: MachineEvent;\n },\n): T {\n const now = options?.now ?? Date.now();\n\n const effectivePolicy: RetryPolicy = {\n ...policy,\n maxRetries: job.maxRetries,\n };\n\n if (shouldRetry(classifiedError, job.retryCount, effectivePolicy)) {\n const delay = computeRetryDelay(job.retryCount, effectivePolicy);\n const retryTransition =\n options?.machine && options.retryEvent\n ? transitionJobState(job, options.machine, options.retryEvent, { now })\n : ({ ...job, state: 'waiting_retry', updatedAt: now } as T);\n\n return {\n ...retryTransition,\n error: classifiedError,\n retryCount: job.retryCount + 1,\n nextRetryAt: now + delay,\n } as T;\n }\n\n const failTransition =\n options?.machine && options.failEvent\n ? transitionJobState(job, options.machine, options.failEvent, { now })\n : ({ ...job, state: 'failed', completedAt: now, updatedAt: now } as T);\n\n return {\n ...failTransition,\n error: classifiedError,\n ...(options?.failedPatch ?? {}),\n } as T;\n}\n","import type { JobState } from './types.js';\n\n// ─── State Machine ────────────────────────────────────────────────────────────\n\nexport type MachineEvent =\n | 'send_issued'\n | 'payment_inflight'\n | 'payment_success'\n | 'payment_failed_retryable'\n | 'payment_failed_permanent'\n | 'invoice_created'\n | 'invoice_received'\n | 'invoice_settled'\n | 'invoice_expired'\n | 'invoice_cancelled'\n | 'channel_opening'\n | 'channel_accepting'\n | 'channel_abandoning'\n | 'channel_updating'\n | 'channel_closing'\n | 'channel_ready'\n | 'channel_closed'\n | 'channel_failed'\n | 'retry_delay_elapsed'\n | 'cancel';\n\ninterface Transition {\n from: JobState | JobState[];\n event: MachineEvent;\n to: JobState;\n}\n\nconst PAYMENT_TRANSITIONS: Transition[] = [\n { from: 'queued', event: 'send_issued', to: 'executing' },\n { from: 'executing', event: 'payment_inflight', to: 'inflight' },\n { from: 'executing', event: 'payment_success', to: 'succeeded' },\n { from: 'executing', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'executing', event: 'payment_failed_permanent', to: 'failed' },\n { from: 'inflight', event: 'payment_success', to: 'succeeded' },\n { from: 'inflight', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'inflight', event: 'payment_failed_permanent', to: 'failed' },\n { from: 'waiting_retry', event: 'retry_delay_elapsed', to: 'executing' },\n {\n from: ['queued', 'executing', 'inflight', 'waiting_retry'],\n event: 'cancel',\n to: 'cancelled',\n },\n];\n\nconst INVOICE_TRANSITIONS: Transition[] = [\n { from: 'queued', event: 'send_issued', to: 'executing' },\n { from: 'executing', event: 'invoice_created', to: 'invoice_created' },\n { from: 'invoice_created', event: 'payment_success', to: 'succeeded' },\n { from: 'executing', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'invoice_created', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'invoice_active', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'invoice_received', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'waiting_retry', event: 'retry_delay_elapsed', to: 'executing' },\n { from: 'invoice_created', event: 'invoice_received', to: 'invoice_received' },\n { from: 'invoice_created', event: 'invoice_settled', to: 'invoice_settled' },\n { from: 'invoice_active', event: 'invoice_received', to: 'invoice_received' },\n { from: 'invoice_active', event: 'invoice_settled', to: 'invoice_settled' },\n { from: 'invoice_active', event: 'invoice_expired', to: 'invoice_expired' },\n { from: 'invoice_active', event: 'invoice_cancelled', to: 'invoice_cancelled' },\n { from: 'invoice_received', event: 'invoice_settled', to: 'invoice_settled' },\n {\n from: ['invoice_created', 'invoice_received'],\n event: 'invoice_expired',\n to: 'invoice_expired',\n },\n {\n from: ['invoice_created', 'invoice_received'],\n event: 'invoice_cancelled',\n to: 'invoice_cancelled',\n },\n {\n from: ['invoice_settled', 'invoice_expired', 'invoice_cancelled'],\n event: 'payment_success',\n to: 'succeeded',\n },\n {\n from: ['invoice_expired', 'invoice_cancelled'],\n event: 'payment_failed_permanent',\n to: 'failed',\n },\n {\n from: ['executing', 'invoice_created', 'invoice_active', 'invoice_received'],\n event: 'payment_failed_permanent',\n to: 'failed',\n },\n {\n from: [\n 'queued',\n 'executing',\n 'waiting_retry',\n 'invoice_created',\n 'invoice_active',\n 'invoice_received',\n ],\n event: 'cancel',\n to: 'cancelled',\n },\n];\n\nconst CHANNEL_TRANSITIONS: Transition[] = [\n { from: 'queued', event: 'send_issued', to: 'executing' },\n { from: 'executing', event: 'channel_opening', to: 'channel_opening' },\n { from: 'executing', event: 'channel_accepting', to: 'channel_accepting' },\n { from: 'executing', event: 'channel_abandoning', to: 'channel_abandoning' },\n { from: 'executing', event: 'channel_updating', to: 'channel_updating' },\n { from: 'channel_opening', event: 'payment_success', to: 'succeeded' },\n { from: 'channel_accepting', event: 'payment_success', to: 'succeeded' },\n { from: 'channel_abandoning', event: 'payment_success', to: 'succeeded' },\n { from: 'channel_updating', event: 'payment_success', to: 'succeeded' },\n { from: 'executing', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'channel_opening', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'channel_accepting', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'channel_abandoning', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'channel_updating', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'channel_awaiting_ready', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'channel_closing', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'executing', event: 'payment_failed_permanent', to: 'failed' },\n { from: 'channel_opening', event: 'payment_failed_permanent', to: 'failed' },\n { from: 'channel_accepting', event: 'payment_failed_permanent', to: 'failed' },\n { from: 'channel_abandoning', event: 'payment_failed_permanent', to: 'failed' },\n { from: 'channel_updating', event: 'payment_failed_permanent', to: 'failed' },\n { from: 'channel_awaiting_ready', event: 'payment_failed_permanent', to: 'failed' },\n { from: 'channel_closing', event: 'payment_failed_permanent', to: 'failed' },\n { from: ['executing', 'channel_ready'], event: 'channel_closing', to: 'channel_closing' },\n { from: 'waiting_retry', event: 'retry_delay_elapsed', to: 'executing' },\n { from: 'channel_opening', event: 'channel_opening', to: 'channel_awaiting_ready' },\n { from: 'channel_awaiting_ready', event: 'channel_opening', to: 'channel_awaiting_ready' },\n { from: 'channel_opening', event: 'channel_ready', to: 'channel_ready' },\n { from: 'channel_awaiting_ready', event: 'channel_ready', to: 'channel_ready' },\n { from: ['channel_opening', 'channel_ready'], event: 'channel_closed', to: 'channel_closed' },\n { from: 'channel_awaiting_ready', event: 'channel_closed', to: 'channel_closed' },\n { from: 'channel_closing', event: 'channel_closed', to: 'channel_closed' },\n { from: 'channel_closing', event: 'payment_success', to: 'succeeded' },\n { from: 'channel_closed', event: 'payment_failed_permanent', to: 'failed' },\n { from: ['channel_ready', 'channel_opening'], event: 'channel_failed', to: 'failed' },\n { from: ['channel_ready', 'channel_closed'], event: 'payment_success', to: 'succeeded' },\n {\n from: [\n 'queued',\n 'executing',\n 'waiting_retry',\n 'channel_opening',\n 'channel_accepting',\n 'channel_abandoning',\n 'channel_updating',\n 'channel_awaiting_ready',\n 'channel_ready',\n 'channel_closing',\n ],\n event: 'cancel',\n to: 'cancelled',\n },\n];\n\nexport class JobStateMachine {\n private readonly table: Map<string, JobState>;\n\n constructor(transitions: Transition[]) {\n this.table = new Map();\n for (const t of transitions) {\n const froms = Array.isArray(t.from) ? t.from : [t.from];\n for (const from of froms) {\n this.table.set(`${from}:${t.event}`, t.to);\n }\n }\n }\n\n transition(current: JobState, event: MachineEvent): JobState | null {\n return this.table.get(`${current}:${event}`) ?? null;\n }\n\n isTerminal(state: JobState): boolean {\n return state === 'succeeded' || state === 'failed' || state === 'cancelled';\n }\n}\n\nexport const paymentStateMachine = new JobStateMachine(PAYMENT_TRANSITIONS);\nexport const invoiceStateMachine = new JobStateMachine(INVOICE_TRANSITIONS);\nexport const channelStateMachine = new JobStateMachine(CHANNEL_TRANSITIONS);\n","import type { FiberRpcClient } from '@fiber-pay/sdk';\nimport { sleep } from '../../utils/async.js';\nimport { classifyRpcError } from '../error-classifier.js';\nimport { applyRetryOrFail, transitionJobState } from '../executor-utils.js';\nimport { invoiceStateMachine } from '../state-machine.js';\nimport type { InvoiceJob, RetryPolicy } from '../types.js';\n\nconst DEFAULT_POLL_INTERVAL = 1_500;\n\nexport async function* runInvoiceJob(\n job: InvoiceJob,\n rpc: FiberRpcClient,\n policy: RetryPolicy,\n signal: AbortSignal,\n): AsyncGenerator<InvoiceJob> {\n let current = { ...job };\n\n if (current.state === 'queued') {\n current = transitionJobState(current, invoiceStateMachine, 'send_issued');\n yield current;\n }\n\n if (current.state === 'waiting_retry') {\n const delay = current.nextRetryAt ? Math.max(0, current.nextRetryAt - Date.now()) : 0;\n if (delay > 0) {\n await sleep(delay, signal);\n if (signal.aborted) {\n current = transitionJobState(current, invoiceStateMachine, 'cancel');\n yield current;\n return;\n }\n }\n current = transitionJobState(current, invoiceStateMachine, 'retry_delay_elapsed', {\n patch: { nextRetryAt: undefined },\n });\n yield current;\n }\n\n try {\n const pollIntervalMs = current.params.pollIntervalMs ?? DEFAULT_POLL_INTERVAL;\n\n if (current.params.action === 'create') {\n if (!current.params.newInvoiceParams) {\n throw new Error('Invoice create job requires newInvoiceParams');\n }\n const created = await rpc.newInvoice(current.params.newInvoiceParams);\n const paymentHash = created.invoice.data.payment_hash;\n const createdStatus = 'Open';\n\n current = {\n ...current,\n state: 'invoice_created',\n result: {\n paymentHash,\n invoiceAddress: created.invoice_address,\n status: createdStatus,\n invoice: created.invoice,\n },\n updatedAt: Date.now(),\n };\n yield current;\n\n if (!current.params.waitForTerminal) {\n current = transitionJobState(current, invoiceStateMachine, 'payment_success');\n yield current;\n return;\n }\n\n // Watch invoice until terminal\n while (true) {\n if (signal.aborted) {\n current = transitionJobState(current, invoiceStateMachine, 'cancel');\n yield current;\n return;\n }\n\n const invoice = await rpc.getInvoice({ payment_hash: paymentHash });\n if (invoice.status === 'Paid') {\n current = {\n ...current,\n state: 'invoice_settled',\n result: {\n paymentHash,\n invoiceAddress: invoice.invoice_address,\n status: invoice.status,\n invoice: invoice.invoice,\n },\n updatedAt: Date.now(),\n };\n yield current;\n\n current = transitionJobState(current, invoiceStateMachine, 'payment_success');\n yield current;\n return;\n }\n\n if (invoice.status === 'Received') {\n current = {\n ...current,\n state: 'invoice_received',\n result: {\n paymentHash,\n invoiceAddress: invoice.invoice_address,\n status: invoice.status,\n invoice: invoice.invoice,\n },\n updatedAt: Date.now(),\n };\n yield current;\n } else if (invoice.status === 'Cancelled') {\n current = {\n ...current,\n state: 'invoice_cancelled',\n result: {\n paymentHash,\n invoiceAddress: invoice.invoice_address,\n status: invoice.status,\n invoice: invoice.invoice,\n },\n completedAt: Date.now(),\n updatedAt: Date.now(),\n };\n yield current;\n current = transitionJobState(current, invoiceStateMachine, 'payment_failed_permanent');\n yield current;\n return;\n } else if (invoice.status === 'Expired') {\n current = {\n ...current,\n state: 'invoice_expired',\n result: {\n paymentHash,\n invoiceAddress: invoice.invoice_address,\n status: invoice.status,\n invoice: invoice.invoice,\n },\n completedAt: Date.now(),\n updatedAt: Date.now(),\n };\n yield current;\n current = transitionJobState(current, invoiceStateMachine, 'payment_failed_permanent');\n yield current;\n return;\n }\n\n await sleep(pollIntervalMs, signal);\n }\n }\n\n if (current.params.action === 'watch') {\n if (!current.params.getInvoicePaymentHash) {\n throw new Error('Invoice watch job requires getInvoicePaymentHash');\n }\n const paymentHash = current.params.getInvoicePaymentHash;\n while (true) {\n if (signal.aborted) {\n current = transitionJobState(current, invoiceStateMachine, 'cancel');\n yield current;\n return;\n }\n\n const invoice = await rpc.getInvoice({ payment_hash: paymentHash });\n current = {\n ...current,\n state:\n invoice.status === 'Paid'\n ? 'invoice_settled'\n : invoice.status === 'Received'\n ? 'invoice_received'\n : invoice.status === 'Cancelled'\n ? 'invoice_cancelled'\n : invoice.status === 'Expired'\n ? 'invoice_expired'\n : 'invoice_active',\n result: {\n paymentHash,\n invoiceAddress: invoice.invoice_address,\n status: invoice.status,\n invoice: invoice.invoice,\n },\n updatedAt: Date.now(),\n };\n yield current;\n\n if (invoice.status === 'Paid') {\n current = transitionJobState(current, invoiceStateMachine, 'payment_success');\n yield current;\n return;\n }\n if (invoice.status === 'Cancelled' || invoice.status === 'Expired') {\n current = transitionJobState(current, invoiceStateMachine, 'payment_failed_permanent');\n yield current;\n return;\n }\n\n await sleep(pollIntervalMs, signal);\n }\n }\n\n if (current.params.action === 'cancel') {\n if (!current.params.cancelInvoiceParams) {\n throw new Error('Invoice cancel job requires cancelInvoiceParams');\n }\n const cancelled = await rpc.cancelInvoice(current.params.cancelInvoiceParams);\n current = {\n ...current,\n state: 'invoice_cancelled',\n result: {\n paymentHash: current.params.cancelInvoiceParams.payment_hash,\n invoiceAddress: cancelled.invoice_address,\n status: cancelled.status,\n invoice: cancelled.invoice,\n },\n updatedAt: Date.now(),\n };\n yield current;\n current = transitionJobState(current, invoiceStateMachine, 'payment_success');\n yield current;\n return;\n }\n\n if (current.params.action === 'settle') {\n if (!current.params.settleInvoiceParams) {\n throw new Error('Invoice settle job requires settleInvoiceParams');\n }\n await rpc.settleInvoice(current.params.settleInvoiceParams);\n current = {\n ...current,\n state: 'invoice_settled',\n result: {\n paymentHash: current.params.settleInvoiceParams.payment_hash,\n status: 'Paid',\n },\n updatedAt: Date.now(),\n };\n yield current;\n current = transitionJobState(current, invoiceStateMachine, 'payment_success');\n yield current;\n return;\n }\n\n throw new Error(\n `Unsupported invoice action: ${(current.params as { action?: string }).action}`,\n );\n } catch (error) {\n const classified = classifyRpcError(error);\n current = applyRetryOrFail(current, classified, policy, {\n machine: invoiceStateMachine,\n retryEvent: 'payment_failed_retryable',\n failEvent: 'payment_failed_permanent',\n });\n yield current;\n }\n}\n","import type { FiberRpcClient } from '@fiber-pay/sdk';\nimport { sleep } from '../../utils/async.js';\nimport { classifyRpcError } from '../error-classifier.js';\nimport { applyRetryOrFail, transitionJobState } from '../executor-utils.js';\nimport { paymentStateMachine } from '../state-machine.js';\nimport type { PaymentJob, RetryPolicy } from '../types.js';\n\n// ─── PaymentExecutor ──────────────────────────────────────────────────────────\n\n/**\n * Drives a single PaymentJob through its full lifecycle.\n *\n * Yields the updated job object on every state transition so the caller\n * (JobManager) can persist + emit events after each change with no extra lookups.\n *\n * The generator terminates when the job reaches a terminal state\n * (succeeded | failed | cancelled).\n */\nexport async function* runPaymentJob(\n job: PaymentJob,\n rpc: FiberRpcClient,\n policy: RetryPolicy,\n signal: AbortSignal,\n): AsyncGenerator<PaymentJob> {\n let current = { ...job };\n\n while (!paymentStateMachine.isTerminal(current.state)) {\n if (signal.aborted) {\n current = transitionJobState(current, paymentStateMachine, 'cancel');\n yield current;\n return;\n }\n\n if (current.state === 'queued') {\n current = transitionJobState(current, paymentStateMachine, 'send_issued');\n yield current;\n continue;\n }\n\n if (current.state === 'waiting_retry') {\n const delay = current.nextRetryAt ? Math.max(0, current.nextRetryAt - Date.now()) : 0;\n if (delay > 0) {\n await sleep(delay, signal);\n if (signal.aborted) {\n current = transitionJobState(current, paymentStateMachine, 'cancel');\n yield current;\n return;\n }\n }\n current = transitionJobState(current, paymentStateMachine, 'retry_delay_elapsed', {\n patch: { nextRetryAt: undefined },\n });\n yield current;\n continue;\n }\n\n if (current.state === 'executing') {\n // ── Issue the RPC call ──────────────────────────────────────────────────\n let paymentHash: string | undefined;\n\n try {\n const sendResult = await rpc.sendPayment(current.params.sendPaymentParams);\n paymentHash = sendResult.payment_hash;\n\n if (sendResult.status === 'Success') {\n current = transitionJobState(current, paymentStateMachine, 'payment_success', {\n patch: {\n result: {\n paymentHash: sendResult.payment_hash,\n status: sendResult.status,\n fee: sendResult.fee,\n failedError: sendResult.failed_error,\n },\n },\n });\n yield current;\n return;\n }\n\n if (sendResult.status === 'Failed') {\n const classified = classifyRpcError(\n new Error(sendResult.failed_error ?? 'Payment failed'),\n sendResult.failed_error,\n );\n current = applyRetryOrFail(current, classified, policy, {\n failedPatch: {\n result: {\n paymentHash: sendResult.payment_hash,\n status: sendResult.status,\n fee: sendResult.fee,\n failedError: sendResult.failed_error,\n },\n },\n machine: paymentStateMachine,\n retryEvent: 'payment_failed_retryable',\n failEvent: 'payment_failed_permanent',\n });\n yield current;\n continue;\n }\n\n // Status is 'Created' or 'Inflight' — move to polling state\n // Dry-run payments are never persisted by the node, so polling\n // getPayment would loop forever with \"Payment session not found\".\n if (current.params.sendPaymentParams.dry_run) {\n current = transitionJobState(current, paymentStateMachine, 'payment_success', {\n patch: {\n result: {\n paymentHash: sendResult.payment_hash,\n status: 'DryRunSuccess',\n fee: sendResult.fee,\n },\n },\n });\n yield current;\n return;\n }\n\n current = transitionJobState(current, paymentStateMachine, 'payment_inflight');\n if (paymentHash) {\n current = {\n ...current,\n params: {\n ...current.params,\n sendPaymentParams: {\n ...current.params.sendPaymentParams,\n payment_hash: paymentHash as `0x${string}`,\n },\n },\n };\n }\n yield current;\n continue;\n } catch (err) {\n // RPC call itself threw — classify and decide\n const classified = classifyRpcError(err);\n current = applyRetryOrFail(current, classified, policy, {\n machine: paymentStateMachine,\n retryEvent: 'payment_failed_retryable',\n failEvent: 'payment_failed_permanent',\n });\n yield current;\n continue;\n }\n }\n\n if (current.state === 'inflight') {\n // ── Poll get_payment until terminal ────────────────────────────────────\n const hash = current.params.sendPaymentParams.payment_hash as string | undefined;\n\n if (!hash) {\n // Shouldn't happen, but fail-safe\n current = transitionJobState(current, paymentStateMachine, 'payment_failed_permanent', {\n patch: {\n error: {\n category: 'unknown',\n retryable: false,\n message: 'No payment_hash in inflight job',\n },\n },\n });\n yield current;\n continue;\n }\n\n try {\n const pollResult = await rpc.getPayment({ payment_hash: hash as `0x${string}` });\n\n if (pollResult.status === 'Success') {\n current = transitionJobState(current, paymentStateMachine, 'payment_success', {\n patch: {\n result: {\n paymentHash: pollResult.payment_hash,\n status: pollResult.status,\n fee: pollResult.fee,\n failedError: pollResult.failed_error,\n },\n },\n });\n yield current;\n return;\n }\n\n if (pollResult.status === 'Failed') {\n const classified = classifyRpcError(\n new Error(pollResult.failed_error ?? 'Payment failed'),\n pollResult.failed_error,\n );\n current = applyRetryOrFail(current, classified, policy, {\n failedPatch: {\n result: {\n paymentHash: pollResult.payment_hash,\n status: pollResult.status,\n fee: pollResult.fee,\n failedError: pollResult.failed_error,\n },\n },\n machine: paymentStateMachine,\n retryEvent: 'payment_failed_retryable',\n failEvent: 'payment_failed_permanent',\n });\n yield current;\n continue;\n }\n\n // Still in-flight — wait and poll again\n await sleep(POLL_INTERVAL_MS, signal);\n if (signal.aborted) {\n current = transitionJobState(current, paymentStateMachine, 'cancel');\n yield current;\n return;\n }\n // Stay in 'inflight', loop continues\n current = { ...current, updatedAt: Date.now() };\n continue;\n } catch (err) {\n // Transient RPC error while polling — back off briefly and retry\n const classified = classifyRpcError(err);\n current = applyRetryOrFail(current, classified, policy, {\n machine: paymentStateMachine,\n retryEvent: 'payment_failed_retryable',\n failEvent: 'payment_failed_permanent',\n });\n yield current;\n continue;\n }\n }\n\n // Unknown state — should not happen if state machine is correct\n break;\n }\n}\n\nconst POLL_INTERVAL_MS = 1_500;\n","import type {\n AbandonChannelParams,\n AcceptChannelParams,\n AcceptChannelResult,\n CancelInvoiceParams,\n GetInvoiceResult,\n NewInvoiceParams,\n OpenChannelParams,\n OpenChannelResult,\n SendPaymentParams,\n SettleInvoiceParams,\n ShutdownChannelParams,\n UpdateChannelParams,\n} from '@fiber-pay/sdk';\n\n// ─── Shared Job ──────────────────────────────────────────────────────────────\n\nexport type JobType = 'payment' | 'invoice' | 'channel';\n\nexport type JobState =\n // Shared lifecycle\n | 'queued'\n | 'executing'\n | 'inflight' // payment only\n | 'waiting_retry'\n // Invoice-specific lifecycle\n | 'invoice_created'\n | 'invoice_active'\n | 'invoice_received'\n | 'invoice_settled'\n | 'invoice_expired'\n | 'invoice_cancelled'\n // Channel-specific lifecycle\n | 'channel_opening'\n | 'channel_accepting'\n | 'channel_abandoning'\n | 'channel_updating'\n | 'channel_awaiting_ready'\n | 'channel_ready'\n | 'channel_closing'\n | 'channel_closed'\n | 'succeeded'\n | 'failed'\n | 'cancelled';\n\nexport const TERMINAL_JOB_STATES = new Set<JobState>(['succeeded', 'failed', 'cancelled']);\n\nexport interface Job<TParams = unknown, TResult = unknown, TType extends JobType = JobType> {\n id: string;\n type: TType;\n state: JobState;\n params: TParams;\n result?: TResult;\n error?: ClassifiedError;\n retryCount: number;\n maxRetries: number;\n nextRetryAt?: number;\n /** For deduplication — derived from invoice payment_hash or caller-supplied */\n idempotencyKey: string;\n createdAt: number;\n updatedAt: number;\n completedAt?: number;\n}\n\n// ─── Job Events ───────────────────────────────────────────────────────────────\n\nexport type JobEventType =\n | 'created'\n | 'executing'\n | 'inflight'\n | 'invoice_created'\n | 'invoice_received'\n | 'invoice_settled'\n | 'invoice_expired'\n | 'invoice_cancelled'\n | 'channel_opening'\n | 'channel_accepting'\n | 'channel_abandoning'\n | 'channel_updating'\n | 'channel_awaiting_ready'\n | 'channel_ready'\n | 'channel_closing'\n | 'channel_closed'\n | 'retry_scheduled'\n | 'retrying'\n | 'succeeded'\n | 'failed'\n | 'cancelled';\n\nexport interface JobEvent {\n id: string;\n jobId: string;\n eventType: JobEventType;\n fromState?: JobState;\n toState?: JobState;\n data?: Record<string, unknown>;\n createdAt: number;\n}\n\n// ─── Payment Job ─────────────────────────────────────────────────────────────\n\nexport interface PaymentJobParams {\n /** Raw invoice string (if paying by invoice) */\n invoice?: string;\n /** SDK send_payment params — merged from invoice or supplied directly */\n sendPaymentParams: SendPaymentParams;\n}\n\nexport interface PaymentJobResult {\n paymentHash: string;\n /** Final Fiber payment status: Success | Failed */\n status: string;\n /** Fee in shannon (hex string from Fiber) */\n fee: string;\n failedError?: string;\n}\n\nexport type PaymentJob = Job<PaymentJobParams, PaymentJobResult, 'payment'>;\n\n// ─── Invoice Job ─────────────────────────────────────────────────────────────\n\nexport type InvoiceJobAction = 'create' | 'watch' | 'cancel' | 'settle';\n\nexport interface InvoiceJobParams {\n action: InvoiceJobAction;\n newInvoiceParams?: NewInvoiceParams;\n getInvoicePaymentHash?: `0x${string}`;\n cancelInvoiceParams?: CancelInvoiceParams;\n settleInvoiceParams?: SettleInvoiceParams;\n /** Wait for lifecycle transitions to complete before succeeding */\n waitForTerminal?: boolean;\n /** Poll interval while waiting for invoice state changes */\n pollIntervalMs?: number;\n}\n\nexport interface InvoiceJobResult {\n paymentHash?: `0x${string}`;\n invoiceAddress?: string;\n status?: GetInvoiceResult['status'];\n invoice?: GetInvoiceResult['invoice'];\n}\n\nexport type InvoiceJob = Job<InvoiceJobParams, InvoiceJobResult, 'invoice'>;\n\n// ─── Channel Job ─────────────────────────────────────────────────────────────\n\nexport type ChannelJobAction = 'open' | 'shutdown' | 'accept' | 'abandon' | 'update';\n\nexport interface ChannelJobParams {\n action: ChannelJobAction;\n openChannelParams?: OpenChannelParams;\n shutdownChannelParams?: ShutdownChannelParams;\n acceptChannelParams?: AcceptChannelParams;\n abandonChannelParams?: AbandonChannelParams;\n updateChannelParams?: UpdateChannelParams;\n /** Optional peer filter for locating channel after open */\n peerId?: string;\n /** Optional channel id to wait for */\n channelId?: `0x${string}`;\n waitForReady?: boolean;\n waitForClosed?: boolean;\n pollIntervalMs?: number;\n}\n\nexport interface ChannelJobResult {\n temporaryChannelId?: OpenChannelResult['temporary_channel_id'];\n acceptedChannelId?: AcceptChannelResult['channel_id'];\n channelId?: `0x${string}`;\n state?: string;\n}\n\nexport type ChannelJob = Job<ChannelJobParams, ChannelJobResult, 'channel'>;\n\nexport type RuntimeJob = PaymentJob | InvoiceJob | ChannelJob;\n\n// ─── Error Classification ─────────────────────────────────────────────────────\n\nexport type ErrorCategory =\n | 'no_route'\n | 'insufficient_balance'\n | 'invoice_expired'\n | 'invoice_cancelled'\n | 'peer_offline'\n | 'timeout'\n | 'temporary_failure'\n | 'amount_too_large'\n | 'invalid_payment'\n | 'unknown';\n\nexport interface ClassifiedError {\n category: ErrorCategory;\n retryable: boolean;\n message: string;\n rawError?: string;\n}\n\n// ─── Retry Policy ─────────────────────────────────────────────────────────────\n\nexport interface RetryPolicy {\n maxRetries: number;\n baseDelayMs: number;\n maxDelayMs: number;\n backoffMultiplier: number;\n jitterMs: number;\n}\n\n// ─── Job Filters ──────────────────────────────────────────────────────────────\n\nexport interface JobFilter {\n type?: JobType;\n state?: JobState | JobState[];\n limit?: number;\n offset?: number;\n}\n","import { ChannelState, type FiberRpcClient } from '@fiber-pay/sdk';\nimport type { AlertManager } from '../alerts/alert-manager.js';\nimport type { AlertPriority } from '../alerts/types.js';\nimport { diffChannels } from '../diff/channel-diff.js';\nimport type { Store } from '../storage/types.js';\nimport { BaseMonitor, type BaseMonitorHooks } from './base-monitor.js';\n\nexport interface ChannelMonitorConfig {\n intervalMs: number;\n includeClosedChannels: boolean;\n}\n\nexport class ChannelMonitor extends BaseMonitor {\n protected get name(): string {\n return 'channel-monitor';\n }\n\n private readonly client: FiberRpcClient;\n private readonly store: Store;\n private readonly alerts: AlertManager;\n private readonly config: ChannelMonitorConfig;\n\n constructor(options: {\n client: FiberRpcClient;\n store: Store;\n alerts: AlertManager;\n config: ChannelMonitorConfig;\n hooks?: BaseMonitorHooks;\n }) {\n super(options.config.intervalMs, options.hooks);\n this.client = options.client;\n this.store = options.store;\n this.alerts = options.alerts;\n this.config = options.config;\n }\n\n protected async poll(): Promise<void> {\n const previous = this.store.getChannelSnapshot();\n const result = await this.client.listChannels({\n include_closed: this.config.includeClosedChannels,\n });\n const current = result.channels;\n const changes = diffChannels(previous, current);\n\n for (const change of changes) {\n if (\n change.type === 'channel_new' &&\n change.channel.state.state_name === ChannelState.NegotiatingFunding\n ) {\n await this.alerts.emit({\n type: 'new_inbound_channel_request',\n priority: 'high',\n source: this.name,\n data: { channelId: change.channel.channel_id, channel: change.channel },\n });\n }\n\n if (change.type === 'channel_state_changed') {\n await this.alerts.emit({\n type: 'channel_state_changed',\n priority: getChannelStatePriority(change.currentState),\n source: this.name,\n data: {\n channelId: change.channel.channel_id,\n previousState: change.previousState,\n currentState: change.currentState,\n channel: change.channel,\n },\n });\n }\n\n if (\n change.type === 'channel_state_changed' &&\n change.currentState === ChannelState.ChannelReady\n ) {\n await this.alerts.emit({\n type: 'channel_became_ready',\n priority: 'medium',\n source: this.name,\n data: change,\n });\n }\n\n if (\n change.type === 'channel_state_changed' &&\n (change.currentState === ChannelState.ShuttingDown ||\n change.currentState === ChannelState.Closed)\n ) {\n await this.alerts.emit({\n type: 'channel_closing',\n priority: 'high',\n source: this.name,\n data: change,\n });\n }\n\n if (change.type === 'channel_disappeared') {\n await this.alerts.emit({\n type: 'channel_state_changed',\n priority: 'high',\n source: this.name,\n data: {\n channelId: change.channelId,\n previousState: change.previousChannel.state.state_name,\n currentState: 'DISAPPEARED',\n channel: change.previousChannel,\n },\n });\n await this.alerts.emit({\n type: 'channel_closing',\n priority: 'high',\n source: this.name,\n data: change,\n });\n }\n\n if (change.type === 'channel_balance_changed') {\n await this.alerts.emit({\n type: 'channel_balance_changed',\n priority: 'low',\n source: this.name,\n data: change,\n });\n }\n\n if (change.type === 'channel_pending_tlc_added') {\n await this.alerts.emit({\n type: 'new_pending_tlc',\n priority: 'medium',\n source: this.name,\n data: change,\n });\n }\n }\n\n this.store.setChannelSnapshot(current);\n }\n}\n\nfunction getChannelStatePriority(stateName: string): AlertPriority {\n const normalized = stateName.toUpperCase();\n const closedState = String(ChannelState.Closed).toUpperCase();\n const shuttingDownState = String(ChannelState.ShuttingDown).toUpperCase();\n const readyState = String(ChannelState.ChannelReady).toUpperCase();\n\n if (\n normalized === closedState ||\n normalized === 'CLOSED' ||\n normalized === shuttingDownState ||\n normalized === 'SHUTTING_DOWN'\n ) {\n return 'high';\n }\n\n if (normalized === readyState || normalized === 'CHANNEL_READY') {\n return 'medium';\n }\n\n return 'low';\n}\n","import type { Channel, Htlc } from '@fiber-pay/sdk';\n\nexport type ChannelDiffEvent =\n | { type: 'channel_new'; channel: Channel }\n | { type: 'channel_state_changed'; channel: Channel; previousState: string; currentState: string }\n | {\n type: 'channel_balance_changed';\n channel: Channel;\n localBalanceBefore: string;\n localBalanceAfter: string;\n remoteBalanceBefore: string;\n remoteBalanceAfter: string;\n }\n | {\n type: 'channel_pending_tlc_added';\n channel: Channel;\n previousPendingTlcCount: number;\n newPendingTlcCount: number;\n }\n | { type: 'channel_disappeared'; channelId: string; previousChannel: Channel };\n\nexport function diffChannels(previous: Channel[], current: Channel[]): ChannelDiffEvent[] {\n const events: ChannelDiffEvent[] = [];\n const prevById = new Map(previous.map((channel) => [channel.channel_id, channel]));\n const currById = new Map(current.map((channel) => [channel.channel_id, channel]));\n\n for (const [channelId, channel] of currById.entries()) {\n const previousChannel = prevById.get(channelId);\n if (!previousChannel) {\n events.push({ type: 'channel_new', channel });\n continue;\n }\n\n if (channel.state.state_name !== previousChannel.state.state_name) {\n events.push({\n type: 'channel_state_changed',\n channel,\n previousState: previousChannel.state.state_name,\n currentState: channel.state.state_name,\n });\n }\n\n if (\n channel.local_balance !== previousChannel.local_balance ||\n channel.remote_balance !== previousChannel.remote_balance\n ) {\n events.push({\n type: 'channel_balance_changed',\n channel,\n localBalanceBefore: previousChannel.local_balance,\n localBalanceAfter: channel.local_balance,\n remoteBalanceBefore: previousChannel.remote_balance,\n remoteBalanceAfter: channel.remote_balance,\n });\n }\n\n const previousPending = new Set(previousChannel.pending_tlcs.map((tlc: Htlc) => tlc.id));\n const newTlcCount = channel.pending_tlcs.filter(\n (tlc: Htlc) => !previousPending.has(tlc.id),\n ).length;\n if (newTlcCount > 0) {\n events.push({\n type: 'channel_pending_tlc_added',\n channel,\n previousPendingTlcCount: previousChannel.pending_tlcs.length,\n newPendingTlcCount: channel.pending_tlcs.length,\n });\n }\n }\n\n for (const [channelId, previousChannel] of prevById.entries()) {\n if (!currById.has(channelId)) {\n events.push({\n type: 'channel_disappeared',\n channelId,\n previousChannel,\n });\n }\n }\n\n return events;\n}\n","export interface BaseMonitorHooks {\n onCycleError?: (error: unknown, monitorName: string) => Promise<void> | void;\n onCycleSuccess?: (monitorName: string) => Promise<void> | void;\n}\n\nexport abstract class BaseMonitor {\n protected readonly intervalMs: number;\n private readonly hooks: BaseMonitorHooks;\n private timer: NodeJS.Timeout | undefined;\n private running = false;\n\n constructor(intervalMs: number, hooks: BaseMonitorHooks = {}) {\n this.intervalMs = intervalMs;\n this.hooks = hooks;\n }\n\n protected abstract get name(): string;\n\n protected abstract poll(): Promise<void>;\n\n start(): void {\n this.stop();\n void this.runOnce();\n this.timer = setInterval(() => {\n void this.runOnce();\n }, this.intervalMs);\n }\n\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = undefined;\n }\n }\n\n private async runOnce(): Promise<void> {\n if (this.running) {\n return;\n }\n\n this.running = true;\n try {\n await this.poll();\n await this.hooks.onCycleSuccess?.(this.name);\n } catch (error) {\n await this.hooks.onCycleError?.(error, this.name);\n } finally {\n this.running = false;\n }\n }\n}\n","import type { FiberRpcClient } from '@fiber-pay/sdk';\nimport type { AlertManager } from '../alerts/alert-manager.js';\nimport { BaseMonitor, type BaseMonitorHooks } from './base-monitor.js';\n\nexport interface HealthMonitorConfig {\n intervalMs: number;\n}\n\nexport class HealthMonitor extends BaseMonitor {\n protected get name(): string {\n return 'health-monitor';\n }\n\n private readonly client: FiberRpcClient;\n private readonly alerts: AlertManager;\n private isOffline = false;\n\n constructor(options: {\n client: FiberRpcClient;\n alerts: AlertManager;\n config: HealthMonitorConfig;\n hooks?: BaseMonitorHooks;\n }) {\n super(options.config.intervalMs, options.hooks);\n this.client = options.client;\n this.alerts = options.alerts;\n }\n\n protected async poll(): Promise<void> {\n let isHealthy = false;\n let failureReason: string | undefined;\n try {\n isHealthy = await this.client.ping();\n } catch (error) {\n failureReason = error instanceof Error ? error.message : String(error);\n isHealthy = false;\n }\n\n if (isHealthy && this.isOffline) {\n this.isOffline = false;\n await this.alerts.emit({\n type: 'node_online',\n priority: 'low',\n source: this.name,\n data: { message: 'Fiber node RPC recovered' },\n });\n return;\n }\n\n if (!isHealthy && !this.isOffline) {\n this.isOffline = true;\n await this.alerts.emit({\n type: 'node_offline',\n priority: 'critical',\n source: this.name,\n data: {\n message: failureReason\n ? `Fiber node ping failed: ${failureReason}`\n : 'Fiber node ping returned false',\n },\n });\n }\n }\n}\n","/**\n * Return true when the RPC error indicates the item permanently does not\n * exist on the node (e.g. \"Payment session not found\"). Callers should\n * move the tracked item to a terminal state so it stops being polled.\n */\nexport function isNotFoundError(error: unknown): boolean {\n const message = error instanceof Error ? error.message : String(error);\n return /not found|does not exist|no such/i.test(message);\n}\n\n/**\n * Determine whether an error thrown during invoice/payment tracking is\n * expected and should be silently skipped (transient connectivity blip).\n * Unexpected errors are re-thrown by callers.\n */\nexport function isExpectedTrackerError(error: unknown): boolean {\n const message = error instanceof Error ? error.message : String(error);\n return /temporarily unavailable|connection refused|timed out|timeout/i.test(message);\n}\n","import type { CkbInvoiceStatus, FiberRpcClient } from '@fiber-pay/sdk';\nimport type { AlertManager } from '../alerts/alert-manager.js';\nimport type { Store } from '../storage/types.js';\nimport { BaseMonitor, type BaseMonitorHooks } from './base-monitor.js';\nimport { isExpectedTrackerError, isNotFoundError } from './tracker-utils.js';\n\nexport interface InvoiceTrackerConfig {\n intervalMs: number;\n completedItemTtlSeconds: number;\n}\n\nexport class InvoiceTracker extends BaseMonitor {\n protected get name(): string {\n return 'invoice-tracker';\n }\n\n private readonly client: FiberRpcClient;\n private readonly store: Store;\n private readonly alerts: AlertManager;\n private readonly config: InvoiceTrackerConfig;\n\n constructor(options: {\n client: FiberRpcClient;\n store: Store;\n alerts: AlertManager;\n config: InvoiceTrackerConfig;\n hooks?: BaseMonitorHooks;\n }) {\n super(options.config.intervalMs, options.hooks);\n this.client = options.client;\n this.store = options.store;\n this.alerts = options.alerts;\n this.config = options.config;\n }\n\n protected async poll(): Promise<void> {\n const tracked = this.store.listTrackedInvoices();\n\n for (const invoice of tracked) {\n if (isTerminalInvoiceStatusString(invoice.status)) {\n continue;\n }\n\n try {\n const next = await this.client.getInvoice({ payment_hash: invoice.paymentHash });\n const previousStatus = invoice.status;\n const currentStatus = next.status;\n\n if (currentStatus !== previousStatus) {\n this.store.updateTrackedInvoice(invoice.paymentHash, currentStatus);\n\n if (currentStatus === 'Received' || currentStatus === 'Paid') {\n await this.alerts.emit({\n type: 'incoming_payment_received',\n priority: 'high',\n source: this.name,\n data: {\n paymentHash: invoice.paymentHash,\n previousStatus,\n currentStatus,\n invoice: next,\n },\n });\n }\n\n if (currentStatus === 'Expired') {\n await this.alerts.emit({\n type: 'invoice_expired',\n priority: 'medium',\n source: this.name,\n data: {\n paymentHash: invoice.paymentHash,\n previousStatus,\n currentStatus,\n invoice: next,\n },\n });\n }\n\n if (currentStatus === 'Cancelled') {\n await this.alerts.emit({\n type: 'invoice_cancelled',\n priority: 'medium',\n source: this.name,\n data: {\n paymentHash: invoice.paymentHash,\n previousStatus,\n currentStatus,\n invoice: next,\n },\n });\n }\n }\n } catch (error) {\n if (isNotFoundError(error)) {\n this.store.updateTrackedInvoice(invoice.paymentHash, 'Cancelled');\n await this.alerts.emit({\n type: 'invoice_cancelled',\n priority: 'medium',\n source: this.name,\n data: {\n paymentHash: invoice.paymentHash,\n previousStatus: invoice.status,\n currentStatus: 'Cancelled',\n reason: 'not_found',\n },\n });\n continue;\n }\n if (isExpectedTrackerError(error)) {\n continue;\n }\n throw error;\n }\n }\n\n this.store.pruneCompleted(this.config.completedItemTtlSeconds * 1000);\n }\n}\n\nexport function isTerminalInvoiceStatus(status: CkbInvoiceStatus): boolean {\n return status === 'Cancelled' || status === 'Expired' || status === 'Paid';\n}\n\nfunction isTerminalInvoiceStatusString(status: string): boolean {\n return status === 'Cancelled' || status === 'Expired' || status === 'Paid';\n}\n","import type { FiberRpcClient } from '@fiber-pay/sdk';\nimport type { AlertManager } from '../alerts/alert-manager.js';\nimport type { Store } from '../storage/types.js';\nimport { BaseMonitor, type BaseMonitorHooks } from './base-monitor.js';\nimport { isExpectedTrackerError, isNotFoundError } from './tracker-utils.js';\n\nexport interface PaymentTrackerConfig {\n intervalMs: number;\n completedItemTtlSeconds: number;\n}\n\nexport class PaymentTracker extends BaseMonitor {\n protected get name(): string {\n return 'payment-tracker';\n }\n\n private readonly client: FiberRpcClient;\n private readonly store: Store;\n private readonly alerts: AlertManager;\n private readonly config: PaymentTrackerConfig;\n\n constructor(options: {\n client: FiberRpcClient;\n store: Store;\n alerts: AlertManager;\n config: PaymentTrackerConfig;\n hooks?: BaseMonitorHooks;\n }) {\n super(options.config.intervalMs, options.hooks);\n this.client = options.client;\n this.store = options.store;\n this.alerts = options.alerts;\n this.config = options.config;\n }\n\n protected async poll(): Promise<void> {\n const tracked = this.store.listTrackedPayments();\n\n for (const payment of tracked) {\n if (isTerminalPaymentStatus(payment.status)) {\n continue;\n }\n\n try {\n const next = await this.client.getPayment({ payment_hash: payment.paymentHash });\n const previousStatus = payment.status;\n const currentStatus = next.status;\n\n if (currentStatus !== previousStatus) {\n this.store.updateTrackedPayment(payment.paymentHash, currentStatus);\n\n if (currentStatus === 'Success') {\n await this.alerts.emit({\n type: 'outgoing_payment_completed',\n priority: 'medium',\n source: this.name,\n data: {\n paymentHash: payment.paymentHash,\n previousStatus,\n currentStatus,\n payment: next,\n },\n });\n }\n\n if (currentStatus === 'Failed') {\n await this.alerts.emit({\n type: 'outgoing_payment_failed',\n priority: 'high',\n source: this.name,\n data: {\n paymentHash: payment.paymentHash,\n previousStatus,\n currentStatus,\n payment: next,\n },\n });\n }\n }\n } catch (error) {\n if (isNotFoundError(error)) {\n this.store.updateTrackedPayment(payment.paymentHash, 'Failed');\n await this.alerts.emit({\n type: 'outgoing_payment_failed',\n priority: 'high',\n source: this.name,\n data: {\n paymentHash: payment.paymentHash,\n previousStatus: payment.status,\n currentStatus: 'Failed',\n reason: 'not_found',\n },\n });\n continue;\n }\n if (isExpectedTrackerError(error)) {\n continue;\n }\n throw error;\n }\n }\n\n this.store.pruneCompleted(this.config.completedItemTtlSeconds * 1000);\n }\n}\n\nfunction isTerminalPaymentStatus(status: string): boolean {\n return status === 'Success' || status === 'Failed';\n}\n","import type { PeerInfo } from '@fiber-pay/sdk';\n\nexport type PeerDiffEvent =\n | { type: 'peer_connected'; peer: PeerInfo }\n | { type: 'peer_disconnected'; peer: PeerInfo };\n\nexport function diffPeers(previous: PeerInfo[], current: PeerInfo[]): PeerDiffEvent[] {\n const events: PeerDiffEvent[] = [];\n const prevById = new Map(previous.map((peer) => [peer.peer_id, peer]));\n const currById = new Map(current.map((peer) => [peer.peer_id, peer]));\n\n for (const [peerId, peer] of currById.entries()) {\n if (!prevById.has(peerId)) {\n events.push({ type: 'peer_connected', peer });\n }\n }\n\n for (const [peerId, peer] of prevById.entries()) {\n if (!currById.has(peerId)) {\n events.push({ type: 'peer_disconnected', peer });\n }\n }\n\n return events;\n}\n","import type { FiberRpcClient } from '@fiber-pay/sdk';\nimport type { AlertManager } from '../alerts/alert-manager.js';\nimport { diffPeers } from '../diff/peer-diff.js';\nimport type { Store } from '../storage/types.js';\nimport { BaseMonitor, type BaseMonitorHooks } from './base-monitor.js';\n\nexport interface PeerMonitorConfig {\n intervalMs: number;\n}\n\nexport class PeerMonitor extends BaseMonitor {\n protected get name(): string {\n return 'peer-monitor';\n }\n\n private readonly client: FiberRpcClient;\n private readonly store: Store;\n private readonly alerts: AlertManager;\n\n constructor(options: {\n client: FiberRpcClient;\n store: Store;\n alerts: AlertManager;\n config: PeerMonitorConfig;\n hooks?: BaseMonitorHooks;\n }) {\n super(options.config.intervalMs, options.hooks);\n this.client = options.client;\n this.store = options.store;\n this.alerts = options.alerts;\n }\n\n protected async poll(): Promise<void> {\n const previous = this.store.getPeerSnapshot();\n const result = await this.client.listPeers();\n const current = result.peers;\n\n const changes = diffPeers(previous, current);\n for (const change of changes) {\n if (change.type === 'peer_connected') {\n await this.alerts.emit({\n type: 'peer_connected',\n priority: 'low',\n source: this.name,\n data: { peer: change.peer },\n });\n }\n if (change.type === 'peer_disconnected') {\n await this.alerts.emit({\n type: 'peer_disconnected',\n priority: 'low',\n source: this.name,\n data: { peer: change.peer },\n });\n }\n }\n\n this.store.setPeerSnapshot(current);\n }\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport http from 'node:http';\nimport { parseListenAddress } from '../config.js';\nimport { isPayloadTooLargeError, readRawBody } from './body.js';\nimport { CORS_HEADERS, CORS_PREFLIGHT_HEADERS, writeJson } from './http-utils.js';\nimport { handleDeleteEndpoint, handleJobPostEndpoint } from './job-routes.js';\nimport { tryParseJson } from './json.js';\nimport { captureTrackedHashes, collectJsonRpcMethods } from './jsonrpc-tracking.js';\nimport { handleMonitorEndpoint } from './monitor-routes.js';\nimport type { RpcMonitorProxyConfig, RpcMonitorProxyDeps } from './types.js';\n\nexport type { RpcMonitorProxyConfig, RpcMonitorProxyDeps, RpcMonitorProxyStatus } from './types.js';\n\nexport class RpcMonitorProxy {\n private readonly config: RpcMonitorProxyConfig;\n private readonly deps: RpcMonitorProxyDeps;\n private server: http.Server | undefined;\n\n constructor(config: RpcMonitorProxyConfig, deps: RpcMonitorProxyDeps) {\n this.config = config;\n this.deps = deps;\n }\n\n async start(): Promise<void> {\n if (this.server) {\n return;\n }\n\n assertNoProxySelfLoop(this.config.listen, this.config.targetUrl);\n\n this.server = http.createServer((req, res) => {\n void this.handleRequest(req, res);\n });\n\n const { host, port } = parseListenAddress(this.config.listen);\n\n await new Promise<void>((resolve, reject) => {\n this.server?.once('error', reject);\n this.server?.listen(port, host, () => {\n this.server?.off('error', reject);\n resolve();\n });\n });\n }\n\n async stop(): Promise<void> {\n if (!this.server) {\n return;\n }\n\n const server = this.server;\n this.server = undefined;\n\n await new Promise<void>((resolve) => {\n server.close(() => resolve());\n });\n }\n\n private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n if (req.method === 'OPTIONS') {\n res.writeHead(204, CORS_PREFLIGHT_HEADERS);\n res.end();\n return;\n }\n\n if (req.method === 'GET') {\n handleMonitorEndpoint(req, res, this.deps);\n return;\n }\n\n if (req.method === 'DELETE') {\n await handleDeleteEndpoint(req, res, this.deps);\n return;\n }\n\n if (req.method !== 'POST') {\n writeJson(res, 405, { error: 'Method not allowed' });\n return;\n }\n\n const url = new URL(req.url ?? '/', 'http://127.0.0.1');\n if (url.pathname.startsWith('/jobs/')) {\n await handleJobPostEndpoint(url.pathname, req, res, this.deps);\n return;\n }\n\n let requestBody: Buffer;\n try {\n requestBody = await readRawBody(req);\n } catch (error) {\n if (isPayloadTooLargeError(error)) {\n writeJson(res, 413, { error: 'Request body too large' });\n return;\n }\n writeJson(res, 400, { error: 'Failed to read request body' });\n return;\n }\n\n const requestJson = tryParseJson(requestBody.toString('utf-8'));\n const methodById = collectJsonRpcMethods(requestJson);\n\n let responseText = '';\n let responseStatus = 500;\n let responseHeaders = new Headers();\n\n try {\n const response = await fetch(this.config.targetUrl, {\n method: 'POST',\n headers: {\n 'content-type': req.headers['content-type'] ?? 'application/json',\n ...(req.headers.authorization ? { authorization: req.headers.authorization } : {}),\n },\n body: requestBody,\n });\n\n responseStatus = response.status;\n responseHeaders = response.headers;\n responseText = await response.text();\n\n const responseJson = tryParseJson(responseText);\n captureTrackedHashes(methodById, responseJson, {\n onInvoiceTracked: this.deps.onInvoiceTracked,\n onPaymentTracked: this.deps.onPaymentTracked,\n });\n } catch (error) {\n writeJson(res, 502, { error: `Proxy request failed: ${String(error)}` });\n return;\n }\n\n const contentType = responseHeaders.get('content-type') ?? 'application/json';\n res.writeHead(responseStatus, {\n 'content-type': contentType,\n ...CORS_HEADERS,\n });\n res.end(responseText);\n }\n}\n\nfunction assertNoProxySelfLoop(listen: string, targetUrl: string): void {\n const { host, port } = parseListenAddress(listen);\n\n let parsed: URL;\n try {\n parsed = new URL(targetUrl);\n } catch {\n throw new Error(`Invalid proxy targetUrl: ${targetUrl}`);\n }\n\n const targetHost = normalizeHost(parsed.hostname);\n const listenHost = normalizeHost(host);\n const targetPort = parsed.port || (parsed.protocol === 'https:' ? '443' : '80');\n\n if (targetHost === listenHost && targetPort === String(port)) {\n throw new Error(\n `Invalid proxy configuration: targetUrl (${targetUrl}) points to proxy listen address (${listen})`,\n );\n }\n}\n\nfunction normalizeHost(host: string): string {\n if (host === 'localhost' || host === '::1') {\n return '127.0.0.1';\n }\n return host;\n}\n","import type { IncomingMessage } from 'node:http';\n\nconst MAX_REQUEST_BODY_BYTES = 1024 * 1024;\n\nexport async function readRawBody(req: IncomingMessage): Promise<Buffer> {\n const chunks: Buffer[] = [];\n let totalBytes = 0;\n\n return await new Promise<Buffer>((resolve, reject) => {\n req.on('data', (chunk: Buffer) => {\n totalBytes += chunk.length;\n if (totalBytes > MAX_REQUEST_BODY_BYTES) {\n req.destroy();\n reject(new PayloadTooLargeError());\n return;\n }\n chunks.push(chunk);\n });\n req.on('end', () => resolve(Buffer.concat(chunks)));\n req.on('error', reject);\n });\n}\n\nclass PayloadTooLargeError extends Error {\n constructor() {\n super('Payload too large');\n this.name = 'PayloadTooLargeError';\n }\n}\n\nexport function isPayloadTooLargeError(error: unknown): boolean {\n return error instanceof PayloadTooLargeError;\n}\n","import type { ServerResponse } from 'node:http';\n\nexport const CORS_HEADERS = {\n 'access-control-allow-origin': '*',\n 'access-control-allow-methods': 'GET,POST,DELETE,OPTIONS',\n 'access-control-allow-headers': 'Content-Type, Authorization',\n};\n\nexport const CORS_PREFLIGHT_HEADERS = {\n ...CORS_HEADERS,\n 'access-control-max-age': '86400',\n};\n\nexport function writeJson(res: ServerResponse, status: number, value: unknown): void {\n res.writeHead(status, {\n 'content-type': 'application/json',\n ...CORS_HEADERS,\n });\n res.end(JSON.stringify(value));\n}\n\nexport function parseOptionalPositiveInteger(value: string | null): number | undefined {\n if (!value) {\n return undefined;\n }\n\n const parsed = Number(value);\n if (!Number.isInteger(parsed) || parsed <= 0) {\n return undefined;\n }\n\n return parsed;\n}\n","export function tryParseJson(text: string): unknown {\n try {\n return JSON.parse(text);\n } catch {\n return undefined;\n }\n}\n\nexport function isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { ChannelJobParams, InvoiceJobParams, PaymentJobParams } from '../jobs/types.js';\nimport { isPayloadTooLargeError, readRawBody } from './body.js';\nimport { writeJson } from './http-utils.js';\nimport { isObject, tryParseJson } from './json.js';\nimport type { RpcMonitorProxyDeps } from './types.js';\n\nexport async function handleJobPostEndpoint(\n pathname: string,\n req: IncomingMessage,\n res: ServerResponse,\n deps: RpcMonitorProxyDeps,\n): Promise<void> {\n let rawBody: Buffer;\n try {\n rawBody = await readRawBody(req);\n } catch (error) {\n if (isPayloadTooLargeError(error)) {\n writeJson(res, 413, { error: 'Request body too large' });\n return;\n }\n writeJson(res, 400, { error: 'Failed to read request body' });\n return;\n }\n\n const body = tryParseJson(rawBody.toString('utf-8'));\n if (!isObject(body)) {\n writeJson(res, 400, { error: 'Invalid JSON body' });\n return;\n }\n\n if (pathname === '/jobs/payment') {\n if (!deps.createPaymentJob) {\n writeJson(res, 404, { error: 'Jobs are not enabled in runtime config' });\n return;\n }\n const params = body.params as PaymentJobParams | undefined;\n if (!params) {\n writeJson(res, 400, { error: 'Missing params for payment job' });\n return;\n }\n const options = body.options as { idempotencyKey?: string; maxRetries?: number } | undefined;\n const job = await deps.createPaymentJob(params, options);\n writeJson(res, 200, job);\n return;\n }\n\n if (pathname === '/jobs/invoice') {\n if (!deps.createInvoiceJob) {\n writeJson(res, 404, { error: 'Jobs are not enabled in runtime config' });\n return;\n }\n const params = body.params as InvoiceJobParams | undefined;\n if (!params) {\n writeJson(res, 400, { error: 'Missing params for invoice job' });\n return;\n }\n const options = body.options as { idempotencyKey?: string; maxRetries?: number } | undefined;\n const job = await deps.createInvoiceJob(params, options);\n writeJson(res, 200, job);\n return;\n }\n\n if (pathname === '/jobs/channel') {\n if (!deps.createChannelJob) {\n writeJson(res, 404, { error: 'Jobs are not enabled in runtime config' });\n return;\n }\n const params = body.params as ChannelJobParams | undefined;\n if (!params) {\n writeJson(res, 400, { error: 'Missing params for channel job' });\n return;\n }\n const options = body.options as\n | { idempotencyKey?: string; maxRetries?: number; reuseTerminal?: boolean }\n | undefined;\n const job = await deps.createChannelJob(params, options);\n writeJson(res, 200, job);\n return;\n }\n\n writeJson(res, 404, { error: 'Unknown jobs endpoint' });\n}\n\nexport async function handleDeleteEndpoint(\n req: IncomingMessage,\n res: ServerResponse,\n deps: RpcMonitorProxyDeps,\n): Promise<void> {\n const url = new URL(req.url ?? '/', 'http://127.0.0.1');\n if (!url.pathname.startsWith('/jobs/')) {\n writeJson(res, 405, { error: 'Method not allowed' });\n return;\n }\n if (!deps.cancelJob) {\n writeJson(res, 404, { error: 'Jobs are not enabled in runtime config' });\n return;\n }\n\n const segments = url.pathname.split('/').filter(Boolean);\n const [, id] = segments;\n if (!id) {\n writeJson(res, 400, { error: 'Missing job id' });\n return;\n }\n\n try {\n deps.cancelJob(id);\n writeJson(res, 204, {});\n } catch (error) {\n writeJson(res, 404, { error: String(error) });\n }\n}\n","import { isObject } from './json.js';\n\ninterface JsonRpcMessage {\n id?: string | number;\n method?: string;\n params?: unknown[];\n result?: unknown;\n error?: unknown;\n}\n\nexport interface RequestMeta {\n method: string;\n dryRun: boolean;\n}\n\nexport function collectJsonRpcMethods(requestBody: unknown): Map<string | number, RequestMeta> {\n const methods = new Map<string | number, RequestMeta>();\n for (const item of normalizeJsonRpcRequest(requestBody)) {\n if (item.id !== undefined && typeof item.method === 'string') {\n const dryRun = isDryRunRequest(item);\n methods.set(item.id, { method: item.method, dryRun });\n }\n }\n return methods;\n}\n\nexport function captureTrackedHashes(\n methodById: Map<string | number, RequestMeta>,\n responseBody: unknown,\n handlers: {\n onInvoiceTracked: (paymentHash: string) => void;\n onPaymentTracked: (paymentHash: string) => void;\n },\n): void {\n const responses = normalizeJsonRpcResponse(responseBody);\n\n for (const message of responses) {\n if (message.error || message.id === undefined) {\n continue;\n }\n const meta = methodById.get(message.id);\n if (!meta) {\n continue;\n }\n\n if (meta.method === 'new_invoice') {\n const paymentHash = extractInvoicePaymentHash(message.result);\n if (paymentHash) {\n handlers.onInvoiceTracked(paymentHash);\n }\n }\n\n // Skip tracking dry-run payments — the node never persists them,\n // so the tracker would poll getPayment forever.\n if (meta.method === 'send_payment' && !meta.dryRun) {\n const paymentHash = extractPaymentHash(message.result);\n if (paymentHash) {\n handlers.onPaymentTracked(paymentHash);\n }\n }\n }\n}\n\nfunction normalizeJsonRpcRequest(body: unknown): JsonRpcMessage[] {\n if (!body) {\n return [];\n }\n if (Array.isArray(body)) {\n return body.filter(isObject) as JsonRpcMessage[];\n }\n if (isObject(body)) {\n return [body as JsonRpcMessage];\n }\n return [];\n}\n\nfunction normalizeJsonRpcResponse(body: unknown): JsonRpcMessage[] {\n if (!body) {\n return [];\n }\n if (Array.isArray(body)) {\n return body.filter(isObject) as JsonRpcMessage[];\n }\n if (isObject(body)) {\n return [body as JsonRpcMessage];\n }\n return [];\n}\n\nfunction extractInvoicePaymentHash(result: unknown): string | undefined {\n if (!isObject(result)) {\n return undefined;\n }\n\n const invoice = result.invoice;\n if (!isObject(invoice)) {\n return undefined;\n }\n\n const data = invoice.data;\n if (!isObject(data)) {\n return undefined;\n }\n\n return typeof data.payment_hash === 'string' ? data.payment_hash : undefined;\n}\n\nfunction extractPaymentHash(result: unknown): string | undefined {\n if (!isObject(result)) {\n return undefined;\n }\n return typeof result.payment_hash === 'string' ? result.payment_hash : undefined;\n}\n\nfunction isDryRunRequest(message: JsonRpcMessage): boolean {\n if (!Array.isArray(message.params) || message.params.length === 0) {\n return false;\n }\n const firstParam = message.params[0];\n return isObject(firstParam) && firstParam.dry_run === true;\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport { isAlertPriority, isAlertType } from '../alerts/types.js';\nimport type { JobFilter } from '../jobs/types.js';\nimport { parseOptionalPositiveInteger, writeJson } from './http-utils.js';\nimport type { RpcMonitorProxyDeps } from './types.js';\n\nexport function handleMonitorEndpoint(\n req: IncomingMessage,\n res: ServerResponse,\n deps: RpcMonitorProxyDeps,\n): void {\n const url = new URL(req.url ?? '/', 'http://127.0.0.1');\n\n if (url.pathname === '/jobs') {\n if (!deps.listJobs) {\n writeJson(res, 404, { error: 'Jobs are not enabled in runtime config' });\n return;\n }\n const state = url.searchParams.get('state') ?? undefined;\n const type = url.searchParams.get('type') as JobFilter['type'] | null;\n const limit = parseOptionalPositiveInteger(url.searchParams.get('limit'));\n const offset = parseOptionalPositiveInteger(url.searchParams.get('offset'));\n writeJson(res, 200, {\n jobs: deps.listJobs({\n state: state as JobFilter['state'],\n type: type ?? undefined,\n limit,\n offset,\n }),\n });\n return;\n }\n\n if (url.pathname.startsWith('/jobs/')) {\n if (!deps.getJob) {\n writeJson(res, 404, { error: 'Jobs are not enabled in runtime config' });\n return;\n }\n\n const segments = url.pathname.split('/').filter(Boolean);\n const [, id, sub] = segments;\n if (!id) {\n writeJson(res, 400, { error: 'Missing job id' });\n return;\n }\n\n if (sub === 'events') {\n if (!deps.listJobEvents) {\n writeJson(res, 404, { error: 'Job events not available' });\n return;\n }\n writeJson(res, 200, { events: deps.listJobEvents(id) });\n return;\n }\n\n const job = deps.getJob(id);\n if (!job) {\n writeJson(res, 404, { error: 'Job not found' });\n return;\n }\n writeJson(res, 200, job);\n return;\n }\n\n if (url.pathname === '/monitor/list_tracked_invoices') {\n writeJson(res, 200, { invoices: deps.listTrackedInvoices() });\n return;\n }\n\n if (url.pathname === '/monitor/list_tracked_payments') {\n writeJson(res, 200, { payments: deps.listTrackedPayments() });\n return;\n }\n\n if (url.pathname === '/monitor/list_alerts') {\n const limitRaw = url.searchParams.get('limit');\n const minPriorityRaw = url.searchParams.get('min_priority');\n const typeRaw = url.searchParams.get('type');\n const sourceRaw = url.searchParams.get('source');\n\n const limit = parseOptionalPositiveInteger(limitRaw);\n if (limitRaw !== null && limit === undefined) {\n writeJson(res, 400, {\n error: 'Invalid query parameter: limit must be a positive integer',\n });\n return;\n }\n\n if (minPriorityRaw && !isAlertPriority(minPriorityRaw)) {\n writeJson(res, 400, {\n error: 'Invalid query parameter: min_priority must be one of critical|high|medium|low',\n });\n return;\n }\n\n if (typeRaw && !isAlertType(typeRaw)) {\n writeJson(res, 400, {\n error: 'Invalid query parameter: type is not a known alert type',\n });\n return;\n }\n\n const minPriority =\n minPriorityRaw && isAlertPriority(minPriorityRaw) ? minPriorityRaw : undefined;\n const type = typeRaw && isAlertType(typeRaw) ? typeRaw : undefined;\n\n writeJson(res, 200, {\n alerts: deps.listAlerts({\n limit,\n minPriority,\n type,\n source: sourceRaw ?? undefined,\n }),\n });\n return;\n }\n\n if (url.pathname === '/monitor/status') {\n writeJson(res, 200, deps.getStatus());\n return;\n }\n\n writeJson(res, 404, { error: 'Not found' });\n}\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport type { Channel, PaymentHash, PeerInfo } from '@fiber-pay/sdk';\nimport {\n type Alert,\n type AlertFilter,\n alertPriorityOrder,\n type TrackedInvoiceState,\n type TrackedPaymentState,\n} from '../alerts/types.js';\nimport type { PersistedRuntimeState, Store } from './types.js';\n\nexport interface MemoryStoreConfig {\n stateFilePath: string;\n flushIntervalMs: number;\n maxAlertHistory: number;\n}\n\nfunction nowMs(): number {\n return Date.now();\n}\n\nfunction toRecord<T extends { paymentHash: PaymentHash }>(\n items: Map<PaymentHash, T>,\n): Record<PaymentHash, T> {\n return Object.fromEntries(items.entries()) as Record<PaymentHash, T>;\n}\n\nexport class MemoryStore implements Store {\n private readonly config: MemoryStoreConfig;\n private channelSnapshot: Channel[] = [];\n private peerSnapshot: PeerInfo[] = [];\n private trackedInvoices = new Map<PaymentHash, TrackedInvoiceState>();\n private trackedPayments = new Map<PaymentHash, TrackedPaymentState>();\n private alerts: Alert[] = [];\n private flushTimer: NodeJS.Timeout | undefined;\n\n constructor(config: MemoryStoreConfig) {\n this.config = config;\n }\n\n async load(): Promise<void> {\n try {\n const raw = await readFile(this.config.stateFilePath, 'utf-8');\n const state = JSON.parse(raw) as PersistedRuntimeState;\n this.channelSnapshot = state.channels ?? [];\n this.peerSnapshot = state.peers ?? [];\n this.trackedInvoices = new Map(Object.entries(state.trackedInvoices ?? {})) as Map<\n PaymentHash,\n TrackedInvoiceState\n >;\n this.trackedPayments = new Map(Object.entries(state.trackedPayments ?? {})) as Map<\n PaymentHash,\n TrackedPaymentState\n >;\n this.alerts = state.alerts ?? [];\n } catch {\n this.channelSnapshot = [];\n this.peerSnapshot = [];\n this.trackedInvoices.clear();\n this.trackedPayments.clear();\n this.alerts = [];\n }\n }\n\n async flush(): Promise<void> {\n const state: PersistedRuntimeState = {\n channels: this.channelSnapshot,\n peers: this.peerSnapshot,\n trackedInvoices: toRecord(this.trackedInvoices),\n trackedPayments: toRecord(this.trackedPayments),\n alerts: this.alerts,\n };\n await mkdir(dirname(this.config.stateFilePath), { recursive: true });\n await writeFile(this.config.stateFilePath, JSON.stringify(state, null, 2), 'utf-8');\n }\n\n startAutoFlush(): void {\n this.stopAutoFlush();\n this.flushTimer = setInterval(() => {\n void this.flush();\n }, this.config.flushIntervalMs);\n }\n\n stopAutoFlush(): void {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n this.flushTimer = undefined;\n }\n }\n\n pruneCompleted(ttlMs: number): void {\n const now = nowMs();\n for (const [hash, entry] of this.trackedInvoices.entries()) {\n if (entry.completedAt && now - entry.completedAt >= ttlMs) {\n this.trackedInvoices.delete(hash);\n }\n }\n for (const [hash, entry] of this.trackedPayments.entries()) {\n if (entry.completedAt && now - entry.completedAt >= ttlMs) {\n this.trackedPayments.delete(hash);\n }\n }\n }\n\n getChannelSnapshot(): Channel[] {\n return this.channelSnapshot;\n }\n\n setChannelSnapshot(channels: Channel[]): void {\n this.channelSnapshot = channels;\n }\n\n getPeerSnapshot(): PeerInfo[] {\n return this.peerSnapshot;\n }\n\n setPeerSnapshot(peers: PeerInfo[]): void {\n this.peerSnapshot = peers;\n }\n\n addTrackedInvoice(hash: PaymentHash, status = 'Open'): void {\n const existing = this.trackedInvoices.get(hash);\n if (existing) return;\n const now = nowMs();\n this.trackedInvoices.set(hash, {\n paymentHash: hash,\n status,\n trackedAt: now,\n updatedAt: now,\n });\n }\n\n listTrackedInvoices(): TrackedInvoiceState[] {\n return [...this.trackedInvoices.values()];\n }\n\n getTrackedInvoice(hash: PaymentHash): TrackedInvoiceState | undefined {\n return this.trackedInvoices.get(hash);\n }\n\n updateTrackedInvoice(hash: PaymentHash, status: string): void {\n const now = nowMs();\n const existing = this.trackedInvoices.get(hash);\n const next: TrackedInvoiceState = existing\n ? {\n ...existing,\n status,\n updatedAt: now,\n completedAt: isTerminalInvoiceStatus(status) ? (existing.completedAt ?? now) : undefined,\n }\n : {\n paymentHash: hash,\n status,\n trackedAt: now,\n updatedAt: now,\n completedAt: isTerminalInvoiceStatus(status) ? now : undefined,\n };\n this.trackedInvoices.set(hash, next);\n }\n\n addTrackedPayment(hash: PaymentHash, status = 'Created'): void {\n const existing = this.trackedPayments.get(hash);\n if (existing) return;\n const now = nowMs();\n this.trackedPayments.set(hash, {\n paymentHash: hash,\n status,\n trackedAt: now,\n updatedAt: now,\n });\n }\n\n listTrackedPayments(): TrackedPaymentState[] {\n return [...this.trackedPayments.values()];\n }\n\n getTrackedPayment(hash: PaymentHash): TrackedPaymentState | undefined {\n return this.trackedPayments.get(hash);\n }\n\n updateTrackedPayment(hash: PaymentHash, status: string): void {\n const now = nowMs();\n const existing = this.trackedPayments.get(hash);\n const next: TrackedPaymentState = existing\n ? {\n ...existing,\n status,\n updatedAt: now,\n completedAt: isTerminalPaymentStatus(status) ? (existing.completedAt ?? now) : undefined,\n }\n : {\n paymentHash: hash,\n status,\n trackedAt: now,\n updatedAt: now,\n completedAt: isTerminalPaymentStatus(status) ? now : undefined,\n };\n this.trackedPayments.set(hash, next);\n }\n\n addAlert(alert: Alert): void {\n this.alerts.push(alert);\n if (this.alerts.length > this.config.maxAlertHistory) {\n this.alerts.splice(0, this.alerts.length - this.config.maxAlertHistory);\n }\n }\n\n listAlerts(filters?: AlertFilter): Alert[] {\n const minPriority = filters?.minPriority;\n const type = filters?.type;\n const source = filters?.source;\n const limit = filters?.limit;\n\n let alerts = this.alerts;\n\n if (minPriority) {\n const minRank = alertPriorityOrder[minPriority];\n alerts = alerts.filter((alert) => alertPriorityOrder[alert.priority] >= minRank);\n }\n\n if (type) {\n alerts = alerts.filter((alert) => alert.type === type);\n }\n\n if (source) {\n alerts = alerts.filter((alert) => alert.source === source);\n }\n\n if (!limit || limit <= 0) {\n return [...alerts];\n }\n\n return alerts.slice(-limit);\n }\n}\n\nfunction isTerminalInvoiceStatus(status: string): boolean {\n return status === 'Paid' || status === 'Cancelled' || status === 'Expired';\n}\n\nfunction isTerminalPaymentStatus(status: string): boolean {\n return status === 'Success' || status === 'Failed';\n}\n","import { randomUUID } from 'node:crypto';\nimport { mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport Database from 'better-sqlite3';\nimport type { Job, JobEvent, JobEventType, JobFilter, JobState, JobType } from '../jobs/types.js';\n\n// ─── Migrations ───────────────────────────────────────────────────────────────\n\nconst MIGRATIONS: Array<{ version: number; sql: string }> = [\n {\n version: 1,\n sql: `\n CREATE TABLE IF NOT EXISTS jobs (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL,\n state TEXT NOT NULL,\n params TEXT NOT NULL,\n result TEXT,\n error TEXT,\n retry_count INTEGER NOT NULL DEFAULT 0,\n max_retries INTEGER NOT NULL DEFAULT 3,\n next_retry_at INTEGER,\n idempotency_key TEXT NOT NULL UNIQUE,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n completed_at INTEGER\n );\n\n CREATE INDEX IF NOT EXISTS idx_jobs_state ON jobs(state);\n CREATE INDEX IF NOT EXISTS idx_jobs_type ON jobs(type);\n CREATE INDEX IF NOT EXISTS idx_jobs_next_retry_at ON jobs(next_retry_at);\n\n CREATE TABLE IF NOT EXISTS job_events (\n id TEXT PRIMARY KEY,\n job_id TEXT NOT NULL REFERENCES jobs(id) ON DELETE CASCADE,\n event_type TEXT NOT NULL,\n from_state TEXT,\n to_state TEXT,\n data TEXT,\n created_at INTEGER NOT NULL\n );\n\n CREATE INDEX IF NOT EXISTS idx_job_events_job_id ON job_events(job_id);\n `,\n },\n];\n\n// ─── SqliteJobStore ───────────────────────────────────────────────────────────\n\nexport class SqliteJobStore {\n private readonly db: Database.Database;\n\n constructor(dbPath: string) {\n mkdirSync(dirname(dbPath), { recursive: true });\n this.db = new Database(dbPath);\n this.db.pragma('journal_mode = WAL');\n this.db.pragma('foreign_keys = ON');\n this.runMigrations();\n }\n\n // ─── Migrations ─────────────────────────────────────────────────────────────\n\n private runMigrations(): void {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS schema_migrations (\n version INTEGER PRIMARY KEY,\n applied_at INTEGER NOT NULL\n );\n `);\n\n const applied = new Set<number>(\n (this.db.prepare('SELECT version FROM schema_migrations').all() as { version: number }[]).map(\n (r) => r.version,\n ),\n );\n\n for (const migration of MIGRATIONS) {\n if (!applied.has(migration.version)) {\n this.db.transaction(() => {\n this.db.exec(migration.sql);\n this.db\n .prepare('INSERT INTO schema_migrations (version, applied_at) VALUES (?, ?)')\n .run(migration.version, Date.now());\n })();\n }\n }\n }\n\n // ─── Job CRUD ────────────────────────────────────────────────────────────────\n\n createJob<P, R>(job: Omit<Job<P, R>, 'id' | 'createdAt' | 'updatedAt'>): Job<P, R> {\n const now = Date.now();\n const full: Job<P, R> = {\n ...job,\n id: randomUUID(),\n createdAt: now,\n updatedAt: now,\n };\n\n this.db\n .prepare(\n `INSERT INTO jobs\n (id, type, state, params, result, error, retry_count, max_retries,\n next_retry_at, idempotency_key, created_at, updated_at, completed_at)\n VALUES\n (@id, @type, @state, @params, @result, @error, @retry_count, @max_retries,\n @next_retry_at, @idempotency_key, @created_at, @updated_at, @completed_at)`,\n )\n .run({\n id: full.id,\n type: full.type,\n state: full.state,\n params: JSON.stringify(full.params),\n result: full.result !== undefined ? JSON.stringify(full.result) : null,\n error: full.error !== undefined ? JSON.stringify(full.error) : null,\n retry_count: full.retryCount,\n max_retries: full.maxRetries,\n next_retry_at: full.nextRetryAt ?? null,\n idempotency_key: full.idempotencyKey,\n created_at: full.createdAt,\n updated_at: full.updatedAt,\n completed_at: full.completedAt ?? null,\n });\n\n return full;\n }\n\n updateJob<P, R>(id: string, updates: Partial<Job<P, R>>): Job<P, R> {\n const existing = this.getJob<P, R>(id);\n if (!existing) throw new Error(`Job not found: ${id}`);\n\n const now = Date.now();\n const merged: Job<P, R> = { ...existing, ...updates, updatedAt: now };\n\n this.db\n .prepare(\n `UPDATE jobs SET\n state = @state,\n params = @params,\n result = @result,\n error = @error,\n retry_count = @retry_count,\n next_retry_at = @next_retry_at,\n updated_at = @updated_at,\n completed_at = @completed_at\n WHERE id = @id`,\n )\n .run({\n id: merged.id,\n state: merged.state,\n params: JSON.stringify(merged.params),\n result: merged.result !== undefined ? JSON.stringify(merged.result) : null,\n error: merged.error !== undefined ? JSON.stringify(merged.error) : null,\n retry_count: merged.retryCount,\n next_retry_at: merged.nextRetryAt ?? null,\n updated_at: merged.updatedAt,\n completed_at: merged.completedAt ?? null,\n });\n\n return merged;\n }\n\n getJob<P = unknown, R = unknown>(id: string): Job<P, R> | undefined {\n const row = this.db.prepare('SELECT * FROM jobs WHERE id = ?').get(id) as DbRow | undefined;\n return row ? this.rowToJob<P, R>(row) : undefined;\n }\n\n getJobByIdempotencyKey<P = unknown, R = unknown>(key: string): Job<P, R> | undefined {\n const row = this.db.prepare('SELECT * FROM jobs WHERE idempotency_key = ?').get(key) as\n | DbRow\n | undefined;\n return row ? this.rowToJob<P, R>(row) : undefined;\n }\n\n listJobs<P = unknown, R = unknown>(filter: JobFilter = {}): Job<P, R>[] {\n const conditions: string[] = [];\n const params: Record<string, unknown> = {};\n\n if (filter.type) {\n conditions.push('type = @type');\n params.type = filter.type;\n }\n if (filter.state) {\n const states = Array.isArray(filter.state) ? filter.state : [filter.state];\n const placeholders = states.map((_, i) => `@state_${i}`).join(', ');\n conditions.push(`state IN (${placeholders})`);\n for (const [i, s] of states.entries()) {\n params[`state_${i}`] = s;\n }\n }\n\n const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';\n const limit = filter.limit ? `LIMIT @limit` : '';\n const offset = filter.offset ? `OFFSET @offset` : '';\n\n if (filter.limit) params.limit = filter.limit;\n if (filter.offset) params.offset = filter.offset;\n\n const rows = this.db\n .prepare(`SELECT * FROM jobs ${where} ORDER BY created_at DESC ${limit} ${offset}`)\n .all(params) as DbRow[];\n\n return rows.map((r) => this.rowToJob<P, R>(r));\n }\n\n deleteJob(id: string): void {\n this.db.prepare('DELETE FROM jobs WHERE id = ?').run(id);\n }\n\n /** Return jobs that are ready to be retried right now. */\n getRetryableJobs<P = unknown, R = unknown>(now = Date.now()): Job<P, R>[] {\n const rows = this.db\n .prepare(\n `SELECT * FROM jobs\n WHERE state = 'waiting_retry' AND next_retry_at <= @now\n ORDER BY next_retry_at ASC`,\n )\n .all({ now }) as DbRow[];\n return rows.map((r) => this.rowToJob<P, R>(r));\n }\n\n /** Return jobs in non-terminal states (for recovery after daemon restart). */\n getInProgressJobs<P = unknown, R = unknown>(): Job<P, R>[] {\n const rows = this.db\n .prepare(\n `SELECT * FROM jobs\n WHERE state IN (\n 'queued',\n 'executing',\n 'inflight',\n 'waiting_retry',\n 'invoice_created',\n 'invoice_active',\n 'invoice_received',\n 'channel_opening',\n 'channel_accepting',\n 'channel_abandoning',\n 'channel_updating',\n 'channel_awaiting_ready',\n 'channel_closing'\n )\n ORDER BY created_at ASC`,\n )\n .all() as DbRow[];\n return rows.map((r) => this.rowToJob<P, R>(r));\n }\n\n // ─── Job Events ──────────────────────────────────────────────────────────────\n\n addJobEvent(\n jobId: string,\n eventType: JobEventType,\n fromState?: JobState,\n toState?: JobState,\n data?: Record<string, unknown>,\n ): JobEvent {\n const event: JobEvent = {\n id: randomUUID(),\n jobId,\n eventType,\n fromState,\n toState,\n data,\n createdAt: Date.now(),\n };\n\n this.db\n .prepare(\n `INSERT INTO job_events (id, job_id, event_type, from_state, to_state, data, created_at)\n VALUES (@id, @job_id, @event_type, @from_state, @to_state, @data, @created_at)`,\n )\n .run({\n id: event.id,\n job_id: event.jobId,\n event_type: event.eventType,\n from_state: event.fromState ?? null,\n to_state: event.toState ?? null,\n data: event.data !== undefined ? JSON.stringify(event.data) : null,\n created_at: event.createdAt,\n });\n\n return event;\n }\n\n listJobEvents(jobId: string): JobEvent[] {\n const rows = this.db\n .prepare('SELECT * FROM job_events WHERE job_id = ? ORDER BY created_at ASC')\n .all(jobId) as DbEventRow[];\n\n return rows.map((r) => ({\n id: r.id,\n jobId: r.job_id,\n eventType: r.event_type as JobEventType,\n fromState: (r.from_state as JobState | undefined) ?? undefined,\n toState: (r.to_state as JobState | undefined) ?? undefined,\n data: r.data ? (JSON.parse(r.data) as Record<string, unknown>) : undefined,\n createdAt: r.created_at,\n }));\n }\n\n // ─── Lifecycle ───────────────────────────────────────────────────────────────\n\n close(): void {\n this.db.close();\n }\n\n // ─── Private Helpers ─────────────────────────────────────────────────────────\n\n private rowToJob<P, R>(row: DbRow): Job<P, R> {\n return {\n id: row.id,\n type: row.type as JobType,\n state: row.state as JobState,\n params: JSON.parse(row.params) as P,\n result: row.result ? (JSON.parse(row.result) as R) : undefined,\n error: row.error ? JSON.parse(row.error) : undefined,\n retryCount: row.retry_count,\n maxRetries: row.max_retries,\n nextRetryAt: row.next_retry_at ?? undefined,\n idempotencyKey: row.idempotency_key,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n completedAt: row.completed_at ?? undefined,\n };\n }\n}\n\n// ─── Internal DB row type ─────────────────────────────────────────────────────\n\ninterface DbRow {\n id: string;\n type: string;\n state: string;\n params: string;\n result: string | null;\n error: string | null;\n retry_count: number;\n max_retries: number;\n next_retry_at: number | null;\n idempotency_key: string;\n created_at: number;\n updated_at: number;\n completed_at: number | null;\n}\n\ninterface DbEventRow {\n id: string;\n job_id: string;\n event_type: string;\n from_state: string | null;\n to_state: string | null;\n data: string | null;\n created_at: number;\n}\n","import type { RuntimeConfigInput } from './config.js';\nimport { FiberMonitorService } from './service.js';\n\nexport interface RuntimeBootstrap {\n service: FiberMonitorService;\n stop: () => Promise<void>;\n waitForShutdownSignal: () => Promise<NodeJS.Signals>;\n}\n\nexport async function startRuntimeService(\n configInput: RuntimeConfigInput = {},\n): Promise<RuntimeBootstrap> {\n const service = new FiberMonitorService(configInput);\n await service.start();\n\n let stopping = false;\n const stop = async (): Promise<void> => {\n if (stopping) {\n return;\n }\n stopping = true;\n await service.stop();\n };\n\n const waitForShutdownSignal = (): Promise<NodeJS.Signals> => {\n return new Promise((resolve) => {\n const onSignal = (signal: NodeJS.Signals) => {\n process.off('SIGINT', onSignal);\n process.off('SIGTERM', onSignal);\n resolve(signal);\n };\n process.on('SIGINT', onSignal);\n process.on('SIGTERM', onSignal);\n });\n };\n\n return {\n service,\n stop,\n waitForShutdownSignal,\n };\n}\n","/**\n * Payment Proof & Tracking System\n * Records, stores, and verifies payment evidence for audit trail and reconciliation\n *\n * IMPORTANT LIMITATION:\n * Fiber Network RPC currently does NOT return the payment preimage to the sender\n * after a successful payment. In standard Lightning protocol, the preimage serves\n * as cryptographic proof of payment (SHA256(preimage) === payment_hash).\n *\n * Until Fiber exposes the preimage in send_payment/get_payment responses:\n * - Payment proofs are based on RPC status (Success/Failed) rather than preimage\n * - For invoices YOU create (as receiver), preimage IS available\n * - This limitation affects sender-side proof verification only\n *\n * Tracking issue: Preimage not exposed in Fiber RPC send_payment result\n */\n\nimport { createHash } from 'node:crypto';\nimport { readFile, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport type { HexString, PaymentStatus } from '@fiber-pay/sdk';\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Complete payment proof record\n */\nexport interface PaymentProof {\n /** Unique identifier (payment hash) */\n id: string;\n /** Status at time of recording */\n status: PaymentStatus;\n /** Original invoice string */\n invoice: string;\n /** Invoice details extracted */\n invoiceDetails: {\n paymentHash: string;\n amountCkb: number;\n description?: string;\n };\n /** Payment execution details */\n execution: {\n amountCkb: number;\n feeCkb: number;\n actualTimestamp: number; // When payment settled (if succeeded)\n requestTimestamp: number; // When payment was initiated\n };\n /** Proof of payment */\n proof: {\n preimage?: HexString; // Secret revealed on successful payment\n peerAddress?: string; // Peer that received payment\n channelUsed?: string; // Channel ID used\n routePath?: string[]; // Peers involved in routing\n };\n /** Verification status */\n verified: boolean;\n verifiedAt?: number;\n verificationMethod?: 'preimage_hash' | 'rpc_status' | 'manual';\n /** Metadata for audit trail */\n metadata: {\n createdAt: number;\n updatedAt: number;\n notes?: string;\n };\n}\n\nexport interface PaymentProofSummary {\n totalProofs: number;\n verifiedCount: number;\n pendingCount: number;\n failedCount: number;\n totalAmountCkb: number;\n totalFeesCkb: number;\n timeRange: {\n earliest?: number;\n latest?: number;\n };\n}\n\n// =============================================================================\n// Payment Proof Manager\n// =============================================================================\n\nexport class PaymentProofManager {\n private proofs: Map<string, PaymentProof> = new Map();\n private proofFilePath: string;\n private maxStoredProofs = 10000; // Prevent unbounded growth\n\n constructor(dataDir: string) {\n this.proofFilePath = `${dataDir}/payment-proofs.json`;\n }\n\n /**\n * Load proofs from disk\n */\n async load(): Promise<void> {\n try {\n const data = await readFile(this.proofFilePath, 'utf-8');\n const proofs = JSON.parse(data) as PaymentProof[];\n this.proofs.clear();\n proofs.forEach((proof) => {\n this.proofs.set(proof.id, proof);\n });\n } catch {\n // File doesn't exist yet or is empty\n this.proofs.clear();\n }\n }\n\n /**\n * Save proofs to disk\n */\n async save(): Promise<void> {\n const proofs = Array.from(this.proofs.values());\n const data = JSON.stringify(proofs, null, 2);\n\n try {\n await writeFile(this.proofFilePath, data, 'utf-8');\n } catch (error) {\n if (error instanceof Error && error.message.includes('ENOENT')) {\n // Directory doesn't exist, create it first\n await this.ensureDirectory();\n await writeFile(this.proofFilePath, data, 'utf-8');\n } else {\n throw error;\n }\n }\n }\n\n /**\n * Record a payment proof after successful execution\n */\n recordPaymentProof(\n paymentHash: string,\n invoice: string,\n invoiceDetails: {\n paymentHash: string;\n amountCkb: number;\n description?: string;\n },\n execution: {\n amountCkb: number;\n feeCkb: number;\n actualTimestamp: number;\n requestTimestamp: number;\n },\n status: PaymentStatus,\n proof?: {\n preimage?: HexString;\n peerAddress?: string;\n channelUsed?: string;\n routePath?: string[];\n },\n ): PaymentProof {\n const now = Date.now();\n const fullProof: PaymentProof = {\n id: paymentHash,\n status,\n invoice,\n invoiceDetails,\n execution,\n proof: proof || {},\n verified: false,\n metadata: {\n createdAt: now,\n updatedAt: now,\n },\n };\n\n this.proofs.set(paymentHash, fullProof);\n\n // Verify if we have preimage\n if (proof?.preimage) {\n const isValid = this.verifyPreimageHash(proof.preimage, invoiceDetails.paymentHash);\n if (isValid) {\n fullProof.verified = true;\n fullProof.verifiedAt = now;\n fullProof.verificationMethod = 'preimage_hash';\n }\n }\n\n // Cleanup if we exceed max proofs (keep newest)\n if (this.proofs.size > this.maxStoredProofs) {\n this.pruneOldestProofs(this.maxStoredProofs * 0.8); // Keep 80% after pruning\n }\n\n return fullProof;\n }\n\n /**\n * Get proof by payment hash\n */\n getProof(paymentHash: string): PaymentProof | undefined {\n return this.proofs.get(paymentHash);\n }\n\n /**\n * Verify a proof's authenticity\n */\n verifyProof(proof: PaymentProof): {\n valid: boolean;\n reason: string;\n } {\n // If already verified with preimage, trust it\n if (proof.verified && proof.verificationMethod === 'preimage_hash') {\n return {\n valid: true,\n reason: 'Verified via preimage hash match',\n };\n }\n\n // Try to verify preimage now\n if (proof.proof?.preimage) {\n const hashValid = this.verifyPreimageHash(\n proof.proof.preimage,\n proof.invoiceDetails.paymentHash,\n );\n if (!hashValid) {\n return {\n valid: false,\n reason: 'Preimage does not hash to payment hash',\n };\n }\n proof.verified = true;\n proof.verifiedAt = Date.now();\n proof.verificationMethod = 'preimage_hash';\n return {\n valid: true,\n reason: 'Preimage verified via hash',\n };\n }\n\n // If status is Success without preimage, it was verified by RPC\n if (proof.status === 'Success') {\n return {\n valid: true,\n reason: 'Payment succeeded according to RPC (preimage not available)',\n };\n }\n\n return {\n valid: false,\n reason: 'No verification method available',\n };\n }\n\n /**\n * Get payment timeline between two timestamps\n */\n getPaymentChain(startTime: number, endTime: number): PaymentProof[] {\n return Array.from(this.proofs.values())\n .filter((p) => p.metadata.createdAt >= startTime && p.metadata.createdAt <= endTime)\n .sort((a, b) => a.metadata.createdAt - b.metadata.createdAt);\n }\n\n /**\n * Get summary statistics\n */\n getSummary(): PaymentProofSummary {\n const proofs = Array.from(this.proofs.values());\n\n let verifiedCount = 0;\n let pendingCount = 0;\n let failedCount = 0;\n let totalAmountCkb = 0;\n let totalFeesCkb = 0;\n let earliest: number | undefined;\n let latest: number | undefined;\n\n proofs.forEach((proof) => {\n if (proof.verified) verifiedCount++;\n else if (proof.status === 'Inflight' || proof.status === 'Created') pendingCount++;\n else if (proof.status === 'Failed') failedCount++;\n\n totalAmountCkb += proof.execution.amountCkb;\n totalFeesCkb += proof.execution.feeCkb;\n\n const createdAt = proof.metadata.createdAt;\n if (!earliest || createdAt < earliest) earliest = createdAt;\n if (!latest || createdAt > latest) latest = createdAt;\n });\n\n return {\n totalProofs: proofs.length,\n verifiedCount,\n pendingCount,\n failedCount,\n totalAmountCkb,\n totalFeesCkb,\n timeRange: {\n earliest,\n latest,\n },\n };\n }\n\n /**\n * Export proofs as audit report\n */\n exportAuditReport(startTime?: number, endTime?: number): string {\n const proofs = Array.from(this.proofs.values())\n .filter((p) => {\n if (!startTime && !endTime) return true;\n const created = p.metadata.createdAt;\n if (startTime && created < startTime) return false;\n if (endTime && created > endTime) return false;\n return true;\n })\n .sort((a, b) => a.metadata.createdAt - b.metadata.createdAt);\n\n const lines: string[] = [\n 'Payment Audit Report',\n `Generated: ${new Date().toISOString()}`,\n `Time Range: ${startTime ? new Date(startTime).toISOString() : 'All'} - ${endTime ? new Date(endTime).toISOString() : 'All'}`,\n `Total Payments: ${proofs.length}`,\n '',\n 'Payment ID | Status | Amount CKB | Fee CKB | Verified | Created At',\n '-'.repeat(80),\n ];\n\n proofs.forEach((p) => {\n lines.push(\n `${p.id.slice(0, 16)}... | ${p.status} | ${p.execution.amountCkb.toFixed(4)} | ${p.execution.feeCkb.toFixed(8)} | ${p.verified ? 'Yes' : 'No'} | ${new Date(p.metadata.createdAt).toISOString()}`,\n );\n });\n\n return lines.join('\\n');\n }\n\n /**\n * Verify preimage hash (SHA256 of preimage = payment_hash)\n */\n private verifyPreimageHash(preimage: HexString, paymentHash: string): boolean {\n try {\n // Remove 0x prefix if present\n const preimageHex = preimage.startsWith('0x') ? preimage.slice(2) : preimage;\n const paymentHashHex = paymentHash.startsWith('0x') ? paymentHash.slice(2) : paymentHash;\n\n // Convert hex to buffer\n const preimageBuffer = Buffer.from(preimageHex, 'hex');\n const paymentHashBuffer = Buffer.from(paymentHashHex, 'hex');\n\n // SHA256 hash the preimage\n const hash = createHash('sha256').update(preimageBuffer).digest();\n\n // Compare\n return hash.equals(paymentHashBuffer);\n } catch {\n return false;\n }\n }\n\n /**\n * Remove oldest proofs to keep storage bounded\n */\n private pruneOldestProofs(count: number): void {\n const sorted = Array.from(this.proofs.values()).sort(\n (a, b) => a.metadata.createdAt - b.metadata.createdAt,\n );\n\n const toRemove = sorted.slice(0, Math.floor(sorted.length - count));\n toRemove.forEach((p) => {\n this.proofs.delete(p.id);\n });\n }\n\n /**\n * Ensure directory exists\n */\n private async ensureDirectory(): Promise<void> {\n const dir = dirname(this.proofFilePath);\n try {\n // Use Node.js 20+ mkdir with recursive option\n const fs = await import('node:fs');\n fs.mkdirSync(dir, { recursive: true });\n } catch {\n // Ignore if fails\n }\n }\n}\n"],"mappings":"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","names":["EventEmitter","resolve","resolve","header","randomUUID","DEFAULT_POLL_INTERVAL","randomUUID","ChannelState","ChannelState","http","resolve","http","resolve","dirname","toRecord","dirname","isTerminalPaymentStatus","randomUUID","mkdirSync","dirname","EventEmitter","resolve","createHash","readFile","writeFile","dirname"]}
|
|
1
|
+
{"version":3,"sources":["../src/alerts/format.ts","../src/alerts/types.ts","../src/service.ts","../src/alerts/alert-manager.ts","../src/alerts/backends/file-jsonl.ts","../src/alerts/backends/stdout.ts","../src/utils/async.ts","../src/alerts/backends/webhook.ts","../src/alerts/backends/websocket.ts","../src/config.ts","../src/jobs/retry-policy.ts","../src/jobs/job-manager.ts","../src/jobs/executors/channel-executor.ts","../src/jobs/error-classifier.ts","../src/jobs/executor-utils.ts","../src/jobs/state-machine.ts","../src/jobs/executors/invoice-executor.ts","../src/jobs/executors/payment-executor.ts","../src/jobs/types.ts","../src/monitors/channel-monitor.ts","../src/diff/channel-diff.ts","../src/monitors/base-monitor.ts","../src/monitors/health-monitor.ts","../src/monitors/tracker-utils.ts","../src/monitors/invoice-tracker.ts","../src/monitors/payment-tracker.ts","../src/diff/peer-diff.ts","../src/monitors/peer-monitor.ts","../src/proxy/rpc-proxy.ts","../src/proxy/body.ts","../src/proxy/http-utils.ts","../src/proxy/json.ts","../src/proxy/job-routes.ts","../src/proxy/jsonrpc-tracking.ts","../src/proxy/monitor-routes.ts","../src/storage/memory-store.ts","../src/storage/sqlite-store.ts","../src/bootstrap.ts","../src/storage/payment-proof.ts"],"sourcesContent":["import type { Alert } from './types.js';\n\nconst ANSI_RESET = '\\x1b[0m';\nconst ANSI_BOLD = '\\x1b[1m';\nconst ANSI_DIM = '\\x1b[2m';\nconst ANSI_RED = '\\x1b[31m';\nconst ANSI_GREEN = '\\x1b[32m';\nconst ANSI_YELLOW = '\\x1b[33m';\nconst ANSI_BLUE = '\\x1b[34m';\nconst ANSI_MAGENTA = '\\x1b[35m';\nconst ANSI_CYAN = '\\x1b[36m';\n\nexport interface FormatRuntimeAlertOptions {\n color?: 'auto' | 'always' | 'never';\n prefix?: string;\n}\n\nfunction clip(value: string, max = 120): string {\n if (value.length <= max) {\n return value;\n }\n return `${value.slice(0, max - 1)}…`;\n}\n\nfunction readStringField(record: Record<string, unknown>, key: string): string | undefined {\n const value = record[key];\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nfunction toRecord(value: unknown): Record<string, unknown> | undefined {\n if (!value || typeof value !== 'object') {\n return undefined;\n }\n return value as Record<string, unknown>;\n}\n\nfunction summarizeAlertData(data: unknown, withColor: boolean): string {\n if (data === null || data === undefined) {\n return '{}';\n }\n\n if (typeof data !== 'object') {\n return clip(String(data), 160);\n }\n\n const record = data as Record<string, unknown>;\n const parts: string[] = [];\n\n const eventType = readStringField(record, 'type');\n if (eventType) {\n parts.push(`type=${eventType}`);\n }\n\n const channel = toRecord(record.channel);\n const previousChannel = toRecord(record.previousChannel);\n\n const channelId =\n readStringField(record, 'channelId') ??\n readStringField(channel ?? {}, 'channel_id') ??\n readStringField(previousChannel ?? {}, 'channel_id');\n if (channelId) {\n parts.push(`channelId=${channelId}`);\n }\n\n const paymentHash = readStringField(record, 'paymentHash');\n if (paymentHash) {\n parts.push(`paymentHash=${paymentHash}`);\n }\n\n const invoicePaymentHash = readStringField(record, 'invoicePaymentHash');\n if (invoicePaymentHash) {\n parts.push(`invoicePaymentHash=${invoicePaymentHash}`);\n }\n\n const peerId = readStringField(record, 'peerId') ?? readStringField(channel ?? {}, 'peer_id');\n if (peerId) {\n parts.push(`peerId=${peerId}`);\n }\n\n const jobId = readStringField(record, 'jobId');\n if (jobId) {\n parts.push(`jobId=${jobId}`);\n }\n\n const previousState = readStringField(record, 'previousState');\n const currentState = readStringField(record, 'currentState');\n if (previousState && currentState) {\n parts.push(\n colorize(`state=${previousState}->${currentState}`, `${ANSI_BOLD}${ANSI_YELLOW}`, withColor),\n );\n }\n\n const channelState = toRecord(channel?.state);\n const previousChannelState = toRecord(previousChannel?.state);\n const currentStateName = readStringField(channelState ?? {}, 'state_name');\n const previousStateName = readStringField(previousChannelState ?? {}, 'state_name');\n if (!previousState && !currentState && previousStateName && currentStateName) {\n parts.push(\n colorize(\n `state=${previousStateName}->${currentStateName}`,\n `${ANSI_BOLD}${ANSI_YELLOW}`,\n withColor,\n ),\n );\n } else if (!previousState && !currentState && currentStateName) {\n parts.push(colorize(`state=${currentStateName}`, `${ANSI_BOLD}${ANSI_YELLOW}`, withColor));\n }\n\n const reason = readStringField(record, 'reason') ?? readStringField(record, 'message');\n if (reason) {\n parts.push(`reason=${clip(reason, 80)}`);\n }\n\n const error = readStringField(record, 'error');\n if (error) {\n parts.push(`error=${clip(error, 80)}`);\n }\n\n if (parts.length > 0) {\n return parts.join(' ');\n }\n\n return clip(JSON.stringify(record), 160);\n}\n\nfunction shouldUseColor(mode: NonNullable<FormatRuntimeAlertOptions['color']>): boolean {\n if (mode === 'always') {\n return true;\n }\n if (mode === 'never') {\n return false;\n }\n return process.env.NO_COLOR === undefined && process.stdout.isTTY !== false;\n}\n\nfunction colorize(text: string, color: string, enabled: boolean): string {\n if (!enabled) {\n return text;\n }\n return `${color}${text}${ANSI_RESET}`;\n}\n\nexport function formatRuntimeAlert(alert: Alert, options: FormatRuntimeAlertOptions = {}): string {\n const colorMode = options.color ?? 'auto';\n const withColor = shouldUseColor(colorMode);\n const priorityLabel = alert.priority.toUpperCase().padEnd(8, ' ');\n\n const priorityColor =\n alert.priority === 'critical'\n ? ANSI_RED\n : alert.priority === 'high'\n ? ANSI_YELLOW\n : alert.priority === 'medium'\n ? ANSI_CYAN\n : ANSI_GREEN;\n\n const typeColor = alert.type.startsWith('channel_')\n ? ANSI_BLUE\n : alert.type.startsWith('payment_') ||\n alert.type.startsWith('incoming_') ||\n alert.type.startsWith('outgoing_')\n ? ANSI_MAGENTA\n : ANSI_CYAN;\n\n const prefixLabel = options.prefix ?? '[fiber-runtime]';\n const prefix = colorize(prefixLabel, `${ANSI_BOLD}${ANSI_CYAN}`, withColor);\n const ts = colorize(alert.timestamp, ANSI_DIM, withColor);\n const priority = colorize(priorityLabel, `${ANSI_BOLD}${priorityColor}`, withColor);\n const type = colorize(alert.type, `${ANSI_BOLD}${typeColor}`, withColor);\n const data = colorize(summarizeAlertData(alert.data, withColor), ANSI_DIM, withColor);\n\n return `${prefix} ${ts} ${priority} ${type} ${data}`;\n}\n","import type { Channel, ChannelId, PaymentHash, PeerInfo } from '@fiber-pay/sdk';\n\nexport type AlertPriority = 'critical' | 'high' | 'medium' | 'low';\n\nexport type AlertType =\n | 'channel_state_changed'\n | 'new_inbound_channel_request'\n | 'channel_became_ready'\n | 'channel_closing'\n | 'incoming_payment_received'\n | 'invoice_expired'\n | 'invoice_cancelled'\n | 'outgoing_payment_completed'\n | 'outgoing_payment_failed'\n | 'channel_balance_changed'\n | 'new_pending_tlc'\n | 'peer_connected'\n | 'peer_disconnected'\n | 'node_offline'\n | 'node_online'\n // Job execution alerts\n | 'payment_job_started'\n | 'payment_job_retrying'\n | 'payment_job_succeeded'\n | 'payment_job_failed'\n | 'invoice_job_started'\n | 'invoice_job_retrying'\n | 'invoice_job_succeeded'\n | 'invoice_job_failed'\n | 'channel_job_started'\n | 'channel_job_retrying'\n | 'channel_job_succeeded'\n | 'channel_job_failed';\n\nexport const alertTypeValues: AlertType[] = [\n 'channel_state_changed',\n 'new_inbound_channel_request',\n 'channel_became_ready',\n 'channel_closing',\n 'incoming_payment_received',\n 'invoice_expired',\n 'invoice_cancelled',\n 'outgoing_payment_completed',\n 'outgoing_payment_failed',\n 'channel_balance_changed',\n 'new_pending_tlc',\n 'peer_connected',\n 'peer_disconnected',\n 'node_offline',\n 'node_online',\n 'payment_job_started',\n 'payment_job_retrying',\n 'payment_job_succeeded',\n 'payment_job_failed',\n 'invoice_job_started',\n 'invoice_job_retrying',\n 'invoice_job_succeeded',\n 'invoice_job_failed',\n 'channel_job_started',\n 'channel_job_retrying',\n 'channel_job_succeeded',\n 'channel_job_failed',\n];\n\nexport const alertPriorityOrder: Record<AlertPriority, number> = {\n low: 1,\n medium: 2,\n high: 3,\n critical: 4,\n};\n\nexport interface AlertFilter {\n limit?: number;\n minPriority?: AlertPriority;\n type?: AlertType;\n source?: string;\n}\n\nexport function isAlertPriority(value: string): value is AlertPriority {\n return value === 'critical' || value === 'high' || value === 'medium' || value === 'low';\n}\n\nexport function isAlertType(value: string): value is AlertType {\n return alertTypeValues.includes(value as AlertType);\n}\n\nexport interface Alert<T = unknown> {\n id: string;\n type: AlertType;\n priority: AlertPriority;\n timestamp: string;\n source: string;\n data: T;\n}\n\nexport interface AlertInput<T = unknown> {\n type: AlertType;\n priority: AlertPriority;\n source: string;\n data: T;\n}\n\nexport interface TrackedInvoiceState {\n paymentHash: PaymentHash;\n status: string;\n trackedAt: number;\n updatedAt: number;\n completedAt?: number;\n}\n\nexport interface TrackedPaymentState {\n paymentHash: PaymentHash;\n status: string;\n trackedAt: number;\n updatedAt: number;\n completedAt?: number;\n}\n\nexport interface ChannelBalanceChangedData {\n channelId: ChannelId;\n localBalanceBefore: string;\n localBalanceAfter: string;\n remoteBalanceBefore: string;\n remoteBalanceAfter: string;\n channel: Channel;\n}\n\nexport interface PendingTlcChangedData {\n channelId: ChannelId;\n newPendingTlcCount: number;\n previousPendingTlcCount: number;\n channel: Channel;\n}\n\nexport interface ChannelStateChangedData {\n channelId: ChannelId;\n previousState: string;\n currentState: string;\n channel: Channel;\n}\n\nexport interface PeerEventData {\n peer: PeerInfo;\n}\n\nexport interface RpcHealthData {\n message: string;\n}\n\nexport interface PaymentJobAlertData {\n jobId: string;\n idempotencyKey: string;\n retryCount: number;\n error?: string;\n fee?: string;\n}\n\nexport interface InvoiceJobAlertData {\n jobId: string;\n idempotencyKey: string;\n retryCount: number;\n action?: string;\n status?: string;\n paymentHash?: `0x${string}`;\n error?: string;\n}\n\nexport interface ChannelJobAlertData {\n jobId: string;\n idempotencyKey: string;\n retryCount: number;\n action?: string;\n peerId?: string;\n temporaryChannelId?: `0x${string}`;\n channelId?: `0x${string}`;\n fundingAmount?: string;\n error?: string;\n}\n\nexport interface AlertBackend {\n start?(): Promise<void>;\n send(alert: Alert): Promise<void>;\n stop?(): Promise<void>;\n}\n","import { EventEmitter } from 'node:events';\nimport { FiberRpcClient } from '@fiber-pay/sdk';\nimport { AlertManager } from './alerts/alert-manager.js';\nimport { DailyJsonlFileAlertBackend, JsonlFileAlertBackend } from './alerts/backends/file-jsonl.js';\nimport { StdoutAlertBackend } from './alerts/backends/stdout.js';\nimport { WebhookAlertBackend } from './alerts/backends/webhook.js';\nimport { WebsocketAlertBackend } from './alerts/backends/websocket.js';\nimport type {\n Alert,\n AlertBackend,\n AlertFilter,\n AlertType,\n ChannelJobAlertData,\n InvoiceJobAlertData,\n PaymentJobAlertData,\n} from './alerts/types.js';\nimport { createRuntimeConfig, type RuntimeConfig, type RuntimeConfigInput } from './config.js';\nimport { JobManager } from './jobs/job-manager.js';\nimport type { ChannelJob, InvoiceJob, PaymentJob, RuntimeJob } from './jobs/types.js';\nimport type { BaseMonitor } from './monitors/base-monitor.js';\nimport { ChannelMonitor } from './monitors/channel-monitor.js';\nimport { HealthMonitor } from './monitors/health-monitor.js';\nimport { InvoiceTracker } from './monitors/invoice-tracker.js';\nimport { PaymentTracker } from './monitors/payment-tracker.js';\nimport { PeerMonitor } from './monitors/peer-monitor.js';\nimport { RpcMonitorProxy } from './proxy/rpc-proxy.js';\nimport { MemoryStore } from './storage/memory-store.js';\nimport { SqliteJobStore } from './storage/sqlite-store.js';\n\nexport class FiberMonitorService extends EventEmitter {\n private readonly config: RuntimeConfig;\n private readonly startedAt: string;\n private readonly client: FiberRpcClient;\n private readonly store: MemoryStore;\n private readonly alerts: AlertManager;\n private readonly monitors: BaseMonitor[];\n private readonly proxy: RpcMonitorProxy;\n private readonly jobStore: SqliteJobStore | null;\n private readonly jobManager: JobManager | null;\n private running = false;\n\n constructor(configInput: RuntimeConfigInput = {}) {\n super();\n this.config = createRuntimeConfig(configInput);\n this.startedAt = new Date().toISOString();\n\n this.client = new FiberRpcClient({\n url: this.config.fiberRpcUrl,\n timeout: this.config.requestTimeoutMs,\n });\n\n this.store = new MemoryStore({\n stateFilePath: this.config.storage.stateFilePath,\n flushIntervalMs: this.config.storage.flushIntervalMs,\n maxAlertHistory: this.config.storage.maxAlertHistory,\n });\n\n this.alerts = new AlertManager({\n backends: this.createAlertBackends(this.config),\n store: this.store,\n });\n\n this.jobStore = this.config.jobs.enabled ? new SqliteJobStore(this.config.jobs.dbPath) : null;\n this.jobManager = this.jobStore\n ? new JobManager(this.client, this.jobStore, {\n maxConcurrentJobs: this.config.jobs.maxConcurrentJobs,\n schedulerIntervalMs: this.config.jobs.schedulerIntervalMs,\n retryPolicy: this.config.jobs.retryPolicy,\n })\n : null;\n\n this.wireJobAlerts();\n\n const hooks = {};\n\n this.monitors = [\n new ChannelMonitor({\n client: this.client,\n store: this.store,\n alerts: this.alerts,\n config: {\n intervalMs: this.config.channelPollIntervalMs,\n includeClosedChannels: this.config.includeClosedChannels,\n },\n hooks,\n }),\n new InvoiceTracker({\n client: this.client,\n store: this.store,\n alerts: this.alerts,\n config: {\n intervalMs: this.config.invoicePollIntervalMs,\n completedItemTtlSeconds: this.config.completedItemTtlSeconds,\n },\n hooks,\n }),\n new PaymentTracker({\n client: this.client,\n store: this.store,\n alerts: this.alerts,\n config: {\n intervalMs: this.config.paymentPollIntervalMs,\n completedItemTtlSeconds: this.config.completedItemTtlSeconds,\n },\n hooks,\n }),\n new PeerMonitor({\n client: this.client,\n store: this.store,\n alerts: this.alerts,\n config: { intervalMs: this.config.peerPollIntervalMs },\n hooks,\n }),\n new HealthMonitor({\n client: this.client,\n alerts: this.alerts,\n config: { intervalMs: this.config.healthPollIntervalMs },\n }),\n ];\n\n this.alerts.onEmit((alert) => {\n this.emit('alert', alert);\n });\n\n const jobManager = this.jobManager;\n const jobStore = this.jobStore;\n\n this.proxy = new RpcMonitorProxy(\n {\n listen: this.config.proxy.listen,\n targetUrl: this.config.fiberRpcUrl,\n },\n {\n onInvoiceTracked: (paymentHash) => {\n this.store.addTrackedInvoice(paymentHash as `0x${string}`);\n },\n onPaymentTracked: (paymentHash) => {\n this.store.addTrackedPayment(paymentHash as `0x${string}`);\n },\n listTrackedInvoices: () => this.store.listTrackedInvoices(),\n listTrackedPayments: () => this.store.listTrackedPayments(),\n listAlerts: (filters) => this.store.listAlerts(filters),\n getStatus: () => this.getStatus(),\n createPaymentJob: jobManager\n ? (params, options) => jobManager.ensurePayment(params, options)\n : undefined,\n createInvoiceJob: jobManager\n ? (params, options) => jobManager.manageInvoice(params, options)\n : undefined,\n createChannelJob: jobManager\n ? (params, options) => jobManager.manageChannel(params, options)\n : undefined,\n getJob: jobManager ? (id) => jobManager.getJob(id) : undefined,\n listJobs: jobManager ? (filter) => jobManager.listJobs(filter) : undefined,\n cancelJob: jobManager ? (id) => jobManager.cancelJob(id) : undefined,\n listJobEvents: jobStore ? (jobId) => jobStore.listJobEvents(jobId) : undefined,\n },\n );\n }\n\n async start(): Promise<void> {\n if (this.running) {\n return;\n }\n\n await this.store.load();\n this.store.startAutoFlush();\n await this.alerts.start();\n\n for (const monitor of this.monitors) {\n monitor.start();\n }\n\n this.jobManager?.start();\n\n if (this.config.proxy.enabled) {\n await this.proxy.start();\n }\n\n this.running = true;\n }\n\n async stop(): Promise<void> {\n if (!this.running) {\n return;\n }\n\n for (const monitor of this.monitors) {\n monitor.stop();\n }\n\n await this.jobManager?.stop();\n\n if (this.config.proxy.enabled) {\n await this.proxy.stop();\n }\n\n this.store.stopAutoFlush();\n await this.store.flush();\n await this.alerts.stop();\n this.jobStore?.close();\n this.running = false;\n }\n\n getStatus(): {\n startedAt: string;\n proxyListen: string;\n targetUrl: string;\n running: boolean;\n } {\n return {\n startedAt: this.startedAt,\n proxyListen: this.config.proxy.listen,\n targetUrl: this.config.fiberRpcUrl,\n running: this.running,\n };\n }\n\n listAlerts(filters?: AlertFilter): Alert[] {\n return this.store.listAlerts(filters);\n }\n\n listTrackedInvoices() {\n return this.store.listTrackedInvoices();\n }\n\n listTrackedPayments() {\n return this.store.listTrackedPayments();\n }\n\n trackInvoice(paymentHash: `0x${string}`): void {\n this.store.addTrackedInvoice(paymentHash);\n }\n\n trackPayment(paymentHash: `0x${string}`): void {\n this.store.addTrackedPayment(paymentHash);\n }\n\n private createAlertBackends(config: RuntimeConfig): AlertBackend[] {\n return config.alerts.map((alertConfig) => {\n if (alertConfig.type === 'stdout') {\n return new StdoutAlertBackend();\n }\n if (alertConfig.type === 'webhook') {\n return new WebhookAlertBackend({\n url: alertConfig.url,\n timeoutMs: alertConfig.timeoutMs,\n headers: alertConfig.headers,\n });\n }\n if (alertConfig.type === 'file') {\n return new JsonlFileAlertBackend(alertConfig.path);\n }\n if (alertConfig.type === 'daily-file') {\n return new DailyJsonlFileAlertBackend(alertConfig.baseLogsDir, alertConfig.filename);\n }\n const [host, portText] = alertConfig.listen.split(':');\n return new WebsocketAlertBackend({\n host,\n port: Number(portText),\n });\n });\n }\n\n private wireJobAlerts(): void {\n if (!this.jobManager) {\n return;\n }\n\n this.jobManager.on('job:created', (job) => {\n this.emitJobAlert(job, 'started', 'low');\n this.trackJobArtifacts(job);\n });\n\n this.jobManager.on('job:state_changed', (job) => {\n this.trackJobArtifacts(job);\n if (job.state === 'waiting_retry') {\n this.emitJobAlert(job, 'retrying', 'medium');\n }\n });\n\n this.jobManager.on('job:succeeded', (job) => {\n this.trackJobArtifacts(job);\n this.emitJobAlert(job, 'succeeded', 'medium');\n });\n\n this.jobManager.on('job:failed', (job) => {\n this.trackJobArtifacts(job);\n this.emitJobAlert(job, 'failed', 'high');\n });\n }\n\n private emitJobAlert(\n job: RuntimeJob,\n lifecycle: 'started' | 'retrying' | 'succeeded' | 'failed',\n priority: 'low' | 'medium' | 'high',\n ): void {\n const type = this.toJobAlertType(job.type, lifecycle);\n const data = this.toJobAlertData(job);\n void this.alerts.emit({\n type,\n priority,\n source: 'job-manager',\n data,\n });\n }\n\n private toJobAlertType(\n jobType: RuntimeJob['type'],\n lifecycle: 'started' | 'retrying' | 'succeeded' | 'failed',\n ): AlertType {\n return `${jobType}_job_${lifecycle}` as AlertType;\n }\n\n private toJobAlertData(\n job: RuntimeJob,\n ): PaymentJobAlertData | InvoiceJobAlertData | ChannelJobAlertData {\n const error = job.error?.message;\n\n if (job.type === 'payment') {\n const paymentJob = job as PaymentJob;\n return {\n jobId: paymentJob.id,\n idempotencyKey: paymentJob.idempotencyKey,\n retryCount: paymentJob.retryCount,\n error,\n fee: paymentJob.result?.fee,\n };\n }\n\n if (job.type === 'invoice') {\n const invoiceJob = job as InvoiceJob;\n return {\n jobId: invoiceJob.id,\n idempotencyKey: invoiceJob.idempotencyKey,\n retryCount: invoiceJob.retryCount,\n action: invoiceJob.params.action,\n status: invoiceJob.result?.status,\n paymentHash: this.extractInvoiceHash(invoiceJob),\n error,\n };\n }\n\n const channelJob = job as ChannelJob;\n return {\n jobId: channelJob.id,\n idempotencyKey: channelJob.idempotencyKey,\n retryCount: channelJob.retryCount,\n action: channelJob.params.action,\n peerId: this.extractChannelPeerId(channelJob),\n temporaryChannelId: this.extractTemporaryChannelId(channelJob),\n channelId: this.extractChannelId(channelJob),\n fundingAmount: this.extractChannelFundingAmount(channelJob),\n error,\n };\n }\n\n private trackJobArtifacts(job: RuntimeJob): void {\n if (job.type === 'payment') {\n const paymentHash = this.extractPaymentHash(job);\n if (paymentHash) {\n this.store.addTrackedPayment(paymentHash);\n }\n return;\n }\n\n if (job.type === 'invoice') {\n const paymentHash = this.extractInvoiceHash(job);\n if (paymentHash) {\n this.store.addTrackedInvoice(paymentHash);\n }\n }\n }\n\n private extractPaymentHash(job: PaymentJob): `0x${string}` | undefined {\n return this.normalizeHash(job.result?.paymentHash ?? job.params.sendPaymentParams.payment_hash);\n }\n\n private extractInvoiceHash(job: InvoiceJob): `0x${string}` | undefined {\n return this.normalizeHash(\n job.result?.paymentHash ??\n job.params.getInvoicePaymentHash ??\n job.params.cancelInvoiceParams?.payment_hash ??\n job.params.settleInvoiceParams?.payment_hash ??\n job.params.newInvoiceParams?.payment_hash,\n );\n }\n\n private extractChannelId(job: ChannelJob): `0x${string}` | undefined {\n return this.normalizeHash(\n job.result?.channelId ??\n job.result?.acceptedChannelId ??\n job.params.channelId ??\n job.params.shutdownChannelParams?.channel_id,\n );\n }\n\n private extractChannelPeerId(job: ChannelJob): string | undefined {\n return job.params.peerId ?? job.params.openChannelParams?.peer_id;\n }\n\n private extractTemporaryChannelId(job: ChannelJob): `0x${string}` | undefined {\n return this.normalizeHash(\n job.result?.temporaryChannelId ?? job.params.acceptChannelParams?.temporary_channel_id,\n );\n }\n\n private extractChannelFundingAmount(job: ChannelJob): string | undefined {\n return job.params.openChannelParams?.funding_amount;\n }\n\n private normalizeHash(value: string | undefined): `0x${string}` | undefined {\n if (!value || !value.startsWith('0x')) {\n return undefined;\n }\n return value as `0x${string}`;\n }\n}\n","import { randomUUID } from 'node:crypto';\nimport type { Store } from '../storage/types.js';\nimport type { Alert, AlertBackend, AlertInput } from './types.js';\n\nexport type AlertEmitListener = (alert: Alert) => void;\n\nexport class AlertManager {\n private readonly backends: AlertBackend[];\n private readonly store: Store;\n private readonly listeners: AlertEmitListener[] = [];\n\n constructor(options: { backends: AlertBackend[]; store: Store }) {\n this.backends = options.backends;\n this.store = options.store;\n }\n\n /** Register a listener that is called after every emitted alert. */\n onEmit(listener: AlertEmitListener): void {\n this.listeners.push(listener);\n }\n\n async start(): Promise<void> {\n for (const backend of this.backends) {\n if (backend.start) {\n await backend.start();\n }\n }\n }\n\n async stop(): Promise<void> {\n for (const backend of this.backends) {\n if (backend.stop) {\n await backend.stop();\n }\n }\n }\n\n async emit(input: AlertInput): Promise<Alert> {\n const alert: Alert = {\n id: randomUUID(),\n timestamp: new Date().toISOString(),\n type: input.type,\n priority: input.priority,\n source: input.source,\n data: input.data,\n };\n\n this.store.addAlert(alert);\n\n await Promise.allSettled(this.backends.map((backend) => backend.send(alert)));\n\n for (const listener of this.listeners) {\n listener(alert);\n }\n\n return alert;\n }\n}\n","import { appendFile, mkdir } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport type { Alert, AlertBackend } from '../types.js';\n\nexport class JsonlFileAlertBackend implements AlertBackend {\n private readonly path: string;\n private initialized = false;\n\n constructor(path: string) {\n this.path = path;\n }\n\n async send(alert: Alert): Promise<void> {\n if (!this.initialized) {\n await mkdir(dirname(this.path), { recursive: true });\n this.initialized = true;\n }\n await appendFile(this.path, `${JSON.stringify(alert)}\\n`, 'utf-8');\n }\n}\n\nfunction todayDateString(): string {\n const now = new Date();\n const y = now.getUTCFullYear();\n const m = String(now.getUTCMonth() + 1).padStart(2, '0');\n const d = String(now.getUTCDate()).padStart(2, '0');\n return `${y}-${m}-${d}`;\n}\n\n/**\n * Alert backend that writes JSONL to a daily-rotated file under\n * `<baseLogsDir>/<YYYY-MM-DD>/<filename>`.\n */\nexport class DailyJsonlFileAlertBackend implements AlertBackend {\n private readonly baseLogsDir: string;\n private readonly filename: string;\n\n constructor(baseLogsDir: string, filename = 'runtime.alerts.jsonl') {\n this.baseLogsDir = baseLogsDir;\n this.filename = filename;\n }\n\n async send(alert: Alert): Promise<void> {\n const dateDir = join(this.baseLogsDir, todayDateString());\n await mkdir(dateDir, { recursive: true });\n await appendFile(join(dateDir, this.filename), `${JSON.stringify(alert)}\\n`, 'utf-8');\n }\n}\n","import { formatRuntimeAlert } from '../format.js';\nimport type { Alert, AlertBackend } from '../types.js';\n\nexport class StdoutAlertBackend implements AlertBackend {\n async send(alert: Alert): Promise<void> {\n console.log(formatRuntimeAlert(alert));\n }\n}\n","export function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(new DOMException('Aborted', 'AbortError'));\n return;\n }\n\n const timer = setTimeout(resolve, ms);\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer);\n reject(new DOMException('Aborted', 'AbortError'));\n },\n { once: true },\n );\n });\n}\n","import { sleep } from '../../utils/async.js';\nimport type { Alert, AlertBackend } from '../types.js';\n\nexport interface WebhookAlertBackendConfig {\n url: string;\n timeoutMs?: number;\n headers?: Record<string, string>;\n}\n\nexport class WebhookAlertBackend implements AlertBackend {\n private readonly config: Required<WebhookAlertBackendConfig>;\n\n constructor(config: WebhookAlertBackendConfig) {\n this.config = {\n timeoutMs: 5000,\n headers: {},\n ...config,\n };\n }\n\n async send(alert: Alert): Promise<void> {\n let lastError: unknown;\n\n for (let attempt = 0; attempt < 3; attempt += 1) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.config.timeoutMs);\n try {\n const response = await fetch(this.config.url, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n ...this.config.headers,\n },\n body: JSON.stringify(alert),\n signal: controller.signal,\n });\n clearTimeout(timer);\n\n if (response.ok) {\n return;\n }\n\n lastError = new Error(`Webhook response status: ${response.status}`);\n } catch (error) {\n clearTimeout(timer);\n lastError = error;\n }\n\n await sleep(100 * 2 ** attempt);\n }\n\n throw new Error(`Failed to deliver webhook alert: ${String(lastError)}`);\n }\n}\n","import { createHash } from 'node:crypto';\nimport http from 'node:http';\nimport type { Duplex } from 'node:stream';\nimport type { Alert, AlertBackend } from '../types.js';\n\nexport interface WebsocketAlertBackendConfig {\n host: string;\n port: number;\n}\n\nexport class WebsocketAlertBackend implements AlertBackend {\n private readonly config: WebsocketAlertBackendConfig;\n private readonly clients = new Set<Duplex>();\n private server: http.Server | undefined;\n\n constructor(config: WebsocketAlertBackendConfig) {\n this.config = config;\n }\n\n async start(): Promise<void> {\n if (this.server) {\n return;\n }\n\n this.server = http.createServer((req, res) => {\n if (req.url === '/health') {\n res.writeHead(200, { 'content-type': 'application/json' });\n res.end(JSON.stringify({ ok: true }));\n return;\n }\n\n res.writeHead(404, { 'content-type': 'application/json' });\n res.end(JSON.stringify({ error: 'Not found' }));\n });\n\n this.server.on('upgrade', (request, socket) => {\n const key = request.headers['sec-websocket-key'];\n if (!key || typeof key !== 'string') {\n socket.destroy();\n return;\n }\n\n const accept = createHash('sha1')\n .update(`${key}258EAFA5-E914-47DA-95CA-C5AB0DC85B11`)\n .digest('base64');\n\n const headers = [\n 'HTTP/1.1 101 Switching Protocols',\n 'Upgrade: websocket',\n 'Connection: Upgrade',\n `Sec-WebSocket-Accept: ${accept}`,\n ];\n\n socket.write(`${headers.join('\\r\\n')}\\r\\n\\r\\n`);\n this.clients.add(socket);\n socket.on('close', () => this.clients.delete(socket));\n socket.on('end', () => this.clients.delete(socket));\n socket.on('error', () => this.clients.delete(socket));\n });\n\n await new Promise<void>((resolve, reject) => {\n this.server?.once('error', reject);\n this.server?.listen(this.config.port, this.config.host, () => {\n this.server?.off('error', reject);\n resolve();\n });\n });\n }\n\n async send(alert: Alert): Promise<void> {\n const payload = Buffer.from(JSON.stringify(alert), 'utf8');\n const frame = buildWebSocketFrame(payload);\n\n for (const client of this.clients) {\n try {\n client.write(frame);\n } catch {\n this.clients.delete(client);\n }\n }\n }\n\n async stop(): Promise<void> {\n for (const client of this.clients) {\n client.destroy();\n }\n this.clients.clear();\n\n if (!this.server) {\n return;\n }\n\n const server = this.server;\n this.server = undefined;\n\n await new Promise<void>((resolve) => {\n server.close(() => resolve());\n });\n }\n}\n\nfunction buildWebSocketFrame(payload: Buffer): Buffer {\n const payloadLength = payload.length;\n if (payloadLength < 126) {\n return Buffer.concat([Buffer.from([0x81, payloadLength]), payload]);\n }\n\n if (payloadLength < 65536) {\n const header = Buffer.alloc(4);\n header[0] = 0x81;\n header[1] = 126;\n header.writeUInt16BE(payloadLength, 2);\n return Buffer.concat([header, payload]);\n }\n\n const header = Buffer.alloc(10);\n header[0] = 0x81;\n header[1] = 127;\n header.writeUInt32BE(0, 2);\n header.writeUInt32BE(payloadLength, 6);\n return Buffer.concat([header, payload]);\n}\n","import { resolve } from 'node:path';\nimport { defaultPaymentRetryPolicy } from './jobs/retry-policy.js';\nimport type { RetryPolicy } from './jobs/types.js';\n\nexport interface StdoutAlertConfig {\n type: 'stdout';\n}\n\nexport interface WebhookAlertConfig {\n type: 'webhook';\n url: string;\n timeoutMs?: number;\n headers?: Record<string, string>;\n}\n\nexport interface WebsocketAlertConfig {\n type: 'websocket';\n listen: string;\n}\n\nexport interface FileAlertConfig {\n type: 'file';\n path: string;\n}\n\nexport interface DailyFileAlertConfig {\n type: 'daily-file';\n baseLogsDir: string;\n filename?: string;\n}\n\nexport type AlertBackendConfig =\n | StdoutAlertConfig\n | WebhookAlertConfig\n | WebsocketAlertConfig\n | FileAlertConfig\n | DailyFileAlertConfig;\n\nexport interface RuntimeConfig {\n fiberRpcUrl: string;\n channelPollIntervalMs: number;\n invoicePollIntervalMs: number;\n paymentPollIntervalMs: number;\n peerPollIntervalMs: number;\n healthPollIntervalMs: number;\n includeClosedChannels: boolean;\n completedItemTtlSeconds: number;\n requestTimeoutMs: number;\n alerts: AlertBackendConfig[];\n proxy: {\n enabled: boolean;\n listen: string;\n };\n storage: {\n stateFilePath: string;\n flushIntervalMs: number;\n maxAlertHistory: number;\n };\n jobs: {\n /** Enable the payment job execution engine. Default: false */\n enabled: boolean;\n /** Path to the SQLite file for job persistence. Default: derived from storage.stateFilePath */\n dbPath: string;\n maxConcurrentJobs: number;\n schedulerIntervalMs: number;\n retryPolicy: RetryPolicy;\n };\n}\n\nexport type RuntimeConfigInput = Omit<Partial<RuntimeConfig>, 'proxy' | 'storage' | 'jobs'> & {\n proxy?: Partial<RuntimeConfig['proxy']>;\n storage?: Partial<RuntimeConfig['storage']>;\n jobs?: Partial<RuntimeConfig['jobs']>;\n};\n\nexport const defaultRuntimeConfig: RuntimeConfig = {\n fiberRpcUrl: 'http://127.0.0.1:8227',\n channelPollIntervalMs: 5000,\n invoicePollIntervalMs: 3000,\n paymentPollIntervalMs: 2000,\n peerPollIntervalMs: 15000,\n healthPollIntervalMs: 10000,\n includeClosedChannels: false,\n completedItemTtlSeconds: 86400,\n requestTimeoutMs: 10000,\n alerts: [{ type: 'stdout' }],\n proxy: {\n enabled: true,\n listen: '127.0.0.1:8229',\n },\n storage: {\n stateFilePath: resolve(process.cwd(), '.fiber-pay-runtime-state.json'),\n flushIntervalMs: 30000,\n maxAlertHistory: 5000,\n },\n jobs: {\n enabled: true,\n dbPath: resolve(process.cwd(), '.fiber-pay-jobs.db'),\n maxConcurrentJobs: 5,\n schedulerIntervalMs: 1000,\n retryPolicy: defaultPaymentRetryPolicy,\n },\n};\n\nexport function createRuntimeConfig(input: RuntimeConfigInput = {}): RuntimeConfig {\n const config: RuntimeConfig = {\n fiberRpcUrl: input.fiberRpcUrl ?? defaultRuntimeConfig.fiberRpcUrl,\n channelPollIntervalMs:\n input.channelPollIntervalMs ?? defaultRuntimeConfig.channelPollIntervalMs,\n invoicePollIntervalMs:\n input.invoicePollIntervalMs ?? defaultRuntimeConfig.invoicePollIntervalMs,\n paymentPollIntervalMs:\n input.paymentPollIntervalMs ?? defaultRuntimeConfig.paymentPollIntervalMs,\n peerPollIntervalMs: input.peerPollIntervalMs ?? defaultRuntimeConfig.peerPollIntervalMs,\n healthPollIntervalMs: input.healthPollIntervalMs ?? defaultRuntimeConfig.healthPollIntervalMs,\n includeClosedChannels:\n input.includeClosedChannels ?? defaultRuntimeConfig.includeClosedChannels,\n completedItemTtlSeconds:\n input.completedItemTtlSeconds ?? defaultRuntimeConfig.completedItemTtlSeconds,\n requestTimeoutMs: input.requestTimeoutMs ?? defaultRuntimeConfig.requestTimeoutMs,\n proxy: {\n enabled: input.proxy?.enabled ?? defaultRuntimeConfig.proxy.enabled,\n listen: input.proxy?.listen ?? defaultRuntimeConfig.proxy.listen,\n },\n storage: {\n stateFilePath: input.storage?.stateFilePath ?? defaultRuntimeConfig.storage.stateFilePath,\n flushIntervalMs:\n input.storage?.flushIntervalMs ?? defaultRuntimeConfig.storage.flushIntervalMs,\n maxAlertHistory:\n input.storage?.maxAlertHistory ?? defaultRuntimeConfig.storage.maxAlertHistory,\n },\n jobs: {\n enabled: input.jobs?.enabled ?? defaultRuntimeConfig.jobs.enabled,\n dbPath: input.jobs?.dbPath ?? defaultRuntimeConfig.jobs.dbPath,\n maxConcurrentJobs:\n input.jobs?.maxConcurrentJobs ?? defaultRuntimeConfig.jobs.maxConcurrentJobs,\n schedulerIntervalMs:\n input.jobs?.schedulerIntervalMs ?? defaultRuntimeConfig.jobs.schedulerIntervalMs,\n retryPolicy: {\n maxRetries:\n input.jobs?.retryPolicy?.maxRetries ?? defaultRuntimeConfig.jobs.retryPolicy.maxRetries,\n baseDelayMs:\n input.jobs?.retryPolicy?.baseDelayMs ?? defaultRuntimeConfig.jobs.retryPolicy.baseDelayMs,\n maxDelayMs:\n input.jobs?.retryPolicy?.maxDelayMs ?? defaultRuntimeConfig.jobs.retryPolicy.maxDelayMs,\n backoffMultiplier:\n input.jobs?.retryPolicy?.backoffMultiplier ??\n defaultRuntimeConfig.jobs.retryPolicy.backoffMultiplier,\n jitterMs:\n input.jobs?.retryPolicy?.jitterMs ?? defaultRuntimeConfig.jobs.retryPolicy.jitterMs,\n },\n },\n alerts: input.alerts ?? defaultRuntimeConfig.alerts,\n };\n\n if (!config.fiberRpcUrl) {\n throw new Error('Runtime config requires fiberRpcUrl');\n }\n if (!config.proxy.listen) {\n throw new Error('Runtime config requires proxy.listen');\n }\n if (config.channelPollIntervalMs <= 0 || config.invoicePollIntervalMs <= 0) {\n throw new Error('Polling intervals must be > 0');\n }\n if (config.paymentPollIntervalMs <= 0 || config.peerPollIntervalMs <= 0) {\n throw new Error('Polling intervals must be > 0');\n }\n if (config.healthPollIntervalMs <= 0) {\n throw new Error('healthPollIntervalMs must be > 0');\n }\n if (config.completedItemTtlSeconds < 0) {\n throw new Error('completedItemTtlSeconds must be >= 0');\n }\n if (config.storage.flushIntervalMs <= 0) {\n throw new Error('storage.flushIntervalMs must be > 0');\n }\n if (config.storage.maxAlertHistory <= 0) {\n throw new Error('storage.maxAlertHistory must be > 0');\n }\n if (!config.jobs.dbPath) {\n throw new Error('jobs.dbPath is required');\n }\n if (config.jobs.maxConcurrentJobs <= 0) {\n throw new Error('jobs.maxConcurrentJobs must be > 0');\n }\n if (config.jobs.schedulerIntervalMs <= 0) {\n throw new Error('jobs.schedulerIntervalMs must be > 0');\n }\n if (config.jobs.retryPolicy.maxRetries < 0) {\n throw new Error('jobs.retryPolicy.maxRetries must be >= 0');\n }\n if (config.jobs.retryPolicy.baseDelayMs < 0) {\n throw new Error('jobs.retryPolicy.baseDelayMs must be >= 0');\n }\n if (config.jobs.retryPolicy.maxDelayMs < 0) {\n throw new Error('jobs.retryPolicy.maxDelayMs must be >= 0');\n }\n\n return config;\n}\n\nexport function parseListenAddress(listen: string): { host: string; port: number } {\n const [host, portText] = listen.split(':');\n const port = Number(portText);\n if (!host || Number.isNaN(port) || port <= 0) {\n throw new Error(`Invalid listen address: ${listen}`);\n }\n return { host, port };\n}\n","import type { ClassifiedError, RetryPolicy } from './types.js';\n\nexport const defaultPaymentRetryPolicy: RetryPolicy = {\n maxRetries: 3,\n baseDelayMs: 2_000,\n maxDelayMs: 30_000,\n backoffMultiplier: 2,\n jitterMs: 500,\n};\n\n/**\n * Decide whether a job should be retried given its error and current retry count.\n */\nexport function shouldRetry(\n error: ClassifiedError,\n retryCount: number,\n policy: RetryPolicy,\n): boolean {\n if (!error.retryable) return false;\n if (retryCount >= policy.maxRetries) return false;\n return true;\n}\n\n/**\n * Compute the next retry delay using exponential backoff with random jitter.\n * retryCount is the number of retries already attempted (0-based before this retry).\n */\nexport function computeRetryDelay(retryCount: number, policy: RetryPolicy): number {\n const base = policy.baseDelayMs * policy.backoffMultiplier ** retryCount;\n const capped = Math.min(base, policy.maxDelayMs);\n const jitter = Math.floor(Math.random() * policy.jitterMs);\n return capped + jitter;\n}\n","import { randomUUID } from 'node:crypto';\nimport { EventEmitter } from 'node:events';\nimport type { FiberRpcClient } from '@fiber-pay/sdk';\nimport type { SqliteJobStore } from '../storage/sqlite-store.js';\nimport { runChannelJob } from './executors/channel-executor.js';\nimport { runInvoiceJob } from './executors/invoice-executor.js';\nimport { runPaymentJob } from './executors/payment-executor.js';\nimport { defaultPaymentRetryPolicy } from './retry-policy.js';\nimport type {\n ChannelJob,\n ChannelJobParams,\n InvoiceJob,\n InvoiceJobParams,\n JobFilter,\n JobState,\n PaymentJob,\n PaymentJobParams,\n RetryPolicy,\n RuntimeJob,\n} from './types.js';\nimport { TERMINAL_JOB_STATES } from './types.js';\n\nfunction stableStringify(value: unknown): string {\n if (value === null || typeof value !== 'object') {\n return JSON.stringify(value);\n }\n if (Array.isArray(value)) {\n return `[${value.map((item) => stableStringify(item)).join(',')}]`;\n }\n const entries = Object.entries(value as Record<string, unknown>)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, nested]) => `${JSON.stringify(key)}:${stableStringify(nested)}`);\n return `{${entries.join(',')}}`;\n}\n\nfunction haveSameParams(left: unknown, right: unknown): boolean {\n return stableStringify(left) === stableStringify(right);\n}\n\nexport interface JobManagerEvents {\n 'job:created': [job: RuntimeJob];\n 'job:state_changed': [job: RuntimeJob, from: JobState];\n 'job:succeeded': [job: RuntimeJob];\n 'job:failed': [job: RuntimeJob];\n 'job:cancelled': [job: RuntimeJob];\n}\n\ninterface ActiveExecution {\n abortController: AbortController;\n promise: Promise<void>;\n}\n\nexport interface JobManagerConfig {\n schedulerIntervalMs?: number;\n maxConcurrentJobs?: number;\n retryPolicy?: RetryPolicy;\n}\n\nexport class JobManager extends EventEmitter<JobManagerEvents> {\n private readonly rpc: FiberRpcClient;\n private readonly store: SqliteJobStore;\n private readonly retryPolicy: RetryPolicy;\n private readonly schedulerIntervalMs: number;\n private readonly maxConcurrentJobs: number;\n\n private running = false;\n private schedulerTimer: ReturnType<typeof setInterval> | undefined;\n private readonly active = new Map<string, ActiveExecution>();\n\n constructor(rpc: FiberRpcClient, store: SqliteJobStore, config: JobManagerConfig = {}) {\n super();\n this.rpc = rpc;\n this.store = store;\n this.retryPolicy = config.retryPolicy ?? defaultPaymentRetryPolicy;\n this.schedulerIntervalMs = config.schedulerIntervalMs ?? 1000;\n this.maxConcurrentJobs = config.maxConcurrentJobs ?? 5;\n }\n\n async ensurePayment(\n params: PaymentJobParams,\n options: {\n idempotencyKey?: string;\n maxRetries?: number;\n } = {},\n ): Promise<PaymentJob> {\n const idempotencyKey =\n options.idempotencyKey ??\n (params.sendPaymentParams.payment_hash as string | undefined) ??\n randomUUID();\n\n const existing = this.store.getJobByIdempotencyKey<PaymentJobParams, PaymentJob['result']>(\n idempotencyKey,\n );\n if (existing?.type === 'payment') {\n if (!haveSameParams(existing.params, params)) {\n throw new Error(\n `Idempotency key collision with different payment params: ${idempotencyKey}. Use a new idempotency key for a new payment intent.`,\n );\n }\n if (existing.state === 'succeeded' || existing.state === 'cancelled') {\n return existing as PaymentJob;\n }\n if (!TERMINAL_JOB_STATES.has(existing.state) || existing.state === 'failed') {\n if (existing.state === 'failed' && !this.active.has(existing.id)) {\n const reset = this.store.updateJob<PaymentJobParams, PaymentJob['result']>(existing.id, {\n state: 'queued',\n params,\n result: undefined,\n error: undefined,\n retryCount: 0,\n nextRetryAt: undefined,\n completedAt: undefined,\n });\n this.schedule(reset as RuntimeJob);\n return reset as PaymentJob;\n }\n return existing as PaymentJob;\n }\n }\n\n const job = this.store.createJob<PaymentJobParams, PaymentJob['result']>({\n type: 'payment',\n state: 'queued',\n params,\n retryCount: 0,\n maxRetries: options.maxRetries ?? this.retryPolicy.maxRetries,\n idempotencyKey,\n }) as PaymentJob;\n\n this.store.addJobEvent(job.id, 'created', undefined, 'queued', this.buildEventData(job));\n this.emit('job:created', job);\n this.schedule(job);\n return job;\n }\n\n async manageInvoice(\n params: InvoiceJobParams,\n options: { idempotencyKey?: string; maxRetries?: number; reuseTerminal?: boolean } = {},\n ): Promise<InvoiceJob> {\n const idempotencyKey = options.idempotencyKey ?? deriveInvoiceKey(params) ?? randomUUID();\n return this.createOrReuseJob<InvoiceJobParams, InvoiceJob['result']>(\n 'invoice',\n params,\n idempotencyKey,\n options.maxRetries,\n options.reuseTerminal,\n ) as Promise<InvoiceJob>;\n }\n\n async manageChannel(\n params: ChannelJobParams,\n options: { idempotencyKey?: string; maxRetries?: number; reuseTerminal?: boolean } = {},\n ): Promise<ChannelJob> {\n const idempotencyKey = options.idempotencyKey ?? deriveChannelKey(params) ?? randomUUID();\n return this.createOrReuseJob<ChannelJobParams, ChannelJob['result']>(\n 'channel',\n params,\n idempotencyKey,\n options.maxRetries,\n options.reuseTerminal,\n ) as Promise<ChannelJob>;\n }\n\n getJob(id: string): RuntimeJob | undefined {\n return this.store.getJob(id) as RuntimeJob | undefined;\n }\n\n listJobs(filter: JobFilter = {}): RuntimeJob[] {\n return this.store.listJobs(filter) as RuntimeJob[];\n }\n\n cancelJob(id: string): void {\n const job = this.getJob(id);\n if (!job) throw new Error(`Job not found: ${id}`);\n if (TERMINAL_JOB_STATES.has(job.state)) return;\n\n this.active.get(id)?.abortController.abort();\n\n if (!this.active.has(id)) {\n const updated = this.store.updateJob(id, {\n state: 'cancelled',\n completedAt: Date.now(),\n }) as RuntimeJob;\n this.store.addJobEvent(id, 'cancelled', job.state, 'cancelled', this.buildEventData(updated));\n this.emit('job:cancelled', updated);\n }\n }\n\n start(): void {\n if (this.running) return;\n this.running = true;\n this.recover();\n this.schedulerTimer = setInterval(() => this.tick(), this.schedulerIntervalMs);\n }\n\n async stop(): Promise<void> {\n this.running = false;\n if (this.schedulerTimer) {\n clearInterval(this.schedulerTimer);\n this.schedulerTimer = undefined;\n }\n for (const [, exec] of this.active) {\n exec.abortController.abort();\n }\n await Promise.allSettled(Array.from(this.active.values()).map((e) => e.promise));\n }\n\n private async createOrReuseJob<P, R>(\n type: 'invoice' | 'channel',\n params: P,\n idempotencyKey: string,\n maxRetries?: number,\n reuseTerminal?: boolean,\n ): Promise<RuntimeJob> {\n const existing = this.store.getJobByIdempotencyKey<P, R>(idempotencyKey);\n if (existing?.type === type) {\n if (!haveSameParams(existing.params, params)) {\n throw new Error(\n `Idempotency key collision with different ${type} params: ${idempotencyKey}. Use a new idempotency key for a new ${type} intent.`,\n );\n }\n if (existing.state === 'succeeded' || existing.state === 'cancelled') {\n if (reuseTerminal === false) {\n const reset = this.store.updateJob<P, R>(existing.id, {\n state: 'queued',\n params,\n result: undefined,\n error: undefined,\n retryCount: 0,\n nextRetryAt: undefined,\n completedAt: undefined,\n } as unknown as Partial<import('./types.js').Job<P, R>>);\n this.store.addJobEvent(\n existing.id,\n 'created',\n existing.state,\n 'queued',\n this.buildEventData(reset as RuntimeJob),\n );\n this.emit('job:created', reset as RuntimeJob);\n this.schedule(reset as RuntimeJob);\n return reset as RuntimeJob;\n }\n return existing as RuntimeJob;\n }\n if (!TERMINAL_JOB_STATES.has(existing.state) || existing.state === 'failed') {\n if (existing.state === 'failed' && !this.active.has(existing.id)) {\n const reset = this.store.updateJob<P, R>(existing.id, {\n state: 'queued',\n params,\n result: undefined,\n error: undefined,\n retryCount: 0,\n nextRetryAt: undefined,\n completedAt: undefined,\n });\n this.schedule(reset as RuntimeJob);\n return reset as RuntimeJob;\n }\n return existing as RuntimeJob;\n }\n }\n\n const job = this.store.createJob<P, R>({\n type,\n state: 'queued',\n params,\n retryCount: 0,\n maxRetries: maxRetries ?? this.retryPolicy.maxRetries,\n idempotencyKey,\n }) as RuntimeJob;\n\n this.store.addJobEvent(job.id, 'created', undefined, 'queued', this.buildEventData(job));\n this.emit('job:created', job);\n this.schedule(job);\n return job;\n }\n\n private tick(): void {\n if (!this.running) return;\n if (this.active.size >= this.maxConcurrentJobs) return;\n\n const queued = this.store.listJobs({\n state: 'queued',\n limit: this.maxConcurrentJobs - this.active.size,\n }) as RuntimeJob[];\n\n for (const job of queued) {\n if (this.active.size >= this.maxConcurrentJobs) break;\n if (!this.active.has(job.id)) {\n this.execute(job);\n }\n }\n\n if (this.active.size < this.maxConcurrentJobs) {\n const retryable = this.store.getRetryableJobs() as RuntimeJob[];\n for (const job of retryable) {\n if (this.active.size >= this.maxConcurrentJobs) break;\n if (!this.active.has(job.id)) {\n this.execute(job);\n }\n }\n }\n }\n\n private schedule(job: RuntimeJob): void {\n if (this.running && this.active.size < this.maxConcurrentJobs && !this.active.has(job.id)) {\n this.execute(job);\n }\n }\n\n private recover(): void {\n const inProgress = this.store.getInProgressJobs() as RuntimeJob[];\n for (const job of inProgress) {\n if (this.active.size >= this.maxConcurrentJobs) break;\n let recoveredJob = job;\n if (job.type === 'payment' && (job.state === 'executing' || job.state === 'inflight')) {\n recoveredJob = this.store.updateJob<unknown, unknown>(job.id, {\n state: 'inflight',\n }) as RuntimeJob;\n }\n this.execute(recoveredJob);\n }\n }\n\n private execute(job: RuntimeJob): void {\n const abortController = new AbortController();\n\n const promise = (async () => {\n try {\n const generator =\n job.type === 'payment'\n ? runPaymentJob(job as PaymentJob, this.rpc, this.retryPolicy, abortController.signal)\n : job.type === 'invoice'\n ? runInvoiceJob(job as InvoiceJob, this.rpc, this.retryPolicy, abortController.signal)\n : runChannelJob(\n job as ChannelJob,\n this.rpc,\n this.retryPolicy,\n abortController.signal,\n );\n\n for await (const updated of generator) {\n const prev = this.getJob(updated.id);\n const fromState = prev?.state ?? job.state;\n\n this.store.updateJob<unknown, unknown>(\n updated.id,\n updated as Partial<import('./types.js').Job>,\n );\n this.store.addJobEvent(\n updated.id,\n stateToEvent(updated.state),\n fromState,\n updated.state,\n this.buildEventData(updated),\n );\n\n this.emit('job:state_changed', updated, fromState);\n\n if (updated.state === 'succeeded') this.emit('job:succeeded', updated);\n if (updated.state === 'failed') this.emit('job:failed', updated);\n if (updated.state === 'cancelled') this.emit('job:cancelled', updated);\n }\n } finally {\n this.active.delete(job.id);\n }\n })();\n\n this.active.set(job.id, { abortController, promise });\n }\n\n private buildEventData(job: RuntimeJob): Record<string, unknown> {\n const base: Record<string, unknown> = {\n type: job.type,\n idempotencyKey: job.idempotencyKey,\n retryCount: job.retryCount,\n maxRetries: job.maxRetries,\n nextRetryAt: job.nextRetryAt,\n };\n\n if (job.error) {\n base.error = {\n category: job.error.category,\n retryable: job.error.retryable,\n message: job.error.message,\n };\n }\n\n if (job.type === 'payment') {\n const paymentJob = job as PaymentJob;\n return {\n ...base,\n invoice: paymentJob.params.invoice,\n paymentHash: paymentJob.result?.paymentHash,\n paymentStatus: paymentJob.result?.status,\n };\n }\n\n if (job.type === 'invoice') {\n const invoiceJob = job as InvoiceJob;\n return {\n ...base,\n action: invoiceJob.params.action,\n paymentHash: invoiceJob.result?.paymentHash ?? invoiceJob.params.getInvoicePaymentHash,\n invoiceStatus: invoiceJob.result?.status,\n };\n }\n\n const channelJob = job as ChannelJob;\n return {\n ...base,\n action: channelJob.params.action,\n channelId:\n channelJob.params.channelId ??\n channelJob.params.shutdownChannelParams?.channel_id ??\n channelJob.result?.channelId,\n peerId: channelJob.params.peerId ?? channelJob.params.openChannelParams?.peer_id,\n channelState: channelJob.result?.state,\n };\n }\n}\n\nfunction deriveInvoiceKey(params: InvoiceJobParams): string | undefined {\n if (params.action === 'watch' && params.getInvoicePaymentHash) {\n return `invoice:watch:${params.getInvoicePaymentHash}`;\n }\n if (params.action === 'cancel' && params.cancelInvoiceParams?.payment_hash) {\n return `invoice:cancel:${params.cancelInvoiceParams.payment_hash}`;\n }\n if (params.action === 'settle' && params.settleInvoiceParams?.payment_hash) {\n return `invoice:settle:${params.settleInvoiceParams.payment_hash}`;\n }\n if (params.action === 'create' && params.newInvoiceParams?.payment_hash) {\n return `invoice:create:${params.newInvoiceParams.payment_hash}`;\n }\n return undefined;\n}\n\nfunction deriveChannelKey(params: ChannelJobParams): string | undefined {\n if (params.action === 'open') return undefined;\n if (params.acceptChannelParams?.temporary_channel_id) {\n return `channel:accept:${params.acceptChannelParams.temporary_channel_id}`;\n }\n if (params.action === 'shutdown' && params.shutdownChannelParams?.channel_id) {\n return `channel:shutdown:${params.shutdownChannelParams.channel_id}`;\n }\n if (params.action === 'abandon' && params.abandonChannelParams?.channel_id) {\n return `channel:abandon:${params.abandonChannelParams.channel_id}`;\n }\n if (params.action === 'update' && params.updateChannelParams?.channel_id) {\n const fingerprint = stableStringify(params.updateChannelParams);\n return `channel:update:${params.updateChannelParams.channel_id}:${fingerprint}`;\n }\n if (params.channelId) return `channel:${params.action}:${params.channelId}`;\n return undefined;\n}\n\nfunction stateToEvent(state: JobState): import('./types.js').JobEventType {\n switch (state) {\n case 'executing':\n return 'executing';\n case 'inflight':\n return 'inflight';\n case 'invoice_created':\n return 'invoice_created';\n case 'invoice_received':\n return 'invoice_received';\n case 'invoice_settled':\n return 'invoice_settled';\n case 'invoice_expired':\n return 'invoice_expired';\n case 'invoice_cancelled':\n return 'invoice_cancelled';\n case 'channel_opening':\n return 'channel_opening';\n case 'channel_accepting':\n return 'channel_accepting';\n case 'channel_abandoning':\n return 'channel_abandoning';\n case 'channel_updating':\n return 'channel_updating';\n case 'channel_awaiting_ready':\n return 'channel_awaiting_ready';\n case 'channel_ready':\n return 'channel_ready';\n case 'channel_closing':\n return 'channel_closing';\n case 'channel_closed':\n return 'channel_closed';\n case 'waiting_retry':\n return 'retry_scheduled';\n case 'succeeded':\n return 'succeeded';\n case 'failed':\n return 'failed';\n case 'cancelled':\n return 'cancelled';\n default:\n return 'executing';\n }\n}\n","import { ChannelState, type FiberRpcClient } from '@fiber-pay/sdk';\nimport { sleep } from '../../utils/async.js';\nimport { classifyRpcError } from '../error-classifier.js';\nimport { applyRetryOrFail, transitionJobState } from '../executor-utils.js';\nimport { channelStateMachine } from '../state-machine.js';\nimport type { ChannelJob, ClassifiedError, RetryPolicy } from '../types.js';\n\nconst DEFAULT_POLL_INTERVAL = 2_000;\n\nexport async function* runChannelJob(\n job: ChannelJob,\n rpc: FiberRpcClient,\n policy: RetryPolicy,\n signal: AbortSignal,\n): AsyncGenerator<ChannelJob> {\n let current = { ...job };\n const resumedFromRetry = job.state === 'waiting_retry';\n\n if (current.state === 'queued') {\n current = transitionJobState(current, channelStateMachine, 'send_issued');\n yield current;\n }\n\n if (current.state === 'waiting_retry') {\n const delay = current.nextRetryAt ? Math.max(0, current.nextRetryAt - Date.now()) : 0;\n if (delay > 0) {\n await sleep(delay, signal);\n if (signal.aborted) {\n current = transitionJobState(current, channelStateMachine, 'cancel');\n yield current;\n return;\n }\n }\n current = transitionJobState(current, channelStateMachine, 'retry_delay_elapsed', {\n patch: { nextRetryAt: undefined },\n });\n yield current;\n }\n\n try {\n const pollIntervalMs = current.params.pollIntervalMs ?? DEFAULT_POLL_INTERVAL;\n\n if (current.params.action === 'open') {\n if (!current.params.openChannelParams) {\n throw new Error('Channel open job requires openChannelParams');\n }\n\n const targetPeerId = current.params.peerId ?? current.params.openChannelParams.peer_id;\n let temporaryChannelId = current.result?.temporaryChannelId;\n\n if (resumedFromRetry) {\n const existing = await findTargetChannel(rpc, targetPeerId, current.params.channelId);\n if (existing && !isClosed(existing.state.state_name)) {\n current = transitionJobState(current, channelStateMachine, 'channel_opening', {\n patch: {\n result: {\n temporaryChannelId,\n channelId: existing.channel_id,\n state: existing.state.state_name,\n },\n },\n });\n yield current;\n } else {\n const opened = await rpc.openChannel(current.params.openChannelParams);\n temporaryChannelId = opened.temporary_channel_id;\n current = transitionJobState(current, channelStateMachine, 'channel_opening', {\n patch: {\n result: {\n temporaryChannelId,\n state: 'OPENING',\n },\n },\n });\n yield current;\n }\n } else {\n const opened = await rpc.openChannel(current.params.openChannelParams);\n temporaryChannelId = opened.temporary_channel_id;\n current = transitionJobState(current, channelStateMachine, 'channel_opening', {\n patch: {\n result: {\n temporaryChannelId,\n state: 'OPENING',\n },\n },\n });\n yield current;\n }\n\n if (!current.params.waitForReady) {\n current = transitionJobState(current, channelStateMachine, 'payment_success');\n yield current;\n return;\n }\n\n while (true) {\n if (signal.aborted) {\n current = transitionJobState(current, channelStateMachine, 'cancel');\n yield current;\n return;\n }\n\n const channels = await rpc.listChannels({\n peer_id: targetPeerId,\n include_closed: true,\n });\n\n const candidates = channels.channels.filter((channel) => {\n if (current.params.channelId && channel.channel_id !== current.params.channelId)\n return false;\n return channel.peer_id === targetPeerId;\n });\n\n const readyMatch = candidates.find(\n (channel) => String(channel.state.state_name).toUpperCase() === 'CHANNEL_READY',\n );\n\n const activeMatch = candidates.find((channel) => !isClosed(channel.state.state_name));\n\n const closedMatch =\n current.params.channelId && !activeMatch && candidates.length > 0\n ? candidates.find((channel) => isTerminalClosed(channel.state.state_name))\n : undefined;\n\n if (readyMatch) {\n current = transitionJobState(current, channelStateMachine, 'channel_ready', {\n patch: {\n result: {\n temporaryChannelId,\n channelId: readyMatch.channel_id,\n state: readyMatch.state.state_name,\n },\n },\n });\n yield current;\n\n current = transitionJobState(current, channelStateMachine, 'payment_success');\n yield current;\n return;\n }\n\n if (closedMatch) {\n current = transitionJobState(current, channelStateMachine, 'channel_closed', {\n patch: {\n result: {\n temporaryChannelId,\n channelId: closedMatch.channel_id,\n state: closedMatch.state.state_name,\n },\n },\n });\n yield current;\n current = transitionJobState(current, channelStateMachine, 'payment_failed_permanent');\n yield current;\n return;\n }\n\n current = transitionJobState(current, channelStateMachine, 'channel_opening');\n yield current;\n await sleep(pollIntervalMs, signal);\n }\n }\n\n if (current.params.action === 'shutdown') {\n const shutdownParams = current.params.shutdownChannelParams;\n if (!shutdownParams) {\n throw new Error('Channel shutdown job requires shutdownChannelParams');\n }\n\n await rpc.shutdownChannel(shutdownParams);\n current = transitionJobState(current, channelStateMachine, 'channel_closing', {\n patch: {\n result: {\n channelId: shutdownParams.channel_id,\n state: 'SHUTTING_DOWN',\n },\n },\n });\n yield current;\n\n const waitForClosed = current.params.waitForClosed ?? Boolean(shutdownParams.force);\n if (!waitForClosed) {\n current = transitionJobState(current, channelStateMachine, 'payment_success');\n yield current;\n return;\n }\n\n while (true) {\n if (signal.aborted) {\n current = transitionJobState(current, channelStateMachine, 'cancel');\n yield current;\n return;\n }\n\n const channels = await rpc.listChannels({ include_closed: true });\n const match = channels.channels.find(\n (channel) => channel.channel_id === shutdownParams.channel_id,\n );\n\n if (!match || isTerminalClosed(String(match.state.state_name))) {\n current = transitionJobState(current, channelStateMachine, 'channel_closed', {\n patch: {\n result: {\n channelId: shutdownParams.channel_id,\n state: 'CLOSED',\n },\n },\n });\n yield current;\n current = transitionJobState(current, channelStateMachine, 'payment_success');\n yield current;\n return;\n }\n\n await sleep(pollIntervalMs, signal);\n }\n }\n\n if (current.params.action === 'accept') {\n if (!current.params.acceptChannelParams) {\n throw new Error('Channel accept job requires acceptChannelParams');\n }\n\n const accepted = await rpc.acceptChannel(current.params.acceptChannelParams);\n current = transitionJobState(current, channelStateMachine, 'channel_accepting', {\n patch: {\n result: {\n acceptedChannelId: accepted.channel_id,\n channelId: accepted.channel_id,\n state: 'ACCEPTED',\n },\n },\n });\n yield current;\n\n current = transitionJobState(current, channelStateMachine, 'payment_success');\n yield current;\n return;\n }\n\n if (current.params.action === 'abandon') {\n if (!current.params.abandonChannelParams) {\n throw new Error('Channel abandon job requires abandonChannelParams');\n }\n\n await rpc.abandonChannel(current.params.abandonChannelParams);\n current = transitionJobState(current, channelStateMachine, 'channel_abandoning', {\n patch: {\n result: {\n channelId: current.params.abandonChannelParams.channel_id,\n state: 'ABANDONED',\n },\n },\n });\n yield current;\n\n current = transitionJobState(current, channelStateMachine, 'payment_success');\n yield current;\n return;\n }\n\n if (current.params.action === 'update') {\n if (!current.params.updateChannelParams) {\n throw new Error('Channel update job requires updateChannelParams');\n }\n\n await rpc.updateChannel(current.params.updateChannelParams);\n current = transitionJobState(current, channelStateMachine, 'channel_updating', {\n patch: {\n result: {\n channelId: current.params.updateChannelParams.channel_id,\n state: 'UPDATED',\n },\n },\n });\n yield current;\n\n current = transitionJobState(current, channelStateMachine, 'payment_success');\n yield current;\n return;\n }\n\n throw new Error(\n `Unsupported channel action: ${(current.params as { action?: string }).action}`,\n );\n } catch (error) {\n const classified = classifyChannelError(error);\n current = applyRetryOrFail(current, classified, policy, {\n machine: channelStateMachine,\n retryEvent: 'payment_failed_retryable',\n failEvent: 'payment_failed_permanent',\n });\n yield current;\n }\n}\n\nfunction classifyChannelError(error: unknown): ClassifiedError {\n const base = classifyRpcError(error);\n if (base.retryable) {\n return base;\n }\n\n const raw = base.rawError ?? base.message;\n if (\n /channel\\s+not\\s+found|no\\s+channel\\s+with\\s+.*\\s+found|no\\s+channel\\s+.*\\s+found/i.test(raw)\n ) {\n return {\n ...base,\n category: 'temporary_failure',\n retryable: true,\n rawError: raw,\n };\n }\n\n if (/invalid\\s+state|negotiatingfunding|cannot\\s+.*\\s+in\\s+.*state/i.test(raw)) {\n return {\n ...base,\n category: 'temporary_failure',\n retryable: true,\n rawError: raw,\n };\n }\n\n return base;\n}\n\nasync function findTargetChannel(rpc: FiberRpcClient, peerId: string, channelId?: `0x${string}`) {\n const channels = await rpc.listChannels({\n peer_id: peerId,\n include_closed: true,\n });\n\n return channels.channels.find((channel) => {\n if (channelId && channel.channel_id !== channelId) return false;\n return channel.peer_id === peerId;\n });\n}\n\nfunction isClosed(stateName: string): boolean {\n return (\n stateName === ChannelState.Closed ||\n stateName === 'CLOSED' ||\n stateName === ChannelState.ShuttingDown ||\n stateName === 'SHUTTING_DOWN'\n );\n}\n\nfunction isTerminalClosed(stateName: string): boolean {\n return stateName === ChannelState.Closed || stateName === 'CLOSED';\n}\n","import type { ClassifiedError, ErrorCategory } from './types.js';\n\n// Fiber node error strings seen in `failed_error` field of PaymentInfo.\n// These are best-effort matches — extend as real failure messages are observed.\nconst PATTERNS: Array<{ pattern: RegExp; category: ErrorCategory; retryable: boolean }> = [\n // Routing / topology\n { pattern: /no path found|no route|route not found/i, category: 'no_route', retryable: true },\n { pattern: /no outgoing channel|no available channel/i, category: 'no_route', retryable: true },\n // Liquidity\n {\n pattern: /insufficient (balance|capacity|funds)/i,\n category: 'insufficient_balance',\n retryable: false,\n },\n {\n pattern: /amount.*too large|exceeds.*capacity/i,\n category: 'amount_too_large',\n retryable: false,\n },\n // Invoice lifecycle\n { pattern: /invoice.*expir|expir.*invoice/i, category: 'invoice_expired', retryable: false },\n { pattern: /invoice.*cancel|cancel.*invoice/i, category: 'invoice_cancelled', retryable: false },\n {\n pattern: /payment hash.*exist|payment_hash.*exist|duplicated payment hash/i,\n category: 'invalid_payment',\n retryable: false,\n },\n // Peer / connectivity\n {\n pattern: /peer.*offline|peer.*unreachable|peer.*disconnect/i,\n category: 'peer_offline',\n retryable: true,\n },\n { pattern: /connection.*refused|connection.*reset/i, category: 'peer_offline', retryable: true },\n { pattern: /fetch failed/i, category: 'peer_offline', retryable: true },\n {\n pattern: /peer.*feature not found|waiting for peer to send init message/i,\n category: 'peer_offline',\n retryable: true,\n },\n {\n pattern: /channel.*already.*exist|duplicat(e|ed).*channel/i,\n category: 'temporary_failure',\n retryable: true,\n },\n // Timeout\n { pattern: /timeout|timed out/i, category: 'timeout', retryable: true },\n // Payment validity\n {\n pattern: /invalid.*invoice|malformed.*invoice/i,\n category: 'invalid_payment',\n retryable: false,\n },\n {\n pattern: /payment.*hash.*mismatch|preimage.*invalid/i,\n category: 'invalid_payment',\n retryable: false,\n },\n // Generic temporary\n {\n pattern: /temporary.*failure|try again|retry/i,\n category: 'temporary_failure',\n retryable: true,\n },\n];\n\n/**\n * Classify an RPC / job failure into a structured error.\n *\n * `failedError` is the raw `failed_error` string from Fiber's `get_payment` response.\n * `error` is any caught JS exception.\n */\nexport function classifyRpcError(error: unknown, failedError?: string): ClassifiedError {\n // Prefer Fiber's own error string since it is the most authoritative\n const raw = failedError ?? (error instanceof Error ? error.message : String(error));\n\n for (const { pattern, category, retryable } of PATTERNS) {\n if (pattern.test(raw)) {\n return { category, retryable, message: raw, rawError: raw };\n }\n }\n\n return {\n category: 'unknown',\n retryable: false, // safe default: don't retry unknowns\n message: raw,\n rawError: raw,\n };\n}\n","import { computeRetryDelay, shouldRetry } from './retry-policy.js';\nimport type { JobStateMachine, MachineEvent } from './state-machine.js';\nimport type { ClassifiedError, JobState, RetryPolicy } from './types.js';\n\ntype RetryableJobShape = {\n state: JobState;\n error?: ClassifiedError;\n retryCount: number;\n maxRetries: number;\n nextRetryAt?: number;\n updatedAt: number;\n completedAt?: number;\n};\n\nexport function transitionJobState<\n T extends { state: JobState; updatedAt: number; completedAt?: number },\n>(\n job: T,\n machine: JobStateMachine,\n event: MachineEvent,\n options?: {\n now?: number;\n patch?: Partial<T>;\n },\n): T {\n const nextState = machine.transition(job.state, event);\n if (!nextState) {\n throw new Error(`Invalid state transition: ${job.state} --${event}--> ?`);\n }\n\n const now = options?.now ?? Date.now();\n return {\n ...job,\n ...(options?.patch ?? {}),\n state: nextState,\n updatedAt: now,\n completedAt: machine.isTerminal(nextState) ? now : job.completedAt,\n } as T;\n}\n\nexport function applyRetryOrFail<T extends RetryableJobShape>(\n job: T,\n classifiedError: ClassifiedError,\n policy: RetryPolicy,\n options?: {\n now?: number;\n failedPatch?: Partial<T>;\n machine?: JobStateMachine;\n retryEvent?: MachineEvent;\n failEvent?: MachineEvent;\n },\n): T {\n const now = options?.now ?? Date.now();\n\n const effectivePolicy: RetryPolicy = {\n ...policy,\n maxRetries: job.maxRetries,\n };\n\n if (shouldRetry(classifiedError, job.retryCount, effectivePolicy)) {\n const delay = computeRetryDelay(job.retryCount, effectivePolicy);\n const retryTransition =\n options?.machine && options.retryEvent\n ? transitionJobState(job, options.machine, options.retryEvent, { now })\n : ({ ...job, state: 'waiting_retry', updatedAt: now } as T);\n\n return {\n ...retryTransition,\n error: classifiedError,\n retryCount: job.retryCount + 1,\n nextRetryAt: now + delay,\n } as T;\n }\n\n const failTransition =\n options?.machine && options.failEvent\n ? transitionJobState(job, options.machine, options.failEvent, { now })\n : ({ ...job, state: 'failed', completedAt: now, updatedAt: now } as T);\n\n return {\n ...failTransition,\n error: classifiedError,\n ...(options?.failedPatch ?? {}),\n } as T;\n}\n","import type { JobState } from './types.js';\n\n// ─── State Machine ────────────────────────────────────────────────────────────\n\nexport type MachineEvent =\n | 'send_issued'\n | 'payment_inflight'\n | 'payment_success'\n | 'payment_failed_retryable'\n | 'payment_failed_permanent'\n | 'invoice_created'\n | 'invoice_received'\n | 'invoice_settled'\n | 'invoice_expired'\n | 'invoice_cancelled'\n | 'channel_opening'\n | 'channel_accepting'\n | 'channel_abandoning'\n | 'channel_updating'\n | 'channel_closing'\n | 'channel_ready'\n | 'channel_closed'\n | 'channel_failed'\n | 'retry_delay_elapsed'\n | 'cancel';\n\ninterface Transition {\n from: JobState | JobState[];\n event: MachineEvent;\n to: JobState;\n}\n\nconst PAYMENT_TRANSITIONS: Transition[] = [\n { from: 'queued', event: 'send_issued', to: 'executing' },\n { from: 'executing', event: 'payment_inflight', to: 'inflight' },\n { from: 'executing', event: 'payment_success', to: 'succeeded' },\n { from: 'executing', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'executing', event: 'payment_failed_permanent', to: 'failed' },\n { from: 'inflight', event: 'payment_success', to: 'succeeded' },\n { from: 'inflight', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'inflight', event: 'payment_failed_permanent', to: 'failed' },\n { from: 'waiting_retry', event: 'retry_delay_elapsed', to: 'executing' },\n {\n from: ['queued', 'executing', 'inflight', 'waiting_retry'],\n event: 'cancel',\n to: 'cancelled',\n },\n];\n\nconst INVOICE_TRANSITIONS: Transition[] = [\n { from: 'queued', event: 'send_issued', to: 'executing' },\n { from: 'executing', event: 'invoice_created', to: 'invoice_created' },\n { from: 'invoice_created', event: 'payment_success', to: 'succeeded' },\n { from: 'executing', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'invoice_created', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'invoice_active', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'invoice_received', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'waiting_retry', event: 'retry_delay_elapsed', to: 'executing' },\n { from: 'invoice_created', event: 'invoice_received', to: 'invoice_received' },\n { from: 'invoice_created', event: 'invoice_settled', to: 'invoice_settled' },\n { from: 'invoice_active', event: 'invoice_received', to: 'invoice_received' },\n { from: 'invoice_active', event: 'invoice_settled', to: 'invoice_settled' },\n { from: 'invoice_active', event: 'invoice_expired', to: 'invoice_expired' },\n { from: 'invoice_active', event: 'invoice_cancelled', to: 'invoice_cancelled' },\n { from: 'invoice_received', event: 'invoice_settled', to: 'invoice_settled' },\n {\n from: ['invoice_created', 'invoice_received'],\n event: 'invoice_expired',\n to: 'invoice_expired',\n },\n {\n from: ['invoice_created', 'invoice_received'],\n event: 'invoice_cancelled',\n to: 'invoice_cancelled',\n },\n {\n from: ['invoice_settled', 'invoice_expired', 'invoice_cancelled'],\n event: 'payment_success',\n to: 'succeeded',\n },\n {\n from: ['invoice_expired', 'invoice_cancelled'],\n event: 'payment_failed_permanent',\n to: 'failed',\n },\n {\n from: ['executing', 'invoice_created', 'invoice_active', 'invoice_received'],\n event: 'payment_failed_permanent',\n to: 'failed',\n },\n {\n from: [\n 'queued',\n 'executing',\n 'waiting_retry',\n 'invoice_created',\n 'invoice_active',\n 'invoice_received',\n ],\n event: 'cancel',\n to: 'cancelled',\n },\n];\n\nconst CHANNEL_TRANSITIONS: Transition[] = [\n { from: 'queued', event: 'send_issued', to: 'executing' },\n { from: 'executing', event: 'channel_opening', to: 'channel_opening' },\n { from: 'executing', event: 'channel_accepting', to: 'channel_accepting' },\n { from: 'executing', event: 'channel_abandoning', to: 'channel_abandoning' },\n { from: 'executing', event: 'channel_updating', to: 'channel_updating' },\n { from: 'channel_opening', event: 'payment_success', to: 'succeeded' },\n { from: 'channel_accepting', event: 'payment_success', to: 'succeeded' },\n { from: 'channel_abandoning', event: 'payment_success', to: 'succeeded' },\n { from: 'channel_updating', event: 'payment_success', to: 'succeeded' },\n { from: 'executing', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'channel_opening', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'channel_accepting', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'channel_abandoning', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'channel_updating', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'channel_awaiting_ready', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'channel_closing', event: 'payment_failed_retryable', to: 'waiting_retry' },\n { from: 'executing', event: 'payment_failed_permanent', to: 'failed' },\n { from: 'channel_opening', event: 'payment_failed_permanent', to: 'failed' },\n { from: 'channel_accepting', event: 'payment_failed_permanent', to: 'failed' },\n { from: 'channel_abandoning', event: 'payment_failed_permanent', to: 'failed' },\n { from: 'channel_updating', event: 'payment_failed_permanent', to: 'failed' },\n { from: 'channel_awaiting_ready', event: 'payment_failed_permanent', to: 'failed' },\n { from: 'channel_closing', event: 'payment_failed_permanent', to: 'failed' },\n { from: ['executing', 'channel_ready'], event: 'channel_closing', to: 'channel_closing' },\n { from: 'waiting_retry', event: 'retry_delay_elapsed', to: 'executing' },\n { from: 'channel_opening', event: 'channel_opening', to: 'channel_awaiting_ready' },\n { from: 'channel_awaiting_ready', event: 'channel_opening', to: 'channel_awaiting_ready' },\n { from: 'channel_opening', event: 'channel_ready', to: 'channel_ready' },\n { from: 'channel_awaiting_ready', event: 'channel_ready', to: 'channel_ready' },\n { from: ['channel_opening', 'channel_ready'], event: 'channel_closed', to: 'channel_closed' },\n { from: 'channel_awaiting_ready', event: 'channel_closed', to: 'channel_closed' },\n { from: 'channel_closing', event: 'channel_closed', to: 'channel_closed' },\n { from: 'channel_closing', event: 'payment_success', to: 'succeeded' },\n { from: 'channel_closed', event: 'payment_failed_permanent', to: 'failed' },\n { from: ['channel_ready', 'channel_opening'], event: 'channel_failed', to: 'failed' },\n { from: ['channel_ready', 'channel_closed'], event: 'payment_success', to: 'succeeded' },\n {\n from: [\n 'queued',\n 'executing',\n 'waiting_retry',\n 'channel_opening',\n 'channel_accepting',\n 'channel_abandoning',\n 'channel_updating',\n 'channel_awaiting_ready',\n 'channel_ready',\n 'channel_closing',\n ],\n event: 'cancel',\n to: 'cancelled',\n },\n];\n\nexport class JobStateMachine {\n private readonly table: Map<string, JobState>;\n\n constructor(transitions: Transition[]) {\n this.table = new Map();\n for (const t of transitions) {\n const froms = Array.isArray(t.from) ? t.from : [t.from];\n for (const from of froms) {\n this.table.set(`${from}:${t.event}`, t.to);\n }\n }\n }\n\n transition(current: JobState, event: MachineEvent): JobState | null {\n return this.table.get(`${current}:${event}`) ?? null;\n }\n\n isTerminal(state: JobState): boolean {\n return state === 'succeeded' || state === 'failed' || state === 'cancelled';\n }\n}\n\nexport const paymentStateMachine = new JobStateMachine(PAYMENT_TRANSITIONS);\nexport const invoiceStateMachine = new JobStateMachine(INVOICE_TRANSITIONS);\nexport const channelStateMachine = new JobStateMachine(CHANNEL_TRANSITIONS);\n","import type { FiberRpcClient } from '@fiber-pay/sdk';\nimport { sleep } from '../../utils/async.js';\nimport { classifyRpcError } from '../error-classifier.js';\nimport { applyRetryOrFail, transitionJobState } from '../executor-utils.js';\nimport { invoiceStateMachine } from '../state-machine.js';\nimport type { InvoiceJob, RetryPolicy } from '../types.js';\n\nconst DEFAULT_POLL_INTERVAL = 1_500;\n\nexport async function* runInvoiceJob(\n job: InvoiceJob,\n rpc: FiberRpcClient,\n policy: RetryPolicy,\n signal: AbortSignal,\n): AsyncGenerator<InvoiceJob> {\n let current = { ...job };\n\n if (current.state === 'queued') {\n current = transitionJobState(current, invoiceStateMachine, 'send_issued');\n yield current;\n }\n\n if (current.state === 'waiting_retry') {\n const delay = current.nextRetryAt ? Math.max(0, current.nextRetryAt - Date.now()) : 0;\n if (delay > 0) {\n await sleep(delay, signal);\n if (signal.aborted) {\n current = transitionJobState(current, invoiceStateMachine, 'cancel');\n yield current;\n return;\n }\n }\n current = transitionJobState(current, invoiceStateMachine, 'retry_delay_elapsed', {\n patch: { nextRetryAt: undefined },\n });\n yield current;\n }\n\n try {\n const pollIntervalMs = current.params.pollIntervalMs ?? DEFAULT_POLL_INTERVAL;\n\n if (current.params.action === 'create') {\n if (!current.params.newInvoiceParams) {\n throw new Error('Invoice create job requires newInvoiceParams');\n }\n const created = await rpc.newInvoice(current.params.newInvoiceParams);\n const paymentHash = created.invoice.data.payment_hash;\n const createdStatus = 'Open';\n\n current = {\n ...current,\n state: 'invoice_created',\n result: {\n paymentHash,\n invoiceAddress: created.invoice_address,\n status: createdStatus,\n invoice: created.invoice,\n },\n updatedAt: Date.now(),\n };\n yield current;\n\n if (!current.params.waitForTerminal) {\n current = transitionJobState(current, invoiceStateMachine, 'payment_success');\n yield current;\n return;\n }\n\n // Watch invoice until terminal\n while (true) {\n if (signal.aborted) {\n current = transitionJobState(current, invoiceStateMachine, 'cancel');\n yield current;\n return;\n }\n\n const invoice = await rpc.getInvoice({ payment_hash: paymentHash });\n if (invoice.status === 'Paid') {\n current = {\n ...current,\n state: 'invoice_settled',\n result: {\n paymentHash,\n invoiceAddress: invoice.invoice_address,\n status: invoice.status,\n invoice: invoice.invoice,\n },\n updatedAt: Date.now(),\n };\n yield current;\n\n current = transitionJobState(current, invoiceStateMachine, 'payment_success');\n yield current;\n return;\n }\n\n if (invoice.status === 'Received') {\n current = {\n ...current,\n state: 'invoice_received',\n result: {\n paymentHash,\n invoiceAddress: invoice.invoice_address,\n status: invoice.status,\n invoice: invoice.invoice,\n },\n updatedAt: Date.now(),\n };\n yield current;\n } else if (invoice.status === 'Cancelled') {\n current = {\n ...current,\n state: 'invoice_cancelled',\n result: {\n paymentHash,\n invoiceAddress: invoice.invoice_address,\n status: invoice.status,\n invoice: invoice.invoice,\n },\n completedAt: Date.now(),\n updatedAt: Date.now(),\n };\n yield current;\n current = transitionJobState(current, invoiceStateMachine, 'payment_failed_permanent');\n yield current;\n return;\n } else if (invoice.status === 'Expired') {\n current = {\n ...current,\n state: 'invoice_expired',\n result: {\n paymentHash,\n invoiceAddress: invoice.invoice_address,\n status: invoice.status,\n invoice: invoice.invoice,\n },\n completedAt: Date.now(),\n updatedAt: Date.now(),\n };\n yield current;\n current = transitionJobState(current, invoiceStateMachine, 'payment_failed_permanent');\n yield current;\n return;\n }\n\n await sleep(pollIntervalMs, signal);\n }\n }\n\n if (current.params.action === 'watch') {\n if (!current.params.getInvoicePaymentHash) {\n throw new Error('Invoice watch job requires getInvoicePaymentHash');\n }\n const paymentHash = current.params.getInvoicePaymentHash;\n while (true) {\n if (signal.aborted) {\n current = transitionJobState(current, invoiceStateMachine, 'cancel');\n yield current;\n return;\n }\n\n const invoice = await rpc.getInvoice({ payment_hash: paymentHash });\n current = {\n ...current,\n state:\n invoice.status === 'Paid'\n ? 'invoice_settled'\n : invoice.status === 'Received'\n ? 'invoice_received'\n : invoice.status === 'Cancelled'\n ? 'invoice_cancelled'\n : invoice.status === 'Expired'\n ? 'invoice_expired'\n : 'invoice_active',\n result: {\n paymentHash,\n invoiceAddress: invoice.invoice_address,\n status: invoice.status,\n invoice: invoice.invoice,\n },\n updatedAt: Date.now(),\n };\n yield current;\n\n if (invoice.status === 'Paid') {\n current = transitionJobState(current, invoiceStateMachine, 'payment_success');\n yield current;\n return;\n }\n if (invoice.status === 'Cancelled' || invoice.status === 'Expired') {\n current = transitionJobState(current, invoiceStateMachine, 'payment_failed_permanent');\n yield current;\n return;\n }\n\n await sleep(pollIntervalMs, signal);\n }\n }\n\n if (current.params.action === 'cancel') {\n if (!current.params.cancelInvoiceParams) {\n throw new Error('Invoice cancel job requires cancelInvoiceParams');\n }\n const cancelled = await rpc.cancelInvoice(current.params.cancelInvoiceParams);\n current = {\n ...current,\n state: 'invoice_cancelled',\n result: {\n paymentHash: current.params.cancelInvoiceParams.payment_hash,\n invoiceAddress: cancelled.invoice_address,\n status: cancelled.status,\n invoice: cancelled.invoice,\n },\n updatedAt: Date.now(),\n };\n yield current;\n current = transitionJobState(current, invoiceStateMachine, 'payment_success');\n yield current;\n return;\n }\n\n if (current.params.action === 'settle') {\n if (!current.params.settleInvoiceParams) {\n throw new Error('Invoice settle job requires settleInvoiceParams');\n }\n await rpc.settleInvoice(current.params.settleInvoiceParams);\n current = {\n ...current,\n state: 'invoice_settled',\n result: {\n paymentHash: current.params.settleInvoiceParams.payment_hash,\n status: 'Paid',\n },\n updatedAt: Date.now(),\n };\n yield current;\n current = transitionJobState(current, invoiceStateMachine, 'payment_success');\n yield current;\n return;\n }\n\n throw new Error(\n `Unsupported invoice action: ${(current.params as { action?: string }).action}`,\n );\n } catch (error) {\n const classified = classifyRpcError(error);\n current = applyRetryOrFail(current, classified, policy, {\n machine: invoiceStateMachine,\n retryEvent: 'payment_failed_retryable',\n failEvent: 'payment_failed_permanent',\n });\n yield current;\n }\n}\n","import type { FiberRpcClient } from '@fiber-pay/sdk';\nimport { sleep } from '../../utils/async.js';\nimport { classifyRpcError } from '../error-classifier.js';\nimport { applyRetryOrFail, transitionJobState } from '../executor-utils.js';\nimport { paymentStateMachine } from '../state-machine.js';\nimport type { PaymentJob, RetryPolicy } from '../types.js';\n\n// ─── PaymentExecutor ──────────────────────────────────────────────────────────\n\n/**\n * Drives a single PaymentJob through its full lifecycle.\n *\n * Yields the updated job object on every state transition so the caller\n * (JobManager) can persist + emit events after each change with no extra lookups.\n *\n * The generator terminates when the job reaches a terminal state\n * (succeeded | failed | cancelled).\n */\nexport async function* runPaymentJob(\n job: PaymentJob,\n rpc: FiberRpcClient,\n policy: RetryPolicy,\n signal: AbortSignal,\n): AsyncGenerator<PaymentJob> {\n let current = { ...job };\n\n while (!paymentStateMachine.isTerminal(current.state)) {\n if (signal.aborted) {\n current = transitionJobState(current, paymentStateMachine, 'cancel');\n yield current;\n return;\n }\n\n if (current.state === 'queued') {\n current = transitionJobState(current, paymentStateMachine, 'send_issued');\n yield current;\n continue;\n }\n\n if (current.state === 'waiting_retry') {\n const delay = current.nextRetryAt ? Math.max(0, current.nextRetryAt - Date.now()) : 0;\n if (delay > 0) {\n await sleep(delay, signal);\n if (signal.aborted) {\n current = transitionJobState(current, paymentStateMachine, 'cancel');\n yield current;\n return;\n }\n }\n current = transitionJobState(current, paymentStateMachine, 'retry_delay_elapsed', {\n patch: { nextRetryAt: undefined },\n });\n yield current;\n continue;\n }\n\n if (current.state === 'executing') {\n // ── Issue the RPC call ──────────────────────────────────────────────────\n let paymentHash: string | undefined;\n\n try {\n const sendResult = await rpc.sendPayment(current.params.sendPaymentParams);\n paymentHash = sendResult.payment_hash;\n\n if (sendResult.status === 'Success') {\n current = transitionJobState(current, paymentStateMachine, 'payment_success', {\n patch: {\n result: {\n paymentHash: sendResult.payment_hash,\n status: sendResult.status,\n fee: sendResult.fee,\n failedError: sendResult.failed_error,\n },\n },\n });\n yield current;\n return;\n }\n\n if (sendResult.status === 'Failed') {\n const classified = classifyRpcError(\n new Error(sendResult.failed_error ?? 'Payment failed'),\n sendResult.failed_error,\n );\n current = applyRetryOrFail(current, classified, policy, {\n failedPatch: {\n result: {\n paymentHash: sendResult.payment_hash,\n status: sendResult.status,\n fee: sendResult.fee,\n failedError: sendResult.failed_error,\n },\n },\n machine: paymentStateMachine,\n retryEvent: 'payment_failed_retryable',\n failEvent: 'payment_failed_permanent',\n });\n yield current;\n continue;\n }\n\n // Status is 'Created' or 'Inflight' — move to polling state\n // Dry-run payments are never persisted by the node, so polling\n // getPayment would loop forever with \"Payment session not found\".\n if (current.params.sendPaymentParams.dry_run) {\n current = transitionJobState(current, paymentStateMachine, 'payment_success', {\n patch: {\n result: {\n paymentHash: sendResult.payment_hash,\n status: 'DryRunSuccess',\n fee: sendResult.fee,\n },\n },\n });\n yield current;\n return;\n }\n\n current = transitionJobState(current, paymentStateMachine, 'payment_inflight');\n if (paymentHash) {\n current = {\n ...current,\n params: {\n ...current.params,\n sendPaymentParams: {\n ...current.params.sendPaymentParams,\n payment_hash: paymentHash as `0x${string}`,\n },\n },\n };\n }\n yield current;\n continue;\n } catch (err) {\n // RPC call itself threw — classify and decide\n const classified = classifyRpcError(err);\n current = applyRetryOrFail(current, classified, policy, {\n machine: paymentStateMachine,\n retryEvent: 'payment_failed_retryable',\n failEvent: 'payment_failed_permanent',\n });\n yield current;\n continue;\n }\n }\n\n if (current.state === 'inflight') {\n // ── Poll get_payment until terminal ────────────────────────────────────\n const hash = current.params.sendPaymentParams.payment_hash as string | undefined;\n\n if (!hash) {\n // Shouldn't happen, but fail-safe\n current = transitionJobState(current, paymentStateMachine, 'payment_failed_permanent', {\n patch: {\n error: {\n category: 'unknown',\n retryable: false,\n message: 'No payment_hash in inflight job',\n },\n },\n });\n yield current;\n continue;\n }\n\n try {\n const pollResult = await rpc.getPayment({ payment_hash: hash as `0x${string}` });\n\n if (pollResult.status === 'Success') {\n current = transitionJobState(current, paymentStateMachine, 'payment_success', {\n patch: {\n result: {\n paymentHash: pollResult.payment_hash,\n status: pollResult.status,\n fee: pollResult.fee,\n failedError: pollResult.failed_error,\n },\n },\n });\n yield current;\n return;\n }\n\n if (pollResult.status === 'Failed') {\n const classified = classifyRpcError(\n new Error(pollResult.failed_error ?? 'Payment failed'),\n pollResult.failed_error,\n );\n current = applyRetryOrFail(current, classified, policy, {\n failedPatch: {\n result: {\n paymentHash: pollResult.payment_hash,\n status: pollResult.status,\n fee: pollResult.fee,\n failedError: pollResult.failed_error,\n },\n },\n machine: paymentStateMachine,\n retryEvent: 'payment_failed_retryable',\n failEvent: 'payment_failed_permanent',\n });\n yield current;\n continue;\n }\n\n // Still in-flight — wait and poll again\n await sleep(POLL_INTERVAL_MS, signal);\n if (signal.aborted) {\n current = transitionJobState(current, paymentStateMachine, 'cancel');\n yield current;\n return;\n }\n // Stay in 'inflight', loop continues\n current = { ...current, updatedAt: Date.now() };\n continue;\n } catch (err) {\n // Transient RPC error while polling — back off briefly and retry\n const classified = classifyRpcError(err);\n current = applyRetryOrFail(current, classified, policy, {\n machine: paymentStateMachine,\n retryEvent: 'payment_failed_retryable',\n failEvent: 'payment_failed_permanent',\n });\n yield current;\n continue;\n }\n }\n\n // Unknown state — should not happen if state machine is correct\n break;\n }\n}\n\nconst POLL_INTERVAL_MS = 1_500;\n","import type {\n AbandonChannelParams,\n AcceptChannelParams,\n AcceptChannelResult,\n CancelInvoiceParams,\n GetInvoiceResult,\n NewInvoiceParams,\n OpenChannelParams,\n OpenChannelResult,\n SendPaymentParams,\n SettleInvoiceParams,\n ShutdownChannelParams,\n UpdateChannelParams,\n} from '@fiber-pay/sdk';\n\n// ─── Shared Job ──────────────────────────────────────────────────────────────\n\nexport type JobType = 'payment' | 'invoice' | 'channel';\n\nexport type JobState =\n // Shared lifecycle\n | 'queued'\n | 'executing'\n | 'inflight' // payment only\n | 'waiting_retry'\n // Invoice-specific lifecycle\n | 'invoice_created'\n | 'invoice_active'\n | 'invoice_received'\n | 'invoice_settled'\n | 'invoice_expired'\n | 'invoice_cancelled'\n // Channel-specific lifecycle\n | 'channel_opening'\n | 'channel_accepting'\n | 'channel_abandoning'\n | 'channel_updating'\n | 'channel_awaiting_ready'\n | 'channel_ready'\n | 'channel_closing'\n | 'channel_closed'\n | 'succeeded'\n | 'failed'\n | 'cancelled';\n\nexport const TERMINAL_JOB_STATES = new Set<JobState>(['succeeded', 'failed', 'cancelled']);\n\nexport interface Job<TParams = unknown, TResult = unknown, TType extends JobType = JobType> {\n id: string;\n type: TType;\n state: JobState;\n params: TParams;\n result?: TResult;\n error?: ClassifiedError;\n retryCount: number;\n maxRetries: number;\n nextRetryAt?: number;\n /** For deduplication — derived from invoice payment_hash or caller-supplied */\n idempotencyKey: string;\n createdAt: number;\n updatedAt: number;\n completedAt?: number;\n}\n\n// ─── Job Events ───────────────────────────────────────────────────────────────\n\nexport type JobEventType =\n | 'created'\n | 'executing'\n | 'inflight'\n | 'invoice_created'\n | 'invoice_received'\n | 'invoice_settled'\n | 'invoice_expired'\n | 'invoice_cancelled'\n | 'channel_opening'\n | 'channel_accepting'\n | 'channel_abandoning'\n | 'channel_updating'\n | 'channel_awaiting_ready'\n | 'channel_ready'\n | 'channel_closing'\n | 'channel_closed'\n | 'retry_scheduled'\n | 'retrying'\n | 'succeeded'\n | 'failed'\n | 'cancelled';\n\nexport interface JobEvent {\n id: string;\n jobId: string;\n eventType: JobEventType;\n fromState?: JobState;\n toState?: JobState;\n data?: Record<string, unknown>;\n createdAt: number;\n}\n\n// ─── Payment Job ─────────────────────────────────────────────────────────────\n\nexport interface PaymentJobParams {\n /** Raw invoice string (if paying by invoice) */\n invoice?: string;\n /** SDK send_payment params — merged from invoice or supplied directly */\n sendPaymentParams: SendPaymentParams;\n}\n\nexport interface PaymentJobResult {\n paymentHash: string;\n /** Final Fiber payment status: Success | Failed */\n status: string;\n /** Fee in shannon (hex string from Fiber) */\n fee: string;\n failedError?: string;\n}\n\nexport type PaymentJob = Job<PaymentJobParams, PaymentJobResult, 'payment'>;\n\n// ─── Invoice Job ─────────────────────────────────────────────────────────────\n\nexport type InvoiceJobAction = 'create' | 'watch' | 'cancel' | 'settle';\n\nexport interface InvoiceJobParams {\n action: InvoiceJobAction;\n newInvoiceParams?: NewInvoiceParams;\n getInvoicePaymentHash?: `0x${string}`;\n cancelInvoiceParams?: CancelInvoiceParams;\n settleInvoiceParams?: SettleInvoiceParams;\n /** Wait for lifecycle transitions to complete before succeeding */\n waitForTerminal?: boolean;\n /** Poll interval while waiting for invoice state changes */\n pollIntervalMs?: number;\n}\n\nexport interface InvoiceJobResult {\n paymentHash?: `0x${string}`;\n invoiceAddress?: string;\n status?: GetInvoiceResult['status'];\n invoice?: GetInvoiceResult['invoice'];\n}\n\nexport type InvoiceJob = Job<InvoiceJobParams, InvoiceJobResult, 'invoice'>;\n\n// ─── Channel Job ─────────────────────────────────────────────────────────────\n\nexport type ChannelJobAction = 'open' | 'shutdown' | 'accept' | 'abandon' | 'update';\n\nexport interface ChannelJobParams {\n action: ChannelJobAction;\n openChannelParams?: OpenChannelParams;\n shutdownChannelParams?: ShutdownChannelParams;\n acceptChannelParams?: AcceptChannelParams;\n abandonChannelParams?: AbandonChannelParams;\n updateChannelParams?: UpdateChannelParams;\n /** Optional peer filter for locating channel after open */\n peerId?: string;\n /** Optional channel id to wait for */\n channelId?: `0x${string}`;\n waitForReady?: boolean;\n waitForClosed?: boolean;\n pollIntervalMs?: number;\n}\n\nexport interface ChannelJobResult {\n temporaryChannelId?: OpenChannelResult['temporary_channel_id'];\n acceptedChannelId?: AcceptChannelResult['channel_id'];\n channelId?: `0x${string}`;\n state?: string;\n}\n\nexport type ChannelJob = Job<ChannelJobParams, ChannelJobResult, 'channel'>;\n\nexport type RuntimeJob = PaymentJob | InvoiceJob | ChannelJob;\n\n// ─── Error Classification ─────────────────────────────────────────────────────\n\nexport type ErrorCategory =\n | 'no_route'\n | 'insufficient_balance'\n | 'invoice_expired'\n | 'invoice_cancelled'\n | 'peer_offline'\n | 'timeout'\n | 'temporary_failure'\n | 'amount_too_large'\n | 'invalid_payment'\n | 'unknown';\n\nexport interface ClassifiedError {\n category: ErrorCategory;\n retryable: boolean;\n message: string;\n rawError?: string;\n}\n\n// ─── Retry Policy ─────────────────────────────────────────────────────────────\n\nexport interface RetryPolicy {\n maxRetries: number;\n baseDelayMs: number;\n maxDelayMs: number;\n backoffMultiplier: number;\n jitterMs: number;\n}\n\n// ─── Job Filters ──────────────────────────────────────────────────────────────\n\nexport interface JobFilter {\n type?: JobType;\n state?: JobState | JobState[];\n limit?: number;\n offset?: number;\n}\n","import { ChannelState, type FiberRpcClient } from '@fiber-pay/sdk';\nimport type { AlertManager } from '../alerts/alert-manager.js';\nimport type { AlertPriority } from '../alerts/types.js';\nimport { diffChannels } from '../diff/channel-diff.js';\nimport type { Store } from '../storage/types.js';\nimport { BaseMonitor, type BaseMonitorHooks } from './base-monitor.js';\n\nexport interface ChannelMonitorConfig {\n intervalMs: number;\n includeClosedChannels: boolean;\n}\n\nexport class ChannelMonitor extends BaseMonitor {\n protected get name(): string {\n return 'channel-monitor';\n }\n\n private readonly client: FiberRpcClient;\n private readonly store: Store;\n private readonly alerts: AlertManager;\n private readonly config: ChannelMonitorConfig;\n\n constructor(options: {\n client: FiberRpcClient;\n store: Store;\n alerts: AlertManager;\n config: ChannelMonitorConfig;\n hooks?: BaseMonitorHooks;\n }) {\n super(options.config.intervalMs, options.hooks);\n this.client = options.client;\n this.store = options.store;\n this.alerts = options.alerts;\n this.config = options.config;\n }\n\n protected async poll(): Promise<void> {\n const previous = this.store.getChannelSnapshot();\n const result = await this.client.listChannels({\n include_closed: this.config.includeClosedChannels,\n });\n const current = result.channels;\n const changes = diffChannels(previous, current);\n\n for (const change of changes) {\n if (\n change.type === 'channel_new' &&\n change.channel.state.state_name === ChannelState.NegotiatingFunding\n ) {\n await this.alerts.emit({\n type: 'new_inbound_channel_request',\n priority: 'high',\n source: this.name,\n data: { channelId: change.channel.channel_id, channel: change.channel },\n });\n }\n\n if (change.type === 'channel_state_changed') {\n await this.alerts.emit({\n type: 'channel_state_changed',\n priority: getChannelStatePriority(change.currentState),\n source: this.name,\n data: {\n channelId: change.channel.channel_id,\n previousState: change.previousState,\n currentState: change.currentState,\n channel: change.channel,\n },\n });\n }\n\n if (\n change.type === 'channel_state_changed' &&\n change.currentState === ChannelState.ChannelReady\n ) {\n await this.alerts.emit({\n type: 'channel_became_ready',\n priority: 'medium',\n source: this.name,\n data: change,\n });\n }\n\n if (\n change.type === 'channel_state_changed' &&\n (change.currentState === ChannelState.ShuttingDown ||\n change.currentState === ChannelState.Closed)\n ) {\n await this.alerts.emit({\n type: 'channel_closing',\n priority: 'high',\n source: this.name,\n data: change,\n });\n }\n\n if (change.type === 'channel_disappeared') {\n await this.alerts.emit({\n type: 'channel_state_changed',\n priority: 'high',\n source: this.name,\n data: {\n channelId: change.channelId,\n previousState: change.previousChannel.state.state_name,\n currentState: 'DISAPPEARED',\n channel: change.previousChannel,\n },\n });\n await this.alerts.emit({\n type: 'channel_closing',\n priority: 'high',\n source: this.name,\n data: change,\n });\n }\n\n if (change.type === 'channel_balance_changed') {\n await this.alerts.emit({\n type: 'channel_balance_changed',\n priority: 'low',\n source: this.name,\n data: change,\n });\n }\n\n if (change.type === 'channel_pending_tlc_added') {\n await this.alerts.emit({\n type: 'new_pending_tlc',\n priority: 'medium',\n source: this.name,\n data: change,\n });\n }\n }\n\n this.store.setChannelSnapshot(current);\n }\n}\n\nfunction getChannelStatePriority(stateName: string): AlertPriority {\n const normalized = stateName.toUpperCase();\n const closedState = String(ChannelState.Closed).toUpperCase();\n const shuttingDownState = String(ChannelState.ShuttingDown).toUpperCase();\n const readyState = String(ChannelState.ChannelReady).toUpperCase();\n\n if (\n normalized === closedState ||\n normalized === 'CLOSED' ||\n normalized === shuttingDownState ||\n normalized === 'SHUTTING_DOWN'\n ) {\n return 'high';\n }\n\n if (normalized === readyState || normalized === 'CHANNEL_READY') {\n return 'medium';\n }\n\n return 'low';\n}\n","import type { Channel, Htlc } from '@fiber-pay/sdk';\n\nexport type ChannelDiffEvent =\n | { type: 'channel_new'; channel: Channel }\n | { type: 'channel_state_changed'; channel: Channel; previousState: string; currentState: string }\n | {\n type: 'channel_balance_changed';\n channel: Channel;\n localBalanceBefore: string;\n localBalanceAfter: string;\n remoteBalanceBefore: string;\n remoteBalanceAfter: string;\n }\n | {\n type: 'channel_pending_tlc_added';\n channel: Channel;\n previousPendingTlcCount: number;\n newPendingTlcCount: number;\n }\n | { type: 'channel_disappeared'; channelId: string; previousChannel: Channel };\n\nexport function diffChannels(previous: Channel[], current: Channel[]): ChannelDiffEvent[] {\n const events: ChannelDiffEvent[] = [];\n const prevById = new Map(previous.map((channel) => [channel.channel_id, channel]));\n const currById = new Map(current.map((channel) => [channel.channel_id, channel]));\n\n for (const [channelId, channel] of currById.entries()) {\n const previousChannel = prevById.get(channelId);\n if (!previousChannel) {\n events.push({ type: 'channel_new', channel });\n continue;\n }\n\n if (channel.state.state_name !== previousChannel.state.state_name) {\n events.push({\n type: 'channel_state_changed',\n channel,\n previousState: previousChannel.state.state_name,\n currentState: channel.state.state_name,\n });\n }\n\n if (\n channel.local_balance !== previousChannel.local_balance ||\n channel.remote_balance !== previousChannel.remote_balance\n ) {\n events.push({\n type: 'channel_balance_changed',\n channel,\n localBalanceBefore: previousChannel.local_balance,\n localBalanceAfter: channel.local_balance,\n remoteBalanceBefore: previousChannel.remote_balance,\n remoteBalanceAfter: channel.remote_balance,\n });\n }\n\n const previousPending = new Set(previousChannel.pending_tlcs.map((tlc: Htlc) => tlc.id));\n const newTlcCount = channel.pending_tlcs.filter(\n (tlc: Htlc) => !previousPending.has(tlc.id),\n ).length;\n if (newTlcCount > 0) {\n events.push({\n type: 'channel_pending_tlc_added',\n channel,\n previousPendingTlcCount: previousChannel.pending_tlcs.length,\n newPendingTlcCount: channel.pending_tlcs.length,\n });\n }\n }\n\n for (const [channelId, previousChannel] of prevById.entries()) {\n if (!currById.has(channelId)) {\n events.push({\n type: 'channel_disappeared',\n channelId,\n previousChannel,\n });\n }\n }\n\n return events;\n}\n","export interface BaseMonitorHooks {\n onCycleError?: (error: unknown, monitorName: string) => Promise<void> | void;\n onCycleSuccess?: (monitorName: string) => Promise<void> | void;\n}\n\nexport abstract class BaseMonitor {\n protected readonly intervalMs: number;\n private readonly hooks: BaseMonitorHooks;\n private timer: NodeJS.Timeout | undefined;\n private running = false;\n\n constructor(intervalMs: number, hooks: BaseMonitorHooks = {}) {\n this.intervalMs = intervalMs;\n this.hooks = hooks;\n }\n\n protected abstract get name(): string;\n\n protected abstract poll(): Promise<void>;\n\n start(): void {\n this.stop();\n void this.runOnce();\n this.timer = setInterval(() => {\n void this.runOnce();\n }, this.intervalMs);\n }\n\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = undefined;\n }\n }\n\n private async runOnce(): Promise<void> {\n if (this.running) {\n return;\n }\n\n this.running = true;\n try {\n await this.poll();\n await this.hooks.onCycleSuccess?.(this.name);\n } catch (error) {\n await this.hooks.onCycleError?.(error, this.name);\n } finally {\n this.running = false;\n }\n }\n}\n","import type { FiberRpcClient } from '@fiber-pay/sdk';\nimport type { AlertManager } from '../alerts/alert-manager.js';\nimport { BaseMonitor, type BaseMonitorHooks } from './base-monitor.js';\n\nexport interface HealthMonitorConfig {\n intervalMs: number;\n}\n\nexport class HealthMonitor extends BaseMonitor {\n protected get name(): string {\n return 'health-monitor';\n }\n\n private readonly client: FiberRpcClient;\n private readonly alerts: AlertManager;\n private isOffline = false;\n\n constructor(options: {\n client: FiberRpcClient;\n alerts: AlertManager;\n config: HealthMonitorConfig;\n hooks?: BaseMonitorHooks;\n }) {\n super(options.config.intervalMs, options.hooks);\n this.client = options.client;\n this.alerts = options.alerts;\n }\n\n protected async poll(): Promise<void> {\n let isHealthy = false;\n let failureReason: string | undefined;\n try {\n isHealthy = await this.client.ping();\n } catch (error) {\n failureReason = error instanceof Error ? error.message : String(error);\n isHealthy = false;\n }\n\n if (isHealthy && this.isOffline) {\n this.isOffline = false;\n await this.alerts.emit({\n type: 'node_online',\n priority: 'low',\n source: this.name,\n data: { message: 'Fiber node RPC recovered' },\n });\n return;\n }\n\n if (!isHealthy && !this.isOffline) {\n this.isOffline = true;\n await this.alerts.emit({\n type: 'node_offline',\n priority: 'critical',\n source: this.name,\n data: {\n message: failureReason\n ? `Fiber node ping failed: ${failureReason}`\n : 'Fiber node ping returned false',\n },\n });\n }\n }\n}\n","/**\n * Return true when the RPC error indicates the item permanently does not\n * exist on the node (e.g. \"Payment session not found\"). Callers should\n * move the tracked item to a terminal state so it stops being polled.\n */\nexport function isNotFoundError(error: unknown): boolean {\n const haystack = collectErrorText(error);\n return /not found|does not exist|no such/i.test(haystack);\n}\n\n/**\n * Determine whether an error thrown during invoice/payment tracking is\n * expected and should be silently skipped (transient connectivity blip).\n * Unexpected errors are re-thrown by callers.\n */\nexport function isExpectedTrackerError(error: unknown): boolean {\n const haystack = collectErrorText(error);\n return /temporarily unavailable|connection refused|timed out|timeout/i.test(haystack);\n}\n\nfunction collectErrorText(error: unknown): string {\n if (error === null || error === undefined) {\n return '';\n }\n\n const parts: string[] = [];\n const seen = new Set<unknown>();\n\n const walk = (value: unknown, depth: number): void => {\n if (value === null || value === undefined) {\n return;\n }\n\n if (depth > 4) {\n return;\n }\n\n if (typeof value === 'string') {\n parts.push(value);\n return;\n }\n\n if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {\n parts.push(String(value));\n return;\n }\n\n if (typeof value !== 'object') {\n return;\n }\n\n if (seen.has(value)) {\n return;\n }\n seen.add(value);\n\n if (value instanceof Error) {\n parts.push(value.message);\n const valueWithData = value as Error & { data?: unknown; cause?: unknown };\n walk(valueWithData.data, depth + 1);\n walk(valueWithData.cause, depth + 1);\n return;\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n walk(item, depth + 1);\n }\n return;\n }\n\n for (const nested of Object.values(value as Record<string, unknown>)) {\n walk(nested, depth + 1);\n }\n };\n\n walk(error, 0);\n return parts.join(' ');\n}\n","import type { CkbInvoiceStatus, FiberRpcClient } from '@fiber-pay/sdk';\nimport type { AlertManager } from '../alerts/alert-manager.js';\nimport type { Store } from '../storage/types.js';\nimport { BaseMonitor, type BaseMonitorHooks } from './base-monitor.js';\nimport { isExpectedTrackerError, isNotFoundError } from './tracker-utils.js';\n\nexport interface InvoiceTrackerConfig {\n intervalMs: number;\n completedItemTtlSeconds: number;\n}\n\nexport class InvoiceTracker extends BaseMonitor {\n protected get name(): string {\n return 'invoice-tracker';\n }\n\n private readonly client: FiberRpcClient;\n private readonly store: Store;\n private readonly alerts: AlertManager;\n private readonly config: InvoiceTrackerConfig;\n\n constructor(options: {\n client: FiberRpcClient;\n store: Store;\n alerts: AlertManager;\n config: InvoiceTrackerConfig;\n hooks?: BaseMonitorHooks;\n }) {\n super(options.config.intervalMs, options.hooks);\n this.client = options.client;\n this.store = options.store;\n this.alerts = options.alerts;\n this.config = options.config;\n }\n\n protected async poll(): Promise<void> {\n const tracked = this.store.listTrackedInvoices();\n\n for (const invoice of tracked) {\n if (isTerminalInvoiceStatusString(invoice.status)) {\n continue;\n }\n\n try {\n const next = await this.client.getInvoice({ payment_hash: invoice.paymentHash });\n const previousStatus = invoice.status;\n const currentStatus = next.status;\n\n if (currentStatus !== previousStatus) {\n this.store.updateTrackedInvoice(invoice.paymentHash, currentStatus);\n\n if (currentStatus === 'Received' || currentStatus === 'Paid') {\n await this.alerts.emit({\n type: 'incoming_payment_received',\n priority: 'high',\n source: this.name,\n data: {\n paymentHash: invoice.paymentHash,\n previousStatus,\n currentStatus,\n invoice: next,\n },\n });\n }\n\n if (currentStatus === 'Expired') {\n await this.alerts.emit({\n type: 'invoice_expired',\n priority: 'medium',\n source: this.name,\n data: {\n paymentHash: invoice.paymentHash,\n previousStatus,\n currentStatus,\n invoice: next,\n },\n });\n }\n\n if (currentStatus === 'Cancelled') {\n await this.alerts.emit({\n type: 'invoice_cancelled',\n priority: 'medium',\n source: this.name,\n data: {\n paymentHash: invoice.paymentHash,\n previousStatus,\n currentStatus,\n invoice: next,\n },\n });\n }\n }\n } catch (error) {\n if (isNotFoundError(error)) {\n this.store.updateTrackedInvoice(invoice.paymentHash, 'Cancelled');\n await this.alerts.emit({\n type: 'invoice_cancelled',\n priority: 'medium',\n source: this.name,\n data: {\n paymentHash: invoice.paymentHash,\n previousStatus: invoice.status,\n currentStatus: 'Cancelled',\n reason: 'not_found',\n },\n });\n continue;\n }\n if (isExpectedTrackerError(error)) {\n continue;\n }\n throw error;\n }\n }\n\n this.store.pruneCompleted(this.config.completedItemTtlSeconds * 1000);\n }\n}\n\nexport function isTerminalInvoiceStatus(status: CkbInvoiceStatus): boolean {\n return status === 'Cancelled' || status === 'Expired' || status === 'Paid';\n}\n\nfunction isTerminalInvoiceStatusString(status: string): boolean {\n return status === 'Cancelled' || status === 'Expired' || status === 'Paid';\n}\n","import type { FiberRpcClient } from '@fiber-pay/sdk';\nimport type { AlertManager } from '../alerts/alert-manager.js';\nimport type { Store } from '../storage/types.js';\nimport { BaseMonitor, type BaseMonitorHooks } from './base-monitor.js';\nimport { isExpectedTrackerError, isNotFoundError } from './tracker-utils.js';\n\nexport interface PaymentTrackerConfig {\n intervalMs: number;\n completedItemTtlSeconds: number;\n}\n\nexport class PaymentTracker extends BaseMonitor {\n protected get name(): string {\n return 'payment-tracker';\n }\n\n private readonly client: FiberRpcClient;\n private readonly store: Store;\n private readonly alerts: AlertManager;\n private readonly config: PaymentTrackerConfig;\n\n constructor(options: {\n client: FiberRpcClient;\n store: Store;\n alerts: AlertManager;\n config: PaymentTrackerConfig;\n hooks?: BaseMonitorHooks;\n }) {\n super(options.config.intervalMs, options.hooks);\n this.client = options.client;\n this.store = options.store;\n this.alerts = options.alerts;\n this.config = options.config;\n }\n\n protected async poll(): Promise<void> {\n const tracked = this.store.listTrackedPayments();\n\n for (const payment of tracked) {\n if (isTerminalPaymentStatus(payment.status)) {\n continue;\n }\n\n try {\n const next = await this.client.getPayment({ payment_hash: payment.paymentHash });\n const previousStatus = payment.status;\n const currentStatus = next.status;\n\n if (currentStatus !== previousStatus) {\n this.store.updateTrackedPayment(payment.paymentHash, currentStatus);\n\n if (currentStatus === 'Success') {\n await this.alerts.emit({\n type: 'outgoing_payment_completed',\n priority: 'medium',\n source: this.name,\n data: {\n paymentHash: payment.paymentHash,\n previousStatus,\n currentStatus,\n payment: next,\n },\n });\n }\n\n if (currentStatus === 'Failed') {\n await this.alerts.emit({\n type: 'outgoing_payment_failed',\n priority: 'high',\n source: this.name,\n data: {\n paymentHash: payment.paymentHash,\n previousStatus,\n currentStatus,\n payment: next,\n },\n });\n }\n }\n } catch (error) {\n if (isNotFoundError(error)) {\n this.store.updateTrackedPayment(payment.paymentHash, 'Failed');\n await this.alerts.emit({\n type: 'outgoing_payment_failed',\n priority: 'high',\n source: this.name,\n data: {\n paymentHash: payment.paymentHash,\n previousStatus: payment.status,\n currentStatus: 'Failed',\n reason: 'not_found',\n },\n });\n continue;\n }\n if (isExpectedTrackerError(error)) {\n continue;\n }\n throw error;\n }\n }\n\n this.store.pruneCompleted(this.config.completedItemTtlSeconds * 1000);\n }\n}\n\nfunction isTerminalPaymentStatus(status: string): boolean {\n return status === 'Success' || status === 'Failed';\n}\n","import type { PeerInfo } from '@fiber-pay/sdk';\n\nexport type PeerDiffEvent =\n | { type: 'peer_connected'; peer: PeerInfo }\n | { type: 'peer_disconnected'; peer: PeerInfo };\n\nexport function diffPeers(previous: PeerInfo[], current: PeerInfo[]): PeerDiffEvent[] {\n const events: PeerDiffEvent[] = [];\n const prevById = new Map(previous.map((peer) => [peer.peer_id, peer]));\n const currById = new Map(current.map((peer) => [peer.peer_id, peer]));\n\n for (const [peerId, peer] of currById.entries()) {\n if (!prevById.has(peerId)) {\n events.push({ type: 'peer_connected', peer });\n }\n }\n\n for (const [peerId, peer] of prevById.entries()) {\n if (!currById.has(peerId)) {\n events.push({ type: 'peer_disconnected', peer });\n }\n }\n\n return events;\n}\n","import type { FiberRpcClient } from '@fiber-pay/sdk';\nimport type { AlertManager } from '../alerts/alert-manager.js';\nimport { diffPeers } from '../diff/peer-diff.js';\nimport type { Store } from '../storage/types.js';\nimport { BaseMonitor, type BaseMonitorHooks } from './base-monitor.js';\n\nexport interface PeerMonitorConfig {\n intervalMs: number;\n}\n\nexport class PeerMonitor extends BaseMonitor {\n protected get name(): string {\n return 'peer-monitor';\n }\n\n private readonly client: FiberRpcClient;\n private readonly store: Store;\n private readonly alerts: AlertManager;\n\n constructor(options: {\n client: FiberRpcClient;\n store: Store;\n alerts: AlertManager;\n config: PeerMonitorConfig;\n hooks?: BaseMonitorHooks;\n }) {\n super(options.config.intervalMs, options.hooks);\n this.client = options.client;\n this.store = options.store;\n this.alerts = options.alerts;\n }\n\n protected async poll(): Promise<void> {\n const previous = this.store.getPeerSnapshot();\n const result = await this.client.listPeers();\n const current = result.peers;\n\n const changes = diffPeers(previous, current);\n for (const change of changes) {\n if (change.type === 'peer_connected') {\n await this.alerts.emit({\n type: 'peer_connected',\n priority: 'low',\n source: this.name,\n data: { peer: change.peer },\n });\n }\n if (change.type === 'peer_disconnected') {\n await this.alerts.emit({\n type: 'peer_disconnected',\n priority: 'low',\n source: this.name,\n data: { peer: change.peer },\n });\n }\n }\n\n this.store.setPeerSnapshot(current);\n }\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport http from 'node:http';\nimport { parseListenAddress } from '../config.js';\nimport { isPayloadTooLargeError, readRawBody } from './body.js';\nimport { CORS_HEADERS, CORS_PREFLIGHT_HEADERS, writeJson } from './http-utils.js';\nimport { handleDeleteEndpoint, handleJobPostEndpoint } from './job-routes.js';\nimport { tryParseJson } from './json.js';\nimport { captureTrackedHashes, collectJsonRpcMethods } from './jsonrpc-tracking.js';\nimport { handleMonitorEndpoint } from './monitor-routes.js';\nimport type { RpcMonitorProxyConfig, RpcMonitorProxyDeps } from './types.js';\n\nexport type { RpcMonitorProxyConfig, RpcMonitorProxyDeps, RpcMonitorProxyStatus } from './types.js';\n\nexport class RpcMonitorProxy {\n private readonly config: RpcMonitorProxyConfig;\n private readonly deps: RpcMonitorProxyDeps;\n private server: http.Server | undefined;\n\n constructor(config: RpcMonitorProxyConfig, deps: RpcMonitorProxyDeps) {\n this.config = config;\n this.deps = deps;\n }\n\n async start(): Promise<void> {\n if (this.server) {\n return;\n }\n\n assertNoProxySelfLoop(this.config.listen, this.config.targetUrl);\n\n this.server = http.createServer((req, res) => {\n void this.handleRequest(req, res);\n });\n\n const { host, port } = parseListenAddress(this.config.listen);\n\n await new Promise<void>((resolve, reject) => {\n this.server?.once('error', reject);\n this.server?.listen(port, host, () => {\n this.server?.off('error', reject);\n resolve();\n });\n });\n }\n\n async stop(): Promise<void> {\n if (!this.server) {\n return;\n }\n\n const server = this.server;\n this.server = undefined;\n\n await new Promise<void>((resolve) => {\n server.close(() => resolve());\n });\n }\n\n private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n if (req.method === 'OPTIONS') {\n res.writeHead(204, CORS_PREFLIGHT_HEADERS);\n res.end();\n return;\n }\n\n if (req.method === 'GET') {\n handleMonitorEndpoint(req, res, this.deps);\n return;\n }\n\n if (req.method === 'DELETE') {\n await handleDeleteEndpoint(req, res, this.deps);\n return;\n }\n\n if (req.method !== 'POST') {\n writeJson(res, 405, { error: 'Method not allowed' });\n return;\n }\n\n const url = new URL(req.url ?? '/', 'http://127.0.0.1');\n if (url.pathname.startsWith('/jobs/')) {\n await handleJobPostEndpoint(url.pathname, req, res, this.deps);\n return;\n }\n\n let requestBody: Buffer;\n try {\n requestBody = await readRawBody(req);\n } catch (error) {\n if (isPayloadTooLargeError(error)) {\n writeJson(res, 413, { error: 'Request body too large' });\n return;\n }\n writeJson(res, 400, { error: 'Failed to read request body' });\n return;\n }\n\n const requestJson = tryParseJson(requestBody.toString('utf-8'));\n const methodById = collectJsonRpcMethods(requestJson);\n\n let responseText = '';\n let responseStatus = 500;\n let responseHeaders = new Headers();\n\n try {\n const response = await fetch(this.config.targetUrl, {\n method: 'POST',\n headers: {\n 'content-type': req.headers['content-type'] ?? 'application/json',\n ...(req.headers.authorization ? { authorization: req.headers.authorization } : {}),\n },\n body: requestBody,\n });\n\n responseStatus = response.status;\n responseHeaders = response.headers;\n responseText = await response.text();\n\n const responseJson = tryParseJson(responseText);\n captureTrackedHashes(methodById, responseJson, {\n onInvoiceTracked: this.deps.onInvoiceTracked,\n onPaymentTracked: this.deps.onPaymentTracked,\n });\n } catch (error) {\n writeJson(res, 502, { error: `Proxy request failed: ${String(error)}` });\n return;\n }\n\n const contentType = responseHeaders.get('content-type') ?? 'application/json';\n res.writeHead(responseStatus, {\n 'content-type': contentType,\n ...CORS_HEADERS,\n });\n res.end(responseText);\n }\n}\n\nfunction assertNoProxySelfLoop(listen: string, targetUrl: string): void {\n const { host, port } = parseListenAddress(listen);\n\n let parsed: URL;\n try {\n parsed = new URL(targetUrl);\n } catch {\n throw new Error(`Invalid proxy targetUrl: ${targetUrl}`);\n }\n\n const targetHost = normalizeHost(parsed.hostname);\n const listenHost = normalizeHost(host);\n const targetPort = parsed.port || (parsed.protocol === 'https:' ? '443' : '80');\n\n if (targetHost === listenHost && targetPort === String(port)) {\n throw new Error(\n `Invalid proxy configuration: targetUrl (${targetUrl}) points to proxy listen address (${listen})`,\n );\n }\n}\n\nfunction normalizeHost(host: string): string {\n if (host === 'localhost' || host === '::1') {\n return '127.0.0.1';\n }\n return host;\n}\n","import type { IncomingMessage } from 'node:http';\n\nconst MAX_REQUEST_BODY_BYTES = 1024 * 1024;\n\nexport async function readRawBody(req: IncomingMessage): Promise<Buffer> {\n const chunks: Buffer[] = [];\n let totalBytes = 0;\n\n return await new Promise<Buffer>((resolve, reject) => {\n req.on('data', (chunk: Buffer) => {\n totalBytes += chunk.length;\n if (totalBytes > MAX_REQUEST_BODY_BYTES) {\n req.destroy();\n reject(new PayloadTooLargeError());\n return;\n }\n chunks.push(chunk);\n });\n req.on('end', () => resolve(Buffer.concat(chunks)));\n req.on('error', reject);\n });\n}\n\nclass PayloadTooLargeError extends Error {\n constructor() {\n super('Payload too large');\n this.name = 'PayloadTooLargeError';\n }\n}\n\nexport function isPayloadTooLargeError(error: unknown): boolean {\n return error instanceof PayloadTooLargeError;\n}\n","import type { ServerResponse } from 'node:http';\n\nexport const CORS_HEADERS = {\n 'access-control-allow-origin': '*',\n 'access-control-allow-methods': 'GET,POST,DELETE,OPTIONS',\n 'access-control-allow-headers': 'Content-Type, Authorization',\n};\n\nexport const CORS_PREFLIGHT_HEADERS = {\n ...CORS_HEADERS,\n 'access-control-max-age': '86400',\n};\n\nexport function writeJson(res: ServerResponse, status: number, value: unknown): void {\n res.writeHead(status, {\n 'content-type': 'application/json',\n ...CORS_HEADERS,\n });\n res.end(JSON.stringify(value));\n}\n\nexport function parseOptionalPositiveInteger(value: string | null): number | undefined {\n if (!value) {\n return undefined;\n }\n\n const parsed = Number(value);\n if (!Number.isInteger(parsed) || parsed <= 0) {\n return undefined;\n }\n\n return parsed;\n}\n","export function tryParseJson(text: string): unknown {\n try {\n return JSON.parse(text);\n } catch {\n return undefined;\n }\n}\n\nexport function isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { ChannelJobParams, InvoiceJobParams, PaymentJobParams } from '../jobs/types.js';\nimport { isPayloadTooLargeError, readRawBody } from './body.js';\nimport { writeJson } from './http-utils.js';\nimport { isObject, tryParseJson } from './json.js';\nimport type { RpcMonitorProxyDeps } from './types.js';\n\nexport async function handleJobPostEndpoint(\n pathname: string,\n req: IncomingMessage,\n res: ServerResponse,\n deps: RpcMonitorProxyDeps,\n): Promise<void> {\n let rawBody: Buffer;\n try {\n rawBody = await readRawBody(req);\n } catch (error) {\n if (isPayloadTooLargeError(error)) {\n writeJson(res, 413, { error: 'Request body too large' });\n return;\n }\n writeJson(res, 400, { error: 'Failed to read request body' });\n return;\n }\n\n const body = tryParseJson(rawBody.toString('utf-8'));\n if (!isObject(body)) {\n writeJson(res, 400, { error: 'Invalid JSON body' });\n return;\n }\n\n if (pathname === '/jobs/payment') {\n if (!deps.createPaymentJob) {\n writeJson(res, 404, { error: 'Jobs are not enabled in runtime config' });\n return;\n }\n const params = body.params as PaymentJobParams | undefined;\n if (!params) {\n writeJson(res, 400, { error: 'Missing params for payment job' });\n return;\n }\n const options = body.options as { idempotencyKey?: string; maxRetries?: number } | undefined;\n const job = await deps.createPaymentJob(params, options);\n writeJson(res, 200, job);\n return;\n }\n\n if (pathname === '/jobs/invoice') {\n if (!deps.createInvoiceJob) {\n writeJson(res, 404, { error: 'Jobs are not enabled in runtime config' });\n return;\n }\n const params = body.params as InvoiceJobParams | undefined;\n if (!params) {\n writeJson(res, 400, { error: 'Missing params for invoice job' });\n return;\n }\n const options = body.options as { idempotencyKey?: string; maxRetries?: number } | undefined;\n const job = await deps.createInvoiceJob(params, options);\n writeJson(res, 200, job);\n return;\n }\n\n if (pathname === '/jobs/channel') {\n if (!deps.createChannelJob) {\n writeJson(res, 404, { error: 'Jobs are not enabled in runtime config' });\n return;\n }\n const params = body.params as ChannelJobParams | undefined;\n if (!params) {\n writeJson(res, 400, { error: 'Missing params for channel job' });\n return;\n }\n const options = body.options as\n | { idempotencyKey?: string; maxRetries?: number; reuseTerminal?: boolean }\n | undefined;\n const job = await deps.createChannelJob(params, options);\n writeJson(res, 200, job);\n return;\n }\n\n writeJson(res, 404, { error: 'Unknown jobs endpoint' });\n}\n\nexport async function handleDeleteEndpoint(\n req: IncomingMessage,\n res: ServerResponse,\n deps: RpcMonitorProxyDeps,\n): Promise<void> {\n const url = new URL(req.url ?? '/', 'http://127.0.0.1');\n if (!url.pathname.startsWith('/jobs/')) {\n writeJson(res, 405, { error: 'Method not allowed' });\n return;\n }\n if (!deps.cancelJob) {\n writeJson(res, 404, { error: 'Jobs are not enabled in runtime config' });\n return;\n }\n\n const segments = url.pathname.split('/').filter(Boolean);\n const [, id] = segments;\n if (!id) {\n writeJson(res, 400, { error: 'Missing job id' });\n return;\n }\n\n try {\n deps.cancelJob(id);\n writeJson(res, 204, {});\n } catch (error) {\n writeJson(res, 404, { error: String(error) });\n }\n}\n","import { isObject } from './json.js';\n\ninterface JsonRpcMessage {\n id?: string | number;\n method?: string;\n params?: unknown[];\n result?: unknown;\n error?: unknown;\n}\n\nexport interface RequestMeta {\n method: string;\n dryRun: boolean;\n}\n\nexport function collectJsonRpcMethods(requestBody: unknown): Map<string | number, RequestMeta> {\n const methods = new Map<string | number, RequestMeta>();\n for (const item of normalizeJsonRpcRequest(requestBody)) {\n if (item.id !== undefined && typeof item.method === 'string') {\n const dryRun = isDryRunRequest(item);\n methods.set(item.id, { method: item.method, dryRun });\n }\n }\n return methods;\n}\n\nexport function captureTrackedHashes(\n methodById: Map<string | number, RequestMeta>,\n responseBody: unknown,\n handlers: {\n onInvoiceTracked: (paymentHash: string) => void;\n onPaymentTracked: (paymentHash: string) => void;\n },\n): void {\n const responses = normalizeJsonRpcResponse(responseBody);\n\n for (const message of responses) {\n if (message.error || message.id === undefined) {\n continue;\n }\n const meta = methodById.get(message.id);\n if (!meta) {\n continue;\n }\n\n if (meta.method === 'new_invoice') {\n const paymentHash = extractInvoicePaymentHash(message.result);\n if (paymentHash) {\n handlers.onInvoiceTracked(paymentHash);\n }\n }\n\n // Skip tracking dry-run payments — the node never persists them,\n // so the tracker would poll getPayment forever.\n if (meta.method === 'send_payment' && !meta.dryRun) {\n const paymentHash = extractPaymentHash(message.result);\n if (paymentHash) {\n handlers.onPaymentTracked(paymentHash);\n }\n }\n }\n}\n\nfunction normalizeJsonRpcRequest(body: unknown): JsonRpcMessage[] {\n if (!body) {\n return [];\n }\n if (Array.isArray(body)) {\n return body.filter(isObject) as JsonRpcMessage[];\n }\n if (isObject(body)) {\n return [body as JsonRpcMessage];\n }\n return [];\n}\n\nfunction normalizeJsonRpcResponse(body: unknown): JsonRpcMessage[] {\n if (!body) {\n return [];\n }\n if (Array.isArray(body)) {\n return body.filter(isObject) as JsonRpcMessage[];\n }\n if (isObject(body)) {\n return [body as JsonRpcMessage];\n }\n return [];\n}\n\nfunction extractInvoicePaymentHash(result: unknown): string | undefined {\n if (!isObject(result)) {\n return undefined;\n }\n\n const invoice = result.invoice;\n if (!isObject(invoice)) {\n return undefined;\n }\n\n const data = invoice.data;\n if (!isObject(data)) {\n return undefined;\n }\n\n return typeof data.payment_hash === 'string' ? data.payment_hash : undefined;\n}\n\nfunction extractPaymentHash(result: unknown): string | undefined {\n if (!isObject(result)) {\n return undefined;\n }\n return typeof result.payment_hash === 'string' ? result.payment_hash : undefined;\n}\n\nfunction isDryRunRequest(message: JsonRpcMessage): boolean {\n if (!Array.isArray(message.params) || message.params.length === 0) {\n return false;\n }\n const firstParam = message.params[0];\n return isObject(firstParam) && firstParam.dry_run === true;\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport { isAlertPriority, isAlertType } from '../alerts/types.js';\nimport type { JobFilter } from '../jobs/types.js';\nimport { parseOptionalPositiveInteger, writeJson } from './http-utils.js';\nimport type { RpcMonitorProxyDeps } from './types.js';\n\nexport function handleMonitorEndpoint(\n req: IncomingMessage,\n res: ServerResponse,\n deps: RpcMonitorProxyDeps,\n): void {\n const url = new URL(req.url ?? '/', 'http://127.0.0.1');\n\n if (url.pathname === '/jobs') {\n if (!deps.listJobs) {\n writeJson(res, 404, { error: 'Jobs are not enabled in runtime config' });\n return;\n }\n const state = url.searchParams.get('state') ?? undefined;\n const type = url.searchParams.get('type') as JobFilter['type'] | null;\n const limit = parseOptionalPositiveInteger(url.searchParams.get('limit'));\n const offset = parseOptionalPositiveInteger(url.searchParams.get('offset'));\n writeJson(res, 200, {\n jobs: deps.listJobs({\n state: state as JobFilter['state'],\n type: type ?? undefined,\n limit,\n offset,\n }),\n });\n return;\n }\n\n if (url.pathname.startsWith('/jobs/')) {\n if (!deps.getJob) {\n writeJson(res, 404, { error: 'Jobs are not enabled in runtime config' });\n return;\n }\n\n const segments = url.pathname.split('/').filter(Boolean);\n const [, id, sub] = segments;\n if (!id) {\n writeJson(res, 400, { error: 'Missing job id' });\n return;\n }\n\n if (sub === 'events') {\n if (!deps.listJobEvents) {\n writeJson(res, 404, { error: 'Job events not available' });\n return;\n }\n writeJson(res, 200, { events: deps.listJobEvents(id) });\n return;\n }\n\n const job = deps.getJob(id);\n if (!job) {\n writeJson(res, 404, { error: 'Job not found' });\n return;\n }\n writeJson(res, 200, job);\n return;\n }\n\n if (url.pathname === '/monitor/list_tracked_invoices') {\n writeJson(res, 200, { invoices: deps.listTrackedInvoices() });\n return;\n }\n\n if (url.pathname === '/monitor/list_tracked_payments') {\n writeJson(res, 200, { payments: deps.listTrackedPayments() });\n return;\n }\n\n if (url.pathname === '/monitor/list_alerts') {\n const limitRaw = url.searchParams.get('limit');\n const minPriorityRaw = url.searchParams.get('min_priority');\n const typeRaw = url.searchParams.get('type');\n const sourceRaw = url.searchParams.get('source');\n\n const limit = parseOptionalPositiveInteger(limitRaw);\n if (limitRaw !== null && limit === undefined) {\n writeJson(res, 400, {\n error: 'Invalid query parameter: limit must be a positive integer',\n });\n return;\n }\n\n if (minPriorityRaw && !isAlertPriority(minPriorityRaw)) {\n writeJson(res, 400, {\n error: 'Invalid query parameter: min_priority must be one of critical|high|medium|low',\n });\n return;\n }\n\n if (typeRaw && !isAlertType(typeRaw)) {\n writeJson(res, 400, {\n error: 'Invalid query parameter: type is not a known alert type',\n });\n return;\n }\n\n const minPriority =\n minPriorityRaw && isAlertPriority(minPriorityRaw) ? minPriorityRaw : undefined;\n const type = typeRaw && isAlertType(typeRaw) ? typeRaw : undefined;\n\n writeJson(res, 200, {\n alerts: deps.listAlerts({\n limit,\n minPriority,\n type,\n source: sourceRaw ?? undefined,\n }),\n });\n return;\n }\n\n if (url.pathname === '/monitor/status') {\n writeJson(res, 200, deps.getStatus());\n return;\n }\n\n writeJson(res, 404, { error: 'Not found' });\n}\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport type { Channel, PaymentHash, PeerInfo } from '@fiber-pay/sdk';\nimport {\n type Alert,\n type AlertFilter,\n alertPriorityOrder,\n type TrackedInvoiceState,\n type TrackedPaymentState,\n} from '../alerts/types.js';\nimport type { PersistedRuntimeState, Store } from './types.js';\n\nexport interface MemoryStoreConfig {\n stateFilePath: string;\n flushIntervalMs: number;\n maxAlertHistory: number;\n}\n\nfunction nowMs(): number {\n return Date.now();\n}\n\nfunction toRecord<T extends { paymentHash: PaymentHash }>(\n items: Map<PaymentHash, T>,\n): Record<PaymentHash, T> {\n return Object.fromEntries(items.entries()) as Record<PaymentHash, T>;\n}\n\nexport class MemoryStore implements Store {\n private readonly config: MemoryStoreConfig;\n private channelSnapshot: Channel[] = [];\n private peerSnapshot: PeerInfo[] = [];\n private trackedInvoices = new Map<PaymentHash, TrackedInvoiceState>();\n private trackedPayments = new Map<PaymentHash, TrackedPaymentState>();\n private alerts: Alert[] = [];\n private flushTimer: NodeJS.Timeout | undefined;\n\n constructor(config: MemoryStoreConfig) {\n this.config = config;\n }\n\n async load(): Promise<void> {\n try {\n const raw = await readFile(this.config.stateFilePath, 'utf-8');\n const state = JSON.parse(raw) as PersistedRuntimeState;\n this.channelSnapshot = state.channels ?? [];\n this.peerSnapshot = state.peers ?? [];\n this.trackedInvoices = new Map(Object.entries(state.trackedInvoices ?? {})) as Map<\n PaymentHash,\n TrackedInvoiceState\n >;\n this.trackedPayments = new Map(Object.entries(state.trackedPayments ?? {})) as Map<\n PaymentHash,\n TrackedPaymentState\n >;\n this.alerts = state.alerts ?? [];\n } catch {\n this.channelSnapshot = [];\n this.peerSnapshot = [];\n this.trackedInvoices.clear();\n this.trackedPayments.clear();\n this.alerts = [];\n }\n }\n\n async flush(): Promise<void> {\n const state: PersistedRuntimeState = {\n channels: this.channelSnapshot,\n peers: this.peerSnapshot,\n trackedInvoices: toRecord(this.trackedInvoices),\n trackedPayments: toRecord(this.trackedPayments),\n alerts: this.alerts,\n };\n await mkdir(dirname(this.config.stateFilePath), { recursive: true });\n await writeFile(this.config.stateFilePath, JSON.stringify(state, null, 2), 'utf-8');\n }\n\n startAutoFlush(): void {\n this.stopAutoFlush();\n this.flushTimer = setInterval(() => {\n void this.flush();\n }, this.config.flushIntervalMs);\n }\n\n stopAutoFlush(): void {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n this.flushTimer = undefined;\n }\n }\n\n pruneCompleted(ttlMs: number): void {\n const now = nowMs();\n for (const [hash, entry] of this.trackedInvoices.entries()) {\n if (entry.completedAt && now - entry.completedAt >= ttlMs) {\n this.trackedInvoices.delete(hash);\n }\n }\n for (const [hash, entry] of this.trackedPayments.entries()) {\n if (entry.completedAt && now - entry.completedAt >= ttlMs) {\n this.trackedPayments.delete(hash);\n }\n }\n }\n\n getChannelSnapshot(): Channel[] {\n return this.channelSnapshot;\n }\n\n setChannelSnapshot(channels: Channel[]): void {\n this.channelSnapshot = channels;\n }\n\n getPeerSnapshot(): PeerInfo[] {\n return this.peerSnapshot;\n }\n\n setPeerSnapshot(peers: PeerInfo[]): void {\n this.peerSnapshot = peers;\n }\n\n addTrackedInvoice(hash: PaymentHash, status = 'Open'): void {\n const existing = this.trackedInvoices.get(hash);\n if (existing) return;\n const now = nowMs();\n this.trackedInvoices.set(hash, {\n paymentHash: hash,\n status,\n trackedAt: now,\n updatedAt: now,\n });\n }\n\n listTrackedInvoices(): TrackedInvoiceState[] {\n return [...this.trackedInvoices.values()];\n }\n\n getTrackedInvoice(hash: PaymentHash): TrackedInvoiceState | undefined {\n return this.trackedInvoices.get(hash);\n }\n\n updateTrackedInvoice(hash: PaymentHash, status: string): void {\n const now = nowMs();\n const existing = this.trackedInvoices.get(hash);\n const next: TrackedInvoiceState = existing\n ? {\n ...existing,\n status,\n updatedAt: now,\n completedAt: isTerminalInvoiceStatus(status) ? (existing.completedAt ?? now) : undefined,\n }\n : {\n paymentHash: hash,\n status,\n trackedAt: now,\n updatedAt: now,\n completedAt: isTerminalInvoiceStatus(status) ? now : undefined,\n };\n this.trackedInvoices.set(hash, next);\n }\n\n addTrackedPayment(hash: PaymentHash, status = 'Created'): void {\n const existing = this.trackedPayments.get(hash);\n if (existing) return;\n const now = nowMs();\n this.trackedPayments.set(hash, {\n paymentHash: hash,\n status,\n trackedAt: now,\n updatedAt: now,\n });\n }\n\n listTrackedPayments(): TrackedPaymentState[] {\n return [...this.trackedPayments.values()];\n }\n\n getTrackedPayment(hash: PaymentHash): TrackedPaymentState | undefined {\n return this.trackedPayments.get(hash);\n }\n\n updateTrackedPayment(hash: PaymentHash, status: string): void {\n const now = nowMs();\n const existing = this.trackedPayments.get(hash);\n const next: TrackedPaymentState = existing\n ? {\n ...existing,\n status,\n updatedAt: now,\n completedAt: isTerminalPaymentStatus(status) ? (existing.completedAt ?? now) : undefined,\n }\n : {\n paymentHash: hash,\n status,\n trackedAt: now,\n updatedAt: now,\n completedAt: isTerminalPaymentStatus(status) ? now : undefined,\n };\n this.trackedPayments.set(hash, next);\n }\n\n addAlert(alert: Alert): void {\n this.alerts.push(alert);\n if (this.alerts.length > this.config.maxAlertHistory) {\n this.alerts.splice(0, this.alerts.length - this.config.maxAlertHistory);\n }\n }\n\n listAlerts(filters?: AlertFilter): Alert[] {\n const minPriority = filters?.minPriority;\n const type = filters?.type;\n const source = filters?.source;\n const limit = filters?.limit;\n\n let alerts = this.alerts;\n\n if (minPriority) {\n const minRank = alertPriorityOrder[minPriority];\n alerts = alerts.filter((alert) => alertPriorityOrder[alert.priority] >= minRank);\n }\n\n if (type) {\n alerts = alerts.filter((alert) => alert.type === type);\n }\n\n if (source) {\n alerts = alerts.filter((alert) => alert.source === source);\n }\n\n if (!limit || limit <= 0) {\n return [...alerts];\n }\n\n return alerts.slice(-limit);\n }\n}\n\nfunction isTerminalInvoiceStatus(status: string): boolean {\n return status === 'Paid' || status === 'Cancelled' || status === 'Expired';\n}\n\nfunction isTerminalPaymentStatus(status: string): boolean {\n return status === 'Success' || status === 'Failed';\n}\n","import { randomUUID } from 'node:crypto';\nimport { mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport Database from 'better-sqlite3';\nimport type { Job, JobEvent, JobEventType, JobFilter, JobState, JobType } from '../jobs/types.js';\n\n// ─── Migrations ───────────────────────────────────────────────────────────────\n\nconst MIGRATIONS: Array<{ version: number; sql: string }> = [\n {\n version: 1,\n sql: `\n CREATE TABLE IF NOT EXISTS jobs (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL,\n state TEXT NOT NULL,\n params TEXT NOT NULL,\n result TEXT,\n error TEXT,\n retry_count INTEGER NOT NULL DEFAULT 0,\n max_retries INTEGER NOT NULL DEFAULT 3,\n next_retry_at INTEGER,\n idempotency_key TEXT NOT NULL UNIQUE,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n completed_at INTEGER\n );\n\n CREATE INDEX IF NOT EXISTS idx_jobs_state ON jobs(state);\n CREATE INDEX IF NOT EXISTS idx_jobs_type ON jobs(type);\n CREATE INDEX IF NOT EXISTS idx_jobs_next_retry_at ON jobs(next_retry_at);\n\n CREATE TABLE IF NOT EXISTS job_events (\n id TEXT PRIMARY KEY,\n job_id TEXT NOT NULL REFERENCES jobs(id) ON DELETE CASCADE,\n event_type TEXT NOT NULL,\n from_state TEXT,\n to_state TEXT,\n data TEXT,\n created_at INTEGER NOT NULL\n );\n\n CREATE INDEX IF NOT EXISTS idx_job_events_job_id ON job_events(job_id);\n `,\n },\n];\n\n// ─── SqliteJobStore ───────────────────────────────────────────────────────────\n\nexport class SqliteJobStore {\n private readonly db: Database.Database;\n\n constructor(dbPath: string) {\n mkdirSync(dirname(dbPath), { recursive: true });\n this.db = new Database(dbPath);\n this.db.pragma('journal_mode = WAL');\n this.db.pragma('foreign_keys = ON');\n this.runMigrations();\n }\n\n // ─── Migrations ─────────────────────────────────────────────────────────────\n\n private runMigrations(): void {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS schema_migrations (\n version INTEGER PRIMARY KEY,\n applied_at INTEGER NOT NULL\n );\n `);\n\n const applied = new Set<number>(\n (this.db.prepare('SELECT version FROM schema_migrations').all() as { version: number }[]).map(\n (r) => r.version,\n ),\n );\n\n for (const migration of MIGRATIONS) {\n if (!applied.has(migration.version)) {\n this.db.transaction(() => {\n this.db.exec(migration.sql);\n this.db\n .prepare('INSERT INTO schema_migrations (version, applied_at) VALUES (?, ?)')\n .run(migration.version, Date.now());\n })();\n }\n }\n }\n\n // ─── Job CRUD ────────────────────────────────────────────────────────────────\n\n createJob<P, R>(job: Omit<Job<P, R>, 'id' | 'createdAt' | 'updatedAt'>): Job<P, R> {\n const now = Date.now();\n const full: Job<P, R> = {\n ...job,\n id: randomUUID(),\n createdAt: now,\n updatedAt: now,\n };\n\n this.db\n .prepare(\n `INSERT INTO jobs\n (id, type, state, params, result, error, retry_count, max_retries,\n next_retry_at, idempotency_key, created_at, updated_at, completed_at)\n VALUES\n (@id, @type, @state, @params, @result, @error, @retry_count, @max_retries,\n @next_retry_at, @idempotency_key, @created_at, @updated_at, @completed_at)`,\n )\n .run({\n id: full.id,\n type: full.type,\n state: full.state,\n params: JSON.stringify(full.params),\n result: full.result !== undefined ? JSON.stringify(full.result) : null,\n error: full.error !== undefined ? JSON.stringify(full.error) : null,\n retry_count: full.retryCount,\n max_retries: full.maxRetries,\n next_retry_at: full.nextRetryAt ?? null,\n idempotency_key: full.idempotencyKey,\n created_at: full.createdAt,\n updated_at: full.updatedAt,\n completed_at: full.completedAt ?? null,\n });\n\n return full;\n }\n\n updateJob<P, R>(id: string, updates: Partial<Job<P, R>>): Job<P, R> {\n const existing = this.getJob<P, R>(id);\n if (!existing) throw new Error(`Job not found: ${id}`);\n\n const now = Date.now();\n const merged: Job<P, R> = { ...existing, ...updates, updatedAt: now };\n\n this.db\n .prepare(\n `UPDATE jobs SET\n state = @state,\n params = @params,\n result = @result,\n error = @error,\n retry_count = @retry_count,\n next_retry_at = @next_retry_at,\n updated_at = @updated_at,\n completed_at = @completed_at\n WHERE id = @id`,\n )\n .run({\n id: merged.id,\n state: merged.state,\n params: JSON.stringify(merged.params),\n result: merged.result !== undefined ? JSON.stringify(merged.result) : null,\n error: merged.error !== undefined ? JSON.stringify(merged.error) : null,\n retry_count: merged.retryCount,\n next_retry_at: merged.nextRetryAt ?? null,\n updated_at: merged.updatedAt,\n completed_at: merged.completedAt ?? null,\n });\n\n return merged;\n }\n\n getJob<P = unknown, R = unknown>(id: string): Job<P, R> | undefined {\n const row = this.db.prepare('SELECT * FROM jobs WHERE id = ?').get(id) as DbRow | undefined;\n return row ? this.rowToJob<P, R>(row) : undefined;\n }\n\n getJobByIdempotencyKey<P = unknown, R = unknown>(key: string): Job<P, R> | undefined {\n const row = this.db.prepare('SELECT * FROM jobs WHERE idempotency_key = ?').get(key) as\n | DbRow\n | undefined;\n return row ? this.rowToJob<P, R>(row) : undefined;\n }\n\n listJobs<P = unknown, R = unknown>(filter: JobFilter = {}): Job<P, R>[] {\n const conditions: string[] = [];\n const params: Record<string, unknown> = {};\n\n if (filter.type) {\n conditions.push('type = @type');\n params.type = filter.type;\n }\n if (filter.state) {\n const states = Array.isArray(filter.state) ? filter.state : [filter.state];\n const placeholders = states.map((_, i) => `@state_${i}`).join(', ');\n conditions.push(`state IN (${placeholders})`);\n for (const [i, s] of states.entries()) {\n params[`state_${i}`] = s;\n }\n }\n\n const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';\n const limit = filter.limit ? `LIMIT @limit` : '';\n const offset = filter.offset ? `OFFSET @offset` : '';\n\n if (filter.limit) params.limit = filter.limit;\n if (filter.offset) params.offset = filter.offset;\n\n const rows = this.db\n .prepare(`SELECT * FROM jobs ${where} ORDER BY created_at DESC ${limit} ${offset}`)\n .all(params) as DbRow[];\n\n return rows.map((r) => this.rowToJob<P, R>(r));\n }\n\n deleteJob(id: string): void {\n this.db.prepare('DELETE FROM jobs WHERE id = ?').run(id);\n }\n\n /** Return jobs that are ready to be retried right now. */\n getRetryableJobs<P = unknown, R = unknown>(now = Date.now()): Job<P, R>[] {\n const rows = this.db\n .prepare(\n `SELECT * FROM jobs\n WHERE state = 'waiting_retry' AND next_retry_at <= @now\n ORDER BY next_retry_at ASC`,\n )\n .all({ now }) as DbRow[];\n return rows.map((r) => this.rowToJob<P, R>(r));\n }\n\n /** Return jobs in non-terminal states (for recovery after daemon restart). */\n getInProgressJobs<P = unknown, R = unknown>(): Job<P, R>[] {\n const rows = this.db\n .prepare(\n `SELECT * FROM jobs\n WHERE state IN (\n 'queued',\n 'executing',\n 'inflight',\n 'waiting_retry',\n 'invoice_created',\n 'invoice_active',\n 'invoice_received',\n 'channel_opening',\n 'channel_accepting',\n 'channel_abandoning',\n 'channel_updating',\n 'channel_awaiting_ready',\n 'channel_closing'\n )\n ORDER BY created_at ASC`,\n )\n .all() as DbRow[];\n return rows.map((r) => this.rowToJob<P, R>(r));\n }\n\n // ─── Job Events ──────────────────────────────────────────────────────────────\n\n addJobEvent(\n jobId: string,\n eventType: JobEventType,\n fromState?: JobState,\n toState?: JobState,\n data?: Record<string, unknown>,\n ): JobEvent {\n const event: JobEvent = {\n id: randomUUID(),\n jobId,\n eventType,\n fromState,\n toState,\n data,\n createdAt: Date.now(),\n };\n\n this.db\n .prepare(\n `INSERT INTO job_events (id, job_id, event_type, from_state, to_state, data, created_at)\n VALUES (@id, @job_id, @event_type, @from_state, @to_state, @data, @created_at)`,\n )\n .run({\n id: event.id,\n job_id: event.jobId,\n event_type: event.eventType,\n from_state: event.fromState ?? null,\n to_state: event.toState ?? null,\n data: event.data !== undefined ? JSON.stringify(event.data) : null,\n created_at: event.createdAt,\n });\n\n return event;\n }\n\n listJobEvents(jobId: string): JobEvent[] {\n const rows = this.db\n .prepare('SELECT * FROM job_events WHERE job_id = ? ORDER BY created_at ASC')\n .all(jobId) as DbEventRow[];\n\n return rows.map((r) => ({\n id: r.id,\n jobId: r.job_id,\n eventType: r.event_type as JobEventType,\n fromState: (r.from_state as JobState | undefined) ?? undefined,\n toState: (r.to_state as JobState | undefined) ?? undefined,\n data: r.data ? (JSON.parse(r.data) as Record<string, unknown>) : undefined,\n createdAt: r.created_at,\n }));\n }\n\n // ─── Lifecycle ───────────────────────────────────────────────────────────────\n\n close(): void {\n this.db.close();\n }\n\n // ─── Private Helpers ─────────────────────────────────────────────────────────\n\n private rowToJob<P, R>(row: DbRow): Job<P, R> {\n return {\n id: row.id,\n type: row.type as JobType,\n state: row.state as JobState,\n params: JSON.parse(row.params) as P,\n result: row.result ? (JSON.parse(row.result) as R) : undefined,\n error: row.error ? JSON.parse(row.error) : undefined,\n retryCount: row.retry_count,\n maxRetries: row.max_retries,\n nextRetryAt: row.next_retry_at ?? undefined,\n idempotencyKey: row.idempotency_key,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n completedAt: row.completed_at ?? undefined,\n };\n }\n}\n\n// ─── Internal DB row type ─────────────────────────────────────────────────────\n\ninterface DbRow {\n id: string;\n type: string;\n state: string;\n params: string;\n result: string | null;\n error: string | null;\n retry_count: number;\n max_retries: number;\n next_retry_at: number | null;\n idempotency_key: string;\n created_at: number;\n updated_at: number;\n completed_at: number | null;\n}\n\ninterface DbEventRow {\n id: string;\n job_id: string;\n event_type: string;\n from_state: string | null;\n to_state: string | null;\n data: string | null;\n created_at: number;\n}\n","import type { RuntimeConfigInput } from './config.js';\nimport { FiberMonitorService } from './service.js';\n\nexport interface RuntimeBootstrap {\n service: FiberMonitorService;\n stop: () => Promise<void>;\n waitForShutdownSignal: () => Promise<NodeJS.Signals>;\n}\n\nexport async function startRuntimeService(\n configInput: RuntimeConfigInput = {},\n): Promise<RuntimeBootstrap> {\n const service = new FiberMonitorService(configInput);\n await service.start();\n\n let stopping = false;\n const stop = async (): Promise<void> => {\n if (stopping) {\n return;\n }\n stopping = true;\n await service.stop();\n };\n\n const waitForShutdownSignal = (): Promise<NodeJS.Signals> => {\n return new Promise((resolve) => {\n const onSignal = (signal: NodeJS.Signals) => {\n process.off('SIGINT', onSignal);\n process.off('SIGTERM', onSignal);\n resolve(signal);\n };\n process.on('SIGINT', onSignal);\n process.on('SIGTERM', onSignal);\n });\n };\n\n return {\n service,\n stop,\n waitForShutdownSignal,\n };\n}\n","/**\n * Payment Proof & Tracking System\n * Records, stores, and verifies payment evidence for audit trail and reconciliation\n *\n * IMPORTANT LIMITATION:\n * Fiber Network RPC currently does NOT return the payment preimage to the sender\n * after a successful payment. In standard Lightning protocol, the preimage serves\n * as cryptographic proof of payment (SHA256(preimage) === payment_hash).\n *\n * Until Fiber exposes the preimage in send_payment/get_payment responses:\n * - Payment proofs are based on RPC status (Success/Failed) rather than preimage\n * - For invoices YOU create (as receiver), preimage IS available\n * - This limitation affects sender-side proof verification only\n *\n * Tracking issue: Preimage not exposed in Fiber RPC send_payment result\n */\n\nimport { createHash } from 'node:crypto';\nimport { readFile, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport type { HexString, PaymentStatus } from '@fiber-pay/sdk';\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Complete payment proof record\n */\nexport interface PaymentProof {\n /** Unique identifier (payment hash) */\n id: string;\n /** Status at time of recording */\n status: PaymentStatus;\n /** Original invoice string */\n invoice: string;\n /** Invoice details extracted */\n invoiceDetails: {\n paymentHash: string;\n amountCkb: number;\n description?: string;\n };\n /** Payment execution details */\n execution: {\n amountCkb: number;\n feeCkb: number;\n actualTimestamp: number; // When payment settled (if succeeded)\n requestTimestamp: number; // When payment was initiated\n };\n /** Proof of payment */\n proof: {\n preimage?: HexString; // Secret revealed on successful payment\n peerAddress?: string; // Peer that received payment\n channelUsed?: string; // Channel ID used\n routePath?: string[]; // Peers involved in routing\n };\n /** Verification status */\n verified: boolean;\n verifiedAt?: number;\n verificationMethod?: 'preimage_hash' | 'rpc_status' | 'manual';\n /** Metadata for audit trail */\n metadata: {\n createdAt: number;\n updatedAt: number;\n notes?: string;\n };\n}\n\nexport interface PaymentProofSummary {\n totalProofs: number;\n verifiedCount: number;\n pendingCount: number;\n failedCount: number;\n totalAmountCkb: number;\n totalFeesCkb: number;\n timeRange: {\n earliest?: number;\n latest?: number;\n };\n}\n\n// =============================================================================\n// Payment Proof Manager\n// =============================================================================\n\nexport class PaymentProofManager {\n private proofs: Map<string, PaymentProof> = new Map();\n private proofFilePath: string;\n private maxStoredProofs = 10000; // Prevent unbounded growth\n\n constructor(dataDir: string) {\n this.proofFilePath = `${dataDir}/payment-proofs.json`;\n }\n\n /**\n * Load proofs from disk\n */\n async load(): Promise<void> {\n try {\n const data = await readFile(this.proofFilePath, 'utf-8');\n const proofs = JSON.parse(data) as PaymentProof[];\n this.proofs.clear();\n proofs.forEach((proof) => {\n this.proofs.set(proof.id, proof);\n });\n } catch {\n // File doesn't exist yet or is empty\n this.proofs.clear();\n }\n }\n\n /**\n * Save proofs to disk\n */\n async save(): Promise<void> {\n const proofs = Array.from(this.proofs.values());\n const data = JSON.stringify(proofs, null, 2);\n\n try {\n await writeFile(this.proofFilePath, data, 'utf-8');\n } catch (error) {\n if (error instanceof Error && error.message.includes('ENOENT')) {\n // Directory doesn't exist, create it first\n await this.ensureDirectory();\n await writeFile(this.proofFilePath, data, 'utf-8');\n } else {\n throw error;\n }\n }\n }\n\n /**\n * Record a payment proof after successful execution\n */\n recordPaymentProof(\n paymentHash: string,\n invoice: string,\n invoiceDetails: {\n paymentHash: string;\n amountCkb: number;\n description?: string;\n },\n execution: {\n amountCkb: number;\n feeCkb: number;\n actualTimestamp: number;\n requestTimestamp: number;\n },\n status: PaymentStatus,\n proof?: {\n preimage?: HexString;\n peerAddress?: string;\n channelUsed?: string;\n routePath?: string[];\n },\n ): PaymentProof {\n const now = Date.now();\n const fullProof: PaymentProof = {\n id: paymentHash,\n status,\n invoice,\n invoiceDetails,\n execution,\n proof: proof || {},\n verified: false,\n metadata: {\n createdAt: now,\n updatedAt: now,\n },\n };\n\n this.proofs.set(paymentHash, fullProof);\n\n // Verify if we have preimage\n if (proof?.preimage) {\n const isValid = this.verifyPreimageHash(proof.preimage, invoiceDetails.paymentHash);\n if (isValid) {\n fullProof.verified = true;\n fullProof.verifiedAt = now;\n fullProof.verificationMethod = 'preimage_hash';\n }\n }\n\n // Cleanup if we exceed max proofs (keep newest)\n if (this.proofs.size > this.maxStoredProofs) {\n this.pruneOldestProofs(this.maxStoredProofs * 0.8); // Keep 80% after pruning\n }\n\n return fullProof;\n }\n\n /**\n * Get proof by payment hash\n */\n getProof(paymentHash: string): PaymentProof | undefined {\n return this.proofs.get(paymentHash);\n }\n\n /**\n * Verify a proof's authenticity\n */\n verifyProof(proof: PaymentProof): {\n valid: boolean;\n reason: string;\n } {\n // If already verified with preimage, trust it\n if (proof.verified && proof.verificationMethod === 'preimage_hash') {\n return {\n valid: true,\n reason: 'Verified via preimage hash match',\n };\n }\n\n // Try to verify preimage now\n if (proof.proof?.preimage) {\n const hashValid = this.verifyPreimageHash(\n proof.proof.preimage,\n proof.invoiceDetails.paymentHash,\n );\n if (!hashValid) {\n return {\n valid: false,\n reason: 'Preimage does not hash to payment hash',\n };\n }\n proof.verified = true;\n proof.verifiedAt = Date.now();\n proof.verificationMethod = 'preimage_hash';\n return {\n valid: true,\n reason: 'Preimage verified via hash',\n };\n }\n\n // If status is Success without preimage, it was verified by RPC\n if (proof.status === 'Success') {\n return {\n valid: true,\n reason: 'Payment succeeded according to RPC (preimage not available)',\n };\n }\n\n return {\n valid: false,\n reason: 'No verification method available',\n };\n }\n\n /**\n * Get payment timeline between two timestamps\n */\n getPaymentChain(startTime: number, endTime: number): PaymentProof[] {\n return Array.from(this.proofs.values())\n .filter((p) => p.metadata.createdAt >= startTime && p.metadata.createdAt <= endTime)\n .sort((a, b) => a.metadata.createdAt - b.metadata.createdAt);\n }\n\n /**\n * Get summary statistics\n */\n getSummary(): PaymentProofSummary {\n const proofs = Array.from(this.proofs.values());\n\n let verifiedCount = 0;\n let pendingCount = 0;\n let failedCount = 0;\n let totalAmountCkb = 0;\n let totalFeesCkb = 0;\n let earliest: number | undefined;\n let latest: number | undefined;\n\n proofs.forEach((proof) => {\n if (proof.verified) verifiedCount++;\n else if (proof.status === 'Inflight' || proof.status === 'Created') pendingCount++;\n else if (proof.status === 'Failed') failedCount++;\n\n totalAmountCkb += proof.execution.amountCkb;\n totalFeesCkb += proof.execution.feeCkb;\n\n const createdAt = proof.metadata.createdAt;\n if (!earliest || createdAt < earliest) earliest = createdAt;\n if (!latest || createdAt > latest) latest = createdAt;\n });\n\n return {\n totalProofs: proofs.length,\n verifiedCount,\n pendingCount,\n failedCount,\n totalAmountCkb,\n totalFeesCkb,\n timeRange: {\n earliest,\n latest,\n },\n };\n }\n\n /**\n * Export proofs as audit report\n */\n exportAuditReport(startTime?: number, endTime?: number): string {\n const proofs = Array.from(this.proofs.values())\n .filter((p) => {\n if (!startTime && !endTime) return true;\n const created = p.metadata.createdAt;\n if (startTime && created < startTime) return false;\n if (endTime && created > endTime) return false;\n return true;\n })\n .sort((a, b) => a.metadata.createdAt - b.metadata.createdAt);\n\n const lines: string[] = [\n 'Payment Audit Report',\n `Generated: ${new Date().toISOString()}`,\n `Time Range: ${startTime ? new Date(startTime).toISOString() : 'All'} - ${endTime ? new Date(endTime).toISOString() : 'All'}`,\n `Total Payments: ${proofs.length}`,\n '',\n 'Payment ID | Status | Amount CKB | Fee CKB | Verified | Created At',\n '-'.repeat(80),\n ];\n\n proofs.forEach((p) => {\n lines.push(\n `${p.id.slice(0, 16)}... | ${p.status} | ${p.execution.amountCkb.toFixed(4)} | ${p.execution.feeCkb.toFixed(8)} | ${p.verified ? 'Yes' : 'No'} | ${new Date(p.metadata.createdAt).toISOString()}`,\n );\n });\n\n return lines.join('\\n');\n }\n\n /**\n * Verify preimage hash (SHA256 of preimage = payment_hash)\n */\n private verifyPreimageHash(preimage: HexString, paymentHash: string): boolean {\n try {\n // Remove 0x prefix if present\n const preimageHex = preimage.startsWith('0x') ? preimage.slice(2) : preimage;\n const paymentHashHex = paymentHash.startsWith('0x') ? paymentHash.slice(2) : paymentHash;\n\n // Convert hex to buffer\n const preimageBuffer = Buffer.from(preimageHex, 'hex');\n const paymentHashBuffer = Buffer.from(paymentHashHex, 'hex');\n\n // SHA256 hash the preimage\n const hash = createHash('sha256').update(preimageBuffer).digest();\n\n // Compare\n return hash.equals(paymentHashBuffer);\n } catch {\n return false;\n }\n }\n\n /**\n * Remove oldest proofs to keep storage bounded\n */\n private pruneOldestProofs(count: number): void {\n const sorted = Array.from(this.proofs.values()).sort(\n (a, b) => a.metadata.createdAt - b.metadata.createdAt,\n );\n\n const toRemove = sorted.slice(0, Math.floor(sorted.length - count));\n toRemove.forEach((p) => {\n this.proofs.delete(p.id);\n });\n }\n\n /**\n * Ensure directory exists\n */\n private async ensureDirectory(): Promise<void> {\n const dir = dirname(this.proofFilePath);\n try {\n // Use Node.js 20+ mkdir with recursive option\n const fs = await import('node:fs');\n fs.mkdirSync(dir, { recursive: true });\n } catch {\n // Ignore if fails\n }\n }\n}\n"],"mappings":"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","names":["EventEmitter","resolve","resolve","header","randomUUID","DEFAULT_POLL_INTERVAL","randomUUID","ChannelState","ChannelState","http","resolve","http","resolve","mkdir","dirname","toRecord","mkdir","dirname","isTerminalPaymentStatus","randomUUID","dirname","EventEmitter","resolve","createHash","readFile","writeFile","dirname"]}
|