functionalscript 0.44.0 → 0.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (571) hide show
  1. package/README.md +5 -3
  2. package/fjs/asn.1/module.f.mjs +8 -1
  3. package/fjs/asn.1/proof.f.d.mts +15 -0
  4. package/fjs/asn.1/proof.f.mjs +31 -3
  5. package/fjs/asserts/module.f.d.mts +14 -0
  6. package/fjs/asserts/module.f.mjs +20 -0
  7. package/fjs/asserts/proof.f.d.mts +3 -0
  8. package/fjs/asserts/proof.f.mjs +15 -1
  9. package/fjs/basen/base128/module.f.mjs +22 -5
  10. package/fjs/basen/base128/proof.f.d.mts +3 -1
  11. package/fjs/basen/base128/proof.f.mjs +3 -1
  12. package/fjs/basen/base64/module.f.mjs +7 -3
  13. package/fjs/basen/base64/proof.f.d.mts +3 -1
  14. package/fjs/basen/base64/proof.f.mjs +7 -4
  15. package/fjs/basen/cbase32/proof.f.d.mts +3 -1
  16. package/fjs/basen/cbase32/proof.f.mjs +3 -1
  17. package/fjs/bnf/data/module.f.d.mts +32 -6
  18. package/fjs/bnf/data/module.f.mjs +112 -7
  19. package/fjs/bnf/data/proof.f.d.mts +2 -0
  20. package/fjs/bnf/data/proof.f.mjs +74 -4
  21. package/fjs/bnf/data/types.d.ts +20 -2
  22. package/fjs/bnf/descent/module.f.d.mts +34 -5
  23. package/fjs/bnf/descent/module.f.mjs +176 -54
  24. package/fjs/bnf/descent/proof.f.d.mts +3 -0
  25. package/fjs/bnf/descent/proof.f.mjs +189 -27
  26. package/fjs/bnf/descent/types.d.ts +24 -18
  27. package/fjs/bnf/ll1/module.f.d.mts +74 -6
  28. package/fjs/bnf/ll1/module.f.mjs +297 -95
  29. package/fjs/bnf/ll1/proof.f.d.mts +17 -2
  30. package/fjs/bnf/ll1/proof.f.mjs +372 -137
  31. package/fjs/bnf/ll1/types.d.ts +25 -27
  32. package/fjs/bnf/matcher/module.f.d.mts +66 -0
  33. package/fjs/bnf/matcher/module.f.mjs +81 -0
  34. package/fjs/bnf/matcher/proof.f.d.mts +10 -0
  35. package/fjs/bnf/matcher/proof.f.mjs +79 -0
  36. package/fjs/bnf/matcher/types.d.ts +54 -0
  37. package/fjs/bnf/module.f.d.mts +15 -6
  38. package/fjs/bnf/module.f.mjs +52 -11
  39. package/fjs/bnf/proof.f.d.mts +2 -0
  40. package/fjs/bnf/proof.f.mjs +79 -3
  41. package/fjs/bnf/testlib.f.d.mts +31 -0
  42. package/fjs/bnf/testlib.f.mjs +80 -0
  43. package/fjs/bnf/token_symbol/module.f.d.mts +4 -3
  44. package/fjs/bnf/token_symbol/module.f.mjs +7 -6
  45. package/fjs/bnf/token_symbol/proof.f.mjs +5 -2
  46. package/fjs/bnf/token_symbol/types.d.ts +2 -2
  47. package/fjs/bnf/types.d.ts +10 -3
  48. package/fjs/cas/cli/module.f.d.mts +1 -1
  49. package/fjs/cas/cli/module.f.mjs +14 -20
  50. package/fjs/cas/cli/proof.f.d.mts +4 -4
  51. package/fjs/cas/cli/proof.f.mjs +47 -34
  52. package/fjs/cas/evo/module.f.d.mts +71 -31
  53. package/fjs/cas/evo/module.f.mjs +223 -138
  54. package/fjs/cas/evo/proof.f.d.mts +10 -1
  55. package/fjs/cas/evo/proof.f.mjs +311 -226
  56. package/fjs/cas/evo/types.d.ts +45 -9
  57. package/fjs/cas/module.f.d.mts +18 -32
  58. package/fjs/cas/module.f.mjs +164 -176
  59. package/fjs/cas/proof.f.d.mts +11 -8
  60. package/fjs/cas/proof.f.mjs +259 -147
  61. package/fjs/cas/types.d.ts +24 -10
  62. package/fjs/ci/common/module.f.d.mts +1 -1
  63. package/fjs/ci/common/module.f.mjs +1 -0
  64. package/fjs/ci/config/module.f.d.mts +3 -3
  65. package/fjs/ci/config/module.f.mjs +3 -3
  66. package/fjs/ci/module.f.d.mts +5 -5
  67. package/fjs/ci/module.f.mjs +8 -7
  68. package/fjs/ci/nix/module.f.d.mts +7 -5
  69. package/fjs/ci/nix/module.f.mjs +13 -12
  70. package/fjs/ci/nix/proof.f.d.mts +2 -0
  71. package/fjs/ci/nix/proof.f.mjs +4 -4
  72. package/fjs/ci/proof.f.d.mts +4 -2
  73. package/fjs/ci/proof.f.mjs +13 -8
  74. package/fjs/cli/module.f.d.mts +4 -6
  75. package/fjs/cli/module.f.mjs +4 -8
  76. package/fjs/cli/proof.f.d.mts +4 -2
  77. package/fjs/cli/proof.f.mjs +21 -18
  78. package/fjs/cli/types.d.ts +2 -3
  79. package/fjs/common/monoid/module.f.d.mts +70 -12
  80. package/fjs/common/monoid/module.f.mjs +177 -14
  81. package/fjs/common/monoid/proof.f.d.mts +12 -1
  82. package/fjs/common/monoid/proof.f.mjs +88 -4
  83. package/fjs/common/monoid/types.d.ts +23 -0
  84. package/fjs/crypto/hmac/module.f.mjs +2 -2
  85. package/fjs/crypto/secp/proof.f.d.mts +3 -1
  86. package/fjs/crypto/secp/proof.f.mjs +3 -1
  87. package/fjs/crypto/sha2/module.f.mjs +3 -1
  88. package/fjs/crypto/sha2/proof.f.d.mts +4 -1
  89. package/fjs/crypto/sha2/proof.f.mjs +27 -1
  90. package/fjs/crypto/sha2/types.d.ts +11 -0
  91. package/fjs/crypto/sign/module.f.mjs +2 -2
  92. package/fjs/crypto/vdf/module.f.d.mts +23 -4
  93. package/fjs/crypto/vdf/module.f.mjs +6 -4
  94. package/fjs/dev/module.f.d.mts +17 -5
  95. package/fjs/dev/module.f.mjs +60 -30
  96. package/fjs/dev/update/module.f.d.mts +11 -3
  97. package/fjs/dev/update/module.f.mjs +16 -11
  98. package/fjs/dev/update/proof.f.d.mts +4 -3
  99. package/fjs/dev/update/proof.f.mjs +11 -7
  100. package/fjs/djs/module.f.d.mts +13 -5
  101. package/fjs/djs/module.f.mjs +31 -16
  102. package/fjs/djs/parser/module.f.d.mts +16 -3
  103. package/fjs/djs/parser/module.f.mjs +135 -16
  104. package/fjs/djs/parser/proof.f.d.mts +8 -1
  105. package/fjs/djs/parser/proof.f.mjs +287 -13
  106. package/fjs/djs/parser/types.d.ts +7 -1
  107. package/fjs/djs/proof.f.d.mts +20 -1
  108. package/fjs/djs/proof.f.mjs +190 -12
  109. package/fjs/djs/serializer/module.f.d.mts +25 -8
  110. package/fjs/djs/serializer/module.f.mjs +66 -19
  111. package/fjs/djs/serializer/proof.f.d.mts +5 -0
  112. package/fjs/djs/serializer/proof.f.mjs +23 -1
  113. package/fjs/djs/tokenizer/module.f.d.mts +17 -5
  114. package/fjs/djs/tokenizer/module.f.mjs +120 -73
  115. package/fjs/djs/tokenizer/proof.f.d.mts +3 -0
  116. package/fjs/djs/tokenizer/proof.f.mjs +86 -67
  117. package/fjs/djs/transpiler/module.f.d.mts +13 -19
  118. package/fjs/djs/transpiler/module.f.mjs +79 -72
  119. package/fjs/djs/transpiler/types.d.ts +29 -0
  120. package/fjs/djs/types.d.ts +7 -1
  121. package/fjs/effects/list/module.f.d.mts +23 -12
  122. package/fjs/effects/list/module.f.mjs +16 -12
  123. package/fjs/effects/list/types.d.ts +27 -7
  124. package/fjs/effects/memory/module.f.d.mts +6 -3
  125. package/fjs/effects/memory/module.f.mjs +7 -7
  126. package/fjs/effects/memory/proof.f.d.mts +4 -0
  127. package/fjs/effects/memory/proof.f.mjs +18 -9
  128. package/fjs/effects/memory/types.d.ts +4 -3
  129. package/fjs/effects/mock/module.f.d.mts +28 -4
  130. package/fjs/effects/mock/module.f.mjs +39 -5
  131. package/fjs/effects/mock/types.d.ts +10 -1
  132. package/fjs/effects/module.d.mts +12 -2
  133. package/fjs/effects/module.f.d.mts +469 -281
  134. package/fjs/effects/module.f.mjs +538 -299
  135. package/fjs/effects/module.mjs +11 -2
  136. package/fjs/effects/node/memory/module.d.mts +7 -2
  137. package/fjs/effects/node/memory/module.mjs +9 -5
  138. package/fjs/effects/node/memory/proof.d.mts +2 -0
  139. package/fjs/effects/node/memory/proof.mjs +12 -5
  140. package/fjs/effects/node/module.d.mts +8 -2
  141. package/fjs/effects/node/module.f.d.mts +183 -43
  142. package/fjs/effects/node/module.f.mjs +260 -62
  143. package/fjs/effects/node/module.mjs +61 -50
  144. package/fjs/effects/node/proof.f.d.mts +28 -2
  145. package/fjs/effects/node/proof.f.mjs +161 -42
  146. package/fjs/effects/node/types.d.ts +106 -18
  147. package/fjs/effects/node/virtual/module.f.d.mts +21 -4
  148. package/fjs/effects/node/virtual/module.f.mjs +113 -70
  149. package/fjs/effects/node/virtual/proof.f.d.mts +31 -2
  150. package/fjs/effects/node/virtual/proof.f.mjs +201 -8
  151. package/fjs/effects/proof.f.d.mts +69 -34
  152. package/fjs/effects/proof.f.mjs +413 -130
  153. package/fjs/effects/types.d.ts +161 -33
  154. package/fjs/emergent_testing/all.test.d.mts +8 -0
  155. package/fjs/emergent_testing/all.test.mjs +14 -0
  156. package/fjs/emergent_testing/module.f.d.mts +22 -10
  157. package/fjs/emergent_testing/module.f.mjs +119 -85
  158. package/fjs/emergent_testing/proof.f.d.mts +21 -7
  159. package/fjs/emergent_testing/proof.f.mjs +169 -35
  160. package/fjs/emergent_testing/types.d.ts +22 -4
  161. package/fjs/fsc/bnf.f.d.mts +3 -0
  162. package/fjs/fsc/bnf.f.mjs +4 -1
  163. package/fjs/fsc/json.f.d.mts +3 -0
  164. package/fjs/fsc/json.f.mjs +4 -1
  165. package/fjs/fsc/module.f.d.mts +9 -0
  166. package/fjs/fsc/module.f.mjs +5 -3
  167. package/fjs/fsm/module.f.d.mts +14 -4
  168. package/fjs/fsm/module.f.mjs +54 -37
  169. package/fjs/fsm/proof.f.d.mts +5 -0
  170. package/fjs/fsm/proof.f.mjs +87 -115
  171. package/fjs/js/keywords/module.f.d.mts +52 -0
  172. package/fjs/js/keywords/module.f.mjs +72 -0
  173. package/fjs/{emergent_testing/scenarios/return-value.pass.d.ts → js/keywords/proof.f.d.mts} +1 -1
  174. package/fjs/js/keywords/proof.f.mjs +13 -0
  175. package/fjs/js/tokenizer/module.f.d.mts +30 -3
  176. package/fjs/js/tokenizer/module.f.mjs +161 -211
  177. package/fjs/js/tokenizer/proof.f.d.mts +1 -0
  178. package/fjs/js/tokenizer/proof.f.mjs +54 -24
  179. package/fjs/js/tokenizer/types.d.ts +33 -24
  180. package/fjs/mcp/cas/module.f.d.mts +1 -6
  181. package/fjs/mcp/cas/module.f.mjs +55 -51
  182. package/fjs/mcp/cas/proof.f.d.mts +15 -0
  183. package/fjs/mcp/cas/proof.f.mjs +174 -0
  184. package/fjs/mcp/evo/module.f.d.mts +19 -10
  185. package/fjs/mcp/evo/module.f.mjs +48 -27
  186. package/fjs/mcp/evo/proof.f.d.mts +6 -1
  187. package/fjs/mcp/evo/proof.f.mjs +115 -31
  188. package/fjs/mcp/module.f.d.mts +39 -4
  189. package/fjs/mcp/module.f.mjs +14 -12
  190. package/fjs/mcp/proof.f.d.mts +13 -1
  191. package/fjs/mcp/proof.f.mjs +120 -61
  192. package/fjs/media/html/module.f.d.mts +12 -0
  193. package/fjs/media/html/module.f.mjs +7 -5
  194. package/fjs/media/html/proof.f.d.mts +3 -0
  195. package/fjs/media/html/proof.f.mjs +4 -1
  196. package/fjs/media/json/extended/module.f.d.mts +82 -0
  197. package/fjs/media/json/extended/module.f.mjs +153 -0
  198. package/fjs/media/json/extended/proof.f.d.mts +42 -0
  199. package/fjs/media/json/extended/proof.f.mjs +127 -0
  200. package/fjs/media/json/extended/types.d.ts +23 -0
  201. package/fjs/media/json/module.f.d.mts +8 -2
  202. package/fjs/media/json/module.f.mjs +43 -41
  203. package/fjs/media/json/number/module.f.d.mts +59 -0
  204. package/fjs/media/json/number/module.f.mjs +136 -0
  205. package/fjs/media/json/number/proof.f.d.mts +24 -0
  206. package/fjs/media/json/number/proof.f.mjs +86 -0
  207. package/fjs/media/json/number/types.d.ts +28 -0
  208. package/fjs/media/json/parser/module.f.d.mts +25 -13
  209. package/fjs/media/json/parser/module.f.mjs +133 -72
  210. package/fjs/media/json/parser/proof.f.d.mts +5 -0
  211. package/fjs/media/json/parser/proof.f.mjs +31 -1
  212. package/fjs/media/json/parser/types.d.ts +38 -14
  213. package/fjs/media/json/rtti/module.f.d.mts +1 -1
  214. package/fjs/media/json/rtti/module.f.mjs +1 -1
  215. package/fjs/media/json/rtti/proof.f.d.mts +3 -0
  216. package/fjs/media/json/rtti/proof.f.mjs +12 -12
  217. package/fjs/media/json/schema/module.f.d.mts +61 -27
  218. package/fjs/media/json/schema/module.f.mjs +218 -63
  219. package/fjs/media/json/schema/proof.f.d.mts +41 -1
  220. package/fjs/media/json/schema/proof.f.mjs +220 -9
  221. package/fjs/media/json/serializer/module.f.d.mts +44 -0
  222. package/fjs/media/json/serializer/module.f.mjs +71 -9
  223. package/fjs/media/json/tokenizer/module.f.d.mts +8 -0
  224. package/fjs/media/json/tokenizer/module.f.mjs +31 -8
  225. package/fjs/media/json/tokenizer/proof.f.d.mts +6 -0
  226. package/fjs/media/json/tokenizer/proof.f.mjs +62 -21
  227. package/fjs/media/json/types.d.ts +36 -10
  228. package/fjs/media/lock/module.f.d.mts +100 -0
  229. package/fjs/media/lock/module.f.mjs +125 -0
  230. package/fjs/media/lock/proof.f.d.mts +33 -0
  231. package/fjs/media/lock/proof.f.mjs +196 -0
  232. package/fjs/media/lock/types.d.ts +15 -0
  233. package/fjs/media/module.f.d.mts +6 -5
  234. package/fjs/media/module.f.mjs +8 -7
  235. package/fjs/media/nix/module.f.d.mts +13 -0
  236. package/fjs/media/nix/module.f.mjs +4 -2
  237. package/fjs/media/nix/proof.f.d.mts +3 -0
  238. package/fjs/media/nix/proof.f.mjs +4 -1
  239. package/fjs/media/note/module.f.d.mts +121 -0
  240. package/fjs/media/note/module.f.mjs +131 -0
  241. package/fjs/media/note/proof.f.d.mts +29 -0
  242. package/fjs/media/note/proof.f.mjs +150 -0
  243. package/fjs/media/note/types.d.ts +10 -0
  244. package/fjs/media/proof.f.d.mts +4 -1
  245. package/fjs/media/proof.f.mjs +40 -21
  246. package/fjs/media/revision/module.f.d.mts +83 -7
  247. package/fjs/media/revision/module.f.mjs +127 -23
  248. package/fjs/media/revision/proof.f.d.mts +14 -0
  249. package/fjs/media/revision/proof.f.mjs +93 -2
  250. package/fjs/media/revision/types.d.ts +34 -5
  251. package/fjs/media/type/module.f.d.mts +53 -18
  252. package/fjs/media/type/module.f.mjs +87 -97
  253. package/fjs/media/type/proof.f.d.mts +17 -0
  254. package/fjs/media/type/proof.f.mjs +73 -13
  255. package/fjs/module.d.mts +5 -0
  256. package/fjs/module.f.d.mts +8 -0
  257. package/fjs/module.f.mjs +33 -10
  258. package/fjs/module.mjs +6 -0
  259. package/fjs/nanvm/proof.f.mjs +3 -3
  260. package/fjs/nanvm/rust/module.f.mjs +1 -1
  261. package/fjs/nanvm/update/module.f.d.mts +4 -4
  262. package/fjs/nanvm/update/module.f.mjs +8 -9
  263. package/fjs/nanvm/update/proof.f.mjs +4 -3
  264. package/fjs/path/module.f.d.mts +8 -0
  265. package/fjs/path/module.f.mjs +4 -2
  266. package/fjs/proof.f.d.mts +7 -3
  267. package/fjs/proof.f.mjs +41 -12
  268. package/fjs/protocol/json_rpc/module.f.d.mts +3 -3
  269. package/fjs/protocol/json_rpc/module.f.mjs +10 -7
  270. package/fjs/protocol/json_rpc/proof.f.d.mts +6 -0
  271. package/fjs/protocol/json_rpc/proof.f.mjs +26 -5
  272. package/fjs/protocol/mcp/module.f.d.mts +10 -13
  273. package/fjs/protocol/mcp/module.f.mjs +74 -58
  274. package/fjs/protocol/mcp/proof.f.d.mts +16 -3
  275. package/fjs/protocol/mcp/proof.f.mjs +224 -69
  276. package/fjs/protocol/mcp/stdio/module.f.d.mts +17 -11
  277. package/fjs/protocol/mcp/stdio/module.f.mjs +39 -33
  278. package/fjs/protocol/mcp/stdio/proof.f.d.mts +5 -3
  279. package/fjs/protocol/mcp/stdio/proof.f.mjs +46 -13
  280. package/fjs/protocol/mcp/stdio/types.d.ts +14 -0
  281. package/fjs/protocol/mcp/types.d.ts +17 -6
  282. package/fjs/sul/id/module.f.d.mts +4 -0
  283. package/fjs/sul/id/module.f.mjs +6 -6
  284. package/fjs/sul/level/hash/module.f.d.mts +4 -1
  285. package/fjs/sul/level/hash/module.f.mjs +6 -4
  286. package/fjs/sul/level/hash/proof.f.d.mts +4 -0
  287. package/fjs/sul/level/hash/proof.f.mjs +7 -4
  288. package/fjs/sul/level/literal/module.f.d.mts +4 -1
  289. package/fjs/sul/level/literal/module.f.mjs +4 -3
  290. package/fjs/sul/level/literal/proof.f.d.mts +3 -0
  291. package/fjs/sul/level/literal/proof.f.mjs +4 -1
  292. package/fjs/sul/module.f.d.mts +5 -3
  293. package/fjs/sul/module.f.mjs +23 -17
  294. package/fjs/sul/proof.f.d.mts +4 -0
  295. package/fjs/sul/proof.f.mjs +5 -2
  296. package/fjs/text/ascii/module.f.d.mts +26 -0
  297. package/fjs/text/ascii/module.f.mjs +49 -1
  298. package/fjs/text/ascii/proof.f.d.mts +10 -0
  299. package/fjs/text/ascii/proof.f.mjs +33 -1
  300. package/fjs/text/code_point/module.f.d.mts +29 -3
  301. package/fjs/text/code_point/module.f.mjs +32 -9
  302. package/fjs/text/code_point/proof.f.d.mts +2 -0
  303. package/fjs/text/code_point/proof.f.mjs +39 -0
  304. package/fjs/text/module.f.d.mts +4 -2
  305. package/fjs/text/module.f.mjs +4 -3
  306. package/fjs/text/proof.f.d.mts +3 -0
  307. package/fjs/text/proof.f.mjs +4 -1
  308. package/fjs/text/sgr/module.f.d.mts +6 -5
  309. package/fjs/text/sgr/module.f.mjs +8 -8
  310. package/fjs/text/sgr/proof.f.d.mts +3 -0
  311. package/fjs/text/sgr/proof.f.mjs +4 -1
  312. package/fjs/text/utf16/module.f.d.mts +5 -1
  313. package/fjs/text/utf16/module.f.mjs +38 -35
  314. package/fjs/text/utf16/proof.f.d.mts +3 -1
  315. package/fjs/text/utf16/proof.f.mjs +19 -2
  316. package/fjs/text/utf8/module.f.d.mts +9 -5
  317. package/fjs/text/utf8/module.f.mjs +20 -20
  318. package/fjs/types/array/module.f.d.mts +2 -1
  319. package/fjs/types/array/module.f.mjs +16 -4
  320. package/fjs/types/bigfloat/module.f.d.mts +21 -1
  321. package/fjs/types/bigfloat/module.f.mjs +33 -7
  322. package/fjs/types/bigfloat/proof.f.d.mts +1 -0
  323. package/fjs/types/bigfloat/proof.f.mjs +46 -0
  324. package/fjs/types/bigint/module.f.d.mts +4 -0
  325. package/fjs/types/bigint/module.f.mjs +4 -3
  326. package/fjs/types/bit_vec/module.f.d.mts +10 -16
  327. package/fjs/types/bit_vec/module.f.mjs +99 -95
  328. package/fjs/types/bit_vec/proof.f.d.mts +6 -0
  329. package/fjs/types/bit_vec/proof.f.mjs +31 -5
  330. package/fjs/types/btree/find/module.f.d.mts +5 -1
  331. package/fjs/types/btree/find/module.f.mjs +5 -5
  332. package/fjs/types/btree/find/proof.f.d.mts +5 -1
  333. package/fjs/types/btree/find/proof.f.mjs +5 -3
  334. package/fjs/types/btree/module.f.d.mts +3 -0
  335. package/fjs/types/btree/module.f.mjs +3 -2
  336. package/fjs/types/btree/proof.f.d.mts +5 -1
  337. package/fjs/types/btree/proof.f.mjs +5 -3
  338. package/fjs/types/btree/remove/module.f.d.mts +11 -0
  339. package/fjs/types/btree/remove/module.f.mjs +10 -10
  340. package/fjs/types/btree/remove/proof.f.d.mts +3 -0
  341. package/fjs/types/btree/remove/proof.f.mjs +4 -1
  342. package/fjs/types/btree/set/module.f.d.mts +9 -0
  343. package/fjs/types/btree/set/module.f.mjs +14 -17
  344. package/fjs/types/btree/set/proof.f.d.mts +3 -0
  345. package/fjs/types/btree/set/proof.f.mjs +16 -1
  346. package/fjs/types/btree/types/module.f.d.mts +2 -1
  347. package/fjs/types/btree/types/module.f.mjs +2 -1
  348. package/fjs/types/byte_set/module.f.d.mts +20 -4
  349. package/fjs/types/byte_set/module.f.mjs +18 -8
  350. package/fjs/types/byte_set/proof.f.d.mts +3 -1
  351. package/fjs/types/byte_set/proof.f.mjs +10 -8
  352. package/fjs/types/function/compare/module.f.d.mts +3 -2
  353. package/fjs/types/function/compare/module.f.mjs +13 -5
  354. package/fjs/types/function/module.f.d.mts +8 -1
  355. package/fjs/types/function/module.f.mjs +8 -1
  356. package/fjs/types/function/operator/module.f.d.mts +2 -1
  357. package/fjs/types/function/operator/module.f.mjs +2 -2
  358. package/fjs/types/list/module.f.d.mts +10 -3
  359. package/fjs/types/list/module.f.mjs +6 -4
  360. package/fjs/types/list/proof.f.d.mts +4 -1
  361. package/fjs/types/list/proof.f.mjs +4 -2
  362. package/fjs/types/nibble_set/module.f.d.mts +2 -1
  363. package/fjs/types/nibble_set/module.f.mjs +2 -2
  364. package/fjs/types/nominal/module.f.d.mts +2 -1
  365. package/fjs/types/nominal/module.f.mjs +2 -1
  366. package/fjs/types/nullable/module.f.d.mts +26 -6
  367. package/fjs/types/nullable/module.f.mjs +25 -6
  368. package/fjs/types/nullable/proof.f.d.mts +4 -0
  369. package/fjs/types/nullable/proof.f.mjs +15 -0
  370. package/fjs/types/number/module.f.d.mts +4 -0
  371. package/fjs/types/number/module.f.mjs +4 -3
  372. package/fjs/types/object/module.f.d.mts +26 -4
  373. package/fjs/types/object/module.f.mjs +26 -7
  374. package/fjs/types/object/proof.f.d.mts +5 -2
  375. package/fjs/types/object/proof.f.mjs +6 -3
  376. package/fjs/types/object/structurally_same/module.f.d.mts +39 -0
  377. package/fjs/types/object/structurally_same/module.f.mjs +59 -0
  378. package/fjs/types/object/structurally_same/proof.f.d.mts +6 -0
  379. package/fjs/types/object/structurally_same/proof.f.mjs +73 -0
  380. package/fjs/types/ordered_map/module.f.d.mts +5 -0
  381. package/fjs/types/ordered_map/module.f.mjs +5 -4
  382. package/fjs/types/ordered_map/proof.f.d.mts +3 -0
  383. package/fjs/types/ordered_map/proof.f.mjs +4 -1
  384. package/fjs/types/patricia_trie/module.f.d.mts +2 -1
  385. package/fjs/types/patricia_trie/module.f.mjs +27 -12
  386. package/fjs/types/patricia_trie/proof.f.d.mts +3 -0
  387. package/fjs/types/patricia_trie/proof.f.mjs +4 -1
  388. package/fjs/types/prime_field/module.f.d.mts +3 -1
  389. package/fjs/types/prime_field/module.f.mjs +3 -2
  390. package/fjs/types/range/module.f.d.mts +2 -1
  391. package/fjs/types/range/module.f.mjs +2 -2
  392. package/fjs/types/range_map/module.f.d.mts +6 -0
  393. package/fjs/types/range_map/module.f.mjs +6 -9
  394. package/fjs/types/range_map/proof.f.d.mts +5 -1
  395. package/fjs/types/range_map/proof.f.mjs +5 -3
  396. package/fjs/types/range_set/module.f.d.mts +5 -0
  397. package/fjs/types/range_set/module.f.mjs +1 -0
  398. package/fjs/types/range_set/proof.f.d.mts +3 -0
  399. package/fjs/types/range_set/proof.f.mjs +4 -1
  400. package/fjs/types/result/module.d.mts +8 -0
  401. package/fjs/types/result/module.f.d.mts +37 -7
  402. package/fjs/types/result/module.f.mjs +38 -8
  403. package/fjs/types/result/module.mjs +9 -1
  404. package/fjs/types/result/proof.f.d.mts +5 -0
  405. package/fjs/types/result/proof.f.mjs +22 -2
  406. package/fjs/types/rtti/common/module.f.d.mts +44 -14
  407. package/fjs/types/rtti/common/module.f.mjs +42 -36
  408. package/fjs/types/rtti/common/proof.f.d.mts +4 -0
  409. package/fjs/types/rtti/common/proof.f.mjs +10 -7
  410. package/fjs/types/rtti/data/module.f.d.mts +134 -0
  411. package/fjs/types/rtti/data/module.f.mjs +1053 -0
  412. package/fjs/types/rtti/data/proof.f.d.mts +76 -0
  413. package/fjs/types/rtti/data/proof.f.mjs +589 -0
  414. package/fjs/types/rtti/data/types.d.ts +83 -0
  415. package/fjs/types/rtti/module.f.d.mts +12 -5
  416. package/fjs/types/rtti/module.f.mjs +7 -5
  417. package/fjs/types/rtti/parse/module.f.d.mts +48 -0
  418. package/fjs/types/rtti/parse/module.f.mjs +45 -34
  419. package/fjs/types/rtti/parse/proof.f.d.mts +3 -2
  420. package/fjs/types/rtti/parse/proof.f.mjs +51 -52
  421. package/fjs/types/rtti/proof.f.d.mts +3 -1
  422. package/fjs/types/rtti/proof.f.mjs +6 -2
  423. package/fjs/types/rtti/ts/module.f.d.mts +68 -9
  424. package/fjs/types/rtti/ts/module.f.mjs +258 -30
  425. package/fjs/types/rtti/ts/proof.f.d.mts +44 -0
  426. package/fjs/types/rtti/ts/proof.f.mjs +152 -4
  427. package/fjs/types/rtti/ts/types.d.ts +25 -1
  428. package/fjs/types/rtti/types.d.ts +40 -0
  429. package/fjs/types/sorted_list/module.f.d.mts +4 -1
  430. package/fjs/types/sorted_list/module.f.mjs +21 -12
  431. package/fjs/types/sorted_list/proof.f.d.mts +3 -1
  432. package/fjs/types/sorted_list/proof.f.mjs +3 -1
  433. package/fjs/types/sorted_set/module.f.d.mts +49 -1
  434. package/fjs/types/sorted_set/module.f.mjs +26 -2
  435. package/fjs/types/sorted_set/proof.f.d.mts +4 -1
  436. package/fjs/types/sorted_set/proof.f.mjs +19 -2
  437. package/fjs/types/string/module.f.d.mts +4 -0
  438. package/fjs/types/string/module.f.mjs +4 -3
  439. package/fjs/types/string_set/module.f.d.mts +3 -1
  440. package/fjs/types/string_set/module.f.mjs +3 -2
  441. package/fjs/types/ts/module.f.d.mts +2 -0
  442. package/fjs/types/ts/module.f.mjs +3 -3
  443. package/fjs/types/ts/proof.f.d.mts +1 -0
  444. package/fjs/types/ts/proof.f.mjs +5 -0
  445. package/fjs/types/ts/types.d.ts +6 -1
  446. package/fjs/types/uint8array/module.f.d.mts +13 -2
  447. package/fjs/types/uint8array/module.f.mjs +20 -15
  448. package/fjs/website/module.f.d.mts +5 -2
  449. package/fjs/website/module.f.mjs +6 -8
  450. package/fjs/website/proof.f.mjs +2 -1
  451. package/package.json +3 -3
  452. package/fjs/asn.1/types.js +0 -6
  453. package/fjs/asserts/types.js +0 -6
  454. package/fjs/basen/types.js +0 -6
  455. package/fjs/bnf/data/types.js +0 -6
  456. package/fjs/bnf/descent/types.js +0 -6
  457. package/fjs/bnf/ll1/types.js +0 -6
  458. package/fjs/bnf/token_symbol/types.js +0 -6
  459. package/fjs/bnf/types.js +0 -6
  460. package/fjs/cas/evo/types.js +0 -7
  461. package/fjs/cas/types.js +0 -6
  462. package/fjs/ci/common/types.js +0 -1
  463. package/fjs/ci/nix/types.js +0 -6
  464. package/fjs/ci/types.js +0 -6
  465. package/fjs/cli/types.js +0 -6
  466. package/fjs/common/monoid/types.js +0 -6
  467. package/fjs/crypto/pow/types.js +0 -6
  468. package/fjs/crypto/secp/types.js +0 -6
  469. package/fjs/crypto/sha2/types.js +0 -6
  470. package/fjs/crypto/sign/types.js +0 -6
  471. package/fjs/crypto/vdf/types.js +0 -6
  472. package/fjs/dev/package_json/module.f.d.mts +0 -32
  473. package/fjs/dev/package_json/module.f.mjs +0 -37
  474. package/fjs/dev/package_json/proof.f.d.mts +0 -6
  475. package/fjs/dev/package_json/proof.f.mjs +0 -32
  476. package/fjs/dev/types.js +0 -6
  477. package/fjs/djs/ast/types.js +0 -8
  478. package/fjs/djs/parser/types.js +0 -7
  479. package/fjs/djs/tokenizer/types.js +0 -7
  480. package/fjs/djs/types.js +0 -7
  481. package/fjs/effects/eff/module.f.d.mts +0 -10
  482. package/fjs/effects/eff/module.f.mjs +0 -68
  483. package/fjs/effects/eff/proof.f.d.mts +0 -12
  484. package/fjs/effects/eff/proof.f.mjs +0 -66
  485. package/fjs/effects/eff/types.d.ts +0 -71
  486. package/fjs/effects/eff/types.js +0 -6
  487. package/fjs/effects/list/types.js +0 -6
  488. package/fjs/effects/memory/types.js +0 -6
  489. package/fjs/effects/mock/types.js +0 -6
  490. package/fjs/effects/node/types.js +0 -6
  491. package/fjs/effects/node/virtual/types.js +0 -7
  492. package/fjs/effects/types.js +0 -6
  493. package/fjs/emergent_testing/all.test.d.ts +0 -1
  494. package/fjs/emergent_testing/all.test.js +0 -5
  495. package/fjs/emergent_testing/scenarios/all.d.ts +0 -1
  496. package/fjs/emergent_testing/scenarios/all.js +0 -1
  497. package/fjs/emergent_testing/scenarios/async-subtests.fail.d.ts +0 -6
  498. package/fjs/emergent_testing/scenarios/async-subtests.fail.js +0 -9
  499. package/fjs/emergent_testing/scenarios/async-subtests.pass.d.ts +0 -6
  500. package/fjs/emergent_testing/scenarios/async-subtests.pass.js +0 -9
  501. package/fjs/emergent_testing/scenarios/async.fail.d.ts +0 -3
  502. package/fjs/emergent_testing/scenarios/async.fail.js +0 -6
  503. package/fjs/emergent_testing/scenarios/async.pass.d.ts +0 -3
  504. package/fjs/emergent_testing/scenarios/async.pass.js +0 -5
  505. package/fjs/emergent_testing/scenarios/fail.fail.d.ts +0 -3
  506. package/fjs/emergent_testing/scenarios/fail.fail.js +0 -3
  507. package/fjs/emergent_testing/scenarios/return-value.pass.js +0 -4
  508. package/fjs/emergent_testing/scenarios/thenable.pass.d.ts +0 -5
  509. package/fjs/emergent_testing/scenarios/thenable.pass.js +0 -11
  510. package/fjs/emergent_testing/scenarios/thenable2.pass.d.ts +0 -5
  511. package/fjs/emergent_testing/scenarios/thenable2.pass.js +0 -3
  512. package/fjs/emergent_testing/scenarios/throw.pass.d.ts +0 -5
  513. package/fjs/emergent_testing/scenarios/throw.pass.js +0 -3
  514. package/fjs/emergent_testing/types.js +0 -6
  515. package/fjs/js/tokenizer/types.js +0 -6
  516. package/fjs/media/html/types.js +0 -6
  517. package/fjs/media/json/parser/types.js +0 -6
  518. package/fjs/media/json/tokenizer/types.js +0 -6
  519. package/fjs/media/json/types.js +0 -13
  520. package/fjs/media/nix/types.js +0 -6
  521. package/fjs/media/revision/types.js +0 -8
  522. package/fjs/media/type/types.js +0 -6
  523. package/fjs/media/types.js +0 -7
  524. package/fjs/nanvm/types.js +0 -11
  525. package/fjs/protocol/json_rpc/types.js +0 -8
  526. package/fjs/protocol/mcp/types.js +0 -8
  527. package/fjs/sul/id/types.js +0 -6
  528. package/fjs/sul/level/hash/types.js +0 -6
  529. package/fjs/sul/level/literal/types.js +0 -6
  530. package/fjs/sul/types.js +0 -6
  531. package/fjs/text/sgr/types.js +0 -6
  532. package/fjs/text/types.js +0 -6
  533. package/fjs/text/utf16/types.js +0 -6
  534. package/fjs/text/utf8/types.js +0 -6
  535. package/fjs/types/array/types.js +0 -6
  536. package/fjs/types/bigfloat/types.js +0 -6
  537. package/fjs/types/bigint/types.js +0 -6
  538. package/fjs/types/bit_vec/types.js +0 -6
  539. package/fjs/types/btree/find/types.js +0 -6
  540. package/fjs/types/btree/types/types.js +0 -6
  541. package/fjs/types/byte_set/types.js +0 -6
  542. package/fjs/types/function/compare/types.js +0 -6
  543. package/fjs/types/function/operator/types.js +0 -6
  544. package/fjs/types/function/types.js +0 -6
  545. package/fjs/types/list/types.js +0 -6
  546. package/fjs/types/nibble_set/types.js +0 -6
  547. package/fjs/types/nominal/types.js +0 -6
  548. package/fjs/types/nullable/types.js +0 -6
  549. package/fjs/types/object/types.js +0 -8
  550. package/fjs/types/option/types.js +0 -6
  551. package/fjs/types/ordered_map/types.js +0 -6
  552. package/fjs/types/patricia_trie/types.js +0 -6
  553. package/fjs/types/phantom/types.js +0 -11
  554. package/fjs/types/prime_field/types.js +0 -6
  555. package/fjs/types/range/types.js +0 -6
  556. package/fjs/types/range_map/types.js +0 -6
  557. package/fjs/types/result/types.js +0 -6
  558. package/fjs/types/rtti/common/types.js +0 -1
  559. package/fjs/types/rtti/parse/types.js +0 -1
  560. package/fjs/types/rtti/ts/types.js +0 -1
  561. package/fjs/types/rtti/types.js +0 -1
  562. package/fjs/types/rtti/validate/module.f.d.mts +0 -6
  563. package/fjs/types/rtti/validate/module.f.mjs +0 -169
  564. package/fjs/types/rtti/validate/proof.f.d.mts +0 -125
  565. package/fjs/types/rtti/validate/proof.f.mjs +0 -437
  566. package/fjs/types/rtti/validate/types.d.ts +0 -6
  567. package/fjs/types/rtti/validate/types.js +0 -1
  568. package/fjs/types/sorted_list/types.js +0 -6
  569. package/fjs/types/sorted_set/types.js +0 -6
  570. package/fjs/types/string_set/types.js +0 -6
  571. package/fjs/types/ts/types.js +0 -8
@@ -9,10 +9,70 @@ import type { MemOp } from '../memory/types.ts';
9
9
  import type { Nominal } from '../../types/nominal/types.ts';
10
10
  import type { Result } from '../../types/result/types.ts';
11
11
  import type { StringMap } from '../../types/object/types.ts';
12
- import type { Effect, Operation, ToAsyncOperationMap } from '../types.ts';
12
+ import type { Effect, NotImplemented, Operation, ToAsyncOperationMap } from '../types.ts';
13
13
  import type { List } from '../list/types.ts';
14
- export type IoResult<T> = Result<T, unknown>;
15
- export type All = ['all', <T>(...effects: Effect<never, T>[]) => readonly T[]];
14
+ /**
15
+ * A host failure, normalized: whatever the runtime threw reduced to a
16
+ * serializable record. `code` is the OS error code when the host supplied one
17
+ * (`'ENOENT'`, `'EEXIST'`), absent otherwise.
18
+ *
19
+ * It is a tagged tuple for the same reason {@link NotImplemented} is — the two
20
+ * share an error channel, and the tag is what tells them apart. That
21
+ * distinction is the whole reason this type exists: with a bare `unknown`
22
+ * error, `NotImplemented | unknown` collapses to `unknown` and a program can no
23
+ * longer tell "this runner cannot do it" from "the host tried and failed".
24
+ *
25
+ * Normalizing also keeps the channel serializable. A thrown `Error` carries a
26
+ * stack, a `cause`, and arbitrary own properties; none of it survives a wire
27
+ * hop, and a runner in another process could not reproduce it.
28
+ */
29
+ export type IoError = readonly ['ioError', IoErrorInfo];
30
+ export type IoErrorInfo = {
31
+ readonly code?: string;
32
+ readonly message: string;
33
+ };
34
+ /**
35
+ * The result of an operation with no failures of its own: it either produces
36
+ * its value or reports that the runner does not implement it.
37
+ *
38
+ * Every operation's return type is a `Result`, including the ones that cannot
39
+ * fail on their own terms — an operation left on a raw contract would be a hole
40
+ * in the error channel, and a runner may omit a handler for any of them.
41
+ */
42
+ export type OpResult<T> = Result<T, NotImplemented>;
43
+ /**
44
+ * The error channel of anything that performs host IO: a normalized host
45
+ * failure, or the report that the runner does not implement the operation.
46
+ *
47
+ * It is one name rather than a union spelled at each site, and that is a
48
+ * migration property rather than brevity. An effect that does no IO *yet* is
49
+ * one added `readFile` away from doing some, and if each signature names its
50
+ * own errors, that one change walks up every enclosing signature — the failure
51
+ * mode that sank `throws` clauses elsewhere, where engineers eventually
52
+ * declared everything throwing rather than maintain the cascade. Declaring the
53
+ * standard channel once is that concession made deliberately: an IO-touching
54
+ * effect says it fails *the way node IO fails*, and gaining a new way to do so
55
+ * changes nothing above it.
56
+ *
57
+ * It is not a licence to widen. An operation with failures of its own extends
58
+ * the channel (`IoChannel | ParseError`), and a computation whose errors are
59
+ * genuinely narrower should say so — this is the default for IO, not a ceiling.
60
+ */
61
+ export type IoChannel = NotImplemented | IoError;
62
+ /**
63
+ * The result of an operation that performs host IO: its value, a normalized
64
+ * host failure, or the missing-handler report.
65
+ */
66
+ export type IoResult<T> = Result<T, IoChannel>;
67
+ /**
68
+ * Runs its effects concurrently and answers each one's whole `Result`.
69
+ *
70
+ * The nesting is deliberate and belongs to the runner: this envelope says
71
+ * whether `all` itself could be dispatched, and each inner `Result` is what
72
+ * that effect answered. `allOk` (`./module.f.mjs`) is the collapse a fallible
73
+ * chain wants.
74
+ */
75
+ export type All = ['all', <T, E>(...effects: Effect<never, T, E>[]) => OpResult<readonly Result<T, E>[]>];
16
76
  export type Fetch = ['fetch', (url: string) => IoResult<Vec>];
17
77
  export type MakeDirectoryOptions = {
18
78
  readonly recursive: true;
@@ -42,7 +102,7 @@ export type WriteFile = readonly ['writeFile', (path: string, data: Vec) => IoRe
42
102
  export type Rm = readonly ['rm', (path: string) => IoResult<void>];
43
103
  export type Rename = readonly ['rename', (src: string, dst: string) => IoResult<void>];
44
104
  export type ReadBytes = readonly ['readBytes', (path: string, offset: number, size: number) => IoResult<Vec>];
45
- export type RandomInt = readonly ['randomInt', () => number];
105
+ export type RandomInt = readonly ['randomInt', () => OpResult<number>];
46
106
  export type ExecResult = {
47
107
  readonly stdout: string;
48
108
  readonly stderr: string;
@@ -66,7 +126,7 @@ export type CreateExclusive = readonly ['createExclusive', (path: string) => IoR
66
126
  */
67
127
  export type WriteBytes = readonly ['writeBytes', (path: string, offset: number, data: Vec) => IoResult<void>];
68
128
  /** @internal */
69
- export type _WriteLoop = <O extends Operation>(offset: number, e: List<O, IoResult<Vec>>) => Effect<O | WriteBytes, IoResult<void>>;
129
+ export type _WriteLoop = <O extends Operation>(offset: number, e: List<O, Vec, IoChannel>) => Effect<O | WriteBytes, void, IoChannel>;
70
130
  /** File metadata returned by `stat`. Only `size` (in bytes) for now. */
71
131
  export type FileStat = {
72
132
  readonly size: number;
@@ -86,11 +146,16 @@ export type ServerResponse = {
86
146
  readonly headers: Headers;
87
147
  readonly body: Vec;
88
148
  };
89
- export type RequestListener<O extends Operation> = (_: IncomingMessage) => Effect<O, ServerResponse>;
90
- export type CreateServer = ['createServer', (listener: RequestListener<Operation>) => Server];
91
- export type Listen = ['listen', (server: Server, port: number) => void];
149
+ /**
150
+ * An HTTP request handler. The channel is `never` because the response frame
151
+ * *is* where a failure goes a listener that cannot answer still has a status
152
+ * code to answer with, so absorbing is the contract rather than an omission.
153
+ */
154
+ export type RequestListener<O extends Operation> = (_: IncomingMessage) => Effect<O, ServerResponse, never>;
155
+ export type CreateServer = ['createServer', (listener: RequestListener<Operation>) => OpResult<Server>];
156
+ export type Listen = ['listen', (server: Server, port: number) => OpResult<void>];
92
157
  export type Http = CreateServer | Listen;
93
- export type Forever = ['forever', () => never];
158
+ export type Forever = ['forever', () => OpResult<never>];
94
159
  export type Module = StringMap<unknown>;
95
160
  export type Import = ['import', (path: string) => IoResult<Module>];
96
161
  /** Named output streams accepted by the `Write` effect. */
@@ -100,7 +165,7 @@ export type WriteConsoles = 'stdout' | 'stderr';
100
165
  * a `Vec`. The Node runner maps each stream name to the appropriate fd and
101
166
  * delegates to the OS via `stream.write()` with backpressure handling.
102
167
  */
103
- export type Write = readonly ['write', (stream: WriteConsoles, data: Vec) => void];
168
+ export type Write = readonly ['write', (stream: WriteConsoles, data: Vec) => OpResult<void>];
104
169
  export type Console = (s: string) => Effect<Write, void>;
105
170
  /** Named input streams accepted by the `Read` effect. */
106
171
  export type ReadConsoles = 'stdin';
@@ -112,10 +177,10 @@ export type ReadConsoles = 'stdin';
112
177
  * rather than the interpreter. Back-pressure is naturally sequential — the next
113
178
  * `read` is only issued once the previous byte is consumed.
114
179
  */
115
- export type Read = readonly ['read', (stream: ReadConsoles) => number | null];
180
+ export type Read = readonly ['read', (stream: ReadConsoles) => OpResult<number | null>];
116
181
  /** @internal */
117
182
  export type _UtfList = EffectList<number>;
118
- export type Now = readonly ['now', () => number];
183
+ export type Now = readonly ['now', () => OpResult<number>];
119
184
  /**
120
185
  * The outcome of a `Sandbox` operation.
121
186
  *
@@ -132,7 +197,7 @@ export type SandboxResult<T> = {
132
197
  */
133
198
  readonly duration: number;
134
199
  };
135
- export type Sandbox = readonly ['sandbox', <T>(f: () => T) => SandboxResult<T>];
200
+ export type Sandbox = readonly ['sandbox', <T>(f: () => T) => OpResult<SandboxResult<T>>];
136
201
  /**
137
202
  * Resolves the return value of a test function inside the effect runner.
138
203
  * If `p` is a real `Promise`, it is awaited and rejections propagate as
@@ -140,7 +205,7 @@ export type Sandbox = readonly ['sandbox', <T>(f: () => T) => SandboxResult<T>];
140
205
  * (objects with a `.then` method that are not `instanceof Promise`) are
141
206
  * treated as ordinary values — not awaited. See `fjs/dev/tf/README.md`.
142
207
  */
143
- export type Await = readonly ['await', (p: unknown) => readonly [unknown]];
208
+ export type Await = readonly ['await', (p: unknown) => OpResult<readonly [unknown]>];
144
209
  /**
145
210
  * Signature of a framework test-registration function (e.g. `nodeTest.test`,
146
211
  * `bunTest.test`). Returns `Promise<void>` so async sub-tests can be awaited.
@@ -157,10 +222,18 @@ export type TestFn = (name: string, options: {
157
222
  export type TestContext = {
158
223
  readonly test: TestFn;
159
224
  };
160
- /** Effect operation that registers a named test with the active `TestContext`. */
161
- export type Test = readonly ['test', (ctx: TestContext, name: string, expectFailure: boolean, test: (t: TestContext) => Effect<Test | All | Await, void>) => void];
225
+ /**
226
+ * Operation that registers a named test with the active `TestContext`.
227
+ *
228
+ * The callback's `never` is the honest reading of what an external framework
229
+ * accepts. Node `--test`, Bun and Deno take a body that either returns or
230
+ * throws; there is no channel to answer a failure through, so the body absorbs
231
+ * its own — which `emergent_testing` does, by panicking, since a throw is the
232
+ * one failure signal those frameworks understand.
233
+ */
234
+ export type Test = readonly ['test', (ctx: TestContext, name: string, expectFailure: boolean, test: (t: TestContext) => Effect<Test | All | Await, void, never>) => OpResult<void>];
162
235
  export type NodeOp = Access | All | Await | Fetch | Fs | Http | Forever | Import | MemOp | Now | RandomInt | Read | Sandbox | Write | Test;
163
- export type NodeEffect<T> = Effect<NodeOp, T>;
236
+ export type NodeEffect<T, E = IoChannel> = Effect<NodeOp, T, E>;
164
237
  export type NodeOperationMap = ToAsyncOperationMap<NodeOp>;
165
238
  /**
166
239
  * The environment variables.
@@ -199,5 +272,20 @@ export type NodeProgramOptions = {
199
272
  readonly nodeVersion?: string;
200
273
  readonly inlineTestContext: boolean;
201
274
  };
202
- export type Program<O extends Operation> = (options: NodeProgramOptions) => Effect<O, number>;
275
+ /**
276
+ * A program: run it, and it answers an exit code.
277
+ *
278
+ * The code lives in a `Result` rather than in a bare `number`, and the two
279
+ * branches say which kind of code it is — `ok(0)` for success, `error(n)` for
280
+ * failure. A bare `number` could not: nothing could short-circuit on it, so a
281
+ * chain that ran one program and then another had to re-test the code by hand,
282
+ * and `step(…, () => pure(0))` was a way to report a failed program as a clean
283
+ * exit that the type system had no opinion about.
284
+ *
285
+ * **`T` is the literal `0`**, so a success carries no information beyond
286
+ * having succeeded, and `r[1]` is the exit code in *either* branch. A runner
287
+ * reads the code without asking which branch it came from; a caller that cares
288
+ * whether the program failed asks `r[0]`.
289
+ */
290
+ export type Program<O extends Operation> = (options: NodeProgramOptions) => Effect<O, 0, number>;
203
291
  export type NodeProgram = Program<NodeOp>;
@@ -2,16 +2,33 @@
2
2
  * Virtual Node-effect operations for filesystem and process tests.
3
3
  *
4
4
  * @module
5
+ *
6
+ * @import { Vec } from '../../../types/bit_vec/types.ts'
7
+ * @import { PartialMemOperationMap, RunInstance } from '../../mock/types.ts'
8
+ * @import { Dirent, FileStat, IoError, IoResult, Module, NodeOp, NodeProgramOptions, SandboxResult } from '../types.ts'
9
+ * @import { Result } from '../../../types/result/types.ts'
10
+ * @import { Error } from '../../../types/result/types.ts'
11
+ * @import { Dir, State, _Entity } from './types.ts'
5
12
  */
6
13
  import type { RunInstance } from '../../mock/types.ts';
7
14
  import type { NodeOp, NodeProgramOptions } from '../types.ts';
8
15
  import type { State } from './types.ts';
9
- /** @import { Key } from '../../memory/types.ts' */
10
- /** @import { Dirent, FileStat, IoResult, Module, NodeOp, NodeProgramOptions, SandboxResult } from '../types.ts' */
11
- /** @import { Dir, State, _Entity } from './types.ts' */
12
16
  /** @type {State} */
13
17
  export declare const emptyState: State;
14
- /** @type {RunInstance<NodeOp, State>} */
18
+ /**
19
+ * The virtual runner.
20
+ *
21
+ * **It implements part of `NodeOp`, and says so.** `exec`, `createServer`,
22
+ * `listen`, `forever` and `test` have no meaning against an in-memory
23
+ * filesystem, and they used to be present as `todo` handlers — entries that
24
+ * existed only to satisfy a total operation map and threw when reached. They
25
+ * are simply absent now, so a program that asks for one gets
26
+ * `error(notImplemented)` back through its own continuation and decides what an
27
+ * incompatible runner means for it, which is what `NotImplemented` was
28
+ * introduced for. A command that is not a `NodeOp` at all still panics.
29
+ *
30
+ * @type {RunInstance<NodeOp, State>}
31
+ */
15
32
  export declare const virtual: RunInstance<NodeOp, State>;
16
33
  /**
17
34
  * Safe, inert defaults for every {@link NodeProgramOptions} field, intended for
@@ -2,20 +2,23 @@
2
2
  * Virtual Node-effect operations for filesystem and process tests.
3
3
  *
4
4
  * @module
5
+ *
6
+ * @import { Vec } from '../../../types/bit_vec/types.ts'
7
+ * @import { PartialMemOperationMap, RunInstance } from '../../mock/types.ts'
8
+ * @import { Dirent, FileStat, IoError, IoResult, Module, NodeOp, NodeProgramOptions, SandboxResult } from '../types.ts'
9
+ * @import { Result } from '../../../types/result/types.ts'
10
+ * @import { Error } from '../../../types/result/types.ts'
11
+ * @import { Dir, State, _Entity } from './types.ts'
5
12
  */
6
13
 
7
- import { todo } from '../../../asserts/module.f.mjs'
14
+ import { assert, todo } from '../../../asserts/module.f.mjs'
8
15
  import { isProperPrefix, join, parse } from '../../../path/module.f.mjs'
9
16
  import { utf8ToString } from '../../../text/module.f.mjs'
10
- /** @import { Vec } from '../../../types/bit_vec/types.ts' */
11
17
  import { empty, length, maxLengthBytes, msb, vec } from '../../../types/bit_vec/module.f.mjs'
12
18
  import { error, ok } from '../../../types/result/module.f.mjs'
13
- import { run } from '../../mock/module.f.mjs'
14
- /** @import { MemOperationMap, RunInstance } from '../../mock/types.ts' */
19
+ import { ioError, nodeCommands } from '../module.f.mjs'
20
+ import { partialRun } from '../../mock/module.f.mjs'
15
21
  import { asBase, asNominal } from '../../memory/module.f.mjs'
16
- /** @import { Key } from '../../memory/types.ts' */
17
- /** @import { Dirent, FileStat, IoResult, Module, NodeOp, NodeProgramOptions, SandboxResult } from '../types.ts' */
18
- /** @import { Dir, State, _Entity } from './types.ts' */
19
22
 
20
23
  /** @type {State} */
21
24
  export const emptyState = {
@@ -43,10 +46,13 @@ const operation = op => {
43
46
  }
44
47
  const [first, ...rest] = path
45
48
  const subDir = dir[first]
46
- if (typeof subDir !== 'object' || Array.isArray(subDir)) {
49
+ // `instanceof Array`, not `Array.isArray`: the latter narrows to `any[]`,
50
+ // which `readonly Vec[]` is not assignable to, so its negative branch never
51
+ // removes a `readonly` array from `_Entity`. Only `instanceof` narrows here.
52
+ if (typeof subDir !== 'object' || subDir instanceof Array) {
47
53
  return op(dir, path)
48
54
  }
49
- const [newSubDir, r] = f(/** @type {Dir} */ (subDir), rest)
55
+ const [newSubDir, r] = f(subDir, rest)
50
56
  return [{ ...dir, [first]: newSubDir }, r]
51
57
  }
52
58
  return path => state => {
@@ -64,12 +70,22 @@ const readOperation = op => operation((dir, path) => [dir, op(dir, path)])
64
70
 
65
71
  const okVoid = ok(undefined)
66
72
 
73
+ /**
74
+ * A virtual host failure. The virtual runner reports the same normalized
75
+ * {@link IoError} the Node runner does, so a program cannot tell the two apart
76
+ * by the shape of what it catches — which is what makes a proof against the
77
+ * virtual filesystem evidence about the real one.
78
+ *
79
+ * @type {(message: string) => Error<IoError>}
80
+ */
81
+ const fail = message => error(ioError({ message }))
82
+
67
83
  /** @type {(recursive: boolean) => (dir: Dir, path: readonly string[]) => readonly [Dir, IoResult<void>]} */
68
84
  const mkdirOp = recursive => (dir, path) => {
69
85
  let d = {}
70
86
  let i = path.length
71
87
  if (i > 1 && !recursive) {
72
- return [dir, error('non-recursive')]
88
+ return [dir, fail('non-recursive')]
73
89
  }
74
90
  while (i > 0) {
75
91
  i -= 1
@@ -83,7 +99,7 @@ const mkdirOp = recursive => (dir, path) => {
83
99
  const mkdir = recursive => operation(mkdirOp(recursive))
84
100
 
85
101
  /** Absent-path error mirroring Node's `ENOENT`, so `isNotFound` recognizes it. */
86
- const enoent = error({ code: 'ENOENT' })
102
+ const enoent = error(ioError({ code: 'ENOENT', message: 'no such file or directory' }))
87
103
 
88
104
  /** @type {(path: string) => (state: State) => readonly [State, IoResult<Vec>]} */
89
105
  const readFile = readOperation((dir, path) => {
@@ -91,15 +107,18 @@ const readFile = readOperation((dir, path) => {
91
107
  const file = dir[path[0]]
92
108
  if (typeof file === 'function') { throw new Error(`'${path[0]}' is a JsModule; readFile not supported`) }
93
109
  if (file === undefined) { return enoent }
94
- if (!Array.isArray(file)) { return error(`'${path[0]}' is not a file`) }
95
- const chunks = /** @type {readonly Vec[]} */ (file)
110
+ // `operation`'s wrapper descends into every plain-object (`Dir`) entry
111
+ // before this op ever runs, and the `JsModule` case already threw above,
112
+ // so `file` here is always a `Vec[]` — never a bare `Dir`.
113
+ assert(Array.isArray(file), `'${path[0]}' is not a file`)
114
+ const chunks = file
96
115
  const capBits = maxLengthBytes * 8n
97
116
  let result = empty
98
117
  for (const chunk of chunks) {
99
118
  const chunkLen = length(chunk)
100
119
  if (chunkLen === 0n) { continue }
101
120
  if (length(result) + chunkLen > capBits) {
102
- return error(`File size exceeds maximum allowed size of ${maxLengthBytes} bytes`)
121
+ return fail(`File size exceeds maximum allowed size of ${maxLengthBytes} bytes`)
103
122
  }
104
123
  result = msb.concat(result)(chunk)
105
124
  }
@@ -108,13 +127,13 @@ const readFile = readOperation((dir, path) => {
108
127
 
109
128
  /** @type {(path: string) => (state: State) => readonly [State, IoResult<Module>]} */
110
129
  const import_ = readOperation((dir, path) => {
111
- if (path.length !== 1) { return error('no such file') }
130
+ if (path.length !== 1) { return fail('no such file') }
112
131
  const entry = dir[path[0]]
113
- if (typeof entry !== 'function') { return error(`'${path[0]}' is not a JsModule`) }
132
+ if (typeof entry !== 'function') { return fail(`'${path[0]}' is not a JsModule`) }
114
133
  return ok(entry())
115
134
  })
116
135
 
117
- const writeFileError = error('invalid file')
136
+ const writeFileError = fail('invalid file')
118
137
 
119
138
  /** @type {(payload: Vec) => (dir: Dir, path: readonly string[]) => readonly [Dir, IoResult<void>]} */
120
139
  const writeFileOp = payload => (dir, path) => {
@@ -129,7 +148,7 @@ const writeFileOp = payload => (dir, path) => {
129
148
  /** @type {(payload: Vec) => (path: string) => (state: State) => readonly [State, IoResult<void>]} */
130
149
  const writeFile = payload => operation(writeFileOp(payload))
131
150
 
132
- const invalidPath = error('invalid path')
151
+ const invalidPath = fail('invalid path')
133
152
 
134
153
  const { entries } = Object
135
154
 
@@ -142,10 +161,10 @@ const readdir = (base, recursive) => readOperation((dir, path) => {
142
161
  let result = []
143
162
  for (const [name, content] of entries(d)) {
144
163
  if (content === undefined) { continue }
145
- const isFile = Array.isArray(content) || typeof content !== 'object'
164
+ const isFile = content instanceof Array || typeof content !== 'object'
146
165
  result = [...result, { name, parentPath, isFile }]
147
166
  if (!isFile && recursive) {
148
- result = [...result, ...f(join(parentPath, name), /** @type {Dir} */ (content))]
167
+ result = [...result, ...f(join(parentPath, name), content)]
149
168
  }
150
169
  }
151
170
  return result
@@ -162,11 +181,15 @@ const access = readOperation((dir, path) => {
162
181
 
163
182
  /** @type {(dir: Dir, path: readonly string[]) => readonly [Dir, IoResult<void>]} */
164
183
  const rmOp = (dir, path) => {
165
- if (path.length !== 1) { return [dir, error('invalid path')] }
184
+ if (path.length !== 1) { return [dir, fail('invalid path')] }
166
185
  const [name] = path
167
186
  const entry = dir[name]
168
- if (entry === undefined) { return [dir, error('no such file')] }
169
- if (!Array.isArray(entry) && typeof entry === 'object') { return [dir, error('is a directory')] }
187
+ if (entry === undefined) { return [dir, fail('no such file')] }
188
+ // No "is a directory" guard here: `operation`'s wrapper descends into
189
+ // every plain-object (`Dir`) entry before this op ever runs, so `entry`
190
+ // is always a `Vec[]` or a `JsModule` — never a bare `Dir` — and rm can
191
+ // always proceed. (`rm` on a genuinely non-empty directory instead hits
192
+ // `path.length !== 1` above, once the wrapper has descended into it.)
170
193
  const { [name]: _, ...rest } = dir
171
194
  return [rest, okVoid]
172
195
  }
@@ -176,7 +199,7 @@ const rm = operation(rmOp)
176
199
 
177
200
  /** @type {(dir: Dir, path: readonly string[]) => readonly [Dir, IoResult<_Entity>]} */
178
201
  const extractEntity = (dir, path) => {
179
- if (path.length === 0) { return [dir, error('cannot extract root')] }
202
+ if (path.length === 0) { return [dir, fail('cannot extract root')] }
180
203
  if (path.length === 1) {
181
204
  const [name] = path
182
205
  const entry = dir[name]
@@ -186,15 +209,21 @@ const extractEntity = (dir, path) => {
186
209
  }
187
210
  const [first, ...rest] = path
188
211
  const sub = dir[first]
189
- if (sub === undefined || Array.isArray(sub) || typeof sub === 'function') { return [dir, enoent] }
190
- const [newSub, result] = extractEntity(/** @type {Dir} */ (sub), rest)
212
+ if (sub === undefined || sub instanceof Array || typeof sub === 'function') { return [dir, enoent] }
213
+ const [newSub, result] = extractEntity(sub, rest)
191
214
  if (result[0] === 'error') { return [dir, result] }
192
215
  return [{ ...dir, [first]: newSub }, result]
193
216
  }
194
217
 
195
218
  /** @type {(dir: Dir, path: readonly string[], entity: _Entity) => readonly [Dir, IoResult<void>]} */
196
219
  const insertEntityAt = (dir, path, entity) => {
197
- if (path.length === 0) { return [dir, error('cannot insert at root')] }
220
+ // `insertEntityAt`'s only external caller, `rename`, always rejects an
221
+ // empty `dst` earlier — `isProperPrefix([], srcParsed)` is true whenever
222
+ // `srcParsed` is non-empty, so renaming onto root is already caught as
223
+ // "onto an ancestor" before this function runs. The recursive self-calls
224
+ // below never pass an empty path either (they only recurse when
225
+ // `path.length > 1`, with a non-empty remainder).
226
+ assert(path.length > 0, 'cannot insert at root')
198
227
  if (path.length === 1) {
199
228
  const [name] = path
200
229
  const existing = dir[name]
@@ -202,16 +231,16 @@ const insertEntityAt = (dir, path, entity) => {
202
231
  const entityIsDir = !Array.isArray(entity) && typeof entity === 'object'
203
232
  const existingIsDir = !Array.isArray(existing) && typeof existing === 'object'
204
233
  if (entityIsDir && !existingIsDir) {
205
- return [dir, error(`cannot overwrite file '${name}' with a directory`)]
234
+ return [dir, fail(`cannot overwrite file '${name}' with a directory`)]
206
235
  }
207
236
  if (!entityIsDir && existingIsDir) {
208
- return [dir, error(`'${name}' is a directory`)]
237
+ return [dir, fail(`'${name}' is a directory`)]
209
238
  }
210
239
  if (entityIsDir && existingIsDir) {
211
- const existingDir = /** @type {Dir} */ (existing)
240
+ const existingDir = existing
212
241
  const hasContent = Object.values(existingDir).some(v => v !== undefined)
213
242
  if (hasContent) {
214
- return [dir, error(`cannot overwrite non-empty directory '${name}'`)]
243
+ return [dir, fail(`cannot overwrite non-empty directory '${name}'`)]
215
244
  }
216
245
  }
217
246
  }
@@ -220,8 +249,8 @@ const insertEntityAt = (dir, path, entity) => {
220
249
  const [first, ...rest] = path
221
250
  const sub = dir[first]
222
251
  if (sub === undefined) { return [dir, enoent] }
223
- if (Array.isArray(sub) || typeof sub === 'function') { return [dir, error('not a directory')] }
224
- const [newSub, result] = insertEntityAt(/** @type {Dir} */ (sub), rest, entity)
252
+ if (sub instanceof Array || typeof sub === 'function') { return [dir, fail('not a directory')] }
253
+ const [newSub, result] = insertEntityAt(sub, rest, entity)
225
254
  if (result[0] === 'error') { return [dir, result] }
226
255
  return [{ ...dir, [first]: newSub }, result]
227
256
  }
@@ -236,7 +265,7 @@ const rename = (src, dst) => state => {
236
265
  // now that source exists, reject if dst is strictly inside src's subtree (rename into own descendant)
237
266
  // or if src is strictly inside dst's subtree (rename onto own ancestor)
238
267
  if (isProperPrefix(srcParsed, dstParsed) || isProperPrefix(dstParsed, srcParsed)) {
239
- return [state, error('cannot rename a directory into its own subtree or onto an ancestor')]
268
+ return [state, fail('cannot rename a directory into its own subtree or onto an ancestor')]
240
269
  }
241
270
  const [dstRoot, dstResult] = insertEntityAt(srcRoot, dstParsed, srcResult[1])
242
271
  if (dstResult[0] === 'error') { return [state, dstResult] }
@@ -249,13 +278,16 @@ const readBytesOp = (path, offset, size) => readOperation((dir, p) => {
249
278
  const file = dir[p[0]]
250
279
  if (typeof file === 'function') { throw new Error(`'${p[0]}' is a JsModule; readBytes not supported`) }
251
280
  if (file === undefined) { return enoent }
252
- if (!Array.isArray(file)) { return error(`'${p[0]}' is not a file`) }
253
- if (!Number.isInteger(offset)) { return error(`Offset ${offset} is not an integer`) }
254
- if (!Number.isInteger(size)) { return error(`Chunk size ${size} is not an integer`) }
255
- if (offset < 0) { return error(`Offset ${offset} is negative`) }
256
- if (size < 0) { return error(`Chunk size ${size} is negative`) }
257
- if (BigInt(size) > maxLengthBytes) { return error(`Chunk size ${size} exceeds maximum allowed size of ${maxLengthBytes} bytes`) }
258
- const chunks = /** @type {readonly Vec[]} */ (file)
281
+ // `operation`'s wrapper descends into every plain-object (`Dir`) entry
282
+ // before this op ever runs, and the `JsModule` case already threw above,
283
+ // so `file` here is always a `Vec[]` never a bare `Dir`.
284
+ assert(Array.isArray(file), `'${p[0]}' is not a file`)
285
+ if (!Number.isInteger(offset)) { return fail(`Offset ${offset} is not an integer`) }
286
+ if (!Number.isInteger(size)) { return fail(`Chunk size ${size} is not an integer`) }
287
+ if (offset < 0) { return fail(`Offset ${offset} is negative`) }
288
+ if (size < 0) { return fail(`Chunk size ${size} is negative`) }
289
+ if (BigInt(size) > maxLengthBytes) { return fail(`Chunk size ${size} exceeds maximum allowed size of ${maxLengthBytes} bytes`) }
290
+ const chunks = file
259
291
  let toSkip = BigInt(offset) * 8n
260
292
  let toRead = BigInt(size) * 8n
261
293
  let result = empty
@@ -282,7 +314,7 @@ const fileSizeBytes = chunks =>
282
314
  chunks.reduce((acc, c) => acc + Number(length(c) / 8n), 0)
283
315
 
284
316
  /** Absent-path error for an already-existing exclusive create, mirroring `EEXIST`. */
285
- const eexist = error({ code: 'EEXIST' })
317
+ const eexist = error(ioError({ code: 'EEXIST', message: 'file already exists' }))
286
318
 
287
319
  /** @type {(dir: Dir, path: readonly string[]) => readonly [Dir, IoResult<void>]} */
288
320
  const createExclusiveOp = (dir, path) => {
@@ -307,11 +339,11 @@ const writeBytesRawOp = (offset, data) => (dir, p) => {
307
339
  const [name] = p
308
340
  const file = dir[name]
309
341
  if (file === undefined) { return [dir, enoent] } // writeBytes never creates
310
- if (!Array.isArray(file)) { return [dir, error(`'${name}' is not a file`)] }
311
- if (!Number.isInteger(offset) || offset < 0) { return [dir, error(`Offset ${offset} is invalid`)] }
312
- const chunks = /** @type {readonly Vec[]} */ (file)
342
+ if (!Array.isArray(file)) { return [dir, fail(`'${name}' is not a file`)] }
343
+ if (!Number.isInteger(offset) || offset < 0) { return [dir, fail(`Offset ${offset} is invalid`)] }
344
+ const chunks = file
313
345
  if (offset !== fileSizeBytes(chunks)) {
314
- return [dir, error(`writeBytes offset ${offset} must equal the file size (append-only)`)]
346
+ return [dir, fail(`writeBytes offset ${offset} must equal the file size (append-only)`)]
315
347
  }
316
348
  return [{ ...dir, [name]: [...chunks, data] }, okVoid]
317
349
  }
@@ -324,43 +356,46 @@ const statOp = readOperation((dir, path) => {
324
356
  if (path.length !== 1) { return enoent }
325
357
  const file = dir[path[0]]
326
358
  if (file === undefined) { return enoent }
327
- if (!Array.isArray(file)) { return error(`'${path[0]}' is not a file`) }
328
- return ok({ size: fileSizeBytes(/** @type {readonly Vec[]} */ (file)) })
359
+ if (!Array.isArray(file)) { return fail(`'${path[0]}' is not a file`) }
360
+ return ok({ size: fileSizeBytes(file) })
329
361
  })
330
362
 
331
- /** @type {MemOperationMap<NodeOp, State>} */
363
+ /** @type {PartialMemOperationMap<NodeOp, State>} */
332
364
  const map = {
333
365
  all: (...a) => state => {
334
- /** @type {readonly unknown[]} */
366
+ // Each entry is the effect's whole `Result`: `all`'s own envelope says
367
+ // only whether the runner could dispatch it, so the inner answers pass
368
+ // through untouched for `allOk` to collapse.
369
+ /** @type {readonly Result<unknown, unknown>[]} */
335
370
  let e = []
336
371
  for (const i of a) {
337
372
  const [ns, ei] = virtual(state)(i)
338
373
  state = ns
339
374
  e = [...e, ei]
340
375
  }
341
- return [state, e]
376
+ return [state, ok(e)]
342
377
  },
343
378
  memCreate: value => state => {
344
379
  const id = `mem${state.memoryNext}`
345
- const key = /** @type {Key<unknown>} */ (asNominal(id))
380
+ const key = asNominal(id)
346
381
  return [{
347
382
  ...state,
348
383
  memoryNext: state.memoryNext + 1,
349
384
  memoryValues: { ...state.memoryValues, [id]: value },
350
- }, key]
385
+ }, ok(key)]
351
386
  },
352
387
  memRead: key => state =>
353
- [state, state.memoryValues[asBase(key)]],
388
+ [state, ok(state.memoryValues[asBase(key)])],
354
389
  memWrite: (key, value) => state => {
355
390
  const id = asBase(key)
356
391
  return [{
357
392
  ...state,
358
393
  memoryValues: { ...state.memoryValues, [id]: value },
359
- }, undefined]
394
+ }, okVoid]
360
395
  },
361
396
  fetch: url => state => {
362
397
  const result = state.internet[url]
363
- return result === undefined ? [state, error('not found')] : [state, ok(result)]
398
+ return result === undefined ? [state, fail('not found')] : [state, ok(result)]
364
399
  },
365
400
  mkdir: (path, p) => mkdir(p !== undefined)(path),
366
401
  readFile,
@@ -374,12 +409,8 @@ const map = {
374
409
  createExclusive,
375
410
  writeBytes: writeBytesOp,
376
411
  stat: statOp,
377
- randomInt: () => state => [{ ...state, randomNext: state.randomNext + 1 }, state.randomNext],
378
- exec: todo,
379
- createServer: todo,
380
- listen: todo,
381
- forever: todo,
382
- now: () => state => [state, state.epochNs],
412
+ randomInt: () => state => [{ ...state, randomNext: state.randomNext + 1 }, ok(state.randomNext)],
413
+ now: () => state => [state, ok(state.epochNs)],
383
414
  // Virtual sandbox is a pass-through: the fixture's test function is
384
415
  // expected to return a `SandboxResult` directly (encoding pass/fail and a
385
416
  // chosen duration), so the handler invokes it without try/catch or clock
@@ -387,23 +418,35 @@ const map = {
387
418
  // result instead of the runner measuring real execution. A genuine
388
419
  // exception in a fixture propagates loudly as a bug in the fixture.
389
420
  // See: issues/156-tf-virtual-tests.md
390
- sandbox: f => state => [state, /** @type {SandboxResult<unknown>} */ (f())],
391
- await: p => state => [state, [p]],
392
- test: todo,
421
+ sandbox: f => state => [state, ok(/** @type {SandboxResult<unknown>} */ (f()))],
422
+ await: p => state => [state, ok([p])],
393
423
  write: (stream, data) => state => {
394
424
  const s = utf8ToString(data)
395
- return [{ ...state, [stream]: `${state[stream]}${s}` }, undefined]
425
+ return [{ ...state, [stream]: `${state[stream]}${s}` }, okVoid]
396
426
  },
397
427
  read: () => state => {
398
428
  const [first, ...rest] = state.stdin
399
429
  return state.stdin.length === 0
400
- ? [state, null]
401
- : [{ ...state, stdin: rest }, first]
430
+ ? [state, ok(null)]
431
+ : [{ ...state, stdin: rest }, ok(first)]
402
432
  },
403
433
  }
404
434
 
405
- /** @type {RunInstance<NodeOp, State>} */
406
- export const virtual = run(map)
435
+ /**
436
+ * The virtual runner.
437
+ *
438
+ * **It implements part of `NodeOp`, and says so.** `exec`, `createServer`,
439
+ * `listen`, `forever` and `test` have no meaning against an in-memory
440
+ * filesystem, and they used to be present as `todo` handlers — entries that
441
+ * existed only to satisfy a total operation map and threw when reached. They
442
+ * are simply absent now, so a program that asks for one gets
443
+ * `error(notImplemented)` back through its own continuation and decides what an
444
+ * incompatible runner means for it, which is what `NotImplemented` was
445
+ * introduced for. A command that is not a `NodeOp` at all still panics.
446
+ *
447
+ * @type {RunInstance<NodeOp, State>}
448
+ */
449
+ export const virtual = partialRun(nodeCommands)(map)
407
450
 
408
451
  const testContext = { test: todo }
409
452