@poe-platform/safe-fs 0.1.727 → 0.1.729
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/README.md +15 -8
- package/dist/safe-fs/contracts/errors.js +8 -1
- package/dist/safe-fs/contracts/filesystem.d.ts +68 -2
- package/dist/safe-fs/contracts/io.js +210 -28
- package/dist/safe-fs/contracts/virtual-path.d.ts +3 -1
- package/dist/safe-fs/contracts/virtual-path.js +20 -1
- package/dist/safe-fs/core.d.ts +1 -0
- package/dist/safe-fs/core.js +1 -0
- package/dist/safe-fs/fs/capabilities.d.ts +1 -1
- package/dist/safe-fs/fs/capabilities.js +59 -21
- package/dist/safe-fs/fs/conditional-chmod.d.ts +7 -0
- package/dist/safe-fs/fs/conditional-chmod.js +19 -0
- package/dist/safe-fs/fs/descriptor.js +51 -25
- package/dist/safe-fs/fs/devices/index.d.ts +7 -2
- package/dist/safe-fs/fs/devices/index.js +210 -29
- package/dist/safe-fs/fs/devices/path.d.ts +3 -1
- package/dist/safe-fs/fs/devices/path.js +70 -12
- package/dist/safe-fs/fs/memory/index.d.ts +70 -48
- package/dist/safe-fs/fs/memory/index.js +1595 -244
- package/dist/safe-fs/fs/memory/ledger.d.ts +8 -1
- package/dist/safe-fs/fs/memory/ledger.js +46 -6
- package/dist/safe-fs/fs/memory/missing-target.js +21 -1
- package/dist/safe-fs/fs/mount/index.d.ts +11 -3
- package/dist/safe-fs/fs/mount/index.js +326 -15
- package/dist/safe-fs/fs/object-publication/index.js +79 -3
- package/dist/safe-fs/fs/overlay/index.d.ts +2 -2
- package/dist/safe-fs/fs/overlay/index.js +27 -5
- package/dist/safe-fs/fs/overlay/memory-publication.d.ts +2 -1
- package/dist/safe-fs/fs/overlay/memory-publication.js +39 -2
- package/dist/safe-fs/fs/quota/index.js +5 -5
- package/dist/safe-fs/fs/readonly/index.d.ts +1 -0
- package/dist/safe-fs/fs/readonly/index.js +13 -0
- package/dist/safe-fs/fs/real/index.d.ts +6 -2
- package/dist/safe-fs/fs/real/index.js +78 -8
- package/dist/safe-fs/fs/s3/filesystem.d.ts +3 -0
- package/dist/safe-fs/fs/s3/filesystem.js +57 -25
- package/dist/safe-fs/fs/s3/http/transport.js +20 -3
- package/dist/safe-fs/fs/s3/mock.js +19 -2
- package/dist/safe-fs/fs/s3/namespace.js +8 -2
- package/dist/safe-fs/fs/s3/registry.js +2 -0
- package/dist/safe-fs/fs/scoped.d.ts +1 -0
- package/dist/safe-fs/fs/scoped.js +261 -74
- package/dist/safe-fs/fs/staging-ancestry.d.ts +8 -0
- package/dist/safe-fs/fs/staging-ancestry.js +115 -0
- package/dist/safe-fs/fs/staging-cleanup.d.ts +5 -0
- package/dist/safe-fs/fs/staging-cleanup.js +63 -0
- package/dist/safe-fs/fs/webdav/webdav.js +7 -5
- package/dist/safe-fs/platform/browser.d.ts +5 -0
- package/dist/safe-fs/platform/browser.js +17 -0
- package/dist/safe-fs/platform/node.d.ts +5 -0
- package/dist/safe-fs/platform/node.js +28 -0
- package/dist/safe-fs/platform/transport-budget.d.ts +7 -0
- package/dist/safe-fs/platform/transport-budget.js +4 -0
- package/dist/safe-fs/testing/object-io-metrics.d.ts +3 -0
- package/dist/safe-fs/testing/object-io-metrics.js +29 -0
- package/dist/safe-fs/testing/object-publication.d.ts +3 -1
- package/dist/safe-fs/testing/object-publication.js +2 -2
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { FsError } from "../contracts/errors.js";
|
|
1
|
+
import { FsError, toFsError } from "../contracts/errors.js";
|
|
2
2
|
import { finishCleanup } from "../contracts/cleanup.js";
|
|
3
|
+
import { inspectStagingBindings } from "./staging-ancestry.js";
|
|
3
4
|
export function retainedReadCapabilities(filesystem, capabilities = filesystem.capabilities) {
|
|
4
5
|
return typeof filesystem.openReadFile === "function" ? capabilities : { ...capabilities, retainedRead: false };
|
|
5
6
|
}
|
|
@@ -104,11 +105,12 @@ export function readOnlyCapabilities(capabilities) {
|
|
|
104
105
|
"symlinks", "streamingRead", "open", "retainedRead", "versionedDescriptors",
|
|
105
106
|
].filter(name => capabilities[name] !== undefined).map(name => [name, capabilities[name]]));
|
|
106
107
|
return Object.freeze({
|
|
107
|
-
...inspection, readOnly: true, write: false, append: false, exclusiveCreate: false,
|
|
108
|
+
...inspection, retainedStagingCleanup: false, readOnly: true, write: false, append: false, exclusiveCreate: false,
|
|
109
|
+
synchronousStagingResolution: false,
|
|
108
110
|
mkdir: false, recursiveMkdir: false, remove: false, removeDirectory: false, recursiveRemove: false,
|
|
109
111
|
rename: false, copy: false, exclusiveCopy: false, truncate: false, streamingAppend: false,
|
|
110
|
-
randomAccessWrite: false, hardlinks: false, permissions: false, timestamps: false,
|
|
111
|
-
descriptorWriteStream: false, atomicResize: false, retainedResize: false, atomicFileMutation: false, atomicEntryRemoval: false, atomicTreeRemoval: false, atomicFileStaging: false, atomicDirectoryMetadata: false, trustedOwnedStaging: false,
|
|
112
|
+
randomAccessWrite: false, hardlinks: false, permissions: false, conditionalChmod: false, timestamps: false,
|
|
113
|
+
descriptorWriteStream: false, atomicResize: false, retainedResize: false, atomicFileMutation: false, atomicEntryRemoval: false, atomicEntryRemovalReceipt: false, atomicTreeRemoval: false, atomicFileStaging: false, atomicDirectoryMetadata: false, trustedOwnedStaging: false,
|
|
112
114
|
atomicFilePublication: false, atomicRename: false, atomicRenameNoReplace: false, streamingWrite: false,
|
|
113
115
|
});
|
|
114
116
|
}
|
|
@@ -116,35 +118,71 @@ export function quotaCapabilities(capabilities) {
|
|
|
116
118
|
const streamingWrite = requireCapabilities(capabilities.write, capabilities.append, !capabilities.readOnly);
|
|
117
119
|
const streamingAppend = requireCapabilities(capabilities.append, !capabilities.readOnly);
|
|
118
120
|
const { streamingWrite: ignoredWrite, streamingAppend: ignoredAppend, ...rest } = capabilities;
|
|
119
|
-
return Object.freeze({ ...rest, atomicFilePublication: false, descriptorWriteStream: false, atomicResize: false, atomicFileMutation: false, atomicEntryRemoval: false, atomicFileStaging: false, atomicDirectoryMetadata: false, trustedOwnedStaging: false,
|
|
121
|
+
return Object.freeze({ ...rest, synchronousStagingResolution: false, retainedStagingCleanup: false, atomicStagingAncestry: false, synchronousDirectoryValidation: false, guardedStagingPublication: false, atomicFilePublication: false, descriptorWriteStream: false, atomicResize: false, atomicFileMutation: false, atomicEntryRemoval: false, atomicEntryRemovalReceipt: false, atomicFileStaging: false, atomicDirectoryMetadata: false, trustedOwnedStaging: false,
|
|
120
122
|
...(streamingWrite === undefined ? {} : { streamingWrite }),
|
|
121
123
|
...(streamingAppend === undefined ? {} : { streamingAppend }),
|
|
122
124
|
});
|
|
123
125
|
}
|
|
126
|
+
const TRUSTED_OWNED_STAGING_METHODS = [
|
|
127
|
+
"createStagedFile", "publishStagedFile", "removeStagedFile", "writeFileConditional", "removeFileConditional", "prepareDirectory",
|
|
128
|
+
];
|
|
124
129
|
export function ownedMutationCapabilities(filesystem, capabilities = filesystem.capabilities) {
|
|
125
|
-
|
|
130
|
+
let unavailable;
|
|
126
131
|
if (capabilities.atomicFilePublication === true && (capabilities.readOnly === true || typeof filesystem.publishFileConditional !== "function"))
|
|
127
|
-
unavailable.atomicFilePublication = false;
|
|
132
|
+
(unavailable ??= {}).atomicFilePublication = false;
|
|
128
133
|
if (capabilities.atomicEntryRemoval === true && (capabilities.readOnly === true || typeof filesystem.removeEntryConditional !== "function"))
|
|
129
|
-
unavailable.atomicEntryRemoval = false;
|
|
134
|
+
(unavailable ??= {}).atomicEntryRemoval = false;
|
|
135
|
+
if (capabilities.atomicEntryRemovalReceipt === true && (capabilities.atomicEntryRemoval !== true || unavailable?.atomicEntryRemoval === false))
|
|
136
|
+
(unavailable ??= {}).atomicEntryRemovalReceipt = false;
|
|
130
137
|
if (capabilities.atomicTreeRemoval === true && (capabilities.readOnly === true || typeof filesystem.removeTreeConditional !== "function"))
|
|
131
|
-
unavailable.atomicTreeRemoval = false;
|
|
138
|
+
(unavailable ??= {}).atomicTreeRemoval = false;
|
|
132
139
|
if (capabilities.atomicFileMutation === true && (capabilities.readOnly === true || typeof filesystem.writeFileConditional !== "function" || typeof filesystem.removeFileConditional !== "function"))
|
|
133
|
-
unavailable.atomicFileMutation = false;
|
|
140
|
+
(unavailable ??= {}).atomicFileMutation = false;
|
|
134
141
|
if (capabilities.atomicFileStaging === true && (capabilities.readOnly === true
|
|
135
142
|
|| typeof filesystem.createStagedFile !== "function" || typeof filesystem.publishStagedFile !== "function" || typeof filesystem.removeStagedFile !== "function"))
|
|
136
|
-
unavailable.atomicFileStaging = false;
|
|
143
|
+
(unavailable ??= {}).atomicFileStaging = false;
|
|
144
|
+
if (capabilities.retainedStagingCleanup === true && (capabilities.atomicFileStaging !== true || unavailable?.atomicFileStaging === false))
|
|
145
|
+
(unavailable ??= {}).retainedStagingCleanup = false;
|
|
146
|
+
if (capabilities.atomicStagingAncestry === true && (capabilities.atomicFileStaging !== true || unavailable?.atomicFileStaging === false))
|
|
147
|
+
(unavailable ??= {}).atomicStagingAncestry = false;
|
|
148
|
+
if (capabilities.synchronousDirectoryValidation === true && typeof filesystem.prepareDirectoryAncestry !== "function")
|
|
149
|
+
(unavailable ??= {}).synchronousDirectoryValidation = false;
|
|
150
|
+
if (capabilities.synchronousStagingResolution === true && (capabilities.readOnly === true || typeof filesystem.prepareStagingResolution !== "function"))
|
|
151
|
+
(unavailable ??= {}).synchronousStagingResolution = false;
|
|
152
|
+
if (capabilities.guardedStagingPublication === true && (capabilities.atomicFileStaging !== true || unavailable?.atomicFileStaging === false))
|
|
153
|
+
(unavailable ??= {}).guardedStagingPublication = false;
|
|
137
154
|
if (capabilities.atomicDirectoryMetadata === true && (capabilities.readOnly === true || typeof filesystem.prepareDirectory !== "function"))
|
|
138
|
-
unavailable.atomicDirectoryMetadata = false;
|
|
139
|
-
if (capabilities.trustedOwnedStaging === true
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
155
|
+
(unavailable ??= {}).atomicDirectoryMetadata = false;
|
|
156
|
+
if (capabilities.trustedOwnedStaging === true) {
|
|
157
|
+
let missing = capabilities.readOnly === true;
|
|
158
|
+
if (!missing) {
|
|
159
|
+
for (let i = 0; i < TRUSTED_OWNED_STAGING_METHODS.length; i++) {
|
|
160
|
+
if (typeof filesystem[TRUSTED_OWNED_STAGING_METHODS[i]] !== "function") {
|
|
161
|
+
missing = true;
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (missing)
|
|
167
|
+
(unavailable ??= {}).trustedOwnedStaging = false;
|
|
168
|
+
}
|
|
169
|
+
return unavailable ? { ...capabilities, ...unavailable } : capabilities;
|
|
143
170
|
}
|
|
144
171
|
export async function requireOwnedMutation(filesystem, path, capability, options, create = false) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
172
|
+
try {
|
|
173
|
+
options.signal?.throwIfAborted();
|
|
174
|
+
const query = create ? { ...options, create: true } : options;
|
|
175
|
+
const capabilities = ownedMutationCapabilities(filesystem, await filesystem.capabilitiesFor?.(path, capability === "atomicStagingAncestry" ? { ...query, stagingAncestry: true } : query) ?? filesystem.capabilities);
|
|
176
|
+
options.signal?.throwIfAborted();
|
|
177
|
+
if (capabilities[capability] !== true && !(capabilities.trustedOwnedStaging === true && ["atomicFileStaging", "atomicFileMutation", "atomicDirectoryMetadata"].includes(capability)))
|
|
178
|
+
throw new FsError("ENOTSUP", { path, syscall: capability });
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
options.signal?.throwIfAborted();
|
|
182
|
+
if (capability === "atomicStagingAncestry" && "ancestors" in options && options.ancestors !== undefined
|
|
183
|
+
&& "destination" in options && ["ENOTSUP", "ENOENT", "ENOTDIR", "ELOOP"].includes(toFsError(error).code)) {
|
|
184
|
+
await inspectStagingBindings(entry => filesystem.lstat(entry, options), path, options);
|
|
185
|
+
}
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
150
188
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ChmodOptions, FileStagingEntry, FileStat } from "../contracts/filesystem.js";
|
|
2
|
+
export interface ConditionalChmodOptions extends ChmodOptions {
|
|
3
|
+
readonly parent: FileStat;
|
|
4
|
+
readonly expected: FileStat;
|
|
5
|
+
readonly ancestors: readonly FileStagingEntry[];
|
|
6
|
+
}
|
|
7
|
+
export declare function snapshotConditionalChmod(path: string, options: ChmodOptions): ConditionalChmodOptions | undefined;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { FsError } from "../contracts/errors.js";
|
|
2
|
+
import { dirname } from "../contracts/virtual-path.js";
|
|
3
|
+
import { snapshotDirectoryAncestry } from "./staging-ancestry.js";
|
|
4
|
+
export function snapshotConditionalChmod(path, options) {
|
|
5
|
+
const { signal, parent, expected, ancestors, commitGuard } = options;
|
|
6
|
+
signal?.throwIfAborted();
|
|
7
|
+
if (parent === undefined && expected === undefined && ancestors === undefined && commitGuard === undefined)
|
|
8
|
+
return undefined;
|
|
9
|
+
if (parent === undefined || expected === undefined || ancestors === undefined) {
|
|
10
|
+
throw new FsError("EINVAL", { syscall: "chmod", path, message: "complete conditional chmod receipt is required" });
|
|
11
|
+
}
|
|
12
|
+
if (commitGuard !== undefined && typeof commitGuard !== "function")
|
|
13
|
+
throw new FsError("EINVAL", { syscall: "chmod", path });
|
|
14
|
+
const entries = snapshotDirectoryAncestry(ancestors);
|
|
15
|
+
if (entries.at(-1)?.path !== dirname(path))
|
|
16
|
+
throw new FsError("EINVAL", { syscall: "chmod", path });
|
|
17
|
+
return { ...(signal === undefined ? {} : { signal }), parent: { ...parent }, expected: { ...expected }, ancestors: entries,
|
|
18
|
+
...(commitGuard === undefined ? {} : { commitGuard }) };
|
|
19
|
+
}
|
|
@@ -45,6 +45,37 @@ function integer(value, syscall, path) {
|
|
|
45
45
|
if (!Number.isSafeInteger(value) || value < 0)
|
|
46
46
|
throw new FsError("EINVAL", { syscall, path });
|
|
47
47
|
}
|
|
48
|
+
const OPEN_FILE_OPTION_KEYS = new Set(["access", "creation", "truncate", "append", "mode", "exactMode", "noFollow", "synchronization", "signal"]);
|
|
49
|
+
const managedCapabilitiesCache = new WeakMap();
|
|
50
|
+
function getManagedCapabilities(capabilities, access, append) {
|
|
51
|
+
let byKey = managedCapabilitiesCache.get(capabilities);
|
|
52
|
+
const key = `${access}:${append ? 1 : 0}`;
|
|
53
|
+
if (byKey) {
|
|
54
|
+
const cached = byKey.get(key);
|
|
55
|
+
if (cached)
|
|
56
|
+
return cached;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
byKey = new Map();
|
|
60
|
+
managedCapabilitiesCache.set(capabilities, byKey);
|
|
61
|
+
}
|
|
62
|
+
const positionedAppendWrite = capabilities.positionedAppendWrite === true && capabilities.positionedWrite && access !== "read";
|
|
63
|
+
const frozen = Object.freeze({
|
|
64
|
+
...(capabilities.noFollow === undefined ? {} : { noFollow: capabilities.noFollow }),
|
|
65
|
+
...(capabilities.publication === undefined ? {} : { publication: capabilities.publication }),
|
|
66
|
+
...(capabilities.position === undefined ? {} : { position: capabilities.position }),
|
|
67
|
+
...(capabilities.readObservation === undefined ? {} : { readObservation: capabilities.readObservation }),
|
|
68
|
+
...(capabilities.openTruncate === undefined ? {} : { openTruncate: capabilities.openTruncate }),
|
|
69
|
+
positionedRead: capabilities.positionedRead && access !== "write",
|
|
70
|
+
positionedWrite: capabilities.positionedWrite && access !== "read" && (!append || positionedAppendWrite),
|
|
71
|
+
...(capabilities.positionedAppendWrite === undefined ? {} : { positionedAppendWrite }),
|
|
72
|
+
...(capabilities.delegateZeroLengthWrite === undefined ? {} : { delegateZeroLengthWrite: capabilities.delegateZeroLengthWrite && access !== "read" }),
|
|
73
|
+
truncate: capabilities.truncate && access !== "read",
|
|
74
|
+
synchronization: capabilities.synchronization,
|
|
75
|
+
});
|
|
76
|
+
byKey.set(key, frozen);
|
|
77
|
+
return frozen;
|
|
78
|
+
}
|
|
48
79
|
class ManagedFileDescriptor {
|
|
49
80
|
capabilities;
|
|
50
81
|
#path;
|
|
@@ -62,26 +93,13 @@ class ManagedFileDescriptor {
|
|
|
62
93
|
const getPosition = capabilities.position === true ? backend.getPosition : undefined;
|
|
63
94
|
if (capabilities.position === true && typeof getPosition !== "function")
|
|
64
95
|
throw new FsError("ENOTSUP", { syscall: "getPosition", path });
|
|
65
|
-
this.#getPosition = getPosition
|
|
96
|
+
this.#getPosition = getPosition;
|
|
66
97
|
const probeRead = capabilities.readObservation === true ? backend.probeRead : undefined;
|
|
67
98
|
if (capabilities.readObservation === true && typeof probeRead !== "function")
|
|
68
99
|
throw new FsError("ENOTSUP", { syscall: "probeRead", path });
|
|
69
|
-
this.#probeRead = probeRead
|
|
100
|
+
this.#probeRead = probeRead;
|
|
70
101
|
this.#backend = backend;
|
|
71
|
-
|
|
72
|
-
this.capabilities = Object.freeze({
|
|
73
|
-
...(capabilities.noFollow === undefined ? {} : { noFollow: capabilities.noFollow }),
|
|
74
|
-
...(capabilities.publication === undefined ? {} : { publication: capabilities.publication }),
|
|
75
|
-
...(capabilities.position === undefined ? {} : { position: capabilities.position }),
|
|
76
|
-
...(capabilities.readObservation === undefined ? {} : { readObservation: capabilities.readObservation }),
|
|
77
|
-
...(capabilities.openTruncate === undefined ? {} : { openTruncate: capabilities.openTruncate }),
|
|
78
|
-
positionedRead: capabilities.positionedRead && options.access !== "write",
|
|
79
|
-
positionedWrite: capabilities.positionedWrite && options.access !== "read" && (!options.append || positionedAppendWrite),
|
|
80
|
-
...(capabilities.positionedAppendWrite === undefined ? {} : { positionedAppendWrite }),
|
|
81
|
-
...(capabilities.delegateZeroLengthWrite === undefined ? {} : { delegateZeroLengthWrite: capabilities.delegateZeroLengthWrite && options.access !== "read" }),
|
|
82
|
-
truncate: capabilities.truncate && options.access !== "read",
|
|
83
|
-
synchronization: capabilities.synchronization,
|
|
84
|
-
});
|
|
102
|
+
this.capabilities = getManagedCapabilities(capabilities, options.access, options.append);
|
|
85
103
|
}
|
|
86
104
|
#run(syscall, options, action) {
|
|
87
105
|
const signal = options.signal;
|
|
@@ -128,7 +146,7 @@ class ManagedFileDescriptor {
|
|
|
128
146
|
return this.#run("getPosition", options, async (backend, forwarded) => {
|
|
129
147
|
if (!this.capabilities.position || !this.#getPosition)
|
|
130
148
|
throw new FsError("ENOTSUP", { syscall: "getPosition", path: this.#path });
|
|
131
|
-
const position = await this.#getPosition(backend.resource, forwarded);
|
|
149
|
+
const position = await this.#getPosition.call(backend, backend.resource, forwarded);
|
|
132
150
|
if (!Number.isSafeInteger(position) || position < 0)
|
|
133
151
|
throw new FsError("EIO", { syscall: "getPosition", path: this.#path });
|
|
134
152
|
return position;
|
|
@@ -138,7 +156,7 @@ class ManagedFileDescriptor {
|
|
|
138
156
|
return this.#run("probeRead", options, async (backend, forwarded) => {
|
|
139
157
|
if (!this.capabilities.readObservation || !this.#probeRead)
|
|
140
158
|
throw new FsError("ENOTSUP", { syscall: "probeRead", path: this.#path });
|
|
141
|
-
const readiness = await this.#probeRead(backend.resource, forwarded);
|
|
159
|
+
const readiness = await this.#probeRead.call(backend, backend.resource, forwarded);
|
|
142
160
|
if (readiness !== "ready" && readiness !== "blocked" && readiness !== "unknown")
|
|
143
161
|
throw new FsError("EIO", { syscall: "probeRead", path: this.#path });
|
|
144
162
|
return readiness;
|
|
@@ -209,11 +227,17 @@ export async function openFileDescriptor(path, options, capabilities, acquire) {
|
|
|
209
227
|
throw new FsError("EINVAL", { syscall: "open", path });
|
|
210
228
|
const signal = options.signal;
|
|
211
229
|
signal?.throwIfAborted();
|
|
212
|
-
const keys = ["access", "creation", "truncate", "append", "mode", "exactMode", "noFollow", "synchronization", "signal"];
|
|
213
230
|
const { access, creation = "never", truncate = false, append = false, mode = 0o666, synchronization } = options;
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
231
|
+
let invalidKey = false;
|
|
232
|
+
for (const key in options) {
|
|
233
|
+
if (Object.prototype.hasOwnProperty.call(options, key) && !OPEN_FILE_OPTION_KEYS.has(key)) {
|
|
234
|
+
invalidKey = true;
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (invalidKey
|
|
239
|
+
|| (access !== "read" && access !== "write" && access !== "readwrite")
|
|
240
|
+
|| (creation !== "never" && creation !== "ifMissing" && creation !== "exclusive")
|
|
217
241
|
|| options.noFollow !== undefined && typeof options.noFollow !== "boolean"
|
|
218
242
|
|| options.exactMode !== undefined && typeof options.exactMode !== "boolean"
|
|
219
243
|
|| typeof truncate !== "boolean" || typeof append !== "boolean"
|
|
@@ -226,7 +250,7 @@ export async function openFileDescriptor(path, options, capabilities, acquire) {
|
|
|
226
250
|
...(options.noFollow === undefined ? {} : { noFollow: options.noFollow }),
|
|
227
251
|
...(options.exactMode === undefined ? {} : { exactMode: options.exactMode }),
|
|
228
252
|
...(signal === undefined ? {} : { signal }), ...(synchronization === undefined ? {} : { synchronization }) });
|
|
229
|
-
const admittedCapabilities = Object.freeze({ ...capabilities });
|
|
253
|
+
const admittedCapabilities = Object.isFrozen(capabilities) ? capabilities : Object.freeze({ ...capabilities });
|
|
230
254
|
admitCapabilities(path, admitted, admittedCapabilities);
|
|
231
255
|
let backend;
|
|
232
256
|
try {
|
|
@@ -238,9 +262,11 @@ export async function openFileDescriptor(path, options, capabilities, acquire) {
|
|
|
238
262
|
}
|
|
239
263
|
try {
|
|
240
264
|
signal?.throwIfAborted();
|
|
241
|
-
const
|
|
265
|
+
const rawBackendCapabilities = backend.capabilities;
|
|
266
|
+
const selected = rawBackendCapabilities ? Object.freeze({ ...rawBackendCapabilities }) : admittedCapabilities;
|
|
242
267
|
signal?.throwIfAborted();
|
|
243
|
-
|
|
268
|
+
if (rawBackendCapabilities)
|
|
269
|
+
admitCapabilities(path, admitted, selected);
|
|
244
270
|
const descriptor = new ManagedFileDescriptor(path, admitted, selected, backend);
|
|
245
271
|
signal?.throwIfAborted();
|
|
246
272
|
return descriptor;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { FileDescriptor, OpenFileOptions } from "../../contracts/descriptor.js";
|
|
2
|
-
import type { AppendFileOptions, CapabilityQueryOptions, CopyFileOptions, DirectoryEntry, FileReadHandle, FileResizeHandle, FileResizeOperation, FileResizeOptions, FileStat, FileSystem, OpenReadFileOptions, OpenResizeFileOptions, FileSystemCapabilities, FsOptions, RenameOptions, MkdirOptions, ReadDirectoryOptions, ReadFileOptions, ReadStreamOptions, RemoveOptions, WriteFileOptions, ConditionalFilePublicationOptions, ConditionalWriteFileOptions, ConditionalRemoveFileOptions, ConditionalRemoveEntryOptions, CreateStagedFileOptions, FileStaging, PublishStagedFileOptions, PrepareDirectoryOptions, StagedFileContent } from "../../contracts/filesystem.js";
|
|
2
|
+
import type { AppendFileOptions, CapabilityQueryOptions, CopyFileOptions, DirectoryEntry, FileReadHandle, FileResizeHandle, FileResizeOperation, FileResizeOptions, FileStat, FileSystem, OpenReadFileOptions, OpenResizeFileOptions, FileSystemCapabilities, FsOptions, RenameOptions, MkdirOptions, ReadDirectoryOptions, ReadFileOptions, ReadStreamOptions, RemoveOptions, WriteFileOptions, ConditionalFilePublicationOptions, ConditionalWriteFileOptions, ConditionalRemoveFileOptions, ConditionalRemoveEntryOptions, ConditionalRemoveEntryReceiptOptions, CreateStagedFileOptions, FileStaging, FileStagingEntry, FileStagingResolution, PublishStagedFileOptions, PrepareDirectoryOptions, StagedFileContent } from "../../contracts/filesystem.js";
|
|
3
3
|
import type { ByteSource } from "../../contracts/io.js";
|
|
4
4
|
export declare class DeviceFileSystem implements FileSystem {
|
|
5
5
|
#private;
|
|
@@ -27,11 +27,16 @@ export declare class DeviceFileSystem implements FileSystem {
|
|
|
27
27
|
rmdir(path: string, options?: FsOptions): Promise<void>;
|
|
28
28
|
publishFileConditional(path: string, source: ByteSource, options: ConditionalFilePublicationOptions): Promise<FileStat>;
|
|
29
29
|
writeFileConditional(path: string, data: Uint8Array, options: ConditionalWriteFileOptions): Promise<FileStat>;
|
|
30
|
-
removeEntryConditional(path: string, options: ConditionalRemoveEntryOptions
|
|
30
|
+
removeEntryConditional(path: string, options: ConditionalRemoveEntryOptions & {
|
|
31
|
+
readonly returnRemainingStat?: false | undefined;
|
|
32
|
+
}): Promise<void>;
|
|
33
|
+
removeEntryConditional(path: string, options: ConditionalRemoveEntryReceiptOptions): Promise<void | FileStat>;
|
|
31
34
|
removeFileConditional(path: string, options: ConditionalRemoveFileOptions): Promise<void>;
|
|
32
35
|
removeTreeConditional(path: string, options: ConditionalRemoveEntryOptions): Promise<void>;
|
|
33
36
|
createStagedFile(path: string, name: string, content: StagedFileContent, options: CreateStagedFileOptions): Promise<FileStaging>;
|
|
34
37
|
publishStagedFile(staging: FileStaging, destination: string, options: PublishStagedFileOptions): Promise<void>;
|
|
38
|
+
prepareDirectoryAncestry(ancestors: readonly FileStagingEntry[], options?: FsOptions): Promise<() => true>;
|
|
39
|
+
prepareStagingResolution(path: string, options?: FsOptions): Promise<FileStagingResolution>;
|
|
35
40
|
removeStagedFile(staging: FileStaging, options?: FsOptions): Promise<void>;
|
|
36
41
|
prepareDirectory(path: string, options: PrepareDirectoryOptions): Promise<FileStat>;
|
|
37
42
|
rename(source: string, destination: string, options?: RenameOptions): Promise<void>;
|