@photostructure/fs-metadata 0.3.2 → 0.3.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.
Files changed (68) hide show
  1. package/CHANGELOG.md +13 -3
  2. package/README.md +3 -3
  3. package/dist/index.cjs +324 -215
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.mjs +329 -215
  6. package/dist/index.mjs.map +1 -1
  7. package/dist/types/debuglog.d.ts +2 -6
  8. package/dist/types/defer.d.ts +1 -2
  9. package/dist/types/dirname.d.ts +1 -0
  10. package/dist/types/hidden.d.ts +5 -42
  11. package/dist/types/index.d.ts +91 -2
  12. package/dist/types/linux/mount_points.d.ts +2 -2
  13. package/dist/types/linux/mtab.d.ts +2 -2
  14. package/dist/types/mount_point.d.ts +1 -46
  15. package/dist/types/options.d.ts +1 -47
  16. package/dist/types/platform.d.ts +1 -0
  17. package/dist/types/remote_info.d.ts +2 -34
  18. package/dist/types/stack_path.d.ts +2 -0
  19. package/dist/types/system_volume.d.ts +2 -2
  20. package/dist/types/types/hidden_metadata.d.ts +32 -0
  21. package/dist/types/types/mount_point.d.ts +46 -0
  22. package/dist/types/types/native_bindings.d.ts +3 -3
  23. package/dist/types/types/options.d.ts +47 -0
  24. package/dist/types/types/remote_info.d.ts +33 -0
  25. package/dist/types/types/volume_metadata.d.ts +46 -0
  26. package/dist/types/unc.d.ts +1 -1
  27. package/dist/types/units.d.ts +25 -3
  28. package/dist/types/volume_metadata.d.ts +4 -50
  29. package/dist/types/volume_mount_points.d.ts +3 -6
  30. package/jest.config.base.cjs +63 -0
  31. package/jest.config.cjs +3 -16
  32. package/package.json +12 -15
  33. package/prebuilds/darwin-arm64/@photostructure+fs-metadata.glibc.node +0 -0
  34. package/prebuilds/win32-x64/@photostructure+fs-metadata.glibc.node +0 -0
  35. package/src/async.ts +9 -0
  36. package/src/debuglog.ts +6 -2
  37. package/src/defer.ts +1 -1
  38. package/src/dirname.ts +13 -0
  39. package/src/global.d.ts +1 -0
  40. package/src/hidden.ts +6 -42
  41. package/src/{exports.ts → index.ts} +75 -30
  42. package/src/linux/mount_points.ts +4 -2
  43. package/src/linux/mtab.ts +3 -3
  44. package/src/mount_point.ts +2 -53
  45. package/src/options.ts +4 -53
  46. package/src/path.ts +12 -5
  47. package/src/platform.ts +5 -5
  48. package/src/remote_info.ts +44 -49
  49. package/src/stack_path.ts +71 -0
  50. package/src/system_volume.ts +3 -6
  51. package/src/test-utils/assert.ts +1 -1
  52. package/src/test-utils/debuglog-child.ts +15 -0
  53. package/src/types/hidden_metadata.ts +38 -0
  54. package/src/types/mount_point.ts +53 -0
  55. package/src/types/native_bindings.ts +3 -3
  56. package/src/types/options.ts +54 -0
  57. package/src/types/remote_info.ts +35 -0
  58. package/src/types/volume_metadata.ts +52 -0
  59. package/src/unc.ts +1 -1
  60. package/src/units.ts +39 -7
  61. package/src/volume_metadata.ts +9 -66
  62. package/src/volume_mount_points.ts +3 -6
  63. package/tsup.config.ts +1 -0
  64. package/dist/types/exports.d.ts +0 -99
  65. package/dist/types/setup.d.ts +0 -2
  66. package/src/index.cts +0 -15
  67. package/src/index.mts +0 -17
  68. package/src/setup.ts +0 -69
package/dist/index.mjs CHANGED
@@ -1,31 +1,19 @@
1
- // src/index.mts
2
- import { dirname as dirname3 } from "node:path";
3
- import { fileURLToPath } from "node:url";
1
+ // node_modules/tsup/assets/esm_shims.js
2
+ import { fileURLToPath } from "url";
3
+ import path from "path";
4
+ var getFilename = () => fileURLToPath(import.meta.url);
5
+ var getDirname = () => path.dirname(getFilename());
6
+ var __dirname = /* @__PURE__ */ getDirname();
4
7
 
5
- // src/setup.ts
8
+ // src/index.ts
6
9
  import NodeGypBuild from "node-gyp-build";
7
10
 
8
11
  // src/debuglog.ts
9
12
  import { debuglog, format } from "node:util";
10
-
11
- // src/defer.ts
12
13
  function defer(thunk) {
13
- let computed = false;
14
- let value;
15
- const fn = () => {
16
- if (!computed) {
17
- computed = true;
18
- value = thunk();
19
- }
20
- return value;
21
- };
22
- fn.reset = () => {
23
- computed = false;
24
- };
25
- return fn;
14
+ let t;
15
+ return () => t ??= thunk();
26
16
  }
27
-
28
- // src/debuglog.ts
29
17
  var debugLogContext = defer(() => {
30
18
  for (const ea of ["fs-metadata", "fs-meta"]) {
31
19
  if (debuglog(ea).enabled) {
@@ -47,31 +35,32 @@ function debug(msg, ...args) {
47
35
  process.stderr.write(timestamp + format(msg, ...args) + "\n");
48
36
  }
49
37
 
50
- // src/fs.ts
51
- import { opendir, stat } from "node:fs/promises";
52
- import { join, resolve } from "node:path";
38
+ // src/defer.ts
39
+ function defer2(thunk) {
40
+ let computed = false;
41
+ let value;
42
+ const fn = () => {
43
+ if (!computed) {
44
+ computed = true;
45
+ value = thunk();
46
+ }
47
+ return value;
48
+ };
49
+ fn.reset = () => {
50
+ computed = false;
51
+ };
52
+ return fn;
53
+ }
53
54
 
54
- // src/async.ts
55
- import { availableParallelism } from "node:os";
56
- import { env } from "node:process";
55
+ // src/stack_path.ts
56
+ import { dirname } from "node:path";
57
57
 
58
- // src/number.ts
59
- function isNumber(value) {
60
- return typeof value === "number" && isFinite(value);
61
- }
62
- var INTEGER_REGEX = /^-?\d+$/;
63
- function toInt(value) {
64
- try {
65
- if (value == null) return;
66
- const s = String(value).trim();
67
- return INTEGER_REGEX.test(s) ? parseInt(s) : void 0;
68
- } catch {
69
- return;
70
- }
71
- }
72
- function gt0(value) {
73
- return isNumber(value) && value > 0;
74
- }
58
+ // src/platform.ts
59
+ import { arch, platform } from "node:process";
60
+ var isLinux = platform === "linux";
61
+ var isWindows = platform === "win32";
62
+ var isMacOS = platform === "darwin";
63
+ var isArm = isLinux && arch.startsWith("arm");
75
64
 
76
65
  // src/string.ts
77
66
  function isString(input) {
@@ -105,6 +94,103 @@ function sortObjectsByLocale(arr, fn, locales, options) {
105
94
  return arr.sort((a, b) => fn(a).localeCompare(fn(b), locales, options));
106
95
  }
107
96
 
97
+ // src/stack_path.ts
98
+ function getCallerDirname() {
99
+ const e = new Error();
100
+ if (e.stack == null) {
101
+ Error.captureStackTrace(e);
102
+ }
103
+ return dirname(extractCallerPath(e.stack));
104
+ }
105
+ var patterns = isWindows ? [
106
+ // Standard: "at functionName (C:\path\file.js:1:1)"
107
+ /\bat\s.+?\((?<path>[A-Z]:\\.+):\d+:\d+\)$/,
108
+ // direct: "at C:\path\file.js:1:1"
109
+ /\bat\s(?<path>[A-Z]:\\.+):\d+:\d+$/,
110
+ // UNC: "at functionName (\\server\share\path\file.js:1:1)"
111
+ /\bat\s.+?\((?<path>\\\\.+):\d+:\d+\)$/,
112
+ // direct: "at \\server\share\path\file.js:1:1"
113
+ /\bat\s(?<path>\\\\.+):\d+:\d+$/
114
+ ] : [
115
+ // Standard: "at functionName (/path/file.js:1:1)"
116
+ /\bat\s.+?\((?<path>\/.+?):\d+:\d+\)$/,
117
+ // Anonymous or direct: "at /path/file.js:1:1"
118
+ /\bat\s(.+[^/]\s)?(?<path>\/.+?):\d+:\d+$/
119
+ ];
120
+ var MaybeUrlRE = /^[a-z]{2,5}:\/\//i;
121
+ function extractCallerPath(stack) {
122
+ const frames = stack.split("\n").filter(Boolean);
123
+ const callerFrame = frames.findIndex(
124
+ (frame) => frame.includes("getCallerDirname")
125
+ );
126
+ if (callerFrame === -1) {
127
+ throw new Error("Invalid stack trace format: missing caller frame");
128
+ }
129
+ for (let i = callerFrame + 1; i < frames.length; i++) {
130
+ const frame = frames[i];
131
+ for (const pattern of patterns) {
132
+ const g = toS(frame).trim().match(pattern)?.groups;
133
+ if (g != null && isNotBlank(g["path"])) {
134
+ const path2 = g["path"];
135
+ if (MaybeUrlRE.test(path2)) {
136
+ try {
137
+ return new URL(path2).pathname;
138
+ } catch {
139
+ }
140
+ }
141
+ return path2;
142
+ }
143
+ }
144
+ }
145
+ throw new Error("Invalid stack trace format: no parsable frames");
146
+ }
147
+
148
+ // src/dirname.ts
149
+ function _dirname() {
150
+ try {
151
+ if (typeof __dirname !== "undefined") return __dirname;
152
+ } catch {
153
+ }
154
+ return getCallerDirname();
155
+ }
156
+
157
+ // src/fs.ts
158
+ import { opendir, stat } from "node:fs/promises";
159
+ import { join, resolve } from "node:path";
160
+
161
+ // src/async.ts
162
+ import { availableParallelism } from "node:os";
163
+ import { env } from "node:process";
164
+
165
+ // src/number.ts
166
+ function isNumber(value) {
167
+ return typeof value === "number" && isFinite(value);
168
+ }
169
+ var INTEGER_REGEX = /^-?\d+$/;
170
+ function toInt(value) {
171
+ try {
172
+ if (value == null) return;
173
+ const s = String(value).trim();
174
+ return INTEGER_REGEX.test(s) ? parseInt(s) : void 0;
175
+ } catch {
176
+ return;
177
+ }
178
+ }
179
+ function gt0(value) {
180
+ return isNumber(value) && value > 0;
181
+ }
182
+
183
+ // src/units.ts
184
+ var SecondMs = 1e3;
185
+ var MinuteMs = 60 * SecondMs;
186
+ var HourMs = 60 * MinuteMs;
187
+ var DayMs = 24 * HourMs;
188
+ var KiB = 1024;
189
+ var MiB = 1024 * KiB;
190
+ var GiB = 1024 * MiB;
191
+ var TiB = 1024 * GiB;
192
+ var f = 1023.995 / 1024;
193
+
108
194
  // src/async.ts
109
195
  var TimeoutError = class extends Error {
110
196
  constructor(message, captureStackTrace = true) {
@@ -128,6 +214,11 @@ async function withTimeout(opts) {
128
214
  desc + ": Expected timeoutMs to be > 0, but got " + timeoutMs
129
215
  );
130
216
  }
217
+ if (timeoutMs > DayMs) {
218
+ throw new TypeError(
219
+ desc + ": Invalid timeoutMs is too large: must be less than one day, but got " + timeoutMs
220
+ );
221
+ }
131
222
  if (timeoutMs === 0) {
132
223
  return opts.promise;
133
224
  }
@@ -178,20 +269,20 @@ async function mapConcurrent({
178
269
  while (executing.size >= maxConcurrency) {
179
270
  await Promise.race(executing);
180
271
  }
181
- const p2 = results[index] = fn(item).catch((error) => error);
182
- executing.add(p2);
183
- p2.finally(() => executing.delete(p2));
272
+ const p = results[index] = fn(item).catch((error) => error);
273
+ executing.add(p);
274
+ p.finally(() => executing.delete(p));
184
275
  }
185
276
  return Promise.all(results);
186
277
  }
187
278
 
188
279
  // src/fs.ts
189
- async function statAsync(path, options) {
190
- return stat(path, options);
280
+ async function statAsync(path2, options) {
281
+ return stat(path2, options);
191
282
  }
192
- async function canStatAsync(path) {
283
+ async function canStatAsync(path2) {
193
284
  try {
194
- return null != await statAsync(path);
285
+ return null != await statAsync(path2);
195
286
  } catch {
196
287
  return false;
197
288
  }
@@ -220,7 +311,7 @@ async function _canReaddir(dir) {
220
311
 
221
312
  // src/hidden.ts
222
313
  import { rename } from "node:fs/promises";
223
- import { basename, dirname as dirname2, join as join2 } from "node:path";
314
+ import { basename, dirname as dirname3, join as join2 } from "node:path";
224
315
 
225
316
  // src/object.ts
226
317
  function isObject(value) {
@@ -301,30 +392,28 @@ function toError(cause) {
301
392
  }
302
393
 
303
394
  // src/path.ts
304
- import { dirname, resolve as resolve2 } from "node:path";
305
-
306
- // src/platform.ts
307
- import { platform } from "node:os";
308
- var p = platform();
309
- var isLinux = p === "linux";
310
- var isWindows = p === "win32";
311
- var isMacOS = p === "darwin";
312
-
313
- // src/path.ts
395
+ import { dirname as dirname2, resolve as resolve2 } from "node:path";
314
396
  function normalizePath(mountPoint) {
315
397
  if (isBlank(mountPoint)) return void 0;
316
398
  const result = isWindows ? normalizeWindowsPath(mountPoint) : normalizePosixPath(mountPoint);
317
399
  return result != null ? resolve2(result) : void 0;
318
400
  }
319
401
  function normalizePosixPath(mountPoint) {
320
- return isBlank(mountPoint) ? void 0 : mountPoint === "/" ? mountPoint : mountPoint.replace(/\/+$/, "");
402
+ if (isBlank(mountPoint)) return void 0;
403
+ if (mountPoint === "/") return mountPoint;
404
+ if (mountPoint[mountPoint.length - 1] !== "/") return mountPoint;
405
+ let end = mountPoint.length - 1;
406
+ while (end > 0 && mountPoint[end] === "/") {
407
+ end--;
408
+ }
409
+ return mountPoint.slice(0, end + 1);
321
410
  }
322
411
  function normalizeWindowsPath(mountPoint) {
323
412
  return /^[a-z]:$/i.test(mountPoint) ? mountPoint.toUpperCase() + "\\" : mountPoint;
324
413
  }
325
- function isRootDirectory(path) {
326
- const n = normalizePath(path);
327
- return n == null ? false : isWindows ? dirname(n) === n : n === "/";
414
+ function isRootDirectory(path2) {
415
+ const n = normalizePath(path2);
416
+ return n == null ? false : isWindows ? dirname2(n) === n : n === "/";
328
417
  }
329
418
 
330
419
  // src/hidden.ts
@@ -352,23 +441,23 @@ var LocalSupport = HiddenSupportByPlatform[process.platform]?.supported ?? {
352
441
  dotPrefix: false,
353
442
  systemFlag: false
354
443
  };
355
- async function isHidden(pathname, nativeFn) {
444
+ async function isHiddenImpl(pathname, nativeFn2) {
356
445
  const norm = normalizePath(pathname);
357
446
  if (norm == null) {
358
447
  throw new Error("Invalid pathname: " + JSON.stringify(pathname));
359
448
  }
360
- return LocalSupport.dotPrefix && isPosixHidden(norm) || LocalSupport.systemFlag && isSystemHidden(norm, nativeFn);
449
+ return LocalSupport.dotPrefix && isPosixHidden(norm) || LocalSupport.systemFlag && isSystemHidden(norm, nativeFn2);
361
450
  }
362
- async function isHiddenRecursive(path, nativeFn) {
363
- let norm = normalizePath(path);
451
+ async function isHiddenRecursiveImpl(path2, nativeFn2) {
452
+ let norm = normalizePath(path2);
364
453
  if (norm == null) {
365
- throw new Error("Invalid path: " + JSON.stringify(path));
454
+ throw new Error("Invalid path: " + JSON.stringify(path2));
366
455
  }
367
456
  while (!isRootDirectory(norm)) {
368
- if (await isHidden(norm, nativeFn)) {
457
+ if (await isHiddenImpl(norm, nativeFn2)) {
369
458
  return true;
370
459
  }
371
- norm = dirname2(norm);
460
+ norm = dirname3(norm);
372
461
  }
373
462
  return false;
374
463
  }
@@ -377,7 +466,7 @@ function createHiddenPosixPath(pathname, hidden) {
377
466
  if (norm == null) {
378
467
  throw new Error("Invalid pathname: " + JSON.stringify(pathname));
379
468
  }
380
- const dir = dirname2(norm);
469
+ const dir = dirname3(norm);
381
470
  const srcBase = basename(norm).replace(/^\./, "");
382
471
  const dest = join2(dir, (hidden ? "." : "") + srcBase);
383
472
  return dest;
@@ -395,22 +484,22 @@ function isPosixHidden(pathname) {
395
484
  const b = basename(pathname);
396
485
  return b.startsWith(".") && b !== "." && b !== "..";
397
486
  }
398
- async function isSystemHidden(pathname, nativeFn) {
487
+ async function isSystemHidden(pathname, nativeFn2) {
399
488
  if (!LocalSupport.systemFlag) {
400
489
  return false;
401
490
  }
402
491
  if (isWindows && isRootDirectory(pathname)) {
403
492
  return false;
404
493
  }
405
- return await canStatAsync(pathname) && await (await nativeFn()).isHidden(pathname);
494
+ return await canStatAsync(pathname) && await (await nativeFn2()).isHidden(pathname);
406
495
  }
407
- async function getHiddenMetadata(pathname, nativeFn) {
496
+ async function getHiddenMetadataImpl(pathname, nativeFn2) {
408
497
  const norm = normalizePath(pathname);
409
498
  if (norm == null) {
410
499
  throw new Error("Invalid pathname: " + JSON.stringify(pathname));
411
500
  }
412
501
  const dotPrefix = isPosixHidden(norm);
413
- const systemFlag = await isSystemHidden(norm, nativeFn);
502
+ const systemFlag = await isSystemHidden(norm, nativeFn2);
414
503
  return {
415
504
  hidden: dotPrefix || systemFlag,
416
505
  dotPrefix,
@@ -418,7 +507,7 @@ async function getHiddenMetadata(pathname, nativeFn) {
418
507
  supported: LocalSupport
419
508
  };
420
509
  }
421
- async function setHidden(pathname, hide, method, nativeFn) {
510
+ async function setHiddenImpl(pathname, hide, method, nativeFn2) {
422
511
  let norm = normalizePath(pathname);
423
512
  if (norm == null) {
424
513
  throw new Error("Invalid pathname: " + JSON.stringify(pathname));
@@ -450,7 +539,7 @@ async function setHidden(pathname, hide, method, nativeFn) {
450
539
  acted = true;
451
540
  }
452
541
  if (LocalSupport.systemFlag && (["all", "systemFlag"].includes(method) || !acted && method === "auto")) {
453
- await (await nativeFn()).setHidden(norm, hide);
542
+ await (await nativeFn2()).setHidden(norm, hide);
454
543
  actions.systemFlag = true;
455
544
  }
456
545
  return { pathname: norm, actions };
@@ -473,6 +562,9 @@ var SystemPathPatternsDefault = [
473
562
  "/run/user/*/gvfs",
474
563
  "/snap/**",
475
564
  "/sys/**",
565
+ "/tmp",
566
+ "/var/tmp",
567
+ // we aren't including /tmp/**, as some people temporarily mount volumes there, like /tmp/project.
476
568
  "**/#snapshot",
477
569
  // Synology and Kubernetes volume snapshots
478
570
  // windows for linux:
@@ -542,6 +634,49 @@ function optionsWithDefaults(overrides = {}) {
542
634
  };
543
635
  }
544
636
 
637
+ // src/string_enum.ts
638
+ function stringEnum(...o) {
639
+ const set = new Set(o);
640
+ const dict = {};
641
+ for (const key of o) {
642
+ dict[key] = key;
643
+ }
644
+ return {
645
+ ...dict,
646
+ values: Object.freeze([...set]),
647
+ size: set.size,
648
+ get: (s) => s != null && set.has(s) ? s : void 0
649
+ };
650
+ }
651
+
652
+ // src/volume_health_status.ts
653
+ var VolumeHealthStatuses = stringEnum(
654
+ "healthy",
655
+ "timeout",
656
+ "inaccessible",
657
+ "disconnected",
658
+ "unknown"
659
+ );
660
+ async function directoryStatus(dir, timeoutMs, canReaddirImpl = canReaddir) {
661
+ try {
662
+ if (await canReaddirImpl(dir, timeoutMs)) {
663
+ return { status: VolumeHealthStatuses.healthy };
664
+ }
665
+ } catch (error) {
666
+ debug("[directoryStatus] %s: %s", dir, error);
667
+ let status = VolumeHealthStatuses.unknown;
668
+ if (error instanceof TimeoutError) {
669
+ status = VolumeHealthStatuses.timeout;
670
+ } else if (isObject(error) && error instanceof Error && "code" in error) {
671
+ if (error.code === "EPERM" || error.code === "EACCES") {
672
+ status = VolumeHealthStatuses.inaccessible;
673
+ }
674
+ }
675
+ return { status, error: toError(error) };
676
+ }
677
+ return { status: VolumeHealthStatuses.unknown };
678
+ }
679
+
545
680
  // src/linux/dev_disk.ts
546
681
  import { readdir, readlink } from "node:fs/promises";
547
682
  import { join as join3, resolve as resolve3 } from "node:path";
@@ -599,8 +734,7 @@ import { readFile } from "node:fs/promises";
599
734
 
600
735
  // src/mount_point.ts
601
736
  function isMountPoint(obj) {
602
- if (!isObject(obj)) return false;
603
- return "mountPoint" in obj && isNotBlank(obj.mountPoint);
737
+ return isObject(obj) && "mountPoint" in obj && isNotBlank(obj.mountPoint);
604
738
  }
605
739
 
606
740
  // src/remote_info.ts
@@ -609,7 +743,7 @@ function isRemoteInfo(obj) {
609
743
  const { remoteHost, remoteShare } = obj;
610
744
  return isNotBlank(remoteHost) && isNotBlank(remoteShare);
611
745
  }
612
- var NETWORK_FS_TYPES = /* @__PURE__ */ new Set([
746
+ var NETWORK_FS_TYPE_ARRAY = [
613
747
  "9p",
614
748
  "afp",
615
749
  "afs",
@@ -617,9 +751,6 @@ var NETWORK_FS_TYPES = /* @__PURE__ */ new Set([
617
751
  "ceph",
618
752
  "cifs",
619
753
  "ftp",
620
- "fuse.cephfs",
621
- "fuse.glusterfs",
622
- "fuse.sshfs",
623
754
  "fuse",
624
755
  "gfs2",
625
756
  "glusterfs",
@@ -631,12 +762,31 @@ var NETWORK_FS_TYPES = /* @__PURE__ */ new Set([
631
762
  "smbfs",
632
763
  "sshfs",
633
764
  "webdav"
765
+ ];
766
+ var NETWORK_FS_TYPES = new Set(NETWORK_FS_TYPE_ARRAY);
767
+ var FS_TYPE_ALIASES = /* @__PURE__ */ new Map([
768
+ ["nfs1", "nfs"],
769
+ ["nfs2", "nfs"],
770
+ ["nfs3", "nfs"],
771
+ ["nfs4", "nfs4"],
772
+ ["fuse.sshfs", "sshfs"],
773
+ ["sshfs.fuse", "sshfs"],
774
+ ["davfs2", "webdav"],
775
+ ["davfs", "webdav"],
776
+ ["cifs.smb", "cifs"],
777
+ ["smbfs", "cifs"],
778
+ ["cephfs", "ceph"],
779
+ ["fuse.ceph", "ceph"],
780
+ ["fuse.cephfs", "ceph"],
781
+ ["rbd", "ceph"],
782
+ ["fuse.glusterfs", "glusterfs"]
634
783
  ]);
635
- function normalizeProtocol(protocol) {
636
- return (protocol ?? "").toLowerCase().replace(/:$/, "");
784
+ function normalizeFsType(fstype) {
785
+ const norm = toS(fstype).toLowerCase().replace(/:$/, "");
786
+ return FS_TYPE_ALIASES.get(norm) ?? norm;
637
787
  }
638
788
  function isRemoteFsType(fstype) {
639
- return isNotBlank(fstype) && NETWORK_FS_TYPES.has(normalizeProtocol(fstype));
789
+ return isNotBlank(fstype) && NETWORK_FS_TYPES.has(normalizeFsType(fstype));
640
790
  }
641
791
  function parseURL(s) {
642
792
  try {
@@ -657,18 +807,22 @@ function extractRemoteInfo(fsSpec) {
657
807
  uri: fsSpec
658
808
  };
659
809
  }
660
- const patterns = [
661
- // CIFS/SMB pattern: //hostname/share or //user@host/share
810
+ const patterns2 = [
662
811
  {
812
+ // CIFS/SMB pattern: //hostname/share or //user@host/share
663
813
  regex: /^\/\/(?:(?<remoteUser>[^/@]+)@)?(?<remoteHost>[^/@]+)\/(?<remoteShare>.+)$/
664
814
  },
665
- // NFS pattern: hostname:/share
666
815
  {
816
+ // sshfs pattern: sshfs#USER@HOST:REMOTE_PATH
817
+ regex: /^(?:(?<protocol>\w+)#)?(?<remoteUser>[^@]+)@(?<remoteHost>[^:]+):(?<remoteShare>.+)$/
818
+ },
819
+ {
820
+ // NFS pattern: hostname:/share
667
821
  protocol: "nfs",
668
822
  regex: /^(?<remoteHost>[^:]+):\/(?!\/)(?<remoteShare>.+)$/
669
823
  }
670
824
  ];
671
- for (const { protocol, regex } of patterns) {
825
+ for (const { protocol, regex } of patterns2) {
672
826
  const o = compactValues({
673
827
  protocol,
674
828
  remote: true,
@@ -683,8 +837,8 @@ function extractRemoteInfo(fsSpec) {
683
837
  const parsed = new URL(fsSpec);
684
838
  if (parsed != null) {
685
839
  debug("[extractRemoteInfo] parsed URL: %o", parsed);
686
- const protocol = normalizeProtocol(parsed.protocol);
687
- if (!isRemoteFsType(protocol)) {
840
+ const fstype = normalizeFsType(parsed.protocol);
841
+ if (!isRemoteFsType(fstype)) {
688
842
  return {
689
843
  uri: fsSpec,
690
844
  remote: false
@@ -692,7 +846,7 @@ function extractRemoteInfo(fsSpec) {
692
846
  } else {
693
847
  return compactValues({
694
848
  uri: fsSpec,
695
- protocol,
849
+ protocol: fstype,
696
850
  remote: true,
697
851
  remoteUser: parsed.username,
698
852
  remoteHost: parsed.hostname,
@@ -708,18 +862,18 @@ function extractRemoteInfo(fsSpec) {
708
862
 
709
863
  // src/glob.ts
710
864
  var cache = /* @__PURE__ */ new Map();
711
- function compileGlob(patterns) {
712
- if (patterns == null || patterns.length === 0) {
865
+ function compileGlob(patterns2) {
866
+ if (patterns2 == null || patterns2.length === 0) {
713
867
  return NeverMatchRE;
714
868
  }
715
- const patternsKey = JSON.stringify(patterns);
869
+ const patternsKey = JSON.stringify(patterns2);
716
870
  {
717
871
  const prior = cache.get(patternsKey);
718
872
  if (prior != null) {
719
873
  return prior;
720
874
  }
721
875
  }
722
- const sorted = patterns.slice().filter(isNotBlank).sort();
876
+ const sorted = patterns2.slice().filter(isNotBlank).sort();
723
877
  const sortedKey = JSON.stringify(sorted);
724
878
  {
725
879
  const prior = cache.get(sortedKey);
@@ -736,8 +890,8 @@ function compileGlob(patterns) {
736
890
  cache.set(sortedKey, result);
737
891
  return result;
738
892
  }
739
- function _compileGlob(patterns) {
740
- const regexPatterns = patterns.map((pattern) => {
893
+ function _compileGlob(patterns2) {
894
+ const regexPatterns = patterns2.map((pattern) => {
741
895
  let regex = "";
742
896
  let i = 0;
743
897
  while (i < pattern.length) {
@@ -843,7 +997,7 @@ function mountEntryToPartialVolumeMetadata(entry, options = {}) {
843
997
  mountFrom: entry.fs_spec,
844
998
  isSystemVolume: isSystemVolume(entry.fs_file, entry.fs_vfstype, options),
845
999
  remote: false,
846
- // < default to false
1000
+ // < default to false, but it may be overridden by extractRemoteInfo
847
1001
  ...extractRemoteInfo(entry.fs_spec)
848
1002
  };
849
1003
  }
@@ -941,16 +1095,16 @@ async function getLinuxMtabMetadata(mountPoint, opts) {
941
1095
  }
942
1096
 
943
1097
  // src/unc.ts
944
- function parseUNCPath(path) {
945
- if (path == null || isBlank(path) || !isString(path)) {
1098
+ function parseUNCPath(path2) {
1099
+ if (path2 == null || isBlank(path2) || !isString(path2)) {
946
1100
  return;
947
1101
  }
948
- if (!path.startsWith("\\\\") && !path.startsWith("//")) {
1102
+ if (!path2.startsWith("\\\\") && !path2.startsWith("//")) {
949
1103
  return;
950
1104
  }
951
- const isForwardSlash = path.startsWith("//");
1105
+ const isForwardSlash = path2.startsWith("//");
952
1106
  const slashChar = isForwardSlash ? "/" : "\\";
953
- const parts = path.slice(2).split(slashChar);
1107
+ const parts = path2.slice(2).split(slashChar);
954
1108
  if (parts.length < 2) {
955
1109
  return;
956
1110
  }
@@ -963,7 +1117,7 @@ function parseUNCPath(path) {
963
1117
  return;
964
1118
  }
965
1119
  const wrongSlash = isForwardSlash ? "\\" : "/";
966
- if (path.includes(wrongSlash)) {
1120
+ if (path2.includes(wrongSlash)) {
967
1121
  return;
968
1122
  }
969
1123
  return { remoteHost, remoteShare, remote: true };
@@ -975,49 +1129,6 @@ function extractUUID(uuid) {
975
1129
  return toS(uuid).match(uuidRegex)?.[0];
976
1130
  }
977
1131
 
978
- // src/string_enum.ts
979
- function stringEnum(...o) {
980
- const set = new Set(o);
981
- const dict = {};
982
- for (const key of o) {
983
- dict[key] = key;
984
- }
985
- return {
986
- ...dict,
987
- values: Object.freeze([...set]),
988
- size: set.size,
989
- get: (s) => s != null && set.has(s) ? s : void 0
990
- };
991
- }
992
-
993
- // src/volume_health_status.ts
994
- var VolumeHealthStatuses = stringEnum(
995
- "healthy",
996
- "timeout",
997
- "inaccessible",
998
- "disconnected",
999
- "unknown"
1000
- );
1001
- async function directoryStatus(dir, timeoutMs, canReaddirImpl = canReaddir) {
1002
- try {
1003
- if (await canReaddirImpl(dir, timeoutMs)) {
1004
- return { status: VolumeHealthStatuses.healthy };
1005
- }
1006
- } catch (error) {
1007
- debug("[directoryStatus] %s: %s", dir, error);
1008
- let status = VolumeHealthStatuses.unknown;
1009
- if (error instanceof TimeoutError) {
1010
- status = VolumeHealthStatuses.timeout;
1011
- } else if (isObject(error) && error instanceof Error && "code" in error) {
1012
- if (error.code === "EPERM" || error.code === "EACCES") {
1013
- status = VolumeHealthStatuses.inaccessible;
1014
- }
1015
- }
1016
- return { status, error: toError(error) };
1017
- }
1018
- return { status: VolumeHealthStatuses.unknown };
1019
- }
1020
-
1021
1132
  // src/array.ts
1022
1133
  function uniqBy(arr, keyFn) {
1023
1134
  const seen = /* @__PURE__ */ new Set();
@@ -1030,21 +1141,21 @@ function uniqBy(arr, keyFn) {
1030
1141
  }
1031
1142
 
1032
1143
  // src/volume_mount_points.ts
1033
- async function getVolumeMountPoints(opts, nativeFn) {
1034
- const p2 = _getVolumeMountPoints(opts, nativeFn);
1035
- return isWindows ? p2 : withTimeout({ desc: "getVolumeMountPoints", ...opts, promise: p2 });
1144
+ async function getVolumeMountPointsImpl(opts, nativeFn2) {
1145
+ const p = _getVolumeMountPoints(opts, nativeFn2);
1146
+ return isWindows ? p : withTimeout({ desc: "getVolumeMountPoints", ...opts, promise: p });
1036
1147
  }
1037
- async function _getVolumeMountPoints(o, nativeFn) {
1148
+ async function _getVolumeMountPoints(o, nativeFn2) {
1038
1149
  debug("[getVolumeMountPoints] gathering mount points with options: %o", o);
1039
1150
  const raw = await (isWindows || isMacOS ? (async () => {
1040
1151
  debug("[getVolumeMountPoints] using native implementation");
1041
- const points = await (await nativeFn()).getVolumeMountPoints(o);
1152
+ const points = await (await nativeFn2()).getVolumeMountPoints(o);
1042
1153
  debug(
1043
1154
  "[getVolumeMountPoints] native returned %d mount points",
1044
1155
  points.length
1045
1156
  );
1046
1157
  return points;
1047
- })() : getLinuxMountPoints(nativeFn, o));
1158
+ })() : getLinuxMountPoints(nativeFn2, o));
1048
1159
  debug("[getVolumeMountPoints] raw mount points: %o", raw);
1049
1160
  const compacted = raw.map((ea) => compactValues(ea)).filter((ea) => isNotBlank(ea.mountPoint));
1050
1161
  for (const ea of compacted) {
@@ -1082,20 +1193,20 @@ async function _getVolumeMountPoints(o, nativeFn) {
1082
1193
  }
1083
1194
 
1084
1195
  // src/volume_metadata.ts
1085
- async function getVolumeMetadata(o, nativeFn) {
1196
+ async function getVolumeMetadataImpl(o, nativeFn2) {
1086
1197
  if (isBlank(o.mountPoint)) {
1087
1198
  throw new TypeError(
1088
1199
  "Invalid mountPoint: got " + JSON.stringify(o.mountPoint)
1089
1200
  );
1090
1201
  }
1091
- const p2 = _getVolumeMetadata(o, nativeFn);
1092
- return isWindows ? p2 : withTimeout({
1202
+ const p = _getVolumeMetadata(o, nativeFn2);
1203
+ return isWindows ? p : withTimeout({
1093
1204
  desc: "getVolumeMetadata()",
1094
1205
  timeoutMs: o.timeoutMs,
1095
- promise: p2
1206
+ promise: p
1096
1207
  });
1097
1208
  }
1098
- async function _getVolumeMetadata(o, nativeFn) {
1209
+ async function _getVolumeMetadata(o, nativeFn2) {
1099
1210
  o = optionsWithDefaults(o);
1100
1211
  const norm = normalizePath(o.mountPoint);
1101
1212
  if (norm == null) {
@@ -1137,7 +1248,7 @@ async function _getVolumeMetadata(o, nativeFn) {
1137
1248
  debug("[getVolumeMetadata] using device: %s", device);
1138
1249
  }
1139
1250
  debug("[getVolumeMetadata] requesting native metadata");
1140
- const metadata = await (await nativeFn()).getVolumeMetadata(o);
1251
+ const metadata = await (await nativeFn2()).getVolumeMetadata(o);
1141
1252
  debug("[getVolumeMetadata] native metadata: %o", metadata);
1142
1253
  const remoteInfo = mtabInfo ?? extractRemoteInfo(metadata.uri) ?? extractRemoteInfo(metadata.mountFrom) ?? (isWindows ? parseUNCPath(o.mountPoint) : void 0);
1143
1254
  debug("[getVolumeMetadata] extracted remote info: %o", remoteInfo);
@@ -1168,10 +1279,10 @@ async function _getVolumeMetadata(o, nativeFn) {
1168
1279
  debug("[getVolumeMetadata] final result for %s: %o", o.mountPoint, result);
1169
1280
  return compactValues(result);
1170
1281
  }
1171
- async function getAllVolumeMetadata(opts, nativeFn) {
1282
+ async function getAllVolumeMetadataImpl(opts, nativeFn2) {
1172
1283
  const o = optionsWithDefaults(opts);
1173
1284
  debug("[getAllVolumeMetadata] starting with options: %o", o);
1174
- const arr = await getVolumeMountPoints(o, nativeFn);
1285
+ const arr = await getVolumeMountPointsImpl(o, nativeFn2);
1175
1286
  debug("[getAllVolumeMetadata] found %d mount points", arr.length);
1176
1287
  const unhealthyMountPoints = arr.filter(
1177
1288
  (ea) => ea.status != null && ea.status !== VolumeHealthStatuses.healthy
@@ -1201,7 +1312,7 @@ async function getAllVolumeMetadata(opts, nativeFn) {
1201
1312
  const results = await mapConcurrent({
1202
1313
  maxConcurrency: o.maxConcurrency,
1203
1314
  items: opts?.includeSystemVolumes ?? IncludeSystemVolumesDefault ? healthy : healthy.filter((ea) => !ea.isSystemVolume),
1204
- fn: async (mp) => getVolumeMetadata({ ...mp, ...o }, nativeFn).catch((error) => ({
1315
+ fn: async (mp) => getVolumeMetadataImpl({ ...mp, ...o }, nativeFn2).catch((error) => ({
1205
1316
  mountPoint: mp.mountPoint,
1206
1317
  error
1207
1318
  }))
@@ -1219,49 +1330,52 @@ async function getAllVolumeMetadata(opts, nativeFn) {
1219
1330
  );
1220
1331
  }
1221
1332
 
1222
- // src/setup.ts
1223
- function setup(dirname4) {
1224
- const nativeFn = defer(async () => {
1225
- const start = Date.now();
1226
- try {
1227
- const dir = await findAncestorDir(dirname4, "binding.gyp");
1228
- if (dir == null) {
1229
- throw new Error(
1230
- "Could not find bindings.gyp in any ancestor directory of " + dirname4
1231
- );
1232
- }
1233
- const bindings = NodeGypBuild(dir);
1234
- bindings.setDebugLogging(isDebugEnabled());
1235
- bindings.setDebugPrefix(debugLogContext() + ":native");
1236
- return bindings;
1237
- } catch (error) {
1238
- debug("Loading native bindings failed: %s", error);
1239
- throw error;
1240
- } finally {
1241
- debug(`Native bindings took %d ms to load`, Date.now() - start);
1333
+ // src/index.ts
1334
+ var nativeFn = defer2(async () => {
1335
+ const start = Date.now();
1336
+ try {
1337
+ const dirname4 = _dirname();
1338
+ const dir = await findAncestorDir(dirname4, "binding.gyp");
1339
+ if (dir == null) {
1340
+ throw new Error(
1341
+ "Could not find bindings.gyp in any ancestor directory of " + dirname4
1342
+ );
1242
1343
  }
1243
- });
1244
- return {
1245
- getVolumeMountPoints: (opts = {}) => getVolumeMountPoints(optionsWithDefaults(opts), nativeFn),
1246
- getVolumeMetadata: (mountPoint, opts = {}) => getVolumeMetadata({ ...optionsWithDefaults(opts), mountPoint }, nativeFn),
1247
- getAllVolumeMetadata: (opts = {}) => getAllVolumeMetadata(optionsWithDefaults(opts), nativeFn),
1248
- isHidden: (pathname) => isHidden(pathname, nativeFn),
1249
- isHiddenRecursive: (pathname) => isHiddenRecursive(pathname, nativeFn),
1250
- getHiddenMetadata: (pathname) => getHiddenMetadata(pathname, nativeFn),
1251
- setHidden: (pathname, hidden, method = "auto") => setHidden(pathname, hidden, method, nativeFn)
1252
- };
1344
+ const bindings = NodeGypBuild(dir);
1345
+ bindings.setDebugLogging(isDebugEnabled());
1346
+ bindings.setDebugPrefix(debugLogContext() + ":native");
1347
+ return bindings;
1348
+ } catch (error) {
1349
+ debug("Loading native bindings failed: %s", error);
1350
+ throw error;
1351
+ } finally {
1352
+ debug(`Native bindings took %d ms to load`, Date.now() - start);
1353
+ }
1354
+ });
1355
+ function getVolumeMountPoints(opts) {
1356
+ return getVolumeMountPointsImpl(optionsWithDefaults(opts), nativeFn);
1357
+ }
1358
+ function getVolumeMetadata(mountPoint, opts) {
1359
+ return getVolumeMetadataImpl(
1360
+ { ...optionsWithDefaults(opts), mountPoint },
1361
+ nativeFn
1362
+ );
1363
+ }
1364
+ function getAllVolumeMetadata(opts) {
1365
+ return getAllVolumeMetadataImpl(optionsWithDefaults(opts), nativeFn);
1366
+ }
1367
+ function isHidden(pathname) {
1368
+ return isHiddenImpl(pathname, nativeFn);
1369
+ }
1370
+ function isHiddenRecursive(pathname) {
1371
+ return isHiddenRecursiveImpl(pathname, nativeFn);
1372
+ }
1373
+ function getHiddenMetadata(pathname) {
1374
+ return getHiddenMetadataImpl(pathname, nativeFn);
1375
+ }
1376
+ function setHidden(pathname, hidden, method = "auto") {
1377
+ return setHiddenImpl(pathname, hidden, method, nativeFn);
1253
1378
  }
1254
-
1255
- // src/index.mts
1256
- var {
1257
- getVolumeMountPoints: getVolumeMountPoints2,
1258
- getVolumeMetadata: getVolumeMetadata2,
1259
- getAllVolumeMetadata: getAllVolumeMetadata2,
1260
- isHidden: isHidden2,
1261
- isHiddenRecursive: isHiddenRecursive2,
1262
- getHiddenMetadata: getHiddenMetadata2,
1263
- setHidden: setHidden2
1264
- } = setup(dirname3(fileURLToPath(import.meta.url)));
1265
1379
  export {
1266
1380
  IncludeSystemVolumesDefault,
1267
1381
  LinuxMountTablePathsDefault,
@@ -1270,13 +1384,13 @@ export {
1270
1384
  SystemPathPatternsDefault,
1271
1385
  TimeoutMsDefault,
1272
1386
  VolumeHealthStatuses,
1273
- getAllVolumeMetadata2 as getAllVolumeMetadata,
1274
- getHiddenMetadata2 as getHiddenMetadata,
1275
- getVolumeMetadata2 as getVolumeMetadata,
1276
- getVolumeMountPoints2 as getVolumeMountPoints,
1277
- isHidden2 as isHidden,
1278
- isHiddenRecursive2 as isHiddenRecursive,
1387
+ getAllVolumeMetadata,
1388
+ getHiddenMetadata,
1389
+ getVolumeMetadata,
1390
+ getVolumeMountPoints,
1391
+ isHidden,
1392
+ isHiddenRecursive,
1279
1393
  optionsWithDefaults,
1280
- setHidden2 as setHidden
1394
+ setHidden
1281
1395
  };
1282
1396
  //# sourceMappingURL=index.mjs.map