meshy-node 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/README.md +1 -1
- package/dashboard/assets/DashboardPage-mQpgVZSz.js +124 -0
- package/dashboard/assets/{DashboardShared-BSDgKTOF.js → DashboardShared-CJtOr7QZ.js} +4 -4
- package/dashboard/assets/{DiffTab-_2QRJdG0.js → DiffTab-Bi7Lu7wa.js} +2 -2
- package/dashboard/assets/{FilesTab-_pFba0dN.js → FilesTab-CwM0TYJk.js} +2 -2
- package/dashboard/assets/{PreviewTab-C5UehUZ1.js → PreviewTab-ti-mR-KD.js} +2 -2
- package/dashboard/assets/{SharedConversationPage-e35GHbGI.js → SharedConversationPage-CUG9tnp-.js} +3 -3
- package/dashboard/assets/{file-3EwPAA-4.js → file-BTuUAaOs.js} +1 -1
- package/dashboard/assets/folder-BbOC2arM.js +6 -0
- package/dashboard/assets/index-BzzXPy7Y.css +1 -0
- package/dashboard/assets/index-Cba_59ol.js +291 -0
- package/dashboard/assets/{input-DMp80MWI.js → input-DXbjJpeh.js} +1 -1
- package/dashboard/index.html +2 -2
- package/main.cjs +269 -37
- package/package.json +1 -1
- package/runtime-metadata.json +5 -5
- package/dashboard/assets/DashboardPage-BUtwv0kD.js +0 -124
- package/dashboard/assets/folder-B6d9_x4J.js +0 -11
- package/dashboard/assets/index-6tOxJBZf.js +0 -276
- package/dashboard/assets/index-Ch6zIZ6Y.css +0 -1
package/dashboard/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>Meshy Dashboard</title>
|
|
7
7
|
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🕸</text></svg>" />
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-Cba_59ol.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BzzXPy7Y.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
package/main.cjs
CHANGED
|
@@ -33089,6 +33089,22 @@ function parseNodeSettingsSnapshot(value) {
|
|
|
33089
33089
|
}
|
|
33090
33090
|
return clone(value);
|
|
33091
33091
|
}
|
|
33092
|
+
function parseDevTunnelHealth(value) {
|
|
33093
|
+
if (!isPlainObject(value)) {
|
|
33094
|
+
return void 0;
|
|
33095
|
+
}
|
|
33096
|
+
if (value.status !== "healthy" && value.status !== "failed" || typeof value.checkedAt !== "number" || !Number.isFinite(value.checkedAt)) {
|
|
33097
|
+
return void 0;
|
|
33098
|
+
}
|
|
33099
|
+
return {
|
|
33100
|
+
status: value.status,
|
|
33101
|
+
checkedAt: value.checkedAt,
|
|
33102
|
+
endpoint: typeof value.endpoint === "string" ? value.endpoint : void 0,
|
|
33103
|
+
reason: typeof value.reason === "string" ? value.reason : void 0,
|
|
33104
|
+
statusCode: typeof value.statusCode === "number" && Number.isFinite(value.statusCode) ? value.statusCode : void 0,
|
|
33105
|
+
consecutiveFailures: typeof value.consecutiveFailures === "number" && Number.isFinite(value.consecutiveFailures) ? value.consecutiveFailures : void 0
|
|
33106
|
+
};
|
|
33107
|
+
}
|
|
33092
33108
|
function isClusterInfo(value) {
|
|
33093
33109
|
return isPlainObject(value) && typeof value.clusterId === "string" && typeof value.createdAt === "number" && Number.isFinite(value.createdAt);
|
|
33094
33110
|
}
|
|
@@ -33112,6 +33128,7 @@ function parseNodeInfo(value) {
|
|
|
33112
33128
|
lastHeartbeat: value.lastHeartbeat,
|
|
33113
33129
|
transportType: typeof value.transportType === "string" ? value.transportType : void 0,
|
|
33114
33130
|
devtunnelEndpoint: typeof value.devtunnelEndpoint === "string" ? value.devtunnelEndpoint : void 0,
|
|
33131
|
+
devtunnelHealth: parseDevTunnelHealth(value.devtunnelHealth),
|
|
33115
33132
|
dashboardOrigin: typeof value.dashboardOrigin === "string" ? value.dashboardOrigin : void 0,
|
|
33116
33133
|
workDir: typeof value.workDir === "string" ? value.workDir : void 0,
|
|
33117
33134
|
workDirFolders: parseStringArray(value.workDirFolders),
|
|
@@ -33515,6 +33532,24 @@ var NodeRegistry = class {
|
|
|
33515
33532
|
}
|
|
33516
33533
|
}
|
|
33517
33534
|
}
|
|
33535
|
+
updateDevTunnelHealth(id, devtunnelHealth) {
|
|
33536
|
+
const node = this.nodes.get(id);
|
|
33537
|
+
if (node) {
|
|
33538
|
+
if (devtunnelHealth) {
|
|
33539
|
+
node.devtunnelHealth = { ...devtunnelHealth };
|
|
33540
|
+
} else {
|
|
33541
|
+
delete node.devtunnelHealth;
|
|
33542
|
+
}
|
|
33543
|
+
this.store.upsertNode(node);
|
|
33544
|
+
}
|
|
33545
|
+
if (this.selfNode && this.selfNode.id === id) {
|
|
33546
|
+
if (devtunnelHealth) {
|
|
33547
|
+
this.selfNode.devtunnelHealth = { ...devtunnelHealth };
|
|
33548
|
+
} else {
|
|
33549
|
+
delete this.selfNode.devtunnelHealth;
|
|
33550
|
+
}
|
|
33551
|
+
}
|
|
33552
|
+
}
|
|
33518
33553
|
updateDashboardOrigin(id, dashboardOrigin) {
|
|
33519
33554
|
const node = this.nodes.get(id);
|
|
33520
33555
|
if (node) {
|
|
@@ -34689,17 +34724,9 @@ var HeartbeatMonitor = class {
|
|
|
34689
34724
|
running = false;
|
|
34690
34725
|
followerMissedMap = /* @__PURE__ */ new Map();
|
|
34691
34726
|
followerPushReachableMap = /* @__PURE__ */ new Map();
|
|
34692
|
-
|
|
34693
|
-
* Tracks whether a push-heartbeat has EVER succeeded for a follower.
|
|
34694
|
-
* If push has never worked, the follower is on an unreachable network
|
|
34695
|
-
* and should not be marked offline based on push failures alone.
|
|
34696
|
-
*/
|
|
34727
|
+
// Tracks whether push-heartbeat has ever succeeded for a follower.
|
|
34697
34728
|
followerEverReachedMap = /* @__PURE__ */ new Map();
|
|
34698
|
-
|
|
34699
|
-
* Last known leader endpoint — preserved across clearLeader() so
|
|
34700
|
-
* follower keepalives can still attempt to reach the leader even
|
|
34701
|
-
* after the follower timer fires.
|
|
34702
|
-
*/
|
|
34729
|
+
// Preserved across clearLeader() so follower keepalives can still reach the leader.
|
|
34703
34730
|
lastKnownLeaderEndpoint = null;
|
|
34704
34731
|
getQueuedMessages;
|
|
34705
34732
|
messageQueue;
|
|
@@ -34856,6 +34883,7 @@ var HeartbeatMonitor = class {
|
|
|
34856
34883
|
});
|
|
34857
34884
|
}
|
|
34858
34885
|
this.applyReportedDevTunnelState(node.id, result.devtunnelEnabled, result.devtunnelEndpoint);
|
|
34886
|
+
this.nodeRegistry.updateDevTunnelHealth(node.id, result.devtunnelEnabled === false ? void 0 : result.devtunnelHealth);
|
|
34859
34887
|
this.nodeRegistry.updateDashboardOrigin(node.id, result.dashboardOrigin);
|
|
34860
34888
|
if (result.workDirFolders) {
|
|
34861
34889
|
this.nodeRegistry.updateFolders(node.id, result.workDirFolders);
|
|
@@ -34922,6 +34950,7 @@ var HeartbeatMonitor = class {
|
|
|
34922
34950
|
supportedAgents: self2.supportedAgents,
|
|
34923
34951
|
devtunnelEnabled: self2.devtunnelEndpoint !== void 0,
|
|
34924
34952
|
devtunnelEndpoint: self2.devtunnelEndpoint,
|
|
34953
|
+
devtunnelHealth: self2.devtunnelHealth,
|
|
34925
34954
|
dashboardOrigin: self2.dashboardOrigin,
|
|
34926
34955
|
workDirFolders: self2.workDir ? listWorkDirFolders(self2.workDir) : void 0,
|
|
34927
34956
|
settingsSnapshot: this.resolveCurrentSettingsSnapshot()
|
|
@@ -34942,6 +34971,7 @@ var HeartbeatMonitor = class {
|
|
|
34942
34971
|
workDir,
|
|
34943
34972
|
devtunnelEnabled,
|
|
34944
34973
|
devtunnelEndpoint,
|
|
34974
|
+
devtunnelHealth,
|
|
34945
34975
|
dashboardOrigin,
|
|
34946
34976
|
workDirFolders,
|
|
34947
34977
|
settingsSnapshot
|
|
@@ -34969,6 +34999,7 @@ var HeartbeatMonitor = class {
|
|
|
34969
34999
|
...transportType ? { transportType } : {},
|
|
34970
35000
|
...workDir ? { workDir } : {},
|
|
34971
35001
|
...devtunnelEnabled && devtunnelEndpoint ? { devtunnelEndpoint } : {},
|
|
35002
|
+
...devtunnelHealth ? { devtunnelHealth } : {},
|
|
34972
35003
|
...dashboardOrigin ? { dashboardOrigin } : {},
|
|
34973
35004
|
...workDirFolders ? { workDirFolders } : {},
|
|
34974
35005
|
...settingsSnapshot ? { settingsSnapshot } : {}
|
|
@@ -35004,6 +35035,7 @@ var HeartbeatMonitor = class {
|
|
|
35004
35035
|
}
|
|
35005
35036
|
this.nodeRegistry.updateLoad(nodeId, load);
|
|
35006
35037
|
this.applyReportedDevTunnelState(nodeId, devtunnelEnabled, devtunnelEndpoint);
|
|
35038
|
+
this.nodeRegistry.updateDevTunnelHealth(nodeId, devtunnelEnabled === false ? void 0 : devtunnelHealth);
|
|
35007
35039
|
this.nodeRegistry.updateDashboardOrigin(nodeId, dashboardOrigin);
|
|
35008
35040
|
if (workDirFolders) {
|
|
35009
35041
|
this.nodeRegistry.updateFolders(nodeId, workDirFolders);
|
|
@@ -35053,6 +35085,7 @@ var HeartbeatMonitor = class {
|
|
|
35053
35085
|
workDir: self2.workDir,
|
|
35054
35086
|
devtunnelEnabled: self2.devtunnelEndpoint !== void 0,
|
|
35055
35087
|
devtunnelEndpoint: self2.devtunnelEndpoint,
|
|
35088
|
+
devtunnelHealth: self2.devtunnelHealth,
|
|
35056
35089
|
dashboardOrigin: self2.dashboardOrigin,
|
|
35057
35090
|
workDirFolders: self2.workDir ? listWorkDirFolders(self2.workDir) : void 0,
|
|
35058
35091
|
settingsSnapshot
|
|
@@ -37760,6 +37793,9 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
37760
37793
|
if (self2.devtunnelEndpoint) {
|
|
37761
37794
|
joinBody.devtunnelEndpoint = self2.devtunnelEndpoint;
|
|
37762
37795
|
}
|
|
37796
|
+
if (self2.devtunnelHealth) {
|
|
37797
|
+
joinBody.devtunnelHealth = self2.devtunnelHealth;
|
|
37798
|
+
}
|
|
37763
37799
|
if (self2.dashboardOrigin) {
|
|
37764
37800
|
joinBody.dashboardOrigin = self2.dashboardOrigin;
|
|
37765
37801
|
}
|
|
@@ -38093,6 +38129,7 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
38093
38129
|
workDir: currentSelf.workDir,
|
|
38094
38130
|
workDirFolders: listWorkDirFolders(this.getWorkDir()),
|
|
38095
38131
|
...currentSelf.devtunnelEndpoint ? { devtunnelEndpoint: currentSelf.devtunnelEndpoint } : {},
|
|
38132
|
+
...currentSelf.devtunnelHealth ? { devtunnelHealth: currentSelf.devtunnelHealth } : {},
|
|
38096
38133
|
...currentSelf.dashboardOrigin ? { dashboardOrigin: currentSelf.dashboardOrigin } : {},
|
|
38097
38134
|
...currentSelf.settingsSnapshot ? { settingsSnapshot: currentSelf.settingsSnapshot } : {}
|
|
38098
38135
|
};
|
|
@@ -42945,6 +42982,14 @@ var NodeSettingsSnapshotSchema = external_exports.object({
|
|
|
42945
42982
|
api: SystemPackageInfoSchema.optional()
|
|
42946
42983
|
}).optional()
|
|
42947
42984
|
});
|
|
42985
|
+
var DevTunnelHealthSchema = external_exports.object({
|
|
42986
|
+
status: external_exports.enum(["healthy", "failed"]),
|
|
42987
|
+
checkedAt: external_exports.number(),
|
|
42988
|
+
endpoint: external_exports.string().optional(),
|
|
42989
|
+
reason: external_exports.string().optional(),
|
|
42990
|
+
statusCode: external_exports.number().optional(),
|
|
42991
|
+
consecutiveFailures: external_exports.number().optional()
|
|
42992
|
+
});
|
|
42948
42993
|
|
|
42949
42994
|
// ../../packages/api/src/schemas/cluster.ts
|
|
42950
42995
|
var NodeInfoSchema = external_exports.object({
|
|
@@ -42959,6 +43004,7 @@ var NodeInfoSchema = external_exports.object({
|
|
|
42959
43004
|
lastHeartbeat: external_exports.number(),
|
|
42960
43005
|
transportType: external_exports.string().optional(),
|
|
42961
43006
|
devtunnelEndpoint: external_exports.string().optional(),
|
|
43007
|
+
devtunnelHealth: DevTunnelHealthSchema.optional(),
|
|
42962
43008
|
dashboardOrigin: external_exports.string().optional(),
|
|
42963
43009
|
workDir: external_exports.string().optional(),
|
|
42964
43010
|
workDirFolders: external_exports.array(external_exports.string()).optional(),
|
|
@@ -42995,6 +43041,7 @@ var JoinClusterBody = external_exports.object({
|
|
|
42995
43041
|
workDir: external_exports.string().optional(),
|
|
42996
43042
|
workDirFolders: external_exports.array(external_exports.string()).optional(),
|
|
42997
43043
|
devtunnelEndpoint: external_exports.string().url().optional(),
|
|
43044
|
+
devtunnelHealth: DevTunnelHealthSchema.optional(),
|
|
42998
43045
|
dashboardOrigin: external_exports.string().url().optional(),
|
|
42999
43046
|
settingsSnapshot: NodeSettingsSnapshotSchema.optional(),
|
|
43000
43047
|
tasks: external_exports.array(JoinTaskSchema).default([])
|
|
@@ -43039,6 +43086,7 @@ var NodeInfoSchema2 = external_exports.object({
|
|
|
43039
43086
|
lastHeartbeat: external_exports.number(),
|
|
43040
43087
|
transportType: external_exports.string().optional(),
|
|
43041
43088
|
devtunnelEndpoint: external_exports.string().optional(),
|
|
43089
|
+
devtunnelHealth: DevTunnelHealthSchema.optional(),
|
|
43042
43090
|
dashboardOrigin: external_exports.string().optional(),
|
|
43043
43091
|
workDir: external_exports.string().optional(),
|
|
43044
43092
|
workDirFolders: external_exports.array(external_exports.string()).optional(),
|
|
@@ -50729,6 +50777,82 @@ function buildRuntimeMetadata(storagePath) {
|
|
|
50729
50777
|
};
|
|
50730
50778
|
}
|
|
50731
50779
|
|
|
50780
|
+
// src/bootstrap/tunnel-health.ts
|
|
50781
|
+
var DEFAULT_TUNNEL_REACHABILITY_INTERVAL_MS = 6e4;
|
|
50782
|
+
var DEFAULT_TUNNEL_REACHABILITY_TIMEOUT_MS = 5e3;
|
|
50783
|
+
var DEFAULT_TUNNEL_RESTART_FAILURE_THRESHOLD = 2;
|
|
50784
|
+
function createTunnelReachabilityMonitor(options = {}) {
|
|
50785
|
+
const failureThreshold = options.failureThreshold ?? DEFAULT_TUNNEL_RESTART_FAILURE_THRESHOLD;
|
|
50786
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
50787
|
+
const healthPath = options.healthPath ?? "/api/system/health";
|
|
50788
|
+
const intervalMs = options.intervalMs ?? DEFAULT_TUNNEL_REACHABILITY_INTERVAL_MS;
|
|
50789
|
+
const now = options.now ?? (() => Date.now());
|
|
50790
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TUNNEL_REACHABILITY_TIMEOUT_MS;
|
|
50791
|
+
let consecutiveFailures = 0;
|
|
50792
|
+
let lastCheckedAt = null;
|
|
50793
|
+
function recordFailure(reason, statusCode) {
|
|
50794
|
+
consecutiveFailures += 1;
|
|
50795
|
+
return {
|
|
50796
|
+
available: false,
|
|
50797
|
+
checked: true,
|
|
50798
|
+
consecutiveFailures,
|
|
50799
|
+
reason,
|
|
50800
|
+
shouldRestart: consecutiveFailures >= failureThreshold,
|
|
50801
|
+
...statusCode !== void 0 ? { statusCode } : {}
|
|
50802
|
+
};
|
|
50803
|
+
}
|
|
50804
|
+
return {
|
|
50805
|
+
async check(endpoint) {
|
|
50806
|
+
const currentTime = now();
|
|
50807
|
+
if (lastCheckedAt !== null && currentTime - lastCheckedAt < intervalMs) {
|
|
50808
|
+
return {
|
|
50809
|
+
available: true,
|
|
50810
|
+
checked: false,
|
|
50811
|
+
consecutiveFailures,
|
|
50812
|
+
shouldRestart: false
|
|
50813
|
+
};
|
|
50814
|
+
}
|
|
50815
|
+
lastCheckedAt = currentTime;
|
|
50816
|
+
if (!endpoint) {
|
|
50817
|
+
return recordFailure("missing endpoint");
|
|
50818
|
+
}
|
|
50819
|
+
try {
|
|
50820
|
+
const response = await fetchWithTimeout2(fetchImpl, buildHealthUrl(endpoint, healthPath), timeoutMs);
|
|
50821
|
+
if (!response.ok) {
|
|
50822
|
+
return recordFailure(`health check returned ${response.status}`, response.status);
|
|
50823
|
+
}
|
|
50824
|
+
consecutiveFailures = 0;
|
|
50825
|
+
return {
|
|
50826
|
+
available: true,
|
|
50827
|
+
checked: true,
|
|
50828
|
+
consecutiveFailures,
|
|
50829
|
+
shouldRestart: false,
|
|
50830
|
+
statusCode: response.status
|
|
50831
|
+
};
|
|
50832
|
+
} catch (err) {
|
|
50833
|
+
return recordFailure(err instanceof Error ? err.message : String(err));
|
|
50834
|
+
}
|
|
50835
|
+
},
|
|
50836
|
+
reset() {
|
|
50837
|
+
consecutiveFailures = 0;
|
|
50838
|
+
lastCheckedAt = null;
|
|
50839
|
+
}
|
|
50840
|
+
};
|
|
50841
|
+
}
|
|
50842
|
+
function buildHealthUrl(endpoint, healthPath) {
|
|
50843
|
+
return new URL(healthPath, endpoint).toString();
|
|
50844
|
+
}
|
|
50845
|
+
async function fetchWithTimeout2(fetchImpl, url, timeoutMs) {
|
|
50846
|
+
const controller = new AbortController();
|
|
50847
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
50848
|
+
timer.unref?.();
|
|
50849
|
+
try {
|
|
50850
|
+
return await fetchImpl(url, { method: "GET", signal: controller.signal });
|
|
50851
|
+
} finally {
|
|
50852
|
+
clearTimeout(timer);
|
|
50853
|
+
}
|
|
50854
|
+
}
|
|
50855
|
+
|
|
50732
50856
|
// src/bootstrap/start-node.ts
|
|
50733
50857
|
function createSettingsSnapshotProvider(options) {
|
|
50734
50858
|
let cachedSnapshot = null;
|
|
@@ -50818,6 +50942,9 @@ function createTunnelManager(options) {
|
|
|
50818
50942
|
let shareTransport = null;
|
|
50819
50943
|
let dashboardHealthTimer = null;
|
|
50820
50944
|
let nodeTunnelHealthTimer = null;
|
|
50945
|
+
let dashboardHealthCheckRunning = false;
|
|
50946
|
+
let nodeTunnelHealthCheckRunning = false;
|
|
50947
|
+
const nodeTunnelReachability = createTunnelReachabilityMonitor();
|
|
50821
50948
|
function createDashboardTransportConfig() {
|
|
50822
50949
|
return {
|
|
50823
50950
|
type: "devtunnel",
|
|
@@ -50857,6 +50984,28 @@ function createTunnelManager(options) {
|
|
|
50857
50984
|
function shouldPublishDashboardTunnel() {
|
|
50858
50985
|
return authMetadata.enabled && (meshyNode.getTransportType() === "devtunnel" || meshyNode.isDevTunnelEnabled());
|
|
50859
50986
|
}
|
|
50987
|
+
function getPublishedNodeTunnelEndpoint() {
|
|
50988
|
+
const self2 = meshyNode.getNodeRegistry().getSelf();
|
|
50989
|
+
return meshyNode.getTransportType() === "devtunnel" ? self2.endpoint : self2.devtunnelEndpoint;
|
|
50990
|
+
}
|
|
50991
|
+
function setPublishedNodeTunnelHealth(health) {
|
|
50992
|
+
const selfId = meshyNode.getNodeRegistry().getSelf().id;
|
|
50993
|
+
meshyNode.getNodeRegistry().updateDevTunnelHealth(selfId, health);
|
|
50994
|
+
}
|
|
50995
|
+
function markPublishedNodeTunnelHealthy(endpoint) {
|
|
50996
|
+
setPublishedNodeTunnelHealth({
|
|
50997
|
+
status: "healthy",
|
|
50998
|
+
checkedAt: Date.now(),
|
|
50999
|
+
...endpoint ? { endpoint } : {}
|
|
51000
|
+
});
|
|
51001
|
+
}
|
|
51002
|
+
function markPublishedNodeTunnelFailed(details) {
|
|
51003
|
+
setPublishedNodeTunnelHealth({
|
|
51004
|
+
status: "failed",
|
|
51005
|
+
checkedAt: Date.now(),
|
|
51006
|
+
...details
|
|
51007
|
+
});
|
|
51008
|
+
}
|
|
50860
51009
|
async function stopDashboardTransport(reason) {
|
|
50861
51010
|
if (!dashboardTransport) {
|
|
50862
51011
|
if (dashboardOrigin) {
|
|
@@ -50960,31 +51109,100 @@ function createTunnelManager(options) {
|
|
|
50960
51109
|
if (!nodeTunnelHealthTimer) {
|
|
50961
51110
|
nodeTunnelHealthTimer = setInterval(() => {
|
|
50962
51111
|
void (async () => {
|
|
50963
|
-
if (
|
|
51112
|
+
if (nodeTunnelHealthCheckRunning) {
|
|
50964
51113
|
return;
|
|
50965
51114
|
}
|
|
50966
|
-
|
|
50967
|
-
if (healthy) {
|
|
50968
|
-
return;
|
|
50969
|
-
}
|
|
50970
|
-
meshyNode.getLogger().warn("published node tunnel became unhealthy; restarting with stable id", {
|
|
50971
|
-
mainTransportType: meshyNode.getTransportType(),
|
|
50972
|
-
sidecarEnabled: meshyNode.isDevTunnelEnabled()
|
|
50973
|
-
});
|
|
51115
|
+
nodeTunnelHealthCheckRunning = true;
|
|
50974
51116
|
try {
|
|
50975
|
-
|
|
50976
|
-
|
|
50977
|
-
|
|
50978
|
-
|
|
50979
|
-
|
|
50980
|
-
|
|
51117
|
+
if (!meshyNode.hasPublishedNodeTunnel()) {
|
|
51118
|
+
nodeTunnelReachability.reset();
|
|
51119
|
+
setPublishedNodeTunnelHealth(void 0);
|
|
51120
|
+
return;
|
|
51121
|
+
}
|
|
51122
|
+
const publishedEndpoint = getPublishedNodeTunnelEndpoint();
|
|
51123
|
+
const healthy = await meshyNode.isPublishedNodeTunnelHealthy().catch(() => false);
|
|
51124
|
+
if (!healthy) {
|
|
51125
|
+
markPublishedNodeTunnelFailed({
|
|
51126
|
+
endpoint: publishedEndpoint,
|
|
51127
|
+
reason: "devtunnel process is not running"
|
|
51128
|
+
});
|
|
51129
|
+
meshyNode.getLogger().warn("published node tunnel process became unhealthy; restarting with stable id", {
|
|
51130
|
+
mainTransportType: meshyNode.getTransportType(),
|
|
51131
|
+
sidecarEnabled: meshyNode.isDevTunnelEnabled()
|
|
51132
|
+
});
|
|
51133
|
+
try {
|
|
51134
|
+
const endpoint = await meshyNode.restartPublishedNodeTunnel();
|
|
51135
|
+
nodeTunnelReachability.reset();
|
|
51136
|
+
markPublishedNodeTunnelHealthy(endpoint);
|
|
51137
|
+
meshyNode.getLogger().info("restarted published node tunnel", {
|
|
51138
|
+
endpoint,
|
|
51139
|
+
stableUrl: true,
|
|
51140
|
+
mainTransportType: meshyNode.getTransportType(),
|
|
51141
|
+
sidecarEnabled: meshyNode.isDevTunnelEnabled()
|
|
51142
|
+
});
|
|
51143
|
+
} catch (err) {
|
|
51144
|
+
markPublishedNodeTunnelFailed({
|
|
51145
|
+
endpoint: publishedEndpoint,
|
|
51146
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
51147
|
+
});
|
|
51148
|
+
meshyNode.getLogger().warn("failed to restart published node tunnel", {
|
|
51149
|
+
error: err instanceof Error ? err.message : String(err),
|
|
51150
|
+
mainTransportType: meshyNode.getTransportType(),
|
|
51151
|
+
sidecarEnabled: meshyNode.isDevTunnelEnabled()
|
|
51152
|
+
});
|
|
51153
|
+
}
|
|
51154
|
+
return;
|
|
51155
|
+
}
|
|
51156
|
+
const reachability = await nodeTunnelReachability.check(publishedEndpoint);
|
|
51157
|
+
if (!reachability.checked) {
|
|
51158
|
+
return;
|
|
51159
|
+
}
|
|
51160
|
+
if (reachability.available) {
|
|
51161
|
+
markPublishedNodeTunnelHealthy(publishedEndpoint);
|
|
51162
|
+
return;
|
|
51163
|
+
}
|
|
51164
|
+
markPublishedNodeTunnelFailed({
|
|
51165
|
+
consecutiveFailures: reachability.consecutiveFailures,
|
|
51166
|
+
endpoint: publishedEndpoint,
|
|
51167
|
+
reason: reachability.reason,
|
|
51168
|
+
statusCode: reachability.statusCode
|
|
50981
51169
|
});
|
|
50982
|
-
|
|
50983
|
-
|
|
50984
|
-
|
|
51170
|
+
meshyNode.getLogger().warn("published node tunnel endpoint health check failed", {
|
|
51171
|
+
consecutiveFailures: reachability.consecutiveFailures,
|
|
51172
|
+
failureThresholdReached: reachability.shouldRestart,
|
|
50985
51173
|
mainTransportType: meshyNode.getTransportType(),
|
|
50986
|
-
|
|
51174
|
+
reason: reachability.reason,
|
|
51175
|
+
sidecarEnabled: meshyNode.isDevTunnelEnabled(),
|
|
51176
|
+
statusCode: reachability.statusCode
|
|
50987
51177
|
});
|
|
51178
|
+
if (!reachability.shouldRestart) {
|
|
51179
|
+
return;
|
|
51180
|
+
}
|
|
51181
|
+
try {
|
|
51182
|
+
const endpoint = await meshyNode.restartPublishedNodeTunnel();
|
|
51183
|
+
nodeTunnelReachability.reset();
|
|
51184
|
+
markPublishedNodeTunnelHealthy(endpoint);
|
|
51185
|
+
meshyNode.getLogger().info("restarted published node tunnel", {
|
|
51186
|
+
endpoint,
|
|
51187
|
+
stableUrl: true,
|
|
51188
|
+
mainTransportType: meshyNode.getTransportType(),
|
|
51189
|
+
sidecarEnabled: meshyNode.isDevTunnelEnabled()
|
|
51190
|
+
});
|
|
51191
|
+
} catch (err) {
|
|
51192
|
+
markPublishedNodeTunnelFailed({
|
|
51193
|
+
consecutiveFailures: reachability.consecutiveFailures,
|
|
51194
|
+
endpoint: publishedEndpoint,
|
|
51195
|
+
reason: err instanceof Error ? err.message : String(err),
|
|
51196
|
+
statusCode: reachability.statusCode
|
|
51197
|
+
});
|
|
51198
|
+
meshyNode.getLogger().warn("failed to restart published node tunnel", {
|
|
51199
|
+
error: err instanceof Error ? err.message : String(err),
|
|
51200
|
+
mainTransportType: meshyNode.getTransportType(),
|
|
51201
|
+
sidecarEnabled: meshyNode.isDevTunnelEnabled()
|
|
51202
|
+
});
|
|
51203
|
+
}
|
|
51204
|
+
} finally {
|
|
51205
|
+
nodeTunnelHealthCheckRunning = false;
|
|
50988
51206
|
}
|
|
50989
51207
|
})();
|
|
50990
51208
|
}, config.cluster.heartbeatInterval);
|
|
@@ -50992,17 +51210,24 @@ function createTunnelManager(options) {
|
|
|
50992
51210
|
if (!dashboardHealthTimer) {
|
|
50993
51211
|
dashboardHealthTimer = setInterval(() => {
|
|
50994
51212
|
void (async () => {
|
|
50995
|
-
if (
|
|
51213
|
+
if (dashboardHealthCheckRunning) {
|
|
50996
51214
|
return;
|
|
50997
51215
|
}
|
|
50998
|
-
|
|
50999
|
-
|
|
51000
|
-
|
|
51216
|
+
dashboardHealthCheckRunning = true;
|
|
51217
|
+
try {
|
|
51218
|
+
if (!dashboardTransport) {
|
|
51219
|
+
return;
|
|
51220
|
+
}
|
|
51221
|
+
const healthy = await dashboardTransport.isHealthy().catch(() => false);
|
|
51222
|
+
if (!healthy) {
|
|
51223
|
+
meshyNode.getLogger().warn("dashboard tunnel process became unhealthy; restarting with stable id", {
|
|
51224
|
+
port: config.node.port
|
|
51225
|
+
});
|
|
51226
|
+
await restartDashboardTransport("healthcheck");
|
|
51227
|
+
}
|
|
51228
|
+
} finally {
|
|
51229
|
+
dashboardHealthCheckRunning = false;
|
|
51001
51230
|
}
|
|
51002
|
-
meshyNode.getLogger().warn("dashboard tunnel became unhealthy; restarting with stable id", {
|
|
51003
|
-
port: config.node.port
|
|
51004
|
-
});
|
|
51005
|
-
await restartDashboardTransport("healthcheck");
|
|
51006
51231
|
})();
|
|
51007
51232
|
}, config.cluster.heartbeatInterval);
|
|
51008
51233
|
}
|
|
@@ -51016,6 +51241,7 @@ function createTunnelManager(options) {
|
|
|
51016
51241
|
clearInterval(nodeTunnelHealthTimer);
|
|
51017
51242
|
nodeTunnelHealthTimer = null;
|
|
51018
51243
|
}
|
|
51244
|
+
nodeTunnelReachability.reset();
|
|
51019
51245
|
}
|
|
51020
51246
|
async function stop() {
|
|
51021
51247
|
stopHealthChecks();
|
|
@@ -51168,6 +51394,9 @@ async function startNode(args) {
|
|
|
51168
51394
|
switchTransport: async (type) => {
|
|
51169
51395
|
const endpoint = await meshyNode.switchTransport(type);
|
|
51170
51396
|
persistNodeStartupTransport(config.storage.path, type);
|
|
51397
|
+
if (type !== "devtunnel" && !meshyNode.isDevTunnelEnabled()) {
|
|
51398
|
+
meshyNode.getNodeRegistry().updateDevTunnelHealth(meshyNode.getNodeRegistry().getSelf().id, void 0);
|
|
51399
|
+
}
|
|
51171
51400
|
await tunnelManager.syncDashboardTransport(`switchTransport:${type}`);
|
|
51172
51401
|
return endpoint;
|
|
51173
51402
|
},
|
|
@@ -51180,6 +51409,9 @@ async function startNode(args) {
|
|
|
51180
51409
|
},
|
|
51181
51410
|
disableDevTunnel: async () => {
|
|
51182
51411
|
await meshyNode.disableDevTunnel();
|
|
51412
|
+
if (meshyNode.getTransportType() !== "devtunnel") {
|
|
51413
|
+
meshyNode.getNodeRegistry().updateDevTunnelHealth(meshyNode.getNodeRegistry().getSelf().id, void 0);
|
|
51414
|
+
}
|
|
51183
51415
|
persistNodeStartupTransport(
|
|
51184
51416
|
config.storage.path,
|
|
51185
51417
|
meshyNode.getTransportType()
|
package/package.json
CHANGED
package/runtime-metadata.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"packageName": "meshy-node",
|
|
3
|
-
"packageVersion": "0.4.
|
|
3
|
+
"packageVersion": "0.4.3",
|
|
4
4
|
"packages": {
|
|
5
5
|
"workspace": {
|
|
6
6
|
"name": "meshy",
|
|
7
|
-
"version": "0.4.
|
|
7
|
+
"version": "0.4.3"
|
|
8
8
|
},
|
|
9
9
|
"node": {
|
|
10
10
|
"name": "meshy-node",
|
|
11
|
-
"version": "0.4.
|
|
11
|
+
"version": "0.4.3"
|
|
12
12
|
},
|
|
13
13
|
"core": {
|
|
14
14
|
"name": "@meshy/core",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"repository": {
|
|
27
27
|
"url": "https://github.com/ai-microsoft/meshy",
|
|
28
|
-
"branch": "
|
|
29
|
-
"commit": "
|
|
28
|
+
"branch": "TunnelRestart",
|
|
29
|
+
"commit": "f34e076"
|
|
30
30
|
}
|
|
31
31
|
}
|