pi-bridge 0.3.3 → 0.3.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-bridge",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "description": "Transparent filesystem bridge that makes pi run natively on a remote machine over SSH",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -4,6 +4,7 @@ const fs = require('fs');
4
4
  const fsp = require('fs/promises');
5
5
  const http = require('http');
6
6
  const path = require('path');
7
+ const { fileURLToPath } = require('url');
7
8
  const { isFakePath, toRemotePath } = require('./path-mapper');
8
9
  const { httpGet, httpPost } = require('./http-client');
9
10
 
@@ -127,9 +128,28 @@ function patchFs(fakeRoot, port, token) {
127
128
  cp: fs.promises.cp ? fs.promises.cp.bind(fs.promises) : undefined,
128
129
  };
129
130
 
130
- // Resolve any path (relative or absolute) to absolute before checking fake root
131
+ // Resolve any path (relative or absolute) to absolute before checking fake root.
132
+ // file: URLs are accepted too: jiti's bundled ESM resolver probes package
133
+ // mains with fs.statSync(new URL(...)), which must reach the remote.
134
+ // Buffer paths deliberately pass through: Node 20's JS rmSync walks children
135
+ // as Buffers via the public fs.*, and routing those would make removeFakeDir
136
+ // list and delete files on the remote.
131
137
  function abs(p) {
132
- return typeof p === 'string' ? path.resolve(p) : null;
138
+ if (typeof p === 'string') return path.resolve(p);
139
+ if (p instanceof URL) return p.protocol === 'file:' ? path.resolve(fileURLToPath(p)) : null;
140
+ return null;
141
+ }
142
+
143
+ // Shared by statSync/lstatSync. Honours { throwIfNoEntry: false }, which the
144
+ // ESM resolver relies on to probe candidate files without try/catch.
145
+ function statRemoteSync(s, opts) {
146
+ try {
147
+ return makeStats(JSON.parse(httpGet(port, token, '/stat?path=' + encodeURIComponent(rpath(s)))));
148
+ } catch (e) {
149
+ const missing = e && e.message && (e.message.includes('ENOENT') || e.message.includes('403'));
150
+ if (missing && opts && opts.throwIfNoEntry === false) return undefined;
151
+ rethrowRemote(e, s);
152
+ }
133
153
  }
134
154
 
135
155
  function rpath(fakePath) {
@@ -229,17 +249,13 @@ function patchFs(fakeRoot, port, token) {
229
249
  fs.statSync = function patchedStatSync(p, opts) {
230
250
  const s = abs(p);
231
251
  if (!s || !isFakePath(s, fakeRoot)) return orig.statSync(p, opts);
232
- try {
233
- return makeStats(JSON.parse(httpGet(port, token, '/stat?path=' + encodeURIComponent(rpath(s)))));
234
- } catch (e) { rethrowRemote(e, s); }
252
+ return statRemoteSync(s, opts);
235
253
  };
236
254
 
237
255
  fs.lstatSync = function patchedLstatSync(p, opts) {
238
256
  const s = abs(p);
239
257
  if (!s || !isFakePath(s, fakeRoot)) return orig.lstatSync(p, opts);
240
- try {
241
- return makeStats(JSON.parse(httpGet(port, token, '/stat?path=' + encodeURIComponent(rpath(s)))));
242
- } catch (e) { rethrowRemote(e, s); }
258
+ return statRemoteSync(s, opts);
243
259
  };
244
260
 
245
261
  fs.writeFileSync = function patchedWriteFileSync(p, data, opts) {
@@ -359,7 +375,7 @@ function patchFs(fakeRoot, port, token) {
359
375
 
360
376
  // createReadStream: read entire file from remote, pipe as stream
361
377
  fs.createReadStream = function patchedCreateReadStream(p, opts) {
362
- const s = typeof p === 'string' ? abs(p) : null;
378
+ const s = abs(p);
363
379
  if (!s || !isFakePath(s, fakeRoot)) return orig.createReadStream(p, opts);
364
380
  const { Readable } = require('stream');
365
381
  const stream = new Readable({ read() {} });
@@ -372,7 +388,7 @@ function patchFs(fakeRoot, port, token) {
372
388
 
373
389
  // createWriteStream: buffer writes, POST on finish
374
390
  fs.createWriteStream = function patchedCreateWriteStream(p, opts) {
375
- const s = typeof p === 'string' ? abs(p) : null;
391
+ const s = abs(p);
376
392
  if (!s || !isFakePath(s, fakeRoot)) return orig.createWriteStream(p, opts);
377
393
  const { Writable } = require('stream');
378
394
  const chunks = [];
@@ -402,7 +418,7 @@ function patchFs(fakeRoot, port, token) {
402
418
  };
403
419
 
404
420
  fs.promises.readFile = async function patchedReadFile(p, opts) {
405
- const s = typeof p === 'string' ? abs(p) : null;
421
+ const s = abs(p);
406
422
  if (!s || !isFakePath(s, fakeRoot)) return origP.readFile(p, opts);
407
423
  try {
408
424
  const body = await httpGetAsync(port, token, '/read?path=' + encodeURIComponent(rpath(s)));
@@ -416,7 +432,7 @@ function patchFs(fakeRoot, port, token) {
416
432
  };
417
433
 
418
434
  fs.promises.readdir = async function patchedReaddir(p, opts) {
419
- const s = typeof p === 'string' ? abs(p) : p.toString();
435
+ const s = abs(p) || p.toString();
420
436
  if (!isFakePath(s, fakeRoot)) return origP.readdir(p, opts);
421
437
  try {
422
438
  const withFileTypes = opts && opts.withFileTypes;
@@ -465,7 +481,7 @@ function patchFs(fakeRoot, port, token) {
465
481
  };
466
482
 
467
483
  fs.promises.writeFile = async function patchedWriteFile(p, data, opts) {
468
- const s = typeof p === 'string' ? abs(p) : null;
484
+ const s = abs(p);
469
485
  if (!s || !isFakePath(s, fakeRoot)) return origP.writeFile(p, data, opts);
470
486
  const content = Buffer.isBuffer(data) ? data.toString('utf8') : String(data);
471
487
  await new Promise(function(resolve, reject) {
@@ -517,7 +533,7 @@ function patchFs(fakeRoot, port, token) {
517
533
  };
518
534
 
519
535
  fs.promises.appendFile = async function patchedAppendFile(p, data, opts) {
520
- const s = typeof p === 'string' ? abs(p) : null;
536
+ const s = abs(p);
521
537
  if (!s || !isFakePath(s, fakeRoot)) return origP.appendFile(p, data, opts);
522
538
  const content = Buffer.isBuffer(data) ? data.toString('utf8') : String(data);
523
539
  const buf = Buffer.from(content, 'utf8');
@@ -614,7 +630,7 @@ function patchFs(fakeRoot, port, token) {
614
630
 
615
631
  // fs.promises.open: return a minimal FileHandle for reading
616
632
  fs.promises.open = async function patchedOpen(p, flags, mode) {
617
- const s = typeof p === 'string' ? abs(p) : null;
633
+ const s = abs(p);
618
634
  if (!s || !isFakePath(s, fakeRoot)) return origP.open(p, flags, mode);
619
635
  // Fetch the file content eagerly; return a minimal FileHandle-like object
620
636
  const content = await httpGetAsync(port, token, '/read?path=' + encodeURIComponent(rpath(s)));
@@ -646,7 +662,7 @@ function patchFs(fakeRoot, port, token) {
646
662
  const watchFilePollers = new Map();
647
663
 
648
664
  fs.watch = function patchedWatch(filename, opts, listener) {
649
- const s = abs(typeof filename === 'string' ? filename : null);
665
+ const s = abs(filename);
650
666
  if (!s || !isFakePath(s, fakeRoot)) return origWatch(filename, opts, listener);
651
667
 
652
668
  if (typeof opts === 'function') { listener = opts; opts = {}; }
@@ -711,7 +727,7 @@ function patchFs(fakeRoot, port, token) {
711
727
  };
712
728
 
713
729
  fs.watchFile = function patchedWatchFile(filename, opts, listener) {
714
- const s = abs(typeof filename === 'string' ? filename : null);
730
+ const s = abs(filename);
715
731
  if (!s || !isFakePath(s, fakeRoot)) {
716
732
  return origWatchFile ? origWatchFile(filename, opts, listener) : undefined;
717
733
  }
@@ -741,7 +757,7 @@ function patchFs(fakeRoot, port, token) {
741
757
  };
742
758
 
743
759
  fs.unwatchFile = function patchedUnwatchFile(filename, listener) {
744
- const s = abs(typeof filename === 'string' ? filename : null);
760
+ const s = abs(filename);
745
761
  if (!s || !isFakePath(s, fakeRoot)) {
746
762
  return origUnwatchFile ? origUnwatchFile(filename, listener) : undefined;
747
763
  }