@poe-platform/safe-fs 0.1.502 → 0.1.504

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.
@@ -50,6 +50,7 @@ export interface FileSystemCapabilities {
50
50
  readonly permissions?: boolean;
51
51
  readonly timestamps?: boolean;
52
52
  readonly atomicRename?: boolean;
53
+ readonly atomicRenameNoReplace?: boolean;
53
54
  readonly snapshotRmdir?: boolean;
54
55
  readonly streamingRead?: boolean;
55
56
  readonly retainedRead?: boolean;
@@ -65,6 +66,9 @@ export interface FileReadHandle {
65
66
  read(position: number, maxBytes: number, options?: FsOptions): Promise<Uint8Array>;
66
67
  close(): Promise<void>;
67
68
  }
69
+ export interface RenameOptions extends FsOptions {
70
+ readonly noReplace?: boolean;
71
+ }
68
72
  export interface ReadFileOptions extends FsOptions {
69
73
  readonly maxBytes?: number;
70
74
  }
@@ -116,7 +120,7 @@ export interface FileSystem {
116
120
  mkdir(path: string, options?: MkdirOptions): Promise<void>;
117
121
  rm(path: string, options?: RemoveOptions): Promise<void>;
118
122
  rmdir?(path: string, options?: FsOptions): Promise<void>;
119
- rename(source: string, destination: string, options?: FsOptions): Promise<void>;
123
+ rename(source: string, destination: string, options?: RenameOptions): Promise<void>;
120
124
  copyFile(source: string, destination: string, options?: CopyFileOptions): Promise<void>;
121
125
  realpath(path: string, options?: FsOptions): Promise<string>;
122
126
  access(path: string, mode?: number, options?: FsOptions): Promise<void>;
@@ -38,7 +38,7 @@ export function readOnlyCapabilities(capabilities) {
38
38
  rename: false, copy: false, exclusiveCopy: false, truncate: false, streamingAppend: false,
39
39
  randomAccessWrite: false, hardlinks: false, permissions: false, timestamps: false,
40
40
  descriptorWriteStream: false,
41
- atomicRename: false, streamingWrite: false,
41
+ atomicRename: false, atomicRenameNoReplace: false, streamingWrite: false,
42
42
  });
43
43
  }
44
44
  export function quotaCapabilities(capabilities) {
@@ -1,4 +1,4 @@
1
- import type { AppendFileOptions, CopyFileOptions, DirectoryEntry, FileReadHandle, FileStat, FileSystem, FileSystemCapabilities, FsOptions, MkdirOptions, ReadDirectoryOptions, ReadFileOptions, ReadStreamOptions, RemoveOptions, WriteFileOptions } from "../../contracts/filesystem.js";
1
+ import type { AppendFileOptions, CopyFileOptions, DirectoryEntry, FileReadHandle, FileStat, FileSystem, FileSystemCapabilities, FsOptions, RenameOptions, MkdirOptions, ReadDirectoryOptions, ReadFileOptions, ReadStreamOptions, RemoveOptions, WriteFileOptions } from "../../contracts/filesystem.js";
2
2
  import type { ByteSource } from "../../contracts/io.js";
3
3
  export declare class DeviceFileSystem implements FileSystem {
4
4
  #private;
@@ -20,7 +20,7 @@ export declare class DeviceFileSystem implements FileSystem {
20
20
  mkdir(path: string, options?: MkdirOptions): Promise<void>;
21
21
  rm(path: string, options?: RemoveOptions): Promise<void>;
22
22
  rmdir(path: string, options?: FsOptions): Promise<void>;
23
- rename(source: string, destination: string, options?: FsOptions): Promise<void>;
23
+ rename(source: string, destination: string, options?: RenameOptions): Promise<void>;
24
24
  copyFile(source: string, destination: string, options?: CopyFileOptions): Promise<void>;
25
25
  access(path: string, mode?: number, options?: FsOptions): Promise<void>;
26
26
  readlink(path: string, options?: FsOptions): Promise<string>;
@@ -11,7 +11,7 @@ const deviceCapabilities = Object.freeze({
11
11
  remove: false, removeDirectory: false, recursiveRemove: false, rename: false,
12
12
  mkdir: false, recursiveMkdir: false, symlinks: false, hardlinks: false, readlink: false,
13
13
  permissions: false, timestamps: false, truncate: false, randomAccessWrite: false,
14
- atomicRename: false, descriptorWriteStream: true,
14
+ atomicRename: false, atomicRenameNoReplace: false, descriptorWriteStream: true,
15
15
  });
16
16
  function globalCapabilities(filesystem) {
17
17
  const capabilities = { readOnly: false };
@@ -278,6 +278,12 @@ export class DeviceFileSystem {
278
278
  async rename(source, destination, options = {}) {
279
279
  await this.#mutable(source, options, false);
280
280
  await this.#mutable(destination, options, false);
281
+ if (options.noReplace) {
282
+ const capabilities = await this.#filesystem.capabilitiesFor?.(destination, options) ?? this.#filesystem.capabilities;
283
+ options.signal?.throwIfAborted();
284
+ if (capabilities.atomicRenameNoReplace !== true)
285
+ throw new FsError("ENOTSUP", { syscall: "rename", path: source, dest: destination });
286
+ }
281
287
  await this.#filesystem.rename(source, destination, options);
282
288
  }
283
289
  async copyFile(source, destination, options = {}) {
@@ -1,4 +1,4 @@
1
- import type { AppendFileOptions, CopyFileOptions, DirectoryEntry, EntryComparison, FileReadHandle, FileStat, FileSystem, FsOptions, MkdirOptions, ReadDirectoryOptions, ReadFileOptions, ReadStreamOptions, RemoveOptions, WriteFileOptions } from "../../contracts/filesystem.js";
1
+ import type { AppendFileOptions, CopyFileOptions, DirectoryEntry, EntryComparison, FileReadHandle, FileStat, FileSystem, FsOptions, RenameOptions, MkdirOptions, ReadDirectoryOptions, ReadFileOptions, ReadStreamOptions, RemoveOptions, WriteFileOptions } from "../../contracts/filesystem.js";
2
2
  import type { ByteSource } from "../../contracts/io.js";
3
3
  import { type MemoryFileSystemOptions } from "./limits.js";
4
4
  export { defaultMemoryFileSystemLimits, type MemoryFileSystemLimits, type MemoryFileSystemOptions } from "./limits.js";
@@ -20,6 +20,7 @@ export declare class MemoryFileSystem implements FileSystem {
20
20
  removeDirectory: true;
21
21
  recursiveRemove: true;
22
22
  rename: true;
23
+ atomicRenameNoReplace: true;
23
24
  copy: true;
24
25
  exclusiveCopy: true;
25
26
  readlink: true;
@@ -76,7 +77,7 @@ export declare class MemoryFileSystem implements FileSystem {
76
77
  mkdir(path: string, options?: MkdirOptions): Promise<void>;
77
78
  rmdir(path: string, options?: FsOptions): Promise<void>;
78
79
  rm(path: string, options?: RemoveOptions): Promise<void>;
79
- rename(source: string, destination: string, options?: FsOptions): Promise<void>;
80
+ rename(source: string, destination: string, options?: RenameOptions): Promise<void>;
80
81
  copyFile(source: string, destination: string, options?: CopyFileOptions): Promise<void>;
81
82
  realpath(path: string, options?: FsOptions): Promise<string>;
82
83
  access(path: string, mode?: number, options?: FsOptions): Promise<void>;
@@ -57,7 +57,7 @@ export class MemoryFileSystem {
57
57
  read: true, stat: true, readdir: true, realpath: true, access: true,
58
58
  write: true, append: true, exclusiveCreate: true, explicitDirectories: true, implicitDirectories: false,
59
59
  mkdir: true, recursiveMkdir: true, remove: true, removeDirectory: true, recursiveRemove: true,
60
- rename: true, copy: true, exclusiveCopy: true, readlink: true, truncate: true,
60
+ rename: true, atomicRenameNoReplace: true, copy: true, exclusiveCopy: true, readlink: true, truncate: true,
61
61
  streamingAppend: true, randomAccessWrite: true,
62
62
  readOnly: false,
63
63
  symlinks: true,
@@ -515,6 +515,8 @@ export class MemoryFileSystem {
515
515
  this.fail("EBUSY", "rename", source, destination);
516
516
  if (destination.endsWith("/") && node.type !== "directory")
517
517
  this.fail("ENOTDIR", "rename", source, destination);
518
+ if (options.noReplace && target.node)
519
+ this.fail("EEXIST", "rename", source, destination);
518
520
  if (target.node === node)
519
521
  return;
520
522
  if (node.type === "directory" && target.path.startsWith(`${origin.path}/`))
@@ -1,4 +1,4 @@
1
- import type { AppendFileOptions, CopyFileOptions, DirectoryEntry, FileReadHandle, FileStat, FileSystem, FileSystemCapabilities, FsOptions, MkdirOptions, ReadDirectoryOptions, ReadFileOptions, ReadStreamOptions, RemoveOptions, WriteFileOptions } from "../../contracts/filesystem.js";
1
+ import type { AppendFileOptions, CopyFileOptions, DirectoryEntry, FileReadHandle, FileStat, FileSystem, FileSystemCapabilities, FsOptions, RenameOptions, MkdirOptions, ReadDirectoryOptions, ReadFileOptions, ReadStreamOptions, RemoveOptions, WriteFileOptions } from "../../contracts/filesystem.js";
2
2
  import type { ByteSource } from "../../contracts/io.js";
3
3
  export interface MountFileSystemOptions {
4
4
  readonly root: FileSystem;
@@ -29,7 +29,7 @@ export declare class MountFileSystem implements FileSystem {
29
29
  mkdir(path: string, options?: MkdirOptions): Promise<void>;
30
30
  rmdir(path: string, options?: FsOptions): Promise<void>;
31
31
  rm(path: string, options?: RemoveOptions): Promise<void>;
32
- rename(source: string, destination: string, options?: FsOptions): Promise<void>;
32
+ rename(source: string, destination: string, options?: RenameOptions): Promise<void>;
33
33
  copyFile(source: string, destination: string, options?: CopyFileOptions): Promise<void>;
34
34
  realpath(path: string, options?: FsOptions): Promise<string>;
35
35
  compareEntry(path: string, peer: FileSystem, peerPath: string, options?: FsOptions): Promise<import("../../contracts/filesystem.js").EntryComparison>;
@@ -96,14 +96,14 @@ export class MountFileSystem {
96
96
  return false;
97
97
  return declared === true && optional[capability]?.some(method => typeof backend[method] !== "function") ? false : declared;
98
98
  });
99
- if (["rename", "copy", "exclusiveCopy"].includes(capability) && mounts.length > 1)
99
+ if (["rename", "atomicRenameNoReplace", "copy", "exclusiveCopy"].includes(capability) && mounts.length > 1)
100
100
  return undefined;
101
101
  return values.every(value => value === true) ? true : values.every(value => value === false) ? false : undefined;
102
102
  };
103
103
  const semantics = Object.fromEntries([
104
104
  "read", "stat", "readdir", "realpath", "access",
105
105
  "write", "append", "exclusiveCreate", "explicitDirectories", "implicitDirectories", "mkdir", "recursiveMkdir",
106
- "remove", "removeDirectory", "recursiveRemove", "rename", "copy", "exclusiveCopy", "readlink", "truncate",
106
+ "remove", "removeDirectory", "recursiveRemove", "rename", "atomicRenameNoReplace", "copy", "exclusiveCopy", "readlink", "truncate",
107
107
  "streamingAppend", "randomAccessWrite", "descriptorWriteStream", "symlinks", "hardlinks", "permissions", "timestamps",
108
108
  ].map(capability => [capability, common(capability)]).filter(([, value]) => value !== undefined));
109
109
  this.capabilities = Object.freeze({
@@ -455,6 +455,12 @@ export class MountFileSystem {
455
455
  this.mutable(target);
456
456
  this.entryPath(source);
457
457
  this.entryPath(destination);
458
+ if (options.noReplace) {
459
+ const capabilities = await target.mount.backend.capabilitiesFor?.(target.local, options) ?? target.mount.backend.capabilities;
460
+ options.signal?.throwIfAborted();
461
+ if (capabilities.atomicRenameNoReplace !== true)
462
+ fail("ENOTSUP");
463
+ }
458
464
  await origin.mount.backend.rename(origin.local, target.local, options);
459
465
  }, destination);
460
466
  }
@@ -1,5 +1,5 @@
1
1
  import type { ByteSource } from "../../contracts/io.js";
2
- import type { AppendFileOptions, CopyFileOptions, DirectoryEntry, FileStat, FileSystem, FileSystemCapabilities, FsOptions, MkdirOptions, ReadDirectoryOptions, ReadFileOptions, ReadStreamOptions, RemoveOptions, WriteFileOptions } from "../../contracts/filesystem.js";
2
+ import type { AppendFileOptions, CopyFileOptions, DirectoryEntry, FileStat, FileSystem, FileSystemCapabilities, FsOptions, RenameOptions, MkdirOptions, ReadDirectoryOptions, ReadFileOptions, ReadStreamOptions, RemoveOptions, WriteFileOptions } from "../../contracts/filesystem.js";
3
3
  export interface OverlayFileSystemOptions {
4
4
  readonly upper: FileSystem;
5
5
  readonly lower: FileSystem;
@@ -58,7 +58,7 @@ export declare class OverlayFileSystem implements FileSystem {
58
58
  rmdir(path: string, options?: FsOptions): Promise<void>;
59
59
  rm(path: string, options?: RemoveOptions): Promise<void>;
60
60
  private materialize;
61
- rename(source: string, destination: string, options?: FsOptions): Promise<void>;
61
+ rename(source: string, destination: string, options?: RenameOptions): Promise<void>;
62
62
  copyFile(source: string, destination: string, options?: CopyFileOptions): Promise<void>;
63
63
  readlink(path: string, options?: FsOptions): Promise<string>;
64
64
  symlink(target: string, path: string, options?: FsOptions): Promise<void>;
@@ -117,7 +117,7 @@ export class OverlayFileSystem {
117
117
  : upper.readlink === false && this.#lower.capabilities.readlink === false ? false : undefined,
118
118
  ...(upper.readOnly === undefined ? {} : { readOnly: upper.readOnly }),
119
119
  ...(effectiveAppend === undefined ? {} : { append: effectiveAppend }),
120
- atomicRename: false,
120
+ atomicRename: false, atomicRenameNoReplace: false,
121
121
  descriptorWriteStream: false,
122
122
  hardlinks: false,
123
123
  symlinks: writable && this.#upper.capabilities.symlinks === true
@@ -737,6 +737,8 @@ export class OverlayFileSystem {
737
737
  }
738
738
  async rename(source, destination, options = {}) {
739
739
  return this.run(options, async () => {
740
+ if (options.noReplace)
741
+ fail("ENOTSUP", source, "atomic no-replace rename is unsupported");
740
742
  this.writable(source);
741
743
  const original = await this.required(source, options, false);
742
744
  const target = await this.resolve(destination, options, false, true);
@@ -130,6 +130,16 @@ export function withFileSystemQuota(fs, options) {
130
130
  await fs.appendFile(path, data, appendOptions);
131
131
  });
132
132
  },
133
+ async rename(source, destination, renameOptions) {
134
+ if (renameOptions?.noReplace) {
135
+ renameOptions.signal?.throwIfAborted();
136
+ const capabilities = await fs.capabilitiesFor?.(destination, renameOptions) ?? fs.capabilities;
137
+ renameOptions?.signal?.throwIfAborted();
138
+ if (capabilities.atomicRenameNoReplace !== true)
139
+ throw new FsError("ENOTSUP", { syscall: "rename", path: source, dest: destination });
140
+ }
141
+ await fs.rename(source, destination, renameOptions);
142
+ },
133
143
  copyFile(source, destination, copyOptions) {
134
144
  return mutate(async () => {
135
145
  await assertDelta(destination, (await fs.stat(source, copyOptions)).size, copyOptions);
@@ -1,5 +1,5 @@
1
1
  import type { ByteSource } from "../../contracts/io.js";
2
- import type { AppendFileOptions, CopyFileOptions, DirectoryEntry, FileStat, FileSystem, FileSystemCapabilities, FsOptions, MkdirOptions, ReadDirectoryOptions, ReadFileOptions, ReadStreamOptions, RemoveOptions, WriteFileOptions } from "../../contracts/filesystem.js";
2
+ import type { AppendFileOptions, CopyFileOptions, DirectoryEntry, FileStat, FileSystem, FileSystemCapabilities, FsOptions, RenameOptions, MkdirOptions, ReadDirectoryOptions, ReadFileOptions, ReadStreamOptions, RemoveOptions, WriteFileOptions } from "../../contracts/filesystem.js";
3
3
  export declare class ReadOnlyFileSystem implements FileSystem {
4
4
  #private;
5
5
  constructor(filesystem: FileSystem);
@@ -22,7 +22,7 @@ export declare class ReadOnlyFileSystem implements FileSystem {
22
22
  rm(path: string, _options?: RemoveOptions): Promise<void>;
23
23
  unlink(path: string, _options?: FsOptions): Promise<void>;
24
24
  rmdir(path: string, _options?: FsOptions): Promise<void>;
25
- rename(source: string, destination: string, _options?: FsOptions): Promise<void>;
25
+ rename(source: string, destination: string, _options?: RenameOptions): Promise<void>;
26
26
  copyFile(source: string, destination: string, _options?: CopyFileOptions): Promise<void>;
27
27
  symlink(target: string, path: string, _options?: FsOptions): Promise<void>;
28
28
  link(existingPath: string, newPath: string, _options?: FsOptions): Promise<void>;
@@ -1,4 +1,4 @@
1
- import type { AppendFileOptions, ByteSource, CopyFileOptions, DirectoryEntry, FileReadHandle, FileStat, FileSystem, FileSystemCapabilities, FsOptions, MkdirOptions, ReadDirectoryOptions, ReadFileOptions, ReadStreamOptions, RemoveOptions, WriteFileOptions } from "../../contracts/index.js";
1
+ import type { AppendFileOptions, ByteSource, CopyFileOptions, DirectoryEntry, FileReadHandle, FileStat, FileSystem, FileSystemCapabilities, FsOptions, RenameOptions, MkdirOptions, ReadDirectoryOptions, ReadFileOptions, ReadStreamOptions, RemoveOptions, WriteFileOptions } from "../../contracts/index.js";
2
2
  export interface RealFileSystemOptions {
3
3
  /** An existing, absolute host directory. It is never created implicitly. */
4
4
  readonly root: string;
@@ -59,7 +59,7 @@ export declare class RealFileSystem implements FileSystem {
59
59
  mkdir(path: string, options?: MkdirOptions): Promise<void>;
60
60
  rmdir(path: string, options?: FsOptions): Promise<void>;
61
61
  rm(path: string, options?: RemoveOptions): Promise<void>;
62
- rename(source: string, destination: string, options?: FsOptions): Promise<void>;
62
+ rename(source: string, destination: string, options?: RenameOptions): Promise<void>;
63
63
  copyFile(source: string, destination: string, options?: CopyFileOptions): Promise<void>;
64
64
  realpath(path: string, options?: FsOptions): Promise<string>;
65
65
  access(path: string, mode?: number, options?: FsOptions): Promise<void>;
@@ -84,7 +84,7 @@ export class RealFileSystem {
84
84
  read: true, stat: true, readdir: true, realpath: true, access: true,
85
85
  write: true, append: true, exclusiveCreate: true, explicitDirectories: true, implicitDirectories: false,
86
86
  mkdir: true, recursiveMkdir: true, remove: true, removeDirectory: true, recursiveRemove: true,
87
- rename: true, copy: true, exclusiveCopy: true, readlink: true, truncate: true,
87
+ rename: true, atomicRenameNoReplace: false, copy: true, exclusiveCopy: true, readlink: true, truncate: true,
88
88
  streamingAppend: true, randomAccessWrite: true,
89
89
  readOnly: false, symlinks: true, hardlinks: true, permissions: true,
90
90
  timestamps: true, atomicRename: true, streamingRead: true, streamingWrite: true, retainedRead: true,
@@ -346,6 +346,8 @@ export class RealFileSystem {
346
346
  }
347
347
  async rename(source, destination, options = {}) {
348
348
  return this.operation("rename", source, options, async () => {
349
+ if (options.noReplace)
350
+ throw new FsError("ENOTSUP", { syscall: "rename", path: source, dest: destination });
349
351
  const from = await this.path(source, { ...options, followFinal: false });
350
352
  const to = await this.path(destination, { ...options, followFinal: false, missing: "final" });
351
353
  this.protectTerminal(source);
@@ -1,5 +1,5 @@
1
1
  import { FsError } from "../../contracts/errors.js";
2
- import type { AppendFileOptions, CopyFileOptions, DirectoryEntry, EntryComparison, FileStat, FileSystem, FsOptions, MkdirOptions, ReadDirectoryOptions, ReadFileOptions, ReadStreamOptions, RemoveOptions, WriteFileOptions } from "../../contracts/filesystem.js";
2
+ import type { AppendFileOptions, CopyFileOptions, DirectoryEntry, EntryComparison, FileStat, FileSystem, FsOptions, RenameOptions, MkdirOptions, ReadDirectoryOptions, ReadFileOptions, ReadStreamOptions, RemoveOptions, WriteFileOptions } from "../../contracts/filesystem.js";
3
3
  import type { ByteSource } from "../../contracts/io.js";
4
4
  import type { S3Transport } from "./transport.js";
5
5
  export interface S3FileSystemOptions {
@@ -41,6 +41,7 @@ export declare class S3FileSystem implements FileSystem {
41
41
  append: boolean;
42
42
  exclusiveCreate: boolean;
43
43
  truncate: boolean;
44
+ atomicRenameNoReplace: false;
44
45
  rename: boolean;
45
46
  streamingAppend: boolean;
46
47
  randomAccessWrite: false;
@@ -99,7 +100,7 @@ export declare class S3FileSystem implements FileSystem {
99
100
  rm(input: string, options?: RemoveOptions): Promise<void>;
100
101
  private copy;
101
102
  copyFile(sourceInput: string, destinationInput: string, options?: CopyFileOptions): Promise<void>;
102
- rename(sourceInput: string, destinationInput: string, options?: FsOptions): Promise<void>;
103
+ rename(sourceInput: string, destinationInput: string, options?: RenameOptions): Promise<void>;
103
104
  private copyWithPut;
104
105
  realpath(input: string, options?: FsOptions): Promise<string>;
105
106
  access(path: string, mode?: number, options?: FsOptions): Promise<void>;
@@ -112,6 +112,7 @@ export class S3FileSystem {
112
112
  append: options.transport.capabilities?.conditionalPut === true,
113
113
  exclusiveCreate: options.transport.capabilities?.conditionalPut === true,
114
114
  truncate: options.transport.capabilities?.conditionalPut === true,
115
+ atomicRenameNoReplace: false,
115
116
  rename: this.allowRename && options.transport.capabilities?.conditionalDelete === true
116
117
  && (options.transport.capabilities?.conditionalCopy === true || options.transport.capabilities?.conditionalPut === true),
117
118
  streamingAppend: options.transport.capabilities?.streamingWrite === true
@@ -674,6 +675,10 @@ export class S3FileSystem {
674
675
  }
675
676
  }
676
677
  async rename(sourceInput, destinationInput, options = {}) {
678
+ if (options.noReplace) {
679
+ options.signal?.throwIfAborted();
680
+ this.unsupported("atomic no-replace rename", sourceInput);
681
+ }
677
682
  const source = this.path(sourceInput);
678
683
  const destination = this.path(destinationInput);
679
684
  this.writable(destination);
@@ -1,3 +1,4 @@
1
+ import { FsError } from "../contracts/errors.js";
1
2
  import { finishCleanup } from "../contracts/cleanup.js";
2
3
  import { registerEntryView } from "./mount/comparison.js";
3
4
  const originals = new WeakMap();
@@ -76,6 +77,17 @@ export function scopeFileSystem(filesystem, charge, signal) {
76
77
  const peer = args[1];
77
78
  args[1] = originals.get(peer) ?? peer;
78
79
  }
80
+ if (property === "rename" && args[2]?.noReplace)
81
+ return (async () => {
82
+ const options = args[2];
83
+ const capabilities = await original.capabilitiesFor?.(args[1], options) ?? original.capabilities;
84
+ assertOpen(options);
85
+ if (capabilities.atomicRenameNoReplace !== true)
86
+ throw new FsError("ENOTSUP", {
87
+ syscall: "rename", path: args[0], dest: args[1],
88
+ });
89
+ return Reflect.apply(method, original, args);
90
+ })();
79
91
  return Reflect.apply(method, original, args);
80
92
  };
81
93
  const scoped = property === "openReadFile"
@@ -1,6 +1,6 @@
1
1
  import type { PlatformComparisonCallback } from "#safe-fs-platform";
2
2
  import type { ByteSource } from "../../contracts/io.js";
3
- import type { AppendFileOptions, CopyFileOptions, DirectoryEntry, EntryComparison, FileStat, FileSystem, FsOptions, MkdirOptions, ReadDirectoryOptions, ReadFileOptions, ReadStreamOptions, RemoveOptions, WriteFileOptions } from "../../contracts/filesystem.js";
3
+ import type { AppendFileOptions, CopyFileOptions, DirectoryEntry, EntryComparison, FileStat, FileSystem, FsOptions, RenameOptions, MkdirOptions, ReadDirectoryOptions, ReadFileOptions, ReadStreamOptions, RemoveOptions, WriteFileOptions } from "../../contracts/filesystem.js";
4
4
  export type WebDavFetch = (url: string, init: RequestInit) => Promise<Response>;
5
5
  export interface WebDavAtomicEmptyDirectoryRequest {
6
6
  readonly operation: "atomic-empty-rmdir/v1";
@@ -49,6 +49,7 @@ export declare class WebDavFileSystem implements FileSystem {
49
49
  remove: true;
50
50
  recursiveRemove: true;
51
51
  rename: true;
52
+ atomicRenameNoReplace: false;
52
53
  copy: true;
53
54
  exclusiveCopy: true;
54
55
  readlink: false;
@@ -114,7 +115,7 @@ export declare class WebDavFileSystem implements FileSystem {
114
115
  private guardTransferIdentity;
115
116
  private transfer;
116
117
  private withDestinationLock;
117
- rename(source: string, destination: string, options?: FsOptions): Promise<void>;
118
+ rename(source: string, destination: string, options?: RenameOptions): Promise<void>;
118
119
  copyFile(source: string, destination: string, options?: CopyFileOptions): Promise<void>;
119
120
  realpath(path: string, options?: FsOptions): Promise<string>;
120
121
  access(path: string, mode?: number, options?: FsOptions): Promise<void>;
@@ -143,7 +143,7 @@ export class WebDavFileSystem {
143
143
  capabilities = Object.freeze({
144
144
  read: true, stat: true, readdir: true, realpath: true, access: true,
145
145
  write: true, append: true, exclusiveCreate: true, explicitDirectories: true, implicitDirectories: false,
146
- mkdir: true, recursiveMkdir: true, remove: true, recursiveRemove: true, rename: true, copy: true,
146
+ mkdir: true, recursiveMkdir: true, remove: true, recursiveRemove: true, rename: true, atomicRenameNoReplace: false, copy: true,
147
147
  exclusiveCopy: true, readlink: false, truncate: false, randomAccessWrite: false,
148
148
  removeDirectory: false, streamingAppend: false,
149
149
  symlinks: false, hardlinks: false, permissions: false, timestamps: true,
@@ -1192,6 +1192,10 @@ export class WebDavFileSystem {
1192
1192
  }
1193
1193
  }
1194
1194
  async rename(source, destination, options = {}) {
1195
+ if (options.noReplace) {
1196
+ options.signal?.throwIfAborted();
1197
+ fail("ENOTSUP", "rename", source, "atomic no-replace rename is unsupported");
1198
+ }
1195
1199
  await this.transfer("MOVE", source, destination, options);
1196
1200
  }
1197
1201
  async copyFile(source, destination, options = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poe-platform/safe-fs",
3
- "version": "0.1.502",
3
+ "version": "0.1.504",
4
4
  "description": "Composable filesystem with a portable core and explicit Node adapters",
5
5
  "type": "module",
6
6
  "license": "MIT",