@scriptc/runtime 0.0.0 → 0.0.2

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 (416) hide show
  1. package/LICENSE +202 -0
  2. package/package.json +16 -6
  3. package/src/scr_array.c +488 -0
  4. package/src/scr_assert.c +1393 -0
  5. package/src/scr_async.c +2593 -0
  6. package/src/scr_async_dyn.c +607 -0
  7. package/src/scr_bytes.c +1425 -0
  8. package/src/scr_bytes_io.c +161 -0
  9. package/src/scr_child.c +3587 -0
  10. package/src/scr_closure.c +214 -0
  11. package/src/scr_console.c +143 -0
  12. package/src/scr_cycle.c +218 -0
  13. package/src/scr_dc.c +805 -0
  14. package/src/scr_dgram.c +1007 -0
  15. package/src/scr_dyn_handle.c +154 -0
  16. package/src/scr_dyn_invoke.c +644 -0
  17. package/src/scr_error.c +332 -0
  18. package/src/scr_events.c +714 -0
  19. package/src/scr_events_emitter.c +699 -0
  20. package/src/scr_exception.c +242 -0
  21. package/src/scr_fetch.c +1130 -0
  22. package/src/scr_fetch_curl.c +654 -0
  23. package/src/scr_http.c +3482 -0
  24. package/src/scr_http2.c +3030 -0
  25. package/src/scr_inspect.c +803 -0
  26. package/src/scr_inspect_island.c +51 -0
  27. package/src/scr_island.c +9363 -0
  28. package/src/scr_json.c +2151 -0
  29. package/src/scr_lib.c +3612 -0
  30. package/src/scr_loop_epoll.c +241 -0
  31. package/src/scr_loop_kqueue.c +121 -0
  32. package/src/scr_loop_wsapoll.c +208 -0
  33. package/src/scr_map.c +591 -0
  34. package/src/scr_net.c +3017 -0
  35. package/src/scr_net_island.c +458 -0
  36. package/src/scr_number.c +115 -0
  37. package/src/scr_object.c +25 -0
  38. package/src/scr_path.c +1266 -0
  39. package/src/scr_platform.h +119 -0
  40. package/src/scr_readline.c +287 -0
  41. package/src/scr_regex.c +1080 -0
  42. package/src/scr_runtime.h +5046 -0
  43. package/src/scr_stream.c +2877 -0
  44. package/src/scr_string.c +1264 -0
  45. package/src/scr_symbol.c +132 -0
  46. package/src/scr_test.c +662 -0
  47. package/src/scr_tls.c +1520 -0
  48. package/src/scr_union.c +105 -0
  49. package/src/scr_url.c +911 -0
  50. package/src/scr_url_internal.h +29 -0
  51. package/src/scr_url_params.c +561 -0
  52. package/src/scr_watch.c +568 -0
  53. package/src/scr_web.c +1778 -0
  54. package/src/scr_win.c +76 -0
  55. package/src/scr_zlib.c +197 -0
  56. package/src/scr_zlib_island.c +15 -0
  57. package/vendor/README.md +52 -0
  58. package/vendor/curl/COPYRIGHT +534 -0
  59. package/vendor/curl/include/curl/curl.h +3214 -0
  60. package/vendor/curl/include/curl/curlver.h +79 -0
  61. package/vendor/curl/include/curl/easy.h +125 -0
  62. package/vendor/curl/include/curl/header.h +74 -0
  63. package/vendor/curl/include/curl/mprintf.h +52 -0
  64. package/vendor/curl/include/curl/multi.h +460 -0
  65. package/vendor/curl/include/curl/options.h +70 -0
  66. package/vendor/curl/include/curl/stdcheaders.h +35 -0
  67. package/vendor/curl/include/curl/system.h +508 -0
  68. package/vendor/curl/include/curl/typecheck-gcc.h +716 -0
  69. package/vendor/curl/include/curl/urlapi.h +149 -0
  70. package/vendor/curl/include/curl/websockets.h +84 -0
  71. package/vendor/mbedtls/LICENSE +553 -0
  72. package/vendor/mbedtls/include/CMakeLists.txt +22 -0
  73. package/vendor/mbedtls/include/mbedtls/aes.h +631 -0
  74. package/vendor/mbedtls/include/mbedtls/aria.h +343 -0
  75. package/vendor/mbedtls/include/mbedtls/asn1.h +642 -0
  76. package/vendor/mbedtls/include/mbedtls/asn1write.h +390 -0
  77. package/vendor/mbedtls/include/mbedtls/base64.h +82 -0
  78. package/vendor/mbedtls/include/mbedtls/bignum.h +1088 -0
  79. package/vendor/mbedtls/include/mbedtls/block_cipher.h +76 -0
  80. package/vendor/mbedtls/include/mbedtls/build_info.h +194 -0
  81. package/vendor/mbedtls/include/mbedtls/camellia.h +305 -0
  82. package/vendor/mbedtls/include/mbedtls/ccm.h +526 -0
  83. package/vendor/mbedtls/include/mbedtls/chacha20.h +209 -0
  84. package/vendor/mbedtls/include/mbedtls/chachapoly.h +351 -0
  85. package/vendor/mbedtls/include/mbedtls/check_config.h +1149 -0
  86. package/vendor/mbedtls/include/mbedtls/cipher.h +1250 -0
  87. package/vendor/mbedtls/include/mbedtls/cmac.h +246 -0
  88. package/vendor/mbedtls/include/mbedtls/compat-2.x.h +46 -0
  89. package/vendor/mbedtls/include/mbedtls/config_adjust_legacy_crypto.h +578 -0
  90. package/vendor/mbedtls/include/mbedtls/config_adjust_legacy_from_psa.h +873 -0
  91. package/vendor/mbedtls/include/mbedtls/config_adjust_psa_from_legacy.h +359 -0
  92. package/vendor/mbedtls/include/mbedtls/config_adjust_psa_superset_legacy.h +145 -0
  93. package/vendor/mbedtls/include/mbedtls/config_adjust_ssl.h +91 -0
  94. package/vendor/mbedtls/include/mbedtls/config_adjust_x509.h +35 -0
  95. package/vendor/mbedtls/include/mbedtls/config_psa.h +61 -0
  96. package/vendor/mbedtls/include/mbedtls/constant_time.h +36 -0
  97. package/vendor/mbedtls/include/mbedtls/ctr_drbg.h +596 -0
  98. package/vendor/mbedtls/include/mbedtls/debug.h +156 -0
  99. package/vendor/mbedtls/include/mbedtls/des.h +385 -0
  100. package/vendor/mbedtls/include/mbedtls/dhm.h +972 -0
  101. package/vendor/mbedtls/include/mbedtls/ecdh.h +455 -0
  102. package/vendor/mbedtls/include/mbedtls/ecdsa.h +674 -0
  103. package/vendor/mbedtls/include/mbedtls/ecjpake.h +298 -0
  104. package/vendor/mbedtls/include/mbedtls/ecp.h +1517 -0
  105. package/vendor/mbedtls/include/mbedtls/entropy.h +274 -0
  106. package/vendor/mbedtls/include/mbedtls/error.h +201 -0
  107. package/vendor/mbedtls/include/mbedtls/gcm.h +387 -0
  108. package/vendor/mbedtls/include/mbedtls/hkdf.h +124 -0
  109. package/vendor/mbedtls/include/mbedtls/hmac_drbg.h +434 -0
  110. package/vendor/mbedtls/include/mbedtls/lms.h +440 -0
  111. package/vendor/mbedtls/include/mbedtls/mbedtls_config.h +4446 -0
  112. package/vendor/mbedtls/include/mbedtls/md.h +526 -0
  113. package/vendor/mbedtls/include/mbedtls/md5.h +190 -0
  114. package/vendor/mbedtls/include/mbedtls/memory_buffer_alloc.h +142 -0
  115. package/vendor/mbedtls/include/mbedtls/net_sockets.h +299 -0
  116. package/vendor/mbedtls/include/mbedtls/nist_kw.h +166 -0
  117. package/vendor/mbedtls/include/mbedtls/oid.h +727 -0
  118. package/vendor/mbedtls/include/mbedtls/pem.h +160 -0
  119. package/vendor/mbedtls/include/mbedtls/pk.h +1303 -0
  120. package/vendor/mbedtls/include/mbedtls/pkcs12.h +186 -0
  121. package/vendor/mbedtls/include/mbedtls/pkcs5.h +198 -0
  122. package/vendor/mbedtls/include/mbedtls/pkcs7.h +252 -0
  123. package/vendor/mbedtls/include/mbedtls/platform.h +516 -0
  124. package/vendor/mbedtls/include/mbedtls/platform_time.h +79 -0
  125. package/vendor/mbedtls/include/mbedtls/platform_util.h +247 -0
  126. package/vendor/mbedtls/include/mbedtls/poly1305.h +168 -0
  127. package/vendor/mbedtls/include/mbedtls/private_access.h +20 -0
  128. package/vendor/mbedtls/include/mbedtls/psa_util.h +207 -0
  129. package/vendor/mbedtls/include/mbedtls/ripemd160.h +136 -0
  130. package/vendor/mbedtls/include/mbedtls/rsa.h +1170 -0
  131. package/vendor/mbedtls/include/mbedtls/sha1.h +219 -0
  132. package/vendor/mbedtls/include/mbedtls/sha256.h +200 -0
  133. package/vendor/mbedtls/include/mbedtls/sha3.h +172 -0
  134. package/vendor/mbedtls/include/mbedtls/sha512.h +208 -0
  135. package/vendor/mbedtls/include/mbedtls/ssl.h +5887 -0
  136. package/vendor/mbedtls/include/mbedtls/ssl_cache.h +187 -0
  137. package/vendor/mbedtls/include/mbedtls/ssl_ciphersuites.h +482 -0
  138. package/vendor/mbedtls/include/mbedtls/ssl_cookie.h +106 -0
  139. package/vendor/mbedtls/include/mbedtls/ssl_ticket.h +199 -0
  140. package/vendor/mbedtls/include/mbedtls/threading.h +167 -0
  141. package/vendor/mbedtls/include/mbedtls/timing.h +94 -0
  142. package/vendor/mbedtls/include/mbedtls/version.h +78 -0
  143. package/vendor/mbedtls/include/mbedtls/x509.h +500 -0
  144. package/vendor/mbedtls/include/mbedtls/x509_crl.h +184 -0
  145. package/vendor/mbedtls/include/mbedtls/x509_crt.h +1208 -0
  146. package/vendor/mbedtls/include/mbedtls/x509_csr.h +382 -0
  147. package/vendor/mbedtls/include/psa/build_info.h +20 -0
  148. package/vendor/mbedtls/include/psa/crypto.h +4998 -0
  149. package/vendor/mbedtls/include/psa/crypto_adjust_auto_enabled.h +31 -0
  150. package/vendor/mbedtls/include/psa/crypto_adjust_config_dependencies.h +51 -0
  151. package/vendor/mbedtls/include/psa/crypto_adjust_config_key_pair_types.h +101 -0
  152. package/vendor/mbedtls/include/psa/crypto_adjust_config_synonyms.h +49 -0
  153. package/vendor/mbedtls/include/psa/crypto_builtin_composites.h +214 -0
  154. package/vendor/mbedtls/include/psa/crypto_builtin_key_derivation.h +118 -0
  155. package/vendor/mbedtls/include/psa/crypto_builtin_primitives.h +114 -0
  156. package/vendor/mbedtls/include/psa/crypto_compat.h +230 -0
  157. package/vendor/mbedtls/include/psa/crypto_config.h +145 -0
  158. package/vendor/mbedtls/include/psa/crypto_driver_common.h +44 -0
  159. package/vendor/mbedtls/include/psa/crypto_driver_contexts_composites.h +151 -0
  160. package/vendor/mbedtls/include/psa/crypto_driver_contexts_key_derivation.h +52 -0
  161. package/vendor/mbedtls/include/psa/crypto_driver_contexts_primitives.h +105 -0
  162. package/vendor/mbedtls/include/psa/crypto_extra.h +2145 -0
  163. package/vendor/mbedtls/include/psa/crypto_legacy.h +88 -0
  164. package/vendor/mbedtls/include/psa/crypto_platform.h +102 -0
  165. package/vendor/mbedtls/include/psa/crypto_se_driver.h +1383 -0
  166. package/vendor/mbedtls/include/psa/crypto_sizes.h +1319 -0
  167. package/vendor/mbedtls/include/psa/crypto_struct.h +527 -0
  168. package/vendor/mbedtls/include/psa/crypto_types.h +508 -0
  169. package/vendor/mbedtls/include/psa/crypto_values.h +2782 -0
  170. package/vendor/mbedtls/library/aes.c +2294 -0
  171. package/vendor/mbedtls/library/aesce.c +624 -0
  172. package/vendor/mbedtls/library/aesce.h +136 -0
  173. package/vendor/mbedtls/library/aesni.c +846 -0
  174. package/vendor/mbedtls/library/aesni.h +162 -0
  175. package/vendor/mbedtls/library/alignment.h +704 -0
  176. package/vendor/mbedtls/library/aria.c +969 -0
  177. package/vendor/mbedtls/library/asn1parse.c +468 -0
  178. package/vendor/mbedtls/library/asn1write.c +440 -0
  179. package/vendor/mbedtls/library/base64.c +322 -0
  180. package/vendor/mbedtls/library/base64_internal.h +45 -0
  181. package/vendor/mbedtls/library/bignum.c +2583 -0
  182. package/vendor/mbedtls/library/bignum_core.c +1240 -0
  183. package/vendor/mbedtls/library/bignum_core.h +872 -0
  184. package/vendor/mbedtls/library/bignum_core_invasive.h +38 -0
  185. package/vendor/mbedtls/library/bignum_internal.h +122 -0
  186. package/vendor/mbedtls/library/bignum_mod.c +394 -0
  187. package/vendor/mbedtls/library/bignum_mod.h +452 -0
  188. package/vendor/mbedtls/library/bignum_mod_raw.c +276 -0
  189. package/vendor/mbedtls/library/bignum_mod_raw.h +416 -0
  190. package/vendor/mbedtls/library/bignum_mod_raw_invasive.h +34 -0
  191. package/vendor/mbedtls/library/block_cipher.c +207 -0
  192. package/vendor/mbedtls/library/block_cipher_internal.h +99 -0
  193. package/vendor/mbedtls/library/bn_mul.h +1094 -0
  194. package/vendor/mbedtls/library/camellia.c +1058 -0
  195. package/vendor/mbedtls/library/ccm.c +777 -0
  196. package/vendor/mbedtls/library/chacha20.c +563 -0
  197. package/vendor/mbedtls/library/chacha20_internal.h +23 -0
  198. package/vendor/mbedtls/library/chachapoly.c +487 -0
  199. package/vendor/mbedtls/library/check_crypto_config.h +136 -0
  200. package/vendor/mbedtls/library/cipher.c +1712 -0
  201. package/vendor/mbedtls/library/cipher_invasive.h +28 -0
  202. package/vendor/mbedtls/library/cipher_wrap.c +2482 -0
  203. package/vendor/mbedtls/library/cipher_wrap.h +178 -0
  204. package/vendor/mbedtls/library/cmac.c +1067 -0
  205. package/vendor/mbedtls/library/common.h +487 -0
  206. package/vendor/mbedtls/library/constant_time.c +247 -0
  207. package/vendor/mbedtls/library/constant_time_impl.h +541 -0
  208. package/vendor/mbedtls/library/constant_time_internal.h +579 -0
  209. package/vendor/mbedtls/library/ctr.h +35 -0
  210. package/vendor/mbedtls/library/ctr_drbg.c +1016 -0
  211. package/vendor/mbedtls/library/debug.c +475 -0
  212. package/vendor/mbedtls/library/debug_internal.h +185 -0
  213. package/vendor/mbedtls/library/des.c +1042 -0
  214. package/vendor/mbedtls/library/dhm.c +700 -0
  215. package/vendor/mbedtls/library/ecdh.c +696 -0
  216. package/vendor/mbedtls/library/ecdsa.c +858 -0
  217. package/vendor/mbedtls/library/ecjpake.c +1216 -0
  218. package/vendor/mbedtls/library/ecp.c +3674 -0
  219. package/vendor/mbedtls/library/ecp_curves.c +6125 -0
  220. package/vendor/mbedtls/library/ecp_curves_new.c +9 -0
  221. package/vendor/mbedtls/library/ecp_internal_alt.h +287 -0
  222. package/vendor/mbedtls/library/ecp_invasive.h +305 -0
  223. package/vendor/mbedtls/library/entropy.c +680 -0
  224. package/vendor/mbedtls/library/entropy_poll.c +233 -0
  225. package/vendor/mbedtls/library/entropy_poll.h +64 -0
  226. package/vendor/mbedtls/library/error.c +878 -0
  227. package/vendor/mbedtls/library/gcm.c +1330 -0
  228. package/vendor/mbedtls/library/hkdf.c +161 -0
  229. package/vendor/mbedtls/library/hmac_drbg.c +633 -0
  230. package/vendor/mbedtls/library/lmots.c +789 -0
  231. package/vendor/mbedtls/library/lmots.h +288 -0
  232. package/vendor/mbedtls/library/lms.c +778 -0
  233. package/vendor/mbedtls/library/md.c +1108 -0
  234. package/vendor/mbedtls/library/md5.c +426 -0
  235. package/vendor/mbedtls/library/md_psa.h +26 -0
  236. package/vendor/mbedtls/library/md_wrap.h +46 -0
  237. package/vendor/mbedtls/library/memory_buffer_alloc.c +751 -0
  238. package/vendor/mbedtls/library/mps_common.h +181 -0
  239. package/vendor/mbedtls/library/mps_error.h +89 -0
  240. package/vendor/mbedtls/library/mps_reader.c +538 -0
  241. package/vendor/mbedtls/library/mps_reader.h +366 -0
  242. package/vendor/mbedtls/library/mps_trace.c +112 -0
  243. package/vendor/mbedtls/library/mps_trace.h +154 -0
  244. package/vendor/mbedtls/library/net_sockets.c +694 -0
  245. package/vendor/mbedtls/library/nist_kw.c +729 -0
  246. package/vendor/mbedtls/library/oid.c +1166 -0
  247. package/vendor/mbedtls/library/padlock.c +157 -0
  248. package/vendor/mbedtls/library/padlock.h +111 -0
  249. package/vendor/mbedtls/library/pem.c +554 -0
  250. package/vendor/mbedtls/library/pk.c +1602 -0
  251. package/vendor/mbedtls/library/pk_ecc.c +261 -0
  252. package/vendor/mbedtls/library/pk_internal.h +241 -0
  253. package/vendor/mbedtls/library/pk_wrap.c +1618 -0
  254. package/vendor/mbedtls/library/pk_wrap.h +138 -0
  255. package/vendor/mbedtls/library/pkcs12.c +437 -0
  256. package/vendor/mbedtls/library/pkcs5.c +500 -0
  257. package/vendor/mbedtls/library/pkcs7.c +787 -0
  258. package/vendor/mbedtls/library/pkparse.c +1392 -0
  259. package/vendor/mbedtls/library/pkwrite.c +631 -0
  260. package/vendor/mbedtls/library/pkwrite.h +121 -0
  261. package/vendor/mbedtls/library/platform.c +402 -0
  262. package/vendor/mbedtls/library/platform_util.c +258 -0
  263. package/vendor/mbedtls/library/poly1305.c +492 -0
  264. package/vendor/mbedtls/library/psa_crypto.c +9532 -0
  265. package/vendor/mbedtls/library/psa_crypto_aead.c +646 -0
  266. package/vendor/mbedtls/library/psa_crypto_aead.h +499 -0
  267. package/vendor/mbedtls/library/psa_crypto_cipher.c +747 -0
  268. package/vendor/mbedtls/library/psa_crypto_cipher.h +316 -0
  269. package/vendor/mbedtls/library/psa_crypto_client.c +22 -0
  270. package/vendor/mbedtls/library/psa_crypto_core.h +983 -0
  271. package/vendor/mbedtls/library/psa_crypto_core_common.h +52 -0
  272. package/vendor/mbedtls/library/psa_crypto_driver_wrappers.h +2896 -0
  273. package/vendor/mbedtls/library/psa_crypto_driver_wrappers_no_static.c +256 -0
  274. package/vendor/mbedtls/library/psa_crypto_driver_wrappers_no_static.h +31 -0
  275. package/vendor/mbedtls/library/psa_crypto_ecp.c +594 -0
  276. package/vendor/mbedtls/library/psa_crypto_ecp.h +267 -0
  277. package/vendor/mbedtls/library/psa_crypto_ffdh.c +361 -0
  278. package/vendor/mbedtls/library/psa_crypto_ffdh.h +131 -0
  279. package/vendor/mbedtls/library/psa_crypto_hash.c +470 -0
  280. package/vendor/mbedtls/library/psa_crypto_hash.h +211 -0
  281. package/vendor/mbedtls/library/psa_crypto_invasive.h +92 -0
  282. package/vendor/mbedtls/library/psa_crypto_its.h +131 -0
  283. package/vendor/mbedtls/library/psa_crypto_mac.c +505 -0
  284. package/vendor/mbedtls/library/psa_crypto_mac.h +264 -0
  285. package/vendor/mbedtls/library/psa_crypto_pake.c +571 -0
  286. package/vendor/mbedtls/library/psa_crypto_pake.h +159 -0
  287. package/vendor/mbedtls/library/psa_crypto_random.c +181 -0
  288. package/vendor/mbedtls/library/psa_crypto_random.h +72 -0
  289. package/vendor/mbedtls/library/psa_crypto_random_impl.h +200 -0
  290. package/vendor/mbedtls/library/psa_crypto_rsa.c +714 -0
  291. package/vendor/mbedtls/library/psa_crypto_rsa.h +321 -0
  292. package/vendor/mbedtls/library/psa_crypto_se.c +373 -0
  293. package/vendor/mbedtls/library/psa_crypto_se.h +192 -0
  294. package/vendor/mbedtls/library/psa_crypto_slot_management.c +1137 -0
  295. package/vendor/mbedtls/library/psa_crypto_slot_management.h +344 -0
  296. package/vendor/mbedtls/library/psa_crypto_storage.c +481 -0
  297. package/vendor/mbedtls/library/psa_crypto_storage.h +392 -0
  298. package/vendor/mbedtls/library/psa_its_file.c +254 -0
  299. package/vendor/mbedtls/library/psa_util.c +614 -0
  300. package/vendor/mbedtls/library/psa_util_internal.h +100 -0
  301. package/vendor/mbedtls/library/ripemd160.c +490 -0
  302. package/vendor/mbedtls/library/rsa.c +3121 -0
  303. package/vendor/mbedtls/library/rsa_alt_helpers.c +455 -0
  304. package/vendor/mbedtls/library/rsa_alt_helpers.h +209 -0
  305. package/vendor/mbedtls/library/rsa_internal.h +188 -0
  306. package/vendor/mbedtls/library/sha1.c +480 -0
  307. package/vendor/mbedtls/library/sha256.c +983 -0
  308. package/vendor/mbedtls/library/sha3.c +721 -0
  309. package/vendor/mbedtls/library/sha512.c +1115 -0
  310. package/vendor/mbedtls/library/ssl_cache.c +410 -0
  311. package/vendor/mbedtls/library/ssl_ciphersuites.c +2050 -0
  312. package/vendor/mbedtls/library/ssl_ciphersuites_internal.h +154 -0
  313. package/vendor/mbedtls/library/ssl_client.c +1023 -0
  314. package/vendor/mbedtls/library/ssl_client.h +22 -0
  315. package/vendor/mbedtls/library/ssl_cookie.c +384 -0
  316. package/vendor/mbedtls/library/ssl_debug_helpers.h +85 -0
  317. package/vendor/mbedtls/library/ssl_debug_helpers_generated.c +251 -0
  318. package/vendor/mbedtls/library/ssl_misc.h +3198 -0
  319. package/vendor/mbedtls/library/ssl_msg.c +6619 -0
  320. package/vendor/mbedtls/library/ssl_ticket.c +556 -0
  321. package/vendor/mbedtls/library/ssl_tls.c +10234 -0
  322. package/vendor/mbedtls/library/ssl_tls12_client.c +3688 -0
  323. package/vendor/mbedtls/library/ssl_tls12_server.c +4311 -0
  324. package/vendor/mbedtls/library/ssl_tls13_client.c +3208 -0
  325. package/vendor/mbedtls/library/ssl_tls13_generic.c +1793 -0
  326. package/vendor/mbedtls/library/ssl_tls13_invasive.h +23 -0
  327. package/vendor/mbedtls/library/ssl_tls13_keys.c +1918 -0
  328. package/vendor/mbedtls/library/ssl_tls13_keys.h +668 -0
  329. package/vendor/mbedtls/library/ssl_tls13_server.c +3624 -0
  330. package/vendor/mbedtls/library/threading.c +193 -0
  331. package/vendor/mbedtls/library/threading_internal.h +28 -0
  332. package/vendor/mbedtls/library/timing.c +152 -0
  333. package/vendor/mbedtls/library/version.c +32 -0
  334. package/vendor/mbedtls/library/version_features.c +856 -0
  335. package/vendor/mbedtls/library/x509.c +1776 -0
  336. package/vendor/mbedtls/library/x509_create.c +570 -0
  337. package/vendor/mbedtls/library/x509_crl.c +708 -0
  338. package/vendor/mbedtls/library/x509_crt.c +3311 -0
  339. package/vendor/mbedtls/library/x509_csr.c +648 -0
  340. package/vendor/mbedtls/library/x509_internal.h +101 -0
  341. package/vendor/mbedtls/library/x509write.c +174 -0
  342. package/vendor/mbedtls/library/x509write_crt.c +688 -0
  343. package/vendor/mbedtls/library/x509write_csr.c +336 -0
  344. package/vendor/quickjs-ng/CMakeLists.txt +566 -0
  345. package/vendor/quickjs-ng/LICENSE +24 -0
  346. package/vendor/quickjs-ng/README.md +24 -0
  347. package/vendor/quickjs-ng/api-test.c +1195 -0
  348. package/vendor/quickjs-ng/builtin-array-fromasync.h +119 -0
  349. package/vendor/quickjs-ng/builtin-iterator-zip-keyed.h +332 -0
  350. package/vendor/quickjs-ng/builtin-iterator-zip.h +337 -0
  351. package/vendor/quickjs-ng/cutils.h +1998 -0
  352. package/vendor/quickjs-ng/dtoa.c +1619 -0
  353. package/vendor/quickjs-ng/dtoa.h +87 -0
  354. package/vendor/quickjs-ng/gen/function_source.c +81 -0
  355. package/vendor/quickjs-ng/gen/hello.c +53 -0
  356. package/vendor/quickjs-ng/gen/hello_module.c +106 -0
  357. package/vendor/quickjs-ng/gen/repl.c +3036 -0
  358. package/vendor/quickjs-ng/gen/standalone.c +323 -0
  359. package/vendor/quickjs-ng/gen/test_fib.c +81 -0
  360. package/vendor/quickjs-ng/libregexp-opcode.h +73 -0
  361. package/vendor/quickjs-ng/libregexp.c +3474 -0
  362. package/vendor/quickjs-ng/libregexp.h +101 -0
  363. package/vendor/quickjs-ng/libunicode-table.h +5173 -0
  364. package/vendor/quickjs-ng/libunicode.c +2069 -0
  365. package/vendor/quickjs-ng/libunicode.h +172 -0
  366. package/vendor/quickjs-ng/list.h +107 -0
  367. package/vendor/quickjs-ng/lre-test.c +52 -0
  368. package/vendor/quickjs-ng/qjs.c +762 -0
  369. package/vendor/quickjs-ng/qjsc.c +673 -0
  370. package/vendor/quickjs-ng/quickjs-atom.h +280 -0
  371. package/vendor/quickjs-ng/quickjs-c-atomics.h +54 -0
  372. package/vendor/quickjs-ng/quickjs-libc.c +5037 -0
  373. package/vendor/quickjs-ng/quickjs-libc.h +87 -0
  374. package/vendor/quickjs-ng/quickjs-opcode.h +377 -0
  375. package/vendor/quickjs-ng/quickjs.c +64041 -0
  376. package/vendor/quickjs-ng/quickjs.h +1447 -0
  377. package/vendor/quickjs-ng/run-test262.c +2374 -0
  378. package/vendor/quickjs-ng/unicode_gen.c +3121 -0
  379. package/vendor/quickjs-ng/unicode_gen_def.h +310 -0
  380. package/vendor/ryu/LICENSE-Boost +23 -0
  381. package/vendor/ryu/common.h +114 -0
  382. package/vendor/ryu/d2s.c +509 -0
  383. package/vendor/ryu/d2s_full_table.h +367 -0
  384. package/vendor/ryu/d2s_intrinsics.h +357 -0
  385. package/vendor/ryu/d2s_small_table.h +186 -0
  386. package/vendor/ryu/digit_table.h +35 -0
  387. package/vendor/ryu/ryu.h +46 -0
  388. package/vendor/zlib/LICENSE +22 -0
  389. package/vendor/zlib/adler32.c +164 -0
  390. package/vendor/zlib/compress.c +75 -0
  391. package/vendor/zlib/crc32.c +1049 -0
  392. package/vendor/zlib/crc32.h +9446 -0
  393. package/vendor/zlib/deflate.c +2139 -0
  394. package/vendor/zlib/deflate.h +377 -0
  395. package/vendor/zlib/gzclose.c +23 -0
  396. package/vendor/zlib/gzguts.h +214 -0
  397. package/vendor/zlib/gzlib.c +582 -0
  398. package/vendor/zlib/gzread.c +602 -0
  399. package/vendor/zlib/gzwrite.c +631 -0
  400. package/vendor/zlib/infback.c +628 -0
  401. package/vendor/zlib/inffast.c +320 -0
  402. package/vendor/zlib/inffast.h +11 -0
  403. package/vendor/zlib/inffixed.h +94 -0
  404. package/vendor/zlib/inflate.c +1526 -0
  405. package/vendor/zlib/inflate.h +126 -0
  406. package/vendor/zlib/inftrees.c +299 -0
  407. package/vendor/zlib/inftrees.h +62 -0
  408. package/vendor/zlib/trees.c +1117 -0
  409. package/vendor/zlib/trees.h +128 -0
  410. package/vendor/zlib/uncompr.c +85 -0
  411. package/vendor/zlib/zconf.h +543 -0
  412. package/vendor/zlib/zlib.h +1938 -0
  413. package/vendor/zlib/zutil.c +299 -0
  414. package/vendor/zlib/zutil.h +254 -0
  415. package/README.md +0 -3
  416. package/index.js +0 -2
@@ -0,0 +1,1130 @@
1
+ /* fetch for the dynamic island, over scriptc's OWN net stack — the
2
+ * scr_platform poller + scr_net sockets, scr_http's HTTP/1.1 client
3
+ * parser, scr_tls (vendored mbedTLS) for https, and zlib for response
4
+ * decompression. No libcurl anywhere: the architecture is Node's own
5
+ * (libuv sockets + OpenSSL + undici; ours: poller + mbedTLS + this
6
+ * unit), which is what lets fetch compile for every target the socket
7
+ * units reach — win32 included, where no system-libcurl contract
8
+ * exists. The curl implementation this replaces stays compilable for
9
+ * one release as the reference (scr_fetch_curl.c, selected by
10
+ * SCRIPTC_FETCH_CURL=1 at build time; same install symbol, same island
11
+ * surface, same fixture suite).
12
+ *
13
+ * Architecture (the JS half is UNCHANGED from the curl bridge):
14
+ * - The JS half (fetch_glue below) defines globalThis.fetch over two host
15
+ * functions: host.start(req, cbs) begins a transfer and host.abort(id)
16
+ * cancels one (response-body cancel). fetch() returns a REAL island
17
+ * promise; the Response's body is an island ReadableStream fed by
18
+ * C→engine callbacks as data arrives.
19
+ * - The C half is a fetch-layer client over scr_http's client machinery:
20
+ * one ScrHttpClientReq per hop, minted runtime closures (caps[0] boxes
21
+ * the transfer) as its response/data/end/error listeners, callbacks
22
+ * firing from the net unit's dispatch station — the loop's own poller
23
+ * sleeps on socket readiness, so this unit registers NO poll hook with
24
+ * the island (the curl bridge needed one to sleep on curl's fds).
25
+ * AbortSignal.timeout stays punctual through the loop's island-timer
26
+ * deadline hook (scr_loop_set_island_deadline — armed island timers cap
27
+ * the idle sleep exactly the way the curl poll capped its own).
28
+ * - fetch SEMANTICS, matched to Node/undici: HTTP errors RESOLVE (only
29
+ * network failure rejects, with TypeError "fetch failed" — Node's exact
30
+ * message); redirects are followed IN THIS UNIT (20 hops, fetch's
31
+ * limit; 303 — and 301/302 for POST — rewrite to GET and drop the body
32
+ * and its content-* headers, the fetch spec's rules; authorization is
33
+ * stripped on cross-origin hops; response.url = the final URL without
34
+ * its fragment, response.redirected set; a redirect hop's own body
35
+ * never reaches the island). The request head carries undici's exact
36
+ * default header set in undici's order (host, connection, the user
37
+ * headers, accept, accept-language, sec-fetch-mode, user-agent,
38
+ * accept-encoding — captured from Node 24 on the wire); gzip/zlib
39
+ * response bodies arrive decompressed (accept-encoding advertises
40
+ * "gzip, deflate", and content-encoding: gzip/x-gzip/deflate inflates
41
+ * through zlib's 15+32 auto-detect — raw-deflate servers and br/zstd
42
+ * are out of the slice, honestly: br/zstd are never offered).
43
+ * - DNS: scr_net dials IP literals only (Node's shape for its slice), so
44
+ * this unit resolves hostnames with getaddrinfo AT HOP START — the
45
+ * dns.lookup precedent (scr_dgram.c): synchronous resolution, first
46
+ * answer wins; failures ride the socket's deferred
47
+ * "getaddrinfo ENOTFOUND host" error so the rejection's cause is
48
+ * Node's exact shape. TLS handshakes verify/SNI against the URL
49
+ * HOSTNAME while the socket dials the resolved IP.
50
+ * - Proxies, matched to Node: undici's global fetch IGNORES http_proxy/
51
+ * https_proxy unless NODE_USE_ENV_PROXY=1 opts in (Node 24's
52
+ * EnvHttpProxyAgent). Opted in, http:// targets relay through the
53
+ * proxy as absolute-URI requests (the classic forward-proxy wire form;
54
+ * undici tunnels CONNECT, but the fixture proxy counts either form
55
+ * identically), no_proxy exclusions honored. https-over-proxy
56
+ * (CONNECT) is out of the slice.
57
+ * - AbortSignal is wired exactly as before (init.signal, or the
58
+ * Request's): an already-aborted signal rejects with its reason before
59
+ * any transfer starts; aborting a live transfer destroys the hop's
60
+ * connection through host.abort (silent on the C side — the glue owns
61
+ * the rejection); AbortSignal.timeout's TimeoutError rides the island
62
+ * timer machinery in scr_web.c.
63
+ * - Error causes, Node's shapes: connect ECONNREFUSED ip:port /
64
+ * getaddrinfo ENOTFOUND host pass through from the net layer with
65
+ * their codes; a server that dies before the response head maps to
66
+ * undici's cause exactly — "other side closed", code UND_ERR_SOCKET
67
+ * (the curl bridge could only offer curl's own string there).
68
+ * - Ownership: each transfer is refcounted — the live registry holds +1
69
+ * and every minted listener closure's box holds +1; settling releases
70
+ * the engine callback object and the hop client, and teardown
71
+ * (registered with the island) frees whatever is still live before the
72
+ * engine goes down, so the island audit stays zero. */
73
+ #ifdef SCR_DYNAMIC
74
+
75
+ #include "scr_runtime.h"
76
+ #include "scr_url_internal.h"
77
+
78
+ #include <stdio.h>
79
+ #include <stdlib.h>
80
+ #include <string.h>
81
+
82
+ #include <zlib.h>
83
+
84
+ #include "quickjs.h"
85
+
86
+ static void fx_oom(void) {
87
+ fputs("scriptc: out of memory\n", stderr);
88
+ abort();
89
+ }
90
+
91
+ /* ── small string helpers (ScrStr names are not NUL-guaranteed at the
92
+ * lengths we compare, so everything is len-aware, ASCII-case-folded) ── */
93
+
94
+ static bool fx_eq_ci(const char *a, size_t alen, const char *b) {
95
+ size_t blen = strlen(b);
96
+ if (alen != blen) return false;
97
+ for (size_t i = 0; i < alen; i++) {
98
+ char c = a[i];
99
+ if (c >= 'A' && c <= 'Z') c = (char)(c - 'A' + 'a');
100
+ if (c != b[i]) return false;
101
+ }
102
+ return true;
103
+ }
104
+
105
+ static bool fx_str_is(const ScrStr *s, const char *lit) { return fx_eq_ci(s->data, s->len, lit); }
106
+
107
+ /* Does the flat [name, value, ...] pairs array carry `name`? */
108
+ static bool fx_pairs_have(ScrArr *pairs, const char *name) {
109
+ size_t n = (size_t)scr_arr_len(pairs);
110
+ bool found = false;
111
+ for (size_t i = 0; i + 1 < n && !found; i += 2) {
112
+ ScrStr *nm = (ScrStr *)scr_arr_get_ref(pairs, (double)i);
113
+ found = fx_eq_ci(nm->data, nm->len, name);
114
+ scr_str_release(nm);
115
+ }
116
+ return found;
117
+ }
118
+
119
+ static void fx_pairs_push(ScrArr *pairs, const char *name, const char *value, size_t vlen) {
120
+ scr_arr_push_ref(pairs, scr_str_new(name, strlen(name)));
121
+ scr_arr_push_ref(pairs, scr_str_new(value, vlen));
122
+ }
123
+
124
+ /* ── transfers ───────────────────────────────────────────────────────── */
125
+
126
+ typedef struct FxTransfer {
127
+ size_t rc; /* the live registry's +1 plus one per minted listener box */
128
+ int id;
129
+ JSContext *ctx;
130
+ JSValue cbs; /* { onResponse, onData, onEnd, onError } — owned while live */
131
+ bool cbs_live;
132
+ /* the request, as it evolves across redirect hops */
133
+ ScrStr *method; /* owned */
134
+ ScrArr *headers; /* flat [name, value, ...] user pairs — owned */
135
+ ScrBytes *body; /* owned, NULL = none */
136
+ ScrUrl *url; /* the CURRENT hop's URL — owned */
137
+ int hops;
138
+ bool redirected;
139
+ /* the live hop */
140
+ ScrHttpClientReq *client; /* +1, NULL between/after hops */
141
+ bool responded; /* onResponse fired (the final response) */
142
+ bool cancelled; /* island aborted/cancelled: die silently */
143
+ bool done; /* settled: no callback ever fires again */
144
+ /* response decompression */
145
+ bool inflating;
146
+ z_stream zs;
147
+ struct FxTransfer *next;
148
+ } FxTransfer;
149
+
150
+ static FxTransfer *fx_live = NULL; /* registry: +1 each */
151
+ static size_t fx_nlive = 0;
152
+ static int fx_next_id = 1;
153
+
154
+ static FxTransfer *fx_retain(FxTransfer *t) {
155
+ t->rc++;
156
+ return t;
157
+ }
158
+
159
+ static void fx_release(FxTransfer *t) {
160
+ if (--t->rc > 0) return;
161
+ scr_str_release(t->method);
162
+ scr_arr_release(t->headers);
163
+ if (t->body) scr_bytes_release(t->body);
164
+ if (t->url) scr_url_release(t->url);
165
+ if (t->client) scr_http_client_release(t->client);
166
+ if (t->inflating) inflateEnd(&t->zs);
167
+ if (t->cbs_live) JS_FreeValue(t->ctx, t->cbs);
168
+ free(t);
169
+ }
170
+
171
+ static void *fx_retain_v(void *p) { return fx_retain((FxTransfer *)p); }
172
+ static void fx_release_v(void *p) { fx_release((FxTransfer *)p); }
173
+
174
+ /* Settle: the transfer is over (delivered, failed, or aborted) — drop the
175
+ * hop client, free the engine callbacks, and leave the registry. Idempotent. */
176
+ static void fx_settle(FxTransfer *t) {
177
+ if (t->done) return;
178
+ t->done = true;
179
+ if (t->client) {
180
+ scr_http_client_release(t->client);
181
+ t->client = NULL;
182
+ }
183
+ if (t->cbs_live) {
184
+ JS_FreeValue(t->ctx, t->cbs);
185
+ t->cbs = JS_UNDEFINED;
186
+ t->cbs_live = false;
187
+ }
188
+ for (FxTransfer **link = &fx_live; *link; link = &(*link)->next) {
189
+ if (*link == t) {
190
+ *link = t->next;
191
+ fx_nlive--;
192
+ fx_release(t); /* the registry's +1 */
193
+ return;
194
+ }
195
+ }
196
+ }
197
+
198
+ /* Calls one callback off the cbs object, swallowing (but reporting) any
199
+ * engine exception — the callbacks are our own glue and must not throw.
200
+ * Entered from the net dispatch station (the main stack): re-anchor the
201
+ * engine's stack-overflow check first, the every-island-entry rule. */
202
+ static void fx_call(FxTransfer *t, const char *name, int argc, JSValueConst *argv) {
203
+ if (!t->cbs_live) return;
204
+ scr_island_host_enter();
205
+ JSContext *ctx = t->ctx;
206
+ JSValue fn = JS_GetPropertyStr(ctx, t->cbs, name);
207
+ JSValue r = JS_Call(ctx, fn, JS_UNDEFINED, argc, argv);
208
+ JS_FreeValue(ctx, fn);
209
+ if (JS_IsException(r)) {
210
+ JSValue e = JS_GetException(ctx);
211
+ const char *msg = JS_ToCString(ctx, e);
212
+ fprintf(stderr, "scriptc: fetch internal callback '%s' threw: %s\n", name,
213
+ msg ? msg : "?");
214
+ if (msg) JS_FreeCString(ctx, msg);
215
+ JS_FreeValue(ctx, e);
216
+ return;
217
+ }
218
+ JS_FreeValue(ctx, r);
219
+ }
220
+
221
+ /* Network failure → onError(detail, code) → the glue's TypeError "fetch
222
+ * failed" with the classified cause. Settles the transfer. */
223
+ static void fx_error(FxTransfer *t, const char *detail, const char *code) {
224
+ if (t->done || t->cancelled) {
225
+ fx_settle(t);
226
+ return;
227
+ }
228
+ JSContext *ctx = t->ctx;
229
+ JSValue args[2];
230
+ args[0] = JS_NewString(ctx, detail);
231
+ args[1] = code ? JS_NewString(ctx, code) : JS_UNDEFINED;
232
+ fx_call(t, "onError", 2, (JSValueConst *)args);
233
+ JS_FreeValue(ctx, args[0]);
234
+ JS_FreeValue(ctx, args[1]);
235
+ fx_settle(t);
236
+ }
237
+
238
+ /* ── minted listener closures (caps[0] boxes the transfer) ───────────── */
239
+
240
+ static ScrClosure *fx_closure(FxTransfer *t, void *fn) {
241
+ /* fn doubles as the closure's own entry: zero-payload lists (req 'end')
242
+ * call cb->fn(cb) directly, payload lists call the fn stored beside the
243
+ * registration — both routes land on the same handler here. */
244
+ ScrClosure *cb = scr_closure_new(fn, 1);
245
+ ScrBox *box = scr_box_new_obj(&fx_retain_v, &fx_release_v, NULL);
246
+ scr_box_set_ref(box, fx_retain(t));
247
+ cb->caps[0] = box;
248
+ return cb;
249
+ }
250
+
251
+ /* +1 — release after use. */
252
+ static FxTransfer *fx_from(ScrClosure *cb) { return (FxTransfer *)scr_box_get_ref(cb->caps[0]); }
253
+
254
+ /* ── URL helpers ─────────────────────────────────────────────────────── */
255
+
256
+ /* scheme://[userinfo@]host[:port]path[?query][#fragment] — response.url
257
+ * and the proxy's absolute-URI form exclude the fragment (Node). */
258
+ static ScrStr *fx_url_serialize(const ScrUrl *u, bool with_fragment) {
259
+ size_t cap = u->scheme->len + u->userinfo->len + u->host->len + u->port->len +
260
+ u->path->len + u->query->len + u->fragment->len + 8;
261
+ char *buf = malloc(cap);
262
+ if (!buf) fx_oom();
263
+ size_t n = 0;
264
+ memcpy(buf + n, u->scheme->data, u->scheme->len);
265
+ n += u->scheme->len;
266
+ buf[n++] = ':';
267
+ if (u->has_authority) {
268
+ buf[n++] = '/';
269
+ buf[n++] = '/';
270
+ if (u->userinfo->len > 0) {
271
+ memcpy(buf + n, u->userinfo->data, u->userinfo->len);
272
+ n += u->userinfo->len;
273
+ buf[n++] = '@';
274
+ }
275
+ memcpy(buf + n, u->host->data, u->host->len);
276
+ n += u->host->len;
277
+ if (u->port->len > 0) {
278
+ buf[n++] = ':';
279
+ memcpy(buf + n, u->port->data, u->port->len);
280
+ n += u->port->len;
281
+ }
282
+ }
283
+ if (u->path->len > 0) {
284
+ memcpy(buf + n, u->path->data, u->path->len);
285
+ n += u->path->len;
286
+ } else {
287
+ buf[n++] = '/';
288
+ }
289
+ memcpy(buf + n, u->query->data, u->query->len);
290
+ n += u->query->len;
291
+ if (with_fragment) {
292
+ memcpy(buf + n, u->fragment->data, u->fragment->len);
293
+ n += u->fragment->len;
294
+ }
295
+ ScrStr *out = scr_str_new(buf, n);
296
+ free(buf);
297
+ return out;
298
+ }
299
+
300
+ /* Parse an absolute URL, answering NULL (static exception CLEARED) instead
301
+ * of throwing — this unit runs inside engine host calls and the net
302
+ * dispatch, where a pending static exception belongs to nobody. */
303
+ static ScrUrl *fx_url_parse(ScrStr *s) {
304
+ ScrUrl *u = scr_url_new(s);
305
+ if (!u) scr_exc_clear();
306
+ return u;
307
+ }
308
+
309
+ /* Resolve a Location header against the current hop's URL. Handles the
310
+ * absolute form plus the relative shapes real servers send (//authority,
311
+ * /rooted, ?query, plain relative); everything reparses through the
312
+ * WHATWG parser so dot segments and encoding normalize consistently. */
313
+ static ScrUrl *fx_resolve(const ScrUrl *base, const ScrStr *loc) {
314
+ ScrStr *abs_try = scr_str_new(loc->data, loc->len);
315
+ ScrUrl *u = fx_url_parse(abs_try);
316
+ scr_str_release(abs_try);
317
+ if (u) return u;
318
+ /* relative: assemble scheme://authority + resolved path/query */
319
+ size_t cap = base->scheme->len + base->userinfo->len + base->host->len + base->port->len +
320
+ base->path->len + base->query->len + loc->len + 16;
321
+ char *buf = malloc(cap);
322
+ if (!buf) fx_oom();
323
+ size_t n = 0;
324
+ memcpy(buf + n, base->scheme->data, base->scheme->len);
325
+ n += base->scheme->len;
326
+ buf[n++] = ':';
327
+ if (loc->len >= 2 && loc->data[0] == '/' && loc->data[1] == '/') {
328
+ memcpy(buf + n, loc->data, loc->len);
329
+ n += loc->len;
330
+ } else {
331
+ buf[n++] = '/';
332
+ buf[n++] = '/';
333
+ if (base->userinfo->len > 0) {
334
+ memcpy(buf + n, base->userinfo->data, base->userinfo->len);
335
+ n += base->userinfo->len;
336
+ buf[n++] = '@';
337
+ }
338
+ memcpy(buf + n, base->host->data, base->host->len);
339
+ n += base->host->len;
340
+ if (base->port->len > 0) {
341
+ buf[n++] = ':';
342
+ memcpy(buf + n, base->port->data, base->port->len);
343
+ n += base->port->len;
344
+ }
345
+ if (loc->len > 0 && loc->data[0] == '/') {
346
+ memcpy(buf + n, loc->data, loc->len);
347
+ n += loc->len;
348
+ } else if (loc->len > 0 && loc->data[0] == '?') {
349
+ memcpy(buf + n, base->path->data, base->path->len);
350
+ n += base->path->len;
351
+ memcpy(buf + n, loc->data, loc->len);
352
+ n += loc->len;
353
+ } else {
354
+ /* plain relative: replace everything after the path's last '/' */
355
+ size_t keep = 0;
356
+ for (size_t i = 0; i < base->path->len; i++) {
357
+ if (base->path->data[i] == '/') keep = i + 1;
358
+ }
359
+ memcpy(buf + n, base->path->data, keep);
360
+ n += keep;
361
+ if (keep == 0) buf[n++] = '/';
362
+ memcpy(buf + n, loc->data, loc->len);
363
+ n += loc->len;
364
+ }
365
+ }
366
+ ScrStr *s = scr_str_new(buf, n);
367
+ free(buf);
368
+ ScrUrl *out = fx_url_parse(s);
369
+ scr_str_release(s);
370
+ return out;
371
+ }
372
+
373
+ /* The URL host with IPv6 brackets stripped (the dial/SNI form). +1. */
374
+ static ScrStr *fx_bare_host(const ScrStr *host) {
375
+ if (host->len >= 2 && host->data[0] == '[' && host->data[host->len - 1] == ']') {
376
+ return scr_str_new(host->data + 1, host->len - 2);
377
+ }
378
+ return scr_str_retain((ScrStr *)host);
379
+ }
380
+
381
+ static int fx_url_port(const ScrUrl *u, int deflt) {
382
+ if (u->port->len == 0) return deflt;
383
+ int p = 0;
384
+ for (size_t i = 0; i < u->port->len; i++) p = p * 10 + (u->port->data[i] - '0');
385
+ return p;
386
+ }
387
+
388
+ /* ── env proxy (NODE_USE_ENV_PROXY=1, undici's EnvHttpProxyAgent) ────── */
389
+
390
+ static const char *fx_env2(const char *lower, const char *upper) {
391
+ const char *v = getenv(lower);
392
+ if (v == NULL || v[0] == '\0') v = getenv(upper);
393
+ return (v != NULL && v[0] != '\0') ? v : NULL;
394
+ }
395
+
396
+ /* no_proxy: comma/space-separated host suffixes; "*" excludes everything;
397
+ * a leading dot is stripped; entries match the host exactly or at a dot
398
+ * boundary. Port qualifiers (host:port) require the port to match. */
399
+ static bool fx_no_proxy_match(const char *list, const ScrStr *host, int port) {
400
+ const char *p = list;
401
+ while (*p) {
402
+ while (*p == ',' || *p == ' ' || *p == '\t') p++;
403
+ const char *start = p;
404
+ while (*p && *p != ',' && *p != ' ' && *p != '\t') p++;
405
+ size_t len = (size_t)(p - start);
406
+ if (len == 0) continue;
407
+ if (len == 1 && start[0] == '*') return true;
408
+ /* split a :port qualifier */
409
+ size_t hlen = len;
410
+ long eport = -1;
411
+ for (size_t i = 0; i < len; i++) {
412
+ if (start[i] == ':') {
413
+ hlen = i;
414
+ eport = strtol(start + i + 1, NULL, 10);
415
+ break;
416
+ }
417
+ }
418
+ if (hlen > 0 && start[0] == '.') {
419
+ start++;
420
+ hlen--;
421
+ }
422
+ if (hlen == 0) continue;
423
+ if (eport >= 0 && eport != port) continue;
424
+ if (host->len == hlen) {
425
+ bool eq = true;
426
+ for (size_t i = 0; i < hlen && eq; i++) {
427
+ char a = host->data[i], b = start[i];
428
+ if (a >= 'A' && a <= 'Z') a = (char)(a - 'A' + 'a');
429
+ if (b >= 'A' && b <= 'Z') b = (char)(b - 'A' + 'a');
430
+ eq = a == b;
431
+ }
432
+ if (eq) return true;
433
+ } else if (host->len > hlen && host->data[host->len - hlen - 1] == '.') {
434
+ bool eq = true;
435
+ for (size_t i = 0; i < hlen && eq; i++) {
436
+ char a = host->data[host->len - hlen + i], b = start[i];
437
+ if (a >= 'A' && a <= 'Z') a = (char)(a - 'A' + 'a');
438
+ if (b >= 'A' && b <= 'Z') b = (char)(b - 'A' + 'a');
439
+ eq = a == b;
440
+ }
441
+ if (eq) return true;
442
+ }
443
+ }
444
+ return false;
445
+ }
446
+
447
+ /* The proxy for this hop's target, parsed (+1), or NULL for direct. */
448
+ static ScrUrl *fx_proxy_for(const ScrUrl *target, bool https, int target_port) {
449
+ const char *optin = getenv("NODE_USE_ENV_PROXY");
450
+ if (optin == NULL || strcmp(optin, "1") != 0) return NULL;
451
+ const char *proxy = https ? fx_env2("https_proxy", "HTTPS_PROXY")
452
+ : fx_env2("http_proxy", "HTTP_PROXY");
453
+ if (proxy == NULL) return NULL;
454
+ const char *no = fx_env2("no_proxy", "NO_PROXY");
455
+ if (no != NULL && fx_no_proxy_match(no, target->host, target_port)) return NULL;
456
+ ScrStr *ps = scr_str_new(proxy, strlen(proxy));
457
+ ScrUrl *u = fx_url_parse(ps);
458
+ scr_str_release(ps);
459
+ return u;
460
+ }
461
+
462
+ /* ── DNS (the dns.lookup precedent: getaddrinfo at hop start) ────────── */
463
+
464
+ /* The address to DIAL for `host` (+1): brackets strip, then the shared
465
+ * blocking lookup (scr_net.c) — IP literals and localhost pass through,
466
+ * hostnames resolve first-answer, and resolution failure answers the
467
+ * HOSTNAME unchanged so the dial's deferred "getaddrinfo ENOTFOUND host"
468
+ * error is Node's exact cause. */
469
+ static ScrStr *fx_dial_host(const ScrStr *host) {
470
+ ScrStr *bare = fx_bare_host(host);
471
+ ScrStr *out = scr_net_blocking_lookup(bare);
472
+ scr_str_release(bare);
473
+ return out;
474
+ }
475
+
476
+ /* ── the hop ─────────────────────────────────────────────────────────── */
477
+
478
+ static void fx_on_response(ScrClosure *cb, ScrHttpReq *res /*+1*/);
479
+ static void fx_on_client_error(ScrClosure *cb, ScrStr *msg /*borrowed*/);
480
+
481
+ static void fx_start_hop(FxTransfer *t) {
482
+ ScrUrl *u = t->url;
483
+ bool https = fx_str_is(u->scheme, "https");
484
+ int default_port = https ? 443 : 80;
485
+ int port = fx_url_port(u, default_port);
486
+ ScrUrl *proxy = https ? NULL : fx_proxy_for(u, https, port);
487
+
488
+ /* undici's request head, in undici's order: host, connection, the user
489
+ * headers, then the fetch defaults for whatever the user left unset. */
490
+ size_t nuser = (size_t)scr_arr_len(t->headers);
491
+ ScrArr *pairs = scr_arr_new(SCR_ELEM_STR, nuser + 16);
492
+ if (!fx_pairs_have(t->headers, "host")) {
493
+ char authority[300];
494
+ int alen;
495
+ if (port != default_port) {
496
+ alen = snprintf(authority, sizeof authority, "%.*s:%d", (int)u->host->len, u->host->data, port);
497
+ } else {
498
+ alen = snprintf(authority, sizeof authority, "%.*s", (int)u->host->len, u->host->data);
499
+ }
500
+ fx_pairs_push(pairs, "host", authority, (size_t)alen);
501
+ }
502
+ if (!fx_pairs_have(t->headers, "connection")) {
503
+ fx_pairs_push(pairs, "connection", "keep-alive", 10);
504
+ }
505
+ for (size_t i = 0; i + 1 < nuser; i += 2) {
506
+ scr_arr_push_ref(pairs, scr_arr_get_ref(t->headers, (double)i));
507
+ scr_arr_push_ref(pairs, scr_arr_get_ref(t->headers, (double)(i + 1)));
508
+ }
509
+ if (!fx_pairs_have(t->headers, "accept")) fx_pairs_push(pairs, "accept", "*/*", 3);
510
+ if (!fx_pairs_have(t->headers, "accept-language")) fx_pairs_push(pairs, "accept-language", "*", 1);
511
+ if (!fx_pairs_have(t->headers, "sec-fetch-mode")) fx_pairs_push(pairs, "sec-fetch-mode", "cors", 4);
512
+ if (!fx_pairs_have(t->headers, "user-agent")) fx_pairs_push(pairs, "user-agent", "node", 4);
513
+ if (!fx_pairs_have(t->headers, "accept-encoding")) {
514
+ fx_pairs_push(pairs, "accept-encoding", "gzip, deflate", 13);
515
+ }
516
+
517
+ /* the request-target and the wire to dial */
518
+ ScrStr *path;
519
+ ScrStr *dial;
520
+ int dial_port;
521
+ if (proxy != NULL) {
522
+ path = fx_url_serialize(u, false); /* absolute-URI through the proxy */
523
+ dial = fx_dial_host(proxy->host);
524
+ dial_port = fx_url_port(proxy, 80);
525
+ } else {
526
+ if (u->query->len > 0) {
527
+ size_t plen = (u->path->len > 0 ? u->path->len : 1) + u->query->len;
528
+ char *pb = malloc(plen);
529
+ if (!pb) fx_oom();
530
+ size_t n = 0;
531
+ if (u->path->len > 0) {
532
+ memcpy(pb, u->path->data, u->path->len);
533
+ n = u->path->len;
534
+ } else {
535
+ pb[n++] = '/';
536
+ }
537
+ memcpy(pb + n, u->query->data, u->query->len);
538
+ n += u->query->len;
539
+ path = scr_str_new(pb, n);
540
+ free(pb);
541
+ } else {
542
+ path = u->path->len > 0 ? scr_str_retain(u->path) : scr_str_new("/", 1);
543
+ }
544
+ dial = fx_dial_host(u->host);
545
+ dial_port = port;
546
+ }
547
+
548
+ ScrHttpClientReq *c;
549
+ if (https) {
550
+ ScrStr *sni = fx_bare_host(u->host);
551
+ void *cli = scr_tls_fetch_client_ctx(sni, true);
552
+ scr_str_release(sni);
553
+ c = scr_http_request_ex(dial, dial_port, path, t->method, 0, pairs, false, NULL, NULL,
554
+ 443, &scr_tls_fetch_client_wrap, cli);
555
+ } else {
556
+ c = scr_http_request_ex(dial, dial_port, path, t->method, 0, pairs, false, NULL, NULL,
557
+ 80, NULL, NULL);
558
+ }
559
+ scr_str_release(dial);
560
+ scr_str_release(path);
561
+ scr_arr_release(pairs);
562
+ if (proxy) scr_url_release(proxy);
563
+
564
+ t->client = c; /* the constructor's +1 */
565
+ scr_http_client_on_response(c, fx_closure(t, (void *)&fx_on_response), &fx_on_response, true);
566
+ scr_http_client_on_error(c, fx_closure(t, (void *)&fx_on_client_error), &fx_on_client_error, false);
567
+ if (t->body != NULL) scr_http_client_end_bytes(c, t->body);
568
+ else scr_http_client_end(c);
569
+ }
570
+
571
+ /* ── redirects ───────────────────────────────────────────────────────── */
572
+
573
+ static void fx_strip_header(ScrArr **headers, const char *name) {
574
+ ScrArr *old = *headers;
575
+ size_t n = (size_t)scr_arr_len(old);
576
+ ScrArr *out = scr_arr_new(SCR_ELEM_STR, n);
577
+ for (size_t i = 0; i + 1 < n; i += 2) {
578
+ ScrStr *nm = (ScrStr *)scr_arr_get_ref(old, (double)i);
579
+ if (fx_eq_ci(nm->data, nm->len, name)) {
580
+ scr_str_release(nm);
581
+ continue;
582
+ }
583
+ scr_arr_push_ref(out, nm);
584
+ scr_arr_push_ref(out, scr_arr_get_ref(old, (double)(i + 1)));
585
+ }
586
+ scr_arr_release(old);
587
+ *headers = out;
588
+ }
589
+
590
+ /* Follows one redirect hop: rewrites the request per the fetch spec and
591
+ * dials the next URL. Consumes nothing; the caller drops res/client. */
592
+ static bool fx_redirect(FxTransfer *t, int status, const ScrStr *loc) {
593
+ if (t->hops >= 20) {
594
+ fx_error(t, "redirect count exceeded", NULL);
595
+ return false;
596
+ }
597
+ t->hops++;
598
+ t->redirected = true;
599
+ ScrUrl *next = fx_resolve(t->url, loc);
600
+ if (next == NULL ||
601
+ !(fx_str_is(next->scheme, "http") || fx_str_is(next->scheme, "https"))) {
602
+ if (next) scr_url_release(next);
603
+ fx_error(t, "invalid redirect URL", NULL);
604
+ return false;
605
+ }
606
+ /* 303 rewrites everything but GET/HEAD to GET; 301/302 rewrite POST —
607
+ * the body and its content-* headers drop with the rewrite. */
608
+ bool is_get = fx_str_is(t->method, "GET");
609
+ bool is_head = fx_str_is(t->method, "HEAD");
610
+ if ((status == 303 && !is_get && !is_head) ||
611
+ ((status == 301 || status == 302) && fx_str_is(t->method, "POST"))) {
612
+ scr_str_release(t->method);
613
+ t->method = scr_str_new("GET", 3);
614
+ if (t->body) {
615
+ scr_bytes_release(t->body);
616
+ t->body = NULL;
617
+ }
618
+ fx_strip_header(&t->headers, "content-type");
619
+ fx_strip_header(&t->headers, "content-length");
620
+ fx_strip_header(&t->headers, "content-encoding");
621
+ fx_strip_header(&t->headers, "content-language");
622
+ fx_strip_header(&t->headers, "content-location");
623
+ }
624
+ /* cross-origin hop: credentials do not follow (the fetch spec's
625
+ * authorization rule; cookies are not modeled as ambient state). */
626
+ bool same_origin = t->url->host->len == next->host->len &&
627
+ memcmp(t->url->host->data, next->host->data, next->host->len) == 0 &&
628
+ fx_url_port(t->url, 0) == fx_url_port(next, 0) &&
629
+ t->url->scheme->len == next->scheme->len &&
630
+ memcmp(t->url->scheme->data, next->scheme->data, next->scheme->len) == 0;
631
+ if (!same_origin) {
632
+ fx_strip_header(&t->headers, "authorization");
633
+ fx_strip_header(&t->headers, "proxy-authorization");
634
+ fx_strip_header(&t->headers, "cookie");
635
+ }
636
+ scr_url_release(t->url);
637
+ t->url = next;
638
+ return true;
639
+ }
640
+
641
+ /* ── response delivery ───────────────────────────────────────────────── */
642
+
643
+ static void fx_emit_chunk(FxTransfer *t, const uint8_t *data, size_t len) {
644
+ if (len == 0) return;
645
+ JSValue chunk = JS_NewUint8ArrayCopy(t->ctx, data, len);
646
+ fx_call(t, "onData", 1, (JSValueConst *)&chunk);
647
+ JS_FreeValue(t->ctx, chunk);
648
+ }
649
+
650
+ static void fx_on_data(ScrClosure *cb, ScrBytes *chunk /*borrowed*/) {
651
+ FxTransfer *t = fx_from(cb);
652
+ if (t == NULL) return;
653
+ if (t->done || t->cancelled || !t->responded) {
654
+ fx_release(t);
655
+ return;
656
+ }
657
+ if (!t->inflating) {
658
+ fx_emit_chunk(t, chunk->data, chunk->len);
659
+ fx_release(t);
660
+ return;
661
+ }
662
+ t->zs.next_in = (Bytef *)chunk->data;
663
+ t->zs.avail_in = (uInt)chunk->len;
664
+ unsigned char out[16384];
665
+ while (t->zs.avail_in > 0 && !t->done) {
666
+ t->zs.next_out = out;
667
+ t->zs.avail_out = sizeof out;
668
+ int r = inflate(&t->zs, Z_NO_FLUSH);
669
+ size_t produced = sizeof out - t->zs.avail_out;
670
+ if (produced > 0) fx_emit_chunk(t, out, produced);
671
+ if (r == Z_STREAM_END) break; /* trailing bytes (if any) are dropped */
672
+ if (r != Z_OK && r != Z_BUF_ERROR) {
673
+ /* corrupt encoding: the body errors (the glue turns a post-resolve
674
+ * onError into controller.error — undici's terminated shape) */
675
+ const char *detail = t->zs.msg ? t->zs.msg : "invalid compressed body";
676
+ ScrHttpClientReq *c = t->client;
677
+ if (c) scr_http_client_destroy(c);
678
+ fx_error(t, detail, NULL);
679
+ break;
680
+ }
681
+ if (r == Z_BUF_ERROR && produced == 0) break; /* need more input */
682
+ }
683
+ fx_release(t);
684
+ }
685
+
686
+ static void fx_on_end(ScrClosure *cb) {
687
+ FxTransfer *t = fx_from(cb);
688
+ if (t == NULL) return;
689
+ if (t->done || t->cancelled) {
690
+ fx_release(t);
691
+ return;
692
+ }
693
+ fx_call(t, "onEnd", 0, NULL);
694
+ fx_settle(t);
695
+ fx_release(t);
696
+ }
697
+
698
+ /* Mid-body death ('aborted' on the response): the body errors. */
699
+ static void fx_on_res_error(ScrClosure *cb, ScrStr *msg /*borrowed*/) {
700
+ FxTransfer *t = fx_from(cb);
701
+ if (t == NULL) return;
702
+ if (t->done || t->cancelled) {
703
+ fx_release(t);
704
+ return;
705
+ }
706
+ fx_error(t, msg->len > 0 ? msg->data : "aborted", NULL);
707
+ fx_release(t);
708
+ }
709
+
710
+ static void fx_on_response(ScrClosure *cb, ScrHttpReq *res /*+1*/) {
711
+ FxTransfer *t = fx_from(cb);
712
+ if (t == NULL) {
713
+ scr_http_req_release(res);
714
+ return;
715
+ }
716
+ if (t->done || t->cancelled) {
717
+ scr_http_req_release(res);
718
+ fx_release(t);
719
+ return;
720
+ }
721
+ int status = (int)scr_http_req_status(res);
722
+
723
+ /* a redirect hop? (Location present, a redirect status) */
724
+ if (status == 301 || status == 302 || status == 303 || status == 307 || status == 308) {
725
+ ScrStr *locname = scr_str_new("location", 8);
726
+ ScrStr *loc = scr_http_req_header(res, locname);
727
+ scr_str_release(locname);
728
+ if (loc != NULL) {
729
+ /* drop this hop's connection (its body never reaches the island) */
730
+ ScrHttpClientReq *old = t->client;
731
+ t->client = NULL;
732
+ bool go = fx_redirect(t, status, loc);
733
+ scr_str_release(loc);
734
+ if (old) {
735
+ scr_http_client_destroy(old);
736
+ scr_http_client_release(old);
737
+ }
738
+ if (go) fx_start_hop(t);
739
+ scr_http_req_release(res);
740
+ fx_release(t);
741
+ return;
742
+ }
743
+ /* a FINAL 3xx (no Location) resolves with its own body, like Node —
744
+ * the curl bridge documented this corner away; this unit delivers it */
745
+ }
746
+
747
+ t->responded = true;
748
+
749
+ /* content-encoding: gzip/x-gzip/deflate inflate transparently (zlib's
750
+ * 15+32 auto-detects the gzip and zlib framings) */
751
+ {
752
+ ScrStr *cename = scr_str_new("content-encoding", 16);
753
+ ScrStr *ce = scr_http_req_header(res, cename);
754
+ scr_str_release(cename);
755
+ if (ce != NULL) {
756
+ if (fx_str_is(ce, "gzip") || fx_str_is(ce, "x-gzip") || fx_str_is(ce, "deflate")) {
757
+ memset(&t->zs, 0, sizeof t->zs);
758
+ if (inflateInit2(&t->zs, 15 + 32) == Z_OK) t->inflating = true;
759
+ }
760
+ scr_str_release(ce);
761
+ }
762
+ }
763
+
764
+ JSContext *ctx = t->ctx;
765
+ ScrArr *raw = scr_http_req_raw_headers(res);
766
+ size_t nraw = (size_t)scr_arr_len(raw);
767
+ JSValue hdrs = JS_NewArray(ctx);
768
+ for (size_t i = 0; i < nraw; i++) {
769
+ ScrStr *s = (ScrStr *)scr_arr_get_ref(raw, (double)i);
770
+ JS_SetPropertyUint32(ctx, hdrs, (uint32_t)i, JS_NewStringLen(ctx, s->data, s->len));
771
+ scr_str_release(s);
772
+ }
773
+ scr_arr_release(raw);
774
+ ScrStr *stext = scr_http_req_status_message(res);
775
+ ScrStr *final_url = fx_url_serialize(t->url, false);
776
+ JSValue argv[5] = {
777
+ JS_NewInt32(ctx, status),
778
+ JS_NewStringLen(ctx, stext ? stext->data : "", stext ? stext->len : 0),
779
+ hdrs,
780
+ JS_NewStringLen(ctx, final_url->data, final_url->len),
781
+ JS_NewBool(ctx, t->redirected),
782
+ };
783
+ if (stext) scr_str_release(stext);
784
+ scr_str_release(final_url);
785
+ fx_call(t, "onResponse", 5, argv);
786
+ for (int i = 0; i < 5; i++) JS_FreeValue(ctx, argv[i]);
787
+
788
+ /* body listeners (registered inside the 'response' emit — the parser
789
+ * delivers body bytes only after this returns, ended bodies fire 'end'
790
+ * right behind us) */
791
+ scr_http_req_on_data(res, fx_closure(t, (void *)&fx_on_data), &fx_on_data, false);
792
+ scr_http_req_on_end(res, fx_closure(t, (void *)&fx_on_end), false);
793
+ scr_http_req_on_error(res, fx_closure(t, (void *)&fx_on_res_error), &fx_on_res_error, false);
794
+
795
+ scr_http_req_release(res);
796
+ fx_release(t);
797
+ }
798
+
799
+ /* Pre-response failure on the hop client: classify into Node's causes. */
800
+ static void fx_on_client_error(ScrClosure *cb, ScrStr *msg /*borrowed*/) {
801
+ FxTransfer *t = fx_from(cb);
802
+ if (t == NULL) return;
803
+ if (t->done || t->cancelled || t->responded) {
804
+ fx_release(t);
805
+ return;
806
+ }
807
+ const char *detail = msg->data;
808
+ const char *code = NULL;
809
+ char codebuf[32];
810
+ if (msg->len > 8 && memcmp(detail, "connect E", 9) == 0) {
811
+ /* "connect ECONNREFUSED ip:port" and family: the code is the token */
812
+ const char *s = detail + 8;
813
+ size_t n = 0;
814
+ while (s[n] != '\0' && s[n] != ' ' && n < sizeof codebuf - 1) n++;
815
+ memcpy(codebuf, s, n);
816
+ codebuf[n] = '\0';
817
+ code = codebuf;
818
+ } else if (msg->len > 12 && memcmp(detail, "getaddrinfo E", 13) == 0) {
819
+ const char *s = detail + 12;
820
+ size_t n = 0;
821
+ while (s[n] != '\0' && s[n] != ' ' && n < sizeof codebuf - 1) n++;
822
+ memcpy(codebuf, s, n);
823
+ codebuf[n] = '\0';
824
+ code = codebuf;
825
+ } else if (fx_eq_ci(detail, msg->len, "socket hang up")) {
826
+ /* undici's cause for a server that died before the response head */
827
+ detail = "other side closed";
828
+ code = "UND_ERR_SOCKET";
829
+ }
830
+ fx_error(t, detail, code);
831
+ fx_release(t);
832
+ }
833
+
834
+ /* ── host functions (called by the fetch glue, inside the engine) ────── */
835
+
836
+ /* host.start({url, method, headers: [n,v,...], body: Uint8Array|undefined},
837
+ * cbs) → transfer id. Everything is copied out of the engine before the
838
+ * net stack sees it. An unparsable URL throws the engine TypeError the
839
+ * promise executor turns into Node's rejection shape. */
840
+ static JSValue fx_host_start(JSContext *ctx, JSValueConst this_val, int argc,
841
+ JSValueConst *argv) {
842
+ (void)this_val;
843
+ (void)argc;
844
+ JSValueConst req = argv[0];
845
+
846
+ JSValue urlv = JS_GetPropertyStr(ctx, req, "url");
847
+ const char *url = JS_ToCString(ctx, urlv);
848
+ JS_FreeValue(ctx, urlv);
849
+ if (!url) return JS_EXCEPTION;
850
+ ScrStr *urlstr = scr_str_new(url, strlen(url));
851
+ ScrUrl *u = fx_url_parse(urlstr);
852
+ scr_str_release(urlstr);
853
+ if (u == NULL) {
854
+ JSValue e = JS_ThrowTypeError(ctx, "Failed to parse URL from %s", url);
855
+ JS_FreeCString(ctx, url);
856
+ return e;
857
+ }
858
+ JS_FreeCString(ctx, url);
859
+ if (!(fx_str_is(u->scheme, "http") || fx_str_is(u->scheme, "https"))) {
860
+ scr_url_release(u);
861
+ return JS_ThrowTypeError(ctx, "fetch failed");
862
+ }
863
+
864
+ FxTransfer *t = calloc(1, sizeof *t);
865
+ if (!t) fx_oom();
866
+ t->rc = 1; /* the registry's */
867
+ t->ctx = ctx;
868
+ t->id = fx_next_id++;
869
+ t->cbs = JS_DupValue(ctx, argv[1]);
870
+ t->cbs_live = true;
871
+ t->url = u;
872
+
873
+ JSValue methodv = JS_GetPropertyStr(ctx, req, "method");
874
+ const char *method = JS_ToCString(ctx, methodv);
875
+ JS_FreeValue(ctx, methodv);
876
+ t->method = scr_str_new(method ? method : "GET", method ? strlen(method) : 3);
877
+ if (method) JS_FreeCString(ctx, method);
878
+
879
+ JSValue hdrs = JS_GetPropertyStr(ctx, req, "headers");
880
+ JSValue lenv = JS_GetPropertyStr(ctx, hdrs, "length");
881
+ uint32_t hn = 0;
882
+ JS_ToUint32(ctx, &hn, lenv);
883
+ JS_FreeValue(ctx, lenv);
884
+ t->headers = scr_arr_new(SCR_ELEM_STR, hn);
885
+ for (uint32_t i = 0; i + 1 < hn; i += 2) {
886
+ JSValue nv = JS_GetPropertyUint32(ctx, hdrs, i);
887
+ JSValue vv = JS_GetPropertyUint32(ctx, hdrs, i + 1);
888
+ size_t nlen = 0, vlen = 0;
889
+ const char *hname = JS_ToCStringLen(ctx, &nlen, nv);
890
+ const char *hvalue = JS_ToCStringLen(ctx, &vlen, vv);
891
+ if (hname && hvalue) {
892
+ scr_arr_push_ref(t->headers, scr_str_new(hname, nlen));
893
+ scr_arr_push_ref(t->headers, scr_str_new(hvalue, vlen));
894
+ }
895
+ if (hname) JS_FreeCString(ctx, hname);
896
+ if (hvalue) JS_FreeCString(ctx, hvalue);
897
+ JS_FreeValue(ctx, nv);
898
+ JS_FreeValue(ctx, vv);
899
+ }
900
+ JS_FreeValue(ctx, hdrs);
901
+
902
+ JSValue bodyv = JS_GetPropertyStr(ctx, req, "body");
903
+ if (!JS_IsUndefined(bodyv) && !JS_IsNull(bodyv)) {
904
+ size_t blen = 0;
905
+ uint8_t *bytes = JS_GetUint8Array(ctx, &blen, bodyv);
906
+ if (bytes != NULL || blen == 0) {
907
+ t->body = scr_bytes_new(SCR_BYTES_U8, (double)blen);
908
+ if (blen > 0) memcpy(t->body->data, bytes, blen);
909
+ }
910
+ }
911
+ JS_FreeValue(ctx, bodyv);
912
+
913
+ t->next = fx_live;
914
+ fx_live = t;
915
+ fx_nlive++;
916
+ fx_start_hop(t);
917
+ return JS_NewInt32(ctx, t->id);
918
+ }
919
+
920
+ /* host.abort(id): the island aborted the fetch or cancelled the response
921
+ * body stream. The transfer dies quietly — no onError, no onEnd. */
922
+ static JSValue fx_host_abort(JSContext *ctx, JSValueConst this_val, int argc,
923
+ JSValueConst *argv) {
924
+ (void)this_val;
925
+ (void)argc;
926
+ int32_t id = 0;
927
+ JS_ToInt32(ctx, &id, argv[0]);
928
+ for (FxTransfer *t = fx_live; t; t = t->next) {
929
+ if (t->id == id) {
930
+ t->cancelled = true;
931
+ if (t->client) scr_http_client_destroy(t->client);
932
+ fx_settle(t);
933
+ break;
934
+ }
935
+ }
936
+ return JS_UNDEFINED;
937
+ }
938
+
939
+ /* ── the JS half (UNCHANGED from the curl bridge — the island surface,
940
+ * abort wiring, and error shaping are the contract the fixture suite
941
+ * pins) ──────────────────────────────────────────────────────────────── */
942
+
943
+ static const char fx_glue[] =
944
+ "(host) => {\n"
945
+ " 'use strict';\n"
946
+ " const g = globalThis;\n"
947
+ " const NULL_BODY = { 204: true, 205: true, 304: true };\n"
948
+ " g.fetch = function fetch(input, init) {\n"
949
+ " return new Promise((resolve, reject) => {\n"
950
+ " let url;\n"
951
+ " let method = 'GET';\n"
952
+ " let headers = null;\n"
953
+ " let body = null;\n"
954
+ " let signal = null;\n"
955
+ " if (input instanceof g.Request) {\n"
956
+ " url = input.url;\n"
957
+ " method = input.method;\n"
958
+ " headers = new g.Headers(input.headers);\n"
959
+ " body = input._body instanceof Uint8Array ? input._body : null;\n"
960
+ " signal = input._signal;\n"
961
+ " } else {\n"
962
+ " url = String(input);\n"
963
+ " }\n"
964
+ " init = init === undefined || init === null ? {} : init;\n"
965
+ " // An explicit init.signal overrides the Request's, null included.\n"
966
+ " if (init.signal !== undefined) {\n"
967
+ " if (init.signal !== null && !(init.signal instanceof g.AbortSignal)) {\n"
968
+ " throw new TypeError('fetch init.signal must be an AbortSignal or null');\n"
969
+ " }\n"
970
+ " signal = init.signal;\n"
971
+ " }\n"
972
+ " if (init.redirect !== undefined && init.redirect !== 'follow') {\n"
973
+ " throw new Error(\"scriptc: only redirect: 'follow' is supported by the embedded fetch\");\n"
974
+ " }\n"
975
+ " // Reuse Request's init handling: method normalization, header\n"
976
+ " // collection, body coercion with its implicit content-type, and the\n"
977
+ " // GET/HEAD-with-body TypeError.\n"
978
+ " const reqInit = {};\n"
979
+ " if (init.method !== undefined) reqInit.method = init.method;\n"
980
+ " if (init.headers !== undefined) reqInit.headers = init.headers;\n"
981
+ " if (init.body !== undefined && init.body !== null) reqInit.body = init.body;\n"
982
+ " if (reqInit.method !== undefined || reqInit.headers !== undefined || reqInit.body !== undefined || headers === null) {\n"
983
+ " const base = input instanceof g.Request ? input : url;\n"
984
+ " const r = new g.Request(base, reqInit);\n"
985
+ " method = r.method;\n"
986
+ " headers = r.headers;\n"
987
+ " if (r._body instanceof Uint8Array) body = r._body;\n"
988
+ " }\n"
989
+ " if (body !== null && !(body instanceof Uint8Array)) {\n"
990
+ " throw new TypeError('streaming request bodies are not supported in the scriptc island');\n"
991
+ " }\n"
992
+ " // An already-aborted signal rejects with ITS reason before any\n"
993
+ " // transfer starts (Node: validation above still throws first).\n"
994
+ " if (signal !== null && signal.aborted) {\n"
995
+ " reject(signal.reason);\n"
996
+ " return;\n"
997
+ " }\n"
998
+ " let controller = null;\n"
999
+ " let resolved = false;\n"
1000
+ " let done = false;\n"
1001
+ " let id = 0;\n"
1002
+ " // The transfer is over (delivered, failed, cancelled, or aborted):\n"
1003
+ " // a later signal abort must not touch it.\n"
1004
+ " const finish = () => {\n"
1005
+ " done = true;\n"
1006
+ " if (signal !== null) signal.removeEventListener('abort', onAbort);\n"
1007
+ " };\n"
1008
+ " const onAbort = () => {\n"
1009
+ " if (done) return;\n"
1010
+ " finish();\n"
1011
+ " host.abort(id); // the C side dies quietly; rejection is ours\n"
1012
+ " if (!resolved) {\n"
1013
+ " resolved = true;\n"
1014
+ " reject(signal.reason);\n"
1015
+ " } else if (controller !== null) {\n"
1016
+ " // Mid-stream: pending and future reads reject with the reason,\n"
1017
+ " // exactly Node's aborted-body behavior.\n"
1018
+ " try { controller.error(signal.reason); } catch (_e) { /* already closed */ }\n"
1019
+ " controller = null;\n"
1020
+ " }\n"
1021
+ " };\n"
1022
+ " const flat = [];\n"
1023
+ " for (const pair of headers) { flat.push(pair[0], pair[1]); }\n"
1024
+ " id = host.start(\n"
1025
+ " { url, method, headers: flat, body: body === null ? undefined : body },\n"
1026
+ " {\n"
1027
+ " onResponse(status, statusText, raw, finalUrl, redirected) {\n"
1028
+ " resolved = true;\n"
1029
+ " const h = new g.Headers();\n"
1030
+ " for (let i = 0; i + 1 < raw.length; i += 2) {\n"
1031
+ " try { h.append(raw[i], raw[i + 1]); } catch (_e) { /* junk line */ }\n"
1032
+ " }\n"
1033
+ " let stream = null;\n"
1034
+ " if (method !== 'HEAD' && NULL_BODY[status] !== true) {\n"
1035
+ " stream = new g.ReadableStream({\n"
1036
+ " start(c) { controller = c; },\n"
1037
+ " cancel() { controller = null; finish(); host.abort(id); },\n"
1038
+ " });\n"
1039
+ " }\n"
1040
+ " resolve(g.__scr_mk_response(status, statusText, h, finalUrl, redirected, stream));\n"
1041
+ " },\n"
1042
+ " onData(chunk) {\n"
1043
+ " if (controller !== null) {\n"
1044
+ " try { controller.enqueue(chunk); } catch (_e) { /* consumer went away */ }\n"
1045
+ " }\n"
1046
+ " },\n"
1047
+ " onEnd() {\n"
1048
+ " finish();\n"
1049
+ " if (controller !== null) {\n"
1050
+ " try { controller.close(); } catch (_e) { /* already errored */ }\n"
1051
+ " controller = null;\n"
1052
+ " }\n"
1053
+ " },\n"
1054
+ " onError(detail, code) {\n"
1055
+ " finish();\n"
1056
+ " if (!resolved) {\n"
1057
+ " // Node's shape: TypeError 'fetch failed' with a CAUSE the\n"
1058
+ " // wrappers classify (message + code for the network cases).\n"
1059
+ " const cause = new Error(String(detail));\n"
1060
+ " if (code !== undefined) cause.code = code;\n"
1061
+ " if (code === 'ECONNREFUSED') cause.syscall = 'connect';\n"
1062
+ " else if (code === 'ENOTFOUND') cause.syscall = 'getaddrinfo';\n"
1063
+ " const err = new TypeError('fetch failed');\n"
1064
+ " err.cause = cause;\n"
1065
+ " reject(err);\n"
1066
+ " } else if (controller !== null) {\n"
1067
+ " try { controller.error(new TypeError('terminated')); } catch (_e) { /* already closed */ }\n"
1068
+ " controller = null;\n"
1069
+ " }\n"
1070
+ " },\n"
1071
+ " },\n"
1072
+ " );\n"
1073
+ " if (signal !== null) signal.addEventListener('abort', onAbort, { once: true });\n"
1074
+ " });\n"
1075
+ " };\n"
1076
+ "}\n";
1077
+
1078
+ /* ── boot / teardown (registered with the island) ────────────────────── */
1079
+
1080
+ static void fx_boot(void *jsctx) {
1081
+ JSContext *ctx = (JSContext *)jsctx;
1082
+ JSValue fn = JS_Eval(ctx, fx_glue, sizeof fx_glue - 1, "<scr-fetch>", JS_EVAL_TYPE_GLOBAL);
1083
+ if (JS_IsException(fn)) {
1084
+ fprintf(stderr, "scriptc: island fetch glue failed to evaluate\n");
1085
+ abort();
1086
+ }
1087
+ JSValue host = JS_NewObject(ctx);
1088
+ JS_SetPropertyStr(ctx, host, "start", JS_NewCFunction(ctx, fx_host_start, "start", 2));
1089
+ JS_SetPropertyStr(ctx, host, "abort", JS_NewCFunction(ctx, fx_host_abort, "abort", 1));
1090
+ JSValue r = JS_Call(ctx, fn, JS_UNDEFINED, 1, (JSValueConst *)&host);
1091
+ JS_FreeValue(ctx, host);
1092
+ JS_FreeValue(ctx, fn);
1093
+ if (JS_IsException(r)) {
1094
+ fprintf(stderr, "scriptc: island fetch glue failed to run\n");
1095
+ abort();
1096
+ }
1097
+ JS_FreeValue(ctx, r);
1098
+ }
1099
+
1100
+ /* Engine teardown with transfers still live (process.exit mid-request, or
1101
+ * an exit with an abandoned body stream): free their engine values FIRST
1102
+ * so the island's counting allocator returns to zero. The net/http exit
1103
+ * cleanups (registered later, so they run earlier — atexit LIFO) have
1104
+ * already dropped the listener closures; whatever the registry still
1105
+ * holds settles here. */
1106
+ static void fx_teardown(void) {
1107
+ while (fx_live) fx_settle(fx_live);
1108
+ }
1109
+
1110
+ /* The emitted main calls this (before any island entry) in builds whose
1111
+ * embedded graph references fetch. No pending/poll hooks: transfers live
1112
+ * on real sockets the loop's own poller sleeps on, and armed island
1113
+ * timers cap that sleep through the loop's island-deadline hook. */
1114
+ void scr_fetch_install(void) {
1115
+ static bool installed = false;
1116
+ if (installed) return;
1117
+ installed = true;
1118
+ /* The net unit's loop hooks (pending/dispatch/pollfd): the emitted main
1119
+ * registers them only for programs that USE node:net — a fetch-only
1120
+ * build must register them itself or its sockets would neither keep
1121
+ * the loop alive nor dispatch. */
1122
+ scr_net_install();
1123
+ /* The island's node:http/https client bridge rides the same units and
1124
+ * is always compiled beside the native fetch (cc.ts) — embedded graphs
1125
+ * that require node:http/https get working clients, not refusals. */
1126
+ scr_net_island_install();
1127
+ scr_island_set_fetch(fx_boot, NULL, NULL, fx_teardown);
1128
+ }
1129
+
1130
+ #endif /* SCR_DYNAMIC */