@openclaw/fs-safe 0.16.0 → 0.17.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.
- package/CHANGELOG.md +48 -0
- package/README.md +8 -1
- package/dist/absolute-path.d.ts.map +1 -1
- package/dist/absolute-path.js +2 -8
- package/dist/advanced.d.ts +2 -0
- package/dist/advanced.d.ts.map +1 -1
- package/dist/advanced.js +2 -0
- package/dist/archive-deadline.d.ts.map +1 -1
- package/dist/archive-deadline.js +22 -23
- package/dist/archive-merge.d.ts +1 -0
- package/dist/archive-merge.d.ts.map +1 -1
- package/dist/archive-merge.js +4 -4
- package/dist/archive-native.d.ts +1 -0
- package/dist/archive-native.d.ts.map +1 -1
- package/dist/archive-native.js +1 -0
- package/dist/archive-options.d.ts +2 -0
- package/dist/archive-options.d.ts.map +1 -1
- package/dist/archive-parser.wasm +0 -0
- package/dist/archive-zip-count.d.ts.map +1 -1
- package/dist/archive-zip-count.js +21 -1
- package/dist/archive-zip-directory.d.ts.map +1 -1
- package/dist/archive-zip-directory.js +23 -1
- package/dist/archive-zip-loader.d.ts +2 -0
- package/dist/archive-zip-loader.d.ts.map +1 -1
- package/dist/archive-zip-loader.js +7 -0
- package/dist/archive-zip-names.d.ts.map +1 -1
- package/dist/archive-zip-names.js +7 -2
- package/dist/archive.d.ts.map +1 -1
- package/dist/archive.js +9 -3
- package/dist/byte-view.d.ts +3 -0
- package/dist/byte-view.d.ts.map +1 -0
- package/dist/byte-view.js +13 -0
- package/dist/creation-darwin.d.ts +0 -1
- package/dist/creation-darwin.d.ts.map +1 -1
- package/dist/creation-darwin.js +0 -9
- package/dist/directory-durability.d.ts +6 -6
- package/dist/directory-durability.d.ts.map +1 -1
- package/dist/directory-receipt.d.ts +2 -2
- package/dist/directory-receipt.d.ts.map +1 -1
- package/dist/directory-receipt.js +15 -19
- package/dist/file-cleanup.d.ts +1 -0
- package/dist/file-cleanup.d.ts.map +1 -1
- package/dist/file-cleanup.js +7 -4
- package/dist/file-contents.d.ts +6 -0
- package/dist/file-contents.d.ts.map +1 -0
- package/dist/file-contents.js +40 -0
- package/dist/file-hash.d.ts.map +1 -1
- package/dist/file-hash.js +16 -4
- package/dist/file-lock-sync-root-acquire.d.ts.map +1 -1
- package/dist/file-lock-sync-root-acquire.js +3 -0
- package/dist/file-lock-sync-root-held.d.ts +1 -2
- package/dist/file-lock-sync-root-held.d.ts.map +1 -1
- package/dist/file-lock-sync-root-held.js +7 -5
- package/dist/file-lock-sync-stale-admission.d.ts.map +1 -1
- package/dist/file-lock-sync-stale-admission.js +3 -0
- package/dist/file-lock-sync.d.ts.map +1 -1
- package/dist/file-lock-sync.js +8 -11
- package/dist/file-store.js +3 -3
- package/dist/guarded-mkdir.d.ts.map +1 -1
- package/dist/guarded-mkdir.js +6 -27
- package/dist/install-path.d.ts.map +1 -1
- package/dist/install-path.js +2 -5
- package/dist/json-durable-queue-ownership.d.ts.map +1 -1
- package/dist/json-durable-queue-ownership.js +2 -6
- package/dist/json-durable-queue-paths.d.ts.map +1 -1
- package/dist/json-durable-queue-paths.js +2 -24
- package/dist/json-durable-queue.d.ts.map +1 -1
- package/dist/json-durable-queue.js +10 -9
- package/dist/json.d.ts.map +1 -1
- package/dist/json.js +32 -75
- package/dist/local-roots.d.ts.map +1 -1
- package/dist/local-roots.js +19 -21
- package/dist/move-path-cleanup.d.ts +5 -19
- package/dist/move-path-cleanup.d.ts.map +1 -1
- package/dist/move-path-cleanup.js +57 -21
- package/dist/move-path.d.ts.map +1 -1
- package/dist/move-path.js +62 -39
- package/dist/native-staged-file.d.ts +2 -1
- package/dist/native-staged-file.d.ts.map +1 -1
- package/dist/native-staged-file.js +8 -5
- package/dist/native.js +2 -2
- package/dist/opened-realpath.d.ts.map +1 -1
- package/dist/opened-realpath.js +11 -2
- package/dist/path.d.ts.map +1 -1
- package/dist/path.js +2 -1
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js +3 -17
- package/dist/pinned-write-input.d.ts.map +1 -1
- package/dist/pinned-write-input.js +11 -1
- package/dist/pinned-write-mode.d.ts +3 -3
- package/dist/pinned-write-mode.d.ts.map +1 -1
- package/dist/pinned-write-mode.js +15 -8
- package/dist/pinned-write-staged.d.ts.map +1 -1
- package/dist/pinned-write-staged.js +10 -11
- package/dist/pinned-write.d.ts.map +1 -1
- package/dist/pinned-write.js +17 -13
- package/dist/publish-file.d.ts +2 -2
- package/dist/publish-file.d.ts.map +1 -1
- package/dist/publish-file.js +56 -96
- package/dist/regular-file.d.ts.map +1 -1
- package/dist/regular-file.js +35 -44
- package/dist/replace-file-copy-fallback.d.ts.map +1 -1
- package/dist/replace-file-copy-fallback.js +28 -26
- package/dist/replace-file-copy-source.d.ts.map +1 -1
- package/dist/replace-file-copy-source.js +13 -22
- package/dist/replace-file-descriptor.d.ts.map +1 -1
- package/dist/replace-file-descriptor.js +10 -16
- package/dist/replace-file-temp-owner.js +6 -6
- package/dist/replace-file.d.ts.map +1 -1
- package/dist/replace-file.js +9 -13
- package/dist/root-directory-list.d.ts.map +1 -1
- package/dist/root-directory-list.js +20 -3
- package/dist/root-file-final-admission.d.ts +1 -1
- package/dist/root-file-final-admission.d.ts.map +1 -1
- package/dist/root-file-final-admission.js +5 -2
- package/dist/root-file.d.ts.map +1 -1
- package/dist/root-file.js +3 -2
- package/dist/root-impl.d.ts.map +1 -1
- package/dist/root-impl.js +50 -20
- package/dist/root-move-noreplace.d.ts +2 -0
- package/dist/root-move-noreplace.d.ts.map +1 -1
- package/dist/root-move-noreplace.js +2 -2
- package/dist/root-read-admission.d.ts.map +1 -1
- package/dist/root-read-admission.js +7 -2
- package/dist/root-remove.d.ts.map +1 -1
- package/dist/root-remove.js +15 -1
- package/dist/sidecar-lock-acquire.d.ts.map +1 -1
- package/dist/sidecar-lock-acquire.js +4 -6
- package/dist/sidecar-lock-handle.d.ts +3 -0
- package/dist/sidecar-lock-handle.d.ts.map +1 -1
- package/dist/sidecar-lock-handle.js +6 -0
- package/dist/sidecar-lock-reclaim.d.ts +1 -1
- package/dist/sidecar-lock-reclaim.d.ts.map +1 -1
- package/dist/sidecar-lock-reclaim.js +11 -8
- package/dist/sidecar-lock.d.ts.map +1 -1
- package/dist/sidecar-lock.js +3 -5
- package/dist/staged-directory.d.ts +2 -2
- package/dist/staged-directory.d.ts.map +1 -1
- package/dist/strict-file-identity.d.ts +1 -1
- package/dist/strict-file-identity.d.ts.map +1 -1
- package/dist/strict-file-identity.js +9 -9
- package/dist/symlink-parents.d.ts.map +1 -1
- package/dist/symlink-parents.js +2 -27
- package/dist/temp-workspace-owner.js +4 -4
- package/dist/unicode-path.d.ts.map +1 -1
- package/dist/unicode-path.js +3 -0
- package/dist/walk.d.ts.map +1 -1
- package/dist/walk.js +4 -2
- package/dist/write-file-handle.d.ts +7 -0
- package/dist/write-file-handle.d.ts.map +1 -1
- package/dist/write-file-handle.js +23 -0
- package/dist/write-open-flags.d.ts.map +1 -1
- package/dist/write-open-flags.js +1 -8
- package/dist/write-queue.d.ts.map +1 -1
- package/dist/write-queue.js +1 -4
- package/docs/advanced.md +68 -1
- package/docs/archive.md +41 -2
- package/docs/atomic.md +29 -5
- package/docs/contributing.md +4 -0
- package/docs/creation.md +8 -4
- package/docs/durability.md +35 -0
- package/docs/file-contents.md +68 -0
- package/docs/json.md +5 -4
- package/docs/local-roots.md +2 -0
- package/docs/mutation-policy-proof.md +5 -3
- package/docs/native.md +9 -8
- package/docs/path.md +4 -4
- package/docs/public-api.md +5 -0
- package/docs/quickstart.md +1 -1
- package/docs/reading.md +2 -2
- package/docs/regular-file.md +3 -0
- package/docs/root.md +9 -0
- package/docs/sidecar-lock.md +9 -1
- package/docs/staged-file.md +4 -3
- package/docs/store.md +3 -1
- package/docs/temp.md +4 -1
- package/docs/types.md +18 -2
- package/docs/walk.md +7 -0
- package/docs/writing.md +9 -2
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,54 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.17.0 - 2026-09-20
|
|
6
|
+
|
|
7
|
+
### Highlights
|
|
8
|
+
|
|
9
|
+
- **Complete writes and exact comparison for borrowed files:** add `writeFileWindowFully()` and `sameFileContentsSync()` 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](https://github.com/openclaw/fs-safe/pull/524))
|
|
10
|
+
- **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](https://github.com/openclaw/fs-safe/pull/516), [#521](https://github.com/openclaw/fs-safe/pull/521), [#522](https://github.com/openclaw/fs-safe/pull/522))
|
|
11
|
+
- **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](https://github.com/openclaw/fs-safe/pull/498), [#500](https://github.com/openclaw/fs-safe/pull/500), [#503](https://github.com/openclaw/fs-safe/pull/503), [#497](https://github.com/openclaw/fs-safe/pull/497), [#527](https://github.com/openclaw/fs-safe/pull/527))
|
|
12
|
+
- **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.
|
|
13
|
+
- **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](https://github.com/openclaw/fs-safe/pull/523), [#526](https://github.com/openclaw/fs-safe/pull/526))
|
|
14
|
+
|
|
15
|
+
### Compatibility and upgrade notes
|
|
16
|
+
|
|
17
|
+
- `entryUmask` defaults to `0`, preserving existing extraction modes. It applies after `entryModes` to 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](https://github.com/openclaw/fs-safe/blob/v0.17.0/docs/archive.md).
|
|
18
|
+
- 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; `null` advances the current cursor. Comparison preserves both cursors and is not a snapshot of concurrently modified files. See [borrowed-handle writes](https://github.com/openclaw/fs-safe/blob/v0.17.0/docs/advanced.md#borrowed-handle-writes) and [exact comparison](https://github.com/openclaw/fs-safe/blob/v0.17.0/docs/file-contents.md).
|
|
19
|
+
- 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 report `ESTALE` after publishing the destination while preserving changed source entries; it is not a transaction or rollback guarantee. ([#512](https://github.com/openclaw/fs-safe/pull/512), [#527](https://github.com/openclaw/fs-safe/pull/527))
|
|
20
|
+
- 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](https://github.com/openclaw/fs-safe/pull/525))
|
|
21
|
+
- Synchronous lock stale-policy callbacks must return synchronously: Promise or thenable results now reject with `TypeError` before deletion. If a protected callback and release both fail, `withFileLock()` and `withFileLockSync()` retain both through `SuppressedError`, with the release failure primary. ([#496](https://github.com/openclaw/fs-safe/pull/496))
|
|
22
|
+
|
|
23
|
+
### Security and correctness
|
|
24
|
+
|
|
25
|
+
- 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](https://github.com/openclaw/fs-safe/pull/498), [#513](https://github.com/openclaw/fs-safe/pull/513))
|
|
26
|
+
- 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](https://github.com/openclaw/fs-safe/pull/498), [#503](https://github.com/openclaw/fs-safe/pull/503))
|
|
27
|
+
- 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](https://github.com/openclaw/fs-safe/pull/500), [#509](https://github.com/openclaw/fs-safe/pull/509))
|
|
28
|
+
- 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](https://github.com/openclaw/fs-safe/pull/497), [#512](https://github.com/openclaw/fs-safe/pull/512), [#527](https://github.com/openclaw/fs-safe/pull/527))
|
|
29
|
+
- 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](https://github.com/openclaw/fs-safe/pull/506))
|
|
30
|
+
- 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](https://github.com/openclaw/fs-safe/pull/521), [#522](https://github.com/openclaw/fs-safe/pull/522))
|
|
31
|
+
- 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](https://github.com/openclaw/fs-safe/pull/496))
|
|
32
|
+
- 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](https://github.com/openclaw/fs-safe/pull/512), [#514](https://github.com/openclaw/fs-safe/pull/514), [#529](https://github.com/openclaw/fs-safe/pull/529))
|
|
33
|
+
- 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](https://github.com/openclaw/fs-safe/pull/519))
|
|
34
|
+
- 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](https://github.com/openclaw/fs-safe/pull/495))
|
|
35
|
+
|
|
36
|
+
### Performance
|
|
37
|
+
|
|
38
|
+
- 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](https://github.com/openclaw/fs-safe/pull/507), [#515](https://github.com/openclaw/fs-safe/pull/515))
|
|
39
|
+
- 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](https://github.com/openclaw/fs-safe/pull/531))
|
|
40
|
+
- 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](https://github.com/openclaw/fs-safe/pull/517), [#532](https://github.com/openclaw/fs-safe/pull/532))
|
|
41
|
+
- 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](https://github.com/openclaw/fs-safe/pull/533), [lock ownership contract](https://github.com/openclaw/fs-safe/blob/v0.17.0/docs/sidecar-lock.md))
|
|
42
|
+
- Reduce repeated bigint metadata allocation in `Root.entries()` and `Root.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](https://github.com/openclaw/fs-safe/pull/510), [#518](https://github.com/openclaw/fs-safe/pull/518), [#508](https://github.com/openclaw/fs-safe/pull/508))
|
|
43
|
+
- Borrow bounded `Uint8Array` stream 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](https://github.com/openclaw/fs-safe/pull/505), [#499](https://github.com/openclaw/fs-safe/pull/499))
|
|
44
|
+
- 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](https://github.com/openclaw/fs-safe/pull/501), [#529](https://github.com/openclaw/fs-safe/pull/529))
|
|
45
|
+
|
|
46
|
+
### Platform support and validation
|
|
47
|
+
|
|
48
|
+
- 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](https://github.com/openclaw/fs-safe/pull/504), [#530](https://github.com/openclaw/fs-safe/pull/530))
|
|
49
|
+
- 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](https://github.com/openclaw/fs-safe/pull/526), [#523](https://github.com/openclaw/fs-safe/pull/523))
|
|
50
|
+
- 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](https://github.com/openclaw/fs-safe/pull/528), [#502](https://github.com/openclaw/fs-safe/pull/502))
|
|
51
|
+
- 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](https://github.com/openclaw/fs-safe/pull/528), [#520](https://github.com/openclaw/fs-safe/pull/520), [#529](https://github.com/openclaw/fs-safe/pull/529))
|
|
52
|
+
|
|
5
53
|
## 0.16.0 - 2026-09-19
|
|
6
54
|
|
|
7
55
|
### Highlights
|
package/README.md
CHANGED
|
@@ -277,7 +277,7 @@ contract. Low-level helpers that OpenClaw needs to compose higher-level APIs are
|
|
|
277
277
|
| `@openclaw/fs-safe/walk` | budget-bounded directory walking with symlink policy, filters, and truncation accounting; not root-bounded |
|
|
278
278
|
| `@openclaw/fs-safe/copy` | directory copying with `clone: "auto"`, `"always"`, or `"never"`; native APFS, Btrfs, ReFS, XFS, and ZFS cloning, portable byte copying, and clone metadata; see [directory copying](docs/copy.md) |
|
|
279
279
|
| `@openclaw/fs-safe/archive` | policy-driven ZIP/TAR extraction, clamp/filter policy, metadata/path-depth limits, gzip/zstd/bzip2 support, and bounded entry reads |
|
|
280
|
-
| `@openclaw/fs-safe/advanced` | lower-level composition helpers such as path scopes, root-file open, bounded descriptor reads, [borrowed-handle and descriptor copying](docs/copy.md#borrowed-filehandle-transfers), [exact directory identity](docs/directory-identity.md), [case probing](docs/path-case.md), [suffix-alias probing](docs/path-suffix-aliases.md), [in-place writes](docs/in-place-write.md), [versioned install-ID encoding](docs/install-path.md#safepathsegmenthashedv2), filename sanitizing, temp-file targets, sibling-temp writes, local-root readers, regular-file helpers, `pathExists`, and `withTimeout`; less stable than focused public subpaths |
|
|
280
|
+
| `@openclaw/fs-safe/advanced` | lower-level composition helpers such as path scopes, root-file open, bounded descriptor reads, [borrowed-handle and descriptor copying](docs/copy.md#borrowed-filehandle-transfers), [complete byte-window writes](docs/advanced.md#borrowed-handle-writes), [exact directory identity](docs/directory-identity.md), [case probing](docs/path-case.md), [suffix-alias probing](docs/path-suffix-aliases.md), [in-place writes](docs/in-place-write.md), [versioned install-ID encoding](docs/install-path.md#safepathsegmenthashedv2), filename sanitizing, temp-file targets, sibling-temp writes, local-root readers, regular-file helpers, `pathExists`, and `withTimeout`; less stable than focused public subpaths |
|
|
281
281
|
| `@openclaw/fs-safe/errors` | `FsSafeError`, closed codes/categories, causes, and operation-specific details receipts |
|
|
282
282
|
| `@openclaw/fs-safe/types` | shared types: `DirEntry`, `PathStat`, … |
|
|
283
283
|
| `@openclaw/fs-safe/test-hooks` | hooks the test suite uses to inject races; registration requires `NODE_ENV=test` or `VITEST=true` |
|
|
@@ -476,6 +476,13 @@ await fs.promises.writeFile(target.path, bytes);
|
|
|
476
476
|
const checksumPath = target.file("payload.sha256");
|
|
477
477
|
```
|
|
478
478
|
|
|
479
|
+
## Exact file comparison
|
|
480
|
+
|
|
481
|
+
For exact comparison of already-open files, use
|
|
482
|
+
[`sameFileContentsSync()`](docs/file-contents.md) from `advanced`. It compares
|
|
483
|
+
bytes through both EOFs with bounded memory and preserves the borrowed
|
|
484
|
+
descriptors' positions and ownership.
|
|
485
|
+
|
|
479
486
|
## Secure absolute file reads
|
|
480
487
|
|
|
481
488
|
Use `readSecureFile()` when the caller gives you an absolute credential path
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"absolute-path.d.ts","sourceRoot":"","sources":["../src/absolute-path.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAUhE,MAAM,MAAM,yBAAyB,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAU5D,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,oBAAoB,GAAG;IAChE,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,8BAA8B,GAAG;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,6BAA6B,GACrC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC1B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,CAAC;AAmL7D,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAchE;AAED,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"absolute-path.d.ts","sourceRoot":"","sources":["../src/absolute-path.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAUhE,MAAM,MAAM,yBAAyB,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAU5D,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,oBAAoB,GAAG;IAChE,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,8BAA8B,GAAG;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,6BAA6B,GACrC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC1B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,CAAC;AAmL7D,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAchE;AAED,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAmBnF;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,8BAAmC,GAC3C,OAAO,CAAC,6BAA6B,CAAC,CA+ExC;AAED,wBAAsB,iCAAiC,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBzF;AAED,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,yBAAyB,CAAA;CAAO,GACrD,OAAO,CAAC,oBAAoB,CAAC,CAmB/B;AAED,wBAAsB,2BAA2B,CAC/C,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,yBAAyB,CAAA;CAAO,GACrD,OAAO,CAAC,4BAA4B,CAAC,CA2BvC"}
|
package/dist/absolute-path.js
CHANGED
|
@@ -155,19 +155,13 @@ export function assertAbsolutePathInput(filePath) {
|
|
|
155
155
|
return normalized;
|
|
156
156
|
}
|
|
157
157
|
export async function findExistingAncestor(filePath) {
|
|
158
|
-
assertNoWindowsPathAlias(filePath);
|
|
159
|
-
return (await findExistingAncestorWithStat(filePath))?.path ?? null;
|
|
160
|
-
}
|
|
161
|
-
async function findExistingAncestorWithStat(filePath) {
|
|
162
158
|
assertNoWindowsPathAlias(filePath);
|
|
163
159
|
let current = resolvePathPreservingWindowsRoot(filePath);
|
|
164
160
|
assertNoWindowsPathAlias(current);
|
|
165
161
|
while (true) {
|
|
166
162
|
try {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
stat: fsSync.lstatSync(pathForWindowsFilesystem(current)),
|
|
170
|
-
};
|
|
163
|
+
fsSync.lstatSync(pathForWindowsFilesystem(current));
|
|
164
|
+
return current;
|
|
171
165
|
}
|
|
172
166
|
catch (err) {
|
|
173
167
|
if (err.code !== "ENOENT") {
|
package/dist/advanced.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { createAsyncLock } from "./async-lock.js";
|
|
2
2
|
export { createDirectory, createDirectorySync, createFileSync, type CreateDirectoryOptions, type CreateFileOptions, type OwnedFileDescriptorSync, } from "./create.js";
|
|
3
3
|
export { copyFileHandle, copyFileDescriptorSync, type CopyFileHandleOptions } from "./file-handle-transfer.js";
|
|
4
|
+
export { sameFileContentsSync, type SameFileContentsOptions } from "./file-contents.js";
|
|
4
5
|
export { overwriteFileHandle, type OverwriteFileHandleOptions } from "./overwrite-file-handle.js";
|
|
5
6
|
export { probePathCaseInsensitiveSync, type ProbePathCaseOptions } from "./path-case.js";
|
|
6
7
|
export { resolvePathPrefixSync, type ResolvedPathPrefix } from "./path-prefix.js";
|
|
@@ -9,6 +10,7 @@ export { readDirectoryIdentity, assertDirectoryIdentitySync, type DirectoryIdent
|
|
|
9
10
|
export { stageFileInDirectory, type StagedFile, type StagedFileReceipt, type PublishedFileReceipt, type StagedFilePublication, type StagedFileCleanupReceipt, type StagedFileFailureDetails, } from "./native-staged-file.js";
|
|
10
11
|
export { readFileDescriptorBounded, readFileDescriptorBoundedSync, readFileHandleBounded, } from "./bounded-read.js";
|
|
11
12
|
export { readFileWindowFully, readFileWindowFullySync, type ReadFileWindowOptions, } from "./positional-read.js";
|
|
13
|
+
export { writeFileWindowFully, type WriteFileWindowOptions } from "./write-file-handle.js";
|
|
12
14
|
export { assertNoUnsafeDeviceReadPath, isUnsafeDeviceReadPath, matchUnsafeDeviceReadPath, type UnsafeDeviceReadPathMatch, type UnsafeDeviceReadPathOptions, type UnsafeDeviceReadPathReason, } from "./device-path.js";
|
|
13
15
|
export { assertAbsolutePathInput, canonicalPathFromExistingAncestor, ensureAbsoluteDirectory, findExistingAncestor, resolveAbsolutePathForRead, resolveAbsolutePathForWrite, type AbsolutePathSymlinkPolicy, type EnsureAbsoluteDirectoryOptions, type EnsureAbsoluteDirectoryResult, type ResolvedAbsolutePath, type ResolvedWritableAbsolutePath, } from "./absolute-path.js";
|
|
14
16
|
export { sameFileIdentity, type FileIdentityStat } from "./file-identity.js";
|
package/dist/advanced.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"advanced.d.ts","sourceRoot":"","sources":["../src/advanced.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"advanced.d.ts","sourceRoot":"","sources":["../src/advanced.ts"],"names":[],"mappings":"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"}
|
package/dist/advanced.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
export { createAsyncLock } from "./async-lock.js";
|
|
5
5
|
export { createDirectory, createDirectorySync, createFileSync, } from "./create.js";
|
|
6
6
|
export { copyFileHandle, copyFileDescriptorSync } from "./file-handle-transfer.js";
|
|
7
|
+
export { sameFileContentsSync } from "./file-contents.js";
|
|
7
8
|
export { overwriteFileHandle } from "./overwrite-file-handle.js";
|
|
8
9
|
export { probePathCaseInsensitiveSync } from "./path-case.js";
|
|
9
10
|
export { resolvePathPrefixSync } from "./path-prefix.js";
|
|
@@ -12,6 +13,7 @@ export { readDirectoryIdentity, assertDirectoryIdentitySync, } from "./directory
|
|
|
12
13
|
export { stageFileInDirectory, } from "./native-staged-file.js";
|
|
13
14
|
export { readFileDescriptorBounded, readFileDescriptorBoundedSync, readFileHandleBounded, } from "./bounded-read.js";
|
|
14
15
|
export { readFileWindowFully, readFileWindowFullySync, } from "./positional-read.js";
|
|
16
|
+
export { writeFileWindowFully } from "./write-file-handle.js";
|
|
15
17
|
export { assertNoUnsafeDeviceReadPath, isUnsafeDeviceReadPath, matchUnsafeDeviceReadPath, } from "./device-path.js";
|
|
16
18
|
export { assertAbsolutePathInput, canonicalPathFromExistingAncestor, ensureAbsoluteDirectory, findExistingAncestor, resolveAbsolutePathForRead, resolveAbsolutePathForWrite, } from "./absolute-path.js";
|
|
17
19
|
export { sameFileIdentity } from "./file-identity.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"archive-deadline.d.ts","sourceRoot":"","sources":["../src/archive-deadline.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,sBAAsB,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IACjE,2BAA2B,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,wBAAsB,gCAAgC,CAAC,CAAC,EACtD,QAAQ,EAAE,kBAAkB,GAAG,SAAS,EACxC,GAAG,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACpB,OAAO,CAAC,CAAC,CAAC,CAEZ;AAWD,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,kBAAkB,GAC3B,OAAO,CAST;AAED,wBAAsB,eAAe,CAAC,CAAC,EACrC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,QAAQ,EAAE,kBAAkB,GAC3B,OAAO,CAAC,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"archive-deadline.d.ts","sourceRoot":"","sources":["../src/archive-deadline.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,sBAAsB,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IACjE,2BAA2B,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,wBAAsB,gCAAgC,CAAC,CAAC,EACtD,QAAQ,EAAE,kBAAkB,GAAG,SAAS,EACxC,GAAG,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACpB,OAAO,CAAC,CAAC,CAAC,CAEZ;AAWD,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,kBAAkB,GAC3B,OAAO,CAST;AAED,wBAAsB,eAAe,CAAC,CAAC,EACrC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,QAAQ,EAAE,kBAAkB,GAC3B,OAAO,CAAC,CAAC,CAAC,CAoBZ;AA4CD,wBAAsB,sBAAsB,CAAC,CAAC,EAC5C,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,OAAO,CAAC,CAAC,CAAC,GAChD,OAAO,CAAC,CAAC,CAAC,CAiBZ"}
|
package/dist/archive-deadline.js
CHANGED
|
@@ -18,11 +18,13 @@ export function createPipelineTimeoutError(err, deadline) {
|
|
|
18
18
|
return err;
|
|
19
19
|
}
|
|
20
20
|
export async function waitForDeadline(promise, deadline) {
|
|
21
|
+
// An elapsed synchronous check must not orphan a later operation rejection.
|
|
22
|
+
void promise.catch(() => undefined);
|
|
21
23
|
deadline.check();
|
|
22
24
|
if (deadline.signal.aborted) {
|
|
23
25
|
throw deadlineReason(deadline);
|
|
24
26
|
}
|
|
25
|
-
|
|
27
|
+
const result = await Promise.race([
|
|
26
28
|
promise,
|
|
27
29
|
new Promise((_, reject) => {
|
|
28
30
|
const abort = () => reject(deadlineReason(deadline));
|
|
@@ -33,21 +35,26 @@ export async function waitForDeadline(promise, deadline) {
|
|
|
33
35
|
promise.then(cleanup, cleanup);
|
|
34
36
|
}),
|
|
35
37
|
]);
|
|
38
|
+
deadline.check();
|
|
39
|
+
return result;
|
|
36
40
|
}
|
|
37
41
|
function createDestinationMutationOwner(check) {
|
|
38
42
|
const active = new Set();
|
|
39
43
|
return {
|
|
40
44
|
ownDestinationMutation: async (run) => {
|
|
41
45
|
check();
|
|
42
|
-
const operation = Promise.resolve().then(run);
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
const operation = Promise.resolve().then(() => { check(); return run(); });
|
|
47
|
+
active.add(operation);
|
|
48
|
+
try {
|
|
49
|
+
return await operation;
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
active.delete(operation);
|
|
53
|
+
}
|
|
47
54
|
},
|
|
48
55
|
waitForDestinationMutations: async () => {
|
|
49
56
|
while (active.size > 0) {
|
|
50
|
-
await Promise.
|
|
57
|
+
await Promise.allSettled(active);
|
|
51
58
|
}
|
|
52
59
|
},
|
|
53
60
|
};
|
|
@@ -55,35 +62,27 @@ function createDestinationMutationOwner(check) {
|
|
|
55
62
|
function createExtractionDeadline(timeoutMs, label) {
|
|
56
63
|
const controller = new AbortController();
|
|
57
64
|
const timeoutError = new Error(`${label} timed out after ${timeoutMs}ms`);
|
|
65
|
+
const enabled = Number.isFinite(timeoutMs) && timeoutMs > 0;
|
|
66
|
+
const startedAt = enabled ? performance.now() : 0;
|
|
58
67
|
const check = () => {
|
|
68
|
+
if (enabled && !controller.signal.aborted && performance.now() - startedAt >= timeoutMs) {
|
|
69
|
+
controller.abort(timeoutError);
|
|
70
|
+
}
|
|
59
71
|
if (controller.signal.aborted) {
|
|
60
72
|
throw signalReason(controller.signal, timeoutError);
|
|
61
73
|
}
|
|
62
74
|
};
|
|
63
|
-
const mutationOwner = createDestinationMutationOwner(check);
|
|
64
|
-
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
65
|
-
return {
|
|
66
|
-
signal: controller.signal,
|
|
67
|
-
check,
|
|
68
|
-
...mutationOwner,
|
|
69
|
-
dispose: () => undefined,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
const cancelTimeout = scheduleTimeout(() => {
|
|
73
|
-
controller.abort(timeoutError);
|
|
74
|
-
}, timeoutMs);
|
|
75
75
|
return {
|
|
76
76
|
signal: controller.signal,
|
|
77
77
|
check,
|
|
78
|
-
...
|
|
79
|
-
dispose:
|
|
78
|
+
...createDestinationMutationOwner(check),
|
|
79
|
+
dispose: enabled ? scheduleTimeout(() => controller.abort(timeoutError), timeoutMs) : () => undefined,
|
|
80
80
|
};
|
|
81
81
|
}
|
|
82
82
|
export async function withExtractionDeadline(timeoutMs, label, run) {
|
|
83
83
|
const deadline = createExtractionDeadline(timeoutMs, label);
|
|
84
|
-
const operation = Promise.resolve().then(
|
|
84
|
+
const operation = Promise.resolve().then(() => { deadline.check(); return run(deadline); });
|
|
85
85
|
try {
|
|
86
|
-
deadline.check();
|
|
87
86
|
try {
|
|
88
87
|
return await waitForDeadline(operation, deadline);
|
|
89
88
|
}
|
package/dist/archive-merge.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ type GuardedMergeParams = Pick<MergeParams, "sourceDir" | "deadline"> & {
|
|
|
17
17
|
export declare function mergePlannedArchiveIntoDestination(params: GuardedMergeParams & {
|
|
18
18
|
entries: readonly ArchivePublicationEntry[];
|
|
19
19
|
durable?: boolean;
|
|
20
|
+
entryUmask?: number;
|
|
20
21
|
}): Promise<void>;
|
|
21
22
|
export declare function mergeExtractedTreeIntoDestination(params: MergeParams): Promise<void>;
|
|
22
23
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"archive-merge.d.ts","sourceRoot":"","sources":["../src/archive-merge.ts"],"names":[],"mappings":"AAGA,OAAO,EAAoC,KAAK,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAClG,OAAO,EAIL,KAAK,qBAAqB,EAC3B,MAAM,sBAAsB,CAAC;AAiB9B,MAAM,MAAM,uBAAuB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AACjG,KAAK,WAAW,GAAG;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B,CAAC;AACF,KAAK,kBAAkB,GAAG,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,UAAU,CAAC,GAAG;IACtE,gBAAgB,EAAE,qBAAqB,CAAC;CACzC,CAAC;AAEF,wBAAsB,kCAAkC,CACtD,MAAM,EAAE,kBAAkB,GAAG;IAAE,OAAO,EAAE,SAAS,uBAAuB,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"archive-merge.d.ts","sourceRoot":"","sources":["../src/archive-merge.ts"],"names":[],"mappings":"AAGA,OAAO,EAAoC,KAAK,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAClG,OAAO,EAIL,KAAK,qBAAqB,EAC3B,MAAM,sBAAsB,CAAC;AAiB9B,MAAM,MAAM,uBAAuB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AACjG,KAAK,WAAW,GAAG;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B,CAAC;AACF,KAAK,kBAAkB,GAAG,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,UAAU,CAAC,GAAG;IACtE,gBAAgB,EAAE,qBAAqB,CAAC;CACzC,CAAC;AAEF,wBAAsB,kCAAkC,CACtD,MAAM,EAAE,kBAAkB,GAAG;IAAE,OAAO,EAAE,SAAS,uBAAuB,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GACnH,OAAO,CAAC,IAAI,CAAC,CAGf;AAED,wBAAsB,iCAAiC,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAS1F"}
|
package/dist/archive-merge.js
CHANGED
|
@@ -20,7 +20,7 @@ import { assertNoWindowsPathAlias } from "./windows-path-alias.js";
|
|
|
20
20
|
import { inspectFileIdentitySync } from "./strict-file-identity.js";
|
|
21
21
|
export async function mergePlannedArchiveIntoDestination(params) {
|
|
22
22
|
assertMergePathInputs(params);
|
|
23
|
-
await mergeTree(params, params.entries, params.durable === true);
|
|
23
|
+
await mergeTree(params, params.entries, params.durable === true, params.entryUmask);
|
|
24
24
|
}
|
|
25
25
|
export async function mergeExtractedTreeIntoDestination(params) {
|
|
26
26
|
const sourceDir = params.sourceDir;
|
|
@@ -37,7 +37,7 @@ function assertMergePathInputs(params) {
|
|
|
37
37
|
assertNoWindowsPathAlias(params.destinationGuard.dir);
|
|
38
38
|
assertNoWindowsPathAlias(params.destinationGuard.realPath);
|
|
39
39
|
}
|
|
40
|
-
async function mergeTree(params, publication, durable = true) {
|
|
40
|
+
async function mergeTree(params, publication, durable = true, entryUmask = 0) {
|
|
41
41
|
const publishedFiles = [];
|
|
42
42
|
const publishedDirectories = [];
|
|
43
43
|
const check = () => params.deadline?.check();
|
|
@@ -132,7 +132,7 @@ async function mergeTree(params, publication, durable = true) {
|
|
|
132
132
|
if (plan && ((planned && planned.kind !== kind) || (!planned && kind === "file"))) {
|
|
133
133
|
throw new FsSafeError("path-mismatch", "archive staging disagrees with the admitted publication plan");
|
|
134
134
|
}
|
|
135
|
-
let mode = plan ? planned?.mode ?? 0o755 : Number(sourceStat.mode & 511n);
|
|
135
|
+
let mode = plan ? (planned?.mode ?? 0o755) & ~entryUmask : Number(sourceStat.mode & 511n);
|
|
136
136
|
await preparePrivateArchiveOutputPath({
|
|
137
137
|
destinationDir, destinationRealDir, deadline: params.deadline,
|
|
138
138
|
relPath, outPath: destinationPath, originalPath, isDirectory: kind === "directory",
|
|
@@ -205,7 +205,7 @@ async function mergeTree(params, publication, durable = true) {
|
|
|
205
205
|
await assertGuards();
|
|
206
206
|
try {
|
|
207
207
|
const options = {
|
|
208
|
-
mkdir:
|
|
208
|
+
mkdir: false, mode, durable: publication ? false : true,
|
|
209
209
|
[onCopySourceAdmission]: (identity, realPath) => {
|
|
210
210
|
assertSourceDirectory(sourceGuard, true);
|
|
211
211
|
assertSourceFrontier();
|
package/dist/archive-native.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export declare function extractNativeArchive(params: {
|
|
|
15
15
|
tarLimits: TarMeterLimits;
|
|
16
16
|
deadline: ExtractionDeadline;
|
|
17
17
|
entryModes?: ExtractArchiveOptions["entryModes"];
|
|
18
|
+
entryUmask?: number;
|
|
18
19
|
entryFilter?: ExtractArchiveOptions["entryFilter"];
|
|
19
20
|
onFiltered?: ExtractArchiveOptions["onFiltered"];
|
|
20
21
|
}): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"archive-native.d.ts","sourceRoot":"","sources":["../src/archive-native.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAEL,KAAK,4BAA4B,EACjC,KAAK,cAAc,EACpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAOlE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAYnE;AAED,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IACjD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,aAAa,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,WAAW,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,4BAA4B,CAAC;IACrC,SAAS,EAAE,cAAc,CAAC;IAC1B,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,UAAU,CAAC,EAAE,qBAAqB,CAAC,YAAY,CAAC,CAAC;IACjD,WAAW,CAAC,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAC;IACnD,UAAU,CAAC,EAAE,qBAAqB,CAAC,YAAY,CAAC,CAAC;CAClD,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"archive-native.d.ts","sourceRoot":"","sources":["../src/archive-native.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAEL,KAAK,4BAA4B,EACjC,KAAK,cAAc,EACpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAOlE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAYnE;AAED,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IACjD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,aAAa,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,WAAW,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,4BAA4B,CAAC;IACrC,SAAS,EAAE,cAAc,CAAC;IAC1B,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,UAAU,CAAC,EAAE,qBAAqB,CAAC,YAAY,CAAC,CAAC;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAC;IACnD,UAAU,CAAC,EAAE,qBAAqB,CAAC,YAAY,CAAC,CAAC;CAClD,GAAG,OAAO,CAAC,IAAI,CAAC,CAmFhB"}
|
package/dist/archive-native.js
CHANGED
|
@@ -17,6 +17,8 @@ export type ExtractArchiveOptions = {
|
|
|
17
17
|
limits?: ArchiveExtractLimits;
|
|
18
18
|
logger?: ArchiveLogger;
|
|
19
19
|
entryModes?: ArchiveEntryModePolicy;
|
|
20
|
+
/** Remove these rwx bits from final entry modes. Defaults to zero. */
|
|
21
|
+
entryUmask?: number;
|
|
20
22
|
entryFilter?: ArchiveEntryFilter;
|
|
21
23
|
onFiltered?: ArchiveFilteredEntryPolicy;
|
|
22
24
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"archive-options.d.ts","sourceRoot":"","sources":["../src/archive-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,KAAK,EACV,kBAAkB,EAClB,sBAAsB,EACtB,0BAA0B,EAC3B,MAAM,qBAAqB,CAAC;AAE7B,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,UAAU,CAAC,EAAE,sBAAsB,CAAC;IACpC,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,UAAU,CAAC,EAAE,0BAA0B,CAAC;CACzC,CAAC"}
|
|
1
|
+
{"version":3,"file":"archive-options.d.ts","sourceRoot":"","sources":["../src/archive-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,KAAK,EACV,kBAAkB,EAClB,sBAAsB,EACtB,0BAA0B,EAC3B,MAAM,qBAAqB,CAAC;AAE7B,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,UAAU,CAAC,EAAE,sBAAsB,CAAC;IACpC,sEAAsE;IACtE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,UAAU,CAAC,EAAE,0BAA0B,CAAC;CACzC,CAAC"}
|
package/dist/archive-parser.wasm
CHANGED
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"archive-zip-count.d.ts","sourceRoot":"","sources":["../src/archive-zip-count.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"archive-zip-count.d.ts","sourceRoot":"","sources":["../src/archive-zip-count.ts"],"names":[],"mappings":"AA8LA,wBAAgB,iCAAiC,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,IAAI,CAU5F"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Conservative public count hint; strict admission must not rely on its fallback.
|
|
2
2
|
const ZIP_EOCD_SIGNATURE = 0x06054b50;
|
|
3
|
+
const ZIP_EOCD_SIGNATURE_BYTES = Buffer.from([0x50, 0x4b, 0x05, 0x06]);
|
|
3
4
|
const ZIP64_EOCD_SIGNATURE = 0x06064b50;
|
|
4
5
|
const ZIP64_EOCD_LOCATOR_SIGNATURE = 0x07064b50;
|
|
5
6
|
const ZIP_EOCD_MIN_BYTES = 22;
|
|
@@ -38,7 +39,26 @@ function findZipEndOfCentralDirectory(buffer) {
|
|
|
38
39
|
return -1;
|
|
39
40
|
}
|
|
40
41
|
const minOffset = Math.max(0, buffer.byteLength - ZIP_EOCD_MIN_BYTES - ZIP_EOCD_MAX_COMMENT_BYTES);
|
|
41
|
-
|
|
42
|
+
const lastOffset = buffer.byteLength - ZIP_EOCD_MIN_BYTES;
|
|
43
|
+
if (buffer.readUInt32LE(lastOffset) === ZIP_EOCD_SIGNATURE &&
|
|
44
|
+
buffer.readUInt16LE(lastOffset + ZIP_EOCD_COMMENT_LENGTH_OFFSET) === 0) {
|
|
45
|
+
return lastOffset;
|
|
46
|
+
}
|
|
47
|
+
const tail = buffer.subarray(minOffset);
|
|
48
|
+
let from = lastOffset - minOffset - 1;
|
|
49
|
+
// Keep the latest valid record semantics of this count hint. Bound native
|
|
50
|
+
// searches so dense false signatures retain the byte scan's cost.
|
|
51
|
+
for (let candidates = 0; candidates < 16 && from >= 0; candidates += 1) {
|
|
52
|
+
const found = tail.lastIndexOf(ZIP_EOCD_SIGNATURE_BYTES, from);
|
|
53
|
+
if (found < 0)
|
|
54
|
+
return -1;
|
|
55
|
+
const offset = minOffset + found;
|
|
56
|
+
const commentLength = buffer.readUInt16LE(offset + ZIP_EOCD_COMMENT_LENGTH_OFFSET);
|
|
57
|
+
if (offset + ZIP_EOCD_MIN_BYTES + commentLength === buffer.byteLength)
|
|
58
|
+
return offset;
|
|
59
|
+
from = found - 1;
|
|
60
|
+
}
|
|
61
|
+
for (let offset = minOffset + from; offset >= minOffset; offset -= 1) {
|
|
42
62
|
if (buffer.readUInt32LE(offset) !== ZIP_EOCD_SIGNATURE) {
|
|
43
63
|
continue;
|
|
44
64
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"archive-zip-directory.d.ts","sourceRoot":"","sources":["../src/archive-zip-directory.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,4BAA4B,EAClC,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,MAAM,MAAM,OAAO,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AACzD,MAAM,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AACzD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,IAAI,EAAE,gBAAgB,CAAC;CACxB,CAAC;
|
|
1
|
+
{"version":3,"file":"archive-zip-directory.d.ts","sourceRoot":"","sources":["../src/archive-zip-directory.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,4BAA4B,EAClC,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,MAAM,MAAM,OAAO,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AACzD,MAAM,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AACzD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,IAAI,EAAE,gBAAgB,CAAC;CACxB,CAAC;AAkKF,wBAAiB,gBAAgB,CAC/B,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,4BAA4B,EAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,GAC/F,OAAO,CAqET"}
|
|
@@ -19,7 +19,8 @@ function* read(offset, length, bound) {
|
|
|
19
19
|
zipFormat("truncated record");
|
|
20
20
|
return bytes;
|
|
21
21
|
}
|
|
22
|
-
|
|
22
|
+
const END_SIGNATURE = Buffer.from([0x50, 0x4b, 0x05, 0x06]);
|
|
23
|
+
function denseEndOffset(tail) {
|
|
23
24
|
let found = -1;
|
|
24
25
|
for (let offset = tail.length - 22; offset >= 0; offset--) {
|
|
25
26
|
if (tail.readUInt32LE(offset) === 0x06054b50 && offset + 22 + tail.readUInt16LE(offset + 20) === tail.length) {
|
|
@@ -32,6 +33,27 @@ function endOffset(tail) {
|
|
|
32
33
|
zipFormat("end record missing");
|
|
33
34
|
return found;
|
|
34
35
|
}
|
|
36
|
+
function endOffset(tail) {
|
|
37
|
+
let found = -1;
|
|
38
|
+
let from = 0;
|
|
39
|
+
// Sparse signatures use native search; dense attacker-controlled markers
|
|
40
|
+
// retain the bounded byte scan instead of one native call per marker.
|
|
41
|
+
for (let candidates = 0; candidates < 16; candidates++) {
|
|
42
|
+
const offset = tail.indexOf(END_SIGNATURE, from);
|
|
43
|
+
if (offset < 0 || offset > tail.length - 22) {
|
|
44
|
+
if (found < 0)
|
|
45
|
+
zipFormat("end record missing");
|
|
46
|
+
return found;
|
|
47
|
+
}
|
|
48
|
+
if (offset + 22 + tail.readUInt16LE(offset + 20) === tail.length) {
|
|
49
|
+
if (found !== -1)
|
|
50
|
+
zipFormat("ambiguous end records");
|
|
51
|
+
found = offset;
|
|
52
|
+
}
|
|
53
|
+
from = offset + 1;
|
|
54
|
+
}
|
|
55
|
+
return denseEndOffset(tail);
|
|
56
|
+
}
|
|
35
57
|
function* zip64End(locator, locatorAt, size) {
|
|
36
58
|
const advertised = zipUInt64(locator, 8);
|
|
37
59
|
// Seek the advertised record, or the fixed ordinary record for a prefixed
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { ZipDirectoryEntry } from "./archive-zip-directory.js";
|
|
2
|
+
import { type ZipEntry } from "./archive-zip-entry.js";
|
|
2
3
|
export type ZipArchiveWithFiles = {
|
|
3
4
|
files: Record<string, unknown>;
|
|
4
5
|
};
|
|
6
|
+
export declare function admittedZipEntries(archive: ZipArchiveWithFiles): readonly ZipEntry[];
|
|
5
7
|
/** Internal: the caller has admitted these unchanged bytes and their metadata. */
|
|
6
8
|
export declare function loadAdmittedZipArchive(buffer: Buffer | Uint8Array, admitted: ZipDirectoryEntry[]): Promise<ZipArchiveWithFiles>;
|
|
7
9
|
//# sourceMappingURL=archive-zip-loader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"archive-zip-loader.d.ts","sourceRoot":"","sources":["../src/archive-zip-loader.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"archive-zip-loader.d.ts","sourceRoot":"","sources":["../src/archive-zip-loader.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAA4B,KAAK,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAGjF,MAAM,MAAM,mBAAmB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC;AAGrE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,SAAS,QAAQ,EAAE,CAEpF;AA4BD,kFAAkF;AAClF,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,GAAG,UAAU,EAC3B,QAAQ,EAAE,iBAAiB,EAAE,GAC5B,OAAO,CAAC,mBAAmB,CAAC,CAqF9B"}
|
|
@@ -2,6 +2,10 @@ import { ArchiveFormatError, ArchiveSecurityError } from "./archive-errors.js";
|
|
|
2
2
|
import { validateArchiveEntryPath } from "./archive-entry.js";
|
|
3
3
|
import { registerAdmittedZipEntry } from "./archive-zip-entry.js";
|
|
4
4
|
import { zipPathKey } from "./archive-zip-names.js";
|
|
5
|
+
const orderedEntries = new WeakMap();
|
|
6
|
+
export function admittedZipEntries(archive) {
|
|
7
|
+
return orderedEntries.get(archive) ?? disagreement();
|
|
8
|
+
}
|
|
5
9
|
function disagreement() {
|
|
6
10
|
throw new ArchiveFormatError("ZIP decoder disagrees with admitted directory metadata");
|
|
7
11
|
}
|
|
@@ -106,6 +110,7 @@ export async function loadAdmittedZipArchive(buffer, admitted) {
|
|
|
106
110
|
if (remaining.size || inserted.size)
|
|
107
111
|
disagreement();
|
|
108
112
|
const files = Object.create(null);
|
|
113
|
+
const entries = [];
|
|
109
114
|
for (const [name, entry, physical] of normalized) {
|
|
110
115
|
const appendSlash = physical.kind === "directory" && !name.endsWith("/");
|
|
111
116
|
const normalizedName = appendSlash ? `${name}/` : name;
|
|
@@ -116,8 +121,10 @@ export async function loadAdmittedZipArchive(buffer, admitted) {
|
|
|
116
121
|
}
|
|
117
122
|
files[normalizedName] = entry;
|
|
118
123
|
registerAdmittedZipEntry(entry, physical);
|
|
124
|
+
entries.push(entry);
|
|
119
125
|
}
|
|
120
126
|
archive.files = files;
|
|
127
|
+
orderedEntries.set(archive, entries);
|
|
121
128
|
return archive;
|
|
122
129
|
}
|
|
123
130
|
async function importOptionalJsZip() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"archive-zip-names.d.ts","sourceRoot":"","sources":["../src/archive-zip-names.ts"],"names":[],"mappings":"AAKA,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,CAEhD;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAK/D;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAcjE;AAUD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG/C;
|
|
1
|
+
{"version":3,"file":"archive-zip-names.d.ts","sourceRoot":"","sources":["../src/archive-zip-names.ts"],"names":[],"mappings":"AAKA,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,CAEhD;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAK/D;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAcjE;AAUD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG/C;AAsBD,wBAAgB,aAAa,CAAC,MAAM,EAAE;IACpC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAC9C,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACnB,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAyEzF"}
|
|
@@ -50,9 +50,12 @@ export function zipPathKey(name) {
|
|
|
50
50
|
function originalName(name, rawName, flags) {
|
|
51
51
|
// ASCII path syntax is encoding-independent. Do not reinterpret legacy bytes
|
|
52
52
|
// as UTF-8 (native ZIP uses CP437); the selected decoder still validates its name.
|
|
53
|
-
|
|
53
|
+
const asciiName = rawName.replace(/[\x80-\xff]/g, "_");
|
|
54
|
+
validateArchiveEntryPath(asciiName);
|
|
54
55
|
if (!(flags & 0x800))
|
|
55
56
|
return undefined;
|
|
57
|
+
if (asciiName === rawName && !types.isSharedArrayBuffer(name.buffer))
|
|
58
|
+
return rawName;
|
|
56
59
|
const decoded = utf8(name);
|
|
57
60
|
validateArchiveEntryPath(decoded);
|
|
58
61
|
return decoded;
|
|
@@ -102,7 +105,9 @@ export function admitZipNames(params) {
|
|
|
102
105
|
interpretations.some((value) => /[/\\]$/.test(value) !== directory)) {
|
|
103
106
|
zipFormat("conflicting terminal directory markers");
|
|
104
107
|
}
|
|
105
|
-
const
|
|
108
|
+
const firstInterpretation = interpretations[0];
|
|
109
|
+
const interpretationKey = firstInterpretation === undefined ? undefined
|
|
110
|
+
: firstInterpretation === centralRaw ? centralKey : zipPathKey(firstInterpretation);
|
|
106
111
|
if (interpretations.some((value) => value !== interpretations[0] && zipPathKey(value) !== interpretationKey)) {
|
|
107
112
|
zipFormat("conflicting Unicode name interpretations");
|
|
108
113
|
}
|
package/dist/archive.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"archive.d.ts","sourceRoot":"","sources":["../src/archive.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"archive.d.ts","sourceRoot":"","sources":["../src/archive.ts"],"names":[],"mappings":"AA6DA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAIlE,YAAY,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AACjF,YAAY,EACV,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,0BAA0B,GAC3B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,kBAAkB,EAClB,yBAAyB,EACzB,wBAAwB,EACxB,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC/F,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,KAAK,wBAAwB,EAAE,KAAK,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AACpH,OAAO,EACL,wBAAwB,EACxB,iBAAiB,EACjB,6BAA6B,EAC7B,mBAAmB,EACnB,2BAA2B,EAC3B,uBAAuB,EACvB,4BAA4B,EAC5B,iCAAiC,EACjC,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,GAC3B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,KAAK,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AACtF,OAAO,EAAE,oBAAoB,EAAE,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,EACL,kCAAkC,EAClC,iCAAiC,EACjC,4BAA4B,EAC5B,wBAAwB,EACxB,4BAA4B,GAC7B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,8BAA8B,EAAE,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrF,OAAO,EACL,2BAA2B,EAC3B,iCAAiC,EACjC,KAAK,mBAAmB,GACzB,MAAM,4BAA4B,CAAC;AAmNpC,wBAAsB,cAAc,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoDjF"}
|
package/dist/archive.js
CHANGED
|
@@ -13,6 +13,7 @@ import { resolveArchiveKind } from "./archive-kind.js";
|
|
|
13
13
|
import { prepareArchiveDestinationGuard, preparePrivateArchiveOutputPath, withStagedArchiveDestination, } from "./archive-staging.js";
|
|
14
14
|
import { mergePlannedArchiveIntoDestination } from "./archive-merge.js";
|
|
15
15
|
import { loadZipArchiveWithPreflight } from "./archive-zip-preflight.js";
|
|
16
|
+
import { admittedZipEntries } from "./archive-zip-loader.js";
|
|
16
17
|
import { zipEntryKind, zipEntryDeclaredSize, zipEntryMode, } from "./archive-zip-entry.js";
|
|
17
18
|
import { createZipIntegrityTransform, normalizeZipIntegrityError, } from "./archive-zip-integrity.js";
|
|
18
19
|
import { FsSafeError } from "./errors.js";
|
|
@@ -131,7 +132,7 @@ async function extractZip(params) {
|
|
|
131
132
|
params.deadline.check();
|
|
132
133
|
const zip = await waitForDeadline(loadZipArchiveWithPreflight(buffer, limits), params.deadline);
|
|
133
134
|
params.deadline.check();
|
|
134
|
-
const entries =
|
|
135
|
+
const entries = admittedZipEntries(zip);
|
|
135
136
|
const strip = Math.max(0, Math.floor(params.stripComponents ?? 0));
|
|
136
137
|
assertArchiveEntryCountWithinLimit(entries.length, limits);
|
|
137
138
|
const budget = createByteBudgetTracker(limits);
|
|
@@ -192,6 +193,7 @@ async function extractZip(params) {
|
|
|
192
193
|
await mergePlannedArchiveIntoDestination({
|
|
193
194
|
entries: acceptedEntries,
|
|
194
195
|
durable: params.durable,
|
|
196
|
+
entryUmask: params.entryUmask,
|
|
195
197
|
sourceDir: stagingRealDir,
|
|
196
198
|
destinationGuard,
|
|
197
199
|
deadline: params.deadline,
|
|
@@ -207,6 +209,10 @@ async function extractZip(params) {
|
|
|
207
209
|
export async function extractArchive(params) {
|
|
208
210
|
const archivePath = params.archivePath;
|
|
209
211
|
const destDir = params.destDir;
|
|
212
|
+
const { entryUmask = 0 } = params;
|
|
213
|
+
if (!Number.isInteger(entryUmask) || entryUmask < 0 || entryUmask > 0o777) {
|
|
214
|
+
throw new RangeError("archive entryUmask must be an integer between 0 and 0o777");
|
|
215
|
+
}
|
|
210
216
|
const onFiltered = resolveArchiveFilteredEntryPolicy(params.onFiltered);
|
|
211
217
|
const kind = params.kind ?? resolveArchiveKind(archivePath);
|
|
212
218
|
if (!kind) {
|
|
@@ -224,7 +230,7 @@ export async function extractArchive(params) {
|
|
|
224
230
|
archivePath, destDir,
|
|
225
231
|
durable: params.durable,
|
|
226
232
|
stripComponents: params.stripComponents, limits,
|
|
227
|
-
entryModes: params.entryModes, entryFilter: params.entryFilter, onFiltered,
|
|
233
|
+
entryModes: params.entryModes, entryUmask, entryFilter: params.entryFilter, onFiltered,
|
|
228
234
|
};
|
|
229
235
|
if (native) {
|
|
230
236
|
await withExtractionDeadline(params.timeoutMs, label, async (deadline) => extractNativeArchive({ ...options, binding: native, kind, tarLimits, deadline }));
|
|
@@ -281,7 +287,7 @@ async function extractWasmTar(params) {
|
|
|
281
287
|
});
|
|
282
288
|
deadline.check();
|
|
283
289
|
await mergePlannedArchiveIntoDestination({ entries: accepted, sourceDir: stagingDir, destinationGuard,
|
|
284
|
-
deadline, durable: options.durable });
|
|
290
|
+
deadline, durable: options.durable, entryUmask: options.entryUmask });
|
|
285
291
|
deadline.check();
|
|
286
292
|
} });
|
|
287
293
|
}
|