@openreceive/react 0.3.2 → 0.4.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.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { CheckoutComponentProps, CheckoutState, QrEncoder, BrowserLoggerOption, CheckoutStatusRefresh, Status, SwapRefundStaging, CheckoutSnapshot, AssetUrlResolver, BrowserLogContext, CheckoutInvoiceSnapshot, ThemePreference, ResolvedTheme, ThemeModel, CheckoutPhase, CheckoutStatusModel, UnixSeconds, BrowserLogger, TransactionDetailsSource } from '@openreceive/browser/headless';
2
+ import { CheckoutComponentProps, CheckoutState, QrEncoder, BrowserLoggerOption, CheckoutStatusRefresh, Status, SwapRefundStaging, CheckoutSnapshot, AssetUrlResolver, ThemePreference, BrowserLogContext, CheckoutInvoiceSnapshot, ResolvedTheme, ThemeModel, CheckoutPhase, CheckoutStatusModel, UnixSeconds, BrowserLogger, TransactionDetailsSource } from '@openreceive/browser/headless';
3
3
  export { TransactionDetailsSource, resolveTransactionDetailRows } from '@openreceive/browser/headless';
4
4
 
5
5
  interface CheckoutData {
@@ -164,11 +164,23 @@ interface CheckoutProps extends CheckoutComponentProps, CheckoutEventHandlers, O
164
164
  readonly children?: CheckoutChildren;
165
165
  /** Passed through to the payment wizard. See {@link PaymentWizardProps.resolveAssetUrl}. */
166
166
  readonly resolveAssetUrl?: AssetUrlResolver;
167
+ /**
168
+ * Lock the checkout to one theme. Wins over the stored preference and any
169
+ * ancestor ThemeScope, and hides the toggle: a host embedding the checkout in
170
+ * a page that is already dark passes `theme="dark"` and is done. `"system"`
171
+ * locks to `prefers-color-scheme`, ignoring the stored preference. Unset (the
172
+ * default), the payer's stored choice applies, falling back to
173
+ * `defaultTheme`, falling back to the system scheme. The custom element's
174
+ * `theme` attribute is the same lock.
175
+ */
176
+ readonly theme?: ThemePreference;
167
177
  }
168
178
  interface UseThemeOptions {
169
179
  readonly defaultTheme?: ThemePreference;
170
180
  readonly storageKey?: string;
171
181
  readonly storage?: Storage;
182
+ /** Lock: this preference wins over storage and scope, and `setTheme` becomes a no-op. */
183
+ readonly theme?: ThemePreference;
172
184
  }
173
185
  interface UseThemeResult {
174
186
  readonly theme: ThemePreference;
@@ -195,6 +207,8 @@ interface ThemeScopeProps extends Omit<React.HTMLAttributes<HTMLElement>, "child
195
207
  readonly defaultTheme?: ThemePreference;
196
208
  readonly storageKey?: string;
197
209
  readonly storage?: Storage;
210
+ /** Lock: this preference wins over storage, and the toggle is not rendered. */
211
+ readonly theme?: ThemePreference;
198
212
  readonly themeToggle?: boolean;
199
213
  readonly topbarClassName?: string;
200
214
  readonly themeToggleClassName?: string;
@@ -225,10 +239,12 @@ interface PaymentWizardProps {
225
239
  readonly decodeLinkUrl?: string;
226
240
  /**
227
241
  * Rewrite a packaged asset path (`assets/provider-icons/strike.png`,
228
- * `assets/icons/btc.svg`) into a URL this host can serve. The packaged URLs
229
- * only resolve under Vite/Rollup; every other bundler needs this, or the
230
- * method icons, provider logos and pay tutorials come out as dead `file://`
231
- * links. See docs/guides/provider-registry.md.
242
+ * `assets/pay_tutorials/strike-1.webp`) into a URL this host can serve. The
243
+ * packaged URLs only resolve under Vite/Rollup; every other bundler needs
244
+ * this, or the provider logos and pay tutorials come out as dead `file://`
245
+ * links. The payment-method icons are compiled in as `data:` URIs and need
246
+ * nothing; given a resolver they go through it too (`assets/icons/btc.svg`).
247
+ * See docs/guides/provider-registry.md.
232
248
  */
233
249
  readonly resolveAssetUrl?: AssetUrlResolver;
234
250
  /**
package/dist/index.js CHANGED
@@ -469,6 +469,7 @@ function useLocalTheme(options = {}) {
469
469
  const storageKey = options.storageKey ?? OPENRECEIVE_THEME_STORAGE_KEY;
470
470
  const storage = options.storage;
471
471
  const defaultTheme = options.defaultTheme;
472
+ const lockedTheme = options.theme;
472
473
  const theme = React4.useSyncExternalStore(
473
474
  subscribeStoredTheme,
474
475
  React4.useCallback(
@@ -493,9 +494,10 @@ function useLocalTheme(options = {}) {
493
494
  getSystemDark,
494
495
  getServerSystemDark
495
496
  );
496
- const themeModel = createThemeModel(theme, { systemDark });
497
+ const themeModel = createThemeModel(lockedTheme ?? theme, { systemDark });
497
498
  const setTheme = React4.useCallback(
498
499
  (nextTheme) => {
500
+ if (lockedTheme !== void 0) return;
499
501
  lastSetTheme.set(storageKey, nextTheme);
500
502
  writeThemePreference(nextTheme, {
501
503
  storage,
@@ -503,13 +505,13 @@ function useLocalTheme(options = {}) {
503
505
  });
504
506
  notifyStoredThemeChange();
505
507
  },
506
- [storage, storageKey]
508
+ [storage, storageKey, lockedTheme]
507
509
  );
508
510
  const toggleTheme = React4.useCallback(() => {
509
511
  setTheme(themeModel.nextTheme);
510
512
  }, [setTheme, themeModel.nextTheme]);
511
513
  return {
512
- theme,
514
+ theme: lockedTheme ?? theme,
513
515
  resolvedTheme: themeModel.resolvedTheme,
514
516
  model: themeModel,
515
517
  nextTheme: themeModel.nextTheme,
@@ -525,7 +527,7 @@ function useTheme(options = {}) {
525
527
  const scoped = React4.useContext(ThemeContext);
526
528
  const local = useLocalTheme(options);
527
529
  const storageKey = options.storageKey ?? OPENRECEIVE_THEME_STORAGE_KEY;
528
- if (scoped !== null && options.storage === void 0 && (options.storageKey === void 0 || options.storageKey === storageKey) && options.defaultTheme === void 0) {
530
+ if (scoped !== null && options.theme === void 0 && options.storage === void 0 && (options.storageKey === void 0 || options.storageKey === storageKey) && options.defaultTheme === void 0) {
529
531
  return { ...scoped, fromScope: true };
530
532
  }
531
533
  return local;
@@ -568,6 +570,7 @@ function ThemeScope(props) {
568
570
  defaultTheme,
569
571
  storageKey,
570
572
  storage,
573
+ theme: lockedTheme,
571
574
  themeToggle = false,
572
575
  topbarClassName,
573
576
  themeToggleClassName,
@@ -578,9 +581,11 @@ function ThemeScope(props) {
578
581
  const theme = useLocalTheme({
579
582
  defaultTheme,
580
583
  storageKey,
581
- storage
584
+ storage,
585
+ theme: lockedTheme
582
586
  });
583
587
  const scopedChildren = typeof children === "function" ? children(theme) : children;
588
+ const showsToggle = themeToggle && lockedTheme === void 0;
584
589
  return React4.createElement(
585
590
  ThemeContext.Provider,
586
591
  { value: theme },
@@ -591,7 +596,7 @@ function ThemeScope(props) {
591
596
  ...elementProps,
592
597
  ...theme.attributes
593
598
  },
594
- themeToggle ? React4.createElement(
599
+ showsToggle ? React4.createElement(
595
600
  "div",
596
601
  {
597
602
  className: topbarClassName
@@ -3086,6 +3091,7 @@ function CheckoutView(props) {
3086
3091
  pollIntervalMs,
3087
3092
  paymentWizard = true,
3088
3093
  themeToggle = true,
3094
+ theme: lockedTheme,
3089
3095
  defaultTheme,
3090
3096
  storageKey,
3091
3097
  components,
@@ -3111,9 +3117,11 @@ function CheckoutView(props) {
3111
3117
  });
3112
3118
  const theme = useTheme({
3113
3119
  defaultTheme,
3114
- storageKey
3120
+ storageKey,
3121
+ theme: lockedTheme
3115
3122
  });
3116
- const ownsTheme = themeToggle && !theme.fromScope;
3123
+ const stampsTheme = !theme.fromScope;
3124
+ const ownsTheme = themeToggle && !theme.fromScope && lockedTheme === void 0;
3117
3125
  const [swapFocused, setSwapFocused] = React10.useState(false);
3118
3126
  const QRCodeComponent = components?.QRCode ?? QRCode;
3119
3127
  const InvoiceSummaryComponent = components?.InvoiceSummary ?? InvoiceSummary;
@@ -3160,206 +3168,207 @@ function CheckoutView(props) {
3160
3168
  className: joinClassNames(className, orClasses7.root, classNames?.root),
3161
3169
  [OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES3.root]: "",
3162
3170
  // Under ThemeScope, inherit data-theme from the page. Standalone Checkout owns it.
3163
- ...ownsTheme ? theme.attributes : {}
3171
+ ...stampsTheme ? theme.attributes : {}
3164
3172
  },
3165
- customChildren === void 0 ? [
3166
- // Above the amount and OUTSIDE the Lightning pane, which drops out on
3167
- // the swap deposit panel, on expiry and on the receipt — the payer
3168
- // needs to know what they are buying on all four screens.
3169
- checkoutModel.checkout.description === void 0 || checkoutModel.checkout.description === "" ? null : React10.createElement(
3170
- "p",
3171
- {
3172
- key: "order-description",
3173
- className: joinClassNames(
3174
- orClasses7.orderDescription,
3175
- classNames?.orderDescription
3176
- ),
3177
- [OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES3.orderDescription]: ""
3178
- },
3179
- checkoutModel.checkout.description
3180
- ),
3181
- ownsTheme ? React10.createElement(ThemeToggle, {
3182
- key: "theme",
3183
- className: classNames?.themeToggle,
3184
- theme: theme.theme,
3185
- resolvedTheme: theme.resolvedTheme,
3186
- onThemeChange: theme.setTheme,
3187
- ButtonComponent
3188
- }) : null,
3189
- mintingLightning ? React10.createElement(
3190
- "div",
3191
- {
3192
- key: "minting-lightning",
3193
- className: orClasses7.creating
3194
- },
3195
- React10.createElement("span", {
3196
- className: orClasses7.spinner,
3197
- "aria-hidden": "true"
3198
- }),
3199
- React10.createElement("p", null, checkoutLabels6.preparingPayment)
3200
- ) : null,
3201
- hideLightning ? null : React10.createElement(
3202
- "div",
3203
- {
3204
- key: "payment-layout",
3205
- className: expired || settled ? orClasses7.paymentLayoutExpired : orClasses7.paymentLayout
3206
- },
3207
- lightningPane,
3208
- React10.createElement(
3173
+ [
3174
+ // Order context from the host, composed ABOVE the shipped payment UI —
3175
+ // the same position as the custom element's `order` slot. Children never
3176
+ // replace the payment UI; a host that wants its own checkout builds on
3177
+ // useCheckout / @openreceive/browser/headless instead.
3178
+ customChildren === void 0 ? null : React10.createElement(React10.Fragment, { key: "order-children" }, customChildren),
3179
+ ...[
3180
+ // Above the amount and OUTSIDE the Lightning pane, which drops out on
3181
+ // the swap deposit panel, on expiry and on the receipt — the payer
3182
+ // needs to know what they are buying on all four screens.
3183
+ checkoutModel.checkout.description === void 0 || checkoutModel.checkout.description === "" ? null : React10.createElement(
3184
+ "p",
3185
+ {
3186
+ key: "order-description",
3187
+ className: joinClassNames(orClasses7.orderDescription, classNames?.orderDescription),
3188
+ [OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES3.orderDescription]: ""
3189
+ },
3190
+ checkoutModel.checkout.description
3191
+ ),
3192
+ ownsTheme ? React10.createElement(ThemeToggle, {
3193
+ key: "theme",
3194
+ className: classNames?.themeToggle,
3195
+ theme: theme.theme,
3196
+ resolvedTheme: theme.resolvedTheme,
3197
+ onThemeChange: theme.setTheme,
3198
+ ButtonComponent
3199
+ }) : null,
3200
+ mintingLightning ? React10.createElement(
3209
3201
  "div",
3210
3202
  {
3211
- key: "payment-info",
3212
- className: orClasses7.paymentInfo
3203
+ key: "minting-lightning",
3204
+ className: orClasses7.creating
3213
3205
  },
3214
- expired || settled ? null : React10.createElement(
3215
- "p",
3216
- {
3217
- key: "invoice-title",
3218
- className: joinClassNames(
3219
- orClasses7.invoiceTitle,
3220
- classNames?.invoiceTitle
3221
- )
3222
- },
3223
- checkoutLabels6.bitcoinLightningInvoice
3224
- ),
3225
- React10.createElement(WaitingState, {
3226
- key: "waiting",
3227
- waiting: checkoutModel.waiting,
3228
- statusTitle: checkoutModel.statusTitle,
3229
- statusDetail: checkoutModel.statusDetail,
3230
- settled,
3231
- className: classNames?.waiting
3206
+ React10.createElement("span", {
3207
+ className: orClasses7.spinner,
3208
+ "aria-hidden": "true"
3232
3209
  }),
3233
- checkoutModel.countdownLabel === void 0 ? null : React10.createElement(
3234
- "div",
3235
- {
3236
- key: "countdown",
3237
- className: joinClassNames(orClasses7.countdown, classNames?.countdown)
3238
- },
3239
- checkoutModel.countdownPrefix,
3240
- " ",
3241
- React10.createElement(
3242
- "strong",
3243
- { className: orClasses7.countdownStrong },
3244
- checkoutModel.countdownLabel
3245
- )
3246
- ),
3247
- showSummaryMeta ? React10.createElement(InvoiceSummaryComponent, {
3248
- key: "summary",
3249
- status: checkoutModel.status,
3250
- PaymentStateComponent,
3251
- className: classNames?.summary,
3252
- classNames
3253
- }) : null,
3254
- settled ? React10.createElement(TransactionDetails, {
3255
- key: "transaction-details",
3256
- // The model IS the checkout state, so the panel reads
3257
- // the same derivation the rest of the screen does. It
3258
- // used to re-flatten the snapshot separately, which
3259
- // reported the displayed ATTEMPT's transaction /
3260
- // workflow state on a checkout the state already knows
3261
- // is paid.
3262
- //
3263
- // The SAME panel the swap flow renders one screen
3264
- // earlier. A payer's whole evidence that they paid is a
3265
- // payment hash and, on a swap, a deposit txid — so the
3266
- // most keep-worthy screen gets copy buttons and
3267
- // explorer links, not un-copyable text. No
3268
- // `decodeLinkUrl` is passed, so the bolt11 never
3269
- // reaches a third party.
3270
- state: checkoutModel,
3271
- className: classNames?.details,
3272
- onError
3273
- }) : expired ? React10.createElement(
3210
+ React10.createElement("p", null, checkoutLabels6.preparingPayment)
3211
+ ) : null,
3212
+ hideLightning ? null : React10.createElement(
3213
+ "div",
3214
+ {
3215
+ key: "payment-layout",
3216
+ className: expired || settled ? orClasses7.paymentLayoutExpired : orClasses7.paymentLayout
3217
+ },
3218
+ lightningPane,
3219
+ React10.createElement(
3274
3220
  "div",
3275
3221
  {
3276
- key: "expired-actions",
3277
- className: joinClassNames(orClasses7.actions, classNames?.actions),
3278
- [OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES3.actions]: ""
3222
+ key: "payment-info",
3223
+ className: orClasses7.paymentInfo
3279
3224
  },
3280
- React10.createElement(
3281
- ButtonComponent ?? "button",
3225
+ expired || settled ? null : React10.createElement(
3226
+ "p",
3282
3227
  {
3283
- type: "button",
3284
- className: orClasses7.btn,
3285
- onClick: startOver
3228
+ key: "invoice-title",
3229
+ className: joinClassNames(orClasses7.invoiceTitle, classNames?.invoiceTitle)
3286
3230
  },
3287
- checkoutLabels6.startOver
3288
- )
3289
- ) : React10.createElement(
3290
- "div",
3291
- {
3292
- key: "actions",
3293
- className: joinClassNames(orClasses7.actions, classNames?.actions),
3294
- [OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES3.actions]: ""
3295
- },
3296
- React10.createElement(CopyButton, {
3297
- key: "copy-invoice",
3298
- invoice: checkoutModel.invoice,
3299
- copyInvoice: checkoutModel.copyInvoice,
3300
- onError,
3301
- logger,
3302
- ButtonComponent,
3303
- className: classNames?.copyButton
3304
- }),
3305
- // Opt-in slot: the default checkout ships no wallet button, so a
3306
- // desktop payer is never sent to a handler that does not exist.
3307
- OpenWalletButtonComponent === void 0 ? null : React10.createElement(OpenWalletButtonComponent, {
3308
- key: "open-wallet",
3309
- invoice: checkoutModel.invoice,
3310
- openWallet: checkoutModel.openWallet,
3311
- onError,
3312
- logger,
3313
- ButtonComponent,
3314
- className: classNames?.openWalletButton
3231
+ checkoutLabels6.bitcoinLightningInvoice
3232
+ ),
3233
+ React10.createElement(WaitingState, {
3234
+ key: "waiting",
3235
+ waiting: checkoutModel.waiting,
3236
+ statusTitle: checkoutModel.statusTitle,
3237
+ statusDetail: checkoutModel.statusDetail,
3238
+ settled,
3239
+ className: classNames?.waiting
3315
3240
  }),
3316
- decodeInvoiceHref === void 0 ? null : React10.createElement(
3317
- "a",
3241
+ checkoutModel.countdownLabel === void 0 ? null : React10.createElement(
3242
+ "div",
3243
+ {
3244
+ key: "countdown",
3245
+ className: joinClassNames(orClasses7.countdown, classNames?.countdown)
3246
+ },
3247
+ checkoutModel.countdownPrefix,
3248
+ " ",
3249
+ React10.createElement(
3250
+ "strong",
3251
+ { className: orClasses7.countdownStrong },
3252
+ checkoutModel.countdownLabel
3253
+ )
3254
+ ),
3255
+ showSummaryMeta ? React10.createElement(InvoiceSummaryComponent, {
3256
+ key: "summary",
3257
+ status: checkoutModel.status,
3258
+ PaymentStateComponent,
3259
+ className: classNames?.summary,
3260
+ classNames
3261
+ }) : null,
3262
+ settled ? React10.createElement(TransactionDetails, {
3263
+ key: "transaction-details",
3264
+ // The model IS the checkout state, so the panel reads
3265
+ // the same derivation the rest of the screen does. It
3266
+ // used to re-flatten the snapshot separately, which
3267
+ // reported the displayed ATTEMPT's transaction /
3268
+ // workflow state on a checkout the state already knows
3269
+ // is paid.
3270
+ //
3271
+ // The SAME panel the swap flow renders one screen
3272
+ // earlier. A payer's whole evidence that they paid is a
3273
+ // payment hash and, on a swap, a deposit txid — so the
3274
+ // most keep-worthy screen gets copy buttons and
3275
+ // explorer links, not un-copyable text. No
3276
+ // `decodeLinkUrl` is passed, so the bolt11 never
3277
+ // reaches a third party.
3278
+ state: checkoutModel,
3279
+ className: classNames?.details,
3280
+ onError
3281
+ }) : expired ? React10.createElement(
3282
+ "div",
3318
3283
  {
3319
- key: "decode-invoice",
3320
- className: orClasses7.btn,
3321
- href: decodeInvoiceHref,
3322
- rel: "noreferrer",
3323
- target: "_blank"
3284
+ key: "expired-actions",
3285
+ className: joinClassNames(orClasses7.actions, classNames?.actions),
3286
+ [OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES3.actions]: ""
3324
3287
  },
3325
- checkoutLabels6.decodeInvoice
3288
+ React10.createElement(
3289
+ ButtonComponent ?? "button",
3290
+ {
3291
+ type: "button",
3292
+ className: orClasses7.btn,
3293
+ onClick: startOver
3294
+ },
3295
+ checkoutLabels6.startOver
3296
+ )
3297
+ ) : React10.createElement(
3298
+ "div",
3299
+ {
3300
+ key: "actions",
3301
+ className: joinClassNames(orClasses7.actions, classNames?.actions),
3302
+ [OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES3.actions]: ""
3303
+ },
3304
+ React10.createElement(CopyButton, {
3305
+ key: "copy-invoice",
3306
+ invoice: checkoutModel.invoice,
3307
+ copyInvoice: checkoutModel.copyInvoice,
3308
+ onError,
3309
+ logger,
3310
+ ButtonComponent,
3311
+ className: classNames?.copyButton
3312
+ }),
3313
+ // Opt-in slot: the default checkout ships no wallet button, so a
3314
+ // desktop payer is never sent to a handler that does not exist.
3315
+ OpenWalletButtonComponent === void 0 ? null : React10.createElement(OpenWalletButtonComponent, {
3316
+ key: "open-wallet",
3317
+ invoice: checkoutModel.invoice,
3318
+ openWallet: checkoutModel.openWallet,
3319
+ onError,
3320
+ logger,
3321
+ ButtonComponent,
3322
+ className: classNames?.openWalletButton
3323
+ }),
3324
+ decodeInvoiceHref === void 0 ? null : React10.createElement(
3325
+ "a",
3326
+ {
3327
+ key: "decode-invoice",
3328
+ className: orClasses7.btn,
3329
+ href: decodeInvoiceHref,
3330
+ rel: "noreferrer",
3331
+ target: "_blank"
3332
+ },
3333
+ checkoutLabels6.decodeInvoice
3334
+ )
3326
3335
  )
3327
3336
  )
3328
- )
3329
- ),
3330
- paymentWizard && !settled && (!expired || swapFocused) ? React10.createElement(PaymentWizard, {
3331
- key: "wizard",
3332
- // Only pass invoice when it's a real bolt11 (non-empty, non-deferred).
3333
- invoice: checkoutModel.invoice || void 0,
3334
- checkout: checkoutModel.checkout,
3335
- className: classNames?.wizard,
3336
- logger,
3337
- onError,
3338
- onSwapFocusChange: setSwapFocused,
3339
- prefix,
3340
- qrEncoder,
3341
- decodeLinkUrl,
3342
- logContext: getCheckoutLogContext({
3343
- invoice_id: checkoutModel.invoice_id,
3344
- payment_hash: checkoutModel.payment_hash,
3345
- amount_msats: checkoutModel.amount_msats
3346
- }),
3347
- onProviderCopy,
3348
- onCopy,
3349
- onRequestLightning,
3350
- onSwapStarted,
3351
- resolveAssetUrl,
3352
- assetBaseUrl,
3353
- // Whether a payer who closes the tab has a URL to come back
3354
- // to. Explicit wins — only the host knows about a per-order
3355
- // route of its own; otherwise infer it from the two props that
3356
- // put the reference in the URL.
3357
- resumable: resumable ?? (syncUrl === true || routeReference !== void 0),
3358
- // The engine's staged refund address rides the controller this
3359
- // model owns, so a poll cannot wipe a review in progress.
3360
- swapRefund: checkoutModel
3361
- }) : null
3362
- ] : customChildren
3337
+ ),
3338
+ paymentWizard && !settled && (!expired || swapFocused) ? React10.createElement(PaymentWizard, {
3339
+ key: "wizard",
3340
+ // Only pass invoice when it's a real bolt11 (non-empty, non-deferred).
3341
+ invoice: checkoutModel.invoice || void 0,
3342
+ checkout: checkoutModel.checkout,
3343
+ className: classNames?.wizard,
3344
+ logger,
3345
+ onError,
3346
+ onSwapFocusChange: setSwapFocused,
3347
+ prefix,
3348
+ qrEncoder,
3349
+ decodeLinkUrl,
3350
+ logContext: getCheckoutLogContext({
3351
+ invoice_id: checkoutModel.invoice_id,
3352
+ payment_hash: checkoutModel.payment_hash,
3353
+ amount_msats: checkoutModel.amount_msats
3354
+ }),
3355
+ onProviderCopy,
3356
+ onCopy,
3357
+ onRequestLightning,
3358
+ onSwapStarted,
3359
+ resolveAssetUrl,
3360
+ assetBaseUrl,
3361
+ // Whether a payer who closes the tab has a URL to come back
3362
+ // to. Explicit wins — only the host knows about a per-order
3363
+ // route of its own; otherwise infer it from the two props that
3364
+ // put the reference in the URL.
3365
+ resumable: resumable ?? (syncUrl === true || routeReference !== void 0),
3366
+ // The engine's staged refund address rides the controller this
3367
+ // model owns, so a poll cannot wipe a review in progress.
3368
+ swapRefund: checkoutModel
3369
+ }) : null
3370
+ ]
3371
+ ]
3363
3372
  );
3364
3373
  }
3365
3374