@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/dist/index.js CHANGED
@@ -1,13 +1,39 @@
1
- // src/fiber-pay-quick-card.tsx
2
- import { useEffect as useEffect3, useId, useState as useState3 } from "react";
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
- [detachNodeListeners]
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 useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
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] = useState2(false);
267
- const [paymentResult, setPaymentResult] = useState2(null);
268
- const [error, setError] = useState2(null);
269
- const isMountedRef = useRef2(true);
270
- useEffect2(
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 = useCallback2(
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] = useState3("");
360
- const [invoiceInput, setInvoiceInput] = useState3("");
361
- const [createdInvoice, setCreatedInvoice] = useState3("");
362
- const [isCreatingInvoice, setIsCreatingInvoice] = useState3(false);
363
- const [invoiceError, setInvoiceError] = useState3(null);
364
- useEffect3(() => {
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
- useEffect3(() => {
784
+ useEffect4(() => {
370
785
  if (payError) {
371
786
  onError?.({ scope: "payment", message: payError });
372
787
  }
373
788
  }, [onError, payError]);
374
- useEffect3(() => {
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__ */ jsxs("div", { style: { ...cardStyle, ...props.style }, className: props.className, children: [
402
- /* @__PURE__ */ jsxs("h3", { children: [
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__ */ jsxs(Fragment, { children: [
409
- isPasskeySupported ? /* @__PURE__ */ jsx("div", { style: rowWithMarginStyle, children: hasPasskeyConfigured ? /* @__PURE__ */ jsx("button", { type: "button", onClick: () => void startWithPasskey(), children: "Login with Passkey" }) : /* @__PURE__ */ jsx("button", { type: "button", onClick: () => void createPasskeyAndStart(passkeyUsername), children: "Register Passkey" }) }) : null,
410
- /* @__PURE__ */ jsx("label", { htmlFor: passwordInputId, children: "Password" }),
411
- /* @__PURE__ */ jsxs("div", { style: rowStyle, children: [
412
- /* @__PURE__ */ jsx(
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__ */ jsx("button", { type: "button", onClick: () => void startWithPassword(password), children: "Start with Password" })
839
+ /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => void startWithPassword(password), children: "Start with Password" })
425
840
  ] })
426
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
427
- /* @__PURE__ */ jsxs("p", { children: [
428
- /* @__PURE__ */ jsx("strong", { children: "State:" }),
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__ */ jsxs("p", { children: [
433
- /* @__PURE__ */ jsx("strong", { children: "Pubkey:" }),
847
+ /* @__PURE__ */ jsxs2("p", { children: [
848
+ /* @__PURE__ */ jsx2("strong", { children: "Pubkey:" }),
434
849
  " ",
435
850
  nodeInfo.pubkey
436
851
  ] }),
437
- /* @__PURE__ */ jsxs("div", { style: rowWithMarginStyle, children: [
438
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => void createInvoice(), disabled: isCreatingInvoice, children: isCreatingInvoice ? "Creating..." : "Create Invoice (1 CKB)" }),
439
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => void stop(), children: "Stop Node" })
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__ */ jsxs("p", { children: [
442
- /* @__PURE__ */ jsx("strong", { children: "Created invoice:" }),
856
+ createdInvoice ? /* @__PURE__ */ jsxs2("p", { children: [
857
+ /* @__PURE__ */ jsx2("strong", { children: "Created invoice:" }),
443
858
  " ",
444
859
  createdInvoice
445
860
  ] }) : null,
446
- /* @__PURE__ */ jsx("label", { htmlFor: invoiceInputId, children: "Invoice" }),
447
- /* @__PURE__ */ jsxs("div", { style: rowStyle, children: [
448
- /* @__PURE__ */ jsx(
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__ */ jsx("button", { type: "button", onClick: () => void payInvoice(invoiceInput), disabled: isPaying, children: isPaying ? "Paying..." : "Pay" })
873
+ /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => void payInvoice(invoiceInput), disabled: isPaying, children: isPaying ? "Paying..." : "Pay" })
459
874
  ] }),
460
- paymentResult ? /* @__PURE__ */ jsxs("p", { children: [
461
- /* @__PURE__ */ jsx("strong", { children: "Payment:" }),
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__ */ jsxs("p", { style: { color: "#b91c1c" }, children: [
467
- /* @__PURE__ */ jsx("strong", { children: "Node error:" }),
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__ */ jsxs("p", { style: { color: "#b91c1c" }, children: [
472
- /* @__PURE__ */ jsx("strong", { children: "Payment error:" }),
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__ */ jsxs("p", { style: { color: "#b91c1c" }, children: [
477
- /* @__PURE__ */ jsx("strong", { children: "Invoice error:" }),
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
  };