@poe-platform/safe-fs 0.1.52 → 0.1.54
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/dist/safe-fs/contracts/filesystem.d.ts +22 -0
- package/dist/safe-fs/fs/capabilities.d.ts +4 -0
- package/dist/safe-fs/fs/capabilities.js +25 -0
- package/dist/safe-fs/fs/memory/index.d.ts +22 -0
- package/dist/safe-fs/fs/memory/index.js +5 -0
- package/dist/safe-fs/fs/mount/index.d.ts +1 -0
- package/dist/safe-fs/fs/mount/index.js +41 -4
- package/dist/safe-fs/fs/overlay/index.js +30 -3
- package/dist/safe-fs/fs/quota/index.js +5 -0
- package/dist/safe-fs/fs/readonly/index.d.ts +1 -0
- package/dist/safe-fs/fs/readonly/index.js +7 -1
- package/dist/safe-fs/fs/real/index.js +5 -0
- package/dist/safe-fs/fs/s3/filesystem.d.ts +22 -0
- package/dist/safe-fs/fs/s3/filesystem.js +12 -0
- package/dist/safe-fs/fs/webdav/webdav.d.ts +22 -0
- package/dist/safe-fs/fs/webdav/webdav.js +9 -0
- package/package.json +1 -1
|
@@ -23,7 +23,28 @@ export interface DirectoryEntry {
|
|
|
23
23
|
}
|
|
24
24
|
export interface FileSystemCapabilities {
|
|
25
25
|
readonly readOnly?: boolean;
|
|
26
|
+
readonly read?: boolean;
|
|
27
|
+
readonly stat?: boolean;
|
|
28
|
+
readonly readdir?: boolean;
|
|
29
|
+
readonly realpath?: boolean;
|
|
30
|
+
readonly access?: boolean;
|
|
31
|
+
readonly write?: boolean;
|
|
26
32
|
readonly append?: boolean;
|
|
33
|
+
readonly exclusiveCreate?: boolean;
|
|
34
|
+
readonly explicitDirectories?: boolean;
|
|
35
|
+
readonly implicitDirectories?: boolean;
|
|
36
|
+
readonly mkdir?: boolean;
|
|
37
|
+
readonly recursiveMkdir?: boolean;
|
|
38
|
+
readonly remove?: boolean;
|
|
39
|
+
readonly removeDirectory?: boolean;
|
|
40
|
+
readonly recursiveRemove?: boolean;
|
|
41
|
+
readonly rename?: boolean;
|
|
42
|
+
readonly copy?: boolean;
|
|
43
|
+
readonly exclusiveCopy?: boolean;
|
|
44
|
+
readonly readlink?: boolean;
|
|
45
|
+
readonly truncate?: boolean;
|
|
46
|
+
readonly streamingAppend?: boolean;
|
|
47
|
+
readonly randomAccessWrite?: boolean;
|
|
27
48
|
readonly symlinks?: boolean;
|
|
28
49
|
readonly hardlinks?: boolean;
|
|
29
50
|
readonly permissions?: boolean;
|
|
@@ -65,6 +86,7 @@ export interface ReadStreamOptions extends FsOptions {
|
|
|
65
86
|
}
|
|
66
87
|
export interface FileSystem {
|
|
67
88
|
readonly capabilities: FileSystemCapabilities;
|
|
89
|
+
capabilitiesFor?(path: string, options?: FsOptions): Promise<FileSystemCapabilities>;
|
|
68
90
|
readFile(path: string, options?: ReadFileOptions): Promise<Uint8Array>;
|
|
69
91
|
writeFile(path: string, data: Uint8Array, options?: WriteFileOptions): Promise<void>;
|
|
70
92
|
appendFile(path: string, data: Uint8Array, options?: AppendFileOptions): Promise<void>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { FileSystemCapabilities } from "../contracts/filesystem.js";
|
|
2
|
+
export declare function requireCapabilities(...values: readonly (boolean | undefined)[]): boolean | undefined;
|
|
3
|
+
export declare function readOnlyCapabilities(capabilities: FileSystemCapabilities): FileSystemCapabilities;
|
|
4
|
+
export declare function quotaCapabilities(capabilities: FileSystemCapabilities): FileSystemCapabilities;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export function requireCapabilities(...values) {
|
|
2
|
+
return values.some(value => value === false) ? false : values.every(value => value === true) ? true : undefined;
|
|
3
|
+
}
|
|
4
|
+
export function readOnlyCapabilities(capabilities) {
|
|
5
|
+
const inspection = Object.fromEntries([
|
|
6
|
+
"read", "stat", "readdir", "realpath", "access", "readlink", "explicitDirectories", "implicitDirectories",
|
|
7
|
+
"symlinks", "streamingRead",
|
|
8
|
+
].filter(name => capabilities[name] !== undefined).map(name => [name, capabilities[name]]));
|
|
9
|
+
return Object.freeze({
|
|
10
|
+
...inspection, readOnly: true, write: false, append: false, exclusiveCreate: false,
|
|
11
|
+
mkdir: false, recursiveMkdir: false, remove: false, removeDirectory: false, recursiveRemove: false,
|
|
12
|
+
rename: false, copy: false, exclusiveCopy: false, truncate: false, streamingAppend: false,
|
|
13
|
+
randomAccessWrite: false, hardlinks: false, permissions: false, timestamps: false,
|
|
14
|
+
atomicRename: false, streamingWrite: false,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
export function quotaCapabilities(capabilities) {
|
|
18
|
+
const streamingWrite = requireCapabilities(capabilities.write, capabilities.append, !capabilities.readOnly);
|
|
19
|
+
const streamingAppend = requireCapabilities(capabilities.append, !capabilities.readOnly);
|
|
20
|
+
const { streamingWrite: ignoredWrite, streamingAppend: ignoredAppend, ...rest } = capabilities;
|
|
21
|
+
return Object.freeze({ ...rest,
|
|
22
|
+
...(streamingWrite === undefined ? {} : { streamingWrite }),
|
|
23
|
+
...(streamingAppend === undefined ? {} : { streamingAppend }),
|
|
24
|
+
});
|
|
25
|
+
}
|
|
@@ -2,6 +2,28 @@ import type { AppendFileOptions, CopyFileOptions, DirectoryEntry, EntryCompariso
|
|
|
2
2
|
import type { ByteSource } from "../../contracts/io.js";
|
|
3
3
|
export declare class MemoryFileSystem implements FileSystem {
|
|
4
4
|
readonly capabilities: Readonly<{
|
|
5
|
+
read: true;
|
|
6
|
+
stat: true;
|
|
7
|
+
readdir: true;
|
|
8
|
+
realpath: true;
|
|
9
|
+
access: true;
|
|
10
|
+
write: true;
|
|
11
|
+
append: true;
|
|
12
|
+
exclusiveCreate: true;
|
|
13
|
+
explicitDirectories: true;
|
|
14
|
+
implicitDirectories: false;
|
|
15
|
+
mkdir: true;
|
|
16
|
+
recursiveMkdir: true;
|
|
17
|
+
remove: true;
|
|
18
|
+
removeDirectory: true;
|
|
19
|
+
recursiveRemove: true;
|
|
20
|
+
rename: true;
|
|
21
|
+
copy: true;
|
|
22
|
+
exclusiveCopy: true;
|
|
23
|
+
readlink: true;
|
|
24
|
+
truncate: true;
|
|
25
|
+
streamingAppend: true;
|
|
26
|
+
randomAccessWrite: true;
|
|
5
27
|
readOnly: false;
|
|
6
28
|
symlinks: true;
|
|
7
29
|
hardlinks: true;
|
|
@@ -48,6 +48,11 @@ const compareOwnedMemory = async (own, peer, options) => {
|
|
|
48
48
|
};
|
|
49
49
|
export class MemoryFileSystem {
|
|
50
50
|
capabilities = Object.freeze({
|
|
51
|
+
read: true, stat: true, readdir: true, realpath: true, access: true,
|
|
52
|
+
write: true, append: true, exclusiveCreate: true, explicitDirectories: true, implicitDirectories: false,
|
|
53
|
+
mkdir: true, recursiveMkdir: true, remove: true, removeDirectory: true, recursiveRemove: true,
|
|
54
|
+
rename: true, copy: true, exclusiveCopy: true, readlink: true, truncate: true,
|
|
55
|
+
streamingAppend: true, randomAccessWrite: true,
|
|
51
56
|
readOnly: false,
|
|
52
57
|
symlinks: true,
|
|
53
58
|
hardlinks: true,
|
|
@@ -9,6 +9,7 @@ export declare class MountFileSystem implements FileSystem {
|
|
|
9
9
|
private readonly mounts;
|
|
10
10
|
constructor(options: MountFileSystemOptions);
|
|
11
11
|
private select;
|
|
12
|
+
capabilitiesFor(path: string, options?: FsOptions): Promise<FileSystemCapabilities>;
|
|
12
13
|
private protected;
|
|
13
14
|
private error;
|
|
14
15
|
private operation;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { FsError, isFsError, toFsError } from "../../contracts/errors.js";
|
|
2
2
|
import { readBytes } from "../../contracts/io.js";
|
|
3
3
|
import { finishCleanup } from "../../contracts/cleanup.js";
|
|
4
|
+
import { readOnlyCapabilities } from "../capabilities.js";
|
|
4
5
|
import { normalizePath, validatePath } from "../../contracts/virtual-path.js";
|
|
5
6
|
import { compareIdentity } from "./identity.js";
|
|
6
7
|
import { compareEntries, registerEntryAuthority, registerEntryView } from "./comparison.js";
|
|
@@ -79,14 +80,32 @@ export class MountFileSystem {
|
|
|
79
80
|
const streamingWrite = streaming("streamingWrite", "writeStream");
|
|
80
81
|
const append = all("append") ? true
|
|
81
82
|
: mounts.every(({ backend }) => backend.capabilities.append === false) ? false : undefined;
|
|
83
|
+
const common = (capability) => {
|
|
84
|
+
const optional = {
|
|
85
|
+
symlinks: ["symlink", "readlink"], hardlinks: ["link"], permissions: ["chmod"], timestamps: ["utimes"], readlink: ["readlink"],
|
|
86
|
+
};
|
|
87
|
+
const values = mounts.map(({ backend }) => {
|
|
88
|
+
if (backend.capabilities.readOnly === true
|
|
89
|
+
&& !["read", "stat", "readdir", "realpath", "access", "readlink", "explicitDirectories", "implicitDirectories"].includes(capability))
|
|
90
|
+
return false;
|
|
91
|
+
const declared = backend.capabilities[capability];
|
|
92
|
+
return declared === true && optional[capability]?.some(method => typeof backend[method] !== "function") ? false : declared;
|
|
93
|
+
});
|
|
94
|
+
if (["rename", "copy", "exclusiveCopy"].includes(capability) && mounts.length > 1)
|
|
95
|
+
return undefined;
|
|
96
|
+
return values.every(value => value === true) ? true : values.every(value => value === false) ? false : undefined;
|
|
97
|
+
};
|
|
98
|
+
const semantics = Object.fromEntries([
|
|
99
|
+
"read", "stat", "readdir", "realpath", "access",
|
|
100
|
+
"write", "append", "exclusiveCreate", "explicitDirectories", "implicitDirectories", "mkdir", "recursiveMkdir",
|
|
101
|
+
"remove", "removeDirectory", "recursiveRemove", "rename", "copy", "exclusiveCopy", "readlink", "truncate",
|
|
102
|
+
"streamingAppend", "randomAccessWrite", "symlinks", "hardlinks", "permissions", "timestamps",
|
|
103
|
+
].map(capability => [capability, common(capability)]).filter(([, value]) => value !== undefined));
|
|
82
104
|
this.capabilities = Object.freeze({
|
|
83
105
|
get snapshotRmdir() { return mounts.some(({ backend }) => backend.capabilities.snapshotRmdir === true); },
|
|
84
106
|
readOnly: all("readOnly"),
|
|
85
107
|
...(append === undefined ? {} : { append }),
|
|
86
|
-
|
|
87
|
-
hardlinks: all("hardlinks", ["link"]),
|
|
88
|
-
permissions: all("permissions", ["chmod"]),
|
|
89
|
-
timestamps: all("timestamps", ["utimes"]),
|
|
108
|
+
...semantics,
|
|
90
109
|
atomicRename: mounts.length === 1 && all("atomicRename"),
|
|
91
110
|
...(streamingRead === undefined ? {} : { streamingRead }),
|
|
92
111
|
...(streamingWrite === undefined ? {} : { streamingWrite }),
|
|
@@ -95,6 +114,24 @@ export class MountFileSystem {
|
|
|
95
114
|
select(path) {
|
|
96
115
|
return this.mounts.find((mount) => within(mount.path, path));
|
|
97
116
|
}
|
|
117
|
+
async capabilitiesFor(path, options = {}) {
|
|
118
|
+
return this.operation("capabilitiesFor", path, options, async () => {
|
|
119
|
+
const location = await this.resolve(path, options, { allowMissing: true });
|
|
120
|
+
const capabilities = await location.mount.backend.capabilitiesFor?.(location.local, options)
|
|
121
|
+
?? location.mount.backend.capabilities;
|
|
122
|
+
if (location.synthetic)
|
|
123
|
+
return readOnlyCapabilities(capabilities);
|
|
124
|
+
if (this.mounts.length === 1 || capabilities.readOnly === true)
|
|
125
|
+
return Object.freeze({ ...capabilities });
|
|
126
|
+
const { rename: ignoredRename, copy: ignoredCopy, exclusiveCopy: ignoredExclusiveCopy, ...selected } = capabilities;
|
|
127
|
+
const cannotPublish = capabilities.write === false && capabilities.streamingWrite === false && capabilities.exclusiveCreate === false;
|
|
128
|
+
return Object.freeze({
|
|
129
|
+
...selected,
|
|
130
|
+
...(capabilities.copy === false && capabilities.exclusiveCopy === false && cannotPublish ? { copy: false } : {}),
|
|
131
|
+
...(capabilities.exclusiveCopy === false && capabilities.exclusiveCreate === false && capabilities.streamingWrite === false ? { exclusiveCopy: false } : {}),
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
}
|
|
98
135
|
protected(path) {
|
|
99
136
|
return path === "/" || this.mounts.some((mount) => within(path, mount.path));
|
|
100
137
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { platform } from "#safe-fs-platform";
|
|
2
|
+
import { requireCapabilities } from "../capabilities.js";
|
|
2
3
|
import { finishCleanup } from "../../contracts/cleanup.js";
|
|
3
4
|
import { collectBytes, readBytes } from "../../contracts/io.js";
|
|
4
5
|
import { FsError, toFsError } from "../../contracts/errors.js";
|
|
@@ -83,9 +84,35 @@ export class OverlayFileSystem {
|
|
|
83
84
|
? readable.every((capability) => capability === true) ? true : undefined : false;
|
|
84
85
|
const append = !writable || this.#upper.capabilities.append === false ? false
|
|
85
86
|
: this.#upper.capabilities.append === true ? true : undefined;
|
|
87
|
+
const upper = this.#upper.capabilities;
|
|
88
|
+
const mutation = requireCapabilities(writable, upper.mkdir, upper.rename, upper.remove, upper.exclusiveCreate, upper.timestamps, upper.permissions);
|
|
89
|
+
const effectiveAppend = requireCapabilities(append, mutation);
|
|
90
|
+
const effectiveStreamingWrite = requireCapabilities(streamingWrite, mutation);
|
|
91
|
+
const semantics = Object.fromEntries([
|
|
92
|
+
...["read", "stat", "readdir", "realpath", "access"].map(capability => [capability,
|
|
93
|
+
requireCapabilities(upper[capability], this.#lower.capabilities[capability])]),
|
|
94
|
+
["write", requireCapabilities(mutation, upper.write)],
|
|
95
|
+
["exclusiveCreate", requireCapabilities(mutation, upper.exclusiveCreate)],
|
|
96
|
+
["mkdir", requireCapabilities(mutation, upper.mkdir)],
|
|
97
|
+
["recursiveMkdir", requireCapabilities(mutation, upper.recursiveMkdir)],
|
|
98
|
+
["remove", requireCapabilities(mutation, upper.remove)],
|
|
99
|
+
["removeDirectory", requireCapabilities(mutation, upper.removeDirectory)],
|
|
100
|
+
["recursiveRemove", requireCapabilities(mutation, upper.recursiveRemove)],
|
|
101
|
+
["rename", requireCapabilities(mutation, upper.rename, upper.write)],
|
|
102
|
+
["copy", requireCapabilities(mutation, upper.write)],
|
|
103
|
+
["exclusiveCopy", requireCapabilities(mutation, upper.exclusiveCreate)],
|
|
104
|
+
["truncate", requireCapabilities(mutation, upper.truncate)],
|
|
105
|
+
["streamingAppend", requireCapabilities(mutation, streamingWrite, upper.streamingAppend)],
|
|
106
|
+
["randomAccessWrite", requireCapabilities(mutation, upper.randomAccessWrite)],
|
|
107
|
+
["explicitDirectories", requireCapabilities(upper.explicitDirectories, this.#lower.capabilities.explicitDirectories)],
|
|
108
|
+
].filter(([, value]) => value !== undefined));
|
|
86
109
|
this.capabilities = Object.freeze({
|
|
87
|
-
|
|
88
|
-
|
|
110
|
+
...semantics,
|
|
111
|
+
implicitDirectories: false,
|
|
112
|
+
readlink: upper.readlink === true && this.#lower.capabilities.readlink === true ? true
|
|
113
|
+
: upper.readlink === false && this.#lower.capabilities.readlink === false ? false : undefined,
|
|
114
|
+
...(upper.readOnly === undefined ? {} : { readOnly: upper.readOnly }),
|
|
115
|
+
...(effectiveAppend === undefined ? {} : { append: effectiveAppend }),
|
|
89
116
|
atomicRename: false,
|
|
90
117
|
hardlinks: false,
|
|
91
118
|
symlinks: writable && this.#upper.capabilities.symlinks === true
|
|
@@ -94,7 +121,7 @@ export class OverlayFileSystem {
|
|
|
94
121
|
permissions: writable && this.#upper.capabilities.permissions === true && typeof this.#upper.chmod === "function",
|
|
95
122
|
timestamps: writable && this.#upper.capabilities.timestamps === true && typeof this.#upper.utimes === "function",
|
|
96
123
|
...(streamingRead === undefined ? {} : { streamingRead }),
|
|
97
|
-
...(
|
|
124
|
+
...(effectiveStreamingWrite === undefined ? {} : { streamingWrite: effectiveStreamingWrite }),
|
|
98
125
|
});
|
|
99
126
|
Object.defineProperty(this, "capabilities", { writable: false, configurable: false });
|
|
100
127
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { quotaCapabilities } from "../capabilities.js";
|
|
1
2
|
export class FileSystemQuotaError extends Error {
|
|
2
3
|
maxBytes;
|
|
3
4
|
constructor(maxBytes) {
|
|
@@ -99,6 +100,10 @@ export function withFileSystemQuota(fs, options) {
|
|
|
99
100
|
};
|
|
100
101
|
return new Proxy(fs, {
|
|
101
102
|
get(target, property) {
|
|
103
|
+
if (property === "capabilities")
|
|
104
|
+
return quotaCapabilities(target.capabilities);
|
|
105
|
+
if (property === "capabilitiesFor")
|
|
106
|
+
return async (path, fsOptions) => quotaCapabilities(await target.capabilitiesFor?.(path, fsOptions) ?? target.capabilities);
|
|
102
107
|
const replacement = Reflect.get(mutations, property);
|
|
103
108
|
if (typeof replacement === "function")
|
|
104
109
|
return replacement;
|
|
@@ -4,6 +4,7 @@ export declare class ReadOnlyFileSystem implements FileSystem {
|
|
|
4
4
|
#private;
|
|
5
5
|
constructor(filesystem: FileSystem);
|
|
6
6
|
get capabilities(): FileSystemCapabilities;
|
|
7
|
+
capabilitiesFor(path: string, options?: FsOptions): Promise<FileSystemCapabilities>;
|
|
7
8
|
readFile(path: string, options?: ReadFileOptions): Promise<Uint8Array>;
|
|
8
9
|
stat(path: string, options?: FsOptions): Promise<FileStat>;
|
|
9
10
|
lstat(path: string, options?: FsOptions): Promise<FileStat>;
|
|
@@ -2,6 +2,7 @@ import { ACCESS_MODES } from "../../contracts/filesystem.js";
|
|
|
2
2
|
import { FsError } from "../../contracts/errors.js";
|
|
3
3
|
import { readBytes } from "../../contracts/io.js";
|
|
4
4
|
import { compareEntries, registerEntryView } from "../mount/comparison.js";
|
|
5
|
+
import { readOnlyCapabilities } from "../capabilities.js";
|
|
5
6
|
function readOnly(syscall, path, dest) {
|
|
6
7
|
throw new FsError("EROFS", { syscall, path, ...(dest === undefined ? {} : { dest }) });
|
|
7
8
|
}
|
|
@@ -26,7 +27,8 @@ export class ReadOnlyFileSystem {
|
|
|
26
27
|
this.#filesystem = filesystem;
|
|
27
28
|
registerEntryView(this, async (path) => ({ filesystem: this.#filesystem, path, readOnly: true }));
|
|
28
29
|
const streamingRead = typeof filesystem.readStream === "function" ? filesystem.capabilities.streamingRead : false;
|
|
29
|
-
this.#capabilities =
|
|
30
|
+
this.#capabilities = readOnlyCapabilities({
|
|
31
|
+
...filesystem.capabilities,
|
|
30
32
|
readOnly: true,
|
|
31
33
|
append: false,
|
|
32
34
|
symlinks: filesystem.capabilities.symlinks === true && typeof filesystem.readlink === "function",
|
|
@@ -41,6 +43,10 @@ export class ReadOnlyFileSystem {
|
|
|
41
43
|
get capabilities() {
|
|
42
44
|
return this.#capabilities;
|
|
43
45
|
}
|
|
46
|
+
async capabilitiesFor(path, options) {
|
|
47
|
+
const capabilities = await this.#filesystem.capabilitiesFor?.(path, options) ?? this.#filesystem.capabilities;
|
|
48
|
+
return readOnlyCapabilities(capabilities);
|
|
49
|
+
}
|
|
44
50
|
async readFile(path, options) {
|
|
45
51
|
return new Uint8Array(await this.#filesystem.readFile(path, options));
|
|
46
52
|
}
|
|
@@ -80,6 +80,11 @@ function nativeError(error) {
|
|
|
80
80
|
*/
|
|
81
81
|
export class RealFileSystem {
|
|
82
82
|
capabilities = Object.freeze({
|
|
83
|
+
read: true, stat: true, readdir: true, realpath: true, access: true,
|
|
84
|
+
write: true, append: true, exclusiveCreate: true, explicitDirectories: true, implicitDirectories: false,
|
|
85
|
+
mkdir: true, recursiveMkdir: true, remove: true, removeDirectory: true, recursiveRemove: true,
|
|
86
|
+
rename: true, copy: true, exclusiveCopy: true, readlink: true, truncate: true,
|
|
87
|
+
streamingAppend: true, randomAccessWrite: true,
|
|
83
88
|
readOnly: false, symlinks: true, hardlinks: true, permissions: true,
|
|
84
89
|
timestamps: true, atomicRename: true, streamingRead: true, streamingWrite: true,
|
|
85
90
|
});
|
|
@@ -22,6 +22,28 @@ export declare class S3RenameError extends FsError {
|
|
|
22
22
|
}
|
|
23
23
|
export declare class S3FileSystem implements FileSystem {
|
|
24
24
|
readonly capabilities: Readonly<{
|
|
25
|
+
read: true;
|
|
26
|
+
stat: true;
|
|
27
|
+
readdir: true;
|
|
28
|
+
realpath: true;
|
|
29
|
+
access: true;
|
|
30
|
+
write: true;
|
|
31
|
+
explicitDirectories: true;
|
|
32
|
+
implicitDirectories: true;
|
|
33
|
+
mkdir: true;
|
|
34
|
+
recursiveMkdir: true;
|
|
35
|
+
remove: true;
|
|
36
|
+
removeDirectory: true;
|
|
37
|
+
recursiveRemove: true;
|
|
38
|
+
copy: true;
|
|
39
|
+
readlink: false;
|
|
40
|
+
exclusiveCopy: boolean;
|
|
41
|
+
append: boolean;
|
|
42
|
+
exclusiveCreate: boolean;
|
|
43
|
+
truncate: boolean;
|
|
44
|
+
rename: boolean;
|
|
45
|
+
streamingAppend: boolean;
|
|
46
|
+
randomAccessWrite: false;
|
|
25
47
|
readOnly: boolean;
|
|
26
48
|
symlinks: false;
|
|
27
49
|
hardlinks: false;
|
|
@@ -104,6 +104,18 @@ export class S3FileSystem {
|
|
|
104
104
|
this.maxStreamBytes = validateLimit(options.maxStreamBytes ?? 5_000_000_000, "maxStreamBytes", 0, 5_000_000_000);
|
|
105
105
|
this.maxListEntries = validateLimit(options.maxListEntries ?? 100_000, "maxListEntries", 1);
|
|
106
106
|
this.capabilities = Object.freeze({
|
|
107
|
+
read: true, stat: true, readdir: true, realpath: true, access: true,
|
|
108
|
+
write: true, explicitDirectories: true, implicitDirectories: true, mkdir: true, recursiveMkdir: true,
|
|
109
|
+
remove: true, removeDirectory: true, recursiveRemove: true, copy: true, readlink: false,
|
|
110
|
+
exclusiveCopy: options.transport.capabilities?.conditionalCopy === true,
|
|
111
|
+
append: options.transport.capabilities?.conditionalPut === true,
|
|
112
|
+
exclusiveCreate: options.transport.capabilities?.conditionalPut === true,
|
|
113
|
+
truncate: options.transport.capabilities?.conditionalPut === true,
|
|
114
|
+
rename: this.allowRename && options.transport.capabilities?.conditionalDelete === true
|
|
115
|
+
&& (options.transport.capabilities?.conditionalCopy === true || options.transport.capabilities?.conditionalPut === true),
|
|
116
|
+
streamingAppend: options.transport.capabilities?.streamingWrite === true
|
|
117
|
+
&& options.transport.capabilities?.conditionalPut === true && typeof options.transport.putObjectStream === "function",
|
|
118
|
+
randomAccessWrite: false,
|
|
107
119
|
readOnly: options.readOnly ?? false,
|
|
108
120
|
symlinks: false, hardlinks: false, permissions: false,
|
|
109
121
|
timestamps: options.transport.capabilities?.conditionalCopy === true || options.transport.capabilities?.conditionalPut === true,
|
|
@@ -33,6 +33,28 @@ export interface WebDavFileSystemOptions {
|
|
|
33
33
|
}
|
|
34
34
|
export declare class WebDavFileSystem implements FileSystem {
|
|
35
35
|
readonly capabilities: Readonly<{
|
|
36
|
+
read: true;
|
|
37
|
+
stat: true;
|
|
38
|
+
readdir: true;
|
|
39
|
+
realpath: true;
|
|
40
|
+
access: true;
|
|
41
|
+
write: true;
|
|
42
|
+
append: true;
|
|
43
|
+
exclusiveCreate: true;
|
|
44
|
+
explicitDirectories: true;
|
|
45
|
+
implicitDirectories: false;
|
|
46
|
+
mkdir: true;
|
|
47
|
+
recursiveMkdir: true;
|
|
48
|
+
remove: true;
|
|
49
|
+
recursiveRemove: true;
|
|
50
|
+
rename: true;
|
|
51
|
+
copy: true;
|
|
52
|
+
exclusiveCopy: true;
|
|
53
|
+
readlink: false;
|
|
54
|
+
truncate: false;
|
|
55
|
+
randomAccessWrite: false;
|
|
56
|
+
removeDirectory: boolean;
|
|
57
|
+
streamingAppend: boolean;
|
|
36
58
|
symlinks: false;
|
|
37
59
|
hardlinks: false;
|
|
38
60
|
permissions: false;
|
|
@@ -140,6 +140,11 @@ function statusCode(element) {
|
|
|
140
140
|
}
|
|
141
141
|
export class WebDavFileSystem {
|
|
142
142
|
capabilities = Object.freeze({
|
|
143
|
+
read: true, stat: true, readdir: true, realpath: true, access: true,
|
|
144
|
+
write: true, append: true, exclusiveCreate: true, explicitDirectories: true, implicitDirectories: false,
|
|
145
|
+
mkdir: true, recursiveMkdir: true, remove: true, recursiveRemove: true, rename: true, copy: true,
|
|
146
|
+
exclusiveCopy: true, readlink: false, truncate: false, randomAccessWrite: false,
|
|
147
|
+
removeDirectory: false, streamingAppend: false,
|
|
143
148
|
symlinks: false, hardlinks: false, permissions: false, timestamps: true,
|
|
144
149
|
atomicRename: false, streamingRead: true, streamingWrite: true,
|
|
145
150
|
});
|
|
@@ -200,6 +205,10 @@ export class WebDavFileSystem {
|
|
|
200
205
|
}
|
|
201
206
|
this.transport = options.fetch === globalThis.fetch ? options.fetch.bind(globalThis) : options.fetch;
|
|
202
207
|
this.requestStreamSupport = options.requestStreamSupport ?? (options.fetch === globalThis.fetch ? "native" : false);
|
|
208
|
+
this.capabilities = Object.freeze({ ...this.capabilities,
|
|
209
|
+
removeDirectory: this.atomicEmptyDirectory !== undefined,
|
|
210
|
+
streamingAppend: this.requestStreamSupport !== false,
|
|
211
|
+
});
|
|
203
212
|
this.maxResponseBytes = positive(options.maxResponseBytes ?? 64 * 1024 * 1024, "maxResponseBytes");
|
|
204
213
|
this.maxXmlBytes = positive(options.maxXmlBytes ?? 2 * 1024 * 1024, "maxXmlBytes");
|
|
205
214
|
this.maxEntries = positive(options.maxEntries ?? 10_000, "maxEntries");
|