@power-plant/schema 0.0.25 → 0.0.26

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.
@@ -0,0 +1,917 @@
1
+ import { EventEmitter } from "node:events";
2
+ import * as nodeFs from "node:fs";
3
+ import { Stats, constants } from "node:fs";
4
+ import { callbackify } from "node:util";
5
+ import { Buffer } from "node:buffer";
6
+ import { MessageChannel, receiveMessageOnPort } from "node:worker_threads";
7
+ import { Readable, Writable } from "node:stream";
8
+
9
+ //#region src/storage/helpers.ts
10
+ function toPathInput(path) {
11
+ if (path instanceof URL) return decodeURIComponent(path.pathname);
12
+ if (Buffer.isBuffer(path)) return path.toString();
13
+ return path;
14
+ }
15
+ function normalizeKey(path) {
16
+ let value = toPathInput(path).replace(/\\/g, "/");
17
+ while (value.startsWith("./")) value = value.slice(2);
18
+ value = value.replace(/^\/+/, "");
19
+ value = value.replace(/\/+/g, "/");
20
+ if (value.length > 1 && value.endsWith("/")) value = value.slice(0, -1);
21
+ return value;
22
+ }
23
+ function resolveKey(...segments) {
24
+ const parts = [];
25
+ for (const segment of segments) for (const part of normalizeKey(segment).split("/")) {
26
+ if (!part || part === ".") continue;
27
+ if (part === "..") {
28
+ parts.pop();
29
+ continue;
30
+ }
31
+ parts.push(part);
32
+ }
33
+ return parts.join("/");
34
+ }
35
+ function dirname(key) {
36
+ const index = key.lastIndexOf("/");
37
+ return index === -1 ? "" : key.slice(0, index);
38
+ }
39
+ function basename(key) {
40
+ const index = key.lastIndexOf("/");
41
+ return index === -1 ? key : key.slice(index + 1);
42
+ }
43
+ function isMetaStorageKey(key) {
44
+ return key.endsWith("$");
45
+ }
46
+ function parentPrefix(key) {
47
+ return key ? `${key}/` : "";
48
+ }
49
+ function getImmediateChildren(base, keys) {
50
+ const prefix = parentPrefix(base);
51
+ const children = /* @__PURE__ */ new Set();
52
+ for (const key of keys) {
53
+ if (isMetaStorageKey(key)) continue;
54
+ const relative = prefix ? key.startsWith(prefix) ? key.slice(prefix.length) : "" : key;
55
+ if (!relative || relative === key) continue;
56
+ const slashIndex = relative.indexOf("/");
57
+ children.add(slashIndex === -1 ? relative : relative.slice(0, slashIndex));
58
+ }
59
+ return [...children].sort();
60
+ }
61
+ function createFsError(code, syscall, path, message) {
62
+ const suffix = path ? ` '${path}'` : "";
63
+ const error = new Error(message ?? `${code}: ${syscall}${suffix}`);
64
+ error.code = code;
65
+ error.syscall = syscall;
66
+ if (path) error.path = path;
67
+ return error;
68
+ }
69
+ function runSync(operation) {
70
+ const { port1, port2 } = new MessageChannel();
71
+ operation().then((value) => {
72
+ port1.postMessage({
73
+ ok: true,
74
+ value
75
+ });
76
+ }, (error) => {
77
+ port1.postMessage({
78
+ ok: false,
79
+ error
80
+ });
81
+ });
82
+ const response = receiveMessageOnPort(port2);
83
+ port1.close();
84
+ port2.close();
85
+ if (!response) throw new Error("Storage operation did not complete.");
86
+ if (!response.message.ok) throw response.message.error;
87
+ return response.message.value;
88
+ }
89
+ function toBuffer(value) {
90
+ if (value == null) return Buffer.alloc(0);
91
+ if (Buffer.isBuffer(value)) return value;
92
+ if (value instanceof Uint8Array) return Buffer.from(value);
93
+ return Buffer.from(value);
94
+ }
95
+ function getEncoding(options) {
96
+ if (typeof options === "string") return options;
97
+ if (options == null) return;
98
+ return options.encoding ?? void 0;
99
+ }
100
+ function shouldReadRaw(options) {
101
+ const encoding = getEncoding(options);
102
+ return encoding === void 0 || encoding === null || encoding === "buffer";
103
+ }
104
+ function decodeStoredValue(value, encoding) {
105
+ const buffer = toBuffer(typeof value === "string" || Buffer.isBuffer(value) || value instanceof Uint8Array ? value : value == null ? "" : JSON.stringify(value));
106
+ if (encoding === void 0 || encoding === null || encoding === "buffer") return buffer;
107
+ return buffer.toString(encoding);
108
+ }
109
+ function encodeWriteValue(data) {
110
+ if (typeof data === "string") return data;
111
+ return toBuffer(Buffer.from(data.buffer, data.byteOffset, data.byteLength));
112
+ }
113
+ function createStats(type, meta, size = 0) {
114
+ const now = Date.now();
115
+ const atime = meta?.atime instanceof Date ? meta.atime : new Date(now);
116
+ const mtime = meta?.mtime instanceof Date ? meta.mtime : new Date(now);
117
+ const mode = type === "directory" ? 16877 : type === "symlink" ? 41471 : 33188;
118
+ const stat = Object.create(Stats.prototype);
119
+ Object.assign(stat, {
120
+ dev: 0,
121
+ ino: 0,
122
+ mode,
123
+ nlink: 1,
124
+ uid: typeof meta?.uid === "number" ? meta.uid : 0,
125
+ gid: typeof meta?.gid === "number" ? meta.gid : 0,
126
+ rdev: 0,
127
+ size,
128
+ blksize: 4096,
129
+ blocks: Math.ceil(size / 512),
130
+ atimeMs: atime.getTime(),
131
+ mtimeMs: mtime.getTime(),
132
+ ctimeMs: mtime.getTime(),
133
+ birthtimeMs: mtime.getTime(),
134
+ atime,
135
+ mtime,
136
+ ctime: mtime,
137
+ birthtime: mtime
138
+ });
139
+ return stat;
140
+ }
141
+ function matchesGlobPattern(pattern, value) {
142
+ return new RegExp(`^${pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*").replace(/\?/g, ".")}$`).test(value);
143
+ }
144
+ function randomSuffix(length = 6) {
145
+ return Array.from({ length }, () => "abcdefghijklmnopqrstuvwxyz0123456789".charAt(Math.floor(Math.random() * 36))).join("");
146
+ }
147
+
148
+ //#endregion
149
+ //#region src/storage/promises.ts
150
+ const SYMLINK_META_KEY = "symlinkTarget";
151
+ function createStoragePromises(storage) {
152
+ const openDescriptors = /* @__PURE__ */ new Map();
153
+ let nextDescriptor = 3;
154
+ async function getMetaSafe(key) {
155
+ try {
156
+ return await storage.getMeta(key) ?? null;
157
+ } catch {
158
+ return null;
159
+ }
160
+ }
161
+ async function getEntry(path, followSymlinks = true) {
162
+ const key = normalizeKey(path);
163
+ if (!key && path !== "." && path !== "/") return null;
164
+ const meta = await getMetaSafe(key);
165
+ if (meta?.[SYMLINK_META_KEY] && typeof meta[SYMLINK_META_KEY] === "string") {
166
+ if (!followSymlinks) return {
167
+ key,
168
+ type: "symlink",
169
+ meta
170
+ };
171
+ return getEntry(meta[SYMLINK_META_KEY], true);
172
+ }
173
+ if (await storage.hasItem(key)) return {
174
+ key,
175
+ type: "file",
176
+ meta
177
+ };
178
+ if (getImmediateChildren(key, (await storage.getKeys(key)).filter((storageKey) => storageKey !== key && !isMetaStorageKey(storageKey))).length > 0) return {
179
+ key,
180
+ type: "directory",
181
+ meta
182
+ };
183
+ return null;
184
+ }
185
+ async function requireEntry(path, followSymlinks = true) {
186
+ const entry = await getEntry(path, followSymlinks);
187
+ if (!entry) throw createFsError("ENOENT", "stat", normalizeKey(path));
188
+ return entry;
189
+ }
190
+ async function getFileSize(key) {
191
+ const meta = await getMetaSafe(key);
192
+ if (typeof meta?.size === "number") return meta.size;
193
+ if (shouldReadRaw()) {
194
+ const raw = await storage.getItemRaw(key);
195
+ return raw == null ? 0 : toBuffer(raw).byteLength;
196
+ }
197
+ const value = await storage.getItem(key);
198
+ return value == null ? 0 : toBuffer(String(value)).byteLength;
199
+ }
200
+ async function readStoredFile(path, options) {
201
+ const key = normalizeKey(path);
202
+ if ((await requireEntry(key, true)).type !== "file") throw createFsError("EISDIR", "read", key, "EISDIR: illegal operation on a directory, read");
203
+ const encoding = getEncoding(options);
204
+ const value = shouldReadRaw(options) ? await storage.getItemRaw(key) : await storage.getItem(key);
205
+ if (value == null) throw createFsError("ENOENT", "open", key);
206
+ return decodeStoredValue(value, encoding);
207
+ }
208
+ async function writeStoredFile(path, data, options) {
209
+ const key = normalizeKey(path);
210
+ const encoding = getEncoding(options);
211
+ const payload = typeof data === "string" ? data : encoding && encoding !== "buffer" ? toBuffer(encodeWriteValue(data)).toString(encoding) : encodeWriteValue(data);
212
+ await storage.setItem(key, payload);
213
+ await storage.setMeta(key, {
214
+ mtime: /* @__PURE__ */ new Date(),
215
+ atime: /* @__PURE__ */ new Date(),
216
+ size: toBuffer(payload).byteLength
217
+ });
218
+ }
219
+ async function removePath(path, options) {
220
+ const key = normalizeKey(path);
221
+ const entry = await getEntry(key, false);
222
+ if (!entry) {
223
+ if (typeof options === "object" && options && "recursive" in options && options.recursive) return;
224
+ throw createFsError("ENOENT", "unlink", key);
225
+ }
226
+ if (entry.type === "directory") {
227
+ const recursive = options === true || (typeof options === "object" && options && "recursive" in options ? Boolean(options.recursive) : false);
228
+ const descendants = (await storage.getKeys(key)).filter((storageKey) => storageKey !== key && !isMetaStorageKey(storageKey) && storageKey.startsWith(parentPrefix(key)));
229
+ if (!recursive && descendants.length > 0) throw createFsError("ENOTEMPTY", "rmdir", key);
230
+ await Promise.all(descendants.map(async (descendant) => storage.removeItem(descendant)));
231
+ if (await storage.hasItem(key)) await storage.removeItem(key);
232
+ return;
233
+ }
234
+ await storage.removeItem(key);
235
+ }
236
+ async function copyEntry(source, destination, recursive = false) {
237
+ if ((await requireEntry(source, true)).type === "directory") {
238
+ if (!recursive) throw createFsError("EISDIR", "copy", source, "EISDIR: illegal operation on a directory, copy");
239
+ const keys = await storage.getKeys(source);
240
+ for (const key of keys) {
241
+ if (isMetaStorageKey(key) || key === source) continue;
242
+ await copyEntry(key, resolveKey(destination, key.slice(source.length).replace(/^\//, "")), true);
243
+ }
244
+ return;
245
+ }
246
+ const content = await readStoredFile(source);
247
+ await writeStoredFile(destination, typeof content === "string" ? content : toBuffer(content));
248
+ const meta = await getMetaSafe(source);
249
+ if (meta) await storage.setMeta(normalizeKey(destination), meta);
250
+ }
251
+ async function statPath(path, followSymlinks = true) {
252
+ const entry = await requireEntry(path, followSymlinks);
253
+ const size = entry.type === "file" ? await getFileSize(entry.key) : 4096;
254
+ return createStats(entry.type, entry.meta, size);
255
+ }
256
+ async function chmodPath(path, mode) {
257
+ const key = normalizeKey(path);
258
+ await requireEntry(key, true);
259
+ await storage.setMeta(key, { mode });
260
+ }
261
+ async function chownPath(path, uid, gid) {
262
+ const key = normalizeKey(path);
263
+ await requireEntry(key, true);
264
+ await storage.setMeta(key, {
265
+ uid,
266
+ gid
267
+ });
268
+ }
269
+ async function mkdirPath(path, options) {
270
+ const key = normalizeKey(path);
271
+ const recursive = typeof options === "object" && options ? Boolean(options.recursive) : false;
272
+ if (!key) return;
273
+ const parent = dirname(key);
274
+ if (parent) {
275
+ const parentEntry = await getEntry(parent, true);
276
+ if (!parentEntry && !recursive) throw createFsError("ENOENT", "mkdir", key);
277
+ if (!parentEntry && recursive) await mkdirPath(parent, { recursive: true });
278
+ }
279
+ if ((await getEntry(key, true))?.type === "file") throw createFsError("EEXIST", "mkdir", key);
280
+ }
281
+ async function mkdtempPath(prefix, options) {
282
+ const directory = `${normalizeKey(prefix)}${randomSuffix()}`;
283
+ await mkdirPath(directory, { recursive: true });
284
+ if (options?.encoding === "buffer") return Buffer.from(directory);
285
+ return directory;
286
+ }
287
+ function createDir(path, options) {
288
+ const key = normalizeKey(path);
289
+ let entries = [];
290
+ let loaded = false;
291
+ let index = 0;
292
+ let closed = false;
293
+ const loadEntries = async () => {
294
+ if (loaded) return;
295
+ await requireEntry(key, true);
296
+ const keys = await storage.getKeys(key);
297
+ entries = getImmediateChildren(key, keys.filter((storageKey) => !isMetaStorageKey(storageKey)));
298
+ loaded = true;
299
+ };
300
+ const toDirent = (name) => ({
301
+ name,
302
+ isFile: () => true,
303
+ isDirectory: () => false,
304
+ isBlockDevice: () => false,
305
+ isCharacterDevice: () => false,
306
+ isSymbolicLink: () => false,
307
+ isFIFO: () => false,
308
+ isSocket: () => false
309
+ });
310
+ return {
311
+ path: key,
312
+ async read() {
313
+ if (closed) throw createFsError("EBADF", "readdir", key);
314
+ await loadEntries();
315
+ if (index >= entries.length) return null;
316
+ const name = entries[index++];
317
+ if (options?.encoding === "buffer") return Buffer.from(name);
318
+ return toDirent(name);
319
+ },
320
+ async close() {
321
+ closed = true;
322
+ },
323
+ async *[Symbol.asyncIterator]() {
324
+ while (true) {
325
+ const entry = await this.read();
326
+ if (!entry) break;
327
+ yield entry;
328
+ }
329
+ }
330
+ };
331
+ }
332
+ function createReadStream(path, options) {
333
+ const key = normalizeKey(path);
334
+ const start = options?.start ?? 0;
335
+ const end = options?.end;
336
+ return Readable.from((async function* () {
337
+ let content = toBuffer(await readStoredFile(key));
338
+ if (start > 0) content = content.subarray(start);
339
+ if (end != null) {
340
+ yield content.subarray(0, Math.max(0, end - start + 1));
341
+ return;
342
+ }
343
+ yield content;
344
+ })());
345
+ }
346
+ function createWriteStream(path, options) {
347
+ const key = normalizeKey(path);
348
+ const chunks = [];
349
+ return new Writable({
350
+ write(chunk, _encoding, callback) {
351
+ chunks.push(toBuffer(chunk));
352
+ callback();
353
+ },
354
+ final: (callback) => {
355
+ const content = Buffer.concat(chunks);
356
+ const payload = options?.encoding && options.encoding !== "buffer" ? content.toString(options.encoding) : content;
357
+ writeStoredFile(key, payload, options).then(() => callback()).catch((error) => callback(error));
358
+ }
359
+ });
360
+ }
361
+ function createFileHandle(descriptor, key) {
362
+ const getDescriptor = () => {
363
+ const current = openDescriptors.get(descriptor);
364
+ if (!current) throw createFsError("EBADF", "read", key);
365
+ return current;
366
+ };
367
+ return {
368
+ fd: descriptor,
369
+ async appendFile(data, options) {
370
+ const current = await readStoredFile(key).catch(() => Buffer.alloc(0));
371
+ await writeStoredFile(key, Buffer.concat([toBuffer(current), toBuffer(typeof data === "string" ? data : encodeWriteValue(data))]), options);
372
+ },
373
+ async chmod(_mode) {},
374
+ async chown(_uid, _gid) {},
375
+ async close() {
376
+ openDescriptors.delete(descriptor);
377
+ },
378
+ createReadStream(options) {
379
+ return createReadStream(key, options);
380
+ },
381
+ createWriteStream(options) {
382
+ return createWriteStream(key, options);
383
+ },
384
+ async datasync() {},
385
+ async read(buffer, offset, length, position) {
386
+ const current = getDescriptor();
387
+ const content = toBuffer(await readStoredFile(key, { encoding: void 0 }));
388
+ const readPosition = position ?? current.position;
389
+ const readOffset = offset ?? 0;
390
+ const readLength = length ?? buffer.length - readOffset;
391
+ const bytesRead = content.copy(buffer, readOffset, readPosition, readPosition + readLength);
392
+ if (position === null || position === void 0) current.position += bytesRead;
393
+ return {
394
+ bytesRead,
395
+ buffer
396
+ };
397
+ },
398
+ async readFile(options) {
399
+ return readStoredFile(key, options);
400
+ },
401
+ async stat(_options) {
402
+ return statPath(key);
403
+ },
404
+ async sync() {},
405
+ async truncate(len = 0) {
406
+ await writeStoredFile(key, toBuffer(await readStoredFile(key)).subarray(0, len));
407
+ },
408
+ async utimes(_atime, _mtime) {
409
+ await storage.setMeta(key, {
410
+ atime: new Date(_atime),
411
+ mtime: new Date(_mtime)
412
+ });
413
+ },
414
+ async write(buffer, offset, length, position) {
415
+ const current = getDescriptor();
416
+ const content = toBuffer(await readStoredFile(key).catch(() => ""));
417
+ const writeOffset = offset ?? 0;
418
+ const writeLength = length ?? buffer.length - writeOffset;
419
+ const writePosition = position ?? current.position;
420
+ buffer.copy(content, writePosition, writeOffset, writeOffset + writeLength);
421
+ await writeStoredFile(key, content);
422
+ if (position === null || position === void 0) current.position += writeLength;
423
+ return {
424
+ bytesWritten: writeLength,
425
+ buffer
426
+ };
427
+ },
428
+ async writeFile(data, options) {
429
+ await writeStoredFile(key, typeof data === "string" ? data : encodeWriteValue(data), options);
430
+ }
431
+ };
432
+ }
433
+ const promises = {
434
+ async access(path, mode = constants.F_OK) {
435
+ const entry = await getEntry(path, true);
436
+ if (!entry) throw createFsError("ENOENT", "access", normalizeKey(path));
437
+ if (mode & constants.W_OK && entry.type === "directory") throw createFsError("EISDIR", "access", normalizeKey(path));
438
+ },
439
+ async appendFile(path, data, options) {
440
+ const key = normalizeKey(path);
441
+ const current = await readStoredFile(key).catch(() => "");
442
+ await writeStoredFile(key, Buffer.concat([toBuffer(current), toBuffer(typeof data === "string" ? data : encodeWriteValue(data))]), options);
443
+ },
444
+ async chmod(path, mode) {
445
+ const key = normalizeKey(path);
446
+ await requireEntry(key, true);
447
+ await storage.setMeta(key, { mode });
448
+ },
449
+ async chown(path, uid, gid) {
450
+ const key = normalizeKey(path);
451
+ await requireEntry(key, true);
452
+ await storage.setMeta(key, {
453
+ uid,
454
+ gid
455
+ });
456
+ },
457
+ async copyFile(src, dest, _mode) {
458
+ await copyEntry(normalizeKey(src), normalizeKey(dest), false);
459
+ },
460
+ async cp(src, dest, options) {
461
+ await copyEntry(normalizeKey(src), normalizeKey(dest), Boolean(options?.recursive));
462
+ },
463
+ async glob(pattern, options) {
464
+ const cwd = normalizeKey(options?.cwd ?? ".");
465
+ const matches = (await storage.getKeys(cwd)).filter((key) => !isMetaStorageKey(key)).filter((key) => matchesGlobPattern(String(pattern), key));
466
+ async function* iterator() {
467
+ for (const match of matches) if (options && "withFileTypes" in options && options.withFileTypes) {
468
+ const entry = await getEntry(match, true);
469
+ yield {
470
+ name: basename(match),
471
+ relative: match.slice(cwd.length).replace(/^\//, ""),
472
+ absolute: match,
473
+ isFile: () => entry?.type === "file",
474
+ isDirectory: () => entry?.type === "directory",
475
+ isSymbolicLink: () => entry?.type === "symlink"
476
+ };
477
+ } else yield match;
478
+ }
479
+ return iterator();
480
+ },
481
+ async lchmod(path, mode) {
482
+ await chmodPath(path, mode);
483
+ },
484
+ async lchown(path, uid, gid) {
485
+ await chownPath(path, uid, gid);
486
+ },
487
+ async lutimes(path, atime, mtime) {
488
+ const key = normalizeKey(path);
489
+ await requireEntry(key, false);
490
+ await storage.setMeta(key, {
491
+ atime: new Date(atime),
492
+ mtime: new Date(mtime)
493
+ });
494
+ },
495
+ async link(existingPath, newPath) {
496
+ const source = normalizeKey(existingPath);
497
+ const destination = normalizeKey(newPath);
498
+ const content = await readStoredFile(source);
499
+ await writeStoredFile(destination, typeof content === "string" ? content : toBuffer(content));
500
+ },
501
+ async lstat(path, _options) {
502
+ return statPath(path, false);
503
+ },
504
+ async mkdir(path, options) {
505
+ return mkdirPath(path, options);
506
+ },
507
+ async mkdtemp(prefix, options) {
508
+ return mkdtempPath(prefix, options);
509
+ },
510
+ async mkdtempDisposable(prefix, options) {
511
+ const directory = await mkdtempPath(prefix, options);
512
+ return {
513
+ path: directory,
514
+ async [Symbol.asyncDispose]() {
515
+ await removePath(directory, {
516
+ recursive: true,
517
+ force: true
518
+ });
519
+ },
520
+ [Symbol.dispose]() {
521
+ runSync(async () => removePath(directory, {
522
+ recursive: true,
523
+ force: true
524
+ }));
525
+ }
526
+ };
527
+ },
528
+ async open(path, _flags, _mode) {
529
+ const key = normalizeKey(path);
530
+ await requireEntry(key, true).catch(async (error) => {
531
+ if (error.code === "ENOENT") {
532
+ await writeStoredFile(key, "");
533
+ return;
534
+ }
535
+ throw error;
536
+ });
537
+ const descriptor = nextDescriptor++;
538
+ openDescriptors.set(descriptor, {
539
+ key,
540
+ position: 0
541
+ });
542
+ return createFileHandle(descriptor, key);
543
+ },
544
+ async opendir(path, options) {
545
+ return createDir(path, options);
546
+ },
547
+ async readdir(path, options) {
548
+ const key = normalizeKey(path);
549
+ await requireEntry(key, true);
550
+ const keys = await storage.getKeys(key);
551
+ let children = getImmediateChildren(key, keys.filter((storageKey) => !isMetaStorageKey(storageKey)));
552
+ if (options && typeof options === "object" && "recursive" in options && options.recursive) children = keys.filter((storageKey) => !isMetaStorageKey(storageKey)).map((storageKey) => storageKey.slice(key.length).replace(/^\//, "")).filter(Boolean);
553
+ if (options && typeof options === "object" && "withFileTypes" in options && options.withFileTypes) return await Promise.all(children.map(async (name) => {
554
+ const entry = await getEntry(resolveKey(key, name), true);
555
+ return {
556
+ name,
557
+ isFile: () => entry?.type === "file",
558
+ isDirectory: () => entry?.type === "directory",
559
+ isBlockDevice: () => false,
560
+ isCharacterDevice: () => false,
561
+ isSymbolicLink: () => entry?.type === "symlink",
562
+ isFIFO: () => false,
563
+ isSocket: () => false
564
+ };
565
+ }));
566
+ if (options && typeof options === "object" && "encoding" in options && options.encoding === "buffer") return children.map((name) => Buffer.from(name));
567
+ return children;
568
+ },
569
+ async readFile(path, options) {
570
+ return readStoredFile(path, options);
571
+ },
572
+ async readlink(path, options) {
573
+ const key = normalizeKey(path);
574
+ const entry = await requireEntry(key, false);
575
+ if (entry.type !== "symlink") throw createFsError("EINVAL", "readlink", key);
576
+ const target = entry.meta?.[SYMLINK_META_KEY];
577
+ if (typeof target !== "string") throw createFsError("EINVAL", "readlink", key);
578
+ if (options && typeof options === "object" && options.encoding === "buffer") return Buffer.from(target);
579
+ return target;
580
+ },
581
+ async realpath(path, options) {
582
+ const resolved = resolveKey(path);
583
+ if (!await getEntry(resolved, true)) throw createFsError("ENOENT", "realpath", resolved);
584
+ if (options && typeof options === "object" && options.encoding === "buffer") return Buffer.from(resolved);
585
+ return resolved;
586
+ },
587
+ async rename(oldPath, newPath) {
588
+ const source = normalizeKey(oldPath);
589
+ const destination = normalizeKey(newPath);
590
+ if ((await requireEntry(source, true)).type === "directory") {
591
+ const keys = await storage.getKeys(source);
592
+ for (const key of keys) {
593
+ if (isMetaStorageKey(key)) continue;
594
+ const relative = key === source ? "" : key.slice(source.length).replace(/^\//, "");
595
+ const target = relative ? resolveKey(destination, relative) : destination;
596
+ if (key === source && await storage.hasItem(key)) {
597
+ const value = await storage.getItem(key);
598
+ if (value != null) await storage.setItem(target, value);
599
+ } else if (key !== source) {
600
+ const value = await storage.getItem(key);
601
+ if (value != null) await storage.setItem(target, value);
602
+ const meta = await getMetaSafe(key);
603
+ if (meta) await storage.setMeta(target, meta);
604
+ await storage.removeItem(key);
605
+ }
606
+ }
607
+ if (await storage.hasItem(source)) await storage.removeItem(source);
608
+ return;
609
+ }
610
+ const content = await storage.getItem(source);
611
+ if (content != null) await storage.setItem(destination, content);
612
+ const meta = await getMetaSafe(source);
613
+ if (meta) await storage.setMeta(destination, meta);
614
+ await storage.removeItem(source);
615
+ },
616
+ async rm(path, options) {
617
+ await removePath(path, options);
618
+ },
619
+ async rmdir(path, options) {
620
+ await removePath(path, options);
621
+ },
622
+ async stat(path, _options) {
623
+ return statPath(path);
624
+ },
625
+ async statfs(path, _options) {
626
+ const keys = await storage.getKeys(normalizeKey(path));
627
+ const stats = Object.create(Stats.prototype);
628
+ Object.assign(stats, {
629
+ type: 0,
630
+ bsize: 4096,
631
+ blocks: keys.length,
632
+ bfree: 0,
633
+ bavail: 0,
634
+ files: keys.length,
635
+ ffree: 0
636
+ });
637
+ return stats;
638
+ },
639
+ async symlink(target, path, _type) {
640
+ const key = normalizeKey(path);
641
+ await storage.setMeta(key, {
642
+ [SYMLINK_META_KEY]: normalizeKey(target),
643
+ mtime: /* @__PURE__ */ new Date(),
644
+ atime: /* @__PURE__ */ new Date()
645
+ });
646
+ },
647
+ async truncate(path, len = 0) {
648
+ const key = normalizeKey(path);
649
+ await writeStoredFile(key, toBuffer(await readStoredFile(key)).subarray(0, len));
650
+ },
651
+ async unlink(path) {
652
+ const key = normalizeKey(path);
653
+ const entry = await getEntry(key, false);
654
+ if (!entry) throw createFsError("ENOENT", "unlink", key);
655
+ if (entry.type === "directory") throw createFsError("EISDIR", "unlink", key);
656
+ await storage.removeItem(key);
657
+ },
658
+ async utimes(path, atime, mtime) {
659
+ const key = normalizeKey(path);
660
+ await requireEntry(key, true);
661
+ await storage.setMeta(key, {
662
+ atime: new Date(atime),
663
+ mtime: new Date(mtime)
664
+ });
665
+ },
666
+ async watch(path, options) {
667
+ const key = normalizeKey(path);
668
+ const unwatch = await storage.watch((event, watchedKey) => {
669
+ if (watchedKey === key || watchedKey.startsWith(parentPrefix(key))) (typeof options === "function" ? options : options.listener)?.(event, watchedKey);
670
+ });
671
+ return {
672
+ async close() {
673
+ await unwatch();
674
+ },
675
+ [Symbol.asyncDispose]: async () => {
676
+ await unwatch();
677
+ }
678
+ };
679
+ },
680
+ async writeFile(path, data, options) {
681
+ await writeStoredFile(path, data, options);
682
+ }
683
+ };
684
+ async function openFd(path, flags, mode) {
685
+ return (await promises.open(path, flags, mode)).fd;
686
+ }
687
+ async function closeFd(fd) {
688
+ if (!openDescriptors.has(fd)) throw createFsError("EBADF", "close");
689
+ openDescriptors.delete(fd);
690
+ }
691
+ async function fstatFd(fd, _options) {
692
+ const descriptor = openDescriptors.get(fd);
693
+ if (!descriptor) throw createFsError("EBADF", "fstat");
694
+ return statPath(descriptor.key);
695
+ }
696
+ async function readFd(fd, buffer, offset, length, position) {
697
+ const descriptor = openDescriptors.get(fd);
698
+ if (!descriptor) throw createFsError("EBADF", "read");
699
+ return createFileHandle(fd, descriptor.key).read(buffer, offset, length, position);
700
+ }
701
+ async function writeFd(fd, buffer, offset, length, position) {
702
+ const descriptor = openDescriptors.get(fd);
703
+ if (!descriptor) throw createFsError("EBADF", "write");
704
+ return createFileHandle(fd, descriptor.key).write(buffer, offset, length, position);
705
+ }
706
+ async function ftruncateFd(fd, len = 0) {
707
+ const descriptor = openDescriptors.get(fd);
708
+ if (!descriptor) throw createFsError("EBADF", "ftruncate");
709
+ await promises.truncate(descriptor.key, len);
710
+ }
711
+ async function futimesFd(fd, atime, mtime) {
712
+ const descriptor = openDescriptors.get(fd);
713
+ if (!descriptor) throw createFsError("EBADF", "futimes");
714
+ await promises.utimes(descriptor.key, atime, mtime);
715
+ }
716
+ async function readvFd(fd, buffers, position) {
717
+ let offset = 0;
718
+ let readPosition = position ?? openDescriptors.get(fd)?.position ?? 0;
719
+ for (const view of buffers) {
720
+ const buffer = Buffer.from(view.buffer, view.byteOffset, view.byteLength);
721
+ const result = await readFd(fd, buffer, 0, buffer.length, readPosition);
722
+ offset += result.bytesRead;
723
+ readPosition += result.bytesRead;
724
+ }
725
+ return {
726
+ bytesRead: offset,
727
+ buffers
728
+ };
729
+ }
730
+ async function writevFd(fd, buffers, position) {
731
+ const content = Buffer.concat(buffers.map((view) => Buffer.from(view.buffer, view.byteOffset, view.byteLength)));
732
+ const descriptor = openDescriptors.get(fd);
733
+ if (!descriptor) throw createFsError("EBADF", "writev");
734
+ const writePosition = position ?? descriptor.position;
735
+ const existing = toBuffer(await readStoredFile(descriptor.key).catch(() => ""));
736
+ content.copy(existing, writePosition);
737
+ await writeStoredFile(descriptor.key, existing);
738
+ if (position == null) descriptor.position += content.byteLength;
739
+ return {
740
+ bytesWritten: content.byteLength,
741
+ buffers
742
+ };
743
+ }
744
+ return {
745
+ promises,
746
+ createReadStream,
747
+ createWriteStream,
748
+ openFd,
749
+ closeFd,
750
+ fstatFd,
751
+ readFd,
752
+ writeFd,
753
+ ftruncateFd,
754
+ futimesFd,
755
+ readvFd,
756
+ writevFd
757
+ };
758
+ }
759
+
760
+ //#endregion
761
+ //#region src/storage/index.ts
762
+ function bindCallback(fn) {
763
+ const callback = callbackify(fn);
764
+ callback.__promisify__ = fn;
765
+ return callback;
766
+ }
767
+ function createNoopAsync() {
768
+ return async () => void 0;
769
+ }
770
+ function createNoopSync() {
771
+ return () => void 0;
772
+ }
773
+ function mapStorageToFileSystem(storage) {
774
+ const core = createStoragePromises(storage);
775
+ const { promises } = core;
776
+ const globAsync = async (...args) => {
777
+ const iterator = promises.glob(...args);
778
+ const results = [];
779
+ for await (const entry of iterator) results.push(typeof entry === "string" ? entry : "absolute" in entry ? String(entry.absolute) : String(entry));
780
+ return results;
781
+ };
782
+ const watchEmitter = (path) => {
783
+ const watcher = new EventEmitter();
784
+ storage.watch((event, key) => {
785
+ const normalized = normalizeKey(path);
786
+ if (key === normalized || key.startsWith(`${normalized}/`)) watcher.emit("change", event, key);
787
+ }).then((unwatch) => {
788
+ watcher.on("close", () => {
789
+ unwatch();
790
+ });
791
+ });
792
+ return watcher;
793
+ };
794
+ return {
795
+ promises,
796
+ access: bindCallback(promises.access),
797
+ appendFile: bindCallback(promises.appendFile),
798
+ chmod: bindCallback(promises.chmod),
799
+ chown: bindCallback(promises.chown),
800
+ close: bindCallback(core.closeFd),
801
+ copyFile: bindCallback(promises.copyFile),
802
+ cp: bindCallback(promises.cp),
803
+ createReadStream: core.createReadStream,
804
+ createWriteStream: core.createWriteStream,
805
+ exists: ((path, callback) => {
806
+ promises.access(path).then(() => callback(true)).catch(() => callback(false));
807
+ }),
808
+ fchmod: bindCallback(createNoopAsync()),
809
+ fchown: bindCallback(createNoopAsync()),
810
+ fdatasync: bindCallback(createNoopAsync()),
811
+ fstat: bindCallback(core.fstatFd),
812
+ fsync: bindCallback(createNoopAsync()),
813
+ ftruncate: bindCallback(core.ftruncateFd),
814
+ futimes: bindCallback(core.futimesFd),
815
+ glob: bindCallback(globAsync),
816
+ lchmod: bindCallback(promises.lchmod),
817
+ lchown: bindCallback(promises.lchown),
818
+ lutimes: bindCallback(promises.lutimes),
819
+ link: bindCallback(promises.link),
820
+ lstat: bindCallback(promises.lstat),
821
+ mkdir: bindCallback(promises.mkdir),
822
+ mkdtemp: bindCallback(promises.mkdtemp),
823
+ open: bindCallback(core.openFd),
824
+ openAsBlob: bindCallback(async (path) => {
825
+ const content = await promises.readFile(path);
826
+ return new Blob([content]);
827
+ }),
828
+ opendir: bindCallback(promises.opendir),
829
+ read: bindCallback(core.readFd),
830
+ readdir: bindCallback(promises.readdir),
831
+ readFile: bindCallback(promises.readFile),
832
+ readlink: bindCallback(promises.readlink),
833
+ readv: bindCallback(core.readvFd),
834
+ realpath: bindCallback(promises.realpath),
835
+ rename: bindCallback(promises.rename),
836
+ rmdir: bindCallback(promises.rmdir),
837
+ rm: bindCallback(promises.rm),
838
+ stat: bindCallback(promises.stat),
839
+ statfs: bindCallback(promises.statfs),
840
+ symlink: bindCallback(promises.symlink),
841
+ truncate: bindCallback(promises.truncate),
842
+ unlink: bindCallback(promises.unlink),
843
+ unwatchFile: nodeFs.unwatchFile,
844
+ utimes: bindCallback(promises.utimes),
845
+ watch: ((path, options, listener) => {
846
+ const watcher = watchEmitter(path);
847
+ const attachListener = (handler) => {
848
+ watcher.on("change", handler);
849
+ };
850
+ if (typeof options === "function") {
851
+ attachListener(options);
852
+ return watcher;
853
+ }
854
+ if (typeof listener === "function") attachListener(listener);
855
+ else if (options && typeof options === "object" && "listener" in options && typeof options.listener === "function") attachListener(options.listener);
856
+ return watcher;
857
+ }),
858
+ watchFile: nodeFs.watchFile,
859
+ write: bindCallback(core.writeFd),
860
+ writeFile: bindCallback(promises.writeFile),
861
+ writev: bindCallback(core.writevFd),
862
+ accessSync: ((path, mode) => runSync(async () => promises.access(path, mode))),
863
+ appendFileSync: ((path, data, options) => runSync(async () => promises.appendFile(path, data, options))),
864
+ chmodSync: ((path, mode) => runSync(async () => promises.chmod(path, mode))),
865
+ chownSync: ((path, uid, gid) => runSync(async () => promises.chown(path, uid, gid))),
866
+ closeSync: ((fd) => runSync(async () => core.closeFd(fd))),
867
+ copyFileSync: ((src, dest, mode) => runSync(async () => promises.copyFile(src, dest, mode))),
868
+ cpSync: ((src, dest, options) => runSync(async () => promises.cp(src, dest, options))),
869
+ existsSync: ((path) => {
870
+ try {
871
+ runSync(async () => promises.access(path));
872
+ return true;
873
+ } catch {
874
+ return false;
875
+ }
876
+ }),
877
+ fchmodSync: createNoopSync(),
878
+ fchownSync: createNoopSync(),
879
+ fdatasyncSync: createNoopSync(),
880
+ fstatSync: ((fd, options) => runSync(async () => core.fstatFd(fd, options))),
881
+ fsyncSync: createNoopSync(),
882
+ ftruncateSync: ((fd, len) => runSync(async () => core.ftruncateFd(fd, len))),
883
+ futimesSync: ((fd, atime, mtime) => runSync(async () => core.futimesFd(fd, atime, mtime))),
884
+ globSync: ((pattern, options) => runSync(async () => globAsync(pattern, options))),
885
+ lchmodSync: ((path, mode) => runSync(async () => promises.lchmod(path, mode))),
886
+ lchownSync: ((path, uid, gid) => runSync(async () => promises.lchown(path, uid, gid))),
887
+ lutimesSync: ((path, atime, mtime) => runSync(async () => promises.lutimes(path, atime, mtime))),
888
+ linkSync: ((existingPath, newPath) => runSync(async () => promises.link(existingPath, newPath))),
889
+ lstatSync: ((path, options) => runSync(async () => promises.lstat(path, options))),
890
+ mkdirSync: ((path, options) => runSync(async () => promises.mkdir(path, options))),
891
+ mkdtempSync: ((prefix, options) => runSync(async () => promises.mkdtemp(prefix, options))),
892
+ openSync: ((path, flags, mode) => runSync(async () => core.openFd(path, flags, mode ?? void 0))),
893
+ opendirSync: ((path, options) => runSync(async () => promises.opendir(path, options))),
894
+ readdirSync: ((path, options) => runSync(async () => promises.readdir(path, options))),
895
+ readFileSync: ((path, options) => runSync(async () => promises.readFile(path, options))),
896
+ readlinkSync: ((path, options) => runSync(async () => promises.readlink(path, options))),
897
+ readSync: ((fd, buffer, offset, length, position) => runSync(async () => core.readFd(fd, buffer, offset ?? 0, length ?? buffer.byteLength, position == null ? null : Number(position))).bytesRead),
898
+ readvSync: ((fd, buffers, position) => runSync(async () => core.readvFd(fd, [...buffers], position)).bytesRead),
899
+ realpathSync: ((path, options) => runSync(async () => promises.realpath(path, options))),
900
+ renameSync: ((oldPath, newPath) => runSync(async () => promises.rename(oldPath, newPath))),
901
+ rmdirSync: ((path) => runSync(async () => promises.rm(path, { recursive: false }))),
902
+ rmSync: ((path, options) => runSync(async () => promises.rm(path, options))),
903
+ statSync: ((path, options) => runSync(async () => promises.stat(path, options))),
904
+ statfsSync: ((path, options) => runSync(async () => promises.statfs(path, options))),
905
+ symlinkSync: ((target, path, type) => runSync(async () => promises.symlink(target, path, type))),
906
+ truncateSync: ((path, len) => runSync(async () => promises.truncate(path, len))),
907
+ unlinkSync: ((path) => runSync(async () => promises.unlink(path))),
908
+ utimesSync: ((path, atime, mtime) => runSync(async () => promises.utimes(path, atime, mtime))),
909
+ writeFileSync: ((file, data, options) => runSync(async () => promises.writeFile(file, data, options))),
910
+ writeSync: ((fd, buffer, offset, length, position) => runSync(async () => core.writeFd(fd, buffer, offset ?? 0, length ?? buffer.byteLength, position == null ? null : Number(position))).bytesWritten),
911
+ writevSync: ((fd, buffers, position) => runSync(async () => core.writevFd(fd, [...buffers], position)).bytesWritten)
912
+ };
913
+ }
914
+
915
+ //#endregion
916
+ export { createStoragePromises as n, normalizeKey as r, mapStorageToFileSystem as t };
917
+ //# sourceMappingURL=storage-C3BT2Xh-.mjs.map