@zenfs/dom 1.1.3 → 1.1.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.
- package/dist/IndexedDB.d.ts +9 -9
- package/dist/IndexedDB.js +28 -37
- package/dist/access.d.ts +31 -18
- package/dist/access.js +118 -152
- package/dist/devices/dsp.js +6 -7
- package/dist/devices/framebuffer.d.ts +5 -1
- package/dist/devices/framebuffer.js +14 -14
- package/dist/storage.d.ts +8 -8
- package/dist/storage.js +3 -3
- package/dist/utils.js +3 -3
- package/dist/xml.d.ts +7 -6
- package/dist/xml.js +27 -17
- package/package.json +5 -4
- package/readme.md +4 -4
- package/tsconfig.json +3 -2
package/dist/IndexedDB.d.ts
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SharedConfig, Store } from '@zenfs/core';
|
|
2
2
|
import { AsyncTransaction, StoreFS } from '@zenfs/core';
|
|
3
|
+
import type * as cache from 'utilium/cache.js';
|
|
3
4
|
/**
|
|
4
|
-
* @hidden
|
|
5
|
+
* @internal @hidden
|
|
5
6
|
*/
|
|
6
7
|
export declare class IndexedDBTransaction extends AsyncTransaction<IndexedDBStore> {
|
|
7
8
|
tx: IDBTransaction;
|
|
8
9
|
store: IndexedDBStore;
|
|
9
10
|
private _idb;
|
|
10
11
|
constructor(tx: IDBTransaction, store: IndexedDBStore);
|
|
11
|
-
keys(): Promise<Iterable<
|
|
12
|
-
get(
|
|
13
|
-
set(
|
|
14
|
-
remove(
|
|
12
|
+
keys(): Promise<Iterable<number>>;
|
|
13
|
+
get(id: number): Promise<Uint8Array | undefined>;
|
|
14
|
+
set(id: number, data: Uint8Array): Promise<void>;
|
|
15
|
+
remove(id: number): Promise<void>;
|
|
15
16
|
commit(): Promise<void>;
|
|
16
17
|
abort(): Promise<void>;
|
|
17
18
|
}
|
|
18
19
|
export declare class IndexedDBStore implements Store {
|
|
19
20
|
protected db: IDBDatabase;
|
|
21
|
+
cache: Map<number, cache.Resource<number>>;
|
|
20
22
|
constructor(db: IDBDatabase);
|
|
21
23
|
sync(): Promise<void>;
|
|
22
24
|
get name(): string;
|
|
23
|
-
clear(): Promise<void>;
|
|
24
|
-
clearSync(): void;
|
|
25
25
|
transaction(): IndexedDBTransaction;
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
@@ -53,7 +53,7 @@ declare const _IndexedDB: {
|
|
|
53
53
|
};
|
|
54
54
|
};
|
|
55
55
|
readonly isAvailable: (idbFactory?: IDBFactory) => Promise<boolean>;
|
|
56
|
-
readonly create: (options: IndexedDBOptions & Partial<SharedConfig>) => Promise<
|
|
56
|
+
readonly create: (options: IndexedDBOptions & Partial<SharedConfig>) => Promise<StoreFS<IndexedDBStore>>;
|
|
57
57
|
};
|
|
58
58
|
type _IndexedDB = typeof _IndexedDB;
|
|
59
59
|
export interface IndexedDB extends _IndexedDB {
|
package/dist/IndexedDB.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AsyncTransaction, StoreFS, log } from '@zenfs/core';
|
|
2
2
|
import { convertException } from './utils.js';
|
|
3
3
|
function wrap(request) {
|
|
4
4
|
return new Promise((resolve, reject) => {
|
|
@@ -10,7 +10,7 @@ function wrap(request) {
|
|
|
10
10
|
});
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
|
-
* @hidden
|
|
13
|
+
* @internal @hidden
|
|
14
14
|
*/
|
|
15
15
|
export class IndexedDBTransaction extends AsyncTransaction {
|
|
16
16
|
constructor(tx, store) {
|
|
@@ -20,33 +20,30 @@ export class IndexedDBTransaction extends AsyncTransaction {
|
|
|
20
20
|
this._idb = tx.objectStore(store.name);
|
|
21
21
|
}
|
|
22
22
|
async keys() {
|
|
23
|
-
return (await wrap(this._idb.getAllKeys())).filter(k => typeof k == 'string').map(k =>
|
|
23
|
+
return (await wrap(this._idb.getAllKeys())).filter(k => typeof k == 'string').map(k => Number(k));
|
|
24
24
|
}
|
|
25
|
-
get(
|
|
26
|
-
|
|
25
|
+
async get(id) {
|
|
26
|
+
const data = await wrap(this._idb.get(id.toString()));
|
|
27
|
+
if (data)
|
|
28
|
+
this._cached(id, { size: data.byteLength }).add(data, 0);
|
|
29
|
+
return data;
|
|
27
30
|
}
|
|
28
|
-
async set(
|
|
29
|
-
|
|
31
|
+
async set(id, data) {
|
|
32
|
+
this._cached(id, { size: data.byteLength }).add(data, 0);
|
|
33
|
+
await wrap(this._idb.put(data, id.toString()));
|
|
30
34
|
}
|
|
31
|
-
remove(
|
|
32
|
-
|
|
35
|
+
remove(id) {
|
|
36
|
+
this.store.cache.delete(id);
|
|
37
|
+
return wrap(this._idb.delete(id.toString()));
|
|
33
38
|
}
|
|
34
39
|
async commit() {
|
|
35
|
-
if (this.done) {
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
40
|
const { promise, resolve, reject } = Promise.withResolvers();
|
|
39
|
-
this.done = true;
|
|
40
41
|
this.tx.oncomplete = () => resolve();
|
|
41
42
|
this.tx.onerror = () => reject(convertException(this.tx.error));
|
|
42
43
|
this.tx.commit();
|
|
43
44
|
return promise;
|
|
44
45
|
}
|
|
45
46
|
async abort() {
|
|
46
|
-
if (this.done) {
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
this.done = true;
|
|
50
47
|
const { promise, resolve, reject } = Promise.withResolvers();
|
|
51
48
|
this.tx.onabort = () => resolve();
|
|
52
49
|
this.tx.onerror = () => reject(convertException(this.tx.error));
|
|
@@ -60,29 +57,24 @@ async function createDB(name, indexedDB = globalThis.indexedDB) {
|
|
|
60
57
|
const db = req.result;
|
|
61
58
|
// This should never happen; we're at version 1. Why does another database exist?
|
|
62
59
|
if (db.objectStoreNames.contains(name)) {
|
|
60
|
+
log.warn('Found unexpected object store: ' + name);
|
|
63
61
|
db.deleteObjectStore(name);
|
|
64
62
|
}
|
|
65
63
|
db.createObjectStore(name);
|
|
66
64
|
};
|
|
67
|
-
|
|
68
|
-
return result;
|
|
65
|
+
return await wrap(req);
|
|
69
66
|
}
|
|
70
67
|
export class IndexedDBStore {
|
|
71
68
|
constructor(db) {
|
|
72
69
|
this.db = db;
|
|
70
|
+
this.cache = new Map();
|
|
73
71
|
}
|
|
74
72
|
sync() {
|
|
75
|
-
|
|
73
|
+
return Promise.resolve();
|
|
76
74
|
}
|
|
77
75
|
get name() {
|
|
78
76
|
return this.db.name;
|
|
79
77
|
}
|
|
80
|
-
clear() {
|
|
81
|
-
return wrap(this.db.transaction(this.name, 'readwrite').objectStore(this.name).clear());
|
|
82
|
-
}
|
|
83
|
-
clearSync() {
|
|
84
|
-
throw ErrnoError.With('ENOSYS', undefined, 'IndexedDBStore.clearSync');
|
|
85
|
-
}
|
|
86
78
|
transaction() {
|
|
87
79
|
const tx = this.db.transaction(this.name, 'readwrite');
|
|
88
80
|
return new IndexedDBTransaction(tx, this);
|
|
@@ -94,14 +86,8 @@ export class IndexedDBStore {
|
|
|
94
86
|
const _IndexedDB = {
|
|
95
87
|
name: 'IndexedDB',
|
|
96
88
|
options: {
|
|
97
|
-
storeName: {
|
|
98
|
-
|
|
99
|
-
required: false,
|
|
100
|
-
},
|
|
101
|
-
idbFactory: {
|
|
102
|
-
type: 'object',
|
|
103
|
-
required: false,
|
|
104
|
-
},
|
|
89
|
+
storeName: { type: 'string', required: false },
|
|
90
|
+
idbFactory: { type: 'object', required: false },
|
|
105
91
|
},
|
|
106
92
|
async isAvailable(idbFactory = globalThis.indexedDB) {
|
|
107
93
|
try {
|
|
@@ -122,9 +108,14 @@ const _IndexedDB = {
|
|
|
122
108
|
async create(options) {
|
|
123
109
|
const db = await createDB(options.storeName || 'zenfs', options.idbFactory);
|
|
124
110
|
const store = new IndexedDBStore(db);
|
|
125
|
-
const fs = new
|
|
126
|
-
if (
|
|
127
|
-
|
|
111
|
+
const fs = new StoreFS(store);
|
|
112
|
+
if (options?.disableAsyncCache) {
|
|
113
|
+
log.notice('Async preloading disabled for IndexedDB');
|
|
114
|
+
return fs;
|
|
115
|
+
}
|
|
116
|
+
const tx = store.transaction();
|
|
117
|
+
for (const id of await tx.keys()) {
|
|
118
|
+
await tx.get(id); // Adds to cache
|
|
128
119
|
}
|
|
129
120
|
return fs;
|
|
130
121
|
},
|
package/dist/access.d.ts
CHANGED
|
@@ -1,29 +1,39 @@
|
|
|
1
|
-
import type { CreationOptions,
|
|
2
|
-
import {
|
|
1
|
+
import type { CreationOptions, FileSystem } from '@zenfs/core';
|
|
2
|
+
import { IndexFS } from '@zenfs/core';
|
|
3
3
|
export interface WebAccessOptions {
|
|
4
4
|
handle: FileSystemDirectoryHandle;
|
|
5
|
+
metadata?: string;
|
|
5
6
|
}
|
|
6
|
-
|
|
7
|
+
type HKindToType<T extends FileSystemHandleKind> = T extends 'directory' ? FileSystemDirectoryHandle : T extends 'file' ? FileSystemFileHandle : FileSystemHandle;
|
|
8
|
+
declare const WebAccessFS_base: import("@zenfs/core").Mixin<typeof IndexFS, import("@zenfs/core").AsyncMixin>;
|
|
7
9
|
export declare class WebAccessFS extends WebAccessFS_base {
|
|
8
|
-
|
|
10
|
+
protected _handles: Map<string, FileSystemHandle>;
|
|
11
|
+
/**
|
|
12
|
+
* Loads all of the handles.
|
|
13
|
+
* @internal @hidden
|
|
14
|
+
*/
|
|
15
|
+
_loadHandles(path: string, handle: FileSystemDirectoryHandle): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Loads metadata
|
|
18
|
+
* @internal @hidden
|
|
19
|
+
*/
|
|
20
|
+
_loadMetadata(metadataPath?: string): Promise<void>;
|
|
9
21
|
/**
|
|
10
22
|
* @hidden
|
|
11
23
|
*/
|
|
12
24
|
_sync: FileSystem;
|
|
13
25
|
constructor(handle: FileSystemDirectoryHandle);
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
26
|
+
remove(path: string): Promise<void>;
|
|
27
|
+
protected removeSync(path: string): void;
|
|
28
|
+
read(path: string, buffer: Uint8Array, offset: number, end: number): Promise<void>;
|
|
29
|
+
write(path: string, buffer: Uint8Array, offset: number): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Do not use!
|
|
32
|
+
* @deprecated @internal @hidden
|
|
33
|
+
*/
|
|
17
34
|
writeFile(path: string, data: Uint8Array): Promise<void>;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
openFile(path: string, flag: string): Promise<PreloadFile<this>>;
|
|
21
|
-
unlink(path: string): Promise<void>;
|
|
22
|
-
link(srcpath: string): Promise<void>;
|
|
23
|
-
rmdir(path: string): Promise<void>;
|
|
24
|
-
mkdir(path: string, mode?: number, options?: CreationOptions): Promise<void>;
|
|
25
|
-
readdir(path: string): Promise<string[]>;
|
|
26
|
-
protected getHandle(path: string): Promise<FileSystemHandle | undefined>;
|
|
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;
|
|
27
37
|
}
|
|
28
38
|
declare const _WebAccess: {
|
|
29
39
|
readonly name: "WebAccess";
|
|
@@ -32,9 +42,12 @@ declare const _WebAccess: {
|
|
|
32
42
|
readonly type: "object";
|
|
33
43
|
readonly required: true;
|
|
34
44
|
};
|
|
45
|
+
readonly metadata: {
|
|
46
|
+
readonly type: "string";
|
|
47
|
+
readonly required: false;
|
|
48
|
+
};
|
|
35
49
|
};
|
|
36
|
-
readonly
|
|
37
|
-
readonly create: (options: WebAccessOptions) => WebAccessFS;
|
|
50
|
+
readonly create: (options: WebAccessOptions) => Promise<WebAccessFS>;
|
|
38
51
|
};
|
|
39
52
|
type _WebAccess = typeof _WebAccess;
|
|
40
53
|
export interface WebAccess extends _WebAccess {
|
package/dist/access.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { Async, constants, Errno, ErrnoError,
|
|
1
|
+
import { Async, constants, Errno, ErrnoError, IndexFS, InMemory, Inode, log } from '@zenfs/core';
|
|
2
|
+
import { S_IFDIR, S_IFMT } from '@zenfs/core/vfs/constants.js';
|
|
2
3
|
import { basename, dirname, join } from '@zenfs/core/vfs/path.js';
|
|
4
|
+
import { _throw } from 'utilium';
|
|
3
5
|
import { convertException } from './utils.js';
|
|
4
6
|
function isResizable(buffer) {
|
|
5
7
|
if (buffer instanceof ArrayBuffer)
|
|
@@ -8,184 +10,148 @@ function isResizable(buffer) {
|
|
|
8
10
|
return buffer.growable;
|
|
9
11
|
return false;
|
|
10
12
|
}
|
|
11
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Since `FileSystemHandle.kind` doesn't have correct type support
|
|
15
|
+
*/
|
|
16
|
+
function isKind(handle, kind) {
|
|
17
|
+
return handle.kind == kind;
|
|
18
|
+
}
|
|
19
|
+
export class WebAccessFS extends Async(IndexFS) {
|
|
20
|
+
/**
|
|
21
|
+
* Loads all of the handles.
|
|
22
|
+
* @internal @hidden
|
|
23
|
+
*/
|
|
24
|
+
async _loadHandles(path, handle) {
|
|
25
|
+
for await (const [key, child] of handle.entries()) {
|
|
26
|
+
const p = join(path, key);
|
|
27
|
+
this._handles.set(p, child);
|
|
28
|
+
if (isKind(child, 'directory'))
|
|
29
|
+
await this._loadHandles(p, child);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Loads metadata
|
|
34
|
+
* @internal @hidden
|
|
35
|
+
*/
|
|
36
|
+
async _loadMetadata(metadataPath) {
|
|
37
|
+
if (metadataPath) {
|
|
38
|
+
const handle = this.get('file', metadataPath);
|
|
39
|
+
const file = await handle.getFile();
|
|
40
|
+
const raw = await file.text();
|
|
41
|
+
const data = JSON.parse(raw);
|
|
42
|
+
this.index.fromJSON(data);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
for (const [path, handle] of this._handles) {
|
|
46
|
+
if (isKind(handle, 'file')) {
|
|
47
|
+
const { lastModified, size } = await handle.getFile();
|
|
48
|
+
this.index.set(path, new Inode({ mode: 0o644 | constants.S_IFREG, size, mtimeMs: lastModified }));
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (!isKind(handle, 'directory'))
|
|
52
|
+
throw new ErrnoError(Errno.EIO, 'Invalid handle', path);
|
|
53
|
+
this.index.set(path, new Inode({ mode: 0o777 | constants.S_IFDIR, size: 0 }));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
12
56
|
constructor(handle) {
|
|
13
|
-
super();
|
|
57
|
+
super(0x77656261, 'webaccessfs');
|
|
14
58
|
this._handles = new Map();
|
|
15
59
|
/**
|
|
16
60
|
* @hidden
|
|
17
61
|
*/
|
|
18
62
|
this._sync = InMemory.create({ name: 'accessfs-cache' });
|
|
63
|
+
this.attributes.set('no_buffer_resize');
|
|
64
|
+
this.attributes.set('setid');
|
|
19
65
|
this._handles.set('/', handle);
|
|
20
66
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
name: 'WebAccess',
|
|
25
|
-
noResizableBuffers: true,
|
|
26
|
-
// Not really, but we don't support opening directories so this prevent the VFS from trying
|
|
27
|
-
features: ['setid'],
|
|
28
|
-
};
|
|
67
|
+
async remove(path) {
|
|
68
|
+
const handle = this.get('directory', dirname(path));
|
|
69
|
+
await handle.removeEntry(basename(path), { recursive: true }).catch(ex => _throw(convertException(ex, path)));
|
|
29
70
|
}
|
|
30
|
-
|
|
31
|
-
|
|
71
|
+
removeSync(path) {
|
|
72
|
+
throw log.crit(ErrnoError.With('ENOSYS', path));
|
|
32
73
|
}
|
|
33
|
-
async
|
|
34
|
-
|
|
35
|
-
if (handle instanceof FileSystemDirectoryHandle) {
|
|
36
|
-
const files = await this.readdir(oldPath);
|
|
37
|
-
await this.mkdir(newPath);
|
|
38
|
-
if (!files.length) {
|
|
39
|
-
await this.unlink(oldPath);
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
for (const file of files) {
|
|
43
|
-
await this.rename(join(oldPath, file), join(newPath, file));
|
|
44
|
-
await this.unlink(oldPath);
|
|
45
|
-
}
|
|
74
|
+
async read(path, buffer, offset, end) {
|
|
75
|
+
if (end <= offset)
|
|
46
76
|
return;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}), destFolder = await this.getHandle(dirname(newPath));
|
|
54
|
-
if (!(destFolder instanceof FileSystemDirectoryHandle)) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
const newFile = await destFolder.getFileHandle(basename(newPath), { create: true }).catch((ex) => {
|
|
58
|
-
throw convertException(ex, newPath, 'rename');
|
|
59
|
-
});
|
|
60
|
-
const writable = await newFile.createWritable();
|
|
61
|
-
await writable.write(await oldFile.arrayBuffer());
|
|
62
|
-
await writable.close();
|
|
63
|
-
await this.unlink(oldPath);
|
|
77
|
+
const handle = this.get('file', path, 'write');
|
|
78
|
+
const file = await handle.getFile();
|
|
79
|
+
const data = await file.arrayBuffer();
|
|
80
|
+
if (data.byteLength < end - offset)
|
|
81
|
+
throw ErrnoError.With('ENODATA', path, 'read');
|
|
82
|
+
buffer.set(new Uint8Array(data, offset, end - offset));
|
|
64
83
|
}
|
|
65
|
-
async
|
|
66
|
-
if (isResizable(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
84
|
+
async write(path, buffer, offset) {
|
|
85
|
+
if (isResizable(buffer.buffer)) {
|
|
86
|
+
const newBuffer = new Uint8Array(new ArrayBuffer(buffer.byteLength), buffer.byteOffset, buffer.byteLength);
|
|
87
|
+
newBuffer.set(buffer);
|
|
88
|
+
buffer = newBuffer;
|
|
89
|
+
}
|
|
90
|
+
const inode = this.index.get(path);
|
|
91
|
+
if (!inode)
|
|
92
|
+
throw ErrnoError.With('ENOENT', path, 'write');
|
|
93
|
+
const isDir = (inode.mode & S_IFMT) == S_IFDIR;
|
|
94
|
+
let handle;
|
|
95
|
+
try {
|
|
96
|
+
handle = this.get(isDir ? 'directory' : 'file', path, 'write');
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
const parent = this.get('directory', dirname(path), 'write');
|
|
100
|
+
handle = await parent[isDir ? 'getDirectoryHandle' : 'getFileHandle'](basename(path), { create: true }).catch((ex) => _throw(convertException(ex, path)));
|
|
101
|
+
this._handles.set(path, handle);
|
|
102
|
+
}
|
|
103
|
+
if (isDir)
|
|
104
|
+
return;
|
|
105
|
+
if (isKind(handle, 'directory')) {
|
|
106
|
+
log.crit(new ErrnoError(Errno.EIO, 'Mismatch in entry kind on write', path, 'write'));
|
|
71
107
|
return;
|
|
72
108
|
}
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
await writable.close();
|
|
77
|
-
}
|
|
78
|
-
async createFile(path, flag) {
|
|
79
|
-
await this.writeFile(path, new Uint8Array());
|
|
80
|
-
return this.openFile(path, flag);
|
|
81
|
-
}
|
|
82
|
-
async stat(path) {
|
|
83
|
-
const handle = await this.getHandle(path);
|
|
84
|
-
if (!handle) {
|
|
85
|
-
throw ErrnoError.With('ENOENT', path, 'stat');
|
|
86
|
-
}
|
|
87
|
-
if (handle instanceof FileSystemDirectoryHandle) {
|
|
88
|
-
return new Stats({ mode: 0o777 | constants.S_IFDIR, size: 4096 });
|
|
89
|
-
}
|
|
90
|
-
if (handle instanceof FileSystemFileHandle) {
|
|
91
|
-
const { lastModified, size } = await handle.getFile();
|
|
92
|
-
return new Stats({ mode: 0o777 | constants.S_IFREG, size, mtimeMs: lastModified });
|
|
93
|
-
}
|
|
94
|
-
throw new ErrnoError(Errno.EBADE, 'Handle is not a directory or file', path, 'stat');
|
|
95
|
-
}
|
|
96
|
-
async openFile(path, flag) {
|
|
97
|
-
const handle = await this.getHandle(path);
|
|
98
|
-
if (!(handle instanceof FileSystemFileHandle)) {
|
|
99
|
-
throw ErrnoError.With('EISDIR', path, 'openFile');
|
|
109
|
+
const writable = await handle.createWritable();
|
|
110
|
+
try {
|
|
111
|
+
await writable.seek(offset);
|
|
100
112
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
});
|
|
104
|
-
const data = new Uint8Array(await file.arrayBuffer());
|
|
105
|
-
const stats = new Stats({ mode: 0o777 | constants.S_IFREG, size: file.size, mtimeMs: file.lastModified });
|
|
106
|
-
return new PreloadFile(this, path, flag, stats, data);
|
|
107
|
-
}
|
|
108
|
-
async unlink(path) {
|
|
109
|
-
const handle = await this.getHandle(dirname(path));
|
|
110
|
-
if (!(handle instanceof FileSystemDirectoryHandle)) {
|
|
111
|
-
throw ErrnoError.With('ENOTDIR', dirname(path), 'unlink');
|
|
113
|
+
catch {
|
|
114
|
+
await writable.write({ type: 'seek', position: offset });
|
|
112
115
|
}
|
|
113
|
-
await
|
|
114
|
-
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
async link(srcpath) {
|
|
119
|
-
return;
|
|
116
|
+
await writable.write(buffer);
|
|
117
|
+
await writable.close();
|
|
118
|
+
const { size, lastModified } = await handle.getFile();
|
|
119
|
+
inode.update({ size, mtimeMs: lastModified });
|
|
120
|
+
this.index.set(path, inode);
|
|
120
121
|
}
|
|
121
|
-
|
|
122
|
-
|
|
122
|
+
/**
|
|
123
|
+
* Do not use!
|
|
124
|
+
* @deprecated @internal @hidden
|
|
125
|
+
*/
|
|
126
|
+
async writeFile(path, data) {
|
|
127
|
+
return this.write(path, data, 0);
|
|
123
128
|
}
|
|
124
129
|
async mkdir(path, mode, options) {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
});
|
|
130
|
-
if (existingHandle) {
|
|
131
|
-
throw ErrnoError.With('EEXIST', path, 'mkdir');
|
|
132
|
-
}
|
|
133
|
-
const handle = await this.getHandle(dirname(path));
|
|
134
|
-
if (!(handle instanceof FileSystemDirectoryHandle)) {
|
|
135
|
-
throw ErrnoError.With('ENOTDIR', path, 'mkdir');
|
|
136
|
-
}
|
|
137
|
-
await handle.getDirectoryHandle(basename(path), { create: true });
|
|
130
|
+
await super.mkdir(path, mode, options);
|
|
131
|
+
const handle = this.get('directory', dirname(path), 'mkdir');
|
|
132
|
+
const dir = await handle.getDirectoryHandle(basename(path), { create: true }).catch((ex) => _throw(convertException(ex, path)));
|
|
133
|
+
this._handles.set(path, dir);
|
|
138
134
|
}
|
|
139
|
-
|
|
140
|
-
const handle =
|
|
141
|
-
if (!
|
|
142
|
-
throw ErrnoError.With('
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
entries.push(k);
|
|
147
|
-
}
|
|
148
|
-
return entries;
|
|
149
|
-
}
|
|
150
|
-
async getHandle(path) {
|
|
151
|
-
if (this._handles.has(path)) {
|
|
152
|
-
return this._handles.get(path);
|
|
153
|
-
}
|
|
154
|
-
let walked = '/';
|
|
155
|
-
for (const part of path.split('/').slice(1)) {
|
|
156
|
-
const handle = this._handles.get(walked);
|
|
157
|
-
if (!(handle instanceof FileSystemDirectoryHandle)) {
|
|
158
|
-
throw ErrnoError.With('ENOTDIR', walked, 'getHandle');
|
|
159
|
-
}
|
|
160
|
-
walked = join(walked, part);
|
|
161
|
-
const child = await handle.getDirectoryHandle(part).catch((ex) => {
|
|
162
|
-
switch (ex.name) {
|
|
163
|
-
case 'TypeMismatchError':
|
|
164
|
-
return handle.getFileHandle(part).catch((ex) => {
|
|
165
|
-
//throw convertException(ex, walked, 'getHandle');
|
|
166
|
-
});
|
|
167
|
-
case 'TypeError':
|
|
168
|
-
throw new ErrnoError(Errno.ENOENT, ex.message, walked, 'getHandle');
|
|
169
|
-
default:
|
|
170
|
-
throw convertException(ex, walked, 'getHandle');
|
|
171
|
-
}
|
|
172
|
-
});
|
|
173
|
-
if (child)
|
|
174
|
-
this._handles.set(walked, child);
|
|
175
|
-
}
|
|
176
|
-
return this._handles.get(path);
|
|
135
|
+
get(kind = null, path, syscall) {
|
|
136
|
+
const handle = this._handles.get(path);
|
|
137
|
+
if (!handle)
|
|
138
|
+
throw ErrnoError.With('ENODATA', path, syscall);
|
|
139
|
+
if (kind && !isKind(handle, kind))
|
|
140
|
+
throw ErrnoError.With(kind == 'directory' ? 'ENOTDIR' : 'EISDIR', path, syscall);
|
|
141
|
+
return handle;
|
|
177
142
|
}
|
|
178
143
|
}
|
|
179
144
|
const _WebAccess = {
|
|
180
145
|
name: 'WebAccess',
|
|
181
146
|
options: {
|
|
182
147
|
handle: { type: 'object', required: true },
|
|
148
|
+
metadata: { type: 'string', required: false },
|
|
183
149
|
},
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
return
|
|
150
|
+
async create(options) {
|
|
151
|
+
const fs = new WebAccessFS(options.handle);
|
|
152
|
+
await fs._loadHandles('/', options.handle);
|
|
153
|
+
await fs._loadMetadata(options.metadata);
|
|
154
|
+
return fs;
|
|
189
155
|
},
|
|
190
156
|
};
|
|
191
157
|
export const WebAccess = _WebAccess;
|
package/dist/devices/dsp.js
CHANGED
|
@@ -8,8 +8,8 @@ if ('AudioWorkletProcessor' in globalThis) {
|
|
|
8
8
|
}
|
|
9
9
|
process(inputs, outputs) {
|
|
10
10
|
if (this.buffer && this.buffer.byteLength >= 128) {
|
|
11
|
-
outputs[0][0].set(this.buffer.
|
|
12
|
-
this.buffer = this.buffer.
|
|
11
|
+
outputs[0][0].set(this.buffer.subarray(0, 128));
|
|
12
|
+
this.buffer = this.buffer.subarray(128);
|
|
13
13
|
}
|
|
14
14
|
return true;
|
|
15
15
|
}
|
|
@@ -44,12 +44,11 @@ export async function dsp(options = {}) {
|
|
|
44
44
|
init(ino, options) {
|
|
45
45
|
return { data: dsp, major: 14, minor: 3 };
|
|
46
46
|
},
|
|
47
|
-
|
|
48
|
-
return
|
|
47
|
+
readD() {
|
|
48
|
+
return;
|
|
49
49
|
},
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return data.byteLength;
|
|
50
|
+
writeD(device, buffer, offset) {
|
|
51
|
+
device.data.port.postMessage(buffer.buffer);
|
|
53
52
|
},
|
|
54
53
|
};
|
|
55
54
|
}
|
|
@@ -2,6 +2,10 @@ import type { DeviceDriver } from '@zenfs/core';
|
|
|
2
2
|
export interface FramebufferOptions {
|
|
3
3
|
canvas?: HTMLCanvasElement | null;
|
|
4
4
|
}
|
|
5
|
+
export interface FramebufferData {
|
|
6
|
+
context: CanvasRenderingContext2D;
|
|
7
|
+
image: ImageData;
|
|
8
|
+
}
|
|
5
9
|
/**
|
|
6
10
|
* A frame buffer
|
|
7
11
|
*
|
|
@@ -10,4 +14,4 @@ export interface FramebufferOptions {
|
|
|
10
14
|
* addDevice(framebuffer, { canvas: document.querySelector('#your-canvas') })
|
|
11
15
|
* ```
|
|
12
16
|
*/
|
|
13
|
-
export declare const framebuffer: DeviceDriver<
|
|
17
|
+
export declare const framebuffer: DeviceDriver<FramebufferData>;
|
|
@@ -15,22 +15,22 @@ export const framebuffer = {
|
|
|
15
15
|
canvas = document.createElement('canvas');
|
|
16
16
|
document.body.appendChild(canvas);
|
|
17
17
|
}
|
|
18
|
-
const
|
|
19
|
-
if (!
|
|
18
|
+
const context = canvas.getContext('2d');
|
|
19
|
+
if (!context) {
|
|
20
20
|
throw new ErrnoError(Errno.EIO, 'Could not get context from canvas whilst initializing frame buffer.');
|
|
21
21
|
}
|
|
22
|
-
|
|
22
|
+
const image = new ImageData(canvas.width, canvas.height);
|
|
23
|
+
return {
|
|
24
|
+
data: { context, image },
|
|
25
|
+
major: 29,
|
|
26
|
+
minor: framebufferN++,
|
|
27
|
+
name: 'fb',
|
|
28
|
+
};
|
|
23
29
|
},
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (data.byteLength < 4 * width * height) {
|
|
30
|
-
return 0;
|
|
31
|
-
}
|
|
32
|
-
const imageData = new ImageData(new Uint8ClampedArray(data), width, height);
|
|
33
|
-
file.device.data.putImageData(imageData, 0, 0);
|
|
34
|
-
return data.byteLength;
|
|
30
|
+
readD() { },
|
|
31
|
+
writeD({ data: { image, context } }, buffer, offset) {
|
|
32
|
+
image.data.set(buffer, offset);
|
|
33
|
+
context.putImageData(image, 0, 0);
|
|
34
|
+
return buffer.byteLength;
|
|
35
35
|
},
|
|
36
36
|
};
|
package/dist/storage.d.ts
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
1
|
+
import type { SyncMapStore, Store } from '@zenfs/core';
|
|
2
|
+
import { StoreFS, SyncMapTransaction } from '@zenfs/core';
|
|
3
3
|
/**
|
|
4
4
|
* A synchronous key-value store backed by Storage.
|
|
5
5
|
*/
|
|
6
|
-
export declare class WebStorageStore implements Store,
|
|
6
|
+
export declare class WebStorageStore implements Store, SyncMapStore {
|
|
7
7
|
protected storage: Storage;
|
|
8
8
|
get name(): string;
|
|
9
9
|
constructor(storage: Storage);
|
|
10
10
|
clear(): void;
|
|
11
11
|
clearSync(): void;
|
|
12
12
|
sync(): Promise<void>;
|
|
13
|
-
transaction():
|
|
14
|
-
keys(): Iterable<
|
|
15
|
-
get(key:
|
|
16
|
-
set(key:
|
|
17
|
-
delete(key:
|
|
13
|
+
transaction(): SyncMapTransaction;
|
|
14
|
+
keys(): Iterable<number>;
|
|
15
|
+
get(key: number): Uint8Array | undefined;
|
|
16
|
+
set(key: number, data: Uint8Array): void;
|
|
17
|
+
delete(key: number): void;
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
20
|
* Options to pass to the StorageFileSystem
|
package/dist/storage.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ErrnoError, Errno,
|
|
1
|
+
import { ErrnoError, Errno, StoreFS, decodeRaw, encodeRaw, SyncMapTransaction } from '@zenfs/core';
|
|
2
2
|
/**
|
|
3
3
|
* A synchronous key-value store backed by Storage.
|
|
4
4
|
*/
|
|
@@ -18,10 +18,10 @@ export class WebStorageStore {
|
|
|
18
18
|
}
|
|
19
19
|
async sync() { }
|
|
20
20
|
transaction() {
|
|
21
|
-
return new
|
|
21
|
+
return new SyncMapTransaction(this);
|
|
22
22
|
}
|
|
23
23
|
keys() {
|
|
24
|
-
return Object.keys(this.storage).map(k =>
|
|
24
|
+
return Object.keys(this.storage).map(k => Number(k));
|
|
25
25
|
}
|
|
26
26
|
get(key) {
|
|
27
27
|
const data = this.storage.getItem(key.toString());
|
package/dist/utils.js
CHANGED
|
@@ -5,13 +5,14 @@ import { ErrnoError, Errno } from '@zenfs/core';
|
|
|
5
5
|
*/
|
|
6
6
|
function errnoForDOMException(ex) {
|
|
7
7
|
switch (ex.name) {
|
|
8
|
+
case 'TypeMismatchError':
|
|
9
|
+
return 'EPERM';
|
|
8
10
|
case 'IndexSizeError':
|
|
9
11
|
case 'HierarchyRequestError':
|
|
10
12
|
case 'InvalidCharacterError':
|
|
11
13
|
case 'InvalidStateError':
|
|
12
14
|
case 'SyntaxError':
|
|
13
15
|
case 'NamespaceError':
|
|
14
|
-
case 'TypeMismatchError':
|
|
15
16
|
case 'ConstraintError':
|
|
16
17
|
case 'VersionError':
|
|
17
18
|
case 'URLMismatchError':
|
|
@@ -57,9 +58,8 @@ function errnoForDOMException(ex) {
|
|
|
57
58
|
* @internal
|
|
58
59
|
*/
|
|
59
60
|
export function convertException(ex, path, syscall) {
|
|
60
|
-
if (ex instanceof ErrnoError)
|
|
61
|
+
if (ex instanceof ErrnoError)
|
|
61
62
|
return ex;
|
|
62
|
-
}
|
|
63
63
|
const code = ex instanceof DOMException ? Errno[errnoForDOMException(ex)] : Errno.EIO;
|
|
64
64
|
const error = new ErrnoError(code, ex.message, path, syscall);
|
|
65
65
|
error.stack = ex.stack;
|
package/dist/xml.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CreationOptions, File,
|
|
1
|
+
import type { CreationOptions, File, InodeLike, StatsLike } from '@zenfs/core';
|
|
2
2
|
import { FileSystem, Stats } from '@zenfs/core';
|
|
3
3
|
export interface XMLOptions {
|
|
4
4
|
/**
|
|
@@ -9,15 +9,14 @@ export interface XMLOptions {
|
|
|
9
9
|
declare const XMLFS_base: import("@zenfs/core").Mixin<typeof FileSystem, import("@zenfs/core").AsyncFSMethods>;
|
|
10
10
|
export declare class XMLFS extends XMLFS_base {
|
|
11
11
|
/**
|
|
12
|
-
* @
|
|
12
|
+
* @inheritDoc XMLOptions.root
|
|
13
13
|
*/
|
|
14
14
|
readonly root: Element;
|
|
15
15
|
constructor(
|
|
16
16
|
/**
|
|
17
|
-
* @
|
|
17
|
+
* @inheritDoc XMLOptions.root
|
|
18
18
|
*/
|
|
19
19
|
root?: Element);
|
|
20
|
-
metadata(): FileSystemMetadata;
|
|
21
20
|
renameSync(oldPath: string, newPath: string): void;
|
|
22
21
|
statSync(path: string): Stats;
|
|
23
22
|
openFileSync(path: string, flag: string): File;
|
|
@@ -27,10 +26,12 @@ export declare class XMLFS extends XMLFS_base {
|
|
|
27
26
|
mkdirSync(path: string, mode: number, { uid, gid }: CreationOptions): void;
|
|
28
27
|
readdirSync(path: string): string[];
|
|
29
28
|
linkSync(target: string, link: string): void;
|
|
30
|
-
syncSync(path: string, data
|
|
29
|
+
syncSync(path: string, data?: Uint8Array, stats?: Readonly<Partial<InodeLike>>): void;
|
|
30
|
+
readSync(path: string, buffer: Uint8Array, offset: number, end: number): void;
|
|
31
|
+
writeSync(path: string, buffer: Uint8Array, offset: number): void;
|
|
31
32
|
toString(): string;
|
|
32
33
|
protected get(syscall: string, path: string): Element;
|
|
33
|
-
protected create(syscall: string, path: string, stats: Partial<
|
|
34
|
+
protected create(syscall: string, path: string, stats: Partial<InodeLike> & Pick<StatsLike, 'mode'>): Element;
|
|
34
35
|
protected add(syscall: string, node: Element, path: string, contents?: boolean): void;
|
|
35
36
|
protected remove(syscall: string, node: Element, path: string, contents?: boolean): void;
|
|
36
37
|
}
|
package/dist/xml.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { constants, decodeRaw, encodeRaw, Errno, ErrnoError, FileSystem,
|
|
1
|
+
import { _inode_fields, constants, decodeRaw, encodeRaw, Errno, ErrnoError, FileSystem, LazyFile, Stats, Sync } from '@zenfs/core';
|
|
2
2
|
import { basename, dirname } from '@zenfs/core/vfs/path.js';
|
|
3
|
-
const statsLikeKeys = ['size', 'mode', 'atimeMs', 'mtimeMs', 'ctimeMs', 'birthtimeMs', 'uid', 'gid', 'ino', 'nlink'];
|
|
4
3
|
function get_stats(node) {
|
|
5
4
|
const stats = {};
|
|
6
|
-
for (const key of
|
|
5
|
+
for (const key of _inode_fields) {
|
|
7
6
|
const value = node.getAttribute(key);
|
|
8
|
-
|
|
7
|
+
if (value !== null && value !== undefined)
|
|
8
|
+
stats[key] = parseInt(value, 16);
|
|
9
9
|
}
|
|
10
10
|
return new Stats(stats);
|
|
11
11
|
}
|
|
12
12
|
function set_stats(node, stats) {
|
|
13
|
-
for (const key of
|
|
14
|
-
if (stats[key]
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
for (const key of Object.keys(stats)) {
|
|
14
|
+
if (!(key in _inode_fields) || stats[key] === undefined)
|
|
15
|
+
continue;
|
|
16
|
+
node.setAttribute(key, stats[key].toString(16));
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
function get_paths(node, contents = false) {
|
|
@@ -30,11 +30,12 @@ function get_paths(node, contents = false) {
|
|
|
30
30
|
export class XMLFS extends Sync(FileSystem) {
|
|
31
31
|
constructor(
|
|
32
32
|
/**
|
|
33
|
-
* @
|
|
33
|
+
* @inheritDoc XMLOptions.root
|
|
34
34
|
*/
|
|
35
35
|
root = new DOMParser().parseFromString('<fs></fs>', 'application/xml').documentElement) {
|
|
36
|
-
super();
|
|
36
|
+
super(0x20786d6c, 'xmltmpfs');
|
|
37
37
|
this.root = root;
|
|
38
|
+
this.attributes.set('setid');
|
|
38
39
|
try {
|
|
39
40
|
this.mkdirSync('/', 0o777, { uid: 0, gid: 0 });
|
|
40
41
|
}
|
|
@@ -44,9 +45,6 @@ export class XMLFS extends Sync(FileSystem) {
|
|
|
44
45
|
throw error;
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
|
-
metadata() {
|
|
48
|
-
return { ...super.metadata(), features: ['setid'] };
|
|
49
|
-
}
|
|
50
48
|
renameSync(oldPath, newPath) {
|
|
51
49
|
const node = this.get('rename', oldPath);
|
|
52
50
|
this.remove('rename', node, oldPath);
|
|
@@ -57,7 +55,7 @@ export class XMLFS extends Sync(FileSystem) {
|
|
|
57
55
|
}
|
|
58
56
|
openFileSync(path, flag) {
|
|
59
57
|
const node = this.get('openFile', path);
|
|
60
|
-
return new
|
|
58
|
+
return new LazyFile(this, path, flag, get_stats(node));
|
|
61
59
|
}
|
|
62
60
|
createFileSync(path, flag, mode, { uid, gid }) {
|
|
63
61
|
const parent = this.statSync(dirname(path));
|
|
@@ -67,7 +65,7 @@ export class XMLFS extends Sync(FileSystem) {
|
|
|
67
65
|
gid: parent.mode & constants.S_ISGID ? parent.gid : gid,
|
|
68
66
|
});
|
|
69
67
|
this.create('createFile', path, stats);
|
|
70
|
-
return new
|
|
68
|
+
return new LazyFile(this, path, flag, stats);
|
|
71
69
|
}
|
|
72
70
|
unlinkSync(path) {
|
|
73
71
|
const node = this.get('unlink', path);
|
|
@@ -107,11 +105,23 @@ export class XMLFS extends Sync(FileSystem) {
|
|
|
107
105
|
const node = this.get('link', target);
|
|
108
106
|
this.add('link', node, link);
|
|
109
107
|
}
|
|
110
|
-
syncSync(path, data, stats) {
|
|
108
|
+
syncSync(path, data, stats = {}) {
|
|
111
109
|
const node = this.get('sync', path);
|
|
112
|
-
|
|
110
|
+
if (data)
|
|
111
|
+
node.textContent = decodeRaw(data);
|
|
113
112
|
set_stats(node, stats);
|
|
114
113
|
}
|
|
114
|
+
readSync(path, buffer, offset, end) {
|
|
115
|
+
const node = this.get('read', path);
|
|
116
|
+
const raw = encodeRaw(node.textContent.slice(offset, end));
|
|
117
|
+
buffer.set(raw);
|
|
118
|
+
}
|
|
119
|
+
writeSync(path, buffer, offset) {
|
|
120
|
+
const node = this.get('write', path);
|
|
121
|
+
const data = decodeRaw(buffer);
|
|
122
|
+
const after = node.textContent.slice(offset + data.length);
|
|
123
|
+
node.textContent = node.textContent.slice(0, offset) + data + after;
|
|
124
|
+
}
|
|
115
125
|
toString() {
|
|
116
126
|
return new XMLSerializer().serializeToString(this.root);
|
|
117
127
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenfs/dom",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.5",
|
|
4
4
|
"description": "DOM backends for ZenFS",
|
|
5
5
|
"funding": {
|
|
6
6
|
"type": "individual",
|
|
@@ -45,14 +45,14 @@
|
|
|
45
45
|
"lint": "eslint src",
|
|
46
46
|
"build": "tsc -p tsconfig.json",
|
|
47
47
|
"build:docs": "typedoc --out docs --name 'ZenFS DOM' src/index.ts",
|
|
48
|
-
"test": "
|
|
48
|
+
"test": "npx zenfs-test -abcf",
|
|
49
49
|
"prepublishOnly": "npm run build"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@eslint/js": "^9.12.0",
|
|
53
|
+
"c8": "^10.1.3",
|
|
53
54
|
"eslint": "^9.12.0",
|
|
54
55
|
"fake-indexeddb": "^6.0.0",
|
|
55
|
-
"file-system-access": "^1.0.4",
|
|
56
56
|
"globals": "^15.10.0",
|
|
57
57
|
"prettier": "^3.2.5",
|
|
58
58
|
"tsx": "^4.19.2",
|
|
@@ -61,7 +61,8 @@
|
|
|
61
61
|
"typescript-eslint": "^8.8.1"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
|
-
"@zenfs/core": "^1.
|
|
64
|
+
"@zenfs/core": "^1.9.1",
|
|
65
|
+
"utilium": "^1.2.10"
|
|
65
66
|
},
|
|
66
67
|
"keywords": [
|
|
67
68
|
"filesystem",
|
package/readme.md
CHANGED
|
@@ -6,10 +6,10 @@ Please read the ZenFS core documentation!
|
|
|
6
6
|
|
|
7
7
|
## Backends
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
9
|
+
- `WebStorage` stores files in a `Storage` object, like `localStorage` and `sessionStorage`.
|
|
10
|
+
- `IndexedDB` stores files into an `IndexedDB` object database.
|
|
11
|
+
- `WebAccess` uses the [File System Access API](https://developer.mozilla.org/Web/API/File_System_API).
|
|
12
|
+
- `XML` uses an `XMLDocument` to store files, which can be appended to the DOM.
|
|
13
13
|
|
|
14
14
|
For more information, see the [API documentation](https://zen-fs.github.io/dom).
|
|
15
15
|
|
package/tsconfig.json
CHANGED
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
"module": "NodeNext",
|
|
4
4
|
"target": "ES2020",
|
|
5
5
|
"outDir": "dist",
|
|
6
|
-
"lib": ["ESNext", "DOM"],
|
|
6
|
+
"lib": ["ESNext", "DOM", "ESNext.AsyncIterable", "DOM.AsyncIterable"],
|
|
7
7
|
"strict": true,
|
|
8
8
|
"moduleResolution": "NodeNext",
|
|
9
|
-
"declaration": true
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"verbatimModuleSyntax": true
|
|
10
11
|
},
|
|
11
12
|
"include": ["src/**/*"],
|
|
12
13
|
"exclude": ["node_modules"]
|