@statewalker/webrun-files-browser 0.7.0 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -107,7 +107,7 @@ class BrowserFilesApi implements FilesApi {
107
107
  stats(path: string): Promise<FileStats | undefined>;
108
108
  exists(path: string): Promise<boolean>;
109
109
  remove(path: string): Promise<boolean>;
110
- move(source: string, target: string): Promise<boolean>;
110
+ move(source: string, target: string): Promise<boolean>; // uses native move when available
111
111
  copy(source: string, target: string): Promise<boolean>;
112
112
  }
113
113
  ```
@@ -141,11 +141,15 @@ function verifyPermission(
141
141
  ): Promise<boolean>;
142
142
  ```
143
143
 
144
+ ## Native Move Support
145
+
146
+ The `move()` method attempts to use the browser's native [`FileSystemHandle.move()`](https://developer.mozilla.org/en-US/docs/Web/API/FileSystemHandle/move) when available (Chrome 110+, Edge 110+). This provides an atomic, in-place rename/move without copying file data. On older browsers or polyfills that lack native `move()`, the method falls back to copy-then-delete.
147
+
144
148
  ## Browser Support
145
149
 
146
150
  The File System Access API is supported in:
147
151
 
148
- - Chrome/Edge 86+
152
+ - Chrome/Edge 86+ (native `move()` from 110+)
149
153
  - Opera 72+
150
154
  - Chrome for Android 86+
151
155
 
@@ -1 +1 @@
1
- {"version":3,"file":"browser-files-api.d.ts","sourceRoot":"","sources":["../src/browser-files-api.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,WAAW,EACX,WAAW,EACZ,MAAM,2BAA2B,CAAC;AAGnC,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,UAAU,EAAE,yBAAyB,CAAC;CACvC;AAED;;;;;;GAMG;AACH,qBAAa,eAAgB,YAAW,QAAQ;IAC9C,OAAO,CAAC,UAAU,CAA4B;gBAElC,OAAO,EAAE,sBAAsB;YAI7B,kBAAkB;YAkBlB,aAAa;IAkBpB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,aAAa,CAAC,UAAU,CAAC;IA6BrE,KAAK,CACT,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,aAAa,CAAC,UAAU,CAAC,GACxD,OAAO,CAAC,IAAI,CAAC;IAsBV,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,aAAa,CAAC,QAAQ,CAAC;IAqCnE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAqCnD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKtC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAgBtC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAMtD,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CA4E7D;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,eAAe,CAAC,CAGhE"}
1
+ {"version":3,"file":"browser-files-api.d.ts","sourceRoot":"","sources":["../src/browser-files-api.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,WAAW,EACX,WAAW,EACZ,MAAM,2BAA2B,CAAC;AAQnC,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,UAAU,EAAE,yBAAyB,CAAC;CACvC;AAED;;;;;;GAMG;AACH,qBAAa,eAAgB,YAAW,QAAQ;IAC9C,OAAO,CAAC,UAAU,CAA4B;gBAElC,OAAO,EAAE,sBAAsB;YAI7B,kBAAkB;YAkBlB,aAAa;IAkBpB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,aAAa,CAAC,UAAU,CAAC;IA6BrE,KAAK,CACT,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,aAAa,CAAC,UAAU,CAAC,GACxD,OAAO,CAAC,IAAI,CAAC;IAsBV,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,aAAa,CAAC,QAAQ,CAAC;IAqCnE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAqCnD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKtC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAgBtC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAgCtD,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CA4E7D;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,eAAe,CAAC,CAGhE"}
@@ -1,5 +1,5 @@
1
- let __statewalker_webrun_files = require("@statewalker/webrun-files");
2
-
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let _statewalker_webrun_files = require("@statewalker/webrun-files");
3
3
  //#region src/browser-files-api.ts
4
4
  /**
5
5
  * Browser filesystem implementation using the File System Access API.
@@ -24,9 +24,9 @@ var BrowserFilesApi = class {
24
24
  return current;
25
25
  }
26
26
  async getFileHandle(path, options = {}) {
27
- const normalized = (0, __statewalker_webrun_files.normalizePath)(path);
28
- const parentPath = (0, __statewalker_webrun_files.dirname)(normalized);
29
- const fileName = (0, __statewalker_webrun_files.basename)(normalized);
27
+ const normalized = (0, _statewalker_webrun_files.normalizePath)(path);
28
+ const parentPath = (0, _statewalker_webrun_files.dirname)(normalized);
29
+ const fileName = (0, _statewalker_webrun_files.basename)(normalized);
30
30
  const parent = await this.getDirectoryHandle(parentPath, options);
31
31
  if (!parent) return null;
32
32
  try {
@@ -59,9 +59,9 @@ var BrowserFilesApi = class {
59
59
  }
60
60
  }
61
61
  async write(path, content) {
62
- const normalized = (0, __statewalker_webrun_files.normalizePath)(path);
63
- const parentPath = (0, __statewalker_webrun_files.dirname)(normalized);
64
- const fileName = (0, __statewalker_webrun_files.basename)(normalized);
62
+ const normalized = (0, _statewalker_webrun_files.normalizePath)(path);
63
+ const parentPath = (0, _statewalker_webrun_files.dirname)(normalized);
64
+ const fileName = (0, _statewalker_webrun_files.basename)(normalized);
65
65
  const parent = await this.getDirectoryHandle(parentPath, { create: true });
66
66
  if (!parent) throw new Error(`Cannot create directory: ${parentPath}`);
67
67
  const writable = await (await parent.getFileHandle(fileName, { create: true })).createWritable();
@@ -72,16 +72,16 @@ var BrowserFilesApi = class {
72
72
  }
73
73
  }
74
74
  async mkdir(path) {
75
- const normalized = (0, __statewalker_webrun_files.normalizePath)(path);
75
+ const normalized = (0, _statewalker_webrun_files.normalizePath)(path);
76
76
  await this.getDirectoryHandle(normalized, { create: true });
77
77
  }
78
78
  async *list(path, options) {
79
- const normalized = (0, __statewalker_webrun_files.normalizePath)(path);
79
+ const normalized = (0, _statewalker_webrun_files.normalizePath)(path);
80
80
  const dirHandle = await this.getDirectoryHandle(normalized);
81
81
  if (!dirHandle) return;
82
82
  const recursive = options?.recursive ?? false;
83
83
  for await (const [name, handle] of dirHandle.entries()) {
84
- const entryPath = (0, __statewalker_webrun_files.joinPath)(normalized, name);
84
+ const entryPath = (0, _statewalker_webrun_files.joinPath)(normalized, name);
85
85
  const isDirectory = handle.kind === "directory";
86
86
  const info = {
87
87
  kind: isDirectory ? "directory" : "file",
@@ -99,7 +99,7 @@ var BrowserFilesApi = class {
99
99
  }
100
100
  }
101
101
  async stats(path) {
102
- const normalized = (0, __statewalker_webrun_files.normalizePath)(path);
102
+ const normalized = (0, _statewalker_webrun_files.normalizePath)(path);
103
103
  if (normalized === "/") return {
104
104
  kind: "directory",
105
105
  lastModified: 0
@@ -124,9 +124,9 @@ var BrowserFilesApi = class {
124
124
  return await this.stats(path) !== void 0;
125
125
  }
126
126
  async remove(path) {
127
- const normalized = (0, __statewalker_webrun_files.normalizePath)(path);
128
- const parentPath = (0, __statewalker_webrun_files.dirname)(normalized);
129
- const name = (0, __statewalker_webrun_files.basename)(normalized);
127
+ const normalized = (0, _statewalker_webrun_files.normalizePath)(path);
128
+ const parentPath = (0, _statewalker_webrun_files.dirname)(normalized);
129
+ const name = (0, _statewalker_webrun_files.basename)(normalized);
130
130
  const parent = await this.getDirectoryHandle(parentPath);
131
131
  if (!parent) return false;
132
132
  try {
@@ -137,20 +137,34 @@ var BrowserFilesApi = class {
137
137
  }
138
138
  }
139
139
  async move(source, target) {
140
+ const sourcePath = (0, _statewalker_webrun_files.normalizePath)(source);
141
+ const targetPath = (0, _statewalker_webrun_files.normalizePath)(target);
142
+ const targetParentPath = (0, _statewalker_webrun_files.dirname)(targetPath);
143
+ const targetName = (0, _statewalker_webrun_files.basename)(targetPath);
144
+ const sourceStats = await this.stats(sourcePath);
145
+ if (!sourceStats) return false;
146
+ const sourceHandle = sourceStats.kind === "file" ? await this.getFileHandle(sourcePath) : await this.getDirectoryHandle(sourcePath);
147
+ if (!sourceHandle) return false;
148
+ if (typeof sourceHandle.move === "function") try {
149
+ const targetParent = await this.getDirectoryHandle(targetParentPath, { create: true });
150
+ if (!targetParent) return false;
151
+ await sourceHandle.move(targetParent, targetName);
152
+ return true;
153
+ } catch {}
140
154
  if (!await this.copy(source, target)) return false;
141
155
  return this.remove(source);
142
156
  }
143
157
  async copy(source, target) {
144
- const sourcePath = (0, __statewalker_webrun_files.normalizePath)(source);
145
- const targetPath = (0, __statewalker_webrun_files.normalizePath)(target);
158
+ const sourcePath = (0, _statewalker_webrun_files.normalizePath)(source);
159
+ const targetPath = (0, _statewalker_webrun_files.normalizePath)(target);
146
160
  const sourceStats = await this.stats(source);
147
161
  if (!sourceStats) return false;
148
162
  if (sourceStats.kind === "file") {
149
163
  const sourceHandle = await this.getFileHandle(sourcePath);
150
164
  if (!sourceHandle) return false;
151
165
  const sourceFile = await sourceHandle.getFile();
152
- const targetParentPath = (0, __statewalker_webrun_files.dirname)(targetPath);
153
- const targetFileName = (0, __statewalker_webrun_files.basename)(targetPath);
166
+ const targetParentPath = (0, _statewalker_webrun_files.dirname)(targetPath);
167
+ const targetFileName = (0, _statewalker_webrun_files.basename)(targetPath);
154
168
  const targetParent = await this.getDirectoryHandle(targetParentPath, { create: true });
155
169
  if (!targetParent) return false;
156
170
  const writable = await (await targetParent.getFileHandle(targetFileName, { create: true })).createWritable();
@@ -173,8 +187,8 @@ var BrowserFilesApi = class {
173
187
  const entryHandle = await this.getFileHandle(entry.path);
174
188
  if (!entryHandle) continue;
175
189
  const entryFile = await entryHandle.getFile();
176
- const newTargetParentPath = (0, __statewalker_webrun_files.dirname)(newTargetPath);
177
- const newTargetFileName = (0, __statewalker_webrun_files.basename)(newTargetPath);
190
+ const newTargetParentPath = (0, _statewalker_webrun_files.dirname)(newTargetPath);
191
+ const newTargetFileName = (0, _statewalker_webrun_files.basename)(newTargetPath);
178
192
  const newTargetParent = await this.getDirectoryHandle(newTargetParentPath, { create: true });
179
193
  if (!newTargetParent) continue;
180
194
  const writable = await (await newTargetParent.getFileHandle(newTargetFileName, { create: true })).createWritable();
@@ -198,7 +212,6 @@ var BrowserFilesApi = class {
198
212
  async function getOPFSFilesApi() {
199
213
  return new BrowserFilesApi({ rootHandle: await navigator.storage.getDirectory() });
200
214
  }
201
-
202
215
  //#endregion
203
216
  //#region src/open-browser-files-api.ts
204
217
  /**
@@ -264,10 +277,9 @@ async function openBrowserFilesApi(options = {}) {
264
277
  }
265
278
  return new BrowserFilesApi({ rootHandle });
266
279
  }
267
-
268
280
  //#endregion
269
281
  exports.BrowserFilesApi = BrowserFilesApi;
270
282
  exports.getOPFSFilesApi = getOPFSFilesApi;
271
283
  exports.isHandlerAccessible = isHandlerAccessible;
272
284
  exports.openBrowserFilesApi = openBrowserFilesApi;
273
- exports.verifyPermission = verifyPermission;
285
+ exports.verifyPermission = verifyPermission;
package/dist/esm/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { basename, dirname, joinPath, normalizePath } from "@statewalker/webrun-files";
2
-
3
2
  //#region src/browser-files-api.ts
4
3
  /**
5
4
  * Browser filesystem implementation using the File System Access API.
@@ -137,6 +136,20 @@ var BrowserFilesApi = class {
137
136
  }
138
137
  }
139
138
  async move(source, target) {
139
+ const sourcePath = normalizePath(source);
140
+ const targetPath = normalizePath(target);
141
+ const targetParentPath = dirname(targetPath);
142
+ const targetName = basename(targetPath);
143
+ const sourceStats = await this.stats(sourcePath);
144
+ if (!sourceStats) return false;
145
+ const sourceHandle = sourceStats.kind === "file" ? await this.getFileHandle(sourcePath) : await this.getDirectoryHandle(sourcePath);
146
+ if (!sourceHandle) return false;
147
+ if (typeof sourceHandle.move === "function") try {
148
+ const targetParent = await this.getDirectoryHandle(targetParentPath, { create: true });
149
+ if (!targetParent) return false;
150
+ await sourceHandle.move(targetParent, targetName);
151
+ return true;
152
+ } catch {}
140
153
  if (!await this.copy(source, target)) return false;
141
154
  return this.remove(source);
142
155
  }
@@ -198,7 +211,6 @@ var BrowserFilesApi = class {
198
211
  async function getOPFSFilesApi() {
199
212
  return new BrowserFilesApi({ rootHandle: await navigator.storage.getDirectory() });
200
213
  }
201
-
202
214
  //#endregion
203
215
  //#region src/open-browser-files-api.ts
204
216
  /**
@@ -264,6 +276,5 @@ async function openBrowserFilesApi(options = {}) {
264
276
  }
265
277
  return new BrowserFilesApi({ rootHandle });
266
278
  }
267
-
268
279
  //#endregion
269
- export { BrowserFilesApi, getOPFSFilesApi, isHandlerAccessible, openBrowserFilesApi, verifyPermission };
280
+ export { BrowserFilesApi, getOPFSFilesApi, isHandlerAccessible, openBrowserFilesApi, verifyPermission };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statewalker/webrun-files-browser",
3
- "version": "0.7.0",
3
+ "version": "0.7.2",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Browser File System Access API implementation for webrun-files",
@@ -29,15 +29,15 @@
29
29
  "src"
30
30
  ],
31
31
  "dependencies": {
32
- "@statewalker/webrun-files": "0.7.0"
32
+ "@statewalker/webrun-files": "^0.7.0"
33
33
  },
34
34
  "devDependencies": {
35
- "@types/node": "^24.10.1",
35
+ "@types/node": "^25.6.0",
36
36
  "native-file-system-adapter": "^3.0.1",
37
- "rimraf": "^6.1.2",
38
- "rolldown": "^1.0.0-beta.53",
39
- "typescript": "^5.6.0",
40
- "vitest": "^4.0.12",
37
+ "rimraf": "^6.1.3",
38
+ "rolldown": "^1.0.0-rc.16",
39
+ "typescript": "^6.0.3",
40
+ "vitest": "^4.1.4",
41
41
  "@statewalker/webrun-files-tests": "1.0.0"
42
42
  },
43
43
  "sideEffects": false,
@@ -14,6 +14,11 @@ import type {
14
14
  } from "@statewalker/webrun-files";
15
15
  import { basename, dirname, joinPath, normalizePath } from "@statewalker/webrun-files";
16
16
 
17
+ /** Chrome 110+ exposes move() on FileSystemHandle; not yet in TS DOM types. */
18
+ interface MovableHandle extends FileSystemHandle {
19
+ move(destination: FileSystemDirectoryHandle, name: string): Promise<void>;
20
+ }
21
+
17
22
  export interface BrowserFilesApiOptions {
18
23
  /**
19
24
  * Root FileSystemDirectoryHandle to use as the filesystem root.
@@ -227,6 +232,32 @@ export class BrowserFilesApi implements FilesApi {
227
232
  }
228
233
 
229
234
  async move(source: string, target: string): Promise<boolean> {
235
+ const sourcePath = normalizePath(source);
236
+ const targetPath = normalizePath(target);
237
+ const targetParentPath = dirname(targetPath);
238
+ const targetName = basename(targetPath);
239
+
240
+ // Try native move() (available in Chrome 110+, Edge 110+)
241
+ const sourceStats = await this.stats(sourcePath);
242
+ if (!sourceStats) return false;
243
+
244
+ const sourceHandle: FileSystemHandle | null =
245
+ sourceStats.kind === "file"
246
+ ? await this.getFileHandle(sourcePath)
247
+ : await this.getDirectoryHandle(sourcePath);
248
+ if (!sourceHandle) return false;
249
+
250
+ if (typeof (sourceHandle as MovableHandle).move === "function") {
251
+ try {
252
+ const targetParent = await this.getDirectoryHandle(targetParentPath, { create: true });
253
+ if (!targetParent) return false;
254
+ await (sourceHandle as MovableHandle).move(targetParent, targetName);
255
+ return true;
256
+ } catch {
257
+ // Fall through to copy-then-delete
258
+ }
259
+ }
260
+
230
261
  const copied = await this.copy(source, target);
231
262
  if (!copied) return false;
232
263
  return this.remove(source);