Repository navigation
fs-safe 0.17.0
Highlights
- Complete writes and exact comparison for borrowed files: add
writeFileWindowFully()andsameFileContentsSync()under/advanced. Complete short writes with cancellation and per-write authority checks, or compare regular-file descriptors byte for byte with bounded memory and optional byte limits. Callers retain handle ownership and path admission. (#524) - Explicit archive permissions and reliable selection: add
extractArchive({ entryUmask })to remove selected permission bits from extracted files and directories. JavaScript ZIP filters now follow physical archive order, and extraction enforces deadlines even when synchronous work delays timer delivery. (#516, #521, #522) - Stronger checks at mutation boundaries: revalidate Root paths and private-file permissions after caller callbacks, retain exact identities through copy-and-remove moves, and keep synchronous JSON staging bound to its descriptor through publication and cleanup. Replaced entries remain protected. (#498, #500, #503, #497, #527)
- Less repeated work in targeted workloads: reduce ZIP scanning and name admission, TAR path validation, directory-walk allocations, store setup, and default lock-payload decoding. Performance results are workload-specific; archive and other control cases with measured costs remain documented in the linked PRs below.
- More reliable deep paths and native loading: resolve valid deep relative paths without JavaScript argument-limit failures, and select the matching native prebuild on Linux installations containing both glibc and musl loaders. (#523, #526)
Compatibility and upgrade notes
entryUmaskdefaults to0, preserving existing extraction modes. It applies afterentryModesto files, explicit directories, and implicit parents, including existing destination subdirectories; it does not change the destination root or private staging modes. The library neither reads nor changes the process umask. See the archive permission contract.- The new borrowed-file helpers do not acquire locks or provide path admission, identity validation, truncation, durability, or cleanup. Numeric write positions preserve the cursor and require handles opened without append mode;
nulladvances the current cursor. Comparison preserves both cursors and is not a snapshot of concurrently modified files. See borrowed-handle writes and exact comparison. - Atomic copy fallback and copied moves require exact bigint identity observations; injected filesystem adapters must honor
{ bigint: true }. Rounded or persistently unknown identities fail closed. A copied move can reportESTALEafter publishing the destination while preserving changed source entries; it is not a transaction or rollback guarantee. (#512, #527) - Pathname hashing and portable create-only writes now report owned descriptor-close failures after otherwise successful work. Earlier operation or cancellation failures retain precedence, and a completed destination remains in place after a late close or verification failure. (#525)
- Synchronous lock stale-policy callbacks must return synchronously: Promise or thenable results now reject with
TypeErrorbefore deletion. If a protected callback and release both fail,withFileLock()andwithFileLockSync()retain both throughSuppressedError, with the release failure primary. (#496)
Security and correctness
- Recheck hardlink policy before Root reads return bytes or handles, verify exact identities in the opened-handle path resolver, and capture local-root link policies before asynchronous admission. Explicit link-allow policies remain supported. (#498, #513)
- Renew directory ancestry and move/removal admission after authority callbacks. Protect replaced roots, copied source files and symlinks, and outside targets; honor callback-triggered removal cancellation before dispatch and preserve the published destination during cleanup failures. (#498, #503)
- Recheck private POSIX ownership and permissions before mode preparation, after producer and authority callbacks, and through fallback publication. Verify final modes and recheck exclusive-publication source and target identities after directory synchronization, preserving substituted entries and completed destinations on late failure. (#500, #509)
- Keep synchronous JSON staging descriptor-bound through publication and cleanup, preserving substitutions and staging-name collisions. Compare exact source, destination, and parent identities in atomic copy fallback and mode admission; retain exact move manifests and hardlink groups beyond JavaScript's safe integer range. (#497, #512, #527)
- Capture append content, encoding, mode, and byte limits before filesystem work so changes to caller options cannot change an in-flight write. Empty string appends no longer insert a newline; missing-file creation and durability behavior remain intact. (#506)
- Preserve physical ZIP entry order for JavaScript extraction filters, including numeric and Unicode filenames, without changing the public loader's files object. Check archive deadlines at monotonic boundaries, queued mutation dispatch, and successful settlement; retain caller errors and join active destination mutations before rejection. (#521, #522)
- Keep observed sidecar tokens separate from creator authority, and stop compromise monitoring after manager reset, including checks already in flight. Ownership verification retains raw bytes, token, and identity checks. (#496)
- Preserve arbitrary atomic filesystem-adapter failures, including nullish values and throwing error-code getters, and preserve original nullish failures from synchronous symlink-parent checks. Retain missing-file errors from durable queue callbacks, migrations, and owned claim transitions instead of misclassifying them as absent entries. (#512, #514, #529)
- Preserve paired temporary-workspace parent-admission and descriptor-close failures in an
AggregateError, including on aliases and newly created roots, instead of selecting compatible cleanup or losing the original diagnostic. (#519) - Accept exact bigint directory receipts in durability, exclusive publication, and staging inputs. Returned receipts retain numeric
Stats, fractional timestamps, and private exact identity authority. (#495)
Performance
- Use bounded signature searches for ZIP end-record admission and entry-count hints, including commented archives. Retain latest-valid-record selection, complete comment and ambiguity checks, conservative count fallbacks, and the dense-marker byte-scan fallback. (#507, #515)
- Reuse validated nonshared ASCII ZIP names and identical canonical keys while preserving shared-memory revalidation, Unicode Path CRCs, collisions, and decoder metadata checks. Public-loader gains were measured for UTF-8-flagged ASCII names on Node 22/24/26; shallow Unicode controls had a small cost. (#531)
- Reuse admitted TAR paths and USTAR components in the shared native/WASM parser, removing redundant allocation and empty-prefix validation. Raw field decoding, padding rejection, and PAX/GNU override checks remain. Linux measurements showed gains for Unicode prefixes, with a small cost on WASM PAX/GNU controls. (#517, #532)
- Skip unused default JSON decoding during sidecar ownership verification and release. Stale-policy parsing and explicit parser callbacks retain their behavior; gains are concentrated in large structured default payloads, and the measured mixed-workload custom-parser cost remains documented. (#533, lock ownership contract)
- Reduce repeated bigint metadata allocation in
Root.entries()andRoot.walk(), reuse normalized prefixes in standalone walkers, and reduce repeated filename and install-name scans. Preserve exact identity checks, lexical paths, callback timing, cancellation, Unicode limits, and encoded names. (#510, #518, #508) - Borrow bounded
Uint8Arraystream slices without payload copies, retaining backpressure and byte limits even with shadowed metadata properties. Reuse archive output-parent preparation while each publication still performs fresh parent and source admission. (#505, #499) - Reuse synchronous store JSON readers and resolve queue filesystem roots directly. Share filesystem admission and remove redundant ancestor, permission-report, and write-queue work while preserving per-call admission, durability checks, and same-path ordering. These changes include measured control tradeoffs, not a universal latency improvement. (#501, #529)
Platform support and validation
- Mark native POSIX beneath-open and duplicated descriptors close-on-exec atomically, preventing child-process inheritance. Preserve caller record locks during macOS ACL inspection, and share Windows secure-file handle ownership without changing borrowed descriptor lifetime or cursor position. (#504, #530)
- Prefer the running executable's ELF interpreter over installed compatibility-loader filenames when Linux process reports cannot identify libc. Resolve deep valid relative paths without spreading components into function arguments, retaining complete validation and containment checks. (#526, #523)
- Correct creation examples, advanced helper signatures, Root option references, homepage primitive names, and documentation of Windows payload writes versus native sidecar publication. Accept Corepack's native pnpm 12 launcher in package validation and correct Crabbox argument forwarding. (#528, #502)
- Strengthen error-code declaration checks and installed archive-consumer proof; repair parent-swap coverage and streamed-create diagnostics, retire superseded package smoke coverage, and measure portable codecs and Windows security fallbacks in native-off benchmarks. Isolate descriptor-close tests from inherited subprocess locks and native-loader tests from real diagnostic-report generation. (#528, #520, #529)
Published packages
| Package | Registry tarball | Verified integrity | Provenance |
|---|---|---|---|
| @openclaw/fs-safe-linux-x64-gnu@0.17.0 | tgz | sha512-ajnsE6avq53s0r5X+9vLN1e9MT0YSt2XJCKvxgk+f/Wh+W4FnInAQxNu19y3FC95SOBAiwYudPcjmevmOTmBRA== |
verified attestation |
| @openclaw/fs-safe-linux-x64-musl@0.17.0 | tgz | sha512-qRvuM1vX/Kj2ouGkyAg/ADXOZzR4lAbyNHfyx1NTo19e5WguwEBcvPfMW+HU2z3m19jFutvdz5IQI+cKL2pwUg== |
verified attestation |
| @openclaw/fs-safe-linux-arm64-gnu@0.17.0 | tgz | sha512-KrpaYk5c4aVfzkGzE1Kt7diG/2X6ByX0LYzBYQ2QKI7iOJfd/OleO6m9GDwABLxdxitMcPeUk1VRp3gMSqC5CQ== |
verified attestation |
| @openclaw/fs-safe-linux-arm64-musl@0.17.0 | tgz | sha512-jGKxoQWbLUV+3vW39PO4JYUwYwsBAVkub65/w7rY9qgKmf8neY/str5oSl4WDcEKs5RqDmJyxAeYrCvmZw5/yg== |
verified attestation |
| @openclaw/fs-safe-darwin-x64@0.17.0 | tgz | sha512-WxRPSXmz0iEoup7x4sfZX3GgHAOmbdmuTB/OZQpx+GGytCdXpzhIX81zg8ZrvbBXqxqnwe3gCAPJijkUO3PjFw== |
verified attestation |
| @openclaw/fs-safe-darwin-arm64@0.17.0 | tgz | sha512-2ySWv0Mz2n3aUIcfdHP+AEaB4wsyx7jblIF88Ebl9Ucx+Z5pEYPUTAlbBQhcrDmP5q+IfBJUKUacLqpOPLg1fQ== |
verified attestation |
| @openclaw/fs-safe-win32-x64-msvc@0.17.0 | tgz | sha512-Q82+jVSZWxOwakmodXWhAJF4oAxb4Ryj17lnO3w9bmowOTIHVdU+EWG7akTSNhocfGyz+ktzIXPA1o6UcHIJZA== |
verified attestation |
| @openclaw/fs-safe@0.17.0 | tgz | sha512-T2p3BM5Iz3CnFdK6XkdMowKsaxTgZG9J/FTIlrA3U/wGZCAqfaqHylFOQqMQqIU14i+8A1OM6Vt80ycu1zeqQw== |
verified attestation |
Release proof: GitHub Actions run.