@photostructure/fs-metadata 0.3.1 → 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 (70) hide show
  1. package/CHANGELOG.md +29 -3
  2. package/README.md +3 -3
  3. package/dist/index.cjs +326 -223
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.mjs +331 -223
  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/fs.ts +3 -15
  40. package/src/global.d.ts +1 -0
  41. package/src/hidden.ts +6 -42
  42. package/src/{exports.ts → index.ts} +75 -30
  43. package/src/linux/mount_points.ts +4 -2
  44. package/src/linux/mtab.ts +3 -3
  45. package/src/mount_point.ts +2 -53
  46. package/src/options.ts +4 -53
  47. package/src/path.ts +12 -5
  48. package/src/platform.ts +5 -5
  49. package/src/remote_info.ts +44 -49
  50. package/src/stack_path.ts +71 -0
  51. package/src/system_volume.ts +3 -6
  52. package/src/test-utils/assert.ts +1 -1
  53. package/src/test-utils/debuglog-child.ts +15 -0
  54. package/src/test-utils/platform.ts +8 -0
  55. package/src/types/hidden_metadata.ts +38 -0
  56. package/src/types/mount_point.ts +53 -0
  57. package/src/types/native_bindings.ts +3 -3
  58. package/src/types/options.ts +54 -0
  59. package/src/types/remote_info.ts +35 -0
  60. package/src/types/volume_metadata.ts +52 -0
  61. package/src/unc.ts +1 -1
  62. package/src/units.ts +39 -7
  63. package/src/volume_metadata.ts +9 -66
  64. package/src/volume_mount_points.ts +3 -6
  65. package/tsup.config.ts +1 -0
  66. package/dist/types/exports.d.ts +0 -99
  67. package/dist/types/setup.d.ts +0 -2
  68. package/src/index.cts +0 -15
  69. package/src/index.mts +0 -17
  70. package/src/setup.ts +0 -69
package/dist/index.cjs CHANGED
@@ -27,7 +27,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
27
  ));
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
 
30
- // src/index.cts
30
+ // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  IncludeSystemVolumesDefault: () => IncludeSystemVolumesDefault,
@@ -37,41 +37,24 @@ __export(index_exports, {
37
37
  SystemPathPatternsDefault: () => SystemPathPatternsDefault,
38
38
  TimeoutMsDefault: () => TimeoutMsDefault,
39
39
  VolumeHealthStatuses: () => VolumeHealthStatuses,
40
- getAllVolumeMetadata: () => getAllVolumeMetadata2,
41
- getHiddenMetadata: () => getHiddenMetadata2,
42
- getVolumeMetadata: () => getVolumeMetadata2,
43
- getVolumeMountPoints: () => getVolumeMountPoints2,
44
- isHidden: () => isHidden2,
45
- isHiddenRecursive: () => isHiddenRecursive2,
40
+ getAllVolumeMetadata: () => getAllVolumeMetadata,
41
+ getHiddenMetadata: () => getHiddenMetadata,
42
+ getVolumeMetadata: () => getVolumeMetadata,
43
+ getVolumeMountPoints: () => getVolumeMountPoints,
44
+ isHidden: () => isHidden,
45
+ isHiddenRecursive: () => isHiddenRecursive,
46
46
  optionsWithDefaults: () => optionsWithDefaults,
47
- setHidden: () => setHidden2
47
+ setHidden: () => setHidden
48
48
  });
49
49
  module.exports = __toCommonJS(index_exports);
50
-
51
- // src/setup.ts
52
50
  var import_node_gyp_build = __toESM(require("node-gyp-build"));
53
51
 
54
52
  // src/debuglog.ts
55
53
  var import_node_util = require("util");
56
-
57
- // src/defer.ts
58
54
  function defer(thunk) {
59
- let computed = false;
60
- let value;
61
- const fn = () => {
62
- if (!computed) {
63
- computed = true;
64
- value = thunk();
65
- }
66
- return value;
67
- };
68
- fn.reset = () => {
69
- computed = false;
70
- };
71
- return fn;
55
+ let t;
56
+ return () => t ??= thunk();
72
57
  }
73
-
74
- // src/debuglog.ts
75
58
  var debugLogContext = defer(() => {
76
59
  for (const ea of ["fs-metadata", "fs-meta"]) {
77
60
  if ((0, import_node_util.debuglog)(ea).enabled) {
@@ -93,32 +76,32 @@ function debug(msg, ...args) {
93
76
  process.stderr.write(timestamp + (0, import_node_util.format)(msg, ...args) + "\n");
94
77
  }
95
78
 
96
- // src/fs.ts
97
- var import_node_fs = require("fs");
98
- var import_promises = require("fs/promises");
79
+ // src/defer.ts
80
+ function defer2(thunk) {
81
+ let computed = false;
82
+ let value;
83
+ const fn = () => {
84
+ if (!computed) {
85
+ computed = true;
86
+ value = thunk();
87
+ }
88
+ return value;
89
+ };
90
+ fn.reset = () => {
91
+ computed = false;
92
+ };
93
+ return fn;
94
+ }
95
+
96
+ // src/stack_path.ts
99
97
  var import_node_path = require("path");
100
98
 
101
- // src/async.ts
102
- var import_node_os = require("os");
99
+ // src/platform.ts
103
100
  var import_node_process = require("process");
104
-
105
- // src/number.ts
106
- function isNumber(value) {
107
- return typeof value === "number" && isFinite(value);
108
- }
109
- var INTEGER_REGEX = /^-?\d+$/;
110
- function toInt(value) {
111
- try {
112
- if (value == null) return;
113
- const s = String(value).trim();
114
- return INTEGER_REGEX.test(s) ? parseInt(s) : void 0;
115
- } catch {
116
- return;
117
- }
118
- }
119
- function gt0(value) {
120
- return isNumber(value) && value > 0;
121
- }
101
+ var isLinux = import_node_process.platform === "linux";
102
+ var isWindows = import_node_process.platform === "win32";
103
+ var isMacOS = import_node_process.platform === "darwin";
104
+ var isArm = isLinux && import_node_process.arch.startsWith("arm");
122
105
 
123
106
  // src/string.ts
124
107
  function isString(input) {
@@ -152,6 +135,104 @@ function sortObjectsByLocale(arr, fn, locales, options) {
152
135
  return arr.sort((a, b) => fn(a).localeCompare(fn(b), locales, options));
153
136
  }
154
137
 
138
+ // src/stack_path.ts
139
+ function getCallerDirname() {
140
+ const e = new Error();
141
+ if (e.stack == null) {
142
+ Error.captureStackTrace(e);
143
+ }
144
+ return (0, import_node_path.dirname)(extractCallerPath(e.stack));
145
+ }
146
+ var patterns = isWindows ? [
147
+ // Standard: "at functionName (C:\path\file.js:1:1)"
148
+ /\bat\s.+?\((?<path>[A-Z]:\\.+):\d+:\d+\)$/,
149
+ // direct: "at C:\path\file.js:1:1"
150
+ /\bat\s(?<path>[A-Z]:\\.+):\d+:\d+$/,
151
+ // UNC: "at functionName (\\server\share\path\file.js:1:1)"
152
+ /\bat\s.+?\((?<path>\\\\.+):\d+:\d+\)$/,
153
+ // direct: "at \\server\share\path\file.js:1:1"
154
+ /\bat\s(?<path>\\\\.+):\d+:\d+$/
155
+ ] : [
156
+ // Standard: "at functionName (/path/file.js:1:1)"
157
+ /\bat\s.+?\((?<path>\/.+?):\d+:\d+\)$/,
158
+ // Anonymous or direct: "at /path/file.js:1:1"
159
+ /\bat\s(.+[^/]\s)?(?<path>\/.+?):\d+:\d+$/
160
+ ];
161
+ var MaybeUrlRE = /^[a-z]{2,5}:\/\//i;
162
+ function extractCallerPath(stack) {
163
+ const frames = stack.split("\n").filter(Boolean);
164
+ const callerFrame = frames.findIndex(
165
+ (frame) => frame.includes("getCallerDirname")
166
+ );
167
+ if (callerFrame === -1) {
168
+ throw new Error("Invalid stack trace format: missing caller frame");
169
+ }
170
+ for (let i = callerFrame + 1; i < frames.length; i++) {
171
+ const frame = frames[i];
172
+ for (const pattern of patterns) {
173
+ const g = toS(frame).trim().match(pattern)?.groups;
174
+ if (g != null && isNotBlank(g["path"])) {
175
+ const path = g["path"];
176
+ if (MaybeUrlRE.test(path)) {
177
+ try {
178
+ return new URL(path).pathname;
179
+ } catch {
180
+ }
181
+ }
182
+ return path;
183
+ }
184
+ }
185
+ }
186
+ throw new Error("Invalid stack trace format: no parsable frames");
187
+ }
188
+
189
+ // src/dirname.ts
190
+ function _dirname() {
191
+ try {
192
+ if (typeof __dirname !== "undefined") return __dirname;
193
+ } catch {
194
+ }
195
+ return getCallerDirname();
196
+ }
197
+
198
+ // src/fs.ts
199
+ var import_node_fs = require("fs");
200
+ var import_promises = require("fs/promises");
201
+ var import_node_path2 = require("path");
202
+
203
+ // src/async.ts
204
+ var import_node_os = require("os");
205
+ var import_node_process2 = require("process");
206
+
207
+ // src/number.ts
208
+ function isNumber(value) {
209
+ return typeof value === "number" && isFinite(value);
210
+ }
211
+ var INTEGER_REGEX = /^-?\d+$/;
212
+ function toInt(value) {
213
+ try {
214
+ if (value == null) return;
215
+ const s = String(value).trim();
216
+ return INTEGER_REGEX.test(s) ? parseInt(s) : void 0;
217
+ } catch {
218
+ return;
219
+ }
220
+ }
221
+ function gt0(value) {
222
+ return isNumber(value) && value > 0;
223
+ }
224
+
225
+ // src/units.ts
226
+ var SecondMs = 1e3;
227
+ var MinuteMs = 60 * SecondMs;
228
+ var HourMs = 60 * MinuteMs;
229
+ var DayMs = 24 * HourMs;
230
+ var KiB = 1024;
231
+ var MiB = 1024 * KiB;
232
+ var GiB = 1024 * MiB;
233
+ var TiB = 1024 * GiB;
234
+ var f = 1023.995 / 1024;
235
+
155
236
  // src/async.ts
156
237
  var TimeoutError = class extends Error {
157
238
  constructor(message, captureStackTrace = true) {
@@ -175,13 +256,18 @@ async function withTimeout(opts) {
175
256
  desc + ": Expected timeoutMs to be > 0, but got " + timeoutMs
176
257
  );
177
258
  }
259
+ if (timeoutMs > DayMs) {
260
+ throw new TypeError(
261
+ desc + ": Invalid timeoutMs is too large: must be less than one day, but got " + timeoutMs
262
+ );
263
+ }
178
264
  if (timeoutMs === 0) {
179
265
  return opts.promise;
180
266
  }
181
267
  const timeoutError = new TimeoutError(
182
268
  `${desc}: timeout after ${timeoutMs}ms`
183
269
  );
184
- if (import_node_process.env["NODE_ENV"] === "test" && timeoutMs === 1) {
270
+ if (import_node_process2.env["NODE_ENV"] === "test" && timeoutMs === 1) {
185
271
  timeoutError.message += "(timeout test)";
186
272
  opts.promise.catch(() => {
187
273
  });
@@ -225,9 +311,9 @@ async function mapConcurrent({
225
311
  while (executing.size >= maxConcurrency) {
226
312
  await Promise.race(executing);
227
313
  }
228
- const p2 = results[index] = fn(item).catch((error) => error);
229
- executing.add(p2);
230
- p2.finally(() => executing.delete(p2));
314
+ const p = results[index] = fn(item).catch((error) => error);
315
+ executing.add(p);
316
+ p.finally(() => executing.delete(p));
231
317
  }
232
318
  return Promise.all(results);
233
319
  }
@@ -244,13 +330,13 @@ async function canStatAsync(path) {
244
330
  }
245
331
  }
246
332
  async function findAncestorDir(dir, file) {
247
- dir = (0, import_node_path.resolve)(dir);
333
+ dir = (0, import_node_path2.resolve)(dir);
248
334
  try {
249
- const s = await statAsync((0, import_node_path.join)(dir, file));
335
+ const s = await statAsync((0, import_node_path2.join)(dir, file));
250
336
  if (s.isFile()) return dir;
251
337
  } catch {
252
338
  }
253
- const parent = (0, import_node_path.resolve)(dir, "..");
339
+ const parent = (0, import_node_path2.resolve)(dir, "..");
254
340
  return parent === dir ? void 0 : findAncestorDir(parent, file);
255
341
  }
256
342
  async function canReaddir(dir, timeoutMs) {
@@ -261,19 +347,13 @@ async function canReaddir(dir, timeoutMs) {
261
347
  });
262
348
  }
263
349
  async function _canReaddir(dir) {
264
- let d = void 0;
265
- try {
266
- d = await (0, import_promises.opendir)(dir);
267
- await d.read();
268
- return true;
269
- } finally {
270
- if (d != null) void d.close();
271
- }
350
+ await (await (0, import_promises.opendir)(dir)).close();
351
+ return true;
272
352
  }
273
353
 
274
354
  // src/hidden.ts
275
355
  var import_promises2 = require("fs/promises");
276
- var import_node_path3 = require("path");
356
+ var import_node_path4 = require("path");
277
357
 
278
358
  // src/object.ts
279
359
  function isObject(value) {
@@ -354,30 +434,28 @@ function toError(cause) {
354
434
  }
355
435
 
356
436
  // src/path.ts
357
- var import_node_path2 = require("path");
358
-
359
- // src/platform.ts
360
- var import_node_os2 = require("os");
361
- var p = (0, import_node_os2.platform)();
362
- var isLinux = p === "linux";
363
- var isWindows = p === "win32";
364
- var isMacOS = p === "darwin";
365
-
366
- // src/path.ts
437
+ var import_node_path3 = require("path");
367
438
  function normalizePath(mountPoint) {
368
439
  if (isBlank(mountPoint)) return void 0;
369
440
  const result = isWindows ? normalizeWindowsPath(mountPoint) : normalizePosixPath(mountPoint);
370
- return result != null ? (0, import_node_path2.resolve)(result) : void 0;
441
+ return result != null ? (0, import_node_path3.resolve)(result) : void 0;
371
442
  }
372
443
  function normalizePosixPath(mountPoint) {
373
- return isBlank(mountPoint) ? void 0 : mountPoint === "/" ? mountPoint : mountPoint.replace(/\/+$/, "");
444
+ if (isBlank(mountPoint)) return void 0;
445
+ if (mountPoint === "/") return mountPoint;
446
+ if (mountPoint[mountPoint.length - 1] !== "/") return mountPoint;
447
+ let end = mountPoint.length - 1;
448
+ while (end > 0 && mountPoint[end] === "/") {
449
+ end--;
450
+ }
451
+ return mountPoint.slice(0, end + 1);
374
452
  }
375
453
  function normalizeWindowsPath(mountPoint) {
376
454
  return /^[a-z]:$/i.test(mountPoint) ? mountPoint.toUpperCase() + "\\" : mountPoint;
377
455
  }
378
456
  function isRootDirectory(path) {
379
457
  const n = normalizePath(path);
380
- return n == null ? false : isWindows ? (0, import_node_path2.dirname)(n) === n : n === "/";
458
+ return n == null ? false : isWindows ? (0, import_node_path3.dirname)(n) === n : n === "/";
381
459
  }
382
460
 
383
461
  // src/hidden.ts
@@ -405,23 +483,23 @@ var LocalSupport = HiddenSupportByPlatform[process.platform]?.supported ?? {
405
483
  dotPrefix: false,
406
484
  systemFlag: false
407
485
  };
408
- async function isHidden(pathname, nativeFn) {
486
+ async function isHiddenImpl(pathname, nativeFn2) {
409
487
  const norm = normalizePath(pathname);
410
488
  if (norm == null) {
411
489
  throw new Error("Invalid pathname: " + JSON.stringify(pathname));
412
490
  }
413
- return LocalSupport.dotPrefix && isPosixHidden(norm) || LocalSupport.systemFlag && isSystemHidden(norm, nativeFn);
491
+ return LocalSupport.dotPrefix && isPosixHidden(norm) || LocalSupport.systemFlag && isSystemHidden(norm, nativeFn2);
414
492
  }
415
- async function isHiddenRecursive(path, nativeFn) {
493
+ async function isHiddenRecursiveImpl(path, nativeFn2) {
416
494
  let norm = normalizePath(path);
417
495
  if (norm == null) {
418
496
  throw new Error("Invalid path: " + JSON.stringify(path));
419
497
  }
420
498
  while (!isRootDirectory(norm)) {
421
- if (await isHidden(norm, nativeFn)) {
499
+ if (await isHiddenImpl(norm, nativeFn2)) {
422
500
  return true;
423
501
  }
424
- norm = (0, import_node_path3.dirname)(norm);
502
+ norm = (0, import_node_path4.dirname)(norm);
425
503
  }
426
504
  return false;
427
505
  }
@@ -430,9 +508,9 @@ function createHiddenPosixPath(pathname, hidden) {
430
508
  if (norm == null) {
431
509
  throw new Error("Invalid pathname: " + JSON.stringify(pathname));
432
510
  }
433
- const dir = (0, import_node_path3.dirname)(norm);
434
- const srcBase = (0, import_node_path3.basename)(norm).replace(/^\./, "");
435
- const dest = (0, import_node_path3.join)(dir, (hidden ? "." : "") + srcBase);
511
+ const dir = (0, import_node_path4.dirname)(norm);
512
+ const srcBase = (0, import_node_path4.basename)(norm).replace(/^\./, "");
513
+ const dest = (0, import_node_path4.join)(dir, (hidden ? "." : "") + srcBase);
436
514
  return dest;
437
515
  }
438
516
  async function setHiddenPosix(pathname, hidden) {
@@ -445,25 +523,25 @@ async function setHiddenPosix(pathname, hidden) {
445
523
  }
446
524
  function isPosixHidden(pathname) {
447
525
  if (!LocalSupport.dotPrefix) return false;
448
- const b = (0, import_node_path3.basename)(pathname);
526
+ const b = (0, import_node_path4.basename)(pathname);
449
527
  return b.startsWith(".") && b !== "." && b !== "..";
450
528
  }
451
- async function isSystemHidden(pathname, nativeFn) {
529
+ async function isSystemHidden(pathname, nativeFn2) {
452
530
  if (!LocalSupport.systemFlag) {
453
531
  return false;
454
532
  }
455
533
  if (isWindows && isRootDirectory(pathname)) {
456
534
  return false;
457
535
  }
458
- return await canStatAsync(pathname) && await (await nativeFn()).isHidden(pathname);
536
+ return await canStatAsync(pathname) && await (await nativeFn2()).isHidden(pathname);
459
537
  }
460
- async function getHiddenMetadata(pathname, nativeFn) {
538
+ async function getHiddenMetadataImpl(pathname, nativeFn2) {
461
539
  const norm = normalizePath(pathname);
462
540
  if (norm == null) {
463
541
  throw new Error("Invalid pathname: " + JSON.stringify(pathname));
464
542
  }
465
543
  const dotPrefix = isPosixHidden(norm);
466
- const systemFlag = await isSystemHidden(norm, nativeFn);
544
+ const systemFlag = await isSystemHidden(norm, nativeFn2);
467
545
  return {
468
546
  hidden: dotPrefix || systemFlag,
469
547
  dotPrefix,
@@ -471,7 +549,7 @@ async function getHiddenMetadata(pathname, nativeFn) {
471
549
  supported: LocalSupport
472
550
  };
473
551
  }
474
- async function setHidden(pathname, hide, method, nativeFn) {
552
+ async function setHiddenImpl(pathname, hide, method, nativeFn2) {
475
553
  let norm = normalizePath(pathname);
476
554
  if (norm == null) {
477
555
  throw new Error("Invalid pathname: " + JSON.stringify(pathname));
@@ -503,14 +581,14 @@ async function setHidden(pathname, hide, method, nativeFn) {
503
581
  acted = true;
504
582
  }
505
583
  if (LocalSupport.systemFlag && (["all", "systemFlag"].includes(method) || !acted && method === "auto")) {
506
- await (await nativeFn()).setHidden(norm, hide);
584
+ await (await nativeFn2()).setHidden(norm, hide);
507
585
  actions.systemFlag = true;
508
586
  }
509
587
  return { pathname: norm, actions };
510
588
  }
511
589
 
512
590
  // src/options.ts
513
- var import_node_os3 = require("os");
591
+ var import_node_os2 = require("os");
514
592
  var TimeoutMsDefault = 5e3;
515
593
  var SystemPathPatternsDefault = [
516
594
  "/boot",
@@ -526,6 +604,9 @@ var SystemPathPatternsDefault = [
526
604
  "/run/user/*/gvfs",
527
605
  "/snap/**",
528
606
  "/sys/**",
607
+ "/tmp",
608
+ "/var/tmp",
609
+ // we aren't including /tmp/**, as some people temporarily mount volumes there, like /tmp/project.
529
610
  "**/#snapshot",
530
611
  // Synology and Kubernetes volume snapshots
531
612
  // windows for linux:
@@ -577,7 +658,7 @@ var LinuxMountTablePathsDefault = [
577
658
  var IncludeSystemVolumesDefault = isWindows;
578
659
  var OptionsDefault = {
579
660
  timeoutMs: TimeoutMsDefault,
580
- maxConcurrency: (0, import_node_os3.availableParallelism)(),
661
+ maxConcurrency: (0, import_node_os2.availableParallelism)(),
581
662
  systemPathPatterns: [...SystemPathPatternsDefault],
582
663
  systemFsTypes: [...SystemFsTypesDefault],
583
664
  linuxMountTablePaths: [...LinuxMountTablePathsDefault],
@@ -595,14 +676,57 @@ function optionsWithDefaults(overrides = {}) {
595
676
  };
596
677
  }
597
678
 
679
+ // src/string_enum.ts
680
+ function stringEnum(...o) {
681
+ const set = new Set(o);
682
+ const dict = {};
683
+ for (const key of o) {
684
+ dict[key] = key;
685
+ }
686
+ return {
687
+ ...dict,
688
+ values: Object.freeze([...set]),
689
+ size: set.size,
690
+ get: (s) => s != null && set.has(s) ? s : void 0
691
+ };
692
+ }
693
+
694
+ // src/volume_health_status.ts
695
+ var VolumeHealthStatuses = stringEnum(
696
+ "healthy",
697
+ "timeout",
698
+ "inaccessible",
699
+ "disconnected",
700
+ "unknown"
701
+ );
702
+ async function directoryStatus(dir, timeoutMs, canReaddirImpl = canReaddir) {
703
+ try {
704
+ if (await canReaddirImpl(dir, timeoutMs)) {
705
+ return { status: VolumeHealthStatuses.healthy };
706
+ }
707
+ } catch (error) {
708
+ debug("[directoryStatus] %s: %s", dir, error);
709
+ let status = VolumeHealthStatuses.unknown;
710
+ if (error instanceof TimeoutError) {
711
+ status = VolumeHealthStatuses.timeout;
712
+ } else if (isObject(error) && error instanceof Error && "code" in error) {
713
+ if (error.code === "EPERM" || error.code === "EACCES") {
714
+ status = VolumeHealthStatuses.inaccessible;
715
+ }
716
+ }
717
+ return { status, error: toError(error) };
718
+ }
719
+ return { status: VolumeHealthStatuses.unknown };
720
+ }
721
+
598
722
  // src/linux/dev_disk.ts
599
723
  var import_promises3 = require("fs/promises");
600
- var import_node_path4 = require("path");
724
+ var import_node_path5 = require("path");
601
725
  async function getUuidFromDevDisk(devicePath) {
602
726
  try {
603
727
  const result = await getBasenameLinkedTo(
604
728
  "/dev/disk/by-uuid",
605
- (0, import_node_path4.resolve)(devicePath)
729
+ (0, import_node_path5.resolve)(devicePath)
606
730
  );
607
731
  debug("[getUuidFromDevDisk] result: %o", result);
608
732
  return result;
@@ -615,7 +739,7 @@ async function getLabelFromDevDisk(devicePath) {
615
739
  try {
616
740
  const result = await getBasenameLinkedTo(
617
741
  "/dev/disk/by-label",
618
- (0, import_node_path4.resolve)(devicePath)
742
+ (0, import_node_path5.resolve)(devicePath)
619
743
  );
620
744
  debug("[getLabelFromDevDisk] result: %o", result);
621
745
  return result;
@@ -636,9 +760,9 @@ async function* readLinks(directory) {
636
760
  for (const dirent of await (0, import_promises3.readdir)(directory, { withFileTypes: true })) {
637
761
  if (dirent.isSymbolicLink()) {
638
762
  try {
639
- const linkTarget = (0, import_node_path4.resolve)(
763
+ const linkTarget = (0, import_node_path5.resolve)(
640
764
  directory,
641
- await (0, import_promises3.readlink)((0, import_node_path4.join)(directory, dirent.name))
765
+ await (0, import_promises3.readlink)((0, import_node_path5.join)(directory, dirent.name))
642
766
  );
643
767
  yield { dirent, linkTarget };
644
768
  } catch {
@@ -652,8 +776,7 @@ var import_promises4 = require("fs/promises");
652
776
 
653
777
  // src/mount_point.ts
654
778
  function isMountPoint(obj) {
655
- if (!isObject(obj)) return false;
656
- return "mountPoint" in obj && isNotBlank(obj.mountPoint);
779
+ return isObject(obj) && "mountPoint" in obj && isNotBlank(obj.mountPoint);
657
780
  }
658
781
 
659
782
  // src/remote_info.ts
@@ -662,7 +785,7 @@ function isRemoteInfo(obj) {
662
785
  const { remoteHost, remoteShare } = obj;
663
786
  return isNotBlank(remoteHost) && isNotBlank(remoteShare);
664
787
  }
665
- var NETWORK_FS_TYPES = /* @__PURE__ */ new Set([
788
+ var NETWORK_FS_TYPE_ARRAY = [
666
789
  "9p",
667
790
  "afp",
668
791
  "afs",
@@ -670,9 +793,6 @@ var NETWORK_FS_TYPES = /* @__PURE__ */ new Set([
670
793
  "ceph",
671
794
  "cifs",
672
795
  "ftp",
673
- "fuse.cephfs",
674
- "fuse.glusterfs",
675
- "fuse.sshfs",
676
796
  "fuse",
677
797
  "gfs2",
678
798
  "glusterfs",
@@ -684,12 +804,31 @@ var NETWORK_FS_TYPES = /* @__PURE__ */ new Set([
684
804
  "smbfs",
685
805
  "sshfs",
686
806
  "webdav"
807
+ ];
808
+ var NETWORK_FS_TYPES = new Set(NETWORK_FS_TYPE_ARRAY);
809
+ var FS_TYPE_ALIASES = /* @__PURE__ */ new Map([
810
+ ["nfs1", "nfs"],
811
+ ["nfs2", "nfs"],
812
+ ["nfs3", "nfs"],
813
+ ["nfs4", "nfs4"],
814
+ ["fuse.sshfs", "sshfs"],
815
+ ["sshfs.fuse", "sshfs"],
816
+ ["davfs2", "webdav"],
817
+ ["davfs", "webdav"],
818
+ ["cifs.smb", "cifs"],
819
+ ["smbfs", "cifs"],
820
+ ["cephfs", "ceph"],
821
+ ["fuse.ceph", "ceph"],
822
+ ["fuse.cephfs", "ceph"],
823
+ ["rbd", "ceph"],
824
+ ["fuse.glusterfs", "glusterfs"]
687
825
  ]);
688
- function normalizeProtocol(protocol) {
689
- return (protocol ?? "").toLowerCase().replace(/:$/, "");
826
+ function normalizeFsType(fstype) {
827
+ const norm = toS(fstype).toLowerCase().replace(/:$/, "");
828
+ return FS_TYPE_ALIASES.get(norm) ?? norm;
690
829
  }
691
830
  function isRemoteFsType(fstype) {
692
- return isNotBlank(fstype) && NETWORK_FS_TYPES.has(normalizeProtocol(fstype));
831
+ return isNotBlank(fstype) && NETWORK_FS_TYPES.has(normalizeFsType(fstype));
693
832
  }
694
833
  function parseURL(s) {
695
834
  try {
@@ -710,18 +849,22 @@ function extractRemoteInfo(fsSpec) {
710
849
  uri: fsSpec
711
850
  };
712
851
  }
713
- const patterns = [
714
- // CIFS/SMB pattern: //hostname/share or //user@host/share
852
+ const patterns2 = [
715
853
  {
854
+ // CIFS/SMB pattern: //hostname/share or //user@host/share
716
855
  regex: /^\/\/(?:(?<remoteUser>[^/@]+)@)?(?<remoteHost>[^/@]+)\/(?<remoteShare>.+)$/
717
856
  },
718
- // NFS pattern: hostname:/share
719
857
  {
858
+ // sshfs pattern: sshfs#USER@HOST:REMOTE_PATH
859
+ regex: /^(?:(?<protocol>\w+)#)?(?<remoteUser>[^@]+)@(?<remoteHost>[^:]+):(?<remoteShare>.+)$/
860
+ },
861
+ {
862
+ // NFS pattern: hostname:/share
720
863
  protocol: "nfs",
721
864
  regex: /^(?<remoteHost>[^:]+):\/(?!\/)(?<remoteShare>.+)$/
722
865
  }
723
866
  ];
724
- for (const { protocol, regex } of patterns) {
867
+ for (const { protocol, regex } of patterns2) {
725
868
  const o = compactValues({
726
869
  protocol,
727
870
  remote: true,
@@ -736,8 +879,8 @@ function extractRemoteInfo(fsSpec) {
736
879
  const parsed = new URL(fsSpec);
737
880
  if (parsed != null) {
738
881
  debug("[extractRemoteInfo] parsed URL: %o", parsed);
739
- const protocol = normalizeProtocol(parsed.protocol);
740
- if (!isRemoteFsType(protocol)) {
882
+ const fstype = normalizeFsType(parsed.protocol);
883
+ if (!isRemoteFsType(fstype)) {
741
884
  return {
742
885
  uri: fsSpec,
743
886
  remote: false
@@ -745,7 +888,7 @@ function extractRemoteInfo(fsSpec) {
745
888
  } else {
746
889
  return compactValues({
747
890
  uri: fsSpec,
748
- protocol,
891
+ protocol: fstype,
749
892
  remote: true,
750
893
  remoteUser: parsed.username,
751
894
  remoteHost: parsed.hostname,
@@ -761,18 +904,18 @@ function extractRemoteInfo(fsSpec) {
761
904
 
762
905
  // src/glob.ts
763
906
  var cache = /* @__PURE__ */ new Map();
764
- function compileGlob(patterns) {
765
- if (patterns == null || patterns.length === 0) {
907
+ function compileGlob(patterns2) {
908
+ if (patterns2 == null || patterns2.length === 0) {
766
909
  return NeverMatchRE;
767
910
  }
768
- const patternsKey = JSON.stringify(patterns);
911
+ const patternsKey = JSON.stringify(patterns2);
769
912
  {
770
913
  const prior = cache.get(patternsKey);
771
914
  if (prior != null) {
772
915
  return prior;
773
916
  }
774
917
  }
775
- const sorted = patterns.slice().filter(isNotBlank).sort();
918
+ const sorted = patterns2.slice().filter(isNotBlank).sort();
776
919
  const sortedKey = JSON.stringify(sorted);
777
920
  {
778
921
  const prior = cache.get(sortedKey);
@@ -789,8 +932,8 @@ function compileGlob(patterns) {
789
932
  cache.set(sortedKey, result);
790
933
  return result;
791
934
  }
792
- function _compileGlob(patterns) {
793
- const regexPatterns = patterns.map((pattern) => {
935
+ function _compileGlob(patterns2) {
936
+ const regexPatterns = patterns2.map((pattern) => {
794
937
  let regex = "";
795
938
  let i = 0;
796
939
  while (i < pattern.length) {
@@ -896,7 +1039,7 @@ function mountEntryToPartialVolumeMetadata(entry, options = {}) {
896
1039
  mountFrom: entry.fs_spec,
897
1040
  isSystemVolume: isSystemVolume(entry.fs_file, entry.fs_vfstype, options),
898
1041
  remote: false,
899
- // < default to false
1042
+ // < default to false, but it may be overridden by extractRemoteInfo
900
1043
  ...extractRemoteInfo(entry.fs_spec)
901
1044
  };
902
1045
  }
@@ -1028,49 +1171,6 @@ function extractUUID(uuid) {
1028
1171
  return toS(uuid).match(uuidRegex)?.[0];
1029
1172
  }
1030
1173
 
1031
- // src/string_enum.ts
1032
- function stringEnum(...o) {
1033
- const set = new Set(o);
1034
- const dict = {};
1035
- for (const key of o) {
1036
- dict[key] = key;
1037
- }
1038
- return {
1039
- ...dict,
1040
- values: Object.freeze([...set]),
1041
- size: set.size,
1042
- get: (s) => s != null && set.has(s) ? s : void 0
1043
- };
1044
- }
1045
-
1046
- // src/volume_health_status.ts
1047
- var VolumeHealthStatuses = stringEnum(
1048
- "healthy",
1049
- "timeout",
1050
- "inaccessible",
1051
- "disconnected",
1052
- "unknown"
1053
- );
1054
- async function directoryStatus(dir, timeoutMs, canReaddirImpl = canReaddir) {
1055
- try {
1056
- if (await canReaddirImpl(dir, timeoutMs)) {
1057
- return { status: VolumeHealthStatuses.healthy };
1058
- }
1059
- } catch (error) {
1060
- debug("[directoryStatus] %s: %s", dir, error);
1061
- let status = VolumeHealthStatuses.unknown;
1062
- if (error instanceof TimeoutError) {
1063
- status = VolumeHealthStatuses.timeout;
1064
- } else if (isObject(error) && error instanceof Error && "code" in error) {
1065
- if (error.code === "EPERM" || error.code === "EACCES") {
1066
- status = VolumeHealthStatuses.inaccessible;
1067
- }
1068
- }
1069
- return { status, error: toError(error) };
1070
- }
1071
- return { status: VolumeHealthStatuses.unknown };
1072
- }
1073
-
1074
1174
  // src/array.ts
1075
1175
  function uniqBy(arr, keyFn) {
1076
1176
  const seen = /* @__PURE__ */ new Set();
@@ -1083,21 +1183,21 @@ function uniqBy(arr, keyFn) {
1083
1183
  }
1084
1184
 
1085
1185
  // src/volume_mount_points.ts
1086
- async function getVolumeMountPoints(opts, nativeFn) {
1087
- const p2 = _getVolumeMountPoints(opts, nativeFn);
1088
- return isWindows ? p2 : withTimeout({ desc: "getVolumeMountPoints", ...opts, promise: p2 });
1186
+ async function getVolumeMountPointsImpl(opts, nativeFn2) {
1187
+ const p = _getVolumeMountPoints(opts, nativeFn2);
1188
+ return isWindows ? p : withTimeout({ desc: "getVolumeMountPoints", ...opts, promise: p });
1089
1189
  }
1090
- async function _getVolumeMountPoints(o, nativeFn) {
1190
+ async function _getVolumeMountPoints(o, nativeFn2) {
1091
1191
  debug("[getVolumeMountPoints] gathering mount points with options: %o", o);
1092
1192
  const raw = await (isWindows || isMacOS ? (async () => {
1093
1193
  debug("[getVolumeMountPoints] using native implementation");
1094
- const points = await (await nativeFn()).getVolumeMountPoints(o);
1194
+ const points = await (await nativeFn2()).getVolumeMountPoints(o);
1095
1195
  debug(
1096
1196
  "[getVolumeMountPoints] native returned %d mount points",
1097
1197
  points.length
1098
1198
  );
1099
1199
  return points;
1100
- })() : getLinuxMountPoints(nativeFn, o));
1200
+ })() : getLinuxMountPoints(nativeFn2, o));
1101
1201
  debug("[getVolumeMountPoints] raw mount points: %o", raw);
1102
1202
  const compacted = raw.map((ea) => compactValues(ea)).filter((ea) => isNotBlank(ea.mountPoint));
1103
1203
  for (const ea of compacted) {
@@ -1135,20 +1235,20 @@ async function _getVolumeMountPoints(o, nativeFn) {
1135
1235
  }
1136
1236
 
1137
1237
  // src/volume_metadata.ts
1138
- async function getVolumeMetadata(o, nativeFn) {
1238
+ async function getVolumeMetadataImpl(o, nativeFn2) {
1139
1239
  if (isBlank(o.mountPoint)) {
1140
1240
  throw new TypeError(
1141
1241
  "Invalid mountPoint: got " + JSON.stringify(o.mountPoint)
1142
1242
  );
1143
1243
  }
1144
- const p2 = _getVolumeMetadata(o, nativeFn);
1145
- return isWindows ? p2 : withTimeout({
1244
+ const p = _getVolumeMetadata(o, nativeFn2);
1245
+ return isWindows ? p : withTimeout({
1146
1246
  desc: "getVolumeMetadata()",
1147
1247
  timeoutMs: o.timeoutMs,
1148
- promise: p2
1248
+ promise: p
1149
1249
  });
1150
1250
  }
1151
- async function _getVolumeMetadata(o, nativeFn) {
1251
+ async function _getVolumeMetadata(o, nativeFn2) {
1152
1252
  o = optionsWithDefaults(o);
1153
1253
  const norm = normalizePath(o.mountPoint);
1154
1254
  if (norm == null) {
@@ -1190,7 +1290,7 @@ async function _getVolumeMetadata(o, nativeFn) {
1190
1290
  debug("[getVolumeMetadata] using device: %s", device);
1191
1291
  }
1192
1292
  debug("[getVolumeMetadata] requesting native metadata");
1193
- const metadata = await (await nativeFn()).getVolumeMetadata(o);
1293
+ const metadata = await (await nativeFn2()).getVolumeMetadata(o);
1194
1294
  debug("[getVolumeMetadata] native metadata: %o", metadata);
1195
1295
  const remoteInfo = mtabInfo ?? extractRemoteInfo(metadata.uri) ?? extractRemoteInfo(metadata.mountFrom) ?? (isWindows ? parseUNCPath(o.mountPoint) : void 0);
1196
1296
  debug("[getVolumeMetadata] extracted remote info: %o", remoteInfo);
@@ -1221,10 +1321,10 @@ async function _getVolumeMetadata(o, nativeFn) {
1221
1321
  debug("[getVolumeMetadata] final result for %s: %o", o.mountPoint, result);
1222
1322
  return compactValues(result);
1223
1323
  }
1224
- async function getAllVolumeMetadata(opts, nativeFn) {
1324
+ async function getAllVolumeMetadataImpl(opts, nativeFn2) {
1225
1325
  const o = optionsWithDefaults(opts);
1226
1326
  debug("[getAllVolumeMetadata] starting with options: %o", o);
1227
- const arr = await getVolumeMountPoints(o, nativeFn);
1327
+ const arr = await getVolumeMountPointsImpl(o, nativeFn2);
1228
1328
  debug("[getAllVolumeMetadata] found %d mount points", arr.length);
1229
1329
  const unhealthyMountPoints = arr.filter(
1230
1330
  (ea) => ea.status != null && ea.status !== VolumeHealthStatuses.healthy
@@ -1254,7 +1354,7 @@ async function getAllVolumeMetadata(opts, nativeFn) {
1254
1354
  const results = await mapConcurrent({
1255
1355
  maxConcurrency: o.maxConcurrency,
1256
1356
  items: opts?.includeSystemVolumes ?? IncludeSystemVolumesDefault ? healthy : healthy.filter((ea) => !ea.isSystemVolume),
1257
- fn: async (mp) => getVolumeMetadata({ ...mp, ...o }, nativeFn).catch((error) => ({
1357
+ fn: async (mp) => getVolumeMetadataImpl({ ...mp, ...o }, nativeFn2).catch((error) => ({
1258
1358
  mountPoint: mp.mountPoint,
1259
1359
  error
1260
1360
  }))
@@ -1272,49 +1372,52 @@ async function getAllVolumeMetadata(opts, nativeFn) {
1272
1372
  );
1273
1373
  }
1274
1374
 
1275
- // src/setup.ts
1276
- function setup(dirname3) {
1277
- const nativeFn = defer(async () => {
1278
- const start = Date.now();
1279
- try {
1280
- const dir = await findAncestorDir(dirname3, "binding.gyp");
1281
- if (dir == null) {
1282
- throw new Error(
1283
- "Could not find bindings.gyp in any ancestor directory of " + dirname3
1284
- );
1285
- }
1286
- const bindings = (0, import_node_gyp_build.default)(dir);
1287
- bindings.setDebugLogging(isDebugEnabled());
1288
- bindings.setDebugPrefix(debugLogContext() + ":native");
1289
- return bindings;
1290
- } catch (error) {
1291
- debug("Loading native bindings failed: %s", error);
1292
- throw error;
1293
- } finally {
1294
- debug(`Native bindings took %d ms to load`, Date.now() - start);
1375
+ // src/index.ts
1376
+ var nativeFn = defer2(async () => {
1377
+ const start = Date.now();
1378
+ try {
1379
+ const dirname4 = _dirname();
1380
+ const dir = await findAncestorDir(dirname4, "binding.gyp");
1381
+ if (dir == null) {
1382
+ throw new Error(
1383
+ "Could not find bindings.gyp in any ancestor directory of " + dirname4
1384
+ );
1295
1385
  }
1296
- });
1297
- return {
1298
- getVolumeMountPoints: (opts = {}) => getVolumeMountPoints(optionsWithDefaults(opts), nativeFn),
1299
- getVolumeMetadata: (mountPoint, opts = {}) => getVolumeMetadata({ ...optionsWithDefaults(opts), mountPoint }, nativeFn),
1300
- getAllVolumeMetadata: (opts = {}) => getAllVolumeMetadata(optionsWithDefaults(opts), nativeFn),
1301
- isHidden: (pathname) => isHidden(pathname, nativeFn),
1302
- isHiddenRecursive: (pathname) => isHiddenRecursive(pathname, nativeFn),
1303
- getHiddenMetadata: (pathname) => getHiddenMetadata(pathname, nativeFn),
1304
- setHidden: (pathname, hidden, method = "auto") => setHidden(pathname, hidden, method, nativeFn)
1305
- };
1386
+ const bindings = (0, import_node_gyp_build.default)(dir);
1387
+ bindings.setDebugLogging(isDebugEnabled());
1388
+ bindings.setDebugPrefix(debugLogContext() + ":native");
1389
+ return bindings;
1390
+ } catch (error) {
1391
+ debug("Loading native bindings failed: %s", error);
1392
+ throw error;
1393
+ } finally {
1394
+ debug(`Native bindings took %d ms to load`, Date.now() - start);
1395
+ }
1396
+ });
1397
+ function getVolumeMountPoints(opts) {
1398
+ return getVolumeMountPointsImpl(optionsWithDefaults(opts), nativeFn);
1399
+ }
1400
+ function getVolumeMetadata(mountPoint, opts) {
1401
+ return getVolumeMetadataImpl(
1402
+ { ...optionsWithDefaults(opts), mountPoint },
1403
+ nativeFn
1404
+ );
1405
+ }
1406
+ function getAllVolumeMetadata(opts) {
1407
+ return getAllVolumeMetadataImpl(optionsWithDefaults(opts), nativeFn);
1408
+ }
1409
+ function isHidden(pathname) {
1410
+ return isHiddenImpl(pathname, nativeFn);
1411
+ }
1412
+ function isHiddenRecursive(pathname) {
1413
+ return isHiddenRecursiveImpl(pathname, nativeFn);
1414
+ }
1415
+ function getHiddenMetadata(pathname) {
1416
+ return getHiddenMetadataImpl(pathname, nativeFn);
1417
+ }
1418
+ function setHidden(pathname, hidden, method = "auto") {
1419
+ return setHiddenImpl(pathname, hidden, method, nativeFn);
1306
1420
  }
1307
-
1308
- // src/index.cts
1309
- var {
1310
- getVolumeMountPoints: getVolumeMountPoints2,
1311
- getVolumeMetadata: getVolumeMetadata2,
1312
- getAllVolumeMetadata: getAllVolumeMetadata2,
1313
- isHidden: isHidden2,
1314
- isHiddenRecursive: isHiddenRecursive2,
1315
- getHiddenMetadata: getHiddenMetadata2,
1316
- setHidden: setHidden2
1317
- } = setup(__dirname);
1318
1421
  // Annotate the CommonJS export names for ESM import in node:
1319
1422
  0 && (module.exports = {
1320
1423
  IncludeSystemVolumesDefault,