@statewalker/webrun-files 0.5.0 → 0.7.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 +1 -1
- package/README.md +93 -113
- package/dist/cjs/index.cjs +84 -526
- package/dist/esm/index.js +78 -517
- package/dist/file-utils.d.ts +47 -0
- package/dist/file-utils.d.ts.map +1 -0
- package/dist/index.d.ts +14 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/{utils/path-utils.d.ts → path-utils.d.ts} +10 -1
- package/dist/path-utils.d.ts.map +1 -0
- package/dist/types.d.ts +90 -54
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -7
- package/src/file-utils.ts +106 -0
- package/src/index.ts +33 -27
- package/src/{utils/path-utils.ts → path-utils.ts} +16 -2
- package/src/types.ts +90 -53
- package/dist/files-api.d.ts +0 -44
- package/dist/files-api.d.ts.map +0 -1
- package/dist/impl/index.d.ts +0 -6
- package/dist/impl/index.d.ts.map +0 -1
- package/dist/impl/mem-files-api.d.ts +0 -13
- package/dist/impl/mem-files-api.d.ts.map +0 -1
- package/dist/impl/node-files-api.d.ts +0 -24
- package/dist/impl/node-files-api.d.ts.map +0 -1
- package/dist/utils/collect-stream.d.ts +0 -16
- package/dist/utils/collect-stream.d.ts.map +0 -1
- package/dist/utils/file-info-utils.d.ts +0 -10
- package/dist/utils/file-info-utils.d.ts.map +0 -1
- package/dist/utils/index.d.ts +0 -8
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/normalize-path.d.ts +0 -21
- package/dist/utils/normalize-path.d.ts.map +0 -1
- package/dist/utils/path-utils.d.ts.map +0 -1
- package/src/files-api.ts +0 -168
- package/src/impl/index.ts +0 -6
- package/src/impl/mem-files-api.ts +0 -323
- package/src/impl/node-files-api.ts +0 -271
- package/src/utils/collect-stream.ts +0 -35
- package/src/utils/file-info-utils.ts +0 -15
- package/src/utils/index.ts +0 -8
- package/src/utils/normalize-path.ts +0 -34
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,78 +1,125 @@
|
|
|
1
1
|
# @statewalker/webrun-files
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Core types and utilities for cross-platform file operations. This package defines the `FilesApi` interface that all storage backends implement, plus utility functions for common file operations.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
npm install @statewalker/webrun-files
|
|
9
|
-
# or
|
|
10
|
-
pnpm add @statewalker/webrun-files
|
|
11
9
|
```
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
For actual filesystem implementations, install one of these packages:
|
|
12
|
+
- `@statewalker/webrun-files-mem` - In-memory storage
|
|
13
|
+
- `@statewalker/webrun-files-node` - Node.js filesystem
|
|
14
|
+
- `@statewalker/webrun-files-browser` - Browser File System Access API
|
|
15
|
+
- `@statewalker/webrun-files-s3` - AWS S3 / S3-compatible storage
|
|
16
|
+
|
|
17
|
+
## The FilesApi Interface
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
All implementations provide this interface:
|
|
16
20
|
|
|
17
21
|
```typescript
|
|
18
|
-
|
|
22
|
+
interface FilesApi {
|
|
23
|
+
// Read file content as async iterable of chunks
|
|
24
|
+
read(path: string, options?: ReadOptions): AsyncIterable<Uint8Array>;
|
|
25
|
+
|
|
26
|
+
// Write content to file (creates parent directories)
|
|
27
|
+
write(path: string, content: Iterable<Uint8Array> | AsyncIterable<Uint8Array>): Promise<void>;
|
|
28
|
+
|
|
29
|
+
// Create directory (and parents)
|
|
30
|
+
mkdir(path: string): Promise<void>;
|
|
31
|
+
|
|
32
|
+
// List directory contents
|
|
33
|
+
list(path: string, options?: ListOptions): AsyncIterable<FileInfo>;
|
|
34
|
+
|
|
35
|
+
// Get file/directory metadata
|
|
36
|
+
stats(path: string): Promise<FileStats | undefined>;
|
|
37
|
+
|
|
38
|
+
// Check if path exists
|
|
39
|
+
exists(path: string): Promise<boolean>;
|
|
40
|
+
|
|
41
|
+
// Remove file or directory (recursively)
|
|
42
|
+
remove(path: string): Promise<boolean>;
|
|
19
43
|
|
|
20
|
-
|
|
44
|
+
// Move/rename file or directory
|
|
45
|
+
move(source: string, target: string): Promise<boolean>;
|
|
46
|
+
|
|
47
|
+
// Copy file or directory (recursively)
|
|
48
|
+
copy(source: string, target: string): Promise<boolean>;
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Quick Start
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { MemFilesApi } from '@statewalker/webrun-files-mem';
|
|
56
|
+
import { readFile, writeText } from '@statewalker/webrun-files';
|
|
57
|
+
|
|
58
|
+
const files = new MemFilesApi();
|
|
21
59
|
|
|
22
60
|
// Write a file
|
|
23
|
-
await files
|
|
24
|
-
new TextEncoder().encode('Remember to water the plants')
|
|
25
|
-
]);
|
|
61
|
+
await writeText(files, '/documents/notes.txt', 'Remember to water the plants');
|
|
26
62
|
|
|
27
63
|
// Read it back
|
|
28
|
-
const content = await
|
|
64
|
+
const content = await readFile(files, '/documents/notes.txt');
|
|
29
65
|
console.log(new TextDecoder().decode(content));
|
|
30
66
|
```
|
|
31
67
|
|
|
32
|
-
|
|
68
|
+
## Utility Functions
|
|
69
|
+
|
|
70
|
+
### Reading Files
|
|
33
71
|
|
|
34
72
|
```typescript
|
|
35
|
-
import {
|
|
73
|
+
import { readFile, readText, tryReadFile, tryReadText, readRange, readAt } from '@statewalker/webrun-files';
|
|
36
74
|
|
|
37
|
-
|
|
38
|
-
|
|
75
|
+
// Read entire file as Uint8Array
|
|
76
|
+
const content = await readFile(files, '/data.bin');
|
|
39
77
|
|
|
40
|
-
|
|
78
|
+
// Read as UTF-8 string
|
|
79
|
+
const text = await readText(files, '/config.json');
|
|
41
80
|
|
|
42
|
-
|
|
81
|
+
// Read with undefined return for missing files
|
|
82
|
+
const maybeContent = await tryReadFile(files, '/optional.txt');
|
|
83
|
+
const maybeText = await tryReadText(files, '/optional.txt');
|
|
43
84
|
|
|
44
|
-
|
|
85
|
+
// Read a specific byte range
|
|
86
|
+
const chunk = await readRange(files, '/large.bin', 1000, 500); // 500 bytes starting at position 1000
|
|
45
87
|
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
await files
|
|
88
|
+
// Read into a buffer at specific offset (like fs.read)
|
|
89
|
+
const buffer = new Uint8Array(100);
|
|
90
|
+
const bytesRead = await readAt(files, '/data.bin', buffer, 0, 100, 500);
|
|
49
91
|
```
|
|
50
92
|
|
|
51
|
-
|
|
93
|
+
### Writing Files
|
|
52
94
|
|
|
53
95
|
```typescript
|
|
54
|
-
|
|
55
|
-
```
|
|
96
|
+
import { writeText } from '@statewalker/webrun-files';
|
|
56
97
|
|
|
57
|
-
|
|
98
|
+
// Write string content as UTF-8
|
|
99
|
+
await writeText(files, '/greeting.txt', 'Hello, World!');
|
|
58
100
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
101
|
+
// Write binary content directly
|
|
102
|
+
await files.write('/data.bin', [new Uint8Array([1, 2, 3, 4])]);
|
|
103
|
+
|
|
104
|
+
// Write from multiple chunks
|
|
105
|
+
await files.write('/large.bin', generateChunks());
|
|
63
106
|
```
|
|
64
107
|
|
|
65
|
-
|
|
108
|
+
### Path Utilities
|
|
66
109
|
|
|
67
110
|
```typescript
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
111
|
+
import { normalizePath, joinPath, dirname, basename, extname } from '@statewalker/webrun-files';
|
|
112
|
+
|
|
113
|
+
normalizePath('//foo/../bar/./baz/'); // '/bar/baz'
|
|
114
|
+
joinPath('/foo', 'bar', 'baz.txt'); // '/foo/bar/baz.txt'
|
|
115
|
+
dirname('/foo/bar/baz.txt'); // '/foo/bar'
|
|
116
|
+
basename('/foo/bar/baz.txt'); // 'baz.txt'
|
|
117
|
+
extname('/foo/bar/baz.txt'); // '.txt'
|
|
71
118
|
```
|
|
72
119
|
|
|
73
|
-
##
|
|
120
|
+
## Working with Files
|
|
74
121
|
|
|
75
|
-
Checking
|
|
122
|
+
### Checking Existence
|
|
76
123
|
|
|
77
124
|
```typescript
|
|
78
125
|
if (await files.exists('/config.json')) {
|
|
@@ -80,7 +127,7 @@ if (await files.exists('/config.json')) {
|
|
|
80
127
|
}
|
|
81
128
|
```
|
|
82
129
|
|
|
83
|
-
|
|
130
|
+
### Getting Metadata
|
|
84
131
|
|
|
85
132
|
```typescript
|
|
86
133
|
const info = await files.stats('/photo.jpg');
|
|
@@ -91,23 +138,21 @@ if (info) {
|
|
|
91
138
|
}
|
|
92
139
|
```
|
|
93
140
|
|
|
94
|
-
Listing
|
|
141
|
+
### Listing Directories
|
|
95
142
|
|
|
96
143
|
```typescript
|
|
144
|
+
// List direct children
|
|
97
145
|
for await (const entry of files.list('/documents')) {
|
|
98
146
|
console.log(`${entry.name} (${entry.kind})`);
|
|
99
147
|
}
|
|
100
|
-
```
|
|
101
148
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
```typescript
|
|
149
|
+
// List recursively
|
|
105
150
|
for await (const entry of files.list('/project', { recursive: true })) {
|
|
106
151
|
console.log(entry.path);
|
|
107
152
|
}
|
|
108
153
|
```
|
|
109
154
|
|
|
110
|
-
|
|
155
|
+
### File Management
|
|
111
156
|
|
|
112
157
|
```typescript
|
|
113
158
|
await files.mkdir('/archive/2024');
|
|
@@ -116,81 +161,16 @@ await files.move('/temp/draft.txt', '/documents/final.txt');
|
|
|
116
161
|
await files.remove('/old-stuff'); // Recursively deletes directories
|
|
117
162
|
```
|
|
118
163
|
|
|
119
|
-
## Low-Level File Handle Operations
|
|
120
|
-
|
|
121
|
-
When you need fine-grained control over file operations, work directly with file handles. Opening a file gives you a handle that supports reading, writing, and appending at specific positions:
|
|
122
|
-
|
|
123
|
-
```typescript
|
|
124
|
-
const handle = await files.open('/data.bin');
|
|
125
|
-
|
|
126
|
-
// Get the current file size
|
|
127
|
-
console.log(`File is ${handle.size} bytes`);
|
|
128
|
-
|
|
129
|
-
// Read a specific range
|
|
130
|
-
for await (const chunk of handle.createReadStream({ start: 0, end: 100 })) {
|
|
131
|
-
// First 100 bytes
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Write at a specific position
|
|
135
|
-
await handle.createWriteStream([newData], { start: 50 });
|
|
136
|
-
|
|
137
|
-
// Append to the end
|
|
138
|
-
await handle.appendFile([moreData]);
|
|
139
|
-
|
|
140
|
-
// Always close when done
|
|
141
|
-
await handle.close();
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
## Building Your Own Backend
|
|
145
|
-
|
|
146
|
-
The `IFilesApi` interface defines the contract that all backends must implement. At minimum, you need four methods:
|
|
147
|
-
|
|
148
|
-
```typescript
|
|
149
|
-
interface IFilesApi {
|
|
150
|
-
list(file: FileRef, options?: ListOptions): AsyncGenerator<FileInfo>;
|
|
151
|
-
stats(file: FileRef): Promise<FileInfo | undefined>;
|
|
152
|
-
remove(file: FileRef): Promise<boolean>;
|
|
153
|
-
open(file: FileRef): Promise<FileHandle>;
|
|
154
|
-
}
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
The `FilesApi` wrapper class builds convenience methods like `read`, `write`, `copy`, and `move` on top of these primitives. Backends can optionally implement native versions of `move`, `copy`, and `mkdir` for better performance.
|
|
158
|
-
|
|
159
|
-
Take a look at `MemFilesApi` or `NodeFilesApi` in the source code for reference implementations.
|
|
160
|
-
|
|
161
164
|
## Type Reference
|
|
162
165
|
|
|
163
|
-
The package exports all the TypeScript types you'll need:
|
|
164
|
-
|
|
165
166
|
```typescript
|
|
166
167
|
import type {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
BinaryStream, // AsyncIterable<Uint8Array> | Iterable<Uint8Array>
|
|
174
|
-
ListOptions, // { recursive?: boolean }
|
|
175
|
-
CopyOptions, // { recursive?: boolean }
|
|
176
|
-
ReadStreamOptions, // { start?: number, end?: number, signal?: AbortSignal }
|
|
177
|
-
WriteStreamOptions, // { start?: number, signal?: AbortSignal }
|
|
178
|
-
} from '@statewalker/webrun-files';
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
## Utility Functions
|
|
182
|
-
|
|
183
|
-
The package includes helpful utilities for working with paths and streams:
|
|
184
|
-
|
|
185
|
-
```typescript
|
|
186
|
-
import {
|
|
187
|
-
normalizePath, // Clean up path strings
|
|
188
|
-
resolveFileRef, // Convert FileRef to normalized path
|
|
189
|
-
joinPath, // Join path segments
|
|
190
|
-
dirname, // Get directory portion of path
|
|
191
|
-
basename, // Get filename portion
|
|
192
|
-
extname, // Get file extension
|
|
193
|
-
collectGenerator, // Collect async iterable into array
|
|
168
|
+
FilesApi, // Core interface for backends
|
|
169
|
+
FileInfo, // Metadata from list() - includes name, path, kind, size, lastModified
|
|
170
|
+
FileStats, // Metadata from stats() - kind, size, lastModified
|
|
171
|
+
FileKind, // "file" | "directory"
|
|
172
|
+
ReadOptions, // { start?: number, length?: number, signal?: AbortSignal }
|
|
173
|
+
ListOptions, // { recursive?: boolean }
|
|
194
174
|
} from '@statewalker/webrun-files';
|
|
195
175
|
```
|
|
196
176
|
|