@gravitylabsllc/porthole 0.1.0 → 0.2.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 +123 -0
- package/dist/adb.js +430 -21
- package/dist/adb.js.map +1 -1
- package/dist/args.js +144 -0
- package/dist/args.js.map +1 -0
- package/dist/capture.js +139 -30
- package/dist/capture.js.map +1 -1
- package/dist/cli.js +221 -62
- package/dist/cli.js.map +1 -1
- package/dist/device.js +337 -4
- package/dist/device.js.map +1 -1
- package/dist/index.js +2030 -377
- package/dist/index.js.map +1 -1
- package/dist/moment.js +240 -0
- package/dist/moment.js.map +1 -0
- package/dist/perfetto.js +826 -0
- package/dist/perfetto.js.map +1 -0
- package/dist/report.js +68 -7
- package/dist/report.js.map +1 -1
- package/dist/save.js +252 -0
- package/dist/save.js.map +1 -0
- package/dist/sessions.js +704 -0
- package/dist/sessions.js.map +1 -0
- package/dist/system.js +169 -0
- package/dist/system.js.map +1 -0
- package/dist/systrace.js +198 -0
- package/dist/systrace.js.map +1 -0
- package/dist/timeline.js +731 -29
- package/dist/timeline.js.map +1 -1
- package/dist/trace.js +317 -27
- package/dist/trace.js.map +1 -1
- package/dist/watermark.js +220 -0
- package/dist/watermark.js.map +1 -0
- package/package.json +10 -4
- package/src/adb.ts +583 -0
- package/src/args.ts +177 -0
- package/src/capture.ts +292 -0
- package/src/cli.ts +367 -0
- package/src/device.ts +635 -0
- package/src/index.ts +2545 -0
- package/src/moment.ts +306 -0
- package/src/perfetto.ts +972 -0
- package/src/report.ts +285 -0
- package/src/save.ts +322 -0
- package/src/sessions.ts +894 -0
- package/src/system.ts +221 -0
- package/src/systrace.ts +258 -0
- package/src/timeline.ts +1036 -0
- package/src/trace.ts +769 -0
- package/src/watermark.ts +337 -0
- package/ui/dist/assets/index-BzqwnvoU.js +70 -0
- package/ui/dist/assets/index-DtnyBXCM.css +1 -0
- package/ui/dist/index.html +2 -2
- package/ui/dist/assets/index--1mlZuNZ.css +0 -1
- package/ui/dist/assets/index-BeVGHRFm.js +0 -68
package/dist/device.js
CHANGED
|
@@ -2,6 +2,21 @@
|
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
import net from "node:net";
|
|
4
4
|
import { EventEmitter } from "node:events";
|
|
5
|
+
import { SessionWriter } from "./sessions.js";
|
|
6
|
+
/**
|
|
7
|
+
* GRA-96: the constant this side of the socket owns, matching
|
|
8
|
+
* `PROTOCOL_VERSION` in `runtime/.../protocol/Protocol.kt` — the two are not
|
|
9
|
+
* derived from a shared source, so a wire-format change obliges updating
|
|
10
|
+
* both by hand (see that file's own comment on the constant it owns). This
|
|
11
|
+
* is a bare integer with no `major.minor` split: a match means compatible,
|
|
12
|
+
* anything else is a refusal, recorded in `protocolMismatch` below rather
|
|
13
|
+
* than thrown, so the rest of the handshake can finish and the mismatch can
|
|
14
|
+
* be reported as the specific, actionable message `porthole_status` needs
|
|
15
|
+
* (GRA-96 AC1/AC2) instead of a generic connection failure.
|
|
16
|
+
*/
|
|
17
|
+
export const PROTOCOL_VERSION = 1;
|
|
18
|
+
/** The one sentence every tool uses for "the socket is up, hello has not landed yet" — GRA-157 AC3. */
|
|
19
|
+
export const HANDSHAKE_PENDING_MESSAGE = "Connected, waiting on the app's first check-in. Ask again in a moment.";
|
|
5
20
|
const RECONNECT_MIN_MS = 500;
|
|
6
21
|
const RECONNECT_MAX_MS = 5_000;
|
|
7
22
|
const REQUEST_TIMEOUT_MS = 5_000;
|
|
@@ -25,10 +40,46 @@ export class DeviceClient extends EventEmitter {
|
|
|
25
40
|
state = "disconnected";
|
|
26
41
|
hello = null;
|
|
27
42
|
lastError = null;
|
|
28
|
-
|
|
43
|
+
/**
|
|
44
|
+
* GRA-163: null until a session that actually got a `hello` has closed;
|
|
45
|
+
* from then on, the most recent one — overwritten on every subsequent
|
|
46
|
+
* close that had a `hello`, so it always names the last confirmed process,
|
|
47
|
+
* never a stale one from further back. See the close handler in
|
|
48
|
+
* `connect()` for where it is set, and index.ts's `exitedProcessField()`/
|
|
49
|
+
* `exitedProcessNotice()` for where it turns into what every tool
|
|
50
|
+
* actually reports (moved there after QA round 1: this field says whose
|
|
51
|
+
* process it is, but only the caller knows whether the ring it is about
|
|
52
|
+
* to describe is empty — see `pendingMessage()`'s own comment below).
|
|
53
|
+
*/
|
|
54
|
+
lastExited = null;
|
|
55
|
+
/**
|
|
56
|
+
* GRA-96: null when the app's `hello.protocol` matches `PROTOCOL_VERSION`,
|
|
57
|
+
* otherwise the sentence `porthole_status` reports verbatim — set once,
|
|
58
|
+
* in `connect()`'s hello handler, right where `hello` itself is set, so it
|
|
59
|
+
* is never stale relative to whichever `hello` is currently held. Kept
|
|
60
|
+
* separate from `lastError`: that field means "the socket or a request
|
|
61
|
+
* failed", this one means "the socket and the handshake both succeeded and
|
|
62
|
+
* the two sides still cannot be trusted to agree on the wire format" — a
|
|
63
|
+
* different fact that deserves its own name instead of overloading
|
|
64
|
+
* lastError's "something went wrong" with a case that is not a failure to
|
|
65
|
+
* connect at all.
|
|
66
|
+
*/
|
|
67
|
+
protocolMismatch = null;
|
|
68
|
+
/**
|
|
69
|
+
* GRA-53 `#session-writer`: null (persistence off) unless a sessions root
|
|
70
|
+
* is given. `undefined`/omitted is the default on purpose — every existing
|
|
71
|
+
* test in `device.test.ts` constructs a `DeviceClient` with two arguments
|
|
72
|
+
* and auto-answers `hello`, so leaving this off must not start writing
|
|
73
|
+
* real files into whatever directory the test happened to run from. The
|
|
74
|
+
* real MCP server boot path (`index.ts`'s `createPortholeServer`) passes
|
|
75
|
+
* one explicitly.
|
|
76
|
+
*/
|
|
77
|
+
sessions;
|
|
78
|
+
constructor(host, port, sessionsRoot) {
|
|
29
79
|
super();
|
|
30
80
|
this.host = host;
|
|
31
81
|
this.port = port;
|
|
82
|
+
this.sessions = sessionsRoot ? new SessionWriter(sessionsRoot) : null;
|
|
32
83
|
}
|
|
33
84
|
start() {
|
|
34
85
|
this.closed = false;
|
|
@@ -36,8 +87,24 @@ export class DeviceClient extends EventEmitter {
|
|
|
36
87
|
}
|
|
37
88
|
stop() {
|
|
38
89
|
this.closed = true;
|
|
90
|
+
// Clearing the timeout without nulling the field leaves scheduleReconnect()'s
|
|
91
|
+
// guard (`this.closed || this.reconnectTimer`) permanently true after a later
|
|
92
|
+
// start(): the stale, already-cleared timer looks exactly like a reconnect
|
|
93
|
+
// that is still scheduled, so a subsequent disconnect never retries.
|
|
39
94
|
if (this.reconnectTimer)
|
|
40
95
|
clearTimeout(this.reconnectTimer);
|
|
96
|
+
this.reconnectTimer = null;
|
|
97
|
+
// GRA-191: close the writer here, synchronously with stop() itself,
|
|
98
|
+
// rather than relying solely on the "close" handler below reacting to
|
|
99
|
+
// socket.destroy() — that handler fires on a later tick (net sockets
|
|
100
|
+
// emit "close" asynchronously), which is exactly the gap that let a
|
|
101
|
+
// still-armed 250ms flush timer survive past a test's own teardown and
|
|
102
|
+
// fire against a sessions root the teardown had already removed
|
|
103
|
+
// (GRA-183's reproduction). close() flushes whatever is queued (which
|
|
104
|
+
// also cancels that timer — see SessionWriter.doFlush()'s own first
|
|
105
|
+
// lines) and marks the writer closed so nothing appended after this
|
|
106
|
+
// point queues into a writer nothing will flush again.
|
|
107
|
+
this.sessions?.close();
|
|
41
108
|
this.socket?.destroy();
|
|
42
109
|
this.socket = null;
|
|
43
110
|
this.setState("disconnected");
|
|
@@ -53,14 +120,87 @@ export class DeviceClient extends EventEmitter {
|
|
|
53
120
|
socket.on("connect", () => {
|
|
54
121
|
this.reconnectDelay = RECONNECT_MIN_MS;
|
|
55
122
|
this.lastError = null;
|
|
56
|
-
|
|
123
|
+
// Not "connected" yet — GRA-157. The TCP handshake finishing says
|
|
124
|
+
// nothing about whether the far end is a Porthole runtime, let alone
|
|
125
|
+
// which app; hello is what answers that, and it has not been asked
|
|
126
|
+
// yet at this line. Callers that need "connected" is real now get it:
|
|
127
|
+
// the state stays "handshaking" until the block below actually has a
|
|
128
|
+
// Hello in hand.
|
|
129
|
+
this.setState("handshaking");
|
|
57
130
|
// hello doubles as a liveness check and as the timeline's origin.
|
|
58
131
|
this.request("hello")
|
|
59
|
-
.then((hello) => {
|
|
132
|
+
.then(async (hello) => {
|
|
133
|
+
// Order matters: hello is set before the state change that
|
|
134
|
+
// announces it, so anything reacting to the "state" event (or
|
|
135
|
+
// reading `.hello` right after seeing state flip to "connected")
|
|
136
|
+
// never observes "connected" with `hello` still null. setState()
|
|
137
|
+
// also asserts this itself, so a future edit that reordered these
|
|
138
|
+
// two lines would fail loudly instead of reintroducing the race.
|
|
60
139
|
this.hello = hello;
|
|
140
|
+
// GRA-96: computed right where `hello` is set, not deferred to
|
|
141
|
+
// whichever tool asks later — a caller reading `protocolMismatch`
|
|
142
|
+
// right after the "hello" event below always sees the answer for
|
|
143
|
+
// the `hello` it just received, never a stale one from a previous
|
|
144
|
+
// connection. Refusal, not a thrown error: the socket is fine and
|
|
145
|
+
// the app really did answer, so the rest of the surface (findings,
|
|
146
|
+
// timeline, …) still works for whatever it can, and this is the
|
|
147
|
+
// one specific, actionable fact layered on top (GRA-96 AC1/AC2).
|
|
148
|
+
// Synchronous, like the assignment above — that is what lets it
|
|
149
|
+
// sit between `this.hello = hello` and the emit below without
|
|
150
|
+
// reopening GRA-191's race (see that emit's own comment).
|
|
151
|
+
this.protocolMismatch =
|
|
152
|
+
hello.protocol === PROTOCOL_VERSION
|
|
153
|
+
? null
|
|
154
|
+
: `The app is speaking protocol ${hello.protocol}; this server understands protocol ` +
|
|
155
|
+
`${PROTOCOL_VERSION}. Update the app's Porthole runtime dependency to a version that ` +
|
|
156
|
+
`speaks protocol ${PROTOCOL_VERSION}, or pin the npm package this MCP server runs from ` +
|
|
157
|
+
`(in .mcp.json) to the version that matches the app.`;
|
|
158
|
+
// GRA-191: `this.hello = hello` above and this emit must stay
|
|
159
|
+
// exactly this close together, with nothing between them that can
|
|
160
|
+
// yield to the event loop. GRA-53 used to put
|
|
161
|
+
// `await this.sessions.open(hello)` right here, reasoning that
|
|
162
|
+
// "connected" — and the events a caller might start sending the
|
|
163
|
+
// instant it sees that state — should never arrive before there
|
|
164
|
+
// was somewhere for `append()` to put them. That reasoning was
|
|
165
|
+
// right about `append()` and wrong about this emit: `open()` is
|
|
166
|
+
// real disk I/O (mkdir/readFile/writeFile/enforceRetention), and
|
|
167
|
+
// awaiting it here opened a window in which `timeline.ts`'s
|
|
168
|
+
// "hello" listener — the thing that clears its ring for a new
|
|
169
|
+
// session — had not run yet, so an event arriving in that window
|
|
170
|
+
// got pushed onto the ring first and was wiped a moment later when
|
|
171
|
+
// the delayed "hello" finally fired (GRA-183's reproduction).
|
|
172
|
+
// Moving the emit up here removes the window instead of narrowing
|
|
173
|
+
// it: every "hello" listener runs to completion before this
|
|
174
|
+
// function's own next line ever executes, so nothing can land
|
|
175
|
+
// between "the ring has cleared for this session" and "the ring
|
|
176
|
+
// is accepting this session's events" — there is no gap for
|
|
177
|
+
// anything to land in. Do not put an `await` of any kind between
|
|
178
|
+
// the assignment above and this emit — that is the exact mistake
|
|
179
|
+
// GRA-191 is about. `sessions.open()` still runs, just after, and
|
|
180
|
+
// `SessionWriter.append()` now queues anything that arrives while
|
|
181
|
+
// it is still in flight rather than dropping it (see sessions.ts),
|
|
182
|
+
// so nothing below this line depends on `open()` having already
|
|
183
|
+
// resolved.
|
|
61
184
|
this.emit("hello", hello);
|
|
185
|
+
// GRA-53 `#session-writer`: opens (or resumes) the on-disk session
|
|
186
|
+
// for this identity. Awaited before `setState("connected")` below
|
|
187
|
+
// — not before the emit above any more — so "connected" still
|
|
188
|
+
// means what GRA-157's tests pin (a writer whose directory is
|
|
189
|
+
// guaranteed to exist by the time a caller sees that state)
|
|
190
|
+
// without that guarantee costing the emit its synchronicity.
|
|
191
|
+
if (this.sessions)
|
|
192
|
+
await this.sessions.open(hello);
|
|
193
|
+
this.setState("connected");
|
|
62
194
|
})
|
|
63
195
|
.catch((error) => {
|
|
196
|
+
// The socket is still open and still usable — only the hello
|
|
197
|
+
// round-trip failed (most likely its own 5s timeout, if the far
|
|
198
|
+
// end accepted the TCP connection but never speaks the protocol).
|
|
199
|
+
// Staying in "handshaking" rather than falling back to "connected"
|
|
200
|
+
// is the point of this whole change; there is deliberately no
|
|
201
|
+
// retry here, since request() already gives every other method
|
|
202
|
+
// the same 5s timeout and nothing about hello is special enough to
|
|
203
|
+
// loop on its own.
|
|
64
204
|
this.lastError = error.message;
|
|
65
205
|
});
|
|
66
206
|
});
|
|
@@ -70,7 +210,29 @@ export class DeviceClient extends EventEmitter {
|
|
|
70
210
|
});
|
|
71
211
|
socket.on("close", () => {
|
|
72
212
|
this.socket = null;
|
|
213
|
+
// GRA-53: flush promptly on disconnect rather than waiting for the
|
|
214
|
+
// interval timer — a killed app or a dropped socket is exactly the
|
|
215
|
+
// moment nothing else will prompt a flush for a while, and the whole
|
|
216
|
+
// point of writing to disk is that this data survives the socket
|
|
217
|
+
// going away. Deliberately NOT sessions.close()/finalize: a reconnect
|
|
218
|
+
// that gets the same hello back (open()'s idempotent-by-identity
|
|
219
|
+
// check) resumes appending to this same file, so the session directory
|
|
220
|
+
// itself is left exactly as GRA-163 leaves the ring — kept, not
|
|
221
|
+
// cleared, until a genuinely new hello says otherwise.
|
|
222
|
+
void this.sessions?.flush();
|
|
223
|
+
// GRA-163: captured before `hello` is cleared below, and only when
|
|
224
|
+
// there was one — a socket that closes mid-handshake (this.hello
|
|
225
|
+
// still null) never had a confirmed session to record, and recording
|
|
226
|
+
// one here would overwrite the real last-exited process with nothing.
|
|
227
|
+
if (this.hello) {
|
|
228
|
+
this.lastExited = { hello: this.hello, disconnectedAt: Date.now() };
|
|
229
|
+
}
|
|
73
230
|
this.hello = null;
|
|
231
|
+
// GRA-96: cleared with `hello`, for the same reason — a mismatch is a
|
|
232
|
+
// fact about the `hello` that produced it, and once that `hello` is
|
|
233
|
+
// gone (a new connection will get its own, possibly no longer
|
|
234
|
+
// mismatched) there is nothing left for this to still be true about.
|
|
235
|
+
this.protocolMismatch = null;
|
|
74
236
|
this.failPending("device disconnected");
|
|
75
237
|
this.setState("disconnected");
|
|
76
238
|
this.scheduleReconnect();
|
|
@@ -105,6 +267,17 @@ export class DeviceClient extends EventEmitter {
|
|
|
105
267
|
return;
|
|
106
268
|
}
|
|
107
269
|
if ("event" in frame) {
|
|
270
|
+
// GRA-53: queued, not written — SessionWriter.append() only ever
|
|
271
|
+
// pushes to its own in-memory array and arms a flush timer, so this
|
|
272
|
+
// line does not touch the filesystem and cannot be the reason a frame
|
|
273
|
+
// is processed late. GRA-191: append() no longer needs the session's
|
|
274
|
+
// directory to already exist to accept this — persistence being off
|
|
275
|
+
// entirely, or a writer `close()` already closed, are the only cases
|
|
276
|
+
// it still silently drops; an event that arrives while `open()` is
|
|
277
|
+
// still awaiting disk I/O (or has not even been called yet — see
|
|
278
|
+
// `connect()`'s "hello" handler) is queued and written once the
|
|
279
|
+
// directory exists.
|
|
280
|
+
this.sessions?.append(frame);
|
|
108
281
|
this.emit("event", frame);
|
|
109
282
|
return;
|
|
110
283
|
}
|
|
@@ -126,6 +299,14 @@ export class DeviceClient extends EventEmitter {
|
|
|
126
299
|
this.pending.clear();
|
|
127
300
|
}
|
|
128
301
|
setState(state) {
|
|
302
|
+
// GRA-157 AC1: "connected" implies `hello` is non-null, enforced here —
|
|
303
|
+
// the one place `state` is actually assigned — rather than left for
|
|
304
|
+
// every reader to remember. If this throws, the bug is in this file
|
|
305
|
+
// (most likely connect()'s hello handler setting state before hello),
|
|
306
|
+
// never in whatever asked for the transition.
|
|
307
|
+
if (state === "connected" && this.hello === null) {
|
|
308
|
+
throw new Error("DeviceClient invariant violated: cannot enter state 'connected' with hello still null");
|
|
309
|
+
}
|
|
129
310
|
if (this.state === state)
|
|
130
311
|
return;
|
|
131
312
|
this.state = state;
|
|
@@ -133,7 +314,26 @@ export class DeviceClient extends EventEmitter {
|
|
|
133
314
|
}
|
|
134
315
|
request(method, params = {}) {
|
|
135
316
|
const socket = this.socket;
|
|
136
|
-
|
|
317
|
+
// "handshaking" is allowed here on purpose: it is the exact state hello
|
|
318
|
+
// itself is sent in (see connect()'s socket.on("connect") above, which
|
|
319
|
+
// sets "handshaking" and then calls request<Hello>("hello") next) —
|
|
320
|
+
// gating on "connected" alone would make sending hello reject itself.
|
|
321
|
+
// Only "connecting" (TCP handshake still in flight — this.socket exists
|
|
322
|
+
// but has not fired "connect" yet) and "disconnected" have no usable
|
|
323
|
+
// socket to write a frame to.
|
|
324
|
+
//
|
|
325
|
+
// GRA-162 QA: this used to spell the same condition out longhand as
|
|
326
|
+
// `this.state !== "handshaking" && this.state !== "connected"`, which is
|
|
327
|
+
// isAttached() negated (De Morgan's) but written by hand instead of
|
|
328
|
+
// through it. That made this a sixth silent site the AC 2 probe did not
|
|
329
|
+
// catch: a `!==` pair against two literals still compiles unchanged when
|
|
330
|
+
// the union grows, and a future state would fall through to "not
|
|
331
|
+
// attached" and reject every request() call with the not-connected
|
|
332
|
+
// message even while the socket was genuinely live. Routing through
|
|
333
|
+
// isAttached() puts this choke point behind the same never-guarded
|
|
334
|
+
// switch as the rest, so a new state fails `tsc` here too instead of
|
|
335
|
+
// silently rejecting live traffic.
|
|
336
|
+
if (!socket || !isAttached(this.state)) {
|
|
137
337
|
return Promise.reject(new Error(this.notConnectedMessage()));
|
|
138
338
|
}
|
|
139
339
|
const id = this.nextId++;
|
|
@@ -157,6 +357,70 @@ export class DeviceClient extends EventEmitter {
|
|
|
157
357
|
socket.write(JSON.stringify({ id, method, params: cleaned }) + "\n");
|
|
158
358
|
});
|
|
159
359
|
}
|
|
360
|
+
/**
|
|
361
|
+
* The disconnected/handshaking half of what every tool says about the
|
|
362
|
+
* connection, written once instead of separately by porthole_status,
|
|
363
|
+
* findings, and whichever tool asks next (GRA-157 AC3). Returns null when
|
|
364
|
+
* `state` is "connected", since `hello` is guaranteed non-null there (see
|
|
365
|
+
* setState() above) and what to say about a live connection differs by
|
|
366
|
+
* caller — porthole_status names the collectors, findings talks about the
|
|
367
|
+
* buffer — so that half stays with each tool.
|
|
368
|
+
*
|
|
369
|
+
* The switch is exhaustive on purpose, with a compiled-in `never` check
|
|
370
|
+
* instead of a `default` that quietly falls through: a fifth
|
|
371
|
+
* ConnectionState added later without a case here fails `tsc`, in this one
|
|
372
|
+
* place, rather than silently being treated as either "connected" or the
|
|
373
|
+
* wall. Everywhere else asks this method instead of re-deriving the answer
|
|
374
|
+
* from `state` and `hello` by hand, which is the actual fix GRA-157 is
|
|
375
|
+
* about. (GRA-162: this used to say it was "deliberately the only place in
|
|
376
|
+
* the package with that check" — it no longer is. QA counted eight sites
|
|
377
|
+
* outside this file that read `device.state === "…"` directly, which
|
|
378
|
+
* `tsc` does not flag when a state is added because `===` against a string
|
|
379
|
+
* literal just evaluates false for anything new. `isAttached()`,
|
|
380
|
+
* `isConnected()` and `isHandshaking()` below give those call sites the
|
|
381
|
+
* same guarantee this switch has always had, instead of leaving them to
|
|
382
|
+
* reinvent it inconsistently or not at all.)
|
|
383
|
+
*/
|
|
384
|
+
/**
|
|
385
|
+
* GRA-163 QA round 1: this used to append an "exited process" sentence of
|
|
386
|
+
* its own (`withExitedSessionNote()`, now removed) whenever `lastExited`
|
|
387
|
+
* was set. That sentence unconditionally said "whatever is still buffered
|
|
388
|
+
* is from X" — true on the branch that has a non-empty ring, false on the
|
|
389
|
+
* branch that does not (the empty-ring-plus-`lastExited` case: a process
|
|
390
|
+
* reconnects, clears the ring on its own `hello`, then dies before
|
|
391
|
+
* emitting anything), because this method has no way to know which one it
|
|
392
|
+
* is being asked from — `pendingMessage()` only ever sees `this.state`
|
|
393
|
+
* and `this.lastExited`, never `timeline.buffer().length`. Two more
|
|
394
|
+
* faults rode along with that one: `porthole_status` calls
|
|
395
|
+
* `exitedProcessField()` unconditionally while `findings`/
|
|
396
|
+
* `what_was_happening` only called it from their non-empty-ring branch,
|
|
397
|
+
* so the same state produced a payload with `exitedProcess` on one tool
|
|
398
|
+
* and without it on another — and the prose was folded into this string
|
|
399
|
+
* while the structured field lived in index.ts, so the two could disagree
|
|
400
|
+
* even about a single tool's own single answer.
|
|
401
|
+
*
|
|
402
|
+
* The fix moves all of it to index.ts's `exitedProcessNotice()`, called
|
|
403
|
+
* from every branch of every tool that might describe ring content,
|
|
404
|
+
* because index.ts is the one place that actually knows whether the ring
|
|
405
|
+
* it is about to describe is empty. This method goes back to answering
|
|
406
|
+
* exactly what its name says: how to reconnect, or that the handshake is
|
|
407
|
+
* still pending. Nothing else.
|
|
408
|
+
*/
|
|
409
|
+
pendingMessage() {
|
|
410
|
+
switch (this.state) {
|
|
411
|
+
case "disconnected":
|
|
412
|
+
case "connecting":
|
|
413
|
+
return this.notConnectedMessage();
|
|
414
|
+
case "handshaking":
|
|
415
|
+
return HANDSHAKE_PENDING_MESSAGE;
|
|
416
|
+
case "connected":
|
|
417
|
+
return null;
|
|
418
|
+
default: {
|
|
419
|
+
const exhaustive = this.state;
|
|
420
|
+
throw new Error(`DeviceClient: unhandled ConnectionState '${exhaustive}'`);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
160
424
|
notConnectedMessage() {
|
|
161
425
|
return [
|
|
162
426
|
`Not connected to the app on ${this.host}:${this.port}.`,
|
|
@@ -171,4 +435,73 @@ export class DeviceClient extends EventEmitter {
|
|
|
171
435
|
.join("\n");
|
|
172
436
|
}
|
|
173
437
|
}
|
|
438
|
+
// --- GRA-162: exhaustive readers of a bare ConnectionState ------------------
|
|
439
|
+
//
|
|
440
|
+
// Free functions, not methods, because every call site below holds a
|
|
441
|
+
// ConnectionState value (`device.state`, or one carried on an event/message)
|
|
442
|
+
// rather than a DeviceClient to ask. Each is a switch with the same
|
|
443
|
+
// compiled-in `never` guard as pendingMessage() above: adding a fifth
|
|
444
|
+
// ConnectionState without extending a case list here fails `tsc` at that
|
|
445
|
+
// list, not silently at nothing. Three functions rather than one because the
|
|
446
|
+
// call sites genuinely want three different questions answered, and a single
|
|
447
|
+
// helper returning a wider type would just move the "did I handle the new
|
|
448
|
+
// case" judgement call to every caller instead of to the compiler here.
|
|
449
|
+
/**
|
|
450
|
+
* The "loose" sense `findings`, `porthole_status` and `what_was_happening`
|
|
451
|
+
* use: the socket is up, whether or not `hello` has landed. True for
|
|
452
|
+
* "handshaking" and "connected"; false for "connecting" and "disconnected".
|
|
453
|
+
*/
|
|
454
|
+
export function isAttached(state) {
|
|
455
|
+
switch (state) {
|
|
456
|
+
case "handshaking":
|
|
457
|
+
case "connected":
|
|
458
|
+
return true;
|
|
459
|
+
case "connecting":
|
|
460
|
+
case "disconnected":
|
|
461
|
+
return false;
|
|
462
|
+
default: {
|
|
463
|
+
const exhaustive = state;
|
|
464
|
+
throw new Error(`DeviceClient: unhandled ConnectionState '${exhaustive}'`);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* The "strict" sense: `hello` has actually landed. True only for
|
|
470
|
+
* "connected" — see setState()'s invariant above, which makes that the only
|
|
471
|
+
* state in which `hello` is guaranteed non-null.
|
|
472
|
+
*/
|
|
473
|
+
export function isConnected(state) {
|
|
474
|
+
switch (state) {
|
|
475
|
+
case "connected":
|
|
476
|
+
return true;
|
|
477
|
+
case "connecting":
|
|
478
|
+
case "handshaking":
|
|
479
|
+
case "disconnected":
|
|
480
|
+
return false;
|
|
481
|
+
default: {
|
|
482
|
+
const exhaustive = state;
|
|
483
|
+
throw new Error(`DeviceClient: unhandled ConnectionState '${exhaustive}'`);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* True only while the handshake is in flight: the socket is up, `hello` has
|
|
489
|
+
* not landed. Named separately from isAttached()/isConnected() because
|
|
490
|
+
* several call sites want to say something specific about the handshake
|
|
491
|
+
* window rather than lump it in with either "attached" or "not yet".
|
|
492
|
+
*/
|
|
493
|
+
export function isHandshaking(state) {
|
|
494
|
+
switch (state) {
|
|
495
|
+
case "handshaking":
|
|
496
|
+
return true;
|
|
497
|
+
case "connecting":
|
|
498
|
+
case "connected":
|
|
499
|
+
case "disconnected":
|
|
500
|
+
return false;
|
|
501
|
+
default: {
|
|
502
|
+
const exhaustive = state;
|
|
503
|
+
throw new Error(`DeviceClient: unhandled ConnectionState '${exhaustive}'`);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}
|
|
174
507
|
//# sourceMappingURL=device.js.map
|
package/dist/device.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"device.js","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"device.js","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"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"}
|