roxify 1.5.9 → 1.5.10

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 CHANGED
@@ -195,6 +195,28 @@ async function encodeCommand(args) {
195
195
  catch (e) {
196
196
  resolvedOutput = join('/', parsed.output || outputPath || outputName);
197
197
  }
198
+ // Check for empty directories *before* attempting native Rust encoder.
199
+ try {
200
+ const anyDir = inputPaths.some((p) => {
201
+ try {
202
+ return statSync(resolve(safeCwd, p)).isDirectory();
203
+ }
204
+ catch (e) {
205
+ return false;
206
+ }
207
+ });
208
+ if (anyDir) {
209
+ const { index } = await packPathsGenerator(inputPaths, undefined, () => { });
210
+ if (!index || index.length === 0) {
211
+ console.log(' ');
212
+ console.error('Error: No files found in specified input paths.');
213
+ process.exit(1);
214
+ }
215
+ }
216
+ }
217
+ catch (e) {
218
+ // ignore errors from the quick pre-check and proceed to try Rust encoding
219
+ }
198
220
  if (isRustBinaryAvailable() && !parsed.forceTs) {
199
221
  try {
200
222
  console.log(`Encoding to ${resolvedOutput} (Using native Rust encoder)\n`);
@@ -313,6 +335,11 @@ async function encodeCommand(args) {
313
335
  if (inputPaths.length > 1) {
314
336
  currentEncodeStep = 'Reading files';
315
337
  const { index, stream, totalSize } = await packPathsGenerator(inputPaths, undefined, onProgress);
338
+ if (!index || index.length === 0) {
339
+ console.log(' ');
340
+ console.error('Error: No files found in specified input paths.');
341
+ process.exit(1);
342
+ }
316
343
  inputData = stream;
317
344
  inputSizeVal = totalSize;
318
345
  displayName = parsed.outputName || 'archive';
@@ -328,6 +355,11 @@ async function encodeCommand(args) {
328
355
  if (st.isDirectory()) {
329
356
  currentEncodeStep = 'Reading files';
330
357
  const { index, stream, totalSize } = await packPathsGenerator([resolvedInput], dirname(resolvedInput), onProgress);
358
+ if (!index || index.length === 0) {
359
+ console.log(' ');
360
+ console.error(`Error: No files found in ${resolvedInput}`);
361
+ process.exit(1);
362
+ }
331
363
  inputData = stream;
332
364
  inputSizeVal = totalSize;
333
365
  displayName = parsed.outputName || basename(resolvedInput);
@@ -1,8 +1,8 @@
1
- import { arch, platform } from 'os';
2
- import { join, dirname, resolve } from 'path';
1
+ import { existsSync } from 'fs';
3
2
  import { createRequire } from 'module';
3
+ import { arch, platform } from 'os';
4
+ import { dirname, join, resolve } from 'path';
4
5
  import { fileURLToPath } from 'url';
5
- import { existsSync } from 'fs';
6
6
  function getNativeModule() {
7
7
  let moduleDir;
8
8
  let nativeRequire;
@@ -59,7 +59,9 @@ function getNativeModule() {
59
59
  // @ts-ignore
60
60
  console.debug('[native] moduleDir', moduleDir);
61
61
  let root = moduleDir && moduleDir !== '.' ? moduleDir : process.cwd();
62
- while (root.length > 1 && !existsSync(resolve(root, 'package.json')) && !existsSync(resolve(root, 'Cargo.toml'))) {
62
+ while (root.length > 1 &&
63
+ !existsSync(resolve(root, 'package.json')) &&
64
+ !existsSync(resolve(root, 'Cargo.toml'))) {
63
65
  const parent = resolve(root, '..');
64
66
  if (parent === root)
65
67
  break;
@@ -23,27 +23,51 @@ function findRustBinary() {
23
23
  const binNames = process.platform === 'win32'
24
24
  ? ['roxify-cli.exe', 'roxify_cli.exe', 'roxify_native.exe']
25
25
  : ['roxify-cli', 'roxify_cli', 'roxify_native'];
26
+ const baseDir = typeof moduleDir !== 'undefined' ? moduleDir : process.cwd();
26
27
  // Possible locations relative to this file (works in repo and in packaged dist)
27
28
  const relativeDirs = [
28
- join(__dirname, '..', '..', 'target', 'release'),
29
- join(__dirname, '..', '..', 'dist'),
30
- join(__dirname, '..'),
31
- join(__dirname, '..', '..'),
29
+ join(baseDir, '..', '..', 'target', 'release'),
30
+ join(baseDir, '..', '..', 'dist'),
31
+ join(baseDir, '..'),
32
+ join(baseDir, '..', '..'),
33
+ join(baseDir, '..', 'target', 'release'),
32
34
  ];
33
35
  for (const dir of relativeDirs) {
34
36
  for (const name of binNames) {
35
37
  candidates.push(join(dir, name));
36
38
  }
37
39
  }
38
- // Common global paths
40
+ // Walk up parents to find a workspace-level target/release (repo root may contain target)
41
+ try {
42
+ let cur = baseDir;
43
+ for (let i = 0; i < 8; i++) {
44
+ for (const name of binNames) {
45
+ candidates.push(join(cur, '..', '..', '..', '..', '..', '..', '..', 'target', 'release', name));
46
+ candidates.push(join(cur, '..', '..', '..', '..', '..', 'target', 'release', name));
47
+ candidates.push(join(cur, '..', '..', '..', 'target', 'release', name));
48
+ candidates.push(join(cur, '..', '..', 'target', 'release', name));
49
+ candidates.push(join(cur, '..', 'target', 'release', name));
50
+ candidates.push(join(cur, 'target', 'release', name));
51
+ }
52
+ const parent = join(cur, '..');
53
+ if (parent === cur)
54
+ break;
55
+ cur = parent;
56
+ }
57
+ }
58
+ catch (e) { }
59
+ // Common global paths (last resort)
39
60
  if (process.platform !== 'win32') {
40
61
  candidates.push('/usr/local/bin/roxify_native');
41
62
  candidates.push('/usr/bin/roxify_native');
42
63
  }
43
64
  for (const p of candidates) {
44
65
  try {
45
- if (existsSync(p))
66
+ if (existsSync(p)) {
67
+ // eslint-disable-next-line no-console
68
+ console.log(`Found Rust binary candidate: ${p}`);
46
69
  return p;
70
+ }
47
71
  }
48
72
  catch (e) { }
49
73
  }
@@ -56,8 +80,11 @@ function findRustBinary() {
56
80
  const out = execSync(`${which} ${name}`, { encoding: 'utf-8' })
57
81
  .split('\n')[0]
58
82
  .trim();
59
- if (out && existsSync(out))
83
+ if (out && existsSync(out)) {
84
+ // eslint-disable-next-line no-console
85
+ console.debug(`Found Rust binary in PATH: ${out}`);
60
86
  return out;
87
+ }
61
88
  }
62
89
  catch (e) {
63
90
  // ignore
@@ -76,30 +103,66 @@ export async function encodeWithRustCLI(inputPath, outputPath, compressionLevel
76
103
  throw new Error('Rust CLI binary not found. Run: cargo build --release');
77
104
  }
78
105
  return new Promise((resolve, reject) => {
79
- const args = ['encode', '--level', String(compressionLevel)];
80
- if (name) {
81
- args.push('--name', name);
82
- }
83
- if (passphrase) {
84
- args.push('--passphrase', passphrase);
85
- args.push('--encrypt', encryptType);
86
- }
106
+ const baseArgs = ['encode', '--level', String(compressionLevel)];
107
+ const addNameArgs = (arr) => {
108
+ if (name) {
109
+ arr.push('--name', name);
110
+ }
111
+ };
112
+ const addPassArgs = (arr) => {
113
+ if (passphrase) {
114
+ arr.push('--passphrase', passphrase);
115
+ arr.push('--encrypt', encryptType);
116
+ }
117
+ };
118
+ const args = [...baseArgs];
119
+ addNameArgs(args);
120
+ addPassArgs(args);
87
121
  args.push(inputPath, outputPath);
88
- const proc = spawn(cliPath, args);
89
- let stderr = '';
90
- proc.stderr.on('data', (data) => {
91
- stderr += data.toString();
92
- });
93
- proc.on('error', (err) => {
94
- reject(new Error(`Failed to spawn Rust CLI: ${err.message}`));
95
- });
96
- proc.on('close', (code) => {
97
- if (code === 0) {
98
- resolve();
122
+ const spawnAndWait = (argsToUse) => {
123
+ return new Promise((res, rej) => {
124
+ const proc = spawn(cliPath, argsToUse);
125
+ let stderr = '';
126
+ proc.stderr.on('data', (data) => {
127
+ stderr += data.toString();
128
+ });
129
+ proc.on('error', (err) => rej(err));
130
+ proc.on('close', (code) => res({ code, stderr }));
131
+ });
132
+ };
133
+ (async () => {
134
+ try {
135
+ const debugMsg = `Rust CLI: ${cliPath} ${args.join(' ')}`;
136
+ // eslint-disable-next-line no-console
137
+ console.log(debugMsg);
138
+ let result = await spawnAndWait(args);
139
+ if (result.code === 0)
140
+ return resolve();
141
+ // If the error mentions an unexpected '--name' arg (older binary), retry without name
142
+ if (name &&
143
+ result.stderr &&
144
+ (/unexpected argument.*--name/.test(result.stderr) ||
145
+ /unexpected argument .*'--name'/.test(result.stderr) ||
146
+ result.stderr.includes("'--name'"))) {
147
+ const argsNoName = [...baseArgs];
148
+ addPassArgs(argsNoName);
149
+ argsNoName.push(inputPath, outputPath);
150
+ // eslint-disable-next-line no-console
151
+ console.log('Rust CLI rejected --name; retrying without --name');
152
+ const retryDebug = `Retrying Rust CLI: ${cliPath} ${argsNoName.join(' ')}`;
153
+ // eslint-disable-next-line no-console
154
+ console.log(retryDebug);
155
+ result = await spawnAndWait(argsNoName);
156
+ // eslint-disable-next-line no-console
157
+ console.log(`Rust retry exited with code ${result.code}`);
158
+ if (result.code === 0)
159
+ return resolve();
160
+ }
161
+ reject(new Error(`Rust CLI exited with code ${result.code}: ${result.stderr}`));
99
162
  }
100
- else {
101
- reject(new Error(`Rust CLI exited with code ${code}: ${stderr}`));
163
+ catch (err) {
164
+ reject(new Error(`Failed to spawn Rust CLI: ${err.message || err}`));
102
165
  }
103
- });
166
+ })();
104
167
  });
105
168
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roxify",
3
- "version": "1.5.9",
3
+ "version": "1.5.10",
4
4
  "description": "Ultra-lightweight PNG steganography with native Rust acceleration. Encode binary data into PNG images with zstd compression.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",