@photostructure/fs-metadata 0.4.0 → 0.5.1

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 (115) hide show
  1. package/C++_REVIEW_TODO.md +291 -0
  2. package/CHANGELOG.md +38 -1
  3. package/CLAUDE.md +346 -0
  4. package/CONTRIBUTING.md +66 -0
  5. package/README.md +20 -1
  6. package/WINDOWS_DEBUG_GUIDE.md +89 -0
  7. package/binding.gyp +3 -2
  8. package/dist/index.cjs +2 -1
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +360 -0
  11. package/dist/index.d.mts +360 -0
  12. package/dist/index.d.ts +360 -0
  13. package/dist/index.mjs +17 -15
  14. package/dist/index.mjs.map +1 -1
  15. package/jest.config.cjs +68 -6
  16. package/package.json +56 -48
  17. package/prebuilds/darwin-arm64/@photostructure+fs-metadata.glibc.node +0 -0
  18. package/prebuilds/linux-arm64/@photostructure+fs-metadata.glibc.node +0 -0
  19. package/prebuilds/linux-arm64/@photostructure+fs-metadata.musl.node +0 -0
  20. package/prebuilds/linux-x64/@photostructure+fs-metadata.glibc.node +0 -0
  21. package/prebuilds/linux-x64/@photostructure+fs-metadata.musl.node +0 -0
  22. package/prebuilds/win32-x64/@photostructure+fs-metadata.glibc.node +0 -0
  23. package/scripts/check-memory.mjs +123 -0
  24. package/scripts/clang-tidy.ts +241 -0
  25. package/scripts/is-platform.mjs +12 -0
  26. package/scripts/post-build.mjs +21 -0
  27. package/scripts/prebuild-linux-glibc.sh +108 -0
  28. package/scripts/precommit.ts +45 -0
  29. package/scripts/sanitizers-test.sh +157 -0
  30. package/scripts/{configure.mjs → setup-native.mjs} +4 -1
  31. package/scripts/valgrind-test.mjs +83 -0
  32. package/scripts/valgrind-test.sh +85 -0
  33. package/src/async.ts +3 -3
  34. package/src/binding.cpp +4 -4
  35. package/src/common/error_utils.h +17 -0
  36. package/src/common/metadata_worker.h +4 -1
  37. package/src/darwin/hidden.cpp +13 -6
  38. package/src/darwin/volume_metadata.cpp +2 -2
  39. package/src/darwin/volume_mount_points.cpp +8 -1
  40. package/src/error.ts +3 -3
  41. package/src/fs.ts +1 -1
  42. package/src/glob.ts +2 -2
  43. package/src/hidden.ts +6 -6
  44. package/src/index.ts +19 -23
  45. package/src/linux/blkid_cache.cpp +23 -14
  46. package/src/linux/dev_disk.ts +2 -2
  47. package/src/linux/gio_mount_points.cpp +7 -7
  48. package/src/linux/gio_utils.cpp +19 -8
  49. package/src/linux/gio_volume_metadata.cpp +15 -15
  50. package/src/linux/mount_points.ts +9 -9
  51. package/src/linux/mtab.ts +7 -7
  52. package/src/linux/volume_metadata.cpp +7 -2
  53. package/src/object.ts +1 -1
  54. package/src/options.ts +3 -3
  55. package/src/path.ts +2 -2
  56. package/src/platform.ts +25 -0
  57. package/src/remote_info.ts +5 -5
  58. package/src/system_volume.ts +8 -8
  59. package/src/test-utils/assert.ts +2 -2
  60. package/src/test-utils/benchmark-harness.ts +192 -0
  61. package/src/test-utils/debuglog-child.ts +30 -4
  62. package/src/test-utils/debuglog-enabled-child.ts +40 -0
  63. package/src/test-utils/hidden-tests.ts +1 -1
  64. package/src/test-utils/jest-setup.ts +14 -0
  65. package/src/test-utils/platform.ts +3 -3
  66. package/src/test-utils/worker-thread-helper.cjs +92 -0
  67. package/src/types/native_bindings.ts +3 -3
  68. package/src/types/volume_metadata.ts +2 -2
  69. package/src/unc.ts +2 -2
  70. package/src/uuid.ts +1 -1
  71. package/src/volume_health_status.ts +6 -6
  72. package/src/volume_metadata.ts +20 -23
  73. package/src/volume_mount_points.ts +12 -17
  74. package/src/windows/drive_status.h +30 -13
  75. package/src/windows/hidden.cpp +32 -11
  76. package/src/windows/volume_metadata.cpp +17 -7
  77. package/tsup.config.ts +8 -2
  78. package/dist/types/array.d.ts +0 -25
  79. package/dist/types/async.d.ts +0 -42
  80. package/dist/types/debuglog.d.ts +0 -3
  81. package/dist/types/defer.d.ts +0 -10
  82. package/dist/types/dirname.d.ts +0 -1
  83. package/dist/types/error.d.ts +0 -17
  84. package/dist/types/fs.d.ts +0 -22
  85. package/dist/types/glob.d.ts +0 -17
  86. package/dist/types/hidden.d.ts +0 -29
  87. package/dist/types/index.d.ts +0 -91
  88. package/dist/types/linux/dev_disk.d.ts +0 -13
  89. package/dist/types/linux/mount_points.d.ts +0 -6
  90. package/dist/types/linux/mtab.d.ts +0 -47
  91. package/dist/types/mount_point.d.ts +0 -2
  92. package/dist/types/number.d.ts +0 -3
  93. package/dist/types/object.d.ts +0 -18
  94. package/dist/types/options.d.ts +0 -33
  95. package/dist/types/path.d.ts +0 -17
  96. package/dist/types/platform.d.ts +0 -4
  97. package/dist/types/random.d.ts +0 -12
  98. package/dist/types/remote_info.d.ts +0 -6
  99. package/dist/types/stack_path.d.ts +0 -2
  100. package/dist/types/string.d.ts +0 -37
  101. package/dist/types/string_enum.d.ts +0 -19
  102. package/dist/types/system_volume.d.ts +0 -14
  103. package/dist/types/types/hidden_metadata.d.ts +0 -32
  104. package/dist/types/types/mount_point.d.ts +0 -46
  105. package/dist/types/types/native_bindings.d.ts +0 -51
  106. package/dist/types/types/options.d.ts +0 -47
  107. package/dist/types/types/remote_info.d.ts +0 -33
  108. package/dist/types/types/volume_metadata.d.ts +0 -46
  109. package/dist/types/unc.d.ts +0 -11
  110. package/dist/types/units.d.ts +0 -38
  111. package/dist/types/uuid.d.ts +0 -16
  112. package/dist/types/volume_health_status.d.ts +0 -24
  113. package/dist/types/volume_metadata.d.ts +0 -8
  114. package/dist/types/volume_mount_points.d.ts +0 -6
  115. package/jest.config.base.cjs +0 -63
@@ -0,0 +1,291 @@
1
+ # C++ Code Review TODO List
2
+
3
+ This document outlines a comprehensive review of all C++ files in the fs-metadata project to identify memory leaks, resource management issues, and API usage improvements.
4
+
5
+ ## Common Patterns to Review
6
+
7
+ ### Memory Management
8
+ - [x] All `malloc`/`free` pairs are properly matched - No malloc/free used, using RAII throughout
9
+ - [x] RAII patterns are used consistently for resource management - Excellent RAII usage across codebase
10
+ - [x] No raw pointers that could leak on exceptions - All resources properly wrapped
11
+ - [x] Smart pointers used appropriately - Consistent use of unique_ptr and custom RAII wrappers
12
+ - [x] All API-allocated resources are properly freed - RAII ensures cleanup
13
+
14
+ ### Platform API Usage
15
+ - [x] Verify API availability for target OS versions - APIs match stated OS requirements
16
+ - [x] Check for deprecated API usage - No deprecated N-API functions found
17
+ - [x] Ensure error handling follows platform conventions - Platform-specific error handling implemented
18
+ - [x] Validate string encoding conversions - UTF-8/wide conversions properly sized
19
+
20
+ ### Security and Input Validation
21
+ - [x] Comprehensive path validation to prevent directory traversal - Added ".." checks to Windows/Darwin hidden.cpp
22
+ - [ ] Input validation for empty/null mount points across all platforms
23
+ - [x] Buffer size constants defined for platform-specific limits - Fixed Windows buffer sizes
24
+ - [ ] Null byte and special character handling in paths
25
+
26
+ ### Thread Safety
27
+ - [x] Replace volatile with std::atomic for thread synchronization - Fixed in drive_status.h
28
+ - [x] Review N-API threadsafe function patterns - All async workers use proper patterns
29
+ - [ ] Document thread safety requirements
30
+ - [x] Ensure proper synchronization in async operations - Using atomic operations with proper memory ordering
31
+
32
+ ## File-by-File Review Checklist
33
+
34
+ ### 1. `src/binding.cpp` ✅
35
+ - [x] Review NAPI memory management patterns - No issues found
36
+ - [x] Check for proper cleanup in async worker lifecycles - Properly managed
37
+ - [x] Verify promise deferred resolution/rejection paths - Correct implementation
38
+ - [x] Validate string conversions between JS and C++ - Using Napi::String correctly
39
+ - [x] **Added**: const-correctness for Napi::Env variables
40
+ - **Platform APIs verified**: Node-API v9 compatibility
41
+
42
+ ### 2. Darwin/macOS Files
43
+
44
+ #### `src/darwin/volume_metadata.cpp` ✅
45
+ - [x] Verify CFRelease for all CoreFoundation objects - Using CFReleaser RAII wrapper
46
+ - DADisk objects properly managed with CFReleaser
47
+ - Disk descriptions properly managed with CFReleaser
48
+ - DASession objects properly managed with CFReleaser
49
+ - [x] Check DiskArbitration API cleanup - RAII ensures cleanup via CFReleaser
50
+ - [x] Review CFStringToString conversion for memory leaks - No leaks, proper string handling
51
+ - [x] Validate statvfs/statfs error handling - Comprehensive error checking
52
+ - [x] Check overflow protection in size calculations - Excellent overflow protection (lines 91-104)
53
+ - **Platform APIs verified**:
54
+ - DiskArbitration framework APIs (macOS 14+) - Proper RAII usage
55
+ - IOKit framework APIs - Not directly used
56
+ - CoreFoundation string handling - CFReleaser ensures proper cleanup
57
+ - **Notes**: Exemplary code with proper RAII, overflow protection, and error handling
58
+
59
+ #### `src/darwin/volume_mount_points.cpp` ✅
60
+ - [x] Review getmntinfo usage and buffer management - Using getmntinfo_r_np with MountBufferRAII
61
+ - [x] Verify CFURLRef lifecycle management - No CFURLRef used in this file
62
+ - [x] Check DADiskCreateFromBSDName cleanup - Not used in this file
63
+ - **Platform APIs verified**:
64
+ - `getmntinfo_r_np` with MNT_NOWAIT for thread safety
65
+ - BSD mount structure compatibility - Properly handled
66
+ - **Notes**: Good use of RAII, async/future for timeout handling, and faccessat for security
67
+
68
+ #### `src/darwin/hidden.cpp` ✅
69
+ - [x] Review NSURL object lifecycle - No NSURL/CFURLRef used, using stat/chflags
70
+ - [x] Check CFURLRef release patterns - Not applicable
71
+ - [x] Verify resource value key handling - Using UF_HIDDEN flag directly
72
+ - **Platform APIs verified**:
73
+ - File attribute APIs (UF_HIDDEN) - Proper usage with stat/chflags
74
+ - Path validation implemented (checks for "..")
75
+ - **Notes**: Simple and correct implementation using BSD APIs
76
+
77
+ ### 3. Windows Files
78
+
79
+ #### `src/windows/volume_metadata.cpp` ✅
80
+ - [x] Review WNetConnection RAII wrapper completeness - **FIXED**: Now handles ERROR_MORE_DATA
81
+ - Dynamic buffer resize implemented when ERROR_MORE_DATA is returned
82
+ - [x] Check GetVolumeInformation error handling - **FIXED**: Now uses MAX_PATH+1
83
+ - Using proper VOLUME_NAME_SIZE constant (MAX_PATH+1) for buffers
84
+ - [x] Verify wide string conversion cleanup - Proper PathConverter usage
85
+ - [x] Validate DeviceIoControl buffer management - Not used in this file
86
+ - **Platform APIs verified**:
87
+ - WNet APIs properly handle ERROR_MORE_DATA
88
+ - GetVolumeInformation uses correct MAX_PATH+1 buffers
89
+ - **Notes**: All buffer issues resolved, proper RAII patterns throughout
90
+
91
+ #### `src/windows/volume_mount_points.cpp` ✅
92
+ - [x] Review GetLogicalDrives usage - Proper usage with unique_ptr buffer
93
+ - [x] Check QueryDosDevice buffer allocation - Not used in this file
94
+ - [x] Verify GetVolumePathNamesForVolumeName memory management - Not used in this file
95
+ - **Platform APIs verified**:
96
+ - GetLogicalDriveStringsW - Proper buffer sizing and iteration
97
+ - GetVolumeInformationW - Using MAX_PATH+1 correctly
98
+ - Parallel drive status checking implemented
99
+ - **Notes**: Good implementation with proper buffer management
100
+
101
+ #### `src/windows/hidden.cpp` ✅
102
+ - [x] Review GetFileAttributes error handling - FileAttributeHandler RAII properly throws on error
103
+ - [x] Check SetFileAttributes validation - Proper error checking with exceptions
104
+ - [x] Verify wide string conversions - PathConverter properly handles UTF-8 to wide
105
+ - [x] **Added**: Path validation for directory traversal (".." check)
106
+ - **Platform APIs verified**:
107
+ - GetFileAttributesW/SetFileAttributesW - Proper usage with error handling
108
+ - FILE_ATTRIBUTE_HIDDEN - Correctly manipulated
109
+ - **Notes**: Excellent RAII implementation with FileAttributeHandler, now with path validation
110
+
111
+ ### 4. Linux Files (Completed)
112
+
113
+ #### `src/linux/volume_metadata.cpp` ✅
114
+ - [x] Review BlkidCache RAII wrapper - Already excellent
115
+ - [x] Check blkid_get_tag_value free() calls - Correctly using free()
116
+ - [x] Verify GIO integration memory management - Proper smart pointers
117
+ - [x] Validate statvfs error handling - Already comprehensive
118
+ - [x] **Added**: Input validation for empty mount points
119
+ - **Platform APIs verified**:
120
+ - libblkid API availability
121
+ - GIO optional dependency handling
122
+ - statvfs behavior
123
+
124
+ #### `src/linux/blkid_cache.cpp` ✅
125
+ - [x] Verify blkid_cache lifecycle - Already has proper RAII
126
+ - [x] Check error handling for cache operations - Good error handling
127
+ - [x] **Improved**: Double-check pattern in destructor for thread safety
128
+ - [x] **Added**: const-correctness for std::lock_guard instances
129
+ - **Platform APIs verified**:
130
+ - libblkid cache APIs - Proper use of blkid_get_cache/blkid_put_cache
131
+
132
+ #### `src/linux/gio_utils.cpp` (if GIO enabled) ✅
133
+ - [x] Review g_object_unref patterns - Already using GioResource RAII
134
+ - [x] Check GError cleanup - Not used in this file (GError-free patterns)
135
+ - [x] Verify GMount/GVolume reference counting - Proper ref/unref pairs
136
+ - [x] **Added**: Exception handling in forEachMount callback
137
+ - [x] **Added**: Null checks for root.get() before G_IS_FILE
138
+ - [x] **Added**: const-correctness for GioResource and callback results
139
+ - **Platform APIs verified**:
140
+ - GLib/GIO APIs (GNOME) - Proper memory management patterns
141
+ - GVfs mount integration
142
+
143
+ #### `src/linux/gio_mount_points.cpp` (if GIO enabled) ✅
144
+ - [x] Review g_volume_monitor lifecycle - Correct usage (singleton pattern)
145
+ - [x] Check GList cleanup patterns - Using g_list_free_full correctly
146
+ - [x] Verify string ownership - Proper GCharPtr smart pointers
147
+ - [x] **Added**: const-correctness for local variables (GCharPtr, GFileInfoPtr, etc.)
148
+ - **Platform APIs verified**:
149
+ - GVolumeMonitor APIs - Reference counting rules
150
+ - Mount enumeration
151
+
152
+ #### `src/linux/gio_volume_metadata.cpp` (if GIO enabled) ✅
153
+ - [x] Review g_drive object management - Using GObjectPtr smart pointers
154
+ - [x] Check g_icon handling - No GIcon usage in this file
155
+ - [x] Verify string ownership - Proper GCharPtr usage
156
+ - [x] **Added**: Defensive null checks for GObjectPtr::get()
157
+ - [x] **Added**: Null checks for string getters
158
+ - [x] **Added**: const-correctness for all GCharPtr and GObjectPtr locals
159
+ - **Platform APIs verified**:
160
+ - GDrive/GVolume metadata APIs - Ownership transfer rules
161
+
162
+ ## Testing Strategy
163
+
164
+ ### Memory Leak Detection ✅
165
+ 1. [x] Run valgrind, LeakSanitizer, and AddressSanitizer on Linux builds
166
+ - **Implemented**: Comprehensive memory testing infrastructure
167
+ - Valgrind: `npm run test:valgrind` with suppressions in `.valgrind.supp`
168
+ - AddressSanitizer: `npm run asan` with proper clang integration
169
+ - LeakSanitizer: Integrated with ASan, suppressions in `.lsan-suppressions.txt`
170
+ - All tests show 0 memory leaks in fs-metadata code
171
+ 2. [ ] Use Application Verifier on Windows
172
+ 3. [ ] Enable address sanitizer for macOS builds
173
+ 4. [x] Run existing memory.test.ts with extended iterations
174
+ - JavaScript memory tests: `npm run test:memory`
175
+ - Comprehensive suite: `npm run tests:memory`
176
+
177
+ ### API Verification
178
+ 1. [ ] Use Perplexity/WebSearch to verify:
179
+ - Minimum OS version requirements for each API
180
+ - Deprecated API alternatives
181
+ - Thread safety guarantees
182
+ - Memory ownership rules
183
+ 2. [ ] Cross-reference with official documentation:
184
+ - Apple Developer Documentation
185
+ - Microsoft Win32 API Reference
186
+ - Linux man pages and library docs
187
+
188
+ ### Resource Management
189
+ 1. [ ] Add stress tests for mount/unmount cycles
190
+ 2. [ ] Test with network filesystem timeouts
191
+ 3. [ ] Verify cleanup on exception paths
192
+ 4. [ ] Test with maximum path lengths
193
+
194
+ ## Priority Items
195
+
196
+ 1. ~~**Critical**: Thread safety in Windows DriveHealthChecker (src/windows/drive_status.h)~~ ✅ Completed
197
+ - ✅ Replaced `volatile bool shouldTerminate` with `std::atomic<bool>`
198
+ - ✅ Replaced `DriveStatus result` with `std::atomic<DriveStatus>`
199
+ - ✅ Removed dangerous `TerminateThread` usage
200
+ - ✅ Increased graceful shutdown timeout from 100ms to 1000ms
201
+ 2. ~~**High**: Windows API buffer issues~~ ✅ Completed
202
+ - ✅ WNetConnection: Handle ERROR_MORE_DATA with dynamic buffer resize
203
+ - ✅ GetVolumeInformation: Use MAX_PATH+1 instead of BUFFER_SIZE
204
+ 3. ~~**High**: CoreFoundation reference counting in macOS code~~ ✅ Completed - CFReleaser RAII wrapper
205
+ 4. ~~**High**: GIO object lifecycle management~~ ✅ Completed - Using smart pointers throughout
206
+ 5. ~~**Medium**: Security - Add comprehensive path validation~~ ✅ Completed
207
+ - ✅ Check for ".." in all platforms (Windows/Darwin have it, Linux doesn't have hidden file support)
208
+ - Validate against null bytes and special characters (remaining)
209
+ - Add input validation for empty mount points (remaining)
210
+ 6. ~~**Medium**: String encoding conversions across platforms~~ ✅ Completed - Proper UTF-8/wide conversions
211
+ 7. ~~**Medium**: Buffer overflow protection in size calculations~~ ✅ Completed - Darwin has exemplary protection
212
+
213
+ ### Completed Items
214
+ - ✅ Linux memory management review (all files)
215
+ - ✅ Darwin/macOS memory management review (all files)
216
+ - ✅ Windows memory management review (all files including drive_status.h)
217
+ - ✅ const-correctness improvements across codebase
218
+ - ✅ Memory leak detection infrastructure (Valgrind + ASan)
219
+ - ✅ Static analysis integration (clang-tidy)
220
+ - ✅ Comprehensive memory testing documentation
221
+ - ✅ RAII patterns verified across all platforms
222
+ - ✅ N-API usage verified - no deprecated functions
223
+ - ✅ Platform API compatibility verified
224
+ - ✅ Thread safety issues resolved (std::atomic usage)
225
+ - ✅ Windows API buffer handling fixed
226
+ - ✅ Path validation for directory traversal added
227
+
228
+ ## Recent Improvements (Completed)
229
+
230
+ ### Code Quality
231
+ 1. **const-correctness**: Added `const` qualifiers to all appropriate local variables across the codebase
232
+ - All Napi::Env instances
233
+ - All GCharPtr, GObjectPtr, GFileInfoPtr instances
234
+ - All std::lock_guard instances
235
+ - Improves code safety and enables compiler optimizations
236
+
237
+ 2. **Static Analysis**: Integrated clang-tidy
238
+ - Added to CI/CD pipeline
239
+ - Uses bear to generate compile_commands.json
240
+ - Runs only on platform-relevant files
241
+ - Added to precommit checks
242
+
243
+ 3. **Memory Testing Infrastructure**
244
+ - Created comprehensive memory testing documentation (`docs/MEMORY_TESTING.md`)
245
+ - Improved ASan configuration with proper suppressions
246
+ - Created standalone test runner (`scripts/sanitizers-test.sh`)
247
+ - Updated `scripts/check-memory.mjs` with better ASan support
248
+ - All memory tests integrated into CI/CD
249
+
250
+ ## Documentation Updates Needed
251
+
252
+ - [x] Document RAII pattern usage guidelines - See existing code patterns
253
+ - [x] Add platform-specific memory management notes - Added to MEMORY_TESTING.md
254
+ - [x] Create error handling best practices - Documented in code
255
+ - [ ] Document thread safety requirements
256
+
257
+ ## Platform API Resources
258
+
259
+ ### macOS/Darwin
260
+ - Core Foundation Memory Management: Functions with "Create" or "Copy" require CFRelease
261
+ - DiskArbitration: Follows standard Core Foundation ownership rules
262
+ - Key Documentation: Apple Developer Documentation for DiskArbitration framework
263
+ - **Review Status**: ✅ All files use proper RAII with CFReleaser template
264
+
265
+ ### Windows
266
+ - WNetGetConnection: Start with 256 chars, handle ERROR_MORE_DATA
267
+ - GetVolumeInformation: Fixed buffers of MAX_PATH+1
268
+ - Key Documentation: Microsoft Learn Win32 API Reference
269
+ - **Review Status**: ⚠️ Buffer handling needs fixes, thread safety critical issue
270
+
271
+ ### Linux
272
+ - libblkid: Use free() for blkid_get_tag_value results, blkid_put_cache() for cache
273
+ - GLib/GIO: Use g_object_unref() or g_clear_object(), match allocation functions
274
+ - Key Documentation: libblkid man pages, GNOME Developer Documentation
275
+ - **Review Status**: ✅ All files properly reviewed and use smart pointers
276
+
277
+ ## Critical Windows Thread Safety Issue ✅ FIXED
278
+
279
+ File: `src/windows/drive_status.h`
280
+ ```cpp
281
+ // Fixed code:
282
+ std::atomic<bool> shouldTerminate{false}; // Using atomic with proper memory ordering
283
+ std::atomic<DriveStatus> result{DriveStatus::Unknown}; // Thread-safe result storage
284
+ // Removed TerminateThread - now uses graceful shutdown with 1000ms timeout
285
+ ```
286
+
287
+ This critical issue has been resolved:
288
+ - ✅ Race conditions eliminated with std::atomic
289
+ - ✅ Removed dangerous TerminateThread call
290
+ - ✅ Proper memory ordering with acquire/release semantics
291
+ - ✅ Graceful thread shutdown with increased timeout
package/CHANGELOG.md CHANGED
@@ -14,6 +14,43 @@ Fixed for any bug fixes.
14
14
  Security in case of vulnerabilities.
15
15
  -->
16
16
 
17
+ ## [0.6.0] - 2025-06-09
18
+
19
+ ### Added
20
+
21
+ - Comprehensive memory testing framework with Valgrind and AddressSanitizer support
22
+ - Thread safety tests for Windows platform
23
+ - Platform-specific build scripts with automatic OS detection
24
+ - Clang-tidy integration for C++ code analysis
25
+ - Worker thread helper for volume metadata operations
26
+ - NAPI_VERSION=9 definition for improved compatibility
27
+ - Dynamic test timeout configuration based on environment (CI, platform, architecture)
28
+ - Prebuild script for Linux GLIBC compatibility in Docker environments
29
+
30
+ ### Breaking
31
+
32
+ - Dropped support for Node.js v18, added support for Node.js v24
33
+
34
+ ### Changed
35
+
36
+ - Simplified ESM/CJS dual module support with unified build configuration
37
+ - Enhanced test coverage with additional error handling and edge case tests
38
+ - Updated all imports to use `node:` prefix for built-in modules
39
+ - Reorganized build and test scripts for better clarity
40
+ - Improved memory test workflow for cross-platform compatibility
41
+ - Renamed native module target from `node_fs_meta` to `fs_metadata` for consistency
42
+
43
+ ### Fixed
44
+
45
+ - Added path validation to prevent directory traversal vulnerabilities in hidden file operations
46
+ - Improved error handling and null checks across Linux GIO implementation
47
+ - Fixed buffer allocation issues in Windows networking and volume operations
48
+ - Enhanced resource management with better validation for empty mount points
49
+ - Made `SystemPathPatternsDefault` values visible in TypeScript typings
50
+ - Added Napi::HandleScope to OnOK and OnError methods for proper scope management
51
+ - Removed unnecessary std::move operations in worker implementations
52
+ - Resolved CI test reliability issues across different environments, particularly Alpine ARM64 emulation timeouts
53
+
17
54
  ## [0.4.0] - 2025-01-09
18
55
 
19
56
  - `Fixed`: Switch to thread-safe `getmntinfo_r_np()` for macOS. Improved darwin resource management.
@@ -23,7 +60,7 @@ Security in case of vulnerabilities.
23
60
  - `Packaging`: Improved ESM/CJS support with common `__dirname` implementation thanks to `tsup` [shims](https://tsup.egoist.dev/#inject-cjs-and-esm-shims).
24
61
 
25
62
  This change simplifies the implementation and improves inline jsdocs as the exported code and docs have been inlined.
26
-
63
+
27
64
  - `Packaging`: Re-enabled test coverage assertions (after finding the magicks to get istanbul to see what the tests were exercising)
28
65
 
29
66
  - `Packaging`: Added debuglog tests
package/CLAUDE.md ADDED
@@ -0,0 +1,346 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ This is @photostructure/fs-metadata - a cross-platform native Node.js module for retrieving filesystem metadata, including mount points, volume information, and space utilization statistics.
8
+
9
+ ### Key Features
10
+ - Cross-platform support: Windows 10+ (x64), macOS 14+, Ubuntu 22+ (x64, arm64)
11
+ - Lists all mounted volumes/drives
12
+ - Gets detailed volume metadata (size, usage, filesystem type, etc.)
13
+ - Hidden file/directory attribute support (get/set)
14
+ - Non-blocking async native implementations
15
+ - Timeout handling for unresponsive network volumes
16
+ - ESM and CJS module support
17
+ - Full TypeScript type definitions
18
+ - Worker threads support with proper context isolation
19
+
20
+ ### Platform-Specific Notes
21
+ - **Linux**: Optional GIO/GVfs mount support via Gnome libraries
22
+ - **Windows**: Uses separate threads per mountpoint for health checks to handle blocked system calls
23
+ - **System Volumes**: Each platform handles system volumes differently; the library uses heuristics to identify them
24
+
25
+ ## Architecture Overview
26
+
27
+ ### Core Structure
28
+ - **Native binding layer** (`src/binding.cpp`): Node-API v9 bridge between JavaScript and platform-specific implementations
29
+ - **Platform abstractions** in `src/common/`: Shared C++ interfaces for cross-platform functionality
30
+ - **Platform implementations**:
31
+ - `src/darwin/`: macOS-specific code using Core Foundation APIs
32
+ - `src/linux/`: Linux-specific code with optional GIO support for GNOME/GVfs
33
+ - `src/windows/`: Windows-specific code using Win32 APIs
34
+
35
+ ### Key Features
36
+ - **Volume Metadata**: Retrieves filesystem information (mount points, disk usage, health status)
37
+ - **Hidden File Support**: Cross-platform hidden file detection and manipulation
38
+ - **Async Operations**: All native operations use Worker threads to avoid blocking
39
+
40
+ ### Build System
41
+ - Uses `node-gyp` for native compilation
42
+ - Conditionally enables GIO support on Linux via `scripts/configure.mjs`
43
+ - Provides prebuilt binaries via `prebuildify` for common platforms
44
+ - Supports both ESM and CJS module formats
45
+
46
+ ### Cross-Module Compatibility
47
+ - **Directory Path Resolution**: Use `_dirname()` from `./dirname` instead of `__dirname`
48
+ - Works in both CommonJS and ESM contexts
49
+ - Handles Jest test environments correctly
50
+ - Example: `const dir = _dirname()` instead of `const dir = __dirname`
51
+
52
+ ### Testing Strategy
53
+ - Jest for both CJS and ESM test suites
54
+ - Platform-specific test expectations handled via `isWindows`, `isMacOS`, `isLinux` helpers
55
+ - Memory leak testing with garbage collection monitoring
56
+ - Coverage thresholds: 80% for all metrics
57
+
58
+ ### Testing File System Metadata
59
+ - **Important**: File system metadata like `available` space, `used` space, and other dynamic properties change continuously as other processes run on the machine
60
+ - Tests should **never** expect exact equality for these values between multiple calls
61
+ - **Do not** make range assertions (e.g., `available > 0` or `used < size`) because:
62
+ - Files can be created or deleted between calls (potentially gigabytes)
63
+ - The changes can be dramatic and unpredictable
64
+ - Instead, for dynamic metadata:
65
+ - Only verify the value exists and has the correct type
66
+ - Use `typeof result.available === 'number'` rather than range checks
67
+ - Focus on testing static properties (e.g., `size`, `mountFrom`, `fstype`) for exact equality
68
+ - Consider using snapshot testing only for stable properties
69
+
70
+ ### Timeout Handling
71
+ - Default timeout for volume operations to handle unresponsive network mounts
72
+ - Windows uses separate threads per mountpoint for health checks
73
+ - Configurable via `Options` interface
74
+
75
+ ### Debug Logging
76
+ - Enable with `NODE_DEBUG=fs-meta` or `NODE_DEBUG=photostructure:fs-metadata`
77
+ - Debug messages from both JavaScript and native code are sent to `stderr`
78
+ - Uses native Node.js debuglog for determining if logging is enabled
79
+
80
+ ## Example Usage
81
+
82
+ ```typescript
83
+ import { getVolumeMountPoints, getVolumeMetadata } from "@photostructure/fs-metadata";
84
+
85
+ // List all mounted volumes
86
+ const mountPoints = await getVolumeMountPoints();
87
+ console.dir({ mountPoints });
88
+
89
+ // Get metadata for a specific volume
90
+ const volumeMetadata = await getVolumeMetadata(mountPoints[0]);
91
+ console.dir({ volumeMetadata });
92
+
93
+ // Check if a file is hidden
94
+ import { isHidden } from "@photostructure/fs-metadata";
95
+ const hidden = await isHidden("/path/to/file");
96
+ ```
97
+
98
+ ## CI/CD Test Reliability Guidelines
99
+
100
+ Based on analysis of recent test failures, here are critical patterns to avoid flaky tests:
101
+
102
+ ### 1. Benchmark and Performance Tests
103
+ - **Problem**: "Cannot log after tests are done" errors in worker_threads.test.ts
104
+ - **Solution**:
105
+ - Always await all async operations before test completion
106
+ - Use proper test lifecycle hooks (afterEach/afterAll) for cleanup
107
+ - Avoid console.log in async contexts without proper synchronization
108
+ - Consider using test.concurrent with explicit done() callbacks
109
+
110
+ ### 2. Alpine Linux ARM64 Issues
111
+ - **Problem**: Tests timeout on emulated Alpine ARM64 environments
112
+ - **Solution**:
113
+ - Skip process-spawning tests on Alpine ARM64 (`if (isAlpine && isARM64)`)
114
+ - Use increased timeout multipliers (20x) for emulated environments
115
+ - Detect emulation via `/proc/cpuinfo` or environment checks
116
+ - Consider separate test suites for native vs emulated environments
117
+
118
+ ### 3. Worker Thread Management
119
+ - **Problem**: Race conditions in concurrent worker operations
120
+ - **Solution**:
121
+ - Implement proper worker pool management with size limits
122
+ - Use Promise.allSettled() instead of Promise.all() for parallel operations
123
+ - Add explicit cleanup in test teardown to terminate all workers
124
+ - Set reasonable concurrency limits based on environment (CPU cores)
125
+
126
+ ### 4. Timeout Test Reliability
127
+ - **Problem**: Timeout tests fail due to timing precision issues
128
+ - **Solution**:
129
+ - Never use exact timing assertions (e.g., expect 100ms)
130
+ - Use ranges with adequate margins (e.g., 90-110ms)
131
+ - Account for CI environment variability (slower machines)
132
+ - Consider mocking timers for deterministic behavior
133
+
134
+ ### 5. File System Operations
135
+ - **Problem**: ENOENT errors for test directories, permission issues
136
+ - **Solution**:
137
+ - Always use unique temporary directories per test
138
+ - Clean up test artifacts in afterEach hooks
139
+ - Check directory existence before operations
140
+ - Handle platform-specific path separators
141
+
142
+ ### 6. Memory and Resource Leaks
143
+ - **Problem**: Tests don't properly clean up resources
144
+ - **Solution**:
145
+ - Explicitly close all file handles, network connections
146
+ - Use try-finally blocks for resource cleanup
147
+ - Monitor memory usage in long-running tests
148
+ - Implement proper garbage collection triggers
149
+
150
+ ### 7. Platform-Specific Failures
151
+ - **Problem**: Different behavior across Windows/macOS/Linux
152
+ - **Solution**:
153
+ - Use platform detection helpers consistently
154
+ - Skip platform-specific tests appropriately
155
+ - Account for filesystem differences (case sensitivity, path formats)
156
+ - Test with platform-specific CI matrices
157
+
158
+ ### 8. Jest Configuration
159
+ - **Problem**: Tests interfere with each other
160
+ - **Solution**:
161
+ - Use `--runInBand` for tests with shared resources
162
+ - Clear module cache between tests when needed
163
+ - Isolate tests that spawn processes
164
+ - Configure proper test timeouts per environment
165
+
166
+ ### Async Cleanup Anti-Patterns
167
+
168
+ **IMPORTANT**: The following approaches are NOT valid solutions for async cleanup issues:
169
+
170
+ ```javascript
171
+ // BAD: Arbitrary timeouts in tests
172
+ await new Promise((resolve) => setTimeout(resolve, 100));
173
+
174
+ // BAD: Forcing garbage collection
175
+ if (global.gc) {
176
+ global.gc();
177
+ }
178
+
179
+ // BAD: Adding setImmediate in afterAll to "fix" hanging tests
180
+ afterAll(async () => {
181
+ await new Promise((resolve) => setImmediate(resolve));
182
+ });
183
+ ```
184
+
185
+ **Why these are problematic:**
186
+
187
+ 1. **Arbitrary timeouts** are race conditions waiting to happen. They might work on fast machines but fail on slower CI runners.
188
+ 2. **Forcing GC** should never be required for correct behavior. If your code depends on GC for correctness, it has a fundamental design flaw.
189
+ 3. **setImmediate/nextTick delays** in cleanup hooks don't fix the root cause - they just paper over the real issue.
190
+ 4. These approaches mask the real problem instead of fixing it.
191
+
192
+ **Note**: This is different from legitimate uses of timeouts, such as:
193
+
194
+ - Waiting for time to pass to test timestamp changes
195
+ - Rate limiting or throttling tests
196
+ - Testing timeout behavior itself
197
+
198
+ The anti-pattern is using timeouts or GC to "fix" async cleanup issues.
199
+
200
+ **What to do instead:**
201
+
202
+ 1. Find the actual resource that's keeping the process alive (use `--detectOpenHandles`)
203
+ 2. Ensure all database connections are properly closed
204
+ 3. Ensure all file handles are closed
205
+ 4. Cancel or await all pending async operations
206
+ 5. Use proper resource management patterns (RAII, try-finally, using statements)
207
+
208
+ ### Windows-Compatible Directory Cleanup
209
+
210
+ **IMPORTANT**: Never use `fs.rmSync()` or `fs.rm()` without proper Windows retry logic for directory cleanup in tests.
211
+
212
+ **Problem**: On Windows, file handles and directory locks can remain active longer than on Unix systems, causing `EBUSY` errors during cleanup.
213
+
214
+ **Proper Solution**: Use `fsp.rm()` (async) with retry options:
215
+
216
+ ```typescript
217
+ await fsp.rm(tempDir, {
218
+ recursive: true,
219
+ force: true,
220
+ maxRetries: process.platform === "win32" ? 3 : 1,
221
+ retryDelay: process.platform === "win32" ? 100 : 0,
222
+ });
223
+ ```
224
+
225
+ **Best Practice**: Use existing test utilities that handle Windows-compatible cleanup patterns. Don't manually clean up temp directories - let the test framework handle it with proper retry logic.
226
+
227
+ ### Adaptive Timeout Testing
228
+
229
+ **Problem**: Fixed timeouts don't account for varying CI environment performance.
230
+
231
+ **Root Causes**:
232
+
233
+ - Alpine Linux (musl libc) is 2x slower than glibc
234
+ - ARM64 emulation on x64 runners is 5x slower
235
+ - Windows process operations are 4x slower
236
+ - macOS VMs are 4x slower
237
+ - CI environments have resource constraints
238
+
239
+ **Solutions**:
240
+
241
+ ```typescript
242
+ // DON'T: Use fixed timeouts
243
+ test("my test", async () => {
244
+ // Test code
245
+ }, 10000);
246
+
247
+ // DO: Use adaptive timeouts based on environment
248
+ import { getTestTimeout } from "./test-utils/test-timeout-config";
249
+
250
+ test(
251
+ "my test",
252
+ async () => {
253
+ // Test code
254
+ },
255
+ getTestTimeout(10000),
256
+ );
257
+
258
+ // DO: Account for platform timing differences
259
+ const timingMultiplier = process.platform === "win32" ? 4 :
260
+ process.platform === "darwin" ? 4 :
261
+ process.env.CI ? 2 : 1;
262
+ ```
263
+
264
+ ### Multi-Process Test Synchronization
265
+
266
+ **Problem**: Multi-process tests failing due to race conditions between process startup and test assertions.
267
+
268
+ **Root Cause**: The timing between process startup and resource acquisition varies significantly by platform.
269
+
270
+ **Solutions**:
271
+
272
+ ```typescript
273
+ // DON'T: Assume immediate process readiness
274
+ const proc = spawn(nodeCmd, [script]);
275
+ const result = await waitForProcessResult(proc);
276
+ expect(result).toBe("expected_outcome"); // May fail due to timing
277
+
278
+ // DO: Use explicit synchronization signals
279
+ const script = `
280
+ // Setup code
281
+ console.log("READY"); // Signal readiness
282
+ // Main test logic
283
+ console.log("RESULT:" + outcome);
284
+ `;
285
+
286
+ const proc = spawn(process.execPath, ["-e", script]);
287
+ await waitForOutput(proc, "READY"); // Wait for process to be ready
288
+ const result = await waitForOutput(proc, "RESULT:");
289
+ expect(result.split(":")[1]).toBe("expected_outcome");
290
+ ```
291
+
292
+ ### Wait-for-Condition Pattern
293
+
294
+ **Problem**: Tests failing because they don't wait for asynchronous conditions to be met.
295
+
296
+ **Solution**: Implement robust condition waiting with platform-aware timing:
297
+
298
+ ```typescript
299
+ async function waitForCondition(
300
+ check: () => boolean | Promise<boolean>,
301
+ options: {
302
+ maxAttempts?: number;
303
+ delay?: number;
304
+ timeoutMs?: number;
305
+ } = {}
306
+ ) {
307
+ const {
308
+ maxAttempts = 50,
309
+ delay = 100,
310
+ timeoutMs = 30000
311
+ } = options;
312
+
313
+ const startTime = Date.now();
314
+
315
+ for (let i = 0; i < maxAttempts; i++) {
316
+ if (Date.now() - startTime > timeoutMs) {
317
+ throw new Error(`Condition not met within ${timeoutMs}ms`);
318
+ }
319
+
320
+ if (await check()) return true;
321
+ await new Promise((resolve) => setTimeout(resolve, delay));
322
+ }
323
+
324
+ return false;
325
+ }
326
+
327
+ // Usage example
328
+ await waitForCondition(
329
+ () => fs.existsSync(expectedFile),
330
+ { timeoutMs: getTestTimeout(10000) }
331
+ );
332
+ ```
333
+
334
+ ### Best Practices Summary
335
+ 1. **Always clean up**: Resources, timers, workers, file handles
336
+ 2. **Never assume timing**: Use ranges and adaptive timeouts, not exact values
337
+ 3. **Isolate tests**: Each test should be independent
338
+ 4. **Platform awareness**: Skip tests that can't work on certain platforms
339
+ 5. **Proper async handling**: Always await or return promises
340
+ 6. **Resource limits**: Don't spawn unlimited workers/processes
341
+ 7. **Environment detection**: Adjust behavior for CI vs local
342
+ 8. **Deterministic tests**: Mock external dependencies when possible
343
+ 9. **Explicit synchronization**: Use signals for multi-process coordination
344
+ 10. **Robust waiting**: Use condition-based waiting instead of arbitrary timeouts
345
+ 11. **Windows compatibility**: Use retry logic for file operations on Windows
346
+ 12. **Anti-pattern awareness**: Avoid masking problems with timeouts or forced GC