@zenfs/dom 1.1.6 → 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;
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));
package/dist/access.d.ts CHANGED
@@ -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
  /**
@@ -33,7 +33,7 @@ export declare class WebAccessFS extends WebAccessFS_base {
33
33
  */
34
34
  writeFile(path: string, data: Uint8Array): Promise<void>;
35
35
  mkdir(path: string, options: CreationOptions): Promise<InodeLike>;
36
- protected get<const T extends FileSystemHandleKind | null>(kind: T | undefined, path: string, syscall?: string): T extends FileSystemHandleKind ? HKindToType<T> : FileSystemHandle;
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
2
  import { basename, dirname, join } from '@zenfs/core/path.js';
3
3
  import { S_IFDIR, S_IFMT } from '@zenfs/core/vfs/constants.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
  }
@@ -60,24 +61,24 @@ export class WebAccessFS extends Async(IndexFS) {
60
61
  * @hidden
61
62
  */
62
63
  this._sync = InMemory.create({ label: 'accessfs-cache' });
63
- this.attributes.set('no_buffer_resize');
64
+ this.attributes.set('no_buffer_resize', true);
64
65
  this._handles.set('/', handle);
65
66
  }
66
67
  async remove(path) {
67
68
  const handle = this.get('directory', dirname(path));
68
69
  await handle.removeEntry(basename(path), { recursive: true }).catch(ex => _throw(convertException(ex, path)));
69
70
  }
70
- removeSync(path) {
71
- throw log.crit(ErrnoError.With('ENOSYS', path));
71
+ removeSync() {
72
+ throw log.crit(withErrno('ENOSYS'));
72
73
  }
73
74
  async read(path, buffer, offset, end) {
74
75
  if (end <= offset)
75
76
  return;
76
- const handle = this.get('file', path, 'write');
77
+ const handle = this.get('file', path);
77
78
  const file = await handle.getFile();
78
79
  const data = await file.arrayBuffer();
79
80
  if (data.byteLength < end - offset)
80
- throw ErrnoError.With('ENODATA', path, 'read');
81
+ throw withErrno('ENODATA');
81
82
  buffer.set(new Uint8Array(data, offset, end - offset));
82
83
  }
83
84
  async write(path, buffer, offset) {
@@ -88,21 +89,21 @@ export class WebAccessFS extends Async(IndexFS) {
88
89
  }
89
90
  const inode = this.index.get(path);
90
91
  if (!inode)
91
- throw ErrnoError.With('ENOENT', path, 'write');
92
+ throw withErrno('ENOENT');
92
93
  const isDir = (inode.mode & S_IFMT) == S_IFDIR;
93
94
  let handle;
94
95
  try {
95
- handle = this.get(isDir ? 'directory' : 'file', path, 'write');
96
+ handle = this.get(isDir ? 'directory' : 'file', path);
96
97
  }
97
98
  catch {
98
- const parent = this.get('directory', dirname(path), 'write');
99
+ const parent = this.get('directory', dirname(path));
99
100
  handle = await parent[isDir ? 'getDirectoryHandle' : 'getFileHandle'](basename(path), { create: true }).catch((ex) => _throw(convertException(ex, path)));
100
101
  this._handles.set(path, handle);
101
102
  }
102
103
  if (isDir)
103
104
  return;
104
105
  if (isKind(handle, 'directory')) {
105
- 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'));
106
107
  return;
107
108
  }
108
109
  const writable = await handle.createWritable();
@@ -127,17 +128,17 @@ export class WebAccessFS extends Async(IndexFS) {
127
128
  }
128
129
  async mkdir(path, options) {
129
130
  const inode = await super.mkdir(path, options);
130
- const handle = this.get('directory', dirname(path), 'mkdir');
131
+ const handle = this.get('directory', dirname(path));
131
132
  const dir = await handle.getDirectoryHandle(basename(path), { create: true }).catch((ex) => _throw(convertException(ex, path)));
132
133
  this._handles.set(path, dir);
133
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
  }
@@ -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 {
package/dist/storage.js CHANGED
@@ -1,4 +1,5 @@
1
- import { Errno, ErrnoError, StoreFS, SyncMapTransaction } from '@zenfs/core';
1
+ import { withErrno } from 'kerium';
2
+ import { StoreFS, SyncMapTransaction } from '@zenfs/core';
2
3
  import { decodeASCII, encodeASCII } from 'utilium';
3
4
  /**
4
5
  * A synchronous key-value store backed by Storage.
@@ -36,7 +37,7 @@ export class WebStorageStore {
36
37
  this.storage.setItem(key.toString(), decodeASCII(data));
37
38
  }
38
39
  catch {
39
- throw new ErrnoError(Errno.ENOSPC, 'Storage is full.');
40
+ throw withErrno('ENOSPC');
40
41
  }
41
42
  }
42
43
  delete(key) {
@@ -44,7 +45,7 @@ export class WebStorageStore {
44
45
  this.storage.removeItem(key.toString());
45
46
  }
46
47
  catch (e) {
47
- throw new ErrnoError(Errno.EIO, 'Unable to delete key ' + key + ': ' + e);
48
+ throw withErrno('EIO', `Unable to delete '${key}': ${e}`);
48
49
  }
49
50
  }
50
51
  }
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.js CHANGED
@@ -1,4 +1,5 @@
1
- import { _inode_fields, constants, Errno, ErrnoError, FileSystem, Inode, Sync } from '@zenfs/core';
1
+ import { withErrno } from 'kerium';
2
+ import { _inode_fields, constants, FileSystem, Inode, Sync } from '@zenfs/core';
2
3
  import { basename, dirname } from '@zenfs/core/path.js';
3
4
  import { decodeASCII, encodeASCII } from 'utilium';
4
5
  function get_stats(node) {
@@ -66,15 +67,15 @@ export class XMLFS extends Sync(FileSystem) {
66
67
  unlinkSync(path) {
67
68
  const node = this.get('unlink', path);
68
69
  if (get_stats(node).mode & constants.S_IFDIR)
69
- throw ErrnoError.With('EISDIR', path, 'unlink');
70
+ throw withErrno('EISDIR');
70
71
  this.remove('unlink', node, path);
71
72
  }
72
73
  rmdirSync(path) {
73
74
  const node = this.get('rmdir', path);
74
75
  if (node.textContent?.length)
75
- throw ErrnoError.With('ENOTEMPTY', path, 'rmdir');
76
+ throw withErrno('ENOTEMPTY');
76
77
  if (!(get_stats(node).mode & constants.S_IFDIR))
77
- throw ErrnoError.With('ENOTDIR', path, 'rmdir');
78
+ throw withErrno('ENOTDIR');
78
79
  this.remove('rmdir', node, path);
79
80
  }
80
81
  mkdirSync(path, options) {
@@ -90,12 +91,12 @@ export class XMLFS extends Sync(FileSystem) {
90
91
  readdirSync(path) {
91
92
  const node = this.get('readdir', path);
92
93
  if (!(get_stats(node).mode & constants.S_IFDIR))
93
- throw ErrnoError.With('ENOTDIR', path, 'rmdir');
94
+ throw withErrno('ENOTDIR');
94
95
  try {
95
96
  return JSON.parse(node.textContent);
96
97
  }
97
98
  catch (e) {
98
- throw new ErrnoError(Errno.EIO, 'Invalid directory listing: ' + e, path, 'readdir');
99
+ throw withErrno('EIO', 'Invalid directory listing: ' + e);
99
100
  }
100
101
  }
101
102
  linkSync(target, link) {
@@ -124,16 +125,16 @@ export class XMLFS extends Sync(FileSystem) {
124
125
  get(syscall, path) {
125
126
  const nodes = this.root.children;
126
127
  if (!nodes)
127
- throw ErrnoError.With('EIO', path, syscall);
128
+ throw withErrno('EIO');
128
129
  for (let i = 0; i < nodes.length; i++) {
129
130
  if (get_paths(nodes[i]).includes(path))
130
131
  return nodes[i];
131
132
  }
132
- throw ErrnoError.With('ENOENT', path, syscall);
133
+ throw withErrno('ENOENT');
133
134
  }
134
135
  create(syscall, path, stats) {
135
136
  if (this.existsSync(path))
136
- throw ErrnoError.With('EEXIST', path, syscall);
137
+ throw withErrno('EEXIST');
137
138
  const node = document.createElement('file');
138
139
  this.add(syscall, node, path);
139
140
  set_stats(node, new Inode({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenfs/dom",
3
- "version": "1.1.6",
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": "^2.0.0",
65
- "utilium": "^1.9.0"
64
+ "@zenfs/core": "^2.1.0",
65
+ "kerium": "^1.3.4",
66
+ "utilium": "^2.0.0"
66
67
  },
67
68
  "keywords": [
68
69
  "filesystem",