@openclaw/fs-safe 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +134 -0
- package/LICENSE +1 -0
- package/README.md +52 -4
- package/dist/absolute-path.d.ts.map +1 -1
- package/dist/absolute-path.js +3 -2
- package/dist/advanced.d.ts +5 -0
- package/dist/advanced.d.ts.map +1 -1
- package/dist/advanced.js +5 -0
- package/dist/archive-crc32.d.ts.map +1 -1
- package/dist/archive-crc32.js +6 -1
- package/dist/archive-deadline.d.ts.map +1 -1
- package/dist/archive-deadline.js +3 -4
- package/dist/archive-durability.d.ts +6 -6
- package/dist/archive-durability.d.ts.map +1 -1
- package/dist/archive-durability.js +1 -1
- package/dist/archive-entry.d.ts.map +1 -1
- package/dist/archive-entry.js +4 -5
- package/dist/archive-gzip-tail.d.ts +3 -0
- package/dist/archive-gzip-tail.d.ts.map +1 -1
- package/dist/archive-gzip-tail.js +23 -3
- package/dist/archive-input.d.ts.map +1 -1
- package/dist/archive-input.js +4 -2
- package/dist/archive-merge.d.ts +5 -1
- package/dist/archive-merge.d.ts.map +1 -1
- package/dist/archive-merge.js +16 -13
- package/dist/archive-native.d.ts.map +1 -1
- package/dist/archive-native.js +7 -6
- package/dist/archive-parser.wasm +0 -0
- package/dist/archive-read.d.ts.map +1 -1
- package/dist/archive-read.js +83 -74
- package/dist/archive-staging.d.ts +6 -3
- package/dist/archive-staging.d.ts.map +1 -1
- package/dist/archive-staging.js +42 -22
- package/dist/archive-tar-stream.d.ts +11 -4
- package/dist/archive-tar-stream.d.ts.map +1 -1
- package/dist/archive-tar-stream.js +23 -10
- package/dist/archive-tar-wasm.d.ts.map +1 -1
- package/dist/archive-tar-wasm.js +18 -14
- package/dist/archive-zip-admission.d.ts +1 -1
- package/dist/archive-zip-admission.d.ts.map +1 -1
- package/dist/archive-zip-admission.js +48 -12
- package/dist/archive-zip-loader.d.ts +6 -0
- package/dist/archive-zip-loader.d.ts.map +1 -0
- package/dist/archive-zip-loader.js +38 -0
- package/dist/archive-zip-names.d.ts.map +1 -1
- package/dist/archive-zip-names.js +13 -8
- package/dist/archive-zip-preflight.d.ts +2 -3
- package/dist/archive-zip-preflight.d.ts.map +1 -1
- package/dist/archive-zip-preflight.js +2 -34
- package/dist/archive.d.ts.map +1 -1
- package/dist/archive.js +12 -10
- package/dist/bounded-read.d.ts +12 -0
- package/dist/bounded-read.d.ts.map +1 -1
- package/dist/bounded-read.js +82 -45
- package/dist/clone-metadata.d.ts +19 -0
- package/dist/clone-metadata.d.ts.map +1 -0
- package/dist/clone-metadata.js +32 -0
- package/dist/copy-file-input.d.ts +22 -0
- package/dist/copy-file-input.d.ts.map +1 -0
- package/dist/copy-file-input.js +69 -0
- package/dist/copy-policy.d.ts +3 -0
- package/dist/copy-policy.d.ts.map +1 -0
- package/dist/copy-policy.js +8 -0
- package/dist/copy-publication.d.ts +10 -1
- package/dist/copy-publication.d.ts.map +1 -1
- package/dist/copy-publication.js +27 -0
- package/dist/copy-tree-portable.d.ts +9 -0
- package/dist/copy-tree-portable.d.ts.map +1 -0
- package/dist/copy-tree-portable.js +222 -0
- package/dist/copy.d.ts +16 -0
- package/dist/copy.d.ts.map +1 -0
- package/dist/copy.js +125 -0
- package/dist/directory-durability.d.ts.map +1 -1
- package/dist/directory-durability.js +5 -4
- package/dist/directory-guard.d.ts +11 -1
- package/dist/directory-guard.d.ts.map +1 -1
- package/dist/directory-guard.js +53 -11
- package/dist/durability.d.ts +1 -1
- package/dist/durability.d.ts.map +1 -1
- package/dist/durability.js +1 -1
- package/dist/error-detail.d.ts.map +1 -1
- package/dist/error-detail.js +4 -1
- package/dist/file-handle-transfer.d.ts +14 -0
- package/dist/file-handle-transfer.d.ts.map +1 -0
- package/dist/file-handle-transfer.js +64 -0
- package/dist/file-hash.d.ts +9 -2
- package/dist/file-hash.d.ts.map +1 -1
- package/dist/file-hash.js +135 -39
- package/dist/file-lock-sync.d.ts.map +1 -1
- package/dist/file-lock-sync.js +8 -4
- package/dist/file-store-boundary.d.ts.map +1 -1
- package/dist/file-store-boundary.js +7 -5
- package/dist/file-store-path.d.ts +3 -0
- package/dist/file-store-path.d.ts.map +1 -0
- package/dist/file-store-path.js +27 -0
- package/dist/file-store-prune.d.ts.map +1 -1
- package/dist/file-store-prune.js +6 -4
- package/dist/file-store-sync-write.d.ts.map +1 -1
- package/dist/file-store-sync-write.js +56 -44
- package/dist/file-store.d.ts.map +1 -1
- package/dist/file-store.js +2 -18
- package/dist/filename.d.ts.map +1 -1
- package/dist/filename.js +4 -13
- package/dist/guarded-mkdir.d.ts +1 -0
- package/dist/guarded-mkdir.d.ts.map +1 -1
- package/dist/guarded-mkdir.js +4 -2
- package/dist/guarded-mutation.d.ts +2 -0
- package/dist/guarded-mutation.d.ts.map +1 -1
- package/dist/guarded-mutation.js +8 -4
- package/dist/guest-dispatch-python.d.ts +2 -0
- package/dist/guest-dispatch-python.d.ts.map +1 -0
- package/dist/guest-dispatch-python.js +117 -0
- package/dist/guest-native-python.d.ts +4 -0
- package/dist/guest-native-python.d.ts.map +1 -0
- package/dist/guest-native-python.js +135 -0
- package/dist/guest.d.ts +9 -0
- package/dist/guest.d.ts.map +1 -0
- package/dist/guest.js +413 -0
- package/dist/home-dir.d.ts.map +1 -1
- package/dist/home-dir.js +9 -7
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/install-path.d.ts.map +1 -1
- package/dist/install-path.js +5 -8
- package/dist/json-durable-queue-directory.js +3 -3
- package/dist/json-durable-queue.d.ts.map +1 -1
- package/dist/json-durable-queue.js +19 -18
- package/dist/json.d.ts.map +1 -1
- package/dist/json.js +2 -1
- package/dist/local-roots.d.ts.map +1 -1
- package/dist/local-roots.js +24 -25
- package/dist/move-path-stage.d.ts +8 -0
- package/dist/move-path-stage.d.ts.map +1 -0
- package/dist/move-path-stage.js +56 -0
- package/dist/move-path.d.ts.map +1 -1
- package/dist/move-path.js +30 -34
- package/dist/mutation-authority.d.ts +9 -0
- package/dist/mutation-authority.d.ts.map +1 -0
- package/dist/mutation-authority.js +36 -0
- package/dist/native-binding.d.ts +29 -1
- package/dist/native-binding.d.ts.map +1 -1
- package/dist/native-operations.d.ts +1 -1
- package/dist/native-operations.d.ts.map +1 -1
- package/dist/native-operations.js +11 -5
- package/dist/native-pinned-write-windows.d.ts.map +1 -1
- package/dist/native-pinned-write-windows.js +19 -7
- package/dist/native-pinned-write.d.ts.map +1 -1
- package/dist/native-pinned-write.js +3 -1
- package/dist/native-staged-file.d.ts +3 -3
- package/dist/native-staged-file.d.ts.map +1 -1
- package/dist/native-staged-file.js +35 -8
- package/dist/opened-realpath.d.ts.map +1 -1
- package/dist/opened-realpath.js +5 -4
- package/dist/output.d.ts +2 -0
- package/dist/output.d.ts.map +1 -1
- package/dist/output.js +2 -0
- package/dist/overwrite-file-handle.d.ts +8 -0
- package/dist/overwrite-file-handle.d.ts.map +1 -0
- package/dist/overwrite-file-handle.js +42 -0
- package/dist/path-case.d.ts +7 -0
- package/dist/path-case.d.ts.map +1 -0
- package/dist/path-case.js +136 -0
- package/dist/path.d.ts.map +1 -1
- package/dist/path.js +5 -2
- package/dist/permissions-windows.d.ts +1 -1
- package/dist/permissions-windows.d.ts.map +1 -1
- package/dist/permissions-windows.js +85 -53
- package/dist/pinned-open.d.ts.map +1 -1
- package/dist/pinned-open.js +3 -1
- package/dist/pinned-operation.js +1 -1
- package/dist/pinned-write.d.ts +7 -3
- package/dist/pinned-write.d.ts.map +1 -1
- package/dist/pinned-write.js +51 -30
- package/dist/positional-read.d.ts +9 -0
- package/dist/positional-read.d.ts.map +1 -0
- package/dist/positional-read.js +36 -0
- package/dist/private-temp-workspace.d.ts.map +1 -1
- package/dist/private-temp-workspace.js +6 -4
- package/dist/publish-copy-stage.d.ts +13 -0
- package/dist/publish-copy-stage.d.ts.map +1 -0
- package/dist/publish-copy-stage.js +47 -0
- package/dist/publish-file.d.ts.map +1 -1
- package/dist/publish-file.js +6 -5
- package/dist/realpath.d.ts +4 -0
- package/dist/realpath.d.ts.map +1 -0
- package/dist/realpath.js +43 -0
- package/dist/recursive-mkdir-path.d.ts +3 -0
- package/dist/recursive-mkdir-path.d.ts.map +1 -0
- package/dist/recursive-mkdir-path.js +8 -0
- package/dist/replace-directory.d.ts.map +1 -1
- package/dist/replace-directory.js +2 -1
- package/dist/replace-file-copy-fallback.d.ts.map +1 -1
- package/dist/replace-file-copy-fallback.js +23 -31
- package/dist/replace-file-copy-source.d.ts.map +1 -1
- package/dist/replace-file-copy-source.js +7 -12
- package/dist/replace-file-mode.d.ts +3 -0
- package/dist/replace-file-mode.d.ts.map +1 -0
- package/dist/replace-file-mode.js +10 -0
- package/dist/replace-file-temp-owner.d.ts.map +1 -1
- package/dist/replace-file-temp-owner.js +6 -2
- package/dist/replace-file.d.ts +1 -0
- package/dist/replace-file.d.ts.map +1 -1
- package/dist/replace-file.js +14 -8
- package/dist/root-context.d.ts +3 -0
- package/dist/root-context.d.ts.map +1 -1
- package/dist/root-context.js +53 -28
- package/dist/root-create-input.d.ts +10 -0
- package/dist/root-create-input.d.ts.map +1 -0
- package/dist/root-create-input.js +80 -0
- package/dist/root-directory-list.d.ts +26 -0
- package/dist/root-directory-list.d.ts.map +1 -0
- package/dist/root-directory-list.js +219 -0
- package/dist/root-entries.d.ts +11 -0
- package/dist/root-entries.d.ts.map +1 -0
- package/dist/root-entries.js +61 -0
- package/dist/root-errors.d.ts +6 -5
- package/dist/root-errors.d.ts.map +1 -1
- package/dist/root-errors.js +16 -12
- package/dist/root-file.d.ts +2 -0
- package/dist/root-file.d.ts.map +1 -1
- package/dist/root-file.js +12 -4
- package/dist/root-impl.d.ts +17 -51
- package/dist/root-impl.d.ts.map +1 -1
- package/dist/root-impl.js +358 -234
- package/dist/root-options.d.ts +77 -0
- package/dist/root-options.d.ts.map +1 -0
- package/dist/root-options.js +18 -0
- package/dist/root-path-existing.d.ts +5 -0
- package/dist/root-path-existing.d.ts.map +1 -1
- package/dist/root-path-existing.js +59 -3
- package/dist/root-path-symlink.d.ts.map +1 -1
- package/dist/root-path-symlink.js +3 -2
- package/dist/root-path.d.ts +1 -0
- package/dist/root-path.d.ts.map +1 -1
- package/dist/root-path.js +74 -162
- package/dist/root-paths.d.ts.map +1 -1
- package/dist/root-paths.js +13 -9
- package/dist/root-remove.d.ts +5 -0
- package/dist/root-remove.d.ts.map +1 -0
- package/dist/root-remove.js +286 -0
- package/dist/root-symlink-policy.d.ts +14 -0
- package/dist/root-symlink-policy.d.ts.map +1 -0
- package/dist/root-symlink-policy.js +34 -0
- package/dist/root-walk.d.ts +5 -4
- package/dist/root-walk.d.ts.map +1 -1
- package/dist/root-walk.js +99 -50
- package/dist/root-write-mode.d.ts.map +1 -1
- package/dist/root-write-mode.js +3 -5
- package/dist/root.d.ts +4 -1
- package/dist/root.d.ts.map +1 -1
- package/dist/secret-file.d.ts.map +1 -1
- package/dist/secret-file.js +2 -1
- package/dist/secret-read-async.d.ts.map +1 -1
- package/dist/secret-read-async.js +2 -1
- package/dist/secure-file.d.ts.map +1 -1
- package/dist/secure-file.js +25 -8
- package/dist/secure-temp-dir.d.ts.map +1 -1
- package/dist/secure-temp-dir.js +2 -1
- package/dist/sibling-staged-file.d.ts +1 -0
- package/dist/sibling-staged-file.d.ts.map +1 -1
- package/dist/sibling-staged-file.js +42 -8
- package/dist/sibling-temp.d.ts +2 -0
- package/dist/sibling-temp.d.ts.map +1 -1
- package/dist/sibling-temp.js +6 -4
- package/dist/sidecar-lock-acquire.d.ts.map +1 -1
- package/dist/sidecar-lock-acquire.js +17 -5
- package/dist/sidecar-lock-policy.d.ts +2 -0
- package/dist/sidecar-lock-policy.d.ts.map +1 -1
- package/dist/sidecar-lock-policy.js +20 -1
- package/dist/staged-directory.d.ts.map +1 -1
- package/dist/staged-directory.js +4 -3
- package/dist/temp-cleanup.d.ts.map +1 -1
- package/dist/temp-cleanup.js +3 -2
- package/dist/temp-target.d.ts +14 -12
- package/dist/temp-target.d.ts.map +1 -1
- package/dist/temp-target.js +12 -6
- package/dist/timing.d.ts +1 -0
- package/dist/timing.d.ts.map +1 -1
- package/dist/timing.js +25 -6
- package/dist/trash.d.ts.map +1 -1
- package/dist/trash.js +9 -7
- package/dist/unicode-path.d.ts +3 -0
- package/dist/unicode-path.d.ts.map +1 -0
- package/dist/unicode-path.js +13 -0
- package/dist/walk.d.ts.map +1 -1
- package/dist/walk.js +9 -28
- package/dist/windows-owner.d.ts +9 -12
- package/dist/windows-owner.d.ts.map +1 -1
- package/dist/windows-owner.js +24 -58
- package/dist/write-file-handle.d.ts +7 -0
- package/dist/write-file-handle.d.ts.map +1 -0
- package/dist/write-file-handle.js +26 -0
- package/docs/advanced.md +22 -4
- package/docs/archive.md +44 -9
- package/docs/atomic.md +24 -1
- package/docs/config.md +1 -0
- package/docs/contributing.md +36 -1
- package/docs/copy.md +155 -0
- package/docs/directory-identity.md +85 -0
- package/docs/durability.md +53 -3
- package/docs/entries.md +109 -0
- package/docs/errors.md +4 -4
- package/docs/file-store.md +15 -0
- package/docs/guest.md +141 -0
- package/docs/in-place-write.md +81 -0
- package/docs/index.md +2 -0
- package/docs/install.md +31 -0
- package/docs/local-roots.md +8 -1
- package/docs/native-helper.md +10 -3
- package/docs/native.md +18 -1
- package/docs/output.md +32 -6
- package/docs/path-case.md +64 -0
- package/docs/path-scope.md +1 -1
- package/docs/permissions.md +29 -10
- package/docs/positional-read.md +63 -0
- package/docs/public-api.md +31 -2
- package/docs/root.md +196 -6
- package/docs/secure-file.md +2 -0
- package/docs/security-model.md +14 -0
- package/docs/sidecar-lock.md +12 -3
- package/docs/temp.md +35 -6
- package/docs/timing.md +2 -0
- package/docs/types.md +19 -12
- package/docs/walk.md +54 -5
- package/docs/writing.md +173 -5
- package/package.json +19 -8
package/dist/json.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../src/json.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,SAAS,CAAC;AAO7B,OAAO,EAAoB,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../src/json.ts"],"names":[],"mappings":"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"}
|
package/dist/json.js
CHANGED
|
@@ -8,6 +8,7 @@ import { stringifyJsonDocument } from "./json-stringify.js";
|
|
|
8
8
|
import { readRegularFile, readRegularFileSync, statRegularFile } from "./regular-file.js";
|
|
9
9
|
import { openRootFileSync } from "./root-file.js";
|
|
10
10
|
import { resolveReadOpenFlags } from "./read-open-flags.js";
|
|
11
|
+
import { recursiveMkdirPath } from "./recursive-mkdir-path.js";
|
|
11
12
|
import { writeTextAtomic } from "./text-atomic.js";
|
|
12
13
|
import { sleep } from "./timing.js";
|
|
13
14
|
const READ_RETRY_MAX_ATTEMPTS = 5;
|
|
@@ -169,7 +170,7 @@ export function writeJsonSync(pathname, data) {
|
|
|
169
170
|
// Keep literal parent segments so staging follows the same symlinks as the target.
|
|
170
171
|
const tmpPath = path.format({ ...path.parse(pathname), base: `.fs-safe-${randomUUID()}.tmp` });
|
|
171
172
|
const payload = `${stringifyJsonDocument(data, null, 2)}\n`;
|
|
172
|
-
fsSync.mkdirSync(path.dirname(pathname), { recursive: true, mode: JSON_DIR_MODE });
|
|
173
|
+
fsSync.mkdirSync(recursiveMkdirPath(path.dirname(pathname)), { recursive: true, mode: JSON_DIR_MODE });
|
|
173
174
|
try {
|
|
174
175
|
const tempIdentity = writeTempJsonFile(tmpPath, payload);
|
|
175
176
|
trySetSecureMode(tmpPath, tempIdentity);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-roots.d.ts","sourceRoot":"","sources":["../src/local-roots.ts"],"names":[],"mappings":"AAQA,OAAO,EAAQ,KAAK,cAAc,EAAE,KAAK,UAAU,EAAE,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAE3F,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,UAAU,GAAG;IAC9C,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,oCAAoC,GAAG,sBAAsB,GAAG;IAC1E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG,sBAAsB,GAAG;IACnE,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B,CAAC;
|
|
1
|
+
{"version":3,"file":"local-roots.d.ts","sourceRoot":"","sources":["../src/local-roots.ts"],"names":[],"mappings":"AAQA,OAAO,EAAQ,KAAK,cAAc,EAAE,KAAK,UAAU,EAAE,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAE3F,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,UAAU,GAAG;IAC9C,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,oCAAoC,GAAG,sBAAsB,GAAG;IAC1E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG,sBAAsB,GAAG;IACnE,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B,CAAC;AAsDF,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,oCAAoC,GAC5C,oBAAoB,GAAG,IAAI,CAqC7B;AAED,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAiCtC"}
|
package/dist/local-roots.js
CHANGED
|
@@ -2,10 +2,10 @@ import fsSync from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { normalizeMaxBytes } from "./byte-budget.js";
|
|
4
4
|
import { FsSafeError } from "./errors.js";
|
|
5
|
-
import { expandHomePrefix,
|
|
5
|
+
import { expandHomePrefix, resolveRequiredHomeDir } from "./home-dir.js";
|
|
6
6
|
import { isFileUrl, safeFileURLToPath } from "./local-file-access.js";
|
|
7
|
-
import {
|
|
8
|
-
import { resolveRootPathSync } from "./root-path.js";
|
|
7
|
+
import { realpathSync } from "./realpath.js";
|
|
8
|
+
import { ROOT_PATH_ALIAS_POLICIES, resolveRootPathSync } from "./root-path.js";
|
|
9
9
|
import { root } from "./root.js";
|
|
10
10
|
function resolveLocalPathInput(input, label) {
|
|
11
11
|
if (isFileUrl(input)) {
|
|
@@ -20,7 +20,14 @@ function resolveLocalPathInput(input, label) {
|
|
|
20
20
|
if (input.includes("\0")) {
|
|
21
21
|
throw new FsSafeError("invalid-path", `${label} must not contain NUL bytes`);
|
|
22
22
|
}
|
|
23
|
-
|
|
23
|
+
const homePrefix = input === "~" || input.startsWith("~/") ||
|
|
24
|
+
(path.sep === "\\" && input.startsWith("~\\"));
|
|
25
|
+
const expanded = homePrefix ? `${resolveRequiredHomeDir()}${path.sep}${input.slice(2)}` : input;
|
|
26
|
+
if (path.isAbsolute(expanded))
|
|
27
|
+
return expanded;
|
|
28
|
+
const drive = path.parse(expanded).root;
|
|
29
|
+
const base = drive ? path.resolve(drive) : process.cwd();
|
|
30
|
+
return `${base}${path.sep}${expanded.slice(drive.length)}`;
|
|
24
31
|
}
|
|
25
32
|
function resolveLocalRootInput(input, label) {
|
|
26
33
|
const trimmed = input.trim();
|
|
@@ -46,7 +53,7 @@ function resolveRootRealSync(rootDir) {
|
|
|
46
53
|
if (!stat.isDirectory()) {
|
|
47
54
|
return null;
|
|
48
55
|
}
|
|
49
|
-
return
|
|
56
|
+
return realpathSync(rootDir);
|
|
50
57
|
}
|
|
51
58
|
catch {
|
|
52
59
|
return null;
|
|
@@ -54,7 +61,7 @@ function resolveRootRealSync(rootDir) {
|
|
|
54
61
|
}
|
|
55
62
|
export function resolveLocalPathFromRootsSync(options) {
|
|
56
63
|
const label = options.label ?? "local roots";
|
|
57
|
-
const requestedPath =
|
|
64
|
+
const requestedPath = resolveLocalPathInput(options.filePath, "file path");
|
|
58
65
|
const rootDirs = options.roots.map((rootEntry) => resolveLocalRootInput(rootEntry, label));
|
|
59
66
|
for (const rootDir of rootDirs) {
|
|
60
67
|
const rootReal = resolveRootRealSync(rootDir);
|
|
@@ -69,6 +76,7 @@ export function resolveLocalPathFromRootsSync(options) {
|
|
|
69
76
|
rootCanonicalPath: rootReal,
|
|
70
77
|
boundaryLabel: label,
|
|
71
78
|
rejectUnresolvedSymlinks: true,
|
|
79
|
+
policy: options.requireFile ? ROOT_PATH_ALIAS_POLICIES.unlinkTarget : undefined,
|
|
72
80
|
});
|
|
73
81
|
}
|
|
74
82
|
catch {
|
|
@@ -77,11 +85,12 @@ export function resolveLocalPathFromRootsSync(options) {
|
|
|
77
85
|
if (!candidate.exists && options.allowMissing !== true) {
|
|
78
86
|
continue;
|
|
79
87
|
}
|
|
88
|
+
if (candidate.exists && options.requireFile === true && candidate.kind !== "file")
|
|
89
|
+
continue;
|
|
80
90
|
if (candidate.exists && options.requireFile === true) {
|
|
81
91
|
try {
|
|
82
|
-
if (!fsSync.lstatSync(requestedPath).isFile())
|
|
92
|
+
if (!fsSync.lstatSync(requestedPath).isFile())
|
|
83
93
|
continue;
|
|
84
|
-
}
|
|
85
94
|
}
|
|
86
95
|
catch {
|
|
87
96
|
continue;
|
|
@@ -94,7 +103,7 @@ export function resolveLocalPathFromRootsSync(options) {
|
|
|
94
103
|
export async function readLocalFileFromRoots(options) {
|
|
95
104
|
const maxBytes = normalizeMaxBytes(options.maxBytes);
|
|
96
105
|
const label = options.label ?? "local roots";
|
|
97
|
-
const requestedPath =
|
|
106
|
+
const requestedPath = resolveLocalPathInput(options.filePath, "file path");
|
|
98
107
|
const rootDirs = options.roots.map((rootEntry) => resolveLocalRootInput(rootEntry, label));
|
|
99
108
|
for (const rootDir of rootDirs) {
|
|
100
109
|
let scopedRoot;
|
|
@@ -113,22 +122,12 @@ export async function readLocalFileFromRoots(options) {
|
|
|
113
122
|
if (maxBytes !== undefined) {
|
|
114
123
|
readOptions.maxBytes = maxBytes;
|
|
115
124
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
.map((rootPath) => path.relative(rootPath, requestedPath))
|
|
123
|
-
.filter(Boolean);
|
|
124
|
-
for (const relativePath of relativePaths) {
|
|
125
|
-
try {
|
|
126
|
-
const result = await scopedRoot.read(relativePath, readOptions);
|
|
127
|
-
return { ...result, root: scopedRoot.rootReal };
|
|
128
|
-
}
|
|
129
|
-
catch {
|
|
130
|
-
// Try the canonical spelling before moving to the next configured root.
|
|
131
|
-
}
|
|
125
|
+
try {
|
|
126
|
+
const result = await scopedRoot.readAbsolute(requestedPath, readOptions);
|
|
127
|
+
return { ...result, root: scopedRoot.rootReal };
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
// Root handles both trusted spellings; try the next configured root.
|
|
132
131
|
}
|
|
133
132
|
}
|
|
134
133
|
return null;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type BigIntStats } from "node:fs";
|
|
2
|
+
export declare function createMoveStageOwner(staged: string): Promise<{
|
|
3
|
+
record(created: BigIntStats): void;
|
|
4
|
+
assertCurrent: () => void;
|
|
5
|
+
published(): void;
|
|
6
|
+
cleanup(): Promise<void>;
|
|
7
|
+
}>;
|
|
8
|
+
//# sourceMappingURL=move-path-stage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"move-path-stage.d.ts","sourceRoot":"","sources":["../src/move-path-stage.ts"],"names":[],"mappings":"AAAA,OAAe,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AASnD,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,MAAM;oBAkBrC,WAAW,GAAG,IAAI;yBAPV,IAAI;iBAkBf,IAAI;eACA,OAAO,CAAC,IAAI,CAAC;GAajC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import fsSync, {} from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { createAsyncDirectoryGuard } from "./directory-guard.js";
|
|
4
|
+
import { FsSafeError } from "./errors.js";
|
|
5
|
+
import { guardedRm, guardedRmSync } from "./guarded-mutation.js";
|
|
6
|
+
import { sameFileIdentityForCleanup } from "./file-identity.js";
|
|
7
|
+
import { registerTempPathForExit } from "./temp-cleanup.js";
|
|
8
|
+
import { realpathSync } from "./realpath.js";
|
|
9
|
+
export async function createMoveStageOwner(staged) {
|
|
10
|
+
const parent = await createAsyncDirectoryGuard(path.dirname(staged), { bigint: true });
|
|
11
|
+
let identity;
|
|
12
|
+
let unregister;
|
|
13
|
+
const changed = () => new FsSafeError("path-mismatch", "move staging path changed before publication");
|
|
14
|
+
const assertParent = () => {
|
|
15
|
+
const current = fsSync.lstatSync(parent.dir, { bigint: true });
|
|
16
|
+
if (!current.isDirectory() || current.isSymbolicLink() ||
|
|
17
|
+
!sameFileIdentityForCleanup(current, parent.stat) ||
|
|
18
|
+
realpathSync.native(parent.dir) !== parent.realPath)
|
|
19
|
+
throw changed();
|
|
20
|
+
};
|
|
21
|
+
const assertCurrent = () => {
|
|
22
|
+
assertParent();
|
|
23
|
+
if (!identity || !sameFileIdentityForCleanup(fsSync.lstatSync(staged, { bigint: true }), identity)) {
|
|
24
|
+
throw changed();
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
return {
|
|
28
|
+
record(created) {
|
|
29
|
+
if (!sameFileIdentityForCleanup(created, created))
|
|
30
|
+
throw changed();
|
|
31
|
+
identity = created;
|
|
32
|
+
unregister = registerTempPathForExit(staged, {
|
|
33
|
+
identity,
|
|
34
|
+
cleanupSync: () => {
|
|
35
|
+
guardedRmSync({ target: staged, recursive: created.isDirectory(), assertBeforeMutation: assertCurrent });
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
},
|
|
39
|
+
assertCurrent,
|
|
40
|
+
published() { unregister?.(); },
|
|
41
|
+
async cleanup() {
|
|
42
|
+
if (!identity)
|
|
43
|
+
return;
|
|
44
|
+
try {
|
|
45
|
+
await guardedRm({ target: staged, recursive: identity.isDirectory(), assertBeforeMutation: assertCurrent });
|
|
46
|
+
unregister?.();
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
if (error.code === "ENOENT" || error instanceof FsSafeError) {
|
|
50
|
+
unregister?.();
|
|
51
|
+
}
|
|
52
|
+
// Retry only the original receipt after transient cleanup I/O failures.
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
package/dist/move-path.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"move-path.d.ts","sourceRoot":"","sources":["../src/move-path.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"move-path.d.ts","sourceRoot":"","sources":["../src/move-path.ts"],"names":[],"mappings":"AAuBA,MAAM,MAAM,0BAA0B,GAAG,QAAQ,CAAC;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb,CAAC,CAAC;AAEH,MAAM,MAAM,+BAA+B,GAAG;IAC5C,qFAAqF;IACrF,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;IAClC,uFAAuF;IACvF,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,qFAAqF;IACrF,sBAAsB,CAAC,EAAE,CAAC,OAAO,EAAE,0BAA0B,KAAK,IAAI,CAAC;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IACrC,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,KAAK,sBAAsB,GAAG,cAAc,GAAG,uBAAuB,CAAC;AAEvE,wBAAgB,oCAAoC,CAClD,KAAK,EAAE,OAAO,EACd,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,sBAAsB,GAAG,SAAS,CASpC;AAiRD,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,+BAA+B,GACvC,OAAO,CAAC,IAAI,CAAC,CAwGf"}
|
package/dist/move-path.js
CHANGED
|
@@ -2,11 +2,14 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import fsSync, { constants as fsConstants } from "node:fs";
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
|
+
import { createAsyncDirectoryGuard } from "./directory-guard.js";
|
|
5
6
|
import { FsSafeError } from "./errors.js";
|
|
6
7
|
import { guardedRename } from "./guarded-mutation.js";
|
|
7
8
|
import { assertSourceStillMatches, cleanupCopiedEntry, createCleanupCopiedEntryState, entryIdentity, sameIdentity, sourceChangedError, } from "./move-path-cleanup.js";
|
|
8
9
|
import { resolveReadOpenFlags } from "./read-open-flags.js";
|
|
9
|
-
import {
|
|
10
|
+
import { cleanupPinnedFilePath } from "./replace-file-temp-owner.js";
|
|
11
|
+
import { createMoveStageOwner } from "./move-path-stage.js";
|
|
12
|
+
import { realpathSync } from "./realpath.js";
|
|
10
13
|
export function moveCopyFallbackReasonForRenameError(error, platform = process.platform) {
|
|
11
14
|
const code = error?.code;
|
|
12
15
|
if (code === "EXDEV") {
|
|
@@ -59,12 +62,12 @@ async function assertCopyDestinationOutsideSource(sourcePath, targetPath, expect
|
|
|
59
62
|
}
|
|
60
63
|
const normalizedSource = path.resolve(sourcePath);
|
|
61
64
|
const normalizedTarget = path.resolve(targetPath);
|
|
62
|
-
const sourceParentReal =
|
|
63
|
-
const targetParentReal =
|
|
65
|
+
const sourceParentReal = realpathSync.native(path.dirname(normalizedSource));
|
|
66
|
+
const targetParentReal = realpathSync.native(path.dirname(normalizedTarget));
|
|
64
67
|
const sourceCandidate = path.join(sourceParentReal, path.basename(normalizedSource));
|
|
65
68
|
const targetCandidate = path.join(targetParentReal, path.basename(normalizedTarget));
|
|
66
69
|
const sourceBoundary = sourceStat.isDirectory()
|
|
67
|
-
?
|
|
70
|
+
? realpathSync.native(sourcePath)
|
|
68
71
|
: sourceCandidate;
|
|
69
72
|
const unsafeTarget = sourceStat.isDirectory()
|
|
70
73
|
? isSameOrDescendant(sourceBoundary, targetCandidate)
|
|
@@ -96,11 +99,12 @@ async function writeAll(handle, buffer, bytesRead) {
|
|
|
96
99
|
let offset = 0;
|
|
97
100
|
while (offset < bytesRead) {
|
|
98
101
|
const { bytesWritten } = await handle.write(buffer, offset, bytesRead - offset);
|
|
102
|
+
if (bytesWritten <= 0)
|
|
103
|
+
throw new FsSafeError("helper-failed", "move copy made no progress");
|
|
99
104
|
offset += bytesWritten;
|
|
100
105
|
}
|
|
101
106
|
}
|
|
102
107
|
async function copyRegularFilePinned(params) {
|
|
103
|
-
let destinationCreated = false;
|
|
104
108
|
let openedIdentity;
|
|
105
109
|
let sourceHandle;
|
|
106
110
|
try {
|
|
@@ -132,9 +136,12 @@ async function copyRegularFilePinned(params) {
|
|
|
132
136
|
throw sourceChangedError(params.from);
|
|
133
137
|
}
|
|
134
138
|
await assertSourceStillMatches(params.from, openedIdentity);
|
|
139
|
+
const parentGuard = await createAsyncDirectoryGuard(path.dirname(params.to), { bigint: true });
|
|
135
140
|
const destinationHandle = await fs.open(params.to, fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL, modeBits(params.mode) || 0o666);
|
|
136
|
-
|
|
141
|
+
let destinationIdentity;
|
|
137
142
|
try {
|
|
143
|
+
destinationIdentity = fsSync.fstatSync(destinationHandle.fd, { bigint: true });
|
|
144
|
+
params.onCreated?.(destinationIdentity);
|
|
138
145
|
const scratch = Buffer.allocUnsafe(64 * 1024);
|
|
139
146
|
while (true) {
|
|
140
147
|
const { bytesRead } = await sourceHandle.read(scratch, 0, scratch.length, null);
|
|
@@ -154,16 +161,16 @@ async function copyRegularFilePinned(params) {
|
|
|
154
161
|
}
|
|
155
162
|
await destinationHandle.chmod(modeBits(params.mode));
|
|
156
163
|
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
await cleanupPinnedFilePath({
|
|
166
|
+
pathname: params.to, handle: destinationHandle, identity: destinationIdentity, parentGuard,
|
|
167
|
+
});
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
157
170
|
finally {
|
|
158
171
|
await destinationHandle.close();
|
|
159
172
|
}
|
|
160
173
|
}
|
|
161
|
-
catch (error) {
|
|
162
|
-
if (destinationCreated) {
|
|
163
|
-
await fs.rm(params.to, { force: true }).catch(() => undefined);
|
|
164
|
-
}
|
|
165
|
-
throw error;
|
|
166
|
-
}
|
|
167
174
|
finally {
|
|
168
175
|
await sourceHandle.close();
|
|
169
176
|
}
|
|
@@ -179,6 +186,7 @@ async function copyEntryWithManifest(from, to, options, expectedIdentity) {
|
|
|
179
186
|
const target = await fs.readlink(from);
|
|
180
187
|
const targetType = process.platform === "win32" && fsSync.statSync(from).isDirectory() ? "junction" : undefined;
|
|
181
188
|
await fs.symlink(target, to, targetType);
|
|
189
|
+
options.onCreated?.(fsSync.lstatSync(to, { bigint: true }));
|
|
182
190
|
// readlink() is path-based; verify the symlink we copied is still the one
|
|
183
191
|
// we inspected before letting the staged destination become visible.
|
|
184
192
|
await assertSourceStillMatches(from, identity);
|
|
@@ -186,6 +194,7 @@ async function copyEntryWithManifest(from, to, options, expectedIdentity) {
|
|
|
186
194
|
}
|
|
187
195
|
if (sourceStat.isDirectory()) {
|
|
188
196
|
await fs.mkdir(to, { mode: modeBits(sourceStat.mode) || 0o755 });
|
|
197
|
+
options.onCreated?.(fsSync.lstatSync(to, { bigint: true }));
|
|
189
198
|
const children = [];
|
|
190
199
|
const childNames = [];
|
|
191
200
|
const directory = await fs.opendir(from);
|
|
@@ -198,7 +207,9 @@ async function copyEntryWithManifest(from, to, options, expectedIdentity) {
|
|
|
198
207
|
for (const child of childNames) {
|
|
199
208
|
children.push({
|
|
200
209
|
name: child,
|
|
201
|
-
manifest: await copyEntryWithManifest(path.join(from, child), path.join(to, child),
|
|
210
|
+
manifest: await copyEntryWithManifest(path.join(from, child), path.join(to, child), {
|
|
211
|
+
sourceHardlinks: options.sourceHardlinks, budget: options.budget,
|
|
212
|
+
}),
|
|
202
213
|
});
|
|
203
214
|
}
|
|
204
215
|
// Directory traversal is path-based in Node. Treat a changed parent as a
|
|
@@ -221,6 +232,7 @@ async function copyEntryWithManifest(from, to, options, expectedIdentity) {
|
|
|
221
232
|
mode: sourceStat.mode,
|
|
222
233
|
rejectHardlinks: options.sourceHardlinks === "reject",
|
|
223
234
|
to,
|
|
235
|
+
onCreated: options.onCreated,
|
|
224
236
|
});
|
|
225
237
|
return { ...copiedIdentity, kind: "leaf" };
|
|
226
238
|
}
|
|
@@ -299,22 +311,22 @@ export async function movePathWithCopyFallback(options) {
|
|
|
299
311
|
const sourceIdentity = await assertCopyDestinationOutsideSource(sourcePath, targetPath);
|
|
300
312
|
const targetDir = path.dirname(targetPath);
|
|
301
313
|
const staged = path.join(targetDir, `.fs-safe-move-${process.pid}-${randomUUID()}.tmp`);
|
|
302
|
-
const
|
|
314
|
+
const stage = await createMoveStageOwner(staged);
|
|
303
315
|
try {
|
|
304
316
|
const manifest = await copyEntryWithManifest(sourcePath, staged, {
|
|
305
317
|
sourceHardlinks: rejectHardlinks ? "reject" : "allow",
|
|
318
|
+
onCreated: stage.record,
|
|
306
319
|
...(rejectHardlinks ? { budget: { discovered: 1 } } : {}),
|
|
307
320
|
}, sourceIdentity);
|
|
308
321
|
const cleanupState = createCleanupCopiedEntryState(sourcePath, manifest);
|
|
309
|
-
unregisterStaged.setIdentity(fsSync.lstatSync(staged, { bigint: true }));
|
|
310
322
|
await assertCopyDestinationOutsideSource(sourcePath, targetPath, manifest);
|
|
311
323
|
await guardedRename({
|
|
312
324
|
from: staged,
|
|
313
325
|
to: targetPath,
|
|
314
|
-
assertBeforeRename,
|
|
326
|
+
assertBeforeRename: () => { assertBeforeRename(); stage.assertCurrent(); },
|
|
315
327
|
onSourceInspected,
|
|
316
328
|
onRenamed: () => {
|
|
317
|
-
|
|
329
|
+
stage.published();
|
|
318
330
|
onRenamed();
|
|
319
331
|
},
|
|
320
332
|
});
|
|
@@ -325,23 +337,7 @@ export async function movePathWithCopyFallback(options) {
|
|
|
325
337
|
}
|
|
326
338
|
finally {
|
|
327
339
|
if (!destinationPublished) {
|
|
328
|
-
|
|
329
|
-
const stagedIdentity = fsSync.lstatSync(staged, { bigint: true });
|
|
330
|
-
if (!stagedIdentity.isSymbolicLink())
|
|
331
|
-
unregisterStaged.setIdentity(stagedIdentity);
|
|
332
|
-
}
|
|
333
|
-
catch (error) {
|
|
334
|
-
if (error.code === "ENOENT") {
|
|
335
|
-
unregisterStaged();
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
try {
|
|
339
|
-
await fs.rm(staged, { recursive: true, force: true });
|
|
340
|
-
unregisterStaged();
|
|
341
|
-
}
|
|
342
|
-
catch {
|
|
343
|
-
// Keep the identity-bound exit cleanup registered for a later retry.
|
|
344
|
-
}
|
|
340
|
+
await stage.cleanup();
|
|
345
341
|
}
|
|
346
342
|
}
|
|
347
343
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FsSafeError } from "./errors.js";
|
|
2
|
+
export declare class MutationAuthorityError extends FsSafeError {
|
|
3
|
+
readonly rejection: unknown;
|
|
4
|
+
constructor(rejection: unknown);
|
|
5
|
+
}
|
|
6
|
+
export declare function assertSynchronousCallbackResult(returned: unknown, name: string): void;
|
|
7
|
+
export declare function composeMutationAssertions(defaultAssertion?: () => void, callAssertion?: () => void): (() => void) | undefined;
|
|
8
|
+
export declare function rethrowMutationAuthorityError(error: unknown): never;
|
|
9
|
+
//# sourceMappingURL=mutation-authority.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mutation-authority.d.ts","sourceRoot":"","sources":["../src/mutation-authority.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,qBAAa,sBAAuB,SAAQ,WAAW;IACzC,QAAQ,CAAC,SAAS,EAAE,OAAO;IAAvC,YAAqB,SAAS,EAAE,OAAO,EAEtC;CACF;AAED,wBAAgB,+BAA+B,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAUrF;AAED,wBAAgB,yBAAyB,CACvC,gBAAgB,CAAC,EAAE,MAAM,IAAI,EAC7B,aAAa,CAAC,EAAE,MAAM,IAAI,GACzB,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAU1B;AAED,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAInE"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { FsSafeError } from "./errors.js";
|
|
2
|
+
export class MutationAuthorityError extends FsSafeError {
|
|
3
|
+
rejection;
|
|
4
|
+
constructor(rejection) {
|
|
5
|
+
super("denied-path", "mutation authority rejected the operation", { cause: rejection });
|
|
6
|
+
this.rejection = rejection;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export function assertSynchronousCallbackResult(returned, name) {
|
|
10
|
+
if (returned !== null &&
|
|
11
|
+
(typeof returned === "object" || typeof returned === "function") &&
|
|
12
|
+
typeof returned.then === "function") {
|
|
13
|
+
// TypeScript permits async functions for () => void. Do not admit their work.
|
|
14
|
+
void Promise.resolve(returned).catch(() => undefined);
|
|
15
|
+
throw new TypeError(`${name} must be synchronous`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function composeMutationAssertions(defaultAssertion, callAssertion) {
|
|
19
|
+
if (!defaultAssertion && !callAssertion)
|
|
20
|
+
return undefined;
|
|
21
|
+
return () => {
|
|
22
|
+
try {
|
|
23
|
+
assertSynchronousCallbackResult(defaultAssertion?.(), "assertBeforeMutation");
|
|
24
|
+
assertSynchronousCallbackResult(callAssertion?.(), "assertBeforeMutation");
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
throw new MutationAuthorityError(error);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export function rethrowMutationAuthorityError(error) {
|
|
32
|
+
if (error instanceof MutationAuthorityError)
|
|
33
|
+
throw error.rejection;
|
|
34
|
+
// Cleanup failures and indeterminate publication receipts must retain their context.
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
package/dist/native-binding.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { TarMeterLimits } from "./archive-limits.js";
|
|
2
2
|
import type { ArchiveMemberKind } from "./archive-plan.js";
|
|
3
|
+
import type { CopyCloneMode } from "./copy-policy.js";
|
|
3
4
|
export interface NativeFileHash {
|
|
4
5
|
bytes: number;
|
|
5
6
|
digest: string;
|
|
@@ -29,6 +30,12 @@ export interface NativeCopyResult {
|
|
|
29
30
|
errorCode?: string;
|
|
30
31
|
errorMessage?: string;
|
|
31
32
|
}
|
|
33
|
+
export interface NativeFileCopyResult {
|
|
34
|
+
fd: number;
|
|
35
|
+
method: "clone" | "copy-file-range" | "copy";
|
|
36
|
+
errorCode?: string;
|
|
37
|
+
errorMessage?: string;
|
|
38
|
+
}
|
|
32
39
|
export interface NativeOpenBeneathResult {
|
|
33
40
|
fd: number;
|
|
34
41
|
containment: "kernel-atomic" | "best-effort";
|
|
@@ -69,9 +76,30 @@ export interface NativeWindowsSecurityFacts {
|
|
|
69
76
|
aces: NativeWindowsAccessControlEntry[];
|
|
70
77
|
}
|
|
71
78
|
export interface NativeBinding {
|
|
79
|
+
/** POSIX system canonicalization; confinement and identity policy stay with callers. */
|
|
80
|
+
canonicalizePath?(path: string, ordinary: boolean): {
|
|
81
|
+
path?: string;
|
|
82
|
+
errno?: number;
|
|
83
|
+
};
|
|
84
|
+
/** Linux/Windows byte transfer; callers retain both admitted descriptors until settlement. */
|
|
85
|
+
copyFileContents?(sourceFd: number, targetFd: number, signal?: AbortSignal): Promise<void>;
|
|
86
|
+
/** Internal: same private, immutable input ownership as the ZIP buffer reader. */
|
|
87
|
+
openTarBufferNative(buffer: Buffer, kind: string, limits: TarMeterLimits, signal?: AbortSignal): Promise<{
|
|
88
|
+
readonly entries: NativeArchiveEntry[];
|
|
89
|
+
readEntry(index: number, maxBytes: number, signal?: AbortSignal): Promise<Buffer>;
|
|
90
|
+
}>;
|
|
91
|
+
/** Internal: input remains private, unpooled and immutable until the reader is released. */
|
|
92
|
+
openZipBufferNative(buffer: Buffer, limits: TarMeterLimits, signal?: AbortSignal): Promise<{
|
|
93
|
+
readonly entries: NativeArchiveEntry[];
|
|
94
|
+
readEntry(index: number, maxBytes: number, signal?: AbortSignal): Promise<Buffer>;
|
|
95
|
+
}>;
|
|
96
|
+
readCloneFileMetadata(paths: string[]): Promise<(Buffer | null)[]>;
|
|
97
|
+
probeTreeClone(parentFd: number): "apfs" | "btrfs" | "refs" | "xfs" | "zfs" | null;
|
|
98
|
+
cloneTree(sourceFd: number | null, parentFd: number, basename: string, concurrency: number, signal?: AbortSignal): Promise<void>;
|
|
72
99
|
createStagedFile?(parentFd: number, basename: string): number;
|
|
73
100
|
stagedFileMatches?(parentFd: number, basename: string, fileFd: number): boolean;
|
|
74
101
|
removeStagedFile?(parentFd: number, basename: string, fileFd: number): "removed" | "name-absent" | "preserved";
|
|
102
|
+
copyFileExclusive?(sourceFd: number, parentFd: number, basename: string, clone: CopyCloneMode, maxBytes: number | undefined, signal: AbortSignal | undefined, sync: boolean): Promise<NativeFileCopyResult>;
|
|
75
103
|
cloneFileExclusive(sourceFd: number, targetRootFd: number, targetRelPath: string): number;
|
|
76
104
|
copyFileRangeExclusive(sourceFd: number, targetRootFd: number, targetRelPath: string): Promise<NativeCopyResult>;
|
|
77
105
|
createPrivateDirectory(path: string): void;
|
|
@@ -88,6 +116,6 @@ export interface NativeBinding {
|
|
|
88
116
|
removeOwnedTreeSync?(parentFd: number, basename: string, directoryFd: number): NativeOwnedTreeRemovalResult;
|
|
89
117
|
renameNoReplace(sourceRootFd: number, sourceRelPath: string, targetRootFd: number, targetRelPath: string): void;
|
|
90
118
|
renameReplace(sourceRootFd: number, sourceRelPath: string, targetRootFd: number, targetRelPath: string): void;
|
|
91
|
-
sha256File(fd: number): Promise<NativeFileHash>;
|
|
119
|
+
sha256File(fd: number, maxBytes?: number, signal?: AbortSignal): Promise<NativeFileHash>;
|
|
92
120
|
}
|
|
93
121
|
//# sourceMappingURL=native-binding.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-binding.d.ts","sourceRoot":"","sources":["../src/native-binding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"native-binding.d.ts","sourceRoot":"","sources":["../src/native-binding.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,7 +10,7 @@ export type NativeFileHandle = {
|
|
|
10
10
|
};
|
|
11
11
|
export declare function nativeOpenFlags(flags: number): number;
|
|
12
12
|
export declare function writeNativeFd(fd: number, data: Buffer): void;
|
|
13
|
-
export declare function writeNativeInput(fd: number, input: PinnedWriteInput, maxBytes?: number): Promise<void>;
|
|
13
|
+
export declare function writeNativeInput(fd: number, input: PinnedWriteInput, maxBytes?: number, assertBeforeMutation?: () => void): Promise<void>;
|
|
14
14
|
export declare function removeNativeCreatedFileIfStillPinned(params: {
|
|
15
15
|
parentPath: string;
|
|
16
16
|
parentFd: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-operations.d.ts","sourceRoot":"","sources":["../src/native-operations.ts"],"names":[],"mappings":"AAAA,OAAe,EAAE,KAAK,WAAW,EAAE,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAG/D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAI7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"native-operations.d.ts","sourceRoot":"","sources":["../src/native-operations.ts"],"names":[],"mappings":"AAAA,OAAe,EAAE,KAAK,WAAW,EAAE,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAG/D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAI7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAI1D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,oBAAoB,CAAC;IAC3C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC;IACvB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5E,CAAC;AAEF,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOrD;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAS5D;AAED,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,gBAAgB,EACvB,QAAQ,CAAC,EAAE,MAAM,EACjB,oBAAoB,CAAC,EAAE,MAAM,IAAI,GAChC,OAAO,CAAC,IAAI,CAAC,CAoBf;AAsBD,wBAAgB,oCAAoC,CAAC,MAAM,EAAE;IAC3D,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB,GAAG,IAAI,CAqBP;AAED,wBAAsB,yBAAyB,CAC7C,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAwDvC"}
|
|
@@ -4,6 +4,8 @@ import path from "node:path";
|
|
|
4
4
|
import { FsSafeError } from "./errors.js";
|
|
5
5
|
import { sameFileIdentityForCleanup } from "./file-identity.js";
|
|
6
6
|
import { getNativeBinding } from "./native.js";
|
|
7
|
+
import { writeAllToFile } from "./write-file-handle.js";
|
|
8
|
+
import { writeCopyFileToFd } from "./copy-file-input.js";
|
|
7
9
|
export function nativeOpenFlags(flags) {
|
|
8
10
|
const closeOnExec = fsSync.constants.O_CLOEXEC;
|
|
9
11
|
return (flags |
|
|
@@ -20,21 +22,25 @@ export function writeNativeFd(fd, data) {
|
|
|
20
22
|
offset += written;
|
|
21
23
|
}
|
|
22
24
|
}
|
|
23
|
-
export async function writeNativeInput(fd, input, maxBytes) {
|
|
25
|
+
export async function writeNativeInput(fd, input, maxBytes, assertBeforeMutation) {
|
|
26
|
+
if (input.kind === "file") {
|
|
27
|
+
await writeCopyFileToFd(fd, input, maxBytes, assertBeforeMutation);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
24
30
|
let bytes = 0;
|
|
25
|
-
const write = (data) => {
|
|
31
|
+
const write = async (data) => {
|
|
26
32
|
bytes += data.byteLength;
|
|
27
33
|
if (maxBytes !== undefined && bytes > maxBytes) {
|
|
28
34
|
throw new FsSafeError("too-large", `file exceeds limit of ${maxBytes} bytes (got at least ${bytes})`);
|
|
29
35
|
}
|
|
30
|
-
|
|
36
|
+
await writeAllToFile(fd, data, { assertBeforeMutation });
|
|
31
37
|
};
|
|
32
38
|
if (input.kind === "buffer") {
|
|
33
|
-
write(typeof input.data === "string" ? Buffer.from(input.data, input.encoding ?? "utf8") : input.data);
|
|
39
|
+
await write(typeof input.data === "string" ? Buffer.from(input.data, input.encoding ?? "utf8") : input.data);
|
|
34
40
|
}
|
|
35
41
|
else {
|
|
36
42
|
for await (const chunk of input.stream) {
|
|
37
|
-
write(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
43
|
+
await write(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
38
44
|
}
|
|
39
45
|
}
|
|
40
46
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-pinned-write-windows.d.ts","sourceRoot":"","sources":["../src/native-pinned-write-windows.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"native-pinned-write-windows.d.ts","sourceRoot":"","sources":["../src/native-pinned-write-windows.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAM3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAI3D,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,IAAI,CAAC,gBAAgB,EAAE,KAAK,GAAG,KAAK,CAAC,EAC3C,KAAK,EAAE,IAAI,CAAC,gBAAgB,EAAE,KAAK,GAAG,KAAK,CAAC,GAC3C,OAAO,CAET;AAWD,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,iBAAiB,EACzB,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,sBAAsB,GAClC,OAAO,CAAC,gBAAgB,CAAC,CA0F3B"}
|