@zenfs/dom 1.1.5 → 1.1.7

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.
@@ -1,24 +1,32 @@
1
1
  import type { SharedConfig, Store } from '@zenfs/core';
2
- import { AsyncTransaction, StoreFS } from '@zenfs/core';
3
- import type * as cache from 'utilium/cache.js';
2
+ import { StoreFS, Transaction } from '@zenfs/core';
4
3
  /**
5
4
  * @internal @hidden
6
5
  */
7
- export declare class IndexedDBTransaction extends AsyncTransaction<IndexedDBStore> {
6
+ export declare class IndexedDBTransaction extends Transaction<IndexedDBStore> {
8
7
  tx: IDBTransaction;
9
8
  store: IndexedDBStore;
10
9
  private _idb;
10
+ protected asyncDone: Promise<unknown>;
11
+ /**
12
+ * Run a asynchronous operation from a sync context. Not magic and subject to (race) conditions.
13
+ * @internal
14
+ */
15
+ protected async(promise: Promise<unknown>): void;
11
16
  constructor(tx: IDBTransaction, store: IndexedDBStore);
12
17
  keys(): Promise<Iterable<number>>;
13
18
  get(id: number): Promise<Uint8Array | undefined>;
19
+ getSync(id: number, offset: number, end?: number): Uint8Array | undefined;
14
20
  set(id: number, data: Uint8Array): Promise<void>;
21
+ setSync(id: number, data: Uint8Array): void;
15
22
  remove(id: number): Promise<void>;
23
+ removeSync(id: number): void;
16
24
  commit(): Promise<void>;
17
25
  abort(): Promise<void>;
18
26
  }
19
27
  export declare class IndexedDBStore implements Store {
20
28
  protected db: IDBDatabase;
21
- cache: Map<number, cache.Resource<number>>;
29
+ cache: Map<number, Uint8Array<ArrayBufferLike>>;
22
30
  constructor(db: IDBDatabase);
23
31
  sync(): Promise<void>;
24
32
  get name(): string;
@@ -52,7 +60,7 @@ declare const _IndexedDB: {
52
60
  readonly required: false;
53
61
  };
54
62
  };
55
- readonly isAvailable: (idbFactory?: IDBFactory) => Promise<boolean>;
63
+ readonly isAvailable: ({ idbFactory }: IndexedDBOptions) => Promise<boolean>;
56
64
  readonly create: (options: IndexedDBOptions & Partial<SharedConfig>) => Promise<StoreFS<IndexedDBStore>>;
57
65
  };
58
66
  type _IndexedDB = typeof _IndexedDB;
package/dist/IndexedDB.js CHANGED
@@ -1,4 +1,5 @@
1
- import { AsyncTransaction, StoreFS, log } from '@zenfs/core';
1
+ import { StoreFS, Transaction } from '@zenfs/core';
2
+ import { log } from 'kerium';
2
3
  import { convertException } from './utils.js';
3
4
  function wrap(request) {
4
5
  return new Promise((resolve, reject) => {
@@ -12,31 +13,54 @@ function wrap(request) {
12
13
  /**
13
14
  * @internal @hidden
14
15
  */
15
- export class IndexedDBTransaction extends AsyncTransaction {
16
+ export class IndexedDBTransaction extends Transaction {
17
+ /**
18
+ * Run a asynchronous operation from a sync context. Not magic and subject to (race) conditions.
19
+ * @internal
20
+ */
21
+ async(promise) {
22
+ this.asyncDone = this.asyncDone.then(() => promise);
23
+ }
16
24
  constructor(tx, store) {
17
25
  super(store);
18
26
  this.tx = tx;
19
27
  this.store = store;
28
+ this.asyncDone = Promise.resolve();
20
29
  this._idb = tx.objectStore(store.name);
21
30
  }
22
31
  async keys() {
23
32
  return (await wrap(this._idb.getAllKeys())).filter(k => typeof k == 'string').map(k => Number(k));
24
33
  }
25
34
  async get(id) {
26
- const data = await wrap(this._idb.get(id.toString()));
35
+ const data = await wrap(this._idb.get(id));
27
36
  if (data)
28
- this._cached(id, { size: data.byteLength }).add(data, 0);
37
+ this.store.cache.set(id, new Uint8Array(data));
29
38
  return data;
30
39
  }
40
+ getSync(id, offset, end) {
41
+ if (!this.store.cache.has(id))
42
+ return;
43
+ const data = new Uint8Array(this.store.cache.get(id));
44
+ end ?? (end = data.byteLength);
45
+ return data.subarray(offset, end);
46
+ }
31
47
  async set(id, data) {
32
- this._cached(id, { size: data.byteLength }).add(data, 0);
33
- await wrap(this._idb.put(data, id.toString()));
48
+ this.store.cache.set(id, new Uint8Array(data));
49
+ await wrap(this._idb.put(data, id));
50
+ }
51
+ setSync(id, data) {
52
+ this.async(this.set(id, data));
34
53
  }
35
54
  remove(id) {
36
55
  this.store.cache.delete(id);
37
- return wrap(this._idb.delete(id.toString()));
56
+ return wrap(this._idb.delete(id));
57
+ }
58
+ removeSync(id) {
59
+ this.store.cache.delete(id);
60
+ this.async(this.remove(id));
38
61
  }
39
62
  async commit() {
63
+ await this.asyncDone;
40
64
  const { promise, resolve, reject } = Promise.withResolvers();
41
65
  this.tx.oncomplete = () => resolve();
42
66
  this.tx.onerror = () => reject(convertException(this.tx.error));
@@ -44,6 +68,7 @@ export class IndexedDBTransaction extends AsyncTransaction {
44
68
  return promise;
45
69
  }
46
70
  async abort() {
71
+ await this.asyncDone;
47
72
  const { promise, resolve, reject } = Promise.withResolvers();
48
73
  this.tx.onabort = () => resolve();
49
74
  this.tx.onerror = () => reject(convertException(this.tx.error));
@@ -89,11 +114,10 @@ const _IndexedDB = {
89
114
  storeName: { type: 'string', required: false },
90
115
  idbFactory: { type: 'object', required: false },
91
116
  },
92
- async isAvailable(idbFactory = globalThis.indexedDB) {
117
+ async isAvailable({ idbFactory = globalThis.indexedDB }) {
93
118
  try {
94
- if (!(idbFactory instanceof IDBFactory)) {
119
+ if (!(idbFactory instanceof IDBFactory))
95
120
  return false;
96
- }
97
121
  const req = idbFactory.open('__zenfs_test');
98
122
  await wrap(req);
99
123
  return true;
@@ -102,7 +126,7 @@ const _IndexedDB = {
102
126
  return false;
103
127
  }
104
128
  finally {
105
- idbFactory.deleteDatabase('__zenfs_test');
129
+ idbFactory?.deleteDatabase('__zenfs_test');
106
130
  }
107
131
  },
108
132
  async create(options) {
package/dist/access.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { CreationOptions, FileSystem } from '@zenfs/core';
1
+ import type { CreationOptions, FileSystem, InodeLike } from '@zenfs/core';
2
2
  import { IndexFS } from '@zenfs/core';
3
3
  export interface WebAccessOptions {
4
4
  handle: FileSystemDirectoryHandle;
@@ -24,7 +24,7 @@ export declare class WebAccessFS extends WebAccessFS_base {
24
24
  _sync: FileSystem;
25
25
  constructor(handle: FileSystemDirectoryHandle);
26
26
  remove(path: string): Promise<void>;
27
- protected removeSync(path: string): void;
27
+ protected removeSync(): void;
28
28
  read(path: string, buffer: Uint8Array, offset: number, end: number): Promise<void>;
29
29
  write(path: string, buffer: Uint8Array, offset: number): Promise<void>;
30
30
  /**
@@ -32,8 +32,8 @@ export declare class WebAccessFS extends WebAccessFS_base {
32
32
  * @deprecated @internal @hidden
33
33
  */
34
34
  writeFile(path: string, data: Uint8Array): Promise<void>;
35
- mkdir(path: string, mode: number, options: CreationOptions): Promise<void>;
36
- protected get<const T extends FileSystemHandleKind | null>(kind: T | undefined, path: string, syscall?: string): T extends FileSystemHandleKind ? HKindToType<T> : FileSystemHandle;
35
+ mkdir(path: string, options: CreationOptions): Promise<InodeLike>;
36
+ protected get<const T extends FileSystemHandleKind | null>(kind: T | undefined, path: string): T extends FileSystemHandleKind ? HKindToType<T> : FileSystemHandle;
37
37
  }
38
38
  declare const _WebAccess: {
39
39
  readonly name: "WebAccess";
package/dist/access.js CHANGED
@@ -1,6 +1,7 @@
1
- import { Async, constants, Errno, ErrnoError, IndexFS, InMemory, Inode, log } from '@zenfs/core';
1
+ import { Async, constants, IndexFS, InMemory, Inode } from '@zenfs/core';
2
+ import { basename, dirname, join } from '@zenfs/core/path.js';
2
3
  import { S_IFDIR, S_IFMT } from '@zenfs/core/vfs/constants.js';
3
- import { basename, dirname, join } from '@zenfs/core/vfs/path.js';
4
+ import { log, withErrno } from 'kerium';
4
5
  import { _throw } from 'utilium';
5
6
  import { convertException } from './utils.js';
6
7
  function isResizable(buffer) {
@@ -49,7 +50,7 @@ export class WebAccessFS extends Async(IndexFS) {
49
50
  continue;
50
51
  }
51
52
  if (!isKind(handle, 'directory'))
52
- throw new ErrnoError(Errno.EIO, 'Invalid handle', path);
53
+ throw withErrno('EIO', 'Invalid handle');
53
54
  this.index.set(path, new Inode({ mode: 0o777 | constants.S_IFDIR, size: 0 }));
54
55
  }
55
56
  }
@@ -59,26 +60,25 @@ export class WebAccessFS extends Async(IndexFS) {
59
60
  /**
60
61
  * @hidden
61
62
  */
62
- this._sync = InMemory.create({ name: 'accessfs-cache' });
63
- this.attributes.set('no_buffer_resize');
64
- this.attributes.set('setid');
63
+ this._sync = InMemory.create({ label: 'accessfs-cache' });
64
+ this.attributes.set('no_buffer_resize', true);
65
65
  this._handles.set('/', handle);
66
66
  }
67
67
  async remove(path) {
68
68
  const handle = this.get('directory', dirname(path));
69
69
  await handle.removeEntry(basename(path), { recursive: true }).catch(ex => _throw(convertException(ex, path)));
70
70
  }
71
- removeSync(path) {
72
- throw log.crit(ErrnoError.With('ENOSYS', path));
71
+ removeSync() {
72
+ throw log.crit(withErrno('ENOSYS'));
73
73
  }
74
74
  async read(path, buffer, offset, end) {
75
75
  if (end <= offset)
76
76
  return;
77
- const handle = this.get('file', path, 'write');
77
+ const handle = this.get('file', path);
78
78
  const file = await handle.getFile();
79
79
  const data = await file.arrayBuffer();
80
80
  if (data.byteLength < end - offset)
81
- throw ErrnoError.With('ENODATA', path, 'read');
81
+ throw withErrno('ENODATA');
82
82
  buffer.set(new Uint8Array(data, offset, end - offset));
83
83
  }
84
84
  async write(path, buffer, offset) {
@@ -89,21 +89,21 @@ export class WebAccessFS extends Async(IndexFS) {
89
89
  }
90
90
  const inode = this.index.get(path);
91
91
  if (!inode)
92
- throw ErrnoError.With('ENOENT', path, 'write');
92
+ throw withErrno('ENOENT');
93
93
  const isDir = (inode.mode & S_IFMT) == S_IFDIR;
94
94
  let handle;
95
95
  try {
96
- handle = this.get(isDir ? 'directory' : 'file', path, 'write');
96
+ handle = this.get(isDir ? 'directory' : 'file', path);
97
97
  }
98
98
  catch {
99
- const parent = this.get('directory', dirname(path), 'write');
99
+ const parent = this.get('directory', dirname(path));
100
100
  handle = await parent[isDir ? 'getDirectoryHandle' : 'getFileHandle'](basename(path), { create: true }).catch((ex) => _throw(convertException(ex, path)));
101
101
  this._handles.set(path, handle);
102
102
  }
103
103
  if (isDir)
104
104
  return;
105
105
  if (isKind(handle, 'directory')) {
106
- log.crit(new ErrnoError(Errno.EIO, 'Mismatch in entry kind on write', path, 'write'));
106
+ log.crit(withErrno('EIO', 'Mismatch in entry kind on write'));
107
107
  return;
108
108
  }
109
109
  const writable = await handle.createWritable();
@@ -126,18 +126,19 @@ export class WebAccessFS extends Async(IndexFS) {
126
126
  async writeFile(path, data) {
127
127
  return this.write(path, data, 0);
128
128
  }
129
- async mkdir(path, mode, options) {
130
- await super.mkdir(path, mode, options);
131
- const handle = this.get('directory', dirname(path), 'mkdir');
129
+ async mkdir(path, options) {
130
+ const inode = await super.mkdir(path, options);
131
+ const handle = this.get('directory', dirname(path));
132
132
  const dir = await handle.getDirectoryHandle(basename(path), { create: true }).catch((ex) => _throw(convertException(ex, path)));
133
133
  this._handles.set(path, dir);
134
+ return inode;
134
135
  }
135
- get(kind = null, path, syscall) {
136
+ get(kind = null, path) {
136
137
  const handle = this._handles.get(path);
137
138
  if (!handle)
138
- throw ErrnoError.With('ENODATA', path, syscall);
139
+ throw withErrno('ENODATA');
139
140
  if (kind && !isKind(handle, kind))
140
- throw ErrnoError.With(kind == 'directory' ? 'ENOTDIR' : 'EISDIR', path, syscall);
141
+ throw withErrno(kind == 'directory' ? 'ENOTDIR' : 'EISDIR');
141
142
  return handle;
142
143
  }
143
144
  }
@@ -44,10 +44,10 @@ export async function dsp(options = {}) {
44
44
  init(ino, options) {
45
45
  return { data: dsp, major: 14, minor: 3 };
46
46
  },
47
- readD() {
47
+ read() {
48
48
  return;
49
49
  },
50
- writeD(device, buffer, offset) {
50
+ write(device, buffer, offset) {
51
51
  device.data.port.postMessage(buffer.buffer);
52
52
  },
53
53
  };
@@ -1,4 +1,4 @@
1
- import { Errno, ErrnoError } from '@zenfs/core';
1
+ import { withErrno } from 'kerium';
2
2
  let framebufferN = 0;
3
3
  /**
4
4
  * A frame buffer
@@ -17,7 +17,7 @@ export const framebuffer = {
17
17
  }
18
18
  const context = canvas.getContext('2d');
19
19
  if (!context) {
20
- throw new ErrnoError(Errno.EIO, 'Could not get context from canvas whilst initializing frame buffer.');
20
+ throw withErrno('EIO', 'Could not get context from canvas whilst initializing frame buffer.');
21
21
  }
22
22
  const image = new ImageData(canvas.width, canvas.height);
23
23
  return {
@@ -27,8 +27,8 @@ export const framebuffer = {
27
27
  name: 'fb',
28
28
  };
29
29
  },
30
- readD() { },
31
- writeD({ data: { image, context } }, buffer, offset) {
30
+ read() { },
31
+ write({ data: { image, context } }, buffer, offset) {
32
32
  image.data.set(buffer, offset);
33
33
  context.putImageData(image, 0, 0);
34
34
  return buffer.byteLength;
package/dist/storage.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { SyncMapStore, Store } from '@zenfs/core';
1
+ import type { Store, SyncMapStore } from '@zenfs/core';
2
2
  import { StoreFS, SyncMapTransaction } from '@zenfs/core';
3
3
  /**
4
4
  * A synchronous key-value store backed by Storage.
@@ -39,7 +39,7 @@ declare const _WebStorage: {
39
39
  /**
40
40
  * @todo Consider replacing `instanceof` with a duck-typing check?
41
41
  */
42
- readonly isAvailable: (storage?: Storage) => boolean;
42
+ readonly isAvailable: (config?: WebStorageOptions) => boolean;
43
43
  readonly create: ({ storage }: WebStorageOptions) => StoreFS<WebStorageStore>;
44
44
  };
45
45
  type _WebStorage = typeof _WebStorage;
package/dist/storage.js CHANGED
@@ -1,4 +1,6 @@
1
- import { ErrnoError, Errno, StoreFS, decodeRaw, encodeRaw, SyncMapTransaction } from '@zenfs/core';
1
+ import { withErrno } from 'kerium';
2
+ import { StoreFS, SyncMapTransaction } from '@zenfs/core';
3
+ import { decodeASCII, encodeASCII } from 'utilium';
2
4
  /**
3
5
  * A synchronous key-value store backed by Storage.
4
6
  */
@@ -28,14 +30,14 @@ export class WebStorageStore {
28
30
  if (typeof data != 'string') {
29
31
  return;
30
32
  }
31
- return encodeRaw(data);
33
+ return encodeASCII(data);
32
34
  }
33
35
  set(key, data) {
34
36
  try {
35
- this.storage.setItem(key.toString(), decodeRaw(data));
37
+ this.storage.setItem(key.toString(), decodeASCII(data));
36
38
  }
37
39
  catch {
38
- throw new ErrnoError(Errno.ENOSPC, 'Storage is full.');
40
+ throw withErrno('ENOSPC');
39
41
  }
40
42
  }
41
43
  delete(key) {
@@ -43,7 +45,7 @@ export class WebStorageStore {
43
45
  this.storage.removeItem(key.toString());
44
46
  }
45
47
  catch (e) {
46
- throw new ErrnoError(Errno.EIO, 'Unable to delete key ' + key + ': ' + e);
48
+ throw withErrno('EIO', `Unable to delete '${key}': ${e}`);
47
49
  }
48
50
  }
49
51
  }
@@ -58,8 +60,8 @@ const _WebStorage = {
58
60
  /**
59
61
  * @todo Consider replacing `instanceof` with a duck-typing check?
60
62
  */
61
- isAvailable(storage = globalThis.localStorage) {
62
- return storage instanceof globalThis.Storage;
63
+ isAvailable(config) {
64
+ return (config?.storage ?? globalThis.localStorage) instanceof globalThis.Storage;
63
65
  },
64
66
  create({ storage = globalThis.localStorage }) {
65
67
  return new StoreFS(new WebStorageStore(storage));
package/dist/utils.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { ErrnoError } from '@zenfs/core';
1
+ import { Exception } from 'kerium';
2
2
  /** @internal */
3
- export type ConvertException = ErrnoError | DOMException | Error;
3
+ export type ConvertException = Exception | DOMException | Error;
4
4
  /**
5
5
  * Handles converting errors, then rethrowing them
6
6
  * @internal
7
7
  */
8
- export declare function convertException(ex: ConvertException, path?: string, syscall?: string): ErrnoError;
8
+ export declare function convertException(ex: ConvertException, path?: string): Exception;
package/dist/utils.js CHANGED
@@ -1,4 +1,4 @@
1
- import { ErrnoError, Errno } from '@zenfs/core';
1
+ import { Exception, Errno } from 'kerium';
2
2
  /**
3
3
  * Converts a DOMException into an Errno
4
4
  * @see https://developer.mozilla.org/Web/API/DOMException
@@ -57,12 +57,13 @@ function errnoForDOMException(ex) {
57
57
  * Handles converting errors, then rethrowing them
58
58
  * @internal
59
59
  */
60
- export function convertException(ex, path, syscall) {
61
- if (ex instanceof ErrnoError)
60
+ export function convertException(ex, path) {
61
+ if (ex instanceof Exception)
62
62
  return ex;
63
63
  const code = ex instanceof DOMException ? Errno[errnoForDOMException(ex)] : Errno.EIO;
64
- const error = new ErrnoError(code, ex.message, path, syscall);
64
+ const error = new Exception(code, ex.message);
65
65
  error.stack = ex.stack;
66
+ Error.captureStackTrace?.(error, convertException);
66
67
  error.cause = ex.cause;
67
68
  return error;
68
69
  }
package/dist/xml.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { CreationOptions, File, InodeLike, StatsLike } from '@zenfs/core';
2
- import { FileSystem, Stats } from '@zenfs/core';
1
+ import type { CreationOptions, InodeLike, StatsLike } from '@zenfs/core';
2
+ import { FileSystem, Inode } from '@zenfs/core';
3
3
  export interface XMLOptions {
4
4
  /**
5
5
  * The root `fs` element
@@ -18,15 +18,15 @@ export declare class XMLFS extends XMLFS_base {
18
18
  */
19
19
  root?: Element);
20
20
  renameSync(oldPath: string, newPath: string): void;
21
- statSync(path: string): Stats;
22
- openFileSync(path: string, flag: string): File;
23
- createFileSync(path: string, flag: string, mode: number, { uid, gid }: CreationOptions): File;
21
+ statSync(path: string): Inode;
22
+ createFileSync(path: string, options: CreationOptions): Inode;
24
23
  unlinkSync(path: string): void;
25
24
  rmdirSync(path: string): void;
26
- mkdirSync(path: string, mode: number, { uid, gid }: CreationOptions): void;
25
+ mkdirSync(path: string, options: CreationOptions): InodeLike;
27
26
  readdirSync(path: string): string[];
28
27
  linkSync(target: string, link: string): void;
29
- syncSync(path: string, data?: Uint8Array, stats?: Readonly<Partial<InodeLike>>): void;
28
+ touchSync(path: string, metadata: Partial<InodeLike>): void;
29
+ syncSync(): void;
30
30
  readSync(path: string, buffer: Uint8Array, offset: number, end: number): void;
31
31
  writeSync(path: string, buffer: Uint8Array, offset: number): void;
32
32
  toString(): string;
@@ -39,7 +39,7 @@ declare const _XML: {
39
39
  name: string;
40
40
  options: {
41
41
  root: {
42
- type: "object";
42
+ type: string;
43
43
  required: false;
44
44
  };
45
45
  };
package/dist/xml.js CHANGED
@@ -1,5 +1,7 @@
1
- import { _inode_fields, constants, decodeRaw, encodeRaw, Errno, ErrnoError, FileSystem, LazyFile, Stats, Sync } from '@zenfs/core';
2
- import { basename, dirname } from '@zenfs/core/vfs/path.js';
1
+ import { withErrno } from 'kerium';
2
+ import { _inode_fields, constants, FileSystem, Inode, Sync } from '@zenfs/core';
3
+ import { basename, dirname } from '@zenfs/core/path.js';
4
+ import { decodeASCII, encodeASCII } from 'utilium';
3
5
  function get_stats(node) {
4
6
  const stats = {};
5
7
  for (const key of _inode_fields) {
@@ -7,7 +9,7 @@ function get_stats(node) {
7
9
  if (value !== null && value !== undefined)
8
10
  stats[key] = parseInt(value, 16);
9
11
  }
10
- return new Stats(stats);
12
+ return new Inode(stats);
11
13
  }
12
14
  function set_stats(node, stats) {
13
15
  for (const key of Object.keys(stats)) {
@@ -35,9 +37,8 @@ export class XMLFS extends Sync(FileSystem) {
35
37
  root = new DOMParser().parseFromString('<fs></fs>', 'application/xml').documentElement) {
36
38
  super(0x20786d6c, 'xmltmpfs');
37
39
  this.root = root;
38
- this.attributes.set('setid');
39
40
  try {
40
- this.mkdirSync('/', 0o777, { uid: 0, gid: 0 });
41
+ this.mkdirSync('/', { uid: 0, gid: 0, mode: 0o777 });
41
42
  }
42
43
  catch (e) {
43
44
  const error = e;
@@ -53,72 +54,68 @@ export class XMLFS extends Sync(FileSystem) {
53
54
  statSync(path) {
54
55
  return get_stats(this.get('stat', path));
55
56
  }
56
- openFileSync(path, flag) {
57
- const node = this.get('openFile', path);
58
- return new LazyFile(this, path, flag, get_stats(node));
59
- }
60
- createFileSync(path, flag, mode, { uid, gid }) {
57
+ createFileSync(path, options) {
61
58
  const parent = this.statSync(dirname(path));
62
- const stats = new Stats({
63
- mode: mode | constants.S_IFREG,
64
- uid: parent.mode & constants.S_ISUID ? parent.uid : uid,
65
- gid: parent.mode & constants.S_ISGID ? parent.gid : gid,
59
+ const inode = new Inode({
60
+ mode: options.mode | constants.S_IFREG,
61
+ uid: parent.mode & constants.S_ISUID ? parent.uid : options.uid,
62
+ gid: parent.mode & constants.S_ISGID ? parent.gid : options.gid,
66
63
  });
67
- this.create('createFile', path, stats);
68
- return new LazyFile(this, path, flag, stats);
64
+ this.create('createFile', path, inode);
65
+ return inode;
69
66
  }
70
67
  unlinkSync(path) {
71
68
  const node = this.get('unlink', path);
72
- if (get_stats(node).isDirectory())
73
- throw ErrnoError.With('EISDIR', path, 'unlink');
69
+ if (get_stats(node).mode & constants.S_IFDIR)
70
+ throw withErrno('EISDIR');
74
71
  this.remove('unlink', node, path);
75
72
  }
76
73
  rmdirSync(path) {
77
74
  const node = this.get('rmdir', path);
78
75
  if (node.textContent?.length)
79
- throw ErrnoError.With('ENOTEMPTY', path, 'rmdir');
80
- if (!get_stats(node).isDirectory())
81
- throw ErrnoError.With('ENOTDIR', path, 'rmdir');
76
+ throw withErrno('ENOTEMPTY');
77
+ if (!(get_stats(node).mode & constants.S_IFDIR))
78
+ throw withErrno('ENOTDIR');
82
79
  this.remove('rmdir', node, path);
83
80
  }
84
- mkdirSync(path, mode, { uid, gid }) {
81
+ mkdirSync(path, options) {
85
82
  const parent = this.statSync(dirname(path));
86
- const node = this.create('mkdir', path, {
87
- mode: mode | constants.S_IFDIR,
88
- uid: parent.mode & constants.S_ISUID ? parent.uid : uid,
89
- gid: parent.mode & constants.S_ISGID ? parent.gid : gid,
83
+ const inode = new Inode({
84
+ mode: options.mode | constants.S_IFDIR,
85
+ uid: parent.mode & constants.S_ISUID ? parent.uid : options.uid,
86
+ gid: parent.mode & constants.S_ISGID ? parent.gid : options.gid,
90
87
  });
91
- node.textContent = '[]';
88
+ this.create('mkdir', path, inode).textContent = '[]';
89
+ return inode;
92
90
  }
93
91
  readdirSync(path) {
94
92
  const node = this.get('readdir', path);
95
- if (!get_stats(node).isDirectory())
96
- throw ErrnoError.With('ENOTDIR', path, 'rmdir');
93
+ if (!(get_stats(node).mode & constants.S_IFDIR))
94
+ throw withErrno('ENOTDIR');
97
95
  try {
98
96
  return JSON.parse(node.textContent);
99
97
  }
100
98
  catch (e) {
101
- throw new ErrnoError(Errno.EIO, 'Invalid directory listing: ' + e, path, 'readdir');
99
+ throw withErrno('EIO', 'Invalid directory listing: ' + e);
102
100
  }
103
101
  }
104
102
  linkSync(target, link) {
105
103
  const node = this.get('link', target);
106
104
  this.add('link', node, link);
107
105
  }
108
- syncSync(path, data, stats = {}) {
109
- const node = this.get('sync', path);
110
- if (data)
111
- node.textContent = decodeRaw(data);
112
- set_stats(node, stats);
106
+ touchSync(path, metadata) {
107
+ const node = this.get('touch', path);
108
+ set_stats(node, metadata);
113
109
  }
110
+ syncSync() { }
114
111
  readSync(path, buffer, offset, end) {
115
112
  const node = this.get('read', path);
116
- const raw = encodeRaw(node.textContent.slice(offset, end));
113
+ const raw = encodeASCII(node.textContent.slice(offset, end));
117
114
  buffer.set(raw);
118
115
  }
119
116
  writeSync(path, buffer, offset) {
120
117
  const node = this.get('write', path);
121
- const data = decodeRaw(buffer);
118
+ const data = decodeASCII(buffer);
122
119
  const after = node.textContent.slice(offset + data.length);
123
120
  node.textContent = node.textContent.slice(0, offset) + data + after;
124
121
  }
@@ -128,19 +125,19 @@ export class XMLFS extends Sync(FileSystem) {
128
125
  get(syscall, path) {
129
126
  const nodes = this.root.children;
130
127
  if (!nodes)
131
- throw ErrnoError.With('EIO', path, syscall);
128
+ throw withErrno('EIO');
132
129
  for (let i = 0; i < nodes.length; i++) {
133
130
  if (get_paths(nodes[i]).includes(path))
134
131
  return nodes[i];
135
132
  }
136
- throw ErrnoError.With('ENOENT', path, syscall);
133
+ throw withErrno('ENOENT');
137
134
  }
138
135
  create(syscall, path, stats) {
139
136
  if (this.existsSync(path))
140
- throw ErrnoError.With('EEXIST', path, syscall);
137
+ throw withErrno('EEXIST');
141
138
  const node = document.createElement('file');
142
139
  this.add(syscall, node, path);
143
- set_stats(node, new Stats({
140
+ set_stats(node, new Inode({
144
141
  ...stats,
145
142
  uid: stats.mode,
146
143
  }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenfs/dom",
3
- "version": "1.1.5",
3
+ "version": "1.1.7",
4
4
  "description": "DOM backends for ZenFS",
5
5
  "funding": {
6
6
  "type": "individual",
@@ -61,8 +61,9 @@
61
61
  "typescript-eslint": "^8.8.1"
62
62
  },
63
63
  "peerDependencies": {
64
- "@zenfs/core": "^1.9.1",
65
- "utilium": "^1.2.10"
64
+ "@zenfs/core": "^2.1.0",
65
+ "kerium": "^1.3.4",
66
+ "utilium": "^2.0.0"
66
67
  },
67
68
  "keywords": [
68
69
  "filesystem",