@oddessentials/odd-dashboard 0.3.7
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 +49 -0
- package/bin/odd-dashboard.js +74 -0
- package/package.json +32 -0
- package/scripts/install.js +139 -0
package/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# npm Shim for odd-dashboard
|
|
2
|
+
|
|
3
|
+
This package provides a convenient way to install `odd-dashboard` via npm.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @oddessentials/odd-dashboard
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## How it works
|
|
12
|
+
|
|
13
|
+
The npm package is a thin wrapper that:
|
|
14
|
+
|
|
15
|
+
1. Downloads the appropriate native binary for your platform during `npm install`
|
|
16
|
+
2. Verifies the binary's checksum against the signed SHA256SUMS file
|
|
17
|
+
3. Provides a Node.js shim that forwards all arguments to the native binary
|
|
18
|
+
|
|
19
|
+
## Supported Platforms
|
|
20
|
+
|
|
21
|
+
- Windows x64
|
|
22
|
+
- macOS x64 (Intel)
|
|
23
|
+
- macOS arm64 (Apple Silicon)
|
|
24
|
+
- Linux x64
|
|
25
|
+
- Linux arm64
|
|
26
|
+
|
|
27
|
+
## Troubleshooting
|
|
28
|
+
|
|
29
|
+
### Binary not installed
|
|
30
|
+
|
|
31
|
+
If you see "odd-dashboard binary not installed" when running the command:
|
|
32
|
+
|
|
33
|
+
1. Check if your platform is supported
|
|
34
|
+
2. Try reinstalling: `npm install -g @oddessentials/odd-dashboard`
|
|
35
|
+
3. Download manually from [GitHub Releases](https://github.com/oddessentials/odd-demonstration/releases)
|
|
36
|
+
|
|
37
|
+
### Checksum verification failed
|
|
38
|
+
|
|
39
|
+
This indicates the downloaded binary may have been tampered with. Please:
|
|
40
|
+
|
|
41
|
+
1. Do NOT use the downloaded file
|
|
42
|
+
2. Report the issue to the maintainers
|
|
43
|
+
3. Download directly from GitHub Releases and verify manually
|
|
44
|
+
|
|
45
|
+
## Alternative Installation Methods
|
|
46
|
+
|
|
47
|
+
- **Linux/macOS**: `curl -fsSL https://raw.githubusercontent.com/oddessentials/odd-demonstration/main/install.sh | sh`
|
|
48
|
+
- **Windows**: `iwr -useb https://raw.githubusercontent.com/oddessentials/odd-demonstration/main/install.ps1 | iex`
|
|
49
|
+
- **Homebrew**: `brew install oddessentials/tap/odd-dashboard`
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* odd-dashboard npm shim - CLI entry point
|
|
4
|
+
*
|
|
5
|
+
* This wrapper script spawns the native binary with all arguments forwarded.
|
|
6
|
+
* If the binary is not installed, it displays installation instructions
|
|
7
|
+
* and exits with a non-zero status code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const { spawn } = require('child_process');
|
|
13
|
+
|
|
14
|
+
const binName = process.platform === 'win32' ? 'odd-dashboard.exe' : 'odd-dashboard';
|
|
15
|
+
const binPath = path.join(__dirname, binName);
|
|
16
|
+
const sentinelPath = path.join(__dirname, '..', '.install-failed');
|
|
17
|
+
|
|
18
|
+
// Check for installation failure sentinel
|
|
19
|
+
if (fs.existsSync(sentinelPath)) {
|
|
20
|
+
const reason = fs.readFileSync(sentinelPath, 'utf-8').trim();
|
|
21
|
+
|
|
22
|
+
console.error(`
|
|
23
|
+
╔════════════════════════════════════════════════════════════════════╗
|
|
24
|
+
║ odd-dashboard binary not installed ║
|
|
25
|
+
╠════════════════════════════════════════════════════════════════════╣
|
|
26
|
+
║ Reason: ${reason.substring(0, 54).padEnd(54)}║
|
|
27
|
+
║ ║
|
|
28
|
+
║ Manual installation options: ║
|
|
29
|
+
║ ║
|
|
30
|
+
║ Linux/macOS: ║
|
|
31
|
+
║ curl -fsSL https://raw.githubusercontent.com/oddessentials/ ║
|
|
32
|
+
║ odd-demonstration/main/install.sh | sh ║
|
|
33
|
+
║ ║
|
|
34
|
+
║ Windows PowerShell: ║
|
|
35
|
+
║ iwr -useb https://raw.githubusercontent.com/oddessentials/ ║
|
|
36
|
+
║ odd-demonstration/main/install.ps1 | iex ║
|
|
37
|
+
║ ║
|
|
38
|
+
║ Or download directly from GitHub Releases: ║
|
|
39
|
+
║ https://github.com/oddessentials/odd-demonstration/releases ║
|
|
40
|
+
╚════════════════════════════════════════════════════════════════════╝
|
|
41
|
+
`);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Check if binary exists
|
|
46
|
+
if (!fs.existsSync(binPath)) {
|
|
47
|
+
console.error(`
|
|
48
|
+
╔════════════════════════════════════════════════════════════════════╗
|
|
49
|
+
║ odd-dashboard binary not found ║
|
|
50
|
+
╠════════════════════════════════════════════════════════════════════╣
|
|
51
|
+
║ Expected at: ${binPath.substring(0, 50).padEnd(50)}║
|
|
52
|
+
║ ║
|
|
53
|
+
║ Try reinstalling: ║
|
|
54
|
+
║ npm install -g @oddessentials/odd-dashboard ║
|
|
55
|
+
╚════════════════════════════════════════════════════════════════════╝
|
|
56
|
+
`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Forward all arguments to the binary
|
|
61
|
+
const args = process.argv.slice(2);
|
|
62
|
+
const child = spawn(binPath, args, {
|
|
63
|
+
stdio: 'inherit',
|
|
64
|
+
windowsHide: true,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
child.on('error', (err) => {
|
|
68
|
+
console.error(`Failed to start odd-dashboard: ${err.message}`);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
child.on('close', (code) => {
|
|
73
|
+
process.exit(code ?? 0);
|
|
74
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@oddessentials/odd-dashboard",
|
|
3
|
+
"version": "0.3.7",
|
|
4
|
+
"description": "Terminal dashboard for Distributed Task Observatory",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/oddessentials/odd-demonstration.git"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"kubernetes",
|
|
11
|
+
"observability",
|
|
12
|
+
"dashboard",
|
|
13
|
+
"tui",
|
|
14
|
+
"cli"
|
|
15
|
+
],
|
|
16
|
+
"author": "OddEssentials",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"homepage": "https://github.com/oddessentials/odd-demonstration#readme",
|
|
19
|
+
"bin": {
|
|
20
|
+
"odd-dashboard": "bin/odd-dashboard.js"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"postinstall": "node scripts/install.js"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=16"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"bin/",
|
|
30
|
+
"scripts/"
|
|
31
|
+
]
|
|
32
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* odd-dashboard postinstall script
|
|
4
|
+
*
|
|
5
|
+
* Downloads the native binary from GitHub Releases with checksum verification.
|
|
6
|
+
* On failure, creates a sentinel file so the CLI wrapper can provide helpful
|
|
7
|
+
* error messages instead of silently failing.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const https = require('https');
|
|
13
|
+
const crypto = require('crypto');
|
|
14
|
+
|
|
15
|
+
const PLATFORM_MAP = {
|
|
16
|
+
'darwin-x64': 'odd-dashboard-macos-x64',
|
|
17
|
+
'darwin-arm64': 'odd-dashboard-macos-arm64',
|
|
18
|
+
'linux-x64': 'odd-dashboard-linux-x64',
|
|
19
|
+
'linux-arm64': 'odd-dashboard-linux-arm64',
|
|
20
|
+
'win32-x64': 'odd-dashboard-windows-x64.exe',
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const VERSION = require('../package.json').version;
|
|
24
|
+
const REPO = 'oddessentials/odd-demonstration';
|
|
25
|
+
const BASE_URL = `https://github.com/${REPO}/releases/download/v${VERSION}`;
|
|
26
|
+
|
|
27
|
+
const binDir = path.join(__dirname, '..', 'bin');
|
|
28
|
+
const sentinelPath = path.join(__dirname, '..', '.install-failed');
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Download a file from a URL, following redirects
|
|
32
|
+
*/
|
|
33
|
+
function download(url) {
|
|
34
|
+
return new Promise((resolve, reject) => {
|
|
35
|
+
const request = (url) => {
|
|
36
|
+
https.get(url, (res) => {
|
|
37
|
+
if (res.statusCode === 301 || res.statusCode === 302) {
|
|
38
|
+
// Follow redirect
|
|
39
|
+
request(res.headers.location);
|
|
40
|
+
} else if (res.statusCode !== 200) {
|
|
41
|
+
reject(new Error(`HTTP ${res.statusCode}: ${url}`));
|
|
42
|
+
} else {
|
|
43
|
+
const chunks = [];
|
|
44
|
+
res.on('data', (chunk) => chunks.push(chunk));
|
|
45
|
+
res.on('end', () => resolve(Buffer.concat(chunks)));
|
|
46
|
+
res.on('error', reject);
|
|
47
|
+
}
|
|
48
|
+
}).on('error', reject);
|
|
49
|
+
};
|
|
50
|
+
request(url);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Parse checksum file and find the expected hash for an artifact
|
|
56
|
+
*/
|
|
57
|
+
function parseChecksum(content, artifact) {
|
|
58
|
+
const lines = content.toString().split('\n');
|
|
59
|
+
for (const line of lines) {
|
|
60
|
+
const [hash, filename] = line.trim().split(/\s+/);
|
|
61
|
+
if (filename === artifact) {
|
|
62
|
+
return hash;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
throw new Error(`Artifact ${artifact} not found in SHA256SUMS`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Write failure sentinel file
|
|
70
|
+
*/
|
|
71
|
+
function writeSentinel(reason) {
|
|
72
|
+
fs.writeFileSync(sentinelPath, reason);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Remove failure sentinel if it exists
|
|
77
|
+
*/
|
|
78
|
+
function clearSentinel() {
|
|
79
|
+
if (fs.existsSync(sentinelPath)) {
|
|
80
|
+
fs.unlinkSync(sentinelPath);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function install() {
|
|
85
|
+
const platform = `${process.platform}-${process.arch}`;
|
|
86
|
+
const artifact = PLATFORM_MAP[platform];
|
|
87
|
+
|
|
88
|
+
if (!artifact) {
|
|
89
|
+
const msg = `Unsupported platform: ${platform}`;
|
|
90
|
+
console.log(`[odd-dashboard] ${msg}`);
|
|
91
|
+
console.log('[odd-dashboard] Binary not installed. Run `odd-dashboard` for manual installation options.');
|
|
92
|
+
writeSentinel(msg);
|
|
93
|
+
return; // Exit 0 to not break npm install
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const binName = process.platform === 'win32' ? 'odd-dashboard.exe' : 'odd-dashboard';
|
|
97
|
+
const binPath = path.join(binDir, binName);
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
// Ensure bin directory exists
|
|
101
|
+
fs.mkdirSync(binDir, { recursive: true });
|
|
102
|
+
|
|
103
|
+
console.log(`[odd-dashboard] Downloading ${artifact}...`);
|
|
104
|
+
|
|
105
|
+
// Download checksum file
|
|
106
|
+
const checksums = await download(`${BASE_URL}/SHA256SUMS`);
|
|
107
|
+
const expectedHash = parseChecksum(checksums, artifact);
|
|
108
|
+
|
|
109
|
+
// Download binary
|
|
110
|
+
const binary = await download(`${BASE_URL}/${artifact}`);
|
|
111
|
+
|
|
112
|
+
// Verify checksum
|
|
113
|
+
const actualHash = crypto.createHash('sha256').update(binary).digest('hex');
|
|
114
|
+
if (actualHash.toLowerCase() !== expectedHash.toLowerCase()) {
|
|
115
|
+
throw new Error(`Checksum mismatch! Expected: ${expectedHash}, Actual: ${actualHash}`);
|
|
116
|
+
}
|
|
117
|
+
console.log('[odd-dashboard] Checksum verified');
|
|
118
|
+
|
|
119
|
+
// Write binary
|
|
120
|
+
fs.writeFileSync(binPath, binary);
|
|
121
|
+
|
|
122
|
+
// Set executable permission on POSIX
|
|
123
|
+
if (process.platform !== 'win32') {
|
|
124
|
+
fs.chmodSync(binPath, 0o755);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
console.log(`[odd-dashboard] Installed to ${binPath}`);
|
|
128
|
+
clearSentinel();
|
|
129
|
+
|
|
130
|
+
} catch (err) {
|
|
131
|
+
const msg = err.message || String(err);
|
|
132
|
+
console.error(`[odd-dashboard] Installation failed: ${msg}`);
|
|
133
|
+
console.error('[odd-dashboard] Run `odd-dashboard` for manual installation options.');
|
|
134
|
+
writeSentinel(msg);
|
|
135
|
+
// Exit 0 to not break npm install - the CLI wrapper will handle the error
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
install();
|