@xfcfam/xf-fs 0.1.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 +107 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/src/api/A.d.ts +17 -0
- package/dist/src/api/A.d.ts.map +1 -0
- package/dist/src/api/A.js +17 -0
- package/dist/src/api/A.js.map +1 -0
- package/dist/src/business/B.d.ts +17 -0
- package/dist/src/business/B.d.ts.map +1 -0
- package/dist/src/business/B.js +17 -0
- package/dist/src/business/B.js.map +1 -0
- package/dist/src/repository/R.d.ts +17 -0
- package/dist/src/repository/R.d.ts.map +1 -0
- package/dist/src/repository/R.js +17 -0
- package/dist/src/repository/R.js.map +1 -0
- package/dist/src/repository/base/AuditedFileRepository.d.ts +86 -0
- package/dist/src/repository/base/AuditedFileRepository.d.ts.map +1 -0
- package/dist/src/repository/base/AuditedFileRepository.js +202 -0
- package/dist/src/repository/base/AuditedFileRepository.js.map +1 -0
- package/dist/src/repository/base/CachedFileRepository.d.ts +53 -0
- package/dist/src/repository/base/CachedFileRepository.d.ts.map +1 -0
- package/dist/src/repository/base/CachedFileRepository.js +107 -0
- package/dist/src/repository/base/CachedFileRepository.js.map +1 -0
- package/dist/src/repository/base/FileRepository.d.ts +170 -0
- package/dist/src/repository/base/FileRepository.d.ts.map +1 -0
- package/dist/src/repository/base/FileRepository.js +382 -0
- package/dist/src/repository/base/FileRepository.js.map +1 -0
- package/dist/src/repository/general/AuditedFileRepository.d.ts +86 -0
- package/dist/src/repository/general/AuditedFileRepository.d.ts.map +1 -0
- package/dist/src/repository/general/AuditedFileRepository.js +238 -0
- package/dist/src/repository/general/AuditedFileRepository.js.map +1 -0
- package/dist/src/repository/general/CachedFileRepository.d.ts +53 -0
- package/dist/src/repository/general/CachedFileRepository.d.ts.map +1 -0
- package/dist/src/repository/general/CachedFileRepository.js +107 -0
- package/dist/src/repository/general/CachedFileRepository.js.map +1 -0
- package/dist/src/repository/general/FileRepository.d.ts +180 -0
- package/dist/src/repository/general/FileRepository.d.ts.map +1 -0
- package/dist/src/repository/general/FileRepository.js +401 -0
- package/dist/src/repository/general/FileRepository.js.map +1 -0
- package/dist/src/repository/structs/DirectoryNotEmptyException.d.ts +13 -0
- package/dist/src/repository/structs/DirectoryNotEmptyException.d.ts.map +1 -0
- package/dist/src/repository/structs/DirectoryNotEmptyException.js +17 -0
- package/dist/src/repository/structs/DirectoryNotEmptyException.js.map +1 -0
- package/dist/src/repository/structs/FileAccessDeniedException.d.ts +14 -0
- package/dist/src/repository/structs/FileAccessDeniedException.d.ts.map +1 -0
- package/dist/src/repository/structs/FileAccessDeniedException.js +18 -0
- package/dist/src/repository/structs/FileAccessDeniedException.js.map +1 -0
- package/dist/src/repository/structs/FileEntry.d.ts +21 -0
- package/dist/src/repository/structs/FileEntry.d.ts.map +1 -0
- package/dist/src/repository/structs/FileEntry.js +2 -0
- package/dist/src/repository/structs/FileEntry.js.map +1 -0
- package/dist/src/repository/structs/FileNotFoundException.d.ts +13 -0
- package/dist/src/repository/structs/FileNotFoundException.d.ts.map +1 -0
- package/dist/src/repository/structs/FileNotFoundException.js +17 -0
- package/dist/src/repository/structs/FileNotFoundException.js.map +1 -0
- package/dist/src/repository/structs/FileStat.d.ts +24 -0
- package/dist/src/repository/structs/FileStat.d.ts.map +1 -0
- package/dist/src/repository/structs/FileStat.js +2 -0
- package/dist/src/repository/structs/FileStat.js.map +1 -0
- package/dist/src/repository/structs/TempFile.d.ts +19 -0
- package/dist/src/repository/structs/TempFile.d.ts.map +1 -0
- package/dist/src/repository/structs/TempFile.js +2 -0
- package/dist/src/repository/structs/TempFile.js.map +1 -0
- package/dist/src/repository/structs/WatchEvent.d.ts +18 -0
- package/dist/src/repository/structs/WatchEvent.d.ts.map +1 -0
- package/dist/src/repository/structs/WatchEvent.js +2 -0
- package/dist/src/repository/structs/WatchEvent.js.map +1 -0
- package/dist/src/repository/structs/Watcher.d.ts +18 -0
- package/dist/src/repository/structs/Watcher.d.ts.map +1 -0
- package/dist/src/repository/structs/Watcher.js +2 -0
- package/dist/src/repository/structs/Watcher.js.map +1 -0
- package/dist/src/repository/transfers/DirectoryNotEmptyException.d.ts +13 -0
- package/dist/src/repository/transfers/DirectoryNotEmptyException.d.ts.map +1 -0
- package/dist/src/repository/transfers/DirectoryNotEmptyException.js +17 -0
- package/dist/src/repository/transfers/DirectoryNotEmptyException.js.map +1 -0
- package/dist/src/repository/transfers/FileAccessDeniedException.d.ts +14 -0
- package/dist/src/repository/transfers/FileAccessDeniedException.d.ts.map +1 -0
- package/dist/src/repository/transfers/FileAccessDeniedException.js +18 -0
- package/dist/src/repository/transfers/FileAccessDeniedException.js.map +1 -0
- package/dist/src/repository/transfers/FileEntry.d.ts +21 -0
- package/dist/src/repository/transfers/FileEntry.d.ts.map +1 -0
- package/dist/src/repository/transfers/FileEntry.js +2 -0
- package/dist/src/repository/transfers/FileEntry.js.map +1 -0
- package/dist/src/repository/transfers/FileNotFoundException.d.ts +13 -0
- package/dist/src/repository/transfers/FileNotFoundException.d.ts.map +1 -0
- package/dist/src/repository/transfers/FileNotFoundException.js +17 -0
- package/dist/src/repository/transfers/FileNotFoundException.js.map +1 -0
- package/dist/src/repository/transfers/FileStat.d.ts +24 -0
- package/dist/src/repository/transfers/FileStat.d.ts.map +1 -0
- package/dist/src/repository/transfers/FileStat.js +2 -0
- package/dist/src/repository/transfers/FileStat.js.map +1 -0
- package/dist/src/repository/transfers/TempFile.d.ts +19 -0
- package/dist/src/repository/transfers/TempFile.d.ts.map +1 -0
- package/dist/src/repository/transfers/TempFile.js +2 -0
- package/dist/src/repository/transfers/TempFile.js.map +1 -0
- package/dist/src/repository/transfers/WatchEvent.d.ts +25 -0
- package/dist/src/repository/transfers/WatchEvent.d.ts.map +1 -0
- package/dist/src/repository/transfers/WatchEvent.js +2 -0
- package/dist/src/repository/transfers/WatchEvent.js.map +1 -0
- package/dist/src/repository/transfers/Watcher.d.ts +18 -0
- package/dist/src/repository/transfers/Watcher.d.ts.map +1 -0
- package/dist/src/repository/transfers/Watcher.js +2 -0
- package/dist/src/repository/transfers/Watcher.js.map +1 -0
- package/dist/src/repository/utils/EncodingUtils.d.ts +29 -0
- package/dist/src/repository/utils/EncodingUtils.d.ts.map +1 -0
- package/dist/src/repository/utils/EncodingUtils.js +36 -0
- package/dist/src/repository/utils/EncodingUtils.js.map +1 -0
- package/dist/src/repository/utils/PathUtils.d.ts +23 -0
- package/dist/src/repository/utils/PathUtils.d.ts.map +1 -0
- package/dist/src/repository/utils/PathUtils.js +53 -0
- package/dist/src/repository/utils/PathUtils.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
import { Repository } from '@xfcfam/xf';
|
|
2
|
+
import { promises as fsp, createReadStream, createWriteStream, watch as fsWatch } from 'node:fs';
|
|
3
|
+
import { Readable, Writable } from 'node:stream';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { posix } from 'node:path';
|
|
6
|
+
import { randomBytes } from 'node:crypto';
|
|
7
|
+
import { FileNotFoundException } from '../transfers/FileNotFoundException.js';
|
|
8
|
+
import { FileAccessDeniedException } from '../transfers/FileAccessDeniedException.js';
|
|
9
|
+
import { DirectoryNotEmptyException } from '../transfers/DirectoryNotEmptyException.js';
|
|
10
|
+
import { PathUtils } from '../utils/PathUtils.js';
|
|
11
|
+
/**
|
|
12
|
+
* Generalization for Access Layer components that operate on the
|
|
13
|
+
* local filesystem.
|
|
14
|
+
*
|
|
15
|
+
* The protocol is "local filesystem" — every method on this class is
|
|
16
|
+
* a syscall (or a tight wrapper over one) translated into the XF
|
|
17
|
+
* Transfer projection: file content as `string` / `Uint8Array`,
|
|
18
|
+
* metadata as {@link FileStat}, directory entries as
|
|
19
|
+
* {@link FileEntry}, change events as {@link WatchEvent}, and active
|
|
20
|
+
* handles as {@link Watcher} / {@link TempFile}.
|
|
21
|
+
*
|
|
22
|
+
* Concrete components extend this class to expose business-meaningful
|
|
23
|
+
* methods that compose the base operations (e.g. `loadProfile()`
|
|
24
|
+
* calls `this.read('/users/profile.json')` then `JSON.parse`).
|
|
25
|
+
*
|
|
26
|
+
* Errors raised by `node:fs` are translated into typed Exception
|
|
27
|
+
* components ({@link FileNotFoundException},
|
|
28
|
+
* {@link FileAccessDeniedException},
|
|
29
|
+
* {@link DirectoryNotEmptyException}) so the Business Layer never
|
|
30
|
+
* inspects `errno` strings. Other failures propagate as native
|
|
31
|
+
* `Error` (consistent with the XF doctrine that runtime exceptions
|
|
32
|
+
* are well-formed transfer vehicles).
|
|
33
|
+
*
|
|
34
|
+
* `terminate()` releases every still-active {@link Watcher} and
|
|
35
|
+
* deletes every still-open {@link TempFile}: even careless callers
|
|
36
|
+
* won't leak OS handles.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* import { FileRepository } from '@xfcfam/xf-fs'
|
|
41
|
+
* import type { User } from '../transfers/User.js'
|
|
42
|
+
*
|
|
43
|
+
* export class UsersFileRepository extends FileRepository {
|
|
44
|
+
* constructor() { super({ rootPath: '/var/data/users' }) }
|
|
45
|
+
*
|
|
46
|
+
* async findById(id: string): Promise<User> {
|
|
47
|
+
* const text = await this.read(`${id}.json`)
|
|
48
|
+
* return JSON.parse(text) as User
|
|
49
|
+
* }
|
|
50
|
+
*
|
|
51
|
+
* async save(user: User): Promise<void> {
|
|
52
|
+
* await this.write(`${user.id}.json`, JSON.stringify(user))
|
|
53
|
+
* }
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export class FileRepository extends Repository {
|
|
58
|
+
constructor(options = {}) {
|
|
59
|
+
super({
|
|
60
|
+
rootPath: options.rootPath ?? process.cwd(),
|
|
61
|
+
openWatchers: new Set(),
|
|
62
|
+
openTempFiles: new Set(),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
async init() { }
|
|
66
|
+
async terminate() {
|
|
67
|
+
// Close every still-active watcher.
|
|
68
|
+
for (const w of [...this.state.openWatchers]) {
|
|
69
|
+
try {
|
|
70
|
+
await w.close();
|
|
71
|
+
}
|
|
72
|
+
catch { /* swallow on shutdown */ }
|
|
73
|
+
}
|
|
74
|
+
// Delete every still-open temp file.
|
|
75
|
+
for (const t of [...this.state.openTempFiles]) {
|
|
76
|
+
try {
|
|
77
|
+
await t.close();
|
|
78
|
+
}
|
|
79
|
+
catch { /* swallow on shutdown */ }
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// ─── Path resolution ──────────────────────────────────────
|
|
83
|
+
/**
|
|
84
|
+
* Resolve a path against `rootPath`. Absolute paths are returned
|
|
85
|
+
* unchanged (with separators normalised); relative paths are joined
|
|
86
|
+
* to the root.
|
|
87
|
+
*/
|
|
88
|
+
resolve(path) {
|
|
89
|
+
const normalised = PathUtils.normalize(path);
|
|
90
|
+
if (PathUtils.isAbsolute(normalised))
|
|
91
|
+
return normalised;
|
|
92
|
+
return PathUtils.join(this.state.rootPath, normalised);
|
|
93
|
+
}
|
|
94
|
+
// ─── File operations ──────────────────────────────────────
|
|
95
|
+
/** Read a file as UTF-8 text. */
|
|
96
|
+
async read(path) {
|
|
97
|
+
const abs = this.resolve(path);
|
|
98
|
+
try {
|
|
99
|
+
return await fsp.readFile(abs, 'utf-8');
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
throw this.translateError(err, abs);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/** Read a file as raw bytes. */
|
|
106
|
+
async readBytes(path) {
|
|
107
|
+
const abs = this.resolve(path);
|
|
108
|
+
try {
|
|
109
|
+
const buf = await fsp.readFile(abs);
|
|
110
|
+
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
throw this.translateError(err, abs);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Write `content` to `path`, overwriting any existing file.
|
|
118
|
+
* Parent directories must already exist; use `mkdir` first if not.
|
|
119
|
+
*/
|
|
120
|
+
async write(path, content) {
|
|
121
|
+
const abs = this.resolve(path);
|
|
122
|
+
try {
|
|
123
|
+
await fsp.writeFile(abs, content);
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
throw this.translateError(err, abs);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/** Append `content` to the end of `path` (creating it if absent). */
|
|
130
|
+
async append(path, content) {
|
|
131
|
+
const abs = this.resolve(path);
|
|
132
|
+
try {
|
|
133
|
+
await fsp.appendFile(abs, content);
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
throw this.translateError(err, abs);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/** Delete the file at `path`. Throws {@link FileNotFoundException} if absent. */
|
|
140
|
+
async delete(path) {
|
|
141
|
+
const abs = this.resolve(path);
|
|
142
|
+
try {
|
|
143
|
+
await fsp.unlink(abs);
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
throw this.translateError(err, abs);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/** Whether the path exists (file, directory, link, anything). */
|
|
150
|
+
async exists(path) {
|
|
151
|
+
const abs = this.resolve(path);
|
|
152
|
+
try {
|
|
153
|
+
await fsp.access(abs);
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/** Stat `path`. Throws {@link FileNotFoundException} if absent. */
|
|
161
|
+
async stat(path) {
|
|
162
|
+
const abs = this.resolve(path);
|
|
163
|
+
try {
|
|
164
|
+
const s = await fsp.lstat(abs);
|
|
165
|
+
return {
|
|
166
|
+
path: abs,
|
|
167
|
+
size: s.size,
|
|
168
|
+
modifiedAt: s.mtime,
|
|
169
|
+
createdAt: s.birthtime ?? s.mtime,
|
|
170
|
+
isFile: s.isFile(),
|
|
171
|
+
isDirectory: s.isDirectory(),
|
|
172
|
+
isSymlink: s.isSymbolicLink(),
|
|
173
|
+
mode: s.mode,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
catch (err) {
|
|
177
|
+
throw this.translateError(err, abs);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// ─── Directory operations ─────────────────────────────────
|
|
181
|
+
/** List immediate entries of a directory (not recursive). */
|
|
182
|
+
async list(path) {
|
|
183
|
+
const abs = this.resolve(path);
|
|
184
|
+
try {
|
|
185
|
+
const entries = await fsp.readdir(abs, { withFileTypes: true });
|
|
186
|
+
const out = [];
|
|
187
|
+
for (const e of entries) {
|
|
188
|
+
const full = PathUtils.join(abs, e.name);
|
|
189
|
+
out.push({
|
|
190
|
+
path: full,
|
|
191
|
+
relativePath: e.name,
|
|
192
|
+
name: e.name,
|
|
193
|
+
isFile: e.isFile(),
|
|
194
|
+
isDirectory: e.isDirectory(),
|
|
195
|
+
isSymlink: e.isSymbolicLink(),
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
out.sort((a, b) => a.name.localeCompare(b.name));
|
|
199
|
+
return out;
|
|
200
|
+
}
|
|
201
|
+
catch (err) {
|
|
202
|
+
throw this.translateError(err, abs);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Walk a directory recursively. Returns every regular file and
|
|
207
|
+
* directory under `path`. `relativePath` is computed relative to
|
|
208
|
+
* the walk root.
|
|
209
|
+
*/
|
|
210
|
+
async walk(path) {
|
|
211
|
+
const root = this.resolve(path);
|
|
212
|
+
const out = [];
|
|
213
|
+
await this.walkInto(root, root, out);
|
|
214
|
+
out.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
|
|
215
|
+
return out;
|
|
216
|
+
}
|
|
217
|
+
async walkInto(current, root, out) {
|
|
218
|
+
let entries;
|
|
219
|
+
try {
|
|
220
|
+
entries = await fsp.readdir(current, { withFileTypes: true });
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
throw this.translateError(err, current);
|
|
224
|
+
}
|
|
225
|
+
for (const e of entries) {
|
|
226
|
+
const full = PathUtils.join(current, e.name);
|
|
227
|
+
const rel = posix.relative(root, full);
|
|
228
|
+
out.push({
|
|
229
|
+
path: full,
|
|
230
|
+
relativePath: rel,
|
|
231
|
+
name: e.name,
|
|
232
|
+
isFile: e.isFile(),
|
|
233
|
+
isDirectory: e.isDirectory(),
|
|
234
|
+
isSymlink: e.isSymbolicLink(),
|
|
235
|
+
});
|
|
236
|
+
if (e.isDirectory())
|
|
237
|
+
await this.walkInto(full, root, out);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/** Create a directory. `recursive` creates intermediate parents. */
|
|
241
|
+
async mkdir(path, options = {}) {
|
|
242
|
+
const abs = this.resolve(path);
|
|
243
|
+
try {
|
|
244
|
+
await fsp.mkdir(abs, { recursive: options.recursive ?? false });
|
|
245
|
+
}
|
|
246
|
+
catch (err) {
|
|
247
|
+
throw this.translateError(err, abs);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Remove a directory. By default the directory must be empty;
|
|
252
|
+
* pass `{ recursive: true }` to delete contents too.
|
|
253
|
+
*/
|
|
254
|
+
async rmdir(path, options = {}) {
|
|
255
|
+
const abs = this.resolve(path);
|
|
256
|
+
try {
|
|
257
|
+
if (options.recursive === true) {
|
|
258
|
+
await fsp.rm(abs, { recursive: true, force: true });
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
await fsp.rmdir(abs);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
catch (err) {
|
|
265
|
+
throw this.translateError(err, abs);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
// ─── Streaming ────────────────────────────────────────────
|
|
269
|
+
/**
|
|
270
|
+
* Open a streaming reader for `path` as a Web `ReadableStream`.
|
|
271
|
+
* Useful for large files (> a few MB) where buffering the whole
|
|
272
|
+
* content in memory is wasteful.
|
|
273
|
+
*/
|
|
274
|
+
readStream(path) {
|
|
275
|
+
const abs = this.resolve(path);
|
|
276
|
+
const node = createReadStream(abs);
|
|
277
|
+
return Readable.toWeb(node);
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Open a streaming writer for `path` as a Web `WritableStream`.
|
|
281
|
+
* Overwrites any existing content.
|
|
282
|
+
*/
|
|
283
|
+
writeStream(path) {
|
|
284
|
+
const abs = this.resolve(path);
|
|
285
|
+
const node = createWriteStream(abs);
|
|
286
|
+
return Writable.toWeb(node);
|
|
287
|
+
}
|
|
288
|
+
// ─── Watching ─────────────────────────────────────────────
|
|
289
|
+
/**
|
|
290
|
+
* Watch a file or directory for changes. `callback` is invoked
|
|
291
|
+
* synchronously by the OS for each event.
|
|
292
|
+
*
|
|
293
|
+
* **Platform restriction**: recursive directory watching is supported
|
|
294
|
+
* only on macOS and Windows (via `node:fs`'s native `recursive`
|
|
295
|
+
* option). On Linux, `node:fs` silently ignores the `recursive` flag
|
|
296
|
+
* and emits no sub-directory events, which would be a silent footgun.
|
|
297
|
+
* Therefore this method throws an `Error` when watching a **directory**
|
|
298
|
+
* on Linux. Watching a single **file** works on every platform and is
|
|
299
|
+
* always allowed.
|
|
300
|
+
*
|
|
301
|
+
* @throws {Error} When watching a directory on Linux (where `node:fs`
|
|
302
|
+
* recursive watching is not supported).
|
|
303
|
+
* @throws {FileNotFoundException} If `path` does not exist.
|
|
304
|
+
*/
|
|
305
|
+
async watch(path, callback) {
|
|
306
|
+
const abs = this.resolve(path);
|
|
307
|
+
if (!(await this.exists(abs)))
|
|
308
|
+
throw new FileNotFoundException(abs);
|
|
309
|
+
// Recursive directory watching degrades silently on Linux (node:fs
|
|
310
|
+
// ignores the `recursive` flag and emits no sub-directory events), so
|
|
311
|
+
// fail loud there for DIRECTORY watches. Watching a single file works
|
|
312
|
+
// identically on every platform and is allowed.
|
|
313
|
+
if (process.platform === 'linux' && (await fsp.stat(abs)).isDirectory()) {
|
|
314
|
+
throw new Error('FileRepository.watch(): recursive directory watching is not supported on Linux ' +
|
|
315
|
+
'(node:fs silently ignores the recursive option). Watch individual files, or use a ' +
|
|
316
|
+
'platform-specific inotify solution for directory trees.');
|
|
317
|
+
}
|
|
318
|
+
const watcher = new WatcherImpl(abs, callback, this.state.openWatchers);
|
|
319
|
+
this.state.openWatchers.add(watcher);
|
|
320
|
+
return watcher;
|
|
321
|
+
}
|
|
322
|
+
// ─── Temp files ───────────────────────────────────────────
|
|
323
|
+
/**
|
|
324
|
+
* Create a unique temporary file under the OS temp directory. The
|
|
325
|
+
* file exists empty on disk; callers write/read it via `read()` /
|
|
326
|
+
* `write()` passing `tempFile.path`. Closing the returned handle
|
|
327
|
+
* deletes the file. `terminate()` closes all outstanding handles.
|
|
328
|
+
*/
|
|
329
|
+
async tempFile(prefix = 'xf-fs-') {
|
|
330
|
+
const name = `${prefix}${randomBytes(8).toString('hex')}`;
|
|
331
|
+
const abs = posix.join(tmpdir().replace(/\\/g, '/'), name);
|
|
332
|
+
await fsp.writeFile(abs, '');
|
|
333
|
+
const handle = new TempFileImpl(abs, this.state.openTempFiles);
|
|
334
|
+
this.state.openTempFiles.add(handle);
|
|
335
|
+
return handle;
|
|
336
|
+
}
|
|
337
|
+
// ─── Error translation ────────────────────────────────────
|
|
338
|
+
/**
|
|
339
|
+
* Translate a `node:fs` error into a typed Exception component when
|
|
340
|
+
* the error code is one of the modelled cases; otherwise return the
|
|
341
|
+
* error unchanged for plain propagation.
|
|
342
|
+
*/
|
|
343
|
+
translateError(err, path) {
|
|
344
|
+
if (typeof err !== 'object' || err === null)
|
|
345
|
+
return err;
|
|
346
|
+
const code = err.code;
|
|
347
|
+
if (code === 'ENOENT')
|
|
348
|
+
return new FileNotFoundException(path);
|
|
349
|
+
if (code === 'EACCES' || code === 'EPERM')
|
|
350
|
+
return new FileAccessDeniedException(path);
|
|
351
|
+
if (code === 'ENOTEMPTY')
|
|
352
|
+
return new DirectoryNotEmptyException(path);
|
|
353
|
+
return err;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
// ─── Concrete Transfer implementations ───────────────────────
|
|
357
|
+
class WatcherImpl {
|
|
358
|
+
path;
|
|
359
|
+
handle;
|
|
360
|
+
active = true;
|
|
361
|
+
registry;
|
|
362
|
+
constructor(path, callback, registry) {
|
|
363
|
+
this.path = path;
|
|
364
|
+
this.registry = registry;
|
|
365
|
+
this.handle = fsWatch(path, { recursive: process.platform !== 'linux' }, (eventType, filename) => {
|
|
366
|
+
const childPath = filename === null ? path : posix.join(path.replace(/\\/g, '/'), filename.toString());
|
|
367
|
+
const kind = eventType === 'rename' ? 'renamed' : 'modified';
|
|
368
|
+
callback({ path: childPath, kind });
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
get isActive() { return this.active; }
|
|
372
|
+
async close() {
|
|
373
|
+
if (!this.active)
|
|
374
|
+
return;
|
|
375
|
+
this.active = false;
|
|
376
|
+
this.registry.delete(this);
|
|
377
|
+
this.handle?.close();
|
|
378
|
+
this.handle = undefined;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
class TempFileImpl {
|
|
382
|
+
path;
|
|
383
|
+
open = true;
|
|
384
|
+
registry;
|
|
385
|
+
constructor(path, registry) {
|
|
386
|
+
this.path = path;
|
|
387
|
+
this.registry = registry;
|
|
388
|
+
}
|
|
389
|
+
get isOpen() { return this.open; }
|
|
390
|
+
async close() {
|
|
391
|
+
if (!this.open)
|
|
392
|
+
return;
|
|
393
|
+
this.open = false;
|
|
394
|
+
this.registry.delete(this);
|
|
395
|
+
try {
|
|
396
|
+
await fsp.unlink(this.path);
|
|
397
|
+
}
|
|
398
|
+
catch { /* already gone */ }
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
//# sourceMappingURL=FileRepository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileRepository.js","sourceRoot":"","sources":["../../../../src/repository/general/FileRepository.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Access-layer Exception — `rmdir` was called on a directory that
|
|
3
|
+
* still contains entries.
|
|
4
|
+
*
|
|
5
|
+
* `FileRepository` translates `node:fs`'s `ENOTEMPTY` into this typed
|
|
6
|
+
* Exception. Callers that want recursive deletion call `rmdir(path,
|
|
7
|
+
* { recursive: true })` instead of catching this one.
|
|
8
|
+
*/
|
|
9
|
+
export declare class DirectoryNotEmptyException extends Error {
|
|
10
|
+
readonly path: string;
|
|
11
|
+
constructor(path: string);
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=DirectoryNotEmptyException.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DirectoryNotEmptyException.d.ts","sourceRoot":"","sources":["../../../../src/repository/structs/DirectoryNotEmptyException.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,qBAAa,0BAA2B,SAAQ,KAAK;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;gBAET,IAAI,EAAE,MAAM;CAKzB"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Access-layer Exception — `rmdir` was called on a directory that
|
|
3
|
+
* still contains entries.
|
|
4
|
+
*
|
|
5
|
+
* `FileRepository` translates `node:fs`'s `ENOTEMPTY` into this typed
|
|
6
|
+
* Exception. Callers that want recursive deletion call `rmdir(path,
|
|
7
|
+
* { recursive: true })` instead of catching this one.
|
|
8
|
+
*/
|
|
9
|
+
export class DirectoryNotEmptyException extends Error {
|
|
10
|
+
path;
|
|
11
|
+
constructor(path) {
|
|
12
|
+
super(`Directory not empty: ${path}`);
|
|
13
|
+
this.name = 'DirectoryNotEmptyException';
|
|
14
|
+
this.path = path;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=DirectoryNotEmptyException.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DirectoryNotEmptyException.js","sourceRoot":"","sources":["../../../../src/repository/structs/DirectoryNotEmptyException.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,OAAO,0BAA2B,SAAQ,KAAK;IAC1C,IAAI,CAAQ;IAErB,YAAY,IAAY;QACtB,KAAK,CAAC,wBAAwB,IAAI,EAAE,CAAC,CAAA;QACrC,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAA;QACxC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;IAClB,CAAC;CACF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Access-layer Exception — the operating system denied permission
|
|
3
|
+
* to perform the requested operation on the path.
|
|
4
|
+
*
|
|
5
|
+
* Thrown by `FileRepository` when `node:fs` raises `EACCES` or
|
|
6
|
+
* `EPERM`. The Repository translates the platform error into this
|
|
7
|
+
* typed Exception so consumers can branch on permission failure
|
|
8
|
+
* without inspecting `errno` codes.
|
|
9
|
+
*/
|
|
10
|
+
export declare class FileAccessDeniedException extends Error {
|
|
11
|
+
readonly path: string;
|
|
12
|
+
constructor(path: string);
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=FileAccessDeniedException.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileAccessDeniedException.d.ts","sourceRoot":"","sources":["../../../../src/repository/structs/FileAccessDeniedException.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;gBAET,IAAI,EAAE,MAAM;CAKzB"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Access-layer Exception — the operating system denied permission
|
|
3
|
+
* to perform the requested operation on the path.
|
|
4
|
+
*
|
|
5
|
+
* Thrown by `FileRepository` when `node:fs` raises `EACCES` or
|
|
6
|
+
* `EPERM`. The Repository translates the platform error into this
|
|
7
|
+
* typed Exception so consumers can branch on permission failure
|
|
8
|
+
* without inspecting `errno` codes.
|
|
9
|
+
*/
|
|
10
|
+
export class FileAccessDeniedException extends Error {
|
|
11
|
+
path;
|
|
12
|
+
constructor(path) {
|
|
13
|
+
super(`Access denied: ${path}`);
|
|
14
|
+
this.name = 'FileAccessDeniedException';
|
|
15
|
+
this.path = path;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=FileAccessDeniedException.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileAccessDeniedException.js","sourceRoot":"","sources":["../../../../src/repository/structs/FileAccessDeniedException.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IACzC,IAAI,CAAQ;IAErB,YAAY,IAAY;QACtB,KAAK,CAAC,kBAAkB,IAAI,EAAE,CAAC,CAAA;QAC/B,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAA;QACvC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;IAClB,CAAC;CACF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Access-layer Transfer — a single entry yielded by directory
|
|
3
|
+
* traversal (`list` / `walk`). Captures path information and the
|
|
4
|
+
* cheap stat fields available from the directory iteration; richer
|
|
5
|
+
* metadata is fetched separately via {@link FileStat}.
|
|
6
|
+
*/
|
|
7
|
+
export interface FileEntry {
|
|
8
|
+
/** Absolute path of the entry on disk. */
|
|
9
|
+
path: string;
|
|
10
|
+
/** Path relative to the walk's root, with `/` separators. */
|
|
11
|
+
relativePath: string;
|
|
12
|
+
/** Final segment of `path` (the filename or directory name). */
|
|
13
|
+
name: string;
|
|
14
|
+
/** Whether the entry is a regular file. */
|
|
15
|
+
isFile: boolean;
|
|
16
|
+
/** Whether the entry is a directory. */
|
|
17
|
+
isDirectory: boolean;
|
|
18
|
+
/** Whether the entry is a symbolic link. */
|
|
19
|
+
isSymlink: boolean;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=FileEntry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileEntry.d.ts","sourceRoot":"","sources":["../../../../src/repository/structs/FileEntry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAA;IACZ,6DAA6D;IAC7D,YAAY,EAAE,MAAM,CAAA;IACpB,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAA;IACZ,2CAA2C;IAC3C,MAAM,EAAE,OAAO,CAAA;IACf,wCAAwC;IACxC,WAAW,EAAE,OAAO,CAAA;IACpB,4CAA4C;IAC5C,SAAS,EAAE,OAAO,CAAA;CACnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileEntry.js","sourceRoot":"","sources":["../../../../src/repository/structs/FileEntry.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Access-layer Exception — the requested path does not exist on disk.
|
|
3
|
+
*
|
|
4
|
+
* Thrown by `FileRepository` operations that require the path to
|
|
5
|
+
* exist (`read`, `stat`, `delete`, `list`, …). The Repository
|
|
6
|
+
* translates the `node:fs` `ENOENT` error into this typed Exception
|
|
7
|
+
* before propagating it upward.
|
|
8
|
+
*/
|
|
9
|
+
export declare class FileNotFoundException extends Error {
|
|
10
|
+
readonly path: string;
|
|
11
|
+
constructor(path: string);
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=FileNotFoundException.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileNotFoundException.d.ts","sourceRoot":"","sources":["../../../../src/repository/structs/FileNotFoundException.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;gBAET,IAAI,EAAE,MAAM;CAKzB"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Access-layer Exception — the requested path does not exist on disk.
|
|
3
|
+
*
|
|
4
|
+
* Thrown by `FileRepository` operations that require the path to
|
|
5
|
+
* exist (`read`, `stat`, `delete`, `list`, …). The Repository
|
|
6
|
+
* translates the `node:fs` `ENOENT` error into this typed Exception
|
|
7
|
+
* before propagating it upward.
|
|
8
|
+
*/
|
|
9
|
+
export class FileNotFoundException extends Error {
|
|
10
|
+
path;
|
|
11
|
+
constructor(path) {
|
|
12
|
+
super(`File not found: ${path}`);
|
|
13
|
+
this.name = 'FileNotFoundException';
|
|
14
|
+
this.path = path;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=FileNotFoundException.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileNotFoundException.js","sourceRoot":"","sources":["../../../../src/repository/structs/FileNotFoundException.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IACrC,IAAI,CAAQ;IAErB,YAAY,IAAY;QACtB,KAAK,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAA;QAChC,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAA;QACnC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;IAClB,CAAC;CACF"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Access-layer Transfer — metadata of a single file or directory.
|
|
3
|
+
* Mirrors `node:fs` `Stats` but reduced to the surface XF artefacts
|
|
4
|
+
* actually consume.
|
|
5
|
+
*/
|
|
6
|
+
export interface FileStat {
|
|
7
|
+
/** Absolute path the stat was taken from. */
|
|
8
|
+
path: string;
|
|
9
|
+
/** Size in bytes (0 for directories). */
|
|
10
|
+
size: number;
|
|
11
|
+
/** Last modification time. */
|
|
12
|
+
modifiedAt: Date;
|
|
13
|
+
/** Creation time. May equal `modifiedAt` on filesystems without birth time. */
|
|
14
|
+
createdAt: Date;
|
|
15
|
+
/** Whether the entry is a regular file. */
|
|
16
|
+
isFile: boolean;
|
|
17
|
+
/** Whether the entry is a directory. */
|
|
18
|
+
isDirectory: boolean;
|
|
19
|
+
/** Whether the entry is a symbolic link. */
|
|
20
|
+
isSymlink: boolean;
|
|
21
|
+
/** POSIX-style permission bits (e.g. `0o644`). */
|
|
22
|
+
mode: number;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=FileStat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileStat.d.ts","sourceRoot":"","sources":["../../../../src/repository/structs/FileStat.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAA;IACZ,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAA;IACZ,8BAA8B;IAC9B,UAAU,EAAE,IAAI,CAAA;IAChB,+EAA+E;IAC/E,SAAS,EAAE,IAAI,CAAA;IACf,2CAA2C;IAC3C,MAAM,EAAE,OAAO,CAAA;IACf,wCAAwC;IACxC,WAAW,EAAE,OAAO,CAAA;IACpB,4CAA4C;IAC5C,SAAS,EAAE,OAAO,CAAA;IAClB,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAA;CACb"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileStat.js","sourceRoot":"","sources":["../../../../src/repository/structs/FileStat.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Access-layer Transfer — a temporary file allocated by
|
|
3
|
+
* `FileRepository.tempFile()`. Carries its absolute path plus a
|
|
4
|
+
* `close()` that deletes the file on the disk.
|
|
5
|
+
*
|
|
6
|
+
* Same shape as {@link Watcher}: a resource handle that the caller
|
|
7
|
+
* is responsible for releasing. The owning `FileRepository` also
|
|
8
|
+
* cleans up every tempfile it ever issued on `terminate()`, so even
|
|
9
|
+
* a careless caller won't leak.
|
|
10
|
+
*/
|
|
11
|
+
export interface TempFile {
|
|
12
|
+
/** Absolute path of the temporary file on disk. */
|
|
13
|
+
readonly path: string;
|
|
14
|
+
/** Whether the temp file is still present (false after `close()`). */
|
|
15
|
+
readonly isOpen: boolean;
|
|
16
|
+
/** Delete the file from disk and mark this handle closed. */
|
|
17
|
+
close(): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=TempFile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TempFile.d.ts","sourceRoot":"","sources":["../../../../src/repository/structs/TempFile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,WAAW,QAAQ;IACvB,mDAAmD;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,sEAAsE;IACtE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,6DAA6D;IAC7D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TempFile.js","sourceRoot":"","sources":["../../../../src/repository/structs/TempFile.ts"],"names":[],"mappings":""}
|