lnlink-server 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +461 -0
- package/{app.js → dist/app.js} +329 -321
- package/dist/binaries.json +25 -0
- package/{build-info.json → dist/build-info.json} +2 -1
- package/{index.js → dist/index.js} +690 -121
- package/dist/index.js.map +7 -0
- package/dist/node_modules/debug/.coveralls.yml +1 -0
- package/dist/node_modules/debug/.eslintrc +11 -0
- package/dist/node_modules/debug/.travis.yml +14 -0
- package/dist/node_modules/debug/CHANGELOG.md +362 -0
- package/dist/node_modules/debug/LICENSE +19 -0
- package/dist/node_modules/debug/Makefile +50 -0
- package/dist/node_modules/debug/README.md +312 -0
- package/dist/node_modules/debug/component.json +19 -0
- package/dist/node_modules/debug/karma.conf.js +70 -0
- package/dist/node_modules/debug/node.js +1 -0
- package/dist/node_modules/debug/package.json +49 -0
- package/dist/node_modules/debug/src/browser.js +185 -0
- package/dist/node_modules/debug/src/debug.js +202 -0
- package/dist/node_modules/debug/src/index.js +10 -0
- package/dist/node_modules/debug/src/inspector-log.js +15 -0
- package/dist/node_modules/debug/src/node.js +248 -0
- package/dist/node_modules/depd/History.md +96 -0
- package/dist/node_modules/depd/LICENSE +22 -0
- package/dist/node_modules/depd/Readme.md +280 -0
- package/dist/node_modules/depd/index.js +522 -0
- package/dist/node_modules/depd/lib/browser/index.js +77 -0
- package/dist/node_modules/depd/lib/compat/callsite-tostring.js +103 -0
- package/dist/node_modules/depd/lib/compat/event-listener-count.js +22 -0
- package/dist/node_modules/depd/lib/compat/index.js +79 -0
- package/dist/node_modules/depd/package.json +41 -0
- package/dist/node_modules/http-errors/HISTORY.md +132 -0
- package/dist/node_modules/http-errors/LICENSE +23 -0
- package/dist/node_modules/http-errors/README.md +135 -0
- package/dist/node_modules/http-errors/index.js +260 -0
- package/dist/node_modules/http-errors/package.json +48 -0
- package/dist/node_modules/inherits/LICENSE +16 -0
- package/dist/node_modules/inherits/README.md +42 -0
- package/dist/node_modules/inherits/inherits.js +7 -0
- package/dist/node_modules/inherits/inherits_browser.js +23 -0
- package/dist/node_modules/inherits/package.json +29 -0
- package/dist/node_modules/ms/index.js +152 -0
- package/dist/node_modules/ms/license.md +21 -0
- package/dist/node_modules/ms/package.json +37 -0
- package/dist/node_modules/ms/readme.md +51 -0
- package/dist/node_modules/setprototypeof/LICENSE +13 -0
- package/dist/node_modules/setprototypeof/README.md +26 -0
- package/dist/node_modules/setprototypeof/index.d.ts +2 -0
- package/dist/node_modules/setprototypeof/index.js +15 -0
- package/dist/node_modules/setprototypeof/package.json +25 -0
- package/dist/node_modules/statuses/HISTORY.md +65 -0
- package/dist/node_modules/statuses/LICENSE +23 -0
- package/dist/node_modules/statuses/README.md +127 -0
- package/dist/node_modules/statuses/codes.json +66 -0
- package/dist/node_modules/statuses/index.js +113 -0
- package/dist/node_modules/statuses/package.json +48 -0
- package/dist/package.json +62 -0
- package/dist/public/css/initOwner.css +705 -0
- package/dist/public/img/logo.svg +1 -0
- package/{public → dist/public}/init.html +5 -5
- package/dist/public/js/init.js +840 -0
- package/{setting.regtest.json → dist/setting.regtest.json} +2 -1
- package/package.json +51 -20
- package/binaries.json +0 -20
- package/index.js.map +0 -7
- package/public/css/initOwner.css +0 -553
- package/public/js/init.js +0 -454
- /package/{config.default.js → dist/config.default.js} +0 -0
- /package/{prisma → dist/prisma}/migrations/20250918020814_/migration.sql +0 -0
- /package/{prisma → dist/prisma}/migrations/20251114105314_auto_update/migration.sql +0 -0
- /package/{prisma → dist/prisma}/migrations/migration_lock.toml +0 -0
- /package/{prisma → dist/prisma}/schema.prisma +0 -0
- /package/{proto → dist/proto}/chainkit.proto +0 -0
- /package/{proto → dist/proto}/lightning.proto +0 -0
- /package/{proto → dist/proto}/lit-status.proto +0 -0
- /package/{proto → dist/proto}/looprpc/client.proto +0 -0
- /package/{proto → dist/proto}/price_oracle.proto +0 -0
- /package/{proto → dist/proto}/rfqrpc/rfq.proto +0 -0
- /package/{proto → dist/proto}/routerrpc/router.proto +0 -0
- /package/{proto → dist/proto}/signrpc/signer.proto +0 -0
- /package/{proto → dist/proto}/stateservice.proto +0 -0
- /package/{proto → dist/proto}/swapserverrpc/common.proto +0 -0
- /package/{proto → dist/proto}/tapchannel.proto +0 -0
- /package/{proto → dist/proto}/tapcommon.proto +0 -0
- /package/{proto → dist/proto}/taprootassets.proto +0 -0
- /package/{proto → dist/proto}/universe.proto +0 -0
- /package/{proto → dist/proto}/walletkit.proto +0 -0
- /package/{proto → dist/proto}/walletunlocker.proto +0 -0
- /package/{public → dist/public}/favicon.ico +0 -0
- /package/{setting.mainnet.json → dist/setting.mainnet.json} +0 -0
- /package/{setting.testnet.json → dist/setting.testnet.json} +0 -0
|
@@ -908,6 +908,7 @@ var require_constants = __commonJS({
|
|
|
908
908
|
"backup_node",
|
|
909
909
|
"restore_node",
|
|
910
910
|
"update_node_name",
|
|
911
|
+
"toggle_tor",
|
|
911
912
|
...READ_ONLY_PERMISSIONS
|
|
912
913
|
];
|
|
913
914
|
var SOCILA_TYPE = {
|
|
@@ -1098,7 +1099,7 @@ var require_nostrEventRepository = __commonJS({
|
|
|
1098
1099
|
}
|
|
1099
1100
|
/**
|
|
1100
1101
|
* Update event status and related fields
|
|
1101
|
-
* @param {number} id - Event ID
|
|
1102
|
+
* @param {number|string} id - Event ID (int) or event_id (string)
|
|
1102
1103
|
* @param {object} updateData - Update data
|
|
1103
1104
|
* @returns {Promise<object>} Updated event
|
|
1104
1105
|
*/
|
|
@@ -1118,6 +1119,13 @@ var require_nostrEventRepository = __commonJS({
|
|
|
1118
1119
|
if (reply_err) {
|
|
1119
1120
|
data.reply_err = reply_err;
|
|
1120
1121
|
}
|
|
1122
|
+
const isStringId = typeof id === "string" && id.length > 10;
|
|
1123
|
+
if (isStringId) {
|
|
1124
|
+
return this.prisma.lnlinkNostrEvent.updateMany({
|
|
1125
|
+
where: { event_id: id },
|
|
1126
|
+
data
|
|
1127
|
+
});
|
|
1128
|
+
}
|
|
1121
1129
|
return this.prisma.lnlinkNostrEvent.update({
|
|
1122
1130
|
where: { id },
|
|
1123
1131
|
data
|
|
@@ -1218,8 +1226,11 @@ var require_events = __commonJS({
|
|
|
1218
1226
|
}, "insertEvent"),
|
|
1219
1227
|
updateEvent: /* @__PURE__ */ __name(async (id, updateData) => {
|
|
1220
1228
|
try {
|
|
1221
|
-
await getNostrEventRepo().updateEvent(id, updateData);
|
|
1222
|
-
|
|
1229
|
+
const result = await getNostrEventRepo().updateEvent(id, updateData);
|
|
1230
|
+
if (result && typeof result.count === "number") {
|
|
1231
|
+
return result.count;
|
|
1232
|
+
}
|
|
1233
|
+
return result ? 1 : 0;
|
|
1223
1234
|
} catch (error) {
|
|
1224
1235
|
console.error("Error updating event:", error);
|
|
1225
1236
|
return 0;
|
|
@@ -2709,7 +2720,8 @@ var require_getConfig = __commonJS({
|
|
|
2709
2720
|
"LINK_DATABASE_URL",
|
|
2710
2721
|
"LINK_REPORT_BASE_URL",
|
|
2711
2722
|
"LINK_REPORT_ADDRESS",
|
|
2712
|
-
"LINK_RGB_HOST"
|
|
2723
|
+
"LINK_RGB_HOST",
|
|
2724
|
+
"LINK_EXTERNAL_NODES"
|
|
2713
2725
|
];
|
|
2714
2726
|
const processConfig = {};
|
|
2715
2727
|
ENV_KEYS.forEach((key) => {
|
|
@@ -5326,6 +5338,7 @@ var require_reportService = __commonJS({
|
|
|
5326
5338
|
// business/service/nodeManage/config.js
|
|
5327
5339
|
var require_config2 = __commonJS({
|
|
5328
5340
|
"business/service/nodeManage/config.js"(exports2, module2) {
|
|
5341
|
+
var path2 = require("node:path");
|
|
5329
5342
|
var { getConfig: getConfig2 } = require_getConfig();
|
|
5330
5343
|
function getBinaryName(baseName) {
|
|
5331
5344
|
const isWindows = process.platform === "win32";
|
|
@@ -5484,18 +5497,18 @@ var require_config2 = __commonJS({
|
|
|
5484
5497
|
const { LINK_BINARY_PATH } = config;
|
|
5485
5498
|
return {
|
|
5486
5499
|
litd: {
|
|
5487
|
-
command:
|
|
5500
|
+
command: path2.join(LINK_BINARY_PATH || "", getBinaryName("litd")),
|
|
5488
5501
|
args: null,
|
|
5489
5502
|
// Generated dynamically
|
|
5490
5503
|
process: null
|
|
5491
5504
|
},
|
|
5492
5505
|
tor: {
|
|
5493
|
-
command:
|
|
5506
|
+
command: path2.join(LINK_BINARY_PATH || "", getBinaryName("tor")),
|
|
5494
5507
|
args: buildTorArgs(),
|
|
5495
5508
|
process: null
|
|
5496
5509
|
},
|
|
5497
5510
|
rgb: {
|
|
5498
|
-
command:
|
|
5511
|
+
command: path2.join(LINK_BINARY_PATH || "", getBinaryName("rgb-lightning-node")),
|
|
5499
5512
|
args: null,
|
|
5500
5513
|
// Generated dynamically
|
|
5501
5514
|
process: null
|
|
@@ -5518,10 +5531,16 @@ var require_processManager = __commonJS({
|
|
|
5518
5531
|
"business/service/nodeManage/processManager.js"(exports2, module2) {
|
|
5519
5532
|
var { spawn, exec } = require("node:child_process");
|
|
5520
5533
|
var { getLightningService } = require_common();
|
|
5534
|
+
var { getConfig: getConfig2 } = require_getConfig();
|
|
5521
5535
|
var Logger = require_linkLogger();
|
|
5522
5536
|
var { sleep } = require_timeUtils();
|
|
5523
5537
|
var { getServiceConfig } = require_config2();
|
|
5524
5538
|
var isWindows = process.platform === "win32";
|
|
5539
|
+
function isExternalNodesMode() {
|
|
5540
|
+
const config = getConfig2();
|
|
5541
|
+
return config.LINK_EXTERNAL_NODES === "true" || config.LINK_EXTERNAL_NODES === true;
|
|
5542
|
+
}
|
|
5543
|
+
__name(isExternalNodesMode, "isExternalNodesMode");
|
|
5525
5544
|
function findProcesses(processName) {
|
|
5526
5545
|
return new Promise((resolve) => {
|
|
5527
5546
|
let command;
|
|
@@ -5601,6 +5620,10 @@ var require_processManager = __commonJS({
|
|
|
5601
5620
|
__name(setServiceProcess, "setServiceProcess");
|
|
5602
5621
|
function startLitdService(args) {
|
|
5603
5622
|
const logger2 = new Logger("processManager");
|
|
5623
|
+
if (isExternalNodesMode()) {
|
|
5624
|
+
logger2.info("External nodes mode: skipping litd local spawn (managed externally)");
|
|
5625
|
+
return Promise.resolve(true);
|
|
5626
|
+
}
|
|
5604
5627
|
return new Promise((resolve, reject) => {
|
|
5605
5628
|
const service = getService("litd");
|
|
5606
5629
|
if (!service) {
|
|
@@ -5652,6 +5675,10 @@ var require_processManager = __commonJS({
|
|
|
5652
5675
|
__name(startLitdService, "startLitdService");
|
|
5653
5676
|
function startTorService(args) {
|
|
5654
5677
|
const logger2 = new Logger("processManager");
|
|
5678
|
+
if (isExternalNodesMode()) {
|
|
5679
|
+
logger2.info("External nodes mode: skipping Tor local spawn (managed externally)");
|
|
5680
|
+
return Promise.resolve(true);
|
|
5681
|
+
}
|
|
5655
5682
|
return new Promise((resolve, reject) => {
|
|
5656
5683
|
const service = getService("tor");
|
|
5657
5684
|
if (!service) {
|
|
@@ -5711,6 +5738,10 @@ var require_processManager = __commonJS({
|
|
|
5711
5738
|
__name(startTorService, "startTorService");
|
|
5712
5739
|
function startRgbService(args) {
|
|
5713
5740
|
const logger2 = new Logger("processManager");
|
|
5741
|
+
if (isExternalNodesMode()) {
|
|
5742
|
+
logger2.info("External nodes mode: skipping RGB local spawn (managed externally)");
|
|
5743
|
+
return Promise.resolve(true);
|
|
5744
|
+
}
|
|
5714
5745
|
return new Promise((resolve, reject) => {
|
|
5715
5746
|
const service = getService("rgb");
|
|
5716
5747
|
if (!service) {
|
|
@@ -5832,8 +5863,12 @@ var require_processManager = __commonJS({
|
|
|
5832
5863
|
}
|
|
5833
5864
|
__name(findAndKillProcess, "findAndKillProcess");
|
|
5834
5865
|
async function stopLitdService() {
|
|
5835
|
-
const initialService = getService("litd");
|
|
5836
5866
|
const logger2 = new Logger("processManager");
|
|
5867
|
+
if (isExternalNodesMode()) {
|
|
5868
|
+
logger2.info("External nodes mode: skipping litd stop (managed externally)");
|
|
5869
|
+
return true;
|
|
5870
|
+
}
|
|
5871
|
+
const initialService = getService("litd");
|
|
5837
5872
|
if (!initialService) {
|
|
5838
5873
|
throw new Error("litd service not found");
|
|
5839
5874
|
}
|
|
@@ -5865,6 +5900,11 @@ var require_processManager = __commonJS({
|
|
|
5865
5900
|
}
|
|
5866
5901
|
__name(stopLitdService, "stopLitdService");
|
|
5867
5902
|
async function stopTorService() {
|
|
5903
|
+
const logger2 = new Logger("processManager");
|
|
5904
|
+
if (isExternalNodesMode()) {
|
|
5905
|
+
logger2.info("External nodes mode: skipping Tor stop (managed externally)");
|
|
5906
|
+
return true;
|
|
5907
|
+
}
|
|
5868
5908
|
const service = getService("tor");
|
|
5869
5909
|
if (!service) {
|
|
5870
5910
|
throw new Error("tor service not found");
|
|
@@ -5878,6 +5918,10 @@ var require_processManager = __commonJS({
|
|
|
5878
5918
|
__name(stopTorService, "stopTorService");
|
|
5879
5919
|
async function stopRgbService() {
|
|
5880
5920
|
const logger2 = new Logger("processManager");
|
|
5921
|
+
if (isExternalNodesMode()) {
|
|
5922
|
+
logger2.info("External nodes mode: skipping RGB stop (managed externally)");
|
|
5923
|
+
return true;
|
|
5924
|
+
}
|
|
5881
5925
|
const service = getService("rgb");
|
|
5882
5926
|
if (!service) {
|
|
5883
5927
|
throw new Error("rgb service not found");
|
|
@@ -5885,15 +5929,27 @@ var require_processManager = __commonJS({
|
|
|
5885
5929
|
try {
|
|
5886
5930
|
logger2.info("Attempting graceful shutdown of RGB via SIGTERM...");
|
|
5887
5931
|
const gracefulShutdown = new Promise((resolve) => {
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
5932
|
+
if (isWindows) {
|
|
5933
|
+
exec(`taskkill /F /IM rgb-lightning-node.exe`, (err, stdout) => {
|
|
5934
|
+
if (!err) {
|
|
5935
|
+
logger2.info(`RGB stopped gracefully: ${stdout}`);
|
|
5936
|
+
resolve(true);
|
|
5937
|
+
} else {
|
|
5938
|
+
logger2.warn(`Graceful shutdown of RGB failed: ${err?.message}`);
|
|
5939
|
+
resolve(false);
|
|
5940
|
+
}
|
|
5941
|
+
});
|
|
5942
|
+
} else {
|
|
5943
|
+
exec(`pkill -SIGTERM -f 'rgb-lightning-node'`, (err, stdout) => {
|
|
5944
|
+
if (!err) {
|
|
5945
|
+
logger2.info(`RGB stopped gracefully: ${stdout}`);
|
|
5946
|
+
resolve(true);
|
|
5947
|
+
} else {
|
|
5948
|
+
logger2.warn(`Graceful shutdown of RGB failed: ${err?.message}`);
|
|
5949
|
+
resolve(false);
|
|
5950
|
+
}
|
|
5951
|
+
});
|
|
5952
|
+
}
|
|
5897
5953
|
});
|
|
5898
5954
|
const gracefulResult = await gracefulShutdown;
|
|
5899
5955
|
if (gracefulResult) {
|
|
@@ -6148,11 +6204,17 @@ var require_statusChecker = __commonJS({
|
|
|
6148
6204
|
"business/service/nodeManage/statusChecker.js"(exports2, module2) {
|
|
6149
6205
|
var findProcess = require("find-process").default;
|
|
6150
6206
|
var { getWalletState } = require_common();
|
|
6207
|
+
var { getConfig: getConfig2 } = require_getConfig();
|
|
6151
6208
|
var { WALLET_STATE_CODE } = require_constants();
|
|
6152
6209
|
var Logger = require_linkLogger();
|
|
6153
6210
|
var { getNodeState } = require_node();
|
|
6154
6211
|
var { getServiceConfig } = require_config2();
|
|
6155
6212
|
var { getServicesState } = require_processManager();
|
|
6213
|
+
function isExternalNodesMode() {
|
|
6214
|
+
const config = getConfig2();
|
|
6215
|
+
return config.LINK_EXTERNAL_NODES === "true" || config.LINK_EXTERNAL_NODES === true;
|
|
6216
|
+
}
|
|
6217
|
+
__name(isExternalNodesMode, "isExternalNodesMode");
|
|
6156
6218
|
var ServiceStatus = {
|
|
6157
6219
|
RUNNING: "Running",
|
|
6158
6220
|
STOPPED: "Stopped"
|
|
@@ -6172,6 +6234,19 @@ var require_statusChecker = __commonJS({
|
|
|
6172
6234
|
async function checkLitdProcess() {
|
|
6173
6235
|
const logger2 = new Logger("statusChecker");
|
|
6174
6236
|
try {
|
|
6237
|
+
if (isExternalNodesMode()) {
|
|
6238
|
+
logger2.info("External nodes mode: checking litd via RPC...");
|
|
6239
|
+
try {
|
|
6240
|
+
const walletState = await getWalletState();
|
|
6241
|
+
if (walletState !== void 0 && walletState !== null) {
|
|
6242
|
+
logger2.info(`Litd is running (wallet state: ${walletState})`);
|
|
6243
|
+
return ServiceStatus.RUNNING;
|
|
6244
|
+
}
|
|
6245
|
+
} catch (rpcError) {
|
|
6246
|
+
logger2.warn(`RPC check failed: ${rpcError.message}`);
|
|
6247
|
+
}
|
|
6248
|
+
return ServiceStatus.STOPPED;
|
|
6249
|
+
}
|
|
6175
6250
|
const processList = await findProcess("name", "litd");
|
|
6176
6251
|
if (processList.length > 0) {
|
|
6177
6252
|
logger2.info(`Found litd process(es): ${processList.map((p) => p.pid).join(", ")}`);
|
|
@@ -6187,6 +6262,19 @@ var require_statusChecker = __commonJS({
|
|
|
6187
6262
|
async function checkRgbProcess() {
|
|
6188
6263
|
const logger2 = new Logger("statusChecker");
|
|
6189
6264
|
try {
|
|
6265
|
+
if (isExternalNodesMode()) {
|
|
6266
|
+
logger2.info("External nodes mode: checking RGB via SDK...");
|
|
6267
|
+
try {
|
|
6268
|
+
const nodeState = await getNodeState();
|
|
6269
|
+
if (nodeState !== void 0 && nodeState !== null) {
|
|
6270
|
+
logger2.info(`RGB is running (node state received)`);
|
|
6271
|
+
return ServiceStatus.RUNNING;
|
|
6272
|
+
}
|
|
6273
|
+
} catch (sdkError) {
|
|
6274
|
+
logger2.warn(`RGB SDK check failed: ${sdkError.message}`);
|
|
6275
|
+
}
|
|
6276
|
+
return ServiceStatus.STOPPED;
|
|
6277
|
+
}
|
|
6190
6278
|
const processList = await findProcess("name", "rgb-lightning-node");
|
|
6191
6279
|
if (processList.length > 0) {
|
|
6192
6280
|
logger2.info(`Found rgb-lightning-node process(es): ${processList.map((p) => p.pid).join(", ")}`);
|
|
@@ -7157,11 +7245,11 @@ var require_accountService = __commonJS({
|
|
|
7157
7245
|
const lnLinkConfig = await getMainLnlinkConfig();
|
|
7158
7246
|
const {
|
|
7159
7247
|
node_npub,
|
|
7160
|
-
settings
|
|
7161
|
-
npub: owner_npub
|
|
7248
|
+
settings
|
|
7162
7249
|
} = lnLinkConfig;
|
|
7163
7250
|
const relay = settings?.nostrRelays ? settings?.nostrRelays?.[0] : null;
|
|
7164
|
-
const
|
|
7251
|
+
const READONLY_SALT = "lnlink_readonly_v1";
|
|
7252
|
+
const sk = stringToFixedBytes(`${node_npub}:${READONLY_SALT}`).toString(
|
|
7165
7253
|
"hex"
|
|
7166
7254
|
);
|
|
7167
7255
|
const pk = getPublicKey(sk);
|
|
@@ -7288,7 +7376,7 @@ var require_package = __commonJS({
|
|
|
7288
7376
|
"package.json"(exports2, module2) {
|
|
7289
7377
|
module2.exports = {
|
|
7290
7378
|
name: "lnlink-server",
|
|
7291
|
-
version: "1.0.
|
|
7379
|
+
version: "1.0.2",
|
|
7292
7380
|
private: false,
|
|
7293
7381
|
main: "dist/index.js",
|
|
7294
7382
|
files: [
|
|
@@ -7297,13 +7385,13 @@ var require_package = __commonJS({
|
|
|
7297
7385
|
],
|
|
7298
7386
|
scripts: {
|
|
7299
7387
|
build: "node build.js && node build.js --mode development --external all --entry electron",
|
|
7300
|
-
"start:bin":
|
|
7388
|
+
"start:bin": "dotenv -e .env.bin -- node scripts/start-bin.js",
|
|
7301
7389
|
"start:docker:dev": "dotenv -e .env.dev -- docker compose -f ./docker-compose.dev.yml up --build",
|
|
7302
7390
|
"start:dev": 'dotenv -e .env.dev -- sh -c "prisma generate && (prisma migrate dev --name auto_update || prisma db push) && clinic heapprof -- node ./app.js"',
|
|
7303
7391
|
"start:regtest": "docker compose --env-file ./.env.regtest -f ./docker-compose-lnlink.yml up --build",
|
|
7304
7392
|
"start:testnet": "docker compose --env-file ./.env.testnet -f ./docker-compose-lnlink.yml up --build",
|
|
7305
7393
|
"start:mainnet": "docker compose --env-file ./.env.mainnet -f ./docker-compose-lnlink.yml up --build",
|
|
7306
|
-
"start:bin:dist":
|
|
7394
|
+
"start:bin:dist": "dotenv -e .env.bin -- node scripts/start-bin.js --dist",
|
|
7307
7395
|
lint: "eslint .",
|
|
7308
7396
|
"lint:fix": "eslint . --fix",
|
|
7309
7397
|
"lint:staged": "lint-staged",
|
|
@@ -7325,6 +7413,7 @@ var require_package = __commonJS({
|
|
|
7325
7413
|
axios: "^1.7.2",
|
|
7326
7414
|
"bitcoin-core": "^4.2.0",
|
|
7327
7415
|
"body-parser": "^1.20.2",
|
|
7416
|
+
bolt11: "^1.4.1",
|
|
7328
7417
|
"cookie-parser": "~1.4.4",
|
|
7329
7418
|
"crypto-js": "^4.2.0",
|
|
7330
7419
|
dayjs: "^1.11.10",
|
|
@@ -8381,8 +8470,49 @@ var require_lndService = __commonJS({
|
|
|
8381
8470
|
return ret;
|
|
8382
8471
|
}
|
|
8383
8472
|
__name(startLink, "startLink");
|
|
8473
|
+
async function toggleTor(args) {
|
|
8474
|
+
const logger2 = new Logger("lnd");
|
|
8475
|
+
const { enable, lnlinkUser } = args;
|
|
8476
|
+
if (enable === void 0 || enable === null) {
|
|
8477
|
+
throw new Error("enable parameter is required (true or false)");
|
|
8478
|
+
}
|
|
8479
|
+
const enableTor = enable === true || enable === "true";
|
|
8480
|
+
logger2.info(`Toggling Tor mode to: ${enableTor}, requested by: ${lnlinkUser?.npub || "unknown"}`);
|
|
8481
|
+
try {
|
|
8482
|
+
const { updateMainLnlinkConfig: updateConfig } = require_dbService();
|
|
8483
|
+
const updateRet = await updateConfig({ enable_tor: enableTor });
|
|
8484
|
+
if (updateRet !== 1) {
|
|
8485
|
+
logger2.warn(`Database update returned: ${updateRet}, proceeding anyway`);
|
|
8486
|
+
}
|
|
8487
|
+
const { reloadConfig } = require_getConfig();
|
|
8488
|
+
await reloadConfig();
|
|
8489
|
+
const { restartTerminal, stopService: stopTor, isServiceRunning: isTorRunning } = require_nodeManage();
|
|
8490
|
+
if (!enableTor) {
|
|
8491
|
+
const torRunning = await isTorRunning("tor");
|
|
8492
|
+
if (torRunning) {
|
|
8493
|
+
logger2.info("Stopping Tor service...");
|
|
8494
|
+
await stopTor("tor");
|
|
8495
|
+
}
|
|
8496
|
+
}
|
|
8497
|
+
logger2.info("Restarting litd with new Tor configuration...");
|
|
8498
|
+
const terminalStatus = await restartTerminal({ lnlinkUser });
|
|
8499
|
+
const nodeInfo = await getNodeInfo();
|
|
8500
|
+
logger2.info(`Tor mode toggled successfully. Tor enabled: ${enableTor}`);
|
|
8501
|
+
return {
|
|
8502
|
+
enable_tor: enableTor,
|
|
8503
|
+
status: "ok",
|
|
8504
|
+
terminal_status: terminalStatus,
|
|
8505
|
+
node_info: nodeInfo
|
|
8506
|
+
};
|
|
8507
|
+
} catch (error) {
|
|
8508
|
+
logger2.error(`Failed to toggle Tor: ${error.message}`);
|
|
8509
|
+
throw error;
|
|
8510
|
+
}
|
|
8511
|
+
}
|
|
8512
|
+
__name(toggleTor, "toggleTor");
|
|
8384
8513
|
module2.exports = {
|
|
8385
8514
|
startLink,
|
|
8515
|
+
toggleTor,
|
|
8386
8516
|
getWalletState,
|
|
8387
8517
|
sendPaymentSync,
|
|
8388
8518
|
createLnInvoice,
|
|
@@ -8457,6 +8587,7 @@ var require_tapdService = __commonJS({
|
|
|
8457
8587
|
} = require_dbService();
|
|
8458
8588
|
var { reportTaskCompletion } = require_reportService();
|
|
8459
8589
|
var TaprootAssetsInstance = require_instance2();
|
|
8590
|
+
var { decode } = require("bolt11");
|
|
8460
8591
|
var syncUniverse = withChecks(async (args) => {
|
|
8461
8592
|
const { LINK_UNIVERSE_HOST } = getConfig2();
|
|
8462
8593
|
const {
|
|
@@ -8941,6 +9072,14 @@ var require_tapdService = __commonJS({
|
|
|
8941
9072
|
if (outgoing_chan_id) {
|
|
8942
9073
|
paymentRequest.outgoing_chan_id = `${outgoing_chan_id}`;
|
|
8943
9074
|
}
|
|
9075
|
+
const decodedInvoice = decode(payment_request);
|
|
9076
|
+
const routingInfo = decodedInvoice.tags.find((tag) => tag.tagName === "routing_info");
|
|
9077
|
+
if (routingInfo && routingInfo.data && routingInfo.data.length > 0) {
|
|
9078
|
+
const lastHop = routingInfo.data[routingInfo.data.length - 1];
|
|
9079
|
+
if (lastHop.pubkey) {
|
|
9080
|
+
paymentRequest.last_hop_pubkey = Buffer2.from(lastHop.pubkey, "hex");
|
|
9081
|
+
}
|
|
9082
|
+
}
|
|
8944
9083
|
const sendParams = {
|
|
8945
9084
|
asset_amount,
|
|
8946
9085
|
asset_id: Buffer2.from(asset_id, "hex"),
|
|
@@ -9227,30 +9366,40 @@ var require_constants2 = __commonJS({
|
|
|
9227
9366
|
"nostr/config/constants.js"(exports2, module2) {
|
|
9228
9367
|
var EVENT_PROCESSING_CONSTANTS = {
|
|
9229
9368
|
// Error handling
|
|
9230
|
-
MAX_CONSECUTIVE_ERRORS:
|
|
9231
|
-
ERROR_BACKOFF_TIME:
|
|
9369
|
+
MAX_CONSECUTIVE_ERRORS: 10,
|
|
9370
|
+
ERROR_BACKOFF_TIME: 2e3,
|
|
9232
9371
|
MAX_FATAL_ERRORS: 10,
|
|
9233
|
-
MAX_BACKOFF_TIME:
|
|
9234
|
-
//
|
|
9235
|
-
// Timeout settings
|
|
9372
|
+
MAX_BACKOFF_TIME: 3e4,
|
|
9373
|
+
// 30 seconds max backoff (reduced from 60s)
|
|
9374
|
+
// Timeout settings - increased for litd/rgb unlock operations (30-50s)
|
|
9236
9375
|
EVENT_PROCESSING_TIMEOUT: 60 * 1e3,
|
|
9237
|
-
// 60 seconds
|
|
9238
|
-
// Concurrent processing settings
|
|
9239
|
-
MAX_CONCURRENT_EVENTS:
|
|
9240
|
-
//
|
|
9241
|
-
CONCURRENT_BATCH_SIZE:
|
|
9242
|
-
//
|
|
9376
|
+
// 60 seconds (to support litd/rgb unlock)
|
|
9377
|
+
// Concurrent processing settings - INCREASED for better throughput
|
|
9378
|
+
MAX_CONCURRENT_EVENTS: 10,
|
|
9379
|
+
// Increased from 3 to 10
|
|
9380
|
+
CONCURRENT_BATCH_SIZE: 15,
|
|
9381
|
+
// Increased from 5 to 15
|
|
9243
9382
|
// Batch processing settings
|
|
9244
|
-
BATCH_SIZE:
|
|
9245
|
-
//
|
|
9246
|
-
|
|
9247
|
-
|
|
9248
|
-
|
|
9249
|
-
|
|
9250
|
-
|
|
9251
|
-
|
|
9252
|
-
|
|
9253
|
-
|
|
9383
|
+
BATCH_SIZE: 10,
|
|
9384
|
+
// Increased from 2 to 10
|
|
9385
|
+
// Sleep intervals - REDUCED for lower latency
|
|
9386
|
+
NORMAL_SLEEP: 50,
|
|
9387
|
+
// Reduced from 300ms to 50ms
|
|
9388
|
+
IDLE_SLEEP: 200,
|
|
9389
|
+
// Reduced from 500ms to 200ms
|
|
9390
|
+
ERROR_SLEEP: 500,
|
|
9391
|
+
// Reduced from 1000ms
|
|
9392
|
+
FATAL_ERROR_SLEEP: 2e3,
|
|
9393
|
+
// Reduced from 3000ms
|
|
9394
|
+
// Rate limiting - INCREASED throughput
|
|
9395
|
+
RATE_LIMIT_REQUESTS: 10,
|
|
9396
|
+
// Increased from 2 to 10 requests
|
|
9397
|
+
RATE_LIMIT_WINDOW: 1e3,
|
|
9398
|
+
// Per second
|
|
9399
|
+
// Memory queue settings
|
|
9400
|
+
MEMORY_QUEUE_MAX_SIZE: 1e3,
|
|
9401
|
+
DB_RECOVERY_INTERVAL: 5e3
|
|
9402
|
+
// Check DB for missed events every 5s
|
|
9254
9403
|
};
|
|
9255
9404
|
var CONNECTION_CONSTANTS = {
|
|
9256
9405
|
MAX_RECONNECT_ATTEMPTS: 100,
|
|
@@ -11318,42 +11467,42 @@ var require_info = __commonJS({
|
|
|
11318
11467
|
let stateValue = null;
|
|
11319
11468
|
if (serviceRunning) {
|
|
11320
11469
|
const rgbClient = getRgbClient();
|
|
11321
|
-
const
|
|
11322
|
-
|
|
11323
|
-
|
|
11324
|
-
|
|
11325
|
-
|
|
11326
|
-
|
|
11327
|
-
|
|
11328
|
-
|
|
11329
|
-
|
|
11330
|
-
|
|
11331
|
-
|
|
11332
|
-
|
|
11333
|
-
|
|
11334
|
-
|
|
11335
|
-
|
|
11336
|
-
|
|
11337
|
-
|
|
11338
|
-
|
|
11339
|
-
|
|
11340
|
-
|
|
11341
|
-
|
|
11342
|
-
|
|
11343
|
-
|
|
11344
|
-
|
|
11345
|
-
|
|
11346
|
-
|
|
11347
|
-
|
|
11348
|
-
|
|
11349
|
-
|
|
11350
|
-
|
|
11351
|
-
|
|
11352
|
-
|
|
11470
|
+
const stateResult = await getNodeState().catch((error) => {
|
|
11471
|
+
logger2.warn(`getCombinedNodeInfo - getNodeState failed: ${error.message}`);
|
|
11472
|
+
return { state: 0 };
|
|
11473
|
+
});
|
|
11474
|
+
stateValue = stateResult?.state ?? null;
|
|
11475
|
+
if (stateValue === 4) {
|
|
11476
|
+
const [
|
|
11477
|
+
nodeInfoResult,
|
|
11478
|
+
balanceResult,
|
|
11479
|
+
peersResult
|
|
11480
|
+
] = await Promise.allSettled([
|
|
11481
|
+
rgbClient.node.getNodeInfo(),
|
|
11482
|
+
rgbClient.onchain.getBtcBalance({
|
|
11483
|
+
skip_sync: false
|
|
11484
|
+
}),
|
|
11485
|
+
rgbClient.lightning.listPeers({})
|
|
11486
|
+
]);
|
|
11487
|
+
if (nodeInfoResult.status === "fulfilled") {
|
|
11488
|
+
nodeInfo = nodeInfoResult.value;
|
|
11489
|
+
} else {
|
|
11490
|
+
logger2.warn(`getCombinedNodeInfo - getNodeInfo failed: ${nodeInfoResult.reason?.message || nodeInfoResult.reason}`);
|
|
11491
|
+
}
|
|
11492
|
+
if (balanceResult.status === "fulfilled") {
|
|
11493
|
+
balance = balanceResult.value;
|
|
11494
|
+
} else {
|
|
11495
|
+
logger2.warn(`getCombinedNodeInfo - getBtcBalance failed: ${balanceResult.reason?.message || balanceResult.reason}`);
|
|
11496
|
+
}
|
|
11497
|
+
if (peersResult.status === "fulfilled") {
|
|
11498
|
+
peers = peersResult.value?.peers ?? [];
|
|
11499
|
+
} else {
|
|
11500
|
+
logger2.warn(`getCombinedNodeInfo - listPeers failed: ${peersResult.reason?.message || peersResult.reason}`);
|
|
11501
|
+
}
|
|
11502
|
+
rgbClient.rgb.refreshTransfers({ skip_sync: false }).catch((error) => {
|
|
11503
|
+
logger2.warn(`getCombinedNodeInfo - refreshTransfers failed: ${error.message}`);
|
|
11504
|
+
});
|
|
11353
11505
|
}
|
|
11354
|
-
rgbClient.rgb.refreshTransfers({ skip_sync: false }).catch((error) => {
|
|
11355
|
-
logger2.warn(`getCombinedNodeInfo - refreshTransfers failed: ${error.message}`);
|
|
11356
|
-
});
|
|
11357
11506
|
}
|
|
11358
11507
|
const readOnlyAccount = await getLnlinkUser({
|
|
11359
11508
|
account_type: ACCOUNT_TYPE.READ_ONLY
|
|
@@ -13013,7 +13162,7 @@ var require_eventProcessor = __commonJS({
|
|
|
13013
13162
|
__name(parseAndExecute, "parseAndExecute");
|
|
13014
13163
|
async function parseEvent(event, sk) {
|
|
13015
13164
|
const content = event.content;
|
|
13016
|
-
const subFrom = event.from;
|
|
13165
|
+
const subFrom = event.from || event.pubkey;
|
|
13017
13166
|
const decryptContent = await nip04.decrypt(sk, subFrom, content);
|
|
13018
13167
|
if (event.kind === NWC_CONSTANTS.REQUEST_KIND) {
|
|
13019
13168
|
await handleNWCRequest(event, sk, subFrom, decryptContent);
|
|
@@ -13062,21 +13211,25 @@ var require_eventProcessor = __commonJS({
|
|
|
13062
13211
|
replyEventId: event.event_id,
|
|
13063
13212
|
kind: NWC_CONSTANTS.RESPONSE_KIND
|
|
13064
13213
|
});
|
|
13065
|
-
|
|
13066
|
-
|
|
13067
|
-
|
|
13068
|
-
|
|
13069
|
-
|
|
13070
|
-
|
|
13214
|
+
if (typeof event.id === "number") {
|
|
13215
|
+
const updateId = event.event_id || event.id;
|
|
13216
|
+
const updateSuccess = await safeUpdateEvent(updateId, {
|
|
13217
|
+
status: EVENT_HANDLE_STATUS.SUCCESS,
|
|
13218
|
+
reply_event_id: replyEvent.id
|
|
13219
|
+
});
|
|
13220
|
+
if (!updateSuccess) {
|
|
13221
|
+
const logger2 = new Logger("nostr-events");
|
|
13222
|
+
logger2.warn(`Failed to update event ${updateId} status, possibly not in DB yet`);
|
|
13223
|
+
}
|
|
13071
13224
|
}
|
|
13072
13225
|
}
|
|
13073
13226
|
__name(handleNWCRequest, "handleNWCRequest");
|
|
13074
13227
|
async function handleDirectMessage(event, sk, subFrom, decryptContent) {
|
|
13075
|
-
const tags = JSON.parse(event.tags);
|
|
13228
|
+
const tags = typeof event.tags === "string" ? JSON.parse(event.tags) : event.tags;
|
|
13076
13229
|
const replyProxyAddr = tags?.find((item) => item?.[0] === "a")?.[1];
|
|
13077
13230
|
const replyTo = replyProxyAddr || subFrom;
|
|
13078
13231
|
const content = decryptContent;
|
|
13079
|
-
const retMsg = await parseAndExecute(content, subFrom, event.event_id);
|
|
13232
|
+
const retMsg = await parseAndExecute(content, subFrom, event.event_id || event.id);
|
|
13080
13233
|
if (retMsg) {
|
|
13081
13234
|
const replyEvent = await execSendMessage({
|
|
13082
13235
|
message: retMsg,
|
|
@@ -13084,12 +13237,16 @@ var require_eventProcessor = __commonJS({
|
|
|
13084
13237
|
robotPrivatekey: sk,
|
|
13085
13238
|
replyEventId: event.event_id
|
|
13086
13239
|
});
|
|
13087
|
-
|
|
13088
|
-
|
|
13089
|
-
|
|
13090
|
-
|
|
13091
|
-
|
|
13092
|
-
|
|
13240
|
+
if (typeof event.id === "number") {
|
|
13241
|
+
const updateId = event.event_id || event.id;
|
|
13242
|
+
const updateSuccess = await safeUpdateEvent(updateId, {
|
|
13243
|
+
status: EVENT_HANDLE_STATUS.SUCCESS,
|
|
13244
|
+
reply_event_id: replyEvent.id
|
|
13245
|
+
});
|
|
13246
|
+
if (!updateSuccess) {
|
|
13247
|
+
const logger2 = new Logger("nostr-events");
|
|
13248
|
+
logger2.warn(`Failed to update event ${updateId} status, possibly not in DB yet`);
|
|
13249
|
+
}
|
|
13093
13250
|
}
|
|
13094
13251
|
}
|
|
13095
13252
|
}
|
|
@@ -13129,28 +13286,33 @@ var require_eventProcessor = __commonJS({
|
|
|
13129
13286
|
}
|
|
13130
13287
|
__name(safeUpdateEvent, "safeUpdateEvent");
|
|
13131
13288
|
async function processSingleEvent(event, sk) {
|
|
13132
|
-
const eventId = event.id;
|
|
13289
|
+
const eventId = event.event_id || event.id;
|
|
13133
13290
|
const logger2 = new Logger("nostr-events");
|
|
13291
|
+
const isFromMemoryQueue = !event.isRecovery && typeof event.id === "number";
|
|
13134
13292
|
try {
|
|
13135
|
-
|
|
13136
|
-
|
|
13137
|
-
|
|
13138
|
-
|
|
13139
|
-
|
|
13140
|
-
|
|
13293
|
+
if (!isFromMemoryQueue && typeof event.id === "number") {
|
|
13294
|
+
const claimed = await safeUpdateEvent(eventId, {
|
|
13295
|
+
status: EVENT_HANDLE_STATUS.REPLYING
|
|
13296
|
+
});
|
|
13297
|
+
if (!claimed) {
|
|
13298
|
+
logger2.debug(`Event ${eventId} could not be claimed, possibly already processing`);
|
|
13299
|
+
return false;
|
|
13300
|
+
}
|
|
13301
|
+
logger2.debug(`Successfully claimed event ${eventId} for processing`);
|
|
13141
13302
|
}
|
|
13142
|
-
logger2.debug(`Successfully claimed event ${eventId} for processing`);
|
|
13143
13303
|
await parseEvent(event, sk);
|
|
13144
13304
|
return true;
|
|
13145
13305
|
} catch (e) {
|
|
13146
13306
|
logger2.error(`Error processing event ${eventId}: ${e.message}`);
|
|
13147
|
-
|
|
13148
|
-
|
|
13149
|
-
|
|
13150
|
-
|
|
13151
|
-
|
|
13152
|
-
|
|
13153
|
-
|
|
13307
|
+
if (!isFromMemoryQueue && typeof event.id === "number") {
|
|
13308
|
+
try {
|
|
13309
|
+
await safeUpdateEvent(eventId, {
|
|
13310
|
+
status: EVENT_HANDLE_STATUS.ERROR,
|
|
13311
|
+
reply_err: e.message
|
|
13312
|
+
});
|
|
13313
|
+
} catch (updateError) {
|
|
13314
|
+
logger2.error(`Failed to update event ${eventId} status to error: ${updateError.message}`);
|
|
13315
|
+
}
|
|
13154
13316
|
}
|
|
13155
13317
|
return false;
|
|
13156
13318
|
}
|
|
@@ -13244,7 +13406,7 @@ var require_eventLoop = __commonJS({
|
|
|
13244
13406
|
this.recordError();
|
|
13245
13407
|
if (error.message.includes("timeout")) {
|
|
13246
13408
|
try {
|
|
13247
|
-
await updateEvent(event.id, {
|
|
13409
|
+
await updateEvent(event.event_id || event.id, {
|
|
13248
13410
|
status: EVENT_HANDLE_STATUS.ERROR,
|
|
13249
13411
|
reply_err: error.message
|
|
13250
13412
|
});
|
|
@@ -13347,7 +13509,10 @@ var require_eventLoop = __commonJS({
|
|
|
13347
13509
|
}
|
|
13348
13510
|
};
|
|
13349
13511
|
async function intervalParseEvent(stopSignal = { stop: false }) {
|
|
13350
|
-
const rateLimiter = new RateLimiter(
|
|
13512
|
+
const rateLimiter = new RateLimiter(
|
|
13513
|
+
EVENT_PROCESSING_CONSTANTS.RATE_LIMIT_REQUESTS || 10,
|
|
13514
|
+
EVENT_PROCESSING_CONSTANTS.RATE_LIMIT_WINDOW || 1e3
|
|
13515
|
+
);
|
|
13351
13516
|
const processor = new ConcurrentEventProcessor(
|
|
13352
13517
|
EVENT_PROCESSING_CONSTANTS.MAX_CONCURRENT_EVENTS,
|
|
13353
13518
|
rateLimiter
|
|
@@ -13436,6 +13601,396 @@ var require_eventLoop = __commonJS({
|
|
|
13436
13601
|
}
|
|
13437
13602
|
});
|
|
13438
13603
|
|
|
13604
|
+
// nostr/events/eventQueue.js
|
|
13605
|
+
var require_eventQueue = __commonJS({
|
|
13606
|
+
"nostr/events/eventQueue.js"(exports2, module2) {
|
|
13607
|
+
var { EventEmitter: EventEmitter2 } = require("node:events");
|
|
13608
|
+
var Logger = require_linkLogger();
|
|
13609
|
+
var PRIORITY = {
|
|
13610
|
+
HIGH: 1,
|
|
13611
|
+
// NWC requests (23194) - user payments
|
|
13612
|
+
NORMAL: 2,
|
|
13613
|
+
// Direct messages (4) - user commands
|
|
13614
|
+
LOW: 3
|
|
13615
|
+
// Other events
|
|
13616
|
+
};
|
|
13617
|
+
function getPriorityForKind(kind) {
|
|
13618
|
+
switch (kind) {
|
|
13619
|
+
case 23194:
|
|
13620
|
+
return PRIORITY.HIGH;
|
|
13621
|
+
case 4:
|
|
13622
|
+
return PRIORITY.NORMAL;
|
|
13623
|
+
default:
|
|
13624
|
+
return PRIORITY.LOW;
|
|
13625
|
+
}
|
|
13626
|
+
}
|
|
13627
|
+
__name(getPriorityForKind, "getPriorityForKind");
|
|
13628
|
+
var EventQueue = class extends EventEmitter2 {
|
|
13629
|
+
static {
|
|
13630
|
+
__name(this, "EventQueue");
|
|
13631
|
+
}
|
|
13632
|
+
constructor(options = {}) {
|
|
13633
|
+
super();
|
|
13634
|
+
this.maxSize = options.maxSize || 1e3;
|
|
13635
|
+
this.highPriorityQueue = [];
|
|
13636
|
+
this.normalPriorityQueue = [];
|
|
13637
|
+
this.lowPriorityQueue = [];
|
|
13638
|
+
this.processingSet = /* @__PURE__ */ new Set();
|
|
13639
|
+
this.logger = new Logger("event-queue");
|
|
13640
|
+
this.stats = {
|
|
13641
|
+
enqueued: 0,
|
|
13642
|
+
processed: 0,
|
|
13643
|
+
dropped: 0,
|
|
13644
|
+
duplicates: 0
|
|
13645
|
+
};
|
|
13646
|
+
}
|
|
13647
|
+
/**
|
|
13648
|
+
* Get total queue size
|
|
13649
|
+
*/
|
|
13650
|
+
get size() {
|
|
13651
|
+
return this.highPriorityQueue.length + this.normalPriorityQueue.length + this.lowPriorityQueue.length;
|
|
13652
|
+
}
|
|
13653
|
+
/**
|
|
13654
|
+
* Check if event is already in queue or being processed
|
|
13655
|
+
* @param {string} eventId - Event ID
|
|
13656
|
+
*/
|
|
13657
|
+
has(eventId) {
|
|
13658
|
+
if (this.processingSet.has(eventId)) {
|
|
13659
|
+
return true;
|
|
13660
|
+
}
|
|
13661
|
+
return this.highPriorityQueue.some((e) => e.id === eventId) || this.normalPriorityQueue.some((e) => e.id === eventId) || this.lowPriorityQueue.some((e) => e.id === eventId);
|
|
13662
|
+
}
|
|
13663
|
+
/**
|
|
13664
|
+
* Add event to queue
|
|
13665
|
+
* @param {object} event - Event object with id, kind, content, etc.
|
|
13666
|
+
* @param {object} options - Additional options
|
|
13667
|
+
* @returns {boolean} Whether event was added
|
|
13668
|
+
*/
|
|
13669
|
+
enqueue(event, options = {}) {
|
|
13670
|
+
const eventId = event.id || event.event_id;
|
|
13671
|
+
if (this.has(eventId)) {
|
|
13672
|
+
this.stats.duplicates++;
|
|
13673
|
+
return false;
|
|
13674
|
+
}
|
|
13675
|
+
if (this.size >= this.maxSize) {
|
|
13676
|
+
if (this.lowPriorityQueue.length > 0) {
|
|
13677
|
+
const dropped = this.lowPriorityQueue.shift();
|
|
13678
|
+
this.logger.warn(`Queue full, dropping low priority event: ${dropped.id}`);
|
|
13679
|
+
this.stats.dropped++;
|
|
13680
|
+
} else if (this.normalPriorityQueue.length > 0) {
|
|
13681
|
+
const dropped = this.normalPriorityQueue.shift();
|
|
13682
|
+
this.logger.warn(`Queue full, dropping normal priority event: ${dropped.id}`);
|
|
13683
|
+
this.stats.dropped++;
|
|
13684
|
+
} else {
|
|
13685
|
+
this.logger.error(`Queue full with only high priority events, dropping new event: ${eventId}`);
|
|
13686
|
+
this.stats.dropped++;
|
|
13687
|
+
return false;
|
|
13688
|
+
}
|
|
13689
|
+
}
|
|
13690
|
+
const priority = options.priority || getPriorityForKind(event.kind);
|
|
13691
|
+
const queueItem = {
|
|
13692
|
+
...event,
|
|
13693
|
+
id: eventId,
|
|
13694
|
+
enqueuedAt: Date.now(),
|
|
13695
|
+
priority,
|
|
13696
|
+
...options
|
|
13697
|
+
};
|
|
13698
|
+
switch (priority) {
|
|
13699
|
+
case PRIORITY.HIGH:
|
|
13700
|
+
this.highPriorityQueue.push(queueItem);
|
|
13701
|
+
break;
|
|
13702
|
+
case PRIORITY.NORMAL:
|
|
13703
|
+
this.normalPriorityQueue.push(queueItem);
|
|
13704
|
+
break;
|
|
13705
|
+
default:
|
|
13706
|
+
this.lowPriorityQueue.push(queueItem);
|
|
13707
|
+
}
|
|
13708
|
+
this.stats.enqueued++;
|
|
13709
|
+
this.emit("enqueue", queueItem);
|
|
13710
|
+
return true;
|
|
13711
|
+
}
|
|
13712
|
+
/**
|
|
13713
|
+
* Get next event to process (respects priority)
|
|
13714
|
+
* @returns {object|null} Next event or null if empty
|
|
13715
|
+
*/
|
|
13716
|
+
dequeue() {
|
|
13717
|
+
let event = null;
|
|
13718
|
+
if (this.highPriorityQueue.length > 0) {
|
|
13719
|
+
event = this.highPriorityQueue.shift();
|
|
13720
|
+
} else if (this.normalPriorityQueue.length > 0) {
|
|
13721
|
+
event = this.normalPriorityQueue.shift();
|
|
13722
|
+
} else if (this.lowPriorityQueue.length > 0) {
|
|
13723
|
+
event = this.lowPriorityQueue.shift();
|
|
13724
|
+
}
|
|
13725
|
+
if (event) {
|
|
13726
|
+
this.processingSet.add(event.id);
|
|
13727
|
+
}
|
|
13728
|
+
return event;
|
|
13729
|
+
}
|
|
13730
|
+
/**
|
|
13731
|
+
* Mark event as done processing
|
|
13732
|
+
* @param {string} eventId - Event ID
|
|
13733
|
+
*/
|
|
13734
|
+
markDone(eventId) {
|
|
13735
|
+
this.processingSet.delete(eventId);
|
|
13736
|
+
this.stats.processed++;
|
|
13737
|
+
}
|
|
13738
|
+
/**
|
|
13739
|
+
* Get multiple events at once
|
|
13740
|
+
* @param {number} count - Number of events to get
|
|
13741
|
+
* @returns {Array} Array of events
|
|
13742
|
+
*/
|
|
13743
|
+
dequeueBatch(count) {
|
|
13744
|
+
const events = [];
|
|
13745
|
+
for (let i = 0; i < count; i++) {
|
|
13746
|
+
const event = this.dequeue();
|
|
13747
|
+
if (!event)
|
|
13748
|
+
break;
|
|
13749
|
+
events.push(event);
|
|
13750
|
+
}
|
|
13751
|
+
return events;
|
|
13752
|
+
}
|
|
13753
|
+
/**
|
|
13754
|
+
* Get queue statistics
|
|
13755
|
+
* @returns {object} Queue statistics object
|
|
13756
|
+
*/
|
|
13757
|
+
getStats() {
|
|
13758
|
+
return {
|
|
13759
|
+
...this.stats,
|
|
13760
|
+
currentSize: this.size,
|
|
13761
|
+
highPriority: this.highPriorityQueue.length,
|
|
13762
|
+
normalPriority: this.normalPriorityQueue.length,
|
|
13763
|
+
lowPriority: this.lowPriorityQueue.length,
|
|
13764
|
+
processing: this.processingSet.size
|
|
13765
|
+
};
|
|
13766
|
+
}
|
|
13767
|
+
/**
|
|
13768
|
+
* Clear all queues
|
|
13769
|
+
*/
|
|
13770
|
+
clear() {
|
|
13771
|
+
this.highPriorityQueue = [];
|
|
13772
|
+
this.normalPriorityQueue = [];
|
|
13773
|
+
this.lowPriorityQueue = [];
|
|
13774
|
+
this.processingSet.clear();
|
|
13775
|
+
}
|
|
13776
|
+
};
|
|
13777
|
+
var queueInstance = null;
|
|
13778
|
+
function getEventQueue() {
|
|
13779
|
+
if (!queueInstance) {
|
|
13780
|
+
queueInstance = new EventQueue({ maxSize: 1e3 });
|
|
13781
|
+
}
|
|
13782
|
+
return queueInstance;
|
|
13783
|
+
}
|
|
13784
|
+
__name(getEventQueue, "getEventQueue");
|
|
13785
|
+
module2.exports = {
|
|
13786
|
+
EventQueue,
|
|
13787
|
+
getEventQueue,
|
|
13788
|
+
PRIORITY,
|
|
13789
|
+
getPriorityForKind
|
|
13790
|
+
};
|
|
13791
|
+
}
|
|
13792
|
+
});
|
|
13793
|
+
|
|
13794
|
+
// nostr/events/immediateProcessor.js
|
|
13795
|
+
var require_immediateProcessor = __commonJS({
|
|
13796
|
+
"nostr/events/immediateProcessor.js"(exports2, module2) {
|
|
13797
|
+
var { EventEmitter: EventEmitter2 } = require("node:events");
|
|
13798
|
+
var {
|
|
13799
|
+
updateEvent,
|
|
13800
|
+
getUnReplyEvents
|
|
13801
|
+
} = require_dbService();
|
|
13802
|
+
var { sleep } = require_utils2();
|
|
13803
|
+
var Logger = require_linkLogger();
|
|
13804
|
+
var { EVENT_HANDLE_STATUS } = require_constants();
|
|
13805
|
+
var { EVENT_PROCESSING_CONSTANTS } = require_constants2();
|
|
13806
|
+
var { processSingleEvent } = require_eventProcessor();
|
|
13807
|
+
var { getEventQueue, PRIORITY } = require_eventQueue();
|
|
13808
|
+
var ImmediateProcessor = class extends EventEmitter2 {
|
|
13809
|
+
static {
|
|
13810
|
+
__name(this, "ImmediateProcessor");
|
|
13811
|
+
}
|
|
13812
|
+
constructor(options = {}) {
|
|
13813
|
+
super();
|
|
13814
|
+
this.maxWorkers = options.maxWorkers || EVENT_PROCESSING_CONSTANTS.MAX_CONCURRENT_EVENTS;
|
|
13815
|
+
this.activeWorkers = 0;
|
|
13816
|
+
this.isRunning = false;
|
|
13817
|
+
this.queue = getEventQueue();
|
|
13818
|
+
this.logger = new Logger("immediate-processor");
|
|
13819
|
+
this.sk = null;
|
|
13820
|
+
this.stats = {
|
|
13821
|
+
processed: 0,
|
|
13822
|
+
succeeded: 0,
|
|
13823
|
+
failed: 0,
|
|
13824
|
+
timeouts: 0
|
|
13825
|
+
};
|
|
13826
|
+
this.processingMap = /* @__PURE__ */ new Map();
|
|
13827
|
+
}
|
|
13828
|
+
/**
|
|
13829
|
+
* Start the processor
|
|
13830
|
+
* @param {string} sk - Private key for signing responses
|
|
13831
|
+
*/
|
|
13832
|
+
start(sk) {
|
|
13833
|
+
if (this.isRunning) {
|
|
13834
|
+
this.logger.warn("Processor already running");
|
|
13835
|
+
return;
|
|
13836
|
+
}
|
|
13837
|
+
this.sk = sk;
|
|
13838
|
+
this.isRunning = true;
|
|
13839
|
+
this.logger.info(`ImmediateProcessor started with ${this.maxWorkers} workers`);
|
|
13840
|
+
this.queue.on("enqueue", () => this.tryProcessNext());
|
|
13841
|
+
this.startDBRecoveryLoop();
|
|
13842
|
+
}
|
|
13843
|
+
/**
|
|
13844
|
+
* Stop the processor
|
|
13845
|
+
*/
|
|
13846
|
+
async stop() {
|
|
13847
|
+
this.isRunning = false;
|
|
13848
|
+
this.queue.removeAllListeners("enqueue");
|
|
13849
|
+
const timeout = 3e4;
|
|
13850
|
+
const startTime = Date.now();
|
|
13851
|
+
while (this.activeWorkers > 0 && Date.now() - startTime < timeout) {
|
|
13852
|
+
this.logger.info(`Waiting for ${this.activeWorkers} workers to complete...`);
|
|
13853
|
+
await sleep(1e3);
|
|
13854
|
+
}
|
|
13855
|
+
if (this.activeWorkers > 0) {
|
|
13856
|
+
this.logger.warn(`Timeout waiting for ${this.activeWorkers} workers`);
|
|
13857
|
+
}
|
|
13858
|
+
this.logger.info("ImmediateProcessor stopped");
|
|
13859
|
+
}
|
|
13860
|
+
/**
|
|
13861
|
+
* Try to start processing next event if workers available
|
|
13862
|
+
*/
|
|
13863
|
+
tryProcessNext() {
|
|
13864
|
+
if (!this.isRunning) {
|
|
13865
|
+
return;
|
|
13866
|
+
}
|
|
13867
|
+
while (this.activeWorkers < this.maxWorkers && this.queue.size > 0) {
|
|
13868
|
+
const event = this.queue.dequeue();
|
|
13869
|
+
if (event) {
|
|
13870
|
+
this.processEvent(event);
|
|
13871
|
+
} else {
|
|
13872
|
+
break;
|
|
13873
|
+
}
|
|
13874
|
+
}
|
|
13875
|
+
}
|
|
13876
|
+
/**
|
|
13877
|
+
* Process a single event
|
|
13878
|
+
* @param {object} event - Event to process
|
|
13879
|
+
*/
|
|
13880
|
+
async processEvent(event) {
|
|
13881
|
+
this.activeWorkers++;
|
|
13882
|
+
const eventId = event.id || event.event_id;
|
|
13883
|
+
const startTime = Date.now();
|
|
13884
|
+
this.processingMap.set(eventId, startTime);
|
|
13885
|
+
this.logger.debug(`Processing event ${eventId} (workers: ${this.activeWorkers}/${this.maxWorkers})`);
|
|
13886
|
+
try {
|
|
13887
|
+
let timeoutId;
|
|
13888
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
13889
|
+
timeoutId = setTimeout(
|
|
13890
|
+
() => reject(new Error("Event processing timeout")),
|
|
13891
|
+
EVENT_PROCESSING_CONSTANTS.EVENT_PROCESSING_TIMEOUT
|
|
13892
|
+
);
|
|
13893
|
+
});
|
|
13894
|
+
try {
|
|
13895
|
+
await Promise.race([
|
|
13896
|
+
processSingleEvent(event, this.sk),
|
|
13897
|
+
timeoutPromise
|
|
13898
|
+
]);
|
|
13899
|
+
this.stats.succeeded++;
|
|
13900
|
+
this.logger.debug(`Event ${eventId} processed in ${Date.now() - startTime}ms`);
|
|
13901
|
+
} finally {
|
|
13902
|
+
clearTimeout(timeoutId);
|
|
13903
|
+
}
|
|
13904
|
+
} catch (error) {
|
|
13905
|
+
this.stats.failed++;
|
|
13906
|
+
this.logger.error(`Failed to process event ${eventId}: ${error.message}`);
|
|
13907
|
+
if (error.message.includes("timeout")) {
|
|
13908
|
+
this.stats.timeouts++;
|
|
13909
|
+
try {
|
|
13910
|
+
await updateEvent(event.id, {
|
|
13911
|
+
status: EVENT_HANDLE_STATUS.ERROR,
|
|
13912
|
+
reply_err: error.message
|
|
13913
|
+
});
|
|
13914
|
+
} catch (updateError) {
|
|
13915
|
+
this.logger.error(`Failed to update event status: ${updateError.message}`);
|
|
13916
|
+
}
|
|
13917
|
+
}
|
|
13918
|
+
} finally {
|
|
13919
|
+
this.stats.processed++;
|
|
13920
|
+
this.processingMap.delete(eventId);
|
|
13921
|
+
this.queue.markDone(eventId);
|
|
13922
|
+
this.activeWorkers--;
|
|
13923
|
+
this.tryProcessNext();
|
|
13924
|
+
}
|
|
13925
|
+
}
|
|
13926
|
+
/**
|
|
13927
|
+
* Add event directly (called from connection manager)
|
|
13928
|
+
* @param {object} event - Raw nostr event
|
|
13929
|
+
* @param {object} options - Additional options
|
|
13930
|
+
* @returns {boolean} Whether event was added
|
|
13931
|
+
*/
|
|
13932
|
+
addEvent(event, options = {}) {
|
|
13933
|
+
return this.queue.enqueue(event, options);
|
|
13934
|
+
}
|
|
13935
|
+
/**
|
|
13936
|
+
* Start DB recovery loop to catch missed events
|
|
13937
|
+
*/
|
|
13938
|
+
startDBRecoveryLoop() {
|
|
13939
|
+
const recoveryLoop = /* @__PURE__ */ __name(async () => {
|
|
13940
|
+
while (this.isRunning) {
|
|
13941
|
+
try {
|
|
13942
|
+
if (this.queue.size < EVENT_PROCESSING_CONSTANTS.MEMORY_QUEUE_MAX_SIZE / 2) {
|
|
13943
|
+
const missedEvents = await getUnReplyEvents(
|
|
13944
|
+
EVENT_PROCESSING_CONSTANTS.BATCH_SIZE
|
|
13945
|
+
);
|
|
13946
|
+
for (const event of missedEvents) {
|
|
13947
|
+
this.queue.enqueue(event, { priority: PRIORITY.LOW, isRecovery: true });
|
|
13948
|
+
}
|
|
13949
|
+
if (missedEvents.length > 0) {
|
|
13950
|
+
this.logger.debug(`Recovered ${missedEvents.length} events from DB`);
|
|
13951
|
+
this.tryProcessNext();
|
|
13952
|
+
}
|
|
13953
|
+
}
|
|
13954
|
+
} catch (error) {
|
|
13955
|
+
this.logger.error(`DB recovery error: ${error.message}`);
|
|
13956
|
+
}
|
|
13957
|
+
await sleep(EVENT_PROCESSING_CONSTANTS.DB_RECOVERY_INTERVAL);
|
|
13958
|
+
}
|
|
13959
|
+
}, "recoveryLoop");
|
|
13960
|
+
recoveryLoop();
|
|
13961
|
+
}
|
|
13962
|
+
/**
|
|
13963
|
+
* Get processor statistics
|
|
13964
|
+
* @returns {object} Statistics object
|
|
13965
|
+
*/
|
|
13966
|
+
getStats() {
|
|
13967
|
+
return {
|
|
13968
|
+
...this.stats,
|
|
13969
|
+
activeWorkers: this.activeWorkers,
|
|
13970
|
+
maxWorkers: this.maxWorkers,
|
|
13971
|
+
queueStats: this.queue.getStats(),
|
|
13972
|
+
processing: Array.from(this.processingMap.entries()).map(([id, time]) => ({
|
|
13973
|
+
id,
|
|
13974
|
+
duration: Date.now() - time
|
|
13975
|
+
}))
|
|
13976
|
+
};
|
|
13977
|
+
}
|
|
13978
|
+
};
|
|
13979
|
+
var processorInstance = null;
|
|
13980
|
+
function getImmediateProcessor() {
|
|
13981
|
+
if (!processorInstance) {
|
|
13982
|
+
processorInstance = new ImmediateProcessor();
|
|
13983
|
+
}
|
|
13984
|
+
return processorInstance;
|
|
13985
|
+
}
|
|
13986
|
+
__name(getImmediateProcessor, "getImmediateProcessor");
|
|
13987
|
+
module2.exports = {
|
|
13988
|
+
ImmediateProcessor,
|
|
13989
|
+
getImmediateProcessor
|
|
13990
|
+
};
|
|
13991
|
+
}
|
|
13992
|
+
});
|
|
13993
|
+
|
|
13439
13994
|
// nostr/connection/connectionManager.js
|
|
13440
13995
|
var require_connectionManager = __commonJS({
|
|
13441
13996
|
"nostr/connection/connectionManager.js"(exports2, module2) {
|
|
@@ -13457,6 +14012,8 @@ var require_connectionManager = __commonJS({
|
|
|
13457
14012
|
CONNECTION_CONSTANTS
|
|
13458
14013
|
} = require_constants2();
|
|
13459
14014
|
var { intervalParseEvent } = require_eventLoop();
|
|
14015
|
+
var { getEventQueue, PRIORITY } = require_eventQueue();
|
|
14016
|
+
var { getImmediateProcessor } = require_immediateProcessor();
|
|
13460
14017
|
var {
|
|
13461
14018
|
getRelays,
|
|
13462
14019
|
execSendMessage,
|
|
@@ -13729,6 +14286,7 @@ var require_connectionManager = __commonJS({
|
|
|
13729
14286
|
};
|
|
13730
14287
|
function createEventHandler(lndConfig, manager) {
|
|
13731
14288
|
const logger2 = new Logger("nostr");
|
|
14289
|
+
const eventQueue = getEventQueue();
|
|
13732
14290
|
return async (event) => {
|
|
13733
14291
|
try {
|
|
13734
14292
|
manager.lastEventReceived = Date.now();
|
|
@@ -13743,18 +14301,25 @@ var require_connectionManager = __commonJS({
|
|
|
13743
14301
|
pubkey: event.pubkey
|
|
13744
14302
|
});
|
|
13745
14303
|
if (user) {
|
|
13746
|
-
const
|
|
13747
|
-
|
|
13748
|
-
|
|
14304
|
+
const priority = event.kind === 23194 ? PRIORITY.HIGH : PRIORITY.NORMAL;
|
|
14305
|
+
const enqueued = eventQueue.enqueue(event, { priority });
|
|
14306
|
+
insertEvent(event).then((ret) => {
|
|
14307
|
+
if (ret > 0) {
|
|
14308
|
+
logger2.debug(`Event ${event.id} persisted to DB`);
|
|
14309
|
+
}
|
|
14310
|
+
}).catch((e) => {
|
|
14311
|
+
logger2.error(`Nostr eventHandler ${event.id} DB error: ${e.message}`);
|
|
13749
14312
|
});
|
|
13750
|
-
|
|
13751
|
-
`
|
|
13752
|
-
|
|
14313
|
+
if (enqueued) {
|
|
14314
|
+
logger2.info(`Event ${event.id} queued for immediate processing (priority: ${priority})`);
|
|
14315
|
+
} else {
|
|
14316
|
+
logger2.warn(`Event ${event.id} duplicate or queue full`);
|
|
14317
|
+
}
|
|
13753
14318
|
} else {
|
|
13754
14319
|
const tags = event.tags;
|
|
13755
14320
|
const replyProxyAddr = tags?.find((item) => item?.[0] === "a")?.[1];
|
|
13756
14321
|
const replyTo = replyProxyAddr || event.pubkey;
|
|
13757
|
-
|
|
14322
|
+
execSendMessage({
|
|
13758
14323
|
message: JSON.stringify({
|
|
13759
14324
|
code: ERROR_CODES.FORBIDDEN,
|
|
13760
14325
|
data: null,
|
|
@@ -13865,11 +14430,14 @@ var require_connectionManager = __commonJS({
|
|
|
13865
14430
|
}
|
|
13866
14431
|
}, 45e3);
|
|
13867
14432
|
const stopSignal = { stop: false };
|
|
14433
|
+
const immediateProcessor = getImmediateProcessor();
|
|
14434
|
+
immediateProcessor.start(lndConfig.node_sk);
|
|
13868
14435
|
intervalParseEvent(stopSignal);
|
|
13869
14436
|
manager.addService({
|
|
13870
|
-
stop: /* @__PURE__ */ __name(() => {
|
|
14437
|
+
stop: /* @__PURE__ */ __name(async () => {
|
|
13871
14438
|
stopSignal.stop = true;
|
|
13872
14439
|
clearInterval(monitorInterval);
|
|
14440
|
+
await immediateProcessor.stop();
|
|
13873
14441
|
}, "stop")
|
|
13874
14442
|
});
|
|
13875
14443
|
return {
|
|
@@ -18579,7 +19147,8 @@ var require_setting_regtest = __commonJS({
|
|
|
18579
19147
|
bitcoindZmqRawTx: "tcp://regtest.lnfi.network:28335",
|
|
18580
19148
|
network: "regtest",
|
|
18581
19149
|
nostrRelays: [
|
|
18582
|
-
"wss://relay01.lnfi.network"
|
|
19150
|
+
"wss://relay01.lnfi.network",
|
|
19151
|
+
"wss://relay02.lnfi.network"
|
|
18583
19152
|
],
|
|
18584
19153
|
officialLndPeer: "03b24a4bf911ffd26ac1d5e5f2440a3c2f6974e4cc85d2ef54e17ee6d3717433d3",
|
|
18585
19154
|
officialLndPeerHost: "34.84.66.29:7739",
|
|
@@ -18761,7 +19330,7 @@ var LnLink = class extends EventEmitter {
|
|
|
18761
19330
|
*/
|
|
18762
19331
|
_ensureEnvironmentAndPrisma() {
|
|
18763
19332
|
if (!process.env.LINK_DATABASE_URL) {
|
|
18764
|
-
const dbPath = path.join(this.options.dataPath, "link", "lnlink.db");
|
|
19333
|
+
const dbPath = path.join(this.options.dataPath, ".link", "lnlink.db");
|
|
18765
19334
|
process.env.LINK_DATABASE_URL = `file:${dbPath}`;
|
|
18766
19335
|
console.log(`\u{1F5C4}\uFE0F Setting database URL: ${dbPath}`);
|
|
18767
19336
|
}
|