@vrowser/fs 0.0.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.
@@ -0,0 +1,289 @@
1
+ //#region src/watcher/protocol.d.ts
2
+ /**
3
+ * File System Sync Protocol
4
+ *
5
+ * Message types for synchronizing file operations between
6
+ * Main Thread (Publisher) and Workers (Subscribers).
7
+ *
8
+ * @module watcher/protocol
9
+ */
10
+ /**
11
+ * @author kazuya kawaguchi (a.k.a. kazupon)
12
+ * @license MIT
13
+ */
14
+ /**
15
+ * File content encoding type.
16
+ * - 'text': UTF-8 string content (JS, TS, JSON, CSS, HTML, etc.)
17
+ * - 'binary': ArrayBuffer content (images, WASM, fonts, etc.)
18
+ *
19
+ * When encoding is 'binary', the content is an ArrayBuffer
20
+ * and MUST be transferred via postMessage's transfer list
21
+ * for zero-copy performance.
22
+ */
23
+ type FSContentEncoding = 'text' | 'binary';
24
+ /**
25
+ * Main Thread -> Worker: Write (create or update) a file.
26
+ *
27
+ * For text files:
28
+ * { type: 'V_FS_WRITE', path: '/main.js', encoding: 'text', content: '...' }
29
+ * -> postMessage(message)
30
+ *
31
+ * For binary files:
32
+ * { type: 'V_FS_WRITE', path: '/image.png', encoding: 'binary', content: ArrayBuffer }
33
+ * -> postMessage(message, [message.content]) // transfer list
34
+ */
35
+ interface FSWriteMessage {
36
+ type: 'V_FS_WRITE';
37
+ /**
38
+ * Path of the file to write. Must not end with '/' (directories use FS_MKDIR with path ending in '/').
39
+ */
40
+ path: string;
41
+ /**
42
+ * Encoding of the content. Determines how the Worker should interpret the content.
43
+ */
44
+ encoding: FSContentEncoding;
45
+ /**
46
+ * Content of the file. Type depends on encoding:
47
+ * - 'text': UTF-8 string content
48
+ * - 'binary': ArrayBuffer content (transferred via postMessage's transfer list)
49
+ */
50
+ content: string | ArrayBuffer;
51
+ }
52
+ /**
53
+ * Main Thread -> Worker: Delete a file.
54
+ */
55
+ interface FSUnlinkMessage {
56
+ type: 'V_FS_UNLINK';
57
+ /**
58
+ * Path of the file to delete. Must not end with '/' (directories use FS_MKDIR with path ending in '/').
59
+ */
60
+ path: string;
61
+ }
62
+ /**
63
+ * Main Thread -> Worker: Create a directory.
64
+ */
65
+ interface FSMkdirMessage {
66
+ type: 'V_FS_MKDIR';
67
+ /**
68
+ * Path of the directory to create. Must end with '/' to distinguish from files.
69
+ */
70
+ path: string;
71
+ }
72
+ /**
73
+ * Main Thread -> Worker: Initialize files in bulk.
74
+ * Used during setup to populate the virtual filesystem.
75
+ *
76
+ * Text files are in `files`, binary files are in `binaryFiles`.
77
+ * Binary ArrayBuffers are transferred via postMessage's transfer list.
78
+ */
79
+ interface FSInitMessage {
80
+ type: 'V_FS_INIT';
81
+ /**
82
+ * Text files: path -> UTF-8 string content
83
+ */
84
+ files?: Record<string, string>;
85
+ /**
86
+ * Binary files: path -> ArrayBuffer content (transferred)
87
+ */
88
+ binaryFiles?: Record<string, ArrayBuffer>;
89
+ }
90
+ type FileSystemSyncMessage = FSWriteMessage | FSUnlinkMessage | FSMkdirMessage | FSInitMessage;
91
+ declare const V_FS_WRITE: "V_FS_WRITE";
92
+ declare const V_FS_UNLINK: "V_FS_UNLINK";
93
+ declare const V_FS_MKDIR: "V_FS_MKDIR";
94
+ declare const V_FS_INIT: "V_FS_INIT";
95
+ //#endregion
96
+ //#region src/watcher/publisher.d.ts
97
+ /**
98
+ * FileSystemPublisher - Main Thread side of the Pub-Sub filesystem sync.
99
+ *
100
+ * Sends V_FS_* protocol messages to Worker targets (Service Worker, Web Worker).
101
+ * Provides a `node:fs`-like API for reduced cognitive load.
102
+ *
103
+ * @module watcher/publisher
104
+ */
105
+ /**
106
+ * A postMessage target compatible like Service Worker and Web Worker APIs.
107
+ */
108
+ interface FileSystemPublisherTarget {
109
+ postMessage(message: any, transfer: Transferable[]): void;
110
+ postMessage(message: any, options?: StructuredSerializeOptions): void;
111
+ }
112
+ /**
113
+ * Publisher for broadcasting filesystem operations to Workers.
114
+ *
115
+ * API is modeled after `node:fs` for familiarity:
116
+ * - `writeFile` accepts both `string` (text) and `ArrayBuffer` (binary)
117
+ * - `unlink` deletes a file
118
+ * - `mkdir` creates a directory
119
+ */
120
+ interface FileSystemPublisher {
121
+ /**
122
+ * Write a file. Encoding is inferred: string → text, ArrayBuffer → binary.
123
+ *
124
+ * @param path - Path of the file to write. Must not end with '/' (directories use mkdir with path ending in '/').
125
+ * @param content - Content of the file. Type determines encoding:
126
+ * - string: UTF-8 text content
127
+ * - ArrayBuffer: binary content (transferred via postMessage's transfer list for zero-copy performance)
128
+ */
129
+ writeFile(path: string, content: string | ArrayBuffer): void;
130
+ /**
131
+ * Delete a file.
132
+ *
133
+ * @param path - Path of the file to delete. Must not end with '/' (directories use mkdir with path ending in '/').
134
+ */
135
+ unlink(path: string): void;
136
+ /**
137
+ * Create a directory.
138
+ *
139
+ * @param path - Path of the directory to create. Must end with '/' to distinguish from files.
140
+ */
141
+ mkdir(path: string): void;
142
+ /**
143
+ * Initialize files in bulk.
144
+ *
145
+ * @param files - Text files: path -> UTF-8 string content
146
+ * @param binaryFiles - Binary files: path -> ArrayBuffer content (transferred)
147
+ */
148
+ initFiles(files?: Record<string, string>, binaryFiles?: Record<string, ArrayBuffer>): void;
149
+ /**
150
+ * Add a postMessage target.
151
+ *
152
+ * @param target - The target to add (e.g. Worker, ServiceWorker)
153
+ */
154
+ addTarget(target: FileSystemPublisherTarget): void;
155
+ /**
156
+ * Remove a postMessage target.
157
+ *
158
+ * @param target - The target to remove (e.g. Worker, ServiceWorker)
159
+ */
160
+ removeTarget(target: FileSystemPublisherTarget): void;
161
+ }
162
+ /**
163
+ * Create a {@link FileSystemPublisher} instance.
164
+ *
165
+ * @param targets - Initial postMessage targets (e.g. Worker, ServiceWorker)
166
+ * @returns FileSystemPublisher instance
167
+ */
168
+ declare function createFileSystemPublisher(targets?: FileSystemPublisherTarget[]): Readonly<FileSystemPublisher>;
169
+ //#endregion
170
+ //#region src/watcher/virtual.d.ts
171
+ /**
172
+ * VirtualFSWatcher - chokidar compatible FSWatcher for virtual filesystems.
173
+ *
174
+ * Unlike real chokidar, this watcher does not monitor the filesystem.
175
+ * File events are triggered externally via `notify()` by the FileSystemSubscriber.
176
+ *
177
+ * @module watcher/virtual
178
+ */
179
+ /**
180
+ * @author kazuya kawaguchi (a.k.a. kazupon)
181
+ * @license MIT
182
+ */
183
+ type WatchEventName = 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir';
184
+ /**
185
+ * Watch options for VirtualFSWatcher.
186
+ * Uses an index signature for structural compatibility with chokidar's WatchOptions.
187
+ */
188
+ interface VirtualWatchOptions {
189
+ [key: string]: any;
190
+ }
191
+ /**
192
+ * chokidar compatible FSWatcher interface for virtual filesystems.
193
+ *
194
+ * This interface is the base type that vite-dev-server's `FSWatcher` extends.
195
+ * The `notify()` method is specific to VirtualFSWatcher.
196
+ */
197
+ interface VirtualFSWatcher {
198
+ options: VirtualWatchOptions;
199
+ /**
200
+ * Notify the watcher of a file event.
201
+ * Called by FileSystemSubscriber when a V_FS_* message is received.
202
+ */
203
+ notify(event: WatchEventName, path: string): void;
204
+ add(paths: string | ReadonlyArray<string>): VirtualFSWatcher;
205
+ unwatch(paths: string | ReadonlyArray<string>): VirtualFSWatcher;
206
+ getWatched(): {
207
+ [directory: string]: string[];
208
+ };
209
+ close(): Promise<void>;
210
+ ref(): VirtualFSWatcher;
211
+ unref(): VirtualFSWatcher;
212
+ on(event: 'add' | 'addDir' | 'change', listener: (path: string, stats?: any) => void): VirtualFSWatcher;
213
+ on(event: 'all', listener: (eventName: WatchEventName, path: string, stats?: any) => void): VirtualFSWatcher;
214
+ on(event: 'error', listener: (error: Error) => void): VirtualFSWatcher;
215
+ on(event: 'raw', listener: (eventName: string, path: string, details: any) => void): VirtualFSWatcher;
216
+ on(event: 'ready', listener: () => void): VirtualFSWatcher;
217
+ on(event: 'unlink' | 'unlinkDir', listener: (path: string) => void): VirtualFSWatcher;
218
+ on(event: string, listener: (...args: any[]) => void): VirtualFSWatcher;
219
+ off(event: string, listener: (...args: any[]) => void): VirtualFSWatcher;
220
+ once(event: string, listener: (...args: any[]) => void): VirtualFSWatcher;
221
+ emit(event: string, ...args: any[]): boolean;
222
+ removeListener(event: string, listener: (...args: any[]) => void): VirtualFSWatcher;
223
+ removeAllListeners(event?: string): VirtualFSWatcher;
224
+ addListener(event: string, listener: (...args: any[]) => void): VirtualFSWatcher;
225
+ listeners(event: string): Function[];
226
+ listenerCount(event: string): number;
227
+ eventNames(): string[];
228
+ getMaxListeners(): number;
229
+ setMaxListeners(n: number): VirtualFSWatcher;
230
+ prependListener(event: string, listener: (...args: any[]) => void): VirtualFSWatcher;
231
+ prependOnceListener(event: string, listener: (...args: any[]) => void): VirtualFSWatcher;
232
+ rawListeners(event: string): Function[];
233
+ }
234
+ /**
235
+ * Create a VirtualFSWatcher instance.
236
+ *
237
+ * @param options - Watch options (structural compatibility with chokidar WatchOptions)
238
+ * @returns VirtualFSWatcher instance
239
+ */
240
+ declare function createVirtualFSWatcher(options?: VirtualWatchOptions): Readonly<VirtualFSWatcher>;
241
+ //#endregion
242
+ //#region src/watcher/subscriber.d.ts
243
+ /**
244
+ * Minimal fs interface required by FileSystemSubscriber.
245
+ */
246
+ interface FileSystemInterfaces {
247
+ existsSync(path: string): boolean;
248
+ writeFileSync(path: string, data: any, options?: any): void;
249
+ unlinkSync(path: string): void;
250
+ mkdirSync(path: string, options?: any): void;
251
+ }
252
+ /**
253
+ * Subscriber for processing filesystem sync messages in Workers.
254
+ */
255
+ interface FileSystemSubscriber {
256
+ /**
257
+ * chokidar compatible {@link VirtualFSWatcher | FSWatcher}.
258
+ */
259
+ readonly watcher: VirtualFSWatcher;
260
+ /**
261
+ * Process a V_FS_* protocol message. Updates vol and notifies watcher.
262
+ */
263
+ handleMessage(message: FileSystemSyncMessage): void;
264
+ }
265
+ /**
266
+ * Options for {@link createFileSystemSubscriber}.
267
+ */
268
+ interface CreateFileSystemSubscriberOptions {
269
+ /**
270
+ * External VirtualFSWatcher instance to use.
271
+ * If provided, the subscriber will use this watcher instead of creating a new one.
272
+ * This allows creating the watcher early (e.g. for DevEnvironment.init)
273
+ * and the subscriber later (e.g. after transformer loads).
274
+ */
275
+ watcher?: VirtualFSWatcher;
276
+ }
277
+ /**
278
+ * Create a {@link FileSystemSubscriber} instance.
279
+ *
280
+ * @param fs - fs instance to use for vol operations.
281
+ * Must be explicitly passed to avoid module instance mismatch when bundlers
282
+ * create separate copies of @vrowser/fs.
283
+ * @param options - Options including optional external watcher
284
+ * @returns FileSystemSubscriber instance with a VirtualFSWatcher
285
+ */
286
+ declare function createFileSystemSubscriber(fs: FileSystemInterfaces, options?: CreateFileSystemSubscriberOptions): Readonly<FileSystemSubscriber>;
287
+ //#endregion
288
+ export { CreateFileSystemSubscriberOptions, FSContentEncoding, FSInitMessage, FSMkdirMessage, FSUnlinkMessage, FSWriteMessage, FileSystemInterfaces, FileSystemPublisher, FileSystemPublisherTarget, FileSystemSubscriber, FileSystemSyncMessage, V_FS_INIT, V_FS_MKDIR, V_FS_UNLINK, V_FS_WRITE, VirtualFSWatcher, VirtualWatchOptions, WatchEventName, createFileSystemPublisher, createFileSystemSubscriber, createVirtualFSWatcher };
289
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/watcher/protocol.ts","../../../src/watcher/publisher.ts","../../../src/watcher/virtual.ts","../../../src/watcher/subscriber.ts"],"sourcesContent":[],"mappings":";;;;;;AAuBA;AAaA;AAqBA;AAWA;AAeA;;;;;AAYA;;;;;;AAOA;AACa,KAhFD,iBAAA,GAgFqC,MAAA,GAAA,QAAA;AACjD;AACA;;;;ACtFA;AAaA;;;;;AAkCoB,UD9BH,cAAA,CC8BG;EAMG,IAAA,EAAA,YAAA;EAAyB;AAShD;;EAEY,IAAA,EAAA,MAAA;EAAT;;;YDtCS;;;;;;EE/BA,OAAA,EAAA,MAAA,GFqCQ,WErCM;AAM1B;AAUA;;;AAasB,UFcL,eAAA,CEdK;EAAwB,IAAA,EAAA,aAAA;EACpB;;;EAGjB,IAAA,EAAA,MAAA;;;;;AAa8B,UFQtB,cAAA,CERsB;EAAiB,IAAA,EAAA,YAAA;EAInD;;;EAGoD,IAAA,EAAA,MAAA;;;;;;;;;AAaiB,UFGzD,aAAA,CEHyD;EAC3C,IAAA,EAAA,WAAA;EAAQ;AASvC;;EAEY,KAAA,CAAA,EFJF,MEIE,CAAA,MAAA,EAAA,MAAA,CAAA;EAAT;;;gBFAa,eAAe;;KAGnB,qBAAA,GACR,iBACA,kBACA,iBACA;cAGS;cACA;cACA;AGnFI,cHoFJ,SGpFwB,EAAA,WAAA;;;;;;;;AHErC;AAaA;AAqBA;AAWA;AAeA;;AAS+B,UCzEd,yBAAA,CDyEc;EAAf,WAAA,CAAA,OAAA,EAAA,GAAA,EAAA,QAAA,ECxEsB,YDwEtB,EAAA,CAAA,EAAA,IAAA;EAAM,WAAA,CAAA,OAAA,EAAA,GAAA,EAAA,OAAA,CAAA,ECvEgB,0BDuEhB,CAAA,EAAA,IAAA;AAGtB;;;;;;AAOA;AACA;AACA;AACa,UCzEI,mBAAA,CDyE4B;;;;ACtF7C;AAaA;;;;EA4B0D,SAAA,CAAA,IAAA,EAAA,MAAA,EAAA,OAAA,EAAA,MAAA,GAnBd,WAmBc,CAAA,EAAA,IAAA;EAMtC;;;AAepB;;EAEY,MAAA,CAAA,IAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAAT;;;;;;;;;ACrEH;AAMA;AAUA;EACW,SAAA,CAAA,KAAA,CAAA,ED6BS,MC7BT,CAAA,MAAA,EAAA,MAAA,CAAA,EAAA,WAAA,CAAA,ED6B+C,MC7B/C,CAAA,MAAA,ED6B8D,WC7B9D,CAAA,CAAA,EAAA,IAAA;EAQK;;;;;EAOL,SAAA,CAAA,MAAA,EDoBS,yBCpBT,CAAA,EAAA,IAAA;EACF;;;;;EAa8B,YAAA,CAAA,MAAA,EDYhB,yBCZgB,CAAA,EAAA,IAAA;;;;;;;;AAW8B,iBDUrD,yBAAA,CCVqD,OAAA,CAAA,EDWzD,yBCXyD,EAAA,CAAA,EDYlE,QCZkE,CDYzD,mBCZyD,CAAA;;;;;;;;AFhDrE;AAaA;AAqBA;AAWA;AAeA;;;AASgB,KE9EJ,cAAA,GF8EI,KAAA,GAAA,QAAA,GAAA,QAAA,GAAA,QAAA,GAAA,WAAA;;AAGhB;;;AAGI,UE9Ea,mBAAA,CF8Eb;EACA,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,GAAA;;AAGJ;AACA;AACA;AACA;;;UE3EiB,gBAAA;EDXA,OAAA,ECYN,mBDZ+B;EAazB;;;;EA4ByC,MAAA,CAAA,KAAA,ECrB1C,cDqB0C,EAAA,IAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAMtC,GAAA,CAAA,KAAA,EAAA,MAAA,GCvBE,aDuBF,CAAA,MAAA,CAAA,CAAA,ECvB0B,gBDuB1B;EAMG,OAAA,CAAA,KAAA,EAAA,MAAA,GC5BG,aD4BH,CAAA,MAAA,CAAA,CAAA,EC5B2B,gBD4B3B;EAAyB,UAAA,EAAA,EAAA;IAShC,CAAA,SAAA,EAAA,MAAA,CAAA,EAAA,MAAyB,EAAA;EAC7B,CAAA;EACA,KAAA,EAAA,ECrCD,ODqCC,CAAA,IAAA,CAAA;EAAT,GAAA,EAAA,ECpCM,gBDoCN;EAAQ,KAAA,EAAA,ECnCA,gBDmCA;yFC5BN;yCAGqB,qDACrB;uCACkC,iBAAiB;uFAInD;4CACuC;uEAC2B;yDACd;EArD7C,GAAA,CAAA,KAAA,EAAA,MAAc,EAAA,QAAA,EAAA,CAAA,GAAA,IAAA,EAAA,GAAA,EAAA,EAAA,GAAA,IAAA,CAAA,EAsDgC,gBAtDhC;EAMT,IAAA,CAAA,KAAA,EAAA,MAAA,EAAA,QAAmB,EAAA,CAAA,GAAA,IAAA,EAAA,GAAA,EAAA,EAAA,GAAA,IAAA,CAAA,EAiDuB,gBAjDvB;EAUnB,IAAA,CAAA,KAAA,EAAA,MAAA,EAAgB,GAAA,IAAA,EAAA,GAAA,EAAA,CAAA,EAAA,OAAA;EACtB,cAAA,CAAA,KAAA,EAAA,MAAA,EAAA,QAAA,EAAA,CAAA,GAAA,IAAA,EAAA,GAAA,EAAA,EAAA,GAAA,IAAA,CAAA,EAwC0D,gBAxC1D;EAQK,kBAAA,CAAA,KAAA,CAAA,EAAA,MAAA,CAAA,EAiCsB,gBAjCtB;EAIM,WAAA,CAAA,KAAA,EAAA,MAAA,EAAA,QAAA,EAAA,CAAA,GAAA,IAAA,EAAA,GAAA,EAAA,EAAA,GAAA,IAAA,CAAA,EA8B4C,gBA9B5C;EAAwB,SAAA,CAAA,KAAA,EAAA,MAAA,CAAA,EA+BlB,QA/BkB,EAAA;EACpB,aAAA,CAAA,KAAA,EAAA,MAAA,CAAA,EAAA,MAAA;EAAwB,UAAA,EAAA,EAAA,MAAA,EAAA;EAEvC,eAAA,EAAA,EAAA,MAAA;EACF,eAAA,CAAA,CAAA,EAAA,MAAA,CAAA,EA+BqB,gBA/BrB;EACE,eAAA,CAAA,KAAA,EAAA,MAAA,EAAA,QAAA,EAAA,CAAA,GAAA,IAAA,EAAA,GAAA,EAAA,EAAA,GAAA,IAAA,CAAA,EA+B2D,gBA/B3D;EAON,mBAAA,CAAA,KAAA,EAAA,MAAA,EAAA,QAAA,EAAA,CAAA,GAAA,IAAA,EAAA,GAAA,EAAA,EAAA,GAAA,IAAA,CAAA,EAyBqE,gBAzBrE;EAGqB,YAAA,CAAA,KAAA,EAAA,MAAA,CAAA,EAuBK,QAvBL,EAAA;;;;;;;;AAUgC,iBAsB1C,sBAAA,CAtB0C,OAAA,CAAA,EAuB/C,mBAvB+C,CAAA,EAwBvD,QAxBuD,CAwB9C,gBAxB8C,CAAA;;;AF2B1D;;;AAGI,UG7Ea,oBAAA,CH6Eb;EACA,UAAA,CAAA,IAAA,EAAA,MAAA,CAAA,EAAA,OAAA;EAAa,aAAA,CAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAA,GAAA,EAAA,OAAA,CAAA,EAAA,GAAA,CAAA,EAAA,IAAA;EAGJ,UAAA,CAAA,IAAkC,EAAA,MAAA,CAAA,EAAA,IAAA;EAClC,SAAA,CAAA,IAAoC,EAAA,MAAA,EAAA,OAAA,CAAA,EAAA,GAAA,CAAA,EAAA,IAAA;AACjD;AACA;;;UG1EiB,oBAAA;EFZA;AAajB;;EA4BoB,SAAA,OAAA,EEzBA,gBFyBA;EAAqD;;;EAYlD,aAAA,CAAA,OAAA,EEjCE,qBFiCF,CAAA,EAAA,IAAA;;AASvB;;;AAEG,UEtCc,iCAAA,CFsCd;EAAQ;;;;;;YE/BC;;ADtCZ;AAMA;AAUA;;;;;;;AAgBW,iBCkBK,0BAAA,CDlBL,EAAA,ECmBL,oBDnBK,EAAA,OAAA,CAAA,ECoBC,iCDpBD,CAAA,ECqBR,QDrBQ,CCqBC,oBDrBD,CAAA"}
@@ -0,0 +1,231 @@
1
+ //#region src/watcher/protocol.ts
2
+ const V_FS_WRITE = "V_FS_WRITE";
3
+ const V_FS_UNLINK = "V_FS_UNLINK";
4
+ const V_FS_MKDIR = "V_FS_MKDIR";
5
+ const V_FS_INIT = "V_FS_INIT";
6
+
7
+ //#endregion
8
+ //#region src/watcher/publisher.ts
9
+ /**
10
+ * Create a {@link FileSystemPublisher} instance.
11
+ *
12
+ * @param targets - Initial postMessage targets (e.g. Worker, ServiceWorker)
13
+ * @returns FileSystemPublisher instance
14
+ */
15
+ function createFileSystemPublisher(targets) {
16
+ const _targets = new Set(targets);
17
+ function broadcast(message, transfer = []) {
18
+ for (const target of _targets) target.postMessage(message, transfer);
19
+ }
20
+ return Object.freeze({
21
+ writeFile(path, content) {
22
+ if (typeof content === "string") broadcast({
23
+ type: "V_FS_WRITE",
24
+ path,
25
+ encoding: "text",
26
+ content
27
+ });
28
+ else {
29
+ const targetList = [..._targets];
30
+ for (let i = 0; i < targetList.length; i++) {
31
+ const buf = i === 0 ? content : content.slice(0);
32
+ const msg = {
33
+ type: "V_FS_WRITE",
34
+ path,
35
+ encoding: "binary",
36
+ content: buf
37
+ };
38
+ targetList[i].postMessage(msg, [buf]);
39
+ }
40
+ }
41
+ },
42
+ unlink(path) {
43
+ broadcast({
44
+ type: "V_FS_UNLINK",
45
+ path
46
+ });
47
+ },
48
+ mkdir(path) {
49
+ broadcast({
50
+ type: "V_FS_MKDIR",
51
+ path
52
+ });
53
+ },
54
+ initFiles(files, binaryFiles) {
55
+ const transfer = binaryFiles ? Object.values(binaryFiles) : [];
56
+ const msg = { type: "V_FS_INIT" };
57
+ if (files) msg.files = files;
58
+ if (binaryFiles) msg.binaryFiles = binaryFiles;
59
+ broadcast(msg, transfer);
60
+ },
61
+ addTarget(target) {
62
+ _targets.add(target);
63
+ },
64
+ removeTarget(target) {
65
+ _targets.delete(target);
66
+ }
67
+ });
68
+ }
69
+
70
+ //#endregion
71
+ //#region src/watcher/virtual.ts
72
+ /**
73
+ * Create a VirtualFSWatcher instance.
74
+ *
75
+ * @param options - Watch options (structural compatibility with chokidar WatchOptions)
76
+ * @returns VirtualFSWatcher instance
77
+ */
78
+ function createVirtualFSWatcher(options = {}) {
79
+ const handlers = /* @__PURE__ */ new Map();
80
+ let closed = false;
81
+ function _emit(event, ...args) {
82
+ const listeners = handlers.get(event);
83
+ if (!listeners?.size) return false;
84
+ for (const handler of [...listeners]) handler(...args);
85
+ return true;
86
+ }
87
+ const watcher = {
88
+ options,
89
+ notify(event, path) {
90
+ if (closed) return;
91
+ _emit(event, path);
92
+ _emit("all", event, path);
93
+ },
94
+ add() {
95
+ return watcher;
96
+ },
97
+ unwatch() {
98
+ return watcher;
99
+ },
100
+ getWatched() {
101
+ return {};
102
+ },
103
+ async close() {
104
+ closed = true;
105
+ handlers.clear();
106
+ },
107
+ ref() {
108
+ return watcher;
109
+ },
110
+ unref() {
111
+ return watcher;
112
+ },
113
+ on(event, listener) {
114
+ if (!handlers.has(event)) handlers.set(event, /* @__PURE__ */ new Set());
115
+ handlers.get(event).add(listener);
116
+ return watcher;
117
+ },
118
+ off(event, listener) {
119
+ handlers.get(event)?.delete(listener);
120
+ return watcher;
121
+ },
122
+ once(event, listener) {
123
+ const wrapper = (...args) => {
124
+ watcher.off(event, wrapper);
125
+ listener(...args);
126
+ };
127
+ return watcher.on(event, wrapper);
128
+ },
129
+ emit(event, ...args) {
130
+ return _emit(event, ...args);
131
+ },
132
+ removeListener(event, listener) {
133
+ return watcher.off(event, listener);
134
+ },
135
+ removeAllListeners(event) {
136
+ if (event) handlers.delete(event);
137
+ else handlers.clear();
138
+ return watcher;
139
+ },
140
+ addListener(event, listener) {
141
+ return watcher.on(event, listener);
142
+ },
143
+ listeners(event) {
144
+ return [...handlers.get(event) ?? []];
145
+ },
146
+ listenerCount(event) {
147
+ return handlers.get(event)?.size ?? 0;
148
+ },
149
+ eventNames() {
150
+ return [...handlers.keys()];
151
+ },
152
+ getMaxListeners() {
153
+ return Infinity;
154
+ },
155
+ setMaxListeners() {
156
+ return watcher;
157
+ },
158
+ prependListener(event, listener) {
159
+ return watcher.on(event, listener);
160
+ },
161
+ prependOnceListener(event, listener) {
162
+ return watcher.once(event, listener);
163
+ },
164
+ rawListeners(event) {
165
+ return watcher.listeners(event);
166
+ }
167
+ };
168
+ return Object.freeze(watcher);
169
+ }
170
+
171
+ //#endregion
172
+ //#region src/watcher/subscriber.ts
173
+ /**
174
+ * Create a {@link FileSystemSubscriber} instance.
175
+ *
176
+ * @param fs - fs instance to use for vol operations.
177
+ * Must be explicitly passed to avoid module instance mismatch when bundlers
178
+ * create separate copies of @vrowser/fs.
179
+ * @param options - Options including optional external watcher
180
+ * @returns FileSystemSubscriber instance with a VirtualFSWatcher
181
+ */
182
+ function createFileSystemSubscriber(fs, options) {
183
+ const watcher = options?.watcher ?? createVirtualFSWatcher();
184
+ function ensureDir(filePath) {
185
+ const dir = filePath.substring(0, filePath.lastIndexOf("/"));
186
+ if (dir && !fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
187
+ }
188
+ function writeToVol(path, encoding, content) {
189
+ ensureDir(path);
190
+ if (encoding === "binary") fs.writeFileSync(path, new Uint8Array(content));
191
+ else fs.writeFileSync(path, content, { encoding: "utf8" });
192
+ }
193
+ function handleMessage(message) {
194
+ switch (message.type) {
195
+ case "V_FS_WRITE": {
196
+ const exists = fs.existsSync(message.path);
197
+ writeToVol(message.path, message.encoding, message.content);
198
+ watcher.notify(exists ? "change" : "add", message.path);
199
+ break;
200
+ }
201
+ case "V_FS_UNLINK":
202
+ if (fs.existsSync(message.path)) {
203
+ fs.unlinkSync(message.path);
204
+ watcher.notify("unlink", message.path);
205
+ }
206
+ break;
207
+ case "V_FS_MKDIR":
208
+ fs.mkdirSync(message.path, { recursive: true });
209
+ watcher.notify("addDir", message.path);
210
+ break;
211
+ case "V_FS_INIT":
212
+ if (message.files) for (const [path, content] of Object.entries(message.files)) {
213
+ writeToVol(path, "text", content);
214
+ watcher.notify("add", path);
215
+ }
216
+ if (message.binaryFiles) for (const [path, content] of Object.entries(message.binaryFiles)) {
217
+ writeToVol(path, "binary", content);
218
+ watcher.notify("add", path);
219
+ }
220
+ break;
221
+ }
222
+ }
223
+ return Object.freeze({
224
+ watcher,
225
+ handleMessage
226
+ });
227
+ }
228
+
229
+ //#endregion
230
+ export { V_FS_INIT, V_FS_MKDIR, V_FS_UNLINK, V_FS_WRITE, createFileSystemPublisher, createFileSystemSubscriber, createVirtualFSWatcher };
231
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["msg: FSWriteMessage","transfer: Transferable[]","msg: FSInitMessage","watcher: VirtualFSWatcher"],"sources":["../../../src/watcher/protocol.ts","../../../src/watcher/publisher.ts","../../../src/watcher/virtual.ts","../../../src/watcher/subscriber.ts"],"sourcesContent":["/**\n * File System Sync Protocol\n *\n * Message types for synchronizing file operations between\n * Main Thread (Publisher) and Workers (Subscribers).\n *\n * @module watcher/protocol\n */\n\n/**\n * @author kazuya kawaguchi (a.k.a. kazupon)\n * @license MIT\n */\n\n/**\n * File content encoding type.\n * - 'text': UTF-8 string content (JS, TS, JSON, CSS, HTML, etc.)\n * - 'binary': ArrayBuffer content (images, WASM, fonts, etc.)\n *\n * When encoding is 'binary', the content is an ArrayBuffer\n * and MUST be transferred via postMessage's transfer list\n * for zero-copy performance.\n */\nexport type FSContentEncoding = 'text' | 'binary'\n\n/**\n * Main Thread -> Worker: Write (create or update) a file.\n *\n * For text files:\n * { type: 'V_FS_WRITE', path: '/main.js', encoding: 'text', content: '...' }\n * -> postMessage(message)\n *\n * For binary files:\n * { type: 'V_FS_WRITE', path: '/image.png', encoding: 'binary', content: ArrayBuffer }\n * -> postMessage(message, [message.content]) // transfer list\n */\nexport interface FSWriteMessage {\n type: 'V_FS_WRITE'\n /**\n * Path of the file to write. Must not end with '/' (directories use FS_MKDIR with path ending in '/').\n */\n path: string\n /**\n * Encoding of the content. Determines how the Worker should interpret the content.\n */\n encoding: FSContentEncoding\n /**\n * Content of the file. Type depends on encoding:\n * - 'text': UTF-8 string content\n * - 'binary': ArrayBuffer content (transferred via postMessage's transfer list)\n */\n content: string | ArrayBuffer\n}\n\n/**\n * Main Thread -> Worker: Delete a file.\n */\nexport interface FSUnlinkMessage {\n type: 'V_FS_UNLINK'\n /**\n * Path of the file to delete. Must not end with '/' (directories use FS_MKDIR with path ending in '/').\n */\n path: string\n}\n\n/**\n * Main Thread -> Worker: Create a directory.\n */\nexport interface FSMkdirMessage {\n type: 'V_FS_MKDIR'\n /**\n * Path of the directory to create. Must end with '/' to distinguish from files.\n */\n path: string\n}\n\n/**\n * Main Thread -> Worker: Initialize files in bulk.\n * Used during setup to populate the virtual filesystem.\n *\n * Text files are in `files`, binary files are in `binaryFiles`.\n * Binary ArrayBuffers are transferred via postMessage's transfer list.\n */\nexport interface FSInitMessage {\n type: 'V_FS_INIT'\n /**\n * Text files: path -> UTF-8 string content\n */\n files?: Record<string, string>\n /**\n * Binary files: path -> ArrayBuffer content (transferred)\n */\n binaryFiles?: Record<string, ArrayBuffer>\n}\n\nexport type FileSystemSyncMessage =\n | FSWriteMessage\n | FSUnlinkMessage\n | FSMkdirMessage\n | FSInitMessage\n\n// Constants\nexport const V_FS_WRITE = 'V_FS_WRITE' as const\nexport const V_FS_UNLINK = 'V_FS_UNLINK' as const\nexport const V_FS_MKDIR = 'V_FS_MKDIR' as const\nexport const V_FS_INIT = 'V_FS_INIT' as const\n","/**\n * FileSystemPublisher - Main Thread side of the Pub-Sub filesystem sync.\n *\n * Sends V_FS_* protocol messages to Worker targets (Service Worker, Web Worker).\n * Provides a `node:fs`-like API for reduced cognitive load.\n *\n * @module watcher/publisher\n */\n\n/**\n * @author kazuya kawaguchi (a.k.a. kazupon)\n * @license MIT\n */\n\nimport type { FSInitMessage, FSWriteMessage, FileSystemSyncMessage } from './protocol.ts'\n\n/**\n * A postMessage target compatible like Service Worker and Web Worker APIs.\n */\nexport interface FileSystemPublisherTarget {\n postMessage(message: any, transfer: Transferable[]): void\n postMessage(message: any, options?: StructuredSerializeOptions): void\n}\n\n/**\n * Publisher for broadcasting filesystem operations to Workers.\n *\n * API is modeled after `node:fs` for familiarity:\n * - `writeFile` accepts both `string` (text) and `ArrayBuffer` (binary)\n * - `unlink` deletes a file\n * - `mkdir` creates a directory\n */\nexport interface FileSystemPublisher {\n /**\n * Write a file. Encoding is inferred: string → text, ArrayBuffer → binary.\n *\n * @param path - Path of the file to write. Must not end with '/' (directories use mkdir with path ending in '/').\n * @param content - Content of the file. Type determines encoding:\n * - string: UTF-8 text content\n * - ArrayBuffer: binary content (transferred via postMessage's transfer list for zero-copy performance)\n */\n writeFile(path: string, content: string | ArrayBuffer): void\n /**\n * Delete a file.\n *\n * @param path - Path of the file to delete. Must not end with '/' (directories use mkdir with path ending in '/').\n */\n unlink(path: string): void\n /**\n * Create a directory.\n *\n * @param path - Path of the directory to create. Must end with '/' to distinguish from files.\n */\n mkdir(path: string): void\n /**\n * Initialize files in bulk.\n *\n * @param files - Text files: path -> UTF-8 string content\n * @param binaryFiles - Binary files: path -> ArrayBuffer content (transferred)\n */\n initFiles(files?: Record<string, string>, binaryFiles?: Record<string, ArrayBuffer>): void\n /**\n * Add a postMessage target.\n *\n * @param target - The target to add (e.g. Worker, ServiceWorker)\n */\n addTarget(target: FileSystemPublisherTarget): void\n /**\n * Remove a postMessage target.\n *\n * @param target - The target to remove (e.g. Worker, ServiceWorker)\n */\n removeTarget(target: FileSystemPublisherTarget): void\n}\n\n/**\n * Create a {@link FileSystemPublisher} instance.\n *\n * @param targets - Initial postMessage targets (e.g. Worker, ServiceWorker)\n * @returns FileSystemPublisher instance\n */\nexport function createFileSystemPublisher(\n targets?: FileSystemPublisherTarget[]\n): Readonly<FileSystemPublisher> {\n const _targets = new Set<FileSystemPublisherTarget>(targets)\n\n function broadcast(message: FileSystemSyncMessage, transfer: Transferable[] = []) {\n for (const target of _targets) {\n target.postMessage(message, transfer)\n }\n }\n\n const instance: FileSystemPublisher = {\n writeFile(path, content) {\n if (typeof content === 'string') {\n broadcast({ type: 'V_FS_WRITE', path, encoding: 'text', content })\n } else {\n // ArrayBuffer: transfer list for zero-copy.\n // First target gets the original buffer, subsequent targets get copies.\n const targetList = [..._targets]\n for (let i = 0; i < targetList.length; i++) {\n const buf = i === 0 ? content : content.slice(0)\n const msg: FSWriteMessage = { type: 'V_FS_WRITE', path, encoding: 'binary', content: buf }\n // @ts-expect-error - postMessage with transfer list is supported by both Worker and ServiceWorker targets, but TypeScript typings may not reflect this accurately.\n targetList[i].postMessage(msg, [buf])\n }\n }\n },\n\n unlink(path) {\n broadcast({ type: 'V_FS_UNLINK', path })\n },\n\n mkdir(path) {\n broadcast({ type: 'V_FS_MKDIR', path })\n },\n\n initFiles(files, binaryFiles) {\n const transfer: Transferable[] = binaryFiles ? Object.values(binaryFiles) : []\n const msg: FSInitMessage = { type: 'V_FS_INIT' }\n if (files) {\n msg.files = files\n }\n if (binaryFiles) {\n msg.binaryFiles = binaryFiles\n }\n broadcast(msg, transfer)\n },\n\n addTarget(target) {\n _targets.add(target)\n },\n\n removeTarget(target) {\n _targets.delete(target)\n }\n }\n\n return Object.freeze(instance)\n}\n","/**\n * VirtualFSWatcher - chokidar compatible FSWatcher for virtual filesystems.\n *\n * Unlike real chokidar, this watcher does not monitor the filesystem.\n * File events are triggered externally via `notify()` by the FileSystemSubscriber.\n *\n * @module watcher/virtual\n */\n\n/**\n * @author kazuya kawaguchi (a.k.a. kazupon)\n * @license MIT\n */\n\nexport type WatchEventName = 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir'\n\n/**\n * Watch options for VirtualFSWatcher.\n * Uses an index signature for structural compatibility with chokidar's WatchOptions.\n */\nexport interface VirtualWatchOptions {\n [key: string]: any\n}\n\n/**\n * chokidar compatible FSWatcher interface for virtual filesystems.\n *\n * This interface is the base type that vite-dev-server's `FSWatcher` extends.\n * The `notify()` method is specific to VirtualFSWatcher.\n */\nexport interface VirtualFSWatcher {\n options: VirtualWatchOptions\n\n // ---- VirtualFSWatcher specific ----\n\n /**\n * Notify the watcher of a file event.\n * Called by FileSystemSubscriber when a V_FS_* message is received.\n */\n notify(event: WatchEventName, path: string): void\n\n // ---- chokidar FSWatcher interface ----\n\n add(paths: string | ReadonlyArray<string>): VirtualFSWatcher\n unwatch(paths: string | ReadonlyArray<string>): VirtualFSWatcher\n getWatched(): { [directory: string]: string[] }\n close(): Promise<void>\n ref(): VirtualFSWatcher\n unref(): VirtualFSWatcher\n\n // ---- EventEmitter I/F (chokidar compatible) ----\n\n on(\n event: 'add' | 'addDir' | 'change',\n listener: (path: string, stats?: any) => void\n ): VirtualFSWatcher\n on(\n event: 'all',\n listener: (eventName: WatchEventName, path: string, stats?: any) => void\n ): VirtualFSWatcher\n on(event: 'error', listener: (error: Error) => void): VirtualFSWatcher\n on(\n event: 'raw',\n listener: (eventName: string, path: string, details: any) => void\n ): VirtualFSWatcher\n on(event: 'ready', listener: () => void): VirtualFSWatcher\n on(event: 'unlink' | 'unlinkDir', listener: (path: string) => void): VirtualFSWatcher\n on(event: string, listener: (...args: any[]) => void): VirtualFSWatcher\n off(event: string, listener: (...args: any[]) => void): VirtualFSWatcher\n once(event: string, listener: (...args: any[]) => void): VirtualFSWatcher\n emit(event: string, ...args: any[]): boolean\n removeListener(event: string, listener: (...args: any[]) => void): VirtualFSWatcher\n removeAllListeners(event?: string): VirtualFSWatcher\n addListener(event: string, listener: (...args: any[]) => void): VirtualFSWatcher\n listeners(event: string): Function[]\n listenerCount(event: string): number\n eventNames(): string[]\n getMaxListeners(): number\n setMaxListeners(n: number): VirtualFSWatcher\n prependListener(event: string, listener: (...args: any[]) => void): VirtualFSWatcher\n prependOnceListener(event: string, listener: (...args: any[]) => void): VirtualFSWatcher\n rawListeners(event: string): Function[]\n}\n\n/**\n * Create a VirtualFSWatcher instance.\n *\n * @param options - Watch options (structural compatibility with chokidar WatchOptions)\n * @returns VirtualFSWatcher instance\n */\nexport function createVirtualFSWatcher(\n options: VirtualWatchOptions = {}\n): Readonly<VirtualFSWatcher> {\n const handlers = new Map<string, Set<(...args: any[]) => void>>()\n let closed = false\n\n function _emit(event: string, ...args: any[]): boolean {\n const listeners = handlers.get(event)\n if (!listeners?.size) {\n return false\n }\n // Clone the set before iterating to avoid issues if handlers are modified during iteration\n for (const handler of [...listeners]) {\n handler(...args)\n }\n return true\n }\n\n const watcher: VirtualFSWatcher = {\n options,\n\n // ---- VirtualFSWatcher specific ----\n\n notify(event, path) {\n if (closed) {\n return\n }\n _emit(event, path)\n _emit('all', event, path)\n },\n\n // ---- chokidar FSWatcher interface ----\n\n add() {\n return watcher\n },\n unwatch() {\n return watcher\n },\n getWatched() {\n return {}\n },\n async close() {\n closed = true\n handlers.clear()\n },\n ref() {\n return watcher\n },\n unref() {\n return watcher\n },\n\n // ---- EventEmitter I/F ----\n\n on(event: string, listener: (...args: any[]) => void) {\n if (!handlers.has(event)) {\n handlers.set(event, new Set())\n }\n handlers.get(event)!.add(listener)\n return watcher\n },\n\n off(event, listener) {\n handlers.get(event)?.delete(listener)\n return watcher\n },\n\n once(event, listener) {\n const wrapper = (...args: any[]) => {\n watcher.off(event, wrapper)\n listener(...args)\n }\n return watcher.on(event, wrapper)\n },\n\n emit(event, ...args) {\n return _emit(event, ...args)\n },\n\n removeListener(event, listener) {\n return watcher.off(event, listener)\n },\n\n removeAllListeners(event?) {\n if (event) {\n handlers.delete(event)\n } else {\n handlers.clear()\n }\n return watcher\n },\n\n addListener(event, listener) {\n return watcher.on(event, listener)\n },\n\n listeners(event) {\n return [...(handlers.get(event) ?? [])]\n },\n\n listenerCount(event) {\n return handlers.get(event)?.size ?? 0\n },\n\n eventNames() {\n return [...handlers.keys()]\n },\n\n getMaxListeners() {\n return Infinity\n },\n setMaxListeners() {\n return watcher\n },\n\n prependListener(event, listener) {\n return watcher.on(event, listener)\n },\n\n prependOnceListener(event, listener) {\n return watcher.once(event, listener)\n },\n\n rawListeners(event) {\n return watcher.listeners(event)\n }\n }\n\n return Object.freeze(watcher)\n}\n","/**\n * FileSystemSubscriber - Worker side of the Pub-Sub filesystem sync.\n *\n * Receives V_FS_* protocol messages, updates the @vrowser/fs memfs volume,\n * and notifies the VirtualFSWatcher to trigger chokidar-compatible events.\n *\n * @module watcher/subscriber\n */\n\n/**\n * @author kazuya kawaguchi (a.k.a. kazupon)\n * @license MIT\n */\n\nimport type { FSContentEncoding, FileSystemSyncMessage } from './protocol.ts'\nimport type { VirtualFSWatcher } from './virtual.ts'\nimport { createVirtualFSWatcher } from './virtual.ts'\n\n/**\n * Minimal fs interface required by FileSystemSubscriber.\n */\nexport interface FileSystemInterfaces {\n existsSync(path: string): boolean\n writeFileSync(path: string, data: any, options?: any): void\n unlinkSync(path: string): void\n mkdirSync(path: string, options?: any): void\n}\n\n/**\n * Subscriber for processing filesystem sync messages in Workers.\n */\nexport interface FileSystemSubscriber {\n /**\n * chokidar compatible {@link VirtualFSWatcher | FSWatcher}.\n */\n readonly watcher: VirtualFSWatcher\n /**\n * Process a V_FS_* protocol message. Updates vol and notifies watcher.\n */\n handleMessage(message: FileSystemSyncMessage): void\n}\n\n/**\n * Options for {@link createFileSystemSubscriber}.\n */\nexport interface CreateFileSystemSubscriberOptions {\n /**\n * External VirtualFSWatcher instance to use.\n * If provided, the subscriber will use this watcher instead of creating a new one.\n * This allows creating the watcher early (e.g. for DevEnvironment.init)\n * and the subscriber later (e.g. after transformer loads).\n */\n watcher?: VirtualFSWatcher\n}\n\n/**\n * Create a {@link FileSystemSubscriber} instance.\n *\n * @param fs - fs instance to use for vol operations.\n * Must be explicitly passed to avoid module instance mismatch when bundlers\n * create separate copies of @vrowser/fs.\n * @param options - Options including optional external watcher\n * @returns FileSystemSubscriber instance with a VirtualFSWatcher\n */\nexport function createFileSystemSubscriber(\n fs: FileSystemInterfaces,\n options?: CreateFileSystemSubscriberOptions\n): Readonly<FileSystemSubscriber> {\n const watcher = options?.watcher ?? createVirtualFSWatcher()\n\n function ensureDir(filePath: string): void {\n const dir = filePath.substring(0, filePath.lastIndexOf('/'))\n if (dir && !fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n }\n\n function writeToVol(\n path: string,\n encoding: FSContentEncoding,\n content: string | ArrayBuffer\n ): void {\n ensureDir(path)\n if (encoding === 'binary') {\n fs.writeFileSync(path, new Uint8Array(content as ArrayBuffer))\n } else {\n fs.writeFileSync(path, content as string, { encoding: 'utf8' })\n }\n }\n\n function handleMessage(message: FileSystemSyncMessage): void {\n switch (message.type) {\n case 'V_FS_WRITE': {\n const exists = fs.existsSync(message.path)\n writeToVol(message.path, message.encoding, message.content)\n watcher.notify(exists ? 'change' : 'add', message.path)\n break\n }\n\n case 'V_FS_UNLINK': {\n if (fs.existsSync(message.path)) {\n fs.unlinkSync(message.path)\n watcher.notify('unlink', message.path)\n }\n break\n }\n\n case 'V_FS_MKDIR': {\n fs.mkdirSync(message.path, { recursive: true })\n watcher.notify('addDir', message.path)\n break\n }\n\n case 'V_FS_INIT': {\n if (message.files) {\n for (const [path, content] of Object.entries(message.files)) {\n writeToVol(path, 'text', content)\n watcher.notify('add', path)\n }\n }\n if (message.binaryFiles) {\n for (const [path, content] of Object.entries(message.binaryFiles)) {\n writeToVol(path, 'binary', content)\n watcher.notify('add', path)\n }\n }\n break\n }\n }\n }\n\n return Object.freeze({ watcher, handleMessage })\n}\n"],"mappings":"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"}