thunder-bridge 1.4.2 → 2.1.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.
@@ -0,0 +1,896 @@
1
+ import { R as Resolved, Q as QrOptions } from './qr-CF-YeXU1.cjs';
2
+ import { A as Amount, T as Ticker, C as Charge, f as MintedPayment, h as PaymentStatus, i as Priced, g as Msat, S as Settlement, P as Payment, Q as Quote, e as Held, H as Handover, j as SocketTicket } from './types-DYZ9EkmJ.cjs';
3
+
4
+ type Sent = {
5
+ method?: string;
6
+ headers?: Record<string, string>;
7
+ body?: string;
8
+ deadline?: AbortSignal;
9
+ staysOnOrigin?: boolean;
10
+ };
11
+ type Verified = {
12
+ address: string;
13
+ family: number;
14
+ };
15
+ /** Carries one request to an address ask() already verified, so nothing resolves the name again */
16
+ type Send = (url: string, sent: Sent, signal: AbortSignal, at: readonly Verified[]) => Promise<Response>;
17
+
18
+ /** What a shop knows about a sale before any rail exists */
19
+ interface Order {
20
+ /** The bank matches it on the statement, and Lightning keys idempotency on it */
21
+ reference: string;
22
+ /** The price in the smallest unit of `currency`, so 48055 is 480.55 CZK */
23
+ amountMinor: number;
24
+ /** ISO 4217. The bank rail moves this, Lightning converts it at `rate` */
25
+ currency: string;
26
+ }
27
+ /** One way to pay one order, already registered with the gateway */
28
+ interface Leg {
29
+ /** The watched payment's id, which with `paymentHash` is what `firstSettled`, `payment` and `settled` take */
30
+ id: string;
31
+ paymentHash: string;
32
+ /** Which rail made it, so a shop can label a leg without knowing how it was built */
33
+ rail: string;
34
+ /** What the payer reads, a BOLT11 invoice or a Short Payment Descriptor */
35
+ scan: string;
36
+ /** The same thing as a QR has to encode it, which is not always `scan` itself */
37
+ qr: string;
38
+ expiresAt: number;
39
+ }
40
+ /**
41
+ * A payment method. Everything that differs between rails is bound once when the
42
+ * rail is built, so the only thing passed per sale is which sale it is
43
+ */
44
+ type Rail = (order: Order) => Promise<Leg>;
45
+ /** What every rail takes, whatever it moves */
46
+ interface RailConfig {
47
+ /** Groups every payment from this rail so `follow` can watch the shop */
48
+ trigger?: string;
49
+ /** How many of that trigger's settlements the gateway keeps replayable past the hour */
50
+ replay?: number;
51
+ /** Where the gateway posts once the money lands, a public https URL */
52
+ webhookUrl?: string;
53
+ /** What `Leg.rail` says, so two rails of one kind can be told apart */
54
+ name?: string;
55
+ }
56
+ /** A Lightning rail the gateway mints for, bound once and then given one order at a time */
57
+ interface LightningRailConfig extends RailConfig {
58
+ /** Priority list, the first address that can prove an invoice wins */
59
+ paidTo: string | string[];
60
+ /**
61
+ * What to charge for one order, the order's own price converted at `rate` by
62
+ * default. Give it a function and the price is whatever you say
63
+ */
64
+ amount?: (order: Order) => Amount;
65
+ /** Where the default conversion gets its rate, the median of four venues by default */
66
+ rate?: Ticker;
67
+ /** Makes the mint safe to retry, the order's reference by default */
68
+ idempotencyKey?: (order: Order) => string | undefined;
69
+ }
70
+ /** The same rail with the invoice resolved here, so the gateway is told neither address nor amount */
71
+ interface BlindLightningRailConfig extends LightningRailConfig {
72
+ /**
73
+ * What the watcher needs and the gateway must not read, sealed under `secret`
74
+ * for the invoice's payment hash before it goes anywhere near the gateway
75
+ */
76
+ sealed?: {
77
+ secret: string;
78
+ data: (order: Order) => unknown;
79
+ };
80
+ /**
81
+ * Where your own `serve.verify` endpoint is mounted, and its secret. Without
82
+ * it the gateway is handed the wallet's own URL, which a gateway enforcing its
83
+ * verify challenge will refuse to poll
84
+ */
85
+ relayThrough?: {
86
+ endpoint: string;
87
+ secret: string;
88
+ };
89
+ /** How the rail reaches wallets, pinned to the address it verified unless you say otherwise */
90
+ send?: Send;
91
+ }
92
+ /** A bank rail: the account the money lands in, and where its arrival is read back from */
93
+ interface BankRailConfig extends RailConfig {
94
+ /** Long lived and server side. Every preimage is derived from it, so losing it loses every proof */
95
+ secret: string;
96
+ /** The account the money goes to, as an IBAN */
97
+ iban: string;
98
+ /** Where `serve.bankVerify` is mounted, a public https URL with no query of its own */
99
+ verifyUrl: string;
100
+ /** When this leg stops being payable, in unix seconds */
101
+ expiresAt: (order: Order) => number;
102
+ /** Sealed before the gateway sees it, the way the blind Lightning rail does */
103
+ sealed?: {
104
+ secret: string;
105
+ data: (order: Order) => unknown;
106
+ };
107
+ /** The Czech variable symbol, taken off the reference's digits by default */
108
+ variableSymbol?: (order: Order) => string | undefined;
109
+ /**
110
+ * Register on a gateway you do not own anyway. The sealed verify URL names
111
+ * nothing about the order, but its operator still learns every watch you place
112
+ */
113
+ allowPublicGateway?: boolean;
114
+ }
115
+ /**
116
+ * A provable invoice from the first address on the list that will issue one, which
117
+ * is what a client mints for itself rather than asking a gateway to. Everything the
118
+ * gateway needs to watch it comes back with everything you need to prove it came
119
+ * from the address you asked for, so you can hand over the first and keep the second.
120
+ *
121
+ * Server side: it resolves hostnames and refuses a private one, which no browser can
122
+ * do. Throws `NoWalletAvailableError` when no address on the list would serve
123
+ */
124
+ declare function invoiceFrom(paidTo: string | string[], amount: Amount, send?: Send): Promise<Resolved>;
125
+ /**
126
+ * One call per sale, whatever the rail moves. Each of these was a free function
127
+ * taking the gateway as a config field, and reaching them through the gateway is
128
+ * what deleted that field
129
+ */
130
+ declare class Rails {
131
+ private readonly gateway;
132
+ constructor(gateway: ThunderBridge);
133
+ /** Lightning, with the gateway minting against a priority list of addresses */
134
+ lightning(config: LightningRailConfig): Rail;
135
+ /**
136
+ * Lightning, with the invoice resolved here so the gateway is told neither the
137
+ * address nor the amount
138
+ */
139
+ blindLightning(config: BlindLightningRailConfig): Rail;
140
+ /** A bank transfer, proved the way a Lightning payment is */
141
+ bank(config: BankRailConfig): Rail;
142
+ /**
143
+ * One bank transfer without building a rail first, for a shop that asks for
144
+ * them one at a time rather than beside another payment method
145
+ */
146
+ transfer(params: BankTransferParams): Promise<BankTransfer>;
147
+ }
148
+
149
+ /**
150
+ * What to ask for: who is paid, how much, and how the QR should look. Every
151
+ * field beyond `paidTo` and `amount` has a default, so the shortest request
152
+ * names two
153
+ */
154
+ interface PaymentRequestInit extends Charge, PaymentRequestOptions {
155
+ }
156
+ /** What `requestPayment` takes beyond the charge itself */
157
+ interface PaymentRequestOptions extends WaitOptions {
158
+ /** Makes the mint safe to retry, so a reloaded checkout replays one invoice */
159
+ idempotencyKey?: string;
160
+ /** Groups this request with every other one carrying the same secret, for `follow` */
161
+ trigger?: string;
162
+ /** How many of that trigger's settlements the gateway keeps replayable past the hour */
163
+ replay?: number;
164
+ /** Size and colour of `qr`, 256 pixels and black by default */
165
+ qr?: QrOptions;
166
+ }
167
+ /**
168
+ * One payment asked for: the invoice to show, the QR to draw it with, and one
169
+ * way to find out it was paid. Everything on it is already proved against the
170
+ * recipient's own server, so nothing here is the gateway's word
171
+ */
172
+ interface PaymentRequest {
173
+ /** What the gateway calls this payment, which is what `payment` and `settled` take */
174
+ readonly id: string;
175
+ readonly bolt11: string;
176
+ readonly paymentHash: string;
177
+ readonly lnAddress: string;
178
+ readonly amountMsat: number;
179
+ /** When the invoice stops being payable, in unix seconds */
180
+ readonly expiresAt: number;
181
+ /** The invoice as an SVG QR, ready to put in an element's `innerHTML` */
182
+ readonly qr: string;
183
+ /** The payment as the gateway first reported it, for anything the fields above leave out */
184
+ readonly payment: MintedPayment;
185
+ /**
186
+ * Resolves once the money has arrived, and rejects when the invoice expires
187
+ * unpaid or the wait is aborted. It follows a WebSocket and reconnects through
188
+ * a drop, so this is one await rather than a poll.
189
+ *
190
+ * `gateway.settled(payment)` is the wider question and ends on an expiry too. This
191
+ * one is about the payment that was asked for, and one that expired was never paid
192
+ */
193
+ paid(options?: WaitOptions): Promise<MintedPayment>;
194
+ /**
195
+ * The same wait as a callback, for a page that has something else to do.
196
+ * Returns a function that stops waiting
197
+ */
198
+ onPaid(arrived: (payment: MintedPayment) => void, failed?: (reason: unknown) => void): () => void;
199
+ /**
200
+ * Ask the recipient's own server whether it settled, and get the preimage it
201
+ * released or null. This is the only answer that comes from somewhere other
202
+ * than the gateway, so it is the one to ask when a payment matters
203
+ */
204
+ prove(): Promise<string | null>;
205
+ }
206
+
207
+ /** The wallet's own LUD-21 URL and the hash its preimage has to match */
208
+ interface Relayed {
209
+ url: string;
210
+ hash: string;
211
+ }
212
+ /** The verify endpoint that asks the wallet for the gateway, and how often it may be asked */
213
+ interface LightningVerifyConfig {
214
+ /** The secret the sealed wallet URL was made with, and nothing else uses it */
215
+ secret: string;
216
+ /**
217
+ * How often you want the gateway to ask, in seconds. It goes out as
218
+ * `Cache-Control: max-age`, so the pace is yours rather than the operator's.
219
+ * Five by default, which is what a Lightning checkout wants
220
+ */
221
+ pollEverySecs?: number;
222
+ /** How the relay reaches the wallet, pinned to the address it verified unless you say otherwise */
223
+ send?: Send;
224
+ }
225
+ /**
226
+ * The URL to hand the gateway instead of the wallet's own, with the wallet's
227
+ * sealed inside it. Point it at wherever `lightningVerifyEndpoint` is mounted
228
+ */
229
+ declare function relayedVerifyUrl(endpoint: string, wallet: Relayed, secret: string): Promise<string>;
230
+
231
+ /** An LNURL-pay endpoint of your own: whose wallets it stands for, and what it charges */
232
+ interface TriggerConfig {
233
+ /** Priority list, quoted at payRequest and then pinned for the callback */
234
+ paidTo: string | string[];
235
+ /**
236
+ * What this trigger costs right now, asked once per payRequest. `fiat` makes it
237
+ * a live rate, and any function of your own makes it a time of day rule.
238
+ *
239
+ * Give it a `{ least, most }` range instead and the payer chooses inside it,
240
+ * which is what a tip jar is. One amount pins the price and the wallet offers
241
+ * no field to type in
242
+ */
243
+ amount: Amount | Range;
244
+ /**
245
+ * Signs the callback URL. Without it anyone could call the callback and make
246
+ * this endpoint mint invoices on wallets of their choosing
247
+ */
248
+ secret: string;
249
+ /** Groups every payment here so `follow` can watch the place, keep it off the QR */
250
+ watchSecret?: string;
251
+ /**
252
+ * How many settlements of this place the gateway keeps replayable past the hour
253
+ * it would otherwise forget them in, up to the ceiling its operator set. What a
254
+ * page that opens later still gets to see. Needs `watchSecret`
255
+ */
256
+ replay?: number;
257
+ /** How the endpoint reaches wallets, pinned to the address it verified unless you say otherwise */
258
+ send?: Send;
259
+ /** Override when a proxy hides the public URL from the request, no trailing slash */
260
+ baseUrl?: string;
261
+ /**
262
+ * Resolve the address here and hand the gateway only a hash and a URL to poll,
263
+ * instead of asking it to mint. It then cannot tell who is being paid beyond
264
+ * the domain in the verify URL, nor how much at all, so the only refusal left
265
+ * to it is refusing everyone. Costs one more round trip and gives up the
266
+ * gateway's CORS proxying, which a server does not need anyway.
267
+ *
268
+ * A gateway that enforces its verify challenge will not poll a wallet's own
269
+ * LUD-21 URL, so pass `relayThrough` as well and the poll comes to you
270
+ */
271
+ blind?: boolean;
272
+ /**
273
+ * Where your own `serve.verify` endpoint is mounted, and the secret it was
274
+ * given. The wallet's URL is sealed inside the one the gateway is handed, so
275
+ * the gateway polls you and learns neither the wallet nor its provider
276
+ */
277
+ relayThrough?: {
278
+ endpoint: string;
279
+ secret: string;
280
+ };
281
+ /**
282
+ * What the watcher needs and the gateway must not have. `data` returns it and
283
+ * `secret` encrypts it, so there is no way to hand the gateway something it
284
+ * can read. Needs 32 characters of randomness, not a passphrase, and every
285
+ * watcher of this trigger holds the same one
286
+ */
287
+ sealed?: {
288
+ secret: string;
289
+ data: (minted: Minted) => unknown;
290
+ };
291
+ }
292
+ /** What a blind mint produced, which is what the sealed payload is built from */
293
+ /**
294
+ * What a payer may choose to send, when the endpoint lets them choose at all.
295
+ * Both ends are asked once per payRequest, so a fiat range moves with the rate
296
+ */
297
+ interface Range {
298
+ least: Amount;
299
+ most: Amount;
300
+ }
301
+ /** What a blind mint produced, which is what the sealed payload is built from */
302
+ interface Minted {
303
+ lnAddress: string;
304
+ amountMsat: number;
305
+ bolt11: string;
306
+ paymentHash: string;
307
+ verifyUrl: string;
308
+ expiresAt: number;
309
+ }
310
+ /**
311
+ * A trigger's live stream is opened with a ticket rather than with the watch
312
+ * secret, so something has to hold the secret and trade it for tickets. That is
313
+ * what these two endpoints are, and they are the only place the gateway's token
314
+ * has to be
315
+ */
316
+ interface WatchTicketConfig {
317
+ /** The trigger to open, the same secret `serve.lnurlPay` groups its payments under */
318
+ watchSecret: string;
319
+ /**
320
+ * How many of this trigger's settlements the socket replays on connect, so a
321
+ * page opened late still shows what it missed, up to the gateway's ceiling
322
+ */
323
+ replay?: number;
324
+ }
325
+
326
+ /**
327
+ * What a wrapping operator may charge over the recipient's own amount. This is a
328
+ * ceiling the client sets rather than a price the operator names, so it sits
329
+ * above what any operator lists and refuses only the ones reaching past it
330
+ */
331
+ interface WrapAllowance {
332
+ /** As a fraction of the recipient's amount, `0.01` by default */
333
+ proportion?: number;
334
+ /** The floor in millisatoshi whatever the fraction works out to, `1000` by default */
335
+ baseMsat?: number;
336
+ }
337
+ /**
338
+ * Prove the invoice really is the one the recipient issued for what you asked,
339
+ * before the payer ever sees it, both fetches go straight to the recipient's own
340
+ * server and none of them goes back to the gateway
341
+ *
342
+ * Throws `GatewayCheatError` when a check fails and `UnverifiedRecipientError`
343
+ * when the recipient could not be reached to run one
344
+ */
345
+ declare function proveOrigin(payment: MintedPayment, asked: Priced, askedAt?: number): Promise<void>;
346
+ /**
347
+ * Prove the money arrived by asking the recipient's own server, not the gateway,
348
+ * returns the preimage when the recipient says it settled and null when it says
349
+ * it has not, and runs the full origin proof first because a verify url the
350
+ * gateway made up would otherwise answer for itself
351
+ */
352
+ declare function proveSettlement(payment: MintedPayment, asked: Priced): Promise<string | null>;
353
+ /** The least a report has to carry for its own proof to be checkable */
354
+ interface Provable {
355
+ status: PaymentStatus;
356
+ preimage: string | null;
357
+ paymentHash: string;
358
+ bolt11?: string | null;
359
+ }
360
+ /**
361
+ * A report `carriesProof` has already accepted, so the preimage is there and the
362
+ * status is settled. Nothing downstream of the check needs a null guard
363
+ */
364
+ type Proven<T extends Provable> = T & {
365
+ status: "paid";
366
+ preimage: string;
367
+ };
368
+ /**
369
+ * Whether a report proves what it claims: it says paid, and it carries a preimage
370
+ * that hashes to the payment hash it itself names. Where an invoice comes with it,
371
+ * the invoice's own hash has to agree too.
372
+ *
373
+ * A payment, a settlement delivered to a webhook and a frame off a trigger all
374
+ * answer this, because all three carry those fields and no other question about
375
+ * one matters.
376
+ *
377
+ * It asks nobody anything, so it costs no round trip and is not a proof of
378
+ * arrival. Only `proveSettlement` asks the recipient
379
+ */
380
+ declare function carriesProof<T extends Provable>(report: T): report is Proven<T>;
381
+ /**
382
+ * The most an operator may add over the recipient's own amount, in millisatoshi.
383
+ * The proportion is what routing and the liquidity behind it costs, and the base
384
+ * is the floor it never drops below, because a fraction of a small payment
385
+ * rounds to nothing the operator can work for
386
+ */
387
+ declare function wrapFeeCeiling(amountMsat: number, allowance?: WrapAllowance): Msat;
388
+ /**
389
+ * Prove a wrapping operator's invoice is the recipient's own payment in
390
+ * disguise, so paying it can only settle by the operator paying the recipient.
391
+ *
392
+ * It compares two invoices and asks nobody anything, so it runs in a browser and
393
+ * costs no round trip. Prove the recipient's own invoice with `proveOrigin`
394
+ * first, because this says nothing about where that one came from.
395
+ *
396
+ * There is no settlement check here and there does not need to be. Both invoices
397
+ * carry one payment hash, so the preimage that settles the wrap is the preimage
398
+ * the recipient released, and `proveSettlement` already reads it from the
399
+ * recipient's own server.
400
+ *
401
+ * Throws `WrapRefusedError` naming which binding failed
402
+ */
403
+ declare function proveWrapped(wrapped: string, recipient: string, allowance?: WrapAllowance): void;
404
+
405
+ /** How far the gateway's clock may drift from yours before a webhook is refused */
406
+ type WebhookOptions = {
407
+ toleranceSecs?: number;
408
+ };
409
+ /**
410
+ * What checks a delivery: the hex the gateway publishes at `/webhook-key`. There
411
+ * is no shared secret to register, so a gateway holds nothing of yours. Rotating
412
+ * its cluster key rotates this too, so a signature that stops verifying is a
413
+ * reason to read the key again before it is a reason to distrust the gateway
414
+ */
415
+ type WebhookCredential = {
416
+ publicKey: string;
417
+ };
418
+ /**
419
+ * Answer the challenge the gateway sends a verify URL before it will poll it,
420
+ * which is how a caller shows the endpoint agreed to the traffic rather than
421
+ * merely being named. Returns null for anything that is not a challenge, so a
422
+ * verify endpoint hands the request on to its own reading of a payment.
423
+ *
424
+ * The nonce is echoed to whoever asked, which grants them nothing, so there is
425
+ * no signature to check here and no secret to hold
426
+ */
427
+ declare function answerVerifyChallenge(request: Request): Promise<Response | null>;
428
+
429
+ /** A Fetch handler, which is what every runtime this targets mounts */
430
+ type Handler = (request: Request) => Promise<Response>;
431
+ /** What to do with what the gateway delivers, and what to believe it with */
432
+ interface WebhookHandlers {
433
+ /**
434
+ * A settlement that proves itself: it says paid and its preimage hashes to the
435
+ * payment hash it names. This is the only callback a shop needs
436
+ */
437
+ onSettled?: (settlement: Proven<Settlement>) => void | Promise<void>;
438
+ /**
439
+ * A delivery that carries no proof, so an expiry. Left unset, the handler
440
+ * answers `202` and does nothing, because acting on an unproven claim is the
441
+ * one thing this refuses to do
442
+ */
443
+ onUnproven?: (settlement: Settlement) => void | Promise<void>;
444
+ /** A whole payment rather than a settlement, which is what an older gateway posts */
445
+ onPayment?: (payment: Payment) => void | Promise<void>;
446
+ /**
447
+ * The key that checks the signature, fetched from the gateway once and kept
448
+ * when you do not pass one. Pass it to pin the key you already read
449
+ */
450
+ credential?: WebhookCredential;
451
+ /** How far the gateway's clock may drift from yours, five minutes by default */
452
+ toleranceSecs?: number;
453
+ }
454
+ /**
455
+ * Everything one gateway lets you mount, in one place so a caller never has to
456
+ * know which handler needs the gateway and which does not. Most of these took it
457
+ * as a config field before, and reaching them through the gateway deleted it.
458
+ *
459
+ * `verify` and `bankVerify` need nothing from the gateway and are here anyway,
460
+ * because a reader looking for a handler should find every handler in one list
461
+ */
462
+ declare class Serve {
463
+ private readonly gateway;
464
+ constructor(gateway: ThunderBridge);
465
+ /**
466
+ * An LNURL-pay endpoint of your own, standing in front of a priority list of
467
+ * addresses, so a printed QR points at your domain and never expires
468
+ */
469
+ lnurlPay(config: TriggerConfig): Handler;
470
+ /** Trades the watch secret for a one minute socket ticket, refusing anyone without it */
471
+ watchTicket(config: WatchTicketConfig): Handler;
472
+ /**
473
+ * Mints a socket ticket for anybody who asks, which makes the trigger's whole
474
+ * stream public, preimages included. Only for a board where that is the point
475
+ */
476
+ publicWatchTicket(config: WatchTicketConfig): Handler;
477
+ /**
478
+ * A verify endpoint of your own that asks the recipient's wallet for you, so
479
+ * the gateway polls you and never the wallet
480
+ */
481
+ verify(config: LightningVerifyConfig): Handler;
482
+ /** The verify endpoint a bank rail is polled at, answering off your own statement */
483
+ bankVerify(config: BankVerifyConfig): Handler;
484
+ /**
485
+ * The whole webhook route: it answers the gateway's challenge, checks the
486
+ * signature against the key the gateway publishes, refuses a settlement that
487
+ * proves nothing, and calls you for the one that does.
488
+ *
489
+ * `export const POST = gateway.serve.webhook({ onSettled: fulfil })` is the
490
+ * entire integration
491
+ */
492
+ webhook(handlers: WebhookHandlers): Handler;
493
+ /** Verify a delivery and read the settlement out of it, null when it is not believable */
494
+ readSettlement(request: Request, options?: WebhookOptions): Promise<Settlement | null>;
495
+ /** Verify a delivery and read the payment out of it, null when it is not believable */
496
+ readPayment(request: Request, options?: WebhookOptions): Promise<Payment | null>;
497
+ /** Answer the challenge the gateway sends before it will post to a webhook of yours */
498
+ answerWebhookChallenge(request: Request, options?: WebhookOptions): Promise<Response | null>;
499
+ private credential;
500
+ }
501
+
502
+ /** How this instance talks to one gateway */
503
+ interface ThunderBridgeOptions {
504
+ /**
505
+ * Sent as `Authorization: Bearer`, which a gateway started with
506
+ * `GATEWAY_TOKEN` requires on every call, the socket handshake included. No
507
+ * browser WebSocket can carry a header, so setting this also puts every socket
508
+ * through a ticket
509
+ */
510
+ token?: string;
511
+ /**
512
+ * The same long lived server side secret your rail derives its preimages from.
513
+ * Given here, every call carries a signature the gateway reads as your identity,
514
+ * so a payment you create is handed back to you and to nobody else. Withheld,
515
+ * you are anonymous and any holder of an id can read what it names
516
+ */
517
+ secret?: string;
518
+ }
519
+ /** How long to wait on a payment, and what the socket URL is allowed to carry */
520
+ interface WaitOptions {
521
+ /** Give up when this aborts, `AbortSignal.timeout(ms)` covers the usual case */
522
+ signal?: AbortSignal;
523
+ /**
524
+ * Mint a short-lived ticket and put that in the socket URL instead of the
525
+ * payment id. Implied by `token` and by `secret`. The id stays readable inside the ticket,
526
+ * what changes is that a URL out of a log stops opening anything after a
527
+ * minute
528
+ */
529
+ tickets?: boolean;
530
+ }
531
+ /** What a socket ticket opens beyond the trigger it names */
532
+ interface TicketOptions {
533
+ /**
534
+ * How many of this trigger's settlements the socket replays on connect, up to
535
+ * the ceiling the gateway's operator set
536
+ */
537
+ replay?: number;
538
+ }
539
+ /** What a mint carries beyond the charge: a retry key, and which trigger it joins */
540
+ interface CreateOptions {
541
+ /**
542
+ * Makes the POST safe to retry. A repeat of a finished request replays its
543
+ * payment instead of asking a wallet for a second invoice, a repeat that
544
+ * arrives while the first is still resolving throws
545
+ * `IdempotencyConflictError`, and the key is held for 24 hours
546
+ */
547
+ idempotencyKey?: string;
548
+ /**
549
+ * Groups this payment with every other one carrying the same secret, so
550
+ * `follow` can watch the place rather than the payment. Registering
551
+ * sends only its sha256, which is also all the gateway stores, so a stolen
552
+ * ledger cannot subscribe. Following sends the secret itself, because the
553
+ * gateway hashes what it is given to find the stream, so the operator of a
554
+ * gateway you do not own learns it the first time you connect. Keep it apart
555
+ * from any URL a payer sees
556
+ */
557
+ trigger?: string;
558
+ /**
559
+ * How many of the trigger's settlements the gateway keeps replayable past the
560
+ * hour it would otherwise forget them in, up to the ceiling its operator set.
561
+ * Needs `trigger`, defaults to none
562
+ */
563
+ replay?: number;
564
+ }
565
+ /** What to do with a trigger's settlements, and how hard to try to keep hearing them */
566
+ interface FollowOptions {
567
+ /** Called for the recent settlements replayed on connect, then for each new one */
568
+ onPayment: (settled: Payment) => void;
569
+ /**
570
+ * How many settlements to ask for on connect, defaults to the gateway's ten.
571
+ * It hands back what it still holds, which is the last hour unless the
572
+ * payments were minted with `replay`
573
+ */
574
+ replay?: number;
575
+ /** Called when a connection drops or a frame is refused, the follow keeps going */
576
+ onError?: (error: unknown) => void;
577
+ /** Reconnect after a drop, defaults to true */
578
+ reconnect?: boolean;
579
+ /**
580
+ * The first wait after a drop, doubling up to 30 seconds and jittered so a
581
+ * fleet does not come back in lockstep, defaults to 3000. A connection that
582
+ * opens puts it back to the first wait
583
+ */
584
+ reconnectDelayMs?: number;
585
+ /**
586
+ * Mint a short-lived ticket and put that in the socket URL instead of the
587
+ * secret, one per connection. Keeps the secret out of access logs, at the cost
588
+ * of a POST before each connect. Implied by `token` and by `secret`. Leave it off for a
589
+ * microcontroller, where one hardcoded URL and a dumb reconnect loop is the
590
+ * whole point
591
+ */
592
+ tickets?: boolean;
593
+ }
594
+ /** How this caller holds a socket open and what it answers on it */
595
+ interface AttendOptions {
596
+ /**
597
+ * What this caller answers when the gateway asks about one of its payments.
598
+ * The preimage when the money is there, null while it is not, and the gateway
599
+ * checks the preimage against the hash either way
600
+ */
601
+ answer: (paymentHash: string) => Promise<string | null> | string | null;
602
+ /** Called when a connection drops or a frame is refused, the socket keeps going */
603
+ onError?: (error: unknown) => void;
604
+ /** Reconnect after a drop, defaults to true */
605
+ reconnect?: boolean;
606
+ /** The first wait after a drop, doubling and jittered, defaults to 3000 */
607
+ reconnectDelayMs?: number;
608
+ }
609
+ /** Talks to a Thunder Bridge gateway and trusts it for nothing it can check itself */
610
+ declare class ThunderBridge {
611
+ private readonly baseUrl;
612
+ private readonly token;
613
+ private readonly handedOut;
614
+ private readonly secret;
615
+ private strangers;
616
+ private speaks;
617
+ private published;
618
+ /** Everything this gateway lets you mount, from an LNURL endpoint to a webhook route */
619
+ readonly serve: Serve;
620
+ /** One call per sale, whatever the rail moves */
621
+ readonly rails: Rails;
622
+ constructor(baseUrl: string, options?: ThunderBridgeOptions);
623
+ /**
624
+ * Whether a token was given to this instance, which is your side of the
625
+ * arrangement and says nothing about the gateway's. `refusesStrangers` is the
626
+ * one that asks the gateway, and it is the one to guard anything with
627
+ */
628
+ get hasToken(): boolean;
629
+ /**
630
+ * Whether the gateway turns away a caller carrying no token, asked by making
631
+ * one unauthenticated read it would have to refuse. `hasToken` answers only
632
+ * whether you configured one, so a made-up token against a public instance
633
+ * reads as yours and is not. Asked once and remembered, because an instance
634
+ * does not change its mind. Anything other than a refusal counts as open, so
635
+ * an unreachable gateway fails closed
636
+ */
637
+ refusesStrangers(): Promise<boolean>;
638
+ /**
639
+ * Ask to be paid for one thing. It mints the invoice, proves it came from the
640
+ * address you asked for, draws the QR and hands back one object with a way to
641
+ * wait for the money. This is `mint` plus the two things every caller does next
642
+ */
643
+ requestPayment(asked: PaymentRequestInit): Promise<PaymentRequest>;
644
+ /**
645
+ * Ask the gateway for an invoice payable to the first address on your list
646
+ * that can issue a provable one, throws `NoWalletAvailableError` when none can
647
+ * and `GatewayCheatError` when what comes back is not what you asked for
648
+ */
649
+ mint(charge: Charge, options?: CreateOptions): Promise<MintedPayment>;
650
+ /**
651
+ * Ask which address would serve an amount without minting anything, throws
652
+ * `NoWalletAvailableError` when none would. A quote is a probe and not a
653
+ * promise: the address it names can still be refused at create time, because
654
+ * whether a wallet returns a provable invoice cannot be known without asking
655
+ * it for one, and asking mints it
656
+ */
657
+ quote(charge: Charge): Promise<Quote>;
658
+ /**
659
+ * The key this gateway signs webhooks with when you registered none of your own.
660
+ * `serve.webhook` reads it for you. Asked once and kept, because it is the same
661
+ * for every instance in the cluster
662
+ */
663
+ webhookKey(): Promise<string>;
664
+ private publishedKey;
665
+ /**
666
+ * Read a payment back, null when the gateway has never heard of it. One method
667
+ * for both sorts: `kind` says whether the gateway minted it or was handed it,
668
+ * and the address, amount and invoice are null on one it was never told
669
+ */
670
+ payment(held: Held): Promise<Payment | null>;
671
+ /**
672
+ * List what this gateway is watching, newest first. Only a gateway started
673
+ * with `GATEWAY_TOKEN` serves this, because on a shared one it would hand
674
+ * every caller everyone else's payments, so a public gateway answers 404.
675
+ *
676
+ * `scanned` says how many settled records were looked at to build the page.
677
+ * Anything older than that window is not in the answer, and the list does not
678
+ * pretend otherwise
679
+ */
680
+ payments(limit?: number): Promise<{
681
+ payments: Payment[];
682
+ scanned: number;
683
+ }>;
684
+ /**
685
+ * Follow a payment over WebSocket until it is paid or expired, reconnecting
686
+ * through a drop. A payment that never answers gives up after a few tries, and
687
+ * one that has answered is followed until its own expiry, so the wait always
688
+ * ends by itself
689
+ */
690
+ settled(held: Held, options?: WaitOptions): Promise<Payment>;
691
+ private followed;
692
+ /**
693
+ * Wait on several payments and keep the first one that is really paid, then stop
694
+ * waiting on the losers, which closes their sockets.
695
+ *
696
+ * This is how one order offers two rails. A Lightning invoice and a bank
697
+ * transfer for the same thing are two payments here, and the payer picks one, so
698
+ * what you want is the one that arrives and nothing further from the other.
699
+ *
700
+ * A leg that expires is a loser, not a winner, which is the whole reason this is
701
+ * not a race: `settled` ends on `paid` and on `expired` alike, and a
702
+ * Lightning invoice expires in an hour while a bank transfer takes days. `null`
703
+ * means every leg ended without being paid.
704
+ *
705
+ * Stopping the wait is not revoking the invoice. Nobody can revoke one, because
706
+ * the recipient's own wallet minted it, so a payer who pays the loser afterwards
707
+ * really does pay twice and that shows up on `follow` as a second settlement to
708
+ * refund.
709
+ */
710
+ firstSettled(held: Held[], options?: WaitOptions): Promise<Payment | null>;
711
+ /**
712
+ * Hand over an invoice you obtained yourself so the gateway watches it without
713
+ * being told the address or the amount. It can then only refuse everyone
714
+ * rather than one recipient, which is what makes leaving it cheap. Anything
715
+ * the watcher needs goes in `sealed`, which the gateway cannot read
716
+ */
717
+ watch(handover: Handover): Promise<Payment>;
718
+ /**
719
+ * What this payment is called, which you can work out before any gateway has
720
+ * heard of it. Every gateway you hand the same invoice to answers with the same
721
+ * name, so watching at several of them adds up to one payment rather than
722
+ * several, and no gateway's key is in the answer. Null when no secret was given,
723
+ * because then the gateway names the payment and only it can
724
+ */
725
+ nameFor(paymentHash: string): Promise<string | null>;
726
+ /**
727
+ * Hold a socket open and answer what the gateway asks about this caller's own
728
+ * payments, so a watch addressed to this caller settles without anybody
729
+ * hosting a URL. Reconnects on its own until the returned function is called
730
+ */
731
+ attend(options: AttendOptions): () => void;
732
+ /**
733
+ * Follow every payment made to one trigger, replayed from the recent ones on
734
+ * connect and then live, reconnecting on its own until the returned function
735
+ * is called. A trigger has no terminal state, so this never resolves
736
+ */
737
+ follow(secret: string, options: FollowOptions): () => void;
738
+ /**
739
+ * A one minute pass onto one trigger's stream, for something that must hold
740
+ * neither the token nor the trigger secret. Mint it in a handler and answer
741
+ * with the ticket alone, because that is all a browser needs to connect and
742
+ * all it can do anything with. `serve.watchTicket` is this method already
743
+ * wrapped in a route
744
+ */
745
+ ticket(trigger: string, options?: TicketOptions): Promise<SocketTicket>;
746
+ private needsTicket;
747
+ private wsTicket;
748
+ private mintedTicket;
749
+ private sending;
750
+ private reading;
751
+ private speaking;
752
+ private handOut;
753
+ private proven;
754
+ }
755
+
756
+ /** One incoming payment as the bank booked it, in the smallest unit of its currency */
757
+ interface Credit {
758
+ amountMinor: number;
759
+ currency: string;
760
+ /** Whatever the payer wrote, wherever this bank puts it. Matching is a whole word, so noise around it is fine */
761
+ reference: string;
762
+ /**
763
+ * Unix seconds. A bank that books a day rather than an instant, as Fio does,
764
+ * gives the day's midnight in its own zone, so rendering this in UTC can show
765
+ * the day before. Nothing here matches on it, it is yours to read
766
+ */
767
+ bookedAt: number;
768
+ }
769
+ /**
770
+ * Recent credits on one account, oldest or newest first, it makes no difference.
771
+ * This is the whole plugin seam: a bank is a function of this shape, and
772
+ * `fioStatement` is one implementation of it
773
+ */
774
+ type Statement = (sinceUnix: number) => Promise<Credit[]>;
775
+ /** One transfer to ask for: what is owed, where it lands, and where its arrival is read back from */
776
+ interface BankTransferParams {
777
+ /**
778
+ * Long lived and server side, at least 32 characters. The preimage is derived
779
+ * from it and the verify query is sealed with it, so losing it loses every proof
780
+ */
781
+ secret: string;
782
+ /** What the payer must leave on the transfer, an order id or a nonce. It is matched, not stored */
783
+ reference: string;
784
+ /** The price in the smallest unit, so 48055 is 480.55 CZK */
785
+ amountMinor: number;
786
+ /** The account the money goes to, as an IBAN */
787
+ iban: string;
788
+ /**
789
+ * Where `bankVerifyEndpoint` is mounted, a public https URL with no query of
790
+ * its own. Not needed when `answerBy` is "agent", because then nothing is polled
791
+ */
792
+ verifyUrl?: string;
793
+ /**
794
+ * How the gateway gets its answer. "poll" hands it a URL it fetches, which
795
+ * needs a public host. "agent" hands it this caller's name instead, and the
796
+ * socket `bankAgent` holds open answers for it, which needs no host at all
797
+ */
798
+ answerBy?: "poll" | "agent";
799
+ /** When the offer dies, in unix seconds. Money in a bank moves on banking days, so give it days */
800
+ expiresAt: number;
801
+ /** Defaults to CZK */
802
+ currency?: string;
803
+ /** Up to ten digits, for accounting systems that still want one */
804
+ variableSymbol?: string;
805
+ /**
806
+ * Groups this transfer with everything else paid to the same secret, so one
807
+ * `followTrigger` socket hears about it. Give the Lightning leg of the same
808
+ * order the same secret and both rails arrive on one stream
809
+ */
810
+ trigger?: string;
811
+ /** How many settlements of that trigger the gateway keeps replayable past the hour, needs `trigger` */
812
+ replay?: number;
813
+ /**
814
+ * Handed back on that stream, so a watcher learns which order settled without
815
+ * asking anyone. It is sealed under `secret` for this transfer's payment hash,
816
+ * so the gateway can neither read it nor move it onto another payment
817
+ */
818
+ sealed?: {
819
+ secret: string;
820
+ data: unknown;
821
+ };
822
+ /**
823
+ * Where the gateway posts once the money lands, a public https URL. Without one
824
+ * a transfer is only ever learned by following the trigger or asking
825
+ */
826
+ webhookUrl?: string;
827
+ /**
828
+ * Register on a gateway you do not own anyway. The sealed verify URL tells its
829
+ * operator nothing about the order, but the URL itself still answers whether
830
+ * that order was paid. Say true only when that much is not worth hiding
831
+ */
832
+ allowPublicGateway?: boolean;
833
+ }
834
+ /** A transfer the gateway is now watching, and the descriptor the payer scans */
835
+ interface BankTransfer {
836
+ /** The watched payment's id at the gateway, which is how you read this order back */
837
+ id: string;
838
+ /** What the gateway was given, and what the preimage has to hash to */
839
+ paymentHash: string;
840
+ /** The same URL you mounted, carrying what to look for and a signature over it */
841
+ verifyUrl: string;
842
+ /** The payer scans this, it is a Short Payment Descriptor, the Czech QR platba format */
843
+ spd: string;
844
+ }
845
+ /** The endpoint the gateway polls for a bank transfer, answering off your own statement */
846
+ interface BankVerifyConfig {
847
+ /** The same secret `bankTransfer` was given */
848
+ secret: string;
849
+ /** The IBAN this endpoint answers for, refusing a question sealed for another account */
850
+ iban: string;
851
+ /** The account to read */
852
+ statement: Statement;
853
+ /** How far back a credit still counts, seven days by default */
854
+ lookBackSecs?: number;
855
+ /**
856
+ * How often you want the gateway to ask, in seconds. It goes out as
857
+ * `Cache-Control: max-age`, so the pace is yours to set rather than the
858
+ * gateway's, and a bank that updates once a minute should say so instead of
859
+ * being polled every few seconds. Thirty by default, clamped to an hour
860
+ */
861
+ pollEverySecs?: number;
862
+ }
863
+ /** One order this caller is waiting on, and the account it is waiting on it in */
864
+ interface BankOrder {
865
+ iban: string;
866
+ reference: string;
867
+ amountMinor: number;
868
+ currency?: string;
869
+ expiresAt: number;
870
+ statement: Statement;
871
+ }
872
+ /** What a caller needs to answer for its own transfers over a socket */
873
+ interface BankAgentConfig {
874
+ /** The gateway holding the watches this caller raised */
875
+ gateway: ThunderBridge;
876
+ /** The same secret `bankTransfer` was given, never leaving this device */
877
+ secret: string;
878
+ /** What the payment the gateway is asking about was asking for, or null when it is none of ours */
879
+ orders: (paymentHash: string) => Promise<BankOrder | null> | BankOrder | null;
880
+ /** How far back a credit still counts, seven days by default */
881
+ lookBackSecs?: number;
882
+ /** Called when a connection drops or a frame is refused, the socket keeps going */
883
+ onError?: (error: unknown) => void;
884
+ }
885
+ /**
886
+ * Answer the gateway over a socket this device opens, so a transfer addressed to
887
+ * this caller settles from a till behind NAT, a browser tab or a phone. The
888
+ * preimage is derived here from the secret, so the gateway is told only that one
889
+ * exists and can check it against the hash it already holds.
890
+ *
891
+ * Call the returned function to stop attending. Whatever is still open is asked
892
+ * again on the gateway's own schedule, so leaving and coming back loses nothing
893
+ */
894
+ declare function bankAgent(config: BankAgentConfig): () => void;
895
+
896
+ export { type AttendOptions as A, type BankAgentConfig as B, type Credit as C, type WebhookOptions as D, type WrapAllowance as E, type FollowOptions as F, answerVerifyChallenge as G, type Handler as H, carriesProof as I, invoiceFrom as J, proveOrigin as K, type Leg as L, type Minted as M, proveSettlement as N, type Order as O, type PaymentRequest as P, proveWrapped as Q, type RailConfig as R, type Statement as S, ThunderBridge as T, relayedVerifyUrl as U, wrapFeeCeiling as V, type WaitOptions as W, type BankOrder as a, type BankTransfer as b, type BankTransferParams as c, type BankVerifyConfig as d, bankAgent as e, type Rail as f, type ThunderBridgeOptions as g, type BankRailConfig as h, type BlindLightningRailConfig as i, type CreateOptions as j, type LightningRailConfig as k, type LightningVerifyConfig as l, type PaymentRequestInit as m, type PaymentRequestOptions as n, type Provable as o, type Proven as p, Rails as q, type Range as r, type Relayed as s, type Send as t, Serve as u, type TicketOptions as v, type TriggerConfig as w, type WatchTicketConfig as x, type WebhookCredential as y, type WebhookHandlers as z };