@gadgetinc/substrate 0.1.0-rc.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 (181) hide show
  1. package/dist/assets/kernel.wasm +0 -0
  2. package/dist/assets/manifest.json +32 -0
  3. package/dist/assets/network-driver.js +2 -0
  4. package/dist/assets/network-driver.js.map +1 -0
  5. package/dist/assets/runtime.js +264 -0
  6. package/dist/assets/runtime.js.map +1 -0
  7. package/dist/binaries.d.ts +58 -0
  8. package/dist/binaries.d.ts.map +1 -0
  9. package/dist/boot/index.d.ts +318 -0
  10. package/dist/boot/index.d.ts.map +1 -0
  11. package/dist/index.d.ts +8 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +4589 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/kernel/bridge.d.ts +64 -0
  16. package/dist/kernel/bridge.d.ts.map +1 -0
  17. package/dist/kernel/types.d.ts +518 -0
  18. package/dist/kernel/types.d.ts.map +1 -0
  19. package/dist/kernel/wasm.d.ts +20 -0
  20. package/dist/kernel/wasm.d.ts.map +1 -0
  21. package/dist/node/assert.d.ts +99 -0
  22. package/dist/node/assert.d.ts.map +1 -0
  23. package/dist/node/async_hooks.d.ts +88 -0
  24. package/dist/node/async_hooks.d.ts.map +1 -0
  25. package/dist/node/buffer.d.ts +62 -0
  26. package/dist/node/buffer.d.ts.map +1 -0
  27. package/dist/node/child_process.d.ts +300 -0
  28. package/dist/node/child_process.d.ts.map +1 -0
  29. package/dist/node/cluster.d.ts +37 -0
  30. package/dist/node/cluster.d.ts.map +1 -0
  31. package/dist/node/constants.d.ts +306 -0
  32. package/dist/node/constants.d.ts.map +1 -0
  33. package/dist/node/crypto.d.ts +176 -0
  34. package/dist/node/crypto.d.ts.map +1 -0
  35. package/dist/node/dgram.d.ts +44 -0
  36. package/dist/node/dgram.d.ts.map +1 -0
  37. package/dist/node/diagnostics_channel.d.ts +57 -0
  38. package/dist/node/diagnostics_channel.d.ts.map +1 -0
  39. package/dist/node/dns.d.ts +278 -0
  40. package/dist/node/dns.d.ts.map +1 -0
  41. package/dist/node/domain.d.ts +21 -0
  42. package/dist/node/domain.d.ts.map +1 -0
  43. package/dist/node/events.d.ts +54 -0
  44. package/dist/node/events.d.ts.map +1 -0
  45. package/dist/node/fs/promises.d.ts +116 -0
  46. package/dist/node/fs/promises.d.ts.map +1 -0
  47. package/dist/node/fs.d.ts +536 -0
  48. package/dist/node/fs.d.ts.map +1 -0
  49. package/dist/node/http.d.ts +471 -0
  50. package/dist/node/http.d.ts.map +1 -0
  51. package/dist/node/http2.d.ts +508 -0
  52. package/dist/node/http2.d.ts.map +1 -0
  53. package/dist/node/https.d.ts +42 -0
  54. package/dist/node/https.d.ts.map +1 -0
  55. package/dist/node/inspector.d.ts +25 -0
  56. package/dist/node/inspector.d.ts.map +1 -0
  57. package/dist/node/net.d.ts +231 -0
  58. package/dist/node/net.d.ts.map +1 -0
  59. package/dist/node/os.d.ts +318 -0
  60. package/dist/node/os.d.ts.map +1 -0
  61. package/dist/node/path.d.ts +144 -0
  62. package/dist/node/path.d.ts.map +1 -0
  63. package/dist/node/process.d.ts +105 -0
  64. package/dist/node/process.d.ts.map +1 -0
  65. package/dist/node/punycode.d.ts +34 -0
  66. package/dist/node/punycode.d.ts.map +1 -0
  67. package/dist/node/querystring.d.ts +49 -0
  68. package/dist/node/querystring.d.ts.map +1 -0
  69. package/dist/node/readline.d.ts +99 -0
  70. package/dist/node/readline.d.ts.map +1 -0
  71. package/dist/node/stream.d.ts +409 -0
  72. package/dist/node/stream.d.ts.map +1 -0
  73. package/dist/node/string_decoder.d.ts +46 -0
  74. package/dist/node/string_decoder.d.ts.map +1 -0
  75. package/dist/node/timers.d.ts +79 -0
  76. package/dist/node/timers.d.ts.map +1 -0
  77. package/dist/node/tls.d.ts +159 -0
  78. package/dist/node/tls.d.ts.map +1 -0
  79. package/dist/node/trace_events.d.ts +18 -0
  80. package/dist/node/trace_events.d.ts.map +1 -0
  81. package/dist/node/tty.d.ts +67 -0
  82. package/dist/node/tty.d.ts.map +1 -0
  83. package/dist/node/url.d.ts +85 -0
  84. package/dist/node/url.d.ts.map +1 -0
  85. package/dist/node/util.d.ts +252 -0
  86. package/dist/node/util.d.ts.map +1 -0
  87. package/dist/node/v8.d.ts +134 -0
  88. package/dist/node/v8.d.ts.map +1 -0
  89. package/dist/node/vm.d.ts +89 -0
  90. package/dist/node/vm.d.ts.map +1 -0
  91. package/dist/node/wasi.d.ts +25 -0
  92. package/dist/node/wasi.d.ts.map +1 -0
  93. package/dist/node/worker_threads.d.ts +206 -0
  94. package/dist/node/worker_threads.d.ts.map +1 -0
  95. package/dist/node/ws.d.ts +110 -0
  96. package/dist/node/ws.d.ts.map +1 -0
  97. package/dist/node/zlib.d.ts +328 -0
  98. package/dist/node/zlib.d.ts.map +1 -0
  99. package/dist/persistence/opfs-store.d.ts +93 -0
  100. package/dist/persistence/opfs-store.d.ts.map +1 -0
  101. package/dist/runtime/async-function-shim.d.ts +27 -0
  102. package/dist/runtime/async-function-shim.d.ts.map +1 -0
  103. package/dist/runtime/fs-interface.d.ts +60 -0
  104. package/dist/runtime/fs-interface.d.ts.map +1 -0
  105. package/dist/runtime/index.d.ts +113 -0
  106. package/dist/runtime/index.d.ts.map +1 -0
  107. package/dist/runtime/loader.d.ts +50 -0
  108. package/dist/runtime/loader.d.ts.map +1 -0
  109. package/dist/runtime/loaders/async-transform.d.ts +40 -0
  110. package/dist/runtime/loaders/async-transform.d.ts.map +1 -0
  111. package/dist/runtime/loaders/cjs.d.ts +37 -0
  112. package/dist/runtime/loaders/cjs.d.ts.map +1 -0
  113. package/dist/runtime/loaders/detect-module-type.d.ts +21 -0
  114. package/dist/runtime/loaders/detect-module-type.d.ts.map +1 -0
  115. package/dist/runtime/loaders/esm.d.ts +140 -0
  116. package/dist/runtime/loaders/esm.d.ts.map +1 -0
  117. package/dist/runtime/loaders/source-map-registry.d.ts +43 -0
  118. package/dist/runtime/loaders/source-map-registry.d.ts.map +1 -0
  119. package/dist/runtime/loaders/source-map.d.ts +50 -0
  120. package/dist/runtime/loaders/source-map.d.ts.map +1 -0
  121. package/dist/runtime/loaders/utils.d.ts +6 -0
  122. package/dist/runtime/loaders/utils.d.ts.map +1 -0
  123. package/dist/runtime/native-globals.d.ts +24 -0
  124. package/dist/runtime/native-globals.d.ts.map +1 -0
  125. package/dist/runtime/network-driver.d.ts +78 -0
  126. package/dist/runtime/network-driver.d.ts.map +1 -0
  127. package/dist/runtime/process-context.d.ts +96 -0
  128. package/dist/runtime/process-context.d.ts.map +1 -0
  129. package/dist/runtime/process-event-loop.d.ts +356 -0
  130. package/dist/runtime/process-event-loop.d.ts.map +1 -0
  131. package/dist/runtime/process-handler.d.ts +71 -0
  132. package/dist/runtime/process-handler.d.ts.map +1 -0
  133. package/dist/runtime/process-handlers/node.d.ts +22 -0
  134. package/dist/runtime/process-handlers/node.d.ts.map +1 -0
  135. package/dist/runtime/process-handlers/npm.d.ts +20 -0
  136. package/dist/runtime/process-handlers/npm.d.ts.map +1 -0
  137. package/dist/runtime/process-handlers/npx.d.ts +11 -0
  138. package/dist/runtime/process-handlers/npx.d.ts.map +1 -0
  139. package/dist/runtime/process-handlers/pnpm.d.ts +12 -0
  140. package/dist/runtime/process-handlers/pnpm.d.ts.map +1 -0
  141. package/dist/runtime/process-handlers/shell.d.ts +24 -0
  142. package/dist/runtime/process-handlers/shell.d.ts.map +1 -0
  143. package/dist/runtime/process-handlers/yarn.d.ts +12 -0
  144. package/dist/runtime/process-handlers/yarn.d.ts.map +1 -0
  145. package/dist/runtime/process-helpers.d.ts +17 -0
  146. package/dist/runtime/process-helpers.d.ts.map +1 -0
  147. package/dist/runtime/process-manager.d.ts +87 -0
  148. package/dist/runtime/process-manager.d.ts.map +1 -0
  149. package/dist/runtime/process-scheduler.d.ts +123 -0
  150. package/dist/runtime/process-scheduler.d.ts.map +1 -0
  151. package/dist/runtime/process-waker.d.ts +24 -0
  152. package/dist/runtime/process-waker.d.ts.map +1 -0
  153. package/dist/runtime/promise.d.ts +44 -0
  154. package/dist/runtime/promise.d.ts.map +1 -0
  155. package/dist/runtime/stack-trace.d.ts +52 -0
  156. package/dist/runtime/stack-trace.d.ts.map +1 -0
  157. package/dist/runtime/wasm-package-interceptor.d.ts +141 -0
  158. package/dist/runtime/wasm-package-interceptor.d.ts.map +1 -0
  159. package/dist/runtime/web-streams.d.ts +57 -0
  160. package/dist/runtime/web-streams.d.ts.map +1 -0
  161. package/dist/runtime/websocket.d.ts +102 -0
  162. package/dist/runtime/websocket.d.ts.map +1 -0
  163. package/dist/shim/websocket-shim-inline.d.ts +9 -0
  164. package/dist/shim/websocket-shim-inline.d.ts.map +1 -0
  165. package/dist/shim/websocket-shim.d.ts +15 -0
  166. package/dist/shim/websocket-shim.d.ts.map +1 -0
  167. package/dist/sw/index.d.ts +53 -0
  168. package/dist/sw/index.d.ts.map +1 -0
  169. package/dist/utils/debug.d.ts +75 -0
  170. package/dist/utils/debug.d.ts.map +1 -0
  171. package/dist/utils/path.d.ts +20 -0
  172. package/dist/utils/path.d.ts.map +1 -0
  173. package/dist/utils/tarball.d.ts +37 -0
  174. package/dist/utils/tarball.d.ts.map +1 -0
  175. package/dist/utils/websocket-protocol.d.ts +102 -0
  176. package/dist/utils/websocket-protocol.d.ts.map +1 -0
  177. package/dist/worker/host.d.ts +14 -0
  178. package/dist/worker/host.d.ts.map +1 -0
  179. package/dist/worker/types.d.ts +209 -0
  180. package/dist/worker/types.d.ts.map +1 -0
  181. package/package.json +53 -0
Binary file
@@ -0,0 +1,32 @@
1
+ {
2
+ "version": "0.1.0-rc.1",
3
+ "generatedAt": "2026-02-18T20:38:13.854Z",
4
+ "assets": {
5
+ "kernel.wasm": {
6
+ "size": 594328,
7
+ "sri": "sha384-i49EGQS/1AxMLvhDMpIgcK5mq0XB1n/vzTp8RHqFEnfdFuEyJSiJA1x3Zc4yVD35"
8
+ },
9
+ "runtime.js": {
10
+ "size": 554001,
11
+ "sri": "sha384-qgrHq5yfVbuVHRGIMUUs+VlqghCuBOgZbl+qPQsuH4RFu+tAc9bD8aaMVkr7TX+e"
12
+ },
13
+ "network-driver.js": {
14
+ "size": 10635,
15
+ "sri": "sha384-PhZsRSm3CA0534SF84mpg/mDoEb1q+A0QOCchUHQJQmP/IGB2QspU3yvWjOsqxt+"
16
+ }
17
+ },
18
+ "binaries": {
19
+ "npm-11.8.0-bundle.tgz": {
20
+ "size": 2752470,
21
+ "sri": "sha384-dw9qZR/CeqbfnFZo1lC5VyyEVsOkI8tzOF9pnRQ1mcs6LXP0WIjNrYdC1nL9dKMs"
22
+ },
23
+ "pnpm-10.6.4-bundle.tgz": {
24
+ "size": 4494244,
25
+ "sri": "sha384-6x6CcmkgPZXceQ0qync8H7/REr4MJMIjfJyMTT8WzCZp+mO7WXA9uQBS1e7Mc3I5"
26
+ },
27
+ "yarn-1.22.22-bundle.tgz": {
28
+ "size": 1247417,
29
+ "sri": "sha384-YCDpJ7LYdOdZxjsnjLVGPQD9ZmtHsREes5PPFy/k2KUYazjVTooc0V0+kPWRnPFE"
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,2 @@
1
+ const e=console,t={off:0,error:1,warn:2,info:3,debug:4,trace:5};function n(){let e=globalThis.__SUBSTRATE_LOG_LEVEL;return typeof e==`string`&&e in t?e:`info`}function r(e){globalThis.__SUBSTRATE_LOG_LEVEL=e}function i(){let e=globalThis.__SUBSTRATE_LOG_COMPONENTS;return Array.isArray(e)?e:[]}function a(e){globalThis.__SUBSTRATE_LOG_COMPONENTS=e}function o(e,r){let a=n(),o=i();return!(t[e]>t[a]||o.length>0&&!o.some(e=>e.endsWith(`*`)?r.startsWith(e.slice(0,-1)):r===e))}const s={off:``,error:`color: #ff5555; font-weight: bold`,warn:`color: #ffaa00; font-weight: bold`,info:`color: #55aaff`,debug:`color: #888888`,trace:`color: #666666`};function c(t){let n=(n,...r)=>{if(n===`off`||!o(n,t))return;let i=`[${t}]`,a=new Date().toISOString().split(`T`)[1]?.slice(0,-1)??``;switch(n){case`error`:e.error(`%c${a} ${n.toUpperCase()} ${i}`,s[n],...r);break;case`warn`:e.warn(`%c${a} ${n.toUpperCase()} ${i}`,s[n],...r);break;case`info`:e.info(`%c${a} ${n.toUpperCase()} ${i}`,s[n],...r);break;case`debug`:e.debug(`%c${a} ${n.toUpperCase()} ${i}`,s[n],...r);break;case`trace`:e.debug(`%c${a} ${n.toUpperCase()} ${i}`,s[n],...r);break}};return{error:(...e)=>n(`error`,...e),warn:(...e)=>n(`warn`,...e),info:(...e)=>n(`info`,...e),debug:(...e)=>n(`debug`,...e),trace:(...e)=>n(`trace`,...e),log:n}}const l=c(`sw`),u=`substrate:network`;let d=null,f={basePath:null,basePathPort:null,listeningPorts:[],proxyUrl:void 0,neverProxy:[]};function p(e){e?.level&&r(e.level),e?.components&&a(e.components)}const m=new Map,h=new Map,g=new Map,_=new Map;let v=0;async function y(){let e=Date.now();if(e-v<6e4||(v=e,_.size===0))return;let t=await self.clients.matchAll({type:`window`}),n=new Set(t.map(e=>e.id));for(let e of _.keys())n.has(e)||(_.delete(e),l.trace(`Cleaned up stale basePath client:`,e))}self.addEventListener(`install`,()=>{l.trace(`Install event triggered`),self.skipWaiting().catch(e=>{l.error(`Error skipping waiting:`,e)})}),self.addEventListener(`activate`,e=>{l.trace(`Activate event triggered`),e.waitUntil(self.clients.claim().then(()=>{l.trace(`Claimed all clients`)})),C()}),self.addEventListener(`message`,e=>{let t=e.data;if(l.trace(`Received message:`,t?.type,t),t?.type===`skipWaiting`)l.trace(`Processing skipWaiting message`),self.skipWaiting().catch(e=>{l.error(`Error skipping waiting:`,e)});else if(t?.type===`claim`)l.trace(`Processing claim message`),self.clients.claim().catch(e=>{l.error(`Error claiming clients:`,e)});else if(t?.type===`config`)l.trace(`Processing config message:`,t.config),f=t.config,p(f.logging),l.trace(`Config applied, listeningPorts:`,f.listeningPorts);else if(t?.type===`port_listen`)f.listeningPorts.includes(t.port)?l.trace(`Port already in list:`,t.port):(f.listeningPorts.push(t.port),l.debug(`Port added:`,t.port,`listeningPorts:`,f.listeningPorts));else if(t?.type===`port_close`){l.trace(`Processing port_close for port:`,t.port);let e=f.listeningPorts.indexOf(t.port);e!==-1&&(f.listeningPorts.splice(e,1),l.debug(`Port removed:`,t.port,`listeningPorts:`,f.listeningPorts))}else if(t?.type===`substrate_ws_connect`){l.debug(`WS connect from client:`,t.clientId,`wsId:`,t.wsId,`url:`,t.url);let n=t,r,i=e.source;if(i&&`id`in i&&(r=_.get(i.id),l.trace(`WS connect source client:`,i.id,`trackedPort:`,r)),r===void 0&&f.basePath&&f.basePathPort)try{let e=new URL(t.url),n=self.location.port||(self.location.protocol===`https:`?`443`:`80`),i=e.port||(e.protocol===`wss:`?`443`:`80`);(e.hostname===`localhost`||e.hostname===`127.0.0.1`)&&i===n&&(r=f.basePathPort,l.debug(`WS connect fallback: same-origin URL, using basePathPort:`,r))}catch{}if(r!==void 0)try{let e=new URL(t.url);if(e.hostname=`localhost`,e.port=String(r),f.basePath&&e.pathname.startsWith(f.basePath)){let t=e.pathname.slice(f.basePath.length);e.pathname=t.startsWith(`/`)?t:`/`+t}l.debug(`Rewrote WS URL for basePath client:`,t.url,`→`,e.toString()),n={...t,url:e.toString()}}catch(e){l.error(`Failed to rewrite WS URL:`,e)}b(n.clientId,n.wsId,n)}else t?.type===`substrate_ws_send`?(l.trace(`WS send from client:`,t.clientId,`wsId:`,t.wsId),b(t.clientId,t.wsId,t)):t?.type===`substrate_ws_close`&&(l.debug(`WS close from client:`,t.clientId,`wsId:`,t.wsId),b(t.clientId,t.wsId,t))});function b(e,t,n){if(d||(l.trace(`No channel for WS message, initializing...`),C()),n.type===`substrate_ws_connect`){let n=h.get(e);n||(n=new Set,h.set(e,n)),n.add(t),g.set(t,e)}let r=n.type.replace(`substrate_`,`sw_`);d.postMessage({...n,type:r})}async function x(e,t,n){let r=await self.clients.matchAll({type:`window`});l.trace(`Sending WS event to clients:`,r.length,`clientId:`,e,`wsId:`,t,`event:`,n);for(let i of r)try{i.postMessage({...n,clientId:e,wsId:t})}catch(e){l.error(`Error sending WS event to client:`,e)}}self.addEventListener(`fetch`,e=>{let t=new URL(e.request.url);if(y().catch(()=>{}),t.origin===self.location.origin&&f.basePath&&f.basePathPort&&t.pathname.startsWith(f.basePath)){l.trace(`BasePath match:`,f.basePath,`pathname:`,t.pathname);let n=e.resultingClientId||e.clientId;e.request.mode===`navigate`&&n&&(_.set(n,f.basePathPort),l.debug(`Tracking basePath client:`,n,`→ port`,f.basePathPort)),e.respondWith(T(e.request,{port:f.basePathPort,stripPrefix:f.basePath}));return}if(t.origin===self.location.origin&&e.clientId){let n=_.get(e.clientId);if(n!==void 0){l.trace(`BasePath client match:`,e.clientId,`→ port`,n,`url:`,t.pathname),e.request.mode===`navigate`&&e.resultingClientId&&(_.set(e.resultingClientId,n),l.debug(`Propagating basePath client:`,e.resultingClientId,`→ port`,n)),e.respondWith(T(e.request,{port:n}));return}}if(f.listeningPorts.length===0&&!f.proxyUrl){l.trace(`No listening ports and no proxy configured, passthrough`);return}let n=S(t);switch(l.trace(`Fetch intercepted:`,e.request.method,t.href,`→`,n),n){case`kernel`:l.trace(`Routing to kernel:`,t.href),e.respondWith(T(e.request));break;case`proxy`:l.trace(`Routing to proxy:`,t.href),e.respondWith(E(e.request));break;default:l.trace(`Passthrough:`,t.href);break}});function S(e){if(e.hostname===`localhost`||e.hostname===`127.0.0.1`){let t=parseInt(e.port)||(e.protocol===`https:`?443:80);return l.trace(`Localhost request, port:`,t,`listening:`,f.listeningPorts),f.listeningPorts.includes(t)?`kernel`:`passthrough`}if(e.origin!==self.location.origin&&f.proxyUrl){if(l.trace(`External origin:`,e.origin,`proxyUrl:`,f.proxyUrl),!f.neverProxy.includes(e.hostname))return`proxy`;l.trace(`Hostname in neverProxy list:`,e.hostname)}return`passthrough`}function C(){l.trace(`Initializing BroadcastChannel:`,u),d&&(l.trace(`Closing existing channel`),d.close()),d=new BroadcastChannel(u),d.onmessage=w,l.trace(`BroadcastChannel initialized`)}function w(e){let t=e.data;if(l.trace(`Channel message received:`,t.type),t.type===`fetch_response`){l.trace(`Fetch response for:`,t.requestId,`status:`,t.status);let e=m.get(t.requestId);if(e){if(clearTimeout(e.timeout),m.delete(t.requestId),t.error){l.debug(`Fetch error for:`,t.requestId,t.error),e.reject(TypeError(t.error));return}let n=new Headers;for(let[e,r]of t.headers)n.append(e,r);let r=t.body??null;l.trace(`Resolving fetch response, body size:`,r?.length??0),e.resolve(new Response(r,{status:t.status,statusText:t.statusText,headers:n}))}else l.trace(`No pending request found for:`,t.requestId)}else if(t.type===`config`)l.trace(`Config update via channel:`,t.config),f=t.config,p(f.logging);else if(t.type===`port_listen`)l.debug(`Port listen via channel:`,t.port),f.listeningPorts.includes(t.port)||(f.listeningPorts.push(t.port),l.debug(`Port added via channel:`,t.port,`listeningPorts:`,f.listeningPorts));else if(t.type===`port_close`){l.trace(`Port close via channel:`,t.port);let e=f.listeningPorts.indexOf(t.port);e!==-1&&(f.listeningPorts.splice(e,1),l.debug(`Port removed via channel:`,t.port))}else if(t.type===`sw_ws_open`){let e=g.get(t.wsId);e&&(l.debug(`WS open for wsId:`,t.wsId,`clientId:`,e),x(e,t.wsId,{type:`substrate_ws_open`,protocol:t.protocol}).catch(e=>l.error(`Error sending ws_open:`,e)))}else if(t.type===`sw_ws_message`){let e=g.get(t.wsId);e&&(l.trace(`WS message for wsId:`,t.wsId),x(e,t.wsId,{type:`substrate_ws_message`,data:t.data}).catch(e=>l.error(`Error sending ws_message:`,e)))}else if(t.type===`sw_ws_close`){let e=g.get(t.wsId);if(e){l.debug(`WS close for wsId:`,t.wsId),x(e,t.wsId,{type:`substrate_ws_close`,code:t.code,reason:t.reason,wasClean:t.wasClean}).catch(e=>l.error(`Error sending ws_close:`,e)),g.delete(t.wsId);let n=h.get(e);n&&(n.delete(t.wsId),n.size===0&&h.delete(e))}}else if(t.type===`sw_ws_error`){let e=g.get(t.wsId);if(e){l.debug(`WS error for wsId:`,t.wsId),x(e,t.wsId,{type:`substrate_ws_error`,message:t.message}).catch(e=>l.error(`Error sending ws_error:`,e)),g.delete(t.wsId);let n=h.get(e);n&&(n.delete(t.wsId),n.size===0&&h.delete(e))}}}async function T(e,t={}){l.trace(`routeToKernel:`,e.method,e.url,t),d||(l.trace(`No channel, initializing...`),C());let n=crypto.randomUUID();l.trace(`Generated requestId:`,n);let r=e.url;if(t.port){let n=new URL(r);if(n.hostname=`localhost`,n.port=String(t.port),t.stripPrefix&&n.pathname.startsWith(t.stripPrefix)){let e=n.pathname.slice(t.stripPrefix.length);n.pathname=e.startsWith(`/`)?e:`/`+e}r=n.toString(),l.trace(`Rewrote URL:`,e.url,`→`,r)}let i=null;if(e.body){let t=await e.arrayBuffer();i=new Uint8Array(t),l.trace(`Read request body, size:`,i.length)}let a=[];return e.headers.forEach((e,t)=>{a.push([t,e])}),l.trace(`Request headers:`,a.length,`entries`),new Promise((t,o)=>{let s=setTimeout(()=>{l.error(`Kernel request timeout:`,r),m.delete(n),o(Error(`Kernel request timeout: ${r}`))},3e4);m.set(n,{resolve:t,reject:o,timeout:s}),l.trace(`Registered pending request:`,n,`total pending:`,m.size);let c={type:`fetch`,requestId:n,url:r,method:e.method,headers:a,body:i};l.trace(`Posting fetch request to channel:`,n),d.postMessage(c)})}async function E(e){if(l.trace(`routeToProxy:`,e.method,e.url),!f.proxyUrl)return l.trace(`No proxy configured, attempting direct fetch`),fetch(e);let t=new URL(f.proxyUrl,self.location.origin);t.searchParams.set(`url`,e.url),l.trace(`Proxy URL:`,t.toString());let n=new Headers;for(let t of[`accept`,`accept-encoding`,`accept-language`,`authorization`,`content-type`,`content-length`,`user-agent`,`if-none-match`,`if-modified-since`,`range`]){let r=e.headers.get(t);r&&n.set(t,r)}n.set(`X-Substrate-Request`,`true`),l.trace(`Fetching via proxy...`);let r=await fetch(t.toString(),{method:e.method,headers:n,body:e.body,redirect:`follow`});return l.trace(`Proxy response:`,r.status,r.statusText),r}export{_ as basePathClients,f as config,S as determineRoute};
2
+ //# sourceMappingURL=network-driver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network-driver.js","names":[],"sources":["../../src/utils/debug.ts","../../src/sw/index.ts"],"sourcesContent":["/**\n * Substrate Logging Utility\n *\n * A unified logging system with configurable levels and component filtering.\n *\n * Configuration via globals:\n * - __SUBSTRATE_LOG_LEVEL: \"off\" | \"error\" | \"warn\" | \"info\" | \"debug\" | \"trace\"\n * - __SUBSTRATE_LOG_COMPONENTS: string[] - filter to specific components (empty = all)\n *\n * Or via API:\n * - setLogLevel(\"debug\")\n * - setLogComponents([\"vfs\", \"proc\"])\n */\n\n// ============================================================================\n// Original Console Reference\n// ============================================================================\n\n/**\n * Capture the original browser console at module load time.\n *\n * CRITICAL: runWithGlobals() replaces globalThis.console with a child process\n * console that routes output to process stdout/stderr. If our internal logging\n * used globalThis.console, it would cause infinite recursion:\n *\n * 1. User code: console.log(\"hello\")\n * 2. Custom console → processContext.writeStdout()\n * 3. writeStdout() → procLog.trace() → console.debug() (OOPS! globalThis.console is replaced)\n * 4. Custom console → processContext.writeStdout()\n * 5. → infinite recursion → stack overflow\n *\n * By capturing the original console here, our internal logging always goes\n * to the real browser console, never to a child process's stdout.\n */\nconst _console = console;\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type LogLevel = \"off\" | \"error\" | \"warn\" | \"info\" | \"debug\" | \"trace\";\n\nexport interface LogConfig {\n level: LogLevel;\n components: string[];\n}\n\nexport interface Logger {\n error: (...args: unknown[]) => void;\n warn: (...args: unknown[]) => void;\n info: (...args: unknown[]) => void;\n debug: (...args: unknown[]) => void;\n trace: (...args: unknown[]) => void;\n /** Log at a specific level */\n log: (level: LogLevel, ...args: unknown[]) => void;\n}\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\n/** Log level ordering (higher = more verbose) */\nconst LOG_LEVEL_ORDER: Record<LogLevel, number> = {\n off: 0,\n error: 1,\n warn: 2,\n info: 3,\n debug: 4,\n trace: 5,\n};\n\n/** Get current log level from global config */\nexport function getLogLevel(): LogLevel {\n const level = (globalThis as Record<string, unknown>).__SUBSTRATE_LOG_LEVEL;\n if (typeof level === \"string\" && level in LOG_LEVEL_ORDER) {\n return level as LogLevel;\n }\n return \"info\";\n}\n\n/** Set log level at runtime */\nexport function setLogLevel(level: LogLevel): void {\n (globalThis as Record<string, unknown>).__SUBSTRATE_LOG_LEVEL = level;\n}\n\n/** Get component filter */\nexport function getLogComponents(): string[] {\n const components = (globalThis as Record<string, unknown>).__SUBSTRATE_LOG_COMPONENTS;\n if (Array.isArray(components)) {\n return components as string[];\n }\n return [];\n}\n\nexport function withNoLogging(fn: () => void): void {\n const originalLogLevel = getLogLevel();\n try {\n setLogLevel(\"off\");\n return fn();\n } finally {\n setLogLevel(originalLogLevel);\n }\n}\n\n/** Set component filter at runtime */\nexport function setLogComponents(components: string[]): void {\n (globalThis as Record<string, unknown>).__SUBSTRATE_LOG_COMPONENTS = components;\n}\n\n/** Get full log config */\nexport function getLogConfig(): LogConfig {\n return {\n level: getLogLevel(),\n components: getLogComponents(),\n };\n}\n\n/** Set full log config at runtime */\nexport function setLogConfig(config: Partial<LogConfig>): void {\n if (config.level !== undefined) {\n setLogLevel(config.level);\n }\n if (config.components !== undefined) {\n setLogComponents(config.components);\n }\n}\n\n// ============================================================================\n// Filtering\n// ============================================================================\n\n/** Check if a log should be emitted based on current config */\nexport function shouldLog(level: LogLevel, component: string): boolean {\n const configLevel = getLogLevel();\n const configComponents = getLogComponents();\n\n // Check level threshold\n if (LOG_LEVEL_ORDER[level] > LOG_LEVEL_ORDER[configLevel]) {\n return false;\n }\n\n // Check component filter (empty = log all)\n if (configComponents.length > 0) {\n // Support wildcard matching\n const matches = configComponents.some((pattern) => {\n if (pattern.endsWith(\"*\")) {\n return component.startsWith(pattern.slice(0, -1));\n }\n return component === pattern;\n });\n if (!matches) {\n return false;\n }\n }\n\n return true;\n}\n\n// ============================================================================\n// Logger Factory\n// ============================================================================\n\n/** Color codes for different log levels (for browser/terminal) */\nconst LEVEL_COLORS: Record<LogLevel, string> = {\n off: \"\",\n error: \"color: #ff5555; font-weight: bold\",\n warn: \"color: #ffaa00; font-weight: bold\",\n info: \"color: #55aaff\",\n debug: \"color: #888888\",\n trace: \"color: #666666\",\n};\n\n/** Create a logger for a specific component */\nexport function createLogger(component: string): Logger {\n const emit = (level: LogLevel, ...args: unknown[]) => {\n if (level === \"off\") return;\n if (!shouldLog(level, component)) return;\n\n const prefix = `[${component}]`;\n const timestamp = new Date().toISOString().split(\"T\")[1]?.slice(0, -1) ?? \"\";\n\n // Use the captured _console to avoid recursion when globalThis.console\n // has been replaced by a child process console.\n switch (level) {\n case \"error\":\n _console.error(\n `%c${timestamp} ${level.toUpperCase()} ${prefix}`,\n LEVEL_COLORS[level],\n ...args,\n );\n break;\n case \"warn\":\n _console.warn(\n `%c${timestamp} ${level.toUpperCase()} ${prefix}`,\n LEVEL_COLORS[level],\n ...args,\n );\n break;\n case \"info\":\n _console.info(\n `%c${timestamp} ${level.toUpperCase()} ${prefix}`,\n LEVEL_COLORS[level],\n ...args,\n );\n break;\n case \"debug\":\n _console.debug(\n `%c${timestamp} ${level.toUpperCase()} ${prefix}`,\n LEVEL_COLORS[level],\n ...args,\n );\n break;\n case \"trace\":\n _console.debug(\n `%c${timestamp} ${level.toUpperCase()} ${prefix}`,\n LEVEL_COLORS[level],\n ...args,\n );\n break;\n }\n };\n\n return {\n error: (...args) => emit(\"error\", ...args),\n warn: (...args) => emit(\"warn\", ...args),\n info: (...args) => emit(\"info\", ...args),\n debug: (...args) => emit(\"debug\", ...args),\n trace: (...args) => emit(\"trace\", ...args),\n log: emit,\n };\n}\n\n// ============================================================================\n// Pre-configured Loggers\n// ============================================================================\n\n/** Kernel logger */\nexport const kernelLog = createLogger(\"kernel\");\n\n/** VFS logger */\nexport const vfsLog = createLogger(\"vfs\");\n\n/** Process logger */\nexport const procLog = createLogger(\"proc\");\n\n/** Network logger */\nexport const netLog = createLogger(\"net\");\n\n/** Event loop logger */\nexport const eventLog = createLogger(\"events\");\n\n/** Module loader logger */\nexport const moduleLog = createLogger(\"module\");\n\n/** ESM loader logger */\nexport const esmLog = createLogger(\"esm\");\n\n/** HTTP logger */\nexport const httpLog = createLogger(\"http\");\n\n/** WebSocket logger */\nexport const wsLog = createLogger(\"ws\");\n\n/** Child process logger */\nexport const childLog = createLogger(\"child_process\");\n\n/** Buffer logger */\nexport const bufferLog = createLogger(\"buffer\");\n\n/** Stream logger */\nexport const streamLog = createLogger(\"stream\");\n\n/** FS logger */\nexport const fsLog = createLogger(\"fs\");\n\n/** Worker logger (for worker/client communication) */\nexport const workerLog = createLogger(\"worker\");\n\n/** Runtime logger */\nexport const runtimeLog = createLogger(\"runtime\");\n","/**\n * Substrate Service Worker\n *\n * Origin-aware network driver that intercepts requests and routes them\n * to the Substrate kernel running in the leader tab's Web Worker.\n *\n * Routing rules (in priority order):\n * 1. Same-origin + basePath prefix → Kernel (prefix stripped, port from config)\n * 2. Same-origin + tracked basePath client → Kernel (port from client tracking)\n * 3. localhost + listening port → Kernel\n * 4. External origin → CORS Proxy (if configured)\n * 5. Everything else → Passthrough to real network\n *\n * BasePath client tracking: When a navigation request matches basePath, the\n * resultingClientId is recorded. Subsequent same-origin requests from that\n * client (e.g., root-relative URLs from an iframe) are automatically routed\n * to the same kernel port, even though they lack the basePath prefix.\n */\n\n/// <reference lib=\"webworker\" />\n\nimport { createLogger, setLogLevel, setLogComponents, type LogLevel } from \"../utils/debug.js\";\n\ndeclare const self: ServiceWorkerGlobalScope;\n\n// Create a logger for the service worker\nconst swLog = createLogger(\"sw\");\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface RoutingConfig {\n /** Base path - all requests below this path go to kernel */\n basePath: string | null;\n /** Port to rewrite basePath requests to (so substrateFetch can route by port) */\n basePathPort: number | null;\n /** Localhost ports that have virtual servers listening */\n listeningPorts: number[];\n /** CORS proxy URL for external requests (optional) */\n proxyUrl?: string;\n /** Domains that don't need proxying (CORS-friendly) */\n neverProxy: string[];\n /** Logging configuration */\n logging?: {\n level?: LogLevel;\n components?: string[];\n };\n}\n\ninterface FetchRequest {\n type: \"fetch\";\n requestId: string;\n url: string;\n method: string;\n headers: [string, string][];\n body: Uint8Array | null;\n}\n\ninterface FetchResponse {\n type: \"fetch_response\";\n requestId: string;\n status: number;\n statusText: string;\n headers: [string, string][];\n body: Uint8Array | null;\n error?: string;\n}\n\ninterface ConfigMessage {\n type: \"config\";\n config: RoutingConfig;\n}\n\ninterface PortUpdateMessage {\n type: \"port_listen\" | \"port_close\";\n port: number;\n}\n\n// WebSocket messages from main thread back to SW (to forward to clients)\ninterface SwWsOpenMessage {\n type: \"sw_ws_open\";\n wsId: number;\n protocol?: string;\n}\n\ninterface SwWsMessageMessage {\n type: \"sw_ws_message\";\n wsId: number;\n data: unknown;\n}\n\ninterface SwWsCloseMessage {\n type: \"sw_ws_close\";\n wsId: number;\n code?: number;\n reason?: string;\n wasClean?: boolean;\n}\n\ninterface SwWsErrorMessage {\n type: \"sw_ws_error\";\n wsId: number;\n message?: string;\n}\n\ntype NetworkMessage =\n | FetchRequest\n | FetchResponse\n | ConfigMessage\n | PortUpdateMessage\n | SwWsOpenMessage\n | SwWsMessageMessage\n | SwWsCloseMessage\n | SwWsErrorMessage;\n\n// =============================================================================\n// State\n// =============================================================================\n\nconst CHANNEL_NAME = \"substrate:network\";\nlet channel: BroadcastChannel | null = null;\n\nlet config: RoutingConfig = {\n basePath: null,\n basePathPort: null,\n listeningPorts: [],\n proxyUrl: undefined,\n neverProxy: [],\n};\n\n/**\n * Apply logging configuration received from the main thread.\n */\nfunction applyLoggingConfig(logging?: { level?: LogLevel; components?: string[] }): void {\n if (logging?.level) {\n setLogLevel(logging.level);\n }\n if (logging?.components) {\n setLogComponents(logging.components);\n }\n}\n\n// Pending fetch requests waiting for responses\nconst pendingRequests = new Map<\n string,\n {\n resolve: (response: Response) => void;\n reject: (error: Error) => void;\n timeout: ReturnType<typeof setTimeout>;\n }\n>();\n\n// Track which client owns which WebSocket connection (clientId -> Set of wsIds)\nconst clientWebSockets = new Map<string, Set<number>>();\n// Reverse mapping: wsId -> clientId (for routing responses)\nconst wsToClient = new Map<number, string>();\n\n/**\n * Tracks Service Worker clients that were served via basePath routing.\n * Maps clientId → basePathPort. When a navigation request matches basePath,\n * we record the resultingClientId so that subsequent sub-resource requests\n * from that client (which won't have the basePath prefix) are routed to\n * the correct kernel port.\n */\nconst basePathClients = new Map<string, number>();\n\n// Periodic cleanup of stale basePath client entries\nlet lastBasePathCleanup = 0;\nconst BASEPATH_CLEANUP_INTERVAL = 60_000;\n\nasync function cleanupStaleBasePathClients(): Promise<void> {\n const now = Date.now();\n if (now - lastBasePathCleanup < BASEPATH_CLEANUP_INTERVAL) return;\n lastBasePathCleanup = now;\n\n if (basePathClients.size === 0) return;\n\n const allClients = await self.clients.matchAll({ type: \"window\" });\n const activeIds = new Set(allClients.map((c) => c.id));\n\n for (const clientId of basePathClients.keys()) {\n if (!activeIds.has(clientId)) {\n basePathClients.delete(clientId);\n swLog.trace(\"Cleaned up stale basePath client:\", clientId);\n }\n }\n}\n\n// =============================================================================\n// Service Worker Lifecycle\n// =============================================================================\n\nself.addEventListener(\"install\", () => {\n swLog.trace(\"Install event triggered\");\n // Activate immediately without waiting for existing clients\n self.skipWaiting().catch((err) => {\n swLog.error(\"Error skipping waiting:\", err);\n });\n});\n\nself.addEventListener(\"activate\", (event) => {\n swLog.trace(\"Activate event triggered\");\n // Claim all clients immediately\n event.waitUntil(\n self.clients.claim().then(() => {\n swLog.trace(\"Claimed all clients\");\n }),\n );\n\n // Initialize broadcast channel\n initChannel();\n});\n\nself.addEventListener(\"message\", (event) => {\n const data = event.data;\n swLog.trace(\"Received message:\", data?.type, data);\n\n if (data?.type === \"skipWaiting\") {\n swLog.trace(\"Processing skipWaiting message\");\n self.skipWaiting().catch((err) => {\n swLog.error(\"Error skipping waiting:\", err);\n });\n } else if (data?.type === \"claim\") {\n swLog.trace(\"Processing claim message\");\n self.clients.claim().catch((err) => {\n swLog.error(\"Error claiming clients:\", err);\n });\n } else if (data?.type === \"config\") {\n swLog.trace(\"Processing config message:\", data.config);\n // Configuration update from leader\n config = data.config;\n // Apply logging config if present\n applyLoggingConfig(config.logging);\n swLog.trace(\"Config applied, listeningPorts:\", config.listeningPorts);\n } else if (data?.type === \"port_listen\") {\n // A new server started listening\n if (!config.listeningPorts.includes(data.port)) {\n config.listeningPorts.push(data.port);\n swLog.debug(\"Port added:\", data.port, \"listeningPorts:\", config.listeningPorts);\n } else {\n swLog.trace(\"Port already in list:\", data.port);\n }\n } else if (data?.type === \"port_close\") {\n swLog.trace(\"Processing port_close for port:\", data.port);\n // A server stopped listening\n const idx = config.listeningPorts.indexOf(data.port);\n if (idx !== -1) {\n config.listeningPorts.splice(idx, 1);\n swLog.debug(\"Port removed:\", data.port, \"listeningPorts:\", config.listeningPorts);\n }\n } else if (data?.type === \"substrate_ws_connect\") {\n // WebSocket connect request from a served page\n swLog.debug(\"WS connect from client:\", data.clientId, \"wsId:\", data.wsId, \"url:\", data.url);\n\n // Rewrite URL for basePath-tracked clients.\n // When a WS connect comes from a client served via basePath routing (e.g., an\n // iframe at /__preview__/), the page's location.port is the playground host port,\n // not the virtual server port. Rewrite the URL to target the correct port,\n // mirroring the HTTP fetch routing logic for basePath clients.\n let wsData = data;\n let trackedPort: number | undefined;\n\n // Method 1: Check event.source (the client that sent the message)\n const source = event.source;\n if (source && \"id\" in source) {\n trackedPort = basePathClients.get((source as Client).id);\n swLog.trace(\"WS connect source client:\", (source as Client).id, \"trackedPort:\", trackedPort);\n }\n\n // Method 2: Fallback — if source not available or not tracked, check if\n // the URL targets same-origin and basePath is configured. Pages served via\n // basePath have window.location pointing to the host origin, so their WS\n // URLs target same-origin (e.g., ws://localhost:HOST_PORT/) instead of the\n // virtual server port. Rewrite to basePathPort in that case.\n if (trackedPort === undefined && config.basePath && config.basePathPort) {\n try {\n const parsed = new URL(data.url);\n const selfPort = self.location.port || (self.location.protocol === \"https:\" ? \"443\" : \"80\");\n const urlPort = parsed.port || (parsed.protocol === \"wss:\" ? \"443\" : \"80\");\n const isSameOrigin =\n (parsed.hostname === \"localhost\" || parsed.hostname === \"127.0.0.1\") &&\n urlPort === selfPort;\n if (isSameOrigin) {\n trackedPort = config.basePathPort;\n swLog.debug(\"WS connect fallback: same-origin URL, using basePathPort:\", trackedPort);\n }\n } catch {\n // ignore parse errors\n }\n }\n\n if (trackedPort !== undefined) {\n try {\n const parsed = new URL(data.url);\n parsed.hostname = \"localhost\";\n parsed.port = String(trackedPort);\n if (config.basePath && parsed.pathname.startsWith(config.basePath)) {\n const stripped = parsed.pathname.slice(config.basePath.length);\n parsed.pathname = stripped.startsWith(\"/\") ? stripped : \"/\" + stripped;\n }\n swLog.debug(\"Rewrote WS URL for basePath client:\", data.url, \"→\", parsed.toString());\n wsData = { ...data, url: parsed.toString() };\n } catch (err) {\n swLog.error(\"Failed to rewrite WS URL:\", err);\n }\n }\n\n handleWsFromClient(wsData.clientId, wsData.wsId, wsData);\n } else if (data?.type === \"substrate_ws_send\") {\n // WebSocket send from a served page\n swLog.trace(\"WS send from client:\", data.clientId, \"wsId:\", data.wsId);\n handleWsFromClient(data.clientId, data.wsId, data);\n } else if (data?.type === \"substrate_ws_close\") {\n // WebSocket close from a served page\n swLog.debug(\"WS close from client:\", data.clientId, \"wsId:\", data.wsId);\n handleWsFromClient(data.clientId, data.wsId, data);\n }\n});\n\n// =============================================================================\n// WebSocket Message Handling\n// =============================================================================\n\n/**\n * Handle WebSocket messages from served pages and forward to main thread via BroadcastChannel.\n */\nfunction handleWsFromClient(\n clientId: string,\n wsId: number,\n data: { type: string; [key: string]: unknown },\n): void {\n if (!channel) {\n swLog.trace(\"No channel for WS message, initializing...\");\n initChannel();\n }\n\n // Track the client-wsId relationship\n if (data.type === \"substrate_ws_connect\") {\n let wsSet = clientWebSockets.get(clientId);\n if (!wsSet) {\n wsSet = new Set();\n clientWebSockets.set(clientId, wsSet);\n }\n wsSet.add(wsId);\n wsToClient.set(wsId, clientId);\n }\n\n // Forward to main thread via BroadcastChannel\n // Map substrate_ws_* types to sw_ws_* for the main thread\n const mappedType = data.type.replace(\"substrate_\", \"sw_\");\n channel!.postMessage({\n ...data,\n type: mappedType,\n });\n}\n\n/**\n * Send a WebSocket event back to the originating client (served page).\n */\nasync function sendWsEventToClient(clientId: string, wsId: number, event: object): Promise<void> {\n // Find the client that owns this WebSocket\n const clients = await self.clients.matchAll({ type: \"window\" });\n\n swLog.trace(\n \"Sending WS event to clients:\",\n clients.length,\n \"clientId:\",\n clientId,\n \"wsId:\",\n wsId,\n \"event:\",\n event,\n );\n\n // Send to all matching clients - the shim will filter by clientId\n for (const client of clients) {\n try {\n client.postMessage({\n ...event,\n clientId,\n wsId,\n });\n } catch (err) {\n swLog.error(\"Error sending WS event to client:\", err);\n }\n }\n}\n\n// =============================================================================\n// Fetch Interception\n// =============================================================================\n\nself.addEventListener(\"fetch\", (event) => {\n const url = new URL(event.request.url);\n\n // Background cleanup of stale basePath client tracking\n cleanupStaleBasePathClients().catch(() => {});\n\n // 1. Same-origin + basePath prefix → kernel (strip prefix)\n if (url.origin === self.location.origin && config.basePath && config.basePathPort) {\n if (url.pathname.startsWith(config.basePath)) {\n swLog.trace(\"BasePath match:\", config.basePath, \"pathname:\", url.pathname);\n\n // Track the resulting client for navigation requests (e.g., iframe loading)\n const trackId = event.resultingClientId || event.clientId;\n if (event.request.mode === \"navigate\" && trackId) {\n basePathClients.set(trackId, config.basePathPort);\n swLog.debug(\"Tracking basePath client:\", trackId, \"→ port\", config.basePathPort);\n }\n\n event.respondWith(\n routeToKernel(event.request, {\n port: config.basePathPort,\n stripPrefix: config.basePath,\n }),\n );\n return;\n }\n }\n\n // 2. Same-origin + tracked basePath client → kernel (root-relative from iframe)\n if (url.origin === self.location.origin && event.clientId) {\n const trackedPort = basePathClients.get(event.clientId);\n if (trackedPort !== undefined) {\n swLog.trace(\n \"BasePath client match:\",\n event.clientId,\n \"→ port\",\n trackedPort,\n \"url:\",\n url.pathname,\n );\n\n // Propagate tracking for navigations within the iframe\n if (event.request.mode === \"navigate\" && event.resultingClientId) {\n basePathClients.set(event.resultingClientId, trackedPort);\n swLog.debug(\"Propagating basePath client:\", event.resultingClientId, \"→ port\", trackedPort);\n }\n\n event.respondWith(routeToKernel(event.request, { port: trackedPort }));\n return;\n }\n }\n\n // 3. Port-based routing requires at least one listening port,\n // but proxy routing can work without any listening ports\n if (config.listeningPorts.length === 0 && !config.proxyUrl) {\n swLog.trace(\"No listening ports and no proxy configured, passthrough\");\n return;\n }\n\n // 4. Remaining routes: localhost port, proxy, passthrough\n const route = determineRoute(url);\n swLog.trace(\"Fetch intercepted:\", event.request.method, url.href, \"→\", route);\n\n switch (route) {\n case \"kernel\":\n swLog.trace(\"Routing to kernel:\", url.href);\n event.respondWith(routeToKernel(event.request));\n break;\n case \"proxy\":\n swLog.trace(\"Routing to proxy:\", url.href);\n event.respondWith(routeToProxy(event.request));\n break;\n case \"passthrough\":\n default:\n swLog.trace(\"Passthrough:\", url.href);\n break;\n }\n});\n\n// =============================================================================\n// Routing Logic\n// =============================================================================\n\n/**\n * Determine route for non-basePath requests.\n * BasePath routing (prefix match + client tracking) is handled directly\n * in the fetch event handler before this function is called.\n */\nfunction determineRoute(url: URL): \"kernel\" | \"proxy\" | \"passthrough\" {\n // 1. localhost → kernel (if port is listening) or passthrough (never proxy)\n const isLocalhost = url.hostname === \"localhost\" || url.hostname === \"127.0.0.1\";\n if (isLocalhost) {\n const port = parseInt(url.port) || (url.protocol === \"https:\" ? 443 : 80);\n swLog.trace(\"Localhost request, port:\", port, \"listening:\", config.listeningPorts);\n if (config.listeningPorts.includes(port)) {\n return \"kernel\";\n }\n // Localhost with no virtual server → passthrough to real network (never proxy)\n return \"passthrough\";\n }\n\n // 2. External origin → proxy (if configured and not in neverProxy)\n if (url.origin !== self.location.origin && config.proxyUrl) {\n swLog.trace(\"External origin:\", url.origin, \"proxyUrl:\", config.proxyUrl);\n if (!config.neverProxy.includes(url.hostname)) {\n return \"proxy\";\n }\n swLog.trace(\"Hostname in neverProxy list:\", url.hostname);\n }\n\n // 3. Everything else → passthrough\n return \"passthrough\";\n}\n\n// =============================================================================\n// Kernel Routing\n// =============================================================================\n\nfunction initChannel(): void {\n swLog.trace(\"Initializing BroadcastChannel:\", CHANNEL_NAME);\n if (channel) {\n swLog.trace(\"Closing existing channel\");\n channel.close();\n }\n\n channel = new BroadcastChannel(CHANNEL_NAME);\n channel.onmessage = handleChannelMessage;\n swLog.trace(\"BroadcastChannel initialized\");\n}\n\nfunction handleChannelMessage(event: MessageEvent<NetworkMessage>): void {\n const msg = event.data;\n swLog.trace(\"Channel message received:\", msg.type);\n\n if (msg.type === \"fetch_response\") {\n swLog.trace(\"Fetch response for:\", msg.requestId, \"status:\", msg.status);\n const pending = pendingRequests.get(msg.requestId);\n if (pending) {\n clearTimeout(pending.timeout);\n pendingRequests.delete(msg.requestId);\n\n // Connection error - reject so browser treats it as a network error\n if (msg.error) {\n swLog.debug(\"Fetch error for:\", msg.requestId, msg.error);\n pending.reject(new TypeError(msg.error));\n return;\n }\n\n const headers = new Headers();\n for (const [key, value] of msg.headers) {\n headers.append(key, value);\n }\n\n const body = msg.body ?? null;\n swLog.trace(\"Resolving fetch response, body size:\", body?.length ?? 0);\n pending.resolve(\n new Response(body as BodyInit | null, {\n status: msg.status,\n statusText: msg.statusText,\n headers,\n }),\n );\n } else {\n swLog.trace(\"No pending request found for:\", msg.requestId);\n }\n } else if (msg.type === \"config\") {\n swLog.trace(\"Config update via channel:\", msg.config);\n config = msg.config;\n applyLoggingConfig(config.logging);\n } else if (msg.type === \"port_listen\") {\n swLog.debug(\"Port listen via channel:\", msg.port);\n if (!config.listeningPorts.includes(msg.port)) {\n config.listeningPorts.push(msg.port);\n swLog.debug(\"Port added via channel:\", msg.port, \"listeningPorts:\", config.listeningPorts);\n }\n } else if (msg.type === \"port_close\") {\n swLog.trace(\"Port close via channel:\", msg.port);\n const idx = config.listeningPorts.indexOf(msg.port);\n if (idx !== -1) {\n config.listeningPorts.splice(idx, 1);\n swLog.debug(\"Port removed via channel:\", msg.port);\n }\n } else if (msg.type === \"sw_ws_open\") {\n // WebSocket opened - forward to the client\n const clientId = wsToClient.get(msg.wsId);\n if (clientId) {\n swLog.debug(\"WS open for wsId:\", msg.wsId, \"clientId:\", clientId);\n sendWsEventToClient(clientId, msg.wsId, {\n type: \"substrate_ws_open\",\n protocol: msg.protocol,\n }).catch((err) => swLog.error(\"Error sending ws_open:\", err));\n }\n } else if (msg.type === \"sw_ws_message\") {\n // WebSocket message - forward to the client\n const clientId = wsToClient.get(msg.wsId);\n if (clientId) {\n swLog.trace(\"WS message for wsId:\", msg.wsId);\n sendWsEventToClient(clientId, msg.wsId, {\n type: \"substrate_ws_message\",\n data: msg.data,\n }).catch((err) => swLog.error(\"Error sending ws_message:\", err));\n }\n } else if (msg.type === \"sw_ws_close\") {\n // WebSocket closed - forward to the client and clean up\n const clientId = wsToClient.get(msg.wsId);\n if (clientId) {\n swLog.debug(\"WS close for wsId:\", msg.wsId);\n sendWsEventToClient(clientId, msg.wsId, {\n type: \"substrate_ws_close\",\n code: msg.code,\n reason: msg.reason,\n wasClean: msg.wasClean,\n }).catch((err) => swLog.error(\"Error sending ws_close:\", err));\n\n // Clean up tracking\n wsToClient.delete(msg.wsId);\n const wsSet = clientWebSockets.get(clientId);\n if (wsSet) {\n wsSet.delete(msg.wsId);\n if (wsSet.size === 0) {\n clientWebSockets.delete(clientId);\n }\n }\n }\n } else if (msg.type === \"sw_ws_error\") {\n // WebSocket error - forward to the client\n const clientId = wsToClient.get(msg.wsId);\n if (clientId) {\n swLog.debug(\"WS error for wsId:\", msg.wsId);\n sendWsEventToClient(clientId, msg.wsId, {\n type: \"substrate_ws_error\",\n message: msg.message,\n }).catch((err) => swLog.error(\"Error sending ws_error:\", err));\n\n // Clean up tracking\n wsToClient.delete(msg.wsId);\n const wsSet = clientWebSockets.get(clientId);\n if (wsSet) {\n wsSet.delete(msg.wsId);\n if (wsSet.size === 0) {\n clientWebSockets.delete(clientId);\n }\n }\n }\n }\n}\n\ninterface KernelRouteOptions {\n /** Port to route to (overrides the port parsed from the URL) */\n port?: number;\n /** BasePath prefix to strip from the pathname */\n stripPrefix?: string;\n}\n\nasync function routeToKernel(\n request: Request,\n options: KernelRouteOptions = {},\n): Promise<Response> {\n swLog.trace(\"routeToKernel:\", request.method, request.url, options);\n\n if (!channel) {\n swLog.trace(\"No channel, initializing...\");\n initChannel();\n }\n\n const requestId = crypto.randomUUID();\n swLog.trace(\"Generated requestId:\", requestId);\n\n // Rewrite URL: set localhost + port, and optionally strip a basePath prefix.\n // The basePath is purely a SW routing concern — the guest server serves from \"/\".\n let url = request.url;\n if (options.port) {\n const parsed = new URL(url);\n parsed.hostname = \"localhost\";\n parsed.port = String(options.port);\n\n if (options.stripPrefix && parsed.pathname.startsWith(options.stripPrefix)) {\n const stripped = parsed.pathname.slice(options.stripPrefix.length);\n parsed.pathname = stripped.startsWith(\"/\") ? stripped : \"/\" + stripped;\n }\n\n url = parsed.toString();\n swLog.trace(\"Rewrote URL:\", request.url, \"→\", url);\n }\n\n // Read body if present\n let body: Uint8Array | null = null;\n if (request.body) {\n const buffer = await request.arrayBuffer();\n body = new Uint8Array(buffer);\n swLog.trace(\"Read request body, size:\", body.length);\n }\n\n // Convert headers\n const headers: [string, string][] = [];\n request.headers.forEach((value, key) => {\n headers.push([key, value]);\n });\n swLog.trace(\"Request headers:\", headers.length, \"entries\");\n\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n swLog.error(\"Kernel request timeout:\", url);\n pendingRequests.delete(requestId);\n reject(new Error(`Kernel request timeout: ${url}`));\n }, 30_000);\n\n pendingRequests.set(requestId, { resolve, reject, timeout });\n swLog.trace(\"Registered pending request:\", requestId, \"total pending:\", pendingRequests.size);\n\n // Send request to leader via BroadcastChannel\n const msg: FetchRequest = {\n type: \"fetch\",\n requestId,\n url,\n method: request.method,\n headers,\n body,\n };\n\n swLog.trace(\"Posting fetch request to channel:\", requestId);\n channel!.postMessage(msg);\n });\n}\n\n// =============================================================================\n// CORS Proxy Routing\n// =============================================================================\n\nasync function routeToProxy(request: Request): Promise<Response> {\n swLog.trace(\"routeToProxy:\", request.method, request.url);\n\n if (!config.proxyUrl) {\n swLog.trace(\"No proxy configured, attempting direct fetch\");\n // No proxy configured, try direct fetch (will likely fail with CORS)\n return fetch(request);\n }\n\n const proxyUrl = new URL(config.proxyUrl, self.location.origin);\n proxyUrl.searchParams.set(\"url\", request.url);\n swLog.trace(\"Proxy URL:\", proxyUrl.toString());\n\n // Forward headers (with some filtering)\n const headers = new Headers();\n const forwardHeaders = [\n \"accept\",\n \"accept-encoding\",\n \"accept-language\",\n \"authorization\",\n \"content-type\",\n \"content-length\",\n \"user-agent\",\n \"if-none-match\",\n \"if-modified-since\",\n \"range\",\n ];\n\n for (const header of forwardHeaders) {\n const value = request.headers.get(header);\n if (value) {\n headers.set(header, value);\n }\n }\n\n // Add Substrate identifier for rate limiting\n headers.set(\"X-Substrate-Request\", \"true\");\n\n swLog.trace(\"Fetching via proxy...\");\n const response = await fetch(proxyUrl.toString(), {\n method: request.method,\n headers,\n body: request.body,\n redirect: \"follow\",\n });\n swLog.trace(\"Proxy response:\", response.status, response.statusText);\n\n return response;\n}\n\n// =============================================================================\n// Export for testing\n// =============================================================================\n\nexport { determineRoute, config, basePathClients };\n"],"mappings":"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"}