tmex-cli 0.11.0 → 0.12.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/CHANGELOG.md +36 -12
- package/dist/runtime/server.js +685 -41
- package/package.json +1 -1
- package/resources/fe-dist/assets/DevicePage-B2xsa-ys.js +21 -0
- package/resources/fe-dist/assets/DevicesPage-Bm7E9QAf.js +2 -0
- package/resources/fe-dist/assets/{FilePage-YWma96aj.js → FilePage-DtXS6Krk.js} +8 -8
- package/resources/fe-dist/assets/{SettingsPage-LhUD03Ln.js → SettingsPage-Bxat-d_V.js} +3 -3
- package/resources/fe-dist/assets/{arc-DLVa298O.js → arc-CWkT1O24.js} +2 -2
- package/resources/fe-dist/assets/{architectureDiagram-3BPJPVTR-EOUpuRby.js → architectureDiagram-3BPJPVTR-nu1LX68y.js} +2 -2
- package/resources/fe-dist/assets/{blockDiagram-GPEHLZMM-BTwwkzZh.js → blockDiagram-GPEHLZMM-DLFLNzT_.js} +2 -2
- package/resources/fe-dist/assets/{c4Diagram-AAUBKEIU-xvTqXxl9.js → c4Diagram-AAUBKEIU-BE8aWxc1.js} +2 -2
- package/resources/fe-dist/assets/{card-cbVDy0Xp.js → card-Duis2VHj.js} +2 -2
- package/resources/fe-dist/assets/channel-zKL2OH3S.js +2 -0
- package/resources/fe-dist/assets/{chunk-2J33WTMH-Blr6l1Nk.js → chunk-2J33WTMH-Dlc3MV0y.js} +2 -2
- package/resources/fe-dist/assets/{chunk-4BX2VUAB-D_Y2TeLg.js → chunk-4BX2VUAB-E9XGobks.js} +2 -2
- package/resources/fe-dist/assets/{chunk-55IACEB6-CimNoYDH.js → chunk-55IACEB6-Bp7ueFZf.js} +2 -2
- package/resources/fe-dist/assets/{chunk-727SXJPM-JPYDN0Cb.js → chunk-727SXJPM-CQrvyHfQ.js} +2 -2
- package/resources/fe-dist/assets/{chunk-AQP2D5EJ-Cb3NZBib.js → chunk-AQP2D5EJ-c0B1XNZr.js} +2 -2
- package/resources/fe-dist/assets/{chunk-FMBD7UC4-DyZ7Ot2F.js → chunk-FMBD7UC4-BWQBkKWs.js} +2 -2
- package/resources/fe-dist/assets/{chunk-ND2GUHAM-SU6Ea3wF.js → chunk-ND2GUHAM-D9TROogS.js} +2 -2
- package/resources/fe-dist/assets/{chunk-QZHKN3VN-B6qXX6sU.js → chunk-QZHKN3VN-DRXr6zVP.js} +2 -2
- package/resources/fe-dist/assets/classDiagram-4FO5ZUOK-Drw216KI.js +2 -0
- package/resources/fe-dist/assets/classDiagram-v2-Q7XG4LA2-Drw216KI.js +2 -0
- package/resources/fe-dist/assets/{cose-bilkent-S5V4N54A-BAyMopHS.js → cose-bilkent-S5V4N54A-CBgJRn7g.js} +2 -2
- package/resources/fe-dist/assets/{dagre-BM42HDAG-Ckrx9BXZ.js → dagre-BM42HDAG-ClYznWvX.js} +2 -2
- package/resources/fe-dist/assets/{diagram-2AECGRRQ-DTnZtf2k.js → diagram-2AECGRRQ-Br_41uIc.js} +2 -2
- package/resources/fe-dist/assets/{diagram-5GNKFQAL-DBpgZj4a.js → diagram-5GNKFQAL-BD9o1BrS.js} +2 -2
- package/resources/fe-dist/assets/{diagram-KO2AKTUF-CfijYCeY.js → diagram-KO2AKTUF-Diq2zS9Y.js} +2 -2
- package/resources/fe-dist/assets/{diagram-LMA3HP47-D7nBmQ-E.js → diagram-LMA3HP47-CLaOalPy.js} +2 -2
- package/resources/fe-dist/assets/{diagram-OG6HWLK6-Bi8sHV0O.js → diagram-OG6HWLK6-BcSlvdPy.js} +2 -2
- package/resources/fe-dist/assets/{erDiagram-TEJ5UH35-DcoDesO2.js → erDiagram-TEJ5UH35-BNlad0c4.js} +2 -2
- package/resources/fe-dist/assets/{flowDiagram-I6XJVG4X-Bbcl9kxS.js → flowDiagram-I6XJVG4X-Zb1FLY00.js} +2 -2
- package/resources/fe-dist/assets/{ganttDiagram-6RSMTGT7-BM8Y7jwp.js → ganttDiagram-6RSMTGT7-DPRPR5Is.js} +2 -2
- package/resources/fe-dist/assets/{gitGraphDiagram-PVQCEYII-x3wpNQcW.js → gitGraphDiagram-PVQCEYII-BENU2uEN.js} +2 -2
- package/resources/fe-dist/assets/index-CRCD4gPw.css +1 -0
- package/resources/fe-dist/assets/index-Den36xcn.js +488 -0
- package/resources/fe-dist/assets/{infoDiagram-5YYISTIA-Bl6cgwVb.js → infoDiagram-5YYISTIA-NfMlH21e.js} +2 -2
- package/resources/fe-dist/assets/{ishikawaDiagram-YF4QCWOH-BfQ7aZxN.js → ishikawaDiagram-YF4QCWOH-CzK9-7uY.js} +2 -2
- package/resources/fe-dist/assets/{journeyDiagram-JHISSGLW-DSwQzmdL.js → journeyDiagram-JHISSGLW-CIX5Ahuw.js} +2 -2
- package/resources/fe-dist/assets/{kanban-definition-UN3LZRKU-B1aWDl4E.js → kanban-definition-UN3LZRKU-C5Ccl5Cw.js} +2 -2
- package/resources/fe-dist/assets/{linear-CfhRC4iX.js → linear-CBC08yeS.js} +2 -2
- package/resources/fe-dist/assets/{markdown-preview-CfBRMViB.js → markdown-preview-Drd503bU.js} +4 -4
- package/resources/fe-dist/assets/{mermaid.core-M-o4g4TO.js → mermaid.core-DYl6mxS0.js} +6 -6
- package/resources/fe-dist/assets/{mindmap-definition-RKZ34NQL-D976sxOA.js → mindmap-definition-RKZ34NQL-ACR2SUDm.js} +2 -2
- package/resources/fe-dist/assets/{pieDiagram-4H26LBE5-PVQ3-EB6.js → pieDiagram-4H26LBE5-BuDDdwwy.js} +2 -2
- package/resources/fe-dist/assets/{quadrantDiagram-W4KKPZXB-BNEFhYNq.js → quadrantDiagram-W4KKPZXB-CzM2Ydhy.js} +2 -2
- package/resources/fe-dist/assets/{refresh-cw-cfX5JiIH.js → refresh-cw-DhzvbVDA.js} +2 -2
- package/resources/fe-dist/assets/{requirementDiagram-4Y6WPE33-B7Zd2lpN.js → requirementDiagram-4Y6WPE33-BveKh_kW.js} +2 -2
- package/resources/fe-dist/assets/{sankeyDiagram-5OEKKPKP-D_Td4j-B.js → sankeyDiagram-5OEKKPKP-BGQ6jtyE.js} +2 -2
- package/resources/fe-dist/assets/{sequenceDiagram-3UESZ5HK-DQSVX5mL.js → sequenceDiagram-3UESZ5HK-D2fdqire.js} +2 -2
- package/resources/fe-dist/assets/{stateDiagram-AJRCARHV-C0PNCTfs.js → stateDiagram-AJRCARHV-DtuVBIq9.js} +2 -2
- package/resources/fe-dist/assets/stateDiagram-v2-BHNVJYJU-gun__PvU.js +2 -0
- package/resources/fe-dist/assets/{timeline-definition-PNZ67QCA-BlMj8Fl1.js → timeline-definition-PNZ67QCA-Dslo0JFS.js} +2 -2
- package/resources/fe-dist/assets/{vennDiagram-CIIHVFJN-DuGxwZiq.js → vennDiagram-CIIHVFJN-BLcoN4xU.js} +2 -2
- package/resources/fe-dist/assets/{wardley-L42UT6IY-4VhWbg10.js → wardley-L42UT6IY-OsbD5r1L.js} +2 -2
- package/resources/fe-dist/assets/{wardleyDiagram-YWT4CUSO-Bu4k6xIx.js → wardleyDiagram-YWT4CUSO-B_33zIif.js} +2 -2
- package/resources/fe-dist/assets/{xychartDiagram-2RQKCTM6-Cv88IDWh.js → xychartDiagram-2RQKCTM6-DcB27Ap1.js} +2 -2
- package/resources/fe-dist/index.html +2 -2
- package/resources/fe-dist/assets/DevicePage-fGI-do8S.js +0 -26
- package/resources/fe-dist/assets/DevicesPage-kGrzwhGj.js +0 -2
- package/resources/fe-dist/assets/channel-DbG6qNF6.js +0 -2
- package/resources/fe-dist/assets/classDiagram-4FO5ZUOK-rB1DgxOZ.js +0 -2
- package/resources/fe-dist/assets/classDiagram-v2-Q7XG4LA2-rB1DgxOZ.js +0 -2
- package/resources/fe-dist/assets/index-cfY8KuW7.js +0 -466
- package/resources/fe-dist/assets/index-vcS0VPIW.css +0 -1
- package/resources/fe-dist/assets/stateDiagram-v2-BHNVJYJU-CB5OePKf.js +0 -2
package/dist/runtime/server.js
CHANGED
|
@@ -22550,7 +22550,7 @@ loadEnv();
|
|
|
22550
22550
|
|
|
22551
22551
|
// src/runtime/server.ts
|
|
22552
22552
|
import { existsSync as existsSync8 } from "fs";
|
|
22553
|
-
import { extname as extname2, join as
|
|
22553
|
+
import { extname as extname2, join as join8, normalize, resolve as resolve6, sep } from "path";
|
|
22554
22554
|
|
|
22555
22555
|
// ../../apps/gateway/src/crypto/errors.ts
|
|
22556
22556
|
function contextLabel(context) {
|
|
@@ -22659,6 +22659,8 @@ var I18N_RESOURCES = {
|
|
|
22659
22659
|
authKey: "Private Key",
|
|
22660
22660
|
authAgent: "SSH Agent",
|
|
22661
22661
|
authConfigRef: "SSH Config",
|
|
22662
|
+
sshConfigRefPlaceholder: "Host alias, e.g. my-server",
|
|
22663
|
+
sshConfigRefHint: "A Host alias from your ssh config, resolved via `ssh -G`. Not the path to the config file.",
|
|
22662
22664
|
password: "Password",
|
|
22663
22665
|
privateKey: "Private Key",
|
|
22664
22666
|
privateKeyPlaceholder: "-----BEGIN OPENSSH PRIVATE KEY-----",
|
|
@@ -23382,12 +23384,45 @@ Time: {{time}}`,
|
|
|
23382
23384
|
unknown: "Failed to load"
|
|
23383
23385
|
},
|
|
23384
23386
|
retry: "Retry (collapse then expand)",
|
|
23387
|
+
menu: {
|
|
23388
|
+
copyAbsolute: "Copy absolute path",
|
|
23389
|
+
copyRelative: "Copy relative path",
|
|
23390
|
+
sendToAgent: "Send to Agent",
|
|
23391
|
+
expand: "Expand",
|
|
23392
|
+
collapse: "Collapse",
|
|
23393
|
+
upload: "Upload files here",
|
|
23394
|
+
open: "Open"
|
|
23395
|
+
},
|
|
23396
|
+
copied: "Copied to clipboard",
|
|
23397
|
+
copyFailed: "Copy failed",
|
|
23398
|
+
sendToAgent: {
|
|
23399
|
+
prompt: "Please work with this path: `{{path}}`"
|
|
23400
|
+
},
|
|
23401
|
+
upload: {
|
|
23402
|
+
uploading: "Uploading {{name}}\u2026",
|
|
23403
|
+
success: "Uploaded {{name}}",
|
|
23404
|
+
fail: "Failed to upload {{name}}"
|
|
23405
|
+
},
|
|
23406
|
+
transfer: {
|
|
23407
|
+
legUserToTmex: "Browser \u2192 tmex",
|
|
23408
|
+
legTmexToServer: "tmex \u2192 Server",
|
|
23409
|
+
legServerToTmex: "Server \u2192 tmex",
|
|
23410
|
+
legTmexToUser: "tmex \u2192 Browser",
|
|
23411
|
+
cancel: "Cancel",
|
|
23412
|
+
canceled: "Canceled {{name}}",
|
|
23413
|
+
downloaded: "Downloaded {{name}}",
|
|
23414
|
+
downloadFailed: "Failed to download {{name}}",
|
|
23415
|
+
dragDownloadStarted: "Started downloading {{name}} (handled by browser)",
|
|
23416
|
+
tooLarge: "{{name}} exceeds the size limit ({{max}})"
|
|
23417
|
+
},
|
|
23418
|
+
agentLaunch: {
|
|
23419
|
+
connectFailed: "Failed to connect to the device",
|
|
23420
|
+
windowFailed: "Failed to create a window"
|
|
23421
|
+
},
|
|
23385
23422
|
install: {
|
|
23386
23423
|
button: "Install rsync",
|
|
23387
23424
|
scopeLocal: "server",
|
|
23388
23425
|
scopeRemote: "remote",
|
|
23389
|
-
connectFailed: "Failed to connect to the device",
|
|
23390
|
-
windowFailed: "Failed to create a window",
|
|
23391
23426
|
prompt: "rsync is not installed on {{device}} ({{scope}}). Please install rsync using the appropriate command for this system (e.g. `brew install rsync`, `sudo apt-get install -y rsync`, or `sudo yum install -y rsync`), then reply once it is done."
|
|
23392
23427
|
}
|
|
23393
23428
|
},
|
|
@@ -23487,6 +23522,8 @@ Time: {{time}}`,
|
|
|
23487
23522
|
authKey: "\u79C1\u94A5",
|
|
23488
23523
|
authAgent: "SSH Agent",
|
|
23489
23524
|
authConfigRef: "SSH Config",
|
|
23525
|
+
sshConfigRefPlaceholder: "Host \u522B\u540D\uFF0C\u5982 my-server",
|
|
23526
|
+
sshConfigRefHint: "\u586B ssh config \u91CC\u7684 Host \u522B\u540D\uFF0C\u7ECF `ssh -G` \u89E3\u6790\uFF1B\u4E0D\u662F config \u6587\u4EF6\u8DEF\u5F84\u3002",
|
|
23490
23527
|
password: "\u5BC6\u7801",
|
|
23491
23528
|
privateKey: "\u79C1\u94A5",
|
|
23492
23529
|
privateKeyPlaceholder: "-----BEGIN OPENSSH PRIVATE KEY-----",
|
|
@@ -24210,12 +24247,45 @@ Bot\uFF1A{{botName}}
|
|
|
24210
24247
|
unknown: "\u52A0\u8F7D\u5931\u8D25"
|
|
24211
24248
|
},
|
|
24212
24249
|
retry: "\u91CD\u8BD5\uFF08\u6536\u8D77\u540E\u518D\u5C55\u5F00\uFF09",
|
|
24250
|
+
menu: {
|
|
24251
|
+
copyAbsolute: "\u590D\u5236\u7EDD\u5BF9\u4F4D\u7F6E",
|
|
24252
|
+
copyRelative: "\u590D\u5236\u76F8\u5BF9\u4F4D\u7F6E",
|
|
24253
|
+
sendToAgent: "\u53D1\u9001\u5230 Agent",
|
|
24254
|
+
expand: "\u5C55\u5F00",
|
|
24255
|
+
collapse: "\u6536\u8D77",
|
|
24256
|
+
upload: "\u4E0A\u4F20\u6587\u4EF6\u5230\u8FD9\u4E2A\u6587\u4EF6\u5939",
|
|
24257
|
+
open: "\u6253\u5F00"
|
|
24258
|
+
},
|
|
24259
|
+
copied: "\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F",
|
|
24260
|
+
copyFailed: "\u590D\u5236\u5931\u8D25",
|
|
24261
|
+
sendToAgent: {
|
|
24262
|
+
prompt: "\u8BF7\u5904\u7406\u8FD9\u4E2A\u8DEF\u5F84\uFF1A`{{path}}`"
|
|
24263
|
+
},
|
|
24264
|
+
upload: {
|
|
24265
|
+
uploading: "\u6B63\u5728\u4E0A\u4F20 {{name}}\u2026",
|
|
24266
|
+
success: "\u5DF2\u4E0A\u4F20 {{name}}",
|
|
24267
|
+
fail: "\u4E0A\u4F20 {{name}} \u5931\u8D25"
|
|
24268
|
+
},
|
|
24269
|
+
transfer: {
|
|
24270
|
+
legUserToTmex: "\u7528\u6237 \u2192 tmex",
|
|
24271
|
+
legTmexToServer: "tmex \u2192 \u670D\u52A1\u5668",
|
|
24272
|
+
legServerToTmex: "\u670D\u52A1\u5668 \u2192 tmex",
|
|
24273
|
+
legTmexToUser: "tmex \u2192 \u7528\u6237",
|
|
24274
|
+
cancel: "\u53D6\u6D88",
|
|
24275
|
+
canceled: "\u5DF2\u53D6\u6D88 {{name}}",
|
|
24276
|
+
downloaded: "\u5DF2\u4E0B\u8F7D {{name}}",
|
|
24277
|
+
downloadFailed: "\u4E0B\u8F7D {{name}} \u5931\u8D25",
|
|
24278
|
+
dragDownloadStarted: "\u5DF2\u5F00\u59CB\u4E0B\u8F7D {{name}}\uFF08\u7531\u6D4F\u89C8\u5668\u63A5\u7BA1\uFF09",
|
|
24279
|
+
tooLarge: "{{name}} \u8D85\u8FC7\u5927\u5C0F\u4E0A\u9650\uFF08{{max}}\uFF09"
|
|
24280
|
+
},
|
|
24281
|
+
agentLaunch: {
|
|
24282
|
+
connectFailed: "\u8FDE\u63A5\u8BBE\u5907\u5931\u8D25",
|
|
24283
|
+
windowFailed: "\u521B\u5EFA\u7A97\u53E3\u5931\u8D25"
|
|
24284
|
+
},
|
|
24213
24285
|
install: {
|
|
24214
24286
|
button: "\u5B89\u88C5 rsync",
|
|
24215
24287
|
scopeLocal: "\u670D\u52A1\u5668",
|
|
24216
24288
|
scopeRemote: "\u8FDC\u7A0B",
|
|
24217
|
-
connectFailed: "\u8FDE\u63A5\u8BBE\u5907\u5931\u8D25",
|
|
24218
|
-
windowFailed: "\u521B\u5EFA\u7A97\u53E3\u5931\u8D25",
|
|
24219
24289
|
prompt: "\u8BBE\u5907 {{device}}\uFF08{{scope}}\uFF09\u4E0A\u672A\u68C0\u6D4B\u5230 rsync\u3002\u8BF7\u6839\u636E\u7CFB\u7EDF\u9009\u62E9\u5408\u9002\u7684\u547D\u4EE4\u5B89\u88C5 rsync\uFF08\u4F8B\u5982 `brew install rsync`\u3001`sudo apt-get install -y rsync` \u6216 `sudo yum install -y rsync`\uFF09\uFF0C\u5B89\u88C5\u5B8C\u6210\u540E\u56DE\u590D\u6211\u3002"
|
|
24220
24290
|
}
|
|
24221
24291
|
},
|
|
@@ -24315,6 +24385,8 @@ Bot\uFF1A{{botName}}
|
|
|
24315
24385
|
authKey: "\u79D8\u5BC6\u9375",
|
|
24316
24386
|
authAgent: "SSH Agent",
|
|
24317
24387
|
authConfigRef: "SSH Config",
|
|
24388
|
+
sshConfigRefPlaceholder: "Host \u30A8\u30A4\u30EA\u30A2\u30B9\uFF08\u4F8B: my-server\uFF09",
|
|
24389
|
+
sshConfigRefHint: "ssh config \u306E Host \u30A8\u30A4\u30EA\u30A2\u30B9\u3092\u5165\u529B\u3057\u307E\u3059\u3002`ssh -G` \u3067\u89E3\u6C7A\u3055\u308C\u307E\u3059\u3002config \u30D5\u30A1\u30A4\u30EB\u306E\u30D1\u30B9\u3067\u306F\u3042\u308A\u307E\u305B\u3093\u3002",
|
|
24318
24390
|
password: "\u30D1\u30B9\u30EF\u30FC\u30C9",
|
|
24319
24391
|
privateKey: "\u79D8\u5BC6\u9375",
|
|
24320
24392
|
privateKeyPlaceholder: "-----BEGIN OPENSSH PRIVATE KEY-----",
|
|
@@ -25038,12 +25110,45 @@ Bot\uFF1A{{botName}}
|
|
|
25038
25110
|
unknown: "\u8AAD\u307F\u8FBC\u307F\u306B\u5931\u6557\u3057\u307E\u3057\u305F"
|
|
25039
25111
|
},
|
|
25040
25112
|
retry: "\u518D\u8A66\u884C\uFF08\u6298\u308A\u305F\u305F\u3093\u3067\u518D\u5C55\u958B\uFF09",
|
|
25113
|
+
menu: {
|
|
25114
|
+
copyAbsolute: "\u7D76\u5BFE\u30D1\u30B9\u3092\u30B3\u30D4\u30FC",
|
|
25115
|
+
copyRelative: "\u76F8\u5BFE\u30D1\u30B9\u3092\u30B3\u30D4\u30FC",
|
|
25116
|
+
sendToAgent: "Agent \u306B\u9001\u308B",
|
|
25117
|
+
expand: "\u5C55\u958B",
|
|
25118
|
+
collapse: "\u6298\u308A\u305F\u305F\u3080",
|
|
25119
|
+
upload: "\u3053\u306E\u30D5\u30A9\u30EB\u30C0\u306B\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9",
|
|
25120
|
+
open: "\u958B\u304F"
|
|
25121
|
+
},
|
|
25122
|
+
copied: "\u30AF\u30EA\u30C3\u30D7\u30DC\u30FC\u30C9\u306B\u30B3\u30D4\u30FC\u3057\u307E\u3057\u305F",
|
|
25123
|
+
copyFailed: "\u30B3\u30D4\u30FC\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
|
|
25124
|
+
sendToAgent: {
|
|
25125
|
+
prompt: "\u3053\u306E\u30D1\u30B9\u3092\u51E6\u7406\u3057\u3066\u304F\u3060\u3055\u3044\uFF1A`{{path}}`"
|
|
25126
|
+
},
|
|
25127
|
+
upload: {
|
|
25128
|
+
uploading: "{{name}} \u3092\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u4E2D\u2026",
|
|
25129
|
+
success: "{{name}} \u3092\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u3057\u307E\u3057\u305F",
|
|
25130
|
+
fail: "{{name}} \u306E\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u306B\u5931\u6557\u3057\u307E\u3057\u305F"
|
|
25131
|
+
},
|
|
25132
|
+
transfer: {
|
|
25133
|
+
legUserToTmex: "\u30D6\u30E9\u30A6\u30B6 \u2192 tmex",
|
|
25134
|
+
legTmexToServer: "tmex \u2192 \u30B5\u30FC\u30D0\u30FC",
|
|
25135
|
+
legServerToTmex: "\u30B5\u30FC\u30D0\u30FC \u2192 tmex",
|
|
25136
|
+
legTmexToUser: "tmex \u2192 \u30D6\u30E9\u30A6\u30B6",
|
|
25137
|
+
cancel: "\u30AD\u30E3\u30F3\u30BB\u30EB",
|
|
25138
|
+
canceled: "{{name}} \u3092\u30AD\u30E3\u30F3\u30BB\u30EB\u3057\u307E\u3057\u305F",
|
|
25139
|
+
downloaded: "{{name}} \u3092\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u3057\u307E\u3057\u305F",
|
|
25140
|
+
downloadFailed: "{{name}} \u306E\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
|
|
25141
|
+
dragDownloadStarted: "{{name}} \u306E\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u3092\u958B\u59CB\uFF08\u30D6\u30E9\u30A6\u30B6\u304C\u51E6\u7406\uFF09",
|
|
25142
|
+
tooLarge: "{{name}} \u306F\u30B5\u30A4\u30BA\u4E0A\u9650\uFF08{{max}}\uFF09\u3092\u8D85\u3048\u3066\u3044\u307E\u3059"
|
|
25143
|
+
},
|
|
25144
|
+
agentLaunch: {
|
|
25145
|
+
connectFailed: "\u30C7\u30D0\u30A4\u30B9\u3078\u306E\u63A5\u7D9A\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
|
|
25146
|
+
windowFailed: "\u30A6\u30A3\u30F3\u30C9\u30A6\u306E\u4F5C\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F"
|
|
25147
|
+
},
|
|
25041
25148
|
install: {
|
|
25042
25149
|
button: "rsync \u3092\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB",
|
|
25043
25150
|
scopeLocal: "\u30B5\u30FC\u30D0\u30FC",
|
|
25044
25151
|
scopeRemote: "\u30EA\u30E2\u30FC\u30C8",
|
|
25045
|
-
connectFailed: "\u30C7\u30D0\u30A4\u30B9\u3078\u306E\u63A5\u7D9A\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
|
|
25046
|
-
windowFailed: "\u30A6\u30A3\u30F3\u30C9\u30A6\u306E\u4F5C\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
|
|
25047
25152
|
prompt: "{{device}}\uFF08{{scope}}\uFF09\u306B rsync \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3002\u30B7\u30B9\u30C6\u30E0\u306B\u5408\u308F\u305B\u305F\u65B9\u6CD5\u3067 rsync \u3092\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3057\uFF08\u4F8B: `brew install rsync`\u3001`sudo apt-get install -y rsync`\u3001`sudo yum install -y rsync`\uFF09\u3001\u5B8C\u4E86\u3057\u305F\u3089\u8FD4\u4FE1\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
|
|
25048
25153
|
}
|
|
25049
25154
|
},
|
|
@@ -27583,6 +27688,7 @@ var config = {
|
|
|
27583
27688
|
baseUrl: getEnv("TMEX_BASE_URL", "http://127.0.0.1:8085"),
|
|
27584
27689
|
siteNameDefault: getEnv("TMEX_SITE_NAME", "tmex"),
|
|
27585
27690
|
databaseUrl: getEnv("DATABASE_URL", "./tmex.db"),
|
|
27691
|
+
transferMaxBytes: Number.parseInt(getEnv("TMEX_TRANSFER_MAX_BYTES", "2147483648"), 10),
|
|
27586
27692
|
bellThrottleSecondsDefault: Number.parseInt(getEnv("TMEX_BELL_THROTTLE_SECONDS", "6"), 10),
|
|
27587
27693
|
notificationThrottleSecondsDefault: Number.parseInt(getEnv("TMEX_NOTIFICATION_THROTTLE_SECONDS", "3"), 10),
|
|
27588
27694
|
tmuxAllowPassthrough: getBooleanEnv("TMEX_TMUX_ALLOW_PASSTHROUGH", false),
|
|
@@ -86753,9 +86859,6 @@ function normalizeHttpUrl(input) {
|
|
|
86753
86859
|
return null;
|
|
86754
86860
|
}
|
|
86755
86861
|
}
|
|
86756
|
-
function encodePercentForTelegramUrl(url2) {
|
|
86757
|
-
return url2.replace(/%/g, "%25");
|
|
86758
|
-
}
|
|
86759
86862
|
|
|
86760
86863
|
class EventNotifier {
|
|
86761
86864
|
webhooks = [];
|
|
@@ -86899,8 +87002,7 @@ class EventNotifier {
|
|
|
86899
87002
|
lines.push(...this.buildPaneMetaLines(event));
|
|
86900
87003
|
const paneUrl = normalizeHttpUrl(buildPaneUrl(event));
|
|
86901
87004
|
if (paneUrl) {
|
|
86902
|
-
|
|
86903
|
-
lines.push("", `<a href="${escapeTelegramHtmlAttribute(tgSafePaneUrl)}">${escapeTelegramHtmlText(t2("notification.telegramBell.viewLink"))}</a>`);
|
|
87005
|
+
lines.push("", `<a href="${escapeTelegramHtmlAttribute(paneUrl)}">${escapeTelegramHtmlText(t2("notification.telegramBell.viewLink"))}</a>`);
|
|
86904
87006
|
}
|
|
86905
87007
|
return lines.join(`
|
|
86906
87008
|
`);
|
|
@@ -86920,8 +87022,7 @@ class EventNotifier {
|
|
|
86920
87022
|
const topbarLabel = this.buildTerminalTopbarLabel(event);
|
|
86921
87023
|
const footer = `from ${event.site.name}: ${topbarLabel}`;
|
|
86922
87024
|
if (paneUrl) {
|
|
86923
|
-
|
|
86924
|
-
lines.push("", `<a href="${escapeTelegramHtmlAttribute(tgSafePaneUrl)}">${escapeTelegramHtmlText(footer)}</a>`);
|
|
87025
|
+
lines.push("", `<a href="${escapeTelegramHtmlAttribute(paneUrl)}">${escapeTelegramHtmlText(footer)}</a>`);
|
|
86925
87026
|
} else {
|
|
86926
87027
|
lines.push("", escapeTelegramHtmlText(footer));
|
|
86927
87028
|
}
|
|
@@ -86961,8 +87062,7 @@ class EventNotifier {
|
|
|
86961
87062
|
}
|
|
86962
87063
|
const paneUrl = normalizeHttpUrl(buildPaneUrl(event));
|
|
86963
87064
|
if (paneUrl) {
|
|
86964
|
-
|
|
86965
|
-
lines.push("", `<a href="${escapeTelegramHtmlAttribute(tgSafePaneUrl)}">${esc2(t2("notification.directLink"))}</a>`);
|
|
87065
|
+
lines.push("", `<a href="${escapeTelegramHtmlAttribute(paneUrl)}">${esc2(t2("notification.directLink"))}</a>`);
|
|
86966
87066
|
}
|
|
86967
87067
|
return lines.join(`
|
|
86968
87068
|
`);
|
|
@@ -95883,10 +95983,12 @@ class ConnectionAlertNotifier {
|
|
|
95883
95983
|
const classified = classifySshError(errObj);
|
|
95884
95984
|
const friendlyMessage = t2(classified.messageKey, { ...classified.messageParams });
|
|
95885
95985
|
const rawMessage = errObj.message;
|
|
95986
|
+
const persistedMessage = rawMessage && !friendlyMessage.includes(rawMessage) ? `${friendlyMessage}
|
|
95987
|
+
${rawMessage}` : friendlyMessage;
|
|
95886
95988
|
console.error(`[conn-alert] device ${device.id} (${device.name}) source=${source} type=${classified.type}: ${rawMessage}`);
|
|
95887
95989
|
if (persist) {
|
|
95888
95990
|
try {
|
|
95889
|
-
this.persister(device.id,
|
|
95991
|
+
this.persister(device.id, persistedMessage, classified.type);
|
|
95890
95992
|
} catch (dbErr) {
|
|
95891
95993
|
console.error("[conn-alert] failed to persist runtime status:", dbErr);
|
|
95892
95994
|
}
|
|
@@ -98251,7 +98353,7 @@ function resolveSshConfigRef(device, deps) {
|
|
|
98251
98353
|
return parseSshConfigOutput(result.stdout, deps.env);
|
|
98252
98354
|
}
|
|
98253
98355
|
function resolveImplicitIdentityFilesForAgentAuth(device, host, port, username, deps) {
|
|
98254
|
-
if (device.authMode !== "agent"
|
|
98356
|
+
if (device.authMode !== "agent") {
|
|
98255
98357
|
return [];
|
|
98256
98358
|
}
|
|
98257
98359
|
const target = username ? `${username}@${host}` : host;
|
|
@@ -98273,7 +98375,7 @@ async function resolveSshConnectConfig(device, decrypt2, inputDeps = {}) {
|
|
|
98273
98375
|
readTextFile: inputDeps.readTextFile ?? ((path) => readFileSync2(path, "utf8"))
|
|
98274
98376
|
};
|
|
98275
98377
|
const sshEnv = toSshAuthEnv(deps.env);
|
|
98276
|
-
const resolvedConfig = resolveSshConfigRef(device, deps);
|
|
98378
|
+
const resolvedConfig = device.authMode === "configRef" ? resolveSshConfigRef(device, deps) : null;
|
|
98277
98379
|
const host = resolvedConfig?.host ?? device.host;
|
|
98278
98380
|
const port = resolvedConfig?.port ?? device.port ?? 22;
|
|
98279
98381
|
const username = resolvedConfig?.username ?? resolveSshUsername(device.username, device.authMode, sshEnv);
|
|
@@ -102871,7 +102973,7 @@ function deleteFileRoot(id) {
|
|
|
102871
102973
|
}
|
|
102872
102974
|
|
|
102873
102975
|
// ../../apps/gateway/src/files/device-storage.ts
|
|
102874
|
-
import { mkdtempSync as mkdtempSync2, readFileSync as readFileSync3, realpathSync, rmSync as rmSync2 } from "fs";
|
|
102976
|
+
import { mkdtempSync as mkdtempSync2, readFileSync as readFileSync3, realpathSync, rmSync as rmSync2, statSync } from "fs";
|
|
102875
102977
|
import { tmpdir as tmpdir2 } from "os";
|
|
102876
102978
|
import { join as join5 } from "path";
|
|
102877
102979
|
|
|
@@ -103106,6 +103208,18 @@ function enqueueDeviceJob(deviceId, job) {
|
|
|
103106
103208
|
}
|
|
103107
103209
|
|
|
103108
103210
|
// ../../apps/gateway/src/files/rsync.ts
|
|
103211
|
+
var PROGRESS_RE = /^\s*([\d,]+)\s+(\d+)%\s+([\d.]+[KMGT]?B\/s)/;
|
|
103212
|
+
function parseRsyncProgress(line) {
|
|
103213
|
+
const m = PROGRESS_RE.exec(line);
|
|
103214
|
+
if (!m)
|
|
103215
|
+
return null;
|
|
103216
|
+
const transferred = Number.parseInt(m[1].replace(/,/g, ""), 10);
|
|
103217
|
+
const pct = Number.parseInt(m[2], 10);
|
|
103218
|
+
if (Number.isNaN(transferred) || Number.isNaN(pct))
|
|
103219
|
+
return null;
|
|
103220
|
+
return { transferred, pct, rate: m[3] };
|
|
103221
|
+
}
|
|
103222
|
+
|
|
103109
103223
|
class RsyncMissingLocalError extends Error {
|
|
103110
103224
|
constructor(message) {
|
|
103111
103225
|
super(message);
|
|
@@ -103127,8 +103241,36 @@ function baseSubprocessEnv() {
|
|
|
103127
103241
|
out.LC_ALL = "C";
|
|
103128
103242
|
return out;
|
|
103129
103243
|
}
|
|
103244
|
+
async function readStdoutWithProgress(stream, onProgress, resetIdle) {
|
|
103245
|
+
const reader = stream.getReader();
|
|
103246
|
+
const decoder4 = new TextDecoder;
|
|
103247
|
+
let full = "";
|
|
103248
|
+
let buf = "";
|
|
103249
|
+
for (;; ) {
|
|
103250
|
+
const { done, value } = await reader.read();
|
|
103251
|
+
if (done)
|
|
103252
|
+
break;
|
|
103253
|
+
resetIdle();
|
|
103254
|
+
const text3 = decoder4.decode(value, { stream: true });
|
|
103255
|
+
full += text3;
|
|
103256
|
+
buf += text3;
|
|
103257
|
+
const parts = buf.split(/[\r\n]/);
|
|
103258
|
+
buf = parts.pop() ?? "";
|
|
103259
|
+
for (const line of parts) {
|
|
103260
|
+
const p = parseRsyncProgress(line);
|
|
103261
|
+
if (p)
|
|
103262
|
+
onProgress(p);
|
|
103263
|
+
}
|
|
103264
|
+
}
|
|
103265
|
+
const tail = parseRsyncProgress(buf);
|
|
103266
|
+
if (tail)
|
|
103267
|
+
onProgress(tail);
|
|
103268
|
+
return full;
|
|
103269
|
+
}
|
|
103130
103270
|
async function runRsync(argv, opts = {}) {
|
|
103271
|
+
const streaming = typeof opts.onProgress === "function";
|
|
103131
103272
|
const timeoutMs = opts.timeoutMs ?? 20000;
|
|
103273
|
+
const idleTimeoutMs = opts.idleTimeoutMs ?? 120000;
|
|
103132
103274
|
let proc;
|
|
103133
103275
|
try {
|
|
103134
103276
|
proc = Bun.spawn(["rsync", ...argv], {
|
|
@@ -103141,21 +103283,36 @@ async function runRsync(argv, opts = {}) {
|
|
|
103141
103283
|
throw new RsyncMissingLocalError(error51 instanceof Error ? error51.message : String(error51));
|
|
103142
103284
|
}
|
|
103143
103285
|
let timedOut = false;
|
|
103144
|
-
const
|
|
103145
|
-
timedOut = true;
|
|
103146
|
-
try {
|
|
103147
|
-
proc.kill();
|
|
103148
|
-
} catch {}
|
|
103149
|
-
}, timeoutMs);
|
|
103150
|
-
const onAbort = () => {
|
|
103286
|
+
const killProc = () => {
|
|
103151
103287
|
try {
|
|
103152
103288
|
proc.kill();
|
|
103153
103289
|
} catch {}
|
|
103154
103290
|
};
|
|
103291
|
+
let killTimer;
|
|
103292
|
+
const armFixed = () => {
|
|
103293
|
+
killTimer = setTimeout(() => {
|
|
103294
|
+
timedOut = true;
|
|
103295
|
+
killProc();
|
|
103296
|
+
}, timeoutMs);
|
|
103297
|
+
};
|
|
103298
|
+
const resetIdle = () => {
|
|
103299
|
+
if (killTimer)
|
|
103300
|
+
clearTimeout(killTimer);
|
|
103301
|
+
killTimer = setTimeout(() => {
|
|
103302
|
+
timedOut = true;
|
|
103303
|
+
killProc();
|
|
103304
|
+
}, idleTimeoutMs);
|
|
103305
|
+
};
|
|
103306
|
+
if (streaming)
|
|
103307
|
+
resetIdle();
|
|
103308
|
+
else
|
|
103309
|
+
armFixed();
|
|
103310
|
+
const onAbort = () => killProc();
|
|
103155
103311
|
opts.signal?.addEventListener("abort", onAbort, { once: true });
|
|
103156
103312
|
try {
|
|
103313
|
+
const stdoutPromise = streaming ? readStdoutWithProgress(proc.stdout, opts.onProgress, resetIdle) : new Response(proc.stdout).text();
|
|
103157
103314
|
const [stdout, stderr, exitCode] = await Promise.all([
|
|
103158
|
-
|
|
103315
|
+
stdoutPromise,
|
|
103159
103316
|
new Response(proc.stderr).text(),
|
|
103160
103317
|
proc.exited
|
|
103161
103318
|
]);
|
|
@@ -103165,7 +103322,8 @@ async function runRsync(argv, opts = {}) {
|
|
|
103165
103322
|
}
|
|
103166
103323
|
return { stdout, stderr, exitCode };
|
|
103167
103324
|
} finally {
|
|
103168
|
-
|
|
103325
|
+
if (killTimer)
|
|
103326
|
+
clearTimeout(killTimer);
|
|
103169
103327
|
opts.signal?.removeEventListener("abort", onAbort);
|
|
103170
103328
|
}
|
|
103171
103329
|
}
|
|
@@ -103347,17 +103505,25 @@ function rsyncListArgs(spec, remotePath) {
|
|
|
103347
103505
|
return args;
|
|
103348
103506
|
}
|
|
103349
103507
|
function rsyncCopyArgs(spec, remotePath, dest) {
|
|
103350
|
-
const args = ["-L"];
|
|
103508
|
+
const args = ["-L", "--progress"];
|
|
103351
103509
|
if (spec.rsh)
|
|
103352
103510
|
args.push("-e", spec.rsh);
|
|
103353
103511
|
args.push(rsyncTargetArg(spec, remotePath), dest);
|
|
103354
103512
|
return args;
|
|
103355
103513
|
}
|
|
103514
|
+
function rsyncUploadArgs(spec, localSource, remoteDest) {
|
|
103515
|
+
const args = ["--progress"];
|
|
103516
|
+
if (spec.rsh)
|
|
103517
|
+
args.push("-e", spec.rsh);
|
|
103518
|
+
args.push(localSource, rsyncTargetArg(spec, remoteDest));
|
|
103519
|
+
return args;
|
|
103520
|
+
}
|
|
103356
103521
|
|
|
103357
103522
|
// ../../apps/gateway/src/files/device-storage.ts
|
|
103358
103523
|
var RAW_MAX_BYTES = 50 * 1024 * 1024;
|
|
103359
103524
|
var LIST_TIMEOUT_MS = 20000;
|
|
103360
103525
|
var COPY_TIMEOUT_MS = 60000;
|
|
103526
|
+
var TRANSFER_IDLE_TIMEOUT_MS = 120000;
|
|
103361
103527
|
function ok(data) {
|
|
103362
103528
|
return { ok: true, data };
|
|
103363
103529
|
}
|
|
@@ -103667,8 +103833,241 @@ async function readRawFile(rootId, inputPath) {
|
|
|
103667
103833
|
}
|
|
103668
103834
|
});
|
|
103669
103835
|
}
|
|
103836
|
+
function sanitizeUploadName(raw) {
|
|
103837
|
+
const base = raw.split("/").pop() ?? "";
|
|
103838
|
+
if (base === "" || base === "." || base === "..")
|
|
103839
|
+
return null;
|
|
103840
|
+
if (base.includes("/") || base.includes("\\") || base.includes("\x00"))
|
|
103841
|
+
return null;
|
|
103842
|
+
return base;
|
|
103843
|
+
}
|
|
103844
|
+
async function pushFileToDevice(rootId, destDir, srcPath, name24, opts = {}) {
|
|
103845
|
+
const safeName = sanitizeUploadName(name24);
|
|
103846
|
+
if (!safeName)
|
|
103847
|
+
return fail("invalid");
|
|
103848
|
+
const r = resolveContext(rootId);
|
|
103849
|
+
if (!r.ok)
|
|
103850
|
+
return fail(r.code);
|
|
103851
|
+
const { root, device } = r.ctx;
|
|
103852
|
+
const norm = checkAndNormalize(device, root.path, destDir);
|
|
103853
|
+
if (!norm.ok)
|
|
103854
|
+
return fail(norm.code);
|
|
103855
|
+
return enqueueDeviceJob(device.id, async () => {
|
|
103856
|
+
let spec;
|
|
103857
|
+
try {
|
|
103858
|
+
spec = await buildRsyncDeviceSpec(device);
|
|
103859
|
+
} catch (error51) {
|
|
103860
|
+
if (error51 instanceof RsyncAuthError)
|
|
103861
|
+
return fail(error51.code, error51.message);
|
|
103862
|
+
throw error51;
|
|
103863
|
+
}
|
|
103864
|
+
try {
|
|
103865
|
+
const destStat = await statViaRsync(spec, norm.path);
|
|
103866
|
+
if (!destStat.ok)
|
|
103867
|
+
return destStat;
|
|
103868
|
+
if (destStat.data.type !== "dir")
|
|
103869
|
+
return fail("not_a_directory");
|
|
103870
|
+
const remoteDest = posixJoin(norm.path, safeName);
|
|
103871
|
+
let res;
|
|
103872
|
+
try {
|
|
103873
|
+
res = await runRsync(rsyncUploadArgs(spec, srcPath, remoteDest), {
|
|
103874
|
+
env: spec.env,
|
|
103875
|
+
onProgress: opts.onProgress,
|
|
103876
|
+
idleTimeoutMs: TRANSFER_IDLE_TIMEOUT_MS,
|
|
103877
|
+
signal: opts.signal
|
|
103878
|
+
});
|
|
103879
|
+
} catch (error51) {
|
|
103880
|
+
if (error51 instanceof RsyncMissingLocalError)
|
|
103881
|
+
return fail("rsync_missing_local");
|
|
103882
|
+
throw error51;
|
|
103883
|
+
}
|
|
103884
|
+
if (res.exitCode !== 0)
|
|
103885
|
+
return fail(classifyRsyncFailure(res.exitCode, res.stderr), res.stderr);
|
|
103886
|
+
return ok({ uploaded: safeName });
|
|
103887
|
+
} finally {
|
|
103888
|
+
spec.cleanup();
|
|
103889
|
+
}
|
|
103890
|
+
});
|
|
103891
|
+
}
|
|
103892
|
+
async function pullFileFromDevice(rootId, inputPath, opts = {}) {
|
|
103893
|
+
const r = resolveContext(rootId);
|
|
103894
|
+
if (!r.ok)
|
|
103895
|
+
return fail(r.code);
|
|
103896
|
+
const { root, device } = r.ctx;
|
|
103897
|
+
const norm = checkAndNormalize(device, root.path, inputPath);
|
|
103898
|
+
if (!norm.ok)
|
|
103899
|
+
return fail(norm.code);
|
|
103900
|
+
return enqueueDeviceJob(device.id, async () => {
|
|
103901
|
+
let spec;
|
|
103902
|
+
try {
|
|
103903
|
+
spec = await buildRsyncDeviceSpec(device);
|
|
103904
|
+
} catch (error51) {
|
|
103905
|
+
if (error51 instanceof RsyncAuthError)
|
|
103906
|
+
return fail(error51.code, error51.message);
|
|
103907
|
+
throw error51;
|
|
103908
|
+
}
|
|
103909
|
+
try {
|
|
103910
|
+
const st = await statViaRsync(spec, norm.path);
|
|
103911
|
+
if (!st.ok)
|
|
103912
|
+
return st;
|
|
103913
|
+
if (st.data.type === "dir")
|
|
103914
|
+
return fail("is_directory");
|
|
103915
|
+
if (st.data.size != null && st.data.size > config.transferMaxBytes)
|
|
103916
|
+
return fail("too_large");
|
|
103917
|
+
const dir2 = mkdtempSync2(join5(tmpdir2(), "tmex-dl-"));
|
|
103918
|
+
const dest = join5(dir2, "f");
|
|
103919
|
+
const cleanup = () => {
|
|
103920
|
+
try {
|
|
103921
|
+
rmSync2(dir2, { recursive: true, force: true });
|
|
103922
|
+
} catch {}
|
|
103923
|
+
};
|
|
103924
|
+
let res;
|
|
103925
|
+
try {
|
|
103926
|
+
res = await runRsync(rsyncCopyArgs(spec, norm.path, dest), {
|
|
103927
|
+
env: spec.env,
|
|
103928
|
+
onProgress: opts.onProgress,
|
|
103929
|
+
idleTimeoutMs: TRANSFER_IDLE_TIMEOUT_MS,
|
|
103930
|
+
signal: opts.signal
|
|
103931
|
+
});
|
|
103932
|
+
} catch (error51) {
|
|
103933
|
+
cleanup();
|
|
103934
|
+
if (error51 instanceof RsyncMissingLocalError)
|
|
103935
|
+
return fail("rsync_missing_local");
|
|
103936
|
+
throw error51;
|
|
103937
|
+
}
|
|
103938
|
+
if (res.exitCode !== 0) {
|
|
103939
|
+
cleanup();
|
|
103940
|
+
return fail(classifyRsyncFailure(res.exitCode, res.stderr), res.stderr);
|
|
103941
|
+
}
|
|
103942
|
+
const name24 = posixBasename(norm.path);
|
|
103943
|
+
let size = st.data.size ?? 0;
|
|
103944
|
+
try {
|
|
103945
|
+
size = statSync(dest).size;
|
|
103946
|
+
} catch {}
|
|
103947
|
+
if (size > config.transferMaxBytes) {
|
|
103948
|
+
cleanup();
|
|
103949
|
+
return fail("too_large");
|
|
103950
|
+
}
|
|
103951
|
+
return ok({ tmpPath: dest, size, name: name24, mime: mimeOf(name24), cleanup });
|
|
103952
|
+
} finally {
|
|
103953
|
+
spec.cleanup();
|
|
103954
|
+
}
|
|
103955
|
+
});
|
|
103956
|
+
}
|
|
103957
|
+
|
|
103958
|
+
// ../../apps/gateway/src/files/transfer-session.ts
|
|
103959
|
+
import { appendFileSync, mkdtempSync as mkdtempSync3, readdirSync, rmSync as rmSync3, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
103960
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
103961
|
+
import { join as join6 } from "path";
|
|
103962
|
+
var sessions = new Map;
|
|
103963
|
+
var SESSION_TTL_MS = 30 * 60000;
|
|
103964
|
+
var downloads = new Map;
|
|
103965
|
+
function sweepStale(now2) {
|
|
103966
|
+
for (const [id, s] of sessions) {
|
|
103967
|
+
if (!s.committing && now2 - s.createdAt > SESSION_TTL_MS) {
|
|
103968
|
+
removeUploadSession(id);
|
|
103969
|
+
}
|
|
103970
|
+
}
|
|
103971
|
+
for (const [id, d] of downloads) {
|
|
103972
|
+
if (now2 - d.createdAt > SESSION_TTL_MS) {
|
|
103973
|
+
removeDownloadSession(id);
|
|
103974
|
+
}
|
|
103975
|
+
}
|
|
103976
|
+
}
|
|
103977
|
+
function createDownloadSession(data) {
|
|
103978
|
+
sweepStale(Date.now());
|
|
103979
|
+
const session = { id: crypto.randomUUID(), createdAt: Date.now(), ...data };
|
|
103980
|
+
downloads.set(session.id, session);
|
|
103981
|
+
return session;
|
|
103982
|
+
}
|
|
103983
|
+
function getDownloadSession(id) {
|
|
103984
|
+
return downloads.get(id);
|
|
103985
|
+
}
|
|
103986
|
+
function removeDownloadSession(id) {
|
|
103987
|
+
const d = downloads.get(id);
|
|
103988
|
+
if (!d)
|
|
103989
|
+
return;
|
|
103990
|
+
downloads.delete(id);
|
|
103991
|
+
try {
|
|
103992
|
+
d.cleanup();
|
|
103993
|
+
} catch {}
|
|
103994
|
+
}
|
|
103995
|
+
function createUploadSession(args) {
|
|
103996
|
+
const now2 = Date.now();
|
|
103997
|
+
sweepStale(now2);
|
|
103998
|
+
const tmpDir = mkdtempSync3(join6(tmpdir3(), "tmex-up-"));
|
|
103999
|
+
const tmpPath = join6(tmpDir, "f");
|
|
104000
|
+
writeFileSync2(tmpPath, new Uint8Array(0));
|
|
104001
|
+
const session = {
|
|
104002
|
+
id: crypto.randomUUID(),
|
|
104003
|
+
rootId: args.rootId,
|
|
104004
|
+
destDir: args.destDir,
|
|
104005
|
+
name: args.name,
|
|
104006
|
+
size: args.size,
|
|
104007
|
+
received: 0,
|
|
104008
|
+
tmpDir,
|
|
104009
|
+
tmpPath,
|
|
104010
|
+
abort: new AbortController,
|
|
104011
|
+
createdAt: now2,
|
|
104012
|
+
committing: false
|
|
104013
|
+
};
|
|
104014
|
+
sessions.set(session.id, session);
|
|
104015
|
+
return session;
|
|
104016
|
+
}
|
|
104017
|
+
function getUploadSession(id) {
|
|
104018
|
+
return sessions.get(id);
|
|
104019
|
+
}
|
|
104020
|
+
function appendUploadChunk(id, offset, bytes) {
|
|
104021
|
+
const s = sessions.get(id);
|
|
104022
|
+
if (!s)
|
|
104023
|
+
return { ok: false, reason: "not_found" };
|
|
104024
|
+
if (offset !== s.received)
|
|
104025
|
+
return { ok: false, reason: "bad_offset" };
|
|
104026
|
+
if (s.received + bytes.byteLength > s.size)
|
|
104027
|
+
return { ok: false, reason: "too_large" };
|
|
104028
|
+
appendFileSync(s.tmpPath, bytes);
|
|
104029
|
+
s.received += bytes.byteLength;
|
|
104030
|
+
return { ok: true, received: s.received };
|
|
104031
|
+
}
|
|
104032
|
+
function removeUploadSession(id) {
|
|
104033
|
+
const s = sessions.get(id);
|
|
104034
|
+
if (!s)
|
|
104035
|
+
return;
|
|
104036
|
+
sessions.delete(id);
|
|
104037
|
+
try {
|
|
104038
|
+
s.abort.abort();
|
|
104039
|
+
} catch {}
|
|
104040
|
+
try {
|
|
104041
|
+
rmSync3(s.tmpDir, { recursive: true, force: true });
|
|
104042
|
+
} catch {}
|
|
104043
|
+
}
|
|
104044
|
+
var transferGcTimer = setInterval(() => sweepStale(Date.now()), 5 * 60000);
|
|
104045
|
+
transferGcTimer.unref?.();
|
|
104046
|
+
var ORPHAN_PREFIXES = ["tmex-up-", "tmex-dl-"];
|
|
104047
|
+
var ORPHAN_MAX_AGE_MS = 60 * 60000;
|
|
104048
|
+
function sweepOrphanTransferTemps() {
|
|
104049
|
+
const base = tmpdir3();
|
|
104050
|
+
let entries;
|
|
104051
|
+
try {
|
|
104052
|
+
entries = readdirSync(base);
|
|
104053
|
+
} catch {
|
|
104054
|
+
return;
|
|
104055
|
+
}
|
|
104056
|
+
const now2 = Date.now();
|
|
104057
|
+
for (const name24 of entries) {
|
|
104058
|
+
if (!ORPHAN_PREFIXES.some((p) => name24.startsWith(p)))
|
|
104059
|
+
continue;
|
|
104060
|
+
const full = join6(base, name24);
|
|
104061
|
+
try {
|
|
104062
|
+
if (now2 - statSync2(full).mtimeMs > ORPHAN_MAX_AGE_MS) {
|
|
104063
|
+
rmSync3(full, { recursive: true, force: true });
|
|
104064
|
+
}
|
|
104065
|
+
} catch {}
|
|
104066
|
+
}
|
|
104067
|
+
}
|
|
103670
104068
|
|
|
103671
104069
|
// ../../apps/gateway/src/api/files.ts
|
|
104070
|
+
var UPLOAD_CHUNK_SIZE = 8 * 1024 * 1024;
|
|
103672
104071
|
function json4(data, status = 200, headers = {}) {
|
|
103673
104072
|
return new Response(JSON.stringify(data), {
|
|
103674
104073
|
status,
|
|
@@ -103832,6 +104231,223 @@ async function handleRaw(url2) {
|
|
|
103832
104231
|
}
|
|
103833
104232
|
return new Response(result.data.data, { status: 200, headers });
|
|
103834
104233
|
}
|
|
104234
|
+
async function handleUploadInit(req) {
|
|
104235
|
+
let body;
|
|
104236
|
+
try {
|
|
104237
|
+
body = await req.json();
|
|
104238
|
+
} catch {
|
|
104239
|
+
return json4({ error: t2("apiError.invalidRequest") }, 400);
|
|
104240
|
+
}
|
|
104241
|
+
const rootId = typeof body.rootId === "string" ? body.rootId : "";
|
|
104242
|
+
const destDir = typeof body.path === "string" ? body.path : "";
|
|
104243
|
+
const rawName = typeof body.name === "string" ? body.name : "";
|
|
104244
|
+
const size = typeof body.size === "number" && Number.isFinite(body.size) ? body.size : -1;
|
|
104245
|
+
if (!rootId || !destDir || !rawName || size < 0) {
|
|
104246
|
+
return json4({ error: t2("apiError.invalidRequest") }, 400);
|
|
104247
|
+
}
|
|
104248
|
+
const name24 = sanitizeUploadName(rawName);
|
|
104249
|
+
if (!name24)
|
|
104250
|
+
return codeError("invalid");
|
|
104251
|
+
if (size > config.transferMaxBytes)
|
|
104252
|
+
return codeError("too_large");
|
|
104253
|
+
const stat = await statFile(rootId, destDir);
|
|
104254
|
+
if (!stat.ok)
|
|
104255
|
+
return codeError(stat.code, stat.detail);
|
|
104256
|
+
if (stat.data.type !== "dir")
|
|
104257
|
+
return codeError("not_a_directory");
|
|
104258
|
+
const session = createUploadSession({ rootId, destDir, name: name24, size });
|
|
104259
|
+
return json4({ uploadId: session.id, chunkSize: UPLOAD_CHUNK_SIZE });
|
|
104260
|
+
}
|
|
104261
|
+
async function handleUploadChunk(req, id, url2) {
|
|
104262
|
+
const offset = Number.parseInt(url2.searchParams.get("offset") ?? "", 10);
|
|
104263
|
+
if (Number.isNaN(offset) || offset < 0)
|
|
104264
|
+
return json4({ error: t2("apiError.invalidRequest") }, 400);
|
|
104265
|
+
const bytes = new Uint8Array(await req.arrayBuffer());
|
|
104266
|
+
const res = appendUploadChunk(id, offset, bytes);
|
|
104267
|
+
if (!res.ok) {
|
|
104268
|
+
if (res.reason === "not_found")
|
|
104269
|
+
return codeError("not_found");
|
|
104270
|
+
if (res.reason === "too_large")
|
|
104271
|
+
return codeError("too_large");
|
|
104272
|
+
return json4({ error: t2("apiError.invalidRequest") }, 409);
|
|
104273
|
+
}
|
|
104274
|
+
return json4({ received: res.received });
|
|
104275
|
+
}
|
|
104276
|
+
function handleUploadCommit(id) {
|
|
104277
|
+
const session = getUploadSession(id);
|
|
104278
|
+
if (!session)
|
|
104279
|
+
return codeError("not_found");
|
|
104280
|
+
if (session.received !== session.size)
|
|
104281
|
+
return codeError("invalid", "incomplete upload");
|
|
104282
|
+
session.committing = true;
|
|
104283
|
+
const encoder3 = new TextEncoder;
|
|
104284
|
+
const stream = new ReadableStream({
|
|
104285
|
+
start(controller) {
|
|
104286
|
+
const emit = (obj) => {
|
|
104287
|
+
try {
|
|
104288
|
+
controller.enqueue(encoder3.encode(`${JSON.stringify(obj)}
|
|
104289
|
+
`));
|
|
104290
|
+
} catch {}
|
|
104291
|
+
};
|
|
104292
|
+
pushFileToDevice(session.rootId, session.destDir, session.tmpPath, session.name, {
|
|
104293
|
+
signal: session.abort.signal,
|
|
104294
|
+
onProgress: (p) => emit({ type: "progress", ...p })
|
|
104295
|
+
}).then((res) => {
|
|
104296
|
+
if (res.ok)
|
|
104297
|
+
emit({ type: "done", uploaded: res.data.uploaded });
|
|
104298
|
+
else
|
|
104299
|
+
emit({ type: "error", code: res.code, detail: res.detail });
|
|
104300
|
+
}).catch((e) => emit({ type: "error", code: "unknown", detail: String(e) })).finally(() => {
|
|
104301
|
+
try {
|
|
104302
|
+
controller.close();
|
|
104303
|
+
} catch {}
|
|
104304
|
+
removeUploadSession(id);
|
|
104305
|
+
});
|
|
104306
|
+
},
|
|
104307
|
+
cancel() {
|
|
104308
|
+
removeUploadSession(id);
|
|
104309
|
+
}
|
|
104310
|
+
});
|
|
104311
|
+
return new Response(stream, {
|
|
104312
|
+
status: 200,
|
|
104313
|
+
headers: { "Content-Type": "application/x-ndjson; charset=utf-8", "Cache-Control": "no-store" }
|
|
104314
|
+
});
|
|
104315
|
+
}
|
|
104316
|
+
function handleUploadCancel(id) {
|
|
104317
|
+
removeUploadSession(id);
|
|
104318
|
+
return json4({ success: true });
|
|
104319
|
+
}
|
|
104320
|
+
function attachmentHeaders(name24, mime, size) {
|
|
104321
|
+
const encoded = encodeURIComponent(name24);
|
|
104322
|
+
const ascii = name24.replace(/["\\\r\n]/g, "_");
|
|
104323
|
+
return {
|
|
104324
|
+
"Content-Type": mime ?? "application/octet-stream",
|
|
104325
|
+
"Content-Length": String(size),
|
|
104326
|
+
"Content-Disposition": `attachment; filename="${ascii}"; filename*=UTF-8''${encoded}`,
|
|
104327
|
+
"Cache-Control": "no-store"
|
|
104328
|
+
};
|
|
104329
|
+
}
|
|
104330
|
+
function streamTempFile(tmpPath, cleanupAfter) {
|
|
104331
|
+
let reader;
|
|
104332
|
+
try {
|
|
104333
|
+
reader = Bun.file(tmpPath).stream().getReader();
|
|
104334
|
+
} catch {
|
|
104335
|
+
cleanupAfter();
|
|
104336
|
+
return null;
|
|
104337
|
+
}
|
|
104338
|
+
return new ReadableStream({
|
|
104339
|
+
async pull(controller) {
|
|
104340
|
+
try {
|
|
104341
|
+
const { done, value } = await reader.read();
|
|
104342
|
+
if (done) {
|
|
104343
|
+
controller.close();
|
|
104344
|
+
cleanupAfter();
|
|
104345
|
+
return;
|
|
104346
|
+
}
|
|
104347
|
+
controller.enqueue(value);
|
|
104348
|
+
} catch (e) {
|
|
104349
|
+
controller.error(e);
|
|
104350
|
+
cleanupAfter();
|
|
104351
|
+
}
|
|
104352
|
+
},
|
|
104353
|
+
cancel() {
|
|
104354
|
+
reader.cancel();
|
|
104355
|
+
cleanupAfter();
|
|
104356
|
+
}
|
|
104357
|
+
});
|
|
104358
|
+
}
|
|
104359
|
+
function handleDownloadPrepare(req) {
|
|
104360
|
+
let abort = null;
|
|
104361
|
+
const encoder3 = new TextEncoder;
|
|
104362
|
+
const stream = new ReadableStream({
|
|
104363
|
+
async start(controller) {
|
|
104364
|
+
const emit = (obj) => {
|
|
104365
|
+
try {
|
|
104366
|
+
controller.enqueue(encoder3.encode(`${JSON.stringify(obj)}
|
|
104367
|
+
`));
|
|
104368
|
+
} catch {}
|
|
104369
|
+
};
|
|
104370
|
+
const close = () => {
|
|
104371
|
+
try {
|
|
104372
|
+
controller.close();
|
|
104373
|
+
} catch {}
|
|
104374
|
+
};
|
|
104375
|
+
let body;
|
|
104376
|
+
try {
|
|
104377
|
+
body = await req.json();
|
|
104378
|
+
} catch {
|
|
104379
|
+
emit({ type: "error", code: "invalid" });
|
|
104380
|
+
close();
|
|
104381
|
+
return;
|
|
104382
|
+
}
|
|
104383
|
+
const rootId = typeof body.rootId === "string" ? body.rootId : "";
|
|
104384
|
+
const path = typeof body.path === "string" ? body.path : "";
|
|
104385
|
+
if (!rootId || !path) {
|
|
104386
|
+
emit({ type: "error", code: "invalid" });
|
|
104387
|
+
close();
|
|
104388
|
+
return;
|
|
104389
|
+
}
|
|
104390
|
+
abort = new AbortController;
|
|
104391
|
+
const result = await pullFileFromDevice(rootId, path, {
|
|
104392
|
+
signal: abort.signal,
|
|
104393
|
+
onProgress: (p) => emit({ type: "progress", ...p })
|
|
104394
|
+
});
|
|
104395
|
+
if (result.ok) {
|
|
104396
|
+
const s = createDownloadSession({
|
|
104397
|
+
tmpPath: result.data.tmpPath,
|
|
104398
|
+
size: result.data.size,
|
|
104399
|
+
name: result.data.name,
|
|
104400
|
+
mime: result.data.mime,
|
|
104401
|
+
cleanup: result.data.cleanup
|
|
104402
|
+
});
|
|
104403
|
+
emit({ type: "done", downloadId: s.id, size: s.size, name: s.name });
|
|
104404
|
+
} else {
|
|
104405
|
+
emit({ type: "error", code: result.code, detail: result.detail });
|
|
104406
|
+
}
|
|
104407
|
+
close();
|
|
104408
|
+
},
|
|
104409
|
+
cancel() {
|
|
104410
|
+
abort?.abort();
|
|
104411
|
+
}
|
|
104412
|
+
});
|
|
104413
|
+
return new Response(stream, {
|
|
104414
|
+
status: 200,
|
|
104415
|
+
headers: { "Content-Type": "application/x-ndjson; charset=utf-8", "Cache-Control": "no-store" }
|
|
104416
|
+
});
|
|
104417
|
+
}
|
|
104418
|
+
function handleDownloadContent(id) {
|
|
104419
|
+
const session = getDownloadSession(id);
|
|
104420
|
+
if (!session)
|
|
104421
|
+
return codeError("not_found");
|
|
104422
|
+
const body = streamTempFile(session.tmpPath, () => removeDownloadSession(id));
|
|
104423
|
+
if (!body)
|
|
104424
|
+
return codeError("unknown");
|
|
104425
|
+
return new Response(body, {
|
|
104426
|
+
status: 200,
|
|
104427
|
+
headers: attachmentHeaders(session.name, session.mime, session.size)
|
|
104428
|
+
});
|
|
104429
|
+
}
|
|
104430
|
+
function handleDownloadCancel(id) {
|
|
104431
|
+
removeDownloadSession(id);
|
|
104432
|
+
return json4({ success: true });
|
|
104433
|
+
}
|
|
104434
|
+
async function handleDownload(req, url2) {
|
|
104435
|
+
const rootId = url2.searchParams.get("rootId");
|
|
104436
|
+
const path = url2.searchParams.get("path");
|
|
104437
|
+
if (!rootId || !path)
|
|
104438
|
+
return json4({ error: t2("apiError.invalidRequest") }, 400);
|
|
104439
|
+
const result = await pullFileFromDevice(rootId, path, {
|
|
104440
|
+
signal: req.signal,
|
|
104441
|
+
onProgress: () => {}
|
|
104442
|
+
});
|
|
104443
|
+
if (!result.ok)
|
|
104444
|
+
return codeError(result.code, result.detail);
|
|
104445
|
+
const { tmpPath, size, name: name24, mime, cleanup } = result.data;
|
|
104446
|
+
const body = streamTempFile(tmpPath, cleanup);
|
|
104447
|
+
if (!body)
|
|
104448
|
+
return codeError("unknown");
|
|
104449
|
+
return new Response(body, { status: 200, headers: attachmentHeaders(name24, mime, size) });
|
|
104450
|
+
}
|
|
103835
104451
|
function handleFilesApiRequest(req, path) {
|
|
103836
104452
|
const url2 = new URL(req.url);
|
|
103837
104453
|
if (path === "/api/files/roots" && req.method === "GET")
|
|
@@ -103852,6 +104468,32 @@ function handleFilesApiRequest(req, path) {
|
|
|
103852
104468
|
return handleStat(url2);
|
|
103853
104469
|
if (path === "/api/files/raw" && req.method === "GET")
|
|
103854
104470
|
return handleRaw(url2);
|
|
104471
|
+
if (path === "/api/files/download" && req.method === "GET")
|
|
104472
|
+
return handleDownload(req, url2);
|
|
104473
|
+
if (path === "/api/files/download/prepare" && req.method === "POST") {
|
|
104474
|
+
return handleDownloadPrepare(req);
|
|
104475
|
+
}
|
|
104476
|
+
const dlContentMatch = path.match(/^\/api\/files\/download\/([^/]+)\/content$/);
|
|
104477
|
+
if (dlContentMatch && req.method === "GET") {
|
|
104478
|
+
return handleDownloadContent(decodeURIComponent(dlContentMatch[1]));
|
|
104479
|
+
}
|
|
104480
|
+
const dlCancelMatch = path.match(/^\/api\/files\/download\/([^/]+)$/);
|
|
104481
|
+
if (dlCancelMatch && req.method === "DELETE") {
|
|
104482
|
+
return handleDownloadCancel(decodeURIComponent(dlCancelMatch[1]));
|
|
104483
|
+
}
|
|
104484
|
+
if (path === "/api/files/upload/init" && req.method === "POST")
|
|
104485
|
+
return handleUploadInit(req);
|
|
104486
|
+
const commitMatch = path.match(/^\/api\/files\/upload\/([^/]+)\/commit$/);
|
|
104487
|
+
if (commitMatch && req.method === "POST") {
|
|
104488
|
+
return handleUploadCommit(decodeURIComponent(commitMatch[1]));
|
|
104489
|
+
}
|
|
104490
|
+
const uploadMatch = path.match(/^\/api\/files\/upload\/([^/]+)$/);
|
|
104491
|
+
if (uploadMatch && req.method === "PUT") {
|
|
104492
|
+
return handleUploadChunk(req, decodeURIComponent(uploadMatch[1]), url2);
|
|
104493
|
+
}
|
|
104494
|
+
if (uploadMatch && req.method === "DELETE") {
|
|
104495
|
+
return handleUploadCancel(decodeURIComponent(uploadMatch[1]));
|
|
104496
|
+
}
|
|
103855
104497
|
return;
|
|
103856
104498
|
}
|
|
103857
104499
|
|
|
@@ -104208,8 +104850,8 @@ function getBaseVersion() {
|
|
|
104208
104850
|
if (cachedBase !== undefined)
|
|
104209
104851
|
return cachedBase;
|
|
104210
104852
|
let base = null;
|
|
104211
|
-
if ("0.
|
|
104212
|
-
base = "0.
|
|
104853
|
+
if ("0.12.0") {
|
|
104854
|
+
base = "0.12.0";
|
|
104213
104855
|
}
|
|
104214
104856
|
if (!base && config.isProd) {
|
|
104215
104857
|
base = readInstallMeta()?.cliVersion ?? null;
|
|
@@ -104300,8 +104942,8 @@ async function fetchChangelog(version3) {
|
|
|
104300
104942
|
import { spawn } from "child_process";
|
|
104301
104943
|
import { closeSync, existsSync as existsSync6, openSync } from "fs";
|
|
104302
104944
|
import { mkdtemp, rm, writeFile } from "fs/promises";
|
|
104303
|
-
import { tmpdir as
|
|
104304
|
-
import { join as
|
|
104945
|
+
import { tmpdir as tmpdir4 } from "os";
|
|
104946
|
+
import { join as join7 } from "path";
|
|
104305
104947
|
class UpgradeController {
|
|
104306
104948
|
state = "idle";
|
|
104307
104949
|
targetVersion = null;
|
|
@@ -104337,12 +104979,12 @@ class UpgradeController {
|
|
|
104337
104979
|
if (!installDir) {
|
|
104338
104980
|
throw new Error("install directory could not be resolved");
|
|
104339
104981
|
}
|
|
104340
|
-
stageDir = await mkdtemp(
|
|
104341
|
-
cacheDir = await mkdtemp(
|
|
104342
|
-
await writeFile(
|
|
104982
|
+
stageDir = await mkdtemp(join7(tmpdir4(), "tmex-upg-"));
|
|
104983
|
+
cacheDir = await mkdtemp(join7(tmpdir4(), "tmex-upg-cache-"));
|
|
104984
|
+
await writeFile(join7(stageDir, "package.json"), `${JSON.stringify({ name: "tmex-upgrade-stage", private: true })}
|
|
104343
104985
|
`);
|
|
104344
104986
|
await this.runBunAdd(stageDir, cacheDir, version3);
|
|
104345
|
-
const binPath =
|
|
104987
|
+
const binPath = join7(stageDir, "node_modules", "tmex-cli", "bin", "tmex.js");
|
|
104346
104988
|
if (!existsSync6(binPath)) {
|
|
104347
104989
|
throw new Error(`downloaded tmex-cli binary not found at ${binPath}`);
|
|
104348
104990
|
}
|
|
@@ -104377,7 +105019,7 @@ class UpgradeController {
|
|
|
104377
105019
|
spawnUpgrade(binPath, installDir, version3) {
|
|
104378
105020
|
let logFd = null;
|
|
104379
105021
|
try {
|
|
104380
|
-
logFd = openSync(
|
|
105022
|
+
logFd = openSync(join7(installDir, "upgrade.log"), "a");
|
|
104381
105023
|
} catch {
|
|
104382
105024
|
logFd = null;
|
|
104383
105025
|
}
|
|
@@ -104413,7 +105055,8 @@ function getSystemInfo() {
|
|
|
104413
105055
|
installedViaCli: install.installedViaCli,
|
|
104414
105056
|
deployment: install.deployment,
|
|
104415
105057
|
canSelfUpdate,
|
|
104416
|
-
serviceName: install.serviceName
|
|
105058
|
+
serviceName: install.serviceName,
|
|
105059
|
+
transferMaxBytes: config.transferMaxBytes
|
|
104417
105060
|
};
|
|
104418
105061
|
}
|
|
104419
105062
|
|
|
@@ -107949,6 +108592,7 @@ async function createGatewayRuntime(options = {}) {
|
|
|
107949
108592
|
}
|
|
107950
108593
|
runtimeController.reset();
|
|
107951
108594
|
primeLocalShellPath();
|
|
108595
|
+
sweepOrphanTransferTemps();
|
|
107952
108596
|
const wsServer = new WebSocketServer;
|
|
107953
108597
|
connectionAlertNotifier.setBroadcaster((deviceId, payload) => {
|
|
107954
108598
|
wsServer.broadcastDeviceError(deviceId, payload);
|
|
@@ -108274,7 +108918,7 @@ async function serveFrontend(req, staticRoot) {
|
|
|
108274
108918
|
if (!existsSync8(requestedPath) && extname2(url2.pathname) !== "") {
|
|
108275
108919
|
return new Response(t3("runtime.notFound"), { status: 404 });
|
|
108276
108920
|
}
|
|
108277
|
-
const indexPath =
|
|
108921
|
+
const indexPath = join8(staticRoot, "index.html");
|
|
108278
108922
|
const targetPath = existsSync8(requestedPath) ? requestedPath : indexPath;
|
|
108279
108923
|
if (!existsSync8(targetPath)) {
|
|
108280
108924
|
return new Response(t3("runtime.frontendMissing"), { status: 500 });
|