@fiber-pay/runtime 0.1.0-rc.1
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/README.md +110 -0
- package/dist/index.d.ts +523 -0
- package/dist/index.js +3389 -0
- package/dist/index.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/service.ts","../src/alerts/alert-manager.ts","../src/alerts/backends/file-jsonl.ts","../src/alerts/format.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/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/jsonrpc-tracking.ts","../src/proxy/job-routes.ts","../src/alerts/types.ts","../src/proxy/monitor-routes.ts","../src/storage/memory-store.ts","../src/storage/sqlite-store.ts","../src/jobs/job-manager.ts","../src/jobs/types.ts","../src/jobs/error-classifier.ts","../src/jobs/state-machine.ts","../src/jobs/executor-utils.ts","../src/jobs/executors/payment-executor.ts","../src/jobs/executors/invoice-executor.ts","../src/jobs/executors/channel-executor.ts","../src/bootstrap.ts"],"sourcesContent":["import { EventEmitter } from 'node:events';\nimport { FiberRpcClient } from '@fiber-pay/sdk';\nimport { AlertManager } from './alerts/alert-manager.js';\nimport { 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 { ChannelMonitor } from './monitors/channel-monitor.js';\nimport { HealthMonitor } from './monitors/health-monitor.js';\nimport { InvoiceTracker } from './monitors/invoice-tracker.js';\nimport { BaseMonitor } from './monitors/base-monitor.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';\nimport { JobManager } from './jobs/job-manager.js';\nimport type { ChannelJob, InvoiceJob, PaymentJob, RuntimeJob } from './jobs/types.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 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: this.jobManager\n ? (params, options) => this.jobManager!.ensurePayment(params, options)\n : undefined,\n createInvoiceJob: this.jobManager\n ? (params, options) => this.jobManager!.manageInvoice(params, options)\n : undefined,\n createChannelJob: this.jobManager\n ? (params, options) => this.jobManager!.manageChannel(params, options)\n : undefined,\n getJob: this.jobManager ? (id) => this.jobManager!.getJob(id) : undefined,\n listJobs: this.jobManager ? (filter) => this.jobManager!.listJobs(filter) : undefined,\n cancelJob: this.jobManager ? (id) => this.jobManager!.cancelJob(id) : undefined,\n listJobEvents: this.jobStore ? (jobId) => this.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 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(job: RuntimeJob): 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 channelId: this.extractChannelId(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 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 } 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","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(`state=${previousStateName}->${currentStateName}`, `${ANSI_BOLD}${ANSI_YELLOW}`, withColor),\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 { Alert, AlertBackend } from '../types.js';\nimport { formatRuntimeAlert } from '../format.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 type { Alert, AlertBackend } from '../types.js';\nimport { sleep } from '../../utils/async.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 type { RetryPolicy } from './jobs/types.js';\nimport { defaultPaymentRetryPolicy } from './jobs/retry-policy.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 type AlertBackendConfig =\n | StdoutAlertConfig\n | WebhookAlertConfig\n | WebsocketAlertConfig\n | FileAlertConfig;\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: 3000,\n invoicePollIntervalMs: 2000,\n paymentPollIntervalMs: 1000,\n peerPollIntervalMs: 10000,\n healthPollIntervalMs: 5000,\n includeClosedChannels: true,\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: 500,\n retryPolicy: defaultPaymentRetryPolicy,\n },\n};\n\nexport function createRuntimeConfig(input: RuntimeConfigInput = {}): RuntimeConfig {\n const config: RuntimeConfig = {\n ...defaultRuntimeConfig,\n ...input,\n proxy: {\n ...defaultRuntimeConfig.proxy,\n ...input.proxy,\n },\n storage: {\n ...defaultRuntimeConfig.storage,\n ...input.storage,\n },\n jobs: {\n ...defaultRuntimeConfig.jobs,\n ...input.jobs,\n retryPolicy: {\n ...defaultRuntimeConfig.jobs.retryPolicy,\n ...input.jobs?.retryPolicy,\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 { ChannelState, 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 (change.type === 'channel_new' && change.channel.state.state_name === ChannelState.NegotiatingFunding) {\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 (change.type === 'channel_state_changed' && change.currentState === ChannelState.ChannelReady) {\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 || 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((tlc: Htlc) => !previousPending.has(tlc.id)).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 { 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 ? `Fiber node ping failed: ${failureReason}` : 'Fiber node ping returned false',\n },\n });\n }\n }\n}\n","/**\n * Determine whether an error thrown during invoice/payment tracking is\n * expected and should be silently skipped (e.g. item not yet indexed,\n * transient connectivity blip). 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 /not found|does not exist|no such|temporarily unavailable|connection refused|timed out|timeout/i.test(\n message,\n );\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 } 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 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 (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","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 } 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 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 (isExpectedTrackerError(error)) {\n continue;\n }\n throw error;\n }\n }\n\n this.store.pruneCompleted(this.config.completedItemTtlSeconds * 1000);\n }\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 { 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 http from 'node:http';\nimport type { IncomingMessage, ServerResponse } 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 { collectJsonRpcMethods, captureTrackedHashes } from './jsonrpc-tracking.js';\nimport { tryParseJson } from './json.js';\nimport { handleJobPostEndpoint, handleDeleteEndpoint } from './job-routes.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 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","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 { isObject } from './json.js';\n\ninterface JsonRpcMessage {\n id?: string | number;\n method?: string;\n result?: unknown;\n error?: unknown;\n}\n\nexport function collectJsonRpcMethods(requestBody: unknown): Map<string | number, string> {\n const methods = new Map<string | number, string>();\n for (const item of normalizeJsonRpcRequest(requestBody)) {\n if (item.id !== undefined && typeof item.method === 'string') {\n methods.set(item.id, item.method);\n }\n }\n return methods;\n}\n\nexport function captureTrackedHashes(\n methodById: Map<string | number, string>,\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 method = methodById.get(message.id);\n if (!method) {\n continue;\n }\n\n if (method === 'new_invoice') {\n const paymentHash = extractInvoicePaymentHash(message.result);\n if (paymentHash) {\n handlers.onInvoiceTracked(paymentHash);\n }\n }\n\n if (method === 'send_payment') {\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","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 { idempotencyKey?: string; maxRetries?: number; reuseTerminal?: boolean } | 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 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 channelId?: `0x${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 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 = 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 type TrackedInvoiceState,\n type TrackedPaymentState,\n alertPriorityOrder,\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 }>(items: Map<PaymentHash, T>): 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 Database from 'better-sqlite3';\nimport { randomUUID } from 'node:crypto';\nimport { mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\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.prepare('INSERT INTO schema_migrations (version, applied_at) VALUES (?, ?)').run(\n migration.version,\n Date.now(),\n );\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\n .prepare('SELECT * FROM jobs WHERE idempotency_key = ?')\n .get(key) as DbRow | 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 { FiberRpcClient } from '@fiber-pay/sdk';\nimport { EventEmitter } from 'node:events';\nimport { randomUUID } from 'node:crypto';\nimport { defaultPaymentRetryPolicy } from './retry-policy.js';\nimport { TERMINAL_JOB_STATES } from './types.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 { runPaymentJob } from './executors/payment-executor.js';\nimport { runInvoiceJob } from './executors/invoice-executor.js';\nimport { runChannelJob } from './executors/channel-executor.js';\nimport type { SqliteJobStore } from '../storage/sqlite-store.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 ?? 500;\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']>(idempotencyKey);\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']>('invoice', params, idempotencyKey, options.maxRetries, options.reuseTerminal) 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']>('channel', params, idempotencyKey, options.maxRetries, options.reuseTerminal) 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(existing.id, 'created', existing.state, 'queued', this.buildEventData(reset as RuntimeJob));\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, { state: 'inflight' }) 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(job as ChannelJob, this.rpc, this.retryPolicy, abortController.signal);\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>(updated.id, updated as Partial<import('./types.js').Job>);\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 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 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 { pattern: /insufficient (balance|capacity|funds)/i, category: 'insufficient_balance', retryable: false },\n { pattern: /amount.*too large|exceeds.*capacity/i, category: 'amount_too_large', retryable: false },\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 { pattern: /payment hash.*exist|payment_hash.*exist|duplicated payment hash/i, category: 'invalid_payment', retryable: false },\n // Peer / connectivity\n { pattern: /peer.*offline|peer.*unreachable|peer.*disconnect/i, category: 'peer_offline', retryable: true },\n { pattern: /connection.*refused|connection.*reset/i, category: 'peer_offline', retryable: true },\n { pattern: /peer.*feature not found|waiting for peer to send init message/i, category: 'peer_offline', retryable: true },\n { pattern: /channel.*already.*exist|duplicat(e|ed).*channel/i, category: 'temporary_failure', retryable: true },\n // Timeout\n { pattern: /timeout|timed out/i, category: 'timeout', retryable: true },\n // Payment validity\n { pattern: /invalid.*invoice|malformed.*invoice/i, category: 'invalid_payment', retryable: false },\n { pattern: /payment.*hash.*mismatch|preimage.*invalid/i, category: 'invalid_payment', retryable: false },\n // Generic temporary\n { pattern: /temporary.*failure|try again|retry/i, category: 'temporary_failure', retryable: true },\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(\n error: unknown,\n failedError?: string,\n): 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 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 { from: ['invoice_created', 'invoice_received'], event: 'invoice_expired', to: 'invoice_expired' },\n { from: ['invoice_created', 'invoice_received'], event: 'invoice_cancelled', to: 'invoice_cancelled' },\n { from: ['invoice_settled', 'invoice_expired', 'invoice_cancelled'], event: 'payment_success', to: 'succeeded' },\n { from: ['invoice_expired', 'invoice_cancelled'], event: 'payment_failed_permanent', to: 'failed' },\n { from: ['executing', 'invoice_created', 'invoice_active', 'invoice_received'], event: 'payment_failed_permanent', to: 'failed' },\n {\n from: ['queued', 'executing', 'waiting_retry', 'invoice_created', 'invoice_active', 'invoice_received'],\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: ['queued', 'executing', 'waiting_retry', 'channel_opening', 'channel_accepting', 'channel_abandoning', 'channel_updating', 'channel_awaiting_ready', 'channel_ready', 'channel_closing'],\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 { 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 nextRetryAt?: number;\n updatedAt: number;\n completedAt?: number;\n};\n\nexport function transitionJobState<T extends { state: JobState; updatedAt: number; completedAt?: number }>(\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 if (shouldRetry(classifiedError, job.retryCount, policy)) {\n const delay = computeRetryDelay(job.retryCount, policy);\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 { FiberRpcClient } from '@fiber-pay/sdk';\nimport { classifyRpcError } from '../error-classifier.js';\nimport { paymentStateMachine } from '../state-machine.js';\nimport type { PaymentJob, RetryPolicy } from '../types.js';\nimport { sleep } from '../../utils/async.js';\nimport { applyRetryOrFail, transitionJobState } from '../executor-utils.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\n ? Math.max(0, current.nextRetryAt - Date.now())\n : 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 current = transitionJobState(current, paymentStateMachine, 'payment_inflight');\n if (paymentHash) {\n current = { ...current, params: { ...current.params, sendPaymentParams: { ...current.params.sendPaymentParams, payment_hash: paymentHash as `0x${string}` } } };\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 =\n 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: { category: 'unknown', retryable: false, message: 'No payment_hash in inflight job' },\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 { FiberRpcClient } from '@fiber-pay/sdk';\nimport { classifyRpcError } from '../error-classifier.js';\nimport { invoiceStateMachine } from '../state-machine.js';\nimport type { InvoiceJob, RetryPolicy } from '../types.js';\nimport { sleep } from '../../utils/async.js';\nimport { applyRetryOrFail, transitionJobState } from '../executor-utils.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 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(`Unsupported invoice action: ${(current.params as { action?: string }).action}`);\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\n","import { ChannelState, type FiberRpcClient } from '@fiber-pay/sdk';\nimport { classifyRpcError } from '../error-classifier.js';\nimport { channelStateMachine } from '../state-machine.js';\nimport type { ChannelJob, RetryPolicy } from '../types.js';\nimport { sleep } from '../../utils/async.js';\nimport { applyRetryOrFail, transitionJobState } from '../executor-utils.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 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) 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 if (!current.params.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((channel) => channel.channel_id === shutdownParams.channel_id);\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(`Unsupported channel action: ${(current.params as { action?: string }).action}`);\n } catch (error) {\n const classified = classifyRpcError(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\nasync function findTargetChannel(\n rpc: FiberRpcClient,\n peerId: string,\n channelId?: `0x${string}`,\n) {\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 { 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(configInput: RuntimeConfigInput = {}): 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"],"mappings":"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","names":["EventEmitter","FiberRpcClient","resolve","resolve","header","http","resolve","http","resolve","dirname","toRecord","dirname","randomUUID","mkdirSync","dirname","randomUUID","ChannelState","DEFAULT_POLL_INTERVAL","ChannelState","randomUUID","EventEmitter","FiberRpcClient","resolve"]}
|