@openreceive/node 0.4.2 → 0.4.5
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-ZYS6QECW.js → chunk-65UPROSE.js} +193 -62
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +24 -8
- package/dist/index.js +65 -65
- package/package.json +2 -2
- package/skills/integrate-openreceive/SKILL.md +16 -5
- package/skills/integrate-openreceive/references/btcpay.md +193 -0
- package/skills/integrate-openreceive/references/django.md +667 -0
- package/skills/integrate-openreceive/references/fastapi.md +537 -0
- package/skills/integrate-openreceive/references/fastify.md +529 -0
- package/skills/integrate-openreceive/references/laravel.md +658 -0
- package/skills/integrate-openreceive/references/next.md +580 -0
- package/skills/integrate-openreceive/references/node.md +33 -14
- package/skills/integrate-openreceive/references/php.md +598 -0
- package/skills/integrate-openreceive/references/rails.md +72 -27
- package/skills/integrate-openreceive/references/woocommerce.md +153 -0
|
@@ -177,6 +177,7 @@ import {
|
|
|
177
177
|
compact,
|
|
178
178
|
formatSpendCapabilityRefusedMessage,
|
|
179
179
|
formatSpendCapabilityWarningMessage,
|
|
180
|
+
OPENRECEIVE_NWC_NOTIFICATION_TYPES,
|
|
180
181
|
OpenReceiveError as OpenReceiveError2,
|
|
181
182
|
parseNwcUri
|
|
182
183
|
} from "@openreceive/core";
|
|
@@ -186,6 +187,8 @@ import {
|
|
|
186
187
|
OPENRECEIVE_MAX_AMOUNT_MSATS,
|
|
187
188
|
OPENRECEIVE_MIN_AMOUNT_MSATS,
|
|
188
189
|
OPENRECEIVE_NWC_METADATA_MAX_BYTES,
|
|
190
|
+
OPENRECEIVE_NWC_REQUIRED_RECEIVE_METHODS,
|
|
191
|
+
OPENRECEIVE_NWC_SPEND_METHODS,
|
|
189
192
|
nonEmptyString,
|
|
190
193
|
recordOrEmpty
|
|
191
194
|
} from "@openreceive/core";
|
|
@@ -194,13 +197,8 @@ import {
|
|
|
194
197
|
var HEX_64 = /^[0-9a-fA-F]{64}$/;
|
|
195
198
|
|
|
196
199
|
// src/nwc/normalize.ts
|
|
197
|
-
var REQUIRED_RECEIVE_METHODS =
|
|
198
|
-
var SPEND_METHODS =
|
|
199
|
-
"pay_invoice",
|
|
200
|
-
"multi_pay_invoice",
|
|
201
|
-
"pay_keysend",
|
|
202
|
-
"multi_pay_keysend"
|
|
203
|
-
];
|
|
200
|
+
var REQUIRED_RECEIVE_METHODS = OPENRECEIVE_NWC_REQUIRED_RECEIVE_METHODS;
|
|
201
|
+
var SPEND_METHODS = OPENRECEIVE_NWC_SPEND_METHODS;
|
|
204
202
|
function summarizeWalletCapabilities(connection, rawInfo, rawServiceInfo) {
|
|
205
203
|
const unwrappedInfo = unwrapNwcResult(rawInfo);
|
|
206
204
|
const info = recordOrEmpty(unwrappedInfo);
|
|
@@ -541,6 +539,7 @@ function delay(milliseconds) {
|
|
|
541
539
|
}
|
|
542
540
|
|
|
543
541
|
// src/alby-nwc.ts
|
|
542
|
+
var NOTIFICATION_TYPES = new Set(OPENRECEIVE_NWC_NOTIFICATION_TYPES);
|
|
544
543
|
var AlbyNwcReceiveClient = class {
|
|
545
544
|
/**
|
|
546
545
|
* Safe, loggable view of the connection (wallet pubkey, relays, lud16, and
|
|
@@ -829,7 +828,7 @@ var AlbyNwcReceiveClient = class {
|
|
|
829
828
|
"debug",
|
|
830
829
|
"nwc.notifications.subscribe.requested",
|
|
831
830
|
"Subscribing to NWC-02 payment_received notifications.",
|
|
832
|
-
{ notification_types:
|
|
831
|
+
{ notification_types: OPENRECEIVE_NWC_NOTIFICATION_TYPES }
|
|
833
832
|
);
|
|
834
833
|
let subscription;
|
|
835
834
|
try {
|
|
@@ -837,7 +836,7 @@ var AlbyNwcReceiveClient = class {
|
|
|
837
836
|
client,
|
|
838
837
|
(rawNotification) => {
|
|
839
838
|
const notification = normalizeNwcNotification(rawNotification);
|
|
840
|
-
if (notification.type
|
|
839
|
+
if (!NOTIFICATION_TYPES.has(notification.type)) return;
|
|
841
840
|
this.#log(
|
|
842
841
|
"debug",
|
|
843
842
|
"nwc.notifications.received",
|
|
@@ -852,7 +851,7 @@ var AlbyNwcReceiveClient = class {
|
|
|
852
851
|
} catch {
|
|
853
852
|
}
|
|
854
853
|
},
|
|
855
|
-
[
|
|
854
|
+
[...OPENRECEIVE_NWC_NOTIFICATION_TYPES]
|
|
856
855
|
);
|
|
857
856
|
} catch (error) {
|
|
858
857
|
const normalized = normalizeNwcWalletError(error);
|
|
@@ -941,7 +940,7 @@ function createNwcReceiveClient(options) {
|
|
|
941
940
|
return new AlbyNwcReceiveClient(options);
|
|
942
941
|
}
|
|
943
942
|
|
|
944
|
-
// src/swap
|
|
943
|
+
// src/generated/swap-tables.ts
|
|
945
944
|
var OPENRECEIVE_SWAP_PAY_IN_ASSETS = [
|
|
946
945
|
"SOL_SOL",
|
|
947
946
|
"USDT_TRON",
|
|
@@ -951,7 +950,7 @@ var OPENRECEIVE_SWAP_PAY_IN_ASSETS = [
|
|
|
951
950
|
"USDT_ETH",
|
|
952
951
|
"USDC_ETH"
|
|
953
952
|
];
|
|
954
|
-
var
|
|
953
|
+
var OPENRECEIVE_SWAP_ASSET_INFO = {
|
|
955
954
|
SOL_SOL: {
|
|
956
955
|
pay_in_asset: "SOL_SOL",
|
|
957
956
|
label: "SOL",
|
|
@@ -1002,6 +1001,37 @@ var ASSET_INFO = {
|
|
|
1002
1001
|
network: "ETH"
|
|
1003
1002
|
}
|
|
1004
1003
|
};
|
|
1004
|
+
var OPENRECEIVE_SWAP_PROVIDER_STATES = [
|
|
1005
|
+
"creating_provider_order",
|
|
1006
|
+
"awaiting_deposit",
|
|
1007
|
+
"confirming",
|
|
1008
|
+
"exchanging",
|
|
1009
|
+
"paying_invoice",
|
|
1010
|
+
"completed",
|
|
1011
|
+
"expired",
|
|
1012
|
+
"refund_required",
|
|
1013
|
+
"refund_pending",
|
|
1014
|
+
"refunded",
|
|
1015
|
+
"attention",
|
|
1016
|
+
"failed"
|
|
1017
|
+
];
|
|
1018
|
+
var OPENRECEIVE_SWAP_STATE_TABLE = {
|
|
1019
|
+
creating_provider_order: { phase: "preparing", terminal: false },
|
|
1020
|
+
awaiting_deposit: { phase: "awaiting_deposit", terminal: false },
|
|
1021
|
+
confirming: { phase: "processing", terminal: false },
|
|
1022
|
+
exchanging: { phase: "processing", terminal: false },
|
|
1023
|
+
paying_invoice: { phase: "processing", terminal: false },
|
|
1024
|
+
completed: { phase: "settling", terminal: false },
|
|
1025
|
+
expired: { phase: "terminal", terminal: true },
|
|
1026
|
+
refund_required: { phase: "refund", terminal: false },
|
|
1027
|
+
refund_pending: { phase: "refund", terminal: false },
|
|
1028
|
+
refunded: { phase: "terminal", terminal: true },
|
|
1029
|
+
attention: { phase: "attention", terminal: true },
|
|
1030
|
+
failed: { phase: "terminal", terminal: true }
|
|
1031
|
+
};
|
|
1032
|
+
|
|
1033
|
+
// src/swap/assets.ts
|
|
1034
|
+
var ASSET_INFO = OPENRECEIVE_SWAP_ASSET_INFO;
|
|
1005
1035
|
function isSwapPayInAsset(value) {
|
|
1006
1036
|
return typeof value === "string" && OPENRECEIVE_SWAP_PAY_IN_ASSETS.includes(value);
|
|
1007
1037
|
}
|
|
@@ -1408,6 +1438,124 @@ function readFixedFloatCurrencies(data) {
|
|
|
1408
1438
|
|
|
1409
1439
|
// src/swap/fixedfloat-orders.ts
|
|
1410
1440
|
import { recordOrEmpty as recordOrEmpty5 } from "@openreceive/core";
|
|
1441
|
+
|
|
1442
|
+
// src/generated/swap-state-table.ts
|
|
1443
|
+
var OPENRECEIVE_SWAP_STATUS_ROWS = [
|
|
1444
|
+
{
|
|
1445
|
+
status: "DONE",
|
|
1446
|
+
refund_tx_present: true,
|
|
1447
|
+
choice: "any",
|
|
1448
|
+
state: "refunded",
|
|
1449
|
+
refund_reason_from_emergency: false
|
|
1450
|
+
},
|
|
1451
|
+
{
|
|
1452
|
+
status: "FINISHED",
|
|
1453
|
+
refund_tx_present: true,
|
|
1454
|
+
choice: "any",
|
|
1455
|
+
state: "refunded",
|
|
1456
|
+
refund_reason_from_emergency: false
|
|
1457
|
+
},
|
|
1458
|
+
{
|
|
1459
|
+
status: "NEW",
|
|
1460
|
+
refund_tx_present: "any",
|
|
1461
|
+
choice: "any",
|
|
1462
|
+
state: "awaiting_deposit",
|
|
1463
|
+
refund_reason_from_emergency: false
|
|
1464
|
+
},
|
|
1465
|
+
{
|
|
1466
|
+
status: "PENDING",
|
|
1467
|
+
refund_tx_present: "any",
|
|
1468
|
+
choice: "any",
|
|
1469
|
+
state: "confirming",
|
|
1470
|
+
refund_reason_from_emergency: false
|
|
1471
|
+
},
|
|
1472
|
+
{
|
|
1473
|
+
status: "EXCHANGE",
|
|
1474
|
+
refund_tx_present: "any",
|
|
1475
|
+
choice: "any",
|
|
1476
|
+
state: "exchanging",
|
|
1477
|
+
refund_reason_from_emergency: false
|
|
1478
|
+
},
|
|
1479
|
+
{
|
|
1480
|
+
status: "WITHDRAW",
|
|
1481
|
+
refund_tx_present: "any",
|
|
1482
|
+
choice: "any",
|
|
1483
|
+
state: "paying_invoice",
|
|
1484
|
+
refund_reason_from_emergency: false
|
|
1485
|
+
},
|
|
1486
|
+
{
|
|
1487
|
+
status: "DONE",
|
|
1488
|
+
refund_tx_present: "any",
|
|
1489
|
+
choice: "any",
|
|
1490
|
+
state: "completed",
|
|
1491
|
+
refund_reason_from_emergency: false
|
|
1492
|
+
},
|
|
1493
|
+
{
|
|
1494
|
+
status: "EXPIRED",
|
|
1495
|
+
refund_tx_present: "any",
|
|
1496
|
+
choice: "any",
|
|
1497
|
+
state: "expired",
|
|
1498
|
+
refund_reason_from_emergency: false
|
|
1499
|
+
},
|
|
1500
|
+
{
|
|
1501
|
+
status: "EMERGENCY",
|
|
1502
|
+
refund_tx_present: true,
|
|
1503
|
+
choice: "REFUND",
|
|
1504
|
+
state: "refunded",
|
|
1505
|
+
refund_reason_from_emergency: true
|
|
1506
|
+
},
|
|
1507
|
+
{
|
|
1508
|
+
status: "EMERGENCY",
|
|
1509
|
+
refund_tx_present: "any",
|
|
1510
|
+
choice: "REFUND",
|
|
1511
|
+
state: "refund_pending",
|
|
1512
|
+
refund_reason_from_emergency: true
|
|
1513
|
+
},
|
|
1514
|
+
{
|
|
1515
|
+
status: "EMERGENCY",
|
|
1516
|
+
refund_tx_present: "any",
|
|
1517
|
+
choice: "EXCHANGE",
|
|
1518
|
+
state: "attention",
|
|
1519
|
+
attention_reason: "provider_reported_emergency",
|
|
1520
|
+
refund_reason_from_emergency: false
|
|
1521
|
+
},
|
|
1522
|
+
{
|
|
1523
|
+
status: "EMERGENCY",
|
|
1524
|
+
refund_tx_present: "any",
|
|
1525
|
+
choice: "any",
|
|
1526
|
+
state: "refund_required",
|
|
1527
|
+
refund_reason_from_emergency: true
|
|
1528
|
+
},
|
|
1529
|
+
{
|
|
1530
|
+
status: "*",
|
|
1531
|
+
status_contains: "FAIL",
|
|
1532
|
+
refund_tx_present: "any",
|
|
1533
|
+
choice: "any",
|
|
1534
|
+
state: "failed",
|
|
1535
|
+
refund_reason_from_emergency: false
|
|
1536
|
+
},
|
|
1537
|
+
{
|
|
1538
|
+
status: "*",
|
|
1539
|
+
refund_tx_present: "any",
|
|
1540
|
+
choice: "any",
|
|
1541
|
+
state: "attention",
|
|
1542
|
+
attention_reason: "provider_status_unrecognized",
|
|
1543
|
+
refund_reason_from_emergency: false
|
|
1544
|
+
}
|
|
1545
|
+
];
|
|
1546
|
+
var OPENRECEIVE_SWAP_EMERGENCY_STATUS_ALIASES = {
|
|
1547
|
+
OVER: "MORE",
|
|
1548
|
+
OVERPAID: "MORE"
|
|
1549
|
+
};
|
|
1550
|
+
var OPENRECEIVE_SWAP_REFUND_REASON_ROWS = [
|
|
1551
|
+
{ all_of: ["LESS", "EXPIRED"], refund_reason: "underpaid_and_late" },
|
|
1552
|
+
{ all_of: ["MORE", "EXPIRED"], refund_reason: "overpaid_and_late" },
|
|
1553
|
+
{ all_of: ["LESS"], refund_reason: "underpaid" },
|
|
1554
|
+
{ all_of: ["MORE"], refund_reason: "overpaid" },
|
|
1555
|
+
{ all_of: ["EXPIRED"], refund_reason: "late_deposit" }
|
|
1556
|
+
];
|
|
1557
|
+
|
|
1558
|
+
// src/swap/fixedfloat-orders.ts
|
|
1411
1559
|
function normalizeFixedFloatOrder(data, input) {
|
|
1412
1560
|
const fields = extractFixedFloatOrderFields(recordOrEmpty5(data), input);
|
|
1413
1561
|
const { attention, attention_reason } = fields.status;
|
|
@@ -1492,58 +1640,28 @@ function extractFixedFloatOrderFields(record, input) {
|
|
|
1492
1640
|
}
|
|
1493
1641
|
function normalizeFixedFloatStatus(status, emergency, refundTxId) {
|
|
1494
1642
|
const normalized = status.toUpperCase();
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
const emergencyStatuses = optionalStringArrayField(emergency, "status").map(
|
|
1507
|
-
(item) => item.toUpperCase()
|
|
1508
|
-
);
|
|
1509
|
-
const refundReason = refundReasonFromEmergencyStatuses(emergencyStatuses);
|
|
1510
|
-
if (choice === "REFUND" && refundTxId !== void 0) {
|
|
1511
|
-
return {
|
|
1512
|
-
state: "refunded",
|
|
1513
|
-
...refundReason === void 0 ? {} : { refund_reason: refundReason }
|
|
1514
|
-
};
|
|
1515
|
-
}
|
|
1516
|
-
if (choice === "REFUND") {
|
|
1517
|
-
return {
|
|
1518
|
-
state: "refund_pending",
|
|
1519
|
-
...refundReason === void 0 ? {} : { refund_reason: refundReason }
|
|
1520
|
-
};
|
|
1521
|
-
}
|
|
1522
|
-
if (choice === "EXCHANGE") {
|
|
1523
|
-
return {
|
|
1524
|
-
state: "attention",
|
|
1525
|
-
attention: true,
|
|
1526
|
-
attention_reason: "provider_reported_emergency"
|
|
1527
|
-
};
|
|
1528
|
-
}
|
|
1529
|
-
return {
|
|
1530
|
-
state: "refund_required",
|
|
1531
|
-
...refundReason === void 0 ? {} : { refund_reason: refundReason }
|
|
1532
|
-
};
|
|
1533
|
-
}
|
|
1534
|
-
if (normalized.includes("FAIL")) return { state: "failed" };
|
|
1535
|
-
return { state: "attention", attention: true, attention_reason: "provider_status_unrecognized" };
|
|
1643
|
+
const refundTxPresent = refundTxId !== void 0;
|
|
1644
|
+
const choice = optionalStringField(emergency, "choice")?.toUpperCase();
|
|
1645
|
+
const row = OPENRECEIVE_SWAP_STATUS_ROWS.find(
|
|
1646
|
+
(candidate) => (candidate.status === "*" ? candidate.status_contains === void 0 || normalized.includes(candidate.status_contains) : candidate.status === normalized) && (candidate.refund_tx_present === "any" || candidate.refund_tx_present === refundTxPresent) && (candidate.choice === "any" || (choice === void 0 ? candidate.choice === "absent" : candidate.choice === choice))
|
|
1647
|
+
);
|
|
1648
|
+
const refundReason = row.refund_reason_from_emergency ? refundReasonFromEmergencyStatuses(optionalStringArrayField(emergency, "status")) : void 0;
|
|
1649
|
+
return {
|
|
1650
|
+
state: row.state,
|
|
1651
|
+
...row.attention_reason === void 0 ? {} : { attention: true, attention_reason: row.attention_reason },
|
|
1652
|
+
...refundReason === void 0 ? {} : { refund_reason: refundReason }
|
|
1653
|
+
};
|
|
1536
1654
|
}
|
|
1537
1655
|
function refundReasonFromEmergencyStatuses(statuses) {
|
|
1538
|
-
const
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1656
|
+
const present = new Set(
|
|
1657
|
+
statuses.map((item) => {
|
|
1658
|
+
const upper = item.toUpperCase();
|
|
1659
|
+
return OPENRECEIVE_SWAP_EMERGENCY_STATUS_ALIASES[upper] ?? upper;
|
|
1660
|
+
})
|
|
1661
|
+
);
|
|
1662
|
+
return OPENRECEIVE_SWAP_REFUND_REASON_ROWS.find(
|
|
1663
|
+
(row) => row.all_of.every((item) => present.has(item))
|
|
1664
|
+
)?.refund_reason;
|
|
1547
1665
|
}
|
|
1548
1666
|
function isRefundPathState(state) {
|
|
1549
1667
|
return state === "refund_required" || state === "refund_pending" || state === "refunded";
|
|
@@ -2282,6 +2400,16 @@ function createNwcEndpointLogger(options) {
|
|
|
2282
2400
|
if (options.onEvent === void 0 && options.logger === void 0) return void 0;
|
|
2283
2401
|
return (entry) => emitEvent(options, entry);
|
|
2284
2402
|
}
|
|
2403
|
+
function summarizeReconcilePass(input) {
|
|
2404
|
+
const decided = [
|
|
2405
|
+
[input.settledCount, "settled"],
|
|
2406
|
+
[input.pendingCount, "pending"],
|
|
2407
|
+
[input.notFoundCount, "not found"]
|
|
2408
|
+
].filter(([count]) => count > 0).map(([count, label]) => `${count} ${label}`);
|
|
2409
|
+
const summary = decided.length === 0 ? "0 decided" : decided.join(", ");
|
|
2410
|
+
const attempts = `${input.attemptCount} ${input.attemptCount === 1 ? "attempt" : "attempts"}`;
|
|
2411
|
+
return input.resultCount === input.attemptCount ? summary : `${summary} of ${attempts}`;
|
|
2412
|
+
}
|
|
2285
2413
|
function sanitizeEvent(entry) {
|
|
2286
2414
|
const clean = {};
|
|
2287
2415
|
for (const [key, value] of Object.entries(entry)) {
|
|
@@ -2408,6 +2536,8 @@ export {
|
|
|
2408
2536
|
HEX_64,
|
|
2409
2537
|
createNwcReceiveClient,
|
|
2410
2538
|
OPENRECEIVE_SWAP_PAY_IN_ASSETS,
|
|
2539
|
+
OPENRECEIVE_SWAP_PROVIDER_STATES,
|
|
2540
|
+
OPENRECEIVE_SWAP_STATE_TABLE,
|
|
2411
2541
|
isSwapPayInAsset,
|
|
2412
2542
|
listSwapAssetInfo,
|
|
2413
2543
|
TransientSwapCache,
|
|
@@ -2418,6 +2548,7 @@ export {
|
|
|
2418
2548
|
createLscSwapProvidersFromEnvironment,
|
|
2419
2549
|
emitLog,
|
|
2420
2550
|
createNwcEndpointLogger,
|
|
2551
|
+
summarizeReconcilePass,
|
|
2421
2552
|
sanitizeEvent,
|
|
2422
2553
|
redactSecrets,
|
|
2423
2554
|
summarizeSwapProviderApiRequest,
|
package/dist/cli.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -148,7 +148,18 @@ declare class AlbyNwcReceiveClient implements ReceiveNwcClient {
|
|
|
148
148
|
declare function createNwcReceiveClient(options: AlbyNwcReceiveClientOptions): AlbyNwcReceiveClient;
|
|
149
149
|
|
|
150
150
|
declare const OPENRECEIVE_SWAP_PAY_IN_ASSETS: readonly ["SOL_SOL", "USDT_TRON", "USDT_SOL", "USDC_SOL", "ETH_ETH", "USDT_ETH", "USDC_ETH"];
|
|
151
|
-
type
|
|
151
|
+
type GeneratedSwapPayInAsset = (typeof OPENRECEIVE_SWAP_PAY_IN_ASSETS)[number];
|
|
152
|
+
declare const OPENRECEIVE_SWAP_PROVIDER_STATES: readonly ["creating_provider_order", "awaiting_deposit", "confirming", "exchanging", "paying_invoice", "completed", "expired", "refund_required", "refund_pending", "refunded", "attention", "failed"];
|
|
153
|
+
type GeneratedSwapProviderState = (typeof OPENRECEIVE_SWAP_PROVIDER_STATES)[number];
|
|
154
|
+
type GeneratedSwapPhase = "preparing" | "awaiting_deposit" | "processing" | "settling" | "terminal" | "refund" | "attention";
|
|
155
|
+
declare const OPENRECEIVE_SWAP_ATTENTION_REASONS: readonly ["provider_reported_emergency", "provider_status_unrecognized", "provider_completed_without_wallet_settlement"];
|
|
156
|
+
type GeneratedSwapAttentionReason = (typeof OPENRECEIVE_SWAP_ATTENTION_REASONS)[number];
|
|
157
|
+
declare const OPENRECEIVE_SWAP_REFUND_REASONS: readonly ["underpaid", "overpaid", "late_deposit", "underpaid_and_late", "overpaid_and_late"];
|
|
158
|
+
type GeneratedSwapRefundReason = (typeof OPENRECEIVE_SWAP_REFUND_REASONS)[number];
|
|
159
|
+
declare const OPENRECEIVE_SWAP_AVAILABILITY_REASONS: readonly ["provider_unconfigured", "amount_too_small", "amount_too_large", "pair_temporarily_unavailable", "region_unsupported", "provider_rate_limited", "provider_unreachable"];
|
|
160
|
+
type GeneratedSwapAvailabilityReason = (typeof OPENRECEIVE_SWAP_AVAILABILITY_REASONS)[number];
|
|
161
|
+
|
|
162
|
+
type SwapPayInAsset = GeneratedSwapPayInAsset;
|
|
152
163
|
|
|
153
164
|
interface SwapCacheResolveOptions<T> {
|
|
154
165
|
readonly refreshSeconds: number;
|
|
@@ -169,15 +180,16 @@ declare class TransientSwapCache {
|
|
|
169
180
|
resolve<T>(key: string, options: SwapCacheResolveOptions<T>): Promise<T>;
|
|
170
181
|
}
|
|
171
182
|
|
|
172
|
-
type SwapProviderState =
|
|
173
|
-
type SwapAvailabilityReason =
|
|
183
|
+
type SwapProviderState = GeneratedSwapProviderState;
|
|
184
|
+
type SwapAvailabilityReason = GeneratedSwapAvailabilityReason;
|
|
174
185
|
/**
|
|
175
186
|
* Why a swap attempt entered the `attention` state and needs human/support review.
|
|
176
187
|
* Every code path that sets `attention: true` records one of these so a dashboard or
|
|
177
|
-
* runbook can branch on the cause instead of a bare boolean.
|
|
178
|
-
*
|
|
188
|
+
* runbook can branch on the cause instead of a bare boolean. The FixedFloat status
|
|
189
|
+
* mapping that produces them is pinned by spec/test-vectors/swap-state.json;
|
|
190
|
+
* `provider_completed_without_wallet_settlement` is reserved and not emitted yet.
|
|
179
191
|
*/
|
|
180
|
-
type SwapAttentionReason =
|
|
192
|
+
type SwapAttentionReason = GeneratedSwapAttentionReason;
|
|
181
193
|
/**
|
|
182
194
|
* Why a swap attempt entered the refund path (`refund_required` → `refunded`).
|
|
183
195
|
* Mapped from FixedFloat `emergency.status` (LESS / MORE / EXPIRED). An overpay
|
|
@@ -185,7 +197,7 @@ type SwapAttentionReason = "provider_completed_without_wallet_settlement" | "pro
|
|
|
185
197
|
* fixed-amount bolt11, so there is nothing to exchange the surplus into and
|
|
186
198
|
* `choice=EXCHANGE` is not a path this client takes.
|
|
187
199
|
*/
|
|
188
|
-
type SwapRefundReason =
|
|
200
|
+
type SwapRefundReason = GeneratedSwapRefundReason;
|
|
189
201
|
interface SwapQuote {
|
|
190
202
|
readonly pay_amount?: string;
|
|
191
203
|
readonly minimum_pay_amount?: string;
|
|
@@ -407,8 +419,12 @@ declare function fixedFloatCompatibleSwapProvider(options: FixedFloatCompatibleS
|
|
|
407
419
|
* - `refund` — a refund is required, staged, or in flight.
|
|
408
420
|
* - `attention` — needs operator/support review (funds may be stuck).
|
|
409
421
|
* - `terminal` — the attempt is over and will not change (expired/refunded/failed).
|
|
422
|
+
*
|
|
423
|
+
* The state → phase/terminal table itself is kernel vocabulary
|
|
424
|
+
* (spec/data/kernel-tables.json) generated into every engine; this module adds the
|
|
425
|
+
* payer-facing copy, which only the JS checkout renders.
|
|
410
426
|
*/
|
|
411
|
-
type SwapPhase =
|
|
427
|
+
type SwapPhase = GeneratedSwapPhase;
|
|
412
428
|
interface SwapStateInfo {
|
|
413
429
|
/** The provider state this describes. */
|
|
414
430
|
readonly state: SwapProviderState;
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
HEX_64,
|
|
3
3
|
OPENRECEIVE_SWAP_PAY_IN_ASSETS,
|
|
4
|
+
OPENRECEIVE_SWAP_PROVIDER_STATES,
|
|
5
|
+
OPENRECEIVE_SWAP_STATE_TABLE,
|
|
4
6
|
ReceiveCheckoutValidationError,
|
|
5
7
|
TransientSwapCache,
|
|
6
8
|
WalletPreflightError,
|
|
@@ -14,9 +16,10 @@ import {
|
|
|
14
16
|
isSwapPayInAsset,
|
|
15
17
|
listSwapAssetInfo,
|
|
16
18
|
sanitizeEvent,
|
|
19
|
+
summarizeReconcilePass,
|
|
17
20
|
summarizeSwapProviderApiRequest,
|
|
18
21
|
summarizeSwapProviderApiResponse
|
|
19
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-65UPROSE.js";
|
|
20
23
|
|
|
21
24
|
// src/index.ts
|
|
22
25
|
import { OpenReceiveError as OpenReceiveError2 } from "@openreceive/core";
|
|
@@ -54,6 +57,7 @@ import path from "path";
|
|
|
54
57
|
import { compact as compact2 } from "@openreceive/core";
|
|
55
58
|
|
|
56
59
|
// src/console-logger.ts
|
|
60
|
+
import { inspect } from "util";
|
|
57
61
|
import { compact } from "@openreceive/core";
|
|
58
62
|
|
|
59
63
|
// src/log-level.ts
|
|
@@ -104,9 +108,9 @@ function createConsoleLogger(options = {}) {
|
|
|
104
108
|
level,
|
|
105
109
|
prefix,
|
|
106
110
|
event,
|
|
107
|
-
message
|
|
108
|
-
|
|
109
|
-
|
|
111
|
+
message,
|
|
112
|
+
fields: compact(fields)
|
|
113
|
+
})
|
|
110
114
|
);
|
|
111
115
|
};
|
|
112
116
|
}
|
|
@@ -125,14 +129,26 @@ function createAppConsoleLogger(options) {
|
|
|
125
129
|
level,
|
|
126
130
|
prefix: options.prefix,
|
|
127
131
|
event,
|
|
128
|
-
message
|
|
129
|
-
|
|
130
|
-
|
|
132
|
+
message,
|
|
133
|
+
fields: compact(fields)
|
|
134
|
+
})
|
|
131
135
|
);
|
|
132
136
|
};
|
|
133
137
|
}
|
|
134
138
|
function formatConsoleLogLine(input) {
|
|
135
|
-
|
|
139
|
+
const head = `[${input.at}] ${input.level.toUpperCase()} [${input.prefix}] ${input.event}: ${input.message}`;
|
|
140
|
+
const fields = Object.entries(input.fields).map(
|
|
141
|
+
([key, value]) => `${key}=${formatFieldValue(value)}`
|
|
142
|
+
);
|
|
143
|
+
return fields.length === 0 ? head : `${head} ${fields.join(" ")}`;
|
|
144
|
+
}
|
|
145
|
+
function formatFieldValue(value) {
|
|
146
|
+
if (typeof value === "string")
|
|
147
|
+
return /^[\w.\-:/@+]*$/.test(value) ? value : JSON.stringify(value);
|
|
148
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
149
|
+
return String(value);
|
|
150
|
+
}
|
|
151
|
+
return inspect(value, { breakLength: Number.POSITIVE_INFINITY, compact: true, depth: 4 });
|
|
136
152
|
}
|
|
137
153
|
|
|
138
154
|
// src/service/file-logger.ts
|
|
@@ -764,92 +780,65 @@ function toSafeInteger(value, field) {
|
|
|
764
780
|
import { isValidSwapAddressForPayInAsset } from "@openreceive/core";
|
|
765
781
|
|
|
766
782
|
// src/swap/state.ts
|
|
767
|
-
var
|
|
783
|
+
var SWAP_STATE_COPY = {
|
|
768
784
|
creating_provider_order: {
|
|
769
|
-
state: "creating_provider_order",
|
|
770
785
|
label: "Preparing payment address",
|
|
771
|
-
detail: "Creating a payment address."
|
|
772
|
-
phase: "preparing",
|
|
773
|
-
terminal: false
|
|
786
|
+
detail: "Creating a payment address."
|
|
774
787
|
},
|
|
775
788
|
awaiting_deposit: {
|
|
776
|
-
state: "awaiting_deposit",
|
|
777
789
|
label: "Waiting for your payment",
|
|
778
|
-
detail: "Send exactly the amount shown below."
|
|
779
|
-
phase: "awaiting_deposit",
|
|
780
|
-
terminal: false
|
|
790
|
+
detail: "Send exactly the amount shown below."
|
|
781
791
|
},
|
|
782
792
|
confirming: {
|
|
783
|
-
state: "confirming",
|
|
784
793
|
label: "Confirming payment",
|
|
785
|
-
detail: "Your payment was detected and is confirming on-chain."
|
|
786
|
-
phase: "processing",
|
|
787
|
-
terminal: false
|
|
794
|
+
detail: "Your payment was detected and is confirming on-chain."
|
|
788
795
|
},
|
|
789
796
|
exchanging: {
|
|
790
|
-
state: "exchanging",
|
|
791
797
|
label: "Converting payment",
|
|
792
|
-
detail: "Your payment is confirmed and being converted. This usually finishes within a minute."
|
|
793
|
-
phase: "processing",
|
|
794
|
-
terminal: false
|
|
798
|
+
detail: "Your payment is confirmed and being converted. This usually finishes within a minute."
|
|
795
799
|
},
|
|
796
800
|
paying_invoice: {
|
|
797
|
-
state: "paying_invoice",
|
|
798
801
|
label: "Finalizing checkout",
|
|
799
|
-
detail: "The provider is sending the Lightning payment. This usually takes a few seconds."
|
|
800
|
-
phase: "processing",
|
|
801
|
-
terminal: false
|
|
802
|
+
detail: "The provider is sending the Lightning payment. This usually takes a few seconds."
|
|
802
803
|
},
|
|
803
804
|
completed: {
|
|
804
|
-
state: "completed",
|
|
805
805
|
label: "Finalizing checkout",
|
|
806
|
-
detail: "The provider is sending the Lightning payment. This usually takes a few seconds."
|
|
807
|
-
phase: "settling",
|
|
808
|
-
terminal: false
|
|
806
|
+
detail: "The provider is sending the Lightning payment. This usually takes a few seconds."
|
|
809
807
|
},
|
|
810
808
|
expired: {
|
|
811
|
-
state: "expired",
|
|
812
809
|
label: "Expired",
|
|
813
|
-
detail: "No payment was received before the payment window closed."
|
|
814
|
-
phase: "terminal",
|
|
815
|
-
terminal: true
|
|
810
|
+
detail: "No payment was received before the payment window closed."
|
|
816
811
|
},
|
|
817
812
|
refund_required: {
|
|
818
|
-
state: "refund_required",
|
|
819
813
|
label: "Refund needed",
|
|
820
|
-
detail: "Enter an address you control to request a refund."
|
|
821
|
-
phase: "refund",
|
|
822
|
-
terminal: false
|
|
814
|
+
detail: "Enter an address you control to request a refund."
|
|
823
815
|
},
|
|
824
816
|
refund_pending: {
|
|
825
|
-
state: "refund_pending",
|
|
826
817
|
label: "Refund pending",
|
|
827
|
-
detail: "Your refund request has been sent."
|
|
828
|
-
phase: "refund",
|
|
829
|
-
terminal: false
|
|
818
|
+
detail: "Your refund request has been sent."
|
|
830
819
|
},
|
|
831
820
|
refunded: {
|
|
832
|
-
state: "refunded",
|
|
833
821
|
label: "Refunded",
|
|
834
|
-
detail: "The provider reports the refund was sent."
|
|
835
|
-
phase: "terminal",
|
|
836
|
-
terminal: true
|
|
822
|
+
detail: "The provider reports the refund was sent."
|
|
837
823
|
},
|
|
838
824
|
attention: {
|
|
839
|
-
state: "attention",
|
|
840
825
|
label: "Needs attention",
|
|
841
|
-
detail: "This payment needs support review."
|
|
842
|
-
phase: "attention",
|
|
843
|
-
terminal: true
|
|
826
|
+
detail: "This payment needs support review."
|
|
844
827
|
},
|
|
845
828
|
failed: {
|
|
846
|
-
state: "failed",
|
|
847
829
|
label: "Failed",
|
|
848
|
-
detail: "This payment address can no longer be used."
|
|
849
|
-
phase: "terminal",
|
|
850
|
-
terminal: true
|
|
830
|
+
detail: "This payment address can no longer be used."
|
|
851
831
|
}
|
|
852
832
|
};
|
|
833
|
+
function swapStateInfo(state) {
|
|
834
|
+
const { phase, terminal } = OPENRECEIVE_SWAP_STATE_TABLE[state];
|
|
835
|
+
return { state, ...SWAP_STATE_COPY[state], phase, terminal };
|
|
836
|
+
}
|
|
837
|
+
var OPENRECEIVE_SWAP_STATES = Object.freeze(
|
|
838
|
+
Object.fromEntries(
|
|
839
|
+
OPENRECEIVE_SWAP_PROVIDER_STATES.map((state) => [state, swapStateInfo(state)])
|
|
840
|
+
)
|
|
841
|
+
);
|
|
853
842
|
|
|
854
843
|
// src/swap/weight-budget.ts
|
|
855
844
|
import { compact as compact3 } from "@openreceive/core";
|
|
@@ -1379,24 +1368,35 @@ async function createOpenReceive(supplied = {}) {
|
|
|
1379
1368
|
maxPages: input.maxPages,
|
|
1380
1369
|
onWalk: (walk) => walks.push(walk)
|
|
1381
1370
|
});
|
|
1371
|
+
const settledCount = results.filter((result) => result.status === "settled").length;
|
|
1372
|
+
const pendingCount = results.filter((result) => result.status === "pending").length;
|
|
1373
|
+
const notFoundCount = results.filter((result) => result.status === "not_found").length;
|
|
1382
1374
|
emitLog(
|
|
1383
1375
|
nodeOptions,
|
|
1384
1376
|
"info",
|
|
1385
1377
|
"payment.reconcile.completed",
|
|
1386
|
-
|
|
1378
|
+
summarizeReconcilePass({
|
|
1379
|
+
attemptCount: input.attempts.length,
|
|
1380
|
+
resultCount: results.length,
|
|
1381
|
+
settledCount,
|
|
1382
|
+
pendingCount,
|
|
1383
|
+
notFoundCount
|
|
1384
|
+
}),
|
|
1387
1385
|
{
|
|
1386
|
+
attempt_count: input.attempts.length,
|
|
1387
|
+
settled_count: settledCount,
|
|
1388
|
+
pending_count: pendingCount,
|
|
1389
|
+
// Zero-valued extras stay off the line; the message already says
|
|
1390
|
+
// what was decided.
|
|
1391
|
+
...notFoundCount === 0 ? {} : { not_found_count: notFoundCount },
|
|
1388
1392
|
// Attempts scanned vs hashes decided: results collapse duplicate
|
|
1389
1393
|
// hashes and omit any the wallet walk could not reach, so a gap
|
|
1390
1394
|
// between these two is how a truncated scan shows up in the log.
|
|
1391
|
-
|
|
1392
|
-
result_count: results.length,
|
|
1393
|
-
settled_count: results.filter((result) => result.status === "settled").length,
|
|
1394
|
-
pending_count: results.filter((result) => result.status === "pending").length,
|
|
1395
|
-
not_found_count: results.filter((result) => result.status === "not_found").length,
|
|
1395
|
+
...results.length === input.attempts.length ? {} : { result_count: results.length },
|
|
1396
1396
|
// All pending attempts share these walks: one creation-time window,
|
|
1397
1397
|
// never one wallet call per invoice.
|
|
1398
|
-
|
|
1399
|
-
...walks[0] === void 0 ? {} : {
|
|
1398
|
+
walks: walks.length,
|
|
1399
|
+
...walks[0] === void 0 ? {} : { window: `${walks[0].from}..${walks[0].until}` }
|
|
1400
1400
|
}
|
|
1401
1401
|
);
|
|
1402
1402
|
return results;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openreceive/node",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"description": "The OpenReceive Node service: receive-only NWC wallet client, checkout and swap service, pricing, and the openreceive CLI.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bitcoin",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"types": "./dist/index.d.ts",
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@getalby/sdk": "^8.0.3",
|
|
20
|
-
"@openreceive/core": "0.4.
|
|
20
|
+
"@openreceive/core": "0.4.5"
|
|
21
21
|
},
|
|
22
22
|
"bin": {
|
|
23
23
|
"openreceive": "./bin/openreceive.mjs"
|