nervur 0.22.0 → 0.22.2-3

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 (398) hide show
  1. package/AUTHORING.md +741 -0
  2. package/KIT-SPEC.md +286 -0
  3. package/LICENSE +1 -1
  4. package/NOTICE +6 -2
  5. package/README.md +97 -424
  6. package/dist/app/app-ground.d.ts +18 -0
  7. package/dist/app/app-ground.js +25 -0
  8. package/dist/app/index.d.ts +2 -0
  9. package/dist/app/index.js +5 -0
  10. package/dist/app/native.d.ts +46 -0
  11. package/dist/app/native.js +101 -0
  12. package/dist/being/being.d.ts +229 -0
  13. package/dist/being/being.js +20 -0
  14. package/dist/being/covers.d.ts +9 -0
  15. package/dist/being/covers.js +21 -0
  16. package/dist/being/index.d.ts +3 -0
  17. package/dist/being/index.js +5 -0
  18. package/dist/being/need.d.ts +49 -0
  19. package/dist/being/need.js +33 -0
  20. package/dist/being/schema.d.ts +100 -0
  21. package/dist/being/schema.js +132 -0
  22. package/dist/being/table.d.ts +42 -0
  23. package/dist/being/table.js +288 -0
  24. package/dist/bench/bench-ground.d.ts +55 -0
  25. package/dist/bench/bench-ground.js +101 -0
  26. package/dist/bench/bench.d.ts +87 -0
  27. package/dist/bench/bench.js +260 -0
  28. package/dist/bench/fake-carry.d.ts +32 -0
  29. package/dist/bench/fake-carry.js +56 -0
  30. package/dist/bench/fake-clock.d.ts +17 -0
  31. package/dist/bench/fake-clock.js +34 -0
  32. package/dist/bench/fake-custody.d.ts +9 -0
  33. package/dist/bench/fake-custody.js +10 -0
  34. package/dist/bench/fake-faculty.d.ts +25 -0
  35. package/dist/bench/fake-faculty.js +48 -0
  36. package/dist/bench/fake-keys.d.ts +5 -0
  37. package/dist/bench/fake-keys.js +9 -0
  38. package/dist/bench/fake-memory.d.ts +14 -0
  39. package/dist/bench/fake-memory.js +46 -0
  40. package/dist/bench/fake-network.d.ts +57 -0
  41. package/dist/bench/fake-network.js +169 -0
  42. package/dist/bench/index.d.ts +11 -0
  43. package/dist/bench/index.js +13 -0
  44. package/dist/bench/seeded.d.ts +11 -0
  45. package/dist/bench/seeded.js +37 -0
  46. package/dist/bench/settle.d.ts +2 -0
  47. package/dist/bench/settle.js +49 -0
  48. package/dist/bench/stewards.d.ts +17 -0
  49. package/dist/bench/stewards.js +20 -0
  50. package/dist/bodies/class-list.d.ts +14 -0
  51. package/dist/bodies/class-list.js +33 -0
  52. package/dist/bodies/joined-carry.d.ts +23 -0
  53. package/dist/bodies/joined-carry.js +42 -0
  54. package/dist/bodies/noble-crypto.d.ts +22 -0
  55. package/dist/bodies/noble-crypto.js +88 -0
  56. package/dist/bodies/seed-keys.d.ts +10 -0
  57. package/dist/bodies/seed-keys.js +42 -0
  58. package/dist/bodies/strict-tools.d.ts +10 -0
  59. package/dist/bodies/strict-tools.js +306 -0
  60. package/dist/bodies/web-carry.d.ts +65 -0
  61. package/dist/bodies/web-carry.js +224 -0
  62. package/dist/bodies/web-clock.d.ts +12 -0
  63. package/dist/bodies/web-clock.js +33 -0
  64. package/dist/browser/browser-ground.d.ts +69 -0
  65. package/dist/browser/browser-ground.js +219 -0
  66. package/dist/browser/index.d.ts +4 -0
  67. package/dist/browser/index.js +7 -0
  68. package/dist/browser/indexeddb-memory.d.ts +17 -0
  69. package/dist/browser/indexeddb-memory.js +97 -0
  70. package/dist/browser/locked-custody.d.ts +25 -0
  71. package/dist/browser/locked-custody.js +89 -0
  72. package/dist/browser/origin-classes.d.ts +7 -0
  73. package/dist/browser/origin-classes.js +31 -0
  74. package/dist/foundation.d.ts +150 -0
  75. package/dist/foundation.js +4 -0
  76. package/dist/ground/ground.d.ts +177 -0
  77. package/dist/ground/ground.js +363 -0
  78. package/dist/house/crossing.d.ts +37 -0
  79. package/dist/house/crossing.js +131 -0
  80. package/dist/house/house.d.ts +80 -0
  81. package/dist/house/house.js +1753 -0
  82. package/dist/house/rows-shape.d.ts +103 -0
  83. package/dist/house/rows-shape.js +12 -0
  84. package/dist/house/rows.d.ts +27 -0
  85. package/dist/house/rows.js +168 -0
  86. package/dist/index.d.ts +29 -1
  87. package/dist/index.js +25 -14
  88. package/dist/node/bridge.d.ts +17 -0
  89. package/dist/node/bridge.js +188 -0
  90. package/dist/node/cli.js +170 -0
  91. package/dist/node/custody.d.ts +20 -0
  92. package/dist/node/custody.js +34 -0
  93. package/dist/node/file-keys.d.ts +7 -0
  94. package/dist/node/file-keys.js +30 -0
  95. package/dist/node/file-memory.d.ts +13 -0
  96. package/dist/node/file-memory.js +91 -0
  97. package/dist/node/folder-classes.d.ts +5 -0
  98. package/dist/node/folder-classes.js +40 -0
  99. package/dist/node/gone.d.ts +2 -0
  100. package/dist/node/gone.js +7 -0
  101. package/dist/node/hand.d.ts +29 -0
  102. package/dist/node/hand.js +85 -0
  103. package/dist/node/held-keys.d.ts +14 -0
  104. package/dist/node/held-keys.js +36 -0
  105. package/dist/node/http.d.ts +11 -0
  106. package/dist/node/http.js +90 -0
  107. package/dist/node/index.d.ts +13 -0
  108. package/dist/node/index.js +15 -0
  109. package/dist/node/keychain-keys.d.ts +10 -0
  110. package/dist/node/keychain-keys.js +51 -0
  111. package/dist/node/ledger-memory.d.ts +17 -0
  112. package/dist/node/ledger-memory.js +151 -0
  113. package/dist/node/lock.d.ts +10 -0
  114. package/dist/node/lock.js +78 -0
  115. package/dist/node/node-ground.d.ts +33 -0
  116. package/dist/node/node-ground.js +147 -0
  117. package/dist/node/notify.d.ts +1 -0
  118. package/dist/node/notify.js +18 -0
  119. package/dist/node/tcp-carry.d.ts +39 -0
  120. package/dist/node/tcp-carry.js +216 -0
  121. package/dist/node/websocket.d.ts +6 -0
  122. package/dist/node/websocket.js +118 -0
  123. package/dist/quo/frame.d.ts +20 -0
  124. package/dist/quo/frame.js +48 -0
  125. package/dist/quo/room.d.ts +154 -0
  126. package/dist/quo/room.js +362 -0
  127. package/dist/serve/index.d.ts +27 -0
  128. package/dist/serve/index.js +55 -0
  129. package/package.json +49 -47
  130. package/dist/browser.d.ts +0 -1
  131. package/dist/browser.js +0 -8
  132. package/dist/cli.js +0 -16
  133. package/dist/core/being/being.d.ts +0 -17
  134. package/dist/core/being/being.js +0 -72
  135. package/dist/core/being/digest.d.ts +0 -3
  136. package/dist/core/being/digest.js +0 -17
  137. package/dist/core/being/faculty.d.ts +0 -10
  138. package/dist/core/being/faculty.js +0 -77
  139. package/dist/core/being/index.d.ts +0 -6
  140. package/dist/core/being/index.js +0 -8
  141. package/dist/core/being/kind.d.ts +0 -6
  142. package/dist/core/being/kind.js +0 -34
  143. package/dist/core/being/types.d.ts +0 -61
  144. package/dist/core/being/types.js +0 -4
  145. package/dist/core/being/words.d.ts +0 -13
  146. package/dist/core/being/words.js +0 -14
  147. package/dist/core/browser/index.d.ts +0 -37
  148. package/dist/core/browser/index.js +0 -196
  149. package/dist/core/browser/worker.d.ts +0 -11
  150. package/dist/core/browser/worker.js +0 -37
  151. package/dist/core/cli/command.d.ts +0 -13
  152. package/dist/core/cli/command.js +0 -330
  153. package/dist/core/cli/edge.d.ts +0 -7
  154. package/dist/core/cli/edge.js +0 -79
  155. package/dist/core/cli/harbor.d.ts +0 -25
  156. package/dist/core/cli/harbor.js +0 -115
  157. package/dist/core/contract/index.d.ts +0 -42
  158. package/dist/core/contract/index.js +0 -34
  159. package/dist/core/contract/link.d.ts +0 -4
  160. package/dist/core/contract/link.js +0 -45
  161. package/dist/core/crypto/aes.d.ts +0 -3
  162. package/dist/core/crypto/aes.js +0 -24
  163. package/dist/core/crypto/bytes.d.ts +0 -6
  164. package/dist/core/crypto/bytes.js +0 -33
  165. package/dist/core/crypto/ed25519.d.ts +0 -3
  166. package/dist/core/crypto/ed25519.js +0 -93
  167. package/dist/core/crypto/hash.d.ts +0 -2
  168. package/dist/core/crypto/hash.js +0 -11
  169. package/dist/core/crypto/index.d.ts +0 -7
  170. package/dist/core/crypto/index.js +0 -10
  171. package/dist/core/crypto/json.d.ts +0 -8
  172. package/dist/core/crypto/json.js +0 -250
  173. package/dist/core/crypto/mlkem.d.ts +0 -12
  174. package/dist/core/crypto/mlkem.js +0 -36
  175. package/dist/core/crypto/subtle.d.ts +0 -3
  176. package/dist/core/crypto/subtle.js +0 -11
  177. package/dist/core/crypto/x25519.d.ts +0 -2
  178. package/dist/core/crypto/x25519.js +0 -24
  179. package/dist/core/edge/index.d.ts +0 -164
  180. package/dist/core/edge/index.js +0 -739
  181. package/dist/core/edge/kit.d.ts +0 -2
  182. package/dist/core/edge/kit.js +0 -2
  183. package/dist/core/folder/index.d.ts +0 -18
  184. package/dist/core/folder/index.js +0 -130
  185. package/dist/core/git/http.d.ts +0 -6
  186. package/dist/core/git/http.js +0 -102
  187. package/dist/core/git/index.d.ts +0 -5
  188. package/dist/core/git/index.js +0 -10
  189. package/dist/core/git/object.d.ts +0 -40
  190. package/dist/core/git/object.js +0 -103
  191. package/dist/core/git/pack.d.ts +0 -9
  192. package/dist/core/git/pack.js +0 -171
  193. package/dist/core/git/store.d.ts +0 -23
  194. package/dist/core/git/store.js +0 -120
  195. package/dist/core/git/zlib.d.ts +0 -6
  196. package/dist/core/git/zlib.js +0 -210
  197. package/dist/core/harbor/carrying.d.ts +0 -51
  198. package/dist/core/harbor/carrying.js +0 -69
  199. package/dist/core/harbor/catalogue.d.ts +0 -33
  200. package/dist/core/harbor/catalogue.js +0 -365
  201. package/dist/core/harbor/dna.d.ts +0 -13
  202. package/dist/core/harbor/dna.js +0 -120
  203. package/dist/core/harbor/dock.d.ts +0 -62
  204. package/dist/core/harbor/dock.js +0 -381
  205. package/dist/core/harbor/harbor.d.ts +0 -16
  206. package/dist/core/harbor/harbor.js +0 -438
  207. package/dist/core/harbor/index.d.ts +0 -11
  208. package/dist/core/harbor/index.js +0 -14
  209. package/dist/core/harbor/memory.d.ts +0 -10
  210. package/dist/core/harbor/memory.js +0 -25
  211. package/dist/core/harbor/package.d.ts +0 -20
  212. package/dist/core/harbor/package.js +0 -172
  213. package/dist/core/harbor/probe.d.ts +0 -22
  214. package/dist/core/harbor/probe.js +0 -15
  215. package/dist/core/harbor/registry.d.ts +0 -15
  216. package/dist/core/harbor/registry.js +0 -110
  217. package/dist/core/harbor/root-line.d.ts +0 -7
  218. package/dist/core/harbor/root-line.js +0 -9
  219. package/dist/core/harbor/terrain.d.ts +0 -25
  220. package/dist/core/harbor/terrain.js +0 -28
  221. package/dist/core/http/index.d.ts +0 -2
  222. package/dist/core/http/index.js +0 -154
  223. package/dist/core/http/websocket.d.ts +0 -29
  224. package/dist/core/http/websocket.js +0 -133
  225. package/dist/core/line/answer.d.ts +0 -8
  226. package/dist/core/line/answer.js +0 -60
  227. package/dist/core/line/frame.d.ts +0 -29
  228. package/dist/core/line/frame.js +0 -77
  229. package/dist/core/line/ground.d.ts +0 -3
  230. package/dist/core/line/ground.js +0 -7
  231. package/dist/core/line/index.d.ts +0 -4
  232. package/dist/core/line/index.js +0 -8
  233. package/dist/core/line/web.d.ts +0 -12
  234. package/dist/core/line/web.js +0 -117
  235. package/dist/core/node/index.d.ts +0 -23
  236. package/dist/core/node/index.js +0 -124
  237. package/dist/core/pointer/bodies.d.ts +0 -31
  238. package/dist/core/pointer/bodies.js +0 -118
  239. package/dist/core/pointer/index.d.ts +0 -2
  240. package/dist/core/pointer/index.js +0 -4
  241. package/dist/core/pointer/world.d.ts +0 -45
  242. package/dist/core/pointer/world.js +0 -106
  243. package/dist/core/proof/contracts.d.ts +0 -19
  244. package/dist/core/proof/contracts.js +0 -116
  245. package/dist/core/proof/expect.d.ts +0 -6
  246. package/dist/core/proof/expect.js +0 -18
  247. package/dist/core/proof/index.d.ts +0 -3
  248. package/dist/core/proof/index.js +0 -14
  249. package/dist/core/proof/law.d.ts +0 -25
  250. package/dist/core/proof/law.js +0 -715
  251. package/dist/core/quo/address.d.ts +0 -19
  252. package/dist/core/quo/address.js +0 -84
  253. package/dist/core/quo/door.d.ts +0 -34
  254. package/dist/core/quo/door.js +0 -174
  255. package/dist/core/quo/index.d.ts +0 -9
  256. package/dist/core/quo/index.js +0 -12
  257. package/dist/core/quo/invitation.d.ts +0 -8
  258. package/dist/core/quo/invitation.js +0 -19
  259. package/dist/core/quo/keys.d.ts +0 -40
  260. package/dist/core/quo/keys.js +0 -79
  261. package/dist/core/quo/payload.d.ts +0 -15
  262. package/dist/core/quo/payload.js +0 -55
  263. package/dist/core/quo/relations.d.ts +0 -40
  264. package/dist/core/quo/relations.js +0 -33
  265. package/dist/core/quo/reply.d.ts +0 -13
  266. package/dist/core/quo/reply.js +0 -35
  267. package/dist/core/quo/seal.d.ts +0 -42
  268. package/dist/core/quo/seal.js +0 -78
  269. package/dist/core/quo/standing.d.ts +0 -39
  270. package/dist/core/quo/standing.js +0 -90
  271. package/dist/core/tcp/index.d.ts +0 -27
  272. package/dist/core/tcp/index.js +0 -209
  273. package/dist/core/ward/allowance.d.ts +0 -14
  274. package/dist/core/ward/allowance.js +0 -32
  275. package/dist/core/ward/cells.d.ts +0 -7
  276. package/dist/core/ward/cells.js +0 -74
  277. package/dist/core/ward/house.d.ts +0 -67
  278. package/dist/core/ward/house.js +0 -473
  279. package/dist/core/ward/index.d.ts +0 -5
  280. package/dist/core/ward/index.js +0 -7
  281. package/dist/core/ward/partition.d.ts +0 -50
  282. package/dist/core/ward/partition.js +0 -66
  283. package/dist/core/ward/stance.d.ts +0 -29
  284. package/dist/core/ward/stance.js +0 -186
  285. package/dist/core/ward/ward.d.ts +0 -44
  286. package/dist/core/ward/ward.js +0 -140
  287. package/dist/core.d.ts +0 -10
  288. package/dist/core.js +0 -19
  289. package/dist/defaults/dock/index.d.ts +0 -4
  290. package/dist/defaults/dock/index.js +0 -11
  291. package/dist/defaults/index.d.ts +0 -5
  292. package/dist/defaults/index.js +0 -10
  293. package/dist/defaults/memory/index.d.ts +0 -12
  294. package/dist/defaults/memory/index.js +0 -39
  295. package/dist/defaults/tcp/index.d.ts +0 -16
  296. package/dist/defaults/tcp/index.js +0 -82
  297. package/dist/defaults/ward/index.d.ts +0 -4
  298. package/dist/defaults/ward/index.js +0 -11
  299. package/dist/defaults/web/index.d.ts +0 -15
  300. package/dist/defaults/web/index.js +0 -90
  301. package/dist/edge.d.ts +0 -1
  302. package/dist/edge.js +0 -9
  303. package/dist/kit.d.ts +0 -4
  304. package/dist/kit.js +0 -12
  305. package/dist/node.d.ts +0 -1
  306. package/dist/node.js +0 -8
  307. package/src/browser.ts +0 -10
  308. package/src/cli.ts +0 -15
  309. package/src/core/being/being.ts +0 -84
  310. package/src/core/being/digest.ts +0 -18
  311. package/src/core/being/faculty.ts +0 -76
  312. package/src/core/being/index.ts +0 -8
  313. package/src/core/being/kind.ts +0 -37
  314. package/src/core/being/types.ts +0 -74
  315. package/src/core/being/words.ts +0 -31
  316. package/src/core/browser/index.ts +0 -219
  317. package/src/core/browser/worker.ts +0 -63
  318. package/src/core/cli/command.ts +0 -311
  319. package/src/core/cli/edge.ts +0 -86
  320. package/src/core/cli/harbor.ts +0 -120
  321. package/src/core/contract/index.ts +0 -82
  322. package/src/core/contract/link.ts +0 -58
  323. package/src/core/crypto/aes.ts +0 -26
  324. package/src/core/crypto/bytes.ts +0 -37
  325. package/src/core/crypto/ed25519.ts +0 -92
  326. package/src/core/crypto/hash.ts +0 -14
  327. package/src/core/crypto/index.ts +0 -10
  328. package/src/core/crypto/json.ts +0 -241
  329. package/src/core/crypto/mlkem.ts +0 -38
  330. package/src/core/crypto/subtle.ts +0 -13
  331. package/src/core/crypto/x25519.ts +0 -23
  332. package/src/core/edge/index.ts +0 -865
  333. package/src/core/folder/index.ts +0 -137
  334. package/src/core/git/http.ts +0 -103
  335. package/src/core/git/index.ts +0 -10
  336. package/src/core/git/object.ts +0 -116
  337. package/src/core/git/pack.ts +0 -147
  338. package/src/core/git/store.ts +0 -122
  339. package/src/core/git/zlib.ts +0 -197
  340. package/src/core/harbor/carrying.ts +0 -124
  341. package/src/core/harbor/catalogue.ts +0 -386
  342. package/src/core/harbor/dna.ts +0 -116
  343. package/src/core/harbor/dock.ts +0 -420
  344. package/src/core/harbor/harbor.ts +0 -433
  345. package/src/core/harbor/index.ts +0 -14
  346. package/src/core/harbor/memory.ts +0 -31
  347. package/src/core/harbor/package.ts +0 -195
  348. package/src/core/harbor/probe.ts +0 -39
  349. package/src/core/harbor/registry.ts +0 -107
  350. package/src/core/harbor/root-line.ts +0 -19
  351. package/src/core/harbor/terrain.ts +0 -54
  352. package/src/core/http/index.ts +0 -147
  353. package/src/core/http/websocket.ts +0 -124
  354. package/src/core/line/answer.ts +0 -60
  355. package/src/core/line/frame.ts +0 -83
  356. package/src/core/line/ground.ts +0 -18
  357. package/src/core/line/index.ts +0 -8
  358. package/src/core/line/web.ts +0 -123
  359. package/src/core/node/index.ts +0 -139
  360. package/src/core/pointer/bodies.ts +0 -122
  361. package/src/core/pointer/index.ts +0 -4
  362. package/src/core/pointer/world.ts +0 -134
  363. package/src/core/proof/contracts.ts +0 -134
  364. package/src/core/proof/expect.ts +0 -25
  365. package/src/core/proof/index.ts +0 -14
  366. package/src/core/proof/law.ts +0 -742
  367. package/src/core/quo/address.ts +0 -87
  368. package/src/core/quo/door.ts +0 -180
  369. package/src/core/quo/index.ts +0 -12
  370. package/src/core/quo/invitation.ts +0 -19
  371. package/src/core/quo/keys.ts +0 -91
  372. package/src/core/quo/payload.ts +0 -61
  373. package/src/core/quo/relations.ts +0 -62
  374. package/src/core/quo/reply.ts +0 -38
  375. package/src/core/quo/seal.ts +0 -101
  376. package/src/core/quo/standing.ts +0 -111
  377. package/src/core/stand/main.ts +0 -20
  378. package/src/core/stand/stand.ts +0 -259
  379. package/src/core/tcp/index.ts +0 -227
  380. package/src/core/ward/allowance.ts +0 -47
  381. package/src/core/ward/cells.ts +0 -77
  382. package/src/core/ward/house.ts +0 -524
  383. package/src/core/ward/index.ts +0 -7
  384. package/src/core/ward/partition.ts +0 -117
  385. package/src/core/ward/stance.ts +0 -207
  386. package/src/core/ward/ward.ts +0 -166
  387. package/src/core.ts +0 -55
  388. package/src/defaults/dock/index.ts +0 -12
  389. package/src/defaults/index.ts +0 -10
  390. package/src/defaults/memory/index.ts +0 -50
  391. package/src/defaults/tcp/index.ts +0 -89
  392. package/src/defaults/ward/index.ts +0 -12
  393. package/src/defaults/web/index.ts +0 -97
  394. package/src/edge.ts +0 -11
  395. package/src/index.ts +0 -18
  396. package/src/kit.ts +0 -15
  397. package/src/node.ts +0 -10
  398. /package/dist/{cli.d.ts → node/cli.d.ts} +0 -0
@@ -0,0 +1,87 @@
1
+ import type { Json, Position } from '../being/being.ts';
2
+ import { type Table } from '../being/table.ts';
3
+ import type { BeingClass } from '../foundation.ts';
4
+ import { type Answer, type Offer } from '../house/house.ts';
5
+ import { FakeClock } from './fake-clock.ts';
6
+ export interface BenchOptions {
7
+ /** Her classes, and any other class her beings meet. */
8
+ readonly classes: readonly BeingClass[];
9
+ /** Fakes of the faculties her needs name. */
10
+ readonly offers?: readonly Offer[];
11
+ /** One seed, so a bench runs the same each time. */
12
+ readonly seed?: string;
13
+ /** Her steward, placed as the author's house's steward; the bench's own where none is given. */
14
+ readonly steward?: BeingClass;
15
+ /** Her public being, placed as the author's house's public being. */
16
+ readonly public?: BeingClass;
17
+ }
18
+ /** Where a check places her: a normal being, the steward, or the public being. */
19
+ export interface CheckOptions {
20
+ readonly classes?: readonly BeingClass[];
21
+ readonly seed?: string;
22
+ readonly position?: Position;
23
+ /** The steward beside her, where she is not it. */
24
+ readonly steward?: BeingClass;
25
+ }
26
+ /** One thing the bench checked: what, and why it failed where it did. */
27
+ export interface Finding {
28
+ readonly ok: boolean;
29
+ readonly what: string;
30
+ readonly why?: string;
31
+ }
32
+ /** A being the bench placed, asked through a handle as any role. */
33
+ export declare class Placed {
34
+ #private;
35
+ readonly id: string;
36
+ constructor(bench: Bench, id: string, table: Table);
37
+ /** The role an ask's entry names first; `steward` where it names every occupant. */
38
+ roleFor(method: string): string;
39
+ /** One ask, crossing as a box, as the occupant who plays `role`. `null` is silence or nothing. */
40
+ ask(method: string, args?: Json, { role }?: {
41
+ role?: string;
42
+ }): Promise<Answer | null>;
43
+ /** Her describe as `role` sees it: `root` where she is the steward, her steward otherwise. */
44
+ describe({ role }?: {
45
+ role?: string;
46
+ }): Promise<{
47
+ state: string;
48
+ asks: {
49
+ method: string;
50
+ }[];
51
+ } | null>;
52
+ /** Her cells as they stand. */
53
+ cells(): Promise<Record<string, Json> | null>;
54
+ }
55
+ export declare class Bench {
56
+ #private;
57
+ readonly clock: FakeClock;
58
+ private constructor();
59
+ static open({ classes, offers, seed, steward, public: open }: BenchOptions): Promise<Bench>;
60
+ /**
61
+ * Her class here: the steward or the public being where the bench opened
62
+ * with her there, and otherwise borne, from her `born` or from the cells
63
+ * an example starts from.
64
+ */
65
+ place(Class: BeingClass, { id, cells, born }?: {
66
+ id?: string;
67
+ cells?: Record<string, Json>;
68
+ born?: Record<string, Json>;
69
+ }): Promise<Placed>;
70
+ /** Lets every ask, effect and reply the houses started run to its end. */
71
+ settle(): Promise<void>;
72
+ /** The clock moved on, and what came due run. */
73
+ advance(ms: number): Promise<void>;
74
+ cellsOf(being: string): Promise<Record<string, Json> | null>;
75
+ through(being: string, role: string, ask: string | undefined, method: string | undefined, args: Json): Promise<Answer | {
76
+ describe: Json;
77
+ } | null>;
78
+ /** Every example of her class run, twice, on two fresh benches. */
79
+ static examples(Class: BeingClass, options?: CheckOptions): Promise<Finding[]>;
80
+ /**
81
+ * Every state her default cells and her examples reach, described to
82
+ * every role she names: what each is shown is what her table says.
83
+ */
84
+ static walk(Class: BeingClass, options?: CheckOptions): Promise<Finding[]>;
85
+ /** Her examples and her walk, and an error naming every finding that failed. */
86
+ static check(Class: BeingClass, options?: CheckOptions): Promise<Finding[]>;
87
+ }
@@ -0,0 +1,260 @@
1
+ import { resolve } from '../being/table.js';
2
+ import { blueprintOf } from '../being/need.js';
3
+ import { StrictTools } from '../bodies/strict-tools.js';
4
+ import { ClassList } from '../bodies/class-list.js';
5
+ import { openForBench } from '../house/house.js';
6
+ import { Room } from '../quo/room.js';
7
+ import { FakeCarry } from './fake-carry.js';
8
+ import { FakeClock } from './fake-clock.js';
9
+ import { FakeKeys } from './fake-keys.js';
10
+ import { FakeMemory } from './fake-memory.js';
11
+ import { SeededCrypto } from './seeded.js';
12
+ import { settle } from './settle.js';
13
+ import { BenchSteward, BenchTester } from './stewards.js';
14
+ const STEWARD = 'steward';
15
+ const PUBLIC = 'public';
16
+ const tools = new StrictTools();
17
+ /** A being the bench placed, asked through a handle as any role. */
18
+ export class Placed {
19
+ id;
20
+ #bench;
21
+ #table;
22
+ constructor(bench, id, table) {
23
+ this.#bench = bench;
24
+ this.id = id;
25
+ this.#table = table;
26
+ }
27
+ /** The role an ask's entry names first; `steward` where it names every occupant. */
28
+ roleFor(method) {
29
+ const entry = this.#table.asks[method];
30
+ return entry?.for?.[0] ?? STEWARD;
31
+ }
32
+ /** One ask, crossing as a box, as the occupant who plays `role`. `null` is silence or nothing. */
33
+ async ask(method, args = {}, { role = this.roleFor(method) } = {}) {
34
+ const answered = await this.#bench.through(this.id, role, method, method, args);
35
+ return answered === null || 'describe' in answered ? null : answered;
36
+ }
37
+ /** Her describe as `role` sees it: `root` where she is the steward, her steward otherwise. */
38
+ async describe({ role = this.id === STEWARD ? 'root' : STEWARD } = {}) {
39
+ const answered = await this.#bench.through(this.id, role, undefined, undefined, {});
40
+ return answered !== null && 'describe' in answered ? answered.describe : null;
41
+ }
42
+ /** Her cells as they stand. */
43
+ cells() {
44
+ return this.#bench.cellsOf(this.id);
45
+ }
46
+ }
47
+ export class Bench {
48
+ clock;
49
+ #author;
50
+ #tester;
51
+ #standings = new Map();
52
+ #steward;
53
+ #public;
54
+ #stranger;
55
+ #count = 0;
56
+ constructor(clock, author, tester, placed, stranger) {
57
+ this.clock = clock;
58
+ this.#author = author;
59
+ this.#tester = tester;
60
+ this.#steward = placed.steward;
61
+ this.#public = placed.public;
62
+ this.#stranger = stranger;
63
+ }
64
+ static async open({ classes, offers = [], seed = 'bench', steward, public: open }) {
65
+ const clock = new FakeClock();
66
+ const network = new Map();
67
+ const house = async (name, list, handed) => {
68
+ const crypto = new SeededCrypto(`${seed}:${name}`);
69
+ const carry = new FakeCarry({ network, address: `bench://${name}` });
70
+ const opened = await openForBench({ keys: new FakeKeys(`${seed}:${name}`, crypto), memory: new FakeMemory(), classes: list, carry, clock, crypto, tools }, handed);
71
+ carry.listen(opened.opened);
72
+ return opened;
73
+ };
74
+ const author = await house('author', new ClassList({ steward: steward ?? BenchSteward, ...(open === undefined ? {} : { public: open }), beings: classes }), offers);
75
+ const tester = await house('bench', new ClassList({ steward: BenchTester }), []);
76
+ // The stranger's key, drawn from the seed, so a re-run signs as the first run did.
77
+ const crypto = new SeededCrypto(`${seed}:stranger`);
78
+ const stranger = { room: new Room(new FakeKeys(`${seed}:stranger`, crypto), crypto, tools), secret: tools.hex(crypto.random(32)) };
79
+ return new Bench(clock, author, tester, { steward, public: open }, stranger);
80
+ }
81
+ /**
82
+ * Her class here: the steward or the public being where the bench opened
83
+ * with her there, and otherwise borne, from her `born` or from the cells
84
+ * an example starts from.
85
+ */
86
+ async place(Class, { id, cells, born } = {}) {
87
+ const table = resolve(Class);
88
+ const position = Class === this.#steward ? STEWARD : Class === this.#public ? PUBLIC : undefined;
89
+ const name = position ?? id ?? `placed-${++this.#count}`;
90
+ if (position === undefined)
91
+ await this.#author.access.bear(table.kind, name, born);
92
+ await this.settle();
93
+ if (cells !== undefined) {
94
+ const patched = await this.#author.access.patch(name, (row) => {
95
+ row.cells = { ...row.cells, ...cells };
96
+ });
97
+ if (!patched)
98
+ throw new Error('memory refused the example’s cells');
99
+ }
100
+ return new Placed(this, name, table);
101
+ }
102
+ /** Lets every ask, effect and reply the houses started run to its end. */
103
+ async settle() {
104
+ await settle();
105
+ }
106
+ /** The clock moved on, and what came due run. */
107
+ async advance(ms) {
108
+ this.clock.advance(ms);
109
+ await this.settle();
110
+ }
111
+ cellsOf(being) {
112
+ return this.#author.access.cells(being);
113
+ }
114
+ // Who plays a role. On the public being, a role `stranger` holds is played
115
+ // by a box with the zero head. A role `root` holds is played through the
116
+ // hand, on any being. Otherwise an occupant named for it plays it, the
117
+ // role true in both sets of notes. A handle is admitted to one ask;
118
+ // `being` is introduced; `steward` is hers.
119
+ async through(being, role, ask, method, args) {
120
+ const holds = async (asker) => role === asker || (await this.#author.access.roles(being, asker)).includes(role);
121
+ const played = being === PUBLIC && (await holds('stranger')) ? this.#zero(method, args) : (await holds('root')) ? this.#hand(being, method, args) : undefined;
122
+ if (played !== undefined) {
123
+ const answered = await played;
124
+ await this.settle();
125
+ return answered;
126
+ }
127
+ const occupant = role === 'handle' ? `handle:bench-${ask}` : role === 'being' ? 'being:bench' : role;
128
+ const key = `${being}\n${occupant}`;
129
+ let standing = this.#standings.get(key);
130
+ if (standing === undefined) {
131
+ const notes = role === STEWARD || role === 'being' || role === 'handle' ? {} : { [role]: true };
132
+ const invitation = await this.#author.access.occupant(being, occupant, { notes, steward: notes, ...(role === 'handle' ? { ask: ask } : {}) });
133
+ const adopted = await this.#tester.opened.ask({ method: 'adopt', args: { invitation } });
134
+ if (!('result' in adopted))
135
+ throw new Error(`the bench could not hold ${role}: ${JSON.stringify(adopted)}`);
136
+ standing = adopted.result;
137
+ this.#standings.set(key, standing);
138
+ }
139
+ const answered = await this.#tester.access.far(STEWARD, standing, method, args);
140
+ await this.settle();
141
+ return answered;
142
+ }
143
+ // A being asked by the holder of the house's hand, which no box carries.
144
+ #hand(being, method, args) {
145
+ return this.#author.opened.ask({ id: being, ...(method === undefined ? {} : { method, args }) });
146
+ }
147
+ // The public being asked by a stranger: a box with the zero head, signed with the bench's stranger key.
148
+ async #zero(method, args) {
149
+ const { room, secret } = this.#stranger;
150
+ const ward = this.#author.opened.ward;
151
+ const sealed = await room.stranger(ward, secret, { ...(method === undefined ? {} : { method }), args: tools.canonical(args) });
152
+ const read = await room.strangerRead(ward, sealed.lid, await this.#author.opened.door(sealed.box));
153
+ if (!('object' in read))
154
+ return null;
155
+ return method === undefined ? { describe: read.object } : read.object;
156
+ }
157
+ /** Every example of her class run, twice, on two fresh benches. */
158
+ static async examples(Class, options = {}) {
159
+ const table = resolve(Class);
160
+ const where = { ...options, seed: options.seed ?? 'examples' };
161
+ const findings = [];
162
+ for (const entry of Object.values(table.asks)) {
163
+ for (const [index, raw] of entry.examples.entries()) {
164
+ const example = raw;
165
+ const what = `${entry.method}, example ${index + 1}${example.description === undefined ? '' : `: ${example.description}`}`;
166
+ try {
167
+ const first = await Bench.#run(Class, table, entry, example, where);
168
+ const second = await Bench.#run(Class, table, entry, example, where);
169
+ if (example.gives !== undefined && tools.canonical(first.answer) !== tools.canonical(example.gives)) {
170
+ findings.push({ ok: false, what, why: `it gives ${JSON.stringify(first.answer)}, and the example says ${JSON.stringify(example.gives)}` });
171
+ }
172
+ else if (tools.canonical(first) !== tools.canonical(second)) {
173
+ findings.push({ ok: false, what, why: 'a re-run on the same cells answered differently' });
174
+ }
175
+ else
176
+ findings.push({ ok: true, what });
177
+ }
178
+ catch (error) {
179
+ findings.push({ ok: false, what, why: error instanceof Error ? error.message : String(error) });
180
+ }
181
+ }
182
+ }
183
+ return findings;
184
+ }
185
+ // A fresh bench with her in the position the check names, and the steward beside her where one is given.
186
+ static #opening(Class, table, example, { classes = [], seed, position = 'normal', steward }) {
187
+ return Bench.open({
188
+ classes: position === 'normal' ? [Class, ...classes] : classes,
189
+ offers: fakes(table, example),
190
+ ...(seed === undefined ? {} : { seed }),
191
+ ...(position === 'steward' ? { steward: Class } : steward === undefined ? {} : { steward }),
192
+ ...(position === 'public' ? { public: Class } : {}),
193
+ });
194
+ }
195
+ static async #run(Class, table, entry, example, options) {
196
+ const bench = await Bench.#opening(Class, table, example, options);
197
+ const placed = await bench.place(Class, example.cells === undefined ? {} : { cells: example.cells });
198
+ const answer = await placed.ask(entry.method, example.args ?? {}, example.role === undefined ? {} : { role: example.role });
199
+ return { answer: answer ?? { nothing: true }, cells: await placed.cells() };
200
+ }
201
+ /**
202
+ * Every state her default cells and her examples reach, described to
203
+ * every role she names: what each is shown is what her table says.
204
+ */
205
+ static async walk(Class, options = {}) {
206
+ const table = resolve(Class);
207
+ const where = { ...options, seed: options.seed ?? 'walk' };
208
+ const position = options.position ?? 'normal';
209
+ const findings = [];
210
+ const starts = [undefined, ...Object.values(table.asks).flatMap((entry) => entry.examples.map((example) => example.cells))];
211
+ const seen = new Set();
212
+ // Each role her position lets someone hold: the steward has no steward, and only the public being has strangers.
213
+ const roles = [...new Set([STEWARD, ...Object.keys(table.roles), ...Object.values(table.asks).flatMap((entry) => entry.for ?? [])])].filter((role) => role !== 'handle' && (role !== 'stranger' || position === 'public') && (role !== STEWARD || position !== 'steward'));
214
+ for (const cells of starts) {
215
+ // One visit a state, from the first cells that reach it.
216
+ const state = table.state({ id: '', position, cells: { ...table.cells, ...cells } });
217
+ if (seen.has(state))
218
+ continue;
219
+ seen.add(state);
220
+ const bench = await Bench.#opening(Class, table, {}, where);
221
+ const placed = await bench.place(Class, cells === undefined ? {} : { cells });
222
+ // The roles a stranger holds, to whom a public being never shows an effect.
223
+ const strange = position === 'public' ? await bench.#author.access.roles(PUBLIC, 'stranger') : [];
224
+ for (const role of roles) {
225
+ const what = `${state}, as ${role}`;
226
+ const described = await placed.describe({ role });
227
+ const shown = (described?.asks ?? []).map((entry) => entry.method).sort();
228
+ const owed = Object.values(table.asks)
229
+ .filter((entry) => !(entry.effect && (role === 'stranger' || strange.includes(role))))
230
+ .filter((entry) => (entry.for === null ? true : entry.for.includes(role)))
231
+ .map((entry) => entry.method)
232
+ .sort();
233
+ if (described === null)
234
+ findings.push({ ok: false, what, why: 'she answered nothing' });
235
+ else if (described.state !== state)
236
+ findings.push({ ok: false, what, why: `she says ${described.state}` });
237
+ else if (shown.join() !== owed.join())
238
+ findings.push({ ok: false, what, why: `she shows ${shown.join(', ') || 'nothing'}, and her table owes ${owed.join(', ') || 'nothing'}` });
239
+ else
240
+ findings.push({ ok: true, what });
241
+ }
242
+ }
243
+ return findings;
244
+ }
245
+ /** Her examples and her walk, and an error naming every finding that failed. */
246
+ static async check(Class, options = {}) {
247
+ const findings = [...(await Bench.examples(Class, options)), ...(await Bench.walk(Class, options))];
248
+ const failed = findings.filter((finding) => !finding.ok);
249
+ if (failed.length > 0)
250
+ throw new Error(`the bench found ${failed.length}:\n${failed.map((finding) => `- ${finding.what}: ${finding.why}`).join('\n')}`);
251
+ return findings;
252
+ }
253
+ }
254
+ // A fake of each faculty her needs name, answering what an example says,
255
+ // and `{ result: null }` where it says nothing.
256
+ const fakes = (table, example) => Object.entries(table.needs).map(([member, blueprint]) => {
257
+ const said = example.fakes?.[member] ?? {};
258
+ const object = Object.fromEntries(Object.keys(blueprint.methods).map((method) => [method, async () => said[method] ?? { result: null }]));
259
+ return { blueprint: blueprintOf(blueprint) ?? blueprint, object, kinds: [table.kind] };
260
+ });
@@ -0,0 +1,32 @@
1
+ import type { Carry, Sent } from '../foundation.ts';
2
+ export type Door = (box: Uint8Array) => Promise<Uint8Array | null>;
3
+ export declare class FakeCarry implements Carry {
4
+ #private;
5
+ /** The next `lose` replies are lost after the far door answered. */
6
+ lose: number;
7
+ /** Every address a box was carried to, in order. */
8
+ readonly tried: string[];
9
+ /** `at` names the addresses written into invitations, as a ground names its own; omitted, the one it listens at. */
10
+ constructor({ network, address, at }: {
11
+ network: Map<string, Door>;
12
+ address: string;
13
+ at?: readonly string[];
14
+ });
15
+ /** A house's door answers at this carry's address, and by pointer to whoever sends through this carry. */
16
+ listen({ ward, door }: {
17
+ ward: string;
18
+ door: Door;
19
+ }): void;
20
+ /** A ward this carry answers no more, by pointer or at its address. */
21
+ unlisten({ ward }: {
22
+ ward: string;
23
+ }): void;
24
+ send({ ward, at, box }: {
25
+ ward: string;
26
+ at: readonly string[];
27
+ box: Uint8Array;
28
+ }): Promise<Sent>;
29
+ at(_options?: {
30
+ toward?: string;
31
+ }): readonly string[];
32
+ }
@@ -0,0 +1,56 @@
1
+ export class FakeCarry {
2
+ #network;
3
+ #address;
4
+ #at;
5
+ /** The next `lose` replies are lost after the far door answered. */
6
+ lose = 0;
7
+ /** Every address a box was carried to, in order. */
8
+ tried = [];
9
+ /** `at` names the addresses written into invitations, as a ground names its own; omitted, the one it listens at. */
10
+ constructor({ network, address, at }) {
11
+ this.#network = network;
12
+ this.#address = address;
13
+ this.#at = at;
14
+ }
15
+ #doors = new Map();
16
+ /** A house's door answers at this carry's address, and by pointer to whoever sends through this carry. */
17
+ listen({ ward, door }) {
18
+ this.#doors.set(ward, door);
19
+ this.#network.set(this.#address, door);
20
+ }
21
+ /** A ward this carry answers no more, by pointer or at its address. */
22
+ unlisten({ ward }) {
23
+ const door = this.#doors.get(ward);
24
+ this.#doors.delete(ward);
25
+ if (door !== undefined && this.#network.get(this.#address) === door)
26
+ this.#network.delete(this.#address);
27
+ }
28
+ async send({ ward, at, box }) {
29
+ const held = this.#doors.get(ward);
30
+ if (held !== undefined) {
31
+ const reply = await held(box);
32
+ if (reply !== null)
33
+ return { reply };
34
+ }
35
+ for (const address of at) {
36
+ const door = this.#network.get(address);
37
+ if (door === undefined)
38
+ continue;
39
+ this.tried.push(address);
40
+ const reply = await door(box);
41
+ // A reply lost after the door answered was heard, so no other address is tried.
42
+ if (this.lose > 0) {
43
+ this.lose--;
44
+ return { reply: null, heard: true };
45
+ }
46
+ // A door that gives nothing was not delivered to, so the next address may be.
47
+ if (reply === null)
48
+ continue;
49
+ return { reply, via: address };
50
+ }
51
+ return { reply: null, heard: false };
52
+ }
53
+ at(_options = {}) {
54
+ return this.#at ?? [this.#address];
55
+ }
56
+ }
@@ -0,0 +1,17 @@
1
+ import type { Clock } from '../foundation.ts';
2
+ export declare class FakeClock implements Clock {
3
+ #private;
4
+ constructor(start?: number);
5
+ now(): number;
6
+ wait({ id, ms }: {
7
+ id: string;
8
+ ms: number;
9
+ }): Promise<boolean>;
10
+ cancel({ id }: {
11
+ id: string;
12
+ }): void;
13
+ /** The time moved on, and every wait it passes fired, earliest first. */
14
+ advance(ms: number): void;
15
+ /** The time of the earliest wait, or `null`. */
16
+ next(): number | null;
17
+ }
@@ -0,0 +1,34 @@
1
+ export class FakeClock {
2
+ #now;
3
+ #waits = new Map();
4
+ constructor(start = Date.UTC(2026, 0, 1)) {
5
+ this.#now = start;
6
+ }
7
+ now() {
8
+ return this.#now;
9
+ }
10
+ wait({ id, ms }) {
11
+ this.#waits.get(id)?.resolve(false);
12
+ return new Promise((resolve) => {
13
+ this.#waits.set(id, { at: this.#now + Math.max(0, ms), resolve });
14
+ });
15
+ }
16
+ cancel({ id }) {
17
+ this.#waits.get(id)?.resolve(false);
18
+ this.#waits.delete(id);
19
+ }
20
+ /** The time moved on, and every wait it passes fired, earliest first. */
21
+ advance(ms) {
22
+ this.#now += ms;
23
+ const due = [...this.#waits].filter(([, waiting]) => waiting.at <= this.#now).sort(([, a], [, b]) => a.at - b.at);
24
+ for (const [id, waiting] of due) {
25
+ this.#waits.delete(id);
26
+ waiting.resolve(true);
27
+ }
28
+ }
29
+ /** The time of the earliest wait, or `null`. */
30
+ next() {
31
+ const times = [...this.#waits.values()].map((waiting) => waiting.at);
32
+ return times.length === 0 ? null : Math.min(...times);
33
+ }
34
+ }
@@ -0,0 +1,9 @@
1
+ import type { Custody } from '../ground/ground.ts';
2
+ import type { Keys } from '../foundation.ts';
3
+ export declare class FakeCustody implements Custody {
4
+ #private;
5
+ constructor(seed?: string);
6
+ keys({ house }: {
7
+ house: string;
8
+ }): Keys;
9
+ }
@@ -0,0 +1,10 @@
1
+ import { FakeKeys } from './fake-keys.js';
2
+ export class FakeCustody {
3
+ #seed;
4
+ constructor(seed = 'custody') {
5
+ this.#seed = seed;
6
+ }
7
+ keys({ house }) {
8
+ return new FakeKeys(`${this.#seed}:${house}`);
9
+ }
10
+ }
@@ -0,0 +1,25 @@
1
+ import type { Json } from '../being/being.ts';
2
+ import type { Faculty } from '../ground/ground.ts';
3
+ type Method = (args: Json) => Json | Promise<Json>;
4
+ /** One call the faculty received. */
5
+ export interface Called {
6
+ readonly method: string;
7
+ readonly args: Json;
8
+ readonly id: string;
9
+ }
10
+ export declare class FakeFaculty {
11
+ #private;
12
+ /** Every call, in the order it came, repeats of one call id among them. */
13
+ readonly calls: Called[];
14
+ /** `blueprint` is a need or a blueprint; `methods` answer each method's args with its result. */
15
+ constructor(blueprint: unknown, methods: Readonly<Record<string, Method>>);
16
+ /** The next `count` calls throw, as a crash does. */
17
+ throwNext(count?: number): void;
18
+ /** The next call answers `{ error: { message } }`, which is final. */
19
+ refuseNext(message: string): void;
20
+ /** The next `count` calls never answer. */
21
+ hangNext(count?: number): void;
22
+ /** The offer a ground hands: the blueprint, and an object whose methods take args and a context. */
23
+ get offer(): Faculty;
24
+ }
25
+ export {};
@@ -0,0 +1,48 @@
1
+ export class FakeFaculty {
2
+ /** Every call, in the order it came, repeats of one call id among them. */
3
+ calls = [];
4
+ #blueprint;
5
+ #methods;
6
+ #throw = 0;
7
+ #refuse = [];
8
+ #hang = 0;
9
+ /** `blueprint` is a need or a blueprint; `methods` answer each method's args with its result. */
10
+ constructor(blueprint, methods) {
11
+ this.#blueprint = blueprint;
12
+ this.#methods = methods;
13
+ }
14
+ /** The next `count` calls throw, as a crash does. */
15
+ throwNext(count = 1) {
16
+ this.#throw += count;
17
+ }
18
+ /** The next call answers `{ error: { message } }`, which is final. */
19
+ refuseNext(message) {
20
+ this.#refuse.push(message);
21
+ }
22
+ /** The next `count` calls never answer. */
23
+ hangNext(count = 1) {
24
+ this.#hang += count;
25
+ }
26
+ /** The offer a ground hands: the blueprint, and an object whose methods take args and a context. */
27
+ get offer() {
28
+ const object = Object.fromEntries(Object.entries(this.#methods).map(([method, answer]) => [
29
+ method,
30
+ async (args, context) => {
31
+ this.calls.push({ method, args, id: context.id });
32
+ if (this.#hang > 0) {
33
+ this.#hang--;
34
+ return new Promise(() => undefined);
35
+ }
36
+ if (this.#throw > 0) {
37
+ this.#throw--;
38
+ throw new Error('the fake faculty crashed');
39
+ }
40
+ const refused = this.#refuse.shift();
41
+ if (refused !== undefined)
42
+ return { error: { message: refused } };
43
+ return { result: await answer(args) };
44
+ },
45
+ ]));
46
+ return { blueprint: this.#blueprint, object };
47
+ }
48
+ }
@@ -0,0 +1,5 @@
1
+ import { SeedKeys } from '../bodies/seed-keys.ts';
2
+ import type { Crypto } from '../foundation.ts';
3
+ export declare class FakeKeys extends SeedKeys {
4
+ constructor(name?: string, crypto?: Crypto);
5
+ }
@@ -0,0 +1,9 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Keys from a name: every ward of a test named, and the same each run.
3
+ import { SeedKeys } from '../bodies/seed-keys.js';
4
+ import { seedOf } from './seeded.js';
5
+ export class FakeKeys extends SeedKeys {
6
+ constructor(name = 'fake', crypto) {
7
+ super(seedOf(name), crypto);
8
+ }
9
+ }
@@ -0,0 +1,14 @@
1
+ import type { Memory, PlaceRead } from '../foundation.ts';
2
+ export declare class FakeMemory implements Memory {
3
+ #private;
4
+ /** The next `count` writes are refused, as a memory another writer moved. */
5
+ refuseNext(count?: number): void;
6
+ read({ place }: {
7
+ place: string;
8
+ }): Promise<PlaceRead>;
9
+ list(): Promise<readonly string[]>;
10
+ write({ writes, expect, }: {
11
+ writes: Readonly<Record<string, Readonly<Record<string, Uint8Array | null>>>>;
12
+ expect: Readonly<Record<string, string | null>>;
13
+ }): Promise<Readonly<Record<string, string | null>> | null>;
14
+ }
@@ -0,0 +1,46 @@
1
+ export class FakeMemory {
2
+ #places = new Map();
3
+ #refuse = 0;
4
+ /** The next `count` writes are refused, as a memory another writer moved. */
5
+ refuseNext(count = 1) {
6
+ this.#refuse += count;
7
+ }
8
+ async read({ place }) {
9
+ const held = this.#places.get(place);
10
+ if (held === undefined)
11
+ return { entries: {}, version: null };
12
+ return { entries: Object.fromEntries([...held.entries].map(([name, bytes]) => [name, bytes.slice()])), version: String(held.version) };
13
+ }
14
+ async list() {
15
+ return [...this.#places.keys()];
16
+ }
17
+ async write({ writes, expect, }) {
18
+ if (this.#refuse > 0) {
19
+ this.#refuse--;
20
+ return null;
21
+ }
22
+ for (const place of new Set([...Object.keys(writes), ...Object.keys(expect)])) {
23
+ const held = this.#places.get(place);
24
+ const version = held === undefined ? null : String(held.version);
25
+ if (!(place in expect) || expect[place] !== version)
26
+ return null;
27
+ }
28
+ const versions = {};
29
+ for (const [place, entries] of Object.entries(writes)) {
30
+ const held = this.#places.get(place) ?? { entries: new Map(), version: 0 };
31
+ for (const [name, bytes] of Object.entries(entries)) {
32
+ if (bytes === null)
33
+ held.entries.delete(name);
34
+ else
35
+ held.entries.set(name, bytes.slice());
36
+ }
37
+ held.version++;
38
+ if (held.entries.size === 0)
39
+ this.#places.delete(place);
40
+ else
41
+ this.#places.set(place, held);
42
+ versions[place] = held.entries.size === 0 ? null : String(held.version);
43
+ }
44
+ return versions;
45
+ }
46
+ }