@openclaw/fs-safe 0.8.2 → 0.8.4
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 +19 -0
- package/README.md +1 -1
- package/dist/absolute-path.d.ts.map +1 -1
- package/dist/absolute-path.js +8 -7
- package/dist/advanced.d.ts +2 -2
- package/dist/advanced.d.ts.map +1 -1
- package/dist/advanced.js +2 -2
- package/dist/archive-kind.d.ts +1 -0
- package/dist/archive-kind.d.ts.map +1 -1
- package/dist/archive-kind.js +6 -0
- package/dist/archive-limits.d.ts +0 -1
- package/dist/archive-limits.d.ts.map +1 -1
- package/dist/archive-limits.js +0 -3
- package/dist/archive-native.d.ts +1 -0
- package/dist/archive-native.d.ts.map +1 -1
- package/dist/archive-native.js +20 -76
- package/dist/archive-parser-errors.d.ts +2 -0
- package/dist/archive-parser-errors.d.ts.map +1 -0
- package/dist/archive-parser-errors.js +12 -0
- package/dist/archive-plan.d.ts +20 -0
- package/dist/archive-plan.d.ts.map +1 -0
- package/dist/archive-plan.js +55 -0
- package/dist/archive-read.d.ts.map +1 -1
- package/dist/archive-read.js +7 -13
- package/dist/archive-tar-inspect.d.ts +7 -0
- package/dist/archive-tar-inspect.d.ts.map +1 -0
- package/dist/archive-tar-inspect.js +59 -0
- package/dist/archive-tar-wasm.d.ts +1 -1
- package/dist/archive-tar-wasm.d.ts.map +1 -1
- package/dist/archive-tar-wasm.js +5 -8
- package/dist/archive-tar.d.ts +3 -1
- package/dist/archive-tar.d.ts.map +1 -1
- package/dist/archive-tar.js +12 -49
- package/dist/archive.d.ts +1 -0
- package/dist/archive.d.ts.map +1 -1
- package/dist/archive.js +54 -33
- package/dist/atomic.d.ts +1 -1
- package/dist/atomic.d.ts.map +1 -1
- package/dist/atomic.js +1 -1
- package/dist/bounded-read-stream.d.ts +1 -5
- package/dist/bounded-read-stream.d.ts.map +1 -1
- package/dist/bounded-read-stream.js +5 -13
- package/dist/bounded-read.d.ts.map +1 -1
- package/dist/bounded-read.js +31 -4
- package/dist/byte-budget.d.ts +0 -1
- package/dist/byte-budget.d.ts.map +1 -1
- package/dist/byte-budget.js +1 -1
- package/dist/directory-durability.js +5 -5
- package/dist/directory-guard.d.ts.map +1 -1
- package/dist/directory-guard.js +5 -6
- package/dist/directory-mode-owner.d.ts.map +1 -1
- package/dist/directory-mode-owner.js +2 -0
- package/dist/error-detail.d.ts +1 -0
- package/dist/error-detail.d.ts.map +1 -1
- package/dist/error-detail.js +6 -0
- package/dist/file-store-boundary.d.ts +1 -1
- package/dist/file-store-boundary.d.ts.map +1 -1
- package/dist/file-store-boundary.js +3 -14
- package/dist/file-store-prune.js +17 -8
- package/dist/file-store.js +3 -3
- package/dist/file-sync.d.ts +5 -0
- package/dist/file-sync.d.ts.map +1 -0
- package/dist/file-sync.js +19 -0
- package/dist/guarded-mkdir.d.ts.map +1 -1
- package/dist/guarded-mkdir.js +5 -4
- package/dist/guarded-mutation.d.ts +3 -0
- package/dist/guarded-mutation.d.ts.map +1 -1
- package/dist/guarded-mutation.js +5 -1
- package/dist/home-dir.d.ts +0 -10
- package/dist/home-dir.d.ts.map +1 -1
- package/dist/home-dir.js +0 -28
- package/dist/json-durable-queue-ownership.d.ts +1 -0
- package/dist/json-durable-queue-ownership.d.ts.map +1 -1
- package/dist/json-durable-queue-ownership.js +139 -18
- package/dist/json-durable-queue.d.ts.map +1 -1
- package/dist/json-durable-queue.js +5 -10
- package/dist/json-store.d.ts.map +1 -1
- package/dist/json-store.js +1 -1
- package/dist/local-roots.d.ts.map +1 -1
- package/dist/local-roots.js +2 -3
- package/dist/move-path-cleanup.d.ts +1 -1
- package/dist/move-path-cleanup.d.ts.map +1 -1
- package/dist/move-path-cleanup.js +4 -2
- package/dist/move-path.d.ts +9 -0
- package/dist/move-path.d.ts.map +1 -1
- package/dist/move-path.js +53 -16
- package/dist/native-binding.d.ts +2 -1
- package/dist/native-binding.d.ts.map +1 -1
- package/dist/native-operations.d.ts +0 -1
- package/dist/native-operations.d.ts.map +1 -1
- package/dist/native-operations.js +0 -10
- package/dist/native-pinned-write-windows.d.ts.map +1 -1
- package/dist/native-pinned-write-windows.js +8 -4
- package/dist/native-pinned-write.js +3 -3
- package/dist/native-staged-file.d.ts +10 -3
- package/dist/native-staged-file.d.ts.map +1 -1
- package/dist/native-staged-file.js +38 -13
- package/dist/opened-realpath.d.ts +12 -1
- package/dist/opened-realpath.d.ts.map +1 -1
- package/dist/opened-realpath.js +16 -14
- package/dist/output.d.ts.map +1 -1
- package/dist/output.js +26 -2
- package/dist/path-policy.js +3 -3
- package/dist/permissions.d.ts +1 -0
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js +3 -0
- package/dist/pinned-write.d.ts +2 -2
- package/dist/pinned-write.d.ts.map +1 -1
- package/dist/pinned-write.js +17 -22
- package/dist/private-temp-workspace.js +1 -1
- package/dist/publish-file.js +2 -2
- package/dist/regular-file.js +8 -8
- package/dist/replace-file-copy-source.d.ts.map +1 -1
- package/dist/replace-file-copy-source.js +2 -7
- package/dist/replace-file-descriptor.d.ts.map +1 -1
- package/dist/replace-file-descriptor.js +11 -20
- package/dist/replace-file-temp-owner.d.ts.map +1 -1
- package/dist/replace-file-temp-owner.js +15 -14
- package/dist/replace-file.d.ts.map +1 -1
- package/dist/replace-file.js +21 -8
- package/dist/root-context.js +5 -5
- package/dist/root-errors.d.ts +1 -0
- package/dist/root-errors.d.ts.map +1 -1
- package/dist/root-errors.js +9 -0
- package/dist/root-file.d.ts.map +1 -1
- package/dist/root-file.js +17 -28
- package/dist/root-impl.d.ts +2 -1
- package/dist/root-impl.d.ts.map +1 -1
- package/dist/root-impl.js +46 -58
- package/dist/root-path-existing.d.ts.map +1 -1
- package/dist/root-path-existing.js +2 -3
- package/dist/root-path-symlink.d.ts.map +1 -1
- package/dist/root-path-symlink.js +2 -3
- package/dist/root-path.d.ts.map +1 -1
- package/dist/root-path.js +51 -97
- package/dist/root-paths.d.ts.map +1 -1
- package/dist/root-paths.js +16 -15
- package/dist/root-write-mode.d.ts +6 -0
- package/dist/root-write-mode.d.ts.map +1 -0
- package/dist/root-write-mode.js +61 -0
- package/dist/root-write-verification.js +8 -8
- package/dist/safe-path-segment.d.ts +1 -0
- package/dist/safe-path-segment.d.ts.map +1 -1
- package/dist/safe-path-segment.js +1 -1
- package/dist/secret-file.d.ts.map +1 -1
- package/dist/secret-file.js +4 -11
- package/dist/secret-read-async.d.ts.map +1 -1
- package/dist/secret-read-async.js +2 -10
- package/dist/secret-read-policy.d.ts +4 -0
- package/dist/secret-read-policy.d.ts.map +1 -1
- package/dist/secret-read-policy.js +12 -0
- package/dist/sibling-staged-file.d.ts.map +1 -1
- package/dist/sibling-staged-file.js +2 -7
- package/dist/sidecar-lock-policy.d.ts +0 -1
- package/dist/sidecar-lock-policy.d.ts.map +1 -1
- package/dist/sidecar-lock-policy.js +0 -4
- package/dist/strict-file-identity.d.ts +1 -1
- package/dist/strict-file-identity.d.ts.map +1 -1
- package/dist/string-coerce.d.ts +0 -9
- package/dist/string-coerce.d.ts.map +1 -1
- package/dist/string-coerce.js +0 -56
- package/dist/symlink-parents.d.ts.map +1 -1
- package/dist/symlink-parents.js +1 -2
- package/dist/temp-target.d.ts.map +1 -1
- package/dist/temp-target.js +1 -12
- package/docs/archive.md +57 -0
- package/docs/atomic.md +53 -19
- package/docs/reading.md +2 -0
- package/docs/root.md +10 -1
- package/docs/staged-file.md +6 -2
- package/docs/types.md +2 -1
- package/docs/writing.md +30 -2
- package/package.json +8 -8
- package/dist/archive-tar-extract.d.ts +0 -11
- package/dist/archive-tar-extract.d.ts.map +0 -1
- package/dist/archive-tar-extract.js +0 -49
- package/dist/fsync.d.ts +0 -2
- package/dist/fsync.d.ts.map +0 -1
- package/dist/fsync.js +0 -1
- package/dist/json-durable-queue-retirement.d.ts +0 -9
- package/dist/json-durable-queue-retirement.d.ts.map +0 -1
- package/dist/json-durable-queue-retirement.js +0 -126
- package/dist/json-durable-queue-transfer-lock.d.ts +0 -2
- package/dist/json-durable-queue-transfer-lock.d.ts.map +0 -1
- package/dist/json-durable-queue-transfer-lock.js +0 -19
- package/dist/mode.d.ts +0 -2
- package/dist/mode.d.ts.map +0 -1
- package/dist/mode.js +0 -3
- package/dist/output-sibling.d.ts +0 -8
- package/dist/output-sibling.d.ts.map +0 -1
- package/dist/output-sibling.js +0 -30
- package/dist/read-error.d.ts +0 -2
- package/dist/read-error.d.ts.map +0 -1
- package/dist/read-error.js +0 -11
- package/dist/short-path.d.ts +0 -2
- package/dist/short-path.d.ts.map +0 -1
- package/dist/short-path.js +0 -7
- package/dist/staged-file.d.ts +0 -10
- package/dist/staged-file.d.ts.map +0 -1
- package/dist/staged-file.js +0 -15
package/dist/file-store-prune.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import fsSync, {} from "node:fs";
|
|
1
2
|
import fs from "node:fs/promises";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { FsSafeError } from "./errors.js";
|
|
@@ -10,29 +11,29 @@ export async function pruneExpiredStoreEntries(params) {
|
|
|
10
11
|
const maxDepth = params.options.maxDepth;
|
|
11
12
|
const pruneEmptyDirs = (recursive || maxDepth !== undefined) && (params.options.pruneEmptyDirs ?? false);
|
|
12
13
|
await fs.mkdir(params.rootDir, { recursive: true, mode: params.dirMode });
|
|
13
|
-
const rootReal =
|
|
14
|
+
const rootReal = fsSync.realpathSync.native(params.rootDir);
|
|
14
15
|
const scopedRoot = await root(rootReal);
|
|
15
16
|
const rootGuard = {
|
|
16
17
|
dir: rootReal,
|
|
17
18
|
realPath: rootReal,
|
|
18
|
-
stat:
|
|
19
|
+
stat: fsSync.lstatSync(rootReal),
|
|
19
20
|
};
|
|
20
21
|
async function assertRootGuard() {
|
|
21
|
-
const stat =
|
|
22
|
+
const stat = fsSync.lstatSync(rootGuard.dir);
|
|
22
23
|
if (stat.isSymbolicLink() ||
|
|
23
24
|
!stat.isDirectory() ||
|
|
24
25
|
stat.dev !== rootGuard.stat.dev ||
|
|
25
26
|
stat.ino !== rootGuard.stat.ino ||
|
|
26
|
-
|
|
27
|
+
fsSync.realpathSync.native(rootGuard.dir) !== rootGuard.realPath) {
|
|
27
28
|
throw new FsSafeError("path-mismatch", "store root changed during prune");
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
31
|
async function readStableDirectory(dir) {
|
|
31
|
-
const before =
|
|
32
|
+
const before = observeOrNull(() => fsSync.lstatSync(dir));
|
|
32
33
|
if (!before || before.isSymbolicLink() || !before.isDirectory()) {
|
|
33
34
|
return null;
|
|
34
35
|
}
|
|
35
|
-
const real =
|
|
36
|
+
const real = observeOrNull(() => fsSync.realpathSync.native(dir));
|
|
36
37
|
if (!real || !isPathInside(rootReal, real)) {
|
|
37
38
|
return null;
|
|
38
39
|
}
|
|
@@ -40,7 +41,7 @@ export async function pruneExpiredStoreEntries(params) {
|
|
|
40
41
|
if (!entries) {
|
|
41
42
|
return null;
|
|
42
43
|
}
|
|
43
|
-
const after =
|
|
44
|
+
const after = observeOrNull(() => fsSync.lstatSync(dir));
|
|
44
45
|
if (!after || before.dev !== after.dev || before.ino !== after.ino) {
|
|
45
46
|
return null;
|
|
46
47
|
}
|
|
@@ -54,7 +55,7 @@ export async function pruneExpiredStoreEntries(params) {
|
|
|
54
55
|
for (const entry of entries) {
|
|
55
56
|
const fullPath = path.join(dir, entry.name);
|
|
56
57
|
const relativePath = relativeDir ? `${relativeDir}/${entry.name}` : entry.name;
|
|
57
|
-
const stat =
|
|
58
|
+
const stat = observeOrNull(() => fsSync.lstatSync(fullPath));
|
|
58
59
|
if (!stat || stat.isSymbolicLink()) {
|
|
59
60
|
continue;
|
|
60
61
|
}
|
|
@@ -84,3 +85,11 @@ export async function pruneExpiredStoreEntries(params) {
|
|
|
84
85
|
}
|
|
85
86
|
await pruneDir(rootReal, "", 0);
|
|
86
87
|
}
|
|
88
|
+
function observeOrNull(observe) {
|
|
89
|
+
try {
|
|
90
|
+
return observe();
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
package/dist/file-store.js
CHANGED
|
@@ -11,7 +11,7 @@ import { writeFileSyncAtomic } from "./file-store-sync-write.js";
|
|
|
11
11
|
import { createJsonStore } from "./json-document-store.js";
|
|
12
12
|
import { stringifyJsonDocument } from "./json-stringify.js";
|
|
13
13
|
import { isNotFoundPathError, resolveSafeRelativePath, splitSafeRelativePath } from "./path.js";
|
|
14
|
-
import { throwFsSafeReadError } from "./
|
|
14
|
+
import { throwFsSafeReadError } from "./root-errors.js";
|
|
15
15
|
import { root } from "./root.js";
|
|
16
16
|
import { DEFAULT_ROOT_MAX_BYTES } from "./root-impl.js";
|
|
17
17
|
import { readRegularFile } from "./regular-file.js";
|
|
@@ -66,7 +66,7 @@ function handleSyncStoreReadOpenFailure(opened) {
|
|
|
66
66
|
});
|
|
67
67
|
}
|
|
68
68
|
async function readFileStoreCopySource(params) {
|
|
69
|
-
const sourceStat =
|
|
69
|
+
const sourceStat = syncFs.lstatSync(params.sourcePath);
|
|
70
70
|
if (sourceStat.isSymbolicLink() || !sourceStat.isFile()) {
|
|
71
71
|
throw new FsSafeError("not-file", "source path is not a file");
|
|
72
72
|
}
|
|
@@ -93,7 +93,7 @@ async function readFileStoreCopySource(params) {
|
|
|
93
93
|
async function copyIntoRoot(params) {
|
|
94
94
|
const relativePath = assertRelativePath(params.relativePath);
|
|
95
95
|
const destination = resolveStorePath(params.rootDir, relativePath);
|
|
96
|
-
const sourceStat =
|
|
96
|
+
const sourceStat = syncFs.lstatSync(params.sourcePath);
|
|
97
97
|
if (sourceStat.isSymbolicLink() || !sourceStat.isFile()) {
|
|
98
98
|
throw new FsSafeError("not-file", "source path is not a file");
|
|
99
99
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import type { FileHandle } from "node:fs/promises";
|
|
3
|
+
export declare function syncFileBestEffort(handle: Pick<FileHandle, "sync">): Promise<void>;
|
|
4
|
+
export declare function syncFileBestEffortSync(fd: number, fsModule?: Pick<typeof fs, "fsyncSync">): void;
|
|
5
|
+
//# sourceMappingURL=file-sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-sync.d.ts","sourceRoot":"","sources":["../src/file-sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAMxF;AAED,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,MAAM,EACV,QAAQ,GAAE,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,CAAM,GAC1C,IAAI,CAMN"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
export async function syncFileBestEffort(handle) {
|
|
3
|
+
try {
|
|
4
|
+
await handle.sync();
|
|
5
|
+
}
|
|
6
|
+
catch (error) {
|
|
7
|
+
if (error?.code !== "EPERM")
|
|
8
|
+
throw error;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function syncFileBestEffortSync(fd, fsModule = fs) {
|
|
12
|
+
try {
|
|
13
|
+
fsModule.fsyncSync(fd);
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
if (error?.code !== "EPERM")
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guarded-mkdir.d.ts","sourceRoot":"","sources":["../src/guarded-mkdir.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"guarded-mkdir.d.ts","sourceRoot":"","sources":["../src/guarded-mkdir.ts"],"names":[],"mappings":"AA0BA;;;;;GAKG;AACH,wBAAsB,6BAA6B,CAAC,MAAM,EAAE;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,GAAG,OAAO,CAAC,MAAM,CAAC,CAuDlB"}
|
package/dist/guarded-mkdir.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import fsSync from "node:fs";
|
|
1
2
|
import fs from "node:fs/promises";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { assertAsyncDirectoryGuard, createAsyncDirectoryGuard } from "./directory-guard.js";
|
|
@@ -10,7 +11,7 @@ function isSameOrChildPath(candidate, parent) {
|
|
|
10
11
|
}
|
|
11
12
|
async function realpathOrThrowNotFile(target) {
|
|
12
13
|
try {
|
|
13
|
-
return path.resolve(
|
|
14
|
+
return path.resolve(fsSync.realpathSync.native(target));
|
|
14
15
|
}
|
|
15
16
|
catch (error) {
|
|
16
17
|
if (isNotFoundPathError(error)) {
|
|
@@ -29,7 +30,7 @@ async function realpathOrThrowNotFile(target) {
|
|
|
29
30
|
*/
|
|
30
31
|
export async function mkdirPathComponentsWithGuards(params) {
|
|
31
32
|
const root = path.resolve(params.rootReal);
|
|
32
|
-
const rootCanonical = path.resolve(
|
|
33
|
+
const rootCanonical = path.resolve(fsSync.realpathSync.native(root));
|
|
33
34
|
const target = path.resolve(params.targetPath);
|
|
34
35
|
const relative = path.relative(root, target);
|
|
35
36
|
if (isPathRelativeEscape(relative)) {
|
|
@@ -49,7 +50,7 @@ export async function mkdirPathComponentsWithGuards(params) {
|
|
|
49
50
|
throw error;
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
|
-
const stat =
|
|
53
|
+
const stat = fsSync.lstatSync(next);
|
|
53
54
|
if ((params.rejectSymlinks && stat.isSymbolicLink()) || (!stat.isSymbolicLink() && !stat.isDirectory())) {
|
|
54
55
|
throw directoryComponentNotDirectoryError();
|
|
55
56
|
}
|
|
@@ -69,7 +70,7 @@ export async function mkdirPathComponentsWithGuards(params) {
|
|
|
69
70
|
// every subsequent segment. Callers that need the final directory
|
|
70
71
|
// (e.g. to guard it themselves after this function returns) must use
|
|
71
72
|
// the returned resolved path, not their own lexical parent path.
|
|
72
|
-
const targetStat =
|
|
73
|
+
const targetStat = fsSync.statSync(nextReal);
|
|
73
74
|
if (!targetStat.isDirectory()) {
|
|
74
75
|
throw directoryComponentNotDirectoryError();
|
|
75
76
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type BigIntStats } from "node:fs";
|
|
1
2
|
import { type AnyAsyncDirectoryGuard, type SyncDirectoryGuard } from "./directory-guard.js";
|
|
2
3
|
export declare function withAsyncDirectoryGuards<T>(guards: readonly AnyAsyncDirectoryGuard[], mutate: () => Promise<T>, options?: {
|
|
3
4
|
verifyAfter?: boolean;
|
|
@@ -8,6 +9,8 @@ export declare function withSyncDirectoryGuards<T>(guards: readonly SyncDirector
|
|
|
8
9
|
}): T;
|
|
9
10
|
export declare function guardedRename(params: {
|
|
10
11
|
assertBeforeRename?: () => void;
|
|
12
|
+
onSourceInspected?: (identity: Pick<BigIntStats, "dev" | "ino">) => void;
|
|
13
|
+
onRenamed?: () => void;
|
|
11
14
|
from: string;
|
|
12
15
|
to: string;
|
|
13
16
|
targetRoot?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guarded-mutation.d.ts","sourceRoot":"","sources":["../src/guarded-mutation.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"guarded-mutation.d.ts","sourceRoot":"","sources":["../src/guarded-mutation.ts"],"names":[],"mappings":"AAAA,OAAe,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAGnD,OAAO,EAOL,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACxB,MAAM,sBAAsB,CAAC;AAE9B,wBAAsB,wBAAwB,CAAC,CAAC,EAC9C,MAAM,EAAE,SAAS,sBAAsB,EAAE,EACzC,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACxB,OAAO,GAAE;IACP,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kBAAkB,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACrE,GACL,OAAO,CAAC,CAAC,CAAC,CAyBZ;AAED,wBAAgB,uBAAuB,CAAC,CAAC,EACvC,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,MAAM,EAAE,MAAM,CAAC,EACf,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAO,GACtC,CAAC,CAWH;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE;IAC1C,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,WAAW,EAAE,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,CAAC;IACzE,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBhB;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GAAG,IAAI,CAUP;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GAAG,OAAO,CAAC,IAAI,CAAC,CAYhB;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GAAG,IAAI,CAWP"}
|
package/dist/guarded-mutation.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import fsSync from "node:fs";
|
|
1
|
+
import fsSync, {} from "node:fs";
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { assertAsyncDirectoryGuard, assertSyncDirectoryGuard, createAsyncDirectoryGuard, createNearestExistingDirectoryGuard, createNearestExistingSyncDirectoryGuard, createSyncDirectoryGuard, } from "./directory-guard.js";
|
|
@@ -48,9 +48,13 @@ export async function guardedRename(params) {
|
|
|
48
48
|
? await createNearestExistingDirectoryGuard(params.targetRoot, path.dirname(params.to))
|
|
49
49
|
: await createAsyncDirectoryGuard(path.dirname(params.to));
|
|
50
50
|
await withAsyncDirectoryGuards([sourceGuard, targetGuard], async () => {
|
|
51
|
+
if (params.onSourceInspected) {
|
|
52
|
+
params.onSourceInspected(await fs.lstat(params.from, { bigint: true }));
|
|
53
|
+
}
|
|
51
54
|
// Authority must survive all awaited guards; do not yield before rename dispatch.
|
|
52
55
|
params.assertBeforeRename?.();
|
|
53
56
|
await fs.rename(params.from, params.to);
|
|
57
|
+
params.onRenamed?.();
|
|
54
58
|
}, { verifyAfter: params.verifyAfter });
|
|
55
59
|
}
|
|
56
60
|
export function guardedRenameSync(params) {
|
package/dist/home-dir.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
export declare function resolveEffectiveHomeDir(env?: NodeJS.ProcessEnv, homedir?: () => string): string | undefined;
|
|
2
|
-
export declare function resolveOsHomeDir(env?: NodeJS.ProcessEnv, homedir?: () => string): string | undefined;
|
|
3
2
|
export declare function resolveRequiredHomeDir(env?: NodeJS.ProcessEnv, homedir?: () => string): string;
|
|
4
|
-
export declare function resolveRequiredOsHomeDir(env?: NodeJS.ProcessEnv, homedir?: () => string): string;
|
|
5
3
|
export declare function expandHomePrefix(input: string, opts?: {
|
|
6
4
|
home?: string;
|
|
7
5
|
env?: NodeJS.ProcessEnv;
|
|
@@ -11,12 +9,4 @@ export declare function resolveHomeRelativePath(input: string, opts?: {
|
|
|
11
9
|
env?: NodeJS.ProcessEnv;
|
|
12
10
|
homedir?: () => string;
|
|
13
11
|
}): string;
|
|
14
|
-
export declare function resolveUserPath(input: string, optsOrEnv?: {
|
|
15
|
-
env?: NodeJS.ProcessEnv;
|
|
16
|
-
homedir?: () => string;
|
|
17
|
-
} | NodeJS.ProcessEnv, homedir?: () => string): string;
|
|
18
|
-
export declare function resolveOsHomeRelativePath(input: string, opts?: {
|
|
19
|
-
env?: NodeJS.ProcessEnv;
|
|
20
|
-
homedir?: () => string;
|
|
21
|
-
}): string;
|
|
22
12
|
//# sourceMappingURL=home-dir.d.ts.map
|
package/dist/home-dir.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"home-dir.d.ts","sourceRoot":"","sources":["../src/home-dir.ts"],"names":[],"mappings":"AAeA,wBAAgB,uBAAuB,CACrC,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,OAAO,GAAE,MAAM,MAAmB,GACjC,MAAM,GAAG,SAAS,CAGpB;
|
|
1
|
+
{"version":3,"file":"home-dir.d.ts","sourceRoot":"","sources":["../src/home-dir.ts"],"names":[],"mappings":"AAeA,wBAAgB,uBAAuB,CACrC,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,OAAO,GAAE,MAAM,MAAmB,GACjC,MAAM,GAAG,SAAS,CAGpB;AAyCD,wBAAgB,sBAAsB,CACpC,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,OAAO,GAAE,MAAM,MAAmB,GACjC,MAAM,CAER;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;IACL,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,MAAM,CAAC;CACxB,GACA,MAAM,CAYR;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;IACL,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,MAAM,CAAC;CACxB,GACA,MAAM,CAcR"}
|
package/dist/home-dir.js
CHANGED
|
@@ -15,10 +15,6 @@ export function resolveEffectiveHomeDir(env = process.env, homedir = os.homedir)
|
|
|
15
15
|
const raw = resolveRawHomeDir(env, homedir);
|
|
16
16
|
return raw ? path.resolve(raw) : undefined;
|
|
17
17
|
}
|
|
18
|
-
export function resolveOsHomeDir(env = process.env, homedir = os.homedir) {
|
|
19
|
-
const raw = resolveRawOsHomeDir(env, homedir);
|
|
20
|
-
return raw ? path.resolve(raw) : undefined;
|
|
21
|
-
}
|
|
22
18
|
function resolveRawHomeDir(env, homedir) {
|
|
23
19
|
const explicitHome = normalize(env.OPENCLAW_HOME);
|
|
24
20
|
if (!explicitHome) {
|
|
@@ -59,9 +55,6 @@ function normalizeSafe(homedir) {
|
|
|
59
55
|
export function resolveRequiredHomeDir(env = process.env, homedir = os.homedir) {
|
|
60
56
|
return resolveEffectiveHomeDir(env, homedir) ?? path.resolve(process.cwd());
|
|
61
57
|
}
|
|
62
|
-
export function resolveRequiredOsHomeDir(env = process.env, homedir = os.homedir) {
|
|
63
|
-
return resolveOsHomeDir(env, homedir) ?? path.resolve(process.cwd());
|
|
64
|
-
}
|
|
65
58
|
export function expandHomePrefix(input, opts) {
|
|
66
59
|
const segments = path.normalize(input).split(path.sep);
|
|
67
60
|
if (segments[0] !== "~") {
|
|
@@ -89,24 +82,3 @@ export function resolveHomeRelativePath(input, opts) {
|
|
|
89
82
|
});
|
|
90
83
|
return path.resolve(expanded);
|
|
91
84
|
}
|
|
92
|
-
export function resolveUserPath(input, optsOrEnv, homedir) {
|
|
93
|
-
const opts = optsOrEnv && ("env" in optsOrEnv || "homedir" in optsOrEnv)
|
|
94
|
-
? optsOrEnv
|
|
95
|
-
: { env: optsOrEnv, homedir };
|
|
96
|
-
return resolveHomeRelativePath(input, opts);
|
|
97
|
-
}
|
|
98
|
-
export function resolveOsHomeRelativePath(input, opts) {
|
|
99
|
-
if (!input) {
|
|
100
|
-
return input;
|
|
101
|
-
}
|
|
102
|
-
const segments = path.normalize(input).split(path.sep);
|
|
103
|
-
if (segments[0] !== "~") {
|
|
104
|
-
return path.resolve(input);
|
|
105
|
-
}
|
|
106
|
-
const expanded = expandHomePrefix(input, {
|
|
107
|
-
home: resolveRequiredOsHomeDir(opts?.env ?? process.env, opts?.homedir ?? os.homedir),
|
|
108
|
-
env: opts?.env,
|
|
109
|
-
homedir: opts?.homedir,
|
|
110
|
-
});
|
|
111
|
-
return path.resolve(expanded);
|
|
112
|
-
}
|
|
@@ -13,4 +13,5 @@ export declare function moveDurableQueueEntryToFailed(params: {
|
|
|
13
13
|
paths: DurableQueueEntryPathsLike;
|
|
14
14
|
failedPath: string;
|
|
15
15
|
}): Promise<void>;
|
|
16
|
+
export declare function getErrorCode(error: unknown): string | null;
|
|
16
17
|
//# sourceMappingURL=json-durable-queue-ownership.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-durable-queue-ownership.d.ts","sourceRoot":"","sources":["../src/json-durable-queue-ownership.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"json-durable-queue-ownership.d.ts","sourceRoot":"","sources":["../src/json-durable-queue-ownership.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,0BAA0B,GAAG,MAAM,CAKpF;AA+DD,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,0BAA0B,EACjC,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAO,GACtC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGxB;AAED,wBAAsB,2BAA2B,CAC/C,KAAK,EAAE,0BAA0B,GAChC,OAAO,CAAC,OAAO,CAAC,CAalB;AAED,wBAAsB,4BAA4B,CAChD,KAAK,EAAE,0BAA0B,GAChC,OAAO,CAAC,IAAI,CAAC,CAyBf;AAED,wBAAsB,6BAA6B,CAAC,MAAM,EAAE;IAC1D,KAAK,EAAE,0BAA0B,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiDhB;AAKD,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAI1D"}
|
|
@@ -1,16 +1,11 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { withSidecarLock } from "./sidecar-lock.js";
|
|
1
3
|
import fs from "node:fs/promises";
|
|
2
4
|
import path from "node:path";
|
|
3
5
|
import { syncDirectory } from "./directory-durability.js";
|
|
4
6
|
import { FsSafeError } from "./errors.js";
|
|
5
|
-
import { sameFileIdentityForCleanup } from "./file-identity.js";
|
|
6
|
-
import { recoverDurableQueueRetirement, retireDurableQueueSource, } from "./json-durable-queue-retirement.js";
|
|
7
|
-
import { withQueueTransferLock } from "./json-durable-queue-transfer-lock.js";
|
|
7
|
+
import { sameFileIdentityForCleanup, sha256Hex } from "./file-identity.js";
|
|
8
8
|
import { serializePathWrite } from "./write-queue.js";
|
|
9
|
-
function getErrorCode(error) {
|
|
10
|
-
return error && typeof error === "object" && "code" in error
|
|
11
|
-
? String(error.code)
|
|
12
|
-
: null;
|
|
13
|
-
}
|
|
14
9
|
export function durableQueueProcessingPath(paths) {
|
|
15
10
|
if (paths.processingPath)
|
|
16
11
|
return paths.processingPath;
|
|
@@ -18,16 +13,6 @@ export function durableQueueProcessingPath(paths) {
|
|
|
18
13
|
? `${paths.jsonPath.slice(0, -".json".length)}.processing`
|
|
19
14
|
: `${paths.jsonPath}.processing`;
|
|
20
15
|
}
|
|
21
|
-
async function lstatOrNull(filePath) {
|
|
22
|
-
try {
|
|
23
|
-
return await fs.lstat(filePath, { bigint: true });
|
|
24
|
-
}
|
|
25
|
-
catch (error) {
|
|
26
|
-
if (getErrorCode(error) === "ENOENT")
|
|
27
|
-
return null;
|
|
28
|
-
throw error;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
16
|
async function regularQueueFileIdentity(filePath) {
|
|
32
17
|
const identity = await lstatOrNull(filePath);
|
|
33
18
|
if (!identity)
|
|
@@ -169,3 +154,139 @@ export async function moveDurableQueueEntryToFailed(params) {
|
|
|
169
154
|
await syncDirectory(path.dirname(sourcePath));
|
|
170
155
|
});
|
|
171
156
|
}
|
|
157
|
+
const RETIREMENT_ROOT_NAME = ".fs-safe-retirements";
|
|
158
|
+
const RETIREMENT_ENTRY_NAME = "entry";
|
|
159
|
+
export function getErrorCode(error) {
|
|
160
|
+
return error && typeof error === "object" && "code" in error
|
|
161
|
+
? String(error.code)
|
|
162
|
+
: null;
|
|
163
|
+
}
|
|
164
|
+
async function lstatOrNull(filePath) {
|
|
165
|
+
try {
|
|
166
|
+
return await fs.lstat(filePath, { bigint: true });
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
if (getErrorCode(error) === "ENOENT")
|
|
170
|
+
return null;
|
|
171
|
+
throw error;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function assertDirectory(identity, label) {
|
|
175
|
+
if (identity.isSymbolicLink() || !identity.isDirectory()) {
|
|
176
|
+
throw new FsSafeError("path-mismatch", `${label} is not an owned directory`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
async function regularFileIdentity(filePath) {
|
|
180
|
+
const identity = await lstatOrNull(filePath);
|
|
181
|
+
if (!identity)
|
|
182
|
+
return null;
|
|
183
|
+
if (identity.isSymbolicLink() || !identity.isFile()) {
|
|
184
|
+
throw new FsSafeError("path-mismatch", "queue retirement path is not a regular file");
|
|
185
|
+
}
|
|
186
|
+
return identity;
|
|
187
|
+
}
|
|
188
|
+
function retirementPaths(jsonPath) {
|
|
189
|
+
const rootPath = path.join(path.dirname(jsonPath), RETIREMENT_ROOT_NAME);
|
|
190
|
+
const dirPath = path.join(rootPath, path.basename(jsonPath));
|
|
191
|
+
return { dirPath, entryPath: path.join(dirPath, RETIREMENT_ENTRY_NAME), rootPath };
|
|
192
|
+
}
|
|
193
|
+
async function inspectRetirementRoot(jsonPath) {
|
|
194
|
+
const rootPath = retirementPaths(jsonPath).rootPath;
|
|
195
|
+
const root = await lstatOrNull(rootPath);
|
|
196
|
+
if (!root)
|
|
197
|
+
return null;
|
|
198
|
+
assertDirectory(root, "queue retirement root");
|
|
199
|
+
return rootPath;
|
|
200
|
+
}
|
|
201
|
+
async function ensureRetirementRoot(jsonPath) {
|
|
202
|
+
const parentPath = path.dirname(jsonPath);
|
|
203
|
+
const rootPath = retirementPaths(jsonPath).rootPath;
|
|
204
|
+
await fs.mkdir(rootPath, { mode: 0o700 }).catch((error) => {
|
|
205
|
+
if (getErrorCode(error) !== "EEXIST")
|
|
206
|
+
throw error;
|
|
207
|
+
});
|
|
208
|
+
const root = await fs.lstat(rootPath, { bigint: true });
|
|
209
|
+
assertDirectory(root, "queue retirement root");
|
|
210
|
+
await syncDirectory(parentPath);
|
|
211
|
+
return rootPath;
|
|
212
|
+
}
|
|
213
|
+
async function removeRetirementRecord(params) {
|
|
214
|
+
await fs.rmdir(params.dirPath).catch((error) => {
|
|
215
|
+
if (getErrorCode(error) !== "ENOENT")
|
|
216
|
+
throw error;
|
|
217
|
+
});
|
|
218
|
+
await syncDirectory(params.rootPath);
|
|
219
|
+
}
|
|
220
|
+
async function recoverDurableQueueRetirement(params) {
|
|
221
|
+
const rootPath = await inspectRetirementRoot(params.jsonPath);
|
|
222
|
+
if (!rootPath)
|
|
223
|
+
return;
|
|
224
|
+
const { dirPath, entryPath } = retirementPaths(params.jsonPath);
|
|
225
|
+
const dir = await lstatOrNull(dirPath);
|
|
226
|
+
if (!dir)
|
|
227
|
+
return;
|
|
228
|
+
assertDirectory(dir, "queue retirement record");
|
|
229
|
+
const names = await fs.readdir(dirPath);
|
|
230
|
+
if (names.length === 0) {
|
|
231
|
+
await removeRetirementRecord({ dirPath, rootPath });
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
if (names.length !== 1 || names[0] !== RETIREMENT_ENTRY_NAME) {
|
|
235
|
+
throw new FsSafeError("path-mismatch", "queue retirement record is ambiguous");
|
|
236
|
+
}
|
|
237
|
+
const entry = await regularFileIdentity(entryPath);
|
|
238
|
+
const processing = await regularFileIdentity(params.processingPath);
|
|
239
|
+
if (!entry || !processing) {
|
|
240
|
+
throw new FsSafeError("path-mismatch", "queue retirement ownership is incomplete");
|
|
241
|
+
}
|
|
242
|
+
if (!sameFileIdentityForCleanup(entry, processing)) {
|
|
243
|
+
const pending = await regularFileIdentity(params.jsonPath);
|
|
244
|
+
if (!pending) {
|
|
245
|
+
await fs.link(entryPath, params.jsonPath);
|
|
246
|
+
await syncDirectory(path.dirname(params.jsonPath));
|
|
247
|
+
}
|
|
248
|
+
else if (sameFileIdentityForCleanup(pending, entry)) {
|
|
249
|
+
await syncDirectory(path.dirname(params.jsonPath));
|
|
250
|
+
}
|
|
251
|
+
else if (pending.nlink > 1n) {
|
|
252
|
+
throw new FsSafeError("path-mismatch", "queue replacement identity is ambiguous");
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
await fs.unlink(entryPath);
|
|
256
|
+
await syncDirectory(dirPath);
|
|
257
|
+
await removeRetirementRecord({ dirPath, rootPath });
|
|
258
|
+
}
|
|
259
|
+
async function retireDurableQueueSource(params) {
|
|
260
|
+
await recoverDurableQueueRetirement(params);
|
|
261
|
+
const rootPath = await ensureRetirementRoot(params.jsonPath);
|
|
262
|
+
const { dirPath, entryPath } = retirementPaths(params.jsonPath);
|
|
263
|
+
await fs.mkdir(dirPath, { mode: 0o700 });
|
|
264
|
+
await syncDirectory(rootPath);
|
|
265
|
+
try {
|
|
266
|
+
await fs.rename(params.jsonPath, entryPath);
|
|
267
|
+
}
|
|
268
|
+
catch (error) {
|
|
269
|
+
if (getErrorCode(error) !== "ENOENT")
|
|
270
|
+
throw error;
|
|
271
|
+
await removeRetirementRecord({ dirPath, rootPath });
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
await syncDirectory(dirPath);
|
|
275
|
+
await syncDirectory(path.dirname(params.jsonPath));
|
|
276
|
+
await recoverDurableQueueRetirement(params);
|
|
277
|
+
}
|
|
278
|
+
async function withQueueTransferLock(filePath, run) {
|
|
279
|
+
const lockPath = path.join(path.dirname(filePath), `.fs-safe-transfer-${sha256Hex(path.basename(filePath)).slice(0, 32)}.lock`);
|
|
280
|
+
return await withSidecarLock(filePath, {
|
|
281
|
+
managerKey: "fs-safe.queue-transfer",
|
|
282
|
+
lockPath,
|
|
283
|
+
staleMs: 30_000,
|
|
284
|
+
staleRecovery: "fail-closed",
|
|
285
|
+
timeoutMs: 45_000,
|
|
286
|
+
payload: () => ({
|
|
287
|
+
ownerToken: randomUUID(),
|
|
288
|
+
createdAt: new Date().toISOString(),
|
|
289
|
+
}),
|
|
290
|
+
retry: { retries: 180, minTimeout: 25, maxTimeout: 250, factor: 1.1 },
|
|
291
|
+
}, run);
|
|
292
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-durable-queue.d.ts","sourceRoot":"","sources":["../src/json-durable-queue.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"json-durable-queue.d.ts","sourceRoot":"","sources":["../src/json-durable-queue.ts"],"names":[],"mappings":"AAmBA,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,0BAA0B,CAAC,CAAC,IAAI;IAC1C,KAAK,EAAE,CAAC,CAAC;IACT,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,2BAA2B,CAAC,CAAC,IAAI;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAOF,eAAO,MAAM,0CAA0C,QAAmB,CAAC;AAM3E,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtE;AAED,wBAAsB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAUpF;AAmBD,wBAAgB,iCAAiC,CAC/C,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,GACT,0BAA0B,CAO5B;AAED,wBAAsB,0BAA0B,CAAC,MAAM,EAAE;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,IAAI,CAAC,CAIhB;AAgLD,wBAAsB,0BAA0B,CAAC,MAAM,EAAE;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CAQhB;AA6DD,wBAAsB,yBAAyB,CAAC,CAAC,EAC/C,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAClC,OAAO,CAAC,CAAC,CAAC,CASZ;AAED,wBAAsB,wBAAwB,CAAC,KAAK,EAAE,0BAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/F;AAED,wBAAsB,yBAAyB,CAAC,CAAC,EAAE,MAAM,EAAE;IACzD,KAAK,EAAE,0BAA0B,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAsBpB;AAED,wBAAsB,kCAAkC,CAAC,CAAC,EACxD,OAAO,EAAE,2BAA2B,CAAC,CAAC,CAAC,GACtC,OAAO,CAAC,CAAC,EAAE,CAAC,CA8Dd;AAED,wBAAsB,iCAAiC,CAAC,MAAM,EAAE;IAC9D,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;CACZ,GAAG,OAAO,CAAC,IAAI,CAAC,CAShB"}
|
|
@@ -3,18 +3,13 @@ import path from "node:path";
|
|
|
3
3
|
import { normalizeMaxBytes } from "./byte-budget.js";
|
|
4
4
|
import { syncDirectory } from "./directory-durability.js";
|
|
5
5
|
import { syncQueueDirectoryCreation } from "./json-durable-queue-directory.js";
|
|
6
|
-
import { acknowledgeDurableQueueEntry, claimDurableQueueEntry, completeDeliveredQueueEntry, moveDurableQueueEntryToFailed, } from "./json-durable-queue-ownership.js";
|
|
6
|
+
import { getErrorCode, acknowledgeDurableQueueEntry, claimDurableQueueEntry, completeDeliveredQueueEntry, moveDurableQueueEntryToFailed, } from "./json-durable-queue-ownership.js";
|
|
7
7
|
import { stringifyJsonDocument } from "./json-stringify.js";
|
|
8
8
|
import { resolveReadOpenFlags } from "./read-open-flags.js";
|
|
9
9
|
import { replaceFileAtomicWithDirectorySync } from "./replace-file.js";
|
|
10
10
|
import { assertSafePathSegment } from "./safe-path-segment.js";
|
|
11
11
|
import { inspectFileIdentity } from "./strict-file-identity.js";
|
|
12
12
|
export const DEFAULT_JSON_DURABLE_QUEUE_ENTRY_MAX_BYTES = 16 * 1024 * 1024;
|
|
13
|
-
function getErrnoCode(error) {
|
|
14
|
-
return error && typeof error === "object" && "code" in error
|
|
15
|
-
? String(error.code)
|
|
16
|
-
: null;
|
|
17
|
-
}
|
|
18
13
|
function assertSafeQueueEntryId(id) {
|
|
19
14
|
assertSafePathSegment(id, { label: "queue entry id" });
|
|
20
15
|
}
|
|
@@ -27,7 +22,7 @@ export async function jsonDurableQueueEntryExists(filePath) {
|
|
|
27
22
|
return stat.isFile();
|
|
28
23
|
}
|
|
29
24
|
catch (error) {
|
|
30
|
-
if (
|
|
25
|
+
if (getErrorCode(error) === "ENOENT") {
|
|
31
26
|
return false;
|
|
32
27
|
}
|
|
33
28
|
throw error;
|
|
@@ -41,7 +36,7 @@ async function unlinkStaleTmpBestEffort(filePath, now, maxAgeMs) {
|
|
|
41
36
|
}
|
|
42
37
|
}
|
|
43
38
|
catch (error) {
|
|
44
|
-
if (
|
|
39
|
+
if (getErrorCode(error) !== "ENOENT") {
|
|
45
40
|
throw error;
|
|
46
41
|
}
|
|
47
42
|
}
|
|
@@ -302,7 +297,7 @@ export async function loadJsonDurableQueueEntry(params) {
|
|
|
302
297
|
return result.entry;
|
|
303
298
|
}
|
|
304
299
|
catch (error) {
|
|
305
|
-
if (
|
|
300
|
+
if (getErrorCode(error) === "ENOENT") {
|
|
306
301
|
return null;
|
|
307
302
|
}
|
|
308
303
|
throw error;
|
|
@@ -314,7 +309,7 @@ export async function loadPendingJsonDurableQueueEntries(options) {
|
|
|
314
309
|
files = await fs.promises.readdir(options.queueDir);
|
|
315
310
|
}
|
|
316
311
|
catch (error) {
|
|
317
|
-
if (
|
|
312
|
+
if (getErrorCode(error) === "ENOENT") {
|
|
318
313
|
return [];
|
|
319
314
|
}
|
|
320
315
|
throw error;
|
package/dist/json-store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-store.d.ts","sourceRoot":"","sources":["../src/json-store.ts"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"json-store.d.ts","sourceRoot":"","sources":["../src/json-store.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,SAAS,EACd,KAAK,oBAAoB,EAC1B,MAAM,0BAA0B,CAAC;AAElC,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI,oBAAoB,GAAG;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,YAAY,EAAE,oBAAoB,EAAE,SAAS,EAAE,oBAAoB,EAAE,CAAC;AAEtE,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAQvE"}
|
package/dist/json-store.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { fileStore } from "./file-store.js";
|
|
3
|
-
import {
|
|
3
|
+
import {} from "./json-document-store.js";
|
|
4
4
|
export function jsonStore(options) {
|
|
5
5
|
const filePath = path.resolve(options.filePath);
|
|
6
6
|
return fileStore({
|
|
@@ -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;AAgDF,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,oCAAoC,GAC5C,oBAAoB,GAAG,IAAI,CAuC7B;AAED,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,oBAAoB,GAAG,IAAI,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;AAgDF,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,oCAAoC,GAC5C,oBAAoB,GAAG,IAAI,CAuC7B;AAED,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CA2CtC"}
|
package/dist/local-roots.js
CHANGED
|
@@ -2,7 +2,7 @@ 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, resolveHomeRelativePath } from "./home-dir.js";
|
|
6
6
|
import { isFileUrl, safeFileURLToPath } from "./local-file-access.js";
|
|
7
7
|
import { isPathInside } from "./path.js";
|
|
8
8
|
import { resolveRootPathSync } from "./root-path.js";
|
|
@@ -20,7 +20,7 @@ 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
|
-
return
|
|
23
|
+
return resolveHomeRelativePath(input);
|
|
24
24
|
}
|
|
25
25
|
function resolveLocalRootInput(input, label) {
|
|
26
26
|
const trimmed = input.trim();
|
|
@@ -106,7 +106,6 @@ export async function readLocalFileFromRoots(options) {
|
|
|
106
106
|
}
|
|
107
107
|
const readOptions = {
|
|
108
108
|
hardlinks: options.hardlinks,
|
|
109
|
-
nonBlockingRead: options.nonBlockingRead,
|
|
110
109
|
symlinks: options.symlinks,
|
|
111
110
|
};
|
|
112
111
|
// Leave maxBytes absent when the caller omits it so Root's own default
|
|
@@ -38,6 +38,6 @@ export declare function sameIdentity(a: EntryIdentity, b: EntryIdentity): boolea
|
|
|
38
38
|
export declare function sourceChangedError(sourcePath: string): Error;
|
|
39
39
|
export declare function assertSourceStillMatches(sourcePath: string, identity: EntryIdentity): Promise<void>;
|
|
40
40
|
export declare function createCleanupCopiedEntryState(sourcePath: string, manifest: CopiedEntryManifest): CleanupCopiedEntryState;
|
|
41
|
-
export declare function cleanupCopiedEntry(sourcePath: string, manifest: CopiedEntryManifest, state: CleanupCopiedEntryState): Promise<CleanupCopiedEntryResult>;
|
|
41
|
+
export declare function cleanupCopiedEntry(sourcePath: string, manifest: CopiedEntryManifest, state: CleanupCopiedEntryState, assertBeforeMutation: () => void): Promise<CleanupCopiedEntryResult>;
|
|
42
42
|
export {};
|
|
43
43
|
//# sourceMappingURL=move-path-cleanup.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"move-path-cleanup.d.ts","sourceRoot":"","sources":["../src/move-path-cleanup.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAC3B,CAAC,aAAa,GAAG;IACf,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,mBAAmB,CAAA;KAAE,CAAC,CAAC;IACjE,IAAI,EAAE,WAAW,CAAC;CACnB,CAAC,GACF,CAAC,aAAa,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEvC,KAAK,wBAAwB,GAAG,SAAS,GAAG,OAAO,CAAC;AAEpD,KAAK,iBAAiB,GAAG;IACvB,QAAQ,EAAE,aAAa,CAAC;IACxB,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5B,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;CAC7C,CAAC;AAEF,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,aAAa,CAUhB;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,aAAa,GAAG,OAAO,CAUxE;AAMD,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,KAAK,CAI5D;AAED,wBAAsB,wBAAwB,CAC5C,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,IAAI,CAAC,CAIf;AA0BD,wBAAgB,6BAA6B,CAC3C,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,mBAAmB,GAC5B,uBAAuB,CAuBzB;AAsDD,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,mBAAmB,EAC7B,KAAK,EAAE,uBAAuB,
|
|
1
|
+
{"version":3,"file":"move-path-cleanup.d.ts","sourceRoot":"","sources":["../src/move-path-cleanup.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAC3B,CAAC,aAAa,GAAG;IACf,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,mBAAmB,CAAA;KAAE,CAAC,CAAC;IACjE,IAAI,EAAE,WAAW,CAAC;CACnB,CAAC,GACF,CAAC,aAAa,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEvC,KAAK,wBAAwB,GAAG,SAAS,GAAG,OAAO,CAAC;AAEpD,KAAK,iBAAiB,GAAG;IACvB,QAAQ,EAAE,aAAa,CAAC;IACxB,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5B,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;CAC7C,CAAC;AAEF,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,aAAa,CAUhB;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,aAAa,GAAG,OAAO,CAUxE;AAMD,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,KAAK,CAI5D;AAED,wBAAsB,wBAAwB,CAC5C,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,IAAI,CAAC,CAIf;AA0BD,wBAAgB,6BAA6B,CAC3C,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,mBAAmB,GAC5B,uBAAuB,CAuBzB;AAsDD,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,mBAAmB,EAC7B,KAAK,EAAE,uBAAuB,EAC9B,oBAAoB,EAAE,MAAM,IAAI,GAC/B,OAAO,CAAC,wBAAwB,CAAC,CAyDnC"}
|