From 6c65f3d634561df333ea534cebfd54fadd4b248d Mon Sep 17 00:00:00 2001 From: Vortex Date: Thu, 7 Mar 2024 14:26:55 -0600 Subject: [PATCH] Fixed resolveBackendConfig not checking options Removed old _InMemory Removed getMount and getMounts Began updating readme --- readme.md | 57 ++++++++++++++++++---------------------- src/backends/InMemory.ts | 22 +++------------- src/backends/backend.ts | 5 +++- src/emulation/index.ts | 2 +- src/emulation/shared.ts | 46 ++++++++++++++++++++------------ src/index.ts | 4 +-- 6 files changed, 66 insertions(+), 70 deletions(-) diff --git a/readme.md b/readme.md index d321b0471..0d4f19ea9 100644 --- a/readme.md +++ b/readme.md @@ -49,12 +49,10 @@ console.log(contents); A `InMemory` backend is created by default. If you would like to use a different one, you must configure BrowserFS. It is recommended to do so using the `configure` function. Here is an example using the `Storage` backend from `@browserfs/fs-dom`: ```js -import { configure, fs, registerBackend } from '@browserfs/core'; -import { StorageFileSystem } from '@browserfs/fs-dom'; -registerBackend(StorageFileSystem); +import { configure, fs } from '@browserfs/core'; +import { StorageStore } from '@browserfs/fs-dom'; -// you can also add a callback as the last parameter instead of using promises -await configure({ fs: 'Storage' }); +await configure({ backend: StorageStore }); if (!fs.existsSync('/test.txt')) { fs.writeFileSync('/test.txt', 'This will persist across reloads!'); @@ -69,23 +67,19 @@ console.log(contents); You can use multiple backends by passing an object to `configure` which maps paths to file systems. The following example mounts a zip file to `/zip`, in-memory storage to `/tmp`, and IndexedDB storage to `/home` (note that `/` has the default in-memory backend): ```js -import { configure, registerBackend } from '@browserfs/core'; -import { IndexedDBFileSystem } from '@browserfs/fs-dom'; -import { ZipFS } from '@browserfs/fs-zip'; -import Buffer from 'buffer'; -registerBackend(IndexedDBFileSystem, ZipFS); +import { configure } from '@browserfs/core'; +import { IndexedDD } from '@browserfs/fs-dom'; +import { Zip } from '@browserfs/fs-zip'; const zipData = await (await fetch('mydata.zip')).arrayBuffer(); await configure({ '/mnt/zip': { - fs: 'ZipFS', - options: { - zipData: Buffer.from(zipData) - } + backend: Zip, + zipData: zipData, }, '/tmp': 'InMemory', - '/home': 'IndexedDB', + '/home': IndexedDB, }; ``` @@ -94,11 +88,10 @@ await configure({ The FS promises API is exposed as `promises`. ```js -import { configure, promises, registerBackend } from '@browserfs/core'; -import { IndexedDBFileSystem } from '@browserfs/fs-dom'; -registerBackend(IndexedDBFileSystem); +import { configure, promises } from '@browserfs/core'; +import { IndexedDB } from '@browserfs/fs-dom'; -await configure({ '/': 'IndexedDB' }); +await configure({ '/': IndexedDB }); const exists = await promises.exists('/myfile.txt'); if (!exists) { @@ -106,46 +99,48 @@ if (!exists) { } ``` -BrowserFS does _not_ provide a seperate method for importing promises in its built form. If you are using Typescript, you can import the promises API from source code (perhaps to reduce you bundle size). Doing so it not recommended as the files may be moved without notice. +BrowserFS does _not_ provide a seperate public import for importing promises in its built form. If you are using ESM, you can import promises functions from `dist/emulation/promises`, though this may change at any time and is not recommended. #### Using asynchronous backends synchronously -You may have noticed that attempting to use a synchronous method on an asynchronous backend (e.g. IndexedDB) results in a "not supplied" error (`ENOTSUP`). If you wish to use an asynchronous backend synchronously you need to wrap it in an `AsyncMirror`: +You may have noticed that attempting to use a synchronous function on an asynchronous backend (e.g. IndexedDB) results in a "not supplied" error (`ENOTSUP`). If you wish to use an asynchronous backend synchronously you need to wrap it in an `AsyncMirror`: ```js import { configure, fs } from '@browserfs/core'; -import { IndexedDBFileSystem } from '@browserfs/fs-dom'; -registerBackend(IndexedDBFileSystem); +import { IndexedDB } from '@browserfs/fs-dom'; await configure({ - '/': { fs: 'AsyncMirror', options: { sync: { fs: 'InMemory' }, async: { fs: 'IndexedDB' } } } + '/': { + backend: 'AsyncMirror', + sync: 'InMemory', + async: IndexedDB + } }); -fs.writeFileSync('/persistant.txt', 'My persistant data'); // This fails if you configure the FS as IndexedDB +fs.writeFileSync('/persistant.txt', 'My persistant data'); // This fails if you configure with only IndexedDB ``` ### Advanced usage #### Creating backends -If you would like to create backends without configure, you may do so by importing the backend's class and calling its `Create` method. You can import the backend directly or with `backends`: +If you would like to create backends without configure, you may do so by importing the backend and calling `createBackend` with it. You can import the backend directly or with `backends`: ```js import { configure, backends, InMemory } from '@browserfs/core'; console.log(backends.InMemory === InMemory) // they are the same -const inMemoryFS = await InMemory.Create(); +const internalInMemoryFS = createBackend(InMemory); ``` -> ⚠ Instances of backends follow the ***internal*** BrowserFS API. You should never use a backend's method unless you are extending a backend. +> ⚠ Instances of backends follow the ***internal*** BrowserFS API. You should never use a backend's methods unless you are extending a backend. -Coming soon: ```js import { configure, InMemory } from '@browserfs/core'; -const inMemoryFS = new InMemory(); -await inMemoryFS.whenReady(); +const internalInMemoryFS = new InMemory(); +await internalInMemoryFS.ready(); ``` #### Mounting diff --git a/src/backends/InMemory.ts b/src/backends/InMemory.ts index ee8e5efbc..3b10c0189 100644 --- a/src/backends/InMemory.ts +++ b/src/backends/InMemory.ts @@ -34,6 +34,10 @@ export class InMemoryStore implements SyncStore, SimpleSyncStore { } } +/** + * A simple in-memory file system backed by an InMemoryStore. + * Files are not persisted across page loads. + */ export const InMemory: Backend = { name: 'InMemory', isAvailable(): boolean { @@ -49,21 +53,3 @@ export const InMemory: Backend = { return new SyncStoreFileSystem({ store: new InMemoryStore(name) }); }, }; - -/** - * A simple in-memory file system backed by an InMemoryStore. - * Files are not persisted across page loads. - */ -export class _InMemory extends SyncStoreFileSystem { - public static isAvailable(): boolean { - return true; - } - - public static create = createBackend.bind(this); - - public static readonly options = {}; - - public constructor() { - super({ store: new InMemoryStore() }); - } -} diff --git a/src/backends/backend.ts b/src/backends/backend.ts index 8a7cd243a..ff7f57ef4 100644 --- a/src/backends/backend.ts +++ b/src/backends/backend.ts @@ -186,5 +186,8 @@ export async function resolveBackendConfig(options: BackendConfig): Promise= 0) { @@ -69,7 +83,11 @@ export function normalizePath(p: string): string { return resolve(p); } -export function normalizeOptions(options: any, defEnc: string | null, defFlag: string, defMode: number | null): { encoding: BufferEncoding; flag: string; mode: number } { +/** + * Normalizes options + * @internal + */ +export function normalizeOptions(options: unknown, defEnc: string | null, defFlag: string, defMode: number | null): { encoding: BufferEncoding; flag: string; mode: number } { // typeof null === 'object' so special-case handing is needed. switch (options === null ? 'null' : typeof options) { case 'object': @@ -80,7 +98,7 @@ export function normalizeOptions(options: any, defEnc: string | null, defFlag: s }; case 'string': return { - encoding: options, + encoding: options, flag: defFlag, mode: defMode!, }; @@ -88,7 +106,7 @@ export function normalizeOptions(options: any, defEnc: string | null, defFlag: s case 'undefined': case 'function': return { - encoding: defEnc! as BufferEncoding, + encoding: defEnc!, flag: defFlag, mode: defMode!, }; @@ -97,6 +115,10 @@ export function normalizeOptions(options: any, defEnc: string | null, defFlag: s } } +/** + * Do nothing + * @internal + */ export function nop() { // do nothing } @@ -127,6 +149,10 @@ export interface MountMapping { [point: string]: FileSystem; } +/** + * The map of mount points + * @internal + */ export const mounts: Map = new Map(); /* @@ -134,20 +160,6 @@ Set a default root. */ mount('/', InMemory.create({ name: 'root' })); -/** - * Gets the file system mounted at `mountPoint` - */ -export function getMount(mountPoint: string): FileSystem { - return mounts.get(mountPoint); -} - -/** - * Gets an object of mount points (keys) and filesystems (values) - */ -export function getMounts(): MountMapping { - return Object.fromEntries(mounts.entries()); -} - /** * Mounts the file system at the given mount point. */ diff --git a/src/index.ts b/src/index.ts index 7a2acf656..3b50b8765 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,7 +13,7 @@ import { type MountMapping, setCred } from './emulation/shared.js'; */ export function initialize(mounts: { [point: string]: FileSystem }, uid: number = 0, gid: number = 0) { setCred(new Cred(uid, gid, uid, gid, uid, gid)); - return fs.initialize(mounts); + fs.initialize(mounts); } /** @@ -57,7 +57,7 @@ export async function configure(config: Configuration): Promise { config[point] = await resolveBackendConfig(value); } - return initialize(config as MountMapping); + initialize(config); } export * from './backends/index.js';