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
@@ -42,18 +42,29 @@
42
42
  *
43
43
  * @module
44
44
  *
45
- * @import { Effect, Operation } from '../../effects/types.ts'
45
+ * @import { Operation } from '../../effects/types.ts'
46
+ * @import { Effect, NotImplemented } from '../../effects/types.ts'
47
+ * @import { EvoChannel, EvoError } from './types.ts'
46
48
  * @import { Key, MemOp } from '../../effects/memory/types.ts'
47
49
  * @import { Cas } from '../types.ts'
48
- * @import { Ok, Result } from '../../types/result/types.ts'
50
+ * @import { Result } from '../../types/result/types.ts'
49
51
  * @import { Vec } from '../../types/bit_vec/types.ts'
50
- * @import { IoResult } from '../../effects/node/types.ts'
52
+ * @import { Ok } from '../../types/result/types.ts'
51
53
  * @import { List } from '../../effects/list/types.ts'
52
- * @import { LockMap, Revision } from '../../media/revision/types.ts'
54
+ * @import { IoChannel, IoResult } from '../../effects/node/types.ts'
55
+ * @import { LockField, LockMap, Revision } from '../../media/revision/types.ts'
53
56
  * @import { Hash, Subject, RevisionData, SubjectState, Cache, Evo } from './types.ts'
54
57
  */
55
58
 
56
- import { pure, foldStep, mapStep, step } from '../../effects/module.f.mjs'
59
+ import {
60
+ catchStep,
61
+ foldStep as ioFoldStep,
62
+ mapStep as ioMapStep,
63
+ pureError,
64
+ pureOk,
65
+ resultMapStep,
66
+ step as ioStep,
67
+ } from '../../effects/module.f.mjs'
57
68
  import { create, read, write } from '../../effects/memory/module.f.mjs'
58
69
  import { collectRead } from '../module.f.mjs'
59
70
  import { cBase32ToVec, vecToCBase32 } from '../../basen/cbase32/module.f.mjs'
@@ -63,11 +74,33 @@ import { ok, error, okThen } from '../../types/result/module.f.mjs'
63
74
  import { nonEmpty, empty as elEmpty } from '../../effects/list/module.f.mjs'
64
75
  import { at, definedEntries } from '../../types/object/module.f.mjs'
65
76
  import { unwrap } from '../../types/nullable/module.f.mjs'
66
- import { isNotFound } from '../../effects/node/module.f.mjs'
77
+ import { errorSummary, isNotFound } from '../../effects/node/module.f.mjs'
67
78
  import { decodeText, encodeText, dialect, checkReferences, isHash } from '../../media/revision/module.f.mjs'
68
79
 
80
+ /**
81
+ * A rejected revision, tagged so it renders alongside `notImplemented` and
82
+ * `ioError` rather than needing a `typeof` test to be told from them.
83
+ *
84
+ * @type {(message: string) => EvoError}
85
+ */
86
+ export const evoError = message => ['evoError', message]
87
+
88
+ /**
89
+ * Renders an {@link EvoChannel} failure as a message.
90
+ *
91
+ * The two cases are told apart by tag and nothing else — which is the whole
92
+ * reason {@link EvoError} is a tuple. A rejected revision already carries a
93
+ * message written for a caller; a runner that could not dispatch is described
94
+ * by `errorSummary`, the same renderer the node channel uses, so there is one
95
+ * phrasing of "operation not implemented" rather than two.
96
+ *
97
+ * @type {(e: EvoChannel) => string}
98
+ */
99
+ export const evoSummary = e => e[0] === 'evoError' ? e[1] : errorSummary(e)
100
+
69
101
  /** A cache with no known subjects yet — the starting point for {@link buildCache}. */
70
- export const emptyCache = /** @type {Cache} */ ({ bySubject: {} })
102
+ /** @type {Cache} */
103
+ export const emptyCache = { bySubject: {} }
71
104
 
72
105
  /** @type {SubjectState} */
73
106
  const emptySubjectState = { hashes: [], parents: [], archived: [] }
@@ -93,11 +126,26 @@ const union = set => items =>
93
126
  */
94
127
  const canonicalHash = h => vecToCBase32(unwrap(cBase32ToVec(h)))
95
128
 
96
- /** Canonicalizes every direct hash in a structurally validated flat lock map.
129
+ /**
130
+ * Canonicalizes every direct hash of a structurally validated lock map, at
131
+ * every depth, preserving its nested scope structure. Nested maps are scopes
132
+ * rather than references, so only the strings are re-spelled — the same split
133
+ * `fjs/media/revision`'s `checkReferences` validates along.
97
134
  * @type {(lock: LockMap) => LockMap}
98
135
  */
99
136
  const canonicalLock = lock =>
100
- Object.fromEntries(definedEntries(lock).map(([subject, hash]) => [subject, canonicalHash(hash)]))
137
+ Object.fromEntries(definedEntries(lock).map(
138
+ ([subject, value]) => [subject, typeof value === 'string' ? canonicalHash(value) : canonicalLock(value)]))
139
+
140
+ /**
141
+ * Canonicalizes a revision's `lock` field: a shared-lock reference is one hash
142
+ * to re-spell, an inline map is walked to the bottom ({@link canonicalLock}).
143
+ * The split is the same one `fjs/media/revision`'s `lockFieldError` validates
144
+ * along, so what this re-spells is exactly what was checked.
145
+ * @type {(value: LockField) => LockField}
146
+ */
147
+ const canonicalLockField = value =>
148
+ typeof value === 'string' ? canonicalHash(value) : canonicalLock(value)
101
149
 
102
150
  /** A subject's current heads: revision hashes seen that no other revision of the same subject names as a parent.
103
151
  * @type {(state: SubjectState) => readonly Hash[]}
@@ -181,46 +229,62 @@ export const decodeRevisionVec = value => {
181
229
  *
182
230
  * @template {Operation} O
183
231
  * @param {Cas<O>} cas
184
- * @returns {(hash: Vec) => Effect<O, Revision | null>}
232
+ * The `never` is a decision, not an observation: reading the store *can* fail,
233
+ * and this maps that failure to `null` alongside "the bytes are not a
234
+ * revision". A scan wants exactly that — one unreadable blob must not fail the
235
+ * whole cache build — but the two are genuinely different answers, and this
236
+ * one loses the difference on purpose. Saying `never` puts that where a reader
237
+ * can disagree with it.
238
+ *
239
+ * @returns {(hash: Vec) => Effect<O, Revision | null, never>}
185
240
  */
186
241
  export const decodeRevisionBlob = cas => hash =>
187
- mapStep(
242
+ resultMapStep(
188
243
  collectRead(cas.read(hash)),
189
- ([tag, value]) => tag === 'error' ? null : decodeRevisionVec(value))
244
+ ([tag, value]) => ok(tag === 'error' ? null : decodeRevisionVec(value)))
190
245
 
191
246
  /**
192
247
  * Scans every hash in `cas` and builds a fresh {@link Cache} from the
193
248
  * `vnd.fjs.revision` blobs found among them. Non-revision blobs are ignored.
194
249
  *
250
+ * A store that cannot be listed is a failure of the scan, not an empty cache:
251
+ * the fold never starts, and the caller is told. Blobs that fail to *read*
252
+ * remain "not a revision" and are skipped — see {@link decodeRevisionBlob}.
253
+ *
195
254
  * @template {Operation} O
196
255
  * @param {Cas<O>} cas
197
- * @returns {Effect<O, Cache>}
256
+ * @returns {Effect<O, Cache, IoChannel>}
198
257
  */
199
- export const buildCache = cas =>
200
- foldStep(
201
- cas.list(),
202
- emptyCache,
203
- hash => cache =>
204
- mapStep(
205
- decodeRevisionBlob(cas)(hash),
206
- revision =>
207
- revision === null ? cache : addRevisionToCache(vecToCBase32(hash), revision)(cache)))
258
+ export const buildCache = cas => {
259
+ // Annotated rather than inferred: the body's `ok(…)` is an `Ok<Cache>`,
260
+ // which unifies with `Result<S, E>` for any `E`, so the fold's error type
261
+ // has nothing to pin it and drifts into the accumulator's.
262
+ /** @type {(hash: Vec) => (cache: Cache) => Effect<O, Cache, IoChannel>} */
263
+ const foldOne = hash => cache =>
264
+ ioMapStep(
265
+ decodeRevisionBlob(cas)(hash),
266
+ revision =>
267
+ revision === null ? cache : addRevisionToCache(vecToCBase32(hash), revision)(cache))
268
+ return ioStep(cas.list(), hashes => ioFoldStep(pureOk(hashes), emptyCache, foldOne))
269
+ }
208
270
 
209
271
  /**
210
272
  * Scans `cas` once and allocates a memory slot holding the resulting {@link Cache}.
211
273
  *
212
274
  * @template {Operation} O
213
275
  * @param {Cas<O>} cas
214
- * @returns {Effect<O | MemOp, Key<Cache>>}
276
+ * @returns {Effect<O | MemOp, Key<Cache>, IoChannel>}
215
277
  */
216
278
  export const initEvo = cas =>
217
- step(buildCache(cas), cache => create(cache))
279
+ ioStep(buildCache(cas), cache => create(cache))
218
280
 
219
281
  /** Reads, then rewrites, the cache at `cacheKey` with `revision` folded in at `hash`.
220
- * @type {(cacheKey: Key<Cache>) => (hash: Hash) => (revision: Revision) => Effect<MemOp, void>}
282
+ * @type {(cacheKey: Key<Cache>) => (hash: Hash) => (revision: Revision) => Effect<MemOp, void, NotImplemented>}
221
283
  */
222
284
  const foldIntoCache = cacheKey => hash => revision =>
223
- step(read(cacheKey), cache => write(cacheKey, addRevisionToCache(hash, revision)(cache)))
285
+ ioStep(
286
+ read(cacheKey),
287
+ cache => write(cacheKey, addRevisionToCache(hash, revision)(cache)))
224
288
 
225
289
  /**
226
290
  * Folds `value` — bytes already written to a `Cas` at `hash` by some other
@@ -230,11 +294,11 @@ const foldIntoCache = cacheKey => hash => revision =>
230
294
  * call can store a revision blob without going through {@link addRevision},
231
295
  * and this is what keeps the cache honest about it without rescanning the
232
296
  * whole store.
233
- * @type {(cacheKey: Key<Cache>) => (hash: Vec) => (value: Vec) => Effect<MemOp, void>}
297
+ * @type {(cacheKey: Key<Cache>) => (hash: Vec) => (value: Vec) => Effect<MemOp, void, NotImplemented>}
234
298
  */
235
299
  export const syncRevision = cacheKey => hash => value => {
236
300
  const revision = decodeRevisionVec(value)
237
- return revision === null ? pure(undefined) : foldIntoCache(cacheKey)(vecToCBase32(hash))(revision)
301
+ return revision === null ? pureOk(undefined) : foldIntoCache(cacheKey)(vecToCBase32(hash))(revision)
238
302
  }
239
303
 
240
304
  /**
@@ -246,39 +310,39 @@ export const syncRevision = cacheKey => hash => value => {
246
310
  *
247
311
  * @template {Operation} O
248
312
  * @param {Cas<O>} cas
249
- * @returns {(parentRef: Hash) => Effect<O, Result<Revision, string>>}
313
+ * @returns {(parentRef: Hash) => Effect<O, Revision, EvoError>}
250
314
  */
251
315
  const resolveParent = cas => parentRef => {
252
316
  const parentHash = cBase32ToVec(parentRef)
253
317
  if (parentHash === null) {
254
- return pure(error(`invalid parent hash: ${parentRef}`))
318
+ return pureError(evoError(`invalid parent hash: ${parentRef}`))
255
319
  }
256
- return mapStep(
320
+ return ioStep(
257
321
  decodeRevisionBlob(cas)(parentHash),
258
- parent => parent === null ? error(`parent is not a revision blob: ${parentRef}`) : ok(parent))
322
+ parent => parent === null
323
+ ? pureError(evoError(`parent is not a revision blob: ${parentRef}`))
324
+ : pureOk(parent))
259
325
  }
260
326
 
261
327
  /**
262
328
  * Resolves and validates every entry of `parents`, in order, short-circuiting on the first failure.
263
329
  *
330
+ * Short-circuiting is `foldStep`'s, not this function's. It used to be
331
+ * two hand-written `[0] === 'error'` tests, which is what a verdict costs when
332
+ * it rides in the value instead of the channel.
333
+ *
264
334
  * @template {Operation} O
265
335
  * @param {Cas<O>} cas
266
- * @returns {(parents: readonly Hash[]) => Effect<O, Result<readonly Revision[], string>>}
336
+ * @returns {(parents: readonly Hash[]) => Effect<O, readonly Revision[], EvoError>}
267
337
  */
268
338
  const resolveParents = cas => parents => {
269
- /** @type {Result<readonly Revision[], string>} */
270
- const init = ok([])
271
- return foldStep(
272
- pure(parents),
339
+ /** @type {readonly Revision[]} */
340
+ const init = []
341
+ return ioFoldStep(
342
+ pureOk(parents),
273
343
  init,
274
- parentRef => (/** @type {Result<readonly Revision[], string>} */ acc) => {
275
- if (acc[0] === 'error') { return pure(acc) }
276
- return mapStep(
277
- resolveParent(cas)(parentRef),
278
- (/** @type {Result<Revision, string>} */ parentResult) =>
279
- /** @type {Result<readonly Revision[], string>} */
280
- (parentResult[0] === 'error' ? parentResult : ok([...acc[1], parentResult[1]])))
281
- })
344
+ parentRef => (/** @type {readonly Revision[]} */ acc) =>
345
+ ioMapStep(resolveParent(cas)(parentRef), parent => [...acc, parent]))
282
346
  }
283
347
 
284
348
  /**
@@ -410,7 +474,7 @@ const buildRevision = input => parents => {
410
474
  ...revision,
411
475
  parents: revision.parents.map(canonicalHash),
412
476
  snapshot: canonicalHash(revision.snapshot),
413
- lock: revision.lock === undefined ? undefined : canonicalLock(revision.lock),
477
+ lock: revision.lock === undefined ? undefined : canonicalLockField(revision.lock),
414
478
  })
415
479
  }
416
480
 
@@ -432,27 +496,41 @@ const buildRevision = input => parents => {
432
496
  *
433
497
  * @template {Operation} O
434
498
  * @param {Cas<O>} cas
435
- * @returns {(cacheKey: Key<Cache>) => (input: RevisionData) => Effect<O | MemOp, Result<Hash, string>>}
499
+ * A rejected revision and an unreachable cache slot share one channel — see
500
+ * {@link Evo.add} — so every branch below answers `pureError`, and the
501
+ * successful path never re-tests what an earlier step already decided.
502
+ *
503
+ * The `Cas` write is the one place a host failure is *translated* rather than
504
+ * propagated: {@link catchStep} turns any `IoChannel` error into one
505
+ * {@link EvoError}, because a caller of this API has the same recourse to a
506
+ * full disk as to a malformed parent, and the store's own error vocabulary is
507
+ * not part of this contract.
508
+ *
509
+ * @returns {(cacheKey: Key<Cache>) => (input: RevisionData) => Effect<O | MemOp, Hash, EvoChannel>}
436
510
  */
437
511
  export const addRevision = cas => cacheKey => input =>
438
- step(
512
+ ioStep(
439
513
  resolveParents(cas)(input.parents),
440
- (/** @type {Result<readonly Revision[], string>} */ parentsResult) => {
441
- const revisionResult = okThen(buildRevision(input))(parentsResult)
442
- if (revisionResult[0] === 'error') { return pure(revisionResult) }
514
+ (/** @type {readonly Revision[]} */ parents) => {
515
+ const revisionResult = buildRevision(input)(parents)
516
+ if (revisionResult[0] === 'error') { return pureError(evoError(revisionResult[1])) }
443
517
  const canonicalRevision = revisionResult[1]
444
518
  const bytes = tryUtf8(encodeText(canonicalRevision))
445
519
  if (bytes === null) {
446
- return pure(error('revision too large to encode'))
520
+ return pureError(evoError('revision too large to encode'))
447
521
  }
448
- return step(
449
- cas.write(nonEmpty(ok(bytes), /** @type {List<never, Ok<Vec>>} */ (elEmpty()))),
450
- (/** @type {IoResult<Vec>} */ writeResult) => {
451
- if (writeResult[0] === 'error') {
452
- return /** @type {Effect<MemOp, Result<Hash, string>>} */ (pure(error('failed to write revision to CAS')))
453
- }
454
- const hash = vecToCBase32(writeResult[1])
455
- return mapStep(foldIntoCache(cacheKey)(hash)(canonicalRevision), () => ok(hash))
522
+ // Annotated so the payload's operation set infers as `never`: the
523
+ // list is built from `pure` cells and requests no commands of its
524
+ // own, which `cas.write`'s `O1` has nothing else to pin it to.
525
+ /** @type {Effect<O, Vec, EvoError>} */
526
+ const written = catchStep(
527
+ cas.write((nonEmpty(bytes, elEmpty()))),
528
+ () => pureError(evoError('failed to write revision to CAS')))
529
+ return ioStep(
530
+ written,
531
+ (/** @type {Vec} */ writtenHash) => {
532
+ const hash = vecToCBase32(writtenHash)
533
+ return ioMapStep(foldIntoCache(cacheKey)(hash)(canonicalRevision), () => hash)
456
534
  })
457
535
  })
458
536
 
@@ -474,7 +552,7 @@ const toRevisionData = ({ subject, parents, snapshot, generation, archived, lock
474
552
  snapshot: canonicalHash(snapshot),
475
553
  generation,
476
554
  archived,
477
- lock: lock === undefined ? undefined : canonicalLock(lock),
555
+ lock: lock === undefined ? undefined : canonicalLockField(lock),
478
556
  })
479
557
 
480
558
  /**
@@ -501,17 +579,17 @@ const toRevisionData = ({ subject, parents, snapshot, generation, archived, lock
501
579
  * how far it got; recovering that difference would mean folding the chunk
502
580
  * stream here instead of reusing `collectRead`, for a distinction no client
503
581
  * can act on differently.
504
- * @type {(hash: Hash) => (result: IoResult<Vec>) => Result<RevisionData, string>}
582
+ * @type {(hash: Hash) => (result: IoResult<Vec>) => Result<RevisionData, EvoError>}
505
583
  */
506
584
  const decodeReadRevision = hash => ([tag, value]) => {
507
585
  if (tag === 'error') {
508
- return error(isNotFound(value)
586
+ return error(evoError(isNotFound(value)
509
587
  ? `revision not found: ${hash}`
510
- : `failed to read revision: ${hash}`)
588
+ : `failed to read revision: ${hash}`))
511
589
  }
512
590
  const revision = decodeRevisionVec(value)
513
591
  return revision === null
514
- ? error(`not a revision blob: ${hash}`)
592
+ ? error(evoError(`not a revision blob: ${hash}`))
515
593
  : ok(toRevisionData(revision))
516
594
  }
517
595
 
@@ -530,13 +608,13 @@ const decodeReadRevision = hash => ([tag, value]) => {
530
608
  *
531
609
  * @template {Operation} O
532
610
  * @param {Cas<O>} cas
533
- * @returns {(hash: Hash) => Effect<O, Result<RevisionData, string>>}
611
+ * @returns {(hash: Hash) => Effect<O, RevisionData, EvoError>}
534
612
  */
535
613
  export const readRevision = cas => hash => {
536
614
  const hashVec = cBase32ToVec(hash)
537
615
  return hashVec === null
538
- ? pure(error(`invalid hash: ${hash}`))
539
- : mapStep(collectRead(cas.read(hashVec)), decodeReadRevision(hash))
616
+ ? pureError(evoError(`invalid hash: ${hash}`))
617
+ : resultMapStep(collectRead(cas.read(hashVec)), decodeReadRevision(hash))
540
618
  }
541
619
 
542
620
  /**
@@ -549,12 +627,12 @@ export const readRevision = cas => hash => {
549
627
  export const evo = cas => cacheKey => ({
550
628
  list: archived => {
551
629
  const listed = subjectListed(archived)
552
- return mapStep(
630
+ return ioMapStep(
553
631
  read(cacheKey),
554
632
  cache => definedEntries(cache.bySubject)
555
633
  .flatMap(([subject, state]) => listed(state) ? [subject] : []))
556
634
  },
557
- head: subject => mapStep(read(cacheKey), cache => {
635
+ head: subject => ioMapStep(read(cacheKey), cache => {
558
636
  const state = at(subject)(cache.bySubject)
559
637
  return state === null ? [] : headsOf(state)
560
638
  }),
@@ -1,8 +1,12 @@
1
1
  /**
2
2
  * @import { Cas } from '../types.ts'
3
+ * @import { EvoChannel } from './types.ts'
4
+ * @import { Result } from '../../types/result/types.ts'
5
+ * @import { Effect } from '../../effects/types.ts'
6
+ * @import { IoChannel, NodeOp } from '../../effects/node/types.ts'
7
+ * @import { State } from '../../effects/node/virtual/types.ts'
3
8
  * @import { Vec } from '../../types/bit_vec/types.ts'
4
9
  * @import { Ok } from '../../types/result/types.ts'
5
- * @import { IoResult } from '../../effects/node/types.ts'
6
10
  * @import { List } from '../../effects/list/types.ts'
7
11
  * @import { RevisionData } from './types.ts'
8
12
  */
@@ -44,9 +48,14 @@ export declare const proof: {
44
48
  revisionCanonicalizesReferenceSpellings: () => void;
45
49
  revisionRoundTripsThroughAdd: () => void;
46
50
  revisionLockRoundTripsAndCanonicalizes: () => void;
51
+ revisionSharedLockReferenceRoundTripsAndCanonicalizes: () => void;
52
+ revisionInvalidSharedLockReferenceIsRejected: () => void;
53
+ revisionNestedLockRoundTripsAndCanonicalizes: () => void;
54
+ revisionInvalidNestedLockValueIsRejected: () => void;
47
55
  revisionAbsentAndEmptyLocksRemainDistinct: () => void;
48
56
  revisionInvalidLockValueIsRejected: () => void;
49
57
  equivalentLockOrdersReuseOneCasAddress: () => void;
58
+ equivalentNestedLockOrdersReuseOneCasAddress: () => void;
50
59
  syncRevisionFoldsValidRevisionIntoCache: () => void;
51
60
  syncRevisionIgnoresNonRevisionContent: () => void;
52
61
  evoHeadUnknownSubjectIsEmpty: () => void;