@openreceive/browser 0.4.9 → 0.4.11
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/{chunk-CPVYEWVM.js → chunk-5F7F2ZAM.js} +291 -238
- package/dist/headless.d.ts +14 -3
- package/dist/headless.js +70 -8
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/{status-Doh8Wz4D.d.ts → status-hEzap3jk.d.ts} +8 -4
- package/package.json +3 -3
- package/skills/debug-openreceive-payment/SKILL.md +8 -0
- package/skills/integrate-openreceive/SKILL.md +11 -0
- package/skills/integrate-openreceive/references/btcpay.md +9 -7
- package/skills/integrate-openreceive/references/django.md +12 -3
- package/skills/integrate-openreceive/references/fastapi.md +13 -4
- package/skills/integrate-openreceive/references/fastify.md +13 -4
- package/skills/integrate-openreceive/references/laravel.md +12 -3
- package/skills/integrate-openreceive/references/next.md +13 -4
- package/skills/integrate-openreceive/references/node.md +13 -4
- package/skills/integrate-openreceive/references/php.md +12 -3
- package/skills/integrate-openreceive/references/rails.md +12 -3
- package/skills/integrate-openreceive/references/woocommerce.md +3 -1
package/dist/headless.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AssetIndexEntry, PaymentWizardRoute } from '@openreceive/provider-data';
|
|
2
2
|
export { PaymentWizardRoute, PaymentWizardRouteRequest, getPaymentWizardRoutes, loadPayTutorialImages, payTutorialImage } from '@openreceive/provider-data';
|
|
3
|
-
import { P as PaymentIconId, a as ParseOpenReceiveOptionalIntegerOptions, b as PaymentMethod, R as ResolvedTheme, T as ThemePreference, c as PaymentMethodOption, d as TickingValueOptions, e as TickingValueController, f as TransientFeedbackOptions, g as TransientFeedbackController, C as CheckoutInvoiceSnapshot, U as UnixSeconds, S as SwapDisplayModel, h as CheckoutSnapshot, i as SwapDepositRisk, j as CheckoutState, k as TransactionDetailsInput, l as TransactionDetailRow, m as CreateCheckoutStateOptions, n as CheckoutStatusModelInput, o as CheckoutStatusModel, p as CheckoutPaymentMethod, B as BrowserLoggerOption, q as ThemeAttributeTarget, r as CheckoutElementAttributes, s as CheckoutElementAttributeOptions, t as CheckoutElementEventHandlers, u as CheckoutElementListeners, v as CreateCheckoutShellOptions, w as CheckoutShellElements, x as CheckoutShellOptions, y as CheckoutShellModel, z as CreateOpenReceiveThemeToggleElementOptions, A as ThemeToggleElementAttributeOptions, D as ThemeToggleElementAttributes, E as StoredThemeModelOptions, F as ThemeModel, G as ThemeModelOptions, H as ReadThemePreferenceOptions, I as ThemeControlTargets, J as ThemeStorageOptions, K as PaymentWizardControllerOptions, L as PaymentWizardController, M as PaymentWizardSelection, N as PaymentWizardModel, W as WizardRouteAssetDisplay, O as WizardRouteDisplay, Q as PaymentWizardSelectionAction } from './status-
|
|
4
|
-
export { V as BrowserLogContext, X as BrowserLogger, Y as BrowserRequestError, Z as CheckoutController, _ as CheckoutControllerOptions, $ as CheckoutPhase, a0 as CheckoutShellRootAttributes, a1 as CheckoutStatusRefresh, a2 as OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES, a3 as OPENRECEIVE_CHECKOUT_DATA_SELECTORS, a4 as OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES, a5 as OPENRECEIVE_CHECKOUT_ELEMENT_EVENTS, a6 as OPENRECEIVE_CHECKOUT_ELEMENT_PARTS, a7 as OPENRECEIVE_CHECKOUT_ELEMENT_PART_SELECTORS, a8 as OPENRECEIVE_CHECKOUT_ELEMENT_SLOTS, a9 as OPENRECEIVE_CHECKOUT_ELEMENT_TAG_NAME, aa as OPENRECEIVE_COPY_FEEDBACK_MS, ab as OPENRECEIVE_DEFAULT_POLL_INTERVAL_MS, ac as OPENRECEIVE_DEFAULT_PREFIX, ad as OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES, ae as OPENRECEIVE_PAYMENT_WIZARD_SELECTORS, af as OPENRECEIVE_PROVIDER_PREVIEW_LIMIT, ag as OPENRECEIVE_STYLE_ROOT_ATTRIBUTE, ah as OPENRECEIVE_STYLE_ROOT_SELECTOR, ai as OPENRECEIVE_THEME_STORAGE_KEY, aj as OPENRECEIVE_THEME_TOGGLE_ELEMENT_ATTRIBUTES, ak as OPENRECEIVE_THEME_TOGGLE_ELEMENT_EVENTS, al as OPENRECEIVE_THEME_TOGGLE_ELEMENT_PARTS, am as OPENRECEIVE_THEME_TOGGLE_ELEMENT_PART_SELECTORS, an as OPENRECEIVE_THEME_TOGGLE_ELEMENT_TAG_NAME, ao as QrEncoder, ap as QrSvgController, aq as QrSvgControllerOptions, ar as Status, as as SwapCopyRow, at as SwapRefundStaging, au as WizardProviderDisplay, av as assertDisplayInvoice, aw as copyInvoice, ax as createCheckoutActionEvent, ay as createCheckoutController, az as createCheckoutErrorEvent, aA as createCheckoutProviderCopyEvent, aB as createCheckoutStateEvent, aC as createQrPayloadSvg, aD as createQrSvg, aE as createQrSvgController, aF as createStatusFetcher, aG as createThemeChangeEvent, aH as currentCheckoutUrl, aI as deriveCheckoutStateLabels, aJ as deriveStatus, aK as enterCheckoutResumePath, aL as escapeHtml, aM as formatAmountCaption, aN as formatDepositAmount, aO as formatFiatAmount, aP as formatMsats, aQ as formatSwapLimit, aR as formatUnixTime, aS as openWallet, aT as paymentIconSvgs, aU as prepareCheckout, aV as requestCheckout } from './status-
|
|
3
|
+
import { P as PaymentIconId, a as ParseOpenReceiveOptionalIntegerOptions, b as PaymentMethod, R as ResolvedTheme, T as ThemePreference, c as PaymentMethodOption, d as TickingValueOptions, e as TickingValueController, f as TransientFeedbackOptions, g as TransientFeedbackController, C as CheckoutInvoiceSnapshot, U as UnixSeconds, S as SwapDisplayModel, h as CheckoutSnapshot, i as SwapDepositRisk, j as CheckoutState, k as TransactionDetailsInput, l as TransactionDetailRow, m as CreateCheckoutStateOptions, n as CheckoutStatusModelInput, o as CheckoutStatusModel, p as CheckoutPaymentMethod, B as BrowserLoggerOption, q as ThemeAttributeTarget, r as CheckoutElementAttributes, s as CheckoutElementAttributeOptions, t as CheckoutElementEventHandlers, u as CheckoutElementListeners, v as CreateCheckoutShellOptions, w as CheckoutShellElements, x as CheckoutShellOptions, y as CheckoutShellModel, z as CreateOpenReceiveThemeToggleElementOptions, A as ThemeToggleElementAttributeOptions, D as ThemeToggleElementAttributes, E as StoredThemeModelOptions, F as ThemeModel, G as ThemeModelOptions, H as ReadThemePreferenceOptions, I as ThemeControlTargets, J as ThemeStorageOptions, K as PaymentWizardControllerOptions, L as PaymentWizardController, M as PaymentWizardSelection, N as PaymentWizardModel, W as WizardRouteAssetDisplay, O as WizardRouteDisplay, Q as PaymentWizardSelectionAction } from './status-hEzap3jk.js';
|
|
4
|
+
export { V as BrowserLogContext, X as BrowserLogger, Y as BrowserRequestError, Z as CheckoutController, _ as CheckoutControllerOptions, $ as CheckoutPhase, a0 as CheckoutShellRootAttributes, a1 as CheckoutStatusRefresh, a2 as OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES, a3 as OPENRECEIVE_CHECKOUT_DATA_SELECTORS, a4 as OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES, a5 as OPENRECEIVE_CHECKOUT_ELEMENT_EVENTS, a6 as OPENRECEIVE_CHECKOUT_ELEMENT_PARTS, a7 as OPENRECEIVE_CHECKOUT_ELEMENT_PART_SELECTORS, a8 as OPENRECEIVE_CHECKOUT_ELEMENT_SLOTS, a9 as OPENRECEIVE_CHECKOUT_ELEMENT_TAG_NAME, aa as OPENRECEIVE_COPY_FEEDBACK_MS, ab as OPENRECEIVE_DEFAULT_POLL_INTERVAL_MS, ac as OPENRECEIVE_DEFAULT_PREFIX, ad as OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES, ae as OPENRECEIVE_PAYMENT_WIZARD_SELECTORS, af as OPENRECEIVE_PROVIDER_PREVIEW_LIMIT, ag as OPENRECEIVE_STYLE_ROOT_ATTRIBUTE, ah as OPENRECEIVE_STYLE_ROOT_SELECTOR, ai as OPENRECEIVE_THEME_STORAGE_KEY, aj as OPENRECEIVE_THEME_TOGGLE_ELEMENT_ATTRIBUTES, ak as OPENRECEIVE_THEME_TOGGLE_ELEMENT_EVENTS, al as OPENRECEIVE_THEME_TOGGLE_ELEMENT_PARTS, am as OPENRECEIVE_THEME_TOGGLE_ELEMENT_PART_SELECTORS, an as OPENRECEIVE_THEME_TOGGLE_ELEMENT_TAG_NAME, ao as QrEncoder, ap as QrSvgController, aq as QrSvgControllerOptions, ar as Status, as as SwapCopyRow, at as SwapRefundStaging, au as WizardProviderDisplay, av as assertDisplayInvoice, aw as copyInvoice, ax as createCheckoutActionEvent, ay as createCheckoutController, az as createCheckoutErrorEvent, aA as createCheckoutProviderCopyEvent, aB as createCheckoutStateEvent, aC as createQrPayloadSvg, aD as createQrSvg, aE as createQrSvgController, aF as createStatusFetcher, aG as createThemeChangeEvent, aH as currentCheckoutUrl, aI as deriveCheckoutStateLabels, aJ as deriveStatus, aK as enterCheckoutResumePath, aL as escapeHtml, aM as formatAmountCaption, aN as formatDepositAmount, aO as formatFiatAmount, aP as formatMsats, aQ as formatSwapLimit, aR as formatUnixTime, aS as openWallet, aT as paymentIconSvgs, aU as prepareCheckout, aV as requestCheckout } from './status-hEzap3jk.js';
|
|
5
5
|
import '@openreceive/core';
|
|
6
6
|
|
|
7
7
|
/** Each packaged payment icon as a `data:image/svg+xml` URI, keyed by id. */
|
|
@@ -747,13 +747,15 @@ interface CheckoutSessionOptions {
|
|
|
747
747
|
snapshot(): CheckoutSnapshot | undefined;
|
|
748
748
|
/** The order being paid, read at call time (the element's is an attribute). */
|
|
749
749
|
reference(): string | undefined;
|
|
750
|
+
/** Endpoint is part of checkout identity; trailing slashes are equivalent. */
|
|
751
|
+
prefix?(): string | undefined;
|
|
750
752
|
/**
|
|
751
753
|
* Mint a Lightning invoice for this reference (POST `${prefix}/checkouts`).
|
|
752
754
|
* The host closes over its own prefix, metadata and fetch. Answer `undefined`
|
|
753
755
|
* to say "this host cannot mint" — React's payment wizard is such a host: it
|
|
754
756
|
* asks its parent for Lightning through `onRequestLightning` instead.
|
|
755
757
|
*/
|
|
756
|
-
requestCheckout?(reference: string): Promise<CheckoutSnapshot> | undefined;
|
|
758
|
+
requestCheckout?(reference: string, signal?: AbortSignal): Promise<CheckoutSnapshot> | undefined;
|
|
757
759
|
/** Publish a snapshot that now carries the Lightning attempt. */
|
|
758
760
|
onSnapshot?(snapshot: CheckoutSnapshot): void;
|
|
759
761
|
/**
|
|
@@ -785,6 +787,14 @@ interface CheckoutSession {
|
|
|
785
787
|
* carries the accepted range the host renders in its unavailable panel.
|
|
786
788
|
*/
|
|
787
789
|
readonly swapQuotes: Readonly<Record<string, CheckoutPaymentMethod>>;
|
|
790
|
+
/** Invalidate every outstanding action when identity changes. */
|
|
791
|
+
syncIdentity(): void;
|
|
792
|
+
reset(): void;
|
|
793
|
+
dispose(): void;
|
|
794
|
+
capture(): {
|
|
795
|
+
readonly signal: AbortSignal;
|
|
796
|
+
isCurrent(): boolean;
|
|
797
|
+
};
|
|
788
798
|
ensureLightning(): Promise<void>;
|
|
789
799
|
/**
|
|
790
800
|
* Quote the pay-in asset, then start the swap when the quote confirms the
|
|
@@ -825,6 +835,7 @@ declare function createCheckoutShell(snapshot: CheckoutSnapshot, options?: Creat
|
|
|
825
835
|
* URL input — no call in this module takes a route of its own.
|
|
826
836
|
*/
|
|
827
837
|
interface SwapRequestOptions {
|
|
838
|
+
readonly signal?: AbortSignal;
|
|
828
839
|
readonly fetch: typeof globalThis.fetch;
|
|
829
840
|
readonly prefix: string;
|
|
830
841
|
readonly logger?: BrowserLoggerOption;
|
package/dist/headless.js
CHANGED
|
@@ -119,7 +119,7 @@ import {
|
|
|
119
119
|
swapOptionLimitSentence,
|
|
120
120
|
swapPickerKey,
|
|
121
121
|
updatePaymentWizardSelection
|
|
122
|
-
} from "./chunk-
|
|
122
|
+
} from "./chunk-5F7F2ZAM.js";
|
|
123
123
|
|
|
124
124
|
// src/headless.ts
|
|
125
125
|
import {
|
|
@@ -177,7 +177,43 @@ function createCheckoutSession(options) {
|
|
|
177
177
|
let mintingLightning = false;
|
|
178
178
|
let startingSwapAsset = null;
|
|
179
179
|
let swapQuotes = {};
|
|
180
|
+
let generation = 0;
|
|
181
|
+
let abort = new AbortController();
|
|
182
|
+
const identityKey = () => JSON.stringify([
|
|
183
|
+
options.reference(),
|
|
184
|
+
(options.prefix?.() ?? options.swap?.prefix() ?? "").replace(/\/+$/, "")
|
|
185
|
+
]);
|
|
186
|
+
let identity = identityKey();
|
|
187
|
+
function invalidateActions() {
|
|
188
|
+
abort.abort();
|
|
189
|
+
abort = new AbortController();
|
|
190
|
+
generation += 1;
|
|
191
|
+
mintingLightning = false;
|
|
192
|
+
startingSwapAsset = null;
|
|
193
|
+
}
|
|
194
|
+
function reset() {
|
|
195
|
+
invalidateActions();
|
|
196
|
+
identity = identityKey();
|
|
197
|
+
wizardError = void 0;
|
|
198
|
+
swapStartError = void 0;
|
|
199
|
+
lightningRequested = false;
|
|
200
|
+
mintingLightning = false;
|
|
201
|
+
startingSwapAsset = null;
|
|
202
|
+
swapQuotes = {};
|
|
203
|
+
}
|
|
204
|
+
function syncIdentity() {
|
|
205
|
+
if (identityKey() !== identity) reset();
|
|
206
|
+
}
|
|
207
|
+
function capture() {
|
|
208
|
+
syncIdentity();
|
|
209
|
+
const captured = generation;
|
|
210
|
+
return {
|
|
211
|
+
signal: abort.signal,
|
|
212
|
+
isCurrent: () => captured === generation && identityKey() === identity
|
|
213
|
+
};
|
|
214
|
+
}
|
|
180
215
|
async function ensureLightning() {
|
|
216
|
+
const action = capture();
|
|
181
217
|
if (mintingLightning) return;
|
|
182
218
|
const reference = options.reference();
|
|
183
219
|
if (reference === void 0 || reference.length === 0) return;
|
|
@@ -195,20 +231,25 @@ function createCheckoutSession(options) {
|
|
|
195
231
|
wizardError = void 0;
|
|
196
232
|
options.onChange();
|
|
197
233
|
try {
|
|
198
|
-
const pending = options.requestCheckout?.(reference);
|
|
234
|
+
const pending = options.requestCheckout?.(reference, action.signal);
|
|
199
235
|
if (pending === void 0) return;
|
|
200
236
|
const checkout = await pending;
|
|
237
|
+
if (!action.isCurrent()) return;
|
|
201
238
|
lightningRequested = true;
|
|
202
239
|
options.onSnapshot?.(mergeMintedCheckout(checkout, options.snapshot()));
|
|
203
240
|
} catch (error) {
|
|
241
|
+
if (!action.isCurrent()) return;
|
|
204
242
|
wizardError = payerFacingMessage(error, MINT_FAILED);
|
|
205
243
|
options.onError(error);
|
|
206
244
|
} finally {
|
|
207
|
-
|
|
208
|
-
|
|
245
|
+
if (action.isCurrent()) {
|
|
246
|
+
mintingLightning = false;
|
|
247
|
+
options.onChange();
|
|
248
|
+
}
|
|
209
249
|
}
|
|
210
250
|
}
|
|
211
251
|
async function startSwap(payInAsset) {
|
|
252
|
+
const action = capture();
|
|
212
253
|
if (startingSwapAsset !== null) return;
|
|
213
254
|
const swap = options.swap;
|
|
214
255
|
if (swap === void 0) {
|
|
@@ -239,9 +280,18 @@ function createCheckoutSession(options) {
|
|
|
239
280
|
swapStartError = void 0;
|
|
240
281
|
options.onChange();
|
|
241
282
|
try {
|
|
242
|
-
const quote = await quoteSwapAsset(
|
|
283
|
+
const quote = await quoteSwapAsset(
|
|
284
|
+
payInAsset,
|
|
285
|
+
prefix,
|
|
286
|
+
fetcher,
|
|
287
|
+
reference,
|
|
288
|
+
csrfHeader,
|
|
289
|
+
action
|
|
290
|
+
);
|
|
291
|
+
if (!action.isCurrent()) return;
|
|
243
292
|
if (quote !== void 0 && quote.available === false) return;
|
|
244
293
|
const started = await startSwapRequest({
|
|
294
|
+
signal: action.signal,
|
|
245
295
|
fetch: fetcher,
|
|
246
296
|
prefix,
|
|
247
297
|
...csrfHeader === void 0 ? {} : { csrfHeader },
|
|
@@ -249,12 +299,14 @@ function createCheckoutSession(options) {
|
|
|
249
299
|
payInAsset,
|
|
250
300
|
...options.logger === void 0 ? {} : { logger: options.logger }
|
|
251
301
|
});
|
|
302
|
+
if (!action.isCurrent()) return;
|
|
252
303
|
selection.setStarted(started);
|
|
253
304
|
selection.setDismissedInvoiceId(null);
|
|
254
305
|
swap.onStarted?.(started);
|
|
255
306
|
selection.setSelectedAsset(payInAsset);
|
|
256
307
|
options.onChange();
|
|
257
308
|
} catch (error) {
|
|
309
|
+
if (!action.isCurrent()) return;
|
|
258
310
|
const landed = selection.started();
|
|
259
311
|
if (landed?.swap?.pay_in_asset === payInAsset && landed.invoice_id !== selection.dismissedInvoiceId()) {
|
|
260
312
|
selection.setSelectedAsset(payInAsset);
|
|
@@ -264,17 +316,22 @@ function createCheckoutSession(options) {
|
|
|
264
316
|
selection.setSelectedAsset(payInAsset);
|
|
265
317
|
failSwapStart(error);
|
|
266
318
|
} finally {
|
|
267
|
-
|
|
319
|
+
if (action.isCurrent()) {
|
|
320
|
+
startingSwapAsset = null;
|
|
321
|
+
options.onChange();
|
|
322
|
+
}
|
|
268
323
|
}
|
|
269
324
|
}
|
|
270
|
-
async function quoteSwapAsset(payInAsset, prefix, fetcher, reference, csrfHeader) {
|
|
325
|
+
async function quoteSwapAsset(payInAsset, prefix, fetcher, reference, csrfHeader, action) {
|
|
271
326
|
const body = await postJson({
|
|
327
|
+
signal: action.signal,
|
|
272
328
|
fetch: fetcher,
|
|
273
329
|
prefix,
|
|
274
330
|
...csrfHeader === void 0 ? {} : { csrfHeader },
|
|
275
331
|
...options.logger === void 0 ? {} : { logger: options.logger },
|
|
276
332
|
body: { reference, action: "swap_quote", pay_in_asset: payInAsset }
|
|
277
333
|
});
|
|
334
|
+
if (!action.isCurrent()) return void 0;
|
|
278
335
|
const quote = normalizeSwapQuote(body);
|
|
279
336
|
if (quote === void 0) return void 0;
|
|
280
337
|
swapQuotes = { ...swapQuotes, [quote.pay_in_asset]: quote };
|
|
@@ -304,12 +361,17 @@ function createCheckoutSession(options) {
|
|
|
304
361
|
get swapQuotes() {
|
|
305
362
|
return swapQuotes;
|
|
306
363
|
},
|
|
364
|
+
syncIdentity,
|
|
365
|
+
reset,
|
|
366
|
+
dispose: reset,
|
|
367
|
+
capture,
|
|
307
368
|
ensureLightning,
|
|
308
369
|
startSwap,
|
|
309
370
|
resetLightningRequest() {
|
|
310
|
-
|
|
371
|
+
reset();
|
|
311
372
|
},
|
|
312
373
|
clearSwapStartError() {
|
|
374
|
+
invalidateActions();
|
|
313
375
|
swapStartError = void 0;
|
|
314
376
|
}
|
|
315
377
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { aW as BrowserLogLevel } from './status-
|
|
2
|
-
export { aX as BrowserLogEntry, X as BrowserLogger, B as BrowserLoggerOption, Y as BrowserRequestError, Z as CheckoutController, _ as CheckoutControllerOptions, h as CheckoutSnapshot, j as CheckoutState, aY as CopyInvoiceOptions, aZ as GuestCheckoutResumeController, a_ as GuestCheckoutResumeOptions, a$ as OpenWalletOptions, b0 as PrepareCheckoutOptions, b1 as QrOptions, b2 as RequestCheckoutOptions, ar as Status, b3 as StatusInvoiceLike, U as UnixSeconds, aw as copyInvoice, ay as createCheckoutController, b4 as createGuestCheckoutResume, b5 as createGuestOrderFetcher, b6 as createLightningUri, b7 as createQrPngDataUrl, aD as createQrSvg, aJ as deriveStatus, aK as enterCheckoutResumePath, aS as openWallet, aU as prepareCheckout, aV as requestCheckout } from './status-
|
|
1
|
+
import { aW as BrowserLogLevel } from './status-hEzap3jk.js';
|
|
2
|
+
export { aX as BrowserLogEntry, X as BrowserLogger, B as BrowserLoggerOption, Y as BrowserRequestError, Z as CheckoutController, _ as CheckoutControllerOptions, h as CheckoutSnapshot, j as CheckoutState, aY as CopyInvoiceOptions, aZ as GuestCheckoutResumeController, a_ as GuestCheckoutResumeOptions, a$ as OpenWalletOptions, b0 as PrepareCheckoutOptions, b1 as QrOptions, b2 as RequestCheckoutOptions, ar as Status, b3 as StatusInvoiceLike, U as UnixSeconds, aw as copyInvoice, ay as createCheckoutController, b4 as createGuestCheckoutResume, b5 as createGuestOrderFetcher, b6 as createLightningUri, b7 as createQrPngDataUrl, aD as createQrSvg, aJ as deriveStatus, aK as enterCheckoutResumePath, aS as openWallet, aU as prepareCheckout, aV as requestCheckout } from './status-hEzap3jk.js';
|
|
3
3
|
import '@openreceive/provider-data';
|
|
4
4
|
import '@openreceive/core';
|
|
5
5
|
|
package/dist/index.js
CHANGED
|
@@ -431,14 +431,17 @@ interface CheckoutInvoiceSwapSnapshot {
|
|
|
431
431
|
}
|
|
432
432
|
/**
|
|
433
433
|
* Formatted fee breakout for the deposit panel, explaining why the payer sends more
|
|
434
|
-
* than the cart total. All figures are display-ready
|
|
434
|
+
* than the cart total. All figures are display-ready strings. `cartTotal` is
|
|
435
|
+
* always fiat; `youSend` and `fee` are fiat for a floating asset and token
|
|
436
|
+
* amounts ("50.05 USDC") for a stablecoin pegged to the fee currency, where a
|
|
437
|
+
* fiat valuation would read as the deposit amount with a typo.
|
|
435
438
|
*/
|
|
436
439
|
interface SwapFeeBreakdown {
|
|
437
440
|
/** Cart total delivered to the merchant, e.g. "$10.00". */
|
|
438
441
|
readonly cartTotal: string;
|
|
439
|
-
/**
|
|
442
|
+
/** What the payer sends: its fiat value ("$10.59") or, for a pegged stablecoin, the deposit amount itself ("10.59 USDC"). */
|
|
440
443
|
readonly youSend: string;
|
|
441
|
-
/** The swap fee absorbed by the payer (exchange spread + network fees), e.g. "$0.59". */
|
|
444
|
+
/** The swap fee absorbed by the payer (exchange spread + network fees), e.g. "$0.59" or "0.59 USDC". */
|
|
442
445
|
readonly fee: string;
|
|
443
446
|
/** The fee as a percentage of the cart total, e.g. "5.9%", when computable. */
|
|
444
447
|
readonly feePercent?: string;
|
|
@@ -817,8 +820,9 @@ interface RequestCheckoutOptions extends RequestCheckoutBaseOptions {
|
|
|
817
820
|
* `prepareCheckout` posts only the order id — it locks the amount and lists
|
|
818
821
|
* payment methods without minting — so there is no memo or metadata to carry.
|
|
819
822
|
*/
|
|
820
|
-
type PrepareCheckoutOptions = Pick<RequestCheckoutBaseOptions, "prefix" | "reference" | "fetch" | "headers" | "csrfHeader">;
|
|
823
|
+
type PrepareCheckoutOptions = Pick<RequestCheckoutBaseOptions, "prefix" | "reference" | "fetch" | "headers" | "csrfHeader" | "signal">;
|
|
821
824
|
interface RequestCheckoutBaseOptions {
|
|
825
|
+
readonly signal?: AbortSignal;
|
|
822
826
|
/**
|
|
823
827
|
* Base path the shipped router is mounted at (e.g. `/openreceive`). The create and
|
|
824
828
|
* prepare routes are derived from it — see {@link checkoutRoutes}. It is required
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openreceive/browser",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.11",
|
|
4
4
|
"description": "Browser helpers and a headless UI engine for Bitcoin Lightning checkout and optional USDT, USDC, SOL and ETH swaps.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bitcoin",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"./styles.css": "./dist/styles.css"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@openreceive/core": "0.4.
|
|
34
|
-
"@openreceive/provider-data": "0.4.
|
|
33
|
+
"@openreceive/core": "0.4.11",
|
|
34
|
+
"@openreceive/provider-data": "0.4.11",
|
|
35
35
|
"qrcode": "^1.5.4"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
@@ -70,6 +70,14 @@ same diagnostics redacted, always exit 0 — safe to share.
|
|
|
70
70
|
- Refunds exist only for swap deposits from `refund_required`. There is **no
|
|
71
71
|
Lightning refund** — the wallet cannot spend. Do not chase one.
|
|
72
72
|
https://openreceive.org/guides/swap-refunds.md
|
|
73
|
+
- "Payer reports two different amounts on a stablecoin checkout" (50.05 or
|
|
74
|
+
50.03?): the deposit amount is a token quantity, `fee.pay_in_fiat` is its
|
|
75
|
+
fiat valuation. Only `swap.deposit_amount` is an instruction. From 0.4.10 the
|
|
76
|
+
packaged checkout renders a USD stablecoin's breakdown in the token and never
|
|
77
|
+
shows `pay_in_fiat`; on an older bundle, upgrade `@openreceive/*`. To verify,
|
|
78
|
+
read the row's `deposit_amount` and `fee` and confirm the UI shows only the
|
|
79
|
+
deposit amount. A custom UI must call `createSwapFeeBreakdown(fee, swap)`
|
|
80
|
+
with the swap, not the fee alone.
|
|
73
81
|
|
|
74
82
|
## 6. Checkout UI shows nothing
|
|
75
83
|
|
|
@@ -86,6 +86,17 @@ state; do not retry-loop it, and do not build an idempotency store around it —
|
|
|
86
86
|
that serialization is the library's job. (A hook failure while persisting an
|
|
87
87
|
attempt is a **503 retryable**, deliberately distinct.)
|
|
88
88
|
|
|
89
|
+
## Amounts on the deposit panel
|
|
90
|
+
|
|
91
|
+
`swap.deposit_amount` is the ONLY amount a payer is ever told to send, in the
|
|
92
|
+
pay-in token. `swap.fee.pay_in_fiat` / `payout_fiat` are fiat valuations that
|
|
93
|
+
explain the spread (why the deposit exceeds the cart total); they are not
|
|
94
|
+
instructions. For a stablecoin pegged to the fee currency (USDT, USDC) the
|
|
95
|
+
packaged checkout expresses the breakdown in the token and never renders
|
|
96
|
+
`pay_in_fiat` — "$50.03" under "50.05 USDC" reads as the same number with a
|
|
97
|
+
typo. A custom UI gets the same rule from `createSwapFeeBreakdown(fee, swap)`;
|
|
98
|
+
pass the swap, not just the fee.
|
|
99
|
+
|
|
89
100
|
## Secrets
|
|
90
101
|
|
|
91
102
|
`NWC_URI` and `LSC_URI_*` are server-only. Never put them in browser code,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# OpenReceive agent directions (BTCPay Server)
|
|
2
2
|
|
|
3
|
-
These directions describe OpenReceive 0.4.
|
|
3
|
+
These directions describe OpenReceive 0.4.11.
|
|
4
4
|
|
|
5
5
|
Connect a BTCPay Server store to a receive-only NWC wallet with the OpenReceive
|
|
6
6
|
plugin, and optionally let payers pay BTCPay invoices with USDT, USDC, ETH or
|
|
@@ -32,7 +32,7 @@ refund path on the same checkout screen.
|
|
|
32
32
|
|
|
33
33
|
## Step 0 — check the deployment before you change anything
|
|
34
34
|
|
|
35
|
-
1. Confirm the BTCPay Server version is 2.4.
|
|
35
|
+
1. Confirm the BTCPay Server version is 2.4.4 or later (Server Settings →
|
|
36
36
|
About, or `GET /api/v1/server/info`). The plugin declares that minimum and
|
|
37
37
|
BTCPay refuses to load it below.
|
|
38
38
|
2. Check whether the plugin is installed (Server Settings → Plugins, or the
|
|
@@ -119,6 +119,8 @@ enough; drop the `.md` for the same page a person would read.
|
|
|
119
119
|
Questions, or a problem with the plugin itself:
|
|
120
120
|
https://openreceive.org/contact
|
|
121
121
|
|
|
122
|
+
- https://openreceive.org/guides/payment-safety-upgrade.md — coordinated upgrades and reviewed repair of existing attempts
|
|
123
|
+
|
|
122
124
|
---
|
|
123
125
|
|
|
124
126
|
## The quickstart, in full
|
|
@@ -128,7 +130,7 @@ passes. The page it comes from is https://openreceive.org/guides/quickstart-btcp
|
|
|
128
130
|
|
|
129
131
|
## BTCPay Server quickstart
|
|
130
132
|
|
|
131
|
-
Requires BTCPay Server ≥ 2.4.
|
|
133
|
+
Requires BTCPay Server ≥ 2.4.4.
|
|
132
134
|
|
|
133
135
|
The OpenReceive plugin makes a receive-only NWC wallet the Lightning node of a
|
|
134
136
|
BTCPay store. BTCPay mints every Lightning invoice in that wallet and records
|
|
@@ -143,7 +145,7 @@ invoices, checkout, webhooks and Greenfield API are the host.
|
|
|
143
145
|
|
|
144
146
|
### 1. Prerequisites
|
|
145
147
|
|
|
146
|
-
- A BTCPay Server, version 2.4.
|
|
148
|
+
- A BTCPay Server, version 2.4.4 or later, on any network (mainnet, testnet,
|
|
147
149
|
signet, regtest). The wallet must be on the same network.
|
|
148
150
|
- A receive-only NWC code for the wallet you want to receive into
|
|
149
151
|
([get one here](https://openreceive.org/get_a_nwc_code_to_receive_payments)).
|
|
@@ -157,9 +159,9 @@ invoices, checkout, webhooks and Greenfield API are the host.
|
|
|
157
159
|
|
|
158
160
|
In BTCPay, open **Server Settings → Plugins**, search the plugin directory
|
|
159
161
|
for **OpenReceive**, click **Install**, and restart BTCPay when prompted.
|
|
160
|
-
BTCPay creates the plugin's
|
|
161
|
-
`BTCPayServer.Plugins.OpenReceive`) in its own
|
|
162
|
-
else is created.
|
|
162
|
+
BTCPay creates the plugin's two tables (`openreceive_invoices` and
|
|
163
|
+
`openreceive_swaps`, schema `BTCPayServer.Plugins.OpenReceive`) in its own
|
|
164
|
+
Postgres at startup; nothing else is created.
|
|
163
165
|
|
|
164
166
|
To build the plugin from source instead, follow
|
|
165
167
|
[the .NET workspace README](https://github.com/OpenReceive/openreceive/blob/master/packages/dotnet/README.md).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# OpenReceive agent directions (Django)
|
|
2
2
|
|
|
3
|
-
These directions describe OpenReceive 0.4.
|
|
3
|
+
These directions describe OpenReceive 0.4.11.
|
|
4
4
|
|
|
5
5
|
Add OpenReceive to a Django project — the app you are already working in. You
|
|
6
6
|
do not need a copy of the OpenReceive source: the Python package is on PyPI
|
|
@@ -130,7 +130,7 @@ itself, and they hold for every integration.
|
|
|
130
130
|
a placeholder that allows everything (`manage.py check` warns
|
|
131
131
|
`openreceive.W002` while it is set) — replace it with this app's real
|
|
132
132
|
ownership check, same as `on_paid`.
|
|
133
|
-
- `on_paid` must be idempotent.
|
|
133
|
+
- `on_paid` must be idempotent. Its database fulfillment commits once per `reference` — your order
|
|
134
134
|
id, one per thing you fulfill, created before checkout, kept across retries,
|
|
135
135
|
never reused. A fresh id per page load lets one order be paid twice.
|
|
136
136
|
- Receive-only NWC is required; a spend-capable code fails closed at boot unless
|
|
@@ -231,6 +231,13 @@ built on `@openreceive/browser/headless`. Read that before writing components.
|
|
|
231
231
|
- `createSwapDisplayModel` → `display.copyRows` for deposits: address, memo,
|
|
232
232
|
and the bare amount each get a copy row. Render `swap.networkWarning*` as
|
|
233
233
|
the model gives it.
|
|
234
|
+
- `swap.deposit_amount` is the only amount a payer is told to send. Never put
|
|
235
|
+
a fiat valuation of it (`swap.fee.pay_in_fiat`) next to a stablecoin amount:
|
|
236
|
+
"$50.03" under "50.05 USDC" reads as a typo, and the payer asks which one to
|
|
237
|
+
send. The one fiat figure on a USDT/USDC deposit panel is the cart total
|
|
238
|
+
(`payout_fiat`); express "you send" and the fee in the token. Use
|
|
239
|
+
`createSwapFeeBreakdown(fee, swap)` — with the swap, not the fee alone — and
|
|
240
|
+
it applies this for you; SOL and ETH keep a fiat breakdown.
|
|
234
241
|
- `createCheckoutSession` owns mint and swap start. To start swaps, pass its
|
|
235
242
|
`swap` option (`selection`, `prefix`, `fetch`) together. Without it
|
|
236
243
|
`startSwap` reports through `onError`.
|
|
@@ -300,6 +307,8 @@ enough; drop the `.md` for the same page a person would read.
|
|
|
300
307
|
Questions, or a problem with the library itself:
|
|
301
308
|
https://openreceive.org/contact
|
|
302
309
|
|
|
310
|
+
- https://openreceive.org/guides/payment-safety-upgrade.md — coordinated upgrades and reviewed repair of existing attempts
|
|
311
|
+
|
|
303
312
|
---
|
|
304
313
|
|
|
305
314
|
## The quickstart, in full
|
|
@@ -473,7 +482,7 @@ The host class needs three things: authorization, the trusted price, and
|
|
|
473
482
|
fulfillment. All three receive the `reference` — a string you choose, and the
|
|
474
483
|
fulfillment identity: your order id, one per thing you fulfill, created before
|
|
475
484
|
checkout, kept across retries, never reused. OpenReceive never looks inside
|
|
476
|
-
it, but `on_paid`
|
|
485
|
+
it, but `on_paid` commits fulfillment once per reference, a new checkout under a reference
|
|
477
486
|
that already settled is refused with 409, and a fresh id per page load lets
|
|
478
487
|
one order be paid twice.
|
|
479
488
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# OpenReceive agent directions (FastAPI)
|
|
2
2
|
|
|
3
|
-
These directions describe OpenReceive 0.4.
|
|
3
|
+
These directions describe OpenReceive 0.4.11.
|
|
4
4
|
|
|
5
5
|
Add OpenReceive to a FastAPI application — the app you are already working in.
|
|
6
6
|
You do not need a copy of the OpenReceive source: the engine is on PyPI
|
|
@@ -116,7 +116,7 @@ itself, and they hold for every integration.
|
|
|
116
116
|
- `authorize` runs on every request, and the `resource` it receives is a CLAIM
|
|
117
117
|
the payer made, not proof. Read the Starlette request's session, cookie or
|
|
118
118
|
auth dependency; never trust a body field.
|
|
119
|
-
- `on_paid` must be idempotent.
|
|
119
|
+
- `on_paid` must be idempotent. Its database fulfillment commits once per `reference` — your order id, one
|
|
120
120
|
per thing you fulfill, created before checkout, kept across retries, never
|
|
121
121
|
reused. A fresh id per page load lets one order be paid twice.
|
|
122
122
|
- Receive-only NWC is required; a spend-capable code fails closed at boot unless
|
|
@@ -228,6 +228,13 @@ components.
|
|
|
228
228
|
- `createSwapDisplayModel` → `display.copyRows` for deposits: address, memo,
|
|
229
229
|
and the bare amount each get a copy row. Render `swap.networkWarning*` as
|
|
230
230
|
the model gives it.
|
|
231
|
+
- `swap.deposit_amount` is the only amount a payer is told to send. Never put
|
|
232
|
+
a fiat valuation of it (`swap.fee.pay_in_fiat`) next to a stablecoin amount:
|
|
233
|
+
"$50.03" under "50.05 USDC" reads as a typo, and the payer asks which one to
|
|
234
|
+
send. The one fiat figure on a USDT/USDC deposit panel is the cart total
|
|
235
|
+
(`payout_fiat`); express "you send" and the fee in the token. Use
|
|
236
|
+
`createSwapFeeBreakdown(fee, swap)` — with the swap, not the fee alone — and
|
|
237
|
+
it applies this for you; SOL and ETH keep a fiat breakdown.
|
|
231
238
|
- `createCheckoutSession` owns mint and swap start. To start swaps, pass its
|
|
232
239
|
`swap` option (`selection`, `prefix`, `fetch`) together. Without it
|
|
233
240
|
`startSwap` reports through `onError`.
|
|
@@ -294,6 +301,8 @@ enough; drop the `.md` for the same page a person would read.
|
|
|
294
301
|
Questions, or a problem with the library itself:
|
|
295
302
|
https://openreceive.org/contact
|
|
296
303
|
|
|
304
|
+
- https://openreceive.org/guides/payment-safety-upgrade.md — coordinated upgrades and reviewed repair of existing attempts
|
|
305
|
+
|
|
297
306
|
---
|
|
298
307
|
|
|
299
308
|
## The quickstart, in full
|
|
@@ -468,7 +477,7 @@ the `reference`. OpenReceive never prices from payer input.
|
|
|
468
477
|
The `reference` is a string you choose, and it is the fulfillment identity:
|
|
469
478
|
your order id — one per thing you fulfill, created before checkout, kept
|
|
470
479
|
across retries, never reused. OpenReceive never looks inside it, but `on_paid`
|
|
471
|
-
|
|
480
|
+
commits fulfillment once per reference, a new checkout under a reference that already
|
|
472
481
|
settled is refused with 409, and a fresh id per page load lets one order be
|
|
473
482
|
paid twice.
|
|
474
483
|
|
|
@@ -517,7 +526,7 @@ Content-Security-Policy has a strict `img-src`, allow `data:`
|
|
|
517
526
|
([Provider registry](https://openreceive.org/guides/provider-registry.md#assets)).
|
|
518
527
|
|
|
519
528
|
That is the whole loop: your server owns the price and the order, the payer gets
|
|
520
|
-
an invoice, and `onPaid` runs
|
|
529
|
+
an invoice, and `onPaid` runs inside the settlement transaction. Rolled-back transactions may retry the callback; use a host outbox for external delivery.
|
|
521
530
|
|
|
522
531
|
A page without a bundler renders the same checkout as a custom element:
|
|
523
532
|
`<openreceive-checkout reference="…" prefix="/openreceive">` from
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# OpenReceive agent directions (Fastify)
|
|
2
2
|
|
|
3
|
-
These directions describe OpenReceive 0.4.
|
|
3
|
+
These directions describe OpenReceive 0.4.11.
|
|
4
4
|
|
|
5
5
|
Add OpenReceive to a Fastify application — the app you are already working in.
|
|
6
6
|
You do not need a copy of the OpenReceive source: the packages are on npm, and
|
|
@@ -107,7 +107,7 @@ itself, and they hold for every integration.
|
|
|
107
107
|
payer-supplied amounts.
|
|
108
108
|
- `authorize` runs on every request, and the `resource` it receives is a CLAIM
|
|
109
109
|
the payer made, not proof. Read a framework session; never trust a body field.
|
|
110
|
-
- `onPaid` must be idempotent.
|
|
110
|
+
- `onPaid` must be idempotent. Its database fulfillment commits once per `reference` — your order id, one
|
|
111
111
|
per thing you fulfill, created before checkout, kept across retries, never
|
|
112
112
|
reused. A fresh id per page load lets one order be paid twice.
|
|
113
113
|
- Receive-only NWC is required; a spend-capable code fails closed at boot unless
|
|
@@ -211,6 +211,13 @@ components.
|
|
|
211
211
|
- `createSwapDisplayModel` → `display.copyRows` for deposits: address, memo,
|
|
212
212
|
and the bare amount each get a copy row. Render `swap.networkWarning*` as
|
|
213
213
|
the model gives it.
|
|
214
|
+
- `swap.deposit_amount` is the only amount a payer is told to send. Never put
|
|
215
|
+
a fiat valuation of it (`swap.fee.pay_in_fiat`) next to a stablecoin amount:
|
|
216
|
+
"$50.03" under "50.05 USDC" reads as a typo, and the payer asks which one to
|
|
217
|
+
send. The one fiat figure on a USDT/USDC deposit panel is the cart total
|
|
218
|
+
(`payout_fiat`); express "you send" and the fee in the token. Use
|
|
219
|
+
`createSwapFeeBreakdown(fee, swap)` — with the swap, not the fee alone — and
|
|
220
|
+
it applies this for you; SOL and ETH keep a fiat breakdown.
|
|
214
221
|
- `createCheckoutSession` owns mint and swap start. To start swaps, pass its
|
|
215
222
|
`swap` option (`selection`, `prefix`, `fetch`) together. Without it
|
|
216
223
|
`startSwap` reports through `onError`.
|
|
@@ -277,6 +284,8 @@ enough; drop the `.md` for the same page a person would read.
|
|
|
277
284
|
Questions, or a problem with the library itself:
|
|
278
285
|
https://openreceive.org/contact
|
|
279
286
|
|
|
287
|
+
- https://openreceive.org/guides/payment-safety-upgrade.md — coordinated upgrades and reviewed repair of existing attempts
|
|
288
|
+
|
|
280
289
|
---
|
|
281
290
|
|
|
282
291
|
## The quickstart, in full
|
|
@@ -470,7 +479,7 @@ the `reference`. OpenReceive never prices from payer input.
|
|
|
470
479
|
The `reference` is a string you choose, and it is the fulfillment identity:
|
|
471
480
|
your order id — one per thing you fulfill, created before checkout, kept
|
|
472
481
|
across retries, never reused. OpenReceive never looks inside it, but `onPaid`
|
|
473
|
-
|
|
482
|
+
commits fulfillment once per reference, a new checkout under a reference that already
|
|
474
483
|
settled is refused with 409, and a fresh id per page load lets one order be
|
|
475
484
|
paid twice.
|
|
476
485
|
|
|
@@ -519,7 +528,7 @@ Content-Security-Policy has a strict `img-src`, allow `data:`
|
|
|
519
528
|
([Provider registry](https://openreceive.org/guides/provider-registry.md#assets)).
|
|
520
529
|
|
|
521
530
|
That is the whole loop: your server owns the price and the order, the payer gets
|
|
522
|
-
an invoice, and `onPaid` runs
|
|
531
|
+
an invoice, and `onPaid` runs inside the settlement transaction. Rolled-back transactions may retry the callback; use a host outbox for external delivery.
|
|
523
532
|
|
|
524
533
|
A runnable illustration of this boundary — not a template to copy models from —
|
|
525
534
|
is Buy a Button
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# OpenReceive agent directions (Laravel)
|
|
2
2
|
|
|
3
|
-
These directions describe OpenReceive 0.4.
|
|
3
|
+
These directions describe OpenReceive 0.4.11.
|
|
4
4
|
|
|
5
5
|
Add OpenReceive to a Laravel application — the app you are already working in.
|
|
6
6
|
You do not need a copy of the OpenReceive source: the package is on Packagist
|
|
@@ -121,7 +121,7 @@ itself, and they hold for every integration.
|
|
|
121
121
|
scaffolds `use AllowAllAuthorize;`, a placeholder trait that allows
|
|
122
122
|
everything (the engine warns at boot while it is there) — replace it with
|
|
123
123
|
this app's real ownership check, same as `onPaid`.
|
|
124
|
-
- `onPaid` must be idempotent.
|
|
124
|
+
- `onPaid` must be idempotent. Its database fulfillment commits once per `reference` — your order
|
|
125
125
|
id, one per thing you fulfill, created before checkout, kept across retries,
|
|
126
126
|
never reused. A fresh id per page load lets one order be paid twice.
|
|
127
127
|
- Receive-only NWC is required; a spend-capable code fails closed at boot unless
|
|
@@ -216,6 +216,13 @@ built on `@openreceive/browser/headless`. Read that before writing components.
|
|
|
216
216
|
- `createSwapDisplayModel` → `display.copyRows` for deposits: address, memo,
|
|
217
217
|
and the bare amount each get a copy row. Render `swap.networkWarning*` as
|
|
218
218
|
the model gives it.
|
|
219
|
+
- `swap.deposit_amount` is the only amount a payer is told to send. Never put
|
|
220
|
+
a fiat valuation of it (`swap.fee.pay_in_fiat`) next to a stablecoin amount:
|
|
221
|
+
"$50.03" under "50.05 USDC" reads as a typo, and the payer asks which one to
|
|
222
|
+
send. The one fiat figure on a USDT/USDC deposit panel is the cart total
|
|
223
|
+
(`payout_fiat`); express "you send" and the fee in the token. Use
|
|
224
|
+
`createSwapFeeBreakdown(fee, swap)` — with the swap, not the fee alone — and
|
|
225
|
+
it applies this for you; SOL and ETH keep a fiat breakdown.
|
|
219
226
|
- `createCheckoutSession` owns mint and swap start. To start swaps, pass its
|
|
220
227
|
`swap` option (`selection`, `prefix`, `fetch`) together. Without it
|
|
221
228
|
`startSwap` reports through `onError`.
|
|
@@ -284,6 +291,8 @@ enough; drop the `.md` for the same page a person would read.
|
|
|
284
291
|
Questions, or a problem with the library itself:
|
|
285
292
|
https://openreceive.org/contact
|
|
286
293
|
|
|
294
|
+
- https://openreceive.org/guides/payment-safety-upgrade.md — coordinated upgrades and reviewed repair of existing attempts
|
|
295
|
+
|
|
287
296
|
---
|
|
288
297
|
|
|
289
298
|
## The quickstart, in full
|
|
@@ -449,7 +458,7 @@ variable as set/unset only.
|
|
|
449
458
|
price, and fulfillment. All three receive the `reference` — a string you
|
|
450
459
|
choose, and the fulfillment identity: your order id, one per thing you
|
|
451
460
|
fulfill, created before checkout, kept across retries, never reused.
|
|
452
|
-
OpenReceive never looks inside it, but `onPaid`
|
|
461
|
+
OpenReceive never looks inside it, but `onPaid` commits fulfillment once per reference, a new
|
|
453
462
|
checkout under a reference that already settled is refused with 409, and a
|
|
454
463
|
fresh id per page load lets one order be paid twice.
|
|
455
464
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# OpenReceive agent directions (Next.js)
|
|
2
2
|
|
|
3
|
-
These directions describe OpenReceive 0.4.
|
|
3
|
+
These directions describe OpenReceive 0.4.11.
|
|
4
4
|
|
|
5
5
|
Add OpenReceive to a Next.js App Router application — the app you are already
|
|
6
6
|
working in. You do not need a copy of the OpenReceive source: the packages are
|
|
@@ -109,7 +109,7 @@ itself, and they hold for every integration.
|
|
|
109
109
|
payer-supplied amounts.
|
|
110
110
|
- `authorize` runs on every request, and the `resource` it receives is a CLAIM
|
|
111
111
|
the payer made, not proof. Read a framework session; never trust a body field.
|
|
112
|
-
- `onPaid` must be idempotent.
|
|
112
|
+
- `onPaid` must be idempotent. Its database fulfillment commits once per `reference` — your order id, one
|
|
113
113
|
per thing you fulfill, created before checkout, kept across retries, never
|
|
114
114
|
reused. A fresh id per page load lets one order be paid twice.
|
|
115
115
|
- Receive-only NWC is required; a spend-capable code fails closed at boot unless
|
|
@@ -217,6 +217,13 @@ components.
|
|
|
217
217
|
- `createSwapDisplayModel` → `display.copyRows` for deposits: address, memo,
|
|
218
218
|
and the bare amount each get a copy row. Render `swap.networkWarning*` as
|
|
219
219
|
the model gives it.
|
|
220
|
+
- `swap.deposit_amount` is the only amount a payer is told to send. Never put
|
|
221
|
+
a fiat valuation of it (`swap.fee.pay_in_fiat`) next to a stablecoin amount:
|
|
222
|
+
"$50.03" under "50.05 USDC" reads as a typo, and the payer asks which one to
|
|
223
|
+
send. The one fiat figure on a USDT/USDC deposit panel is the cart total
|
|
224
|
+
(`payout_fiat`); express "you send" and the fee in the token. Use
|
|
225
|
+
`createSwapFeeBreakdown(fee, swap)` — with the swap, not the fee alone — and
|
|
226
|
+
it applies this for you; SOL and ETH keep a fiat breakdown.
|
|
220
227
|
- `createCheckoutSession` owns mint and swap start. To start swaps, pass its
|
|
221
228
|
`swap` option (`selection`, `prefix`, `fetch`) together. Without it
|
|
222
229
|
`startSwap` reports through `onError`.
|
|
@@ -283,6 +290,8 @@ enough; drop the `.md` for the same page a person would read.
|
|
|
283
290
|
Questions, or a problem with the library itself:
|
|
284
291
|
https://openreceive.org/contact
|
|
285
292
|
|
|
293
|
+
- https://openreceive.org/guides/payment-safety-upgrade.md — coordinated upgrades and reviewed repair of existing attempts
|
|
294
|
+
|
|
286
295
|
---
|
|
287
296
|
|
|
288
297
|
## The quickstart, in full
|
|
@@ -489,7 +498,7 @@ the `reference`. OpenReceive never prices from payer input.
|
|
|
489
498
|
The `reference` is a string you choose, and it is the fulfillment identity:
|
|
490
499
|
your order id — one per thing you fulfill, created before checkout, kept
|
|
491
500
|
across retries, never reused. OpenReceive never looks inside it, but `onPaid`
|
|
492
|
-
|
|
501
|
+
commits fulfillment once per reference, a new checkout under a reference that already
|
|
493
502
|
settled is refused with 409, and a fresh id per page load lets one order be
|
|
494
503
|
paid twice.
|
|
495
504
|
|
|
@@ -569,7 +578,7 @@ Content-Security-Policy has a strict `img-src`, allow `data:`
|
|
|
569
578
|
([Provider registry](https://openreceive.org/guides/provider-registry.md#assets)).
|
|
570
579
|
|
|
571
580
|
That is the whole loop: your server owns the price and the order, the payer gets
|
|
572
|
-
an invoice, and `onPaid` runs
|
|
581
|
+
an invoice, and `onPaid` runs inside the settlement transaction. Rolled-back transactions may retry the callback; use a host outbox for external delivery.
|
|
573
582
|
|
|
574
583
|
A runnable illustration of this boundary — not a template to copy models from —
|
|
575
584
|
is Buy a Button
|