@zenfs/dom 1.2.0 → 1.2.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/dist/access.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { CreationOptions, FileSystem, InodeLike } from '@zenfs/core';
2
- import { IndexFS } from '@zenfs/core';
2
+ import { IndexFS, Inode } from '@zenfs/core';
3
3
  export interface WebAccessOptions {
4
4
  handle: FileSystemDirectoryHandle;
5
5
  metadata?: string;
@@ -9,7 +9,7 @@ export interface WebAccessOptions {
9
9
  */
10
10
  disableHandleCache?: boolean;
11
11
  }
12
- type HKindToType<T extends FileSystemHandleKind> = T extends 'directory' ? FileSystemDirectoryHandle : T extends 'file' ? FileSystemFileHandle : FileSystemHandle;
12
+ type HKindToType<T extends FileSystemHandleKind | null> = T extends 'directory' ? FileSystemDirectoryHandle : T extends 'file' ? FileSystemFileHandle : FileSystemHandle;
13
13
  declare const WebAccessFS_base: import("@zenfs/core").Mixin<typeof IndexFS, import("@zenfs/core").AsyncMixin>;
14
14
  /**
15
15
  * @todo Consider supporting synchronous stuff with `FileSystemFileHandle.createSyncAccessHandle()`\
@@ -39,6 +39,8 @@ export declare class WebAccessFS extends WebAccessFS_base {
39
39
  */
40
40
  _sync: FileSystem;
41
41
  constructor(root: FileSystemDirectoryHandle, disableHandleCache?: boolean);
42
+ stat(path: string): Promise<Inode>;
43
+ readdir(path: string): Promise<string[]>;
42
44
  protected remove(path: string): Promise<void>;
43
45
  protected removeSync(): void;
44
46
  read(path: string, buffer: Uint8Array, offset: number, end: number): Promise<void>;
@@ -49,7 +51,7 @@ export declare class WebAccessFS extends WebAccessFS_base {
49
51
  */
50
52
  writeFile(path: string, data: Uint8Array): Promise<void>;
51
53
  mkdir(path: string, options: CreationOptions): Promise<InodeLike>;
52
- protected get<const T extends FileSystemHandleKind | null>(kind: T | undefined, path: string): Promise<T extends FileSystemHandleKind ? HKindToType<T> : FileSystemHandle>;
54
+ protected get<const T extends FileSystemHandleKind | null>(kind: T | undefined, path: string): Promise<HKindToType<T>>;
53
55
  }
54
56
  declare const _WebAccess: {
55
57
  readonly name: "WebAccess";
package/dist/access.js CHANGED
@@ -1,6 +1,5 @@
1
1
  import { Async, constants, IndexFS, InMemory, Inode } from '@zenfs/core';
2
2
  import { basename, dirname, join } from '@zenfs/core/path.js';
3
- import { S_IFDIR, S_IFMT } from '@zenfs/core/vfs/constants.js';
4
3
  import { log, withErrno } from 'kerium';
5
4
  import { alert } from 'kerium/log';
6
5
  import { _throw } from 'utilium';
@@ -79,6 +78,39 @@ export class WebAccessFS extends Async(IndexFS) {
79
78
  if (disableHandleCache)
80
79
  this.attributes.set('no_handle_cache', true);
81
80
  }
81
+ async stat(path) {
82
+ try {
83
+ return await super.stat(path);
84
+ }
85
+ catch (ex) {
86
+ if (ex.code != 'ENOENT')
87
+ throw ex;
88
+ // This handle must have been created after initialization
89
+ // Try to add a new inode for the handle to the index
90
+ const handle = await this.get(null, path);
91
+ const inode = new Inode();
92
+ if (isKind(handle, 'file')) {
93
+ const file = await handle.getFile();
94
+ inode.update({
95
+ mode: 0o644 | constants.S_IFREG,
96
+ size: file.size,
97
+ mtimeMs: file.lastModified,
98
+ });
99
+ }
100
+ else {
101
+ inode.update({
102
+ mode: constants.S_IFDIR | 0o777,
103
+ size: 0,
104
+ });
105
+ }
106
+ this.index.set(path, inode);
107
+ return inode;
108
+ }
109
+ }
110
+ async readdir(path) {
111
+ const dirHandle = await this.get('directory', path);
112
+ return await Array.fromAsync(dirHandle.keys());
113
+ }
82
114
  async remove(path) {
83
115
  const handle = await this.get('directory', dirname(path));
84
116
  await handle.removeEntry(basename(path), { recursive: true }).catch(ex => _throw(convertException(ex, path)));
@@ -93,7 +125,11 @@ export class WebAccessFS extends Async(IndexFS) {
93
125
  const file = await handle.getFile();
94
126
  const data = await file.arrayBuffer();
95
127
  if (data.byteLength < end - offset)
96
- throw alert(withErrno('EIO', `Unexpected mismatch in file data size. This should not happen.\n\t\tTried to read ${end - offset} bytes but the file is ${data.byteLength} bytes.`));
128
+ throw alert(withErrno('EIO', [
129
+ 'Unexpected mismatch in file data size. This should not happen.',
130
+ `tried to read ${end - offset} bytes but the file is ${data.byteLength} bytes.`,
131
+ `path: ${path}`,
132
+ ].join('\n' + ' '.repeat(24))));
97
133
  buffer.set(new Uint8Array(data, offset, end - offset));
98
134
  }
99
135
  async write(path, buffer, offset) {
@@ -105,7 +141,7 @@ export class WebAccessFS extends Async(IndexFS) {
105
141
  const inode = this.index.get(path);
106
142
  if (!inode)
107
143
  throw withErrno('ENOENT');
108
- const isDir = (inode.mode & S_IFMT) == S_IFDIR;
144
+ const isDir = (inode.mode & constants.S_IFMT) == constants.S_IFDIR;
109
145
  let handle;
110
146
  try {
111
147
  handle = await this.get(isDir ? 'directory' : 'file', path);
@@ -151,13 +187,12 @@ export class WebAccessFS extends Async(IndexFS) {
151
187
  return inode;
152
188
  }
153
189
  async get(kind = null, path) {
154
- if (!this.disableHandleCache) {
155
- const handle = this._handles.get(path);
156
- if (!handle)
157
- throw withErrno('ENOENT');
158
- if (kind && !isKind(handle, kind))
190
+ const maybeHandle = this._handles.get(path);
191
+ if (!this.disableHandleCache && maybeHandle) {
192
+ if (kind && !isKind(maybeHandle, kind))
159
193
  throw withErrno(kind == 'directory' ? 'ENOTDIR' : 'EISDIR');
160
- return handle;
194
+ return maybeHandle;
195
+ // Otherwise, fall through to the slow path
161
196
  }
162
197
  if (path == '/')
163
198
  return this.root;
@@ -168,13 +203,21 @@ export class WebAccessFS extends Async(IndexFS) {
168
203
  }
169
204
  try {
170
205
  const handle = await dir[kind == 'file' ? 'getFileHandle' : 'getDirectoryHandle'](parts.at(-1));
206
+ if (!this.disableHandleCache)
207
+ this._handles.set(path, handle);
171
208
  return handle;
172
209
  }
173
210
  catch (ex) {
174
- if (ex.name == 'TypeMismatchError')
175
- throw withErrno(kind == 'file' ? 'EISDIR' : 'ENOTDIR');
176
- else
211
+ if (ex.name != 'TypeMismatchError')
177
212
  throw convertException(ex, path);
213
+ else if (kind === null) {
214
+ const handle = await dir.getFileHandle(parts.at(-1)).catch(ex => _throw(convertException(ex, path)));
215
+ if (!this.disableHandleCache)
216
+ this._handles.set(path, handle);
217
+ return handle;
218
+ }
219
+ else
220
+ throw withErrno(kind == 'file' ? 'EISDIR' : 'ENOTDIR');
178
221
  }
179
222
  }
180
223
  }
@@ -186,7 +229,7 @@ const _WebAccess = {
186
229
  disableHandleCache: { type: 'boolean', required: false },
187
230
  },
188
231
  async create(options) {
189
- const fs = new WebAccessFS(options.handle);
232
+ const fs = new WebAccessFS(options.handle, options.disableHandleCache);
190
233
  await fs._loadMetadata(options.metadata);
191
234
  return fs;
192
235
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenfs/dom",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "DOM backends for ZenFS",
5
5
  "funding": {
6
6
  "type": "individual",