@xstate-devtools/adapter 0.1.2 → 0.1.3
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/package.json +1 -1
- package/src/server.ts +41 -3
package/package.json
CHANGED
package/src/server.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Server entrypoint — exposes a WebSocket bridge so the DevTools panel
|
|
2
2
|
// can connect to actors running in Node.
|
|
3
|
+
import { createServer as createTcpServer } from 'node:net'
|
|
3
4
|
import type {
|
|
4
5
|
ExtensionToPageMessage,
|
|
5
6
|
PageToExtensionMessage,
|
|
@@ -12,6 +13,28 @@ import {
|
|
|
12
13
|
} from './logging.js'
|
|
13
14
|
import { sanitize } from './sanitize.js'
|
|
14
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Find the lowest TCP port >= `start` that is not currently in use.
|
|
18
|
+
* Uses a temporary TCP server to probe; the port is released before resolving.
|
|
19
|
+
*/
|
|
20
|
+
function getAvailablePort(start: number): Promise<number> {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
const probe = createTcpServer()
|
|
23
|
+
probe.unref()
|
|
24
|
+
probe.on('error', (err: NodeJS.ErrnoException) => {
|
|
25
|
+
if (err.code === 'EADDRINUSE') {
|
|
26
|
+
resolve(getAvailablePort(start + 1))
|
|
27
|
+
} else {
|
|
28
|
+
reject(err)
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
probe.listen(start, '127.0.0.1', () => {
|
|
32
|
+
const port = (probe.address() as { port: number }).port
|
|
33
|
+
probe.close(() => resolve(port))
|
|
34
|
+
})
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
|
|
15
38
|
export interface ServerAdapterOptions {
|
|
16
39
|
/** Port to listen on. Defaults to env XSTATE_DEVTOOLS_PORT or 9301. */
|
|
17
40
|
port?: number
|
|
@@ -89,6 +112,8 @@ interface CachedServer {
|
|
|
89
112
|
buffer: string[]
|
|
90
113
|
bufferSize: number
|
|
91
114
|
activated: boolean
|
|
115
|
+
/** Resolves with the actual TCP port once the WS server is listening. */
|
|
116
|
+
port: Promise<number>
|
|
92
117
|
close: () => void
|
|
93
118
|
}
|
|
94
119
|
|
|
@@ -132,12 +157,20 @@ export function createServerAdapter(options: ServerAdapterOptions = {}) {
|
|
|
132
157
|
let wss: any = null
|
|
133
158
|
let closed = false
|
|
134
159
|
|
|
160
|
+
let portResolve!: (port: number) => void
|
|
161
|
+
let portReject!: (err: unknown) => void
|
|
162
|
+
const portPromise = new Promise<number>((res, rej) => {
|
|
163
|
+
portResolve = res
|
|
164
|
+
portReject = rej
|
|
165
|
+
})
|
|
166
|
+
|
|
135
167
|
server = {
|
|
136
168
|
clients,
|
|
137
169
|
dispatchHandlers,
|
|
138
170
|
buffer,
|
|
139
171
|
bufferSize,
|
|
140
172
|
activated: false,
|
|
173
|
+
port: portPromise,
|
|
141
174
|
close: () => {
|
|
142
175
|
closed = true
|
|
143
176
|
infoLog('closing WebSocket server', { host, port, clientCount: clients.size })
|
|
@@ -160,8 +193,12 @@ export function createServerAdapter(options: ServerAdapterOptions = {}) {
|
|
|
160
193
|
const mod = await import('ws')
|
|
161
194
|
const WSServer = (mod as any).WebSocketServer ?? (mod as any).Server
|
|
162
195
|
if (closed) return
|
|
163
|
-
|
|
164
|
-
|
|
196
|
+
const actualPort = await getAvailablePort(port)
|
|
197
|
+
if (closed) return
|
|
198
|
+
wss = new WSServer({ port: actualPort, host })
|
|
199
|
+
process.env.XSTATE_DEVTOOLS_PORT = String(actualPort)
|
|
200
|
+
portResolve(actualPort)
|
|
201
|
+
infoLog('WebSocket server listening', { host, port: actualPort })
|
|
165
202
|
wss.on('connection', (ws: ClientLike) => {
|
|
166
203
|
infoLog('panel connected to WebSocket server', {
|
|
167
204
|
host,
|
|
@@ -214,6 +251,7 @@ export function createServerAdapter(options: ServerAdapterOptions = {}) {
|
|
|
214
251
|
warnLog('WS server error', { host, port, message: err.message })
|
|
215
252
|
})
|
|
216
253
|
} catch (e) {
|
|
254
|
+
portReject(e)
|
|
217
255
|
warnLog('could not start server adapter — install `ws` to enable', {
|
|
218
256
|
host,
|
|
219
257
|
port,
|
|
@@ -268,5 +306,5 @@ export function createServerAdapter(options: ServerAdapterOptions = {}) {
|
|
|
268
306
|
}
|
|
269
307
|
|
|
270
308
|
const inspector = createInspector(transport, 'srv')
|
|
271
|
-
return { ...inspector, close: server.close }
|
|
309
|
+
return { ...inspector, close: server.close, port: server.port }
|
|
272
310
|
}
|