@arkade-os/lnurl-client 0.0.0-stage → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1176 @@
1
+ /**
2
+ * The single error type for expected LNURL failures.
3
+ *
4
+ * It unifies the server's two wire shapes: the LUD-06 protocol shape
5
+ * (`HTTP 200` carrying `{ status: "ERROR", reason }`) and the management
6
+ * shape (a real status code carrying `{ error, code? }`). Either way the
7
+ * caller keeps a `reason`, plus the `httpStatus` and `code` when the wire
8
+ * carried them.
9
+ *
10
+ * `retryable` is true if and only if `httpStatus === 429`: rate limiting is
11
+ * the one failure worth retrying, everything else is terminal.
12
+ */
13
+ declare class LnurlError extends Error {
14
+ /** Human-readable failure reason, taken from the wire `reason`/`error` field. */
15
+ readonly reason: string;
16
+ /** HTTP status when the failure came with one; absent for LUD-06 bodies answered at HTTP 200. */
17
+ readonly httpStatus?: number;
18
+ /** Machine-readable server code, when the management surface sent one. */
19
+ readonly code?: string;
20
+ /** True if and only if `httpStatus === 429`; every other failure is terminal. */
21
+ readonly retryable: boolean;
22
+ /**
23
+ * Creates an `LnurlError`.
24
+ *
25
+ * @param reason - Human-readable failure reason, also used as the message.
26
+ * @param opts - Optional `httpStatus` and `code` captured from the response.
27
+ */
28
+ constructor(reason: string, opts?: {
29
+ httpStatus?: number;
30
+ code?: string;
31
+ });
32
+ }
33
+ /**
34
+ * Thrown when the request itself never completed: the injected `fetch`
35
+ * rejected, or the body could not be read as JSON. The original failure is
36
+ * preserved as `cause`. Protocol and rate-limit failures never surface here;
37
+ * they become `LnurlError`.
38
+ */
39
+ declare class LnurlTransportError extends Error {
40
+ /**
41
+ * Creates an `LnurlTransportError`.
42
+ *
43
+ * @param message - Short description of which transport step failed.
44
+ * @param opts - Optional `cause` carrying the original thrown value.
45
+ */
46
+ constructor(message: string, opts?: {
47
+ cause?: unknown;
48
+ });
49
+ }
50
+ /**
51
+ * Thrown when `pollVerify` outlasts its deadline without seeing a settled
52
+ * invoice. `lastSnapshot` carries the most recent verify state so the caller
53
+ * can resume, display, or log it instead of starting blind.
54
+ */
55
+ declare class LnurlTimeoutError extends Error {
56
+ /** The most recent verify snapshot seen before the deadline, when one was seen. */
57
+ readonly lastSnapshot?: unknown;
58
+ /**
59
+ * Creates an `LnurlTimeoutError`.
60
+ *
61
+ * @param message - Short description including the timeout that elapsed.
62
+ * @param opts - Optional `lastSnapshot` with the latest verify state.
63
+ */
64
+ constructor(message: string, opts?: {
65
+ lastSnapshot?: unknown;
66
+ });
67
+ }
68
+
69
+ /**
70
+ * The `fetch` implementation this client calls.
71
+ *
72
+ * Deliberately structural rather than `typeof globalThis.fetch`: an
73
+ * implementation whose signature differs slightly — notably `expo/fetch`,
74
+ * which React Native needs for a readable `response.body` — is then
75
+ * assignable without an `as unknown as` cast. Only string URLs are ever
76
+ * passed, so any `fetch` accepting something wider satisfies this.
77
+ */
78
+ type FetchImpl = (input: string, init?: RequestInit) => Promise<Response>;
79
+
80
+ interface PaymentOption {
81
+ /** Rail identifier the callback expects back as `paymentOption`. */
82
+ id: string;
83
+ /** Rail family, e.g. `lightning` or `arkade`. */
84
+ type: string;
85
+ /** The rail as a CAIP-19 asset id; `id` is still what the callback takes back. */
86
+ caip19Id?: string;
87
+ /** Whether the rail can currently be selected. */
88
+ available?: boolean;
89
+ /** Whether callback answers on this rail carry a LUD-21 `verify` URL; absent means unknown. */
90
+ verifiable?: boolean;
91
+ /** Minimum sendable amount on this rail. */
92
+ minSendable?: number;
93
+ /** Maximum sendable amount on this rail. */
94
+ maxSendable?: number;
95
+ /** CAIP-19 id of the token a token option is paid in; its CAIP-2 namespace is `type`.
96
+ * Read token options through `tokenOptions`, which validates them. */
97
+ asset?: string;
98
+ /** The `units[]` code a token option is quoted in. */
99
+ unit?: string;
100
+ /** The third party the payer hands funds to on this option, e.g. "FixedFloat". */
101
+ provider?: string;
102
+ }
103
+ /**
104
+ * A unit the receiver prices in on the lightning rail (fiat or asset alongside
105
+ * the native `sat`/`msat`). Quoting a non-native unit is what produces the
106
+ * `paymentQuote` echoed on the invoice result.
107
+ */
108
+ interface Unit {
109
+ /** Unit code the callback expects back as `unit`, e.g. `USD`. */
110
+ code: string;
111
+ /** Decimal places amounts in this unit are expressed with. */
112
+ decimals: number;
113
+ /** Human-readable unit name. */
114
+ name?: string;
115
+ /** Display symbol for the unit. */
116
+ symbol?: string;
117
+ /** Asset identifier backing the unit, for asset-denominated units. */
118
+ assetId?: string;
119
+ /** Minimum amount expressible in this unit, as a decimal string. */
120
+ minAmount?: string;
121
+ /** Maximum amount expressible in this unit, as a decimal string. */
122
+ maxAmount?: string;
123
+ }
124
+ /** An amount paired with the unit it is denominated in. */
125
+ interface AmountObject {
126
+ /** Decimal amount string in `unit`. */
127
+ amount: string;
128
+ /** Unit code from `Unit.code`. */
129
+ unit: string;
130
+ }
131
+ /**
132
+ * The server's quote for a unit-converted payment: what was requested, what
133
+ * the payer pays, what the receiver gets, and the fee breakdown in between.
134
+ */
135
+ interface PaymentQuote {
136
+ /** Quote identifier, when the server issues one. */
137
+ id?: string;
138
+ /** Expiry of the quote, when the server bounds it. */
139
+ expiresAt?: string;
140
+ /** Amount the payer asked to deliver. */
141
+ requested: AmountObject;
142
+ /** Amount the payer must actually pay. */
143
+ payment: AmountObject;
144
+ /** Amount the receiver will get after conversion. */
145
+ receive?: AmountObject;
146
+ /** Named fee legs making up the difference. */
147
+ fees?: {
148
+ name?: string;
149
+ amount: AmountObject;
150
+ }[];
151
+ }
152
+ /** An LUD-06 payRequest plus the `source` (URL and surface) it was fetched from. */
153
+ interface PayRequest {
154
+ /** LUD-06 tag; `resolve` rejects anything that is not a payRequest. */
155
+ tag: "payRequest";
156
+ /** Callback URL the invoice request is built against. */
157
+ callback: string;
158
+ /** Minimum sendable amount in millisats. */
159
+ minSendable: number;
160
+ /** Maximum sendable amount in millisats. */
161
+ maxSendable: number;
162
+ /** JSON-encoded LUD-06 metadata array. */
163
+ metadata: string;
164
+ /** Maximum comment length in characters, when the receiver accepts one. */
165
+ commentAllowed?: number;
166
+ paymentOptions?: PaymentOption[];
167
+ units?: Unit[];
168
+ /** Where this payRequest came from; drives the rail guards downstream. */
169
+ source: {
170
+ url: string;
171
+ surface: "address" | "session";
172
+ };
173
+ }
174
+ /**
175
+ * Options for asking the callback for an invoice or payment destination.
176
+ * `amountSat` is sats and is converted to millisats on the wire.
177
+ */
178
+ interface RequestInvoiceOptions {
179
+ /** Amount to pay in sats; converted to millisats on the wire. */
180
+ amountSat: number;
181
+ /** Optional payer comment, sent when the payRequest allows one. */
182
+ comment?: string;
183
+ paymentOption?: string;
184
+ /** Lightning rail only. */
185
+ unit?: string;
186
+ }
187
+ /**
188
+ * What the callback answered: either a BOLT11 invoice to pay, or a
189
+ * destination to pay on a non-lightning rail (e.g. an Arkade address).
190
+ */
191
+ type InvoiceResult = Bolt11Result | DestinationResult;
192
+ /**
193
+ * A BOLT11 invoice from the callback. `verify` is optional because the server
194
+ * omits it when the invoice's payment hash will not decode; `pollVerify`
195
+ * refuses a missing one instead of polling `undefined`.
196
+ */
197
+ interface Bolt11Result {
198
+ /** Discriminant for the BOLT11 shape. */
199
+ kind: "bolt11";
200
+ /** The BOLT11 invoice to pay. */
201
+ pr: string;
202
+ /** Verify URL tracking settlement; absent when the server could not decode the payment hash. */
203
+ verify?: string;
204
+ /** LUD-XX verifyBatch: endpoint that batch-styles or streams settlement for a whole tracked set. */
205
+ verifyBatch?: string;
206
+ /** Rail the invoice was issued for, echoed back when one was selected. */
207
+ paymentOption?: string;
208
+ /** Quote for a unit-converted payment, when one was requested. */
209
+ paymentQuote?: PaymentQuote;
210
+ }
211
+ /**
212
+ * A non-BOLT11 destination from the callback: pay it on the selected rail and
213
+ * then track settlement through `verify`, exactly like the BOLT11 shape.
214
+ */
215
+ interface DestinationResult {
216
+ /** Discriminant for the destination shape. */
217
+ kind: "destination";
218
+ /** The selected rail both sides settle on. */
219
+ paymentOption: string;
220
+ /** Where to pay on that rail, e.g. an Arkade address. */
221
+ paymentDestination?: string;
222
+ /** A memo the payment must carry. A wallet that cannot attach one must not pay. */
223
+ paymentDestinationTag?: string;
224
+ /** Wallet-executable instruction carrying the amount (BIP21, EIP-681, Solana Pay); none on Tron. */
225
+ paymentURI?: string;
226
+ /** What the payer actually pays on a rail priced in a token. Its `expiresAt` is the
227
+ * payer's deadline: a token answer carries no top-level `expiresAt`. */
228
+ paymentQuote?: PaymentQuote;
229
+ /** Unix seconds after which the server stops attributing payments to this destination. */
230
+ expiresAt?: number;
231
+ /** The third party the payer hands funds to, e.g. "FixedFloat". */
232
+ provider?: string;
233
+ /** Verify URL tracking settlement; absent under the same conditions as the BOLT11 shape. */
234
+ verify?: string;
235
+ /** LUD-XX verifyBatch: batch/stream endpoint covering a whole tracked set. */
236
+ verifyBatch?: string;
237
+ }
238
+ /** The settlement state `pollVerify` resolves with, in either rail shape. */
239
+ type VerifyStatus = Bolt11VerifyStatus | DestinationVerifyStatus;
240
+ /** Settlement state of a BOLT11 payment: `preimage` is null until settled. */
241
+ interface Bolt11VerifyStatus {
242
+ /** Discriminant for the BOLT11 shape. */
243
+ kind: "bolt11";
244
+ /** Whether the invoice has settled. */
245
+ settled: boolean;
246
+ /** Payment preimage once settled, null while pending. */
247
+ preimage: string | null;
248
+ /** The invoice this status belongs to. */
249
+ pr: string;
250
+ }
251
+ /** Settlement state of a destination-rail payment. */
252
+ interface DestinationVerifyStatus {
253
+ /** Discriminant for the destination shape. */
254
+ kind: "destination";
255
+ /** Whether the payment has settled. */
256
+ settled: boolean;
257
+ /** The rail both sides settled on. */
258
+ paymentOption: string;
259
+ /** Where the payment landed, when the server reports it. */
260
+ paymentDestination?: string;
261
+ /** Server-assigned payment reference, when the server reports one. */
262
+ paymentReference?: string;
263
+ }
264
+ /**
265
+ * Tuning for `pollVerify`: how often to re-poll, how long to wait overall,
266
+ * what to report per poll, and how to abort early.
267
+ */
268
+ interface PollVerifyOptions {
269
+ /** Milliseconds between polls; defaults to 1000. */
270
+ intervalMs?: number;
271
+ /** Overall deadline in milliseconds; defaults to 120000. */
272
+ timeoutMs?: number;
273
+ /** Called with every polled snapshot, including unsettled ones. */
274
+ onUpdate?: (s: VerifyStatus) => void;
275
+ /** Abort signal for caller-driven cancellation. */
276
+ signal?: AbortSignal;
277
+ /** The payment the verify URL was issued for — the callback's answer will do.
278
+ * An answer about any other payment then fails instead of resolving. */
279
+ expect?: VerifyExpectation;
280
+ }
281
+ /** The invoice, or the rail and destination, a verify answer must be about. */
282
+ type VerifyExpectation = Pick<Bolt11Result, "pr"> | Pick<DestinationResult, "paymentOption" | "paymentDestination">;
283
+ /**
284
+ * One page of address payment activity: what was paid to one address, who it
285
+ * belongs to, and where to resume. nextSince is inclusive, so a client
286
+ * re-fetching from it dedupes on paymentHash/verifyId.
287
+ */
288
+ interface PaymentPage {
289
+ /** Where the payments were earned: domain, full address (null when nameless), and handle. */
290
+ source: {
291
+ domain: string;
292
+ lightningAddress: string | null;
293
+ handle: string;
294
+ };
295
+ /** Activity entries, least recently changed first. */
296
+ payments: PaymentActivity[];
297
+ /** The last row's updatedAt (createdAt on older servers), or the request's since when empty. */
298
+ nextSince: number;
299
+ }
300
+ /**
301
+ * One payment to an address. The rail decides the shape: only the lightning
302
+ * rail carries a real payment hash, so the arkade rail is keyed by its
303
+ * verify id instead of overloading the hash field.
304
+ */
305
+ type PaymentActivity = Bolt11Activity | DestinationActivity;
306
+ /**
307
+ * A lightning-rail payment to the address. paymentHash is a real BOLT11
308
+ * payment hash here.
309
+ */
310
+ interface Bolt11Activity {
311
+ /** Discriminant for the BOLT11 shape. */
312
+ kind: "bolt11";
313
+ /** Real BOLT11 payment hash. */
314
+ paymentHash: string;
315
+ /** The BOLT11 invoice handed to the payer. */
316
+ pr: string;
317
+ /** Payment preimage once settled, null while pending. */
318
+ preimage: string | null;
319
+ /** RFQ id when this was an offline swap, null for relay invoices. */
320
+ swapId: string | null;
321
+ /** Arkade txid of the claim that paid the covenant out to the owner — a swap
322
+ * settles on a preimage, so this is the only txid their wallet holds. */
323
+ payoutReference: string | null;
324
+ /** Whether the payment has settled. */
325
+ settled: boolean;
326
+ /** Agreed amount in millisats, when recorded. */
327
+ amountMsat: number | null;
328
+ /** Creation timestamp in milliseconds. */
329
+ createdAt: number;
330
+ /** Settlement timestamp in milliseconds, null while pending. */
331
+ settledAt: number | null;
332
+ }
333
+ /**
334
+ * A destination-rail (e.g. arkade/covenant) payment to the address. The
335
+ * server's paymentHash field holds a random verify id on this rail, so it
336
+ * is exposed as verifyId and there is no paymentHash here at all.
337
+ */
338
+ interface DestinationActivity {
339
+ /** Discriminant for the destination shape. */
340
+ kind: "destination";
341
+ /** Opaque verify id minted by the server; NOT a payment hash. */
342
+ verifyId: string;
343
+ /** The rail both sides settled on. */
344
+ paymentOption: string;
345
+ /** Where the payment landed, when the server reports it. */
346
+ paymentDestination: string | null;
347
+ /** Attribution key for per-payment covenant addresses. */
348
+ covenantScript: string | null;
349
+ /** Arkade txid once observed, null until then. */
350
+ paymentReference: string | null;
351
+ /** Arkade txid that credited the owner's own address — the payment itself on
352
+ * the static rail, the sweep on a covenant one. */
353
+ payoutReference: string | null;
354
+ /** Whether the payment has settled. */
355
+ settled: boolean;
356
+ /** Agreed amount in millisats, when recorded. */
357
+ amountMsat: number | null;
358
+ /** Creation timestamp in milliseconds. */
359
+ createdAt: number;
360
+ /** Settlement timestamp in milliseconds, null while pending. */
361
+ settledAt: number | null;
362
+ }
363
+
364
+ /**
365
+ * Fetches the payRequest for a lightning address or bech32 LNURL.
366
+ *
367
+ * The returned payRequest carries its `source` (URL plus `address`/`session`
368
+ * surface) so `requestInvoice` can key its rail guards off it. Anything whose
369
+ * `tag` is not `payRequest` is rejected: this client only pays.
370
+ *
371
+ * @param input - A lightning address or bech32 LNURL.
372
+ * @param fetchImpl - The injected `fetch` implementation to call.
373
+ * @returns The payRequest with its fetch source attached.
374
+ */
375
+ declare function resolve(input: string, fetchImpl: FetchImpl): Promise<PayRequest>;
376
+ /**
377
+ * Asks the payRequest callback for an invoice or payment destination.
378
+ *
379
+ * `amountSat` is sats and is converted to millisats on the wire; it is
380
+ * range-checked locally against the payRequest bounds before any network
381
+ * call. `paymentOption` and `unit` are rejected on a session payRequest that
382
+ * does not advertise them: a live session's callback would silently ignore them.
383
+ * `verify` on the result is optional: the server omits it when the BOLT11
384
+ * payment hash will not decode.
385
+ *
386
+ * @param payRequest - The payRequest from `resolve`, with its source attached.
387
+ * @param opts - `amountSat` plus optional comment, rail and unit selection.
388
+ * @param fetchImpl - The injected `fetch` implementation to call.
389
+ * @returns A BOLT11 invoice or a destination to pay on the selected rail.
390
+ */
391
+ declare function requestInvoice(payRequest: PayRequest, opts: RequestInvoiceOptions, fetchImpl: FetchImpl): Promise<InvoiceResult>;
392
+ /**
393
+ * Whether a verify answer is about `expected`: a BOLT11 status for the same payment
394
+ * hash, or a destination status on the same rail and, when both name one, the same
395
+ * destination. The preimage check alone only proves the answer's own invoice.
396
+ */
397
+ declare function verifyStatusIsFor(status: VerifyStatus, expected: VerifyExpectation): boolean;
398
+ /**
399
+ * Polls a verify URL until the payment settles, the deadline passes, or the
400
+ * caller aborts.
401
+ *
402
+ * `verify` is optional on a callback response (the server omits it when the
403
+ * BOLT11 payment hash will not decode), so there is no polling without a URL
404
+ * and an empty one is rejected. A `{ status: "ERROR" }` body at HTTP 200 is
405
+ * terminal, not a retry: unknown payment hashes report `Not found` that way.
406
+ * Every snapshot, settled or not, goes to `onUpdate`; an overrun throws
407
+ * `LnurlTimeoutError` with the last snapshot attached.
408
+ *
409
+ * @param verifyUrl - The verify URL from the invoice result.
410
+ * @param opts - Optional interval, timeout, per-poll callback and abort signal.
411
+ * @param fetchImpl - The injected `fetch` implementation to call.
412
+ * @returns The settled verify status.
413
+ */
414
+ declare function pollVerify(verifyUrl: string, opts: PollVerifyOptions | undefined, fetchImpl: FetchImpl): Promise<VerifyStatus>;
415
+
416
+ /** One entry of the batch endpoint's `results` map, keyed by the verify URL. */
417
+ type VerifyBatchResultItem = {
418
+ kind: "verify";
419
+ status: VerifyStatus;
420
+ } | {
421
+ kind: "error";
422
+ reason: string;
423
+ };
424
+ interface VerifyBatchResult {
425
+ /** One entry per presented verify URL, keyed by the exact string the caller presented. */
426
+ results: Record<string, VerifyBatchResultItem>;
427
+ }
428
+ interface BatchVerifyOptions {
429
+ /** Abort the whole call. */
430
+ signal?: AbortSignal;
431
+ }
432
+ /**
433
+ * One-shot LUD-XX verifyBatch snapshot: N invoice statuses on one GET.
434
+ *
435
+ * `verifyBatchUrl` is the endpoint advertised alongside the verify URLs in the
436
+ * callback response; callers group pending invoices by that URL and issue one
437
+ * request per group. The `verify` URLs themselves are opaque and passed whole.
438
+ * A per-item error (`{status:"ERROR", reason}` inside `results`) is data, not a
439
+ * transport failure, so it is represented rather than thrown; a malformed
440
+ * request carries the top-level error shape and still throws.
441
+ */
442
+ declare function batchVerify(verifyBatchUrl: string, verifyUrls: readonly string[], opts?: BatchVerifyOptions, fetchImpl?: FetchImpl): Promise<VerifyBatchResult>;
443
+ interface OpenVerifyBatchStreamOptions {
444
+ /** The endpoint from the callback response's `verifyBatch` field. */
445
+ verifyBatchUrl: string;
446
+ /** Verify URLs pending at open; the endpoint covers exactly this set at first. */
447
+ verifyUrls: readonly string[];
448
+ /** Abort from the caller's side, triggering a clean close. */
449
+ signal?: AbortSignal;
450
+ }
451
+ interface VerifyBatchStreamHandlers {
452
+ /** Every verify-answer frame: the initial snapshot burst and later settlements. */
453
+ onUpdate?: (url: string, status: VerifyStatus) => void;
454
+ /** One call per removed URL; nothing further arrives for it. */
455
+ onRemoved?: (url: string) => void;
456
+ /** A stream failure other than a close the user initiated. */
457
+ onError?: (err: Error) => void;
458
+ /** Stream ended, cleanly or in failure. */
459
+ onClose?: () => void;
460
+ }
461
+ interface VerifyBatchStream {
462
+ /** The server's session for this stream; undefined until the session frame lands. */
463
+ readonly sessionId: string | undefined;
464
+ /**
465
+ * Adds and removes tracked verify URLs while the connection stays open. Each
466
+ * added URL is answered with one snapshot frame; each removed one with one
467
+ * `removed` frame. Throws when the stream has already ended.
468
+ */
469
+ update(verifyUrlsToAdd: readonly string[], verifyUrlsToRemove?: readonly string[]): void;
470
+ /** Ends the stream locally; safe to call more than once. */
471
+ close(): void;
472
+ }
473
+ /**
474
+ * Opens an LUD-XX verifyBatch stream on one connection: the endpoint reads the
475
+ * presented set, emits the snapshot burst, then pushes settlements live.
476
+ *
477
+ * A service without streaming answers the same request with the one-shot JSON
478
+ * snapshot (per LUD-01 the header is ignored, only 406 reaches a rejection):
479
+ * that body is still the current settlement state, so it is delivered through
480
+ * `onUpdate` before `onClose` and the caller falls back to polling.
481
+ */
482
+ declare function openVerifyBatchStream(opts: OpenVerifyBatchStreamOptions, handlers: VerifyBatchStreamHandlers, fetchImpl?: FetchImpl): VerifyBatchStream;
483
+
484
+ /**
485
+ * Options for opening a receiver session. Without a `token` the session is
486
+ * ephemeral: its id is random and dies with the socket, so there is nothing
487
+ * to reconnect to. Pass a token-derived `token` for a resumable session.
488
+ */
489
+ interface OpenSessionOptions {
490
+ /** Reusable token a session id is derived from; enables reconnect. */
491
+ token?: string;
492
+ /** Abort signal tearing down the stream and any pending reconnect wait. */
493
+ signal?: AbortSignal;
494
+ /** `false` disables reconnect; otherwise `{ maxAttempts?, baseDelayMs? }` with exponential backoff. */
495
+ reconnect?: false | {
496
+ maxAttempts?: number;
497
+ baseDelayMs?: number;
498
+ };
499
+ }
500
+ /**
501
+ * The two answers to a payer's invoice request, each `POST`ing to
502
+ * `/lnurl/session/:id/invoice` with the session Bearer token: either the
503
+ * BOLT11 invoice the payer should pay, or a rejection reason.
504
+ */
505
+ interface InvoiceResponder {
506
+ /**
507
+ * Answers the invoice request with a BOLT11 invoice.
508
+ *
509
+ * @param pr - The BOLT11 invoice the payer should pay.
510
+ * @returns A promise settling when the server accepts the invoice.
511
+ */
512
+ answerInvoice(pr: string): Promise<void>;
513
+ /**
514
+ * Rejects the invoice request with a payer-visible reason.
515
+ *
516
+ * @param reason - Why the request is refused.
517
+ * @returns A promise settling when the server accepts the rejection.
518
+ */
519
+ rejectInvoice(reason: string): Promise<void>;
520
+ }
521
+ /**
522
+ * Callbacks driving a receiver session. Only `onInvoiceRequest` is required:
523
+ * without it there is no way to mint the invoice each payer waits for.
524
+ */
525
+ interface SessionHandlers {
526
+ /**
527
+ * Called per payer invoice request; answer via `respond`.
528
+ *
529
+ * @param req - The requested `amountMsat` plus the payer `comment`, when one was sent.
530
+ * @param respond - Answers or rejects this specific request.
531
+ * @returns Nothing, or a promise whose rejection routes to `onError`.
532
+ */
533
+ onInvoiceRequest(req: {
534
+ amountMsat: number;
535
+ comment?: string;
536
+ }, respond: InvoiceResponder): void | Promise<void>;
537
+ /** Called with the parsed body of each `invoice_settled` frame. */
538
+ onSettled?(data: Record<string, unknown>): void;
539
+ /** Called with transport, parse and request failures; never throws back. */
540
+ onError?(err: Error): void;
541
+ /** Called with the 1-based count before each reconnect attempt. */
542
+ onReconnect?(attempt: number): void;
543
+ }
544
+ /**
545
+ * A live receiver session: the LNURL to display plus settlement reporting.
546
+ * Invoice creation stays caller-side: the client never holds keys or funds,
547
+ * it only ferries the payer's request to the caller's invoice provider.
548
+ */
549
+ interface LnurlSession {
550
+ /** Server-assigned session id, also the ownership key for LUD-16 addresses. */
551
+ readonly sessionId: string;
552
+ /** The LNURL to encode (QR, bech32) for payers. */
553
+ readonly lnurl: string;
554
+ /** Token owning this session; sent as the Bearer credential. */
555
+ readonly token: string;
556
+ /** Whether `close()` has been called. */
557
+ readonly closed: boolean;
558
+ /**
559
+ * Reports local settlement of an invoice for this session.
560
+ *
561
+ * Only valid while the session is connected: the server authenticates it
562
+ * against its live in-memory session map, so a dropped session must
563
+ * reconnect first or this is a 401.
564
+ *
565
+ * @param preimage - The payment preimage proving settlement.
566
+ * @returns A promise settling when the server records it.
567
+ */
568
+ reportSettled(preimage: string): Promise<void>;
569
+ /**
570
+ * Closes the session: stops reconnects and cancels the stream reader so an
571
+ * idle stream does not hang.
572
+ */
573
+ close(): void;
574
+ }
575
+ /**
576
+ * Opens a receiver session as POST-SSE over `fetch`, not `EventSource`.
577
+ *
578
+ * `EventSource` is GET-only and carries neither a JSON body nor an auth
579
+ * header, while the endpoint requires a `POST` with an optional `{ token }`
580
+ * body. The promise resolves on the first `session_created` frame carrying
581
+ * `{ sessionId, lnurl, token }`, not on the HTTP 200. Reconnect only happens
582
+ * when a `token` was supplied, because an ephemeral session id is random and
583
+ * dies with the socket; a 409 (id held by a different token) never retries.
584
+ * A null response body fails loudly instead of hanging.
585
+ *
586
+ * @param baseUrl - Server root, e.g. `https://lnurl.example.com`.
587
+ * @param opts - Optional token, abort signal and reconnect policy.
588
+ * @param handlers - Invoice, settlement, error and reconnect callbacks.
589
+ * @param fetchImpl - The injected `fetch` implementation to call.
590
+ * @returns The opened session once `session_created` arrives.
591
+ */
592
+ declare function openSession(baseUrl: string, opts: OpenSessionOptions, handlers: SessionHandlers, fetchImpl: FetchImpl): Promise<LnurlSession>;
593
+
594
+ /**
595
+ * Derives the session token from a raw private key.
596
+ *
597
+ * Produces exactly the same token as {@link deriveSessionTokenWithSigner},
598
+ * because it performs the same deterministic ECDSA signature itself — so a
599
+ * wallet can move between the two without losing ownership of its addresses.
600
+ *
601
+ * Prefer the signer form where an `Identity` is available: this one requires
602
+ * the caller to hand over key material, which a library should not need.
603
+ *
604
+ * @param privateKeyHex - Private key as a hex string.
605
+ * @param domain - The LUD-16 domain this token is for.
606
+ * @returns The session token as a hex string, valid only at that domain.
607
+ */
608
+ declare function deriveSessionToken(privateKeyHex: string, domain: string): string;
609
+ /**
610
+ * Derives the session token from a signer, so the private key never leaves the
611
+ * wallet. `@arkade-os/ts-sdk`'s `Identity` satisfies this structurally:
612
+ *
613
+ * ```ts
614
+ * const token = await deriveSessionTokenWithSigner(
615
+ * (msg, type) => identity.signMessage(msg, type),
616
+ * 'example.com',
617
+ * )
618
+ * ```
619
+ *
620
+ * **ECDSA specifically, and the type is passed for you.** BIP-340 schnorr is
621
+ * randomised unless an explicit aux is supplied, which `Identity.signMessage`
622
+ * does not expose — and schnorr is its *default* signature type. A schnorr
623
+ * signature is also 64 bytes, exactly like a compact ECDSA one, so nothing
624
+ * about the returned bytes reveals the mistake. A non-deterministic signer
625
+ * would mint a fresh token on every call and silently orphan the address, so
626
+ * this signs twice and compares rather than trusting the caller to have wired
627
+ * it correctly.
628
+ *
629
+ * @param signMessage - Signs a digest; called with `"ecdsa"` by this function.
630
+ * @param domain - The LUD-16 domain this token is for.
631
+ * @returns The session token as a hex string, identical to the key-derived one.
632
+ */
633
+ declare function deriveSessionTokenWithSigner(signMessage: (message: Uint8Array, signatureType: "ecdsa") => Promise<Uint8Array>, domain: string): Promise<string>;
634
+ /**
635
+ * Derives the session id from a token: the first 32 hex chars of
636
+ * `sha256(hexDecode(token))`, hashing the token's bytes, not its hex string.
637
+ *
638
+ * Must agree with the server's derivation (`src/session-token.ts`): the id is
639
+ * both the live session key and the ownership key for registered LUD-16
640
+ * lightning addresses, so a mismatch would orphan addresses and sessions.
641
+ *
642
+ * @param tokenHex - Session token as a hex string.
643
+ * @returns The 32-hex-char session id.
644
+ */
645
+ declare function deriveSessionId(tokenHex: string): string;
646
+
647
+ type LnurlSurface = "address" | "session";
648
+ /**
649
+ * Reports whether the input looks like a lightning address (`user@domain`).
650
+ *
651
+ * This is a shape check only; it never touches the network, so a well-formed
652
+ * but unregistered address still returns true here and fails at `resolve`.
653
+ *
654
+ * @param input - The raw user input to test.
655
+ * @returns True when the input has the `user@domain` shape.
656
+ */
657
+ declare function isLnAddress(input: string): boolean;
658
+ /**
659
+ * Reports whether the input is a bech32 LNURL that decodes to an http(s) URL.
660
+ *
661
+ * Decoded with an explicit 1023 limit because real LNURLs exceed bech32's
662
+ * 90-char default; mixed case is rejected per BIP-173, while an all-uppercase
663
+ * LNURL (what QR codes carry) still decodes fine.
664
+ *
665
+ * @param input - The raw user input to test.
666
+ * @returns True when the input is a well-formed LNURL.
667
+ */
668
+ declare function isLnUrl(input: string): boolean;
669
+ /**
670
+ * Reports whether the input is payable input of either shape: a lightning
671
+ * address or a bech32 LNURL.
672
+ *
673
+ * @param input - The raw user input to test.
674
+ * @returns True for a lightning address or a well-formed LNURL.
675
+ */
676
+ declare function isValidLnUrl(input: string): boolean;
677
+ /**
678
+ * Maps user input to the payRequest URL plus the surface it belongs to.
679
+ *
680
+ * A lightning address resolves against `https://domain/.well-known/lnurlp/user`
681
+ * with a lowercased username; a bech32 LNURL carries its own URL. The surface
682
+ * is `address` for `/.well-known/lnurlp/` URLs and `session` otherwise, which
683
+ * is what the payer rail guards are keyed off.
684
+ *
685
+ * @param input - A lightning address or bech32 LNURL.
686
+ * @returns The payRequest `url` and its `surface`.
687
+ */
688
+ declare function toPayRequestUrl(input: string): {
689
+ url: string;
690
+ surface: LnurlSurface;
691
+ };
692
+
693
+ /**
694
+ * What registering a LUD-16 lightning address needs. `token` owns the
695
+ * address: the server derives the session id from it and keys ownership off
696
+ * that id, so the same token lists and revokes what it registered.
697
+ */
698
+ interface RegisterAddressRequest {
699
+ /** Token owning the address; doubles as the Bearer credential. */
700
+ token: string;
701
+ /** Desired username; server-assigned when omitted. */
702
+ username?: string;
703
+ /** Claim code binding the registration, on domains that issue one. */
704
+ claimCode?: string;
705
+ /** Receiving domain; the server default when omitted. */
706
+ domain?: string;
707
+ /** Sent as `X-API-Key` on domains that require one. */
708
+ apiKey?: string;
709
+ /** Registers a nameless receiver instead; mutually exclusive with `username`/`claimCode`. */
710
+ nameless?: boolean;
711
+ }
712
+ /** A freshly registered LUD-16 lightning address and how to reach it. */
713
+ interface RegisteredAddress {
714
+ /** The `user@domain` address payers use; null for a nameless receiver. */
715
+ lightningAddress: string | null;
716
+ /** The bech32 LNURL encoding of the payRequest URL. */
717
+ lnurl: string;
718
+ /** Username part of the address; null for a nameless receiver. */
719
+ username: string | null;
720
+ /** The username, or the session id while nameless; changes on upgrade. */
721
+ handle: string;
722
+ /** Domain part of the address. */
723
+ domain: string;
724
+ /** Registration status reported by the server. */
725
+ status: string;
726
+ nameless: boolean;
727
+ sessionLnurl: string | null;
728
+ }
729
+ /** One address owned by a token, as listed by the server; same nullability as `RegisteredAddress`. */
730
+ interface AddressListEntry {
731
+ username: string | null;
732
+ /** Domain part of the address. */
733
+ domain: string;
734
+ /** Registration status reported by the server. */
735
+ status: string;
736
+ /** Creation timestamp reported by the server. */
737
+ createdAt: number;
738
+ lightningAddress: string | null;
739
+ /** The bech32 LNURL encoding of the payRequest URL. */
740
+ lnurl: string;
741
+ handle: string;
742
+ nameless: boolean;
743
+ /** Survives a later upgrade to a name. */
744
+ sessionLnurl: string | null;
745
+ }
746
+ /** What a domain allows, discoverable before calling any of its routes. */
747
+ interface DomainCapabilities {
748
+ domain: string;
749
+ allocationModes: string[];
750
+ usernameRules: {
751
+ minLen: number;
752
+ maxLen: number;
753
+ pattern: string;
754
+ };
755
+ requireApiKey: boolean;
756
+ }
757
+ /**
758
+ * What binding an Arkade identity to an address needs. `claimPublicKey` must
759
+ * be a compressed 33-byte key and is checked locally; the Arkade address
760
+ * itself is NOT validated client-side because that would need the SDK, which
761
+ * is deliberately not a dependency.
762
+ */
763
+ interface RegisterArkadeIdentityRequest {
764
+ /** Token owning the address; sent as the Bearer credential. */
765
+ token: string;
766
+ /** Handle of the already-registered address. */
767
+ handle: string;
768
+ /** Arkade address receiving offline payments; validated server-side. */
769
+ arkadeAddress: string;
770
+ /** Compressed 33-byte public key: `02`/`03` prefix plus 64 hex chars. */
771
+ claimPublicKey: string;
772
+ /** Boarding address the onchain rail pays; omit it to leave a registered one alone. */
773
+ boardingAddress?: string;
774
+ /** Receiving domain; the server default when omitted. */
775
+ domain?: string;
776
+ }
777
+ /**
778
+ * Registers a LUD-16 lightning address owned by `req.token`.
779
+ *
780
+ * @param baseUrl - Server root, e.g. `https://lnurl.example.com`.
781
+ * @param req - Token, optional username/claimCode/domain, and optional API key.
782
+ * @param fetchImpl - The injected `fetch` implementation to call.
783
+ * @returns The registered address and how to reach it.
784
+ */
785
+ declare function registerAddress(baseUrl: string, req: RegisterAddressRequest, fetchImpl: FetchImpl): Promise<RegisteredAddress>;
786
+ /**
787
+ * Lists the LUD-16 addresses owned by a token.
788
+ *
789
+ * @param baseUrl - Server root, e.g. `https://lnurl.example.com`.
790
+ * @param token - Token whose addresses to list; sent as the Bearer credential.
791
+ * @param fetchImpl - The injected `fetch` implementation to call.
792
+ * @returns The addresses owned by the token.
793
+ */
794
+ declare function listAddresses(baseUrl: string, token: string, fetchImpl: FetchImpl): Promise<AddressListEntry[]>;
795
+ /** Upgrades a nameless receiver in place to a named one; everything handed out while nameless keeps working. */
796
+ declare function upgradeAddress(baseUrl: string, req: {
797
+ token: string;
798
+ handle: string;
799
+ username?: string;
800
+ claimCode?: string;
801
+ domain?: string;
802
+ }, fetchImpl: FetchImpl): Promise<RegisteredAddress>;
803
+ declare function domainCapabilities(baseUrl: string, opts: {
804
+ domain?: string;
805
+ } | undefined, fetchImpl: FetchImpl): Promise<DomainCapabilities>;
806
+ /**
807
+ * Lists the payments made to one address owned by a token, oldest first.
808
+ *
809
+ * @param baseUrl - Server root, e.g. `https://lnurl.example.com`.
810
+ * @param token - Token owning the address; sent as the Bearer credential.
811
+ * @param handle - Handle of the address whose payments to list.
812
+ * @param opts - Optional domain, inclusive since cursor and page limit.
813
+ * @param fetchImpl - The injected `fetch` implementation to call.
814
+ * @returns The payment page with rail-discriminated activity entries.
815
+ */
816
+ declare function listPayments(baseUrl: string, token: string, handle: string, opts: {
817
+ domain?: string;
818
+ since?: number;
819
+ limit?: number;
820
+ } | undefined, fetchImpl: FetchImpl): Promise<PaymentPage>;
821
+ /**
822
+ * Revokes one address owned by a token.
823
+ *
824
+ * @param baseUrl - Server root, e.g. `https://lnurl.example.com`.
825
+ * @param token - Token owning the address; sent as the Bearer credential.
826
+ * @param handle - Handle of the address to revoke.
827
+ * @param opts - Optional domain scoping the revocation.
828
+ * @param fetchImpl - The injected `fetch` implementation to call.
829
+ * @returns A promise settling when the server revokes the address.
830
+ */
831
+ declare function revokeAddress(baseUrl: string, token: string, handle: string, opts: {
832
+ domain?: string;
833
+ } | undefined, fetchImpl: FetchImpl): Promise<void>;
834
+ /**
835
+ * Binds an Arkade identity to a registered address for offline receive.
836
+ *
837
+ * `claimPublicKey` must be a compressed 33-byte key and is rejected locally
838
+ * before any network call; the Arkade address itself is NOT validated
839
+ * client-side because that would need the SDK, which is deliberately not a
840
+ * dependency, so a malformed one fails server-side instead.
841
+ *
842
+ * `boardingAddress` is unvalidated for a stronger reason — it is a Bitcoin
843
+ * address on the operator's network, which this package cannot know — and
844
+ * omitting it sends no field, read server-side as "leave the onchain rail".
845
+ *
846
+ * @param baseUrl - Server root, e.g. `https://lnurl.example.com`.
847
+ * @param req - Token, handle, Arkade address, claim key, optional boarding address and domain.
848
+ * @param fetchImpl - The injected `fetch` implementation to call.
849
+ * @returns A promise settling when the server records the identity.
850
+ */
851
+ declare function registerArkadeIdentity(baseUrl: string, req: RegisterArkadeIdentityRequest, fetchImpl: FetchImpl): Promise<void>;
852
+
853
+ /**
854
+ * One synced payment row, keyed by server plus server-local identifier.
855
+ * Identifiers are unique per server, not globally, so the key scopes them.
856
+ */
857
+ interface StoredPayment {
858
+ /** `${baseUrl}|${identifier}` — identifiers are unique per server, not globally. */
859
+ key: string;
860
+ /** Server root the payment was synced from. */
861
+ baseUrl: string;
862
+ /** Domain serving the address, taken from the page source. */
863
+ domain: string;
864
+ /** Full `user@domain` address, taken from the page source; null when nameless. */
865
+ lightningAddress: string | null;
866
+ /** The username, or the session id while nameless, taken from the page source. */
867
+ handle: string;
868
+ /** paymentHash for bolt11, verifyId for destination. */
869
+ identifier: string;
870
+ /** Which rail the payment arrived on. */
871
+ kind: "bolt11" | "destination";
872
+ /** Whether the payment has settled. */
873
+ settled: boolean;
874
+ /** Agreed amount in millisats, when recorded. */
875
+ amountMsat: number | null;
876
+ /** Creation timestamp in milliseconds. */
877
+ createdAt: number;
878
+ /** Settlement timestamp in milliseconds, null while pending. */
879
+ settledAt: number | null;
880
+ /** RFQ id when a bolt11 payment was an offline swap, null otherwise. */
881
+ swapId: string | null;
882
+ /** Arkade txid once observed on a destination payment, null otherwise. */
883
+ paymentReference: string | null;
884
+ /** Arkade txid that credited the owner's own address, on any rail — the one
885
+ * their wallet can match against its own transaction history. */
886
+ payoutReference: string | null;
887
+ /** Preimage once a bolt11 payment settled; null while pending and on the
888
+ * destination rail, which has no invoice to prove. */
889
+ preimage: string | null;
890
+ /** The rail a destination payment settled on, e.g. `arkade`. Null on the
891
+ * bolt11 rail, where `kind` already says which rail it was. */
892
+ paymentOption: string | null;
893
+ /** Per-payment covenant script when the server derived one, else null. The
894
+ * attribution key for concurrent covenant payments, and what a consumer
895
+ * verifying the payment on-chain has to match against. */
896
+ covenantScript: string | null;
897
+ }
898
+ /**
899
+ * The persistence the sync loop needs. The package ships no implementation:
900
+ * IndexedDB does not exist in Node or React Native, so the consumer supplies
901
+ * the store — exactly as it already supplies `fetchImpl`. `upsert` is a
902
+ * primitive rather than read-then-write so a database-backed store can do it
903
+ * in one statement instead of loading every record on every sync.
904
+ */
905
+ interface PaymentSyncStore {
906
+ /** Insert or replace by `record.key`. MUST overwrite, never append. */
907
+ upsert(records: StoredPayment[]): Promise<void>;
908
+ /** Last good inclusive cursor for one address, undefined when never synced. */
909
+ readWatermark(baseUrl: string, lightningAddress: string): Promise<number | undefined>;
910
+ /** Persists the inclusive cursor after a page is upserted; it moves backwards. */
911
+ writeWatermark(baseUrl: string, lightningAddress: string, since: number): Promise<void>;
912
+ }
913
+ /**
914
+ * One address to sync: where it lives and whose payments to list.
915
+ */
916
+ interface PaymentSyncTarget {
917
+ /** Server root serving the address. */
918
+ baseUrl: string;
919
+ /** Token owning the address; sent as the Bearer credential. */
920
+ token: string;
921
+ /** The username, or the session id while nameless; the sync watermark is keyed off it. */
922
+ handle: string;
923
+ /** Domain part of the address. */
924
+ domain: string;
925
+ }
926
+ /**
927
+ * Syncs payment activity for every target into the consumer-supplied store.
928
+ *
929
+ * Each target paginates while a page comes back full
930
+ * (`payments.length === limit`); a short page ends that target. The watermark
931
+ * is written only after a page is successfully upserted, so a target that fails
932
+ * wholly keeps its old cursor. It holds the oldest row still waiting to settle,
933
+ * not the newest `createdAt`, because `settled` mutates after a row is created;
934
+ * it reaches one page back at most, so a row nothing will ever settle costs one
935
+ * extra page per sync rather than re-paging the history. Pagination itself still
936
+ * walks `nextSince` forward. `nextSince` is inclusive, so the boundary row is
937
+ * deliberately re-fetched and the store's key-overwrite absorbs it — the loop
938
+ * itself never dedupes. Only `LnurlError.retryable` (HTTP 429) is retried;
939
+ * anything else is terminal. A full page that leaves the cursor where it was
940
+ * fails that target instead of re-fetching itself forever. A failing target is
941
+ * collected into `failures` and the loop continues with the next one; this
942
+ * function never throws.
943
+ *
944
+ * `client` is a factory rather than a single client because a client is pinned
945
+ * to one `baseUrl`, while targets may live on different servers. Sharing one
946
+ * would send every target's bearer token to whichever server that client was
947
+ * built for:
948
+ *
949
+ * ```ts
950
+ * await syncPayments(targets, {
951
+ * client: (baseUrl) => createLnurlClient({ baseUrl }),
952
+ * store,
953
+ * })
954
+ * ```
955
+ *
956
+ * @param targets - Addresses to sync, each bound to its serving baseUrl.
957
+ * @param opts - Builds the client for one server, the store to write to, and an optional page limit.
958
+ * @returns `synced` counts every row upserted, including rows a target stored
959
+ * on earlier pages before failing on a later one — so it always
960
+ * matches what is in the store. Such a target also appears in
961
+ * `failures`, meaning a non-zero `synced` and a failure can coexist.
962
+ */
963
+ declare function syncPayments(targets: PaymentSyncTarget[], opts: {
964
+ client: (baseUrl: string) => Pick<LnurlClient, "listPayments">;
965
+ store: PaymentSyncStore;
966
+ limit?: number;
967
+ }): Promise<{
968
+ synced: number;
969
+ failures: {
970
+ baseUrl: string;
971
+ error: unknown;
972
+ }[];
973
+ }>;
974
+
975
+ /** A CAIP-19 asset id, split. Its CAIP-2 prefix is the chain. */
976
+ interface TokenAsset {
977
+ id: string;
978
+ chainId: string;
979
+ namespace: string;
980
+ chainReference: string;
981
+ assetNamespace: string;
982
+ reference: string;
983
+ }
984
+ /** A `units[]` entry a token option is quoted in. */
985
+ interface TokenUnit {
986
+ code: string;
987
+ decimals: number;
988
+ name?: string;
989
+ }
990
+ /** A payment option for a token on a non-Bitcoin chain, as `tokenOptions` accepts one. */
991
+ interface TokenOption {
992
+ id: string;
993
+ asset: TokenAsset;
994
+ unit: TokenUnit;
995
+ /** False only when the payRequest says the option is down right now. */
996
+ available: boolean;
997
+ verifiable?: boolean;
998
+ minSendable?: number;
999
+ maxSendable?: number;
1000
+ /** The third party the payer hands the token to, e.g. "FixedFloat". */
1001
+ provider?: string;
1002
+ }
1003
+ /** True when `address` is a recipient on chains of the given CAIP-2 namespace. */
1004
+ declare function isTokenAddress(namespace: string, address: string): boolean;
1005
+ /**
1006
+ * The payRequest's token options, parsed exactly as the BTCPay LNURLVerify plugin parses
1007
+ * them (TokenOption.cs), so a wallet and a checkout agree on what is on offer.
1008
+ *
1009
+ * An option is dropped when its `asset` is not a CAIP-19 id of a namespace a payment can
1010
+ * be built for, when its `type` is not that namespace, when its `unit` names no `units[]`
1011
+ * entry, and, with every option sharing it, when its `id` is not unique.
1012
+ */
1013
+ declare function tokenOptions(payRequest: Pick<PayRequest, "paymentOptions" | "units">): TokenOption[];
1014
+
1015
+ /** A `PaymentSyncStore` over `localStorage`. Synchronous, a few megabytes, and it
1016
+ * rewrites every record per upsert — back a real wallet with IndexedDB instead. */
1017
+ declare function browserPaymentStore(prefix?: string): PaymentSyncStore;
1018
+ /** Everything synced for one address, newest first. A nameless receiver has no
1019
+ * lightning address to match on, so name it by `{ domain, handle }` instead. */
1020
+ declare function storedPayments(address: string | {
1021
+ domain: string;
1022
+ handle: string;
1023
+ }, prefix?: string): StoredPayment[];
1024
+ declare function forgetStoredPayments(prefix?: string): void;
1025
+
1026
+ /**
1027
+ * Options for `createLnurlClient`. Everything is optional: payer-only
1028
+ * callers omit `baseUrl` entirely and inject nothing when the global `fetch`
1029
+ * will do.
1030
+ */
1031
+ interface LnurlClientOptions {
1032
+ /**
1033
+ * Server root, needed ONLY for receiver/management calls (`openSession`,
1034
+ * `registerAddress`, `listAddresses`, `revokeAddress`,
1035
+ * `registerArkadeIdentity`). The payer surface is host-agnostic — an
1036
+ * address resolves against its own domain and a bech32 LNURL against its
1037
+ * decoded URL — so `createLnurlClient()` with no argument is valid for
1038
+ * payer-only use. Those methods throw `LnurlError` when it is missing.
1039
+ */
1040
+ baseUrl?: string;
1041
+ /**
1042
+ * `fetch` implementation to call. Defaults to resolving `globalThis.fetch`
1043
+ * per call, not once at construction, so a client built at module scope
1044
+ * still sees a fetch installed later (mock, polyfill, service worker).
1045
+ */
1046
+ fetchImpl?: FetchImpl;
1047
+ }
1048
+ /**
1049
+ * The single facade both roles use: host-agnostic payer calls plus
1050
+ * `baseUrl`-bound receiver/management calls sharing one `fetch`.
1051
+ */
1052
+ interface LnurlClient {
1053
+ /**
1054
+ * Fetches the payRequest for a lightning address or bech32 LNURL.
1055
+ *
1056
+ * @param input - A lightning address or bech32 LNURL.
1057
+ * @returns The payRequest with its fetch source attached.
1058
+ */
1059
+ resolve(input: string): Promise<PayRequest>;
1060
+ /**
1061
+ * Asks the payRequest callback for an invoice or payment destination.
1062
+ *
1063
+ * @param payRequest - The payRequest from `resolve`.
1064
+ * @param opts - `amountSat` plus optional comment, rail and unit selection.
1065
+ * @returns A BOLT11 invoice or a destination to pay on the selected rail.
1066
+ */
1067
+ requestInvoice(payRequest: PayRequest, opts: RequestInvoiceOptions): Promise<InvoiceResult>;
1068
+ /**
1069
+ * Polls a verify URL until the payment settles, the deadline passes, or the
1070
+ * caller aborts.
1071
+ *
1072
+ * @param verifyUrl - The verify URL from the invoice result.
1073
+ * @param opts - Optional interval, timeout, per-poll callback and abort signal.
1074
+ * @returns The settled verify status.
1075
+ */
1076
+ pollVerify(verifyUrl: string, opts?: PollVerifyOptions): Promise<VerifyStatus>;
1077
+ /**
1078
+ * One-shot LUD-XX verifyBatch: N invoice statuses on one GET.
1079
+ *
1080
+ * @param verifyBatchUrl - The endpoint advertised next to the verify URLs.
1081
+ * @param verifyUrls - The verify URLs currently pending, grouped by endpoint.
1082
+ * @param opts - Optional abort signal and `fetch` override.
1083
+ */
1084
+ batchVerify(verifyBatchUrl: string, verifyUrls: readonly string[], opts?: BatchVerifyOptions & {
1085
+ fetchImpl?: FetchImpl;
1086
+ }): Promise<VerifyBatchResult>;
1087
+ /**
1088
+ * Opens a receiver session as POST-SSE; resolves on `session_created`.
1089
+ * Requires `baseUrl`.
1090
+ *
1091
+ * @param opts - Optional token, abort signal and reconnect policy.
1092
+ * @param handlers - Invoice, settlement, error and reconnect callbacks.
1093
+ * @returns The opened session once `session_created` arrives.
1094
+ */
1095
+ openSession(opts: OpenSessionOptions, handlers: SessionHandlers): Promise<LnurlSession>;
1096
+ /**
1097
+ * LUD-XX verifyBatch stream: snapshot burst first, then live settlements, and
1098
+ * in-place tracked-set updates without reopening the connection.
1099
+ *
1100
+ * @param opts - Endpoint plus the initially pending verify URLs.
1101
+ * @param handlers - Frame, removal and close callbacks.
1102
+ */
1103
+ openVerifyBatchStream(opts: OpenVerifyBatchStreamOptions & {
1104
+ fetchImpl?: FetchImpl;
1105
+ }, handlers: VerifyBatchStreamHandlers): VerifyBatchStream;
1106
+ /**
1107
+ * Registers a LUD-16 lightning address. Requires `baseUrl`.
1108
+ *
1109
+ * @param req - Token, optional username/claimCode/domain, and optional API key.
1110
+ * @returns The registered address and how to reach it.
1111
+ */
1112
+ registerAddress(req: RegisterAddressRequest): Promise<RegisteredAddress>;
1113
+ upgradeAddress(req: {
1114
+ token: string;
1115
+ handle: string;
1116
+ username?: string;
1117
+ claimCode?: string;
1118
+ domain?: string;
1119
+ }): Promise<RegisteredAddress>;
1120
+ domainCapabilities(opts?: {
1121
+ domain?: string;
1122
+ }): Promise<DomainCapabilities>;
1123
+ /**
1124
+ * Lists the LUD-16 addresses owned by a token. Requires `baseUrl`.
1125
+ *
1126
+ * @param token - Token whose addresses to list.
1127
+ * @returns The addresses owned by the token.
1128
+ */
1129
+ listAddresses(token: string): Promise<AddressListEntry[]>;
1130
+ /**
1131
+ * Revokes one address owned by a token. Requires `baseUrl`.
1132
+ *
1133
+ * @param token - Token owning the address.
1134
+ * @param handle - Handle of the address to revoke.
1135
+ * @param opts - Optional domain scoping the revocation.
1136
+ * @returns A promise settling when the server revokes the address.
1137
+ */
1138
+ revokeAddress(token: string, handle: string, opts?: {
1139
+ domain?: string;
1140
+ }): Promise<void>;
1141
+ /**
1142
+ * Binds an Arkade identity to a registered address. Requires `baseUrl`.
1143
+ *
1144
+ * @param req - Token, handle, Arkade address, claim key, optional boarding address and domain.
1145
+ * @returns A promise settling when the server records the identity.
1146
+ */
1147
+ registerArkadeIdentity(req: RegisterArkadeIdentityRequest): Promise<void>;
1148
+ /**
1149
+ * Lists the payments made to one address owned by a token. Requires `baseUrl`.
1150
+ *
1151
+ * @param token - Token owning the address.
1152
+ * @param handle - Handle of the address whose payments to list.
1153
+ * @param opts - Optional domain, inclusive since cursor and page limit.
1154
+ * @returns The payment page with rail-discriminated activity entries.
1155
+ */
1156
+ listPayments(token: string, handle: string, opts?: {
1157
+ domain?: string;
1158
+ since?: number;
1159
+ limit?: number;
1160
+ }): Promise<PaymentPage>;
1161
+ }
1162
+ /**
1163
+ * Creates the client both roles share.
1164
+ *
1165
+ * `baseUrl` is receiver-side state only: the payer surface resolves against
1166
+ * the address domain or the decoded LNURL, so payer-only callers pass nothing
1167
+ * and only the receiver/management methods demand it. The default `fetch`
1168
+ * resolves `globalThis.fetch` per call, not once at construction, so a client
1169
+ * built at module scope still sees a fetch installed later.
1170
+ *
1171
+ * @param opts - Optional `baseUrl` and `fetchImpl`.
1172
+ * @returns A client sharing one resolved `fetch` across both roles.
1173
+ */
1174
+ declare function createLnurlClient(opts?: LnurlClientOptions): LnurlClient;
1175
+
1176
+ export { type AddressListEntry, type AmountObject, type BatchVerifyOptions, type Bolt11Activity, type Bolt11Result, type Bolt11VerifyStatus, type DestinationActivity, type DestinationResult, type DestinationVerifyStatus, type DomainCapabilities, type FetchImpl, type InvoiceResponder, type InvoiceResult, type LnurlClient, type LnurlClientOptions, LnurlError, type LnurlSession, type LnurlSurface, LnurlTimeoutError, LnurlTransportError, type OpenSessionOptions, type OpenVerifyBatchStreamOptions, type PayRequest, type PaymentActivity, type PaymentOption, type PaymentPage, type PaymentQuote, type PaymentSyncStore, type PaymentSyncTarget, type PollVerifyOptions, type RegisterAddressRequest, type RegisterArkadeIdentityRequest, type RegisteredAddress, type RequestInvoiceOptions, type SessionHandlers, type StoredPayment, type TokenAsset, type TokenOption, type TokenUnit, type Unit, type VerifyBatchResult, type VerifyBatchResultItem, type VerifyBatchStream, type VerifyBatchStreamHandlers, type VerifyExpectation, type VerifyStatus, batchVerify, browserPaymentStore, createLnurlClient, deriveSessionId, deriveSessionToken, deriveSessionTokenWithSigner, domainCapabilities, forgetStoredPayments, isLnAddress, isLnUrl, isTokenAddress, isValidLnUrl, listAddresses, listPayments, openSession, openVerifyBatchStream, pollVerify, registerAddress, registerArkadeIdentity, requestInvoice, resolve, revokeAddress, storedPayments, syncPayments, toPayRequestUrl, tokenOptions, upgradeAddress, verifyStatusIsFor };