@zenfs/dom 0.0.5 → 0.1.0

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/index.d.ts CHANGED
@@ -1,5 +1,3 @@
1
- export * from './backends/FileSystemAccess.js';
2
- export * from './backends/HTTPRequest.js';
3
- export * from './backends/IndexedDB.js';
4
- export * from './backends/Storage.js';
5
- export * from './backends/Worker.js';
1
+ export * from './FileSystemAccess.js';
2
+ export * from './IndexedDB.js';
3
+ export * from './Storage.js';
package/dist/index.js CHANGED
@@ -1,5 +1,3 @@
1
- export * from './backends/FileSystemAccess.js';
2
- export * from './backends/HTTPRequest.js';
3
- export * from './backends/IndexedDB.js';
4
- export * from './backends/Storage.js';
5
- export * from './backends/Worker.js';
1
+ export * from './FileSystemAccess.js';
2
+ export * from './IndexedDB.js';
3
+ export * from './Storage.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenfs/dom",
3
- "version": "0.0.5",
3
+ "version": "0.1.0",
4
4
  "description": "DOM backends for ZenFS",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist",
@@ -10,15 +10,15 @@
10
10
  "storage"
11
11
  ],
12
12
  "type": "module",
13
- "homepage": "https://github.com/zen-fs/fs-dom",
13
+ "homepage": "https://github.com/zen-fs/dom",
14
14
  "author": "James P. <jp@drvortex.dev> (https://drvortex.dev)",
15
15
  "license": "MIT",
16
16
  "repository": {
17
17
  "type": "git",
18
- "url": "git+https://github.com/zen-fs/fs-dom.git"
18
+ "url": "git+https://github.com/zen-fs/dom.git"
19
19
  },
20
20
  "bugs": {
21
- "url": "https://github.com/zen-fs/fs-dom/issues"
21
+ "url": "https://github.com/zen-fs/dom/issues"
22
22
  },
23
23
  "engines": {
24
24
  "node": ">= 18"
@@ -36,7 +36,7 @@
36
36
  "scripts": {
37
37
  "format": "prettier --write src",
38
38
  "format:check": "prettier --check src",
39
- "lint": "eslint src",
39
+ "lint": "tsc -p tsconfig.json --noEmit && eslint src",
40
40
  "build": "node scripts/build.mjs",
41
41
  "build:docs": "typedoc --out docs --name 'ZenFS DOM' src/index.ts",
42
42
  "prepublishOnly": "npm run build"
@@ -50,7 +50,7 @@
50
50
  "typedoc": "^0.25.1",
51
51
  "typescript": "5.2.2"
52
52
  },
53
- "dependencies": {
54
- "@zenfs/core": "^0.1.0"
53
+ "peerDependencies": {
54
+ "@zenfs/core": "^0.3.2"
55
55
  }
56
56
  }
package/readme.md CHANGED
@@ -1,36 +1,28 @@
1
1
  # ZenFS DOM Backends
2
2
 
3
- [ZenFS](https://github.com/zen-fs/core) backends for DOM APIs. DOM APIs are *only* available natively in browsers.
3
+ [ZenFS](https://github.com/zen-fs/core) backends for DOM APIs. DOM APIs are _only_ available natively in browsers.
4
4
 
5
- Please read the ZenFS documentation!
5
+ > [!IMPORTANT]
6
+ > Please read the ZenFS documentation!
6
7
 
7
8
  ## Backends
8
9
 
9
- - `HTTPRequest`: Downloads files on-demand from a webserver using `fetch`.
10
- - `Storage`: Stores files in a `Storage` object, like `localStorage` and `seesionStorage`.
11
- - `IndexedDB`: Stores files into an `IndexedDB` object database.
12
- - `WorkerFS`: Lets you mount the ZenFS file system configured in the main thread in a WebWorker, or the other way around!
10
+ - `Storage`: Stores files in a `Storage` object, like `localStorage` and `sessionStorage`.
11
+ - `IndexedDB`: Stores files into an `IndexedDB` object database.
12
+ - `FileSystemAccess`: Store files using the [Web File System API](https://developer.mozilla.org/Web/API/File_System_API).
13
13
 
14
- For more information, see the [API documentation](https://zen-fs.github.io/fs-dom).
15
-
16
- ## Installing
17
-
18
- ```sh
19
- npm install @zenfs/fs-dom
20
- ```
14
+ For more information, see the [API documentation](https://zen-fs.github.io/dom).
21
15
 
22
16
  ## Usage
23
17
 
24
- > 🛈 The examples are written in ESM. If you are using CJS, you can `require` the package. If running in a browser you can add a script tag to your HTML pointing to the `browser.min.js` and use ZenFS DOM via the global `ZenFS_DOM` object.
25
-
26
- You can use DOM backends, though you must register them if you plan on using `configure`:
18
+ > [!NOTE]
19
+ > The examples are written in ESM. If you are using CJS, you can `require` the package. If running in a browser you can add a script tag to your HTML pointing to the `browser.min.js` and use ZenFS DOM via the global `ZenFS_DOM` object.
27
20
 
28
21
  ```js
29
- import { configure, fs, registerBackend } from '@zenfs/core';
30
- import { Storage } from '@zenfs/fs-dom';
22
+ import { configure, fs } from '@zenfs/core';
23
+ import { Storage } from '@zenfs/dom';
31
24
 
32
- registerBackend(Storage);
33
- await configure({ fs: 'Storage', options: { storage: localStorage } });
25
+ await configure({ backend: Storage, storage: localStorage });
34
26
 
35
27
  if (!fs.existsSync('/test.txt')) {
36
28
  fs.writeFileSync('/test.txt', 'This will persist across reloads!');
@@ -1,44 +0,0 @@
1
- import { Cred } from '@zenfs/core/cred.js';
2
- import { FileFlag, PreloadFile } from '@zenfs/core/file.js';
3
- import { BaseFileSystem, FileSystemMetadata } from '@zenfs/core/filesystem.js';
4
- import { Stats } from '@zenfs/core/stats.js';
5
- import { type BackendOptions } from '@zenfs/core/backends/backend.js';
6
- declare global {
7
- interface FileSystemDirectoryHandle {
8
- [Symbol.iterator](): IterableIterator<[string, FileSystemHandle]>;
9
- entries(): IterableIterator<[string, FileSystemHandle]>;
10
- keys(): IterableIterator<string>;
11
- values(): IterableIterator<FileSystemHandle>;
12
- }
13
- }
14
- interface FileSystemAccessFileSystemOptions {
15
- handle: FileSystemDirectoryHandle;
16
- }
17
- export declare class FileSystemAccessFile extends PreloadFile<FileSystemAccessFileSystem> {
18
- constructor(_fs: FileSystemAccessFileSystem, _path: string, _flag: FileFlag, _stat: Stats, contents?: Uint8Array);
19
- sync(): Promise<void>;
20
- close(): Promise<void>;
21
- }
22
- export declare class FileSystemAccessFileSystem extends BaseFileSystem {
23
- static readonly Name = "FileSystemAccess";
24
- static Create: any;
25
- static readonly Options: BackendOptions;
26
- static isAvailable(): boolean;
27
- private _handles;
28
- constructor({ handle }: FileSystemAccessFileSystemOptions);
29
- get metadata(): FileSystemMetadata;
30
- _sync(p: string, data: Uint8Array, stats: Stats, cred: Cred): Promise<void>;
31
- rename(oldPath: string, newPath: string, cred: Cred): Promise<void>;
32
- writeFile(fname: string, data: Uint8Array, flag: FileFlag, mode: number, cred: Cred, createFile?: boolean): Promise<void>;
33
- createFile(p: string, flag: FileFlag, mode: number, cred: Cred): Promise<FileSystemAccessFile>;
34
- stat(path: string, cred: Cred): Promise<Stats>;
35
- exists(p: string, cred: Cred): Promise<boolean>;
36
- openFile(path: string, flags: FileFlag, cred: Cred): Promise<FileSystemAccessFile>;
37
- unlink(path: string, cred: Cred): Promise<void>;
38
- rmdir(path: string, cred: Cred): Promise<void>;
39
- mkdir(p: string, mode: any, cred: Cred): Promise<void>;
40
- readdir(path: string, cred: Cred): Promise<string[]>;
41
- private newFile;
42
- private getHandle;
43
- }
44
- export {};
@@ -1,208 +0,0 @@
1
- var _a;
2
- import { basename, dirname, join } from '@zenfs/core/emulation/path.js';
3
- import { ApiError, ErrorCode } from '@zenfs/core/ApiError.js';
4
- import { Cred } from '@zenfs/core/cred.js';
5
- import { FileFlag, PreloadFile } from '@zenfs/core/file.js';
6
- import { BaseFileSystem } from '@zenfs/core/filesystem.js';
7
- import { Stats, FileType } from '@zenfs/core/stats.js';
8
- import { CreateBackend } from '@zenfs/core/backends/backend.js';
9
- const handleError = (path = '', error) => {
10
- if (error.name === 'NotFoundError') {
11
- throw ApiError.ENOENT(path);
12
- }
13
- throw error;
14
- };
15
- export class FileSystemAccessFile extends PreloadFile {
16
- constructor(_fs, _path, _flag, _stat, contents) {
17
- super(_fs, _path, _flag, _stat, contents);
18
- }
19
- async sync() {
20
- if (this.isDirty()) {
21
- await this._fs._sync(this.getPath(), this.getBuffer(), this.getStats(), Cred.Root);
22
- this.resetDirty();
23
- }
24
- }
25
- async close() {
26
- await this.sync();
27
- }
28
- }
29
- export class FileSystemAccessFileSystem extends BaseFileSystem {
30
- static isAvailable() {
31
- return typeof FileSystemHandle === 'function';
32
- }
33
- constructor({ handle }) {
34
- super();
35
- this._handles = new Map();
36
- this._handles.set('/', handle);
37
- }
38
- get metadata() {
39
- return {
40
- ...super.metadata,
41
- name: _a.Name,
42
- };
43
- }
44
- async _sync(p, data, stats, cred) {
45
- const currentStats = await this.stat(p, cred);
46
- if (stats.mtime !== currentStats.mtime) {
47
- await this.writeFile(p, data, FileFlag.getFileFlag('w'), currentStats.mode, cred);
48
- }
49
- }
50
- async rename(oldPath, newPath, cred) {
51
- try {
52
- const handle = await this.getHandle(oldPath);
53
- if (handle instanceof FileSystemDirectoryHandle) {
54
- const files = await this.readdir(oldPath, cred);
55
- await this.mkdir(newPath, 'wx', cred);
56
- if (files.length === 0) {
57
- await this.unlink(oldPath, cred);
58
- }
59
- else {
60
- for (const file of files) {
61
- await this.rename(join(oldPath, file), join(newPath, file), cred);
62
- await this.unlink(oldPath, cred);
63
- }
64
- }
65
- }
66
- if (handle instanceof FileSystemFileHandle) {
67
- const oldFile = await handle.getFile(), destFolder = await this.getHandle(dirname(newPath));
68
- if (destFolder instanceof FileSystemDirectoryHandle) {
69
- const newFile = await destFolder.getFileHandle(basename(newPath), { create: true });
70
- const writable = await newFile.createWritable();
71
- const buffer = await oldFile.arrayBuffer();
72
- await writable.write(buffer);
73
- writable.close();
74
- await this.unlink(oldPath, cred);
75
- }
76
- }
77
- }
78
- catch (err) {
79
- handleError(oldPath, err);
80
- }
81
- }
82
- async writeFile(fname, data, flag, mode, cred, createFile) {
83
- const handle = await this.getHandle(dirname(fname));
84
- if (handle instanceof FileSystemDirectoryHandle) {
85
- const file = await handle.getFileHandle(basename(fname), { create: true });
86
- const writable = await file.createWritable();
87
- await writable.write(data);
88
- await writable.close();
89
- //return createFile ? this.newFile(fname, flag, data) : undefined;
90
- }
91
- }
92
- async createFile(p, flag, mode, cred) {
93
- await this.writeFile(p, new Uint8Array(), flag, mode, cred, true);
94
- return this.openFile(p, flag, cred);
95
- }
96
- async stat(path, cred) {
97
- const handle = await this.getHandle(path);
98
- if (!handle) {
99
- throw ApiError.FileError(ErrorCode.EINVAL, path);
100
- }
101
- if (handle instanceof FileSystemDirectoryHandle) {
102
- return new Stats(FileType.DIRECTORY, 4096);
103
- }
104
- if (handle instanceof FileSystemFileHandle) {
105
- const { lastModified, size } = await handle.getFile();
106
- return new Stats(FileType.FILE, size, undefined, undefined, lastModified);
107
- }
108
- }
109
- async exists(p, cred) {
110
- try {
111
- await this.getHandle(p);
112
- return true;
113
- }
114
- catch (e) {
115
- return false;
116
- }
117
- }
118
- async openFile(path, flags, cred) {
119
- const handle = await this.getHandle(path);
120
- if (handle instanceof FileSystemFileHandle) {
121
- const file = await handle.getFile();
122
- const buffer = await file.arrayBuffer();
123
- return this.newFile(path, flags, buffer, file.size, file.lastModified);
124
- }
125
- }
126
- async unlink(path, cred) {
127
- const handle = await this.getHandle(dirname(path));
128
- if (handle instanceof FileSystemDirectoryHandle) {
129
- try {
130
- await handle.removeEntry(basename(path), { recursive: true });
131
- }
132
- catch (e) {
133
- handleError(path, e);
134
- }
135
- }
136
- }
137
- async rmdir(path, cred) {
138
- return this.unlink(path, cred);
139
- }
140
- async mkdir(p, mode, cred) {
141
- const overwrite = mode && mode.flag && mode.flag.includes('w') && !mode.flag.includes('x');
142
- const existingHandle = await this.getHandle(p);
143
- if (existingHandle && !overwrite) {
144
- throw ApiError.EEXIST(p);
145
- }
146
- const handle = await this.getHandle(dirname(p));
147
- if (handle instanceof FileSystemDirectoryHandle) {
148
- await handle.getDirectoryHandle(basename(p), { create: true });
149
- }
150
- }
151
- async readdir(path, cred) {
152
- const handle = await this.getHandle(path);
153
- if (!(handle instanceof FileSystemDirectoryHandle)) {
154
- throw ApiError.ENOTDIR(path);
155
- }
156
- const _keys = [];
157
- for await (const key of handle.keys()) {
158
- _keys.push(join(path, key));
159
- }
160
- return _keys;
161
- }
162
- newFile(path, flag, data, size, lastModified) {
163
- return new FileSystemAccessFile(this, path, flag, new Stats(FileType.FILE, size || 0, undefined, undefined, lastModified || new Date().getTime()), new Uint8Array(data));
164
- }
165
- async getHandle(path) {
166
- if (this._handles.has(path)) {
167
- return this._handles.get(path);
168
- }
169
- let walkedPath = '/';
170
- const [, ...pathParts] = path.split('/');
171
- const getHandleParts = async ([pathPart, ...remainingPathParts]) => {
172
- const walkingPath = join(walkedPath, pathPart);
173
- const continueWalk = (handle) => {
174
- walkedPath = walkingPath;
175
- this._handles.set(walkedPath, handle);
176
- if (remainingPathParts.length === 0) {
177
- return this._handles.get(path);
178
- }
179
- getHandleParts(remainingPathParts);
180
- };
181
- const handle = this._handles.get(walkedPath);
182
- try {
183
- return await continueWalk(await handle.getDirectoryHandle(pathPart));
184
- }
185
- catch (error) {
186
- if (error.name === 'TypeMismatchError') {
187
- try {
188
- return await continueWalk(await handle.getFileHandle(pathPart));
189
- }
190
- catch (err) {
191
- handleError(walkingPath, err);
192
- }
193
- }
194
- else if (error.message === 'Name is not allowed.') {
195
- throw new ApiError(ErrorCode.ENOENT, error.message, walkingPath);
196
- }
197
- else {
198
- handleError(walkingPath, error);
199
- }
200
- }
201
- };
202
- await getHandleParts(pathParts);
203
- }
204
- }
205
- _a = FileSystemAccessFileSystem;
206
- FileSystemAccessFileSystem.Name = 'FileSystemAccess';
207
- FileSystemAccessFileSystem.Create = CreateBackend.bind(_a);
208
- FileSystemAccessFileSystem.Options = {};
@@ -1,85 +0,0 @@
1
- import { BaseFileSystem, FileSystemMetadata } from '@zenfs/core/filesystem.js';
2
- import { FileFlag, NoSyncFile } from '@zenfs/core/file.js';
3
- import { Stats } from '@zenfs/core/stats.js';
4
- import { Cred } from '@zenfs/core/cred.js';
5
- import { type BackendOptions } from '@zenfs/core/backends/backend.js';
6
- export interface HTTPRequestIndex {
7
- [key: string]: string;
8
- }
9
- export declare namespace HTTPRequest {
10
- /**
11
- * Configuration options for a HTTPRequest file system.
12
- */
13
- interface Options {
14
- /**
15
- * URL to a file index as a JSON file or the file index object itself, generated with the make_http_index script.
16
- * Defaults to `index.json`.
17
- */
18
- index?: string | HTTPRequestIndex;
19
- /** Used as the URL prefix for fetched files.
20
- * Default: Fetch files relative to the index.
21
- */
22
- baseUrl?: string;
23
- }
24
- }
25
- /**
26
- * A simple filesystem backed by HTTP downloads. You must create a directory listing using the
27
- * `make_http_index` tool provided by ZenFS.
28
- *
29
- * If you install ZenFS globally with `npm i -g zenfs`, you can generate a listing by
30
- * running `make_http_index` in your terminal in the directory you would like to index:
31
- *
32
- * ```
33
- * make_http_index > index.json
34
- * ```
35
- *
36
- * Listings objects look like the following:
37
- *
38
- * ```json
39
- * {
40
- * "home": {
41
- * "jvilk": {
42
- * "someFile.txt": null,
43
- * "someDir": {
44
- * // Empty directory
45
- * }
46
- * }
47
- * }
48
- * }
49
- * ```
50
- *
51
- * *This example has the folder `/home/jvilk` with subfile `someFile.txt` and subfolder `someDir`.*
52
- */
53
- export declare class HTTPRequest extends BaseFileSystem {
54
- static readonly Name = "HTTPRequest";
55
- static Create: any;
56
- static readonly Options: BackendOptions;
57
- static isAvailable(): boolean;
58
- readonly prefixUrl: string;
59
- private _index;
60
- constructor({ index, baseUrl }: HTTPRequest.Options);
61
- get metadata(): FileSystemMetadata;
62
- empty(): void;
63
- /**
64
- * Special HTTPFS function: Preload the given file into the index.
65
- * @param path
66
- * @param buffer
67
- */
68
- preloadFile(path: string, buffer: Uint8Array): void;
69
- stat(path: string, cred: Cred): Promise<Stats>;
70
- open(path: string, flags: FileFlag, mode: number, cred: Cred): Promise<NoSyncFile<this>>;
71
- readdir(path: string, cred: Cred): Promise<string[]>;
72
- /**
73
- * We have the entire file as a buffer; optimize readFile.
74
- */
75
- readFile(fname: string, flag: FileFlag, cred: Cred): Promise<Uint8Array>;
76
- private _getHTTPPath;
77
- /**
78
- * Asynchronously download the given file.
79
- */
80
- private _requestFile;
81
- /**
82
- * Only requests the HEAD content, for the file size.
83
- */
84
- private _requestFileSize;
85
- }
@@ -1,202 +0,0 @@
1
- var _a;
2
- import { BaseFileSystem } from '@zenfs/core/filesystem.js';
3
- import { ApiError, ErrorCode } from '@zenfs/core/ApiError.js';
4
- import { ActionType, NoSyncFile } from '@zenfs/core/file.js';
5
- import { Stats } from '@zenfs/core/stats.js';
6
- import { fetchIsAvailable, fetchFile, fetchFileSize } from '../fetch.js';
7
- import { FileIndex, isIndexFileInode, isIndexDirInode } from '@zenfs/core/FileIndex.js';
8
- import { CreateBackend } from '@zenfs/core/backends/backend.js';
9
- import { R_OK } from '@zenfs/core/emulation/constants.js';
10
- /**
11
- * A simple filesystem backed by HTTP downloads. You must create a directory listing using the
12
- * `make_http_index` tool provided by ZenFS.
13
- *
14
- * If you install ZenFS globally with `npm i -g zenfs`, you can generate a listing by
15
- * running `make_http_index` in your terminal in the directory you would like to index:
16
- *
17
- * ```
18
- * make_http_index > index.json
19
- * ```
20
- *
21
- * Listings objects look like the following:
22
- *
23
- * ```json
24
- * {
25
- * "home": {
26
- * "jvilk": {
27
- * "someFile.txt": null,
28
- * "someDir": {
29
- * // Empty directory
30
- * }
31
- * }
32
- * }
33
- * }
34
- * ```
35
- *
36
- * *This example has the folder `/home/jvilk` with subfile `someFile.txt` and subfolder `someDir`.*
37
- */
38
- export class HTTPRequest extends BaseFileSystem {
39
- static isAvailable() {
40
- return fetchIsAvailable;
41
- }
42
- constructor({ index, baseUrl = '' }) {
43
- super();
44
- if (!index) {
45
- index = 'index.json';
46
- }
47
- const indexRequest = typeof index == 'string' ? fetchFile(index, 'json') : Promise.resolve(index);
48
- this._ready = indexRequest.then(data => {
49
- this._index = FileIndex.fromListing(data);
50
- return this;
51
- });
52
- // prefix_url must end in a directory separator.
53
- if (baseUrl.length > 0 && baseUrl.charAt(baseUrl.length - 1) !== '/') {
54
- baseUrl = baseUrl + '/';
55
- }
56
- this.prefixUrl = baseUrl;
57
- }
58
- get metadata() {
59
- return {
60
- ...super.metadata,
61
- name: _a.Name,
62
- readonly: true,
63
- };
64
- }
65
- empty() {
66
- this._index.fileIterator(function (file) {
67
- file.fileData = null;
68
- });
69
- }
70
- /**
71
- * Special HTTPFS function: Preload the given file into the index.
72
- * @param path
73
- * @param buffer
74
- */
75
- preloadFile(path, buffer) {
76
- const inode = this._index.getInode(path);
77
- if (isIndexFileInode(inode)) {
78
- if (inode === null) {
79
- throw ApiError.ENOENT(path);
80
- }
81
- const stats = inode.getData();
82
- stats.size = buffer.length;
83
- stats.fileData = buffer;
84
- }
85
- else {
86
- throw ApiError.EISDIR(path);
87
- }
88
- }
89
- async stat(path, cred) {
90
- const inode = this._index.getInode(path);
91
- if (inode === null) {
92
- throw ApiError.ENOENT(path);
93
- }
94
- if (!inode.toStats().hasAccess(R_OK, cred)) {
95
- throw ApiError.EACCES(path);
96
- }
97
- let stats;
98
- if (isIndexFileInode(inode)) {
99
- stats = inode.getData();
100
- // At this point, a non-opened file will still have default stats from the listing.
101
- if (stats.size < 0) {
102
- stats.size = await this._requestFileSize(path);
103
- }
104
- }
105
- else if (isIndexDirInode(inode)) {
106
- stats = inode.getStats();
107
- }
108
- else {
109
- throw ApiError.FileError(ErrorCode.EINVAL, path);
110
- }
111
- return stats;
112
- }
113
- async open(path, flags, mode, cred) {
114
- // INVARIANT: You can't write to files on this file system.
115
- if (flags.isWriteable()) {
116
- throw new ApiError(ErrorCode.EPERM, path);
117
- }
118
- // Check if the path exists, and is a file.
119
- const inode = this._index.getInode(path);
120
- if (inode === null) {
121
- throw ApiError.ENOENT(path);
122
- }
123
- if (!inode.toStats().hasAccess(flags.getMode(), cred)) {
124
- throw ApiError.EACCES(path);
125
- }
126
- if (isIndexFileInode(inode) || isIndexDirInode(inode)) {
127
- switch (flags.pathExistsAction()) {
128
- case ActionType.THROW_EXCEPTION:
129
- case ActionType.TRUNCATE_FILE:
130
- throw ApiError.EEXIST(path);
131
- case ActionType.NOP:
132
- if (isIndexDirInode(inode)) {
133
- const stats = inode.getStats();
134
- return new NoSyncFile(this, path, flags, stats, stats.fileData || undefined);
135
- }
136
- const stats = inode.getData();
137
- // Use existing file contents.
138
- // XXX: Uh, this maintains the previously-used flag.
139
- if (stats.fileData) {
140
- return new NoSyncFile(this, path, flags, Stats.clone(stats), stats.fileData);
141
- }
142
- // @todo be lazier about actually requesting the file
143
- const buffer = await this._requestFile(path, 'buffer');
144
- // we don't initially have file sizes
145
- stats.size = buffer.length;
146
- stats.fileData = buffer;
147
- return new NoSyncFile(this, path, flags, Stats.clone(stats), buffer);
148
- default:
149
- throw new ApiError(ErrorCode.EINVAL, 'Invalid FileMode object.');
150
- }
151
- }
152
- else {
153
- throw ApiError.EPERM(path);
154
- }
155
- }
156
- async readdir(path, cred) {
157
- return this.readdirSync(path, cred);
158
- }
159
- /**
160
- * We have the entire file as a buffer; optimize readFile.
161
- */
162
- async readFile(fname, flag, cred) {
163
- // Get file.
164
- const fd = await this.open(fname, flag, 0o644, cred);
165
- try {
166
- return fd.getBuffer();
167
- }
168
- finally {
169
- await fd.close();
170
- }
171
- }
172
- _getHTTPPath(filePath) {
173
- if (filePath.charAt(0) === '/') {
174
- filePath = filePath.slice(1);
175
- }
176
- return this.prefixUrl + filePath;
177
- }
178
- _requestFile(p, type) {
179
- return fetchFile(this._getHTTPPath(p), type);
180
- }
181
- /**
182
- * Only requests the HEAD content, for the file size.
183
- */
184
- _requestFileSize(path) {
185
- return fetchFileSize(this._getHTTPPath(path));
186
- }
187
- }
188
- _a = HTTPRequest;
189
- HTTPRequest.Name = 'HTTPRequest';
190
- HTTPRequest.Create = CreateBackend.bind(_a);
191
- HTTPRequest.Options = {
192
- index: {
193
- type: ['string', 'object'],
194
- optional: true,
195
- description: 'URL to a file index as a JSON file or the file index object itself, generated with the make_http_index script. Defaults to `index.json`.',
196
- },
197
- baseUrl: {
198
- type: 'string',
199
- optional: true,
200
- description: 'Used as the URL prefix for fetched files. Default: Fetch files relative to the index.',
201
- },
202
- };