@jisan901/fs-browser 1.0.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/LICENSE +21 -0
- package/README.md +620 -0
- package/bin/withfs.js +276 -0
- package/package.json +67 -0
- package/plugin/fs-handlers.js +419 -0
- package/plugin/vite.js +67 -0
- package/src/index.d.ts +288 -0
- package/src/index.js +402 -0
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fs:browser - Browser-compatible filesystem API
|
|
3
|
+
* TypeScript Declaration File
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
declare module 'fs:browser' {
|
|
7
|
+
/**
|
|
8
|
+
* Configuration options for fs-browser
|
|
9
|
+
*/
|
|
10
|
+
export interface FsConfig {
|
|
11
|
+
apiBase?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* File encoding options
|
|
16
|
+
*/
|
|
17
|
+
export type BufferEncoding =
|
|
18
|
+
| 'ascii'
|
|
19
|
+
| 'utf8'
|
|
20
|
+
| 'utf-8'
|
|
21
|
+
| 'utf16le'
|
|
22
|
+
| 'ucs2'
|
|
23
|
+
| 'ucs-2'
|
|
24
|
+
| 'base64'
|
|
25
|
+
| 'base64url'
|
|
26
|
+
| 'latin1'
|
|
27
|
+
| 'binary'
|
|
28
|
+
| 'hex';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Options for file operations
|
|
32
|
+
*/
|
|
33
|
+
export interface FileOptions {
|
|
34
|
+
encoding?: BufferEncoding | null;
|
|
35
|
+
flag?: string;
|
|
36
|
+
mode?: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Options for directory operations
|
|
41
|
+
*/
|
|
42
|
+
export interface MkdirOptions {
|
|
43
|
+
recursive?: boolean;
|
|
44
|
+
mode?: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Options for readdir
|
|
49
|
+
*/
|
|
50
|
+
export interface ReaddirOptions {
|
|
51
|
+
encoding?: BufferEncoding | null;
|
|
52
|
+
withFileTypes?: boolean;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Options for rm/rmdir operations
|
|
57
|
+
*/
|
|
58
|
+
export interface RmOptions {
|
|
59
|
+
recursive?: boolean;
|
|
60
|
+
force?: boolean;
|
|
61
|
+
maxRetries?: number;
|
|
62
|
+
retryDelay?: number;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Directory entry with type information
|
|
67
|
+
*/
|
|
68
|
+
export interface Dirent {
|
|
69
|
+
name: string;
|
|
70
|
+
isFile(): boolean;
|
|
71
|
+
isDirectory(): boolean;
|
|
72
|
+
isSymbolicLink(): boolean;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* File statistics
|
|
77
|
+
*/
|
|
78
|
+
export interface Stats {
|
|
79
|
+
isFile(): boolean;
|
|
80
|
+
isDirectory(): boolean;
|
|
81
|
+
isSymbolicLink(): boolean;
|
|
82
|
+
mode: number;
|
|
83
|
+
size: number;
|
|
84
|
+
atimeMs: number;
|
|
85
|
+
mtimeMs: number;
|
|
86
|
+
ctimeMs: number;
|
|
87
|
+
birthtimeMs: number;
|
|
88
|
+
atime: Date;
|
|
89
|
+
mtime: Date;
|
|
90
|
+
ctime: Date;
|
|
91
|
+
birthtime: Date;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Read file contents
|
|
96
|
+
* @param path - File path
|
|
97
|
+
* @param options - Encoding string or options object
|
|
98
|
+
* @returns File contents as string or Buffer
|
|
99
|
+
*/
|
|
100
|
+
export function readFile(
|
|
101
|
+
path: string,
|
|
102
|
+
options?: BufferEncoding | FileOptions
|
|
103
|
+
): Promise<string>;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Write data to file
|
|
107
|
+
* @param path - File path
|
|
108
|
+
* @param data - Data to write (string, Buffer, Blob, ArrayBuffer, TypedArray, or object)
|
|
109
|
+
* @param options - Encoding string or options object
|
|
110
|
+
*/
|
|
111
|
+
export function writeFile(
|
|
112
|
+
path: string,
|
|
113
|
+
data: string | Buffer | Blob | ArrayBuffer | ArrayBufferView | object,
|
|
114
|
+
options?: BufferEncoding | FileOptions
|
|
115
|
+
): Promise<void>;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Append data to file
|
|
119
|
+
* @param path - File path
|
|
120
|
+
* @param data - Data to append (string, Buffer, Blob, ArrayBuffer, TypedArray, or object)
|
|
121
|
+
* @param options - Encoding string or options object
|
|
122
|
+
*/
|
|
123
|
+
export function appendFile(
|
|
124
|
+
path: string,
|
|
125
|
+
data: string | Buffer | Blob | ArrayBuffer | ArrayBufferView | object,
|
|
126
|
+
options?: BufferEncoding | FileOptions
|
|
127
|
+
): Promise<void>;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Copy file
|
|
131
|
+
* @param src - Source path
|
|
132
|
+
* @param dest - Destination path
|
|
133
|
+
* @param flags - Copy flags (default: 0)
|
|
134
|
+
*/
|
|
135
|
+
export function copyFile(
|
|
136
|
+
src: string,
|
|
137
|
+
dest: string,
|
|
138
|
+
flags?: number
|
|
139
|
+
): Promise<void>;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Read directory contents
|
|
143
|
+
* @param path - Directory path
|
|
144
|
+
* @param options - Options object
|
|
145
|
+
* @returns Array of filenames or Dirent objects
|
|
146
|
+
*/
|
|
147
|
+
export function readdir(
|
|
148
|
+
path: string,
|
|
149
|
+
options?: { withFileTypes?: false } & ReaddirOptions
|
|
150
|
+
): Promise<string[]>;
|
|
151
|
+
export function readdir(
|
|
152
|
+
path: string,
|
|
153
|
+
options: { withFileTypes: true } & ReaddirOptions
|
|
154
|
+
): Promise<Dirent[]>;
|
|
155
|
+
export function readdir(
|
|
156
|
+
path: string,
|
|
157
|
+
options?: ReaddirOptions
|
|
158
|
+
): Promise<string[] | Dirent[]>;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Create directory
|
|
162
|
+
* @param path - Directory path
|
|
163
|
+
* @param options - Options object
|
|
164
|
+
*/
|
|
165
|
+
export function mkdir(
|
|
166
|
+
path: string,
|
|
167
|
+
options?: MkdirOptions
|
|
168
|
+
): Promise<void>;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Remove directory
|
|
172
|
+
* @param path - Directory path
|
|
173
|
+
* @param options - Options object
|
|
174
|
+
*/
|
|
175
|
+
export function rmdir(
|
|
176
|
+
path: string,
|
|
177
|
+
options?: RmOptions
|
|
178
|
+
): Promise<void>;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Remove file or directory
|
|
182
|
+
* @param path - Path to remove
|
|
183
|
+
* @param options - Options object
|
|
184
|
+
*/
|
|
185
|
+
export function rm(
|
|
186
|
+
path: string,
|
|
187
|
+
options?: RmOptions
|
|
188
|
+
): Promise<void>;
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Rename or move file/directory
|
|
192
|
+
* @param oldPath - Old path
|
|
193
|
+
* @param newPath - New path
|
|
194
|
+
*/
|
|
195
|
+
export function rename(
|
|
196
|
+
oldPath: string,
|
|
197
|
+
newPath: string
|
|
198
|
+
): Promise<void>;
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Delete file
|
|
202
|
+
* @param path - File path
|
|
203
|
+
*/
|
|
204
|
+
export function unlink(path: string): Promise<void>;
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Get file/directory stats
|
|
208
|
+
* @param path - Path
|
|
209
|
+
* @returns File statistics
|
|
210
|
+
*/
|
|
211
|
+
export function stat(path: string): Promise<Stats>;
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Get file/directory stats (doesn't follow symlinks)
|
|
215
|
+
* @param path - Path
|
|
216
|
+
* @returns File statistics
|
|
217
|
+
*/
|
|
218
|
+
export function lstat(path: string): Promise<Stats>;
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Get canonical path
|
|
222
|
+
* @param path - Path
|
|
223
|
+
* @returns Resolved path
|
|
224
|
+
*/
|
|
225
|
+
export function realpath(path: string): Promise<string>;
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Read symbolic link
|
|
229
|
+
* @param path - Link path
|
|
230
|
+
* @returns Link target path
|
|
231
|
+
*/
|
|
232
|
+
export function readlink(path: string): Promise<string>;
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Check if file exists (convenience method)
|
|
236
|
+
* @param path - Path
|
|
237
|
+
* @returns true if exists, false otherwise
|
|
238
|
+
*/
|
|
239
|
+
export function exists(path: string): Promise<boolean>;
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Configure the fs-browser module
|
|
243
|
+
* @param options - Configuration options
|
|
244
|
+
* @returns Configured fs module with all methods
|
|
245
|
+
*/
|
|
246
|
+
export function configure(options: FsConfig): {
|
|
247
|
+
readFile: typeof readFile;
|
|
248
|
+
writeFile: typeof writeFile;
|
|
249
|
+
appendFile: typeof appendFile;
|
|
250
|
+
copyFile: typeof copyFile;
|
|
251
|
+
readdir: typeof readdir;
|
|
252
|
+
mkdir: typeof mkdir;
|
|
253
|
+
rmdir: typeof rmdir;
|
|
254
|
+
rm: typeof rm;
|
|
255
|
+
rename: typeof rename;
|
|
256
|
+
unlink: typeof unlink;
|
|
257
|
+
stat: typeof stat;
|
|
258
|
+
lstat: typeof lstat;
|
|
259
|
+
realpath: typeof realpath;
|
|
260
|
+
readlink: typeof readlink;
|
|
261
|
+
exists: typeof exists;
|
|
262
|
+
configure: typeof configure;
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Default export with all methods
|
|
267
|
+
*/
|
|
268
|
+
const fs: {
|
|
269
|
+
readFile: typeof readFile;
|
|
270
|
+
writeFile: typeof writeFile;
|
|
271
|
+
appendFile: typeof appendFile;
|
|
272
|
+
copyFile: typeof copyFile;
|
|
273
|
+
readdir: typeof readdir;
|
|
274
|
+
mkdir: typeof mkdir;
|
|
275
|
+
rmdir: typeof rmdir;
|
|
276
|
+
rm: typeof rm;
|
|
277
|
+
rename: typeof rename;
|
|
278
|
+
unlink: typeof unlink;
|
|
279
|
+
stat: typeof stat;
|
|
280
|
+
lstat: typeof lstat;
|
|
281
|
+
realpath: typeof realpath;
|
|
282
|
+
readlink: typeof readlink;
|
|
283
|
+
exists: typeof exists;
|
|
284
|
+
configure: typeof configure;
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
export default fs;
|
|
288
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fs:browser - Browser-compatible filesystem API
|
|
3
|
+
* Uses fetch to communicate with backend fs API
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
let API_BASE = '/api/fs';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Configure the fs-browser module
|
|
10
|
+
* @param {Object} options - Configuration options
|
|
11
|
+
* @param {string} options.apiBase - Base URL for the fs API
|
|
12
|
+
* @returns {Object} - Configured fs module
|
|
13
|
+
*/
|
|
14
|
+
export function configure(options = {}) {
|
|
15
|
+
if (options.apiBase !== undefined) {
|
|
16
|
+
API_BASE = options.apiBase;
|
|
17
|
+
// Ensure no trailing slash
|
|
18
|
+
if (API_BASE.endsWith('/')) {
|
|
19
|
+
API_BASE = API_BASE.slice(0, -1);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
readFile,
|
|
25
|
+
writeFile,
|
|
26
|
+
appendFile,
|
|
27
|
+
copyFile,
|
|
28
|
+
readdir,
|
|
29
|
+
mkdir,
|
|
30
|
+
rmdir,
|
|
31
|
+
rm,
|
|
32
|
+
rename,
|
|
33
|
+
unlink,
|
|
34
|
+
stat,
|
|
35
|
+
lstat,
|
|
36
|
+
realpath,
|
|
37
|
+
readlink,
|
|
38
|
+
exists,
|
|
39
|
+
configure
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Read file contents
|
|
45
|
+
* @param {string} path - File path
|
|
46
|
+
* @param {string|Object} options - Encoding string or options object
|
|
47
|
+
* @returns {Promise<string|Buffer>}
|
|
48
|
+
*/
|
|
49
|
+
export async function readFile(path, options = 'utf8') {
|
|
50
|
+
const encoding = typeof options === 'string' ? options : options?.encoding || 'utf8';
|
|
51
|
+
const response = await fetch(`${API_BASE}/readFile?path=${encodeURIComponent(path)}&encoding=${encoding}`);
|
|
52
|
+
|
|
53
|
+
if (!response.ok) {
|
|
54
|
+
const error = await response.json();
|
|
55
|
+
throw new Error(error.error?.message || 'Failed to read file');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const { data } = await response.json();
|
|
59
|
+
return data;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Write data to file
|
|
64
|
+
* @param {string} path - File path
|
|
65
|
+
* @param {string|Buffer|Blob} data - Data to write
|
|
66
|
+
* @param {string|Object} options - Encoding string or options object
|
|
67
|
+
* @returns {Promise<void>}
|
|
68
|
+
*/
|
|
69
|
+
export async function writeFile(path, data, options = 'utf8') {
|
|
70
|
+
const encoding = typeof options === 'string' ? options : options?.encoding || 'utf8';
|
|
71
|
+
|
|
72
|
+
let body;
|
|
73
|
+
let contentType;
|
|
74
|
+
|
|
75
|
+
// Handle Blob
|
|
76
|
+
if (data instanceof Blob) {
|
|
77
|
+
body = data;
|
|
78
|
+
contentType = data.type || 'application/octet-stream';
|
|
79
|
+
}
|
|
80
|
+
// Handle ArrayBuffer
|
|
81
|
+
else if (data instanceof ArrayBuffer) {
|
|
82
|
+
body = new Blob([data], { type: 'application/octet-stream' });
|
|
83
|
+
contentType = 'application/octet-stream';
|
|
84
|
+
}
|
|
85
|
+
// Handle Uint8Array or other TypedArray
|
|
86
|
+
else if (ArrayBuffer.isView(data)) {
|
|
87
|
+
body = new Blob([data], { type: 'application/octet-stream' });
|
|
88
|
+
contentType = 'application/octet-stream';
|
|
89
|
+
}
|
|
90
|
+
// Handle string
|
|
91
|
+
else if (typeof data === 'string') {
|
|
92
|
+
body = new Blob([data], { type: 'text/plain' });
|
|
93
|
+
contentType = 'text/plain';
|
|
94
|
+
}
|
|
95
|
+
// Handle object (convert to JSON)
|
|
96
|
+
else if (typeof data === 'object') {
|
|
97
|
+
body = JSON.stringify(data);
|
|
98
|
+
contentType = 'application/json';
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
throw new Error('Unsupported data type');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const response = await fetch(`${API_BASE}/writeFile?path=${encodeURIComponent(path)}`, {
|
|
105
|
+
method: 'POST',
|
|
106
|
+
headers: { 'Content-Type': contentType },
|
|
107
|
+
body
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
if (!response.ok) {
|
|
111
|
+
const error = await response.json();
|
|
112
|
+
throw new Error(error.error?.message || 'Failed to write file');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Append data to file
|
|
118
|
+
* @param {string} path - File path
|
|
119
|
+
* @param {string|Buffer|Blob} data - Data to append
|
|
120
|
+
* @param {string|Object} options - Encoding string or options object
|
|
121
|
+
* @returns {Promise<void>}
|
|
122
|
+
*/
|
|
123
|
+
export async function appendFile(path, data, options = 'utf8') {
|
|
124
|
+
const encoding = typeof options === 'string' ? options : options?.encoding || 'utf8';
|
|
125
|
+
|
|
126
|
+
let body;
|
|
127
|
+
let contentType;
|
|
128
|
+
|
|
129
|
+
if (data instanceof Blob) {
|
|
130
|
+
body = data;
|
|
131
|
+
contentType = data.type || 'application/octet-stream';
|
|
132
|
+
}
|
|
133
|
+
else if (data instanceof ArrayBuffer) {
|
|
134
|
+
body = new Blob([data], { type: 'application/octet-stream' });
|
|
135
|
+
contentType = 'application/octet-stream';
|
|
136
|
+
}
|
|
137
|
+
else if (ArrayBuffer.isView(data)) {
|
|
138
|
+
body = new Blob([data], { type: 'application/octet-stream' });
|
|
139
|
+
contentType = 'application/octet-stream';
|
|
140
|
+
}
|
|
141
|
+
else if (typeof data === 'string') {
|
|
142
|
+
body = new Blob([data], { type: 'text/plain' });
|
|
143
|
+
contentType = 'text/plain';
|
|
144
|
+
}
|
|
145
|
+
else if (typeof data === 'object') {
|
|
146
|
+
body = JSON.stringify(data);
|
|
147
|
+
contentType = 'application/json';
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
throw new Error('Unsupported data type');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const response = await fetch(`${API_BASE}/appendFile?path=${encodeURIComponent(path)}`, {
|
|
154
|
+
method: 'POST',
|
|
155
|
+
headers: { 'Content-Type': contentType },
|
|
156
|
+
body
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
if (!response.ok) {
|
|
160
|
+
const error = await response.json();
|
|
161
|
+
throw new Error(error.error?.message || 'Failed to append file');
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Copy file
|
|
167
|
+
* @param {string} src - Source path
|
|
168
|
+
* @param {string} dest - Destination path
|
|
169
|
+
* @param {number} flags - Copy flags
|
|
170
|
+
* @returns {Promise<void>}
|
|
171
|
+
*/
|
|
172
|
+
export async function copyFile(src, dest, flags = 0) {
|
|
173
|
+
const response = await fetch(`${API_BASE}/copyFile`, {
|
|
174
|
+
method: 'POST',
|
|
175
|
+
headers: { 'Content-Type': 'application/json' },
|
|
176
|
+
body: JSON.stringify({ src, dest, flags })
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
if (!response.ok) {
|
|
180
|
+
const error = await response.json();
|
|
181
|
+
throw new Error(error.error?.message || 'Failed to copy file');
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Read directory contents
|
|
187
|
+
* @param {string} path - Directory path
|
|
188
|
+
* @param {Object} options - Options
|
|
189
|
+
* @returns {Promise<string[]|Dirent[]>}
|
|
190
|
+
*/
|
|
191
|
+
export async function readdir(path, options = {}) {
|
|
192
|
+
const withFileTypes = options.withFileTypes || false;
|
|
193
|
+
const response = await fetch(`${API_BASE}/readdir?path=${encodeURIComponent(path)}&withFileTypes=${withFileTypes}`);
|
|
194
|
+
|
|
195
|
+
if (!response.ok) {
|
|
196
|
+
const error = await response.json();
|
|
197
|
+
throw new Error(error.error?.message || 'Failed to read directory');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const { files } = await response.json();
|
|
201
|
+
return files;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Create directory
|
|
206
|
+
* @param {string} path - Directory path
|
|
207
|
+
* @param {Object} options - Options
|
|
208
|
+
* @returns {Promise<void>}
|
|
209
|
+
*/
|
|
210
|
+
export async function mkdir(path, options = {}) {
|
|
211
|
+
const recursive = options.recursive !== undefined ? options.recursive : true;
|
|
212
|
+
const response = await fetch(`${API_BASE}/mkdir`, {
|
|
213
|
+
method: 'POST',
|
|
214
|
+
headers: { 'Content-Type': 'application/json' },
|
|
215
|
+
body: JSON.stringify({ path, recursive })
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
if (!response.ok) {
|
|
219
|
+
const error = await response.json();
|
|
220
|
+
throw new Error(error.error?.message || 'Failed to create directory');
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Remove directory
|
|
226
|
+
* @param {string} path - Directory path
|
|
227
|
+
* @param {Object} options - Options
|
|
228
|
+
* @returns {Promise<void>}
|
|
229
|
+
*/
|
|
230
|
+
export async function rmdir(path, options = {}) {
|
|
231
|
+
const recursive = options.recursive || false;
|
|
232
|
+
const response = await fetch(`${API_BASE}/rmdir`, {
|
|
233
|
+
method: 'DELETE',
|
|
234
|
+
headers: { 'Content-Type': 'application/json' },
|
|
235
|
+
body: JSON.stringify({ path, recursive })
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
if (!response.ok) {
|
|
239
|
+
const error = await response.json();
|
|
240
|
+
throw new Error(error.error?.message || 'Failed to remove directory');
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Remove file or directory
|
|
246
|
+
* @param {string} path - Path to remove
|
|
247
|
+
* @param {Object} options - Options
|
|
248
|
+
* @returns {Promise<void>}
|
|
249
|
+
*/
|
|
250
|
+
export async function rm(path, options = {}) {
|
|
251
|
+
const recursive = options.recursive || false;
|
|
252
|
+
const force = options.force || false;
|
|
253
|
+
const response = await fetch(`${API_BASE}/rm`, {
|
|
254
|
+
method: 'DELETE',
|
|
255
|
+
headers: { 'Content-Type': 'application/json' },
|
|
256
|
+
body: JSON.stringify({ path, recursive, force })
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
if (!response.ok) {
|
|
260
|
+
const error = await response.json();
|
|
261
|
+
throw new Error(error.error?.message || 'Failed to remove');
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Rename or move file/directory
|
|
267
|
+
* @param {string} oldPath - Old path
|
|
268
|
+
* @param {string} newPath - New path
|
|
269
|
+
* @returns {Promise<void>}
|
|
270
|
+
*/
|
|
271
|
+
export async function rename(oldPath, newPath) {
|
|
272
|
+
const response = await fetch(`${API_BASE}/rename`, {
|
|
273
|
+
method: 'PUT',
|
|
274
|
+
headers: { 'Content-Type': 'application/json' },
|
|
275
|
+
body: JSON.stringify({ oldPath, newPath })
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
if (!response.ok) {
|
|
279
|
+
const error = await response.json();
|
|
280
|
+
throw new Error(error.error?.message || 'Failed to rename');
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Delete file
|
|
286
|
+
* @param {string} path - File path
|
|
287
|
+
* @returns {Promise<void>}
|
|
288
|
+
*/
|
|
289
|
+
export async function unlink(path) {
|
|
290
|
+
const response = await fetch(`${API_BASE}/unlink`, {
|
|
291
|
+
method: 'DELETE',
|
|
292
|
+
headers: { 'Content-Type': 'application/json' },
|
|
293
|
+
body: JSON.stringify({ path })
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
if (!response.ok) {
|
|
297
|
+
const error = await response.json();
|
|
298
|
+
throw new Error(error.error?.message || 'Failed to delete file');
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Get file/directory stats
|
|
304
|
+
* @param {string} path - Path
|
|
305
|
+
* @returns {Promise<Stats>}
|
|
306
|
+
*/
|
|
307
|
+
export async function stat(path) {
|
|
308
|
+
const response = await fetch(`${API_BASE}/stat?path=${encodeURIComponent(path)}`);
|
|
309
|
+
|
|
310
|
+
if (!response.ok) {
|
|
311
|
+
const error = await response.json();
|
|
312
|
+
throw new Error(error.error?.message || 'Failed to get stats');
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const { stats } = await response.json();
|
|
316
|
+
return stats;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Get file/directory stats (doesn't follow symlinks)
|
|
321
|
+
* @param {string} path - Path
|
|
322
|
+
* @returns {Promise<Stats>}
|
|
323
|
+
*/
|
|
324
|
+
export async function lstat(path) {
|
|
325
|
+
const response = await fetch(`${API_BASE}/lstat?path=${encodeURIComponent(path)}`);
|
|
326
|
+
|
|
327
|
+
if (!response.ok) {
|
|
328
|
+
const error = await response.json();
|
|
329
|
+
throw new Error(error.error?.message || 'Failed to get stats');
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const { stats } = await response.json();
|
|
333
|
+
return stats;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Get canonical path
|
|
338
|
+
* @param {string} path - Path
|
|
339
|
+
* @returns {Promise<string>}
|
|
340
|
+
*/
|
|
341
|
+
export async function realpath(path) {
|
|
342
|
+
const response = await fetch(`${API_BASE}/realpath?path=${encodeURIComponent(path)}`);
|
|
343
|
+
|
|
344
|
+
if (!response.ok) {
|
|
345
|
+
const error = await response.json();
|
|
346
|
+
throw new Error(error.error?.message || 'Failed to get real path');
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const { realPath } = await response.json();
|
|
350
|
+
return realPath;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Read symbolic link
|
|
355
|
+
* @param {string} path - Link path
|
|
356
|
+
* @returns {Promise<string>}
|
|
357
|
+
*/
|
|
358
|
+
export async function readlink(path) {
|
|
359
|
+
const response = await fetch(`${API_BASE}/readlink?path=${encodeURIComponent(path)}`);
|
|
360
|
+
|
|
361
|
+
if (!response.ok) {
|
|
362
|
+
const error = await response.json();
|
|
363
|
+
throw new Error(error.error?.message || 'Failed to read link');
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const { target } = await response.json();
|
|
367
|
+
return target;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Check if file exists (convenience method)
|
|
372
|
+
* @param {string} path - Path
|
|
373
|
+
* @returns {Promise<boolean>}
|
|
374
|
+
*/
|
|
375
|
+
export async function exists(path) {
|
|
376
|
+
try {
|
|
377
|
+
await stat(path);
|
|
378
|
+
return true;
|
|
379
|
+
} catch {
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Default export with all methods
|
|
385
|
+
export default {
|
|
386
|
+
readFile,
|
|
387
|
+
writeFile,
|
|
388
|
+
appendFile,
|
|
389
|
+
copyFile,
|
|
390
|
+
readdir,
|
|
391
|
+
mkdir,
|
|
392
|
+
rmdir,
|
|
393
|
+
rm,
|
|
394
|
+
rename,
|
|
395
|
+
unlink,
|
|
396
|
+
stat,
|
|
397
|
+
lstat,
|
|
398
|
+
realpath,
|
|
399
|
+
readlink,
|
|
400
|
+
exists,
|
|
401
|
+
configure
|
|
402
|
+
};
|