functionalscript 0.45.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 (296) 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 +10 -0
  4. package/fjs/asn.1/proof.f.mjs +16 -0
  5. package/fjs/basen/base128/module.f.mjs +22 -5
  6. package/fjs/bnf/data/module.f.d.mts +32 -6
  7. package/fjs/bnf/data/module.f.mjs +112 -7
  8. package/fjs/bnf/data/proof.f.d.mts +2 -0
  9. package/fjs/bnf/data/proof.f.mjs +74 -3
  10. package/fjs/bnf/data/types.d.ts +20 -2
  11. package/fjs/bnf/descent/module.f.d.mts +28 -14
  12. package/fjs/bnf/descent/module.f.mjs +122 -77
  13. package/fjs/bnf/descent/proof.f.d.mts +2 -0
  14. package/fjs/bnf/descent/proof.f.mjs +117 -31
  15. package/fjs/bnf/descent/types.d.ts +12 -14
  16. package/fjs/bnf/ll1/module.f.d.mts +64 -22
  17. package/fjs/bnf/ll1/module.f.mjs +214 -154
  18. package/fjs/bnf/ll1/proof.f.d.mts +15 -2
  19. package/fjs/bnf/ll1/proof.f.mjs +323 -149
  20. package/fjs/bnf/ll1/types.d.ts +16 -24
  21. package/fjs/bnf/matcher/module.f.d.mts +66 -0
  22. package/fjs/bnf/matcher/module.f.mjs +81 -0
  23. package/fjs/bnf/matcher/proof.f.d.mts +10 -0
  24. package/fjs/bnf/matcher/proof.f.mjs +79 -0
  25. package/fjs/bnf/matcher/types.d.ts +54 -0
  26. package/fjs/bnf/testlib.f.d.mts +31 -0
  27. package/fjs/bnf/testlib.f.mjs +80 -0
  28. package/fjs/cas/cli/module.f.d.mts +1 -1
  29. package/fjs/cas/cli/module.f.mjs +14 -20
  30. package/fjs/cas/cli/proof.f.d.mts +1 -3
  31. package/fjs/cas/cli/proof.f.mjs +44 -33
  32. package/fjs/cas/evo/module.f.d.mts +64 -18
  33. package/fjs/cas/evo/module.f.mjs +148 -70
  34. package/fjs/cas/evo/proof.f.d.mts +10 -1
  35. package/fjs/cas/evo/proof.f.mjs +305 -223
  36. package/fjs/cas/evo/types.d.ts +45 -9
  37. package/fjs/cas/module.f.d.mts +18 -32
  38. package/fjs/cas/module.f.mjs +129 -128
  39. package/fjs/cas/proof.f.d.mts +11 -8
  40. package/fjs/cas/proof.f.mjs +259 -147
  41. package/fjs/cas/types.d.ts +24 -10
  42. package/fjs/ci/config/module.f.d.mts +2 -2
  43. package/fjs/ci/config/module.f.mjs +2 -2
  44. package/fjs/ci/module.f.d.mts +5 -5
  45. package/fjs/ci/module.f.mjs +8 -7
  46. package/fjs/ci/nix/module.f.d.mts +7 -5
  47. package/fjs/ci/nix/module.f.mjs +13 -12
  48. package/fjs/ci/nix/proof.f.mjs +2 -2
  49. package/fjs/ci/proof.f.mjs +9 -5
  50. package/fjs/cli/module.f.d.mts +4 -6
  51. package/fjs/cli/module.f.mjs +4 -8
  52. package/fjs/cli/proof.f.mjs +17 -16
  53. package/fjs/cli/types.d.ts +2 -3
  54. package/fjs/common/monoid/types.d.ts +1 -1
  55. package/fjs/crypto/hmac/module.f.mjs +2 -2
  56. package/fjs/crypto/sha2/module.f.mjs +3 -1
  57. package/fjs/crypto/sha2/proof.f.d.mts +1 -0
  58. package/fjs/crypto/sha2/proof.f.mjs +24 -0
  59. package/fjs/crypto/sha2/types.d.ts +11 -0
  60. package/fjs/crypto/sign/module.f.mjs +2 -2
  61. package/fjs/dev/module.f.d.mts +13 -4
  62. package/fjs/dev/module.f.mjs +56 -27
  63. package/fjs/dev/update/module.f.d.mts +9 -4
  64. package/fjs/dev/update/module.f.mjs +14 -10
  65. package/fjs/dev/update/proof.f.d.mts +1 -3
  66. package/fjs/dev/update/proof.f.mjs +10 -5
  67. package/fjs/djs/module.f.d.mts +13 -5
  68. package/fjs/djs/module.f.mjs +31 -16
  69. package/fjs/djs/parser/module.f.d.mts +13 -3
  70. package/fjs/djs/parser/module.f.mjs +117 -16
  71. package/fjs/djs/parser/proof.f.d.mts +5 -1
  72. package/fjs/djs/parser/proof.f.mjs +274 -12
  73. package/fjs/djs/parser/types.d.ts +7 -1
  74. package/fjs/djs/proof.f.d.mts +18 -2
  75. package/fjs/djs/proof.f.mjs +187 -12
  76. package/fjs/djs/serializer/module.f.d.mts +25 -8
  77. package/fjs/djs/serializer/module.f.mjs +61 -15
  78. package/fjs/djs/serializer/proof.f.d.mts +5 -0
  79. package/fjs/djs/serializer/proof.f.mjs +23 -1
  80. package/fjs/djs/tokenizer/module.f.d.mts +17 -5
  81. package/fjs/djs/tokenizer/module.f.mjs +99 -60
  82. package/fjs/djs/tokenizer/proof.f.d.mts +1 -1
  83. package/fjs/djs/tokenizer/proof.f.mjs +74 -67
  84. package/fjs/djs/transpiler/module.f.d.mts +12 -7
  85. package/fjs/djs/transpiler/module.f.mjs +82 -56
  86. package/fjs/djs/transpiler/types.d.ts +7 -3
  87. package/fjs/djs/types.d.ts +7 -1
  88. package/fjs/effects/list/module.f.d.mts +14 -11
  89. package/fjs/effects/list/module.f.mjs +13 -11
  90. package/fjs/effects/list/types.d.ts +27 -7
  91. package/fjs/effects/memory/module.f.d.mts +2 -1
  92. package/fjs/effects/memory/module.f.mjs +3 -4
  93. package/fjs/effects/memory/proof.f.mjs +13 -7
  94. package/fjs/effects/memory/types.d.ts +4 -3
  95. package/fjs/effects/mock/module.f.d.mts +20 -4
  96. package/fjs/effects/mock/module.f.mjs +37 -5
  97. package/fjs/effects/mock/types.d.ts +10 -1
  98. package/fjs/effects/module.d.mts +4 -2
  99. package/fjs/effects/module.f.d.mts +466 -280
  100. package/fjs/effects/module.f.mjs +537 -299
  101. package/fjs/effects/module.mjs +2 -1
  102. package/fjs/effects/node/memory/module.d.mts +4 -2
  103. package/fjs/effects/node/memory/module.mjs +6 -3
  104. package/fjs/effects/node/memory/proof.mjs +10 -4
  105. package/fjs/effects/node/module.d.mts +4 -3
  106. package/fjs/effects/node/module.f.d.mts +168 -33
  107. package/fjs/effects/node/module.f.mjs +256 -52
  108. package/fjs/effects/node/module.mjs +57 -34
  109. package/fjs/effects/node/proof.f.d.mts +28 -2
  110. package/fjs/effects/node/proof.f.mjs +161 -42
  111. package/fjs/effects/node/types.d.ts +106 -18
  112. package/fjs/effects/node/virtual/module.f.d.mts +18 -4
  113. package/fjs/effects/node/virtual/module.f.mjs +110 -68
  114. package/fjs/effects/node/virtual/proof.f.d.mts +28 -2
  115. package/fjs/effects/node/virtual/proof.f.mjs +190 -9
  116. package/fjs/effects/proof.f.d.mts +69 -37
  117. package/fjs/effects/proof.f.mjs +410 -130
  118. package/fjs/effects/types.d.ts +161 -33
  119. package/fjs/emergent_testing/module.f.d.mts +19 -12
  120. package/fjs/emergent_testing/module.f.mjs +93 -33
  121. package/fjs/emergent_testing/proof.f.d.mts +21 -7
  122. package/fjs/emergent_testing/proof.f.mjs +166 -32
  123. package/fjs/emergent_testing/types.d.ts +22 -4
  124. package/fjs/fsm/module.f.d.mts +14 -4
  125. package/fjs/fsm/module.f.mjs +54 -37
  126. package/fjs/fsm/proof.f.d.mts +2 -0
  127. package/fjs/fsm/proof.f.mjs +83 -114
  128. package/fjs/js/keywords/module.f.d.mts +52 -0
  129. package/fjs/js/keywords/module.f.mjs +72 -0
  130. package/fjs/js/keywords/proof.f.d.mts +3 -0
  131. package/fjs/js/keywords/proof.f.mjs +13 -0
  132. package/fjs/js/tokenizer/module.f.d.mts +26 -6
  133. package/fjs/js/tokenizer/module.f.mjs +145 -159
  134. package/fjs/js/tokenizer/proof.f.d.mts +1 -0
  135. package/fjs/js/tokenizer/proof.f.mjs +54 -24
  136. package/fjs/js/tokenizer/types.d.ts +33 -24
  137. package/fjs/mcp/cas/module.f.d.mts +1 -6
  138. package/fjs/mcp/cas/module.f.mjs +55 -51
  139. package/fjs/mcp/cas/proof.f.d.mts +15 -0
  140. package/fjs/mcp/cas/proof.f.mjs +174 -0
  141. package/fjs/mcp/evo/module.f.d.mts +19 -10
  142. package/fjs/mcp/evo/module.f.mjs +48 -27
  143. package/fjs/mcp/evo/proof.f.d.mts +6 -1
  144. package/fjs/mcp/evo/proof.f.mjs +115 -31
  145. package/fjs/mcp/module.f.d.mts +4 -4
  146. package/fjs/mcp/module.f.mjs +6 -6
  147. package/fjs/mcp/proof.f.d.mts +5 -3
  148. package/fjs/mcp/proof.f.mjs +112 -46
  149. package/fjs/media/html/module.f.mjs +1 -1
  150. package/fjs/media/json/extended/module.f.d.mts +82 -0
  151. package/fjs/media/json/extended/module.f.mjs +153 -0
  152. package/fjs/media/json/extended/proof.f.d.mts +42 -0
  153. package/fjs/media/json/extended/proof.f.mjs +127 -0
  154. package/fjs/media/json/extended/types.d.ts +23 -0
  155. package/fjs/media/json/module.f.d.mts +8 -2
  156. package/fjs/media/json/module.f.mjs +43 -41
  157. package/fjs/media/json/number/module.f.d.mts +59 -0
  158. package/fjs/media/json/number/module.f.mjs +136 -0
  159. package/fjs/media/json/number/proof.f.d.mts +24 -0
  160. package/fjs/media/json/number/proof.f.mjs +86 -0
  161. package/fjs/media/json/number/types.d.ts +28 -0
  162. package/fjs/media/json/parser/module.f.d.mts +25 -13
  163. package/fjs/media/json/parser/module.f.mjs +114 -70
  164. package/fjs/media/json/parser/proof.f.d.mts +5 -0
  165. package/fjs/media/json/parser/proof.f.mjs +31 -1
  166. package/fjs/media/json/parser/types.d.ts +33 -14
  167. package/fjs/media/json/rtti/module.f.d.mts +1 -1
  168. package/fjs/media/json/rtti/module.f.mjs +1 -1
  169. package/fjs/media/json/rtti/proof.f.mjs +9 -9
  170. package/fjs/media/json/schema/module.f.mjs +3 -13
  171. package/fjs/media/json/schema/proof.f.d.mts +0 -1
  172. package/fjs/media/json/schema/proof.f.mjs +1 -2
  173. package/fjs/media/json/serializer/module.f.d.mts +32 -1
  174. package/fjs/media/json/serializer/module.f.mjs +64 -2
  175. package/fjs/media/json/tokenizer/module.f.mjs +7 -3
  176. package/fjs/media/json/tokenizer/proof.f.d.mts +6 -0
  177. package/fjs/media/json/tokenizer/proof.f.mjs +62 -21
  178. package/fjs/media/json/types.d.ts +36 -10
  179. package/fjs/media/lock/module.f.d.mts +100 -0
  180. package/fjs/media/lock/module.f.mjs +125 -0
  181. package/fjs/media/lock/proof.f.d.mts +33 -0
  182. package/fjs/media/lock/proof.f.mjs +196 -0
  183. package/fjs/media/lock/types.d.ts +15 -0
  184. package/fjs/media/module.f.d.mts +6 -5
  185. package/fjs/media/module.f.mjs +8 -7
  186. package/fjs/media/note/module.f.d.mts +121 -0
  187. package/fjs/media/note/module.f.mjs +131 -0
  188. package/fjs/media/note/proof.f.d.mts +29 -0
  189. package/fjs/media/note/proof.f.mjs +150 -0
  190. package/fjs/media/note/types.d.ts +10 -0
  191. package/fjs/media/proof.f.d.mts +4 -1
  192. package/fjs/media/proof.f.mjs +40 -21
  193. package/fjs/media/revision/module.f.d.mts +78 -7
  194. package/fjs/media/revision/module.f.mjs +119 -12
  195. package/fjs/media/revision/proof.f.d.mts +10 -0
  196. package/fjs/media/revision/proof.f.mjs +88 -0
  197. package/fjs/media/revision/types.d.ts +34 -5
  198. package/fjs/media/type/module.f.d.mts +33 -15
  199. package/fjs/media/type/module.f.mjs +35 -29
  200. package/fjs/media/type/proof.f.d.mts +2 -1
  201. package/fjs/media/type/proof.f.mjs +30 -10
  202. package/fjs/module.f.mjs +29 -8
  203. package/fjs/nanvm/proof.f.mjs +3 -3
  204. package/fjs/nanvm/rust/module.f.mjs +1 -1
  205. package/fjs/nanvm/update/module.f.d.mts +4 -4
  206. package/fjs/nanvm/update/module.f.mjs +8 -9
  207. package/fjs/nanvm/update/proof.f.mjs +4 -3
  208. package/fjs/proof.f.d.mts +3 -3
  209. package/fjs/proof.f.mjs +36 -10
  210. package/fjs/protocol/json_rpc/module.f.d.mts +2 -2
  211. package/fjs/protocol/json_rpc/module.f.mjs +3 -3
  212. package/fjs/protocol/json_rpc/proof.f.mjs +4 -4
  213. package/fjs/protocol/mcp/module.f.d.mts +10 -13
  214. package/fjs/protocol/mcp/module.f.mjs +74 -58
  215. package/fjs/protocol/mcp/proof.f.d.mts +13 -4
  216. package/fjs/protocol/mcp/proof.f.mjs +193 -61
  217. package/fjs/protocol/mcp/stdio/module.f.d.mts +15 -7
  218. package/fjs/protocol/mcp/stdio/module.f.mjs +38 -25
  219. package/fjs/protocol/mcp/stdio/proof.f.d.mts +4 -2
  220. package/fjs/protocol/mcp/stdio/proof.f.mjs +45 -12
  221. package/fjs/protocol/mcp/stdio/types.d.ts +1 -1
  222. package/fjs/protocol/mcp/types.d.ts +17 -6
  223. package/fjs/sul/id/module.f.d.mts +0 -1
  224. package/fjs/sul/id/module.f.mjs +2 -3
  225. package/fjs/sul/level/hash/module.f.mjs +2 -1
  226. package/fjs/sul/level/hash/proof.f.mjs +2 -2
  227. package/fjs/sul/module.f.mjs +18 -13
  228. package/fjs/text/code_point/module.f.d.mts +8 -0
  229. package/fjs/text/code_point/module.f.mjs +8 -1
  230. package/fjs/text/code_point/proof.f.d.mts +1 -0
  231. package/fjs/text/code_point/proof.f.mjs +11 -0
  232. package/fjs/text/sgr/module.f.d.mts +4 -6
  233. package/fjs/text/sgr/module.f.mjs +6 -7
  234. package/fjs/text/utf16/module.f.mjs +7 -2
  235. package/fjs/text/utf16/proof.f.mjs +3 -3
  236. package/fjs/text/utf8/module.f.mjs +4 -2
  237. package/fjs/types/array/module.f.mjs +14 -2
  238. package/fjs/types/bit_vec/module.f.d.mts +0 -2
  239. package/fjs/types/bit_vec/module.f.mjs +46 -32
  240. package/fjs/types/bit_vec/proof.f.mjs +2 -2
  241. package/fjs/types/btree/remove/module.f.mjs +1 -1
  242. package/fjs/types/btree/set/module.f.mjs +9 -11
  243. package/fjs/types/btree/set/proof.f.mjs +12 -0
  244. package/fjs/types/byte_set/module.f.d.mts +11 -4
  245. package/fjs/types/byte_set/module.f.mjs +14 -6
  246. package/fjs/types/byte_set/proof.f.mjs +7 -7
  247. package/fjs/types/function/compare/module.f.mjs +10 -3
  248. package/fjs/types/list/module.f.d.mts +1 -1
  249. package/fjs/types/list/module.f.mjs +1 -1
  250. package/fjs/types/nullable/module.f.d.mts +18 -4
  251. package/fjs/types/nullable/module.f.mjs +21 -4
  252. package/fjs/types/nullable/proof.f.d.mts +4 -0
  253. package/fjs/types/nullable/proof.f.mjs +15 -0
  254. package/fjs/types/object/module.f.d.mts +12 -2
  255. package/fjs/types/object/module.f.mjs +11 -1
  256. package/fjs/types/patricia_trie/module.f.mjs +26 -11
  257. package/fjs/types/result/module.f.d.mts +3 -3
  258. package/fjs/types/result/module.f.mjs +3 -3
  259. package/fjs/types/rtti/common/module.f.d.mts +25 -28
  260. package/fjs/types/rtti/common/module.f.mjs +36 -32
  261. package/fjs/types/rtti/common/proof.f.mjs +5 -5
  262. package/fjs/types/rtti/data/module.f.d.mts +14 -0
  263. package/fjs/types/rtti/data/module.f.mjs +25 -2
  264. package/fjs/types/rtti/data/proof.f.d.mts +1 -0
  265. package/fjs/types/rtti/data/proof.f.mjs +25 -2
  266. package/fjs/types/rtti/parse/module.f.d.mts +24 -14
  267. package/fjs/types/rtti/parse/module.f.mjs +37 -28
  268. package/fjs/types/rtti/parse/proof.f.d.mts +3 -2
  269. package/fjs/types/rtti/parse/proof.f.mjs +33 -14
  270. package/fjs/types/rtti/proof.f.mjs +3 -1
  271. package/fjs/types/rtti/ts/module.f.mjs +13 -17
  272. package/fjs/types/rtti/ts/types.d.ts +14 -1
  273. package/fjs/types/sorted_set/module.f.d.mts +18 -0
  274. package/fjs/types/sorted_set/module.f.mjs +22 -0
  275. package/fjs/types/sorted_set/proof.f.d.mts +1 -0
  276. package/fjs/types/sorted_set/proof.f.mjs +16 -1
  277. package/fjs/types/uint8array/module.f.d.mts +1 -1
  278. package/fjs/types/uint8array/module.f.mjs +1 -1
  279. package/fjs/website/module.f.d.mts +3 -3
  280. package/fjs/website/module.f.mjs +4 -7
  281. package/fjs/website/proof.f.mjs +2 -1
  282. package/package.json +2 -2
  283. package/fjs/dev/package_json/module.f.d.mts +0 -39
  284. package/fjs/dev/package_json/module.f.mjs +0 -40
  285. package/fjs/dev/package_json/proof.f.d.mts +0 -6
  286. package/fjs/dev/package_json/proof.f.mjs +0 -32
  287. package/fjs/effects/eff/module.f.d.mts +0 -20
  288. package/fjs/effects/eff/module.f.mjs +0 -70
  289. package/fjs/effects/eff/proof.f.d.mts +0 -15
  290. package/fjs/effects/eff/proof.f.mjs +0 -69
  291. package/fjs/effects/eff/types.d.ts +0 -71
  292. package/fjs/types/rtti/validate/module.f.d.mts +0 -41
  293. package/fjs/types/rtti/validate/module.f.mjs +0 -171
  294. package/fjs/types/rtti/validate/proof.f.d.mts +0 -125
  295. package/fjs/types/rtti/validate/proof.f.mjs +0 -437
  296. package/fjs/types/rtti/validate/types.d.ts +0 -6
@@ -1,11 +1,13 @@
1
1
  /**
2
2
  * @import { Unknown } from '../../../media/json/types.ts'
3
- * @import { Effect } from '../../../effects/types.ts'
4
3
  * @import { State } from '../../../effects/node/virtual/types.ts'
5
- * @import { Id, Response } from '../../json_rpc/types.ts'
4
+ * @import { Id } from '../../json_rpc/types.ts'
6
5
  * @import { Step } from './types.ts'
6
+ * @import { Read, Write } from '../../../effects/node/types.ts'
7
7
  */
8
8
  export declare const proof: {
9
+ readFailurePropagates: () => void;
10
+ readFailureAfterALinePropagates: () => void;
9
11
  eofImmediately: () => void;
10
12
  requestWritesResponse: () => void;
11
13
  requestWithoutTrailingNewline: () => void;
@@ -1,13 +1,14 @@
1
1
  /**
2
2
  * @import { Unknown } from '../../../media/json/types.ts'
3
- * @import { Effect } from '../../../effects/types.ts'
4
3
  * @import { State } from '../../../effects/node/virtual/types.ts'
5
- * @import { Id, Response } from '../../json_rpc/types.ts'
4
+ * @import { Id } from '../../json_rpc/types.ts'
6
5
  * @import { Step } from './types.ts'
6
+ * @import { Read, Write } from '../../../effects/node/types.ts'
7
7
  */
8
8
 
9
- import { assertEq } from '../../../asserts/module.f.mjs'
9
+ import { assert, assertEq } from '../../../asserts/module.f.mjs'
10
10
  import { pure } from '../../../effects/module.f.mjs'
11
+ import { pureOk } from '../../../effects/module.f.mjs'
11
12
  import { emptyState, virtual } from '../../../effects/node/virtual/module.f.mjs'
12
13
  import { stringify } from '../../../media/json/module.f.mjs'
13
14
  import { utf8 } from '../../../text/module.f.mjs'
@@ -16,6 +17,8 @@ import { maxLengthBytes } from '../../../types/bit_vec/module.f.mjs'
16
17
  import { sort } from '../../../types/object/module.f.mjs'
17
18
  import { internalError, jsonrpc, parseError } from '../../json_rpc/module.f.mjs'
18
19
  import { stdioTransport } from './module.f.mjs'
20
+ import { run as mockRun } from '../../../effects/mock/module.f.mjs'
21
+ import { error, ok } from '../../../types/result/module.f.mjs'
19
22
 
20
23
  const stringifyJson = stringify(sort)
21
24
 
@@ -32,7 +35,7 @@ const idOf = value =>
32
35
  /** @type {Step<never>} */
33
36
  const echoStep = value => {
34
37
  const id = idOf(value)
35
- return pure(id === undefined
38
+ return pureOk(id === undefined
36
39
  ? null
37
40
  : { jsonrpc, result: { ok: true }, id })
38
41
  }
@@ -51,15 +54,15 @@ const run = runStep(echoStep)
51
54
 
52
55
  /** @type {(id: Id) => string} */
53
56
  const okResponse = id =>
54
- stringifyJson(/** @type {Unknown} */ ({ jsonrpc, result: { ok: true }, id })) + '\n'
57
+ stringifyJson({ jsonrpc, result: { ok: true }, id }) + '\n'
55
58
 
56
59
  /** @type {string} */
57
60
  const parseErrorLine =
58
- stringifyJson(/** @type {Unknown} */ ({ jsonrpc, error: parseError, id: null })) + '\n'
61
+ stringifyJson({ jsonrpc, error: parseError, id: null }) + '\n'
59
62
 
60
63
  /** @type {(id: Id) => string} */
61
64
  const internalErrorLine = id =>
62
- stringifyJson(/** @type {Unknown} */ ({ jsonrpc, error: internalError, id })) + '\n'
65
+ stringifyJson({ jsonrpc, error: internalError, id }) + '\n'
63
66
 
64
67
  /** @type {(id: number) => string} */
65
68
  const ping = id => `{"jsonrpc":"2.0","method":"ping","id":${id}}`
@@ -71,6 +74,36 @@ const oversizedString = 'a'.repeat(Number(maxLengthBytes) + 1)
71
74
  const notification = '{"jsonrpc":"2.0","method":"notifications/initialized"}'
72
75
 
73
76
  export const proof = {
77
+ // A stdin that cannot be read ends the loop and hands the failure back,
78
+ // where it used to panic. EOF is not this case: that is `ok(null)`, and
79
+ // `eofImmediately` above pins it as the clean shutdown it should be.
80
+ readFailurePropagates: () => {
81
+ const runner = mockRun(/** @type {Parameters<typeof mockRun<Read | Write, undefined>>[0]} */ ({
82
+ read: () => (/** @type {undefined} */ s) => [s, error(/** @type {const} */ (['notImplemented', 'read']))],
83
+ write: () => (/** @type {undefined} */ s) => [s, ok(undefined)],
84
+ }))
85
+ const [, result] = runner(undefined)(stdioTransport(echoStep))
86
+ assert(result[0] === 'error', result)
87
+ },
88
+
89
+ // The same, one turn of the loop later. The proof above only reaches the
90
+ // *first* read, so a tail that swallowed the failure on recursion would
91
+ // still pass it: here stdin yields one complete line, the handler answers
92
+ // it, and the read after that fails.
93
+ readFailureAfterALinePropagates: () => {
94
+ const bytes = toBytes(ping(1) + '\n')
95
+ const runner = mockRun(/** @type {Parameters<typeof mockRun<Read | Write, readonly number[]>>[0]} */ ({
96
+ read: () => (/** @type {readonly number[]} */ s) =>
97
+ s.length === 0
98
+ ? [s, error(/** @type {const} */ (['notImplemented', 'read']))]
99
+ : [s.slice(1), ok(s[0])],
100
+ write: () => (/** @type {readonly number[]} */ s) => [s, ok(undefined)],
101
+ }))
102
+ const [rest, result] = runner(bytes)(stdioTransport(echoStep))
103
+ assertEq(rest.length, 0, 'expected the line to be consumed before the failure')
104
+ assert(result[0] === 'error', result)
105
+ },
106
+
74
107
  // EOF on the very first read: clean shutdown, nothing written, no further reads.
75
108
  eofImmediately: () => {
76
109
  const state = run('')
@@ -120,9 +153,9 @@ export const proof = {
120
153
  /** @type {Step<never>} */
121
154
  const step = value => {
122
155
  const id = idOf(value)
123
- return pure(id === undefined
156
+ return pureOk(id === undefined
124
157
  ? null
125
- : /** @type {Response} */ (/** @type {unknown} */ ({ jsonrpc, result: { ok: true, nextCursor: undefined }, id })))
158
+ : { jsonrpc, result: { ok: true, nextCursor: undefined }, id })
126
159
  }
127
160
  const state = runStep(step)(ping(1) + '\n')
128
161
  assertEq(state.stdout, okResponse(1))
@@ -137,7 +170,7 @@ export const proof = {
137
170
  /** @type {Step<never>} */
138
171
  const step = value => {
139
172
  const id = idOf(value)
140
- return pure(id === undefined
173
+ return pureOk(id === undefined
141
174
  ? null
142
175
  : { jsonrpc, result: { big: oversizedString }, id })
143
176
  }
@@ -151,7 +184,7 @@ export const proof = {
151
184
  /** @type {Step<never>} */
152
185
  const step = value => {
153
186
  const id = idOf(value)
154
- return pure(id === undefined
187
+ return pureOk(id === undefined
155
188
  ? null
156
189
  : id === 1
157
190
  ? { jsonrpc, result: { big: oversizedString }, id }
@@ -171,7 +204,7 @@ export const proof = {
171
204
  /** @type {Step<never>} */
172
205
  const step = value => {
173
206
  const id = idOf(value)
174
- return pure(id === undefined
207
+ return pureOk(id === undefined
175
208
  ? null
176
209
  : { jsonrpc, result: { ok: true }, id: oversizedString })
177
210
  }
@@ -11,4 +11,4 @@ import type { Response } from '../../json_rpc/types.ts';
11
11
  * for a notification that needs no reply. The shape of
12
12
  * `mcpStep(config)(handlers)(key)`.
13
13
  */
14
- export type Step<O extends Operation> = (value: Unknown) => Effect<O, Response | null>;
14
+ export type Step<O extends Operation> = (value: Unknown) => Effect<O, Response | null, never>;
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import type { Ts } from '../../types/rtti/ts/types.ts';
9
9
  import type { Unknown } from '../../media/json/types.ts';
10
- import type { Operation, Effect } from '../../effects/types.ts';
10
+ import type { Effect, Operation } from '../../effects/types.ts';
11
11
  import type { Type } from '../../types/rtti/types.ts';
12
12
  import type { Response } from '../json_rpc/types.ts';
13
13
  import type { implementation, serverCapabilities, initializeParams, initializeResult, textContent, blobResource, embeddedResource, contentItem, tool, toolsListParams, toolsListResult, toolsCallParams, toolsCallResult } from './module.f.mjs';
@@ -26,8 +26,8 @@ export type ToolsCallParams = Ts<typeof toolsCallParams>;
26
26
  export type ToolsCallResult = Ts<typeof toolsCallResult>;
27
27
  /** Per-method handlers for a hello-world MCP tool server. */
28
28
  export type McpHandlers<O extends Operation> = {
29
- readonly toolsList: (params: ToolsListParams) => Effect<O, ToolsListResult>;
30
- readonly toolsCall: (params: ToolsCallParams) => Effect<O, ToolsCallResult>;
29
+ readonly toolsList: (params: ToolsListParams) => Effect<O, ToolsListResult, never>;
30
+ readonly toolsCall: (params: ToolsCallParams) => Effect<O, ToolsCallResult, never>;
31
31
  };
32
32
  /**
33
33
  * A single declarative tool entry combining metadata, input schema, and type-safe handler.
@@ -39,10 +39,21 @@ export type ToolEntry<O extends Operation> = {
39
39
  readonly name: string;
40
40
  readonly description: string;
41
41
  readonly inputRtti: Type;
42
- readonly handle: (args: Unknown) => Effect<O, ToolsCallResult>;
42
+ readonly handle: (args: Unknown) => Effect<O, ToolsCallResult, never>;
43
43
  };
44
- /** Top-level handler: maps a raw JSON value to a JSON-RPC response (or `null` for notifications). */
45
- export type Handle<O extends Operation> = (value: Unknown) => Effect<O, Response | null>;
44
+ /**
45
+ * A JSON-RPC step: given a decoded message, produce the response to write, or
46
+ * `null` for a notification.
47
+ *
48
+ * **`never` is a claim, not an absence.** The handler behind this does perform
49
+ * effects and they can fail — a session-state read is dispatched by a runner
50
+ * that may decline it. It says `never` because it has *absorbed* those: a
51
+ * request's failure becomes `_errResponse(id)(internalError)` and a
52
+ * notification's is dropped, there being no frame to put it in. Spelling that
53
+ * as `Effect<…, never>` puts the decision in the type where a reader can
54
+ * disagree with it, which an opaque payload could not.
55
+ */
56
+ export type Handle<O extends Operation> = (value: Unknown) => Effect<O, Response | null, never>;
46
57
  /** State carried before the peer sends `initialize`. */
47
58
  export type Uninitialized = readonly ['uninitialized'];
48
59
  /** State after `initialize` response was sent but before `notifications/initialized` arrives. */
@@ -7,7 +7,6 @@
7
7
  * @module
8
8
  *
9
9
  * @import { Vec } from '../../types/bit_vec/types.ts'
10
- * @import { Point2D } from '../../crypto/secp/types.ts'
11
10
  * @import { V8 } from '../../crypto/sha2/types.ts'
12
11
  * @import { Id } from './types.ts'
13
12
  */
@@ -7,14 +7,13 @@
7
7
  * @module
8
8
  *
9
9
  * @import { Vec } from '../../types/bit_vec/types.ts'
10
- * @import { Point2D } from '../../crypto/secp/types.ts'
11
10
  * @import { V8 } from '../../crypto/sha2/types.ts'
12
11
  * @import { Id } from './types.ts'
13
12
  */
14
13
 
15
14
  import { toArray } from '../../types/list/module.f.mjs'
16
15
  import { length, msb, uint, uintChunkList, unpack, vec } from '../../types/bit_vec/module.f.mjs'
17
- import { assertEq } from '../../asserts/module.f.mjs'
16
+ import { assertEq, assertNotNullish } from '../../asserts/module.f.mjs'
18
17
  import { utf8 } from '../../text/module.f.mjs'
19
18
  import { secp256r1 } from '../../crypto/secp/module.f.mjs'
20
19
  import { base32 } from '../../crypto/sha2/module.f.mjs'
@@ -33,7 +32,7 @@ const utf8IvSeed = utf8(ivSeed)
33
32
  const c = secp256r1
34
33
 
35
34
  /** @type {bigint} */
36
- const ivUint = /** @type {Point2D} */ (c.mul(uint(utf8IvSeed))(c.g))[0]
35
+ const ivUint = assertNotNullish(c.mul(uint(utf8IvSeed))(c.g))[0]
37
36
 
38
37
  // 64 hex = 256 bits = 32 bytes:
39
38
  assertEq(
@@ -9,6 +9,7 @@
9
9
  * @import { Add, EncodeState } from './types.ts'
10
10
  */
11
11
 
12
+ import { assertNotNullish } from '../../../asserts/module.f.mjs'
12
13
  import { emptyState, patriciaTrie } from '../../../types/patricia_trie/module.f.mjs'
13
14
  import { compress } from '../../id/module.f.mjs'
14
15
  import { asBase } from '../../../types/nominal/module.f.mjs'
@@ -49,7 +50,7 @@ export const encode =
49
50
  return [undefined, push([asBase(symbol), symbol], state)]
50
51
  }
51
52
  const [root1, storage1] = end(state)
52
- const [root2, storage2] = rootCreate(/** @type {Id} */ (root1), symbol, storage1)
53
+ const [root2, storage2] = rootCreate(assertNotNullish(root1), symbol, storage1)
53
54
  return [root2, [storage2, []]]
54
55
  }
55
56
  }
@@ -3,7 +3,7 @@
3
3
  * @import { EncodeState } from './types.ts'
4
4
  */
5
5
 
6
- import { assert, assertEq } from '../../../asserts/module.f.mjs'
6
+ import { assert, assertEq, assertNotNullish } from '../../../asserts/module.f.mjs'
7
7
  import { compress, level3Id } from '../../id/module.f.mjs'
8
8
  import { emptyEncodeState, encode } from './module.f.mjs'
9
9
 
@@ -80,7 +80,7 @@ export const proof = {
80
80
  // Output equals the merged value in the last add call
81
81
  output_is_last_add: () => {
82
82
  const [out, storage] = runWord([s1, s0, s1])
83
- assertEq(out, /** @type {_NodeList[number]} */ (storage.at(-1))[2])
83
+ assertEq(out, assertNotNullish(storage.at(-1))[2])
84
84
  },
85
85
 
86
86
  // Stack is empty after flush; storage is preserved
@@ -32,22 +32,27 @@ export const encode =
32
32
 
33
33
  /** @typedef {readonly [Id | undefined, S, readonly _HashState[]]} _CascadeResult */
34
34
 
35
- /** @type {(id0: Id, storage0: S, stacks0: readonly _HashState[]) => _CascadeResult} */
36
- const cascade = (id0, storage0, stacks0) => {
37
- let id = id0, storage = storage0, stacks = stacks0
38
- for (let index = 0; ; index++) {
39
- if (index >= stacks.length) {
40
- const [, [newStorage, newStack]] = step(id, [storage, []])
41
- return [id, newStorage, [...stacks, newStack]]
42
- }
43
- const [out, [newStorage, newStack]] = step(id, [storage, stacks[index]])
44
- stacks = [...stacks.slice(0, index), newStack, ...stacks.slice(index + 1)]
45
- storage = newStorage
46
- if (out === undefined) return [undefined, storage, stacks]
47
- id = out
35
+ // Recursive rather than a `for(;;)` loop: every exit is one of the two
36
+ // `return`s below, so a bare `for(;;)` picks up a phantom "loop falls
37
+ // through" branch that V8's coverage instrumentation can never mark
38
+ // taken there is no third way out to take it. Recursion has no such
39
+ // branch to begin with.
40
+ /** @type {(id: Id, storage: S, stacks: readonly _HashState[], index: number) => _CascadeResult} */
41
+ const cascadeFrom = (id, storage, stacks, index) => {
42
+ if (index >= stacks.length) {
43
+ const [, [newStorage, newStack]] = step(id, [storage, []])
44
+ return [id, newStorage, [...stacks, newStack]]
48
45
  }
46
+ const [out, [newStorage, newStack]] = step(id, [storage, stacks[index]])
47
+ const newStacks = [...stacks.slice(0, index), newStack, ...stacks.slice(index + 1)]
48
+ return out === undefined
49
+ ? [undefined, newStorage, newStacks]
50
+ : cascadeFrom(out, newStorage, newStacks, index + 1)
49
51
  }
50
52
 
53
+ /** @type {(id0: Id, storage0: S, stacks0: readonly _HashState[]) => _CascadeResult} */
54
+ const cascade = (id0, storage0, stacks0) => cascadeFrom(id0, storage0, stacks0, 0)
55
+
51
56
  /** @type {(bit: bigint, state: EncodeState<S>) => readonly [Id | undefined, EncodeState<S>]} */
52
57
  const literalStep = (bit, state) => {
53
58
  const [ps, storage, stacks] = state
@@ -49,6 +49,14 @@ export declare const decoder: <Unit, S, Cp>(byteOp: StateScan<Unit, S | null, Li
49
49
  * @returns {(state: S | null) => readonly [List<Cp>, S | null]} The end-of-input step.
50
50
  */
51
51
  export declare const eofFlush: <S, Cp>(toError: (state: S) => Cp) => (state: S | null) => readonly [List<Cp>, S | null];
52
+ /**
53
+ * The last code point of the Basic Multilingual Plane. Exported because the
54
+ * UTF-8 encoder needs the boundary itself — its 3-byte form covers the BMP up
55
+ * to here — where the predicates below only answer membership. `maxCodePoint`
56
+ * stays private: `isSupplementaryPlane` already expresses the one range a
57
+ * caller has wanted it for.
58
+ */
59
+ export declare const bmpMax = /** @type {const} */ 65535;
52
60
  /**
53
61
  * Checks whether the 16-bit word (U16) is a high surrogate.
54
62
  * Range: 0xD800 - 0xDBFF.
@@ -76,7 +76,14 @@ export const eofFlush = toError => state =>
76
76
  const surrogateMin = /** @type {const} */ 0xd800
77
77
  const lowSurrogateMin = /** @type {const} */ 0xdc00
78
78
  const surrogateMax = /** @type {const} */ 0xdfff
79
- const bmpMax = /** @type {const} */ 0xffff
79
+ /**
80
+ * The last code point of the Basic Multilingual Plane. Exported because the
81
+ * UTF-8 encoder needs the boundary itself — its 3-byte form covers the BMP up
82
+ * to here — where the predicates below only answer membership. `maxCodePoint`
83
+ * stays private: `isSupplementaryPlane` already expresses the one range a
84
+ * caller has wanted it for.
85
+ */
86
+ export const bmpMax = /** @type {const} */ 0xffff
80
87
  const maxCodePoint = /** @type {const} */ 0x10_ffff
81
88
 
82
89
  /**
@@ -3,6 +3,7 @@ export declare const proof: {
3
3
  isHighSurrogate: (() => void)[];
4
4
  isLowSurrogate: (() => void)[];
5
5
  isBmpCodePoint: (() => void)[];
6
+ bmpMax: (() => void)[];
6
7
  isSupplementaryPlane: (() => void)[];
7
8
  isValidCodePoint: (() => void)[];
8
9
  isTextCodePoint: (() => void)[];
@@ -1,6 +1,7 @@
1
1
  import { assertEq } from '../../asserts/module.f.mjs'
2
2
  import { toArray } from '../../types/list/module.f.mjs'
3
3
  import {
4
+ bmpMax,
4
5
  eofFlush,
5
6
  isBmpCodePoint,
6
7
  isHighSurrogate,
@@ -64,6 +65,16 @@ export const proof = {
64
65
  () => check(isBmpCodePoint(0xd800), false),
65
66
  () => check(isBmpCodePoint(0x10000), false),
66
67
  ],
68
+ bmpMax: [
69
+ // The exported boundary and the predicates derived from it must agree:
70
+ // `bmpMax` is the last BMP code point, and the next one starts the
71
+ // supplementary planes. This is the pairing the UTF-8 encoder relies
72
+ // on to split its 3-byte and 4-byte forms.
73
+ () => check(isBmpCodePoint(bmpMax), true),
74
+ () => check(isSupplementaryPlane(bmpMax), false),
75
+ () => check(isSupplementaryPlane(bmpMax + 1), true),
76
+ () => check(isBmpCodePoint(bmpMax + 1), false),
77
+ ],
67
78
  isSupplementaryPlane: [
68
79
  () => check(isSupplementaryPlane(0x10000), true),
69
80
  () => check(isSupplementaryPlane(0x10ffff), true),
@@ -6,12 +6,10 @@
6
6
  *
7
7
  * @module
8
8
  *
9
- * @import { Write, WriteConsoles, NodeProgramOptions } from '../../effects/node/types.ts'
10
- * @import { Effect } from '../../effects/types.ts'
9
+ * @import { Console, Write, WriteConsoles, NodeProgramOptions } from '../../effects/node/types.ts'
11
10
  * @import { Stdout, WriteText, CsiConsole } from './types.ts'
12
11
  */
13
- import type { Write, WriteConsoles, NodeProgramOptions } from '../../effects/node/types.ts';
14
- import type { Effect } from '../../effects/types.ts';
12
+ import type { Console, WriteConsoles, NodeProgramOptions } from '../../effects/node/types.ts';
15
13
  import type { Stdout, WriteText } from './types.ts';
16
14
  /** @type {string} */
17
15
  export declare const backspace: string;
@@ -56,6 +54,6 @@ export declare const createConsoleText: (stdout: Stdout) => WriteText;
56
54
  * stream is not a TTY, then encodes to UTF-8 and emits a `Write` effect.
57
55
  * Does NOT append `\n` — callers are responsible for line termination.
58
56
  *
59
- * @type {(options: NodeProgramOptions) => (stream: WriteConsoles) => (s: string) => Effect<Write, void>}
57
+ * @type {(options: NodeProgramOptions) => (stream: WriteConsoles) => Console}
60
58
  */
61
- export declare const csiWrite: (options: NodeProgramOptions) => (stream: WriteConsoles) => (s: string) => Effect<Write, void>;
59
+ export declare const csiWrite: (options: NodeProgramOptions) => (stream: WriteConsoles) => Console;
@@ -6,8 +6,7 @@
6
6
  *
7
7
  * @module
8
8
  *
9
- * @import { Write, WriteConsoles, NodeProgramOptions } from '../../effects/node/types.ts'
10
- * @import { Effect } from '../../effects/types.ts'
9
+ * @import { Console, Write, WriteConsoles, NodeProgramOptions } from '../../effects/node/types.ts'
11
10
  * @import { Stdout, WriteText, CsiConsole } from './types.ts'
12
11
  */
13
12
 
@@ -49,13 +48,13 @@ export const csi = end => code =>
49
48
  export const sgr = csi('m')
50
49
 
51
50
  /** Resets all SGR styles to terminal defaults. */
52
- export const reset = /** @type {string} */ (sgr(0))
51
+ export const reset = sgr(0)
53
52
  /** Enables bold/intense text rendering when supported by the terminal. */
54
- export const bold = /** @type {string} */ (sgr(1))
53
+ export const bold = sgr(1)
55
54
  /** Applies red foreground color to subsequent text. */
56
- export const fgRed = /** @type {string} */ (sgr(31))
55
+ export const fgRed = sgr(31)
57
56
  /** Applies green foreground color to subsequent text. */
58
- export const fgGreen = /** @type {string} */ (sgr(32))
57
+ export const fgGreen = sgr(32)
59
58
 
60
59
  const { max } = Math
61
60
 
@@ -92,7 +91,7 @@ const str = isTTY => s =>
92
91
  * stream is not a TTY, then encodes to UTF-8 and emits a `Write` effect.
93
92
  * Does NOT append `\n` — callers are responsible for line termination.
94
93
  *
95
- * @type {(options: NodeProgramOptions) => (stream: WriteConsoles) => (s: string) => Effect<Write, void>}
94
+ * @type {(options: NodeProgramOptions) => (stream: WriteConsoles) => Console}
96
95
  */
97
96
  export const csiWrite = ({ std }) => stream => {
98
97
  const toStr = str(std[stream].isTTY)
@@ -160,7 +160,9 @@ const u16 = i => Number.isInteger(i) && isInU16Range(i)
160
160
  * This can be either `null` (no state) or the previous high surrogate value.
161
161
  * @param word - The current UTF-16 word (U16) to process.
162
162
  * @returns A tuple where the first element is a list of decoded Unicode code points (`CodePoint`), and
163
- * the second element is the updated state. If the word is invalid, an error code `0xffffffff` is returned.
163
+ * the second element is the updated state. A word outside the `U16`
164
+ * domain is reported as one bare `errorMask` unit, the same shape the
165
+ * UTF-8 decoder's out-of-range guard emits.
164
166
  *
165
167
  * @example
166
168
  *
@@ -182,7 +184,10 @@ const u16 = i => Number.isInteger(i) && isInU16Range(i)
182
184
  */
183
185
  const utf16ByteToCodePointOp = (word, state) => {
184
186
  if (!u16(word)) {
185
- return [[0xffffffff], state]
187
+ // Out of domain, so there is no payload to tag: emit the bare mask,
188
+ // matching `utf8ByteToCodePointOp`'s guard. Every other error path
189
+ // below tags a real code unit with `| errorMask`.
190
+ return [[errorMask], state]
186
191
  }
187
192
  if (state === null) {
188
193
  if (isBmpCodePoint(word)) { return [[word], null] }
@@ -24,7 +24,7 @@ export const proof = {
24
24
  toCodePointList: [
25
25
  () => {
26
26
  const result = stringify(toArray(toCodePointList([-1, 65536])))
27
- assertEq(result, '[4294967295,4294967295]')
27
+ assertEq(result, '[2147483648,2147483648]')
28
28
  },
29
29
  () => {
30
30
  const result = stringify(toArray(toCodePointList([0, 36, 8364, 55295, 57344, 65535])))
@@ -60,14 +60,14 @@ export const proof = {
60
60
  // partition the integers in that range.
61
61
  () => {
62
62
  const result = stringify(toArray(toCodePointList([56319.5])))
63
- assertEq(result, '[4294967295]')
63
+ assertEq(result, '[2147483648]')
64
64
  },
65
65
  // A non-integer word doesn't disturb a pending high surrogate: it is
66
66
  // reported invalid on its own, and the surrogate is still flagged
67
67
  // unpaired at EOF.
68
68
  () => {
69
69
  const result = stringify(toArray(toCodePointList([55296, 56319.5])))
70
- assertEq(result, '[4294967295,-2147428352]')
70
+ assertEq(result, '[2147483648,-2147428352]')
71
71
  }
72
72
  ],
73
73
  fromCodePointList: [
@@ -11,9 +11,11 @@
11
11
 
12
12
  import { flatMap, toArray } from '../../types/list/module.f.mjs'
13
13
  import {
14
+ bmpMax,
14
15
  decoder,
15
16
  eofFlush,
16
17
  errorMask,
18
+ isSupplementaryPlane,
17
19
  isValidCodePoint,
18
20
  } from '../code_point/module.f.mjs'
19
21
  import { msb, u8List, length } from '../../types/bit_vec/module.f.mjs'
@@ -94,14 +96,14 @@ const codePointToUtf8 = input => {
94
96
  if (input >= 0x0080 && input <= 0x07ff) {
95
97
  return [input >> 6 | lead2Tag, contByte(input)]
96
98
  }
97
- if (input >= 0x0800 && input <= 0xffff) {
99
+ if (input >= 0x0800 && input <= bmpMax) {
98
100
  return [
99
101
  input >> 12 | lead3Tag,
100
102
  contByte(input >> 6),
101
103
  contByte(input),
102
104
  ]
103
105
  }
104
- if (input >= 0x10000 && input <= 0x10ffff) {
106
+ if (isSupplementaryPlane(input)) {
105
107
  return [
106
108
  input >> 18 | lead4Tag,
107
109
  contByte(input >> 12),
@@ -53,10 +53,22 @@ export const first = at(0)
53
53
  */
54
54
  export const last = a => at(a.length - 1)(a)
55
55
 
56
+ /**
57
+ * Applies `f` to a non-empty array, answering `null` for an empty one — the
58
+ * shared shape of the whole-array accessors below.
59
+ *
60
+ * The guard is `a.length === 0` and not `first(a) === null`: `first` goes
61
+ * through `fromUndefined`, so it reads a *stored* `null` or `undefined`
62
+ * element as absence. `[null]` is not empty, but `first` says it is.
63
+ *
64
+ * @type {<T, R>(f: (a: readonly T[]) => R) => (a: readonly T[]) => R | null}
65
+ */
66
+ const onNonEmpty = f => a => a.length === 0 ? null : f(a)
67
+
56
68
  /**
57
69
  * @type {<T>(a: readonly T[]) => readonly T[] | null}
58
70
  */
59
- export const tail = a => a.length === 0 ? null : uncheckTail(a)
71
+ export const tail = onNonEmpty(uncheckTail)
60
72
 
61
73
  /**
62
74
  * @type {<T>(a: readonly T[]) => readonly [T, readonly T[]] | null}
@@ -69,7 +81,7 @@ export const splitFirst = a => {
69
81
  }
70
82
 
71
83
  /** @type {<T>(a: readonly T[]) => readonly T[] | null} */
72
- export const head = a => a.length === 0 ? null : uncheckHead(a)
84
+ export const head = onNonEmpty(uncheckHead)
73
85
 
74
86
  /** @type {<T>(a: readonly T[]) => readonly [readonly T[], T] | null} */
75
87
  export const splitLast = a => {
@@ -120,8 +120,6 @@ export declare const pack: ({ length, uint }: Unpacked) => Vec;
120
120
  /** @type {({ uint }: Unpacked) => bigint} */
121
121
  export declare const unpackedUint: ({ uint }: Unpacked) => bigint;
122
122
  export type _Base = {
123
- readonly front: (len: bigint) => (v: Vec) => bigint;
124
- readonly removeFront: (len: bigint) => (v: Vec) => Vec;
125
123
  readonly norm: _NormOp;
126
124
  readonly uintCmp: (a: bigint) => (b: bigint) => Sign;
127
125
  readonly unpackSplit: (len: bigint) => (u: Unpacked) => readonly [bigint, bigint];