roxify 1.14.1 → 1.14.2
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/Cargo.toml +76 -0
- package/dist/cli.js +45 -22
- package/native/archive.rs +220 -0
- package/native/audio.rs +151 -0
- package/native/bench_hybrid.rs +145 -0
- package/native/bwt.rs +56 -0
- package/native/context_mixing.rs +117 -0
- package/native/core.rs +378 -0
- package/native/crypto.rs +209 -0
- package/native/encoder.rs +405 -0
- package/native/hybrid.rs +297 -0
- package/native/image_utils.rs +82 -0
- package/native/io_advice.rs +43 -0
- package/native/io_ntfs_optimized.rs +99 -0
- package/native/lib.rs +480 -0
- package/native/main.rs +939 -0
- package/native/mtf.rs +106 -0
- package/native/packer.rs +863 -0
- package/native/png_chunk_writer.rs +146 -0
- package/native/png_utils.rs +554 -0
- package/native/pool.rs +101 -0
- package/native/progress.rs +142 -0
- package/native/rans.rs +149 -0
- package/native/rans_byte.rs +286 -0
- package/native/reconstitution.rs +623 -0
- package/native/streaming.rs +189 -0
- package/native/streaming_decode.rs +720 -0
- package/native/streaming_encode.rs +684 -0
- package/native/test_small_bwt.rs +31 -0
- package/native/test_stages.rs +70 -0
- package/package.json +6 -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
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
mod bwt;
|
|
2
|
+
mod mtf;
|
|
3
|
+
mod rans_byte;
|
|
4
|
+
mod context_mixing;
|
|
5
|
+
mod pool;
|
|
6
|
+
|
|
7
|
+
fn main() {
|
|
8
|
+
let data = b"banana";
|
|
9
|
+
|
|
10
|
+
// Test BWT
|
|
11
|
+
let bwt_result = bwt::bwt_encode(data).unwrap();
|
|
12
|
+
println!("BWT of 'banana': {:?}", String::from_utf8_lossy(&bwt_result.transformed));
|
|
13
|
+
println!("Primary index: {}", bwt_result.primary_index);
|
|
14
|
+
|
|
15
|
+
let decoded = bwt::bwt_decode(&bwt_result.transformed, bwt_result.primary_index).unwrap();
|
|
16
|
+
println!("BWT decode: {:?}", String::from_utf8_lossy(&decoded));
|
|
17
|
+
assert_eq!(&decoded, data, "BWT round-trip failed");
|
|
18
|
+
println!("BWT round-trip OK!\n");
|
|
19
|
+
|
|
20
|
+
// Test MTF
|
|
21
|
+
let mtf_enc = mtf::mtf_encode(data);
|
|
22
|
+
println!("MTF of 'banana': {:?}", mtf_enc);
|
|
23
|
+
let mtf_dec = mtf::mtf_decode(&mtf_enc);
|
|
24
|
+
assert_eq!(mtf_dec, data, "MTF round-trip failed");
|
|
25
|
+
println!("MTF round-trip OK!\n");
|
|
26
|
+
|
|
27
|
+
// Test RLE0
|
|
28
|
+
let test_rle = vec![0, 0, 0, 5, 0, 3, 0, 0, 0, 0, 0, 7];
|
|
29
|
+
let rle_enc = mtf::rle0_encode(&test_rle);
|
|
30
|
+
println!("RLE0 of {:?}: {:?}", test_rle, rle_enc);
|
|
31
|
+
let rle_dec = mtf::rle0_decode(&rle_enc);
|
|
32
|
+
println!("RLE0 decode: {:?}", rle_dec);
|
|
33
|
+
assert_eq!(rle_dec, test_rle, "RLE0 round-trip failed");
|
|
34
|
+
println!("RLE0 round-trip OK!\n");
|
|
35
|
+
|
|
36
|
+
// Test rANS byte
|
|
37
|
+
let test_data = b"abracadabra";
|
|
38
|
+
let stats = rans_byte::SymbolStats::from_data(test_data);
|
|
39
|
+
let encoded = rans_byte::rans_encode_block(test_data, &stats);
|
|
40
|
+
println!("rANS encoded 'abracadabra': {} bytes -> {} bytes", test_data.len(), encoded.len());
|
|
41
|
+
let decoded = rans_byte::rans_decode_block(&encoded, &stats, test_data.len()).unwrap();
|
|
42
|
+
assert_eq!(&decoded, test_data, "rANS round-trip failed");
|
|
43
|
+
println!("rANS round-trip OK!\n");
|
|
44
|
+
|
|
45
|
+
// Test full pipeline on larger data
|
|
46
|
+
let big_data: Vec<u8> = "Hello World! Testing the full BWT+MTF+RLE+rANS pipeline. ".repeat(20).into_bytes();
|
|
47
|
+
let bwt_r = bwt::bwt_encode(&big_data).unwrap();
|
|
48
|
+
let mtf_r = mtf::mtf_encode(&bwt_r.transformed);
|
|
49
|
+
let rle_r = mtf::rle0_encode(&mtf_r);
|
|
50
|
+
let stats = rans_byte::SymbolStats::from_data(&rle_r);
|
|
51
|
+
let enc = rans_byte::rans_encode_block(&rle_r, &stats);
|
|
52
|
+
|
|
53
|
+
println!("Full pipeline: {} -> BWT {} -> MTF {} -> RLE {} -> rANS {}",
|
|
54
|
+
big_data.len(), bwt_r.transformed.len(), mtf_r.len(), rle_r.len(), enc.len());
|
|
55
|
+
|
|
56
|
+
let dec_rle = rans_byte::rans_decode_block(&enc, &stats, rle_r.len()).unwrap();
|
|
57
|
+
assert_eq!(dec_rle, rle_r, "rANS stage failed");
|
|
58
|
+
|
|
59
|
+
let dec_mtf = mtf::rle0_decode(&dec_rle);
|
|
60
|
+
assert_eq!(dec_mtf, mtf_r, "RLE0 stage failed");
|
|
61
|
+
|
|
62
|
+
let dec_bwt = mtf::mtf_decode(&dec_mtf);
|
|
63
|
+
assert_eq!(dec_bwt, bwt_r.transformed, "MTF stage failed");
|
|
64
|
+
|
|
65
|
+
let dec_orig = bwt::bwt_decode(&dec_bwt, bwt_r.primary_index).unwrap();
|
|
66
|
+
assert_eq!(dec_orig, big_data, "BWT stage failed");
|
|
67
|
+
|
|
68
|
+
println!("Full pipeline round-trip OK!");
|
|
69
|
+
println!("Ratio: {:.1}%", (enc.len() as f64 / big_data.len() as f64) * 100.0);
|
|
70
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "roxify",
|
|
3
|
-
"version": "1.14.
|
|
3
|
+
"version": "1.14.2",
|
|
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,11 @@
|
|
|
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
|
-
"
|
|
16
|
+
"scripts/download-binary.cjs",
|
|
17
|
+
"native/Cargo.toml",
|
|
18
|
+
"native/**/*.rs",
|
|
19
|
+
"Cargo.toml",
|
|
20
20
|
"README.md",
|
|
21
21
|
"LICENSE"
|
|
22
22
|
],
|
|
@@ -96,4 +96,4 @@
|
|
|
96
96
|
"node": ">=18.0.0"
|
|
97
97
|
},
|
|
98
98
|
"dependencies": {}
|
|
99
|
-
}
|
|
99
|
+
}
|
|
@@ -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
|