@fiber-pay/react 0.2.3 → 0.2.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/README.md +40 -1
- package/dist/index.d.ts +102 -19
- package/dist/index.js +877 -56
- package/dist/index.js.map +1 -1
- package/package.json +10 -4
package/dist/index.js
CHANGED
|
@@ -1,13 +1,39 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
import {
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import {
|
|
3
|
+
ChannelState,
|
|
4
|
+
ConfigBuilder as ConfigBuilder2,
|
|
5
|
+
ckbHash,
|
|
6
|
+
ckbToShannons,
|
|
7
|
+
derivePublicKey,
|
|
8
|
+
FiberBrowserNode as FiberBrowserNode2,
|
|
9
|
+
FiberRpcError,
|
|
10
|
+
formatShannonsAsCkb as formatShannonsAsCkb2,
|
|
11
|
+
fromHex,
|
|
12
|
+
getLockBalanceShannons as getLockBalanceShannons2,
|
|
13
|
+
PasskeyCredentialProvider as PasskeyCredentialProvider2,
|
|
14
|
+
PasswordCredentialProvider as PasswordCredentialProvider2,
|
|
15
|
+
RawKeyCredentialProvider as RawKeyCredentialProvider2,
|
|
16
|
+
scriptToAddress as scriptToAddress2,
|
|
17
|
+
shannonsToCkb,
|
|
18
|
+
toHex
|
|
19
|
+
} from "@fiber-pay/sdk/browser";
|
|
20
|
+
|
|
21
|
+
// src/connect-button.tsx
|
|
22
|
+
import {
|
|
23
|
+
useCallback as useCallback2,
|
|
24
|
+
useEffect as useEffect2,
|
|
25
|
+
useRef as useRef2,
|
|
26
|
+
useState as useState2
|
|
27
|
+
} from "react";
|
|
3
28
|
|
|
4
29
|
// src/use-fiber-node.ts
|
|
5
30
|
import {
|
|
6
31
|
FiberBrowserNode,
|
|
7
32
|
PasskeyCredentialProvider,
|
|
8
|
-
PasswordCredentialProvider
|
|
33
|
+
PasswordCredentialProvider,
|
|
34
|
+
RawKeyCredentialProvider
|
|
9
35
|
} from "@fiber-pay/sdk/browser";
|
|
10
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
36
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
11
37
|
var PASSKEY_UNAVAILABLE_REASON_TEXT = {
|
|
12
38
|
"window-unavailable": "Passkey is not available because there is no browser window context.",
|
|
13
39
|
"insecure-context": "Passkey requires a secure context (HTTPS or localhost).",
|
|
@@ -52,8 +78,9 @@ function useFiberNode(options) {
|
|
|
52
78
|
node.off("error", nodeListenersRef.current.error);
|
|
53
79
|
nodeListenersRef.current = null;
|
|
54
80
|
}, []);
|
|
55
|
-
useEffect(
|
|
56
|
-
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
isMountedRef.current = true;
|
|
83
|
+
return () => {
|
|
57
84
|
isMountedRef.current = false;
|
|
58
85
|
const node = nodeRef.current;
|
|
59
86
|
nodeRef.current = null;
|
|
@@ -62,10 +89,10 @@ function useFiberNode(options) {
|
|
|
62
89
|
void node.stop().catch(() => {
|
|
63
90
|
});
|
|
64
91
|
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
);
|
|
92
|
+
};
|
|
93
|
+
}, [detachNodeListeners]);
|
|
68
94
|
useEffect(() => {
|
|
95
|
+
if (options.enabled === false) return;
|
|
69
96
|
let cancelled = false;
|
|
70
97
|
PasskeyCredentialProvider.getSupportStatus().then((status) => {
|
|
71
98
|
if (!cancelled) {
|
|
@@ -89,7 +116,7 @@ function useFiberNode(options) {
|
|
|
89
116
|
return () => {
|
|
90
117
|
cancelled = true;
|
|
91
118
|
};
|
|
92
|
-
}, [walletId]);
|
|
119
|
+
}, [walletId, options.enabled]);
|
|
93
120
|
const initNode = useCallback(
|
|
94
121
|
(credential) => {
|
|
95
122
|
if (nodeRef.current) {
|
|
@@ -217,6 +244,26 @@ function useFiberNode(options) {
|
|
|
217
244
|
await cleanupFailedStart(node);
|
|
218
245
|
}
|
|
219
246
|
}, [cleanupFailedStart, initNode, walletId]);
|
|
247
|
+
const startWithRawKey = useCallback(
|
|
248
|
+
async (fiberKey, ckbSecretKey) => {
|
|
249
|
+
setError(null);
|
|
250
|
+
let node = null;
|
|
251
|
+
try {
|
|
252
|
+
const credential = new RawKeyCredentialProvider(fiberKey, ckbSecretKey, walletId);
|
|
253
|
+
node = initNode(credential);
|
|
254
|
+
const info = await node.start();
|
|
255
|
+
if (isMountedRef.current) {
|
|
256
|
+
setNodeInfo(info);
|
|
257
|
+
}
|
|
258
|
+
} catch (startError) {
|
|
259
|
+
if (isMountedRef.current) {
|
|
260
|
+
setError(asErrorMessage(startError));
|
|
261
|
+
}
|
|
262
|
+
await cleanupFailedStart(node);
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
[cleanupFailedStart, initNode, walletId]
|
|
266
|
+
);
|
|
220
267
|
const stop = useCallback(async () => {
|
|
221
268
|
const node = nodeRef.current;
|
|
222
269
|
if (!node) {
|
|
@@ -238,11 +285,15 @@ function useFiberNode(options) {
|
|
|
238
285
|
}
|
|
239
286
|
}
|
|
240
287
|
}, [detachNodeListeners]);
|
|
288
|
+
const isStarting = useMemo(() => state === "unlocking" || state === "starting", [state]);
|
|
289
|
+
const isRunning = useMemo(() => state === "running", [state]);
|
|
241
290
|
return {
|
|
242
291
|
state,
|
|
243
292
|
node: nodeRef.current,
|
|
244
293
|
nodeInfo,
|
|
245
294
|
error,
|
|
295
|
+
isStarting,
|
|
296
|
+
isRunning,
|
|
246
297
|
isPasskeySupported,
|
|
247
298
|
passkeySupportReason,
|
|
248
299
|
passkeyUnavailableReason,
|
|
@@ -250,12 +301,376 @@ function useFiberNode(options) {
|
|
|
250
301
|
startWithPassword,
|
|
251
302
|
createPasskeyAndStart,
|
|
252
303
|
startWithPasskey,
|
|
304
|
+
startWithRawKey,
|
|
253
305
|
stop
|
|
254
306
|
};
|
|
255
307
|
}
|
|
256
308
|
|
|
309
|
+
// src/connect-button.tsx
|
|
310
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
311
|
+
function truncateNodeId(id) {
|
|
312
|
+
if (id.length <= 16) return id;
|
|
313
|
+
return `${id.slice(0, 8)}\u2026${id.slice(-4)}`;
|
|
314
|
+
}
|
|
315
|
+
var styles = {
|
|
316
|
+
root: {
|
|
317
|
+
position: "relative",
|
|
318
|
+
display: "inline-flex",
|
|
319
|
+
alignItems: "center",
|
|
320
|
+
gap: "0.5rem",
|
|
321
|
+
fontFamily: "system-ui, -apple-system, sans-serif"
|
|
322
|
+
},
|
|
323
|
+
button: {
|
|
324
|
+
display: "inline-flex",
|
|
325
|
+
alignItems: "center",
|
|
326
|
+
gap: "0.5rem",
|
|
327
|
+
padding: "0.5rem 1.25rem",
|
|
328
|
+
fontSize: "0.875rem",
|
|
329
|
+
fontWeight: 600,
|
|
330
|
+
borderRadius: "9999px",
|
|
331
|
+
border: "none",
|
|
332
|
+
cursor: "pointer",
|
|
333
|
+
transition: "background-color 0.15s, opacity 0.15s",
|
|
334
|
+
lineHeight: 1.4
|
|
335
|
+
},
|
|
336
|
+
connectButton: {
|
|
337
|
+
backgroundColor: "var(--fpay-accent, #6366f1)",
|
|
338
|
+
color: "var(--fpay-accent-fg, #fff)"
|
|
339
|
+
},
|
|
340
|
+
connectedButton: {
|
|
341
|
+
backgroundColor: "var(--fpay-accent-subtle, rgba(99,102,241,0.12))",
|
|
342
|
+
color: "var(--fpay-accent, #6366f1)",
|
|
343
|
+
border: "1px solid var(--fpay-accent-border, rgba(99,102,241,0.35))"
|
|
344
|
+
},
|
|
345
|
+
disabledButton: {
|
|
346
|
+
opacity: 0.6,
|
|
347
|
+
cursor: "not-allowed"
|
|
348
|
+
},
|
|
349
|
+
statusDot: {
|
|
350
|
+
display: "inline-block",
|
|
351
|
+
width: "0.5rem",
|
|
352
|
+
height: "0.5rem",
|
|
353
|
+
borderRadius: "50%",
|
|
354
|
+
backgroundColor: "var(--fpay-accent, #6366f1)"
|
|
355
|
+
},
|
|
356
|
+
errorText: {
|
|
357
|
+
fontSize: "0.75rem",
|
|
358
|
+
color: "var(--fpay-error, #ef4444)",
|
|
359
|
+
maxWidth: "220px",
|
|
360
|
+
overflow: "hidden",
|
|
361
|
+
textOverflow: "ellipsis",
|
|
362
|
+
whiteSpace: "nowrap"
|
|
363
|
+
},
|
|
364
|
+
dropdown: {
|
|
365
|
+
position: "absolute",
|
|
366
|
+
right: 0,
|
|
367
|
+
top: "100%",
|
|
368
|
+
marginTop: "0.5rem",
|
|
369
|
+
width: "280px",
|
|
370
|
+
borderRadius: "0.75rem",
|
|
371
|
+
border: "1px solid var(--fpay-border, #e5e7eb)",
|
|
372
|
+
backgroundColor: "var(--fpay-bg-elevated, #fff)",
|
|
373
|
+
padding: "1rem",
|
|
374
|
+
boxShadow: "0 10px 25px rgba(0,0,0,0.1)",
|
|
375
|
+
zIndex: 100
|
|
376
|
+
},
|
|
377
|
+
infoRow: {
|
|
378
|
+
display: "flex",
|
|
379
|
+
justifyContent: "space-between",
|
|
380
|
+
alignItems: "center",
|
|
381
|
+
padding: "0.375rem 0",
|
|
382
|
+
fontSize: "0.75rem"
|
|
383
|
+
},
|
|
384
|
+
infoLabel: {
|
|
385
|
+
color: "var(--fpay-text-secondary, #6b7280)"
|
|
386
|
+
},
|
|
387
|
+
infoValue: {
|
|
388
|
+
fontFamily: "ui-monospace, monospace",
|
|
389
|
+
color: "var(--fpay-text-primary, #111827)"
|
|
390
|
+
},
|
|
391
|
+
separator: {
|
|
392
|
+
borderTop: "1px solid var(--fpay-border, #e5e7eb)",
|
|
393
|
+
margin: "0.75rem 0"
|
|
394
|
+
},
|
|
395
|
+
disconnectButton: {
|
|
396
|
+
display: "flex",
|
|
397
|
+
width: "100%",
|
|
398
|
+
alignItems: "center",
|
|
399
|
+
justifyContent: "space-between",
|
|
400
|
+
padding: "0.625rem 0.75rem",
|
|
401
|
+
fontSize: "0.875rem",
|
|
402
|
+
fontWeight: 600,
|
|
403
|
+
border: "1px solid var(--fpay-border, #e5e7eb)",
|
|
404
|
+
borderRadius: "0.5rem",
|
|
405
|
+
backgroundColor: "var(--fpay-bg-secondary, #f9fafb)",
|
|
406
|
+
color: "var(--fpay-text-primary, #111827)",
|
|
407
|
+
cursor: "pointer",
|
|
408
|
+
transition: "background-color 0.15s"
|
|
409
|
+
},
|
|
410
|
+
spinner: {
|
|
411
|
+
animation: "fpay-spin 1s linear infinite"
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
var KEYFRAMES_ID = "fpay-connect-button-keyframes";
|
|
415
|
+
function ensureKeyframes() {
|
|
416
|
+
if (typeof document === "undefined") return;
|
|
417
|
+
if (document.getElementById(KEYFRAMES_ID)) return;
|
|
418
|
+
const style = document.createElement("style");
|
|
419
|
+
style.id = KEYFRAMES_ID;
|
|
420
|
+
style.textContent = `@keyframes fpay-spin { to { transform: rotate(360deg); } }`;
|
|
421
|
+
document.head.appendChild(style);
|
|
422
|
+
}
|
|
423
|
+
function Spinner({ size = 16 }) {
|
|
424
|
+
return /* @__PURE__ */ jsx(
|
|
425
|
+
"svg",
|
|
426
|
+
{
|
|
427
|
+
width: size,
|
|
428
|
+
height: size,
|
|
429
|
+
viewBox: "0 0 24 24",
|
|
430
|
+
fill: "none",
|
|
431
|
+
stroke: "currentColor",
|
|
432
|
+
strokeWidth: "2",
|
|
433
|
+
strokeLinecap: "round",
|
|
434
|
+
strokeLinejoin: "round",
|
|
435
|
+
style: styles.spinner,
|
|
436
|
+
role: "img",
|
|
437
|
+
"aria-label": "Loading",
|
|
438
|
+
children: /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
|
|
439
|
+
}
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
function Chevron({ open }) {
|
|
443
|
+
return /* @__PURE__ */ jsx(
|
|
444
|
+
"svg",
|
|
445
|
+
{
|
|
446
|
+
width: "12",
|
|
447
|
+
height: "12",
|
|
448
|
+
viewBox: "0 0 24 24",
|
|
449
|
+
fill: "none",
|
|
450
|
+
stroke: "currentColor",
|
|
451
|
+
strokeWidth: "2",
|
|
452
|
+
strokeLinecap: "round",
|
|
453
|
+
strokeLinejoin: "round",
|
|
454
|
+
style: { transition: "transform 0.15s", transform: open ? "rotate(180deg)" : "none" },
|
|
455
|
+
"aria-hidden": "true",
|
|
456
|
+
children: /* @__PURE__ */ jsx("polyline", { points: "6 9 12 15 18 9" })
|
|
457
|
+
}
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
function ConnectButton(props) {
|
|
461
|
+
const {
|
|
462
|
+
network = "testnet",
|
|
463
|
+
fiber: externalFiber,
|
|
464
|
+
strategy,
|
|
465
|
+
password,
|
|
466
|
+
walletId,
|
|
467
|
+
passkeyUsername = "User",
|
|
468
|
+
wasmFactory,
|
|
469
|
+
nodeConfig,
|
|
470
|
+
className,
|
|
471
|
+
style,
|
|
472
|
+
dropdownStyle,
|
|
473
|
+
renderConnectedDropdown,
|
|
474
|
+
onConnect,
|
|
475
|
+
onDisconnect,
|
|
476
|
+
onError
|
|
477
|
+
} = props;
|
|
478
|
+
const internalFiber = useFiberNode({
|
|
479
|
+
network,
|
|
480
|
+
walletId,
|
|
481
|
+
wasmFactory,
|
|
482
|
+
nodeConfig,
|
|
483
|
+
enabled: !externalFiber
|
|
484
|
+
});
|
|
485
|
+
const fiber = externalFiber ?? internalFiber;
|
|
486
|
+
const {
|
|
487
|
+
state,
|
|
488
|
+
node,
|
|
489
|
+
nodeInfo,
|
|
490
|
+
error,
|
|
491
|
+
isStarting,
|
|
492
|
+
isRunning,
|
|
493
|
+
isPasskeySupported,
|
|
494
|
+
passkeyUnavailableReason,
|
|
495
|
+
hasPasskeyConfigured,
|
|
496
|
+
createPasskeyAndStart,
|
|
497
|
+
startWithPasskey,
|
|
498
|
+
startWithPassword,
|
|
499
|
+
stop
|
|
500
|
+
} = fiber;
|
|
501
|
+
const [isConnecting, setIsConnecting] = useState2(false);
|
|
502
|
+
const [showDropdown, setShowDropdown] = useState2(false);
|
|
503
|
+
const [localError, setLocalError] = useState2(null);
|
|
504
|
+
const dropdownRef = useRef2(null);
|
|
505
|
+
const effectiveIsStarting = isConnecting || isStarting;
|
|
506
|
+
useEffect2(() => ensureKeyframes(), []);
|
|
507
|
+
useEffect2(() => {
|
|
508
|
+
if (!showDropdown) return;
|
|
509
|
+
function handleClickOutside(e) {
|
|
510
|
+
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
511
|
+
setShowDropdown(false);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
515
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
516
|
+
}, [showDropdown]);
|
|
517
|
+
const prevRunningRef = useRef2(false);
|
|
518
|
+
useEffect2(() => {
|
|
519
|
+
if (isRunning && !prevRunningRef.current && node && nodeInfo) {
|
|
520
|
+
onConnect?.(node, nodeInfo);
|
|
521
|
+
}
|
|
522
|
+
if (!isRunning && prevRunningRef.current) {
|
|
523
|
+
onDisconnect?.();
|
|
524
|
+
}
|
|
525
|
+
prevRunningRef.current = isRunning;
|
|
526
|
+
}, [isRunning, node, nodeInfo, onConnect, onDisconnect]);
|
|
527
|
+
useEffect2(() => {
|
|
528
|
+
if (error) onError?.(error);
|
|
529
|
+
}, [error, onError]);
|
|
530
|
+
const handleConnect = useCallback2(async () => {
|
|
531
|
+
setIsConnecting(true);
|
|
532
|
+
setLocalError(null);
|
|
533
|
+
try {
|
|
534
|
+
switch (strategy) {
|
|
535
|
+
case "password":
|
|
536
|
+
if (!password) throw new Error('Password is required for "password" strategy');
|
|
537
|
+
await startWithPassword(password);
|
|
538
|
+
break;
|
|
539
|
+
case "passkey":
|
|
540
|
+
if (hasPasskeyConfigured) {
|
|
541
|
+
await startWithPasskey();
|
|
542
|
+
} else {
|
|
543
|
+
await createPasskeyAndStart(passkeyUsername);
|
|
544
|
+
}
|
|
545
|
+
break;
|
|
546
|
+
}
|
|
547
|
+
} catch (err) {
|
|
548
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
549
|
+
setLocalError(msg);
|
|
550
|
+
onError?.(msg);
|
|
551
|
+
} finally {
|
|
552
|
+
setIsConnecting(false);
|
|
553
|
+
}
|
|
554
|
+
}, [
|
|
555
|
+
strategy,
|
|
556
|
+
password,
|
|
557
|
+
passkeyUsername,
|
|
558
|
+
hasPasskeyConfigured,
|
|
559
|
+
startWithPassword,
|
|
560
|
+
startWithPasskey,
|
|
561
|
+
createPasskeyAndStart,
|
|
562
|
+
onError
|
|
563
|
+
]);
|
|
564
|
+
const handleDisconnect = useCallback2(async () => {
|
|
565
|
+
try {
|
|
566
|
+
await stop();
|
|
567
|
+
} catch (err) {
|
|
568
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
569
|
+
setLocalError(msg);
|
|
570
|
+
onError?.(msg);
|
|
571
|
+
} finally {
|
|
572
|
+
setShowDropdown(false);
|
|
573
|
+
}
|
|
574
|
+
}, [stop, onError]);
|
|
575
|
+
const closeDropdown = useCallback2(() => {
|
|
576
|
+
setShowDropdown(false);
|
|
577
|
+
}, []);
|
|
578
|
+
const hasError = !!(error || localError);
|
|
579
|
+
let buttonLabel;
|
|
580
|
+
let buttonOnClick;
|
|
581
|
+
let buttonDisabled = false;
|
|
582
|
+
let buttonStyle;
|
|
583
|
+
if (isRunning) {
|
|
584
|
+
buttonLabel = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
585
|
+
/* @__PURE__ */ jsx("span", { style: styles.statusDot }),
|
|
586
|
+
/* @__PURE__ */ jsx("span", { style: { fontFamily: "ui-monospace, monospace" }, children: nodeInfo?.pubkey ? truncateNodeId(nodeInfo.pubkey) : "Connected" }),
|
|
587
|
+
/* @__PURE__ */ jsx(Chevron, { open: showDropdown })
|
|
588
|
+
] });
|
|
589
|
+
buttonOnClick = () => setShowDropdown((s) => !s);
|
|
590
|
+
buttonStyle = { ...styles.button, ...styles.connectedButton };
|
|
591
|
+
} else if (effectiveIsStarting) {
|
|
592
|
+
buttonLabel = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
593
|
+
/* @__PURE__ */ jsx(Spinner, {}),
|
|
594
|
+
"Connecting\u2026"
|
|
595
|
+
] });
|
|
596
|
+
buttonDisabled = true;
|
|
597
|
+
buttonStyle = { ...styles.button, ...styles.connectButton, ...styles.disabledButton };
|
|
598
|
+
} else {
|
|
599
|
+
switch (strategy) {
|
|
600
|
+
case "passkey":
|
|
601
|
+
buttonLabel = hasPasskeyConfigured ? "Connect with Passkey" : "Connect via Passkey";
|
|
602
|
+
if (!isPasskeySupported) {
|
|
603
|
+
buttonLabel = "Passkey unavailable";
|
|
604
|
+
buttonDisabled = true;
|
|
605
|
+
}
|
|
606
|
+
break;
|
|
607
|
+
case "password":
|
|
608
|
+
buttonLabel = "Connect";
|
|
609
|
+
break;
|
|
610
|
+
}
|
|
611
|
+
buttonOnClick = handleConnect;
|
|
612
|
+
buttonStyle = {
|
|
613
|
+
...styles.button,
|
|
614
|
+
...styles.connectButton,
|
|
615
|
+
...buttonDisabled ? styles.disabledButton : {}
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
return /* @__PURE__ */ jsxs("div", { className, style: { ...styles.root, ...style }, "data-fpay-connect-button": "", children: [
|
|
619
|
+
(hasError || !isPasskeySupported && passkeyUnavailableReason && strategy === "passkey") && /* @__PURE__ */ jsx("span", { style: styles.errorText, children: error || localError || passkeyUnavailableReason }),
|
|
620
|
+
isRunning ? /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, ref: dropdownRef, children: [
|
|
621
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: buttonOnClick, style: buttonStyle, children: buttonLabel }),
|
|
622
|
+
showDropdown && /* @__PURE__ */ jsx("div", { style: { ...styles.dropdown, ...dropdownStyle }, children: renderConnectedDropdown ? renderConnectedDropdown({
|
|
623
|
+
fiber,
|
|
624
|
+
closeDropdown,
|
|
625
|
+
disconnect: handleDisconnect
|
|
626
|
+
}) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
627
|
+
nodeInfo && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
628
|
+
/* @__PURE__ */ jsxs("div", { style: styles.infoRow, children: [
|
|
629
|
+
/* @__PURE__ */ jsx("span", { style: styles.infoLabel, children: "Pubkey" }),
|
|
630
|
+
/* @__PURE__ */ jsx("span", { style: styles.infoValue, children: truncateNodeId(nodeInfo.pubkey) })
|
|
631
|
+
] }),
|
|
632
|
+
/* @__PURE__ */ jsxs("div", { style: styles.infoRow, children: [
|
|
633
|
+
/* @__PURE__ */ jsx("span", { style: styles.infoLabel, children: "State" }),
|
|
634
|
+
/* @__PURE__ */ jsx("span", { style: styles.infoValue, children: state })
|
|
635
|
+
] })
|
|
636
|
+
] }),
|
|
637
|
+
/* @__PURE__ */ jsx("div", { style: styles.separator }),
|
|
638
|
+
/* @__PURE__ */ jsxs(
|
|
639
|
+
"button",
|
|
640
|
+
{
|
|
641
|
+
type: "button",
|
|
642
|
+
onClick: () => void handleDisconnect(),
|
|
643
|
+
style: styles.disconnectButton,
|
|
644
|
+
children: [
|
|
645
|
+
/* @__PURE__ */ jsx("span", { children: "Disconnect" }),
|
|
646
|
+
/* @__PURE__ */ jsx(
|
|
647
|
+
"svg",
|
|
648
|
+
{
|
|
649
|
+
width: "14",
|
|
650
|
+
height: "14",
|
|
651
|
+
viewBox: "0 0 24 24",
|
|
652
|
+
fill: "none",
|
|
653
|
+
stroke: "currentColor",
|
|
654
|
+
strokeWidth: "2",
|
|
655
|
+
strokeLinecap: "round",
|
|
656
|
+
strokeLinejoin: "round",
|
|
657
|
+
"aria-hidden": "true",
|
|
658
|
+
children: /* @__PURE__ */ jsx("path", { d: "M9 18l6-6-6-6" })
|
|
659
|
+
}
|
|
660
|
+
)
|
|
661
|
+
]
|
|
662
|
+
}
|
|
663
|
+
)
|
|
664
|
+
] }) })
|
|
665
|
+
] }) : /* @__PURE__ */ jsx("button", { type: "button", onClick: buttonOnClick, disabled: buttonDisabled, style: buttonStyle, children: buttonLabel })
|
|
666
|
+
] });
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
// src/fiber-pay-quick-card.tsx
|
|
670
|
+
import { useEffect as useEffect4, useId, useState as useState4 } from "react";
|
|
671
|
+
|
|
257
672
|
// src/use-fiber-payment.ts
|
|
258
|
-
import { useCallback as
|
|
673
|
+
import { useCallback as useCallback3, useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
|
|
259
674
|
function asErrorMessage2(error) {
|
|
260
675
|
if (error instanceof Error) {
|
|
261
676
|
return error.message;
|
|
@@ -263,17 +678,17 @@ function asErrorMessage2(error) {
|
|
|
263
678
|
return String(error);
|
|
264
679
|
}
|
|
265
680
|
function useFiberPayment(node) {
|
|
266
|
-
const [isPaying, setIsPaying] =
|
|
267
|
-
const [paymentResult, setPaymentResult] =
|
|
268
|
-
const [error, setError] =
|
|
269
|
-
const isMountedRef =
|
|
270
|
-
|
|
681
|
+
const [isPaying, setIsPaying] = useState3(false);
|
|
682
|
+
const [paymentResult, setPaymentResult] = useState3(null);
|
|
683
|
+
const [error, setError] = useState3(null);
|
|
684
|
+
const isMountedRef = useRef3(true);
|
|
685
|
+
useEffect3(
|
|
271
686
|
() => () => {
|
|
272
687
|
isMountedRef.current = false;
|
|
273
688
|
},
|
|
274
689
|
[]
|
|
275
690
|
);
|
|
276
|
-
const payInvoice =
|
|
691
|
+
const payInvoice = useCallback3(
|
|
277
692
|
async (invoice) => {
|
|
278
693
|
if (!node) {
|
|
279
694
|
if (isMountedRef.current) {
|
|
@@ -318,7 +733,7 @@ function useFiberPayment(node) {
|
|
|
318
733
|
}
|
|
319
734
|
|
|
320
735
|
// src/fiber-pay-quick-card.tsx
|
|
321
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
736
|
+
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
322
737
|
var ONE_CKB_SHANNONS = "0x5f5e100";
|
|
323
738
|
var cardStyle = {
|
|
324
739
|
border: "1px solid #ddd",
|
|
@@ -356,22 +771,22 @@ function FiberPayQuickCard(props) {
|
|
|
356
771
|
stop
|
|
357
772
|
} = useFiberNode({ network, walletId: props.walletId });
|
|
358
773
|
const { payInvoice, isPaying, error: payError, paymentResult } = useFiberPayment(node);
|
|
359
|
-
const [password, setPassword] =
|
|
360
|
-
const [invoiceInput, setInvoiceInput] =
|
|
361
|
-
const [createdInvoice, setCreatedInvoice] =
|
|
362
|
-
const [isCreatingInvoice, setIsCreatingInvoice] =
|
|
363
|
-
const [invoiceError, setInvoiceError] =
|
|
364
|
-
|
|
774
|
+
const [password, setPassword] = useState4("");
|
|
775
|
+
const [invoiceInput, setInvoiceInput] = useState4("");
|
|
776
|
+
const [createdInvoice, setCreatedInvoice] = useState4("");
|
|
777
|
+
const [isCreatingInvoice, setIsCreatingInvoice] = useState4(false);
|
|
778
|
+
const [invoiceError, setInvoiceError] = useState4(null);
|
|
779
|
+
useEffect4(() => {
|
|
365
780
|
if (nodeError) {
|
|
366
781
|
onError?.({ scope: "node", message: nodeError });
|
|
367
782
|
}
|
|
368
783
|
}, [nodeError, onError]);
|
|
369
|
-
|
|
784
|
+
useEffect4(() => {
|
|
370
785
|
if (payError) {
|
|
371
786
|
onError?.({ scope: "payment", message: payError });
|
|
372
787
|
}
|
|
373
788
|
}, [onError, payError]);
|
|
374
|
-
|
|
789
|
+
useEffect4(() => {
|
|
375
790
|
if (paymentResult) {
|
|
376
791
|
onPaymentResult?.(paymentResult);
|
|
377
792
|
}
|
|
@@ -398,18 +813,18 @@ function FiberPayQuickCard(props) {
|
|
|
398
813
|
setIsCreatingInvoice(false);
|
|
399
814
|
}
|
|
400
815
|
};
|
|
401
|
-
return /* @__PURE__ */
|
|
402
|
-
/* @__PURE__ */
|
|
816
|
+
return /* @__PURE__ */ jsxs2("div", { style: { ...cardStyle, ...props.style }, className: props.className, children: [
|
|
817
|
+
/* @__PURE__ */ jsxs2("h3", { children: [
|
|
403
818
|
title,
|
|
404
819
|
" (",
|
|
405
820
|
network,
|
|
406
821
|
")"
|
|
407
822
|
] }),
|
|
408
|
-
!nodeInfo ? /* @__PURE__ */
|
|
409
|
-
isPasskeySupported ? /* @__PURE__ */
|
|
410
|
-
/* @__PURE__ */
|
|
411
|
-
/* @__PURE__ */
|
|
412
|
-
/* @__PURE__ */
|
|
823
|
+
!nodeInfo ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
824
|
+
isPasskeySupported ? /* @__PURE__ */ jsx2("div", { style: rowWithMarginStyle, children: hasPasskeyConfigured ? /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => void startWithPasskey(), children: "Login with Passkey" }) : /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => void createPasskeyAndStart(passkeyUsername), children: "Register Passkey" }) }) : null,
|
|
825
|
+
/* @__PURE__ */ jsx2("label", { htmlFor: passwordInputId, children: "Password" }),
|
|
826
|
+
/* @__PURE__ */ jsxs2("div", { style: rowStyle, children: [
|
|
827
|
+
/* @__PURE__ */ jsx2(
|
|
413
828
|
"input",
|
|
414
829
|
{
|
|
415
830
|
id: passwordInputId,
|
|
@@ -421,31 +836,31 @@ function FiberPayQuickCard(props) {
|
|
|
421
836
|
placeholder: "Password"
|
|
422
837
|
}
|
|
423
838
|
),
|
|
424
|
-
/* @__PURE__ */
|
|
839
|
+
/* @__PURE__ */ jsx2("button", { type: "button", onClick: () => void startWithPassword(password), children: "Start with Password" })
|
|
425
840
|
] })
|
|
426
|
-
] }) : /* @__PURE__ */
|
|
427
|
-
/* @__PURE__ */
|
|
428
|
-
/* @__PURE__ */
|
|
841
|
+
] }) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
842
|
+
/* @__PURE__ */ jsxs2("p", { children: [
|
|
843
|
+
/* @__PURE__ */ jsx2("strong", { children: "State:" }),
|
|
429
844
|
" ",
|
|
430
845
|
state
|
|
431
846
|
] }),
|
|
432
|
-
/* @__PURE__ */
|
|
433
|
-
/* @__PURE__ */
|
|
847
|
+
/* @__PURE__ */ jsxs2("p", { children: [
|
|
848
|
+
/* @__PURE__ */ jsx2("strong", { children: "Pubkey:" }),
|
|
434
849
|
" ",
|
|
435
850
|
nodeInfo.pubkey
|
|
436
851
|
] }),
|
|
437
|
-
/* @__PURE__ */
|
|
438
|
-
/* @__PURE__ */
|
|
439
|
-
/* @__PURE__ */
|
|
852
|
+
/* @__PURE__ */ jsxs2("div", { style: rowWithMarginStyle, children: [
|
|
853
|
+
/* @__PURE__ */ jsx2("button", { type: "button", onClick: () => void createInvoice(), disabled: isCreatingInvoice, children: isCreatingInvoice ? "Creating..." : "Create Invoice (1 CKB)" }),
|
|
854
|
+
/* @__PURE__ */ jsx2("button", { type: "button", onClick: () => void stop(), children: "Stop Node" })
|
|
440
855
|
] }),
|
|
441
|
-
createdInvoice ? /* @__PURE__ */
|
|
442
|
-
/* @__PURE__ */
|
|
856
|
+
createdInvoice ? /* @__PURE__ */ jsxs2("p", { children: [
|
|
857
|
+
/* @__PURE__ */ jsx2("strong", { children: "Created invoice:" }),
|
|
443
858
|
" ",
|
|
444
859
|
createdInvoice
|
|
445
860
|
] }) : null,
|
|
446
|
-
/* @__PURE__ */
|
|
447
|
-
/* @__PURE__ */
|
|
448
|
-
/* @__PURE__ */
|
|
861
|
+
/* @__PURE__ */ jsx2("label", { htmlFor: invoiceInputId, children: "Invoice" }),
|
|
862
|
+
/* @__PURE__ */ jsxs2("div", { style: rowStyle, children: [
|
|
863
|
+
/* @__PURE__ */ jsx2(
|
|
449
864
|
"input",
|
|
450
865
|
{
|
|
451
866
|
id: invoiceInputId,
|
|
@@ -455,33 +870,439 @@ function FiberPayQuickCard(props) {
|
|
|
455
870
|
placeholder: "Paste invoice to pay"
|
|
456
871
|
}
|
|
457
872
|
),
|
|
458
|
-
/* @__PURE__ */
|
|
873
|
+
/* @__PURE__ */ jsx2("button", { type: "button", onClick: () => void payInvoice(invoiceInput), disabled: isPaying, children: isPaying ? "Paying..." : "Pay" })
|
|
459
874
|
] }),
|
|
460
|
-
paymentResult ? /* @__PURE__ */
|
|
461
|
-
/* @__PURE__ */
|
|
875
|
+
paymentResult ? /* @__PURE__ */ jsxs2("p", { children: [
|
|
876
|
+
/* @__PURE__ */ jsx2("strong", { children: "Payment:" }),
|
|
462
877
|
" ",
|
|
463
878
|
paymentResult.status
|
|
464
879
|
] }) : null
|
|
465
880
|
] }),
|
|
466
|
-
nodeError ? /* @__PURE__ */
|
|
467
|
-
/* @__PURE__ */
|
|
881
|
+
nodeError ? /* @__PURE__ */ jsxs2("p", { style: { color: "#b91c1c" }, children: [
|
|
882
|
+
/* @__PURE__ */ jsx2("strong", { children: "Node error:" }),
|
|
468
883
|
" ",
|
|
469
884
|
nodeError
|
|
470
885
|
] }) : null,
|
|
471
|
-
payError ? /* @__PURE__ */
|
|
472
|
-
/* @__PURE__ */
|
|
886
|
+
payError ? /* @__PURE__ */ jsxs2("p", { style: { color: "#b91c1c" }, children: [
|
|
887
|
+
/* @__PURE__ */ jsx2("strong", { children: "Payment error:" }),
|
|
473
888
|
" ",
|
|
474
889
|
payError
|
|
475
890
|
] }) : null,
|
|
476
|
-
invoiceError ? /* @__PURE__ */
|
|
477
|
-
/* @__PURE__ */
|
|
891
|
+
invoiceError ? /* @__PURE__ */ jsxs2("p", { style: { color: "#b91c1c" }, children: [
|
|
892
|
+
/* @__PURE__ */ jsx2("strong", { children: "Invoice error:" }),
|
|
478
893
|
" ",
|
|
479
894
|
invoiceError
|
|
480
895
|
] }) : null
|
|
481
896
|
] });
|
|
482
897
|
}
|
|
898
|
+
|
|
899
|
+
// src/node-info-panel.tsx
|
|
900
|
+
import {
|
|
901
|
+
ConfigBuilder,
|
|
902
|
+
formatShannonsAsCkb,
|
|
903
|
+
getLockBalanceShannons,
|
|
904
|
+
scriptToAddress
|
|
905
|
+
} from "@fiber-pay/sdk/browser";
|
|
906
|
+
import {
|
|
907
|
+
useCallback as useCallback4,
|
|
908
|
+
useEffect as useEffect5,
|
|
909
|
+
useRef as useRef4,
|
|
910
|
+
useState as useState5
|
|
911
|
+
} from "react";
|
|
912
|
+
import { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
913
|
+
function truncateMiddle(str, left = 8, right = 8) {
|
|
914
|
+
if (str.length <= left + right + 3) return str;
|
|
915
|
+
return `${str.slice(0, left)}\u2026${str.slice(-right)}`;
|
|
916
|
+
}
|
|
917
|
+
function copyToClipboard(text) {
|
|
918
|
+
void navigator.clipboard.writeText(text);
|
|
919
|
+
}
|
|
920
|
+
async function fetchNodeStats(node, network) {
|
|
921
|
+
const [nodeInfo, peers, channels] = await Promise.all([
|
|
922
|
+
node.nodeInfo(),
|
|
923
|
+
node.listPeers(),
|
|
924
|
+
node.listChannels()
|
|
925
|
+
]);
|
|
926
|
+
const lockScript = nodeInfo.default_funding_lock_script;
|
|
927
|
+
const ckbRpcUrl = ConfigBuilder.getDefaults(network).ckbRpcUrl;
|
|
928
|
+
if (!lockScript || lockScript.args === "0x") {
|
|
929
|
+
return {
|
|
930
|
+
pubkey: nodeInfo.pubkey,
|
|
931
|
+
peers: peers.peers.length,
|
|
932
|
+
channels: channels.channels.length,
|
|
933
|
+
ckbAddress: null,
|
|
934
|
+
balanceCkb: null,
|
|
935
|
+
externalFunding: true
|
|
936
|
+
};
|
|
937
|
+
}
|
|
938
|
+
const ckbAddress = scriptToAddress(lockScript, network);
|
|
939
|
+
const balanceShannons = await getLockBalanceShannons(ckbRpcUrl, lockScript);
|
|
940
|
+
const balanceCkb = formatShannonsAsCkb(balanceShannons, 4);
|
|
941
|
+
return {
|
|
942
|
+
pubkey: nodeInfo.pubkey,
|
|
943
|
+
peers: peers.peers.length,
|
|
944
|
+
channels: channels.channels.length,
|
|
945
|
+
ckbAddress,
|
|
946
|
+
balanceCkb,
|
|
947
|
+
externalFunding: false
|
|
948
|
+
};
|
|
949
|
+
}
|
|
950
|
+
var styles2 = {
|
|
951
|
+
root: {
|
|
952
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
953
|
+
fontSize: "0.875rem",
|
|
954
|
+
color: "var(--fpay-text-primary, #111827)"
|
|
955
|
+
},
|
|
956
|
+
idle: {
|
|
957
|
+
padding: "1rem",
|
|
958
|
+
textAlign: "center",
|
|
959
|
+
color: "var(--fpay-text-secondary, #6b7280)",
|
|
960
|
+
fontSize: "0.75rem"
|
|
961
|
+
},
|
|
962
|
+
loading: {
|
|
963
|
+
display: "flex",
|
|
964
|
+
alignItems: "center",
|
|
965
|
+
gap: "0.5rem",
|
|
966
|
+
padding: "0.5rem 0",
|
|
967
|
+
fontSize: "0.75rem",
|
|
968
|
+
color: "var(--fpay-text-secondary, #6b7280)"
|
|
969
|
+
},
|
|
970
|
+
errorBox: {
|
|
971
|
+
marginBottom: "0.5rem",
|
|
972
|
+
padding: "0.375rem 0.5rem",
|
|
973
|
+
fontSize: "0.75rem",
|
|
974
|
+
borderRadius: "0.5rem",
|
|
975
|
+
border: "1px solid var(--fpay-error-border, rgba(239,68,68,0.3))",
|
|
976
|
+
backgroundColor: "var(--fpay-error-bg, rgba(239,68,68,0.1))",
|
|
977
|
+
color: "var(--fpay-error, #ef4444)"
|
|
978
|
+
},
|
|
979
|
+
infoRow: {
|
|
980
|
+
display: "flex",
|
|
981
|
+
justifyContent: "space-between",
|
|
982
|
+
alignItems: "center",
|
|
983
|
+
gap: "0.75rem",
|
|
984
|
+
padding: "0.375rem 0"
|
|
985
|
+
},
|
|
986
|
+
infoLabel: {
|
|
987
|
+
fontSize: "0.75rem",
|
|
988
|
+
color: "var(--fpay-text-secondary, #6b7280)"
|
|
989
|
+
},
|
|
990
|
+
infoValueWrapper: {
|
|
991
|
+
display: "flex",
|
|
992
|
+
alignItems: "center",
|
|
993
|
+
gap: "0.375rem"
|
|
994
|
+
},
|
|
995
|
+
infoValue: {
|
|
996
|
+
fontFamily: "ui-monospace, monospace",
|
|
997
|
+
fontSize: "0.75rem",
|
|
998
|
+
color: "var(--fpay-text-primary, #111827)"
|
|
999
|
+
},
|
|
1000
|
+
copyButton: {
|
|
1001
|
+
display: "inline-flex",
|
|
1002
|
+
alignItems: "center",
|
|
1003
|
+
justifyContent: "center",
|
|
1004
|
+
padding: "0.25rem",
|
|
1005
|
+
borderRadius: "0.25rem",
|
|
1006
|
+
border: "none",
|
|
1007
|
+
background: "none",
|
|
1008
|
+
cursor: "pointer",
|
|
1009
|
+
color: "var(--fpay-text-secondary, #6b7280)",
|
|
1010
|
+
transition: "color 0.15s"
|
|
1011
|
+
},
|
|
1012
|
+
statsGrid: {
|
|
1013
|
+
display: "grid",
|
|
1014
|
+
gridTemplateColumns: "1fr 1fr",
|
|
1015
|
+
gap: "0.5rem",
|
|
1016
|
+
marginTop: "0.5rem"
|
|
1017
|
+
},
|
|
1018
|
+
statCard: {
|
|
1019
|
+
padding: "0.375rem 0.5rem",
|
|
1020
|
+
textAlign: "center",
|
|
1021
|
+
borderRadius: "0.5rem",
|
|
1022
|
+
border: "1px solid var(--fpay-border, #e5e7eb)",
|
|
1023
|
+
backgroundColor: "var(--fpay-bg-secondary, #f9fafb)"
|
|
1024
|
+
},
|
|
1025
|
+
statLabel: {
|
|
1026
|
+
fontSize: "0.625rem",
|
|
1027
|
+
color: "var(--fpay-text-secondary, #6b7280)"
|
|
1028
|
+
},
|
|
1029
|
+
statValue: {
|
|
1030
|
+
fontSize: "0.875rem",
|
|
1031
|
+
fontWeight: 600,
|
|
1032
|
+
color: "var(--fpay-text-primary, #111827)"
|
|
1033
|
+
},
|
|
1034
|
+
qrContainer: {
|
|
1035
|
+
display: "flex",
|
|
1036
|
+
flexDirection: "column",
|
|
1037
|
+
alignItems: "center",
|
|
1038
|
+
gap: "0.25rem",
|
|
1039
|
+
marginTop: "0.75rem",
|
|
1040
|
+
padding: "0.5rem",
|
|
1041
|
+
borderRadius: "0.5rem",
|
|
1042
|
+
border: "1px solid var(--fpay-border, #e5e7eb)",
|
|
1043
|
+
backgroundColor: "var(--fpay-bg-secondary, #f9fafb)"
|
|
1044
|
+
},
|
|
1045
|
+
qrCaption: {
|
|
1046
|
+
fontSize: "0.625rem",
|
|
1047
|
+
color: "var(--fpay-text-secondary, #6b7280)"
|
|
1048
|
+
},
|
|
1049
|
+
balanceRow: {
|
|
1050
|
+
display: "flex",
|
|
1051
|
+
justifyContent: "space-between",
|
|
1052
|
+
alignItems: "center",
|
|
1053
|
+
width: "100%",
|
|
1054
|
+
marginTop: "0.5rem",
|
|
1055
|
+
paddingTop: "0.5rem",
|
|
1056
|
+
borderTop: "1px solid var(--fpay-border, #e5e7eb)"
|
|
1057
|
+
},
|
|
1058
|
+
statusBadge: {
|
|
1059
|
+
display: "inline-flex",
|
|
1060
|
+
alignItems: "center",
|
|
1061
|
+
gap: "0.375rem",
|
|
1062
|
+
padding: "0.25rem 0.625rem",
|
|
1063
|
+
fontSize: "0.75rem",
|
|
1064
|
+
fontWeight: 500,
|
|
1065
|
+
borderRadius: "9999px",
|
|
1066
|
+
marginBottom: "0.5rem"
|
|
1067
|
+
}
|
|
1068
|
+
};
|
|
1069
|
+
var STATUS_COLORS = {
|
|
1070
|
+
idle: { bg: "rgba(107,114,128,0.1)", fg: "#6b7280", dot: "#9ca3af" },
|
|
1071
|
+
unlocking: { bg: "rgba(245,158,11,0.1)", fg: "#d97706", dot: "#f59e0b" },
|
|
1072
|
+
starting: { bg: "rgba(245,158,11,0.1)", fg: "#d97706", dot: "#f59e0b" },
|
|
1073
|
+
running: { bg: "rgba(34,197,94,0.1)", fg: "#16a34a", dot: "#22c55e" },
|
|
1074
|
+
stopping: { bg: "rgba(245,158,11,0.1)", fg: "#d97706", dot: "#f59e0b" },
|
|
1075
|
+
stopped: { bg: "rgba(107,114,128,0.1)", fg: "#6b7280", dot: "#9ca3af" },
|
|
1076
|
+
error: { bg: "rgba(239,68,68,0.1)", fg: "#dc2626", dot: "#ef4444" }
|
|
1077
|
+
};
|
|
1078
|
+
function CopyIcon() {
|
|
1079
|
+
return /* @__PURE__ */ jsxs3(
|
|
1080
|
+
"svg",
|
|
1081
|
+
{
|
|
1082
|
+
width: "12",
|
|
1083
|
+
height: "12",
|
|
1084
|
+
viewBox: "0 0 24 24",
|
|
1085
|
+
fill: "none",
|
|
1086
|
+
stroke: "currentColor",
|
|
1087
|
+
strokeWidth: "2",
|
|
1088
|
+
strokeLinecap: "round",
|
|
1089
|
+
strokeLinejoin: "round",
|
|
1090
|
+
"aria-hidden": "true",
|
|
1091
|
+
children: [
|
|
1092
|
+
/* @__PURE__ */ jsx3("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
|
|
1093
|
+
/* @__PURE__ */ jsx3("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
|
|
1094
|
+
]
|
|
1095
|
+
}
|
|
1096
|
+
);
|
|
1097
|
+
}
|
|
1098
|
+
function InfoRow({ label, value, copyable }) {
|
|
1099
|
+
return /* @__PURE__ */ jsxs3("div", { style: styles2.infoRow, children: [
|
|
1100
|
+
/* @__PURE__ */ jsx3("span", { style: styles2.infoLabel, children: label }),
|
|
1101
|
+
/* @__PURE__ */ jsxs3("div", { style: styles2.infoValueWrapper, children: [
|
|
1102
|
+
/* @__PURE__ */ jsx3("span", { style: styles2.infoValue, children: truncateMiddle(value, 6, 6) }),
|
|
1103
|
+
copyable && /* @__PURE__ */ jsx3(
|
|
1104
|
+
"button",
|
|
1105
|
+
{
|
|
1106
|
+
type: "button",
|
|
1107
|
+
onClick: () => copyToClipboard(value),
|
|
1108
|
+
style: styles2.copyButton,
|
|
1109
|
+
title: "Copy to clipboard",
|
|
1110
|
+
"aria-label": `Copy ${label}`,
|
|
1111
|
+
children: /* @__PURE__ */ jsx3(CopyIcon, {})
|
|
1112
|
+
}
|
|
1113
|
+
)
|
|
1114
|
+
] })
|
|
1115
|
+
] });
|
|
1116
|
+
}
|
|
1117
|
+
function NodeInfoPanel(props) {
|
|
1118
|
+
const {
|
|
1119
|
+
node,
|
|
1120
|
+
network,
|
|
1121
|
+
pollInterval = 15e3,
|
|
1122
|
+
showQrCode = false,
|
|
1123
|
+
renderQrCode,
|
|
1124
|
+
className,
|
|
1125
|
+
style
|
|
1126
|
+
} = props;
|
|
1127
|
+
const [stats, setStats] = useState5(null);
|
|
1128
|
+
const [statsError, setStatsError] = useState5(null);
|
|
1129
|
+
const [statsLoading, setStatsLoading] = useState5(false);
|
|
1130
|
+
const cancelledRef = useRef4(false);
|
|
1131
|
+
const [QRComponent, setQRComponent] = useState5(null);
|
|
1132
|
+
useEffect5(() => {
|
|
1133
|
+
let cancelled = false;
|
|
1134
|
+
if (!showQrCode || renderQrCode) return;
|
|
1135
|
+
import("qrcode.react").then((mod) => {
|
|
1136
|
+
if (cancelled) return;
|
|
1137
|
+
const Comp = mod.QRCodeSVG ?? mod.default;
|
|
1138
|
+
if (Comp) setQRComponent(() => Comp);
|
|
1139
|
+
}).catch(() => {
|
|
1140
|
+
});
|
|
1141
|
+
return () => {
|
|
1142
|
+
cancelled = true;
|
|
1143
|
+
};
|
|
1144
|
+
}, [showQrCode, renderQrCode]);
|
|
1145
|
+
const loadingRef = useRef4(false);
|
|
1146
|
+
const loadStats = useCallback4(async () => {
|
|
1147
|
+
if (!node || node.state !== "running" || loadingRef.current) return;
|
|
1148
|
+
loadingRef.current = true;
|
|
1149
|
+
setStatsLoading(true);
|
|
1150
|
+
setStatsError(null);
|
|
1151
|
+
try {
|
|
1152
|
+
const data = await fetchNodeStats(node, network);
|
|
1153
|
+
if (!cancelledRef.current) setStats(data);
|
|
1154
|
+
} catch (e) {
|
|
1155
|
+
if (!cancelledRef.current) {
|
|
1156
|
+
setStatsError(e instanceof Error ? e.message : String(e));
|
|
1157
|
+
}
|
|
1158
|
+
} finally {
|
|
1159
|
+
loadingRef.current = false;
|
|
1160
|
+
if (!cancelledRef.current) setStatsLoading(false);
|
|
1161
|
+
}
|
|
1162
|
+
}, [node, network]);
|
|
1163
|
+
useEffect5(() => {
|
|
1164
|
+
cancelledRef.current = false;
|
|
1165
|
+
if (!node || node.state !== "running") {
|
|
1166
|
+
setStats(null);
|
|
1167
|
+
setStatsError(null);
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
void loadStats();
|
|
1171
|
+
const interval = setInterval(() => void loadStats(), pollInterval);
|
|
1172
|
+
return () => {
|
|
1173
|
+
cancelledRef.current = true;
|
|
1174
|
+
clearInterval(interval);
|
|
1175
|
+
};
|
|
1176
|
+
}, [node, node?.state, pollInterval, loadStats]);
|
|
1177
|
+
if (!node) {
|
|
1178
|
+
return /* @__PURE__ */ jsx3("div", { className, style: { ...styles2.root, ...style }, "data-fpay-node-info": "", children: /* @__PURE__ */ jsx3("div", { style: styles2.idle, children: "No node connected" }) });
|
|
1179
|
+
}
|
|
1180
|
+
const nodeState = node.state;
|
|
1181
|
+
const statusColor = STATUS_COLORS[nodeState] ?? STATUS_COLORS.idle;
|
|
1182
|
+
return /* @__PURE__ */ jsxs3("div", { className, style: { ...styles2.root, ...style }, "data-fpay-node-info": "", children: [
|
|
1183
|
+
/* @__PURE__ */ jsxs3(
|
|
1184
|
+
"div",
|
|
1185
|
+
{
|
|
1186
|
+
style: {
|
|
1187
|
+
...styles2.statusBadge,
|
|
1188
|
+
backgroundColor: statusColor.bg,
|
|
1189
|
+
color: statusColor.fg
|
|
1190
|
+
},
|
|
1191
|
+
children: [
|
|
1192
|
+
/* @__PURE__ */ jsx3(
|
|
1193
|
+
"span",
|
|
1194
|
+
{
|
|
1195
|
+
style: {
|
|
1196
|
+
display: "inline-block",
|
|
1197
|
+
width: "0.5rem",
|
|
1198
|
+
height: "0.5rem",
|
|
1199
|
+
borderRadius: "50%",
|
|
1200
|
+
backgroundColor: statusColor.dot
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
),
|
|
1204
|
+
nodeState
|
|
1205
|
+
]
|
|
1206
|
+
}
|
|
1207
|
+
),
|
|
1208
|
+
statsLoading && !stats && /* @__PURE__ */ jsxs3("div", { style: styles2.loading, children: [
|
|
1209
|
+
/* @__PURE__ */ jsxs3(
|
|
1210
|
+
"svg",
|
|
1211
|
+
{
|
|
1212
|
+
width: "12",
|
|
1213
|
+
height: "12",
|
|
1214
|
+
viewBox: "0 0 24 24",
|
|
1215
|
+
fill: "none",
|
|
1216
|
+
stroke: "currentColor",
|
|
1217
|
+
strokeWidth: "2",
|
|
1218
|
+
strokeLinecap: "round",
|
|
1219
|
+
strokeLinejoin: "round",
|
|
1220
|
+
role: "img",
|
|
1221
|
+
"aria-label": "Loading",
|
|
1222
|
+
children: [
|
|
1223
|
+
/* @__PURE__ */ jsx3("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }),
|
|
1224
|
+
/* @__PURE__ */ jsx3(
|
|
1225
|
+
"animateTransform",
|
|
1226
|
+
{
|
|
1227
|
+
attributeName: "transform",
|
|
1228
|
+
type: "rotate",
|
|
1229
|
+
from: "0 12 12",
|
|
1230
|
+
to: "360 12 12",
|
|
1231
|
+
dur: "1s",
|
|
1232
|
+
repeatCount: "indefinite"
|
|
1233
|
+
}
|
|
1234
|
+
)
|
|
1235
|
+
]
|
|
1236
|
+
}
|
|
1237
|
+
),
|
|
1238
|
+
"Loading\u2026"
|
|
1239
|
+
] }),
|
|
1240
|
+
statsError && /* @__PURE__ */ jsx3("div", { style: styles2.errorBox, children: statsError }),
|
|
1241
|
+
stats && /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
1242
|
+
/* @__PURE__ */ jsx3(InfoRow, { label: "Pubkey", value: stats.pubkey, copyable: true }),
|
|
1243
|
+
stats.externalFunding ? /* @__PURE__ */ jsx3("div", { style: { padding: "0.25rem 0", fontSize: "0.75rem", color: "#6b7280" }, children: "External funding mode" }) : stats.ckbAddress ? /* @__PURE__ */ jsx3(InfoRow, { label: "CKB Address", value: stats.ckbAddress, copyable: true }) : null,
|
|
1244
|
+
/* @__PURE__ */ jsxs3("div", { style: styles2.statsGrid, children: [
|
|
1245
|
+
/* @__PURE__ */ jsxs3("div", { style: styles2.statCard, children: [
|
|
1246
|
+
/* @__PURE__ */ jsx3("div", { style: styles2.statLabel, children: "Peers" }),
|
|
1247
|
+
/* @__PURE__ */ jsx3("div", { style: styles2.statValue, children: stats.peers })
|
|
1248
|
+
] }),
|
|
1249
|
+
/* @__PURE__ */ jsxs3("div", { style: styles2.statCard, children: [
|
|
1250
|
+
/* @__PURE__ */ jsx3("div", { style: styles2.statLabel, children: "Channels" }),
|
|
1251
|
+
/* @__PURE__ */ jsx3("div", { style: styles2.statValue, children: stats.channels })
|
|
1252
|
+
] })
|
|
1253
|
+
] }),
|
|
1254
|
+
showQrCode && stats.ckbAddress && /* @__PURE__ */ jsxs3("div", { style: styles2.qrContainer, children: [
|
|
1255
|
+
renderQrCode ? renderQrCode(stats.ckbAddress) : QRComponent ? /* @__PURE__ */ jsx3(
|
|
1256
|
+
QRComponent,
|
|
1257
|
+
{
|
|
1258
|
+
value: stats.ckbAddress,
|
|
1259
|
+
size: 120,
|
|
1260
|
+
bgColor: "transparent",
|
|
1261
|
+
fgColor: "currentColor"
|
|
1262
|
+
}
|
|
1263
|
+
) : /* @__PURE__ */ jsx3("div", { style: { fontSize: "0.625rem", color: "#9ca3af" }, children: "Install qrcode.react for QR code" }),
|
|
1264
|
+
/* @__PURE__ */ jsx3("span", { style: styles2.qrCaption, children: "Scan to deposit CKB" }),
|
|
1265
|
+
/* @__PURE__ */ jsxs3("div", { style: styles2.balanceRow, children: [
|
|
1266
|
+
/* @__PURE__ */ jsx3("span", { style: { fontSize: "0.75rem", color: "#6b7280" }, children: "Balance" }),
|
|
1267
|
+
/* @__PURE__ */ jsxs3(
|
|
1268
|
+
"span",
|
|
1269
|
+
{
|
|
1270
|
+
style: {
|
|
1271
|
+
fontFamily: "ui-monospace, monospace",
|
|
1272
|
+
fontSize: "0.75rem",
|
|
1273
|
+
fontWeight: 500
|
|
1274
|
+
},
|
|
1275
|
+
children: [
|
|
1276
|
+
stats.balanceCkb ?? "\u2014",
|
|
1277
|
+
" CKB"
|
|
1278
|
+
]
|
|
1279
|
+
}
|
|
1280
|
+
)
|
|
1281
|
+
] })
|
|
1282
|
+
] })
|
|
1283
|
+
] })
|
|
1284
|
+
] });
|
|
1285
|
+
}
|
|
483
1286
|
export {
|
|
1287
|
+
ChannelState,
|
|
1288
|
+
ConfigBuilder2 as ConfigBuilder,
|
|
1289
|
+
ConnectButton,
|
|
1290
|
+
FiberBrowserNode2 as FiberBrowserNode,
|
|
484
1291
|
FiberPayQuickCard,
|
|
1292
|
+
FiberRpcError,
|
|
1293
|
+
NodeInfoPanel,
|
|
1294
|
+
PasskeyCredentialProvider2 as PasskeyCredentialProvider,
|
|
1295
|
+
PasswordCredentialProvider2 as PasswordCredentialProvider,
|
|
1296
|
+
RawKeyCredentialProvider2 as RawKeyCredentialProvider,
|
|
1297
|
+
ckbHash,
|
|
1298
|
+
ckbToShannons,
|
|
1299
|
+
derivePublicKey,
|
|
1300
|
+
formatShannonsAsCkb2 as formatShannonsAsCkb,
|
|
1301
|
+
fromHex,
|
|
1302
|
+
getLockBalanceShannons2 as getLockBalanceShannons,
|
|
1303
|
+
scriptToAddress2 as scriptToAddress,
|
|
1304
|
+
shannonsToCkb,
|
|
1305
|
+
toHex,
|
|
485
1306
|
useFiberNode,
|
|
486
1307
|
useFiberPayment
|
|
487
1308
|
};
|