@openclaw/fs-safe 0.8.6 → 0.10.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 +93 -0
- package/README.md +17 -0
- package/dist/advanced.d.ts +1 -0
- package/dist/advanced.d.ts.map +1 -1
- package/dist/advanced.js +1 -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 +24 -0
- package/dist/archive-durability.d.ts.map +1 -0
- package/dist/archive-durability.js +180 -0
- package/dist/archive-gzip-tail.d.ts +2 -0
- package/dist/archive-gzip-tail.d.ts.map +1 -1
- package/dist/archive-gzip-tail.js +22 -4
- package/dist/archive-input.js +4 -4
- package/dist/archive-kind.d.ts.map +1 -1
- package/dist/archive-kind.js +3 -2
- package/dist/archive-merge.d.ts +1 -0
- package/dist/archive-merge.d.ts.map +1 -1
- package/dist/archive-merge.js +42 -9
- package/dist/archive-native.d.ts +1 -0
- package/dist/archive-native.d.ts.map +1 -1
- package/dist/archive-native.js +4 -2
- package/dist/archive-options.d.ts +2 -0
- package/dist/archive-options.d.ts.map +1 -1
- package/dist/archive-parser.wasm +0 -0
- package/dist/archive-read.d.ts.map +1 -1
- package/dist/archive-read.js +72 -70
- package/dist/archive-staging.d.ts +1 -1
- package/dist/archive-staging.d.ts.map +1 -1
- package/dist/archive-staging.js +24 -19
- 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 +20 -8
- package/dist/archive-tar-wasm.d.ts.map +1 -1
- package/dist/archive-tar-wasm.js +2 -1
- package/dist/archive.d.ts.map +1 -1
- package/dist/archive.js +9 -4
- package/dist/bounded-read.d.ts +7 -0
- package/dist/bounded-read.d.ts.map +1 -1
- package/dist/bounded-read.js +73 -43
- 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 +23 -0
- package/dist/copy-file-input.d.ts.map +1 -0
- package/dist/copy-file-input.js +91 -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 +15 -0
- package/dist/copy-publication.d.ts.map +1 -0
- package/dist/copy-publication.js +30 -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 +191 -0
- package/dist/copy.d.ts +16 -0
- package/dist/copy.d.ts.map +1 -0
- package/dist/copy.js +123 -0
- package/dist/directory-mode-node.d.ts.map +1 -1
- package/dist/directory-mode-node.js +4 -4
- package/dist/durability.d.ts +1 -1
- package/dist/durability.d.ts.map +1 -1
- package/dist/error-detail.d.ts.map +1 -1
- package/dist/error-detail.js +4 -1
- package/dist/file-hash.d.ts +6 -2
- package/dist/file-hash.d.ts.map +1 -1
- package/dist/file-hash.js +49 -12
- package/dist/file-store-sync-write.d.ts +1 -0
- package/dist/file-store-sync-write.d.ts.map +1 -1
- package/dist/file-store-sync-write.js +9 -6
- package/dist/file-store.d.ts +4 -0
- package/dist/file-store.d.ts.map +1 -1
- package/dist/file-store.js +10 -1
- package/dist/filename.d.ts.map +1 -1
- package/dist/filename.js +2 -12
- package/dist/fs.d.ts.map +1 -1
- package/dist/fs.js +1 -2
- package/dist/guarded-mkdir.d.ts +1 -0
- package/dist/guarded-mkdir.d.ts.map +1 -1
- package/dist/guarded-mkdir.js +1 -0
- package/dist/guarded-mutation.d.ts +2 -0
- package/dist/guarded-mutation.d.ts.map +1 -1
- package/dist/guarded-mutation.js +9 -5
- 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 +9 -13
- package/dist/json-document-store.d.ts +3 -0
- package/dist/json-document-store.d.ts.map +1 -1
- package/dist/json-document-store.js +1 -0
- package/dist/json-durable-queue-directory.js +3 -3
- package/dist/json-durable-queue-ownership.js +3 -2
- package/dist/json-durable-queue.d.ts.map +1 -1
- package/dist/json-durable-queue.js +31 -27
- package/dist/local-roots.d.ts.map +1 -1
- package/dist/local-roots.js +22 -24
- package/dist/move-path-cleanup.d.ts.map +1 -1
- package/dist/move-path-cleanup.js +4 -3
- 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 +55 -0
- package/dist/move-path.d.ts.map +1 -1
- package/dist/move-path.js +55 -47
- package/dist/mutation-authority.d.ts +8 -0
- package/dist/mutation-authority.d.ts.map +1 -0
- package/dist/mutation-authority.js +36 -0
- package/dist/native-binding.d.ts +24 -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 +18 -7
- package/dist/native-pinned-write.d.ts.map +1 -1
- package/dist/native-pinned-write.js +1 -0
- 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-file-failure.d.ts +1 -1
- package/dist/opened-file-failure.d.ts.map +1 -1
- package/dist/opened-file-failure.js +3 -2
- package/dist/path.d.ts.map +1 -1
- package/dist/path.js +3 -1
- package/dist/permissions-windows.d.ts.map +1 -1
- package/dist/permissions-windows.js +38 -48
- package/dist/permissions.js +3 -3
- package/dist/pinned-operation.js +1 -1
- package/dist/pinned-write.d.ts +5 -1
- package/dist/pinned-write.d.ts.map +1 -1
- package/dist/pinned-write.js +50 -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 +9 -3
- 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 +26 -25
- package/dist/replace-file-copy-fallback.d.ts.map +1 -1
- package/dist/replace-file-copy-fallback.js +30 -17
- package/dist/replace-file-copy-source.d.ts.map +1 -1
- package/dist/replace-file-copy-source.js +10 -5
- 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.map +1 -1
- package/dist/replace-file.js +8 -3
- package/dist/root-context.d.ts +3 -0
- package/dist/root-context.d.ts.map +1 -1
- package/dist/root-context.js +51 -26
- package/dist/root-directory-list.d.ts +24 -0
- package/dist/root-directory-list.d.ts.map +1 -0
- package/dist/root-directory-list.js +201 -0
- package/dist/root-errors.d.ts +1 -0
- package/dist/root-errors.d.ts.map +1 -1
- package/dist/root-errors.js +3 -0
- 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 +6 -50
- package/dist/root-impl.d.ts.map +1 -1
- package/dist/root-impl.js +342 -208
- package/dist/root-options.d.ts +66 -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 +56 -1
- 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-symlink-policy.d.ts +13 -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 +1 -4
- package/dist/root.d.ts +3 -1
- package/dist/root.d.ts.map +1 -1
- package/dist/secret-file.d.ts +1 -0
- package/dist/secret-file.d.ts.map +1 -1
- package/dist/secret-file.js +1 -0
- package/dist/secret-read-async.js +5 -5
- package/dist/secure-file.d.ts +1 -1
- package/dist/secure-file.d.ts.map +1 -1
- package/dist/secure-file.js +23 -13
- package/dist/sibling-staged-file.js +7 -7
- package/dist/sibling-temp.d.ts.map +1 -1
- package/dist/sibling-temp.js +16 -7
- package/dist/sidecar-lock-acquire.d.ts +1 -1
- package/dist/sidecar-lock-acquire.d.ts.map +1 -1
- package/dist/sidecar-lock-acquire.js +6 -4
- package/dist/sidecar-lock-policy.d.ts.map +1 -1
- package/dist/sidecar-lock-policy.js +5 -3
- package/dist/sidecar-lock-reclaim.d.ts.map +1 -1
- package/dist/sidecar-lock-reclaim.js +16 -4
- package/dist/sidecar-lock.d.ts.map +1 -1
- package/dist/sidecar-lock.js +2 -1
- package/dist/temp-cleanup.d.ts.map +1 -1
- package/dist/temp-cleanup.js +3 -2
- package/dist/temp-target.d.ts.map +1 -1
- package/dist/temp-target.js +9 -4
- package/dist/timing.d.ts +1 -0
- package/dist/timing.d.ts.map +1 -1
- package/dist/timing.js +25 -6
- package/dist/trash.js +2 -2
- package/dist/walk.d.ts.map +1 -1
- package/dist/walk.js +7 -27
- 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 +6 -0
- package/dist/write-file-handle.d.ts.map +1 -0
- package/dist/write-file-handle.js +25 -0
- package/dist/write-open-flags.d.ts.map +1 -1
- package/dist/write-open-flags.js +1 -2
- package/docs/advanced.md +18 -4
- package/docs/archive.md +57 -9
- package/docs/atomic.md +7 -0
- package/docs/contributing.md +7 -0
- package/docs/copy.md +86 -0
- package/docs/durability.md +17 -2
- package/docs/errors.md +1 -1
- package/docs/file-store.md +48 -3
- package/docs/json-store.md +10 -0
- package/docs/local-roots.md +8 -1
- package/docs/native.md +14 -1
- package/docs/permissions.md +20 -10
- package/docs/positional-read.md +63 -0
- package/docs/reading.md +6 -0
- package/docs/root.md +168 -6
- package/docs/secret-file.md +6 -0
- package/docs/security-model.md +14 -0
- package/docs/sidecar-lock.md +2 -0
- package/docs/timing.md +2 -0
- package/docs/types.md +18 -11
- package/docs/walk.md +54 -5
- package/docs/writing.md +25 -5
- package/package.json +16 -11
package/dist/root-walk.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { FsSafeError } from "./errors.js";
|
|
3
3
|
import { resolveRootPath } from "./root-path.js";
|
|
4
|
+
import { createSuppressedError } from "./suppressed-error.js";
|
|
4
5
|
function validateBudget(name, value) {
|
|
5
6
|
if (value === undefined)
|
|
6
7
|
return Number.POSITIVE_INFINITY;
|
|
@@ -25,6 +26,9 @@ export async function* walkRoot(root, relativePath, options) {
|
|
|
25
26
|
if (!["skip", "follow-within-root"].includes(options.symlinkPolicy)) {
|
|
26
27
|
throw new TypeError(`invalid root walk symlink policy: ${String(options.symlinkPolicy)}`);
|
|
27
28
|
}
|
|
29
|
+
if (options.order !== undefined && !["sorted", "filesystem"].includes(options.order)) {
|
|
30
|
+
throw new TypeError(`invalid root walk order: ${String(options.order)}`);
|
|
31
|
+
}
|
|
28
32
|
if (options.limitBehavior !== undefined &&
|
|
29
33
|
!["truncate", "throw"].includes(options.limitBehavior)) {
|
|
30
34
|
throw new TypeError(`invalid root walk limit behavior: ${String(options.limitBehavior)}`);
|
|
@@ -38,6 +42,12 @@ export async function* walkRoot(root, relativePath, options) {
|
|
|
38
42
|
const visitedDirectories = new Set();
|
|
39
43
|
let examined = 0;
|
|
40
44
|
let truncated = false;
|
|
45
|
+
const admitEntry = () => {
|
|
46
|
+
if (examined >= maxEntries)
|
|
47
|
+
return false;
|
|
48
|
+
examined += 1;
|
|
49
|
+
return true;
|
|
50
|
+
};
|
|
41
51
|
const onLimit = (atPath) => {
|
|
42
52
|
if ((options.limitBehavior ?? "truncate") === "throw") {
|
|
43
53
|
throw new FsSafeError("too-large", `root walk budget exceeded at ${atPath || "."}`);
|
|
@@ -45,9 +55,15 @@ export async function* walkRoot(root, relativePath, options) {
|
|
|
45
55
|
truncated = true;
|
|
46
56
|
return limitEntry(atPath);
|
|
47
57
|
};
|
|
58
|
+
const onDirectoryError = (directory, error) => {
|
|
59
|
+
// Rethrow cancellation with any disposal failure already attached.
|
|
60
|
+
if (options.signal?.aborted || (options.onDirectoryError ?? "throw") === "throw")
|
|
61
|
+
throw error;
|
|
62
|
+
return { relativePath: directory, kind: "directory-error", size: 0, error };
|
|
63
|
+
};
|
|
48
64
|
async function* visit(directory, depth) {
|
|
49
65
|
options.signal?.throwIfAborted();
|
|
50
|
-
let
|
|
66
|
+
let listing;
|
|
51
67
|
try {
|
|
52
68
|
const resolvedDirectory = await resolveRootPath({
|
|
53
69
|
absolutePath: path.resolve(root.rootReal, directory),
|
|
@@ -67,66 +83,99 @@ export async function* walkRoot(root, relativePath, options) {
|
|
|
67
83
|
.relative(root.rootReal, resolvedDirectory.canonicalPath)
|
|
68
84
|
.split(path.sep)
|
|
69
85
|
.join(path.posix.sep);
|
|
70
|
-
|
|
86
|
+
listing = await root.list(listingDirectory, {
|
|
87
|
+
order: options.order ?? "sorted",
|
|
88
|
+
signal: options.signal,
|
|
89
|
+
snapshot: maxEntries === Number.POSITIVE_INFINITY,
|
|
90
|
+
admitEntry,
|
|
91
|
+
});
|
|
71
92
|
}
|
|
72
93
|
catch (error) {
|
|
73
|
-
|
|
74
|
-
options.signal?.throwIfAborted();
|
|
75
|
-
if ((options.onDirectoryError ?? "throw") === "throw")
|
|
76
|
-
throw error;
|
|
77
|
-
yield { relativePath: directory, kind: "directory-error", size: 0, error };
|
|
94
|
+
yield onDirectoryError(directory, error);
|
|
78
95
|
return;
|
|
79
96
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (
|
|
97
|
+
// A thrown undefined still needs to be retained if closing also fails.
|
|
98
|
+
let failed = false;
|
|
99
|
+
let operationError;
|
|
100
|
+
try {
|
|
101
|
+
while (true) {
|
|
102
|
+
let next;
|
|
103
|
+
try {
|
|
104
|
+
next = await listing.next();
|
|
105
|
+
options.signal?.throwIfAborted();
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
yield onDirectoryError(directory, error);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (next === undefined)
|
|
112
|
+
return;
|
|
113
|
+
const name = next.kind === "entry" ? next.entry.name : next.name;
|
|
114
|
+
const child = directory
|
|
115
|
+
? path.posix.join(directory.split(path.sep).join(path.posix.sep), name)
|
|
116
|
+
: name;
|
|
117
|
+
if (next.kind === "limit") {
|
|
118
|
+
yield onLimit(child);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const entry = next.entry;
|
|
122
|
+
let kind = entryKind(entry);
|
|
123
|
+
let size = entry.size;
|
|
124
|
+
if (kind === "symlink") {
|
|
125
|
+
if (options.symlinkPolicy === "skip") {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const resolved = await resolveRootPath({
|
|
129
|
+
absolutePath: path.resolve(root.rootReal, child),
|
|
130
|
+
rootPath: root.rootReal,
|
|
131
|
+
rootCanonicalPath: root.rootReal,
|
|
132
|
+
boundaryLabel: "root walk",
|
|
133
|
+
});
|
|
134
|
+
if (!resolved.exists) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const target = await root.stat(path.relative(root.rootReal, resolved.canonicalPath));
|
|
138
|
+
kind = target.isDirectory ? "directory" : target.isFile ? "file" : "other";
|
|
139
|
+
size = target.size;
|
|
140
|
+
}
|
|
141
|
+
const walkEntry = { relativePath: child, kind, size };
|
|
142
|
+
const filterResult = options.entryFilter?.(walkEntry) ?? "include";
|
|
143
|
+
if (!["include", "skip", "skip-subtree"].includes(filterResult)) {
|
|
144
|
+
throw new TypeError(`invalid root walk entryFilter result: ${String(filterResult)}`);
|
|
145
|
+
}
|
|
146
|
+
if (filterResult === "include") {
|
|
147
|
+
yield walkEntry;
|
|
148
|
+
}
|
|
149
|
+
if (kind !== "directory") {
|
|
95
150
|
continue;
|
|
96
151
|
}
|
|
97
|
-
|
|
98
|
-
absolutePath: path.resolve(root.rootReal, child),
|
|
99
|
-
rootPath: root.rootReal,
|
|
100
|
-
rootCanonicalPath: root.rootReal,
|
|
101
|
-
boundaryLabel: "root walk",
|
|
102
|
-
});
|
|
103
|
-
if (!resolved.exists) {
|
|
152
|
+
if (filterResult === "skip-subtree") {
|
|
104
153
|
continue;
|
|
105
154
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
if (filterResult === "include") {
|
|
115
|
-
yield walkEntry;
|
|
116
|
-
}
|
|
117
|
-
if (kind !== "directory") {
|
|
118
|
-
continue;
|
|
155
|
+
if (depth >= maxDepth) {
|
|
156
|
+
yield onLimit(child);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
yield* visit(child, depth + 1);
|
|
160
|
+
if (truncated)
|
|
161
|
+
return;
|
|
119
162
|
}
|
|
120
|
-
|
|
121
|
-
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
failed = true;
|
|
166
|
+
operationError = error;
|
|
167
|
+
throw error;
|
|
168
|
+
}
|
|
169
|
+
finally {
|
|
170
|
+
try {
|
|
171
|
+
await listing[Symbol.asyncDispose]();
|
|
122
172
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
173
|
+
catch (closeError) {
|
|
174
|
+
if (failed) {
|
|
175
|
+
throw createSuppressedError(closeError, operationError, "directory walk and close both failed");
|
|
176
|
+
}
|
|
177
|
+
throw closeError;
|
|
126
178
|
}
|
|
127
|
-
yield* visit(child, depth + 1);
|
|
128
|
-
if (truncated)
|
|
129
|
-
return;
|
|
130
179
|
}
|
|
131
180
|
}
|
|
132
181
|
yield* visit(relativePath, 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root-write-mode.d.ts","sourceRoot":"","sources":["../src/root-write-mode.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"root-write-mode.d.ts","sourceRoot":"","sources":["../src/root-write-mode.ts"],"names":[],"mappings":"AASA,wBAAsB,sBAAsB,CAAC,MAAM,EAAE;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,GAAG,OAAO,CAAC,MAAM,CAAC,CAsClB"}
|
package/dist/root-write-mode.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import fsSync from "node:fs";
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
3
|
import { FsSafeError } from "./errors.js";
|
|
4
|
-
import { sameFileIdentity } from "./file-identity.js";
|
|
5
4
|
import { isNotFoundPathError, isPathInside } from "./path.js";
|
|
6
5
|
import { resolveReadOpenFlags } from "./read-open-flags.js";
|
|
7
6
|
import { hardlinkedPathNotAllowedError, outsideWorkspaceError } from "./root-errors.js";
|
|
@@ -23,9 +22,7 @@ export async function inheritWriteTargetMode(params) {
|
|
|
23
22
|
const handle = await fs.open(params.targetPath, resolveReadOpenFlags());
|
|
24
23
|
try {
|
|
25
24
|
// Bind admission to the inode whose metadata is inherited.
|
|
26
|
-
|
|
27
|
-
throw new FsSafeError("path-mismatch", "write target changed during mode inheritance");
|
|
28
|
-
}
|
|
25
|
+
await inspectFileIdentity(() => fsSync.fstatSync(handle.fd, { bigint: true }), existing);
|
|
29
26
|
}
|
|
30
27
|
finally {
|
|
31
28
|
await handle.close().catch(() => undefined);
|
package/dist/root.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
export { DEFAULT_ROOT_MAX_BYTES, openLocalFileSafely, readLocalFileSafely, resolveOpenedFileRealPathForHandle, root, type DenyMutationPolicy, type HardlinkPolicy, type RenameIdentityPolicy, type OpenResult, type ReadResult, type Root, type RootAppendOptions, type RootCopyOptions, type RootCreateJsonOptions, type RootCreateOptions, type RootDefaults, type RootMkdirOptions, type RootMoveOptions, type RootOpenOptions, type RootOpenWritableOptions, type RootOptions, type RootReadOptions, type RootRemoveOptions, type RootWriteJsonOptions, type RootWriteOptions, type SymlinkPolicy, type WritableOpenMode, type WritableOpenResult, } from "./root-impl.js";
|
|
1
|
+
export { DEFAULT_ROOT_MAX_BYTES, openLocalFileSafely, readLocalFileSafely, resolveOpenedFileRealPathForHandle, root, type DenyMutationPolicy, type HardlinkPolicy, type MutationSymlinkPolicy, type RenameIdentityPolicy, type OpenResult, type ReadResult, type Root, type RootAppendOptions, type RootCopyOptions, type RootCopySource, type RootCreateJsonOptions, type RootCreateOptions, type RootDefaults, type RootMkdirOptions, type RootMoveOptions, type RootOpenOptions, type RootOpenWritableOptions, type RootOptions, type RootReadOptions, type RootRemoveOptions, type RootWriteJsonOptions, type RootWriteOptions, type SymlinkPolicy, type WritableOpenMode, type WritableOpenResult, } from "./root-impl.js";
|
|
2
|
+
export type { RootCopyPublicationReceipt } from "./copy-publication.js";
|
|
3
|
+
export type { CopyCloneMode } from "./copy-policy.js";
|
|
2
4
|
export type { ContainmentGuarantee } from "./containment.js";
|
|
3
5
|
export type { RootWalkDataEntry, RootWalkDataEntryKind, RootWalkDirectoryErrorBehavior, RootWalkEntry, RootWalkEntryFilter, RootWalkEntryFilterResult, RootWalkEntryKind, RootWalkLimitBehavior, RootWalkOptions, RootWalkSymlinkPolicy, } from "./root-walk.js";
|
|
4
6
|
//# sourceMappingURL=root.d.ts.map
|
package/dist/root.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root.d.ts","sourceRoot":"","sources":["../src/root.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,mBAAmB,EACnB,kCAAkC,EAClC,IAAI,EACJ,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,IAAI,EACT,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,uBAAuB,EAC5B,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,GACxB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,YAAY,EACV,iBAAiB,EACjB,qBAAqB,EACrB,8BAA8B,EAC9B,aAAa,EACb,mBAAmB,EACnB,yBAAyB,EACzB,iBAAiB,EACjB,qBAAqB,EACrB,eAAe,EACf,qBAAqB,GACtB,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"root.d.ts","sourceRoot":"","sources":["../src/root.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,mBAAmB,EACnB,kCAAkC,EAClC,IAAI,EACJ,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,IAAI,EACT,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,uBAAuB,EAC5B,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,GACxB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AACxE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,YAAY,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,YAAY,EACV,iBAAiB,EACjB,qBAAqB,EACrB,8BAA8B,EAC9B,aAAa,EACb,mBAAmB,EACnB,yBAAyB,EACzB,iBAAiB,EACjB,qBAAqB,EACrB,eAAe,EACf,qBAAqB,GACtB,MAAM,gBAAgB,CAAC"}
|
package/dist/secret-file.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"secret-file.d.ts","sourceRoot":"","sources":["../src/secret-file.ts"],"names":[],"mappings":"AAAA,OAAW,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAK/C,OAAO,EAAkF,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAUhJ,OAAO,EAML,KAAK,qBAAqB,EAC3B,MAAM,yBAAyB,CAAC;AAIjC,eAAO,MAAM,uBAAuB,MAAQ,CAAC;AAC7C,eAAO,MAAM,wBAAwB,MAAQ,CAAC;AAE9C,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,qBAA0B,GAClC,MAAM,CAkER;AAED,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,qBAA0B,GAClC,MAAM,GAAG,SAAS,CAUpB;AA8JD,KAAK,qBAAqB,GAAG;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"secret-file.d.ts","sourceRoot":"","sources":["../src/secret-file.ts"],"names":[],"mappings":"AAAA,OAAW,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAK/C,OAAO,EAAkF,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAUhJ,OAAO,EAML,KAAK,qBAAqB,EAC3B,MAAM,yBAAyB,CAAC;AAIjC,eAAO,MAAM,uBAAuB,MAAQ,CAAC;AAC7C,eAAO,MAAM,wBAAwB,MAAQ,CAAC;AAE9C,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,qBAA0B,GAClC,MAAM,CAkER;AAED,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,qBAA0B,GAClC,MAAM,GAAG,SAAS,CAUpB;AA8JD,KAAK,qBAAqB,GAAG;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAYF,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,IAAI,CAAC,qBAAqB,EAAE,SAAS,CAAC,GAC7C,OAAO,CAAC;IACT,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC;IAC5C,WAAW,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC,CAuBD;AAwDD,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAKxF;AAED,wBAAsB,sBAAsB,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAezF"}
|
package/dist/secret-file.js
CHANGED
|
@@ -284,6 +284,7 @@ async function materializeSecretFileAtomic(params, createOnly) {
|
|
|
284
284
|
basename: fileName,
|
|
285
285
|
mkdir: false,
|
|
286
286
|
mode,
|
|
287
|
+
sync: params.durable !== false,
|
|
287
288
|
overwrite: !createOnly,
|
|
288
289
|
input: { kind: "buffer", data: typeof params.content === "string" ? params.content : Buffer.from(params.content) },
|
|
289
290
|
rootIdentity: { dev: parentGuard.stat.dev, ino: parentGuard.stat.ino },
|
|
@@ -10,8 +10,8 @@ export async function readSecretFile(filePath, label, options = {}) {
|
|
|
10
10
|
const { resolvedPath, maxBytes } = resolveSecretReadPolicy(filePath, label, options);
|
|
11
11
|
async function inspectInput(symlinkMessage) {
|
|
12
12
|
const stat = options.rejectSymlink
|
|
13
|
-
?
|
|
14
|
-
:
|
|
13
|
+
? fsSync.lstatSync(resolvedPath, { bigint: true })
|
|
14
|
+
: fsSync.statSync(resolvedPath, { bigint: true });
|
|
15
15
|
if (options.rejectSymlink && stat.isSymbolicLink()) {
|
|
16
16
|
throw new FsSafeError("symlink", symlinkMessage);
|
|
17
17
|
}
|
|
@@ -29,19 +29,19 @@ export async function readSecretFile(filePath, label, options = {}) {
|
|
|
29
29
|
let handle;
|
|
30
30
|
let raw;
|
|
31
31
|
try {
|
|
32
|
-
const realPath =
|
|
32
|
+
const realPath = fsSync.realpathSync.native(resolvedPath);
|
|
33
33
|
assertNoUnsafeDeviceReadPath(realPath);
|
|
34
34
|
handle = await fs.open(realPath, resolveReadOpenFlags());
|
|
35
35
|
const openedHandle = handle;
|
|
36
36
|
const openedStat = await inspectFileIdentity(async () => {
|
|
37
|
-
const stat =
|
|
37
|
+
const stat = fsSync.fstatSync(openedHandle.fd, { bigint: true });
|
|
38
38
|
if (!stat.isFile() || (options.rejectHardlinks !== false && stat.nlink > 1n)) {
|
|
39
39
|
throw new FsSafeError("path-mismatch", "security validation failed");
|
|
40
40
|
}
|
|
41
41
|
return stat;
|
|
42
42
|
}, previewStat);
|
|
43
43
|
await inspectFileIdentity(async () => {
|
|
44
|
-
const stat =
|
|
44
|
+
const stat = fsSync.lstatSync(realPath, { bigint: true });
|
|
45
45
|
if (!stat.isFile())
|
|
46
46
|
throw new FsSafeError("path-mismatch", "security validation failed");
|
|
47
47
|
return stat;
|
package/dist/secure-file.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"secure-file.d.ts","sourceRoot":"","sources":["../src/secure-file.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"secure-file.d.ts","sourceRoot":"","sources":["../src/secure-file.ts"],"names":[],"mappings":"AAAA,OAAe,EAAE,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAa7C,OAAO,EAOL,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC5B,MAAM,kBAAkB,CAAC;AAI1B,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,sBAAsB,CAAC;IAC/B,WAAW,CAAC,EAAE,2BAA2B,CAAC;IAC1C,MAAM,CAAC,EAAE,uBAAuB,CAAC;IACjC,EAAE,CAAC,EAAE,mBAAmB,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG,sBAAsB,CAAC;AAE7D,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,KAAK,CAAC;IACZ,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B,CAAC;AAmMF,wBAAsB,cAAc,CAClC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,oBAAoB,CAAC,CAe/B"}
|
package/dist/secure-file.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 { readFileHandleBounded } from "./bounded-read.js";
|
|
@@ -10,6 +11,7 @@ import { formatPermissionErrorDetail } from "./permission-exec.js";
|
|
|
10
11
|
import { resolveReadOpenFlags } from "./read-open-flags.js";
|
|
11
12
|
import { inspectPathPermissions, isGroupReadable, isGroupWritable, isWorldReadable, isWorldWritable, modeBits, } from "./permissions.js";
|
|
12
13
|
import { inspectFileIdentity } from "./strict-file-identity.js";
|
|
14
|
+
import { scheduleTimeout } from "./timing.js";
|
|
13
15
|
function isAbsolutePathname(value) {
|
|
14
16
|
return (path.isAbsolute(value) ||
|
|
15
17
|
(process.platform === "win32" &&
|
|
@@ -26,11 +28,15 @@ async function openSecureHandle(options, maxBytes) {
|
|
|
26
28
|
if (!isAbsolutePathname(options.filePath)) {
|
|
27
29
|
throw new FsSafeError("invalid-path", `${label(options)} must be an absolute path.`);
|
|
28
30
|
}
|
|
29
|
-
|
|
31
|
+
let preStat;
|
|
32
|
+
try {
|
|
33
|
+
preStat = fsSync.lstatSync(options.filePath);
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
30
36
|
throw new FsSafeError("not-found", `${label(options)} is not readable: ${options.filePath}`, {
|
|
31
37
|
cause: err,
|
|
32
38
|
});
|
|
33
|
-
}
|
|
39
|
+
}
|
|
34
40
|
if (preStat.isSymbolicLink()) {
|
|
35
41
|
if (!options.trust?.allowSymlink) {
|
|
36
42
|
throw new FsSafeError("symlink", `${label(options)} must not be a symlink: ${options.filePath}`);
|
|
@@ -52,22 +58,22 @@ async function openSecureHandle(options, maxBytes) {
|
|
|
52
58
|
throw err;
|
|
53
59
|
}
|
|
54
60
|
try {
|
|
55
|
-
const openedStat =
|
|
61
|
+
const openedStat = fsSync.fstatSync(handle.fd);
|
|
56
62
|
if (!openedStat.isFile()) {
|
|
57
63
|
throw new FsSafeError("not-file", `${label(options)} must be a file: ${options.filePath}`);
|
|
58
64
|
}
|
|
59
|
-
const openedIdentity = await inspectFileIdentity(() => handle.
|
|
65
|
+
const openedIdentity = await inspectFileIdentity(() => fsSync.fstatSync(handle.fd, { bigint: true }));
|
|
60
66
|
await inspectFileIdentity(async () => {
|
|
61
67
|
const pathStat = options.trust?.allowSymlink
|
|
62
|
-
?
|
|
63
|
-
:
|
|
68
|
+
? fsSync.statSync(options.filePath, { bigint: true })
|
|
69
|
+
: fsSync.lstatSync(options.filePath, { bigint: true });
|
|
64
70
|
if (!options.trust?.allowSymlink && pathStat.isSymbolicLink()) {
|
|
65
71
|
throw new FsSafeError("symlink", `${label(options)} must not be a symlink: ${options.filePath}`);
|
|
66
72
|
}
|
|
67
73
|
return pathStat;
|
|
68
74
|
}, openedIdentity);
|
|
69
|
-
const realPath =
|
|
70
|
-
await inspectFileIdentity(() =>
|
|
75
|
+
const realPath = fsSync.realpathSync.native(options.filePath);
|
|
76
|
+
await inspectFileIdentity(() => fsSync.statSync(realPath, { bigint: true }), openedIdentity);
|
|
71
77
|
if (maxBytes !== undefined && openedStat.size > maxBytes) {
|
|
72
78
|
throw new FsSafeError("too-large", `${label(options)} exceeded maxBytes (${maxBytes}).`);
|
|
73
79
|
}
|
|
@@ -84,7 +90,12 @@ async function assertTrustedDirs(options, realPath) {
|
|
|
84
90
|
}
|
|
85
91
|
const trusted = await Promise.all(options.trust.trustedDirs.map(async (dir) => {
|
|
86
92
|
const resolved = path.resolve(dir);
|
|
87
|
-
|
|
93
|
+
try {
|
|
94
|
+
return fsSync.realpathSync.native(resolved);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return resolved;
|
|
98
|
+
}
|
|
88
99
|
}));
|
|
89
100
|
if (!trusted.some((dir) => isPathInside(dir, realPath))) {
|
|
90
101
|
throw new FsSafeError("outside-workspace", `${label(options)} is outside trustedDirs: ${realPath}`);
|
|
@@ -150,12 +161,12 @@ async function readHandleWithTimeout(handle, timeoutMs, maxBytes) {
|
|
|
150
161
|
if (timeoutMs === undefined || !Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
151
162
|
return await read();
|
|
152
163
|
}
|
|
153
|
-
let
|
|
164
|
+
let cancelTimeout;
|
|
154
165
|
try {
|
|
155
166
|
return await Promise.race([
|
|
156
167
|
read(),
|
|
157
168
|
new Promise((_resolve, reject) => {
|
|
158
|
-
|
|
169
|
+
cancelTimeout = scheduleTimeout(() => {
|
|
159
170
|
void handle.close().catch(() => undefined);
|
|
160
171
|
reject(new FsSafeError("timeout", `secure file read timed out after ${timeoutMs}ms`));
|
|
161
172
|
}, timeoutMs);
|
|
@@ -163,8 +174,7 @@ async function readHandleWithTimeout(handle, timeoutMs, maxBytes) {
|
|
|
163
174
|
]);
|
|
164
175
|
}
|
|
165
176
|
finally {
|
|
166
|
-
|
|
167
|
-
clearTimeout(timeout);
|
|
177
|
+
cancelTimeout?.();
|
|
168
178
|
}
|
|
169
179
|
}
|
|
170
180
|
export async function readSecureFile(options) {
|
|
@@ -22,7 +22,7 @@ function assertRegularFile(stat) {
|
|
|
22
22
|
}
|
|
23
23
|
async function inspectStage(inspect, expected) {
|
|
24
24
|
return await inspectFileIdentity(async () => {
|
|
25
|
-
const stat =
|
|
25
|
+
const stat = inspect();
|
|
26
26
|
assertRegularFile(stat);
|
|
27
27
|
return stat;
|
|
28
28
|
}, expected);
|
|
@@ -33,20 +33,20 @@ async function inspectStage(inspect, expected) {
|
|
|
33
33
|
export async function writeCallbackSibling(params) {
|
|
34
34
|
const parent = path.dirname(params.tempPath);
|
|
35
35
|
const guard = await createAsyncDirectoryGuard(parent);
|
|
36
|
-
const parentIdentity = await inspectFileIdentity(() =>
|
|
36
|
+
const parentIdentity = await inspectFileIdentity(() => fsSync.lstatSync(parent, { bigint: true }));
|
|
37
37
|
const assertParent = async () => {
|
|
38
38
|
await assertAsyncDirectoryGuard(guard);
|
|
39
|
-
await inspectFileIdentity(() =>
|
|
39
|
+
await inspectFileIdentity(() => fsSync.lstatSync(parent, { bigint: true }), parentIdentity);
|
|
40
40
|
};
|
|
41
41
|
let handle;
|
|
42
42
|
let identity;
|
|
43
43
|
let unregister;
|
|
44
44
|
let renamed = false;
|
|
45
45
|
let failure;
|
|
46
|
-
const inspectPath = (pathname, expected) => inspectStage(() =>
|
|
46
|
+
const inspectPath = (pathname, expected) => inspectStage(() => fsSync.lstatSync(pathname, { bigint: true }), expected);
|
|
47
47
|
const assertCurrent = async (pathname) => {
|
|
48
48
|
await assertParent();
|
|
49
|
-
const opened = await inspectStage(() => handle.
|
|
49
|
+
const opened = await inspectStage(() => fsSync.fstatSync(handle.fd, { bigint: true }), identity);
|
|
50
50
|
const current = await inspectPath(pathname, opened);
|
|
51
51
|
if (params.maxBytes !== undefined &&
|
|
52
52
|
(opened.size > params.maxBytes || current.size > params.maxBytes)) {
|
|
@@ -68,7 +68,7 @@ export async function writeCallbackSibling(params) {
|
|
|
68
68
|
}
|
|
69
69
|
throw error;
|
|
70
70
|
}
|
|
71
|
-
const opened = await inspectStage(() => handle.
|
|
71
|
+
const opened = await inspectStage(() => fsSync.fstatSync(handle.fd, { bigint: true }), before);
|
|
72
72
|
await inspectPath(params.tempPath, opened);
|
|
73
73
|
await assertParent();
|
|
74
74
|
identity = opened;
|
|
@@ -116,7 +116,7 @@ export async function writeCallbackSibling(params) {
|
|
|
116
116
|
if (!renamed && identity) {
|
|
117
117
|
try {
|
|
118
118
|
await assertParent();
|
|
119
|
-
await inspectStage(() => handle.
|
|
119
|
+
await inspectStage(() => fsSync.fstatSync(handle.fd, { bigint: true }), identity);
|
|
120
120
|
await inspectPath(params.tempPath, identity);
|
|
121
121
|
await fs.unlink(params.tempPath);
|
|
122
122
|
unregister?.();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sibling-temp.d.ts","sourceRoot":"","sources":["../src/sibling-temp.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sibling-temp.d.ts","sourceRoot":"","sources":["../src/sibling-temp.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,2BAA2B,CAAC,CAAC,IAAI;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IAC5C,gBAAgB,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,CAAC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uGAAuG;IACvG,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,yEAAyE;IACzE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,0BAA0B,CAAC,CAAC,IAAI;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,CAAC,CAAC;CACX,CAAC;AASF,wBAAsB,oBAAoB,CAAC,CAAC,EAC1C,OAAO,EAAE,2BAA2B,CAAC,CAAC,CAAC,GACtC,OAAO,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC,CAoBxC;AAwBD,wBAAsB,uBAAuB,CAAC,MAAM,EAAE;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6ChB"}
|
package/dist/sibling-temp.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import crypto, { randomUUID } from "node:crypto";
|
|
2
|
+
import fsSync from "node:fs";
|
|
2
3
|
import fs from "node:fs/promises";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { assertAsyncDirectoryGuard, createAsyncDirectoryGuard } from "./directory-guard.js";
|
|
@@ -52,14 +53,22 @@ function buildSiblingTempPath(params) {
|
|
|
52
53
|
return path.join(path.dirname(params.targetPath), `${prefix}${safeTail}${suffix}`);
|
|
53
54
|
}
|
|
54
55
|
export async function writeViaSiblingTempPath(params) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
.
|
|
56
|
+
let rootDir;
|
|
57
|
+
try {
|
|
58
|
+
rootDir = fsSync.realpathSync.native(path.resolve(params.rootDir));
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
rootDir = path.resolve(params.rootDir);
|
|
62
|
+
}
|
|
58
63
|
const requestedTargetPath = path.resolve(params.targetPath);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
.
|
|
64
|
+
let targetPath;
|
|
65
|
+
try {
|
|
66
|
+
const realDir = fsSync.realpathSync.native(path.dirname(requestedTargetPath));
|
|
67
|
+
targetPath = path.join(realDir, path.basename(requestedTargetPath));
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
targetPath = requestedTargetPath;
|
|
71
|
+
}
|
|
63
72
|
const relativeTargetPath = path.relative(rootDir, targetPath);
|
|
64
73
|
if (!relativeTargetPath ||
|
|
65
74
|
relativeTargetPath === ".." ||
|
|
@@ -2,7 +2,7 @@ import { type NativeFileHandle } from "./native-operations.js";
|
|
|
2
2
|
import type { Root } from "./root-impl.js";
|
|
3
3
|
import { type SidecarLockSnapshot } from "./sidecar-lock-reclaim.js";
|
|
4
4
|
import type { SidecarLockAcquireOptions, SidecarLockHandle } from "./sidecar-lock-types.js";
|
|
5
|
-
type SidecarFileHandle = Pick<NativeFileHandle, "close" | "stat" | "writeFile">;
|
|
5
|
+
type SidecarFileHandle = Pick<NativeFileHandle, "fd" | "close" | "stat" | "writeFile">;
|
|
6
6
|
export type HeldSidecarLock = {
|
|
7
7
|
refCount: number;
|
|
8
8
|
reentrantOwner?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidecar-lock-acquire.d.ts","sourceRoot":"","sources":["../src/sidecar-lock-acquire.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sidecar-lock-acquire.d.ts","sourceRoot":"","sources":["../src/sidecar-lock-acquire.ts"],"names":[],"mappings":"AAQA,OAAO,EAA6B,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1F,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAS3C,OAAO,EAWL,KAAK,mBAAmB,EACzB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,yBAAyB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAI5F,KAAK,iBAAiB,GAAG,IAAI,CAAC,gBAAgB,EAAE,IAAI,GAAG,OAAO,GAAG,MAAM,GAAG,WAAW,CAAC,CAAC;AAEvF,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,cAAc,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,QAAQ,CAAC,EAAE,IAAI,CAAC;IAChB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IACxC,eAAe,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC;CAClC,CAAC;AAEF,KAAK,6BAA6B,GAAG;IACnC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACnC,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,2BAA2B,IAAI,IAAI,CAAC;IACpC,iBAAiB,CAAC,oBAAoB,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,GAAG,iBAAiB,CAAC;IAC1F,eAAe,CACb,oBAAoB,EAAE,MAAM,EAC5B,IAAI,EAAE,eAAe,EACrB,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAC5B,OAAO,CAAC,OAAO,CAAC,CAAC;CACrB,CAAC;AAqBF,wBAAsB,kBAAkB,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/E,OAAO,EAAE,yBAAyB,CAAC,QAAQ,CAAC,EAC5C,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,iBAAiB,CAAC,CAqT5B"}
|
|
@@ -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 { canonicalPathFromExistingAncestor } from "./absolute-path.js";
|
|
@@ -9,6 +10,7 @@ import { createNativeExclusiveFile } from "./native-operations.js";
|
|
|
9
10
|
import { computeSidecarLockDelayMs, defaultSidecarLockShouldReclaim, isTransientLockFileDenial, maxTransientLockDenials, validateSidecarLockRetryOptions, validateSidecarLockTimeoutMs, } from "./sidecar-lock-policy.js";
|
|
10
11
|
import { readSidecarLockRawSnapshot, parseSidecarLockSnapshot, relativeSidecarLockPath, releaseSidecarReclaimGuard, removeSidecarLockIfUnchanged, removeStaleSidecarLockIfAllowed, serializeSidecarLockPayload, sidecarLockSnapshotStillPresent, sidecarReclaimGuardExists, tryAcquireSidecarReclaimGuard, } from "./sidecar-lock-reclaim.js";
|
|
11
12
|
import { createSuppressedError } from "./suppressed-error.js";
|
|
13
|
+
import { sleep } from "./timing.js";
|
|
12
14
|
async function resolveNormalizedTargetPath(targetPath, lockRoot) {
|
|
13
15
|
const resolved = path.resolve(targetPath);
|
|
14
16
|
const dir = path.dirname(resolved);
|
|
@@ -22,7 +24,7 @@ async function resolveNormalizedTargetPath(targetPath, lockRoot) {
|
|
|
22
24
|
}
|
|
23
25
|
await fs.mkdir(dir, { recursive: true });
|
|
24
26
|
try {
|
|
25
|
-
return path.join(
|
|
27
|
+
return path.join(fsSync.realpathSync.native(dir), path.basename(resolved));
|
|
26
28
|
}
|
|
27
29
|
catch {
|
|
28
30
|
return resolved;
|
|
@@ -85,7 +87,7 @@ export async function acquireSidecarLock(options, context) {
|
|
|
85
87
|
: Math.max(0, options.timeoutMs - elapsed);
|
|
86
88
|
const delay = Math.min(computeSidecarLockDelayMs(retry, attempt), remaining);
|
|
87
89
|
attempt += 1;
|
|
88
|
-
await
|
|
90
|
+
await sleep(delay);
|
|
89
91
|
};
|
|
90
92
|
// Waiting can fail on the caller's own retry or deadline limits. Classifying
|
|
91
93
|
// a denial as contention must not cost them the original diagnosis, so hand
|
|
@@ -159,7 +161,7 @@ export async function acquireSidecarLock(options, context) {
|
|
|
159
161
|
}
|
|
160
162
|
await handle.writeFile(raw, "utf8");
|
|
161
163
|
}
|
|
162
|
-
const snapshot = { raw, payload, stat:
|
|
164
|
+
const snapshot = { raw, payload, stat: fsSync.fstatSync(handle.fd), ownershipToken };
|
|
163
165
|
if (snapshot.stat.nlink === 0) {
|
|
164
166
|
await handle.close();
|
|
165
167
|
handle = null;
|
|
@@ -213,7 +215,7 @@ export async function acquireSidecarLock(options, context) {
|
|
|
213
215
|
if (handle) {
|
|
214
216
|
const failedSnapshot = createdSnapshot ?? { payload: null };
|
|
215
217
|
try {
|
|
216
|
-
failedSnapshot.stat =
|
|
218
|
+
failedSnapshot.stat = fsSync.fstatSync(handle.fd);
|
|
217
219
|
}
|
|
218
220
|
catch {
|
|
219
221
|
// Best-effort cleanup of a failed exclusive create.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidecar-lock-policy.d.ts","sourceRoot":"","sources":["../src/sidecar-lock-policy.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAQvE,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,uBAAuB,GAAG,IAAI,CAkBpF;AAED,wBAAgB,4BAA4B,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAGhF;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,uBAAuB,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"sidecar-lock-policy.d.ts","sourceRoot":"","sources":["../src/sidecar-lock-policy.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAQvE,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,uBAAuB,GAAG,IAAI,CAkBpF;AAED,wBAAgB,4BAA4B,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAGhF;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,uBAAuB,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAUjG;AASD,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGnF;AAED,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAU7E;AAED,wBAAsB,+BAA+B,CAAC,MAAM,EAAE;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC,OAAO,CAAC,CAQnB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import fsSync from "node:fs";
|
|
2
2
|
function assertFiniteNonNegative(value, label) {
|
|
3
3
|
if (!Number.isFinite(value) || value < 0) {
|
|
4
4
|
throw new RangeError(`${label} must be a finite non-negative number`);
|
|
@@ -32,7 +32,9 @@ export function computeSidecarLockDelayMs(retry, attempt) {
|
|
|
32
32
|
const minTimeout = retry.minTimeout ?? 50;
|
|
33
33
|
const maxTimeout = retry.maxTimeout ?? 1000;
|
|
34
34
|
const factor = retry.factor ?? 1;
|
|
35
|
-
|
|
35
|
+
// Zero times an overflowing power is NaN, which makes Atomics.wait unbounded.
|
|
36
|
+
const scaled = minTimeout === 0 ? 0 : minTimeout * factor ** attempt;
|
|
37
|
+
const base = Math.min(maxTimeout, Math.max(minTimeout, scaled));
|
|
36
38
|
const jitter = retry.randomize ? 1 + Math.random() : 1;
|
|
37
39
|
return Math.min(maxTimeout, Math.round(base * jitter));
|
|
38
40
|
}
|
|
@@ -63,7 +65,7 @@ export async function defaultSidecarLockShouldReclaim(params) {
|
|
|
63
65
|
if (createdAtMs !== null)
|
|
64
66
|
return params.nowMs - createdAtMs > params.staleMs;
|
|
65
67
|
try {
|
|
66
|
-
return params.nowMs -
|
|
68
|
+
return params.nowMs - fsSync.statSync(params.lockPath).mtimeMs > params.staleMs;
|
|
67
69
|
}
|
|
68
70
|
catch {
|
|
69
71
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidecar-lock-reclaim.d.ts","sourceRoot":"","sources":["../src/sidecar-lock-reclaim.ts"],"names":[],"mappings":"AACA,OAAe,EAAE,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAO7C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAa3C,MAAM,MAAM,wBAAwB,GAAG;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,KAAK,sBAAsB,GAAG,IAAI,CAAC,mBAAmB,EAAE,SAAS,CAAC,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAErF,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,sBAAsB,GAAG,IAAI,EACvC,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,GAChC,mBAAmB,GAAG,IAAI,CAE5B;AAYD,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE7E;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAC7E,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,MAAM,CAAC;CACxB,CAWA;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAahF;AAED,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,GAChC,OAAO,CAUT;AAOD,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,UAAU,CAAC,OAAO,0BAA0B,CAAC,CAAC,CAAC,CAAC,GAAG;IAAE,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAA;CAAO,GAC3G,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAErC;AAED,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IACP,QAAQ,CAAC,EAAE,IAAI,CAAC;IAChB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,4BAA4B,CAAC,EAAE,OAAO,CAAC;IAEvC,kBAAkB,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAC5C,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACrC,GACL,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"sidecar-lock-reclaim.d.ts","sourceRoot":"","sources":["../src/sidecar-lock-reclaim.ts"],"names":[],"mappings":"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"}
|