@openreceive/browser 0.1.1 → 0.2.2

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.
Files changed (87) hide show
  1. package/README.md +63 -0
  2. package/dist/chunk-WLLNZH26.js +3051 -0
  3. package/dist/headless.d.ts +804 -0
  4. package/dist/headless.js +891 -0
  5. package/dist/index.d.ts +32 -4
  6. package/dist/index.js +32 -2
  7. package/dist/status-B1vDOhvh.d.ts +1001 -0
  8. package/dist/styles.css +3 -759
  9. package/package.json +57 -15
  10. package/dist/assets/icons/bank.svg +0 -12
  11. package/dist/assets/icons/bnb.svg +0 -1
  12. package/dist/assets/icons/card.svg +0 -14
  13. package/dist/assets/icons/doge.svg +0 -1
  14. package/dist/assets/pay_tutorials/boltz-1.webp +0 -0
  15. package/dist/assets/pay_tutorials/boltz-2.webp +0 -0
  16. package/dist/assets/pay_tutorials/cashapp-1.webp +0 -0
  17. package/dist/assets/pay_tutorials/cashapp-2.webp +0 -0
  18. package/dist/assets/pay_tutorials/cashapp-3.webp +0 -0
  19. package/dist/assets/pay_tutorials/cashapp-4.webp +0 -0
  20. package/dist/assets/pay_tutorials/cashapp-5.webp +0 -0
  21. package/dist/assets/pay_tutorials/cashapp-6.webp +0 -0
  22. package/dist/assets/pay_tutorials/coinbase-1.webp +0 -0
  23. package/dist/assets/pay_tutorials/coinbase-2.webp +0 -0
  24. package/dist/assets/pay_tutorials/fixedfloat-1.webp +0 -0
  25. package/dist/assets/pay_tutorials/fixedfloat-2.webp +0 -0
  26. package/dist/assets/pay_tutorials/kraken-1.webp +0 -0
  27. package/dist/assets/pay_tutorials/kraken-2.webp +0 -0
  28. package/dist/assets/pay_tutorials/kraken-3.webp +0 -0
  29. package/dist/assets/pay_tutorials/kraken-4.webp +0 -0
  30. package/dist/assets/pay_tutorials/strike-1.webp +0 -0
  31. package/dist/assets/pay_tutorials/strike-2.webp +0 -0
  32. package/dist/assets/pay_tutorials/strike-3.webp +0 -0
  33. package/dist/assets/pay_tutorials/strike-4.webp +0 -0
  34. package/dist/assets/provider-icons/aqua.png +0 -0
  35. package/dist/assets/provider-icons/belo.png +0 -0
  36. package/dist/assets/provider-icons/binance.png +0 -0
  37. package/dist/assets/provider-icons/bipa.png +0 -0
  38. package/dist/assets/provider-icons/bitfinex.png +0 -0
  39. package/dist/assets/provider-icons/bitget.png +0 -0
  40. package/dist/assets/provider-icons/bitnob.png +0 -0
  41. package/dist/assets/provider-icons/bitso.png +0 -0
  42. package/dist/assets/provider-icons/bity.png +0 -0
  43. package/dist/assets/provider-icons/blink.png +0 -0
  44. package/dist/assets/provider-icons/bluewallet.png +0 -0
  45. package/dist/assets/provider-icons/boltz.png +0 -0
  46. package/dist/assets/provider-icons/bringin.png +0 -0
  47. package/dist/assets/provider-icons/bullbitcoin.png +0 -0
  48. package/dist/assets/provider-icons/cakewallet.png +0 -0
  49. package/dist/assets/provider-icons/cashapp.png +0 -0
  50. package/dist/assets/provider-icons/changenow.png +0 -0
  51. package/dist/assets/provider-icons/chivo.png +0 -0
  52. package/dist/assets/provider-icons/coinbase.png +0 -0
  53. package/dist/assets/provider-icons/coincorner.png +0 -0
  54. package/dist/assets/provider-icons/fixedfloat.png +0 -0
  55. package/dist/assets/provider-icons/getalby.png +0 -0
  56. package/dist/assets/provider-icons/kraken.png +0 -0
  57. package/dist/assets/provider-icons/kryptex.png +0 -0
  58. package/dist/assets/provider-icons/kucoin.png +0 -0
  59. package/dist/assets/provider-icons/manifest.json +0 -207
  60. package/dist/assets/provider-icons/mtpelerin.png +0 -0
  61. package/dist/assets/provider-icons/muun.png +0 -0
  62. package/dist/assets/provider-icons/okcoin.png +0 -0
  63. package/dist/assets/provider-icons/okx.png +0 -0
  64. package/dist/assets/provider-icons/phoenix.png +0 -0
  65. package/dist/assets/provider-icons/pouch.png +0 -0
  66. package/dist/assets/provider-icons/ripio.png +0 -0
  67. package/dist/assets/provider-icons/river.png +0 -0
  68. package/dist/assets/provider-icons/rizful.png +0 -0
  69. package/dist/assets/provider-icons/shakepay.png +0 -0
  70. package/dist/assets/provider-icons/sideshift.png +0 -0
  71. package/dist/assets/provider-icons/simpleswap.png +0 -0
  72. package/dist/assets/provider-icons/speed.png +0 -0
  73. package/dist/assets/provider-icons/strike.png +0 -0
  74. package/dist/assets/provider-icons/trocador.png +0 -0
  75. package/dist/assets/provider-icons/walletofsatoshi.png +0 -0
  76. package/dist/assets/provider-icons/zeus.png +0 -0
  77. package/dist/country-map.d.ts +0 -5
  78. package/dist/country-map.js +0 -17
  79. package/dist/internal.d.ts +0 -834
  80. package/dist/internal.js +0 -2615
  81. package/dist/pay-tutorials.d.ts +0 -1
  82. package/dist/pay-tutorials.js +0 -1
  83. package/dist/provider-icons.d.ts +0 -1
  84. package/dist/provider-icons.js +0 -1
  85. package/dist/qrcode.d.ts +0 -11
  86. package/dist/status.d.ts +0 -9
  87. package/dist/status.js +0 -25
@@ -0,0 +1,891 @@
1
+ import {
2
+ BrowserRequestError,
3
+ OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES,
4
+ OPENRECEIVE_CHECKOUT_DATA_SELECTORS,
5
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES,
6
+ OPENRECEIVE_CHECKOUT_ELEMENT_EVENTS,
7
+ OPENRECEIVE_CHECKOUT_ELEMENT_PARTS,
8
+ OPENRECEIVE_CHECKOUT_ELEMENT_PART_SELECTORS,
9
+ OPENRECEIVE_CHECKOUT_ELEMENT_TAG_NAME,
10
+ OPENRECEIVE_COPY_FEEDBACK_MS,
11
+ OPENRECEIVE_DEFAULT_POLL_INTERVAL_MS,
12
+ OPENRECEIVE_DEFAULT_PREFIX,
13
+ OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES,
14
+ OPENRECEIVE_PAYMENT_WIZARD_SELECTORS,
15
+ OPENRECEIVE_THEME_STORAGE_KEY,
16
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_ATTRIBUTES,
17
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_EVENTS,
18
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_PARTS,
19
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_PART_SELECTORS,
20
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_TAG_NAME,
21
+ assertDisplayInvoice,
22
+ assetButtonClasses,
23
+ buildMethodGridEntries,
24
+ checkoutElementStyles,
25
+ checkoutLabels,
26
+ checkoutRoutes,
27
+ copyInvoice,
28
+ createBlockExplorerUrl,
29
+ createCheckoutActionEvent,
30
+ createCheckoutController,
31
+ createCheckoutErrorEvent,
32
+ createCheckoutProviderCopyEvent,
33
+ createCheckoutSnapshotFromInvoice,
34
+ createCheckoutState,
35
+ createCheckoutStateEvent,
36
+ createCheckoutStatusModel,
37
+ createDetailExternalLink,
38
+ createLightningInvoiceDecodeUrl,
39
+ createPaymentDataEntries,
40
+ createPaymentWizardController,
41
+ createPaymentWizardModel,
42
+ createPaymentWizardSelection,
43
+ createQrPayloadSvg,
44
+ createQrSvg,
45
+ createStatusFetcher,
46
+ createSwapDisplayModel,
47
+ createSwapUnavailableModel,
48
+ createThemeChangeEvent,
49
+ createTickingValueController,
50
+ createTransactionDetails,
51
+ createTransactionDetailsFromState,
52
+ createTransientFeedbackController,
53
+ createWizardRouteAssetDisplays,
54
+ createWizardRouteDisplays,
55
+ deriveCheckoutStateLabels,
56
+ deriveStatus,
57
+ enterCheckoutResumePath,
58
+ escapeHtml,
59
+ findReusableLightningInvoice,
60
+ findSwapGridGroup,
61
+ formatAmountCaption,
62
+ formatChooseNetworkHeading,
63
+ formatDepositAmount,
64
+ formatFiatAmount,
65
+ formatMsats,
66
+ formatNetworkSummary,
67
+ formatSwapLimit,
68
+ formatUnixTime,
69
+ getExplorerNetwork,
70
+ getNetworkIcon,
71
+ getPaymentMethodIcon,
72
+ getRouteNetworkLabel,
73
+ getSwapOptionIcon,
74
+ getSwapRefundFormError,
75
+ getWizardEmptyMessage,
76
+ isPaidCheckoutSnapshot,
77
+ isReusableLightningInvoice,
78
+ mergeAttemptIntoCheckout,
79
+ mergeAttemptIntoSnapshot,
80
+ mergeMintedCheckout,
81
+ networkButtonClasses,
82
+ networkCheckClasses,
83
+ networkMobileRevealClasses,
84
+ networkSummaryIconClasses,
85
+ openWallet,
86
+ optionalSafeInteger,
87
+ orClasses,
88
+ overlaySwapRefundStaging,
89
+ parseBooleanAttribute,
90
+ parseMethodPickerKey,
91
+ parseOptionalInteger,
92
+ parsePaymentMethod,
93
+ parseResolvedTheme,
94
+ parseThemePreference,
95
+ paymentAccentId,
96
+ paymentIconUrls,
97
+ paymentMethods,
98
+ prepareCheckout,
99
+ readJsonResponse,
100
+ requestCheckout,
101
+ requestHeaders,
102
+ resolveBrowserLogger,
103
+ resolvePreservedNetworkSelection,
104
+ resolveTransactionDetailRows,
105
+ sanitizeBrowserLogEntry,
106
+ selectCheckoutDisplayInvoice,
107
+ swapAssetMatchesRoute,
108
+ swapGroupLimitOption,
109
+ swapOptionLimitMessage,
110
+ swapPickerKey,
111
+ updatePaymentWizardSelection,
112
+ updateSelectedSwapNetworks,
113
+ wizardNetworkGroupIds
114
+ } from "./chunk-WLLNZH26.js";
115
+
116
+ // src/internal/checkout-props.ts
117
+ var CREATE_MODE_ONLY_PROPS = [
118
+ "metadata",
119
+ "syncUrl",
120
+ "resumePathPrefix",
121
+ "routeReference"
122
+ ];
123
+ var warnedSnapshotModeProps = /* @__PURE__ */ new Set();
124
+ function validateCheckoutProps(props) {
125
+ const snapshot = props.checkout ?? null;
126
+ if (snapshot === null && (props.reference === void 0 || props.reference.length === 0)) {
127
+ throw new TypeError(
128
+ `${props.framework} Checkout requires a checkout snapshot or a reference (create mode).`
129
+ );
130
+ }
131
+ if (snapshot === null) return;
132
+ const ignored = CREATE_MODE_ONLY_PROPS.filter((name) => props[name] !== void 0);
133
+ if (ignored.length === 0) return;
134
+ const key = `${props.framework}:${ignored.join(",")}`;
135
+ if (warnedSnapshotModeProps.has(key)) return;
136
+ warnedSnapshotModeProps.add(key);
137
+ const warn = props.warn ?? ((message) => globalThis.console?.warn?.(message));
138
+ warn(
139
+ `${props.framework} Checkout ignores ${ignored.join(", ")} in snapshot mode; those props only apply when the component creates the checkout from a reference.`
140
+ );
141
+ }
142
+
143
+ // src/internal/checkout-session.ts
144
+ import { recordOrEmpty as recordOrEmpty2 } from "@openreceive/core";
145
+
146
+ // src/internal/swap-http.ts
147
+ import { nonEmptyString, recordOrEmpty } from "@openreceive/core";
148
+ async function postJson(options) {
149
+ const { body } = options;
150
+ const routes = checkoutRoutes(options.prefix);
151
+ const reference = nonEmptyString(body.reference);
152
+ const action = nonEmptyString(body.action);
153
+ if (action !== void 0 && action !== "swap_quote" && action !== "refund_swap") {
154
+ throw new Error(`Unrecognized checkout action ${action}.`);
155
+ }
156
+ emitSwapActionLog(options.logger, "requested", body);
157
+ try {
158
+ const result = action === "swap_quote" ? await requestJson(options, routes.swapsQuote, {
159
+ reference,
160
+ pay_in_asset: body.pay_in_asset
161
+ }) : action === "refund_swap" ? await refundRequest(options, routes, body, reference) : await requestJson(options, routes.paymentsCheck, withoutAction(body));
162
+ if (action === "refund_swap") {
163
+ emitSwapActionLog(options.logger, "succeeded", body, swapActionResultFields(result));
164
+ }
165
+ return result;
166
+ } catch (error) {
167
+ emitSwapActionLog(options.logger, "failed", body, {
168
+ error_message: error instanceof Error ? error.message : String(error)
169
+ });
170
+ throw error;
171
+ }
172
+ }
173
+ function normalizeSwapStartInvoice(body) {
174
+ const outer = recordOrEmpty(body);
175
+ const swap = recordOrEmpty(outer.swap ?? body);
176
+ const checkout = recordOrEmpty(swap.checkout);
177
+ const paymentHash = nonEmptyString(swap.payment_hash ?? checkout.payment_hash);
178
+ if (paymentHash === void 0 || nonEmptyString(swap.provider) === void 0 || nonEmptyString(swap.pay_in_asset) === void 0 || nonEmptyString(swap.deposit_address) === void 0 || nonEmptyString(swap.deposit_amount) === void 0 || nonEmptyString(swap.provider_state) === void 0 || typeof swap.provider_expires_at !== "number") {
179
+ throw new Error("Swap response did not include provider instructions.");
180
+ }
181
+ const amountMsats = optionalSafeInteger(checkout.amount_msats, "amount_msats");
182
+ return {
183
+ invoice_id: paymentHash,
184
+ rail: "swap",
185
+ payment_hash: paymentHash,
186
+ ...amountMsats === void 0 ? {} : { amount_msats: amountMsats },
187
+ transaction_state: "pending",
188
+ workflow_state: "invoice_created",
189
+ expires_at: swap.provider_expires_at,
190
+ swap: {
191
+ provider: swap.provider,
192
+ pay_in_asset: swap.pay_in_asset,
193
+ deposit_address: swap.deposit_address,
194
+ deposit_amount: swap.deposit_amount,
195
+ provider_state: swap.provider_state,
196
+ provider_expires_at: swap.provider_expires_at,
197
+ ...copyOptionalSwapFields(swap)
198
+ }
199
+ };
200
+ }
201
+ async function startSwapRequest(options) {
202
+ const logBody = {
203
+ action: "start_swap",
204
+ reference: options.reference,
205
+ pay_in_asset: options.payInAsset
206
+ };
207
+ emitSwapActionLog(options.logger, "requested", logBody);
208
+ try {
209
+ const body = await requestJson(options, checkoutRoutes(options.prefix).swaps, {
210
+ reference: options.reference,
211
+ pay_in_asset: options.payInAsset
212
+ });
213
+ emitSwapActionLog(options.logger, "succeeded", logBody, swapActionResultFields(body));
214
+ return normalizeSwapStartInvoice(body);
215
+ } catch (error) {
216
+ emitSwapActionLog(options.logger, "failed", logBody, {
217
+ error_message: error instanceof Error ? error.message : String(error)
218
+ });
219
+ throw error;
220
+ }
221
+ }
222
+ async function requestSwapRefund(options) {
223
+ const payment = options.invoices.find(
224
+ (invoice) => invoice != null && (invoice.swap?.attempt_id ?? invoice.invoice_id) === options.attemptId
225
+ );
226
+ if (payment?.payment_hash === void 0) {
227
+ throw new Error("Swap refund requires the original payment hash.");
228
+ }
229
+ const body = await postJson({
230
+ fetch: options.fetch,
231
+ prefix: options.prefix,
232
+ ...options.logger === void 0 ? {} : { logger: options.logger },
233
+ ...options.headers === void 0 ? {} : { headers: options.headers },
234
+ body: {
235
+ ...options.reference === void 0 ? {} : { reference: options.reference },
236
+ payment_hash: payment.payment_hash,
237
+ action: "refund_swap",
238
+ attempt_id: options.attemptId,
239
+ refund_address: options.refundAddress,
240
+ confirm: options.confirm
241
+ }
242
+ });
243
+ return normalizeSwapStartInvoice(body);
244
+ }
245
+ async function refundRequest(options, routes, body, reference) {
246
+ if (reference === void 0) throw new Error("Swap refund requires reference.");
247
+ const refundAddress = nonEmptyString(body.refund_address);
248
+ if (refundAddress === void 0) throw new Error("Swap refund requires refund_address.");
249
+ const paymentHash = nonEmptyString(body.payment_hash);
250
+ if (paymentHash === void 0) throw new Error("Swap refund requires payment_hash.");
251
+ if (body.confirm === true) {
252
+ const status2 = recordOrEmpty(
253
+ await requestJson(options, routes.swapsRefunds, {
254
+ reference,
255
+ payment_hash: paymentHash,
256
+ refund_address: refundAddress
257
+ })
258
+ );
259
+ return { swap: status2 };
260
+ }
261
+ const status = recordOrEmpty(
262
+ await requestJson(options, routes.swapsStatus, {
263
+ reference,
264
+ payment_hash: paymentHash
265
+ })
266
+ );
267
+ return { swap: { ...status, refund_address: refundAddress } };
268
+ }
269
+ function withoutAction(body) {
270
+ const { action: _action, ...rest } = body;
271
+ return rest;
272
+ }
273
+ async function requestJson(options, url, body) {
274
+ const fetcher = options.fetch;
275
+ const response = await fetcher(url, {
276
+ method: "POST",
277
+ headers: requestHeaders(options.headers),
278
+ body: JSON.stringify(body)
279
+ });
280
+ return readJsonResponse(response, "OpenReceive request failed.");
281
+ }
282
+ function copyOptionalSwapFields(swap) {
283
+ const output = {};
284
+ for (const key of [
285
+ "deposit_memo",
286
+ "deposit_tx_id",
287
+ "payout_tx_id",
288
+ "refund_tx_id",
289
+ "refund_reason",
290
+ "refund_amount",
291
+ "attention",
292
+ "attempt_id",
293
+ "provider_order_id",
294
+ "refund_address",
295
+ "attention_reason",
296
+ "deposit_received_amount",
297
+ "fee"
298
+ ]) {
299
+ if (swap[key] !== void 0) output[key] = swap[key];
300
+ }
301
+ return output;
302
+ }
303
+ function emitSwapActionLog(logger, outcome, body, extra = {}) {
304
+ const sink = resolveBrowserLogger(logger);
305
+ if (sink === void 0) return;
306
+ const action = nonEmptyString(body.action);
307
+ if (action !== "start_swap" && action !== "refund_swap") return;
308
+ const event = action === "start_swap" ? `swap.start.${outcome}` : `swap.refund.${outcome}`;
309
+ const level = outcome === "failed" ? "warn" : outcome === "requested" ? "debug" : "info";
310
+ try {
311
+ sink(
312
+ sanitizeBrowserLogEntry({
313
+ level,
314
+ event,
315
+ message: `${action === "start_swap" ? "Swap start" : "Swap refund"} ${outcome}.`,
316
+ reference: nonEmptyString(body.reference),
317
+ pay_in_asset: nonEmptyString(body.pay_in_asset),
318
+ ...action === "refund_swap" ? { confirm: body.confirm === true } : {},
319
+ ...extra
320
+ })
321
+ );
322
+ } catch {
323
+ }
324
+ }
325
+ function swapActionResultFields(body) {
326
+ const swap = recordOrEmpty(recordOrEmpty(body).swap ?? body);
327
+ return {
328
+ payment_hash: nonEmptyString(swap.payment_hash),
329
+ provider_state: nonEmptyString(swap.provider_state),
330
+ attention: typeof swap.attention === "boolean" ? swap.attention : void 0
331
+ };
332
+ }
333
+
334
+ // src/internal/checkout-session.ts
335
+ var SWAP_START_FAILED = "Could not prepare the payment address. Please try again.";
336
+ var MINT_FAILED = "Could not create the Lightning invoice. Please try again.";
337
+ function normalizeSwapQuote(body) {
338
+ const quote = recordOrEmpty2(recordOrEmpty2(body).quote ?? body);
339
+ const payInAsset = quote.pay_in_asset ?? quote.pay_asset;
340
+ return typeof payInAsset === "string" ? { ...quote, pay_in_asset: payInAsset } : void 0;
341
+ }
342
+ function payerFacingMessage(error, fallback) {
343
+ return error instanceof Error && error.message.length > 0 ? error.message : fallback;
344
+ }
345
+ function createCheckoutSession(options) {
346
+ let wizardError;
347
+ let swapStartError;
348
+ let lightningRequested = false;
349
+ let mintingLightning = false;
350
+ let startingSwapAsset = null;
351
+ let swapQuotes = {};
352
+ async function ensureLightning() {
353
+ if (mintingLightning) return;
354
+ const reference = options.reference();
355
+ if (reference === void 0 || reference.length === 0) return;
356
+ const current = options.snapshot();
357
+ if (current !== void 0) {
358
+ const reusableLightning = findReusableLightningInvoice(current);
359
+ if (reusableLightning !== void 0) {
360
+ lightningRequested = true;
361
+ options.onSnapshot?.(mergeAttemptIntoSnapshot(reusableLightning, current));
362
+ options.onChange();
363
+ return;
364
+ }
365
+ }
366
+ mintingLightning = true;
367
+ wizardError = void 0;
368
+ options.onChange();
369
+ try {
370
+ const pending = options.requestCheckout?.(reference);
371
+ if (pending === void 0) return;
372
+ const checkout = await pending;
373
+ lightningRequested = true;
374
+ options.onSnapshot?.(mergeMintedCheckout(checkout, options.snapshot()));
375
+ } catch (error) {
376
+ wizardError = payerFacingMessage(error, MINT_FAILED);
377
+ options.onError(error);
378
+ } finally {
379
+ mintingLightning = false;
380
+ options.onChange();
381
+ }
382
+ }
383
+ async function startSwap(payInAsset) {
384
+ if (startingSwapAsset !== null) return;
385
+ const selection = options.swapSelection;
386
+ const prefix = options.swapPrefix?.();
387
+ const fetcher = options.fetch?.();
388
+ const reference = options.reference();
389
+ if (selection === void 0 || prefix === void 0 || fetcher === void 0) return;
390
+ if (reference === void 0 || reference.length === 0) return;
391
+ const alreadyStarted = selection.started();
392
+ if (alreadyStarted?.swap?.pay_in_asset === payInAsset && alreadyStarted.invoice_id !== selection.dismissedInvoiceId()) {
393
+ selection.setSelectedAsset(payInAsset);
394
+ options.onChange();
395
+ return;
396
+ }
397
+ startingSwapAsset = payInAsset;
398
+ swapStartError = void 0;
399
+ options.onChange();
400
+ try {
401
+ const quote = await quoteSwapAsset(payInAsset, prefix, fetcher, reference);
402
+ if (quote !== void 0 && quote.available === false) return;
403
+ const started = await startSwapRequest({
404
+ fetch: fetcher,
405
+ prefix,
406
+ reference,
407
+ payInAsset,
408
+ ...options.logger === void 0 ? {} : { logger: options.logger }
409
+ });
410
+ selection.setStarted(started);
411
+ selection.setDismissedInvoiceId(null);
412
+ options.onSwapStarted?.(started);
413
+ selection.setSelectedAsset(payInAsset);
414
+ options.onChange();
415
+ } catch (error) {
416
+ const landed = selection.started();
417
+ if (landed?.swap?.pay_in_asset === payInAsset && landed.invoice_id !== selection.dismissedInvoiceId()) {
418
+ selection.setSelectedAsset(payInAsset);
419
+ options.onChange();
420
+ return;
421
+ }
422
+ selection.setSelectedAsset(payInAsset);
423
+ failSwapStart(error);
424
+ } finally {
425
+ startingSwapAsset = null;
426
+ }
427
+ }
428
+ async function quoteSwapAsset(payInAsset, prefix, fetcher, reference) {
429
+ const body = await postJson({
430
+ fetch: fetcher,
431
+ prefix,
432
+ ...options.logger === void 0 ? {} : { logger: options.logger },
433
+ body: { reference, action: "swap_quote", pay_in_asset: payInAsset }
434
+ });
435
+ const quote = normalizeSwapQuote(body);
436
+ if (quote === void 0) return void 0;
437
+ swapQuotes = { ...swapQuotes, [quote.pay_in_asset]: quote };
438
+ return quote;
439
+ }
440
+ function failSwapStart(error) {
441
+ swapStartError = payerFacingMessage(error, SWAP_START_FAILED);
442
+ options.onError(error);
443
+ options.onChange();
444
+ }
445
+ return {
446
+ get wizardError() {
447
+ return wizardError;
448
+ },
449
+ get swapStartError() {
450
+ return swapStartError;
451
+ },
452
+ get lightningRequested() {
453
+ return lightningRequested;
454
+ },
455
+ get mintingLightning() {
456
+ return mintingLightning;
457
+ },
458
+ get startingSwapAsset() {
459
+ return startingSwapAsset;
460
+ },
461
+ get swapQuotes() {
462
+ return swapQuotes;
463
+ },
464
+ ensureLightning,
465
+ startSwap,
466
+ resetLightningRequest() {
467
+ lightningRequested = false;
468
+ },
469
+ clearSwapStartError() {
470
+ swapStartError = void 0;
471
+ }
472
+ };
473
+ }
474
+
475
+ // src/internal/theme.ts
476
+ function readThemePreference(options = {}) {
477
+ const value = readStorageValue(
478
+ options.storage ?? getBrowserStorage(),
479
+ options.storageKey ?? OPENRECEIVE_THEME_STORAGE_KEY
480
+ );
481
+ return value === "light" || value === "dark" || value === "system" ? value : options.defaultTheme ?? "system";
482
+ }
483
+ function writeThemePreference(theme, options = {}) {
484
+ writeStorageValue(
485
+ options.storage ?? getBrowserStorage(),
486
+ options.storageKey ?? OPENRECEIVE_THEME_STORAGE_KEY,
487
+ theme
488
+ );
489
+ }
490
+ function resolveTheme(theme, options = {}) {
491
+ if (theme === "light" || theme === "dark") return theme;
492
+ if (options.systemDark !== void 0) return options.systemDark ? "dark" : "light";
493
+ return globalThis.matchMedia?.("(prefers-color-scheme: dark)").matches ? "dark" : "light";
494
+ }
495
+ function getNextThemePreference(theme, options = {}) {
496
+ return resolveTheme(theme, options) === "dark" ? "light" : "dark";
497
+ }
498
+ function getThemeToggleLabel(resolvedTheme) {
499
+ return `${resolvedTheme} mode`;
500
+ }
501
+ function createThemeModel(theme, options = {}) {
502
+ const resolvedTheme = resolveTheme(theme, options);
503
+ return {
504
+ theme,
505
+ resolvedTheme,
506
+ nextTheme: getNextThemePreference(theme, options),
507
+ toggleLabel: getThemeToggleLabel(resolvedTheme),
508
+ attributes: {
509
+ "data-theme": resolvedTheme,
510
+ "data-openreceive-theme": resolvedTheme
511
+ },
512
+ checkoutElementAttributes: {
513
+ theme: resolvedTheme
514
+ }
515
+ };
516
+ }
517
+ function createStoredThemeModel(options = {}) {
518
+ const theme = readThemePreference(options);
519
+ return createThemeModel(theme, { systemDark: options.systemDark });
520
+ }
521
+ function toggleStoredThemePreference(options = {}) {
522
+ const currentTheme = createStoredThemeModel(options);
523
+ writeThemePreference(currentTheme.nextTheme, options);
524
+ return createStoredThemeModel(options);
525
+ }
526
+ function applyThemeAttributes(target, theme) {
527
+ if (target === null || target === void 0) return;
528
+ for (const [name, value] of Object.entries(theme.attributes)) {
529
+ if (target.getAttribute(name) !== value) target.setAttribute(name, value);
530
+ }
531
+ }
532
+ function applyCheckoutThemeAttributes(target, theme) {
533
+ if (target === null || target === void 0) return;
534
+ for (const [name, value] of Object.entries(theme.checkoutElementAttributes)) {
535
+ if (target.getAttribute(name) !== value) target.setAttribute(name, value);
536
+ }
537
+ }
538
+ function applyThemeControls(targets, theme) {
539
+ applyThemeAttributes(targets.root, theme);
540
+ applyCheckoutThemeAttributes(targets.checkout, theme);
541
+ if (targets.toggle !== null && targets.toggle !== void 0) {
542
+ targets.toggle.textContent = theme.toggleLabel;
543
+ }
544
+ }
545
+ function syncStoredThemeControls(targets, options = {}) {
546
+ const theme = createStoredThemeModel(options);
547
+ applyThemeControls(targets, theme);
548
+ return theme;
549
+ }
550
+ function toggleStoredThemeControls(targets, options = {}) {
551
+ const theme = toggleStoredThemePreference(options);
552
+ applyThemeControls(targets, theme);
553
+ return theme;
554
+ }
555
+ function readStorageValue(storage, key) {
556
+ try {
557
+ return storage?.getItem(key) ?? null;
558
+ } catch {
559
+ return null;
560
+ }
561
+ }
562
+ function writeStorageValue(storage, key, value) {
563
+ try {
564
+ storage?.setItem(key, value);
565
+ } catch {
566
+ }
567
+ }
568
+ function getBrowserStorage() {
569
+ try {
570
+ return globalThis.localStorage;
571
+ } catch {
572
+ return void 0;
573
+ }
574
+ }
575
+
576
+ // src/internal/elements.ts
577
+ function createModeAttributes(options) {
578
+ const attributes = {};
579
+ if (options.metadata !== void 0) {
580
+ attributes[OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.metadata] = JSON.stringify(options.metadata);
581
+ }
582
+ if (options.syncUrl === true) {
583
+ attributes[OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.syncUrl] = "";
584
+ }
585
+ if (options.resumePathPrefix !== void 0) {
586
+ attributes[OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.resumePathPrefix] = options.resumePathPrefix;
587
+ }
588
+ if (options.routeReference !== void 0) {
589
+ attributes[OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.routeReference] = options.routeReference;
590
+ }
591
+ return attributes;
592
+ }
593
+ function sharedElementAttributes(options) {
594
+ const attributes = {};
595
+ const isSet = (value) => value !== void 0 && value !== null;
596
+ if (isSet(options.prefix)) {
597
+ attributes[OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.prefix] = options.prefix;
598
+ }
599
+ if (isSet(options.theme)) {
600
+ attributes[OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.theme] = options.theme;
601
+ }
602
+ if (options.paymentWizard !== void 0) {
603
+ attributes[OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.paymentWizard] = String(
604
+ options.paymentWizard
605
+ );
606
+ }
607
+ if (options.decodeLinkUrl !== void 0) {
608
+ attributes[OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.decodeLinkUrl] = options.decodeLinkUrl;
609
+ }
610
+ if (options.polling !== void 0) {
611
+ attributes[OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.polling] = String(options.polling);
612
+ }
613
+ if (options.pollIntervalMs !== void 0) {
614
+ attributes[OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.pollIntervalMs] = String(
615
+ options.pollIntervalMs
616
+ );
617
+ }
618
+ return attributes;
619
+ }
620
+ function createCheckoutElementAttributes(snapshot, options = {}) {
621
+ if (snapshot === null) {
622
+ if (options.reference === void 0 || options.reference.length === 0) {
623
+ throw new TypeError(
624
+ "OpenReceive checkout element create mode requires a reference when no snapshot is given."
625
+ );
626
+ }
627
+ return {
628
+ [OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.reference]: options.reference,
629
+ ...sharedElementAttributes(options),
630
+ ...createModeAttributes(options)
631
+ };
632
+ }
633
+ const displayInvoice = selectCheckoutDisplayInvoice(snapshot);
634
+ const bolt11 = displayInvoice?.invoice;
635
+ if (displayInvoice === void 0 || typeof bolt11 !== "string") {
636
+ const deferred = {
637
+ [OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.reference]: snapshot.reference,
638
+ ...sharedElementAttributes(options),
639
+ ...createModeAttributes(options)
640
+ };
641
+ if (snapshot.amount_msats !== void 0) {
642
+ deferred[OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.amountMsats] = String(snapshot.amount_msats);
643
+ }
644
+ return deferred;
645
+ }
646
+ const invoice = displayInvoice;
647
+ assertDisplayInvoice(bolt11);
648
+ const attributes = {
649
+ [OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.reference]: snapshot.reference,
650
+ [OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.invoiceId]: invoice.invoice_id,
651
+ [OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.invoice]: bolt11,
652
+ [OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.rail]: invoice.rail
653
+ };
654
+ if (invoice.payment_hash !== void 0) {
655
+ attributes[OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.paymentHash] = invoice.payment_hash;
656
+ }
657
+ const amountMsats = invoice.amount_msats ?? snapshot.amount_msats;
658
+ if (amountMsats !== void 0) {
659
+ attributes[OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.amountMsats] = String(amountMsats);
660
+ }
661
+ const fiat = invoice.fiat_quote?.fiat ?? snapshot.fiat;
662
+ if (fiat?.currency !== void 0) {
663
+ attributes[OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.fiatCurrency] = fiat.currency;
664
+ }
665
+ if (fiat?.value !== void 0) {
666
+ attributes[OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.fiatValue] = fiat.value;
667
+ }
668
+ attributes[OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.status] = isPaidCheckoutSnapshot(snapshot) ? "settled" : snapshot.status === "expired" ? "expired" : deriveStatus(invoice);
669
+ if (invoice.expires_at !== void 0) {
670
+ attributes[OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.expiresAt] = String(invoice.expires_at);
671
+ }
672
+ return { ...attributes, ...sharedElementAttributes(options) };
673
+ }
674
+ function createThemeToggleElementAttributes(options = {}) {
675
+ return {
676
+ ...options.rootSelector === void 0 ? {} : { [OPENRECEIVE_THEME_TOGGLE_ELEMENT_ATTRIBUTES.rootSelector]: options.rootSelector },
677
+ ...options.checkoutSelector === void 0 ? {} : {
678
+ [OPENRECEIVE_THEME_TOGGLE_ELEMENT_ATTRIBUTES.checkoutSelector]: options.checkoutSelector
679
+ },
680
+ ...options.defaultTheme === void 0 ? {} : { [OPENRECEIVE_THEME_TOGGLE_ELEMENT_ATTRIBUTES.defaultTheme]: options.defaultTheme },
681
+ ...options.storageKey === void 0 ? {} : { [OPENRECEIVE_THEME_TOGGLE_ELEMENT_ATTRIBUTES.storageKey]: options.storageKey }
682
+ };
683
+ }
684
+ function createCheckoutElementListeners(handlers = {}) {
685
+ return {
686
+ ...handlers.onCopy === void 0 ? {} : { [OPENRECEIVE_CHECKOUT_ELEMENT_EVENTS.copy]: handlers.onCopy },
687
+ ...handlers.onOpenWallet === void 0 ? {} : { [OPENRECEIVE_CHECKOUT_ELEMENT_EVENTS.openWallet]: handlers.onOpenWallet },
688
+ ...handlers.onState === void 0 ? {} : { [OPENRECEIVE_CHECKOUT_ELEMENT_EVENTS.state]: handlers.onState },
689
+ ...handlers.onSettled === void 0 ? {} : { [OPENRECEIVE_CHECKOUT_ELEMENT_EVENTS.settled]: handlers.onSettled },
690
+ ...handlers.onProviderCopy === void 0 ? {} : { [OPENRECEIVE_CHECKOUT_ELEMENT_EVENTS.providerCopy]: handlers.onProviderCopy },
691
+ ...handlers.onStartOver === void 0 ? {} : { [OPENRECEIVE_CHECKOUT_ELEMENT_EVENTS.startOver]: handlers.onStartOver },
692
+ ...handlers.onError === void 0 ? {} : { [OPENRECEIVE_CHECKOUT_ELEMENT_EVENTS.error]: handlers.onError }
693
+ };
694
+ }
695
+ function createCheckoutShellModel(snapshot, options = {}) {
696
+ const theme = createStoredThemeModel(options);
697
+ const ownTheme = options.themeToggle !== false;
698
+ return {
699
+ theme,
700
+ rootAttributes: ownTheme ? theme.attributes : {},
701
+ checkout: {
702
+ tagName: OPENRECEIVE_CHECKOUT_ELEMENT_TAG_NAME,
703
+ attributes: createCheckoutElementAttributes(snapshot, {
704
+ ...options,
705
+ ...ownTheme ? { theme: theme.resolvedTheme } : {}
706
+ }),
707
+ listeners: createCheckoutElementListeners(options)
708
+ },
709
+ themeToggle: ownTheme ? {
710
+ tagName: OPENRECEIVE_THEME_TOGGLE_ELEMENT_TAG_NAME,
711
+ attributes: createThemeToggleElementAttributes({
712
+ rootSelector: options.rootSelector,
713
+ checkoutSelector: options.checkoutSelector ?? OPENRECEIVE_CHECKOUT_ELEMENT_TAG_NAME,
714
+ defaultTheme: options.defaultTheme,
715
+ storageKey: options.storageKey
716
+ })
717
+ } : null
718
+ };
719
+ }
720
+ function applyCheckoutElementAttributes(target, attributes) {
721
+ for (const [name, value] of Object.entries(attributes)) {
722
+ if (value !== void 0 && value !== null) target.setAttribute(name, value);
723
+ }
724
+ }
725
+ function applyCheckoutElementListeners(target, listeners) {
726
+ for (const [name, listener] of Object.entries(listeners)) {
727
+ if (listener !== void 0) target.addEventListener(name, listener);
728
+ }
729
+ }
730
+ function applyThemeToggleElementAttributes(target, attributes) {
731
+ for (const [name, value] of Object.entries(attributes)) {
732
+ if (value !== void 0) target.setAttribute(name, value);
733
+ }
734
+ }
735
+ function createThemeToggleElement(options = {}) {
736
+ const ownerDocument = options.document ?? globalThis.document;
737
+ if (ownerDocument === void 0) {
738
+ throw new Error("OpenReceive theme toggle element creation requires document.");
739
+ }
740
+ const element = ownerDocument.createElement(OPENRECEIVE_THEME_TOGGLE_ELEMENT_TAG_NAME);
741
+ applyThemeToggleElementAttributes(element, createThemeToggleElementAttributes(options));
742
+ return element;
743
+ }
744
+ function createCheckoutShell(snapshot, options = {}) {
745
+ const ownerDocument = options.document ?? globalThis.document;
746
+ if (ownerDocument === void 0) {
747
+ throw new Error("OpenReceive checkout shell creation requires document.");
748
+ }
749
+ const shell = createCheckoutShellModel(snapshot, options);
750
+ if (shell.themeToggle !== null) {
751
+ applyThemeAttributes(options.root, shell.theme);
752
+ }
753
+ const checkout = ownerDocument.createElement(shell.checkout.tagName);
754
+ applyCheckoutElementAttributes(checkout, shell.checkout.attributes);
755
+ applyCheckoutElementListeners(checkout, shell.checkout.listeners);
756
+ let themeToggle = null;
757
+ if (shell.themeToggle !== null) {
758
+ themeToggle = ownerDocument.createElement(shell.themeToggle.tagName);
759
+ applyThemeToggleElementAttributes(themeToggle, shell.themeToggle.attributes);
760
+ }
761
+ return {
762
+ theme: shell.theme,
763
+ rootAttributes: shell.rootAttributes,
764
+ checkout,
765
+ themeToggle
766
+ };
767
+ }
768
+ export {
769
+ BrowserRequestError,
770
+ OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES,
771
+ OPENRECEIVE_CHECKOUT_DATA_SELECTORS,
772
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES,
773
+ OPENRECEIVE_CHECKOUT_ELEMENT_EVENTS,
774
+ OPENRECEIVE_CHECKOUT_ELEMENT_PARTS,
775
+ OPENRECEIVE_CHECKOUT_ELEMENT_PART_SELECTORS,
776
+ OPENRECEIVE_CHECKOUT_ELEMENT_TAG_NAME,
777
+ OPENRECEIVE_COPY_FEEDBACK_MS,
778
+ OPENRECEIVE_DEFAULT_POLL_INTERVAL_MS,
779
+ OPENRECEIVE_DEFAULT_PREFIX,
780
+ OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES,
781
+ OPENRECEIVE_PAYMENT_WIZARD_SELECTORS,
782
+ OPENRECEIVE_THEME_STORAGE_KEY,
783
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_ATTRIBUTES,
784
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_EVENTS,
785
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_PARTS,
786
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_PART_SELECTORS,
787
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_TAG_NAME,
788
+ applyCheckoutElementAttributes,
789
+ assertDisplayInvoice,
790
+ assetButtonClasses,
791
+ buildMethodGridEntries,
792
+ checkoutElementStyles,
793
+ checkoutLabels,
794
+ copyInvoice,
795
+ createBlockExplorerUrl,
796
+ createCheckoutActionEvent,
797
+ createCheckoutController,
798
+ createCheckoutElementAttributes,
799
+ createCheckoutElementListeners,
800
+ createCheckoutErrorEvent,
801
+ createCheckoutProviderCopyEvent,
802
+ createCheckoutSession,
803
+ createCheckoutShell,
804
+ createCheckoutShellModel,
805
+ createCheckoutSnapshotFromInvoice,
806
+ createCheckoutState,
807
+ createCheckoutStateEvent,
808
+ createCheckoutStatusModel,
809
+ createDetailExternalLink,
810
+ createLightningInvoiceDecodeUrl,
811
+ createPaymentDataEntries,
812
+ createPaymentWizardController,
813
+ createPaymentWizardModel,
814
+ createPaymentWizardSelection,
815
+ createQrPayloadSvg,
816
+ createQrSvg,
817
+ createStatusFetcher,
818
+ createStoredThemeModel,
819
+ createSwapDisplayModel,
820
+ createSwapUnavailableModel,
821
+ createThemeChangeEvent,
822
+ createThemeModel,
823
+ createThemeToggleElement,
824
+ createThemeToggleElementAttributes,
825
+ createTickingValueController,
826
+ createTransactionDetails,
827
+ createTransactionDetailsFromState,
828
+ createTransientFeedbackController,
829
+ createWizardRouteAssetDisplays,
830
+ createWizardRouteDisplays,
831
+ deriveCheckoutStateLabels,
832
+ deriveStatus,
833
+ enterCheckoutResumePath,
834
+ escapeHtml,
835
+ findSwapGridGroup,
836
+ formatAmountCaption,
837
+ formatChooseNetworkHeading,
838
+ formatDepositAmount,
839
+ formatFiatAmount,
840
+ formatMsats,
841
+ formatNetworkSummary,
842
+ formatSwapLimit,
843
+ formatUnixTime,
844
+ getExplorerNetwork,
845
+ getNetworkIcon,
846
+ getPaymentMethodIcon,
847
+ getRouteNetworkLabel,
848
+ getSwapOptionIcon,
849
+ getSwapRefundFormError,
850
+ getWizardEmptyMessage,
851
+ isReusableLightningInvoice,
852
+ mergeAttemptIntoCheckout,
853
+ mergeAttemptIntoSnapshot,
854
+ networkButtonClasses,
855
+ networkCheckClasses,
856
+ networkMobileRevealClasses,
857
+ networkSummaryIconClasses,
858
+ normalizeSwapStartInvoice,
859
+ openWallet,
860
+ orClasses,
861
+ overlaySwapRefundStaging,
862
+ parseBooleanAttribute,
863
+ parseMethodPickerKey,
864
+ parseOptionalInteger,
865
+ parsePaymentMethod,
866
+ parseResolvedTheme,
867
+ parseThemePreference,
868
+ paymentAccentId,
869
+ paymentIconUrls,
870
+ paymentMethods,
871
+ postJson,
872
+ prepareCheckout,
873
+ readThemePreference,
874
+ requestCheckout,
875
+ requestSwapRefund,
876
+ resolvePreservedNetworkSelection,
877
+ resolveTransactionDetailRows,
878
+ selectCheckoutDisplayInvoice,
879
+ startSwapRequest,
880
+ swapAssetMatchesRoute,
881
+ swapGroupLimitOption,
882
+ swapOptionLimitMessage,
883
+ swapPickerKey,
884
+ syncStoredThemeControls,
885
+ toggleStoredThemeControls,
886
+ updatePaymentWizardSelection,
887
+ updateSelectedSwapNetworks,
888
+ validateCheckoutProps,
889
+ wizardNetworkGroupIds,
890
+ writeThemePreference
891
+ };