@openreceive/node 0.3.2 → 0.3.3

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.
@@ -1,3 +1,946 @@
1
+ // src/nwc/errors.ts
2
+ import {
3
+ isErrorCode,
4
+ isRetryableErrorCode,
5
+ OpenReceiveError
6
+ } from "@openreceive/core";
7
+ var WalletPreflightError = class extends Error {
8
+ code;
9
+ summary;
10
+ constructor(code, message, summary) {
11
+ super(message);
12
+ this.name = "WalletPreflightError";
13
+ this.code = code;
14
+ this.summary = summary;
15
+ }
16
+ };
17
+ var ReceiveCheckoutValidationError = class extends Error {
18
+ constructor(message) {
19
+ super(message);
20
+ this.name = "ReceiveCheckoutValidationError";
21
+ }
22
+ };
23
+ var NWC_ERROR_CODE_ALIASES = {
24
+ ABORT_ERROR: "TIMEOUT",
25
+ BAD_REQUEST: "INVALID_REQUEST",
26
+ CONNECTION_ERROR: "WALLET_UNAVAILABLE",
27
+ EXPIRED: "INVOICE_EXPIRED",
28
+ FETCH_ERROR: "WALLET_UNAVAILABLE",
29
+ FORBIDDEN: "RESTRICTED",
30
+ INVOICE_NOT_FOUND: "NOT_FOUND",
31
+ INVALID_PARAMETER: "INVALID_REQUEST",
32
+ INVALID_PARAMETERS: "INVALID_REQUEST",
33
+ INVALID_PARAMS: "INVALID_REQUEST",
34
+ METHOD_NOT_FOUND: "UNSUPPORTED_METHOD",
35
+ NETWORK_ERROR: "WALLET_UNAVAILABLE",
36
+ NIP47_NETWORK_ERROR: "WALLET_UNAVAILABLE",
37
+ NOSTR_NETWORK_ERROR: "WALLET_UNAVAILABLE",
38
+ NOT_AUTHORIZED: "UNAUTHORIZED",
39
+ NOT_SUPPORTED: "UNSUPPORTED_METHOD",
40
+ NOTFOUND: "NOT_FOUND",
41
+ PERMISSION_DENIED: "RESTRICTED",
42
+ RELAY_CONNECTION_ERROR: "WALLET_UNAVAILABLE",
43
+ REQUEST_TIMEOUT: "TIMEOUT",
44
+ SERVICE_UNAVAILABLE: "WALLET_UNAVAILABLE",
45
+ TIMED_OUT: "TIMEOUT",
46
+ TIMEOUT_ERROR: "TIMEOUT",
47
+ UNKNOWN_METHOD: "UNSUPPORTED_METHOD",
48
+ UNSUPPORTED: "UNSUPPORTED_METHOD",
49
+ UNSUPPORTED_ENCRYPTION_MODE: "UNSUPPORTED_ENCRYPTION",
50
+ WALLET_OFFLINE: "WALLET_UNAVAILABLE",
51
+ WALLET_UNREACHABLE: "WALLET_UNAVAILABLE"
52
+ };
53
+ var OPENRECEIVE_ERROR_MESSAGES = {
54
+ NOT_IMPLEMENTED: "NWC wallet service does not implement this method.",
55
+ RESTRICTED: "NWC wallet service restricted this request.",
56
+ UNAUTHORIZED: "NWC wallet service rejected authorization.",
57
+ FORBIDDEN: "The host application did not authorize this request.",
58
+ RATE_LIMITED: "NWC wallet service rate limited this request.",
59
+ QUOTA_EXCEEDED: "NWC wallet service quota was exceeded.",
60
+ INTERNAL: "NWC wallet service returned an internal error.",
61
+ UNSUPPORTED_ENCRYPTION: "NWC wallet service does not support the required encryption mode.",
62
+ OTHER: "NWC wallet service returned an unknown error.",
63
+ NOT_FOUND: "NWC wallet service could not find the requested resource.",
64
+ TIMEOUT: "NWC wallet service request timed out.",
65
+ INVALID_REQUEST: "OpenReceive sent an invalid NWC wallet request.",
66
+ WALLET_UNAVAILABLE: "NWC wallet service is unavailable.",
67
+ INVOICE_EXPIRED: "NWC wallet reported that the invoice is expired.",
68
+ UNSUPPORTED_METHOD: "NWC wallet service does not support the requested method.",
69
+ CONFLICT: "NWC wallet service reported a conflicting request."
70
+ };
71
+ function normalizeNwcWalletError(error) {
72
+ if (error instanceof OpenReceiveError) return error;
73
+ const records = collectErrorRecords(error);
74
+ const code = knownErrorCode(error) ?? errorCodeFromRecords(records) ?? (typeof error === "string" ? normalizeNwcErrorCode(error) : void 0) ?? "OTHER";
75
+ const message = errorMessageFromRecords(records, error, code);
76
+ const retryable = firstBooleanField(records, ["retryable"]) ?? isRetryableErrorCode(code);
77
+ const requestId = firstStringField(records, ["request_id", "requestId"]);
78
+ const details = firstRecordField(records, ["details"]);
79
+ const body = {
80
+ code,
81
+ message,
82
+ retryable,
83
+ ...requestId === void 0 ? {} : { request_id: requestId },
84
+ ...details === void 0 ? {} : { details }
85
+ };
86
+ return new OpenReceiveError(body, { cause: error });
87
+ }
88
+ function knownErrorCode(error) {
89
+ if (error instanceof ReceiveCheckoutValidationError) {
90
+ return "INVALID_REQUEST";
91
+ }
92
+ if (error instanceof WalletPreflightError) {
93
+ if (error.code === "missing_required_method") return "UNSUPPORTED_METHOD";
94
+ if (error.code === "spend_capability_advertised") return "RESTRICTED";
95
+ if (error.code === "unsupported_encryption") return "UNSUPPORTED_ENCRYPTION";
96
+ return "WALLET_UNAVAILABLE";
97
+ }
98
+ return void 0;
99
+ }
100
+ function errorCodeFromRecords(records) {
101
+ for (const record of records) {
102
+ const directCode = normalizeNwcErrorCode(record.code) ?? normalizeNwcErrorCode(record.error_code) ?? normalizeNwcErrorCode(record.errorCode) ?? normalizeNwcErrorCode(record.type);
103
+ if (directCode !== void 0 && directCode !== "OTHER") return directCode;
104
+ const nameCode = normalizeNwcErrorCode(record.name);
105
+ if (nameCode !== void 0 && nameCode !== "OTHER") return nameCode;
106
+ if (directCode !== void 0) return directCode;
107
+ }
108
+ return void 0;
109
+ }
110
+ function normalizeNwcErrorCode(value) {
111
+ if (typeof value !== "string" || value.trim().length === 0) return void 0;
112
+ const normalized = normalizeNwcErrorCodeText(value);
113
+ return NWC_ERROR_CODE_ALIASES[normalized] ?? (isErrorCode(normalized) ? normalized : void 0);
114
+ }
115
+ function normalizeNwcErrorCodeText(value) {
116
+ return value.trim().replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
117
+ }
118
+ function errorMessageFromRecords(records, error, code) {
119
+ const message = firstStringField(records, ["message", "description", "reason"]);
120
+ if (message !== void 0 && normalizeNwcErrorCode(message) !== code) {
121
+ return message;
122
+ }
123
+ if (typeof error === "string" && normalizeNwcErrorCode(error) === void 0) {
124
+ const trimmed = error.trim();
125
+ if (trimmed.length > 0) return trimmed;
126
+ }
127
+ return OPENRECEIVE_ERROR_MESSAGES[code];
128
+ }
129
+ function collectErrorRecords(value) {
130
+ const records = [];
131
+ collectErrorRecordsInto(value, records, /* @__PURE__ */ new Set());
132
+ return records;
133
+ }
134
+ function collectErrorRecordsInto(value, records, seen) {
135
+ if (typeof value !== "object" || value === null || seen.has(value)) return;
136
+ seen.add(value);
137
+ const record = value;
138
+ records.push(record);
139
+ for (const key of ["error", "result", "cause", "data"]) {
140
+ collectErrorRecordsInto(record[key], records, seen);
141
+ }
142
+ }
143
+ function firstStringField(records, fields) {
144
+ for (const record of records) {
145
+ for (const field of fields) {
146
+ const value = record[field];
147
+ if (typeof value === "string" && value.trim().length > 0) {
148
+ return value;
149
+ }
150
+ }
151
+ }
152
+ return void 0;
153
+ }
154
+ function firstBooleanField(records, fields) {
155
+ for (const record of records) {
156
+ for (const field of fields) {
157
+ const value = record[field];
158
+ if (typeof value === "boolean") return value;
159
+ }
160
+ }
161
+ return void 0;
162
+ }
163
+ function firstRecordField(records, fields) {
164
+ for (const record of records) {
165
+ for (const field of fields) {
166
+ const value = record[field];
167
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
168
+ return value;
169
+ }
170
+ }
171
+ }
172
+ return void 0;
173
+ }
174
+
175
+ // src/alby-nwc.ts
176
+ import {
177
+ compact,
178
+ formatSpendCapabilityRefusedMessage,
179
+ formatSpendCapabilityWarningMessage,
180
+ OpenReceiveError as OpenReceiveError2,
181
+ parseNwcUri
182
+ } from "@openreceive/core";
183
+
184
+ // src/nwc/normalize.ts
185
+ import {
186
+ OPENRECEIVE_MAX_AMOUNT_MSATS,
187
+ OPENRECEIVE_MIN_AMOUNT_MSATS,
188
+ OPENRECEIVE_NWC_METADATA_MAX_BYTES,
189
+ nonEmptyString,
190
+ recordOrEmpty
191
+ } from "@openreceive/core";
192
+
193
+ // src/hex.ts
194
+ var HEX_64 = /^[0-9a-fA-F]{64}$/;
195
+
196
+ // src/nwc/normalize.ts
197
+ var REQUIRED_RECEIVE_METHODS = ["make_invoice", "list_transactions"];
198
+ var SPEND_METHODS = [
199
+ "pay_invoice",
200
+ "multi_pay_invoice",
201
+ "pay_keysend",
202
+ "multi_pay_keysend"
203
+ ];
204
+ function summarizeWalletCapabilities(connection, rawInfo, rawServiceInfo) {
205
+ const unwrappedInfo = unwrapNwcResult(rawInfo);
206
+ const info = recordOrEmpty(unwrappedInfo);
207
+ const serviceInfo = rawServiceInfo === void 0 ? void 0 : recordOrEmpty(unwrapNwcResult(rawServiceInfo));
208
+ const methods = normalizeStringList(
209
+ info.methods ?? info.capabilities ?? info.supported_methods ?? info.supportedMethods ?? (typeof unwrappedInfo === "string" ? unwrappedInfo : void 0)
210
+ ).map(normalizeNwcMethodName);
211
+ const encryption = chooseEncryptionMode(
212
+ normalizeStringList(
213
+ serviceInfo?.encryption ?? serviceInfo?.encryptions ?? info.encryption ?? info.encryptions
214
+ )
215
+ );
216
+ const spendMethods = spendMethodsIn(methods);
217
+ const missingMethods = REQUIRED_RECEIVE_METHODS.filter((method) => !methods.includes(method));
218
+ const warnings = spendMethods.map(
219
+ (method) => `Wallet advertises spend method '${method}'; OpenReceive checkout will not expose it.`
220
+ );
221
+ return {
222
+ walletPubkey: connection.walletPubkey,
223
+ relays: [...connection.relays],
224
+ methods,
225
+ encryption,
226
+ spendCapabilityAdvertised: spendMethods.length > 0,
227
+ receiveCheckoutReady: missingMethods.length === 0,
228
+ warnings
229
+ };
230
+ }
231
+ function spendMethodsIn(methods) {
232
+ return methods.filter(
233
+ (method) => SPEND_METHODS.includes(method)
234
+ );
235
+ }
236
+ function toNip47MakeInvoiceParams(request) {
237
+ const params = {
238
+ amount: toSafeNumber(request.amount_msats, "amount_msats")
239
+ };
240
+ if (request.description !== void 0) params.description = request.description;
241
+ if (request.description_hash !== void 0) {
242
+ params.description_hash = request.description_hash;
243
+ }
244
+ if (request.expiry !== void 0) params.expiry = request.expiry;
245
+ if (request.metadata !== void 0) params.metadata = request.metadata;
246
+ return params;
247
+ }
248
+ function toNip47ListTransactionsParams(request) {
249
+ const params = {};
250
+ if (request.from !== void 0) params.from = request.from;
251
+ if (request.until !== void 0) params.until = request.until;
252
+ if (request.limit !== void 0) params.limit = request.limit;
253
+ if (request.offset !== void 0) params.offset = request.offset;
254
+ if (request.unpaid !== void 0) params.unpaid = request.unpaid;
255
+ if (request.type !== void 0) params.type = request.type;
256
+ return params;
257
+ }
258
+ function validateMakeInvoiceRequest(request) {
259
+ if (request.amount_msats < OPENRECEIVE_MIN_AMOUNT_MSATS) {
260
+ throw new ReceiveCheckoutValidationError("amount_msats must be at least 1000");
261
+ }
262
+ if (request.amount_msats > OPENRECEIVE_MAX_AMOUNT_MSATS) {
263
+ throw new ReceiveCheckoutValidationError("amount_msats exceeds JSON safe integer boundary");
264
+ }
265
+ if (request.description !== void 0 && request.description_hash !== void 0) {
266
+ throw new ReceiveCheckoutValidationError(
267
+ "At most one of description or description_hash may be present"
268
+ );
269
+ }
270
+ if (request.description_hash !== void 0 && !HEX_64.test(request.description_hash)) {
271
+ throw new ReceiveCheckoutValidationError("description_hash must be 64 hex characters");
272
+ }
273
+ if (request.metadata !== void 0) {
274
+ const metadataBytes = byteLength(JSON.stringify(request.metadata));
275
+ if (metadataBytes > OPENRECEIVE_NWC_METADATA_MAX_BYTES) {
276
+ throw new ReceiveCheckoutValidationError(
277
+ `metadata must serialize below ${OPENRECEIVE_NWC_METADATA_MAX_BYTES} bytes`
278
+ );
279
+ }
280
+ }
281
+ }
282
+ function validateListTransactionsRequest(request) {
283
+ validateOptionalNonNegativeInteger(request.from, "from");
284
+ validateOptionalNonNegativeInteger(request.until, "until");
285
+ validateOptionalNonNegativeInteger(request.offset, "offset");
286
+ if (request.limit !== void 0 && (!Number.isSafeInteger(request.limit) || request.limit <= 0)) {
287
+ throw new ReceiveCheckoutValidationError("limit must be a positive safe integer");
288
+ }
289
+ if (request.from !== void 0 && request.until !== void 0 && request.from > request.until) {
290
+ throw new ReceiveCheckoutValidationError("from must be less than or equal to until");
291
+ }
292
+ if (request.type !== void 0 && request.type !== "incoming" && request.type !== "outgoing") {
293
+ throw new ReceiveCheckoutValidationError("type must be incoming or outgoing");
294
+ }
295
+ }
296
+ function validateOptionalNonNegativeInteger(value, field) {
297
+ if (value === void 0) return;
298
+ if (!Number.isSafeInteger(value) || value < 0) {
299
+ throw new ReceiveCheckoutValidationError(`${field} must be a non-negative safe integer`);
300
+ }
301
+ }
302
+ function normalizeMakeInvoiceResult(rawResult) {
303
+ const result = recordOrEmpty(unwrapNwcResult(rawResult));
304
+ const invoice = requiredString(result.invoice, "invoice");
305
+ const paymentHash = requiredString(result.payment_hash ?? result.paymentHash, "payment_hash");
306
+ if (!HEX_64.test(paymentHash)) {
307
+ throw new TypeError("payment_hash must be 64 hex characters");
308
+ }
309
+ const amountMsats = toBigInt(result.amount_msats ?? result.amount, "amount_msats");
310
+ const createdAt = parseOptionalInteger(result.created_at ?? result.createdAt, "created_at");
311
+ const expiresAt = parseOptionalInteger(result.expires_at ?? result.expiresAt, "expires_at");
312
+ return {
313
+ invoice,
314
+ payment_hash: paymentHash,
315
+ amount_msats: amountMsats,
316
+ ...createdAt === void 0 ? {} : { created_at: createdAt },
317
+ ...expiresAt === void 0 ? {} : { expires_at: expiresAt }
318
+ };
319
+ }
320
+ function normalizeListTransactionsResult(rawResult) {
321
+ const unwrapped = unwrapNwcResult(rawResult);
322
+ const result = recordOrEmpty(unwrapped);
323
+ let rawTransactions;
324
+ if (Array.isArray(result.transactions)) {
325
+ rawTransactions = result.transactions;
326
+ } else if (Array.isArray(unwrapped)) {
327
+ rawTransactions = unwrapped;
328
+ } else if ((unwrapped === void 0 || unwrapped === null || typeof unwrapped === "object") && Object.keys(result).length === 0) {
329
+ rawTransactions = [];
330
+ } else {
331
+ throw new TypeError("list_transactions returned an unrecognized result shape");
332
+ }
333
+ const transactions = [];
334
+ let skippedRows = 0;
335
+ for (const rawTransaction of rawTransactions) {
336
+ try {
337
+ transactions.push(normalizeNwcTransaction(rawTransaction));
338
+ } catch {
339
+ skippedRows += 1;
340
+ }
341
+ }
342
+ if (transactions.length === 0 && skippedRows > 0) {
343
+ throw new TypeError("list_transactions returned no usable rows");
344
+ }
345
+ return { transactions, skippedRows };
346
+ }
347
+ function normalizeNwcTransaction(rawTransaction) {
348
+ const result = recordOrEmpty(rawTransaction);
349
+ const normalized = {};
350
+ const type = normalizeTransactionType(result.type);
351
+ if (type !== void 0) normalized.type = type;
352
+ const invoice = nonEmptyString(result.invoice);
353
+ if (invoice !== void 0) normalized.invoice = invoice;
354
+ const paymentHash = nonEmptyString(result.payment_hash ?? result.paymentHash);
355
+ if (paymentHash !== void 0) {
356
+ if (!/^[0-9a-fA-F]{64}$/.test(paymentHash)) {
357
+ throw new TypeError("payment_hash must be 64 hexadecimal characters");
358
+ }
359
+ normalized.payment_hash = paymentHash;
360
+ }
361
+ if (result.amount_msats !== void 0 || result.amount !== void 0) {
362
+ normalized.amount_msats = toBigInt(result.amount_msats ?? result.amount, "amount_msats");
363
+ }
364
+ const transactionState = normalizeTransactionState(
365
+ result.transaction_state ?? result.transactionState ?? result.state
366
+ ) ?? (result.settled === true || result.paid === true ? "settled" : void 0);
367
+ if (transactionState !== void 0) {
368
+ normalized.transaction_state = transactionState;
369
+ }
370
+ const createdAt = optionalUnixSeconds(result.created_at ?? result.createdAt, "created_at");
371
+ if (createdAt !== void 0) normalized.created_at = createdAt;
372
+ const expiresAt = optionalUnixSeconds(result.expires_at ?? result.expiresAt, "expires_at");
373
+ if (expiresAt !== void 0) normalized.expires_at = expiresAt;
374
+ const settledAt = optionalUnixSeconds(result.settled_at ?? result.settledAt, "settled_at");
375
+ if (settledAt !== void 0) normalized.settled_at = settledAt;
376
+ const preimage = nonEmptyString(result.preimage);
377
+ if (preimage !== void 0) normalized.preimage = preimage;
378
+ const description = nonEmptyString(result.description);
379
+ if (description !== void 0) normalized.description = description;
380
+ const descriptionHash = nonEmptyString(result.description_hash ?? result.descriptionHash);
381
+ if (descriptionHash !== void 0) normalized.description_hash = descriptionHash;
382
+ if (result.fees_paid !== void 0 || result.feesPaid !== void 0) {
383
+ normalized.fees_paid_msats = toBigInt(result.fees_paid ?? result.feesPaid, "fees_paid");
384
+ }
385
+ return normalized;
386
+ }
387
+ function normalizeNwcNotification(rawNotification) {
388
+ const record = recordOrEmpty(rawNotification);
389
+ const type = typeof record.notification_type === "string" ? record.notification_type : typeof record.notificationType === "string" ? record.notificationType : typeof record.type === "string" ? record.type : "unknown";
390
+ const payload = recordOrEmpty(record.notification);
391
+ let transaction;
392
+ if (Object.keys(payload).length > 0) {
393
+ try {
394
+ transaction = normalizeNwcTransaction(payload);
395
+ } catch {
396
+ }
397
+ }
398
+ const rawHash = payload.payment_hash ?? payload.paymentHash ?? record.payment_hash ?? record.paymentHash;
399
+ const paymentHash = typeof rawHash === "string" && rawHash.length > 0 ? rawHash : transaction?.payment_hash;
400
+ return {
401
+ type,
402
+ ...paymentHash === void 0 ? {} : { payment_hash: paymentHash },
403
+ ...transaction === void 0 ? {} : { transaction }
404
+ };
405
+ }
406
+ function chooseEncryptionMode(encryptionModes) {
407
+ const normalized = encryptionModes.map((mode) => mode.toLowerCase().replace(/[- ]/g, "_"));
408
+ if (normalized.includes("nip44_v2") || normalized.includes("nip44") || normalized.includes("nip_44")) {
409
+ return "nip44_v2";
410
+ }
411
+ if (normalized.length === 0 || normalized.includes("nip04") || normalized.includes("nip_04")) {
412
+ return "nip04";
413
+ }
414
+ return void 0;
415
+ }
416
+ function normalizeStringList(value) {
417
+ if (Array.isArray(value)) {
418
+ return value.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
419
+ }
420
+ if (typeof value === "string") {
421
+ return value.split(/[,\s]+/).map((item) => item.trim()).filter(Boolean);
422
+ }
423
+ return [];
424
+ }
425
+ function normalizeNwcMethodName(value) {
426
+ return value.trim().replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[-\s]+/g, "_").toLowerCase();
427
+ }
428
+ function normalizeTransactionState(value) {
429
+ if (typeof value !== "string") return void 0;
430
+ const normalized = value.toLowerCase();
431
+ if (normalized === "pending" || normalized === "settled" || normalized === "expired" || normalized === "failed" || normalized === "accepted") {
432
+ return normalized;
433
+ }
434
+ return void 0;
435
+ }
436
+ function normalizeTransactionType(value) {
437
+ if (typeof value !== "string") return void 0;
438
+ const normalized = value.toLowerCase();
439
+ if (normalized === "incoming" || normalized === "outgoing") return normalized;
440
+ return void 0;
441
+ }
442
+ function parseOptionalInteger(value, fieldName) {
443
+ if (value === void 0 || value === null) return void 0;
444
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
445
+ throw new TypeError(`${fieldName} must be a non-negative safe integer`);
446
+ }
447
+ return value;
448
+ }
449
+ function optionalUnixSeconds(value, fieldName) {
450
+ if (value === void 0 || value === null) return void 0;
451
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
452
+ throw new TypeError(`${fieldName} must be a non-negative number of Unix seconds`);
453
+ }
454
+ return Math.floor(value);
455
+ }
456
+ function requiredString(value, fieldName) {
457
+ if (typeof value !== "string" || value.length === 0) {
458
+ throw new TypeError(`${fieldName} must be a non-empty string`);
459
+ }
460
+ return value;
461
+ }
462
+ function toBigInt(value, fieldName) {
463
+ if (typeof value === "bigint") return value;
464
+ if (typeof value === "number" && Number.isSafeInteger(value)) {
465
+ return BigInt(value);
466
+ }
467
+ if (typeof value === "string" && /^[0-9]+$/.test(value)) {
468
+ return BigInt(value);
469
+ }
470
+ throw new TypeError(`${fieldName} must be an integer`);
471
+ }
472
+ function toSafeNumber(value, fieldName) {
473
+ if (value > BigInt(Number.MAX_SAFE_INTEGER)) {
474
+ throw new ReceiveCheckoutValidationError(`${fieldName} exceeds JSON safe integer boundary`);
475
+ }
476
+ return Number(value);
477
+ }
478
+ function byteLength(value) {
479
+ return new TextEncoder().encode(value).length;
480
+ }
481
+ function unwrapNwcResult(value) {
482
+ const record = recordOrEmpty(value);
483
+ return record.result ?? value;
484
+ }
485
+
486
+ // src/nwc/transport.ts
487
+ import { createRequire } from "module";
488
+ import { pathToFileURL } from "url";
489
+ import { recordOrEmpty as recordOrEmpty2 } from "@openreceive/core";
490
+ var require2 = createRequire(import.meta.url);
491
+ async function callRequiredMethod(client, names, request) {
492
+ for (const name of names) {
493
+ const method = client[name];
494
+ if (typeof method === "function") {
495
+ return await method.call(
496
+ client,
497
+ request
498
+ );
499
+ }
500
+ }
501
+ throw new WalletPreflightError(
502
+ "wallet_unavailable",
503
+ `NWC client does not expose ${names.join(" or ")}.`
504
+ );
505
+ }
506
+ async function createDefaultAlbyNwcClient(connectionString) {
507
+ ensureNodeWebSocket();
508
+ const dynamicImport = new Function("specifier", "return import(specifier)");
509
+ const namespace = recordOrEmpty2(
510
+ await dynamicImport(pathToFileURL(require2.resolve("@getalby/sdk/nwc")).href)
511
+ );
512
+ const Constructor = namespace.NWCClient;
513
+ if (typeof Constructor !== "function") {
514
+ throw new WalletPreflightError(
515
+ "wallet_unavailable",
516
+ "@getalby/sdk/nwc did not expose NWCClient."
517
+ );
518
+ }
519
+ const NWCClientConstructor = Constructor;
520
+ return new NWCClientConstructor({
521
+ nostrWalletConnectUrl: connectionString
522
+ });
523
+ }
524
+ function ensureNodeWebSocket() {
525
+ if (globalThis.WebSocket !== void 0) return;
526
+ throw new WalletPreflightError(
527
+ "wallet_unavailable",
528
+ "OpenReceive requires Node 22 or newer with the built-in WebSocket API."
529
+ );
530
+ }
531
+ async function closeNwcNotificationSubscription(subscription) {
532
+ if (typeof subscription !== "function") {
533
+ throw new TypeError("NWC subscribeNotifications must resolve to an unsubscribe function.");
534
+ }
535
+ await subscription();
536
+ }
537
+ function delay(milliseconds) {
538
+ return new Promise((resolve) => {
539
+ setTimeout(resolve, milliseconds);
540
+ });
541
+ }
542
+
543
+ // src/alby-nwc.ts
544
+ var AlbyNwcReceiveClient = class {
545
+ /**
546
+ * Safe, loggable view of the connection (wallet pubkey, relays, lud16, and
547
+ * the secret-redacted URI). The parsed connection with the client secret is
548
+ * deliberately private: `console.log(client)` or host error serialization
549
+ * must never leak the secret.
550
+ */
551
+ connection;
552
+ #connection;
553
+ #connectionString;
554
+ #client;
555
+ #clientPromise;
556
+ #clientFactory;
557
+ #preflightSummary;
558
+ #preflightPromise;
559
+ #requirePreflight;
560
+ #logger;
561
+ #allowSpendCapableWallet;
562
+ #spendCapabilityWarningDelayMs;
563
+ #spendCapabilityWarning;
564
+ #closed = false;
565
+ constructor(options) {
566
+ this.#connectionString = options.connectionString;
567
+ this.#connection = parseNwcUri(options.connectionString);
568
+ this.connection = {
569
+ walletPubkey: this.#connection.walletPubkey,
570
+ relays: [...this.#connection.relays],
571
+ ...this.#connection.lud16 === void 0 ? {} : { lud16: this.#connection.lud16 },
572
+ redacted: this.#connection.redacted
573
+ };
574
+ this.#client = options.client;
575
+ this.#clientFactory = options.clientFactory;
576
+ this.#requirePreflight = options.requirePreflight ?? true;
577
+ this.#logger = options.logger;
578
+ this.#allowSpendCapableWallet = options.allowSpendCapableWallet ?? false;
579
+ this.#spendCapabilityWarningDelayMs = options.spendCapabilityWarningDelayMs ?? 0;
580
+ this.#spendCapabilityWarning = options.spendCapabilityWarning ?? ((message) => {
581
+ if (this.#logger === void 0) console.error(message);
582
+ else this.#log("error", "nwc.spend_capability_warning", message);
583
+ });
584
+ }
585
+ #log(level, event, message, fields = {}) {
586
+ if (this.#logger === void 0) return;
587
+ try {
588
+ this.#logger({
589
+ level,
590
+ event,
591
+ message,
592
+ wallet_pubkey: this.connection.walletPubkey,
593
+ ...fields
594
+ });
595
+ } catch {
596
+ }
597
+ }
598
+ async preflight() {
599
+ const client = await this.getClient();
600
+ const hasGetInfo = typeof client.getInfo === "function" || typeof client.get_info === "function";
601
+ const hasInfoEvent = typeof client.getWalletServiceInfo === "function";
602
+ const rawInfo = hasGetInfo || !hasInfoEvent ? await this.#fetchWalletInfo(
603
+ "get_info",
604
+ () => callRequiredMethod(client, ["getInfo", "get_info"], {})
605
+ ) : void 0;
606
+ const rawServiceInfo = hasInfoEvent ? await this.#fetchWalletInfo(
607
+ "info_event",
608
+ () => client.getWalletServiceInfo()
609
+ ) : void 0;
610
+ if (rawInfo === void 0) {
611
+ this.#log(
612
+ "warn",
613
+ "nwc.info_event.methods_fallback",
614
+ "NWC client exposes no get_info; proving receive-only from the service-wide info event (kind 13194) rather than this connection's own method list."
615
+ );
616
+ }
617
+ const summary = summarizeWalletCapabilities(
618
+ this.#connection,
619
+ rawInfo ?? rawServiceInfo,
620
+ rawServiceInfo
621
+ );
622
+ this.#log("debug", "nwc.preflight.summarized", "NWC wallet capabilities summarized.", {
623
+ methods_source: rawInfo === void 0 ? "info_event" : "get_info",
624
+ methods: summary.methods,
625
+ encryption: summary.encryption,
626
+ receive_checkout_ready: summary.receiveCheckoutReady,
627
+ spend_capability_advertised: summary.spendCapabilityAdvertised
628
+ });
629
+ if (!summary.receiveCheckoutReady) {
630
+ throw new WalletPreflightError(
631
+ "missing_required_method",
632
+ "NWC wallet must advertise make_invoice and list_transactions for receive checkout.",
633
+ summary
634
+ );
635
+ }
636
+ if (summary.encryption !== "nip04" && summary.encryption !== "nip44_v2") {
637
+ throw new WalletPreflightError(
638
+ "unsupported_encryption",
639
+ "NWC wallet must support NIP-04 or NIP-44 v2 encryption.",
640
+ summary
641
+ );
642
+ }
643
+ if (summary.spendCapabilityAdvertised) {
644
+ const spendMethods = spendMethodsIn(summary.methods);
645
+ if (!this.#allowSpendCapableWallet) {
646
+ this.#log(
647
+ "error",
648
+ "nwc.spend_capability_advertised",
649
+ "NWC connection advertises send-payment methods; refusing to boot without an explicit override.",
650
+ { methods: spendMethods }
651
+ );
652
+ throw new WalletPreflightError(
653
+ "spend_capability_advertised",
654
+ formatSpendCapabilityRefusedMessage({ spendMethods }),
655
+ summary
656
+ );
657
+ }
658
+ const warning = formatSpendCapabilityWarningMessage({
659
+ spendMethods
660
+ });
661
+ this.#log(
662
+ "error",
663
+ "nwc.spend_capability_advertised",
664
+ "NWC connection advertises send-payment methods; continuing because the spend-capable override is set.",
665
+ { methods: spendMethods }
666
+ );
667
+ try {
668
+ this.#spendCapabilityWarning(warning);
669
+ } catch {
670
+ }
671
+ if (this.#spendCapabilityWarningDelayMs > 0) {
672
+ await delay(this.#spendCapabilityWarningDelayMs);
673
+ }
674
+ }
675
+ this.#preflightSummary = summary;
676
+ return summary;
677
+ }
678
+ async makeInvoice(request) {
679
+ await this.ensurePreflight();
680
+ validateMakeInvoiceRequest(request);
681
+ this.#log(
682
+ "debug",
683
+ "nwc.make_invoice.requested",
684
+ "Calling NWC wallet make_invoice.",
685
+ compact({
686
+ method: "make_invoice",
687
+ // String form: msats above 2^53 would silently round through Number().
688
+ amount_msats: request.amount_msats.toString(),
689
+ expiry: request.expiry,
690
+ has_description: request.description !== void 0,
691
+ has_description_hash: request.description_hash !== void 0
692
+ })
693
+ );
694
+ const startedAt = Date.now();
695
+ let rawResult;
696
+ try {
697
+ rawResult = await callRequiredMethod(
698
+ await this.getClient(),
699
+ ["makeInvoice", "make_invoice"],
700
+ toNip47MakeInvoiceParams(request)
701
+ );
702
+ } catch (error) {
703
+ const normalized = normalizeNwcWalletError(error);
704
+ this.#log("error", "nwc.make_invoice.failed", "NWC wallet make_invoice failed.", {
705
+ method: "make_invoice",
706
+ duration_ms: Date.now() - startedAt,
707
+ error_code: normalized.code,
708
+ error_message: normalized.message
709
+ });
710
+ throw normalized;
711
+ }
712
+ let result;
713
+ try {
714
+ result = normalizeMakeInvoiceResult(rawResult);
715
+ } catch (error) {
716
+ const normalized = normalizeNwcWalletError(error);
717
+ this.#log("error", "nwc.make_invoice.failed", "NWC wallet make_invoice failed.", {
718
+ method: "make_invoice",
719
+ duration_ms: Date.now() - startedAt,
720
+ error_code: normalized.code,
721
+ error_message: normalized.message
722
+ });
723
+ throw normalized;
724
+ }
725
+ this.#log("debug", "nwc.make_invoice.completed", "NWC wallet make_invoice completed.", {
726
+ method: "make_invoice",
727
+ duration_ms: Date.now() - startedAt,
728
+ payment_hash: result.payment_hash,
729
+ amount_msats: result.amount_msats.toString()
730
+ });
731
+ return result;
732
+ }
733
+ async listTransactions(request) {
734
+ await this.ensurePreflight();
735
+ validateListTransactionsRequest(request);
736
+ this.#log(
737
+ "debug",
738
+ "nwc.list_transactions.requested",
739
+ "Calling NWC wallet list_transactions.",
740
+ compact({
741
+ method: "list_transactions",
742
+ from: request.from,
743
+ until: request.until,
744
+ limit: request.limit,
745
+ offset: request.offset,
746
+ unpaid: request.unpaid,
747
+ type: request.type
748
+ })
749
+ );
750
+ const startedAt = Date.now();
751
+ let rawResult;
752
+ try {
753
+ rawResult = await callRequiredMethod(
754
+ await this.getClient(),
755
+ ["listTransactions", "list_transactions"],
756
+ toNip47ListTransactionsParams(request)
757
+ );
758
+ } catch (error) {
759
+ const normalized = normalizeNwcWalletError(error);
760
+ this.#log("error", "nwc.list_transactions.failed", "NWC wallet list_transactions failed.", {
761
+ method: "list_transactions",
762
+ duration_ms: Date.now() - startedAt,
763
+ error_code: normalized.code,
764
+ error_message: normalized.message
765
+ });
766
+ throw normalized;
767
+ }
768
+ let result;
769
+ try {
770
+ result = normalizeListTransactionsResult(rawResult);
771
+ } catch (error) {
772
+ const normalized = normalizeNwcWalletError(error);
773
+ this.#log("error", "nwc.list_transactions.failed", "NWC wallet list_transactions failed.", {
774
+ method: "list_transactions",
775
+ duration_ms: Date.now() - startedAt,
776
+ error_code: normalized.code,
777
+ error_message: normalized.message
778
+ });
779
+ throw normalized;
780
+ }
781
+ if (result.skippedRows > 0) {
782
+ this.#log(
783
+ "warn",
784
+ "nwc.list_transactions.rows_skipped",
785
+ "Skipped wallet transaction rows that could not be normalized.",
786
+ {
787
+ method: "list_transactions",
788
+ skipped_count: result.skippedRows
789
+ }
790
+ );
791
+ }
792
+ this.#log(
793
+ "debug",
794
+ "nwc.list_transactions.completed",
795
+ "NWC wallet list_transactions completed.",
796
+ {
797
+ method: "list_transactions",
798
+ duration_ms: Date.now() - startedAt,
799
+ transaction_count: result.transactions.length
800
+ }
801
+ );
802
+ return {
803
+ transactions: result.transactions,
804
+ ...result.skippedRows === 0 ? {} : { skippedRows: result.skippedRows }
805
+ };
806
+ }
807
+ /**
808
+ * Opt-in NWC-02 notification subscription, limited to `payment_received`.
809
+ * Notifications are authenticated wallet data: the handler receives the
810
+ * payload normalized like a `list_transactions` row so a payload satisfying
811
+ * the settlement rule can settle its pending attempt directly, while
812
+ * anything less only wakes reconciliation. Direct settlement assumes the
813
+ * client binds notification decryption to the connection's wallet pubkey
814
+ * (the bundled @getalby/sdk does). Resolves to an unsubscribe function.
815
+ * Throws an OpenReceiveError with code `UNSUPPORTED_METHOD` when the
816
+ * underlying wallet client does not support NWC notifications.
817
+ */
818
+ async subscribeNotifications(handler) {
819
+ const client = await this.getClient();
820
+ const subscribe = client.subscribeNotifications;
821
+ if (typeof subscribe !== "function") {
822
+ throw new OpenReceiveError2({
823
+ code: "UNSUPPORTED_METHOD",
824
+ message: "NWC wallet client does not support NWC notifications (subscribeNotifications). Keep polling reconciliation.",
825
+ retryable: false
826
+ });
827
+ }
828
+ this.#log(
829
+ "debug",
830
+ "nwc.notifications.subscribe.requested",
831
+ "Subscribing to NWC-02 payment_received notifications.",
832
+ { notification_types: ["payment_received"] }
833
+ );
834
+ let subscription;
835
+ try {
836
+ subscription = await subscribe.call(
837
+ client,
838
+ (rawNotification) => {
839
+ const notification = normalizeNwcNotification(rawNotification);
840
+ if (notification.type !== "payment_received") return;
841
+ this.#log(
842
+ "debug",
843
+ "nwc.notifications.received",
844
+ "NWC payment_received notification received.",
845
+ compact({
846
+ notification_type: notification.type,
847
+ payment_hash: notification.payment_hash
848
+ })
849
+ );
850
+ try {
851
+ handler(notification);
852
+ } catch {
853
+ }
854
+ },
855
+ ["payment_received"]
856
+ );
857
+ } catch (error) {
858
+ const normalized = normalizeNwcWalletError(error);
859
+ this.#log(
860
+ "error",
861
+ "nwc.notifications.subscribe.failed",
862
+ "NWC notification subscription failed.",
863
+ { error_code: normalized.code, error_message: normalized.message }
864
+ );
865
+ throw normalized;
866
+ }
867
+ this.#log(
868
+ "info",
869
+ "nwc.notifications.subscribe.completed",
870
+ "Subscribed to NWC-02 payment_received notifications; polling reconciliation remains the safety net."
871
+ );
872
+ return async () => {
873
+ await closeNwcNotificationSubscription(subscription);
874
+ this.#log(
875
+ "info",
876
+ "nwc.notifications.unsubscribed",
877
+ "Unsubscribed from NWC-02 wallet notifications."
878
+ );
879
+ };
880
+ }
881
+ async #fetchWalletInfo(source, call) {
882
+ const method = source === "get_info" ? "get_info" : "getWalletServiceInfo";
883
+ const label = source === "get_info" ? "get_info" : "info event (kind 13194)";
884
+ this.#log("debug", `nwc.${source}.requested`, `Fetching NWC wallet ${label}.`, { method });
885
+ const startedAt = Date.now();
886
+ try {
887
+ const raw = await call();
888
+ this.#log("debug", `nwc.${source}.completed`, `NWC wallet ${label} loaded.`, {
889
+ method,
890
+ duration_ms: Date.now() - startedAt
891
+ });
892
+ return raw;
893
+ } catch (error) {
894
+ const normalized = normalizeNwcWalletError(error);
895
+ this.#log("error", `nwc.${source}.failed`, `NWC wallet ${label} fetch failed.`, {
896
+ method,
897
+ duration_ms: Date.now() - startedAt,
898
+ error_code: normalized.code,
899
+ error_message: normalized.message
900
+ });
901
+ throw normalized;
902
+ }
903
+ }
904
+ async close() {
905
+ if (this.#closed) return;
906
+ this.#closed = true;
907
+ const client = this.#client ?? await this.#clientPromise?.catch(() => void 0);
908
+ this.#client = void 0;
909
+ this.#clientPromise = void 0;
910
+ await client?.close?.();
911
+ }
912
+ async ensurePreflight() {
913
+ if (!this.#requirePreflight || this.#preflightSummary !== void 0) return;
914
+ this.#preflightPromise ??= this.preflight();
915
+ try {
916
+ await this.#preflightPromise;
917
+ } catch (error) {
918
+ this.#preflightPromise = void 0;
919
+ throw error;
920
+ }
921
+ }
922
+ async getClient() {
923
+ if (this.#closed) {
924
+ throw new Error("OpenReceive NWC receive client is closed; create a new client.");
925
+ }
926
+ if (this.#client !== void 0) return this.#client;
927
+ this.#clientPromise ??= (async () => {
928
+ const client = this.#clientFactory !== void 0 ? await this.#clientFactory(this.#connection) : await createDefaultAlbyNwcClient(this.#connectionString);
929
+ this.#client = client;
930
+ return client;
931
+ })();
932
+ try {
933
+ return await this.#clientPromise;
934
+ } catch (error) {
935
+ this.#clientPromise = void 0;
936
+ throw error;
937
+ }
938
+ }
939
+ };
940
+ function createNwcReceiveClient(options) {
941
+ return new AlbyNwcReceiveClient(options);
942
+ }
943
+
1
944
  // src/swap/assets.ts
2
945
  var OPENRECEIVE_SWAP_PAY_IN_ASSETS = [
3
946
  "SOL_SOL",
@@ -92,13 +1035,13 @@ function isLightningNetwork(value) {
92
1035
  }
93
1036
 
94
1037
  // src/swap/fixedfloat.ts
95
- import { ceilDiv as ceilDiv2, OPENRECEIVE_SATS_PER_BTC as OPENRECEIVE_SATS_PER_BTC2, recordOrEmpty as recordOrEmpty4, unixSeconds } from "@openreceive/core";
1038
+ import { ceilDiv as ceilDiv2, OPENRECEIVE_SATS_PER_BTC as OPENRECEIVE_SATS_PER_BTC2, recordOrEmpty as recordOrEmpty6, unixSeconds } from "@openreceive/core";
96
1039
 
97
1040
  // src/swap/fixedfloat-currencies.ts
98
- import { recordOrEmpty as recordOrEmpty2 } from "@openreceive/core";
1041
+ import { recordOrEmpty as recordOrEmpty4 } from "@openreceive/core";
99
1042
 
100
1043
  // src/swap/fixedfloat-fields.ts
101
- import { recordOrEmpty } from "@openreceive/core";
1044
+ import { recordOrEmpty as recordOrEmpty3 } from "@openreceive/core";
102
1045
  function optionalCoercedString(value) {
103
1046
  if (typeof value === "string" && value.length > 0) return value;
104
1047
  if (typeof value === "number" && Number.isFinite(value)) return String(value);
@@ -111,7 +1054,7 @@ function optionalStringField(record, field) {
111
1054
  function optionalNestedString(value, path) {
112
1055
  let current = value;
113
1056
  for (const key of path) {
114
- current = recordOrEmpty(current)[key];
1057
+ current = recordOrEmpty3(current)[key];
115
1058
  }
116
1059
  return optionalCoercedString(current);
117
1060
  }
@@ -127,7 +1070,7 @@ function optionalStringArrayField(record, field) {
127
1070
  const string = optionalCoercedString(value);
128
1071
  return string === void 0 ? [] : [string];
129
1072
  }
130
- function requiredString(value, field) {
1073
+ function requiredString2(value, field) {
131
1074
  const string = optionalCoercedString(value);
132
1075
  if (string === void 0) {
133
1076
  throw new Error(`FixedFloat response missing ${field}.`);
@@ -442,11 +1385,11 @@ function fixedFloatRatePairKeys(resolution) {
442
1385
  return keys;
443
1386
  }
444
1387
  function readFixedFloatCurrencies(data) {
445
- const record = recordOrEmpty2(data);
1388
+ const record = recordOrEmpty4(data);
446
1389
  const items = Array.isArray(data) ? data : Array.isArray(record.ccies) ? record.ccies : Array.isArray(record.currencies) ? record.currencies : [];
447
1390
  const currencies = [];
448
1391
  for (const item of items) {
449
- const record2 = recordOrEmpty2(item);
1392
+ const record2 = recordOrEmpty4(item);
450
1393
  const code = optionalStringField(record2, "code") ?? optionalStringField(record2, "ticker");
451
1394
  const coin = optionalStringField(record2, "coin") ?? optionalStringField(record2, "currency") ?? optionalStringField(record2, "symbol");
452
1395
  const network = optionalStringField(record2, "network") ?? optionalStringField(record2, "chain") ?? optionalStringField(record2, "networkName") ?? optionalStringField(record2, "name");
@@ -464,9 +1407,9 @@ function readFixedFloatCurrencies(data) {
464
1407
  }
465
1408
 
466
1409
  // src/swap/fixedfloat-orders.ts
467
- import { recordOrEmpty as recordOrEmpty3 } from "@openreceive/core";
1410
+ import { recordOrEmpty as recordOrEmpty5 } from "@openreceive/core";
468
1411
  function normalizeFixedFloatOrder(data, input) {
469
- const fields = extractFixedFloatOrderFields(recordOrEmpty3(data), input);
1412
+ const fields = extractFixedFloatOrderFields(recordOrEmpty5(data), input);
470
1413
  const { attention, attention_reason } = fields.status;
471
1414
  return {
472
1415
  provider: input.provider,
@@ -498,7 +1441,7 @@ function readFixedFloatOrderFee(record) {
498
1441
  return { currency: "USD", pay_in_fiat: payInFiat, payout_fiat: payoutFiat };
499
1442
  }
500
1443
  function requiredOrderField(record, field, fallback, label) {
501
- return optionalStringField(record, field) ?? fallback ?? requiredString(record[field], label);
1444
+ return optionalStringField(record, field) ?? fallback ?? requiredString2(record[field], label);
502
1445
  }
503
1446
  function requiredExpiresAt(expiresAt) {
504
1447
  if (expiresAt === void 0) {
@@ -516,8 +1459,8 @@ function persistedStatus(fallback) {
516
1459
  }
517
1460
  function extractFixedFloatOrderFields(record, input) {
518
1461
  const fallback = input.fallback;
519
- const from = recordOrEmpty3(record.from);
520
- const emergency = recordOrEmpty3(record.emergency);
1462
+ const from = recordOrEmpty5(record.from);
1463
+ const emergency = recordOrEmpty5(record.emergency);
521
1464
  const refundTxId = optionalNestedString(record, ["back", "tx", "id"]) ?? optionalNestedString(record, ["refund", "tx", "id"]) ?? fallback?.refund_tx_id;
522
1465
  const rawStatus = optionalStringField(record, "status");
523
1466
  const status = rawStatus === void 0 && fallback !== void 0 ? persistedStatus(fallback) : normalizeFixedFloatStatus(rawStatus ?? "NEW", emergency, refundTxId);
@@ -532,7 +1475,7 @@ function extractFixedFloatOrderFields(record, input) {
532
1475
  // body the one we already persisted stands. A create body without either is
533
1476
  // a provider contract break, not something to paper over with now + 10min.
534
1477
  expiresAt: requiredExpiresAt(
535
- readUnixSeconds(recordOrEmpty3(record.time).expiration) ?? fallback?.expires_at
1478
+ readUnixSeconds(recordOrEmpty5(record.time).expiration) ?? fallback?.expires_at
536
1479
  ),
537
1480
  depositMemo: optionalStringField(from, "tag") ?? fallback?.deposit_memo,
538
1481
  depositTxId: optionalNestedString(record, ["from", "tx", "id"]) ?? fallback?.deposit_tx_id,
@@ -1064,7 +2007,7 @@ var FixedFloatProvider = class {
1064
2007
  direction: "to",
1065
2008
  amount: amountMsatsToBtcString(invoiceAmountMsats)
1066
2009
  });
1067
- return readFixedFloatOrderFee(recordOrEmpty4(data));
2010
+ return readFixedFloatOrderFee(recordOrEmpty6(data));
1068
2011
  } catch {
1069
2012
  return void 0;
1070
2013
  }
@@ -1175,7 +2118,7 @@ function amountMsatsToBtcString(amountMsats) {
1175
2118
  }
1176
2119
 
1177
2120
  // src/lsc-uri.ts
1178
- import { compact } from "@openreceive/core";
2121
+ import { compact as compact2 } from "@openreceive/core";
1179
2122
  var LSC_URI_PROTOCOL = "lightning+swapconnect:";
1180
2123
  var LSC_ENV_NAMES = ["LSC_URI_PRIMARY", "LSC_URI_BACKUP"];
1181
2124
  var LSC_QUERY_PARAMETERS = /* @__PURE__ */ new Set(["key", "secret"]);
@@ -1264,7 +2207,7 @@ function readLscConnectionsFromEnvironment(environment = process.env) {
1264
2207
  function createLscSwapProvidersFromEnvironment(environment = process.env, options = {}) {
1265
2208
  return readLscConnectionsFromEnvironment(environment).map(
1266
2209
  (connection) => fixedFloatCompatibleSwapProvider(
1267
- compact({
2210
+ compact2({
1268
2211
  id: connection.providerId,
1269
2212
  baseUrl: connection.baseUrl,
1270
2213
  key: connection.key,
@@ -1314,7 +2257,7 @@ function providerIdFromUri(uri) {
1314
2257
  }
1315
2258
 
1316
2259
  // src/service/logging.ts
1317
- import { compact as compact2, isRecord } from "@openreceive/core";
2260
+ import { compact as compact3, isRecord } from "@openreceive/core";
1318
2261
  function emitLog(options, level, event, message, fields = {}) {
1319
2262
  emitEvent(options, {
1320
2263
  level,
@@ -1375,7 +2318,7 @@ function redactSecrets(value) {
1375
2318
  }
1376
2319
  function summarizeSwapProviderApiRequest(entry) {
1377
2320
  const body = isRecord(entry.body) ? entry.body : void 0;
1378
- return compact2({
2321
+ return compact3({
1379
2322
  provider: entry.provider,
1380
2323
  path: entry.path,
1381
2324
  reference: optionalLogString(body?.id),
@@ -1460,6 +2403,10 @@ function optionalLogNumber(value) {
1460
2403
  }
1461
2404
 
1462
2405
  export {
2406
+ WalletPreflightError,
2407
+ ReceiveCheckoutValidationError,
2408
+ HEX_64,
2409
+ createNwcReceiveClient,
1463
2410
  OPENRECEIVE_SWAP_PAY_IN_ASSETS,
1464
2411
  isSwapPayInAsset,
1465
2412
  listSwapAssetInfo,