@openreceive/browser 0.4.10 → 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-FIAYCDZO.js → chunk-5F7F2ZAM.js} +241 -213
- 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-Cnx1Vv-w.d.ts → status-hEzap3jk.d.ts} +2 -1
- package/package.json +3 -3
- package/skills/integrate-openreceive/references/btcpay.md +6 -4
- package/skills/integrate-openreceive/references/django.md +5 -3
- package/skills/integrate-openreceive/references/fastapi.md +6 -4
- package/skills/integrate-openreceive/references/fastify.md +6 -4
- package/skills/integrate-openreceive/references/laravel.md +5 -3
- package/skills/integrate-openreceive/references/next.md +6 -4
- package/skills/integrate-openreceive/references/node.md +6 -4
- package/skills/integrate-openreceive/references/php.md +5 -3
- package/skills/integrate-openreceive/references/rails.md +5 -3
- package/skills/integrate-openreceive/references/woocommerce.md +3 -1
|
@@ -952,6 +952,7 @@ function createSwapDisplayModel(invoice, options = {}) {
|
|
|
952
952
|
const depositRisk = swapDepositRisk(swap.pay_in_asset);
|
|
953
953
|
const doubleSpendWarning = `Pay with one method only \u2014 if you already sent ${asset.assetLabel}, do not also pay the Lightning invoice.`;
|
|
954
954
|
const settled = invoice.transaction_state === "settled";
|
|
955
|
+
const instructionsExpired = expiresInSeconds === 0 && swap.provider_state === "awaiting_deposit";
|
|
955
956
|
const feeBreakdown = createSwapFeeBreakdown(swap.fee, swap);
|
|
956
957
|
return {
|
|
957
958
|
provider: swap.provider,
|
|
@@ -987,14 +988,14 @@ function createSwapDisplayModel(invoice, options = {}) {
|
|
|
987
988
|
],
|
|
988
989
|
{ label: checkoutLabels.swapCopyAmount, value: depositAmount, selectable: true }
|
|
989
990
|
],
|
|
990
|
-
providerStateLabel: settled ? "Payment complete" : getSwapProviderStateLabel(swap.provider_state),
|
|
991
|
-
providerStateDetail: settled ? "Your payment is confirmed and your order is complete." : getSwapProviderStateDetail(swap.provider_state, swap.pay_in_asset, {
|
|
991
|
+
providerStateLabel: instructionsExpired ? "Payment window closed" : settled ? "Payment complete" : getSwapProviderStateLabel(swap.provider_state),
|
|
992
|
+
providerStateDetail: instructionsExpired ? "Do not send another payment. We are checking for an existing deposit and any recovery options." : settled ? "Your payment is confirmed and your order is complete." : getSwapProviderStateDetail(swap.provider_state, swap.pay_in_asset, {
|
|
992
993
|
refundReason: swap.refund_reason,
|
|
993
994
|
depositAmount: swap.deposit_amount,
|
|
994
995
|
depositReceivedAmount: swap.deposit_received_amount,
|
|
995
996
|
refundAmount: swap.refund_amount
|
|
996
997
|
}),
|
|
997
|
-
state: settled ? "settled" : getSwapPanelState(swap.provider_state),
|
|
998
|
+
state: settled ? "settled" : instructionsExpired ? "progress" : getSwapPanelState(swap.provider_state),
|
|
998
999
|
expiresInSeconds,
|
|
999
1000
|
countdownLabel: formatCountdown(expiresInSeconds),
|
|
1000
1001
|
qrPayload: createSwapQrPayload(swap),
|
|
@@ -1087,7 +1088,7 @@ function getSwapProviderStateDetail(state, payInAsset, refundContext = {}) {
|
|
|
1087
1088
|
return "Your payment is confirmed and being converted. This usually finishes within a minute.";
|
|
1088
1089
|
}
|
|
1089
1090
|
if (state === "paying_invoice" || state === "completed") {
|
|
1090
|
-
return "
|
|
1091
|
+
return "We are checking whether the wallet received the payment. Provider completion alone does not confirm payment.";
|
|
1091
1092
|
}
|
|
1092
1093
|
if (state === "expired") return "No payment was received before the payment window closed.";
|
|
1093
1094
|
if (state === "refund_required" || state === "refund_pending" || state === "refunded") {
|
|
@@ -1361,6 +1362,127 @@ function isCheckoutStateSource(value) {
|
|
|
1361
1362
|
return "checkout_id" in value && "reference" in value && "invoice_id" in value && "invoice" in value && "transaction_state" in value && "phase" in value;
|
|
1362
1363
|
}
|
|
1363
1364
|
|
|
1365
|
+
// src/internal/console-logger.ts
|
|
1366
|
+
import { isSensitiveLogKey, sanitizeLogValue } from "@openreceive/core";
|
|
1367
|
+
|
|
1368
|
+
// src/internal/log-level.ts
|
|
1369
|
+
var BROWSER_LOG_LEVEL_ORDER = {
|
|
1370
|
+
debug: 10,
|
|
1371
|
+
info: 20,
|
|
1372
|
+
warn: 30,
|
|
1373
|
+
error: 40
|
|
1374
|
+
};
|
|
1375
|
+
var BROWSER_LOG_LEVEL_ALIASES = {
|
|
1376
|
+
debug: "debug",
|
|
1377
|
+
info: "info",
|
|
1378
|
+
warn: "warn",
|
|
1379
|
+
warning: "warn",
|
|
1380
|
+
error: "error"
|
|
1381
|
+
};
|
|
1382
|
+
function browserLogLevelOrder(level) {
|
|
1383
|
+
return BROWSER_LOG_LEVEL_ORDER[level];
|
|
1384
|
+
}
|
|
1385
|
+
function parseBrowserLogLevel(value) {
|
|
1386
|
+
if (value === void 0 || value === null) return void 0;
|
|
1387
|
+
const normalized = value.trim().toLowerCase();
|
|
1388
|
+
if (normalized.length === 0) return void 0;
|
|
1389
|
+
return BROWSER_LOG_LEVEL_ALIASES[normalized];
|
|
1390
|
+
}
|
|
1391
|
+
function resolveBrowserLogLevel(value, fallback = "info") {
|
|
1392
|
+
return parseBrowserLogLevel(value) ?? fallback;
|
|
1393
|
+
}
|
|
1394
|
+
function readBrowserLogLevelFromEnvironment(source) {
|
|
1395
|
+
if (source !== void 0) {
|
|
1396
|
+
return resolveBrowserLogLevel(
|
|
1397
|
+
source.LOG_LEVEL ?? source.VITE_LOG_LEVEL ?? source.NEXT_PUBLIC_LOG_LEVEL
|
|
1398
|
+
);
|
|
1399
|
+
}
|
|
1400
|
+
const fromGlobal = parseBrowserLogLevel(readGlobalLogLevel());
|
|
1401
|
+
if (fromGlobal !== void 0) return fromGlobal;
|
|
1402
|
+
const metaEnv = readImportMetaEnv();
|
|
1403
|
+
const parsedMeta = parseBrowserLogLevel(
|
|
1404
|
+
metaEnv?.LOG_LEVEL ?? metaEnv?.VITE_LOG_LEVEL ?? metaEnv?.NEXT_PUBLIC_LOG_LEVEL
|
|
1405
|
+
);
|
|
1406
|
+
if (parsedMeta !== void 0) return parsedMeta;
|
|
1407
|
+
const processEnv = typeof process !== "undefined" ? process.env : void 0;
|
|
1408
|
+
return resolveBrowserLogLevel(processEnv?.LOG_LEVEL);
|
|
1409
|
+
}
|
|
1410
|
+
function readGlobalLogLevel() {
|
|
1411
|
+
try {
|
|
1412
|
+
const value = globalThis.__OPENRECEIVE_LOG_LEVEL__;
|
|
1413
|
+
return typeof value === "string" ? value : void 0;
|
|
1414
|
+
} catch {
|
|
1415
|
+
return void 0;
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
function readImportMetaEnv() {
|
|
1419
|
+
try {
|
|
1420
|
+
return import.meta.env;
|
|
1421
|
+
} catch {
|
|
1422
|
+
return void 0;
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
// src/internal/console-logger.ts
|
|
1427
|
+
function createConsoleWriter(options) {
|
|
1428
|
+
const target = options.console ?? console;
|
|
1429
|
+
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
1430
|
+
return (level, prefix, event, message, fields) => {
|
|
1431
|
+
const minLevel = options.minLevel === void 0 ? readBrowserLogLevelFromEnvironment() : resolveBrowserLogLevel(options.minLevel);
|
|
1432
|
+
if (browserLogLevelOrder(level) < browserLogLevelOrder(minLevel)) {
|
|
1433
|
+
return;
|
|
1434
|
+
}
|
|
1435
|
+
const method = level === "error" ? "error" : level === "warn" ? "warn" : level === "debug" ? "debug" : "info";
|
|
1436
|
+
const sink = target[method] ?? target.log;
|
|
1437
|
+
const {
|
|
1438
|
+
level: _level,
|
|
1439
|
+
event: _event,
|
|
1440
|
+
message: cleanMessage,
|
|
1441
|
+
...cleanFields
|
|
1442
|
+
} = sanitizeBrowserLogEntry({ level, event, message, ...fields });
|
|
1443
|
+
sink.call(
|
|
1444
|
+
target,
|
|
1445
|
+
`[${now().toISOString()}] ${level.toUpperCase()} [${prefix}] ${event}: ${cleanMessage}`,
|
|
1446
|
+
cleanFields
|
|
1447
|
+
);
|
|
1448
|
+
};
|
|
1449
|
+
}
|
|
1450
|
+
function sanitizeBrowserLogEntry(entry) {
|
|
1451
|
+
const clean = {};
|
|
1452
|
+
for (const [key, value] of Object.entries(entry)) {
|
|
1453
|
+
if (isSensitiveLogKey(key)) {
|
|
1454
|
+
clean[key] = "[REDACTED]";
|
|
1455
|
+
} else {
|
|
1456
|
+
clean[key] = sanitizeLogValue(value);
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
return clean;
|
|
1460
|
+
}
|
|
1461
|
+
function createBrowserConsoleLogger(options = {}) {
|
|
1462
|
+
const prefix = options.prefix ?? "openreceive";
|
|
1463
|
+
const write = createConsoleWriter(options);
|
|
1464
|
+
return (entry) => {
|
|
1465
|
+
const { level, event, message, ...fields } = entry;
|
|
1466
|
+
write(level, prefix, event, message, fields);
|
|
1467
|
+
};
|
|
1468
|
+
}
|
|
1469
|
+
function createAppBrowserConsoleLogger(options) {
|
|
1470
|
+
const write = createConsoleWriter(options);
|
|
1471
|
+
return (event, message, fields = {}, level = "info") => {
|
|
1472
|
+
write(level, options.prefix, event, message, fields);
|
|
1473
|
+
};
|
|
1474
|
+
}
|
|
1475
|
+
var defaultBrowserConsoleLogger;
|
|
1476
|
+
function getDefaultBrowserConsoleLogger() {
|
|
1477
|
+
defaultBrowserConsoleLogger ??= createBrowserConsoleLogger();
|
|
1478
|
+
return defaultBrowserConsoleLogger;
|
|
1479
|
+
}
|
|
1480
|
+
function resolveBrowserLogger(logger) {
|
|
1481
|
+
if (logger === false) return void 0;
|
|
1482
|
+
if (logger !== void 0) return logger;
|
|
1483
|
+
return getDefaultBrowserConsoleLogger();
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1364
1486
|
// src/internal/wizard.ts
|
|
1365
1487
|
import { getSwapRefundAddressError } from "@openreceive/core/swap-address";
|
|
1366
1488
|
import {
|
|
@@ -1956,176 +2078,6 @@ function createPaymentWizardController(options = {}) {
|
|
|
1956
2078
|
return new BrowserPaymentWizardController(options);
|
|
1957
2079
|
}
|
|
1958
2080
|
|
|
1959
|
-
// src/internal/log-level.ts
|
|
1960
|
-
var BROWSER_LOG_LEVEL_ORDER = {
|
|
1961
|
-
debug: 10,
|
|
1962
|
-
info: 20,
|
|
1963
|
-
warn: 30,
|
|
1964
|
-
error: 40
|
|
1965
|
-
};
|
|
1966
|
-
var BROWSER_LOG_LEVEL_ALIASES = {
|
|
1967
|
-
debug: "debug",
|
|
1968
|
-
info: "info",
|
|
1969
|
-
warn: "warn",
|
|
1970
|
-
warning: "warn",
|
|
1971
|
-
error: "error"
|
|
1972
|
-
};
|
|
1973
|
-
function browserLogLevelOrder(level) {
|
|
1974
|
-
return BROWSER_LOG_LEVEL_ORDER[level];
|
|
1975
|
-
}
|
|
1976
|
-
function parseBrowserLogLevel(value) {
|
|
1977
|
-
if (value === void 0 || value === null) return void 0;
|
|
1978
|
-
const normalized = value.trim().toLowerCase();
|
|
1979
|
-
if (normalized.length === 0) return void 0;
|
|
1980
|
-
return BROWSER_LOG_LEVEL_ALIASES[normalized];
|
|
1981
|
-
}
|
|
1982
|
-
function resolveBrowserLogLevel(value, fallback = "info") {
|
|
1983
|
-
return parseBrowserLogLevel(value) ?? fallback;
|
|
1984
|
-
}
|
|
1985
|
-
function readBrowserLogLevelFromEnvironment(source) {
|
|
1986
|
-
if (source !== void 0) {
|
|
1987
|
-
return resolveBrowserLogLevel(
|
|
1988
|
-
source.LOG_LEVEL ?? source.VITE_LOG_LEVEL ?? source.NEXT_PUBLIC_LOG_LEVEL
|
|
1989
|
-
);
|
|
1990
|
-
}
|
|
1991
|
-
const fromGlobal = parseBrowserLogLevel(readGlobalLogLevel());
|
|
1992
|
-
if (fromGlobal !== void 0) return fromGlobal;
|
|
1993
|
-
const metaEnv = readImportMetaEnv();
|
|
1994
|
-
const parsedMeta = parseBrowserLogLevel(
|
|
1995
|
-
metaEnv?.LOG_LEVEL ?? metaEnv?.VITE_LOG_LEVEL ?? metaEnv?.NEXT_PUBLIC_LOG_LEVEL
|
|
1996
|
-
);
|
|
1997
|
-
if (parsedMeta !== void 0) return parsedMeta;
|
|
1998
|
-
const processEnv = typeof process !== "undefined" ? process.env : void 0;
|
|
1999
|
-
return resolveBrowserLogLevel(processEnv?.LOG_LEVEL);
|
|
2000
|
-
}
|
|
2001
|
-
function readGlobalLogLevel() {
|
|
2002
|
-
try {
|
|
2003
|
-
const value = globalThis.__OPENRECEIVE_LOG_LEVEL__;
|
|
2004
|
-
return typeof value === "string" ? value : void 0;
|
|
2005
|
-
} catch {
|
|
2006
|
-
return void 0;
|
|
2007
|
-
}
|
|
2008
|
-
}
|
|
2009
|
-
function readImportMetaEnv() {
|
|
2010
|
-
try {
|
|
2011
|
-
return import.meta.env;
|
|
2012
|
-
} catch {
|
|
2013
|
-
return void 0;
|
|
2014
|
-
}
|
|
2015
|
-
}
|
|
2016
|
-
|
|
2017
|
-
// src/internal/console-logger.ts
|
|
2018
|
-
function createConsoleWriter(options) {
|
|
2019
|
-
const target = options.console ?? console;
|
|
2020
|
-
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
2021
|
-
return (level, prefix, event, message, fields) => {
|
|
2022
|
-
const minLevel = options.minLevel === void 0 ? readBrowserLogLevelFromEnvironment() : resolveBrowserLogLevel(options.minLevel);
|
|
2023
|
-
if (browserLogLevelOrder(level) < browserLogLevelOrder(minLevel)) {
|
|
2024
|
-
return;
|
|
2025
|
-
}
|
|
2026
|
-
const method = level === "error" ? "error" : level === "warn" ? "warn" : level === "debug" ? "debug" : "info";
|
|
2027
|
-
const sink = target[method] ?? target.log;
|
|
2028
|
-
const {
|
|
2029
|
-
level: _level,
|
|
2030
|
-
event: _event,
|
|
2031
|
-
message: cleanMessage,
|
|
2032
|
-
...cleanFields
|
|
2033
|
-
} = sanitizeBrowserLogEntry({ level, event, message, ...fields });
|
|
2034
|
-
sink.call(
|
|
2035
|
-
target,
|
|
2036
|
-
`[${now().toISOString()}] ${level.toUpperCase()} [${prefix}] ${event}: ${cleanMessage}`,
|
|
2037
|
-
cleanFields
|
|
2038
|
-
);
|
|
2039
|
-
};
|
|
2040
|
-
}
|
|
2041
|
-
function sanitizeBrowserLogEntry(entry) {
|
|
2042
|
-
const clean = {};
|
|
2043
|
-
for (const [key, value] of Object.entries(entry)) {
|
|
2044
|
-
if (/secret|token|authorization|cookie|nwc/i.test(key)) {
|
|
2045
|
-
clean[key] = "[REDACTED]";
|
|
2046
|
-
} else {
|
|
2047
|
-
clean[key] = sanitizeBrowserLogValue(value);
|
|
2048
|
-
}
|
|
2049
|
-
}
|
|
2050
|
-
return clean;
|
|
2051
|
-
}
|
|
2052
|
-
function sanitizeBrowserLogValue(value) {
|
|
2053
|
-
if (typeof value === "string") return redactBrowserSecrets(value);
|
|
2054
|
-
if (Array.isArray(value)) return value.map(sanitizeBrowserLogValue);
|
|
2055
|
-
if (typeof value !== "object" || value === null) return value;
|
|
2056
|
-
const clean = {};
|
|
2057
|
-
for (const [key, nested] of Object.entries(value)) {
|
|
2058
|
-
if (/secret|token|authorization|cookie|nwc/i.test(key)) {
|
|
2059
|
-
clean[key] = "[REDACTED]";
|
|
2060
|
-
} else {
|
|
2061
|
-
clean[key] = sanitizeBrowserLogValue(nested);
|
|
2062
|
-
}
|
|
2063
|
-
}
|
|
2064
|
-
return clean;
|
|
2065
|
-
}
|
|
2066
|
-
function redactBrowserSecrets(value) {
|
|
2067
|
-
return value.replace(/nostr\+walletconnect:\/\/[^\s"'`<>]+/g, "[REDACTED_NWC]").replace(/([?&](?:_or_evt|token|secret)=)[^&\s"'`<>]+/gi, "$1[REDACTED]");
|
|
2068
|
-
}
|
|
2069
|
-
function createBrowserConsoleLogger(options = {}) {
|
|
2070
|
-
const prefix = options.prefix ?? "openreceive";
|
|
2071
|
-
const write = createConsoleWriter(options);
|
|
2072
|
-
return (entry) => {
|
|
2073
|
-
const { level, event, message, ...fields } = entry;
|
|
2074
|
-
write(level, prefix, event, message, fields);
|
|
2075
|
-
};
|
|
2076
|
-
}
|
|
2077
|
-
function createAppBrowserConsoleLogger(options) {
|
|
2078
|
-
const write = createConsoleWriter(options);
|
|
2079
|
-
return (event, message, fields = {}, level = "info") => {
|
|
2080
|
-
write(level, options.prefix, event, message, fields);
|
|
2081
|
-
};
|
|
2082
|
-
}
|
|
2083
|
-
var defaultBrowserConsoleLogger;
|
|
2084
|
-
function getDefaultBrowserConsoleLogger() {
|
|
2085
|
-
defaultBrowserConsoleLogger ??= createBrowserConsoleLogger();
|
|
2086
|
-
return defaultBrowserConsoleLogger;
|
|
2087
|
-
}
|
|
2088
|
-
function resolveBrowserLogger(logger) {
|
|
2089
|
-
if (logger === false) return void 0;
|
|
2090
|
-
if (logger !== void 0) return logger;
|
|
2091
|
-
return getDefaultBrowserConsoleLogger();
|
|
2092
|
-
}
|
|
2093
|
-
|
|
2094
|
-
// src/internal/checkout-read.ts
|
|
2095
|
-
import { nonEmptyString } from "@openreceive/core";
|
|
2096
|
-
function optionalRecord(value) {
|
|
2097
|
-
if (value === void 0) return void 0;
|
|
2098
|
-
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
2099
|
-
throw new Error("OpenReceive metadata must be an object.");
|
|
2100
|
-
}
|
|
2101
|
-
return value;
|
|
2102
|
-
}
|
|
2103
|
-
function requiredInvoiceRail(value) {
|
|
2104
|
-
if (value === "lightning" || value === "swap" || value === "checkout_lock") return value;
|
|
2105
|
-
throw new TypeError("OpenReceive invoice rail must be lightning, swap, or checkout_lock.");
|
|
2106
|
-
}
|
|
2107
|
-
function requiredString(value, fieldName) {
|
|
2108
|
-
const text = nonEmptyString(value);
|
|
2109
|
-
if (text === void 0) {
|
|
2110
|
-
throw new TypeError(`OpenReceive checkout response requires ${fieldName}.`);
|
|
2111
|
-
}
|
|
2112
|
-
return text;
|
|
2113
|
-
}
|
|
2114
|
-
function optionalSafeInteger(value, fieldName = "integer") {
|
|
2115
|
-
if (value === void 0 || value === null) return void 0;
|
|
2116
|
-
if (typeof value !== "number" || !Number.isSafeInteger(value)) {
|
|
2117
|
-
throw new TypeError(`OpenReceive checkout response ${fieldName} must be a safe integer.`);
|
|
2118
|
-
}
|
|
2119
|
-
return value;
|
|
2120
|
-
}
|
|
2121
|
-
function requiredSafeInteger(value, fieldName) {
|
|
2122
|
-
const integer = optionalSafeInteger(value, fieldName);
|
|
2123
|
-
if (integer === void 0) {
|
|
2124
|
-
throw new TypeError(`OpenReceive checkout response requires ${fieldName}.`);
|
|
2125
|
-
}
|
|
2126
|
-
return integer;
|
|
2127
|
-
}
|
|
2128
|
-
|
|
2129
2081
|
// src/internal/checkout-log.ts
|
|
2130
2082
|
import { compact } from "@openreceive/core";
|
|
2131
2083
|
function checkoutLogFields(state) {
|
|
@@ -2206,6 +2158,41 @@ function emitBrowserLog(logger, level, event, message, fields = {}) {
|
|
|
2206
2158
|
}
|
|
2207
2159
|
}
|
|
2208
2160
|
|
|
2161
|
+
// src/internal/checkout-read.ts
|
|
2162
|
+
import { nonEmptyString } from "@openreceive/core";
|
|
2163
|
+
function optionalRecord(value) {
|
|
2164
|
+
if (value === void 0) return void 0;
|
|
2165
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
2166
|
+
throw new Error("OpenReceive metadata must be an object.");
|
|
2167
|
+
}
|
|
2168
|
+
return value;
|
|
2169
|
+
}
|
|
2170
|
+
function requiredInvoiceRail(value) {
|
|
2171
|
+
if (value === "lightning" || value === "swap" || value === "checkout_lock") return value;
|
|
2172
|
+
throw new TypeError("OpenReceive invoice rail must be lightning, swap, or checkout_lock.");
|
|
2173
|
+
}
|
|
2174
|
+
function requiredString(value, fieldName) {
|
|
2175
|
+
const text = nonEmptyString(value);
|
|
2176
|
+
if (text === void 0) {
|
|
2177
|
+
throw new TypeError(`OpenReceive checkout response requires ${fieldName}.`);
|
|
2178
|
+
}
|
|
2179
|
+
return text;
|
|
2180
|
+
}
|
|
2181
|
+
function optionalSafeInteger(value, fieldName = "integer") {
|
|
2182
|
+
if (value === void 0 || value === null) return void 0;
|
|
2183
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value)) {
|
|
2184
|
+
throw new TypeError(`OpenReceive checkout response ${fieldName} must be a safe integer.`);
|
|
2185
|
+
}
|
|
2186
|
+
return value;
|
|
2187
|
+
}
|
|
2188
|
+
function requiredSafeInteger(value, fieldName) {
|
|
2189
|
+
const integer = optionalSafeInteger(value, fieldName);
|
|
2190
|
+
if (integer === void 0) {
|
|
2191
|
+
throw new TypeError(`OpenReceive checkout response requires ${fieldName}.`);
|
|
2192
|
+
}
|
|
2193
|
+
return integer;
|
|
2194
|
+
}
|
|
2195
|
+
|
|
2209
2196
|
// src/internal/checkout-state.ts
|
|
2210
2197
|
function selectCheckoutDisplayInvoice(snapshot) {
|
|
2211
2198
|
if (snapshot.active !== void 0 && snapshot.active.rail !== "checkout_lock") {
|
|
@@ -2380,15 +2367,14 @@ function normalizeCheckoutState(state, now) {
|
|
|
2380
2367
|
const expiresInSeconds = base.expires_at === void 0 || now === void 0 ? void 0 : Math.max(0, base.expires_at - now);
|
|
2381
2368
|
const phase = statePhase === "invoice_created" || statePhase === "verifying" ? expiresInSeconds === 0 ? "expired" : statePhase : statePhase;
|
|
2382
2369
|
const settled = base.paid || base.transaction_state === "settled";
|
|
2370
|
+
const monitoring = checkoutMonitoring(base);
|
|
2383
2371
|
return {
|
|
2384
2372
|
...base,
|
|
2385
2373
|
...deriveCheckoutStateLabels(base),
|
|
2386
2374
|
phase,
|
|
2387
2375
|
settled,
|
|
2388
|
-
// A
|
|
2389
|
-
|
|
2390
|
-
// both /payments/check and the provider instead of asking forever.
|
|
2391
|
-
terminal: isTerminalPhase(phase) || !settled && isTerminalSwapProviderState(base.swap?.provider_state),
|
|
2376
|
+
// A local instruction deadline says nothing about wallet or refund finality.
|
|
2377
|
+
terminal: !monitoring.payment && !monitoring.provider,
|
|
2392
2378
|
...expiresInSeconds === void 0 ? {} : { expires_in_seconds: expiresInSeconds }
|
|
2393
2379
|
};
|
|
2394
2380
|
}
|
|
@@ -2409,8 +2395,13 @@ function getCheckoutPhase(transactionState, workflowState) {
|
|
|
2409
2395
|
}
|
|
2410
2396
|
return "invoice_created";
|
|
2411
2397
|
}
|
|
2412
|
-
function
|
|
2413
|
-
|
|
2398
|
+
function checkoutMonitoring(state) {
|
|
2399
|
+
if (state.workflow_state === "cancelled") return { payment: false, provider: false };
|
|
2400
|
+
const payment = !state.paid && !["settled", "expired", "failed", "attention"].includes(state.transaction_state ?? "pending") && !["expired", "failed", "attention"].includes(state.workflow_state ?? "invoice_created");
|
|
2401
|
+
const providerState = state.swap?.provider_state;
|
|
2402
|
+
const recovery = providerState === "refund_required" || providerState === "refund_pending";
|
|
2403
|
+
const provider = providerState !== void 0 && !isTerminalSwapProviderState(providerState) && providerState !== "completed" && (recovery || !state.paid && state.transaction_state !== "settled");
|
|
2404
|
+
return { payment, provider };
|
|
2414
2405
|
}
|
|
2415
2406
|
function snapshotFromCheckoutState(state) {
|
|
2416
2407
|
const invoice = {
|
|
@@ -2570,6 +2561,7 @@ function normalizeRequestCheckoutOptions(options) {
|
|
|
2570
2561
|
const reference = nonEmptyString2(options.reference);
|
|
2571
2562
|
const metadata = optionalRecord(options.metadata);
|
|
2572
2563
|
return {
|
|
2564
|
+
signal: options.signal,
|
|
2573
2565
|
routes: checkoutRoutes(options.prefix),
|
|
2574
2566
|
reference: reference ?? "",
|
|
2575
2567
|
fetch: options.fetch,
|
|
@@ -2599,6 +2591,7 @@ async function requestCheckout(options) {
|
|
|
2599
2591
|
const headers = request.headers === void 0 ? {} : request.headers;
|
|
2600
2592
|
const response = await fetcher(request.routes.checkouts, {
|
|
2601
2593
|
method: "POST",
|
|
2594
|
+
signal: request.signal,
|
|
2602
2595
|
headers: requestHeaders(headers, request.csrfHeader),
|
|
2603
2596
|
body: JSON.stringify(requestBody)
|
|
2604
2597
|
});
|
|
@@ -2622,6 +2615,7 @@ async function prepareCheckout(options) {
|
|
|
2622
2615
|
const headers = request.headers === void 0 ? {} : request.headers;
|
|
2623
2616
|
const response = await fetcher(request.routes.checkoutsPrepare, {
|
|
2624
2617
|
method: "POST",
|
|
2618
|
+
signal: request.signal,
|
|
2625
2619
|
headers: requestHeaders(headers, request.csrfHeader),
|
|
2626
2620
|
body: JSON.stringify({ reference: request.reference })
|
|
2627
2621
|
});
|
|
@@ -2645,50 +2639,57 @@ function createStatusFetcher(options) {
|
|
|
2645
2639
|
if (activePaymentHash === void 0 || !/^[0-9a-f]{64}$/i.test(activePaymentHash)) {
|
|
2646
2640
|
return snapshot;
|
|
2647
2641
|
}
|
|
2648
|
-
const response = await fetcher(routes.paymentsCheck, {
|
|
2649
|
-
method: "POST",
|
|
2650
|
-
headers: requestHeaders(headers, options.csrfHeader),
|
|
2651
|
-
body: JSON.stringify({
|
|
2652
|
-
reference,
|
|
2653
|
-
payment_hash: activePaymentHash
|
|
2654
|
-
})
|
|
2655
|
-
});
|
|
2656
|
-
const body = await readJsonResponse(response, "Could not refresh invoice status.");
|
|
2657
|
-
const payment = recordOrEmpty(body);
|
|
2658
2642
|
const next = structuredClone(snapshot);
|
|
2659
2643
|
if (next.active === void 0) return next;
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
let
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2644
|
+
let active = next.active;
|
|
2645
|
+
let payment = {};
|
|
2646
|
+
let paymentError;
|
|
2647
|
+
if (checkoutMonitoring(active).payment) {
|
|
2648
|
+
try {
|
|
2649
|
+
const response = await fetcher(routes.paymentsCheck, {
|
|
2650
|
+
method: "POST",
|
|
2651
|
+
headers: requestHeaders(headers, options.csrfHeader),
|
|
2652
|
+
body: JSON.stringify({ reference, payment_hash: activePaymentHash })
|
|
2653
|
+
});
|
|
2654
|
+
payment = recordOrEmpty(
|
|
2655
|
+
await readJsonResponse(response, "Could not refresh invoice status.")
|
|
2656
|
+
);
|
|
2657
|
+
const state2 = nonEmptyString2(payment.status) ?? "pending";
|
|
2658
|
+
const paidAt = optionalSafeInteger(payment.paid_at, "paid_at");
|
|
2659
|
+
active = {
|
|
2660
|
+
...active,
|
|
2661
|
+
transaction_state: state2 === "not_found" ? "pending" : state2,
|
|
2662
|
+
...paidAt === void 0 ? {} : { settled_at: paidAt }
|
|
2663
|
+
};
|
|
2664
|
+
} catch (error) {
|
|
2665
|
+
paymentError = error;
|
|
2666
|
+
}
|
|
2667
|
+
}
|
|
2668
|
+
if (active.rail === "swap" && checkoutMonitoring(active).provider) {
|
|
2669
2669
|
try {
|
|
2670
2670
|
const swapResponse = await fetcher(routes.swapsStatus, {
|
|
2671
2671
|
method: "POST",
|
|
2672
2672
|
headers: requestHeaders(headers, options.csrfHeader),
|
|
2673
2673
|
body: JSON.stringify({ reference, payment_hash: activePaymentHash })
|
|
2674
2674
|
});
|
|
2675
|
-
|
|
2676
|
-
|
|
2675
|
+
active = mergeSwapStatusIntoInvoice(
|
|
2676
|
+
active,
|
|
2677
|
+
recordOrEmpty(await readJsonResponse(swapResponse, "Could not refresh swap status."))
|
|
2677
2678
|
);
|
|
2678
|
-
active = mergeSwapStatusIntoInvoice(active, swapBody);
|
|
2679
2679
|
swapStatusFailures = 0;
|
|
2680
2680
|
} catch (error) {
|
|
2681
2681
|
swapStatusFailures += 1;
|
|
2682
2682
|
const definitive = error instanceof BrowserRequestError && error.retryable === false;
|
|
2683
|
-
|
|
2684
|
-
if (swap !== void 0 && (definitive || swapStatusFailures >= SWAP_STATUS_FAILURE_LIMIT)) {
|
|
2683
|
+
if (active.swap !== void 0 && (definitive || swapStatusFailures >= SWAP_STATUS_FAILURE_LIMIT)) {
|
|
2685
2684
|
active = {
|
|
2686
2685
|
...active,
|
|
2687
|
-
swap: { ...swap, attention: true, attention_reason: "swap_status_unavailable" }
|
|
2686
|
+
swap: { ...active.swap, attention: true, attention_reason: "swap_status_unavailable" }
|
|
2688
2687
|
};
|
|
2689
2688
|
}
|
|
2689
|
+
if (paymentError === void 0 && !checkoutMonitoring(active).payment) paymentError = error;
|
|
2690
2690
|
}
|
|
2691
2691
|
}
|
|
2692
|
+
const state = active.transaction_state;
|
|
2692
2693
|
const paymentMethods2 = normalizePaymentMethods(payment.payment_methods);
|
|
2693
2694
|
const others = next.invoices.filter(
|
|
2694
2695
|
(entry) => entry.invoice_id !== active.invoice_id && entry.rail !== "checkout_lock"
|
|
@@ -2700,6 +2701,7 @@ function createStatusFetcher(options) {
|
|
|
2700
2701
|
status: state === "settled" ? "paid" : state === "expired" || state === "failed" ? "expired" : "open",
|
|
2701
2702
|
...paymentMethods2 === void 0 ? {} : { payment_methods: paymentMethods2 }
|
|
2702
2703
|
};
|
|
2704
|
+
if (paymentError !== void 0 && active.swap === void 0) throw paymentError;
|
|
2703
2705
|
return snapshot;
|
|
2704
2706
|
};
|
|
2705
2707
|
}
|
|
@@ -3095,6 +3097,7 @@ async function requestJson(options, url, body) {
|
|
|
3095
3097
|
const fetcher = options.fetch;
|
|
3096
3098
|
const response = await fetcher(url, {
|
|
3097
3099
|
method: "POST",
|
|
3100
|
+
signal: options.signal,
|
|
3098
3101
|
headers: requestHeaders(options.headers, options.csrfHeader),
|
|
3099
3102
|
body: JSON.stringify(body)
|
|
3100
3103
|
});
|
|
@@ -3176,6 +3179,8 @@ var CheckoutWatcher = class {
|
|
|
3176
3179
|
countdownTimer;
|
|
3177
3180
|
pollTimer;
|
|
3178
3181
|
running = false;
|
|
3182
|
+
generation = 0;
|
|
3183
|
+
pendingRefresh;
|
|
3179
3184
|
pollInFlight = false;
|
|
3180
3185
|
pollFailureCount = 0;
|
|
3181
3186
|
pollBackoffUntil;
|
|
@@ -3242,6 +3247,9 @@ var CheckoutWatcher = class {
|
|
|
3242
3247
|
}
|
|
3243
3248
|
stop() {
|
|
3244
3249
|
this.running = false;
|
|
3250
|
+
this.generation += 1;
|
|
3251
|
+
this.pollInFlight = false;
|
|
3252
|
+
this.pendingRefresh = void 0;
|
|
3245
3253
|
this.stopCountdown();
|
|
3246
3254
|
this.stopPolling();
|
|
3247
3255
|
}
|
|
@@ -3280,8 +3288,10 @@ var CheckoutWatcher = class {
|
|
|
3280
3288
|
if (refreshStatus === void 0 || current.reference.length === 0) {
|
|
3281
3289
|
return current;
|
|
3282
3290
|
}
|
|
3291
|
+
const generation = this.generation;
|
|
3283
3292
|
try {
|
|
3284
|
-
const fetched = await
|
|
3293
|
+
const fetched = await this.fetchSnapshot(current.reference);
|
|
3294
|
+
if (generation !== this.generation) return this.state ?? current;
|
|
3285
3295
|
if (fetched === null) return current;
|
|
3286
3296
|
const next = this.publishSnapshot(fetched);
|
|
3287
3297
|
const nextState = createCheckoutState(next, {
|
|
@@ -3297,10 +3307,20 @@ var CheckoutWatcher = class {
|
|
|
3297
3307
|
}
|
|
3298
3308
|
return nextState;
|
|
3299
3309
|
} catch (error) {
|
|
3310
|
+
if (generation !== this.generation) return this.state ?? current;
|
|
3300
3311
|
this.options.onError?.(error);
|
|
3301
3312
|
throw error;
|
|
3302
3313
|
}
|
|
3303
3314
|
}
|
|
3315
|
+
fetchSnapshot(reference) {
|
|
3316
|
+
if (this.pendingRefresh !== void 0) return this.pendingRefresh;
|
|
3317
|
+
const pending = Promise.resolve(this.options.refreshStatus?.(reference) ?? null);
|
|
3318
|
+
this.pendingRefresh = pending;
|
|
3319
|
+
void pending.finally(() => {
|
|
3320
|
+
if (this.pendingRefresh === pending) this.pendingRefresh = void 0;
|
|
3321
|
+
}).catch(() => void 0);
|
|
3322
|
+
return pending;
|
|
3323
|
+
}
|
|
3304
3324
|
applyState(state) {
|
|
3305
3325
|
if (!this.running) return;
|
|
3306
3326
|
this.state = state;
|
|
@@ -3314,7 +3334,7 @@ var CheckoutWatcher = class {
|
|
|
3314
3334
|
this.stop();
|
|
3315
3335
|
return;
|
|
3316
3336
|
}
|
|
3317
|
-
if (state.settled || state.expires_at === void 0) {
|
|
3337
|
+
if (state.settled || state.expires_at === void 0 || state.expires_in_seconds === 0) {
|
|
3318
3338
|
this.stopCountdown();
|
|
3319
3339
|
} else if (this.countdownTimer === void 0) {
|
|
3320
3340
|
this.countdownTimer = this.setInterval()(() => {
|
|
@@ -3330,7 +3350,7 @@ var CheckoutWatcher = class {
|
|
|
3330
3350
|
}, 1e3);
|
|
3331
3351
|
}
|
|
3332
3352
|
const canPollAttempt = state.rail !== "checkout_lock" && typeof state.payment_hash === "string" && /^[0-9a-f]{64}$/i.test(state.payment_hash);
|
|
3333
|
-
if (
|
|
3353
|
+
if (this.options.refreshStatus === void 0 || state.reference.length === 0 || !canPollAttempt) {
|
|
3334
3354
|
this.stopPolling();
|
|
3335
3355
|
} else if (this.pollTimer === void 0) {
|
|
3336
3356
|
this.pollTimer = this.setInterval()(() => {
|
|
@@ -3342,20 +3362,22 @@ var CheckoutWatcher = class {
|
|
|
3342
3362
|
const refreshStatus = this.options.refreshStatus;
|
|
3343
3363
|
const current = this.state;
|
|
3344
3364
|
if (!this.running || refreshStatus === void 0 || current === void 0) return;
|
|
3345
|
-
if (current.terminal
|
|
3365
|
+
if (current.terminal) {
|
|
3346
3366
|
this.stopPolling();
|
|
3347
3367
|
return;
|
|
3348
3368
|
}
|
|
3349
3369
|
if (this.pollInFlight) return;
|
|
3350
3370
|
if (this.pollBackoffUntil !== void 0 && this.now() < this.pollBackoffUntil) return;
|
|
3351
3371
|
this.pollInFlight = true;
|
|
3372
|
+
const generation = this.generation;
|
|
3352
3373
|
try {
|
|
3353
|
-
const fetched = await
|
|
3374
|
+
const fetched = await this.fetchSnapshot(current.reference);
|
|
3375
|
+
if (generation !== this.generation) return;
|
|
3354
3376
|
this.pollFailureCount = 0;
|
|
3355
3377
|
this.pollBackoffUntil = void 0;
|
|
3356
3378
|
if (fetched === null) return;
|
|
3357
3379
|
if (!this.running || this.state === void 0) return;
|
|
3358
|
-
if (this.state.
|
|
3380
|
+
if (this.state.terminal) return;
|
|
3359
3381
|
const next = this.publishSnapshot(fetched);
|
|
3360
3382
|
this.applyState(
|
|
3361
3383
|
createCheckoutState(next, {
|
|
@@ -3366,13 +3388,14 @@ var CheckoutWatcher = class {
|
|
|
3366
3388
|
})
|
|
3367
3389
|
);
|
|
3368
3390
|
} catch (error) {
|
|
3391
|
+
if (generation !== this.generation) return;
|
|
3369
3392
|
this.pollFailureCount += 1;
|
|
3370
3393
|
const retryAfterSeconds = error instanceof BrowserRequestError ? error.retryAfterSeconds : void 0;
|
|
3371
3394
|
const backoffSeconds = retryAfterSeconds ?? Math.min(60, 2 ** Math.min(this.pollFailureCount, 6));
|
|
3372
3395
|
this.pollBackoffUntil = this.now() + backoffSeconds;
|
|
3373
3396
|
this.options.onError?.(error);
|
|
3374
3397
|
} finally {
|
|
3375
|
-
this.pollInFlight = false;
|
|
3398
|
+
if (generation === this.generation) this.pollInFlight = false;
|
|
3376
3399
|
}
|
|
3377
3400
|
}
|
|
3378
3401
|
stopCountdown() {
|
|
@@ -3399,6 +3422,7 @@ var BrowserCheckoutController = class {
|
|
|
3399
3422
|
options;
|
|
3400
3423
|
watcher;
|
|
3401
3424
|
state;
|
|
3425
|
+
generation = 0;
|
|
3402
3426
|
constructor(options) {
|
|
3403
3427
|
this.options = options;
|
|
3404
3428
|
this.watcher = this.createWatcher(options);
|
|
@@ -3408,6 +3432,7 @@ var BrowserCheckoutController = class {
|
|
|
3408
3432
|
return this.state;
|
|
3409
3433
|
}
|
|
3410
3434
|
stop() {
|
|
3435
|
+
this.generation += 1;
|
|
3411
3436
|
this.watcher.stop();
|
|
3412
3437
|
}
|
|
3413
3438
|
getState() {
|
|
@@ -3469,6 +3494,7 @@ var BrowserCheckoutController = class {
|
|
|
3469
3494
|
if (paymentHash === void 0) {
|
|
3470
3495
|
throw new Error(`No swap attempt ${options.attemptId} in this checkout.`);
|
|
3471
3496
|
}
|
|
3497
|
+
const generation = this.generation;
|
|
3472
3498
|
const invoice = await requestSwapRefund({
|
|
3473
3499
|
fetch: this.options.fetch ?? globalThis.fetch,
|
|
3474
3500
|
prefix,
|
|
@@ -3480,10 +3506,12 @@ var BrowserCheckoutController = class {
|
|
|
3480
3506
|
refundAddress: options.refundAddress,
|
|
3481
3507
|
confirm
|
|
3482
3508
|
});
|
|
3509
|
+
if (generation !== this.generation) throw new DOMException("Checkout changed.", "AbortError");
|
|
3483
3510
|
this.watcher.stageSwapInvoice(invoice);
|
|
3484
3511
|
return invoice;
|
|
3485
3512
|
}
|
|
3486
3513
|
cancel() {
|
|
3514
|
+
this.generation += 1;
|
|
3487
3515
|
this.state = this.watcher.cancel();
|
|
3488
3516
|
emitBrowserLog(
|
|
3489
3517
|
this.options.logger,
|
|
@@ -3759,6 +3787,7 @@ export {
|
|
|
3759
3787
|
createTransactionDetails,
|
|
3760
3788
|
createTransactionDetailsFromState,
|
|
3761
3789
|
resolveTransactionDetailRows,
|
|
3790
|
+
createAppBrowserConsoleLogger,
|
|
3762
3791
|
getWizardEmptyMessage,
|
|
3763
3792
|
getRouteNetworkLabel,
|
|
3764
3793
|
createWizardRouteAssetDisplays,
|
|
@@ -3790,7 +3819,6 @@ export {
|
|
|
3790
3819
|
createPaymentWizardModel,
|
|
3791
3820
|
updatePaymentWizardSelection,
|
|
3792
3821
|
createPaymentWizardController,
|
|
3793
|
-
createAppBrowserConsoleLogger,
|
|
3794
3822
|
selectCheckoutDisplayInvoice,
|
|
3795
3823
|
isPaidCheckoutSnapshot,
|
|
3796
3824
|
isReusableLightningInvoice,
|