@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.
- package/README.md +332 -423
- package/dist/bin/host.d.ts +6 -3
- package/dist/bin/host.js +301 -505
- package/dist/bin/host.js.map +1 -1
- package/dist/bin/join-output.d.ts +56 -0
- package/dist/bin/join-output.js +92 -0
- package/dist/bin/join-output.js.map +1 -0
- package/dist/bin/nat-output.d.ts +49 -0
- package/dist/bin/nat-output.js +127 -0
- package/dist/bin/nat-output.js.map +1 -0
- package/dist/hosted/claim-details.d.ts +44 -0
- package/dist/hosted/claim-details.js +66 -0
- package/dist/hosted/claim-details.js.map +1 -0
- package/dist/hosted/hosted-node-service.d.ts +318 -0
- package/dist/hosted/hosted-node-service.js +666 -0
- package/dist/hosted/hosted-node-service.js.map +1 -0
- package/dist/hosted/hosted-node-store.d.ts +40 -0
- package/dist/hosted/hosted-node-store.js +126 -0
- package/dist/hosted/hosted-node-store.js.map +1 -0
- package/dist/{donation/donation-supervisor.d.ts → hosted/hosted-node-supervisor.d.ts} +70 -53
- package/dist/hosted/hosted-node-supervisor.js +396 -0
- package/dist/hosted/hosted-node-supervisor.js.map +1 -0
- package/dist/hosted/hosted-node-watcher.d.ts +83 -0
- package/dist/hosted/hosted-node-watcher.js +224 -0
- package/dist/hosted/hosted-node-watcher.js.map +1 -0
- package/dist/hosted/index.d.ts +16 -0
- package/dist/hosted/index.js +13 -0
- package/dist/hosted/index.js.map +1 -0
- package/dist/hosted/node-status.d.ts +35 -0
- package/dist/hosted/node-status.js +61 -0
- package/dist/hosted/node-status.js.map +1 -0
- package/dist/hosted/types.d.ts +134 -0
- package/dist/hosted/types.js +22 -0
- package/dist/hosted/types.js.map +1 -0
- package/dist/index.d.ts +12 -24
- package/dist/index.js +9 -19
- package/dist/index.js.map +1 -1
- package/dist/installer/config.d.ts +4 -34
- package/dist/installer/config.js +3 -18
- package/dist/installer/config.js.map +1 -1
- package/dist/installer/index.d.ts +7 -19
- package/dist/installer/index.js +14 -69
- package/dist/installer/index.js.map +1 -1
- package/dist/installer/paths.d.ts +0 -2
- package/dist/installer/paths.js +0 -4
- package/dist/installer/paths.js.map +1 -1
- package/dist/installer/wizard.d.ts +0 -7
- package/dist/installer/wizard.js +1 -8
- package/dist/installer/wizard.js.map +1 -1
- package/dist/nat/address-resolver.d.ts +18 -17
- package/dist/nat/address-resolver.js +79 -25
- package/dist/nat/address-resolver.js.map +1 -1
- package/dist/nat/address-watch.d.ts +37 -0
- package/dist/nat/address-watch.js +84 -0
- package/dist/nat/address-watch.js.map +1 -0
- package/dist/nat/ddns/duckdns.d.ts +2 -1
- package/dist/nat/ddns/duckdns.js +5 -1
- package/dist/nat/ddns/duckdns.js.map +1 -1
- package/dist/nat/ddns/index.d.ts +6 -0
- package/dist/nat/ddns/index.js.map +1 -1
- package/dist/nat/index.d.ts +12 -9
- package/dist/nat/index.js +6 -5
- package/dist/nat/index.js.map +1 -1
- package/dist/nat/nat-service.d.ts +203 -77
- package/dist/nat/nat-service.js +602 -237
- package/dist/nat/nat-service.js.map +1 -1
- package/dist/nat/nat-store.d.ts +12 -5
- package/dist/nat/nat-store.js +114 -30
- package/dist/nat/nat-store.js.map +1 -1
- package/dist/nat/port-mapper.d.ts +83 -79
- package/dist/nat/port-mapper.js +148 -189
- package/dist/nat/port-mapper.js.map +1 -1
- package/dist/nat/reachability.d.ts +31 -15
- package/dist/nat/reachability.js +97 -22
- package/dist/nat/reachability.js.map +1 -1
- package/dist/nat/types.d.ts +78 -27
- package/dist/nat/types.js +8 -5
- package/dist/nat/types.js.map +1 -1
- package/dist/orchestrator/host-process-orchestrator.d.ts +29 -71
- package/dist/orchestrator/host-process-orchestrator.js +78 -218
- package/dist/orchestrator/host-process-orchestrator.js.map +1 -1
- package/dist/{installer/identity.d.ts → orchestrator/identity-file.d.ts} +5 -5
- package/dist/{installer/identity.js → orchestrator/identity-file.js} +6 -6
- package/dist/orchestrator/identity-file.js.map +1 -0
- package/dist/orchestrator/index.d.ts +2 -3
- package/dist/orchestrator/index.js +1 -1
- package/dist/orchestrator/index.js.map +1 -1
- package/dist/orchestrator/node-identity.d.ts +6 -6
- package/dist/orchestrator/node-identity.js +7 -7
- package/dist/orchestrator/node-identity.js.map +1 -1
- package/dist/orchestrator/port-allocator.d.ts +5 -6
- package/dist/orchestrator/port-allocator.js +9 -11
- package/dist/orchestrator/port-allocator.js.map +1 -1
- package/dist/orchestrator/state-store.d.ts +3 -5
- package/dist/orchestrator/state-store.js +2 -10
- package/dist/orchestrator/state-store.js.map +1 -1
- package/dist/orchestrator/types.d.ts +33 -22
- package/dist/orchestrator/types.js.map +1 -1
- package/dist/server/error-handler.d.ts +5 -25
- package/dist/server/error-handler.js +11 -74
- package/dist/server/error-handler.js.map +1 -1
- package/dist/server/events/types.d.ts +7 -11
- package/dist/server/events/types.js +2 -1
- package/dist/server/events/types.js.map +1 -1
- package/dist/server/index.d.ts +11 -37
- package/dist/server/index.js +30 -48
- package/dist/server/index.js.map +1 -1
- package/dist/server/routes/hosted-nodes.d.ts +28 -0
- package/dist/server/routes/hosted-nodes.js +68 -0
- package/dist/server/routes/hosted-nodes.js.map +1 -0
- package/dist/server/routes/nat.d.ts +4 -1
- package/dist/server/routes/nat.js +13 -2
- package/dist/server/routes/nat.js.map +1 -1
- package/dist/server/routes/nodes.d.ts +6 -20
- package/dist/server/routes/nodes.js +7 -86
- package/dist/server/routes/nodes.js.map +1 -1
- package/dist/server/routes/settings.d.ts +2 -7
- package/dist/server/routes/settings.js +3 -7
- package/dist/server/routes/settings.js.map +1 -1
- package/dist/server/routes/status.d.ts +2 -25
- package/dist/server/routes/status.js +1 -11
- package/dist/server/routes/status.js.map +1 -1
- package/dist/server/server.js +8 -8
- package/dist/server/settings-store.d.ts +2 -2
- package/dist/server/settings-store.js +2 -2
- package/dist/server/static.js +1 -2
- package/dist/server/static.js.map +1 -1
- package/dist/ui/assets/index-4FWuU8ye.js +19 -0
- package/dist/ui/assets/index-4FWuU8ye.js.map +1 -0
- package/dist/ui/assets/index-Di9Q4d01.css +1 -0
- package/dist/ui/index.html +2 -2
- package/dist/update/index.d.ts +2 -2
- package/dist/update/index.js +2 -2
- package/dist/update/store.d.ts +1 -1
- package/dist/update/store.js +1 -1
- package/dist/update/types.d.ts +1 -1
- package/dist/update/types.js +1 -1
- package/package.json +5 -6
- package/src/__tests__/cli-nat.smoke.test.ts +219 -212
- package/src/__tests__/cli.smoke.test.ts +1 -1
- package/src/__tests__/global-setup.ts +2 -3
- package/src/__tests__/orchestrator-claim-secret.test.ts +112 -0
- package/src/__tests__/orchestrator-handle-contract.ts +134 -134
- package/src/__tests__/orchestrator-node-identity.test.ts +182 -203
- package/src/__tests__/orchestrator-ports.test.ts +124 -143
- package/src/__tests__/orchestrator-push.test.ts +138 -146
- package/src/__tests__/orchestrator.test.ts +1019 -1063
- package/src/bin/host.ts +368 -553
- package/src/bin/join-output.ts +120 -0
- package/src/bin/nat-output.ts +177 -0
- package/src/{donation → hosted}/__tests__/fake-orchestrator.test.ts +173 -173
- package/src/{donation → hosted}/__tests__/fake-orchestrator.ts +265 -243
- package/src/hosted/__tests__/hosted-node-service.test.ts +609 -0
- package/src/hosted/__tests__/hosted-node-supervisor.test.ts +474 -0
- package/src/hosted/__tests__/test-invitation.ts +33 -0
- package/src/hosted/claim-details.ts +96 -0
- package/src/hosted/hosted-node-service.ts +795 -0
- package/src/hosted/hosted-node-store.ts +144 -0
- package/src/hosted/hosted-node-supervisor.ts +439 -0
- package/src/hosted/hosted-node-watcher.ts +250 -0
- package/src/hosted/index.ts +53 -0
- package/src/hosted/node-status.ts +71 -0
- package/src/hosted/types.ts +153 -0
- package/src/index.ts +72 -91
- package/src/installer/__tests__/config.test.ts +15 -40
- package/src/installer/__tests__/installer.smoke.test.ts +5 -86
- package/src/installer/__tests__/wizard.test.ts +56 -64
- package/src/installer/config.ts +135 -175
- package/src/installer/index.ts +15 -83
- package/src/installer/paths.ts +104 -109
- package/src/installer/wizard.ts +87 -103
- package/src/nat/__tests__/address-resolver.test.ts +107 -82
- package/src/nat/__tests__/nat-service.test.ts +433 -408
- package/src/nat/__tests__/nat-store.test.ts +127 -93
- package/src/nat/__tests__/port-mapper.test.ts +30 -191
- package/src/nat/__tests__/reachability.test.ts +96 -13
- package/src/nat/address-resolver.ts +94 -52
- package/src/nat/address-watch.ts +92 -0
- package/src/nat/ddns/duckdns.ts +5 -1
- package/src/nat/ddns/index.ts +6 -0
- package/src/nat/index.ts +87 -71
- package/src/nat/nat-service.ts +889 -501
- package/src/nat/nat-store.ts +237 -154
- package/src/nat/port-mapper.ts +241 -329
- package/src/nat/reachability.ts +134 -25
- package/src/nat/types.ts +209 -159
- package/src/{installer/__tests__/identity.test.ts → orchestrator/__tests__/identity-file.test.ts} +34 -34
- package/src/orchestrator/__tests__/node-identity.test.ts +62 -62
- package/src/orchestrator/host-process-orchestrator.ts +81 -243
- package/src/{installer/identity.ts → orchestrator/identity-file.ts} +56 -56
- package/src/orchestrator/index.ts +9 -10
- package/src/orchestrator/node-identity.ts +41 -41
- package/src/orchestrator/port-allocator.ts +71 -73
- package/src/orchestrator/state-store.ts +76 -90
- package/src/orchestrator/types.ts +34 -23
- package/src/server/__tests__/bus.test.ts +38 -38
- package/src/server/__tests__/error-handler.test.ts +81 -118
- package/src/server/__tests__/fakes.ts +40 -44
- package/src/server/__tests__/hosted-nodes-route.test.ts +160 -0
- package/src/server/__tests__/nodes-route.test.ts +114 -283
- package/src/server/__tests__/publishers.test.ts +193 -180
- package/src/server/__tests__/server.smoke.test.ts +134 -223
- package/src/server/__tests__/settings-route.test.ts +179 -195
- package/src/server/__tests__/sse-route.test.ts +119 -119
- package/src/server/__tests__/status-route.test.ts +82 -121
- package/src/server/error-handler.ts +112 -178
- package/src/server/events/types.ts +20 -24
- package/src/server/index.ts +223 -267
- package/src/server/routes/hosted-nodes.ts +83 -0
- package/src/server/routes/nat.ts +75 -63
- package/src/server/routes/nodes.ts +96 -188
- package/src/server/routes/settings.ts +115 -123
- package/src/server/routes/status.ts +102 -134
- package/src/server/server.ts +8 -8
- package/src/server/settings-store.ts +2 -2
- package/src/server/static.ts +1 -2
- package/src/update/index.ts +2 -2
- package/src/update/store.ts +1 -1
- package/src/update/types.ts +1 -1
- package/dist/auth/duration.d.ts +0 -1
- package/dist/auth/duration.js +0 -32
- package/dist/auth/duration.js.map +0 -1
- package/dist/auth/index.d.ts +0 -11
- package/dist/auth/index.js +0 -9
- package/dist/auth/index.js.map +0 -1
- package/dist/auth/self-label.d.ts +0 -36
- package/dist/auth/self-label.js +0 -57
- package/dist/auth/self-label.js.map +0 -1
- package/dist/auth/trust-circle-store.d.ts +0 -26
- package/dist/auth/trust-circle-store.js +0 -129
- package/dist/auth/trust-circle-store.js.map +0 -1
- package/dist/auth/trust-circle.d.ts +0 -156
- package/dist/auth/trust-circle.js +0 -307
- package/dist/auth/trust-circle.js.map +0 -1
- package/dist/auth/types.d.ts +0 -84
- package/dist/auth/types.js +0 -24
- package/dist/auth/types.js.map +0 -1
- package/dist/donation/donation-service.d.ts +0 -389
- package/dist/donation/donation-service.js +0 -828
- package/dist/donation/donation-service.js.map +0 -1
- package/dist/donation/donation-store.d.ts +0 -51
- package/dist/donation/donation-store.js +0 -152
- package/dist/donation/donation-store.js.map +0 -1
- package/dist/donation/donation-supervisor.js +0 -364
- package/dist/donation/donation-supervisor.js.map +0 -1
- package/dist/donation/grant-service.d.ts +0 -80
- package/dist/donation/grant-service.js +0 -210
- package/dist/donation/grant-service.js.map +0 -1
- package/dist/donation/grant-store.d.ts +0 -38
- package/dist/donation/grant-store.js +0 -135
- package/dist/donation/grant-store.js.map +0 -1
- package/dist/donation/index.d.ts +0 -20
- package/dist/donation/index.js +0 -17
- package/dist/donation/index.js.map +0 -1
- package/dist/donation/types.d.ts +0 -224
- package/dist/donation/types.js +0 -40
- package/dist/donation/types.js.map +0 -1
- package/dist/installer/identity.js.map +0 -1
- package/dist/owner/index.d.ts +0 -11
- package/dist/owner/index.js +0 -11
- package/dist/owner/index.js.map +0 -1
- package/dist/owner/owner-node-client.d.ts +0 -110
- package/dist/owner/owner-node-client.js +0 -184
- package/dist/owner/owner-node-client.js.map +0 -1
- package/dist/server/routes/bootstrap-node-validation.d.ts +0 -115
- package/dist/server/routes/bootstrap-node-validation.js +0 -197
- package/dist/server/routes/bootstrap-node-validation.js.map +0 -1
- package/dist/server/routes/grants-admin.d.ts +0 -29
- package/dist/server/routes/grants-admin.js +0 -58
- package/dist/server/routes/grants-admin.js.map +0 -1
- package/dist/server/routes/grants.d.ts +0 -28
- package/dist/server/routes/grants.js +0 -165
- package/dist/server/routes/grants.js.map +0 -1
- package/dist/server/routes/provision-request-validation.d.ts +0 -45
- package/dist/server/routes/provision-request-validation.js +0 -97
- package/dist/server/routes/provision-request-validation.js.map +0 -1
- package/dist/server/routes/strands.d.ts +0 -20
- package/dist/server/routes/strands.js +0 -38
- package/dist/server/routes/strands.js.map +0 -1
- package/dist/server/routes/trust-circle.d.ts +0 -17
- package/dist/server/routes/trust-circle.js +0 -35
- package/dist/server/routes/trust-circle.js.map +0 -1
- package/dist/strands/index.d.ts +0 -7
- package/dist/strands/index.js +0 -6
- package/dist/strands/index.js.map +0 -1
- package/dist/strands/strand-service.d.ts +0 -50
- package/dist/strands/strand-service.js +0 -103
- package/dist/strands/strand-service.js.map +0 -1
- package/dist/strands/types.d.ts +0 -93
- package/dist/strands/types.js +0 -23
- package/dist/strands/types.js.map +0 -1
- package/dist/ui/assets/index-C6nELNfC.js +0 -23
- package/dist/ui/assets/index-C6nELNfC.js.map +0 -1
- package/dist/ui/assets/index-TtIYSeZO.css +0 -1
- package/src/__tests__/cli-invite.smoke.test.ts +0 -192
- package/src/__tests__/host-owner.smoke.test.ts +0 -123
- package/src/__tests__/orchestrator-owner.test.ts +0 -234
- package/src/__tests__/orchestrator-pin-keys.test.ts +0 -152
- package/src/auth/__tests__/duration.test.ts +0 -28
- package/src/auth/__tests__/self-label.test.ts +0 -85
- package/src/auth/__tests__/trust-circle-integration.test.ts +0 -152
- package/src/auth/__tests__/trust-circle-store.test.ts +0 -115
- package/src/auth/__tests__/trust-circle.test.ts +0 -445
- package/src/auth/duration.ts +0 -33
- package/src/auth/index.ts +0 -21
- package/src/auth/self-label.ts +0 -74
- package/src/auth/trust-circle-store.ts +0 -155
- package/src/auth/trust-circle.ts +0 -395
- package/src/auth/types.ts +0 -99
- package/src/donation/__tests__/donation-service.test.ts +0 -1193
- package/src/donation/__tests__/donation-supervisor.test.ts +0 -548
- package/src/donation/__tests__/grant-service.test.ts +0 -213
- package/src/donation/__tests__/grant-store.test.ts +0 -113
- package/src/donation/donation-service.ts +0 -1033
- package/src/donation/donation-store.ts +0 -176
- package/src/donation/donation-supervisor.ts +0 -411
- package/src/donation/grant-service.ts +0 -252
- package/src/donation/grant-store.ts +0 -152
- package/src/donation/index.ts +0 -65
- package/src/donation/types.ts +0 -260
- package/src/owner/__tests__/owner-node-client.test.ts +0 -194
- package/src/owner/index.ts +0 -12
- package/src/owner/owner-node-client.ts +0 -259
- package/src/server/__tests__/bootstrap-node-validation.test.ts +0 -138
- package/src/server/__tests__/grants-admin-route.test.ts +0 -171
- package/src/server/__tests__/grants-route.test.ts +0 -394
- package/src/server/__tests__/strands-route.test.ts +0 -234
- package/src/server/routes/bootstrap-node-validation.ts +0 -206
- package/src/server/routes/grants-admin.ts +0 -74
- package/src/server/routes/grants.ts +0 -193
- package/src/server/routes/provision-request-validation.ts +0 -105
- package/src/server/routes/strands.ts +0 -54
- package/src/server/routes/trust-circle.ts +0 -49
- package/src/strands/__tests__/strand-service.test.ts +0 -165
- package/src/strands/index.ts +0 -14
- package/src/strands/strand-service.ts +0 -135
- package/src/strands/types.ts +0 -102
package/src/server/routes/nat.ts
CHANGED
|
@@ -1,63 +1,75 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* NAT/DDNS HTTP routes — thin adapters around `NatHandlers`
|
|
3
|
-
* (`createNatHandlers(service)`). Side-effects (settings change, reachability
|
|
4
|
-
* re-test, DDNS reconfiguration) emit a `connectivity-changed`
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
import type {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* NAT/DDNS HTTP routes — thin adapters around `NatHandlers`
|
|
3
|
+
* (`createNatHandlers(service)`). Side-effects (settings change, reachability
|
|
4
|
+
* re-test, DDNS reconfiguration, a manual forward) emit a `connectivity-changed`
|
|
5
|
+
* bus event. The service's own change listener covers the changes that happen
|
|
6
|
+
* on their own (a mapping completing after a spawn, an IP change) — see
|
|
7
|
+
* `server/index.ts`.
|
|
8
|
+
*
|
|
9
|
+
* Mount path: `/nat/*` — matches the existing CLI (cadre-host nat ...).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { FastifyInstance } from 'fastify';
|
|
13
|
+
|
|
14
|
+
import type { ManualForwardPatch, NatHandlers, NatSettingsFile, NatStatusSnapshot } from '../../nat/types.js';
|
|
15
|
+
import type { EventBus } from '../events/bus.js';
|
|
16
|
+
|
|
17
|
+
export interface NatRoutesOptions {
|
|
18
|
+
handlers: NatHandlers;
|
|
19
|
+
events: EventBus;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function registerNatRoutes(app: FastifyInstance, opts: NatRoutesOptions): void {
|
|
23
|
+
const { handlers, events } = opts;
|
|
24
|
+
|
|
25
|
+
app.get('/nat/status', async () => handlers.getStatus());
|
|
26
|
+
|
|
27
|
+
app.post('/nat/test', async () => {
|
|
28
|
+
const snap = await handlers.testReachability();
|
|
29
|
+
publishConnectivity(events, snap);
|
|
30
|
+
return snap;
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
app.get('/nat/providers', async () => handlers.listDdnsProviders());
|
|
34
|
+
|
|
35
|
+
app.put('/nat/ddns', async (request) => {
|
|
36
|
+
const body = (request.body ?? {}) as {
|
|
37
|
+
providerId?: string;
|
|
38
|
+
hostname?: string;
|
|
39
|
+
config?: Record<string, string>;
|
|
40
|
+
externallyManaged?: boolean;
|
|
41
|
+
};
|
|
42
|
+
const snap = await handlers.putDdns({
|
|
43
|
+
providerId: body.providerId ?? '',
|
|
44
|
+
hostname: body.hostname ?? '',
|
|
45
|
+
config: body.config ?? {},
|
|
46
|
+
externallyManaged: body.externallyManaged ?? false,
|
|
47
|
+
});
|
|
48
|
+
publishConnectivity(events, snap);
|
|
49
|
+
return snap;
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
app.put('/nat/settings', async (request) => {
|
|
53
|
+
const body = (request.body ?? {}) as Partial<Omit<NatSettingsFile, 'version' | 'forwards'>>;
|
|
54
|
+
const snap = await handlers.putSettings(body);
|
|
55
|
+
publishConnectivity(events, snap);
|
|
56
|
+
return snap;
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// The ports the user forwarded on their router for one node. `null` clears a
|
|
60
|
+
// port; both cleared removes the entry. Unknown node → 404 unknown_node; a
|
|
61
|
+
// body that is not an object, or a port outside 1–65535 → 400 invalid_config
|
|
62
|
+
// (all from the service, which reads only `tcp` and `ws`).
|
|
63
|
+
app.put<{ Params: { nodeId: string } }>('/nat/nodes/:nodeId/forward', async (request) => {
|
|
64
|
+
const snap = await handlers.putForward(request.params.nodeId, (request.body ?? {}) as ManualForwardPatch);
|
|
65
|
+
publishConnectivity(events, snap);
|
|
66
|
+
return snap;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function publishConnectivity(events: EventBus, snap: NatStatusSnapshot): void {
|
|
71
|
+
events.publish({
|
|
72
|
+
type: 'connectivity-changed',
|
|
73
|
+
directReachability: snap.directReachability,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
@@ -1,188 +1,96 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* /api/nodes — list managed cadre nodes, look up
|
|
3
|
-
* lifecycle
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
);
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
return { ok: true, data: { node } };
|
|
98
|
-
}
|
|
99
|
-
return ownerOnlyFallback(reply, orchestrator, id, 'start');
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
app.post<{ Params: { id: string } }>('/api/nodes/:id/restart', async (request, reply) => {
|
|
103
|
-
const { id } = request.params;
|
|
104
|
-
if (orchestrator.isOwnerNode(id)) {
|
|
105
|
-
if (role === 'donor') return ownCadreDisabled(reply, 'restart');
|
|
106
|
-
if (!orchestrator.hasOwnerConfig()) {
|
|
107
|
-
return notImplemented(reply, `restart ${id}: owner node has no saved spawn config.`);
|
|
108
|
-
}
|
|
109
|
-
const node = await orchestrator.restartOwnerNode();
|
|
110
|
-
return { ok: true, data: { node } };
|
|
111
|
-
}
|
|
112
|
-
return ownerOnlyFallback(reply, orchestrator, id, 'restart');
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* 404 for unknown ids; 501 not_implemented for known non-owner nodes — all of
|
|
118
|
-
* them donated. A donated node's containerId is its donation id, so the
|
|
119
|
-
* message names `node.id` rather than the route param, which may be the
|
|
120
|
-
* opaque dockerId — only the donation id is what the terminate command takes.
|
|
121
|
-
*/
|
|
122
|
-
function ownerOnlyFallback(
|
|
123
|
-
reply: FastifyReply,
|
|
124
|
-
orchestrator: HostProcessOrchestrator,
|
|
125
|
-
id: string,
|
|
126
|
-
verb: 'start' | 'stop' | 'restart',
|
|
127
|
-
) {
|
|
128
|
-
const node = orchestrator.getNode(id);
|
|
129
|
-
if (!node) return notFound(reply, id);
|
|
130
|
-
return notImplemented(
|
|
131
|
-
reply,
|
|
132
|
-
`${verb} ${id}: only the owner node can be started, stopped or restarted here; a donated node's lifecycle is owned by the donation surface — end it with 'cadre-host grant terminate ${node.id}' (DELETE /grants-admin/donations/${node.id}).`,
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function notFound(reply: FastifyReply, id: string) {
|
|
137
|
-
return reply.code(404).send({
|
|
138
|
-
ok: false,
|
|
139
|
-
error: { code: 'not_found', message: `Unknown node: ${id}` },
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function notImplemented(reply: FastifyReply, message: string) {
|
|
144
|
-
return reply.code(501).send({ ok: false, error: { code: 'not_implemented', message } });
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function ownCadreDisabled(reply: FastifyReply, verb: 'start' | 'restart') {
|
|
148
|
-
return reply.code(409).send({
|
|
149
|
-
ok: false,
|
|
150
|
-
error: {
|
|
151
|
-
code: 'own_cadre_disabled',
|
|
152
|
-
message: `${verb} owner: this host's own cadre is turned off (donor-only mode). Set ownCadre.enabled in host.config.json and restart cadre-host to run it again.`,
|
|
153
|
-
},
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Read the last `n` lines from a log file by walking the tail in chunks.
|
|
159
|
-
* Returns [] for a missing file.
|
|
160
|
-
*/
|
|
161
|
-
export function tailLogFile(path: string, n: number): string[] {
|
|
162
|
-
if (!existsSync(path)) return [];
|
|
163
|
-
const fd = openSync(path, 'r');
|
|
164
|
-
try {
|
|
165
|
-
const size = statSync(path).size;
|
|
166
|
-
const chunkSize = 8192;
|
|
167
|
-
let pos = size;
|
|
168
|
-
const buffers: Buffer[] = [];
|
|
169
|
-
let newlineCount = 0;
|
|
170
|
-
while (pos > 0 && newlineCount <= n) {
|
|
171
|
-
const readLen = Math.min(chunkSize, pos);
|
|
172
|
-
pos -= readLen;
|
|
173
|
-
const buf = Buffer.alloc(readLen);
|
|
174
|
-
readSync(fd, buf, 0, readLen, pos);
|
|
175
|
-
buffers.unshift(buf);
|
|
176
|
-
for (let i = 0; i < buf.length; i++) {
|
|
177
|
-
if (buf[i] === 0x0a) newlineCount++;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
const joined = Buffer.concat(buffers).toString('utf8');
|
|
181
|
-
const lines = joined.split('\n');
|
|
182
|
-
const trimmed = lines[lines.length - 1] === '' ? lines.slice(0, -1) : lines;
|
|
183
|
-
return trimmed.slice(-n);
|
|
184
|
-
} finally {
|
|
185
|
-
closeSync(fd);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
1
|
+
/**
|
|
2
|
+
* /api/nodes — list managed cadre nodes (orchestrator handles), look up one
|
|
3
|
+
* node's details, and tail its log. Read-only: every node's lifecycle belongs to
|
|
4
|
+
* `/api/hosted-nodes`, whose supervisor would undo at once a stop issued
|
|
5
|
+
* anywhere else. A handle's `partyId` is the placeholder an unclaimed node was
|
|
6
|
+
* started with until its first respawn after the claim; the hosted-node record
|
|
7
|
+
* carries the real party.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { existsSync, openSync, readSync, closeSync, statSync } from 'node:fs';
|
|
11
|
+
|
|
12
|
+
import type { FastifyInstance, FastifyReply } from 'fastify';
|
|
13
|
+
|
|
14
|
+
import type { HostProcessOrchestrator } from '../../orchestrator/index.js';
|
|
15
|
+
import { defaultLogPath } from '../../orchestrator/log-rotator.js';
|
|
16
|
+
|
|
17
|
+
const DEFAULT_LOG_LINES = 200;
|
|
18
|
+
const MAX_LOG_LINES = 2000;
|
|
19
|
+
|
|
20
|
+
export interface NodesRoutesOptions {
|
|
21
|
+
orchestrator: HostProcessOrchestrator;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function registerNodesRoutes(app: FastifyInstance, opts: NodesRoutesOptions): void {
|
|
25
|
+
const { orchestrator } = opts;
|
|
26
|
+
|
|
27
|
+
app.get('/api/nodes', async () => {
|
|
28
|
+
return { ok: true, data: { nodes: orchestrator.listNodes() } };
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
app.get<{ Params: { id: string } }>('/api/nodes/:id', async (request, reply) => {
|
|
32
|
+
const node = orchestrator.getNode(request.params.id);
|
|
33
|
+
if (!node) return notFound(reply, request.params.id);
|
|
34
|
+
let stats = null;
|
|
35
|
+
try {
|
|
36
|
+
stats = await orchestrator.getStats(node.dockerId);
|
|
37
|
+
} catch {
|
|
38
|
+
// Stats unavailable (dead process etc.) — surface null.
|
|
39
|
+
}
|
|
40
|
+
return { ok: true, data: { node, stats } };
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
app.get<{ Params: { id: string }; Querystring: { lines?: string } }>(
|
|
44
|
+
'/api/nodes/:id/logs',
|
|
45
|
+
async (request, reply) => {
|
|
46
|
+
const node = orchestrator.getNode(request.params.id);
|
|
47
|
+
if (!node) return notFound(reply, request.params.id);
|
|
48
|
+
const requested = Number(request.query.lines ?? DEFAULT_LOG_LINES);
|
|
49
|
+
const tail = Number.isFinite(requested)
|
|
50
|
+
? Math.max(1, Math.min(MAX_LOG_LINES, Math.floor(requested)))
|
|
51
|
+
: DEFAULT_LOG_LINES;
|
|
52
|
+
const lines = tailLogFile(defaultLogPath(node.workdir), tail);
|
|
53
|
+
return { ok: true, data: { lines } };
|
|
54
|
+
},
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function notFound(reply: FastifyReply, id: string) {
|
|
59
|
+
return reply.code(404).send({
|
|
60
|
+
ok: false,
|
|
61
|
+
error: { code: 'not_found', message: `Unknown node: ${id}` },
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Read the last `n` lines from a log file by walking the tail in chunks.
|
|
67
|
+
* Returns [] for a missing file.
|
|
68
|
+
*/
|
|
69
|
+
export function tailLogFile(path: string, n: number): string[] {
|
|
70
|
+
if (!existsSync(path)) return [];
|
|
71
|
+
const fd = openSync(path, 'r');
|
|
72
|
+
try {
|
|
73
|
+
const size = statSync(path).size;
|
|
74
|
+
const chunkSize = 8192;
|
|
75
|
+
let pos = size;
|
|
76
|
+
const buffers: Buffer[] = [];
|
|
77
|
+
let newlineCount = 0;
|
|
78
|
+
while (pos > 0 && newlineCount <= n) {
|
|
79
|
+
const readLen = Math.min(chunkSize, pos);
|
|
80
|
+
pos -= readLen;
|
|
81
|
+
const buf = Buffer.alloc(readLen);
|
|
82
|
+
readSync(fd, buf, 0, readLen, pos);
|
|
83
|
+
buffers.unshift(buf);
|
|
84
|
+
for (let i = 0; i < buf.length; i++) {
|
|
85
|
+
if (buf[i] === 0x0a) newlineCount++;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const joined = Buffer.concat(buffers).toString('utf8');
|
|
89
|
+
const lines = joined.split('\n');
|
|
90
|
+
const trimmed = lines[lines.length - 1] === '' ? lines.slice(0, -1) : lines;
|
|
91
|
+
return trimmed.slice(-n);
|
|
92
|
+
} finally {
|
|
93
|
+
closeSync(fd);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|