@compressius/cmx 0.1.19
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 +21 -0
- package/bin/cmx.js +34 -0
- package/package.json +31 -0
- package/scripts/install.js +76 -0
package/README.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# CMX
|
|
2
|
+
|
|
3
|
+
This package installs the CMX binary for your platform from its matching GitHub Release and verifies it against that release's `SHA256SUMS` file.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm install --global @compressius/cmx
|
|
7
|
+
# or
|
|
8
|
+
pnpm add --global @compressius/cmx
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
The `latest` npm tag tracks stable CMX releases. The `nightly` tag tracks prereleases:
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm install --global @compressius/cmx@nightly
|
|
15
|
+
# or
|
|
16
|
+
pnpm add --global @compressius/cmx@nightly
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Supported platforms are macOS and Linux on x64 or ARM64, plus Windows on x64 or ARM64. The package requires Node.js 18 or newer only during installation; `cmx` itself is a standalone native binary.
|
|
20
|
+
|
|
21
|
+
Some pnpm configurations block dependency lifecycle scripts by default. In that case, the first `cmx` command downloads and verifies the same matching binary automatically.
|
package/bin/cmx.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const { spawnSync } = require('node:child_process');
|
|
5
|
+
const fs = require('node:fs');
|
|
6
|
+
const path = require('node:path');
|
|
7
|
+
|
|
8
|
+
const platforms = { darwin: 'darwin', linux: 'linux', win32: 'windows' };
|
|
9
|
+
const architectures = { x64: 'amd64', arm64: 'arm64' };
|
|
10
|
+
const os = platforms[process.platform];
|
|
11
|
+
const arch = architectures[process.arch];
|
|
12
|
+
|
|
13
|
+
if (!os || !arch) {
|
|
14
|
+
console.error(`CMX does not support ${process.platform}/${process.arch}.`);
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async function main() {
|
|
19
|
+
const extension = os === 'windows' ? '.exe' : '';
|
|
20
|
+
const binary = path.join(__dirname, '..', 'platform', `cmx-${os}-${arch}${extension}`);
|
|
21
|
+
if (!fs.existsSync(binary)) await require('../scripts/install').install();
|
|
22
|
+
|
|
23
|
+
const result = spawnSync(binary, process.argv.slice(2), { stdio: 'inherit' });
|
|
24
|
+
if (result.error) {
|
|
25
|
+
console.error(`Unable to run CMX: ${result.error.message}`);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
process.exit(result.status ?? 1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
main().catch((error) => {
|
|
32
|
+
console.error(`CMX installation failed: ${error.message}`);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@compressius/cmx",
|
|
3
|
+
"version": "0.1.19",
|
|
4
|
+
"description": "CMX local context-compression gateway",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/administrakt0r/cmx2.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://compressi.us",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/administrakt0r/cmx2/issues"
|
|
13
|
+
},
|
|
14
|
+
"bin": {
|
|
15
|
+
"cmx": "bin/cmx.js"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"postinstall": "node scripts/install.js"
|
|
19
|
+
},
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=18"
|
|
22
|
+
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"bin",
|
|
28
|
+
"scripts",
|
|
29
|
+
"README.md"
|
|
30
|
+
]
|
|
31
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const crypto = require('node:crypto');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const https = require('node:https');
|
|
6
|
+
const path = require('node:path');
|
|
7
|
+
|
|
8
|
+
const packageJson = require('../package.json');
|
|
9
|
+
const platforms = { darwin: 'darwin', linux: 'linux', win32: 'windows' };
|
|
10
|
+
const architectures = { x64: 'amd64', arm64: 'arm64' };
|
|
11
|
+
const os = platforms[process.platform];
|
|
12
|
+
const arch = architectures[process.arch];
|
|
13
|
+
|
|
14
|
+
if (!os || !arch) {
|
|
15
|
+
throw new Error(`CMX does not support ${process.platform}/${process.arch}.`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const asset = `cmx-${os}-${arch}${os === 'windows' ? '.exe' : ''}`;
|
|
19
|
+
const tag = `v${packageJson.version}`;
|
|
20
|
+
const releaseBase = `https://github.com/administrakt0r/cmx/releases/download/${tag}`;
|
|
21
|
+
|
|
22
|
+
function download(url, redirects = 0) {
|
|
23
|
+
if (redirects > 5) return Promise.reject(new Error(`Too many redirects downloading ${url}.`));
|
|
24
|
+
return new Promise((resolve, reject) => {
|
|
25
|
+
const request = https.get(url, { headers: { 'User-Agent': 'cmx-npm-installer' } }, (response) => {
|
|
26
|
+
if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
|
|
27
|
+
response.resume();
|
|
28
|
+
resolve(download(new URL(response.headers.location, url), redirects + 1));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (response.statusCode !== 200) {
|
|
32
|
+
response.resume();
|
|
33
|
+
reject(new Error(`Download failed for ${url}: HTTP ${response.statusCode}.`));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const chunks = [];
|
|
37
|
+
response.on('data', (chunk) => chunks.push(chunk));
|
|
38
|
+
response.on('end', () => resolve(Buffer.concat(chunks)));
|
|
39
|
+
});
|
|
40
|
+
request.setTimeout(60_000, () => request.destroy(new Error(`Timed out downloading ${url}.`)));
|
|
41
|
+
request.on('error', reject);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function checksumFor(sums) {
|
|
46
|
+
const escapedAsset = asset.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
47
|
+
const expression = new RegExp(`^([a-fA-F0-9]{64})\\s+\\*?${escapedAsset}$`, 'm');
|
|
48
|
+
const match = sums.toString('utf8').match(expression);
|
|
49
|
+
if (!match) throw new Error(`Release checksum is missing for ${asset}.`);
|
|
50
|
+
return match[1].toLowerCase();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function install() {
|
|
54
|
+
const [binary, sums] = await Promise.all([
|
|
55
|
+
download(`${releaseBase}/${asset}`),
|
|
56
|
+
download(`${releaseBase}/SHA256SUMS`),
|
|
57
|
+
]);
|
|
58
|
+
const actual = crypto.createHash('sha256').update(binary).digest('hex');
|
|
59
|
+
if (actual !== checksumFor(sums)) throw new Error(`Checksum mismatch for ${asset}; CMX was not installed.`);
|
|
60
|
+
|
|
61
|
+
const platformDir = path.join(__dirname, '..', 'platform');
|
|
62
|
+
fs.mkdirSync(platformDir, { recursive: true });
|
|
63
|
+
const destination = path.join(platformDir, asset);
|
|
64
|
+
fs.writeFileSync(destination, binary, { mode: 0o755 });
|
|
65
|
+
if (os !== 'windows') fs.chmodSync(destination, 0o755);
|
|
66
|
+
console.log(`Installed CMX ${tag} for ${os}/${arch}.`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
module.exports = { install };
|
|
70
|
+
|
|
71
|
+
if (require.main === module) {
|
|
72
|
+
install().catch((error) => {
|
|
73
|
+
console.error(`CMX installation failed: ${error.message}`);
|
|
74
|
+
process.exitCode = 1;
|
|
75
|
+
});
|
|
76
|
+
}
|