@stim-cli/server 0.0.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +139 -1
- package/dist/protocol-dn2_TUeH.mjs +393 -0
- package/dist/protocol.d.mts +187 -0
- package/dist/protocol.mjs +2 -0
- package/dist/protocol.schema.json +669 -0
- package/dist/stim-server.d.mts +1 -0
- package/dist/stim-server.mjs +1714 -0
- package/package.json +36 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Janic Duplessis
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,141 @@
|
|
|
1
1
|
# @stim-cli/server
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`stim-server` serves Stim state to paired read-only clients, such as the Stim
|
|
4
|
+
phone app. It runs on the Mac, next to Stim, and changes no Stim state: it
|
|
5
|
+
writes only its own pairing state under `$STIM_HOME/server/`.
|
|
6
|
+
|
|
7
|
+
The design is in
|
|
8
|
+
[`docs/specs/2026-09-25-stim-server-design.md`](../../docs/specs/2026-09-25-stim-server-design.md).
|
|
9
|
+
|
|
10
|
+
## Commands
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
stim-server [--port <n>] # serve paired clients, port 7787 by default
|
|
14
|
+
stim-server pair [--port <n>] # print a single-use pairing payload
|
|
15
|
+
stim-server devices [list] # list paired devices
|
|
16
|
+
stim-server devices revoke <id> # revoke a paired device
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`pair --json` prints `{ "qr": <payload>, "expiresAt": "<ISO time>" }`, and
|
|
20
|
+
`devices --json` prints `{ "devices": [...] }` with each device's `id`, `name`,
|
|
21
|
+
`identity`, `pairedAt`, `lastSeenAt` and `capabilities`, never its token hash.
|
|
22
|
+
|
|
23
|
+
`GET http://127.0.0.1:7787/health` answers requests from this Mac with the
|
|
24
|
+
server's name, versions, protocol, `stimHome`, and the Tailscale state it
|
|
25
|
+
started with. Stim Desktop uses it to find a running server. A request through
|
|
26
|
+
`tailscale serve`, on a Tailscale address, or with a `Host` other than
|
|
27
|
+
`127.0.0.1` or `localhost` gets HTTP 426, like any other plain HTTP request.
|
|
28
|
+
|
|
29
|
+
`stim-server` runs the `stim` version this package was released with, not the
|
|
30
|
+
one on your PATH. It reads the login shell's environment once at start, so
|
|
31
|
+
`PATH`, `ANDROID_HOME`, and `STIM_*` variables match your terminal even when
|
|
32
|
+
another app starts it.
|
|
33
|
+
|
|
34
|
+
## Tailscale
|
|
35
|
+
|
|
36
|
+
Tailscale carries and encrypts the traffic between the phone and the Mac, on
|
|
37
|
+
the same Wi-Fi or across networks, and identifies each device. Stim adds no
|
|
38
|
+
cryptography of its own. You need Tailscale on the Mac and on the phone, in the
|
|
39
|
+
same tailnet or with the Mac shared to the phone's user.
|
|
40
|
+
|
|
41
|
+
`stim-server` listens only on `127.0.0.1` and on the Mac's Tailscale
|
|
42
|
+
addresses, never on every interface. Run this once so clients can use
|
|
43
|
+
`wss://<mac>.<tailnet>.ts.net` with a valid certificate:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
tailscale serve --bg http://127.0.0.1:7787
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
When Tailscale is not running, `stim-server` listens on loopback only and
|
|
50
|
+
says so on stderr. Start Tailscale, then restart `stim-server`.
|
|
51
|
+
|
|
52
|
+
## Pairing
|
|
53
|
+
|
|
54
|
+
`stim-server pair` prints the JSON that the pairing QR code encodes:
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{ "v": 1, "name": "Janic's MacBook Pro", "endpoint": "wss://janics-mbp.tail1234.ts.net", "pairingToken": "..." }
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The pairing token works once and expires after 5 minutes. A client spends it in
|
|
61
|
+
`hello` and receives a random device token, which it presents on every later
|
|
62
|
+
connection. The server stores only the SHA-256 hash of each token.
|
|
63
|
+
|
|
64
|
+
At pairing, the server records the peer's tailnet node and user from
|
|
65
|
+
`tailscale whois`. A device token presented from any other node is refused, so
|
|
66
|
+
a leaked token alone is not enough. A device paired over loopback, from this
|
|
67
|
+
Mac, is accepted only over loopback. `tailscale serve` connects from loopback
|
|
68
|
+
and names the peer in `X-Forwarded-For`, which the server trusts only on
|
|
69
|
+
loopback connections. Forward only `tailscale serve` in HTTP mode to the
|
|
70
|
+
loopback port: a forwarder that omits that header, such as `tailscale serve
|
|
71
|
+
--tcp`, `ssh -L`, or a tunnel, makes every remote peer look like this Mac.
|
|
72
|
+
|
|
73
|
+
A connection must send `hello` within 5 seconds. Five failed attempts from the
|
|
74
|
+
same peer within a minute block new connections from it for up to a minute.
|
|
75
|
+
|
|
76
|
+
Paired devices live in `$STIM_HOME/server/devices.json`. Revoking a device
|
|
77
|
+
closes its open connections.
|
|
78
|
+
|
|
79
|
+
## Protocol
|
|
80
|
+
|
|
81
|
+
JSON messages over a WebSocket. Requests are `{ "id", "method", "params" }`,
|
|
82
|
+
answered by `{ "id", "result" }` or `{ "id", "error": { "code", "message" } }`.
|
|
83
|
+
Events are `{ "event", "subscription", ... }`.
|
|
84
|
+
|
|
85
|
+
- `hello` must come first. Params: `protocol` (1), `client` (`name`,
|
|
86
|
+
`version`), and `auth`, either `{ "pairingToken", "deviceName" }` or
|
|
87
|
+
`{ "deviceToken" }`. The result carries the server name and versions, the
|
|
88
|
+
granted capabilities (`read` only in protocol 1), the paired device, and the
|
|
89
|
+
new `deviceToken` when the hello paired.
|
|
90
|
+
- `status.subscribe` returns a subscription id. Each `status` event carries a
|
|
91
|
+
full payload as `stim status --watch --json` prints it. All subscribers share
|
|
92
|
+
one `stim status --watch --json` child, which stops with the last
|
|
93
|
+
subscriber.
|
|
94
|
+
- `logs.query` returns `{ "records" }`, and `logs.subscribe` sends `logs`
|
|
95
|
+
events: first the last `tail` matching records, then new ones in batches.
|
|
96
|
+
Both take the Stim Desktop log viewer's filters: `workspace` (required),
|
|
97
|
+
`sources` (`metro`, `client`, `device`, `build`), `slot`, `level` (the
|
|
98
|
+
minimum), `grep` (a regular expression), `errors`, and `tail` (1 to 5000,
|
|
99
|
+
5000 by default). Without `sources`, `errors` keeps the CLI's default error
|
|
100
|
+
scope. They run `stim logs --json` and `stim logs --json --follow` in the
|
|
101
|
+
workspace. Subscribers with the same workspace and filters share one
|
|
102
|
+
`--follow` child, which stops with the last of them.
|
|
103
|
+
- `stats.get` and `settings.get` return the payload of `stim stats --json` and
|
|
104
|
+
`stim settings --json`, which masks sensitive values. Without `workspace`,
|
|
105
|
+
they run in the home directory and cover the machine only.
|
|
106
|
+
- `frames.subscribe` takes `workspace`, `platform` (`ios` or `android`) and
|
|
107
|
+
`slot` (`default` when absent) and sends `frame` events: a JPEG screenshot,
|
|
108
|
+
base64 in `data`, with `width`, `height` and `capturedAt`. It serves only a
|
|
109
|
+
booted simulator or a running emulator that `stim status` lists as owned by
|
|
110
|
+
that workspace; any other device ends the subscription with a
|
|
111
|
+
`frames-failed` `error` event, and so does a device that stops or changes
|
|
112
|
+
owner. Simulators are captured with `xcrun simctl io <udid> screenshot`, of
|
|
113
|
+
the primary display, or of the default display when that `simctl` does not
|
|
114
|
+
accept `primary`. Emulators are captured through their gRPC `getScreenshot`,
|
|
115
|
+
found through the discovery file and token the emulator writes when Stim
|
|
116
|
+
boots it, scaled to fit 1280 pixels and converted with `sips`. An emulator
|
|
117
|
+
Stim booted before it passed `-grpc` has no endpoint. A frame is sent only
|
|
118
|
+
when the screen changed: up to 5 per second while it changes, backing off to
|
|
119
|
+
one capture per second while it does not, with capturing taking at most half
|
|
120
|
+
of each device's time. All subscribers of a device share one capture loop,
|
|
121
|
+
which sends a new subscriber the latest frame and stops with the last
|
|
122
|
+
subscriber, and at most two captures run at once. A client whose socket has
|
|
123
|
+
more than 1 MiB unsent skips frames and gets the newest once it catches up.
|
|
124
|
+
- `unsubscribe` ends a subscription.
|
|
125
|
+
- An `error` event ends a subscription whose source failed, or whose client
|
|
126
|
+
fell behind (`slow-client`); subscribe again.
|
|
127
|
+
|
|
128
|
+
`workspace` is an environment `path` from a status payload. Any other path is
|
|
129
|
+
refused with `unknown-workspace` and runs nothing. A connection holds at most
|
|
130
|
+
32 subscriptions and runs at most 4 `logs.query`, `stats.get` and
|
|
131
|
+
`settings.get` requests at a time. Those requests fail after 60 seconds or
|
|
132
|
+
32 MiB of output, and closing the connection stops them. A `stim` child that
|
|
133
|
+
ignores SIGTERM gets SIGKILL a second later. A log subscriber whose socket has more than
|
|
134
|
+
4 MiB unsent gets no more batches until it catches up; past 20,000
|
|
135
|
+
waiting records the server ends that subscription with `slow-client`.
|
|
136
|
+
|
|
137
|
+
The error codes `unauthorized`, `pairing-expired`, and `protocol-unsupported`
|
|
138
|
+
refuse the client until it pairs again or updates; clients retry the others.
|
|
139
|
+
|
|
140
|
+
The package exports the message types, and the build writes their JSON Schema
|
|
141
|
+
to `dist/protocol.schema.json`, exported as `@stim-cli/server/protocol.schema.json`.
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
//#region src/protocol.ts
|
|
2
|
+
const PROTOCOL_VERSION = 1;
|
|
3
|
+
const PROTOCOL_SCHEMA_FILE = "protocol.schema.json";
|
|
4
|
+
const CAPABILITIES = ["read"];
|
|
5
|
+
const METHODS = [
|
|
6
|
+
"hello",
|
|
7
|
+
"status.subscribe",
|
|
8
|
+
"logs.query",
|
|
9
|
+
"logs.subscribe",
|
|
10
|
+
"stats.get",
|
|
11
|
+
"settings.get",
|
|
12
|
+
"frames.subscribe",
|
|
13
|
+
"unsubscribe"
|
|
14
|
+
];
|
|
15
|
+
/**
|
|
16
|
+
* `unauthorized`, `pairing-expired` and `protocol-unsupported` refuse the client until it pairs again or
|
|
17
|
+
* updates; clients retry the others.
|
|
18
|
+
*/
|
|
19
|
+
const ERROR_CODES = [
|
|
20
|
+
"unauthorized",
|
|
21
|
+
"pairing-expired",
|
|
22
|
+
"protocol-unsupported",
|
|
23
|
+
"identity-unavailable",
|
|
24
|
+
"bad-request",
|
|
25
|
+
"unknown-method",
|
|
26
|
+
"already-authenticated",
|
|
27
|
+
"unknown-subscription",
|
|
28
|
+
"unknown-workspace",
|
|
29
|
+
"limit-exceeded",
|
|
30
|
+
"slow-client",
|
|
31
|
+
"status-failed",
|
|
32
|
+
"logs-failed",
|
|
33
|
+
"stim-failed",
|
|
34
|
+
"frames-failed"
|
|
35
|
+
];
|
|
36
|
+
const LOG_SOURCES = [
|
|
37
|
+
"metro",
|
|
38
|
+
"client",
|
|
39
|
+
"device",
|
|
40
|
+
"build"
|
|
41
|
+
];
|
|
42
|
+
const LOG_LEVELS = [
|
|
43
|
+
"debug",
|
|
44
|
+
"info",
|
|
45
|
+
"warn",
|
|
46
|
+
"error",
|
|
47
|
+
"fatal"
|
|
48
|
+
];
|
|
49
|
+
const MAX_LOG_TAIL = 5e3;
|
|
50
|
+
const requestId = { type: ["integer", "string"] };
|
|
51
|
+
const protocolError = {
|
|
52
|
+
type: "object",
|
|
53
|
+
required: ["code", "message"],
|
|
54
|
+
additionalProperties: false,
|
|
55
|
+
properties: {
|
|
56
|
+
code: { enum: [...ERROR_CODES] },
|
|
57
|
+
message: { type: "string" }
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
function request(method, params) {
|
|
61
|
+
return {
|
|
62
|
+
type: "object",
|
|
63
|
+
required: params ? [
|
|
64
|
+
"id",
|
|
65
|
+
"method",
|
|
66
|
+
"params"
|
|
67
|
+
] : ["id", "method"],
|
|
68
|
+
additionalProperties: false,
|
|
69
|
+
properties: {
|
|
70
|
+
id: requestId,
|
|
71
|
+
method: { const: method },
|
|
72
|
+
params: params ?? {
|
|
73
|
+
type: "object",
|
|
74
|
+
maxProperties: 0
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function optionalParams(method, params) {
|
|
80
|
+
return {
|
|
81
|
+
type: "object",
|
|
82
|
+
required: ["id", "method"],
|
|
83
|
+
additionalProperties: false,
|
|
84
|
+
properties: {
|
|
85
|
+
id: requestId,
|
|
86
|
+
method: { const: method },
|
|
87
|
+
params
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/** The JSON Schema of every message on the wire, written to `dist/protocol.schema.json` at build time. */
|
|
92
|
+
function protocolJsonSchema() {
|
|
93
|
+
return {
|
|
94
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
95
|
+
title: "Stim server protocol",
|
|
96
|
+
description: `Messages exchanged over the stim-server WebSocket, protocol version 1.`,
|
|
97
|
+
"x-stim-protocol": 1,
|
|
98
|
+
$defs: {
|
|
99
|
+
ProtocolError: protocolError,
|
|
100
|
+
HelloParams: {
|
|
101
|
+
type: "object",
|
|
102
|
+
required: [
|
|
103
|
+
"protocol",
|
|
104
|
+
"client",
|
|
105
|
+
"auth"
|
|
106
|
+
],
|
|
107
|
+
additionalProperties: false,
|
|
108
|
+
properties: {
|
|
109
|
+
protocol: { type: "integer" },
|
|
110
|
+
client: {
|
|
111
|
+
type: "object",
|
|
112
|
+
required: ["name", "version"],
|
|
113
|
+
properties: {
|
|
114
|
+
name: { type: "string" },
|
|
115
|
+
version: { type: "string" }
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
auth: { oneOf: [{
|
|
119
|
+
type: "object",
|
|
120
|
+
required: ["pairingToken", "deviceName"],
|
|
121
|
+
additionalProperties: false,
|
|
122
|
+
properties: {
|
|
123
|
+
pairingToken: { type: "string" },
|
|
124
|
+
deviceName: {
|
|
125
|
+
type: "string",
|
|
126
|
+
minLength: 1
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}, {
|
|
130
|
+
type: "object",
|
|
131
|
+
required: ["deviceToken"],
|
|
132
|
+
additionalProperties: false,
|
|
133
|
+
properties: { deviceToken: { type: "string" } }
|
|
134
|
+
}] }
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
HelloResult: {
|
|
138
|
+
type: "object",
|
|
139
|
+
required: [
|
|
140
|
+
"protocol",
|
|
141
|
+
"server",
|
|
142
|
+
"capabilities",
|
|
143
|
+
"device"
|
|
144
|
+
],
|
|
145
|
+
additionalProperties: false,
|
|
146
|
+
properties: {
|
|
147
|
+
protocol: { type: "integer" },
|
|
148
|
+
server: {
|
|
149
|
+
type: "object",
|
|
150
|
+
required: [
|
|
151
|
+
"name",
|
|
152
|
+
"version",
|
|
153
|
+
"stim"
|
|
154
|
+
],
|
|
155
|
+
additionalProperties: false,
|
|
156
|
+
properties: {
|
|
157
|
+
name: { type: "string" },
|
|
158
|
+
version: { type: "string" },
|
|
159
|
+
stim: { type: "string" }
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
capabilities: {
|
|
163
|
+
type: "array",
|
|
164
|
+
items: { enum: [...CAPABILITIES] }
|
|
165
|
+
},
|
|
166
|
+
device: {
|
|
167
|
+
type: "object",
|
|
168
|
+
required: ["id", "name"],
|
|
169
|
+
additionalProperties: false,
|
|
170
|
+
properties: {
|
|
171
|
+
id: { type: "string" },
|
|
172
|
+
name: { type: "string" }
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
deviceToken: { type: "string" }
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
LogRecord: {
|
|
179
|
+
type: "object",
|
|
180
|
+
description: "One record as `stim logs --json` prints it.",
|
|
181
|
+
properties: {
|
|
182
|
+
ts: { type: "number" },
|
|
183
|
+
src: { type: "string" },
|
|
184
|
+
level: { type: "string" },
|
|
185
|
+
msg: { type: "string" }
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
LogFilter: {
|
|
189
|
+
type: "object",
|
|
190
|
+
required: ["workspace"],
|
|
191
|
+
additionalProperties: false,
|
|
192
|
+
properties: {
|
|
193
|
+
workspace: {
|
|
194
|
+
type: "string",
|
|
195
|
+
description: "An environment path from a status payload."
|
|
196
|
+
},
|
|
197
|
+
sources: {
|
|
198
|
+
type: "array",
|
|
199
|
+
minItems: 1,
|
|
200
|
+
items: { enum: [...LOG_SOURCES] }
|
|
201
|
+
},
|
|
202
|
+
level: { enum: [...LOG_LEVELS] },
|
|
203
|
+
slot: {
|
|
204
|
+
type: "string",
|
|
205
|
+
minLength: 1
|
|
206
|
+
},
|
|
207
|
+
grep: {
|
|
208
|
+
type: "string",
|
|
209
|
+
description: "A regular expression matched against each message."
|
|
210
|
+
},
|
|
211
|
+
errors: { type: "boolean" },
|
|
212
|
+
tail: {
|
|
213
|
+
type: "integer",
|
|
214
|
+
minimum: 1,
|
|
215
|
+
maximum: MAX_LOG_TAIL,
|
|
216
|
+
default: MAX_LOG_TAIL
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
FrameTarget: {
|
|
221
|
+
type: "object",
|
|
222
|
+
required: ["workspace", "platform"],
|
|
223
|
+
additionalProperties: false,
|
|
224
|
+
properties: {
|
|
225
|
+
workspace: {
|
|
226
|
+
type: "string",
|
|
227
|
+
description: "An environment path from a status payload."
|
|
228
|
+
},
|
|
229
|
+
platform: { enum: ["ios", "android"] },
|
|
230
|
+
slot: {
|
|
231
|
+
type: "string",
|
|
232
|
+
minLength: 1,
|
|
233
|
+
default: "default"
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
WorkspaceParams: {
|
|
238
|
+
type: "object",
|
|
239
|
+
additionalProperties: false,
|
|
240
|
+
properties: { workspace: {
|
|
241
|
+
type: "string",
|
|
242
|
+
description: "An environment path from a status payload."
|
|
243
|
+
} }
|
|
244
|
+
},
|
|
245
|
+
ClientRequest: { oneOf: [
|
|
246
|
+
request("hello", { $ref: "#/$defs/HelloParams" }),
|
|
247
|
+
request("status.subscribe"),
|
|
248
|
+
request("logs.query", { $ref: "#/$defs/LogFilter" }),
|
|
249
|
+
request("logs.subscribe", { $ref: "#/$defs/LogFilter" }),
|
|
250
|
+
request("frames.subscribe", { $ref: "#/$defs/FrameTarget" }),
|
|
251
|
+
optionalParams("stats.get", { $ref: "#/$defs/WorkspaceParams" }),
|
|
252
|
+
optionalParams("settings.get", { $ref: "#/$defs/WorkspaceParams" }),
|
|
253
|
+
request("unsubscribe", {
|
|
254
|
+
type: "object",
|
|
255
|
+
required: ["subscription"],
|
|
256
|
+
additionalProperties: false,
|
|
257
|
+
properties: { subscription: { type: "string" } }
|
|
258
|
+
})
|
|
259
|
+
] },
|
|
260
|
+
ServerResponse: { oneOf: [{
|
|
261
|
+
type: "object",
|
|
262
|
+
required: ["id", "result"],
|
|
263
|
+
additionalProperties: false,
|
|
264
|
+
properties: {
|
|
265
|
+
id: requestId,
|
|
266
|
+
result: { anyOf: [
|
|
267
|
+
{ $ref: "#/$defs/HelloResult" },
|
|
268
|
+
{
|
|
269
|
+
type: "object",
|
|
270
|
+
required: ["subscription"],
|
|
271
|
+
additionalProperties: false,
|
|
272
|
+
properties: { subscription: { type: "string" } }
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
type: "object",
|
|
276
|
+
required: ["records"],
|
|
277
|
+
additionalProperties: false,
|
|
278
|
+
properties: { records: {
|
|
279
|
+
type: "array",
|
|
280
|
+
items: { $ref: "#/$defs/LogRecord" }
|
|
281
|
+
} }
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
type: "object",
|
|
285
|
+
description: "The payload of `stim stats --json` or `stim settings --json`, or {} for unsubscribe."
|
|
286
|
+
}
|
|
287
|
+
] }
|
|
288
|
+
}
|
|
289
|
+
}, {
|
|
290
|
+
type: "object",
|
|
291
|
+
required: ["id", "error"],
|
|
292
|
+
additionalProperties: false,
|
|
293
|
+
properties: {
|
|
294
|
+
id: { type: [
|
|
295
|
+
"integer",
|
|
296
|
+
"string",
|
|
297
|
+
"null"
|
|
298
|
+
] },
|
|
299
|
+
error: { $ref: "#/$defs/ProtocolError" }
|
|
300
|
+
}
|
|
301
|
+
}] },
|
|
302
|
+
ServerEvent: { oneOf: [
|
|
303
|
+
{
|
|
304
|
+
type: "object",
|
|
305
|
+
required: [
|
|
306
|
+
"event",
|
|
307
|
+
"subscription",
|
|
308
|
+
"payload"
|
|
309
|
+
],
|
|
310
|
+
additionalProperties: false,
|
|
311
|
+
properties: {
|
|
312
|
+
event: { const: "status" },
|
|
313
|
+
subscription: { type: "string" },
|
|
314
|
+
payload: {
|
|
315
|
+
type: "object",
|
|
316
|
+
description: "A full payload, as `stim status --watch --json` prints it."
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
type: "object",
|
|
322
|
+
required: [
|
|
323
|
+
"event",
|
|
324
|
+
"subscription",
|
|
325
|
+
"records"
|
|
326
|
+
],
|
|
327
|
+
additionalProperties: false,
|
|
328
|
+
properties: {
|
|
329
|
+
event: { const: "logs" },
|
|
330
|
+
subscription: { type: "string" },
|
|
331
|
+
records: {
|
|
332
|
+
type: "array",
|
|
333
|
+
items: { $ref: "#/$defs/LogRecord" }
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
type: "object",
|
|
339
|
+
required: [
|
|
340
|
+
"event",
|
|
341
|
+
"subscription",
|
|
342
|
+
"platform",
|
|
343
|
+
"slot",
|
|
344
|
+
"mime",
|
|
345
|
+
"width",
|
|
346
|
+
"height",
|
|
347
|
+
"capturedAt",
|
|
348
|
+
"data"
|
|
349
|
+
],
|
|
350
|
+
additionalProperties: false,
|
|
351
|
+
properties: {
|
|
352
|
+
event: { const: "frame" },
|
|
353
|
+
subscription: { type: "string" },
|
|
354
|
+
platform: { enum: ["ios", "android"] },
|
|
355
|
+
slot: { type: "string" },
|
|
356
|
+
mime: { const: "image/jpeg" },
|
|
357
|
+
width: { type: "integer" },
|
|
358
|
+
height: { type: "integer" },
|
|
359
|
+
capturedAt: {
|
|
360
|
+
type: "string",
|
|
361
|
+
format: "date-time"
|
|
362
|
+
},
|
|
363
|
+
data: {
|
|
364
|
+
type: "string",
|
|
365
|
+
contentEncoding: "base64"
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
type: "object",
|
|
371
|
+
required: [
|
|
372
|
+
"event",
|
|
373
|
+
"subscription",
|
|
374
|
+
"error"
|
|
375
|
+
],
|
|
376
|
+
additionalProperties: false,
|
|
377
|
+
properties: {
|
|
378
|
+
event: { const: "error" },
|
|
379
|
+
subscription: { type: "string" },
|
|
380
|
+
error: { $ref: "#/$defs/ProtocolError" }
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
] }
|
|
384
|
+
},
|
|
385
|
+
oneOf: [
|
|
386
|
+
{ $ref: "#/$defs/ClientRequest" },
|
|
387
|
+
{ $ref: "#/$defs/ServerResponse" },
|
|
388
|
+
{ $ref: "#/$defs/ServerEvent" }
|
|
389
|
+
]
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
//#endregion
|
|
393
|
+
export { MAX_LOG_TAIL as a, PROTOCOL_VERSION as c, LOG_SOURCES as i, protocolJsonSchema as l, ERROR_CODES as n, METHODS as o, LOG_LEVELS as r, PROTOCOL_SCHEMA_FILE as s, CAPABILITIES as t };
|