mindwire 0.1.33 → 0.1.34
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/{chunk-H2I3VRBS.js → chunk-3QFDSYKC.js} +11 -10
- package/dist/chunk-3QFDSYKC.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/computer/lifecycle.d.ts +3 -0
- package/dist/computer/relay-health.d.ts +21 -5
- package/dist/{controller-QBC6L7AT.js → controller-AGT6MCJG.js} +88 -15
- package/dist/controller-AGT6MCJG.js.map +1 -0
- package/dist/{controller-handoff-NFDOLPJL.js → controller-handoff-3LAYBJUL.js} +3 -3
- package/dist/{controller-handoff-NFDOLPJL.js.map → controller-handoff-3LAYBJUL.js.map} +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-H2I3VRBS.js.map +0 -1
- package/dist/controller-QBC6L7AT.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { defaultStateDirectory, superviseComputer, ensureComputer, computerPairingURI, stopComputer, computerClient, SDK_VERSION, readJSON, writeJSON, currentProcessIdentity, processStateAlive, acquireProcessLock, computerPairingQRData } from './chunk-
|
|
2
|
+
import { defaultStateDirectory, superviseComputer, ensureComputer, computerPairingURI, stopComputer, computerClient, SDK_VERSION, readJSON, writeJSON, currentProcessIdentity, processStateAlive, acquireProcessLock, computerPairingQRData } from './chunk-3QFDSYKC.js';
|
|
3
3
|
import './chunk-T6TD76UA.js';
|
|
4
4
|
import { promisify, parseArgs } from 'util';
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
@@ -23,6 +23,8 @@ export interface ControllerState extends ProcessState {
|
|
|
23
23
|
recovering?: boolean;
|
|
24
24
|
routes?: ComputerRoute[];
|
|
25
25
|
checkedAt?: number;
|
|
26
|
+
relayFailureSince?: number;
|
|
27
|
+
relayFailures?: number;
|
|
26
28
|
}
|
|
27
29
|
export declare const defaultStateDirectory: () => string;
|
|
28
30
|
export declare const defaultComputerConfig: () => ComputerConfig;
|
|
@@ -34,6 +36,7 @@ export declare function directRoutes(config: ComputerConfig, port: number): Comp
|
|
|
34
36
|
export declare function ensureComputer(directory: string, cliPath: string, patch?: Partial<ComputerConfig>, onProgress?: (message: string) => void, options?: {
|
|
35
37
|
resume?: boolean;
|
|
36
38
|
signal?: AbortSignal;
|
|
39
|
+
timeoutMs?: number;
|
|
37
40
|
}): Promise<Mindwire>;
|
|
38
41
|
export declare function superviseComputer(directory: string): Promise<void>;
|
|
39
42
|
export declare function stopComputer(directory: string, force?: boolean): Promise<void>;
|
|
@@ -1,14 +1,29 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type LookupFunction } from "node:net";
|
|
2
2
|
import type { ComputerRoute } from "../computer.js";
|
|
3
3
|
import type { RelayOptions } from "./relay.js";
|
|
4
4
|
export declare class RelayCheckError extends Error {
|
|
5
5
|
readonly code: "dns" | "timeout" | "proxy" | "connection" | "response";
|
|
6
|
-
|
|
6
|
+
readonly addressMissing: boolean;
|
|
7
|
+
constructor(code: "dns" | "timeout" | "proxy" | "connection" | "response", message: string, cause?: Error, addressMissing?: boolean);
|
|
7
8
|
}
|
|
8
|
-
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
/** Local NXDOMAIN can be a stale cache. A missing address confirmed by the
|
|
10
|
+
* provider is different: its helper may stay alive after the quick tunnel expires.
|
|
11
|
+
* Keep a grace period for newly allocated records and ordinary internet outages. */
|
|
11
12
|
export declare function relayNeedsRestart(error: unknown, failures: number, failedForMs: number): boolean;
|
|
13
|
+
type RelayDNSResult = {
|
|
14
|
+
addresses: {
|
|
15
|
+
address: string;
|
|
16
|
+
family: number;
|
|
17
|
+
}[];
|
|
18
|
+
missing: boolean;
|
|
19
|
+
};
|
|
20
|
+
/** Use the tunnel provider's HTTPS resolver only after local DNS fails. This
|
|
21
|
+
* bypasses router negative caches without another service or a persisted IP.
|
|
22
|
+
* A DNS answer never replaces TLS hostname validation or the phone's SSH pin. */
|
|
23
|
+
export declare function resolveCloudflareAddress(hostname: string, family?: number, options?: {
|
|
24
|
+
fetch?: typeof fetch;
|
|
25
|
+
timeoutMs?: number;
|
|
26
|
+
}): Promise<RelayDNSResult>;
|
|
12
27
|
/** Check the actual WebSocket byte path, not just the helper's PID or its logs.
|
|
13
28
|
* The phone still authenticates and pins the SSH host before sending secrets. */
|
|
14
29
|
export declare function checkRelay(route: ComputerRoute, options?: {
|
|
@@ -19,3 +34,4 @@ export declare function checkRelay(route: ComputerRoute, options?: {
|
|
|
19
34
|
/** Don't rotate a quick-tunnel address during an ordinary internet outage.
|
|
20
35
|
* Let the provider reconnect with the same address until it is reachable again. */
|
|
21
36
|
export declare function relayProviderReachable(options: RelayOptions, signal?: AbortSignal): Promise<boolean>;
|
|
37
|
+
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { binaryCacheDirectory, cachedExecutable, verifyReleaseBytes, cacheExecutable, executableChecksum } from './chunk-3FR7BFAW.js';
|
|
2
|
-
import { readJSON, processStateAlive, currentProcessIdentity, ensureDaemonBinary, SDK_VERSION, computerClient, processIdentity, adoptProcess, writeJSON, directRoutes, CONTROLLER_PROTOCOL, ownChild } from './chunk-
|
|
2
|
+
import { readJSON, processStateAlive, currentProcessIdentity, ensureDaemonBinary, SDK_VERSION, computerClient, processIdentity, adoptProcess, writeJSON, directRoutes, CONTROLLER_PROTOCOL, ownChild } from './chunk-3QFDSYKC.js';
|
|
3
3
|
import './chunk-T6TD76UA.js';
|
|
4
4
|
import { execFile, execFileSync, spawn } from 'child_process';
|
|
5
5
|
import { randomBytes, randomUUID } from 'crypto';
|
|
@@ -12,6 +12,7 @@ import { promisify } from 'util';
|
|
|
12
12
|
import { request } from 'https';
|
|
13
13
|
import { lookup } from 'dns';
|
|
14
14
|
import { Resolver } from 'dns/promises';
|
|
15
|
+
import { isIP } from 'net';
|
|
15
16
|
import WebSocket from 'ws';
|
|
16
17
|
|
|
17
18
|
var CLOUDFLARED_VERSION = "2026.9.3";
|
|
@@ -242,31 +243,90 @@ async function startRelay(options, port, runtime = {}) {
|
|
|
242
243
|
}
|
|
243
244
|
}
|
|
244
245
|
var RelayCheckError = class extends Error {
|
|
245
|
-
constructor(code, message, cause) {
|
|
246
|
+
constructor(code, message, cause, addressMissing = false) {
|
|
246
247
|
super(message, cause ? { cause } : void 0);
|
|
247
248
|
this.code = code;
|
|
249
|
+
this.addressMissing = addressMissing;
|
|
248
250
|
this.name = "RelayCheckError";
|
|
249
251
|
}
|
|
250
252
|
code;
|
|
253
|
+
addressMissing;
|
|
251
254
|
};
|
|
252
255
|
function relayNeedsRestart(error, failures, failedForMs) {
|
|
253
|
-
return failures >= 2 && failedForMs >= 9e4 && !(error instanceof RelayCheckError && error.code === "dns");
|
|
256
|
+
return failures >= 2 && failedForMs >= 9e4 && (!(error instanceof RelayCheckError && error.code === "dns") || error.addressMissing);
|
|
257
|
+
}
|
|
258
|
+
var quickTunnelHost = /^[a-z0-9-]+\.trycloudflare\.com$/i;
|
|
259
|
+
async function resolveCloudflareAddress(hostname, family = 0, options = {}) {
|
|
260
|
+
if (!quickTunnelHost.test(hostname)) return { addresses: [], missing: false };
|
|
261
|
+
const abort = new AbortController();
|
|
262
|
+
const timer = setTimeout(() => abort.abort(), options.timeoutMs ?? 3e3);
|
|
263
|
+
try {
|
|
264
|
+
const types = family === 4 ? [1] : family === 6 ? [28] : [1, 28];
|
|
265
|
+
const results = await Promise.all(types.map(async (type) => {
|
|
266
|
+
try {
|
|
267
|
+
const response = await (options.fetch ?? fetch)(
|
|
268
|
+
`https://cloudflare-dns.com/dns-query?name=${encodeURIComponent(hostname)}&type=${type}`,
|
|
269
|
+
{ headers: { accept: "application/dns-json" }, redirect: "error", signal: abort.signal }
|
|
270
|
+
);
|
|
271
|
+
if (response.status !== 200 || !response.body) {
|
|
272
|
+
await response.body?.cancel();
|
|
273
|
+
return void 0;
|
|
274
|
+
}
|
|
275
|
+
const reader = response.body.getReader();
|
|
276
|
+
let text = "", size = 0;
|
|
277
|
+
const decoder = new TextDecoder();
|
|
278
|
+
try {
|
|
279
|
+
for (; ; ) {
|
|
280
|
+
const chunk = await reader.read();
|
|
281
|
+
if (chunk.done) break;
|
|
282
|
+
size += chunk.value.length;
|
|
283
|
+
if (size > 16384) return void 0;
|
|
284
|
+
text += decoder.decode(chunk.value, { stream: true });
|
|
285
|
+
}
|
|
286
|
+
} finally {
|
|
287
|
+
await reader.cancel();
|
|
288
|
+
}
|
|
289
|
+
const result = JSON.parse(text + decoder.decode());
|
|
290
|
+
if (!Array.isArray(result.Question) || !result.Question.some((question) => question.name?.replace(/\.$/, "").toLowerCase() === hostname.toLowerCase() && question.type === type)) return void 0;
|
|
291
|
+
if (result.Status === 3) return { addresses: [], missing: true };
|
|
292
|
+
if (result.Status !== 0) return void 0;
|
|
293
|
+
const addresses = (Array.isArray(result.Answer) ? result.Answer : []).flatMap((answer) => {
|
|
294
|
+
const family2 = answer.type === 1 ? 4 : answer.type === 28 ? 6 : 0;
|
|
295
|
+
return family2 && answer.type === type && typeof answer.data === "string" && isIP(answer.data) === family2 ? [{ address: answer.data, family: family2 }] : [];
|
|
296
|
+
});
|
|
297
|
+
return { addresses, missing: false };
|
|
298
|
+
} catch {
|
|
299
|
+
return void 0;
|
|
300
|
+
}
|
|
301
|
+
}));
|
|
302
|
+
return {
|
|
303
|
+
addresses: results.flatMap((result) => result?.addresses ?? []),
|
|
304
|
+
missing: results.every((result) => result?.missing === true)
|
|
305
|
+
};
|
|
306
|
+
} finally {
|
|
307
|
+
clearTimeout(timer);
|
|
308
|
+
}
|
|
254
309
|
}
|
|
255
310
|
var relayLookup = (hostname, options, callback) => {
|
|
256
311
|
lookup(hostname, options, (error, address, family) => {
|
|
257
|
-
if (error?.code
|
|
312
|
+
if (!["ENOTFOUND", "EAI_AGAIN"].includes(error?.code ?? "") || !quickTunnelHost.test(hostname)) {
|
|
258
313
|
callback(error, address, family);
|
|
259
314
|
return;
|
|
260
315
|
}
|
|
261
316
|
const resolver = new Resolver({ timeout: 3e3, tries: 1 });
|
|
317
|
+
const requestedFamily = options.family === "IPv4" ? 4 : options.family === "IPv6" ? 6 : options.family ?? 0;
|
|
262
318
|
void Promise.all([
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
]).then((results) => {
|
|
266
|
-
|
|
319
|
+
requestedFamily === 6 ? [] : resolver.resolve4(hostname).then((addresses) => addresses.map((address2) => ({ address: address2, family: 4 })), () => []),
|
|
320
|
+
requestedFamily === 4 ? [] : resolver.resolve6(hostname).then((addresses) => addresses.map((address2) => ({ address: address2, family: 6 })), () => [])
|
|
321
|
+
]).then(async (results) => {
|
|
322
|
+
let addresses = results.flat();
|
|
267
323
|
if (!addresses.length) {
|
|
268
|
-
|
|
269
|
-
|
|
324
|
+
const provider = await resolveCloudflareAddress(hostname, requestedFamily);
|
|
325
|
+
addresses = provider.addresses;
|
|
326
|
+
if (!addresses.length) {
|
|
327
|
+
callback(Object.assign(error, { relayAddressMissing: provider.missing }), address, family);
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
270
330
|
}
|
|
271
331
|
if (options.all) callback(null, addresses);
|
|
272
332
|
else callback(null, addresses[0].address, addresses[0].family);
|
|
@@ -293,7 +353,12 @@ async function checkRelay(route, options = {}) {
|
|
|
293
353
|
socket.on("error", (error) => {
|
|
294
354
|
if (["ENOTFOUND", "EAI_AGAIN"].includes(error.code ?? "")) {
|
|
295
355
|
const provider = new URL(route.url).hostname.endsWith(".trycloudflare.com") ? "Cloudflare's" : "the tunnel's";
|
|
296
|
-
finish(new RelayCheckError(
|
|
356
|
+
finish(new RelayCheckError(
|
|
357
|
+
"dns",
|
|
358
|
+
`Waiting for ${provider} internet address (DNS)\u2026`,
|
|
359
|
+
error,
|
|
360
|
+
error.relayAddressMissing === true
|
|
361
|
+
));
|
|
297
362
|
} else if (/(?:[Uu]nexpected server response|[Ee]xpected 101)/.test(error.message)) {
|
|
298
363
|
finish(new RelayCheckError("proxy", "The internet tunnel isn't reaching Mindwire. Retrying\u2026", error));
|
|
299
364
|
} else {
|
|
@@ -474,6 +539,11 @@ async function superviseComputer(directory) {
|
|
|
474
539
|
if (owner2) {
|
|
475
540
|
if (saved.outputFile && saved.route && saved.port === websocketPort && saved.options === JSON.stringify(config.relay)) {
|
|
476
541
|
relay = await adoptRelay(owner2, saved.route, directory, saved.outputFile);
|
|
542
|
+
relayWasReachable = !!previous?.routes?.some((route) => JSON.stringify(route) === JSON.stringify(saved.route));
|
|
543
|
+
if (previous?.relayFailureSince && relayWasReachable) {
|
|
544
|
+
relayFailedAt = Math.min(Date.now(), previous.relayFailureSince);
|
|
545
|
+
relayHealthFailures = previous.relayFailures ?? 0;
|
|
546
|
+
}
|
|
477
547
|
} else {
|
|
478
548
|
if (!saved.outputFile) await phase("Refreshing the internet tunnel for this update\u2026");
|
|
479
549
|
const abandoned = await adoptRelay(owner2, saved.route, directory, saved.outputFile);
|
|
@@ -591,6 +661,7 @@ async function superviseComputer(directory) {
|
|
|
591
661
|
relayHealthFailures++;
|
|
592
662
|
nextCheckAt = checkedAt + Math.min(15e3, recoveryDelay(relayHealthFailures));
|
|
593
663
|
if (result.canRestart) {
|
|
664
|
+
await phase(result.error instanceof RelayCheckError && result.error.addressMissing ? "Cloudflare's address expired. Creating a new secure tunnel\u2026" : "The internet tunnel stopped responding. Replacing it\u2026");
|
|
594
665
|
await relay.close();
|
|
595
666
|
relay = void 0;
|
|
596
667
|
relayWasReachable = false;
|
|
@@ -609,7 +680,7 @@ async function superviseComputer(directory) {
|
|
|
609
680
|
await checkRelay(checking.route, { signal: abort.signal });
|
|
610
681
|
checkResult = { relay: checking };
|
|
611
682
|
} catch (error) {
|
|
612
|
-
const canRestart = !!checking.owner && relayFailedAt > 0 && relayNeedsRestart(error, relayHealthFailures, Date.now() - relayFailedAt) && await relayProviderReachable(config.relay, abort.signal).catch(() => false);
|
|
683
|
+
const canRestart = !!checking.owner && relayFailedAt > 0 && relayNeedsRestart(error, relayHealthFailures, Date.now() - relayFailedAt) && (error instanceof RelayCheckError && error.addressMissing || await relayProviderReachable(config.relay, abort.signal).catch(() => false));
|
|
613
684
|
checkResult = { relay: checking, error, canRestart };
|
|
614
685
|
}
|
|
615
686
|
})();
|
|
@@ -635,7 +706,9 @@ async function superviseComputer(directory) {
|
|
|
635
706
|
phase: ready ? void 0 : daemonError ?? relayError ?? relayMessage,
|
|
636
707
|
error: daemonError ?? relayError,
|
|
637
708
|
errorCode: daemonError ? void 0 : relayErrorCode,
|
|
638
|
-
recovering: !ready
|
|
709
|
+
recovering: !ready,
|
|
710
|
+
relayFailureSince: relayFailedAt || void 0,
|
|
711
|
+
relayFailures: relayHealthFailures || void 0
|
|
639
712
|
};
|
|
640
713
|
const serialized = JSON.stringify(state);
|
|
641
714
|
if (serialized !== lastController) {
|
|
@@ -716,5 +789,5 @@ async function superviseComputer(directory) {
|
|
|
716
789
|
}
|
|
717
790
|
|
|
718
791
|
export { recoveryDelay, superviseComputer };
|
|
719
|
-
//# sourceMappingURL=controller-
|
|
720
|
-
//# sourceMappingURL=controller-
|
|
792
|
+
//# sourceMappingURL=controller-AGT6MCJG.js.map
|
|
793
|
+
//# sourceMappingURL=controller-AGT6MCJG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/computer/cloudflare-binary.ts","../src/computer/relay-output.ts","../src/computer/relay.ts","../src/computer/relay-health.ts","../src/computer/controller.ts"],"names":["path","request","tmpdir","path2","rm","resolve","delay","family","address","process","spawn","client","owner","state"],"mappings":"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","file":"controller-AGT6MCJG.js","sourcesContent":["import { execFile } from \"node:child_process\";\nimport { mkdtemp, writeFile, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport * as path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { binaryCacheDirectory, cachedExecutable, cacheExecutable, executableChecksum, verifyReleaseBytes } from \"../binary-cache.js\";\n\n// The bridge was tested against this release. The helper never updates itself or\n// changes a system installation; a newer Mindwire release can advance this pin.\nexport const CLOUDFLARED_VERSION = \"2026.9.3\";\nconst execute = promisify(execFile);\n\nexport async function ensureCloudflareBinary(options: {\n cacheDir?: string; platform?: string; arch?: string; fetch?: typeof fetch;\n onProgress?: (message: string) => void | Promise<void>;\n} = {}): Promise<string> {\n const platform = options.platform ?? process.platform, arch = options.arch ?? process.arch;\n const cpu = arch === \"x64\" ? \"amd64\" : arch === \"arm64\" ? \"arm64\" : \"\";\n if (!cpu || ![\"darwin\", \"linux\", \"win32\"].includes(platform) || platform === \"win32\" && cpu !== \"amd64\") {\n throw new Error(\"Install cloudflared for this computer, or select another connection provider.\");\n }\n const asset = `cloudflared-${platform === \"win32\" ? \"windows\" : platform}-${cpu}${platform === \"darwin\" ? \".tgz\" : platform === \"win32\" ? \".exe\" : \"\"}`;\n const bin = path.join(options.cacheDir ?? await binaryCacheDirectory(), \"cloudflared\", CLOUDFLARED_VERSION,\n `${platform}-${arch}`, platform === \"win32\" ? \"cloudflared.exe\" : \"cloudflared\");\n const cached = await cachedExecutable(bin);\n if (cached) return cached;\n await options.onProgress?.(\"Downloading the secure connection helper…\");\n const request = options.fetch ?? fetch;\n const release = await request(`https://api.github.com/repos/cloudflare/cloudflared/releases/tags/${CLOUDFLARED_VERSION}`,\n { headers: { Accept: \"application/vnd.github+json\" }, signal: AbortSignal.timeout(20_000) });\n if (!release.ok) throw new Error(\"Couldn't download the connection helper. Retry, install cloudflared yourself, or choose another provider.\");\n const metadata = await release.json() as { assets?: { name: string; digest?: string; browser_download_url: string }[] };\n const item = metadata.assets?.find(value => value.name === asset);\n const checksum = item?.digest?.match(/^sha256:([a-f0-9]{64})$/i)?.[1];\n const expectedURL = `https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/${asset}`;\n if (!checksum || item?.browser_download_url !== expectedURL) throw new Error(\"The connection helper has no verified release asset for this computer.\");\n const downloaded = await request(expectedURL, { signal: AbortSignal.timeout(120_000) });\n if (!downloaded.ok) throw new Error(\"Couldn't download the connection helper. Check your internet connection and retry.\");\n const archive = new Uint8Array(await downloaded.arrayBuffer());\n await verifyReleaseBytes(archive, checksum, asset);\n let executable = archive;\n if (platform === \"darwin\") {\n const temporary = await mkdtemp(path.join(tmpdir(), \"mindwire-cloudflared-\"));\n try {\n const archivePath = path.join(temporary, asset);\n await writeFile(archivePath, archive, { mode: 0o600 });\n // Read only this exact archive member to stdout. No archive paths are\n // extracted into the filesystem and no downloaded script is executed.\n const result = await execute(\"/usr/bin/tar\", [\"-xzOf\", archivePath, \"cloudflared\"],\n { encoding: \"buffer\", maxBuffer: 128 * 1024 * 1024, timeout: 30_000 });\n executable = new Uint8Array(result.stdout);\n } finally { await rm(temporary, { recursive: true, force: true }); }\n }\n return cacheExecutable(bin, executable, await executableChecksum(executable));\n}\n\nexport async function cloudflareCommand(options: Parameters<typeof ensureCloudflareBinary>[0]): Promise<string> {\n try {\n await execute(\"cloudflared\", [\"--version\"], { timeout: 3000, windowsHide: true });\n return \"cloudflared\";\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw new Error(\"The installed cloudflared could not start. Repair it or choose another connection provider.\");\n return ensureCloudflareBinary(options);\n }\n}\n","import { randomUUID } from \"node:crypto\";\nimport { open, rm, type FileHandle } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport * as path from \"node:path\";\n\n/** A provider must not inherit pipes whose reader dies during a controller\n * upgrade. Use a private append-only file descriptor, consume startup output,\n * then discard it. A successor can adopt the same file without touching the\n * provider or its address. Raw provider output is never copied to our logs. */\nexport class RelayOutput {\n private position = 0;\n private timer?: ReturnType<typeof setInterval>;\n private pending: Promise<void> = Promise.resolve();\n private closing?: Promise<void>;\n\n private constructor(readonly file: string, private readonly handle: FileHandle) {}\n\n static async create(directory = tmpdir()): Promise<RelayOutput> {\n const file = path.join(directory, `.relay-output-${randomUUID()}.log`);\n return new RelayOutput(file, await open(file, \"ax+\", 0o600));\n }\n\n static async adopt(directory: string, file: string): Promise<RelayOutput | undefined> {\n // Only our private spool files can be truncated or removed during adoption.\n if (path.dirname(file) !== path.resolve(directory)\n || !/^\\.relay-output-[a-f0-9-]{36}\\.log$/.test(path.basename(file))) return;\n try {\n const output = new RelayOutput(file, await open(file, \"r+\"));\n output.discard();\n return output;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n }\n }\n\n get fd(): number { return this.handle.fd; }\n\n async read(): Promise<Buffer> {\n const { size } = await this.handle.stat();\n if (size > 2 * 1024 * 1024) throw new Error(\"The tunnel helper produced too much startup output. Check its configuration.\");\n const data = Buffer.alloc(Math.min(65_536, Math.max(0, size - this.position)));\n const { bytesRead } = await this.handle.read(data, 0, data.length, this.position);\n this.position += bytesRead;\n return data.subarray(0, bytesRead);\n }\n\n discard(): void {\n if (this.timer || this.closing) return;\n const drain = () => {\n // O_APPEND on the provider's descriptor ensures truncation never leaves\n // sparse holes. After readiness no log record is needed for connectivity.\n this.pending = this.pending.then(() => this.handle.truncate(0)).catch(() => {});\n };\n drain();\n this.timer = setInterval(drain, 2000);\n this.timer.unref();\n }\n\n close(): Promise<void> {\n return this.closing ??= (async () => {\n clearInterval(this.timer);\n await this.pending;\n await this.handle.close();\n await rm(this.file, { force: true });\n })();\n }\n}\n","import { spawn, type ChildProcess } from \"node:child_process\";\nimport { readFile } from \"node:fs/promises\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport type { ComputerRoute } from \"../computer.js\";\nimport { cloudflareCommand } from \"./cloudflare-binary.js\";\nimport { ownChild, type OwnedProcess } from \"./process.js\";\nimport { RelayOutput } from \"./relay-output.js\";\n\nexport interface RelayOptions {\n kind: \"none\" | \"cloudflare\" | \"ngrok\" | \"custom\";\n /** A stable, already configured hostname; custom relays must forward WebSocket upgrades. */\n url?: string;\n cloudflareTokenFile?: string;\n}\nexport interface RelayHandle { route?: ComputerRoute; process?: ChildProcess; owner?: OwnedProcess; outputFile?: string; close(): void | Promise<void> }\n\nexport async function adoptRelay(owner: OwnedProcess, route: ComputerRoute | undefined, directory: string, outputFile?: string): Promise<RelayHandle> {\n const output = outputFile ? await RelayOutput.adopt(directory, outputFile) : undefined;\n return { route, owner, outputFile: output?.file, async close() { await owner.close(); await output?.close(); } };\n}\n\nexport function websocketURL(value: string): string {\n const url = new URL(value);\n if (url.protocol === \"https:\") url.protocol = \"wss:\";\n if (url.protocol !== \"wss:\" || !url.hostname || url.username || url.password || url.hash) {\n throw new Error(\"Relay URLs must use wss:// with no embedded credentials or fragment.\");\n }\n if (!url.pathname || url.pathname === \"/\") url.pathname = \"/ssh\";\n return url.toString();\n}\n\n/** Both providers forward encrypted SSH bytes to one loopback WebSocket bridge. */\nexport async function startRelay(options: RelayOptions, port: number, runtime: {\n cacheDir?: string; outputDirectory?: string; onProgress?: (message: string) => void | Promise<void>;\n signal?: AbortSignal; onSpawn?: (owner: OwnedProcess, outputFile: string) => Promise<void>;\n} = {}): Promise<RelayHandle> {\n runtime.signal?.throwIfAborted();\n if (options.kind === \"none\") return { close() {} };\n if (options.kind === \"custom\") {\n if (!options.url) throw new Error(\"A custom relay needs --relay-url wss://your-host/ssh.\");\n return { route: { kind: \"websocket\", url: websocketURL(options.url) }, close() {} };\n }\n const origin = `http://127.0.0.1:${port}`;\n const env = { ...process.env };\n let command: string, args: string[];\n if (options.kind === \"cloudflare\") {\n command = await cloudflareCommand(runtime);\n await runtime.onProgress?.(\"Connecting through Cloudflare…\");\n if (options.cloudflareTokenFile) {\n if (!options.url) throw new Error(\"A named Cloudflare tunnel needs --relay-url for its configured hostname.\");\n env.TUNNEL_TOKEN = (await readFile(options.cloudflareTokenFile, \"utf8\")).trim();\n args = [\"tunnel\", \"--no-autoupdate\", \"run\"];\n } else {\n if (options.url) throw new Error(\"Use --cloudflare-token-file with a named tunnel, or --relay custom for an existing tunnel.\");\n args = [\"tunnel\", \"--no-autoupdate\", \"--url\", origin];\n }\n } else {\n command = \"ngrok\";\n args = [\"http\", origin, \"--log\", \"stdout\", \"--log-format\", \"json\"];\n if (options.url) {\n const url = new URL(websocketURL(options.url));\n args.push(\"--url\", `https://${url.host}`);\n }\n }\n runtime.signal?.throwIfAborted();\n const output = await RelayOutput.create(runtime.outputDirectory);\n const child = spawn(command, args, { env, detached: true, stdio: [\"ignore\", output.fd, output.fd], windowsHide: true });\n let failure: Error | undefined;\n child.on(\"error\", error => { failure = error; });\n let owner: OwnedProcess | undefined;\n try {\n await new Promise<void>((resolve, reject) => { child.once(\"spawn\", resolve); child.once(\"error\", reject); });\n owner = await ownChild(child);\n await runtime.onSpawn?.(owner, output.file);\n const deadline = Date.now() + 45_000;\n let buffer = \"\", cloudflareAddress = options.url, cloudflareConnected = false;\n while (Date.now() < deadline) {\n runtime.signal?.throwIfAborted();\n if (failure) throw new Error(`Could not run ${options.kind}. Check its installation.`, { cause: failure });\n if (!owner.alive()) throw new Error(`${options.kind} exited before the tunnel connected. Check its account configuration.`);\n const received = buffer + (await output.read()).toString();\n buffer = received.slice(-16_384);\n let found: string | undefined;\n if (options.kind === \"cloudflare\") {\n cloudflareAddress ??= received.match(/https:\\/\\/[a-z0-9-]+\\.trycloudflare\\.com/)?.[0];\n cloudflareConnected ||= /Registered tunnel connection/.test(received);\n if (cloudflareConnected) found = cloudflareAddress;\n } else {\n for (const line of received.split(/\\r?\\n/)) {\n try {\n const event = JSON.parse(line) as { msg?: string; url?: string };\n if (event.msg === \"started tunnel\" && event.url?.startsWith(\"https://\")) found = event.url;\n } catch { /* Wait for a complete JSON log record. */ }\n }\n }\n if (found) {\n const route: ComputerRoute = { kind: \"websocket\", url: websocketURL(found) };\n output.discard();\n const provider = owner;\n return { route, process: child, owner, outputFile: output.file,\n async close() { await provider.close(); await output.close(); } };\n }\n await delay(50, undefined, { signal: runtime.signal });\n }\n throw new Error(`${options.kind} did not establish its tunnel. Check your internet connection and its configuration.`);\n } catch (error) {\n if (owner) await owner.close();\n else if (child.pid) await (await ownChild(child)).close();\n await output.close();\n throw error;\n }\n}\n","import { request } from \"node:https\";\nimport { lookup } from \"node:dns\";\nimport { Resolver } from \"node:dns/promises\";\nimport { isIP, type LookupFunction } from \"node:net\";\nimport WebSocket from \"ws\";\nimport type { ComputerRoute } from \"../computer.js\";\nimport type { RelayOptions } from \"./relay.js\";\n\nexport class RelayCheckError extends Error {\n constructor(readonly code: \"dns\" | \"timeout\" | \"proxy\" | \"connection\" | \"response\", message: string, cause?: Error,\n readonly addressMissing = false) {\n super(message, cause ? { cause } : undefined);\n this.name = \"RelayCheckError\";\n }\n}\n\n/** Local NXDOMAIN can be a stale cache. A missing address confirmed by the\n * provider is different: its helper may stay alive after the quick tunnel expires.\n * Keep a grace period for newly allocated records and ordinary internet outages. */\nexport function relayNeedsRestart(error: unknown, failures: number, failedForMs: number): boolean {\n return failures >= 2 && failedForMs >= 90_000\n && (!(error instanceof RelayCheckError && error.code === \"dns\") || error.addressMissing);\n}\n\ntype RelayDNSResult = { addresses: { address: string; family: number }[]; missing: boolean };\nconst quickTunnelHost = /^[a-z0-9-]+\\.trycloudflare\\.com$/i;\n\n/** Use the tunnel provider's HTTPS resolver only after local DNS fails. This\n * bypasses router negative caches without another service or a persisted IP.\n * A DNS answer never replaces TLS hostname validation or the phone's SSH pin. */\nexport async function resolveCloudflareAddress(hostname: string, family = 0,\n options: { fetch?: typeof fetch; timeoutMs?: number } = {}): Promise<RelayDNSResult> {\n if (!quickTunnelHost.test(hostname)) return { addresses: [], missing: false };\n const abort = new AbortController();\n const timer = setTimeout(() => abort.abort(), options.timeoutMs ?? 3000);\n try {\n const types = family === 4 ? [1] : family === 6 ? [28] : [1, 28];\n const results = await Promise.all(types.map(async type => {\n try {\n const response = await (options.fetch ?? fetch)(\n `https://cloudflare-dns.com/dns-query?name=${encodeURIComponent(hostname)}&type=${type}`,\n { headers: { accept: \"application/dns-json\" }, redirect: \"error\", signal: abort.signal });\n if (response.status !== 200 || !response.body) { await response.body?.cancel(); return undefined; }\n const reader = response.body.getReader();\n let text = \"\", size = 0;\n const decoder = new TextDecoder();\n try {\n for (;;) {\n const chunk = await reader.read();\n if (chunk.done) break;\n size += chunk.value.length;\n if (size > 16_384) return undefined;\n text += decoder.decode(chunk.value, { stream: true });\n }\n } finally { await reader.cancel(); }\n const result = JSON.parse(text + decoder.decode()) as {\n Status?: number; Question?: { name?: string; type?: number }[];\n Answer?: { type?: number; data?: string }[];\n };\n if (!Array.isArray(result.Question) || !result.Question.some(question =>\n question.name?.replace(/\\.$/, \"\").toLowerCase() === hostname.toLowerCase() && question.type === type)) return undefined;\n if (result.Status === 3) return { addresses: [], missing: true };\n if (result.Status !== 0) return undefined;\n const addresses = (Array.isArray(result.Answer) ? result.Answer : []).flatMap(answer => {\n const family = answer.type === 1 ? 4 : answer.type === 28 ? 6 : 0;\n return family && answer.type === type && typeof answer.data === \"string\" && isIP(answer.data) === family\n ? [{ address: answer.data, family }] : [];\n });\n return { addresses, missing: false };\n } catch { return undefined; }\n }));\n return { addresses: results.flatMap(result => result?.addresses ?? []),\n missing: results.every(result => result?.missing === true) };\n } finally { clearTimeout(timer); }\n}\n\n/** Try OS DNS, then its uncached resolver, then the provider for quick tunnels.\n * TLS SNI/certificate validation still use the original hostname. */\nconst relayLookup: LookupFunction = (hostname, options, callback) => {\n lookup(hostname, options, (error, address, family) => {\n if (![\"ENOTFOUND\", \"EAI_AGAIN\"].includes((error as NodeJS.ErrnoException | null)?.code ?? \"\") || !quickTunnelHost.test(hostname)) {\n callback(error, address, family); return;\n }\n const resolver = new Resolver({ timeout: 3000, tries: 1 });\n const requestedFamily = options.family === \"IPv4\" ? 4 : options.family === \"IPv6\" ? 6 : options.family ?? 0;\n void Promise.all([\n requestedFamily === 6 ? [] : resolver.resolve4(hostname).then(addresses => addresses.map(address => ({ address, family: 4 })), () => []),\n requestedFamily === 4 ? [] : resolver.resolve6(hostname).then(addresses => addresses.map(address => ({ address, family: 6 })), () => []),\n ]).then(async results => {\n let addresses = results.flat();\n if (!addresses.length) {\n const provider = await resolveCloudflareAddress(hostname, requestedFamily);\n addresses = provider.addresses;\n if (!addresses.length) {\n callback(Object.assign(error!, { relayAddressMissing: provider.missing }), address, family); return;\n }\n }\n if (options.all) callback(null, addresses);\n else callback(null, addresses[0]!.address, addresses[0]!.family);\n });\n });\n};\n\n/** Check the actual WebSocket byte path, not just the helper's PID or its logs.\n * The phone still authenticates and pins the SSH host before sending secrets. */\nexport async function checkRelay(route: ComputerRoute, options: { signal?: AbortSignal; timeoutMs?: number; lookup?: LookupFunction } = {}): Promise<void> {\n options.signal?.throwIfAborted();\n if (route.kind !== \"websocket\") throw new Error(\"Expected an internet tunnel address.\");\n await new Promise<void>((resolve, reject) => {\n const socket = new WebSocket(route.url, { maxPayload: 4096, perMessageDeflate: false, followRedirects: false, lookup: options.lookup ?? relayLookup });\n let finished = false, banner = \"\";\n const finish = (error?: Error) => {\n if (finished) return;\n finished = true;\n clearTimeout(timer);\n options.signal?.removeEventListener(\"abort\", aborted);\n socket.terminate();\n if (error) reject(error); else resolve();\n };\n const aborted = () => finish(options.signal?.reason ?? new Error(\"Connection check cancelled.\"));\n const timer = setTimeout(() => finish(new RelayCheckError(\"timeout\", \"The internet tunnel isn't responding. Retrying…\")), options.timeoutMs ?? 8000);\n socket.on(\"error\", error => {\n if ([\"ENOTFOUND\", \"EAI_AGAIN\"].includes((error as NodeJS.ErrnoException).code ?? \"\")) {\n const provider = new URL(route.url).hostname.endsWith(\".trycloudflare.com\") ? \"Cloudflare's\" : \"the tunnel's\";\n finish(new RelayCheckError(\"dns\", `Waiting for ${provider} internet address (DNS)…`, error,\n (error as Error & { relayAddressMissing?: boolean }).relayAddressMissing === true));\n } else if (/(?:[Uu]nexpected server response|[Ee]xpected 101)/.test(error.message)) {\n finish(new RelayCheckError(\"proxy\", \"The internet tunnel isn't reaching Mindwire. Retrying…\", error));\n } else {\n finish(new RelayCheckError(\"connection\", \"The internet tunnel couldn't connect. Retrying…\", error));\n }\n });\n socket.on(\"close\", () => finish(new RelayCheckError(\"connection\", \"The internet tunnel closed before reaching Mindwire. Retrying…\")));\n socket.on(\"message\", (data, binary) => {\n if (!binary) { finish(new RelayCheckError(\"response\", \"The internet tunnel returned an invalid SSH response.\")); return; }\n banner += data.toString();\n if (banner.length > 1024) { finish(new RelayCheckError(\"response\", \"The internet tunnel returned an invalid SSH response.\")); return; }\n if (banner.includes(\"\\n\")) {\n finish(banner.split(\"\\n\")[0]?.trim() === \"SSH-2.0-Mindwire\" ? undefined\n : new RelayCheckError(\"response\", \"The internet tunnel isn't connected to the Mindwire SSH service.\"));\n }\n });\n options.signal?.addEventListener(\"abort\", aborted, { once: true });\n if (options.signal?.aborted) aborted();\n });\n}\n\n/** Don't rotate a quick-tunnel address during an ordinary internet outage.\n * Let the provider reconnect with the same address until it is reachable again. */\nexport async function relayProviderReachable(options: RelayOptions, signal?: AbortSignal): Promise<boolean> {\n if (options.kind !== \"cloudflare\" && options.kind !== \"ngrok\") return false;\n signal?.throwIfAborted();\n return new Promise<boolean>(resolve => {\n const url = options.kind === \"cloudflare\" ? \"https://api.trycloudflare.com/\" : \"https://api.ngrok.com/\";\n let finished = false;\n const done = (reachable: boolean) => {\n if (finished) return;\n finished = true;\n clearTimeout(timer);\n probe.destroy();\n resolve(reachable);\n };\n const probe = request(url, { method: \"HEAD\", signal }, response => {\n response.destroy();\n done(true);\n });\n const timer = setTimeout(() => done(false), 5000);\n probe.on(\"error\", () => done(false));\n probe.end();\n });\n}\n","import { spawn, execFileSync } from \"node:child_process\";\nimport { randomBytes } from \"node:crypto\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport type { Mindwire } from \"../client.js\";\nimport { ensureDaemonBinary } from \"../daemon-binary.js\";\nimport { SDK_VERSION } from \"../version.js\";\nimport type { ComputerInfo, ComputerRoute, ComputerUpdate } from \"../computer.js\";\nimport { computerClient, directRoutes, readJSON, writeJSON, CONTROLLER_PROTOCOL, type ComputerConfig, type ControllerState } from \"./lifecycle.js\";\nimport { adoptRelay, startRelay, type RelayHandle } from \"./relay.js\";\nimport { checkRelay, relayNeedsRestart, relayProviderReachable, RelayCheckError } from \"./relay-health.js\";\nimport { adoptProcess, ownChild, currentProcessIdentity, processStateAlive, processIdentity, type OwnedProcess, type ProcessIdentity } from \"./process.js\";\nimport { RelayOutput } from \"./relay-output.js\";\n\ninterface SavedRelay { owner: ProcessIdentity; port: number; options: string; route?: ComputerRoute; outputFile?: string }\nexport function recoveryDelay(failures: number): number { return Math.min(60_000, 1000 * 2 ** Math.min(6, Math.max(0, failures - 1))); }\n\n/** Own process lifecycle separately from any mobile view or pairing command. */\nexport async function superviseComputer(directory: string): Promise<void> {\n if ((await readJSON<{ stopped: boolean }>(path.join(directory, \"computer-stopped.json\")))?.stopped) return;\n let config = await readJSON<ComputerConfig>(path.join(directory, \"computer-config.json\"));\n if (!config) throw new Error(\"Computer configuration is missing.\");\n const controllerPath = path.join(directory, \"computer-controller.json\");\n const relayPath = path.join(directory, \"computer-relay.json\");\n const previous = await readJSON<ControllerState>(controllerPath);\n if (await processStateAlive(previous)) throw new Error(\"The computer already has a service controller.\");\n const owner = await currentProcessIdentity();\n const phase = (message: string) => writeJSON(controllerPath, { ...owner, protocol: CONTROLLER_PROTOCOL, cliVersion: SDK_VERSION, ready: false, phase: message, recovering: true });\n await phase(\"Preparing Mindwire…\");\n let child: OwnedProcess | undefined, relay: RelayHandle | undefined, stopping = false;\n let relayTask: Promise<void> | undefined, updateTask: Promise<void> | undefined;\n let relayResult: { handle?: RelayHandle; error?: unknown } | undefined;\n let checkTask: Promise<void> | undefined;\n let checkResult: { relay: RelayHandle; error?: unknown; canRestart?: boolean } | undefined;\n const abort = new AbortController();\n const stop = () => { stopping = true; abort.abort(); };\n process.on(\"SIGTERM\", stop); process.on(\"SIGINT\", stop);\n\n let token: string;\n try { token = (await fs.readFile(path.join(directory, \"daemon.token\"), \"utf8\")).trim(); }\n catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n token = randomBytes(32).toString(\"hex\");\n await fs.writeFile(path.join(directory, \"daemon.token\"), token, { mode: 0o600, flag: \"wx\" });\n }\n const daemonEnv = { ...process.env };\n if (process.platform === \"win32\") {\n try {\n const git = execFileSync(\"where.exe\", [\"git\"], { encoding: \"utf8\", timeout: 3000, windowsHide: true }).split(/\\r?\\n/)[0];\n if (git) {\n const shellDirectory = path.resolve(path.dirname(git), \"..\", \"bin\");\n await fs.access(path.join(shellDirectory, \"bash.exe\"));\n const pathKey = Object.keys(daemonEnv).find(key => key.toLowerCase() === \"path\") ?? \"PATH\";\n daemonEnv[pathKey] = `${shellDirectory}${path.delimiter}${daemonEnv[pathKey] ?? \"\"}`;\n }\n } catch { /* Git/Bash are checked only when their capabilities are used. */ }\n }\n const oldRuntime = await readJSON<ComputerInfo>(path.join(directory, \"computer-runtime.json\"));\n // An automatically selected port remains stable across controller/release restarts.\n let sshPort = config.sshPort || oldRuntime?.sshPort || 0;\n let websocketPort = config.websocketPort || oldRuntime?.websocketPort || 0;\n const launch = async (binary: string): Promise<Mindwire> => {\n await fs.rm(path.join(directory, \"computer-runtime.json\"), { force: true });\n const process = spawn(binary, [\"--computer\"], {\n cwd: config!.directory, stdio: [\"ignore\", \"inherit\", \"inherit\"], windowsHide: true,\n env: { ...daemonEnv, DAEMON_TOKEN: token, ADDR: \"127.0.0.1:0\", STATE_PATH: path.join(directory, \"agent-state.json\"),\n WORKSPACE_DB_PATH: path.join(directory, \"workspace.db\"), AGENT_CWD: config!.directory,\n COMPUTER_SSH_ADDR: `${config!.bind.includes(\":\") ? `[${config!.bind}]` : config!.bind}:${sshPort}`,\n COMPUTER_WS_ADDR: `127.0.0.1:${websocketPort}`, MINDWIRE_COMPUTER_MANAGED: \"1\" },\n });\n let failure: Error | undefined;\n process.on(\"error\", error => { failure = error; });\n await new Promise<void>((resolve, reject) => { process.once(\"spawn\", resolve); process.once(\"error\", reject); });\n child = await ownChild(process);\n for (let attempt = 0; attempt < 100; attempt++) {\n if (stopping) throw new Error(\"Mindwire is stopping.\");\n if (failure) throw failure;\n if (!child.alive()) throw new Error(\"Mindwire exited during startup. Check computer.log and the installed release.\");\n try {\n const client = await computerClient(directory);\n const info = await client.computer.info();\n if (info.pid !== child.pid) throw new Error(\"Another service owns this computer's state.\");\n const health = await client.health();\n if ((health as { computerConnectionVersion?: number }).computerConnectionVersion !== 1) throw new Error(\"Update Mindwire to a release that supports computer connections.\");\n sshPort = info.sshPort; websocketPort = info.websocketPort;\n return client;\n } catch (error) { if (attempt === 99) throw error; }\n await delay(100);\n }\n throw new Error(\"Mindwire startup timed out.\");\n };\n\n let routes: ComputerRoute[] = [], published = \"\";\n let client: Mindwire | undefined;\n let relayMessage = \"Preparing your internet connection…\", relayError: string | undefined;\n let relayErrorCode: string | undefined;\n let daemonError: string | undefined, nextDaemonAt = 0, daemonFailures = 0;\n let nextRelayAt = 0, relayFailures = 0, changingDaemon = false;\n let daemonReadyAt = Date.now(), relayReadyAt = Date.now();\n let relayReachable = false, relayWasReachable = false, relayHealthFailures = 0;\n let relayFailedAt = 0;\n let nextCheckAt = 0, checkedAt = 0;\n try {\n await phase(\"Checking the Mindwire service…\");\n let binary = config.daemonBin ?? await ensureDaemonBinary({ version: config.version ?? SDK_VERSION, cacheDir: process.env.MINDWIRE_RELEASE_CACHE_DIR });\n // A killed controller must not restart a healthy daemon or lose its PTYs.\n try { client = await computerClient(directory); } catch { /* Cold start. */ }\n if (client) {\n const info = await client.computer.info();\n const identity = await processIdentity(info.pid);\n child = identity ? await adoptProcess(identity) : undefined;\n if (!child) throw new Error(\"Couldn't verify the existing Mindwire process. Leave it running and retry.\");\n sshPort = info.sshPort; websocketPort = info.websocketPort;\n } else {\n await phase(\"Starting the Mindwire service…\");\n client = await launch(binary);\n }\n\n const saved = await readJSON<SavedRelay>(relayPath);\n if (saved) {\n const owner = await adoptProcess(saved.owner);\n if (owner) {\n if (saved.outputFile && saved.route && saved.port === websocketPort && saved.options === JSON.stringify(config.relay)) {\n relay = await adoptRelay(owner, saved.route, directory, saved.outputFile);\n relayWasReachable = !!previous?.routes?.some(route => JSON.stringify(route) === JSON.stringify(saved.route));\n if (previous?.relayFailureSince && relayWasReachable) {\n relayFailedAt = Math.min(Date.now(), previous.relayFailureSince);\n relayHealthFailures = previous.relayFailures ?? 0;\n }\n } else {\n // An old helper's pipes belonged to the controller we replaced. It\n // can still answer briefly, then die on its next log write. Migrate\n // it once before certifying a QR, keeping the daemon and phone keys.\n if (!saved.outputFile) await phase(\"Refreshing the internet tunnel for this update…\");\n const abandoned = await adoptRelay(owner, saved.route, directory, saved.outputFile);\n await abandoned.close();\n await fs.rm(relayPath, { force: true });\n }\n } else if (saved.outputFile) {\n await (await RelayOutput.adopt(directory, saved.outputFile))?.close();\n }\n }\n\n let lastController = \"\";\n while (!stopping) {\n if (!changingDaemon && child && !child.alive()) {\n child = undefined; client = undefined;\n daemonError = \"The service stopped. Restarting it…\";\n nextDaemonAt = Date.now() + recoveryDelay(++daemonFailures);\n }\n if (child?.alive() && Date.now() - daemonReadyAt > 60_000) daemonFailures = 0;\n if (relayReachable && relay?.owner?.alive() && Date.now() - relayReadyAt > 60_000) relayFailures = 0;\n if (!changingDaemon && !child?.alive() && Date.now() >= nextDaemonAt) {\n daemonError = \"The service stopped. Restarting it…\";\n await phase(daemonError);\n try {\n client = await launch(binary); published = \"\"; daemonError = undefined; daemonReadyAt = Date.now();\n } catch (error) {\n if (child) await child.close();\n child = undefined; client = undefined;\n daemonError = error instanceof Error ? error.message : \"Service restart failed.\";\n nextDaemonAt = Date.now() + recoveryDelay(++daemonFailures);\n }\n }\n\n if (relay?.owner && !relay.owner.alive()) {\n await relay.close();\n relay = undefined;\n relayReachable = false; relayWasReachable = false;\n relayErrorCode = undefined;\n relayError = \"The internet tunnel disconnected. Reconnecting…\";\n nextRelayAt = Date.now() + recoveryDelay(++relayFailures);\n }\n if (relayResult) {\n const result = relayResult; relayResult = undefined; relayTask = undefined;\n if (result.handle) {\n relay = result.handle; relayError = undefined; relayErrorCode = undefined; relayReadyAt = Date.now();\n relayReachable = false; relayWasReachable = false; relayHealthFailures = 0; relayFailedAt = 0; nextCheckAt = 0;\n if (relay.owner?.identity) await writeJSON(relayPath, {\n owner: relay.owner.identity, port: websocketPort, options: JSON.stringify(config.relay), route: relay.route, outputFile: relay.outputFile,\n } satisfies SavedRelay);\n } else {\n relayError = result.error instanceof Error ? result.error.message : \"The internet tunnel couldn't connect.\";\n nextRelayAt = Date.now() + recoveryDelay(++relayFailures);\n }\n }\n if (!relay && !relayTask && Date.now() >= nextRelayAt) {\n relayError = undefined; relayErrorCode = undefined;\n relayMessage = \"Reconnecting your internet tunnel…\";\n relayTask = startRelay(config.relay, websocketPort, {\n cacheDir: path.join(directory, \"tools\"), outputDirectory: directory, signal: abort.signal,\n onProgress: message => { relayMessage = message; },\n onSpawn: async (owner, outputFile) => {\n if (owner.identity) await writeJSON(relayPath, {\n owner: owner.identity, port: websocketPort, options: JSON.stringify(config!.relay), outputFile,\n } satisfies SavedRelay);\n },\n }).then(handle => { relayResult = { handle }; }, error => { relayResult = { error }; });\n }\n\n if (checkResult) {\n const result = checkResult; checkResult = undefined; checkTask = undefined;\n // A late failure from a replaced helper cannot invalidate its successor.\n if (result.relay === relay) {\n checkedAt = Date.now();\n relayReachable = !result.error;\n if (!result.error) {\n relayWasReachable = true; relayHealthFailures = 0; relayFailedAt = 0; relayError = undefined; relayErrorCode = undefined;\n nextCheckAt = checkedAt + 30_000;\n } else {\n relayError = result.error instanceof Error ? result.error.message : \"The internet tunnel couldn't connect. Retrying…\";\n relayErrorCode = result.error instanceof RelayCheckError ? result.error.code : undefined;\n relayFailedAt ||= checkedAt;\n relayHealthFailures++;\n nextCheckAt = checkedAt + Math.min(15_000, recoveryDelay(relayHealthFailures));\n if (result.canRestart) {\n // Only replace the tunnel after repeated failures with working\n // internet. The daemon, phone keys, chats and PTYs keep running.\n await phase(result.error instanceof RelayCheckError && result.error.addressMissing\n ? \"Cloudflare's address expired. Creating a new secure tunnel…\"\n : \"The internet tunnel stopped responding. Replacing it…\");\n await relay!.close(); relay = undefined;\n relayWasReachable = false; nextRelayAt = Date.now() + recoveryDelay(++relayFailures);\n await fs.rm(relayPath, { force: true });\n }\n }\n }\n }\n const requestedCheck = await readJSON<{ requestedAt: number }>(path.join(directory, \"computer-check.json\"));\n if (config.relay.kind === \"none\") checkedAt = Math.max(checkedAt, requestedCheck?.requestedAt ?? 0);\n if (relay?.route && !checkTask && (Date.now() >= nextCheckAt || (requestedCheck?.requestedAt ?? 0) > checkedAt)) {\n const checking = relay;\n checkTask = (async () => {\n try {\n await checkRelay(checking.route!, { signal: abort.signal });\n checkResult = { relay: checking };\n } catch (error) {\n const canRestart = !!checking.owner && relayFailedAt > 0\n && relayNeedsRestart(error, relayHealthFailures, Date.now() - relayFailedAt)\n && (error instanceof RelayCheckError && error.addressMissing\n || await relayProviderReachable(config!.relay, abort.signal).catch(() => false));\n checkResult = { relay: checking, error, canRestart };\n }\n })();\n }\n\n routes = directRoutes(config, sshPort);\n if (relay?.route && relayWasReachable) routes.push(relay.route);\n const routeJSON = JSON.stringify(routes);\n if (!changingDaemon && client && child?.alive() && routeJSON !== published) {\n try { await client.computer.setRoutes(routes); published = routeJSON; }\n catch { /* Retry publication; never claim the new routes are ready yet. */ }\n }\n const ready = !!client && !!child?.alive() && !changingDaemon && routes.length > 0 && published === routeJSON\n && (config.relay.kind === \"none\" || relayReachable);\n const state: ControllerState = { ...owner, protocol: CONTROLLER_PROTOCOL, cliVersion: SDK_VERSION, ready, routes, checkedAt,\n phase: ready ? undefined : daemonError ?? relayError ?? relayMessage, error: daemonError ?? relayError,\n errorCode: daemonError ? undefined : relayErrorCode, recovering: !ready,\n relayFailureSince: relayFailedAt || undefined, relayFailures: relayHealthFailures || undefined };\n const serialized = JSON.stringify(state);\n if (serialized !== lastController) { await writeJSON(controllerPath, state); lastController = serialized; }\n\n const updatePath = path.join(directory, \"computer-update.json\");\n const update = !updateTask && client && child?.alive() ? await readJSON<ComputerUpdate>(updatePath) : undefined;\n if (update && [\"queued\", \"downloading\", \"waiting\", \"restarting\"].includes(update.status)) {\n // Waiting for idle does not block relay recovery or address publication.\n updateTask = (async () => {\n const status = async (state: ComputerUpdate[\"status\"], error?: string) => writeJSON(updatePath,\n { ...update, status: state, error, updatedAt: new Date().toISOString() });\n try {\n await status(\"downloading\");\n const replacement = await ensureDaemonBinary({ version: update.version, cacheDir: process.env.MINDWIRE_RELEASE_CACHE_DIR });\n await status(\"waiting\");\n let lease: Awaited<ReturnType<Mindwire[\"service\"][\"acquireUpdate\"]>> | undefined;\n while (!stopping && !lease) {\n try { lease = await client!.service.acquireUpdate(); }\n catch (error) { if ((error as { status?: number }).status !== 409) throw error; await delay(2000); }\n }\n if (stopping || !lease) return;\n if (lease.pid !== child?.pid) { await client!.service.releaseUpdate(lease.id); throw new Error(\"The leased service process changed.\"); }\n changingDaemon = true;\n await status(\"restarting\");\n await child!.close();\n try {\n client = await launch(replacement);\n const health = await client.health();\n if (health.version.replace(/^v/, \"\") !== update.version) throw new Error(\"The replacement service reports a different release version.\");\n } catch (error) {\n if (child) await child.close();\n if (!stopping) client = await launch(binary);\n throw error;\n }\n binary = replacement;\n config = { ...config!, daemonBin: undefined, version: update.version };\n await writeJSON(path.join(directory, \"computer-config.json\"), config);\n await client.computer.setRoutes(routes); published = JSON.stringify(routes);\n await status(\"complete\");\n } catch (error) { await status(\"failed\", error instanceof Error ? error.message : \"Service update failed.\"); }\n finally { changingDaemon = false; published = \"\"; }\n })().finally(() => { updateTask = undefined; });\n }\n await delay(500);\n }\n } catch (error) {\n await writeJSON(controllerPath, { ...owner, ready: false, error: error instanceof Error ? error.message : \"Computer service failed.\" });\n throw error;\n } finally {\n abort.abort();\n await relayTask; await checkTask; await updateTask;\n if (relayResult?.handle && relayResult.handle !== relay) await relayResult.handle.close();\n await relay?.close();\n if (child) await child.close();\n process.off(\"SIGTERM\", stop); process.off(\"SIGINT\", stop);\n if (stopping) await writeJSON(controllerPath, { pid: 0, ready: false });\n }\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readJSON, processIdentity, writeJSON, processStateAlive } from './chunk-
|
|
1
|
+
import { readJSON, processIdentity, writeJSON, processStateAlive } from './chunk-3QFDSYKC.js';
|
|
2
2
|
import './chunk-T6TD76UA.js';
|
|
3
3
|
import { execFile } from 'child_process';
|
|
4
4
|
import * as path from 'path';
|
|
@@ -67,5 +67,5 @@ async function handoffController(directory, state, config, info) {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
export { handoffController };
|
|
70
|
-
//# sourceMappingURL=controller-handoff-
|
|
71
|
-
//# sourceMappingURL=controller-handoff-
|
|
70
|
+
//# sourceMappingURL=controller-handoff-3LAYBJUL.js.map
|
|
71
|
+
//# sourceMappingURL=controller-handoff-3LAYBJUL.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/computer/controller-handoff.ts"],"names":["route","delay"],"mappings":"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","file":"controller-handoff-
|
|
1
|
+
{"version":3,"sources":["../src/computer/controller-handoff.ts"],"names":["route","delay"],"mappings":"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","file":"controller-handoff-3LAYBJUL.js","sourcesContent":["import { execFile } from \"node:child_process\";\nimport * as path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport type { ComputerInfo } from \"../computer.js\";\nimport { readJSON, writeJSON, type ComputerConfig, type ControllerState } from \"./lifecycle.js\";\nimport { processIdentity, processStateAlive, type ProcessIdentity } from \"./process.js\";\n\nconst execute = promisify(execFile);\n\nasync function controllerProcess(pid: number, directory: string): Promise<{ identity: ProcessIdentity; children: { pid: number; name: string }[] }> {\n const identity = await processIdentity(pid);\n if (!identity) throw new Error(\"The computer controller changed. Retry the connection.\");\n let command: string, children: { pid: number; name: string }[];\n if (process.platform === \"win32\") {\n const result = await execute(\"powershell.exe\", [\"-NoProfile\", \"-NonInteractive\", \"-Command\",\n `$p=Get-CimInstance Win32_Process -Filter 'ProcessId = ${pid}'; $c=@(Get-CimInstance Win32_Process -Filter 'ParentProcessId = ${pid}'); @{command=$p.CommandLine; children=@($c | ForEach-Object { @{pid=$_.ProcessId; name=$_.Name} })} | ConvertTo-Json -Depth 4 -Compress`],\n { timeout: 5000, windowsHide: true });\n const value = JSON.parse(result.stdout);\n command = String(value.command ?? \"\").replaceAll('\"', \"\");\n children = value.children;\n } else {\n const [args, processes] = await Promise.all([\n execute(\"/bin/ps\", [\"-p\", String(pid), \"-o\", \"args=\"], { timeout: 3000 }),\n execute(\"/bin/ps\", [\"-axo\", \"pid=,ppid=,comm=\"], { timeout: 3000 }),\n ]);\n command = args.stdout.trim();\n children = processes.stdout.split(\"\\n\").flatMap(line => {\n const match = line.trim().match(/^(\\d+)\\s+(\\d+)\\s+(.+)$/);\n return match && Number(match[2]) === pid ? [{ pid: Number(match[1]), name: path.basename(match[3]!) }] : [];\n });\n }\n // Old releases recorded only a PID. Verify the actual controller command before\n // signalling it; a reused PID must never affect an unrelated process.\n if (!command.endsWith(`dist${path.sep}cli.js _serve --state-dir ${directory}`)\n || !/(?:^|[\\/\\\\])(?:node|bun)(?:\\.exe)?\\s/.test(command)) {\n throw new Error(\"Couldn't verify the old Mindwire controller. Restart Mindwire on the computer before connecting.\");\n }\n if ((await processIdentity(pid))?.start !== identity.start) throw new Error(\"The computer controller changed. Retry the connection.\");\n return { identity, children };\n}\n\n/** Hand off an old CLI controller without stopping the daemon or its terminals.\n * Its graceful shutdown deliberately closes both children, so only the verified\n * supervisor is terminated; the new controller adopts the existing children. */\nexport async function handoffController(directory: string, state: ControllerState, config: ComputerConfig, info: ComputerInfo): Promise<void> {\n const { identity, children } = await controllerProcess(state.pid, directory);\n if (state.start && state.start !== identity.start) throw new Error(\"The computer controller changed. Retry the connection.\");\n const relayFile = path.join(directory, \"computer-relay.json\");\n if (!await readJSON(relayFile)) {\n // Releases before process adoption didn't record the provider child. Capture\n // just that controller's unique helper before it becomes an orphan.\n const executable = config.relay.kind === \"cloudflare\" ? \"cloudflared\" : config.relay.kind === \"ngrok\" ? \"ngrok\" : undefined;\n const candidates = executable ? children.filter(child => child.name === executable || child.name === executable + \".exe\") : [];\n const route = info.routes.find(route => route.kind === \"websocket\");\n const relayOwner = candidates.length === 1 ? await processIdentity(candidates[0]!.pid) : undefined;\n if (route && relayOwner) await writeJSON(relayFile, {\n owner: relayOwner, port: info.websocketPort, options: JSON.stringify(config.relay), route,\n });\n }\n if (!await processStateAlive(identity)) throw new Error(\"The computer controller changed. Retry the connection.\");\n process.kill(identity.pid, \"SIGKILL\");\n for (let attempt = 0; attempt < 40; attempt++) {\n if (!await processStateAlive(identity)) return;\n await delay(50);\n }\n throw new Error(\"The old Mindwire controller is still exiting. Retry the connection.\");\n}\n"]}
|
package/dist/index.cjs
CHANGED
|
@@ -1139,7 +1139,7 @@ init_errors();
|
|
|
1139
1139
|
init_errors();
|
|
1140
1140
|
|
|
1141
1141
|
// src/version.ts
|
|
1142
|
-
var SDK_VERSION = "0.1.
|
|
1142
|
+
var SDK_VERSION = "0.1.34" ;
|
|
1143
1143
|
function versionAtLeast(actual, desired) {
|
|
1144
1144
|
if (actual === desired) return true;
|
|
1145
1145
|
if (!actual || !/^\d+\.\d+\.\d+$/.test(actual) || !/^\d+\.\d+\.\d+$/.test(desired)) return false;
|
package/dist/index.js
CHANGED
|
@@ -1002,7 +1002,7 @@ function computerPairingURI(invitation) {
|
|
|
1002
1002
|
}
|
|
1003
1003
|
|
|
1004
1004
|
// src/version.ts
|
|
1005
|
-
var SDK_VERSION = "0.1.
|
|
1005
|
+
var SDK_VERSION = "0.1.34" ;
|
|
1006
1006
|
function versionAtLeast(actual, desired) {
|
|
1007
1007
|
if (actual === desired) return true;
|
|
1008
1008
|
if (!actual || !/^\d+\.\d+\.\d+$/.test(actual) || !/^\d+\.\d+\.\d+$/.test(desired)) return false;
|