@ricsam/isolate 0.0.1 → 0.1.1

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 (299) hide show
  1. package/README.md +243 -34
  2. package/dist/cjs/bridge/diagnostics.cjs +58 -0
  3. package/dist/cjs/bridge/diagnostics.cjs.map +10 -0
  4. package/dist/cjs/bridge/legacy-adapters.cjs +242 -0
  5. package/dist/cjs/bridge/legacy-adapters.cjs.map +10 -0
  6. package/dist/cjs/bridge/request-context.cjs +59 -0
  7. package/dist/cjs/bridge/request-context.cjs.map +10 -0
  8. package/dist/cjs/bridge/runtime-bindings.cjs +367 -0
  9. package/dist/cjs/bridge/runtime-bindings.cjs.map +10 -0
  10. package/dist/cjs/browser/browser-runtime.cjs +157 -0
  11. package/dist/cjs/browser/browser-runtime.cjs.map +10 -0
  12. package/dist/cjs/daemon.cjs +91 -0
  13. package/dist/cjs/daemon.cjs.map +10 -0
  14. package/dist/cjs/files/index.cjs +140 -0
  15. package/dist/cjs/files/index.cjs.map +10 -0
  16. package/dist/cjs/host/create-isolate-host.cjs +235 -0
  17. package/dist/cjs/host/create-isolate-host.cjs.map +10 -0
  18. package/dist/cjs/host/index.cjs +47 -0
  19. package/dist/cjs/host/index.cjs.map +10 -0
  20. package/dist/cjs/index.cjs +55 -0
  21. package/dist/cjs/index.cjs.map +10 -0
  22. package/dist/cjs/internal/client/connection.cjs +1919 -0
  23. package/dist/cjs/internal/client/connection.cjs.map +10 -0
  24. package/dist/cjs/internal/client/index.cjs +48 -0
  25. package/dist/cjs/internal/client/index.cjs.map +10 -0
  26. package/dist/cjs/internal/client/types.cjs +30 -0
  27. package/dist/cjs/internal/client/types.cjs.map +9 -0
  28. package/dist/cjs/internal/console/index.cjs +506 -0
  29. package/dist/cjs/internal/console/index.cjs.map +10 -0
  30. package/dist/cjs/internal/console/utils.cjs +70 -0
  31. package/dist/cjs/internal/console/utils.cjs.map +10 -0
  32. package/dist/cjs/internal/core/index.cjs +2745 -0
  33. package/dist/cjs/internal/core/index.cjs.map +10 -0
  34. package/dist/cjs/internal/crypto/index.cjs +470 -0
  35. package/dist/cjs/internal/crypto/index.cjs.map +10 -0
  36. package/dist/cjs/internal/daemon/callback-fs-handler.cjs +355 -0
  37. package/dist/cjs/internal/daemon/callback-fs-handler.cjs.map +10 -0
  38. package/dist/cjs/internal/daemon/connection.cjs +1952 -0
  39. package/dist/cjs/internal/daemon/connection.cjs.map +10 -0
  40. package/dist/cjs/internal/daemon/daemon.cjs +98 -0
  41. package/dist/cjs/internal/daemon/daemon.cjs.map +10 -0
  42. package/dist/cjs/internal/daemon/index.cjs +145 -0
  43. package/dist/cjs/internal/daemon/index.cjs.map +10 -0
  44. package/dist/cjs/internal/daemon/runtime-pool.cjs +106 -0
  45. package/dist/cjs/internal/daemon/runtime-pool.cjs.map +10 -0
  46. package/dist/cjs/internal/daemon/types.cjs +30 -0
  47. package/dist/cjs/internal/daemon/types.cjs.map +9 -0
  48. package/dist/cjs/internal/encoding/index.cjs +419 -0
  49. package/dist/cjs/internal/encoding/index.cjs.map +10 -0
  50. package/dist/cjs/internal/fetch/consistency/origins.cjs +598 -0
  51. package/dist/cjs/internal/fetch/consistency/origins.cjs.map +10 -0
  52. package/dist/cjs/internal/fetch/index.cjs +2640 -0
  53. package/dist/cjs/internal/fetch/index.cjs.map +10 -0
  54. package/dist/cjs/internal/fetch/stream-state.cjs +256 -0
  55. package/dist/cjs/internal/fetch/stream-state.cjs.map +10 -0
  56. package/dist/cjs/internal/fs/index.cjs +847 -0
  57. package/dist/cjs/internal/fs/index.cjs.map +10 -0
  58. package/dist/cjs/internal/fs/node-adapter.cjs +254 -0
  59. package/dist/cjs/internal/fs/node-adapter.cjs.map +10 -0
  60. package/dist/cjs/internal/module-loader/bundle.cjs +482 -0
  61. package/dist/cjs/internal/module-loader/bundle.cjs.map +10 -0
  62. package/dist/cjs/internal/module-loader/index.cjs +240 -0
  63. package/dist/cjs/internal/module-loader/index.cjs.map +10 -0
  64. package/dist/cjs/internal/module-loader/mappings.cjs +120 -0
  65. package/dist/cjs/internal/module-loader/mappings.cjs.map +10 -0
  66. package/dist/cjs/internal/module-loader/resolve.cjs +177 -0
  67. package/dist/cjs/internal/module-loader/resolve.cjs.map +10 -0
  68. package/dist/cjs/internal/module-loader/strip-types.cjs +236 -0
  69. package/dist/cjs/internal/module-loader/strip-types.cjs.map +10 -0
  70. package/dist/cjs/internal/path/index.cjs +503 -0
  71. package/dist/cjs/internal/path/index.cjs.map +10 -0
  72. package/dist/cjs/internal/playwright/client.cjs +49 -0
  73. package/dist/cjs/internal/playwright/client.cjs.map +10 -0
  74. package/dist/cjs/internal/playwright/handler.cjs +1416 -0
  75. package/dist/cjs/internal/playwright/handler.cjs.map +10 -0
  76. package/dist/cjs/internal/playwright/index.cjs +1289 -0
  77. package/dist/cjs/internal/playwright/index.cjs.map +10 -0
  78. package/dist/cjs/internal/playwright/types.cjs +47 -0
  79. package/dist/cjs/internal/playwright/types.cjs.map +10 -0
  80. package/dist/cjs/internal/protocol/codec.cjs +510 -0
  81. package/dist/cjs/internal/protocol/codec.cjs.map +10 -0
  82. package/dist/cjs/internal/protocol/framing.cjs +141 -0
  83. package/dist/cjs/internal/protocol/framing.cjs.map +10 -0
  84. package/dist/cjs/internal/protocol/index.cjs +110 -0
  85. package/dist/cjs/internal/protocol/index.cjs.map +10 -0
  86. package/dist/cjs/internal/protocol/marshalValue.cjs +518 -0
  87. package/dist/cjs/internal/protocol/marshalValue.cjs.map +10 -0
  88. package/dist/cjs/internal/protocol/serialization.cjs +109 -0
  89. package/dist/cjs/internal/protocol/serialization.cjs.map +10 -0
  90. package/dist/cjs/internal/protocol/types.cjs +181 -0
  91. package/dist/cjs/internal/protocol/types.cjs.map +10 -0
  92. package/dist/cjs/internal/runtime/index.cjs +1235 -0
  93. package/dist/cjs/internal/runtime/index.cjs.map +10 -0
  94. package/dist/cjs/internal/server/index.cjs +223 -0
  95. package/dist/cjs/internal/server/index.cjs.map +10 -0
  96. package/dist/cjs/internal/test-environment/index.cjs +1415 -0
  97. package/dist/cjs/internal/test-environment/index.cjs.map +10 -0
  98. package/dist/cjs/internal/timers/index.cjs +200 -0
  99. package/dist/cjs/internal/timers/index.cjs.map +10 -0
  100. package/dist/cjs/internal/transform/index.cjs +361 -0
  101. package/dist/cjs/internal/transform/index.cjs.map +10 -0
  102. package/dist/cjs/internal/typecheck/index.cjs +60 -0
  103. package/dist/cjs/internal/typecheck/index.cjs.map +10 -0
  104. package/dist/cjs/internal/typecheck/isolate-types.cjs +2614 -0
  105. package/dist/cjs/internal/typecheck/isolate-types.cjs.map +10 -0
  106. package/dist/cjs/internal/typecheck/typecheck.cjs +131 -0
  107. package/dist/cjs/internal/typecheck/typecheck.cjs.map +10 -0
  108. package/dist/cjs/modules/index.cjs +160 -0
  109. package/dist/cjs/modules/index.cjs.map +10 -0
  110. package/dist/cjs/package.json +5 -0
  111. package/dist/cjs/runtime/script-runtime.cjs +97 -0
  112. package/dist/cjs/runtime/script-runtime.cjs.map +10 -0
  113. package/dist/cjs/server/app-server.cjs +158 -0
  114. package/dist/cjs/server/app-server.cjs.map +10 -0
  115. package/dist/cjs/testing/integration-helpers.cjs +127 -0
  116. package/dist/cjs/testing/integration-helpers.cjs.map +10 -0
  117. package/dist/cjs/typecheck/index.cjs +96 -0
  118. package/dist/cjs/typecheck/index.cjs.map +10 -0
  119. package/dist/cjs/types.cjs +30 -0
  120. package/dist/cjs/types.cjs.map +9 -0
  121. package/dist/mjs/bridge/diagnostics.mjs +18 -0
  122. package/dist/mjs/bridge/diagnostics.mjs.map +10 -0
  123. package/dist/mjs/bridge/legacy-adapters.mjs +178 -0
  124. package/dist/mjs/bridge/legacy-adapters.mjs.map +10 -0
  125. package/dist/mjs/bridge/request-context.mjs +19 -0
  126. package/dist/mjs/bridge/request-context.mjs.map +10 -0
  127. package/dist/mjs/bridge/runtime-bindings.mjs +303 -0
  128. package/dist/mjs/bridge/runtime-bindings.mjs.map +10 -0
  129. package/dist/mjs/browser/browser-runtime.mjs +93 -0
  130. package/dist/mjs/browser/browser-runtime.mjs.map +10 -0
  131. package/dist/mjs/daemon.mjs +91 -0
  132. package/dist/mjs/daemon.mjs.map +10 -0
  133. package/dist/mjs/files/index.mjs +76 -0
  134. package/dist/mjs/files/index.mjs.map +10 -0
  135. package/dist/mjs/host/create-isolate-host.mjs +171 -0
  136. package/dist/mjs/host/create-isolate-host.mjs.map +10 -0
  137. package/dist/mjs/host/index.mjs +7 -0
  138. package/dist/mjs/host/index.mjs.map +10 -0
  139. package/dist/mjs/index.mjs +15 -0
  140. package/dist/mjs/index.mjs.map +10 -0
  141. package/dist/mjs/internal/client/connection.mjs +1872 -0
  142. package/dist/mjs/internal/client/connection.mjs.map +10 -0
  143. package/dist/mjs/internal/client/index.mjs +8 -0
  144. package/dist/mjs/internal/client/index.mjs.map +10 -0
  145. package/dist/mjs/internal/client/types.mjs +2 -0
  146. package/dist/mjs/internal/client/types.mjs.map +9 -0
  147. package/dist/mjs/internal/console/index.mjs +442 -0
  148. package/dist/mjs/internal/console/index.mjs.map +10 -0
  149. package/dist/mjs/internal/console/utils.mjs +30 -0
  150. package/dist/mjs/internal/console/utils.mjs.map +10 -0
  151. package/dist/mjs/internal/core/index.mjs +2681 -0
  152. package/dist/mjs/internal/core/index.mjs.map +10 -0
  153. package/dist/mjs/internal/crypto/index.mjs +406 -0
  154. package/dist/mjs/internal/crypto/index.mjs.map +10 -0
  155. package/dist/mjs/internal/daemon/callback-fs-handler.mjs +315 -0
  156. package/dist/mjs/internal/daemon/callback-fs-handler.mjs.map +10 -0
  157. package/dist/mjs/internal/daemon/connection.mjs +1931 -0
  158. package/dist/mjs/internal/daemon/connection.mjs.map +10 -0
  159. package/dist/mjs/internal/daemon/daemon.mjs +98 -0
  160. package/dist/mjs/internal/daemon/daemon.mjs.map +10 -0
  161. package/dist/mjs/internal/daemon/index.mjs +105 -0
  162. package/dist/mjs/internal/daemon/index.mjs.map +10 -0
  163. package/dist/mjs/internal/daemon/runtime-pool.mjs +66 -0
  164. package/dist/mjs/internal/daemon/runtime-pool.mjs.map +10 -0
  165. package/dist/mjs/internal/daemon/types.mjs +2 -0
  166. package/dist/mjs/internal/daemon/types.mjs.map +9 -0
  167. package/dist/mjs/internal/encoding/index.mjs +379 -0
  168. package/dist/mjs/internal/encoding/index.mjs.map +10 -0
  169. package/dist/mjs/internal/fetch/consistency/origins.mjs +558 -0
  170. package/dist/mjs/internal/fetch/consistency/origins.mjs.map +10 -0
  171. package/dist/mjs/internal/fetch/index.mjs +2580 -0
  172. package/dist/mjs/internal/fetch/index.mjs.map +10 -0
  173. package/dist/mjs/internal/fetch/stream-state.mjs +216 -0
  174. package/dist/mjs/internal/fetch/stream-state.mjs.map +10 -0
  175. package/dist/mjs/internal/fs/index.mjs +783 -0
  176. package/dist/mjs/internal/fs/index.mjs.map +10 -0
  177. package/dist/mjs/internal/fs/node-adapter.mjs +190 -0
  178. package/dist/mjs/internal/fs/node-adapter.mjs.map +10 -0
  179. package/dist/mjs/internal/module-loader/bundle.mjs +418 -0
  180. package/dist/mjs/internal/module-loader/bundle.mjs.map +10 -0
  181. package/dist/mjs/internal/module-loader/index.mjs +185 -0
  182. package/dist/mjs/internal/module-loader/index.mjs.map +10 -0
  183. package/dist/mjs/internal/module-loader/mappings.mjs +80 -0
  184. package/dist/mjs/internal/module-loader/mappings.mjs.map +10 -0
  185. package/dist/mjs/internal/module-loader/resolve.mjs +113 -0
  186. package/dist/mjs/internal/module-loader/resolve.mjs.map +10 -0
  187. package/dist/mjs/internal/module-loader/strip-types.mjs +172 -0
  188. package/dist/mjs/internal/module-loader/strip-types.mjs.map +10 -0
  189. package/dist/mjs/internal/path/index.mjs +463 -0
  190. package/dist/mjs/internal/path/index.mjs.map +10 -0
  191. package/dist/mjs/internal/playwright/client.mjs +13 -0
  192. package/dist/mjs/internal/playwright/client.mjs.map +10 -0
  193. package/dist/mjs/internal/playwright/handler.mjs +1378 -0
  194. package/dist/mjs/internal/playwright/handler.mjs.map +10 -0
  195. package/dist/mjs/internal/playwright/index.mjs +1234 -0
  196. package/dist/mjs/internal/playwright/index.mjs.map +10 -0
  197. package/dist/mjs/internal/playwright/types.mjs +7 -0
  198. package/dist/mjs/internal/playwright/types.mjs.map +10 -0
  199. package/dist/mjs/internal/protocol/codec.mjs +470 -0
  200. package/dist/mjs/internal/protocol/codec.mjs.map +10 -0
  201. package/dist/mjs/internal/protocol/framing.mjs +101 -0
  202. package/dist/mjs/internal/protocol/framing.mjs.map +10 -0
  203. package/dist/mjs/internal/protocol/index.mjs +98 -0
  204. package/dist/mjs/internal/protocol/index.mjs.map +10 -0
  205. package/dist/mjs/internal/protocol/marshalValue.mjs +494 -0
  206. package/dist/mjs/internal/protocol/marshalValue.mjs.map +10 -0
  207. package/dist/mjs/internal/protocol/serialization.mjs +69 -0
  208. package/dist/mjs/internal/protocol/serialization.mjs.map +10 -0
  209. package/dist/mjs/internal/protocol/types.mjs +141 -0
  210. package/dist/mjs/internal/protocol/types.mjs.map +10 -0
  211. package/dist/mjs/internal/runtime/index.mjs +1198 -0
  212. package/dist/mjs/internal/runtime/index.mjs.map +10 -0
  213. package/dist/mjs/internal/server/index.mjs +183 -0
  214. package/dist/mjs/internal/server/index.mjs.map +10 -0
  215. package/dist/mjs/internal/test-environment/index.mjs +1351 -0
  216. package/dist/mjs/internal/test-environment/index.mjs.map +10 -0
  217. package/dist/mjs/internal/timers/index.mjs +136 -0
  218. package/dist/mjs/internal/timers/index.mjs.map +10 -0
  219. package/dist/mjs/internal/transform/index.mjs +321 -0
  220. package/dist/mjs/internal/transform/index.mjs.map +10 -0
  221. package/dist/mjs/internal/typecheck/index.mjs +35 -0
  222. package/dist/mjs/internal/typecheck/index.mjs.map +10 -0
  223. package/dist/mjs/internal/typecheck/isolate-types.mjs +2574 -0
  224. package/dist/mjs/internal/typecheck/isolate-types.mjs.map +10 -0
  225. package/dist/mjs/internal/typecheck/typecheck.mjs +91 -0
  226. package/dist/mjs/internal/typecheck/typecheck.mjs.map +10 -0
  227. package/dist/mjs/modules/index.mjs +96 -0
  228. package/dist/mjs/modules/index.mjs.map +10 -0
  229. package/dist/mjs/package.json +5 -0
  230. package/dist/mjs/runtime/script-runtime.mjs +57 -0
  231. package/dist/mjs/runtime/script-runtime.mjs.map +10 -0
  232. package/dist/mjs/server/app-server.mjs +118 -0
  233. package/dist/mjs/server/app-server.mjs.map +10 -0
  234. package/dist/mjs/testing/integration-helpers.mjs +63 -0
  235. package/dist/mjs/testing/integration-helpers.mjs.map +10 -0
  236. package/dist/mjs/typecheck/index.mjs +56 -0
  237. package/dist/mjs/typecheck/index.mjs.map +10 -0
  238. package/dist/mjs/types.mjs +2 -0
  239. package/dist/mjs/types.mjs.map +9 -0
  240. package/dist/types/bridge/diagnostics.d.ts +12 -0
  241. package/dist/types/bridge/legacy-adapters.d.ts +14 -0
  242. package/dist/types/bridge/request-context.d.ts +10 -0
  243. package/dist/types/bridge/runtime-bindings.d.ts +14 -0
  244. package/dist/types/browser/browser-runtime.d.ts +3 -0
  245. package/dist/types/daemon.d.ts +2 -0
  246. package/dist/types/files/index.d.ts +5 -0
  247. package/dist/types/host/create-isolate-host.d.ts +2 -0
  248. package/dist/types/host/index.d.ts +1 -0
  249. package/dist/types/index.d.ts +5 -0
  250. package/dist/types/internal/client/connection.d.ts +9 -0
  251. package/dist/types/internal/client/index.d.ts +8 -0
  252. package/dist/types/internal/client/types.d.ts +198 -0
  253. package/dist/types/internal/console/index.d.ts +108 -0
  254. package/dist/types/internal/console/utils.d.ts +27 -0
  255. package/dist/types/internal/core/index.d.ts +119 -0
  256. package/dist/types/internal/crypto/index.d.ts +18 -0
  257. package/dist/types/internal/daemon/callback-fs-handler.d.ts +28 -0
  258. package/dist/types/internal/daemon/connection.d.ts +9 -0
  259. package/dist/types/internal/daemon/daemon.d.ts +2 -0
  260. package/dist/types/internal/daemon/index.d.ts +14 -0
  261. package/dist/types/internal/daemon/runtime-pool.d.ts +16 -0
  262. package/dist/types/internal/daemon/types.d.ts +211 -0
  263. package/dist/types/internal/encoding/index.d.ts +21 -0
  264. package/dist/types/internal/fetch/consistency/origins.d.ts +179 -0
  265. package/dist/types/internal/fetch/index.d.ts +93 -0
  266. package/dist/types/internal/fetch/stream-state.d.ts +65 -0
  267. package/dist/types/internal/fs/index.d.ts +70 -0
  268. package/dist/types/internal/fs/node-adapter.d.ts +24 -0
  269. package/dist/types/internal/module-loader/bundle.d.ts +33 -0
  270. package/dist/types/internal/module-loader/index.d.ts +30 -0
  271. package/dist/types/internal/module-loader/mappings.d.ts +47 -0
  272. package/dist/types/internal/module-loader/resolve.d.ts +26 -0
  273. package/dist/types/internal/module-loader/strip-types.d.ts +19 -0
  274. package/dist/types/internal/path/index.d.ts +23 -0
  275. package/dist/types/internal/playwright/client.d.ts +7 -0
  276. package/dist/types/internal/playwright/handler.d.ts +44 -0
  277. package/dist/types/internal/playwright/index.d.ts +14 -0
  278. package/dist/types/internal/playwright/types.d.ts +145 -0
  279. package/dist/types/internal/protocol/codec.d.ts +242 -0
  280. package/dist/types/internal/protocol/framing.d.ts +89 -0
  281. package/dist/types/internal/protocol/index.d.ts +10 -0
  282. package/dist/types/internal/protocol/marshalValue.d.ts +79 -0
  283. package/dist/types/internal/protocol/serialization.d.ts +23 -0
  284. package/dist/types/internal/protocol/types.d.ts +996 -0
  285. package/dist/types/internal/runtime/index.d.ts +200 -0
  286. package/dist/types/internal/server/index.d.ts +42 -0
  287. package/dist/types/internal/test-environment/index.d.ts +112 -0
  288. package/dist/types/internal/timers/index.d.ts +22 -0
  289. package/dist/types/internal/transform/index.d.ts +36 -0
  290. package/dist/types/internal/typecheck/index.d.ts +7 -0
  291. package/dist/types/internal/typecheck/isolate-types.d.ts +94 -0
  292. package/dist/types/internal/typecheck/typecheck.d.ts +148 -0
  293. package/dist/types/modules/index.d.ts +2 -0
  294. package/dist/types/runtime/script-runtime.d.ts +6 -0
  295. package/dist/types/server/app-server.d.ts +3 -0
  296. package/dist/types/testing/integration-helpers.d.ts +9 -0
  297. package/dist/types/typecheck/index.d.ts +8 -0
  298. package/dist/types/types.d.ts +233 -0
  299. package/package.json +82 -6
@@ -0,0 +1,1931 @@
1
+ // src/internal/daemon/connection.ts
2
+ import { AsyncLocalStorage } from "node:async_hooks";
3
+ import { randomUUID } from "node:crypto";
4
+ import {
5
+ createFrameParser,
6
+ buildFrame,
7
+ MessageType,
8
+ ErrorCode,
9
+ STREAM_CHUNK_SIZE,
10
+ STREAM_DEFAULT_CREDIT,
11
+ marshalValue,
12
+ isPromiseRef,
13
+ isAsyncIteratorRef,
14
+ deserializeResponse,
15
+ IsolateEvents,
16
+ ClientEvents
17
+ } from "../protocol/index.mjs";
18
+ import { createCallbackFileSystemHandler } from "./callback-fs-handler.mjs";
19
+ import {
20
+ createRuntime
21
+ } from "../runtime/index.mjs";
22
+ import {
23
+ collectRuntimePoolSnapshot,
24
+ formatRuntimeLabel,
25
+ formatRuntimePoolSnapshot
26
+ } from "./runtime-pool.mjs";
27
+ var LINKER_CONFLICT_ERROR = "Module is currently being linked by another linker";
28
+ var NULL_BODY_STATUSES = new Set([101, 103, 204, 205, 304]);
29
+ var DEFAULT_CALLBACK_TIMEOUT_MS = 120000;
30
+ var FETCH_CALLBACK_TIMEOUT_MS = 35000;
31
+ var requestContextStorage = new AsyncLocalStorage;
32
+ function createAbortError(reason = "The operation was aborted") {
33
+ if (typeof DOMException !== "undefined") {
34
+ return new DOMException(reason, "AbortError");
35
+ }
36
+ const error = new Error(reason);
37
+ error.name = "AbortError";
38
+ return error;
39
+ }
40
+ function sendCallbackAbortMessage(connection, targetRequestId, reason) {
41
+ const abortMessage = {
42
+ type: MessageType.CALLBACK_ABORT,
43
+ requestId: connection.nextRequestId++,
44
+ targetRequestId,
45
+ reason
46
+ };
47
+ sendMessage(connection.socket, abortMessage);
48
+ }
49
+ function getErrorText(error) {
50
+ if (error instanceof Error) {
51
+ const cause = error.cause;
52
+ const causeText = cause instanceof Error ? `${cause.name}: ${cause.message}
53
+ ${cause.stack ?? ""}` : cause != null ? String(cause) : "";
54
+ return [error.name, error.message, error.stack, causeText].filter((part) => part != null && part !== "").join(`
55
+ `);
56
+ }
57
+ if (typeof error === "string") {
58
+ return error;
59
+ }
60
+ try {
61
+ return JSON.stringify(error);
62
+ } catch {
63
+ return String(error ?? "");
64
+ }
65
+ }
66
+ function isLinkerConflictError(error) {
67
+ const text = getErrorText(error).toLowerCase();
68
+ return text.includes(LINKER_CONFLICT_ERROR.toLowerCase());
69
+ }
70
+ function isRuntimeTimeoutError(error) {
71
+ return error instanceof Error && /^(Execution|Test) timed out after \d+ms$/i.test(error.message);
72
+ }
73
+ function handleConnection(socket, state) {
74
+ const connection = {
75
+ socket,
76
+ isolates: new Set,
77
+ pendingRequests: new Map,
78
+ pendingCallbacks: new Map,
79
+ nextRequestId: 1,
80
+ nextCallbackId: 1,
81
+ nextStreamId: 1,
82
+ activeStreams: new Map,
83
+ streamReceivers: new Map,
84
+ callbackStreamReceivers: new Map,
85
+ dispatchAbortControllers: new Map,
86
+ earlyAbortedDispatches: new Set
87
+ };
88
+ state.connections.set(socket, connection);
89
+ const parser = createFrameParser();
90
+ socket.on("data", (data) => {
91
+ try {
92
+ for (const frame of parser.feed(new Uint8Array(data))) {
93
+ handleMessage(frame.message, connection, state).catch((err) => {
94
+ console.error("Error handling message:", err);
95
+ });
96
+ }
97
+ } catch (err) {
98
+ console.error("Error parsing frame:", err);
99
+ socket.destroy();
100
+ }
101
+ });
102
+ socket.on("close", () => {
103
+ for (const streamId of Array.from(connection.activeStreams.keys())) {
104
+ closeActiveDownloadSession(connection, streamId);
105
+ }
106
+ for (const [, controller] of connection.dispatchAbortControllers) {
107
+ controller.abort();
108
+ }
109
+ connection.dispatchAbortControllers.clear();
110
+ connection.earlyAbortedDispatches.clear();
111
+ for (const isolateId of connection.isolates) {
112
+ const instance = state.isolates.get(isolateId);
113
+ if (instance) {
114
+ if (instance.namespaceId != null && !instance.isDisposed) {
115
+ if (instance.isPoisoned) {
116
+ hardDeleteRuntime(instance, state, "owner connection closed after runtime was poisoned").catch(() => {});
117
+ } else {
118
+ softDeleteRuntime(instance, state, "owner connection closed; preserving namespaced runtime for reuse");
119
+ }
120
+ } else if (!instance.isDisposed) {
121
+ hardDeleteRuntime(instance, state, "owner connection closed for non-namespaced runtime").catch(() => {});
122
+ }
123
+ }
124
+ }
125
+ for (const [, pending] of connection.pendingCallbacks) {
126
+ pending.cleanup?.();
127
+ pending.reject(new Error("Connection closed"));
128
+ }
129
+ connection.pendingCallbacks.clear();
130
+ state.connections.delete(socket);
131
+ });
132
+ socket.on("error", (err) => {
133
+ console.error("Socket error:", err);
134
+ });
135
+ }
136
+ function sendMessage(socket, message) {
137
+ const frame = buildFrame(message);
138
+ socket.write(frame);
139
+ }
140
+ function closeActiveDownloadSession(connection, streamId) {
141
+ const session = connection.activeStreams.get(streamId);
142
+ if (!session) {
143
+ return;
144
+ }
145
+ session.state = "closed";
146
+ if (session.creditResolver) {
147
+ session.creditResolver();
148
+ session.creditResolver = undefined;
149
+ }
150
+ if (session.cancelReader) {
151
+ session.cancelReader();
152
+ session.cancelReader = undefined;
153
+ }
154
+ connection.activeStreams.delete(streamId);
155
+ }
156
+ function sendError(socket, requestId, code, message, details) {
157
+ const response = {
158
+ type: MessageType.RESPONSE_ERROR,
159
+ requestId,
160
+ code,
161
+ message,
162
+ details
163
+ };
164
+ sendMessage(socket, response);
165
+ }
166
+ function sendOk(socket, requestId, data) {
167
+ const response = {
168
+ type: MessageType.RESPONSE_OK,
169
+ requestId,
170
+ data
171
+ };
172
+ sendMessage(socket, response);
173
+ }
174
+ async function handleMessage(message, connection, state) {
175
+ state.stats.totalRequestsProcessed++;
176
+ switch (message.type) {
177
+ case MessageType.CREATE_RUNTIME:
178
+ await handleCreateRuntime(message, connection, state);
179
+ break;
180
+ case MessageType.DISPOSE_RUNTIME:
181
+ await handleDisposeRuntime(message, connection, state);
182
+ break;
183
+ case MessageType.EVAL:
184
+ await handleEval(message, connection, state);
185
+ break;
186
+ case MessageType.DISPATCH_REQUEST:
187
+ await handleDispatchRequest(message, connection, state);
188
+ break;
189
+ case MessageType.DISPATCH_REQUEST_ABORT:
190
+ handleDispatchRequestAbort(message, connection);
191
+ break;
192
+ case MessageType.CALLBACK_RESPONSE:
193
+ handleCallbackResponse(message, connection);
194
+ break;
195
+ case MessageType.WS_OPEN:
196
+ await handleWsOpen(message, connection, state);
197
+ break;
198
+ case MessageType.WS_MESSAGE:
199
+ await handleWsMessage(message, connection, state);
200
+ break;
201
+ case MessageType.WS_CLOSE:
202
+ await handleWsClose(message, connection, state);
203
+ break;
204
+ case MessageType.FETCH_GET_UPGRADE_REQUEST:
205
+ await handleFetchGetUpgradeRequest(message, connection, state);
206
+ break;
207
+ case MessageType.FETCH_HAS_SERVE_HANDLER:
208
+ await handleFetchHasServeHandler(message, connection, state);
209
+ break;
210
+ case MessageType.FETCH_HAS_ACTIVE_CONNECTIONS:
211
+ await handleFetchHasActiveConnections(message, connection, state);
212
+ break;
213
+ case MessageType.FETCH_WS_ERROR:
214
+ await handleFetchWsError(message, connection, state);
215
+ break;
216
+ case MessageType.TIMERS_CLEAR_ALL:
217
+ await handleTimersClearAll(message, connection, state);
218
+ break;
219
+ case MessageType.CONSOLE_RESET:
220
+ await handleConsoleReset(message, connection, state);
221
+ break;
222
+ case MessageType.CONSOLE_GET_TIMERS:
223
+ await handleConsoleGetTimers(message, connection, state);
224
+ break;
225
+ case MessageType.CONSOLE_GET_COUNTERS:
226
+ await handleConsoleGetCounters(message, connection, state);
227
+ break;
228
+ case MessageType.CONSOLE_GET_GROUP_DEPTH:
229
+ await handleConsoleGetGroupDepth(message, connection, state);
230
+ break;
231
+ case MessageType.RUN_TESTS:
232
+ await handleRunTests(message, connection, state);
233
+ break;
234
+ case MessageType.RESET_TEST_ENV:
235
+ await handleResetTestEnv(message, connection, state);
236
+ break;
237
+ case MessageType.HAS_TESTS:
238
+ await handleHasTests(message, connection, state);
239
+ break;
240
+ case MessageType.GET_TEST_COUNT:
241
+ await handleGetTestCount(message, connection, state);
242
+ break;
243
+ case MessageType.GET_COLLECTED_DATA:
244
+ await handleGetCollectedData(message, connection, state);
245
+ break;
246
+ case MessageType.CLEAR_COLLECTED_DATA:
247
+ await handleClearCollectedData(message, connection, state);
248
+ break;
249
+ case MessageType.PING:
250
+ sendMessage(connection.socket, { type: MessageType.PONG });
251
+ break;
252
+ case MessageType.STREAM_PUSH:
253
+ handleStreamPush(message, connection);
254
+ break;
255
+ case MessageType.STREAM_PULL:
256
+ handleStreamPull(message, connection);
257
+ break;
258
+ case MessageType.STREAM_CLOSE:
259
+ handleStreamClose(message, connection);
260
+ break;
261
+ case MessageType.STREAM_ERROR:
262
+ handleStreamError(message, connection);
263
+ break;
264
+ case MessageType.CALLBACK_STREAM_START:
265
+ handleCallbackStreamStart(message, connection);
266
+ break;
267
+ case MessageType.CALLBACK_STREAM_CHUNK:
268
+ handleCallbackStreamChunk(message, connection);
269
+ break;
270
+ case MessageType.CALLBACK_STREAM_END:
271
+ handleCallbackStreamEnd(message, connection);
272
+ break;
273
+ case MessageType.CLIENT_EVENT:
274
+ handleClientEvent(message, connection, state);
275
+ break;
276
+ default:
277
+ sendError(connection.socket, message.requestId ?? 0, ErrorCode.UNKNOWN_MESSAGE_TYPE, `Unknown message type: ${message.type}`);
278
+ }
279
+ }
280
+ function logRuntimeLifecycle(state, event, instance, reason, level = "log") {
281
+ const logger = level === "warn" ? console.warn : console.log;
282
+ const poisonedSuffix = instance.isPoisoned ? " poisoned=true" : "";
283
+ const reasonSuffix = reason ? `: ${reason}` : "";
284
+ logger(`[isolate-daemon] ${event} runtime ${formatRuntimeLabel(instance)}${poisonedSuffix}${reasonSuffix}; ${formatRuntimePoolSnapshot(collectRuntimePoolSnapshot(state))}`);
285
+ }
286
+ async function hardDeleteRuntime(instance, state, reason) {
287
+ const wasPooled = instance.isDisposed;
288
+ try {
289
+ if (instance.runtimeAbortController && !instance.runtimeAbortController.signal.aborted) {
290
+ instance.runtimeAbortController.abort(new Error(reason ?? "Runtime was permanently disposed"));
291
+ }
292
+ await instance.runtime.dispose();
293
+ } finally {
294
+ state.isolates.delete(instance.isolateId);
295
+ if (instance.namespaceId != null) {
296
+ const indexed = state.namespacedRuntimes.get(instance.namespaceId);
297
+ if (indexed?.isolateId === instance.isolateId) {
298
+ state.namespacedRuntimes.delete(instance.namespaceId);
299
+ }
300
+ }
301
+ instance.isDisposed = true;
302
+ instance.disposedAt = undefined;
303
+ instance.ownerConnection = null;
304
+ if (instance.callbackContext) {
305
+ if (instance.callbackContext.reconnectionPromise) {
306
+ clearTimeout(instance.callbackContext.reconnectionPromise.timeoutId);
307
+ instance.callbackContext.reconnectionPromise.promise.catch(() => {});
308
+ instance.callbackContext.reconnectionPromise.reject(new Error("Runtime was permanently disposed"));
309
+ instance.callbackContext.reconnectionPromise = undefined;
310
+ }
311
+ instance.callbackContext.connection = null;
312
+ }
313
+ logRuntimeLifecycle(state, wasPooled ? "evicted pooled" : "hard-disposed", instance, reason);
314
+ }
315
+ }
316
+ var RECONNECTION_TIMEOUT_MS = 30000;
317
+ function softDeleteRuntime(instance, state, reason) {
318
+ if (instance.runtimeAbortController && !instance.runtimeAbortController.signal.aborted) {
319
+ instance.runtimeAbortController.abort(new Error(reason ?? "Runtime was soft-disposed"));
320
+ }
321
+ instance.isDisposed = true;
322
+ instance.disposedAt = Date.now();
323
+ instance.ownerConnection = null;
324
+ if (instance.callbackContext) {
325
+ instance.callbackContext.connection = null;
326
+ let resolve;
327
+ let reject;
328
+ const promise = new Promise((res, rej) => {
329
+ resolve = res;
330
+ reject = rej;
331
+ });
332
+ promise.catch(() => {});
333
+ const timeoutId = setTimeout(() => {
334
+ if (instance.callbackContext?.reconnectionPromise) {
335
+ instance.callbackContext.reconnectionPromise = undefined;
336
+ reject(new Error("Reconnection timeout: no client reconnected within timeout"));
337
+ }
338
+ }, RECONNECTION_TIMEOUT_MS);
339
+ instance.callbackContext.reconnectionPromise = {
340
+ promise,
341
+ resolve,
342
+ reject,
343
+ timeoutId
344
+ };
345
+ }
346
+ instance.callbacks.clear();
347
+ instance.runtime.timers.clearAll();
348
+ instance.runtime.console.reset();
349
+ instance.runtime.pendingCallbacks.length = 0;
350
+ instance.returnedCallbacks?.clear();
351
+ instance.returnedPromises?.clear();
352
+ instance.returnedIterators?.clear();
353
+ instance.runtime.clearModuleCache();
354
+ logRuntimeLifecycle(state, "soft-disposed", instance, reason);
355
+ }
356
+ function reuseNamespacedRuntime(instance, connection, message, state) {
357
+ instance.ownerConnection = connection.socket;
358
+ instance.isDisposed = false;
359
+ instance.isPoisoned = false;
360
+ instance.disposedAt = undefined;
361
+ instance.lastActivity = Date.now();
362
+ instance.runtimeAbortController = new AbortController;
363
+ connection.isolates.add(instance.isolateId);
364
+ const callbacks = message.options.callbacks;
365
+ const testEnvOptions = message.options.testEnvironment != null && typeof message.options.testEnvironment === "object" ? message.options.testEnvironment : undefined;
366
+ if (instance.callbackContext) {
367
+ instance.callbackContext.connection = connection;
368
+ if (instance.callbackContext.reconnectionPromise) {
369
+ clearTimeout(instance.callbackContext.reconnectionPromise.timeoutId);
370
+ instance.callbackContext.reconnectionPromise.resolve(connection);
371
+ instance.callbackContext.reconnectionPromise = undefined;
372
+ }
373
+ instance.callbackContext.consoleOnEntry = callbacks?.console?.onEntry?.callbackId;
374
+ instance.callbackContext.fetch = callbacks?.fetch?.callbackId;
375
+ instance.callbackContext.moduleLoader = callbacks?.moduleLoader?.callbackId;
376
+ instance.callbackContext.testEnvironmentOnEvent = testEnvOptions?.callbacks?.onEvent?.callbackId;
377
+ instance.callbackContext.playwright = {
378
+ handlerCallbackId: callbacks?.playwright?.handlerCallbackId,
379
+ onBrowserConsoleLogCallbackId: callbacks?.playwright?.onBrowserConsoleLogCallbackId,
380
+ onNetworkRequestCallbackId: callbacks?.playwright?.onNetworkRequestCallbackId,
381
+ onNetworkResponseCallbackId: callbacks?.playwright?.onNetworkResponseCallbackId
382
+ };
383
+ instance.callbackContext.fs = {
384
+ readFile: callbacks?.fs?.readFile?.callbackId,
385
+ writeFile: callbacks?.fs?.writeFile?.callbackId,
386
+ stat: callbacks?.fs?.stat?.callbackId,
387
+ readdir: callbacks?.fs?.readdir?.callbackId,
388
+ unlink: callbacks?.fs?.unlink?.callbackId,
389
+ mkdir: callbacks?.fs?.mkdir?.callbackId,
390
+ rmdir: callbacks?.fs?.rmdir?.callbackId
391
+ };
392
+ instance.callbackContext.custom.clear();
393
+ if (callbacks?.custom) {
394
+ for (const [name, reg] of Object.entries(callbacks.custom)) {
395
+ if (reg) {
396
+ instance.callbackContext.custom.set(name, reg.callbackId);
397
+ }
398
+ }
399
+ }
400
+ }
401
+ instance.callbacks.clear();
402
+ if (callbacks?.console?.onEntry) {
403
+ instance.callbacks.set(callbacks.console.onEntry.callbackId, {
404
+ ...callbacks.console.onEntry,
405
+ name: "onEntry"
406
+ });
407
+ }
408
+ if (callbacks?.fetch) {
409
+ instance.callbacks.set(callbacks.fetch.callbackId, callbacks.fetch);
410
+ }
411
+ if (callbacks?.fs) {
412
+ for (const [name, reg] of Object.entries(callbacks.fs)) {
413
+ if (reg) {
414
+ instance.callbacks.set(reg.callbackId, { ...reg, name });
415
+ }
416
+ }
417
+ }
418
+ if (callbacks?.moduleLoader) {
419
+ instance.callbacks.set(callbacks.moduleLoader.callbackId, callbacks.moduleLoader);
420
+ }
421
+ if (callbacks?.custom) {
422
+ for (const [name, reg] of Object.entries(callbacks.custom)) {
423
+ if (reg) {
424
+ instance.callbacks.set(reg.callbackId, { ...reg, name });
425
+ }
426
+ }
427
+ }
428
+ if (testEnvOptions?.callbacks?.onEvent) {
429
+ instance.callbacks.set(testEnvOptions.callbacks.onEvent.callbackId, {
430
+ ...testEnvOptions.callbacks.onEvent,
431
+ name: "testEnvironment.onEvent"
432
+ });
433
+ }
434
+ if (callbacks?.playwright) {
435
+ instance.callbacks.set(callbacks.playwright.handlerCallbackId, {
436
+ callbackId: callbacks.playwright.handlerCallbackId,
437
+ name: "playwright.handler",
438
+ type: "async"
439
+ });
440
+ if (callbacks.playwright.onBrowserConsoleLogCallbackId !== undefined) {
441
+ instance.callbacks.set(callbacks.playwright.onBrowserConsoleLogCallbackId, {
442
+ callbackId: callbacks.playwright.onBrowserConsoleLogCallbackId,
443
+ name: "playwright.onBrowserConsoleLog",
444
+ type: "sync"
445
+ });
446
+ }
447
+ if (callbacks.playwright.onNetworkRequestCallbackId !== undefined) {
448
+ instance.callbacks.set(callbacks.playwright.onNetworkRequestCallbackId, {
449
+ callbackId: callbacks.playwright.onNetworkRequestCallbackId,
450
+ name: "playwright.onNetworkRequest",
451
+ type: "sync"
452
+ });
453
+ }
454
+ if (callbacks.playwright.onNetworkResponseCallbackId !== undefined) {
455
+ instance.callbacks.set(callbacks.playwright.onNetworkResponseCallbackId, {
456
+ callbackId: callbacks.playwright.onNetworkResponseCallbackId,
457
+ name: "playwright.onNetworkResponse",
458
+ type: "sync"
459
+ });
460
+ }
461
+ }
462
+ instance.returnedCallbacks = new Map;
463
+ instance.returnedPromises = new Map;
464
+ instance.returnedIterators = new Map;
465
+ instance.nextLocalCallbackId = 1e6;
466
+ logRuntimeLifecycle(state, "reused pooled", instance);
467
+ }
468
+ async function waitForConnection(callbackContext) {
469
+ if (callbackContext.connection) {
470
+ return callbackContext.connection;
471
+ }
472
+ if (callbackContext.reconnectionPromise) {
473
+ return callbackContext.reconnectionPromise.promise;
474
+ }
475
+ throw new Error("No connection available and no reconnection pending");
476
+ }
477
+ function getCurrentHostSignal(instance) {
478
+ return requestContextStorage.getStore()?.signal ?? instance?.runtimeAbortController?.signal;
479
+ }
480
+ async function invokeCallbackWithReconnect(callbackContext, getCallbackId, args, label, invokeClientCallback, options) {
481
+ const conn = await waitForConnection(callbackContext);
482
+ const cbId = getCallbackId();
483
+ if (cbId === undefined) {
484
+ throw new Error(`${label} callback not available`);
485
+ }
486
+ try {
487
+ return await invokeClientCallback(conn, cbId, args, options);
488
+ } catch (err) {
489
+ if (callbackContext.reconnectionPromise && !callbackContext.connection) {
490
+ const newConn = await callbackContext.reconnectionPromise.promise;
491
+ const newCbId = getCallbackId();
492
+ if (newCbId === undefined) {
493
+ throw new Error(`${label} callback not available after reconnection`);
494
+ }
495
+ return invokeClientCallback(newConn, newCbId, args, options);
496
+ }
497
+ throw err;
498
+ }
499
+ }
500
+ async function evictOldestDisposedRuntime(state) {
501
+ let oldest = null;
502
+ let oldestTime = Infinity;
503
+ for (const [, instance] of state.isolates) {
504
+ if (instance.isDisposed && instance.disposedAt !== undefined) {
505
+ if (instance.disposedAt < oldestTime) {
506
+ oldestTime = instance.disposedAt;
507
+ oldest = instance;
508
+ }
509
+ }
510
+ }
511
+ if (oldest) {
512
+ try {
513
+ await hardDeleteRuntime(oldest, state, "LRU eviction to make room for a new runtime");
514
+ } catch {}
515
+ return true;
516
+ }
517
+ return false;
518
+ }
519
+ async function handleCreateRuntime(message, connection, state) {
520
+ const namespaceId = message.options.namespaceId;
521
+ let namespaceCreationLocked = false;
522
+ if (namespaceId != null) {
523
+ const existing = state.namespacedRuntimes.get(namespaceId);
524
+ if (existing) {
525
+ if (!existing.isDisposed) {
526
+ if (existing.ownerConnection === connection.socket) {
527
+ sendOk(connection.socket, message.requestId, {
528
+ isolateId: existing.isolateId,
529
+ reused: true
530
+ });
531
+ return;
532
+ }
533
+ sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, `Namespace "${namespaceId}" already has an active runtime`);
534
+ return;
535
+ }
536
+ reuseNamespacedRuntime(existing, connection, message, state);
537
+ sendOk(connection.socket, message.requestId, {
538
+ isolateId: existing.isolateId,
539
+ reused: true
540
+ });
541
+ return;
542
+ }
543
+ if (state.namespacedCreatesInFlight.has(namespaceId)) {
544
+ sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, `Namespace "${namespaceId}" creation already in progress`);
545
+ return;
546
+ }
547
+ state.namespacedCreatesInFlight.add(namespaceId);
548
+ namespaceCreationLocked = true;
549
+ }
550
+ try {
551
+ if (state.isolates.size >= state.options.maxIsolates) {
552
+ if (!await evictOldestDisposedRuntime(state)) {
553
+ const targetLabel = namespaceId != null ? `namespace=${JSON.stringify(namespaceId)}` : "non-namespaced";
554
+ console.warn(`[isolate-daemon] denied runtime create for ${targetLabel}: ${formatRuntimePoolSnapshot(collectRuntimePoolSnapshot(state))}`);
555
+ sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_MEMORY_LIMIT, `Maximum isolates (${state.options.maxIsolates}) reached`);
556
+ return;
557
+ }
558
+ }
559
+ const isolateId = randomUUID();
560
+ const consoleCallbacks = message.options.callbacks?.console;
561
+ const fetchCallback = message.options.callbacks?.fetch;
562
+ const fsCallbacks = message.options.callbacks?.fs;
563
+ const moduleLoaderCallback = message.options.callbacks?.moduleLoader;
564
+ const customCallbacks = message.options.callbacks?.custom;
565
+ const callbackContext = {
566
+ connection,
567
+ consoleOnEntry: consoleCallbacks?.onEntry?.callbackId,
568
+ fetch: fetchCallback?.callbackId,
569
+ moduleLoader: moduleLoaderCallback?.callbackId,
570
+ testEnvironmentOnEvent: message.options.testEnvironment != null && typeof message.options.testEnvironment === "object" ? message.options.testEnvironment.callbacks?.onEvent?.callbackId : undefined,
571
+ playwright: {
572
+ handlerCallbackId: message.options.callbacks?.playwright?.handlerCallbackId,
573
+ onBrowserConsoleLogCallbackId: message.options.callbacks?.playwright?.onBrowserConsoleLogCallbackId,
574
+ onNetworkRequestCallbackId: message.options.callbacks?.playwright?.onNetworkRequestCallbackId,
575
+ onNetworkResponseCallbackId: message.options.callbacks?.playwright?.onNetworkResponseCallbackId
576
+ },
577
+ fs: {
578
+ readFile: fsCallbacks?.readFile?.callbackId,
579
+ writeFile: fsCallbacks?.writeFile?.callbackId,
580
+ stat: fsCallbacks?.stat?.callbackId,
581
+ readdir: fsCallbacks?.readdir?.callbackId,
582
+ unlink: fsCallbacks?.unlink?.callbackId,
583
+ mkdir: fsCallbacks?.mkdir?.callbackId,
584
+ rmdir: fsCallbacks?.rmdir?.callbackId
585
+ },
586
+ custom: new Map(customCallbacks ? Object.entries(customCallbacks).map(([name, reg]) => [name, reg.callbackId]) : [])
587
+ };
588
+ const instance = {
589
+ isolateId,
590
+ runtime: null,
591
+ ownerConnection: connection.socket,
592
+ callbacks: new Map,
593
+ createdAt: Date.now(),
594
+ lastActivity: Date.now(),
595
+ runtimeAbortController: new AbortController,
596
+ returnedCallbacks: new Map,
597
+ returnedPromises: new Map,
598
+ returnedIterators: new Map,
599
+ nextLocalCallbackId: 1e6,
600
+ namespaceId,
601
+ isDisposed: false,
602
+ isPoisoned: false,
603
+ callbackContext
604
+ };
605
+ let bridgedCustomFunctions;
606
+ let customFnMarshalOptions;
607
+ if (customCallbacks) {
608
+ const createMarshalContext = () => ({
609
+ registerCallback: (fn) => {
610
+ const callbackId = instance.nextLocalCallbackId++;
611
+ instance.returnedCallbacks.set(callbackId, fn);
612
+ return callbackId;
613
+ },
614
+ registerPromise: (promise) => {
615
+ const promiseId = instance.nextLocalCallbackId++;
616
+ instance.returnedPromises.set(promiseId, promise);
617
+ return promiseId;
618
+ },
619
+ registerIterator: (iterator) => {
620
+ const iteratorId = instance.nextLocalCallbackId++;
621
+ instance.returnedIterators.set(iteratorId, iterator);
622
+ return iteratorId;
623
+ }
624
+ });
625
+ const addCallbackIdsToRefs = (value) => {
626
+ if (value === null || typeof value !== "object")
627
+ return value;
628
+ if (isPromiseRef(value)) {
629
+ if ("__resolveCallbackId" in value)
630
+ return value;
631
+ const resolveCallbackId = instance.nextLocalCallbackId++;
632
+ instance.returnedCallbacks.set(resolveCallbackId, async (promiseId) => {
633
+ const promise = instance.returnedPromises.get(promiseId);
634
+ if (!promise)
635
+ throw new Error(`Promise ${promiseId} not found`);
636
+ const result2 = await promise;
637
+ instance.returnedPromises.delete(promiseId);
638
+ const ctx = createMarshalContext();
639
+ const marshalled = await marshalValue(result2, ctx);
640
+ return addCallbackIdsToRefs(marshalled);
641
+ });
642
+ return { ...value, __resolveCallbackId: resolveCallbackId };
643
+ }
644
+ if (isAsyncIteratorRef(value)) {
645
+ if ("__nextCallbackId" in value)
646
+ return value;
647
+ const nextCallbackId = instance.nextLocalCallbackId++;
648
+ instance.returnedCallbacks.set(nextCallbackId, async (iteratorId) => {
649
+ const iterator = instance.returnedIterators.get(iteratorId);
650
+ if (!iterator)
651
+ throw new Error(`Iterator ${iteratorId} not found`);
652
+ const result2 = await iterator.next();
653
+ if (result2.done)
654
+ instance.returnedIterators.delete(iteratorId);
655
+ const ctx = createMarshalContext();
656
+ const marshalledValue = await marshalValue(result2.value, ctx);
657
+ return { done: result2.done, value: addCallbackIdsToRefs(marshalledValue) };
658
+ });
659
+ const returnCallbackId = instance.nextLocalCallbackId++;
660
+ instance.returnedCallbacks.set(returnCallbackId, async (iteratorId, returnValue) => {
661
+ const iterator = instance.returnedIterators.get(iteratorId);
662
+ instance.returnedIterators.delete(iteratorId);
663
+ if (!iterator || !iterator.return)
664
+ return { done: true, value: undefined };
665
+ const result2 = await iterator.return(returnValue);
666
+ const ctx = createMarshalContext();
667
+ const marshalledValue = await marshalValue(result2.value, ctx);
668
+ return { done: true, value: addCallbackIdsToRefs(marshalledValue) };
669
+ });
670
+ const throwCallbackId = instance.nextLocalCallbackId++;
671
+ instance.returnedCallbacks.set(throwCallbackId, async (iteratorId, errorValue) => {
672
+ const iterator = instance.returnedIterators.get(iteratorId);
673
+ if (!iterator) {
674
+ throw new Error(`Iterator ${iteratorId} not found`);
675
+ }
676
+ try {
677
+ if (!iterator.throw) {
678
+ throw Object.assign(new Error(errorValue?.message ?? "Iterator does not support throw()"), { name: errorValue?.name ?? "Error", stack: errorValue?.stack });
679
+ }
680
+ const thrownError = Object.assign(new Error(errorValue?.message ?? "Iterator throw()"), { name: errorValue?.name ?? "Error", stack: errorValue?.stack });
681
+ const result2 = await iterator.throw(thrownError);
682
+ if (result2.done) {
683
+ instance.returnedIterators.delete(iteratorId);
684
+ }
685
+ const ctx = createMarshalContext();
686
+ const marshalledValue = await marshalValue(result2.value, ctx);
687
+ return { done: result2.done, value: addCallbackIdsToRefs(marshalledValue) };
688
+ } catch (error) {
689
+ instance.returnedIterators.delete(iteratorId);
690
+ throw error;
691
+ }
692
+ });
693
+ return {
694
+ ...value,
695
+ __nextCallbackId: nextCallbackId,
696
+ __returnCallbackId: returnCallbackId,
697
+ __throwCallbackId: throwCallbackId
698
+ };
699
+ }
700
+ if (Array.isArray(value))
701
+ return value.map((item) => addCallbackIdsToRefs(item));
702
+ const result = {};
703
+ for (const key of Object.keys(value)) {
704
+ result[key] = addCallbackIdsToRefs(value[key]);
705
+ }
706
+ return result;
707
+ };
708
+ const LOCAL_CALLBACK_THRESHOLD = 1e6;
709
+ const invokeCallback = async (callbackId, args) => {
710
+ if (callbackId >= LOCAL_CALLBACK_THRESHOLD) {
711
+ const callback = instance.returnedCallbacks.get(callbackId);
712
+ if (!callback) {
713
+ throw new Error(`Local callback ${callbackId} not found`);
714
+ }
715
+ return await callback(...args);
716
+ } else {
717
+ const conn = await waitForConnection(callbackContext);
718
+ try {
719
+ return await invokeClientCallback(conn, callbackId, args, {
720
+ signal: getCurrentHostSignal(instance)
721
+ });
722
+ } catch (err) {
723
+ if (callbackContext.reconnectionPromise && !callbackContext.connection) {
724
+ const newConn = await callbackContext.reconnectionPromise.promise;
725
+ return invokeClientCallback(newConn, callbackId, args, {
726
+ signal: getCurrentHostSignal(instance)
727
+ });
728
+ }
729
+ throw err;
730
+ }
731
+ }
732
+ };
733
+ customFnMarshalOptions = { createMarshalContext, addCallbackIdsToRefs, invokeCallback };
734
+ bridgedCustomFunctions = {};
735
+ for (const [name, registration] of Object.entries(customCallbacks)) {
736
+ if (name.includes(":"))
737
+ continue;
738
+ const callbackContext_ = callbackContext;
739
+ if (registration.type === "asyncIterator") {
740
+ bridgedCustomFunctions[name] = {
741
+ type: "asyncIterator",
742
+ fn: (...args) => {
743
+ const startCallbackId = callbackContext_.custom.get(`${name}:start`);
744
+ const nextCallbackId = callbackContext_.custom.get(`${name}:next`);
745
+ const returnCallbackId = callbackContext_.custom.get(`${name}:return`);
746
+ async function* bridgedIterator() {
747
+ const startResult = await invokeCallbackWithReconnect(callbackContext_, () => callbackContext_.custom.get(`${name}:start`), args, `AsyncIterator '${name}' start`, invokeClientCallback, { signal: getCurrentHostSignal(instance) });
748
+ const iteratorId = startResult.iteratorId;
749
+ try {
750
+ while (true) {
751
+ const nextResult = await invokeCallbackWithReconnect(callbackContext_, () => callbackContext_.custom.get(`${name}:next`), [iteratorId], `AsyncIterator '${name}' next`, invokeClientCallback, { signal: getCurrentHostSignal(instance) });
752
+ if (nextResult.done)
753
+ return nextResult.value;
754
+ yield nextResult.value;
755
+ }
756
+ } finally {
757
+ const retConn = callbackContext_.connection;
758
+ const retCbId = callbackContext_.custom.get(`${name}:return`);
759
+ if (retConn && retCbId !== undefined) {
760
+ await invokeClientCallback(retConn, retCbId, [iteratorId], {
761
+ signal: getCurrentHostSignal(instance)
762
+ }).catch(() => {});
763
+ }
764
+ }
765
+ }
766
+ return bridgedIterator();
767
+ }
768
+ };
769
+ } else {
770
+ bridgedCustomFunctions[name] = {
771
+ type: registration.type,
772
+ fn: async (...args) => {
773
+ return invokeCallbackWithReconnect(callbackContext_, () => callbackContext_.custom.get(name), args, `Custom function '${name}'`, invokeClientCallback, { signal: getCurrentHostSignal(instance) });
774
+ }
775
+ };
776
+ }
777
+ }
778
+ }
779
+ let moduleLoader;
780
+ if (moduleLoaderCallback) {
781
+ moduleLoader = async (specifier, importer) => {
782
+ return invokeCallbackWithReconnect(callbackContext, () => callbackContext.moduleLoader, [specifier, importer], "Module loader", invokeClientCallback, { signal: getCurrentHostSignal(instance) });
783
+ };
784
+ }
785
+ let testEnvironment;
786
+ if (message.options.testEnvironment) {
787
+ const testEnvOption = message.options.testEnvironment;
788
+ const testEnvOptions = typeof testEnvOption === "object" ? testEnvOption : undefined;
789
+ testEnvironment = {
790
+ onEvent: testEnvOptions?.callbacks?.onEvent ? (event) => {
791
+ const conn = callbackContext.connection;
792
+ const callbackId = callbackContext.testEnvironmentOnEvent;
793
+ if (!conn || callbackId === undefined) {
794
+ return;
795
+ }
796
+ const promise = invokeClientCallback(conn, callbackId, [JSON.stringify(event)], { signal: getCurrentHostSignal(instance) }).catch(() => {});
797
+ instance.runtime?.pendingCallbacks?.push(promise);
798
+ } : undefined,
799
+ testTimeout: testEnvOptions?.testTimeout
800
+ };
801
+ if (testEnvOptions?.callbacks?.onEvent) {
802
+ instance.callbacks.set(testEnvOptions.callbacks.onEvent.callbackId, {
803
+ ...testEnvOptions.callbacks.onEvent,
804
+ name: "testEnvironment.onEvent"
805
+ });
806
+ }
807
+ }
808
+ let playwrightOptions;
809
+ const playwrightCallbacks = message.options.callbacks?.playwright;
810
+ if (playwrightCallbacks) {
811
+ playwrightOptions = {
812
+ handler: async (op) => {
813
+ try {
814
+ const resultJson = await invokeCallbackWithReconnect(callbackContext, () => callbackContext.playwright.handlerCallbackId, [JSON.stringify(op)], "Playwright handler", invokeClientCallback, { signal: getCurrentHostSignal(instance) });
815
+ return JSON.parse(resultJson);
816
+ } catch (err) {
817
+ const error = err;
818
+ return { ok: false, error: { name: error.name, message: error.message } };
819
+ }
820
+ },
821
+ timeout: message.options.playwright?.timeout,
822
+ console: playwrightCallbacks.console,
823
+ onEvent: (event) => {
824
+ const conn = callbackContext.connection;
825
+ if (!conn) {
826
+ return;
827
+ }
828
+ if (event.type === "browserConsoleLog" && callbackContext.playwright.onBrowserConsoleLogCallbackId !== undefined) {
829
+ const promise = invokeClientCallback(conn, callbackContext.playwright.onBrowserConsoleLogCallbackId, [{ level: event.level, stdout: event.stdout, timestamp: event.timestamp }], { signal: getCurrentHostSignal(instance) }).catch(() => {});
830
+ instance.runtime?.pendingCallbacks?.push(promise);
831
+ } else if (event.type === "networkRequest" && callbackContext.playwright.onNetworkRequestCallbackId !== undefined) {
832
+ const promise = invokeClientCallback(conn, callbackContext.playwright.onNetworkRequestCallbackId, [event], { signal: getCurrentHostSignal(instance) }).catch(() => {});
833
+ instance.runtime?.pendingCallbacks?.push(promise);
834
+ } else if (event.type === "networkResponse" && callbackContext.playwright.onNetworkResponseCallbackId !== undefined) {
835
+ const promise = invokeClientCallback(conn, callbackContext.playwright.onNetworkResponseCallbackId, [event], { signal: getCurrentHostSignal(instance) }).catch(() => {});
836
+ instance.runtime?.pendingCallbacks?.push(promise);
837
+ }
838
+ }
839
+ };
840
+ }
841
+ const runtime = await createRuntime({
842
+ memoryLimitMB: message.options.memoryLimitMB ?? state.options.defaultMemoryLimitMB,
843
+ executionTimeout: message.options.executionTimeout,
844
+ cwd: message.options.cwd,
845
+ console: {
846
+ onEntry: (entry) => {
847
+ const conn = callbackContext.connection;
848
+ const callbackId = callbackContext.consoleOnEntry;
849
+ if (!conn || callbackId === undefined)
850
+ return;
851
+ const promise = invokeClientCallback(conn, callbackId, [entry]).catch(() => {});
852
+ runtime.pendingCallbacks.push(promise);
853
+ }
854
+ },
855
+ fetch: async (url, init) => {
856
+ if (init.signal.aborted) {
857
+ throw createAbortError();
858
+ }
859
+ const serialized = {
860
+ url,
861
+ method: init.method,
862
+ headers: init.headers,
863
+ body: init.rawBody,
864
+ signalAborted: init.signal.aborted
865
+ };
866
+ const callbackAbortController = new AbortController;
867
+ const onInitAbort = () => callbackAbortController.abort();
868
+ const currentSignal = getCurrentHostSignal(instance);
869
+ const onCurrentAbort = () => callbackAbortController.abort();
870
+ init.signal.addEventListener("abort", onInitAbort, { once: true });
871
+ currentSignal?.addEventListener("abort", onCurrentAbort, { once: true });
872
+ const result = await invokeCallbackWithReconnect(callbackContext, () => callbackContext.fetch, [serialized], "Fetch", invokeClientCallback, {
873
+ signal: callbackAbortController.signal,
874
+ timeoutMs: FETCH_CALLBACK_TIMEOUT_MS,
875
+ timeoutLabel: "fetch callback"
876
+ }).finally(() => {
877
+ init.signal.removeEventListener("abort", onInitAbort);
878
+ currentSignal?.removeEventListener("abort", onCurrentAbort);
879
+ });
880
+ if (result && typeof result === "object" && result.__streamingResponse) {
881
+ const response = result.response;
882
+ response.__isCallbackStream = true;
883
+ return response;
884
+ }
885
+ return deserializeResponse(result);
886
+ },
887
+ fs: {
888
+ getDirectory: async (dirPath) => {
889
+ const conn = await waitForConnection(callbackContext);
890
+ return createCallbackFileSystemHandler({
891
+ connection: conn,
892
+ callbackContext,
893
+ invokeClientCallback,
894
+ basePath: dirPath,
895
+ getSignal: () => getCurrentHostSignal(instance)
896
+ });
897
+ }
898
+ },
899
+ moduleLoader,
900
+ customFunctions: bridgedCustomFunctions,
901
+ customFunctionsMarshalOptions: customFnMarshalOptions,
902
+ testEnvironment,
903
+ playwright: playwrightOptions
904
+ });
905
+ instance.runtime = runtime;
906
+ if (consoleCallbacks?.onEntry) {
907
+ instance.callbacks.set(consoleCallbacks.onEntry.callbackId, {
908
+ ...consoleCallbacks.onEntry,
909
+ name: "onEntry"
910
+ });
911
+ }
912
+ if (fetchCallback) {
913
+ instance.callbacks.set(fetchCallback.callbackId, fetchCallback);
914
+ }
915
+ if (fsCallbacks) {
916
+ for (const [name, reg] of Object.entries(fsCallbacks)) {
917
+ if (reg) {
918
+ instance.callbacks.set(reg.callbackId, { ...reg, name });
919
+ }
920
+ }
921
+ }
922
+ if (moduleLoaderCallback) {
923
+ instance.callbacks.set(moduleLoaderCallback.callbackId, moduleLoaderCallback);
924
+ }
925
+ if (customCallbacks) {
926
+ for (const [name, reg] of Object.entries(customCallbacks)) {
927
+ if (reg) {
928
+ instance.callbacks.set(reg.callbackId, { ...reg, name });
929
+ }
930
+ }
931
+ }
932
+ if (playwrightCallbacks) {
933
+ instance.callbacks.set(playwrightCallbacks.handlerCallbackId, {
934
+ callbackId: playwrightCallbacks.handlerCallbackId,
935
+ name: "playwright.handler",
936
+ type: "async"
937
+ });
938
+ if (playwrightCallbacks.onBrowserConsoleLogCallbackId !== undefined) {
939
+ instance.callbacks.set(playwrightCallbacks.onBrowserConsoleLogCallbackId, {
940
+ callbackId: playwrightCallbacks.onBrowserConsoleLogCallbackId,
941
+ name: "playwright.onBrowserConsoleLog",
942
+ type: "sync"
943
+ });
944
+ }
945
+ if (playwrightCallbacks.onNetworkRequestCallbackId !== undefined) {
946
+ instance.callbacks.set(playwrightCallbacks.onNetworkRequestCallbackId, {
947
+ callbackId: playwrightCallbacks.onNetworkRequestCallbackId,
948
+ name: "playwright.onNetworkRequest",
949
+ type: "sync"
950
+ });
951
+ }
952
+ if (playwrightCallbacks.onNetworkResponseCallbackId !== undefined) {
953
+ instance.callbacks.set(playwrightCallbacks.onNetworkResponseCallbackId, {
954
+ callbackId: playwrightCallbacks.onNetworkResponseCallbackId,
955
+ name: "playwright.onNetworkResponse",
956
+ type: "sync"
957
+ });
958
+ }
959
+ }
960
+ state.isolates.set(isolateId, instance);
961
+ connection.isolates.add(isolateId);
962
+ state.stats.totalIsolatesCreated++;
963
+ if (namespaceId != null) {
964
+ state.namespacedRuntimes.set(namespaceId, instance);
965
+ }
966
+ runtime.fetch.onWebSocketCommand((cmd) => {
967
+ const targetConnection = callbackContext.connection;
968
+ if (!targetConnection) {
969
+ return;
970
+ }
971
+ let data;
972
+ if (cmd.data instanceof ArrayBuffer) {
973
+ data = new Uint8Array(cmd.data);
974
+ } else {
975
+ data = cmd.data;
976
+ }
977
+ const payload = {
978
+ type: cmd.type,
979
+ connectionId: cmd.connectionId,
980
+ data,
981
+ code: cmd.code,
982
+ reason: cmd.reason
983
+ };
984
+ sendMessage(targetConnection.socket, {
985
+ type: MessageType.ISOLATE_EVENT,
986
+ isolateId,
987
+ event: IsolateEvents.WS_COMMAND,
988
+ payload
989
+ });
990
+ });
991
+ runtime.fetch.onClientWebSocketCommand((cmd) => {
992
+ const targetConnection = callbackContext.connection;
993
+ if (!targetConnection) {
994
+ return;
995
+ }
996
+ let data;
997
+ if (cmd.data instanceof ArrayBuffer) {
998
+ data = new Uint8Array(cmd.data);
999
+ } else {
1000
+ data = cmd.data;
1001
+ }
1002
+ if (cmd.type === "connect") {
1003
+ const payload = {
1004
+ socketId: cmd.socketId,
1005
+ url: cmd.url,
1006
+ protocols: cmd.protocols
1007
+ };
1008
+ sendMessage(targetConnection.socket, {
1009
+ type: MessageType.ISOLATE_EVENT,
1010
+ isolateId,
1011
+ event: IsolateEvents.WS_CLIENT_CONNECT,
1012
+ payload
1013
+ });
1014
+ } else if (cmd.type === "send") {
1015
+ const payload = {
1016
+ socketId: cmd.socketId,
1017
+ data
1018
+ };
1019
+ sendMessage(targetConnection.socket, {
1020
+ type: MessageType.ISOLATE_EVENT,
1021
+ isolateId,
1022
+ event: IsolateEvents.WS_CLIENT_SEND,
1023
+ payload
1024
+ });
1025
+ } else if (cmd.type === "close") {
1026
+ const payload = {
1027
+ socketId: cmd.socketId,
1028
+ code: cmd.code,
1029
+ reason: cmd.reason
1030
+ };
1031
+ sendMessage(targetConnection.socket, {
1032
+ type: MessageType.ISOLATE_EVENT,
1033
+ isolateId,
1034
+ event: IsolateEvents.WS_CLIENT_CLOSE,
1035
+ payload
1036
+ });
1037
+ }
1038
+ });
1039
+ runtime.fetch.onEvent((eventName, payload) => {
1040
+ const targetConnection = callbackContext.connection;
1041
+ if (!targetConnection) {
1042
+ return;
1043
+ }
1044
+ sendMessage(targetConnection.socket, {
1045
+ type: MessageType.ISOLATE_EVENT,
1046
+ isolateId,
1047
+ event: eventName,
1048
+ payload
1049
+ });
1050
+ });
1051
+ sendOk(connection.socket, message.requestId, { isolateId, reused: false });
1052
+ logRuntimeLifecycle(state, "created", instance);
1053
+ } catch (err) {
1054
+ const error = err;
1055
+ sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1056
+ } finally {
1057
+ if (namespaceCreationLocked && namespaceId != null) {
1058
+ state.namespacedCreatesInFlight.delete(namespaceId);
1059
+ }
1060
+ }
1061
+ }
1062
+ async function handleDisposeRuntime(message, connection, state) {
1063
+ const instance = state.isolates.get(message.isolateId);
1064
+ if (!instance) {
1065
+ sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1066
+ return;
1067
+ }
1068
+ if (instance.ownerConnection !== connection.socket) {
1069
+ sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not owned by this connection`);
1070
+ return;
1071
+ }
1072
+ try {
1073
+ connection.isolates.delete(message.isolateId);
1074
+ const requestReason = typeof message.reason === "string" && message.reason.length > 0 ? message.reason : message.hard ? "client requested hard dispose" : undefined;
1075
+ if (instance.namespaceId != null) {
1076
+ if (message.hard || instance.isPoisoned) {
1077
+ await hardDeleteRuntime(instance, state, requestReason);
1078
+ } else {
1079
+ softDeleteRuntime(instance, state, requestReason);
1080
+ }
1081
+ } else {
1082
+ await hardDeleteRuntime(instance, state, requestReason);
1083
+ }
1084
+ sendOk(connection.socket, message.requestId);
1085
+ } catch (err) {
1086
+ const error = err;
1087
+ if (instance.namespaceId != null && isLinkerConflictError(error)) {
1088
+ instance.isPoisoned = true;
1089
+ }
1090
+ sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1091
+ }
1092
+ }
1093
+ async function handleEval(message, connection, state) {
1094
+ const instance = state.isolates.get(message.isolateId);
1095
+ if (!instance) {
1096
+ sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1097
+ return;
1098
+ }
1099
+ instance.lastActivity = Date.now();
1100
+ try {
1101
+ await instance.runtime.eval(message.code, {
1102
+ filename: message.filename,
1103
+ executionTimeout: message.executionTimeout
1104
+ });
1105
+ sendOk(connection.socket, message.requestId, { value: undefined });
1106
+ } catch (err) {
1107
+ const error = err;
1108
+ if (isRuntimeTimeoutError(error)) {
1109
+ instance.isPoisoned = true;
1110
+ } else if (instance.namespaceId != null && isLinkerConflictError(error)) {
1111
+ instance.isPoisoned = true;
1112
+ }
1113
+ sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1114
+ }
1115
+ }
1116
+ async function handleDispatchRequest(message, connection, state) {
1117
+ const instance = state.isolates.get(message.isolateId);
1118
+ if (!instance) {
1119
+ sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1120
+ return;
1121
+ }
1122
+ instance.lastActivity = Date.now();
1123
+ const dispatchAbortController = new AbortController;
1124
+ connection.dispatchAbortControllers.set(message.requestId, dispatchAbortController);
1125
+ if (connection.earlyAbortedDispatches.has(message.requestId) || message.request.signalAborted) {
1126
+ dispatchAbortController.abort();
1127
+ connection.earlyAbortedDispatches.delete(message.requestId);
1128
+ }
1129
+ await requestContextStorage.run({
1130
+ ...message.context ?? {},
1131
+ signal: dispatchAbortController.signal
1132
+ }, async () => {
1133
+ try {
1134
+ let requestBody = null;
1135
+ if (message.request.bodyStreamId !== undefined) {
1136
+ requestBody = await receiveStreamedBody(connection, message.request.bodyStreamId);
1137
+ } else if (message.request.body) {
1138
+ requestBody = message.request.body;
1139
+ }
1140
+ const request = new Request(message.request.url, {
1141
+ method: message.request.method,
1142
+ headers: message.request.headers,
1143
+ body: requestBody,
1144
+ signal: dispatchAbortController.signal
1145
+ });
1146
+ const response = await instance.runtime.fetch.dispatchRequest(request, {
1147
+ signal: dispatchAbortController.signal
1148
+ });
1149
+ if (response.body) {
1150
+ await sendStreamedResponse(connection, message.requestId, response);
1151
+ } else {
1152
+ const headers = [];
1153
+ response.headers.forEach((value, key) => {
1154
+ headers.push([key, value]);
1155
+ });
1156
+ sendOk(connection.socket, message.requestId, {
1157
+ response: {
1158
+ status: response.status,
1159
+ statusText: response.statusText,
1160
+ headers,
1161
+ body: null
1162
+ }
1163
+ });
1164
+ }
1165
+ } catch (err) {
1166
+ const error = err;
1167
+ sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1168
+ } finally {
1169
+ connection.dispatchAbortControllers.delete(message.requestId);
1170
+ connection.earlyAbortedDispatches.delete(message.requestId);
1171
+ }
1172
+ });
1173
+ }
1174
+ function handleDispatchRequestAbort(message, connection) {
1175
+ const controller = connection.dispatchAbortControllers.get(message.targetRequestId);
1176
+ if (controller) {
1177
+ controller.abort();
1178
+ return;
1179
+ }
1180
+ connection.earlyAbortedDispatches.add(message.targetRequestId);
1181
+ }
1182
+ function receiveStreamedBody(connection, streamId) {
1183
+ return new Promise((resolve, reject) => {
1184
+ const receiver = {
1185
+ streamId,
1186
+ requestId: 0,
1187
+ chunks: [],
1188
+ totalBytes: 0,
1189
+ resolve,
1190
+ reject
1191
+ };
1192
+ connection.streamReceivers.set(streamId, receiver);
1193
+ sendMessage(connection.socket, {
1194
+ type: MessageType.STREAM_PULL,
1195
+ streamId,
1196
+ maxBytes: STREAM_DEFAULT_CREDIT
1197
+ });
1198
+ });
1199
+ }
1200
+ async function handleWsOpen(message, connection, state) {
1201
+ const instance = state.isolates.get(message.isolateId);
1202
+ if (!instance) {
1203
+ sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1204
+ return;
1205
+ }
1206
+ instance.lastActivity = Date.now();
1207
+ try {
1208
+ instance.runtime.fetch.dispatchWebSocketOpen(message.connectionId);
1209
+ sendOk(connection.socket, message.requestId);
1210
+ } catch (err) {
1211
+ const error = err;
1212
+ sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1213
+ }
1214
+ }
1215
+ async function handleWsMessage(message, connection, state) {
1216
+ const instance = state.isolates.get(message.isolateId);
1217
+ if (!instance) {
1218
+ sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1219
+ return;
1220
+ }
1221
+ instance.lastActivity = Date.now();
1222
+ try {
1223
+ const data = message.data instanceof Uint8Array ? message.data.buffer.slice(message.data.byteOffset, message.data.byteOffset + message.data.byteLength) : message.data;
1224
+ instance.runtime.fetch.dispatchWebSocketMessage(message.connectionId, data);
1225
+ sendOk(connection.socket, message.requestId);
1226
+ } catch (err) {
1227
+ const error = err;
1228
+ sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1229
+ }
1230
+ }
1231
+ async function handleWsClose(message, connection, state) {
1232
+ const instance = state.isolates.get(message.isolateId);
1233
+ if (!instance) {
1234
+ sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1235
+ return;
1236
+ }
1237
+ instance.lastActivity = Date.now();
1238
+ try {
1239
+ instance.runtime.fetch.dispatchWebSocketClose(message.connectionId, message.code, message.reason);
1240
+ sendOk(connection.socket, message.requestId);
1241
+ } catch (err) {
1242
+ const error = err;
1243
+ sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1244
+ }
1245
+ }
1246
+ function handleClientEvent(message, connection, state) {
1247
+ const instance = state.isolates.get(message.isolateId);
1248
+ if (!instance)
1249
+ return;
1250
+ instance.lastActivity = Date.now();
1251
+ switch (message.event) {
1252
+ case ClientEvents.WS_CLIENT_OPENED: {
1253
+ const payload = message.payload;
1254
+ instance.runtime.fetch.dispatchClientWebSocketOpen(payload.socketId, payload.protocol, payload.extensions);
1255
+ break;
1256
+ }
1257
+ case ClientEvents.WS_CLIENT_MESSAGE: {
1258
+ const payload = message.payload;
1259
+ const data = payload.data instanceof Uint8Array ? payload.data.buffer.slice(payload.data.byteOffset, payload.data.byteOffset + payload.data.byteLength) : payload.data;
1260
+ instance.runtime.fetch.dispatchClientWebSocketMessage(payload.socketId, data);
1261
+ break;
1262
+ }
1263
+ case ClientEvents.WS_CLIENT_CLOSED: {
1264
+ const payload = message.payload;
1265
+ instance.runtime.fetch.dispatchClientWebSocketClose(payload.socketId, payload.code, payload.reason, payload.wasClean);
1266
+ break;
1267
+ }
1268
+ case ClientEvents.WS_CLIENT_ERROR: {
1269
+ const payload = message.payload;
1270
+ instance.runtime.fetch.dispatchClientWebSocketError(payload.socketId);
1271
+ break;
1272
+ }
1273
+ default: {
1274
+ instance.runtime.fetch.dispatchEvent(message.event, message.payload);
1275
+ break;
1276
+ }
1277
+ }
1278
+ }
1279
+ async function handleFetchGetUpgradeRequest(message, connection, state) {
1280
+ const instance = state.isolates.get(message.isolateId);
1281
+ if (!instance) {
1282
+ sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1283
+ return;
1284
+ }
1285
+ instance.lastActivity = Date.now();
1286
+ try {
1287
+ const upgradeRequest = instance.runtime.fetch.getUpgradeRequest();
1288
+ sendOk(connection.socket, message.requestId, upgradeRequest);
1289
+ } catch (err) {
1290
+ const error = err;
1291
+ sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1292
+ }
1293
+ }
1294
+ async function handleFetchHasServeHandler(message, connection, state) {
1295
+ const instance = state.isolates.get(message.isolateId);
1296
+ if (!instance) {
1297
+ sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1298
+ return;
1299
+ }
1300
+ instance.lastActivity = Date.now();
1301
+ try {
1302
+ const hasHandler = instance.runtime.fetch.hasServeHandler();
1303
+ sendOk(connection.socket, message.requestId, hasHandler);
1304
+ } catch (err) {
1305
+ const error = err;
1306
+ sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1307
+ }
1308
+ }
1309
+ async function handleFetchHasActiveConnections(message, connection, state) {
1310
+ const instance = state.isolates.get(message.isolateId);
1311
+ if (!instance) {
1312
+ sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1313
+ return;
1314
+ }
1315
+ instance.lastActivity = Date.now();
1316
+ try {
1317
+ const hasConnections = instance.runtime.fetch.hasActiveConnections();
1318
+ sendOk(connection.socket, message.requestId, hasConnections);
1319
+ } catch (err) {
1320
+ const error = err;
1321
+ sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1322
+ }
1323
+ }
1324
+ async function handleFetchWsError(message, connection, state) {
1325
+ const instance = state.isolates.get(message.isolateId);
1326
+ if (!instance) {
1327
+ sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1328
+ return;
1329
+ }
1330
+ instance.lastActivity = Date.now();
1331
+ try {
1332
+ instance.runtime.fetch.dispatchWebSocketError(message.connectionId, new Error(message.error));
1333
+ sendOk(connection.socket, message.requestId);
1334
+ } catch (err) {
1335
+ const error = err;
1336
+ sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1337
+ }
1338
+ }
1339
+ async function handleTimersClearAll(message, connection, state) {
1340
+ const instance = state.isolates.get(message.isolateId);
1341
+ if (!instance) {
1342
+ sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1343
+ return;
1344
+ }
1345
+ instance.lastActivity = Date.now();
1346
+ try {
1347
+ instance.runtime.timers.clearAll();
1348
+ sendOk(connection.socket, message.requestId);
1349
+ } catch (err) {
1350
+ const error = err;
1351
+ sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1352
+ }
1353
+ }
1354
+ async function handleConsoleReset(message, connection, state) {
1355
+ const instance = state.isolates.get(message.isolateId);
1356
+ if (!instance) {
1357
+ sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1358
+ return;
1359
+ }
1360
+ instance.lastActivity = Date.now();
1361
+ try {
1362
+ instance.runtime.console.reset();
1363
+ sendOk(connection.socket, message.requestId);
1364
+ } catch (err) {
1365
+ const error = err;
1366
+ sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1367
+ }
1368
+ }
1369
+ async function handleConsoleGetTimers(message, connection, state) {
1370
+ const instance = state.isolates.get(message.isolateId);
1371
+ if (!instance) {
1372
+ sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1373
+ return;
1374
+ }
1375
+ instance.lastActivity = Date.now();
1376
+ try {
1377
+ const timers = instance.runtime.console.getTimers();
1378
+ sendOk(connection.socket, message.requestId, Object.fromEntries(timers));
1379
+ } catch (err) {
1380
+ const error = err;
1381
+ sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1382
+ }
1383
+ }
1384
+ async function handleConsoleGetCounters(message, connection, state) {
1385
+ const instance = state.isolates.get(message.isolateId);
1386
+ if (!instance) {
1387
+ sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1388
+ return;
1389
+ }
1390
+ instance.lastActivity = Date.now();
1391
+ try {
1392
+ const counters = instance.runtime.console.getCounters();
1393
+ sendOk(connection.socket, message.requestId, Object.fromEntries(counters));
1394
+ } catch (err) {
1395
+ const error = err;
1396
+ sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1397
+ }
1398
+ }
1399
+ async function handleConsoleGetGroupDepth(message, connection, state) {
1400
+ const instance = state.isolates.get(message.isolateId);
1401
+ if (!instance) {
1402
+ sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1403
+ return;
1404
+ }
1405
+ instance.lastActivity = Date.now();
1406
+ try {
1407
+ const depth = instance.runtime.console.getGroupDepth();
1408
+ sendOk(connection.socket, message.requestId, depth);
1409
+ } catch (err) {
1410
+ const error = err;
1411
+ sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1412
+ }
1413
+ }
1414
+ function handleCallbackResponse(message, connection) {
1415
+ const pending = connection.pendingCallbacks.get(message.requestId);
1416
+ if (!pending) {
1417
+ console.warn(`No pending callback for requestId: ${message.requestId}`);
1418
+ return;
1419
+ }
1420
+ connection.pendingCallbacks.delete(message.requestId);
1421
+ pending.cleanup?.();
1422
+ if (message.error) {
1423
+ const error = new Error(message.error.message);
1424
+ error.name = message.error.name;
1425
+ if (message.error.stack) {
1426
+ error.stack = message.error.stack;
1427
+ }
1428
+ pending.reject(error);
1429
+ } else {
1430
+ pending.resolve(message.result);
1431
+ }
1432
+ }
1433
+ async function invokeClientCallback(connection, callbackId, args, options) {
1434
+ const requestId = connection.nextCallbackId++;
1435
+ const timeoutMs = options?.timeoutMs ?? DEFAULT_CALLBACK_TIMEOUT_MS;
1436
+ return new Promise((resolve, reject) => {
1437
+ let settled = false;
1438
+ let timeoutId;
1439
+ let onAbort;
1440
+ let callbackInvokeSent = false;
1441
+ const settle = (handler, value) => {
1442
+ if (settled)
1443
+ return;
1444
+ settled = true;
1445
+ connection.pendingCallbacks.delete(requestId);
1446
+ if (timeoutId) {
1447
+ clearTimeout(timeoutId);
1448
+ timeoutId = undefined;
1449
+ }
1450
+ if (options?.signal && onAbort) {
1451
+ options.signal.removeEventListener("abort", onAbort);
1452
+ }
1453
+ handler(value);
1454
+ };
1455
+ onAbort = () => {
1456
+ if (settled)
1457
+ return;
1458
+ if (callbackInvokeSent) {
1459
+ sendCallbackAbortMessage(connection, requestId, options?.timeoutLabel ? `${options.timeoutLabel} aborted` : "Callback aborted");
1460
+ }
1461
+ settle(reject, createAbortError());
1462
+ };
1463
+ if (options?.signal) {
1464
+ if (options.signal.aborted) {
1465
+ onAbort();
1466
+ return;
1467
+ }
1468
+ options.signal.addEventListener("abort", onAbort, { once: true });
1469
+ }
1470
+ if (timeoutMs > 0) {
1471
+ timeoutId = setTimeout(() => {
1472
+ if (settled)
1473
+ return;
1474
+ const label = options?.timeoutLabel ?? "callback";
1475
+ const timeoutError = new Error(`${label} timed out after ${timeoutMs}ms`);
1476
+ if (callbackInvokeSent) {
1477
+ sendCallbackAbortMessage(connection, requestId, timeoutError.message);
1478
+ }
1479
+ settle(reject, timeoutError);
1480
+ }, timeoutMs);
1481
+ }
1482
+ const pending = {
1483
+ callbackId,
1484
+ cleanup: () => {
1485
+ if (timeoutId) {
1486
+ clearTimeout(timeoutId);
1487
+ timeoutId = undefined;
1488
+ }
1489
+ if (options?.signal && onAbort) {
1490
+ options.signal.removeEventListener("abort", onAbort);
1491
+ }
1492
+ },
1493
+ resolve: (result) => settle(resolve, result),
1494
+ reject: (error) => settle(reject, error)
1495
+ };
1496
+ connection.pendingCallbacks.set(requestId, pending);
1497
+ const requestContext = requestContextStorage.getStore();
1498
+ const invoke = {
1499
+ type: MessageType.CALLBACK_INVOKE,
1500
+ requestId,
1501
+ callbackId,
1502
+ args,
1503
+ context: requestContext ? {
1504
+ requestId: requestContext.requestId,
1505
+ metadata: requestContext.metadata
1506
+ } : undefined
1507
+ };
1508
+ sendMessage(connection.socket, invoke);
1509
+ callbackInvokeSent = true;
1510
+ });
1511
+ }
1512
+ function handleStreamPush(message, connection) {
1513
+ const receiver = connection.streamReceivers.get(message.streamId);
1514
+ if (!receiver) {
1515
+ sendMessage(connection.socket, {
1516
+ type: MessageType.STREAM_ERROR,
1517
+ streamId: message.streamId,
1518
+ error: "Stream not found"
1519
+ });
1520
+ return;
1521
+ }
1522
+ receiver.chunks.push(message.chunk);
1523
+ receiver.totalBytes += message.chunk.length;
1524
+ sendMessage(connection.socket, {
1525
+ type: MessageType.STREAM_PULL,
1526
+ streamId: message.streamId,
1527
+ maxBytes: STREAM_DEFAULT_CREDIT
1528
+ });
1529
+ }
1530
+ function handleStreamPull(message, connection) {
1531
+ const session = connection.activeStreams.get(message.streamId);
1532
+ if (!session) {
1533
+ return;
1534
+ }
1535
+ session.credit += message.maxBytes;
1536
+ if (session.creditResolver) {
1537
+ session.creditResolver();
1538
+ session.creditResolver = undefined;
1539
+ }
1540
+ }
1541
+ function handleStreamClose(message, connection) {
1542
+ const receiver = connection.streamReceivers.get(message.streamId);
1543
+ if (!receiver) {
1544
+ return;
1545
+ }
1546
+ const totalLength = receiver.chunks.reduce((sum, chunk) => sum + chunk.length, 0);
1547
+ const body = new Uint8Array(totalLength);
1548
+ let offset = 0;
1549
+ for (const chunk of receiver.chunks) {
1550
+ body.set(chunk, offset);
1551
+ offset += chunk.length;
1552
+ }
1553
+ receiver.resolve(body);
1554
+ connection.streamReceivers.delete(message.streamId);
1555
+ }
1556
+ function handleStreamError(message, connection) {
1557
+ const receiver = connection.streamReceivers.get(message.streamId);
1558
+ if (receiver) {
1559
+ receiver.reject(new Error(message.error));
1560
+ connection.streamReceivers.delete(message.streamId);
1561
+ }
1562
+ const session = connection.activeStreams.get(message.streamId);
1563
+ if (session) {
1564
+ closeActiveDownloadSession(connection, message.streamId);
1565
+ }
1566
+ const callbackReceiver = connection.callbackStreamReceivers.get(message.streamId);
1567
+ if (callbackReceiver && callbackReceiver.state === "active") {
1568
+ callbackReceiver.state = "errored";
1569
+ callbackReceiver.error = new Error(message.error);
1570
+ const resolvers = callbackReceiver.pullResolvers.splice(0);
1571
+ for (const resolver of resolvers) {
1572
+ resolver();
1573
+ }
1574
+ connection.callbackStreamReceivers.delete(message.streamId);
1575
+ }
1576
+ }
1577
+ function handleCallbackStreamStart(message, connection) {
1578
+ const receiver = {
1579
+ streamId: message.streamId,
1580
+ requestId: message.requestId,
1581
+ metadata: message.metadata,
1582
+ controller: null,
1583
+ state: "active",
1584
+ pendingChunks: [],
1585
+ pullResolvers: [],
1586
+ controllerFinalized: false
1587
+ };
1588
+ const readableStream = new ReadableStream({
1589
+ start(controller) {
1590
+ receiver.controller = controller;
1591
+ },
1592
+ pull(_controller) {
1593
+ if (receiver.controllerFinalized) {
1594
+ return;
1595
+ }
1596
+ if (receiver.pendingChunks.length > 0) {
1597
+ const chunk = receiver.pendingChunks.shift();
1598
+ receiver.controller.enqueue(chunk);
1599
+ return Promise.resolve();
1600
+ }
1601
+ if (receiver.state === "closed") {
1602
+ if (!receiver.controllerFinalized) {
1603
+ receiver.controllerFinalized = true;
1604
+ receiver.controller.close();
1605
+ }
1606
+ return Promise.resolve();
1607
+ }
1608
+ if (receiver.state === "errored") {
1609
+ if (!receiver.controllerFinalized && receiver.error) {
1610
+ receiver.controllerFinalized = true;
1611
+ receiver.controller.error(receiver.error);
1612
+ }
1613
+ return Promise.resolve();
1614
+ }
1615
+ return new Promise((resolve) => {
1616
+ receiver.pullResolvers.push(resolve);
1617
+ });
1618
+ },
1619
+ cancel(_reason) {
1620
+ receiver.state = "closed";
1621
+ receiver.controllerFinalized = true;
1622
+ const resolvers = receiver.pullResolvers.splice(0);
1623
+ for (const resolver of resolvers) {
1624
+ resolver();
1625
+ }
1626
+ connection.callbackStreamReceivers.delete(message.streamId);
1627
+ sendMessage(connection.socket, {
1628
+ type: MessageType.CALLBACK_STREAM_CANCEL,
1629
+ streamId: message.streamId
1630
+ });
1631
+ return Promise.resolve();
1632
+ }
1633
+ });
1634
+ const cancelStream = () => {
1635
+ connection.callbackStreamReceivers.delete(message.streamId);
1636
+ sendMessage(connection.socket, {
1637
+ type: MessageType.CALLBACK_STREAM_CANCEL,
1638
+ streamId: message.streamId
1639
+ });
1640
+ };
1641
+ connection.callbackStreamReceivers.set(message.streamId, receiver);
1642
+ const pending = connection.pendingCallbacks.get(message.requestId);
1643
+ if (!pending) {
1644
+ cancelStream();
1645
+ return;
1646
+ }
1647
+ try {
1648
+ const body = NULL_BODY_STATUSES.has(message.metadata.status) ? null : readableStream;
1649
+ const response = new Response(body, {
1650
+ status: message.metadata.status,
1651
+ statusText: message.metadata.statusText,
1652
+ headers: message.metadata.headers
1653
+ });
1654
+ connection.pendingCallbacks.delete(message.requestId);
1655
+ pending.resolve({ __streamingResponse: true, response });
1656
+ if (body === null) {
1657
+ cancelStream();
1658
+ }
1659
+ } catch (err) {
1660
+ connection.pendingCallbacks.delete(message.requestId);
1661
+ cancelStream();
1662
+ const error = err instanceof Error ? err : new Error(String(err));
1663
+ pending.reject(error);
1664
+ }
1665
+ }
1666
+ function handleCallbackStreamChunk(message, connection) {
1667
+ const receiver = connection.callbackStreamReceivers.get(message.streamId);
1668
+ if (receiver && receiver.state === "active") {
1669
+ if (receiver.pullResolvers.length > 0) {
1670
+ receiver.controller.enqueue(message.chunk);
1671
+ const resolver = receiver.pullResolvers.shift();
1672
+ resolver();
1673
+ } else {
1674
+ receiver.pendingChunks.push(message.chunk);
1675
+ }
1676
+ }
1677
+ }
1678
+ function handleCallbackStreamEnd(message, connection) {
1679
+ const receiver = connection.callbackStreamReceivers.get(message.streamId);
1680
+ if (receiver) {
1681
+ receiver.state = "closed";
1682
+ while (receiver.pendingChunks.length > 0) {
1683
+ const chunk = receiver.pendingChunks.shift();
1684
+ receiver.controller.enqueue(chunk);
1685
+ }
1686
+ if (!receiver.controllerFinalized) {
1687
+ receiver.controllerFinalized = true;
1688
+ receiver.controller.close();
1689
+ }
1690
+ const resolvers = receiver.pullResolvers.splice(0);
1691
+ for (const resolver of resolvers) {
1692
+ resolver();
1693
+ }
1694
+ connection.callbackStreamReceivers.delete(message.streamId);
1695
+ }
1696
+ }
1697
+ function waitForCredit(session) {
1698
+ return new Promise((resolve) => {
1699
+ session.creditResolver = resolve;
1700
+ });
1701
+ }
1702
+ async function sendStreamedResponse(connection, requestId, response) {
1703
+ const SEND_LOOP_YIELD_BYTES = 64 * 1024;
1704
+ const streamId = connection.nextStreamId++;
1705
+ const headers = [];
1706
+ response.headers.forEach((value, key) => {
1707
+ headers.push([key, value]);
1708
+ });
1709
+ const startMsg = {
1710
+ type: MessageType.RESPONSE_STREAM_START,
1711
+ requestId,
1712
+ streamId,
1713
+ metadata: {
1714
+ status: response.status,
1715
+ statusText: response.statusText,
1716
+ headers
1717
+ }
1718
+ };
1719
+ sendMessage(connection.socket, startMsg);
1720
+ if (!response.body) {
1721
+ const endMsg = {
1722
+ type: MessageType.RESPONSE_STREAM_END,
1723
+ requestId,
1724
+ streamId
1725
+ };
1726
+ sendMessage(connection.socket, endMsg);
1727
+ return;
1728
+ }
1729
+ const session = {
1730
+ streamId,
1731
+ direction: "download",
1732
+ requestId,
1733
+ state: "active",
1734
+ bytesTransferred: 0,
1735
+ credit: STREAM_DEFAULT_CREDIT
1736
+ };
1737
+ connection.activeStreams.set(streamId, session);
1738
+ const reader = response.body.getReader();
1739
+ session.cancelReader = () => {
1740
+ reader.cancel("Stream cancelled by client").catch(() => {});
1741
+ };
1742
+ let cancelledByClient = false;
1743
+ let bytesSinceYield = 0;
1744
+ let chunksSinceYield = 0;
1745
+ try {
1746
+ streamLoop:
1747
+ while (true) {
1748
+ while (session.credit < STREAM_CHUNK_SIZE && session.state === "active") {
1749
+ await waitForCredit(session);
1750
+ }
1751
+ if (session.state !== "active") {
1752
+ cancelledByClient = true;
1753
+ break;
1754
+ }
1755
+ const { done, value } = await reader.read();
1756
+ if (done) {
1757
+ const endMsg = {
1758
+ type: MessageType.RESPONSE_STREAM_END,
1759
+ requestId,
1760
+ streamId
1761
+ };
1762
+ sendMessage(connection.socket, endMsg);
1763
+ break;
1764
+ }
1765
+ for (let offset = 0;offset < value.length; offset += STREAM_CHUNK_SIZE) {
1766
+ const chunk = value.slice(offset, offset + STREAM_CHUNK_SIZE);
1767
+ const chunkMsg = {
1768
+ type: MessageType.RESPONSE_STREAM_CHUNK,
1769
+ requestId,
1770
+ streamId,
1771
+ chunk
1772
+ };
1773
+ sendMessage(connection.socket, chunkMsg);
1774
+ const creditCost = Math.max(chunk.length, STREAM_CHUNK_SIZE);
1775
+ session.credit -= creditCost;
1776
+ session.bytesTransferred += chunk.length;
1777
+ bytesSinceYield += chunk.length;
1778
+ chunksSinceYield += 1;
1779
+ if (chunk.length < 1024 || bytesSinceYield >= SEND_LOOP_YIELD_BYTES || chunksSinceYield >= 256) {
1780
+ bytesSinceYield = 0;
1781
+ chunksSinceYield = 0;
1782
+ await new Promise((resolve) => setImmediate(resolve));
1783
+ if (session.state !== "active") {
1784
+ cancelledByClient = true;
1785
+ break streamLoop;
1786
+ }
1787
+ }
1788
+ }
1789
+ }
1790
+ } catch (err) {
1791
+ if (cancelledByClient || session.state !== "active") {
1792
+ return;
1793
+ }
1794
+ const errorMsg = {
1795
+ type: MessageType.STREAM_ERROR,
1796
+ streamId,
1797
+ error: err.message
1798
+ };
1799
+ sendMessage(connection.socket, errorMsg);
1800
+ } finally {
1801
+ if (cancelledByClient) {
1802
+ await Promise.race([
1803
+ reader.cancel("Stream cancelled by client").catch(() => {}),
1804
+ new Promise((resolve) => setTimeout(resolve, 50))
1805
+ ]);
1806
+ }
1807
+ session.cancelReader = undefined;
1808
+ reader.releaseLock();
1809
+ closeActiveDownloadSession(connection, streamId);
1810
+ }
1811
+ }
1812
+ async function handleRunTests(message, connection, state) {
1813
+ const instance = state.isolates.get(message.isolateId);
1814
+ if (!instance) {
1815
+ sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1816
+ return;
1817
+ }
1818
+ instance.lastActivity = Date.now();
1819
+ if (instance.pendingTestRun) {
1820
+ try {
1821
+ const results = await instance.pendingTestRun.promise;
1822
+ const currentConn = instance.callbackContext?.connection;
1823
+ if (currentConn) {
1824
+ sendOk(currentConn.socket, message.requestId, results);
1825
+ }
1826
+ } catch (err) {
1827
+ const error = err;
1828
+ const currentConn = instance.callbackContext?.connection;
1829
+ if (currentConn) {
1830
+ sendError(currentConn.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1831
+ }
1832
+ }
1833
+ return;
1834
+ }
1835
+ try {
1836
+ const runPromise = instance.runtime.testEnvironment.runTests(message.timeout);
1837
+ instance.pendingTestRun = { promise: runPromise };
1838
+ const results = await runPromise;
1839
+ instance.pendingTestRun = undefined;
1840
+ const currentConn = instance.callbackContext?.connection ?? connection;
1841
+ sendOk(currentConn.socket, message.requestId, results);
1842
+ } catch (err) {
1843
+ instance.pendingTestRun = undefined;
1844
+ const error = err;
1845
+ if (isRuntimeTimeoutError(error)) {
1846
+ instance.isPoisoned = true;
1847
+ }
1848
+ const currentConn = instance.callbackContext?.connection ?? connection;
1849
+ sendError(currentConn.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1850
+ }
1851
+ }
1852
+ async function handleResetTestEnv(message, connection, state) {
1853
+ const instance = state.isolates.get(message.isolateId);
1854
+ if (!instance) {
1855
+ sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1856
+ return;
1857
+ }
1858
+ instance.lastActivity = Date.now();
1859
+ try {
1860
+ instance.runtime.testEnvironment.reset();
1861
+ sendOk(connection.socket, message.requestId);
1862
+ } catch (err) {
1863
+ const error = err;
1864
+ sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1865
+ }
1866
+ }
1867
+ async function handleHasTests(message, connection, state) {
1868
+ const instance = state.isolates.get(message.isolateId);
1869
+ if (!instance) {
1870
+ sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1871
+ return;
1872
+ }
1873
+ instance.lastActivity = Date.now();
1874
+ try {
1875
+ const result = instance.runtime.testEnvironment.hasTests();
1876
+ sendOk(connection.socket, message.requestId, result);
1877
+ } catch (err) {
1878
+ const error = err;
1879
+ sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1880
+ }
1881
+ }
1882
+ async function handleGetTestCount(message, connection, state) {
1883
+ const instance = state.isolates.get(message.isolateId);
1884
+ if (!instance) {
1885
+ sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1886
+ return;
1887
+ }
1888
+ instance.lastActivity = Date.now();
1889
+ try {
1890
+ const result = instance.runtime.testEnvironment.getTestCount();
1891
+ sendOk(connection.socket, message.requestId, result);
1892
+ } catch (err) {
1893
+ const error = err;
1894
+ sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1895
+ }
1896
+ }
1897
+ async function handleGetCollectedData(message, connection, state) {
1898
+ const instance = state.isolates.get(message.isolateId);
1899
+ if (!instance) {
1900
+ sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1901
+ return;
1902
+ }
1903
+ instance.lastActivity = Date.now();
1904
+ try {
1905
+ const data = instance.runtime.playwright.getCollectedData();
1906
+ sendOk(connection.socket, message.requestId, data);
1907
+ } catch (err) {
1908
+ const error = err;
1909
+ sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1910
+ }
1911
+ }
1912
+ async function handleClearCollectedData(message, connection, state) {
1913
+ const instance = state.isolates.get(message.isolateId);
1914
+ if (!instance) {
1915
+ sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1916
+ return;
1917
+ }
1918
+ instance.lastActivity = Date.now();
1919
+ try {
1920
+ instance.runtime.playwright.clearCollectedData();
1921
+ sendOk(connection.socket, message.requestId);
1922
+ } catch (err) {
1923
+ const error = err;
1924
+ sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1925
+ }
1926
+ }
1927
+ export {
1928
+ handleConnection
1929
+ };
1930
+
1931
+ //# debugId=821596E06E80F8D064756E2164756E21