tmex-cli 0.4.2 → 0.4.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/dist/runtime/server.js +396 -88
- package/package.json +1 -1
- package/resources/fe-dist/assets/DevicePage-B9rZioAr.js +26 -0
- package/resources/fe-dist/assets/{DevicePage-CKaPUo7L.js.map → DevicePage-B9rZioAr.js.map} +1 -1
- package/resources/fe-dist/assets/DevicesPage-Bco831ry.js +17 -0
- package/resources/fe-dist/assets/DevicesPage-Bco831ry.js.map +1 -0
- package/resources/fe-dist/assets/SettingsPage-BRs8Unfx.js +17 -0
- package/resources/fe-dist/assets/{SettingsPage-BfkOW0fc.js.map → SettingsPage-BRs8Unfx.js.map} +1 -1
- package/resources/fe-dist/assets/index-40zyi_9K.css +1 -0
- package/resources/fe-dist/assets/index-BhBqXsZI.js +215 -0
- package/resources/fe-dist/assets/index-BhBqXsZI.js.map +1 -0
- package/resources/fe-dist/assets/select-D70hG6p7.js +17 -0
- package/resources/fe-dist/assets/{select-CNlE6MiW.js.map → select-D70hG6p7.js.map} +1 -1
- package/resources/fe-dist/assets/switch-DsyIGzyC.js +12 -0
- package/resources/fe-dist/assets/{switch-CxkzOIL6.js.map → switch-DsyIGzyC.js.map} +1 -1
- package/resources/fe-dist/assets/useValueChanged-CBb-JR7o.js +7 -0
- package/resources/fe-dist/assets/{useValueChanged-CO2U5MoL.js.map → useValueChanged-CBb-JR7o.js.map} +1 -1
- package/resources/fe-dist/index.html +2 -2
- package/resources/gateway-drizzle/0003_glamorous_lizard.sql +1 -0
- package/resources/gateway-drizzle/meta/0003_snapshot.json +542 -0
- package/resources/gateway-drizzle/meta/_journal.json +7 -0
- package/resources/fe-dist/assets/DevicePage-CKaPUo7L.js +0 -26
- package/resources/fe-dist/assets/DevicesPage-FqU-Dxhu.js +0 -17
- package/resources/fe-dist/assets/DevicesPage-FqU-Dxhu.js.map +0 -1
- package/resources/fe-dist/assets/SettingsPage-BfkOW0fc.js +0 -17
- package/resources/fe-dist/assets/index-EgHfq93I.js +0 -449
- package/resources/fe-dist/assets/index-EgHfq93I.js.map +0 -1
- package/resources/fe-dist/assets/index-Ytlj3p_q.css +0 -1
- package/resources/fe-dist/assets/select-CNlE6MiW.js +0 -17
- package/resources/fe-dist/assets/switch-CxkzOIL6.js +0 -12
- package/resources/fe-dist/assets/useValueChanged-CO2U5MoL.js +0 -7
package/dist/runtime/server.js
CHANGED
|
@@ -20524,6 +20524,8 @@ var I18N_RESOURCES = {
|
|
|
20524
20524
|
chatId: "Chat ID",
|
|
20525
20525
|
applyTime: "Application Time",
|
|
20526
20526
|
gatewayOnline: "\uD83D\uDFE2 Gateway online @ {{siteName}}",
|
|
20527
|
+
deviceConnectionError: `\uD83D\uDD34 {{siteName}}: Connection error on device "{{deviceName}}" ({{host}}) [{{category}}]
|
|
20528
|
+
{{error}}`,
|
|
20527
20529
|
authSuccess: "\u2705 Authorized. You will now receive notifications.",
|
|
20528
20530
|
authPending: "\u23F3 Authorization request received. Please approve in tmex settings.",
|
|
20529
20531
|
authFailed: "\u274C Authorization request failed. Please contact administrator.",
|
|
@@ -20564,11 +20566,30 @@ Time: {{time}}`,
|
|
|
20564
20566
|
hostNotFound: "Host not found: Unable to resolve hostname. Please check DNS or hostname configuration.",
|
|
20565
20567
|
handshakeFailed: "Handshake failed: Unable to establish secure connection. Possibly incompatible key exchange algorithm.",
|
|
20566
20568
|
tmuxUnavailable: "Remote tmux unavailable or failed to start. Please ensure tmux is installed and available in the remote shell PATH.",
|
|
20569
|
+
connectionClosed: "Connection closed, attempting to reconnect",
|
|
20567
20570
|
unknown: "Connection failed: {{message}}",
|
|
20568
20571
|
reconnecting: "Connection interrupted, reconnecting in {{delay}} seconds ({{attempt}}/{{maxRetries}})",
|
|
20569
20572
|
reconnectFailed: "Auto-reconnect failed, please retry manually",
|
|
20570
20573
|
reconnected: "Device reconnected automatically"
|
|
20571
20574
|
},
|
|
20575
|
+
deviceStatus: {
|
|
20576
|
+
reconnecting: "Reconnecting {{delay}}s",
|
|
20577
|
+
offline: "Offline",
|
|
20578
|
+
errorBadge: {
|
|
20579
|
+
authFailed: "Auth failed",
|
|
20580
|
+
agentUnavailable: "Agent unavailable",
|
|
20581
|
+
agentNoIdentity: "Agent has no keys",
|
|
20582
|
+
configRefNotSupported: "SSH Config unsupported",
|
|
20583
|
+
networkUnreachable: "Network unreachable",
|
|
20584
|
+
connectionRefused: "Refused",
|
|
20585
|
+
timeout: "Timeout",
|
|
20586
|
+
hostNotFound: "Host not found",
|
|
20587
|
+
handshakeFailed: "Handshake failed",
|
|
20588
|
+
tmuxUnavailable: "Tmux unavailable",
|
|
20589
|
+
connectionClosed: "Disconnected",
|
|
20590
|
+
unknown: "Connection error"
|
|
20591
|
+
}
|
|
20592
|
+
},
|
|
20572
20593
|
websocket: {
|
|
20573
20594
|
error: "WebSocket connection error",
|
|
20574
20595
|
checkGateway: "Please check Gateway status",
|
|
@@ -20862,6 +20883,8 @@ Time: {{time}}`,
|
|
|
20862
20883
|
chatId: "chatId",
|
|
20863
20884
|
applyTime: "\u7533\u8BF7\u65F6\u95F4",
|
|
20864
20885
|
gatewayOnline: "\uD83D\uDFE2 Gateway online @ {{siteName}}",
|
|
20886
|
+
deviceConnectionError: `\uD83D\uDD34 {{siteName}}\uFF1A\u8BBE\u5907\u300C{{deviceName}}\u300D({{host}}) \u8FDE\u63A5\u5F02\u5E38 [{{category}}]
|
|
20887
|
+
{{error}}`,
|
|
20865
20888
|
authSuccess: "\u2705 \u5DF2\u6388\u6743\uFF0C\u53EF\u63A5\u6536\u901A\u77E5\u3002",
|
|
20866
20889
|
authPending: "\u23F3 \u5DF2\u6536\u5230\u6388\u6743\u7533\u8BF7\uFF0C\u8BF7\u5728 tmex \u8BBE\u7F6E\u9875\u5BA1\u6279\u3002",
|
|
20867
20890
|
authFailed: "\u274C \u6388\u6743\u7533\u8BF7\u5931\u8D25\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u3002",
|
|
@@ -20902,11 +20925,30 @@ Bot\uFF1A{{botName}}
|
|
|
20902
20925
|
hostNotFound: "\u4E3B\u673A\u672A\u627E\u5230\uFF1A\u65E0\u6CD5\u89E3\u6790\u4E3B\u673A\u5730\u5740\uFF0C\u8BF7\u68C0\u67E5 DNS \u6216\u4E3B\u673A\u540D\u662F\u5426\u6B63\u786E",
|
|
20903
20926
|
handshakeFailed: "\u63E1\u624B\u5931\u8D25\uFF1A\u65E0\u6CD5\u5EFA\u7ACB\u5B89\u5168\u8FDE\u63A5\uFF0C\u53EF\u80FD\u662F\u5BC6\u94A5\u4EA4\u6362\u7B97\u6CD5\u4E0D\u517C\u5BB9",
|
|
20904
20927
|
tmuxUnavailable: "\u8FDC\u7AEF tmux \u4E0D\u53EF\u7528\u6216\u542F\u52A8\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u8FDC\u7AEF\u662F\u5426\u5DF2\u5B89\u88C5 tmux\uFF0C\u4E14\u8FDC\u7AEF shell PATH \u53EF\u627E\u5230 tmux",
|
|
20928
|
+
connectionClosed: "\u8FDE\u63A5\u5DF2\u65AD\u5F00\uFF0C\u5C1D\u8BD5\u91CD\u8FDE\u4E2D",
|
|
20905
20929
|
unknown: "\u8FDE\u63A5\u5931\u8D25\uFF1A{{message}}",
|
|
20906
20930
|
reconnecting: "\u8FDE\u63A5\u4E2D\u65AD\uFF0C{{delay}} \u79D2\u540E\u81EA\u52A8\u91CD\u8FDE\uFF08{{attempt}}/{{maxRetries}}\uFF09",
|
|
20907
20931
|
reconnectFailed: "\u81EA\u52A8\u91CD\u8FDE\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u91CD\u8BD5",
|
|
20908
20932
|
reconnected: "\u8BBE\u5907\u5DF2\u81EA\u52A8\u91CD\u8FDE"
|
|
20909
20933
|
},
|
|
20934
|
+
deviceStatus: {
|
|
20935
|
+
reconnecting: "\u91CD\u8FDE\u4E2D {{delay}}s",
|
|
20936
|
+
offline: "\u79BB\u7EBF",
|
|
20937
|
+
errorBadge: {
|
|
20938
|
+
authFailed: "\u8BA4\u8BC1\u5931\u8D25",
|
|
20939
|
+
agentUnavailable: "Agent \u4E0D\u53EF\u7528",
|
|
20940
|
+
agentNoIdentity: "Agent \u65E0\u5BC6\u94A5",
|
|
20941
|
+
configRefNotSupported: "\u4E0D\u652F\u6301 SSH Config",
|
|
20942
|
+
networkUnreachable: "\u7F51\u7EDC\u4E0D\u53EF\u8FBE",
|
|
20943
|
+
connectionRefused: "\u8FDE\u63A5\u88AB\u62D2",
|
|
20944
|
+
timeout: "\u8FDE\u63A5\u8D85\u65F6",
|
|
20945
|
+
hostNotFound: "\u4E3B\u673A\u672A\u627E\u5230",
|
|
20946
|
+
handshakeFailed: "\u63E1\u624B\u5931\u8D25",
|
|
20947
|
+
tmuxUnavailable: "tmux \u4E0D\u53EF\u7528",
|
|
20948
|
+
connectionClosed: "\u8FDE\u63A5\u5DF2\u65AD\u5F00",
|
|
20949
|
+
unknown: "\u8FDE\u63A5\u5F02\u5E38"
|
|
20950
|
+
}
|
|
20951
|
+
},
|
|
20910
20952
|
websocket: {
|
|
20911
20953
|
error: "WebSocket \u8FDE\u63A5\u9519\u8BEF",
|
|
20912
20954
|
checkGateway: "\u8BF7\u68C0\u67E5 Gateway \u72B6\u6001",
|
|
@@ -21200,6 +21242,8 @@ Bot\uFF1A{{botName}}
|
|
|
21200
21242
|
chatId: "Chat ID",
|
|
21201
21243
|
applyTime: "\u7533\u8ACB\u6642\u9593",
|
|
21202
21244
|
gatewayOnline: "\uD83D\uDFE2 Gateway online @ {{siteName}}",
|
|
21245
|
+
deviceConnectionError: `\uD83D\uDD34 {{siteName}}\uFF1A\u30C7\u30D0\u30A4\u30B9\u300C{{deviceName}}\u300D({{host}}) \u3067\u63A5\u7D9A\u30A8\u30E9\u30FC [{{category}}]
|
|
21246
|
+
{{error}}`,
|
|
21203
21247
|
authSuccess: "\u2705 \u627F\u8A8D\u3055\u308C\u307E\u3057\u305F\u3002\u901A\u77E5\u3092\u53D7\u4FE1\u3067\u304D\u307E\u3059\u3002",
|
|
21204
21248
|
authPending: "\u23F3 \u8A8D\u8A3C\u30EA\u30AF\u30A8\u30B9\u30C8\u3092\u53D7\u4FE1\u3057\u307E\u3057\u305F\u3002tmex \u8A2D\u5B9A\u30DA\u30FC\u30B8\u3067\u627F\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
21205
21249
|
authFailed: "\u274C \u8A8D\u8A3C\u30EA\u30AF\u30A8\u30B9\u30C8\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002\u7BA1\u7406\u8005\u306B\u9023\u7D61\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
@@ -21240,11 +21284,30 @@ Bot\uFF1A{{botName}}
|
|
|
21240
21284
|
hostNotFound: "\u30DB\u30B9\u30C8\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\uFF1A\u30DB\u30B9\u30C8\u540D\u3092\u89E3\u6C7A\u3067\u304D\u307E\u305B\u3093\u3002DNS \u307E\u305F\u306F\u30DB\u30B9\u30C8\u540D\u8A2D\u5B9A\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
21241
21285
|
handshakeFailed: "\u30CF\u30F3\u30C9\u30B7\u30A7\u30A4\u30AF\u306B\u5931\u6557\u3057\u307E\u3057\u305F\uFF1A\u5B89\u5168\u306A\u63A5\u7D9A\u3092\u78BA\u7ACB\u3067\u304D\u307E\u305B\u3093\u3002\u30AD\u30FC\u4EA4\u63DB\u30A2\u30EB\u30B4\u30EA\u30BA\u30E0\u304C\u4E92\u63DB\u6027\u304C\u306A\u3044\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002",
|
|
21242
21286
|
tmuxUnavailable: "\u30EA\u30E2\u30FC\u30C8 tmux \u304C\u5229\u7528\u3067\u304D\u306A\u3044\u304B\u8D77\u52D5\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002tmux \u304C\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3055\u308C\u3001\u30EA\u30E2\u30FC\u30C8 shell \u306E PATH \u304B\u3089\u53C2\u7167\u3067\u304D\u308B\u3053\u3068\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
21287
|
+
connectionClosed: "\u63A5\u7D9A\u304C\u5207\u65AD\u3055\u308C\u307E\u3057\u305F\u3002\u518D\u63A5\u7D9A\u3092\u8A66\u307F\u3066\u3044\u307E\u3059",
|
|
21243
21288
|
unknown: "\u63A5\u7D9A\u306B\u5931\u6557\u3057\u307E\u3057\u305F\uFF1A{{message}}",
|
|
21244
21289
|
reconnecting: "\u63A5\u7D9A\u304C\u4E2D\u65AD\u3055\u308C\u307E\u3057\u305F\u3002{{delay}} \u79D2\u5F8C\u306B\u518D\u63A5\u7D9A\u3057\u307E\u3059\uFF08{{attempt}}/{{maxRetries}}\uFF09",
|
|
21245
21290
|
reconnectFailed: "\u81EA\u52D5\u518D\u63A5\u7D9A\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002\u624B\u52D5\u3067\u518D\u8A66\u884C\u3057\u3066\u304F\u3060\u3055\u3044",
|
|
21246
21291
|
reconnected: "\u30C7\u30D0\u30A4\u30B9\u304C\u81EA\u52D5\u7684\u306B\u518D\u63A5\u7D9A\u3055\u308C\u307E\u3057\u305F"
|
|
21247
21292
|
},
|
|
21293
|
+
deviceStatus: {
|
|
21294
|
+
reconnecting: "\u518D\u63A5\u7D9A\u4E2D {{delay}}s",
|
|
21295
|
+
offline: "\u30AA\u30D5\u30E9\u30A4\u30F3",
|
|
21296
|
+
errorBadge: {
|
|
21297
|
+
authFailed: "\u8A8D\u8A3C\u5931\u6557",
|
|
21298
|
+
agentUnavailable: "Agent \u5229\u7528\u4E0D\u53EF",
|
|
21299
|
+
agentNoIdentity: "Agent \u306B\u9375\u306A\u3057",
|
|
21300
|
+
configRefNotSupported: "SSH Config \u975E\u5BFE\u5FDC",
|
|
21301
|
+
networkUnreachable: "\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u4E0D\u53EF\u9054",
|
|
21302
|
+
connectionRefused: "\u63A5\u7D9A\u62D2\u5426",
|
|
21303
|
+
timeout: "\u30BF\u30A4\u30E0\u30A2\u30A6\u30C8",
|
|
21304
|
+
hostNotFound: "\u30DB\u30B9\u30C8\u672A\u691C\u51FA",
|
|
21305
|
+
handshakeFailed: "\u30CF\u30F3\u30C9\u30B7\u30A7\u30A4\u30AF\u5931\u6557",
|
|
21306
|
+
tmuxUnavailable: "tmux \u5229\u7528\u4E0D\u53EF",
|
|
21307
|
+
connectionClosed: "\u5207\u65AD",
|
|
21308
|
+
unknown: "\u63A5\u7D9A\u30A8\u30E9\u30FC"
|
|
21309
|
+
}
|
|
21310
|
+
},
|
|
21248
21311
|
websocket: {
|
|
21249
21312
|
error: "WebSocket \u63A5\u7D9A\u30A8\u30E9\u30FC",
|
|
21250
21313
|
checkGateway: "Gateway \u72B6\u614B\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044",
|
|
@@ -28884,7 +28947,8 @@ var deviceRuntimeStatus = sqliteTable("device_runtime_status", {
|
|
|
28884
28947
|
deviceId: text("device_id").primaryKey().references(() => devices.id, { onDelete: "cascade" }),
|
|
28885
28948
|
lastSeenAt: text("last_seen_at"),
|
|
28886
28949
|
tmuxAvailable: integer("tmux_available", { mode: "boolean" }).notNull().default(false),
|
|
28887
|
-
lastError: text("last_error")
|
|
28950
|
+
lastError: text("last_error"),
|
|
28951
|
+
lastErrorType: text("last_error_type")
|
|
28888
28952
|
});
|
|
28889
28953
|
var webhookEndpoints = sqliteTable("webhook_endpoints", {
|
|
28890
28954
|
id: text("id").primaryKey(),
|
|
@@ -29057,7 +29121,8 @@ function createDevice(device) {
|
|
|
29057
29121
|
deviceId: device.id,
|
|
29058
29122
|
lastSeenAt: null,
|
|
29059
29123
|
tmuxAvailable: false,
|
|
29060
|
-
lastError: null
|
|
29124
|
+
lastError: null,
|
|
29125
|
+
lastErrorType: null
|
|
29061
29126
|
}).onConflictDoNothing({ target: deviceRuntimeStatus.deviceId }).run();
|
|
29062
29127
|
});
|
|
29063
29128
|
}
|
|
@@ -29114,6 +29179,26 @@ function deleteDevice(id) {
|
|
|
29114
29179
|
const orm = getDb();
|
|
29115
29180
|
orm.delete(devices).where(eq(devices.id, id)).run();
|
|
29116
29181
|
}
|
|
29182
|
+
function getDeviceRuntimeStatus(deviceId) {
|
|
29183
|
+
const orm = getDb();
|
|
29184
|
+
const row = orm.select().from(deviceRuntimeStatus).where(eq(deviceRuntimeStatus.deviceId, deviceId)).get();
|
|
29185
|
+
if (!row) {
|
|
29186
|
+
return {
|
|
29187
|
+
deviceId,
|
|
29188
|
+
lastSeenAt: null,
|
|
29189
|
+
tmuxAvailable: false,
|
|
29190
|
+
lastError: null,
|
|
29191
|
+
lastErrorType: null
|
|
29192
|
+
};
|
|
29193
|
+
}
|
|
29194
|
+
return {
|
|
29195
|
+
deviceId: row.deviceId,
|
|
29196
|
+
lastSeenAt: row.lastSeenAt,
|
|
29197
|
+
tmuxAvailable: row.tmuxAvailable,
|
|
29198
|
+
lastError: row.lastError,
|
|
29199
|
+
lastErrorType: row.lastErrorType
|
|
29200
|
+
};
|
|
29201
|
+
}
|
|
29117
29202
|
function updateDeviceRuntimeStatus(deviceId, status) {
|
|
29118
29203
|
const orm = getDb();
|
|
29119
29204
|
const setValues = {};
|
|
@@ -29126,6 +29211,9 @@ function updateDeviceRuntimeStatus(deviceId, status) {
|
|
|
29126
29211
|
if (status.lastError !== undefined) {
|
|
29127
29212
|
setValues.lastError = status.lastError;
|
|
29128
29213
|
}
|
|
29214
|
+
if (status.lastErrorType !== undefined) {
|
|
29215
|
+
setValues.lastErrorType = status.lastErrorType;
|
|
29216
|
+
}
|
|
29129
29217
|
if (Object.keys(setValues).length === 0) {
|
|
29130
29218
|
return;
|
|
29131
29219
|
}
|
|
@@ -52033,6 +52121,241 @@ var eventNotifier = new EventNotifier;
|
|
|
52033
52121
|
import { mkdirSync, rmSync } from "fs";
|
|
52034
52122
|
import { homedir } from "os";
|
|
52035
52123
|
|
|
52124
|
+
// ../../apps/gateway/src/ws/error-classify.ts
|
|
52125
|
+
function classifySshError(error) {
|
|
52126
|
+
const msg = error.message.toLowerCase();
|
|
52127
|
+
if (msg.includes("ssh_config_ref_not_supported")) {
|
|
52128
|
+
return {
|
|
52129
|
+
type: "ssh_config_ref_not_supported",
|
|
52130
|
+
messageKey: "sshError.configRefNotSupported"
|
|
52131
|
+
};
|
|
52132
|
+
}
|
|
52133
|
+
if (msg.includes("ssh_auth_sock") || msg.includes("auth_sock")) {
|
|
52134
|
+
return {
|
|
52135
|
+
type: "agent_unavailable",
|
|
52136
|
+
messageKey: "sshError.agentUnavailable"
|
|
52137
|
+
};
|
|
52138
|
+
}
|
|
52139
|
+
if (msg.includes("agent") && (msg.includes("no identities") || msg.includes("failure"))) {
|
|
52140
|
+
return {
|
|
52141
|
+
type: "agent_no_identity",
|
|
52142
|
+
messageKey: "sshError.agentNoIdentities"
|
|
52143
|
+
};
|
|
52144
|
+
}
|
|
52145
|
+
if (msg.includes("permission denied")) {
|
|
52146
|
+
return {
|
|
52147
|
+
type: "auth_failed",
|
|
52148
|
+
messageKey: "sshError.authFailed"
|
|
52149
|
+
};
|
|
52150
|
+
}
|
|
52151
|
+
if (msg.includes("all configured authentication methods failed")) {
|
|
52152
|
+
return {
|
|
52153
|
+
type: "auth_failed",
|
|
52154
|
+
messageKey: "sshError.authFailedGeneric"
|
|
52155
|
+
};
|
|
52156
|
+
}
|
|
52157
|
+
if (msg.includes("enetunreach") || msg.includes("ehostunreach")) {
|
|
52158
|
+
return {
|
|
52159
|
+
type: "network_unreachable",
|
|
52160
|
+
messageKey: "sshError.networkUnreachable"
|
|
52161
|
+
};
|
|
52162
|
+
}
|
|
52163
|
+
if (msg.includes("connect refused") || msg.includes("connection refused") || msg.includes("econnrefused")) {
|
|
52164
|
+
return {
|
|
52165
|
+
type: "connection_refused",
|
|
52166
|
+
messageKey: "sshError.connectionRefused"
|
|
52167
|
+
};
|
|
52168
|
+
}
|
|
52169
|
+
if (msg.includes("timeout") || msg.includes("etimedout")) {
|
|
52170
|
+
return {
|
|
52171
|
+
type: "timeout",
|
|
52172
|
+
messageKey: "sshError.connectionTimeout"
|
|
52173
|
+
};
|
|
52174
|
+
}
|
|
52175
|
+
if (msg.includes("host not found") || msg.includes("getaddrinfo") || msg.includes("enotfound")) {
|
|
52176
|
+
return {
|
|
52177
|
+
type: "host_not_found",
|
|
52178
|
+
messageKey: "sshError.hostNotFound"
|
|
52179
|
+
};
|
|
52180
|
+
}
|
|
52181
|
+
if (msg.includes("handshake failed") || msg.includes("unable to verify")) {
|
|
52182
|
+
return {
|
|
52183
|
+
type: "handshake_failed",
|
|
52184
|
+
messageKey: "sshError.handshakeFailed"
|
|
52185
|
+
};
|
|
52186
|
+
}
|
|
52187
|
+
if (msg.includes("remote tmux unavailable") || msg.includes("tmux_not_found") || msg.includes("tmux: command not found") || msg.includes("tmux control mode not ready") || msg.includes("tmux exited") || msg.includes("tmux_exec_failed")) {
|
|
52188
|
+
return {
|
|
52189
|
+
type: "tmux_unavailable",
|
|
52190
|
+
messageKey: "sshError.tmuxUnavailable"
|
|
52191
|
+
};
|
|
52192
|
+
}
|
|
52193
|
+
if (msg.includes("ssh_connection_closed") || msg.includes("connection closed") || msg.includes("ssh command channel not ready") || msg.includes("ssh connection not ready") || msg.includes("channel closed")) {
|
|
52194
|
+
return {
|
|
52195
|
+
type: "connection_closed",
|
|
52196
|
+
messageKey: "sshError.connectionClosed"
|
|
52197
|
+
};
|
|
52198
|
+
}
|
|
52199
|
+
return {
|
|
52200
|
+
type: "unknown",
|
|
52201
|
+
messageKey: "sshError.unknown",
|
|
52202
|
+
messageParams: { message: error.message }
|
|
52203
|
+
};
|
|
52204
|
+
}
|
|
52205
|
+
|
|
52206
|
+
// ../../apps/gateway/src/push/connection-alerts.ts
|
|
52207
|
+
var NOTIFY_THROTTLE_MS = 5 * 60 * 1000;
|
|
52208
|
+
function toErrorObject(err) {
|
|
52209
|
+
if (err instanceof Error) {
|
|
52210
|
+
return err;
|
|
52211
|
+
}
|
|
52212
|
+
if (typeof err === "string") {
|
|
52213
|
+
return new Error(err);
|
|
52214
|
+
}
|
|
52215
|
+
try {
|
|
52216
|
+
return new Error(JSON.stringify(err));
|
|
52217
|
+
} catch {
|
|
52218
|
+
return new Error(String(err));
|
|
52219
|
+
}
|
|
52220
|
+
}
|
|
52221
|
+
|
|
52222
|
+
class ConnectionAlertNotifier {
|
|
52223
|
+
throttleMap = new Map;
|
|
52224
|
+
broadcaster = null;
|
|
52225
|
+
settingsProvider = () => getSiteSettings();
|
|
52226
|
+
persister = (deviceId, friendlyMessage, errorType) => {
|
|
52227
|
+
updateDeviceRuntimeStatus(deviceId, {
|
|
52228
|
+
lastSeenAt: new Date().toISOString(),
|
|
52229
|
+
lastError: friendlyMessage,
|
|
52230
|
+
lastErrorType: errorType
|
|
52231
|
+
});
|
|
52232
|
+
};
|
|
52233
|
+
telegramSender = (text2) => telegramService.sendToAuthorizedChats({ text: text2 });
|
|
52234
|
+
setBroadcaster(broadcaster) {
|
|
52235
|
+
this.broadcaster = broadcaster;
|
|
52236
|
+
}
|
|
52237
|
+
setSettingsProvider(provider) {
|
|
52238
|
+
this.settingsProvider = provider;
|
|
52239
|
+
}
|
|
52240
|
+
setPersister(persister) {
|
|
52241
|
+
this.persister = persister;
|
|
52242
|
+
}
|
|
52243
|
+
setTelegramSender(sender) {
|
|
52244
|
+
this.telegramSender = sender;
|
|
52245
|
+
}
|
|
52246
|
+
async notify(alert) {
|
|
52247
|
+
const { device, error, source, silentTelegram = false, persist = true } = alert;
|
|
52248
|
+
const errObj = toErrorObject(error);
|
|
52249
|
+
const classified = classifySshError(errObj);
|
|
52250
|
+
const friendlyMessage = t2(classified.messageKey, { ...classified.messageParams });
|
|
52251
|
+
const rawMessage = errObj.message;
|
|
52252
|
+
console.error(`[conn-alert] device ${device.id} (${device.name}) source=${source} type=${classified.type}: ${rawMessage}`);
|
|
52253
|
+
if (persist) {
|
|
52254
|
+
try {
|
|
52255
|
+
this.persister(device.id, friendlyMessage, classified.type);
|
|
52256
|
+
} catch (dbErr) {
|
|
52257
|
+
console.error("[conn-alert] failed to persist runtime status:", dbErr);
|
|
52258
|
+
}
|
|
52259
|
+
}
|
|
52260
|
+
if (this.broadcaster) {
|
|
52261
|
+
try {
|
|
52262
|
+
this.broadcaster(device.id, {
|
|
52263
|
+
deviceId: device.id,
|
|
52264
|
+
type: "error",
|
|
52265
|
+
errorType: classified.type,
|
|
52266
|
+
message: friendlyMessage,
|
|
52267
|
+
rawMessage
|
|
52268
|
+
});
|
|
52269
|
+
} catch (broadcastErr) {
|
|
52270
|
+
console.error("[conn-alert] failed to broadcast:", broadcastErr);
|
|
52271
|
+
}
|
|
52272
|
+
}
|
|
52273
|
+
if (!silentTelegram && this.shouldSendTelegram(device.id, classified.type)) {
|
|
52274
|
+
await this.sendTelegram(device, classified.type, friendlyMessage, rawMessage);
|
|
52275
|
+
}
|
|
52276
|
+
return {
|
|
52277
|
+
errorType: classified.type,
|
|
52278
|
+
messageKey: classified.messageKey,
|
|
52279
|
+
message: friendlyMessage,
|
|
52280
|
+
rawMessage
|
|
52281
|
+
};
|
|
52282
|
+
}
|
|
52283
|
+
clear(deviceId) {
|
|
52284
|
+
for (const key of this.throttleMap.keys()) {
|
|
52285
|
+
if (key.startsWith(`${deviceId}:`)) {
|
|
52286
|
+
this.throttleMap.delete(key);
|
|
52287
|
+
}
|
|
52288
|
+
}
|
|
52289
|
+
}
|
|
52290
|
+
shouldSendTelegram(deviceId, errorType) {
|
|
52291
|
+
const key = `${deviceId}:${errorType}`;
|
|
52292
|
+
const now = Date.now();
|
|
52293
|
+
const last = this.throttleMap.get(key) ?? 0;
|
|
52294
|
+
if (now - last < NOTIFY_THROTTLE_MS) {
|
|
52295
|
+
return false;
|
|
52296
|
+
}
|
|
52297
|
+
this.throttleMap.set(key, now);
|
|
52298
|
+
for (const [otherKey, ts] of this.throttleMap) {
|
|
52299
|
+
if (otherKey !== key && otherKey.startsWith(`${deviceId}:`) && now - ts >= NOTIFY_THROTTLE_MS) {
|
|
52300
|
+
this.throttleMap.delete(otherKey);
|
|
52301
|
+
}
|
|
52302
|
+
}
|
|
52303
|
+
return true;
|
|
52304
|
+
}
|
|
52305
|
+
async sendTelegram(device, errorType, friendlyMessage, rawMessage) {
|
|
52306
|
+
let settings;
|
|
52307
|
+
try {
|
|
52308
|
+
settings = this.settingsProvider();
|
|
52309
|
+
} catch (err) {
|
|
52310
|
+
console.error("[conn-alert] failed to read site settings:", err);
|
|
52311
|
+
return;
|
|
52312
|
+
}
|
|
52313
|
+
const categoryKey = `deviceStatus.errorBadge.${toBadgeKey(errorType)}`;
|
|
52314
|
+
const translatedCategory = t2(categoryKey, { defaultValue: errorType });
|
|
52315
|
+
const text2 = t2("telegram.deviceConnectionError", {
|
|
52316
|
+
siteName: settings.siteName,
|
|
52317
|
+
deviceName: device.name,
|
|
52318
|
+
host: device.host ?? "-",
|
|
52319
|
+
category: translatedCategory,
|
|
52320
|
+
error: friendlyMessage || rawMessage
|
|
52321
|
+
});
|
|
52322
|
+
try {
|
|
52323
|
+
await this.telegramSender(text2);
|
|
52324
|
+
} catch (notifyErr) {
|
|
52325
|
+
console.error("[conn-alert] telegram send failed:", notifyErr);
|
|
52326
|
+
}
|
|
52327
|
+
}
|
|
52328
|
+
}
|
|
52329
|
+
function toBadgeKey(errorType) {
|
|
52330
|
+
switch (errorType) {
|
|
52331
|
+
case "auth_failed":
|
|
52332
|
+
return "authFailed";
|
|
52333
|
+
case "agent_unavailable":
|
|
52334
|
+
return "agentUnavailable";
|
|
52335
|
+
case "agent_no_identity":
|
|
52336
|
+
return "agentNoIdentity";
|
|
52337
|
+
case "ssh_config_ref_not_supported":
|
|
52338
|
+
return "configRefNotSupported";
|
|
52339
|
+
case "network_unreachable":
|
|
52340
|
+
return "networkUnreachable";
|
|
52341
|
+
case "connection_refused":
|
|
52342
|
+
return "connectionRefused";
|
|
52343
|
+
case "timeout":
|
|
52344
|
+
return "timeout";
|
|
52345
|
+
case "host_not_found":
|
|
52346
|
+
return "hostNotFound";
|
|
52347
|
+
case "handshake_failed":
|
|
52348
|
+
return "handshakeFailed";
|
|
52349
|
+
case "tmux_unavailable":
|
|
52350
|
+
return "tmuxUnavailable";
|
|
52351
|
+
case "connection_closed":
|
|
52352
|
+
return "connectionClosed";
|
|
52353
|
+
default:
|
|
52354
|
+
return "unknown";
|
|
52355
|
+
}
|
|
52356
|
+
}
|
|
52357
|
+
var connectionAlertNotifier = new ConnectionAlertNotifier;
|
|
52358
|
+
|
|
52036
52359
|
// ../../apps/gateway/src/tmux/local-shell-path.ts
|
|
52037
52360
|
import { existsSync } from "fs";
|
|
52038
52361
|
import { delimiter, join as join2 } from "path";
|
|
@@ -53058,13 +53381,26 @@ class LocalExternalTmuxConnection {
|
|
|
53058
53381
|
this.recoverFromTargetMissingError(message);
|
|
53059
53382
|
return result;
|
|
53060
53383
|
}
|
|
53061
|
-
|
|
53062
|
-
lastSeenAt: new Date().toISOString(),
|
|
53063
|
-
tmuxAvailable: false,
|
|
53064
|
-
lastError: message
|
|
53065
|
-
});
|
|
53384
|
+
this.notifyRuntimeError(message);
|
|
53066
53385
|
throw new Error(message);
|
|
53067
53386
|
}
|
|
53387
|
+
async notifyRuntimeError(message) {
|
|
53388
|
+
const device = getDeviceById(this.deviceId);
|
|
53389
|
+
if (!device) {
|
|
53390
|
+
updateDeviceRuntimeStatus(this.deviceId, {
|
|
53391
|
+
lastSeenAt: new Date().toISOString(),
|
|
53392
|
+
tmuxAvailable: false,
|
|
53393
|
+
lastError: message
|
|
53394
|
+
});
|
|
53395
|
+
return;
|
|
53396
|
+
}
|
|
53397
|
+
await connectionAlertNotifier.notify({
|
|
53398
|
+
device,
|
|
53399
|
+
error: new Error(message),
|
|
53400
|
+
source: "runtime",
|
|
53401
|
+
silentTelegram: true
|
|
53402
|
+
});
|
|
53403
|
+
}
|
|
53068
53404
|
async runTmuxAllowFailure(argv) {
|
|
53069
53405
|
return this.deps.run(["tmux", ...argv]);
|
|
53070
53406
|
}
|
|
@@ -54053,7 +54389,9 @@ class SshExternalTmuxConnection {
|
|
|
54053
54389
|
const next = this.pipeTransition.catch(() => {
|
|
54054
54390
|
return;
|
|
54055
54391
|
}).then(task);
|
|
54056
|
-
this.pipeTransition = next
|
|
54392
|
+
this.pipeTransition = next.catch(() => {
|
|
54393
|
+
return;
|
|
54394
|
+
});
|
|
54057
54395
|
return next;
|
|
54058
54396
|
}
|
|
54059
54397
|
async runTmux(argv, allowTargetMissing = false, timeoutMs = 1e4) {
|
|
@@ -54096,6 +54434,8 @@ class SshExternalTmuxConnection {
|
|
|
54096
54434
|
}).then(() => this.executeShellCommand(command, timeoutMs));
|
|
54097
54435
|
this.commandQueue = next.then(() => {
|
|
54098
54436
|
return;
|
|
54437
|
+
}, () => {
|
|
54438
|
+
return;
|
|
54099
54439
|
});
|
|
54100
54440
|
return next;
|
|
54101
54441
|
}
|
|
@@ -54657,9 +54997,14 @@ class PushSupervisor {
|
|
|
54657
54997
|
},
|
|
54658
54998
|
onError: (error) => {
|
|
54659
54999
|
console.error(`[push] tmux error on device ${entry.deviceId}:`, error);
|
|
55000
|
+
connectionAlertNotifier.notify({
|
|
55001
|
+
device,
|
|
55002
|
+
error,
|
|
55003
|
+
source: "runtime"
|
|
55004
|
+
});
|
|
54660
55005
|
},
|
|
54661
55006
|
onClose: () => {
|
|
54662
|
-
this.handleClose(entry.deviceId, generation, runtime);
|
|
55007
|
+
this.handleClose(entry.deviceId, generation, runtime, device);
|
|
54663
55008
|
}
|
|
54664
55009
|
});
|
|
54665
55010
|
entry.runtime = runtime;
|
|
@@ -54683,6 +55028,11 @@ class PushSupervisor {
|
|
|
54683
55028
|
return;
|
|
54684
55029
|
}
|
|
54685
55030
|
console.error(`[push] failed connecting device ${entry.deviceId}:`, err);
|
|
55031
|
+
await connectionAlertNotifier.notify({
|
|
55032
|
+
device,
|
|
55033
|
+
error: err,
|
|
55034
|
+
source: "connect"
|
|
55035
|
+
});
|
|
54686
55036
|
detachRuntime();
|
|
54687
55037
|
entry.detachRuntime = null;
|
|
54688
55038
|
entry.runtime = null;
|
|
@@ -54720,11 +55070,16 @@ class PushSupervisor {
|
|
|
54720
55070
|
this.connectEntry(entry);
|
|
54721
55071
|
}, delayMs);
|
|
54722
55072
|
}
|
|
54723
|
-
async handleClose(deviceId, generation, runtime) {
|
|
55073
|
+
async handleClose(deviceId, generation, runtime, device) {
|
|
54724
55074
|
const entry = this.entries.get(deviceId);
|
|
54725
55075
|
if (!entry || entry.generation !== generation || entry.runtime !== runtime) {
|
|
54726
55076
|
return;
|
|
54727
55077
|
}
|
|
55078
|
+
await connectionAlertNotifier.notify({
|
|
55079
|
+
device,
|
|
55080
|
+
error: new Error("ssh_connection_closed"),
|
|
55081
|
+
source: "close"
|
|
55082
|
+
});
|
|
54728
55083
|
entry.detachRuntime?.();
|
|
54729
55084
|
entry.detachRuntime = null;
|
|
54730
55085
|
entry.runtime = null;
|
|
@@ -54785,82 +55140,6 @@ class PushSupervisor {
|
|
|
54785
55140
|
}
|
|
54786
55141
|
var pushSupervisor = new PushSupervisor;
|
|
54787
55142
|
|
|
54788
|
-
// ../../apps/gateway/src/ws/error-classify.ts
|
|
54789
|
-
function classifySshError(error) {
|
|
54790
|
-
const msg = error.message.toLowerCase();
|
|
54791
|
-
if (msg.includes("ssh_config_ref_not_supported")) {
|
|
54792
|
-
return {
|
|
54793
|
-
type: "ssh_config_ref_not_supported",
|
|
54794
|
-
messageKey: "sshError.configRefNotSupported"
|
|
54795
|
-
};
|
|
54796
|
-
}
|
|
54797
|
-
if (msg.includes("ssh_auth_sock") || msg.includes("auth_sock")) {
|
|
54798
|
-
return {
|
|
54799
|
-
type: "agent_unavailable",
|
|
54800
|
-
messageKey: "sshError.agentUnavailable"
|
|
54801
|
-
};
|
|
54802
|
-
}
|
|
54803
|
-
if (msg.includes("agent") && (msg.includes("no identities") || msg.includes("failure"))) {
|
|
54804
|
-
return {
|
|
54805
|
-
type: "agent_no_identity",
|
|
54806
|
-
messageKey: "sshError.agentNoIdentities"
|
|
54807
|
-
};
|
|
54808
|
-
}
|
|
54809
|
-
if (msg.includes("permission denied")) {
|
|
54810
|
-
return {
|
|
54811
|
-
type: "auth_failed",
|
|
54812
|
-
messageKey: "sshError.authFailed"
|
|
54813
|
-
};
|
|
54814
|
-
}
|
|
54815
|
-
if (msg.includes("all configured authentication methods failed")) {
|
|
54816
|
-
return {
|
|
54817
|
-
type: "auth_failed",
|
|
54818
|
-
messageKey: "sshError.authFailedGeneric"
|
|
54819
|
-
};
|
|
54820
|
-
}
|
|
54821
|
-
if (msg.includes("enetunreach") || msg.includes("ehostunreach")) {
|
|
54822
|
-
return {
|
|
54823
|
-
type: "network_unreachable",
|
|
54824
|
-
messageKey: "sshError.networkUnreachable"
|
|
54825
|
-
};
|
|
54826
|
-
}
|
|
54827
|
-
if (msg.includes("connect refused") || msg.includes("connection refused") || msg.includes("econnrefused")) {
|
|
54828
|
-
return {
|
|
54829
|
-
type: "connection_refused",
|
|
54830
|
-
messageKey: "sshError.connectionRefused"
|
|
54831
|
-
};
|
|
54832
|
-
}
|
|
54833
|
-
if (msg.includes("timeout") || msg.includes("etimedout")) {
|
|
54834
|
-
return {
|
|
54835
|
-
type: "timeout",
|
|
54836
|
-
messageKey: "sshError.connectionTimeout"
|
|
54837
|
-
};
|
|
54838
|
-
}
|
|
54839
|
-
if (msg.includes("host not found") || msg.includes("getaddrinfo") || msg.includes("enotfound")) {
|
|
54840
|
-
return {
|
|
54841
|
-
type: "host_not_found",
|
|
54842
|
-
messageKey: "sshError.hostNotFound"
|
|
54843
|
-
};
|
|
54844
|
-
}
|
|
54845
|
-
if (msg.includes("handshake failed") || msg.includes("unable to verify")) {
|
|
54846
|
-
return {
|
|
54847
|
-
type: "handshake_failed",
|
|
54848
|
-
messageKey: "sshError.handshakeFailed"
|
|
54849
|
-
};
|
|
54850
|
-
}
|
|
54851
|
-
if (msg.includes("remote tmux unavailable") || msg.includes("tmux_not_found") || msg.includes("tmux: command not found") || msg.includes("tmux control mode not ready") || msg.includes("tmux exited") || msg.includes("tmux_exec_failed")) {
|
|
54852
|
-
return {
|
|
54853
|
-
type: "tmux_unavailable",
|
|
54854
|
-
messageKey: "sshError.tmuxUnavailable"
|
|
54855
|
-
};
|
|
54856
|
-
}
|
|
54857
|
-
return {
|
|
54858
|
-
type: "unknown",
|
|
54859
|
-
messageKey: "sshError.unknown",
|
|
54860
|
-
messageParams: { message: error.message }
|
|
54861
|
-
};
|
|
54862
|
-
}
|
|
54863
|
-
|
|
54864
55143
|
// ../../apps/gateway/src/api/test-connection.ts
|
|
54865
55144
|
function inferFailurePhase(errorType) {
|
|
54866
55145
|
if (errorType === "tmux_unavailable") {
|
|
@@ -55094,8 +55373,18 @@ function handleApiRequest(req, _server) {
|
|
|
55094
55373
|
}
|
|
55095
55374
|
return json2({ error: t2("apiError.notFound") }, 404);
|
|
55096
55375
|
}
|
|
55376
|
+
function enrichDeviceWithRuntime(device) {
|
|
55377
|
+
const status = getDeviceRuntimeStatus(device.id);
|
|
55378
|
+
return {
|
|
55379
|
+
...device,
|
|
55380
|
+
lastSeenAt: status.lastSeenAt,
|
|
55381
|
+
lastError: status.lastError,
|
|
55382
|
+
lastErrorType: status.lastErrorType,
|
|
55383
|
+
tmuxAvailable: status.tmuxAvailable
|
|
55384
|
+
};
|
|
55385
|
+
}
|
|
55097
55386
|
async function handleGetDevices() {
|
|
55098
|
-
const devices2 = getAllDevices();
|
|
55387
|
+
const devices2 = getAllDevices().map(enrichDeviceWithRuntime);
|
|
55099
55388
|
return json2({ devices: devices2 });
|
|
55100
55389
|
}
|
|
55101
55390
|
async function handleGetDevice(id) {
|
|
@@ -55103,7 +55392,7 @@ async function handleGetDevice(id) {
|
|
|
55103
55392
|
if (!device) {
|
|
55104
55393
|
return json2({ error: t2("apiError.deviceNotFound") }, 404);
|
|
55105
55394
|
}
|
|
55106
|
-
return json2({ device });
|
|
55395
|
+
return json2({ device: enrichDeviceWithRuntime(device) });
|
|
55107
55396
|
}
|
|
55108
55397
|
async function handleCreateDevice(req) {
|
|
55109
55398
|
const body = await req.json();
|
|
@@ -56675,6 +56964,15 @@ class WebSocketServer {
|
|
|
56675
56964
|
this.sendEnvelope(client, exports_ws_borsh.KIND_DEVICE_EVENT, payloadBytes);
|
|
56676
56965
|
}
|
|
56677
56966
|
}
|
|
56967
|
+
broadcastDeviceError(deviceId, payload) {
|
|
56968
|
+
const entry = this.connections.get(deviceId);
|
|
56969
|
+
if (!entry)
|
|
56970
|
+
return;
|
|
56971
|
+
const payloadBytes = exports_ws_borsh.encodeDeviceEventPayload(payload);
|
|
56972
|
+
for (const client of entry.clients) {
|
|
56973
|
+
this.sendEnvelope(client, exports_ws_borsh.KIND_DEVICE_EVENT, payloadBytes);
|
|
56974
|
+
}
|
|
56975
|
+
}
|
|
56678
56976
|
broadcastDeviceEvent(entry, payload) {
|
|
56679
56977
|
const payloadBytes = exports_ws_borsh.encodeDeviceEventPayload(payload);
|
|
56680
56978
|
for (const client of entry.clients) {
|
|
@@ -56767,6 +57065,9 @@ async function createGatewayRuntime(options = {}) {
|
|
|
56767
57065
|
runtimeController.reset();
|
|
56768
57066
|
primeLocalShellPath();
|
|
56769
57067
|
const wsServer = new WebSocketServer;
|
|
57068
|
+
connectionAlertNotifier.setBroadcaster((deviceId, payload) => {
|
|
57069
|
+
wsServer.broadcastDeviceError(deviceId, payload);
|
|
57070
|
+
});
|
|
56770
57071
|
await telegramService.refresh();
|
|
56771
57072
|
await pushSupervisor.start();
|
|
56772
57073
|
try {
|
|
@@ -56809,6 +57110,7 @@ async function createGatewayRuntime(options = {}) {
|
|
|
56809
57110
|
runtimeController.onRestart(listener);
|
|
56810
57111
|
},
|
|
56811
57112
|
async stop() {
|
|
57113
|
+
connectionAlertNotifier.setBroadcaster(null);
|
|
56812
57114
|
wsServer.closeAll();
|
|
56813
57115
|
await pushSupervisor.stopAll();
|
|
56814
57116
|
await tmuxRuntimeRegistry.shutdownAll();
|
|
@@ -57115,6 +57417,12 @@ async function main() {
|
|
|
57115
57417
|
});
|
|
57116
57418
|
console.log(`[tmex] ${t3("runtime.started", { url: `http://${host}:${port}` })}`);
|
|
57117
57419
|
}
|
|
57420
|
+
process.on("unhandledRejection", (reason) => {
|
|
57421
|
+
console.error("[tmex][unhandledRejection]", reason);
|
|
57422
|
+
});
|
|
57423
|
+
process.on("uncaughtException", (error) => {
|
|
57424
|
+
console.error("[tmex][uncaughtException]", error);
|
|
57425
|
+
});
|
|
57118
57426
|
try {
|
|
57119
57427
|
await main();
|
|
57120
57428
|
} catch (error) {
|