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
@@ -1,715 +0,0 @@
1
- import { Loader, Memory } from '../contract/index.js';
2
- import { blob, idOf } from '../git/index.js';
3
- import { copyPackage, Dna, MemoryFaculty } from '../harbor/index.js';
4
- import { BundleLoader, CryptoEntropy, SourceLoader, VolatileMemory, World } from '../pointer/index.js';
5
- // The law's module, as its author writes it: one ES module that imports
6
- // nothing but `'nervur'`, and nothing of it but the core. A shelf is a
7
- // memory faculty's store, kept in this process by the scenes and reached
8
- // through a registered symbol, so the module's class and the scenes read
9
- // one shelf.
10
- export const LAW = `import { Being, Dock, Faculty, MemoryFaculty, ownerAsk, Ward } from 'nervur';
11
-
12
- export const module = 'org.example.law';
13
- export const version = '1';
14
-
15
- class Echoes extends Faculty {
16
- static kind = 'org.example.echoes';
17
- }
18
- class Echo extends Echoes {
19
- static kind = 'org.example.echo';
20
- static asks = { echo: {} };
21
- echo(args, asker) {
22
- return { echoed: args.text ?? null, to: asker.id ?? null };
23
- }
24
- }
25
-
26
- class Shop extends Being {
27
- static kind = 'org.example.shop';
28
- static cells = { sold: [] };
29
- static asks = { buy: {}, sold: {} };
30
- buy(args, asker) {
31
- this.cells.sold.push(String(args.item) + ' to ' + (asker.id ?? 'nobody'));
32
- return { bought: args.item ?? null };
33
- }
34
- sold() {
35
- return { sold: this.cells.sold };
36
- }
37
- }
38
-
39
- class Customer extends Being {
40
- static kind = 'org.example.customer';
41
- static asks = { join: {}, buy: {}, echo: {}, spoil: {} };
42
- spoil() {
43
- try {
44
- this.cells.when = new Date();
45
- return { kept: true };
46
- } catch {
47
- return { refused: true };
48
- }
49
- }
50
- async join(args) {
51
- return { joined: await this.stance.standings.take('shop', args.invitation) };
52
- }
53
- async buy(args) {
54
- return { said: (await this.stance.standings.get('shop')?.ask('buy', args)) ?? null };
55
- }
56
- async echo(args) {
57
- if (!this.stance.standings.get('echo')) await this.stance.lend(Echoes, 'echo');
58
- return { said: (await this.stance.standings.get('echo')?.ask('echo', args)) ?? null };
59
- }
60
- }
61
-
62
- // A being whose fields are her cells, and nothing else.
63
- class Profile extends Being {
64
- static kind = 'org.example.profile';
65
- static cells = { name: '', age: 0 };
66
- static asks = { set: {}, get: {} };
67
- set(args) {
68
- if (typeof args.name === 'string') this.cells.name = args.name;
69
- if (typeof args.age === 'number') this.cells.age = args.age;
70
- return this.get();
71
- }
72
- get() {
73
- return { name: this.cells.name ?? null, age: this.cells.age ?? null };
74
- }
75
- }
76
-
77
- // A memory faculty a module brings: places on a shelf of this process, by
78
- // the faculty's key, which outlive a harbor as a database outlives its
79
- // client.
80
- const shelf = (key) => globalThis[Symbol.for('org.example.shelf')](key);
81
- class Shelf extends MemoryFaculty {
82
- static kind = 'org.example.shelf';
83
- read(place) {
84
- return shelf(this.stance.key).read(place);
85
- }
86
- write(place, entries) {
87
- return shelf(this.stance.key).write(place, entries);
88
- }
89
- places() {
90
- return shelf(this.stance.key).places();
91
- }
92
- forget(place) {
93
- return shelf(this.stance.key).forget(place);
94
- }
95
- }
96
-
97
- // A ward and a dock a module brings, each with an ask of her own.
98
- class Steward extends Ward {
99
- static kind = 'org.example.steward';
100
- static asks = { ...Ward.asks, sign: ownerAsk('a signature of this ward') };
101
- sign() {
102
- return { signed: this.steward.pk() };
103
- }
104
- }
105
- class Quay extends Dock {
106
- static kind = 'org.example.quay';
107
- static asks = { ...Dock.asks, moor: ownerAsk('the wards moored here') };
108
- moor() {
109
- return { moored: this.hosted.map((h) => h.ward) };
110
- }
111
- }
112
-
113
- export const classes = [Echo, Shop, Customer, Profile, Shelf, Steward, Quay];
114
- `;
115
- export const law = { module: 'org.example.law', version: '1', source: LAW };
116
- // A module of no class, added beside the law's.
117
- const TWIN = "export const module = 'org.example.twin';\nexport const version = '1';\nexport const classes = [];\n";
118
- // The law's module built by a bundler from its source, as a ground that
119
- // imports no source runs it: the bundle an edge is deployed with, which
120
- // carries the module of no class beside it.
121
- export const lawBundle = (module) => new BundleLoader([
122
- { source: LAW, module },
123
- { source: TWIN, module: { module: 'org.example.twin', version: '1', classes: [] } },
124
- ]);
125
- const STEWARD = 'org.example.steward';
126
- const QUAY = 'org.example.quay';
127
- const PROFILE = 'org.example.profile';
128
- const SHELF = 'org.example.shelf';
129
- // Every byte a memory is handed, seen from outside it, and a keep it
130
- // refuses where `refuse` says.
131
- class Watched extends Memory {
132
- inner;
133
- seen = [];
134
- refuse = () => false;
135
- constructor(inner) {
136
- super();
137
- this.inner = inner;
138
- }
139
- read(place) {
140
- return this.inner.read(place);
141
- }
142
- write(place, entries) {
143
- if (this.refuse(place))
144
- return Promise.reject(new Error('refused'));
145
- for (const [name, bytes] of entries)
146
- this.seen.push({ place, name, bytes: bytes && bytes.slice() });
147
- return this.inner.write(place, entries);
148
- }
149
- places() {
150
- return this.inner.places();
151
- }
152
- forget(place) {
153
- return this.inner.forget(place);
154
- }
155
- }
156
- // The shelves the law module's memory faculty keeps, one per key.
157
- const shelves = new Map();
158
- const shelfOf = (key) => {
159
- let found = shelves.get(key);
160
- if (!found)
161
- shelves.set(key, (found = new Watched(new VolatileMemory())));
162
- return found;
163
- };
164
- globalThis[Symbol.for('org.example.shelf')] = shelfOf;
165
- // The loader a scene's harbor runs its code with on this terrain.
166
- const loaderOf = (t) => t.loader?.() ?? new SourceLoader();
167
- const on = (t, bodies = {}) => ({ ...bodies, loader: loaderOf(t) });
168
- // The root line as a scene reads it: what the ward said, or the line's
169
- // silence, word or error.
170
- const root = async (harbor, method, args, ward) => {
171
- const out = await harbor.ask({ ...(ward === undefined ? {} : { ward }), ...(method === undefined ? {} : { method }), ...(args === undefined ? {} : { args }) });
172
- return 'answer' in out ? out.answer : out;
173
- };
174
- // What a being said, asked as the owner through her ward.
175
- const being = async (harbor, key, method, args, ward) => {
176
- const out = (await root(harbor, 'ask', { being: key, method, args }, ward));
177
- return 'answer' in out ? out.answer : out;
178
- };
179
- const census = async (harbor, ward) => (await root(harbor, undefined, undefined, ward)).notes;
180
- const catalogue = async (harbor, method, args = {}) => (await being(harbor, 'catalogue', method, args));
181
- // The hosted wards that stand now.
182
- const standing = async (harbor) => {
183
- const { wards, failed } = await census(harbor);
184
- return Object.keys(wards).filter((ward) => !Object.hasOwn(failed.wards, ward));
185
- };
186
- // A harbor of the world whose catalogue runs the law's module.
187
- export const standOne = async (world, name, t, parts = {}) => {
188
- const harbor = await world.harbor(name, on(t, parts));
189
- await catalogue(harbor, 'add', { source: LAW });
190
- return harbor;
191
- };
192
- const CATALOGUE = { catalogue: { class: 'org.nervur.catalogue', public: false, absent: false } };
193
- const NONE = { wards: {}, routes: {} };
194
- // The places of a root memory the wards keep, the DNA's left out.
195
- const wardPlaces = async (memory) => (await memory.places()).filter((p) => !Dna.occupies(p));
196
- const utf8 = (text) => new TextEncoder().encode(text);
197
- const holds = (bytes, part) => {
198
- outer: for (let at = 0; at + part.length <= bytes.length; at += 1) {
199
- for (let k = 0; k < part.length; k += 1)
200
- if (bytes[at + k] !== part[k])
201
- continue outer;
202
- return true;
203
- }
204
- return false;
205
- };
206
- const hex = (bytes) => [...bytes].map((b) => b.toString(16).padStart(2, '0')).join('');
207
- const drawn = () => hex(new CryptoEntropy().draw(32));
208
- const me = (world, method, args = {}) => being(world.get('home'), 'me', method, args, 'alice');
209
- const sold = async (harbor) => (await being(harbor, 'shop', 'sold', {}, 'shop')).sold;
210
- // Acme hosts a shop; home opens an echo, hosts alice and bob under the
211
- // seeds named, and alice takes the shop and lends the echo.
212
- const stand = async (world, t, bodies, seeds, expect) => {
213
- const acme = await standOne(world, 'acme', t, bodies.acme);
214
- const home = await standOne(world, 'home', t, bodies.home);
215
- expect.same(await standing(home), [], `${t.name}: a new harbor hosts nobody`);
216
- expect.same(await root(home, 'open', { key: 'echo', class: 'org.example.echo' }), { opened: 'echo' });
217
- expect.same(await root(home, 'host', { ward: 'alice', seed: seeds.alice }), { hosted: 'alice' });
218
- expect.same(await root(home, 'host', { ward: 'bob', seed: seeds.bob }), { hosted: 'bob' });
219
- expect.same(await root(home, 'boot', { key: 'me', class: 'org.example.customer' }, 'alice'), { booted: 'me' });
220
- expect.same(await root(acme, 'host', { ward: 'shop' }), { hosted: 'shop' });
221
- expect.same(await root(acme, 'boot', { key: 'shop', class: 'org.example.shop' }, 'shop'), { booted: 'shop' });
222
- const invitation = (await root(acme, 'invite', { being: 'shop', id: 'alice' }, 'shop'));
223
- expect.same(await me(world, 'join', { invitation }), { joined: 'shop' });
224
- expect.same(await me(world, 'buy', { item: 'tea' }), { said: { bought: 'tea' } });
225
- expect.same(await me(world, 'echo', { text: 'hi' }), { said: { echoed: 'hi', to: 'lent:1' } });
226
- };
227
- // A loader that runs every source but one module's, which it refuses.
228
- class Refusing extends Loader {
229
- #inner;
230
- #module;
231
- constructor(inner, module) {
232
- super();
233
- this.#inner = inner;
234
- this.#module = module;
235
- }
236
- load(source, id) {
237
- if (source.includes(`'${this.#module}'`))
238
- return Promise.reject(new Error(`${this.#module} is refused here`));
239
- return this.#inner.load(source, id);
240
- }
241
- }
242
- export const lawScenes = (t, expect) => [
243
- [
244
- `law on ${t.name}: empty memory unpacks a box ward holding the dock and her catalogue, live an empty commit, and it wakes the same`,
245
- async () => {
246
- const bodies = t.make();
247
- const world = new World(t.defaults);
248
- const harbor = await world.harbor('h', on(t, bodies));
249
- const { pk } = await census(harbor);
250
- const empty = { pk, class: t.defaults.dock.kind, beings: CATALOGUE, wards: {}, routes: {}, reach: [], failed: NONE, listening: [] };
251
- expect.same(await census(harbor), empty);
252
- const live = (await catalogue(harbor, 'live')).live;
253
- const log = (await catalogue(harbor, 'log')).log;
254
- expect.same(log.map(({ commit, parents, message }) => ({ commit, parents, message })), [{ commit: live, parents: [], message: 'genesis' }]);
255
- const again = await world.restart('h', t.again(bodies));
256
- expect.same(await census(again), empty, 'the seed is the box ward');
257
- expect.same(await catalogue(again, 'live'), { live }, 'a wake stands live again');
258
- },
259
- ],
260
- [
261
- `law on ${t.name}: a restart whose loader does not run a module live holds stands, its beings absent, and wakes them when it runs again`,
262
- async () => {
263
- const bodies = t.make();
264
- const world = new World(t.defaults);
265
- const harbor = await standOne(world, 'h', t, bodies);
266
- expect.same(await root(harbor, 'open', { key: 'echo', class: 'org.example.echo' }), { opened: 'echo' });
267
- expect.same(await root(harbor, 'host', { ward: 'w' }), { hosted: 'w' });
268
- const { live } = await catalogue(harbor, 'live');
269
- const id = await idOf(blob(LAW));
270
- const lost = await world.restart('h', { ...t.again(bodies), loader: new BundleLoader([]) });
271
- expect.same(await standing(lost), ['w'], 'the rest of the harbor stands');
272
- expect.same((await census(lost)).beings.echo?.absent, true);
273
- expect.same(await catalogue(lost, 'modules'), {
274
- live,
275
- modules: { [law.module]: { running: null, blob: id, failed: `redeploy needed: blob ${id} is no module this bundle carries, and it carries none` } },
276
- });
277
- const again = await world.restart('h', { ...t.again(bodies), loader: loaderOf(t) });
278
- expect.same((await census(again)).beings.echo?.absent, false);
279
- expect.same(await catalogue(again, 'modules'), { live, modules: { [law.module]: { running: '1', blob: id } } });
280
- },
281
- ],
282
- [
283
- `law on ${t.name}: a module that does not load is removed only once no being stands on the kinds of its domain`,
284
- async () => {
285
- const bodies = t.make();
286
- const world = new World(t.defaults);
287
- const harbor = await standOne(world, 'h', t, bodies);
288
- expect.same(await root(harbor, 'open', { key: 'echo', class: 'org.example.echo' }), { opened: 'echo' });
289
- const lost = await world.restart('h', { ...t.again(bodies), loader: new BundleLoader([]) });
290
- const remove = () => catalogue(lost, 'remove', { module: law.module });
291
- expect.same(await remove(), { error: 'a being stands on this module' });
292
- expect.same(await root(lost, 'unboot', { being: 'echo' }), { unbooted: 'echo' });
293
- const removed = await remove();
294
- expect.equal(removed.removed, law.module);
295
- const after = await world.restart('h', t.again(bodies));
296
- expect.same(await catalogue(after, 'modules'), { live: removed.live, modules: {} });
297
- },
298
- ],
299
- [
300
- `law on ${t.name}: a restart where one module does not load runs the others, and the one alone stays out`,
301
- async () => {
302
- const bodies = t.make();
303
- const world = new World(t.defaults);
304
- const harbor = await standOne(world, 'h', t, bodies);
305
- expect.equal((await catalogue(harbor, 'add', { source: TWIN })).added, 'org.example.twin');
306
- expect.same(await root(harbor, 'open', { key: 'echo', class: 'org.example.echo' }), { opened: 'echo' });
307
- const split = await world.restart('h', { ...t.again(bodies), loader: new Refusing(loaderOf(t), 'org.example.twin') });
308
- expect.same((await census(split)).beings.echo?.absent, false, 'the module beside it runs');
309
- const { modules } = (await catalogue(split, 'modules'));
310
- expect.same([modules[law.module]?.running, modules['org.example.twin']?.running], ['1', null]);
311
- expect.equal(modules['org.example.twin']?.failed, 'org.example.twin is refused here');
312
- },
313
- ],
314
- [
315
- `law on ${t.name}: a hosted ward whose place does not open fails alone, and a box ward whose place does not open fails the harbor`,
316
- async () => {
317
- const bodies = t.make();
318
- const watched = new Watched(bodies.memory);
319
- const world = new World(t.defaults);
320
- const harbor = await standOne(world, 'h', t, { custody: bodies.custody, memory: watched });
321
- expect.same(await root(harbor, 'host', { ward: 'good' }), { hosted: 'good' });
322
- const from = watched.seen.length;
323
- expect.same(await root(harbor, 'host', { ward: 'bad' }), { hosted: 'bad' });
324
- const box = watched.seen[0].place;
325
- const bad = watched.seen.slice(from).find((s) => s.place !== box).place;
326
- const spoil = async (place) => {
327
- const [[name, bytes]] = [...(await watched.inner.read(place))];
328
- const changed = bytes.slice();
329
- changed[0] = changed[0] ^ 1;
330
- await watched.inner.write(place, new Map([[name, changed]]));
331
- };
332
- await spoil(bad);
333
- const again = await world.restart('h', t.again(bodies));
334
- expect.same(await standing(again), ['good']);
335
- expect.same((await census(again)).failed, { wards: { bad: 'an entry the package did not seal' }, routes: {} });
336
- expect.same(await again.ask({ ward: 'bad' }), { error: 'the ward did not stand', reason: 'an entry the package did not seal' });
337
- expect.same(await root(again, 'host', { ward: 'bad' }), { error: 'bad is hosted already' }, 'its name and seed stay kept');
338
- await spoil(box);
339
- let refused = '';
340
- await world.restart('h', t.again(bodies)).catch((e) => (refused = e.message));
341
- expect.equal(refused, 'an entry the package did not seal');
342
- },
343
- ],
344
- [
345
- `law on ${t.name}: a package carried to another memory stands the same harbor, its DNA with it, under the same seed`,
346
- async () => {
347
- const here = t.make();
348
- const there = t.make();
349
- const world = new World(t.defaults);
350
- const harbor = await standOne(world, 'here', t, here);
351
- expect.same(await root(harbor, 'open', { key: 'echo', class: 'org.example.echo' }), { opened: 'echo' });
352
- expect.same(await root(harbor, 'host', { ward: 'alice' }), { hosted: 'alice' });
353
- expect.same(await root(harbor, 'boot', { key: 'me', class: 'org.example.customer' }, 'alice'), { booted: 'me' });
354
- const pks = { box: (await census(harbor)).pk, alice: (await census(harbor, 'alice')).pk };
355
- const carried = await copyPackage(here.memory, there.memory);
356
- expect.equal(carried.filter((p) => !Dna.occupies(p)).length, 2, 'the box ward and alice, beside the DNA');
357
- const moved = await world.harbor('there', on(t, { custody: here.custody, memory: there.memory }));
358
- expect.same({ box: (await census(moved)).pk, alice: (await census(moved, 'alice')).pk }, pks);
359
- expect.same(await catalogue(moved, 'live'), await catalogue(harbor, 'live'));
360
- expect.same((await census(moved, 'alice')).beings, { me: { class: 'org.example.customer', public: false, absent: false } });
361
- expect.same(await being(moved, 'me', 'echo', { text: 'moved' }, 'alice'), { said: { echoed: 'moved', to: 'lent:1' } });
362
- const stranger = await world.harbor('stranger', on(t, { custody: t.make().custody, memory: there.memory }));
363
- expect.same(await standing(stranger), [], 'the bytes carried say nothing without the seed');
364
- },
365
- ],
366
- [
367
- `law on ${t.name}: the root sweeps every place the dock does not name, and nothing it does, the DNA's among them`,
368
- async () => {
369
- const bodies = t.make();
370
- const world = new World(t.defaults);
371
- const harbor = await standOne(world, 'h', t, bodies);
372
- expect.same(await root(harbor, 'host', { ward: 'w' }), { hosted: 'w' });
373
- const mine = (await bodies.memory.places()).sort();
374
- expect.equal((await wardPlaces(bodies.memory)).length, 2, 'the box ward and the ward it hosts');
375
- await bodies.memory.write('ff'.repeat(16), new Map([['ab', new Uint8Array([1, 2, 3])]]));
376
- expect.same(await root(harbor, 'sweep'), { swept: ['ff'.repeat(16)] });
377
- expect.same((await bodies.memory.places()).sort(), mine, 'what the dock names stays');
378
- expect.same(await root(harbor, 'sweep'), { swept: [] });
379
- const again = await world.restart('h', t.again(bodies));
380
- expect.same(await standing(again), ['w']);
381
- expect.same(await root(again, 'boot', { key: 'me', class: 'org.example.customer' }, 'w'), { booted: 'me' });
382
- },
383
- ],
384
- [
385
- `law on ${t.name}: a restart stands the dock, its faculties, every hosted ward and its beings, and lends, with nobody asking`,
386
- async () => {
387
- const bodies = { acme: t.make(), home: t.make() };
388
- const world = new World(t.defaults);
389
- await stand(world, t, bodies, { alice: drawn(), bob: drawn() }, expect);
390
- const pksOf = async (home, acme) => ({ box: (await census(home)).pk, alice: (await census(home, 'alice')).pk, bob: (await census(home, 'bob')).pk, shop: (await census(acme, 'shop')).pk });
391
- const pks = await pksOf(world.get('home'), world.get('acme'));
392
- const beings = await census(world.get('home'), 'alice');
393
- const home = await world.restart('home', t.again(bodies.home));
394
- const acme = await world.restart('acme', t.again(bodies.acme));
395
- expect.same(await standing(home), ['alice', 'bob']);
396
- expect.same(await standing(acme), ['shop']);
397
- expect.same(await pksOf(home, acme), pks);
398
- expect.same(await census(home, 'alice'), beings);
399
- expect.equal((await census(home)).beings.echo?.class, 'org.example.echo');
400
- expect.same(await me(world, 'buy', { item: 'cake' }), { said: { bought: 'cake' } });
401
- expect.same(await me(world, 'echo', { text: 'again' }), { said: { echoed: 'again', to: 'lent:1' } });
402
- expect.same(await sold(acme), ['tea to alice', 'cake to alice']);
403
- },
404
- ],
405
- [
406
- `law on ${t.name}: the dock holds a far ward and a far being under two names, and pilots each after a restart`,
407
- async () => {
408
- const bodies = { acme: t.make(), home: t.make() };
409
- const world = new World(t.defaults);
410
- const acme = await standOne(world, 'acme', t, bodies.acme);
411
- const home = await standOne(world, 'home', t, bodies.home);
412
- expect.same(await root(acme, 'host', { ward: 'shop' }), { hosted: 'shop' });
413
- expect.same(await root(acme, 'boot', { key: 'shop', class: 'org.example.shop' }, 'shop'), { booted: 'shop' });
414
- const onShop = (await root(acme, 'invite', { being: 'shop', id: 'home', notes: { owner: true } }, 'shop'));
415
- const onAcme = (await root(acme, 'own', { id: 'home' }));
416
- expect.same(await root(home, 'hold', { name: 'shop', invitation: onShop }), { held: 'shop', ward: (await census(acme, 'shop')).pk });
417
- expect.same(await root(home, 'hold', { name: 'acme', invitation: onAcme }), { held: 'acme', ward: (await census(acme)).pk });
418
- const again = await world.restart('home', t.again(bodies.home));
419
- expect.same(await root(again, 'pilot', { name: 'shop', method: 'buy', args: { item: 'tea' } }), { answer: { bought: 'tea' } });
420
- expect.same(await root(again, 'pilot', { name: 'acme', method: 'host', args: { ward: 'deli' } }), { answer: { hosted: 'deli' } });
421
- expect.same(await sold(acme), ['tea to home']);
422
- expect.same(await root(again, 'drop', { name: 'shop' }), { dropped: 'shop' });
423
- expect.same(await root(again, 'pilot', { name: 'shop' }), { error: 'shop is not held' });
424
- },
425
- ],
426
- [
427
- `law on ${t.name}: every root ask is a step a restart may follow, and each step wakes whole`,
428
- async () => {
429
- const bodies = t.make();
430
- const world = new World(t.defaults);
431
- await world.harbor('h', on(t, bodies));
432
- const step = async (ask, want) => {
433
- expect.same(await ask(world.get('h')), want);
434
- return world.restart('h', t.again(bodies));
435
- };
436
- await step(async (h) => {
437
- const { added, version } = await catalogue(h, 'add', { source: LAW });
438
- return { added, version };
439
- }, { added: law.module, version: law.version });
440
- await step((h) => root(h, 'open', { key: 'echo', class: 'org.example.echo' }), { opened: 'echo' });
441
- await step((h) => root(h, 'host', { ward: 'alice' }), { hosted: 'alice' });
442
- await step((h) => root(h, 'boot', { key: 'me', class: 'org.example.customer' }, 'alice'), { booted: 'me' });
443
- const h = await step((x) => being(x, 'me', 'echo', { text: 'one' }, 'alice'), { said: { echoed: 'one', to: 'lent:1' } });
444
- expect.same(await being(h, 'me', 'echo', { text: 'two' }, 'alice'), { said: { echoed: 'two', to: 'lent:1' } });
445
- },
446
- ],
447
- [
448
- `law on ${t.name}: a ward and the dock that become a module's class stand so again after a restart, the dock once the catalogue wakes`,
449
- async () => {
450
- const bodies = t.make();
451
- const world = new World(t.defaults);
452
- const harbor = await standOne(world, 'h', t, bodies);
453
- expect.same(await root(harbor, 'open', { key: 'echo', class: 'org.example.echo' }), { opened: 'echo' });
454
- expect.same(await root(harbor, 'host', { ward: 'alice' }), { hosted: 'alice' });
455
- expect.same(await root(harbor, 'become', { class: STEWARD }, 'alice'), { became: STEWARD });
456
- expect.same(await root(harbor, 'become', { class: QUAY }), { became: QUAY });
457
- const again = await world.restart('h', t.again(bodies));
458
- expect.same(await root(again, 'sign', undefined, 'alice'), { signed: (await census(again, 'alice')).pk });
459
- expect.same(await root(again, 'moor'), { moored: ['alice'] });
460
- expect.same((await census(again)).failed, NONE);
461
- expect.same(await root(again, 'boot', { key: 'me', class: 'org.example.customer' }, 'alice'), { booted: 'me' });
462
- expect.same(await being(again, 'me', 'echo', { text: 'hi' }, 'alice'), { said: { echoed: 'hi', to: 'lent:1' } }, 'the quay lends');
463
- },
464
- ],
465
- [
466
- `law on ${t.name}: the terrain keeps the seed and sealed bytes, and reads no name, cell, hosted seed or code`,
467
- async () => {
468
- const home = t.make();
469
- const watched = new Watched(home.memory);
470
- const world = new World(t.defaults);
471
- const seeds = { alice: drawn(), bob: drawn() };
472
- await stand(world, t, { acme: t.make(), home: { custody: home.custody, memory: watched } }, seeds, expect);
473
- const secrets = [seeds.alice, seeds.bob].map(utf8);
474
- // Names of five bytes or more: a shorter one turns up in random bytes
475
- // of this size often enough to fail a run by chance.
476
- const words = ['alice', 'org.example', 'hosted', 'lent:1', 'customer', 'nervur', 'modules', 'genesis'].map(utf8);
477
- expect.ok(watched.seen.length > 0, 'the harbor kept something');
478
- for (const { place, name, bytes } of watched.seen) {
479
- expect.ok(/^[0-9a-f]+$/.test(place) && /^[0-9a-f]+$/.test(name), 'names are the kit hex');
480
- if (bytes === null)
481
- continue;
482
- for (const secret of secrets)
483
- expect.ok(!holds(bytes, secret), 'no hosted seed in the clear');
484
- for (const word of words)
485
- expect.ok(!holds(bytes, word), 'no name, cell or code in the clear');
486
- expect.ok(!holds(bytes, await home.custody.seed()), 'no harbor seed in memory');
487
- }
488
- },
489
- ],
490
- [
491
- `law on ${t.name}: another seed finds nothing of the package, and a byte changed refuses to unpack`,
492
- async () => {
493
- const bodies = t.make();
494
- const watched = new Watched(bodies.memory);
495
- const world = new World(t.defaults);
496
- const harbor = await standOne(world, 'h', t, { custody: bodies.custody, memory: watched });
497
- expect.same(await root(harbor, 'host', { ward: 'w' }), { hosted: 'w' });
498
- const last = [...watched.seen].reverse().find((s) => s.bytes !== null && s.bytes.length > 0);
499
- const stranger = await world.harbor('stranger', on(t, { custody: t.make().custody, memory: watched }));
500
- expect.same(await standing(stranger), [], 'another seed opens another package');
501
- const bytes = last.bytes.slice();
502
- bytes[0] = bytes[0] ^ 1;
503
- await watched.inner.write(last.place, new Map([[last.name, bytes]]));
504
- let refused = false;
505
- await world.restart('h', t.again(bodies)).catch(() => (refused = true));
506
- expect.ok(refused, 'a changed byte does not unpack');
507
- },
508
- ],
509
- ];
510
- const keepersOf = (t) => {
511
- const ground = t.defaults.classes.find((C) => C.prototype instanceof MemoryFaculty);
512
- if (!ground)
513
- throw new Error('the keeper scenes need defaults that bring a memory faculty');
514
- return [{ name: 'the root memory' }, { name: 'a memory faculty of the terrain', memory: 'vault', kind: ground.kind, ground: true }, { name: 'a memory faculty of a module', memory: 'shelf', kind: SHELF }];
515
- };
516
- const onKeeper = (k) => (k.memory === undefined ? {} : { memory: k.memory });
517
- // A place of the package is thirty-two hex digits, and one a memory
518
- // faculty of the terrain keeps is longer.
519
- const PLACE = 32;
520
- // The keeper opened in the box ward, where it is a memory faculty.
521
- const openKeeper = async (harbor, k, expect) => {
522
- if (k.memory !== undefined)
523
- expect.same(await root(harbor, 'open', { key: k.memory, class: k.kind }), { opened: k.memory });
524
- };
525
- const profile = (harbor, method, args = {}) => being(harbor, 'me', method, args, 'ana');
526
- // Acme's shop kept by `k`, home's alice on the root memory, joined, and
527
- // every box that reaches the shop's door seen.
528
- const shopOn = async (world, t, k, expect) => {
529
- const bodies = { acme: t.make(), home: t.make() };
530
- const acme = await standOne(world, 'acme', t, bodies.acme);
531
- const home = await standOne(world, 'home', t, bodies.home);
532
- await openKeeper(acme, k, expect);
533
- expect.same(await root(acme, 'host', { ward: 'shop', ...onKeeper(k) }), { hosted: 'shop' });
534
- expect.same(await root(acme, 'boot', { key: 'shop', class: 'org.example.shop' }, 'shop'), { booted: 'shop' });
535
- expect.same(await root(home, 'host', { ward: 'alice' }), { hosted: 'alice' });
536
- expect.same(await root(home, 'boot', { key: 'me', class: 'org.example.customer' }, 'alice'), { booted: 'me' });
537
- const invitation = (await root(acme, 'invite', { being: 'shop', id: 'alice' }, 'shop'));
538
- const shop = (await census(acme, 'shop')).pk;
539
- const boxes = [];
540
- const carry = world.carry.bind(world);
541
- world.carry = (pk, bytes) => {
542
- if (pk === shop)
543
- boxes.push(bytes.slice());
544
- return carry(pk, bytes);
545
- };
546
- expect.same(await me(world, 'join', { invitation }), { joined: 'shop' });
547
- return { acme: bodies.acme, boxes, shop };
548
- };
549
- // A cell is a being's field made durable, whoever keeps it: the law's
550
- // scenes of a being's fields, run over every keeper a hosted ward's place
551
- // may live with.
552
- export const keeperScenes = (t, expect) => [
553
- ...keepersOf(t).flatMap((k) => [
554
- [
555
- `law on ${t.name}: a being's fields kept by ${k.name} come back at wake, sealed, where that keeper alone holds them`,
556
- async () => {
557
- shelves.clear();
558
- const bodies = t.make();
559
- const watched = new Watched(bodies.memory);
560
- const world = new World(t.defaults);
561
- const harbor = await standOne(world, 'h', t, { custody: bodies.custody, memory: watched });
562
- await openKeeper(harbor, k, expect);
563
- expect.same(await root(harbor, 'host', { ward: 'ana', ...onKeeper(k) }), { hosted: 'ana' });
564
- expect.same(await root(harbor, 'boot', { key: 'me', class: PROFILE }, 'ana'), { booted: 'me' });
565
- expect.same(await profile(harbor, 'set', { name: 'Anastasia', age: 31 }), { name: 'Anastasia', age: 31 });
566
- const again = await world.restart('h', t.again(bodies));
567
- expect.same(await profile(again, 'get'), { name: 'Anastasia', age: 31 });
568
- expect.same((await census(again)).failed, NONE);
569
- const places = await wardPlaces(bodies.memory);
570
- const shelf = await shelfOf('shelf').places();
571
- if (k.memory === undefined)
572
- expect.same([places.length, shelf.length], [2, 0], 'the box ward and ana, on the root memory');
573
- else if (k.ground)
574
- expect.same([places.length, places.filter((p) => p.length > PLACE).length, shelf.length], [2, 1, 0], 'ana behind the memory faculty of the terrain');
575
- else
576
- expect.same([places.length, shelf.length], [1, 1], 'the box ward on the root memory, ana on the shelf');
577
- const seen = [...watched.seen, ...shelfOf('shelf').seen];
578
- for (const { bytes } of seen) {
579
- if (bytes === null)
580
- continue;
581
- for (const word of ['Anastasia', 'org.example', 'vault'].map(utf8))
582
- expect.ok(!holds(bytes, word), 'no field, kind or key in the clear');
583
- }
584
- },
585
- ],
586
- [
587
- `law on ${t.name}: an answer whose keep ${k.name} refuses is silence, and the being keeps what she had`,
588
- async () => {
589
- shelves.clear();
590
- const bodies = t.make();
591
- const watched = new Watched(bodies.memory);
592
- const world = new World(t.defaults);
593
- const harbor = await standOne(world, 'h', t, { custody: bodies.custody, memory: watched });
594
- const box = watched.seen[0].place;
595
- await openKeeper(harbor, k, expect);
596
- expect.same(await root(harbor, 'host', { ward: 'ana', ...onKeeper(k) }), { hosted: 'ana' });
597
- expect.same(await root(harbor, 'boot', { key: 'me', class: PROFILE }, 'ana'), { booted: 'me' });
598
- expect.same(await profile(harbor, 'set', { age: 31 }), { name: '', age: 31 });
599
- // Only the keeper named refuses, so a keep that went elsewhere
600
- // would answer.
601
- if (k.memory === undefined)
602
- watched.refuse = (place) => place !== box;
603
- else if (k.ground)
604
- watched.refuse = (place) => place.length > box.length;
605
- else
606
- shelfOf('shelf').refuse = () => true;
607
- expect.ok(JSON.stringify(await profile(harbor, 'set', { age: 32 })) !== JSON.stringify({ name: '', age: 32 }), 'no answer leaves an unkept keep');
608
- watched.refuse = () => false;
609
- shelfOf('shelf').refuse = () => false;
610
- expect.same(await profile(harbor, 'get'), { name: '', age: 31 }, 'what she wrote is put back');
611
- const again = await world.restart('h', t.again(bodies));
612
- expect.same(await profile(again, 'get'), { name: '', age: 31 });
613
- expect.same(await profile(again, 'set', { age: 32 }), { name: '', age: 32 });
614
- },
615
- ],
616
- [
617
- `law on ${t.name}: the door's keys and the being's cells are one keep with ${k.name}, so a box replayed after a wake is answered once`,
618
- async () => {
619
- shelves.clear();
620
- const world = new World(t.defaults);
621
- const { acme, boxes, shop } = await shopOn(world, t, k, expect);
622
- const from = boxes.length;
623
- expect.same(await me(world, 'buy', { item: 'tea' }), { said: { bought: 'tea' } });
624
- const replayed = boxes.slice(from);
625
- expect.ok(replayed.length > 0, 'the buy crossed the door');
626
- const again = await world.restart('acme', t.again(acme));
627
- expect.same(await sold(again), ['tea to alice']);
628
- for (const bytes of replayed)
629
- await again.arrive(shop, bytes);
630
- expect.same(await sold(again), ['tea to alice'], 'a replayed box does not buy again');
631
- expect.same(await me(world, 'buy', { item: 'cake' }), { said: { bought: 'cake' } });
632
- expect.same(await sold(world.get('acme')), ['tea to alice', 'cake to alice']);
633
- },
634
- ],
635
- ]),
636
- [
637
- `law on ${t.name}: a ward whose memory faculty does not stand at wake fails alone, and stands whole once it returns`,
638
- async () => {
639
- shelves.clear();
640
- const bodies = t.make();
641
- const world = new World(t.defaults);
642
- const harbor = await standOne(world, 'h', t, bodies);
643
- await openKeeper(harbor, keepersOf(t)[2], expect);
644
- expect.same(await root(harbor, 'host', { ward: 'ana', memory: 'shelf' }), { hosted: 'ana' });
645
- expect.same(await root(harbor, 'host', { ward: 'bea' }), { hosted: 'bea' });
646
- expect.same(await root(harbor, 'boot', { key: 'me', class: PROFILE }, 'ana'), { booted: 'me' });
647
- expect.same(await profile(harbor, 'set', { age: 31 }), { name: '', age: 31 });
648
- const lost = await world.restart('h', { ...t.again(bodies), loader: new BundleLoader([]) });
649
- expect.same(await standing(lost), ['bea'], 'the root and its own ward stand');
650
- expect.same((await census(lost)).failed, { wards: { ana: 'the memory faculty shelf does not stand' }, routes: {} });
651
- const back = await world.restart('h', { ...t.again(bodies), loader: loaderOf(t) });
652
- expect.same(await standing(back), ['ana', 'bea']);
653
- expect.same(await profile(back, 'get'), { name: '', age: 31 });
654
- },
655
- ],
656
- [
657
- `law on ${t.name}: a ward carried between keepers keeps its fields, its door and its key, and leaves nothing where it was`,
658
- async () => {
659
- shelves.clear();
660
- const world = new World(t.defaults);
661
- const { acme, shop } = await shopOn(world, t, keepersOf(t)[0], expect);
662
- const harbor = world.get('acme');
663
- for (const k of keepersOf(t).slice(1))
664
- await openKeeper(harbor, k, expect);
665
- const items = ['tea', 'cake', 'bread', 'milk'];
666
- // The wards the root memory keeps, the places the terrain's memory
667
- // faculty keeps in it, and the shelf's.
668
- const counts = async () => {
669
- const places = await wardPlaces(acme.memory);
670
- return [places.filter((p) => p.length === PLACE).length, places.filter((p) => p.length > PLACE).length, (await shelfOf('shelf').places()).length];
671
- };
672
- expect.same(await me(world, 'buy', { item: items[0] }), { said: { bought: items[0] } });
673
- const road = [
674
- [keepersOf(t)[1], [1, 1, 0]],
675
- [keepersOf(t)[2], [1, 0, 1]],
676
- [keepersOf(t)[0], [2, 0, 0]],
677
- ];
678
- for (const [i, [k, want]] of road.entries()) {
679
- expect.same(await root(world.get('acme'), 'move', { ward: 'shop', memory: k.memory ?? null }), { moved: 'shop', memory: k.memory ?? null });
680
- expect.same(await counts(), want, `only ${k.name} holds the shop`);
681
- const again = await world.restart('acme', t.again(acme));
682
- expect.equal((await census(again, 'shop')).pk, shop, 'the key moves with the ward');
683
- expect.same(await me(world, 'buy', { item: items[i + 1] }), { said: { bought: items[i + 1] } });
684
- expect.same(await sold(again), items.slice(0, i + 2).map((item) => `${item} to alice`));
685
- }
686
- expect.same(await root(world.get('acme'), 'move', { ward: 'shop', memory: null }), { error: 'shop is kept there already' });
687
- expect.same(await root(world.get('acme'), 'move', { ward: 'shop', memory: 'echo' }), { error: 'no such memory faculty' });
688
- },
689
- ],
690
- [
691
- `law on ${t.name}: a memory faculty keeping a ward does not go, and the root sweeps what no keeper is named for`,
692
- async () => {
693
- shelves.clear();
694
- const bodies = t.make();
695
- const world = new World(t.defaults);
696
- const harbor = await standOne(world, 'h', t, bodies);
697
- for (const k of keepersOf(t).slice(1))
698
- await openKeeper(harbor, k, expect);
699
- expect.same(await root(harbor, 'host', { ward: 'ana', memory: 'vault' }), { hosted: 'ana' });
700
- expect.same(await root(harbor, 'host', { ward: 'bea', memory: 'shelf' }), { hosted: 'bea' });
701
- expect.same(await root(harbor, 'host', { ward: 'cy', memory: 'nothing' }), { error: 'no such memory faculty' });
702
- expect.same(await root(harbor, 'unboot', { being: 'vault' }), { error: 'a ward is kept by this memory faculty' });
703
- const before = [(await bodies.memory.places()).sort(), await shelfOf('shelf').places()];
704
- const stray = 'ee'.repeat(16);
705
- await bodies.memory.write(stray, new Map([['ab', new Uint8Array([1])]]));
706
- await shelfOf('shelf').write(stray, new Map([['ab', new Uint8Array([2])]]));
707
- expect.same(await root(harbor, 'sweep'), { swept: [stray, stray] });
708
- expect.same([(await bodies.memory.places()).sort(), await shelfOf('shelf').places()], before, 'what the dock names stays');
709
- expect.same(await root(harbor, 'move', { ward: 'bea', memory: null }), { moved: 'bea', memory: null });
710
- expect.same(await root(harbor, 'unboot', { being: 'shelf' }), { unbooted: 'shelf' });
711
- const again = await world.restart('h', t.again(bodies));
712
- expect.same(await standing(again), ['ana', 'bea']);
713
- },
714
- ],
715
- ];