@zenfs/dom 1.1.6 → 1.1.8
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/IndexedDB.d.ts +12 -4
- package/dist/IndexedDB.js +33 -8
- package/dist/access.d.ts +3 -3
- package/dist/access.js +17 -15
- package/dist/devices/framebuffer.js +2 -2
- package/dist/storage.js +4 -3
- package/dist/utils.d.ts +3 -3
- package/dist/utils.js +5 -4
- package/dist/xml.js +10 -9
- package/package.json +7 -6
package/dist/IndexedDB.d.ts
CHANGED
|
@@ -1,24 +1,32 @@
|
|
|
1
1
|
import type { SharedConfig, Store } from '@zenfs/core';
|
|
2
|
-
import {
|
|
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
|
|
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,
|
|
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 {
|
|
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
|
|
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
|
-
return (await wrap(this._idb.getAllKeys())).
|
|
32
|
+
return (await wrap(this._idb.getAllKeys())).map(Number);
|
|
24
33
|
}
|
|
25
34
|
async get(id) {
|
|
26
|
-
const data = await wrap(this._idb.get(id
|
|
35
|
+
const data = await wrap(this._idb.get(id));
|
|
27
36
|
if (data)
|
|
28
|
-
this.
|
|
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.
|
|
33
|
-
await wrap(this._idb.put(data, id
|
|
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
|
|
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
|
@@ -23,8 +23,8 @@ export declare class WebAccessFS extends WebAccessFS_base {
|
|
|
23
23
|
*/
|
|
24
24
|
_sync: FileSystem;
|
|
25
25
|
constructor(handle: FileSystemDirectoryHandle);
|
|
26
|
-
remove(path: string): Promise<void>;
|
|
27
|
-
protected removeSync(
|
|
26
|
+
protected remove(path: string): Promise<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
|
|
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,8 @@
|
|
|
1
|
-
import { Async, constants,
|
|
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';
|
|
5
|
+
import { alert } from 'kerium/log';
|
|
4
6
|
import { _throw } from 'utilium';
|
|
5
7
|
import { convertException } from './utils.js';
|
|
6
8
|
function isResizable(buffer) {
|
|
@@ -49,7 +51,7 @@ export class WebAccessFS extends Async(IndexFS) {
|
|
|
49
51
|
continue;
|
|
50
52
|
}
|
|
51
53
|
if (!isKind(handle, 'directory'))
|
|
52
|
-
throw
|
|
54
|
+
throw withErrno('EIO', 'Invalid handle');
|
|
53
55
|
this.index.set(path, new Inode({ mode: 0o777 | constants.S_IFDIR, size: 0 }));
|
|
54
56
|
}
|
|
55
57
|
}
|
|
@@ -60,24 +62,24 @@ export class WebAccessFS extends Async(IndexFS) {
|
|
|
60
62
|
* @hidden
|
|
61
63
|
*/
|
|
62
64
|
this._sync = InMemory.create({ label: 'accessfs-cache' });
|
|
63
|
-
this.attributes.set('no_buffer_resize');
|
|
65
|
+
this.attributes.set('no_buffer_resize', true);
|
|
64
66
|
this._handles.set('/', handle);
|
|
65
67
|
}
|
|
66
68
|
async remove(path) {
|
|
67
69
|
const handle = this.get('directory', dirname(path));
|
|
68
70
|
await handle.removeEntry(basename(path), { recursive: true }).catch(ex => _throw(convertException(ex, path)));
|
|
69
71
|
}
|
|
70
|
-
removeSync(
|
|
71
|
-
throw log.crit(
|
|
72
|
+
removeSync() {
|
|
73
|
+
throw log.crit(withErrno('ENOSYS'));
|
|
72
74
|
}
|
|
73
75
|
async read(path, buffer, offset, end) {
|
|
74
76
|
if (end <= offset)
|
|
75
77
|
return;
|
|
76
|
-
const handle = this.get('file', path
|
|
78
|
+
const handle = this.get('file', path);
|
|
77
79
|
const file = await handle.getFile();
|
|
78
80
|
const data = await file.arrayBuffer();
|
|
79
81
|
if (data.byteLength < end - offset)
|
|
80
|
-
throw
|
|
82
|
+
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.`));
|
|
81
83
|
buffer.set(new Uint8Array(data, offset, end - offset));
|
|
82
84
|
}
|
|
83
85
|
async write(path, buffer, offset) {
|
|
@@ -88,21 +90,21 @@ export class WebAccessFS extends Async(IndexFS) {
|
|
|
88
90
|
}
|
|
89
91
|
const inode = this.index.get(path);
|
|
90
92
|
if (!inode)
|
|
91
|
-
throw
|
|
93
|
+
throw withErrno('ENOENT');
|
|
92
94
|
const isDir = (inode.mode & S_IFMT) == S_IFDIR;
|
|
93
95
|
let handle;
|
|
94
96
|
try {
|
|
95
|
-
handle = this.get(isDir ? 'directory' : 'file', path
|
|
97
|
+
handle = this.get(isDir ? 'directory' : 'file', path);
|
|
96
98
|
}
|
|
97
99
|
catch {
|
|
98
|
-
const parent = this.get('directory', dirname(path)
|
|
100
|
+
const parent = this.get('directory', dirname(path));
|
|
99
101
|
handle = await parent[isDir ? 'getDirectoryHandle' : 'getFileHandle'](basename(path), { create: true }).catch((ex) => _throw(convertException(ex, path)));
|
|
100
102
|
this._handles.set(path, handle);
|
|
101
103
|
}
|
|
102
104
|
if (isDir)
|
|
103
105
|
return;
|
|
104
106
|
if (isKind(handle, 'directory')) {
|
|
105
|
-
log.crit(
|
|
107
|
+
log.crit(withErrno('EIO', 'Mismatch in entry kind on write'));
|
|
106
108
|
return;
|
|
107
109
|
}
|
|
108
110
|
const writable = await handle.createWritable();
|
|
@@ -127,17 +129,17 @@ export class WebAccessFS extends Async(IndexFS) {
|
|
|
127
129
|
}
|
|
128
130
|
async mkdir(path, options) {
|
|
129
131
|
const inode = await super.mkdir(path, options);
|
|
130
|
-
const handle = this.get('directory', dirname(path)
|
|
132
|
+
const handle = this.get('directory', dirname(path));
|
|
131
133
|
const dir = await handle.getDirectoryHandle(basename(path), { create: true }).catch((ex) => _throw(convertException(ex, path)));
|
|
132
134
|
this._handles.set(path, dir);
|
|
133
135
|
return inode;
|
|
134
136
|
}
|
|
135
|
-
get(kind = null, path
|
|
137
|
+
get(kind = null, path) {
|
|
136
138
|
const handle = this._handles.get(path);
|
|
137
139
|
if (!handle)
|
|
138
|
-
throw
|
|
140
|
+
throw withErrno('ENODATA');
|
|
139
141
|
if (kind && !isKind(handle, kind))
|
|
140
|
-
throw
|
|
142
|
+
throw withErrno(kind == 'directory' ? 'ENOTDIR' : 'EISDIR');
|
|
141
143
|
return handle;
|
|
142
144
|
}
|
|
143
145
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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
|
|
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 {
|
|
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
|
|
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
|
|
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 {
|
|
1
|
+
import { Exception } from 'kerium';
|
|
2
2
|
/** @internal */
|
|
3
|
-
export type ConvertException =
|
|
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
|
|
8
|
+
export declare function convertException(ex: ConvertException, path?: string): Exception;
|
package/dist/utils.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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
|
|
61
|
-
if (ex instanceof
|
|
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
|
|
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 {
|
|
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
|
|
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
|
|
76
|
+
throw withErrno('ENOTEMPTY');
|
|
76
77
|
if (!(get_stats(node).mode & constants.S_IFDIR))
|
|
77
|
-
throw
|
|
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
|
|
94
|
+
throw withErrno('ENOTDIR');
|
|
94
95
|
try {
|
|
95
96
|
return JSON.parse(node.textContent);
|
|
96
97
|
}
|
|
97
98
|
catch (e) {
|
|
98
|
-
throw
|
|
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
|
|
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
|
|
133
|
+
throw withErrno('ENOENT');
|
|
133
134
|
}
|
|
134
135
|
create(syscall, path, stats) {
|
|
135
136
|
if (this.existsSync(path))
|
|
136
|
-
throw
|
|
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.
|
|
3
|
+
"version": "1.1.8",
|
|
4
4
|
"description": "DOM backends for ZenFS",
|
|
5
5
|
"funding": {
|
|
6
6
|
"type": "individual",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"tsconfig.json"
|
|
33
33
|
],
|
|
34
34
|
"engines": {
|
|
35
|
-
"node": ">=
|
|
35
|
+
"node": ">= 22"
|
|
36
36
|
},
|
|
37
37
|
"exports": {
|
|
38
38
|
".": "./dist/index.js",
|
|
@@ -53,16 +53,17 @@
|
|
|
53
53
|
"c8": "^10.1.3",
|
|
54
54
|
"eslint": "^9.12.0",
|
|
55
55
|
"fake-indexeddb": "^6.0.0",
|
|
56
|
-
"globals": "^
|
|
56
|
+
"globals": "^16.0.0",
|
|
57
57
|
"prettier": "^3.2.5",
|
|
58
58
|
"tsx": "^4.19.2",
|
|
59
|
-
"typedoc": "^0.
|
|
59
|
+
"typedoc": "^0.28.0",
|
|
60
60
|
"typescript": "^5.7.2",
|
|
61
61
|
"typescript-eslint": "^8.8.1"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
|
-
"@zenfs/core": "^2.
|
|
65
|
-
"
|
|
64
|
+
"@zenfs/core": "^2.1.0",
|
|
65
|
+
"kerium": "^1.3.4",
|
|
66
|
+
"utilium": "^2.0.0"
|
|
66
67
|
},
|
|
67
68
|
"keywords": [
|
|
68
69
|
"filesystem",
|