@openclaw/fs-safe 0.5.0 → 0.5.2
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 +79 -0
- package/README.md +18 -6
- package/dist/absolute-path.d.ts.map +1 -1
- package/dist/absolute-path.js +20 -12
- package/dist/archive-entry.d.ts +1 -0
- package/dist/archive-entry.d.ts.map +1 -1
- package/dist/archive-entry.js +25 -5
- package/dist/archive-input.d.ts +7 -0
- package/dist/archive-input.d.ts.map +1 -1
- package/dist/archive-input.js +11 -1
- package/dist/archive-limits.js +1 -1
- package/dist/archive-native.d.ts.map +1 -1
- package/dist/archive-native.js +6 -3
- package/dist/archive-policy.d.ts.map +1 -1
- package/dist/archive-policy.js +2 -1
- package/dist/archive-read.d.ts.map +1 -1
- package/dist/archive-read.js +30 -12
- package/dist/archive-staging.d.ts.map +1 -1
- package/dist/archive-staging.js +3 -2
- package/dist/archive-tar-meta.d.ts.map +1 -1
- package/dist/archive-tar-meta.js +7 -1
- package/dist/archive-tar.d.ts.map +1 -1
- package/dist/archive-tar.js +7 -4
- package/dist/archive-zip-entry.d.ts +1 -0
- package/dist/archive-zip-entry.d.ts.map +1 -1
- package/dist/archive-zip-integrity.d.ts +4 -0
- package/dist/archive-zip-integrity.d.ts.map +1 -0
- package/dist/archive-zip-integrity.js +44 -0
- package/dist/archive-zip-preflight.d.ts.map +1 -1
- package/dist/archive-zip-preflight.js +6 -1
- package/dist/archive.d.ts.map +1 -1
- package/dist/archive.js +5 -2
- package/dist/bounded-read-stream.d.ts.map +1 -1
- package/dist/bounded-read-stream.js +13 -2
- package/dist/deny-mutations.d.ts +1 -0
- package/dist/deny-mutations.d.ts.map +1 -1
- package/dist/deny-mutations.js +6 -39
- package/dist/device-path.d.ts +1 -0
- package/dist/device-path.d.ts.map +1 -1
- package/dist/device-path.js +30 -8
- package/dist/directory-guard.d.ts.map +1 -1
- package/dist/directory-guard.js +5 -4
- package/dist/error-detail.d.ts +2 -0
- package/dist/error-detail.d.ts.map +1 -0
- package/dist/error-detail.js +4 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +3 -0
- package/dist/file-hash.d.ts.map +1 -1
- package/dist/file-hash.js +4 -1
- package/dist/file-lock-sync.d.ts.map +1 -1
- package/dist/file-lock-sync.js +88 -35
- package/dist/file-store-boundary.d.ts +6 -0
- package/dist/file-store-boundary.d.ts.map +1 -1
- package/dist/file-store-boundary.js +20 -5
- package/dist/file-store-sync-write.d.ts +9 -0
- package/dist/file-store-sync-write.d.ts.map +1 -0
- package/dist/file-store-sync-write.js +97 -0
- package/dist/file-store.d.ts.map +1 -1
- package/dist/file-store.js +36 -128
- package/dist/filename.d.ts.map +1 -1
- package/dist/filename.js +27 -0
- package/dist/guarded-mkdir.d.ts.map +1 -1
- package/dist/guarded-mkdir.js +5 -6
- package/dist/install-path.js +1 -1
- package/dist/json-document-store.d.ts.map +1 -1
- package/dist/json-document-store.js +19 -13
- package/dist/json.d.ts.map +1 -1
- package/dist/json.js +1 -3
- package/dist/local-file-access.d.ts +3 -2
- package/dist/local-file-access.d.ts.map +1 -1
- package/dist/local-file-access.js +12 -6
- package/dist/local-roots.d.ts.map +1 -1
- package/dist/local-roots.js +35 -30
- package/dist/move-path.d.ts.map +1 -1
- package/dist/move-path.js +51 -12
- package/dist/native/darwin-arm64/fs-safe-native.node +0 -0
- package/dist/native/darwin-x64/fs-safe-native.node +0 -0
- package/dist/native/linux-arm64-gnu/fs-safe-native.node +0 -0
- package/dist/native/linux-arm64-musl/fs-safe-native.node +0 -0
- package/dist/native/linux-x64-gnu/fs-safe-native.node +0 -0
- package/dist/native/linux-x64-musl/fs-safe-native.node +0 -0
- package/dist/native/win32-x64-msvc/fs-safe-native.node +0 -0
- package/dist/native-binding.d.ts +1 -0
- package/dist/native-binding.d.ts.map +1 -1
- package/dist/native-operations.d.ts.map +1 -1
- package/dist/native-operations.js +14 -1
- package/dist/native-pinned-write.d.ts.map +1 -1
- package/dist/native-pinned-write.js +44 -17
- package/dist/output-sibling.d.ts.map +1 -1
- package/dist/output-sibling.js +6 -5
- package/dist/path-policy.d.ts.map +1 -1
- package/dist/path-policy.js +1 -7
- package/dist/path.d.ts.map +1 -1
- package/dist/path.js +7 -2
- package/dist/permission-exec.d.ts +6 -0
- package/dist/permission-exec.d.ts.map +1 -0
- package/dist/permission-exec.js +28 -0
- package/dist/permissions-windows.d.ts +56 -0
- package/dist/permissions-windows.d.ts.map +1 -0
- package/dist/permissions-windows.js +285 -0
- package/dist/permissions.d.ts +3 -46
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js +17 -328
- package/dist/pinned-write.js +2 -1
- package/dist/regular-file.d.ts.map +1 -1
- package/dist/regular-file.js +21 -2
- package/dist/replace-directory.d.ts.map +1 -1
- package/dist/replace-directory.js +10 -1
- package/dist/replace-file-copy-fallback.d.ts +3 -0
- package/dist/replace-file-copy-fallback.d.ts.map +1 -1
- package/dist/replace-file-copy-fallback.js +18 -11
- package/dist/replace-file-descriptor.d.ts +33 -0
- package/dist/replace-file-descriptor.d.ts.map +1 -0
- package/dist/replace-file-descriptor.js +96 -0
- package/dist/replace-file.d.ts +9 -2
- package/dist/replace-file.d.ts.map +1 -1
- package/dist/replace-file.js +64 -72
- package/dist/root-context.d.ts +8 -0
- package/dist/root-context.d.ts.map +1 -1
- package/dist/root-context.js +43 -2
- package/dist/root-errors.d.ts +7 -0
- package/dist/root-errors.d.ts.map +1 -1
- package/dist/root-errors.js +46 -1
- package/dist/root-file.d.ts +1 -0
- package/dist/root-file.d.ts.map +1 -1
- package/dist/root-file.js +2 -0
- package/dist/root-impl.d.ts.map +1 -1
- package/dist/root-impl.js +213 -168
- package/dist/root-path-symlink.d.ts +3 -0
- package/dist/root-path-symlink.d.ts.map +1 -0
- package/dist/root-path-symlink.js +35 -0
- package/dist/root-path.d.ts +1 -0
- package/dist/root-path.d.ts.map +1 -1
- package/dist/root-path.js +129 -190
- package/dist/root-walk.d.ts.map +1 -1
- package/dist/root-walk.js +15 -0
- package/dist/safe-path-segment.d.ts +2 -0
- package/dist/safe-path-segment.d.ts.map +1 -1
- package/dist/safe-path-segment.js +28 -4
- package/dist/secret-file.d.ts.map +1 -1
- package/dist/secret-file.js +19 -3
- package/dist/secure-temp-dir.d.ts.map +1 -1
- package/dist/secure-temp-dir.js +6 -1
- package/dist/short-path.d.ts +2 -0
- package/dist/short-path.d.ts.map +1 -0
- package/dist/short-path.js +7 -0
- package/dist/sidecar-lock-acquire.d.ts +30 -0
- package/dist/sidecar-lock-acquire.d.ts.map +1 -0
- package/dist/sidecar-lock-acquire.js +260 -0
- package/dist/sidecar-lock-policy.d.ts +3 -0
- package/dist/sidecar-lock-policy.d.ts.map +1 -1
- package/dist/sidecar-lock-policy.js +20 -3
- package/dist/sidecar-lock-reclaim.d.ts +5 -1
- package/dist/sidecar-lock-reclaim.d.ts.map +1 -1
- package/dist/sidecar-lock-reclaim.js +59 -9
- package/dist/sidecar-lock.d.ts.map +1 -1
- package/dist/sidecar-lock.js +27 -226
- package/dist/temp-target.d.ts.map +1 -1
- package/dist/temp-target.js +66 -7
- package/dist/test-hooks.d.ts +1 -0
- package/dist/test-hooks.d.ts.map +1 -1
- package/dist/timing.d.ts +2 -0
- package/dist/timing.d.ts.map +1 -1
- package/dist/timing.js +9 -0
- package/dist/walk.d.ts.map +1 -1
- package/dist/walk.js +15 -0
- package/docs/advanced.md +1 -1
- package/docs/archive.md +27 -20
- package/docs/assets/readme-banner.jpg +0 -0
- package/docs/atomic.md +48 -19
- package/docs/errors.md +31 -7
- package/docs/file-store.md +10 -1
- package/docs/filename.md +17 -16
- package/docs/index.md +1 -0
- package/docs/install-path.md +9 -6
- package/docs/json.md +8 -2
- package/docs/local-roots.md +79 -103
- package/docs/native-helper.md +11 -5
- package/docs/native.md +2 -2
- package/docs/output.md +8 -3
- package/docs/path-scope.md +4 -1
- package/docs/path.md +7 -3
- package/docs/permissions.md +8 -0
- package/docs/public-api.md +109 -0
- package/docs/quickstart.md +6 -2
- package/docs/reading.md +13 -10
- package/docs/root.md +26 -4
- package/docs/secret-file.md +17 -4
- package/docs/security-model.md +21 -4
- package/docs/sidecar-lock.md +15 -5
- package/docs/temp.md +37 -5
- package/docs/test-hooks.md +2 -0
- package/docs/types.md +32 -15
- package/docs/writing.md +25 -12
- package/package.json +10 -6
- package/dist/archive-file-io.d.ts +0 -9
- package/dist/archive-file-io.d.ts.map +0 -1
- package/dist/archive-file-io.js +0 -11
- package/dist/file-store-source.d.ts +0 -5
- package/dist/file-store-source.d.ts.map +0 -1
- package/dist/file-store-source.js +0 -30
- package/dist/file-url.d.ts +0 -2
- package/dist/file-url.d.ts.map +0 -1
- package/dist/file-url.js +0 -1
- package/dist/path-stat.d.ts +0 -4
- package/dist/path-stat.d.ts.map +0 -1
- package/dist/path-stat.js +0 -15
- package/dist/windows-permissions-native.d.ts +0 -9
- package/dist/windows-permissions-native.d.ts.map +0 -1
- package/dist/windows-permissions-native.js +0 -31
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import syncFs, {} from "node:fs";
|
|
2
|
+
import fs, {} from "node:fs/promises";
|
|
3
|
+
import { FsSafeError } from "./errors.js";
|
|
4
|
+
import { sameFileIdentity } from "./file-identity.js";
|
|
5
|
+
function directoryOpenFlags() {
|
|
6
|
+
return (syncFs.constants.O_RDONLY |
|
|
7
|
+
syncFs.constants.O_DIRECTORY |
|
|
8
|
+
syncFs.constants.O_NOFOLLOW |
|
|
9
|
+
syncFs.constants.O_NONBLOCK);
|
|
10
|
+
}
|
|
11
|
+
function assertDirectory(identity, dirPath) {
|
|
12
|
+
if (identity.isSymbolicLink() || !identity.isDirectory()) {
|
|
13
|
+
throw new FsSafeError("not-file", `Atomic replace parent must be a real directory: ${dirPath}`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function assertSameDirectory(expected, opened, dirPath) {
|
|
17
|
+
assertDirectory(opened, dirPath);
|
|
18
|
+
if (!sameFileIdentity(expected, opened)) {
|
|
19
|
+
throw new FsSafeError("path-mismatch", `Atomic replace parent changed before its mode could be applied: ${dirPath}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export async function applyDirectoryMode(params) {
|
|
23
|
+
// Node does not enforce POSIX directory modes on Windows, and its directory
|
|
24
|
+
// descriptors are not consistently openable. mkdir(mode) remains the only
|
|
25
|
+
// bounded behavior there; never fall back to a pathname chmod.
|
|
26
|
+
if (process.platform === "win32") {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const expected = await params.fsModule.lstat(params.dirPath);
|
|
30
|
+
assertDirectory(expected, params.dirPath);
|
|
31
|
+
const handle = await params.fsModule.open(params.dirPath, directoryOpenFlags());
|
|
32
|
+
try {
|
|
33
|
+
assertSameDirectory(expected, await handle.stat(), params.dirPath);
|
|
34
|
+
await handle.chmod(params.mode);
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
await handle.close();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export function applyDirectoryModeSync(params) {
|
|
41
|
+
if (process.platform === "win32") {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const expected = params.fsModule.lstatSync(params.dirPath);
|
|
45
|
+
assertDirectory(expected, params.dirPath);
|
|
46
|
+
const fd = params.fsModule.openSync(params.dirPath, directoryOpenFlags());
|
|
47
|
+
try {
|
|
48
|
+
assertSameDirectory(expected, params.fsModule.fstatSync(fd), params.dirPath);
|
|
49
|
+
params.fchmodSync?.(fd, params.mode);
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
params.fsModule.closeSync(fd);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export async function writeTempFile(params) {
|
|
56
|
+
const handle = await params.fsModule.open(params.tempPath, "wx", params.mode);
|
|
57
|
+
try {
|
|
58
|
+
await params.fsModule.writeFile(handle, params.content);
|
|
59
|
+
await handle.chmod(params.mode);
|
|
60
|
+
if (params.sync) {
|
|
61
|
+
try {
|
|
62
|
+
await handle.sync();
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
if (error.code !== "EPERM") {
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return await handle.stat();
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
await handle.close();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export function writeTempFileSync(params) {
|
|
77
|
+
const fd = params.fsModule.openSync(params.tempPath, "wx", params.mode);
|
|
78
|
+
try {
|
|
79
|
+
params.fsModule.writeFileSync(fd, params.content);
|
|
80
|
+
params.fchmodSync?.(fd, params.mode);
|
|
81
|
+
if (params.sync) {
|
|
82
|
+
try {
|
|
83
|
+
params.fsModule.fsyncSync(fd);
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
if (error.code !== "EPERM") {
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return params.fsModule.fstatSync(fd);
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
params.fsModule.closeSync(fd);
|
|
95
|
+
}
|
|
96
|
+
}
|
package/dist/replace-file.d.ts
CHANGED
|
@@ -2,9 +2,16 @@ import syncFs from "node:fs";
|
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
3
|
import { type ReplaceFileAtomicRestoreCleanup, type ReplaceFileAtomicRestoreFailureDetails, type ReplaceFileCopyFallbackRestorePolicy, type ReplaceFileDestinationHardlinkPolicy } from "./replace-file-copy-fallback.js";
|
|
4
4
|
export type ReplaceFileAtomicFileSystem = {
|
|
5
|
-
promises: Pick<typeof fs, "mkdir" | "
|
|
5
|
+
promises: Pick<typeof fs, "mkdir" | "writeFile" | "rename" | "copyFile" | "unlink" | "rm" | "open" | "stat" | "lstat"> & {
|
|
6
|
+
/** @deprecated Accepted for adapter compatibility but never called. */
|
|
7
|
+
chmod?: typeof fs.chmod;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
export type ReplaceFileAtomicSyncFileSystem = Pick<typeof syncFs, "mkdirSync" | "readFileSync" | "writeFileSync" | "renameSync" | "copyFileSync" | "unlinkSync" | "rmSync" | "openSync" | "fsyncSync" | "closeSync" | "fstatSync" | "statSync" | "lstatSync" | "ftruncateSync" | "readSync" | "writeSync"> & {
|
|
11
|
+
/** @deprecated Accepted for adapter compatibility but never called. */
|
|
12
|
+
chmodSync?: typeof syncFs.chmodSync;
|
|
13
|
+
fchmodSync?: typeof syncFs.fchmodSync;
|
|
6
14
|
};
|
|
7
|
-
export type ReplaceFileAtomicSyncFileSystem = Pick<typeof syncFs, "mkdirSync" | "chmodSync" | "readFileSync" | "writeFileSync" | "renameSync" | "copyFileSync" | "unlinkSync" | "rmSync" | "openSync" | "fsyncSync" | "closeSync" | "fstatSync" | "statSync" | "lstatSync" | "ftruncateSync" | "readSync" | "writeSync">;
|
|
8
15
|
export type { ReplaceFileAtomicRestoreCleanup, ReplaceFileAtomicRestoreFailureDetails, ReplaceFileCopyFallbackRestorePolicy, ReplaceFileDestinationHardlinkPolicy, };
|
|
9
16
|
type ReplaceFileAtomicBaseOptions = {
|
|
10
17
|
filePath: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replace-file.d.ts","sourceRoot":"","sources":["../src/replace-file.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,SAAS,CAAC;AAE7B,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAElC,OAAO,EAKL,KAAK,+BAA+B,EACpC,KAAK,sCAAsC,EAC3C,KAAK,oCAAoC,EACzC,KAAK,oCAAoC,EAC1C,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"replace-file.d.ts","sourceRoot":"","sources":["../src/replace-file.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,SAAS,CAAC;AAE7B,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAElC,OAAO,EAKL,KAAK,+BAA+B,EACpC,KAAK,sCAAsC,EAC3C,KAAK,oCAAoC,EACzC,KAAK,oCAAoC,EAC1C,MAAM,iCAAiC,CAAC;AAazC,MAAM,MAAM,2BAA2B,GAAG;IACxC,QAAQ,EAAE,IAAI,CACZ,OAAO,EAAE,EACP,OAAO,GACP,WAAW,GACX,QAAQ,GACR,UAAU,GACV,QAAQ,GACR,IAAI,GACJ,MAAM,GACN,MAAM,GACN,OAAO,CACV,GAAG;QACF,uEAAuE;QACvE,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC;KACzB,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG,IAAI,CAChD,OAAO,MAAM,EACX,WAAW,GACX,cAAc,GACd,eAAe,GACf,YAAY,GACZ,cAAc,GACd,YAAY,GACZ,QAAQ,GACR,UAAU,GACV,WAAW,GACX,WAAW,GACX,WAAW,GACX,UAAU,GACV,WAAW,GACX,eAAe,GACf,UAAU,GACV,WAAW,CACd,GAAG;IACF,uEAAuE;IACvE,SAAS,CAAC,EAAE,OAAO,MAAM,CAAC,SAAS,CAAC;IACpC,UAAU,CAAC,EAAE,OAAO,MAAM,CAAC,UAAU,CAAC;CACvC,CAAC;AAEF,YAAY,EACV,+BAA+B,EAC/B,sCAAsC,EACtC,oCAAoC,EACpC,oCAAoC,GACrC,CAAC;AAEF,KAAK,4BAA4B,GAAG;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,6BAA6B,CAAC,EAAE,OAAO,CAAC;IACxC,mBAAmB,CAAC,EAAE,oCAAoC,CAAC;IAC3D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oBAAoB,CAAC,EAAE,oCAAoC,CAAC;IAC5D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG,4BAA4B,GAAG;IACpE,UAAU,CAAC,EAAE,2BAA2B,CAAC;IACzC,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAClF,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,4BAA4B,GAAG;IACxE,UAAU,CAAC,EAAE,+BAA+B,CAAC;IAC7C,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CACzE,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,MAAM,EAAE,QAAQ,GAAG,eAAe,CAAC;CACpC,CAAC;AAgNF,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,uBAAuB,CAAC,CAOlC;AAkED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,4BAA4B,GACpC,uBAAuB,CAoFzB"}
|
package/dist/replace-file.js
CHANGED
|
@@ -3,8 +3,10 @@ import syncFs from "node:fs";
|
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { assertDestinationHardlinkPolicy, assertDestinationHardlinkPolicySync, copyFallbackReplace, copyFallbackReplaceSync, } from "./replace-file-copy-fallback.js";
|
|
6
|
+
import { applyDirectoryMode, applyDirectoryModeSync, writeTempFile, writeTempFileSync, } from "./replace-file-descriptor.js";
|
|
6
7
|
import { assertSafePathPrefix } from "./safe-path-segment.js";
|
|
7
8
|
import { registerTempPathForExit } from "./temp-cleanup.js";
|
|
9
|
+
import { sleep, sleepSync } from "./timing.js";
|
|
8
10
|
import { serializePathWrite } from "./write-queue.js";
|
|
9
11
|
function isRetryableRenameError(error) {
|
|
10
12
|
return error.code === "EBUSY";
|
|
@@ -13,9 +15,6 @@ function isPermissionRenameError(error) {
|
|
|
13
15
|
const code = error.code;
|
|
14
16
|
return code === "EPERM" || code === "EEXIST";
|
|
15
17
|
}
|
|
16
|
-
async function sleep(ms) {
|
|
17
|
-
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
18
|
-
}
|
|
19
18
|
async function renameWithRetry(params) {
|
|
20
19
|
for (let attempt = 0; attempt <= params.maxRetries; attempt++) {
|
|
21
20
|
try {
|
|
@@ -35,6 +34,7 @@ async function renameWithRetry(params) {
|
|
|
35
34
|
destinationHardlinks: params.destinationHardlinks,
|
|
36
35
|
restore: params.copyFallbackRestore,
|
|
37
36
|
maxRestoreBytes: params.maxRestoreBytes,
|
|
37
|
+
sync: params.syncFallback,
|
|
38
38
|
});
|
|
39
39
|
return { method: "copy-fallback" };
|
|
40
40
|
}
|
|
@@ -43,12 +43,6 @@ async function renameWithRetry(params) {
|
|
|
43
43
|
}
|
|
44
44
|
throw new Error("Atomic rename retry loop exhausted.");
|
|
45
45
|
}
|
|
46
|
-
function sleepSync(ms) {
|
|
47
|
-
if (ms <= 0) {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
51
|
-
}
|
|
52
46
|
function renameWithRetrySync(params) {
|
|
53
47
|
for (let attempt = 0; attempt <= params.maxRetries; attempt++) {
|
|
54
48
|
try {
|
|
@@ -68,6 +62,8 @@ function renameWithRetrySync(params) {
|
|
|
68
62
|
destinationHardlinks: params.destinationHardlinks,
|
|
69
63
|
restore: params.copyFallbackRestore,
|
|
70
64
|
maxRestoreBytes: params.maxRestoreBytes,
|
|
65
|
+
fchmodSync: params.fchmodSync,
|
|
66
|
+
sync: params.syncFallback,
|
|
71
67
|
});
|
|
72
68
|
return { method: "copy-fallback" };
|
|
73
69
|
}
|
|
@@ -126,33 +122,8 @@ function resolveModeSync(options) {
|
|
|
126
122
|
}
|
|
127
123
|
return stat ? stat.mode : defaultMode;
|
|
128
124
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
try {
|
|
132
|
-
await handle.sync();
|
|
133
|
-
}
|
|
134
|
-
catch (error) {
|
|
135
|
-
if (error.code !== "EPERM") {
|
|
136
|
-
throw error;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
finally {
|
|
140
|
-
await handle.close();
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
function syncTempFileSync(fsModule, tempPath) {
|
|
144
|
-
const fd = fsModule.openSync(tempPath, "r+");
|
|
145
|
-
try {
|
|
146
|
-
fsModule.fsyncSync(fd);
|
|
147
|
-
}
|
|
148
|
-
catch (error) {
|
|
149
|
-
if (error.code !== "EPERM") {
|
|
150
|
-
throw error;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
finally {
|
|
154
|
-
fsModule.closeSync(fd);
|
|
155
|
-
}
|
|
125
|
+
function missingFchmodSyncError() {
|
|
126
|
+
return new TypeError("fileSystem.fchmodSync is required when mode, dirMode, or preserveExistingMode is specified");
|
|
156
127
|
}
|
|
157
128
|
async function syncDirectoryBestEffort(fsModule, dirPath) {
|
|
158
129
|
let handle;
|
|
@@ -191,9 +162,15 @@ async function cleanupTempFile(params) {
|
|
|
191
162
|
const cleanupError = await params.fsModule
|
|
192
163
|
.rm(params.tempPath, { force: true })
|
|
193
164
|
.catch((error) => error);
|
|
194
|
-
if (cleanupError
|
|
195
|
-
|
|
165
|
+
if (!cleanupError)
|
|
166
|
+
return true;
|
|
167
|
+
if (params.throwOnCleanupError) {
|
|
168
|
+
if (params.originalError !== undefined) {
|
|
169
|
+
throw new Error(`Atomic file replace failed (${String(params.originalError)}); cleanup also failed (${String(cleanupError)})`, { cause: params.originalError });
|
|
170
|
+
}
|
|
171
|
+
throw cleanupError;
|
|
196
172
|
}
|
|
173
|
+
return false;
|
|
197
174
|
}
|
|
198
175
|
export async function replaceFileAtomic(options) {
|
|
199
176
|
const filePath = options.filePath;
|
|
@@ -213,15 +190,17 @@ async function replaceFileAtomicUnserialized(options) {
|
|
|
213
190
|
const unregisterTempPath = registerTempPathForExit(tempPath);
|
|
214
191
|
let tempExists = false;
|
|
215
192
|
let originalError;
|
|
216
|
-
await fsModule.mkdir(dir, { recursive: true, mode: dirMode });
|
|
217
|
-
await fsModule.chmod(dir, dirMode).catch(() => undefined);
|
|
218
193
|
try {
|
|
194
|
+
await fsModule.mkdir(dir, { recursive: true, mode: dirMode });
|
|
195
|
+
await applyDirectoryMode({ fsModule, dirPath: dir, mode: dirMode });
|
|
219
196
|
tempExists = true;
|
|
220
|
-
await
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
197
|
+
unregisterTempPath.setIdentity(await writeTempFile({
|
|
198
|
+
fsModule,
|
|
199
|
+
tempPath,
|
|
200
|
+
content: options.content,
|
|
201
|
+
mode,
|
|
202
|
+
sync: options.syncTempFile === true,
|
|
203
|
+
}));
|
|
225
204
|
if (options.beforeRename) {
|
|
226
205
|
await options.beforeRename({ filePath, tempPath });
|
|
227
206
|
}
|
|
@@ -236,10 +215,12 @@ async function replaceFileAtomicUnserialized(options) {
|
|
|
236
215
|
copyFallbackRestore: options.copyFallbackRestore ?? "none",
|
|
237
216
|
maxRestoreBytes: options.maxRestoreBytes,
|
|
238
217
|
destinationHardlinks: options.destinationHardlinks,
|
|
218
|
+
syncFallback: options.syncTempFile === true,
|
|
239
219
|
});
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
220
|
+
if (result.method === "rename") {
|
|
221
|
+
tempExists = false;
|
|
222
|
+
unregisterTempPath();
|
|
223
|
+
}
|
|
243
224
|
if (options.syncParentDir) {
|
|
244
225
|
await syncDirectoryBestEffort(fsModule, dir);
|
|
245
226
|
}
|
|
@@ -250,15 +231,17 @@ async function replaceFileAtomicUnserialized(options) {
|
|
|
250
231
|
throw error;
|
|
251
232
|
}
|
|
252
233
|
finally {
|
|
234
|
+
let tempRemoved = !tempExists;
|
|
253
235
|
if (tempExists) {
|
|
254
|
-
await cleanupTempFile({
|
|
236
|
+
tempRemoved = await cleanupTempFile({
|
|
255
237
|
fsModule,
|
|
256
238
|
tempPath,
|
|
257
239
|
originalError,
|
|
258
240
|
throwOnCleanupError: options.throwOnCleanupError === true,
|
|
259
241
|
});
|
|
260
242
|
}
|
|
261
|
-
|
|
243
|
+
if (tempRemoved)
|
|
244
|
+
unregisterTempPath();
|
|
262
245
|
}
|
|
263
246
|
}
|
|
264
247
|
export function replaceFileAtomicSync(options) {
|
|
@@ -269,24 +252,29 @@ export function replaceFileAtomicSync(options) {
|
|
|
269
252
|
const dir = path.dirname(filePath);
|
|
270
253
|
const dirMode = options.dirMode ?? 0o700;
|
|
271
254
|
const mode = resolveModeSync(options);
|
|
255
|
+
const fchmodSync = options.fileSystem?.fchmodSync ?? (options.fileSystem === undefined ? syncFs.fchmodSync : undefined);
|
|
256
|
+
if (!fchmodSync &&
|
|
257
|
+
(options.mode !== undefined ||
|
|
258
|
+
options.preserveExistingMode === true ||
|
|
259
|
+
(process.platform !== "win32" && options.dirMode !== undefined))) {
|
|
260
|
+
throw missingFchmodSyncError();
|
|
261
|
+
}
|
|
272
262
|
const tempPath = buildReplaceTempPath(filePath, options.tempPrefix);
|
|
273
263
|
const unregisterTempPath = registerTempPathForExit(tempPath);
|
|
274
264
|
let tempExists = false;
|
|
275
265
|
let originalError;
|
|
276
|
-
fsModule.mkdirSync(dir, { recursive: true, mode: dirMode });
|
|
277
|
-
try {
|
|
278
|
-
fsModule.chmodSync(dir, dirMode);
|
|
279
|
-
}
|
|
280
|
-
catch {
|
|
281
|
-
// Best-effort on platforms that do not enforce POSIX modes.
|
|
282
|
-
}
|
|
283
266
|
try {
|
|
267
|
+
fsModule.mkdirSync(dir, { recursive: true, mode: dirMode });
|
|
268
|
+
applyDirectoryModeSync({ fsModule, dirPath: dir, mode: dirMode, fchmodSync });
|
|
284
269
|
tempExists = true;
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
270
|
+
unregisterTempPath.setIdentity(writeTempFileSync({
|
|
271
|
+
fsModule,
|
|
272
|
+
tempPath,
|
|
273
|
+
content: options.content,
|
|
274
|
+
mode,
|
|
275
|
+
fchmodSync,
|
|
276
|
+
sync: options.syncTempFile === true,
|
|
277
|
+
}));
|
|
290
278
|
if (options.beforeRename) {
|
|
291
279
|
options.beforeRename({ filePath, tempPath });
|
|
292
280
|
}
|
|
@@ -301,14 +289,12 @@ export function replaceFileAtomicSync(options) {
|
|
|
301
289
|
copyFallbackRestore: options.copyFallbackRestore ?? "none",
|
|
302
290
|
maxRestoreBytes: options.maxRestoreBytes,
|
|
303
291
|
destinationHardlinks: options.destinationHardlinks,
|
|
292
|
+
fchmodSync,
|
|
293
|
+
syncFallback: options.syncTempFile === true,
|
|
304
294
|
});
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
fsModule.chmodSync(filePath, mode);
|
|
309
|
-
}
|
|
310
|
-
catch {
|
|
311
|
-
// Best-effort on platforms that do not enforce POSIX modes.
|
|
295
|
+
if (result.method === "rename") {
|
|
296
|
+
tempExists = false;
|
|
297
|
+
unregisterTempPath();
|
|
312
298
|
}
|
|
313
299
|
if (options.syncParentDir) {
|
|
314
300
|
syncDirectoryBestEffortSync(fsModule, dir);
|
|
@@ -320,17 +306,23 @@ export function replaceFileAtomicSync(options) {
|
|
|
320
306
|
throw error;
|
|
321
307
|
}
|
|
322
308
|
finally {
|
|
309
|
+
let tempRemoved = !tempExists;
|
|
323
310
|
if (tempExists) {
|
|
324
311
|
try {
|
|
325
312
|
fsModule.rmSync(tempPath, { force: true });
|
|
313
|
+
tempRemoved = true;
|
|
326
314
|
}
|
|
327
315
|
catch (cleanupError) {
|
|
328
|
-
if (options.throwOnCleanupError
|
|
329
|
-
|
|
316
|
+
if (options.throwOnCleanupError) {
|
|
317
|
+
if (originalError !== undefined) {
|
|
318
|
+
throw new Error(`Atomic file replace failed (${String(originalError)}); cleanup also failed (${String(cleanupError)})`, { cause: originalError });
|
|
319
|
+
}
|
|
320
|
+
throw cleanupError;
|
|
330
321
|
}
|
|
331
322
|
// The temp file is best-effort cleanup after write failure.
|
|
332
323
|
}
|
|
333
324
|
}
|
|
334
|
-
|
|
325
|
+
if (tempRemoved)
|
|
326
|
+
unregisterTempPath();
|
|
335
327
|
}
|
|
336
328
|
}
|
package/dist/root-context.d.ts
CHANGED
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
export type RootContext = {
|
|
2
2
|
rootDir: string;
|
|
3
|
+
rootIdentity: {
|
|
4
|
+
dev: number;
|
|
5
|
+
ino: number;
|
|
6
|
+
};
|
|
3
7
|
rootReal: string;
|
|
4
8
|
rootWithSep: string;
|
|
5
9
|
};
|
|
6
10
|
export declare const ensureTrailingSep: (value: string) => string;
|
|
7
11
|
export declare function assertValidRootRelativePath(relativePath: string): void;
|
|
12
|
+
export declare function assertValidRootDestinationPath(relativePath: string): void;
|
|
8
13
|
export declare function expandRelativePathWithHome(relativePath: string): Promise<string>;
|
|
9
14
|
export declare function resolveRootContext(rootDir: string): Promise<RootContext>;
|
|
15
|
+
export declare function assertRootIdentityCurrent(root: RootContext): Promise<void>;
|
|
10
16
|
export declare function resolvePathInRoot(root: RootContext, relativePath: string, options?: {
|
|
11
17
|
aliasErrorCode?: "outside-workspace" | "path-alias";
|
|
12
18
|
allowFinalSymlink?: boolean;
|
|
19
|
+
rejectUnsafeDeviceReads?: boolean;
|
|
20
|
+
rejectSymlinks?: boolean;
|
|
13
21
|
}): Promise<{
|
|
14
22
|
rootReal: string;
|
|
15
23
|
rootWithSep: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root-context.d.ts","sourceRoot":"","sources":["../src/root-context.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"root-context.d.ts","sourceRoot":"","sources":["../src/root-context.ts"],"names":[],"mappings":"AAiBA,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,iBAAiB,UAAW,MAAM,WACM,CAAC;AAEtD,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAEtE;AAED,wBAAgB,8BAA8B,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAKzE;AAID,wBAAsB,0BAA0B,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAYtF;AAED,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CA0B9E;AAED,wBAAsB,yBAAyB,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBhF;AAED,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,WAAW,EACjB,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE;IACR,cAAc,CAAC,EAAE,mBAAmB,GAAG,YAAY,CAAC;IACpD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,GACA,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA0CtE;AAED,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAEvE"}
|
package/dist/root-context.js
CHANGED
|
@@ -2,13 +2,22 @@ import fs from "node:fs/promises";
|
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { FsSafeError } from "./errors.js";
|
|
5
|
+
import { sameFileIdentity } from "./file-identity.js";
|
|
5
6
|
import { expandHomePrefix } from "./home-dir.js";
|
|
6
|
-
import { assertNoNulPathInput, isNotFoundPathError, isPathInside } from "./path.js";
|
|
7
|
+
import { assertNoNulPathInput, assertNoUnsafeDeviceReadPath, hasNodeErrorCode, isNotFoundPathError, isPathInside, } from "./path.js";
|
|
7
8
|
import { ROOT_PATH_ALIAS_POLICIES, resolveRootPath } from "./root-path.js";
|
|
9
|
+
import { outsideWorkspaceError } from "./root-errors.js";
|
|
10
|
+
import { isDriveRelativePath } from "./safe-path-segment.js";
|
|
8
11
|
export const ensureTrailingSep = (value) => value.endsWith(path.sep) ? value : value + path.sep;
|
|
9
12
|
export function assertValidRootRelativePath(relativePath) {
|
|
10
13
|
assertNoNulPathInput(relativePath, "relative path contains a NUL byte");
|
|
11
14
|
}
|
|
15
|
+
export function assertValidRootDestinationPath(relativePath) {
|
|
16
|
+
assertValidRootRelativePath(relativePath);
|
|
17
|
+
if (isDriveRelativePath(relativePath)) {
|
|
18
|
+
throw new FsSafeError("invalid-path", "relative path must not start with a drive letter");
|
|
19
|
+
}
|
|
20
|
+
}
|
|
12
21
|
let cachedHomePath;
|
|
13
22
|
export async function expandRelativePathWithHome(relativePath) {
|
|
14
23
|
const rawHome = process.env.HOME || process.env.USERPROFILE || os.homedir();
|
|
@@ -27,12 +36,14 @@ export async function expandRelativePathWithHome(relativePath) {
|
|
|
27
36
|
export async function resolveRootContext(rootDir) {
|
|
28
37
|
assertNoNulPathInput(rootDir, "root dir contains a NUL byte");
|
|
29
38
|
let rootReal;
|
|
39
|
+
let rootIdentity;
|
|
30
40
|
try {
|
|
31
41
|
rootReal = await fs.realpath(rootDir);
|
|
32
42
|
const rootStat = await fs.stat(rootReal);
|
|
33
43
|
if (!rootStat.isDirectory()) {
|
|
34
44
|
throw new FsSafeError("invalid-path", "root dir is not a directory");
|
|
35
45
|
}
|
|
46
|
+
rootIdentity = { dev: rootStat.dev, ino: rootStat.ino };
|
|
36
47
|
}
|
|
37
48
|
catch (err) {
|
|
38
49
|
if (err instanceof FsSafeError) {
|
|
@@ -45,16 +56,37 @@ export async function resolveRootContext(rootDir) {
|
|
|
45
56
|
}
|
|
46
57
|
return {
|
|
47
58
|
rootDir: path.resolve(rootDir),
|
|
59
|
+
rootIdentity,
|
|
48
60
|
rootReal,
|
|
49
61
|
rootWithSep: ensureTrailingSep(rootReal),
|
|
50
62
|
};
|
|
51
63
|
}
|
|
64
|
+
export async function assertRootIdentityCurrent(root) {
|
|
65
|
+
let current;
|
|
66
|
+
try {
|
|
67
|
+
current = await fs.lstat(root.rootReal);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
throw new FsSafeError("path-mismatch", "root path changed during operation", {
|
|
71
|
+
cause: error instanceof Error ? error : undefined,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
if (current.isSymbolicLink() ||
|
|
75
|
+
!current.isDirectory() ||
|
|
76
|
+
!sameFileIdentity(current, root.rootIdentity)) {
|
|
77
|
+
throw new FsSafeError("path-mismatch", "root path changed during operation");
|
|
78
|
+
}
|
|
79
|
+
}
|
|
52
80
|
export async function resolvePathInRoot(root, relativePath, options) {
|
|
53
81
|
assertValidRootRelativePath(relativePath);
|
|
82
|
+
await assertRootIdentityCurrent(root);
|
|
54
83
|
const expanded = await expandRelativePathWithHome(relativePath);
|
|
55
84
|
const resolved = path.resolve(root.rootWithSep, expanded);
|
|
56
85
|
if (!isPathInside(root.rootWithSep, resolved)) {
|
|
57
|
-
throw
|
|
86
|
+
throw outsideWorkspaceError();
|
|
87
|
+
}
|
|
88
|
+
if (options?.rejectUnsafeDeviceReads === true) {
|
|
89
|
+
assertNoUnsafeDeviceReadPath(resolved);
|
|
58
90
|
}
|
|
59
91
|
const rawAbsolutePath = path.isAbsolute(expanded)
|
|
60
92
|
? expanded
|
|
@@ -66,9 +98,18 @@ export async function resolvePathInRoot(root, relativePath, options) {
|
|
|
66
98
|
rootCanonicalPath: root.rootReal,
|
|
67
99
|
boundaryLabel: "root",
|
|
68
100
|
policy: options?.allowFinalSymlink ? ROOT_PATH_ALIAS_POLICIES.unlinkTarget : undefined,
|
|
101
|
+
rejectSymlinks: options?.rejectSymlinks,
|
|
69
102
|
});
|
|
70
103
|
}
|
|
71
104
|
catch (error) {
|
|
105
|
+
if (error instanceof FsSafeError && error.code === "symlink") {
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
if (hasNodeErrorCode(error, "ENAMETOOLONG")) {
|
|
109
|
+
throw new FsSafeError("invalid-path", "relative path is too long", {
|
|
110
|
+
cause: error instanceof Error ? error : undefined,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
72
113
|
const code = options?.aliasErrorCode ?? "outside-workspace";
|
|
73
114
|
throw new FsSafeError(code, code === "path-alias" ? "path alias escape blocked" : "file is outside workspace root", {
|
|
74
115
|
cause: error instanceof Error ? error : undefined,
|
package/dist/root-errors.d.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
+
import { FsSafeError } from "./errors.js";
|
|
2
|
+
export declare function fileNotFoundError(cause?: unknown): FsSafeError;
|
|
3
|
+
export declare function outsideWorkspaceError(): FsSafeError;
|
|
4
|
+
export declare function directoryComponentNotDirectoryError(cause?: unknown): FsSafeError;
|
|
5
|
+
export declare function hardlinkedPathNotAllowedError(): FsSafeError;
|
|
1
6
|
export declare function isAlreadyExistsError(error: unknown): boolean;
|
|
2
7
|
export declare function normalizePinnedWriteError(error: unknown): Error;
|
|
3
8
|
export declare function normalizePinnedPathError(error: unknown): Error;
|
|
9
|
+
export declare function normalizeRemoveGuardError(error: unknown): Error;
|
|
10
|
+
export declare function normalizeRemovePathError(error: unknown): Error;
|
|
4
11
|
//# sourceMappingURL=root-errors.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root-errors.d.ts","sourceRoot":"","sources":["../src/root-errors.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"root-errors.d.ts","sourceRoot":"","sources":["../src/root-errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAK1C,wBAAgB,iBAAiB,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,WAAW,CAI9D;AAED,wBAAgB,qBAAqB,IAAI,WAAW,CAEnD;AAED,wBAAgB,mCAAmC,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,WAAW,CAIhF;AAED,wBAAgB,6BAA6B,IAAI,WAAW,CAE3D;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE5D;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAU/D;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAO9D;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAQ/D;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAe9D"}
|
package/dist/root-errors.js
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
import { FsSafeError } from "./errors.js";
|
|
2
|
-
import { hasNodeErrorCode } from "./path.js";
|
|
2
|
+
import { hasNodeErrorCode, isNodeError, isNotFoundPathError } from "./path.js";
|
|
3
|
+
const REMOVE_NOT_EMPTY_CODES = new Set(["ENOTEMPTY", "EEXIST"]);
|
|
4
|
+
export function fileNotFoundError(cause) {
|
|
5
|
+
return cause === undefined
|
|
6
|
+
? new FsSafeError("not-found", "file not found")
|
|
7
|
+
: new FsSafeError("not-found", "file not found", { cause });
|
|
8
|
+
}
|
|
9
|
+
export function outsideWorkspaceError() {
|
|
10
|
+
return new FsSafeError("outside-workspace", "file is outside workspace root");
|
|
11
|
+
}
|
|
12
|
+
export function directoryComponentNotDirectoryError(cause) {
|
|
13
|
+
return cause === undefined
|
|
14
|
+
? new FsSafeError("not-file", "directory component must be a directory")
|
|
15
|
+
: new FsSafeError("not-file", "directory component must be a directory", { cause });
|
|
16
|
+
}
|
|
17
|
+
export function hardlinkedPathNotAllowedError() {
|
|
18
|
+
return new FsSafeError("hardlink", "hardlinked path not allowed");
|
|
19
|
+
}
|
|
3
20
|
export function isAlreadyExistsError(error) {
|
|
4
21
|
return hasNodeErrorCode(error, "EEXIST") || /File exists|EEXIST/i.test(String(error));
|
|
5
22
|
}
|
|
@@ -7,6 +24,9 @@ export function normalizePinnedWriteError(error) {
|
|
|
7
24
|
if (error instanceof FsSafeError) {
|
|
8
25
|
return error;
|
|
9
26
|
}
|
|
27
|
+
if (isNotFoundPathError(error)) {
|
|
28
|
+
return fileNotFoundError(error instanceof Error ? error : undefined);
|
|
29
|
+
}
|
|
10
30
|
return new FsSafeError("invalid-path", "path is not a regular file under root", {
|
|
11
31
|
cause: error instanceof Error ? error : undefined,
|
|
12
32
|
});
|
|
@@ -19,3 +39,28 @@ export function normalizePinnedPathError(error) {
|
|
|
19
39
|
cause: error instanceof Error ? error : undefined,
|
|
20
40
|
});
|
|
21
41
|
}
|
|
42
|
+
export function normalizeRemoveGuardError(error) {
|
|
43
|
+
if (error instanceof FsSafeError) {
|
|
44
|
+
return error;
|
|
45
|
+
}
|
|
46
|
+
if (isNotFoundPathError(error)) {
|
|
47
|
+
return fileNotFoundError(error instanceof Error ? error : undefined);
|
|
48
|
+
}
|
|
49
|
+
return normalizePinnedPathError(error);
|
|
50
|
+
}
|
|
51
|
+
export function normalizeRemovePathError(error) {
|
|
52
|
+
if (error instanceof FsSafeError) {
|
|
53
|
+
return error;
|
|
54
|
+
}
|
|
55
|
+
if (!isNodeError(error) || typeof error.code !== "string") {
|
|
56
|
+
return normalizePinnedPathError(error);
|
|
57
|
+
}
|
|
58
|
+
const cause = error instanceof Error ? error : undefined;
|
|
59
|
+
if (isNotFoundPathError(error)) {
|
|
60
|
+
return fileNotFoundError(cause);
|
|
61
|
+
}
|
|
62
|
+
if (REMOVE_NOT_EMPTY_CODES.has(error.code)) {
|
|
63
|
+
return new FsSafeError("not-empty", "directory is not empty", { cause });
|
|
64
|
+
}
|
|
65
|
+
return new FsSafeError("not-removable", "path could not be removed", { cause });
|
|
66
|
+
}
|
package/dist/root-file.d.ts
CHANGED
package/dist/root-file.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root-file.d.ts","sourceRoot":"","sources":["../src/root-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AAOzB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAEL,KAAK,yBAAyB,EAC9B,KAAK,2BAA2B,EACjC,MAAM,kBAAkB,CAAC;AAE1B,KAAK,cAAc,GAAG,IAAI,CACxB,OAAO,EAAE,EACP,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,UAAU,GACV,cAAc,GACd,cAAc,CACjB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,2BAA2B,GAAG,YAAY,CAAC;AAEnF,MAAM,MAAM,kBAAkB,GAC1B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAC5E;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,yBAAyB,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtE,MAAM,MAAM,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,EAAE;IAAE,EAAE,EAAE,KAAK,CAAA;CAAE,CAAC,CAAC;AAE7E,MAAM,MAAM,sBAAsB,GAAG;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,WAAW,CAAC,EAAE,yBAAyB,CAAC;IACxC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,IAAI,CAAC,EAAE,cAAc,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,sBAAsB,GAAG;IACxD,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B,CAAC;AAQF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAW3D;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,kBAAkB,
|
|
1
|
+
{"version":3,"file":"root-file.d.ts","sourceRoot":"","sources":["../src/root-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AAOzB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAEL,KAAK,yBAAyB,EAC9B,KAAK,2BAA2B,EACjC,MAAM,kBAAkB,CAAC;AAE1B,KAAK,cAAc,GAAG,IAAI,CACxB,OAAO,EAAE,EACP,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,UAAU,GACV,cAAc,GACd,cAAc,CACjB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,2BAA2B,GAAG,YAAY,CAAC;AAEnF,MAAM,MAAM,kBAAkB,GAC1B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAC5E;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,yBAAyB,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtE,MAAM,MAAM,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,EAAE;IAAE,EAAE,EAAE,KAAK,CAAA;CAAE,CAAC,CAAC;AAE7E,MAAM,MAAM,sBAAsB,GAAG;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,WAAW,CAAC,EAAE,yBAAyB,CAAC;IACxC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,IAAI,CAAC,EAAE,cAAc,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,sBAAsB,GAAG;IACxD,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B,CAAC;AAQF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAW3D;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,kBAAkB,CAwBnF;AAED,wBAAgB,wBAAwB,CAAC,CAAC,EACxC,OAAO,EAAE,mBAAmB,EAC5B,QAAQ,EAAE;IACR,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,CAAC,CAAC;IAC3C,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,CAAC,CAAC;IACjD,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,CAAC,CAAC;IACzC,QAAQ,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,CAAC,CAAC;CAC/C,GACA,CAAC,CAUH;AAoDD,wBAAsB,YAAY,CAChC,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,kBAAkB,CAAC,CAuB7B"}
|
package/dist/root-file.js
CHANGED
|
@@ -21,6 +21,7 @@ export function openRootFileSync(params) {
|
|
|
21
21
|
rootPath: params.rootPath,
|
|
22
22
|
rootCanonicalPath: params.rootRealPath,
|
|
23
23
|
boundaryLabel: params.boundaryLabel,
|
|
24
|
+
rejectSymlinks: params.rejectSymlinks ?? true,
|
|
24
25
|
skipLexicalRootCheck: params.skipLexicalRootCheck,
|
|
25
26
|
}),
|
|
26
27
|
});
|
|
@@ -90,6 +91,7 @@ export async function openRootFile(params) {
|
|
|
90
91
|
rootCanonicalPath: params.rootRealPath,
|
|
91
92
|
boundaryLabel: params.boundaryLabel,
|
|
92
93
|
policy: params.aliasPolicy,
|
|
94
|
+
rejectSymlinks: params.rejectSymlinks ?? true,
|
|
93
95
|
skipLexicalRootCheck: params.skipLexicalRootCheck,
|
|
94
96
|
}),
|
|
95
97
|
});
|
package/dist/root-impl.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root-impl.d.ts","sourceRoot":"","sources":["../src/root-impl.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAO7D,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,KAAK,oBAAoB,EAG1B,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"root-impl.d.ts","sourceRoot":"","sources":["../src/root-impl.ts"],"names":[],"mappings":"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"}
|