@stim-cli/core 1.13.0 → 1.15.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/README.md +15 -0
- package/dist/{core-CmZJEFj_.mjs → core-BwaxUjLX.mjs} +133 -5
- package/dist/index-DgLuTAvh.d.mts +1826 -0
- package/dist/index.d.mts +41 -1
- package/dist/index.mjs +2 -2
- package/dist/oversight.d.mts +308 -0
- package/dist/oversight.mjs +666 -0
- package/dist/ownership-claim-Xxxr9MPp.d.mts +152 -0
- package/dist/ownership-claim.d.mts +1 -151
- package/dist/phone-protocol.d.mts +434 -0
- package/dist/phone-protocol.mjs +2 -0
- package/dist/process-identity-BTyww2Xj.d.mts +37 -0
- package/dist/process-identity.d.mts +2 -30
- package/dist/process-identity.mjs +10 -2
- package/dist/protocol-BjnE921M.d.mts +1442 -0
- package/dist/protocol.d.mts +2 -0
- package/dist/protocol.mjs +372 -0
- package/dist/receive-protocol.d.mts +12 -0
- package/dist/receive-protocol.mjs +16563 -0
- package/dist/state.d.mts +2 -737
- package/dist/state.mjs +2738 -680
- package/package.json +21 -1
|
@@ -0,0 +1,1442 @@
|
|
|
1
|
+
import { C as HostedDeviceRequest, In as StatusPayload, Jr as HostedAppDelivery, Lr as HostedAppLaunch, T as HostedDeviceSession, Xr as HostedAppOffer, Za as NdjsonRecord, b as HostedDeviceOfferRequest, i as HostedLogsPage, r as HostedLogsCursor, tn as BuildPlanPayload, y as HostedDeviceOffer } from "./index-DgLuTAvh.mjs";
|
|
2
|
+
//#region protocol.d.ts
|
|
3
|
+
declare const PROTOCOL_VERSION = 1;
|
|
4
|
+
declare const PROTOCOL_SCHEMA_FILE = "protocol.schema.json";
|
|
5
|
+
/**
|
|
6
|
+
* `read` serves state. `control` also runs {@link ACTIONS}; only the Mac grants it. `build` lets another Mac run
|
|
7
|
+
* project code here to build for it; it never comes with `read` or `control`, and only the Mac approves it.
|
|
8
|
+
* `device-host` permits a client's native app code in its own hosted sessions, and grants no other capability.
|
|
9
|
+
*/
|
|
10
|
+
declare const CAPABILITIES: readonly ["read", "control", "build", "device-host"];
|
|
11
|
+
type Capability = (typeof CAPABILITIES)[number];
|
|
12
|
+
/**
|
|
13
|
+
* What this server serves beyond protocol version 1's base, so a client can tell before it asks. `physical-ios` and
|
|
14
|
+
* `physical-android` are `physical: true` on `frames.subscribe` for that platform's leased device, and for an
|
|
15
|
+
* Android phone also on `control.begin`. An older server ignores `physical` on `frames.subscribe` and would stream
|
|
16
|
+
* the slot's Stim-owned device instead. `notifications` is `notifications.list` and the `notification` event.
|
|
17
|
+
* `macos-hosted` relays `frames.subscribe` and control for a workspace whose macOS app
|
|
18
|
+
* `stim macos --remote` placed on another Mac.
|
|
19
|
+
* `macos-windows` is the `macos-windows` event on a macOS `frames.subscribe`, naming the window capture follows
|
|
20
|
+
* and the app's other windows.
|
|
21
|
+
* `hosted-congestion` is `device-host.frames.congested`, which lowers the bitrate of a hosted video subscription
|
|
22
|
+
* whose client is behind.
|
|
23
|
+
* `macos-window-select` is `input.window`, which pins the view to a macOS app window named by `macos-windows`,
|
|
24
|
+
* bringing it to the front, or with null resumes following the front window.
|
|
25
|
+
* `server-update` is `server.update.status`, `server.update.start` and `server.update.chunk`.
|
|
26
|
+
*/
|
|
27
|
+
declare const FEATURES: readonly ["physical-ios", "physical-android", "notifications", "macos-window", "macos-windows", "macos-window-select", "macos-window-control", "macos-keyboard-extended", "device-frames", "macos-hosted", "duo-frames", "workspace-diff", "hosted-congestion", "server-update"];
|
|
28
|
+
type Feature = (typeof FEATURES)[number];
|
|
29
|
+
declare const METHODS: readonly ["hello", "route.setup", "status.subscribe", "logs.query", "logs.subscribe", "stats.get", "settings.get", "workspace.files", "workspace.diff", "frames.subscribe", "frames.keyframe", "frames.seek", "frames.live", "replay.range", "replay.keyframe", "recording.set", "build.plan", "machine.get", "machine.history", "machine.details", "unsubscribe", "action", "control.begin", "control.end", "input.touch", "input.text", "input.button", "input.rotate", "input.posture", "input.simulator", "input.scroll", "input.key", "input.window", "push.register", "push.unregister", "notifications.list", "build.offer", "build.sync", "build.start", "build.cancel", "build.artifact", "build.attach", "device-host.offer", "device-host.reserve", "device-host.attach", "device-host.stop", "device-host.app.offer", "device-host.app.chunk", "device-host.app.handoff", "device-host.app.launch", "device-host.app.attach", "device-host.logs.query", "device-host.metro.open", "device-host.metro.close", "device-host.frames.subscribe", "device-host.frames.keyframe", "device-host.frames.congested", "device-host.unsubscribe", "device-host.control.begin", "device-host.control.end", "device-host.input.touch", "device-host.input.text", "device-host.input.scroll", "device-host.input.key", "device-host.input.button", "device-host.input.rotate", "device-host.input.posture", "device-host.input.window", "server.update.status", "server.update.start", "server.update.chunk", "machines.update.start", "machines.update.status"];
|
|
30
|
+
/**
|
|
31
|
+
* The methods that update this server's `stim-server service`. A Mac this one approved for `build` or
|
|
32
|
+
* `device-host` may call them; they need neither `read` nor `control`.
|
|
33
|
+
*/
|
|
34
|
+
declare const SERVER_UPDATE_METHODS: readonly ["server.update.status", "server.update.start", "server.update.chunk"];
|
|
35
|
+
/** The methods a connection with the `build` capability may call; they need `build`, not `read`. */
|
|
36
|
+
declare const BUILD_METHODS: readonly ["build.offer", "build.sync", "build.start", "build.cancel", "build.artifact", "build.attach"];
|
|
37
|
+
/** Methods restricted to explicitly approved device-host clients. */
|
|
38
|
+
declare const DEVICE_HOST_METHODS: readonly ["device-host.offer", "device-host.reserve", "device-host.attach", "device-host.stop", "device-host.app.offer", "device-host.app.chunk", "device-host.app.handoff", "device-host.app.launch", "device-host.app.attach", "device-host.logs.query", "device-host.metro.open", "device-host.metro.close", "device-host.frames.subscribe", "device-host.frames.keyframe", "device-host.frames.congested", "device-host.unsubscribe", "device-host.control.begin", "device-host.control.end", "device-host.input.touch", "device-host.input.text", "device-host.input.scroll", "device-host.input.key", "device-host.input.button", "device-host.input.rotate", "device-host.input.posture", "device-host.input.window"];
|
|
39
|
+
type Method = (typeof METHODS)[number];
|
|
40
|
+
declare const PUSH_TOKEN_PATTERN = "^(Expo|Exponent)PushToken\\[[^\\]\\s]{1,256}\\]$";
|
|
41
|
+
/**
|
|
42
|
+
* `unauthorized`, `pairing-expired` and `protocol-unsupported` refuse the client until it pairs again or
|
|
43
|
+
* updates; `approval-pending` refuses a build client until the Mac approves it; clients retry the others.
|
|
44
|
+
*/
|
|
45
|
+
declare const ERROR_CODES: readonly ["unauthorized", "pairing-expired", "protocol-unsupported", "approval-pending", "identity-unavailable", "bad-request", "unknown-method", "already-authenticated", "unknown-subscription", "unknown-workspace", "limit-exceeded", "slow-client", "status-failed", "logs-failed", "stim-failed", "frames-failed", "forbidden", "unknown-action", "action-busy", "action-failed", "device-busy", "unknown-session", "no-recording", "build-refused", "build-busy"];
|
|
46
|
+
type ErrorCode = (typeof ERROR_CODES)[number];
|
|
47
|
+
type RequestId = number | string;
|
|
48
|
+
/** Spends a single-use pairing token; the result carries the new device token. */
|
|
49
|
+
interface PairingAuth {
|
|
50
|
+
pairingToken: string;
|
|
51
|
+
deviceName: string;
|
|
52
|
+
}
|
|
53
|
+
/** Presents the device token a previous pairing returned. */
|
|
54
|
+
interface DeviceAuth {
|
|
55
|
+
deviceToken: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Asks, from another Mac on the tailnet, to build here. The result carries a device token with no
|
|
59
|
+
* capabilities and `approval`; the token authenticates once the Mac approves the request.
|
|
60
|
+
*/
|
|
61
|
+
interface BuildRequestAuth {
|
|
62
|
+
request: "build";
|
|
63
|
+
deviceName: string;
|
|
64
|
+
}
|
|
65
|
+
/** Requests explicit device hosting approval; grants no read, control or build access. */
|
|
66
|
+
interface DeviceHostRequestAuth {
|
|
67
|
+
request: "device-host";
|
|
68
|
+
deviceName: string;
|
|
69
|
+
}
|
|
70
|
+
interface HelloParams {
|
|
71
|
+
protocol: number;
|
|
72
|
+
client: {
|
|
73
|
+
name: string;
|
|
74
|
+
version: string;
|
|
75
|
+
};
|
|
76
|
+
auth: PairingAuth | DeviceAuth | BuildRequestAuth | DeviceHostRequestAuth;
|
|
77
|
+
}
|
|
78
|
+
interface HelloResult {
|
|
79
|
+
/** Present when the server runs under Stim Host: the grants macOS gives that app, or null if unavailable. */
|
|
80
|
+
host?: {
|
|
81
|
+
name: string;
|
|
82
|
+
screenRecording: boolean;
|
|
83
|
+
accessibility: boolean;
|
|
84
|
+
} | null;
|
|
85
|
+
protocol: number;
|
|
86
|
+
/**
|
|
87
|
+
* The Mac's name, this package's version, the version of the `stim` it runs, and the home directory of the
|
|
88
|
+
* user it runs as, so clients can show paths under it as `~/...`.
|
|
89
|
+
*/
|
|
90
|
+
server: {
|
|
91
|
+
name: string;
|
|
92
|
+
version: string;
|
|
93
|
+
stim: string;
|
|
94
|
+
home: string;
|
|
95
|
+
};
|
|
96
|
+
capabilities: Capability[];
|
|
97
|
+
features: Feature[];
|
|
98
|
+
/** The actions this device may run: every one of {@link ACTIONS} with `control`, none without. */
|
|
99
|
+
actions: ActionName[];
|
|
100
|
+
/** The paired device this connection authenticated as, as `stim-server devices` lists it. */
|
|
101
|
+
device: {
|
|
102
|
+
id: string;
|
|
103
|
+
name: string;
|
|
104
|
+
};
|
|
105
|
+
/** Present only when the hello spent a pairing token or requested build or device-host access. The server keeps only its hash. */
|
|
106
|
+
deviceToken?: string;
|
|
107
|
+
/** Present only on a build or device-host request, which the server then closes; the request lapses at `expiresAt`. */
|
|
108
|
+
approval?: {
|
|
109
|
+
state: "pending";
|
|
110
|
+
expiresAt: string;
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
interface SubscribeResult {
|
|
114
|
+
subscription: string;
|
|
115
|
+
}
|
|
116
|
+
interface UnsubscribeParams {
|
|
117
|
+
subscription: string;
|
|
118
|
+
}
|
|
119
|
+
declare const LOG_SOURCES: readonly ["metro", "client", "device", "build", "agent"];
|
|
120
|
+
type LogSource = (typeof LOG_SOURCES)[number];
|
|
121
|
+
declare const LOG_LEVELS: readonly ["debug", "info", "warn", "error", "fatal"];
|
|
122
|
+
type LogLevel = (typeof LOG_LEVELS)[number];
|
|
123
|
+
declare const MAX_LOG_TAIL = 5e3;
|
|
124
|
+
/**
|
|
125
|
+
* The Stim Desktop log viewer's filters, passed to `stim logs`. `workspace` is an environment `path` from a
|
|
126
|
+
* status payload. Without `sources`, `errors` keeps the CLI's default error scope. `tail` defaults to
|
|
127
|
+
* {@link MAX_LOG_TAIL}, which is also its maximum.
|
|
128
|
+
*/
|
|
129
|
+
interface LogFilter {
|
|
130
|
+
workspace: string;
|
|
131
|
+
sources?: LogSource[];
|
|
132
|
+
level?: LogLevel;
|
|
133
|
+
slot?: string;
|
|
134
|
+
grep?: string;
|
|
135
|
+
errors?: boolean;
|
|
136
|
+
tail?: number;
|
|
137
|
+
}
|
|
138
|
+
/** One record as `stim logs --json` prints it. */
|
|
139
|
+
type LogRecord = NdjsonRecord;
|
|
140
|
+
interface LogsQueryResult {
|
|
141
|
+
records: LogRecord[];
|
|
142
|
+
}
|
|
143
|
+
/** Without `workspace`, stats and settings cover the machine only. */
|
|
144
|
+
interface WorkspaceParams {
|
|
145
|
+
workspace?: string;
|
|
146
|
+
}
|
|
147
|
+
/** `stim stats --json`. */
|
|
148
|
+
type StatsResult = Record<string, unknown>;
|
|
149
|
+
/** `stim settings --json`; the CLI masks sensitive values. */
|
|
150
|
+
type SettingsResult = Record<string, unknown>;
|
|
151
|
+
/** `web` is the workspace's Stim-owned Chrome page, from `stim web`; it has only the default slot. */
|
|
152
|
+
declare const PLATFORMS: readonly ["ios", "android", "web", "macos"];
|
|
153
|
+
type Platform = (typeof PLATFORMS)[number];
|
|
154
|
+
/** The platforms `build.plan` predicts builds for. */
|
|
155
|
+
type BuildPlatform = Extract<Platform, "ios" | "android">;
|
|
156
|
+
type ControlPlatform = Platform;
|
|
157
|
+
/** `reload` also reaches the workspace's Stim-owned Chrome page. */
|
|
158
|
+
declare const RELOAD_PLATFORMS: readonly ["ios", "android", "web"];
|
|
159
|
+
type ReloadPlatform = (typeof RELOAD_PLATFORMS)[number];
|
|
160
|
+
declare const FRAME_FPS: {
|
|
161
|
+
readonly default: 5;
|
|
162
|
+
readonly max: 30;
|
|
163
|
+
readonly video: 60;
|
|
164
|
+
};
|
|
165
|
+
declare const FRAME_EDGE: {
|
|
166
|
+
readonly min: 240;
|
|
167
|
+
readonly default: 1280;
|
|
168
|
+
readonly max: 2048;
|
|
169
|
+
};
|
|
170
|
+
/**
|
|
171
|
+
* A device `stim status` lists as owned by `workspace`, in `slot` (`default` when absent). Frames come only
|
|
172
|
+
* from a booted simulator or a running emulator Stim created, or from the page of the workspace's running
|
|
173
|
+
* Stim-owned Chrome (`web`, default slot only). With `physical`, frames come from the physical device the workspace
|
|
174
|
+
* leases in `slot` instead, as `stim status` lists it under `deviceLeases`; an iPhone streams only over a USB
|
|
175
|
+
* cable, and an Android phone over adb. `fps` caps how many frames a second this
|
|
176
|
+
* subscription gets, and `maxEdge` asks for frames scaled to fit that many pixels; the server may send smaller
|
|
177
|
+
* frames, and larger ones while another subscriber of the same device asks for more.
|
|
178
|
+
*/
|
|
179
|
+
interface FrameTarget {
|
|
180
|
+
/** Requests installed ordinary-device artwork for this live subscription. */
|
|
181
|
+
deviceFrame?: boolean;
|
|
182
|
+
/** Requests a composed Duo image carrying the pose used to map its input. */
|
|
183
|
+
duoFrame?: boolean;
|
|
184
|
+
workspace: string;
|
|
185
|
+
platform: Platform;
|
|
186
|
+
slot?: string;
|
|
187
|
+
physical?: boolean;
|
|
188
|
+
fps?: number;
|
|
189
|
+
maxEdge?: number;
|
|
190
|
+
/** The codecs this client decodes. The server picks one when it can encode video; see {@link FramesSubscribeResult}. */
|
|
191
|
+
video?: VideoCodec[];
|
|
192
|
+
/**
|
|
193
|
+
* Starts the subscription replaying the footage recorded at `at`, as {@link FramesSeekParams} does, and needs
|
|
194
|
+
* `video`. It needs no running device until `frames.live`, so a stopped workspace's footage can be replayed.
|
|
195
|
+
*/
|
|
196
|
+
at?: number;
|
|
197
|
+
rate?: FramesSeekParams["rate"];
|
|
198
|
+
}
|
|
199
|
+
declare const VIDEO_CODECS: readonly ["h264"];
|
|
200
|
+
type VideoCodec = (typeof VIDEO_CODECS)[number];
|
|
201
|
+
/**
|
|
202
|
+
* With `video`, frames arrive as binary WebSocket messages, one H.264 access unit each; see {@link VideoPacket}.
|
|
203
|
+
* A subscription whose device falls back to screenshots still sends JSON `frame` events.
|
|
204
|
+
*/
|
|
205
|
+
interface FramesSubscribeResult extends SubscribeResult {
|
|
206
|
+
video?: VideoCodec;
|
|
207
|
+
}
|
|
208
|
+
/** Asks for a keyframe on a video subscription, after the client lost its decoder state. */
|
|
209
|
+
interface KeyframeParams {
|
|
210
|
+
subscription: string;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Plays recorded footage into a video subscription instead of the live screen: the frame at `at` (epoch
|
|
214
|
+
* milliseconds on the Mac's clock) arrives at once, as the access units from the keyframe before it, then playback
|
|
215
|
+
* goes on at `rate` times real time. A `rate` of 0 stays paused on that frame. Time where nothing was recorded is
|
|
216
|
+
* skipped.
|
|
217
|
+
*/
|
|
218
|
+
interface FramesSeekParams {
|
|
219
|
+
subscription: string;
|
|
220
|
+
at: number;
|
|
221
|
+
rate: (typeof REPLAY_RATES)[number];
|
|
222
|
+
}
|
|
223
|
+
declare const REPLAY_RATES: readonly [0, 1, 2];
|
|
224
|
+
/** `at` is the capture time of the frame shown, at or before the one asked for. */
|
|
225
|
+
interface FramesSeekResult {
|
|
226
|
+
at: number;
|
|
227
|
+
}
|
|
228
|
+
/** Returns a subscription that seeked to the live screen. */
|
|
229
|
+
interface FramesLiveParams {
|
|
230
|
+
subscription: string;
|
|
231
|
+
}
|
|
232
|
+
/** A device slot of a workspace, as `frames.subscribe` names it. */
|
|
233
|
+
interface ReplayTarget {
|
|
234
|
+
workspace: string;
|
|
235
|
+
platform: Platform;
|
|
236
|
+
slot?: string;
|
|
237
|
+
}
|
|
238
|
+
/** A time range with recorded footage, in epoch milliseconds on the Mac's clock. */
|
|
239
|
+
interface ReplaySpan {
|
|
240
|
+
start: number;
|
|
241
|
+
end: number;
|
|
242
|
+
}
|
|
243
|
+
/** Kinds of timeline marker: an agent `action` on the device, an app or build `error`, and a `crash`. */
|
|
244
|
+
declare const REPLAY_MARKER_KINDS: readonly ["action", "error", "crash"];
|
|
245
|
+
/**
|
|
246
|
+
* Something that happened at `at`: an action has agent-device's or the web agent's `command`, such as `press`,
|
|
247
|
+
* `fill`, `open` or `click`. `label` is one line of the log record.
|
|
248
|
+
*/
|
|
249
|
+
interface ReplayMarker {
|
|
250
|
+
at: number;
|
|
251
|
+
kind: (typeof REPLAY_MARKER_KINDS)[number];
|
|
252
|
+
command?: string;
|
|
253
|
+
label: string;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* What can be replayed for a device slot. `enabled` is the workspace's `recording.enabled`; `recording` is true
|
|
257
|
+
* while the server records the device now. `spans` are the recorded ranges, oldest first, and `markers` the agent
|
|
258
|
+
* actions and errors from the start of the first span on.
|
|
259
|
+
*/
|
|
260
|
+
interface ReplayRange {
|
|
261
|
+
enabled: boolean;
|
|
262
|
+
recording: boolean;
|
|
263
|
+
spans: ReplaySpan[];
|
|
264
|
+
markers: ReplayMarker[];
|
|
265
|
+
}
|
|
266
|
+
/** A device slot, as {@link ReplayTarget} names it, and a time in epoch milliseconds on the Mac's clock. */
|
|
267
|
+
interface ReplayKeyframeParams extends ReplayTarget {
|
|
268
|
+
at: number;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* The keyframe that starts the recorded segment of about 5 seconds `frames.seek` would show `at` from: the first
|
|
272
|
+
* segment that ends at or after `at`, or the newest one. `start` and `end` are the segment's times, `at` the
|
|
273
|
+
* keyframe's capture time, and `data` the base64 Annex-B access unit, which carries its SPS and PPS.
|
|
274
|
+
*/
|
|
275
|
+
interface ReplayKeyframe {
|
|
276
|
+
start: number;
|
|
277
|
+
end: number;
|
|
278
|
+
at: number;
|
|
279
|
+
width: number;
|
|
280
|
+
height: number;
|
|
281
|
+
posture?: "folded" | "unfolded";
|
|
282
|
+
data: string;
|
|
283
|
+
}
|
|
284
|
+
/** Turns `recording.enabled` on or off in the machine layer. Needs `control`. */
|
|
285
|
+
interface RecordingSetParams {
|
|
286
|
+
enabled: boolean;
|
|
287
|
+
}
|
|
288
|
+
/** `recordingsDeleted` lists the workspaces whose recordings turning recording off deleted. */
|
|
289
|
+
interface RecordingSetResult {
|
|
290
|
+
enabled: boolean;
|
|
291
|
+
recordingsDeleted: string[];
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* A replaying subscription reached the newest recorded frame, at `at`, and stays paused there; the client can
|
|
295
|
+
* seek again or return to live with `frames.live`.
|
|
296
|
+
*/
|
|
297
|
+
interface ReplayEndedEvent {
|
|
298
|
+
event: "replay-ended";
|
|
299
|
+
subscription: string;
|
|
300
|
+
at: number;
|
|
301
|
+
}
|
|
302
|
+
declare const VIDEO_HEADER_VERSION = 1;
|
|
303
|
+
/** The keyframe bit of a {@link VideoPacket}'s flags. */
|
|
304
|
+
declare const VIDEO_KEYFRAME = 1;
|
|
305
|
+
/** The flag bits of a {@link VideoPacket} that carry an iPhone Duo's posture, as `posture` on a `frame` event. */
|
|
306
|
+
declare const VIDEO_FOLDED = 2;
|
|
307
|
+
declare const VIDEO_UNFOLDED = 4;
|
|
308
|
+
/** Bit 5 marks clockwise artwork quarter-turns in bits 3-4; absent on recordings and unsupported sources. */
|
|
309
|
+
declare const VIDEO_ARTWORK = 32;
|
|
310
|
+
/**
|
|
311
|
+
* The layout of a binary video message, big-endian: u8 version ({@link VIDEO_HEADER_VERSION}), u8 flags
|
|
312
|
+
* ({@link VIDEO_KEYFRAME}, posture bits and {@link VIDEO_ARTWORK}), u16 header length, u32 sequence number of the messages sent on this subscription, f64 capture time in milliseconds since the
|
|
313
|
+
* epoch on the Mac's clock, u16 width, u16 height, u8 subscription id length N, N bytes of ASCII subscription
|
|
314
|
+
* id. After the header comes one Annex-B H.264 access unit; a keyframe carries its SPS and PPS. The stream has
|
|
315
|
+
* no B-frames, so each access unit is shown as it arrives.
|
|
316
|
+
*/
|
|
317
|
+
interface VideoPacket {
|
|
318
|
+
subscription: string;
|
|
319
|
+
keyframe: boolean;
|
|
320
|
+
sequence: number;
|
|
321
|
+
capturedAt: number;
|
|
322
|
+
width: number;
|
|
323
|
+
height: number;
|
|
324
|
+
posture?: "folded" | "unfolded";
|
|
325
|
+
artworkTurns?: number;
|
|
326
|
+
accessUnit: Uint8Array;
|
|
327
|
+
}
|
|
328
|
+
/** Each action runs one fixed `stim` command in the workspace. */
|
|
329
|
+
declare const ACTIONS: readonly ["reload", "stop"];
|
|
330
|
+
type ActionName = (typeof ACTIONS)[number];
|
|
331
|
+
/**
|
|
332
|
+
* `reload` runs `stim reload --json`, with `platform` when more than one platform is live; `stop` runs
|
|
333
|
+
* `stim stop --json`. `workspace` is an environment `path` from a status payload. Needs `control`.
|
|
334
|
+
*/
|
|
335
|
+
type ActionParams = {
|
|
336
|
+
action: "reload";
|
|
337
|
+
workspace: string;
|
|
338
|
+
platform?: ReloadPlatform;
|
|
339
|
+
} | {
|
|
340
|
+
action: "stop";
|
|
341
|
+
workspace: string;
|
|
342
|
+
};
|
|
343
|
+
/** `output` is the JSON the command printed. */
|
|
344
|
+
interface ActionResult {
|
|
345
|
+
action: ActionName;
|
|
346
|
+
workspace: string;
|
|
347
|
+
output: Record<string, unknown>;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Starts a control session on the device `stim status` lists as owned by `workspace` in `slot`. Needs
|
|
351
|
+
* `control`. Refused with `device-busy` while an agent, a device lock or another client drives the device,
|
|
352
|
+
* unless `takeOver` is true. `physical` picks the physical device the workspace leases instead, and only while that
|
|
353
|
+
* lease lasts: the server never takes or renews a physical device's lease, so `takeOver` cannot move one between
|
|
354
|
+
* workspaces. A physical iPhone is view only, so it is refused.
|
|
355
|
+
*/
|
|
356
|
+
interface ControlBeginParams {
|
|
357
|
+
workspace: string;
|
|
358
|
+
platform: ControlPlatform;
|
|
359
|
+
slot?: string;
|
|
360
|
+
physical?: boolean;
|
|
361
|
+
takeOver?: boolean;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* `lease` is the `stim device lock` lease the server holds for the session, or null when it holds none, such
|
|
365
|
+
* as after taking over a device another workspace leases, and always for a web page or native macOS app, which `stim device lock`
|
|
366
|
+
* does not cover. For a physical device it is the workspace's own lease, which the session ends with. `postures` lists what `input.posture` accepts for
|
|
367
|
+
* the device: `folded` and `unfolded` for an iPhone Duo, all three for an emulator with a hinge, and none
|
|
368
|
+
* otherwise.
|
|
369
|
+
*/
|
|
370
|
+
interface ControlBeginResult {
|
|
371
|
+
session: string;
|
|
372
|
+
platform: Platform;
|
|
373
|
+
lease: {
|
|
374
|
+
grantedAt: string | null;
|
|
375
|
+
expiresAt: string;
|
|
376
|
+
} | null;
|
|
377
|
+
postures: DevicePosture[];
|
|
378
|
+
simulator?: SimulatorOptions;
|
|
379
|
+
}
|
|
380
|
+
/** Available simulator controls and the current guest animation setting; null means unsupported. */
|
|
381
|
+
interface SimulatorOptions {
|
|
382
|
+
canShake: boolean;
|
|
383
|
+
slowAnimations: boolean | null;
|
|
384
|
+
}
|
|
385
|
+
type SimulatorCommand = {
|
|
386
|
+
action: "read" | "shake";
|
|
387
|
+
} | {
|
|
388
|
+
action: "slow-animations";
|
|
389
|
+
enabled: boolean;
|
|
390
|
+
};
|
|
391
|
+
type InputSimulatorParams = SimulatorCommand & {
|
|
392
|
+
session: string;
|
|
393
|
+
};
|
|
394
|
+
interface ControlEndParams {
|
|
395
|
+
session: string;
|
|
396
|
+
}
|
|
397
|
+
declare const TOUCH_PHASES: readonly ["down", "move", "up"];
|
|
398
|
+
type TouchPhase = (typeof TOUCH_PHASES)[number];
|
|
399
|
+
/**
|
|
400
|
+
* `x` and `y` are fractions of the upright screen, origin top-left; on a web page, of its viewport, where a
|
|
401
|
+
* drag scrolls. `display` is 0 for the main display; without it, an iPhone Duo's touch goes to the panel its
|
|
402
|
+
* frames show.
|
|
403
|
+
*/
|
|
404
|
+
interface InputTouchParams {
|
|
405
|
+
session: string;
|
|
406
|
+
phase: TouchPhase;
|
|
407
|
+
x: number;
|
|
408
|
+
y: number;
|
|
409
|
+
display?: number;
|
|
410
|
+
/** The revision of the composed Duo image actually displayed by the client. */
|
|
411
|
+
duoRevision?: string;
|
|
412
|
+
}
|
|
413
|
+
/** Native macOS pixel scrolling at a normalized point of the captured window. Deltas are capped at 1000 pixels. */
|
|
414
|
+
interface InputScrollParams {
|
|
415
|
+
session: string;
|
|
416
|
+
x: number;
|
|
417
|
+
y: number;
|
|
418
|
+
deltaX: number;
|
|
419
|
+
deltaY: number;
|
|
420
|
+
}
|
|
421
|
+
declare const INPUT_KEYS: readonly ["escape", "tab", "return", "backspace", "left", "right", "up", "down", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
|
|
422
|
+
type InputKey = (typeof INPUT_KEYS)[number];
|
|
423
|
+
declare const KEY_MODIFIERS: readonly ["command", "shift", "option", "control"];
|
|
424
|
+
type KeyModifier = (typeof KEY_MODIFIERS)[number];
|
|
425
|
+
/** Pins an owned macOS app window by id, or resumes following its front window with null. */
|
|
426
|
+
interface InputWindowParams {
|
|
427
|
+
session: string;
|
|
428
|
+
window: number | null;
|
|
429
|
+
}
|
|
430
|
+
/** A fixed native macOS key and optional modifiers, sent only to the captured owned app window. */
|
|
431
|
+
interface InputKeyParams {
|
|
432
|
+
session: string;
|
|
433
|
+
key: InputKey;
|
|
434
|
+
modifiers?: KeyModifier[];
|
|
435
|
+
}
|
|
436
|
+
declare const MAX_INPUT_TEXT = 256;
|
|
437
|
+
/** Printable ASCII, where `\n` presses Return, `\t` Tab and `\b` Delete. */
|
|
438
|
+
interface InputTextParams {
|
|
439
|
+
session: string;
|
|
440
|
+
text: string;
|
|
441
|
+
}
|
|
442
|
+
/** `home` and `lock` on iOS and Android; `back` on Android and web, where it goes back in the page's history; `app-switch` on Android only. */
|
|
443
|
+
declare const INPUT_BUTTONS: readonly ["home", "lock", "back", "app-switch"];
|
|
444
|
+
type InputButton = (typeof INPUT_BUTTONS)[number];
|
|
445
|
+
interface InputButtonParams {
|
|
446
|
+
session: string;
|
|
447
|
+
button: InputButton;
|
|
448
|
+
}
|
|
449
|
+
/** `left` turns the device a quarter turn counterclockwise, `right` clockwise. */
|
|
450
|
+
declare const ROTATE_DIRECTIONS: readonly ["left", "right"];
|
|
451
|
+
type RotateDirection = (typeof ROTATE_DIRECTIONS)[number];
|
|
452
|
+
interface InputRotateParams {
|
|
453
|
+
session: string;
|
|
454
|
+
direction: RotateDirection;
|
|
455
|
+
}
|
|
456
|
+
declare const DEVICE_POSTURES: readonly ["folded", "half-open", "unfolded"];
|
|
457
|
+
type DevicePosture = (typeof DEVICE_POSTURES)[number];
|
|
458
|
+
/** Moves the hinge of a device whose `control.begin` result lists `posture`. */
|
|
459
|
+
interface InputPostureParams {
|
|
460
|
+
session: string;
|
|
461
|
+
posture: DevicePosture;
|
|
462
|
+
}
|
|
463
|
+
/** Predicts the next `ios` or `android` build of `workspace` in `slot` (`default` when absent). */
|
|
464
|
+
interface BuildPlanParams {
|
|
465
|
+
workspace: string;
|
|
466
|
+
platform: BuildPlatform;
|
|
467
|
+
slot?: string;
|
|
468
|
+
}
|
|
469
|
+
/** `stim ios|android --plan --json`. It builds, boots and installs nothing, and writes no Stim state. */
|
|
470
|
+
type BuildPlanResult = BuildPlanPayload;
|
|
471
|
+
/** A client's repository on a build machine: letters, digits, `.`, `_` and `-`, at most 80. */
|
|
472
|
+
declare const BUILD_REPO_PATTERN = "^[A-Za-z0-9][A-Za-z0-9._-]{0,79}$";
|
|
473
|
+
/** Asks a build machine what it can build, how busy it is, and how warm its copy of `repo` is. */
|
|
474
|
+
interface BuildOfferParams {
|
|
475
|
+
repo: string;
|
|
476
|
+
/** sha256 of the repository's lockfile, compared with the one the machine last installed from. */
|
|
477
|
+
lockfile?: string;
|
|
478
|
+
}
|
|
479
|
+
/** The toolchain a build must match exactly on both Macs. */
|
|
480
|
+
interface BuildToolchain {
|
|
481
|
+
stimBuild: string | null;
|
|
482
|
+
arch: string;
|
|
483
|
+
xcode: string | null;
|
|
484
|
+
simulatorSdk: string | null;
|
|
485
|
+
macosSdk: string | null;
|
|
486
|
+
cocoapods: string | null;
|
|
487
|
+
/** Simulator runtime identifiers that have an iPhone simulator to build for. */
|
|
488
|
+
runtimes: string[];
|
|
489
|
+
/** The major version of the JDK Gradle runs on there. */
|
|
490
|
+
jdk: string | null;
|
|
491
|
+
/** The NDK, build-tools and platform directories of its Android SDK; null without an SDK. */
|
|
492
|
+
androidSdk: {
|
|
493
|
+
ndk: string[];
|
|
494
|
+
buildTools: string[];
|
|
495
|
+
platforms: string[];
|
|
496
|
+
} | null;
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* How busy the build machine is. `running` counts offloaded builds and `max` is how many it runs at once.
|
|
500
|
+
* `cpus`, `loadPerCore` (5-minute load average per CPU), `builds` (its own Stim native builds plus the offloaded
|
|
501
|
+
* ones), `maxBuilds` (its `concurrency.maxBuilds`, 0 when unlimited) and `maxLoadPerCore` are absent from a
|
|
502
|
+
* stim-server older than them. `declined` is why it would refuse a build now, null when it would take one.
|
|
503
|
+
*/
|
|
504
|
+
interface BuildCapacity {
|
|
505
|
+
running: number;
|
|
506
|
+
max: number;
|
|
507
|
+
diskFreeBytes: number | null;
|
|
508
|
+
minDiskFreeBytes: number;
|
|
509
|
+
cpus?: number;
|
|
510
|
+
loadPerCore?: number;
|
|
511
|
+
builds?: number;
|
|
512
|
+
maxBuilds?: number;
|
|
513
|
+
maxLoadPerCore?: number;
|
|
514
|
+
declined?: string | null;
|
|
515
|
+
}
|
|
516
|
+
interface BuildOfferResult {
|
|
517
|
+
toolchain: BuildToolchain;
|
|
518
|
+
capacity: BuildCapacity;
|
|
519
|
+
warm: {
|
|
520
|
+
checkout: boolean;
|
|
521
|
+
dependencies: boolean;
|
|
522
|
+
build: boolean;
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
/** One file of the client's checkout. A `link` blob holds the symlink's target. */
|
|
526
|
+
interface BuildFile {
|
|
527
|
+
path: string;
|
|
528
|
+
kind: "file" | "exec" | "link";
|
|
529
|
+
size: number;
|
|
530
|
+
sha256: string;
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* One page of the manifest of `repo`, as `git ls-files -co --exclude-standard` lists it. Pages accumulate until
|
|
534
|
+
* `done`; the next `build.sync` after that starts a new manifest.
|
|
535
|
+
*/
|
|
536
|
+
interface BuildSyncParams {
|
|
537
|
+
repo: string;
|
|
538
|
+
files: BuildFile[];
|
|
539
|
+
done: boolean;
|
|
540
|
+
}
|
|
541
|
+
/** The digests of this page the machine lacks; the client sends each as binary frames before `build.start`. */
|
|
542
|
+
interface BuildSyncResult {
|
|
543
|
+
missing: string[];
|
|
544
|
+
}
|
|
545
|
+
/** The Gradle choices of an Android build: `assemble<variant>`, one ABI, and the caches it compiles with. */
|
|
546
|
+
interface BuildAndroidOptions {
|
|
547
|
+
variant: string | null;
|
|
548
|
+
abi: string | null;
|
|
549
|
+
gradleBuildCache: boolean;
|
|
550
|
+
pch: "auto" | "on" | "off";
|
|
551
|
+
compilerCache: "ccache" | "none";
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Builds the synced manifest of `repo`. The machine refuses unless its fingerprint equals `fingerprint`. iOS
|
|
555
|
+
* needs `runtime`; Android needs `android`; macOS needs `macos` and uses the manifest digest as its fingerprint.
|
|
556
|
+
*/
|
|
557
|
+
interface BuildStartParams {
|
|
558
|
+
repo: string;
|
|
559
|
+
project: string;
|
|
560
|
+
platform: "ios" | "android" | "macos";
|
|
561
|
+
configuration?: string | null;
|
|
562
|
+
scheme?: string | null;
|
|
563
|
+
runtime?: string | null;
|
|
564
|
+
fingerprint: string;
|
|
565
|
+
packageName?: string | null;
|
|
566
|
+
isExpo?: boolean;
|
|
567
|
+
optimizations?: Record<string, unknown> | null;
|
|
568
|
+
android?: BuildAndroidOptions | null;
|
|
569
|
+
macos?: {
|
|
570
|
+
product: string;
|
|
571
|
+
infoPlist: string;
|
|
572
|
+
bundleId: string;
|
|
573
|
+
resources?: Record<string, string>;
|
|
574
|
+
assetCatalog?: string | null;
|
|
575
|
+
} | null;
|
|
576
|
+
stimBuild: string;
|
|
577
|
+
}
|
|
578
|
+
interface BuildJobParams {
|
|
579
|
+
job: string;
|
|
580
|
+
}
|
|
581
|
+
/** A job taken over by a new connection: its outcome once it ended, else null and its progress follows. */
|
|
582
|
+
interface BuildAttachResult {
|
|
583
|
+
outcome: BuildJobOutcome | null;
|
|
584
|
+
}
|
|
585
|
+
/** Sent after the artifact's binary frames: the archive's name, size and sha256. */
|
|
586
|
+
interface BuildArtifactResult {
|
|
587
|
+
name: string;
|
|
588
|
+
size: number;
|
|
589
|
+
sha256: string;
|
|
590
|
+
/**
|
|
591
|
+
* For a macOS job, a single-use token for the staged bundle this Mac keeps for a while, which a hosted session of a
|
|
592
|
+
* device-host client on the same tailnet node can take with `device-host.app.handoff`.
|
|
593
|
+
*/
|
|
594
|
+
handoff?: string;
|
|
595
|
+
}
|
|
596
|
+
type BuildJobOutcome = {
|
|
597
|
+
ok: true;
|
|
598
|
+
artifact: BuildArtifactResult;
|
|
599
|
+
fingerprint: string;
|
|
600
|
+
compilationCache: Record<string, unknown>;
|
|
601
|
+
timings: Record<string, number>;
|
|
602
|
+
} | {
|
|
603
|
+
ok: false;
|
|
604
|
+
code: string;
|
|
605
|
+
message: string;
|
|
606
|
+
timings?: Record<string, number>;
|
|
607
|
+
};
|
|
608
|
+
type MemoryPressure = "normal" | "warning" | "critical";
|
|
609
|
+
/** A volume that holds Stim workspaces, Stim home, or the simulators. */
|
|
610
|
+
interface MachineVolume {
|
|
611
|
+
/** `/`, or `/Volumes/<name>` for an external volume. */
|
|
612
|
+
mount: string;
|
|
613
|
+
/** What Stim keeps there: `Workspaces`, `Stim home`, `Simulators`. */
|
|
614
|
+
holds: string[];
|
|
615
|
+
/** Free space without purgeable space, which is what Stim's disk budget measures. */
|
|
616
|
+
freeBytes: number;
|
|
617
|
+
totalBytes: number;
|
|
618
|
+
}
|
|
619
|
+
/** Cheap machine usage, read in the server process without running `stim`. */
|
|
620
|
+
interface MachineUsage {
|
|
621
|
+
volumes: MachineVolume[];
|
|
622
|
+
/**
|
|
623
|
+
* `usedBytes` is the Mac's memory in use, as Activity Monitor's "Memory Used" counts it: app memory, wired and
|
|
624
|
+
* compressed. `pressure` is the macOS memory pressure level. Both are null on other systems or when they cannot
|
|
625
|
+
* be read.
|
|
626
|
+
*/
|
|
627
|
+
memory: {
|
|
628
|
+
totalBytes: number;
|
|
629
|
+
usedBytes: number | null;
|
|
630
|
+
pressure: MemoryPressure | null;
|
|
631
|
+
};
|
|
632
|
+
load: {
|
|
633
|
+
avg1: number;
|
|
634
|
+
avg5: number;
|
|
635
|
+
avg15: number;
|
|
636
|
+
cpus: number;
|
|
637
|
+
};
|
|
638
|
+
/**
|
|
639
|
+
* `usage` is the Mac's overall CPU busy fraction (0..1), from the tick delta between this call and the
|
|
640
|
+
* previous one. Null on the first call of a server process, since there is no previous sample yet.
|
|
641
|
+
*/
|
|
642
|
+
cpu: {
|
|
643
|
+
usage: number | null;
|
|
644
|
+
cores: number;
|
|
645
|
+
};
|
|
646
|
+
sampledAt: string;
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* One `machine.history` sample. `at` is epoch milliseconds. `cpu` is the busy fraction (0..1) since the previous
|
|
650
|
+
* sample. `memoryPressure` is 0 (normal), 1 (warning) or 2 (critical). `diskFreeBytes` is the free space of the
|
|
651
|
+
* startup volume, `/`. A field is null when it could not be read.
|
|
652
|
+
*/
|
|
653
|
+
interface UsageSample {
|
|
654
|
+
at: number;
|
|
655
|
+
cpu: number | null;
|
|
656
|
+
memoryUsedBytes: number | null;
|
|
657
|
+
memoryPressure: 0 | 1 | 2 | null;
|
|
658
|
+
diskFreeBytes: number | null;
|
|
659
|
+
}
|
|
660
|
+
/** Returns only the samples taken after `sinceMs`, epoch milliseconds. */
|
|
661
|
+
interface MachineHistoryParams {
|
|
662
|
+
sinceMs?: number;
|
|
663
|
+
}
|
|
664
|
+
interface MachineHistory {
|
|
665
|
+
intervalMs: number;
|
|
666
|
+
samples: UsageSample[];
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* The Mac's disk and build detail: the payloads of the `stim gc --json` dry run and of `stim stats --json`, both run in
|
|
670
|
+
* the home directory. A part is null when its command failed, and its `gcError` or `statsError` says why.
|
|
671
|
+
* `measuredAt` is when the commands started. The server keeps one result for 60 seconds, shared by every connection.
|
|
672
|
+
*/
|
|
673
|
+
interface MachineDetails {
|
|
674
|
+
gc: Record<string, unknown> | null;
|
|
675
|
+
gcError?: string;
|
|
676
|
+
stats: Record<string, unknown> | null;
|
|
677
|
+
statsError?: string;
|
|
678
|
+
/**
|
|
679
|
+
* `buildMachines` from `stim doctor --json --platform ios`; empty when `offload.machines` names none. The reply
|
|
680
|
+
* never waits for doctor: `buildMachines` and `buildMachinesError` are the last result a background doctor run
|
|
681
|
+
* settled, `buildMachinesAt` is when it settled, and `buildMachinesPending` is true while that result is stale
|
|
682
|
+
* (or absent) and a refresh is running. A client that wants the refreshed result asks `machine.details` again.
|
|
683
|
+
*/
|
|
684
|
+
buildMachines: BuildMachineReport[] | null;
|
|
685
|
+
buildMachinesError?: string;
|
|
686
|
+
buildMachinesAt?: string;
|
|
687
|
+
buildMachinesPending?: boolean;
|
|
688
|
+
/**
|
|
689
|
+
* The builds this Mac ran for other Macs as a build machine, one entry per client, from the audit log. `today` is
|
|
690
|
+
* this Mac's local calendar day. Absent from a server older than this field.
|
|
691
|
+
*/
|
|
692
|
+
buildClients?: BuildClientSummary[];
|
|
693
|
+
measuredAt: string;
|
|
694
|
+
}
|
|
695
|
+
interface BuildClientSummary {
|
|
696
|
+
id: string;
|
|
697
|
+
name: string;
|
|
698
|
+
builds: number;
|
|
699
|
+
failed: number;
|
|
700
|
+
buildMs: number;
|
|
701
|
+
today: {
|
|
702
|
+
builds: number;
|
|
703
|
+
failed: number;
|
|
704
|
+
buildMs: number;
|
|
705
|
+
};
|
|
706
|
+
lastAt: string;
|
|
707
|
+
}
|
|
708
|
+
/** One `offload.machines` entry as `stim doctor --json` reports it; `guide facts doctor` defines the fields. */
|
|
709
|
+
interface BuildMachineReport {
|
|
710
|
+
machine: string;
|
|
711
|
+
state: string;
|
|
712
|
+
dnsName?: string;
|
|
713
|
+
deviceId?: string;
|
|
714
|
+
requestedAt?: string;
|
|
715
|
+
offloadable?: boolean;
|
|
716
|
+
reasons?: string[];
|
|
717
|
+
problems?: {
|
|
718
|
+
code: string;
|
|
719
|
+
reason: string;
|
|
720
|
+
}[];
|
|
721
|
+
capacity?: BuildMachineCapacity;
|
|
722
|
+
}
|
|
723
|
+
interface BuildMachineCapacity {
|
|
724
|
+
running?: number;
|
|
725
|
+
max?: number;
|
|
726
|
+
diskFreeBytes?: number | null;
|
|
727
|
+
minDiskFreeBytes?: number;
|
|
728
|
+
cpus?: number;
|
|
729
|
+
loadPerCore?: number;
|
|
730
|
+
builds?: number;
|
|
731
|
+
maxBuilds?: number;
|
|
732
|
+
maxLoadPerCore?: number;
|
|
733
|
+
declined?: string | null;
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* What stim-server can push, named like the phone's notification settings: work `started` (a workspace began
|
|
737
|
+
* warming or an agent first drove its device), an agent that looks `stuck`, one that is `looping` on the same
|
|
738
|
+
* failure, work `finished` (the agent stopped after a green build, or the workspace's pull request became ready for
|
|
739
|
+
* review or merged), a `machine` in trouble, and a `control` conflict over a device this phone controls.
|
|
740
|
+
*/
|
|
741
|
+
declare const PUSH_EVENTS: readonly ["started", "stuck", "looping", "finished", "machine", "control", "attention"];
|
|
742
|
+
type PushEvent = (typeof PUSH_EVENTS)[number];
|
|
743
|
+
/** Events phones registered before `PUSH_EVENTS`: `disk` stands for `machine`, and the others no longer push. */
|
|
744
|
+
declare const LEGACY_PUSH_EVENTS: readonly ["build-failed", "log-errors", "disk", "app-stopped", "slow-build"];
|
|
745
|
+
type LegacyPushEvent = (typeof LEGACY_PUSH_EVENTS)[number];
|
|
746
|
+
/**
|
|
747
|
+
* How a pushed event is delivered: `alert` with a banner and sound, `silent` to the notification list only (iOS
|
|
748
|
+
* `interruptionLevel` `passive`, the Android `updates` channel). An event the device leaves out of `events` is off.
|
|
749
|
+
*/
|
|
750
|
+
declare const NOTIFICATION_LEVELS: readonly ["alert", "silent"];
|
|
751
|
+
type NotificationLevel = (typeof NOTIFICATION_LEVELS)[number];
|
|
752
|
+
/**
|
|
753
|
+
* When pushes stay silent, in minutes after midnight in the phone's IANA `timeZone`; an `end` before `start` spans
|
|
754
|
+
* midnight. A problem that still holds when they end is pushed then; events during them are not.
|
|
755
|
+
*/
|
|
756
|
+
interface QuietHours {
|
|
757
|
+
start: number;
|
|
758
|
+
end: number;
|
|
759
|
+
timeZone: string;
|
|
760
|
+
}
|
|
761
|
+
/**
|
|
762
|
+
* Asks the server to push this device's notifications through the Expo push service to `token`, an Expo push
|
|
763
|
+
* token, for at least one event. Registering again replaces the previous registration. `ref` is echoed as
|
|
764
|
+
* `data.ref` in every push, so the phone can tell which Mac sent it. `stuckMinutes` is how long a driven workspace
|
|
765
|
+
* must show no activity to look stuck, 15 by default. `levels` sets each event's delivery; an event it leaves out
|
|
766
|
+
* is silent. An older server ignores `levels`. `agentOnly` is accepted from older phones and ignored.
|
|
767
|
+
*/
|
|
768
|
+
interface PushRegisterParams {
|
|
769
|
+
token: string;
|
|
770
|
+
events: (PushEvent | LegacyPushEvent)[];
|
|
771
|
+
levels?: Partial<Record<PushEvent, NotificationLevel>>;
|
|
772
|
+
agentOnly?: boolean;
|
|
773
|
+
ref: string;
|
|
774
|
+
stuckMinutes?: number;
|
|
775
|
+
quietHours?: QuietHours;
|
|
776
|
+
}
|
|
777
|
+
/** Why the registered phones did not get a logged notification when it happened. */
|
|
778
|
+
declare const NOTIFICATION_SUPPRESSIONS: readonly ["muted", "quiet-hours"];
|
|
779
|
+
type NotificationSuppression = (typeof NOTIFICATION_SUPPRESSIONS)[number];
|
|
780
|
+
/** What a logged notification opens, as its push's `data` does. */
|
|
781
|
+
type NotificationTarget = {
|
|
782
|
+
kind: "machine";
|
|
783
|
+
} | {
|
|
784
|
+
kind: "workspace";
|
|
785
|
+
path: string;
|
|
786
|
+
} | {
|
|
787
|
+
kind: "device";
|
|
788
|
+
path: string;
|
|
789
|
+
platform: Platform;
|
|
790
|
+
slot: string;
|
|
791
|
+
} | {
|
|
792
|
+
kind: "build";
|
|
793
|
+
path: string;
|
|
794
|
+
platform: BuildPlatform;
|
|
795
|
+
} | {
|
|
796
|
+
kind: "url";
|
|
797
|
+
path: string;
|
|
798
|
+
url: string;
|
|
799
|
+
};
|
|
800
|
+
/**
|
|
801
|
+
* One oversight notification the server generated, whether or not it was pushed. `seq` grows by one per entry in
|
|
802
|
+
* a log; `id` names the workspace or machine and category, as a push's collapse id does, so a later episode shares
|
|
803
|
+
* it. `suppressed` is set when no registered phone got it at `at`: `muted` when none wants its category,
|
|
804
|
+
* `quiet-hours` when those that do were in quiet hours; a problem that still held when they ended was pushed then.
|
|
805
|
+
*/
|
|
806
|
+
interface NotificationEntry {
|
|
807
|
+
seq: number;
|
|
808
|
+
at: string;
|
|
809
|
+
id: string;
|
|
810
|
+
category: PushEvent;
|
|
811
|
+
title: string;
|
|
812
|
+
body: string;
|
|
813
|
+
/** The event's default delivery; a device's `levels` decide how its push was delivered. */
|
|
814
|
+
quiet: boolean;
|
|
815
|
+
target: NotificationTarget;
|
|
816
|
+
suppressed?: NotificationSuppression;
|
|
817
|
+
}
|
|
818
|
+
/** Returns only the entries after `since`, a `cursor` an earlier list returned. */
|
|
819
|
+
interface NotificationsListParams {
|
|
820
|
+
since?: number;
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* The server's notification history, newest first. `log` changes when the history starts over, so a cursor or
|
|
824
|
+
* read state kept for another `log` no longer applies; `cursor` is the newest `seq`, 0 for an empty log.
|
|
825
|
+
*/
|
|
826
|
+
interface NotificationsListResult {
|
|
827
|
+
log: string;
|
|
828
|
+
cursor: number;
|
|
829
|
+
notifications: NotificationEntry[];
|
|
830
|
+
}
|
|
831
|
+
interface WorkspaceFile {
|
|
832
|
+
path: string;
|
|
833
|
+
staged: boolean;
|
|
834
|
+
unstaged: boolean;
|
|
835
|
+
untracked: boolean;
|
|
836
|
+
status: string;
|
|
837
|
+
}
|
|
838
|
+
interface WorkspaceFiles {
|
|
839
|
+
files: WorkspaceFile[];
|
|
840
|
+
truncated: boolean;
|
|
841
|
+
}
|
|
842
|
+
interface WorkspacePatch {
|
|
843
|
+
section: "staged" | "unstaged" | "untracked";
|
|
844
|
+
kind: "text" | "binary" | "too-large" | "unavailable";
|
|
845
|
+
text: string;
|
|
846
|
+
}
|
|
847
|
+
interface WorkspaceDiff {
|
|
848
|
+
path: string;
|
|
849
|
+
patches: WorkspacePatch[];
|
|
850
|
+
}
|
|
851
|
+
/** A `.tgz` package of a client-supplied stim-server build: its file name, size in bytes and sha256. */
|
|
852
|
+
interface ServerUpdatePackage {
|
|
853
|
+
name: string;
|
|
854
|
+
size: number;
|
|
855
|
+
sha256: string;
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* What `server.update.start` installs: an exact stim-server `release` from the public npm registry, or the
|
|
859
|
+
* `packages` of a client's own build, which the Mac takes only while its `server.acceptClientBuilds` is true.
|
|
860
|
+
*/
|
|
861
|
+
type ServerUpdateStartParams = {
|
|
862
|
+
release: string;
|
|
863
|
+
} | {
|
|
864
|
+
packages: ServerUpdatePackage[];
|
|
865
|
+
};
|
|
866
|
+
/**
|
|
867
|
+
* An update this server runs. `uploading` waits for the rest of the packages; `installing` runs
|
|
868
|
+
* `stim-server service update`, whose last `log` lines say how far it got. The connection closes when the job
|
|
869
|
+
* restarts; the new server's `hello` and `server.update.status` then tell how it ended.
|
|
870
|
+
*/
|
|
871
|
+
interface ServerUpdateProgress {
|
|
872
|
+
id: string;
|
|
873
|
+
by: {
|
|
874
|
+
id: string;
|
|
875
|
+
name: string;
|
|
876
|
+
};
|
|
877
|
+
target: string;
|
|
878
|
+
state: "uploading" | "installing";
|
|
879
|
+
startedAt: string;
|
|
880
|
+
missing: {
|
|
881
|
+
name: string;
|
|
882
|
+
offset: number;
|
|
883
|
+
}[];
|
|
884
|
+
log: string[];
|
|
885
|
+
}
|
|
886
|
+
interface ServerUpdateOutcome {
|
|
887
|
+
at: string;
|
|
888
|
+
target: string;
|
|
889
|
+
ok: boolean;
|
|
890
|
+
message: string;
|
|
891
|
+
}
|
|
892
|
+
/**
|
|
893
|
+
* Whether this server can update itself, and how. `service` is the `stim-server service` label it runs under, or
|
|
894
|
+
* null when it does not run as a service and so cannot update itself. `last` is how the last `service update`
|
|
895
|
+
* of that label ended, whoever ran it.
|
|
896
|
+
*/
|
|
897
|
+
interface ServerUpdateStatus {
|
|
898
|
+
server: {
|
|
899
|
+
version: string;
|
|
900
|
+
stimBuild: string | null;
|
|
901
|
+
};
|
|
902
|
+
service: string | null;
|
|
903
|
+
acceptsClientBuilds: boolean;
|
|
904
|
+
running: ServerUpdateProgress | null;
|
|
905
|
+
last: ServerUpdateOutcome | null;
|
|
906
|
+
}
|
|
907
|
+
/**
|
|
908
|
+
* Where an update this Mac asked `machine` for stands: the host's own `server.update.status`, or why it could not be
|
|
909
|
+
* read (`unreachable`, also while the host restarts), and how much of this Mac's build it has sent.
|
|
910
|
+
*/
|
|
911
|
+
interface MachineUpdateStatus {
|
|
912
|
+
remote: ServerUpdateStatus | null;
|
|
913
|
+
unreachable: string | null;
|
|
914
|
+
upload: {
|
|
915
|
+
sent: number;
|
|
916
|
+
total: number;
|
|
917
|
+
error: string | null;
|
|
918
|
+
} | null;
|
|
919
|
+
}
|
|
920
|
+
interface Methods {
|
|
921
|
+
"machines.update.start": {
|
|
922
|
+
params: {
|
|
923
|
+
machine: string;
|
|
924
|
+
};
|
|
925
|
+
result: ServerUpdateProgress;
|
|
926
|
+
};
|
|
927
|
+
"machines.update.status": {
|
|
928
|
+
params: {
|
|
929
|
+
machine: string;
|
|
930
|
+
};
|
|
931
|
+
result: MachineUpdateStatus;
|
|
932
|
+
};
|
|
933
|
+
"server.update.status": {
|
|
934
|
+
params?: Record<string, never>;
|
|
935
|
+
result: ServerUpdateStatus;
|
|
936
|
+
};
|
|
937
|
+
"server.update.start": {
|
|
938
|
+
params: ServerUpdateStartParams;
|
|
939
|
+
result: ServerUpdateProgress;
|
|
940
|
+
};
|
|
941
|
+
"server.update.chunk": {
|
|
942
|
+
params: {
|
|
943
|
+
id: string;
|
|
944
|
+
name: string;
|
|
945
|
+
offset: number;
|
|
946
|
+
data: string;
|
|
947
|
+
};
|
|
948
|
+
result: ServerUpdateProgress;
|
|
949
|
+
};
|
|
950
|
+
"workspace.files": {
|
|
951
|
+
params: {
|
|
952
|
+
workspace: string;
|
|
953
|
+
group: "changed" | "untracked";
|
|
954
|
+
};
|
|
955
|
+
result: WorkspaceFiles;
|
|
956
|
+
};
|
|
957
|
+
"workspace.diff": {
|
|
958
|
+
params: {
|
|
959
|
+
workspace: string;
|
|
960
|
+
path: string;
|
|
961
|
+
};
|
|
962
|
+
result: WorkspaceDiff;
|
|
963
|
+
};
|
|
964
|
+
"device-host.offer": {
|
|
965
|
+
params: HostedDeviceOfferRequest;
|
|
966
|
+
result: HostedDeviceOffer;
|
|
967
|
+
};
|
|
968
|
+
"route.setup": {
|
|
969
|
+
params?: Record<string, never>;
|
|
970
|
+
result: ServeRoute;
|
|
971
|
+
};
|
|
972
|
+
"device-host.reserve": {
|
|
973
|
+
params: HostedDeviceRequest;
|
|
974
|
+
result: HostedDeviceSession;
|
|
975
|
+
};
|
|
976
|
+
"device-host.attach": {
|
|
977
|
+
params: {
|
|
978
|
+
session: string;
|
|
979
|
+
} | {
|
|
980
|
+
attempt: string;
|
|
981
|
+
};
|
|
982
|
+
result: HostedDeviceSession;
|
|
983
|
+
};
|
|
984
|
+
"device-host.stop": {
|
|
985
|
+
params: {
|
|
986
|
+
session: string;
|
|
987
|
+
};
|
|
988
|
+
result: HostedDeviceSession;
|
|
989
|
+
};
|
|
990
|
+
"device-host.app.offer": {
|
|
991
|
+
params: HostedAppOffer;
|
|
992
|
+
result: {
|
|
993
|
+
delivery: HostedAppDelivery;
|
|
994
|
+
missing: {
|
|
995
|
+
sha256: string;
|
|
996
|
+
size: number;
|
|
997
|
+
offset: number;
|
|
998
|
+
}[];
|
|
999
|
+
};
|
|
1000
|
+
};
|
|
1001
|
+
"device-host.app.chunk": {
|
|
1002
|
+
params: {
|
|
1003
|
+
session: string;
|
|
1004
|
+
attempt: string;
|
|
1005
|
+
sha256: string;
|
|
1006
|
+
offset: number;
|
|
1007
|
+
data: string;
|
|
1008
|
+
};
|
|
1009
|
+
result: {
|
|
1010
|
+
offset: number;
|
|
1011
|
+
};
|
|
1012
|
+
};
|
|
1013
|
+
"device-host.app.handoff": {
|
|
1014
|
+
params: {
|
|
1015
|
+
session: string;
|
|
1016
|
+
attempt: string;
|
|
1017
|
+
build: {
|
|
1018
|
+
handoff: string;
|
|
1019
|
+
sha256: string;
|
|
1020
|
+
};
|
|
1021
|
+
};
|
|
1022
|
+
result: {
|
|
1023
|
+
files: number;
|
|
1024
|
+
bytes: number;
|
|
1025
|
+
};
|
|
1026
|
+
};
|
|
1027
|
+
"device-host.app.launch": {
|
|
1028
|
+
params: {
|
|
1029
|
+
session: string;
|
|
1030
|
+
attempt: string;
|
|
1031
|
+
};
|
|
1032
|
+
result: HostedAppLaunch;
|
|
1033
|
+
};
|
|
1034
|
+
"device-host.app.attach": {
|
|
1035
|
+
params: {
|
|
1036
|
+
session: string;
|
|
1037
|
+
attempt: string;
|
|
1038
|
+
};
|
|
1039
|
+
result: HostedAppLaunch;
|
|
1040
|
+
};
|
|
1041
|
+
"device-host.logs.query": {
|
|
1042
|
+
params: {
|
|
1043
|
+
session: string;
|
|
1044
|
+
cursor?: HostedLogsCursor;
|
|
1045
|
+
};
|
|
1046
|
+
result: HostedLogsPage;
|
|
1047
|
+
};
|
|
1048
|
+
"device-host.metro.open": {
|
|
1049
|
+
params: {
|
|
1050
|
+
session: string;
|
|
1051
|
+
gatewayPort: number;
|
|
1052
|
+
secret: string;
|
|
1053
|
+
};
|
|
1054
|
+
result: {
|
|
1055
|
+
port: number;
|
|
1056
|
+
};
|
|
1057
|
+
};
|
|
1058
|
+
"device-host.metro.close": {
|
|
1059
|
+
params: {
|
|
1060
|
+
session: string;
|
|
1061
|
+
};
|
|
1062
|
+
result: {
|
|
1063
|
+
port: null;
|
|
1064
|
+
};
|
|
1065
|
+
};
|
|
1066
|
+
"device-host.frames.subscribe": {
|
|
1067
|
+
params: {
|
|
1068
|
+
session: string;
|
|
1069
|
+
fps?: number;
|
|
1070
|
+
maxEdge?: number;
|
|
1071
|
+
video?: string[];
|
|
1072
|
+
};
|
|
1073
|
+
result: FramesSubscribeResult;
|
|
1074
|
+
};
|
|
1075
|
+
"device-host.frames.keyframe": Methods["frames.keyframe"];
|
|
1076
|
+
"device-host.frames.congested": Methods["frames.keyframe"];
|
|
1077
|
+
"device-host.unsubscribe": Methods["unsubscribe"];
|
|
1078
|
+
"device-host.control.begin": {
|
|
1079
|
+
params: {
|
|
1080
|
+
session: string;
|
|
1081
|
+
takeOver?: boolean;
|
|
1082
|
+
};
|
|
1083
|
+
result: ControlBeginResult;
|
|
1084
|
+
};
|
|
1085
|
+
"device-host.control.end": Methods["control.end"];
|
|
1086
|
+
"device-host.input.touch": Methods["input.touch"];
|
|
1087
|
+
"device-host.input.text": Methods["input.text"];
|
|
1088
|
+
"device-host.input.scroll": Methods["input.scroll"];
|
|
1089
|
+
"device-host.input.key": Methods["input.key"];
|
|
1090
|
+
"device-host.input.button": Methods["input.button"];
|
|
1091
|
+
"device-host.input.rotate": Methods["input.rotate"];
|
|
1092
|
+
"device-host.input.posture": Methods["input.posture"];
|
|
1093
|
+
"device-host.input.window": Methods["input.window"];
|
|
1094
|
+
hello: {
|
|
1095
|
+
params: HelloParams;
|
|
1096
|
+
result: HelloResult;
|
|
1097
|
+
};
|
|
1098
|
+
"status.subscribe": {
|
|
1099
|
+
params?: Record<string, never>;
|
|
1100
|
+
result: SubscribeResult;
|
|
1101
|
+
};
|
|
1102
|
+
"logs.query": {
|
|
1103
|
+
params: LogFilter;
|
|
1104
|
+
result: LogsQueryResult;
|
|
1105
|
+
};
|
|
1106
|
+
"logs.subscribe": {
|
|
1107
|
+
params: LogFilter;
|
|
1108
|
+
result: SubscribeResult;
|
|
1109
|
+
};
|
|
1110
|
+
"stats.get": {
|
|
1111
|
+
params?: WorkspaceParams;
|
|
1112
|
+
result: StatsResult;
|
|
1113
|
+
};
|
|
1114
|
+
"settings.get": {
|
|
1115
|
+
params?: WorkspaceParams;
|
|
1116
|
+
result: SettingsResult;
|
|
1117
|
+
};
|
|
1118
|
+
"frames.subscribe": {
|
|
1119
|
+
params: FrameTarget;
|
|
1120
|
+
result: FramesSubscribeResult;
|
|
1121
|
+
};
|
|
1122
|
+
"frames.keyframe": {
|
|
1123
|
+
params: KeyframeParams;
|
|
1124
|
+
result: Record<string, never>;
|
|
1125
|
+
};
|
|
1126
|
+
"frames.seek": {
|
|
1127
|
+
params: FramesSeekParams;
|
|
1128
|
+
result: FramesSeekResult;
|
|
1129
|
+
};
|
|
1130
|
+
"frames.live": {
|
|
1131
|
+
params: FramesLiveParams;
|
|
1132
|
+
result: Record<string, never>;
|
|
1133
|
+
};
|
|
1134
|
+
"replay.range": {
|
|
1135
|
+
params: ReplayTarget;
|
|
1136
|
+
result: ReplayRange;
|
|
1137
|
+
};
|
|
1138
|
+
"replay.keyframe": {
|
|
1139
|
+
params: ReplayKeyframeParams;
|
|
1140
|
+
result: ReplayKeyframe;
|
|
1141
|
+
};
|
|
1142
|
+
"recording.set": {
|
|
1143
|
+
params: RecordingSetParams;
|
|
1144
|
+
result: RecordingSetResult;
|
|
1145
|
+
};
|
|
1146
|
+
"build.plan": {
|
|
1147
|
+
params: BuildPlanParams;
|
|
1148
|
+
result: BuildPlanResult;
|
|
1149
|
+
};
|
|
1150
|
+
"machine.get": {
|
|
1151
|
+
params?: Record<string, never>;
|
|
1152
|
+
result: MachineUsage;
|
|
1153
|
+
};
|
|
1154
|
+
"machine.history": {
|
|
1155
|
+
params?: MachineHistoryParams;
|
|
1156
|
+
result: MachineHistory;
|
|
1157
|
+
};
|
|
1158
|
+
"machine.details": {
|
|
1159
|
+
params?: Record<string, never>;
|
|
1160
|
+
result: MachineDetails;
|
|
1161
|
+
};
|
|
1162
|
+
unsubscribe: {
|
|
1163
|
+
params: UnsubscribeParams;
|
|
1164
|
+
result: Record<string, never>;
|
|
1165
|
+
};
|
|
1166
|
+
action: {
|
|
1167
|
+
params: ActionParams;
|
|
1168
|
+
result: ActionResult;
|
|
1169
|
+
};
|
|
1170
|
+
"control.begin": {
|
|
1171
|
+
params: ControlBeginParams;
|
|
1172
|
+
result: ControlBeginResult;
|
|
1173
|
+
};
|
|
1174
|
+
"control.end": {
|
|
1175
|
+
params: ControlEndParams;
|
|
1176
|
+
result: Record<string, never>;
|
|
1177
|
+
};
|
|
1178
|
+
"input.touch": {
|
|
1179
|
+
params: InputTouchParams;
|
|
1180
|
+
result: Record<string, never>;
|
|
1181
|
+
};
|
|
1182
|
+
"input.text": {
|
|
1183
|
+
params: InputTextParams;
|
|
1184
|
+
result: Record<string, never>;
|
|
1185
|
+
};
|
|
1186
|
+
"input.button": {
|
|
1187
|
+
params: InputButtonParams;
|
|
1188
|
+
result: Record<string, never>;
|
|
1189
|
+
};
|
|
1190
|
+
"input.rotate": {
|
|
1191
|
+
params: InputRotateParams;
|
|
1192
|
+
result: Record<string, never>;
|
|
1193
|
+
};
|
|
1194
|
+
"input.posture": {
|
|
1195
|
+
params: InputPostureParams;
|
|
1196
|
+
result: Record<string, never>;
|
|
1197
|
+
};
|
|
1198
|
+
"input.simulator": {
|
|
1199
|
+
params: InputSimulatorParams;
|
|
1200
|
+
result: SimulatorOptions;
|
|
1201
|
+
};
|
|
1202
|
+
"input.scroll": {
|
|
1203
|
+
params: InputScrollParams;
|
|
1204
|
+
result: Record<string, never>;
|
|
1205
|
+
};
|
|
1206
|
+
"input.key": {
|
|
1207
|
+
params: InputKeyParams;
|
|
1208
|
+
result: Record<string, never>;
|
|
1209
|
+
};
|
|
1210
|
+
"input.window": {
|
|
1211
|
+
params: InputWindowParams;
|
|
1212
|
+
result: Record<string, never>;
|
|
1213
|
+
};
|
|
1214
|
+
"push.register": {
|
|
1215
|
+
params: PushRegisterParams;
|
|
1216
|
+
result: Record<string, never>;
|
|
1217
|
+
};
|
|
1218
|
+
"push.unregister": {
|
|
1219
|
+
params?: Record<string, never>;
|
|
1220
|
+
result: Record<string, never>;
|
|
1221
|
+
};
|
|
1222
|
+
"notifications.list": {
|
|
1223
|
+
params?: NotificationsListParams;
|
|
1224
|
+
result: NotificationsListResult;
|
|
1225
|
+
};
|
|
1226
|
+
"build.offer": {
|
|
1227
|
+
params: BuildOfferParams;
|
|
1228
|
+
result: BuildOfferResult;
|
|
1229
|
+
};
|
|
1230
|
+
"build.sync": {
|
|
1231
|
+
params: BuildSyncParams;
|
|
1232
|
+
result: BuildSyncResult;
|
|
1233
|
+
};
|
|
1234
|
+
"build.start": {
|
|
1235
|
+
params: BuildStartParams;
|
|
1236
|
+
result: BuildJobParams;
|
|
1237
|
+
};
|
|
1238
|
+
"build.cancel": {
|
|
1239
|
+
params: BuildJobParams;
|
|
1240
|
+
result: Record<string, never>;
|
|
1241
|
+
};
|
|
1242
|
+
"build.artifact": {
|
|
1243
|
+
params: BuildJobParams;
|
|
1244
|
+
result: BuildArtifactResult;
|
|
1245
|
+
};
|
|
1246
|
+
"build.attach": {
|
|
1247
|
+
params: BuildJobParams;
|
|
1248
|
+
result: BuildAttachResult;
|
|
1249
|
+
};
|
|
1250
|
+
}
|
|
1251
|
+
type ClientRequest = { [M in Method]: {
|
|
1252
|
+
id: RequestId;
|
|
1253
|
+
method: M;
|
|
1254
|
+
} & Pick<Methods[M], "params">; }[Method];
|
|
1255
|
+
interface ProtocolError {
|
|
1256
|
+
code: ErrorCode;
|
|
1257
|
+
message: string;
|
|
1258
|
+
}
|
|
1259
|
+
type ServerResponse = {
|
|
1260
|
+
id: RequestId;
|
|
1261
|
+
result: Methods[Method]["result"];
|
|
1262
|
+
} | {
|
|
1263
|
+
id: RequestId | null;
|
|
1264
|
+
error: ProtocolError;
|
|
1265
|
+
};
|
|
1266
|
+
/** One CPU and memory series of {@link UsageHistory}: `cpuPercent` is ps %CPU, where 100 is one core. */
|
|
1267
|
+
interface UsageSeries {
|
|
1268
|
+
cpuPercent: (number | null)[];
|
|
1269
|
+
memoryMb: (number | null)[];
|
|
1270
|
+
}
|
|
1271
|
+
/** A simulator's or emulator's series; `id` is its UDID or AVD name, as its machine owner names it. */
|
|
1272
|
+
interface DeviceUsageSeries extends UsageSeries {
|
|
1273
|
+
kind: "simulator" | "emulator";
|
|
1274
|
+
id: string;
|
|
1275
|
+
workspace: string | null;
|
|
1276
|
+
slot?: string;
|
|
1277
|
+
}
|
|
1278
|
+
/**
|
|
1279
|
+
* The last 10 minutes of CPU and memory the server read from status payloads while a client was connected, in slots
|
|
1280
|
+
* of `intervalMs`, oldest first: point `i` of `n` is at `endAt - (n - 1 - i) * intervalMs`, null where no payload
|
|
1281
|
+
* fell in its slot. An environment's series sums every machine owner of that `workspace`, an environment `path`.
|
|
1282
|
+
*/
|
|
1283
|
+
interface UsageHistory {
|
|
1284
|
+
intervalMs: number;
|
|
1285
|
+
endAt: number;
|
|
1286
|
+
environments: (UsageSeries & {
|
|
1287
|
+
workspace: string;
|
|
1288
|
+
})[];
|
|
1289
|
+
devices: DeviceUsageSeries[];
|
|
1290
|
+
}
|
|
1291
|
+
/** A full status payload, as `stim status --watch --json` prints it, and the server's usage history, when it has one. */
|
|
1292
|
+
interface StatusEvent {
|
|
1293
|
+
event: "status";
|
|
1294
|
+
subscription: string;
|
|
1295
|
+
payload: StatusPayload;
|
|
1296
|
+
usage?: UsageHistory;
|
|
1297
|
+
/** `grantedAt` of the device leases this server holds for phones; absent when it holds none. */
|
|
1298
|
+
ownLeases?: string[];
|
|
1299
|
+
}
|
|
1300
|
+
/**
|
|
1301
|
+
* Records for a `logs.subscribe` subscription: first the last `tail` matching records, then new ones as
|
|
1302
|
+
* they arrive.
|
|
1303
|
+
*/
|
|
1304
|
+
interface LogsEvent {
|
|
1305
|
+
event: "logs";
|
|
1306
|
+
subscription: string;
|
|
1307
|
+
records: LogRecord[];
|
|
1308
|
+
}
|
|
1309
|
+
/** A subscription ended because its source failed or the client fell behind; the client may resubscribe. */
|
|
1310
|
+
interface ErrorEvent {
|
|
1311
|
+
event: "error";
|
|
1312
|
+
subscription: string;
|
|
1313
|
+
error: ProtocolError;
|
|
1314
|
+
}
|
|
1315
|
+
/** A frame of the device's screen, sent when the screen changed, at most `fps` times a second. */
|
|
1316
|
+
/** Installed device artwork rasterized on the Mac; layers contain PNG bytes, never a local path. */
|
|
1317
|
+
interface DeviceFrameArtwork {
|
|
1318
|
+
width: number;
|
|
1319
|
+
height: number;
|
|
1320
|
+
aperture: {
|
|
1321
|
+
x: number;
|
|
1322
|
+
y: number;
|
|
1323
|
+
width: number;
|
|
1324
|
+
height: number;
|
|
1325
|
+
};
|
|
1326
|
+
cornerRadius: number;
|
|
1327
|
+
quarterTurns: number;
|
|
1328
|
+
background: string;
|
|
1329
|
+
foreground: string;
|
|
1330
|
+
}
|
|
1331
|
+
interface DeviceFrameEvent {
|
|
1332
|
+
event: "device-frame";
|
|
1333
|
+
subscription: string;
|
|
1334
|
+
artwork: DeviceFrameArtwork | null;
|
|
1335
|
+
}
|
|
1336
|
+
interface MacosWindow {
|
|
1337
|
+
id: number;
|
|
1338
|
+
title: string;
|
|
1339
|
+
frame: {
|
|
1340
|
+
x: number;
|
|
1341
|
+
y: number;
|
|
1342
|
+
width: number;
|
|
1343
|
+
height: number;
|
|
1344
|
+
};
|
|
1345
|
+
}
|
|
1346
|
+
/**
|
|
1347
|
+
* Sent after subscribing and when the captured window, window list or pin mode changes. `pinned` is true while
|
|
1348
|
+
* `input.window` pins the view to `current`, and false while following the front window.
|
|
1349
|
+
*/
|
|
1350
|
+
interface MacosWindowsEvent {
|
|
1351
|
+
event: "macos-windows";
|
|
1352
|
+
subscription: string;
|
|
1353
|
+
current: MacosWindow | null;
|
|
1354
|
+
windows: MacosWindow[];
|
|
1355
|
+
pinned: boolean;
|
|
1356
|
+
}
|
|
1357
|
+
interface DuoFramePose {
|
|
1358
|
+
revision: string;
|
|
1359
|
+
screenID: number;
|
|
1360
|
+
angle: number;
|
|
1361
|
+
orientation: number;
|
|
1362
|
+
}
|
|
1363
|
+
interface FrameEvent {
|
|
1364
|
+
event: "frame";
|
|
1365
|
+
subscription: string;
|
|
1366
|
+
platform: Platform;
|
|
1367
|
+
slot: string;
|
|
1368
|
+
mime: "image/jpeg";
|
|
1369
|
+
width: number;
|
|
1370
|
+
height: number;
|
|
1371
|
+
capturedAt: string;
|
|
1372
|
+
/** Base64-encoded image bytes. */
|
|
1373
|
+
data: string;
|
|
1374
|
+
/**
|
|
1375
|
+
* An iPhone Duo's or Android foldable emulator's posture. A Duo reports the panel it lit: the cover when
|
|
1376
|
+
* folded, the inner panel when unfolded. An emulator with a hinge reports `folded` while it shows only its
|
|
1377
|
+
* outer display, and `unfolded` otherwise, including half open.
|
|
1378
|
+
*/
|
|
1379
|
+
posture?: "folded" | "unfolded";
|
|
1380
|
+
/** Clockwise artwork rotation captured with this frame. */
|
|
1381
|
+
artworkTurns?: number;
|
|
1382
|
+
duo?: DuoFramePose;
|
|
1383
|
+
}
|
|
1384
|
+
/**
|
|
1385
|
+
* Captures for a `frames.subscribe` subscription are slow or a timed-out capture is being retried; the
|
|
1386
|
+
* client keeps showing its last frame. Followed by `delayed: false` once captures recover. `reason` says why
|
|
1387
|
+
* frames stopped when the server knows, such as a locked iPhone or one another app captures.
|
|
1388
|
+
*/
|
|
1389
|
+
interface FrameDelayedEvent {
|
|
1390
|
+
event: "frame-delayed";
|
|
1391
|
+
subscription: string;
|
|
1392
|
+
delayed: boolean;
|
|
1393
|
+
reason?: string;
|
|
1394
|
+
}
|
|
1395
|
+
declare const CONTROL_END_REASONS: readonly ["idle", "taken-over", "device-gone", "forbidden", "failed"];
|
|
1396
|
+
/**
|
|
1397
|
+
* The server ended a control session: no input for 5 minutes, another client took the device over, the device
|
|
1398
|
+
* stopped or changed owner, the device lost `control`, or input could not reach the device.
|
|
1399
|
+
*/
|
|
1400
|
+
interface ControlEndedEvent {
|
|
1401
|
+
event: "control-ended";
|
|
1402
|
+
session: string;
|
|
1403
|
+
reason: (typeof CONTROL_END_REASONS)[number];
|
|
1404
|
+
message: string;
|
|
1405
|
+
}
|
|
1406
|
+
/** A notification the server just logged, sent to each connection that sent `notifications.list`. */
|
|
1407
|
+
interface NotificationEvent {
|
|
1408
|
+
event: "notification";
|
|
1409
|
+
log: string;
|
|
1410
|
+
notification: NotificationEntry;
|
|
1411
|
+
}
|
|
1412
|
+
/**
|
|
1413
|
+
* A build job's progress: a `phase` line, a build-log `record`, or, last, its `outcome`. The job ends with the
|
|
1414
|
+
* connection that started it.
|
|
1415
|
+
*/
|
|
1416
|
+
interface BuildProgressEvent {
|
|
1417
|
+
event: "build.progress";
|
|
1418
|
+
job: string;
|
|
1419
|
+
phase?: string;
|
|
1420
|
+
msg?: string;
|
|
1421
|
+
record?: Record<string, unknown>;
|
|
1422
|
+
outcome?: BuildJobOutcome;
|
|
1423
|
+
}
|
|
1424
|
+
type ServerEvent = BuildProgressEvent | NotificationEvent | StatusEvent | LogsEvent | FrameEvent | DeviceFrameEvent | MacosWindowsEvent | FrameDelayedEvent | ReplayEndedEvent | ErrorEvent | ControlEndedEvent;
|
|
1425
|
+
type ServerMessage = ServerResponse | ServerEvent;
|
|
1426
|
+
type ServeRoute = {
|
|
1427
|
+
state: "routed";
|
|
1428
|
+
port: number;
|
|
1429
|
+
} | {
|
|
1430
|
+
state: "funneled";
|
|
1431
|
+
ports: number[];
|
|
1432
|
+
port: number;
|
|
1433
|
+
} | {
|
|
1434
|
+
state: "missing";
|
|
1435
|
+
port: number;
|
|
1436
|
+
} | {
|
|
1437
|
+
state: "unknown";
|
|
1438
|
+
reason: string;
|
|
1439
|
+
port: number;
|
|
1440
|
+
};
|
|
1441
|
+
//#endregion
|
|
1442
|
+
export { FrameDelayedEvent as $, VIDEO_CODECS as $n, NotificationSuppression as $t, Capability as A, SERVER_UPDATE_METHODS as An, LogRecord as At, DeviceFrameArtwork as B, SettingsResult as Bn, MachineUpdateStatus as Bt, BuildRequestAuth as C, ReplayKeyframeParams as Cn, KeyframeParams as Ct, BuildToolchain as D, ReplayTarget as Dn, LegacyPushEvent as Dt, BuildSyncResult as E, ReplaySpan as En, LOG_SOURCES as Et, ControlEndedEvent as F, ServerUpdateOutcome as Fn, MAX_LOG_TAIL as Ft, DuoFramePose as G, SubscribeResult as Gn, MemoryPressure as Gt, DeviceHostRequestAuth as H, SimulatorOptions as Hn, MachineVolume as Ht, ControlPlatform as I, ServerUpdatePackage as In, METHODS as It, ErrorEvent as J, UnsubscribeParams as Jn, NOTIFICATION_LEVELS as Jt, ERROR_CODES as K, TOUCH_PHASES as Kn, Method as Kt, DEVICE_HOST_METHODS as L, ServerUpdateProgress as Ln, MachineDetails as Lt, ControlBeginParams as M, ServerEvent as Mn, LogsEvent as Mt, ControlBeginResult as N, ServerMessage as Nn, LogsQueryResult as Nt, CAPABILITIES as O, RequestId as On, LogFilter as Ot, ControlEndParams as P, ServerResponse as Pn, MAX_INPUT_TEXT as Pt, Feature as Q, VIDEO_ARTWORK as Qn, NotificationLevel as Qt, DEVICE_POSTURES as R, ServerUpdateStartParams as Rn, MachineHistory as Rt, BuildProgressEvent as S, ReplayKeyframe as Sn, KeyModifier as St, BuildSyncParams as T, ReplayRange as Tn, LOG_LEVELS as Tt, DevicePosture as U, StatsResult as Un, MacosWindow as Ut, DeviceFrameEvent as V, SimulatorCommand as Vn, MachineUsage as Vt, DeviceUsageSeries as W, StatusEvent as Wn, MacosWindowsEvent as Wt, FRAME_EDGE as X, UsageSample as Xn, NotificationEntry as Xt, FEATURES as Y, UsageHistory as Yn, NOTIFICATION_SUPPRESSIONS as Yt, FRAME_FPS as Z, UsageSeries as Zn, NotificationEvent as Zt, BuildOfferParams as _, ROTATE_DIRECTIONS as _n, InputSimulatorParams as _t, BUILD_METHODS as a, PROTOCOL_VERSION as an, VideoPacket as ar, FramesSubscribeResult as at, BuildPlanResult as b, ReloadPlatform as bn, InputWindowParams as bt, BuildArtifactResult as c, PairingAuth as cn, WorkspaceFiles as cr, INPUT_BUTTONS as ct, BuildClientSummary as d, PushEvent as dn, InputButtonParams as dt, NotificationTarget as en, VIDEO_FOLDED as er, FrameEvent as et, BuildFile as f, PushRegisterParams as fn, InputKey as ft, BuildMachineReport as g, REPLAY_RATES as gn, InputScrollParams as gt, BuildMachineCapacity as h, REPLAY_MARKER_KINDS as hn, InputRotateParams as ht, ActionResult as i, PROTOCOL_SCHEMA_FILE as in, VideoCodec as ir, FramesSeekResult as it, ClientRequest as j, ServeRoute as jn, LogSource as jt, CONTROL_END_REASONS as k, RotateDirection as kn, LogLevel as kt, BuildAttachResult as l, Platform as ln, WorkspaceParams as lr, INPUT_KEYS as lt, BuildJobParams as m, RELOAD_PLATFORMS as mn, InputPostureParams as mt, ActionName as n, NotificationsListResult as nn, VIDEO_KEYFRAME as nr, FramesLiveParams as nt, BUILD_REPO_PATTERN as o, PUSH_EVENTS as on, WorkspaceDiff as or, HelloParams as ot, BuildJobOutcome as p, QuietHours as pn, InputKeyParams as pt, ErrorCode as q, TouchPhase as qn, Methods as qt, ActionParams as r, PLATFORMS as rn, VIDEO_UNFOLDED as rr, FramesSeekParams as rt, BuildAndroidOptions as s, PUSH_TOKEN_PATTERN as sn, WorkspaceFile as sr, HelloResult as st, ACTIONS as t, NotificationsListParams as tn, VIDEO_HEADER_VERSION as tr, FrameTarget as tt, BuildCapacity as u, ProtocolError as un, WorkspacePatch as ur, InputButton as ut, BuildOfferResult as v, RecordingSetParams as vn, InputTextParams as vt, BuildStartParams as w, ReplayMarker as wn, LEGACY_PUSH_EVENTS as wt, BuildPlatform as x, ReplayEndedEvent as xn, KEY_MODIFIERS as xt, BuildPlanParams as y, RecordingSetResult as yn, InputTouchParams as yt, DeviceAuth as z, ServerUpdateStatus as zn, MachineHistoryParams as zt };
|