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,101 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // The two native bodies of a phone's ground, over what the shell hands in.
3
+ // The shell's secret store is the iOS Keychain or the Android Keystore, and
4
+ // its store is a native file or database the operating system never
5
+ // evicts. The library holds the contracts' logic here; a shell holds only
6
+ // the two small interfaces below, in its own native code.
7
+ import { SeedKeys } from '../bodies/seed-keys.js';
8
+ const NAME = /^[a-z0-9][a-z0-9._-]{0,63}$/;
9
+ const SEED = /^[0-9a-f]{64}$/;
10
+ const hex = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('');
11
+ const bytes = (text) => new Uint8Array(text.match(/../g)?.map((pair) => parseInt(pair, 16)) ?? []);
12
+ /** One seed for each house in the platform's secret store, drawn on first use. */
13
+ export class NativeCustody {
14
+ #secrets;
15
+ #turn = Promise.resolve();
16
+ constructor(secrets) {
17
+ this.#secrets = secrets;
18
+ }
19
+ keys({ house }) {
20
+ if (!NAME.test(house))
21
+ return Promise.reject(new TypeError(`no house is named ${house}`));
22
+ // One seed is drawn at a time, so two first uses of a house never draw two.
23
+ const turn = this.#turn.then(async () => {
24
+ const name = `nervur.seed.${house}`;
25
+ let seed = await this.#secrets.get(name);
26
+ if (seed === null) {
27
+ seed = hex(crypto.getRandomValues(new Uint8Array(32)));
28
+ await this.#secrets.set(name, seed);
29
+ }
30
+ if (!SEED.test(seed))
31
+ throw new Error(`the seed of ${house} is not sixty-four hex digits`);
32
+ return new SeedKeys(seed);
33
+ });
34
+ this.#turn = turn.catch(() => undefined);
35
+ return turn;
36
+ }
37
+ }
38
+ /**
39
+ * Memory over a native store, one memory for each name. Each place is one
40
+ * key, its entries as hex beside its version. Versions come from one
41
+ * counter for the memory, so a place removed and written again never
42
+ * shows a version it showed before. A write reads every place it names
43
+ * and swaps them all against what it read.
44
+ */
45
+ export class NativeMemory {
46
+ #store;
47
+ #prefix;
48
+ constructor(store, name) {
49
+ if (!NAME.test(name))
50
+ throw new TypeError(`no memory is named ${name}`);
51
+ this.#store = store;
52
+ this.#prefix = `nervur/${name}/`;
53
+ }
54
+ #key(place) {
55
+ return `${this.#prefix}p/${place}`;
56
+ }
57
+ async read({ place }) {
58
+ const text = await this.#store.get(this.#key(place));
59
+ if (text === null)
60
+ return { entries: {}, version: null };
61
+ const held = JSON.parse(text);
62
+ return { entries: Object.fromEntries(Object.entries(held.e).map(([name, value]) => [name, bytes(value)])), version: String(held.v) };
63
+ }
64
+ async list() {
65
+ const places = `${this.#prefix}p/`;
66
+ return (await this.#store.keys(places)).map((key) => key.slice(places.length));
67
+ }
68
+ async write({ writes, expect, }) {
69
+ const places = [...new Set([...Object.keys(writes), ...Object.keys(expect)])];
70
+ const count = `${this.#prefix}count`;
71
+ const held = { [count]: await this.#store.get(count) };
72
+ for (const place of places)
73
+ held[this.#key(place)] = await this.#store.get(this.#key(place));
74
+ for (const place of places) {
75
+ const text = held[this.#key(place)];
76
+ const version = text === null ? null : String(JSON.parse(text).v);
77
+ if (!(place in expect) || expect[place] !== version)
78
+ return null;
79
+ }
80
+ let next = held[count] === null ? 0 : Number(held[count]);
81
+ const landing = {};
82
+ const versions = {};
83
+ for (const [place, entries] of Object.entries(writes)) {
84
+ const text = held[this.#key(place)];
85
+ const kept = { ...(text === null ? {} : JSON.parse(text).e) };
86
+ for (const [name, value] of Object.entries(entries)) {
87
+ if (value === null)
88
+ delete kept[name];
89
+ else
90
+ kept[name] = hex(value);
91
+ }
92
+ next += 1;
93
+ const empty = Object.keys(kept).length === 0;
94
+ landing[this.#key(place)] = empty ? null : JSON.stringify({ v: next, e: kept });
95
+ versions[place] = empty ? null : String(next);
96
+ }
97
+ landing[count] = String(next);
98
+ // What another writer moved since the read refuses the swap, as it would the versions.
99
+ return (await this.#store.swap(landing, held)) ? versions : null;
100
+ }
101
+ }
@@ -0,0 +1,229 @@
1
+ import type { MethodSpec, Need, BLUEPRINT } from './need.ts';
2
+ import type { Handle, Inbound, Infer, Invitation, Outbound } from './schema.ts';
3
+ /** A JSON value, as cells and notes hold. */
4
+ export type Json = null | boolean | number | string | readonly Json[] | {
5
+ readonly [key: string]: Json;
6
+ };
7
+ /** What a call outward carries: JSON, bytes, and the handles and invitations the callee's schema places. */
8
+ export type Passed = Json | Uint8Array | Handle | Invitation | readonly Passed[] | {
9
+ readonly [key: string]: Passed;
10
+ };
11
+ /** Notes on a relation. */
12
+ export type Notes = Readonly<Record<string, Json>>;
13
+ /** Where the house placed her. */
14
+ export type Position = 'steward' | 'public' | 'normal';
15
+ /** Who asks now. */
16
+ export interface Asker {
17
+ readonly id: string;
18
+ readonly notes: Notes;
19
+ readonly steward: Notes;
20
+ readonly signer?: Uint8Array;
21
+ }
22
+ /** What a role and her state read of her. */
23
+ export interface Me<C> {
24
+ readonly id: string;
25
+ readonly position: Position;
26
+ readonly cells: Readonly<C>;
27
+ }
28
+ type Names = string | readonly string[];
29
+ /** One example of an ask, run by the bench and nowhere else. */
30
+ export interface Example {
31
+ readonly description?: string;
32
+ readonly cells?: Json;
33
+ readonly role?: string;
34
+ readonly args?: Json;
35
+ readonly fakes?: Json;
36
+ readonly gives?: Json;
37
+ }
38
+ /** An ask's entry: the method's gate. */
39
+ export interface Entry extends MethodSpec {
40
+ readonly in?: Names;
41
+ readonly for?: Names;
42
+ readonly to?: Names;
43
+ readonly examples?: readonly Example[];
44
+ }
45
+ /** What a class declares. */
46
+ export interface Declaration<C = Record<string, Json>, N = Record<string, Need>, A = Record<string, Entry>> {
47
+ readonly kind: string;
48
+ readonly description?: string;
49
+ readonly cells?: C;
50
+ readonly needs?: N;
51
+ readonly roles?: Readonly<Record<string, (asker: Asker, me: Me<C>) => boolean>>;
52
+ readonly state?: (me: Me<C>) => string;
53
+ readonly asks: A;
54
+ /** Markup as text over her asks, which a screen renders. */
55
+ readonly view?: string;
56
+ }
57
+ /** A relation, with her notes and her steward's. */
58
+ export interface Relation {
59
+ readonly id: string;
60
+ readonly notes: Notes;
61
+ readonly steward: Notes;
62
+ }
63
+ type Resolved<S> = S extends {
64
+ readonly result: infer R;
65
+ } ? Inbound<Infer<R>> : null;
66
+ type Sent<S> = S extends {
67
+ readonly args: infer A;
68
+ } ? Outbound<Infer<A>> : Record<string, never>;
69
+ type IsAwaited<S> = S extends {
70
+ readonly hints: {
71
+ readonly idempotent: true;
72
+ };
73
+ } ? true : S extends {
74
+ readonly hints: {
75
+ readonly readOnly: true;
76
+ };
77
+ } ? true : false;
78
+ /** How she calls one method: awaited, or an effect answered through `reply`. */
79
+ type Given<S, O extends unknown[]> = {} extends Sent<S> ? [args?: Sent<S>, ...O] : [args: Sent<S>, ...O];
80
+ type IsReadOnly<S> = S extends {
81
+ readonly hints: {
82
+ readonly readOnly: true;
83
+ };
84
+ } ? true : false;
85
+ export type Call<S, R extends string> = IsReadOnly<S> extends true ? (...given: Given<S, [options?: {
86
+ after?: Resolved<S>;
87
+ }]>) => Promise<Resolved<S>> : IsAwaited<S> extends true ? (...given: Given<S, []>) => Promise<Resolved<S>> : (...given: Given<S, [options?: {
88
+ reply?: R;
89
+ }]>) => void;
90
+ /** The frozen face of a need: its methods and nothing else. */
91
+ export type Face<X, R extends string = string> = {
92
+ readonly [K in Exclude<keyof X, typeof BLUEPRINT>]: Call<X[K], R>;
93
+ };
94
+ /** A standing asked with no need matched, such as her steward. */
95
+ export type Untyped = Readonly<Record<string, (args?: Passed, options?: {
96
+ reply?: string;
97
+ }) => Promise<unknown> | void>>;
98
+ /** What `this.house` gives every being. */
99
+ export interface HouseReach<R extends string = string> {
100
+ now(): number;
101
+ random(options: {
102
+ length: number;
103
+ }): Uint8Array;
104
+ alarm(options: {
105
+ at: number;
106
+ ask: R;
107
+ args?: Json;
108
+ key: string;
109
+ }): void;
110
+ cancelAlarm(options: {
111
+ key: string;
112
+ }): void;
113
+ }
114
+ /** Her standings. */
115
+ export interface Standings {
116
+ list(): readonly Relation[];
117
+ note(id: string, notes: Notes): void;
118
+ drop(id: string): void;
119
+ }
120
+ /** Her occupants and handles. */
121
+ export interface Occupants {
122
+ list(): readonly Relation[];
123
+ note(id: string, notes: Notes): void;
124
+ dismiss(id: string): void;
125
+ }
126
+ /** The steward's six powers. */
127
+ export interface Powers {
128
+ /** A new occupant of another being, as a handle she may pass on. */
129
+ invite(options: {
130
+ id: string;
131
+ occupant: string;
132
+ notes?: Notes;
133
+ expires?: number;
134
+ }): Handle;
135
+ bear(options: {
136
+ kind: string;
137
+ id: string;
138
+ args?: Json;
139
+ }): void;
140
+ remove(options: {
141
+ id: string;
142
+ }): void;
143
+ /** Every being, her kind, whether she is absent, and the replies her table refused. */
144
+ list(): Promise<readonly {
145
+ id: string;
146
+ kind: string;
147
+ absent: boolean;
148
+ dead: readonly {
149
+ ask: string;
150
+ args: Json;
151
+ at: number;
152
+ why: string;
153
+ }[];
154
+ }[]>;
155
+ /** Her args may carry a handle she holds or an invitation she carries, as any call outward. */
156
+ ask(call: {
157
+ id: string;
158
+ method: string;
159
+ args?: Passed;
160
+ }, options?: {
161
+ reply?: string;
162
+ }): Promise<unknown> | void;
163
+ introduce(options: {
164
+ from: string;
165
+ to: string;
166
+ notes?: Notes;
167
+ }): void;
168
+ }
169
+ export declare const DECLARATION: unique symbol;
170
+ declare const ASKS: unique symbol;
171
+ /** The asks of a class, carried in its type alone. */
172
+ export interface Typed<A> {
173
+ readonly [ASKS]?: A;
174
+ }
175
+ type AskOf<T, K> = T extends Typed<infer A> ? (K extends keyof A ? A[K] : never) : never;
176
+ /** The args her method `K` receives. */
177
+ export type Args<T, K extends string> = AskOf<T, K> extends {
178
+ readonly args: infer S;
179
+ } ? Inbound<Infer<S>> : Record<string, never>;
180
+ /** What her method `K` answers. */
181
+ export type Result<T, K extends string> = AskOf<T, K> extends {
182
+ readonly result: infer S;
183
+ } ? Outbound<Infer<S>> : void;
184
+ /** What every being reaches. */
185
+ export declare abstract class Being<C = Record<string, Json>, R extends string = string> {
186
+ readonly id: string;
187
+ readonly position: Position;
188
+ readonly asker: Asker;
189
+ cells: C;
190
+ readonly house: HouseReach<R>;
191
+ readonly standings: Standings;
192
+ readonly occupants: Occupants;
193
+ /** Her steward, asked as a standing, where she is not one. */
194
+ readonly steward?: Untyped;
195
+ /** The house's powers, where she is the steward. */
196
+ readonly powers?: Powers;
197
+ /** A standing matched to a need. */
198
+ held: <X extends Need>(id: string, need: X) => Face<X, R>;
199
+ /**
200
+ * A handle to one of her asks. Each invitation it leaves as is spent within
201
+ * `expires` milliseconds of leaving, or never binds.
202
+ */
203
+ handle: (ask: R, options?: {
204
+ bind?: Json;
205
+ notes?: Notes;
206
+ once?: boolean;
207
+ expires?: number;
208
+ }) => Handle;
209
+ /** A new occupant, as a handle, with `expires` as `handle` has it. */
210
+ invite: (id: string, options?: {
211
+ notes?: Notes;
212
+ expires?: number;
213
+ }) => Handle;
214
+ /** Throws an error the asker can act on. */
215
+ fail: (message: string) => never;
216
+ /** A class, declared by one object. */
217
+ static of<C extends Record<string, Json> = Record<string, never>, const N extends Record<string, Need> = Record<never, never>, const A extends Record<string, Entry> = Record<string, Entry>>(declaration: Declaration<C, N, A>): BeingClass<C, N, A>;
218
+ }
219
+ /** What `Being.of` gives: a class to extend. */
220
+ export type BeingClass<C, N, A> = (abstract new () => Being<C, keyof A & string> & {
221
+ readonly [K in keyof N]: Face<N[K], keyof A & string>;
222
+ } & Typed<A>) & {
223
+ readonly [DECLARATION]: Declaration<C, N, A>;
224
+ };
225
+ /** The members of `Being` a class may not name. */
226
+ export declare const MEMBERS: ReadonlySet<string>;
227
+ /** The declaration a class carries, or nothing where it is no class of `Being.of`. */
228
+ export declare const declarationOf: (value: unknown) => Declaration | undefined;
229
+ export {};
@@ -0,0 +1,20 @@
1
+ export const DECLARATION = Symbol('declaration');
2
+ /** What every being reaches. */
3
+ export class Being {
4
+ /** A class, declared by one object. */
5
+ static of(declaration) {
6
+ // A class of her own, so the house reads her declaration from it.
7
+ class Declared extends Being {
8
+ static [DECLARATION] = declaration;
9
+ }
10
+ return Declared;
11
+ }
12
+ }
13
+ /** The members of `Being` a class may not name. */
14
+ export const MEMBERS = new Set(['id', 'position', 'asker', 'cells', 'house', 'standings', 'occupants', 'steward', 'powers', 'held', 'handle', 'invite', 'fail']);
15
+ /** The declaration a class carries, or nothing where it is no class of `Being.of`. */
16
+ export const declarationOf = (value) => {
17
+ if (typeof value !== 'function' || !(value.prototype instanceof Being))
18
+ return undefined;
19
+ return value[DECLARATION];
20
+ };
@@ -0,0 +1,9 @@
1
+ import type { Blueprint } from './need.ts';
2
+ /** Covered, or the first rule that fails, as a sentence. */
3
+ export type Cover = {
4
+ readonly covered: true;
5
+ } | {
6
+ readonly covered: false;
7
+ readonly why: string;
8
+ };
9
+ export declare const covers: (offer: Blueprint, want: Blueprint) => Cover;
@@ -0,0 +1,21 @@
1
+ const requiredOf = (schema) => {
2
+ const required = schema.required;
3
+ return Array.isArray(required) ? required : [];
4
+ };
5
+ export const covers = (offer, want) => {
6
+ if (offer.name !== want.name)
7
+ return { covered: false, why: `the offer is ${offer.name}, and the need is ${want.name}` };
8
+ for (const [name, wanted] of Object.entries(want.methods)) {
9
+ const offered = offer.methods[name];
10
+ if (offered === undefined)
11
+ return { covered: false, why: `${want.name} offers no ${name}` };
12
+ const sent = new Set(requiredOf(wanted.args));
13
+ const extra = requiredOf(offered.args).find((key) => !sent.has(key));
14
+ if (extra !== undefined)
15
+ return { covered: false, why: `${want.name}.${name} requires ${extra}, which the need does not send` };
16
+ if (offered.hints.idempotent !== wanted.hints.idempotent) {
17
+ return { covered: false, why: `${want.name}.${name} is idempotent in one and not the other` };
18
+ }
19
+ }
20
+ return { covered: true };
21
+ };
@@ -0,0 +1,3 @@
1
+ export { Being, type Args, type Result } from './being.ts';
2
+ export { need } from './need.ts';
3
+ export { s } from './schema.ts';
@@ -0,0 +1,5 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // `nervur/being`: what a being's author imports, and nothing else.
3
+ export { Being } from './being.js';
4
+ export { need } from './need.js';
5
+ export { s } from './schema.js';
@@ -0,0 +1,49 @@
1
+ import { type Schema } from './schema.ts';
2
+ /** The three hints an ask or a method may carry. */
3
+ export interface Hints {
4
+ readonly readOnly?: boolean;
5
+ readonly idempotent?: boolean;
6
+ readonly destructive?: boolean;
7
+ }
8
+ /** A method as its author writes it, in a need or in an ask's entry. */
9
+ export interface MethodSpec {
10
+ readonly args?: Schema;
11
+ readonly result?: Schema;
12
+ readonly hints?: Hints;
13
+ readonly description?: string;
14
+ /** How long an awaited caller waits for it, in milliseconds, within the bound. */
15
+ readonly wait?: number;
16
+ }
17
+ /** A method of a blueprint, every field settled. */
18
+ export interface BlueprintMethod {
19
+ readonly args: Schema;
20
+ readonly result?: Schema;
21
+ readonly hints: Required<Hints>;
22
+ readonly description?: string;
23
+ readonly wait: number;
24
+ }
25
+ /** An awaited call's wait where none is named, and the bound no wait passes. */
26
+ export declare const WAIT = 30000;
27
+ export declare const WAIT_BOUND = 300000;
28
+ /** The shape of what can be called: a name and its methods. */
29
+ export interface Blueprint {
30
+ readonly name: string;
31
+ readonly methods: Readonly<Record<string, BlueprintMethod>>;
32
+ }
33
+ export declare const BLUEPRINT: unique symbol;
34
+ /** A need: her methods by name, and the blueprint they make. */
35
+ export type Need<M extends Record<string, MethodSpec> = Record<string, MethodSpec>> = {
36
+ readonly [K in keyof M]: M[K];
37
+ } & {
38
+ readonly [BLUEPRINT]: Blueprint;
39
+ };
40
+ /** Whether a method is awaited: `readOnly` implies `idempotent`. */
41
+ export declare const awaited: (hints: Hints | undefined) => boolean;
42
+ /** Hints settled, `readOnly` carrying `idempotent` with it. */
43
+ export declare const settled: (hints: Hints | undefined) => Required<Hints>;
44
+ /** One method settled: the empty object where args are omitted. */
45
+ export declare const method: (spec: MethodSpec) => BlueprintMethod;
46
+ /** A blueprint at its minimum, under the name matching uses. */
47
+ export declare const need: <const M extends Record<string, MethodSpec>>(name: string, methods: M) => Need<M>;
48
+ /** The blueprint a need makes, or nothing where the value is no need. */
49
+ export declare const blueprintOf: (value: unknown) => Blueprint | undefined;
@@ -0,0 +1,33 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // A need: a blueprint at its minimum, the shape of what she calls.
3
+ import { s } from './schema.js';
4
+ /** An awaited call's wait where none is named, and the bound no wait passes. */
5
+ export const WAIT = 30_000;
6
+ export const WAIT_BOUND = 300_000;
7
+ export const BLUEPRINT = Symbol('blueprint');
8
+ /** Whether a method is awaited: `readOnly` implies `idempotent`. */
9
+ export const awaited = (hints) => hints?.idempotent === true || hints?.readOnly === true;
10
+ /** Hints settled, `readOnly` carrying `idempotent` with it. */
11
+ export const settled = (hints) => ({
12
+ readOnly: hints?.readOnly === true,
13
+ idempotent: awaited(hints),
14
+ destructive: hints?.destructive === true,
15
+ });
16
+ /** One method settled: the empty object where args are omitted. */
17
+ export const method = (spec) => Object.freeze({
18
+ args: spec.args ?? s.object({}),
19
+ ...(spec.result === undefined ? {} : { result: spec.result }),
20
+ hints: Object.freeze(settled(spec.hints)),
21
+ ...(spec.description === undefined ? {} : { description: spec.description }),
22
+ wait: typeof spec.wait === 'number' ? Math.min(spec.wait, WAIT_BOUND) : WAIT,
23
+ });
24
+ /** A blueprint at its minimum, under the name matching uses. */
25
+ export const need = (name, methods) => {
26
+ const blueprint = Object.freeze({
27
+ name,
28
+ methods: Object.freeze(Object.fromEntries(Object.entries(methods).map(([key, spec]) => [key, method(spec)]))),
29
+ });
30
+ return Object.freeze({ ...methods, [BLUEPRINT]: blueprint });
31
+ };
32
+ /** The blueprint a need makes, or nothing where the value is no need. */
33
+ export const blueprintOf = (value) => typeof value === 'object' && value !== null && BLUEPRINT in value ? value[BLUEPRINT] : undefined;
@@ -0,0 +1,100 @@
1
+ declare const TYPE: unique symbol;
2
+ /** A schema in the closed subset, typed by what it admits. */
3
+ export type Schema<T = unknown> = {
4
+ readonly [key: string]: unknown;
5
+ } & {
6
+ readonly [TYPE]?: T;
7
+ };
8
+ /** The type a schema admits. */
9
+ export type Infer<S> = S extends {
10
+ readonly [TYPE]?: infer T;
11
+ } ? T : never;
12
+ /** A relation crossing: a handle on the way out, a standing id on the way in. */
13
+ export interface HandleMark {
14
+ readonly handleMark: true;
15
+ }
16
+ /** An invitation carried unopened. It is an object and never a value. */
17
+ export interface Invitation {
18
+ readonly invitation: true;
19
+ }
20
+ /** A reference to one of her asks, or to an occupant she minted. */
21
+ export interface Handle {
22
+ readonly id: string;
23
+ }
24
+ type Mapped<T, H> = T extends HandleMark ? H : T extends Invitation ? // A handle under s.invitation leaves as an invitation too.
25
+ Invitation | (H extends Handle ? Handle : never) : T extends Uint8Array ? T : T extends readonly (infer E)[] ? Mapped<E, H>[] : T extends object ? {
26
+ [K in keyof T]: Mapped<T[K], H>;
27
+ } : T;
28
+ /** What a method receives: a handle has arrived as a standing id. */
29
+ export type Inbound<T> = Mapped<T, string>;
30
+ /** What a call sends: a handle leaves as a handle, or as an invitation she carries, for its receiver to take. */
31
+ export type Outbound<T> = Mapped<T, Handle | Invitation>;
32
+ export declare const HANDLE_MEDIA = "application/vnd.nervur.handle";
33
+ export declare const INVITATION_MEDIA = "application/vnd.nervur.invitation";
34
+ /** The keywords the house checks, and no other. */
35
+ export declare const KEYWORDS: ReadonlySet<string>;
36
+ declare const OPTIONAL: unique symbol;
37
+ type Optional<S extends Schema> = S & {
38
+ readonly [OPTIONAL]: true;
39
+ };
40
+ type Flat<T> = {
41
+ [K in keyof T]: T[K];
42
+ } & {};
43
+ type Props = Record<string, Schema>;
44
+ type OptionalKeys<P extends Props> = {
45
+ [K in keyof P]: P[K] extends {
46
+ readonly [OPTIONAL]: true;
47
+ } ? K : never;
48
+ }[keyof P];
49
+ type ObjectOf<P extends Props> = Flat<{
50
+ -readonly [K in Exclude<keyof P, OptionalKeys<P>>]: Infer<P[K]>;
51
+ } & {
52
+ -readonly [K in OptionalKeys<P>]?: Infer<P[K]>;
53
+ }>;
54
+ /** A method of a need, as `s.reply` reads it. */
55
+ export interface MethodRef<R = unknown> {
56
+ readonly args?: Schema;
57
+ readonly result?: Schema<R>;
58
+ }
59
+ /** The args of a reply: the method's result, or its error. */
60
+ export type Reply<R> = {
61
+ result: R;
62
+ error?: undefined;
63
+ } | {
64
+ error: {
65
+ message: string;
66
+ };
67
+ result?: undefined;
68
+ };
69
+ type Bounds = {
70
+ minimum?: number;
71
+ maximum?: number;
72
+ };
73
+ type Lengths = {
74
+ minLength?: number;
75
+ maxLength?: number;
76
+ };
77
+ type Scalar = string | number | boolean | null;
78
+ export declare const s: Readonly<{
79
+ object: <P extends Props>(properties: P) => Schema<ObjectOf<P>>;
80
+ string: (lengths?: Lengths & {
81
+ pattern?: string;
82
+ }) => Schema<string>;
83
+ number: (bounds?: Bounds) => Schema<number>;
84
+ integer: (bounds?: Bounds) => Schema<number>;
85
+ boolean: () => Schema<boolean>;
86
+ array: <S extends Schema>(items: S) => Schema<Infer<S>[]>;
87
+ enum: <const V extends readonly Scalar[]>(values: V) => Schema<V[number]>;
88
+ const: <const V extends Scalar>(value: V) => Schema<V>;
89
+ bytes: (lengths?: Lengths) => Schema<Uint8Array>;
90
+ optional: <S extends Schema>(schema: S) => Optional<S>;
91
+ handle: () => Schema<HandleMark>;
92
+ invitation: () => Schema<Invitation>;
93
+ reply: <R>(method: MethodRef<R>) => Schema<Reply<unknown extends R ? null : R>>;
94
+ }>;
95
+ /**
96
+ * Every way a schema leaves the subset, each as a sentence naming where.
97
+ * The empty list is a schema the house checks.
98
+ */
99
+ export declare const outside: (schema: unknown, at?: string) => string[];
100
+ export {};