@b9g/filesystem 0.1.7 → 0.1.8
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 +8 -8
- package/package.json +7 -7
- package/src/bun-s3.d.ts +6 -6
- package/src/bun-s3.js +5 -7
- package/src/index.d.ts +33 -38
- package/src/index.js +50 -38
- package/src/memory.d.ts +7 -7
- package/src/memory.js +32 -13
- package/src/node-fs.d.ts +45 -0
- package/src/{node.js → node-fs.js} +22 -12
- package/src/node.d.ts +0 -37
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
|
-
- `
|
|
254
|
+
- `CustomDirectoryStorage` - Directory storage with custom backend factories
|
|
255
255
|
|
|
256
256
|
### Types
|
|
257
257
|
|
|
258
|
-
- `
|
|
259
|
-
- `
|
|
260
|
-
- `
|
|
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
|
-
###
|
|
267
|
+
### DirectoryStorage
|
|
268
268
|
|
|
269
269
|
```typescript
|
|
270
|
-
interface
|
|
270
|
+
interface DirectoryStorage {
|
|
271
271
|
open(name: string): Promise<FileSystemDirectoryHandle>;
|
|
272
272
|
}
|
|
273
273
|
|
|
274
|
-
class
|
|
275
|
-
register(name: string, factory:
|
|
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,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@b9g/filesystem",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Universal File System Access API implementations for all platforms",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"dependencies": {
|
|
@@ -50,13 +50,13 @@
|
|
|
50
50
|
"types": "./src/memory.d.ts",
|
|
51
51
|
"import": "./src/memory.js"
|
|
52
52
|
},
|
|
53
|
-
"./node": {
|
|
54
|
-
"types": "./src/node.d.ts",
|
|
55
|
-
"import": "./src/node.js"
|
|
53
|
+
"./node-fs": {
|
|
54
|
+
"types": "./src/node-fs.d.ts",
|
|
55
|
+
"import": "./src/node-fs.js"
|
|
56
56
|
},
|
|
57
|
-
"./node.js": {
|
|
58
|
-
"types": "./src/node.d.ts",
|
|
59
|
-
"import": "./src/node.js"
|
|
57
|
+
"./node-fs.js": {
|
|
58
|
+
"types": "./src/node-fs.d.ts",
|
|
59
|
+
"import": "./src/node-fs.js"
|
|
60
60
|
},
|
|
61
61
|
"./package.json": "./package.json"
|
|
62
62
|
}
|
package/src/bun-s3.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Bun S3 filesystem implementation
|
|
3
3
|
*
|
|
4
|
-
* Provides
|
|
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
|
|
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
|
|
38
|
-
* const
|
|
39
|
-
* return new
|
|
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
|
|
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
|
@@ -154,8 +154,7 @@ var S3FileSystemBackend = class {
|
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
} catch (error) {
|
|
157
|
-
if (error instanceof DOMException)
|
|
158
|
-
throw error;
|
|
157
|
+
if (error instanceof DOMException) throw error;
|
|
159
158
|
throw new DOMException("Entry not found", "NotFoundError");
|
|
160
159
|
}
|
|
161
160
|
}
|
|
@@ -179,7 +178,7 @@ var S3FileSystemBackend = class {
|
|
|
179
178
|
return this.#prefix ? `${this.#prefix}/${cleanPath}` : cleanPath;
|
|
180
179
|
}
|
|
181
180
|
};
|
|
182
|
-
var
|
|
181
|
+
var S3Directory = class _S3Directory {
|
|
183
182
|
kind;
|
|
184
183
|
name;
|
|
185
184
|
#backend;
|
|
@@ -257,9 +256,8 @@ var S3Bucket = class _S3Bucket {
|
|
|
257
256
|
return this.entries();
|
|
258
257
|
}
|
|
259
258
|
async isSameEntry(other) {
|
|
260
|
-
if (other.kind !== "directory")
|
|
261
|
-
|
|
262
|
-
return other instanceof _S3Bucket && other.name === this.name;
|
|
259
|
+
if (other.kind !== "directory") return false;
|
|
260
|
+
return other instanceof _S3Directory && other.name === this.name;
|
|
263
261
|
}
|
|
264
262
|
async queryPermission() {
|
|
265
263
|
return "granted";
|
|
@@ -269,6 +267,6 @@ var S3Bucket = class _S3Bucket {
|
|
|
269
267
|
}
|
|
270
268
|
};
|
|
271
269
|
export {
|
|
272
|
-
|
|
270
|
+
S3Directory,
|
|
273
271
|
S3FileSystemBackend
|
|
274
272
|
};
|
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(
|
|
88
|
-
requestPermission(
|
|
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
|
-
*
|
|
138
|
-
* This could become a future web standard
|
|
133
|
+
* Directory storage interface - parallels CacheStorage for filesystem access
|
|
139
134
|
*/
|
|
140
|
-
export interface
|
|
135
|
+
export interface DirectoryStorage {
|
|
141
136
|
/**
|
|
142
|
-
* Open a named
|
|
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
|
|
142
|
+
* Check if a named directory exists
|
|
148
143
|
*/
|
|
149
144
|
has(name: string): Promise<boolean>;
|
|
150
145
|
/**
|
|
151
|
-
* Delete a named
|
|
146
|
+
* Delete a named directory and all its contents
|
|
152
147
|
*/
|
|
153
148
|
delete(name: string): Promise<boolean>;
|
|
154
149
|
/**
|
|
155
|
-
* List all available
|
|
150
|
+
* List all available directory names
|
|
156
151
|
*/
|
|
157
152
|
keys(): Promise<string[]>;
|
|
158
153
|
}
|
|
159
154
|
/**
|
|
160
|
-
* Factory function type for creating
|
|
161
|
-
* @param name
|
|
162
|
-
* @returns FileSystemDirectoryHandle
|
|
155
|
+
* Factory function type for creating directories
|
|
156
|
+
* @param name Directory name to create
|
|
157
|
+
* @returns FileSystemDirectoryHandle instance
|
|
163
158
|
*/
|
|
164
|
-
export type
|
|
159
|
+
export type DirectoryFactory = (name: string) => FileSystemDirectoryHandle | Promise<FileSystemDirectoryHandle>;
|
|
165
160
|
/**
|
|
166
|
-
* Custom
|
|
161
|
+
* Custom directory storage with factory-based directory creation
|
|
167
162
|
*
|
|
168
|
-
* Provides a registry of named
|
|
169
|
-
* with lazy instantiation and singleton behavior per
|
|
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
|
|
168
|
+
export declare class CustomDirectoryStorage {
|
|
174
169
|
#private;
|
|
175
170
|
/**
|
|
176
|
-
* @param factory Function that creates
|
|
171
|
+
* @param factory Function that creates directory instances by name
|
|
177
172
|
*/
|
|
178
|
-
constructor(factory:
|
|
173
|
+
constructor(factory: DirectoryFactory);
|
|
179
174
|
/**
|
|
180
|
-
* Open a named
|
|
175
|
+
* Open a named directory - creates if it doesn't exist
|
|
181
176
|
*
|
|
182
|
-
* @param name
|
|
183
|
-
* @returns FileSystemDirectoryHandle for the
|
|
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
|
|
182
|
+
* Check if a named directory exists
|
|
188
183
|
*
|
|
189
|
-
* @param name
|
|
190
|
-
* @returns true if
|
|
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
|
|
189
|
+
* Delete a named directory
|
|
195
190
|
*
|
|
196
|
-
* @param name
|
|
197
|
-
* @returns true if
|
|
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
|
|
196
|
+
* List all opened directory names
|
|
202
197
|
*
|
|
203
|
-
* @returns Array of
|
|
198
|
+
* @returns Array of directory names
|
|
204
199
|
*/
|
|
205
200
|
keys(): Promise<string[]>;
|
|
206
201
|
/**
|
|
207
|
-
* Get statistics about opened
|
|
202
|
+
* Get statistics about opened directories (non-standard utility method)
|
|
208
203
|
*
|
|
209
|
-
* @returns Object with
|
|
204
|
+
* @returns Object with directory statistics
|
|
210
205
|
*/
|
|
211
206
|
getStats(): {
|
|
212
207
|
openInstances: number;
|
|
213
|
-
|
|
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
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
63
|
+
throw new DOMException(
|
|
64
|
+
"Invalid data type for write",
|
|
65
|
+
"NotSupportedError"
|
|
66
|
+
);
|
|
49
67
|
}
|
|
50
68
|
} finally {
|
|
51
69
|
writer.releaseLock();
|
|
@@ -78,36 +96,30 @@ var ShovelHandle = class _ShovelHandle {
|
|
|
78
96
|
return this.#backend;
|
|
79
97
|
}
|
|
80
98
|
async isSameEntry(other) {
|
|
81
|
-
if (other.kind !== this.kind)
|
|
82
|
-
|
|
83
|
-
if (!(other instanceof _ShovelHandle))
|
|
84
|
-
return false;
|
|
99
|
+
if (other.kind !== this.kind) return false;
|
|
100
|
+
if (!(other instanceof _ShovelHandle)) return false;
|
|
85
101
|
return this.path === other.path;
|
|
86
102
|
}
|
|
87
|
-
async queryPermission(
|
|
88
|
-
const _mode = descriptor?.mode || "read";
|
|
103
|
+
async queryPermission(_descriptor) {
|
|
89
104
|
return "granted";
|
|
90
105
|
}
|
|
91
|
-
async requestPermission(
|
|
92
|
-
const _mode = descriptor?.mode || "read";
|
|
106
|
+
async requestPermission(_descriptor) {
|
|
93
107
|
return "granted";
|
|
94
108
|
}
|
|
95
109
|
/**
|
|
96
110
|
* Validates that a name is actually a name and not a path
|
|
97
111
|
* The File System Access API only accepts names, not paths
|
|
112
|
+
* WPT expects TypeError for invalid names
|
|
98
113
|
*/
|
|
99
114
|
validateName(name) {
|
|
100
115
|
if (!name || name.trim() === "") {
|
|
101
|
-
throw new
|
|
116
|
+
throw new TypeError("Name cannot be empty");
|
|
102
117
|
}
|
|
103
118
|
if (name.includes("/") || name.includes("\\")) {
|
|
104
|
-
throw new
|
|
105
|
-
"Name cannot contain path separators",
|
|
106
|
-
"NotAllowedError"
|
|
107
|
-
);
|
|
119
|
+
throw new TypeError("Name cannot contain path separators");
|
|
108
120
|
}
|
|
109
121
|
if (name === "." || name === "..") {
|
|
110
|
-
throw new
|
|
122
|
+
throw new TypeError("Name cannot be '.' or '..'");
|
|
111
123
|
}
|
|
112
124
|
}
|
|
113
125
|
};
|
|
@@ -249,45 +261,45 @@ var ShovelDirectoryHandle = class _ShovelDirectoryHandle extends ShovelHandle {
|
|
|
249
261
|
return `${base}/${name}`;
|
|
250
262
|
}
|
|
251
263
|
};
|
|
252
|
-
var
|
|
264
|
+
var CustomDirectoryStorage = class {
|
|
253
265
|
#instances;
|
|
254
266
|
#factory;
|
|
255
267
|
/**
|
|
256
|
-
* @param factory Function that creates
|
|
268
|
+
* @param factory Function that creates directory instances by name
|
|
257
269
|
*/
|
|
258
270
|
constructor(factory) {
|
|
259
271
|
this.#instances = /* @__PURE__ */ new Map();
|
|
260
272
|
this.#factory = factory;
|
|
261
273
|
}
|
|
262
274
|
/**
|
|
263
|
-
* Open a named
|
|
275
|
+
* Open a named directory - creates if it doesn't exist
|
|
264
276
|
*
|
|
265
|
-
* @param name
|
|
266
|
-
* @returns FileSystemDirectoryHandle for the
|
|
277
|
+
* @param name Directory name (e.g., 'tmp', 'dist', 'uploads')
|
|
278
|
+
* @returns FileSystemDirectoryHandle for the directory
|
|
267
279
|
*/
|
|
268
280
|
async open(name) {
|
|
269
281
|
const existing = this.#instances.get(name);
|
|
270
282
|
if (existing) {
|
|
271
283
|
return existing;
|
|
272
284
|
}
|
|
273
|
-
const
|
|
274
|
-
this.#instances.set(name,
|
|
275
|
-
return
|
|
285
|
+
const dir = await this.#factory(name);
|
|
286
|
+
this.#instances.set(name, dir);
|
|
287
|
+
return dir;
|
|
276
288
|
}
|
|
277
289
|
/**
|
|
278
|
-
* Check if a named
|
|
290
|
+
* Check if a named directory exists
|
|
279
291
|
*
|
|
280
|
-
* @param name
|
|
281
|
-
* @returns true if
|
|
292
|
+
* @param name Directory name to check
|
|
293
|
+
* @returns true if directory has been opened
|
|
282
294
|
*/
|
|
283
295
|
async has(name) {
|
|
284
296
|
return this.#instances.has(name);
|
|
285
297
|
}
|
|
286
298
|
/**
|
|
287
|
-
* Delete a named
|
|
299
|
+
* Delete a named directory
|
|
288
300
|
*
|
|
289
|
-
* @param name
|
|
290
|
-
* @returns true if
|
|
301
|
+
* @param name Directory name to delete
|
|
302
|
+
* @returns true if directory was deleted, false if it didn't exist
|
|
291
303
|
*/
|
|
292
304
|
async delete(name) {
|
|
293
305
|
const instance = this.#instances.get(name);
|
|
@@ -298,27 +310,27 @@ var CustomBucketStorage = class {
|
|
|
298
310
|
return false;
|
|
299
311
|
}
|
|
300
312
|
/**
|
|
301
|
-
* List all opened
|
|
313
|
+
* List all opened directory names
|
|
302
314
|
*
|
|
303
|
-
* @returns Array of
|
|
315
|
+
* @returns Array of directory names
|
|
304
316
|
*/
|
|
305
317
|
async keys() {
|
|
306
318
|
return Array.from(this.#instances.keys());
|
|
307
319
|
}
|
|
308
320
|
/**
|
|
309
|
-
* Get statistics about opened
|
|
321
|
+
* Get statistics about opened directories (non-standard utility method)
|
|
310
322
|
*
|
|
311
|
-
* @returns Object with
|
|
323
|
+
* @returns Object with directory statistics
|
|
312
324
|
*/
|
|
313
325
|
getStats() {
|
|
314
326
|
return {
|
|
315
327
|
openInstances: this.#instances.size,
|
|
316
|
-
|
|
328
|
+
directoryNames: Array.from(this.#instances.keys())
|
|
317
329
|
};
|
|
318
330
|
}
|
|
319
331
|
};
|
|
320
332
|
export {
|
|
321
|
-
|
|
333
|
+
CustomDirectoryStorage,
|
|
322
334
|
ShovelDirectoryHandle,
|
|
323
335
|
ShovelFileHandle,
|
|
324
336
|
ShovelHandle
|
package/src/memory.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* In-memory filesystem implementation
|
|
3
3
|
*
|
|
4
|
-
* Provides
|
|
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
|
|
20
|
+
interface MemoryDirectoryData {
|
|
21
21
|
name: string;
|
|
22
22
|
files: Map<string, MemoryFile>;
|
|
23
|
-
directories: Map<string,
|
|
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:
|
|
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
|
|
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
|
|
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
|
@@ -11,8 +11,7 @@ var MemoryFileSystemBackend = class {
|
|
|
11
11
|
}
|
|
12
12
|
async stat(path) {
|
|
13
13
|
const entry = this.#resolvePath(path);
|
|
14
|
-
if (!entry)
|
|
15
|
-
return null;
|
|
14
|
+
if (!entry) return null;
|
|
16
15
|
if ("content" in entry) {
|
|
17
16
|
return { kind: "file" };
|
|
18
17
|
} else {
|
|
@@ -115,17 +114,14 @@ var MemoryFileSystemBackend = class {
|
|
|
115
114
|
let current = this.#root;
|
|
116
115
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
117
116
|
const nextDir = current.directories.get(parts[i]);
|
|
118
|
-
if (!nextDir)
|
|
119
|
-
return null;
|
|
117
|
+
if (!nextDir) return null;
|
|
120
118
|
current = nextDir;
|
|
121
119
|
}
|
|
122
120
|
const finalName = parts[parts.length - 1];
|
|
123
121
|
const file = current.files.get(finalName);
|
|
124
|
-
if (file)
|
|
125
|
-
return file;
|
|
122
|
+
if (file) return file;
|
|
126
123
|
const dir = current.directories.get(finalName);
|
|
127
|
-
if (dir)
|
|
128
|
-
return dir;
|
|
124
|
+
if (dir) return dir;
|
|
129
125
|
return null;
|
|
130
126
|
}
|
|
131
127
|
#resolveParent(path) {
|
|
@@ -145,7 +141,7 @@ var MemoryFileSystemBackend = class {
|
|
|
145
141
|
return { parentDir: current, name };
|
|
146
142
|
}
|
|
147
143
|
};
|
|
148
|
-
var
|
|
144
|
+
var MemoryDirectory = class _MemoryDirectory {
|
|
149
145
|
kind;
|
|
150
146
|
name;
|
|
151
147
|
#backend;
|
|
@@ -160,6 +156,15 @@ var MemoryBucket = class _MemoryBucket {
|
|
|
160
156
|
this.#backend = new MemoryFileSystemBackend(root);
|
|
161
157
|
}
|
|
162
158
|
async getFileHandle(name, options) {
|
|
159
|
+
if (!name || name.trim() === "") {
|
|
160
|
+
throw new TypeError("Name cannot be empty");
|
|
161
|
+
}
|
|
162
|
+
if (name.includes("/") || name.includes("\\")) {
|
|
163
|
+
throw new TypeError("Name cannot contain path separators");
|
|
164
|
+
}
|
|
165
|
+
if (name === "." || name === "..") {
|
|
166
|
+
throw new TypeError("Name cannot be '.' or '..'");
|
|
167
|
+
}
|
|
163
168
|
const filePath = `/${name}`;
|
|
164
169
|
const stat = await this.#backend.stat(filePath);
|
|
165
170
|
if (!stat && options?.create) {
|
|
@@ -175,6 +180,15 @@ var MemoryBucket = class _MemoryBucket {
|
|
|
175
180
|
return new ShovelFileHandle(this.#backend, filePath);
|
|
176
181
|
}
|
|
177
182
|
async getDirectoryHandle(name, options) {
|
|
183
|
+
if (!name || name.trim() === "") {
|
|
184
|
+
throw new TypeError("Name cannot be empty");
|
|
185
|
+
}
|
|
186
|
+
if (name.includes("/") || name.includes("\\")) {
|
|
187
|
+
throw new TypeError("Name cannot contain path separators");
|
|
188
|
+
}
|
|
189
|
+
if (name === "." || name === "..") {
|
|
190
|
+
throw new TypeError("Name cannot be '.' or '..'");
|
|
191
|
+
}
|
|
178
192
|
const dirPath = `/${name}`;
|
|
179
193
|
const stat = await this.#backend.stat(dirPath);
|
|
180
194
|
if (!stat && options?.create) {
|
|
@@ -194,6 +208,12 @@ var MemoryBucket = class _MemoryBucket {
|
|
|
194
208
|
await this.#backend.remove(entryPath, options?.recursive);
|
|
195
209
|
}
|
|
196
210
|
async resolve(possibleDescendant) {
|
|
211
|
+
if (possibleDescendant instanceof _MemoryDirectory) {
|
|
212
|
+
if (await this.isSameEntry(possibleDescendant)) {
|
|
213
|
+
return [];
|
|
214
|
+
}
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
197
217
|
if (!(possibleDescendant instanceof ShovelDirectoryHandle || possibleDescendant instanceof ShovelFileHandle)) {
|
|
198
218
|
return null;
|
|
199
219
|
}
|
|
@@ -228,9 +248,8 @@ var MemoryBucket = class _MemoryBucket {
|
|
|
228
248
|
return this.entries();
|
|
229
249
|
}
|
|
230
250
|
async isSameEntry(other) {
|
|
231
|
-
if (other.kind !== "directory")
|
|
232
|
-
|
|
233
|
-
return other instanceof _MemoryBucket && other.name === this.name;
|
|
251
|
+
if (other.kind !== "directory") return false;
|
|
252
|
+
return other instanceof _MemoryDirectory && other.name === this.name;
|
|
234
253
|
}
|
|
235
254
|
async queryPermission() {
|
|
236
255
|
return "granted";
|
|
@@ -240,6 +259,6 @@ var MemoryBucket = class _MemoryBucket {
|
|
|
240
259
|
}
|
|
241
260
|
};
|
|
242
261
|
export {
|
|
243
|
-
|
|
262
|
+
MemoryDirectory,
|
|
244
263
|
MemoryFileSystemBackend
|
|
245
264
|
};
|
package/src/node-fs.d.ts
ADDED
|
@@ -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
|
-
|
|
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
|
|
141
|
+
var NodeFSDirectory = class extends ShovelDirectoryHandle {
|
|
139
142
|
#rootPath;
|
|
140
|
-
|
|
141
|
-
|
|
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
|
-
|
|
151
|
-
|
|
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
|
-
}
|