herdr-remote 0.2.38 → 0.3.31
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/dist/chunks/353DMT35.js +3 -0
- package/dist/chunks/42KARAL4.js +31 -0
- package/dist/chunks/7AUQHB3O.js +10 -0
- package/dist/chunks/7SMZ43LI.js +9 -0
- package/dist/chunks/AM3OEMFK.js +16 -0
- package/dist/chunks/ANNJESOL.js +10 -0
- package/dist/chunks/AWB4A65P.js +63 -0
- package/dist/chunks/C2UUZY6J.js +2 -0
- package/dist/chunks/DGUZCGQN.js +3 -0
- package/dist/chunks/H24ZP5D5.js +16 -0
- package/dist/chunks/I6NRCYLI.js +3 -0
- package/dist/chunks/JJGEV4EZ.js +3 -0
- package/dist/chunks/KRSURB5L.js +5 -0
- package/dist/chunks/KRVF37OW.js +3 -0
- package/dist/chunks/KUDCC7ZO.js +6 -0
- package/dist/chunks/M3NRPJK2.js +77 -0
- package/dist/chunks/M4AFZHKH.js +3 -0
- package/dist/chunks/M52LJEES.js +6 -0
- package/dist/chunks/O2LNVFUT.js +3 -0
- package/dist/chunks/OJPBI7KB.js +3 -0
- package/dist/chunks/OMN6C7J6.js +3 -0
- package/dist/chunks/PBMBFWLQ.js +3 -0
- package/dist/chunks/PBRQ3HEG.js +3 -0
- package/dist/chunks/PFFVGFPL.js +45 -0
- package/dist/chunks/QRGNEKME.js +5 -0
- package/dist/chunks/TNLCNVA2.js +3 -0
- package/dist/chunks/U27JJKJ6.js +3 -0
- package/dist/chunks/U6QAYG3E.js +3 -0
- package/dist/chunks/UEOQE77N.js +4 -0
- package/dist/chunks/WSACSE45.js +4 -0
- package/dist/chunks/WY7WHEJ4.js +3 -0
- package/dist/chunks/XJKWLK43.js +4 -0
- package/dist/chunks/XN6D5S55.js +3 -0
- package/dist/chunks/YD3MIP7B.js +5 -0
- package/dist/chunks/YXDQ62BB.js +4 -0
- package/dist/cli.js +21 -294
- package/dist/connector/admin-broker.js +3 -302
- package/dist/connector/main.js +20 -18
- package/dist/harfbuzz-subset.wasm +0 -0
- package/dist/postinstall.js +17 -0
- package/herdr-plugin.toml +1 -1
- package/node_modules/herdr-remote-relay/bin/herdr-remote-relay.js +33 -92
- package/node_modules/herdr-remote-relay/package.json +3 -46
- package/package.json +8 -27
- package/dist/agent-status.js +0 -130
- package/dist/binary-plist.js +0 -157
- package/dist/config.js +0 -278
- package/dist/connector/admin-broker-setup.js +0 -40
- package/dist/connector/admin-shell.js +0 -67
- package/dist/connector/admin-tab.js +0 -90
- package/dist/connector/adminBrokerEndpoint.js +0 -68
- package/dist/connector/agent-watch.js +0 -123
- package/dist/connector/elevatedPty.js +0 -141
- package/dist/connector/font-server.js +0 -165
- package/dist/connector/herdr-prefix-keys.js +0 -28
- package/dist/connector/host-connector.js +0 -433
- package/dist/connector/host-hello.js +0 -32
- package/dist/connector/lock.js +0 -73
- package/dist/connector/sessions.js +0 -381
- package/dist/connector/update-report.js +0 -70
- package/dist/connector/wire.js +0 -42
- package/dist/exit-codes.js +0 -13
- package/dist/font-subset.js +0 -110
- package/dist/herdr-api.js +0 -254
- package/dist/herdr-command.js +0 -245
- package/dist/herdr-plugin.js +0 -120
- package/dist/herdr-server.js +0 -190
- package/dist/i18n/en.js +0 -257
- package/dist/i18n/index.js +0 -48
- package/dist/i18n/zh.js +0 -256
- package/dist/keepalive/detached.js +0 -97
- package/dist/keepalive/environment.js +0 -44
- package/dist/keepalive/index.js +0 -129
- package/dist/keepalive/launchd.js +0 -117
- package/dist/keepalive/systemd.js +0 -112
- package/dist/keepalive/types.js +0 -1
- package/dist/keepalive/windows-service-setup.js +0 -138
- package/dist/keepalive/windows-service.js +0 -272
- package/dist/keepalive/windows-task.js +0 -191
- package/dist/lib/process.js +0 -132
- package/dist/lifecycle.js +0 -79
- package/dist/net-interfaces.js +0 -82
- package/dist/node-pty-loader.js +0 -80
- package/dist/pasted-files.js +0 -115
- package/dist/paths.js +0 -74
- package/dist/pty-session.js +0 -133
- package/dist/relay-client.js +0 -106
- package/dist/relay-urls.js +0 -99
- package/dist/runtime.js +0 -107
- package/dist/service.js +0 -267
- package/dist/settings-model.js +0 -298
- package/dist/socket-discovery.js +0 -70
- package/dist/supervisor.js +0 -323
- package/dist/terminal-font/deps.js +0 -83
- package/dist/terminal-font/files.js +0 -357
- package/dist/terminal-font/formats.js +0 -355
- package/dist/terminal-font/index.js +0 -187
- package/dist/terminal-font/readers.js +0 -373
- package/dist/terminal-font/terminals.js +0 -147
- package/dist/terminal-palette.js +0 -399
- package/dist/tui/App.js +0 -199
- package/dist/tui/api.js +0 -91
- package/dist/tui/components/TextField.js +0 -50
- package/dist/tui/components/common.js +0 -80
- package/dist/tui/index.js +0 -36
- package/dist/tui/mouse/index.js +0 -164
- package/dist/tui/mouse/protocol.js +0 -96
- package/dist/tui/mouse/source.js +0 -79
- package/dist/tui/screens/About.js +0 -172
- package/dist/tui/screens/Herdr.js +0 -75
- package/dist/tui/screens/Keepalive.js +0 -141
- package/dist/tui/screens/Overview.js +0 -36
- package/dist/tui/screens/Pair.js +0 -74
- package/dist/tui/screens/Relay.js +0 -243
- package/dist/tui/screens/Services.js +0 -63
- package/dist/tui/screens/Wizard.js +0 -241
- package/dist/tui/terminal.js +0 -39
- package/dist/tui/theme.js +0 -33
- package/dist/update-command.js +0 -118
- package/dist/updater/in-place.js +0 -83
- package/dist/updater/npm.js +0 -62
- package/dist/updater.js +0 -401
- package/node_modules/herdr-remote-relay/README.md +0 -76
- package/node_modules/herdr-remote-relay/README.zh-CN.md +0 -76
- package/node_modules/herdr-remote-relay/config.example.json +0 -18
- package/node_modules/herdr-remote-relay/deploy/cloudflared/config.yml.example +0 -9
- package/node_modules/herdr-remote-relay/deploy/docker/compose.yaml +0 -23
- package/node_modules/herdr-remote-relay/deploy/nginx/herdr-remote-relay.conf.example +0 -49
- package/node_modules/herdr-remote-relay/deploy/systemd/herdr-remote-relay.service +0 -41
- package/node_modules/herdr-remote-relay/deploy/systemd/relay.env.example +0 -25
- package/node_modules/herdr-remote-relay/dist/auth-store.d.ts +0 -114
- package/node_modules/herdr-remote-relay/dist/auth-store.js +0 -289
- package/node_modules/herdr-remote-relay/dist/metrics.d.ts +0 -76
- package/node_modules/herdr-remote-relay/dist/metrics.js +0 -249
- package/node_modules/herdr-remote-relay/dist/protocol/frames.d.ts +0 -27
- package/node_modules/herdr-remote-relay/dist/protocol/frames.js +0 -110
- package/node_modules/herdr-remote-relay/dist/protocol/herdr-keys.d.ts +0 -8
- package/node_modules/herdr-remote-relay/dist/protocol/herdr-keys.js +0 -34
- package/node_modules/herdr-remote-relay/dist/protocol/http.d.ts +0 -165
- package/node_modules/herdr-remote-relay/dist/protocol/http.js +0 -3
- package/node_modules/herdr-remote-relay/dist/protocol/index.d.ts +0 -7
- package/node_modules/herdr-remote-relay/dist/protocol/index.js +0 -9
- package/node_modules/herdr-remote-relay/dist/protocol/messages.d.ts +0 -362
- package/node_modules/herdr-remote-relay/dist/protocol/messages.js +0 -20
- package/node_modules/herdr-remote-relay/dist/protocol/paste.d.ts +0 -14
- package/node_modules/herdr-remote-relay/dist/protocol/paste.js +0 -50
- package/node_modules/herdr-remote-relay/dist/protocol/release.d.ts +0 -8
- package/node_modules/herdr-remote-relay/dist/protocol/release.js +0 -17
- package/node_modules/herdr-remote-relay/dist/protocol/terminal.d.ts +0 -79
- package/node_modules/herdr-remote-relay/dist/protocol/terminal.js +0 -150
- package/node_modules/herdr-remote-relay/dist/relay-config.d.ts +0 -74
- package/node_modules/herdr-remote-relay/dist/relay-config.js +0 -316
- package/node_modules/herdr-remote-relay/dist/relay-server.d.ts +0 -67
- package/node_modules/herdr-remote-relay/dist/relay-server.js +0 -196
- package/node_modules/herdr-remote-relay/dist/scroll-input.d.ts +0 -17
- package/node_modules/herdr-remote-relay/dist/scroll-input.js +0 -124
- package/node_modules/herdr-remote-relay/dist/server/client-channel.d.ts +0 -3
- package/node_modules/herdr-remote-relay/dist/server/client-channel.js +0 -396
- package/node_modules/herdr-remote-relay/dist/server/font-proxy.d.ts +0 -19
- package/node_modules/herdr-remote-relay/dist/server/font-proxy.js +0 -155
- package/node_modules/herdr-remote-relay/dist/server/host-broadcasts.d.ts +0 -27
- package/node_modules/herdr-remote-relay/dist/server/host-broadcasts.js +0 -83
- package/node_modules/herdr-remote-relay/dist/server/host-channel.d.ts +0 -3
- package/node_modules/herdr-remote-relay/dist/server/host-channel.js +0 -271
- package/node_modules/herdr-remote-relay/dist/server/http-api.d.ts +0 -4
- package/node_modules/herdr-remote-relay/dist/server/http-api.js +0 -219
- package/node_modules/herdr-remote-relay/dist/server/maintenance.d.ts +0 -5
- package/node_modules/herdr-remote-relay/dist/server/maintenance.js +0 -64
- package/node_modules/herdr-remote-relay/dist/server/requests.d.ts +0 -34
- package/node_modules/herdr-remote-relay/dist/server/requests.js +0 -142
- package/node_modules/herdr-remote-relay/dist/server/sessions.d.ts +0 -36
- package/node_modules/herdr-remote-relay/dist/server/sessions.js +0 -230
- package/node_modules/herdr-remote-relay/dist/server/sockets.d.ts +0 -12
- package/node_modules/herdr-remote-relay/dist/server/sockets.js +0 -64
- package/node_modules/herdr-remote-relay/dist/server/status.d.ts +0 -11
- package/node_modules/herdr-remote-relay/dist/server/status.js +0 -99
- package/node_modules/herdr-remote-relay/dist/server/transport.d.ts +0 -16
- package/node_modules/herdr-remote-relay/dist/server/transport.js +0 -110
- package/node_modules/herdr-remote-relay/dist/server/types.d.ts +0 -133
- package/node_modules/herdr-remote-relay/dist/server/types.js +0 -3
- package/node_modules/herdr-remote-relay/dist/server/version.d.ts +0 -2
- package/node_modules/herdr-remote-relay/dist/server/version.js +0 -5
- package/node_modules/herdr-remote-relay/dist/state.d.ts +0 -6
- package/node_modules/herdr-remote-relay/dist/state.js +0 -47
- package/node_modules/ws/LICENSE +0 -20
- package/node_modules/ws/README.md +0 -548
- package/node_modules/ws/browser.js +0 -8
- package/node_modules/ws/index.js +0 -22
- package/node_modules/ws/lib/buffer-util.js +0 -131
- package/node_modules/ws/lib/constants.js +0 -19
- package/node_modules/ws/lib/event-target.js +0 -292
- package/node_modules/ws/lib/extension.js +0 -203
- package/node_modules/ws/lib/limiter.js +0 -55
- package/node_modules/ws/lib/permessage-deflate.js +0 -530
- package/node_modules/ws/lib/receiver.js +0 -743
- package/node_modules/ws/lib/sender.js +0 -607
- package/node_modules/ws/lib/stream.js +0 -161
- package/node_modules/ws/lib/subprotocol.js +0 -62
- package/node_modules/ws/lib/validation.js +0 -152
- package/node_modules/ws/lib/websocket-server.js +0 -562
- package/node_modules/ws/lib/websocket.js +0 -1407
- package/node_modules/ws/package.json +0 -74
- package/node_modules/ws/wrapper.mjs +0 -21
package/dist/cli.js
CHANGED
|
@@ -1,19 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
// the subcommands exist for scripting and for the actions declared in
|
|
5
|
-
// herdr-plugin.toml, which Herdr runs without a terminal attached.
|
|
6
|
-
import fs from 'node:fs';
|
|
7
|
-
import os from 'node:os';
|
|
8
|
-
import path from 'node:path';
|
|
9
|
-
import { LANGUAGES, loadConfig, migrateLegacyConfig } from './config.js';
|
|
10
|
-
import { PACKAGE_ROOT, configPath, stateDir } from './paths.js';
|
|
11
|
-
import { extractPairingCode } from './relay-client.js';
|
|
12
|
-
import { resolvePublicUrl } from './relay-urls.js';
|
|
13
|
-
import { createTranslator, detectLocale } from './i18n/index.js';
|
|
14
|
-
import { preferredLanAddress } from './net-interfaces.js';
|
|
15
|
-
const VERSION = JSON.parse(fs.readFileSync(path.join(PACKAGE_ROOT, 'package.json'), 'utf8')).version;
|
|
16
|
-
const USAGE = `herdr-remote ${VERSION} — browser access to Herdr workspaces
|
|
1
|
+
import { createRequire as __herdrCreateRequire } from 'node:module';
|
|
2
|
+
const require = __herdrCreateRequire(import.meta.url);
|
|
3
|
+
import{a as y,b as A}from"./chunks/XN6D5S55.js";import{f as S,h as w}from"./chunks/DGUZCGQN.js";import"./chunks/U6QAYG3E.js";import{f as m,l as v,n as $,o as k}from"./chunks/M52LJEES.js";import"./chunks/KRVF37OW.js";import"./chunks/QRGNEKME.js";import"./chunks/PBMBFWLQ.js";import{a as d,c as h,d as g}from"./chunks/TNLCNVA2.js";import"./chunks/I6NRCYLI.js";import U from"node:fs";import P from"node:os";import u from"node:path";var j=JSON.parse(U.readFileSync(u.join(d,"package.json"),"utf8")).version,f=`herdr-remote ${j} \u2014 browser access to Herdr workspaces
|
|
17
4
|
|
|
18
5
|
Usage: herdr-remote [command] [options]
|
|
19
6
|
|
|
@@ -39,281 +26,21 @@ Options:
|
|
|
39
26
|
-v, --version Show version
|
|
40
27
|
|
|
41
28
|
Self-hosting: docs/self-hosted-relay.md
|
|
42
|
-
`;
|
|
43
|
-
function
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (arg === '--help' || arg === '-h') {
|
|
61
|
-
flags.help = true;
|
|
62
|
-
continue;
|
|
63
|
-
}
|
|
64
|
-
if (arg === '--version' || arg === '-v') {
|
|
65
|
-
flags.version = true;
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
if (arg === '--lang') {
|
|
69
|
-
flags.lang = argv[index + 1];
|
|
70
|
-
index += 1;
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
73
|
-
if (arg.startsWith('--lang=')) {
|
|
74
|
-
flags.lang = arg.slice('--lang='.length);
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
if (arg.startsWith('-')) {
|
|
78
|
-
flags.unknown = arg;
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
positional.push(arg);
|
|
82
|
-
}
|
|
83
|
-
return { positional, flags };
|
|
84
|
-
}
|
|
85
|
-
function printJson(value) {
|
|
86
|
-
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
87
|
-
}
|
|
88
|
-
function describeStatus(status, t) {
|
|
89
|
-
const lines = [];
|
|
90
|
-
lines.push(`${t('overview.mode')}: ${t(`mode.${status.mode}`)}`);
|
|
91
|
-
if (status.relay.local) {
|
|
92
|
-
lines.push(`${t('overview.relay')}: ${status.relay.alive ? t('common.running') : t('common.stopped')} (${status.relay.bind}:${status.relay.port})`);
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
95
|
-
lines.push(`${t('overview.relay')}: ${status.relay.remoteUrl}`);
|
|
96
|
-
}
|
|
97
|
-
lines.push(`${t('overview.host')}: ${status.host.alive ? t('common.running') : t('common.stopped')}`);
|
|
98
|
-
lines.push(`${t('overview.socket')}: ${status.host.socketPath}${status.host.socketExists ? '' : ` (${t('overview.socketMissing')})`}`);
|
|
99
|
-
lines.push(`${t('overview.webUrl')}: ${status.publicUrl}`);
|
|
100
|
-
if (status.keepalive) {
|
|
101
|
-
const state = status.keepalive.active
|
|
102
|
-
? t('common.running')
|
|
103
|
-
: status.keepalive.installed
|
|
104
|
-
? t('common.installed')
|
|
105
|
-
: t('common.notInstalled');
|
|
106
|
-
lines.push(`${t('overview.keepalive')}: ${status.keepalive.manager} — ${state}`);
|
|
107
|
-
}
|
|
108
|
-
if (status.relay.health && status.relay.health.ok === false) {
|
|
109
|
-
lines.push(`${t('overview.relay')}: ${t('overview.unreachable', { message: status.relay.health.message ?? '' })}`);
|
|
110
|
-
}
|
|
111
|
-
return lines.join('\n');
|
|
112
|
-
}
|
|
113
|
-
async function runTui(options) {
|
|
114
|
-
const { startTui } = await import('./tui/index.js');
|
|
115
|
-
await startTui(options);
|
|
116
|
-
}
|
|
117
|
-
async function main(argv = process.argv.slice(2)) {
|
|
118
|
-
const { positional, flags } = parseArgs(argv);
|
|
119
|
-
if (process.platform === 'win32') {
|
|
120
|
-
const relative = path.relative(PACKAGE_ROOT, process.cwd());
|
|
121
|
-
const insidePackage = relative === '' ||
|
|
122
|
-
(relative !== '..' && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative));
|
|
123
|
-
if (insidePackage) {
|
|
124
|
-
// Herdr starts plugin panels in PACKAGE_ROOT; Windows locks the cwd,
|
|
125
|
-
// preventing npm from replacing that directory.
|
|
126
|
-
process.chdir(os.homedir());
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
const command = positional[0] || null;
|
|
130
|
-
// Answered before anything reads the config or queries the terminal.
|
|
131
|
-
if (flags.help) {
|
|
132
|
-
process.stdout.write(USAGE);
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
if (flags.version) {
|
|
136
|
-
process.stdout.write(`${VERSION}\n`);
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
if (flags.unknown) {
|
|
140
|
-
process.stderr.write(`herdr-remote: unknown option "${flags.unknown}"\n\n${USAGE}`);
|
|
141
|
-
process.exitCode = 2;
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
migrateLegacyConfig();
|
|
145
|
-
// Ask the terminal for its colors while it is still a plain terminal: the
|
|
146
|
-
// TUI takes the screen a few lines below, and the services this command
|
|
147
|
-
// starts usually run detached with nothing to ask. Everything downstream
|
|
148
|
-
// inherits the answer through the environment.
|
|
149
|
-
await (await import('./terminal-palette.js')).captureTerminalPalette();
|
|
150
|
-
// The font, likewise, is read while this process still knows which terminal
|
|
151
|
-
// it runs in: its variables and its parent process are gone once a service
|
|
152
|
-
// manager or Herdr's detached server starts the connector.
|
|
153
|
-
(await import('./terminal-font/index.js')).captureTerminalFont();
|
|
154
|
-
const config = loadConfig();
|
|
155
|
-
const preference = flags.lang && LANGUAGES.includes(flags.lang)
|
|
156
|
-
? flags.lang
|
|
157
|
-
: config.ui.language;
|
|
158
|
-
const t = createTranslator(detectLocale({ preference }));
|
|
159
|
-
// Loaded lazily so that the TUI does not pay for loading the
|
|
160
|
-
// service layer (which pulls in the relay package and node-pty).
|
|
161
|
-
const lifecycle = await import('./lifecycle.js');
|
|
162
|
-
const service = await import('./service.js');
|
|
163
|
-
switch (command) {
|
|
164
|
-
case null: {
|
|
165
|
-
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
166
|
-
await runTui({ language: flags.lang || null });
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
// Herdr runs plugin panes and actions without a TTY; emit status instead
|
|
170
|
-
// of trying to paint an interface into a pipe.
|
|
171
|
-
printJson(await lifecycle.fullStatus(config));
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
case 'start': {
|
|
175
|
-
const result = lifecycle.startAll(config);
|
|
176
|
-
if (flags.json)
|
|
177
|
-
printJson(result);
|
|
178
|
-
else
|
|
179
|
-
process.stdout.write(`${t('services.started')}\n${describeStatus(await lifecycle.fullStatus(config), t)}\n`);
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
case 'stop': {
|
|
183
|
-
const result = lifecycle.stopAll(config);
|
|
184
|
-
if (flags.json)
|
|
185
|
-
printJson(result);
|
|
186
|
-
else
|
|
187
|
-
process.stdout.write(`${t('services.stopped')}\n`);
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
case 'restart': {
|
|
191
|
-
const result = lifecycle.restartAll(config);
|
|
192
|
-
if (flags.json)
|
|
193
|
-
printJson(result);
|
|
194
|
-
else
|
|
195
|
-
process.stdout.write(`${t('services.restarted')}\n`);
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
case 'status': {
|
|
199
|
-
const status = await lifecycle.fullStatus(config);
|
|
200
|
-
if (flags.json)
|
|
201
|
-
printJson(status);
|
|
202
|
-
else
|
|
203
|
-
process.stdout.write(`${describeStatus(status, t)}\n`);
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
case 'pair': {
|
|
207
|
-
const pairing = await service.pair();
|
|
208
|
-
if (flags.json) {
|
|
209
|
-
printJson(pairing);
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
const code = extractPairingCode(pairing);
|
|
213
|
-
const url = pairing.pairUrl ||
|
|
214
|
-
`${resolvePublicUrl(config, preferredLanAddress())}/?pairCode=${encodeURIComponent(code)}`;
|
|
215
|
-
const minutes = `${Math.round((config.auth.pairingTtlMs || 600000) / 60000)}m`;
|
|
216
|
-
process.stdout.write(`${t('pair.code')}: ${code}\n${t('pair.url')}: ${url}\n${t('pair.expires', { minutes, time: new Date(pairing.expiresAt).toLocaleTimeString() })}\n`);
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
case 'url': {
|
|
220
|
-
process.stdout.write(`${resolvePublicUrl(config, preferredLanAddress())}\n`);
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
223
|
-
case 'update': {
|
|
224
|
-
const { runUpdate } = await import('./update-command.js');
|
|
225
|
-
const outcome = await runUpdate(t, {
|
|
226
|
-
config,
|
|
227
|
-
...(flags.json ? { report: () => { } } : {}),
|
|
228
|
-
});
|
|
229
|
-
if (flags.json)
|
|
230
|
-
printJson(outcome);
|
|
231
|
-
if (!outcome.ok)
|
|
232
|
-
process.exitCode = 1;
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
case 'run': {
|
|
236
|
-
const { runForeground } = await import('./supervisor.js');
|
|
237
|
-
await runForeground({ logToFiles: Boolean(flags.daemon) });
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
case 'admin-broker': {
|
|
241
|
-
const broker = await import('./connector/admin-broker.js');
|
|
242
|
-
const action = positional[1] || 'status';
|
|
243
|
-
if (action === 'install') {
|
|
244
|
-
broker.installAdminBroker(t);
|
|
245
|
-
printJson({ installed: true, available: await broker.waitForAdminBroker() });
|
|
246
|
-
}
|
|
247
|
-
else if (action === 'uninstall') {
|
|
248
|
-
broker.uninstallAdminBroker(t);
|
|
249
|
-
printJson({ installed: false });
|
|
250
|
-
}
|
|
251
|
-
else if (action === 'restart') {
|
|
252
|
-
if ((await broker.stopAdminBroker()) === 'busy')
|
|
253
|
-
throw new Error(t('adminBroker.busy'));
|
|
254
|
-
broker.startAdminBrokerTask(t);
|
|
255
|
-
printJson({ available: await broker.waitForAdminBroker() });
|
|
256
|
-
}
|
|
257
|
-
else if (action === 'status') {
|
|
258
|
-
printJson({ available: await broker.adminBrokerStatus() });
|
|
259
|
-
}
|
|
260
|
-
else {
|
|
261
|
-
throw new Error(`unknown administrator broker action: ${action}`);
|
|
262
|
-
}
|
|
263
|
-
return;
|
|
264
|
-
}
|
|
265
|
-
case 'admin-shell': {
|
|
266
|
-
const { runAdminShell } = await import('./connector/admin-shell.js');
|
|
267
|
-
process.exitCode = await runAdminShell(t);
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
case 'keepalive': {
|
|
271
|
-
const keepalive = await import('./keepalive/index.js');
|
|
272
|
-
const action = positional[1] || 'status';
|
|
273
|
-
if (action === 'install' && flags.elevated) {
|
|
274
|
-
const { completeServiceInstall } = await import('./keepalive/windows-service-setup.js');
|
|
275
|
-
process.exitCode = await completeServiceInstall(t);
|
|
276
|
-
}
|
|
277
|
-
else if (action === 'install')
|
|
278
|
-
printJson(await keepalive.install(config));
|
|
279
|
-
else if (action === 'uninstall')
|
|
280
|
-
printJson(await keepalive.uninstall(config));
|
|
281
|
-
else if (action === 'restart')
|
|
282
|
-
printJson(keepalive.restart(config));
|
|
283
|
-
else if (action === 'status')
|
|
284
|
-
printJson(keepalive.status(config));
|
|
285
|
-
else
|
|
286
|
-
throw new Error(`unknown keepalive action: ${action}`);
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
case 'plugin': {
|
|
290
|
-
const plugin = await import('./herdr-plugin.js');
|
|
291
|
-
const action = positional[1] || 'status';
|
|
292
|
-
if (action === 'link')
|
|
293
|
-
printJson(plugin.register());
|
|
294
|
-
else if (action === 'unlink')
|
|
295
|
-
printJson(plugin.unregister());
|
|
296
|
-
else if (action === 'status')
|
|
297
|
-
printJson(plugin.registrationStatus());
|
|
298
|
-
else
|
|
299
|
-
throw new Error(`unknown plugin action: ${action}`);
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
case 'config': {
|
|
303
|
-
// Handy when reporting a problem: where does this install read from?
|
|
304
|
-
printJson({ configPath: configPath(), stateDir: stateDir(), config });
|
|
305
|
-
return;
|
|
306
|
-
}
|
|
307
|
-
default:
|
|
308
|
-
process.stderr.write(`herdr-remote: unknown command "${command}"\n\n${USAGE}`);
|
|
309
|
-
process.exitCode = 2;
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
/** Runs the command line and reports a failure as the exit code. */
|
|
313
|
-
function run() {
|
|
314
|
-
main().catch((error) => {
|
|
315
|
-
process.stderr.write(`herdr-remote: ${error.message}\n`);
|
|
316
|
-
process.exitCode = 1;
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
export { run, parseArgs, describeStatus };
|
|
29
|
+
`;function E(n){let s=[],t={};for(let l=0;l<n.length;l+=1){let r=n[l];if(r==="--json"){t.json=!0;continue}if(r==="--daemon"){t.daemon=!0;continue}if(r==="--elevated"){t.elevated=!0;continue}if(r==="--help"||r==="-h"){t.help=!0;continue}if(r==="--version"||r==="-v"){t.version=!0;continue}if(r==="--lang"){t.lang=n[l+1],l+=1;continue}if(r.startsWith("--lang=")){t.lang=r.slice(7);continue}if(r.startsWith("-")){t.unknown=r;continue}s.push(r)}return{positional:s,flags:t}}function i(n){process.stdout.write(`${JSON.stringify(n,null,2)}
|
|
30
|
+
`)}function b(n,s){let t=[];if(t.push(`${s("overview.mode")}: ${s(`mode.${n.mode}`)}`),n.relay.local?t.push(`${s("overview.relay")}: ${n.relay.alive?s("common.running"):s("common.stopped")} (${n.relay.bind}:${n.relay.port})`):t.push(`${s("overview.relay")}: ${n.relay.remoteUrl}`),t.push(`${s("overview.host")}: ${n.host.alive?s("common.running"):s("common.stopped")}`),t.push(`${s("overview.socket")}: ${n.host.socketPath}${n.host.socketExists?"":` (${s("overview.socketMissing")})`}`),t.push(`${s("overview.webUrl")}: ${n.publicUrl}`),n.keepalive){let l=n.keepalive.active?s("common.running"):n.keepalive.installed?s("common.installed"):s("common.notInstalled");t.push(`${s("overview.keepalive")}: ${n.keepalive.manager} \u2014 ${l}`)}return n.relay.health&&n.relay.health.ok===!1&&t.push(`${s("overview.relay")}: ${s("overview.unreachable",{message:n.relay.health.message??""})}`),t.join(`
|
|
31
|
+
`)}async function B(n){let{startTui:s}=await import("./chunks/M3NRPJK2.js");await s(n)}async function O(n=process.argv.slice(2)){let{positional:s,flags:t}=E(n);if(process.platform==="win32"){let e=u.relative(d,process.cwd());(e===""||e!==".."&&!e.startsWith(`..${u.sep}`)&&!u.isAbsolute(e))&&process.chdir(P.homedir())}let l=s[0]||null;if(t.help){process.stdout.write(f);return}if(t.version){process.stdout.write(`${j}
|
|
32
|
+
`);return}if(t.unknown){process.stderr.write(`herdr-remote: unknown option "${t.unknown}"
|
|
33
|
+
|
|
34
|
+
${f}`),process.exitCode=2;return}$(),await(await import("./chunks/O2LNVFUT.js")).captureTerminalPalette(),(await import("./chunks/WY7WHEJ4.js")).captureTerminalFont();let r=k(),T=t.lang&&v.includes(t.lang)?t.lang:r.ui.language,a=A(y({preference:T})),c=await import("./chunks/353DMT35.js"),C=await import("./chunks/OJPBI7KB.js");switch(l){case null:{if(process.stdin.isTTY&&process.stdout.isTTY){await B({language:t.lang||null});return}i(await c.fullStatus(r));return}case"start":{let e=c.startAll(r);t.json?i(e):process.stdout.write(`${a("services.started")}
|
|
35
|
+
${b(await c.fullStatus(r),a)}
|
|
36
|
+
`);return}case"stop":{let e=c.stopAll(r);t.json?i(e):process.stdout.write(`${a("services.stopped")}
|
|
37
|
+
`);return}case"restart":{let e=c.restartAll(r);t.json?i(e):process.stdout.write(`${a("services.restarted")}
|
|
38
|
+
`);return}case"status":{let e=await c.fullStatus(r);t.json?i(e):process.stdout.write(`${b(e,a)}
|
|
39
|
+
`);return}case"pair":{let e=await C.pair();if(t.json){i(e);return}let o=S(e),p=e.pairUrl||`${m(r,w())}/?pairCode=${encodeURIComponent(o)}`,x=`${Math.round((r.auth.pairingTtlMs||6e5)/6e4)}m`;process.stdout.write(`${a("pair.code")}: ${o}
|
|
40
|
+
${a("pair.url")}: ${p}
|
|
41
|
+
${a("pair.expires",{minutes:x,time:new Date(e.expiresAt).toLocaleTimeString()})}
|
|
42
|
+
`);return}case"url":{process.stdout.write(`${m(r,w())}
|
|
43
|
+
`);return}case"update":{let{runUpdate:e}=await import("./chunks/WSACSE45.js"),o=await e(a,{config:r,...t.json?{report:()=>{}}:{}});t.json&&i(o),o.ok||(process.exitCode=1);return}case"run":{let{runForeground:e}=await import("./chunks/YD3MIP7B.js");await e({logToFiles:!!t.daemon});return}case"admin-broker":{let e=await import("./connector/admin-broker.js"),o=s[1]||"status";if(o==="install")e.installAdminBroker(a),i({installed:!0,available:await e.waitForAdminBroker()});else if(o==="uninstall")e.uninstallAdminBroker(a),i({installed:!1});else if(o==="restart"){if(await e.stopAdminBroker()==="busy")throw new Error(a("adminBroker.busy"));e.startAdminBrokerTask(a),i({available:await e.waitForAdminBroker()})}else if(o==="status")i({available:await e.adminBrokerStatus()});else throw new Error(`unknown administrator broker action: ${o}`);return}case"admin-shell":{let{runAdminShell:e}=await import("./chunks/YXDQ62BB.js");process.exitCode=await e(a);return}case"keepalive":{let e=await import("./chunks/OMN6C7J6.js"),o=s[1]||"status";if(o==="install"&&t.elevated){let{completeServiceInstall:p}=await import("./chunks/AM3OEMFK.js");process.exitCode=await p(a)}else if(o==="install")i(await e.install(r));else if(o==="uninstall")i(await e.uninstall(r));else if(o==="restart")i(e.restart(r));else if(o==="status")i(e.status(r));else throw new Error(`unknown keepalive action: ${o}`);return}case"plugin":{let e=await import("./chunks/XJKWLK43.js"),o=s[1]||"status";if(o==="link")i(e.register());else if(o==="unlink")i(e.unregister());else if(o==="status")i(e.registrationStatus());else throw new Error(`unknown plugin action: ${o}`);return}case"config":{i({configPath:g(),stateDir:h(),config:r});return}default:process.stderr.write(`herdr-remote: unknown command "${l}"
|
|
44
|
+
|
|
45
|
+
${f}`),process.exitCode=2}}function M(){O().catch(n=>{process.stderr.write(`herdr-remote: ${n.message}
|
|
46
|
+
`),process.exitCode=1})}export{b as describeStatus,E as parseArgs,M as run};
|
|
@@ -1,302 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
import path from 'node:path';
|
|
5
|
-
import { fileURLToPath } from 'node:url';
|
|
6
|
-
import { PtySession } from '../pty-session.js';
|
|
7
|
-
import { stateDir } from '../paths.js';
|
|
8
|
-
import { ADMIN_BROKER_MAX_MESSAGE_BYTES, adminBrokerTaskName, adminBrokerTokenMatches, connectAdminBroker, listenAdminBroker, publishAdminBrokerEndpoint, sendAdminBrokerMessage, } from './adminBrokerEndpoint.js';
|
|
9
|
-
const BROKER_PING_TIMEOUT_MS = 1_000;
|
|
10
|
-
const BROKER_START_TIMEOUT_MS = 5_000;
|
|
11
|
-
const BROKER_START_POLL_MS = 250;
|
|
12
|
-
const BROKER_TASK_END_TIMEOUT_MS = 10_000;
|
|
13
|
-
/** Time for a stopping broker's goodbye to reach the caller before the process ends. */
|
|
14
|
-
const BROKER_EXIT_GRACE_MS = 1_000;
|
|
15
|
-
function powershellQuote(value) {
|
|
16
|
-
return `'${value.replaceAll("'", "''")}'`;
|
|
17
|
-
}
|
|
18
|
-
function runPowerShell(script, t) {
|
|
19
|
-
try {
|
|
20
|
-
execFileSync('powershell.exe', [
|
|
21
|
-
'-NoProfile',
|
|
22
|
-
'-NonInteractive',
|
|
23
|
-
'-EncodedCommand',
|
|
24
|
-
Buffer.from(script, 'utf16le').toString('base64'),
|
|
25
|
-
], {
|
|
26
|
-
stdio: 'pipe',
|
|
27
|
-
windowsHide: true,
|
|
28
|
-
timeout: 15_000,
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
catch {
|
|
32
|
-
throw new Error(t('adminBroker.needsElevation'));
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
/** Registers and starts the broker's logon task; run elevated. */
|
|
36
|
-
export function adminBrokerTaskScript() {
|
|
37
|
-
const brokerPath = fileURLToPath(import.meta.url);
|
|
38
|
-
// Pinned so the broker publishes its endpoint where this install's callers look.
|
|
39
|
-
const brokerCommand = `$env:HERDR_REMOTE_STATE_DIR = ${powershellQuote(stateDir())}; & ${powershellQuote(process.execPath)} ${powershellQuote(brokerPath)}`;
|
|
40
|
-
const encodedBrokerCommand = Buffer.from(brokerCommand, 'utf16le').toString('base64');
|
|
41
|
-
const powershell = path.join(process.env.SystemRoot || 'C:\\Windows', 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe');
|
|
42
|
-
// Not PACKAGE_ROOT: npm updates the package by renaming its directory, and
|
|
43
|
-
// Windows refuses while it is the working directory of this long-lived task.
|
|
44
|
-
return `
|
|
45
|
-
$ErrorActionPreference = 'Stop'
|
|
46
|
-
$taskName = ${powershellQuote(adminBrokerTaskName())}
|
|
47
|
-
$user = [Security.Principal.WindowsIdentity]::GetCurrent().Name
|
|
48
|
-
$action = New-ScheduledTaskAction -Execute ${powershellQuote(powershell)} -Argument ${powershellQuote(`-NoProfile -NonInteractive -WindowStyle Hidden -EncodedCommand ${encodedBrokerCommand}`)} -WorkingDirectory ${powershellQuote(stateDir())}
|
|
49
|
-
$trigger = New-ScheduledTaskTrigger -AtLogOn -User $user
|
|
50
|
-
$principal = New-ScheduledTaskPrincipal -UserId $user -LogonType Interactive -RunLevel Highest
|
|
51
|
-
$settings = New-ScheduledTaskSettingsSet -MultipleInstances IgnoreNew -StartWhenAvailable -ExecutionTimeLimit (New-TimeSpan -Seconds 0)
|
|
52
|
-
Stop-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue
|
|
53
|
-
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Force | Out-Null
|
|
54
|
-
Start-ScheduledTask -TaskName $taskName
|
|
55
|
-
`;
|
|
56
|
-
}
|
|
57
|
-
export function installAdminBroker(t) {
|
|
58
|
-
if (process.platform !== 'win32')
|
|
59
|
-
throw new Error(t('adminBroker.windowsOnly'));
|
|
60
|
-
// The task cannot start in a working directory that does not exist yet.
|
|
61
|
-
fs.mkdirSync(stateDir(), { recursive: true });
|
|
62
|
-
runPowerShell(adminBrokerTaskScript(), t);
|
|
63
|
-
}
|
|
64
|
-
export function uninstallAdminBroker(t) {
|
|
65
|
-
if (process.platform !== 'win32')
|
|
66
|
-
throw new Error(t('adminBroker.windowsOnly'));
|
|
67
|
-
runPowerShell(`
|
|
68
|
-
$ErrorActionPreference = 'Stop'
|
|
69
|
-
$taskName = ${powershellQuote(adminBrokerTaskName())}
|
|
70
|
-
Stop-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue
|
|
71
|
-
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue
|
|
72
|
-
`, t);
|
|
73
|
-
}
|
|
74
|
-
/** Send the broker one request and read the type of its one reply, or null without one. */
|
|
75
|
-
function requestAdminBroker(type) {
|
|
76
|
-
let broker;
|
|
77
|
-
try {
|
|
78
|
-
broker = connectAdminBroker();
|
|
79
|
-
}
|
|
80
|
-
catch {
|
|
81
|
-
return Promise.resolve(null);
|
|
82
|
-
}
|
|
83
|
-
const { socket, token } = broker;
|
|
84
|
-
return new Promise((resolve) => {
|
|
85
|
-
let settled = false;
|
|
86
|
-
let response = '';
|
|
87
|
-
const finish = (reply) => {
|
|
88
|
-
if (settled)
|
|
89
|
-
return;
|
|
90
|
-
settled = true;
|
|
91
|
-
socket.destroy();
|
|
92
|
-
resolve(reply);
|
|
93
|
-
};
|
|
94
|
-
socket.setTimeout(BROKER_PING_TIMEOUT_MS, () => finish(null));
|
|
95
|
-
socket.setEncoding('utf8');
|
|
96
|
-
socket.on('connect', () => sendAdminBrokerMessage(socket, { type, token }));
|
|
97
|
-
socket.on('data', (chunk) => {
|
|
98
|
-
response += chunk;
|
|
99
|
-
const newline = response.indexOf('\n');
|
|
100
|
-
if (newline < 0)
|
|
101
|
-
return;
|
|
102
|
-
try {
|
|
103
|
-
finish(String(JSON.parse(response.slice(0, newline)).type));
|
|
104
|
-
}
|
|
105
|
-
catch {
|
|
106
|
-
finish(null);
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
socket.on('error', () => finish(null));
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
export async function adminBrokerStatus() {
|
|
113
|
-
return (await requestAdminBroker('ping')) === 'pong';
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Ask the broker to exit so its task can start it on a new release. It stays
|
|
117
|
-
* while an administrator terminal is open: that terminal may be the one asking.
|
|
118
|
-
* A broker from before this request answers neither way.
|
|
119
|
-
*/
|
|
120
|
-
export async function stopAdminBroker() {
|
|
121
|
-
const reply = await requestAdminBroker('shutdown');
|
|
122
|
-
return reply === 'bye' ? 'stopped' : reply === 'busy' ? 'busy' : 'unavailable';
|
|
123
|
-
}
|
|
124
|
-
/** Start the broker's task now, which the account that registered it may do unelevated. */
|
|
125
|
-
export function startAdminBrokerTask(t) {
|
|
126
|
-
if (process.platform !== 'win32')
|
|
127
|
-
throw new Error(t('adminBroker.windowsOnly'));
|
|
128
|
-
runPowerShell(`
|
|
129
|
-
$ErrorActionPreference = 'Stop'
|
|
130
|
-
$taskName = ${powershellQuote(adminBrokerTaskName())}
|
|
131
|
-
# A broker that was just stopped may still be ending, and IgnoreNew drops a start until it has.
|
|
132
|
-
$deadline = [DateTime]::UtcNow.AddMilliseconds(${BROKER_TASK_END_TIMEOUT_MS})
|
|
133
|
-
while ((Get-ScheduledTask -TaskName $taskName).State -eq 'Running' -and [DateTime]::UtcNow -lt $deadline) { Start-Sleep -Milliseconds ${BROKER_START_POLL_MS} }
|
|
134
|
-
Start-ScheduledTask -TaskName $taskName
|
|
135
|
-
`, t);
|
|
136
|
-
}
|
|
137
|
-
/** The task starts the broker a moment after it is registered; wait for it to answer. */
|
|
138
|
-
export async function waitForAdminBroker() {
|
|
139
|
-
const deadline = Date.now() + BROKER_START_TIMEOUT_MS;
|
|
140
|
-
while (!(await adminBrokerStatus())) {
|
|
141
|
-
if (Date.now() >= deadline)
|
|
142
|
-
return false;
|
|
143
|
-
await new Promise((resolve) => setTimeout(resolve, BROKER_START_POLL_MS));
|
|
144
|
-
}
|
|
145
|
-
return true;
|
|
146
|
-
}
|
|
147
|
-
function writeError(socket, error) {
|
|
148
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
149
|
-
sendAdminBrokerMessage(socket, { type: 'error', message });
|
|
150
|
-
socket.end();
|
|
151
|
-
}
|
|
152
|
-
function startBrokerPty(socket, message, spawn) {
|
|
153
|
-
if (typeof message.command !== 'string' || !message.command || message.command.length > 4096)
|
|
154
|
-
throw new Error('Invalid administrator terminal command.');
|
|
155
|
-
if (path.basename(message.command).toLowerCase() !== 'powershell.exe')
|
|
156
|
-
throw new Error('The administrator broker only starts PowerShell.');
|
|
157
|
-
if (!Array.isArray(message.args) ||
|
|
158
|
-
message.args.length > 128 ||
|
|
159
|
-
!message.args.every((arg) => typeof arg === 'string'))
|
|
160
|
-
throw new Error('Invalid administrator terminal arguments.');
|
|
161
|
-
if (message.args.length !== 2 ||
|
|
162
|
-
message.args[0] !== '-NoLogo' ||
|
|
163
|
-
message.args[1] !== '-NoProfile')
|
|
164
|
-
throw new Error('The administrator broker only starts an interactive PowerShell prompt.');
|
|
165
|
-
if (typeof message.cwd !== 'string' || message.cwd.length > 4096)
|
|
166
|
-
throw new Error('Invalid administrator terminal working directory.');
|
|
167
|
-
if (message.socketPath !== null && message.socketPath !== undefined)
|
|
168
|
-
throw new Error('An administrator PowerShell session does not use a Herdr socket.');
|
|
169
|
-
const pty = new PtySession({
|
|
170
|
-
command: message.command,
|
|
171
|
-
args: message.args,
|
|
172
|
-
cwd: message.cwd,
|
|
173
|
-
socketPath: message.socketPath,
|
|
174
|
-
platform: 'win32',
|
|
175
|
-
// A plain PowerShell prompt does not need the Herdr UI's Kitty or mouse modes.
|
|
176
|
-
fastWindowsPty: true,
|
|
177
|
-
spawn,
|
|
178
|
-
});
|
|
179
|
-
pty.start({
|
|
180
|
-
cols: PtySession.clampDimension(message.cols, PtySession.DEFAULT_COLS),
|
|
181
|
-
rows: PtySession.clampDimension(message.rows, PtySession.DEFAULT_ROWS),
|
|
182
|
-
onData: (data) => {
|
|
183
|
-
if (socket.writable)
|
|
184
|
-
sendAdminBrokerMessage(socket, {
|
|
185
|
-
type: 'data',
|
|
186
|
-
dataBase64: Buffer.from(data).toString('base64'),
|
|
187
|
-
});
|
|
188
|
-
},
|
|
189
|
-
onExit: ({ exitCode, signal }) => {
|
|
190
|
-
if (socket.writable)
|
|
191
|
-
sendAdminBrokerMessage(socket, { type: 'exit', exitCode, signal });
|
|
192
|
-
socket.end();
|
|
193
|
-
},
|
|
194
|
-
});
|
|
195
|
-
sendAdminBrokerMessage(socket, { type: 'started', pid: pty.terminal?.pid ?? 0 });
|
|
196
|
-
return pty;
|
|
197
|
-
}
|
|
198
|
-
/** Listen on loopback and publish the endpoint; every request must carry its token. */
|
|
199
|
-
export function serveAdminBroker({ spawn, onShutdown = () => { }, } = {}) {
|
|
200
|
-
let token = '';
|
|
201
|
-
const sessions = new Set();
|
|
202
|
-
const server = net.createServer((socket) => {
|
|
203
|
-
socket.setEncoding('utf8');
|
|
204
|
-
let pending = '';
|
|
205
|
-
let pty = null;
|
|
206
|
-
let firstMessage = true;
|
|
207
|
-
socket.on('data', (chunk) => {
|
|
208
|
-
pending += chunk;
|
|
209
|
-
if (Buffer.byteLength(pending, 'utf8') > ADMIN_BROKER_MAX_MESSAGE_BYTES) {
|
|
210
|
-
socket.destroy(new Error('Administrator terminal message exceeded the limit.'));
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
while (true) {
|
|
214
|
-
const newline = pending.indexOf('\n');
|
|
215
|
-
if (newline < 0)
|
|
216
|
-
return;
|
|
217
|
-
const line = pending.slice(0, newline);
|
|
218
|
-
pending = pending.slice(newline + 1);
|
|
219
|
-
let message;
|
|
220
|
-
try {
|
|
221
|
-
message = JSON.parse(line);
|
|
222
|
-
}
|
|
223
|
-
catch {
|
|
224
|
-
writeError(socket, new Error('Invalid administrator terminal message.'));
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
if (firstMessage) {
|
|
228
|
-
firstMessage = false;
|
|
229
|
-
if (!adminBrokerTokenMatches(token, message.token)) {
|
|
230
|
-
writeError(socket, new Error('Administrator terminal request was not authorized.'));
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
if (message.type === 'ping') {
|
|
234
|
-
sendAdminBrokerMessage(socket, { type: 'pong' });
|
|
235
|
-
socket.end();
|
|
236
|
-
return;
|
|
237
|
-
}
|
|
238
|
-
if (message.type === 'shutdown') {
|
|
239
|
-
const busy = sessions.size > 0;
|
|
240
|
-
sendAdminBrokerMessage(socket, { type: busy ? 'busy' : 'bye' });
|
|
241
|
-
socket.end();
|
|
242
|
-
if (!busy) {
|
|
243
|
-
server.close();
|
|
244
|
-
onShutdown();
|
|
245
|
-
}
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
if (message.type !== 'start') {
|
|
249
|
-
writeError(socket, new Error('Expected an administrator terminal start request.'));
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
try {
|
|
253
|
-
pty = startBrokerPty(socket, message, spawn);
|
|
254
|
-
sessions.add(pty);
|
|
255
|
-
}
|
|
256
|
-
catch (error) {
|
|
257
|
-
writeError(socket, error);
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
260
|
-
continue;
|
|
261
|
-
}
|
|
262
|
-
if (!pty)
|
|
263
|
-
return;
|
|
264
|
-
if (message.type === 'input' && typeof message.dataBase64 === 'string') {
|
|
265
|
-
if (message.dataBase64.length <= ADMIN_BROKER_MAX_MESSAGE_BYTES)
|
|
266
|
-
pty.write(Buffer.from(message.dataBase64, 'base64'));
|
|
267
|
-
}
|
|
268
|
-
else if (message.type === 'resize') {
|
|
269
|
-
pty.resize(message.cols, message.rows);
|
|
270
|
-
}
|
|
271
|
-
else if (message.type === 'kill') {
|
|
272
|
-
pty.kill();
|
|
273
|
-
socket.end();
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
});
|
|
278
|
-
const release = () => {
|
|
279
|
-
if (!pty)
|
|
280
|
-
return;
|
|
281
|
-
pty.kill();
|
|
282
|
-
sessions.delete(pty);
|
|
283
|
-
};
|
|
284
|
-
socket.on('close', release);
|
|
285
|
-
socket.on('error', release);
|
|
286
|
-
});
|
|
287
|
-
listenAdminBroker(server, (port) => {
|
|
288
|
-
token = publishAdminBrokerEndpoint(port);
|
|
289
|
-
});
|
|
290
|
-
return server;
|
|
291
|
-
}
|
|
292
|
-
function runAdminBroker() {
|
|
293
|
-
if (process.platform !== 'win32')
|
|
294
|
-
throw new Error('Administrator PTYs are only supported on Windows.');
|
|
295
|
-
serveAdminBroker({
|
|
296
|
-
onShutdown: () => setTimeout(() => process.exit(0), BROKER_EXIT_GRACE_MS).unref(),
|
|
297
|
-
}).on('error', (error) => {
|
|
298
|
-
process.stderr.write(`herdr-remote administrator broker: ${error.message}\n`);
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
|
-
if (path.basename(process.argv[1] || '') === 'admin-broker.js')
|
|
302
|
-
runAdminBroker();
|
|
1
|
+
import { createRequire as __herdrCreateRequire } from 'node:module';
|
|
2
|
+
const require = __herdrCreateRequire(import.meta.url);
|
|
3
|
+
import{e as a,f as b,g as c,h as d,i as e,j as f,k as g,l as h}from"../chunks/42KARAL4.js";import"../chunks/TNLCNVA2.js";import"../chunks/I6NRCYLI.js";export{d as adminBrokerStatus,a as adminBrokerTaskScript,b as installAdminBroker,h as serveAdminBroker,f as startAdminBrokerTask,e as stopAdminBroker,c as uninstallAdminBroker,g as waitForAdminBroker};
|