nervur 0.21.4 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (339) hide show
  1. package/README.md +215 -158
  2. package/dist/browser.js +4 -3
  3. package/dist/cli.js +16 -0
  4. package/dist/{being → core/being}/being.js +10 -0
  5. package/dist/{being → core/being}/faculty.js +5 -2
  6. package/dist/{being → core/being}/index.d.ts +1 -1
  7. package/dist/{being → core/being}/index.js +1 -1
  8. package/dist/{being → core/being}/kind.d.ts +2 -0
  9. package/dist/{being → core/being}/kind.js +6 -0
  10. package/dist/{being → core/being}/types.js +1 -1
  11. package/dist/{browser → core/browser}/index.d.ts +6 -5
  12. package/dist/{browser → core/browser}/index.js +10 -10
  13. package/dist/{browser → core/browser}/worker.d.ts +2 -3
  14. package/dist/{browser → core/browser}/worker.js +8 -11
  15. package/dist/{cli → core/cli}/command.d.ts +4 -4
  16. package/dist/{cli → core/cli}/command.js +116 -66
  17. package/dist/{cli → core/cli}/edge.js +4 -2
  18. package/dist/core/cli/harbor.d.ts +25 -0
  19. package/dist/{cli → core/cli}/harbor.js +45 -33
  20. package/dist/{contract → core/contract}/index.d.ts +6 -5
  21. package/dist/{contract → core/contract}/index.js +8 -9
  22. package/dist/core/contract/link.d.ts +4 -0
  23. package/dist/core/contract/link.js +45 -0
  24. package/dist/{crypto → core/crypto}/ed25519.js +22 -14
  25. package/dist/core/crypto/subtle.d.ts +3 -0
  26. package/dist/core/crypto/subtle.js +11 -0
  27. package/dist/core/crypto/x25519.js +24 -0
  28. package/dist/core/edge/index.d.ts +164 -0
  29. package/dist/core/edge/index.js +739 -0
  30. package/dist/core/edge/kit.d.ts +2 -0
  31. package/dist/core/edge/kit.js +2 -0
  32. package/dist/core/git/http.d.ts +6 -0
  33. package/dist/core/git/http.js +102 -0
  34. package/dist/core/git/index.d.ts +5 -0
  35. package/dist/core/git/index.js +10 -0
  36. package/dist/core/git/object.d.ts +40 -0
  37. package/dist/core/git/object.js +103 -0
  38. package/dist/core/git/pack.d.ts +9 -0
  39. package/dist/core/git/pack.js +171 -0
  40. package/dist/core/git/store.d.ts +23 -0
  41. package/dist/core/git/store.js +120 -0
  42. package/dist/core/git/zlib.d.ts +6 -0
  43. package/dist/core/git/zlib.js +210 -0
  44. package/dist/core/harbor/carrying.d.ts +51 -0
  45. package/dist/core/harbor/carrying.js +69 -0
  46. package/dist/core/harbor/catalogue.d.ts +33 -0
  47. package/dist/core/harbor/catalogue.js +365 -0
  48. package/dist/core/harbor/dna.d.ts +13 -0
  49. package/dist/core/harbor/dna.js +120 -0
  50. package/dist/{harbor → core/harbor}/dock.d.ts +22 -13
  51. package/dist/core/harbor/dock.js +381 -0
  52. package/dist/core/harbor/harbor.d.ts +16 -0
  53. package/dist/core/harbor/harbor.js +438 -0
  54. package/dist/core/harbor/index.d.ts +11 -0
  55. package/dist/{harbor → core/harbor}/index.js +5 -5
  56. package/dist/core/harbor/memory.d.ts +10 -0
  57. package/dist/core/harbor/memory.js +25 -0
  58. package/dist/{harbor → core/harbor}/package.d.ts +0 -1
  59. package/dist/{harbor → core/harbor}/package.js +9 -9
  60. package/dist/core/harbor/probe.d.ts +22 -0
  61. package/dist/core/harbor/probe.js +15 -0
  62. package/dist/core/harbor/registry.d.ts +15 -0
  63. package/dist/{harbor → core/harbor}/registry.js +26 -10
  64. package/dist/core/harbor/root-line.d.ts +7 -0
  65. package/dist/core/harbor/root-line.js +9 -0
  66. package/dist/{harbor → core/harbor}/terrain.d.ts +9 -6
  67. package/dist/{harbor → core/harbor}/terrain.js +5 -4
  68. package/dist/core/http/index.d.ts +2 -0
  69. package/dist/{http → core/http}/index.js +3 -5
  70. package/dist/{line → core/line}/answer.d.ts +2 -2
  71. package/dist/{line → core/line}/frame.d.ts +0 -5
  72. package/dist/{line → core/line}/frame.js +0 -4
  73. package/dist/core/line/ground.js +7 -0
  74. package/dist/core/line/index.d.ts +4 -0
  75. package/dist/core/line/index.js +8 -0
  76. package/dist/core/line/web.d.ts +12 -0
  77. package/dist/{line → core/line}/web.js +13 -77
  78. package/dist/{node → core/node}/index.d.ts +2 -15
  79. package/dist/core/node/index.js +124 -0
  80. package/dist/{pointer → core/pointer}/bodies.d.ts +7 -5
  81. package/dist/core/pointer/bodies.js +118 -0
  82. package/dist/core/pointer/index.d.ts +2 -0
  83. package/dist/{pointer → core/pointer}/index.js +1 -1
  84. package/dist/{pointer → core/pointer}/world.d.ts +13 -9
  85. package/dist/{pointer → core/pointer}/world.js +31 -16
  86. package/dist/{proof → core/proof}/contracts.d.ts +6 -2
  87. package/dist/{proof → core/proof}/contracts.js +11 -10
  88. package/dist/core/proof/index.d.ts +3 -0
  89. package/dist/{proof → core/proof}/index.js +2 -2
  90. package/dist/core/proof/law.d.ts +25 -0
  91. package/dist/core/proof/law.js +715 -0
  92. package/dist/{tcp → core/tcp}/index.d.ts +7 -4
  93. package/dist/{tcp → core/tcp}/index.js +11 -62
  94. package/dist/{ward/ward.d.ts → core/ward/house.d.ts} +24 -10
  95. package/dist/core/ward/house.js +473 -0
  96. package/dist/core/ward/index.d.ts +5 -0
  97. package/dist/core/ward/index.js +7 -0
  98. package/dist/{ward → core/ward}/partition.d.ts +1 -0
  99. package/dist/{ward → core/ward}/stance.d.ts +2 -2
  100. package/dist/{ward → core/ward}/stance.js +5 -2
  101. package/dist/{ward/ward-being.d.ts → core/ward/ward.d.ts} +14 -6
  102. package/dist/core/ward/ward.js +140 -0
  103. package/dist/core.d.ts +10 -0
  104. package/dist/core.js +19 -0
  105. package/dist/defaults/dock/index.d.ts +4 -0
  106. package/dist/defaults/dock/index.js +11 -0
  107. package/dist/defaults/index.d.ts +5 -0
  108. package/dist/defaults/index.js +10 -0
  109. package/dist/defaults/memory/index.d.ts +12 -0
  110. package/dist/defaults/memory/index.js +39 -0
  111. package/dist/defaults/tcp/index.d.ts +16 -0
  112. package/dist/defaults/tcp/index.js +82 -0
  113. package/dist/defaults/ward/index.d.ts +4 -0
  114. package/dist/defaults/ward/index.js +11 -0
  115. package/dist/defaults/web/index.d.ts +15 -0
  116. package/dist/defaults/web/index.js +90 -0
  117. package/dist/edge.js +4 -3
  118. package/dist/index.d.ts +1 -8
  119. package/dist/index.js +13 -18
  120. package/dist/kit.d.ts +4 -0
  121. package/dist/kit.js +12 -0
  122. package/dist/node.js +4 -3
  123. package/package.json +23 -18
  124. package/src/browser.ts +4 -3
  125. package/src/cli.ts +15 -0
  126. package/src/{being → core/being}/being.ts +4 -0
  127. package/src/{being → core/being}/faculty.ts +5 -2
  128. package/src/{being → core/being}/index.ts +1 -1
  129. package/src/{being → core/being}/kind.ts +7 -0
  130. package/src/{being → core/being}/types.ts +1 -1
  131. package/src/{browser → core/browser}/index.ts +16 -13
  132. package/src/{browser → core/browser}/worker.ts +11 -14
  133. package/src/{cli → core/cli}/command.ts +113 -66
  134. package/src/{cli → core/cli}/edge.ts +4 -2
  135. package/src/{cli → core/cli}/harbor.ts +48 -31
  136. package/src/{contract → core/contract}/index.ts +14 -14
  137. package/src/core/contract/link.ts +58 -0
  138. package/src/{crypto → core/crypto}/ed25519.ts +22 -14
  139. package/src/core/crypto/subtle.ts +13 -0
  140. package/src/core/crypto/x25519.ts +23 -0
  141. package/src/core/edge/index.ts +865 -0
  142. package/src/core/git/http.ts +103 -0
  143. package/src/core/git/index.ts +10 -0
  144. package/src/core/git/object.ts +116 -0
  145. package/src/core/git/pack.ts +147 -0
  146. package/src/core/git/store.ts +122 -0
  147. package/src/core/git/zlib.ts +197 -0
  148. package/src/core/harbor/carrying.ts +124 -0
  149. package/src/core/harbor/catalogue.ts +386 -0
  150. package/src/core/harbor/dna.ts +116 -0
  151. package/src/core/harbor/dock.ts +420 -0
  152. package/src/core/harbor/harbor.ts +433 -0
  153. package/src/core/harbor/index.ts +14 -0
  154. package/src/core/harbor/memory.ts +31 -0
  155. package/src/{harbor → core/harbor}/package.ts +15 -15
  156. package/src/core/harbor/probe.ts +39 -0
  157. package/src/{harbor → core/harbor}/registry.ts +28 -11
  158. package/src/core/harbor/root-line.ts +19 -0
  159. package/src/{harbor → core/harbor}/terrain.ts +14 -7
  160. package/src/{http → core/http}/index.ts +5 -8
  161. package/src/{line → core/line}/answer.ts +3 -2
  162. package/src/{line → core/line}/frame.ts +0 -5
  163. package/src/core/line/ground.ts +18 -0
  164. package/src/core/line/index.ts +8 -0
  165. package/src/{line → core/line}/web.ts +1 -105
  166. package/src/core/node/index.ts +139 -0
  167. package/src/core/pointer/bodies.ts +122 -0
  168. package/src/core/pointer/index.ts +4 -0
  169. package/src/{pointer → core/pointer}/world.ts +45 -21
  170. package/src/{proof → core/proof}/contracts.ts +18 -13
  171. package/src/{proof → core/proof}/index.ts +3 -3
  172. package/src/core/proof/law.ts +742 -0
  173. package/src/{stand → core/stand}/stand.ts +2 -2
  174. package/src/{tcp → core/tcp}/index.ts +17 -74
  175. package/src/core/ward/house.ts +524 -0
  176. package/src/core/ward/index.ts +7 -0
  177. package/src/{ward → core/ward}/partition.ts +5 -1
  178. package/src/{ward → core/ward}/stance.ts +5 -2
  179. package/src/core/ward/ward.ts +166 -0
  180. package/src/core.ts +55 -0
  181. package/src/defaults/dock/index.ts +12 -0
  182. package/src/defaults/index.ts +10 -0
  183. package/src/defaults/memory/index.ts +50 -0
  184. package/src/defaults/tcp/index.ts +89 -0
  185. package/src/defaults/ward/index.ts +12 -0
  186. package/src/defaults/web/index.ts +97 -0
  187. package/src/edge.ts +4 -3
  188. package/src/index.ts +13 -50
  189. package/src/kit.ts +15 -0
  190. package/src/node.ts +4 -3
  191. package/dist/cli/harbor.d.ts +0 -16
  192. package/dist/cli/main.js +0 -14
  193. package/dist/crypto/subtle.d.ts +0 -10
  194. package/dist/crypto/subtle.js +0 -29
  195. package/dist/crypto/x25519.js +0 -21
  196. package/dist/edge/index.d.ts +0 -81
  197. package/dist/edge/index.js +0 -400
  198. package/dist/harbor/carrying.d.ts +0 -17
  199. package/dist/harbor/carrying.js +0 -38
  200. package/dist/harbor/catalogue.d.ts +0 -28
  201. package/dist/harbor/catalogue.js +0 -109
  202. package/dist/harbor/dock.js +0 -236
  203. package/dist/harbor/harbor.d.ts +0 -45
  204. package/dist/harbor/harbor.js +0 -347
  205. package/dist/harbor/index.d.ts +0 -11
  206. package/dist/harbor/probe.d.ts +0 -18
  207. package/dist/harbor/probe.js +0 -15
  208. package/dist/harbor/registry.d.ts +0 -10
  209. package/dist/harbor/relay.d.ts +0 -15
  210. package/dist/harbor/relay.js +0 -406
  211. package/dist/harbor/root-line.d.ts +0 -9
  212. package/dist/harbor/root-line.js +0 -38
  213. package/dist/harbor/store.d.ts +0 -13
  214. package/dist/harbor/store.js +0 -53
  215. package/dist/http/index.d.ts +0 -4
  216. package/dist/line/ground.js +0 -9
  217. package/dist/line/index.d.ts +0 -5
  218. package/dist/line/index.js +0 -9
  219. package/dist/line/push.d.ts +0 -7
  220. package/dist/line/push.js +0 -92
  221. package/dist/line/web.d.ts +0 -30
  222. package/dist/node/index.js +0 -236
  223. package/dist/pointer/bodies.js +0 -80
  224. package/dist/pointer/index.d.ts +0 -2
  225. package/dist/proof/index.d.ts +0 -3
  226. package/dist/proof/law.d.ts +0 -90
  227. package/dist/proof/law.js +0 -591
  228. package/dist/tcp/frame.d.ts +0 -25
  229. package/dist/tcp/frame.js +0 -64
  230. package/dist/ward/index.d.ts +0 -6
  231. package/dist/ward/index.js +0 -8
  232. package/dist/ward/pilot.d.ts +0 -8
  233. package/dist/ward/pilot.js +0 -50
  234. package/dist/ward/ward-being.js +0 -82
  235. package/dist/ward/ward.js +0 -290
  236. package/src/cli/main.ts +0 -13
  237. package/src/crypto/subtle.ts +0 -33
  238. package/src/crypto/x25519.ts +0 -21
  239. package/src/edge/index.ts +0 -490
  240. package/src/harbor/carrying.ts +0 -56
  241. package/src/harbor/catalogue.ts +0 -134
  242. package/src/harbor/dock.ts +0 -265
  243. package/src/harbor/harbor.ts +0 -381
  244. package/src/harbor/index.ts +0 -14
  245. package/src/harbor/probe.ts +0 -34
  246. package/src/harbor/relay.ts +0 -418
  247. package/src/harbor/root-line.ts +0 -39
  248. package/src/harbor/store.ts +0 -69
  249. package/src/line/ground.ts +0 -19
  250. package/src/line/index.ts +0 -9
  251. package/src/line/push.ts +0 -112
  252. package/src/node/index.ts +0 -241
  253. package/src/pointer/bodies.ts +0 -82
  254. package/src/pointer/index.ts +0 -4
  255. package/src/proof/law.ts +0 -591
  256. package/src/ward/index.ts +0 -8
  257. package/src/ward/pilot.ts +0 -50
  258. package/src/ward/ward-being.ts +0 -103
  259. package/src/ward/ward.ts +0 -328
  260. /package/dist/{cli/main.d.ts → cli.d.ts} +0 -0
  261. /package/dist/{being → core/being}/being.d.ts +0 -0
  262. /package/dist/{being → core/being}/digest.d.ts +0 -0
  263. /package/dist/{being → core/being}/digest.js +0 -0
  264. /package/dist/{being → core/being}/faculty.d.ts +0 -0
  265. /package/dist/{being → core/being}/types.d.ts +0 -0
  266. /package/dist/{being → core/being}/words.d.ts +0 -0
  267. /package/dist/{being → core/being}/words.js +0 -0
  268. /package/dist/{cli → core/cli}/edge.d.ts +0 -0
  269. /package/dist/{crypto → core/crypto}/aes.d.ts +0 -0
  270. /package/dist/{crypto → core/crypto}/aes.js +0 -0
  271. /package/dist/{crypto → core/crypto}/bytes.d.ts +0 -0
  272. /package/dist/{crypto → core/crypto}/bytes.js +0 -0
  273. /package/dist/{crypto → core/crypto}/ed25519.d.ts +0 -0
  274. /package/dist/{crypto → core/crypto}/hash.d.ts +0 -0
  275. /package/dist/{crypto → core/crypto}/hash.js +0 -0
  276. /package/dist/{crypto → core/crypto}/index.d.ts +0 -0
  277. /package/dist/{crypto → core/crypto}/index.js +0 -0
  278. /package/dist/{crypto → core/crypto}/json.d.ts +0 -0
  279. /package/dist/{crypto → core/crypto}/json.js +0 -0
  280. /package/dist/{crypto → core/crypto}/mlkem.d.ts +0 -0
  281. /package/dist/{crypto → core/crypto}/mlkem.js +0 -0
  282. /package/dist/{crypto → core/crypto}/x25519.d.ts +0 -0
  283. /package/dist/{folder → core/folder}/index.d.ts +0 -0
  284. /package/dist/{folder → core/folder}/index.js +0 -0
  285. /package/dist/{http → core/http}/websocket.d.ts +0 -0
  286. /package/dist/{http → core/http}/websocket.js +0 -0
  287. /package/dist/{line → core/line}/answer.js +0 -0
  288. /package/dist/{line → core/line}/ground.d.ts +0 -0
  289. /package/dist/{proof → core/proof}/expect.d.ts +0 -0
  290. /package/dist/{proof → core/proof}/expect.js +0 -0
  291. /package/dist/{quo → core/quo}/address.d.ts +0 -0
  292. /package/dist/{quo → core/quo}/address.js +0 -0
  293. /package/dist/{quo → core/quo}/door.d.ts +0 -0
  294. /package/dist/{quo → core/quo}/door.js +0 -0
  295. /package/dist/{quo → core/quo}/index.d.ts +0 -0
  296. /package/dist/{quo → core/quo}/index.js +0 -0
  297. /package/dist/{quo → core/quo}/invitation.d.ts +0 -0
  298. /package/dist/{quo → core/quo}/invitation.js +0 -0
  299. /package/dist/{quo → core/quo}/keys.d.ts +0 -0
  300. /package/dist/{quo → core/quo}/keys.js +0 -0
  301. /package/dist/{quo → core/quo}/payload.d.ts +0 -0
  302. /package/dist/{quo → core/quo}/payload.js +0 -0
  303. /package/dist/{quo → core/quo}/relations.d.ts +0 -0
  304. /package/dist/{quo → core/quo}/relations.js +0 -0
  305. /package/dist/{quo → core/quo}/reply.d.ts +0 -0
  306. /package/dist/{quo → core/quo}/reply.js +0 -0
  307. /package/dist/{quo → core/quo}/seal.d.ts +0 -0
  308. /package/dist/{quo → core/quo}/seal.js +0 -0
  309. /package/dist/{quo → core/quo}/standing.d.ts +0 -0
  310. /package/dist/{quo → core/quo}/standing.js +0 -0
  311. /package/dist/{ward → core/ward}/allowance.d.ts +0 -0
  312. /package/dist/{ward → core/ward}/allowance.js +0 -0
  313. /package/dist/{ward → core/ward}/cells.d.ts +0 -0
  314. /package/dist/{ward → core/ward}/cells.js +0 -0
  315. /package/dist/{ward → core/ward}/partition.js +0 -0
  316. /package/src/{being → core/being}/digest.ts +0 -0
  317. /package/src/{being → core/being}/words.ts +0 -0
  318. /package/src/{crypto → core/crypto}/aes.ts +0 -0
  319. /package/src/{crypto → core/crypto}/bytes.ts +0 -0
  320. /package/src/{crypto → core/crypto}/hash.ts +0 -0
  321. /package/src/{crypto → core/crypto}/index.ts +0 -0
  322. /package/src/{crypto → core/crypto}/json.ts +0 -0
  323. /package/src/{crypto → core/crypto}/mlkem.ts +0 -0
  324. /package/src/{folder → core/folder}/index.ts +0 -0
  325. /package/src/{http → core/http}/websocket.ts +0 -0
  326. /package/src/{proof → core/proof}/expect.ts +0 -0
  327. /package/src/{quo → core/quo}/address.ts +0 -0
  328. /package/src/{quo → core/quo}/door.ts +0 -0
  329. /package/src/{quo → core/quo}/index.ts +0 -0
  330. /package/src/{quo → core/quo}/invitation.ts +0 -0
  331. /package/src/{quo → core/quo}/keys.ts +0 -0
  332. /package/src/{quo → core/quo}/payload.ts +0 -0
  333. /package/src/{quo → core/quo}/relations.ts +0 -0
  334. /package/src/{quo → core/quo}/reply.ts +0 -0
  335. /package/src/{quo → core/quo}/seal.ts +0 -0
  336. /package/src/{quo → core/quo}/standing.ts +0 -0
  337. /package/src/{stand → core/stand}/main.ts +0 -0
  338. /package/src/{ward → core/ward}/allowance.ts +0 -0
  339. /package/src/{ward → core/ward}/cells.ts +0 -0
@@ -1,406 +0,0 @@
1
- // SPDX-License-Identifier: Apache-2.0
2
- // The relay: a harbor nobody dials is reached through a harbor that is,
3
- // by relations alone. Both sides are kit faculties, opened by the root.
4
- //
5
- // On the reached harbor, `org.nervur.relay`:
6
- //
7
- // invite { id, wards } a relay client invited under `id`, its
8
- // notes naming the ward pks it collects for
9
- // release { id } that client let go, and every box waiting
10
- // for its wards answered with nothing
11
- // collect { replies?, wait? } asked by a client: the replies to the boxes
12
- // it took last, handed to their callers, then
13
- // the boxes waiting for its wards; with
14
- // `wait`, it waits for one first
15
- // bell { endpoint } asked by a client: the push endpoint rung
16
- // when a box waits for it, or null for none
17
- // key asked by a client: the key its device
18
- // subscribes to pushes with
19
- //
20
- // A box for a ward a client collects for reaches this harbor on any
21
- // carrier, and the caller's dial waits for its reply, or for nothing once
22
- // `RELAY_WAIT` passes. No box is opened here. A box no waiting collect
23
- // takes rings the client's bell once, through a `Push` faculty the relay
24
- // lends, until the client collects again.
25
- //
26
- // On the harbor nobody dials, `org.nervur.relay-client`:
27
- //
28
- // hold { invitation, line?, every? } the relay's invitation taken; a
29
- // line collects always, `every`
30
- // rings on a schedule, in ms
31
- // ring every waiting box collected, handed
32
- // to this harbor's doors, and the
33
- // replies returned: a doorbell
34
- // bell { endpoint } the relay's `bell`, asked
35
- // key the relay's `key`, asked
36
- // drop the relay let go
37
- //
38
- // Its harbor's `reach` names the relay's address, so every invitation it
39
- // gives sends callers there. Whatever hears a push on the device asks
40
- // `ring`.
41
- import { Faculty, isSilence, isWord, told } from '../being/index.js';
42
- import { hex, isHex, unhex } from '../crypto/index.js';
43
- import { readInvitation } from '../quo/index.js';
44
- import { ownerAsk } from '../ward/index.js';
45
- import { CarrierFaculty, UNDIALED } from './carrying.js';
46
- export const RELAY = 'org.nervur.relay';
47
- export const RELAY_CLIENT = 'org.nervur.relay-client';
48
- export const PUSH = 'org.nervur.push';
49
- // How long a box waits for its reply: a caller's allowance, unless it
50
- // asks for another.
51
- export const RELAY_WAIT = 30_000;
52
- // How long a collect with `wait` holds, inside the client's allowance.
53
- export const RELAY_HOLD = 20_000;
54
- // How long a line rests after a collect that reached nothing.
55
- export const RELAY_REST = 1_000;
56
- // The largest box a relay carries, so the collect answering it stays a
57
- // box Quo carries.
58
- export const RELAYED = 262_144;
59
- // The longest push endpoint a relay keeps.
60
- const ENDPOINT = 2_048;
61
- // The most boxes one collect hands over.
62
- const BATCH = 16;
63
- const CLIENT = 'relay';
64
- const PUSHER = 'push';
65
- // The contract of a ring with no content: `key` answers the key a device
66
- // subscribes with, and `ring { endpoint }` answers `rung`, `gone` where
67
- // the push service has let the endpoint go, or an error.
68
- export class Push extends Faculty {
69
- static kind = PUSH;
70
- }
71
- const text = (v) => typeof v === 'string';
72
- const wardsOf = (notes) => (Array.isArray(notes?.relay) ? notes.relay.filter(text) : []);
73
- const collects = (_, notes) => wardsOf(notes).length > 0;
74
- const clientAsk = (description, input = {}) => ({ description, input: { type: 'object', ...input }, for: collects });
75
- const readReplies = (v) => v === undefined
76
- ? []
77
- : Array.isArray(v) && v.every((r) => typeof r === 'object' && r !== null && Number.isInteger(r.n) && (r.box === null || isHex(r.box, (r.box ?? '').length / 2)))
78
- ? v
79
- : null;
80
- // An answer, or the error it stands for.
81
- const answered = (out) => (isSilence(out) ? { error: 'silence' } : isWord(out) ? { error: told(out) } : out);
82
- export const relayFaculty = (clock) => class Relay extends CarrierFaculty {
83
- static kind = RELAY;
84
- static cells = { clients: {}, bells: {} };
85
- static asks = {
86
- invite: ownerAsk('a relay client, collecting for the ward pks named', { required: ['id', 'wards'] }),
87
- release: ownerAsk('a relay client let go', { required: ['id'] }),
88
- collect: clientAsk('the replies to the boxes taken last, then the boxes waiting'),
89
- bell: clientAsk('the push endpoint rung when a box waits, or null', { required: ['endpoint'] }),
90
- key: clientAsk('the key a device subscribes to pushes with'),
91
- };
92
- #n = 0;
93
- #waiting = [];
94
- #taken = new Map();
95
- #collectors = new Set();
96
- // The clients rung since they last collected.
97
- #rung = new Set();
98
- #lending;
99
- accepts() {
100
- return false;
101
- }
102
- dial() {
103
- return Promise.resolve(UNDIALED);
104
- }
105
- get #clients() {
106
- return this.cells.clients;
107
- }
108
- get #bells() {
109
- return this.cells.bells;
110
- }
111
- relays(pk) {
112
- return Object.values(this.#clients).some((wards) => wards.includes(pk));
113
- }
114
- relay(pk, bytes) {
115
- if (!this.relays(pk) || bytes.length > RELAYED)
116
- return Promise.resolve(null);
117
- return new Promise((resolve) => {
118
- const wait = clock.wait(RELAY_WAIT);
119
- const box = { n: ++this.#n, ward: pk, bytes, answer: resolve, cancel: wait.cancel };
120
- void wait.done.then(() => this.#settle(box, null));
121
- this.#waiting.push(box);
122
- let woken = false;
123
- for (const collector of this.#collectors) {
124
- if (!collector.wards.includes(pk))
125
- continue;
126
- collector.wake();
127
- woken = true;
128
- }
129
- if (woken)
130
- return;
131
- for (const [id, wards] of Object.entries(this.#clients)) {
132
- if (!wards.includes(pk) || !Object.hasOwn(this.#bells, id) || this.#rung.has(id))
133
- continue;
134
- this.#rung.add(id);
135
- void this.#ring(id);
136
- }
137
- });
138
- }
139
- // Every box answered with nothing, and every collect woken.
140
- sleep() {
141
- for (const box of [...this.#waiting, ...this.#taken.values()])
142
- this.#settle(box, null);
143
- for (const collector of this.#collectors)
144
- collector.wake();
145
- return Promise.resolve();
146
- }
147
- async invite(args) {
148
- const { id, wards } = args;
149
- if (!text(id) || !Array.isArray(wards) || wards.length === 0 || !wards.every((w) => isHex(w, 64)))
150
- return { error: 'id is text and wards a list of ward pks' };
151
- if (Object.hasOwn(this.#clients, id))
152
- return { error: 'that client is invited' };
153
- const invitation = await this.stance.occupants.invite(id, { relay: wards });
154
- if (invitation === null)
155
- return { error: 'not invited' };
156
- this.#clients[id] = [...wards];
157
- return { invitation };
158
- }
159
- release(args) {
160
- if (!text(args.id) || !Object.hasOwn(this.#clients, args.id))
161
- return { error: 'no such client' };
162
- this.stance.occupants.remove(args.id);
163
- delete this.#clients[args.id];
164
- delete this.#bells[args.id];
165
- this.#rung.delete(args.id);
166
- for (const box of [...this.#waiting, ...this.#taken.values()])
167
- if (!this.relays(box.ward))
168
- this.#settle(box, null);
169
- return { released: args.id };
170
- }
171
- async collect(args, asker) {
172
- const replies = readReplies(args.replies);
173
- if (replies === null)
174
- return { error: 'replies are a list of { n, box }' };
175
- const id = asker.id;
176
- this.#rung.delete(id);
177
- const replied = new Set(replies.map((r) => r.n));
178
- for (const { n, box } of replies) {
179
- const taken = this.#taken.get(n);
180
- if (taken?.collector === id)
181
- this.#settle(taken, box === null ? null : unhex(box));
182
- }
183
- // A client answers every box it took in its next collect, so a box it
184
- // left out never reached its doors, and waits again. A door that
185
- // hears it twice answers the second as repeated.
186
- for (const taken of [...this.#taken.values()]) {
187
- if (taken.collector !== id || replied.has(taken.n))
188
- continue;
189
- this.#taken.delete(taken.n);
190
- delete taken.collector;
191
- this.#waiting.unshift(taken);
192
- }
193
- const wards = wardsOf(this.notes(asker));
194
- if (args.wait === true && !this.#waiting.some((b) => wards.includes(b.ward)))
195
- await this.#hold(wards);
196
- const boxes = this.#waiting.filter((b) => wards.includes(b.ward)).slice(0, BATCH);
197
- for (const box of boxes) {
198
- this.#waiting.splice(this.#waiting.indexOf(box), 1);
199
- box.collector = id;
200
- this.#taken.set(box.n, box);
201
- }
202
- return { boxes: boxes.map(({ n, ward, bytes }) => ({ n, ward, box: hex(bytes) })) };
203
- }
204
- bell(args, asker) {
205
- const { endpoint } = args;
206
- const id = asker.id;
207
- if (endpoint === null) {
208
- delete this.#bells[id];
209
- return { bell: null };
210
- }
211
- if (!text(endpoint) || endpoint.length > ENDPOINT || !/^https?:\/\//.test(endpoint))
212
- return { error: 'endpoint is a web URL, or null' };
213
- this.#bells[id] = endpoint;
214
- return { bell: endpoint };
215
- }
216
- async key() {
217
- const push = await this.#push();
218
- return push ? answered(await push.ask('key')) : { error: 'no push faculty is open' };
219
- }
220
- // The client's bell rung. An endpoint the push service calls gone is
221
- // forgotten, and kept at the relay's next arrival.
222
- async #ring(id) {
223
- const push = await this.#push();
224
- const endpoint = this.#bells[id];
225
- if (!push || endpoint === undefined)
226
- return;
227
- const out = answered(await push.ask('ring', { endpoint }));
228
- if (out.gone === true && this.#bells[id] === endpoint)
229
- delete this.#bells[id];
230
- }
231
- async #push() {
232
- if (!this.stance.standings.get(PUSHER)) {
233
- this.#lending ??= this.stance.lend(Push, PUSHER).finally(() => (this.#lending = undefined));
234
- await this.#lending;
235
- }
236
- return this.stance.standings.get(PUSHER);
237
- }
238
- #hold(wards) {
239
- return new Promise((resolve) => {
240
- const wait = clock.wait(RELAY_HOLD);
241
- const collector = {
242
- wards,
243
- wake: () => {
244
- wait.cancel();
245
- this.#collectors.delete(collector);
246
- resolve();
247
- },
248
- };
249
- this.#collectors.add(collector);
250
- void wait.done.then(collector.wake);
251
- });
252
- }
253
- #settle(box, reply) {
254
- box.cancel();
255
- const at = this.#waiting.indexOf(box);
256
- if (at >= 0)
257
- this.#waiting.splice(at, 1);
258
- this.#taken.delete(box.n);
259
- box.answer(reply);
260
- }
261
- };
262
- export const relayClient = (ground, clock) => class RelayClient extends CarrierFaculty {
263
- static kind = RELAY_CLIENT;
264
- static asks = {
265
- hold: ownerAsk("a relay's invitation, collected from on a line, a schedule or a ring", { required: ['invitation'] }),
266
- ring: ownerAsk('every waiting box collected and answered now'),
267
- bell: ownerAsk('the push endpoint the relay rings, or null', { required: ['endpoint'] }),
268
- key: ownerAsk('the key this device subscribes to pushes with'),
269
- drop: ownerAsk('the relay let go'),
270
- };
271
- #awake = false;
272
- #replies = [];
273
- #turn = Promise.resolve();
274
- // Ends every rest and schedule when the client sleeps or lets go.
275
- #stop = () => { };
276
- accepts() {
277
- return false;
278
- }
279
- dial() {
280
- return Promise.resolve(UNDIALED);
281
- }
282
- awake() {
283
- if (!this.#awake) {
284
- this.#awake = true;
285
- this.#start();
286
- }
287
- return Promise.resolve();
288
- }
289
- sleep() {
290
- this.#awake = false;
291
- this.#stop();
292
- return Promise.resolve();
293
- }
294
- async hold(args) {
295
- const invitation = readInvitation(args.invitation);
296
- const { line, every } = args;
297
- if (invitation === null || (line !== undefined && typeof line !== 'boolean') || (every !== undefined && !(Number.isInteger(every) && every > 0))) {
298
- return { error: 'an invitation, line a boolean and every a positive integer' };
299
- }
300
- if (this.stance.standings.get(CLIENT))
301
- return { error: 'a relay is held' };
302
- if ((await this.stance.standings.take(CLIENT, invitation)) === null)
303
- return { error: 'not taken' };
304
- this.cells.line = line === true;
305
- if (every !== undefined)
306
- this.cells.every = every;
307
- this.#start();
308
- return { held: invitation.ward };
309
- }
310
- async ring() {
311
- if (!this.stance.standings.get(CLIENT))
312
- return { error: 'no relay is held' };
313
- let carried = 0;
314
- for (;;) {
315
- const sent = this.#replies.length;
316
- const got = await this.#collect(false);
317
- if (got === null)
318
- return { error: 'the relay was not reached', carried };
319
- carried += got;
320
- if (got === 0 && sent === 0)
321
- return { carried };
322
- }
323
- }
324
- bell(args) {
325
- return this.#relay('bell', { endpoint: args.endpoint ?? null });
326
- }
327
- key() {
328
- return this.#relay('key');
329
- }
330
- drop() {
331
- if (!this.stance.standings.remove(CLIENT))
332
- return { error: 'no relay is held' };
333
- delete this.cells.line;
334
- delete this.cells.every;
335
- this.#stop();
336
- return { dropped: true };
337
- }
338
- async #relay(method, args = {}) {
339
- const standing = this.stance.standings.get(CLIENT);
340
- return standing ? answered(await standing.ask(method, args)) : { error: 'no relay is held' };
341
- }
342
- #start() {
343
- if (!this.#awake || !this.stance.standings.get(CLIENT))
344
- return;
345
- this.#stop();
346
- let stopped = false;
347
- const rests = new Set();
348
- this.#stop = () => {
349
- stopped = true;
350
- for (const end of rests)
351
- end();
352
- };
353
- const rest = (ms) => new Promise((resolve) => {
354
- const wait = clock.wait(ms);
355
- const end = () => {
356
- wait.cancel();
357
- rests.delete(end);
358
- resolve();
359
- };
360
- rests.add(end);
361
- void wait.done.then(end);
362
- });
363
- const going = () => !stopped && this.stance.standings.get(CLIENT) !== undefined;
364
- if (this.cells.line === true) {
365
- void (async () => {
366
- while (going())
367
- if ((await this.#collect(true)) === null && going())
368
- await rest(RELAY_REST);
369
- })();
370
- }
371
- const every = this.cells.every;
372
- if (every !== undefined) {
373
- void (async () => {
374
- for (await rest(every); going(); await rest(every))
375
- await this.ring();
376
- })();
377
- }
378
- }
379
- // One collect: the replies owed go with it, and each box it brings is
380
- // handed to this harbor's doors. The number of boxes, or null where the
381
- // relay was not reached.
382
- // Collects run one after another, so each carries the replies to every
383
- // box the one before it brought, as the relay counts on.
384
- #collect(wait) {
385
- const run = this.#turn.then(() => this.#collectNow(wait));
386
- this.#turn = run.catch(() => undefined);
387
- return run;
388
- }
389
- async #collectNow(wait) {
390
- const standing = this.stance.standings.get(CLIENT);
391
- if (!standing)
392
- return null;
393
- const replies = this.#replies.splice(0);
394
- const out = await standing.ask('collect', { replies, wait });
395
- const boxes = !isSilence(out) && !isWord(out) && Array.isArray(out.boxes) ? out.boxes : null;
396
- if (boxes === null) {
397
- this.#replies.unshift(...replies);
398
- return null;
399
- }
400
- for (const { n, ward, box } of boxes) {
401
- const reply = text(ward) && text(box) && isHex(box, box.length / 2) ? await ground.arrive(ward, unhex(box)) : null;
402
- this.#replies.push({ n: n, box: reply === null ? null : hex(reply) });
403
- }
404
- return boxes.length;
405
- }
406
- };
@@ -1,9 +0,0 @@
1
- import { type JsonObject } from '../being/index.ts';
2
- import type { Harbor } from './harbor.ts';
3
- export type RootRequest = {
4
- ward?: string;
5
- method?: string;
6
- args?: JsonObject;
7
- };
8
- export declare const readRootRequest: (value: unknown) => RootRequest | null;
9
- export declare const rootLine: (harbor: Harbor, value: unknown) => Promise<JsonObject>;
@@ -1,38 +0,0 @@
1
- // SPDX-License-Identifier: Apache-2.0
2
- // The root line: one request, one answer, both plain JSON, for whatever
3
- // carries the root's asks to a harbor in its own process. The command line
4
- // carries it over a local socket, and an edge route carries it the same way.
5
- //
6
- // request { ward?, method?, args? } no ward is the box ward, no
7
- // method the census
8
- // answer { answer } what the ward-being said
9
- // { silence: true } she said nothing
10
- // { word } a kit word: unreached, late, ...
11
- // { error } the request was not one, or the
12
- // ward is none this harbor holds
13
- import { isSilence, isWord, told } from '../being/index.js';
14
- const object = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
15
- export const readRootRequest = (value) => {
16
- if (!object(value))
17
- return null;
18
- const { ward, method, args } = value;
19
- if ((ward !== undefined && typeof ward !== 'string') || (method !== undefined && typeof method !== 'string') || (args !== undefined && !object(args)))
20
- return null;
21
- return { ...(ward === undefined ? {} : { ward }), ...(method === undefined ? {} : { method }), ...(args === undefined ? {} : { args }) };
22
- };
23
- export const rootLine = async (harbor, value) => {
24
- const request = readRootRequest(value);
25
- if (request === null)
26
- return { error: 'not a root request' };
27
- const ward = request.ward === undefined ? harbor.box : harbor.ward(request.ward);
28
- if (ward === undefined) {
29
- const failed = request.ward === undefined ? undefined : harbor.failures().wards[request.ward];
30
- return failed === undefined ? { error: 'no such ward' } : { error: 'the ward did not stand', reason: failed };
31
- }
32
- const out = await ward.root(request.method, request.args);
33
- if (isSilence(out))
34
- return { silence: true };
35
- if (isWord(out))
36
- return { word: told(out) };
37
- return { answer: out };
38
- };
@@ -1,13 +0,0 @@
1
- import { Faculty, type BeingClass } from '../being/index.ts';
2
- import type { Memory } from '../contract/index.ts';
3
- export declare const STORE = "org.nervur.store";
4
- export declare const GROUND_STORE = "org.nervur.ground-store";
5
- export declare abstract class Store extends Faculty {
6
- static readonly kind: string;
7
- abstract read(place: string): Promise<Map<string, Uint8Array>>;
8
- abstract write(place: string, entries: ReadonlyMap<string, Uint8Array | null>): Promise<void>;
9
- abstract places(): Promise<string[]>;
10
- abstract forget(place: string): Promise<void>;
11
- occupies(_place: string): boolean;
12
- }
13
- export declare const groundStore: (memory: Memory) => BeingClass;
@@ -1,53 +0,0 @@
1
- // SPDX-License-Identifier: Apache-2.0
2
- // The store: a faculty that keeps a hosted ward's place, where the root
3
- // memory does not. It makes the same promise the Memory body makes, lent
4
- // once the dock stands: sealed entries in places, each keep whole or not
5
- // at all. The box ward never moves off the root memory, since the store
6
- // itself stands from the box ward's cells.
7
- //
8
- // A ward is the unit a keeper holds: its head, its ward-being and every
9
- // being of it are one place and one keep, so an answer's cells and the
10
- // door's keys move together, whoever keeps them.
11
- //
12
- // The kit ships `org.nervur.ground-store` on every ground: places of the
13
- // terrain's own memory under the faculty's key, so a store stands wherever
14
- // a harbor does. A store of a cloud, a database or a ledger is a class
15
- // fulfilling `org.nervur.store`, handed to the catalogue in a module.
16
- import { Faculty } from '../being/index.js';
17
- import { hex, utf8 } from '../crypto/index.js';
18
- export const STORE = 'org.nervur.store';
19
- export const GROUND_STORE = 'org.nervur.ground-store';
20
- export class Store extends Faculty {
21
- static kind = STORE;
22
- // Whether a place of the root memory is this store's own, so the root's
23
- // sweep leaves it.
24
- occupies(_place) {
25
- return false;
26
- }
27
- }
28
- // A place of the package is thirty-two hex digits.
29
- const PLACE = 32;
30
- // The store over the terrain's memory, made for one harbor. Its places are
31
- // the package's, behind the hex of the faculty's key, so two stores and the
32
- // root never meet in one place.
33
- export const groundStore = (memory) => class GroundStore extends Store {
34
- static kind = GROUND_STORE;
35
- get #prefix() {
36
- return hex(utf8(this.stance.key));
37
- }
38
- occupies(place) {
39
- return place.length === this.#prefix.length + PLACE && place.startsWith(this.#prefix);
40
- }
41
- read(place) {
42
- return memory.read(this.#prefix + place);
43
- }
44
- write(place, entries) {
45
- return memory.write(this.#prefix + place, entries);
46
- }
47
- async places() {
48
- return (await memory.places()).filter((place) => this.occupies(place)).map((place) => place.slice(this.#prefix.length));
49
- }
50
- forget(place) {
51
- return memory.forget(this.#prefix + place);
52
- }
53
- };
@@ -1,4 +0,0 @@
1
- import type { Ground, GroundFaculty } from '../harbor/index.ts';
2
- import { type WebListen, type WebListener } from '../line/index.ts';
3
- export declare const webServe: (ground: Ground, listen: WebListen) => Promise<WebListener>;
4
- export declare const webGround: GroundFaculty;
@@ -1,9 +0,0 @@
1
- import { HeldLoader, PointerTerrain } from '../pointer/index.js';
2
- import { webPush } from './push.js';
3
- import { WEB_OPENING, webFaculty } from './web.js';
4
- export const NEUTRAL = 'neutral';
5
- export const neutralGround = {
6
- name: NEUTRAL,
7
- fits: () => true,
8
- terrain: ({ modules = [] }) => new PointerTerrain({ loader: new HeldLoader(modules), faculties: [webFaculty(), webPush], opens: [WEB_OPENING] }),
9
- };
@@ -1,5 +0,0 @@
1
- export { ASK, askBody, askFrame, FrameReader, MAX_BODY, NOTHING, nothingBody, nothingFrame, readBody, REPLY, replyBody, replyFrame, TCP, TCP_OPENING, type Frame } from './frame.ts';
2
- export { answerHeld, answerPost, type HeldSide } from './answer.ts';
3
- export { NEUTRAL, neutralGround } from './ground.ts';
4
- export { base64url, PUSH_TTL, pushEndpoint, VAPID_LIFE, WEB_PUSH, webPush } from './push.ts';
5
- export { MAX_POST, MIN_POST, readPost, WEB, WEB_OPENING, WebDialer, webFaculty, type WebListen, type WebListener, type WebServe } from './web.ts';
@@ -1,9 +0,0 @@
1
- // SPDX-License-Identifier: Apache-2.0
2
- // The lines Quo is carried on, with no platform under them: the frames
3
- // both published carriers share, the web carrier on fetch and the
4
- // WebSocket client, and a ring with no content as Web Push sends it.
5
- export { ASK, askBody, askFrame, FrameReader, MAX_BODY, NOTHING, nothingBody, nothingFrame, readBody, REPLY, replyBody, replyFrame, TCP, TCP_OPENING } from './frame.js';
6
- export { answerHeld, answerPost } from './answer.js';
7
- export { NEUTRAL, neutralGround } from './ground.js';
8
- export { base64url, PUSH_TTL, pushEndpoint, VAPID_LIFE, WEB_PUSH, webPush } from './push.js';
9
- export { MAX_POST, MIN_POST, readPost, WEB, WEB_OPENING, WebDialer, webFaculty } from './web.js';
@@ -1,7 +0,0 @@
1
- import { type GroundFaculty } from '../harbor/index.ts';
2
- export declare const WEB_PUSH = "org.nervur.web-push";
3
- export declare const PUSH_TTL = 60;
4
- export declare const VAPID_LIFE = 43200;
5
- export declare const base64url: (bytes: Uint8Array) => string;
6
- export declare const pushEndpoint: (value: unknown) => URL | null;
7
- export declare const webPush: GroundFaculty;
package/dist/line/push.js DELETED
@@ -1,92 +0,0 @@
1
- import { concat, utf8 } from '../crypto/index.js';
2
- import { Push } from '../harbor/index.js';
3
- import { ownerAsk } from '../ward/index.js';
4
- export const WEB_PUSH = 'org.nervur.web-push';
5
- // How long a push service holds a ring for a device, in seconds.
6
- export const PUSH_TTL = 60;
7
- // How long a VAPID token stands, in seconds, inside RFC 8292's day.
8
- export const VAPID_LIFE = 43_200;
9
- const EC = { name: 'ECDSA', namedCurve: 'P-256' };
10
- export const base64url = (bytes) => {
11
- let s = '';
12
- for (const b of bytes)
13
- s += String.fromCharCode(b);
14
- return btoa(s).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
15
- };
16
- const unbase64url = (text) => Uint8Array.from(atob(text.replace(/-/g, '+').replace(/_/g, '/')), (c) => c.charCodeAt(0));
17
- const local = (host) => host === '127.0.0.1' || host === 'localhost' || host === '[::1]';
18
- // A push endpoint: an https URL, or plain http to this machine alone.
19
- export const pushEndpoint = (value) => {
20
- if (typeof value !== 'string')
21
- return null;
22
- try {
23
- const url = new URL(value);
24
- return url.protocol === 'https:' || (url.protocol === 'http:' && local(url.hostname)) ? url : null;
25
- }
26
- catch {
27
- return null;
28
- }
29
- };
30
- const isSubject = (value) => typeof value === 'string' && /^(mailto:.+|https:\/\/.+)$/.test(value);
31
- export const webPush = () => class WebPush extends Push {
32
- static kind = WEB_PUSH;
33
- static asks = {
34
- subject: ownerAsk('the contact a push service reaches, a mailto: or https: URI', { required: ['subject'] }),
35
- key: { description: 'the key a device subscribes to pushes with', input: { type: 'object' } },
36
- ring: { description: 'a ring with no content to a push endpoint', input: { type: 'object', required: ['endpoint'] } },
37
- };
38
- #drawing;
39
- subject(args) {
40
- if (!isSubject(args.subject))
41
- return { error: 'subject is a mailto: or https: URI' };
42
- this.cells.subject = args.subject;
43
- return { subject: args.subject };
44
- }
45
- async key() {
46
- return { key: WebPush.#public(await this.#vapid()) };
47
- }
48
- async ring(args) {
49
- const endpoint = pushEndpoint(args.endpoint);
50
- if (endpoint === null)
51
- return { error: 'endpoint is an https URL' };
52
- const sub = this.cells.subject;
53
- if (!isSubject(sub))
54
- return { error: 'no subject is set' };
55
- const vapid = await this.#vapid();
56
- const signing = await crypto.subtle.importKey('jwk', { kty: 'EC', crv: 'P-256', ...vapid }, EC, false, ['sign']);
57
- const part = (value) => base64url(utf8(JSON.stringify(value)));
58
- const unsigned = `${part({ typ: 'JWT', alg: 'ES256' })}.${part({ aud: endpoint.origin, exp: Math.floor(Date.now() / 1000) + VAPID_LIFE, sub })}`;
59
- const signature = new Uint8Array(await crypto.subtle.sign({ name: 'ECDSA', hash: 'SHA-256' }, signing, new Uint8Array(utf8(unsigned))));
60
- let status;
61
- try {
62
- const response = await fetch(endpoint, {
63
- method: 'POST',
64
- headers: { TTL: String(PUSH_TTL), Urgency: 'high', 'Content-Length': '0', Authorization: `vapid t=${unsigned}.${base64url(signature)}, k=${WebPush.#public(vapid)}` },
65
- });
66
- status = response.status;
67
- await response.body?.cancel();
68
- }
69
- catch {
70
- return { error: 'the push service was not reached' };
71
- }
72
- if (status === 404 || status === 410)
73
- return { gone: true };
74
- return status >= 200 && status < 300 ? { rung: true } : { error: `the push service answered ${String(status)}` };
75
- }
76
- static #public({ x, y }) {
77
- return base64url(concat(Uint8Array.of(4), unbase64url(x), unbase64url(y)));
78
- }
79
- #vapid() {
80
- const kept = this.cells.vapid;
81
- if (kept)
82
- return Promise.resolve(kept);
83
- this.#drawing ??= (async () => {
84
- const pair = await crypto.subtle.generateKey(EC, true, ['sign']);
85
- const { d, x, y } = await crypto.subtle.exportKey('jwk', pair.privateKey);
86
- const vapid = { d: d, x: x, y: y };
87
- this.cells.vapid = vapid;
88
- return vapid;
89
- })();
90
- return this.#drawing;
91
- }
92
- };