mindwire 0.1.33 → 0.1.36
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/binary-cache-CG52TXCZ.js +3 -0
- package/dist/{binary-cache-VM7VHCEU.js.map → binary-cache-CG52TXCZ.js.map} +1 -1
- package/dist/chunk-67BNDGRK.js +20 -0
- package/dist/chunk-67BNDGRK.js.map +1 -0
- package/dist/{chunk-3FR7BFAW.js → chunk-PFYKJ6LX.js} +56 -4
- package/dist/chunk-PFYKJ6LX.js.map +1 -0
- package/dist/{chunk-H2I3VRBS.js → chunk-RTGZDLSG.js} +529 -177
- package/dist/chunk-RTGZDLSG.js.map +1 -0
- package/dist/cli.js +763 -32
- package/dist/cli.js.map +1 -1
- package/dist/computer/connection-change.d.ts +13 -0
- package/dist/computer/connection-flow.d.ts +3 -3
- package/dist/computer/directory-http.d.ts +8 -0
- package/dist/computer/discovery.d.ts +13 -0
- package/dist/computer/lifecycle.d.ts +5 -1
- package/dist/computer/managed-relay.d.ts +27 -0
- package/dist/computer/oblien-auth.d.ts +25 -0
- package/dist/computer/provider-errors.d.ts +9 -0
- package/dist/computer/provider-info.d.ts +7 -0
- package/dist/computer/provider-setup.d.ts +20 -0
- package/dist/computer/relay-health.d.ts +22 -6
- package/dist/computer/relay.d.ts +11 -3
- package/dist/computer/setup-prompt.d.ts +9 -0
- package/dist/computer.d.ts +27 -1
- package/dist/connection-change-IBNL42BL.js +41 -0
- package/dist/connection-change-IBNL42BL.js.map +1 -0
- package/dist/{controller-QBC6L7AT.js → controller-2SJLZMJZ.js} +283 -290
- package/dist/controller-2SJLZMJZ.js.map +1 -0
- package/dist/{controller-handoff-NFDOLPJL.js → controller-handoff-RUUHODNC.js} +4 -4
- package/dist/{controller-handoff-NFDOLPJL.js.map → controller-handoff-RUUHODNC.js.map} +1 -1
- package/dist/index.cjs +12 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +12 -3
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/dist/binary-cache-VM7VHCEU.js +0 -4
- package/dist/chunk-3FR7BFAW.js.map +0 -1
- package/dist/chunk-H2I3VRBS.js.map +0 -1
- package/dist/controller-QBC6L7AT.js.map +0 -1
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type ComputerConfig } from "./lifecycle.js";
|
|
2
|
+
export interface ComputerConnectionChange {
|
|
3
|
+
id: string;
|
|
4
|
+
patch: Pick<Partial<ComputerConfig>, "relay" | "host">;
|
|
5
|
+
status: "queued" | "connecting" | "complete" | "failed";
|
|
6
|
+
message?: string;
|
|
7
|
+
}
|
|
8
|
+
/** The controller verifies a replacement before committing it. Parallel CLI
|
|
9
|
+
* invocations join the same settings change, or run one after the other. */
|
|
10
|
+
export declare function changeComputerConnection(directory: string, patch: ComputerConnectionChange["patch"], options?: {
|
|
11
|
+
signal?: AbortSignal;
|
|
12
|
+
onProgress?: (message: string) => void;
|
|
13
|
+
}): Promise<void>;
|
|
@@ -4,12 +4,12 @@ export declare function connectionAction(value: string | undefined): ConnectionA
|
|
|
4
4
|
/** Safe to copy into either a Unix shell or PowerShell, even when an ID starts
|
|
5
5
|
* with a dash. Validate old daemons too; these values originated on a phone. */
|
|
6
6
|
export declare function approvalCommand(pairingId: string, requestId: string): string;
|
|
7
|
-
/**
|
|
8
|
-
*
|
|
9
|
-
* or fresh approval. The old commands remain aliases, not separate UX paths. */
|
|
7
|
+
/** Stable endpoints need no new invitation after network loss or restart.
|
|
8
|
+
* An approval means ready to reconnect, never proof of current connectivity. */
|
|
10
9
|
export declare function chooseConnectionAction(options: {
|
|
11
10
|
requested?: ConnectionAction;
|
|
12
11
|
devices: ComputerDevice[];
|
|
12
|
+
persistent?: boolean;
|
|
13
13
|
}): Promise<ConnectionAction>;
|
|
14
14
|
/** A fresh key is never merged by name. Replacement requires the owner's explicit
|
|
15
15
|
* choice of the exact approvals shown here; a different same-name phone can be added. */
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare class DirectoryRequestError extends Error {
|
|
2
|
+
readonly status: number;
|
|
3
|
+
readonly code: string;
|
|
4
|
+
readonly retryAfter: number;
|
|
5
|
+
constructor(status: number, code: string, retryAfter?: number);
|
|
6
|
+
}
|
|
7
|
+
/** Bounded, same-origin requests. No redirects, cookie jar or retained credentials. */
|
|
8
|
+
export declare function directoryRequest<T>(url: string, path: string, body: unknown): Promise<T>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Mindwire } from "../client.js";
|
|
2
|
+
import type { ComputerDiscoveryStatus } from "../computer.js";
|
|
3
|
+
import type { SetupPrompt } from "./setup-prompt.js";
|
|
4
|
+
export declare const DIRECTORY_API_PATH = "/api/computer-directory/v1";
|
|
5
|
+
export declare const DIRECTORY_URL = "https://console.mindwire.sh/api/computer-directory/v1";
|
|
6
|
+
export declare function directoryURL(value: string): string;
|
|
7
|
+
export declare function enableAddressDiscovery(options: {
|
|
8
|
+
directory: string;
|
|
9
|
+
computer: Mindwire;
|
|
10
|
+
prompt: SetupPrompt;
|
|
11
|
+
url?: string;
|
|
12
|
+
}): Promise<ComputerDiscoveryStatus>;
|
|
13
|
+
export declare function discoveryDescription(status: ComputerDiscoveryStatus | undefined): string;
|
|
@@ -12,7 +12,7 @@ export interface ComputerConfig {
|
|
|
12
12
|
websocketPort: number;
|
|
13
13
|
relay: RelayOptions;
|
|
14
14
|
}
|
|
15
|
-
export declare const CONTROLLER_PROTOCOL =
|
|
15
|
+
export declare const CONTROLLER_PROTOCOL = 3;
|
|
16
16
|
export interface ControllerState extends ProcessState {
|
|
17
17
|
protocol?: number;
|
|
18
18
|
cliVersion?: string;
|
|
@@ -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,8 @@ 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;
|
|
40
|
+
waitForRoutes?: boolean;
|
|
37
41
|
}): Promise<Mindwire>;
|
|
38
42
|
export declare function superviseComputer(directory: string): Promise<void>;
|
|
39
43
|
export declare function stopComputer(directory: string, force?: boolean): Promise<void>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Oblien } from "oblien";
|
|
2
|
+
import { type RelayOptions } from "./relay.js";
|
|
3
|
+
export interface RelayWorkerConfig {
|
|
4
|
+
options: RelayOptions;
|
|
5
|
+
port: number;
|
|
6
|
+
}
|
|
7
|
+
interface TunnelToken {
|
|
8
|
+
token: string;
|
|
9
|
+
connect_url: string;
|
|
10
|
+
expires_at: string;
|
|
11
|
+
}
|
|
12
|
+
/** Cache only the short-lived broker token. Renew early without disconnecting a
|
|
13
|
+
* healthy carrier; a later reconnect uses the newest token for the same tunnel. */
|
|
14
|
+
export declare class OblienTunnelLease {
|
|
15
|
+
private readonly tunnelId;
|
|
16
|
+
private readonly client;
|
|
17
|
+
private readonly now;
|
|
18
|
+
private value?;
|
|
19
|
+
private pending?;
|
|
20
|
+
constructor(tunnelId: number, client: () => Promise<Oblien>, now?: () => number);
|
|
21
|
+
get(force?: boolean): Promise<TunnelToken>;
|
|
22
|
+
}
|
|
23
|
+
export declare function relayFailureMessage(error: unknown, provider: string): string;
|
|
24
|
+
/** A separate owned process survives controller updates just like cloudflared.
|
|
25
|
+
* It does not own the daemon, terminals, identity, or phone authorization. */
|
|
26
|
+
export declare function runManagedRelay(file: string): Promise<void>;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Oblien } from "oblien";
|
|
2
|
+
import type { SetupPrompt } from "./setup-prompt.js";
|
|
3
|
+
export interface OblienCredentials {
|
|
4
|
+
token?: string;
|
|
5
|
+
clientId?: string;
|
|
6
|
+
clientSecret?: string;
|
|
7
|
+
baseUrl?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class ProviderSignInRequired extends Error {
|
|
10
|
+
readonly code = "provider_sign_in";
|
|
11
|
+
constructor(provider?: string);
|
|
12
|
+
}
|
|
13
|
+
export declare function tokenExpiry(token: string): number | undefined;
|
|
14
|
+
export declare function oblienClient(credentials: OblienCredentials): Oblien;
|
|
15
|
+
/** The SDK's resource methods share this transport but do not yet accept a
|
|
16
|
+
* timeout. Bound every request, including tunnel creation and token renewal,
|
|
17
|
+
* without bypassing the official resource API or retrying mutations. */
|
|
18
|
+
export declare function boundedOblienClient(client: Oblien, timeoutMs?: number): Oblien;
|
|
19
|
+
/** Auth is not yet a public SDK resource. Use the SDK's authenticated transport
|
|
20
|
+
* for the documented browser-session endpoints; all tunnel calls use edgeTunnel. */
|
|
21
|
+
export declare function authenticatedOblien(file: string, options?: {
|
|
22
|
+
now?: () => number;
|
|
23
|
+
client?: typeof oblienClient;
|
|
24
|
+
}): Promise<Oblien>;
|
|
25
|
+
export declare function signInOblien(file: string, prompt: SetupPrompt): Promise<Oblien>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type ProviderErrorCode = "provider_sign_in" | "provider_limit" | "provider_missing" | "provider_certificate" | "provider_configuration" | "provider_connection";
|
|
2
|
+
export declare class ProviderConnectionError extends Error {
|
|
3
|
+
readonly code: ProviderErrorCode;
|
|
4
|
+
constructor(code: ProviderErrorCode, message: string);
|
|
5
|
+
}
|
|
6
|
+
export declare function providerNeedsAction(code: string | undefined): boolean;
|
|
7
|
+
/** Inspect transport causes, but never forward their raw text or headers. */
|
|
8
|
+
export declare function hasCertificateError(error: unknown): boolean;
|
|
9
|
+
export declare function providerFailure(error: unknown, provider: string): ProviderConnectionError;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ComputerConnectionInfo } from "../computer.js";
|
|
2
|
+
import type { RelayOptions } from "./relay.js";
|
|
3
|
+
/** Credential renewal does not change the address already saved by the phone. */
|
|
4
|
+
export declare function connectionAddress(relay: RelayOptions, host?: string): string;
|
|
5
|
+
/** Public, non-secret metadata. Route/SSH identity is independent of provider credentials. */
|
|
6
|
+
export declare function connectionInfo(relay: RelayOptions, host?: string): ComputerConnectionInfo;
|
|
7
|
+
export declare function connectionDescription(info: ComputerConnectionInfo): string;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Oblien } from "oblien";
|
|
2
|
+
import { type ComputerConfig } from "./lifecycle.js";
|
|
3
|
+
import type { SetupPrompt } from "./setup-prompt.js";
|
|
4
|
+
export type ConnectionProvider = "oblien" | "cloudflare" | "ngrok" | "vpn" | "custom" | "temporary" | "automatic";
|
|
5
|
+
export declare function chooseProvider(prompt: SetupPrompt): Promise<ConnectionProvider>;
|
|
6
|
+
export declare function connectionProvider(value: string): ConnectionProvider;
|
|
7
|
+
export declare function providerHostname(value: string): string;
|
|
8
|
+
/** No port-based account-wide reuse: two computers commonly use the same port. */
|
|
9
|
+
export declare function prepareOblienTunnel(client: Oblien, stateFile: string, port: number): Promise<{
|
|
10
|
+
id: number;
|
|
11
|
+
url: string;
|
|
12
|
+
}>;
|
|
13
|
+
/** Setup is explicit and serialized. Background startup only consumes the saved
|
|
14
|
+
* result: it never opens a browser, changes provider, or creates another tunnel. */
|
|
15
|
+
export declare function setupProvider(options: {
|
|
16
|
+
directory: string;
|
|
17
|
+
provider: ConnectionProvider;
|
|
18
|
+
prompt: SetupPrompt;
|
|
19
|
+
config?: ComputerConfig;
|
|
20
|
+
}): Promise<Partial<ComputerConfig>>;
|
|
@@ -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
|
-
readonly code: "dns" | "timeout" | "proxy" | "connection" | "response";
|
|
6
|
-
|
|
5
|
+
readonly code: "dns" | "timeout" | "proxy" | "connection" | "response" | "provider_certificate";
|
|
6
|
+
readonly addressMissing: boolean;
|
|
7
|
+
constructor(code: "dns" | "timeout" | "proxy" | "connection" | "response" | "provider_certificate", 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 {};
|
package/dist/computer/relay.d.ts
CHANGED
|
@@ -2,25 +2,33 @@ import { type ChildProcess } from "node:child_process";
|
|
|
2
2
|
import type { ComputerRoute } from "../computer.js";
|
|
3
3
|
import { type OwnedProcess } from "./process.js";
|
|
4
4
|
export interface RelayOptions {
|
|
5
|
-
kind: "none" | "cloudflare" | "ngrok" | "custom";
|
|
5
|
+
kind: "none" | "oblien" | "cloudflare" | "ngrok" | "custom";
|
|
6
6
|
/** A stable, already configured hostname; custom relays must forward WebSocket upgrades. */
|
|
7
7
|
url?: string;
|
|
8
8
|
cloudflareTokenFile?: string;
|
|
9
|
+
cloudflareTunnelId?: string;
|
|
10
|
+
cloudflareCredentialsFile?: string;
|
|
11
|
+
ngrokTokenFile?: string;
|
|
12
|
+
oblienTunnelId?: number;
|
|
13
|
+
oblienCredentialsFile?: string;
|
|
9
14
|
}
|
|
10
15
|
export interface RelayHandle {
|
|
11
16
|
route?: ComputerRoute;
|
|
12
17
|
process?: ChildProcess;
|
|
13
18
|
owner?: OwnedProcess;
|
|
14
19
|
outputFile?: string;
|
|
20
|
+
configFile?: string;
|
|
15
21
|
close(): void | Promise<void>;
|
|
16
22
|
}
|
|
17
|
-
export declare function adoptRelay(owner: OwnedProcess, route: ComputerRoute | undefined, directory: string, outputFile?: string): Promise<RelayHandle>;
|
|
23
|
+
export declare function adoptRelay(owner: OwnedProcess, route: ComputerRoute | undefined, directory: string, outputFile?: string, configFile?: string): Promise<RelayHandle>;
|
|
18
24
|
export declare function websocketURL(value: string): string;
|
|
25
|
+
export declare function validateRelayOptions(options: RelayOptions): void;
|
|
19
26
|
/** Both providers forward encrypted SSH bytes to one loopback WebSocket bridge. */
|
|
20
27
|
export declare function startRelay(options: RelayOptions, port: number, runtime?: {
|
|
21
28
|
cacheDir?: string;
|
|
22
29
|
outputDirectory?: string;
|
|
30
|
+
cliPath?: string;
|
|
23
31
|
onProgress?: (message: string) => void | Promise<void>;
|
|
24
32
|
signal?: AbortSignal;
|
|
25
|
-
onSpawn?: (owner: OwnedProcess, outputFile: string) => Promise<void>;
|
|
33
|
+
onSpawn?: (owner: OwnedProcess, outputFile: string, configFile?: string) => Promise<void>;
|
|
26
34
|
}): Promise<RelayHandle>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface SetupPrompt {
|
|
2
|
+
question(text: string): Promise<string>;
|
|
3
|
+
secret(text: string): Promise<string>;
|
|
4
|
+
print(text: string): void;
|
|
5
|
+
open(url: string): void;
|
|
6
|
+
}
|
|
7
|
+
/** No shell interpolation, even for a URL returned by a provider. */
|
|
8
|
+
export declare function openSetupURL(value: string): void;
|
|
9
|
+
export declare const terminalSetupPrompt: SetupPrompt;
|
package/dist/computer.d.ts
CHANGED
|
@@ -7,6 +7,10 @@ export type ComputerRoute = {
|
|
|
7
7
|
kind: "websocket";
|
|
8
8
|
url: string;
|
|
9
9
|
};
|
|
10
|
+
export interface ComputerConnectionInfo {
|
|
11
|
+
provider: "oblien" | "cloudflare" | "ngrok" | "custom" | "direct";
|
|
12
|
+
address: "persistent" | "temporary" | "network";
|
|
13
|
+
}
|
|
10
14
|
export interface ComputerInvitation {
|
|
11
15
|
version: 1;
|
|
12
16
|
computerId: string;
|
|
@@ -37,6 +41,23 @@ export interface ComputerDevice {
|
|
|
37
41
|
createdAt: string;
|
|
38
42
|
revoked: boolean;
|
|
39
43
|
connected?: boolean;
|
|
44
|
+
/** This phone acknowledged securely saving its address-discovery key. */
|
|
45
|
+
addressRecovery?: boolean;
|
|
46
|
+
}
|
|
47
|
+
export interface ComputerDiscoveryStatus {
|
|
48
|
+
version: 1;
|
|
49
|
+
enabled: boolean;
|
|
50
|
+
directoryId: string;
|
|
51
|
+
url?: string;
|
|
52
|
+
sequence?: number;
|
|
53
|
+
publishedSequence?: number;
|
|
54
|
+
publishedAt?: number;
|
|
55
|
+
error?: string;
|
|
56
|
+
}
|
|
57
|
+
export interface ComputerDirectoryEnvelope {
|
|
58
|
+
publicKey: string;
|
|
59
|
+
payload: string;
|
|
60
|
+
signature: string;
|
|
40
61
|
}
|
|
41
62
|
/** Signature is a base64 Ed25519 proof over
|
|
42
63
|
* `mindwire-computer-pairing-v1\n${pairingId}\n${id}\n${name}\n${publicKey}`.
|
|
@@ -79,6 +100,8 @@ export interface ComputerInfo {
|
|
|
79
100
|
/** 2 supports signed reconnection and atomic replacement of lost device keys.
|
|
80
101
|
* 3 requires signed pairing acknowledgements and expires/revokes pairing transports. */
|
|
81
102
|
pairingVersion?: number;
|
|
103
|
+
connection?: ComputerConnectionInfo;
|
|
104
|
+
discovery?: ComputerDiscoveryStatus;
|
|
82
105
|
}
|
|
83
106
|
export interface ComputerForwardRequest {
|
|
84
107
|
id: string;
|
|
@@ -93,7 +116,10 @@ export declare class ComputerApi {
|
|
|
93
116
|
private readonly client;
|
|
94
117
|
constructor(client: Mindwire);
|
|
95
118
|
info(): Promise<ComputerInfo>;
|
|
96
|
-
|
|
119
|
+
discovery(): Promise<ComputerDiscoveryStatus>;
|
|
120
|
+
configureDiscovery(enabled: boolean, url?: string): Promise<ComputerDiscoveryStatus>;
|
|
121
|
+
directoryEnrollment(url: string, challenge: string): Promise<ComputerDirectoryEnvelope>;
|
|
122
|
+
setRoutes(routes: ComputerRoute[], connection?: ComputerConnectionInfo): Promise<ComputerInfo>;
|
|
97
123
|
updateStatus(): Promise<ComputerUpdate>;
|
|
98
124
|
/** Automatic requests wait for idle. With serviceUpdateVersion >= 2, force
|
|
99
125
|
* promotes the same active request to an explicit restart without re-downloading. */
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { acquireProcessLock, readJSON, writeJSON } from './chunk-RTGZDLSG.js';
|
|
2
|
+
import './chunk-PFYKJ6LX.js';
|
|
3
|
+
import { randomUUID } from 'crypto';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import { setTimeout } from 'timers/promises';
|
|
6
|
+
|
|
7
|
+
async function changeComputerConnection(directory, patch, options = {}) {
|
|
8
|
+
const lock = await acquireProcessLock(path.join(directory, "connection-change.lock"), { signal: options.signal });
|
|
9
|
+
const file = path.join(directory, "computer-connection-change.json");
|
|
10
|
+
try {
|
|
11
|
+
const saved = await readJSON(path.join(directory, "computer-config.json"));
|
|
12
|
+
if (Object.entries(patch).every(([key, value]) => JSON.stringify(saved?.[key]) === JSON.stringify(value))) return;
|
|
13
|
+
const previous = await readJSON(file);
|
|
14
|
+
if (previous && ["queued", "connecting"].includes(previous.status) && JSON.stringify(previous.patch) !== JSON.stringify(patch)) {
|
|
15
|
+
throw new Error("Another connection change is still running. Run mindwire status, then retry.");
|
|
16
|
+
}
|
|
17
|
+
const request = previous && ["queued", "connecting"].includes(previous.status) ? previous : { id: randomUUID(), patch, status: "queued" };
|
|
18
|
+
await writeJSON(file, request);
|
|
19
|
+
let message;
|
|
20
|
+
const deadline = Date.now() + 13e4;
|
|
21
|
+
while (Date.now() < deadline) {
|
|
22
|
+
options.signal?.throwIfAborted();
|
|
23
|
+
const current = await readJSON(file);
|
|
24
|
+
if (current?.id !== request.id) throw new Error("The connection change was replaced. Run mindwire status.");
|
|
25
|
+
if (current.status === "complete") return;
|
|
26
|
+
if (current.status === "failed") throw new Error(current.message ?? "Connection setup failed. The previous connection is unchanged.");
|
|
27
|
+
if (current.message && message !== current.message) {
|
|
28
|
+
message = current.message;
|
|
29
|
+
options.onProgress?.(message);
|
|
30
|
+
}
|
|
31
|
+
await setTimeout(250, void 0, { signal: options.signal });
|
|
32
|
+
}
|
|
33
|
+
throw new Error("Connection setup is still running in the background. Run mindwire status for its result.");
|
|
34
|
+
} finally {
|
|
35
|
+
await lock?.close();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export { changeComputerConnection };
|
|
40
|
+
//# sourceMappingURL=connection-change-IBNL42BL.js.map
|
|
41
|
+
//# sourceMappingURL=connection-change-IBNL42BL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/computer/connection-change.ts"],"names":["delay"],"mappings":";;;;;;AAeA,eAAsB,wBAAA,CAAyB,SAAA,EAAmB,KAAA,EAA0C,OAAA,GAExG,EAAC,EAAkB;AACrB,EAAA,MAAM,IAAA,GAAO,MAAM,kBAAA,CAAwB,IAAA,CAAA,IAAA,CAAK,SAAA,EAAW,wBAAwB,CAAA,EAAG,EAAE,MAAA,EAAQ,OAAA,CAAQ,MAAA,EAAQ,CAAA;AAChH,EAAA,MAAM,IAAA,GAAY,IAAA,CAAA,IAAA,CAAK,SAAA,EAAW,iCAAiC,CAAA;AACnE,EAAA,IAAI;AACF,IAAA,MAAM,QAAQ,MAAM,QAAA,CAA8B,IAAA,CAAA,IAAA,CAAK,SAAA,EAAW,sBAAsB,CAAC,CAAA;AACzF,IAAA,IAAI,MAAA,CAAO,QAAQ,KAAK,CAAA,CAAE,MAAM,CAAC,CAAC,KAAK,KAAK,CAAA,KAAM,KAAK,SAAA,CAAU,KAAA,GAAQ,GAA2B,CAAC,CAAA,KAAM,KAAK,SAAA,CAAU,KAAK,CAAC,CAAA,EAAG;AACnI,IAAA,MAAM,QAAA,GAAW,MAAM,QAAA,CAAmC,IAAI,CAAA;AAC9D,IAAA,IAAI,YAAY,CAAC,QAAA,EAAU,YAAY,CAAA,CAAE,SAAS,QAAA,CAAS,MAAM,CAAA,IAAK,IAAA,CAAK,UAAU,QAAA,CAAS,KAAK,MAAM,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,EAAG;AAC9H,MAAA,MAAM,IAAI,MAAM,8EAA8E,CAAA;AAAA,IAChG;AACA,IAAA,MAAM,UAAU,QAAA,IAAY,CAAC,QAAA,EAAU,YAAY,EAAE,QAAA,CAAS,QAAA,CAAS,MAAM,CAAA,GAAI,WAC7E,EAAE,EAAA,EAAI,YAAW,EAAG,KAAA,EAAO,QAAQ,QAAA,EAAkB;AACzD,IAAA,MAAM,SAAA,CAAU,MAAM,OAAO,CAAA;AAC7B,IAAA,IAAI,OAAA;AACJ,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,EAAI,GAAI,IAAA;AAC9B,IAAA,OAAO,IAAA,CAAK,GAAA,EAAI,GAAI,QAAA,EAAU;AAC5B,MAAA,OAAA,CAAQ,QAAQ,cAAA,EAAe;AAC/B,MAAA,MAAM,OAAA,GAAU,MAAM,QAAA,CAAmC,IAAI,CAAA;AAC7D,MAAA,IAAI,SAAS,EAAA,KAAO,OAAA,CAAQ,IAAI,MAAM,IAAI,MAAM,0DAA0D,CAAA;AAC1G,MAAA,IAAI,OAAA,CAAQ,WAAW,UAAA,EAAY;AACnC,MAAA,IAAI,OAAA,CAAQ,WAAW,QAAA,EAAU,MAAM,IAAI,KAAA,CAAM,OAAA,CAAQ,WAAW,gEAAgE,CAAA;AACpI,MAAA,IAAI,OAAA,CAAQ,OAAA,IAAW,OAAA,KAAY,OAAA,CAAQ,OAAA,EAAS;AAAE,QAAA,OAAA,GAAU,OAAA,CAAQ,OAAA;AAAS,QAAA,OAAA,CAAQ,aAAa,OAAO,CAAA;AAAA,MAAG;AAChH,MAAA,MAAMA,WAAM,GAAA,EAAK,KAAA,CAAA,EAAW,EAAE,MAAA,EAAQ,OAAA,CAAQ,QAAQ,CAAA;AAAA,IACxD;AACA,IAAA,MAAM,IAAI,MAAM,0FAA0F,CAAA;AAAA,EAC5G,CAAA,SAAE;AAAU,IAAA,MAAM,MAAM,KAAA,EAAM;AAAA,EAAG;AACnC","file":"connection-change-IBNL42BL.js","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport * as path from \"node:path\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport { acquireProcessLock } from \"./lock.js\";\nimport { readJSON, writeJSON, type ComputerConfig } from \"./lifecycle.js\";\n\nexport interface ComputerConnectionChange {\n id: string;\n patch: Pick<Partial<ComputerConfig>, \"relay\" | \"host\">;\n status: \"queued\" | \"connecting\" | \"complete\" | \"failed\";\n message?: string;\n}\n\n/** The controller verifies a replacement before committing it. Parallel CLI\n * invocations join the same settings change, or run one after the other. */\nexport async function changeComputerConnection(directory: string, patch: ComputerConnectionChange[\"patch\"], options: {\n signal?: AbortSignal; onProgress?: (message: string) => void;\n} = {}): Promise<void> {\n const lock = await acquireProcessLock(path.join(directory, \"connection-change.lock\"), { signal: options.signal });\n const file = path.join(directory, \"computer-connection-change.json\");\n try {\n const saved = await readJSON<ComputerConfig>(path.join(directory, \"computer-config.json\"));\n if (Object.entries(patch).every(([key, value]) => JSON.stringify(saved?.[key as keyof ComputerConfig]) === JSON.stringify(value))) return;\n const previous = await readJSON<ComputerConnectionChange>(file);\n if (previous && [\"queued\", \"connecting\"].includes(previous.status) && JSON.stringify(previous.patch) !== JSON.stringify(patch)) {\n throw new Error(\"Another connection change is still running. Run mindwire status, then retry.\");\n }\n const request = previous && [\"queued\", \"connecting\"].includes(previous.status) ? previous\n : { id: randomUUID(), patch, status: \"queued\" as const };\n await writeJSON(file, request);\n let message: string | undefined;\n const deadline = Date.now() + 130_000;\n while (Date.now() < deadline) {\n options.signal?.throwIfAborted();\n const current = await readJSON<ComputerConnectionChange>(file);\n if (current?.id !== request.id) throw new Error(\"The connection change was replaced. Run mindwire status.\");\n if (current.status === \"complete\") return;\n if (current.status === \"failed\") throw new Error(current.message ?? \"Connection setup failed. The previous connection is unchanged.\");\n if (current.message && message !== current.message) { message = current.message; options.onProgress?.(message); }\n await delay(250, undefined, { signal: options.signal });\n }\n throw new Error(\"Connection setup is still running in the background. Run mindwire status for its result.\");\n } finally { await lock?.close(); }\n}\n"]}
|