@zenfs/core 0.14.1 → 0.15.1

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/config.d.ts CHANGED
@@ -34,7 +34,7 @@ export interface Configuration<T extends ConfigMounts> extends SharedConfig {
34
34
  /**
35
35
  * Configures ZenFS with single mount point /
36
36
  */
37
- export declare function configure<T extends Backend>(config: MountConfiguration<T>): Promise<void>;
37
+ export declare function configureSingle<T extends Backend>(config: MountConfiguration<T>): Promise<void>;
38
38
  /**
39
39
  * Configures ZenFS with the given configuration
40
40
  * @see Configuration
package/dist/config.js CHANGED
@@ -47,6 +47,17 @@ export async function resolveMountConfig(config, _depth = 0) {
47
47
  await mount.ready();
48
48
  return mount;
49
49
  }
50
+ /**
51
+ * Configures ZenFS with single mount point /
52
+ */
53
+ export async function configureSingle(config) {
54
+ if (!isBackendConfig(config)) {
55
+ throw new TypeError('Invalid single mount point configuration');
56
+ }
57
+ const resolved = await resolveMountConfig(config);
58
+ fs.umount('/');
59
+ fs.mount('/', resolved);
60
+ }
50
61
  /**
51
62
  * Configures ZenFS with the given configuration
52
63
  * @see Configuration
@@ -54,10 +65,6 @@ export async function resolveMountConfig(config, _depth = 0) {
54
65
  export async function configure(config) {
55
66
  const uid = 'uid' in config ? config.uid || 0 : 0;
56
67
  const gid = 'gid' in config ? config.gid || 0 : 0;
57
- if (isMountConfig(config)) {
58
- // single FS
59
- config = { mounts: { '/': config } };
60
- }
61
68
  setCred({ uid, gid, suid: uid, sgid: gid, euid: uid, egid: gid });
62
69
  if (!config.mounts) {
63
70
  return;
@@ -18,7 +18,7 @@ import { BigIntStats, type Stats } from '../stats.js';
18
18
  import { Dir, Dirent } from './dir.js';
19
19
  import { ReadStream, WriteStream } from './streams.js';
20
20
  export * as constants from './constants.js';
21
- import '../symbol-dispose.js';
21
+ import '../polyfills.js';
22
22
  export declare class FileHandle implements promises.FileHandle {
23
23
  /**
24
24
  * The file descriptor for this file handle.
@@ -54,7 +54,7 @@ import { dirname, join, parse } from './path.js';
54
54
  import { _statfs, cred, fd2file, fdMap, file2fd, fixError, mounts, resolveMount } from './shared.js';
55
55
  import { ReadStream, WriteStream } from './streams.js';
56
56
  export * as constants from './constants.js';
57
- import '../symbol-dispose.js';
57
+ import '../polyfills.js';
58
58
  export class FileHandle {
59
59
  constructor(fdOrFile) {
60
60
  const isFile = typeof fdOrFile != 'number';
package/dist/file.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  import type { FileReadResult } from 'node:fs/promises';
4
4
  import type { FileSystem } from './filesystem.js';
5
5
  import { Stats, type FileType } from './stats.js';
6
- import './symbol-dispose.js';
6
+ import './polyfills.js';
7
7
  declare global {
8
8
  interface ArrayBuffer {
9
9
  readonly resizable: boolean;
package/dist/file.js CHANGED
@@ -2,7 +2,7 @@ import { O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_SYNC, O_TRUNC, O_WRONLY,
2
2
  import { Errno, ErrnoError } from './error.js';
3
3
  import { size_max } from './inode.js';
4
4
  import { Stats } from './stats.js';
5
- import './symbol-dispose.js';
5
+ import './polyfills.js';
6
6
  const validFlags = ['r', 'r+', 'rs', 'rs+', 'w', 'wx', 'w+', 'wx+', 'a', 'ax', 'a+', 'ax+'];
7
7
  export function parseFlag(flag) {
8
8
  if (typeof flag === 'number') {
@@ -0,0 +1,20 @@
1
+ Promise.withResolvers ?? (Promise.withResolvers = function () {
2
+ let _resolve,
3
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
4
+ _reject;
5
+ const promise = new Promise((resolve, reject) => {
6
+ _resolve = resolve;
7
+ _reject = reject;
8
+ });
9
+ return { promise, resolve: _resolve, reject: _reject };
10
+ });
11
+ /*
12
+ A polyfill for when these symbols are undefined.
13
+ For some reason, NodeJS does not polyfill them in a VM context.
14
+ Since jest uses a VM context for ESM, these need to be here.
15
+ */
16
+ // @ts-expect-error 2540
17
+ Symbol['dispose'] ?? (Symbol['dispose'] = Symbol('Symbol.dispose'));
18
+ // @ts-expect-error 2540
19
+ Symbol['asyncDispose'] ?? (Symbol['asyncDispose'] = Symbol('Symbol.asyncDispose'));
20
+ export {};
package/license.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) James P. and other ZenFS contributors.
1
+ Copyright (c) James Prevett and other ZenFS contributors.
2
2
  Copyright (c) 2013-2023 John Vilk and other BrowserFS contributors.
3
3
  Copyright (c) Joyent, Inc. and other Node contributors for `test/fixtures/node`.
4
4
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenfs/core",
3
- "version": "0.14.1",
3
+ "version": "0.15.1",
4
4
  "description": "A filesystem, anywhere",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -34,7 +34,7 @@
34
34
  "url": "https://github.com/zen-fs/core/issues"
35
35
  },
36
36
  "engines": {
37
- "node": ">= 22"
37
+ "node": ">= 16"
38
38
  },
39
39
  "exports": {
40
40
  ".": "./dist/index.js",
package/readme.md CHANGED
@@ -58,11 +58,11 @@ import { configure, InMemory } from '@zenfs/core';
58
58
  import { IndexedDB } from '@zenfs/dom';
59
59
  import { Zip } from '@zenfs/zip';
60
60
 
61
- const zipData = await (await fetch('mydata.zip')).arrayBuffer();
61
+ const res = await fetch('mydata.zip');
62
62
 
63
63
  await configure({
64
64
  mounts: {
65
- '/mnt/zip': { backend: Zip, zipData },
65
+ '/mnt/zip': { backend: Zip, data: await res.arrayBuffer() },
66
66
  '/tmp': InMemory,
67
67
  '/home': IndexedDB,
68
68
  }
@@ -79,10 +79,10 @@ await configure({
79
79
  Here is an example that mounts the `WebStorage` backend from `@zenfs/dom` on `/`:
80
80
 
81
81
  ```js
82
- import { configure, fs } from '@zenfs/core';
82
+ import { configureSingle, fs } from '@zenfs/core';
83
83
  import { WebStorage } from '@zenfs/dom';
84
84
 
85
- await configure({ backend: WebStorage });
85
+ await configureSingle({ backend: WebStorage });
86
86
 
87
87
  if (!fs.existsSync('/test.txt')) {
88
88
  fs.writeFileSync('/test.txt', 'This will persist across reloads!');
@@ -97,11 +97,11 @@ console.log(contents);
97
97
  The FS promises API is exposed as `promises`.
98
98
 
99
99
  ```js
100
- import { configure } from '@zenfs/core';
100
+ import { configureSingle } from '@zenfs/core';
101
101
  import { exists, writeFile } from '@zenfs/core/promises';
102
102
  import { IndexedDB } from '@zenfs/dom';
103
103
 
104
- await configure({ '/': IndexedDB });
104
+ await configureSingle({ backend: IndexedDB });
105
105
 
106
106
  const exists = await exists('/myfile.txt');
107
107
  if (!exists) {
@@ -137,7 +137,7 @@ await configure({
137
137
  fs.mkdirSync('/mnt');
138
138
 
139
139
  const res = await fetch('mydata.zip');
140
- const zipfs = await resolveMountConfig({ backend: Zip, zipData: await res.arrayBuffer() });
140
+ const zipfs = await resolveMountConfig({ backend: Zip, data: await res.arrayBuffer() });
141
141
  fs.mount('/mnt/zip', zipfs);
142
142
 
143
143
  // do stuff with the mounted zip
@@ -5,6 +5,7 @@ import type { FileSystemMetadata } from '../filesystem.js';
5
5
  import { FileSystem } from '../filesystem.js';
6
6
  import type { Stats } from '../stats.js';
7
7
  import type { Backend } from './backend.js';
8
+ import '../polyfills.js';
8
9
 
9
10
  export interface MutexLock extends PromiseWithResolvers<void> {
10
11
  [Symbol.dispose](): void;
@@ -1,6 +1,6 @@
1
1
  import { ErrnoError } from '../../error.js';
2
2
  import type { Ino } from '../../inode.js';
3
- import '../../symbol-dispose.js';
3
+ import '../../polyfills.js';
4
4
 
5
5
  /**
6
6
  * Represents a key-value store.
package/src/config.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { type Entries } from 'utilium';
2
1
  import type { Backend, BackendConfiguration, FilesystemOf, SharedConfig } from './backends/backend.js';
3
2
  import { checkOptions, isBackend, isBackendConfig } from './backends/backend.js';
4
3
  import * as fs from './emulation/index.js';
@@ -91,34 +90,31 @@ export interface Configuration<T extends ConfigMounts> extends SharedConfig {
91
90
  /**
92
91
  * Configures ZenFS with single mount point /
93
92
  */
94
- export async function configure<T extends Backend>(config: MountConfiguration<T>): Promise<void>;
93
+ export async function configureSingle<T extends Backend>(config: MountConfiguration<T>): Promise<void> {
94
+ if (!isBackendConfig(config)) {
95
+ throw new TypeError('Invalid single mount point configuration');
96
+ }
95
97
 
96
- /**
97
- * Configures ZenFS with the given configuration
98
- * @see Configuration
99
- */
100
- export async function configure<T extends ConfigMounts>(config: Partial<Configuration<T>>): Promise<void>;
98
+ const resolved = await resolveMountConfig(config);
99
+ fs.umount('/');
100
+ fs.mount('/', resolved);
101
+ }
101
102
 
102
103
  /**
103
104
  * Configures ZenFS with the given configuration
104
105
  * @see Configuration
105
106
  */
106
- export async function configure(config: MountConfiguration<Backend> | Partial<Configuration<ConfigMounts>>): Promise<void> {
107
+ export async function configure<T extends ConfigMounts>(config: Partial<Configuration<T>>): Promise<void> {
107
108
  const uid = 'uid' in config ? config.uid || 0 : 0;
108
109
  const gid = 'gid' in config ? config.gid || 0 : 0;
109
110
 
110
- if (isMountConfig(config)) {
111
- // single FS
112
- config = { mounts: { '/': config } } as Partial<Configuration<ConfigMounts>>;
113
- }
114
-
115
111
  setCred({ uid, gid, suid: uid, sgid: gid, euid: uid, egid: gid });
116
112
 
117
113
  if (!config.mounts) {
118
114
  return;
119
115
  }
120
116
 
121
- for (const [point, mountConfig] of Object.entries(config.mounts) as Entries<typeof config.mounts>) {
117
+ for (const [point, mountConfig] of Object.entries(config.mounts)) {
122
118
  if (!point.startsWith('/')) {
123
119
  throw new ErrnoError(Errno.EINVAL, 'Mount points must have absolute paths');
124
120
  }
@@ -127,7 +123,7 @@ export async function configure(config: MountConfiguration<Backend> | Partial<Co
127
123
  mountConfig.disableAsyncCache ??= config.disableAsyncCache || false;
128
124
  }
129
125
 
130
- config.mounts[point] = await resolveMountConfig(mountConfig);
126
+ config.mounts[point as keyof T & `/${string}`] = await resolveMountConfig(mountConfig);
131
127
  }
132
128
 
133
129
  fs.mountObject(config.mounts as MountObject);
@@ -18,7 +18,7 @@ import { dirname, join, parse } from './path.js';
18
18
  import { _statfs, cred, fd2file, fdMap, file2fd, fixError, mounts, resolveMount } from './shared.js';
19
19
  import { ReadStream, WriteStream } from './streams.js';
20
20
  export * as constants from './constants.js';
21
- import '../symbol-dispose.js';
21
+ import '../polyfills.js';
22
22
 
23
23
  export class FileHandle implements promises.FileHandle {
24
24
  /**
package/src/file.ts CHANGED
@@ -4,7 +4,7 @@ import { Errno, ErrnoError } from './error.js';
4
4
  import type { FileSystem } from './filesystem.js';
5
5
  import { size_max } from './inode.js';
6
6
  import { Stats, type FileType } from './stats.js';
7
- import './symbol-dispose.js';
7
+ import './polyfills.js';
8
8
 
9
9
  /*
10
10
  Typescript does not include a type declaration for resizable array buffers.
@@ -0,0 +1,20 @@
1
+ Promise.withResolvers ??= function <T>(): PromiseWithResolvers<T> {
2
+ let _resolve: ((value: T | PromiseLike<T>) => void) | undefined,
3
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
4
+ _reject: ((reason?: any) => void) | undefined;
5
+ const promise = new Promise<T>((resolve, reject) => {
6
+ _resolve = resolve;
7
+ _reject = reject;
8
+ });
9
+ return { promise, resolve: _resolve!, reject: _reject! };
10
+ };
11
+
12
+ /*
13
+ A polyfill for when these symbols are undefined.
14
+ For some reason, NodeJS does not polyfill them in a VM context.
15
+ Since jest uses a VM context for ESM, these need to be here.
16
+ */
17
+ // @ts-expect-error 2540
18
+ Symbol['dispose'] ??= Symbol('Symbol.dispose');
19
+ // @ts-expect-error 2540
20
+ Symbol['asyncDispose'] ??= Symbol('Symbol.asyncDispose');
@@ -1,10 +0,0 @@
1
- /*
2
- This file acts as a polyfill for when these symbols are undefined.
3
- For some reason, NodeJS does not polyfill them in a VM context.
4
- Since jest uses a VM context for ESM, these need to be here.
5
- */
6
- // @ts-expect-error 2540
7
- Symbol['dispose'] ?? (Symbol['dispose'] = Symbol('Symbol.dispose'));
8
- // @ts-expect-error 2540
9
- Symbol['asyncDispose'] ?? (Symbol['asyncDispose'] = Symbol('Symbol.asyncDispose'));
10
- export {};
@@ -1,9 +0,0 @@
1
- /*
2
- This file acts as a polyfill for when these symbols are undefined.
3
- For some reason, NodeJS does not polyfill them in a VM context.
4
- Since jest uses a VM context for ESM, these need to be here.
5
- */
6
- // @ts-expect-error 2540
7
- Symbol['dispose'] ??= Symbol('Symbol.dispose');
8
- // @ts-expect-error 2540
9
- Symbol['asyncDispose'] ??= Symbol('Symbol.asyncDispose');
File without changes