lnlink-server 1.1.7 → 1.1.9
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/app.js +312 -312
- package/dist/build-info.json +1 -1
- package/dist/config.default.js +1 -0
- package/dist/index.js +809 -37
- package/dist/index.js.map +4 -4
- package/dist/package.json +1 -1
- package/dist/prisma/migrations/20260402072918_add_exchange_orders/migration.sql +25 -0
- package/dist/prisma/migrations/20260403022951_auto_update/migration.sql +27 -0
- package/dist/prisma/schema.prisma +21 -0
- package/dist/public/js/init.js +125 -90
- package/dist/setting.mainnet.json +2 -1
- package/dist/setting.regtest.json +4 -4
- package/dist/setting.testnet.json +2 -1
- package/package.json +2 -2
- package/prisma/migrations/20260402072918_add_exchange_orders/migration.sql +25 -0
- package/prisma/migrations/20260403022951_auto_update/migration.sql +27 -0
- package/prisma/schema.prisma +21 -0
package/dist/package.json
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
-- CreateTable
|
|
2
|
+
CREATE TABLE "exchange_orders" (
|
|
3
|
+
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
|
4
|
+
"payment_hash" TEXT NOT NULL,
|
|
5
|
+
"btc_invoice" TEXT NOT NULL,
|
|
6
|
+
"btc_amount" TEXT NOT NULL,
|
|
7
|
+
"rgb_invoice" TEXT,
|
|
8
|
+
"asset_id" TEXT NOT NULL,
|
|
9
|
+
"asset_amount" TEXT NOT NULL,
|
|
10
|
+
"preimage" TEXT,
|
|
11
|
+
"status" TEXT NOT NULL,
|
|
12
|
+
"error_message" TEXT,
|
|
13
|
+
"htlc_expiry_at" INTEGER NOT NULL,
|
|
14
|
+
"created_at" INTEGER NOT NULL,
|
|
15
|
+
"updated_at" INTEGER NOT NULL
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
-- CreateIndex
|
|
19
|
+
CREATE UNIQUE INDEX "exchange_orders_payment_hash_key" ON "exchange_orders"("payment_hash");
|
|
20
|
+
|
|
21
|
+
-- CreateIndex
|
|
22
|
+
CREATE INDEX "exchange_orders_status_idx" ON "exchange_orders"("status");
|
|
23
|
+
|
|
24
|
+
-- CreateIndex
|
|
25
|
+
CREATE INDEX "exchange_orders_created_at_idx" ON "exchange_orders"("created_at");
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
-- RedefineTables
|
|
2
|
+
PRAGMA defer_foreign_keys=ON;
|
|
3
|
+
PRAGMA foreign_keys=OFF;
|
|
4
|
+
CREATE TABLE "new_exchange_orders" (
|
|
5
|
+
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
|
6
|
+
"payment_hash" TEXT NOT NULL,
|
|
7
|
+
"btc_invoice" TEXT NOT NULL,
|
|
8
|
+
"btc_amount" TEXT NOT NULL,
|
|
9
|
+
"rgb_invoice" TEXT,
|
|
10
|
+
"asset_id" TEXT NOT NULL,
|
|
11
|
+
"asset_amount" TEXT NOT NULL,
|
|
12
|
+
"preimage" TEXT,
|
|
13
|
+
"status" TEXT NOT NULL,
|
|
14
|
+
"error_message" TEXT,
|
|
15
|
+
"btc_retry_count" INTEGER NOT NULL DEFAULT 0,
|
|
16
|
+
"htlc_expiry_at" INTEGER NOT NULL,
|
|
17
|
+
"created_at" INTEGER NOT NULL,
|
|
18
|
+
"updated_at" INTEGER NOT NULL
|
|
19
|
+
);
|
|
20
|
+
INSERT INTO "new_exchange_orders" ("asset_amount", "asset_id", "btc_amount", "btc_invoice", "created_at", "error_message", "htlc_expiry_at", "id", "payment_hash", "preimage", "rgb_invoice", "status", "updated_at") SELECT "asset_amount", "asset_id", "btc_amount", "btc_invoice", "created_at", "error_message", "htlc_expiry_at", "id", "payment_hash", "preimage", "rgb_invoice", "status", "updated_at" FROM "exchange_orders";
|
|
21
|
+
DROP TABLE "exchange_orders";
|
|
22
|
+
ALTER TABLE "new_exchange_orders" RENAME TO "exchange_orders";
|
|
23
|
+
CREATE UNIQUE INDEX "exchange_orders_payment_hash_key" ON "exchange_orders"("payment_hash");
|
|
24
|
+
CREATE INDEX "exchange_orders_status_idx" ON "exchange_orders"("status");
|
|
25
|
+
CREATE INDEX "exchange_orders_created_at_idx" ON "exchange_orders"("created_at");
|
|
26
|
+
PRAGMA foreign_keys=ON;
|
|
27
|
+
PRAGMA defer_foreign_keys=OFF;
|
|
@@ -134,6 +134,27 @@ model LnlinkTransaction {
|
|
|
134
134
|
@@map("lnlink_transactions")
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
+
model ExchangeOrder {
|
|
138
|
+
id Int @id @default(autoincrement())
|
|
139
|
+
payment_hash String @unique
|
|
140
|
+
btc_invoice String
|
|
141
|
+
btc_amount String
|
|
142
|
+
rgb_invoice String?
|
|
143
|
+
asset_id String
|
|
144
|
+
asset_amount String
|
|
145
|
+
preimage String?
|
|
146
|
+
status String
|
|
147
|
+
error_message String?
|
|
148
|
+
btc_retry_count Int @default(0)
|
|
149
|
+
htlc_expiry_at Int
|
|
150
|
+
created_at Int
|
|
151
|
+
updated_at Int
|
|
152
|
+
|
|
153
|
+
@@index([status])
|
|
154
|
+
@@index([created_at])
|
|
155
|
+
@@map("exchange_orders")
|
|
156
|
+
}
|
|
157
|
+
|
|
137
158
|
// LnLink Orders Table
|
|
138
159
|
model LnlinkOrder {
|
|
139
160
|
id Int @id @default(autoincrement())
|
package/dist/public/js/init.js
CHANGED
|
@@ -5,7 +5,8 @@ let isAdvancedConfigVisible = false
|
|
|
5
5
|
function openExternalUrl(url) {
|
|
6
6
|
if (window.electronAPI && window.electronAPI.openExternal) {
|
|
7
7
|
window.electronAPI.openExternal(url)
|
|
8
|
-
}
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
9
10
|
// Fallback for non-Electron environments
|
|
10
11
|
window.open(url, "_blank")
|
|
11
12
|
}
|
|
@@ -62,7 +63,7 @@ async function fetchNetworkConfigs() {
|
|
|
62
63
|
// nostrRelays: item.nostrRelays ? [item.nostrRelays] : [],
|
|
63
64
|
nostrRelays: [
|
|
64
65
|
"wss://relay01.lnfi.network",
|
|
65
|
-
"wss://
|
|
66
|
+
"wss://vault.iris.to",
|
|
66
67
|
],
|
|
67
68
|
officialLndPeer: item.lndPeerId,
|
|
68
69
|
officialLndPeerHost: item.lndPeerHost,
|
|
@@ -80,12 +81,14 @@ async function fetchNetworkConfigs() {
|
|
|
80
81
|
networkConfigs = apiConfigs
|
|
81
82
|
console.log("Network configs updated from API")
|
|
82
83
|
}
|
|
83
|
-
}
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
84
86
|
console.warn(
|
|
85
87
|
"API returned success but no data or invalid format, using default configs.",
|
|
86
88
|
)
|
|
87
89
|
}
|
|
88
|
-
}
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
89
92
|
console.error(
|
|
90
93
|
"Error fetching network configs, using default configs:",
|
|
91
94
|
error,
|
|
@@ -128,7 +131,8 @@ function showErrorModal(message) {
|
|
|
128
131
|
document.getElementById("errorModal"),
|
|
129
132
|
)
|
|
130
133
|
errorModal.show()
|
|
131
|
-
}
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
132
136
|
console.error("Error:", message)
|
|
133
137
|
}
|
|
134
138
|
}
|
|
@@ -142,7 +146,8 @@ function showSuccessModal(message) {
|
|
|
142
146
|
document.getElementById("successModal"),
|
|
143
147
|
)
|
|
144
148
|
successModal.show()
|
|
145
|
-
}
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
146
151
|
console.log("Success:", message)
|
|
147
152
|
}
|
|
148
153
|
}
|
|
@@ -188,11 +193,13 @@ function showConfirmModal(message, onConfirm, onCancel) {
|
|
|
188
193
|
}
|
|
189
194
|
|
|
190
195
|
confirmModal.show()
|
|
191
|
-
}
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
192
198
|
// eslint-disable-next-line no-alert
|
|
193
199
|
if (confirm(message.replace(/<[^>]*>/g, ""))) {
|
|
194
200
|
if (onConfirm) onConfirm()
|
|
195
|
-
}
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
196
203
|
if (onCancel) onCancel()
|
|
197
204
|
}
|
|
198
205
|
}
|
|
@@ -202,20 +209,22 @@ function showConfirmModal(message, onConfirm, onCancel) {
|
|
|
202
209
|
function getStatusClass(value) {
|
|
203
210
|
const strValue = String(value).toLowerCase()
|
|
204
211
|
if (
|
|
205
|
-
strValue === "true"
|
|
206
|
-
strValue === "running"
|
|
207
|
-
strValue === "active"
|
|
208
|
-
strValue === "online"
|
|
212
|
+
strValue === "true"
|
|
213
|
+
|| strValue === "running"
|
|
214
|
+
|| strValue === "active"
|
|
215
|
+
|| strValue === "online"
|
|
209
216
|
) {
|
|
210
217
|
return { class: "status-success", icon: "fas fa-check-circle" }
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
strValue === "
|
|
214
|
-
strValue === "
|
|
215
|
-
strValue === "
|
|
218
|
+
}
|
|
219
|
+
else if (
|
|
220
|
+
strValue === "false"
|
|
221
|
+
|| strValue === "stopped"
|
|
222
|
+
|| strValue === "inactive"
|
|
223
|
+
|| strValue === "offline"
|
|
216
224
|
) {
|
|
217
225
|
return { class: "status-error", icon: "fas fa-times-circle" }
|
|
218
|
-
}
|
|
226
|
+
}
|
|
227
|
+
else if (strValue.includes("pending") || strValue.includes("waiting")) {
|
|
219
228
|
return { class: "status-warning", icon: "fas fa-clock" }
|
|
220
229
|
}
|
|
221
230
|
return { class: "", icon: "fas fa-info-circle" }
|
|
@@ -227,12 +236,12 @@ async function getInfo(showLoading = true) {
|
|
|
227
236
|
|
|
228
237
|
// Show loading state
|
|
229
238
|
if (showLoading) {
|
|
230
|
-
mainContent.innerHTML
|
|
231
|
-
|
|
239
|
+
mainContent.innerHTML
|
|
240
|
+
= "<div class=\"loading-container\"><div class=\"loading\"></div><div>Loading information...</div></div>"
|
|
232
241
|
}
|
|
233
242
|
|
|
234
243
|
try {
|
|
235
|
-
const res = await fetch("/api/lnd/info").then(
|
|
244
|
+
const res = await fetch("/api/lnd/info").then(res => res.json())
|
|
236
245
|
|
|
237
246
|
if (res.code === 200) {
|
|
238
247
|
if (res.data) {
|
|
@@ -250,23 +259,26 @@ async function getInfo(showLoading = true) {
|
|
|
250
259
|
renderConfigurationForm(res.data, torReachable)
|
|
251
260
|
}
|
|
252
261
|
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
res.
|
|
262
|
+
}
|
|
263
|
+
else if (
|
|
264
|
+
res.code === 500
|
|
265
|
+
&& res.message === "Please init the wallet or init owner first"
|
|
256
266
|
) {
|
|
257
267
|
// Fetch network configs only when needed for configuration
|
|
258
268
|
await fetchNetworkConfigs()
|
|
259
269
|
|
|
260
270
|
// If wallet/owner not initialized, show configuration form
|
|
261
271
|
renderConfigurationForm({})
|
|
262
|
-
} else {
|
|
263
|
-
mainContent.innerHTML =
|
|
264
|
-
'<div class="alert alert-danger"><i class="fas fa-exclamation-triangle"></i> Failed to load information</div>'
|
|
265
272
|
}
|
|
266
|
-
|
|
273
|
+
else {
|
|
274
|
+
mainContent.innerHTML
|
|
275
|
+
= "<div class=\"alert alert-danger\"><i class=\"fas fa-exclamation-triangle\"></i> Failed to load information</div>"
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
catch (error) {
|
|
267
279
|
console.error("Failed to get info:", error)
|
|
268
|
-
mainContent.innerHTML
|
|
269
|
-
|
|
280
|
+
mainContent.innerHTML
|
|
281
|
+
= "<div class=\"alert alert-danger\"><i class=\"fas fa-exclamation-triangle\"></i> Network error occurred</div>"
|
|
270
282
|
}
|
|
271
283
|
}
|
|
272
284
|
|
|
@@ -276,12 +288,12 @@ function renderConfiguredView(basicData, settings, torReachable) {
|
|
|
276
288
|
const mainContent = document.getElementById("main-content")
|
|
277
289
|
|
|
278
290
|
// Extract Node ID (Nostr PubKey)
|
|
279
|
-
const nodeId
|
|
280
|
-
settings.officialNostrPubKey || basicData.officialNostrPubKey || "Unknown"
|
|
291
|
+
const nodeId
|
|
292
|
+
= settings.officialNostrPubKey || basicData.officialNostrPubKey || "Unknown"
|
|
281
293
|
|
|
282
294
|
// Get Tor status from basicData
|
|
283
|
-
const enableTor
|
|
284
|
-
basicData.enableTor !== undefined ? basicData.enableTor : true
|
|
295
|
+
const enableTor
|
|
296
|
+
= basicData.enableTor !== undefined ? basicData.enableTor : true
|
|
285
297
|
|
|
286
298
|
// Determine Service Status
|
|
287
299
|
// We check basicData for status indicators or default to design mocks if not present
|
|
@@ -289,10 +301,10 @@ function renderConfiguredView(basicData, settings, torReachable) {
|
|
|
289
301
|
const rgbStatus = basicData.rgb || "Stopped" // Mock/Default based on design
|
|
290
302
|
const litdStatus = basicData.litd || "Stopped" // Mock/Default based on design
|
|
291
303
|
|
|
292
|
-
const isRgbRunning
|
|
293
|
-
rgbStatus.toLowerCase() === "running" || rgbStatus === "true"
|
|
294
|
-
const isLitdRunning
|
|
295
|
-
litdStatus.toLowerCase() === "running" || litdStatus === "true"
|
|
304
|
+
const isRgbRunning
|
|
305
|
+
= rgbStatus.toLowerCase() === "running" || rgbStatus === "true"
|
|
306
|
+
const isLitdRunning
|
|
307
|
+
= litdStatus.toLowerCase() === "running" || litdStatus === "true"
|
|
296
308
|
|
|
297
309
|
const rgbClass = isRgbRunning ? "running" : "stopped"
|
|
298
310
|
const litdClass = isLitdRunning ? "running" : "stopped"
|
|
@@ -446,13 +458,15 @@ function updateManageButtonState(anyRunning, allRunning) {
|
|
|
446
458
|
// All services running - enable button
|
|
447
459
|
manageBtn.disabled = false
|
|
448
460
|
manageBtn.classList.remove("loading-state")
|
|
449
|
-
manageBtn.innerHTML =
|
|
450
|
-
}
|
|
461
|
+
manageBtn.innerHTML = "Manage My Node <i class=\"fas fa-arrow-right\"></i>"
|
|
462
|
+
}
|
|
463
|
+
else if (anyRunning) {
|
|
451
464
|
// Some services starting - show loading
|
|
452
465
|
manageBtn.disabled = true
|
|
453
466
|
manageBtn.classList.add("loading-state")
|
|
454
|
-
manageBtn.innerHTML =
|
|
455
|
-
}
|
|
467
|
+
manageBtn.innerHTML = "<span class=\"loading\"></span> Starting Services..."
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
456
470
|
// No services running - show normal but disabled
|
|
457
471
|
manageBtn.disabled = true
|
|
458
472
|
manageBtn.classList.remove("loading-state")
|
|
@@ -488,7 +502,8 @@ async function pollServiceStatus() {
|
|
|
488
502
|
if (nameEl && nameEl.textContent.includes("RGB")) {
|
|
489
503
|
rgbStatusEl = box.querySelector(".status-value")
|
|
490
504
|
rgbDotEl = box.querySelector(".status-dot")
|
|
491
|
-
}
|
|
505
|
+
}
|
|
506
|
+
else if (nameEl && nameEl.textContent.includes("LITD")) {
|
|
492
507
|
litdStatusEl = box.querySelector(".status-value")
|
|
493
508
|
litdDotEl = box.querySelector(".status-dot")
|
|
494
509
|
}
|
|
@@ -528,14 +543,16 @@ async function pollServiceStatus() {
|
|
|
528
543
|
attempts++
|
|
529
544
|
if (attempts < maxAttempts) {
|
|
530
545
|
setTimeout(checkStatus, 1000)
|
|
531
|
-
}
|
|
546
|
+
}
|
|
547
|
+
else {
|
|
532
548
|
console.log("Service status polling timed out")
|
|
533
549
|
// Re-enable button even if services didn't start
|
|
534
550
|
updateManageButtonState(false, false)
|
|
535
551
|
const manageBtn = document.querySelector(".manage-btn")
|
|
536
552
|
manageBtn.disabled = false
|
|
537
553
|
}
|
|
538
|
-
}
|
|
554
|
+
}
|
|
555
|
+
catch (error) {
|
|
539
556
|
console.error("Error polling service status:", error)
|
|
540
557
|
attempts++
|
|
541
558
|
if (attempts < maxAttempts) {
|
|
@@ -576,8 +593,8 @@ window.navigateToManage = function navigateToManage(url, button) {
|
|
|
576
593
|
window.openManageUrl = function openManageUrl(url, linkEl) {
|
|
577
594
|
if (!url) return
|
|
578
595
|
if (linkEl) {
|
|
579
|
-
linkEl.innerHTML
|
|
580
|
-
|
|
596
|
+
linkEl.innerHTML
|
|
597
|
+
= "<i class=\"fas fa-spinner fa-spin status-icon\"></i>Loading..."
|
|
581
598
|
}
|
|
582
599
|
setTimeout(() => {
|
|
583
600
|
window.location.href = url
|
|
@@ -680,7 +697,8 @@ function togglePasswordVisibility(icon) {
|
|
|
680
697
|
input.type = "text"
|
|
681
698
|
icon.classList.remove("fa-eye")
|
|
682
699
|
icon.classList.add("fa-eye-slash")
|
|
683
|
-
}
|
|
700
|
+
}
|
|
701
|
+
else {
|
|
684
702
|
input.type = "password"
|
|
685
703
|
icon.classList.remove("fa-eye-slash")
|
|
686
704
|
icon.classList.add("fa-eye")
|
|
@@ -712,7 +730,8 @@ function copyToClipboard(text, triggerElement) {
|
|
|
712
730
|
console.error("Could not copy text: ", err)
|
|
713
731
|
},
|
|
714
732
|
)
|
|
715
|
-
}
|
|
733
|
+
}
|
|
734
|
+
else {
|
|
716
735
|
const textArea = document.createElement("textarea")
|
|
717
736
|
textArea.value = text
|
|
718
737
|
textArea.style.position = "fixed"
|
|
@@ -723,7 +742,8 @@ function copyToClipboard(text, triggerElement) {
|
|
|
723
742
|
try {
|
|
724
743
|
document.execCommand("copy")
|
|
725
744
|
showFeedback()
|
|
726
|
-
}
|
|
745
|
+
}
|
|
746
|
+
catch (err) {
|
|
727
747
|
console.error("Fallback: Oops, unable to copy", err)
|
|
728
748
|
}
|
|
729
749
|
document.body.removeChild(textArea)
|
|
@@ -829,7 +849,8 @@ window.toggleAdvanced = function () {
|
|
|
829
849
|
container.style.display = "block"
|
|
830
850
|
icon.classList.remove("fa-chevron-down")
|
|
831
851
|
icon.classList.add("fa-chevron-up")
|
|
832
|
-
}
|
|
852
|
+
}
|
|
853
|
+
else {
|
|
833
854
|
container.style.display = "none"
|
|
834
855
|
icon.classList.remove("fa-chevron-up")
|
|
835
856
|
icon.classList.add("fa-chevron-down")
|
|
@@ -848,7 +869,8 @@ window.selectNetwork = function (network) {
|
|
|
848
869
|
document.querySelectorAll(".btn-network").forEach((btn) => {
|
|
849
870
|
if (btn.dataset.value === network) {
|
|
850
871
|
btn.classList.add("active")
|
|
851
|
-
}
|
|
872
|
+
}
|
|
873
|
+
else {
|
|
852
874
|
btn.classList.remove("active")
|
|
853
875
|
}
|
|
854
876
|
})
|
|
@@ -868,7 +890,8 @@ window.togglePassword = function (id) {
|
|
|
868
890
|
const input = document.getElementById(id)
|
|
869
891
|
if (input.type === "password") {
|
|
870
892
|
input.type = "text"
|
|
871
|
-
}
|
|
893
|
+
}
|
|
894
|
+
else {
|
|
872
895
|
input.type = "password"
|
|
873
896
|
}
|
|
874
897
|
}
|
|
@@ -970,7 +993,8 @@ function updateConfigFields() {
|
|
|
970
993
|
let editableFields = []
|
|
971
994
|
if (selectedNetwork === "regtest") {
|
|
972
995
|
editableFields = ["bitcoindPass"]
|
|
973
|
-
}
|
|
996
|
+
}
|
|
997
|
+
else if (selectedNetwork === "mainnet") {
|
|
974
998
|
editableFields = [
|
|
975
999
|
"bitcoindRpcHost",
|
|
976
1000
|
"bitcoindRpcPort",
|
|
@@ -981,7 +1005,8 @@ function updateConfigFields() {
|
|
|
981
1005
|
"rgbProxy",
|
|
982
1006
|
"bitcoindIndex",
|
|
983
1007
|
]
|
|
984
|
-
}
|
|
1008
|
+
}
|
|
1009
|
+
else if (selectedNetwork === "testnet") {
|
|
985
1010
|
editableFields = ["bitcoindPass"]
|
|
986
1011
|
}
|
|
987
1012
|
|
|
@@ -1052,9 +1077,9 @@ async function handleInitTorToggle(checkbox, torReachable) {
|
|
|
1052
1077
|
|
|
1053
1078
|
if (!checkbox.checked) {
|
|
1054
1079
|
label.classList.add("disabled-state")
|
|
1055
|
-
label.innerHTML
|
|
1056
|
-
|
|
1057
|
-
|
|
1080
|
+
label.innerHTML
|
|
1081
|
+
= `Disabled - Enable Tor to ensure all features work properly${
|
|
1082
|
+
torTooltipShort}`
|
|
1058
1083
|
return
|
|
1059
1084
|
}
|
|
1060
1085
|
|
|
@@ -1069,17 +1094,18 @@ async function handleInitTorToggle(checkbox, torReachable) {
|
|
|
1069
1094
|
label.classList.remove("disabled-state")
|
|
1070
1095
|
label.textContent = "Enabled-Enhanced privacy"
|
|
1071
1096
|
// label.style.color = "#10b981";
|
|
1072
|
-
}
|
|
1097
|
+
}
|
|
1098
|
+
else {
|
|
1073
1099
|
checkbox.checked = false
|
|
1074
1100
|
label.classList.add("disabled-state")
|
|
1075
|
-
label.innerHTML
|
|
1076
|
-
|
|
1077
|
-
|
|
1101
|
+
label.innerHTML
|
|
1102
|
+
= `Disabled - Enable Tor to ensure all features work properly${
|
|
1103
|
+
torTooltipLong}`
|
|
1078
1104
|
label.style.color = ""
|
|
1079
1105
|
showErrorModal(
|
|
1080
|
-
"<div>Your current network environment does not support Tor. Check your network or proxy (TUN mode required).</div>"
|
|
1081
|
-
|
|
1082
|
-
|
|
1106
|
+
"<div>Your current network environment does not support Tor. Check your network or proxy (TUN mode required).</div>"
|
|
1107
|
+
+ "<div style='margin-top: 10px;'>If Tor is disabled or fails to enable, your Taproot Assets node will only be able to initiate outbound connections to other nodes.</div>"
|
|
1108
|
+
+ "<div style='margin-top: 5px;'>Other nodes will not be able to connect to your node, and your node cannot be shared for inbound connections.</div>",
|
|
1083
1109
|
)
|
|
1084
1110
|
}
|
|
1085
1111
|
}
|
|
@@ -1091,7 +1117,8 @@ async function checkTorReachability() {
|
|
|
1091
1117
|
const response = await fetch("/api/lnd/tor/check")
|
|
1092
1118
|
const result = await response.json()
|
|
1093
1119
|
return result.data?.reachable === true
|
|
1094
|
-
}
|
|
1120
|
+
}
|
|
1121
|
+
catch {
|
|
1095
1122
|
return false
|
|
1096
1123
|
}
|
|
1097
1124
|
}
|
|
@@ -1111,7 +1138,7 @@ async function handleConfigFormSubmit(event) {
|
|
|
1111
1138
|
form.classList.add("was-validated")
|
|
1112
1139
|
submitBtn.setAttribute("disabled", "disabled")
|
|
1113
1140
|
// Use the new loading spinner style
|
|
1114
|
-
submitBtn.innerHTML =
|
|
1141
|
+
submitBtn.innerHTML = "<div class=\"loading\"></div>Save and Continue"
|
|
1115
1142
|
const formData = new FormData(form)
|
|
1116
1143
|
const myHeaders = new Headers()
|
|
1117
1144
|
myHeaders.append("Content-Type", "application/json")
|
|
@@ -1127,9 +1154,10 @@ async function handleConfigFormSubmit(event) {
|
|
|
1127
1154
|
// Handle comma-separated array
|
|
1128
1155
|
settings[key] = value
|
|
1129
1156
|
.split(",")
|
|
1130
|
-
.map(
|
|
1131
|
-
.filter(
|
|
1132
|
-
}
|
|
1157
|
+
.map(item => item.trim())
|
|
1158
|
+
.filter(item => item)
|
|
1159
|
+
}
|
|
1160
|
+
else {
|
|
1133
1161
|
settings[key] = value
|
|
1134
1162
|
}
|
|
1135
1163
|
}
|
|
@@ -1140,15 +1168,15 @@ async function handleConfigFormSubmit(event) {
|
|
|
1140
1168
|
|
|
1141
1169
|
// Check Tor network reachability if Tor is enabled
|
|
1142
1170
|
if (enableTor) {
|
|
1143
|
-
submitBtn.innerHTML =
|
|
1171
|
+
submitBtn.innerHTML = "<div class=\"loading\"></div>Checking Tor network..."
|
|
1144
1172
|
const torReachable = await checkTorReachability()
|
|
1145
1173
|
if (!torReachable) {
|
|
1146
1174
|
submitBtn.removeAttribute("disabled")
|
|
1147
1175
|
submitBtn.innerHTML = "Save and Continue"
|
|
1148
1176
|
showErrorModal(
|
|
1149
|
-
"<div>Your current network environment does not support Tor. Check your network or proxy (TUN mode required).</div>"
|
|
1150
|
-
|
|
1151
|
-
|
|
1177
|
+
"<div>Your current network environment does not support Tor. Check your network or proxy (TUN mode required).</div>"
|
|
1178
|
+
+ "<div style='margin-top: 10px;'>If Tor is disabled or fails to enable, your Taproot Assets node will only be able to initiate outbound connections to other nodes.</div>"
|
|
1179
|
+
+ "<div style='margin-top: 5px;'>Other nodes will not be able to connect to your node, and your node cannot be shared for inbound connections.</div>",
|
|
1152
1180
|
)
|
|
1153
1181
|
return
|
|
1154
1182
|
}
|
|
@@ -1176,16 +1204,19 @@ async function handleConfigFormSubmit(event) {
|
|
|
1176
1204
|
|
|
1177
1205
|
// Refresh page data to show running services
|
|
1178
1206
|
await getInfo(false)
|
|
1179
|
-
}
|
|
1207
|
+
}
|
|
1208
|
+
else {
|
|
1180
1209
|
showErrorModal(result.message || "Configuration failed")
|
|
1181
1210
|
}
|
|
1182
|
-
}
|
|
1211
|
+
}
|
|
1212
|
+
catch (error) {
|
|
1183
1213
|
console.error("Network error:", error)
|
|
1184
1214
|
showErrorModal("Network error occurred")
|
|
1185
|
-
}
|
|
1215
|
+
}
|
|
1216
|
+
finally {
|
|
1186
1217
|
submitBtn.removeAttribute("disabled")
|
|
1187
|
-
submitBtn.innerHTML
|
|
1188
|
-
|
|
1218
|
+
submitBtn.innerHTML
|
|
1219
|
+
= "<i class=\"fas fa-save\"></i> Save Complete Configuration"
|
|
1189
1220
|
}
|
|
1190
1221
|
}
|
|
1191
1222
|
|
|
@@ -1215,9 +1246,9 @@ async function handleTorToggle(checkbox, torReachable) {
|
|
|
1215
1246
|
if (enable && !torReachable) {
|
|
1216
1247
|
checkbox.checked = false
|
|
1217
1248
|
showErrorModal(
|
|
1218
|
-
"<div>Your current network environment does not support Tor. Check your network or proxy (TUN mode required).</div>"
|
|
1219
|
-
|
|
1220
|
-
|
|
1249
|
+
"<div>Your current network environment does not support Tor. Check your network or proxy (TUN mode required).</div>"
|
|
1250
|
+
+ "<div style='margin-top: 10px;'>If Tor is disabled or fails to enable, your Taproot Assets node will only be able to initiate outbound connections to other nodes.</div>"
|
|
1251
|
+
+ "<div style='margin-top: 5px;'>Other nodes will not be able to connect to your node, and your node cannot be shared for inbound connections.</div>",
|
|
1221
1252
|
)
|
|
1222
1253
|
return
|
|
1223
1254
|
}
|
|
@@ -1246,8 +1277,8 @@ async function handleTorToggle(checkbox, torReachable) {
|
|
|
1246
1277
|
label.innerHTML = enable
|
|
1247
1278
|
? `Enabled - Enhanced privacy`
|
|
1248
1279
|
: `Disabled - Enable Tor to ensure all features work properly${
|
|
1249
|
-
|
|
1250
|
-
|
|
1280
|
+
torReachable ? torTooltipShort : torTooltipLong
|
|
1281
|
+
}`
|
|
1251
1282
|
|
|
1252
1283
|
// Show success message
|
|
1253
1284
|
showToast(
|
|
@@ -1257,30 +1288,34 @@ async function handleTorToggle(checkbox, torReachable) {
|
|
|
1257
1288
|
|
|
1258
1289
|
// Poll service status to update UI
|
|
1259
1290
|
await pollServiceStatus()
|
|
1260
|
-
}
|
|
1291
|
+
}
|
|
1292
|
+
else {
|
|
1261
1293
|
throw new Error(result.message || "Failed to toggle Tor")
|
|
1262
1294
|
}
|
|
1263
|
-
}
|
|
1295
|
+
}
|
|
1296
|
+
catch (error) {
|
|
1264
1297
|
console.error("Error toggling Tor:", error)
|
|
1265
1298
|
// Revert checkbox state on error
|
|
1266
1299
|
checkbox.checked = !enable
|
|
1267
1300
|
label.textContent = originalText
|
|
1268
1301
|
showToast(`Failed to toggle Tor: ${error.message}`, "error")
|
|
1269
|
-
}
|
|
1302
|
+
}
|
|
1303
|
+
finally {
|
|
1270
1304
|
checkbox.disabled = false
|
|
1271
1305
|
}
|
|
1272
1306
|
}
|
|
1273
1307
|
|
|
1274
1308
|
if (!enable) {
|
|
1275
1309
|
showConfirmModal(
|
|
1276
|
-
"<div>If Tor is disabled or fails to enable, your Taproot Assets node will only be able to initiate outbound connections to other nodes.</div>"
|
|
1277
|
-
|
|
1310
|
+
"<div>If Tor is disabled or fails to enable, your Taproot Assets node will only be able to initiate outbound connections to other nodes.</div>"
|
|
1311
|
+
+ "<div style='margin-top: 5px;'>Other nodes will not be able to connect to your node, and your node cannot be shared for inbound connections.</div>",
|
|
1278
1312
|
executeToggle,
|
|
1279
1313
|
() => {
|
|
1280
1314
|
checkbox.checked = true
|
|
1281
1315
|
},
|
|
1282
1316
|
)
|
|
1283
|
-
}
|
|
1317
|
+
}
|
|
1318
|
+
else {
|
|
1284
1319
|
await executeToggle()
|
|
1285
1320
|
}
|
|
1286
1321
|
}
|
|
@@ -18,5 +18,6 @@
|
|
|
18
18
|
"officialRgbPeerHost": "CHANGE_ME_MAINNET_RGB_HOST:9736",
|
|
19
19
|
"officialUniverseServer": "CHANGE_ME_MAINNET_UNIVERSE_HOST:10009",
|
|
20
20
|
"priceOracle": "grpc-oracle.lnfi.network",
|
|
21
|
-
"rgbProxy": "rpc://CHANGE_ME_MAINNET_RGB_PROXY_HOST:5000/json-rpc"
|
|
21
|
+
"rgbProxy": "rpc://CHANGE_ME_MAINNET_RGB_PROXY_HOST:5000/json-rpc",
|
|
22
|
+
"rgbPriceServer": "https://api-oracle.lnfi.network"
|
|
22
23
|
}
|
|
@@ -8,15 +8,15 @@
|
|
|
8
8
|
"bitcoindZmqRawTx": "tcp://regtest.lnfi.network:28335",
|
|
9
9
|
"network": "regtest",
|
|
10
10
|
"nostrRelays": [
|
|
11
|
-
"wss://
|
|
12
|
-
"wss://relay01.lnfi.network"
|
|
11
|
+
"wss://relay01.lnfi.network","wss://vault.iris.to"
|
|
13
12
|
],
|
|
14
13
|
"officialLndPeer": "03b24a4bf911ffd26ac1d5e5f2440a3c2f6974e4cc85d2ef54e17ee6d3717433d3",
|
|
15
|
-
"officialLndPeerHost": "34.84.
|
|
14
|
+
"officialLndPeerHost": "34.84.69.164:7739",
|
|
16
15
|
"officialNostrPubKey": "npub1me48869w43j30cfry9ayz9dsdl4gj54xppgk9krrv7g6hsq7psuqp3yusn",
|
|
17
16
|
"officialRgbPeer": "03b7153e278882e48e690acd0743305cbada86b131ab3388ccd782b45b02f064ef",
|
|
18
17
|
"officialRgbPeerHost": "regtest.lnfi.network:9736",
|
|
19
18
|
"officialUniverseServer": "regtest.lnfi.network:10009",
|
|
20
19
|
"priceOracle": "grpc-oracle.lnfi.network",
|
|
21
|
-
"rgbProxy": "rpc://regtest.lnfi.network:5000/json-rpc"
|
|
20
|
+
"rgbProxy": "rpc://regtest.lnfi.network:5000/json-rpc",
|
|
21
|
+
"rgbPriceServer": "https://api-oracle.lnfi.network"
|
|
22
22
|
}
|
|
@@ -18,5 +18,6 @@
|
|
|
18
18
|
"officialRgbPeerHost": "CHANGE_ME_TESTNET_RGB_HOST:9736",
|
|
19
19
|
"officialUniverseServer": "CHANGE_ME_TESTNET_UNIVERSE_HOST:10009",
|
|
20
20
|
"priceOracle": "grpc-oracle.lnfi.network",
|
|
21
|
-
"rgbProxy": "rpc://CHANGE_ME_TESTNET_RGB_PROXY_HOST:5000/json-rpc"
|
|
21
|
+
"rgbProxy": "rpc://CHANGE_ME_TESTNET_RGB_PROXY_HOST:5000/json-rpc",
|
|
22
|
+
"rgbPriceServer": "https://api-oracle.lnfi.network"
|
|
22
23
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lnlink-server",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.9",
|
|
4
4
|
"private": false,
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"files": [
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"build": "node build.js && node build.js --mode development --external all --entry electron",
|
|
13
13
|
"start:bin": "node scripts/start-bin.js",
|
|
14
14
|
"start:docker:dev": "dotenv -e .env.dev -- docker compose -f ./docker-compose.dev.yml up --build",
|
|
15
|
-
"start:dev": "dotenv -e .env.dev -- sh -c \"prisma generate && (prisma migrate dev --name auto_update || prisma db push) &&
|
|
15
|
+
"start:dev": "dotenv -e .env.dev -- sh -c \"prisma generate && (prisma migrate dev --name auto_update || prisma db push) && node ./app.js\"",
|
|
16
16
|
"start:regtest": "docker compose --env-file ./.env.regtest -f ./docker-compose-lnlink.yml up --build",
|
|
17
17
|
"start:testnet": "docker compose --env-file ./.env.testnet -f ./docker-compose-lnlink.yml up --build",
|
|
18
18
|
"start:mainnet": "docker compose --env-file ./.env.mainnet -f ./docker-compose-lnlink.yml up --build",
|