@openclaw/openshell-sandbox 2026.9.1 → 2026.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +87 -47
- package/node_modules/@openclaw/fs-safe/CHANGELOG.md +700 -0
- package/node_modules/@openclaw/fs-safe/LICENSE +21 -0
- package/node_modules/@openclaw/fs-safe/README.md +564 -0
- package/node_modules/@openclaw/fs-safe/SECURITY.md +45 -0
- package/node_modules/@openclaw/fs-safe/dist/absolute-path.d.ts +33 -0
- package/node_modules/@openclaw/fs-safe/dist/absolute-path.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/absolute-path.js +307 -0
- package/node_modules/@openclaw/fs-safe/dist/advanced.d.ts +26 -0
- package/node_modules/@openclaw/fs-safe/dist/advanced.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/advanced.js +28 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-crc32.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-crc32.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-crc32.js +14 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-deadline.d.ts +12 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-deadline.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-deadline.js +103 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-entry.d.ts +14 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-entry.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-entry.js +85 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-errors.d.ts +13 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-errors.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-errors.js +23 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-gzip-tail.d.ts +18 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-gzip-tail.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-gzip-tail.js +74 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-input.d.ts +19 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-input.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-input.js +92 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-kind.d.ts +9 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-kind.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-kind.js +82 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-limits.d.ts +57 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-limits.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-limits.js +131 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-merge.d.ts +18 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-merge.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-merge.js +157 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-native.d.ts +20 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-native.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-native.js +107 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-options.d.ts +21 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-options.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-options.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-parser-errors.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-parser-errors.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-parser-errors.js +12 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-parser.wasm +0 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-plan.d.ts +20 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-plan.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-plan.js +55 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-policy.d.ts +22 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-policy.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-policy.js +38 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-read.d.ts +6 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-read.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-read.js +225 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-staging.d.ts +31 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-staging.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-staging.js +250 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-tar-inspect.d.ts +7 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-tar-inspect.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-tar-inspect.js +59 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-tar-stream.d.ts +18 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-tar-stream.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-tar-stream.js +95 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-tar-wasm.d.ts +18 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-tar-wasm.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-tar-wasm.js +99 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-tar.d.ts +19 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-tar.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-tar.js +21 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-admission.d.ts +8 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-admission.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-admission.js +60 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-count.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-count.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-count.js +140 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-directory.d.ts +15 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-directory.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-directory.js +228 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-entry.d.ts +21 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-entry.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-entry.js +27 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-integrity.d.ts +5 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-integrity.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-integrity.js +41 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-names.d.ts +12 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-names.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-names.js +100 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-preflight.d.ts +7 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-preflight.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-preflight.js +44 -0
- package/node_modules/@openclaw/fs-safe/dist/archive.d.ts +15 -0
- package/node_modules/@openclaw/fs-safe/dist/archive.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/archive.js +275 -0
- package/node_modules/@openclaw/fs-safe/dist/async-lock.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/async-lock.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/async-lock.js +17 -0
- package/node_modules/@openclaw/fs-safe/dist/atomic.d.ts +5 -0
- package/node_modules/@openclaw/fs-safe/dist/atomic.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/atomic.js +4 -0
- package/node_modules/@openclaw/fs-safe/dist/bounded-read-stream.d.ts +4 -0
- package/node_modules/@openclaw/fs-safe/dist/bounded-read-stream.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/bounded-read-stream.js +21 -0
- package/node_modules/@openclaw/fs-safe/dist/bounded-read.d.ts +14 -0
- package/node_modules/@openclaw/fs-safe/dist/bounded-read.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/bounded-read.js +106 -0
- package/node_modules/@openclaw/fs-safe/dist/byte-budget.d.ts +4 -0
- package/node_modules/@openclaw/fs-safe/dist/byte-budget.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/byte-budget.js +9 -0
- package/node_modules/@openclaw/fs-safe/dist/config.d.ts +3 -0
- package/node_modules/@openclaw/fs-safe/dist/config.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/config.js +2 -0
- package/node_modules/@openclaw/fs-safe/dist/containment.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/containment.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/containment.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/deny-mutations.d.ts +12 -0
- package/node_modules/@openclaw/fs-safe/dist/deny-mutations.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/deny-mutations.js +69 -0
- package/node_modules/@openclaw/fs-safe/dist/device-path.d.ts +15 -0
- package/node_modules/@openclaw/fs-safe/dist/device-path.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/device-path.js +137 -0
- package/node_modules/@openclaw/fs-safe/dist/directory-durability.d.ts +44 -0
- package/node_modules/@openclaw/fs-safe/dist/directory-durability.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/directory-durability.js +299 -0
- package/node_modules/@openclaw/fs-safe/dist/directory-guard.d.ts +31 -0
- package/node_modules/@openclaw/fs-safe/dist/directory-guard.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/directory-guard.js +82 -0
- package/node_modules/@openclaw/fs-safe/dist/directory-mode-node.d.ts +8 -0
- package/node_modules/@openclaw/fs-safe/dist/directory-mode-node.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/directory-mode-node.js +93 -0
- package/node_modules/@openclaw/fs-safe/dist/directory-mode-owner.d.ts +21 -0
- package/node_modules/@openclaw/fs-safe/dist/directory-mode-owner.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/directory-mode-owner.js +78 -0
- package/node_modules/@openclaw/fs-safe/dist/durability.d.ts +4 -0
- package/node_modules/@openclaw/fs-safe/dist/durability.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/durability.js +3 -0
- package/node_modules/@openclaw/fs-safe/dist/error-detail.d.ts +3 -0
- package/node_modules/@openclaw/fs-safe/dist/error-detail.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/error-detail.js +10 -0
- package/node_modules/@openclaw/fs-safe/dist/errors.d.ts +14 -0
- package/node_modules/@openclaw/fs-safe/dist/errors.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/errors.js +26 -0
- package/node_modules/@openclaw/fs-safe/dist/file-hash.d.ts +10 -0
- package/node_modules/@openclaw/fs-safe/dist/file-hash.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/file-hash.js +73 -0
- package/node_modules/@openclaw/fs-safe/dist/file-identity.d.ts +8 -0
- package/node_modules/@openclaw/fs-safe/dist/file-identity.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/file-identity.js +34 -0
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync.d.ts +35 -0
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync.js +349 -0
- package/node_modules/@openclaw/fs-safe/dist/file-lock.d.ts +24 -0
- package/node_modules/@openclaw/fs-safe/dist/file-lock.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/file-lock.js +46 -0
- package/node_modules/@openclaw/fs-safe/dist/file-observation.d.ts +9 -0
- package/node_modules/@openclaw/fs-safe/dist/file-observation.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/file-observation.js +22 -0
- package/node_modules/@openclaw/fs-safe/dist/file-store-boundary.d.ts +33 -0
- package/node_modules/@openclaw/fs-safe/dist/file-store-boundary.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/file-store-boundary.js +189 -0
- package/node_modules/@openclaw/fs-safe/dist/file-store-limit.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/file-store-limit.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/file-store-limit.js +8 -0
- package/node_modules/@openclaw/fs-safe/dist/file-store-prune.d.ts +12 -0
- package/node_modules/@openclaw/fs-safe/dist/file-store-prune.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/file-store-prune.js +95 -0
- package/node_modules/@openclaw/fs-safe/dist/file-store-sync-write.d.ts +9 -0
- package/node_modules/@openclaw/fs-safe/dist/file-store-sync-write.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/file-store-sync-write.js +127 -0
- package/node_modules/@openclaw/fs-safe/dist/file-store.d.ts +62 -0
- package/node_modules/@openclaw/fs-safe/dist/file-store.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/file-store.js +357 -0
- package/node_modules/@openclaw/fs-safe/dist/file-sync.d.ts +5 -0
- package/node_modules/@openclaw/fs-safe/dist/file-sync.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/file-sync.js +19 -0
- package/node_modules/@openclaw/fs-safe/dist/filename.d.ts +8 -0
- package/node_modules/@openclaw/fs-safe/dist/filename.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/filename.js +91 -0
- package/node_modules/@openclaw/fs-safe/dist/fs.d.ts +13 -0
- package/node_modules/@openclaw/fs-safe/dist/fs.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/fs.js +30 -0
- package/node_modules/@openclaw/fs-safe/dist/guarded-mkdir.d.ts +14 -0
- package/node_modules/@openclaw/fs-safe/dist/guarded-mkdir.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/guarded-mkdir.js +87 -0
- package/node_modules/@openclaw/fs-safe/dist/guarded-mutation.d.ts +37 -0
- package/node_modules/@openclaw/fs-safe/dist/guarded-mutation.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/guarded-mutation.js +82 -0
- package/node_modules/@openclaw/fs-safe/dist/home-dir.d.ts +12 -0
- package/node_modules/@openclaw/fs-safe/dist/home-dir.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/home-dir.js +84 -0
- package/node_modules/@openclaw/fs-safe/dist/index.d.ts +7 -0
- package/node_modules/@openclaw/fs-safe/dist/index.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/index.js +5 -0
- package/node_modules/@openclaw/fs-safe/dist/install-path.d.ts +20 -0
- package/node_modules/@openclaw/fs-safe/dist/install-path.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/install-path.js +94 -0
- package/node_modules/@openclaw/fs-safe/dist/json-document-store.d.ts +35 -0
- package/node_modules/@openclaw/fs-safe/dist/json-document-store.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/json-document-store.js +97 -0
- package/node_modules/@openclaw/fs-safe/dist/json-durable-queue-directory.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/json-durable-queue-directory.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/json-durable-queue-directory.js +20 -0
- package/node_modules/@openclaw/fs-safe/dist/json-durable-queue-ownership.d.ts +17 -0
- package/node_modules/@openclaw/fs-safe/dist/json-durable-queue-ownership.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/json-durable-queue-ownership.js +292 -0
- package/node_modules/@openclaw/fs-safe/dist/json-durable-queue.d.ts +46 -0
- package/node_modules/@openclaw/fs-safe/dist/json-durable-queue.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/json-durable-queue.js +383 -0
- package/node_modules/@openclaw/fs-safe/dist/json-store.d.ts +9 -0
- package/node_modules/@openclaw/fs-safe/dist/json-store.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/json-store.js +12 -0
- package/node_modules/@openclaw/fs-safe/dist/json-stringify.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/json-stringify.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/json-stringify.js +7 -0
- package/node_modules/@openclaw/fs-safe/dist/json.d.ts +50 -0
- package/node_modules/@openclaw/fs-safe/dist/json.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/json.js +343 -0
- package/node_modules/@openclaw/fs-safe/dist/local-file-access.d.ts +9 -0
- package/node_modules/@openclaw/fs-safe/dist/local-file-access.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/local-file-access.js +87 -0
- package/node_modules/@openclaw/fs-safe/dist/local-roots.d.ts +26 -0
- package/node_modules/@openclaw/fs-safe/dist/local-roots.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/local-roots.js +135 -0
- package/node_modules/@openclaw/fs-safe/dist/lock-config.d.ts +10 -0
- package/node_modules/@openclaw/fs-safe/dist/lock-config.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/lock-config.js +12 -0
- package/node_modules/@openclaw/fs-safe/dist/move-path-cleanup.d.ts +43 -0
- package/node_modules/@openclaw/fs-safe/dist/move-path-cleanup.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/move-path-cleanup.js +161 -0
- package/node_modules/@openclaw/fs-safe/dist/move-path.d.ts +21 -0
- package/node_modules/@openclaw/fs-safe/dist/move-path.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/move-path.js +334 -0
- package/node_modules/@openclaw/fs-safe/dist/native-binding.d.ts +93 -0
- package/node_modules/@openclaw/fs-safe/dist/native-binding.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/native-binding.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/native-config.d.ts +17 -0
- package/node_modules/@openclaw/fs-safe/dist/native-config.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/native-config.js +71 -0
- package/node_modules/@openclaw/fs-safe/dist/native-operations.d.ts +21 -0
- package/node_modules/@openclaw/fs-safe/dist/native-operations.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/native-operations.js +132 -0
- package/node_modules/@openclaw/fs-safe/dist/native-pinned-write-windows.d.ts +8 -0
- package/node_modules/@openclaw/fs-safe/dist/native-pinned-write-windows.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/native-pinned-write-windows.js +96 -0
- package/node_modules/@openclaw/fs-safe/dist/native-pinned-write.d.ts +5 -0
- package/node_modules/@openclaw/fs-safe/dist/native-pinned-write.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/native-pinned-write.js +161 -0
- package/node_modules/@openclaw/fs-safe/dist/native-staged-file.d.ts +31 -0
- package/node_modules/@openclaw/fs-safe/dist/native-staged-file.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/native-staged-file.js +362 -0
- package/node_modules/@openclaw/fs-safe/dist/native.d.ts +14 -0
- package/node_modules/@openclaw/fs-safe/dist/native.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/native.js +204 -0
- package/node_modules/@openclaw/fs-safe/dist/opened-file-failure.d.ts +8 -0
- package/node_modules/@openclaw/fs-safe/dist/opened-file-failure.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/opened-file-failure.js +45 -0
- package/node_modules/@openclaw/fs-safe/dist/opened-realpath.d.ts +16 -0
- package/node_modules/@openclaw/fs-safe/dist/opened-realpath.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/opened-realpath.js +92 -0
- package/node_modules/@openclaw/fs-safe/dist/output.d.ts +15 -0
- package/node_modules/@openclaw/fs-safe/dist/output.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/output.js +123 -0
- package/node_modules/@openclaw/fs-safe/dist/owner-dacl.d.ts +31 -0
- package/node_modules/@openclaw/fs-safe/dist/owner-dacl.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/owner-dacl.js +28 -0
- package/node_modules/@openclaw/fs-safe/dist/path-policy.d.ts +25 -0
- package/node_modules/@openclaw/fs-safe/dist/path-policy.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/path-policy.js +44 -0
- package/node_modules/@openclaw/fs-safe/dist/path.d.ts +21 -0
- package/node_modules/@openclaw/fs-safe/dist/path.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/path.js +136 -0
- package/node_modules/@openclaw/fs-safe/dist/permission-exec.d.ts +25 -0
- package/node_modules/@openclaw/fs-safe/dist/permission-exec.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/permission-exec.js +74 -0
- package/node_modules/@openclaw/fs-safe/dist/permissions-public.d.ts +4 -0
- package/node_modules/@openclaw/fs-safe/dist/permissions-public.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/permissions-public.js +3 -0
- package/node_modules/@openclaw/fs-safe/dist/permissions-windows.d.ts +59 -0
- package/node_modules/@openclaw/fs-safe/dist/permissions-windows.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/permissions-windows.js +296 -0
- package/node_modules/@openclaw/fs-safe/dist/permissions.d.ts +60 -0
- package/node_modules/@openclaw/fs-safe/dist/permissions.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/permissions.js +125 -0
- package/node_modules/@openclaw/fs-safe/dist/pinned-open.d.ts +24 -0
- package/node_modules/@openclaw/fs-safe/dist/pinned-open.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/pinned-open.js +74 -0
- package/node_modules/@openclaw/fs-safe/dist/pinned-operation.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/pinned-operation.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/pinned-operation.js +35 -0
- package/node_modules/@openclaw/fs-safe/dist/pinned-write.d.ts +36 -0
- package/node_modules/@openclaw/fs-safe/dist/pinned-write.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/pinned-write.js +252 -0
- package/node_modules/@openclaw/fs-safe/dist/private-directory.d.ts +5 -0
- package/node_modules/@openclaw/fs-safe/dist/private-directory.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/private-directory.js +14 -0
- package/node_modules/@openclaw/fs-safe/dist/private-temp-workspace.d.ts +45 -0
- package/node_modules/@openclaw/fs-safe/dist/private-temp-workspace.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/private-temp-workspace.js +299 -0
- package/node_modules/@openclaw/fs-safe/dist/publish-file-failure.d.ts +28 -0
- package/node_modules/@openclaw/fs-safe/dist/publish-file-failure.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/publish-file-failure.js +22 -0
- package/node_modules/@openclaw/fs-safe/dist/publish-file.d.ts +21 -0
- package/node_modules/@openclaw/fs-safe/dist/publish-file.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/publish-file.js +366 -0
- package/node_modules/@openclaw/fs-safe/dist/read-open-flags.d.ts +8 -0
- package/node_modules/@openclaw/fs-safe/dist/read-open-flags.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/read-open-flags.js +13 -0
- package/node_modules/@openclaw/fs-safe/dist/read-opened-file.d.ts +21 -0
- package/node_modules/@openclaw/fs-safe/dist/read-opened-file.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/read-opened-file.js +18 -0
- package/node_modules/@openclaw/fs-safe/dist/regular-file.d.ts +38 -0
- package/node_modules/@openclaw/fs-safe/dist/regular-file.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/regular-file.js +391 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-directory.d.ts +7 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-directory.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-directory.js +42 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file-copy-fallback.d.ts +39 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file-copy-fallback.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file-copy-fallback.js +331 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file-copy-source.d.ts +21 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file-copy-source.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file-copy-source.js +107 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file-descriptor.d.ts +51 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file-descriptor.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file-descriptor.js +161 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file-rename-policy.d.ts +7 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file-rename-policy.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file-rename-policy.js +30 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file-temp-owner.d.ts +53 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file-temp-owner.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file-temp-owner.js +376 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file.d.ts +58 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file.js +329 -0
- package/node_modules/@openclaw/fs-safe/dist/root-context.d.ts +38 -0
- package/node_modules/@openclaw/fs-safe/dist/root-context.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/root-context.js +141 -0
- package/node_modules/@openclaw/fs-safe/dist/root-errors.d.ts +12 -0
- package/node_modules/@openclaw/fs-safe/dist/root-errors.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/root-errors.js +75 -0
- package/node_modules/@openclaw/fs-safe/dist/root-file.d.ts +45 -0
- package/node_modules/@openclaw/fs-safe/dist/root-file.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/root-file.js +120 -0
- package/node_modules/@openclaw/fs-safe/dist/root-impl.d.ts +163 -0
- package/node_modules/@openclaw/fs-safe/dist/root-impl.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/root-impl.js +1230 -0
- package/node_modules/@openclaw/fs-safe/dist/root-path-existing.d.ts +3 -0
- package/node_modules/@openclaw/fs-safe/dist/root-path-existing.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/root-path-existing.js +68 -0
- package/node_modules/@openclaw/fs-safe/dist/root-path-symlink.d.ts +7 -0
- package/node_modules/@openclaw/fs-safe/dist/root-path-symlink.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/root-path-symlink.js +35 -0
- package/node_modules/@openclaw/fs-safe/dist/root-path.d.ts +40 -0
- package/node_modules/@openclaw/fs-safe/dist/root-path.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/root-path.js +481 -0
- package/node_modules/@openclaw/fs-safe/dist/root-paths.d.ts +89 -0
- package/node_modules/@openclaw/fs-safe/dist/root-paths.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/root-paths.js +381 -0
- package/node_modules/@openclaw/fs-safe/dist/root-walk.d.ts +41 -0
- package/node_modules/@openclaw/fs-safe/dist/root-walk.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/root-walk.js +133 -0
- package/node_modules/@openclaw/fs-safe/dist/root-write-mode.d.ts +6 -0
- package/node_modules/@openclaw/fs-safe/dist/root-write-mode.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/root-write-mode.js +61 -0
- package/node_modules/@openclaw/fs-safe/dist/root-write-verification.d.ts +12 -0
- package/node_modules/@openclaw/fs-safe/dist/root-write-verification.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/root-write-verification.js +97 -0
- package/node_modules/@openclaw/fs-safe/dist/root.d.ts +4 -0
- package/node_modules/@openclaw/fs-safe/dist/root.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/root.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/safe-path-segment.d.ts +12 -0
- package/node_modules/@openclaw/fs-safe/dist/safe-path-segment.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/safe-path-segment.js +75 -0
- package/node_modules/@openclaw/fs-safe/dist/secret-file.d.ts +25 -0
- package/node_modules/@openclaw/fs-safe/dist/secret-file.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/secret-file.js +329 -0
- package/node_modules/@openclaw/fs-safe/dist/secret-read-async.d.ts +4 -0
- package/node_modules/@openclaw/fs-safe/dist/secret-read-async.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/secret-read-async.js +73 -0
- package/node_modules/@openclaw/fs-safe/dist/secret-read-policy.d.ts +17 -0
- package/node_modules/@openclaw/fs-safe/dist/secret-read-policy.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/secret-read-policy.js +40 -0
- package/node_modules/@openclaw/fs-safe/dist/secret.d.ts +4 -0
- package/node_modules/@openclaw/fs-safe/dist/secret.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/secret.js +3 -0
- package/node_modules/@openclaw/fs-safe/dist/secure-file.d.ts +32 -0
- package/node_modules/@openclaw/fs-safe/dist/secure-file.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/secure-file.js +182 -0
- package/node_modules/@openclaw/fs-safe/dist/secure-temp-dir.d.ts +27 -0
- package/node_modules/@openclaw/fs-safe/dist/secure-temp-dir.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/secure-temp-dir.js +160 -0
- package/node_modules/@openclaw/fs-safe/dist/sibling-staged-file.d.ts +15 -0
- package/node_modules/@openclaw/fs-safe/dist/sibling-staged-file.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/sibling-staged-file.js +143 -0
- package/node_modules/@openclaw/fs-safe/dist/sibling-temp.d.ts +27 -0
- package/node_modules/@openclaw/fs-safe/dist/sibling-temp.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/sibling-temp.js +95 -0
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-acquire.d.ts +31 -0
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-acquire.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-acquire.js +336 -0
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-handle.d.ts +24 -0
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-handle.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-handle.js +42 -0
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-policy.d.ts +14 -0
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-policy.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-policy.js +71 -0
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-reclaim.d.ts +63 -0
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-reclaim.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-reclaim.js +305 -0
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-root.d.ts +3 -0
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-root.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-root.js +76 -0
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-types.d.ts +63 -0
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-types.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-types.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock.d.ts +14 -0
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock.js +265 -0
- package/node_modules/@openclaw/fs-safe/dist/staged-directory.d.ts +16 -0
- package/node_modules/@openclaw/fs-safe/dist/staged-directory.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/staged-directory.js +60 -0
- package/node_modules/@openclaw/fs-safe/dist/staged-file-types.d.ts +56 -0
- package/node_modules/@openclaw/fs-safe/dist/staged-file-types.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/staged-file-types.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/store.d.ts +4 -0
- package/node_modules/@openclaw/fs-safe/dist/store.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/store.js +3 -0
- package/node_modules/@openclaw/fs-safe/dist/strict-file-identity.d.ts +6 -0
- package/node_modules/@openclaw/fs-safe/dist/strict-file-identity.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/strict-file-identity.js +51 -0
- package/node_modules/@openclaw/fs-safe/dist/string-coerce.d.ts +5 -0
- package/node_modules/@openclaw/fs-safe/dist/string-coerce.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/string-coerce.js +16 -0
- package/node_modules/@openclaw/fs-safe/dist/suppressed-error.d.ts +6 -0
- package/node_modules/@openclaw/fs-safe/dist/suppressed-error.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/suppressed-error.js +15 -0
- package/node_modules/@openclaw/fs-safe/dist/symlink-parents.d.ts +12 -0
- package/node_modules/@openclaw/fs-safe/dist/symlink-parents.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/symlink-parents.js +78 -0
- package/node_modules/@openclaw/fs-safe/dist/temp-cleanup.d.ts +14 -0
- package/node_modules/@openclaw/fs-safe/dist/temp-cleanup.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/temp-cleanup.js +87 -0
- package/node_modules/@openclaw/fs-safe/dist/temp-target.d.ts +28 -0
- package/node_modules/@openclaw/fs-safe/dist/temp-target.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/temp-target.js +137 -0
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-owner.d.ts +23 -0
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-owner.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-owner.js +320 -0
- package/node_modules/@openclaw/fs-safe/dist/temp.d.ts +4 -0
- package/node_modules/@openclaw/fs-safe/dist/temp.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/temp.js +2 -0
- package/node_modules/@openclaw/fs-safe/dist/test-hooks.d.ts +25 -0
- package/node_modules/@openclaw/fs-safe/dist/test-hooks.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/test-hooks.js +13 -0
- package/node_modules/@openclaw/fs-safe/dist/text-atomic.d.ts +14 -0
- package/node_modules/@openclaw/fs-safe/dist/text-atomic.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/text-atomic.js +14 -0
- package/node_modules/@openclaw/fs-safe/dist/timing.d.ts +8 -0
- package/node_modules/@openclaw/fs-safe/dist/timing.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/timing.js +40 -0
- package/node_modules/@openclaw/fs-safe/dist/trash.d.ts +5 -0
- package/node_modules/@openclaw/fs-safe/dist/trash.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/trash.js +171 -0
- package/node_modules/@openclaw/fs-safe/dist/types.d.ts +23 -0
- package/node_modules/@openclaw/fs-safe/dist/types.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/types.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/walk.d.ts +37 -0
- package/node_modules/@openclaw/fs-safe/dist/walk.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/walk.js +207 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-command.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-command.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-command.js +34 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-owner.d.ts +32 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-owner.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-owner.js +126 -0
- package/node_modules/@openclaw/fs-safe/dist/write-open-flags.d.ts +5 -0
- package/node_modules/@openclaw/fs-safe/dist/write-open-flags.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/write-open-flags.js +35 -0
- package/node_modules/@openclaw/fs-safe/dist/write-queue.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/write-queue.d.ts.map +1 -0
- package/node_modules/@openclaw/fs-safe/dist/write-queue.js +18 -0
- package/node_modules/@openclaw/fs-safe/docs/advanced.md +153 -0
- package/node_modules/@openclaw/fs-safe/docs/archive.md +658 -0
- package/node_modules/@openclaw/fs-safe/docs/assets/readme-banner.jpg +0 -0
- package/node_modules/@openclaw/fs-safe/docs/atomic.md +334 -0
- package/node_modules/@openclaw/fs-safe/docs/config.md +131 -0
- package/node_modules/@openclaw/fs-safe/docs/contributing.md +180 -0
- package/node_modules/@openclaw/fs-safe/docs/durability.md +313 -0
- package/node_modules/@openclaw/fs-safe/docs/errors.md +232 -0
- package/node_modules/@openclaw/fs-safe/docs/file-store.md +258 -0
- package/node_modules/@openclaw/fs-safe/docs/filename.md +96 -0
- package/node_modules/@openclaw/fs-safe/docs/index.md +84 -0
- package/node_modules/@openclaw/fs-safe/docs/install-path.md +170 -0
- package/node_modules/@openclaw/fs-safe/docs/install.md +163 -0
- package/node_modules/@openclaw/fs-safe/docs/json-store.md +221 -0
- package/node_modules/@openclaw/fs-safe/docs/json.md +213 -0
- package/node_modules/@openclaw/fs-safe/docs/local-roots.md +141 -0
- package/node_modules/@openclaw/fs-safe/docs/migrating-to-0.5.md +196 -0
- package/node_modules/@openclaw/fs-safe/docs/migrating-to-0.6.md +43 -0
- package/node_modules/@openclaw/fs-safe/docs/native-helper.md +118 -0
- package/node_modules/@openclaw/fs-safe/docs/native.md +196 -0
- package/node_modules/@openclaw/fs-safe/docs/output.md +139 -0
- package/node_modules/@openclaw/fs-safe/docs/path-scope.md +159 -0
- package/node_modules/@openclaw/fs-safe/docs/path.md +208 -0
- package/node_modules/@openclaw/fs-safe/docs/permissions.md +200 -0
- package/node_modules/@openclaw/fs-safe/docs/private-file-store.md +54 -0
- package/node_modules/@openclaw/fs-safe/docs/public-api.md +112 -0
- package/node_modules/@openclaw/fs-safe/docs/quickstart.md +154 -0
- package/node_modules/@openclaw/fs-safe/docs/reading.md +183 -0
- package/node_modules/@openclaw/fs-safe/docs/regular-file.md +190 -0
- package/node_modules/@openclaw/fs-safe/docs/root.md +266 -0
- package/node_modules/@openclaw/fs-safe/docs/secret-file.md +273 -0
- package/node_modules/@openclaw/fs-safe/docs/secure-file.md +100 -0
- package/node_modules/@openclaw/fs-safe/docs/security-model.md +188 -0
- package/node_modules/@openclaw/fs-safe/docs/sidecar-lock.md +439 -0
- package/node_modules/@openclaw/fs-safe/docs/staged-file.md +182 -0
- package/node_modules/@openclaw/fs-safe/docs/store.md +94 -0
- package/node_modules/@openclaw/fs-safe/docs/temp.md +476 -0
- package/node_modules/@openclaw/fs-safe/docs/test-hooks.md +96 -0
- package/node_modules/@openclaw/fs-safe/docs/testing.md +189 -0
- package/node_modules/@openclaw/fs-safe/docs/timing.md +121 -0
- package/node_modules/@openclaw/fs-safe/docs/types.md +188 -0
- package/node_modules/@openclaw/fs-safe/docs/walk.md +128 -0
- package/node_modules/@openclaw/fs-safe/docs/writing.md +347 -0
- package/node_modules/@openclaw/fs-safe/package.json +187 -0
- package/node_modules/@openclaw/fs-safe-darwin-arm64/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-darwin-arm64/package.json +29 -0
- package/node_modules/@openclaw/fs-safe-darwin-x64/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-darwin-x64/package.json +29 -0
- package/node_modules/@openclaw/fs-safe-linux-arm64-gnu/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-linux-arm64-gnu/package.json +32 -0
- package/node_modules/@openclaw/fs-safe-linux-arm64-musl/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-linux-arm64-musl/package.json +32 -0
- package/node_modules/@openclaw/fs-safe-linux-x64-gnu/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-linux-x64-gnu/package.json +32 -0
- package/node_modules/@openclaw/fs-safe-linux-x64-musl/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-linux-x64-musl/package.json +32 -0
- package/node_modules/@openclaw/fs-safe-win32-x64-msvc/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-win32-x64-msvc/package.json +29 -0
- package/node_modules/core-util-is/LICENSE +19 -0
- package/node_modules/core-util-is/README.md +3 -0
- package/node_modules/core-util-is/lib/util.js +107 -0
- package/node_modules/core-util-is/package.json +38 -0
- package/node_modules/immediate/LICENSE.txt +20 -0
- package/node_modules/immediate/README.md +93 -0
- package/node_modules/immediate/dist/immediate.js +75 -0
- package/node_modules/immediate/dist/immediate.min.js +1 -0
- package/node_modules/immediate/lib/browser.js +69 -0
- package/node_modules/immediate/lib/index.js +73 -0
- package/node_modules/immediate/package.json +42 -0
- package/node_modules/inherits/LICENSE +16 -0
- package/node_modules/inherits/README.md +42 -0
- package/node_modules/inherits/inherits.js +9 -0
- package/node_modules/inherits/inherits_browser.js +27 -0
- package/node_modules/inherits/package.json +29 -0
- package/node_modules/isarray/.npmignore +1 -0
- package/node_modules/isarray/.travis.yml +4 -0
- package/node_modules/isarray/Makefile +6 -0
- package/node_modules/isarray/README.md +60 -0
- package/node_modules/isarray/component.json +19 -0
- package/node_modules/isarray/index.js +5 -0
- package/node_modules/isarray/package.json +45 -0
- package/node_modules/isarray/test.js +20 -0
- package/node_modules/jszip/.codeclimate.yml +16 -0
- package/node_modules/jszip/.editorconfig +8 -0
- package/node_modules/jszip/.eslintrc.js +43 -0
- package/node_modules/jszip/.github/workflows/pr.yaml +58 -0
- package/node_modules/jszip/.jekyll-metadata +0 -0
- package/node_modules/jszip/.travis.yml +17 -0
- package/node_modules/jszip/CHANGES.md +204 -0
- package/node_modules/jszip/LICENSE.markdown +651 -0
- package/node_modules/jszip/README.markdown +33 -0
- package/node_modules/jszip/deps.js +37 -0
- package/node_modules/jszip/dist/jszip.js +11577 -0
- package/node_modules/jszip/dist/jszip.min.js +13 -0
- package/node_modules/jszip/graph.svg +601 -0
- package/node_modules/jszip/index.d.ts +330 -0
- package/node_modules/jszip/lib/base64.js +106 -0
- package/node_modules/jszip/lib/compressedObject.js +74 -0
- package/node_modules/jszip/lib/compressions.js +14 -0
- package/node_modules/jszip/lib/crc32.js +77 -0
- package/node_modules/jszip/lib/defaults.js +11 -0
- package/node_modules/jszip/lib/external.js +18 -0
- package/node_modules/jszip/lib/flate.js +85 -0
- package/node_modules/jszip/lib/generate/ZipFileWorker.js +539 -0
- package/node_modules/jszip/lib/generate/index.js +57 -0
- package/node_modules/jszip/lib/index.js +55 -0
- package/node_modules/jszip/lib/license_header.js +11 -0
- package/node_modules/jszip/lib/load.js +88 -0
- package/node_modules/jszip/lib/nodejs/NodejsStreamInputAdapter.js +74 -0
- package/node_modules/jszip/lib/nodejs/NodejsStreamOutputAdapter.js +42 -0
- package/node_modules/jszip/lib/nodejsUtils.js +57 -0
- package/node_modules/jszip/lib/object.js +384 -0
- package/node_modules/jszip/lib/readable-stream-browser.js +10 -0
- package/node_modules/jszip/lib/reader/ArrayReader.js +57 -0
- package/node_modules/jszip/lib/reader/DataReader.js +116 -0
- package/node_modules/jszip/lib/reader/NodeBufferReader.js +19 -0
- package/node_modules/jszip/lib/reader/StringReader.js +38 -0
- package/node_modules/jszip/lib/reader/Uint8ArrayReader.js +22 -0
- package/node_modules/jszip/lib/reader/readerFor.js +28 -0
- package/node_modules/jszip/lib/signature.js +7 -0
- package/node_modules/jszip/lib/stream/ConvertWorker.js +26 -0
- package/node_modules/jszip/lib/stream/Crc32Probe.js +24 -0
- package/node_modules/jszip/lib/stream/DataLengthProbe.js +29 -0
- package/node_modules/jszip/lib/stream/DataWorker.js +116 -0
- package/node_modules/jszip/lib/stream/GenericWorker.js +263 -0
- package/node_modules/jszip/lib/stream/StreamHelper.js +214 -0
- package/node_modules/jszip/lib/support.js +38 -0
- package/node_modules/jszip/lib/utf8.js +275 -0
- package/node_modules/jszip/lib/utils.js +501 -0
- package/node_modules/jszip/lib/zipEntries.js +261 -0
- package/node_modules/jszip/lib/zipEntry.js +293 -0
- package/node_modules/jszip/lib/zipObject.js +133 -0
- package/node_modules/jszip/package.json +67 -0
- package/node_modules/jszip/sponsors.md +21 -0
- package/node_modules/jszip/tsconfig.json +101 -0
- package/node_modules/jszip/vendor/FileSaver.js +247 -0
- package/node_modules/lie/README.md +62 -0
- package/node_modules/lie/dist/lie.js +350 -0
- package/node_modules/lie/dist/lie.min.js +1 -0
- package/node_modules/lie/dist/lie.polyfill.js +358 -0
- package/node_modules/lie/dist/lie.polyfill.min.js +1 -0
- package/node_modules/lie/lib/browser.js +273 -0
- package/node_modules/lie/lib/index.js +298 -0
- package/node_modules/lie/license.md +7 -0
- package/node_modules/lie/lie.d.ts +244 -0
- package/node_modules/lie/package.json +69 -0
- package/node_modules/lie/polyfill.js +4 -0
- package/node_modules/pako/CHANGELOG.md +164 -0
- package/node_modules/pako/LICENSE +21 -0
- package/node_modules/pako/README.md +191 -0
- package/node_modules/pako/dist/pako.js +6818 -0
- package/node_modules/pako/dist/pako.min.js +1 -0
- package/node_modules/pako/dist/pako_deflate.js +3997 -0
- package/node_modules/pako/dist/pako_deflate.min.js +1 -0
- package/node_modules/pako/dist/pako_inflate.js +3300 -0
- package/node_modules/pako/dist/pako_inflate.min.js +1 -0
- package/node_modules/pako/index.js +14 -0
- package/node_modules/pako/lib/deflate.js +400 -0
- package/node_modules/pako/lib/inflate.js +423 -0
- package/node_modules/pako/lib/utils/common.js +105 -0
- package/node_modules/pako/lib/utils/strings.js +187 -0
- package/node_modules/pako/lib/zlib/README +59 -0
- package/node_modules/pako/lib/zlib/adler32.js +51 -0
- package/node_modules/pako/lib/zlib/constants.js +68 -0
- package/node_modules/pako/lib/zlib/crc32.js +59 -0
- package/node_modules/pako/lib/zlib/deflate.js +1874 -0
- package/node_modules/pako/lib/zlib/gzheader.js +58 -0
- package/node_modules/pako/lib/zlib/inffast.js +345 -0
- package/node_modules/pako/lib/zlib/inflate.js +1556 -0
- package/node_modules/pako/lib/zlib/inftrees.js +343 -0
- package/node_modules/pako/lib/zlib/messages.js +32 -0
- package/node_modules/pako/lib/zlib/trees.js +1222 -0
- package/node_modules/pako/lib/zlib/zstream.js +47 -0
- package/node_modules/pako/package.json +44 -0
- package/node_modules/process-nextick-args/index.js +45 -0
- package/node_modules/process-nextick-args/license.md +19 -0
- package/node_modules/process-nextick-args/package.json +25 -0
- package/node_modules/process-nextick-args/readme.md +18 -0
- package/node_modules/readable-stream/.travis.yml +34 -0
- package/node_modules/readable-stream/CONTRIBUTING.md +38 -0
- package/node_modules/readable-stream/GOVERNANCE.md +136 -0
- package/node_modules/readable-stream/LICENSE +47 -0
- package/node_modules/readable-stream/README.md +58 -0
- package/node_modules/readable-stream/doc/wg-meetings/2015-01-30.md +60 -0
- package/node_modules/readable-stream/duplex-browser.js +1 -0
- package/node_modules/readable-stream/duplex.js +1 -0
- package/node_modules/readable-stream/lib/_stream_duplex.js +131 -0
- package/node_modules/readable-stream/lib/_stream_passthrough.js +47 -0
- package/node_modules/readable-stream/lib/_stream_readable.js +1019 -0
- package/node_modules/readable-stream/lib/_stream_transform.js +214 -0
- package/node_modules/readable-stream/lib/_stream_writable.js +685 -0
- package/node_modules/readable-stream/lib/internal/streams/BufferList.js +78 -0
- package/node_modules/readable-stream/lib/internal/streams/destroy.js +84 -0
- package/node_modules/readable-stream/lib/internal/streams/stream-browser.js +1 -0
- package/node_modules/readable-stream/lib/internal/streams/stream.js +1 -0
- package/node_modules/readable-stream/package.json +52 -0
- package/node_modules/readable-stream/passthrough.js +1 -0
- package/node_modules/readable-stream/readable-browser.js +7 -0
- package/node_modules/readable-stream/readable.js +19 -0
- package/node_modules/readable-stream/transform.js +1 -0
- package/node_modules/readable-stream/writable-browser.js +1 -0
- package/node_modules/readable-stream/writable.js +8 -0
- package/node_modules/safe-buffer/LICENSE +21 -0
- package/node_modules/safe-buffer/README.md +584 -0
- package/node_modules/safe-buffer/index.d.ts +187 -0
- package/node_modules/safe-buffer/index.js +62 -0
- package/node_modules/safe-buffer/package.json +37 -0
- package/node_modules/setimmediate/LICENSE.txt +20 -0
- package/node_modules/setimmediate/package.json +30 -0
- package/node_modules/setimmediate/setImmediate.js +186 -0
- package/node_modules/string_decoder/.travis.yml +50 -0
- package/node_modules/string_decoder/LICENSE +48 -0
- package/node_modules/string_decoder/README.md +47 -0
- package/node_modules/string_decoder/lib/string_decoder.js +296 -0
- package/node_modules/string_decoder/package.json +31 -0
- package/node_modules/util-deprecate/History.md +16 -0
- package/node_modules/util-deprecate/LICENSE +24 -0
- package/node_modules/util-deprecate/README.md +53 -0
- package/node_modules/util-deprecate/browser.js +67 -0
- package/node_modules/util-deprecate/node.js +6 -0
- package/node_modules/util-deprecate/package.json +27 -0
- package/package.json +6 -4
- /package/node_modules/{p-limit/node_modules/yocto-queue → yocto-queue}/index.d.ts +0 -0
- /package/node_modules/{p-limit/node_modules/yocto-queue → yocto-queue}/index.js +0 -0
- /package/node_modules/{p-limit/node_modules/yocto-queue → yocto-queue}/license +0 -0
- /package/node_modules/{p-limit/node_modules/yocto-queue → yocto-queue}/package.json +0 -0
- /package/node_modules/{p-limit/node_modules/yocto-queue → yocto-queue}/readme.md +0 -0
|
@@ -0,0 +1,658 @@
|
|
|
1
|
+
# Archive extraction
|
|
2
|
+
|
|
3
|
+
`@openclaw/fs-safe/archive` extracts ZIP and TAR archives behind one API, with traversal checks, blocked-link-type rejection, and entry-count and byte budgets. When the native binding is available for the current platform, Rust streams ZIP, TAR, gzip, zstd, and bzip2 while TypeScript remains the sole policy owner; every accepted output is created fd-relative in a private staging root. Extraction then merges through the same safe-open boundary used by direct writes — a symlinked entry can't trick the merge into following an out-of-tree path.
|
|
4
|
+
|
|
5
|
+
TAR admission uses one Rust core compiled into both the native binding and a
|
|
6
|
+
bundled, import-free WebAssembly module. The guarded JavaScript fallback uses
|
|
7
|
+
that module for TAR/gzip and optional `jszip` for ZIP. TAR needs no optional
|
|
8
|
+
parser dependency, runtime download, install script, or consumer Rust toolchain.
|
|
9
|
+
Installs omitting optional dependencies can import every public subpath and use
|
|
10
|
+
TAR/gzip in `auto` or `off`; ZIP fallback still requires `jszip`.
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import { extractArchive, resolveArchiveKind } from "@openclaw/fs-safe/archive";
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## `extractArchive`
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
await extractArchive({
|
|
20
|
+
archivePath: "/srv/uploads/plugin.zip",
|
|
21
|
+
destDir: "/srv/workspace/plugins/plugin",
|
|
22
|
+
kind: "zip", // optional; resolveArchiveKind() can infer
|
|
23
|
+
timeoutMs: 15_000, // hard budget; active destination mutation is joined
|
|
24
|
+
stripComponents: 0, // tar-style strip-leading-dirs
|
|
25
|
+
entryModes: "clamp", // default; use "preserve" for archive rwx bits
|
|
26
|
+
entryFilter: ({ path, kind, size }) => "extract",
|
|
27
|
+
onFiltered: "reject-archive", // default; opt into "skip-entry" explicitly
|
|
28
|
+
limits: {
|
|
29
|
+
maxArchiveBytes: 256 * 1024 * 1024,
|
|
30
|
+
maxEntries: 50_000,
|
|
31
|
+
maxExtractedBytes: 512 * 1024 * 1024,
|
|
32
|
+
maxEntryBytes: 256 * 1024 * 1024,
|
|
33
|
+
maxMetaEntryBytes: 1024 * 1024,
|
|
34
|
+
maxEntryPathComponents: 256,
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Parameters
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
type ExtractArchiveOptions = {
|
|
43
|
+
archivePath: string; // absolute path to the archive
|
|
44
|
+
destDir: string; // absolute destination directory; must already exist
|
|
45
|
+
timeoutMs: number; // positive wall-clock budget; <= 0/non-finite disables it
|
|
46
|
+
kind?: ArchiveKind; // "zip" | "tar" | "tar-zstd" | "tar-bzip2"
|
|
47
|
+
stripComponents?: number; // strip N leading dirs from entry paths
|
|
48
|
+
tarGzip?: boolean; // when archive is .tar.gz/.tgz
|
|
49
|
+
limits?: ArchiveExtractLimits;
|
|
50
|
+
logger?: ArchiveLogger; // { info?, warn? }
|
|
51
|
+
entryModes?: "clamp" | "preserve";
|
|
52
|
+
entryFilter?: (entry: { path: string; kind: ArchiveEntryKind; size: number }) =>
|
|
53
|
+
"extract" | "skip";
|
|
54
|
+
onFiltered?: "reject-archive" | "skip-entry";
|
|
55
|
+
};
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`entryModes` defaults to `"clamp"`: directories become `0o755`; files become
|
|
59
|
+
`0o644`, or `0o755` when the archived owner-execute bit is set. `"preserve"`
|
|
60
|
+
keeps archived read/write/execute bits. Both policies strip setuid, setgid, and
|
|
61
|
+
sticky bits, and neither applies archived ownership. An explicit zero mode,
|
|
62
|
+
including a mode containing only stripped special bits, stays zero under
|
|
63
|
+
`"preserve"`. Absent metadata defaults to `0o644` for files and `0o755` for
|
|
64
|
+
directories; ZIP UNIX creator records with zero attributes are explicit zero,
|
|
65
|
+
while non-UNIX ZIP records use the absent-metadata defaults.
|
|
66
|
+
|
|
67
|
+
TAR mode fields containing only NUL/ASCII-space padding use absent defaults.
|
|
68
|
+
Both backends recognize GNU binary modes, including signed values,
|
|
69
|
+
within JavaScript's safe-integer range before masking permission bits.
|
|
70
|
+
Malformed or unsupported mode fields consistently fall back to zero, matching
|
|
71
|
+
the former native behavior. This replaces JavaScript's decoder-dependent octal
|
|
72
|
+
prefix parsing, defaulting, or rejection for malformed fields. Ordinary octal,
|
|
73
|
+
absent, explicit zero, and supported GNU binary fields retain their behavior.
|
|
74
|
+
|
|
75
|
+
Final modes remain separate from private working staging permissions: files
|
|
76
|
+
stay `0o600` and directories `0o700` until publication. Files receive their final
|
|
77
|
+
mode through the guarded copy's owned writer descriptor. Directories are pinned
|
|
78
|
+
before descending and finalized after their children, including empty and
|
|
79
|
+
restrictive directories. Explicit accepted directory modes win regardless of
|
|
80
|
+
archive order; implicit parents receive `0o755`. Existing destination directories
|
|
81
|
+
also receive the requested final mode. They are never temporarily widened to
|
|
82
|
+
allow child writes; insufficient write/search access still rejects.
|
|
83
|
+
|
|
84
|
+
Directory mode changes use a retained no-follow read descriptor when possible.
|
|
85
|
+
On macOS x64/arm64, read-denied directories can use a retained search descriptor.
|
|
86
|
+
On Linux x64/arm64, the Node-only search route retains an `O_PATH` descriptor and
|
|
87
|
+
changes modes through its exact `/proc/self/fd/N` reference after verifying the
|
|
88
|
+
procfs namespace and followed identity. The descriptor stays open through the
|
|
89
|
+
operation and verification; original root, ancestor and named-directory checks
|
|
90
|
+
still apply. This route trusts host mount-namespace integrity and does not claim
|
|
91
|
+
atomic ancestry checks or protection against privileged mount replacement.
|
|
92
|
+
Readable directories do not depend on procfs. A Linux search-only directory
|
|
93
|
+
needing a mode change requires accessible, genuine procfs; unavailable or
|
|
94
|
+
untrusted authority rejects explicitly instead of silently accepting a wrong
|
|
95
|
+
mode. Other unsupported search-only routes also fail closed. Windows retains
|
|
96
|
+
its existing bounded lack of POSIX mode enforcement.
|
|
97
|
+
|
|
98
|
+
Native extraction is deliberately split into two phases. Rust first reports an
|
|
99
|
+
entry manifest without creating paths. TypeScript validates paths, applies
|
|
100
|
+
`stripComponents`, filters, limits, and mode policy, then passes an explicit
|
|
101
|
+
accepted-entry plan back to Rust. Rust owns raw-stream admission, decompression,
|
|
102
|
+
and fd-relative `mkdirBeneath`/exclusive-open writes. This keeps filter policy identical
|
|
103
|
+
between native and JavaScript paths rather than reimplementing it in Rust.
|
|
104
|
+
|
|
105
|
+
ZIP extraction and bounded reads admit every physical central-directory record and its referenced local header before either decoder can normalize or collapse names. Raw names and valid Unicode Path names must pass traversal checks before stripping, filtering, or selecting a requested member; duplicate or colliding names reject with `entry-path`, even in unrelated or skipped members. Materially conflicting local/central or Unicode interpretations, malformed critical metadata, and ambiguous framing reject with `ArchiveFormatError`. Harmless separator and dot-component equivalence is allowed only after validation. Ordinary legacy filename decoding remains backend-selected.
|
|
106
|
+
|
|
107
|
+
`stripComponents` removes leading nonempty, non-`.` path components after
|
|
108
|
+
normalizing separators. For example, `./pkg/hello.txt` with
|
|
109
|
+
`stripComponents: 1` extracts to `hello.txt` on both backends. Entries with no
|
|
110
|
+
remaining components are skipped before the filter callback, but still count
|
|
111
|
+
toward `maxEntries` and undergo traversal validation. JavaScript TAR extraction
|
|
112
|
+
copies the admitted payload range to this accepted output path, so depth checks,
|
|
113
|
+
collision checks, writes, and mode application agree.
|
|
114
|
+
|
|
115
|
+
An `entryFilter` sees the validated **canonical effective archive path before
|
|
116
|
+
stripping**, entry kind, and declared size. On every JavaScript and native
|
|
117
|
+
ZIP/TAR backend (including gzip and native zstd/bzip2), backslashes become `/`,
|
|
118
|
+
empty and `.` components are removed, and trailing separators are removed from
|
|
119
|
+
directory paths. For example, `./pkg//state\cache/value` is presented as
|
|
120
|
+
`pkg/state/cache/value`, even with `stripComponents: 1`. Case and Unicode
|
|
121
|
+
spelling are preserved. Local PAX `path`, GNU long-name, and supported ZIP
|
|
122
|
+
Unicode Path names use the same canonicalization.
|
|
123
|
+
|
|
124
|
+
Raw paths undergo traversal, absolute/drive-path, and NUL validation **before**
|
|
125
|
+
canonicalization; normalization cannot turn an unsafe path into an accepted
|
|
126
|
+
one. Stripping and output collision checks use this same canonical identity.
|
|
127
|
+
On Windows, archive admission also rejects reserved device segments such as
|
|
128
|
+
`NUL`, `CON.txt`, and `nul .txt` with `ArchiveSecurityError("entry-path")`,
|
|
129
|
+
before extraction or bounded member reads. Ignored trailing spaces in the stem
|
|
130
|
+
before an extension do not bypass this check. Ordinary members with these names
|
|
131
|
+
remain valid on POSIX; this is a host-specific device guard, not a portable-name
|
|
132
|
+
restriction.
|
|
133
|
+
Filters that compare exact strings should use canonical pre-strip paths,
|
|
134
|
+
including directory names without a trailing `/`.
|
|
135
|
+
Returning `"skip"` rejects the whole archive unless `onFiltered` is
|
|
136
|
+
explicitly `"skip-entry"`. Runtime values other than `"reject-archive"` and
|
|
137
|
+
`"skip-entry"` reject before extraction starts instead of falling through to
|
|
138
|
+
skip behavior. Path traversal and archive-wide entry-count checks still apply
|
|
139
|
+
to skipped entries.
|
|
140
|
+
`maxEntryBytes` and `maxExtractedBytes` charge only entries accepted after
|
|
141
|
+
stripping and filtering. Skipping a large member does not consume these payload
|
|
142
|
+
budgets. The separate complete-stream decoded limit still applies to all TAR
|
|
143
|
+
content, including skipped or fully stripped members.
|
|
144
|
+
|
|
145
|
+
For example, a fleet restore can omit regenerated cache entries while rejecting
|
|
146
|
+
any other policy mismatch by default:
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
await extractArchive({
|
|
150
|
+
archivePath: snapshotPath,
|
|
151
|
+
destDir: restoreRoot,
|
|
152
|
+
timeoutMs: 30_000,
|
|
153
|
+
entryFilter: ({ path: entryPath, kind }) =>
|
|
154
|
+
kind === "directory" && entryPath === "state/cache"
|
|
155
|
+
? "skip"
|
|
156
|
+
: entryPath.startsWith("state/cache/")
|
|
157
|
+
? "skip"
|
|
158
|
+
: "extract",
|
|
159
|
+
onFiltered: "skip-entry",
|
|
160
|
+
limits: { maxEntries: 50_000, maxEntryPathComponents: 64 },
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
If skipping was not explicitly part of the restore contract, omit
|
|
165
|
+
`onFiltered`; the first `"skip"` then rejects the complete archive with
|
|
166
|
+
`ArchiveSecurityError("entry-filtered")`.
|
|
167
|
+
|
|
168
|
+
Both TAR routes finish bounded admission before TypeScript policy evaluation,
|
|
169
|
+
so a rejected plan never starts extraction. The JavaScript path owns its input,
|
|
170
|
+
decoder, and WASM parser streams, joining their teardown on validation, write,
|
|
171
|
+
or timeout failure.
|
|
172
|
+
|
|
173
|
+
TAR character devices, block devices, and FIFOs are presented to the filter as
|
|
174
|
+
`kind: "other"`. Accepted entries of these types reject with
|
|
175
|
+
`ArchiveSecurityError("entry-link")`; an explicit `"skip-entry"` filter can omit
|
|
176
|
+
them. GNU typeflag `D` (`GNUDumpDir`) is a directory on both backends, including
|
|
177
|
+
its filter kind, canonical path, and directory creation policy. Its declared
|
|
178
|
+
body size follows the existing TAR strip/filter payload budgets; dump contents
|
|
179
|
+
are not restored as files.
|
|
180
|
+
|
|
181
|
+
Unsupported logical TAR records, including volume headers (`V`), Solaris ACL
|
|
182
|
+
records (`A`), inodes (`I`), continuations (`M`), and unrecognized typeflags,
|
|
183
|
+
still undergo entry counting, raw/effective path validation, stripping, depth
|
|
184
|
+
and output collision checks in physical order. Each remaining record reaches
|
|
185
|
+
`entryFilter` once with its canonical pre-strip path, `kind: "other"`, and
|
|
186
|
+
declared effective size. A filter skip rejects with `"entry-filtered"` unless
|
|
187
|
+
`onFiltered: "skip-entry"` is explicit. Accepted unsupported records are safely
|
|
188
|
+
omitted and do not consume output payload budgets. The shared core admits these records explicitly. GNU long names describe one such
|
|
189
|
+
record and are then cleared; local PAX on unsupported types and GNU sparse
|
|
190
|
+
`S` records retain their existing fail-closed format policy.
|
|
191
|
+
|
|
192
|
+
If `kind` is omitted, the helper calls `resolveArchiveKind(archivePath)` and throws if the extension is not recognized. Pass `kind` explicitly when the archive name doesn't carry the type (e.g. content-addressed names). Archive inputs must remain regular files from preview through descriptor admission; POSIX opens are no-follow and nonblocking, so a FIFO swap cannot stall before deadline checks resume. A positive finite `timeoutMs` is a wall-clock budget; zero, negative, `NaN`, and infinity disable the deadline. Non-mutating work rejects promptly when the budget expires. If a live destination mutation is already in flight, rejection waits only for that mutation and any rollback to finish; no later destination mutation can begin.
|
|
193
|
+
|
|
194
|
+
The destination merge is nontransactional: each file is published atomically,
|
|
195
|
+
but completed files and directories can remain when a later copy, post-copy
|
|
196
|
+
check, mode application, or deadline fails. This also applies to
|
|
197
|
+
`mergeExtractedTreeIntoDestination()`. Guarded `Root.copyIn()` owns cleanup for
|
|
198
|
+
its operation; the archive merge does not unlink the current destination name
|
|
199
|
+
on error because it has no publication receipt proving ownership. A failure
|
|
200
|
+
before publication preserves a pre-existing file, and rejection does not grant
|
|
201
|
+
authority to delete a substituted file or alias. Failed extraction does not
|
|
202
|
+
restore overwritten contents. Active destination mutations and their guarded
|
|
203
|
+
cleanup still finish before rejection; no later destination mutation begins.
|
|
204
|
+
New directories whose postorder finalization was never reached can retain their
|
|
205
|
+
private working mode after failure. Failure cleanup closes retained descriptors;
|
|
206
|
+
it does not run a final chmod sweep or roll back the archive. The public merge
|
|
207
|
+
helper still derives modes from its external source tree and must be able to
|
|
208
|
+
read that source; it never chmods an unreadable external source to admit it.
|
|
209
|
+
|
|
210
|
+
### Limits
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
type ArchiveExtractLimits = {
|
|
214
|
+
maxArchiveBytes?: number; // refuse if archivePath stat'd size exceeds this
|
|
215
|
+
maxEntries?: number; // refuse before extracting if entry count > this
|
|
216
|
+
maxExtractedBytes?: number; // cap total payload bytes accepted after strip/filter
|
|
217
|
+
maxEntryBytes?: number; // cap one accepted entry after strip/filter
|
|
218
|
+
maxMetaEntryBytes?: number; // refuse one PAX/GNU metadata body above this
|
|
219
|
+
maxEntryPathComponents?: number; // bound output path depth after stripComponents
|
|
220
|
+
};
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Defaults exist for each (`DEFAULT_MAX_ARCHIVE_BYTES_ZIP`, `DEFAULT_MAX_ENTRIES`, `DEFAULT_MAX_EXTRACTED_BYTES`, `DEFAULT_MAX_ENTRY_BYTES`, `DEFAULT_MAX_META_ENTRY_BYTES`, `DEFAULT_MAX_ENTRY_PATH_COMPONENTS`). An explicit zero remains zero rather than selecting the default. `maxEntries` counts every archive entry, including entries removed by `stripComponents` or an explicit filter. The path-component default is 256. It is evaluated after `stripComponents` and before TypeScript accepts an entry for either JavaScript or native extraction, so rejected entries cannot cause implicit parent-directory creation. The same resolved 1 MiB metadata default applies to the native and WASM core.
|
|
224
|
+
|
|
225
|
+
A limit violation throws `ArchiveLimitError`. Its constant and string code are:
|
|
226
|
+
|
|
227
|
+
| Constant | Code |
|
|
228
|
+
|---|---|
|
|
229
|
+
| `ARCHIVE_SIZE_EXCEEDS_LIMIT` | `archive-size-exceeds-limit` |
|
|
230
|
+
| `ENTRY_COUNT_EXCEEDS_LIMIT` | `archive-entry-count-exceeds-limit` |
|
|
231
|
+
| `EXTRACTED_SIZE_EXCEEDS_LIMIT` | `archive-extracted-size-exceeds-limit` |
|
|
232
|
+
| `DECODED_SIZE_EXCEEDS_LIMIT` | `archive-decoded-size-exceeds-limit` |
|
|
233
|
+
| `ENTRY_EXTRACTED_SIZE_EXCEEDS_LIMIT` | `archive-entry-extracted-size-exceeds-limit` |
|
|
234
|
+
| `META_ENTRY_SIZE_EXCEEDS_LIMIT` | `archive-meta-entry-size-exceeds-limit` |
|
|
235
|
+
| `ENTRY_PATH_COMPONENTS_EXCEEDS_LIMIT` | `archive-entry-path-components-exceeds-limit` |
|
|
236
|
+
| `MANIFEST_SIZE_EXCEEDS_LIMIT` | `archive-manifest-size-exceeds-limit` |
|
|
237
|
+
|
|
238
|
+
`MANIFEST_SIZE_EXCEEDS_LIMIT` is an active internal TAR admission limit, shared
|
|
239
|
+
by JavaScript and native extraction and bounded reads. Each logical member,
|
|
240
|
+
including ignored, filtered, and fully stripped members, charges
|
|
241
|
+
`64 + 2 * UTF-8 byte length of its effective pre-strip path` before emission or
|
|
242
|
+
retention. PAX/GNU metadata headers do not themselves charge a member cost.
|
|
243
|
+
The allowance is independent of `maxArchiveBytes`: derive a per-member path
|
|
244
|
+
allowance of `max(256, min(maxMetaEntryBytes, max(1, maxEntryPathComponents) * 256))`,
|
|
245
|
+
apply the same 64-byte overhead and doubled path cost, multiply by `maxEntries`,
|
|
246
|
+
and cap the total at 64 MiB using saturating arithmetic. Zero and very large
|
|
247
|
+
public limits remain deterministic. There is no public `maxManifestBytes`
|
|
248
|
+
option; this charged manifest budget supplements the decoded and metadata
|
|
249
|
+
limits rather than bounding the complete process heap.
|
|
250
|
+
|
|
251
|
+
Catch and branch on the code to surface a meaningful response to the caller.
|
|
252
|
+
|
|
253
|
+
Entry policy failures throw `ArchiveSecurityError`. Its entry-related codes
|
|
254
|
+
are `"entry-path"`, `"entry-link"`, and `"entry-filtered"`; destination-race
|
|
255
|
+
codes remain `"destination-not-directory"`, `"destination-symlink"`, and
|
|
256
|
+
`"destination-symlink-traversal"`.
|
|
257
|
+
|
|
258
|
+
## What it defends against
|
|
259
|
+
|
|
260
|
+
- **Path traversal:** entries with `..`, absolute paths, NUL bytes, or Windows drive-relative segments such as `C:secret` and `nested/C:secret` are rejected (`ArchiveSecurityError`). On Windows, path segments containing `:` are also rejected as alternate data stream names before either backend writes to the filesystem.
|
|
261
|
+
- **Symlink/hardlink entries:** rejected by default, including ZIP entries whose Unix mode says symlink while their name ends in a slash or their DOS directory bit is set. An explicit `entryFilter` with `onFiltered: "skip-entry"` can omit these entries. Some archives ship symlink/hardlink entries that point outside the destination once resolved; `extractArchive` does not follow them.
|
|
262
|
+
- **Ambiguous output names:** duplicate names and distinct names that collide after `stripComponents`, case normalization, or Unicode normalization are rejected instead of relying on backend- or volume-specific overwrite order.
|
|
263
|
+
- **TOCTOU during merge:** extraction first writes to a private temp dir, then merges into `destDir` using the same boundary checks as `root().write()`. Destination symlink swaps are checked with the selected platform mechanism; non-Linux routes retain the best-effort race window documented in the [security model](security-model.md#containment-guarantees-by-platform).
|
|
264
|
+
- **Zip bombs:** `maxExtractedBytes` and `maxEntryBytes` apply to *post-decompression* bytes, so highly-compressed payloads hit the cap before they exhaust disk.
|
|
265
|
+
- **Corrupt ZIP payloads:** streamed output must match both the central-directory CRC and declared uncompressed size before it can leave private staging.
|
|
266
|
+
- **Gzip container integrity:** every concatenated gzip member must have a complete valid header, body, CRC32, and ISIZE trailer. A completed member may be followed by all-zero compressed-container padding (including system-tar stdout padding), bounded by the original archive-byte limit. The padding must remain zero through physical EOF; nonzero bytes or another member after padding reject. Truncation and corruption reject before publication or selected bytes return on both backends. Compressed padding is separate from decoded TAR EOF and does not bypass its checks.
|
|
267
|
+
- **Slow-loris archives:** `timeoutMs` is a hard wall-clock budget for non-mutating work. Extraction is aborted on overrun; if a destination mutation is already in flight, that mutation and rollback are joined before rejection so archive-controlled publication cannot continue afterward.
|
|
268
|
+
- **Metadata bombs:** a streaming pass-through reader rejects oversized PAX, GNU long-name, and GNU long-link bodies before buffering their bodies. It understands octal and base-256 fixed sizes and validates bounded local PAX bodies before using their size overrides for member framing. Original archive bytes remain unchanged.
|
|
269
|
+
|
|
270
|
+
### Raw TAR framing
|
|
271
|
+
|
|
272
|
+
Extraction and bounded reads admit the complete decoded TAR stream through the
|
|
273
|
+
shared Rust core. This applies to plain TAR,
|
|
274
|
+
gzip, and native-supported zstd/bzip2, without changing native-mode availability
|
|
275
|
+
or fallback policy. The native and WASM builds enforce the same
|
|
276
|
+
framing rules:
|
|
277
|
+
|
|
278
|
+
- Every nonzero header must have a valid unsigned octal checksum, delimited
|
|
279
|
+
within its field. Checksum validation precedes metadata allocation and member
|
|
280
|
+
policy. Fixed name, prefix, and linkname fields require strict UTF-8 and NUL
|
|
281
|
+
padding. Raw hardlink (`1`) and symlink (`2`) headers require a nonempty
|
|
282
|
+
linkname; every other type, including PAX/GNU metadata, requires an empty
|
|
283
|
+
linkname. This check precedes metadata handling and member/filter policy.
|
|
284
|
+
- Directory (`5`), hardlink (`1`), and symlink (`2`) raw headers must declare
|
|
285
|
+
zero body bytes, whether or not local PAX metadata is present. Valid zero-size
|
|
286
|
+
links remain subject to the existing link/filter policy.
|
|
287
|
+
- EOF requires two consecutive, complete 512-byte zero blocks at a header
|
|
288
|
+
boundary. A header after just one zero block, a missing/partial EOF marker,
|
|
289
|
+
and any nonzero bytes after EOF reject. Additional zero padding after EOF may
|
|
290
|
+
have any byte length within the decoded ceiling; zero blocks inside a declared
|
|
291
|
+
member body are payload.
|
|
292
|
+
- Headers and padded bodies must be complete. Size fields accept unsigned
|
|
293
|
+
octal with ASCII-space/NUL padding or supported positive base-256 encoding;
|
|
294
|
+
malformed numbers and non-padding bytes after a NUL reject. Raw sizes and
|
|
295
|
+
padded sizes must fit `Number.MAX_SAFE_INTEGER`, even with PAX overrides,
|
|
296
|
+
before member budgets are considered.
|
|
297
|
+
|
|
298
|
+
Framing failures use `ArchiveFormatError("archive-header-invalid")`, except
|
|
299
|
+
invalid UTF-8 or nonzero bytes after the first NUL in fixed name, linkname,
|
|
300
|
+
and USTAR prefix fields, which use `ArchiveSecurityError("entry-path")`.
|
|
301
|
+
Missing linknames on links and nonempty linknames on non-links still use the
|
|
302
|
+
format error. PAX `x` and GNU long-name/long-link `L`/`K` payloads retain their
|
|
303
|
+
existing support and metadata limits; the zero-body rule is not applied to all
|
|
304
|
+
non-regular types.
|
|
305
|
+
PAX effective sizes determine regular-member framing. Admission preserves input
|
|
306
|
+
bytes and emits an ordered manifest with exact effective names, types, modes,
|
|
307
|
+
sizes, and decoded payload offsets. TypeScript owns filtering, stripping,
|
|
308
|
+
collisions, permissions, and accepted-output limits. Executors replay admitted
|
|
309
|
+
ranges from the immutable staged input; no second TAR parser interprets PAX,
|
|
310
|
+
GNU names, or payload lengths. Native writes remain descriptor-relative;
|
|
311
|
+
JavaScript writes use the shared guarded private staging and pinned-write helpers.
|
|
312
|
+
|
|
313
|
+
Original member names and USTAR prefixes are validated even when overridden.
|
|
314
|
+
Non-padding bytes after a fixed path field's NUL terminator reject. The core
|
|
315
|
+
enforces the 255-byte component ceiling under NFC and NFD, including Hangul
|
|
316
|
+
expansion. Every replay drains and validates physical EOF before publication or
|
|
317
|
+
returning selected bytes. Unrequested, filtered, and stripped members cannot
|
|
318
|
+
bypass validation. Decompression remains streaming; no complete decoded archive
|
|
319
|
+
is retained in memory or written to a decoded spool.
|
|
320
|
+
|
|
321
|
+
The WASM transport has a fixed 64 KiB input buffer, one pending member event,
|
|
322
|
+
and a 256 MiB maximum linear memory per isolated parser instance. Metadata is
|
|
323
|
+
bounded before allocation; allocation failure rejects. Stream backpressure
|
|
324
|
+
bounds queued chunks, and completion/error destroys the instance's parser
|
|
325
|
+
state. The manifest retains the existing charged budget below; linear memory
|
|
326
|
+
is an additional execution resource bound, not a new public limit option.
|
|
327
|
+
|
|
328
|
+
The raw meter enforces `maxEntries` before consuming each logical member's body,
|
|
329
|
+
including members later skipped by filtering or stripping. PAX/GNU metadata
|
|
330
|
+
headers do not count as members; their payloads use `maxMetaEntryBytes`.
|
|
331
|
+
The meter does not receive `maxEntryBytes` or `maxExtractedBytes`: those payload
|
|
332
|
+
budgets apply only after strip/filter acceptance, using declared effective
|
|
333
|
+
sizes and excluding block padding. JavaScript's entry checker and the native
|
|
334
|
+
accepted-plan builder retain this shared policy. Every TAR admission/parser
|
|
335
|
+
pass has a separate absolute decoded ceiling:
|
|
336
|
+
`maxExtractedBytes + maxArchiveBytes`, safely clamped to
|
|
337
|
+
`Number.MAX_SAFE_INTEGER` (768 MiB with defaults). It counts every admitted
|
|
338
|
+
decoded byte: headers, bodies, metadata, all block padding, both EOF blocks,
|
|
339
|
+
and zero padding after EOF. It bounds complete decoding before parser policy,
|
|
340
|
+
including all filtered/stripped content; cumulative metadata and zero tails
|
|
341
|
+
cannot bypass this bound. Exceeding this ceiling throws
|
|
342
|
+
`ArchiveLimitError("archive-decoded-size-exceeds-limit")`.
|
|
343
|
+
|
|
344
|
+
The same TypeScript helper derives the ceiling for JavaScript and every native
|
|
345
|
+
TAR pass. Before selecting a backend, it caps internal metadata/decoded limits at
|
|
346
|
+
`Number.MAX_SAFE_INTEGER` and logical entry counts at `2^32 - 1`. Larger finite
|
|
347
|
+
options such as `Number.MAX_VALUE` remain valid; high-level payload budgets keep
|
|
348
|
+
their large values. The decoded ceiling uses clamped `maxExtractedBytes` and
|
|
349
|
+
archive overhead with safe addition. Ordinary limits, including
|
|
350
|
+
zero and the existing defaulting/rounding rules, retain their behavior.
|
|
351
|
+
There is no new public option. This is an absolute decoded admission
|
|
352
|
+
cap, not a decompression-ratio policy; bounded stream/codec read-ahead remains.
|
|
353
|
+
There is no independent TAR parser decompression-ratio threshold.
|
|
354
|
+
|
|
355
|
+
### Bounded local PAX support
|
|
356
|
+
|
|
357
|
+
Extraction and single-entry reads accept one nonempty local POSIX `x` header
|
|
358
|
+
(USTAR or GNU header format) immediately before one regular/contiguous file,
|
|
359
|
+
directory, symlink, or hardlink. `path`, `linkpath`, and `size` override that
|
|
360
|
+
member only. Effective paths still pass traversal validation before stripping,
|
|
361
|
+
then the output paths pass depth and collision checks. The filter receives the
|
|
362
|
+
canonical effective pre-strip path, followed by link policy checks. PAX never
|
|
363
|
+
permits link creation. Effective sizes drive framing, filters, and the existing output-byte
|
|
364
|
+
budgets; `maxEntries` still counts members, not their metadata headers.
|
|
365
|
+
|
|
366
|
+
Records must have exact byte lengths, ASCII keys, a final newline, and no
|
|
367
|
+
duplicate keys or unconsumed bytes. `path` and `linkpath` must be nonempty strict
|
|
368
|
+
UTF-8 without NUL. Unicode, a leading BOM, numeric-looking names, and embedded
|
|
369
|
+
newlines preserve their exact spelling; newlines inside a byte-counted value
|
|
370
|
+
are data. Windows filesystem filename restrictions still apply during creation.
|
|
371
|
+
Ownership names retain the existing nonempty printable-ASCII contract. Raw name,
|
|
372
|
+
USTAR prefix, and link fields still require strict UTF-8 and NUL padding even
|
|
373
|
+
when metadata overrides them. Raw link targets must be present only on links.
|
|
374
|
+
`size`, `uid`, and `gid`
|
|
375
|
+
must be canonical unsigned decimal safe integers (zero is valid; signs, leading
|
|
376
|
+
zeros, fractions, and exponents are not). Padded member sizes must also fit the
|
|
377
|
+
safe integer range. Raw and effective directory/link sizes must both be zero;
|
|
378
|
+
non-directory paths ending with a separator and `linkpath` on non-links are
|
|
379
|
+
rejected rather than allowing parser-specific type or framing changes.
|
|
380
|
+
|
|
381
|
+
The descriptive allowlist is `mtime`, `atime`, `ctime` (signed decimal seconds
|
|
382
|
+
with optional fractional digits, within JavaScript's Date range), `uid`, `gid`,
|
|
383
|
+
`uname`, and `gname`. These attributes are accepted but not restored to the
|
|
384
|
+
destination. `LIBARCHIVE.xattr.*` and `SCHILY.xattr.*` with nonempty ASCII
|
|
385
|
+
alphanumeric/dot/underscore/hyphen suffixes are also accepted as inert metadata,
|
|
386
|
+
never restored as extended attributes. Their values are byte-counted and may
|
|
387
|
+
contain NUL, non-UTF8 bytes, or newlines, including macOS provenance metadata.
|
|
388
|
+
|
|
389
|
+
Global `g`, old `X`, old GNU `N`, empty/dangling/repeated local headers, mixed
|
|
390
|
+
PAX/GNU extension chains, unknown keys, charset declarations, ACL extensions,
|
|
391
|
+
and all sparse extensions (including `GNU.sparse.*`, `SCHILY.filetype`,
|
|
392
|
+
`SCHILY.realsize`, and `SCHILY.size`) fail closed with
|
|
393
|
+
`ArchiveFormatError("archive-header-invalid")`. GNU sparse extension blocks are still
|
|
394
|
+
metered in 512-byte units before rejection, preserving metadata-limit errors
|
|
395
|
+
for excessive chains. The per-body `maxMetaEntryBytes` limit bounds PAX storage
|
|
396
|
+
and duplicate-key state; one local header per member prevents local metadata
|
|
397
|
+
chains without introducing a new limit or changing defaults.
|
|
398
|
+
|
|
399
|
+
### Bounded GNU long names and links
|
|
400
|
+
|
|
401
|
+
The shared core buffers GNU long-name `L` and long-link `K` bodies within
|
|
402
|
+
`maxMetaEntryBytes`. A body must contain a nonempty
|
|
403
|
+
UTF-8 name, with either no NUL or exactly one terminal NUL. Embedded NULs,
|
|
404
|
+
additional terminal NULs, bytes after a NUL, and invalid UTF-8 reject with
|
|
405
|
+
`ArchiveFormatError("archive-header-invalid")`. The core preserves original
|
|
406
|
+
archive bytes, including the optional terminator and block padding.
|
|
407
|
+
|
|
408
|
+
One logical member may have at most one `L` and one `K`, in either order.
|
|
409
|
+
Repeated metadata of either kind, mixed PAX/GNU chains in either direction,
|
|
410
|
+
and GNU metadata without a following member reject with the same format error.
|
|
411
|
+
Pending metadata is cleared only when its described member is admitted;
|
|
412
|
+
metadata records do not count toward `maxEntries`.
|
|
413
|
+
|
|
414
|
+
An `L` name undergoes raw-path validation before parser normalization, stripping,
|
|
415
|
+
or filtering; unsafe paths reject with `ArchiveSecurityError("entry-path")`.
|
|
416
|
+
The validated name remains pending until its described header arrives. An
|
|
417
|
+
effective name ending in `/` or `\` requires raw directory type `5` or `D`;
|
|
418
|
+
other types reject with `ArchiveFormatError` before filtering, preventing the
|
|
419
|
+
parsers from disagreeing about a member's type.
|
|
420
|
+
`K` validates encoding and NUL structure without authorizing link creation.
|
|
421
|
+
Normal link/filter policy still governs the described member. Canonical
|
|
422
|
+
pre-strip filter paths, decoded-stream ceilings, and physical EOF checks apply
|
|
423
|
+
to plain/gzip TAR and native zstd/bzip2 alike.
|
|
424
|
+
|
|
425
|
+
## `inspectTarArchive`
|
|
426
|
+
|
|
427
|
+
Inspect accepted TAR members without creating an extracted tree. This operation
|
|
428
|
+
uses the same complete Rust/WASM admission and TypeScript extraction planner as
|
|
429
|
+
`extractArchive`, with zero stripping. It detects plain TAR or gzip from the
|
|
430
|
+
input bytes; ZIP, zstd, and bzip2 are not part of this inspection API.
|
|
431
|
+
|
|
432
|
+
```ts
|
|
433
|
+
import { inspectTarArchive } from "@openclaw/fs-safe/archive";
|
|
434
|
+
|
|
435
|
+
const entries = await inspectTarArchive({
|
|
436
|
+
archivePath: "/srv/uploads/tree.tar.gz",
|
|
437
|
+
timeoutMs: 30_000,
|
|
438
|
+
limits: {
|
|
439
|
+
maxArchiveBytes: 16 * 1024 * 1024,
|
|
440
|
+
maxEntries: 5_000,
|
|
441
|
+
maxEntryBytes: 16 * 1024 * 1024,
|
|
442
|
+
maxExtractedBytes: 64 * 1024 * 1024,
|
|
443
|
+
},
|
|
444
|
+
entryFilter: ({ kind }) => kind === "file" || kind === "directory" ? "extract" : "skip",
|
|
445
|
+
onFiltered: "reject-archive",
|
|
446
|
+
});
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
`InspectTarArchiveOptions` accepts `archivePath`, `timeoutMs`, `limits`,
|
|
450
|
+
`entryFilter`, and `onFiltered`, with the same defaults and error classes as
|
|
451
|
+
extraction. The result is a frozen array of frozen `InspectedTarEntry` records:
|
|
452
|
+
`{ path: string; kind: "file" | "directory"; size: number }`, in archive order.
|
|
453
|
+
`size` is the effective declared payload length. `path` is extraction's
|
|
454
|
+
canonical pre-strip identity: case, Unicode spelling, BOM, and embedded LF are
|
|
455
|
+
preserved, while separators and dot components follow the existing archive path
|
|
456
|
+
contract. No human-readable tar listing or escape decoding is involved.
|
|
457
|
+
|
|
458
|
+
Full framing, gzip integrity, EOF, metadata, decoded-byte, and manifest-budget
|
|
459
|
+
validation finishes before the caller's filter runs. The shared planner then
|
|
460
|
+
applies traversal, collision, depth, blocked-type, and accepted-payload limits.
|
|
461
|
+
A failure returns no partial result. Filter callbacks are decisions, not admission
|
|
462
|
+
receipts: later policy, collision, or budget checks can still reject the archive.
|
|
463
|
+
Only the resolved Promise/result is authorization-worthy; do not perform
|
|
464
|
+
irreversible actions from a filter callback.
|
|
465
|
+
|
|
466
|
+
Root-only records count toward entry limits but produce no result; PAX/GNU metadata headers are not members. Only accepted
|
|
467
|
+
file/directory members appear, not implicit parent directories. Unsupported
|
|
468
|
+
records follow extraction's omission policy unless the filter rejects them, as
|
|
469
|
+
in the example. AppleDouble records encoded as ordinary files are ordinary
|
|
470
|
+
members, not hidden metadata.
|
|
471
|
+
|
|
472
|
+
Inspection pins and privately stages its input, then cleans up that copy. It
|
|
473
|
+
neither creates destination paths nor tests destination permissions or platform
|
|
474
|
+
filename restrictions. Its result is evidence about those inspected bytes, not
|
|
475
|
+
an extraction capability or a promise that a later file at `archivePath` is
|
|
476
|
+
unchanged. Callers making authorization decisions must retain the same private
|
|
477
|
+
immutable archive or verify byte identity before extracting with matching
|
|
478
|
+
filter/limit settings. Extraction always performs its own admission and guarded
|
|
479
|
+
publication. Native `off`, `auto`, and `require` retain their existing selection
|
|
480
|
+
and availability semantics; inspection does not fall back after native failure.
|
|
481
|
+
|
|
482
|
+
## `resolveArchiveKind`
|
|
483
|
+
|
|
484
|
+
```ts
|
|
485
|
+
import { resolveArchiveKind, type ArchiveKind } from "@openclaw/fs-safe/archive";
|
|
486
|
+
|
|
487
|
+
const kind = resolveArchiveKind("upload.zip"); // "zip"
|
|
488
|
+
const tar = resolveArchiveKind("upload.tar.gz"); // "tar"
|
|
489
|
+
const zstd = resolveArchiveKind("upload.tar.zst"); // "tar-zstd" when native is available
|
|
490
|
+
const unknown = resolveArchiveKind("upload.bin"); // null
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
Recognizes:
|
|
494
|
+
|
|
495
|
+
- `*.zip` → `"zip"`
|
|
496
|
+
- `*.tar`, `*.tar.gz`, `*.tgz` → `"tar"`
|
|
497
|
+
- `*.tar.zst`, `*.tar.zstd`, `*.tzst` → `"tar-zstd"` (native only)
|
|
498
|
+
- `*.tar.bz2`, `*.tbz2`, `*.tbz` → `"tar-bzip2"` (native only)
|
|
499
|
+
|
|
500
|
+
Returns `null` for unknown extensions; check the result before calling
|
|
501
|
+
`extractArchive` if the filename is caller-controlled. A recognized zstd or
|
|
502
|
+
bzip2 TAR extension with no native binding throws the typed
|
|
503
|
+
`FsSafeError("helper-unavailable")` with installation guidance. This includes
|
|
504
|
+
`mode: "off"`; those two formats have no JavaScript fallback.
|
|
505
|
+
|
|
506
|
+
For a service whose input contract requires zstd, configure native mode before
|
|
507
|
+
the first archive call so a packaging mistake fails at the boundary:
|
|
508
|
+
|
|
509
|
+
```ts
|
|
510
|
+
import { configureFsSafeNative } from "@openclaw/fs-safe/config";
|
|
511
|
+
import { extractArchive } from "@openclaw/fs-safe/archive";
|
|
512
|
+
|
|
513
|
+
configureFsSafeNative({ mode: "require" });
|
|
514
|
+
await extractArchive({
|
|
515
|
+
archivePath: "/srv/restore/snapshot.tar.zst",
|
|
516
|
+
destDir: "/srv/restore/staging",
|
|
517
|
+
kind: "tar-zstd",
|
|
518
|
+
timeoutMs: 60_000,
|
|
519
|
+
});
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
## `readArchiveEntry`
|
|
523
|
+
|
|
524
|
+
`readArchiveEntry(archivePath, entryPath, { maxBytes, kind? })` reads one
|
|
525
|
+
regular-file entry into a bounded `Buffer` without extracting a tree. It pins
|
|
526
|
+
and privately stages the archive input, rejects link, directory, and duplicate
|
|
527
|
+
entries, verifies ZIP CRC and declared size,
|
|
528
|
+
and throws `ArchiveLimitError` if the requested entry's output exceeds
|
|
529
|
+
`maxBytes`. ZIP output within that cap must match the declared uncompressed
|
|
530
|
+
size exactly; either a shorter or longer payload throws
|
|
531
|
+
`ArchiveFormatError("archive-header-invalid")` before bytes are returned on
|
|
532
|
+
both JavaScript and native backends.
|
|
533
|
+
For TAR, `maxBytes` applies only to that requested entry: a larger
|
|
534
|
+
unrequested member remains valid within the default archive admission limits.
|
|
535
|
+
TAR traversal uses default entry-count, compressed-input, and metadata limits,
|
|
536
|
+
plus the 768 MiB decoded ceiling derived from default extracted/archive byte
|
|
537
|
+
limits. It does not apply payload budgets to unrequested members. ZIP
|
|
538
|
+
inputs retain the archive subpath's 256 MiB compressed-input ceiling.
|
|
539
|
+
With a native binding it uses the same Rust decoders as extraction, including
|
|
540
|
+
zstd and bzip2 TAR. Without native it retains the JS ZIP/TAR/gzip implementation.
|
|
541
|
+
|
|
542
|
+
Requested paths and effective member names use extraction's canonical pre-strip
|
|
543
|
+
identity: backslashes become `/`, and repeated separators and `.` components
|
|
544
|
+
are removed after raw-path validation. For example, `./pkg//value` and
|
|
545
|
+
`pkg\value` both address `pkg/value`, including supported GNU/PAX and ZIP
|
|
546
|
+
Unicode Path names. Case and Unicode spelling are preserved. Requests ending
|
|
547
|
+
in `/` or `\` still reject as non-files. Canonical duplicate members reject
|
|
548
|
+
before an unrelated requested entry can be returned.
|
|
549
|
+
|
|
550
|
+
```ts
|
|
551
|
+
const rawManifest = await readArchiveEntry(uploadPath, "package/manifest.json", {
|
|
552
|
+
maxBytes: 64 * 1024,
|
|
553
|
+
});
|
|
554
|
+
const manifest = JSON.parse(rawManifest.toString("utf8")) as PluginManifest;
|
|
555
|
+
validatePluginManifest(manifest);
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
## Lower-level building blocks
|
|
559
|
+
|
|
560
|
+
The archive subpath also exports the helpers `extractArchive` is built on. Most callers will not need them, but they are stable and documented:
|
|
561
|
+
|
|
562
|
+
| Function | Purpose |
|
|
563
|
+
|---|---|
|
|
564
|
+
| `withStagedArchiveDestination(opts)` | Creates a private staging dir outside the destination, calls your `run(stagingDir)`, then cleans it up. |
|
|
565
|
+
| `mergeExtractedTreeIntoDestination(opts)` | The merge step alone — staged tree → destination through boundary checks. |
|
|
566
|
+
| `prepareArchiveDestinationDir(destDir)` | Canonicalizes and asserts the destination directory. |
|
|
567
|
+
| `prepareArchiveOutputPath({ destinationDir, destinationRealDir, relPath, outPath, originalPath, isDirectory, deadline? })` | Validates and prepares parents for an already-resolved entry output path. |
|
|
568
|
+
| `loadZipArchiveWithPreflight(buffer, limits?)` | Loads a JSZip from a `Buffer` or `Uint8Array` with size/entry-count preflight before unzipping. |
|
|
569
|
+
| `readZipCentralDirectoryEntryCount(buffer)` | Returns the entry count from an already-loaded ZIP `Buffer` or `Uint8Array` without decoding payloads. |
|
|
570
|
+
| `createTarEntryPreflightChecker(opts)` | Returns a per-entry checker for use as a `tar.x` `onReadEntry` hook. |
|
|
571
|
+
|
|
572
|
+
These let you build custom extractors that share the same safety machinery — for example, a streaming uploader that wants to refuse archives with too many entries before reading any payloads.
|
|
573
|
+
|
|
574
|
+
## Path helpers
|
|
575
|
+
|
|
576
|
+
`archive-entry` exports a handful of low-level helpers for entry-path normalization:
|
|
577
|
+
|
|
578
|
+
```ts
|
|
579
|
+
import {
|
|
580
|
+
isWindowsDrivePath,
|
|
581
|
+
normalizeArchiveEntryPath,
|
|
582
|
+
resolveArchiveOutputPath,
|
|
583
|
+
stripArchivePath,
|
|
584
|
+
validateArchiveEntryPath,
|
|
585
|
+
} from "@openclaw/fs-safe/archive";
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
- `validateArchiveEntryPath(raw, opts)` — throws `ArchiveSecurityError` for `..`, absolute, NUL-containing, drive-relative, or otherwise unsafe entry paths, including alternate data stream names on Windows.
|
|
589
|
+
- `normalizeArchiveEntryPath(raw)` — converts backslashes in the entry path to forward slashes.
|
|
590
|
+
- `stripArchivePath(entryPath, n)` — normalize separators, drop empty and `.` components, then strip the leading N components, returning `null` if none remain.
|
|
591
|
+
- `resolveArchiveOutputPath({ rootDir, relPath, originalPath, escapeLabel? })` — combines the validated relative path with the root and rejects escapes using the original archive path for diagnostics.
|
|
592
|
+
- `isWindowsDrivePath(value)` — detects drive-relative segments such as `C:secret` or `nested/C:secret` that should be rejected.
|
|
593
|
+
|
|
594
|
+
Validate attacker-controlled paths before calling normalization or stripping
|
|
595
|
+
helpers. After validation, `stripArchivePath(entryPath, 0)` returns the canonical
|
|
596
|
+
pre-strip identity used by extraction filters (or `null` for an empty path).
|
|
597
|
+
|
|
598
|
+
## Common patterns
|
|
599
|
+
|
|
600
|
+
### Extract an upload, surface budget violations
|
|
601
|
+
|
|
602
|
+
```ts
|
|
603
|
+
import { extractArchive, ArchiveLimitError, ARCHIVE_LIMIT_ERROR_CODE } from "@openclaw/fs-safe/archive";
|
|
604
|
+
|
|
605
|
+
try {
|
|
606
|
+
await extractArchive({
|
|
607
|
+
archivePath: upload.path,
|
|
608
|
+
destDir: targetDir,
|
|
609
|
+
kind: "zip",
|
|
610
|
+
timeoutMs: 30_000,
|
|
611
|
+
limits: {
|
|
612
|
+
maxArchiveBytes: 100 * 1024 * 1024,
|
|
613
|
+
maxEntries: 10_000,
|
|
614
|
+
maxExtractedBytes: 200 * 1024 * 1024,
|
|
615
|
+
maxEntryBytes: 50 * 1024 * 1024,
|
|
616
|
+
},
|
|
617
|
+
});
|
|
618
|
+
} catch (err) {
|
|
619
|
+
if (err instanceof ArchiveLimitError) {
|
|
620
|
+
return reply(413, { code: err.code, message: err.message });
|
|
621
|
+
}
|
|
622
|
+
throw err;
|
|
623
|
+
}
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
### Decide kind from MIME, not filename
|
|
627
|
+
|
|
628
|
+
```ts
|
|
629
|
+
const kind: ArchiveKind = mime === "application/zip" ? "zip" : "tar";
|
|
630
|
+
await extractArchive({ archivePath, destDir, kind, timeoutMs: 10_000 });
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
### Stage to private dir, then commit as a directory
|
|
634
|
+
|
|
635
|
+
```ts
|
|
636
|
+
import { withTempWorkspace } from "@openclaw/fs-safe/temp";
|
|
637
|
+
import { replaceDirectoryAtomic } from "@openclaw/fs-safe/atomic";
|
|
638
|
+
|
|
639
|
+
await withTempWorkspace({ rootDir: "/srv/site/tmp", prefix: "extract-" }, async (ws) => {
|
|
640
|
+
await extractArchive({
|
|
641
|
+
archivePath: upload.path,
|
|
642
|
+
destDir: ws.dir,
|
|
643
|
+
timeoutMs: 30_000,
|
|
644
|
+
});
|
|
645
|
+
await replaceDirectoryAtomic({
|
|
646
|
+
stagedDir: ws.dir,
|
|
647
|
+
targetDir: "/srv/site/plugin",
|
|
648
|
+
});
|
|
649
|
+
});
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
## See also
|
|
653
|
+
|
|
654
|
+
- [Atomic writes](atomic.md) — `replaceDirectoryAtomic` for staged directory replacement.
|
|
655
|
+
- [Temp workspaces](temp.md) — extract into a private workspace and commit as one step.
|
|
656
|
+
- [Errors](errors.md) — `FsSafeError` codes the underlying writes can raise.
|
|
657
|
+
- [Migrating to 0.5](migrating-to-0.5.md) — clamp-default and native-format upgrade checklist.
|
|
658
|
+
- [`extractArchive` source](https://github.com/openclaw/fs-safe/blob/main/src/archive.ts).
|
|
Binary file
|