roxify 1.14.1 → 1.14.3
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/cli.js +46 -23
- package/package.json +3 -6
- package/scripts/download-binary.cjs +259 -0
- package/scripts/postinstall.cjs +136 -110
- package/dist/rox-macos-universal +0 -0
- package/dist/roxify_native +0 -0
- package/dist/roxify_native-macos-arm64 +0 -0
- package/dist/roxify_native-macos-x64 +0 -0
- package/dist/roxify_native.exe +0 -0
- package/roxify_native-aarch64-apple-darwin.node +0 -0
- package/roxify_native-aarch64-pc-windows-msvc.node +0 -0
- package/roxify_native-aarch64-unknown-linux-gnu.node +0 -0
- package/roxify_native-i686-pc-windows-msvc.node +0 -0
- package/roxify_native-i686-unknown-linux-gnu.node +0 -0
- package/roxify_native-universal-apple-darwin.node +0 -0
- package/roxify_native-x86_64-apple-darwin.node +0 -0
- package/roxify_native-x86_64-pc-windows-msvc.node +0 -0
- package/roxify_native-x86_64-unknown-linux-gnu.node +0 -0
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import { readdirSync, readFileSync, statSync, writeFileSync } from 'fs';
|
|
|
3
3
|
import { open } from 'fs/promises';
|
|
4
4
|
import { basename, dirname, join, resolve } from 'path';
|
|
5
5
|
import * as cliProgress from './stub-progress.js';
|
|
6
|
-
import { encodeWithRustCLI, havepassphraseWithRustCLI, isRustBinaryAvailable, listWithRustCLI, } from './utils/rust-cli-wrapper.js';
|
|
6
|
+
import { decodeWithRustCLI, encodeWithRustCLI, havepassphraseWithRustCLI, isRustBinaryAvailable, listWithRustCLI, } from './utils/rust-cli-wrapper.js';
|
|
7
7
|
async function loadJsEngine() {
|
|
8
8
|
const indexMod = await import('./index.js');
|
|
9
9
|
const packMod = await import('./pack.js');
|
|
@@ -20,7 +20,7 @@ async function loadJsEngine() {
|
|
|
20
20
|
VFSIndexEntry: undefined,
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
|
-
const VERSION = '1.14.
|
|
23
|
+
const VERSION = '1.14.3';
|
|
24
24
|
function getDirectorySize(dirPath) {
|
|
25
25
|
let totalSize = 0;
|
|
26
26
|
try {
|
|
@@ -462,6 +462,38 @@ async function encodeCommand(args) {
|
|
|
462
462
|
else {
|
|
463
463
|
const resolvedInput = resolvedInputs[0];
|
|
464
464
|
const st = statSync(resolvedInput);
|
|
465
|
+
// Calculate total size for deciding whether to use Rust CLI streaming
|
|
466
|
+
const totalInputSize = st.isDirectory()
|
|
467
|
+
? getDirectorySize(resolvedInput)
|
|
468
|
+
: st.size;
|
|
469
|
+
// Use Rust CLI for large files (> 1GB) to avoid Buffer.concat 4GB limit
|
|
470
|
+
const STREAMING_THRESHOLD = 1024 * 1024 * 1024; // 1GB
|
|
471
|
+
if (totalInputSize > STREAMING_THRESHOLD && isRustBinaryAvailable()) {
|
|
472
|
+
console.log('Using native Rust encoder (streaming for large payload)\n');
|
|
473
|
+
const encodeStart = Date.now();
|
|
474
|
+
let lastPct = 0;
|
|
475
|
+
await encodeWithRustCLI(resolvedInput, resolvedOutput, parsed.level ? Number(parsed.level) : 6, parsed.passphrase, parsed.encrypt || 'aes', parsed.outputName || (st.isDirectory() ? basename(resolvedInput) : undefined), undefined, // ramBudgetMb
|
|
476
|
+
(current, total, step) => {
|
|
477
|
+
const pct = Math.floor((current / total) * 100);
|
|
478
|
+
if (pct !== lastPct) {
|
|
479
|
+
lastPct = pct;
|
|
480
|
+
if (barStarted) {
|
|
481
|
+
encodeBar.update(pct, { step });
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
});
|
|
485
|
+
const encodeTime = Date.now() - encodeStart;
|
|
486
|
+
if (barStarted) {
|
|
487
|
+
encodeBar.update(100, { step: 'done', elapsed: String(Math.floor(encodeTime / 1000)) });
|
|
488
|
+
encodeBar.stop();
|
|
489
|
+
}
|
|
490
|
+
console.log(`\nSuccess!`);
|
|
491
|
+
console.log(` Input: ${(totalInputSize / 1024 / 1024).toFixed(2)} MB`);
|
|
492
|
+
console.log(` Time: ${encodeTime}ms`);
|
|
493
|
+
console.log(` Saved: ${resolvedOutput}`);
|
|
494
|
+
console.log(' ');
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
465
497
|
if (st.isDirectory()) {
|
|
466
498
|
currentEncodeStep = 'Reading files';
|
|
467
499
|
const { index, stream, totalSize } = await js.packPathsGenerator([resolvedInput], dirname(resolvedInput), onProgress);
|
|
@@ -591,33 +623,24 @@ async function decodeCommand(args) {
|
|
|
591
623
|
}
|
|
592
624
|
const resolvedInput = resolve(inputPath);
|
|
593
625
|
const resolvedOutput = parsed.output || outputPath || '.';
|
|
626
|
+
if (!isRustBinaryAvailable()) {
|
|
627
|
+
console.error('Error: Rust decoder binary not found');
|
|
628
|
+
process.exit(1);
|
|
629
|
+
}
|
|
594
630
|
try {
|
|
595
631
|
console.log(' ');
|
|
596
632
|
console.log('Decoding... (Using native Rust decoder)\n');
|
|
597
633
|
const startTime = Date.now();
|
|
598
634
|
const decodeBar = new cliProgress.SingleBar({ format: ' {bar} {percentage}% | {step} | {elapsed}s' }, cliProgress.Presets.shades_classic);
|
|
599
635
|
decodeBar.start(100, 0, { step: 'Decoding', elapsed: '0' });
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
await import('fs/promises').then(({ mkdir }) => mkdir(parent, { recursive: true }));
|
|
609
|
-
}
|
|
610
|
-
catch { }
|
|
611
|
-
writeFileSync(dest, file.buf);
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
else if (result.buf) {
|
|
615
|
-
const outputFile = resolvedOutput === '.' ? join(process.cwd(), result.meta?.name || basename(resolvedInput).replace(/\.[^.]+$/, '')) : resolvedOutput;
|
|
616
|
-
writeFileSync(outputFile, result.buf);
|
|
617
|
-
}
|
|
618
|
-
else {
|
|
619
|
-
throw new Error('Decoded result is empty');
|
|
620
|
-
}
|
|
636
|
+
await decodeWithRustCLI(resolvedInput, resolvedOutput, parsed.passphrase, parsed.files, parsed.dict, parsed.ramBudgetMb, (current, total, step) => {
|
|
637
|
+
const pct = total > 0 ? Math.floor((current / total) * 100) : 0;
|
|
638
|
+
const elapsed = Math.floor((Date.now() - startTime) / 1000);
|
|
639
|
+
decodeBar.update(Math.min(pct, 99), {
|
|
640
|
+
step: step || 'Decoding',
|
|
641
|
+
elapsed: String(elapsed),
|
|
642
|
+
});
|
|
643
|
+
});
|
|
621
644
|
const decodeTime = Date.now() - startTime;
|
|
622
645
|
decodeBar.update(100, { step: 'done', elapsed: String(Math.floor(decodeTime / 1000)) });
|
|
623
646
|
decodeBar.stop();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "roxify",
|
|
3
|
-
"version": "1.14.
|
|
3
|
+
"version": "1.14.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Ultra-lightweight PNG steganography with native Rust acceleration. Encode binary data into PNG images with zstd compression.",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -12,11 +12,8 @@
|
|
|
12
12
|
"files": [
|
|
13
13
|
"dist/**/*.js",
|
|
14
14
|
"dist/**/*.d.ts",
|
|
15
|
-
"dist/roxify_native*",
|
|
16
|
-
"dist/rox-macos-universal",
|
|
17
15
|
"scripts/postinstall.cjs",
|
|
18
|
-
"
|
|
19
|
-
"libroxify_native-*.node",
|
|
16
|
+
"scripts/download-binary.cjs",
|
|
20
17
|
"README.md",
|
|
21
18
|
"LICENSE"
|
|
22
19
|
],
|
|
@@ -96,4 +93,4 @@
|
|
|
96
93
|
"node": ">=18.0.0"
|
|
97
94
|
},
|
|
98
95
|
"dependencies": {}
|
|
99
|
-
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
const https = require('https');
|
|
2
|
+
const { createWriteStream, existsSync, mkdirSync, chmodSync, unlinkSync } = require('fs');
|
|
3
|
+
const { join } = require('path');
|
|
4
|
+
const { platform, arch } = require('os');
|
|
5
|
+
|
|
6
|
+
const GITHUB_REPO = 'RoxasYTB/roxify';
|
|
7
|
+
const DIST_DIR = join(__dirname, '..', 'dist');
|
|
8
|
+
const root = join(__dirname, '..');
|
|
9
|
+
|
|
10
|
+
function getPlatformBinary() {
|
|
11
|
+
const os = platform();
|
|
12
|
+
const cpu = arch();
|
|
13
|
+
|
|
14
|
+
const map = {
|
|
15
|
+
linux: { x64: 'roxify_native', arm64: 'roxify_native' },
|
|
16
|
+
win32: { x64: 'roxify_native.exe', arm64: 'roxify_native.exe' },
|
|
17
|
+
darwin: { x64: 'rox-macos-universal', arm64: 'rox-macos-universal' },
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
return (map[os] && map[os][cpu]) || null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function getReleaseAssetName(version) {
|
|
24
|
+
const os = platform();
|
|
25
|
+
const cpu = arch();
|
|
26
|
+
|
|
27
|
+
// Map platform/arch to release asset names as uploaded by GitHub Actions
|
|
28
|
+
const map = {
|
|
29
|
+
linux: {
|
|
30
|
+
x64: `roxify_native-x86_64-unknown-linux-gnu`,
|
|
31
|
+
arm64: `roxify_native-aarch64-unknown-linux-gnu`
|
|
32
|
+
},
|
|
33
|
+
win32: {
|
|
34
|
+
x64: `roxify_native-x86_64-pc-windows-msvc.exe`,
|
|
35
|
+
arm64: `roxify_native-aarch64-pc-windows-msvc.exe`
|
|
36
|
+
},
|
|
37
|
+
darwin: {
|
|
38
|
+
x64: `rox-macos-universal`,
|
|
39
|
+
arm64: `rox-macos-universal`
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
return (map[os] && map[os][cpu]) || null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function getNativeLibAssetName(version) {
|
|
47
|
+
const os = platform();
|
|
48
|
+
const cpu = arch();
|
|
49
|
+
|
|
50
|
+
const triples = {
|
|
51
|
+
linux: { x64: 'x86_64-unknown-linux-gnu', arm64: 'aarch64-unknown-linux-gnu' },
|
|
52
|
+
win32: { x64: 'x86_64-pc-windows-msvc', arm64: 'aarch64-pc-windows-msvc' },
|
|
53
|
+
darwin: { x64: 'x86_64-apple-darwin', arm64: 'aarch64-apple-darwin' },
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const triple = triples[os] && triples[os][cpu];
|
|
57
|
+
if (!triple) return null;
|
|
58
|
+
|
|
59
|
+
return `roxify_native-${triple}.node`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function downloadFile(url, dest, maxRedirects = 5) {
|
|
63
|
+
return new Promise((resolve, reject) => {
|
|
64
|
+
if (maxRedirects <= 0) {
|
|
65
|
+
reject(new Error('Too many redirects'));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const file = createWriteStream(dest);
|
|
70
|
+
const request = https.get(url, { timeout: 60000 }, (response) => {
|
|
71
|
+
// Handle redirects
|
|
72
|
+
if (response.statusCode === 302 || response.statusCode === 301) {
|
|
73
|
+
const location = response.headers.location;
|
|
74
|
+
if (location) {
|
|
75
|
+
file.close();
|
|
76
|
+
// Clean up partial file
|
|
77
|
+
try { unlinkSync(dest); } catch { }
|
|
78
|
+
downloadFile(location, dest, maxRedirects - 1).then(resolve).catch(reject);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (response.statusCode !== 200) {
|
|
84
|
+
file.close();
|
|
85
|
+
try { unlinkSync(dest); } catch { }
|
|
86
|
+
reject(new Error(`HTTP ${response.statusCode} for ${url}`));
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
let downloaded = 0;
|
|
91
|
+
response.on('data', (chunk) => {
|
|
92
|
+
downloaded += chunk.length;
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
response.pipe(file);
|
|
96
|
+
|
|
97
|
+
file.on('finish', () => {
|
|
98
|
+
file.close();
|
|
99
|
+
console.log(`roxify: Downloaded ${(downloaded / 1024 / 1024).toFixed(2)} MB`);
|
|
100
|
+
resolve();
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
request.on('error', (err) => {
|
|
105
|
+
file.close();
|
|
106
|
+
try { unlinkSync(dest); } catch { }
|
|
107
|
+
reject(err);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
request.on('timeout', () => {
|
|
111
|
+
request.destroy();
|
|
112
|
+
file.close();
|
|
113
|
+
try { unlinkSync(dest); } catch { }
|
|
114
|
+
reject(new Error('Request timeout'));
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function getLatestReleaseVersion() {
|
|
120
|
+
const url = `https://api.github.com/repos/${GITHUB_REPO}/releases/latest`;
|
|
121
|
+
|
|
122
|
+
return new Promise((resolve, reject) => {
|
|
123
|
+
https.get(url, {
|
|
124
|
+
headers: {
|
|
125
|
+
'User-Agent': 'roxify-install',
|
|
126
|
+
'Accept': 'application/vnd.github.v3+json'
|
|
127
|
+
},
|
|
128
|
+
timeout: 10000
|
|
129
|
+
}, (response) => {
|
|
130
|
+
if (response.statusCode !== 200) {
|
|
131
|
+
reject(new Error(`GitHub API HTTP ${response.statusCode}`));
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let data = '';
|
|
136
|
+
response.on('data', chunk => data += chunk);
|
|
137
|
+
response.on('end', () => {
|
|
138
|
+
try {
|
|
139
|
+
const release = JSON.parse(data);
|
|
140
|
+
const version = release.tag_name.replace(/^v/, '');
|
|
141
|
+
resolve(version);
|
|
142
|
+
} catch (e) {
|
|
143
|
+
reject(new Error('Failed to parse GitHub API response'));
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}).on('error', reject).on('timeout', function () { this.destroy(); reject(new Error('API timeout')); });
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async function downloadBinary() {
|
|
151
|
+
let version;
|
|
152
|
+
try {
|
|
153
|
+
version = require('../package.json').version;
|
|
154
|
+
} catch (e) {
|
|
155
|
+
version = '1.14.2';
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Try to get latest release version from GitHub
|
|
159
|
+
try {
|
|
160
|
+
const latestVersion = await getLatestReleaseVersion();
|
|
161
|
+
if (latestVersion && latestVersion !== version) {
|
|
162
|
+
console.log(`roxify: Latest release is v${latestVersion} (package is v${version})`);
|
|
163
|
+
version = latestVersion;
|
|
164
|
+
}
|
|
165
|
+
} catch (e) {
|
|
166
|
+
console.log(`roxify: Using package version v${version} (could not check latest: ${e.message})`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const binaryName = getPlatformBinary();
|
|
170
|
+
const assetName = getReleaseAssetName(version);
|
|
171
|
+
|
|
172
|
+
if (!binaryName || !assetName) {
|
|
173
|
+
console.log(`roxify: Unsupported platform ${platform()}/${arch()}`);
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (!existsSync(DIST_DIR)) {
|
|
178
|
+
mkdirSync(DIST_DIR, { recursive: true });
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const destPath = join(DIST_DIR, binaryName);
|
|
182
|
+
|
|
183
|
+
// Check if already exists
|
|
184
|
+
if (existsSync(destPath)) {
|
|
185
|
+
console.log(`roxify: CLI binary already exists at ${destPath}`);
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const url = `https://github.com/${GITHUB_REPO}/releases/download/v${version}/${assetName}`;
|
|
190
|
+
|
|
191
|
+
console.log(`roxify: Downloading ${assetName} from GitHub...`);
|
|
192
|
+
console.log(`roxify: URL: ${url}`);
|
|
193
|
+
|
|
194
|
+
try {
|
|
195
|
+
await downloadFile(url, destPath);
|
|
196
|
+
|
|
197
|
+
if (platform() !== 'win32') {
|
|
198
|
+
try { chmodSync(destPath, 0o755); } catch { }
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
console.log(`roxify: CLI binary ready at ${destPath}`);
|
|
202
|
+
return true;
|
|
203
|
+
} catch (e) {
|
|
204
|
+
console.log(`roxify: Download failed: ${e.message}`);
|
|
205
|
+
// Clean up partial download
|
|
206
|
+
try { unlinkSync(destPath); } catch { }
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
async function downloadNativeLib() {
|
|
212
|
+
let version;
|
|
213
|
+
try {
|
|
214
|
+
version = require('../package.json').version;
|
|
215
|
+
} catch (e) {
|
|
216
|
+
version = '1.14.2';
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Try to get latest release version from GitHub
|
|
220
|
+
try {
|
|
221
|
+
const latestVersion = await getLatestReleaseVersion();
|
|
222
|
+
if (latestVersion && latestVersion !== version) {
|
|
223
|
+
version = latestVersion;
|
|
224
|
+
}
|
|
225
|
+
} catch (e) {
|
|
226
|
+
// Use package version
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const assetName = getNativeLibAssetName(version);
|
|
230
|
+
|
|
231
|
+
if (!assetName) {
|
|
232
|
+
console.log(`roxify: Unsupported platform for native lib ${platform()}/${arch()}`);
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const destPath = join(root, assetName);
|
|
237
|
+
|
|
238
|
+
// Check if already exists
|
|
239
|
+
if (existsSync(destPath)) {
|
|
240
|
+
console.log(`roxify: Native lib already exists at ${destPath}`);
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const url = `https://github.com/${GITHUB_REPO}/releases/download/v${version}/${assetName}`;
|
|
245
|
+
|
|
246
|
+
console.log(`roxify: Downloading native lib ${assetName}...`);
|
|
247
|
+
|
|
248
|
+
try {
|
|
249
|
+
await downloadFile(url, destPath);
|
|
250
|
+
console.log(`roxify: Native lib ready at ${destPath}`);
|
|
251
|
+
return true;
|
|
252
|
+
} catch (e) {
|
|
253
|
+
console.log(`roxify: Native lib download failed: ${e.message}`);
|
|
254
|
+
try { unlinkSync(destPath); } catch { }
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
module.exports = { downloadBinary, downloadNativeLib, getPlatformBinary, getLatestReleaseVersion };
|
package/scripts/postinstall.cjs
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
const { execSync } = require('child_process');
|
|
2
|
-
const { existsSync, copyFileSync, mkdirSync, readdirSync, unlinkSync } = require('fs');
|
|
2
|
+
const { existsSync, copyFileSync, mkdirSync, readdirSync, unlinkSync, chmodSync } = require('fs');
|
|
3
3
|
const { join } = require('path');
|
|
4
4
|
const { platform, arch } = require('os');
|
|
5
5
|
|
|
6
6
|
const root = join(__dirname, '..');
|
|
7
7
|
const distDir = join(root, 'dist');
|
|
8
8
|
|
|
9
|
+
// Try to import download helper
|
|
10
|
+
try {
|
|
11
|
+
var { downloadBinary, downloadNativeLib } = require('./download-binary.cjs');
|
|
12
|
+
} catch (e) {
|
|
13
|
+
console.log('roxify: Download helper not available, will use local build only');
|
|
14
|
+
var downloadBinary = null;
|
|
15
|
+
var downloadNativeLib = null;
|
|
16
|
+
}
|
|
17
|
+
|
|
9
18
|
function hasCargo() {
|
|
10
19
|
try {
|
|
11
20
|
execSync('cargo --version', { stdio: 'ignore', timeout: 5000 });
|
|
@@ -18,165 +27,182 @@ function getTriples() {
|
|
|
18
27
|
const cpu = arch();
|
|
19
28
|
const map = {
|
|
20
29
|
linux: { x64: ['x86_64-unknown-linux-gnu'], arm64: ['aarch64-unknown-linux-gnu'] },
|
|
21
|
-
win32: { x64: ['x86_64-pc-windows-msvc'
|
|
30
|
+
win32: { x64: ['x86_64-pc-windows-msvc'], arm64: ['aarch64-pc-windows-msvc'] },
|
|
22
31
|
darwin: { x64: ['x86_64-apple-darwin'], arm64: ['aarch64-apple-darwin'] },
|
|
23
32
|
};
|
|
24
33
|
return (map[os] && map[os][cpu]) || [];
|
|
25
34
|
}
|
|
26
35
|
|
|
27
|
-
function getLibExt() {
|
|
28
|
-
if (platform() === 'win32') return 'dll';
|
|
29
|
-
if (platform() === 'darwin') return 'dylib';
|
|
30
|
-
return 'so';
|
|
31
|
-
}
|
|
32
|
-
|
|
33
36
|
function getBinaryName() {
|
|
34
37
|
return platform() === 'win32' ? 'roxify_native.exe' : 'roxify_native';
|
|
35
38
|
}
|
|
36
39
|
|
|
37
|
-
function
|
|
38
|
-
|
|
39
|
-
const triples = getTriples();
|
|
40
|
-
const candidates = [join(distDir, name), join(root, 'target', 'release', name)];
|
|
41
|
-
for (const t of triples) {
|
|
42
|
-
candidates.push(join(root, 'target', t, 'release', name));
|
|
43
|
-
}
|
|
44
|
-
for (const c of candidates) {
|
|
45
|
-
if (existsSync(c)) return c;
|
|
46
|
-
}
|
|
47
|
-
return null;
|
|
40
|
+
function getMacosBinaryName() {
|
|
41
|
+
return 'rox-macos-universal';
|
|
48
42
|
}
|
|
49
43
|
|
|
50
|
-
function
|
|
51
|
-
const triples = getTriples();
|
|
52
|
-
const ext = getLibExt();
|
|
53
|
-
const prefix = platform() === 'win32' ? '' : 'lib';
|
|
54
|
-
for (const t of triples) {
|
|
55
|
-
const specific = join(root, `roxify_native-${t}.node`);
|
|
56
|
-
if (existsSync(specific)) return { path: specific, triple: t };
|
|
57
|
-
}
|
|
58
|
-
for (const t of triples) {
|
|
59
|
-
for (const profile of ['release', 'fastdev']) {
|
|
60
|
-
const paths = [
|
|
61
|
-
join(root, 'target', t, profile, `${prefix}roxify_native.${ext}`),
|
|
62
|
-
join(root, 'target', profile, `${prefix}roxify_native.${ext}`),
|
|
63
|
-
];
|
|
64
|
-
for (const p of paths) {
|
|
65
|
-
if (existsSync(p)) return { path: p, triple: t };
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
return null;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function buildNative(target) {
|
|
73
|
-
if (!hasCargo()) return false;
|
|
74
|
-
const args = target ? ` --target ${target}` : '';
|
|
75
|
-
console.log(`roxify: Building native lib${args}...`);
|
|
76
|
-
try {
|
|
77
|
-
execSync(`cargo build --release --lib${args}`, { cwd: root, stdio: 'inherit', timeout: 600000 });
|
|
78
|
-
return true;
|
|
79
|
-
} catch {
|
|
80
|
-
console.log('roxify: Native lib build failed');
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function buildBinary() {
|
|
44
|
+
function buildBinaryLocally() {
|
|
86
45
|
if (!hasCargo()) {
|
|
87
|
-
console.log('roxify: Cargo not found,
|
|
46
|
+
console.log('roxify: Cargo not found, will try to download prebuilt binary');
|
|
88
47
|
return false;
|
|
89
48
|
}
|
|
90
|
-
console.log('roxify: Building native CLI binary...');
|
|
49
|
+
console.log('roxify: Building native CLI binary locally...');
|
|
91
50
|
try {
|
|
92
51
|
execSync('cargo build --release --bin roxify_native', { cwd: root, stdio: 'inherit', timeout: 600000 });
|
|
93
52
|
return true;
|
|
94
|
-
} catch {
|
|
95
|
-
console.log('roxify:
|
|
53
|
+
} catch (e) {
|
|
54
|
+
console.log('roxify: Local build failed, will try to download prebuilt binary');
|
|
96
55
|
return false;
|
|
97
56
|
}
|
|
98
57
|
}
|
|
99
58
|
|
|
100
|
-
function ensureCliBinary() {
|
|
59
|
+
async function ensureCliBinary() {
|
|
101
60
|
if (!existsSync(distDir)) mkdirSync(distDir, { recursive: true });
|
|
102
|
-
const dest = join(distDir, getBinaryName());
|
|
103
|
-
if (existsSync(dest)) return;
|
|
104
61
|
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
62
|
+
const binaryName = platform() === 'darwin' ? getMacosBinaryName() : getBinaryName();
|
|
63
|
+
const dest = join(distDir, binaryName);
|
|
64
|
+
|
|
65
|
+
if (existsSync(dest)) {
|
|
66
|
+
console.log(`roxify: CLI binary already exists at ${dest}`);
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Check if built locally exists
|
|
71
|
+
const localBuilt = join(root, 'target', 'release', getBinaryName());
|
|
72
|
+
if (existsSync(localBuilt)) {
|
|
73
|
+
copyFileSync(localBuilt, dest);
|
|
108
74
|
if (platform() !== 'win32') {
|
|
109
|
-
try {
|
|
75
|
+
try { chmodSync(dest, 0o755); } catch { }
|
|
110
76
|
}
|
|
111
|
-
console.log(`roxify:
|
|
112
|
-
return;
|
|
77
|
+
console.log(`roxify: CLI binary copied from local build`);
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (process.env.ROXIFY_SKIP_BUILD === '1') return false;
|
|
82
|
+
|
|
83
|
+
// PRIMARY: Try download from GitHub releases (fast, no compilation)
|
|
84
|
+
if (downloadBinary && !process.env.ROXIFY_FORCE_LOCAL_BUILD) {
|
|
85
|
+
console.log(`roxify: Attempting to download prebuilt binary from GitHub...`);
|
|
86
|
+
const downloaded = await downloadBinary();
|
|
87
|
+
if (downloaded) {
|
|
88
|
+
console.log(`roxify: Successfully downloaded prebuilt binary`);
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
console.log(`roxify: Download failed, will try local build...`);
|
|
113
92
|
}
|
|
114
|
-
if (existing) return;
|
|
115
|
-
if (process.env.ROXIFY_SKIP_BUILD === '1') return;
|
|
116
93
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (existsSync(
|
|
120
|
-
copyFileSync(
|
|
94
|
+
// FALLBACK: Try local build (requires Cargo)
|
|
95
|
+
if (buildBinaryLocally()) {
|
|
96
|
+
if (existsSync(localBuilt)) {
|
|
97
|
+
copyFileSync(localBuilt, dest);
|
|
121
98
|
if (platform() !== 'win32') {
|
|
122
|
-
try {
|
|
99
|
+
try { chmodSync(dest, 0o755); } catch { }
|
|
123
100
|
}
|
|
124
|
-
console.log(
|
|
101
|
+
console.log(`roxify: CLI binary built locally`);
|
|
102
|
+
return true;
|
|
125
103
|
}
|
|
126
104
|
}
|
|
105
|
+
|
|
106
|
+
console.log('roxify: No native binary available, TypeScript fallback will be used');
|
|
107
|
+
return false;
|
|
127
108
|
}
|
|
128
109
|
|
|
129
|
-
function ensureNativeLib() {
|
|
110
|
+
async function ensureNativeLib() {
|
|
130
111
|
const triples = getTriples();
|
|
131
112
|
if (!triples.length) return;
|
|
132
113
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
114
|
+
const triple = triples[0];
|
|
115
|
+
const dest = join(root, `roxify_native-${triple}.node`);
|
|
116
|
+
|
|
117
|
+
if (existsSync(dest)) return;
|
|
118
|
+
|
|
119
|
+
// Check if built locally
|
|
120
|
+
const ext = platform() === 'win32' ? 'dll' : (platform() === 'darwin' ? 'dylib' : 'so');
|
|
121
|
+
const prefix = platform() === 'win32' ? '' : 'lib';
|
|
122
|
+
const localBuilt = join(root, 'target', 'release', `${prefix}roxify_native.${ext}`);
|
|
136
123
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
copyFileSync(found.path, dest);
|
|
141
|
-
console.log(`roxify: Copied native lib → ${dest}`);
|
|
124
|
+
if (existsSync(localBuilt)) {
|
|
125
|
+
copyFileSync(localBuilt, dest);
|
|
126
|
+
console.log(`roxify: Native lib copied from local build → ${dest}`);
|
|
142
127
|
return;
|
|
143
128
|
}
|
|
144
129
|
|
|
145
130
|
if (process.env.ROXIFY_SKIP_BUILD === '1') return;
|
|
146
131
|
|
|
147
|
-
|
|
148
|
-
if (
|
|
149
|
-
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
copyFileSync(built, dest);
|
|
155
|
-
console.log(`roxify: Native lib built → ${dest}`);
|
|
132
|
+
// PRIMARY: Try download from GitHub releases
|
|
133
|
+
if (downloadNativeLib && !process.env.ROXIFY_FORCE_LOCAL_BUILD) {
|
|
134
|
+
console.log(`roxify: Attempting to download native lib from GitHub...`);
|
|
135
|
+
const downloaded = await downloadNativeLib();
|
|
136
|
+
if (downloaded) {
|
|
137
|
+
console.log(`roxify: Successfully downloaded native lib`);
|
|
138
|
+
return;
|
|
156
139
|
}
|
|
140
|
+
console.log(`roxify: Native lib download failed, will try local build...`);
|
|
157
141
|
}
|
|
158
|
-
}
|
|
159
142
|
|
|
160
|
-
|
|
161
|
-
|
|
143
|
+
// FALLBACK: Try build locally
|
|
144
|
+
if (hasCargo()) {
|
|
145
|
+
console.log(`roxify: Building native lib locally...`);
|
|
146
|
+
try {
|
|
147
|
+
execSync('cargo build --release --lib', { cwd: root, stdio: 'inherit', timeout: 600000 });
|
|
148
|
+
if (existsSync(localBuilt)) {
|
|
149
|
+
copyFileSync(localBuilt, dest);
|
|
150
|
+
console.log(`roxify: Native lib built locally → ${dest}`);
|
|
151
|
+
}
|
|
152
|
+
} catch {
|
|
153
|
+
console.log('roxify: Native lib build failed, TypeScript fallback will be used');
|
|
154
|
+
}
|
|
155
|
+
}
|
|
162
156
|
}
|
|
163
|
-
ensureNativeLib();
|
|
164
157
|
|
|
165
|
-
//
|
|
158
|
+
// Always ensure CLI binary is available (download first, build as fallback)
|
|
159
|
+
(async () => {
|
|
160
|
+
await ensureCliBinary();
|
|
161
|
+
await ensureNativeLib();
|
|
162
|
+
|
|
163
|
+
// Summary
|
|
164
|
+
console.log('');
|
|
165
|
+
console.log('roxify: Post-install complete');
|
|
166
|
+
console.log(`roxify: Platform: ${platform()}/${arch()}`);
|
|
167
|
+
if (!existsSync(join(distDir, platform() === 'darwin' ? getMacosBinaryName() : getBinaryName()))) {
|
|
168
|
+
console.log('roxify: WARNING: No native CLI binary available - will use TypeScript fallback');
|
|
169
|
+
}
|
|
170
|
+
})();
|
|
171
|
+
|
|
172
|
+
// Cleanup: remove ALL other platform .node artifacts
|
|
166
173
|
try {
|
|
167
174
|
const triples = getTriples();
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
const
|
|
173
|
-
if (
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
175
|
+
const files = readdirSync(root);
|
|
176
|
+
for (const f of files) {
|
|
177
|
+
const m = f.match(/^roxify_native-(.+)\.node$/);
|
|
178
|
+
if (m) {
|
|
179
|
+
const fileTriple = m[1];
|
|
180
|
+
if (!triples.includes(fileTriple)) {
|
|
181
|
+
try {
|
|
182
|
+
unlinkSync(join(root, f));
|
|
183
|
+
console.log(`roxify: removed unused native lib ${f}`);
|
|
184
|
+
} catch (e) { }
|
|
179
185
|
}
|
|
180
186
|
}
|
|
181
187
|
}
|
|
182
188
|
} catch (e) { }
|
|
189
|
+
|
|
190
|
+
// Cleanup: remove ALL other platform CLI binaries from dist/
|
|
191
|
+
try {
|
|
192
|
+
const os = platform();
|
|
193
|
+
const distFiles = existsSync(distDir) ? readdirSync(distDir) : [];
|
|
194
|
+
const keepName = os === 'darwin' ? getMacosBinaryName() : getBinaryName();
|
|
195
|
+
|
|
196
|
+
for (const f of distFiles) {
|
|
197
|
+
// Skip if it's the correct binary for this platform
|
|
198
|
+
if (f === keepName) continue;
|
|
199
|
+
|
|
200
|
+
// Remove any roxify_native binary
|
|
201
|
+
if (f.match(/^roxify_native/) || f === 'rox-macos-universal') {
|
|
202
|
+
try {
|
|
203
|
+
unlinkSync(join(distDir, f));
|
|
204
|
+
console.log(`roxify: removed unused binary dist/${f}`);
|
|
205
|
+
} catch (e) { }
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
} catch (e) { }
|
package/dist/rox-macos-universal
DELETED
|
Binary file
|
package/dist/roxify_native
DELETED
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/roxify_native.exe
DELETED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|