@openclaw/fs-safe 0.15.0 → 0.16.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 +38 -0
- package/README.md +28 -6
- package/dist/advanced.d.ts +1 -0
- package/dist/advanced.d.ts.map +1 -1
- package/dist/advanced.js +1 -0
- package/dist/archive-kind.d.ts +0 -1
- package/dist/archive-kind.d.ts.map +1 -1
- package/dist/archive-kind.js +5 -17
- package/dist/archive-parser.wasm +0 -0
- package/dist/archive-read.d.ts.map +1 -1
- package/dist/archive-read.js +6 -7
- package/dist/archive-tar-stream.d.ts +3 -0
- package/dist/archive-tar-stream.d.ts.map +1 -1
- package/dist/archive-tar-stream.js +56 -37
- package/dist/archive-tar-wasm.d.ts +16 -4
- package/dist/archive-tar-wasm.d.ts.map +1 -1
- package/dist/archive-tar-wasm.js +134 -34
- package/dist/archive.d.ts.map +1 -1
- package/dist/archive.js +5 -6
- package/dist/clone-metadata.d.ts +1 -0
- package/dist/clone-metadata.d.ts.map +1 -1
- package/dist/clone-metadata.js +6 -2
- package/dist/create-directory.d.ts +20 -0
- package/dist/create-directory.d.ts.map +1 -0
- package/dist/create-directory.js +130 -0
- package/dist/create-file-async.d.ts +7 -0
- package/dist/create-file-async.d.ts.map +1 -0
- package/dist/create-file-async.js +121 -0
- package/dist/create-file.d.ts +8 -0
- package/dist/create-file.d.ts.map +1 -0
- package/dist/create-file.js +190 -0
- package/dist/create-owned-file.d.ts +8 -0
- package/dist/create-owned-file.d.ts.map +1 -0
- package/dist/create-owned-file.js +16 -0
- package/dist/create.d.ts +4 -0
- package/dist/create.d.ts.map +1 -0
- package/dist/create.js +2 -0
- package/dist/creation-darwin.d.ts +7 -0
- package/dist/creation-darwin.d.ts.map +1 -0
- package/dist/creation-darwin.js +79 -0
- package/dist/creation-file-state.d.ts +19 -0
- package/dist/creation-file-state.d.ts.map +1 -0
- package/dist/creation-file-state.js +118 -0
- package/dist/creation-path.d.ts +21 -0
- package/dist/creation-path.d.ts.map +1 -0
- package/dist/creation-path.js +71 -0
- package/dist/creation-permissions.d.ts +19 -0
- package/dist/creation-permissions.d.ts.map +1 -0
- package/dist/creation-permissions.js +125 -0
- package/dist/directory-durability.d.ts +1 -1
- package/dist/directory-durability.d.ts.map +1 -1
- package/dist/directory-durability.js +22 -80
- package/dist/directory-guard.d.ts +3 -0
- package/dist/directory-guard.d.ts.map +1 -1
- package/dist/directory-mode-node.d.ts +2 -0
- package/dist/directory-mode-node.d.ts.map +1 -1
- package/dist/directory-mode-node.js +8 -0
- package/dist/directory-receipt.d.ts +24 -0
- package/dist/directory-receipt.d.ts.map +1 -0
- package/dist/directory-receipt.js +127 -0
- package/dist/file-cleanup.d.ts +19 -0
- package/dist/file-cleanup.d.ts.map +1 -0
- package/dist/file-cleanup.js +78 -0
- package/dist/file-observation.d.ts +1 -1
- package/dist/file-observation.d.ts.map +1 -1
- package/dist/file-store-boundary.d.ts +2 -6
- package/dist/file-store-boundary.d.ts.map +1 -1
- package/dist/file-store-boundary.js +3 -9
- package/dist/file-store-sync-write.d.ts.map +1 -1
- package/dist/file-store-sync-write.js +2 -5
- package/dist/guarded-mkdir.d.ts +1 -0
- package/dist/guarded-mkdir.d.ts.map +1 -1
- package/dist/guarded-mkdir.js +36 -7
- package/dist/move-path.js +1 -1
- package/dist/native-binding.d.ts +11 -1
- package/dist/native-binding.d.ts.map +1 -1
- package/dist/native-fallback-warning.d.ts +4 -0
- package/dist/native-fallback-warning.d.ts.map +1 -0
- package/dist/native-fallback-warning.js +11 -0
- package/dist/native-operations.d.ts +0 -2
- package/dist/native-operations.d.ts.map +1 -1
- package/dist/native-operations.js +0 -24
- package/dist/native-parent-admission.d.ts +2 -0
- package/dist/native-parent-admission.d.ts.map +1 -1
- package/dist/native-parent-admission.js +3 -2
- package/dist/native-pinned-write-windows.d.ts +1 -1
- package/dist/native-pinned-write-windows.d.ts.map +1 -1
- package/dist/native-pinned-write-windows.js +173 -28
- package/dist/native-pinned-write.d.ts.map +1 -1
- package/dist/native-pinned-write.js +19 -3
- package/dist/native-policy-parent-windows.d.ts.map +1 -1
- package/dist/native-policy-parent-windows.js +15 -6
- package/dist/native-staged-file.d.ts +3 -2
- package/dist/native-staged-file.d.ts.map +1 -1
- package/dist/native-staged-file.js +86 -39
- package/dist/owner-dacl.d.ts.map +1 -1
- package/dist/owner-dacl.js +10 -4
- package/dist/pinned-write-input.d.ts +4 -0
- package/dist/pinned-write-input.d.ts.map +1 -0
- package/dist/pinned-write-input.js +25 -0
- package/dist/pinned-write-mode.d.ts +5 -0
- package/dist/pinned-write-mode.d.ts.map +1 -0
- package/dist/pinned-write-mode.js +24 -0
- package/dist/pinned-write-staged.d.ts +6 -0
- package/dist/pinned-write-staged.d.ts.map +1 -0
- package/dist/pinned-write-staged.js +187 -0
- package/dist/pinned-write-types.d.ts +3 -0
- package/dist/pinned-write-types.d.ts.map +1 -1
- package/dist/pinned-write.d.ts.map +1 -1
- package/dist/pinned-write.js +35 -145
- package/dist/private-directory.d.ts.map +1 -1
- package/dist/private-directory.js +18 -4
- package/dist/private-producer-handoff-sync.d.ts +14 -0
- package/dist/private-producer-handoff-sync.d.ts.map +1 -0
- package/dist/private-producer-handoff-sync.js +114 -0
- package/dist/private-producer-handoff.d.ts +22 -4
- package/dist/private-producer-handoff.d.ts.map +1 -1
- package/dist/private-producer-handoff.js +140 -77
- package/dist/publish-copy-stage.d.ts +2 -1
- package/dist/publish-copy-stage.d.ts.map +1 -1
- package/dist/publish-copy-stage.js +16 -7
- package/dist/publish-file.d.ts.map +1 -1
- package/dist/publish-file.js +2 -2
- package/dist/replace-file-temp-owner.d.ts +0 -7
- package/dist/replace-file-temp-owner.d.ts.map +1 -1
- package/dist/replace-file-temp-owner.js +3 -54
- package/dist/root-create-input.d.ts +2 -1
- package/dist/root-create-input.d.ts.map +1 -1
- package/dist/root-create-input.js +13 -4
- package/dist/root-directory-creation.d.ts +3 -3
- package/dist/root-directory-creation.d.ts.map +1 -1
- package/dist/root-directory-creation.js +15 -3
- package/dist/root-impl.d.ts.map +1 -1
- package/dist/root-impl.js +28 -7
- package/dist/root-move-noreplace.d.ts.map +1 -1
- package/dist/root-move-noreplace.js +22 -13
- package/dist/root-options.d.ts +12 -4
- package/dist/root-options.d.ts.map +1 -1
- package/dist/root-path-stat.d.ts.map +1 -1
- package/dist/root-path-stat.js +59 -7
- package/dist/root-write-publication.js +1 -1
- package/dist/secret-file.d.ts.map +1 -1
- package/dist/secret-file.js +1 -0
- package/dist/secure-file-windows.d.ts +6 -0
- package/dist/secure-file-windows.d.ts.map +1 -1
- package/dist/secure-file-windows.js +34 -117
- package/dist/secure-file.js +2 -2
- package/dist/sidecar-lock-root.d.ts.map +1 -1
- package/dist/sidecar-lock-root.js +2 -1
- package/dist/staged-directory.d.ts.map +1 -1
- package/dist/staged-directory.js +6 -6
- package/dist/staged-file-settlement.d.ts +17 -0
- package/dist/staged-file-settlement.d.ts.map +1 -0
- package/dist/staged-file-settlement.js +57 -0
- package/dist/windows-owner.d.ts.map +1 -1
- package/dist/windows-owner.js +2 -1
- package/dist/windows-security-bridge.cs +336 -0
- package/dist/windows-security-bridge.ps1 +15 -0
- package/dist/windows-security-command.d.ts +26 -0
- package/dist/windows-security-command.d.ts.map +1 -0
- package/dist/windows-security-command.js +363 -0
- package/dist/windows-security-facts.d.ts +6 -0
- package/dist/windows-security-facts.d.ts.map +1 -0
- package/dist/windows-security-facts.js +108 -0
- package/docs/advanced.md +3 -1
- package/docs/archive.md +61 -37
- package/docs/config.md +6 -2
- package/docs/contributing.md +44 -4
- package/docs/copy.md +2 -0
- package/docs/creation.md +128 -0
- package/docs/durability.md +24 -0
- package/docs/install.md +31 -7
- package/docs/migrating-to-0.5.md +15 -6
- package/docs/migrating-to-0.6.md +9 -4
- package/docs/native-helper.md +22 -9
- package/docs/native.md +38 -7
- package/docs/permissions.md +37 -14
- package/docs/root.md +34 -0
- package/docs/secret-file.md +11 -2
- package/docs/secure-file.md +9 -4
- package/docs/sidecar-lock.md +5 -4
- package/docs/staged-file.md +5 -0
- package/docs/writing.md +71 -5
- package/package.json +18 -15
|
@@ -2,13 +2,14 @@ import fsSync, {} from "node:fs";
|
|
|
2
2
|
import fs, {} from "node:fs/promises";
|
|
3
3
|
import { FsSafeError } from "./errors.js";
|
|
4
4
|
import { sameFileIdentityForCleanup } from "./file-identity.js";
|
|
5
|
+
import { assertSynchronousCallbackResult } from "./mutation-authority.js";
|
|
5
6
|
import { resolveReadOpenFlags } from "./read-open-flags.js";
|
|
6
7
|
import { inspectFileIdentitySync } from "./strict-file-identity.js";
|
|
7
8
|
import { registerTempPathForExit, } from "./temp-cleanup.js";
|
|
8
9
|
function pathMismatch(message) {
|
|
9
10
|
return new FsSafeError("path-mismatch", message);
|
|
10
11
|
}
|
|
11
|
-
function assertInitialSource(stat) {
|
|
12
|
+
export function assertInitialSource(stat) {
|
|
12
13
|
if (stat.isSymbolicLink()) {
|
|
13
14
|
throw new FsSafeError("path-alias", "isolated producer output must not be a symlink");
|
|
14
15
|
}
|
|
@@ -19,7 +20,7 @@ function assertInitialSource(stat) {
|
|
|
19
20
|
throw new FsSafeError("hardlink", "isolated producer output must have exactly one link");
|
|
20
21
|
}
|
|
21
22
|
}
|
|
22
|
-
function inspectLinkedFile(inspect, expected, links, label) {
|
|
23
|
+
export function inspectLinkedFile(inspect, expected, links, label) {
|
|
23
24
|
return inspectFileIdentitySync(() => {
|
|
24
25
|
const stat = inspect();
|
|
25
26
|
if (stat.isSymbolicLink() || !stat.isFile() || stat.nlink !== links) {
|
|
@@ -28,11 +29,11 @@ function inspectLinkedFile(inspect, expected, links, label) {
|
|
|
28
29
|
return stat;
|
|
29
30
|
}, expected);
|
|
30
31
|
}
|
|
31
|
-
function assertParents(params) {
|
|
32
|
+
export function assertParents(params) {
|
|
32
33
|
params.assertTargetParent();
|
|
33
34
|
params.assertSourceParent();
|
|
34
35
|
}
|
|
35
|
-
function normalizeLinkError(error) {
|
|
36
|
+
export function normalizeLinkError(error) {
|
|
36
37
|
const code = error?.code;
|
|
37
38
|
if (code === "EEXIST") {
|
|
38
39
|
return new FsSafeError("already-exists", "isolated producer sibling already exists", {
|
|
@@ -101,7 +102,7 @@ async function throwAfterClosing(primary, handles) {
|
|
|
101
102
|
throw combinedFailure(primary, settlement);
|
|
102
103
|
}
|
|
103
104
|
function inspectSourceDescriptor(handle, identity, links = 1n) {
|
|
104
|
-
inspectLinkedFile(() => fsSync.fstatSync(handle.fd, { bigint: true }), identity, links, "isolated producer descriptor");
|
|
105
|
+
return inspectLinkedFile(() => fsSync.fstatSync(handle.fd, { bigint: true }), identity, links, "isolated producer descriptor");
|
|
105
106
|
}
|
|
106
107
|
function historicalOpenFlags(readWrite) {
|
|
107
108
|
const access = readWrite ? fsSync.constants.O_RDWR : fsSync.constants.O_RDONLY;
|
|
@@ -164,109 +165,171 @@ async function openProducerSource(params, identity, links = 1n) {
|
|
|
164
165
|
}
|
|
165
166
|
return fallback;
|
|
166
167
|
}
|
|
167
|
-
function
|
|
168
|
+
function inspectHandoff(params, handle, identity, state, links) {
|
|
168
169
|
assertParents(params);
|
|
169
|
-
inspectSourceDescriptor(handle, identity,
|
|
170
|
-
|
|
171
|
-
|
|
170
|
+
const opened = inspectSourceDescriptor(handle, identity, links);
|
|
171
|
+
if (state.cleanup !== "removed") {
|
|
172
|
+
inspectLinkedFile(() => fsSync.lstatSync(params.sourcePath, { bigint: true }), identity, links, "isolated producer path");
|
|
173
|
+
}
|
|
174
|
+
const named = state.publication === "published" ? inspectLinkedFile(() => fsSync.lstatSync(params.targetPath, { bigint: true }), identity, links, "isolated producer sibling") : undefined;
|
|
175
|
+
return { opened, named };
|
|
172
176
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
const identity = inspectFileIdentitySync(() => {
|
|
177
|
+
async function handoffFile(params) {
|
|
178
|
+
const created = "source" in params ? params : undefined;
|
|
179
|
+
const identity = created?.identity ?? inspectFileIdentitySync(() => {
|
|
180
|
+
assertParents(params);
|
|
176
181
|
const stat = fsSync.lstatSync(params.sourcePath, { bigint: true });
|
|
177
182
|
assertInitialSource(stat);
|
|
178
183
|
return stat;
|
|
179
184
|
});
|
|
180
|
-
let handle;
|
|
181
|
-
|
|
185
|
+
let handle = created?.source;
|
|
186
|
+
const owners = new Set(handle ? [handle] : []);
|
|
187
|
+
const failures = [];
|
|
182
188
|
let unregister;
|
|
183
|
-
const state = {
|
|
189
|
+
const state = {
|
|
190
|
+
siblingOwned: false, publication: "not-published", cleanup: "preserved", closeFailed: false,
|
|
191
|
+
};
|
|
192
|
+
async function close(owned) {
|
|
193
|
+
// Final creation consumes its pin before close can release and recycle it.
|
|
194
|
+
// Legacy temporary handoff retains its historical FileHandle close retry.
|
|
195
|
+
if (created)
|
|
196
|
+
owners.delete(owned);
|
|
197
|
+
try {
|
|
198
|
+
await owned.close();
|
|
199
|
+
owners.delete(owned);
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
state.closeFailed = true;
|
|
203
|
+
throw error;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
184
206
|
try {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
207
|
+
assertInitialSource(identity);
|
|
208
|
+
if (!handle) {
|
|
209
|
+
handle = await openProducerSource({ ...params, readWrite: "readWrite" in params && params.readWrite }, identity);
|
|
210
|
+
owners.add(handle);
|
|
211
|
+
}
|
|
212
|
+
inspectHandoff(params, handle, identity, state, 1n);
|
|
213
|
+
if (created?.verifyDescriptor)
|
|
214
|
+
await created.verifyDescriptor(handle.fd, params.sourcePath, 1);
|
|
215
|
+
if (!created) {
|
|
216
|
+
unregister = registerTempPathForExit(params.targetPath, {
|
|
217
|
+
cleanupSync: () => removeSiblingIfOwned({
|
|
218
|
+
assertTargetParent: params.assertTargetParent, identity, state, targetPath: params.targetPath,
|
|
219
|
+
}),
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
assertSynchronousCallbackResult(created?.assertBeforeMutation?.(), "assertBeforeMutation");
|
|
223
|
+
inspectHandoff(params, handle, identity, state, 1n);
|
|
224
|
+
state.publication = "indeterminate";
|
|
197
225
|
try {
|
|
198
226
|
fsSync.linkSync(params.sourcePath, params.targetPath);
|
|
199
227
|
}
|
|
200
228
|
catch (error) {
|
|
201
|
-
|
|
229
|
+
const normalized = normalizeLinkError(error);
|
|
230
|
+
if (normalized instanceof FsSafeError &&
|
|
231
|
+
(normalized.code === "already-exists" || normalized.code === "helper-unavailable")) {
|
|
232
|
+
state.publication = "not-published";
|
|
233
|
+
}
|
|
234
|
+
throw normalized;
|
|
202
235
|
}
|
|
203
|
-
state.
|
|
204
|
-
|
|
236
|
+
state.publication = "published";
|
|
237
|
+
state.siblingOwned = !created;
|
|
238
|
+
try {
|
|
239
|
+
assertSynchronousCallbackResult(created?.onPublished?.(), "onPublished");
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
failures.push(error);
|
|
243
|
+
}
|
|
244
|
+
inspectHandoff(params, handle, identity, state, 2n);
|
|
205
245
|
if (process.platform === "win32") {
|
|
206
246
|
// Legacy Windows unlink retains a delete-pending name until handles
|
|
207
247
|
// opened through that name close. Transfer the pin before retiring it.
|
|
208
|
-
|
|
209
|
-
|
|
248
|
+
const sibling = created
|
|
249
|
+
? await fs.open(params.targetPath, historicalOpenFlags(true))
|
|
250
|
+
: await openProducerSource({ ...params, sourcePath: params.targetPath,
|
|
251
|
+
readWrite: "readWrite" in params && params.readWrite }, identity, 2n);
|
|
252
|
+
owners.add(sibling);
|
|
253
|
+
inspectHandoff(params, sibling, identity, state, 2n);
|
|
254
|
+
if (created?.verifyDescriptor)
|
|
255
|
+
await created.verifyDescriptor(sibling.fd, params.targetPath, 2);
|
|
256
|
+
inspectHandoff(params, sibling, identity, state, 2n);
|
|
210
257
|
inspectSourceDescriptor(handle, identity, 2n);
|
|
211
|
-
await
|
|
212
|
-
handle =
|
|
213
|
-
siblingHandle = undefined;
|
|
258
|
+
await close(handle);
|
|
259
|
+
handle = sibling;
|
|
214
260
|
// The old handle's close yielded; both names must still be ours.
|
|
215
|
-
|
|
261
|
+
inspectHandoff(params, handle, identity, state, 2n);
|
|
216
262
|
}
|
|
217
|
-
|
|
263
|
+
if (created?.verifyDescriptor)
|
|
264
|
+
await created.verifyDescriptor(handle.fd, process.platform === "win32" ? params.targetPath : params.sourcePath, 2);
|
|
265
|
+
assertSynchronousCallbackResult(created?.assertBeforeMutation?.(), "assertBeforeMutation");
|
|
266
|
+
inspectHandoff(params, handle, identity, state, 2n);
|
|
267
|
+
state.cleanup = "failed";
|
|
218
268
|
fsSync.unlinkSync(params.sourcePath);
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
269
|
+
state.cleanup = "removed";
|
|
270
|
+
if (created?.verifyDescriptor)
|
|
271
|
+
await created.verifyDescriptor(handle.fd, params.targetPath, 1);
|
|
272
|
+
const { opened, named } = inspectHandoff(params, handle, identity, state, 1n);
|
|
222
273
|
const originalMode = identity.mode & 511n;
|
|
223
|
-
if (process.platform === "win32" && (originalMode & 128n) === 0n &&
|
|
224
|
-
((opened.mode & 511n) !== originalMode || (
|
|
274
|
+
if (!created && process.platform === "win32" && (originalMode & 128n) === 0n &&
|
|
275
|
+
((opened.mode & 511n) !== originalMode || (named.mode & 511n) !== originalMode)) {
|
|
225
276
|
// Legacy unlink clears the shared read-only attribute. Repair only the
|
|
226
277
|
// admitted sibling inode, without reopening or chmodding its pathname.
|
|
227
278
|
assertParents(params);
|
|
228
279
|
fsSync.fchmodSync(handle.fd, Number(originalMode));
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
const restoredSibling = inspectLinkedFile(() => fsSync.lstatSync(params.targetPath, { bigint: true }), identity, 1n, "isolated producer sibling");
|
|
232
|
-
if ((restored.mode & 511n) !== originalMode || (restoredSibling.mode & 511n) !== originalMode) {
|
|
280
|
+
const restored = inspectHandoff(params, handle, identity, state, 1n);
|
|
281
|
+
if ((restored.opened.mode & 511n) !== originalMode || (restored.named.mode & 511n) !== originalMode) {
|
|
233
282
|
throw pathMismatch("isolated producer read-only mode could not be restored");
|
|
234
283
|
}
|
|
235
284
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
285
|
+
if (!created) {
|
|
286
|
+
const registered = unregister;
|
|
287
|
+
const release = (() => {
|
|
288
|
+
state.siblingOwned = false;
|
|
289
|
+
registered();
|
|
290
|
+
});
|
|
291
|
+
release.setIdentity = registered.setIdentity;
|
|
292
|
+
return { handle, identity, unregister: release };
|
|
293
|
+
}
|
|
243
294
|
}
|
|
244
295
|
catch (error) {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
});
|
|
254
|
-
unregister();
|
|
255
|
-
}
|
|
256
|
-
catch (cleanupError) {
|
|
257
|
-
settlement.push(cleanupError);
|
|
258
|
-
}
|
|
296
|
+
failures.push(error);
|
|
297
|
+
}
|
|
298
|
+
if (failures.length === 0)
|
|
299
|
+
return handle;
|
|
300
|
+
if (unregister) {
|
|
301
|
+
try {
|
|
302
|
+
removeSiblingIfOwned({ assertTargetParent: params.assertTargetParent, identity, state, targetPath: params.targetPath });
|
|
303
|
+
unregister();
|
|
259
304
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
305
|
+
catch (error) {
|
|
306
|
+
failures.push(error);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
for (const owned of [...owners].reverse()) {
|
|
310
|
+
try {
|
|
311
|
+
await close(owned);
|
|
312
|
+
}
|
|
313
|
+
catch (error) {
|
|
314
|
+
failures.push(error);
|
|
269
315
|
}
|
|
270
|
-
throw combinedFailure(error, settlement);
|
|
271
316
|
}
|
|
317
|
+
const primary = failures[0];
|
|
318
|
+
const cause = combinedFailure(primary, failures.slice(1));
|
|
319
|
+
if (!created)
|
|
320
|
+
throw cause;
|
|
321
|
+
throw new FsSafeError(state.closeFailed || failures.length > 1 ? "helper-failed" : primary instanceof FsSafeError ? primary.code : "helper-failed", "created file publication failed", {
|
|
322
|
+
cause,
|
|
323
|
+
details: {
|
|
324
|
+
publication: { status: state.publication }, cleanup: state.cleanup,
|
|
325
|
+
resources: state.closeFailed ? "close-failed" : "closed",
|
|
326
|
+
path: params.targetPath, dev: identity.dev, ino: identity.ino,
|
|
327
|
+
},
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
export function handoffPrivateProducerFile(params) {
|
|
331
|
+
return handoffFile(params);
|
|
332
|
+
}
|
|
333
|
+
export function handoffCreatedFile(params) {
|
|
334
|
+
return handoffFile(params);
|
|
272
335
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type BigIntStats } from "node:fs";
|
|
2
|
-
import type
|
|
2
|
+
import { type AnyAsyncDirectoryGuard } from "./directory-guard.js";
|
|
3
3
|
import type { PublishedWriteIdentity } from "./pinned-write.js";
|
|
4
4
|
export declare function publishCopyStage(params: {
|
|
5
5
|
temporaryPath: string;
|
|
@@ -8,6 +8,7 @@ export declare function publishCopyStage(params: {
|
|
|
8
8
|
identity: BigIntStats;
|
|
9
9
|
parentGuard: AnyAsyncDirectoryGuard;
|
|
10
10
|
assertBeforeMutation?: () => void;
|
|
11
|
+
onPublicationAttempt?: () => void;
|
|
11
12
|
onPublished?: (identity: PublishedWriteIdentity) => void;
|
|
12
13
|
}): void;
|
|
13
14
|
//# sourceMappingURL=publish-copy-stage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish-copy-stage.d.ts","sourceRoot":"","sources":["../src/publish-copy-stage.ts"],"names":[],"mappings":"AAAA,OAAW,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAE/C,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"publish-copy-stage.d.ts","sourceRoot":"","sources":["../src/publish-copy-stage.ts"],"names":[],"mappings":"AAAA,OAAW,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAE/C,OAAO,EAA4B,KAAK,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAG7F,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAIhE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE;IACvC,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,WAAW,CAAC;IACtB,WAAW,EAAE,sBAAsB,CAAC;IACpC,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;IAClC,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;IAClC,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,sBAAsB,KAAK,IAAI,CAAC;CAC1D,GAAG,IAAI,CA4CP"}
|
|
@@ -1,19 +1,28 @@
|
|
|
1
1
|
import fs, {} from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { assertSyncDirectoryGuard } from "./directory-guard.js";
|
|
3
4
|
import { FsSafeError } from "./errors.js";
|
|
4
5
|
import { sameFileIdentityForCleanup } from "./file-identity.js";
|
|
5
6
|
// Node has no portable no-replace rename. Link only our completed private stage,
|
|
6
7
|
// then unlink it in the same JS turn so local readers never observe two names.
|
|
7
8
|
export function publishCopyStage(params) {
|
|
8
9
|
const { identity, temporaryPath, targetPath } = params;
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
!
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
const assertCurrent = () => {
|
|
11
|
+
assertSyncDirectoryGuard(params.parentGuard);
|
|
12
|
+
const staged = fs.lstatSync(temporaryPath, { bigint: true });
|
|
13
|
+
const opened = fs.fstatSync(params.fd, { bigint: true });
|
|
14
|
+
if (!staged.isFile() || staged.isSymbolicLink() || staged.nlink !== 1n ||
|
|
15
|
+
!sameFileIdentityForCleanup(staged, identity) ||
|
|
16
|
+
!sameFileIdentityForCleanup(opened, identity)) {
|
|
17
|
+
throw new FsSafeError("path-mismatch", "exclusive copy stage changed before publication");
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
assertCurrent();
|
|
16
21
|
params.assertBeforeMutation?.();
|
|
22
|
+
// Caller authority checks can synchronously replace a parent or staged entry.
|
|
23
|
+
if (params.assertBeforeMutation)
|
|
24
|
+
assertCurrent();
|
|
25
|
+
params.onPublicationAttempt?.();
|
|
17
26
|
fs.linkSync(temporaryPath, targetPath);
|
|
18
27
|
let observerRejected = false;
|
|
19
28
|
let observerError;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish-file.d.ts","sourceRoot":"","sources":["../src/publish-file.ts"],"names":[],"mappings":"AACA,OAAe,EAAoB,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAG/D,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EAC1B,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"publish-file.d.ts","sourceRoot":"","sources":["../src/publish-file.ts"],"names":[],"mappings":"AACA,OAAe,EAAoB,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAG/D,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EAC1B,MAAM,2BAA2B,CAAC;AAInC,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,oBAAoB,CAAC;AAK5B,OAAO,EAML,KAAK,qCAAqC,EAC3C,MAAM,2BAA2B,CAAC;AAKnC,YAAY,EACV,2BAA2B,EAC3B,wCAAwC,EACxC,kCAAkC,EAClC,gCAAgC,EAChC,qCAAqC,GACtC,MAAM,2BAA2B,CAAC;AAEnC,MAAM,MAAM,4BAA4B,GAAG,cAAc,GAAG,eAAe,GAAG,kBAAkB,CAAC;AAEjG,MAAM,MAAM,0BAA0B,GAAG;IACvC,MAAM,EAAE,UAAU,GAAG,gBAAgB,GAAG,kBAAkB,CAAC;IAC3D,QAAQ,EAAE,KAAK,CAAC;IAChB,aAAa,EAAE,oBAAoB,CAAC;CACrC,CAAC;AAIF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE/D;AA0ND,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IACjD,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,sBAAsB,CAAC,EAAE,gBAAgB,CAAC;IAC1C,QAAQ,EAAE,4BAA4B,CAAC;IACvC,aAAa,CAAC,EAAE,qCAAqC,CAAC;IACtD,aAAa,CAAC,EAAE,gBAAgB,CAAC;CAClC,GAAG,OAAO,CAAC,0BAA0B,CAAC,CA4NtC"}
|
package/dist/publish-file.js
CHANGED
|
@@ -4,6 +4,7 @@ import fs, {} from "node:fs/promises";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { pinDirectory, } from "./directory-durability.js";
|
|
6
6
|
import { FsSafeError } from "./errors.js";
|
|
7
|
+
import { ownDirectoryReceipt } from "./directory-receipt.js";
|
|
7
8
|
import { hashFileHandle } from "./file-hash.js";
|
|
8
9
|
import { sameFileIdentity, sameFileIdentityForCleanup, } from "./file-identity.js";
|
|
9
10
|
import { syncFileBestEffortSync } from "./file-sync.js";
|
|
@@ -183,8 +184,7 @@ export async function publishFileExclusive(params) {
|
|
|
183
184
|
const targetPathInput = admitStandalonePublicationPath(params.targetPath, "publication target uses a Windows filesystem namespace alias");
|
|
184
185
|
const parentReceiptInput = params.parentReceipt;
|
|
185
186
|
const parentReceipt = parentReceiptInput
|
|
186
|
-
?
|
|
187
|
-
identity: parentReceiptInput.identity }
|
|
187
|
+
? ownDirectoryReceipt(parentReceiptInput)
|
|
188
188
|
: undefined;
|
|
189
189
|
if (parentReceipt) {
|
|
190
190
|
assertNoWindowsPathAlias(parentReceipt.path, "filesystem", "publication parent uses a Windows filesystem namespace alias");
|
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
import syncFs, { type BigIntStats } from "node:fs";
|
|
2
2
|
import fs, { type FileHandle } from "node:fs/promises";
|
|
3
|
-
import { type AnyAsyncDirectoryGuard } from "./directory-guard.js";
|
|
4
3
|
type AsyncOwnerFileSystem = Pick<typeof fs, "lstat" | "open" | "unlink">;
|
|
5
4
|
type SyncOwnerFileSystem = Pick<typeof syncFs, "closeSync" | "fstatSync" | "lstatSync" | "openSync" | "readFileSync" | "unlinkSync">;
|
|
6
5
|
export type AtomicTempFailure = Readonly<{
|
|
7
6
|
error: unknown;
|
|
8
7
|
}>;
|
|
9
8
|
export declare function removePathIfIdentityUnchanged(targetPath: string, identity: Pick<BigIntStats, "dev" | "ino">): Promise<void>;
|
|
10
|
-
export declare function cleanupPinnedFilePath(params: {
|
|
11
|
-
pathname: string;
|
|
12
|
-
handle: FileHandle;
|
|
13
|
-
identity?: BigIntStats;
|
|
14
|
-
parentGuard: AnyAsyncDirectoryGuard;
|
|
15
|
-
}): Promise<void>;
|
|
16
9
|
export declare class AsyncAtomicTempOwner {
|
|
17
10
|
#private;
|
|
18
11
|
readonly pathname: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replace-file-temp-owner.d.ts","sourceRoot":"","sources":["../src/replace-file-temp-owner.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,EAAE,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,EAAE,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"replace-file-temp-owner.d.ts","sourceRoot":"","sources":["../src/replace-file-temp-owner.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,EAAE,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,EAAE,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAWvD,KAAK,oBAAoB,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC,CAAC;AACzE,KAAK,mBAAmB,GAAG,IAAI,CAC7B,OAAO,MAAM,EACb,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,UAAU,GAAG,cAAc,GAAG,YAAY,CACrF,CAAC;AAIF,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAmB7D,wBAAsB,6BAA6B,CACjD,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,IAAI,CAAC,WAAW,EAAE,KAAK,GAAG,KAAK,CAAC,GACzC,OAAO,CAAC,IAAI,CAAC,CAOf;AAkFD,qBAAa,oBAAoB;;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAM1B,YAAY,QAAQ,EAAE,MAAM,EAG3B;IAED,KAAK,IAAI,IAAI,CAEZ;IAED,QAAQ,CAAC,UAAU,aAAc,WAAW,KAAG,IAAI,CAGjD;IAEF,KAAK,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,UAAU,CAAC;QAAC,QAAQ,EAAE,WAAW,CAAA;KAAE,GAAG,IAAI,CAG/D;IAED,IAAI,QAAQ,IAAI,WAAW,CAG1B;IAEK,aAAa,CAAC,QAAQ,EAAE,oBAAoB,EAAE,QAAQ,SAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoB3F;IAEK,eAAe,CACnB,QAAQ,EAAE,oBAAoB,EAC9B,QAAQ,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CA8Cf;IAED,WAAW,IAAI,IAAI,CAGlB;IAEK,MAAM,CAAC,MAAM,EAAE;QACnB,QAAQ,EAAE,oBAAoB,CAAC;QAC/B,eAAe,CAAC,EAAE,iBAAiB,CAAC;QACpC,mBAAmB,EAAE,OAAO,CAAC;KAC9B,GAAG,OAAO,CAAC,IAAI,CAAC,CAqChB;CACF;AAED,qBAAa,mBAAmB;;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAM1B,YAAY,QAAQ,EAAE,MAAM,EAG3B;IAED,KAAK,IAAI,IAAI,CAEZ;IAED,QAAQ,CAAC,UAAU,aAAc,WAAW,KAAG,IAAI,CAGjD;IAEF,KAAK,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,WAAW,CAAA;KAAE,GAAG,IAAI,CAGvD;IAED,IAAI,QAAQ,IAAI,WAAW,CAG1B;IAED,aAAa,CAAC,QAAQ,EAAE,mBAAmB,EAAE,QAAQ,SAAgB,GAAG,IAAI,CAkB3E;IAED,eAAe,CACb,QAAQ,EAAE,mBAAmB,EAC7B,QAAQ,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,MAAM,GACpB,IAAI,CAkDN;IAED,WAAW,IAAI,IAAI,CAGlB;IAED,MAAM,CAAC,MAAM,EAAE;QACb,QAAQ,EAAE,mBAAmB,CAAC;QAC9B,eAAe,CAAC,EAAE,iBAAiB,CAAC;QACpC,mBAAmB,EAAE,OAAO,CAAC;KAC9B,GAAG,IAAI,CAuCP;CACF"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import syncFs, {} from "node:fs";
|
|
2
2
|
import fs, {} from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { createAsyncDirectoryGuard } from "./directory-guard.js";
|
|
5
|
+
import { hasErrorCode, removeOwnedPath } from "./file-cleanup.js";
|
|
5
6
|
import { resolveReadOpenFlags } from "./read-open-flags.js";
|
|
6
7
|
import { FsSafeError } from "./errors.js";
|
|
7
8
|
import { sameFileIdentityForCleanup, sha256Hex } from "./file-identity.js";
|
|
@@ -9,17 +10,6 @@ import { withAsyncDirectoryGuards } from "./guarded-mutation.js";
|
|
|
9
10
|
import { inspectFileIdentity, inspectFileIdentitySync } from "./strict-file-identity.js";
|
|
10
11
|
import { registerTempPathForExit } from "./temp-cleanup.js";
|
|
11
12
|
const PUBLISHED_READ_FLAGS = resolveReadOpenFlags();
|
|
12
|
-
function hasErrorCode(error, expected) {
|
|
13
|
-
if ((typeof error !== "object" || error === null) && typeof error !== "function") {
|
|
14
|
-
return false;
|
|
15
|
-
}
|
|
16
|
-
try {
|
|
17
|
-
return Reflect.get(error, "code") === expected;
|
|
18
|
-
}
|
|
19
|
-
catch {
|
|
20
|
-
return false;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
13
|
function describeFailure(error) {
|
|
24
14
|
try {
|
|
25
15
|
return String(error);
|
|
@@ -68,58 +58,17 @@ function cleanupFailure(originalFailure, cleanupError) {
|
|
|
68
58
|
return isErrorValue(cleanupError) ? cleanupError : new Error(describeFailure(cleanupError));
|
|
69
59
|
}
|
|
70
60
|
async function cleanupOwnedPath(params) {
|
|
71
|
-
if (!params.identity)
|
|
72
|
-
return true;
|
|
73
61
|
try {
|
|
74
|
-
|
|
75
|
-
? syncFs.lstatSync(params.pathname, { bigint: true })
|
|
76
|
-
: await params.fsModule.lstat(params.pathname, { bigint: true });
|
|
77
|
-
if (current.isSymbolicLink() ||
|
|
78
|
-
!current.isFile() ||
|
|
79
|
-
current.nlink !== 1n ||
|
|
80
|
-
!sameFileIdentityForCleanup(current, params.identity)) {
|
|
81
|
-
return true;
|
|
82
|
-
}
|
|
83
|
-
await params.fsModule.unlink(params.pathname);
|
|
62
|
+
await removeOwnedPath(params);
|
|
84
63
|
return true;
|
|
85
64
|
}
|
|
86
65
|
catch (cleanupError) {
|
|
87
|
-
if (hasErrorCode(cleanupError, "ENOENT"))
|
|
88
|
-
return true;
|
|
89
66
|
if (params.throwOnCleanupError) {
|
|
90
67
|
throw cleanupFailure(params.originalFailure, cleanupError);
|
|
91
68
|
}
|
|
92
69
|
return false;
|
|
93
70
|
}
|
|
94
71
|
}
|
|
95
|
-
// Borrowed handle: the caller retains it until this best-effort cleanup finishes.
|
|
96
|
-
export async function cleanupPinnedFilePath(params) {
|
|
97
|
-
if (!params.identity)
|
|
98
|
-
return;
|
|
99
|
-
try {
|
|
100
|
-
const guard = params.parentGuard;
|
|
101
|
-
if ([guard.stat.dev, guard.stat.ino].some((value) => typeof value === "number" && !Number.isSafeInteger(value)))
|
|
102
|
-
return;
|
|
103
|
-
await assertAsyncDirectoryGuard(guard);
|
|
104
|
-
const parent = syncFs.lstatSync(guard.dir, { bigint: true });
|
|
105
|
-
if (parent.isSymbolicLink() || !parent.isDirectory() ||
|
|
106
|
-
!sameFileIdentityForCleanup(parent, guard.stat))
|
|
107
|
-
return;
|
|
108
|
-
const opened = syncFs.fstatSync(params.handle.fd, { bigint: true });
|
|
109
|
-
if (!opened.isFile() || opened.nlink !== 1n ||
|
|
110
|
-
!sameFileIdentityForCleanup(opened, params.identity))
|
|
111
|
-
return;
|
|
112
|
-
await cleanupOwnedPath({
|
|
113
|
-
fsModule: fs,
|
|
114
|
-
pathname: params.pathname,
|
|
115
|
-
identity: params.identity,
|
|
116
|
-
throwOnCleanupError: false,
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
catch {
|
|
120
|
-
// Unverifiable authority must preserve the path and the original write failure.
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
72
|
function cleanupOwnedPathSync(params) {
|
|
124
73
|
if (!params.identity)
|
|
125
74
|
return true;
|
|
@@ -4,9 +4,10 @@ declare const exclusiveSidecarCreate: unique symbol;
|
|
|
4
4
|
export declare const sidecarExclusiveCreate: Readonly<{
|
|
5
5
|
[exclusiveSidecarCreate]: true;
|
|
6
6
|
}>;
|
|
7
|
-
export type RootWriteParams = RootWriteOptions & RootCreateStreamOptions & {
|
|
7
|
+
export type RootWriteParams = RootWriteOptions & RootCreateOptions & RootCreateStreamOptions & {
|
|
8
8
|
relativePath: string;
|
|
9
9
|
data: string | Buffer | AsyncIterable<Uint8Array>;
|
|
10
|
+
strictFileSync?: boolean;
|
|
10
11
|
[exclusiveSidecarCreate]?: true;
|
|
11
12
|
};
|
|
12
13
|
export declare function rethrowCreateInputError(error: unknown): never;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root-create-input.d.ts","sourceRoot":"","sources":["../src/root-create-input.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAItG,QAAA,MAAM,sBAAsB,eAAmC,CAAC;AAChE,eAAO,MAAM,sBAAsB;;EAA6D,CAAC;AAEjG,MAAM,MAAM,eAAe,GAAG,gBAAgB,GAAG,uBAAuB,GAAG;
|
|
1
|
+
{"version":3,"file":"root-create-input.d.ts","sourceRoot":"","sources":["../src/root-create-input.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAItG,QAAA,MAAM,sBAAsB,eAAmC,CAAC;AAChE,eAAO,MAAM,sBAAsB;;EAA6D,CAAC;AAEjG,MAAM,MAAM,eAAe,GAAG,gBAAgB,GAAG,iBAAiB,GAAG,uBAAuB,GAAG;IAC7F,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;IAClD,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,CAAC,sBAAsB,CAAC,CAAC,EAAE,IAAI,CAAC;CACjC,CAAC;AAQF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAG7D;AAED,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,eAAe,CAAC,MAAM,CAAC,EAC7B,OAAO,EAAE,iBAAiB,GAAG,uBAAuB,EACpD,eAAe,CAAC,EAAE,MAAM,GACvB,iBAAiB,GAAG,uBAAuB,CAkB7C;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,eAAe,GAAG,gBAAgB,CA8CxE"}
|
|
@@ -20,24 +20,33 @@ export function rethrowCreateInputError(error) {
|
|
|
20
20
|
export function createInputOptions(data, options, defaultMaxBytes) {
|
|
21
21
|
if (typeof data === "string" || Buffer.isBuffer(data))
|
|
22
22
|
return options;
|
|
23
|
-
options
|
|
23
|
+
const { signal } = options;
|
|
24
|
+
signal?.throwIfAborted();
|
|
24
25
|
if (options.encoding !== undefined || options.renameIdentity !== undefined) {
|
|
25
26
|
throw new TypeError("streamed create does not accept encoding or renameIdentity");
|
|
26
27
|
}
|
|
27
28
|
const maxBytes = normalizeMaxBytes(options.maxBytes, { defaultValue: defaultMaxBytes });
|
|
29
|
+
const { assertBeforeMutation } = options;
|
|
28
30
|
return {
|
|
29
31
|
...options,
|
|
30
32
|
maxBytes,
|
|
33
|
+
signal,
|
|
31
34
|
assertBeforeMutation: () => {
|
|
32
|
-
|
|
33
|
-
return
|
|
35
|
+
signal?.throwIfAborted();
|
|
36
|
+
return assertBeforeMutation == null ? undefined : Reflect.apply(assertBeforeMutation, options, []);
|
|
34
37
|
},
|
|
35
38
|
};
|
|
36
39
|
}
|
|
37
40
|
export function rootWriteInput(params) {
|
|
41
|
+
if (params.atomic !== undefined && typeof params.atomic !== "boolean") {
|
|
42
|
+
throw new TypeError("atomic must be a boolean");
|
|
43
|
+
}
|
|
38
44
|
const data = params.data;
|
|
39
45
|
if (typeof data === "string" || Buffer.isBuffer(data)) {
|
|
40
|
-
return {
|
|
46
|
+
return {
|
|
47
|
+
kind: "buffer", data, encoding: params.encoding,
|
|
48
|
+
stageBeforePublish: params[exclusiveSidecarCreate] ? false : params.atomic === true ? true : undefined,
|
|
49
|
+
};
|
|
41
50
|
}
|
|
42
51
|
return {
|
|
43
52
|
kind: "stream",
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { PinnedWriteMutationAdmission } from "./pinned-write.js";
|
|
2
|
-
import type
|
|
2
|
+
import { type RootContext } from "./root-context.js";
|
|
3
3
|
/**
|
|
4
4
|
* Complete the common Root.mkdir case with one exact existing parent. This is
|
|
5
5
|
* optional evidence: every uncertain probe returns to the ordered root walk.
|
|
6
6
|
*/
|
|
7
7
|
export declare function tryMkdirAtExactParent(root: RootContext, targetPath: string, mutationAdmission: PinnedWriteMutationAdmission): Promise<boolean>;
|
|
8
|
-
export declare function prepareRootWriteTarget(root: RootContext, targetPath: string, assertBeforeMutation?: () => void, mutationAdmission?: PinnedWriteMutationAdmission): Promise<string>;
|
|
8
|
+
export declare function prepareRootWriteTarget(root: RootContext, targetPath: string, assertBeforeMutation?: () => void, mutationAdmission?: PinnedWriteMutationAdmission, privateMode?: boolean): Promise<string>;
|
|
9
9
|
export declare function mkdirPathFallback(root: RootContext, resolved: {
|
|
10
10
|
rootReal: string;
|
|
11
11
|
resolved: string;
|
|
12
|
-
}, assertBeforeMutation?: () => void, rejectSymlinks?: boolean, mutationAdmission?: PinnedWriteMutationAdmission): Promise<void>;
|
|
12
|
+
}, assertBeforeMutation?: () => void, rejectSymlinks?: boolean, mutationAdmission?: PinnedWriteMutationAdmission, privateMode?: boolean): Promise<void>;
|
|
13
13
|
//# sourceMappingURL=root-directory-creation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root-directory-creation.d.ts","sourceRoot":"","sources":["../src/root-directory-creation.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"root-directory-creation.d.ts","sourceRoot":"","sources":["../src/root-directory-creation.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;AAEtE,OAAO,EAA6B,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAuDhF;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,WAAW,EACjB,UAAU,EAAE,MAAM,EAClB,iBAAiB,EAAE,4BAA4B,GAC9C,OAAO,CAAC,OAAO,CAAC,CAoGlB;AAED,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,WAAW,EACjB,UAAU,EAAE,MAAM,EAClB,oBAAoB,CAAC,EAAE,MAAM,IAAI,EACjC,iBAAiB,CAAC,EAAE,4BAA4B,EAChD,WAAW,UAAQ,GAClB,OAAO,CAAC,MAAM,CAAC,CA+BjB;AAED,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,WAAW,EACjB,QAAQ,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,EAChD,oBAAoB,CAAC,EAAE,MAAM,IAAI,EACjC,cAAc,UAAQ,EACtB,iBAAiB,CAAC,EAAE,4BAA4B,EAChD,WAAW,UAAQ,GAClB,OAAO,CAAC,IAAI,CAAC,CAiCf"}
|