twd-relay 0.2.1 → 1.0.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/dist/browser.cjs.js +1 -1
- package/dist/browser.d.ts +2 -0
- package/dist/browser.es.js +130 -77
- package/dist/cli.js +316 -294
- package/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.es.js +1 -1
- package/dist/relay-C8UTSEbG.js +132 -0
- package/dist/relay-CpUORBd7.cjs +1 -0
- package/dist/vite.cjs.js +1 -1
- package/dist/vite.d.ts +3 -0
- package/dist/vite.es.js +11 -9
- package/package.json +6 -5
- package/dist/createTwdRelay-22etCW_8.js +0 -123
- package/dist/createTwdRelay-VRmjHboP.cjs +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,259 +1,261 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createServer } from "http";
|
|
3
|
-
import WebSocket
|
|
4
|
-
|
|
3
|
+
import WebSocket, { WebSocket as WebSocket$1, WebSocketServer } from "ws";
|
|
4
|
+
//#region src/relay/createTwdRelay.ts
|
|
5
|
+
var DEFAULT_PATH = "/__twd/ws";
|
|
5
6
|
function createTwdRelay(server, options) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
},
|
|
161
|
-
get browserConnected() {
|
|
162
|
-
return browser !== null && browser.readyState === WebSocket.OPEN;
|
|
163
|
-
},
|
|
164
|
-
get clientCount() {
|
|
165
|
-
return clients.size;
|
|
166
|
-
}
|
|
167
|
-
};
|
|
7
|
+
const path = options?.path ?? DEFAULT_PATH;
|
|
8
|
+
const onError = options?.onError;
|
|
9
|
+
const wss = new WebSocketServer({ noServer: true });
|
|
10
|
+
let browser = null;
|
|
11
|
+
const clients = /* @__PURE__ */ new Set();
|
|
12
|
+
let runInProgress = false;
|
|
13
|
+
function sendError(ws, code, message) {
|
|
14
|
+
const msg = {
|
|
15
|
+
type: "error",
|
|
16
|
+
code,
|
|
17
|
+
message
|
|
18
|
+
};
|
|
19
|
+
if (ws.readyState === WebSocket$1.OPEN) ws.send(JSON.stringify(msg));
|
|
20
|
+
}
|
|
21
|
+
function broadcastToClients(data) {
|
|
22
|
+
for (const client of clients) if (client.readyState === WebSocket$1.OPEN) client.send(data);
|
|
23
|
+
}
|
|
24
|
+
function sendConnectedStatus(ws) {
|
|
25
|
+
const msg = {
|
|
26
|
+
type: "connected",
|
|
27
|
+
browser: browser !== null && browser.readyState === WebSocket$1.OPEN
|
|
28
|
+
};
|
|
29
|
+
if (ws.readyState === WebSocket$1.OPEN) ws.send(JSON.stringify(msg));
|
|
30
|
+
}
|
|
31
|
+
function notifyBrowserDisconnected() {
|
|
32
|
+
broadcastToClients(JSON.stringify({
|
|
33
|
+
type: "connected",
|
|
34
|
+
browser: false
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
function handleBrowserMessage(data) {
|
|
38
|
+
let parsed;
|
|
39
|
+
try {
|
|
40
|
+
parsed = JSON.parse(data);
|
|
41
|
+
} catch {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (parsed.type === "run:complete") runInProgress = false;
|
|
45
|
+
broadcastToClients(data);
|
|
46
|
+
}
|
|
47
|
+
function handleClientMessage(ws, data) {
|
|
48
|
+
let parsed;
|
|
49
|
+
try {
|
|
50
|
+
parsed = JSON.parse(data);
|
|
51
|
+
} catch {
|
|
52
|
+
sendError(ws, "INVALID_MESSAGE", "Invalid JSON");
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (!parsed.type) {
|
|
56
|
+
sendError(ws, "INVALID_MESSAGE", "Missing \"type\" field");
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (parsed.type === "run") {
|
|
60
|
+
if (!browser || browser.readyState !== WebSocket$1.OPEN) {
|
|
61
|
+
sendError(ws, "NO_BROWSER", "No browser connected");
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (runInProgress) {
|
|
65
|
+
sendError(ws, "RUN_IN_PROGRESS", "A test run is already in progress");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
runInProgress = true;
|
|
69
|
+
browser.send(data);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (parsed.type === "status") {
|
|
73
|
+
if (!browser || browser.readyState !== WebSocket$1.OPEN) {
|
|
74
|
+
sendError(ws, "NO_BROWSER", "No browser connected");
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
browser.send(data);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
sendError(ws, "UNKNOWN_COMMAND", `Unknown command: ${parsed.type}`);
|
|
81
|
+
}
|
|
82
|
+
function handleConnection(ws) {
|
|
83
|
+
let identified = false;
|
|
84
|
+
const identifyHandler = (raw) => {
|
|
85
|
+
const data = typeof raw === "string" ? raw : raw.toString();
|
|
86
|
+
if (!identified) {
|
|
87
|
+
let parsed;
|
|
88
|
+
try {
|
|
89
|
+
parsed = JSON.parse(data);
|
|
90
|
+
} catch {
|
|
91
|
+
sendError(ws, "INVALID_MESSAGE", "Invalid JSON");
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (parsed.type !== "hello" || parsed.role !== "browser" && parsed.role !== "client") {
|
|
95
|
+
sendError(ws, "INVALID_MESSAGE", "First message must be a hello with role \"browser\" or \"client\"");
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
identified = true;
|
|
99
|
+
if (parsed.role === "browser") {
|
|
100
|
+
if (browser && browser.readyState === WebSocket$1.OPEN) browser.close(1e3, "Replaced by new browser");
|
|
101
|
+
browser = ws;
|
|
102
|
+
runInProgress = false;
|
|
103
|
+
ws.on("close", () => {
|
|
104
|
+
if (browser === ws) {
|
|
105
|
+
browser = null;
|
|
106
|
+
runInProgress = false;
|
|
107
|
+
notifyBrowserDisconnected();
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
broadcastToClients(JSON.stringify({
|
|
111
|
+
type: "connected",
|
|
112
|
+
browser: true
|
|
113
|
+
}));
|
|
114
|
+
ws.on("message", (raw) => {
|
|
115
|
+
handleBrowserMessage(typeof raw === "string" ? raw : raw.toString());
|
|
116
|
+
});
|
|
117
|
+
} else {
|
|
118
|
+
clients.add(ws);
|
|
119
|
+
ws.on("close", () => {
|
|
120
|
+
clients.delete(ws);
|
|
121
|
+
});
|
|
122
|
+
sendConnectedStatus(ws);
|
|
123
|
+
ws.on("message", (raw) => {
|
|
124
|
+
handleClientMessage(ws, typeof raw === "string" ? raw : raw.toString());
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
ws.removeListener("message", identifyHandler);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
ws.on("message", identifyHandler);
|
|
131
|
+
ws.on("error", (err) => {
|
|
132
|
+
if (onError) onError(err);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
const upgradeHandler = (request, socket, head) => {
|
|
136
|
+
if (new URL(request.url ?? "/", `http://${request.headers.host ?? "localhost"}`).pathname === path) wss.handleUpgrade(request, socket, head, (ws) => {
|
|
137
|
+
handleConnection(ws);
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
server.on("upgrade", upgradeHandler);
|
|
141
|
+
wss.on("error", (err) => {
|
|
142
|
+
if (onError) onError(err);
|
|
143
|
+
});
|
|
144
|
+
return {
|
|
145
|
+
close() {
|
|
146
|
+
server.removeListener("upgrade", upgradeHandler);
|
|
147
|
+
for (const client of clients) client.close(1e3, "Relay shutting down");
|
|
148
|
+
clients.clear();
|
|
149
|
+
if (browser && browser.readyState === WebSocket$1.OPEN) browser.close(1e3, "Relay shutting down");
|
|
150
|
+
browser = null;
|
|
151
|
+
runInProgress = false;
|
|
152
|
+
wss.close();
|
|
153
|
+
},
|
|
154
|
+
get browserConnected() {
|
|
155
|
+
return browser !== null && browser.readyState === WebSocket$1.OPEN;
|
|
156
|
+
},
|
|
157
|
+
get clientCount() {
|
|
158
|
+
return clients.size;
|
|
159
|
+
}
|
|
160
|
+
};
|
|
168
161
|
}
|
|
162
|
+
//#endregion
|
|
163
|
+
//#region src/cli/run.ts
|
|
169
164
|
function run(options) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
165
|
+
const { port, timeout, path, host, testNames } = options;
|
|
166
|
+
const url = `ws://${host}:${port}${path}`;
|
|
167
|
+
console.log(`Connecting to ${url}...`);
|
|
168
|
+
const ws = new WebSocket(url);
|
|
169
|
+
let runSent = false;
|
|
170
|
+
let runComplete = false;
|
|
171
|
+
let failed = false;
|
|
172
|
+
const timer = setTimeout(() => {
|
|
173
|
+
console.error(`\nTimeout: no run:complete received within ${timeout / 1e3}s`);
|
|
174
|
+
ws.close();
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}, timeout);
|
|
177
|
+
ws.on("open", () => {
|
|
178
|
+
ws.send(JSON.stringify({
|
|
179
|
+
type: "hello",
|
|
180
|
+
role: "client"
|
|
181
|
+
}));
|
|
182
|
+
});
|
|
183
|
+
ws.on("message", (data) => {
|
|
184
|
+
const msg = JSON.parse(data.toString());
|
|
185
|
+
switch (msg.type) {
|
|
186
|
+
case "connected":
|
|
187
|
+
if (msg.browser && !runSent) {
|
|
188
|
+
runSent = true;
|
|
189
|
+
console.log("Browser connected, triggering test run...\n");
|
|
190
|
+
const runMsg = {
|
|
191
|
+
type: "run",
|
|
192
|
+
scope: "all"
|
|
193
|
+
};
|
|
194
|
+
if (testNames?.length) runMsg.testNames = testNames;
|
|
195
|
+
ws.send(JSON.stringify(runMsg));
|
|
196
|
+
} else if (!msg.browser) console.log("Waiting for browser to connect...");
|
|
197
|
+
break;
|
|
198
|
+
case "run:start":
|
|
199
|
+
console.log(`Running ${msg.testCount} test(s)...\n`);
|
|
200
|
+
break;
|
|
201
|
+
case "test:start":
|
|
202
|
+
console.log(` RUN: ${msg.suite} > ${msg.name}`);
|
|
203
|
+
break;
|
|
204
|
+
case "test:pass":
|
|
205
|
+
console.log(` PASS: ${msg.suite} > ${msg.name} (${msg.duration}ms)`);
|
|
206
|
+
break;
|
|
207
|
+
case "test:fail":
|
|
208
|
+
failed = true;
|
|
209
|
+
console.log(` FAIL: ${msg.suite} > ${msg.name} (${msg.duration}ms)`);
|
|
210
|
+
if (msg.error) console.log(` Error: ${msg.error}`);
|
|
211
|
+
break;
|
|
212
|
+
case "test:skip":
|
|
213
|
+
console.log(` SKIP: ${msg.suite} > ${msg.name}`);
|
|
214
|
+
break;
|
|
215
|
+
case "run:complete": {
|
|
216
|
+
const duration = (msg.duration / 1e3).toFixed(1);
|
|
217
|
+
console.log(`\n--- Run complete ---`);
|
|
218
|
+
console.log(`Passed: ${msg.passed} | Failed: ${msg.failed} | Skipped: ${msg.skipped}`);
|
|
219
|
+
console.log(`Duration: ${duration}s`);
|
|
220
|
+
runComplete = true;
|
|
221
|
+
clearTimeout(timer);
|
|
222
|
+
ws.close();
|
|
223
|
+
process.exit(failed || msg.failed > 0 ? 1 : 0);
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
case "error":
|
|
227
|
+
console.error(`Error [${msg.code}]: ${msg.message}`);
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
ws.on("close", () => {
|
|
232
|
+
clearTimeout(timer);
|
|
233
|
+
if (!runComplete) {
|
|
234
|
+
console.error("Connection closed before run completed");
|
|
235
|
+
process.exit(1);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
ws.on("error", (err) => {
|
|
239
|
+
clearTimeout(timer);
|
|
240
|
+
console.error(`Connection error: ${err.message}`);
|
|
241
|
+
process.exit(1);
|
|
242
|
+
});
|
|
247
243
|
}
|
|
248
|
-
|
|
249
|
-
|
|
244
|
+
//#endregion
|
|
245
|
+
//#region src/cli/standalone.ts
|
|
246
|
+
var args = process.argv.slice(2);
|
|
247
|
+
var subcommand = args.find((a) => !a.startsWith("--"));
|
|
250
248
|
function parseFlag(name) {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
249
|
+
const idx = args.indexOf(name);
|
|
250
|
+
if (idx !== -1 && args[idx + 1]) return args[idx + 1];
|
|
251
|
+
}
|
|
252
|
+
function parseFlagAll(name) {
|
|
253
|
+
const values = [];
|
|
254
|
+
for (let i = 0; i < args.length; i++) if (args[i] === name && args[i + 1] && !args[i + 1].startsWith("--")) values.push(args[i + 1]);
|
|
255
|
+
return values;
|
|
254
256
|
}
|
|
255
257
|
function printHelp() {
|
|
256
|
-
|
|
258
|
+
console.log(`Usage: twd-relay [command] [options]
|
|
257
259
|
|
|
258
260
|
Commands:
|
|
259
261
|
(none), serve Start the standalone relay server (default)
|
|
@@ -261,66 +263,86 @@ Commands:
|
|
|
261
263
|
|
|
262
264
|
Options for serve:
|
|
263
265
|
--port <port> Port to listen on (default: 9876)
|
|
266
|
+
--path <path> WebSocket path (default: /__twd/ws)
|
|
264
267
|
|
|
265
268
|
Options for run:
|
|
266
269
|
--port <port> Relay port to connect to (default: 5173)
|
|
270
|
+
--host <host> Relay host to connect to (default: localhost)
|
|
271
|
+
--path <path> WebSocket path (default: /__twd/ws)
|
|
267
272
|
--timeout <ms> Timeout in ms (default: 180000)
|
|
273
|
+
--test <name> Filter tests by name substring (repeatable)
|
|
268
274
|
|
|
269
275
|
Examples:
|
|
270
276
|
twd-relay # start relay on port 9876
|
|
277
|
+
twd-relay serve --path /app/__twd/ws
|
|
271
278
|
twd-relay run # trigger run via Vite dev server on 5173
|
|
272
279
|
twd-relay run --port 9876 # trigger run on custom port
|
|
273
|
-
twd-relay run --
|
|
280
|
+
twd-relay run --host 192.168.1.10 --path /app/__twd/ws
|
|
281
|
+
twd-relay run --timeout 30000 # custom timeout
|
|
282
|
+
twd-relay run --test "login" # run tests matching "login"
|
|
283
|
+
twd-relay run --test "login" --test "signup" # run multiple`);
|
|
274
284
|
}
|
|
275
285
|
if (args.includes("--help") || args.includes("-h")) {
|
|
276
|
-
|
|
277
|
-
|
|
286
|
+
printHelp();
|
|
287
|
+
process.exit(0);
|
|
278
288
|
}
|
|
279
289
|
if (subcommand === "run") {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
290
|
+
const portStr = parseFlag("--port");
|
|
291
|
+
const timeoutStr = parseFlag("--timeout");
|
|
292
|
+
const pathFlag = parseFlag("--path") ?? "/__twd/ws";
|
|
293
|
+
const hostFlag = parseFlag("--host") ?? "localhost";
|
|
294
|
+
const port = portStr ? parseInt(portStr, 10) : 5173;
|
|
295
|
+
if (isNaN(port)) {
|
|
296
|
+
console.error("Invalid port number:", portStr);
|
|
297
|
+
process.exit(1);
|
|
298
|
+
}
|
|
299
|
+
const timeout = timeoutStr ? parseInt(timeoutStr, 10) : 18e4;
|
|
300
|
+
if (isNaN(timeout)) {
|
|
301
|
+
console.error("Invalid timeout value:", timeoutStr);
|
|
302
|
+
process.exit(1);
|
|
303
|
+
}
|
|
304
|
+
const testNames = parseFlagAll("--test");
|
|
305
|
+
run({
|
|
306
|
+
port,
|
|
307
|
+
timeout,
|
|
308
|
+
path: pathFlag,
|
|
309
|
+
host: hostFlag,
|
|
310
|
+
testNames: testNames.length > 0 ? testNames : void 0
|
|
311
|
+
});
|
|
293
312
|
} else if (!subcommand || subcommand === "serve") {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
313
|
+
const portStr = parseFlag("--port");
|
|
314
|
+
const pathFlag = parseFlag("--path") ?? "/__twd/ws";
|
|
315
|
+
let port = 9876;
|
|
316
|
+
if (portStr) {
|
|
317
|
+
port = parseInt(portStr, 10);
|
|
318
|
+
if (isNaN(port)) {
|
|
319
|
+
console.error("Invalid port number:", portStr);
|
|
320
|
+
process.exit(1);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
const server = createServer();
|
|
324
|
+
const relay = createTwdRelay(server, {
|
|
325
|
+
path: pathFlag,
|
|
326
|
+
onError(err) {
|
|
327
|
+
console.error("[twd-relay] Error:", err.message);
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
server.listen(port, () => {
|
|
331
|
+
console.log(`TWD Relay running on ws://localhost:${port}${pathFlag}`);
|
|
332
|
+
console.log("Waiting for connections...");
|
|
333
|
+
});
|
|
334
|
+
function shutdown() {
|
|
335
|
+
console.log("\nShutting down...");
|
|
336
|
+
relay.close();
|
|
337
|
+
server.close(() => {
|
|
338
|
+
process.exit(0);
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
process.on("SIGINT", shutdown);
|
|
342
|
+
process.on("SIGTERM", shutdown);
|
|
322
343
|
} else {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
344
|
+
console.error(`Unknown command: ${subcommand}`);
|
|
345
|
+
printHelp();
|
|
346
|
+
process.exit(1);
|
|
326
347
|
}
|
|
348
|
+
//#endregion
|
package/dist/index.cjs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./relay-CpUORBd7.cjs");exports.createTwdRelay=e.createTwdRelay;
|