@limrun/api 0.59.0 → 0.60.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/CHANGELOG.md +63 -0
- package/destination-tunnel-dialer.d.mts +7 -0
- package/destination-tunnel-dialer.d.mts.map +1 -1
- package/destination-tunnel-dialer.d.ts +7 -0
- package/destination-tunnel-dialer.d.ts.map +1 -1
- package/destination-tunnel-dialer.js +15 -4
- package/destination-tunnel-dialer.js.map +1 -1
- package/destination-tunnel-dialer.mjs +13 -3
- package/destination-tunnel-dialer.mjs.map +1 -1
- package/destination-tunnel.d.mts +4 -0
- package/destination-tunnel.d.mts.map +1 -1
- package/destination-tunnel.d.ts +4 -0
- package/destination-tunnel.d.ts.map +1 -1
- package/destination-tunnel.js +2 -0
- package/destination-tunnel.js.map +1 -1
- package/destination-tunnel.mjs +2 -0
- package/destination-tunnel.mjs.map +1 -1
- package/index.d.mts +1 -0
- package/index.d.mts.map +1 -1
- package/index.d.ts +1 -0
- package/index.d.ts.map +1 -1
- package/index.js +4 -2
- package/index.js.map +1 -1
- package/index.mjs +1 -0
- package/index.mjs.map +1 -1
- package/internal/destination-tunnel-management.d.mts +2 -0
- package/internal/destination-tunnel-management.d.mts.map +1 -1
- package/internal/destination-tunnel-management.d.ts +2 -0
- package/internal/destination-tunnel-management.d.ts.map +1 -1
- package/internal/destination-tunnel-management.js +5 -0
- package/internal/destination-tunnel-management.js.map +1 -1
- package/internal/destination-tunnel-management.mjs +6 -1
- package/internal/destination-tunnel-management.mjs.map +1 -1
- package/internal/destination-tunnel-url.d.mts +2 -0
- package/internal/destination-tunnel-url.d.mts.map +1 -1
- package/internal/destination-tunnel-url.d.ts +2 -0
- package/internal/destination-tunnel-url.d.ts.map +1 -1
- package/internal/destination-tunnel-url.js +9 -2
- package/internal/destination-tunnel-url.js.map +1 -1
- package/internal/destination-tunnel-url.mjs +8 -2
- package/internal/destination-tunnel-url.mjs.map +1 -1
- package/ios-client.d.mts +6 -4
- package/ios-client.d.mts.map +1 -1
- package/ios-client.d.ts +6 -4
- package/ios-client.d.ts.map +1 -1
- package/ios-client.js +3 -1
- package/ios-client.js.map +1 -1
- package/ios-client.mjs +3 -1
- package/ios-client.mjs.map +1 -1
- package/ios-launch-environment.d.mts +3 -0
- package/ios-launch-environment.d.mts.map +1 -0
- package/ios-launch-environment.d.ts +3 -0
- package/ios-launch-environment.d.ts.map +1 -0
- package/ios-launch-environment.js +14 -0
- package/ios-launch-environment.js.map +1 -0
- package/ios-launch-environment.mjs +11 -0
- package/ios-launch-environment.mjs.map +1 -0
- package/package.json +22 -2
- package/resources/android-instances.d.mts +12 -0
- package/resources/android-instances.d.mts.map +1 -1
- package/resources/android-instances.d.ts +12 -0
- package/resources/android-instances.d.ts.map +1 -1
- package/resources/ios-instances.d.mts +12 -0
- package/resources/ios-instances.d.mts.map +1 -1
- package/resources/ios-instances.d.ts +12 -0
- package/resources/ios-instances.d.ts.map +1 -1
- package/src/destination-tunnel-dialer.ts +18 -3
- package/src/destination-tunnel.ts +6 -0
- package/src/index.ts +6 -0
- package/src/internal/destination-tunnel-management.ts +15 -1
- package/src/internal/destination-tunnel-url.ts +15 -2
- package/src/ios-client.ts +12 -5
- package/src/ios-launch-environment.ts +11 -0
- package/src/resources/android-instances.ts +14 -0
- package/src/resources/ios-instances.ts +14 -0
- package/src/tunnel-connector.ts +677 -0
- package/src/tunnel.ts +8 -6
- package/src/version.ts +1 -1
- package/tunnel-connector.d.mts +77 -0
- package/tunnel-connector.d.mts.map +1 -0
- package/tunnel-connector.d.ts +77 -0
- package/tunnel-connector.d.ts.map +1 -0
- package/tunnel-connector.js +561 -0
- package/tunnel-connector.js.map +1 -0
- package/tunnel-connector.mjs +557 -0
- package/tunnel-connector.mjs.map +1 -0
- package/tunnel.d.mts +2 -0
- package/tunnel.d.mts.map +1 -1
- package/tunnel.d.ts +2 -0
- package/tunnel.d.ts.map +1 -1
- package/tunnel.js +8 -6
- package/tunnel.js.map +1 -1
- package/tunnel.mjs +7 -6
- package/tunnel.mjs.map +1 -1
- package/version.d.mts +1 -1
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/version.mjs +1 -1
|
@@ -136,6 +136,8 @@ export type DestinationTunnelClientMessage =
|
|
|
136
136
|
inspection: DestinationTunnelInspectionConfig;
|
|
137
137
|
/** Default per-flow receive window this client grants. */
|
|
138
138
|
window: number;
|
|
139
|
+
/** Persistent tunnel this session serves. The instance only echoes it in status. */
|
|
140
|
+
name?: string;
|
|
139
141
|
}
|
|
140
142
|
| {
|
|
141
143
|
type: 'openOk';
|
|
@@ -160,6 +162,8 @@ export type DestinationTunnelServerMessage =
|
|
|
160
162
|
tunnelId: string;
|
|
161
163
|
selectors: DestinationTunnelSelectorReport[];
|
|
162
164
|
configHash: string;
|
|
165
|
+
/** The persistent tunnel name the client sent in start, echoed back. */
|
|
166
|
+
name?: string;
|
|
163
167
|
}
|
|
164
168
|
| {
|
|
165
169
|
type: 'open';
|
|
@@ -466,6 +470,7 @@ export function encodeDestinationTunnelClientMessage(message: DestinationTunnelC
|
|
|
466
470
|
selectors,
|
|
467
471
|
inspection,
|
|
468
472
|
window: readWindow(record),
|
|
473
|
+
...readOptionalString(record, 'name'),
|
|
469
474
|
});
|
|
470
475
|
}
|
|
471
476
|
case 'openOk':
|
|
@@ -510,6 +515,7 @@ export function decodeDestinationTunnelServerMessage(value: unknown): Destinatio
|
|
|
510
515
|
readSelectorReport(value, `selector-${index + 1}`),
|
|
511
516
|
),
|
|
512
517
|
configHash: readString(message, 'configHash'),
|
|
518
|
+
...readOptionalString(message, 'name'),
|
|
513
519
|
};
|
|
514
520
|
case 'open':
|
|
515
521
|
return {
|
package/src/index.ts
CHANGED
|
@@ -13,6 +13,12 @@ export {
|
|
|
13
13
|
type DestinationTcpTunnel,
|
|
14
14
|
type DestinationTcpTunnelOptions,
|
|
15
15
|
} from './destination-tunnel-dialer';
|
|
16
|
+
export {
|
|
17
|
+
runTunnel,
|
|
18
|
+
type TunnelConnector,
|
|
19
|
+
type TunnelConnectorEvent,
|
|
20
|
+
type TunnelConnectorOptions,
|
|
21
|
+
} from './tunnel-connector';
|
|
16
22
|
export {
|
|
17
23
|
decodeDestinationTunnelInspectionSSEEvent,
|
|
18
24
|
deriveDestinationTunnelInspectionURL,
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { nodeProxyTransport } from './proxy-transport';
|
|
2
2
|
import { deriveDestinationTunnelStatusURL, deriveDestinationTunnelStopURL } from './destination-tunnel-url';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
readArray,
|
|
5
|
+
readNonEmptyString,
|
|
6
|
+
readOptionalString,
|
|
7
|
+
readRecord,
|
|
8
|
+
readString,
|
|
9
|
+
} from './destination-tunnel-wire-reader';
|
|
4
10
|
import {
|
|
5
11
|
normalizeDestinationTunnelInspection,
|
|
6
12
|
type DestinationTunnelBindReport,
|
|
@@ -11,6 +17,8 @@ import {
|
|
|
11
17
|
export interface DestinationTunnelStatus {
|
|
12
18
|
active?: {
|
|
13
19
|
tunnelId: string;
|
|
20
|
+
/** Persistent tunnel the session serves, absent for a one-instance tunnel. */
|
|
21
|
+
name?: string;
|
|
14
22
|
state: 'starting' | 'ready' | 'stopping';
|
|
15
23
|
selectors: DestinationTunnelSelectorReport[];
|
|
16
24
|
inspection: DestinationTunnelInspectionConfig;
|
|
@@ -28,12 +36,16 @@ export interface DestinationTunnelStatus {
|
|
|
28
36
|
};
|
|
29
37
|
}
|
|
30
38
|
|
|
39
|
+
/** Status and stop answer at once; a wedged instance must not hold its caller for minutes. */
|
|
40
|
+
const MANAGEMENT_TIMEOUT_MS = 10_000;
|
|
41
|
+
|
|
31
42
|
export async function getDestinationTunnelStatus(
|
|
32
43
|
apiUrl: string,
|
|
33
44
|
token: string,
|
|
34
45
|
): Promise<DestinationTunnelStatus> {
|
|
35
46
|
const response = await nodeProxyTransport.fetch(deriveDestinationTunnelStatusURL(apiUrl).toString(), {
|
|
36
47
|
headers: { Authorization: `Bearer ${token}` },
|
|
48
|
+
signal: AbortSignal.timeout(MANAGEMENT_TIMEOUT_MS),
|
|
37
49
|
});
|
|
38
50
|
if (!response.ok) {
|
|
39
51
|
throw new Error(`getTunnelStatus failed: ${response.status} ${await response.text()}`);
|
|
@@ -50,6 +62,7 @@ export async function stopDestinationTunnel(apiUrl: string, token: string, tunne
|
|
|
50
62
|
{
|
|
51
63
|
method: 'DELETE',
|
|
52
64
|
headers: { Authorization: `Bearer ${token}` },
|
|
65
|
+
signal: AbortSignal.timeout(MANAGEMENT_TIMEOUT_MS),
|
|
53
66
|
},
|
|
54
67
|
);
|
|
55
68
|
if (!response.ok) {
|
|
@@ -80,6 +93,7 @@ function readActiveTunnel(value: unknown): NonNullable<DestinationTunnelStatus['
|
|
|
80
93
|
}
|
|
81
94
|
return {
|
|
82
95
|
tunnelId: readNonEmptyString(active, 'tunnelId'),
|
|
96
|
+
...readOptionalString(active, 'name'),
|
|
83
97
|
state,
|
|
84
98
|
selectors: readArray(active, 'selectors').map((selector, index) =>
|
|
85
99
|
readSelectorReport(selector, `selector-${index + 1}`),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** The endpoint at `path` under
|
|
1
|
+
/** The endpoint at `path` under a base URL, without query or fragment. */
|
|
2
2
|
function deriveEndpointURL(apiUrl: string, path: string): URL {
|
|
3
3
|
const url = new URL(apiUrl);
|
|
4
4
|
if (
|
|
@@ -26,7 +26,20 @@ export function deriveAdbHttpURL(adbUrl: string, path: string): URL {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
export function deriveDestinationTunnelURL(apiUrl: string): string {
|
|
29
|
-
|
|
29
|
+
return webSocketURL(deriveEndpointURL(apiUrl, 'tunnel'));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** The control WebSocket of a persistent tunnel, under the Limrun API base URL. */
|
|
33
|
+
export function deriveTunnelConnectURL(baseURL: string, organizationId: string, name: string): string {
|
|
34
|
+
return webSocketURL(
|
|
35
|
+
deriveEndpointURL(
|
|
36
|
+
baseURL,
|
|
37
|
+
`v1/organizations/${encodeURIComponent(organizationId)}/tunnels/${encodeURIComponent(name)}/connect`,
|
|
38
|
+
),
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function webSocketURL(url: URL): string {
|
|
30
43
|
url.protocol = url.protocol === 'https:' || url.protocol === 'wss:' ? 'wss:' : 'ws:';
|
|
31
44
|
return url.toString();
|
|
32
45
|
}
|
package/src/ios-client.ts
CHANGED
|
@@ -450,21 +450,23 @@ export type AppWatch = {
|
|
|
450
450
|
stop: () => Promise<void>;
|
|
451
451
|
};
|
|
452
452
|
|
|
453
|
-
type
|
|
453
|
+
type LaunchAppCommonOptions = {
|
|
454
|
+
/** App environment variables. Requires relaunch; reserved keys and existing launch variables are ignored. */
|
|
455
|
+
env?: Record<string, string>;
|
|
454
456
|
/** Called once when the launched app exits, crashes, or is terminated. */
|
|
455
457
|
onExit?: LaunchAppExitCallback;
|
|
456
458
|
};
|
|
457
459
|
|
|
458
|
-
type StandardLaunchAppOptions =
|
|
460
|
+
type StandardLaunchAppOptions = LaunchAppCommonOptions & {
|
|
459
461
|
/**
|
|
460
462
|
* Launch behavior when the app may already be running.
|
|
461
|
-
* Defaults to `ForegroundIfRunning`
|
|
463
|
+
* Defaults to `ForegroundIfRunning`, or `RelaunchIfRunning` when env is nonempty.
|
|
462
464
|
*/
|
|
463
465
|
mode?: LaunchAppMode;
|
|
464
466
|
runtime?: undefined;
|
|
465
467
|
};
|
|
466
468
|
|
|
467
|
-
type RuntimeLaunchAppOptions =
|
|
469
|
+
type RuntimeLaunchAppOptions = LaunchAppCommonOptions & {
|
|
468
470
|
/** Runtime launches must relaunch so runtime injection is applied. */
|
|
469
471
|
mode?: Extract<LaunchAppMode, 'RelaunchIfRunning'>;
|
|
470
472
|
/** Optional app runtime to attach during launch. */
|
|
@@ -2368,7 +2370,11 @@ export async function createInstanceClient(options: InstanceClientOptions): Prom
|
|
|
2368
2370
|
new Error('launchApp runtime launches require RelaunchIfRunning so runtime injection is applied.'),
|
|
2369
2371
|
);
|
|
2370
2372
|
}
|
|
2371
|
-
const
|
|
2373
|
+
const hasEnvironment = Object.keys(launchOptions.env ?? {}).length > 0;
|
|
2374
|
+
const mode =
|
|
2375
|
+
launchOptions.runtime ? 'RelaunchIfRunning' : (
|
|
2376
|
+
launchOptions.mode ?? (hasEnvironment ? 'RelaunchIfRunning' : undefined)
|
|
2377
|
+
);
|
|
2372
2378
|
const onExit = launchOptions.onExit;
|
|
2373
2379
|
const execId = onExit ? generateId() : undefined;
|
|
2374
2380
|
if (execId && onExit) {
|
|
@@ -2378,6 +2384,7 @@ export async function createInstanceClient(options: InstanceClientOptions): Prom
|
|
|
2378
2384
|
bundleId,
|
|
2379
2385
|
mode,
|
|
2380
2386
|
runtime: launchOptions.runtime,
|
|
2387
|
+
env: launchOptions.env,
|
|
2381
2388
|
execId,
|
|
2382
2389
|
}).catch((error) => {
|
|
2383
2390
|
if (execId) {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Parse repeatable KEY=VALUE entries; the last occurrence of a key wins. */
|
|
2
|
+
export function parseLaunchEnvironment(entries: string[]): Record<string, string> {
|
|
3
|
+
const env = Object.fromEntries(
|
|
4
|
+
entries.map((entry) => {
|
|
5
|
+
const separator = entry.indexOf('=');
|
|
6
|
+
if (separator < 1) throw new Error('launch environment must use KEY=VALUE');
|
|
7
|
+
return [entry.slice(0, separator), entry.slice(separator + 1)];
|
|
8
|
+
}),
|
|
9
|
+
);
|
|
10
|
+
return env;
|
|
11
|
+
}
|
|
@@ -88,6 +88,13 @@ export namespace AndroidInstance {
|
|
|
88
88
|
* 10m, 3h. Default is "0" which means no hard timeout.
|
|
89
89
|
*/
|
|
90
90
|
hardTimeout?: string;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Names a persistent tunnel (`lim tunnel run --name`) that serves this
|
|
94
|
+
* instance. Creation fails while that tunnel is offline, and the instance
|
|
95
|
+
* becomes ready only after the tunnel attaches.
|
|
96
|
+
*/
|
|
97
|
+
tunnel?: string;
|
|
91
98
|
}
|
|
92
99
|
|
|
93
100
|
export interface Status {
|
|
@@ -241,6 +248,13 @@ export namespace AndroidInstanceCreateParams {
|
|
|
241
248
|
region?: string;
|
|
242
249
|
|
|
243
250
|
sandbox?: Spec.Sandbox;
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Names a persistent tunnel (`lim tunnel run --name`) that serves this
|
|
254
|
+
* instance. Creation fails while that tunnel is offline, and the instance
|
|
255
|
+
* becomes ready only after the tunnel attaches.
|
|
256
|
+
*/
|
|
257
|
+
tunnel?: string;
|
|
244
258
|
}
|
|
245
259
|
|
|
246
260
|
export namespace Spec {
|
|
@@ -88,6 +88,13 @@ export namespace IosInstance {
|
|
|
88
88
|
* 10m, 3h. Default is "0" which means no hard timeout.
|
|
89
89
|
*/
|
|
90
90
|
hardTimeout?: string;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Names a persistent tunnel (`lim tunnel run --name`) that serves this
|
|
94
|
+
* instance. Creation fails while that tunnel is offline, and the instance
|
|
95
|
+
* becomes ready only after the tunnel attaches.
|
|
96
|
+
*/
|
|
97
|
+
tunnel?: string;
|
|
91
98
|
}
|
|
92
99
|
|
|
93
100
|
export interface Status {
|
|
@@ -230,6 +237,13 @@ export namespace IosInstanceCreateParams {
|
|
|
230
237
|
* the first.
|
|
231
238
|
*/
|
|
232
239
|
region?: string;
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Names a persistent tunnel (`lim tunnel run --name`) that serves this
|
|
243
|
+
* instance. Creation fails while that tunnel is offline, and the instance
|
|
244
|
+
* becomes ready only after the tunnel attaches.
|
|
245
|
+
*/
|
|
246
|
+
tunnel?: string;
|
|
233
247
|
}
|
|
234
248
|
|
|
235
249
|
export namespace Spec {
|