@zenfs/dom 1.0.3 → 1.0.5

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,5 +1,5 @@
1
- import type { Ino, SharedConfig, Store } from '@zenfs/core';
2
- import { AsyncTransaction, StoreFS } from '@zenfs/core';
1
+ import type { SharedConfig, Store } from '@zenfs/core';
2
+ import { Async, AsyncTransaction, StoreFS } from '@zenfs/core';
3
3
  /**
4
4
  * @hidden
5
5
  */
@@ -8,10 +8,10 @@ export declare class IndexedDBTransaction extends AsyncTransaction<IndexedDBStor
8
8
  store: IndexedDBStore;
9
9
  private _idb;
10
10
  constructor(tx: IDBTransaction, store: IndexedDBStore);
11
- keys(): Promise<Iterable<Ino>>;
12
- get(key: Ino): Promise<Uint8Array>;
13
- set(key: Ino, data: Uint8Array): Promise<void>;
14
- remove(key: Ino): Promise<void>;
11
+ keys(): Promise<Iterable<bigint>>;
12
+ get(key: bigint): Promise<Uint8Array>;
13
+ set(key: bigint, data: Uint8Array): Promise<void>;
14
+ remove(key: bigint): Promise<void>;
15
15
  commit(): Promise<void>;
16
16
  abort(): Promise<void>;
17
17
  }
@@ -46,30 +46,14 @@ declare const _IndexedDB: {
46
46
  readonly storeName: {
47
47
  readonly type: "string";
48
48
  readonly required: false;
49
- readonly description: "The name of this file system. You can have multiple IndexedDB file systems operating at once, but each must have a different name.";
50
49
  };
51
50
  readonly idbFactory: {
52
51
  readonly type: "object";
53
52
  readonly required: false;
54
- readonly description: "The IDBFactory to use. Defaults to globalThis.indexedDB.";
55
53
  };
56
54
  };
57
55
  readonly isAvailable: (idbFactory?: IDBFactory) => Promise<boolean>;
58
- readonly create: (options: IndexedDBOptions & Partial<SharedConfig>) => Promise<{
59
- _sync?: import("@zenfs/core").FileSystem;
60
- queueDone(): Promise<void>;
61
- ready(): Promise<void>;
62
- renameSync(oldPath: string, newPath: string): void;
63
- statSync(path: string): import("@zenfs/core").Stats;
64
- createFileSync(path: string, flag: string, mode: number): import("@zenfs/core").File;
65
- openFileSync(path: string, flag: string): import("@zenfs/core").File;
66
- unlinkSync(path: string): void;
67
- rmdirSync(path: string): void;
68
- mkdirSync(path: string, mode: number): void;
69
- readdirSync(path: string): string[];
70
- linkSync(srcpath: string, dstpath: string): void;
71
- syncSync(path: string, data: Uint8Array, stats: Readonly<import("@zenfs/core").Stats>): void;
72
- } & StoreFS<IndexedDBStore>>;
56
+ readonly create: (options: IndexedDBOptions & Partial<SharedConfig>) => Promise<Async & StoreFS<IndexedDBStore>>;
73
57
  };
74
58
  type _IndexedDB = typeof _IndexedDB;
75
59
  interface IndexedDB extends _IndexedDB {
package/dist/IndexedDB.js CHANGED
@@ -97,12 +97,10 @@ const _IndexedDB = {
97
97
  storeName: {
98
98
  type: 'string',
99
99
  required: false,
100
- description: 'The name of this file system. You can have multiple IndexedDB file systems operating at once, but each must have a different name.',
101
100
  },
102
101
  idbFactory: {
103
102
  type: 'object',
104
103
  required: false,
105
- description: 'The IDBFactory to use. Defaults to globalThis.indexedDB.',
106
104
  },
107
105
  },
108
106
  async isAvailable(idbFactory = globalThis.indexedDB) {
@@ -112,13 +110,14 @@ const _IndexedDB = {
112
110
  }
113
111
  const req = idbFactory.open('__zenfs_test');
114
112
  await wrap(req);
115
- idbFactory.deleteDatabase('__zenfs_test');
116
113
  return true;
117
114
  }
118
- catch (e) {
119
- idbFactory.deleteDatabase('__zenfs_test');
115
+ catch {
120
116
  return false;
121
117
  }
118
+ finally {
119
+ idbFactory.deleteDatabase('__zenfs_test');
120
+ }
122
121
  },
123
122
  async create(options) {
124
123
  const db = await createDB(options.storeName || 'zenfs', options.idbFactory);
package/dist/Storage.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Ino, SimpleSyncStore, Store } from '@zenfs/core';
1
+ import type { SimpleSyncStore, Store } from '@zenfs/core';
2
2
  import { SimpleTransaction, StoreFS } from '@zenfs/core';
3
3
  /**
4
4
  * A synchronous key-value store backed by Storage.
@@ -11,10 +11,10 @@ export declare class WebStorageStore implements Store, SimpleSyncStore {
11
11
  clearSync(): void;
12
12
  sync(): Promise<void>;
13
13
  transaction(): SimpleTransaction;
14
- keys(): Iterable<Ino>;
15
- get(key: Ino): Uint8Array | undefined;
16
- set(key: Ino, data: Uint8Array): void;
17
- delete(key: Ino): void;
14
+ keys(): Iterable<bigint>;
15
+ get(key: bigint): Uint8Array | undefined;
16
+ set(key: bigint, data: Uint8Array): void;
17
+ delete(key: bigint): void;
18
18
  }
19
19
  /**
20
20
  * Options to pass to the StorageFileSystem
package/dist/Storage.js CHANGED
@@ -34,7 +34,7 @@ export class WebStorageStore {
34
34
  try {
35
35
  this.storage.setItem(key.toString(), decodeRaw(data));
36
36
  }
37
- catch (e) {
37
+ catch {
38
38
  throw new ErrnoError(Errno.ENOSPC, 'Storage is full.');
39
39
  }
40
40
  }
package/dist/access.d.ts CHANGED
@@ -1,23 +1,9 @@
1
1
  import type { FileSystemMetadata } from '@zenfs/core';
2
- import { FileSystem, PreloadFile, Stats } from '@zenfs/core';
2
+ import { Async, FileSystem, PreloadFile, Stats } from '@zenfs/core';
3
3
  export interface WebAccessOptions {
4
4
  handle: FileSystemDirectoryHandle;
5
5
  }
6
- declare const WebAccessFS_base: import("@zenfs/core").Mixin<typeof FileSystem, {
7
- _sync?: FileSystem;
8
- queueDone(): Promise<void>;
9
- ready(): Promise<void>;
10
- renameSync(oldPath: string, newPath: string): void;
11
- statSync(path: string): Stats;
12
- createFileSync(path: string, flag: string, mode: number): import("@zenfs/core").File;
13
- openFileSync(path: string, flag: string): import("@zenfs/core").File;
14
- unlinkSync(path: string): void;
15
- rmdirSync(path: string): void;
16
- mkdirSync(path: string, mode: number): void;
17
- readdirSync(path: string): string[];
18
- linkSync(srcpath: string, dstpath: string): void;
19
- syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
20
- }>;
6
+ declare const WebAccessFS_base: import("@zenfs/core").Mixin<typeof FileSystem, Async>;
21
7
  export declare class WebAccessFS extends WebAccessFS_base {
22
8
  private _handles;
23
9
  /**
@@ -26,7 +12,7 @@ export declare class WebAccessFS extends WebAccessFS_base {
26
12
  _sync: FileSystem;
27
13
  constructor(handle: FileSystemDirectoryHandle);
28
14
  metadata(): FileSystemMetadata;
29
- sync(path: string, data: Uint8Array, stats: Stats): Promise<void>;
15
+ sync(path: string, data: Uint8Array): Promise<void>;
30
16
  rename(oldPath: string, newPath: string): Promise<void>;
31
17
  writeFile(path: string, data: Uint8Array): Promise<void>;
32
18
  createFile(path: string, flag: string): Promise<PreloadFile<this>>;
@@ -37,7 +23,7 @@ export declare class WebAccessFS extends WebAccessFS_base {
37
23
  rmdir(path: string): Promise<void>;
38
24
  mkdir(path: string): Promise<void>;
39
25
  readdir(path: string): Promise<string[]>;
40
- protected getHandle(path: string): Promise<FileSystemHandle>;
26
+ protected getHandle(path: string): Promise<FileSystemHandle | undefined>;
41
27
  }
42
28
  declare const _WebAccess: {
43
29
  readonly name: "WebAccess";
package/dist/access.js CHANGED
@@ -19,44 +19,40 @@ export class WebAccessFS extends Async(FileSystem) {
19
19
  noResizableBuffers: true,
20
20
  };
21
21
  }
22
- async sync(path, data, stats) {
23
- const currentStats = await this.stat(path);
24
- if (stats.mtime !== currentStats.mtime) {
25
- await this.writeFile(path, data);
26
- }
22
+ async sync(path, data) {
23
+ await this.writeFile(path, data);
27
24
  }
28
25
  async rename(oldPath, newPath) {
29
- try {
30
- const handle = await this.getHandle(oldPath);
31
- if (handle instanceof FileSystemDirectoryHandle) {
32
- const files = await this.readdir(oldPath);
33
- await this.mkdir(newPath);
34
- if (files.length == 0) {
35
- await this.unlink(oldPath);
36
- }
37
- else {
38
- for (const file of files) {
39
- await this.rename(join(oldPath, file), join(newPath, file));
40
- await this.unlink(oldPath);
41
- }
42
- }
43
- }
44
- if (!(handle instanceof FileSystemFileHandle)) {
26
+ const handle = await this.getHandle(oldPath);
27
+ if (handle instanceof FileSystemDirectoryHandle) {
28
+ const files = await this.readdir(oldPath);
29
+ await this.mkdir(newPath);
30
+ if (!files.length) {
31
+ await this.unlink(oldPath);
45
32
  return;
46
33
  }
47
- const oldFile = await handle.getFile(), destFolder = await this.getHandle(dirname(newPath));
48
- if (!(destFolder instanceof FileSystemDirectoryHandle)) {
49
- return;
34
+ for (const file of files) {
35
+ await this.rename(join(oldPath, file), join(newPath, file));
36
+ await this.unlink(oldPath);
50
37
  }
51
- const newFile = await destFolder.getFileHandle(basename(newPath), { create: true });
52
- const writable = await newFile.createWritable();
53
- await writable.write(await oldFile.arrayBuffer());
54
- await writable.close();
55
- await this.unlink(oldPath);
38
+ return;
39
+ }
40
+ if (!(handle instanceof FileSystemFileHandle)) {
41
+ throw new ErrnoError(Errno.ENOTSUP, 'Not a file or directory handle', oldPath, 'rename');
56
42
  }
57
- catch (ex) {
43
+ const oldFile = await handle.getFile().catch((ex) => {
58
44
  throw convertException(ex, oldPath, 'rename');
45
+ }), destFolder = await this.getHandle(dirname(newPath));
46
+ if (!(destFolder instanceof FileSystemDirectoryHandle)) {
47
+ return;
59
48
  }
49
+ const newFile = await destFolder.getFileHandle(basename(newPath), { create: true }).catch((ex) => {
50
+ throw convertException(ex, newPath, 'rename');
51
+ });
52
+ const writable = await newFile.createWritable();
53
+ await writable.write(await oldFile.arrayBuffer());
54
+ await writable.close();
55
+ await this.unlink(oldPath);
60
56
  }
61
57
  async writeFile(path, data) {
62
58
  if (data.buffer.resizable) {
@@ -94,35 +90,35 @@ export class WebAccessFS extends Async(FileSystem) {
94
90
  if (!(handle instanceof FileSystemFileHandle)) {
95
91
  throw ErrnoError.With('EISDIR', path, 'openFile');
96
92
  }
97
- try {
98
- const file = await handle.getFile();
99
- const data = new Uint8Array(await file.arrayBuffer());
100
- const stats = new Stats({ mode: 0o777 | S_IFREG, size: file.size, mtimeMs: file.lastModified });
101
- return new PreloadFile(this, path, flag, stats, data);
102
- }
103
- catch (ex) {
93
+ const file = await handle.getFile().catch((ex) => {
104
94
  throw convertException(ex, path, 'openFile');
105
- }
95
+ });
96
+ const data = new Uint8Array(await file.arrayBuffer());
97
+ const stats = new Stats({ mode: 0o777 | S_IFREG, size: file.size, mtimeMs: file.lastModified });
98
+ return new PreloadFile(this, path, flag, stats, data);
106
99
  }
107
100
  async unlink(path) {
108
101
  const handle = await this.getHandle(dirname(path));
109
- if (handle instanceof FileSystemDirectoryHandle) {
110
- try {
111
- await handle.removeEntry(basename(path), { recursive: true });
112
- }
113
- catch (ex) {
114
- throw convertException(ex, path, 'unlink');
115
- }
102
+ if (!(handle instanceof FileSystemDirectoryHandle)) {
103
+ throw ErrnoError.With('ENOTDIR', dirname(path), 'unlink');
116
104
  }
105
+ await handle.removeEntry(basename(path), { recursive: true }).catch((ex) => {
106
+ throw convertException(ex, path, 'unlink');
107
+ });
117
108
  }
109
+ // eslint-disable-next-line @typescript-eslint/require-await
118
110
  async link(srcpath) {
119
- throw ErrnoError.With('ENOSYS', srcpath, 'WebAccessFS.link');
111
+ return;
120
112
  }
121
113
  async rmdir(path) {
122
114
  return this.unlink(path);
123
115
  }
124
116
  async mkdir(path) {
125
- const existingHandle = await this.getHandle(path);
117
+ const existingHandle = await this.getHandle(path).catch((ex) => {
118
+ if (ex.code != 'ENOENT') {
119
+ throw ex;
120
+ }
121
+ });
126
122
  if (existingHandle) {
127
123
  throw ErrnoError.With('EEXIST', path, 'mkdir');
128
124
  }
@@ -154,26 +150,20 @@ export class WebAccessFS extends Async(FileSystem) {
154
150
  throw ErrnoError.With('ENOTDIR', walked, 'getHandle');
155
151
  }
156
152
  walked = join(walked, part);
157
- try {
158
- const dirHandle = await handle.getDirectoryHandle(part);
159
- this._handles.set(walked, dirHandle);
160
- }
161
- catch (_ex) {
162
- const ex = _ex;
163
- if (ex.name == 'TypeMismatchError') {
164
- try {
165
- const fileHandle = await handle.getFileHandle(part);
166
- this._handles.set(walked, fileHandle);
167
- }
168
- catch (ex) {
169
- convertException(ex, walked, 'getHandle');
170
- }
153
+ const child = await handle.getDirectoryHandle(part).catch((ex) => {
154
+ switch (ex.name) {
155
+ case 'TypeMismatchError':
156
+ return handle.getFileHandle(part).catch((ex) => {
157
+ //throw convertException(ex, walked, 'getHandle');
158
+ });
159
+ case 'TypeError':
160
+ throw new ErrnoError(Errno.ENOENT, ex.message, walked, 'getHandle');
161
+ default:
162
+ throw convertException(ex, walked, 'getHandle');
171
163
  }
172
- if (ex.name === 'TypeError') {
173
- throw new ErrnoError(Errno.ENOENT, ex.message, walked, 'getHandle');
174
- }
175
- convertException(ex, walked, 'getHandle');
176
- }
164
+ });
165
+ if (child)
166
+ this._handles.set(walked, child);
177
167
  }
178
168
  return this._handles.get(path);
179
169
  }
@@ -0,0 +1,6 @@
1
+ import type { DeviceDriver } from '@zenfs/core';
2
+ import './audioworklet.d.ts';
3
+ export interface DspOptions {
4
+ audioContext?: AudioContext;
5
+ }
6
+ export declare function dsp(options?: DspOptions): Promise<DeviceDriver<AudioWorkletNode>>;
@@ -0,0 +1,55 @@
1
+ import './audioworklet.d.ts';
2
+ if ('AudioWorkletProcessor' in globalThis) {
3
+ class Dsp extends AudioWorkletProcessor {
4
+ constructor() {
5
+ super();
6
+ this.port.onmessage = ({ data }) => {
7
+ this.buffer = new Float32Array(data);
8
+ };
9
+ }
10
+ process(inputs, outputs) {
11
+ if (this.buffer && this.buffer.byteLength >= 128) {
12
+ outputs[0][0].set(this.buffer.slice(0, 128));
13
+ this.buffer = this.buffer.slice(128);
14
+ }
15
+ return true;
16
+ }
17
+ static get parameterDescriptors() {
18
+ return [
19
+ {
20
+ name: 'gain',
21
+ defaultValue: 1,
22
+ minValue: 0,
23
+ maxValue: 1,
24
+ automationRate: 'a-rate',
25
+ },
26
+ ];
27
+ }
28
+ }
29
+ registerProcessor('zenfs:dsp', Dsp);
30
+ }
31
+ export async function dsp(options = {}) {
32
+ const context = options.audioContext || new AudioContext();
33
+ await context.audioWorklet.addModule(import.meta.url);
34
+ const dsp = new AudioWorkletNode(context, 'zenfs:dsp');
35
+ dsp.connect(context.destination);
36
+ // add a click-handler to resume (due to web security) https://goo.gl/7K7WLu
37
+ document.addEventListener('click', () => {
38
+ if (context.state != 'running') {
39
+ void context.resume().catch(() => { });
40
+ }
41
+ });
42
+ return {
43
+ name: 'dsp',
44
+ init() {
45
+ return { data: dsp, major: 14, minor: 3 };
46
+ },
47
+ read() {
48
+ return 0;
49
+ },
50
+ write(file, data) {
51
+ dsp.port.postMessage(data.buffer);
52
+ return data.byteLength;
53
+ },
54
+ };
55
+ }
@@ -0,0 +1,5 @@
1
+ import type { DeviceDriver } from '@zenfs/core';
2
+ export interface FramebufferOptions {
3
+ canvas?: HTMLCanvasElement | null;
4
+ }
5
+ export declare function framebuffer({ canvas }?: FramebufferOptions): DeviceDriver<CanvasRenderingContext2D>;
@@ -0,0 +1,30 @@
1
+ /* Credit: David Konsumer */
2
+ import { Errno, ErrnoError } from '@zenfs/core';
3
+ let framebufferN = 0;
4
+ export function framebuffer({ canvas } = {}) {
5
+ if (!canvas) {
6
+ canvas = document.createElement('canvas');
7
+ document.body.appendChild(canvas);
8
+ }
9
+ const ctx = canvas.getContext('2d');
10
+ if (!ctx) {
11
+ throw new ErrnoError(Errno.EIO, 'Could not get context from canvas whilst initializing frame buffer.');
12
+ }
13
+ return {
14
+ name: 'framebuffer',
15
+ init() {
16
+ return { data: ctx, major: 29, minor: framebufferN++ };
17
+ },
18
+ read() {
19
+ return 0;
20
+ },
21
+ write(file, data) {
22
+ if (data.byteLength < 4 * canvas.width * canvas.height) {
23
+ return 0;
24
+ }
25
+ const imageData = new ImageData(new Uint8ClampedArray(data), canvas.width, canvas.height);
26
+ ctx.putImageData(imageData, 0, 0);
27
+ return data.byteLength;
28
+ },
29
+ };
30
+ }
@@ -0,0 +1,2 @@
1
+ export * from './dsp.js';
2
+ export * from './framebuffer.js';
@@ -0,0 +1,2 @@
1
+ export * from './dsp.js';
2
+ export * from './framebuffer.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenfs/dom",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "DOM backends for ZenFS",
5
5
  "funding": {
6
6
  "type": "individual",
@@ -11,6 +11,9 @@
11
11
  "type": "module",
12
12
  "homepage": "https://github.com/zen-fs/dom",
13
13
  "author": "James Prevett <jp@jamespre.dev> (https://jamespre.dev)",
14
+ "contributors": [
15
+ "David Konsumer <konsumer@jetboystudio.com>"
16
+ ],
14
17
  "license": "MIT",
15
18
  "repository": {
16
19
  "type": "git",
@@ -29,7 +32,8 @@
29
32
  },
30
33
  "exports": {
31
34
  ".": "./dist/index.js",
32
- "./*": "./dist/*"
35
+ "./*": "./dist/*",
36
+ "./devices": "./dist/devices/index.js"
33
37
  },
34
38
  "scripts": {
35
39
  "format": "prettier --write .",
@@ -51,7 +55,7 @@
51
55
  "typescript-eslint": "^8.8.1"
52
56
  },
53
57
  "peerDependencies": {
54
- "@zenfs/core": "^1.2.0"
58
+ "@zenfs/core": "^1.3.0"
55
59
  },
56
60
  "optionalDependencies": {
57
61
  "fake-indexeddb": "^6.0.0",