@b9g/filesystem 0.1.7 → 0.1.9

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/README.md CHANGED
@@ -251,28 +251,28 @@ router.post('/upload', async (request) => {
251
251
  - `ShovelFileHandle` - FileSystemFileHandle implementation
252
252
  - `ShovelDirectoryHandle` - FileSystemDirectoryHandle implementation
253
253
  - `ShovelHandle` - Base handle class
254
- - `CustomBucketStorage` - Bucket storage with custom backend factories
254
+ - `CustomDirectoryStorage` - Directory storage with custom backend factories
255
255
 
256
256
  ### Types
257
257
 
258
- - `Bucket` - Alias for FileSystemDirectoryHandle
259
- - `BucketStorage` - Interface for bucket storage (`open(name): Promise<FileSystemDirectoryHandle>`)
260
- - `BucketFactory` - Factory function type for creating bucket backends
258
+ - `Directory` - Alias for FileSystemDirectoryHandle
259
+ - `DirectoryStorage` - Interface for directory storage (`open(name): Promise<FileSystemDirectoryHandle>`)
260
+ - `DirectoryFactory` - Factory function type for creating directory backends
261
261
  - `FileSystemConfig` - Configuration for filesystem backends
262
262
  - `FileSystemPermissionDescriptor` - Permission descriptor type
263
263
  - `FileSystemBackend` - Backend interface for filesystem implementations
264
264
 
265
265
  ## API Reference
266
266
 
267
- ### BucketStorage
267
+ ### DirectoryStorage
268
268
 
269
269
  ```typescript
270
- interface BucketStorage {
270
+ interface DirectoryStorage {
271
271
  open(name: string): Promise<FileSystemDirectoryHandle>;
272
272
  }
273
273
 
274
- class CustomBucketStorage implements BucketStorage {
275
- register(name: string, factory: BucketFactory): void;
274
+ class CustomDirectoryStorage implements DirectoryStorage {
275
+ register(name: string, factory: DirectoryFactory): void;
276
276
  open(name: string): Promise<FileSystemDirectoryHandle>;
277
277
  }
278
278
  ```
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "@b9g/filesystem",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Universal File System Access API implementations for all platforms",
5
5
  "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/bikeshaving/shovel.git",
9
+ "directory": "packages/filesystem"
10
+ },
6
11
  "dependencies": {
7
12
  "mime": "^4.0.4"
8
13
  },
@@ -50,13 +55,13 @@
50
55
  "types": "./src/memory.d.ts",
51
56
  "import": "./src/memory.js"
52
57
  },
53
- "./node": {
54
- "types": "./src/node.d.ts",
55
- "import": "./src/node.js"
58
+ "./node-fs": {
59
+ "types": "./src/node-fs.d.ts",
60
+ "import": "./src/node-fs.js"
56
61
  },
57
- "./node.js": {
58
- "types": "./src/node.d.ts",
59
- "import": "./src/node.js"
62
+ "./node-fs.js": {
63
+ "types": "./src/node-fs.d.ts",
64
+ "import": "./src/node-fs.js"
60
65
  },
61
66
  "./package.json": "./package.json"
62
67
  }
package/src/bun-s3.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Bun S3 filesystem implementation
3
3
  *
4
- * Provides S3Bucket (root) and S3FileSystemBackend for storage operations
4
+ * Provides S3Directory (root) and S3FileSystemBackend for storage operations
5
5
  * using Bun's native S3 client.
6
6
  */
7
7
  import { type FileSystemBackend } from "./index.js";
@@ -27,16 +27,16 @@ export declare class S3FileSystemBackend implements FileSystemBackend {
27
27
  remove(path: string, recursive?: boolean): Promise<void>;
28
28
  }
29
29
  /**
30
- * S3 bucket - root entry point for S3 filesystem using Bun's S3 client
30
+ * S3 directory - root entry point for S3 filesystem using Bun's S3 client
31
31
  * Implements FileSystemDirectoryHandle for S3 object storage
32
32
  *
33
33
  * Example usage with namespacing:
34
34
  * ```typescript
35
35
  * const s3 = new S3Client({ ... });
36
36
  *
37
- * // Use in CustomBucketStorage factory for multi-tenancy
38
- * const buckets = new CustomBucketStorage(async (name) => {
39
- * return new S3Bucket(
37
+ * // Use in CustomDirectoryStorage factory for multi-tenancy
38
+ * const directories = new CustomDirectoryStorage(async (name) => {
39
+ * return new S3Directory(
40
40
  * s3,
41
41
  * "my-company-bucket",
42
42
  * `my-app/production/${name}` // Prefix for isolation
@@ -44,7 +44,7 @@ export declare class S3FileSystemBackend implements FileSystemBackend {
44
44
  * });
45
45
  * ```
46
46
  */
47
- export declare class S3Bucket implements FileSystemDirectoryHandle {
47
+ export declare class S3Directory implements FileSystemDirectoryHandle {
48
48
  #private;
49
49
  readonly kind: "directory";
50
50
  readonly name: string;
package/src/bun-s3.js CHANGED
@@ -179,7 +179,7 @@ var S3FileSystemBackend = class {
179
179
  return this.#prefix ? `${this.#prefix}/${cleanPath}` : cleanPath;
180
180
  }
181
181
  };
182
- var S3Bucket = class _S3Bucket {
182
+ var S3Directory = class _S3Directory {
183
183
  kind;
184
184
  name;
185
185
  #backend;
@@ -259,7 +259,7 @@ var S3Bucket = class _S3Bucket {
259
259
  async isSameEntry(other) {
260
260
  if (other.kind !== "directory")
261
261
  return false;
262
- return other instanceof _S3Bucket && other.name === this.name;
262
+ return other instanceof _S3Directory && other.name === this.name;
263
263
  }
264
264
  async queryPermission() {
265
265
  return "granted";
@@ -269,6 +269,6 @@ var S3Bucket = class _S3Bucket {
269
269
  }
270
270
  };
271
271
  export {
272
- S3Bucket,
272
+ S3Directory,
273
273
  S3FileSystemBackend
274
274
  };
package/src/index.d.ts CHANGED
@@ -7,11 +7,6 @@ export interface FileSystemConfig {
7
7
  /** Platform-specific configuration */
8
8
  [key: string]: any;
9
9
  }
10
- /**
11
- * Bucket is a semantic alias for FileSystemDirectoryHandle
12
- * Represents a named storage bucket that provides direct filesystem access
13
- */
14
- export type Bucket = FileSystemDirectoryHandle;
15
10
  /**
16
11
  * Permission descriptor for File System Access API
17
12
  */
@@ -84,11 +79,12 @@ export declare abstract class ShovelHandle implements FileSystemHandle {
84
79
  get name(): string;
85
80
  get backend(): FileSystemBackend;
86
81
  isSameEntry(other: FileSystemHandle): Promise<boolean>;
87
- queryPermission(descriptor?: FileSystemPermissionDescriptor): Promise<PermissionState>;
88
- requestPermission(descriptor?: FileSystemPermissionDescriptor): Promise<PermissionState>;
82
+ queryPermission(_descriptor?: FileSystemPermissionDescriptor): Promise<PermissionState>;
83
+ requestPermission(_descriptor?: FileSystemPermissionDescriptor): Promise<PermissionState>;
89
84
  /**
90
85
  * Validates that a name is actually a name and not a path
91
86
  * The File System Access API only accepts names, not paths
87
+ * WPT expects TypeError for invalid names
92
88
  */
93
89
  validateName(name: string): void;
94
90
  }
@@ -134,82 +130,81 @@ export declare class ShovelDirectoryHandle extends ShovelHandle implements FileS
134
130
  ]>;
135
131
  }
136
132
  /**
137
- * Bucket storage interface - parallels CacheStorage for filesystem access
138
- * This could become a future web standard
133
+ * Directory storage interface - parallels CacheStorage for filesystem access
139
134
  */
140
- export interface BucketStorage {
135
+ export interface DirectoryStorage {
141
136
  /**
142
- * Open a named bucket - returns FileSystemDirectoryHandle (root of that bucket)
137
+ * Open a named directory - returns FileSystemDirectoryHandle (root)
143
138
  * Well-known names: 'static', 'tmp'
144
139
  */
145
140
  open(name: string): Promise<FileSystemDirectoryHandle>;
146
141
  /**
147
- * Check if a named bucket exists
142
+ * Check if a named directory exists
148
143
  */
149
144
  has(name: string): Promise<boolean>;
150
145
  /**
151
- * Delete a named bucket and all its contents
146
+ * Delete a named directory and all its contents
152
147
  */
153
148
  delete(name: string): Promise<boolean>;
154
149
  /**
155
- * List all available bucket names
150
+ * List all available directory names
156
151
  */
157
152
  keys(): Promise<string[]>;
158
153
  }
159
154
  /**
160
- * Factory function type for creating buckets
161
- * @param name Bucket name to create
162
- * @returns FileSystemDirectoryHandle (Bucket) instance
155
+ * Factory function type for creating directories
156
+ * @param name Directory name to create
157
+ * @returns FileSystemDirectoryHandle instance
163
158
  */
164
- export type BucketFactory = (name: string) => FileSystemDirectoryHandle | Promise<FileSystemDirectoryHandle>;
159
+ export type DirectoryFactory = (name: string) => FileSystemDirectoryHandle | Promise<FileSystemDirectoryHandle>;
165
160
  /**
166
- * Custom bucket storage with factory-based bucket creation
161
+ * Custom directory storage with factory-based directory creation
167
162
  *
168
- * Provides a registry of named buckets (FileSystemDirectoryHandle instances)
169
- * with lazy instantiation and singleton behavior per bucket name.
163
+ * Provides a registry of named directories (FileSystemDirectoryHandle instances)
164
+ * with lazy instantiation and singleton behavior per directory name.
170
165
  *
171
166
  * Mirrors the CustomCacheStorage pattern for consistency across the platform.
172
167
  */
173
- export declare class CustomBucketStorage {
168
+ export declare class CustomDirectoryStorage {
174
169
  #private;
175
170
  /**
176
- * @param factory Function that creates bucket instances by name
171
+ * @param factory Function that creates directory instances by name
177
172
  */
178
- constructor(factory: BucketFactory);
173
+ constructor(factory: DirectoryFactory);
179
174
  /**
180
- * Open a named bucket - creates if it doesn't exist
175
+ * Open a named directory - creates if it doesn't exist
181
176
  *
182
- * @param name Bucket name (e.g., 'tmp', 'dist', 'uploads')
183
- * @returns FileSystemDirectoryHandle for the bucket
177
+ * @param name Directory name (e.g., 'tmp', 'dist', 'uploads')
178
+ * @returns FileSystemDirectoryHandle for the directory
184
179
  */
185
180
  open(name: string): Promise<FileSystemDirectoryHandle>;
186
181
  /**
187
- * Check if a named bucket exists
182
+ * Check if a named directory exists
188
183
  *
189
- * @param name Bucket name to check
190
- * @returns true if bucket has been opened
184
+ * @param name Directory name to check
185
+ * @returns true if directory has been opened
191
186
  */
192
187
  has(name: string): Promise<boolean>;
193
188
  /**
194
- * Delete a named bucket
189
+ * Delete a named directory
195
190
  *
196
- * @param name Bucket name to delete
197
- * @returns true if bucket was deleted, false if it didn't exist
191
+ * @param name Directory name to delete
192
+ * @returns true if directory was deleted, false if it didn't exist
198
193
  */
199
194
  delete(name: string): Promise<boolean>;
200
195
  /**
201
- * List all opened bucket names
196
+ * List all opened directory names
202
197
  *
203
- * @returns Array of bucket names
198
+ * @returns Array of directory names
204
199
  */
205
200
  keys(): Promise<string[]>;
206
201
  /**
207
- * Get statistics about opened buckets (non-standard utility method)
202
+ * Get statistics about opened directories (non-standard utility method)
208
203
  *
209
- * @returns Object with bucket statistics
204
+ * @returns Object with directory statistics
210
205
  */
211
206
  getStats(): {
212
207
  openInstances: number;
213
- bucketNames: string[];
208
+ directoryNames: string[];
214
209
  };
215
210
  }
package/src/index.js CHANGED
@@ -41,11 +41,29 @@ var ShovelWritableFileStream = class extends WritableStream {
41
41
  try {
42
42
  if (typeof data === "string") {
43
43
  await writer.write(new TextEncoder().encode(data));
44
- } else if (data instanceof Uint8Array || data instanceof ArrayBuffer) {
45
- const bytes = data instanceof ArrayBuffer ? new Uint8Array(data) : data;
46
- await writer.write(bytes);
44
+ } else if (data instanceof Uint8Array) {
45
+ await writer.write(data);
46
+ } else if (data instanceof ArrayBuffer) {
47
+ await writer.write(new Uint8Array(data));
48
+ } else if (data instanceof Blob) {
49
+ const buffer = await data.arrayBuffer();
50
+ await writer.write(new Uint8Array(buffer));
51
+ } else if (ArrayBuffer.isView(data)) {
52
+ await writer.write(
53
+ new Uint8Array(data.buffer, data.byteOffset, data.byteLength)
54
+ );
55
+ } else if (typeof data === "object" && data !== null && "type" in data) {
56
+ const params = data;
57
+ if (params.type === "write" && params.data !== void 0) {
58
+ await this.write(params.data);
59
+ return;
60
+ }
61
+ throw new DOMException("Invalid write params", "NotSupportedError");
47
62
  } else {
48
- await writer.write(new TextEncoder().encode(String(data)));
63
+ throw new DOMException(
64
+ "Invalid data type for write",
65
+ "NotSupportedError"
66
+ );
49
67
  }
50
68
  } finally {
51
69
  writer.releaseLock();
@@ -84,30 +102,26 @@ var ShovelHandle = class _ShovelHandle {
84
102
  return false;
85
103
  return this.path === other.path;
86
104
  }
87
- async queryPermission(descriptor) {
88
- const _mode = descriptor?.mode || "read";
105
+ async queryPermission(_descriptor) {
89
106
  return "granted";
90
107
  }
91
- async requestPermission(descriptor) {
92
- const _mode = descriptor?.mode || "read";
108
+ async requestPermission(_descriptor) {
93
109
  return "granted";
94
110
  }
95
111
  /**
96
112
  * Validates that a name is actually a name and not a path
97
113
  * The File System Access API only accepts names, not paths
114
+ * WPT expects TypeError for invalid names
98
115
  */
99
116
  validateName(name) {
100
117
  if (!name || name.trim() === "") {
101
- throw new DOMException("Name cannot be empty", "NotAllowedError");
118
+ throw new TypeError("Name cannot be empty");
102
119
  }
103
120
  if (name.includes("/") || name.includes("\\")) {
104
- throw new DOMException(
105
- "Name cannot contain path separators",
106
- "NotAllowedError"
107
- );
121
+ throw new TypeError("Name cannot contain path separators");
108
122
  }
109
123
  if (name === "." || name === "..") {
110
- throw new DOMException("Name cannot be '.' or '..'", "NotAllowedError");
124
+ throw new TypeError("Name cannot be '.' or '..'");
111
125
  }
112
126
  }
113
127
  };
@@ -249,45 +263,45 @@ var ShovelDirectoryHandle = class _ShovelDirectoryHandle extends ShovelHandle {
249
263
  return `${base}/${name}`;
250
264
  }
251
265
  };
252
- var CustomBucketStorage = class {
266
+ var CustomDirectoryStorage = class {
253
267
  #instances;
254
268
  #factory;
255
269
  /**
256
- * @param factory Function that creates bucket instances by name
270
+ * @param factory Function that creates directory instances by name
257
271
  */
258
272
  constructor(factory) {
259
273
  this.#instances = /* @__PURE__ */ new Map();
260
274
  this.#factory = factory;
261
275
  }
262
276
  /**
263
- * Open a named bucket - creates if it doesn't exist
277
+ * Open a named directory - creates if it doesn't exist
264
278
  *
265
- * @param name Bucket name (e.g., 'tmp', 'dist', 'uploads')
266
- * @returns FileSystemDirectoryHandle for the bucket
279
+ * @param name Directory name (e.g., 'tmp', 'dist', 'uploads')
280
+ * @returns FileSystemDirectoryHandle for the directory
267
281
  */
268
282
  async open(name) {
269
283
  const existing = this.#instances.get(name);
270
284
  if (existing) {
271
285
  return existing;
272
286
  }
273
- const bucket = await this.#factory(name);
274
- this.#instances.set(name, bucket);
275
- return bucket;
287
+ const dir = await this.#factory(name);
288
+ this.#instances.set(name, dir);
289
+ return dir;
276
290
  }
277
291
  /**
278
- * Check if a named bucket exists
292
+ * Check if a named directory exists
279
293
  *
280
- * @param name Bucket name to check
281
- * @returns true if bucket has been opened
294
+ * @param name Directory name to check
295
+ * @returns true if directory has been opened
282
296
  */
283
297
  async has(name) {
284
298
  return this.#instances.has(name);
285
299
  }
286
300
  /**
287
- * Delete a named bucket
301
+ * Delete a named directory
288
302
  *
289
- * @param name Bucket name to delete
290
- * @returns true if bucket was deleted, false if it didn't exist
303
+ * @param name Directory name to delete
304
+ * @returns true if directory was deleted, false if it didn't exist
291
305
  */
292
306
  async delete(name) {
293
307
  const instance = this.#instances.get(name);
@@ -298,27 +312,27 @@ var CustomBucketStorage = class {
298
312
  return false;
299
313
  }
300
314
  /**
301
- * List all opened bucket names
315
+ * List all opened directory names
302
316
  *
303
- * @returns Array of bucket names
317
+ * @returns Array of directory names
304
318
  */
305
319
  async keys() {
306
320
  return Array.from(this.#instances.keys());
307
321
  }
308
322
  /**
309
- * Get statistics about opened buckets (non-standard utility method)
323
+ * Get statistics about opened directories (non-standard utility method)
310
324
  *
311
- * @returns Object with bucket statistics
325
+ * @returns Object with directory statistics
312
326
  */
313
327
  getStats() {
314
328
  return {
315
329
  openInstances: this.#instances.size,
316
- bucketNames: Array.from(this.#instances.keys())
330
+ directoryNames: Array.from(this.#instances.keys())
317
331
  };
318
332
  }
319
333
  };
320
334
  export {
321
- CustomBucketStorage,
335
+ CustomDirectoryStorage,
322
336
  ShovelDirectoryHandle,
323
337
  ShovelFileHandle,
324
338
  ShovelHandle
package/src/memory.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * In-memory filesystem implementation
3
3
  *
4
- * Provides MemoryBucket (root) and MemoryFileSystemBackend for storage operations
4
+ * Provides MemoryDirectory (root) and MemoryFileSystemBackend for storage operations
5
5
  * using in-memory data structures.
6
6
  */
7
7
  import { type FileSystemBackend } from "./index.js";
@@ -15,19 +15,19 @@ interface MemoryFile {
15
15
  type: string;
16
16
  }
17
17
  /**
18
- * In-memory directory data
18
+ * In-memory directory data (internal structure)
19
19
  */
20
- interface MemoryDirectory {
20
+ interface MemoryDirectoryData {
21
21
  name: string;
22
22
  files: Map<string, MemoryFile>;
23
- directories: Map<string, MemoryDirectory>;
23
+ directories: Map<string, MemoryDirectoryData>;
24
24
  }
25
25
  /**
26
26
  * In-memory storage backend that implements FileSystemBackend
27
27
  */
28
28
  export declare class MemoryFileSystemBackend implements FileSystemBackend {
29
29
  #private;
30
- constructor(root: MemoryDirectory);
30
+ constructor(root: MemoryDirectoryData);
31
31
  stat(path: string): Promise<{
32
32
  kind: "file" | "directory";
33
33
  } | null>;
@@ -44,10 +44,10 @@ export declare class MemoryFileSystemBackend implements FileSystemBackend {
44
44
  remove(path: string, recursive?: boolean): Promise<void>;
45
45
  }
46
46
  /**
47
- * Memory bucket - root entry point for in-memory filesystem
47
+ * Memory directory - root entry point for in-memory filesystem
48
48
  * Implements FileSystemDirectoryHandle and owns the root data structure
49
49
  */
50
- export declare class MemoryBucket implements FileSystemDirectoryHandle {
50
+ export declare class MemoryDirectory implements FileSystemDirectoryHandle {
51
51
  #private;
52
52
  readonly kind: "directory";
53
53
  readonly name: string;
package/src/memory.js CHANGED
@@ -145,7 +145,7 @@ var MemoryFileSystemBackend = class {
145
145
  return { parentDir: current, name };
146
146
  }
147
147
  };
148
- var MemoryBucket = class _MemoryBucket {
148
+ var MemoryDirectory = class _MemoryDirectory {
149
149
  kind;
150
150
  name;
151
151
  #backend;
@@ -160,6 +160,15 @@ var MemoryBucket = class _MemoryBucket {
160
160
  this.#backend = new MemoryFileSystemBackend(root);
161
161
  }
162
162
  async getFileHandle(name, options) {
163
+ if (!name || name.trim() === "") {
164
+ throw new TypeError("Name cannot be empty");
165
+ }
166
+ if (name.includes("/") || name.includes("\\")) {
167
+ throw new TypeError("Name cannot contain path separators");
168
+ }
169
+ if (name === "." || name === "..") {
170
+ throw new TypeError("Name cannot be '.' or '..'");
171
+ }
163
172
  const filePath = `/${name}`;
164
173
  const stat = await this.#backend.stat(filePath);
165
174
  if (!stat && options?.create) {
@@ -175,6 +184,15 @@ var MemoryBucket = class _MemoryBucket {
175
184
  return new ShovelFileHandle(this.#backend, filePath);
176
185
  }
177
186
  async getDirectoryHandle(name, options) {
187
+ if (!name || name.trim() === "") {
188
+ throw new TypeError("Name cannot be empty");
189
+ }
190
+ if (name.includes("/") || name.includes("\\")) {
191
+ throw new TypeError("Name cannot contain path separators");
192
+ }
193
+ if (name === "." || name === "..") {
194
+ throw new TypeError("Name cannot be '.' or '..'");
195
+ }
178
196
  const dirPath = `/${name}`;
179
197
  const stat = await this.#backend.stat(dirPath);
180
198
  if (!stat && options?.create) {
@@ -194,6 +212,12 @@ var MemoryBucket = class _MemoryBucket {
194
212
  await this.#backend.remove(entryPath, options?.recursive);
195
213
  }
196
214
  async resolve(possibleDescendant) {
215
+ if (possibleDescendant instanceof _MemoryDirectory) {
216
+ if (await this.isSameEntry(possibleDescendant)) {
217
+ return [];
218
+ }
219
+ return null;
220
+ }
197
221
  if (!(possibleDescendant instanceof ShovelDirectoryHandle || possibleDescendant instanceof ShovelFileHandle)) {
198
222
  return null;
199
223
  }
@@ -230,7 +254,7 @@ var MemoryBucket = class _MemoryBucket {
230
254
  async isSameEntry(other) {
231
255
  if (other.kind !== "directory")
232
256
  return false;
233
- return other instanceof _MemoryBucket && other.name === this.name;
257
+ return other instanceof _MemoryDirectory && other.name === this.name;
234
258
  }
235
259
  async queryPermission() {
236
260
  return "granted";
@@ -240,6 +264,6 @@ var MemoryBucket = class _MemoryBucket {
240
264
  }
241
265
  };
242
266
  export {
243
- MemoryBucket,
267
+ MemoryDirectory,
244
268
  MemoryFileSystemBackend
245
269
  };
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Node.js filesystem implementation using node:fs
3
+ *
4
+ * Provides NodeFSDirectory (root) and NodeFSBackend for storage operations
5
+ * using Node.js fs module. Works in both Node.js and Bun.
6
+ */
7
+ import { type FileSystemBackend, ShovelDirectoryHandle } from "./index.js";
8
+ /**
9
+ * Node.js storage backend using node:fs
10
+ */
11
+ export declare class NodeFSBackend implements FileSystemBackend {
12
+ #private;
13
+ constructor(rootPath: string);
14
+ stat(filePath: string): Promise<{
15
+ kind: "file" | "directory";
16
+ } | null>;
17
+ readFile(filePath: string): Promise<{
18
+ content: Uint8Array;
19
+ lastModified?: number;
20
+ }>;
21
+ writeFile(filePath: string, data: Uint8Array): Promise<void>;
22
+ listDir(dirPath: string): Promise<Array<{
23
+ name: string;
24
+ kind: "file" | "directory";
25
+ }>>;
26
+ createDir(dirPath: string): Promise<void>;
27
+ remove(entryPath: string, recursive?: boolean): Promise<void>;
28
+ }
29
+ /**
30
+ * Node.js directory using node:fs - root entry point for local filesystem
31
+ * Extends ShovelDirectoryHandle with "/" as root path
32
+ */
33
+ export declare class NodeFSDirectory extends ShovelDirectoryHandle {
34
+ #private;
35
+ /**
36
+ * Create a NodeFSDirectory
37
+ * @param name - Directory name (used for display)
38
+ * @param options - Options object containing the filesystem path
39
+ * @param options.path - The actual filesystem path to use as root
40
+ */
41
+ constructor(name: string, options?: {
42
+ path?: string;
43
+ });
44
+ get name(): string;
45
+ }
@@ -1,9 +1,12 @@
1
- /// <reference types="./node.d.ts" />
2
- // src/node.ts
1
+ /// <reference types="./node-fs.d.ts" />
2
+ // src/node-fs.ts
3
3
  import { ShovelDirectoryHandle } from "./index.js";
4
4
  import * as FS from "fs/promises";
5
5
  import * as Path from "path";
6
- var NodeFileSystemBackend = class {
6
+ function isErrnoException(error) {
7
+ return error instanceof Error && "code" in error;
8
+ }
9
+ var NodeFSBackend = class {
7
10
  #rootPath;
8
11
  constructor(rootPath) {
9
12
  this.#rootPath = rootPath;
@@ -20,7 +23,7 @@ var NodeFileSystemBackend = class {
20
23
  return null;
21
24
  }
22
25
  } catch (error) {
23
- if (error.code === "ENOENT") {
26
+ if (isErrnoException(error) && error.code === "ENOENT") {
24
27
  return null;
25
28
  }
26
29
  throw error;
@@ -38,7 +41,7 @@ var NodeFileSystemBackend = class {
38
41
  lastModified: stats.mtimeMs
39
42
  };
40
43
  } catch (error) {
41
- if (error.code === "ENOENT") {
44
+ if (isErrnoException(error) && error.code === "ENOENT") {
42
45
  throw new DOMException("File not found", "NotFoundError");
43
46
  }
44
47
  throw error;
@@ -70,7 +73,7 @@ var NodeFileSystemBackend = class {
70
73
  }
71
74
  return results;
72
75
  } catch (error) {
73
- if (error.code === "ENOENT") {
76
+ if (isErrnoException(error) && error.code === "ENOENT") {
74
77
  throw new DOMException("Directory not found", "NotFoundError");
75
78
  }
76
79
  throw error;
@@ -108,7 +111,7 @@ var NodeFileSystemBackend = class {
108
111
  }
109
112
  }
110
113
  } catch (error) {
111
- if (error.code === "ENOENT") {
114
+ if (isErrnoException(error) && error.code === "ENOENT") {
112
115
  throw new DOMException("Entry not found", "NotFoundError");
113
116
  }
114
117
  throw error;
@@ -135,10 +138,17 @@ var NodeFileSystemBackend = class {
135
138
  return resolvedPath;
136
139
  }
137
140
  };
138
- var NodeBucket = class extends ShovelDirectoryHandle {
141
+ var NodeFSDirectory = class extends ShovelDirectoryHandle {
139
142
  #rootPath;
140
- constructor(rootPath) {
141
- super(new NodeFileSystemBackend(rootPath), "/");
143
+ /**
144
+ * Create a NodeFSDirectory
145
+ * @param name - Directory name (used for display)
146
+ * @param options - Options object containing the filesystem path
147
+ * @param options.path - The actual filesystem path to use as root
148
+ */
149
+ constructor(name, options) {
150
+ const rootPath = options?.path ?? name;
151
+ super(new NodeFSBackend(rootPath), "/");
142
152
  this.#rootPath = rootPath;
143
153
  }
144
154
  // Override name to use the directory basename instead of "/"
@@ -147,6 +157,6 @@ var NodeBucket = class extends ShovelDirectoryHandle {
147
157
  }
148
158
  };
149
159
  export {
150
- NodeBucket,
151
- NodeFileSystemBackend
160
+ NodeFSBackend,
161
+ NodeFSDirectory
152
162
  };
package/src/node.d.ts DELETED
@@ -1,37 +0,0 @@
1
- /**
2
- * Node.js filesystem implementation
3
- *
4
- * Provides NodeBucket (root) and NodeFileSystemBackend for storage operations
5
- * using Node.js fs module.
6
- */
7
- import { type FileSystemBackend, ShovelDirectoryHandle } from "./index.js";
8
- /**
9
- * Node.js storage backend that implements FileSystemBackend
10
- */
11
- export declare class NodeFileSystemBackend implements FileSystemBackend {
12
- #private;
13
- constructor(rootPath: string);
14
- stat(filePath: string): Promise<{
15
- kind: "file" | "directory";
16
- } | null>;
17
- readFile(filePath: string): Promise<{
18
- content: Uint8Array;
19
- lastModified?: number;
20
- }>;
21
- writeFile(filePath: string, data: Uint8Array): Promise<void>;
22
- listDir(dirPath: string): Promise<Array<{
23
- name: string;
24
- kind: "file" | "directory";
25
- }>>;
26
- createDir(dirPath: string): Promise<void>;
27
- remove(entryPath: string, recursive?: boolean): Promise<void>;
28
- }
29
- /**
30
- * Node bucket - root entry point for Node.js filesystem
31
- * Extends ShovelDirectoryHandle with "/" as root path
32
- */
33
- export declare class NodeBucket extends ShovelDirectoryHandle {
34
- #private;
35
- constructor(rootPath: string);
36
- get name(): string;
37
- }