@seanhogg/builderforce-webcontainers-core 2026.10.2 → 2026.10.4

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 (426) hide show
  1. package/dist/build.d.ts +42 -0
  2. package/dist/build.d.ts.map +1 -0
  3. package/dist/build.js +65 -0
  4. package/dist/build.js.map +1 -0
  5. package/dist/buildHost.d.ts +31 -0
  6. package/dist/buildHost.d.ts.map +1 -0
  7. package/dist/buildHost.js +125 -0
  8. package/dist/buildHost.js.map +1 -0
  9. package/dist/buildHtml.d.ts +28 -0
  10. package/dist/buildHtml.d.ts.map +1 -0
  11. package/dist/buildHtml.js +74 -0
  12. package/dist/buildHtml.js.map +1 -0
  13. package/dist/bundler.d.ts +129 -0
  14. package/dist/bundler.d.ts.map +1 -0
  15. package/dist/bundler.js +79 -0
  16. package/dist/bundler.js.map +1 -0
  17. package/dist/check/acquire.d.ts +46 -0
  18. package/dist/check/acquire.d.ts.map +1 -0
  19. package/dist/check/acquire.js +179 -0
  20. package/dist/check/acquire.js.map +1 -0
  21. package/dist/check/compilerHost.d.ts +22 -0
  22. package/dist/check/compilerHost.d.ts.map +1 -0
  23. package/dist/check/compilerHost.js +128 -0
  24. package/dist/check/compilerHost.js.map +1 -0
  25. package/dist/check/diagnostics.d.ts +23 -0
  26. package/dist/check/diagnostics.d.ts.map +1 -0
  27. package/dist/check/diagnostics.js +28 -0
  28. package/dist/check/diagnostics.js.map +1 -0
  29. package/dist/check/index.d.ts +19 -0
  30. package/dist/check/index.d.ts.map +1 -0
  31. package/dist/check/index.js +13 -0
  32. package/dist/check/index.js.map +1 -0
  33. package/dist/check/projects.d.ts +26 -0
  34. package/dist/check/projects.d.ts.map +1 -0
  35. package/dist/check/projects.js +124 -0
  36. package/dist/check/projects.js.map +1 -0
  37. package/dist/check/shims.d.ts +29 -0
  38. package/dist/check/shims.d.ts.map +1 -0
  39. package/dist/check/shims.js +76 -0
  40. package/dist/check/shims.js.map +1 -0
  41. package/dist/check/typeStore.d.ts +57 -0
  42. package/dist/check/typeStore.d.ts.map +1 -0
  43. package/dist/check/typeStore.js +89 -0
  44. package/dist/check/typeStore.js.map +1 -0
  45. package/dist/check/typecheck.d.ts +29 -0
  46. package/dist/check/typecheck.d.ts.map +1 -0
  47. package/dist/check/typecheck.js +91 -0
  48. package/dist/check/typecheck.js.map +1 -0
  49. package/dist/compileComponent.d.ts +8 -0
  50. package/dist/compileComponent.d.ts.map +1 -0
  51. package/dist/compileComponent.js +22 -0
  52. package/dist/compileComponent.js.map +1 -0
  53. package/dist/compileScript.d.ts +19 -4
  54. package/dist/compileScript.d.ts.map +1 -1
  55. package/dist/compileScript.js +37 -12
  56. package/dist/compileScript.js.map +1 -1
  57. package/dist/components.d.ts +41 -0
  58. package/dist/components.d.ts.map +1 -0
  59. package/dist/components.js +14 -0
  60. package/dist/components.js.map +1 -0
  61. package/dist/detectProject.d.ts +3 -0
  62. package/dist/detectProject.d.ts.map +1 -1
  63. package/dist/detectProject.js +16 -6
  64. package/dist/detectProject.js.map +1 -1
  65. package/dist/devServer.d.ts +5 -2
  66. package/dist/devServer.d.ts.map +1 -1
  67. package/dist/devServer.js +12 -8
  68. package/dist/devServer.js.map +1 -1
  69. package/dist/hash.d.ts +2 -0
  70. package/dist/hash.d.ts.map +1 -0
  71. package/dist/hash.js +22 -0
  72. package/dist/hash.js.map +1 -0
  73. package/dist/index.d.ts +24 -6
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +14 -3
  76. package/dist/index.js.map +1 -1
  77. package/dist/installer/bins.d.ts +24 -0
  78. package/dist/installer/bins.d.ts.map +1 -0
  79. package/dist/installer/bins.js +56 -0
  80. package/dist/installer/bins.js.map +1 -0
  81. package/dist/installer/index.d.ts +14 -0
  82. package/dist/installer/index.d.ts.map +1 -0
  83. package/dist/installer/index.js +9 -0
  84. package/dist/installer/index.js.map +1 -0
  85. package/dist/installer/install.d.ts +46 -0
  86. package/dist/installer/install.d.ts.map +1 -0
  87. package/dist/installer/install.js +245 -0
  88. package/dist/installer/install.js.map +1 -0
  89. package/dist/installer/lockfile.d.ts +49 -0
  90. package/dist/installer/lockfile.d.ts.map +1 -0
  91. package/dist/installer/lockfile.js +110 -0
  92. package/dist/installer/lockfile.js.map +1 -0
  93. package/dist/installer/registry.d.ts +84 -0
  94. package/dist/installer/registry.d.ts.map +1 -0
  95. package/dist/installer/registry.js +130 -0
  96. package/dist/installer/registry.js.map +1 -0
  97. package/dist/installer/semver.d.ts +38 -0
  98. package/dist/installer/semver.d.ts.map +1 -0
  99. package/dist/installer/semver.js +187 -0
  100. package/dist/installer/semver.js.map +1 -0
  101. package/dist/installer/spec.d.ts +30 -0
  102. package/dist/installer/spec.d.ts.map +1 -0
  103. package/dist/installer/spec.js +30 -0
  104. package/dist/installer/spec.js.map +1 -0
  105. package/dist/installer/tar.d.ts +17 -0
  106. package/dist/installer/tar.d.ts.map +1 -0
  107. package/dist/installer/tar.js +150 -0
  108. package/dist/installer/tar.js.map +1 -0
  109. package/dist/installer/tree.d.ts +48 -0
  110. package/dist/installer/tree.d.ts.map +1 -0
  111. package/dist/installer/tree.js +179 -0
  112. package/dist/installer/tree.js.map +1 -0
  113. package/dist/node/assert.d.ts +15 -0
  114. package/dist/node/assert.d.ts.map +1 -0
  115. package/dist/node/assert.js +137 -0
  116. package/dist/node/assert.js.map +1 -0
  117. package/dist/node/buffer.d.ts +84 -0
  118. package/dist/node/buffer.d.ts.map +1 -0
  119. package/dist/node/buffer.js +304 -0
  120. package/dist/node/buffer.js.map +1 -0
  121. package/dist/node/builtins.d.ts +25 -0
  122. package/dist/node/builtins.d.ts.map +1 -0
  123. package/dist/node/builtins.js +101 -0
  124. package/dist/node/builtins.js.map +1 -0
  125. package/dist/node/callable.d.ts +13 -0
  126. package/dist/node/callable.d.ts.map +1 -0
  127. package/dist/node/callable.js +26 -0
  128. package/dist/node/callable.js.map +1 -0
  129. package/dist/node/childProcess.d.ts +13 -0
  130. package/dist/node/childProcess.d.ts.map +1 -0
  131. package/dist/node/childProcess.js +143 -0
  132. package/dist/node/childProcess.js.map +1 -0
  133. package/dist/node/crypto.d.ts +3 -0
  134. package/dist/node/crypto.d.ts.map +1 -0
  135. package/dist/node/crypto.js +180 -0
  136. package/dist/node/crypto.js.map +1 -0
  137. package/dist/node/esm.d.ts +9 -0
  138. package/dist/node/esm.d.ts.map +1 -0
  139. package/dist/node/esm.js +202 -0
  140. package/dist/node/esm.js.map +1 -0
  141. package/dist/node/events.d.ts +40 -0
  142. package/dist/node/events.d.ts.map +1 -0
  143. package/dist/node/events.js +160 -0
  144. package/dist/node/events.js.map +1 -0
  145. package/dist/node/fs/index.d.ts +7 -0
  146. package/dist/node/fs/index.d.ts.map +1 -0
  147. package/dist/node/fs/index.js +270 -0
  148. package/dist/node/fs/index.js.map +1 -0
  149. package/dist/node/fs/stats.d.ts +93 -0
  150. package/dist/node/fs/stats.d.ts.map +1 -0
  151. package/dist/node/fs/stats.js +104 -0
  152. package/dist/node/fs/stats.js.map +1 -0
  153. package/dist/node/fs/sync.d.ts +98 -0
  154. package/dist/node/fs/sync.d.ts.map +1 -0
  155. package/dist/node/fs/sync.js +348 -0
  156. package/dist/node/fs/sync.js.map +1 -0
  157. package/dist/node/hashes.d.ts +15 -0
  158. package/dist/node/hashes.d.ts.map +1 -0
  159. package/dist/node/hashes.js +195 -0
  160. package/dist/node/hashes.js.map +1 -0
  161. package/dist/node/http/client.d.ts +35 -0
  162. package/dist/node/http/client.d.ts.map +1 -0
  163. package/dist/node/http/client.js +161 -0
  164. package/dist/node/http/client.js.map +1 -0
  165. package/dist/node/http/index.d.ts +5 -0
  166. package/dist/node/http/index.d.ts.map +1 -0
  167. package/dist/node/http/index.js +125 -0
  168. package/dist/node/http/index.js.map +1 -0
  169. package/dist/node/http/server.d.ts +135 -0
  170. package/dist/node/http/server.d.ts.map +1 -0
  171. package/dist/node/http/server.js +308 -0
  172. package/dist/node/http/server.js.map +1 -0
  173. package/dist/node/http/status.d.ts +3 -0
  174. package/dist/node/http/status.d.ts.map +1 -0
  175. package/dist/node/http/status.js +13 -0
  176. package/dist/node/http/status.js.map +1 -0
  177. package/dist/node/inspect.d.ts +22 -0
  178. package/dist/node/inspect.d.ts.map +1 -0
  179. package/dist/node/inspect.js +172 -0
  180. package/dist/node/inspect.js.map +1 -0
  181. package/dist/node/loader.d.ts +91 -0
  182. package/dist/node/loader.d.ts.map +1 -0
  183. package/dist/node/loader.js +265 -0
  184. package/dist/node/loader.js.map +1 -0
  185. package/dist/node/loop.d.ts +71 -0
  186. package/dist/node/loop.d.ts.map +1 -0
  187. package/dist/node/loop.js +189 -0
  188. package/dist/node/loop.js.map +1 -0
  189. package/dist/node/misc.d.ts +10 -0
  190. package/dist/node/misc.d.ts.map +1 -0
  191. package/dist/node/misc.js +256 -0
  192. package/dist/node/misc.js.map +1 -0
  193. package/dist/node/path.d.ts +14 -0
  194. package/dist/node/path.d.ts.map +1 -0
  195. package/dist/node/path.js +128 -0
  196. package/dist/node/path.js.map +1 -0
  197. package/dist/node/process.d.ts +31 -0
  198. package/dist/node/process.d.ts.map +1 -0
  199. package/dist/node/process.js +309 -0
  200. package/dist/node/process.js.map +1 -0
  201. package/dist/node/program.d.ts +19 -0
  202. package/dist/node/program.d.ts.map +1 -0
  203. package/dist/node/program.js +165 -0
  204. package/dist/node/program.js.map +1 -0
  205. package/dist/node/readline.d.ts +2 -0
  206. package/dist/node/readline.d.ts.map +1 -0
  207. package/dist/node/readline.js +155 -0
  208. package/dist/node/readline.js.map +1 -0
  209. package/dist/node/resolve.d.ts +45 -0
  210. package/dist/node/resolve.d.ts.map +1 -0
  211. package/dist/node/resolve.js +206 -0
  212. package/dist/node/resolve.js.map +1 -0
  213. package/dist/node/runtime.d.ts +40 -0
  214. package/dist/node/runtime.d.ts.map +1 -0
  215. package/dist/node/runtime.js +149 -0
  216. package/dist/node/runtime.js.map +1 -0
  217. package/dist/node/stream/index.d.ts +52 -0
  218. package/dist/node/stream/index.d.ts.map +1 -0
  219. package/dist/node/stream/index.js +184 -0
  220. package/dist/node/stream/index.js.map +1 -0
  221. package/dist/node/stream/readable.d.ts +83 -0
  222. package/dist/node/stream/readable.d.ts.map +1 -0
  223. package/dist/node/stream/readable.js +325 -0
  224. package/dist/node/stream/readable.js.map +1 -0
  225. package/dist/node/stream/writable.d.ts +80 -0
  226. package/dist/node/stream/writable.d.ts.map +1 -0
  227. package/dist/node/stream/writable.js +224 -0
  228. package/dist/node/stream/writable.js.map +1 -0
  229. package/dist/node/urlqs.d.ts +22 -0
  230. package/dist/node/urlqs.d.ts.map +1 -0
  231. package/dist/node/urlqs.js +165 -0
  232. package/dist/node/urlqs.js.map +1 -0
  233. package/dist/node/util.d.ts +37 -0
  234. package/dist/node/util.d.ts.map +1 -0
  235. package/dist/node/util.js +160 -0
  236. package/dist/node/util.js.map +1 -0
  237. package/dist/node/zlib.d.ts +2 -0
  238. package/dist/node/zlib.d.ts.map +1 -0
  239. package/dist/node/zlib.js +133 -0
  240. package/dist/node/zlib.js.map +1 -0
  241. package/dist/packageCdn.d.ts +40 -0
  242. package/dist/packageCdn.d.ts.map +1 -1
  243. package/dist/packageCdn.js +54 -7
  244. package/dist/packageCdn.js.map +1 -1
  245. package/dist/projectConfig.d.ts +6 -2
  246. package/dist/projectConfig.d.ts.map +1 -1
  247. package/dist/projectConfig.js +32 -8
  248. package/dist/projectConfig.js.map +1 -1
  249. package/dist/shell/builtins.d.ts +23 -0
  250. package/dist/shell/builtins.d.ts.map +1 -0
  251. package/dist/shell/builtins.js +131 -0
  252. package/dist/shell/builtins.js.map +1 -0
  253. package/dist/shell/context.d.ts +41 -0
  254. package/dist/shell/context.d.ts.map +1 -0
  255. package/dist/shell/context.js +65 -0
  256. package/dist/shell/context.js.map +1 -0
  257. package/dist/shell/devHandoff.d.ts +18 -0
  258. package/dist/shell/devHandoff.d.ts.map +1 -0
  259. package/dist/shell/devHandoff.js +36 -0
  260. package/dist/shell/devHandoff.js.map +1 -0
  261. package/dist/shell/exec.d.ts +67 -0
  262. package/dist/shell/exec.d.ts.map +1 -0
  263. package/dist/shell/exec.js +247 -0
  264. package/dist/shell/exec.js.map +1 -0
  265. package/dist/shell/expand.d.ts +28 -0
  266. package/dist/shell/expand.d.ts.map +1 -0
  267. package/dist/shell/expand.js +149 -0
  268. package/dist/shell/expand.js.map +1 -0
  269. package/dist/shell/fileCommands.d.ts +10 -0
  270. package/dist/shell/fileCommands.d.ts.map +1 -0
  271. package/dist/shell/fileCommands.js +208 -0
  272. package/dist/shell/fileCommands.js.map +1 -0
  273. package/dist/shell/lineEditor.d.ts +43 -0
  274. package/dist/shell/lineEditor.d.ts.map +1 -0
  275. package/dist/shell/lineEditor.js +234 -0
  276. package/dist/shell/lineEditor.js.map +1 -0
  277. package/dist/shell/npm.d.ts +6 -0
  278. package/dist/shell/npm.d.ts.map +1 -0
  279. package/dist/shell/npm.js +234 -0
  280. package/dist/shell/npm.js.map +1 -0
  281. package/dist/shell/parse.d.ts +73 -0
  282. package/dist/shell/parse.d.ts.map +1 -0
  283. package/dist/shell/parse.js +300 -0
  284. package/dist/shell/parse.js.map +1 -0
  285. package/dist/shell/program.d.ts +12 -0
  286. package/dist/shell/program.d.ts.map +1 -0
  287. package/dist/shell/program.js +219 -0
  288. package/dist/shell/program.js.map +1 -0
  289. package/dist/shell/textCommands.d.ts +15 -0
  290. package/dist/shell/textCommands.d.ts.map +1 -0
  291. package/dist/shell/textCommands.js +185 -0
  292. package/dist/shell/textCommands.js.map +1 -0
  293. package/dist/styleModules.d.ts +6 -0
  294. package/dist/styleModules.d.ts.map +1 -1
  295. package/dist/styleModules.js +14 -4
  296. package/dist/styleModules.js.map +1 -1
  297. package/dist/svelteCompiler.d.ts +28 -0
  298. package/dist/svelteCompiler.d.ts.map +1 -0
  299. package/dist/svelteCompiler.js +13 -0
  300. package/dist/svelteCompiler.js.map +1 -0
  301. package/dist/system/commands.d.ts +26 -0
  302. package/dist/system/commands.d.ts.map +1 -0
  303. package/dist/system/commands.js +53 -0
  304. package/dist/system/commands.js.map +1 -0
  305. package/dist/system/index.d.ts +23 -0
  306. package/dist/system/index.d.ts.map +1 -0
  307. package/dist/system/index.js +16 -0
  308. package/dist/system/index.js.map +1 -0
  309. package/dist/system/kernel.d.ts +54 -0
  310. package/dist/system/kernel.d.ts.map +1 -0
  311. package/dist/system/kernel.js +81 -0
  312. package/dist/system/kernel.js.map +1 -0
  313. package/dist/system/ports.d.ts +32 -0
  314. package/dist/system/ports.d.ts.map +1 -0
  315. package/dist/system/ports.js +57 -0
  316. package/dist/system/ports.js.map +1 -0
  317. package/dist/system/process.d.ts +32 -0
  318. package/dist/system/process.d.ts.map +1 -0
  319. package/dist/system/process.js +130 -0
  320. package/dist/system/process.js.map +1 -0
  321. package/dist/system/programs.d.ts +10 -0
  322. package/dist/system/programs.d.ts.map +1 -0
  323. package/dist/system/programs.js +22 -0
  324. package/dist/system/programs.js.map +1 -0
  325. package/dist/system/terminal.d.ts +45 -0
  326. package/dist/system/terminal.d.ts.map +1 -0
  327. package/dist/system/terminal.js +127 -0
  328. package/dist/system/terminal.js.map +1 -0
  329. package/dist/system/types.d.ts +100 -0
  330. package/dist/system/types.d.ts.map +1 -0
  331. package/dist/system/types.js +2 -0
  332. package/dist/system/types.js.map +1 -0
  333. package/dist/vfs.d.ts +28 -4
  334. package/dist/vfs.d.ts.map +1 -1
  335. package/dist/vfs.js +95 -32
  336. package/dist/vfs.js.map +1 -1
  337. package/dist/vueCompiler.d.ts +75 -0
  338. package/dist/vueCompiler.d.ts.map +1 -0
  339. package/dist/vueCompiler.js +67 -0
  340. package/dist/vueCompiler.js.map +1 -0
  341. package/package.json +18 -2
  342. package/src/build.ts +105 -0
  343. package/src/buildHost.ts +154 -0
  344. package/src/buildHtml.ts +101 -0
  345. package/src/bundler.ts +190 -0
  346. package/src/check/acquire.ts +212 -0
  347. package/src/check/compilerHost.ts +138 -0
  348. package/src/check/diagnostics.ts +48 -0
  349. package/src/check/index.ts +28 -0
  350. package/src/check/projects.ts +149 -0
  351. package/src/check/shims.ts +88 -0
  352. package/src/check/typeStore.ts +103 -0
  353. package/src/check/typecheck.ts +134 -0
  354. package/src/compileComponent.ts +21 -0
  355. package/src/compileScript.ts +42 -13
  356. package/src/components.ts +59 -0
  357. package/src/detectProject.ts +18 -6
  358. package/src/devServer.ts +16 -11
  359. package/src/hash.ts +22 -0
  360. package/src/index.ts +35 -6
  361. package/src/installer/bins.ts +64 -0
  362. package/src/installer/index.ts +13 -0
  363. package/src/installer/install.ts +275 -0
  364. package/src/installer/lockfile.ts +146 -0
  365. package/src/installer/registry.ts +175 -0
  366. package/src/installer/semver.ts +190 -0
  367. package/src/installer/spec.ts +53 -0
  368. package/src/installer/tar.ts +155 -0
  369. package/src/installer/tree.ts +236 -0
  370. package/src/node/assert.ts +127 -0
  371. package/src/node/buffer.ts +304 -0
  372. package/src/node/builtins.ts +123 -0
  373. package/src/node/callable.ts +25 -0
  374. package/src/node/childProcess.ts +164 -0
  375. package/src/node/crypto.ts +187 -0
  376. package/src/node/esm.ts +196 -0
  377. package/src/node/events.ts +176 -0
  378. package/src/node/fs/index.ts +277 -0
  379. package/src/node/fs/stats.ts +110 -0
  380. package/src/node/fs/sync.ts +335 -0
  381. package/src/node/hashes.ts +171 -0
  382. package/src/node/http/client.ts +173 -0
  383. package/src/node/http/index.ts +122 -0
  384. package/src/node/http/server.ts +308 -0
  385. package/src/node/http/status.ts +13 -0
  386. package/src/node/inspect.ts +166 -0
  387. package/src/node/loader.ts +293 -0
  388. package/src/node/loop.ts +193 -0
  389. package/src/node/misc.ts +250 -0
  390. package/src/node/path.ts +135 -0
  391. package/src/node/process.ts +324 -0
  392. package/src/node/program.ts +170 -0
  393. package/src/node/readline.ts +157 -0
  394. package/src/node/resolve.ts +216 -0
  395. package/src/node/runtime.ts +184 -0
  396. package/src/node/stream/index.ts +196 -0
  397. package/src/node/stream/readable.ts +345 -0
  398. package/src/node/stream/writable.ts +244 -0
  399. package/src/node/urlqs.ts +162 -0
  400. package/src/node/util.ts +145 -0
  401. package/src/node/zlib.ts +145 -0
  402. package/src/packageCdn.ts +91 -7
  403. package/src/projectConfig.ts +34 -7
  404. package/src/shell/builtins.ts +141 -0
  405. package/src/shell/context.ts +89 -0
  406. package/src/shell/devHandoff.ts +49 -0
  407. package/src/shell/exec.ts +268 -0
  408. package/src/shell/expand.ts +145 -0
  409. package/src/shell/fileCommands.ts +206 -0
  410. package/src/shell/lineEditor.ts +233 -0
  411. package/src/shell/npm.ts +229 -0
  412. package/src/shell/parse.ts +295 -0
  413. package/src/shell/program.ts +223 -0
  414. package/src/shell/textCommands.ts +177 -0
  415. package/src/styleModules.ts +15 -4
  416. package/src/svelteCompiler.ts +31 -0
  417. package/src/system/commands.ts +72 -0
  418. package/src/system/index.ts +22 -0
  419. package/src/system/kernel.ts +106 -0
  420. package/src/system/ports.ts +73 -0
  421. package/src/system/process.ts +158 -0
  422. package/src/system/programs.ts +31 -0
  423. package/src/system/terminal.ts +135 -0
  424. package/src/system/types.ts +103 -0
  425. package/src/vfs.ts +92 -28
  426. package/src/vueCompiler.ts +121 -0
@@ -0,0 +1,166 @@
1
+ /**
2
+ * `util.inspect` and `util.format` — what `console.log` prints in Node. Close to
3
+ * Node's output for the common shapes (nested objects to depth 2, arrays, Map,
4
+ * Set, errors with stacks, Buffers, circular references); colours are ignored.
5
+ */
6
+
7
+ export const inspectCustom = Symbol.for('nodejs.util.inspect.custom');
8
+
9
+ export interface InspectOptions {
10
+ depth?: number | null;
11
+ colors?: boolean;
12
+ compact?: boolean | number;
13
+ breakLength?: number;
14
+ showHidden?: boolean;
15
+ sorted?: boolean;
16
+ }
17
+
18
+ const IDENT = /^[A-Za-z_$][\w$]*$/;
19
+
20
+ function quote(s: string): string {
21
+ const q = s.includes("'") && !s.includes('"') ? '"' : "'";
22
+ return q + s.replace(/\\/g, '\\\\').replace(/\n/g, '\\n').replace(new RegExp(q, 'g'), '\\' + q) + q;
23
+ }
24
+
25
+ function formatKey(key: string | symbol): string {
26
+ if (typeof key === 'symbol') return `[${key.toString()}]`;
27
+ return IDENT.test(key) ? key : quote(key);
28
+ }
29
+
30
+ function wrap(open: string, items: string[], close: string, breakLength: number, indent: string): string {
31
+ if (!items.length) return `${open}${close}`;
32
+ const single = `${open} ${items.join(', ')} ${close}`;
33
+ if (single.length + indent.length <= breakLength && !items.some((i) => i.includes('\n'))) return single;
34
+ const inner = indent + ' ';
35
+ return `${open}\n${items.map((i) => inner + i).join(',\n')}\n${indent}${close}`;
36
+ }
37
+
38
+ function constructorName(value: object): string | undefined {
39
+ const proto = Object.getPrototypeOf(value);
40
+ if (proto === null) return '[Object: null prototype]';
41
+ const name = proto?.constructor?.name;
42
+ return name && name !== 'Object' ? name : undefined;
43
+ }
44
+
45
+ export function inspect(value: unknown, options: InspectOptions = {}): string {
46
+ const depth = options.depth === null ? Infinity : options.depth ?? 2;
47
+ const breakLength = options.breakLength ?? 80;
48
+ const seen: object[] = [];
49
+
50
+ const fmt = (v: unknown, level: number, indent: string, nested: boolean): string => {
51
+ switch (typeof v) {
52
+ case 'string': return nested ? quote(v) : v;
53
+ case 'number': return Object.is(v, -0) ? '-0' : String(v);
54
+ case 'bigint': return `${v}n`;
55
+ case 'boolean': return String(v);
56
+ case 'undefined': return 'undefined';
57
+ case 'symbol': return v.toString();
58
+ case 'function': {
59
+ const name = v.name ? `: ${v.name}` : ' (anonymous)';
60
+ const kind = /^class\s/.test(Function.prototype.toString.call(v)) ? 'class' : 'Function';
61
+ const keys = Object.keys(v);
62
+ const base = kind === 'class' ? `[class ${v.name || '(anonymous)'}]` : `[${kind}${name}]`;
63
+ if (!keys.length || level > depth) return base;
64
+ return wrap(`${base} {`, keys.map((k) => `${formatKey(k)}: ${fmt((v as any)[k], level + 1, indent + ' ', true)}`), '}', breakLength, indent);
65
+ }
66
+ }
67
+ if (v === null) return 'null';
68
+ const obj = v as Record<string | symbol, unknown>;
69
+ const custom = obj[inspectCustom];
70
+ if (typeof custom === 'function') {
71
+ const result = custom.call(obj, depth - level, { ...options, stylize: (s: string) => s }, inspect);
72
+ return typeof result === 'string' ? result : fmt(result, level, indent, nested);
73
+ }
74
+ if (seen.includes(obj)) return '[Circular *1]';
75
+ if (v instanceof Error) {
76
+ const stack = v.stack && v.stack.includes(v.message) ? v.stack : `${v.name}: ${v.message}${v.stack ? '\n' + v.stack.split('\n').slice(1).join('\n') : ''}`;
77
+ const extra = Object.keys(v).filter((k) => k !== 'stack' && k !== 'message');
78
+ if (!extra.length || level > depth) return stack;
79
+ seen.push(obj);
80
+ const out = wrap(`${stack} {`, extra.map((k) => `${formatKey(k)}: ${fmt(obj[k], level + 1, indent + ' ', true)}`), '}', breakLength, indent);
81
+ seen.pop();
82
+ return out;
83
+ }
84
+ if (v instanceof Date) return Number.isNaN(v.getTime()) ? 'Invalid Date' : v.toISOString();
85
+ if (v instanceof RegExp) return String(v);
86
+ if (v instanceof Promise) return 'Promise { <pending> }';
87
+ if (v instanceof WeakMap) return 'WeakMap { <items unknown> }';
88
+ if (v instanceof WeakSet) return 'WeakSet { <items unknown> }';
89
+ if (ArrayBuffer.isView(v) && !(v instanceof DataView)) {
90
+ const bytes = v as unknown as ArrayLike<number> & { constructor: { name: string } };
91
+ if (bytes.constructor.name === 'Buffer') {
92
+ const hex = Array.from(bytes as Uint8Array).slice(0, 50).map((b) => b.toString(16).padStart(2, '0'));
93
+ return `<Buffer${hex.length ? ' ' + hex.join(' ') : ''}${bytes.length > 50 ? ` ... ${bytes.length - 50} more bytes` : ''}>`;
94
+ }
95
+ return `${bytes.constructor.name}(${bytes.length}) [ ${Array.from(bytes).slice(0, 100).join(', ')} ]`;
96
+ }
97
+ if (level > depth) {
98
+ if (Array.isArray(v)) return '[Array]';
99
+ return `[${constructorName(obj) ?? 'Object'}]`;
100
+ }
101
+
102
+ seen.push(obj);
103
+ const next = (x: unknown) => fmt(x, level + 1, indent + ' ', true);
104
+ let out: string;
105
+ if (Array.isArray(v)) {
106
+ const items = v.slice(0, 100).map(next);
107
+ if (v.length > 100) items.push(`... ${v.length - 100} more items`);
108
+ for (const k of Object.keys(v)) if (!/^\d+$/.test(k)) items.push(`${formatKey(k)}: ${next(obj[k])}`);
109
+ const prefix = constructorName(obj) && constructorName(obj) !== 'Array' ? `${constructorName(obj)}(${v.length}) ` : '';
110
+ out = wrap(`${prefix}[`, items, ']', breakLength, indent);
111
+ } else if (v instanceof Map) {
112
+ out = wrap(`Map(${v.size}) {`, [...v].map(([k, val]) => `${next(k)} => ${next(val)}`), '}', breakLength, indent);
113
+ } else if (v instanceof Set) {
114
+ out = wrap(`Set(${v.size}) {`, [...v].map(next), '}', breakLength, indent);
115
+ } else {
116
+ const keys: Array<string | symbol> = [...Object.keys(obj), ...Object.getOwnPropertySymbols(obj).filter((s) => Object.getOwnPropertyDescriptor(obj, s)?.enumerable)];
117
+ if (options.sorted) keys.sort();
118
+ const items = keys.map((k) => {
119
+ const desc = Object.getOwnPropertyDescriptor(obj, k);
120
+ const shown = desc && (desc.get || desc.set) ? (desc.get && desc.set ? '[Getter/Setter]' : desc.get ? '[Getter]' : '[Setter]') : next(obj[k]);
121
+ return `${formatKey(k)}: ${shown}`;
122
+ });
123
+ const name = constructorName(obj);
124
+ const tag = (obj as { [Symbol.toStringTag]?: string })[Symbol.toStringTag];
125
+ const prefix = name ? `${name}${tag && tag !== name ? ` [${tag}]` : ''} ` : tag ? `Object [${tag}] ` : '';
126
+ out = items.length || !prefix ? wrap(`${prefix}{`, items, '}', breakLength, indent) : `${prefix}{}`;
127
+ }
128
+ seen.pop();
129
+ return out;
130
+ };
131
+
132
+ return fmt(value, 0, '', false);
133
+ }
134
+ inspect.custom = inspectCustom;
135
+ inspect.defaultOptions = { depth: 2 } as InspectOptions;
136
+
137
+ /** printf-style `util.format`: %s %d %i %f %j %o %O %c %%. */
138
+ export function format(...args: unknown[]): string {
139
+ const [first, ...rest] = args;
140
+ if (typeof first !== 'string') return args.map((a) => inspect(a)).join(' ');
141
+ let i = 0;
142
+ let out = first.replace(/%([sdifjoOc%])/g, (match, spec: string) => {
143
+ if (spec === '%') return '%';
144
+ if (i >= rest.length) return match;
145
+ const arg = rest[i++];
146
+ switch (spec) {
147
+ case 's': return typeof arg === 'string' ? arg : typeof arg === 'bigint' ? `${arg}n` : typeof arg === 'object' && arg !== null ? inspect(arg, { depth: 1 }) : String(arg);
148
+ case 'd': return typeof arg === 'bigint' ? `${arg}n` : String(Number(arg));
149
+ case 'i': return typeof arg === 'bigint' ? `${arg}n` : String(parseInt(String(arg), 10));
150
+ case 'f': return String(parseFloat(String(arg)));
151
+ case 'j':
152
+ try {
153
+ return JSON.stringify(arg);
154
+ } catch {
155
+ return '[Circular]';
156
+ }
157
+ case 'c': return '';
158
+ default: return inspect(arg, { depth: spec === 'o' ? 4 : 2 });
159
+ }
160
+ });
161
+ for (; i < rest.length; i++) {
162
+ const arg = rest[i];
163
+ out += ' ' + (typeof arg === 'string' ? arg : inspect(arg));
164
+ }
165
+ return out;
166
+ }
@@ -0,0 +1,293 @@
1
+ /**
2
+ * The module system: Node's `Module` with `_load`, `_resolveFilename`,
3
+ * `_extensions`, `_compile` and `require.cache` — the hooks tools monkeypatch
4
+ * (module-alias, pirates, require-in-the-middle) are real and are what
5
+ * `require` goes through.
6
+ *
7
+ * Every file runs inside the CommonJS wrapper; ES modules are rewritten to it
8
+ * first (esm.ts). The wrapper also receives this process's globals (`process`,
9
+ * `Buffer`, timers, `console`…) as parameters, so several runtimes can share
10
+ * one JS realm (tests, the in-process kernel) without touching `globalThis`.
11
+ */
12
+ import type { VirtualFileSystem } from '../vfs.js';
13
+ import { dirname, extname } from '../paths.js';
14
+ import { esmToCjs, ESM_MARK, hasModuleSyntax, mayBeEsm } from './esm.js';
15
+ import { findPackageScope, IMPORT_CONDITIONS, nodeModulePaths, REQUIRE_CONDITIONS, resolveNodeModule, type Resolution } from './resolve.js';
16
+
17
+ export interface LoaderOptions {
18
+ fs: VirtualFileSystem;
19
+ isBuiltin(name: string): boolean;
20
+ /** A builtin's exports (`fs`, `path`…). `module` is answered by the loader itself. */
21
+ builtin(name: string): unknown;
22
+ /** Injected into every module's wrapper by name. */
23
+ globals: Record<string, unknown>;
24
+ }
25
+
26
+ export interface NodeModule {
27
+ id: string;
28
+ filename: string;
29
+ path: string;
30
+ exports: any;
31
+ loaded: boolean;
32
+ parent: NodeModule | null | undefined;
33
+ children: NodeModule[];
34
+ paths: string[];
35
+ require(id: string): any;
36
+ /** Top-level-await modules: settles when evaluation finishes. */
37
+ __tla?: Promise<unknown>;
38
+ }
39
+
40
+ const AsyncFunction = Object.getPrototypeOf(async () => undefined).constructor as FunctionConstructor;
41
+
42
+ function stripShebang(source: string): string {
43
+ const text = source.charCodeAt(0) === 0xfeff ? source.slice(1) : source;
44
+ return text.startsWith('#!') ? '//' + text.slice(2) : text;
45
+ }
46
+
47
+ export function createModuleSystem(options: LoaderOptions) {
48
+ const { fs } = options;
49
+ const cache: Record<string, NodeModule> = Object.create(null);
50
+ const interop = new WeakMap<object, object>();
51
+ const globalNames = Object.keys(options.globals);
52
+ const globalValues = globalNames.map((n) => options.globals[n]);
53
+ let main: NodeModule | undefined;
54
+
55
+ function isEsmFile(filename: string, source: string): boolean {
56
+ const ext = extname(filename);
57
+ if (ext === '.mjs') return true;
58
+ if (ext === '.cjs') return false;
59
+ if (findPackageScope(fs, dirname(filename))?.pkg.type === 'module') return true;
60
+ // Node 22 "detect-module": ambiguous .js with import/export syntax is ESM.
61
+ return mayBeEsm(source) && hasModuleSyntax(source);
62
+ }
63
+
64
+ /** What `import` sees of a module: an ES module's own namespace, or `{ default: module.exports, ...named }`. */
65
+ function namespaceOf(exports: any): any {
66
+ if (exports && exports[ESM_MARK]) return exports;
67
+ if ((typeof exports !== 'object' && typeof exports !== 'function') || exports === null) return { default: exports };
68
+ let ns = interop.get(exports);
69
+ if (!ns) {
70
+ ns = Object.create(null) as object;
71
+ for (const key of Object.keys(exports)) if (key !== 'default') Object.defineProperty(ns, key, { enumerable: true, get: () => exports[key] });
72
+ Object.defineProperty(ns, 'default', { enumerable: true, value: exports });
73
+ interop.set(exports, ns);
74
+ }
75
+ return ns;
76
+ }
77
+
78
+ class Module implements NodeModule {
79
+ static _cache = cache;
80
+ static _pathCache = Object.create(null);
81
+ static builtinModules: string[] = [];
82
+ static globalPaths = ['/usr/local/lib/node'];
83
+ static Module = Module;
84
+ static _extensions: Record<string, (module: Module, filename: string) => void> = {
85
+ '.js'(module, filename) {
86
+ const source = fs.readText(filename) ?? '';
87
+ if (isEsmFile(filename, source)) module._compile(esmToCjs(stripShebang(source)), filename, true);
88
+ else module._compile(source, filename);
89
+ },
90
+ '.cjs'(module, filename) {
91
+ module._compile(fs.readText(filename) ?? '', filename);
92
+ },
93
+ '.mjs'(module, filename) {
94
+ module._compile(esmToCjs(stripShebang(fs.readText(filename) ?? '')), filename, true);
95
+ },
96
+ '.json'(module, filename) {
97
+ try {
98
+ module.exports = JSON.parse(stripShebang(fs.readText(filename) ?? ''));
99
+ } catch (error) {
100
+ (error as Error).message = `${filename}: ${(error as Error).message}`;
101
+ throw error;
102
+ }
103
+ },
104
+ '.node'(_module, filename) {
105
+ throw Object.assign(new Error(`Native addons cannot run in the browser: ${filename}`), { code: 'ERR_DLOPEN_FAILED' });
106
+ },
107
+ };
108
+
109
+ id: string;
110
+ filename: string;
111
+ path: string;
112
+ exports: any = {};
113
+ loaded = false;
114
+ children: NodeModule[] = [];
115
+ paths: string[];
116
+ __tla?: Promise<unknown>;
117
+
118
+ constructor(id = '', public parent: NodeModule | null | undefined = undefined) {
119
+ this.id = id;
120
+ this.filename = id;
121
+ this.path = dirname(id || '/');
122
+ this.paths = nodeModulePaths(this.path);
123
+ parent?.children.push(this);
124
+ }
125
+
126
+ static _resolveFilename(request: string, parent?: NodeModule, _isMain?: boolean, opts?: { paths?: string[]; conditions?: readonly string[] }): string {
127
+ const fromDir = parent?.filename ? dirname(parent.filename) : (options.globals.process as { cwd(): string } | undefined)?.cwd() ?? '/';
128
+ const resolution = resolveNodeModule(fs, request, fromDir, {
129
+ conditions: opts?.conditions ?? REQUIRE_CONDITIONS,
130
+ isBuiltin: options.isBuiltin,
131
+ from: parent?.filename,
132
+ paths: opts?.paths,
133
+ });
134
+ return 'builtin' in resolution ? `node:${resolution.builtin}` : resolution.path;
135
+ }
136
+
137
+ static _load(request: string, parent?: NodeModule, isMain = false): any {
138
+ const filename = Module._resolveFilename(request, parent, isMain);
139
+ return loadResolved(filename, parent, isMain).exports;
140
+ }
141
+
142
+ static _nodeModulePaths = nodeModulePaths;
143
+ static isBuiltin = (name: string) => options.isBuiltin(name.replace(/^node:/, ''));
144
+ static createRequire = (filename: string | URL) => {
145
+ const path = typeof filename === 'string' ? filename.replace(/^file:\/\//, '') : decodeURIComponent(filename.pathname);
146
+ return makeRequire(new Module(path.endsWith('/') ? path + '__entry.js' : path));
147
+ };
148
+ static wrap = (source: string) => `(function (exports, require, module, __filename, __dirname) { ${source}\n});`;
149
+ static wrapper = ['(function (exports, require, module, __filename, __dirname) { ', '\n});'];
150
+ static syncBuiltinESMExports = () => undefined;
151
+ static register = () => undefined;
152
+ static findSourceMap = () => undefined;
153
+ static runMain = () => undefined;
154
+
155
+ require(id: string): any {
156
+ if (typeof id !== 'string' || !id) throw new TypeError('The "id" argument must be a non-empty string');
157
+ return Module._load(id, this, false);
158
+ }
159
+
160
+ _compile(content: string, filename: string, esm = false): unknown {
161
+ const require = makeRequire(this);
162
+ const dir = dirname(filename);
163
+ const names = ['exports', 'require', 'module', '__filename', '__dirname', ...globalNames];
164
+ const values: unknown[] = [this.exports, require, this, filename, dir, ...globalValues];
165
+ if (esm) {
166
+ names.push('__bfwc_import', '__bfwc_dynamic', '__bfwc_meta', '__bfwc_esm', '__bfwc_star', '__bfwc_get');
167
+ values.push(...esmHelpers(this, filename));
168
+ }
169
+ const code = `${stripShebang(content)}\n//# sourceURL=${encodeURI('file://' + filename)}`;
170
+ let fn: (...args: unknown[]) => unknown;
171
+ try {
172
+ fn = new Function(...names, code) as typeof fn;
173
+ } catch (error) {
174
+ if (esm && error instanceof SyntaxError && /await/.test(error.message)) fn = new AsyncFunction(...names, code) as typeof fn;
175
+ else {
176
+ if (error instanceof Error) error.message = `${filename}: ${error.message}`;
177
+ throw error;
178
+ }
179
+ }
180
+ const result = fn.apply(this.exports, values);
181
+ if (result instanceof Promise) this.__tla = result;
182
+ return result;
183
+ }
184
+ }
185
+
186
+ function esmHelpers(module: Module, filename: string): unknown[] {
187
+ const load = (specifier: string): { exports: any; __tla?: Promise<unknown> } => {
188
+ let target: string;
189
+ try {
190
+ target = Module._resolveFilename(specifier, module, false, { conditions: REQUIRE_CONDITIONS });
191
+ } catch (error) {
192
+ // Prefer a package's CommonJS build (no transform, no binding snapshots);
193
+ // ESM-only packages resolve through the "import" condition instead.
194
+ if ((error as { code?: string }).code !== 'ERR_PACKAGE_PATH_NOT_EXPORTED') throw error;
195
+ target = Module._resolveFilename(specifier, module, false, { conditions: IMPORT_CONDITIONS });
196
+ }
197
+ return loadResolved(target, module, false);
198
+ };
199
+ const importSync = (specifier: string) => namespaceOf(load(specifier).exports);
200
+ const meta = {
201
+ url: 'file://' + filename,
202
+ filename,
203
+ dirname: dirname(filename),
204
+ resolve: (specifier: string) => {
205
+ const target = Module._resolveFilename(specifier, module, false, { conditions: IMPORT_CONDITIONS });
206
+ return target.startsWith('node:') ? target : 'file://' + target;
207
+ },
208
+ };
209
+ const define = (exports: any, getters: Record<string, () => unknown>) => {
210
+ Object.defineProperty(exports, '__esModule', { value: true });
211
+ Object.defineProperty(exports, ESM_MARK, { value: true });
212
+ for (const [name, get] of Object.entries(getters)) Object.defineProperty(exports, name, { enumerable: true, configurable: true, get });
213
+ };
214
+ const star = (exports: any, ns: any) => {
215
+ for (const key of Object.keys(ns)) {
216
+ if (key === 'default' || key === '__esModule' || Object.prototype.hasOwnProperty.call(exports, key)) continue;
217
+ Object.defineProperty(exports, key, { enumerable: true, configurable: true, get: () => ns[key] });
218
+ }
219
+ };
220
+ const get = (ns: any, key: string) => {
221
+ try {
222
+ return ns[key];
223
+ } catch {
224
+ return undefined; // a cyclic import read before the binding was initialised
225
+ }
226
+ };
227
+ const dynamic = async (specifier: string) => {
228
+ const loaded = load(String(specifier));
229
+ if (loaded.__tla) await loaded.__tla;
230
+ return namespaceOf(loaded.exports);
231
+ };
232
+ return [importSync, dynamic, meta, define, star, get];
233
+ }
234
+
235
+ function loadResolved(filename: string, parent: NodeModule | undefined, isMain: boolean): { exports: any } {
236
+ if (filename.startsWith('node:')) {
237
+ const name = filename.slice(5);
238
+ return { exports: name === 'module' ? Module : options.builtin(name) };
239
+ }
240
+ const cached = cache[filename];
241
+ if (cached) {
242
+ if (parent && !parent.children.includes(cached)) parent.children.push(cached);
243
+ return cached;
244
+ }
245
+ const module = new Module(filename, parent ?? null);
246
+ if (isMain) {
247
+ main = module;
248
+ module.id = '.';
249
+ }
250
+ cache[filename] = module;
251
+ try {
252
+ const handler = Module._extensions[extname(filename)] ?? Module._extensions['.js']!;
253
+ handler(module, filename);
254
+ } catch (error) {
255
+ delete cache[filename];
256
+ throw error;
257
+ }
258
+ module.loaded = true;
259
+ return module;
260
+ }
261
+
262
+ function makeRequire(module: Module) {
263
+ const require = ((id: string) => module.require(id)) as ((id: string) => any) & Record<string, any>;
264
+ const resolve = (request: string, opts?: { paths?: string[] }) => {
265
+ const target = Module._resolveFilename(request, module, false, opts);
266
+ return target.startsWith('node:') && !request.startsWith('node:') ? request : target;
267
+ };
268
+ resolve.paths = (request: string) => (options.isBuiltin(request) ? null : nodeModulePaths(module.path));
269
+ require.resolve = resolve;
270
+ require.cache = cache;
271
+ require.extensions = Module._extensions;
272
+ Object.defineProperty(require, 'main', { get: () => main, enumerable: true });
273
+ return require;
274
+ }
275
+
276
+ return {
277
+ Module,
278
+ cache,
279
+ /** Run `filename` as the main module. */
280
+ runMain(filename: string): NodeModule {
281
+ return loadResolved(filename, undefined, true) as NodeModule;
282
+ },
283
+ get main() {
284
+ return main;
285
+ },
286
+ createRequire: Module.createRequire,
287
+ resolve(request: string, fromDir: string): Resolution {
288
+ return resolveNodeModule(fs, request, fromDir, { conditions: REQUIRE_CONDITIONS, isBuiltin: options.isBuiltin });
289
+ },
290
+ };
291
+ }
292
+
293
+ export type ModuleSystem = ReturnType<typeof createModuleSystem>;
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Node's "the process exits when there is nothing left to do", recreated.
3
+ *
4
+ * A browser has no way to ask "is anything still pending?", so the runtime
5
+ * counts what Node would count: ref'd timers and intervals, listening servers,
6
+ * open watchers, a flowing stdin, child processes and in-flight requests
7
+ * (`hold()`). When the count reaches zero, an idle check runs on a later
8
+ * macrotask — after every pending microtask (promise chains, fs callbacks) has
9
+ * drained — and if still zero, the process exits.
10
+ *
11
+ * Timers are Node-shaped objects (`ref`/`unref`/`refresh`/`hasRef`), and errors
12
+ * thrown from any callback are routed to the process as uncaught exceptions.
13
+ */
14
+
15
+ const realSetTimeout = globalThis.setTimeout.bind(globalThis);
16
+ const realClearTimeout = globalThis.clearTimeout.bind(globalThis);
17
+ const realSetInterval = globalThis.setInterval.bind(globalThis);
18
+ const realClearInterval = globalThis.clearInterval.bind(globalThis);
19
+
20
+ type Callback = (...args: any[]) => void;
21
+
22
+ let nextTimerId = 1;
23
+
24
+ export class Timeout {
25
+ readonly _id = nextTimerId++;
26
+ _ref = true;
27
+ _handle: ReturnType<typeof realSetTimeout> | undefined;
28
+ _destroyed = false;
29
+
30
+ constructor(
31
+ private readonly loop: EventLoop,
32
+ readonly _onTimeout: Callback,
33
+ readonly _idleTimeout: number,
34
+ private readonly args: unknown[],
35
+ readonly _repeat: boolean,
36
+ ) {}
37
+
38
+ ref(): this {
39
+ if (!this._ref && !this._destroyed) this.loop._refChanged(this, true);
40
+ this._ref = true;
41
+ return this;
42
+ }
43
+
44
+ unref(): this {
45
+ if (this._ref && !this._destroyed) this.loop._refChanged(this, false);
46
+ this._ref = false;
47
+ return this;
48
+ }
49
+
50
+ hasRef(): boolean {
51
+ return this._ref;
52
+ }
53
+
54
+ refresh(): this {
55
+ if (!this._destroyed) this.loop._arm(this);
56
+ return this;
57
+ }
58
+
59
+ close(): this {
60
+ this.loop.clear(this);
61
+ return this;
62
+ }
63
+
64
+ [Symbol.toPrimitive](): number {
65
+ return this._id;
66
+ }
67
+
68
+ _fire(): void {
69
+ this.loop._run(() => this._onTimeout(...this.args));
70
+ }
71
+ }
72
+
73
+ export interface EventLoopOptions {
74
+ /** Called once when nothing keeps the process alive. */
75
+ onIdle(): void;
76
+ /** An exception escaped a callback. */
77
+ onError(error: unknown): void;
78
+ }
79
+
80
+ export class EventLoop {
81
+ private holds = 0;
82
+ private readonly timers = new Map<number, Timeout>();
83
+ private refTimers = 0;
84
+ private checkScheduled = false;
85
+ private stopped = false;
86
+
87
+ constructor(private readonly options: EventLoopOptions) {}
88
+
89
+ /** Keep the process alive until the returned function is called (idempotent). */
90
+ hold(): () => void {
91
+ if (this.stopped) return () => undefined;
92
+ this.holds++;
93
+ let released = false;
94
+ return () => {
95
+ if (released) return;
96
+ released = true;
97
+ this.holds--;
98
+ this.scheduleCheck();
99
+ };
100
+ }
101
+
102
+ /** Run `fn` the way a callback from the loop runs: errors become uncaught exceptions. */
103
+ _run(fn: () => void): void {
104
+ if (this.stopped) return;
105
+ try {
106
+ fn();
107
+ } catch (error) {
108
+ this.options.onError(error);
109
+ }
110
+ }
111
+
112
+ get alive(): boolean {
113
+ return this.holds > 0 || this.refTimers > 0;
114
+ }
115
+
116
+ setTimeout = (fn: Callback, ms?: number, ...args: unknown[]): Timeout => this.add(fn, ms, args, false);
117
+ setInterval = (fn: Callback, ms?: number, ...args: unknown[]): Timeout => this.add(fn, ms, args, true);
118
+ setImmediate = (fn: Callback, ...args: unknown[]): Timeout => this.add(fn, 0, args, false);
119
+ clearTimeout = (timer: unknown): void => this.clear(timer);
120
+ clearInterval = (timer: unknown): void => this.clear(timer);
121
+ clearImmediate = (timer: unknown): void => this.clear(timer);
122
+
123
+ clear(timer: unknown): void {
124
+ const id = typeof timer === 'object' && timer ? (timer as Timeout)._id : Number(timer);
125
+ const t = this.timers.get(id);
126
+ if (!t) return;
127
+ this.disarm(t);
128
+ this.timers.delete(id);
129
+ t._destroyed = true;
130
+ if (t._ref) {
131
+ this.refTimers--;
132
+ this.scheduleCheck();
133
+ }
134
+ }
135
+
136
+ /** Has the loop been asked to check for idleness? Run the check after microtasks drain. */
137
+ scheduleCheck(): void {
138
+ if (this.checkScheduled || this.stopped) return;
139
+ this.checkScheduled = true;
140
+ // Two macrotask hops: a callback that schedules work via a just-resolved
141
+ // promise gets every chance to register a timer or hold first.
142
+ realSetTimeout(() => {
143
+ realSetTimeout(() => {
144
+ this.checkScheduled = false;
145
+ if (!this.alive && !this.stopped) this.options.onIdle();
146
+ }, 0);
147
+ }, 0);
148
+ }
149
+
150
+ /** Stop everything: the process has exited. */
151
+ stop(): void {
152
+ this.stopped = true;
153
+ for (const t of this.timers.values()) this.disarm(t);
154
+ this.timers.clear();
155
+ }
156
+
157
+ _refChanged(_t: Timeout, ref: boolean): void {
158
+ this.refTimers += ref ? 1 : -1;
159
+ if (!ref) this.scheduleCheck();
160
+ }
161
+
162
+ _arm(t: Timeout): void {
163
+ this.disarm(t);
164
+ const ms = Math.max(0, t._idleTimeout);
165
+ if (t._repeat) t._handle = realSetInterval(() => t._fire(), Math.max(1, ms));
166
+ else {
167
+ t._handle = realSetTimeout(() => {
168
+ this.timers.delete(t._id);
169
+ t._destroyed = true;
170
+ if (t._ref) this.refTimers--;
171
+ t._fire();
172
+ if (t._ref) this.scheduleCheck();
173
+ }, ms);
174
+ }
175
+ }
176
+
177
+ private add(fn: Callback, ms: number | undefined, args: unknown[], repeat: boolean): Timeout {
178
+ if (typeof fn !== 'function') throw new TypeError('The "callback" argument must be of type function');
179
+ const t = new Timeout(this, fn, Number.isFinite(ms) ? Number(ms) : 1, args, repeat);
180
+ if (this.stopped) return t;
181
+ this.timers.set(t._id, t);
182
+ this.refTimers++;
183
+ this._arm(t);
184
+ return t;
185
+ }
186
+
187
+ private disarm(t: Timeout): void {
188
+ if (t._handle === undefined) return;
189
+ if (t._repeat) realClearInterval(t._handle);
190
+ else realClearTimeout(t._handle);
191
+ t._handle = undefined;
192
+ }
193
+ }