@tinycloud/vfs 0.1.0-beta.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/dist/index.cjs ADDED
@@ -0,0 +1,910 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ TinyCloudVfsProvider: () => TinyCloudVfsProvider,
34
+ createTinyCloudDelegatedVfs: () => createTinyCloudDelegatedVfs,
35
+ createTinyCloudVfs: () => createTinyCloudVfs,
36
+ createTinyCloudVfsFromNode: () => createTinyCloudVfsFromNode
37
+ });
38
+ module.exports = __toCommonJS(index_exports);
39
+
40
+ // src/TinyCloudVfsProvider.ts
41
+ var import_node_buffer2 = require("buffer");
42
+ var import_vfs = require("@platformatic/vfs");
43
+
44
+ // src/bridge.ts
45
+ var import_node_worker_threads = require("worker_threads");
46
+ var import_node_path = require("path");
47
+
48
+ // src/errors.ts
49
+ var ERRNO = {
50
+ EPERM: -1,
51
+ ENOENT: -2,
52
+ EIO: -5,
53
+ EBADF: -9,
54
+ EACCES: -13,
55
+ EBUSY: -16,
56
+ EEXIST: -17,
57
+ ENOTDIR: -20,
58
+ EISDIR: -21,
59
+ EINVAL: -22,
60
+ ENOTEMPTY: -39,
61
+ EROFS: -30
62
+ };
63
+ function createNodeError(code, message, syscall, path) {
64
+ const error = new Error(message);
65
+ error.code = code;
66
+ error.errno = ERRNO[code] ?? -1;
67
+ error.syscall = syscall;
68
+ if (path) {
69
+ error.path = path;
70
+ }
71
+ return error;
72
+ }
73
+ function createEISDIR(syscall, path) {
74
+ return createNodeError("EISDIR", `illegal operation on a directory, ${syscall} '${path}'`, syscall, path);
75
+ }
76
+ function createEROFS(syscall, path) {
77
+ return createNodeError("EROFS", `read-only file system, ${syscall} '${path}'`, syscall, path);
78
+ }
79
+ function createEIO(syscall, path, message) {
80
+ return createNodeError("EIO", `${message}, ${syscall} '${path}'`, syscall, path);
81
+ }
82
+ function fromWorkerError(error) {
83
+ return createNodeError(
84
+ error.code,
85
+ error.message,
86
+ error.syscall ?? "vfs",
87
+ error.path
88
+ );
89
+ }
90
+
91
+ // src/bridge.ts
92
+ var import_meta = {};
93
+ var WAIT_SLICE_MS = 1e3;
94
+ function createWaitSignal() {
95
+ const buffer = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT);
96
+ return {
97
+ buffer,
98
+ view: new Int32Array(buffer)
99
+ };
100
+ }
101
+ function resolveWorkerSpecifier() {
102
+ if (typeof __dirname !== "undefined") {
103
+ return (0, import_node_path.join)(__dirname, "worker.cjs");
104
+ }
105
+ return new URL("./worker.js", import_meta.url);
106
+ }
107
+ var TinyCloudVfsBridge = class {
108
+ worker;
109
+ constructor(init) {
110
+ const specifier = resolveWorkerSpecifier();
111
+ this.worker = typeof specifier === "string" ? new import_node_worker_threads.Worker(specifier) : new import_node_worker_threads.Worker(specifier);
112
+ const response = this.requestSync({ type: "init", init });
113
+ if (!response.ok) {
114
+ this.worker.terminate();
115
+ throw createEIO("init", "/", response.error.message);
116
+ }
117
+ }
118
+ close() {
119
+ void this.worker.terminate();
120
+ }
121
+ requestSync(request) {
122
+ const { port1, port2 } = new import_node_worker_threads.MessageChannel();
123
+ const { buffer, view } = createWaitSignal();
124
+ this.worker.postMessage(
125
+ {
126
+ request,
127
+ replyPort: port1,
128
+ waitBuffer: buffer
129
+ },
130
+ [port1]
131
+ );
132
+ while (Atomics.load(view, 0) === 0) {
133
+ Atomics.wait(view, 0, 0, WAIT_SLICE_MS);
134
+ }
135
+ const response = (0, import_node_worker_threads.receiveMessageOnPort)(port2)?.message;
136
+ port2.close();
137
+ if (!response) {
138
+ throw createEIO("bridge", "/", "worker did not return a response");
139
+ }
140
+ return response;
141
+ }
142
+ async requestAsync(request) {
143
+ return this.requestSync(request);
144
+ }
145
+ };
146
+
147
+ // src/fsPatch.ts
148
+ var import_node_buffer = require("buffer");
149
+ var import_node_fs = __toESM(require("fs"), 1);
150
+ var import_promises = __toESM(require("fs/promises"), 1);
151
+ var import_node_module = require("module");
152
+ var import_node_url = require("url");
153
+ var activeVfs = /* @__PURE__ */ new Set();
154
+ var mutableFs = import_node_fs.default;
155
+ var mutableFsPromises = import_promises.default;
156
+ var originalFsMethods = {
157
+ writeFileSync: mutableFs.writeFileSync.bind(mutableFs),
158
+ appendFileSync: mutableFs.appendFileSync.bind(mutableFs),
159
+ mkdirSync: mutableFs.mkdirSync.bind(mutableFs),
160
+ renameSync: mutableFs.renameSync.bind(mutableFs),
161
+ unlinkSync: mutableFs.unlinkSync.bind(mutableFs),
162
+ rmdirSync: mutableFs.rmdirSync.bind(mutableFs),
163
+ writeFile: mutableFs.writeFile.bind(mutableFs),
164
+ appendFile: mutableFs.appendFile.bind(mutableFs),
165
+ mkdir: mutableFs.mkdir.bind(mutableFs),
166
+ rename: mutableFs.rename.bind(mutableFs),
167
+ unlink: mutableFs.unlink.bind(mutableFs),
168
+ rmdir: mutableFs.rmdir.bind(mutableFs)
169
+ };
170
+ var originalPromiseMethods = {
171
+ writeFile: mutableFsPromises.writeFile.bind(mutableFsPromises),
172
+ appendFile: mutableFsPromises.appendFile.bind(mutableFsPromises),
173
+ mkdir: mutableFsPromises.mkdir.bind(mutableFsPromises),
174
+ rename: mutableFsPromises.rename.bind(mutableFsPromises),
175
+ unlink: mutableFsPromises.unlink.bind(mutableFsPromises),
176
+ rmdir: mutableFsPromises.rmdir.bind(mutableFsPromises)
177
+ };
178
+ var installed = false;
179
+ function toPathString(path) {
180
+ if (typeof path === "string") {
181
+ return path;
182
+ }
183
+ if (import_node_buffer.Buffer.isBuffer(path)) {
184
+ return path.toString();
185
+ }
186
+ if (path instanceof URL) {
187
+ return (0, import_node_url.fileURLToPath)(path);
188
+ }
189
+ return null;
190
+ }
191
+ function activeVfsBySpecificity() {
192
+ return [...activeVfs].sort((left, right) => {
193
+ return (right.mountPoint?.length ?? 0) - (left.mountPoint?.length ?? 0);
194
+ });
195
+ }
196
+ function findMountedVfs(path) {
197
+ const normalizedPath = toPathString(path);
198
+ if (!normalizedPath) {
199
+ return null;
200
+ }
201
+ for (const vfs of activeVfsBySpecificity()) {
202
+ if (vfs.mounted && vfs.shouldHandle(normalizedPath)) {
203
+ return { vfs, path: normalizedPath };
204
+ }
205
+ }
206
+ return null;
207
+ }
208
+ function findMountedVfsForPaths(paths, syscall) {
209
+ let selected = null;
210
+ const normalizedPaths = [];
211
+ for (const path of paths) {
212
+ const normalizedPath = toPathString(path);
213
+ if (!normalizedPath) {
214
+ normalizedPaths.push(String(path));
215
+ continue;
216
+ }
217
+ normalizedPaths.push(normalizedPath);
218
+ const match = findMountedVfs(normalizedPath);
219
+ if (!match) {
220
+ continue;
221
+ }
222
+ if (selected && selected !== match.vfs) {
223
+ throw createNodeError(
224
+ "EXDEV",
225
+ `cross-device link not permitted, ${syscall} '${normalizedPaths.join("' -> '")}'`,
226
+ syscall,
227
+ normalizedPath
228
+ );
229
+ }
230
+ selected = match.vfs;
231
+ }
232
+ if (!selected) {
233
+ return null;
234
+ }
235
+ return { vfs: selected, paths: normalizedPaths };
236
+ }
237
+ function withCallback(promise, callback) {
238
+ promise.then(
239
+ (result) => process.nextTick(callback, null, result),
240
+ (error) => process.nextTick(callback, error)
241
+ );
242
+ }
243
+ function installFsWritePatches() {
244
+ if (installed) {
245
+ return;
246
+ }
247
+ mutableFs.writeFileSync = ((file, data, options) => {
248
+ const match = findMountedVfs(file);
249
+ if (!match) {
250
+ return originalFsMethods.writeFileSync(file, data, options);
251
+ }
252
+ return match.vfs.writeFileSync(match.path, data, options);
253
+ });
254
+ mutableFs.appendFileSync = ((file, data, options) => {
255
+ const match = findMountedVfs(file);
256
+ if (!match) {
257
+ return originalFsMethods.appendFileSync(file, data, options);
258
+ }
259
+ return match.vfs.appendFileSync(match.path, data, options);
260
+ });
261
+ mutableFs.mkdirSync = ((path, options) => {
262
+ const match = findMountedVfs(path);
263
+ if (!match) {
264
+ return originalFsMethods.mkdirSync(path, options);
265
+ }
266
+ return match.vfs.mkdirSync(match.path, options);
267
+ });
268
+ mutableFs.renameSync = ((oldPath, newPath) => {
269
+ const match = findMountedVfsForPaths([oldPath, newPath], "rename");
270
+ if (!match) {
271
+ return originalFsMethods.renameSync(oldPath, newPath);
272
+ }
273
+ const [normalizedOld, normalizedNew] = match.paths;
274
+ return match.vfs.renameSync(normalizedOld, normalizedNew);
275
+ });
276
+ mutableFs.unlinkSync = ((path) => {
277
+ const match = findMountedVfs(path);
278
+ if (!match) {
279
+ return originalFsMethods.unlinkSync(path);
280
+ }
281
+ return match.vfs.unlinkSync(match.path);
282
+ });
283
+ mutableFs.rmdirSync = ((path, options) => {
284
+ const match = findMountedVfs(path);
285
+ if (!match) {
286
+ return originalFsMethods.rmdirSync(path, options);
287
+ }
288
+ return match.vfs.rmdirSync(match.path, options);
289
+ });
290
+ mutableFs.writeFile = ((file, data, options, callback) => {
291
+ const match = findMountedVfs(file);
292
+ if (!match) {
293
+ return originalFsMethods.writeFile(file, data, options, callback);
294
+ }
295
+ const resolvedOptions = typeof options === "function" ? void 0 : options;
296
+ const resolvedCallback = typeof options === "function" ? options : callback;
297
+ if (typeof resolvedCallback !== "function") {
298
+ return originalFsMethods.writeFile(file, data, options, callback);
299
+ }
300
+ withCallback(match.vfs.promises.writeFile(match.path, data, resolvedOptions), resolvedCallback);
301
+ });
302
+ mutableFs.appendFile = ((file, data, options, callback) => {
303
+ const match = findMountedVfs(file);
304
+ if (!match) {
305
+ return originalFsMethods.appendFile(file, data, options, callback);
306
+ }
307
+ const resolvedOptions = typeof options === "function" ? void 0 : options;
308
+ const resolvedCallback = typeof options === "function" ? options : callback;
309
+ if (typeof resolvedCallback !== "function") {
310
+ return originalFsMethods.appendFile(file, data, options, callback);
311
+ }
312
+ withCallback(match.vfs.promises.appendFile(match.path, data, resolvedOptions), resolvedCallback);
313
+ });
314
+ mutableFs.mkdir = ((path, options, callback) => {
315
+ const match = findMountedVfs(path);
316
+ if (!match) {
317
+ return originalFsMethods.mkdir(path, options, callback);
318
+ }
319
+ const resolvedOptions = typeof options === "function" ? void 0 : options;
320
+ const resolvedCallback = typeof options === "function" ? options : callback;
321
+ if (typeof resolvedCallback !== "function") {
322
+ return originalFsMethods.mkdir(path, options, callback);
323
+ }
324
+ withCallback(match.vfs.promises.mkdir(match.path, resolvedOptions), resolvedCallback);
325
+ });
326
+ mutableFs.rename = ((oldPath, newPath, callback) => {
327
+ const match = findMountedVfsForPaths([oldPath, newPath], "rename");
328
+ if (!match) {
329
+ return originalFsMethods.rename(oldPath, newPath, callback);
330
+ }
331
+ if (typeof callback !== "function") {
332
+ return originalFsMethods.rename(oldPath, newPath, callback);
333
+ }
334
+ const [normalizedOld, normalizedNew] = match.paths;
335
+ withCallback(match.vfs.promises.rename(normalizedOld, normalizedNew), callback);
336
+ });
337
+ mutableFs.unlink = ((path, callback) => {
338
+ const match = findMountedVfs(path);
339
+ if (!match) {
340
+ return originalFsMethods.unlink(path, callback);
341
+ }
342
+ if (typeof callback !== "function") {
343
+ return originalFsMethods.unlink(path, callback);
344
+ }
345
+ withCallback(match.vfs.promises.unlink(match.path), callback);
346
+ });
347
+ mutableFs.rmdir = ((path, options, callback) => {
348
+ const match = findMountedVfs(path);
349
+ if (!match) {
350
+ return originalFsMethods.rmdir(path, options, callback);
351
+ }
352
+ const resolvedCallback = typeof options === "function" ? options : callback;
353
+ if (typeof resolvedCallback !== "function") {
354
+ return originalFsMethods.rmdir(path, options, callback);
355
+ }
356
+ withCallback(match.vfs.promises.rmdir(match.path, typeof options === "function" ? void 0 : options), resolvedCallback);
357
+ });
358
+ const promisePatches = {
359
+ async writeFile(file, data, options) {
360
+ const match = findMountedVfs(file);
361
+ if (!match) {
362
+ return originalPromiseMethods.writeFile(file, data, options);
363
+ }
364
+ return match.vfs.promises.writeFile(match.path, data, options);
365
+ },
366
+ async appendFile(file, data, options) {
367
+ const match = findMountedVfs(file);
368
+ if (!match) {
369
+ return originalPromiseMethods.appendFile(file, data, options);
370
+ }
371
+ return match.vfs.promises.appendFile(match.path, data, options);
372
+ },
373
+ async mkdir(path, options) {
374
+ const match = findMountedVfs(path);
375
+ if (!match) {
376
+ return originalPromiseMethods.mkdir(path, options);
377
+ }
378
+ return match.vfs.promises.mkdir(match.path, options);
379
+ },
380
+ async rename(oldPath, newPath) {
381
+ const match = findMountedVfsForPaths([oldPath, newPath], "rename");
382
+ if (!match) {
383
+ return originalPromiseMethods.rename(oldPath, newPath);
384
+ }
385
+ const [normalizedOld, normalizedNew] = match.paths;
386
+ return match.vfs.promises.rename(normalizedOld, normalizedNew);
387
+ },
388
+ async unlink(path) {
389
+ const match = findMountedVfs(path);
390
+ if (!match) {
391
+ return originalPromiseMethods.unlink(path);
392
+ }
393
+ return match.vfs.promises.unlink(match.path);
394
+ },
395
+ async rmdir(path, options) {
396
+ const match = findMountedVfs(path);
397
+ if (!match) {
398
+ return originalPromiseMethods.rmdir(path, options);
399
+ }
400
+ return match.vfs.promises.rmdir(match.path, options);
401
+ }
402
+ };
403
+ mutableFs.promises.writeFile = promisePatches.writeFile;
404
+ mutableFs.promises.appendFile = promisePatches.appendFile;
405
+ mutableFs.promises.mkdir = promisePatches.mkdir;
406
+ mutableFs.promises.rename = promisePatches.rename;
407
+ mutableFs.promises.unlink = promisePatches.unlink;
408
+ mutableFs.promises.rmdir = promisePatches.rmdir;
409
+ mutableFsPromises.writeFile = promisePatches.writeFile;
410
+ mutableFsPromises.appendFile = promisePatches.appendFile;
411
+ mutableFsPromises.mkdir = promisePatches.mkdir;
412
+ mutableFsPromises.rename = promisePatches.rename;
413
+ mutableFsPromises.unlink = promisePatches.unlink;
414
+ mutableFsPromises.rmdir = promisePatches.rmdir;
415
+ (0, import_node_module.syncBuiltinESMExports)();
416
+ installed = true;
417
+ }
418
+ function uninstallFsWritePatches() {
419
+ if (!installed || activeVfs.size > 0) {
420
+ return;
421
+ }
422
+ mutableFs.writeFileSync = originalFsMethods.writeFileSync;
423
+ mutableFs.appendFileSync = originalFsMethods.appendFileSync;
424
+ mutableFs.mkdirSync = originalFsMethods.mkdirSync;
425
+ mutableFs.renameSync = originalFsMethods.renameSync;
426
+ mutableFs.unlinkSync = originalFsMethods.unlinkSync;
427
+ mutableFs.rmdirSync = originalFsMethods.rmdirSync;
428
+ mutableFs.writeFile = originalFsMethods.writeFile;
429
+ mutableFs.appendFile = originalFsMethods.appendFile;
430
+ mutableFs.mkdir = originalFsMethods.mkdir;
431
+ mutableFs.rename = originalFsMethods.rename;
432
+ mutableFs.unlink = originalFsMethods.unlink;
433
+ mutableFs.rmdir = originalFsMethods.rmdir;
434
+ mutableFs.promises.writeFile = originalPromiseMethods.writeFile;
435
+ mutableFs.promises.appendFile = originalPromiseMethods.appendFile;
436
+ mutableFs.promises.mkdir = originalPromiseMethods.mkdir;
437
+ mutableFs.promises.rename = originalPromiseMethods.rename;
438
+ mutableFs.promises.unlink = originalPromiseMethods.unlink;
439
+ mutableFs.promises.rmdir = originalPromiseMethods.rmdir;
440
+ mutableFsPromises.writeFile = originalPromiseMethods.writeFile;
441
+ mutableFsPromises.appendFile = originalPromiseMethods.appendFile;
442
+ mutableFsPromises.mkdir = originalPromiseMethods.mkdir;
443
+ mutableFsPromises.rename = originalPromiseMethods.rename;
444
+ mutableFsPromises.unlink = originalPromiseMethods.unlink;
445
+ mutableFsPromises.rmdir = originalPromiseMethods.rmdir;
446
+ (0, import_node_module.syncBuiltinESMExports)();
447
+ installed = false;
448
+ }
449
+ function registerMountedVfs(vfs) {
450
+ activeVfs.add(vfs);
451
+ installFsWritePatches();
452
+ }
453
+ function deregisterMountedVfs(vfs) {
454
+ activeVfs.delete(vfs);
455
+ uninstallFsWritePatches();
456
+ }
457
+ function wrapVfsWithFsWritePatches(vfs) {
458
+ const patchableVfs = vfs;
459
+ const originalMount = vfs.mount.bind(vfs);
460
+ const originalUnmount = vfs.unmount.bind(vfs);
461
+ const originalDispose = patchableVfs[Symbol.dispose]?.bind(vfs);
462
+ let registered = false;
463
+ patchableVfs.mount = ((prefix) => {
464
+ const mounted = originalMount(prefix);
465
+ if (!registered) {
466
+ registerMountedVfs(patchableVfs);
467
+ registered = true;
468
+ }
469
+ return mounted;
470
+ });
471
+ patchableVfs.unmount = (() => {
472
+ if (registered) {
473
+ deregisterMountedVfs(patchableVfs);
474
+ registered = false;
475
+ }
476
+ return originalUnmount();
477
+ });
478
+ if (originalDispose) {
479
+ patchableVfs[Symbol.dispose] = (() => {
480
+ if (registered) {
481
+ deregisterMountedVfs(patchableVfs);
482
+ registered = false;
483
+ }
484
+ return originalDispose();
485
+ });
486
+ }
487
+ return patchableVfs;
488
+ }
489
+
490
+ // src/pathing.ts
491
+ var import_node_path2 = require("path");
492
+ function normalizeVfsPath(inputPath) {
493
+ const normalized = import_node_path2.posix.normalize(inputPath.replace(/\\/g, "/"));
494
+ const absolute = normalized.startsWith("/") ? normalized : `/${normalized}`;
495
+ return absolute;
496
+ }
497
+
498
+ // src/metadata.ts
499
+ function normalizeMode(kind, mode) {
500
+ if (typeof mode === "number" && Number.isFinite(mode)) {
501
+ return mode;
502
+ }
503
+ return kind === "directory" ? 493 : 420;
504
+ }
505
+
506
+ // src/TinyCloudVfsProvider.ts
507
+ var S_IFREG = 32768;
508
+ var S_IFDIR = 16384;
509
+ var DEFAULT_BLOCK_SIZE = 4096;
510
+ function createStats(metadata) {
511
+ const mode = metadata.kind === "directory" ? metadata.mode | S_IFDIR : metadata.mode | S_IFREG;
512
+ return {
513
+ dev: 0,
514
+ mode,
515
+ nlink: 1,
516
+ uid: process.getuid?.() ?? 0,
517
+ gid: process.getgid?.() ?? 0,
518
+ rdev: 0,
519
+ blksize: DEFAULT_BLOCK_SIZE,
520
+ ino: 0,
521
+ size: metadata.kind === "directory" ? DEFAULT_BLOCK_SIZE : metadata.size,
522
+ blocks: metadata.kind === "directory" ? 8 : Math.ceil(metadata.size / 512),
523
+ atimeMs: metadata.mtimeMs,
524
+ mtimeMs: metadata.mtimeMs,
525
+ ctimeMs: metadata.ctimeMs,
526
+ birthtimeMs: metadata.birthtimeMs,
527
+ atime: new Date(metadata.mtimeMs),
528
+ mtime: new Date(metadata.mtimeMs),
529
+ ctime: new Date(metadata.ctimeMs),
530
+ birthtime: new Date(metadata.birthtimeMs),
531
+ isFile: () => metadata.kind === "file",
532
+ isDirectory: () => metadata.kind === "directory",
533
+ isSymbolicLink: () => false,
534
+ isBlockDevice: () => false,
535
+ isCharacterDevice: () => false,
536
+ isFIFO: () => false,
537
+ isSocket: () => false
538
+ };
539
+ }
540
+ function createDirent(entry) {
541
+ return {
542
+ name: entry.name,
543
+ parentPath: entry.parentPath,
544
+ path: entry.parentPath,
545
+ isFile: () => entry.kind === "file",
546
+ isDirectory: () => entry.kind === "directory",
547
+ isSymbolicLink: () => false,
548
+ isBlockDevice: () => false,
549
+ isCharacterDevice: () => false,
550
+ isFIFO: () => false,
551
+ isSocket: () => false
552
+ };
553
+ }
554
+ function expectStatResult(response) {
555
+ if (!response.ok) {
556
+ throw fromWorkerError(response.error);
557
+ }
558
+ if (!response.result || !("metadata" in response.result)) {
559
+ throw new Error("worker returned an unexpected stat payload");
560
+ }
561
+ return response.result.metadata;
562
+ }
563
+ function expectReadFileResult(response) {
564
+ if (!response.ok) {
565
+ throw fromWorkerError(response.error);
566
+ }
567
+ if (!response.result || !("metadata" in response.result) || !("content" in response.result)) {
568
+ throw new Error("worker returned an unexpected readFile payload");
569
+ }
570
+ return response.result;
571
+ }
572
+ function expectReaddirResult(response) {
573
+ if (!response.ok) {
574
+ throw fromWorkerError(response.error);
575
+ }
576
+ if (!response.result || !("entries" in response.result)) {
577
+ throw new Error("worker returned an unexpected readdir payload");
578
+ }
579
+ return response.result.entries;
580
+ }
581
+ function isWriteFlag(flags = "r") {
582
+ return /[wa+]/.test(flags);
583
+ }
584
+ function isAppendFlag(flags = "r") {
585
+ return flags.startsWith("a");
586
+ }
587
+ function isTruncateFlag(flags = "r") {
588
+ return flags.startsWith("w");
589
+ }
590
+ var TinyCloudVfsFileHandle = class {
591
+ bridge;
592
+ state;
593
+ closed = false;
594
+ dirty = false;
595
+ position = 0;
596
+ constructor(bridge, state) {
597
+ this.bridge = bridge;
598
+ this.state = state;
599
+ if (isAppendFlag(state.flags)) {
600
+ this.position = state.content.length;
601
+ }
602
+ }
603
+ ensureOpen() {
604
+ if (this.closed) {
605
+ throw new Error("file handle is closed");
606
+ }
607
+ }
608
+ commit() {
609
+ if (!this.dirty) {
610
+ return;
611
+ }
612
+ const response = this.bridge.requestSync({
613
+ type: "writeFile",
614
+ path: this.state.path,
615
+ content: this.state.content,
616
+ mode: this.state.mode
617
+ });
618
+ if (!response.ok) {
619
+ throw fromWorkerError(response.error);
620
+ }
621
+ this.dirty = false;
622
+ }
623
+ readSync(buffer, offset, length, position) {
624
+ this.ensureOpen();
625
+ const readFrom = position ?? this.position;
626
+ const available = Math.max(0, this.state.content.length - readFrom);
627
+ const bytesToRead = Math.min(length, available);
628
+ if (bytesToRead === 0) {
629
+ return 0;
630
+ }
631
+ this.state.content.copy(buffer, offset, readFrom, readFrom + bytesToRead);
632
+ if (position === null || position === void 0) {
633
+ this.position = readFrom + bytesToRead;
634
+ }
635
+ return bytesToRead;
636
+ }
637
+ writeSync(buffer, offset, length, position) {
638
+ this.ensureOpen();
639
+ const writeFrom = position ?? this.position;
640
+ const data = buffer.subarray(offset, offset + length);
641
+ const requiredLength = writeFrom + data.length;
642
+ if (requiredLength > this.state.content.length) {
643
+ const next = import_node_buffer2.Buffer.alloc(requiredLength);
644
+ this.state.content.copy(next, 0, 0, this.state.content.length);
645
+ this.state.content = next;
646
+ }
647
+ data.copy(this.state.content, writeFrom);
648
+ this.state.metadata = {
649
+ ...this.state.metadata,
650
+ size: this.state.content.length,
651
+ mtimeMs: Date.now(),
652
+ ctimeMs: Date.now()
653
+ };
654
+ this.dirty = true;
655
+ if (position === null || position === void 0) {
656
+ this.position = writeFrom + data.length;
657
+ }
658
+ return data.length;
659
+ }
660
+ readFileSync(options) {
661
+ this.ensureOpen();
662
+ const encoding = typeof options === "string" ? options : options?.encoding;
663
+ if (encoding) {
664
+ return this.state.content.toString(encoding);
665
+ }
666
+ return import_node_buffer2.Buffer.from(this.state.content);
667
+ }
668
+ writeFileSync(data, options) {
669
+ this.ensureOpen();
670
+ const encoding = typeof options === "string" ? options : options?.encoding;
671
+ const buffer = typeof data === "string" ? import_node_buffer2.Buffer.from(data, encoding) : import_node_buffer2.Buffer.from(data);
672
+ if (isAppendFlag(this.state.flags)) {
673
+ this.state.content = import_node_buffer2.Buffer.concat([this.state.content, buffer]);
674
+ } else {
675
+ this.state.content = import_node_buffer2.Buffer.from(buffer);
676
+ }
677
+ this.state.metadata = {
678
+ ...this.state.metadata,
679
+ size: this.state.content.length,
680
+ mtimeMs: Date.now(),
681
+ ctimeMs: Date.now(),
682
+ mode: normalizeMode("file", typeof options === "object" ? options?.mode : this.state.mode)
683
+ };
684
+ this.dirty = true;
685
+ this.position = this.state.content.length;
686
+ }
687
+ statSync() {
688
+ this.ensureOpen();
689
+ return createStats({
690
+ ...this.state.metadata,
691
+ size: this.state.content.length
692
+ });
693
+ }
694
+ closeSync() {
695
+ this.ensureOpen();
696
+ this.commit();
697
+ this.closed = true;
698
+ }
699
+ };
700
+ var TinyCloudVfsProvider = class extends import_vfs.VirtualProvider {
701
+ bridge;
702
+ forceReadOnly;
703
+ constructor(options) {
704
+ super();
705
+ this.forceReadOnly = options.readOnly === true;
706
+ this.bridge = new TinyCloudVfsBridge({
707
+ source: options.source,
708
+ mountPrefix: options.mountPrefix ?? ""
709
+ });
710
+ }
711
+ get readonly() {
712
+ return this.forceReadOnly;
713
+ }
714
+ close() {
715
+ this.bridge.close();
716
+ }
717
+ ensureWritable(path, syscall) {
718
+ if (this.forceReadOnly) {
719
+ throw createEROFS(syscall, path);
720
+ }
721
+ }
722
+ normalize(path) {
723
+ return normalizeVfsPath(path);
724
+ }
725
+ openSync(path, flags = "r", mode) {
726
+ const normalized = this.normalize(path);
727
+ const writable = isWriteFlag(flags);
728
+ if (writable) {
729
+ this.ensureWritable(normalized, "open");
730
+ }
731
+ let metadata;
732
+ let content = import_node_buffer2.Buffer.alloc(0);
733
+ try {
734
+ const response = expectReadFileResult(this.bridge.requestSync({ type: "readFile", path: normalized }));
735
+ metadata = response.metadata;
736
+ content = import_node_buffer2.Buffer.from(response.content);
737
+ if (isTruncateFlag(flags)) {
738
+ content = import_node_buffer2.Buffer.alloc(0);
739
+ metadata = {
740
+ ...metadata,
741
+ size: 0,
742
+ mode: normalizeMode("file", mode ?? metadata.mode)
743
+ };
744
+ }
745
+ } catch (error) {
746
+ const typed = error;
747
+ if (typed.code !== "ENOENT" || !writable) {
748
+ throw error;
749
+ }
750
+ metadata = {
751
+ kind: "file",
752
+ size: 0,
753
+ mode: normalizeMode("file", mode),
754
+ ctimeMs: Date.now(),
755
+ mtimeMs: Date.now(),
756
+ birthtimeMs: Date.now()
757
+ };
758
+ }
759
+ if (metadata.kind !== "file") {
760
+ throw createEISDIR("open", normalized);
761
+ }
762
+ return new TinyCloudVfsFileHandle(this.bridge, {
763
+ path: normalized,
764
+ flags,
765
+ mode: normalizeMode("file", mode ?? metadata.mode),
766
+ content,
767
+ metadata
768
+ });
769
+ }
770
+ async open(path, flags = "r", mode) {
771
+ return this.openSync(path, flags, mode);
772
+ }
773
+ statSync(path) {
774
+ const normalized = this.normalize(path);
775
+ return createStats(expectStatResult(this.bridge.requestSync({ type: "stat", path: normalized })));
776
+ }
777
+ async stat(path) {
778
+ return this.statSync(path);
779
+ }
780
+ lstatSync(path) {
781
+ return this.statSync(path);
782
+ }
783
+ async lstat(path) {
784
+ return this.lstatSync(path);
785
+ }
786
+ readdirSync(path, options) {
787
+ const normalized = this.normalize(path);
788
+ const entries = expectReaddirResult(this.bridge.requestSync({ type: "readdir", path: normalized }));
789
+ if (options?.withFileTypes) {
790
+ return entries.map(createDirent);
791
+ }
792
+ return entries.map((entry) => entry.name);
793
+ }
794
+ async readdir(path, options) {
795
+ return this.readdirSync(path, options);
796
+ }
797
+ mkdirSync(path, options) {
798
+ const normalized = this.normalize(path);
799
+ this.ensureWritable(normalized, "mkdir");
800
+ const response = this.bridge.requestSync({
801
+ type: "mkdir",
802
+ path: normalized,
803
+ recursive: options?.recursive === true,
804
+ mode: options?.mode
805
+ });
806
+ if (!response.ok) {
807
+ throw fromWorkerError(response.error);
808
+ }
809
+ return options?.recursive ? normalized : void 0;
810
+ }
811
+ async mkdir(path, options) {
812
+ return this.mkdirSync(path, options);
813
+ }
814
+ rmdirSync(path) {
815
+ const normalized = this.normalize(path);
816
+ this.ensureWritable(normalized, "rmdir");
817
+ const response = this.bridge.requestSync({ type: "rmdir", path: normalized });
818
+ if (!response.ok) {
819
+ throw fromWorkerError(response.error);
820
+ }
821
+ }
822
+ async rmdir(path) {
823
+ this.rmdirSync(path);
824
+ }
825
+ unlinkSync(path) {
826
+ const normalized = this.normalize(path);
827
+ this.ensureWritable(normalized, "unlink");
828
+ const response = this.bridge.requestSync({ type: "unlink", path: normalized });
829
+ if (!response.ok) {
830
+ throw fromWorkerError(response.error);
831
+ }
832
+ }
833
+ async unlink(path) {
834
+ this.unlinkSync(path);
835
+ }
836
+ renameSync(oldPath, newPath) {
837
+ const normalizedOld = this.normalize(oldPath);
838
+ const normalizedNew = this.normalize(newPath);
839
+ this.ensureWritable(normalizedOld, "rename");
840
+ const response = this.bridge.requestSync({
841
+ type: "rename",
842
+ oldPath: normalizedOld,
843
+ newPath: normalizedNew
844
+ });
845
+ if (!response.ok) {
846
+ throw fromWorkerError(response.error);
847
+ }
848
+ }
849
+ async rename(oldPath, newPath) {
850
+ this.renameSync(oldPath, newPath);
851
+ }
852
+ };
853
+ function toSessionSource(node, host) {
854
+ if (!node.session) {
855
+ throw new Error("TinyCloudNode has no active session; call signIn() or restoreSession() first.");
856
+ }
857
+ const resolvedHost = host ?? node.config?.host ?? "https://node.tinycloud.xyz";
858
+ return {
859
+ kind: "session",
860
+ host: resolvedHost,
861
+ session: node.session
862
+ };
863
+ }
864
+ function createTinyCloudVfs(options) {
865
+ const provider = new TinyCloudVfsProvider(options);
866
+ const vfs = wrapVfsWithFsWritePatches((0, import_vfs.create)(provider, {
867
+ moduleHooks: options.moduleHooks,
868
+ overlay: options.overlay,
869
+ virtualCwd: options.virtualCwd
870
+ }));
871
+ if (options.mountPoint) {
872
+ vfs.mount(options.mountPoint);
873
+ }
874
+ return { provider, vfs };
875
+ }
876
+ function createTinyCloudVfsFromNode(node, options = {}) {
877
+ return createTinyCloudVfs({
878
+ ...options,
879
+ source: toSessionSource(node, options.host)
880
+ });
881
+ }
882
+ async function createTinyCloudDelegatedVfs(options) {
883
+ if (!options.node.session) {
884
+ throw new Error("TinyCloudNode has no active session; call signIn() or restoreSession() first.");
885
+ }
886
+ if (typeof options.node.useDelegation !== "function") {
887
+ throw new Error("TinyCloudNode does not expose useDelegation().");
888
+ }
889
+ const access = await options.node.useDelegation(options.delegation);
890
+ if (!access?.session) {
891
+ throw new Error("Delegated access does not expose a resolved session snapshot.");
892
+ }
893
+ return createTinyCloudVfs({
894
+ ...options,
895
+ source: {
896
+ kind: "resolved-delegation",
897
+ host: options.host ?? options.delegation.host ?? "https://node.tinycloud.xyz",
898
+ session: access.session,
899
+ kvPrefix: access.kv?.config?.prefix ?? ""
900
+ }
901
+ });
902
+ }
903
+ // Annotate the CommonJS export names for ESM import in node:
904
+ 0 && (module.exports = {
905
+ TinyCloudVfsProvider,
906
+ createTinyCloudDelegatedVfs,
907
+ createTinyCloudVfs,
908
+ createTinyCloudVfsFromNode
909
+ });
910
+ //# sourceMappingURL=index.cjs.map