@dev-anywhere/relay 0.4.64 → 0.4.65
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/{chunk-PM4ZJUGS.js → chunk-H7OL7UK7.js} +169 -11
- package/dist/chunk-H7OL7UK7.js.map +1 -0
- package/dist/handlers/client.d.ts +6 -1
- package/dist/handlers/client.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/registry.d.ts +19 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +3 -3
- package/dist/chunk-PM4ZJUGS.js.map +0 -1
|
@@ -62,6 +62,7 @@ import { z as z4 } from "zod";
|
|
|
62
62
|
var providerValues = ["claude", "codex"];
|
|
63
63
|
var ptyOwnerValues = ["local-terminal", "proxy-hosted"];
|
|
64
64
|
var sessionModeValues = ["pty", "json"];
|
|
65
|
+
var sessionKindValues = ["agent", "terminal"];
|
|
65
66
|
|
|
66
67
|
// ../../packages/shared/dist/constants/pty.js
|
|
67
68
|
var PtySemanticState = {
|
|
@@ -94,6 +95,7 @@ var agentStatusPhaseValues = [
|
|
|
94
95
|
];
|
|
95
96
|
var SessionInfoSchema = z4.object({
|
|
96
97
|
sessionId: IdSchema,
|
|
98
|
+
kind: z4.enum(sessionKindValues).optional(),
|
|
97
99
|
name: z4.string().optional(),
|
|
98
100
|
// cwd 只用于展示完整路径/tooltip,不作为前端路由或权限判断来源。
|
|
99
101
|
cwd: z4.string().optional(),
|
|
@@ -505,6 +507,14 @@ var ProxyInfoSchema = z8.object({
|
|
|
505
507
|
online: z8.boolean(),
|
|
506
508
|
sessions: z8.array(z8.string()).optional()
|
|
507
509
|
});
|
|
510
|
+
var RelayClientInfoSchema = z8.object({
|
|
511
|
+
clientId: IdSchema,
|
|
512
|
+
proxyId: IdSchema.optional(),
|
|
513
|
+
connectedAt: z8.number().int().nonnegative(),
|
|
514
|
+
current: z8.boolean().optional(),
|
|
515
|
+
userAgent: z8.string().optional(),
|
|
516
|
+
remoteAddress: z8.string().optional()
|
|
517
|
+
});
|
|
508
518
|
var AgentCliAvailabilitySchema = z8.object({
|
|
509
519
|
available: z8.boolean(),
|
|
510
520
|
command: z8.string().optional(),
|
|
@@ -571,6 +581,21 @@ var relayControlDefinitions = [
|
|
|
571
581
|
...RequestIdShape,
|
|
572
582
|
proxies: z8.array(ProxyInfoSchema)
|
|
573
583
|
}),
|
|
584
|
+
control("relay_client_list_request", RequestIdShape),
|
|
585
|
+
control("relay_client_list_response", {
|
|
586
|
+
...RequestIdShape,
|
|
587
|
+
clients: z8.array(RelayClientInfoSchema)
|
|
588
|
+
}),
|
|
589
|
+
control("relay_client_kick", { ...RequiredRequestIdShape, clientId: IdSchema }),
|
|
590
|
+
control("relay_client_kick_response", {
|
|
591
|
+
...RequiredRequestIdShape,
|
|
592
|
+
clientId: IdSchema,
|
|
593
|
+
success: z8.boolean(),
|
|
594
|
+
...RequestErrorShape
|
|
595
|
+
}),
|
|
596
|
+
control("relay_client_kicked", {
|
|
597
|
+
reason: z8.string().optional()
|
|
598
|
+
}),
|
|
574
599
|
control("proxy_select", { ...RequestIdShape, proxyId: IdSchema }),
|
|
575
600
|
control("proxy_select_response", {
|
|
576
601
|
...RequestIdShape,
|
|
@@ -810,9 +835,10 @@ var relayControlDefinitions = [
|
|
|
810
835
|
// 远程创建 JSON 会话,client -> proxy -> response
|
|
811
836
|
control("session_create", {
|
|
812
837
|
...RequestIdShape,
|
|
813
|
-
|
|
838
|
+
kind: z8.enum(sessionKindValues).optional(),
|
|
839
|
+
cwd: z8.string().optional(),
|
|
814
840
|
name: z8.string().optional(),
|
|
815
|
-
provider: z8.enum(providerValues),
|
|
841
|
+
provider: z8.enum(providerValues).optional(),
|
|
816
842
|
mode: z8.enum(sessionModeValues).optional(),
|
|
817
843
|
resumeSessionId: z8.string().optional(),
|
|
818
844
|
// 透传给 claude CLI 的 --permission-mode, undefined 时 proxy 兜底为 "default"
|
|
@@ -824,6 +850,7 @@ var relayControlDefinitions = [
|
|
|
824
850
|
sessionId: IdSchema.optional(),
|
|
825
851
|
name: z8.string().optional(),
|
|
826
852
|
nameLocked: z8.boolean().optional(),
|
|
853
|
+
kind: z8.enum(sessionKindValues).optional(),
|
|
827
854
|
mode: z8.enum(sessionModeValues).optional(),
|
|
828
855
|
provider: z8.enum(providerValues).optional(),
|
|
829
856
|
ptyOwner: z8.enum(ptyOwnerValues).optional(),
|
|
@@ -902,6 +929,7 @@ var relayControlDefinitions = [
|
|
|
902
929
|
control("session_sync", {
|
|
903
930
|
sessions: z8.array(z8.object({
|
|
904
931
|
id: z8.string(),
|
|
932
|
+
kind: z8.enum(sessionKindValues).optional(),
|
|
905
933
|
mode: z8.enum(sessionModeValues),
|
|
906
934
|
provider: z8.enum(providerValues),
|
|
907
935
|
ptyOwner: z8.enum(ptyOwnerValues).optional(),
|
|
@@ -934,6 +962,11 @@ function isClientToProxyRelayControlType(type) {
|
|
|
934
962
|
return ClientToProxyRelayControlTypes.has(type);
|
|
935
963
|
}
|
|
936
964
|
|
|
965
|
+
// ../../packages/shared/dist/constants/relay-close-codes.js
|
|
966
|
+
var RelayCloseCode = {
|
|
967
|
+
CLIENT_KICKED: 4401
|
|
968
|
+
};
|
|
969
|
+
|
|
937
970
|
// ../../packages/shared/dist/binary-frame.js
|
|
938
971
|
var SID_LEN_BYTES = 1;
|
|
939
972
|
var SEQ_BYTES = 4;
|
|
@@ -977,7 +1010,7 @@ var proxyConnectionFSM = defineFSM({
|
|
|
977
1010
|
var RelayRegistry = class {
|
|
978
1011
|
proxyStates = /* @__PURE__ */ new Map();
|
|
979
1012
|
clientBindings = /* @__PURE__ */ new Map();
|
|
980
|
-
connectedClients = /* @__PURE__ */ new
|
|
1013
|
+
connectedClients = /* @__PURE__ */ new Map();
|
|
981
1014
|
registerProxy(proxyId, ws, name) {
|
|
982
1015
|
const existing = this.proxyStates.get(proxyId);
|
|
983
1016
|
if (existing) {
|
|
@@ -1135,21 +1168,43 @@ var RelayRegistry = class {
|
|
|
1135
1168
|
}
|
|
1136
1169
|
return count;
|
|
1137
1170
|
}
|
|
1138
|
-
addClientWs(ws) {
|
|
1139
|
-
this.connectedClients.
|
|
1171
|
+
addClientWs(ws, metadata = {}) {
|
|
1172
|
+
this.connectedClients.set(ws, {
|
|
1173
|
+
connectedAt: metadata.connectedAt ?? Date.now(),
|
|
1174
|
+
...metadata.clientId !== void 0 ? { clientId: metadata.clientId } : {},
|
|
1175
|
+
...metadata.userAgent !== void 0 ? { userAgent: metadata.userAgent } : {},
|
|
1176
|
+
...metadata.remoteAddress !== void 0 ? { remoteAddress: metadata.remoteAddress } : {}
|
|
1177
|
+
});
|
|
1178
|
+
}
|
|
1179
|
+
updateConnectedClientId(ws, clientId) {
|
|
1180
|
+
const metadata = this.connectedClients.get(ws);
|
|
1181
|
+
if (metadata) {
|
|
1182
|
+
metadata.clientId = clientId;
|
|
1183
|
+
return;
|
|
1184
|
+
}
|
|
1185
|
+
this.addClientWs(ws, { clientId });
|
|
1140
1186
|
}
|
|
1141
1187
|
removeClientWs(ws) {
|
|
1142
1188
|
this.connectedClients.delete(ws);
|
|
1143
1189
|
}
|
|
1144
1190
|
getAllClientWs() {
|
|
1145
1191
|
const clients = [];
|
|
1146
|
-
for (const ws of this.connectedClients) {
|
|
1192
|
+
for (const ws of this.connectedClients.keys()) {
|
|
1147
1193
|
if (ws.readyState === WebSocket.OPEN) {
|
|
1148
1194
|
clients.push(ws);
|
|
1149
1195
|
}
|
|
1150
1196
|
}
|
|
1151
1197
|
return clients;
|
|
1152
1198
|
}
|
|
1199
|
+
getConnectedClientSockets(clientId) {
|
|
1200
|
+
const sockets = [];
|
|
1201
|
+
for (const [ws, metadata] of this.connectedClients) {
|
|
1202
|
+
if (metadata.clientId === clientId && ws.readyState === WebSocket.OPEN) {
|
|
1203
|
+
sockets.push(ws);
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
return sockets;
|
|
1207
|
+
}
|
|
1153
1208
|
// 获取单个 proxy 的详细状态信息
|
|
1154
1209
|
getProxyDetail(proxyId) {
|
|
1155
1210
|
const state = this.proxyStates.get(proxyId);
|
|
@@ -1176,6 +1231,22 @@ var RelayRegistry = class {
|
|
|
1176
1231
|
}
|
|
1177
1232
|
return details;
|
|
1178
1233
|
}
|
|
1234
|
+
getConnectedClientDetails(currentClientId) {
|
|
1235
|
+
const details = [];
|
|
1236
|
+
for (const [ws, metadata] of this.connectedClients) {
|
|
1237
|
+
if (ws.readyState !== WebSocket.OPEN || !metadata.clientId) continue;
|
|
1238
|
+
const binding = this.clientBindings.get(metadata.clientId);
|
|
1239
|
+
details.push({
|
|
1240
|
+
clientId: metadata.clientId,
|
|
1241
|
+
...binding?.proxyId !== void 0 ? { proxyId: binding.proxyId } : {},
|
|
1242
|
+
connectedAt: metadata.connectedAt,
|
|
1243
|
+
...metadata.clientId === currentClientId ? { current: true } : {},
|
|
1244
|
+
...metadata.userAgent !== void 0 ? { userAgent: metadata.userAgent } : {},
|
|
1245
|
+
...metadata.remoteAddress !== void 0 ? { remoteAddress: metadata.remoteAddress } : {}
|
|
1246
|
+
});
|
|
1247
|
+
}
|
|
1248
|
+
return details;
|
|
1249
|
+
}
|
|
1179
1250
|
};
|
|
1180
1251
|
|
|
1181
1252
|
// src/health.ts
|
|
@@ -2335,6 +2406,7 @@ function handleVoiceConfigControl(msg, ws, store, logger, providers) {
|
|
|
2335
2406
|
var MAX_JSON_MESSAGE_SIZE2 = 1 * 1024 * 1024;
|
|
2336
2407
|
function handleClientRegister(clientId, clientWs, registry, logger) {
|
|
2337
2408
|
clientWs.clientId = clientId;
|
|
2409
|
+
registry.updateConnectedClientId(clientWs, clientId);
|
|
2338
2410
|
const binding = registry.getClientBinding(clientId);
|
|
2339
2411
|
if (!binding) {
|
|
2340
2412
|
clientWs.send(
|
|
@@ -2369,6 +2441,72 @@ function handleClientRegister(clientId, clientWs, registry, logger) {
|
|
|
2369
2441
|
);
|
|
2370
2442
|
logger.info({ clientId, proxyId, status: "restored" }, "Client registered");
|
|
2371
2443
|
}
|
|
2444
|
+
function handleRelayClientListRequest(clientWs, registry, requestId) {
|
|
2445
|
+
clientWs.send(
|
|
2446
|
+
JSON.stringify({
|
|
2447
|
+
type: "relay_client_list_response",
|
|
2448
|
+
requestId,
|
|
2449
|
+
clients: registry.getConnectedClientDetails(clientWs.clientId)
|
|
2450
|
+
})
|
|
2451
|
+
);
|
|
2452
|
+
}
|
|
2453
|
+
function handleRelayClientKick(clientWs, registry, logger, requestId, targetClientId) {
|
|
2454
|
+
if (targetClientId === clientWs.clientId) {
|
|
2455
|
+
clientWs.send(
|
|
2456
|
+
JSON.stringify({
|
|
2457
|
+
type: "relay_client_kick_response",
|
|
2458
|
+
requestId,
|
|
2459
|
+
clientId: targetClientId,
|
|
2460
|
+
success: false,
|
|
2461
|
+
errorCode: ControlErrorCode.UNKNOWN,
|
|
2462
|
+
error: "\u4E0D\u80FD\u65AD\u5F00\u5F53\u524D\u5BA2\u6237\u7AEF"
|
|
2463
|
+
})
|
|
2464
|
+
);
|
|
2465
|
+
return;
|
|
2466
|
+
}
|
|
2467
|
+
const targets = registry.getConnectedClientSockets(targetClientId);
|
|
2468
|
+
if (targets.length === 0) {
|
|
2469
|
+
clientWs.send(
|
|
2470
|
+
JSON.stringify({
|
|
2471
|
+
type: "relay_client_kick_response",
|
|
2472
|
+
requestId,
|
|
2473
|
+
clientId: targetClientId,
|
|
2474
|
+
success: false,
|
|
2475
|
+
errorCode: ControlErrorCode.UNKNOWN,
|
|
2476
|
+
error: "\u5BA2\u6237\u7AEF\u4E0D\u5728\u7EBF"
|
|
2477
|
+
})
|
|
2478
|
+
);
|
|
2479
|
+
return;
|
|
2480
|
+
}
|
|
2481
|
+
const kickedMessage = JSON.stringify({
|
|
2482
|
+
type: "relay_client_kicked",
|
|
2483
|
+
reason: "\u7531\u5BA2\u6237\u7AEF\u7BA1\u7406\u65AD\u5F00"
|
|
2484
|
+
});
|
|
2485
|
+
for (const target of targets) {
|
|
2486
|
+
try {
|
|
2487
|
+
target.send(kickedMessage);
|
|
2488
|
+
target.close(RelayCloseCode.CLIENT_KICKED, "client kicked");
|
|
2489
|
+
} catch (err) {
|
|
2490
|
+
logger.warn({ err, clientId: targetClientId }, "Failed to close kicked client");
|
|
2491
|
+
target.terminate();
|
|
2492
|
+
} finally {
|
|
2493
|
+
registry.removeClientWs(target);
|
|
2494
|
+
registry.unbindClientById(targetClientId);
|
|
2495
|
+
}
|
|
2496
|
+
}
|
|
2497
|
+
clientWs.send(
|
|
2498
|
+
JSON.stringify({
|
|
2499
|
+
type: "relay_client_kick_response",
|
|
2500
|
+
requestId,
|
|
2501
|
+
clientId: targetClientId,
|
|
2502
|
+
success: true
|
|
2503
|
+
})
|
|
2504
|
+
);
|
|
2505
|
+
logger.info(
|
|
2506
|
+
{ byClientId: clientWs.clientId, targetClientId, targetCount: targets.length },
|
|
2507
|
+
"Relay client kicked"
|
|
2508
|
+
);
|
|
2509
|
+
}
|
|
2372
2510
|
function rejectNotBound(ws) {
|
|
2373
2511
|
ws.send(
|
|
2374
2512
|
JSON.stringify({
|
|
@@ -2405,10 +2543,10 @@ function sendRelayProxyProbeFailure(ws, requestId, error, chaos) {
|
|
|
2405
2543
|
}
|
|
2406
2544
|
ws.send(response);
|
|
2407
2545
|
}
|
|
2408
|
-
function handleClientConnection(ws, registry, logger, chaos, voiceConfigStore, voiceProviders) {
|
|
2546
|
+
function handleClientConnection(ws, registry, logger, chaos, voiceConfigStore, voiceProviders, connectionInfo = {}) {
|
|
2409
2547
|
const clientWs = ws;
|
|
2410
2548
|
clientWs.isAlive = true;
|
|
2411
|
-
registry.addClientWs(clientWs);
|
|
2549
|
+
registry.addClientWs(clientWs, connectionInfo);
|
|
2412
2550
|
clientWs.on("pong", () => {
|
|
2413
2551
|
clientWs.isAlive = true;
|
|
2414
2552
|
});
|
|
@@ -2435,6 +2573,14 @@ function handleClientConnection(ws, registry, logger, chaos, voiceConfigStore, v
|
|
|
2435
2573
|
handleClientRegister(msg.clientId, clientWs, registry, logger);
|
|
2436
2574
|
return;
|
|
2437
2575
|
}
|
|
2576
|
+
if (msg.type === "relay_client_list_request") {
|
|
2577
|
+
handleRelayClientListRequest(clientWs, registry, msg.requestId);
|
|
2578
|
+
return;
|
|
2579
|
+
}
|
|
2580
|
+
if (msg.type === "relay_client_kick") {
|
|
2581
|
+
handleRelayClientKick(clientWs, registry, logger, msg.requestId, msg.clientId);
|
|
2582
|
+
return;
|
|
2583
|
+
}
|
|
2438
2584
|
if (msg.type === "proxy_list_request") {
|
|
2439
2585
|
const proxies = registry.listProxiesWithName().map((p) => ({
|
|
2440
2586
|
...p,
|
|
@@ -3152,6 +3298,15 @@ function createVoiceProviderRegistry(adapters) {
|
|
|
3152
3298
|
// src/server.ts
|
|
3153
3299
|
var MODULE_DIR = dirname3(fileURLToPath2(import.meta.url));
|
|
3154
3300
|
var PACKAGED_FONTS_DIR = resolve(MODULE_DIR, "../assets/fonts");
|
|
3301
|
+
function firstHeaderValue(value) {
|
|
3302
|
+
if (Array.isArray(value)) return value[0];
|
|
3303
|
+
return value;
|
|
3304
|
+
}
|
|
3305
|
+
function requestRemoteAddress(request) {
|
|
3306
|
+
const forwardedFor = firstHeaderValue(request.headers["x-forwarded-for"]);
|
|
3307
|
+
const firstForwarded = forwardedFor?.split(",")[0]?.trim();
|
|
3308
|
+
return firstForwarded || request.socket.remoteAddress;
|
|
3309
|
+
}
|
|
3155
3310
|
function createRelayServer(options) {
|
|
3156
3311
|
const { heartbeatInterval = 3e4, logger, dataDir, proxyToken, clientToken, chaos } = options;
|
|
3157
3312
|
const proxyTokenRequired = typeof proxyToken === "string" && proxyToken.length > 0;
|
|
@@ -3297,8 +3452,11 @@ function createRelayServer(options) {
|
|
|
3297
3452
|
proxyWss.on("connection", (ws) => {
|
|
3298
3453
|
handleProxyConnection(ws, registry, logger, relayChaos);
|
|
3299
3454
|
});
|
|
3300
|
-
clientWss.on("connection", (ws) => {
|
|
3301
|
-
handleClientConnection(ws, registry, logger, relayChaos, voiceConfigStore, voiceProviders
|
|
3455
|
+
clientWss.on("connection", (ws, request) => {
|
|
3456
|
+
handleClientConnection(ws, registry, logger, relayChaos, voiceConfigStore, voiceProviders, {
|
|
3457
|
+
userAgent: firstHeaderValue(request.headers["user-agent"]),
|
|
3458
|
+
remoteAddress: requestRemoteAddress(request)
|
|
3459
|
+
});
|
|
3302
3460
|
});
|
|
3303
3461
|
voiceAsrWss.on("connection", (ws) => {
|
|
3304
3462
|
handleVoiceAsrConnection(ws, voiceConfigStore, logger, voiceProviders);
|
|
@@ -3368,4 +3526,4 @@ export {
|
|
|
3368
3526
|
parseRelayChaosFromEnv,
|
|
3369
3527
|
createRelayServer
|
|
3370
3528
|
};
|
|
3371
|
-
//# sourceMappingURL=chunk-
|
|
3529
|
+
//# sourceMappingURL=chunk-H7OL7UK7.js.map
|