@poe-platform/safe-fs 0.1.804 → 0.1.805
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/errors.d.ts +1 -0
- package/dist/safe-fs/contracts/errors.js +12 -0
- package/dist/safe-fs/core.d.ts +2 -14
- package/dist/safe-fs/core.js +2 -11
- package/dist/safe-fs/fs/devices/index.d.ts +6 -1
- package/dist/safe-fs/fs/devices/index.js +38 -23
- package/dist/safe-fs/fs/devices/path.js +1 -1
- package/dist/safe-fs/fs/memory/atomic-view.d.ts +3 -0
- package/dist/safe-fs/fs/memory/atomic-view.js +5 -0
- package/dist/safe-fs/fs/memory/index.d.ts +5 -2
- package/dist/safe-fs/fs/memory/index.js +124 -78
- package/dist/safe-fs/fs/memory/limits.js +3 -0
- package/dist/safe-fs/fs/mount/comparison.js +3 -3
- package/dist/safe-fs/fs/readonly/index.js +1 -1
- package/dist/safe-fs/fs/s3/filesystem.js +1 -1
- package/dist/safe-fs/fs/webdav/webdav.js +1 -1
- package/dist/safe-fs/runtime-core.d.ts +26 -0
- package/dist/safe-fs/runtime-core.js +56 -0
- package/package.json +5 -1
|
@@ -40,6 +40,7 @@ export interface FsErrorOptions extends ErrorOptions {
|
|
|
40
40
|
readonly message?: string;
|
|
41
41
|
}
|
|
42
42
|
export declare class FsError extends Error {
|
|
43
|
+
static [Symbol.hasInstance](value: unknown): boolean;
|
|
43
44
|
readonly code: ErrnoCode;
|
|
44
45
|
readonly errno: PlatformErrno;
|
|
45
46
|
readonly syscall?: string;
|
|
@@ -31,7 +31,18 @@ const descriptions = {
|
|
|
31
31
|
ETIMEDOUT: "operation timed out",
|
|
32
32
|
EXDEV: "cross-device link not permitted",
|
|
33
33
|
};
|
|
34
|
+
const FS_ERROR_BRAND = Symbol.for("@poe-code/safe-fs.FsError");
|
|
34
35
|
export class FsError extends Error {
|
|
36
|
+
static [Symbol.hasInstance](value) {
|
|
37
|
+
if (typeof value !== "object" || value === null)
|
|
38
|
+
return false;
|
|
39
|
+
if (this !== FsError)
|
|
40
|
+
return Function.prototype[Symbol.hasInstance].call(this, value);
|
|
41
|
+
if (Function.prototype[Symbol.hasInstance].call(FsError, value))
|
|
42
|
+
return true;
|
|
43
|
+
const record = value;
|
|
44
|
+
return record[FS_ERROR_BRAND] === true && isErrnoCode(record.code);
|
|
45
|
+
}
|
|
35
46
|
code;
|
|
36
47
|
errno;
|
|
37
48
|
syscall;
|
|
@@ -53,6 +64,7 @@ export class FsError extends Error {
|
|
|
53
64
|
finally {
|
|
54
65
|
errorConstructor.stackTraceLimit = prevStackLimit;
|
|
55
66
|
}
|
|
67
|
+
Object.defineProperty(this, FS_ERROR_BRAND, { value: true, enumerable: false, configurable: false, writable: false });
|
|
56
68
|
this.name = "FsError";
|
|
57
69
|
this.code = code;
|
|
58
70
|
this.errno = errno;
|
package/dist/safe-fs/core.d.ts
CHANGED
|
@@ -1,28 +1,16 @@
|
|
|
1
|
-
export * from "./
|
|
2
|
-
export
|
|
3
|
-
export * from "./contracts/io.js";
|
|
4
|
-
export { openFileDescriptor } from "./fs/descriptor.js";
|
|
5
|
-
export type { DescriptorBackend, DescriptorOpenOptions } from "./fs/descriptor.js";
|
|
6
|
-
export { assertPathWithin, isPathWithin, normalizePath, relativePath, resolvePath, validatePath } from "./contracts/virtual-path.js";
|
|
7
|
-
export { basename, dirname, extname, isAbsolutePath, joinPath, posixPath } from "./contracts/portable-path.js";
|
|
8
|
-
export * from "./fs/memory/index.js";
|
|
9
|
-
export * from "./fs/devices/index.js";
|
|
1
|
+
export * from "./runtime-core.js";
|
|
2
|
+
export { MemoryFileSystem, MemoryRedirectHandle, createMemoryFileSystem, defaultMemoryFileSystemLimits, bindConditionalMutation, getLastReadMemoryFileSourceRef, isCleanAbsolutePath, tryGetMemoryDirectoryEntryNamesSync, tryMkdirMemorySync, tryOpenMemoryRedirectHandleSync, tryReadMemoryFileViewSync, tryResolveMemoryDevicePath, tryRmRfMemorySync, tryWriteMemoryFileInDirSync, tryWriteMemoryFileSync, utf8ByteLength } from "./fs/memory/index.js";
|
|
10
3
|
export * from "./fs/readonly/index.js";
|
|
11
4
|
export * from "./fs/mount/index.js";
|
|
12
5
|
export * from "./fs/overlay/index.js";
|
|
13
6
|
export * from "./fs/quota/index.js";
|
|
14
7
|
export * from "./fs/object-publication/index.js";
|
|
15
|
-
export { retargetScopedFileSystem, scopeFileSystem, retainFileSystemCleanup } from "./fs/scoped.js";
|
|
16
|
-
export type { RetainedFileSystemCleanupView, RetainedFileSystemCleanupOptions } from "./fs/scoped.js";
|
|
17
8
|
export * from "./fs/webdav/index.js";
|
|
18
9
|
export * from "./bridge/index.js";
|
|
19
10
|
export * from "./python/index.js";
|
|
20
|
-
export { compareEntries, registerEntryView } from "./fs/mount/comparison.js";
|
|
21
|
-
export type { EntryViewResolver } from "./fs/mount/comparison.js";
|
|
22
11
|
export { parseXml, parseXmlSteps, XmlLimitError } from "./xml.js";
|
|
23
12
|
export type { XmlName, XmlAttribute, XmlContent, XmlElement, XmlLimits } from "./xml.js";
|
|
24
13
|
export * from "./contracts/object.js";
|
|
25
14
|
export { ObjectAuthority } from "./fs/object-authority.js";
|
|
26
|
-
export { bindConditionalMutation, type ConditionalMutationBinding } from "./fs/memory/index.js";
|
|
27
15
|
export * from "./fs/s3/index.js";
|
|
28
16
|
export * from "./fs/s3/http/index.js";
|
package/dist/safe-fs/core.js
CHANGED
|
@@ -1,24 +1,15 @@
|
|
|
1
|
-
export * from "./
|
|
2
|
-
export
|
|
3
|
-
export * from "./contracts/io.js";
|
|
4
|
-
export { openFileDescriptor } from "./fs/descriptor.js";
|
|
5
|
-
export { assertPathWithin, isPathWithin, normalizePath, relativePath, resolvePath, validatePath } from "./contracts/virtual-path.js";
|
|
6
|
-
export { basename, dirname, extname, isAbsolutePath, joinPath, posixPath } from "./contracts/portable-path.js";
|
|
7
|
-
export * from "./fs/memory/index.js";
|
|
8
|
-
export * from "./fs/devices/index.js";
|
|
1
|
+
export * from "./runtime-core.js";
|
|
2
|
+
export { MemoryFileSystem, MemoryRedirectHandle, createMemoryFileSystem, defaultMemoryFileSystemLimits, bindConditionalMutation, getLastReadMemoryFileSourceRef, isCleanAbsolutePath, tryGetMemoryDirectoryEntryNamesSync, tryMkdirMemorySync, tryOpenMemoryRedirectHandleSync, tryReadMemoryFileViewSync, tryResolveMemoryDevicePath, tryRmRfMemorySync, tryWriteMemoryFileInDirSync, tryWriteMemoryFileSync, utf8ByteLength } from "./fs/memory/index.js";
|
|
9
3
|
export * from "./fs/readonly/index.js";
|
|
10
4
|
export * from "./fs/mount/index.js";
|
|
11
5
|
export * from "./fs/overlay/index.js";
|
|
12
6
|
export * from "./fs/quota/index.js";
|
|
13
7
|
export * from "./fs/object-publication/index.js";
|
|
14
|
-
export { retargetScopedFileSystem, scopeFileSystem, retainFileSystemCleanup } from "./fs/scoped.js";
|
|
15
8
|
export * from "./fs/webdav/index.js";
|
|
16
9
|
export * from "./bridge/index.js";
|
|
17
10
|
export * from "./python/index.js";
|
|
18
|
-
export { compareEntries, registerEntryView } from "./fs/mount/comparison.js";
|
|
19
11
|
export { parseXml, parseXmlSteps, XmlLimitError } from "./xml.js";
|
|
20
12
|
export * from "./contracts/object.js";
|
|
21
13
|
export { ObjectAuthority } from "./fs/object-authority.js";
|
|
22
|
-
export { bindConditionalMutation } from "./fs/memory/index.js";
|
|
23
14
|
export * from "./fs/s3/index.js";
|
|
24
15
|
export * from "./fs/s3/http/index.js";
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import type { FileDescriptor, OpenFileOptions } from "../../contracts/descriptor.js";
|
|
2
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
|
+
import { type EntryLocation } from "../mount/comparison.js";
|
|
5
|
+
import { pathNamespace } from "../path-namespace.js";
|
|
4
6
|
export declare class DeviceFileSystem implements FileSystem {
|
|
5
7
|
#private;
|
|
6
8
|
readonly capabilities: FileSystemCapabilities;
|
|
9
|
+
get [pathNamespace](): any;
|
|
10
|
+
_resolveEntryView: (path: string, options: FsOptions) => Promise<EntryLocation>;
|
|
11
|
+
_entryAuthority: () => Promise<"unknown">;
|
|
7
12
|
constructor(filesystem: FileSystem);
|
|
8
13
|
canonicalizeMissingTarget(path: string, options?: FsOptions): string | undefined;
|
|
9
14
|
capabilitiesFor(path: string, options?: CapabilityQueryOptions): Promise<FileSystemCapabilities>;
|
|
10
15
|
stat(path: string, options?: FsOptions): Promise<FileStat>;
|
|
11
16
|
lstat(path: string, options?: FsOptions): Promise<FileStat>;
|
|
12
|
-
compareEntry(path: string, peer: FileSystem, peerPath: string, options?: FsOptions): Promise<import("../../
|
|
17
|
+
compareEntry(path: string, peer: FileSystem, peerPath: string, options?: FsOptions): Promise<import("../../runtime-core.js").EntryComparison>;
|
|
13
18
|
realpath(path: string, options?: FsOptions): Promise<string>;
|
|
14
19
|
readFile(path: string, options?: ReadFileOptions): Promise<Uint8Array>;
|
|
15
20
|
readStream(path: string, options?: ReadStreamOptions): ByteSource;
|
|
@@ -2,9 +2,9 @@ import { snapshotStagingCreation } from "../staging-cleanup.js";
|
|
|
2
2
|
import { FsError, isFsError } from "../../contracts/errors.js";
|
|
3
3
|
import { finishCleanup } from "../../contracts/cleanup.js";
|
|
4
4
|
import { admitDirectoryEntries, directoryEntryLimit } from "../directory-admission.js";
|
|
5
|
-
import { compareEntries
|
|
5
|
+
import { compareEntries } from "../mount/comparison.js";
|
|
6
6
|
import { deviceDirectory, lexicalDevicePath, nullPath, resolveDevicePath } from "./path.js";
|
|
7
|
-
import { tryResolveMemoryDevicePath } from "
|
|
7
|
+
import { tryResolveMemoryDevicePath } from "../../runtime-core.js";
|
|
8
8
|
import { createDeviceYield, deviceReadStream, drainDeviceFile, drainDeviceInput } from "./stream.js";
|
|
9
9
|
import { openRetainedReadFile, openRetainedResizeFile, retainedResizeCapabilities, ownedMutationCapabilities, requireOwnedMutation } from "../capabilities.js";
|
|
10
10
|
import { pathNamespace } from "../path-namespace.js";
|
|
@@ -71,21 +71,46 @@ function nonnegative(value, path) {
|
|
|
71
71
|
if (value !== undefined && (!Number.isSafeInteger(value) || value < 0))
|
|
72
72
|
throw new FsError("EINVAL", { path });
|
|
73
73
|
}
|
|
74
|
+
const sharedUnknownEntryAuthority = async () => "unknown";
|
|
74
75
|
export class DeviceFileSystem {
|
|
75
76
|
#filesystem;
|
|
76
77
|
capabilities;
|
|
77
|
-
#
|
|
78
|
-
#
|
|
78
|
+
#identityScopeObj;
|
|
79
|
+
#nullStatObj;
|
|
80
|
+
#directoryStatObj;
|
|
81
|
+
get [pathNamespace]() {
|
|
82
|
+
return Reflect.get(this.#filesystem, pathNamespace);
|
|
83
|
+
}
|
|
84
|
+
get #nullStat() {
|
|
85
|
+
if (this.#nullStatObj)
|
|
86
|
+
return this.#nullStatObj;
|
|
87
|
+
const identityScope = (this.#identityScopeObj ??= Object.freeze({}));
|
|
88
|
+
return (this.#nullStatObj = Object.freeze({
|
|
89
|
+
type: "character", mode: 0o020666, size: 0, allocatedBytes: 0, uid: 0, gid: 0,
|
|
90
|
+
mtimeMs: 0, atimeMs: 0, ctimeMs: 0, birthtimeMs: 0, identityScope, ino: 1, dev: 0, nlink: 1, preferredIoBlockSize: 4096,
|
|
91
|
+
}));
|
|
92
|
+
}
|
|
93
|
+
get #directoryStat() {
|
|
94
|
+
if (this.#directoryStatObj)
|
|
95
|
+
return this.#directoryStatObj;
|
|
96
|
+
const identityScope = (this.#identityScopeObj ??= Object.freeze({}));
|
|
97
|
+
return (this.#directoryStatObj = Object.freeze({
|
|
98
|
+
type: "directory", mode: 0o040755, size: 0, allocatedBytes: 0, uid: 0, gid: 0,
|
|
99
|
+
mtimeMs: 0, atimeMs: 0, ctimeMs: 0, birthtimeMs: 0, identityScope, ino: 2, dev: 0, nlink: 1,
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
_resolveEntryView = async (path, options) => {
|
|
103
|
+
const resolved = await this.#resolve(path, options);
|
|
104
|
+
if (resolved === nullPath || resolved === deviceDirectory) {
|
|
105
|
+
return { filesystem: this, path: resolved, stat: resolved === nullPath ? this.#nullStat : this.#directoryStat, readOnly: false };
|
|
106
|
+
}
|
|
107
|
+
return { filesystem: this.#filesystem, path };
|
|
108
|
+
};
|
|
109
|
+
_entryAuthority = sharedUnknownEntryAuthority;
|
|
79
110
|
constructor(filesystem) {
|
|
80
111
|
this.#filesystem = filesystem;
|
|
81
|
-
Object.defineProperty(this, pathNamespace, { get: () => Reflect.get(filesystem, pathNamespace) });
|
|
82
112
|
this.capabilities = globalCapabilities(filesystem);
|
|
83
|
-
|
|
84
|
-
const stat = { mode: 0o020666, size: 0, allocatedBytes: 0, uid: 0, gid: 0,
|
|
85
|
-
mtimeMs: 0, atimeMs: 0, ctimeMs: 0, birthtimeMs: 0, identityScope, ino: 1, dev: 0, nlink: 1 };
|
|
86
|
-
this.#nullStat = Object.freeze({ ...stat, type: "character", preferredIoBlockSize: 4096 });
|
|
87
|
-
this.#directoryStat = Object.freeze({ ...stat, type: "directory", mode: 0o040755, ino: 2 });
|
|
88
|
-
const methods = new Map();
|
|
113
|
+
let methods;
|
|
89
114
|
const view = new Proxy(this, {
|
|
90
115
|
set: (_target, property, value) => Reflect.set(filesystem, property, value, filesystem),
|
|
91
116
|
get(target, property) {
|
|
@@ -93,24 +118,14 @@ export class DeviceFileSystem {
|
|
|
93
118
|
if (typeof value !== "function" || property === "constructor")
|
|
94
119
|
return value;
|
|
95
120
|
const backing = Reflect.get(filesystem, property, filesystem);
|
|
96
|
-
const cached = methods
|
|
121
|
+
const cached = methods?.get(property);
|
|
97
122
|
if (cached && cached.backing === backing)
|
|
98
123
|
return cached.bound;
|
|
99
124
|
const bound = value.bind(target);
|
|
100
|
-
methods.set(property, { backing, bound });
|
|
125
|
+
(methods ??= new Map()).set(property, { backing, bound });
|
|
101
126
|
return bound;
|
|
102
127
|
},
|
|
103
128
|
});
|
|
104
|
-
for (const identity of [this, view])
|
|
105
|
-
registerEntryView(identity, async (path, options) => {
|
|
106
|
-
const resolved = await this.#resolve(path, options);
|
|
107
|
-
if (resolved === nullPath || resolved === deviceDirectory)
|
|
108
|
-
return { filesystem: this, path: resolved,
|
|
109
|
-
stat: resolved === nullPath ? this.#nullStat : this.#directoryStat, readOnly: false };
|
|
110
|
-
return { filesystem, path };
|
|
111
|
-
});
|
|
112
|
-
// This internal view has no identity proof beyond its synthetic stats.
|
|
113
|
-
registerEntryAuthority(this, async () => "unknown");
|
|
114
129
|
return view;
|
|
115
130
|
}
|
|
116
131
|
#resolve(path, options, followFinal = true, resizeCreate, traversal) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FsError, isFsError } from "../../contracts/errors.js";
|
|
2
2
|
import { pathByteLength, validatePath } from "../../contracts/virtual-path.js";
|
|
3
3
|
import { capturePathNamespace, pathNamespace } from "../path-namespace.js";
|
|
4
|
-
import { isCleanAbsolutePath, tryResolveMemoryDevicePath } from "
|
|
4
|
+
import { isCleanAbsolutePath, tryResolveMemoryDevicePath } from "../../runtime-core.js";
|
|
5
5
|
export const nullPath = "/dev/null";
|
|
6
6
|
export const deviceDirectory = "/dev";
|
|
7
7
|
function isNullParts(parts) {
|
|
@@ -4,5 +4,8 @@ export interface MemoryAtomicView {
|
|
|
4
4
|
stat(path: string): FileStat | undefined;
|
|
5
5
|
names(path: string): readonly string[];
|
|
6
6
|
}
|
|
7
|
+
type LazyMemoryAtomicView = (this: FileSystem) => MemoryAtomicView | undefined;
|
|
7
8
|
export declare function registerMemoryAtomicView(fs: FileSystem, view: MemoryAtomicView, intact: () => boolean): void;
|
|
9
|
+
export declare function registerLazyMemoryAtomicView(fs: FileSystem, create: LazyMemoryAtomicView): void;
|
|
8
10
|
export declare function memoryAtomicView(fs: FileSystem): MemoryAtomicView | undefined;
|
|
11
|
+
export {};
|
|
@@ -2,7 +2,12 @@ const views = new WeakMap();
|
|
|
2
2
|
export function registerMemoryAtomicView(fs, view, intact) {
|
|
3
3
|
views.set(fs, { view, intact });
|
|
4
4
|
}
|
|
5
|
+
export function registerLazyMemoryAtomicView(fs, create) {
|
|
6
|
+
views.set(fs, create);
|
|
7
|
+
}
|
|
5
8
|
export function memoryAtomicView(fs) {
|
|
6
9
|
const registered = views.get(fs);
|
|
10
|
+
if (typeof registered === "function")
|
|
11
|
+
return registered.call(fs);
|
|
7
12
|
return registered?.intact() ? registered.view : undefined;
|
|
8
13
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AppendFileOptions, CopyFileOptions, DirectoryEntry, EntryComparison, FileReadHandle, FileResizeHandle, FileStat, FileSystem, FileSystemCapabilities, FsOptions, ChmodOptions, RenameOptions, MkdirOptions, ReadDirectoryOptions, ReadFileOptions, ReadStreamOptions, RemoveOptions, FileDescriptor, OpenFileOptions, OpenReadFileOptions, OpenResizeFileOptions, WriteFileOptions, ConditionalWriteFileOptions, ConditionalRemoveFileOptions, ConditionalRemoveEntryOptions, ConditionalRemoveEntryReceiptOptions, CreateStagedFileOptions, FileStaging, FileStagingEntry, FileStagingResolution, PublishStagedFileOptions, PrepareDirectoryOptions, StagedFileContent } from "../../contracts/filesystem.js";
|
|
2
2
|
import type { ByteSource } from "../../contracts/io.js";
|
|
3
|
+
import { type MemoryAtomicView } from "./atomic-view.js";
|
|
3
4
|
import { MemoryAllocation, MemoryLedger } from "./ledger.js";
|
|
4
5
|
import { type MemoryFileSystemOptions } from "./limits.js";
|
|
5
6
|
export { defaultMemoryFileSystemLimits, type MemoryFileSystemLimits, type MemoryFileSystemOptions } from "./limits.js";
|
|
@@ -59,9 +60,10 @@ export interface ConditionalMutationBinding {
|
|
|
59
60
|
}
|
|
60
61
|
export declare function bindConditionalMutation<Result>(identityScope: object | symbol | undefined, binding: ConditionalMutationBinding, action: () => Promise<Result>): Promise<Result>;
|
|
61
62
|
export declare class MemoryFileSystem implements FileSystem {
|
|
63
|
+
#private;
|
|
62
64
|
capabilitiesFor?: NonNullable<FileSystem["capabilitiesFor"]>;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
private get identityScope();
|
|
66
|
+
get capabilities(): FileSystemCapabilities;
|
|
65
67
|
private nextInode;
|
|
66
68
|
private readonly ledger;
|
|
67
69
|
readonly _cache: MemoryCache;
|
|
@@ -70,6 +72,7 @@ export declare class MemoryFileSystem implements FileSystem {
|
|
|
70
72
|
private readonly root;
|
|
71
73
|
private totalBytes;
|
|
72
74
|
symlinkCount: number;
|
|
75
|
+
_getAtomicView(): MemoryAtomicView | undefined;
|
|
73
76
|
constructor(options?: MemoryFileSystemOptions);
|
|
74
77
|
compareEntry(path: string, peer: FileSystem, peerPath: string, options?: FsOptions): Promise<EntryComparison>;
|
|
75
78
|
canonicalizeMissingTarget(path: string, options?: FsOptions): string | undefined;
|
|
@@ -9,7 +9,7 @@ import { directoryAncestryPaths, runStagingGuard, snapshotDirectoryAncestry, sna
|
|
|
9
9
|
import { compareIdentity } from "../mount/identity.js";
|
|
10
10
|
import { createStagingCleanup, snapshotStagingCreation } from "../staging-cleanup.js";
|
|
11
11
|
import { resolveMissingTarget } from "./missing-target.js";
|
|
12
|
-
import {
|
|
12
|
+
import { registerLazyMemoryAtomicView } from "./atomic-view.js";
|
|
13
13
|
import { snapshotConditionalChmod } from "../conditional-chmod.js";
|
|
14
14
|
import { MemoryAllocation, MemoryLedger } from "./ledger.js";
|
|
15
15
|
import { normalizeMemoryFileSystemLimits } from "./limits.js";
|
|
@@ -50,14 +50,17 @@ const DUMMY_POOL_LEDGER = new MemoryLedger(normalizeMemoryFileSystemLimits({}));
|
|
|
50
50
|
const DUMMY_POOL_ALLOCATION = new MemoryAllocation(EMPTY_ALLOC_BYTES, DUMMY_POOL_LEDGER);
|
|
51
51
|
const DUMMY_POOL_FILE_NODE = new MemoryFileNode(0, 0, null, 0, DUMMY_POOL_ALLOCATION, DUMMY_POOL_ALLOCATION.data);
|
|
52
52
|
DUMMY_POOL_FILE_NODE.atimeMs = DUMMY_POOL_FILE_NODE.mtimeMs = DUMMY_POOL_FILE_NODE.ctimeMs = DUMMY_POOL_FILE_NODE.birthtimeMs = 1700000000000;
|
|
53
|
+
const EMPTY_DIR_TABLE = new Int16Array(0);
|
|
54
|
+
const EMPTY_DIR_KEYS = [];
|
|
55
|
+
const EMPTY_DIR_VALS = [];
|
|
53
56
|
class FastDirectoryEntriesMap {
|
|
54
57
|
// Keep speculative slots local so a failed write cannot pin a tenant globally.
|
|
55
58
|
_missKey = "";
|
|
56
59
|
_missSlot = -1;
|
|
57
|
-
_table =
|
|
58
|
-
_mask =
|
|
59
|
-
_keys =
|
|
60
|
-
_vals =
|
|
60
|
+
_table = EMPTY_DIR_TABLE;
|
|
61
|
+
_mask = 0;
|
|
62
|
+
_keys = EMPTY_DIR_KEYS;
|
|
63
|
+
_vals = EMPTY_DIR_VALS;
|
|
61
64
|
_next = 0;
|
|
62
65
|
size = 0;
|
|
63
66
|
[Symbol.toStringTag] = "Map";
|
|
@@ -90,6 +93,11 @@ class FastDirectoryEntriesMap {
|
|
|
90
93
|
getForWriteWithHash(k, h) {
|
|
91
94
|
let slot = h & this._mask;
|
|
92
95
|
if (this.size === 0) {
|
|
96
|
+
if (this._keys.length === 0) {
|
|
97
|
+
this._missKey = "";
|
|
98
|
+
this._missSlot = -1;
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
93
101
|
this._missKey = k;
|
|
94
102
|
this._missSlot = slot;
|
|
95
103
|
return undefined;
|
|
@@ -205,7 +213,7 @@ class FastDirectoryEntriesMap {
|
|
|
205
213
|
return this;
|
|
206
214
|
}
|
|
207
215
|
if (this._next >= this._keys.length) {
|
|
208
|
-
this._rebuild(this.size * 2 <= this._keys.length ? this._keys.length : this._keys.length * 2);
|
|
216
|
+
this._rebuild(this._keys.length === 0 ? 8 : (this.size * 2 <= this._keys.length ? this._keys.length : this._keys.length * 2));
|
|
209
217
|
}
|
|
210
218
|
let slot = this._hash(k);
|
|
211
219
|
const mask = this._mask;
|
|
@@ -415,7 +423,6 @@ class MemoryCache {
|
|
|
415
423
|
const typeModes = { file: 0o100000, directory: 0o040000, symlink: 0o120000 };
|
|
416
424
|
const emptyResolveOptions = Object.freeze({});
|
|
417
425
|
const noFollowResolveOptions = Object.freeze({ followFinal: false });
|
|
418
|
-
const sharedMkdirResolveOptions = { createDirectories: 0o777 };
|
|
419
426
|
const sharedAllowMissingNoFollowOptions = Object.freeze({ allowMissing: true, followFinal: false });
|
|
420
427
|
const sharedFastLocation = { node: undefined, parent: DUMMY_POOL_DIR_NODE, name: "", path: "" };
|
|
421
428
|
const resolvedVoid = Promise.resolve();
|
|
@@ -441,7 +448,7 @@ const compareOwnedMemory = async (own, peer, options) => {
|
|
|
441
448
|
let answer = "unknown";
|
|
442
449
|
const visited = new Set();
|
|
443
450
|
for (const [left, right] of [[own, peer], [peer, own]]) {
|
|
444
|
-
if (!registeredAuthorities.has(left.filesystem) || visited.has(left.filesystem))
|
|
451
|
+
if ((!registeredAuthorities.has(left.filesystem) && !ownedStores.has(left.filesystem)) || visited.has(left.filesystem))
|
|
445
452
|
continue;
|
|
446
453
|
visited.add(left.filesystem);
|
|
447
454
|
const comparison = left.filesystem.compareEntry;
|
|
@@ -590,32 +597,48 @@ class MemoryReadStream {
|
|
|
590
597
|
return STREAM_RESOLVED_DONE;
|
|
591
598
|
}
|
|
592
599
|
}
|
|
600
|
+
const SHARED_STOCK_MEMORY_CAPABILITIES = Object.freeze({
|
|
601
|
+
read: true, stat: true, readdir: true, realpath: true, access: true, open: true,
|
|
602
|
+
write: true, append: true, exclusiveCreate: true, explicitDirectories: true, implicitDirectories: false,
|
|
603
|
+
mkdir: true, recursiveMkdir: true, remove: true, removeDirectory: true, recursiveRemove: true,
|
|
604
|
+
rename: true, atomicRenameNoReplace: true, copy: true, exclusiveCopy: true, readlink: true, truncate: true,
|
|
605
|
+
streamingAppend: true, randomAccessWrite: true,
|
|
606
|
+
readOnly: false,
|
|
607
|
+
symlinks: true, conditionalChmod: true,
|
|
608
|
+
hardlinks: true,
|
|
609
|
+
permissions: true,
|
|
610
|
+
timestamps: true,
|
|
611
|
+
atomicRename: true,
|
|
612
|
+
atomicFileStaging: true, retainedStagingCleanup: true, retainedStagingWrite: true, atomicStagingAncestry: true, atomicFileMutation: true, atomicEntryRemoval: true, atomicEntryRemovalReceipt: true, atomicTreeRemoval: true,
|
|
613
|
+
synchronousDirectoryValidation: true, synchronousStagingResolution: true, guardedStagingPublication: true,
|
|
614
|
+
atomicDirectoryMetadata: true,
|
|
615
|
+
streamingRead: true,
|
|
616
|
+
retainedRead: true,
|
|
617
|
+
retainedResize: true,
|
|
618
|
+
streamingWrite: true,
|
|
619
|
+
descriptorWriteStream: true,
|
|
620
|
+
});
|
|
621
|
+
function customMemoryCapabilities(filesystem) {
|
|
622
|
+
return Object.freeze({
|
|
623
|
+
...SHARED_STOCK_MEMORY_CAPABILITIES,
|
|
624
|
+
get retainedResize() { return stockRetainedResize(filesystem); },
|
|
625
|
+
get descriptorWriteStream() { return stockDescriptorWrite(filesystem); },
|
|
626
|
+
});
|
|
627
|
+
}
|
|
593
628
|
export class MemoryFileSystem {
|
|
594
629
|
capabilitiesFor;
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
atomicRename: true,
|
|
608
|
-
atomicFileStaging: true, retainedStagingCleanup: true, retainedStagingWrite: true, atomicStagingAncestry: true, atomicFileMutation: true, atomicEntryRemoval: true, atomicEntryRemovalReceipt: true, atomicTreeRemoval: true,
|
|
609
|
-
synchronousDirectoryValidation: true, synchronousStagingResolution: true, guardedStagingPublication: true,
|
|
610
|
-
atomicDirectoryMetadata: true,
|
|
611
|
-
streamingRead: true,
|
|
612
|
-
retainedRead: true,
|
|
613
|
-
get retainedResize() { return stockRetainedResize(filesystem); },
|
|
614
|
-
streamingWrite: true,
|
|
615
|
-
get descriptorWriteStream() { return stockDescriptorWrite(filesystem); },
|
|
616
|
-
});
|
|
617
|
-
})(this);
|
|
618
|
-
identityScope = Symbol();
|
|
630
|
+
#customCapabilities;
|
|
631
|
+
#identityScopeSym;
|
|
632
|
+
get identityScope() {
|
|
633
|
+
return (this.#identityScopeSym ??= Symbol());
|
|
634
|
+
}
|
|
635
|
+
get capabilities() {
|
|
636
|
+
if (!this.#customCapabilities) {
|
|
637
|
+
this.#customCapabilities = customMemoryCapabilities(this);
|
|
638
|
+
this._owner.capabilities = this.#customCapabilities;
|
|
639
|
+
}
|
|
640
|
+
return this.#customCapabilities;
|
|
641
|
+
}
|
|
619
642
|
nextInode = 1;
|
|
620
643
|
ledger;
|
|
621
644
|
_cache;
|
|
@@ -624,26 +647,34 @@ export class MemoryFileSystem {
|
|
|
624
647
|
root;
|
|
625
648
|
totalBytes = 0;
|
|
626
649
|
symlinkCount = 0;
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
650
|
+
#atomicView;
|
|
651
|
+
_getAtomicView() {
|
|
652
|
+
const owner = ownedStores.get(this);
|
|
653
|
+
if (!owner ||
|
|
654
|
+
Object.getPrototypeOf(this) !== MemoryFileSystem.prototype ||
|
|
655
|
+
this.root !== owner.root ||
|
|
656
|
+
this.ledger !== owner.ledger ||
|
|
657
|
+
this.capabilities !== owner.capabilities) {
|
|
658
|
+
return undefined;
|
|
631
659
|
}
|
|
632
|
-
const
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
660
|
+
const proto = MemoryFileSystem.prototype;
|
|
661
|
+
for (let i = 0; i < memoryImplementationKeys.length; i++) {
|
|
662
|
+
const name = memoryImplementationKeys[i];
|
|
663
|
+
const expected = memoryImplementationDescriptors[i];
|
|
664
|
+
if (name === "capabilities")
|
|
665
|
+
continue;
|
|
666
|
+
if (Object.prototype.hasOwnProperty.call(this, name)) {
|
|
667
|
+
const actual = Object.getOwnPropertyDescriptor(this, name);
|
|
668
|
+
if (!actual || actual.value !== expected.value || actual.get !== expected.get || actual.set !== expected.set)
|
|
669
|
+
return undefined;
|
|
670
|
+
}
|
|
671
|
+
else if (expected.get !== undefined || expected.set !== undefined || proto[name] !== expected.value) {
|
|
672
|
+
const actual = Object.getOwnPropertyDescriptor(MemoryFileSystem.prototype, name);
|
|
673
|
+
if (!actual || actual.value !== expected.value || actual.get !== expected.get || actual.set !== expected.set)
|
|
674
|
+
return undefined;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
return this.#atomicView ??= {
|
|
647
678
|
stat: (path) => {
|
|
648
679
|
this.validatePath(path, "overlayAtomicView");
|
|
649
680
|
let node = this.root;
|
|
@@ -665,30 +696,28 @@ export class MemoryFileSystem {
|
|
|
665
696
|
this.fail("ENOTDIR", "overlayAtomicView", path);
|
|
666
697
|
return [...node.entries.keys()];
|
|
667
698
|
},
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
return true;
|
|
691
|
-
});
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
constructor(options = {}) {
|
|
702
|
+
this.ledger = new MemoryLedger(normalizeMemoryFileSystemLimits(options));
|
|
703
|
+
if (this.ledger.hasInfiniteRetained && this.ledger.hasInfiniteFileBytes) {
|
|
704
|
+
replenishSharedMemoryPools();
|
|
705
|
+
}
|
|
706
|
+
const cache = new MemoryCache();
|
|
707
|
+
this._cache = cache;
|
|
708
|
+
memoryCaches.set(this.ledger, cache);
|
|
709
|
+
this.ledger.reserve(0, 1, "mkdir", "/");
|
|
710
|
+
this.root = this.directory(0o755);
|
|
711
|
+
const root = this.root;
|
|
712
|
+
const owner = {
|
|
713
|
+
root,
|
|
714
|
+
ledger: this.ledger,
|
|
715
|
+
capabilities: SHARED_STOCK_MEMORY_CAPABILITIES,
|
|
716
|
+
intact: () => this.root === root,
|
|
717
|
+
};
|
|
718
|
+
this._owner = owner;
|
|
719
|
+
ownedStores.set(this, owner);
|
|
720
|
+
registerLazyMemoryAtomicView(this, memoryImplementation._getAtomicView.value);
|
|
692
721
|
if (this.compareEntry === memoryImplementation.compareEntry?.value) {
|
|
693
722
|
registeredAuthorities.add(this);
|
|
694
723
|
registerEntryAuthority(this, compareOwnedMemory);
|
|
@@ -2896,7 +2925,10 @@ export class MemoryFileSystem {
|
|
|
2896
2925
|
if (!descriptor || !("value" in descriptor) || descriptor.value !== memoryImplementation[name]?.value)
|
|
2897
2926
|
unsupported();
|
|
2898
2927
|
}
|
|
2899
|
-
const
|
|
2928
|
+
const capabilities = Object.getOwnPropertyDescriptor(this, "capabilities");
|
|
2929
|
+
const retainedRead = capabilities === undefined
|
|
2930
|
+
? Object.getOwnPropertyDescriptor(MemoryFileSystem.prototype, "capabilities")?.get === memoryImplementation.capabilities?.get
|
|
2931
|
+
: capabilities.value?.retainedRead;
|
|
2900
2932
|
signal?.throwIfAborted();
|
|
2901
2933
|
if (retainedRead !== true)
|
|
2902
2934
|
unsupported();
|
|
@@ -3036,7 +3068,7 @@ function stockDescriptorWrite(filesystem) {
|
|
|
3036
3068
|
return false;
|
|
3037
3069
|
const owner = ownedStores.get(filesystem);
|
|
3038
3070
|
const capDesc = Object.getOwnPropertyDescriptor(filesystem, "capabilities");
|
|
3039
|
-
return !!capDesc && "value" in capDesc && capDesc.value === owner.capabilities;
|
|
3071
|
+
return (capDesc === undefined && Object.getOwnPropertyDescriptor(MemoryFileSystem.prototype, "capabilities")?.get === memoryImplementation.capabilities?.get) || (!!capDesc && "value" in capDesc && capDesc.value === owner.capabilities);
|
|
3040
3072
|
}
|
|
3041
3073
|
function stockRetainedResize(filesystem) {
|
|
3042
3074
|
if (!stockDescriptorWrite(filesystem) || !isStockMemoryMethods(filesystem, stockRetainedResizeMethodNames, false))
|
|
@@ -3395,7 +3427,7 @@ export function tryResolveMemoryDevicePath(filesystem, path, resizeCreate) {
|
|
|
3395
3427
|
start = slash + 1;
|
|
3396
3428
|
}
|
|
3397
3429
|
}
|
|
3398
|
-
const cachedMethodValuesMap = new WeakMap();
|
|
3430
|
+
const cachedMethodValuesMap = /* @__PURE__ */ new WeakMap();
|
|
3399
3431
|
function getExpectedMethodValues(names) {
|
|
3400
3432
|
let vals = cachedMethodValuesMap.get(names);
|
|
3401
3433
|
if (!vals) {
|
|
@@ -3718,3 +3750,17 @@ export function tryWriteMemoryFileInDirSync(filesystem, dirPrefix, name, data, a
|
|
|
3718
3750
|
mem.writeMemoryFileInDirFast(dirPrefix, name, data, append, mode);
|
|
3719
3751
|
return true;
|
|
3720
3752
|
}
|
|
3753
|
+
const _memHooks = (globalThis.__safeBashMemHooks ??= { protos: new Set(), byProto: new Map() });
|
|
3754
|
+
_memHooks.protos.add(MemoryFileSystem.prototype);
|
|
3755
|
+
_memHooks.byProto.set(MemoryFileSystem.prototype, {
|
|
3756
|
+
tryGetMemoryDirectoryEntryNamesSync,
|
|
3757
|
+
tryReadMemoryFileViewSync,
|
|
3758
|
+
tryResolveMemoryDevicePath,
|
|
3759
|
+
tryOpenMemoryRedirectHandleSync,
|
|
3760
|
+
tryWriteMemoryFileSync,
|
|
3761
|
+
tryMkdirMemorySync,
|
|
3762
|
+
tryRmRfMemorySync,
|
|
3763
|
+
tryWriteMemoryFileInDirSync,
|
|
3764
|
+
});
|
|
3765
|
+
_memHooks.isCleanAbsolutePath = isCleanAbsolutePath;
|
|
3766
|
+
_memHooks.bindConditionalMutation = bindConditionalMutation;
|
|
@@ -7,6 +7,9 @@ export const defaultMemoryFileSystemLimits = Object.freeze({
|
|
|
7
7
|
maxMetadataUnits: Infinity,
|
|
8
8
|
});
|
|
9
9
|
export function normalizeMemoryFileSystemLimits(options) {
|
|
10
|
+
if (options === undefined || (typeof options === "object" && options !== null && Object.getPrototypeOf(options) === Object.prototype && Reflect.ownKeys(options).length === 0)) {
|
|
11
|
+
return defaultMemoryFileSystemLimits;
|
|
12
|
+
}
|
|
10
13
|
const keys = ["maxPathBytes", "maxPathComponents", "maxFileBytes", "maxRetainedBytes", "maxMetadataUnits"];
|
|
11
14
|
const record = readConfigRecord(options, "memory option", [...keys, "maxBytes"]);
|
|
12
15
|
const limits = { ...defaultMemoryFileSystemLimits };
|
|
@@ -29,7 +29,7 @@ export async function resolveEntryView(filesystem, path, options = {}) {
|
|
|
29
29
|
readOnly ||= location.readOnly === true || location.filesystem.capabilities.readOnly === true;
|
|
30
30
|
if (location.stat)
|
|
31
31
|
return { filesystem: location.filesystem, path: location.path, stat: location.stat, readOnly };
|
|
32
|
-
const resolve = resolvers.get(location.filesystem);
|
|
32
|
+
const resolve = resolvers.get(location.filesystem) ?? location.filesystem._resolveEntryView;
|
|
33
33
|
if (!resolve) {
|
|
34
34
|
let stat;
|
|
35
35
|
let followedPath;
|
|
@@ -49,7 +49,7 @@ export async function resolveEntryView(filesystem, path, options = {}) {
|
|
|
49
49
|
}
|
|
50
50
|
let next;
|
|
51
51
|
try {
|
|
52
|
-
next = await resolve(location.path, options);
|
|
52
|
+
next = await resolve.call(location.filesystem, location.path, options);
|
|
53
53
|
}
|
|
54
54
|
catch (error) {
|
|
55
55
|
options.signal?.throwIfAborted();
|
|
@@ -74,7 +74,7 @@ export async function compareResolvedEntries(own, peer, options = {}) {
|
|
|
74
74
|
let result = "unknown";
|
|
75
75
|
for (const [left, right] of [[own, peer], [peer, own]]) {
|
|
76
76
|
options.signal?.throwIfAborted();
|
|
77
|
-
const authority = authorities.get(left.filesystem);
|
|
77
|
+
const authority = authorities.get(left.filesystem) ?? left.filesystem._entryAuthority;
|
|
78
78
|
const key = authority ?? left.filesystem;
|
|
79
79
|
if (queried.has(key))
|
|
80
80
|
continue;
|
|
@@ -202,7 +202,7 @@ export class ReadOnlyFileSystem {
|
|
|
202
202
|
readOnly("openResizeFile", path);
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
|
-
const readOnlyImplementation = Object.getOwnPropertyDescriptors(ReadOnlyFileSystem.prototype);
|
|
205
|
+
const readOnlyImplementation = /* @__PURE__ */ Object.getOwnPropertyDescriptors(ReadOnlyFileSystem.prototype);
|
|
206
206
|
export function createReadOnlyFileSystem(filesystem) {
|
|
207
207
|
return new ReadOnlyFileSystem(filesystem);
|
|
208
208
|
}
|
|
@@ -1374,4 +1374,4 @@ export class WebDavFileSystem {
|
|
|
1374
1374
|
}
|
|
1375
1375
|
async truncate(path, _length, _options = {}) { this.unsupported("truncate", path); }
|
|
1376
1376
|
}
|
|
1377
|
-
const originalWebDavComparison = WebDavFileSystem.prototype.compareEntry;
|
|
1377
|
+
const originalWebDavComparison = /* @__PURE__ */ (() => WebDavFileSystem.prototype.compareEntry)();
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export * from "./contracts/errors.js";
|
|
2
|
+
export * from "./contracts/filesystem.js";
|
|
3
|
+
export * from "./contracts/io.js";
|
|
4
|
+
export { openFileDescriptor } from "./fs/descriptor.js";
|
|
5
|
+
export type { DescriptorBackend, DescriptorOpenOptions } from "./fs/descriptor.js";
|
|
6
|
+
export { assertPathWithin, isPathWithin, normalizePath, relativePath, resolvePath, validatePath } from "./contracts/virtual-path.js";
|
|
7
|
+
export { basename, dirname, extname, isAbsolutePath, joinPath, posixPath } from "./contracts/portable-path.js";
|
|
8
|
+
import type { FileSystem } from "./contracts/filesystem.js";
|
|
9
|
+
export type { MemoryFileSystem, MemoryFileSystemLimits, MemoryFileSystemOptions, MemoryRedirectHandle } from "./fs/memory/index.js";
|
|
10
|
+
export declare function isUnmodifiedMemoryFileSystem(fs: FileSystem): boolean;
|
|
11
|
+
export declare function isCleanAbsolutePath(p: string): boolean;
|
|
12
|
+
export declare function tryGetMemoryDirectoryEntryNamesSync(fs: FileSystem, path: string): any;
|
|
13
|
+
export declare function tryReadMemoryFileViewSync(fs: FileSystem, path: string, maxBytes?: number, signal?: AbortSignal, captureSourceRef?: boolean, beforeRead?: () => void): Uint8Array | undefined;
|
|
14
|
+
export declare function tryResolveMemoryDevicePath(fs: FileSystem, path: string, followFinal?: boolean): string | undefined;
|
|
15
|
+
export * from "./fs/devices/index.js";
|
|
16
|
+
export { retargetScopedFileSystem, scopeFileSystem, retainFileSystemCleanup } from "./fs/scoped.js";
|
|
17
|
+
export type { RetainedFileSystemCleanupView, RetainedFileSystemCleanupOptions } from "./fs/scoped.js";
|
|
18
|
+
export { compareEntries, registerEntryView } from "./fs/mount/comparison.js";
|
|
19
|
+
export type { EntryViewResolver } from "./fs/mount/comparison.js";
|
|
20
|
+
export type { ConditionalMutationBinding } from "./fs/memory/index.js";
|
|
21
|
+
export declare function bindConditionalMutation<Result>(identityScope: object | symbol | undefined, binding: any, action: () => Promise<Result>): Promise<Result>;
|
|
22
|
+
export declare function tryOpenMemoryRedirectHandleSync(fs: FileSystem, path: string, append: boolean, mode: number, signal?: AbortSignal): any;
|
|
23
|
+
export declare function tryWriteMemoryFileSync(fs: FileSystem, path: string, data: Uint8Array, append: boolean, mode: number, signal?: AbortSignal): boolean;
|
|
24
|
+
export declare function tryMkdirMemorySync(fs: FileSystem, path: string, recursive: boolean, mode: number, signal?: AbortSignal, dirPrefixHint?: string): boolean;
|
|
25
|
+
export declare function tryRmRfMemorySync(fs: FileSystem, path: string, signal?: AbortSignal): boolean;
|
|
26
|
+
export declare function tryWriteMemoryFileInDirSync(fs: FileSystem, dirPrefix: string, name: string, data: Uint8Array, append: boolean, mode: number, signal?: AbortSignal): boolean;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export * from "./contracts/errors.js";
|
|
2
|
+
export * from "./contracts/filesystem.js";
|
|
3
|
+
export * from "./contracts/io.js";
|
|
4
|
+
export { openFileDescriptor } from "./fs/descriptor.js";
|
|
5
|
+
export { assertPathWithin, isPathWithin, normalizePath, relativePath, resolvePath, validatePath } from "./contracts/virtual-path.js";
|
|
6
|
+
export { basename, dirname, extname, isAbsolutePath, joinPath, posixPath } from "./contracts/portable-path.js";
|
|
7
|
+
const _getMemHooks = () => globalThis.__safeBashMemHooks;
|
|
8
|
+
export function isUnmodifiedMemoryFileSystem(fs) {
|
|
9
|
+
const proto = Object.getPrototypeOf(fs);
|
|
10
|
+
if (!proto || !_getMemHooks()?.protos?.has(proto))
|
|
11
|
+
return false;
|
|
12
|
+
return Object.getOwnPropertyNames(fs).every(name => {
|
|
13
|
+
const method = Object.getOwnPropertyDescriptor(proto, name)?.value;
|
|
14
|
+
return typeof method !== "function" || Object.getOwnPropertyDescriptor(fs, name)?.value === method;
|
|
15
|
+
}) && Object.getOwnPropertyNames(proto).every(name => {
|
|
16
|
+
const method = Object.getOwnPropertyDescriptor(proto, name)?.value;
|
|
17
|
+
return typeof method !== "function" || Reflect.get(fs, name) === method;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
export function isCleanAbsolutePath(p) {
|
|
21
|
+
const fn = _getMemHooks()?.isCleanAbsolutePath;
|
|
22
|
+
if (fn)
|
|
23
|
+
return fn(p);
|
|
24
|
+
return p.length > 0 && p.charCodeAt(0) === 47 && !p.includes("//") && !p.includes("/.") && (p.length === 1 || p.charCodeAt(p.length - 1) !== 47);
|
|
25
|
+
}
|
|
26
|
+
export function tryGetMemoryDirectoryEntryNamesSync(fs, path) {
|
|
27
|
+
return (fs && _getMemHooks()?.byProto?.get(Object.getPrototypeOf(fs))?.tryGetMemoryDirectoryEntryNamesSync)?.(fs, path);
|
|
28
|
+
}
|
|
29
|
+
export function tryReadMemoryFileViewSync(fs, path, maxBytes, signal, captureSourceRef, beforeRead) {
|
|
30
|
+
return (fs && _getMemHooks()?.byProto?.get(Object.getPrototypeOf(fs))?.tryReadMemoryFileViewSync)?.(fs, path, maxBytes, signal, captureSourceRef, beforeRead);
|
|
31
|
+
}
|
|
32
|
+
export function tryResolveMemoryDevicePath(fs, path, followFinal) {
|
|
33
|
+
return (fs && _getMemHooks()?.byProto?.get(Object.getPrototypeOf(fs))?.tryResolveMemoryDevicePath)?.(fs, path, followFinal);
|
|
34
|
+
}
|
|
35
|
+
export * from "./fs/devices/index.js";
|
|
36
|
+
export { retargetScopedFileSystem, scopeFileSystem, retainFileSystemCleanup } from "./fs/scoped.js";
|
|
37
|
+
export { compareEntries, registerEntryView } from "./fs/mount/comparison.js";
|
|
38
|
+
export async function bindConditionalMutation(identityScope, binding, action) {
|
|
39
|
+
const fn = _getMemHooks()?.bindConditionalMutation;
|
|
40
|
+
return fn ? fn(identityScope, binding, action) : action();
|
|
41
|
+
}
|
|
42
|
+
export function tryOpenMemoryRedirectHandleSync(fs, path, append, mode, signal) {
|
|
43
|
+
return (fs && _getMemHooks()?.byProto?.get(Object.getPrototypeOf(fs))?.tryOpenMemoryRedirectHandleSync)?.(fs, path, append, mode, signal);
|
|
44
|
+
}
|
|
45
|
+
export function tryWriteMemoryFileSync(fs, path, data, append, mode, signal) {
|
|
46
|
+
return Boolean((fs && _getMemHooks()?.byProto?.get(Object.getPrototypeOf(fs))?.tryWriteMemoryFileSync)?.(fs, path, data, append, mode, signal));
|
|
47
|
+
}
|
|
48
|
+
export function tryMkdirMemorySync(fs, path, recursive, mode, signal, dirPrefixHint) {
|
|
49
|
+
return Boolean((fs && _getMemHooks()?.byProto?.get(Object.getPrototypeOf(fs))?.tryMkdirMemorySync)?.(fs, path, recursive, mode, signal, dirPrefixHint));
|
|
50
|
+
}
|
|
51
|
+
export function tryRmRfMemorySync(fs, path, signal) {
|
|
52
|
+
return Boolean((fs && _getMemHooks()?.byProto?.get(Object.getPrototypeOf(fs))?.tryRmRfMemorySync)?.(fs, path, signal));
|
|
53
|
+
}
|
|
54
|
+
export function tryWriteMemoryFileInDirSync(fs, dirPrefix, name, data, append, mode, signal) {
|
|
55
|
+
return Boolean((fs && _getMemHooks()?.byProto?.get(Object.getPrototypeOf(fs))?.tryWriteMemoryFileInDirSync)?.(fs, dirPrefix, name, data, append, mode, signal));
|
|
56
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@poe-platform/safe-fs",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.805",
|
|
4
4
|
"description": "Composable filesystem with a portable core and explicit Node adapters",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -126,6 +126,10 @@
|
|
|
126
126
|
"./contracts/errors": {
|
|
127
127
|
"types": "./dist/safe-fs/contracts/errors.d.ts",
|
|
128
128
|
"import": "./dist/safe-fs/contracts/errors.js"
|
|
129
|
+
},
|
|
130
|
+
"./runtime-core": {
|
|
131
|
+
"types": "./dist/safe-fs/runtime-core.d.ts",
|
|
132
|
+
"import": "./dist/safe-fs/runtime-core.js"
|
|
129
133
|
}
|
|
130
134
|
},
|
|
131
135
|
"repository": {
|