@serfab/cadre-host 1.14.0 → 1.16.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 +19 -4
- package/dist/bin/host.js +32 -20
- package/dist/bin/host.js.map +1 -1
- package/dist/bin/nat-output.d.ts +5 -0
- package/dist/bin/nat-output.js +12 -1
- package/dist/bin/nat-output.js.map +1 -1
- package/dist/bin/ui-access.d.ts +22 -0
- package/dist/bin/ui-access.js +44 -0
- package/dist/bin/ui-access.js.map +1 -0
- package/dist/hosted/claim-details.d.ts +25 -3
- package/dist/hosted/claim-details.js +31 -37
- package/dist/hosted/claim-details.js.map +1 -1
- package/dist/hosted/hosted-node-service.d.ts +7 -0
- package/dist/hosted/hosted-node-service.js +16 -4
- package/dist/hosted/hosted-node-service.js.map +1 -1
- package/dist/hosted/hosted-node-watcher.d.ts +16 -4
- package/dist/hosted/hosted-node-watcher.js +45 -9
- package/dist/hosted/hosted-node-watcher.js.map +1 -1
- package/dist/hosted/node-status.d.ts +19 -3
- package/dist/hosted/node-status.js +21 -5
- package/dist/hosted/node-status.js.map +1 -1
- package/dist/hosted/types.d.ts +12 -5
- package/dist/hosted/types.js.map +1 -1
- package/dist/installer/config.d.ts +23 -0
- package/dist/installer/config.js +46 -0
- package/dist/installer/config.js.map +1 -1
- package/dist/installer/index.d.ts +2 -0
- package/dist/installer/index.js +7 -16
- package/dist/installer/index.js.map +1 -1
- package/dist/installer/wizard.d.ts +12 -2
- package/dist/installer/wizard.js +15 -7
- package/dist/installer/wizard.js.map +1 -1
- package/dist/nat/index.d.ts +2 -1
- package/dist/nat/index.js +1 -0
- package/dist/nat/index.js.map +1 -1
- package/dist/nat/nat-service.d.ts +22 -5
- package/dist/nat/nat-service.js +75 -26
- package/dist/nat/nat-service.js.map +1 -1
- package/dist/nat/nat-store.js +11 -0
- package/dist/nat/nat-store.js.map +1 -1
- package/dist/nat/network-mode.d.ts +19 -0
- package/dist/nat/network-mode.js +32 -0
- package/dist/nat/network-mode.js.map +1 -0
- package/dist/nat/reachability.d.ts +5 -4
- package/dist/nat/reachability.js +19 -6
- package/dist/nat/reachability.js.map +1 -1
- package/dist/nat/types.d.ts +26 -6
- package/dist/nat/types.js.map +1 -1
- package/dist/orchestrator/host-process-orchestrator.d.ts +3 -3
- package/dist/orchestrator/host-process-orchestrator.js +6 -15
- package/dist/orchestrator/host-process-orchestrator.js.map +1 -1
- package/dist/package-version.d.ts +1 -0
- package/dist/package-version.js +4 -0
- package/dist/package-version.js.map +1 -0
- package/dist/server/routes/settings.d.ts +1 -0
- package/dist/server/routes/settings.js +15 -1
- package/dist/server/routes/settings.js.map +1 -1
- package/dist/server/routes/status.js +2 -32
- package/dist/server/routes/status.js.map +1 -1
- package/dist/ui/assets/index-BHd8CWZA.css +1 -0
- package/dist/ui/assets/index-Ccr2GjPT.js +23 -0
- package/dist/ui/assets/{index-4FWuU8ye.js.map → index-Ccr2GjPT.js.map} +1 -1
- package/dist/ui/index.html +2 -2
- package/package.json +4 -5
- package/src/__tests__/cli.smoke.test.ts +1 -1
- package/src/__tests__/orchestrator-claim-secret.test.ts +1 -2
- package/src/__tests__/orchestrator-env-scrub.test.ts +160 -163
- package/src/__tests__/orchestrator-handle-contract.ts +1 -1
- package/src/__tests__/orchestrator-node-identity.test.ts +0 -5
- package/src/__tests__/orchestrator-push.test.ts +3 -3
- package/src/__tests__/orchestrator.test.ts +3 -5
- package/src/__tests__/ui-access.test.ts +30 -0
- package/src/bin/host.ts +30 -20
- package/src/bin/nat-output.ts +12 -1
- package/src/bin/ui-access.ts +50 -0
- package/src/hosted/__tests__/fake-orchestrator.test.ts +0 -1
- package/src/hosted/__tests__/fake-orchestrator.ts +263 -265
- package/src/hosted/__tests__/hosted-node-service.test.ts +708 -609
- package/src/hosted/__tests__/hosted-node-supervisor.test.ts +475 -474
- package/src/hosted/claim-details.ts +44 -37
- package/src/hosted/hosted-node-service.ts +23 -4
- package/src/hosted/hosted-node-watcher.ts +288 -250
- package/src/hosted/node-status.ts +31 -5
- package/src/hosted/types.ts +160 -153
- package/src/installer/__tests__/installer.smoke.test.ts +184 -182
- package/src/installer/__tests__/wizard.test.ts +76 -56
- package/src/installer/config.ts +66 -0
- package/src/installer/index.ts +252 -259
- package/src/installer/wizard.ts +101 -87
- package/src/nat/__tests__/nat-service.test.ts +608 -540
- package/src/nat/__tests__/nat-store.test.ts +130 -127
- package/src/nat/__tests__/network-mode.test.ts +38 -0
- package/src/nat/index.ts +91 -87
- package/src/nat/nat-service.ts +79 -26
- package/src/nat/nat-store.ts +249 -237
- package/src/nat/network-mode.ts +36 -0
- package/src/nat/reachability.ts +155 -143
- package/src/nat/types.ts +232 -209
- package/src/orchestrator/host-process-orchestrator.ts +1089 -1098
- package/src/package-version.ts +4 -0
- package/src/server/__tests__/fakes.ts +41 -40
- package/src/server/__tests__/hosted-nodes-route.test.ts +161 -160
- package/src/server/__tests__/settings-route.test.ts +31 -0
- package/src/server/routes/settings.ts +128 -115
- package/src/server/routes/status.ts +72 -102
- package/dist/ui/assets/index-4FWuU8ye.js +0 -19
- package/dist/ui/assets/index-Di9Q4d01.css +0 -1
package/src/installer/index.ts
CHANGED
|
@@ -1,259 +1,252 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Public installer surface for cadre-host.
|
|
3
|
-
*
|
|
4
|
-
* Orchestrates the install / uninstall flow described in
|
|
5
|
-
* `tickets/implement/6.4.1-cadre-host-installer.md`.
|
|
6
|
-
*
|
|
7
|
-
* The class is purposefully thin — heavy lifting lives in the focused
|
|
8
|
-
* subsystem modules (wizard.ts, config.ts, service-host/{systemd,launchd,nssm}.ts,
|
|
9
|
-
* browser.ts).
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { existsSync, mkdirSync,
|
|
13
|
-
import { randomBytes } from 'node:crypto';
|
|
14
|
-
import debug from 'debug';
|
|
15
|
-
|
|
16
|
-
import { NatStore } from '../nat/index.js';
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
import {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
type
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
export {
|
|
42
|
-
export
|
|
43
|
-
export type {
|
|
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
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
//
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
//
|
|
221
|
-
//
|
|
222
|
-
//
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
} catch {
|
|
254
|
-
return '0.0.0-unknown';
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// Exposed for tests that drive the wizard with a custom prompt fn.
|
|
259
|
-
export { runWizard };
|
|
1
|
+
/**
|
|
2
|
+
* Public installer surface for cadre-host.
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates the install / uninstall flow described in
|
|
5
|
+
* `tickets/implement/6.4.1-cadre-host-installer.md`.
|
|
6
|
+
*
|
|
7
|
+
* The class is purposefully thin — heavy lifting lives in the focused
|
|
8
|
+
* subsystem modules (wizard.ts, config.ts, service-host/{systemd,launchd,nssm}.ts,
|
|
9
|
+
* browser.ts).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { existsSync, mkdirSync, rmSync } from 'node:fs';
|
|
13
|
+
import { randomBytes } from 'node:crypto';
|
|
14
|
+
import debug from 'debug';
|
|
15
|
+
|
|
16
|
+
import { NatStore, publicInterfaceAddress } from '../nat/index.js';
|
|
17
|
+
import { packageVersion } from '../package-version.js';
|
|
18
|
+
|
|
19
|
+
import { openBrowser } from './browser.js';
|
|
20
|
+
import { writeHostConfig, type HostConfigFile } from './config.js';
|
|
21
|
+
import {
|
|
22
|
+
configPath,
|
|
23
|
+
defaultHostJs,
|
|
24
|
+
defaultServiceDir,
|
|
25
|
+
logsDir,
|
|
26
|
+
} from './paths.js';
|
|
27
|
+
import {
|
|
28
|
+
detectPlatform,
|
|
29
|
+
type SupportedPlatform,
|
|
30
|
+
} from './platform.js';
|
|
31
|
+
import { createServiceHost, type ServiceHost, type ServiceHostContext } from './service-host/index.js';
|
|
32
|
+
import {
|
|
33
|
+
defaultsForPlatform,
|
|
34
|
+
runWizard,
|
|
35
|
+
runWizardWith,
|
|
36
|
+
DEFAULT_UI_PORT,
|
|
37
|
+
type WizardAnswers,
|
|
38
|
+
type WizardDefaults,
|
|
39
|
+
} from './wizard.js';
|
|
40
|
+
|
|
41
|
+
export type { HostConfigFile, PushSettings } from './config.js';
|
|
42
|
+
export { readHostConfig, updateHostConfig, writeHostConfig } from './config.js';
|
|
43
|
+
export type { WizardAnswers, WizardDefaults } from './wizard.js';
|
|
44
|
+
export type { ServiceHost, ServiceHostContext, ServiceHostStatus } from './service-host/index.js';
|
|
45
|
+
|
|
46
|
+
const log = debug('cadre:host:installer');
|
|
47
|
+
|
|
48
|
+
export interface InstallOptions {
|
|
49
|
+
/** If true, all prompts use defaults; CLI flags override individual values. */
|
|
50
|
+
nonInteractive: boolean;
|
|
51
|
+
/** Override the data dir. */
|
|
52
|
+
dataDir?: string;
|
|
53
|
+
/** Override the UI port. */
|
|
54
|
+
uiPort?: number;
|
|
55
|
+
/** Disable UPnP probing on first run. */
|
|
56
|
+
noUpnp?: boolean;
|
|
57
|
+
/** Open browser at end (default true; suppressed by --no-browser or non-TTY). */
|
|
58
|
+
openBrowser?: boolean;
|
|
59
|
+
/** System-wide install — v1 emits a not-yet-supported error. */
|
|
60
|
+
system?: boolean;
|
|
61
|
+
/** Path to node.exe / node binary used by the service-host unit. */
|
|
62
|
+
nodePath?: string;
|
|
63
|
+
/**
|
|
64
|
+
* Write the data dir (config, NAT seed) but register no OS service.
|
|
65
|
+
* The host is then run by hand with `cadre-host start`. Nothing is listening
|
|
66
|
+
* after such an install, so the browser-open step is skipped too.
|
|
67
|
+
*/
|
|
68
|
+
noService?: boolean;
|
|
69
|
+
/** Test-only: stub the service-host registration. */
|
|
70
|
+
serviceHost?: ServiceHost;
|
|
71
|
+
/** Test-only: stub the interactive wizard. Production callers leave unset. */
|
|
72
|
+
wizard?: (defaults: WizardDefaults) => Promise<WizardAnswers>;
|
|
73
|
+
/** Test-only: stub the interface read that decides whether to ask about UPnP. */
|
|
74
|
+
publicInterfaceAddress?: () => string | null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface InstallResult {
|
|
78
|
+
dataDir: string;
|
|
79
|
+
uiUrl: string;
|
|
80
|
+
/** The registered service's name; absent when `noService` skipped registration. */
|
|
81
|
+
serviceName?: string;
|
|
82
|
+
/** Path to the rendered config file. */
|
|
83
|
+
configPath: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface UninstallOptions {
|
|
87
|
+
/** Also remove the data dir (default false — preserve hosted-node records, node identities and NAT state). */
|
|
88
|
+
removeData: boolean;
|
|
89
|
+
/** Skip the confirmation prompt (for scripts). */
|
|
90
|
+
yes: boolean;
|
|
91
|
+
/** Override the data dir to remove (defaults to platform default). */
|
|
92
|
+
dataDir?: string;
|
|
93
|
+
/** Test-only: stub the service-host registration. */
|
|
94
|
+
serviceHost?: ServiceHost;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface InstallerOptions {
|
|
98
|
+
platform?: SupportedPlatform;
|
|
99
|
+
/** Installer version string written into host.config.json. */
|
|
100
|
+
installerVersion?: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export class Installer {
|
|
104
|
+
private readonly platform: SupportedPlatform;
|
|
105
|
+
private readonly installerVersion: string;
|
|
106
|
+
|
|
107
|
+
constructor(opts: InstallerOptions = {}) {
|
|
108
|
+
this.platform = opts.platform ?? detectPlatform();
|
|
109
|
+
this.installerVersion = opts.installerVersion ?? packageVersion;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async install(opts: InstallOptions): Promise<InstallResult> {
|
|
113
|
+
if (opts.system) {
|
|
114
|
+
throw new Error(
|
|
115
|
+
'cadre-host install --system is not yet supported. Run without --system ' +
|
|
116
|
+
'for a per-user install; see packages/cadre-host/service/README.md.',
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// 1. Resolve answers — wizard for interactive, defaults+overrides otherwise.
|
|
121
|
+
const answers = await this.resolveAnswers(opts);
|
|
122
|
+
|
|
123
|
+
// 2. Make sure the data dir exists.
|
|
124
|
+
mkdirSync(answers.dataDir, { recursive: true });
|
|
125
|
+
mkdirSync(logsDir(answers.dataDir), { recursive: true });
|
|
126
|
+
|
|
127
|
+
// 3. Config.
|
|
128
|
+
const cfg: HostConfigFile = {
|
|
129
|
+
version: 3,
|
|
130
|
+
installId: randomInstallId(),
|
|
131
|
+
uiPort: answers.uiPort,
|
|
132
|
+
dataDir: answers.dataDir,
|
|
133
|
+
upnpEnabled: answers.upnpEnabled,
|
|
134
|
+
installedAt: new Date().toISOString(),
|
|
135
|
+
installerVersion: this.installerVersion,
|
|
136
|
+
updates: { autoApply: false },
|
|
137
|
+
};
|
|
138
|
+
const cfgPath = configPath(answers.dataDir);
|
|
139
|
+
writeHostConfig(cfgPath, cfg);
|
|
140
|
+
|
|
141
|
+
// 4. Seed nat.json with the UPnP flag so the NatService picks it up on
|
|
142
|
+
// first start. Ports are not seeded: the service maps every hosted
|
|
143
|
+
// node's ports from the orchestrator's allocations.
|
|
144
|
+
seedNatSettings(answers.dataDir, answers.upnpEnabled);
|
|
145
|
+
|
|
146
|
+
const uiUrl = `http://127.0.0.1:${answers.uiPort}/`;
|
|
147
|
+
|
|
148
|
+
// 5. Service-host registration.
|
|
149
|
+
if (opts.noService) {
|
|
150
|
+
log('--no-service: skipping service registration and browser open');
|
|
151
|
+
return { dataDir: answers.dataDir, uiUrl, configPath: cfgPath };
|
|
152
|
+
}
|
|
153
|
+
const serviceHost = opts.serviceHost ?? createServiceHost(this.platform);
|
|
154
|
+
const ctx: ServiceHostContext = {
|
|
155
|
+
nodePath: opts.nodePath ?? process.execPath,
|
|
156
|
+
hostJs: defaultHostJs(),
|
|
157
|
+
dataDir: answers.dataDir,
|
|
158
|
+
serviceDir: defaultServiceDir(),
|
|
159
|
+
};
|
|
160
|
+
await serviceHost.install(ctx);
|
|
161
|
+
|
|
162
|
+
// 6. Browser open (best-effort).
|
|
163
|
+
const shouldOpenBrowser = opts.openBrowser !== false && !opts.nonInteractive && process.stdout.isTTY;
|
|
164
|
+
if (shouldOpenBrowser) {
|
|
165
|
+
openBrowser(uiUrl);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
dataDir: answers.dataDir,
|
|
170
|
+
uiUrl,
|
|
171
|
+
serviceName: serviceHost.name,
|
|
172
|
+
configPath: cfgPath,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async uninstall(opts: UninstallOptions): Promise<void> {
|
|
177
|
+
const dataDir = opts.dataDir ?? defaultsForPlatform(this.platform).dataDir;
|
|
178
|
+
const serviceHost = opts.serviceHost ?? createServiceHost(this.platform);
|
|
179
|
+
const ctx: ServiceHostContext = {
|
|
180
|
+
nodePath: process.execPath,
|
|
181
|
+
hostJs: defaultHostJs(),
|
|
182
|
+
dataDir,
|
|
183
|
+
serviceDir: defaultServiceDir(),
|
|
184
|
+
};
|
|
185
|
+
await serviceHost.uninstall(ctx);
|
|
186
|
+
|
|
187
|
+
if (opts.removeData) {
|
|
188
|
+
if (existsSync(dataDir)) {
|
|
189
|
+
rmSync(dataDir, { recursive: true, force: true });
|
|
190
|
+
log('removed data dir %s', dataDir);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async status(opts: { serviceHost?: ServiceHost } = {}): Promise<{ installed: boolean; running: boolean }> {
|
|
196
|
+
const serviceHost = opts.serviceHost ?? createServiceHost(this.platform);
|
|
197
|
+
const ctx: ServiceHostContext = {
|
|
198
|
+
nodePath: process.execPath,
|
|
199
|
+
hostJs: defaultHostJs(),
|
|
200
|
+
dataDir: defaultsForPlatform(this.platform).dataDir,
|
|
201
|
+
serviceDir: defaultServiceDir(),
|
|
202
|
+
};
|
|
203
|
+
return await serviceHost.status(ctx);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** Exposed for tests / unattended CI. Resolves the wizard answers without running prompts. */
|
|
207
|
+
resolveAnswersFromOptions(opts: InstallOptions): WizardAnswers {
|
|
208
|
+
const defaults = defaultsForPlatform(this.platform);
|
|
209
|
+
return {
|
|
210
|
+
dataDir: opts.dataDir ?? defaults.dataDir,
|
|
211
|
+
uiPort: opts.uiPort ?? defaults.uiPort,
|
|
212
|
+
upnpEnabled: opts.noUpnp ? false : defaults.upnpEnabled,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
private async resolveAnswers(opts: InstallOptions): Promise<WizardAnswers> {
|
|
217
|
+
if (opts.nonInteractive) {
|
|
218
|
+
return this.resolveAnswersFromOptions(opts);
|
|
219
|
+
}
|
|
220
|
+
// CLI flags overlay the platform defaults so the wizard's `[...]` hint
|
|
221
|
+
// shows the user's chosen value. Pressing Enter accepts it; typing a new
|
|
222
|
+
// value also works (and now actually has an effect — the previous
|
|
223
|
+
// implementation showed the platform default in the prompt and silently
|
|
224
|
+
// discarded user input because the CLI flag won post-hoc).
|
|
225
|
+
const platformDefaults = defaultsForPlatform(this.platform);
|
|
226
|
+
const defaults: WizardDefaults = {
|
|
227
|
+
dataDir: opts.dataDir ?? platformDefaults.dataDir,
|
|
228
|
+
uiPort: opts.uiPort ?? platformDefaults.uiPort,
|
|
229
|
+
upnpEnabled: opts.noUpnp ? false : platformDefaults.upnpEnabled,
|
|
230
|
+
// A flag answers its question: the wizard asks only for what the command line left open.
|
|
231
|
+
given: { dataDir: opts.dataDir !== undefined, uiPort: opts.uiPort !== undefined, upnpEnabled: opts.noUpnp === true },
|
|
232
|
+
publicInterfaceIp: (opts.publicInterfaceAddress ?? publicInterfaceAddress)(),
|
|
233
|
+
};
|
|
234
|
+
const wizard = opts.wizard ?? runWizard;
|
|
235
|
+
return await wizard(defaults);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export { runWizardWith, defaultsForPlatform, DEFAULT_UI_PORT };
|
|
240
|
+
|
|
241
|
+
function seedNatSettings(dataDir: string, upnpEnabled: boolean): void {
|
|
242
|
+
const store = new NatStore(dataDir);
|
|
243
|
+
// `update()` merges + persists.
|
|
244
|
+
store.update({ upnpEnabled });
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function randomInstallId(): string {
|
|
248
|
+
return randomBytes(16).toString('hex');
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Exposed for tests that drive the wizard with a custom prompt fn.
|
|
252
|
+
export { runWizard };
|