@jonathanyee/devtunnel-ctl 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +328 -2
- package/dist/auth.d.ts +24 -0
- package/dist/auth.js +151 -0
- package/dist/auth.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +246 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +22 -0
- package/dist/config.js +94 -0
- package/dist/config.js.map +1 -0
- package/dist/core.d.ts +16 -0
- package/dist/core.js +114 -0
- package/dist/core.js.map +1 -0
- package/dist/daemon.d.ts +31 -0
- package/dist/daemon.js +153 -0
- package/dist/daemon.js.map +1 -0
- package/dist/forwarding.d.ts +15 -0
- package/dist/forwarding.js +87 -0
- package/dist/forwarding.js.map +1 -0
- package/dist/host-process.d.ts +4 -0
- package/dist/host-process.js +110 -0
- package/dist/host-process.js.map +1 -0
- package/dist/host-sdk.d.ts +38 -0
- package/dist/host-sdk.js +327 -0
- package/dist/host-sdk.js.map +1 -0
- package/dist/host-service.d.ts +21 -0
- package/dist/host-service.js +193 -0
- package/dist/host-service.js.map +1 -0
- package/dist/host-worker.d.ts +1 -0
- package/dist/host-worker.js +80 -0
- package/dist/host-worker.js.map +1 -0
- package/dist/host.d.ts +43 -0
- package/dist/host.js +158 -0
- package/dist/host.js.map +1 -0
- package/dist/launchd.d.ts +15 -0
- package/dist/launchd.js +135 -0
- package/dist/launchd.js.map +1 -0
- package/dist/lock.d.ts +10 -0
- package/dist/lock.js +110 -0
- package/dist/lock.js.map +1 -0
- package/dist/log.d.ts +26 -0
- package/dist/log.js +67 -0
- package/dist/log.js.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +5 -0
- package/dist/main.js.map +1 -0
- package/dist/paths.d.ts +4 -0
- package/dist/paths.js +39 -0
- package/dist/paths.js.map +1 -0
- package/dist/probe.d.ts +1 -0
- package/dist/probe.js +45 -0
- package/dist/probe.js.map +1 -0
- package/dist/recovery.d.ts +77 -0
- package/dist/recovery.js +265 -0
- package/dist/recovery.js.map +1 -0
- package/dist/rpc.d.ts +30 -0
- package/dist/rpc.js +208 -0
- package/dist/rpc.js.map +1 -0
- package/dist/sdk-transport.d.ts +33 -0
- package/dist/sdk-transport.js +239 -0
- package/dist/sdk-transport.js.map +1 -0
- package/npm-shrinkwrap.json +810 -0
- package/package.json +31 -4
package/dist/cli.js
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
import { Store, validateConfig } from "./config.js";
|
|
5
|
+
import { stateDir, executable } from "./paths.js";
|
|
6
|
+
import { bounded, Fault, record, safeFault } from "./core.js";
|
|
7
|
+
import { request } from "./rpc.js";
|
|
8
|
+
import { Daemon } from "./daemon.js";
|
|
9
|
+
import { DaemonLock } from "./lock.js";
|
|
10
|
+
import { service } from "./launchd.js";
|
|
11
|
+
import { validateHost } from "./host.js";
|
|
12
|
+
import { runHost } from "./host-process.js";
|
|
13
|
+
import { hostService, serveHost } from "./host-service.js";
|
|
14
|
+
export const help = `devtunnel-ctl - resilient Dev Tunnels hosting and SSH forwarding
|
|
15
|
+
|
|
16
|
+
init [--helper /absolute/path/devtunnel]
|
|
17
|
+
host TUNNEL[.CLUSTER] [--helper /absolute/path/devtunnel] [--cluster ID] [--probe-port PORT ...]
|
|
18
|
+
host-service install|start|stop|uninstall|status TUNNEL [--cluster ID]
|
|
19
|
+
install also accepts --helper and repeatable --probe-port (macOS only)
|
|
20
|
+
daemon Foreground service; Ctrl-C stops it
|
|
21
|
+
profile add NAME --tunnel ID[.CLUSTER] --local PORT [--remote 22] [--cluster ID] [--paused]
|
|
22
|
+
profile list | status [NAME] [--json]
|
|
23
|
+
pause NAME|all | resume NAME|all | reconnect NAME|all
|
|
24
|
+
logs [--follow] Recent sanitized logs from the running daemon
|
|
25
|
+
login [--device-code] [--github] Explicit devtunnel sign-in only
|
|
26
|
+
service install|start|stop|uninstall|status
|
|
27
|
+
|
|
28
|
+
Global: --state-dir /absolute/private/directory, --help
|
|
29
|
+
State defaults to ~/.devtunnel-ctl. Start a daemon before modifying profiles.
|
|
30
|
+
Reconnect never unpauses. Stable ports never shift. Fresh clients may break SSH sessions.
|
|
31
|
+
Host preserves all configured ports. Probes check only explicitly selected ports.
|
|
32
|
+
Starting a host may displace another host. Replacement disconnects active clients.
|
|
33
|
+
Windows supports foreground host only; pass --helper with an absolute devtunnel.exe path.
|
|
34
|
+
`;
|
|
35
|
+
function argumentsFor(args) {
|
|
36
|
+
try {
|
|
37
|
+
return parseArgs({ args, allowPositionals: true, strict: true, options: {
|
|
38
|
+
'state-dir': { type: 'string' }, helper: { type: 'string' }, tunnel: { type: 'string' },
|
|
39
|
+
local: { type: 'string' }, remote: { type: 'string' }, cluster: { type: 'string' },
|
|
40
|
+
'probe-port': { type: 'string', multiple: true },
|
|
41
|
+
paused: { type: 'boolean' }, json: { type: 'boolean' }, follow: { type: 'boolean' },
|
|
42
|
+
'device-code': { type: 'boolean' }, github: { type: 'boolean' }, help: { type: 'boolean', short: 'h' },
|
|
43
|
+
} });
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
throw new Fault('invalid-config', 'Invalid CLI arguments. Run devtunnel-ctl --help.');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
export async function cli(args, entry) {
|
|
50
|
+
const parsed = argumentsFor(args);
|
|
51
|
+
const { values: flags, positionals: words } = parsed;
|
|
52
|
+
if (flags.help || !words.length) {
|
|
53
|
+
console.log(help);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const [command, sub, name] = words;
|
|
57
|
+
const allowed = {
|
|
58
|
+
init: ['helper'], daemon: [], profile: sub === 'add' ? ['tunnel', 'local', 'remote', 'cluster', 'paused'] : ['json'],
|
|
59
|
+
status: ['json'], pause: [], resume: [], reconnect: [], logs: ['follow'], login: ['device-code', 'github'], service: [],
|
|
60
|
+
host: ['helper', 'cluster', 'probe-port'],
|
|
61
|
+
'host-service': sub === 'install' ? ['helper', 'cluster', 'probe-port'] : ['cluster'],
|
|
62
|
+
};
|
|
63
|
+
if (!command || !(command in allowed) || Object.keys(flags).some(k => k !== 'state-dir' && !allowed[command].includes(k))) {
|
|
64
|
+
throw new Fault('invalid-config', 'Unknown command or misplaced option. Run devtunnel-ctl --help.');
|
|
65
|
+
}
|
|
66
|
+
if (command === 'host' || command === 'host-service') {
|
|
67
|
+
const actions = ['install', 'start', 'stop', 'uninstall', 'status'];
|
|
68
|
+
const tunnelId = command === 'host' ? sub : name;
|
|
69
|
+
if (!tunnelId || words.length !== (command === 'host' ? 2 : 3) ||
|
|
70
|
+
(command === 'host-service' && !actions.includes(sub ?? '')))
|
|
71
|
+
throw new Fault('invalid-config', 'Use host TUNNEL or host-service ACTION TUNNEL.');
|
|
72
|
+
if (process.platform === 'win32' && (command !== 'host' || flags['state-dir'])) {
|
|
73
|
+
throw new Fault('invalid-config', 'Windows supports foreground host only, without --state-dir. Pass an absolute --helper path.');
|
|
74
|
+
}
|
|
75
|
+
const store = new Store(stateDir(flags['state-dir']));
|
|
76
|
+
const helperPath = flags.helper ?? (process.platform === 'win32' ? undefined : (await store.load()).helperPath);
|
|
77
|
+
if (!helperPath)
|
|
78
|
+
throw new Fault('invalid-config', 'Specify --helper with the absolute path to devtunnel.exe.');
|
|
79
|
+
const options = validateHost({ tunnelId, clusterId: flags.cluster, helperPath,
|
|
80
|
+
probePorts: (flags['probe-port'] ?? []).map(Number) });
|
|
81
|
+
if (command === 'host-service') {
|
|
82
|
+
console.log(JSON.stringify(await hostService(sub, options, store.dir, entry)));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
console.error('Hosting may displace another host. Recovery replacements can disconnect existing clients.');
|
|
86
|
+
if (process.platform === 'win32')
|
|
87
|
+
await runHost(options, message => console.log(JSON.stringify(message)));
|
|
88
|
+
else
|
|
89
|
+
await serveHost(options, store.dir);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (process.platform === 'win32')
|
|
93
|
+
throw new Fault('invalid-config', 'Windows supports foreground host only. Client daemon and service commands require macOS or Linux.');
|
|
94
|
+
const store = new Store(stateDir(flags['state-dir']));
|
|
95
|
+
await store.init();
|
|
96
|
+
const socket = join(store.dir, 'control.sock');
|
|
97
|
+
const print = (value) => console.log(JSON.stringify(value, null, flags.json ? 2 : undefined));
|
|
98
|
+
if (command === 'init') {
|
|
99
|
+
if (words.length !== 1)
|
|
100
|
+
throw new Fault('invalid-config', 'init accepts only --helper.');
|
|
101
|
+
const lock = new DaemonLock(store.dir);
|
|
102
|
+
await lock.acquire();
|
|
103
|
+
try {
|
|
104
|
+
const config = await store.load();
|
|
105
|
+
const helperPath = await executable(flags.helper ?? config.helperPath);
|
|
106
|
+
await store.save(validateConfig({ ...config, helperPath }));
|
|
107
|
+
print({ initialized: true, config: store.configPath, helper: helperPath });
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
await lock.release();
|
|
111
|
+
}
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (command === 'daemon') {
|
|
115
|
+
if (words.length !== 1)
|
|
116
|
+
throw new Fault('invalid-config', 'daemon accepts no positional arguments.');
|
|
117
|
+
let shutdown = () => { };
|
|
118
|
+
const daemon = new Daemon(store, { fatal: fault => { console.error(`${fault.code}: ${fault.message}`); process.exitCode = 1; shutdown(); } });
|
|
119
|
+
await daemon.start();
|
|
120
|
+
console.log('Daemon ready. Private control socket: ' + socket);
|
|
121
|
+
await new Promise((resolve, reject) => {
|
|
122
|
+
shutdown = () => {
|
|
123
|
+
process.off('SIGINT', shutdown);
|
|
124
|
+
process.off('SIGTERM', shutdown);
|
|
125
|
+
void daemon.stop().then(resolve, reject);
|
|
126
|
+
};
|
|
127
|
+
process.once('SIGINT', shutdown);
|
|
128
|
+
process.once('SIGTERM', shutdown);
|
|
129
|
+
});
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (command === 'login') {
|
|
133
|
+
if (words.length !== 1)
|
|
134
|
+
throw new Fault('invalid-config', 'login accepts only --device-code and --github.');
|
|
135
|
+
const config = await store.load();
|
|
136
|
+
await bounded(signal => new Promise((resolve, reject) => {
|
|
137
|
+
const child = spawn(config.helperPath, ['user', 'login', ...(flags['device-code'] ? ['-d'] : []),
|
|
138
|
+
...(flags.github ? ['-g'] : [])], { stdio: 'inherit', shell: false });
|
|
139
|
+
const abort = () => child.kill('SIGKILL');
|
|
140
|
+
signal.addEventListener('abort', abort, { once: true });
|
|
141
|
+
child.on('error', () => { signal.removeEventListener('abort', abort); reject(new Fault('invalid-config', 'Cannot execute configured login helper.')); });
|
|
142
|
+
child.on('close', code => {
|
|
143
|
+
signal.removeEventListener('abort', abort);
|
|
144
|
+
if (code === 0)
|
|
145
|
+
resolve();
|
|
146
|
+
else
|
|
147
|
+
reject(new Fault('login-required'));
|
|
148
|
+
});
|
|
149
|
+
}), 300000);
|
|
150
|
+
console.log('Sign-in completed. Run devtunnel-ctl reconnect all to retry blocked profiles.');
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (command === 'service') {
|
|
154
|
+
if (words.length !== 2 || !sub || !['install', 'start', 'stop', 'uninstall', 'status'].includes(sub)) {
|
|
155
|
+
throw new Fault('invalid-config', 'Use service install, start, stop, uninstall or status.');
|
|
156
|
+
}
|
|
157
|
+
print(await service(sub, store, entry));
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (command === 'profile' && sub === 'add') {
|
|
161
|
+
if (words.length !== 3 || !name || !flags.tunnel || !flags.local) {
|
|
162
|
+
throw new Fault('invalid-config', 'Use profile add NAME --tunnel ID --local PORT [--remote 22] [--cluster ID] [--paused].');
|
|
163
|
+
}
|
|
164
|
+
const config = validateConfig({ version: 1, helperPath: '/unused', profiles: [{
|
|
165
|
+
name, tunnelId: flags.tunnel, clusterId: flags.cluster, localPort: Number(flags.local),
|
|
166
|
+
remotePort: Number(flags.remote ?? 22), paused: flags.paused ?? false,
|
|
167
|
+
}] });
|
|
168
|
+
print(await request(socket, { v: 1, command: 'add', profile: config.profiles[0] }));
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
if (command === 'status' || (command === 'profile' && sub === 'list')) {
|
|
172
|
+
if ((command === 'status' && words.length > 2) || (command === 'profile' && words.length !== 2)) {
|
|
173
|
+
throw new Fault('invalid-config', 'Use status [NAME] or profile list.');
|
|
174
|
+
}
|
|
175
|
+
const response = await request(socket, { v: 1, command: 'status' });
|
|
176
|
+
if (!record(response) || !Array.isArray(response.profiles))
|
|
177
|
+
throw new Fault('protocol');
|
|
178
|
+
const profiles = response.profiles.filter(p => record(p) && (command !== 'status' || !sub || p.name === sub));
|
|
179
|
+
if (sub && command === 'status' && !profiles.length)
|
|
180
|
+
throw new Fault('invalid-config', 'No matching profile.');
|
|
181
|
+
if (flags.json)
|
|
182
|
+
print({ ...response, profiles });
|
|
183
|
+
else {
|
|
184
|
+
console.log('NAME LOCAL REMOTE STATE RELAY LAST SSH CHECK / NEXT RETRY');
|
|
185
|
+
for (const p of profiles) {
|
|
186
|
+
if (!record(p))
|
|
187
|
+
throw new Fault('protocol');
|
|
188
|
+
const success = typeof p.lastHealthyAt === 'number' ? new Date(p.lastHealthyAt).toISOString() : 'never';
|
|
189
|
+
const retry = typeof p.nextRetryAt === 'number' ? new Date(p.nextRetryAt).toISOString() : '-';
|
|
190
|
+
console.log(`${String(p.name).padEnd(16)} ${String(p.localPort).padEnd(7)} ${String(p.remotePort).padEnd(7)} ${String(p.state).padEnd(21)} ${p.relayConnected ? 'yes' : 'no '} ${success} / ${retry}`);
|
|
191
|
+
if (record(p.cause) && typeof p.cause.message === 'string')
|
|
192
|
+
console.log(' ' + p.cause.message);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (command === 'pause' || command === 'resume' || command === 'reconnect') {
|
|
198
|
+
if (words.length !== 2 || !sub)
|
|
199
|
+
throw new Fault('invalid-config', `${command} requires NAME or all.`);
|
|
200
|
+
print(await request(socket, { v: 1, command, name: sub }));
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (command === 'logs') {
|
|
204
|
+
if (words.length !== 1)
|
|
205
|
+
throw new Fault('invalid-config', 'Use logs [--follow].');
|
|
206
|
+
let instance = '', sequence = 0, stopped = false;
|
|
207
|
+
const stop = () => { stopped = true; };
|
|
208
|
+
if (flags.follow) {
|
|
209
|
+
process.once('SIGINT', stop);
|
|
210
|
+
process.once('SIGTERM', stop);
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
do {
|
|
214
|
+
const result = await request(socket, { v: 1, command: 'logs' });
|
|
215
|
+
if (!record(result) || typeof result.instance !== 'string' || !Array.isArray(result.entries))
|
|
216
|
+
throw new Fault('protocol');
|
|
217
|
+
if (result.instance !== instance) {
|
|
218
|
+
instance = result.instance;
|
|
219
|
+
sequence = 0;
|
|
220
|
+
}
|
|
221
|
+
for (const value of result.entries) {
|
|
222
|
+
if (!record(value) || typeof value.sequence !== 'number' || typeof value.line !== 'string')
|
|
223
|
+
throw new Fault('protocol');
|
|
224
|
+
if (value.sequence > sequence) {
|
|
225
|
+
console.log(value.line);
|
|
226
|
+
sequence = value.sequence;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
if (flags.follow && !stopped)
|
|
230
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
231
|
+
} while (flags.follow && !stopped);
|
|
232
|
+
}
|
|
233
|
+
finally {
|
|
234
|
+
process.off('SIGINT', stop);
|
|
235
|
+
process.off('SIGTERM', stop);
|
|
236
|
+
}
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
throw new Fault('invalid-config', 'Unknown command. Run devtunnel-ctl --help.');
|
|
240
|
+
}
|
|
241
|
+
export function report(error) {
|
|
242
|
+
const fault = safeFault(error);
|
|
243
|
+
console.error(`${fault.code}: ${fault.message}`);
|
|
244
|
+
process.exitCode = 1;
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface Profile {
|
|
2
|
+
name: string;
|
|
3
|
+
tunnelId: string;
|
|
4
|
+
clusterId?: string;
|
|
5
|
+
remotePort: number;
|
|
6
|
+
localPort: number;
|
|
7
|
+
paused: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface Config {
|
|
10
|
+
version: 1;
|
|
11
|
+
helperPath: string;
|
|
12
|
+
profiles: Profile[];
|
|
13
|
+
}
|
|
14
|
+
export declare function validateConfig(value: unknown): Config;
|
|
15
|
+
export declare class Store {
|
|
16
|
+
readonly dir: string;
|
|
17
|
+
readonly configPath: string;
|
|
18
|
+
constructor(dir: string);
|
|
19
|
+
init(): Promise<void>;
|
|
20
|
+
load(): Promise<Config>;
|
|
21
|
+
save(value: Config): Promise<void>;
|
|
22
|
+
}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { open, rename, lstat, unlink } from 'node:fs/promises';
|
|
2
|
+
import { join, isAbsolute } from 'node:path';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import { constants } from 'node:fs';
|
|
5
|
+
import { Fault, record } from "./core.js";
|
|
6
|
+
import { privateDir, privatePath } from "./paths.js";
|
|
7
|
+
function invalid(detail) { throw new Fault('invalid-config', detail); }
|
|
8
|
+
const port = (v) => Number.isInteger(v) && Number(v) >= 1 && Number(v) <= 65535;
|
|
9
|
+
const idPattern = /^[a-z0-9][a-z0-9-]{0,62}$/i;
|
|
10
|
+
export function validateConfig(value) {
|
|
11
|
+
if (!record(value) || value.version !== 1 || typeof value.helperPath !== 'string' ||
|
|
12
|
+
!isAbsolute(value.helperPath) || /[\0\r\n]/.test(value.helperPath) ||
|
|
13
|
+
!Array.isArray(value.profiles) || value.profiles.length > 64)
|
|
14
|
+
invalid('Invalid configuration schema.');
|
|
15
|
+
const names = new Set(), ports = new Set();
|
|
16
|
+
const profiles = value.profiles.map((p) => {
|
|
17
|
+
if (!record(p) || typeof p.name !== 'string' || !/^[a-z][a-z0-9-]{0,31}$/.test(p.name) ||
|
|
18
|
+
typeof p.tunnelId !== 'string' || !port(p.localPort) || !port(p.remotePort) ||
|
|
19
|
+
typeof p.paused !== 'boolean')
|
|
20
|
+
invalid('Invalid SSH profile.');
|
|
21
|
+
const [tunnelId, suffix, extra] = p.tunnelId.split('.');
|
|
22
|
+
const cluster = p.clusterId ?? suffix;
|
|
23
|
+
if (!tunnelId || !idPattern.test(tunnelId) || extra !== undefined ||
|
|
24
|
+
(cluster !== undefined && (typeof cluster !== 'string' || !idPattern.test(cluster))) ||
|
|
25
|
+
(suffix !== undefined && p.clusterId !== undefined && suffix !== p.clusterId))
|
|
26
|
+
invalid('Invalid tunnel or cluster ID.');
|
|
27
|
+
if (names.has(p.name) || ports.has(p.localPort))
|
|
28
|
+
invalid('Profile names and local ports must be unique.');
|
|
29
|
+
names.add(p.name);
|
|
30
|
+
ports.add(p.localPort);
|
|
31
|
+
return { name: p.name, tunnelId, ...(cluster ? { clusterId: String(cluster) } : {}),
|
|
32
|
+
localPort: p.localPort, remotePort: p.remotePort, paused: p.paused };
|
|
33
|
+
});
|
|
34
|
+
return { version: 1, helperPath: value.helperPath, profiles };
|
|
35
|
+
}
|
|
36
|
+
export class Store {
|
|
37
|
+
dir;
|
|
38
|
+
configPath;
|
|
39
|
+
constructor(dir) { this.dir = dir; this.configPath = join(dir, 'config.json'); }
|
|
40
|
+
async init() { await privateDir(this.dir); }
|
|
41
|
+
async load() {
|
|
42
|
+
try {
|
|
43
|
+
await privatePath(this.configPath);
|
|
44
|
+
const handle = await open(this.configPath, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
45
|
+
try {
|
|
46
|
+
if ((await handle.stat()).size > 65536)
|
|
47
|
+
invalid('Configuration exceeds 64 KiB.');
|
|
48
|
+
return validateConfig(JSON.parse(await handle.readFile('utf8')));
|
|
49
|
+
}
|
|
50
|
+
finally {
|
|
51
|
+
await handle.close();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
|
|
56
|
+
return { version: 1, helperPath: '/opt/homebrew/bin/devtunnel', profiles: [] };
|
|
57
|
+
}
|
|
58
|
+
throw error instanceof Fault ? error : new Fault('invalid-config', 'Cannot read private configuration.');
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async save(value) {
|
|
62
|
+
const config = validateConfig(value);
|
|
63
|
+
await this.init();
|
|
64
|
+
try {
|
|
65
|
+
await lstat(this.configPath);
|
|
66
|
+
await privatePath(this.configPath);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
if (!(error instanceof Error && 'code' in error && error.code === 'ENOENT'))
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
const temp = `${this.configPath}.${randomUUID()}.tmp`;
|
|
73
|
+
const handle = await open(temp, 'wx', 0o600);
|
|
74
|
+
try {
|
|
75
|
+
await handle.writeFile(JSON.stringify(config, null, 2) + '\n');
|
|
76
|
+
await handle.sync();
|
|
77
|
+
await handle.close();
|
|
78
|
+
await rename(temp, this.configPath);
|
|
79
|
+
const dir = await open(this.dir, 'r');
|
|
80
|
+
try {
|
|
81
|
+
await dir.sync();
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
await dir.close();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
await handle.close().catch(() => { });
|
|
89
|
+
await unlink(temp).catch(() => { });
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/core.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type FaultCode = 'login-required' | 'access-denied' | 'port-conflict' | 'remote-unavailable' | 'retrying' | 'throttled' | 'timeout' | 'aborted' | 'invalid-config' | 'protocol' | 'daemon-unavailable' | 'internal' | 'host-superseded' | 'host-cleanup-failed';
|
|
2
|
+
export declare class Fault extends Error {
|
|
3
|
+
readonly code: FaultCode;
|
|
4
|
+
readonly retryAfterMs: number;
|
|
5
|
+
constructor(code: FaultCode, message?: string, retryAfterMs?: number);
|
|
6
|
+
}
|
|
7
|
+
export declare function isFaultCode(value: unknown): value is FaultCode;
|
|
8
|
+
export declare function record(value: unknown): value is Record<string, unknown>;
|
|
9
|
+
export declare function safeFault(error: unknown): Fault;
|
|
10
|
+
export declare function redact(text: string): string;
|
|
11
|
+
export interface Clock {
|
|
12
|
+
now(): number;
|
|
13
|
+
later(ms: number, callback: () => void): () => void;
|
|
14
|
+
}
|
|
15
|
+
export declare const clock: Clock;
|
|
16
|
+
export declare function bounded<T>(action: (signal: AbortSignal) => Promise<T>, ms: number, parent?: AbortSignal, late?: (value: T) => void | Promise<void>, timer?: Clock): Promise<T>;
|
package/dist/core.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
const messages = {
|
|
2
|
+
'login-required': 'Sign-in required. Run devtunnel-ctl login, then reconnect.',
|
|
3
|
+
'access-denied': 'Tunnel access denied. Check the account and tunnel permissions.',
|
|
4
|
+
'port-conflict': 'A configured loopback port is occupied. Release it explicitly or change the profile.',
|
|
5
|
+
'remote-unavailable': 'SSH host or remote forwarding path unavailable; network location is uncertain.',
|
|
6
|
+
retrying: 'Connection unavailable; recovery will retry.',
|
|
7
|
+
throttled: 'The service is throttling requests; waiting before retry.',
|
|
8
|
+
timeout: 'Operation exceeded its deadline.',
|
|
9
|
+
aborted: 'Operation cancelled.',
|
|
10
|
+
'invalid-config': 'Invalid configuration.',
|
|
11
|
+
protocol: 'Invalid or oversized control message.',
|
|
12
|
+
'daemon-unavailable': 'Daemon unavailable. Run devtunnel-ctl daemon or start the installed service.',
|
|
13
|
+
internal: 'Operation failed. Check configuration and sanitized service logs.',
|
|
14
|
+
'host-superseded': 'Another host took over this tunnel. Automatic hosting stopped to avoid reconnect contention.',
|
|
15
|
+
'host-cleanup-failed': 'Owned host endpoint cleanup failed. Automatic hosting stopped; inspect this tunnel before starting another host.',
|
|
16
|
+
};
|
|
17
|
+
export class Fault extends Error {
|
|
18
|
+
code;
|
|
19
|
+
retryAfterMs;
|
|
20
|
+
constructor(code, message = messages[code], retryAfterMs = 0) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.name = 'Fault';
|
|
23
|
+
this.code = code;
|
|
24
|
+
this.retryAfterMs = retryAfterMs;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function isFaultCode(value) {
|
|
28
|
+
return typeof value === 'string' && Object.hasOwn(messages, value);
|
|
29
|
+
}
|
|
30
|
+
export function record(value) {
|
|
31
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
32
|
+
}
|
|
33
|
+
export function safeFault(error) {
|
|
34
|
+
if (error instanceof Fault)
|
|
35
|
+
return error;
|
|
36
|
+
const obj = record(error) ? error : {};
|
|
37
|
+
const response = record(obj.response) ? obj.response : {};
|
|
38
|
+
const context = record(obj.errorContext) ? obj.errorContext : {};
|
|
39
|
+
const status = response.status ?? obj.statusCode ?? obj.status ?? context.statusCode;
|
|
40
|
+
if (status === 401)
|
|
41
|
+
return new Fault('login-required');
|
|
42
|
+
if (status === 403)
|
|
43
|
+
return new Fault('access-denied');
|
|
44
|
+
if (status === 429 || status === 503) {
|
|
45
|
+
const headers = record(response.headers) ? response.headers : {};
|
|
46
|
+
const retry = headers['retry-after'];
|
|
47
|
+
const seconds = typeof retry === 'string' ? Number(retry) : NaN;
|
|
48
|
+
const ms = Number.isFinite(seconds) ? seconds * 1000 :
|
|
49
|
+
typeof retry === 'string' ? Date.parse(retry) - Date.now() : 0;
|
|
50
|
+
return new Fault('throttled', messages.throttled, Math.max(0, Math.min(ms || 0, 86400000)));
|
|
51
|
+
}
|
|
52
|
+
if (obj.code === 'EADDRINUSE')
|
|
53
|
+
return new Fault('port-conflict');
|
|
54
|
+
if (status === 404 || obj.code === 'ECONNREFUSED')
|
|
55
|
+
return new Fault('remote-unavailable');
|
|
56
|
+
if (error instanceof Error && [
|
|
57
|
+
'No hosts are currently accepting connections for the tunnel.',
|
|
58
|
+
'The specified host is not currently accepting connections to the tunnel.',
|
|
59
|
+
'The host is not currently accepting Tunnel relay connections.',
|
|
60
|
+
].includes(error.message))
|
|
61
|
+
return new Fault('remote-unavailable');
|
|
62
|
+
return new Fault('retrying');
|
|
63
|
+
}
|
|
64
|
+
export function redact(text) {
|
|
65
|
+
return text
|
|
66
|
+
.replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g, '[redacted]')
|
|
67
|
+
.replace(/\b(Bearer|Tunnel)\s+[^\s",;]+/gi, '$1 [redacted]')
|
|
68
|
+
.replace(/((?:["']?(?:access[_-]?token|token|authorization)["']?)\s*[:=]\s*["']?)[^"'\s,;}]+/gi, '$1[redacted]')
|
|
69
|
+
.slice(0, 1024);
|
|
70
|
+
}
|
|
71
|
+
export const clock = {
|
|
72
|
+
now: () => Date.now(),
|
|
73
|
+
later: (ms, callback) => { const timer = setTimeout(callback, ms); return () => clearTimeout(timer); },
|
|
74
|
+
};
|
|
75
|
+
export function bounded(action, ms, parent, late, timer = clock) {
|
|
76
|
+
const controller = new AbortController();
|
|
77
|
+
return new Promise((resolve, reject) => {
|
|
78
|
+
let settled = false;
|
|
79
|
+
let cancelTimer = () => { };
|
|
80
|
+
const finish = (error, value) => {
|
|
81
|
+
if (settled)
|
|
82
|
+
return;
|
|
83
|
+
settled = true;
|
|
84
|
+
cancelTimer();
|
|
85
|
+
parent?.removeEventListener('abort', aborted);
|
|
86
|
+
if (error !== undefined) {
|
|
87
|
+
controller.abort();
|
|
88
|
+
reject(error);
|
|
89
|
+
}
|
|
90
|
+
else
|
|
91
|
+
resolve(value);
|
|
92
|
+
};
|
|
93
|
+
const aborted = () => finish(new Fault('aborted'));
|
|
94
|
+
if (parent?.aborted) {
|
|
95
|
+
aborted();
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
parent?.addEventListener('abort', aborted, { once: true });
|
|
99
|
+
cancelTimer = timer.later(ms, () => finish(new Fault('timeout')));
|
|
100
|
+
Promise.resolve().then(() => {
|
|
101
|
+
if (controller.signal.aborted)
|
|
102
|
+
throw new Fault('aborted');
|
|
103
|
+
return action(controller.signal);
|
|
104
|
+
}).then(value => {
|
|
105
|
+
if (settled) {
|
|
106
|
+
if (late)
|
|
107
|
+
void Promise.resolve().then(() => late(value)).catch(() => process.emitWarning('Cancelled-operation resource cleanup failed.', { code: 'DTC_CLEANUP' }));
|
|
108
|
+
}
|
|
109
|
+
else
|
|
110
|
+
finish(undefined, value);
|
|
111
|
+
}, error => finish(error));
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=core.js.map
|
package/dist/core.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.js","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"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"}
|
package/dist/daemon.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Store } from './config.ts';
|
|
2
|
+
import { TokenProvider } from './auth.ts';
|
|
3
|
+
import type { Transport } from './sdk-transport.ts';
|
|
4
|
+
import { Fault } from './core.ts';
|
|
5
|
+
export interface DaemonOptions {
|
|
6
|
+
transport?: (tokens: TokenProvider) => Transport;
|
|
7
|
+
fatal?: (fault: Fault) => void;
|
|
8
|
+
}
|
|
9
|
+
export declare class Daemon {
|
|
10
|
+
private readonly store;
|
|
11
|
+
private readonly options;
|
|
12
|
+
private readonly log;
|
|
13
|
+
private readonly lock;
|
|
14
|
+
private readonly instance;
|
|
15
|
+
private config;
|
|
16
|
+
private tokens;
|
|
17
|
+
private transport;
|
|
18
|
+
private rpc;
|
|
19
|
+
private readonly controllers;
|
|
20
|
+
private mutations;
|
|
21
|
+
private queued;
|
|
22
|
+
private stopping;
|
|
23
|
+
private stopPromise;
|
|
24
|
+
constructor(store: Store, options?: DaemonOptions);
|
|
25
|
+
start(): Promise<void>;
|
|
26
|
+
private writeLog;
|
|
27
|
+
private create;
|
|
28
|
+
private logStatus;
|
|
29
|
+
private handle;
|
|
30
|
+
stop(): Promise<void>;
|
|
31
|
+
}
|