@aaronbassett/midnight-local-devnet 0.1.2 → 0.2.1

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.
Files changed (94) hide show
  1. package/README.md +44 -5
  2. package/dist/cli/commands/dashboard.d.ts +3 -0
  3. package/dist/cli/commands/dashboard.js +20 -0
  4. package/dist/cli/commands/dashboard.js.map +1 -0
  5. package/dist/cli/commands/interactive.d.ts +3 -0
  6. package/dist/cli/commands/interactive.js +16 -0
  7. package/dist/cli/commands/interactive.js.map +1 -0
  8. package/dist/cli/dashboard/app.d.ts +9 -0
  9. package/dist/cli/dashboard/app.js +106 -0
  10. package/dist/cli/dashboard/app.js.map +1 -0
  11. package/dist/cli/dashboard/components/gauge.d.ts +9 -0
  12. package/dist/cli/dashboard/components/gauge.js +10 -0
  13. package/dist/cli/dashboard/components/gauge.js.map +1 -0
  14. package/dist/cli/dashboard/components/panel-box.d.ts +10 -0
  15. package/dist/cli/dashboard/components/panel-box.js +6 -0
  16. package/dist/cli/dashboard/components/panel-box.js.map +1 -0
  17. package/dist/cli/dashboard/components/sparkline.d.ts +9 -0
  18. package/dist/cli/dashboard/components/sparkline.js +25 -0
  19. package/dist/cli/dashboard/components/sparkline.js.map +1 -0
  20. package/dist/cli/dashboard/components/status-badge.d.ts +6 -0
  21. package/dist/cli/dashboard/components/status-badge.js +24 -0
  22. package/dist/cli/dashboard/components/status-badge.js.map +1 -0
  23. package/dist/cli/dashboard/hooks/use-breakpoint.d.ts +7 -0
  24. package/dist/cli/dashboard/hooks/use-breakpoint.js +15 -0
  25. package/dist/cli/dashboard/hooks/use-breakpoint.js.map +1 -0
  26. package/dist/cli/dashboard/hooks/use-health.d.ts +9 -0
  27. package/dist/cli/dashboard/hooks/use-health.js +35 -0
  28. package/dist/cli/dashboard/hooks/use-health.js.map +1 -0
  29. package/dist/cli/dashboard/hooks/use-indexer-info.d.ts +5 -0
  30. package/dist/cli/dashboard/hooks/use-indexer-info.js +19 -0
  31. package/dist/cli/dashboard/hooks/use-indexer-info.js.map +1 -0
  32. package/dist/cli/dashboard/hooks/use-logs.d.ts +19 -0
  33. package/dist/cli/dashboard/hooks/use-logs.js +55 -0
  34. package/dist/cli/dashboard/hooks/use-logs.js.map +1 -0
  35. package/dist/cli/dashboard/hooks/use-node-info.d.ts +21 -0
  36. package/dist/cli/dashboard/hooks/use-node-info.js +49 -0
  37. package/dist/cli/dashboard/hooks/use-node-info.js.map +1 -0
  38. package/dist/cli/dashboard/hooks/use-polling.d.ts +7 -0
  39. package/dist/cli/dashboard/hooks/use-polling.js +35 -0
  40. package/dist/cli/dashboard/hooks/use-polling.js.map +1 -0
  41. package/dist/cli/dashboard/hooks/use-proof-server.d.ts +7 -0
  42. package/dist/cli/dashboard/hooks/use-proof-server.js +14 -0
  43. package/dist/cli/dashboard/hooks/use-proof-server.js.map +1 -0
  44. package/dist/cli/dashboard/hooks/use-services.d.ts +3 -0
  45. package/dist/cli/dashboard/hooks/use-services.js +6 -0
  46. package/dist/cli/dashboard/hooks/use-services.js.map +1 -0
  47. package/dist/cli/dashboard/hooks/use-terminal-size.d.ts +5 -0
  48. package/dist/cli/dashboard/hooks/use-terminal-size.js +22 -0
  49. package/dist/cli/dashboard/hooks/use-terminal-size.js.map +1 -0
  50. package/dist/cli/dashboard/hooks/use-wallet-state.d.ts +10 -0
  51. package/dist/cli/dashboard/hooks/use-wallet-state.js +63 -0
  52. package/dist/cli/dashboard/hooks/use-wallet-state.js.map +1 -0
  53. package/dist/cli/dashboard/layouts/large.d.ts +7 -0
  54. package/dist/cli/dashboard/layouts/large.js +13 -0
  55. package/dist/cli/dashboard/layouts/large.js.map +1 -0
  56. package/dist/cli/dashboard/layouts/medium.d.ts +7 -0
  57. package/dist/cli/dashboard/layouts/medium.js +11 -0
  58. package/dist/cli/dashboard/layouts/medium.js.map +1 -0
  59. package/dist/cli/dashboard/layouts/small.d.ts +7 -0
  60. package/dist/cli/dashboard/layouts/small.js +11 -0
  61. package/dist/cli/dashboard/layouts/small.js.map +1 -0
  62. package/dist/cli/dashboard/lib/log-parser.d.ts +15 -0
  63. package/dist/cli/dashboard/lib/log-parser.js +44 -0
  64. package/dist/cli/dashboard/lib/log-parser.js.map +1 -0
  65. package/dist/cli/dashboard/lib/proof-server-api.d.ts +15 -0
  66. package/dist/cli/dashboard/lib/proof-server-api.js +48 -0
  67. package/dist/cli/dashboard/lib/proof-server-api.js.map +1 -0
  68. package/dist/cli/dashboard/lib/substrate-rpc.d.ts +16 -0
  69. package/dist/cli/dashboard/lib/substrate-rpc.js +39 -0
  70. package/dist/cli/dashboard/lib/substrate-rpc.js.map +1 -0
  71. package/dist/cli/dashboard/panels/indexer-panel.d.ts +11 -0
  72. package/dist/cli/dashboard/panels/indexer-panel.js +17 -0
  73. package/dist/cli/dashboard/panels/indexer-panel.js.map +1 -0
  74. package/dist/cli/dashboard/panels/log-panel.d.ts +13 -0
  75. package/dist/cli/dashboard/panels/log-panel.js +27 -0
  76. package/dist/cli/dashboard/panels/log-panel.js.map +1 -0
  77. package/dist/cli/dashboard/panels/node-panel.d.ts +10 -0
  78. package/dist/cli/dashboard/panels/node-panel.js +17 -0
  79. package/dist/cli/dashboard/panels/node-panel.js.map +1 -0
  80. package/dist/cli/dashboard/panels/proof-panel.d.ts +10 -0
  81. package/dist/cli/dashboard/panels/proof-panel.js +20 -0
  82. package/dist/cli/dashboard/panels/proof-panel.js.map +1 -0
  83. package/dist/cli/dashboard/panels/response-graph.d.ts +10 -0
  84. package/dist/cli/dashboard/panels/response-graph.js +12 -0
  85. package/dist/cli/dashboard/panels/response-graph.js.map +1 -0
  86. package/dist/cli/dashboard/panels/wallet-panel.d.ts +9 -0
  87. package/dist/cli/dashboard/panels/wallet-panel.js +24 -0
  88. package/dist/cli/dashboard/panels/wallet-panel.js.map +1 -0
  89. package/dist/cli/dashboard/types.d.ts +39 -0
  90. package/dist/cli/dashboard/types.js +2 -0
  91. package/dist/cli/dashboard/types.js.map +1 -0
  92. package/dist/cli.js +18 -18
  93. package/dist/cli.js.map +1 -1
  94. package/package.json +6 -2
package/README.md CHANGED
@@ -13,16 +13,16 @@ A CLI and MCP (Model Context Protocol) server for managing a local Docker-based
13
13
 
14
14
  ### CLI
15
15
 
16
- Run with no arguments to enter interactive mode:
16
+ Start the network:
17
17
 
18
18
  ```bash
19
- npx @aaronbassett/midnight-local-devnet
19
+ npx @aaronbassett/midnight-local-devnet start
20
20
  ```
21
21
 
22
- Or start the network directly:
22
+ Open the realtime dashboard in a second terminal pane to monitor your devnet:
23
23
 
24
24
  ```bash
25
- npx @aaronbassett/midnight-local-devnet start
25
+ npx @aaronbassett/midnight-local-devnet dashboard
26
26
  ```
27
27
 
28
28
  ### MCP Server
@@ -58,9 +58,48 @@ All commands can be run via `npx @aaronbassett/midnight-local-devnet <command>`.
58
58
  | `fund <address>` | Fund a Bech32 address with NIGHT tokens | `--amount <n>` Amount in NIGHT (default: 50,000) |
59
59
  | `fund-file <path>` | Fund all accounts from an accounts.json file | |
60
60
  | `generate-accounts` | Generate random test accounts | `--count <n>`, `--format <mnemonic\|privateKey>`, `--output <path>`, `--fund`, `--register-dust` |
61
+ | `dashboard` | Open realtime terminal dashboard | |
61
62
  | `interactive` | Start interactive menu mode | |
62
63
 
63
- Running with no arguments automatically enters interactive mode.
64
+ Running with no arguments displays help.
65
+
66
+ ## Dashboard
67
+
68
+ The `dashboard` command opens a realtime terminal UI that displays the state of all local devnet services. It's designed to run in a side terminal pane while you develop.
69
+
70
+ ```bash
71
+ npx @aaronbassett/midnight-local-devnet dashboard
72
+ ```
73
+
74
+ The dashboard shows:
75
+
76
+ - **Node** -- Block height, average block time, chain, peers, sync status, version
77
+ - **Indexer** -- Indexed block height, lag vs node, readiness
78
+ - **Proof Server** -- Version, proof versions, job processing/pending/capacity
79
+ - **Wallet** -- Master wallet NIGHT (unshielded + shielded) and DUST balances
80
+ - **Logs** -- Combined color-coded log stream from all services, filterable by service, level, or substring search
81
+ - **Response Times** -- Sparkline charts of per-service response times (large terminals only)
82
+
83
+ The layout adapts to your terminal width:
84
+
85
+ | Terminal Width | Layout |
86
+ |---|---|
87
+ | < 40 columns | Single column, compact |
88
+ | 40--119 columns | Two-column grid |
89
+ | 120+ columns | Three-column with response time graphs |
90
+
91
+ Keyboard shortcuts:
92
+
93
+ | Key | Action |
94
+ |---|---|
95
+ | Tab | Cycle focus between panels |
96
+ | Up/Down | Scroll logs (when focused) |
97
+ | `s` | Cycle log service filter |
98
+ | `l` | Cycle log level filter |
99
+ | `/` | Enter log search mode |
100
+ | `q` | Exit dashboard |
101
+
102
+ The dashboard starts regardless of whether the network is running. Panels show "Connecting..." and update live when services come up.
64
103
 
65
104
  ## MCP Tool Reference
66
105
 
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ import type { NetworkManager } from '../../core/network-manager.js';
3
+ export declare function registerDashboardCommand(program: Command, manager: NetworkManager): void;
@@ -0,0 +1,20 @@
1
+ export function registerDashboardCommand(program, manager) {
2
+ program
3
+ .command('dashboard')
4
+ .description('Open realtime terminal dashboard for the local devnet')
5
+ .action(async () => {
6
+ if (!process.stdin.isTTY) {
7
+ console.error('Error: Dashboard requires an interactive terminal (TTY).');
8
+ console.error('Run this command directly in a terminal, not through a pipe or script.');
9
+ process.exit(1);
10
+ }
11
+ // Dynamic import to avoid loading React/ink for non-dashboard commands
12
+ const { render } = await import('ink');
13
+ const React = await import('react');
14
+ const { App } = await import('../dashboard/app.js');
15
+ const { waitUntilExit } = render(React.createElement(App, { manager, config: manager.config }));
16
+ await waitUntilExit();
17
+ await manager.shutdown();
18
+ });
19
+ }
20
+ //# sourceMappingURL=dashboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../../src/cli/commands/dashboard.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,wBAAwB,CAAC,OAAgB,EAAE,OAAuB;IAChF,OAAO;SACJ,OAAO,CAAC,WAAW,CAAC;SACpB,WAAW,CAAC,uDAAuD,CAAC;SACpE,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACzB,OAAO,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAC;YAC1E,OAAO,CAAC,KAAK,CAAC,wEAAwE,CAAC,CAAC;YACxF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,uEAAuE;QACvE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;QACvC,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC;QACpC,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAC;QAEpD,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,CAC9B,KAAK,CAAC,aAAa,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAC9D,CAAC;QAEF,MAAM,aAAa,EAAE,CAAC;QACtB,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ import type { NetworkManager } from '../../core/network-manager.js';
3
+ export declare function registerInteractiveCommand(program: Command, manager: NetworkManager): void;
@@ -0,0 +1,16 @@
1
+ import { startInteractiveMode } from '../interactive.js';
2
+ export function registerInteractiveCommand(program, manager) {
3
+ program
4
+ .command('interactive')
5
+ .description('Start interactive menu mode')
6
+ .action(async () => {
7
+ try {
8
+ await startInteractiveMode(manager);
9
+ }
10
+ catch (error) {
11
+ console.error('Interactive mode error:', error instanceof Error ? error.message : error);
12
+ process.exit(1);
13
+ }
14
+ });
15
+ }
16
+ //# sourceMappingURL=interactive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.js","sourceRoot":"","sources":["../../../src/cli/commands/interactive.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAEzD,MAAM,UAAU,0BAA0B,CAAC,OAAgB,EAAE,OAAuB;IAClF,OAAO;SACJ,OAAO,CAAC,aAAa,CAAC;SACtB,WAAW,CAAC,6BAA6B,CAAC;SAC1C,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,IAAI,CAAC;YACH,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACzF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import type { NetworkManager } from '../../core/network-manager.js';
3
+ import type { NetworkConfig } from '../../core/types.js';
4
+ interface AppProps {
5
+ manager: NetworkManager;
6
+ config: NetworkConfig;
7
+ }
8
+ export declare function App({ manager, config }: AppProps): React.ReactElement;
9
+ export {};
@@ -0,0 +1,106 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { Box, Text, useInput, useApp } from 'ink';
4
+ import { useBreakpoint } from './hooks/use-breakpoint.js';
5
+ import { useNodeInfo } from './hooks/use-node-info.js';
6
+ import { useProofServer } from './hooks/use-proof-server.js';
7
+ import { useHealth } from './hooks/use-health.js';
8
+ import { useIndexerInfo } from './hooks/use-indexer-info.js';
9
+ import { useWalletState } from './hooks/use-wallet-state.js';
10
+ import { useLogs } from './hooks/use-logs.js';
11
+ import { SmallLayout } from './layouts/small.js';
12
+ import { MediumLayout } from './layouts/medium.js';
13
+ import { LargeLayout } from './layouts/large.js';
14
+ const PANEL_CYCLE = ['node', 'indexer', 'proof', 'wallet', 'logs', 'graph'];
15
+ export function App({ manager, config }) {
16
+ const { exit } = useApp();
17
+ const { breakpoint, columns, rows } = useBreakpoint();
18
+ // Data hooks
19
+ const nodeInfo = useNodeInfo(config.node);
20
+ const proofServer = useProofServer(config.proofServer);
21
+ const health = useHealth(config);
22
+ const indexerInfo = useIndexerInfo(config.indexer);
23
+ const walletState = useWalletState(manager);
24
+ const logs = useLogs();
25
+ // UI state
26
+ const [focusedPanel, setFocusedPanel] = useState('node');
27
+ const [searchMode, setSearchMode] = useState(false);
28
+ const [searchText, setSearchText] = useState('');
29
+ const isInteractive = process.stdin.isTTY === true;
30
+ useInput((input, key) => {
31
+ if (searchMode) {
32
+ if (key.escape || key.return) {
33
+ setSearchMode(false);
34
+ if (key.return)
35
+ logs.setSearch(searchText);
36
+ if (key.escape) {
37
+ setSearchText('');
38
+ logs.setSearch('');
39
+ }
40
+ return;
41
+ }
42
+ if (key.backspace || key.delete) {
43
+ setSearchText((prev) => prev.slice(0, -1));
44
+ return;
45
+ }
46
+ setSearchText((prev) => prev + input);
47
+ return;
48
+ }
49
+ if (input === 'q') {
50
+ exit();
51
+ return;
52
+ }
53
+ if (key.tab) {
54
+ setFocusedPanel((prev) => {
55
+ const idx = PANEL_CYCLE.indexOf(prev);
56
+ return PANEL_CYCLE[(idx + 1) % PANEL_CYCLE.length];
57
+ });
58
+ return;
59
+ }
60
+ if (input === 's') {
61
+ logs.cycleService();
62
+ return;
63
+ }
64
+ if (input === 'l') {
65
+ logs.cycleLevel();
66
+ return;
67
+ }
68
+ if (input === '/') {
69
+ setSearchMode(true);
70
+ setSearchText('');
71
+ return;
72
+ }
73
+ if (key.upArrow) {
74
+ if (focusedPanel === 'logs')
75
+ logs.scrollUp();
76
+ return;
77
+ }
78
+ if (key.downArrow) {
79
+ if (focusedPanel === 'logs')
80
+ logs.scrollDown();
81
+ return;
82
+ }
83
+ }, { isActive: isInteractive });
84
+ const data = {
85
+ node: nodeInfo.data,
86
+ nodeLoading: nodeInfo.loading,
87
+ indexer: indexerInfo.data,
88
+ indexerLoading: indexerInfo.loading,
89
+ proofServer: proofServer.data,
90
+ proofServerLoading: proofServer.loading,
91
+ wallet: walletState,
92
+ logs,
93
+ healthHistory: {
94
+ nodeHistory: health.data?.nodeHistory ?? [],
95
+ indexerHistory: health.data?.indexerHistory ?? [],
96
+ proofServerHistory: health.data?.proofServerHistory ?? [],
97
+ },
98
+ focusedPanel,
99
+ searchMode,
100
+ searchText,
101
+ columns,
102
+ rows,
103
+ };
104
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { bold: true, color: "cyan", children: "Midnight Local Devnet" }), _jsxs(Text, { color: "gray", children: [columns, "x", rows, " | ", breakpoint, " | Tab=focus q=quit s=svc l=lvl /=search"] })] }), breakpoint === 'small' && _jsx(SmallLayout, { data: data }), breakpoint === 'medium' && _jsx(MediumLayout, { data: data }), breakpoint === 'large' && _jsx(LargeLayout, { data: data })] }));
105
+ }
106
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../../src/cli/dashboard/app.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ interface GaugeProps {
3
+ value: number;
4
+ max: number;
5
+ width?: number;
6
+ label?: string;
7
+ }
8
+ export declare function Gauge({ value, max, width, label }: GaugeProps): React.ReactElement;
9
+ export {};
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Text } from 'ink';
3
+ export function Gauge({ value, max, width = 10, label }) {
4
+ const filled = max > 0 ? Math.round((value / max) * width) : 0;
5
+ const empty = width - filled;
6
+ const percentage = max > 0 ? Math.round((value / max) * 100) : 0;
7
+ const color = percentage >= 90 ? 'red' : percentage >= 70 ? 'yellow' : 'green';
8
+ return (_jsxs(Text, { children: [_jsx(Text, { color: color, children: '█'.repeat(filled) }), _jsx(Text, { color: "gray", children: '░'.repeat(empty) }), _jsxs(Text, { children: [" ", value, "/", max] }), label ? _jsxs(Text, { children: [" ", label] }) : null] }));
9
+ }
10
+ //# sourceMappingURL=gauge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gauge.js","sourceRoot":"","sources":["../../../../src/cli/dashboard/components/gauge.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAS3B,MAAM,UAAU,KAAK,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,GAAG,EAAE,EAAE,KAAK,EAAc;IACjE,MAAM,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;IAC7B,MAAM,UAAU,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEjE,MAAM,KAAK,GAAG,UAAU,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;IAE/E,OAAO,CACL,MAAC,IAAI,eACH,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,YAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAQ,EAC/C,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,YAAE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAQ,EAC7C,MAAC,IAAI,oBAAG,KAAK,OAAG,GAAG,IAAQ,EAC1B,KAAK,CAAC,CAAC,CAAC,MAAC,IAAI,oBAAG,KAAK,IAAQ,CAAC,CAAC,CAAC,IAAI,IAChC,CACR,CAAC;AACJ,CAAC"}
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ interface PanelBoxProps {
3
+ title: string;
4
+ focused?: boolean;
5
+ width?: number | string;
6
+ height?: number;
7
+ children: React.ReactNode;
8
+ }
9
+ export declare function PanelBox({ title, focused, width, height, children }: PanelBoxProps): React.ReactElement;
10
+ export {};
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from 'ink';
3
+ export function PanelBox({ title, focused, width, height, children }) {
4
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: focused ? 'bold' : 'single', borderColor: focused ? 'cyan' : 'gray', width: width, height: height, paddingX: 1, children: [_jsx(Text, { bold: true, color: focused ? 'cyan' : 'white', children: title }), children] }));
5
+ }
6
+ //# sourceMappingURL=panel-box.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"panel-box.js","sourceRoot":"","sources":["../../../../src/cli/dashboard/components/panel-box.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAUhC,MAAM,UAAU,QAAQ,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAiB;IACjF,OAAO,CACL,MAAC,GAAG,IACF,aAAa,EAAC,QAAQ,EACtB,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,EACxC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EACtC,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,CAAC,aAEX,KAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,YACzC,KAAK,GACD,EACN,QAAQ,IACL,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ export declare function renderSparkline(data: number[], maxWidth?: number): string;
3
+ interface SparklineProps {
4
+ data: number[];
5
+ maxWidth?: number;
6
+ color?: string;
7
+ }
8
+ export declare function Sparkline({ data, maxWidth, color }: SparklineProps): React.ReactElement;
9
+ export {};
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Text } from 'ink';
3
+ const BARS = ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'];
4
+ export function renderSparkline(data, maxWidth) {
5
+ if (data.length === 0)
6
+ return '';
7
+ const values = maxWidth && data.length > maxWidth ? data.slice(-maxWidth) : data;
8
+ const min = Math.min(...values);
9
+ const max = Math.max(...values);
10
+ const range = max - min;
11
+ if (range === 0) {
12
+ const mid = Math.floor((BARS.length - 1) / 2);
13
+ return values.map(() => BARS[mid]).join('');
14
+ }
15
+ return values
16
+ .map((v) => {
17
+ const idx = Math.round(((v - min) / range) * (BARS.length - 1));
18
+ return BARS[idx];
19
+ })
20
+ .join('');
21
+ }
22
+ export function Sparkline({ data, maxWidth, color }) {
23
+ return _jsx(Text, { color: color, children: renderSparkline(data, maxWidth) });
24
+ }
25
+ //# sourceMappingURL=sparkline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sparkline.js","sourceRoot":"","sources":["../../../../src/cli/dashboard/components/sparkline.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAE3B,MAAM,IAAI,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAU,CAAC;AAE/D,MAAM,UAAU,eAAe,CAAC,IAAc,EAAE,QAAiB;IAC/D,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEjC,MAAM,MAAM,GAAG,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACjF,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;IAChC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;IAChC,MAAM,KAAK,GAAG,GAAG,GAAG,GAAG,CAAC;IAExB,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;QAChB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9C,OAAO,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,MAAM;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QAChE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AAQD,MAAM,UAAU,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAkB;IACjE,OAAO,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,YAAG,eAAe,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAQ,CAAC;AACtE,CAAC"}
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ interface StatusBadgeProps {
3
+ status: 'healthy' | 'unhealthy' | 'unknown' | 'running' | 'stopped' | 'busy' | 'ok';
4
+ }
5
+ export declare function StatusBadge({ status }: StatusBadgeProps): React.ReactElement;
6
+ export {};
@@ -0,0 +1,24 @@
1
+ import { jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Text } from 'ink';
3
+ const STATUS_COLORS = {
4
+ healthy: 'green',
5
+ running: 'green',
6
+ ok: 'green',
7
+ busy: 'yellow',
8
+ unknown: 'gray',
9
+ unhealthy: 'red',
10
+ stopped: 'red',
11
+ };
12
+ const STATUS_SYMBOLS = {
13
+ healthy: '●',
14
+ running: '●',
15
+ ok: '●',
16
+ busy: '◐',
17
+ unknown: '○',
18
+ unhealthy: '●',
19
+ stopped: '●',
20
+ };
21
+ export function StatusBadge({ status }) {
22
+ return (_jsxs(Text, { color: STATUS_COLORS[status], children: [STATUS_SYMBOLS[status], " ", status] }));
23
+ }
24
+ //# sourceMappingURL=status-badge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-badge.js","sourceRoot":"","sources":["../../../../src/cli/dashboard/components/status-badge.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAM3B,MAAM,aAAa,GAA+C;IAChE,OAAO,EAAE,OAAO;IAChB,OAAO,EAAE,OAAO;IAChB,EAAE,EAAE,OAAO;IACX,IAAI,EAAE,QAAQ;IACd,OAAO,EAAE,MAAM;IACf,SAAS,EAAE,KAAK;IAChB,OAAO,EAAE,KAAK;CACf,CAAC;AAEF,MAAM,cAAc,GAA+C;IACjE,OAAO,EAAE,GAAG;IACZ,OAAO,EAAE,GAAG;IACZ,EAAE,EAAE,GAAG;IACP,IAAI,EAAE,GAAG;IACT,OAAO,EAAE,GAAG;IACZ,SAAS,EAAE,GAAG;IACd,OAAO,EAAE,GAAG;CACb,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,EAAE,MAAM,EAAoB;IACtD,OAAO,CACL,MAAC,IAAI,IAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,aAC/B,cAAc,CAAC,MAAM,CAAC,OAAG,MAAM,IAC3B,CACR,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ export type Breakpoint = 'small' | 'medium' | 'large';
2
+ export declare function getBreakpoint(width: number): Breakpoint;
3
+ export declare function useBreakpoint(): {
4
+ breakpoint: Breakpoint;
5
+ columns: number;
6
+ rows: number;
7
+ };
@@ -0,0 +1,15 @@
1
+ import { useMemo } from 'react';
2
+ import { useTerminalSize } from './use-terminal-size.js';
3
+ export function getBreakpoint(width) {
4
+ if (width < 40)
5
+ return 'small';
6
+ if (width < 120)
7
+ return 'medium';
8
+ return 'large';
9
+ }
10
+ export function useBreakpoint() {
11
+ const { columns, rows } = useTerminalSize();
12
+ const breakpoint = useMemo(() => getBreakpoint(columns), [columns]);
13
+ return { breakpoint, columns, rows };
14
+ }
15
+ //# sourceMappingURL=use-breakpoint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-breakpoint.js","sourceRoot":"","sources":["../../../../src/cli/dashboard/hooks/use-breakpoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAIzD,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,IAAI,KAAK,GAAG,EAAE;QAAE,OAAO,OAAO,CAAC;IAC/B,IAAI,KAAK,GAAG,GAAG;QAAE,OAAO,QAAQ,CAAC;IACjC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,eAAe,EAAE,CAAC;IAC5C,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACpE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACvC,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { type HealthReport } from '../../../core/health.js';
2
+ import type { NetworkConfig } from '../../../core/types.js';
3
+ export interface HealthWithHistory {
4
+ current: HealthReport;
5
+ nodeHistory: number[];
6
+ indexerHistory: number[];
7
+ proofServerHistory: number[];
8
+ }
9
+ export declare function useHealth(config: NetworkConfig): import("./use-polling.js").PollingState<HealthWithHistory>;
@@ -0,0 +1,35 @@
1
+ import { useRef } from 'react';
2
+ import { usePolling } from './use-polling.js';
3
+ import { checkAllHealth } from '../../../core/health.js';
4
+ const MAX_HISTORY = 30;
5
+ export function useHealth(config) {
6
+ const nodeHistory = useRef([]);
7
+ const indexerHistory = useRef([]);
8
+ const proofServerHistory = useRef([]);
9
+ const polling = usePolling(async () => {
10
+ const report = await checkAllHealth(config);
11
+ if (report.node.responseTime != null) {
12
+ nodeHistory.current.push(report.node.responseTime);
13
+ if (nodeHistory.current.length > MAX_HISTORY)
14
+ nodeHistory.current.shift();
15
+ }
16
+ if (report.indexer.responseTime != null) {
17
+ indexerHistory.current.push(report.indexer.responseTime);
18
+ if (indexerHistory.current.length > MAX_HISTORY)
19
+ indexerHistory.current.shift();
20
+ }
21
+ if (report.proofServer.responseTime != null) {
22
+ proofServerHistory.current.push(report.proofServer.responseTime);
23
+ if (proofServerHistory.current.length > MAX_HISTORY)
24
+ proofServerHistory.current.shift();
25
+ }
26
+ return {
27
+ current: report,
28
+ nodeHistory: [...nodeHistory.current],
29
+ indexerHistory: [...indexerHistory.current],
30
+ proofServerHistory: [...proofServerHistory.current],
31
+ };
32
+ }, 10000);
33
+ return polling;
34
+ }
35
+ //# sourceMappingURL=use-health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-health.js","sourceRoot":"","sources":["../../../../src/cli/dashboard/hooks/use-health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAqB,MAAM,yBAAyB,CAAC;AAU5E,MAAM,WAAW,GAAG,EAAE,CAAC;AAEvB,MAAM,UAAU,SAAS,CAAC,MAAqB;IAC7C,MAAM,WAAW,GAAG,MAAM,CAAW,EAAE,CAAC,CAAC;IACzC,MAAM,cAAc,GAAG,MAAM,CAAW,EAAE,CAAC,CAAC;IAC5C,MAAM,kBAAkB,GAAG,MAAM,CAAW,EAAE,CAAC,CAAC;IAEhD,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,IAAgC,EAAE;QAChE,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC,CAAC;QAE5C,IAAI,MAAM,CAAC,IAAI,CAAC,YAAY,IAAI,IAAI,EAAE,CAAC;YACrC,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YACnD,IAAI,WAAW,CAAC,OAAO,CAAC,MAAM,GAAG,WAAW;gBAAE,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAC5E,CAAC;QACD,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,IAAI,IAAI,EAAE,CAAC;YACxC,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;YACzD,IAAI,cAAc,CAAC,OAAO,CAAC,MAAM,GAAG,WAAW;gBAAE,cAAc,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAClF,CAAC;QACD,IAAI,MAAM,CAAC,WAAW,CAAC,YAAY,IAAI,IAAI,EAAE,CAAC;YAC5C,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;YACjE,IAAI,kBAAkB,CAAC,OAAO,CAAC,MAAM,GAAG,WAAW;gBAAE,kBAAkB,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAC1F,CAAC;QAED,OAAO;YACL,OAAO,EAAE,MAAM;YACf,WAAW,EAAE,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC;YACrC,cAAc,EAAE,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC;YAC3C,kBAAkB,EAAE,CAAC,GAAG,kBAAkB,CAAC,OAAO,CAAC;SACpD,CAAC;IACJ,CAAC,EAAE,KAAK,CAAC,CAAC;IAEV,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export interface IndexerInfo {
2
+ ready: boolean;
3
+ responseTime: number | null;
4
+ }
5
+ export declare function useIndexerInfo(indexerUrl: string): import("./use-polling.js").PollingState<IndexerInfo>;
@@ -0,0 +1,19 @@
1
+ import { usePolling } from './use-polling.js';
2
+ async function fetchIndexerInfo(indexerUrl) {
3
+ const origin = new URL(indexerUrl).origin;
4
+ const start = Date.now();
5
+ try {
6
+ const response = await fetch(`${origin}/ready`, { signal: AbortSignal.timeout(5000) });
7
+ return {
8
+ ready: response.ok,
9
+ responseTime: Date.now() - start,
10
+ };
11
+ }
12
+ catch {
13
+ return { ready: false, responseTime: Date.now() - start };
14
+ }
15
+ }
16
+ export function useIndexerInfo(indexerUrl) {
17
+ return usePolling(() => fetchIndexerInfo(indexerUrl), 10000);
18
+ }
19
+ //# sourceMappingURL=use-indexer-info.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-indexer-info.js","sourceRoot":"","sources":["../../../../src/cli/dashboard/hooks/use-indexer-info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAO9C,KAAK,UAAU,gBAAgB,CAAC,UAAkB;IAChD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC;IAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,QAAQ,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACvF,OAAO;YACL,KAAK,EAAE,QAAQ,CAAC,EAAE;YAClB,YAAY,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;SACjC,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;IAC5D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,UAAkB;IAC/C,OAAO,UAAU,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,CAAC;AAC/D,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { type ParsedLogLine, type LogFilter } from '../lib/log-parser.js';
2
+ export interface LogState {
3
+ lines: ParsedLogLine[];
4
+ filteredLines: ParsedLogLine[];
5
+ filter: LogFilter;
6
+ scrollOffset: number;
7
+ }
8
+ export declare function useLogs(): {
9
+ lines: ParsedLogLine[];
10
+ allLines: ParsedLogLine[];
11
+ filter: LogFilter;
12
+ scrollOffset: number;
13
+ loading: boolean;
14
+ cycleService: () => void;
15
+ cycleLevel: () => void;
16
+ setSearch: (search: string) => void;
17
+ scrollUp: () => void;
18
+ scrollDown: () => void;
19
+ };
@@ -0,0 +1,55 @@
1
+ import { useState, useCallback } from 'react';
2
+ import { usePolling } from './use-polling.js';
3
+ import { composeLogs } from '../../../core/docker.js';
4
+ import { parseLogLines, filterLogs } from '../lib/log-parser.js';
5
+ const SERVICE_CYCLE = [undefined, 'node', 'indexer', 'proof-server'];
6
+ const LEVEL_CYCLE = [undefined, 'info', 'warn', 'error'];
7
+ export function useLogs() {
8
+ const [filter, setFilter] = useState({});
9
+ const [scrollOffset, setScrollOffset] = useState(0);
10
+ const polling = usePolling(async () => {
11
+ const raw = await composeLogs({ lines: 100 });
12
+ return parseLogLines(raw);
13
+ }, 3000);
14
+ const lines = polling.data ?? [];
15
+ const filteredLines = filterLogs(lines, filter);
16
+ const cycleService = useCallback(() => {
17
+ setFilter((prev) => {
18
+ const currentIdx = SERVICE_CYCLE.indexOf(prev.service);
19
+ const nextIdx = (currentIdx + 1) % SERVICE_CYCLE.length;
20
+ return { ...prev, service: SERVICE_CYCLE[nextIdx] };
21
+ });
22
+ setScrollOffset(0);
23
+ }, []);
24
+ const cycleLevel = useCallback(() => {
25
+ setFilter((prev) => {
26
+ const currentIdx = LEVEL_CYCLE.indexOf(prev.level);
27
+ const nextIdx = (currentIdx + 1) % LEVEL_CYCLE.length;
28
+ return { ...prev, level: LEVEL_CYCLE[nextIdx] };
29
+ });
30
+ setScrollOffset(0);
31
+ }, []);
32
+ const setSearch = useCallback((search) => {
33
+ setFilter((prev) => ({ ...prev, search: search || undefined }));
34
+ setScrollOffset(0);
35
+ }, []);
36
+ const scrollUp = useCallback(() => {
37
+ setScrollOffset((prev) => Math.max(0, prev - 1));
38
+ }, []);
39
+ const scrollDown = useCallback(() => {
40
+ setScrollOffset((prev) => Math.min(filteredLines.length - 1, prev + 1));
41
+ }, [filteredLines.length]);
42
+ return {
43
+ lines: filteredLines,
44
+ allLines: lines,
45
+ filter,
46
+ scrollOffset,
47
+ loading: polling.loading,
48
+ cycleService,
49
+ cycleLevel,
50
+ setSearch,
51
+ scrollUp,
52
+ scrollDown,
53
+ };
54
+ }
55
+ //# sourceMappingURL=use-logs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-logs.js","sourceRoot":"","sources":["../../../../src/cli/dashboard/hooks/use-logs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { type SystemHealth } from '../lib/substrate-rpc.js';
2
+ export interface NodeInfo {
3
+ chainName: string | null;
4
+ nodeName: string | null;
5
+ version: string | null;
6
+ health: SystemHealth | null;
7
+ bestBlock: number | null;
8
+ avgBlockTime: number | null;
9
+ }
10
+ export declare function useNodeInfo(nodeUrl: string): {
11
+ data: {
12
+ avgBlockTime: number | null;
13
+ chainName: string | null;
14
+ nodeName: string | null;
15
+ version: string | null;
16
+ health: SystemHealth | null;
17
+ bestBlock: number | null;
18
+ } | null;
19
+ error: unknown | null;
20
+ loading: boolean;
21
+ };