@statewalker/webrun-files 0.5.0 → 0.9.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.
Files changed (42) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +131 -114
  3. package/dist/cjs/index.cjs +85 -529
  4. package/dist/esm/index.js +78 -519
  5. package/dist/file-utils.d.ts +47 -0
  6. package/dist/file-utils.d.ts.map +1 -0
  7. package/dist/index.d.ts +14 -8
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/{utils/path-utils.d.ts → path-utils.d.ts} +10 -1
  10. package/dist/path-utils.d.ts.map +1 -0
  11. package/dist/types.d.ts +130 -51
  12. package/dist/types.d.ts.map +1 -1
  13. package/package.json +7 -10
  14. package/src/file-utils.ts +106 -0
  15. package/src/index.ts +38 -27
  16. package/src/{utils/path-utils.ts → path-utils.ts} +16 -2
  17. package/src/types.ts +136 -53
  18. package/dist/files-api.d.ts +0 -44
  19. package/dist/files-api.d.ts.map +0 -1
  20. package/dist/impl/index.d.ts +0 -6
  21. package/dist/impl/index.d.ts.map +0 -1
  22. package/dist/impl/mem-files-api.d.ts +0 -13
  23. package/dist/impl/mem-files-api.d.ts.map +0 -1
  24. package/dist/impl/node-files-api.d.ts +0 -24
  25. package/dist/impl/node-files-api.d.ts.map +0 -1
  26. package/dist/utils/collect-stream.d.ts +0 -16
  27. package/dist/utils/collect-stream.d.ts.map +0 -1
  28. package/dist/utils/file-info-utils.d.ts +0 -10
  29. package/dist/utils/file-info-utils.d.ts.map +0 -1
  30. package/dist/utils/index.d.ts +0 -8
  31. package/dist/utils/index.d.ts.map +0 -1
  32. package/dist/utils/normalize-path.d.ts +0 -21
  33. package/dist/utils/normalize-path.d.ts.map +0 -1
  34. package/dist/utils/path-utils.d.ts.map +0 -1
  35. package/src/files-api.ts +0 -168
  36. package/src/impl/index.ts +0 -6
  37. package/src/impl/mem-files-api.ts +0 -323
  38. package/src/impl/node-files-api.ts +0 -271
  39. package/src/utils/collect-stream.ts +0 -35
  40. package/src/utils/file-info-utils.ts +0 -15
  41. package/src/utils/index.ts +0 -8
  42. package/src/utils/normalize-path.ts +0 -34
package/dist/esm/index.js CHANGED
@@ -1,46 +1,98 @@
1
- //#region src/utils/collect-stream.ts
1
+ //#region src/file-utils.ts
2
2
  /**
3
- * Stream collection utilities
3
+ * Collect async iterable chunks into a single Uint8Array.
4
4
  */
5
+ async function collectChunks(chunks) {
6
+ const parts = [];
7
+ let totalLength = 0;
8
+ for await (const chunk of chunks) {
9
+ parts.push(chunk);
10
+ totalLength += chunk.length;
11
+ }
12
+ if (parts.length === 0) return /* @__PURE__ */ new Uint8Array(0);
13
+ if (parts.length === 1) return parts[0];
14
+ const result = new Uint8Array(totalLength);
15
+ let offset = 0;
16
+ for (const chunk of parts) {
17
+ result.set(chunk, offset);
18
+ offset += chunk.length;
19
+ }
20
+ return result;
21
+ }
5
22
  /**
6
- * Collects all values from an async generator into an array.
23
+ * Read entire file content into a Uint8Array.
24
+ * Returns empty array if file doesn't exist.
7
25
  */
8
- async function collectGenerator(generator) {
9
- const results = [];
10
- for await (const item of generator) results.push(item);
11
- return results;
26
+ async function readFile(files, path) {
27
+ return collectChunks(files.read(path));
12
28
  }
13
29
  /**
14
- * Converts a synchronous iterable to an async iterable.
30
+ * Read entire file content as a UTF-8 string.
31
+ * Returns empty string if file doesn't exist.
15
32
  */
16
- async function* toAsyncIterable(iterable) {
17
- for (const item of iterable) yield item;
33
+ async function readText(files, path) {
34
+ const data = await readFile(files, path);
35
+ return new TextDecoder().decode(data);
18
36
  }
19
37
  /**
20
- * Normalizes BinaryStream to AsyncIterable<Uint8Array>.
38
+ * Read file content, returning undefined if file doesn't exist.
21
39
  */
22
- function toBinaryAsyncIterable(data) {
23
- if (Symbol.asyncIterator in data) return data;
24
- return toAsyncIterable(data);
40
+ async function tryReadFile(files, path) {
41
+ if (!await files.exists(path)) return void 0;
42
+ return readFile(files, path);
43
+ }
44
+ /**
45
+ * Read file content as string, returning undefined if file doesn't exist.
46
+ */
47
+ async function tryReadText(files, path) {
48
+ const data = await tryReadFile(files, path);
49
+ return data ? new TextDecoder().decode(data) : void 0;
25
50
  }
26
-
27
- //#endregion
28
- //#region src/utils/file-info-utils.ts
29
51
  /**
30
- * Check if FileInfo represents a directory
52
+ * Read a specific byte range from a file.
53
+ *
54
+ * @param files - FilesApi instance
55
+ * @param path - File path
56
+ * @param position - Starting byte position
57
+ * @param length - Number of bytes to read
58
+ * @returns Uint8Array with requested bytes (may be shorter if EOF reached)
31
59
  */
32
- function isDirectory(info) {
33
- return info?.kind === "directory";
60
+ async function readRange(files, path, position, length) {
61
+ return collectChunks(files.read(path, {
62
+ start: position,
63
+ length
64
+ }));
34
65
  }
35
66
  /**
36
- * Check if FileInfo represents a file
67
+ * Read bytes from a file into a buffer at a specific offset.
68
+ * Similar to Node.js fs.read() signature.
69
+ *
70
+ * @param files - FilesApi instance
71
+ * @param path - File path
72
+ * @param buffer - Target buffer to write into
73
+ * @param bufferOffset - Offset in buffer where to start writing
74
+ * @param length - Number of bytes to read
75
+ * @param position - Position in file where to start reading
76
+ * @returns Number of bytes actually read
37
77
  */
38
- function isFile(info) {
39
- return info?.kind === "file";
78
+ async function readAt(files, path, buffer, bufferOffset, length, position) {
79
+ const data = await readRange(files, path, position, length);
80
+ const bytesToCopy = Math.min(data.length, buffer.length - bufferOffset);
81
+ buffer.set(data.subarray(0, bytesToCopy), bufferOffset);
82
+ return bytesToCopy;
83
+ }
84
+ /**
85
+ * Write a string to a file as UTF-8.
86
+ */
87
+ async function writeText(files, path, content) {
88
+ await files.write(path, [new TextEncoder().encode(content)]);
40
89
  }
41
-
42
90
  //#endregion
43
- //#region src/utils/normalize-path.ts
91
+ //#region src/path-utils.ts
92
+ /**
93
+ * Path manipulation utilities for virtual filesystem paths.
94
+ * All paths use forward slashes and start with "/".
95
+ */
44
96
  /**
45
97
  * Normalizes a file path to a consistent format.
46
98
  * - Adds leading slash if missing
@@ -54,24 +106,6 @@ function normalizePath(filePath) {
54
106
  return `/${segments.join("/")}`;
55
107
  }
56
108
  /**
57
- * Extracts path string from FileRef.
58
- */
59
- function toPath(file) {
60
- return typeof file === "object" ? file.path : String(file);
61
- }
62
- /**
63
- * Normalizes FileRef to a path string.
64
- */
65
- function resolveFileRef(file) {
66
- return normalizePath(toPath(file));
67
- }
68
-
69
- //#endregion
70
- //#region src/utils/path-utils.ts
71
- /**
72
- * Path manipulation utilities
73
- */
74
- /**
75
109
  * Joins path segments with proper normalization.
76
110
  */
77
111
  function joinPath(...segments) {
@@ -105,480 +139,5 @@ function extname(path) {
105
139
  if (dotIndex <= 0) return "";
106
140
  return name.substring(dotIndex);
107
141
  }
108
-
109
- //#endregion
110
- //#region src/files-api.ts
111
- const IGNORE_FILE = ".ignore";
112
- var FilesApi = class {
113
- constructor(fs) {
114
- this.fs = fs;
115
- }
116
- list(file, options) {
117
- return this.fs.list(file, options);
118
- }
119
- stats(file) {
120
- return this.fs.stats(file);
121
- }
122
- remove(file) {
123
- return this.fs.remove(file);
124
- }
125
- open(file) {
126
- return this.fs.open(file);
127
- }
128
- /**
129
- * Checks if a file or directory exists.
130
- */
131
- async exists(file) {
132
- return await this.stats(file) !== void 0;
133
- }
134
- /**
135
- * Reads file content as a stream.
136
- */
137
- async *read(file, options = {}) {
138
- const handle = await this.open(file);
139
- try {
140
- yield* handle.createReadStream(options);
141
- } finally {
142
- await handle.close();
143
- }
144
- }
145
- /**
146
- * Writes content to a file.
147
- */
148
- async write(file, content) {
149
- const handle = await this.open(file);
150
- try {
151
- await handle.createWriteStream(toBinaryAsyncIterable(content));
152
- } finally {
153
- await handle.close();
154
- }
155
- }
156
- /**
157
- * Reads entire file into a single buffer.
158
- */
159
- async readFile(file) {
160
- const chunks = [];
161
- let totalLength = 0;
162
- for await (const chunk of this.read(file)) {
163
- chunks.push(chunk);
164
- totalLength += chunk.length;
165
- }
166
- if (chunks.length === 0) return new Uint8Array(0);
167
- if (chunks.length === 1) return chunks[0];
168
- const result = new Uint8Array(totalLength);
169
- let offset = 0;
170
- for (const chunk of chunks) {
171
- result.set(chunk, offset);
172
- offset += chunk.length;
173
- }
174
- return result;
175
- }
176
- /**
177
- * Copies file or directory.
178
- * Uses native implementation if available, otherwise falls back to read/write.
179
- */
180
- async copy(source, target, options = {}) {
181
- if (this.fs.copy) return this.fs.copy(source, target, options);
182
- const sourceInfo = await this.stats(source);
183
- if (!sourceInfo) return false;
184
- const sourcePath = resolveFileRef(source);
185
- const targetPath = resolveFileRef(target);
186
- const recursive = options.recursive ?? true;
187
- if (sourceInfo.kind === "directory") for await (const entry of this.list(source, { recursive })) {
188
- if (entry.kind === "directory") continue;
189
- const newTargetPath = targetPath + entry.path.substring(sourcePath.length);
190
- await this.write(newTargetPath, this.read(entry.path));
191
- }
192
- else await this.write(targetPath, this.read(sourcePath));
193
- return true;
194
- }
195
- /**
196
- * Moves file or directory.
197
- * Uses native implementation if available, otherwise falls back to copy+delete.
198
- */
199
- async move(source, target) {
200
- if (this.fs.move) return this.fs.move(source, target);
201
- if (!await this.copy(source, target)) return false;
202
- await this.remove(source);
203
- return true;
204
- }
205
- /**
206
- * Creates a directory.
207
- * Uses native implementation if available, otherwise creates a placeholder file.
208
- */
209
- async mkdir(file) {
210
- if (this.fs.mkdir) return this.fs.mkdir(file);
211
- const placeholderPath = joinPath(resolveFileRef(file), IGNORE_FILE);
212
- await this.write(placeholderPath, [new Uint8Array(0)]);
213
- }
214
- };
215
-
216
- //#endregion
217
- //#region src/impl/mem-files-api.ts
218
- var MemFileHandle = class {
219
- constructor(store, path) {
220
- this.store = store;
221
- this.path = path;
222
- }
223
- get size() {
224
- const entry = this.store.get(this.path);
225
- if (entry?.kind === "file") return entry.content.length;
226
- return 0;
227
- }
228
- getOrCreateFile() {
229
- let entry = this.store.get(this.path);
230
- if (!entry || entry.kind !== "file") {
231
- entry = {
232
- kind: "file",
233
- content: new Uint8Array(0),
234
- lastModified: Date.now()
235
- };
236
- this.store.set(this.path, entry);
237
- }
238
- return entry;
239
- }
240
- async close() {}
241
- async appendFile(data, options = {}) {
242
- const file = this.getOrCreateFile();
243
- const chunks = [file.content];
244
- let bytesWritten = 0;
245
- for await (const chunk of toBinaryAsyncIterable(data)) {
246
- if (options.signal?.aborted) throw new Error("Operation aborted");
247
- chunks.push(chunk);
248
- bytesWritten += chunk.length;
249
- }
250
- const totalLength = chunks.reduce((sum, c) => sum + c.length, 0);
251
- const merged = new Uint8Array(totalLength);
252
- let offset = 0;
253
- for (const chunk of chunks) {
254
- merged.set(chunk, offset);
255
- offset += chunk.length;
256
- }
257
- file.content = merged;
258
- file.lastModified = Date.now();
259
- return bytesWritten;
260
- }
261
- async *createReadStream(options = {}) {
262
- const entry = this.store.get(this.path);
263
- if (!entry || entry.kind !== "file") return;
264
- const { start = 0, end = Infinity, signal } = options;
265
- const bufferSize = 8192;
266
- const content = entry.content;
267
- const actualEnd = Math.min(end, content.length);
268
- let position = start;
269
- while (position < actualEnd) {
270
- if (signal?.aborted) throw new Error("Operation aborted");
271
- const remaining = actualEnd - position;
272
- const toRead = Math.min(bufferSize, remaining);
273
- yield content.subarray(position, position + toRead);
274
- position += toRead;
275
- }
276
- }
277
- async createWriteStream(data, options = {}) {
278
- const { start = 0, signal } = options;
279
- const file = this.getOrCreateFile();
280
- const chunks = [];
281
- let bytesWritten = 0;
282
- if (start > 0 && file.content.length > 0) chunks.push(file.content.subarray(0, Math.min(start, file.content.length)));
283
- if (start > file.content.length) chunks.push(new Uint8Array(start - file.content.length));
284
- for await (const chunk of toBinaryAsyncIterable(data)) {
285
- if (signal?.aborted) throw new Error("Operation aborted");
286
- chunks.push(chunk);
287
- bytesWritten += chunk.length;
288
- }
289
- const totalLength = chunks.reduce((sum, c) => sum + c.length, 0);
290
- const merged = new Uint8Array(totalLength);
291
- let offset = 0;
292
- for (const chunk of chunks) {
293
- merged.set(chunk, offset);
294
- offset += chunk.length;
295
- }
296
- file.content = merged;
297
- file.lastModified = Date.now();
298
- return bytesWritten;
299
- }
300
- async read(buffer, offset, length, position) {
301
- const entry = this.store.get(this.path);
302
- if (!entry || entry.kind !== "file") return 0;
303
- const content = entry.content;
304
- const available = content.length - position;
305
- if (available <= 0) return 0;
306
- const bytesToRead = Math.min(length, available, buffer.length - offset);
307
- buffer.set(content.subarray(position, position + bytesToRead), offset);
308
- return bytesToRead;
309
- }
310
- };
311
- var MemFilesApi = class {
312
- store = /* @__PURE__ */ new Map();
313
- async *list(file, options = {}) {
314
- const normalized = resolveFileRef(file);
315
- const prefix = normalized === "/" ? "/" : `${normalized}/`;
316
- const { recursive = false } = options;
317
- const seen = /* @__PURE__ */ new Set();
318
- for (const [path, entry] of this.store.entries()) {
319
- if (!path.startsWith(prefix)) continue;
320
- const segments = path.substring(prefix.length).split("/");
321
- if (segments.length === 0 || segments[0] === "") continue;
322
- if (segments.length === 1) {
323
- if (seen.has(path)) continue;
324
- seen.add(path);
325
- const info = {
326
- kind: entry.kind,
327
- name: basename(path),
328
- path,
329
- lastModified: entry.lastModified
330
- };
331
- if (entry.kind === "file") info.size = entry.content.length;
332
- yield info;
333
- } else if (recursive) {
334
- if (seen.has(path)) continue;
335
- seen.add(path);
336
- const info = {
337
- kind: entry.kind,
338
- name: basename(path),
339
- path,
340
- lastModified: entry.lastModified
341
- };
342
- if (entry.kind === "file") info.size = entry.content.length;
343
- yield info;
344
- } else {
345
- const dirName = segments[0];
346
- const dirPath = joinPath(normalized, dirName);
347
- if (!seen.has(dirPath)) {
348
- seen.add(dirPath);
349
- yield {
350
- kind: "directory",
351
- name: dirName,
352
- path: dirPath,
353
- lastModified: 0
354
- };
355
- }
356
- }
357
- }
358
- }
359
- async stats(file) {
360
- const normalized = resolveFileRef(file);
361
- const entry = this.store.get(normalized);
362
- if (entry) {
363
- const info = {
364
- kind: entry.kind,
365
- name: basename(normalized),
366
- path: normalized,
367
- lastModified: entry.lastModified
368
- };
369
- if (entry.kind === "file") info.size = entry.content.length;
370
- return info;
371
- }
372
- if (normalized === "/") return {
373
- kind: "directory",
374
- name: "",
375
- path: "/",
376
- lastModified: 0
377
- };
378
- const prefix = `${normalized}/`;
379
- for (const path of this.store.keys()) if (path.startsWith(prefix)) return {
380
- kind: "directory",
381
- name: basename(normalized),
382
- path: normalized,
383
- lastModified: 0
384
- };
385
- }
386
- async remove(file) {
387
- const normalized = resolveFileRef(file);
388
- const prefix = `${normalized}/`;
389
- let removed = false;
390
- if (this.store.delete(normalized)) removed = true;
391
- for (const path of [...this.store.keys()]) if (path.startsWith(prefix)) {
392
- this.store.delete(path);
393
- removed = true;
394
- }
395
- return removed;
396
- }
397
- async open(file) {
398
- const normalized = resolveFileRef(file);
399
- return new MemFileHandle(this.store, normalized);
400
- }
401
- async mkdir(file) {
402
- const normalized = resolveFileRef(file);
403
- if (!this.store.has(normalized)) this.store.set(normalized, {
404
- kind: "directory",
405
- lastModified: Date.now()
406
- });
407
- }
408
- };
409
-
410
- //#endregion
411
- //#region src/impl/node-files-api.ts
412
- /**
413
- * Wraps Node.js FileHandle to implement our FileHandle interface.
414
- */
415
- var NodeFileHandleWrapper = class {
416
- constructor(handle, _size) {
417
- this.handle = handle;
418
- this._size = _size;
419
- }
420
- get size() {
421
- return this._size;
422
- }
423
- async close() {
424
- await this.handle.close();
425
- }
426
- async appendFile(data, options = {}) {
427
- let bytesWritten = 0;
428
- const asyncData = toBinaryAsyncIterable(data);
429
- for await (const chunk of asyncData) {
430
- if (options.signal?.aborted) throw new Error("Operation aborted");
431
- await this.handle.appendFile(chunk);
432
- bytesWritten += chunk.length;
433
- }
434
- this._size = (await this.handle.stat()).size;
435
- return bytesWritten;
436
- }
437
- async *createReadStream(options = {}) {
438
- const { start = 0, end = Infinity, signal } = options;
439
- const bufferSize = 8192;
440
- let position = start;
441
- const actualEnd = Math.min(end, this._size);
442
- while (position < actualEnd) {
443
- if (signal?.aborted) throw new Error("Operation aborted");
444
- const remaining = actualEnd - position;
445
- const toRead = Math.min(bufferSize, remaining);
446
- const buffer = new Uint8Array(toRead);
447
- const { bytesRead } = await this.handle.read(buffer, 0, toRead, position);
448
- if (bytesRead === 0) break;
449
- yield buffer.subarray(0, bytesRead);
450
- position += bytesRead;
451
- }
452
- }
453
- async createWriteStream(data, options = {}) {
454
- const { start = 0, signal } = options;
455
- let position = start;
456
- let bytesWritten = 0;
457
- const asyncData = toBinaryAsyncIterable(data);
458
- await this.handle.truncate(start);
459
- for await (const chunk of asyncData) {
460
- if (signal?.aborted) throw new Error("Operation aborted");
461
- const { bytesWritten: written } = await this.handle.write(chunk, 0, chunk.length, position);
462
- position += written;
463
- bytesWritten += written;
464
- }
465
- this._size = (await this.handle.stat()).size;
466
- return bytesWritten;
467
- }
468
- async chmod(mode) {
469
- await this.handle.chmod(mode);
470
- }
471
- async chown(uid, gid) {
472
- await this.handle.chown(uid, gid);
473
- }
474
- async read(buffer, offset, length, position) {
475
- const actualLength = Math.min(length, buffer.length - offset);
476
- if (actualLength <= 0) return 0;
477
- return (await this.handle.read(buffer, offset, actualLength, position)).bytesRead;
478
- }
479
- };
480
- var NodeFilesApi = class {
481
- fs;
482
- rootDir;
483
- constructor(options) {
484
- this.fs = options.fs;
485
- this.rootDir = options.rootDir ?? "";
486
- }
487
- resolvePath(file) {
488
- const normalized = resolveFileRef(file);
489
- return this.rootDir + normalized;
490
- }
491
- async *list(file, options = {}) {
492
- const dirPath = this.resolvePath(file);
493
- const { recursive = false } = options;
494
- try {
495
- const entries = await this.fs.readdir(dirPath, { withFileTypes: true });
496
- for (const entry of entries) {
497
- const entryPath = joinPath(resolveFileRef(file), entry.name);
498
- const fullPath = this.rootDir + entryPath;
499
- const info = {
500
- kind: entry.isDirectory() ? "directory" : "file",
501
- name: entry.name,
502
- path: entryPath,
503
- lastModified: 0
504
- };
505
- try {
506
- const stat = await this.fs.stat(fullPath);
507
- info.size = stat.size;
508
- info.lastModified = stat.mtimeMs;
509
- } catch {}
510
- yield info;
511
- if (recursive && entry.isDirectory()) yield* this.list(entryPath, options);
512
- }
513
- } catch {}
514
- }
515
- async stats(file) {
516
- const fullPath = this.resolvePath(file);
517
- const normalized = resolveFileRef(file);
518
- try {
519
- const stat = await this.fs.stat(fullPath);
520
- return {
521
- kind: stat.isDirectory() ? "directory" : "file",
522
- name: basename(normalized),
523
- path: normalized,
524
- size: stat.size,
525
- lastModified: stat.mtimeMs
526
- };
527
- } catch {
528
- return;
529
- }
530
- }
531
- async remove(file) {
532
- const fullPath = this.resolvePath(file);
533
- try {
534
- if ((await this.fs.stat(fullPath)).isDirectory()) await this.fs.rm(fullPath, {
535
- recursive: true,
536
- force: true
537
- });
538
- else await this.fs.unlink(fullPath);
539
- return true;
540
- } catch {
541
- return false;
542
- }
543
- }
544
- async open(file) {
545
- const fullPath = this.resolvePath(file);
546
- const normalized = resolveFileRef(file);
547
- const dir = this.rootDir + dirname(normalized);
548
- await this.fs.mkdir(dir, { recursive: true });
549
- const handle = await this.fs.open(fullPath, "a+");
550
- return new NodeFileHandleWrapper(handle, (await handle.stat()).size);
551
- }
552
- async move(source, target) {
553
- const sourcePath = this.resolvePath(source);
554
- const targetPath = this.resolvePath(target);
555
- try {
556
- const targetDir = dirname(targetPath);
557
- await this.fs.mkdir(targetDir, { recursive: true });
558
- await this.fs.rename(sourcePath, targetPath);
559
- return true;
560
- } catch {
561
- return false;
562
- }
563
- }
564
- async copy(source, target, options = {}) {
565
- const sourcePath = this.resolvePath(source);
566
- const targetPath = this.resolvePath(target);
567
- const { recursive = true } = options;
568
- try {
569
- const targetDir = dirname(targetPath);
570
- await this.fs.mkdir(targetDir, { recursive: true });
571
- await this.fs.cp(sourcePath, targetPath, { recursive });
572
- return true;
573
- } catch {
574
- return false;
575
- }
576
- }
577
- async mkdir(file) {
578
- const fullPath = this.resolvePath(file);
579
- await this.fs.mkdir(fullPath, { recursive: true });
580
- }
581
- };
582
-
583
142
  //#endregion
584
- export { FilesApi, MemFilesApi, NodeFilesApi, basename, collectGenerator, dirname, extname, isDirectory, isFile, joinPath, normalizePath, resolveFileRef, toAsyncIterable, toBinaryAsyncIterable, toPath };
143
+ export { basename, dirname, extname, joinPath, normalizePath, readAt, readFile, readRange, readText, tryReadFile, tryReadText, writeText };
@@ -0,0 +1,47 @@
1
+ import type { FilesApi } from "./types.js";
2
+ /**
3
+ * Read entire file content into a Uint8Array.
4
+ * Returns empty array if file doesn't exist.
5
+ */
6
+ export declare function readFile(files: FilesApi, path: string): Promise<Uint8Array>;
7
+ /**
8
+ * Read entire file content as a UTF-8 string.
9
+ * Returns empty string if file doesn't exist.
10
+ */
11
+ export declare function readText(files: FilesApi, path: string): Promise<string>;
12
+ /**
13
+ * Read file content, returning undefined if file doesn't exist.
14
+ */
15
+ export declare function tryReadFile(files: FilesApi, path: string): Promise<Uint8Array | undefined>;
16
+ /**
17
+ * Read file content as string, returning undefined if file doesn't exist.
18
+ */
19
+ export declare function tryReadText(files: FilesApi, path: string): Promise<string | undefined>;
20
+ /**
21
+ * Read a specific byte range from a file.
22
+ *
23
+ * @param files - FilesApi instance
24
+ * @param path - File path
25
+ * @param position - Starting byte position
26
+ * @param length - Number of bytes to read
27
+ * @returns Uint8Array with requested bytes (may be shorter if EOF reached)
28
+ */
29
+ export declare function readRange(files: FilesApi, path: string, position: number, length: number): Promise<Uint8Array>;
30
+ /**
31
+ * Read bytes from a file into a buffer at a specific offset.
32
+ * Similar to Node.js fs.read() signature.
33
+ *
34
+ * @param files - FilesApi instance
35
+ * @param path - File path
36
+ * @param buffer - Target buffer to write into
37
+ * @param bufferOffset - Offset in buffer where to start writing
38
+ * @param length - Number of bytes to read
39
+ * @param position - Position in file where to start reading
40
+ * @returns Number of bytes actually read
41
+ */
42
+ export declare function readAt(files: FilesApi, path: string, buffer: Uint8Array, bufferOffset: number, length: number, position: number): Promise<number>;
43
+ /**
44
+ * Write a string to a file as UTF-8.
45
+ */
46
+ export declare function writeText(files: FilesApi, path: string, content: string): Promise<void>;
47
+ //# sourceMappingURL=file-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-utils.d.ts","sourceRoot":"","sources":["../src/file-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAuB3C;;;GAGG;AACH,wBAAsB,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAEjF;AAED;;;GAGG;AACH,wBAAsB,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAG7E;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAGhG;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAG5F;AAED;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAC7B,KAAK,EAAE,QAAQ,EACf,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,UAAU,CAAC,CAErB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,MAAM,CAC1B,KAAK,EAAE,QAAQ,EACf,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,UAAU,EAClB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,CAKjB;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE7F"}
package/dist/index.d.ts CHANGED
@@ -1,12 +1,18 @@
1
1
  /**
2
2
  * webrun-files - Cross-platform filesystem API
3
+ *
4
+ * This package provides:
5
+ * - FilesApi interface for filesystem abstraction
6
+ * - Utility functions for common file operations
7
+ * - Path manipulation utilities
8
+ *
9
+ * For implementations, use:
10
+ * - @statewalker/webrun-files-mem (in-memory)
11
+ * - @statewalker/webrun-files-node (Node.js)
12
+ * - @statewalker/webrun-files-browser (browser)
13
+ * - @statewalker/webrun-files-s3 (S3)
3
14
  */
4
- export { FilesApi } from "./files-api.js";
5
- export { MemFilesApi } from "./impl/mem-files-api.js";
6
- export { NodeFilesApi } from "./impl/node-files-api.js";
7
- export type { AppendOptions, BinaryStream, CopyOptions, FileHandle, FileInfo, FileKind, FileRef, IFilesApi, ListOptions, ReadStreamOptions, WriteStreamOptions, } from "./types.js";
8
- export { collectGenerator, toAsyncIterable, toBinaryAsyncIterable, } from "./utils/collect-stream.js";
9
- export { normalizePath, resolveFileRef, toPath, } from "./utils/normalize-path.js";
10
- export { isDirectory, isFile } from "./utils/file-info-utils.js";
11
- export { basename, dirname, extname, joinPath } from "./utils/path-utils.js";
15
+ export { readAt, readFile, readRange, readText, tryReadFile, tryReadText, writeText, } from "./file-utils.js";
16
+ export { basename, dirname, extname, joinPath, normalizePath, } from "./path-utils.js";
17
+ export type { DirectoryEntryInfo, DirectoryEntryStats, FileEntryInfo, FileEntryLocation, FileEntryStats, FileInfo, FileKind, FileStats, FilesApi, ListOptions, ReadOptions, } from "./types.js";
12
18
  //# sourceMappingURL=index.d.ts.map