@photostructure/fs-metadata 0.6.1 → 0.7.0

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 (89) hide show
  1. package/CHANGELOG.md +7 -1
  2. package/CLAUDE.md +141 -315
  3. package/CODE_OF_CONDUCT.md +11 -11
  4. package/CONTRIBUTING.md +1 -1
  5. package/README.md +34 -103
  6. package/binding.gyp +97 -22
  7. package/claude.sh +23 -0
  8. package/dist/index.cjs +51 -21
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +5 -0
  11. package/dist/index.d.mts +5 -0
  12. package/dist/index.d.ts +5 -0
  13. package/dist/index.mjs +51 -21
  14. package/dist/index.mjs.map +1 -1
  15. package/doc/C++_REVIEW_TODO.md +97 -25
  16. package/doc/GPG_RELEASE_HOWTO.md +44 -13
  17. package/doc/MACOS_API_REFERENCE.md +469 -0
  18. package/doc/SECURITY_AUDIT_2025.md +809 -0
  19. package/doc/SSH_RELEASE_HOWTO.md +28 -24
  20. package/doc/WINDOWS_API_REFERENCE.md +422 -0
  21. package/doc/WINDOWS_ARM64_SECURITY.md +161 -0
  22. package/doc/WINDOWS_DEBUG_GUIDE.md +9 -2
  23. package/doc/examples.md +267 -0
  24. package/doc/gotchas.md +297 -0
  25. package/doc/logo.png +0 -0
  26. package/doc/logo.svg +85 -0
  27. package/doc/macos-asan-sip-issue.md +71 -0
  28. package/doc/social.png +0 -0
  29. package/doc/social.svg +125 -0
  30. package/doc/windows-build.md +226 -0
  31. package/doc/windows-clang-tidy.md +72 -0
  32. package/doc/windows-memory-testing.md +108 -0
  33. package/doc/windows-prebuildify-arm64.md +232 -0
  34. package/jest.config.cjs +23 -0
  35. package/package.json +61 -36
  36. package/prebuilds/darwin-arm64/@photostructure+fs-metadata.glibc.node +0 -0
  37. package/prebuilds/darwin-x64/@photostructure+fs-metadata.glibc.node +0 -0
  38. package/prebuilds/linux-arm64/@photostructure+fs-metadata.glibc.node +0 -0
  39. package/prebuilds/linux-arm64/@photostructure+fs-metadata.musl.node +0 -0
  40. package/prebuilds/linux-x64/@photostructure+fs-metadata.glibc.node +0 -0
  41. package/prebuilds/linux-x64/@photostructure+fs-metadata.musl.node +0 -0
  42. package/prebuilds/win32-arm64/@photostructure+fs-metadata.glibc.node +0 -0
  43. package/prebuilds/win32-x64/@photostructure+fs-metadata.glibc.node +0 -0
  44. package/scripts/check-memory.ts +186 -0
  45. package/scripts/clang-tidy.ts +690 -99
  46. package/scripts/install.cjs +42 -0
  47. package/scripts/is-platform.mjs +1 -1
  48. package/scripts/macos-asan.sh +155 -0
  49. package/scripts/post-build.mjs +3 -3
  50. package/scripts/prebuild-linux-glibc.sh +12 -1
  51. package/scripts/prebuildify-wrapper.ts +77 -0
  52. package/scripts/precommit.ts +45 -20
  53. package/scripts/sanitizers-test.sh +1 -1
  54. package/src/common/volume_metadata.h +6 -0
  55. package/src/darwin/hidden.cpp +73 -25
  56. package/src/darwin/path_security.h +149 -0
  57. package/src/darwin/raii_utils.h +104 -4
  58. package/src/darwin/volume_metadata.cpp +132 -58
  59. package/src/darwin/volume_mount_points.cpp +80 -47
  60. package/src/hidden.ts +36 -13
  61. package/src/linux/gio_mount_points.cpp +17 -18
  62. package/src/linux/gio_utils.cpp +92 -37
  63. package/src/linux/gio_utils.h +11 -5
  64. package/src/linux/gio_volume_metadata.cpp +111 -48
  65. package/src/linux/volume_metadata.cpp +67 -4
  66. package/src/object.ts +1 -0
  67. package/src/options.ts +6 -0
  68. package/src/path.ts +11 -0
  69. package/src/remote_info.ts +5 -3
  70. package/src/stack_path.ts +8 -6
  71. package/src/string_enum.ts +1 -0
  72. package/src/test-utils/memory-test-core.ts +336 -0
  73. package/src/test-utils/memory-test-runner.ts +108 -0
  74. package/src/test-utils/platform.ts +46 -1
  75. package/src/test-utils/worker-thread-helper.cjs +154 -27
  76. package/src/types/native_bindings.ts +1 -1
  77. package/src/types/options.ts +6 -0
  78. package/src/windows/drive_status.h +133 -163
  79. package/src/windows/error_utils.h +54 -3
  80. package/src/windows/fs_meta.h +1 -1
  81. package/src/windows/hidden.cpp +60 -43
  82. package/src/windows/security_utils.h +250 -0
  83. package/src/windows/string.h +68 -11
  84. package/src/windows/system_volume.h +1 -1
  85. package/src/windows/thread_pool.h +206 -0
  86. package/src/windows/volume_metadata.cpp +11 -6
  87. package/src/windows/volume_mount_points.cpp +8 -7
  88. package/src/windows/windows_arch.h +39 -0
  89. package/scripts/check-memory.mjs +0 -123
package/CHANGELOG.md CHANGED
@@ -14,7 +14,13 @@ Fixed for any bug fixes.
14
14
  Security in case of vulnerabilities.
15
15
  -->
16
16
 
17
- ## [0.6.0] - 2025-06-09
17
+ ## 0.7.0 - 2025-10-24
18
+
19
+ - Audit and address [several resource handling issues](./doc/SECURITY_AUDIT_2025.md)
20
+ - Added support for Node.js v25
21
+ - Updated dev dependencies
22
+
23
+ ## 0.6.0 - 2025-06-09
18
24
 
19
25
  ### Added
20
26
 
package/CLAUDE.md CHANGED
@@ -4,242 +4,151 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
4
4
 
5
5
  ## Project Overview
6
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
7
+ @photostructure/fs-metadata - Cross-platform native Node.js module for filesystem metadata retrieval.
45
8
 
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`
9
+ ### Directory Structure
10
+
11
+ - `src/` - Source code (TypeScript and C++)
12
+ - `dist/` - Compiled JavaScript output (gitignored)
13
+ - `doc/` - Static documentation (manually written, checked into git)
14
+ - `build/` - All build artifacts (gitignored)
15
+ - `build/docs/` - Generated API documentation from TypeDoc (deployed to GitHub Pages)
16
+ - `scripts/` - Build and utility scripts
17
+ - `prebuilds/` - Prebuilt native binaries for different platforms
18
+
19
+ ### Script Preferences
20
+
21
+ **Always** use TypeScript (`.ts`) scripts executed with `tsx` instead of:
22
+
23
+ - `.js` scripts (require compilation or older Node.js syntax)
24
+ - `.mjs` scripts (ESM-only, compatibility issues)
25
+ - `.cjs` scripts (CommonJS-only, less type safety)
51
26
 
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
27
+ TypeScript with tsx provides type safety, modern syntax, and seamless execution.
28
+
29
+ ## Critical Knowledge
57
30
 
58
31
  ### 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
32
 
80
- ## Release Process
33
+ **Never** expect exact equality for dynamic values (`available`, `used`) between calls. Only verify:
81
34
 
82
- The project uses a vanilla npm/git release workflow with GPG signed commits for security:
35
+ - Value exists and has correct type: `typeof result.available === 'number'`
36
+ - Test static properties (`size`, `mountFrom`, `fstype`) for exact equality
37
+ - Avoid range assertions (`available > 0`) - file changes can be dramatic
83
38
 
84
- ### Prerequisites
85
- - Repository secrets must be configured:
86
- - `NPM_TOKEN`: Authentication token for npm publishing
87
- - `GPG_PRIVATE_KEY`: ASCII-armored GPG private key for signing commits
88
- - `GPG_PASSPHRASE`: Passphrase for the GPG key (if applicable)
39
+ ### Cross-Module Compatibility
89
40
 
90
- ### Automated Release
91
- 1. Trigger via GitHub Actions workflow dispatch with version type (patch/minor/major)
92
- 2. Builds all prebuilds for supported platforms
93
- 3. Runs comprehensive test suite across platforms
94
- 4. Uses `npm version` to bump version and create signed git tags
95
- 5. Publishes to npm registry
96
- 6. Creates GitHub release with auto-generated notes
97
- 7. All commits and tags are GPG signed for verification
41
+ Use `_dirname()` from `./dirname` instead of `__dirname` - works in both CommonJS and ESM contexts.
98
42
 
99
- ### Manual Release (if needed)
100
- ```bash
101
- npm run prepare-release
102
- git config commit.gpgsign true
103
- npm version patch|minor|major
104
- npm publish
105
- git push origin main --follow-tags
106
- ```
43
+ ### Node.js Version Compatibility
107
44
 
108
- ## Example Usage
45
+ Jest 30 doesn't support Node.js 23. Use Node.js 20, 22, or 24.
109
46
 
110
- ```typescript
111
- import { getVolumeMountPoints, getVolumeMetadata } from "@photostructure/fs-metadata";
47
+ ## Windows-Specific Issues
112
48
 
113
- // List all mounted volumes
114
- const mountPoints = await getVolumeMountPoints();
115
- console.dir({ mountPoints });
49
+ ### Windows CI Jest Worker Failures
116
50
 
117
- // Get metadata for a specific volume
118
- const volumeMetadata = await getVolumeMetadata(mountPoints[0]);
119
- console.dir({ volumeMetadata });
51
+ **Problem**: Jest worker processes fail on Windows CI environments (both x64 and ARM64) with "Jest worker encountered 4 child process exceptions".
120
52
 
121
- // Check if a file is hidden
122
- import { isHidden } from "@photostructure/fs-metadata";
123
- const hidden = await isHidden("/path/to/file");
124
- ```
53
+ **Solution for Memory Tests**:
125
54
 
126
- ## CI/CD Test Reliability Guidelines
127
-
128
- Based on analysis of recent test failures, here are critical patterns to avoid flaky tests:
129
-
130
- ### 1. Benchmark and Performance Tests
131
- - **Problem**: "Cannot log after tests are done" errors in worker_threads.test.ts
132
- - **Solution**:
133
- - Always await all async operations before test completion
134
- - Use proper test lifecycle hooks (afterEach/afterAll) for cleanup
135
- - Avoid console.log in async contexts without proper synchronization
136
- - Consider using test.concurrent with explicit done() callbacks
137
-
138
- ### 2. Alpine Linux ARM64 Issues
139
- - **Problem**: Tests timeout on emulated Alpine ARM64 environments
140
- - **Solution**:
141
- - Skip process-spawning tests on Alpine ARM64 (`if (isAlpine && isARM64)`)
142
- - Use increased timeout multipliers (20x) for emulated environments
143
- - Detect emulation via `/proc/cpuinfo` or environment checks
144
- - Consider separate test suites for native vs emulated environments
145
-
146
- ### 3. Worker Thread Management
147
- - **Problem**: Race conditions in concurrent worker operations
148
- - **Solution**:
149
- - Implement proper worker pool management with size limits
150
- - Use Promise.allSettled() instead of Promise.all() for parallel operations
151
- - Add explicit cleanup in test teardown to terminate all workers
152
- - Set reasonable concurrency limits based on environment (CPU cores)
153
-
154
- ### 4. Timeout Test Reliability
155
- - **Problem**: Timeout tests fail due to timing precision issues
156
- - **Solution**:
157
- - Never use exact timing assertions (e.g., expect 100ms)
158
- - Use ranges with adequate margins (e.g., 90-110ms)
159
- - Account for CI environment variability (slower machines)
160
- - Consider mocking timers for deterministic behavior
161
-
162
- ### 5. File System Operations
163
- - **Problem**: ENOENT errors for test directories, permission issues
164
- - **Solution**:
165
- - Always use unique temporary directories per test
166
- - Clean up test artifacts in afterEach hooks
167
- - Check directory existence before operations
168
- - Handle platform-specific path separators
169
-
170
- ### 6. Memory and Resource Leaks
171
- - **Problem**: Tests don't properly clean up resources
172
- - **Solution**:
173
- - Explicitly close all file handles, network connections
174
- - Use try-finally blocks for resource cleanup
175
- - Monitor memory usage in long-running tests
176
- - Implement proper garbage collection triggers
177
-
178
- ### 7. Platform-Specific Failures
179
- - **Problem**: Different behavior across Windows/macOS/Linux
180
- - **Solution**:
181
- - Use platform detection helpers consistently
182
- - Skip platform-specific tests appropriately
183
- - Account for filesystem differences (case sensitivity, path formats)
184
- - Test with platform-specific CI matrices
185
-
186
- ### 8. Jest Configuration
187
- - **Problem**: Tests interfere with each other
188
- - **Solution**:
189
- - Use `--runInBand` for tests with shared resources
190
- - Clear module cache between tests when needed
191
- - Isolate tests that spawn processes
192
- - Configure proper test timeouts per environment
193
-
194
- ### Async Cleanup Anti-Patterns
195
-
196
- **IMPORTANT**: The following approaches are NOT valid solutions for async cleanup issues:
55
+ Memory tests now use a standalone TypeScript runner (`src/test-utils/memory-test-runner.ts`) that bypasses Jest entirely on all platforms. This provides more accurate memory measurements without Jest overhead and avoids worker process issues.
197
56
 
198
- ```javascript
199
- // BAD: Arbitrary timeouts in tests
200
- await new Promise((resolve) => setTimeout(resolve, 100));
57
+ - Run full memory check suite (includes native tools): `npm run check:memory`
58
+ - Memory test logic is in `src/test-utils/memory-test-core.ts`
201
59
 
202
- // BAD: Forcing garbage collection
203
- if (global.gc) {
204
- global.gc();
205
- }
60
+ **Workaround for Other Tests**:
206
61
 
207
- // BAD: Adding setImmediate in afterAll to "fix" hanging tests
208
- afterAll(async () => {
209
- await new Promise((resolve) => setImmediate(resolve));
210
- });
211
- ```
62
+ 1. Jest is configured to use single worker mode (`maxWorkers: 1`) for all Windows CI environments
63
+ 2. Tests that stress worker threads or concurrency are skipped on Windows CI using `describeSkipWindowsCI` or `describePlatformStable`:
64
+
65
+ - `worker_threads.test.ts` - Worker thread integration tests
66
+ - `thread_safety.test.ts` - Concurrent operations stress tests
67
+ - `windows-memory-check.test.ts` - Memory leak detection (Windows only)
68
+ - `windows-resource-security.test.ts` - Resource handle leak tests (Windows only)
69
+
70
+ **Note**: These tests pass locally but fail in CI. The native module loads correctly, but Jest's worker process management has fundamental incompatibilities with these specific tests on GitHub Actions Windows runners.
212
71
 
213
- **Why these are problematic:**
72
+ ### Build Architecture Issue
214
73
 
215
- 1. **Arbitrary timeouts** are race conditions waiting to happen. They might work on fast machines but fail on slower CI runners.
216
- 2. **Forcing GC** should never be required for correct behavior. If your code depends on GC for correctness, it has a fundamental design flaw.
217
- 3. **setImmediate/nextTick delays** in cleanup hooks don't fix the root cause - they just paper over the real issue.
218
- 4. These approaches mask the real problem instead of fixing it.
74
+ **Problem**: "No Target Architecture" error from Windows SDK headers when building with node-gyp/prebuildify.
219
75
 
220
- **Note**: This is different from legitimate uses of timeouts, such as:
76
+ **Solution**: Use `scripts/prebuildify-wrapper.ts` which sets the `CL` environment variable with architecture defines:
221
77
 
222
- - Waiting for time to pass to test timestamp changes
223
- - Rate limiting or throttling tests
224
- - Testing timeout behavior itself
78
+ - For x64: `CL=/D_M_X64 /D_WIN64 /D_AMD64_`
79
+ - For ARM64: `CL=/D_M_ARM64 /D_WIN64`
225
80
 
226
- The anti-pattern is using timeouts or GC to "fix" async cleanup issues.
81
+ **Why This is Necessary**:
227
82
 
228
- **What to do instead:**
83
+ - Prebuildify doesn't properly pass architecture defines from binding.gyp conditions
84
+ - The Windows SDK requires these macros before including `<windows.h>`
85
+ - Projects like node-sqlite avoid this by not using Windows headers directly
229
86
 
230
- 1. Find the actual resource that's keeping the process alive (use `--detectOpenHandles`)
231
- 2. Ensure all database connections are properly closed
232
- 3. Ensure all file handles are closed
233
- 4. Cancel or await all pending async operations
234
- 5. Use proper resource management patterns (RAII, try-finally, using statements)
87
+ **Why Other Approaches Failed**:
235
88
 
236
- ### Windows-Compatible Directory Cleanup
89
+ - **Source file defines**: Would hardcode x64 defines, breaking ARM64 builds
90
+ - **windows_compat.h wrapper**: Can't distinguish x64 from ARM64 at compile time
91
+ - **binding.gyp conditions**: Not evaluated properly by prebuildify
92
+ - **msvs_settings defines**: Not passed through to the compiler
237
93
 
238
- **IMPORTANT**: Never use `fs.rmSync()` or `fs.rm()` without proper Windows retry logic for directory cleanup in tests.
94
+ ### Memory Testing Limitations
239
95
 
240
- **Problem**: On Windows, file handles and directory locks can remain active longer than on Unix systems, causing `EBUSY` errors during cleanup.
96
+ Traditional Windows tools **do not work** with Node.js native modules:
241
97
 
242
- **Proper Solution**: Use `fsp.rm()` (async) with retry options:
98
+ - **Dr. Memory**: Fails with "Unable to load client library: ucrtbase.dll"
99
+ - **Debug CRT builds**: Cannot be loaded by Node.js (missing debug runtime + UNC path issues)
100
+ - **Visual Leak Detector**: Requires debug builds which don't work
101
+ - **Application Verifier**: Cannot hook into Node.js memory management
102
+
103
+ Use JavaScript-based memory testing (`src/windows-memory-check.test.ts`) instead.
104
+
105
+ ### Static Analysis (clang-tidy) Limitations
106
+
107
+ **clang-tidy on Windows** has limited effectiveness due to MSVC header incompatibility:
108
+
109
+ - Generates many false errors about missing std namespace members
110
+ - Still provides valuable warnings about your code
111
+ - See `doc/windows-clang-tidy.md` for details
112
+ - Consider using Visual Studio Code Analysis as an alternative
113
+
114
+ ### WSL Development
115
+
116
+ Run Windows commands from WSL:
117
+
118
+ ```bash
119
+ cmd.exe /c "cd C:\\Users\\matth\\src\\fs-metadata && npm test"
120
+ # Or create helper: echo 'cmd.exe /c "cd C:\\Users\\matth\\src\\fs-metadata && $@"' > ~/bin/win-run
121
+ ```
122
+
123
+ ## Memory Leak Detection
124
+
125
+ Run `npm run check:memory` for comprehensive platform-specific testing:
126
+
127
+ - **All platforms**: JavaScript memory tests with GC triggers
128
+ - **Windows**: Handle count monitoring via `process.report`
129
+ - **Linux**: Valgrind + AddressSanitizer/LeakSanitizer
130
+ - **macOS**: AddressSanitizer (may fail due to SIP - expected)
131
+
132
+ ## CI/CD Test Reliability
133
+
134
+ ### Critical Anti-Patterns
135
+
136
+ **Never** use these to "fix" async issues:
137
+
138
+ ```javascript
139
+ // BAD: Arbitrary timeouts
140
+ await new Promise((resolve) => setTimeout(resolve, 100));
141
+ // BAD: Forcing GC
142
+ if (global.gc) global.gc();
143
+ // BAD: setImmediate in afterAll
144
+ afterAll(async () => {
145
+ await new Promise((resolve) => setImmediate(resolve));
146
+ });
147
+ ```
148
+
149
+ ### Windows Directory Cleanup
150
+
151
+ Always use retry logic:
243
152
 
244
153
  ```typescript
245
154
  await fsp.rm(tempDir, {
@@ -250,125 +159,42 @@ await fsp.rm(tempDir, {
250
159
  });
251
160
  ```
252
161
 
253
- **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.
162
+ ### Platform Performance Multipliers
254
163
 
255
- ### Adaptive Timeout Testing
164
+ - Alpine Linux (musl): 2x slower
165
+ - ARM64 emulation: 5x slower
166
+ - Windows processes: 4x slower
167
+ - macOS VMs: 4x slower
256
168
 
257
- **Problem**: Fixed timeouts don't account for varying CI environment performance.
169
+ ### Multi-Process Synchronization
258
170
 
259
- **Root Causes**:
171
+ Use explicit signals:
260
172
 
261
- - Alpine Linux (musl libc) is 2x slower than glibc
262
- - ARM64 emulation on x64 runners is 5x slower
263
- - Windows process operations are 4x slower
264
- - macOS VMs are 4x slower
265
- - CI environments have resource constraints
266
-
267
- **Solutions**:
268
-
269
- ```typescript
270
- // DON'T: Use fixed timeouts
271
- test("my test", async () => {
272
- // Test code
273
- }, 10000);
274
-
275
- // DO: Use adaptive timeouts based on environment
276
- import { getTestTimeout } from "./test-utils/test-timeout-config";
277
-
278
- test(
279
- "my test",
280
- async () => {
281
- // Test code
282
- },
283
- getTestTimeout(10000),
284
- );
285
-
286
- // DO: Account for platform timing differences
287
- const timingMultiplier = process.platform === "win32" ? 4 :
288
- process.platform === "darwin" ? 4 :
289
- process.env.CI ? 2 : 1;
173
+ ```javascript
174
+ console.log("READY"); // Signal readiness
175
+ console.log("RESULT:" + outcome); // Signal result
290
176
  ```
291
177
 
292
- ### Multi-Process Test Synchronization
178
+ ## Release Process
293
179
 
294
- **Problem**: Multi-process tests failing due to race conditions between process startup and test assertions.
180
+ Requires repository secrets:
295
181
 
296
- **Root Cause**: The timing between process startup and resource acquisition varies significantly by platform.
182
+ - `NPM_TOKEN`: npm authentication
183
+ - `GPG_PRIVATE_KEY`: ASCII-armored GPG key
184
+ - `GPG_PASSPHRASE`: GPG passphrase
297
185
 
298
- **Solutions**:
186
+ Automated via GitHub Actions workflow dispatch or manual:
299
187
 
300
- ```typescript
301
- // DON'T: Assume immediate process readiness
302
- const proc = spawn(nodeCmd, [script]);
303
- const result = await waitForProcessResult(proc);
304
- expect(result).toBe("expected_outcome"); // May fail due to timing
305
-
306
- // DO: Use explicit synchronization signals
307
- const script = `
308
- // Setup code
309
- console.log("READY"); // Signal readiness
310
- // Main test logic
311
- console.log("RESULT:" + outcome);
312
- `;
313
-
314
- const proc = spawn(process.execPath, ["-e", script]);
315
- await waitForOutput(proc, "READY"); // Wait for process to be ready
316
- const result = await waitForOutput(proc, "RESULT:");
317
- expect(result.split(":")[1]).toBe("expected_outcome");
188
+ ```bash
189
+ npm run prepare-release
190
+ git config commit.gpgsign true
191
+ npm version patch|minor|major
192
+ npm publish
193
+ git push origin main --follow-tags
318
194
  ```
319
195
 
320
- ### Wait-for-Condition Pattern
196
+ ## General guidance
321
197
 
322
- **Problem**: Tests failing because they don't wait for asynchronous conditions to be met.
323
-
324
- **Solution**: Implement robust condition waiting with platform-aware timing:
325
-
326
- ```typescript
327
- async function waitForCondition(
328
- check: () => boolean | Promise<boolean>,
329
- options: {
330
- maxAttempts?: number;
331
- delay?: number;
332
- timeoutMs?: number;
333
- } = {}
334
- ) {
335
- const {
336
- maxAttempts = 50,
337
- delay = 100,
338
- timeoutMs = 30000
339
- } = options;
340
-
341
- const startTime = Date.now();
342
-
343
- for (let i = 0; i < maxAttempts; i++) {
344
- if (Date.now() - startTime > timeoutMs) {
345
- throw new Error(`Condition not met within ${timeoutMs}ms`);
346
- }
347
-
348
- if (await check()) return true;
349
- await new Promise((resolve) => setTimeout(resolve, delay));
350
- }
351
-
352
- return false;
353
- }
354
-
355
- // Usage example
356
- await waitForCondition(
357
- () => fs.existsSync(expectedFile),
358
- { timeoutMs: getTestTimeout(10000) }
359
- );
360
- ```
198
+ Never do inline imports like `const { mkdirSync } = await import("node:fs");` -- just use standard imports.
361
199
 
362
- ### Best Practices Summary
363
- 1. **Always clean up**: Resources, timers, workers, file handles
364
- 2. **Never assume timing**: Use ranges and adaptive timeouts, not exact values
365
- 3. **Isolate tests**: Each test should be independent
366
- 4. **Platform awareness**: Skip tests that can't work on certain platforms
367
- 5. **Proper async handling**: Always await or return promises
368
- 6. **Resource limits**: Don't spawn unlimited workers/processes
369
- 7. **Environment detection**: Adjust behavior for CI vs local
370
- 8. **Deterministic tests**: Mock external dependencies when possible
371
- 9. **Explicit synchronization**: Use signals for multi-process coordination
372
- 10. **Robust waiting**: Use condition-based waiting instead of arbitrary timeouts
373
- 11. **Windows compatibility**: Use retry logic for file operations on Windows
374
- 12. **Anti-pattern awareness**: Avoid masking problems with timeouts or forced GC
200
+ Never include claude code messages in git commits
@@ -17,23 +17,23 @@ diverse, inclusive, and healthy community.
17
17
  Examples of behavior that contributes to a positive environment for our
18
18
  community include:
19
19
 
20
- * Demonstrating empathy and kindness toward other people
21
- * Being respectful of differing opinions, viewpoints, and experiences
22
- * Giving and gracefully accepting constructive feedback
23
- * Accepting responsibility and apologizing to those affected by our mistakes,
20
+ - Demonstrating empathy and kindness toward other people
21
+ - Being respectful of differing opinions, viewpoints, and experiences
22
+ - Giving and gracefully accepting constructive feedback
23
+ - Accepting responsibility and apologizing to those affected by our mistakes,
24
24
  and learning from the experience
25
- * Focusing on what is best not just for us as individuals, but for the
25
+ - Focusing on what is best not just for us as individuals, but for the
26
26
  overall community
27
27
 
28
28
  Examples of unacceptable behavior include:
29
29
 
30
- * The use of sexualized language or imagery, and sexual attention or
30
+ - The use of sexualized language or imagery, and sexual attention or
31
31
  advances of any kind
32
- * Trolling, insulting or derogatory comments, and personal or political attacks
33
- * Public or private harassment
34
- * Publishing others' private information, such as a physical or email
32
+ - Trolling, insulting or derogatory comments, and personal or political attacks
33
+ - Public or private harassment
34
+ - Publishing others' private information, such as a physical or email
35
35
  address, without their explicit permission
36
- * Other conduct which could reasonably be considered inappropriate in a
36
+ - Other conduct which could reasonably be considered inappropriate in a
37
37
  professional setting
38
38
 
39
39
  ## Enforcement Responsibilities
@@ -106,7 +106,7 @@ Violating these terms may lead to a permanent ban.
106
106
  ### 4. Permanent Ban
107
107
 
108
108
  **Community Impact**: Demonstrating a pattern of violation of community
109
- standards, including sustained inappropriate behavior, harassment of an
109
+ standards, including sustained inappropriate behavior, harassment of an
110
110
  individual, or aggression toward or disparagement of classes of individuals.
111
111
 
112
112
  **Consequence**: A permanent ban from any sort of public interaction within
package/CONTRIBUTING.md CHANGED
@@ -26,7 +26,7 @@ Install the Xcode Command Line Tools, and then
26
26
 
27
27
  ### On Ubuntu/Debian
28
28
 
29
- sudo apt-get install build-essential clang-format libglib2.0-dev libblkid-dev uuid-dev
29
+ sudo apt-get install bear build-essential clang-format libglib2.0-dev libblkid-dev uuid-dev
30
30
 
31
31
  ## Before submitting your PR
32
32