almostnode 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +731 -0
  3. package/dist/__sw__.js +394 -0
  4. package/dist/ai-chatbot-demo-entry.d.ts +6 -0
  5. package/dist/ai-chatbot-demo-entry.d.ts.map +1 -0
  6. package/dist/ai-chatbot-demo.d.ts +42 -0
  7. package/dist/ai-chatbot-demo.d.ts.map +1 -0
  8. package/dist/assets/runtime-worker-D9x_Ddwz.js +60543 -0
  9. package/dist/assets/runtime-worker-D9x_Ddwz.js.map +1 -0
  10. package/dist/convex-app-demo-entry.d.ts +6 -0
  11. package/dist/convex-app-demo-entry.d.ts.map +1 -0
  12. package/dist/convex-app-demo.d.ts +68 -0
  13. package/dist/convex-app-demo.d.ts.map +1 -0
  14. package/dist/cors-proxy.d.ts +46 -0
  15. package/dist/cors-proxy.d.ts.map +1 -0
  16. package/dist/create-runtime.d.ts +42 -0
  17. package/dist/create-runtime.d.ts.map +1 -0
  18. package/dist/demo.d.ts +6 -0
  19. package/dist/demo.d.ts.map +1 -0
  20. package/dist/dev-server.d.ts +97 -0
  21. package/dist/dev-server.d.ts.map +1 -0
  22. package/dist/frameworks/next-dev-server.d.ts +202 -0
  23. package/dist/frameworks/next-dev-server.d.ts.map +1 -0
  24. package/dist/frameworks/vite-dev-server.d.ts +85 -0
  25. package/dist/frameworks/vite-dev-server.d.ts.map +1 -0
  26. package/dist/index.cjs +14965 -0
  27. package/dist/index.cjs.map +1 -0
  28. package/dist/index.d.ts +71 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.mjs +14867 -0
  31. package/dist/index.mjs.map +1 -0
  32. package/dist/next-demo.d.ts +49 -0
  33. package/dist/next-demo.d.ts.map +1 -0
  34. package/dist/npm/index.d.ts +71 -0
  35. package/dist/npm/index.d.ts.map +1 -0
  36. package/dist/npm/registry.d.ts +66 -0
  37. package/dist/npm/registry.d.ts.map +1 -0
  38. package/dist/npm/resolver.d.ts +52 -0
  39. package/dist/npm/resolver.d.ts.map +1 -0
  40. package/dist/npm/tarball.d.ts +29 -0
  41. package/dist/npm/tarball.d.ts.map +1 -0
  42. package/dist/runtime-interface.d.ts +90 -0
  43. package/dist/runtime-interface.d.ts.map +1 -0
  44. package/dist/runtime.d.ts +103 -0
  45. package/dist/runtime.d.ts.map +1 -0
  46. package/dist/sandbox-helpers.d.ts +43 -0
  47. package/dist/sandbox-helpers.d.ts.map +1 -0
  48. package/dist/sandbox-runtime.d.ts +65 -0
  49. package/dist/sandbox-runtime.d.ts.map +1 -0
  50. package/dist/server-bridge.d.ts +89 -0
  51. package/dist/server-bridge.d.ts.map +1 -0
  52. package/dist/shims/assert.d.ts +51 -0
  53. package/dist/shims/assert.d.ts.map +1 -0
  54. package/dist/shims/async_hooks.d.ts +37 -0
  55. package/dist/shims/async_hooks.d.ts.map +1 -0
  56. package/dist/shims/buffer.d.ts +20 -0
  57. package/dist/shims/buffer.d.ts.map +1 -0
  58. package/dist/shims/child_process-browser.d.ts +92 -0
  59. package/dist/shims/child_process-browser.d.ts.map +1 -0
  60. package/dist/shims/child_process.d.ts +93 -0
  61. package/dist/shims/child_process.d.ts.map +1 -0
  62. package/dist/shims/chokidar.d.ts +55 -0
  63. package/dist/shims/chokidar.d.ts.map +1 -0
  64. package/dist/shims/cluster.d.ts +52 -0
  65. package/dist/shims/cluster.d.ts.map +1 -0
  66. package/dist/shims/crypto.d.ts +122 -0
  67. package/dist/shims/crypto.d.ts.map +1 -0
  68. package/dist/shims/dgram.d.ts +34 -0
  69. package/dist/shims/dgram.d.ts.map +1 -0
  70. package/dist/shims/diagnostics_channel.d.ts +80 -0
  71. package/dist/shims/diagnostics_channel.d.ts.map +1 -0
  72. package/dist/shims/dns.d.ts +87 -0
  73. package/dist/shims/dns.d.ts.map +1 -0
  74. package/dist/shims/domain.d.ts +25 -0
  75. package/dist/shims/domain.d.ts.map +1 -0
  76. package/dist/shims/esbuild.d.ts +105 -0
  77. package/dist/shims/esbuild.d.ts.map +1 -0
  78. package/dist/shims/events.d.ts +37 -0
  79. package/dist/shims/events.d.ts.map +1 -0
  80. package/dist/shims/fs.d.ts +115 -0
  81. package/dist/shims/fs.d.ts.map +1 -0
  82. package/dist/shims/fsevents.d.ts +67 -0
  83. package/dist/shims/fsevents.d.ts.map +1 -0
  84. package/dist/shims/http.d.ts +217 -0
  85. package/dist/shims/http.d.ts.map +1 -0
  86. package/dist/shims/http2.d.ts +81 -0
  87. package/dist/shims/http2.d.ts.map +1 -0
  88. package/dist/shims/https.d.ts +36 -0
  89. package/dist/shims/https.d.ts.map +1 -0
  90. package/dist/shims/inspector.d.ts +25 -0
  91. package/dist/shims/inspector.d.ts.map +1 -0
  92. package/dist/shims/module.d.ts +22 -0
  93. package/dist/shims/module.d.ts.map +1 -0
  94. package/dist/shims/net.d.ts +100 -0
  95. package/dist/shims/net.d.ts.map +1 -0
  96. package/dist/shims/os.d.ts +159 -0
  97. package/dist/shims/os.d.ts.map +1 -0
  98. package/dist/shims/path.d.ts +72 -0
  99. package/dist/shims/path.d.ts.map +1 -0
  100. package/dist/shims/perf_hooks.d.ts +50 -0
  101. package/dist/shims/perf_hooks.d.ts.map +1 -0
  102. package/dist/shims/process.d.ts +93 -0
  103. package/dist/shims/process.d.ts.map +1 -0
  104. package/dist/shims/querystring.d.ts +23 -0
  105. package/dist/shims/querystring.d.ts.map +1 -0
  106. package/dist/shims/readdirp.d.ts +52 -0
  107. package/dist/shims/readdirp.d.ts.map +1 -0
  108. package/dist/shims/readline.d.ts +62 -0
  109. package/dist/shims/readline.d.ts.map +1 -0
  110. package/dist/shims/rollup.d.ts +34 -0
  111. package/dist/shims/rollup.d.ts.map +1 -0
  112. package/dist/shims/sentry.d.ts +163 -0
  113. package/dist/shims/sentry.d.ts.map +1 -0
  114. package/dist/shims/stream.d.ts +181 -0
  115. package/dist/shims/stream.d.ts.map +1 -0
  116. package/dist/shims/tls.d.ts +53 -0
  117. package/dist/shims/tls.d.ts.map +1 -0
  118. package/dist/shims/tty.d.ts +30 -0
  119. package/dist/shims/tty.d.ts.map +1 -0
  120. package/dist/shims/url.d.ts +64 -0
  121. package/dist/shims/url.d.ts.map +1 -0
  122. package/dist/shims/util.d.ts +106 -0
  123. package/dist/shims/util.d.ts.map +1 -0
  124. package/dist/shims/v8.d.ts +73 -0
  125. package/dist/shims/v8.d.ts.map +1 -0
  126. package/dist/shims/vfs-adapter.d.ts +126 -0
  127. package/dist/shims/vfs-adapter.d.ts.map +1 -0
  128. package/dist/shims/vm.d.ts +45 -0
  129. package/dist/shims/vm.d.ts.map +1 -0
  130. package/dist/shims/worker_threads.d.ts +66 -0
  131. package/dist/shims/worker_threads.d.ts.map +1 -0
  132. package/dist/shims/ws.d.ts +66 -0
  133. package/dist/shims/ws.d.ts.map +1 -0
  134. package/dist/shims/zlib.d.ts +161 -0
  135. package/dist/shims/zlib.d.ts.map +1 -0
  136. package/dist/transform.d.ts +24 -0
  137. package/dist/transform.d.ts.map +1 -0
  138. package/dist/virtual-fs.d.ts +226 -0
  139. package/dist/virtual-fs.d.ts.map +1 -0
  140. package/dist/vite-demo.d.ts +35 -0
  141. package/dist/vite-demo.d.ts.map +1 -0
  142. package/dist/vite-sw.js +132 -0
  143. package/dist/worker/runtime-worker.d.ts +8 -0
  144. package/dist/worker/runtime-worker.d.ts.map +1 -0
  145. package/dist/worker-runtime.d.ts +50 -0
  146. package/dist/worker-runtime.d.ts.map +1 -0
  147. package/package.json +85 -0
  148. package/src/ai-chatbot-demo-entry.ts +244 -0
  149. package/src/ai-chatbot-demo.ts +509 -0
  150. package/src/convex-app-demo-entry.ts +1107 -0
  151. package/src/convex-app-demo.ts +1316 -0
  152. package/src/cors-proxy.ts +81 -0
  153. package/src/create-runtime.ts +147 -0
  154. package/src/demo.ts +304 -0
  155. package/src/dev-server.ts +274 -0
  156. package/src/frameworks/next-dev-server.ts +2224 -0
  157. package/src/frameworks/vite-dev-server.ts +702 -0
  158. package/src/index.ts +101 -0
  159. package/src/next-demo.ts +1784 -0
  160. package/src/npm/index.ts +347 -0
  161. package/src/npm/registry.ts +152 -0
  162. package/src/npm/resolver.ts +385 -0
  163. package/src/npm/tarball.ts +209 -0
  164. package/src/runtime-interface.ts +103 -0
  165. package/src/runtime.ts +1046 -0
  166. package/src/sandbox-helpers.ts +173 -0
  167. package/src/sandbox-runtime.ts +252 -0
  168. package/src/server-bridge.ts +426 -0
  169. package/src/shims/assert.ts +664 -0
  170. package/src/shims/async_hooks.ts +86 -0
  171. package/src/shims/buffer.ts +75 -0
  172. package/src/shims/child_process-browser.ts +217 -0
  173. package/src/shims/child_process.ts +463 -0
  174. package/src/shims/chokidar.ts +313 -0
  175. package/src/shims/cluster.ts +67 -0
  176. package/src/shims/crypto.ts +830 -0
  177. package/src/shims/dgram.ts +47 -0
  178. package/src/shims/diagnostics_channel.ts +196 -0
  179. package/src/shims/dns.ts +172 -0
  180. package/src/shims/domain.ts +58 -0
  181. package/src/shims/esbuild.ts +805 -0
  182. package/src/shims/events.ts +195 -0
  183. package/src/shims/fs.ts +803 -0
  184. package/src/shims/fsevents.ts +63 -0
  185. package/src/shims/http.ts +904 -0
  186. package/src/shims/http2.ts +96 -0
  187. package/src/shims/https.ts +86 -0
  188. package/src/shims/inspector.ts +30 -0
  189. package/src/shims/module.ts +82 -0
  190. package/src/shims/net.ts +359 -0
  191. package/src/shims/os.ts +195 -0
  192. package/src/shims/path.ts +199 -0
  193. package/src/shims/perf_hooks.ts +92 -0
  194. package/src/shims/process.ts +346 -0
  195. package/src/shims/querystring.ts +97 -0
  196. package/src/shims/readdirp.ts +228 -0
  197. package/src/shims/readline.ts +110 -0
  198. package/src/shims/rollup.ts +80 -0
  199. package/src/shims/sentry.ts +133 -0
  200. package/src/shims/stream.ts +1126 -0
  201. package/src/shims/tls.ts +95 -0
  202. package/src/shims/tty.ts +64 -0
  203. package/src/shims/url.ts +171 -0
  204. package/src/shims/util.ts +312 -0
  205. package/src/shims/v8.ts +113 -0
  206. package/src/shims/vfs-adapter.ts +402 -0
  207. package/src/shims/vm.ts +83 -0
  208. package/src/shims/worker_threads.ts +111 -0
  209. package/src/shims/ws.ts +382 -0
  210. package/src/shims/zlib.ts +289 -0
  211. package/src/transform.ts +313 -0
  212. package/src/types/external.d.ts +67 -0
  213. package/src/virtual-fs.ts +903 -0
  214. package/src/vite-demo.ts +577 -0
  215. package/src/worker/runtime-worker.ts +128 -0
  216. package/src/worker-runtime.ts +145 -0
@@ -0,0 +1,803 @@
1
+ /**
2
+ * Node.js fs module shim
3
+ * Wraps VirtualFS to provide Node.js compatible API
4
+ */
5
+
6
+ import { VirtualFS, createNodeError } from '../virtual-fs';
7
+ import type { Stats, FSWatcher, WatchListener, WatchEventType } from '../virtual-fs';
8
+
9
+ export type { Stats, FSWatcher, WatchListener, WatchEventType };
10
+
11
+ export interface FsShim {
12
+ readFileSync(path: string): Buffer;
13
+ readFileSync(path: string, encoding: 'utf8' | 'utf-8'): string;
14
+ readFileSync(path: string, options: { encoding: 'utf8' | 'utf-8' }): string;
15
+ readFileSync(path: string, options: { encoding?: null }): Buffer;
16
+ writeFileSync(path: string, data: string | Uint8Array): void;
17
+ existsSync(path: string): boolean;
18
+ mkdirSync(path: string, options?: { recursive?: boolean }): void;
19
+ readdirSync(path: string): string[];
20
+ readdirSync(path: string, options: { withFileTypes: true }): Dirent[];
21
+ readdirSync(path: string, options?: { withFileTypes?: boolean; encoding?: string } | string): string[] | Dirent[];
22
+ statSync(path: string): Stats;
23
+ lstatSync(path: string): Stats;
24
+ fstatSync(fd: number): Stats;
25
+ unlinkSync(path: string): void;
26
+ rmdirSync(path: string): void;
27
+ renameSync(oldPath: string, newPath: string): void;
28
+ realpathSync(path: string): string;
29
+ accessSync(path: string, mode?: number): void;
30
+ copyFileSync(src: string, dest: string): void;
31
+ openSync(path: string, flags: string | number, mode?: number): number;
32
+ closeSync(fd: number): void;
33
+ readSync(fd: number, buffer: Buffer | Uint8Array, offset: number, length: number, position: number | null): number;
34
+ writeSync(fd: number, buffer: Buffer | Uint8Array | string, offset?: number, length?: number, position?: number | null): number;
35
+ ftruncateSync(fd: number, len?: number): void;
36
+ fsyncSync(fd: number): void;
37
+ fdatasyncSync(fd: number): void;
38
+ mkdtempSync(prefix: string): string;
39
+ rmSync(path: string, options?: { recursive?: boolean; force?: boolean }): void;
40
+ watch(filename: string, options?: { persistent?: boolean; recursive?: boolean }, listener?: WatchListener): FSWatcher;
41
+ watch(filename: string, listener?: WatchListener): FSWatcher;
42
+ readFile(path: string, callback: (err: Error | null, data?: Uint8Array) => void): void;
43
+ readFile(path: string, options: { encoding: string }, callback: (err: Error | null, data?: string) => void): void;
44
+ stat(path: string, callback: (err: Error | null, stats?: Stats) => void): void;
45
+ lstat(path: string, callback: (err: Error | null, stats?: Stats) => void): void;
46
+ readdir(path: string, callback: (err: Error | null, files?: string[]) => void): void;
47
+ realpath(path: string, callback: (err: Error | null, resolvedPath?: string) => void): void;
48
+ access(path: string, callback: (err: Error | null) => void): void;
49
+ access(path: string, mode: number, callback: (err: Error | null) => void): void;
50
+ createReadStream(path: string): unknown;
51
+ createWriteStream(path: string): unknown;
52
+ promises: FsPromises;
53
+ constants: FsConstants;
54
+ }
55
+
56
+ export interface FsPromises {
57
+ readFile(path: string): Promise<Buffer>;
58
+ readFile(path: string, encoding: 'utf8' | 'utf-8'): Promise<string>;
59
+ readFile(path: string, options: { encoding: 'utf8' | 'utf-8' }): Promise<string>;
60
+ writeFile(path: string, data: string | Uint8Array): Promise<void>;
61
+ stat(path: string): Promise<Stats>;
62
+ lstat(path: string): Promise<Stats>;
63
+ readdir(path: string): Promise<string[]>;
64
+ mkdir(path: string, options?: { recursive?: boolean }): Promise<void>;
65
+ unlink(path: string): Promise<void>;
66
+ rmdir(path: string): Promise<void>;
67
+ rename(oldPath: string, newPath: string): Promise<void>;
68
+ access(path: string, mode?: number): Promise<void>;
69
+ realpath(path: string): Promise<string>;
70
+ copyFile(src: string, dest: string): Promise<void>;
71
+ }
72
+
73
+ export interface FsConstants {
74
+ F_OK: number;
75
+ R_OK: number;
76
+ W_OK: number;
77
+ X_OK: number;
78
+ }
79
+
80
+ /**
81
+ * Dirent class - represents a directory entry returned by readdirSync with withFileTypes: true
82
+ */
83
+ export class Dirent {
84
+ name: string;
85
+ private _isDirectory: boolean;
86
+ private _isFile: boolean;
87
+
88
+ constructor(name: string, isDirectory: boolean, isFile: boolean) {
89
+ this.name = name;
90
+ this._isDirectory = isDirectory;
91
+ this._isFile = isFile;
92
+ }
93
+
94
+ isDirectory(): boolean {
95
+ return this._isDirectory;
96
+ }
97
+
98
+ isFile(): boolean {
99
+ return this._isFile;
100
+ }
101
+
102
+ isBlockDevice(): boolean {
103
+ return false;
104
+ }
105
+
106
+ isCharacterDevice(): boolean {
107
+ return false;
108
+ }
109
+
110
+ isFIFO(): boolean {
111
+ return false;
112
+ }
113
+
114
+ isSocket(): boolean {
115
+ return false;
116
+ }
117
+
118
+ isSymbolicLink(): boolean {
119
+ return false;
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Create a Buffer-like object from Uint8Array
125
+ * This is a minimal Buffer implementation for browser compatibility
126
+ */
127
+ function createBuffer(data: Uint8Array): Buffer {
128
+ const buffer = data as Buffer;
129
+
130
+ // Add Buffer-specific methods
131
+ Object.defineProperty(buffer, 'toString', {
132
+ value: function (encoding?: string) {
133
+ if (encoding === 'utf8' || encoding === 'utf-8' || !encoding) {
134
+ return new TextDecoder().decode(this);
135
+ }
136
+ if (encoding === 'base64') {
137
+ let binary = '';
138
+ for (let i = 0; i < this.length; i++) {
139
+ binary += String.fromCharCode(this[i]);
140
+ }
141
+ return btoa(binary);
142
+ }
143
+ if (encoding === 'hex') {
144
+ return Array.from(this as Uint8Array)
145
+ .map((b) => b.toString(16).padStart(2, '0'))
146
+ .join('');
147
+ }
148
+ throw new Error(`Unsupported encoding: ${encoding}`);
149
+ },
150
+ writable: true,
151
+ configurable: true,
152
+ });
153
+
154
+ return buffer;
155
+ }
156
+
157
+ /**
158
+ * Convert a path-like value to a string path
159
+ * Handles URL objects (file:// protocol) and Buffer
160
+ */
161
+ // Path remapping for CLI tools that use incorrect absolute paths
162
+ // This maps /convex/ -> /project/convex/ to fix the Convex CLI path issue
163
+ const pathRemaps: Array<{ from: string; to: string }> = [
164
+ { from: '/convex/', to: '/project/convex/' },
165
+ ];
166
+
167
+ function remapPath(path: string): string {
168
+ // Strip 'vfs:' namespace prefix from paths (comes from esbuild namespace)
169
+ if (path.includes('vfs:')) {
170
+ const cleanPath = path.replace(/vfs:/g, '');
171
+ if (!remapPath.logged) remapPath.logged = new Set();
172
+ if (!remapPath.logged.has(path)) {
173
+ console.log(`[fs] Stripping vfs: prefix: ${path} -> ${cleanPath}`);
174
+ remapPath.logged.add(path);
175
+ }
176
+ path = cleanPath;
177
+ }
178
+
179
+ for (const remap of pathRemaps) {
180
+ if (path === remap.from.slice(0, -1) || path.startsWith(remap.from)) {
181
+ const remapped = remap.to + path.slice(remap.from.length);
182
+ // Only log once per unique path to avoid noise
183
+ if (!remapPath.logged) remapPath.logged = new Set();
184
+ if (!remapPath.logged.has(path)) {
185
+ console.log(`[fs] Remapping path: ${path} -> ${remapped}`);
186
+ remapPath.logged.add(path);
187
+ }
188
+ return remapped;
189
+ }
190
+ }
191
+ return path;
192
+ }
193
+ remapPath.logged = new Set<string>();
194
+
195
+ function toPath(pathLike: unknown, getCwd?: () => string): string {
196
+ let path: string;
197
+
198
+ if (typeof pathLike === 'string') {
199
+ path = pathLike;
200
+ } else if (pathLike instanceof URL) {
201
+ // Handle file:// URLs
202
+ if (pathLike.protocol === 'file:') {
203
+ // Remove file:// prefix and decode
204
+ path = decodeURIComponent(pathLike.pathname);
205
+ } else {
206
+ throw new Error(`Unsupported URL protocol: ${pathLike.protocol}`);
207
+ }
208
+ } else if (Buffer.isBuffer(pathLike)) {
209
+ path = pathLike.toString('utf8');
210
+ } else if (pathLike && typeof pathLike === 'object' && 'toString' in pathLike) {
211
+ path = String(pathLike);
212
+ } else {
213
+ throw new TypeError(`Path must be a string, URL, or Buffer. Received: ${typeof pathLike}`);
214
+ }
215
+
216
+ // Resolve relative paths against cwd
217
+ if (!path.startsWith('/') && getCwd) {
218
+ const cwd = getCwd();
219
+ path = cwd.endsWith('/') ? cwd + path : cwd + '/' + path;
220
+ }
221
+
222
+ // Apply path remapping for CLI tools that use incorrect absolute paths
223
+ path = remapPath(path);
224
+
225
+ return path;
226
+ }
227
+
228
+ // File descriptor tracking
229
+ interface FileDescriptor {
230
+ path: string;
231
+ position: number;
232
+ flags: string;
233
+ content: Uint8Array;
234
+ }
235
+
236
+ const fdMap = new Map<number, FileDescriptor>();
237
+ let nextFd = 3; // Start at 3 (0, 1, 2 are stdin, stdout, stderr)
238
+
239
+ // Call tracking for infinite loop detection
240
+ const callTracker = {
241
+ statSync: new Map<string, number>(),
242
+ readdirSync: new Map<string, number>(),
243
+ lastReset: Date.now(),
244
+ };
245
+
246
+ function trackCall(method: 'statSync' | 'readdirSync', path: string): void {
247
+ // Reset counters every 500ms to allow legitimate repeated calls
248
+ const now = Date.now();
249
+ if (now - callTracker.lastReset > 500) {
250
+ callTracker.statSync.clear();
251
+ callTracker.readdirSync.clear();
252
+ callTracker.lastReset = now;
253
+ }
254
+
255
+ const map = callTracker[method];
256
+ const count = (map.get(path) || 0) + 1;
257
+ map.set(path, count);
258
+
259
+ // Log at different thresholds to understand the pattern
260
+ if (count === 10 && path.includes('_generated')) {
261
+ console.warn(`[fs] ${method} called ${count}x on ${path}`);
262
+ // Print full stack trace at 10 calls to see the call path
263
+ const err = new Error();
264
+ console.log(`[fs] Stack at ${count} calls:`, err.stack?.split('\n').slice(1, 10).join('\n'));
265
+ }
266
+ if (count === 50) {
267
+ console.warn(`[fs] Potential infinite loop: ${method} called ${count}+ times on ${path}`);
268
+ }
269
+ }
270
+
271
+ export function createFsShim(vfs: VirtualFS, getCwd?: () => string): FsShim {
272
+ // Helper to resolve paths with cwd
273
+ const resolvePath = (pathLike: unknown) => toPath(pathLike, getCwd);
274
+ const constants: FsConstants = {
275
+ F_OK: 0,
276
+ R_OK: 4,
277
+ W_OK: 2,
278
+ X_OK: 1,
279
+ };
280
+
281
+ const promises: FsPromises = {
282
+ readFile(pathLike: unknown, encodingOrOptions?: string | { encoding?: string | null }): Promise<Buffer | string> {
283
+ return new Promise((resolve, reject) => {
284
+ try {
285
+ const path = resolvePath(pathLike);
286
+ let encoding: string | undefined;
287
+ if (typeof encodingOrOptions === 'string') {
288
+ encoding = encodingOrOptions;
289
+ } else if (encodingOrOptions?.encoding) {
290
+ encoding = encodingOrOptions.encoding;
291
+ }
292
+
293
+ if (encoding === 'utf8' || encoding === 'utf-8') {
294
+ resolve(vfs.readFileSync(path, 'utf8'));
295
+ } else {
296
+ resolve(createBuffer(vfs.readFileSync(path)));
297
+ }
298
+ } catch (err) {
299
+ reject(err);
300
+ }
301
+ });
302
+ },
303
+ writeFile(pathLike: unknown, data: string | Uint8Array): Promise<void> {
304
+ return new Promise((resolve, reject) => {
305
+ try {
306
+ vfs.writeFileSync(resolvePath(pathLike), data);
307
+ resolve();
308
+ } catch (err) {
309
+ reject(err);
310
+ }
311
+ });
312
+ },
313
+ stat(pathLike: string | unknown): Promise<Stats> {
314
+ return new Promise((resolve, reject) => {
315
+ try {
316
+ const path = typeof pathLike === 'string' ? pathLike : resolvePath(pathLike);
317
+ resolve(vfs.statSync(path));
318
+ } catch (err) {
319
+ reject(err);
320
+ }
321
+ });
322
+ },
323
+ lstat(pathLike: unknown): Promise<Stats> {
324
+ return this.stat(resolvePath(pathLike));
325
+ },
326
+ readdir(pathLike: unknown): Promise<string[]> {
327
+ return new Promise((resolve, reject) => {
328
+ try {
329
+ resolve(vfs.readdirSync(resolvePath(pathLike)));
330
+ } catch (err) {
331
+ reject(err);
332
+ }
333
+ });
334
+ },
335
+ mkdir(pathLike: unknown, options?: { recursive?: boolean }): Promise<void> {
336
+ return new Promise((resolve, reject) => {
337
+ try {
338
+ vfs.mkdirSync(resolvePath(pathLike), options);
339
+ resolve();
340
+ } catch (err) {
341
+ reject(err);
342
+ }
343
+ });
344
+ },
345
+ unlink(pathLike: unknown): Promise<void> {
346
+ return new Promise((resolve, reject) => {
347
+ try {
348
+ vfs.unlinkSync(resolvePath(pathLike));
349
+ resolve();
350
+ } catch (err) {
351
+ reject(err);
352
+ }
353
+ });
354
+ },
355
+ rmdir(path: string): Promise<void> {
356
+ return new Promise((resolve, reject) => {
357
+ try {
358
+ vfs.rmdirSync(path);
359
+ resolve();
360
+ } catch (err) {
361
+ reject(err);
362
+ }
363
+ });
364
+ },
365
+ rename(oldPath: string, newPath: string): Promise<void> {
366
+ return new Promise((resolve, reject) => {
367
+ try {
368
+ vfs.renameSync(oldPath, newPath);
369
+ resolve();
370
+ } catch (err) {
371
+ reject(err);
372
+ }
373
+ });
374
+ },
375
+ access(path: string, mode?: number): Promise<void> {
376
+ return new Promise((resolve, reject) => {
377
+ try {
378
+ vfs.accessSync(path, mode);
379
+ resolve();
380
+ } catch (err) {
381
+ reject(err);
382
+ }
383
+ });
384
+ },
385
+ realpath(path: string): Promise<string> {
386
+ return new Promise((resolve, reject) => {
387
+ try {
388
+ resolve(vfs.realpathSync(path));
389
+ } catch (err) {
390
+ reject(err);
391
+ }
392
+ });
393
+ },
394
+ copyFile(src: string, dest: string): Promise<void> {
395
+ return new Promise((resolve, reject) => {
396
+ try {
397
+ vfs.copyFileSync(src, dest);
398
+ resolve();
399
+ } catch (err) {
400
+ reject(err);
401
+ }
402
+ });
403
+ },
404
+ } as FsPromises;
405
+
406
+ return {
407
+ readFileSync(
408
+ pathLike: unknown,
409
+ encodingOrOptions?: string | { encoding?: string | null }
410
+ ): Buffer | string {
411
+ const path = resolvePath(pathLike);
412
+ let encoding: string | undefined;
413
+
414
+ if (typeof encodingOrOptions === 'string') {
415
+ encoding = encodingOrOptions;
416
+ } else if (encodingOrOptions?.encoding) {
417
+ encoding = encodingOrOptions.encoding;
418
+ }
419
+
420
+ if (encoding === 'utf8' || encoding === 'utf-8') {
421
+ return vfs.readFileSync(path, 'utf8');
422
+ }
423
+
424
+ const data = vfs.readFileSync(path);
425
+ return createBuffer(data);
426
+ },
427
+
428
+ writeFileSync(pathLike: unknown, data: string | Uint8Array): void {
429
+ // Handle file descriptor
430
+ if (typeof pathLike === 'number') {
431
+ const fd = pathLike;
432
+ const entry = fdMap.get(fd);
433
+ if (!entry) {
434
+ const err = new Error(`EBADF: bad file descriptor, write`) as Error & { code: string; errno: number };
435
+ err.code = 'EBADF';
436
+ err.errno = -9;
437
+ throw err;
438
+ }
439
+ // Convert string to Uint8Array if needed
440
+ const bytes = typeof data === 'string' ? new TextEncoder().encode(data) : data;
441
+ // Replace entire content
442
+ entry.content = new Uint8Array(bytes);
443
+ entry.position = bytes.length;
444
+ return;
445
+ }
446
+ const path = resolvePath(pathLike);
447
+ // Debug: Log when writing to convex directories
448
+ if (path.includes('convex') || path.includes('_generated')) {
449
+ console.log('[fs] writeFileSync:', path);
450
+ }
451
+ vfs.writeFileSync(path, data);
452
+ },
453
+
454
+ existsSync(pathLike: unknown): boolean {
455
+ return vfs.existsSync(resolvePath(pathLike));
456
+ },
457
+
458
+ mkdirSync(pathLike: unknown, options?: { recursive?: boolean }): void {
459
+ const path = resolvePath(pathLike);
460
+ // Debug: Log when creating convex directories
461
+ if (path.includes('convex') || path.includes('_generated')) {
462
+ console.log('[fs] mkdirSync:', path, options);
463
+ }
464
+ vfs.mkdirSync(path, options);
465
+ },
466
+
467
+ readdirSync(pathLike: unknown, options?: { withFileTypes?: boolean; encoding?: string } | string): string[] | Dirent[] {
468
+ const path = resolvePath(pathLike);
469
+ trackCall('readdirSync', path);
470
+ const entries = vfs.readdirSync(path);
471
+
472
+ // Handle withFileTypes option - returns Dirent objects instead of strings
473
+ const opts = typeof options === 'string' ? { encoding: options } : options;
474
+ if (opts?.withFileTypes) {
475
+ const dirents: Dirent[] = entries.map(name => {
476
+ const entryPath = path.endsWith('/') ? path + name : path + '/' + name;
477
+ let isDir = false;
478
+ let isFile = false;
479
+ try {
480
+ const stat = vfs.statSync(entryPath);
481
+ isDir = stat.isDirectory();
482
+ isFile = stat.isFile();
483
+ } catch {
484
+ isFile = true; // Default to file if stat fails
485
+ }
486
+ return new Dirent(name, isDir, isFile);
487
+ });
488
+ // Debug: Log readdirSync results for _generated
489
+ if (path.includes('_generated')) {
490
+ console.log(`[fs] readdirSync(${path}, withFileTypes) -> [${dirents.map(d => d.name).join(', ')}]`);
491
+ }
492
+ return dirents;
493
+ }
494
+
495
+ // Debug: Log readdirSync results for _generated
496
+ if (path.includes('_generated')) {
497
+ console.log(`[fs] readdirSync(${path}) -> [${entries.join(', ')}]`);
498
+ }
499
+ return entries;
500
+ },
501
+
502
+ statSync(pathLike: unknown): Stats {
503
+ const origPath = typeof pathLike === 'string' ? pathLike : String(pathLike);
504
+ const path = resolvePath(pathLike);
505
+ trackCall('statSync', path);
506
+ const result = vfs.statSync(path);
507
+ // Debug: Log all statSync calls on _generated paths (show if path was modified)
508
+ if (path.includes('_generated')) {
509
+ const wasRemapped = origPath !== path;
510
+ console.log(`[fs] statSync(${origPath}${wasRemapped ? ' -> ' + path : ''}) -> isDir: ${result.isDirectory()}`);
511
+ }
512
+ return result;
513
+ },
514
+
515
+ lstatSync(pathLike: unknown): Stats {
516
+ return vfs.lstatSync(resolvePath(pathLike));
517
+ },
518
+
519
+ fstatSync(fd: number): Stats {
520
+ const entry = fdMap.get(fd);
521
+ if (!entry) {
522
+ const err = new Error(`EBADF: bad file descriptor, fstat`) as Error & { code: string; errno: number };
523
+ err.code = 'EBADF';
524
+ err.errno = -9;
525
+ throw err;
526
+ }
527
+ return vfs.statSync(entry.path);
528
+ },
529
+
530
+ openSync(pathLike: unknown, flags: string | number, _mode?: number): number {
531
+ const path = resolvePath(pathLike);
532
+ const flagStr = typeof flags === 'number' ? 'r' : flags;
533
+
534
+ // Check if file exists for read modes
535
+ const exists = vfs.existsSync(path);
536
+ const isWriteMode = flagStr.includes('w') || flagStr.includes('a');
537
+ const isReadMode = flagStr.includes('r') && !flagStr.includes('+');
538
+
539
+ if (!exists && isReadMode) {
540
+ const err = new Error(`ENOENT: no such file or directory, open '${path}'`) as Error & { code: string; errno: number; path: string };
541
+ err.code = 'ENOENT';
542
+ err.errno = -2;
543
+ err.path = path;
544
+ throw err;
545
+ }
546
+
547
+ // Get or create content
548
+ let content: Uint8Array;
549
+ if (exists && !flagStr.includes('w')) {
550
+ content = vfs.readFileSync(path);
551
+ } else {
552
+ content = new Uint8Array(0);
553
+ if (isWriteMode) {
554
+ // Ensure parent directory exists
555
+ const parentPath = path.substring(0, path.lastIndexOf('/')) || '/';
556
+ if (!vfs.existsSync(parentPath)) {
557
+ vfs.mkdirSync(parentPath, { recursive: true });
558
+ }
559
+ }
560
+ }
561
+
562
+ const fd = nextFd++;
563
+ fdMap.set(fd, {
564
+ path,
565
+ position: flagStr.includes('a') ? content.length : 0,
566
+ flags: flagStr,
567
+ content: new Uint8Array(content),
568
+ });
569
+ return fd;
570
+ },
571
+
572
+ closeSync(fd: number): void {
573
+ const entry = fdMap.get(fd);
574
+ if (!entry) {
575
+ return; // Silently ignore
576
+ }
577
+ // Write back content if it was opened for writing
578
+ if (entry.flags.includes('w') || entry.flags.includes('a') || entry.flags.includes('+')) {
579
+ vfs.writeFileSync(entry.path, entry.content);
580
+ }
581
+ fdMap.delete(fd);
582
+ },
583
+
584
+ readSync(fd: number, buffer: Buffer | Uint8Array, offset: number, length: number, position: number | null): number {
585
+ const entry = fdMap.get(fd);
586
+ if (!entry) {
587
+ const err = new Error(`EBADF: bad file descriptor, read`) as Error & { code: string; errno: number };
588
+ err.code = 'EBADF';
589
+ err.errno = -9;
590
+ throw err;
591
+ }
592
+
593
+ const readPos = position !== null ? position : entry.position;
594
+ const bytesToRead = Math.min(length, entry.content.length - readPos);
595
+
596
+ if (bytesToRead <= 0) {
597
+ return 0;
598
+ }
599
+
600
+ for (let i = 0; i < bytesToRead; i++) {
601
+ buffer[offset + i] = entry.content[readPos + i];
602
+ }
603
+
604
+ if (position === null) {
605
+ entry.position += bytesToRead;
606
+ }
607
+
608
+ return bytesToRead;
609
+ },
610
+
611
+ writeSync(fd: number, buffer: Buffer | Uint8Array | string, offset?: number, length?: number, position?: number | null): number {
612
+ const entry = fdMap.get(fd);
613
+ if (!entry) {
614
+ const err = new Error(`EBADF: bad file descriptor, write`) as Error & { code: string; errno: number };
615
+ err.code = 'EBADF';
616
+ err.errno = -9;
617
+ throw err;
618
+ }
619
+
620
+ // Handle string input
621
+ let data: Uint8Array;
622
+ if (typeof buffer === 'string') {
623
+ data = new TextEncoder().encode(buffer);
624
+ offset = 0;
625
+ length = data.length;
626
+ } else {
627
+ data = buffer;
628
+ offset = offset ?? 0;
629
+ length = length ?? (data.length - offset);
630
+ }
631
+
632
+ const writePos = position !== null && position !== undefined ? position : entry.position;
633
+ const endPos = writePos + length;
634
+
635
+ // Expand content if needed
636
+ if (endPos > entry.content.length) {
637
+ const newContent = new Uint8Array(endPos);
638
+ newContent.set(entry.content);
639
+ entry.content = newContent;
640
+ }
641
+
642
+ // Write data
643
+ for (let i = 0; i < length; i++) {
644
+ entry.content[writePos + i] = data[offset + i];
645
+ }
646
+
647
+ if (position === null || position === undefined) {
648
+ entry.position = endPos;
649
+ }
650
+
651
+ return length;
652
+ },
653
+
654
+ ftruncateSync(fd: number, len: number = 0): void {
655
+ const entry = fdMap.get(fd);
656
+ if (!entry) {
657
+ const err = new Error(`EBADF: bad file descriptor, ftruncate`) as Error & { code: string; errno: number };
658
+ err.code = 'EBADF';
659
+ err.errno = -9;
660
+ throw err;
661
+ }
662
+
663
+ if (len < entry.content.length) {
664
+ entry.content = entry.content.slice(0, len);
665
+ } else if (len > entry.content.length) {
666
+ const newContent = new Uint8Array(len);
667
+ newContent.set(entry.content);
668
+ entry.content = newContent;
669
+ }
670
+ },
671
+
672
+ fsyncSync(_fd: number): void {
673
+ // No-op - our virtual FS doesn't have disk buffering
674
+ },
675
+
676
+ fdatasyncSync(_fd: number): void {
677
+ // No-op - our virtual FS doesn't have disk buffering
678
+ },
679
+
680
+ mkdtempSync(prefix: string): string {
681
+ // Generate a unique suffix
682
+ const suffix = Math.random().toString(36).slice(2, 8);
683
+ const tempDir = `${prefix}${suffix}`;
684
+ const resolvedPath = resolvePath(tempDir);
685
+ vfs.mkdirSync(resolvedPath, { recursive: true });
686
+ return resolvedPath;
687
+ },
688
+
689
+ rmSync(pathLike: unknown, options?: { recursive?: boolean; force?: boolean }): void {
690
+ const path = resolvePath(pathLike);
691
+ if (!vfs.existsSync(path)) {
692
+ if (options?.force) return;
693
+ throw createNodeError('ENOENT', 'rm', path);
694
+ }
695
+ const stats = vfs.statSync(path);
696
+ if (stats.isDirectory()) {
697
+ if (options?.recursive) {
698
+ // Recursively delete directory contents
699
+ const entries = vfs.readdirSync(path);
700
+ for (const entry of entries) {
701
+ const entryPath = path.endsWith('/') ? path + entry : path + '/' + entry;
702
+ this.rmSync(entryPath, options);
703
+ }
704
+ vfs.rmdirSync(path);
705
+ } else {
706
+ throw createNodeError('EISDIR', 'rm', path);
707
+ }
708
+ } else {
709
+ vfs.unlinkSync(path);
710
+ }
711
+ },
712
+
713
+ unlinkSync(pathLike: unknown): void {
714
+ const path = resolvePath(pathLike);
715
+ // Debug: Log unlink calls on _generated
716
+ if (path.includes('_generated')) {
717
+ console.log(`[fs] unlinkSync(${path})`);
718
+ }
719
+ vfs.unlinkSync(path);
720
+ },
721
+
722
+ rmdirSync(pathLike: unknown): void {
723
+ vfs.rmdirSync(resolvePath(pathLike));
724
+ },
725
+
726
+ renameSync(oldPathLike: unknown, newPathLike: unknown): void {
727
+ vfs.renameSync(resolvePath(oldPathLike), resolvePath(newPathLike));
728
+ },
729
+
730
+ realpathSync(pathLike: unknown): string {
731
+ return vfs.realpathSync(resolvePath(pathLike));
732
+ },
733
+
734
+ accessSync(pathLike: unknown, _mode?: number): void {
735
+ vfs.accessSync(resolvePath(pathLike));
736
+ },
737
+
738
+ copyFileSync(srcLike: unknown, destLike: unknown): void {
739
+ const src = resolvePath(srcLike);
740
+ const dest = resolvePath(destLike);
741
+ const data = vfs.readFileSync(src);
742
+ vfs.writeFileSync(dest, data);
743
+ },
744
+
745
+ watch(
746
+ pathLike: unknown,
747
+ optionsOrListener?: { persistent?: boolean; recursive?: boolean } | WatchListener,
748
+ listener?: WatchListener
749
+ ): FSWatcher {
750
+ return vfs.watch(resolvePath(pathLike), optionsOrListener as { persistent?: boolean; recursive?: boolean }, listener);
751
+ },
752
+
753
+ readFile(
754
+ pathLike: unknown,
755
+ optionsOrCallback?: { encoding?: string } | ((err: Error | null, data?: string | Uint8Array) => void),
756
+ callback?: (err: Error | null, data?: string | Uint8Array) => void
757
+ ): void {
758
+ const path = resolvePath(pathLike);
759
+ vfs.readFile(path, optionsOrCallback as { encoding?: string }, callback);
760
+ },
761
+
762
+ stat(pathLike: unknown, callback: (err: Error | null, stats?: Stats) => void): void {
763
+ vfs.stat(resolvePath(pathLike), callback);
764
+ },
765
+
766
+ lstat(pathLike: unknown, callback: (err: Error | null, stats?: Stats) => void): void {
767
+ vfs.lstat(resolvePath(pathLike), callback);
768
+ },
769
+
770
+ readdir(
771
+ pathLike: unknown,
772
+ optionsOrCallback?: { withFileTypes?: boolean } | ((err: Error | null, files?: string[]) => void),
773
+ callback?: (err: Error | null, files?: string[]) => void
774
+ ): void {
775
+ vfs.readdir(resolvePath(pathLike), optionsOrCallback as { withFileTypes?: boolean }, callback);
776
+ },
777
+
778
+ realpath(pathLike: unknown, callback: (err: Error | null, resolvedPath?: string) => void): void {
779
+ vfs.realpath(resolvePath(pathLike), callback);
780
+ },
781
+
782
+ access(
783
+ pathLike: unknown,
784
+ modeOrCallback?: number | ((err: Error | null) => void),
785
+ callback?: (err: Error | null) => void
786
+ ): void {
787
+ vfs.access(resolvePath(pathLike), modeOrCallback, callback);
788
+ },
789
+
790
+ createReadStream(pathLike: unknown): unknown {
791
+ return vfs.createReadStream(resolvePath(pathLike));
792
+ },
793
+
794
+ createWriteStream(pathLike: unknown): unknown {
795
+ return vfs.createWriteStream(resolvePath(pathLike));
796
+ },
797
+
798
+ promises,
799
+ constants,
800
+ } as FsShim;
801
+ }
802
+
803
+ export default createFsShim;