@serfab/cadre-host 1.12.0 → 1.14.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 (337) hide show
  1. package/README.md +332 -423
  2. package/dist/bin/host.d.ts +6 -3
  3. package/dist/bin/host.js +301 -505
  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 +49 -0
  9. package/dist/bin/nat-output.js +127 -0
  10. package/dist/bin/nat-output.js.map +1 -0
  11. package/dist/hosted/claim-details.d.ts +44 -0
  12. package/dist/hosted/claim-details.js +66 -0
  13. package/dist/hosted/claim-details.js.map +1 -0
  14. package/dist/hosted/hosted-node-service.d.ts +318 -0
  15. package/dist/hosted/hosted-node-service.js +666 -0
  16. package/dist/hosted/hosted-node-service.js.map +1 -0
  17. package/dist/hosted/hosted-node-store.d.ts +40 -0
  18. package/dist/hosted/hosted-node-store.js +126 -0
  19. package/dist/hosted/hosted-node-store.js.map +1 -0
  20. package/dist/{donation/donation-supervisor.d.ts → hosted/hosted-node-supervisor.d.ts} +70 -53
  21. package/dist/hosted/hosted-node-supervisor.js +396 -0
  22. package/dist/hosted/hosted-node-supervisor.js.map +1 -0
  23. package/dist/hosted/hosted-node-watcher.d.ts +83 -0
  24. package/dist/hosted/hosted-node-watcher.js +224 -0
  25. package/dist/hosted/hosted-node-watcher.js.map +1 -0
  26. package/dist/hosted/index.d.ts +16 -0
  27. package/dist/hosted/index.js +13 -0
  28. package/dist/hosted/index.js.map +1 -0
  29. package/dist/hosted/node-status.d.ts +35 -0
  30. package/dist/hosted/node-status.js +61 -0
  31. package/dist/hosted/node-status.js.map +1 -0
  32. package/dist/hosted/types.d.ts +134 -0
  33. package/dist/hosted/types.js +22 -0
  34. package/dist/hosted/types.js.map +1 -0
  35. package/dist/index.d.ts +12 -24
  36. package/dist/index.js +9 -19
  37. package/dist/index.js.map +1 -1
  38. package/dist/installer/config.d.ts +4 -34
  39. package/dist/installer/config.js +3 -18
  40. package/dist/installer/config.js.map +1 -1
  41. package/dist/installer/index.d.ts +7 -19
  42. package/dist/installer/index.js +14 -69
  43. package/dist/installer/index.js.map +1 -1
  44. package/dist/installer/paths.d.ts +0 -2
  45. package/dist/installer/paths.js +0 -4
  46. package/dist/installer/paths.js.map +1 -1
  47. package/dist/installer/wizard.d.ts +0 -7
  48. package/dist/installer/wizard.js +1 -8
  49. package/dist/installer/wizard.js.map +1 -1
  50. package/dist/nat/address-resolver.d.ts +18 -17
  51. package/dist/nat/address-resolver.js +79 -25
  52. package/dist/nat/address-resolver.js.map +1 -1
  53. package/dist/nat/address-watch.d.ts +37 -0
  54. package/dist/nat/address-watch.js +84 -0
  55. package/dist/nat/address-watch.js.map +1 -0
  56. package/dist/nat/ddns/duckdns.d.ts +2 -1
  57. package/dist/nat/ddns/duckdns.js +5 -1
  58. package/dist/nat/ddns/duckdns.js.map +1 -1
  59. package/dist/nat/ddns/index.d.ts +6 -0
  60. package/dist/nat/ddns/index.js.map +1 -1
  61. package/dist/nat/index.d.ts +12 -9
  62. package/dist/nat/index.js +6 -5
  63. package/dist/nat/index.js.map +1 -1
  64. package/dist/nat/nat-service.d.ts +203 -77
  65. package/dist/nat/nat-service.js +602 -237
  66. package/dist/nat/nat-service.js.map +1 -1
  67. package/dist/nat/nat-store.d.ts +12 -5
  68. package/dist/nat/nat-store.js +114 -30
  69. package/dist/nat/nat-store.js.map +1 -1
  70. package/dist/nat/port-mapper.d.ts +83 -79
  71. package/dist/nat/port-mapper.js +148 -189
  72. package/dist/nat/port-mapper.js.map +1 -1
  73. package/dist/nat/reachability.d.ts +31 -15
  74. package/dist/nat/reachability.js +97 -22
  75. package/dist/nat/reachability.js.map +1 -1
  76. package/dist/nat/types.d.ts +78 -27
  77. package/dist/nat/types.js +8 -5
  78. package/dist/nat/types.js.map +1 -1
  79. package/dist/orchestrator/host-process-orchestrator.d.ts +29 -71
  80. package/dist/orchestrator/host-process-orchestrator.js +78 -218
  81. package/dist/orchestrator/host-process-orchestrator.js.map +1 -1
  82. package/dist/{installer/identity.d.ts → orchestrator/identity-file.d.ts} +5 -5
  83. package/dist/{installer/identity.js → orchestrator/identity-file.js} +6 -6
  84. package/dist/orchestrator/identity-file.js.map +1 -0
  85. package/dist/orchestrator/index.d.ts +2 -3
  86. package/dist/orchestrator/index.js +1 -1
  87. package/dist/orchestrator/index.js.map +1 -1
  88. package/dist/orchestrator/node-identity.d.ts +6 -6
  89. package/dist/orchestrator/node-identity.js +7 -7
  90. package/dist/orchestrator/node-identity.js.map +1 -1
  91. package/dist/orchestrator/port-allocator.d.ts +5 -6
  92. package/dist/orchestrator/port-allocator.js +9 -11
  93. package/dist/orchestrator/port-allocator.js.map +1 -1
  94. package/dist/orchestrator/state-store.d.ts +3 -5
  95. package/dist/orchestrator/state-store.js +2 -10
  96. package/dist/orchestrator/state-store.js.map +1 -1
  97. package/dist/orchestrator/types.d.ts +33 -22
  98. package/dist/orchestrator/types.js.map +1 -1
  99. package/dist/server/error-handler.d.ts +5 -25
  100. package/dist/server/error-handler.js +11 -74
  101. package/dist/server/error-handler.js.map +1 -1
  102. package/dist/server/events/types.d.ts +7 -11
  103. package/dist/server/events/types.js +2 -1
  104. package/dist/server/events/types.js.map +1 -1
  105. package/dist/server/index.d.ts +11 -37
  106. package/dist/server/index.js +30 -48
  107. package/dist/server/index.js.map +1 -1
  108. package/dist/server/routes/hosted-nodes.d.ts +28 -0
  109. package/dist/server/routes/hosted-nodes.js +68 -0
  110. package/dist/server/routes/hosted-nodes.js.map +1 -0
  111. package/dist/server/routes/nat.d.ts +4 -1
  112. package/dist/server/routes/nat.js +13 -2
  113. package/dist/server/routes/nat.js.map +1 -1
  114. package/dist/server/routes/nodes.d.ts +6 -20
  115. package/dist/server/routes/nodes.js +7 -86
  116. package/dist/server/routes/nodes.js.map +1 -1
  117. package/dist/server/routes/settings.d.ts +2 -7
  118. package/dist/server/routes/settings.js +3 -7
  119. package/dist/server/routes/settings.js.map +1 -1
  120. package/dist/server/routes/status.d.ts +2 -25
  121. package/dist/server/routes/status.js +1 -11
  122. package/dist/server/routes/status.js.map +1 -1
  123. package/dist/server/server.js +8 -8
  124. package/dist/server/settings-store.d.ts +2 -2
  125. package/dist/server/settings-store.js +2 -2
  126. package/dist/server/static.js +1 -2
  127. package/dist/server/static.js.map +1 -1
  128. package/dist/ui/assets/index-4FWuU8ye.js +19 -0
  129. package/dist/ui/assets/index-4FWuU8ye.js.map +1 -0
  130. package/dist/ui/assets/index-Di9Q4d01.css +1 -0
  131. package/dist/ui/index.html +2 -2
  132. package/dist/update/index.d.ts +2 -2
  133. package/dist/update/index.js +2 -2
  134. package/dist/update/store.d.ts +1 -1
  135. package/dist/update/store.js +1 -1
  136. package/dist/update/types.d.ts +1 -1
  137. package/dist/update/types.js +1 -1
  138. package/package.json +5 -6
  139. package/src/__tests__/cli-nat.smoke.test.ts +219 -212
  140. package/src/__tests__/cli.smoke.test.ts +1 -1
  141. package/src/__tests__/global-setup.ts +2 -3
  142. package/src/__tests__/orchestrator-claim-secret.test.ts +112 -0
  143. package/src/__tests__/orchestrator-handle-contract.ts +134 -134
  144. package/src/__tests__/orchestrator-node-identity.test.ts +182 -203
  145. package/src/__tests__/orchestrator-ports.test.ts +124 -143
  146. package/src/__tests__/orchestrator-push.test.ts +138 -146
  147. package/src/__tests__/orchestrator.test.ts +1019 -1063
  148. package/src/bin/host.ts +368 -553
  149. package/src/bin/join-output.ts +120 -0
  150. package/src/bin/nat-output.ts +177 -0
  151. package/src/{donation → hosted}/__tests__/fake-orchestrator.test.ts +173 -173
  152. package/src/{donation → hosted}/__tests__/fake-orchestrator.ts +265 -243
  153. package/src/hosted/__tests__/hosted-node-service.test.ts +609 -0
  154. package/src/hosted/__tests__/hosted-node-supervisor.test.ts +474 -0
  155. package/src/hosted/__tests__/test-invitation.ts +33 -0
  156. package/src/hosted/claim-details.ts +96 -0
  157. package/src/hosted/hosted-node-service.ts +795 -0
  158. package/src/hosted/hosted-node-store.ts +144 -0
  159. package/src/hosted/hosted-node-supervisor.ts +439 -0
  160. package/src/hosted/hosted-node-watcher.ts +250 -0
  161. package/src/hosted/index.ts +53 -0
  162. package/src/hosted/node-status.ts +71 -0
  163. package/src/hosted/types.ts +153 -0
  164. package/src/index.ts +72 -91
  165. package/src/installer/__tests__/config.test.ts +15 -40
  166. package/src/installer/__tests__/installer.smoke.test.ts +5 -86
  167. package/src/installer/__tests__/wizard.test.ts +56 -64
  168. package/src/installer/config.ts +135 -175
  169. package/src/installer/index.ts +15 -83
  170. package/src/installer/paths.ts +104 -109
  171. package/src/installer/wizard.ts +87 -103
  172. package/src/nat/__tests__/address-resolver.test.ts +107 -82
  173. package/src/nat/__tests__/nat-service.test.ts +433 -408
  174. package/src/nat/__tests__/nat-store.test.ts +127 -93
  175. package/src/nat/__tests__/port-mapper.test.ts +30 -191
  176. package/src/nat/__tests__/reachability.test.ts +96 -13
  177. package/src/nat/address-resolver.ts +94 -52
  178. package/src/nat/address-watch.ts +92 -0
  179. package/src/nat/ddns/duckdns.ts +5 -1
  180. package/src/nat/ddns/index.ts +6 -0
  181. package/src/nat/index.ts +87 -71
  182. package/src/nat/nat-service.ts +889 -501
  183. package/src/nat/nat-store.ts +237 -154
  184. package/src/nat/port-mapper.ts +241 -329
  185. package/src/nat/reachability.ts +134 -25
  186. package/src/nat/types.ts +209 -159
  187. package/src/{installer/__tests__/identity.test.ts → orchestrator/__tests__/identity-file.test.ts} +34 -34
  188. package/src/orchestrator/__tests__/node-identity.test.ts +62 -62
  189. package/src/orchestrator/host-process-orchestrator.ts +81 -243
  190. package/src/{installer/identity.ts → orchestrator/identity-file.ts} +56 -56
  191. package/src/orchestrator/index.ts +9 -10
  192. package/src/orchestrator/node-identity.ts +41 -41
  193. package/src/orchestrator/port-allocator.ts +71 -73
  194. package/src/orchestrator/state-store.ts +76 -90
  195. package/src/orchestrator/types.ts +34 -23
  196. package/src/server/__tests__/bus.test.ts +38 -38
  197. package/src/server/__tests__/error-handler.test.ts +81 -118
  198. package/src/server/__tests__/fakes.ts +40 -44
  199. package/src/server/__tests__/hosted-nodes-route.test.ts +160 -0
  200. package/src/server/__tests__/nodes-route.test.ts +114 -283
  201. package/src/server/__tests__/publishers.test.ts +193 -180
  202. package/src/server/__tests__/server.smoke.test.ts +134 -223
  203. package/src/server/__tests__/settings-route.test.ts +179 -195
  204. package/src/server/__tests__/sse-route.test.ts +119 -119
  205. package/src/server/__tests__/status-route.test.ts +82 -121
  206. package/src/server/error-handler.ts +112 -178
  207. package/src/server/events/types.ts +20 -24
  208. package/src/server/index.ts +223 -267
  209. package/src/server/routes/hosted-nodes.ts +83 -0
  210. package/src/server/routes/nat.ts +75 -63
  211. package/src/server/routes/nodes.ts +96 -188
  212. package/src/server/routes/settings.ts +115 -123
  213. package/src/server/routes/status.ts +102 -134
  214. package/src/server/server.ts +8 -8
  215. package/src/server/settings-store.ts +2 -2
  216. package/src/server/static.ts +1 -2
  217. package/src/update/index.ts +2 -2
  218. package/src/update/store.ts +1 -1
  219. package/src/update/types.ts +1 -1
  220. package/dist/auth/duration.d.ts +0 -1
  221. package/dist/auth/duration.js +0 -32
  222. package/dist/auth/duration.js.map +0 -1
  223. package/dist/auth/index.d.ts +0 -11
  224. package/dist/auth/index.js +0 -9
  225. package/dist/auth/index.js.map +0 -1
  226. package/dist/auth/self-label.d.ts +0 -36
  227. package/dist/auth/self-label.js +0 -57
  228. package/dist/auth/self-label.js.map +0 -1
  229. package/dist/auth/trust-circle-store.d.ts +0 -26
  230. package/dist/auth/trust-circle-store.js +0 -129
  231. package/dist/auth/trust-circle-store.js.map +0 -1
  232. package/dist/auth/trust-circle.d.ts +0 -156
  233. package/dist/auth/trust-circle.js +0 -307
  234. package/dist/auth/trust-circle.js.map +0 -1
  235. package/dist/auth/types.d.ts +0 -84
  236. package/dist/auth/types.js +0 -24
  237. package/dist/auth/types.js.map +0 -1
  238. package/dist/donation/donation-service.d.ts +0 -389
  239. package/dist/donation/donation-service.js +0 -828
  240. package/dist/donation/donation-service.js.map +0 -1
  241. package/dist/donation/donation-store.d.ts +0 -51
  242. package/dist/donation/donation-store.js +0 -152
  243. package/dist/donation/donation-store.js.map +0 -1
  244. package/dist/donation/donation-supervisor.js +0 -364
  245. package/dist/donation/donation-supervisor.js.map +0 -1
  246. package/dist/donation/grant-service.d.ts +0 -80
  247. package/dist/donation/grant-service.js +0 -210
  248. package/dist/donation/grant-service.js.map +0 -1
  249. package/dist/donation/grant-store.d.ts +0 -38
  250. package/dist/donation/grant-store.js +0 -135
  251. package/dist/donation/grant-store.js.map +0 -1
  252. package/dist/donation/index.d.ts +0 -20
  253. package/dist/donation/index.js +0 -17
  254. package/dist/donation/index.js.map +0 -1
  255. package/dist/donation/types.d.ts +0 -224
  256. package/dist/donation/types.js +0 -40
  257. package/dist/donation/types.js.map +0 -1
  258. package/dist/installer/identity.js.map +0 -1
  259. package/dist/owner/index.d.ts +0 -11
  260. package/dist/owner/index.js +0 -11
  261. package/dist/owner/index.js.map +0 -1
  262. package/dist/owner/owner-node-client.d.ts +0 -110
  263. package/dist/owner/owner-node-client.js +0 -184
  264. package/dist/owner/owner-node-client.js.map +0 -1
  265. package/dist/server/routes/bootstrap-node-validation.d.ts +0 -115
  266. package/dist/server/routes/bootstrap-node-validation.js +0 -197
  267. package/dist/server/routes/bootstrap-node-validation.js.map +0 -1
  268. package/dist/server/routes/grants-admin.d.ts +0 -29
  269. package/dist/server/routes/grants-admin.js +0 -58
  270. package/dist/server/routes/grants-admin.js.map +0 -1
  271. package/dist/server/routes/grants.d.ts +0 -28
  272. package/dist/server/routes/grants.js +0 -165
  273. package/dist/server/routes/grants.js.map +0 -1
  274. package/dist/server/routes/provision-request-validation.d.ts +0 -45
  275. package/dist/server/routes/provision-request-validation.js +0 -97
  276. package/dist/server/routes/provision-request-validation.js.map +0 -1
  277. package/dist/server/routes/strands.d.ts +0 -20
  278. package/dist/server/routes/strands.js +0 -38
  279. package/dist/server/routes/strands.js.map +0 -1
  280. package/dist/server/routes/trust-circle.d.ts +0 -17
  281. package/dist/server/routes/trust-circle.js +0 -35
  282. package/dist/server/routes/trust-circle.js.map +0 -1
  283. package/dist/strands/index.d.ts +0 -7
  284. package/dist/strands/index.js +0 -6
  285. package/dist/strands/index.js.map +0 -1
  286. package/dist/strands/strand-service.d.ts +0 -50
  287. package/dist/strands/strand-service.js +0 -103
  288. package/dist/strands/strand-service.js.map +0 -1
  289. package/dist/strands/types.d.ts +0 -93
  290. package/dist/strands/types.js +0 -23
  291. package/dist/strands/types.js.map +0 -1
  292. package/dist/ui/assets/index-C6nELNfC.js +0 -23
  293. package/dist/ui/assets/index-C6nELNfC.js.map +0 -1
  294. package/dist/ui/assets/index-TtIYSeZO.css +0 -1
  295. package/src/__tests__/cli-invite.smoke.test.ts +0 -192
  296. package/src/__tests__/host-owner.smoke.test.ts +0 -123
  297. package/src/__tests__/orchestrator-owner.test.ts +0 -234
  298. package/src/__tests__/orchestrator-pin-keys.test.ts +0 -152
  299. package/src/auth/__tests__/duration.test.ts +0 -28
  300. package/src/auth/__tests__/self-label.test.ts +0 -85
  301. package/src/auth/__tests__/trust-circle-integration.test.ts +0 -152
  302. package/src/auth/__tests__/trust-circle-store.test.ts +0 -115
  303. package/src/auth/__tests__/trust-circle.test.ts +0 -445
  304. package/src/auth/duration.ts +0 -33
  305. package/src/auth/index.ts +0 -21
  306. package/src/auth/self-label.ts +0 -74
  307. package/src/auth/trust-circle-store.ts +0 -155
  308. package/src/auth/trust-circle.ts +0 -395
  309. package/src/auth/types.ts +0 -99
  310. package/src/donation/__tests__/donation-service.test.ts +0 -1193
  311. package/src/donation/__tests__/donation-supervisor.test.ts +0 -548
  312. package/src/donation/__tests__/grant-service.test.ts +0 -213
  313. package/src/donation/__tests__/grant-store.test.ts +0 -113
  314. package/src/donation/donation-service.ts +0 -1033
  315. package/src/donation/donation-store.ts +0 -176
  316. package/src/donation/donation-supervisor.ts +0 -411
  317. package/src/donation/grant-service.ts +0 -252
  318. package/src/donation/grant-store.ts +0 -152
  319. package/src/donation/index.ts +0 -65
  320. package/src/donation/types.ts +0 -260
  321. package/src/owner/__tests__/owner-node-client.test.ts +0 -194
  322. package/src/owner/index.ts +0 -12
  323. package/src/owner/owner-node-client.ts +0 -259
  324. package/src/server/__tests__/bootstrap-node-validation.test.ts +0 -138
  325. package/src/server/__tests__/grants-admin-route.test.ts +0 -171
  326. package/src/server/__tests__/grants-route.test.ts +0 -394
  327. package/src/server/__tests__/strands-route.test.ts +0 -234
  328. package/src/server/routes/bootstrap-node-validation.ts +0 -206
  329. package/src/server/routes/grants-admin.ts +0 -74
  330. package/src/server/routes/grants.ts +0 -193
  331. package/src/server/routes/provision-request-validation.ts +0 -105
  332. package/src/server/routes/strands.ts +0 -54
  333. package/src/server/routes/trust-circle.ts +0 -49
  334. package/src/strands/__tests__/strand-service.test.ts +0 -165
  335. package/src/strands/index.ts +0 -14
  336. package/src/strands/strand-service.ts +0 -135
  337. package/src/strands/types.ts +0 -102
@@ -1,225 +1,184 @@
1
+ import { BlockList } from 'node:net';
2
+ import { networkInterfaces } from 'node:os';
1
3
  import debug from 'debug';
4
+ import { upnpNat } from '@achingbrain/nat-port-mapper';
2
5
  import { NatError } from './types.js';
3
6
  const log = debug('cadre:host:nat-port-mapper');
4
- /** Default lease TTL: 1 hour. The router must keep our mapping at least this long. */
7
+ /**
8
+ * Default lease TTL: 1 hour. `@achingbrain/nat-port-mapper` takes the TTL in
9
+ * milliseconds and floors the lease it asks the router for at 3600 s, so a
10
+ * shorter value here would still lease an hour.
11
+ */
5
12
  export const DEFAULT_LEASE_TTL_MS = 60 * 60 * 1000;
6
- /** Default refresh cadence: half the TTL, so two refreshes per lease. */
13
+ /** Default renewal cadence: half the TTL, so two renewals per lease. */
7
14
  export const DEFAULT_REFRESH_MS = 30 * 60 * 1000;
15
+ /** How long to listen for a UPnP gateway's SSDP answer before giving up. */
16
+ export const GATEWAY_DISCOVERY_TIMEOUT_MS = 10000;
17
+ /** Bound on one SOAP call to the router (map, unmap, external IP). */
18
+ export const GATEWAY_OPERATION_TIMEOUT_MS = 10000;
19
+ /** Signal that aborts after `ms`; the timer is cleared by `done()` so it never holds the process open. */
20
+ function deadline(ms) {
21
+ const controller = new AbortController();
22
+ const timer = setTimeout(() => controller.abort(new Error(`timed out after ${ms} ms`)), ms);
23
+ timer.unref();
24
+ return { signal: controller.signal, done: () => clearTimeout(timer) };
25
+ }
8
26
  /**
9
- * Default factory: loads @achingbrain/nat-port-mapper. Wrapped in dynamic
10
- * import so a missing dep at install time doesn't crash the package.
27
+ * Pick the IPv4 address of the local interface whose subnet contains the router.
28
+ *
29
+ * Not `mapAll`: that maps on every local address and leaves stray mappings for
30
+ * VPN and container interfaces. The address returned is the one a user is told
31
+ * to forward to, so it must be the one on the router's own network.
11
32
  */
12
- export async function createDefaultPortMapper(opts = {}) {
13
- let mod;
14
- try {
15
- mod = (await import('@achingbrain/nat-port-mapper'));
16
- }
17
- catch (err) {
18
- throw new NatError('mapping_failed', `@achingbrain/nat-port-mapper is not installed: ${err.message}`);
19
- }
20
- let client;
21
- try {
22
- client = await mod.upnpNat({
33
+ export function pickLanAddress(routerHost, interfaces = networkInterfaces()) {
34
+ for (const entries of Object.values(interfaces)) {
35
+ for (const entry of entries ?? []) {
36
+ if (entry.family !== 'IPv4' || entry.internal || !entry.cidr)
37
+ continue;
38
+ const prefix = Number(entry.cidr.split('/')[1]);
39
+ if (!Number.isInteger(prefix))
40
+ continue;
41
+ const subnet = new BlockList();
42
+ try {
43
+ subnet.addSubnet(entry.address, prefix, 'ipv4');
44
+ if (subnet.check(routerHost, 'ipv4'))
45
+ return entry.address;
46
+ }
47
+ catch (err) {
48
+ log('skipping interface entry %s (%s): %s', entry.address, entry.cidr, err.message);
49
+ }
50
+ }
51
+ }
52
+ return null;
53
+ }
54
+ /**
55
+ * UPnP port mapper over `@achingbrain/nat-port-mapper` v4: `upnpNat()` hands
56
+ * out a client that discovers gateways; mapping, unmapping and the external IP
57
+ * live on the discovered `Gateway`.
58
+ *
59
+ * The library's auto-refresh stays off: cadre-host renews leases itself so it
60
+ * can report lease expiry and per-mapping failures.
61
+ */
62
+ export class UpnpPortMapper {
63
+ constructor(opts = {}) {
64
+ this.gateway = null;
65
+ this.lanAddress = null;
66
+ this.client = upnpNat({
23
67
  description: opts.description ?? 'sereus-cadre-host',
24
- ttl: Math.round((opts.ttlMs ?? DEFAULT_LEASE_TTL_MS) / 1000),
68
+ autoRefresh: false,
25
69
  });
26
70
  }
27
- catch (err) {
28
- throw new NatError('mapping_failed', `upnpNat() failed: ${err.message}`);
29
- }
30
- return new NatPortMapperAdapter(client, opts.ttlMs ?? DEFAULT_LEASE_TTL_MS);
31
- }
32
- class NatPortMapperAdapter {
33
- constructor(client, defaultTtlMs) {
34
- this.client = client;
35
- this.defaultTtlMs = defaultTtlMs;
36
- }
37
- async map(opts) {
38
- const ttlMs = opts.ttlMs ?? this.defaultTtlMs;
39
- const protocol = opts.protocol ?? 'tcp';
40
- let externalIp = null;
41
- try {
42
- externalIp = await this.client.externalIp();
43
- }
44
- catch (err) {
45
- log('externalIp() failed: %s', err.message);
46
- }
71
+ async discover() {
72
+ const gateway = await this.findIpv4Gateway();
73
+ if (!gateway)
74
+ return null;
75
+ const lanAddress = pickLanAddress(gateway.host);
76
+ if (!lanAddress) {
77
+ throw new NatError('router_unreachable', `found a UPnP router at ${gateway.host} but no local IPv4 interface shares its subnet`);
78
+ }
79
+ this.gateway = gateway;
80
+ this.lanAddress = lanAddress;
81
+ log('discovered gateway %s (%s), mapping from %s', gateway.id, gateway.host, lanAddress);
82
+ return { lanAddress, routerHost: gateway.host };
83
+ }
84
+ async map(req) {
85
+ const { gateway, lanAddress } = this.requireGateway();
86
+ const op = deadline(GATEWAY_OPERATION_TIMEOUT_MS);
47
87
  try {
48
- await this.client.map({
49
- localPort: opts.internalPort,
50
- externalPort: opts.externalPort,
51
- protocol,
52
- ttl: Math.round(ttlMs / 1000),
88
+ const mapping = await gateway.map(req.internalPort, lanAddress, {
89
+ externalPort: req.internalPort,
90
+ protocol: req.protocol,
91
+ ttl: req.ttlMs,
92
+ autoRefresh: false,
93
+ signal: op.signal,
53
94
  });
95
+ return { externalPort: mapping.externalPort, leaseExpiresAt: new Date(Date.now() + req.ttlMs) };
54
96
  }
55
97
  catch (err) {
56
- throw new NatError('mapping_failed', `router refused mapping for port ${opts.externalPort}: ${err.message}`);
57
- }
58
- return {
59
- mode: 'auto-upnp',
60
- externalIp,
61
- externalPort: opts.externalPort,
62
- internalPort: opts.internalPort,
63
- protocol,
64
- leaseExpiresAt: new Date(Date.now() + ttlMs),
65
- };
66
- }
67
- async verify(externalPort, protocol = 'tcp') {
68
- void externalPort;
69
- void protocol;
70
- // The current library doesn't expose an introspection API. Treat a
71
- // working externalIp() as a proxy for "router still reachable" — refresh
72
- // failures will surface via re-running map().
98
+ throw new NatError('mapping_failed', `router refused the mapping for port ${req.internalPort}: ${err.message}`);
99
+ }
100
+ finally {
101
+ op.done();
102
+ }
103
+ }
104
+ // NOTE: the library tracks the mappings this process made and `unmap` only sends a
105
+ // delete for those, so after a host restart a port mapped by the previous process is
106
+ // left to expire with its lease rather than deleted. It also names the INTERNAL port
107
+ // as the external one in that delete, so a mapping the router granted on another
108
+ // external port is not deleted either; it, too, expires with its lease (1 h). And it
109
+ // appends one tracked entry per successful `map` of a port, so after N renewals an
110
+ // unmap sends N deletes (the first is the one that counts); they all run under the
111
+ // one 10 s bound, which caps the cost of a process that has renewed for days.
112
+ async unmap(internalPort, _protocol) {
113
+ if (!this.gateway)
114
+ return;
115
+ const op = deadline(GATEWAY_OPERATION_TIMEOUT_MS);
73
116
  try {
74
- await this.client.externalIp();
75
- return true;
117
+ await this.gateway.unmap(internalPort, { signal: op.signal });
76
118
  }
77
119
  catch (err) {
78
- log('verify() failed: %s', err.message);
79
- return false;
120
+ log('unmap(%d) failed: %s', internalPort, err.message);
121
+ }
122
+ finally {
123
+ op.done();
80
124
  }
81
125
  }
82
126
  async externalIp() {
127
+ if (!this.gateway)
128
+ return null;
129
+ const op = deadline(GATEWAY_OPERATION_TIMEOUT_MS);
83
130
  try {
84
- return await this.client.externalIp();
131
+ return await this.gateway.externalIp({ signal: op.signal });
85
132
  }
86
133
  catch (err) {
87
134
  log('externalIp() failed: %s', err.message);
88
135
  return null;
89
136
  }
90
- }
91
- async unmap(externalPort, protocol = 'tcp') {
92
- try {
93
- await this.client.unmap({ externalPort, protocol });
94
- }
95
- catch (err) {
96
- log('unmap(%d) failed: %s', externalPort, err.message);
97
- }
98
- }
99
- async stop() {
100
- try {
101
- await this.client.stop();
137
+ finally {
138
+ op.done();
102
139
  }
103
- catch (err) {
104
- log('stop() failed: %s', err.message);
105
- }
106
- }
107
- }
108
- /**
109
- * Long-running orchestrator over a PortMapper. Owns the refresh timer and
110
- * surfaces the latest state for the NatService snapshot.
111
- */
112
- export class PortMapperService {
113
- constructor(opts) {
114
- this.refreshHandle = null;
115
- this.started = false;
116
- this.mapper = opts.mapper;
117
- this.externalPort = opts.externalPort;
118
- this.internalPort = opts.internalPort;
119
- this.protocol = opts.protocol ?? 'tcp';
120
- this.ttlMs = opts.ttlMs ?? DEFAULT_LEASE_TTL_MS;
121
- this.refreshMs = opts.refreshMs ?? DEFAULT_REFRESH_MS;
122
- this.nowFn = opts.now ?? (() => new Date());
123
- this.setTimer = opts.setTimer ?? ((fn, ms) => setTimeout(fn, ms));
124
- this.clearTimer = opts.clearTimer ?? ((h) => clearTimeout(h));
125
- this.state = {
126
- mode: 'disabled',
127
- externalPort: this.externalPort,
128
- internalPort: this.internalPort,
129
- routerExternalIp: null,
130
- leaseExpiresAt: null,
131
- lastError: null,
132
- };
133
140
  }
134
- getState() {
135
- return { ...this.state };
136
- }
137
- /** Install the mapping and schedule periodic refresh. */
138
- async start() {
139
- if (this.started)
140
- return;
141
- this.started = true;
142
- await this.installMapping();
143
- this.scheduleRefresh();
144
- }
145
- /** Release the mapping and clear timers. Idempotent. */
141
+ /**
142
+ * Forget the gateway. Deliberately not `gateway.stop()`: that deletes every
143
+ * mapping this process made, and hosted children keep running across a host
144
+ * restart, so their mappings must outlive this process.
145
+ */
146
146
  async stop() {
147
- if (!this.started)
148
- return;
149
- this.started = false;
150
- if (this.refreshHandle) {
151
- this.clearTimer(this.refreshHandle);
152
- this.refreshHandle = null;
153
- }
147
+ this.gateway = null;
148
+ this.lanAddress = null;
149
+ }
150
+ requireGateway() {
151
+ if (!this.gateway || !this.lanAddress) {
152
+ throw new NatError('router_unreachable', 'no UPnP gateway discovered');
153
+ }
154
+ return { gateway: this.gateway, lanAddress: this.lanAddress };
155
+ }
156
+ /**
157
+ * First IPv4 gateway to answer the SSDP search, or null when none did within
158
+ * the timeout.
159
+ *
160
+ * NOTE: the library searches for `InternetGatewayDevice:2` only (its
161
+ * `upnp/discovery.js`), and a router that implements only version 1 does not
162
+ * answer a version-2 search, so such a router reads as "not found". There is
163
+ * no library option for it; if it shows up on real hosts, the fix is a fork or
164
+ * another library.
165
+ */
166
+ async findIpv4Gateway() {
167
+ const search = deadline(GATEWAY_DISCOVERY_TIMEOUT_MS);
154
168
  try {
155
- await this.mapper.unmap(this.externalPort, this.protocol);
156
- }
157
- catch (err) {
158
- log('unmap during stop failed: %s', err.message);
159
- }
160
- try {
161
- await this.mapper.stop();
169
+ for await (const gateway of this.client.findGateways({ signal: search.signal })) {
170
+ if (gateway.family === 'IPv4')
171
+ return gateway;
172
+ }
173
+ return null;
162
174
  }
163
175
  catch (err) {
164
- log('mapper.stop() failed: %s', err.message);
165
- }
166
- this.state = {
167
- ...this.state,
168
- mode: 'disabled',
169
- routerExternalIp: null,
170
- leaseExpiresAt: null,
171
- };
172
- }
173
- /** Force an immediate verify+refresh cycle (used by testReachability). */
174
- async refresh() {
175
- if (!this.started)
176
- return this.getState();
177
- const ok = await this.mapper.verify(this.externalPort, this.protocol).catch(() => false);
178
- if (!ok) {
179
- log('verify() returned false; re-mapping');
180
- await this.installMapping();
181
- return this.getState();
176
+ if (search.signal.aborted)
177
+ return null;
178
+ throw new NatError('router_unreachable', `UPnP discovery failed: ${err.message}`);
182
179
  }
183
- // Refresh: re-issue the mapping to extend the lease.
184
- await this.installMapping();
185
- return this.getState();
186
- }
187
- scheduleRefresh() {
188
- if (this.refreshHandle)
189
- this.clearTimer(this.refreshHandle);
190
- this.refreshHandle = this.setTimer(() => {
191
- void this.refresh().catch((err) => log('refresh timer error: %s', err.message));
192
- // Re-arm after the call to avoid drift.
193
- this.scheduleRefresh();
194
- }, this.refreshMs);
195
- }
196
- async installMapping() {
197
- try {
198
- const r = await this.mapper.map({
199
- externalPort: this.externalPort,
200
- internalPort: this.internalPort,
201
- protocol: this.protocol,
202
- ttlMs: this.ttlMs,
203
- });
204
- this.state = {
205
- mode: r.mode,
206
- externalPort: r.externalPort,
207
- internalPort: r.internalPort,
208
- routerExternalIp: r.externalIp,
209
- leaseExpiresAt: r.leaseExpiresAt,
210
- lastError: null,
211
- };
212
- log('mapped port %d (mode=%s, externalIp=%s)', r.externalPort, r.mode, r.externalIp ?? '?');
213
- }
214
- catch (err) {
215
- const message = err.message;
216
- this.state = {
217
- ...this.state,
218
- mode: 'failed',
219
- leaseExpiresAt: null,
220
- lastError: message,
221
- };
222
- log('mapping failed: %s', message);
180
+ finally {
181
+ search.done();
223
182
  }
224
183
  }
225
184
  }
@@ -1 +1 @@
1
- {"version":3,"file":"port-mapper.js","sourceRoot":"","sources":["../../src/nat/port-mapper.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"port-mapper.js","sourceRoot":"","sources":["../../src/nat/port-mapper.ts"],"names":[],"mappings":"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"}
@@ -1,19 +1,35 @@
1
- import type { DirectReachability, PortForwardMode } from './types.js';
2
- export interface ReachabilityInput {
3
- portMode: PortForwardMode;
1
+ /**
2
+ * Reachability verdicts: one per hosted node, and the host-level roll-up the
3
+ * dashboard badge shows. Heuristics over the mapping table, not a dial-back —
4
+ * libp2p AutoNAT is a later ticket.
5
+ */
6
+ import type { DirectReachability, NodeReachability, NodeVerdict, PortRoute } from './types.js';
7
+ export interface NodeVerdictInput {
8
+ tcp: PortRoute;
9
+ /** Null for a handle persisted by an older build without a WebSocket port. */
10
+ ws: PortRoute | null;
11
+ /** Whether a public host part exists: a DDNS hostname, or a public IPv4. */
12
+ hostKnown: boolean;
4
13
  cgnatDetected: boolean;
14
+ upnpEnabled: boolean;
15
+ gatewayFound: boolean;
16
+ /** The address a user forwards to; null when no gateway was found. */
17
+ lanAddress: string | null;
18
+ }
19
+ export interface NodeVerdictResult {
20
+ verdict: NodeVerdict;
21
+ reason: string | null;
5
22
  }
6
23
  /**
7
- * v1 reachability heuristic.
8
- *
9
- * Returns:
10
- * - 'cgnat' when CGNAT was detected (highest signal — UPnP succeeded but our
11
- * external IP isn't actually reachable from the open internet).
12
- * - 'unreachable' when port mapping failed.
13
- * - 'reachable' when an auto mapping succeeded.
14
- * - 'unknown' otherwise (manual config, disabled UPnP, etc).
15
- *
16
- * A future ticket will replace this with libp2p AutoNAT or a sereus-owned
17
- * dial-back probe (see the follow-up section of `6.3-cadre-host-nat`).
24
+ * `unreachable` when either port has no usable route or the host part is
25
+ * unknown; otherwise `manual` when either port is forwarded by hand, else
26
+ * `mapped`. A UPnP route under CGNAT is not usable: the router's mapping is on
27
+ * a carrier-private address.
28
+ */
29
+ export declare function evaluateNodeReachability(input: NodeVerdictInput): NodeVerdictResult;
30
+ /**
31
+ * Host roll-up: `cgnat` when CGNAT is detected and no node is reachable
32
+ * through a manual route; `unknown` with no running nodes; `reachable` when
33
+ * every running node is `mapped`/`manual`; else `unreachable`.
18
34
  */
19
- export declare function evaluateReachability(input: ReachabilityInput): DirectReachability;
35
+ export declare function evaluateHostReachability(nodes: ReadonlyArray<Pick<NodeReachability, 'running' | 'verdict'>>, cgnatDetected: boolean): DirectReachability;
@@ -1,29 +1,104 @@
1
1
  /**
2
- * v1 reachability heuristic.
3
- *
4
- * Returns:
5
- * - 'cgnat' when CGNAT was detected (highest signal — UPnP succeeded but our
6
- * external IP isn't actually reachable from the open internet).
7
- * - 'unreachable' when port mapping failed.
8
- * - 'reachable' when an auto mapping succeeded.
9
- * - 'unknown' otherwise (manual config, disabled UPnP, etc).
10
- *
11
- * A future ticket will replace this with libp2p AutoNAT or a sereus-owned
12
- * dial-back probe (see the follow-up section of `6.3-cadre-host-nat`).
2
+ * Reachability verdicts: one per hosted node, and the host-level roll-up the
3
+ * dashboard badge shows. Heuristics over the mapping table, not a dial-back —
4
+ * libp2p AutoNAT is a later ticket.
13
5
  */
14
- export function evaluateReachability(input) {
6
+ /**
7
+ * `unreachable` when either port has no usable route or the host part is
8
+ * unknown; otherwise `manual` when either port is forwarded by hand, else
9
+ * `mapped`. A UPnP route under CGNAT is not usable: the router's mapping is on
10
+ * a carrier-private address.
11
+ */
12
+ export function evaluateNodeReachability(input) {
13
+ const ports = portRoutes(input);
14
+ const failing = ports.filter(({ route }) => !usable(route, input.cgnatDetected));
15
+ if (!input.hostKnown) {
16
+ return { verdict: 'unreachable', reason: HOST_UNKNOWN_REASON };
17
+ }
18
+ if (failing.length > 0) {
19
+ return { verdict: 'unreachable', reason: describeFailures(failing, input) };
20
+ }
21
+ const manual = ports.some(({ route }) => route.source === 'manual');
22
+ return { verdict: manual ? 'manual' : 'mapped', reason: null };
23
+ }
24
+ /**
25
+ * Host roll-up: `cgnat` when CGNAT is detected and no node is reachable
26
+ * through a manual route; `unknown` with no running nodes; `reachable` when
27
+ * every running node is `mapped`/`manual`; else `unreachable`.
28
+ */
29
+ export function evaluateHostReachability(nodes, cgnatDetected) {
30
+ const running = nodes.filter((n) => n.running);
31
+ if (cgnatDetected && !running.some((n) => n.verdict === 'manual'))
32
+ return 'cgnat';
33
+ if (running.length === 0)
34
+ return 'unknown';
35
+ return running.every((n) => n.verdict !== 'unreachable') ? 'reachable' : 'unreachable';
36
+ }
37
+ const HOST_UNKNOWN_REASON = "This host's public address is unknown: no dynamic DNS hostname is set and no public IPv4 address was detected. " +
38
+ 'Set a DDNS hostname, or check that this machine can reach the internet.';
39
+ function portRoutes(input) {
40
+ const out = [{ kind: 'tcp', route: input.tcp }];
41
+ if (input.ws)
42
+ out.push({ kind: 'ws', route: input.ws });
43
+ return out;
44
+ }
45
+ function usable(route, cgnatDetected) {
46
+ if (route.externalPort === null || route.source === null)
47
+ return false;
48
+ return !(cgnatDetected && route.source === 'upnp');
49
+ }
50
+ /** Behind CGNAT no router-side remedy helps, so CGNAT outranks whatever else failed the port. */
51
+ function causeOf(route, input) {
15
52
  if (input.cgnatDetected)
16
53
  return 'cgnat';
17
- switch (input.portMode) {
18
- case 'auto-upnp':
19
- case 'auto-natpmp':
20
- return 'reachable';
21
- case 'failed':
22
- return 'unreachable';
23
- case 'manual':
24
- case 'disabled':
25
- default:
26
- return 'unknown';
54
+ if (route.error)
55
+ return 'refused';
56
+ if (!input.upnpEnabled)
57
+ return 'upnp_off';
58
+ if (!input.gatewayFound)
59
+ return 'no_gateway';
60
+ return 'pending';
61
+ }
62
+ /** One sentence per distinct cause, each naming every port that failed for it. */
63
+ function describeFailures(failing, input) {
64
+ const byCause = new Map();
65
+ for (const entry of failing) {
66
+ const cause = causeOf(entry.route, input);
67
+ byCause.set(cause, [...(byCause.get(cause) ?? []), entry]);
68
+ }
69
+ return [...byCause.entries()].map(([cause, entries]) => describeCause(cause, entries, input)).join(' ');
70
+ }
71
+ function describeCause(cause, entries, input) {
72
+ const names = entries.map(({ kind, route }) => `${kindLabel(kind)} port ${route.internalPort}`);
73
+ const lan = input.lanAddress ?? "this machine's LAN address";
74
+ const forwardHint = `Forward ${entries.length === 1 ? 'port' : 'ports'} ${listPorts(entries)} to ${lan} on your router, then tell cadre-host the external ${entries.length === 1 ? 'port' : 'ports'}.`;
75
+ switch (cause) {
76
+ case 'cgnat':
77
+ return `This host is behind carrier-grade NAT, so the ${joinNames(names)} cannot be reached from outside through your router, and neither UPnP nor a port forward on your router will help; a relay is needed.`;
78
+ case 'refused': {
79
+ const errors = entries.map(({ route }) => route.error).filter((e) => !!e);
80
+ return `Router refused the ${joinNames(names)} mapping (${errors.join('; ')}). ${forwardHint}`;
81
+ }
82
+ case 'upnp_off':
83
+ return `UPnP is off, so the ${joinNames(names)} ${entries.length === 1 ? 'is' : 'are'} not mapped. Turn UPnP on, or: ${lowerFirst(forwardHint)}`;
84
+ case 'no_gateway':
85
+ return `No UPnP router answered, so the ${joinNames(names)} ${entries.length === 1 ? 'is' : 'are'} not mapped. Enable UPnP on your router, or: ${lowerFirst(forwardHint)}`;
86
+ case 'pending':
87
+ return `The ${joinNames(names)} ${entries.length === 1 ? 'is' : 'are'} not mapped yet; the router is being asked.`;
27
88
  }
28
89
  }
90
+ function kindLabel(kind) {
91
+ return kind === 'tcp' ? 'TCP' : 'WebSocket';
92
+ }
93
+ function listPorts(entries) {
94
+ return joinNames(entries.map(({ route }) => String(route.internalPort)));
95
+ }
96
+ function joinNames(names) {
97
+ if (names.length <= 1)
98
+ return names[0] ?? '';
99
+ return `${names.slice(0, -1).join(', ')} and ${names[names.length - 1]}`;
100
+ }
101
+ function lowerFirst(s) {
102
+ return s.charAt(0).toLowerCase() + s.slice(1);
103
+ }
29
104
  //# sourceMappingURL=reachability.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"reachability.js","sourceRoot":"","sources":["../../src/nat/reachability.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAwB;IAC3D,IAAI,KAAK,CAAC,aAAa;QAAE,OAAO,OAAO,CAAC;IACxC,QAAQ,KAAK,CAAC,QAAQ,EAAE,CAAC;QACvB,KAAK,WAAW,CAAC;QACjB,KAAK,aAAa;YAChB,OAAO,WAAW,CAAC;QACrB,KAAK,QAAQ;YACX,OAAO,aAAa,CAAC;QACvB,KAAK,QAAQ,CAAC;QACd,KAAK,UAAU,CAAC;QAChB;YACE,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"reachability.js","sourceRoot":"","sources":["../../src/nat/reachability.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA4BH;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CAAC,KAAuB;IAC9D,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAChC,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC;IACjF,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;QACrB,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;IACjE,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC;IAC9E,CAAC;IACD,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC;IACpE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AACjE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CACtC,KAAmE,EACnE,aAAsB;IAEtB,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAC/C,IAAI,aAAa,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC;QAAE,OAAO,OAAO,CAAC;IAClF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC3C,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,aAAa,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,aAAa,CAAC;AACzF,CAAC;AAED,MAAM,mBAAmB,GACvB,iHAAiH;IACjH,yEAAyE,CAAC;AAO5E,SAAS,UAAU,CAAC,KAAuB;IACzC,MAAM,GAAG,GAAgB,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;IAC7D,IAAI,KAAK,CAAC,EAAE;QAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;IACxD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,MAAM,CAAC,KAAgB,EAAE,aAAsB;IACtD,IAAI,KAAK,CAAC,YAAY,KAAK,IAAI,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACvE,OAAO,CAAC,CAAC,aAAa,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;AACrD,CAAC;AAID,iGAAiG;AACjG,SAAS,OAAO,CAAC,KAAgB,EAAE,KAAuB;IACxD,IAAI,KAAK,CAAC,aAAa;QAAE,OAAO,OAAO,CAAC;IACxC,IAAI,KAAK,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAClC,IAAI,CAAC,KAAK,CAAC,WAAW;QAAE,OAAO,UAAU,CAAC;IAC1C,IAAI,CAAC,KAAK,CAAC,YAAY;QAAE,OAAO,YAAY,CAAC;IAC7C,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,kFAAkF;AAClF,SAAS,gBAAgB,CAAC,OAAoB,EAAE,KAAuB;IACrE,MAAM,OAAO,GAAG,IAAI,GAAG,EAA6B,CAAC;IACrD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC1G,CAAC;AAED,SAAS,aAAa,CAAC,KAAmB,EAAE,OAAoB,EAAE,KAAuB;IACvF,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,SAAS,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC;IAChG,MAAM,GAAG,GAAG,KAAK,CAAC,UAAU,IAAI,4BAA4B,CAAC;IAC7D,MAAM,WAAW,GAAG,WAAW,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,IAAI,SAAS,CAAC,OAAO,CAAC,OAAO,GAAG,sDAAsD,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC;IACvM,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,OAAO;YACV,OAAO,iDAAiD,SAAS,CAAC,KAAK,CAAC,uIAAuI,CAAC;QAClN,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACvF,OAAO,sBAAsB,SAAS,CAAC,KAAK,CAAC,aAAa,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,WAAW,EAAE,CAAC;QACjG,CAAC;QACD,KAAK,UAAU;YACb,OAAO,uBAAuB,SAAS,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,kCAAkC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QACnJ,KAAK,YAAY;YACf,OAAO,mCAAmC,SAAS,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,gDAAgD,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7K,KAAK,SAAS;YACZ,OAAO,OAAO,SAAS,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,6CAA6C,CAAC;IACvH,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,IAAc;IAC/B,OAAO,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC;AAC9C,CAAC;AAED,SAAS,SAAS,CAAC,OAAoB;IACrC,OAAO,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AAC3E,CAAC;AAED,SAAS,SAAS,CAAC,KAAe;IAChC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC7C,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;AAC3E,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC"}