tmex-cli 0.4.1 → 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 +414 -88
- package/package.json +1 -1
- package/resources/fe-dist/assets/DevicePage-B9rZioAr.js +26 -0
- package/resources/fe-dist/assets/{DevicePage-n4JoyDed.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-hS99lHcp.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-DGBwxGiK.js.map → select-D70hG6p7.js.map} +1 -1
- package/resources/fe-dist/assets/switch-DsyIGzyC.js +12 -0
- package/resources/fe-dist/assets/{switch-CWUBjs7N.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-DwJ_SDCu.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-n4JoyDed.js +0 -26
- package/resources/fe-dist/assets/DevicesPage-BwLKaiUR.js +0 -17
- package/resources/fe-dist/assets/DevicesPage-BwLKaiUR.js.map +0 -1
- package/resources/fe-dist/assets/SettingsPage-hS99lHcp.js +0 -17
- package/resources/fe-dist/assets/index-CJaX5rlK.css +0 -1
- package/resources/fe-dist/assets/index-CJyFlAt8.js +0 -449
- package/resources/fe-dist/assets/index-CJyFlAt8.js.map +0 -1
- package/resources/fe-dist/assets/select-DGBwxGiK.js +0 -17
- package/resources/fe-dist/assets/switch-CWUBjs7N.js +0 -12
- package/resources/fe-dist/assets/useValueChanged-DwJ_SDCu.js +0 -7
package/dist/runtime/server.js
CHANGED
|
@@ -20363,8 +20363,13 @@ var I18N_RESOURCES = {
|
|
|
20363
20363
|
title: "Device Management",
|
|
20364
20364
|
devices: "Devices",
|
|
20365
20365
|
addDevice: "Add Device",
|
|
20366
|
+
addDeviceDescription: "Fill in device details and choose a connection method",
|
|
20366
20367
|
addFirstDevice: "Add First Device",
|
|
20367
20368
|
editDevice: "Edit Device",
|
|
20369
|
+
editDeviceDescription: "Update device configuration",
|
|
20370
|
+
sectionBasic: "Basic Info",
|
|
20371
|
+
sectionConnection: "Connection",
|
|
20372
|
+
sectionAuth: "Authentication",
|
|
20368
20373
|
noDevices: "No Devices",
|
|
20369
20374
|
noDevicesDescription: "Add a local or SSH device to get started",
|
|
20370
20375
|
name: "Device Name",
|
|
@@ -20397,6 +20402,7 @@ var I18N_RESOURCES = {
|
|
|
20397
20402
|
disconnected: "Disconnected",
|
|
20398
20403
|
connecting: "Connecting...",
|
|
20399
20404
|
deleteConfirm: "Delete this device?",
|
|
20405
|
+
deleteDescription: 'Device "{{name}}" will be permanently removed. This action cannot be undone.',
|
|
20400
20406
|
deleteSuccess: "Device deleted",
|
|
20401
20407
|
createSuccess: "Device created",
|
|
20402
20408
|
updateSuccess: "Device updated",
|
|
@@ -20518,6 +20524,8 @@ var I18N_RESOURCES = {
|
|
|
20518
20524
|
chatId: "Chat ID",
|
|
20519
20525
|
applyTime: "Application Time",
|
|
20520
20526
|
gatewayOnline: "\uD83D\uDFE2 Gateway online @ {{siteName}}",
|
|
20527
|
+
deviceConnectionError: `\uD83D\uDD34 {{siteName}}: Connection error on device "{{deviceName}}" ({{host}}) [{{category}}]
|
|
20528
|
+
{{error}}`,
|
|
20521
20529
|
authSuccess: "\u2705 Authorized. You will now receive notifications.",
|
|
20522
20530
|
authPending: "\u23F3 Authorization request received. Please approve in tmex settings.",
|
|
20523
20531
|
authFailed: "\u274C Authorization request failed. Please contact administrator.",
|
|
@@ -20558,11 +20566,30 @@ Time: {{time}}`,
|
|
|
20558
20566
|
hostNotFound: "Host not found: Unable to resolve hostname. Please check DNS or hostname configuration.",
|
|
20559
20567
|
handshakeFailed: "Handshake failed: Unable to establish secure connection. Possibly incompatible key exchange algorithm.",
|
|
20560
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",
|
|
20561
20570
|
unknown: "Connection failed: {{message}}",
|
|
20562
20571
|
reconnecting: "Connection interrupted, reconnecting in {{delay}} seconds ({{attempt}}/{{maxRetries}})",
|
|
20563
20572
|
reconnectFailed: "Auto-reconnect failed, please retry manually",
|
|
20564
20573
|
reconnected: "Device reconnected automatically"
|
|
20565
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
|
+
},
|
|
20566
20593
|
websocket: {
|
|
20567
20594
|
error: "WebSocket connection error",
|
|
20568
20595
|
checkGateway: "Please check Gateway status",
|
|
@@ -20695,8 +20722,13 @@ Time: {{time}}`,
|
|
|
20695
20722
|
title: "\u8BBE\u5907\u7BA1\u7406",
|
|
20696
20723
|
devices: "\u8BBE\u5907",
|
|
20697
20724
|
addDevice: "\u6DFB\u52A0\u8BBE\u5907",
|
|
20725
|
+
addDeviceDescription: "\u586B\u5199\u8BBE\u5907\u4FE1\u606F\u5E76\u9009\u62E9\u8FDE\u63A5\u65B9\u5F0F",
|
|
20698
20726
|
addFirstDevice: "\u6DFB\u52A0\u7B2C\u4E00\u4E2A\u8BBE\u5907",
|
|
20699
20727
|
editDevice: "\u4FEE\u6539\u8BBE\u5907",
|
|
20728
|
+
editDeviceDescription: "\u66F4\u65B0\u8BBE\u5907\u914D\u7F6E",
|
|
20729
|
+
sectionBasic: "\u57FA\u672C\u4FE1\u606F",
|
|
20730
|
+
sectionConnection: "\u8FDE\u63A5\u4FE1\u606F",
|
|
20731
|
+
sectionAuth: "\u8BA4\u8BC1\u4FE1\u606F",
|
|
20700
20732
|
noDevices: "\u6682\u65E0\u8BBE\u5907",
|
|
20701
20733
|
noDevicesDescription: "\u6DFB\u52A0\u672C\u5730\u6216 SSH \u8BBE\u5907\u5F00\u59CB\u4F7F\u7528",
|
|
20702
20734
|
name: "\u8BBE\u5907\u540D\u79F0",
|
|
@@ -20729,6 +20761,7 @@ Time: {{time}}`,
|
|
|
20729
20761
|
disconnected: "\u5DF2\u65AD\u5F00",
|
|
20730
20762
|
connecting: "\u8FDE\u63A5\u4E2D...",
|
|
20731
20763
|
deleteConfirm: "\u5220\u9664\u6B64\u8BBE\u5907\uFF1F",
|
|
20764
|
+
deleteDescription: '\u8BBE\u5907 "{{name}}" \u5C06\u88AB\u6C38\u4E45\u79FB\u9664\uFF0C\u6B64\u64CD\u4F5C\u65E0\u6CD5\u64A4\u9500\u3002',
|
|
20732
20765
|
deleteSuccess: "\u8BBE\u5907\u5DF2\u5220\u9664",
|
|
20733
20766
|
createSuccess: "\u8BBE\u5907\u5DF2\u521B\u5EFA",
|
|
20734
20767
|
updateSuccess: "\u8BBE\u5907\u5DF2\u66F4\u65B0",
|
|
@@ -20850,6 +20883,8 @@ Time: {{time}}`,
|
|
|
20850
20883
|
chatId: "chatId",
|
|
20851
20884
|
applyTime: "\u7533\u8BF7\u65F6\u95F4",
|
|
20852
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}}`,
|
|
20853
20888
|
authSuccess: "\u2705 \u5DF2\u6388\u6743\uFF0C\u53EF\u63A5\u6536\u901A\u77E5\u3002",
|
|
20854
20889
|
authPending: "\u23F3 \u5DF2\u6536\u5230\u6388\u6743\u7533\u8BF7\uFF0C\u8BF7\u5728 tmex \u8BBE\u7F6E\u9875\u5BA1\u6279\u3002",
|
|
20855
20890
|
authFailed: "\u274C \u6388\u6743\u7533\u8BF7\u5931\u8D25\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u3002",
|
|
@@ -20890,11 +20925,30 @@ Bot\uFF1A{{botName}}
|
|
|
20890
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",
|
|
20891
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",
|
|
20892
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",
|
|
20893
20929
|
unknown: "\u8FDE\u63A5\u5931\u8D25\uFF1A{{message}}",
|
|
20894
20930
|
reconnecting: "\u8FDE\u63A5\u4E2D\u65AD\uFF0C{{delay}} \u79D2\u540E\u81EA\u52A8\u91CD\u8FDE\uFF08{{attempt}}/{{maxRetries}}\uFF09",
|
|
20895
20931
|
reconnectFailed: "\u81EA\u52A8\u91CD\u8FDE\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u91CD\u8BD5",
|
|
20896
20932
|
reconnected: "\u8BBE\u5907\u5DF2\u81EA\u52A8\u91CD\u8FDE"
|
|
20897
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
|
+
},
|
|
20898
20952
|
websocket: {
|
|
20899
20953
|
error: "WebSocket \u8FDE\u63A5\u9519\u8BEF",
|
|
20900
20954
|
checkGateway: "\u8BF7\u68C0\u67E5 Gateway \u72B6\u6001",
|
|
@@ -21027,8 +21081,13 @@ Bot\uFF1A{{botName}}
|
|
|
21027
21081
|
title: "\u30C7\u30D0\u30A4\u30B9\u7BA1\u7406",
|
|
21028
21082
|
devices: "\u30C7\u30D0\u30A4\u30B9",
|
|
21029
21083
|
addDevice: "\u30C7\u30D0\u30A4\u30B9\u3092\u8FFD\u52A0",
|
|
21084
|
+
addDeviceDescription: "\u30C7\u30D0\u30A4\u30B9\u60C5\u5831\u3092\u5165\u529B\u3057\u3001\u63A5\u7D9A\u65B9\u6CD5\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044",
|
|
21030
21085
|
addFirstDevice: "\u6700\u521D\u306E\u30C7\u30D0\u30A4\u30B9\u3092\u8FFD\u52A0",
|
|
21031
21086
|
editDevice: "\u30C7\u30D0\u30A4\u30B9\u3092\u7DE8\u96C6",
|
|
21087
|
+
editDeviceDescription: "\u30C7\u30D0\u30A4\u30B9\u8A2D\u5B9A\u3092\u66F4\u65B0",
|
|
21088
|
+
sectionBasic: "\u57FA\u672C\u60C5\u5831",
|
|
21089
|
+
sectionConnection: "\u63A5\u7D9A\u60C5\u5831",
|
|
21090
|
+
sectionAuth: "\u8A8D\u8A3C\u60C5\u5831",
|
|
21032
21091
|
noDevices: "\u30C7\u30D0\u30A4\u30B9\u304C\u3042\u308A\u307E\u305B\u3093",
|
|
21033
21092
|
noDevicesDescription: "\u30ED\u30FC\u30AB\u30EB\u307E\u305F\u306F SSH \u30C7\u30D0\u30A4\u30B9\u3092\u8FFD\u52A0\u3057\u3066\u958B\u59CB",
|
|
21034
21093
|
name: "\u30C7\u30D0\u30A4\u30B9\u540D",
|
|
@@ -21061,6 +21120,7 @@ Bot\uFF1A{{botName}}
|
|
|
21061
21120
|
disconnected: "\u5207\u65AD\u6E08\u307F",
|
|
21062
21121
|
connecting: "\u63A5\u7D9A\u4E2D...",
|
|
21063
21122
|
deleteConfirm: "\u3053\u306E\u30C7\u30D0\u30A4\u30B9\u3092\u524A\u9664\u3057\u307E\u3059\u304B\uFF1F",
|
|
21123
|
+
deleteDescription: "\u30C7\u30D0\u30A4\u30B9\u300C{{name}}\u300D\u306F\u5B8C\u5168\u306B\u524A\u9664\u3055\u308C\u307E\u3059\u3002\u3053\u306E\u64CD\u4F5C\u306F\u53D6\u308A\u6D88\u305B\u307E\u305B\u3093\u3002",
|
|
21064
21124
|
deleteSuccess: "\u30C7\u30D0\u30A4\u30B9\u3092\u524A\u9664\u3057\u307E\u3057\u305F",
|
|
21065
21125
|
createSuccess: "\u30C7\u30D0\u30A4\u30B9\u3092\u4F5C\u6210\u3057\u307E\u3057\u305F",
|
|
21066
21126
|
updateSuccess: "\u30C7\u30D0\u30A4\u30B9\u3092\u66F4\u65B0\u3057\u307E\u3057\u305F",
|
|
@@ -21182,6 +21242,8 @@ Bot\uFF1A{{botName}}
|
|
|
21182
21242
|
chatId: "Chat ID",
|
|
21183
21243
|
applyTime: "\u7533\u8ACB\u6642\u9593",
|
|
21184
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}}`,
|
|
21185
21247
|
authSuccess: "\u2705 \u627F\u8A8D\u3055\u308C\u307E\u3057\u305F\u3002\u901A\u77E5\u3092\u53D7\u4FE1\u3067\u304D\u307E\u3059\u3002",
|
|
21186
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",
|
|
21187
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",
|
|
@@ -21222,11 +21284,30 @@ Bot\uFF1A{{botName}}
|
|
|
21222
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",
|
|
21223
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",
|
|
21224
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",
|
|
21225
21288
|
unknown: "\u63A5\u7D9A\u306B\u5931\u6557\u3057\u307E\u3057\u305F\uFF1A{{message}}",
|
|
21226
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",
|
|
21227
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",
|
|
21228
21291
|
reconnected: "\u30C7\u30D0\u30A4\u30B9\u304C\u81EA\u52D5\u7684\u306B\u518D\u63A5\u7D9A\u3055\u308C\u307E\u3057\u305F"
|
|
21229
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
|
+
},
|
|
21230
21311
|
websocket: {
|
|
21231
21312
|
error: "WebSocket \u63A5\u7D9A\u30A8\u30E9\u30FC",
|
|
21232
21313
|
checkGateway: "Gateway \u72B6\u614B\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044",
|
|
@@ -28866,7 +28947,8 @@ var deviceRuntimeStatus = sqliteTable("device_runtime_status", {
|
|
|
28866
28947
|
deviceId: text("device_id").primaryKey().references(() => devices.id, { onDelete: "cascade" }),
|
|
28867
28948
|
lastSeenAt: text("last_seen_at"),
|
|
28868
28949
|
tmuxAvailable: integer("tmux_available", { mode: "boolean" }).notNull().default(false),
|
|
28869
|
-
lastError: text("last_error")
|
|
28950
|
+
lastError: text("last_error"),
|
|
28951
|
+
lastErrorType: text("last_error_type")
|
|
28870
28952
|
});
|
|
28871
28953
|
var webhookEndpoints = sqliteTable("webhook_endpoints", {
|
|
28872
28954
|
id: text("id").primaryKey(),
|
|
@@ -29039,7 +29121,8 @@ function createDevice(device) {
|
|
|
29039
29121
|
deviceId: device.id,
|
|
29040
29122
|
lastSeenAt: null,
|
|
29041
29123
|
tmuxAvailable: false,
|
|
29042
|
-
lastError: null
|
|
29124
|
+
lastError: null,
|
|
29125
|
+
lastErrorType: null
|
|
29043
29126
|
}).onConflictDoNothing({ target: deviceRuntimeStatus.deviceId }).run();
|
|
29044
29127
|
});
|
|
29045
29128
|
}
|
|
@@ -29096,6 +29179,26 @@ function deleteDevice(id) {
|
|
|
29096
29179
|
const orm = getDb();
|
|
29097
29180
|
orm.delete(devices).where(eq(devices.id, id)).run();
|
|
29098
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
|
+
}
|
|
29099
29202
|
function updateDeviceRuntimeStatus(deviceId, status) {
|
|
29100
29203
|
const orm = getDb();
|
|
29101
29204
|
const setValues = {};
|
|
@@ -29108,6 +29211,9 @@ function updateDeviceRuntimeStatus(deviceId, status) {
|
|
|
29108
29211
|
if (status.lastError !== undefined) {
|
|
29109
29212
|
setValues.lastError = status.lastError;
|
|
29110
29213
|
}
|
|
29214
|
+
if (status.lastErrorType !== undefined) {
|
|
29215
|
+
setValues.lastErrorType = status.lastErrorType;
|
|
29216
|
+
}
|
|
29111
29217
|
if (Object.keys(setValues).length === 0) {
|
|
29112
29218
|
return;
|
|
29113
29219
|
}
|
|
@@ -52015,6 +52121,241 @@ var eventNotifier = new EventNotifier;
|
|
|
52015
52121
|
import { mkdirSync, rmSync } from "fs";
|
|
52016
52122
|
import { homedir } from "os";
|
|
52017
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
|
+
|
|
52018
52359
|
// ../../apps/gateway/src/tmux/local-shell-path.ts
|
|
52019
52360
|
import { existsSync } from "fs";
|
|
52020
52361
|
import { delimiter, join as join2 } from "path";
|
|
@@ -53040,13 +53381,26 @@ class LocalExternalTmuxConnection {
|
|
|
53040
53381
|
this.recoverFromTargetMissingError(message);
|
|
53041
53382
|
return result;
|
|
53042
53383
|
}
|
|
53043
|
-
|
|
53044
|
-
lastSeenAt: new Date().toISOString(),
|
|
53045
|
-
tmuxAvailable: false,
|
|
53046
|
-
lastError: message
|
|
53047
|
-
});
|
|
53384
|
+
this.notifyRuntimeError(message);
|
|
53048
53385
|
throw new Error(message);
|
|
53049
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
|
+
}
|
|
53050
53404
|
async runTmuxAllowFailure(argv) {
|
|
53051
53405
|
return this.deps.run(["tmux", ...argv]);
|
|
53052
53406
|
}
|
|
@@ -54035,7 +54389,9 @@ class SshExternalTmuxConnection {
|
|
|
54035
54389
|
const next = this.pipeTransition.catch(() => {
|
|
54036
54390
|
return;
|
|
54037
54391
|
}).then(task);
|
|
54038
|
-
this.pipeTransition = next
|
|
54392
|
+
this.pipeTransition = next.catch(() => {
|
|
54393
|
+
return;
|
|
54394
|
+
});
|
|
54039
54395
|
return next;
|
|
54040
54396
|
}
|
|
54041
54397
|
async runTmux(argv, allowTargetMissing = false, timeoutMs = 1e4) {
|
|
@@ -54078,6 +54434,8 @@ class SshExternalTmuxConnection {
|
|
|
54078
54434
|
}).then(() => this.executeShellCommand(command, timeoutMs));
|
|
54079
54435
|
this.commandQueue = next.then(() => {
|
|
54080
54436
|
return;
|
|
54437
|
+
}, () => {
|
|
54438
|
+
return;
|
|
54081
54439
|
});
|
|
54082
54440
|
return next;
|
|
54083
54441
|
}
|
|
@@ -54639,9 +54997,14 @@ class PushSupervisor {
|
|
|
54639
54997
|
},
|
|
54640
54998
|
onError: (error) => {
|
|
54641
54999
|
console.error(`[push] tmux error on device ${entry.deviceId}:`, error);
|
|
55000
|
+
connectionAlertNotifier.notify({
|
|
55001
|
+
device,
|
|
55002
|
+
error,
|
|
55003
|
+
source: "runtime"
|
|
55004
|
+
});
|
|
54642
55005
|
},
|
|
54643
55006
|
onClose: () => {
|
|
54644
|
-
this.handleClose(entry.deviceId, generation, runtime);
|
|
55007
|
+
this.handleClose(entry.deviceId, generation, runtime, device);
|
|
54645
55008
|
}
|
|
54646
55009
|
});
|
|
54647
55010
|
entry.runtime = runtime;
|
|
@@ -54665,6 +55028,11 @@ class PushSupervisor {
|
|
|
54665
55028
|
return;
|
|
54666
55029
|
}
|
|
54667
55030
|
console.error(`[push] failed connecting device ${entry.deviceId}:`, err);
|
|
55031
|
+
await connectionAlertNotifier.notify({
|
|
55032
|
+
device,
|
|
55033
|
+
error: err,
|
|
55034
|
+
source: "connect"
|
|
55035
|
+
});
|
|
54668
55036
|
detachRuntime();
|
|
54669
55037
|
entry.detachRuntime = null;
|
|
54670
55038
|
entry.runtime = null;
|
|
@@ -54702,11 +55070,16 @@ class PushSupervisor {
|
|
|
54702
55070
|
this.connectEntry(entry);
|
|
54703
55071
|
}, delayMs);
|
|
54704
55072
|
}
|
|
54705
|
-
async handleClose(deviceId, generation, runtime) {
|
|
55073
|
+
async handleClose(deviceId, generation, runtime, device) {
|
|
54706
55074
|
const entry = this.entries.get(deviceId);
|
|
54707
55075
|
if (!entry || entry.generation !== generation || entry.runtime !== runtime) {
|
|
54708
55076
|
return;
|
|
54709
55077
|
}
|
|
55078
|
+
await connectionAlertNotifier.notify({
|
|
55079
|
+
device,
|
|
55080
|
+
error: new Error("ssh_connection_closed"),
|
|
55081
|
+
source: "close"
|
|
55082
|
+
});
|
|
54710
55083
|
entry.detachRuntime?.();
|
|
54711
55084
|
entry.detachRuntime = null;
|
|
54712
55085
|
entry.runtime = null;
|
|
@@ -54767,82 +55140,6 @@ class PushSupervisor {
|
|
|
54767
55140
|
}
|
|
54768
55141
|
var pushSupervisor = new PushSupervisor;
|
|
54769
55142
|
|
|
54770
|
-
// ../../apps/gateway/src/ws/error-classify.ts
|
|
54771
|
-
function classifySshError(error) {
|
|
54772
|
-
const msg = error.message.toLowerCase();
|
|
54773
|
-
if (msg.includes("ssh_config_ref_not_supported")) {
|
|
54774
|
-
return {
|
|
54775
|
-
type: "ssh_config_ref_not_supported",
|
|
54776
|
-
messageKey: "sshError.configRefNotSupported"
|
|
54777
|
-
};
|
|
54778
|
-
}
|
|
54779
|
-
if (msg.includes("ssh_auth_sock") || msg.includes("auth_sock")) {
|
|
54780
|
-
return {
|
|
54781
|
-
type: "agent_unavailable",
|
|
54782
|
-
messageKey: "sshError.agentUnavailable"
|
|
54783
|
-
};
|
|
54784
|
-
}
|
|
54785
|
-
if (msg.includes("agent") && (msg.includes("no identities") || msg.includes("failure"))) {
|
|
54786
|
-
return {
|
|
54787
|
-
type: "agent_no_identity",
|
|
54788
|
-
messageKey: "sshError.agentNoIdentities"
|
|
54789
|
-
};
|
|
54790
|
-
}
|
|
54791
|
-
if (msg.includes("permission denied")) {
|
|
54792
|
-
return {
|
|
54793
|
-
type: "auth_failed",
|
|
54794
|
-
messageKey: "sshError.authFailed"
|
|
54795
|
-
};
|
|
54796
|
-
}
|
|
54797
|
-
if (msg.includes("all configured authentication methods failed")) {
|
|
54798
|
-
return {
|
|
54799
|
-
type: "auth_failed",
|
|
54800
|
-
messageKey: "sshError.authFailedGeneric"
|
|
54801
|
-
};
|
|
54802
|
-
}
|
|
54803
|
-
if (msg.includes("enetunreach") || msg.includes("ehostunreach")) {
|
|
54804
|
-
return {
|
|
54805
|
-
type: "network_unreachable",
|
|
54806
|
-
messageKey: "sshError.networkUnreachable"
|
|
54807
|
-
};
|
|
54808
|
-
}
|
|
54809
|
-
if (msg.includes("connect refused") || msg.includes("connection refused") || msg.includes("econnrefused")) {
|
|
54810
|
-
return {
|
|
54811
|
-
type: "connection_refused",
|
|
54812
|
-
messageKey: "sshError.connectionRefused"
|
|
54813
|
-
};
|
|
54814
|
-
}
|
|
54815
|
-
if (msg.includes("timeout") || msg.includes("etimedout")) {
|
|
54816
|
-
return {
|
|
54817
|
-
type: "timeout",
|
|
54818
|
-
messageKey: "sshError.connectionTimeout"
|
|
54819
|
-
};
|
|
54820
|
-
}
|
|
54821
|
-
if (msg.includes("host not found") || msg.includes("getaddrinfo") || msg.includes("enotfound")) {
|
|
54822
|
-
return {
|
|
54823
|
-
type: "host_not_found",
|
|
54824
|
-
messageKey: "sshError.hostNotFound"
|
|
54825
|
-
};
|
|
54826
|
-
}
|
|
54827
|
-
if (msg.includes("handshake failed") || msg.includes("unable to verify")) {
|
|
54828
|
-
return {
|
|
54829
|
-
type: "handshake_failed",
|
|
54830
|
-
messageKey: "sshError.handshakeFailed"
|
|
54831
|
-
};
|
|
54832
|
-
}
|
|
54833
|
-
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")) {
|
|
54834
|
-
return {
|
|
54835
|
-
type: "tmux_unavailable",
|
|
54836
|
-
messageKey: "sshError.tmuxUnavailable"
|
|
54837
|
-
};
|
|
54838
|
-
}
|
|
54839
|
-
return {
|
|
54840
|
-
type: "unknown",
|
|
54841
|
-
messageKey: "sshError.unknown",
|
|
54842
|
-
messageParams: { message: error.message }
|
|
54843
|
-
};
|
|
54844
|
-
}
|
|
54845
|
-
|
|
54846
55143
|
// ../../apps/gateway/src/api/test-connection.ts
|
|
54847
55144
|
function inferFailurePhase(errorType) {
|
|
54848
55145
|
if (errorType === "tmux_unavailable") {
|
|
@@ -55076,8 +55373,18 @@ function handleApiRequest(req, _server) {
|
|
|
55076
55373
|
}
|
|
55077
55374
|
return json2({ error: t2("apiError.notFound") }, 404);
|
|
55078
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
|
+
}
|
|
55079
55386
|
async function handleGetDevices() {
|
|
55080
|
-
const devices2 = getAllDevices();
|
|
55387
|
+
const devices2 = getAllDevices().map(enrichDeviceWithRuntime);
|
|
55081
55388
|
return json2({ devices: devices2 });
|
|
55082
55389
|
}
|
|
55083
55390
|
async function handleGetDevice(id) {
|
|
@@ -55085,7 +55392,7 @@ async function handleGetDevice(id) {
|
|
|
55085
55392
|
if (!device) {
|
|
55086
55393
|
return json2({ error: t2("apiError.deviceNotFound") }, 404);
|
|
55087
55394
|
}
|
|
55088
|
-
return json2({ device });
|
|
55395
|
+
return json2({ device: enrichDeviceWithRuntime(device) });
|
|
55089
55396
|
}
|
|
55090
55397
|
async function handleCreateDevice(req) {
|
|
55091
55398
|
const body = await req.json();
|
|
@@ -56657,6 +56964,15 @@ class WebSocketServer {
|
|
|
56657
56964
|
this.sendEnvelope(client, exports_ws_borsh.KIND_DEVICE_EVENT, payloadBytes);
|
|
56658
56965
|
}
|
|
56659
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
|
+
}
|
|
56660
56976
|
broadcastDeviceEvent(entry, payload) {
|
|
56661
56977
|
const payloadBytes = exports_ws_borsh.encodeDeviceEventPayload(payload);
|
|
56662
56978
|
for (const client of entry.clients) {
|
|
@@ -56749,6 +57065,9 @@ async function createGatewayRuntime(options = {}) {
|
|
|
56749
57065
|
runtimeController.reset();
|
|
56750
57066
|
primeLocalShellPath();
|
|
56751
57067
|
const wsServer = new WebSocketServer;
|
|
57068
|
+
connectionAlertNotifier.setBroadcaster((deviceId, payload) => {
|
|
57069
|
+
wsServer.broadcastDeviceError(deviceId, payload);
|
|
57070
|
+
});
|
|
56752
57071
|
await telegramService.refresh();
|
|
56753
57072
|
await pushSupervisor.start();
|
|
56754
57073
|
try {
|
|
@@ -56791,6 +57110,7 @@ async function createGatewayRuntime(options = {}) {
|
|
|
56791
57110
|
runtimeController.onRestart(listener);
|
|
56792
57111
|
},
|
|
56793
57112
|
async stop() {
|
|
57113
|
+
connectionAlertNotifier.setBroadcaster(null);
|
|
56794
57114
|
wsServer.closeAll();
|
|
56795
57115
|
await pushSupervisor.stopAll();
|
|
56796
57116
|
await tmuxRuntimeRegistry.shutdownAll();
|
|
@@ -57097,6 +57417,12 @@ async function main() {
|
|
|
57097
57417
|
});
|
|
57098
57418
|
console.log(`[tmex] ${t3("runtime.started", { url: `http://${host}:${port}` })}`);
|
|
57099
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
|
+
});
|
|
57100
57426
|
try {
|
|
57101
57427
|
await main();
|
|
57102
57428
|
} catch (error) {
|