@poe-platform/safe-fs 0.1.531 → 0.1.533
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/core.d.ts
CHANGED
|
@@ -9,7 +9,8 @@ export * from "./fs/readonly/index.js";
|
|
|
9
9
|
export * from "./fs/mount/index.js";
|
|
10
10
|
export * from "./fs/overlay/index.js";
|
|
11
11
|
export * from "./fs/quota/index.js";
|
|
12
|
-
export { scopeFileSystem } from "./fs/scoped.js";
|
|
12
|
+
export { scopeFileSystem, retainFileSystemCleanup } from "./fs/scoped.js";
|
|
13
|
+
export type { RetainedFileSystemCleanupView, RetainedFileSystemCleanupOptions } from "./fs/scoped.js";
|
|
13
14
|
export * from "./fs/webdav/index.js";
|
|
14
15
|
export * from "./bridge/index.js";
|
|
15
16
|
export { compareEntries } from "./fs/mount/comparison.js";
|
package/dist/safe-fs/core.js
CHANGED
|
@@ -9,7 +9,7 @@ export * from "./fs/readonly/index.js";
|
|
|
9
9
|
export * from "./fs/mount/index.js";
|
|
10
10
|
export * from "./fs/overlay/index.js";
|
|
11
11
|
export * from "./fs/quota/index.js";
|
|
12
|
-
export { scopeFileSystem } from "./fs/scoped.js";
|
|
12
|
+
export { scopeFileSystem, retainFileSystemCleanup } from "./fs/scoped.js";
|
|
13
13
|
export * from "./fs/webdav/index.js";
|
|
14
14
|
export * from "./bridge/index.js";
|
|
15
15
|
export { compareEntries } from "./fs/mount/comparison.js";
|
|
@@ -1,2 +1,12 @@
|
|
|
1
|
-
import type { FileSystem } from "../contracts/filesystem.js";
|
|
2
|
-
export declare function scopeFileSystem(filesystem: FileSystem, charge: () => void, signal: AbortSignal): FileSystem;
|
|
1
|
+
import type { FileSystem, FsOptions } from "../contracts/filesystem.js";
|
|
2
|
+
export declare function scopeFileSystem(filesystem: FileSystem, charge: () => void, signal: AbortSignal, cleanupCharge?: () => void): FileSystem;
|
|
3
|
+
export interface RetainedFileSystemCleanupView {
|
|
4
|
+
readonly lstat: FileSystem["lstat"];
|
|
5
|
+
readonly realpath: FileSystem["realpath"];
|
|
6
|
+
readonly rm: (path: string, options?: FsOptions) => Promise<void>;
|
|
7
|
+
readonly rmdir?: NonNullable<FileSystem["rmdir"]>;
|
|
8
|
+
}
|
|
9
|
+
export interface RetainedFileSystemCleanupOptions {
|
|
10
|
+
readonly maxOperations?: number;
|
|
11
|
+
}
|
|
12
|
+
export declare function retainFileSystemCleanup(filesystem: FileSystem, cleanupCallback: (view: RetainedFileSystemCleanupView) => void | PromiseLike<void>, options?: RetainedFileSystemCleanupOptions): () => Promise<void>;
|
|
@@ -9,8 +9,8 @@ const operations = new Set([
|
|
|
9
9
|
"readlink", "realpath", "rename", "rm", "rmdir", "stat", "symlink", "truncate", "utimes",
|
|
10
10
|
"writeFile", "writeStream",
|
|
11
11
|
]);
|
|
12
|
-
export function scopeFileSystem(filesystem, charge, signal) {
|
|
13
|
-
const original = originals.get(filesystem) ?? filesystem;
|
|
12
|
+
export function scopeFileSystem(filesystem, charge, signal, cleanupCharge = charge) {
|
|
13
|
+
const original = originals.get(filesystem)?.filesystem ?? filesystem;
|
|
14
14
|
const methods = new Map();
|
|
15
15
|
const assertOpen = (options) => {
|
|
16
16
|
signal.throwIfAborted();
|
|
@@ -165,7 +165,7 @@ export function scopeFileSystem(filesystem, charge, signal) {
|
|
|
165
165
|
}
|
|
166
166
|
if (property === "compareEntry") {
|
|
167
167
|
const peer = args[1];
|
|
168
|
-
args[1] = originals.get(peer) ?? peer;
|
|
168
|
+
args[1] = originals.get(peer)?.filesystem ?? peer;
|
|
169
169
|
}
|
|
170
170
|
if (property === "rename" && args[2]?.noReplace)
|
|
171
171
|
return (async () => {
|
|
@@ -199,10 +199,94 @@ export function scopeFileSystem(filesystem, charge, signal) {
|
|
|
199
199
|
return scoped;
|
|
200
200
|
},
|
|
201
201
|
});
|
|
202
|
-
originals.set(view, original);
|
|
202
|
+
originals.set(view, { filesystem: original, signal, cleanupCharge });
|
|
203
203
|
registerEntryView(view, async (path, options) => {
|
|
204
204
|
assertOpen(options);
|
|
205
205
|
return { filesystem: original, path };
|
|
206
206
|
});
|
|
207
207
|
return view;
|
|
208
208
|
}
|
|
209
|
+
export function retainFileSystemCleanup(filesystem, cleanupCallback, options) {
|
|
210
|
+
const maximum = options?.maxOperations === undefined ? 256 : options.maxOperations;
|
|
211
|
+
if (!Number.isSafeInteger(maximum) || maximum < 0 || maximum > 4096)
|
|
212
|
+
throw new RangeError("cleanup maxOperations must be an integer between 0 and 4096");
|
|
213
|
+
if (typeof cleanupCallback !== "function")
|
|
214
|
+
throw new TypeError("cleanup callback must be a function");
|
|
215
|
+
const scope = originals.get(filesystem);
|
|
216
|
+
scope?.signal.throwIfAborted();
|
|
217
|
+
const backing = scope?.filesystem ?? filesystem;
|
|
218
|
+
const pending = new Set();
|
|
219
|
+
let operations = 0;
|
|
220
|
+
let active = false;
|
|
221
|
+
let closing;
|
|
222
|
+
const invoke = (method, path, settings) => {
|
|
223
|
+
if (!active) {
|
|
224
|
+
const rejected = Promise.reject(new FsError("EBADF", { syscall: method, path, message: "cleanup callback is not active" }));
|
|
225
|
+
void rejected.catch(() => { });
|
|
226
|
+
return rejected;
|
|
227
|
+
}
|
|
228
|
+
let result;
|
|
229
|
+
try {
|
|
230
|
+
settings?.signal?.throwIfAborted();
|
|
231
|
+
if (operations >= maximum)
|
|
232
|
+
throw new FsError("EFBIG", { syscall: method, path, message: "cleanup operation limit exceeded" });
|
|
233
|
+
operations++;
|
|
234
|
+
scope?.cleanupCharge();
|
|
235
|
+
settings?.signal?.throwIfAborted();
|
|
236
|
+
const operation = backing[method];
|
|
237
|
+
if (typeof operation !== "function")
|
|
238
|
+
throw new FsError("ENOTSUP", { syscall: method, path });
|
|
239
|
+
const parameters = method === "rm" ? { ...settings, recursive: false, force: false } : settings;
|
|
240
|
+
result = Promise.resolve(Reflect.apply(operation, backing, [path, parameters]));
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
result = Promise.reject(error);
|
|
244
|
+
void result.catch(() => { });
|
|
245
|
+
return result;
|
|
246
|
+
}
|
|
247
|
+
const completion = result.then(() => { pending.delete(completion); return { status: "fulfilled", value: undefined }; }, error => { pending.delete(completion); return { status: "rejected", reason: error }; });
|
|
248
|
+
pending.add(completion);
|
|
249
|
+
return result;
|
|
250
|
+
};
|
|
251
|
+
const view = Object.freeze(Object.assign(Object.create(null), {
|
|
252
|
+
lstat: invoke.bind(undefined, "lstat"),
|
|
253
|
+
realpath: invoke.bind(undefined, "realpath"),
|
|
254
|
+
rm: invoke.bind(undefined, "rm"),
|
|
255
|
+
...(typeof backing.rmdir === "function" ? { rmdir: invoke.bind(undefined, "rmdir") } : {}),
|
|
256
|
+
}));
|
|
257
|
+
scope?.signal.throwIfAborted();
|
|
258
|
+
return () => {
|
|
259
|
+
if (!closing) {
|
|
260
|
+
closing = Promise.resolve().then(async () => {
|
|
261
|
+
active = true;
|
|
262
|
+
let callbackFailed = false;
|
|
263
|
+
let callbackFailure;
|
|
264
|
+
try {
|
|
265
|
+
const result = cleanupCallback(view);
|
|
266
|
+
if (result !== undefined)
|
|
267
|
+
await result;
|
|
268
|
+
}
|
|
269
|
+
catch (error) {
|
|
270
|
+
callbackFailed = true;
|
|
271
|
+
callbackFailure = error;
|
|
272
|
+
}
|
|
273
|
+
finally {
|
|
274
|
+
active = false;
|
|
275
|
+
}
|
|
276
|
+
const outcomes = await Promise.all(pending);
|
|
277
|
+
if (callbackFailed)
|
|
278
|
+
throw callbackFailure;
|
|
279
|
+
const failures = [];
|
|
280
|
+
for (const outcome of outcomes)
|
|
281
|
+
if (outcome.status === "rejected")
|
|
282
|
+
failures.push(outcome.reason);
|
|
283
|
+
if (failures.length === 1)
|
|
284
|
+
throw failures[0];
|
|
285
|
+
if (failures.length > 1)
|
|
286
|
+
throw new AggregateError(failures, "retained filesystem cleanup failed");
|
|
287
|
+
});
|
|
288
|
+
void closing.catch(() => { });
|
|
289
|
+
}
|
|
290
|
+
return closing;
|
|
291
|
+
};
|
|
292
|
+
}
|
package/dist/safe-fs/index.d.ts
CHANGED
|
@@ -10,7 +10,8 @@ export * from "./fs/readonly/index.js";
|
|
|
10
10
|
export * from "./fs/mount/index.js";
|
|
11
11
|
export * from "./fs/overlay/index.js";
|
|
12
12
|
export * from "./fs/quota/index.js";
|
|
13
|
-
export { scopeFileSystem } from "./fs/scoped.js";
|
|
13
|
+
export { scopeFileSystem, retainFileSystemCleanup } from "./fs/scoped.js";
|
|
14
|
+
export type { RetainedFileSystemCleanupView, RetainedFileSystemCleanupOptions } from "./fs/scoped.js";
|
|
14
15
|
export * from "./node/index.js";
|
|
15
16
|
export { createFileSystem, readConfigRecord, validateFileSystemConfig } from "./config.js";
|
|
16
17
|
export type { FileSystemConfig, FileSystemAdapterDescriptor, FileSystemAdapterRegistry } from "./config.js";
|
package/dist/safe-fs/index.js
CHANGED
|
@@ -9,7 +9,7 @@ export * from "./fs/readonly/index.js";
|
|
|
9
9
|
export * from "./fs/mount/index.js";
|
|
10
10
|
export * from "./fs/overlay/index.js";
|
|
11
11
|
export * from "./fs/quota/index.js";
|
|
12
|
-
export { scopeFileSystem } from "./fs/scoped.js";
|
|
12
|
+
export { scopeFileSystem, retainFileSystemCleanup } from "./fs/scoped.js";
|
|
13
13
|
export * from "./node/index.js";
|
|
14
14
|
export { createFileSystem, readConfigRecord, validateFileSystemConfig } from "./config.js";
|
|
15
15
|
export { createNodeFileSystemAdapterRegistry } from "./config.node.js";
|