@shello/bin 0.1.0
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/bin/shello.js +18 -0
- package/package.json +41 -0
- package/postinstall.js +139 -0
package/bin/shello.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const { execFileSync } = require('child_process')
|
|
3
|
+
const fs = require('fs')
|
|
4
|
+
const path = require('path')
|
|
5
|
+
|
|
6
|
+
const binary = path.join(__dirname, 'shello')
|
|
7
|
+
|
|
8
|
+
if (!fs.existsSync(binary)) {
|
|
9
|
+
console.error('shello binary not found. Run: npm rebuild shello')
|
|
10
|
+
console.error('Or install directly: curl -fsSL https://get.shello.to | sh')
|
|
11
|
+
process.exit(1)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
execFileSync(binary, process.argv.slice(2), { stdio: 'inherit' })
|
|
16
|
+
} catch (err) {
|
|
17
|
+
process.exit(err.status || 1)
|
|
18
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@shello/bin",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "P2P terminal access — no ports, no cloud, just connect",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/shelloto/shello.git",
|
|
9
|
+
"directory": "packages/shello-npm"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://say.shello.to",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"terminal",
|
|
14
|
+
"ssh",
|
|
15
|
+
"p2p",
|
|
16
|
+
"remote",
|
|
17
|
+
"webrtc",
|
|
18
|
+
"peer-to-peer"
|
|
19
|
+
],
|
|
20
|
+
"bin": {
|
|
21
|
+
"shello": "./bin/shello.js"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"bin/shello.js",
|
|
25
|
+
"postinstall.js"
|
|
26
|
+
],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"postinstall": "node postinstall.js"
|
|
29
|
+
},
|
|
30
|
+
"os": [
|
|
31
|
+
"darwin",
|
|
32
|
+
"linux"
|
|
33
|
+
],
|
|
34
|
+
"cpu": [
|
|
35
|
+
"arm64",
|
|
36
|
+
"x64"
|
|
37
|
+
],
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=16"
|
|
40
|
+
}
|
|
41
|
+
}
|
package/postinstall.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const fs = require('fs')
|
|
3
|
+
const path = require('path')
|
|
4
|
+
const https = require('https')
|
|
5
|
+
const crypto = require('crypto')
|
|
6
|
+
|
|
7
|
+
const REPO = 'shelloto/shello'
|
|
8
|
+
const BINARY = 'shello'
|
|
9
|
+
|
|
10
|
+
const PLATFORM_MAP = { darwin: 'darwin', linux: 'linux' }
|
|
11
|
+
const ARCH_MAP = { arm64: 'arm64', x64: 'amd64' }
|
|
12
|
+
|
|
13
|
+
const platform = PLATFORM_MAP[process.platform]
|
|
14
|
+
const arch = ARCH_MAP[process.arch]
|
|
15
|
+
|
|
16
|
+
if (process.env.SHELLO_SKIP_INSTALL) {
|
|
17
|
+
console.log('Skipping shello binary download (SHELLO_SKIP_INSTALL set)')
|
|
18
|
+
process.exit(0)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (!platform || !arch) {
|
|
22
|
+
console.error(`Unsupported platform: ${process.platform}/${process.arch}`)
|
|
23
|
+
console.error('Supported: darwin/arm64, darwin/x64, linux/arm64, linux/x64')
|
|
24
|
+
process.exit(1)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const binDir = path.join(__dirname, 'bin')
|
|
28
|
+
const binPath = path.join(binDir, BINARY)
|
|
29
|
+
|
|
30
|
+
function httpsGet(url) {
|
|
31
|
+
return new Promise((resolve, reject) => {
|
|
32
|
+
https.get(url, { headers: { 'User-Agent': 'shello-npm' } }, (res) => {
|
|
33
|
+
if (res.statusCode === 301 || res.statusCode === 302) {
|
|
34
|
+
return httpsGet(res.headers.location).then(resolve).catch(reject)
|
|
35
|
+
}
|
|
36
|
+
if (res.statusCode !== 200) {
|
|
37
|
+
return reject(new Error(`HTTP ${res.statusCode} from ${url}`))
|
|
38
|
+
}
|
|
39
|
+
resolve(res)
|
|
40
|
+
}).on('error', reject)
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function fetchJSON(url) {
|
|
45
|
+
return new Promise((resolve, reject) => {
|
|
46
|
+
httpsGet(url).then((res) => {
|
|
47
|
+
let data = ''
|
|
48
|
+
res.on('data', (chunk) => (data += chunk))
|
|
49
|
+
res.on('end', () => {
|
|
50
|
+
try {
|
|
51
|
+
resolve(JSON.parse(data))
|
|
52
|
+
} catch (e) {
|
|
53
|
+
reject(new Error(`Failed to parse JSON from ${url}: ${e.message}`))
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
}).catch(reject)
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function fetchText(url) {
|
|
61
|
+
return new Promise((resolve, reject) => {
|
|
62
|
+
httpsGet(url).then((res) => {
|
|
63
|
+
let data = ''
|
|
64
|
+
res.on('data', (chunk) => (data += chunk))
|
|
65
|
+
res.on('end', () => resolve(data))
|
|
66
|
+
}).catch(reject)
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function download(url, dest) {
|
|
71
|
+
return new Promise((resolve, reject) => {
|
|
72
|
+
httpsGet(url).then((res) => {
|
|
73
|
+
const file = fs.createWriteStream(dest)
|
|
74
|
+
res.pipe(file)
|
|
75
|
+
file.on('finish', () => {
|
|
76
|
+
file.close()
|
|
77
|
+
resolve()
|
|
78
|
+
})
|
|
79
|
+
file.on('error', (err) => {
|
|
80
|
+
fs.unlink(dest, () => {})
|
|
81
|
+
reject(err)
|
|
82
|
+
})
|
|
83
|
+
}).catch(reject)
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function main() {
|
|
88
|
+
const release = await fetchJSON(
|
|
89
|
+
`https://api.github.com/repos/${REPO}/releases/latest`
|
|
90
|
+
)
|
|
91
|
+
const tag = release.tag_name
|
|
92
|
+
if (!tag) {
|
|
93
|
+
throw new Error('No releases found. Install manually: https://say.shello.to')
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const binaryName = `${BINARY}-${platform}-${arch}`
|
|
97
|
+
const binaryURL = `https://github.com/${REPO}/releases/download/${tag}/${binaryName}`
|
|
98
|
+
|
|
99
|
+
console.log(`Downloading ${BINARY} ${tag} (${platform}/${arch})...`)
|
|
100
|
+
|
|
101
|
+
fs.mkdirSync(binDir, { recursive: true })
|
|
102
|
+
await download(binaryURL, binPath)
|
|
103
|
+
fs.chmodSync(binPath, 0o755)
|
|
104
|
+
|
|
105
|
+
// Verify checksum if available
|
|
106
|
+
try {
|
|
107
|
+
const checksums = await fetchText(
|
|
108
|
+
`https://github.com/${REPO}/releases/download/${tag}/checksums.txt`
|
|
109
|
+
)
|
|
110
|
+
const expected = checksums
|
|
111
|
+
.split('\n')
|
|
112
|
+
.find((line) => line.includes(binaryName))
|
|
113
|
+
if (expected) {
|
|
114
|
+
const hash = crypto
|
|
115
|
+
.createHash('sha256')
|
|
116
|
+
.update(fs.readFileSync(binPath))
|
|
117
|
+
.digest('hex')
|
|
118
|
+
const expectedHash = expected.split(/\s+/)[0]
|
|
119
|
+
if (hash !== expectedHash) {
|
|
120
|
+
fs.unlinkSync(binPath)
|
|
121
|
+
throw new Error(
|
|
122
|
+
`Checksum mismatch: expected ${expectedHash}, got ${hash}`
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
console.log('Checksum verified.')
|
|
126
|
+
}
|
|
127
|
+
} catch (e) {
|
|
128
|
+
if (e.message.includes('Checksum mismatch')) throw e
|
|
129
|
+
// Checksums file not available — that's OK
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
console.log(`Installed ${BINARY} ${tag} to ${binPath}`)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
main().catch((err) => {
|
|
136
|
+
console.error(`Failed to install shello: ${err.message}`)
|
|
137
|
+
console.error('You can install manually: curl -fsSL https://get.shello.to | sh')
|
|
138
|
+
process.exit(1)
|
|
139
|
+
})
|