@serfab/cadre-host 1.13.0 → 1.15.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 (352) hide show
  1. package/README.md +347 -423
  2. package/dist/bin/host.d.ts +6 -3
  3. package/dist/bin/host.js +332 -524
  4. package/dist/bin/host.js.map +1 -1
  5. package/dist/bin/join-output.d.ts +56 -0
  6. package/dist/bin/join-output.js +92 -0
  7. package/dist/bin/join-output.js.map +1 -0
  8. package/dist/bin/nat-output.d.ts +54 -0
  9. package/dist/bin/nat-output.js +138 -0
  10. package/dist/bin/nat-output.js.map +1 -0
  11. package/dist/bin/ui-access.d.ts +22 -0
  12. package/dist/bin/ui-access.js +44 -0
  13. package/dist/bin/ui-access.js.map +1 -0
  14. package/dist/hosted/claim-details.d.ts +66 -0
  15. package/dist/hosted/claim-details.js +60 -0
  16. package/dist/hosted/claim-details.js.map +1 -0
  17. package/dist/hosted/hosted-node-service.d.ts +325 -0
  18. package/dist/hosted/hosted-node-service.js +678 -0
  19. package/dist/hosted/hosted-node-service.js.map +1 -0
  20. package/dist/hosted/hosted-node-store.d.ts +40 -0
  21. package/dist/hosted/hosted-node-store.js +126 -0
  22. package/dist/hosted/hosted-node-store.js.map +1 -0
  23. package/dist/{donation/donation-supervisor.d.ts → hosted/hosted-node-supervisor.d.ts} +70 -53
  24. package/dist/hosted/hosted-node-supervisor.js +396 -0
  25. package/dist/hosted/hosted-node-supervisor.js.map +1 -0
  26. package/dist/hosted/hosted-node-watcher.d.ts +95 -0
  27. package/dist/hosted/hosted-node-watcher.js +260 -0
  28. package/dist/hosted/hosted-node-watcher.js.map +1 -0
  29. package/dist/hosted/index.d.ts +16 -0
  30. package/dist/hosted/index.js +13 -0
  31. package/dist/hosted/index.js.map +1 -0
  32. package/dist/hosted/node-status.d.ts +51 -0
  33. package/dist/hosted/node-status.js +77 -0
  34. package/dist/hosted/node-status.js.map +1 -0
  35. package/dist/hosted/types.d.ts +141 -0
  36. package/dist/hosted/types.js +22 -0
  37. package/dist/hosted/types.js.map +1 -0
  38. package/dist/index.d.ts +12 -24
  39. package/dist/index.js +9 -19
  40. package/dist/index.js.map +1 -1
  41. package/dist/installer/config.d.ts +27 -34
  42. package/dist/installer/config.js +46 -15
  43. package/dist/installer/config.js.map +1 -1
  44. package/dist/installer/index.d.ts +9 -19
  45. package/dist/installer/index.js +21 -85
  46. package/dist/installer/index.js.map +1 -1
  47. package/dist/installer/paths.d.ts +0 -2
  48. package/dist/installer/paths.js +0 -4
  49. package/dist/installer/paths.js.map +1 -1
  50. package/dist/installer/wizard.d.ts +12 -9
  51. package/dist/installer/wizard.js +15 -14
  52. package/dist/installer/wizard.js.map +1 -1
  53. package/dist/nat/address-resolver.d.ts +18 -17
  54. package/dist/nat/address-resolver.js +79 -25
  55. package/dist/nat/address-resolver.js.map +1 -1
  56. package/dist/nat/address-watch.d.ts +37 -0
  57. package/dist/nat/address-watch.js +84 -0
  58. package/dist/nat/address-watch.js.map +1 -0
  59. package/dist/nat/ddns/duckdns.d.ts +2 -1
  60. package/dist/nat/ddns/duckdns.js +5 -1
  61. package/dist/nat/ddns/duckdns.js.map +1 -1
  62. package/dist/nat/ddns/index.d.ts +6 -0
  63. package/dist/nat/ddns/index.js.map +1 -1
  64. package/dist/nat/index.d.ts +13 -9
  65. package/dist/nat/index.js +7 -5
  66. package/dist/nat/index.js.map +1 -1
  67. package/dist/nat/nat-service.d.ts +220 -77
  68. package/dist/nat/nat-service.js +653 -239
  69. package/dist/nat/nat-service.js.map +1 -1
  70. package/dist/nat/nat-store.d.ts +12 -5
  71. package/dist/nat/nat-store.js +124 -29
  72. package/dist/nat/nat-store.js.map +1 -1
  73. package/dist/nat/network-mode.d.ts +19 -0
  74. package/dist/nat/network-mode.js +32 -0
  75. package/dist/nat/network-mode.js.map +1 -0
  76. package/dist/nat/port-mapper.d.ts +83 -79
  77. package/dist/nat/port-mapper.js +148 -189
  78. package/dist/nat/port-mapper.js.map +1 -1
  79. package/dist/nat/reachability.d.ts +32 -15
  80. package/dist/nat/reachability.js +110 -22
  81. package/dist/nat/reachability.js.map +1 -1
  82. package/dist/nat/types.d.ts +98 -27
  83. package/dist/nat/types.js +8 -5
  84. package/dist/nat/types.js.map +1 -1
  85. package/dist/orchestrator/host-process-orchestrator.d.ts +32 -74
  86. package/dist/orchestrator/host-process-orchestrator.js +84 -233
  87. package/dist/orchestrator/host-process-orchestrator.js.map +1 -1
  88. package/dist/{installer/identity.d.ts → orchestrator/identity-file.d.ts} +5 -5
  89. package/dist/{installer/identity.js → orchestrator/identity-file.js} +6 -6
  90. package/dist/orchestrator/identity-file.js.map +1 -0
  91. package/dist/orchestrator/index.d.ts +2 -3
  92. package/dist/orchestrator/index.js +1 -1
  93. package/dist/orchestrator/index.js.map +1 -1
  94. package/dist/orchestrator/node-identity.d.ts +6 -6
  95. package/dist/orchestrator/node-identity.js +7 -7
  96. package/dist/orchestrator/node-identity.js.map +1 -1
  97. package/dist/orchestrator/port-allocator.d.ts +5 -6
  98. package/dist/orchestrator/port-allocator.js +9 -11
  99. package/dist/orchestrator/port-allocator.js.map +1 -1
  100. package/dist/orchestrator/state-store.d.ts +3 -5
  101. package/dist/orchestrator/state-store.js +2 -10
  102. package/dist/orchestrator/state-store.js.map +1 -1
  103. package/dist/orchestrator/types.d.ts +33 -22
  104. package/dist/orchestrator/types.js.map +1 -1
  105. package/dist/package-version.d.ts +1 -0
  106. package/dist/package-version.js +4 -0
  107. package/dist/package-version.js.map +1 -0
  108. package/dist/server/error-handler.d.ts +5 -25
  109. package/dist/server/error-handler.js +11 -74
  110. package/dist/server/error-handler.js.map +1 -1
  111. package/dist/server/events/types.d.ts +7 -11
  112. package/dist/server/events/types.js +2 -1
  113. package/dist/server/events/types.js.map +1 -1
  114. package/dist/server/index.d.ts +11 -37
  115. package/dist/server/index.js +30 -48
  116. package/dist/server/index.js.map +1 -1
  117. package/dist/server/routes/hosted-nodes.d.ts +28 -0
  118. package/dist/server/routes/hosted-nodes.js +68 -0
  119. package/dist/server/routes/hosted-nodes.js.map +1 -0
  120. package/dist/server/routes/nat.d.ts +4 -1
  121. package/dist/server/routes/nat.js +13 -2
  122. package/dist/server/routes/nat.js.map +1 -1
  123. package/dist/server/routes/nodes.d.ts +6 -20
  124. package/dist/server/routes/nodes.js +7 -86
  125. package/dist/server/routes/nodes.js.map +1 -1
  126. package/dist/server/routes/settings.d.ts +3 -7
  127. package/dist/server/routes/settings.js +18 -8
  128. package/dist/server/routes/settings.js.map +1 -1
  129. package/dist/server/routes/status.d.ts +2 -25
  130. package/dist/server/routes/status.js +3 -43
  131. package/dist/server/routes/status.js.map +1 -1
  132. package/dist/server/server.js +8 -8
  133. package/dist/server/settings-store.d.ts +2 -2
  134. package/dist/server/settings-store.js +2 -2
  135. package/dist/server/static.js +1 -2
  136. package/dist/server/static.js.map +1 -1
  137. package/dist/ui/assets/index-BHd8CWZA.css +1 -0
  138. package/dist/ui/assets/index-Ccr2GjPT.js +23 -0
  139. package/dist/ui/assets/index-Ccr2GjPT.js.map +1 -0
  140. package/dist/ui/index.html +2 -2
  141. package/dist/update/index.d.ts +2 -2
  142. package/dist/update/index.js +2 -2
  143. package/dist/update/store.d.ts +1 -1
  144. package/dist/update/store.js +1 -1
  145. package/dist/update/types.d.ts +1 -1
  146. package/dist/update/types.js +1 -1
  147. package/package.json +5 -7
  148. package/src/__tests__/cli-nat.smoke.test.ts +219 -212
  149. package/src/__tests__/cli.smoke.test.ts +2 -2
  150. package/src/__tests__/global-setup.ts +2 -3
  151. package/src/__tests__/orchestrator-claim-secret.test.ts +111 -0
  152. package/src/__tests__/orchestrator-env-scrub.test.ts +160 -163
  153. package/src/__tests__/orchestrator-handle-contract.ts +134 -134
  154. package/src/__tests__/orchestrator-node-identity.test.ts +177 -203
  155. package/src/__tests__/orchestrator-ports.test.ts +124 -143
  156. package/src/__tests__/orchestrator-push.test.ts +138 -146
  157. package/src/__tests__/orchestrator.test.ts +1017 -1063
  158. package/src/__tests__/ui-access.test.ts +30 -0
  159. package/src/bin/host.ts +397 -572
  160. package/src/bin/join-output.ts +120 -0
  161. package/src/bin/nat-output.ts +188 -0
  162. package/src/bin/ui-access.ts +50 -0
  163. package/src/{donation → hosted}/__tests__/fake-orchestrator.test.ts +172 -173
  164. package/src/{donation → hosted}/__tests__/fake-orchestrator.ts +43 -23
  165. package/src/hosted/__tests__/hosted-node-service.test.ts +708 -0
  166. package/src/hosted/__tests__/hosted-node-supervisor.test.ts +475 -0
  167. package/src/hosted/__tests__/test-invitation.ts +33 -0
  168. package/src/hosted/claim-details.ts +103 -0
  169. package/src/hosted/hosted-node-service.ts +814 -0
  170. package/src/hosted/hosted-node-store.ts +144 -0
  171. package/src/hosted/hosted-node-supervisor.ts +439 -0
  172. package/src/hosted/hosted-node-watcher.ts +288 -0
  173. package/src/hosted/index.ts +53 -0
  174. package/src/hosted/node-status.ts +97 -0
  175. package/src/hosted/types.ts +160 -0
  176. package/src/index.ts +72 -91
  177. package/src/installer/__tests__/config.test.ts +15 -40
  178. package/src/installer/__tests__/installer.smoke.test.ts +184 -263
  179. package/src/installer/__tests__/wizard.test.ts +25 -13
  180. package/src/installer/config.ts +201 -175
  181. package/src/installer/index.ts +252 -327
  182. package/src/installer/paths.ts +104 -109
  183. package/src/installer/wizard.ts +24 -26
  184. package/src/nat/__tests__/address-resolver.test.ts +107 -82
  185. package/src/nat/__tests__/nat-service.test.ts +608 -515
  186. package/src/nat/__tests__/nat-store.test.ts +49 -12
  187. package/src/nat/__tests__/network-mode.test.ts +38 -0
  188. package/src/nat/__tests__/port-mapper.test.ts +30 -191
  189. package/src/nat/__tests__/reachability.test.ts +96 -13
  190. package/src/nat/address-resolver.ts +94 -52
  191. package/src/nat/address-watch.ts +92 -0
  192. package/src/nat/ddns/duckdns.ts +5 -1
  193. package/src/nat/ddns/index.ts +6 -0
  194. package/src/nat/index.ts +33 -13
  195. package/src/nat/nat-service.ts +942 -501
  196. package/src/nat/nat-store.ts +126 -31
  197. package/src/nat/network-mode.ts +36 -0
  198. package/src/nat/port-mapper.ts +241 -329
  199. package/src/nat/reachability.ts +155 -34
  200. package/src/nat/types.ts +110 -37
  201. package/src/{installer/__tests__/identity.test.ts → orchestrator/__tests__/identity-file.test.ts} +34 -34
  202. package/src/orchestrator/__tests__/node-identity.test.ts +62 -62
  203. package/src/orchestrator/host-process-orchestrator.ts +1089 -1260
  204. package/src/{installer/identity.ts → orchestrator/identity-file.ts} +56 -56
  205. package/src/orchestrator/index.ts +9 -10
  206. package/src/orchestrator/node-identity.ts +41 -41
  207. package/src/orchestrator/port-allocator.ts +71 -73
  208. package/src/orchestrator/state-store.ts +76 -90
  209. package/src/orchestrator/types.ts +34 -23
  210. package/src/package-version.ts +4 -0
  211. package/src/server/__tests__/bus.test.ts +38 -38
  212. package/src/server/__tests__/error-handler.test.ts +81 -118
  213. package/src/server/__tests__/fakes.ts +15 -18
  214. package/src/server/__tests__/hosted-nodes-route.test.ts +161 -0
  215. package/src/server/__tests__/nodes-route.test.ts +114 -283
  216. package/src/server/__tests__/publishers.test.ts +193 -180
  217. package/src/server/__tests__/server.smoke.test.ts +134 -223
  218. package/src/server/__tests__/settings-route.test.ts +210 -195
  219. package/src/server/__tests__/sse-route.test.ts +119 -119
  220. package/src/server/__tests__/status-route.test.ts +82 -121
  221. package/src/server/error-handler.ts +112 -178
  222. package/src/server/events/types.ts +20 -24
  223. package/src/server/index.ts +223 -267
  224. package/src/server/routes/hosted-nodes.ts +83 -0
  225. package/src/server/routes/nat.ts +75 -63
  226. package/src/server/routes/nodes.ts +96 -188
  227. package/src/server/routes/settings.ts +20 -15
  228. package/src/server/routes/status.ts +5 -67
  229. package/src/server/server.ts +8 -8
  230. package/src/server/settings-store.ts +2 -2
  231. package/src/server/static.ts +1 -2
  232. package/src/update/index.ts +2 -2
  233. package/src/update/store.ts +1 -1
  234. package/src/update/types.ts +1 -1
  235. package/dist/auth/duration.d.ts +0 -1
  236. package/dist/auth/duration.js +0 -32
  237. package/dist/auth/duration.js.map +0 -1
  238. package/dist/auth/index.d.ts +0 -11
  239. package/dist/auth/index.js +0 -9
  240. package/dist/auth/index.js.map +0 -1
  241. package/dist/auth/self-label.d.ts +0 -36
  242. package/dist/auth/self-label.js +0 -57
  243. package/dist/auth/self-label.js.map +0 -1
  244. package/dist/auth/trust-circle-store.d.ts +0 -26
  245. package/dist/auth/trust-circle-store.js +0 -129
  246. package/dist/auth/trust-circle-store.js.map +0 -1
  247. package/dist/auth/trust-circle.d.ts +0 -156
  248. package/dist/auth/trust-circle.js +0 -307
  249. package/dist/auth/trust-circle.js.map +0 -1
  250. package/dist/auth/types.d.ts +0 -84
  251. package/dist/auth/types.js +0 -24
  252. package/dist/auth/types.js.map +0 -1
  253. package/dist/donation/donation-service.d.ts +0 -389
  254. package/dist/donation/donation-service.js +0 -828
  255. package/dist/donation/donation-service.js.map +0 -1
  256. package/dist/donation/donation-store.d.ts +0 -51
  257. package/dist/donation/donation-store.js +0 -152
  258. package/dist/donation/donation-store.js.map +0 -1
  259. package/dist/donation/donation-supervisor.js +0 -364
  260. package/dist/donation/donation-supervisor.js.map +0 -1
  261. package/dist/donation/grant-service.d.ts +0 -80
  262. package/dist/donation/grant-service.js +0 -210
  263. package/dist/donation/grant-service.js.map +0 -1
  264. package/dist/donation/grant-store.d.ts +0 -38
  265. package/dist/donation/grant-store.js +0 -135
  266. package/dist/donation/grant-store.js.map +0 -1
  267. package/dist/donation/index.d.ts +0 -20
  268. package/dist/donation/index.js +0 -17
  269. package/dist/donation/index.js.map +0 -1
  270. package/dist/donation/types.d.ts +0 -224
  271. package/dist/donation/types.js +0 -40
  272. package/dist/donation/types.js.map +0 -1
  273. package/dist/installer/identity.js.map +0 -1
  274. package/dist/owner/index.d.ts +0 -11
  275. package/dist/owner/index.js +0 -11
  276. package/dist/owner/index.js.map +0 -1
  277. package/dist/owner/owner-node-client.d.ts +0 -110
  278. package/dist/owner/owner-node-client.js +0 -184
  279. package/dist/owner/owner-node-client.js.map +0 -1
  280. package/dist/server/routes/bootstrap-node-validation.d.ts +0 -115
  281. package/dist/server/routes/bootstrap-node-validation.js +0 -197
  282. package/dist/server/routes/bootstrap-node-validation.js.map +0 -1
  283. package/dist/server/routes/grants-admin.d.ts +0 -29
  284. package/dist/server/routes/grants-admin.js +0 -58
  285. package/dist/server/routes/grants-admin.js.map +0 -1
  286. package/dist/server/routes/grants.d.ts +0 -28
  287. package/dist/server/routes/grants.js +0 -165
  288. package/dist/server/routes/grants.js.map +0 -1
  289. package/dist/server/routes/provision-request-validation.d.ts +0 -45
  290. package/dist/server/routes/provision-request-validation.js +0 -97
  291. package/dist/server/routes/provision-request-validation.js.map +0 -1
  292. package/dist/server/routes/strands.d.ts +0 -20
  293. package/dist/server/routes/strands.js +0 -38
  294. package/dist/server/routes/strands.js.map +0 -1
  295. package/dist/server/routes/trust-circle.d.ts +0 -17
  296. package/dist/server/routes/trust-circle.js +0 -35
  297. package/dist/server/routes/trust-circle.js.map +0 -1
  298. package/dist/strands/index.d.ts +0 -7
  299. package/dist/strands/index.js +0 -6
  300. package/dist/strands/index.js.map +0 -1
  301. package/dist/strands/strand-service.d.ts +0 -50
  302. package/dist/strands/strand-service.js +0 -103
  303. package/dist/strands/strand-service.js.map +0 -1
  304. package/dist/strands/types.d.ts +0 -93
  305. package/dist/strands/types.js +0 -23
  306. package/dist/strands/types.js.map +0 -1
  307. package/dist/ui/assets/index-C6nELNfC.js +0 -23
  308. package/dist/ui/assets/index-C6nELNfC.js.map +0 -1
  309. package/dist/ui/assets/index-TtIYSeZO.css +0 -1
  310. package/src/__tests__/cli-invite.smoke.test.ts +0 -192
  311. package/src/__tests__/host-owner.smoke.test.ts +0 -123
  312. package/src/__tests__/orchestrator-owner.test.ts +0 -234
  313. package/src/__tests__/orchestrator-pin-keys.test.ts +0 -152
  314. package/src/auth/__tests__/duration.test.ts +0 -28
  315. package/src/auth/__tests__/self-label.test.ts +0 -85
  316. package/src/auth/__tests__/trust-circle-integration.test.ts +0 -152
  317. package/src/auth/__tests__/trust-circle-store.test.ts +0 -115
  318. package/src/auth/__tests__/trust-circle.test.ts +0 -445
  319. package/src/auth/duration.ts +0 -33
  320. package/src/auth/index.ts +0 -21
  321. package/src/auth/self-label.ts +0 -74
  322. package/src/auth/trust-circle-store.ts +0 -155
  323. package/src/auth/trust-circle.ts +0 -395
  324. package/src/auth/types.ts +0 -99
  325. package/src/donation/__tests__/donation-service.test.ts +0 -1193
  326. package/src/donation/__tests__/donation-supervisor.test.ts +0 -548
  327. package/src/donation/__tests__/grant-service.test.ts +0 -213
  328. package/src/donation/__tests__/grant-store.test.ts +0 -113
  329. package/src/donation/donation-service.ts +0 -1033
  330. package/src/donation/donation-store.ts +0 -176
  331. package/src/donation/donation-supervisor.ts +0 -411
  332. package/src/donation/grant-service.ts +0 -252
  333. package/src/donation/grant-store.ts +0 -152
  334. package/src/donation/index.ts +0 -65
  335. package/src/donation/types.ts +0 -260
  336. package/src/owner/__tests__/owner-node-client.test.ts +0 -194
  337. package/src/owner/index.ts +0 -12
  338. package/src/owner/owner-node-client.ts +0 -259
  339. package/src/server/__tests__/bootstrap-node-validation.test.ts +0 -138
  340. package/src/server/__tests__/grants-admin-route.test.ts +0 -171
  341. package/src/server/__tests__/grants-route.test.ts +0 -394
  342. package/src/server/__tests__/strands-route.test.ts +0 -234
  343. package/src/server/routes/bootstrap-node-validation.ts +0 -206
  344. package/src/server/routes/grants-admin.ts +0 -74
  345. package/src/server/routes/grants.ts +0 -193
  346. package/src/server/routes/provision-request-validation.ts +0 -105
  347. package/src/server/routes/strands.ts +0 -54
  348. package/src/server/routes/trust-circle.ts +0 -49
  349. package/src/strands/__tests__/strand-service.test.ts +0 -165
  350. package/src/strands/index.ts +0 -14
  351. package/src/strands/strand-service.ts +0 -135
  352. package/src/strands/types.ts +0 -102
@@ -5,8 +5,8 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <meta name="color-scheme" content="light dark" />
7
7
  <title>cadre-host</title>
8
- <script type="module" crossorigin src="./assets/index-C6nELNfC.js"></script>
9
- <link rel="stylesheet" crossorigin href="./assets/index-TtIYSeZO.css">
8
+ <script type="module" crossorigin src="./assets/index-Ccr2GjPT.js"></script>
9
+ <link rel="stylesheet" crossorigin href="./assets/index-BHd8CWZA.css">
10
10
  </head>
11
11
  <body>
12
12
  <div id="app"></div>
@@ -98,8 +98,8 @@ export declare class UpdateService {
98
98
  stop(): void;
99
99
  }
100
100
  /**
101
- * Typed handler facade — mirrors `createTrustCircleHandlers` /
102
- * `createNatHandlers`. The local-UI ticket consumes these.
101
+ * Typed handler facade — same shape as `createNatHandlers`. The local-UI
102
+ * server consumes these.
103
103
  */
104
104
  export declare function createUpdateHandlers(service: UpdateService): UpdateHandlers;
105
105
  export type { UpdateState, UpdateApplyResult, UpdateSettings, UpdateManifest, SignedManifest } from './types.js';
@@ -231,8 +231,8 @@ export class UpdateService {
231
231
  }
232
232
  }
233
233
  /**
234
- * Typed handler facade — mirrors `createTrustCircleHandlers` /
235
- * `createNatHandlers`. The local-UI ticket consumes these.
234
+ * Typed handler facade — same shape as `createNatHandlers`. The local-UI
235
+ * server consumes these.
236
236
  */
237
237
  export function createUpdateHandlers(service) {
238
238
  return {
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Atomic JSON store for `<dataDir>/update-state.json`.
3
3
  *
4
- * Mirrors `TrustCircleStore` / `NatStore`: load on demand, write to
4
+ * Mirrors `NatStore`: load on demand, write to
5
5
  * `<path>.tmp` then rename. Single-writer assumption — only one cadre-host
6
6
  * process owns a given dataDir.
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Atomic JSON store for `<dataDir>/update-state.json`.
3
3
  *
4
- * Mirrors `TrustCircleStore` / `NatStore`: load on demand, write to
4
+ * Mirrors `NatStore`: load on demand, write to
5
5
  * `<path>.tmp` then rename. Single-writer assumption — only one cadre-host
6
6
  * process owns a given dataDir.
7
7
  */
@@ -8,7 +8,7 @@
8
8
  * - apply.ts — invoke `npm install -g` + rollback on failure.
9
9
  * - index.ts — composes the above (UpdateService).
10
10
  *
11
- * Mirrors the typed-handler pattern used by trust-circle and NAT (handlers
11
+ * Mirrors the typed-handler pattern used by NAT (handlers
12
12
  * throw `UpdateError` whose `.code` the local-UI maps to HTTP status).
13
13
  */
14
14
  /** Inner manifest object — signed by the release key. */
@@ -8,7 +8,7 @@
8
8
  * - apply.ts — invoke `npm install -g` + rollback on failure.
9
9
  * - index.ts — composes the above (UpdateService).
10
10
  *
11
- * Mirrors the typed-handler pattern used by trust-circle and NAT (handlers
11
+ * Mirrors the typed-handler pattern used by NAT (handlers
12
12
  * throw `UpdateError` whose `.code` the local-UI maps to HTTP status).
13
13
  */
14
14
  /** Thrown by UpdateService.apply() and related entry points. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serfab/cadre-host",
3
- "version": "1.13.0",
3
+ "version": "1.15.0",
4
4
  "type": "module",
5
5
  "description": "Self-hosted cadre node manager for basement-PC deployments",
6
6
  "main": "dist/index.js",
@@ -29,8 +29,7 @@
29
29
  "cadre",
30
30
  "host",
31
31
  "self-hosted",
32
- "p2p",
33
- "trust-circle"
32
+ "p2p"
34
33
  ],
35
34
  "scripts": {
36
35
  "clean": "rimraf dist",
@@ -64,10 +63,9 @@
64
63
  "@libp2p/crypto": "^5.1.23",
65
64
  "@libp2p/interface": "^3.3.0",
66
65
  "@libp2p/peer-id": "^6.0.15",
67
- "@multiformats/multiaddr": "^13.0.3",
68
- "@serfab/cadre-cli": "^1.13.0",
69
- "@serfab/cadre-core": "^1.13.0",
70
- "@serfab/cadre-provider": "^1.13.0",
66
+ "@serfab/cadre-cli": "^1.15.0",
67
+ "@serfab/cadre-core": "^1.15.0",
68
+ "@serfab/cadre-provider": "^1.15.0",
71
69
  "commander": "^14.0.2",
72
70
  "debug": "^4.4.3",
73
71
  "fastify": "^5.7.1",
@@ -1,212 +1,219 @@
1
- /**
2
- * CLI smoke test for the `nat` subcommand. Spawns a stub HTTP server playing
3
- * the role of cadre-host's management API and asserts the CLI:
4
- * - GETs /nat/status
5
- * - POSTs /nat/test
6
- * - PUTs /nat/ddns with the expected body
7
- * - PUTs /nat/settings
8
- * - Exits non-zero when the host is not reachable
9
- *
10
- * Relies on `yarn build` having produced dist/bin/host.js.
11
- */
12
-
13
- import { spawn } from 'node:child_process';
14
- import { createServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http';
15
- import { existsSync } from 'node:fs';
16
- import { fileURLToPath } from 'node:url';
17
- import { dirname, resolve } from 'node:path';
18
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
19
-
20
- const here = dirname(fileURLToPath(import.meta.url));
21
- const binPath = resolve(here, '../../dist/bin/host.js');
22
-
23
- // These smoke tests cold-start the built CLI as a child process (Node boot +,
24
- // for some, an HTTP server). That comfortably exceeds vitest's 5s default under
25
- // heavy parallel load, so give the subprocess generous headroom.
26
- vi.setConfig({ testTimeout: 30000 });
27
-
28
- interface StubServer {
29
- server: Server;
30
- port: number;
31
- requests: Array<{ method: string; url: string; body: string }>;
32
- setResponse(handler: (req: IncomingMessage, res: ServerResponse) => void): void;
33
- }
34
-
35
- const DEFAULT_STATUS = {
36
- portMode: 'auto-upnp',
37
- externalPort: 4001,
38
- internalPort: 4001,
39
- routerExternalIp: '203.0.113.5',
40
- mappingLeaseExpiresAt: null,
41
- externalIp: '203.0.113.5',
42
- externalIpDetectedAt: new Date().toISOString(),
43
- cgnatDetected: false,
44
- directReachability: 'reachable',
45
- lastTestedAt: null,
46
- ddns: {
47
- providerId: 'duckdns',
48
- hostname: 'foo.duckdns.org',
49
- externallyManaged: false,
50
- lastUpdateAt: null,
51
- lastUpdateOk: null,
52
- lastError: null,
53
- },
54
- };
55
-
56
- async function startStub(): Promise<StubServer> {
57
- const requests: StubServer['requests'] = [];
58
- let handler: (req: IncomingMessage, res: ServerResponse) => void = (_req, res) => {
59
- res.statusCode = 200;
60
- res.setHeader('content-type', 'application/json');
61
- res.end(JSON.stringify(DEFAULT_STATUS));
62
- };
63
-
64
- const server = createServer((req, res) => {
65
- const chunks: Buffer[] = [];
66
- req.on('data', (chunk: Buffer) => chunks.push(chunk));
67
- req.on('end', () => {
68
- requests.push({ method: req.method ?? '', url: req.url ?? '', body: Buffer.concat(chunks).toString('utf8') });
69
- handler(req, res);
70
- });
71
- });
72
-
73
- await new Promise<void>((resolveStart) => server.listen(0, '127.0.0.1', () => resolveStart()));
74
- const addr = server.address();
75
- const port = typeof addr === 'object' && addr ? addr.port : 0;
76
- return {
77
- server,
78
- port,
79
- requests,
80
- setResponse: (h) => { handler = h; },
81
- };
82
- }
83
-
84
- function runCli(args: string[]): Promise<{ code: number; stdout: string; stderr: string }> {
85
- return new Promise((resolveRun) => {
86
- const child = spawn(process.execPath, [binPath, ...args], { stdio: ['ignore', 'pipe', 'pipe'] });
87
- let stdout = '';
88
- let stderr = '';
89
- child.stdout.on('data', (chunk: Buffer) => { stdout += chunk.toString('utf8'); });
90
- child.stderr.on('data', (chunk: Buffer) => { stderr += chunk.toString('utf8'); });
91
- child.on('close', (code) => resolveRun({ code: code ?? -1, stdout, stderr }));
92
- });
93
- }
94
-
95
- let stub: StubServer;
96
-
97
- beforeEach(async () => {
98
- if (!existsSync(binPath)) {
99
- throw new Error(`cadre-host bin not built at ${binPath}; run \`yarn build\` first`);
100
- }
101
- stub = await startStub();
102
- });
103
-
104
- afterEach(async () => {
105
- await new Promise<void>((resolveClose) => stub.server.close(() => resolveClose()));
106
- });
107
-
108
- describe('cadre-host nat status', () => {
109
- it('GETs /nat/status and renders the snapshot', async () => {
110
- const result = await runCli(['nat', 'status', '--port', String(stub.port)]);
111
- expect(result.code).toBe(0);
112
- expect(stub.requests).toHaveLength(1);
113
- expect(stub.requests[0]!.method).toBe('GET');
114
- expect(stub.requests[0]!.url).toBe('/nat/status');
115
- expect(result.stdout).toContain('auto-upnp');
116
- expect(result.stdout).toContain('203.0.113.5');
117
- expect(result.stdout).toContain('foo.duckdns.org');
118
- });
119
-
120
- it('--json prints raw JSON', async () => {
121
- const result = await runCli(['nat', 'status', '--port', String(stub.port), '--json']);
122
- expect(result.code).toBe(0);
123
- const parsed = JSON.parse(result.stdout);
124
- expect(parsed.portMode).toBe('auto-upnp');
125
- });
126
-
127
- it('exits 2 when cadre-host is unreachable', async () => {
128
- const port = stub.port;
129
- await new Promise<void>((resolveClose) => stub.server.close(() => resolveClose()));
130
- const result = await runCli(['nat', 'status', '--port', String(port)]);
131
- expect(result.code).toBe(2);
132
- expect(result.stderr).toMatch(/cadre-host start|Failed to reach/);
133
- });
134
- });
135
-
136
- describe('cadre-host nat test', () => {
137
- it('POSTs /nat/test', async () => {
138
- const result = await runCli(['nat', 'test', '--port', String(stub.port)]);
139
- expect(result.code).toBe(0);
140
- expect(stub.requests[0]!.method).toBe('POST');
141
- expect(stub.requests[0]!.url).toBe('/nat/test');
142
- });
143
- });
144
-
145
- describe('cadre-host nat ddns set', () => {
146
- it('PUTs /nat/ddns with provider + hostname + token', async () => {
147
- const result = await runCli([
148
- 'nat', 'ddns', 'set', 'duckdns',
149
- '--hostname', 'foo.duckdns.org',
150
- '--token', 'TOK',
151
- '--port', String(stub.port),
152
- ]);
153
- expect(result.code).toBe(0);
154
- expect(stub.requests[0]!.method).toBe('PUT');
155
- expect(stub.requests[0]!.url).toBe('/nat/ddns');
156
- const body = JSON.parse(stub.requests[0]!.body);
157
- expect(body.providerId).toBe('duckdns');
158
- expect(body.hostname).toBe('foo.duckdns.org');
159
- expect(body.config).toEqual({ token: 'TOK' });
160
- });
161
-
162
- it('exits 1 when --hostname is missing', async () => {
163
- const result = await runCli([
164
- 'nat', 'ddns', 'set', 'duckdns',
165
- '--token', 'TOK',
166
- '--port', String(stub.port),
167
- ]);
168
- expect(result.code).toBe(1);
169
- expect(result.stderr).toMatch(/--hostname/);
170
- });
171
-
172
- it('exits 1 when --token is missing on a non-TTY stdin', async () => {
173
- const result = await runCli([
174
- 'nat', 'ddns', 'set', 'duckdns',
175
- '--hostname', 'foo.duckdns.org',
176
- '--port', String(stub.port),
177
- ]);
178
- expect(result.code).toBe(1);
179
- expect(result.stderr).toMatch(/--token/);
180
- });
181
- });
182
-
183
- describe('cadre-host nat ddns external', () => {
184
- it('PUTs /nat/settings with externallyManaged=true', async () => {
185
- const result = await runCli([
186
- 'nat', 'ddns', 'external',
187
- '--hostname', 'mydomain.example.com',
188
- '--port', String(stub.port),
189
- ]);
190
- expect(result.code).toBe(0);
191
- expect(stub.requests[0]!.method).toBe('PUT');
192
- expect(stub.requests[0]!.url).toBe('/nat/settings');
193
- const body = JSON.parse(stub.requests[0]!.body);
194
- expect(body.ddns.hostname).toBe('mydomain.example.com');
195
- expect(body.ddns.externallyManaged).toBe(true);
196
- });
197
- });
198
-
199
- describe('cadre-host nat settings', () => {
200
- it('PUTs /nat/settings with --external-port and --no-upnp', async () => {
201
- const result = await runCli([
202
- 'nat', 'settings',
203
- '--external-port', '4002',
204
- '--no-upnp',
205
- '--port', String(stub.port),
206
- ]);
207
- expect(result.code).toBe(0);
208
- const body = JSON.parse(stub.requests[0]!.body);
209
- expect(body.externalPort).toBe(4002);
210
- expect(body.upnpEnabled).toBe(false);
211
- });
212
- });
1
+ /**
2
+ * CLI smoke test for the `nat` subcommand. Spawns a stub HTTP server playing
3
+ * the role of cadre-host's management API and asserts the CLI:
4
+ * - GETs /nat/status
5
+ * - POSTs /nat/test
6
+ * - PUTs /nat/ddns with the expected body
7
+ * - PUTs /nat/settings
8
+ * - Exits non-zero when the host is not reachable
9
+ *
10
+ * Relies on `yarn build` having produced dist/bin/host.js.
11
+ */
12
+
13
+ import { spawn } from 'node:child_process';
14
+ import { createServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http';
15
+ import { existsSync } from 'node:fs';
16
+ import { fileURLToPath } from 'node:url';
17
+ import { dirname, resolve } from 'node:path';
18
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
19
+
20
+ const here = dirname(fileURLToPath(import.meta.url));
21
+ const binPath = resolve(here, '../../dist/bin/host.js');
22
+
23
+ // These smoke tests cold-start the built CLI as a child process (Node boot +,
24
+ // for some, an HTTP server). That comfortably exceeds vitest's 5s default under
25
+ // heavy parallel load, so give the subprocess generous headroom.
26
+ vi.setConfig({ testTimeout: 30000 });
27
+
28
+ interface StubServer {
29
+ server: Server;
30
+ port: number;
31
+ requests: Array<{ method: string; url: string; body: string }>;
32
+ setResponse(handler: (req: IncomingMessage, res: ServerResponse) => void): void;
33
+ }
34
+
35
+ const DEFAULT_STATUS = {
36
+ upnpEnabled: true,
37
+ gateway: { found: true, lanAddress: '192.168.1.20', routerExternalIp: '203.0.113.5', lastError: null },
38
+ externalIp: '203.0.113.5',
39
+ externalIpDetectedAt: new Date().toISOString(),
40
+ cgnatDetected: false,
41
+ directReachability: 'reachable',
42
+ lastTestedAt: null,
43
+ nodes: [
44
+ {
45
+ nodeId: 'owner',
46
+ running: true,
47
+ verdict: 'mapped',
48
+ reason: null,
49
+ tcp: { internalPort: 4001, externalPort: 4001, source: 'upnp', leaseExpiresAt: null, error: null },
50
+ ws: { internalPort: 10001, externalPort: 10001, source: 'upnp', leaseExpiresAt: null, error: null },
51
+ publicAddrs: ['/ip4/203.0.113.5/tcp/4001', '/ip4/203.0.113.5/tcp/10001/ws'],
52
+ },
53
+ ],
54
+ ddns: {
55
+ providerId: 'duckdns',
56
+ hostname: 'foo.duckdns.org',
57
+ externallyManaged: false,
58
+ lastUpdateAt: null,
59
+ lastUpdateOk: null,
60
+ lastError: null,
61
+ },
62
+ };
63
+
64
+ async function startStub(): Promise<StubServer> {
65
+ const requests: StubServer['requests'] = [];
66
+ let handler: (req: IncomingMessage, res: ServerResponse) => void = (_req, res) => {
67
+ res.statusCode = 200;
68
+ res.setHeader('content-type', 'application/json');
69
+ res.end(JSON.stringify(DEFAULT_STATUS));
70
+ };
71
+
72
+ const server = createServer((req, res) => {
73
+ const chunks: Buffer[] = [];
74
+ req.on('data', (chunk: Buffer) => chunks.push(chunk));
75
+ req.on('end', () => {
76
+ requests.push({ method: req.method ?? '', url: req.url ?? '', body: Buffer.concat(chunks).toString('utf8') });
77
+ handler(req, res);
78
+ });
79
+ });
80
+
81
+ await new Promise<void>((resolveStart) => server.listen(0, '127.0.0.1', () => resolveStart()));
82
+ const addr = server.address();
83
+ const port = typeof addr === 'object' && addr ? addr.port : 0;
84
+ return {
85
+ server,
86
+ port,
87
+ requests,
88
+ setResponse: (h) => { handler = h; },
89
+ };
90
+ }
91
+
92
+ function runCli(args: string[]): Promise<{ code: number; stdout: string; stderr: string }> {
93
+ return new Promise((resolveRun) => {
94
+ const child = spawn(process.execPath, [binPath, ...args], { stdio: ['ignore', 'pipe', 'pipe'] });
95
+ let stdout = '';
96
+ let stderr = '';
97
+ child.stdout.on('data', (chunk: Buffer) => { stdout += chunk.toString('utf8'); });
98
+ child.stderr.on('data', (chunk: Buffer) => { stderr += chunk.toString('utf8'); });
99
+ child.on('close', (code) => resolveRun({ code: code ?? -1, stdout, stderr }));
100
+ });
101
+ }
102
+
103
+ let stub: StubServer;
104
+
105
+ beforeEach(async () => {
106
+ if (!existsSync(binPath)) {
107
+ throw new Error(`cadre-host bin not built at ${binPath}; run \`yarn build\` first`);
108
+ }
109
+ stub = await startStub();
110
+ });
111
+
112
+ afterEach(async () => {
113
+ await new Promise<void>((resolveClose) => stub.server.close(() => resolveClose()));
114
+ });
115
+
116
+ describe('cadre-host nat status', () => {
117
+ it('GETs /nat/status and renders the snapshot', async () => {
118
+ const result = await runCli(['nat', 'status', '--port', String(stub.port)]);
119
+ expect(result.code).toBe(0);
120
+ expect(stub.requests).toHaveLength(1);
121
+ expect(stub.requests[0]!.method).toBe('GET');
122
+ expect(stub.requests[0]!.url).toBe('/nat/status');
123
+ expect(result.stdout).toContain('reachable');
124
+ expect(result.stdout).toContain('203.0.113.5');
125
+ expect(result.stdout).toContain('owner: mapped');
126
+ expect(result.stdout).toContain('foo.duckdns.org');
127
+ });
128
+
129
+ it('--json prints raw JSON', async () => {
130
+ const result = await runCli(['nat', 'status', '--port', String(stub.port), '--json']);
131
+ expect(result.code).toBe(0);
132
+ const parsed = JSON.parse(result.stdout);
133
+ expect(parsed.directReachability).toBe('reachable');
134
+ });
135
+
136
+ it('exits 2 when cadre-host is unreachable', async () => {
137
+ const port = stub.port;
138
+ await new Promise<void>((resolveClose) => stub.server.close(() => resolveClose()));
139
+ const result = await runCli(['nat', 'status', '--port', String(port)]);
140
+ expect(result.code).toBe(2);
141
+ expect(result.stderr).toMatch(/cadre-host start|Failed to reach/);
142
+ });
143
+ });
144
+
145
+ describe('cadre-host nat test', () => {
146
+ it('POSTs /nat/test', async () => {
147
+ const result = await runCli(['nat', 'test', '--port', String(stub.port)]);
148
+ expect(result.code).toBe(0);
149
+ expect(stub.requests[0]!.method).toBe('POST');
150
+ expect(stub.requests[0]!.url).toBe('/nat/test');
151
+ });
152
+ });
153
+
154
+ describe('cadre-host nat ddns set', () => {
155
+ it('PUTs /nat/ddns with provider + hostname + token', async () => {
156
+ const result = await runCli([
157
+ 'nat', 'ddns', 'set', 'duckdns',
158
+ '--hostname', 'foo.duckdns.org',
159
+ '--token', 'TOK',
160
+ '--port', String(stub.port),
161
+ ]);
162
+ expect(result.code).toBe(0);
163
+ expect(stub.requests[0]!.method).toBe('PUT');
164
+ expect(stub.requests[0]!.url).toBe('/nat/ddns');
165
+ const body = JSON.parse(stub.requests[0]!.body);
166
+ expect(body.providerId).toBe('duckdns');
167
+ expect(body.hostname).toBe('foo.duckdns.org');
168
+ expect(body.config).toEqual({ token: 'TOK' });
169
+ });
170
+
171
+ it('exits 1 when --hostname is missing', async () => {
172
+ const result = await runCli([
173
+ 'nat', 'ddns', 'set', 'duckdns',
174
+ '--token', 'TOK',
175
+ '--port', String(stub.port),
176
+ ]);
177
+ expect(result.code).toBe(1);
178
+ expect(result.stderr).toMatch(/--hostname/);
179
+ });
180
+
181
+ it('exits 1 when --token is missing on a non-TTY stdin', async () => {
182
+ const result = await runCli([
183
+ 'nat', 'ddns', 'set', 'duckdns',
184
+ '--hostname', 'foo.duckdns.org',
185
+ '--port', String(stub.port),
186
+ ]);
187
+ expect(result.code).toBe(1);
188
+ expect(result.stderr).toMatch(/--token/);
189
+ });
190
+ });
191
+
192
+ describe('cadre-host nat ddns external', () => {
193
+ it('PUTs /nat/settings with externallyManaged=true', async () => {
194
+ const result = await runCli([
195
+ 'nat', 'ddns', 'external',
196
+ '--hostname', 'mydomain.example.com',
197
+ '--port', String(stub.port),
198
+ ]);
199
+ expect(result.code).toBe(0);
200
+ expect(stub.requests[0]!.method).toBe('PUT');
201
+ expect(stub.requests[0]!.url).toBe('/nat/settings');
202
+ const body = JSON.parse(stub.requests[0]!.body);
203
+ expect(body.ddns.hostname).toBe('mydomain.example.com');
204
+ expect(body.ddns.externallyManaged).toBe(true);
205
+ });
206
+ });
207
+
208
+ describe('cadre-host nat settings', () => {
209
+ it('PUTs /nat/settings with --no-upnp', async () => {
210
+ const result = await runCli([
211
+ 'nat', 'settings',
212
+ '--no-upnp',
213
+ '--port', String(stub.port),
214
+ ]);
215
+ expect(result.code).toBe(0);
216
+ expect(stub.requests[0]!.url).toBe('/nat/settings');
217
+ expect(JSON.parse(stub.requests[0]!.body)).toEqual({ upnpEnabled: false });
218
+ });
219
+ });
@@ -28,7 +28,7 @@ describe('cadre-host CLI smoke test', () => {
28
28
  });
29
29
 
30
30
  expect(stdout.length).toBeGreaterThan(0);
31
- for (const cmd of ['install', 'start', 'status', 'invite', 'uninstall']) {
31
+ for (const cmd of ['install', 'start', 'status', 'uninstall']) {
32
32
  expect(stdout).toContain(cmd);
33
33
  }
34
34
  });
@@ -42,7 +42,7 @@ describe('cadre-host CLI smoke test', () => {
42
42
  encoding: 'utf8',
43
43
  });
44
44
  // The built CLI reads package.json at runtime, so this holds even against a
45
- // stale dist — it catches the version falling back to '0.0.0-unknown'.
45
+ // stale dist — it catches dist/package-version.js resolving the wrong path.
46
46
  const pkg = JSON.parse(
47
47
  readFileSync(resolve(here, '../../package.json'), 'utf8'),
48
48
  ) as { version: string };
@@ -2,9 +2,8 @@
2
2
  * Vitest global setup — runs once before the whole cadre-host suite.
3
3
  *
4
4
  * `src/update/manifest.ts` and `src/push/index.ts` import real symbols from
5
- * `@serfab/cadre-core` (`canonicalJson`, `validatePushCredentials`), and
6
- * `trust-circle-integration.test.ts` imports and drives a real `CadreNode` from
7
- * it too. `@serfab/cadre-core`'s compiled entry point in turn imports
5
+ * `@serfab/cadre-core` (`canonicalJson`, `validatePushCredentials`).
6
+ * `@serfab/cadre-core`'s compiled entry point in turn imports
8
7
  * `@serfab/quereus-plugin-sereus`, which imports the `@optimystic/*` and
9
8
  * `@quereus/quereus` packages linked in from their sibling checkouts.
10
9
  * `host-process-orchestrator.ts` also resolves `@serfab/cadre-cli`'s bin path at