meshy-node 0.4.1 → 0.4.2
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-DaZ-EQZ4.js +124 -0
- package/dashboard/assets/{DashboardShared-BSDgKTOF.js → DashboardShared-CKWmFD7i.js} +4 -4
- package/dashboard/assets/{DiffTab-_2QRJdG0.js → DiffTab-HUpulZ_U.js} +2 -2
- package/dashboard/assets/{FilesTab-_pFba0dN.js → FilesTab-vVa4GgR5.js} +2 -2
- package/dashboard/assets/{PreviewTab-C5UehUZ1.js → PreviewTab-DRyl2BmE.js} +2 -2
- package/dashboard/assets/{SharedConversationPage-e35GHbGI.js → SharedConversationPage-B4sLTwC9.js} +3 -3
- package/dashboard/assets/{file-3EwPAA-4.js → file-BXP_hlLG.js} +1 -1
- package/dashboard/assets/folder-B3put-Ay.js +6 -0
- package/dashboard/assets/index-Bg0PqgJi.js +291 -0
- package/dashboard/assets/index-BzzXPy7Y.css +1 -0
- package/dashboard/assets/{input-DMp80MWI.js → input-DH4KoLjb.js} +1 -1
- package/dashboard/index.html +2 -2
- package/main.cjs +268 -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/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;
|
|
@@ -34922,6 +34949,7 @@ var HeartbeatMonitor = class {
|
|
|
34922
34949
|
supportedAgents: self2.supportedAgents,
|
|
34923
34950
|
devtunnelEnabled: self2.devtunnelEndpoint !== void 0,
|
|
34924
34951
|
devtunnelEndpoint: self2.devtunnelEndpoint,
|
|
34952
|
+
devtunnelHealth: self2.devtunnelHealth,
|
|
34925
34953
|
dashboardOrigin: self2.dashboardOrigin,
|
|
34926
34954
|
workDirFolders: self2.workDir ? listWorkDirFolders(self2.workDir) : void 0,
|
|
34927
34955
|
settingsSnapshot: this.resolveCurrentSettingsSnapshot()
|
|
@@ -34942,6 +34970,7 @@ var HeartbeatMonitor = class {
|
|
|
34942
34970
|
workDir,
|
|
34943
34971
|
devtunnelEnabled,
|
|
34944
34972
|
devtunnelEndpoint,
|
|
34973
|
+
devtunnelHealth,
|
|
34945
34974
|
dashboardOrigin,
|
|
34946
34975
|
workDirFolders,
|
|
34947
34976
|
settingsSnapshot
|
|
@@ -34969,6 +34998,7 @@ var HeartbeatMonitor = class {
|
|
|
34969
34998
|
...transportType ? { transportType } : {},
|
|
34970
34999
|
...workDir ? { workDir } : {},
|
|
34971
35000
|
...devtunnelEnabled && devtunnelEndpoint ? { devtunnelEndpoint } : {},
|
|
35001
|
+
...devtunnelHealth ? { devtunnelHealth } : {},
|
|
34972
35002
|
...dashboardOrigin ? { dashboardOrigin } : {},
|
|
34973
35003
|
...workDirFolders ? { workDirFolders } : {},
|
|
34974
35004
|
...settingsSnapshot ? { settingsSnapshot } : {}
|
|
@@ -35004,6 +35034,7 @@ var HeartbeatMonitor = class {
|
|
|
35004
35034
|
}
|
|
35005
35035
|
this.nodeRegistry.updateLoad(nodeId, load);
|
|
35006
35036
|
this.applyReportedDevTunnelState(nodeId, devtunnelEnabled, devtunnelEndpoint);
|
|
35037
|
+
this.nodeRegistry.updateDevTunnelHealth(nodeId, devtunnelEnabled === false ? void 0 : devtunnelHealth);
|
|
35007
35038
|
this.nodeRegistry.updateDashboardOrigin(nodeId, dashboardOrigin);
|
|
35008
35039
|
if (workDirFolders) {
|
|
35009
35040
|
this.nodeRegistry.updateFolders(nodeId, workDirFolders);
|
|
@@ -35053,6 +35084,7 @@ var HeartbeatMonitor = class {
|
|
|
35053
35084
|
workDir: self2.workDir,
|
|
35054
35085
|
devtunnelEnabled: self2.devtunnelEndpoint !== void 0,
|
|
35055
35086
|
devtunnelEndpoint: self2.devtunnelEndpoint,
|
|
35087
|
+
devtunnelHealth: self2.devtunnelHealth,
|
|
35056
35088
|
dashboardOrigin: self2.dashboardOrigin,
|
|
35057
35089
|
workDirFolders: self2.workDir ? listWorkDirFolders(self2.workDir) : void 0,
|
|
35058
35090
|
settingsSnapshot
|
|
@@ -37760,6 +37792,9 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
37760
37792
|
if (self2.devtunnelEndpoint) {
|
|
37761
37793
|
joinBody.devtunnelEndpoint = self2.devtunnelEndpoint;
|
|
37762
37794
|
}
|
|
37795
|
+
if (self2.devtunnelHealth) {
|
|
37796
|
+
joinBody.devtunnelHealth = self2.devtunnelHealth;
|
|
37797
|
+
}
|
|
37763
37798
|
if (self2.dashboardOrigin) {
|
|
37764
37799
|
joinBody.dashboardOrigin = self2.dashboardOrigin;
|
|
37765
37800
|
}
|
|
@@ -38093,6 +38128,7 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
38093
38128
|
workDir: currentSelf.workDir,
|
|
38094
38129
|
workDirFolders: listWorkDirFolders(this.getWorkDir()),
|
|
38095
38130
|
...currentSelf.devtunnelEndpoint ? { devtunnelEndpoint: currentSelf.devtunnelEndpoint } : {},
|
|
38131
|
+
...currentSelf.devtunnelHealth ? { devtunnelHealth: currentSelf.devtunnelHealth } : {},
|
|
38096
38132
|
...currentSelf.dashboardOrigin ? { dashboardOrigin: currentSelf.dashboardOrigin } : {},
|
|
38097
38133
|
...currentSelf.settingsSnapshot ? { settingsSnapshot: currentSelf.settingsSnapshot } : {}
|
|
38098
38134
|
};
|
|
@@ -42945,6 +42981,14 @@ var NodeSettingsSnapshotSchema = external_exports.object({
|
|
|
42945
42981
|
api: SystemPackageInfoSchema.optional()
|
|
42946
42982
|
}).optional()
|
|
42947
42983
|
});
|
|
42984
|
+
var DevTunnelHealthSchema = external_exports.object({
|
|
42985
|
+
status: external_exports.enum(["healthy", "failed"]),
|
|
42986
|
+
checkedAt: external_exports.number(),
|
|
42987
|
+
endpoint: external_exports.string().optional(),
|
|
42988
|
+
reason: external_exports.string().optional(),
|
|
42989
|
+
statusCode: external_exports.number().optional(),
|
|
42990
|
+
consecutiveFailures: external_exports.number().optional()
|
|
42991
|
+
});
|
|
42948
42992
|
|
|
42949
42993
|
// ../../packages/api/src/schemas/cluster.ts
|
|
42950
42994
|
var NodeInfoSchema = external_exports.object({
|
|
@@ -42959,6 +43003,7 @@ var NodeInfoSchema = external_exports.object({
|
|
|
42959
43003
|
lastHeartbeat: external_exports.number(),
|
|
42960
43004
|
transportType: external_exports.string().optional(),
|
|
42961
43005
|
devtunnelEndpoint: external_exports.string().optional(),
|
|
43006
|
+
devtunnelHealth: DevTunnelHealthSchema.optional(),
|
|
42962
43007
|
dashboardOrigin: external_exports.string().optional(),
|
|
42963
43008
|
workDir: external_exports.string().optional(),
|
|
42964
43009
|
workDirFolders: external_exports.array(external_exports.string()).optional(),
|
|
@@ -42995,6 +43040,7 @@ var JoinClusterBody = external_exports.object({
|
|
|
42995
43040
|
workDir: external_exports.string().optional(),
|
|
42996
43041
|
workDirFolders: external_exports.array(external_exports.string()).optional(),
|
|
42997
43042
|
devtunnelEndpoint: external_exports.string().url().optional(),
|
|
43043
|
+
devtunnelHealth: DevTunnelHealthSchema.optional(),
|
|
42998
43044
|
dashboardOrigin: external_exports.string().url().optional(),
|
|
42999
43045
|
settingsSnapshot: NodeSettingsSnapshotSchema.optional(),
|
|
43000
43046
|
tasks: external_exports.array(JoinTaskSchema).default([])
|
|
@@ -43039,6 +43085,7 @@ var NodeInfoSchema2 = external_exports.object({
|
|
|
43039
43085
|
lastHeartbeat: external_exports.number(),
|
|
43040
43086
|
transportType: external_exports.string().optional(),
|
|
43041
43087
|
devtunnelEndpoint: external_exports.string().optional(),
|
|
43088
|
+
devtunnelHealth: DevTunnelHealthSchema.optional(),
|
|
43042
43089
|
dashboardOrigin: external_exports.string().optional(),
|
|
43043
43090
|
workDir: external_exports.string().optional(),
|
|
43044
43091
|
workDirFolders: external_exports.array(external_exports.string()).optional(),
|
|
@@ -50729,6 +50776,82 @@ function buildRuntimeMetadata(storagePath) {
|
|
|
50729
50776
|
};
|
|
50730
50777
|
}
|
|
50731
50778
|
|
|
50779
|
+
// src/bootstrap/tunnel-health.ts
|
|
50780
|
+
var DEFAULT_TUNNEL_REACHABILITY_INTERVAL_MS = 6e4;
|
|
50781
|
+
var DEFAULT_TUNNEL_REACHABILITY_TIMEOUT_MS = 5e3;
|
|
50782
|
+
var DEFAULT_TUNNEL_RESTART_FAILURE_THRESHOLD = 2;
|
|
50783
|
+
function createTunnelReachabilityMonitor(options = {}) {
|
|
50784
|
+
const failureThreshold = options.failureThreshold ?? DEFAULT_TUNNEL_RESTART_FAILURE_THRESHOLD;
|
|
50785
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
50786
|
+
const healthPath = options.healthPath ?? "/api/system/health";
|
|
50787
|
+
const intervalMs = options.intervalMs ?? DEFAULT_TUNNEL_REACHABILITY_INTERVAL_MS;
|
|
50788
|
+
const now = options.now ?? (() => Date.now());
|
|
50789
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TUNNEL_REACHABILITY_TIMEOUT_MS;
|
|
50790
|
+
let consecutiveFailures = 0;
|
|
50791
|
+
let lastCheckedAt = null;
|
|
50792
|
+
function recordFailure(reason, statusCode) {
|
|
50793
|
+
consecutiveFailures += 1;
|
|
50794
|
+
return {
|
|
50795
|
+
available: false,
|
|
50796
|
+
checked: true,
|
|
50797
|
+
consecutiveFailures,
|
|
50798
|
+
reason,
|
|
50799
|
+
shouldRestart: consecutiveFailures >= failureThreshold,
|
|
50800
|
+
...statusCode !== void 0 ? { statusCode } : {}
|
|
50801
|
+
};
|
|
50802
|
+
}
|
|
50803
|
+
return {
|
|
50804
|
+
async check(endpoint) {
|
|
50805
|
+
const currentTime = now();
|
|
50806
|
+
if (lastCheckedAt !== null && currentTime - lastCheckedAt < intervalMs) {
|
|
50807
|
+
return {
|
|
50808
|
+
available: true,
|
|
50809
|
+
checked: false,
|
|
50810
|
+
consecutiveFailures,
|
|
50811
|
+
shouldRestart: false
|
|
50812
|
+
};
|
|
50813
|
+
}
|
|
50814
|
+
lastCheckedAt = currentTime;
|
|
50815
|
+
if (!endpoint) {
|
|
50816
|
+
return recordFailure("missing endpoint");
|
|
50817
|
+
}
|
|
50818
|
+
try {
|
|
50819
|
+
const response = await fetchWithTimeout2(fetchImpl, buildHealthUrl(endpoint, healthPath), timeoutMs);
|
|
50820
|
+
if (!response.ok) {
|
|
50821
|
+
return recordFailure(`health check returned ${response.status}`, response.status);
|
|
50822
|
+
}
|
|
50823
|
+
consecutiveFailures = 0;
|
|
50824
|
+
return {
|
|
50825
|
+
available: true,
|
|
50826
|
+
checked: true,
|
|
50827
|
+
consecutiveFailures,
|
|
50828
|
+
shouldRestart: false,
|
|
50829
|
+
statusCode: response.status
|
|
50830
|
+
};
|
|
50831
|
+
} catch (err) {
|
|
50832
|
+
return recordFailure(err instanceof Error ? err.message : String(err));
|
|
50833
|
+
}
|
|
50834
|
+
},
|
|
50835
|
+
reset() {
|
|
50836
|
+
consecutiveFailures = 0;
|
|
50837
|
+
lastCheckedAt = null;
|
|
50838
|
+
}
|
|
50839
|
+
};
|
|
50840
|
+
}
|
|
50841
|
+
function buildHealthUrl(endpoint, healthPath) {
|
|
50842
|
+
return new URL(healthPath, endpoint).toString();
|
|
50843
|
+
}
|
|
50844
|
+
async function fetchWithTimeout2(fetchImpl, url, timeoutMs) {
|
|
50845
|
+
const controller = new AbortController();
|
|
50846
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
50847
|
+
timer.unref?.();
|
|
50848
|
+
try {
|
|
50849
|
+
return await fetchImpl(url, { method: "GET", signal: controller.signal });
|
|
50850
|
+
} finally {
|
|
50851
|
+
clearTimeout(timer);
|
|
50852
|
+
}
|
|
50853
|
+
}
|
|
50854
|
+
|
|
50732
50855
|
// src/bootstrap/start-node.ts
|
|
50733
50856
|
function createSettingsSnapshotProvider(options) {
|
|
50734
50857
|
let cachedSnapshot = null;
|
|
@@ -50818,6 +50941,9 @@ function createTunnelManager(options) {
|
|
|
50818
50941
|
let shareTransport = null;
|
|
50819
50942
|
let dashboardHealthTimer = null;
|
|
50820
50943
|
let nodeTunnelHealthTimer = null;
|
|
50944
|
+
let dashboardHealthCheckRunning = false;
|
|
50945
|
+
let nodeTunnelHealthCheckRunning = false;
|
|
50946
|
+
const nodeTunnelReachability = createTunnelReachabilityMonitor();
|
|
50821
50947
|
function createDashboardTransportConfig() {
|
|
50822
50948
|
return {
|
|
50823
50949
|
type: "devtunnel",
|
|
@@ -50857,6 +50983,28 @@ function createTunnelManager(options) {
|
|
|
50857
50983
|
function shouldPublishDashboardTunnel() {
|
|
50858
50984
|
return authMetadata.enabled && (meshyNode.getTransportType() === "devtunnel" || meshyNode.isDevTunnelEnabled());
|
|
50859
50985
|
}
|
|
50986
|
+
function getPublishedNodeTunnelEndpoint() {
|
|
50987
|
+
const self2 = meshyNode.getNodeRegistry().getSelf();
|
|
50988
|
+
return meshyNode.getTransportType() === "devtunnel" ? self2.endpoint : self2.devtunnelEndpoint;
|
|
50989
|
+
}
|
|
50990
|
+
function setPublishedNodeTunnelHealth(health) {
|
|
50991
|
+
const selfId = meshyNode.getNodeRegistry().getSelf().id;
|
|
50992
|
+
meshyNode.getNodeRegistry().updateDevTunnelHealth(selfId, health);
|
|
50993
|
+
}
|
|
50994
|
+
function markPublishedNodeTunnelHealthy(endpoint) {
|
|
50995
|
+
setPublishedNodeTunnelHealth({
|
|
50996
|
+
status: "healthy",
|
|
50997
|
+
checkedAt: Date.now(),
|
|
50998
|
+
...endpoint ? { endpoint } : {}
|
|
50999
|
+
});
|
|
51000
|
+
}
|
|
51001
|
+
function markPublishedNodeTunnelFailed(details) {
|
|
51002
|
+
setPublishedNodeTunnelHealth({
|
|
51003
|
+
status: "failed",
|
|
51004
|
+
checkedAt: Date.now(),
|
|
51005
|
+
...details
|
|
51006
|
+
});
|
|
51007
|
+
}
|
|
50860
51008
|
async function stopDashboardTransport(reason) {
|
|
50861
51009
|
if (!dashboardTransport) {
|
|
50862
51010
|
if (dashboardOrigin) {
|
|
@@ -50960,31 +51108,100 @@ function createTunnelManager(options) {
|
|
|
50960
51108
|
if (!nodeTunnelHealthTimer) {
|
|
50961
51109
|
nodeTunnelHealthTimer = setInterval(() => {
|
|
50962
51110
|
void (async () => {
|
|
50963
|
-
if (
|
|
51111
|
+
if (nodeTunnelHealthCheckRunning) {
|
|
50964
51112
|
return;
|
|
50965
51113
|
}
|
|
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
|
-
});
|
|
51114
|
+
nodeTunnelHealthCheckRunning = true;
|
|
50974
51115
|
try {
|
|
50975
|
-
|
|
50976
|
-
|
|
50977
|
-
|
|
50978
|
-
|
|
50979
|
-
|
|
50980
|
-
|
|
51116
|
+
if (!meshyNode.hasPublishedNodeTunnel()) {
|
|
51117
|
+
nodeTunnelReachability.reset();
|
|
51118
|
+
setPublishedNodeTunnelHealth(void 0);
|
|
51119
|
+
return;
|
|
51120
|
+
}
|
|
51121
|
+
const publishedEndpoint = getPublishedNodeTunnelEndpoint();
|
|
51122
|
+
const healthy = await meshyNode.isPublishedNodeTunnelHealthy().catch(() => false);
|
|
51123
|
+
if (!healthy) {
|
|
51124
|
+
markPublishedNodeTunnelFailed({
|
|
51125
|
+
endpoint: publishedEndpoint,
|
|
51126
|
+
reason: "devtunnel process is not running"
|
|
51127
|
+
});
|
|
51128
|
+
meshyNode.getLogger().warn("published node tunnel process became unhealthy; restarting with stable id", {
|
|
51129
|
+
mainTransportType: meshyNode.getTransportType(),
|
|
51130
|
+
sidecarEnabled: meshyNode.isDevTunnelEnabled()
|
|
51131
|
+
});
|
|
51132
|
+
try {
|
|
51133
|
+
const endpoint = await meshyNode.restartPublishedNodeTunnel();
|
|
51134
|
+
nodeTunnelReachability.reset();
|
|
51135
|
+
markPublishedNodeTunnelHealthy(endpoint);
|
|
51136
|
+
meshyNode.getLogger().info("restarted published node tunnel", {
|
|
51137
|
+
endpoint,
|
|
51138
|
+
stableUrl: true,
|
|
51139
|
+
mainTransportType: meshyNode.getTransportType(),
|
|
51140
|
+
sidecarEnabled: meshyNode.isDevTunnelEnabled()
|
|
51141
|
+
});
|
|
51142
|
+
} catch (err) {
|
|
51143
|
+
markPublishedNodeTunnelFailed({
|
|
51144
|
+
endpoint: publishedEndpoint,
|
|
51145
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
51146
|
+
});
|
|
51147
|
+
meshyNode.getLogger().warn("failed to restart published node tunnel", {
|
|
51148
|
+
error: err instanceof Error ? err.message : String(err),
|
|
51149
|
+
mainTransportType: meshyNode.getTransportType(),
|
|
51150
|
+
sidecarEnabled: meshyNode.isDevTunnelEnabled()
|
|
51151
|
+
});
|
|
51152
|
+
}
|
|
51153
|
+
return;
|
|
51154
|
+
}
|
|
51155
|
+
const reachability = await nodeTunnelReachability.check(publishedEndpoint);
|
|
51156
|
+
if (!reachability.checked) {
|
|
51157
|
+
return;
|
|
51158
|
+
}
|
|
51159
|
+
if (reachability.available) {
|
|
51160
|
+
markPublishedNodeTunnelHealthy(publishedEndpoint);
|
|
51161
|
+
return;
|
|
51162
|
+
}
|
|
51163
|
+
markPublishedNodeTunnelFailed({
|
|
51164
|
+
consecutiveFailures: reachability.consecutiveFailures,
|
|
51165
|
+
endpoint: publishedEndpoint,
|
|
51166
|
+
reason: reachability.reason,
|
|
51167
|
+
statusCode: reachability.statusCode
|
|
50981
51168
|
});
|
|
50982
|
-
|
|
50983
|
-
|
|
50984
|
-
|
|
51169
|
+
meshyNode.getLogger().warn("published node tunnel endpoint health check failed", {
|
|
51170
|
+
consecutiveFailures: reachability.consecutiveFailures,
|
|
51171
|
+
failureThresholdReached: reachability.shouldRestart,
|
|
50985
51172
|
mainTransportType: meshyNode.getTransportType(),
|
|
50986
|
-
|
|
51173
|
+
reason: reachability.reason,
|
|
51174
|
+
sidecarEnabled: meshyNode.isDevTunnelEnabled(),
|
|
51175
|
+
statusCode: reachability.statusCode
|
|
50987
51176
|
});
|
|
51177
|
+
if (!reachability.shouldRestart) {
|
|
51178
|
+
return;
|
|
51179
|
+
}
|
|
51180
|
+
try {
|
|
51181
|
+
const endpoint = await meshyNode.restartPublishedNodeTunnel();
|
|
51182
|
+
nodeTunnelReachability.reset();
|
|
51183
|
+
markPublishedNodeTunnelHealthy(endpoint);
|
|
51184
|
+
meshyNode.getLogger().info("restarted published node tunnel", {
|
|
51185
|
+
endpoint,
|
|
51186
|
+
stableUrl: true,
|
|
51187
|
+
mainTransportType: meshyNode.getTransportType(),
|
|
51188
|
+
sidecarEnabled: meshyNode.isDevTunnelEnabled()
|
|
51189
|
+
});
|
|
51190
|
+
} catch (err) {
|
|
51191
|
+
markPublishedNodeTunnelFailed({
|
|
51192
|
+
consecutiveFailures: reachability.consecutiveFailures,
|
|
51193
|
+
endpoint: publishedEndpoint,
|
|
51194
|
+
reason: err instanceof Error ? err.message : String(err),
|
|
51195
|
+
statusCode: reachability.statusCode
|
|
51196
|
+
});
|
|
51197
|
+
meshyNode.getLogger().warn("failed to restart published node tunnel", {
|
|
51198
|
+
error: err instanceof Error ? err.message : String(err),
|
|
51199
|
+
mainTransportType: meshyNode.getTransportType(),
|
|
51200
|
+
sidecarEnabled: meshyNode.isDevTunnelEnabled()
|
|
51201
|
+
});
|
|
51202
|
+
}
|
|
51203
|
+
} finally {
|
|
51204
|
+
nodeTunnelHealthCheckRunning = false;
|
|
50988
51205
|
}
|
|
50989
51206
|
})();
|
|
50990
51207
|
}, config.cluster.heartbeatInterval);
|
|
@@ -50992,17 +51209,24 @@ function createTunnelManager(options) {
|
|
|
50992
51209
|
if (!dashboardHealthTimer) {
|
|
50993
51210
|
dashboardHealthTimer = setInterval(() => {
|
|
50994
51211
|
void (async () => {
|
|
50995
|
-
if (
|
|
51212
|
+
if (dashboardHealthCheckRunning) {
|
|
50996
51213
|
return;
|
|
50997
51214
|
}
|
|
50998
|
-
|
|
50999
|
-
|
|
51000
|
-
|
|
51215
|
+
dashboardHealthCheckRunning = true;
|
|
51216
|
+
try {
|
|
51217
|
+
if (!dashboardTransport) {
|
|
51218
|
+
return;
|
|
51219
|
+
}
|
|
51220
|
+
const healthy = await dashboardTransport.isHealthy().catch(() => false);
|
|
51221
|
+
if (!healthy) {
|
|
51222
|
+
meshyNode.getLogger().warn("dashboard tunnel process became unhealthy; restarting with stable id", {
|
|
51223
|
+
port: config.node.port
|
|
51224
|
+
});
|
|
51225
|
+
await restartDashboardTransport("healthcheck");
|
|
51226
|
+
}
|
|
51227
|
+
} finally {
|
|
51228
|
+
dashboardHealthCheckRunning = false;
|
|
51001
51229
|
}
|
|
51002
|
-
meshyNode.getLogger().warn("dashboard tunnel became unhealthy; restarting with stable id", {
|
|
51003
|
-
port: config.node.port
|
|
51004
|
-
});
|
|
51005
|
-
await restartDashboardTransport("healthcheck");
|
|
51006
51230
|
})();
|
|
51007
51231
|
}, config.cluster.heartbeatInterval);
|
|
51008
51232
|
}
|
|
@@ -51016,6 +51240,7 @@ function createTunnelManager(options) {
|
|
|
51016
51240
|
clearInterval(nodeTunnelHealthTimer);
|
|
51017
51241
|
nodeTunnelHealthTimer = null;
|
|
51018
51242
|
}
|
|
51243
|
+
nodeTunnelReachability.reset();
|
|
51019
51244
|
}
|
|
51020
51245
|
async function stop() {
|
|
51021
51246
|
stopHealthChecks();
|
|
@@ -51168,6 +51393,9 @@ async function startNode(args) {
|
|
|
51168
51393
|
switchTransport: async (type) => {
|
|
51169
51394
|
const endpoint = await meshyNode.switchTransport(type);
|
|
51170
51395
|
persistNodeStartupTransport(config.storage.path, type);
|
|
51396
|
+
if (type !== "devtunnel" && !meshyNode.isDevTunnelEnabled()) {
|
|
51397
|
+
meshyNode.getNodeRegistry().updateDevTunnelHealth(meshyNode.getNodeRegistry().getSelf().id, void 0);
|
|
51398
|
+
}
|
|
51171
51399
|
await tunnelManager.syncDashboardTransport(`switchTransport:${type}`);
|
|
51172
51400
|
return endpoint;
|
|
51173
51401
|
},
|
|
@@ -51180,6 +51408,9 @@ async function startNode(args) {
|
|
|
51180
51408
|
},
|
|
51181
51409
|
disableDevTunnel: async () => {
|
|
51182
51410
|
await meshyNode.disableDevTunnel();
|
|
51411
|
+
if (meshyNode.getTransportType() !== "devtunnel") {
|
|
51412
|
+
meshyNode.getNodeRegistry().updateDevTunnelHealth(meshyNode.getNodeRegistry().getSelf().id, void 0);
|
|
51413
|
+
}
|
|
51183
51414
|
persistNodeStartupTransport(
|
|
51184
51415
|
config.storage.path,
|
|
51185
51416
|
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.2",
|
|
4
4
|
"packages": {
|
|
5
5
|
"workspace": {
|
|
6
6
|
"name": "meshy",
|
|
7
|
-
"version": "0.4.
|
|
7
|
+
"version": "0.4.2"
|
|
8
8
|
},
|
|
9
9
|
"node": {
|
|
10
10
|
"name": "meshy-node",
|
|
11
|
-
"version": "0.4.
|
|
11
|
+
"version": "0.4.2"
|
|
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": "c895cea"
|
|
30
30
|
}
|
|
31
31
|
}
|