meshy-node 0.1.3 → 0.1.5

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/main.cjs CHANGED
@@ -4619,7 +4619,7 @@ var require_helpers = __commonJS({
4619
4619
  };
4620
4620
  Object.defineProperty(exports2, "__esModule", { value: true });
4621
4621
  exports2.req = exports2.json = exports2.toBuffer = void 0;
4622
- var http4 = __importStar(require("http"));
4622
+ var http3 = __importStar(require("http"));
4623
4623
  var https2 = __importStar(require("https"));
4624
4624
  async function toBuffer(stream) {
4625
4625
  let length = 0;
@@ -4645,7 +4645,7 @@ var require_helpers = __commonJS({
4645
4645
  exports2.json = json;
4646
4646
  function req(url, opts = {}) {
4647
4647
  const href = typeof url === "string" ? url : url.href;
4648
- const req2 = (href.startsWith("https:") ? https2 : http4).request(url, opts);
4648
+ const req2 = (href.startsWith("https:") ? https2 : http3).request(url, opts);
4649
4649
  const promise = new Promise((resolve11, reject) => {
4650
4650
  req2.once("response", resolve11).once("error", reject).end();
4651
4651
  });
@@ -4693,11 +4693,11 @@ var require_dist = __commonJS({
4693
4693
  Object.defineProperty(exports2, "__esModule", { value: true });
4694
4694
  exports2.Agent = void 0;
4695
4695
  var net = __importStar(require("net"));
4696
- var http4 = __importStar(require("http"));
4696
+ var http3 = __importStar(require("http"));
4697
4697
  var https_1 = require("https");
4698
4698
  __exportStar(require_helpers(), exports2);
4699
4699
  var INTERNAL = /* @__PURE__ */ Symbol("AgentBaseInternalState");
4700
- var Agent = class extends http4.Agent {
4700
+ var Agent = class extends http3.Agent {
4701
4701
  constructor(opts) {
4702
4702
  super(opts);
4703
4703
  this[INTERNAL] = {};
@@ -4769,7 +4769,7 @@ var require_dist = __commonJS({
4769
4769
  const fakeSocket = this.incrementSockets(name2);
4770
4770
  Promise.resolve().then(() => this.connect(req, connectOpts)).then((socket) => {
4771
4771
  this.decrementSockets(name2, fakeSocket);
4772
- if (socket instanceof http4.Agent) {
4772
+ if (socket instanceof http3.Agent) {
4773
4773
  try {
4774
4774
  return socket.addRequest(req, connectOpts);
4775
4775
  } catch (err) {
@@ -23145,10 +23145,10 @@ var require_layer = __commonJS({
23145
23145
  var require_methods = __commonJS({
23146
23146
  "../../node_modules/.pnpm/methods@1.1.2/node_modules/methods/index.js"(exports2, module2) {
23147
23147
  "use strict";
23148
- var http4 = require("http");
23148
+ var http3 = require("http");
23149
23149
  module2.exports = getCurrentNodeMethods() || getBasicNodeMethods();
23150
23150
  function getCurrentNodeMethods() {
23151
- return http4.METHODS && http4.METHODS.map(function lowerCaseMethod(method) {
23151
+ return http3.METHODS && http3.METHODS.map(function lowerCaseMethod(method) {
23152
23152
  return method.toLowerCase();
23153
23153
  });
23154
23154
  }
@@ -25766,7 +25766,7 @@ var require_application = __commonJS({
25766
25766
  var query = require_query();
25767
25767
  var debug = require_src2()("express:application");
25768
25768
  var View = require_view();
25769
- var http4 = require("http");
25769
+ var http3 = require("http");
25770
25770
  var compileETag = require_utils2().compileETag;
25771
25771
  var compileQueryParser = require_utils2().compileQueryParser;
25772
25772
  var compileTrust = require_utils2().compileTrust;
@@ -26015,7 +26015,7 @@ var require_application = __commonJS({
26015
26015
  tryRender(view, renderOptions, done);
26016
26016
  };
26017
26017
  app.listen = function listen() {
26018
- var server = http4.createServer(this);
26018
+ var server = http3.createServer(this);
26019
26019
  return server.listen.apply(server, arguments);
26020
26020
  };
26021
26021
  function logerror(err) {
@@ -26617,12 +26617,12 @@ var require_request = __commonJS({
26617
26617
  var deprecate = require_depd()("express");
26618
26618
  var isIP = require("net").isIP;
26619
26619
  var typeis = require_type_is();
26620
- var http4 = require("http");
26620
+ var http3 = require("http");
26621
26621
  var fresh = require_fresh();
26622
26622
  var parseRange = require_range_parser();
26623
26623
  var parse = require_parseurl();
26624
26624
  var proxyaddr = require_proxy_addr();
26625
- var req = Object.create(http4.IncomingMessage.prototype);
26625
+ var req = Object.create(http3.IncomingMessage.prototype);
26626
26626
  module2.exports = req;
26627
26627
  req.get = req.header = function header(name2) {
26628
26628
  if (!name2) {
@@ -27044,7 +27044,7 @@ var require_response = __commonJS({
27044
27044
  var deprecate = require_depd()("express");
27045
27045
  var encodeUrl = require_encodeurl();
27046
27046
  var escapeHtml = require_escape_html();
27047
- var http4 = require("http");
27047
+ var http3 = require("http");
27048
27048
  var isAbsolute4 = require_utils2().isAbsolute;
27049
27049
  var onFinished = require_on_finished();
27050
27050
  var path17 = require("path");
@@ -27060,7 +27060,7 @@ var require_response = __commonJS({
27060
27060
  var mime = send.mime;
27061
27061
  var resolve11 = path17.resolve;
27062
27062
  var vary = require_vary();
27063
- var res = Object.create(http4.ServerResponse.prototype);
27063
+ var res = Object.create(http3.ServerResponse.prototype);
27064
27064
  module2.exports = res;
27065
27065
  var charsetRegExp = /;\s*charset\s*=/;
27066
27066
  res.status = function status(code) {
@@ -27784,7 +27784,6 @@ __export(main_exports, {
27784
27784
  shouldSkipStartupRequirementsCheck: () => shouldSkipStartupRequirementsCheck
27785
27785
  });
27786
27786
  module.exports = __toCommonJS(main_exports);
27787
- var http3 = __toESM(require("http"), 1);
27788
27787
  var nodePath = __toESM(require("path"), 1);
27789
27788
 
27790
27789
  // ../../packages/core/src/logger.ts
@@ -32704,8 +32703,7 @@ function parseNodeInfo(value) {
32704
32703
  lastHeartbeat: value.lastHeartbeat,
32705
32704
  transportType: typeof value.transportType === "string" ? value.transportType : void 0,
32706
32705
  devtunnelEndpoint: typeof value.devtunnelEndpoint === "string" ? value.devtunnelEndpoint : void 0,
32707
- dashboardOrigin: typeof value.dashboardOrigin === "string" ? value.dashboardOrigin : void 0,
32708
- previewOrigin: typeof value.previewOrigin === "string" ? value.previewOrigin : void 0
32706
+ dashboardOrigin: typeof value.dashboardOrigin === "string" ? value.dashboardOrigin : void 0
32709
32707
  };
32710
32708
  }
32711
32709
  function parseTask(value) {
@@ -32821,8 +32819,9 @@ var DEFAULT_NODE_REQUEST_TIMEOUT_MS = 1500;
32821
32819
  function getNodePublicEndpoint(node) {
32822
32820
  return node.devtunnelEndpoint ?? node.endpoint;
32823
32821
  }
32824
- function getNodeRequestEndpoints(node) {
32825
- return node.devtunnelEndpoint && node.devtunnelEndpoint !== node.endpoint ? [node.endpoint, node.devtunnelEndpoint] : [node.endpoint];
32822
+ function getNodeRequestEndpoints(node, options = {}) {
32823
+ const endpoints = options.preferPublicEndpoint ? [node.devtunnelEndpoint, node.endpoint] : [node.endpoint, node.devtunnelEndpoint];
32824
+ return endpoints.filter((endpoint, index, values) => typeof endpoint === "string" && endpoint.length > 0 && values.indexOf(endpoint) === index);
32826
32825
  }
32827
32826
  function createRequestSignal(signal, timeoutMs) {
32828
32827
  const controller = new AbortController();
@@ -32852,9 +32851,9 @@ async function fetchWithTimeout(url, init, timeoutMs = DEFAULT_NODE_REQUEST_TIME
32852
32851
  cleanup();
32853
32852
  }
32854
32853
  }
32855
- async function fetchNodeWithFallback(node, path17, init, timeoutMs = DEFAULT_NODE_REQUEST_TIMEOUT_MS, trace) {
32854
+ async function fetchNodeWithFallback(node, path17, init, timeoutMs = DEFAULT_NODE_REQUEST_TIMEOUT_MS, trace, options) {
32856
32855
  let lastError;
32857
- const endpoints = getNodeRequestEndpoints(node);
32856
+ const endpoints = getNodeRequestEndpoints(node, options);
32858
32857
  for (const [index, endpoint] of endpoints.entries()) {
32859
32858
  const attempt = index + 1;
32860
32859
  trace?.onAttempt?.({ attempt, endpoint, path: path17, timeoutMs, totalEndpoints: endpoints.length });
@@ -32990,24 +32989,6 @@ var NodeRegistry = class {
32990
32989
  }
32991
32990
  }
32992
32991
  }
32993
- updatePreviewOrigin(id, previewOrigin) {
32994
- const node = this.nodes.get(id);
32995
- if (node) {
32996
- if (previewOrigin) {
32997
- node.previewOrigin = previewOrigin;
32998
- } else {
32999
- delete node.previewOrigin;
33000
- }
33001
- this.store.upsertNode(node);
33002
- }
33003
- if (this.selfNode && this.selfNode.id === id) {
33004
- if (previewOrigin) {
33005
- this.selfNode.previewOrigin = previewOrigin;
33006
- } else {
33007
- delete this.selfNode.previewOrigin;
33008
- }
33009
- }
33010
- }
33011
32992
  // -- Self --------------------------------------------------------------
33012
32993
  setSelf(info) {
33013
32994
  this.selfNode = { ...info };
@@ -34139,7 +34120,6 @@ var HeartbeatMonitor = class {
34139
34120
  this.nodeRegistry.updateLoad(node.id, result.load);
34140
34121
  this.applyReportedDevTunnelState(node.id, result.devtunnelEnabled, result.devtunnelEndpoint);
34141
34122
  this.nodeRegistry.updateDashboardOrigin(node.id, result.dashboardOrigin);
34142
- this.nodeRegistry.updatePreviewOrigin(node.id, result.previewOrigin);
34143
34123
  if (result.workDirFolders) {
34144
34124
  this.nodeRegistry.updateFolders(node.id, result.workDirFolders);
34145
34125
  }
@@ -34205,7 +34185,6 @@ var HeartbeatMonitor = class {
34205
34185
  devtunnelEnabled: self2.devtunnelEndpoint !== void 0,
34206
34186
  devtunnelEndpoint: self2.devtunnelEndpoint,
34207
34187
  dashboardOrigin: self2.dashboardOrigin,
34208
- previewOrigin: self2.previewOrigin,
34209
34188
  workDirFolders: self2.workDir ? listWorkDirFolders(self2.workDir) : void 0
34210
34189
  };
34211
34190
  return response;
@@ -34224,7 +34203,6 @@ var HeartbeatMonitor = class {
34224
34203
  devtunnelEnabled,
34225
34204
  devtunnelEndpoint,
34226
34205
  dashboardOrigin,
34227
- previewOrigin,
34228
34206
  workDirFolders
34229
34207
  } = req;
34230
34208
  const existingNode = this.nodeRegistry.getNode(nodeId);
@@ -34249,7 +34227,6 @@ var HeartbeatMonitor = class {
34249
34227
  ...workDir ? { workDir } : {},
34250
34228
  ...devtunnelEnabled && devtunnelEndpoint ? { devtunnelEndpoint } : {},
34251
34229
  ...dashboardOrigin ? { dashboardOrigin } : {},
34252
- ...previewOrigin ? { previewOrigin } : {},
34253
34230
  ...workDirFolders ? { workDirFolders } : {}
34254
34231
  });
34255
34232
  this.log.info("keepalive restored missing follower", { nodeId, endpoint: normalizedEndpoint });
@@ -34283,7 +34260,6 @@ var HeartbeatMonitor = class {
34283
34260
  this.nodeRegistry.updateLoad(nodeId, load);
34284
34261
  this.applyReportedDevTunnelState(nodeId, devtunnelEnabled, devtunnelEndpoint);
34285
34262
  this.nodeRegistry.updateDashboardOrigin(nodeId, dashboardOrigin);
34286
- this.nodeRegistry.updatePreviewOrigin(nodeId, previewOrigin);
34287
34263
  if (workDirFolders) {
34288
34264
  this.nodeRegistry.updateFolders(nodeId, workDirFolders);
34289
34265
  }
@@ -34341,7 +34317,6 @@ var HeartbeatMonitor = class {
34341
34317
  devtunnelEnabled: self2.devtunnelEndpoint !== void 0,
34342
34318
  devtunnelEndpoint: self2.devtunnelEndpoint,
34343
34319
  dashboardOrigin: self2.dashboardOrigin,
34344
- previewOrigin: self2.previewOrigin,
34345
34320
  workDirFolders: self2.workDir ? listWorkDirFolders(self2.workDir) : void 0
34346
34321
  };
34347
34322
  this.log.debug("sending keepalive request", {
@@ -34667,7 +34642,8 @@ var EXCLUDED_PATH_PREFIXES = [
34667
34642
  "/api/cluster/"
34668
34643
  ];
34669
34644
  var EXCLUDED_PATH_SUFFIXES = [
34670
- "/devtunnel"
34645
+ "/devtunnel",
34646
+ "/output/preview-sessions"
34671
34647
  ];
34672
34648
  var WRITE_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH", "DELETE"]);
34673
34649
  var DataRouter = class {
@@ -35854,6 +35830,18 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
35854
35830
  }
35855
35831
  async joinCluster(seedUrl) {
35856
35832
  const log2 = this.logger.child("node/join-cluster");
35833
+ const currentSelf = this.nodeRegistry.getSelf();
35834
+ if (this.config.transport.type !== "devtunnel" && !currentSelf.devtunnelEndpoint && !this.devtunnelTransport) {
35835
+ log2.info("enabling anonymous node tunnel before cluster join", {
35836
+ seedUrl,
35837
+ transportType: this.config.transport.type
35838
+ });
35839
+ const devtunnelEndpoint = await this.enableDevTunnel();
35840
+ log2.info("enabled anonymous node tunnel before cluster join", {
35841
+ seedUrl,
35842
+ devtunnelEndpoint
35843
+ });
35844
+ }
35857
35845
  const tasks = this.taskEngine.listTasks().tasks;
35858
35846
  const self2 = this.nodeRegistry.getSelf();
35859
35847
  const joinBody = {
@@ -35872,17 +35860,13 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
35872
35860
  if (self2.dashboardOrigin) {
35873
35861
  joinBody.dashboardOrigin = self2.dashboardOrigin;
35874
35862
  }
35875
- if (self2.previewOrigin) {
35876
- joinBody.previewOrigin = self2.previewOrigin;
35877
- }
35878
35863
  log2.info("sending cluster join request", {
35879
35864
  seedUrl,
35880
35865
  nodeId: self2.id,
35881
35866
  endpoint: self2.endpoint,
35882
35867
  taskCount: tasks.length,
35883
35868
  hasDevTunnel: !!self2.devtunnelEndpoint,
35884
- hasDashboardOrigin: !!self2.dashboardOrigin,
35885
- hasPreviewOrigin: !!self2.previewOrigin
35869
+ hasDashboardOrigin: !!self2.dashboardOrigin
35886
35870
  });
35887
35871
  let response;
35888
35872
  try {
@@ -36069,6 +36053,27 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
36069
36053
  getTransportType() {
36070
36054
  return this.config.transport.type;
36071
36055
  }
36056
+ hasPublishedNodeTunnel() {
36057
+ return this.config.transport.type === "devtunnel" || this.devtunnelTransport !== null;
36058
+ }
36059
+ async isPublishedNodeTunnelHealthy() {
36060
+ if (this.config.transport.type === "devtunnel") {
36061
+ return this.transport.isHealthy();
36062
+ }
36063
+ if (this.devtunnelTransport) {
36064
+ return this.devtunnelTransport.isHealthy();
36065
+ }
36066
+ return true;
36067
+ }
36068
+ async restartPublishedNodeTunnel() {
36069
+ if (this.config.transport.type === "devtunnel") {
36070
+ return this.restartPrimaryTransport();
36071
+ }
36072
+ if (this.devtunnelTransport) {
36073
+ return this.restartDevTunnelSidecar();
36074
+ }
36075
+ return void 0;
36076
+ }
36072
36077
  async switchTransport(transportType) {
36073
36078
  if (this.config.transport.type === transportType && this.transport) {
36074
36079
  return this.transport.getEndpoint();
@@ -36172,8 +36177,7 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
36172
36177
  workDir: currentSelf.workDir,
36173
36178
  workDirFolders: listWorkDirFolders(this.getWorkDir()),
36174
36179
  ...currentSelf.devtunnelEndpoint ? { devtunnelEndpoint: currentSelf.devtunnelEndpoint } : {},
36175
- ...currentSelf.dashboardOrigin ? { dashboardOrigin: currentSelf.dashboardOrigin } : {},
36176
- ...currentSelf.previewOrigin ? { previewOrigin: currentSelf.previewOrigin } : {}
36180
+ ...currentSelf.dashboardOrigin ? { dashboardOrigin: currentSelf.dashboardOrigin } : {}
36177
36181
  };
36178
36182
  this.selfInfo = nextSelf;
36179
36183
  this.nodeRegistry.setSelf(nextSelf);
@@ -36209,6 +36213,64 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
36209
36213
  }
36210
36214
  };
36211
36215
  }
36216
+ async restartPrimaryTransport() {
36217
+ const nextTransportConfig = this.resolveTransportConfig(this.config.transport.type, this.selfInfo.id);
36218
+ const previousTransport = this.transport;
36219
+ let nextTransport = null;
36220
+ await previousTransport.stop().catch(() => void 0);
36221
+ try {
36222
+ nextTransport = this.transportFactory(nextTransportConfig);
36223
+ await nextTransport.start(this.config.node.port);
36224
+ const nextEndpoint = await nextTransport.getEndpoint();
36225
+ this.transport = nextTransport;
36226
+ this.selfInfo.endpoint = nextEndpoint;
36227
+ this.selfInfo.transportType = this.config.transport.type;
36228
+ this.nodeRegistry.updateEndpoint(this.selfInfo.id, nextEndpoint);
36229
+ this.eventBus.emit("transport.changed", {
36230
+ nodeId: this.selfInfo.id,
36231
+ transportType: this.config.transport.type,
36232
+ endpoint: nextEndpoint
36233
+ });
36234
+ return nextEndpoint;
36235
+ } catch (err) {
36236
+ if (nextTransport) {
36237
+ await nextTransport.stop().catch(() => void 0);
36238
+ }
36239
+ this.transport = previousTransport;
36240
+ throw err;
36241
+ }
36242
+ }
36243
+ async restartDevTunnelSidecar() {
36244
+ if (!this.devtunnelTransport) {
36245
+ throw new Error("DevTunnel sidecar is not enabled");
36246
+ }
36247
+ const previousTransport = this.devtunnelTransport;
36248
+ const tunnelConfig = this.resolveStableDevTunnelConfig("sidecar", this.selfInfo.id);
36249
+ let nextTransport = null;
36250
+ await previousTransport.stop().catch(() => void 0);
36251
+ try {
36252
+ nextTransport = this.transportFactory(tunnelConfig);
36253
+ await nextTransport.start(this.config.node.port);
36254
+ const devtunnelEndpoint = await nextTransport.getEndpoint();
36255
+ this.devtunnelTransport = nextTransport;
36256
+ this.syncSelfInfoFromRegistry();
36257
+ this.selfInfo.devtunnelEndpoint = devtunnelEndpoint;
36258
+ this.nodeRegistry.setSelf(this.selfInfo);
36259
+ this.nodeRegistry.updateDevTunnelEndpoint(this.selfInfo.id, devtunnelEndpoint);
36260
+ this.eventBus.emit("transport.changed", {
36261
+ nodeId: this.selfInfo.id,
36262
+ transportType: "devtunnel",
36263
+ endpoint: devtunnelEndpoint
36264
+ });
36265
+ return devtunnelEndpoint;
36266
+ } catch (err) {
36267
+ if (nextTransport) {
36268
+ await nextTransport.stop().catch(() => void 0);
36269
+ }
36270
+ this.devtunnelTransport = previousTransport;
36271
+ throw err;
36272
+ }
36273
+ }
36212
36274
  /**
36213
36275
  * Handle a task received via pull-based dispatch (keepalive channel).
36214
36276
  * Mirrors the logic of POST /api/worker/execute but without the HTTP layer.
@@ -40408,8 +40470,7 @@ var NodeInfoSchema = external_exports.object({
40408
40470
  lastHeartbeat: external_exports.number(),
40409
40471
  transportType: external_exports.string().optional(),
40410
40472
  devtunnelEndpoint: external_exports.string().optional(),
40411
- dashboardOrigin: external_exports.string().optional(),
40412
- previewOrigin: external_exports.string().optional()
40473
+ dashboardOrigin: external_exports.string().optional()
40413
40474
  });
40414
40475
  var JoinTaskSchema = external_exports.object({
40415
40476
  id: external_exports.string(),
@@ -40441,7 +40502,6 @@ var JoinClusterBody = external_exports.object({
40441
40502
  workDirFolders: external_exports.array(external_exports.string()).optional(),
40442
40503
  devtunnelEndpoint: external_exports.string().url().optional(),
40443
40504
  dashboardOrigin: external_exports.string().url().optional(),
40444
- previewOrigin: external_exports.string().url().optional(),
40445
40505
  tasks: external_exports.array(JoinTaskSchema).default([])
40446
40506
  });
40447
40507
  var JoinClusterResponse = external_exports.object({
@@ -40484,7 +40544,6 @@ var NodeInfoSchema2 = external_exports.object({
40484
40544
  transportType: external_exports.string().optional(),
40485
40545
  devtunnelEndpoint: external_exports.string().optional(),
40486
40546
  dashboardOrigin: external_exports.string().optional(),
40487
- previewOrigin: external_exports.string().optional(),
40488
40547
  workDir: external_exports.string().optional(),
40489
40548
  workDirFolders: external_exports.array(external_exports.string()).optional()
40490
40549
  });
@@ -40935,8 +40994,7 @@ function createClusterRoutes() {
40935
40994
  endpoint: body.endpoint,
40936
40995
  taskCount: body.tasks?.length ?? 0,
40937
40996
  hasDevTunnel: !!body.devtunnelEndpoint,
40938
- hasDashboardOrigin: !!body.dashboardOrigin,
40939
- hasPreviewOrigin: !!body.previewOrigin
40997
+ hasDashboardOrigin: !!body.dashboardOrigin
40940
40998
  });
40941
40999
  const existingNodes = nodeRegistry.getAllNodes();
40942
41000
  let removedCount = 0;
@@ -40959,8 +41017,7 @@ function createClusterRoutes() {
40959
41017
  ...body.workDir && { workDir: body.workDir },
40960
41018
  ...body.workDirFolders && { workDirFolders: body.workDirFolders },
40961
41019
  ...body.devtunnelEndpoint && { devtunnelEndpoint: body.devtunnelEndpoint },
40962
- ...body.dashboardOrigin && { dashboardOrigin: body.dashboardOrigin },
40963
- ...body.previewOrigin && { previewOrigin: body.previewOrigin }
41020
+ ...body.dashboardOrigin && { dashboardOrigin: body.dashboardOrigin }
40964
41021
  };
40965
41022
  nodeRegistry.addNode(node);
40966
41023
  taskEngine.importTasks(body.tasks ?? []);
@@ -41467,9 +41524,6 @@ function computeParentPath(rootPath, currentPath, useAbsolute) {
41467
41524
  }
41468
41525
 
41469
41526
  // ../../packages/api/src/routes/node-workdir.ts
41470
- function asyncHandler2(fn) {
41471
- return (req, res, next) => fn(req, res, next).catch(next);
41472
- }
41473
41527
  function sendLocalNodeWorkDirTree(req, res, nodeId, options = {}) {
41474
41528
  const query = NodeWorkDirTreeQuery.parse(req.query);
41475
41529
  const { nodeRegistry, workDir } = req.app.locals.deps;
@@ -41489,13 +41543,6 @@ function sendLocalNodeWorkDirTree(req, res, nodeId, options = {}) {
41489
41543
  }
41490
41544
  ));
41491
41545
  }
41492
- function createLocalNodeWorkDirRoutes(options = {}) {
41493
- const router = (0, import_express2.Router)();
41494
- router.get("/:id/workdir/tree", asyncHandler2(async (req, res) => {
41495
- sendLocalNodeWorkDirTree(req, res, req.params.id, options);
41496
- }));
41497
- return router;
41498
- }
41499
41546
 
41500
41547
  // ../../packages/api/src/task-route-utils.ts
41501
41548
  var fs11 = __toESM(require("fs"), 1);
@@ -41686,42 +41733,26 @@ var MIME_MAP2 = {
41686
41733
  function getMime(filePath) {
41687
41734
  return MIME_MAP2[path13.extname(filePath).toLowerCase()] ?? "application/octet-stream";
41688
41735
  }
41689
- function handlePreviewRequest(sessionManager, req, res) {
41690
- const url = new URL(req.url ?? "/", "http://localhost");
41691
- if (!url.pathname.startsWith("/preview/")) {
41692
- return false;
41693
- }
41694
- if (req.method !== "GET") {
41695
- res.writeHead(405, { "Content-Type": "text/plain" });
41696
- res.end("Method not allowed");
41697
- return true;
41698
- }
41699
- const match = url.pathname.match(/^\/preview\/([a-f0-9]+)(?:\/(.*))?$/i);
41700
- const token = match?.[1];
41701
- if (!token) {
41702
- res.writeHead(404, { "Content-Type": "text/plain" });
41703
- res.end("Preview not found");
41704
- return true;
41705
- }
41736
+ function sendPreviewAssetResponse(sessionManager, token, requestedPath, res) {
41706
41737
  const session = sessionManager.get(token);
41707
41738
  if (!session) {
41708
41739
  res.writeHead(403, { "Content-Type": "text/plain" });
41709
41740
  res.end("Invalid or expired preview token");
41710
- return true;
41741
+ return;
41711
41742
  }
41712
- const requestedPath = decodeURIComponent(match?.[2] ?? session.entryPath);
41743
+ const resolvedRequestedPath = decodeURIComponent(requestedPath ?? session.entryPath);
41713
41744
  let resolved;
41714
41745
  try {
41715
- resolved = resolvePreviewPath(session.rootPath, requestedPath).absolutePath;
41746
+ resolved = resolvePreviewPath(session.rootPath, resolvedRequestedPath).absolutePath;
41716
41747
  } catch {
41717
41748
  res.writeHead(400, { "Content-Type": "text/plain" });
41718
41749
  res.end("Invalid path");
41719
- return true;
41750
+ return;
41720
41751
  }
41721
41752
  if (!fs12.existsSync(resolved) || !fs12.statSync(resolved).isFile()) {
41722
41753
  res.writeHead(404, { "Content-Type": "text/plain" });
41723
41754
  res.end("File not found");
41724
- return true;
41755
+ return;
41725
41756
  }
41726
41757
  const mime = getMime(resolved);
41727
41758
  const content = fs12.readFileSync(resolved);
@@ -41731,6 +41762,122 @@ function handlePreviewRequest(sessionManager, req, res) {
41731
41762
  "Cache-Control": "no-cache"
41732
41763
  });
41733
41764
  res.end(content);
41765
+ }
41766
+ function handlePreviewRequest(sessionManager, req, res) {
41767
+ const url = new URL(req.url ?? "/", "http://localhost");
41768
+ if (!url.pathname.startsWith("/preview/")) {
41769
+ return false;
41770
+ }
41771
+ if (req.method !== "GET") {
41772
+ res.writeHead(405, { "Content-Type": "text/plain" });
41773
+ res.end("Method not allowed");
41774
+ return true;
41775
+ }
41776
+ const match = url.pathname.match(/^\/preview\/([a-f0-9]+)(?:\/(.*))?$/i);
41777
+ const token = match?.[1];
41778
+ if (!token) {
41779
+ res.writeHead(404, { "Content-Type": "text/plain" });
41780
+ res.end("Preview not found");
41781
+ return true;
41782
+ }
41783
+ sendPreviewAssetResponse(sessionManager, token, match?.[2], res);
41784
+ return true;
41785
+ }
41786
+
41787
+ // ../../packages/api/src/preview/preview-proxy.ts
41788
+ function parsePreviewRequest(previewUrl) {
41789
+ const pathname = new URL(previewUrl, "http://localhost").pathname;
41790
+ const match = pathname.match(/^\/preview\/([a-f0-9]+)(?:\/(.*))?$/i);
41791
+ const token = match?.[1];
41792
+ if (!token) {
41793
+ return null;
41794
+ }
41795
+ return {
41796
+ token,
41797
+ requestedPath: match?.[2]
41798
+ };
41799
+ }
41800
+ function extractPreviewToken(previewUrl) {
41801
+ return parsePreviewRequest(previewUrl)?.token ?? null;
41802
+ }
41803
+ function buildPreviewAssetProxyPath(token, requestedPath) {
41804
+ const search = new URLSearchParams({ token });
41805
+ if (requestedPath) {
41806
+ search.set("path", decodeURIComponent(requestedPath));
41807
+ }
41808
+ return `/api/worker/preview-asset?${search.toString()}`;
41809
+ }
41810
+ var PreviewProxyManager = class {
41811
+ sessions = /* @__PURE__ */ new Map();
41812
+ register(token, nodeId, expiresAt) {
41813
+ this.sessions.set(token, { token, nodeId, expiresAt });
41814
+ }
41815
+ get(token) {
41816
+ const session = this.sessions.get(token);
41817
+ if (!session) {
41818
+ return null;
41819
+ }
41820
+ if (Date.now() > session.expiresAt) {
41821
+ this.sessions.delete(token);
41822
+ return null;
41823
+ }
41824
+ return session;
41825
+ }
41826
+ cleanup() {
41827
+ const now = Date.now();
41828
+ for (const [token, session] of this.sessions) {
41829
+ if (session.expiresAt <= now) {
41830
+ this.sessions.delete(token);
41831
+ }
41832
+ }
41833
+ }
41834
+ };
41835
+ function rewritePreviewSessionPayloadForProxy(manager, payload, nodeId) {
41836
+ const token = extractPreviewToken(payload.previewUrl);
41837
+ if (!token) {
41838
+ return payload;
41839
+ }
41840
+ manager.register(token, nodeId, payload.expiresAt);
41841
+ return {
41842
+ ...payload,
41843
+ previewUrl: buildPreviewUrl("", {
41844
+ token,
41845
+ entryPath: payload.entryPath
41846
+ })
41847
+ };
41848
+ }
41849
+ async function handlePreviewProxyRequest(manager, nodeRegistry, logger27, req, res) {
41850
+ const requestPath = req.originalUrl ?? req.url;
41851
+ const previewRequest = parsePreviewRequest(requestPath);
41852
+ if (!previewRequest) {
41853
+ return false;
41854
+ }
41855
+ const session = manager.get(previewRequest.token);
41856
+ if (!session) {
41857
+ return false;
41858
+ }
41859
+ const node = nodeRegistry.getNode(session.nodeId);
41860
+ if (!node) {
41861
+ throw new MeshyError("NODE_NOT_FOUND", `Preview worker ${session.nodeId} not found`, 404);
41862
+ }
41863
+ const previewLog = logger27.child("preview-proxy");
41864
+ const proxyPath = buildPreviewAssetProxyPath(previewRequest.token, previewRequest.requestedPath);
41865
+ const { endpoint, response } = await fetchNodeWithFallback(
41866
+ node,
41867
+ proxyPath,
41868
+ void 0,
41869
+ void 0,
41870
+ void 0,
41871
+ { preferPublicEndpoint: true }
41872
+ );
41873
+ previewLog.debug("proxying preview asset from assigned worker", {
41874
+ token: previewRequest.token,
41875
+ nodeId: session.nodeId,
41876
+ requestPath,
41877
+ proxyPath,
41878
+ endpoint
41879
+ });
41880
+ await sendProxyResponse(res, response);
41734
41881
  return true;
41735
41882
  }
41736
41883
 
@@ -41837,21 +41984,18 @@ function getLocalTaskOutputDiff(taskEngine, taskId) {
41837
41984
  const rootPath = getTaskOutputRoot(taskEngine, taskId);
41838
41985
  return getGitDiff(rootPath);
41839
41986
  }
41840
- async function createPreviewSessionPayload(deps, taskId, entryPath) {
41987
+ async function createPreviewSessionPayload(deps, taskId, entryPath, requestOrigin) {
41841
41988
  const previewManager = deps.previewSessionManager;
41842
41989
  if (!previewManager) {
41843
41990
  throw new MeshyError("VALIDATION_ERROR", "Preview not available on this node", 400);
41844
41991
  }
41845
- if (!deps.previewPort) {
41846
- throw new MeshyError("VALIDATION_ERROR", "Preview server not running", 400);
41847
- }
41848
41992
  const rootPath = getTaskOutputRoot(deps.taskEngine, taskId);
41849
41993
  const session = previewManager.create({
41850
41994
  taskId,
41851
41995
  rootPath,
41852
41996
  entryPath
41853
41997
  });
41854
- const origin = deps.ensurePreviewOrigin ? await deps.ensurePreviewOrigin() ?? deps.previewOrigin : deps.previewOrigin;
41998
+ const origin = requestOrigin ?? deps.dashboardOrigin ?? deps.localDashboardOrigin;
41855
41999
  if (!origin) {
41856
42000
  throw new MeshyError("VALIDATION_ERROR", "Preview origin not available", 502);
41857
42001
  }
@@ -42123,7 +42267,7 @@ function createNodeWorkdirProxyTrace(log2, nodeId, proxyPath) {
42123
42267
  }
42124
42268
  };
42125
42269
  }
42126
- function asyncHandler3(fn) {
42270
+ function asyncHandler2(fn) {
42127
42271
  return (req, res, next) => fn(req, res, next).catch(next);
42128
42272
  }
42129
42273
  async function maybeHandleRemoteNodeWorkDirRequest(req, res, nodeId) {
@@ -42158,13 +42302,13 @@ async function maybeHandleRemoteNodeWorkDirRequest(req, res, nodeId) {
42158
42302
  return true;
42159
42303
  }
42160
42304
  try {
42161
- const proxyTarget = node.previewOrigin ? { endpoint: node.previewOrigin } : node;
42162
42305
  const { endpoint, response } = await fetchNodeWithFallback(
42163
- proxyTarget,
42306
+ node,
42164
42307
  proxyPath,
42165
42308
  void 0,
42166
42309
  NODE_WORKDIR_PROXY_TIMEOUT_MS,
42167
- createNodeWorkdirProxyTrace(log2, nodeId, proxyPath)
42310
+ createNodeWorkdirProxyTrace(log2, nodeId, proxyPath),
42311
+ { preferPublicEndpoint: true }
42168
42312
  );
42169
42313
  log2.debug("proxying node workdir request", {
42170
42314
  nodeId,
@@ -42197,7 +42341,7 @@ async function maybeHandleRemoteNodeWorkDirRequest(req, res, nodeId) {
42197
42341
  }
42198
42342
  function createNodeRoutes() {
42199
42343
  const router = (0, import_express3.Router)();
42200
- router.get("/", asyncHandler3(async (req, res) => {
42344
+ router.get("/", asyncHandler2(async (req, res) => {
42201
42345
  const { nodeRegistry } = req.app.locals.deps;
42202
42346
  const query = NodeListQuery.parse(req.query);
42203
42347
  let nodes = nodeRegistry.getAllNodes();
@@ -42211,7 +42355,7 @@ function createNodeRoutes() {
42211
42355
  }
42212
42356
  res.json({ nodes });
42213
42357
  }));
42214
- router.get("/:id", asyncHandler3(async (req, res) => {
42358
+ router.get("/:id", asyncHandler2(async (req, res) => {
42215
42359
  const { nodeRegistry } = req.app.locals.deps;
42216
42360
  const node = nodeRegistry.getNode(req.params.id);
42217
42361
  if (!node) {
@@ -42219,7 +42363,7 @@ function createNodeRoutes() {
42219
42363
  }
42220
42364
  res.json(node);
42221
42365
  }));
42222
- router.get("/:id/status", asyncHandler3(async (req, res) => {
42366
+ router.get("/:id/status", asyncHandler2(async (req, res) => {
42223
42367
  const { nodeRegistry, taskEngine } = req.app.locals.deps;
42224
42368
  const node = nodeRegistry.getNode(req.params.id);
42225
42369
  if (!node) {
@@ -42234,7 +42378,7 @@ function createNodeRoutes() {
42234
42378
  }));
42235
42379
  res.json({ node, tasks: taskSummary });
42236
42380
  }));
42237
- router.get("/:id/workdir/tree", asyncHandler3(async (req, res) => {
42381
+ router.get("/:id/workdir/tree", asyncHandler2(async (req, res) => {
42238
42382
  const nodeId = req.params.id;
42239
42383
  const handled = await maybeHandleRemoteNodeWorkDirRequest(req, res, nodeId);
42240
42384
  if (handled) {
@@ -42242,7 +42386,7 @@ function createNodeRoutes() {
42242
42386
  }
42243
42387
  sendLocalNodeWorkDirTree(req, res, nodeId);
42244
42388
  }));
42245
- router.patch("/:id", asyncHandler3(async (req, res) => {
42389
+ router.patch("/:id", asyncHandler2(async (req, res) => {
42246
42390
  const { nodeRegistry, persistNodeNamePreference } = req.app.locals.deps;
42247
42391
  const updates = UpdateNodeBody.parse(req.body);
42248
42392
  const nodeId = req.params.id;
@@ -42265,7 +42409,7 @@ function createNodeRoutes() {
42265
42409
  }
42266
42410
  res.json(node);
42267
42411
  }));
42268
- router.delete("/:id", asyncHandler3(async (req, res) => {
42412
+ router.delete("/:id", asyncHandler2(async (req, res) => {
42269
42413
  const { nodeRegistry, election } = req.app.locals.deps;
42270
42414
  if (!election.isLeader()) {
42271
42415
  throw new MeshyError("NOT_LEADER", "Only the leader node can delete nodes", 403);
@@ -42277,7 +42421,7 @@ function createNodeRoutes() {
42277
42421
  nodeRegistry.removeNode(req.params.id);
42278
42422
  res.json({ ok: true });
42279
42423
  }));
42280
- router.post("/:id/devtunnel", asyncHandler3(async (req, res) => {
42424
+ router.post("/:id/devtunnel", asyncHandler2(async (req, res) => {
42281
42425
  const { nodeRegistry, election, heartbeat, enableDevTunnel, disableDevTunnel, taskEngine } = req.app.locals.deps;
42282
42426
  const self2 = nodeRegistry.getSelf();
42283
42427
  const targetId = req.params.id;
@@ -42444,9 +42588,71 @@ function startLocalTaskFollowUp(deps, task, content, assignedTo, metadata) {
42444
42588
 
42445
42589
  // ../../packages/api/src/routes/task-output.ts
42446
42590
  var import_express4 = __toESM(require_express2(), 1);
42447
- function asyncHandler4(fn) {
42591
+
42592
+ // ../../packages/api/src/request-origin.ts
42593
+ function getFirstHeaderValue(value) {
42594
+ if (Array.isArray(value)) {
42595
+ return getFirstHeaderValue(value[0]);
42596
+ }
42597
+ if (typeof value !== "string") {
42598
+ return void 0;
42599
+ }
42600
+ const first = value.split(",")[0]?.trim();
42601
+ return first ? first : void 0;
42602
+ }
42603
+ function getForwardedHeaderOrigin(req) {
42604
+ const forwarded = getFirstHeaderValue(req.headers.forwarded);
42605
+ if (!forwarded) {
42606
+ return void 0;
42607
+ }
42608
+ let host;
42609
+ let proto;
42610
+ for (const segment of forwarded.split(";")) {
42611
+ const [rawKey, rawValue] = segment.split("=", 2);
42612
+ const key = rawKey?.trim().toLowerCase();
42613
+ const value = rawValue?.trim().replace(/^"|"$/g, "");
42614
+ if (!key || !value) {
42615
+ continue;
42616
+ }
42617
+ if (key === "host" && !host) {
42618
+ host = value;
42619
+ }
42620
+ if (key === "proto" && !proto) {
42621
+ proto = value;
42622
+ }
42623
+ }
42624
+ if (!host) {
42625
+ return void 0;
42626
+ }
42627
+ return `${proto ?? req.protocol ?? "http"}://${host}`;
42628
+ }
42629
+ function resolveRequestOrigin(req) {
42630
+ const forwardedOrigin = getForwardedHeaderOrigin(req);
42631
+ if (forwardedOrigin) {
42632
+ return forwardedOrigin;
42633
+ }
42634
+ const host = getFirstHeaderValue(req.headers["x-forwarded-host"]) ?? getFirstHeaderValue(req.headers.host) ?? req.get("host");
42635
+ if (!host) {
42636
+ return void 0;
42637
+ }
42638
+ const proto = getFirstHeaderValue(req.headers["x-forwarded-proto"]) ?? req.protocol ?? "http";
42639
+ return `${proto}://${host}`;
42640
+ }
42641
+
42642
+ // ../../packages/api/src/routes/task-output.ts
42643
+ function asyncHandler3(fn) {
42448
42644
  return (req, res, next) => fn(req, res, next).catch(next);
42449
42645
  }
42646
+ function isPreviewSessionPayload(value) {
42647
+ return typeof value === "object" && value !== null && typeof value.previewUrl === "string" && typeof value.entryPath === "string" && typeof value.expiresAt === "number";
42648
+ }
42649
+ function rewritePreviewPayloadIfNeeded(req, nodeId, payload) {
42650
+ const { previewProxyManager } = req.app.locals.deps;
42651
+ if (!previewProxyManager) {
42652
+ return payload;
42653
+ }
42654
+ return rewritePreviewSessionPayloadForProxy(previewProxyManager, payload, nodeId);
42655
+ }
42450
42656
  async function maybeHandleRemoteTaskOutputRequest(req, res, taskId, subPath, init, fallbackRequest) {
42451
42657
  const { taskEngine, nodeRegistry, heartbeat, logger: rootLogger } = req.app.locals.deps;
42452
42658
  const log2 = rootLogger.child("tasks/output");
@@ -42467,14 +42673,20 @@ async function maybeHandleRemoteTaskOutputRequest(req, res, taskId, subPath, ini
42467
42673
  if (!node) {
42468
42674
  throw new MeshyError("NODE_NOT_FOUND", `Assigned node ${assignedNodeId} not found`, 404);
42469
42675
  }
42470
- if (!node.previewOrigin) {
42676
+ if (!node.endpoint && !node.devtunnelEndpoint) {
42471
42677
  if (fallbackRequest && heartbeat?.requestWorkerControl) {
42472
- log2.warn("task output server origin missing, falling back to keepalive control", {
42678
+ log2.warn("worker output endpoint missing, falling back to keepalive control", {
42473
42679
  taskId,
42474
42680
  assignedTo: assignedNodeId,
42475
42681
  kind: fallbackRequest.kind
42476
42682
  });
42477
42683
  const controlResponse = await heartbeat.requestWorkerControl(assignedNodeId, fallbackRequest);
42684
+ if (fallbackRequest.kind === "task-preview-session" && controlResponse.bodyEncoding === "json" && isPreviewSessionPayload(controlResponse.body)) {
42685
+ res.status(controlResponse.statusCode).json(
42686
+ rewritePreviewPayloadIfNeeded(req, assignedNodeId, controlResponse.body)
42687
+ );
42688
+ return true;
42689
+ }
42478
42690
  sendWorkerControlResponse(res, controlResponse);
42479
42691
  return true;
42480
42692
  }
@@ -42484,31 +42696,47 @@ async function maybeHandleRemoteTaskOutputRequest(req, res, taskId, subPath, ini
42484
42696
  const proxyPath = `/api/tasks/${taskId}/output${subPath}${qs}`;
42485
42697
  try {
42486
42698
  const { endpoint, response: proxyRes } = await fetchNodeWithFallback(
42487
- { endpoint: node.previewOrigin },
42699
+ node,
42488
42700
  proxyPath,
42489
- init
42701
+ init,
42702
+ void 0,
42703
+ void 0,
42704
+ { preferPublicEndpoint: true }
42490
42705
  );
42491
- log2.debug("proxying task output request to worker output server", {
42706
+ log2.debug("proxying task output request to worker node API", {
42492
42707
  taskId,
42493
42708
  assignedTo: assignedNodeId,
42494
42709
  proxyPath,
42495
- outputOrigin: endpoint
42710
+ outputEndpoint: endpoint
42496
42711
  });
42712
+ if (fallbackRequest?.kind === "task-preview-session" && proxyRes.ok) {
42713
+ const body = await proxyRes.json().catch(() => null);
42714
+ if (isPreviewSessionPayload(body)) {
42715
+ res.status(proxyRes.status).json(rewritePreviewPayloadIfNeeded(req, assignedNodeId, body));
42716
+ return true;
42717
+ }
42718
+ }
42497
42719
  await sendProxyResponse(res, proxyRes);
42498
42720
  return true;
42499
42721
  } catch (err) {
42500
42722
  if (fallbackRequest && heartbeat?.requestWorkerControl) {
42501
- log2.warn("output server proxy failed, falling back to keepalive control", {
42723
+ log2.warn("worker output proxy failed, falling back to keepalive control", {
42502
42724
  taskId,
42503
42725
  assignedTo: assignedNodeId,
42504
42726
  kind: fallbackRequest.kind,
42505
42727
  error: err instanceof Error ? err.message : String(err)
42506
42728
  });
42507
42729
  const controlResponse = await heartbeat.requestWorkerControl(assignedNodeId, fallbackRequest);
42730
+ if (fallbackRequest.kind === "task-preview-session" && controlResponse.bodyEncoding === "json" && isPreviewSessionPayload(controlResponse.body)) {
42731
+ res.status(controlResponse.statusCode).json(
42732
+ rewritePreviewPayloadIfNeeded(req, assignedNodeId, controlResponse.body)
42733
+ );
42734
+ return true;
42735
+ }
42508
42736
  sendWorkerControlResponse(res, controlResponse);
42509
42737
  return true;
42510
42738
  }
42511
- log2.warn("output server proxy error", {
42739
+ log2.warn("worker output proxy error", {
42512
42740
  taskId,
42513
42741
  assignedTo: assignedNodeId,
42514
42742
  error: err instanceof Error ? err.message : String(err)
@@ -42519,7 +42747,7 @@ async function maybeHandleRemoteTaskOutputRequest(req, res, taskId, subPath, ini
42519
42747
  function createTaskOutputRoutes(options = {}) {
42520
42748
  const router = (0, import_express4.Router)();
42521
42749
  const allowRemoteProxy = options.allowRemoteProxy ?? true;
42522
- router.get("/:id/output", asyncHandler4(async (req, res) => {
42750
+ router.get("/:id/output", asyncHandler3(async (req, res) => {
42523
42751
  const taskId = req.params.id;
42524
42752
  if (allowRemoteProxy) {
42525
42753
  const handled = await maybeHandleRemoteTaskOutputRequest(req, res, taskId, "", void 0, {
@@ -42533,7 +42761,7 @@ function createTaskOutputRoutes(options = {}) {
42533
42761
  const { taskEngine } = req.app.locals.deps;
42534
42762
  res.json(getLocalTaskOutputSummary(taskEngine, taskId));
42535
42763
  }));
42536
- router.get("/:id/output/tree", asyncHandler4(async (req, res) => {
42764
+ router.get("/:id/output/tree", asyncHandler3(async (req, res) => {
42537
42765
  const taskId = req.params.id;
42538
42766
  const query = TaskOutputTreeQuery.parse(req.query);
42539
42767
  if (allowRemoteProxy) {
@@ -42549,7 +42777,7 @@ function createTaskOutputRoutes(options = {}) {
42549
42777
  const { taskEngine } = req.app.locals.deps;
42550
42778
  res.json(getLocalTaskOutputTree(taskEngine, taskId, query.path));
42551
42779
  }));
42552
- router.get("/:id/output/content", asyncHandler4(async (req, res) => {
42780
+ router.get("/:id/output/content", asyncHandler3(async (req, res) => {
42553
42781
  const taskId = req.params.id;
42554
42782
  const query = TaskOutputContentQuery.parse(req.query);
42555
42783
  if (allowRemoteProxy) {
@@ -42565,7 +42793,7 @@ function createTaskOutputRoutes(options = {}) {
42565
42793
  const { taskEngine } = req.app.locals.deps;
42566
42794
  res.json(getLocalTaskOutputContent(taskEngine, taskId, query.path));
42567
42795
  }));
42568
- router.get("/:id/output/download", asyncHandler4(async (req, res) => {
42796
+ router.get("/:id/output/download", asyncHandler3(async (req, res) => {
42569
42797
  const taskId = req.params.id;
42570
42798
  const query = TaskOutputDownloadQuery.parse(req.query);
42571
42799
  if (allowRemoteProxy) {
@@ -42585,7 +42813,7 @@ function createTaskOutputRoutes(options = {}) {
42585
42813
  }
42586
42814
  res.send(download.content);
42587
42815
  }));
42588
- router.get("/:id/output/diff", asyncHandler4(async (req, res) => {
42816
+ router.get("/:id/output/diff", asyncHandler3(async (req, res) => {
42589
42817
  const taskId = req.params.id;
42590
42818
  if (allowRemoteProxy) {
42591
42819
  const handled = await maybeHandleRemoteTaskOutputRequest(req, res, taskId, "/diff", void 0, {
@@ -42599,7 +42827,7 @@ function createTaskOutputRoutes(options = {}) {
42599
42827
  const { taskEngine } = req.app.locals.deps;
42600
42828
  res.json(getLocalTaskOutputDiff(taskEngine, taskId));
42601
42829
  }));
42602
- router.post("/:id/output/preview-sessions", asyncHandler4(async (req, res) => {
42830
+ router.post("/:id/output/preview-sessions", asyncHandler3(async (req, res) => {
42603
42831
  const taskId = req.params.id;
42604
42832
  const body = TaskPreviewSessionBody.parse(req.body ?? {});
42605
42833
  if (allowRemoteProxy) {
@@ -42616,7 +42844,7 @@ function createTaskOutputRoutes(options = {}) {
42616
42844
  return;
42617
42845
  }
42618
42846
  }
42619
- res.json(await createPreviewSessionPayload(req.app.locals.deps, taskId, body.path));
42847
+ res.json(await createPreviewSessionPayload(req.app.locals.deps, taskId, body.path, resolveRequestOrigin(req)));
42620
42848
  }));
42621
42849
  return router;
42622
42850
  }
@@ -42625,7 +42853,7 @@ function createTaskOutputRoutes(options = {}) {
42625
42853
  var TERMINAL_STATUSES3 = /* @__PURE__ */ new Set(["completed", "failed", "cancelled", "archived"]);
42626
42854
  var ARCHIVABLE_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled", "archived"]);
42627
42855
  var ACTIVE_STATUSES = /* @__PURE__ */ new Set(["pending", "assigned", "running"]);
42628
- function asyncHandler5(fn) {
42856
+ function asyncHandler4(fn) {
42629
42857
  return (req, res, next) => fn(req, res, next).catch(next);
42630
42858
  }
42631
42859
  function withAssignedNodeMetadata(task, nodeRegistry) {
@@ -42641,7 +42869,7 @@ function withAssignedNodeMetadata(task, nodeRegistry) {
42641
42869
  }
42642
42870
  function createTaskRoutes() {
42643
42871
  const router = (0, import_express5.Router)();
42644
- router.post("/", asyncHandler5(async (req, res) => {
42872
+ router.post("/", asyncHandler4(async (req, res) => {
42645
42873
  const { taskEngine, nodeRegistry } = req.app.locals.deps;
42646
42874
  const body = CreateTaskBody.parse(req.body);
42647
42875
  const task = taskEngine.createTask({
@@ -42660,7 +42888,7 @@ function createTaskRoutes() {
42660
42888
  }
42661
42889
  res.status(201).json(withAssignedNodeMetadata(task, nodeRegistry));
42662
42890
  }));
42663
- router.get("/", asyncHandler5(async (req, res) => {
42891
+ router.get("/", asyncHandler4(async (req, res) => {
42664
42892
  const { taskEngine, nodeRegistry } = req.app.locals.deps;
42665
42893
  const query = TaskListQuery.parse(req.query);
42666
42894
  const filter = {};
@@ -42675,7 +42903,7 @@ function createTaskRoutes() {
42675
42903
  total: result.total
42676
42904
  });
42677
42905
  }));
42678
- router.post("/batch/delete", asyncHandler5(async (req, res) => {
42906
+ router.post("/batch/delete", asyncHandler4(async (req, res) => {
42679
42907
  const { taskEngine } = req.app.locals.deps;
42680
42908
  const { ids } = BatchTaskIdsBody.parse(req.body);
42681
42909
  const results = ids.map((id) => {
@@ -42688,7 +42916,7 @@ function createTaskRoutes() {
42688
42916
  });
42689
42917
  res.json({ results });
42690
42918
  }));
42691
- router.post("/batch/archive", asyncHandler5(async (req, res) => {
42919
+ router.post("/batch/archive", asyncHandler4(async (req, res) => {
42692
42920
  const { taskEngine } = req.app.locals.deps;
42693
42921
  const { ids } = BatchTaskIdsBody.parse(req.body);
42694
42922
  const results = ids.map((id) => {
@@ -42706,7 +42934,7 @@ function createTaskRoutes() {
42706
42934
  });
42707
42935
  res.json({ results });
42708
42936
  }));
42709
- router.get("/:id", asyncHandler5(async (req, res) => {
42937
+ router.get("/:id", asyncHandler4(async (req, res) => {
42710
42938
  const { taskEngine, nodeRegistry } = req.app.locals.deps;
42711
42939
  const task = taskEngine.getTask(req.params.id);
42712
42940
  if (!task) {
@@ -42714,7 +42942,7 @@ function createTaskRoutes() {
42714
42942
  }
42715
42943
  res.json(withAssignedNodeMetadata(task, nodeRegistry));
42716
42944
  }));
42717
- router.patch("/:id", asyncHandler5(async (req, res) => {
42945
+ router.patch("/:id", asyncHandler4(async (req, res) => {
42718
42946
  const { taskEngine, nodeRegistry, logger: rootLogger } = req.app.locals.deps;
42719
42947
  const log2 = rootLogger.child("tasks/patch");
42720
42948
  const updates = UpdateTaskBody.parse(req.body);
@@ -42753,7 +42981,7 @@ function createTaskRoutes() {
42753
42981
  }
42754
42982
  res.json(withAssignedNodeMetadata(task, nodeRegistry));
42755
42983
  }));
42756
- router.delete("/:id", asyncHandler5(async (req, res) => {
42984
+ router.delete("/:id", asyncHandler4(async (req, res) => {
42757
42985
  const { taskEngine } = req.app.locals.deps;
42758
42986
  const result = taskEngine.deleteTask(req.params.id);
42759
42987
  if (!result) {
@@ -42761,7 +42989,7 @@ function createTaskRoutes() {
42761
42989
  }
42762
42990
  res.json({ ok: true });
42763
42991
  }));
42764
- router.post("/:id/cancel", asyncHandler5(async (req, res) => {
42992
+ router.post("/:id/cancel", asyncHandler4(async (req, res) => {
42765
42993
  const { taskEngine, nodeRegistry, engineRegistry, heartbeat, logger: rootLogger } = req.app.locals.deps;
42766
42994
  const log2 = rootLogger.child("tasks/cancel");
42767
42995
  const task = taskEngine.getTask(req.params.id);
@@ -42798,18 +43026,18 @@ function createTaskRoutes() {
42798
43026
  }, task.id);
42799
43027
  res.json({ ok: true });
42800
43028
  }));
42801
- router.post("/:id/assign", asyncHandler5(async (req, res) => {
43029
+ router.post("/:id/assign", asyncHandler4(async (req, res) => {
42802
43030
  const { taskEngine, nodeRegistry } = req.app.locals.deps;
42803
43031
  const body = AssignTaskBody.parse(req.body);
42804
43032
  const task = taskEngine.assignTask(req.params.id, body.nodeId);
42805
43033
  res.json(withAssignedNodeMetadata(task, nodeRegistry));
42806
43034
  }));
42807
- router.post("/:id/retry", asyncHandler5(async (req, res) => {
43035
+ router.post("/:id/retry", asyncHandler4(async (req, res) => {
42808
43036
  const { taskEngine, nodeRegistry } = req.app.locals.deps;
42809
43037
  const task = taskEngine.retryTask(req.params.id);
42810
43038
  res.json(withAssignedNodeMetadata(task, nodeRegistry));
42811
43039
  }));
42812
- router.get("/:id/logs", asyncHandler5(async (req, res) => {
43040
+ router.get("/:id/logs", asyncHandler4(async (req, res) => {
42813
43041
  const { engineRegistry, taskEngine, nodeRegistry, logger: rootLogger } = req.app.locals.deps;
42814
43042
  const log2 = rootLogger.child("tasks/logs");
42815
43043
  const query = TaskLogsQuery.parse(req.query);
@@ -42851,7 +43079,14 @@ function createTaskRoutes() {
42851
43079
  if (node) {
42852
43080
  const proxyPath = `/api/tasks/${taskId}/logs?after=${after}`;
42853
43081
  try {
42854
- const { endpoint, response: proxyRes } = await fetchNodeWithFallback(node, proxyPath);
43082
+ const { endpoint, response: proxyRes } = await fetchNodeWithFallback(
43083
+ node,
43084
+ proxyPath,
43085
+ void 0,
43086
+ void 0,
43087
+ void 0,
43088
+ { preferPublicEndpoint: true }
43089
+ );
42855
43090
  const proxyUrl = `${endpoint}${proxyPath}`;
42856
43091
  log2.debug("proxying request", { url: proxyUrl });
42857
43092
  log2.debug("proxy response", { status: proxyRes.status });
@@ -42876,7 +43111,7 @@ function createTaskRoutes() {
42876
43111
  });
42877
43112
  res.json(local);
42878
43113
  }));
42879
- router.post("/:id/message", asyncHandler5(async (req, res) => {
43114
+ router.post("/:id/message", asyncHandler4(async (req, res) => {
42880
43115
  const { taskEngine, engineRegistry, nodeRegistry, heartbeat, logger: rootLogger } = req.app.locals.deps;
42881
43116
  const log2 = rootLogger.child("tasks/message");
42882
43117
  const body = SendMessageBody.parse(req.body);
@@ -42972,12 +43207,12 @@ var WorkerMessageBody = external_exports.object({
42972
43207
  var WorkerTaskBody = external_exports.object({
42973
43208
  taskId: external_exports.string().min(1)
42974
43209
  });
42975
- function asyncHandler6(fn) {
43210
+ function asyncHandler5(fn) {
42976
43211
  return (req, res, next) => fn(req, res, next).catch(next);
42977
43212
  }
42978
43213
  function createWorkerRoutes() {
42979
43214
  const router = (0, import_express6.Router)();
42980
- router.post("/execute", asyncHandler6(async (req, res) => {
43215
+ router.post("/execute", asyncHandler5(async (req, res) => {
42981
43216
  const { taskEngine, engineRegistry, nodeRegistry, eventBus, logger: rootLogger, workDir } = req.app.locals.deps;
42982
43217
  const log2 = rootLogger.child("worker/execute");
42983
43218
  const task = req.body;
@@ -43050,7 +43285,7 @@ function createWorkerRoutes() {
43050
43285
  }
43051
43286
  }
43052
43287
  }));
43053
- router.post("/message", asyncHandler6(async (req, res) => {
43288
+ router.post("/message", asyncHandler5(async (req, res) => {
43054
43289
  const { engineRegistry, taskEngine, nodeRegistry, eventBus, logger: rootLogger } = req.app.locals.deps;
43055
43290
  const log2 = rootLogger.child("worker/message");
43056
43291
  const body = WorkerMessageBody.parse(req.body);
@@ -43093,7 +43328,7 @@ function createWorkerRoutes() {
43093
43328
  }
43094
43329
  res.json({ ok: true });
43095
43330
  }));
43096
- router.post("/cancel", asyncHandler6(async (req, res) => {
43331
+ router.post("/cancel", asyncHandler5(async (req, res) => {
43097
43332
  const { taskEngine, engineRegistry, logger: rootLogger } = req.app.locals.deps;
43098
43333
  const log2 = rootLogger.child("worker/cancel");
43099
43334
  const body = WorkerTaskBody.parse(req.body);
@@ -43113,7 +43348,7 @@ function createWorkerRoutes() {
43113
43348
  terminal: result.terminal
43114
43349
  });
43115
43350
  }));
43116
- router.post("/output", asyncHandler6(async (req, res) => {
43351
+ router.post("/output", asyncHandler5(async (req, res) => {
43117
43352
  const { eventBus, engineRegistry, taskEngine, logger: rootLogger } = req.app.locals.deps;
43118
43353
  const log2 = rootLogger.child("worker/output");
43119
43354
  const { taskId, event } = req.body;
@@ -43128,7 +43363,7 @@ function createWorkerRoutes() {
43128
43363
  }
43129
43364
  res.json({ ok: true });
43130
43365
  }));
43131
- router.post("/heartbeat", asyncHandler6(async (req, res) => {
43366
+ router.post("/heartbeat", asyncHandler5(async (req, res) => {
43132
43367
  const { heartbeat, logger: rootLogger } = req.app.locals.deps;
43133
43368
  const log2 = rootLogger.child("worker/heartbeat");
43134
43369
  const body = req.body;
@@ -43145,7 +43380,7 @@ function createWorkerRoutes() {
43145
43380
  });
43146
43381
  res.json(response);
43147
43382
  }));
43148
- router.post("/keepalive", asyncHandler6(async (req, res) => {
43383
+ router.post("/keepalive", asyncHandler5(async (req, res) => {
43149
43384
  const { heartbeat, logger: rootLogger } = req.app.locals.deps;
43150
43385
  const log2 = rootLogger.child("worker/keepalive");
43151
43386
  const body = req.body;
@@ -43165,27 +43400,41 @@ function createWorkerRoutes() {
43165
43400
  });
43166
43401
  res.json(response);
43167
43402
  }));
43168
- router.post("/vote", asyncHandler6(async (req, res) => {
43403
+ router.post("/vote", asyncHandler5(async (req, res) => {
43169
43404
  const { election } = req.app.locals.deps;
43170
43405
  const response = election.handleVoteRequest(req.body);
43171
43406
  res.json(response);
43172
43407
  }));
43173
- router.post("/announce", asyncHandler6(async (req, res) => {
43408
+ router.post("/announce", asyncHandler5(async (req, res) => {
43174
43409
  const { election } = req.app.locals.deps;
43175
43410
  election.handleLeaderAnnounce(req.body);
43176
43411
  res.json({ ok: true });
43177
43412
  }));
43178
- router.post("/preview-session", asyncHandler6(async (req, res) => {
43413
+ router.post("/preview-session", asyncHandler5(async (req, res) => {
43179
43414
  const { logger: rootLogger } = req.app.locals.deps;
43180
43415
  const log2 = rootLogger.child("worker/preview-session");
43181
43416
  const body = TaskPreviewSessionBody.extend({
43182
43417
  taskId: external_exports.string().min(1)
43183
43418
  }).parse(req.body ?? {});
43184
- const payload = await createPreviewSessionPayload(req.app.locals.deps, body.taskId, body.path);
43419
+ const payload = await createPreviewSessionPayload(
43420
+ req.app.locals.deps,
43421
+ body.taskId,
43422
+ body.path,
43423
+ resolveRequestOrigin(req)
43424
+ );
43185
43425
  log2.info("created preview session", { taskId: body.taskId, entryPath: payload.entryPath });
43186
43426
  res.json(payload);
43187
43427
  }));
43188
- router.post("/control-response", asyncHandler6(async (req, res) => {
43428
+ router.get("/preview-asset", asyncHandler5(async (req, res) => {
43429
+ const { previewSessionManager } = req.app.locals.deps;
43430
+ if (!previewSessionManager) {
43431
+ throw new MeshyError("VALIDATION_ERROR", "Preview not available on this node", 400);
43432
+ }
43433
+ const token = external_exports.string().min(1).parse(req.query.token);
43434
+ const requestedPath = typeof req.query.path === "string" && req.query.path.length > 0 ? req.query.path : void 0;
43435
+ sendPreviewAssetResponse(previewSessionManager, token, requestedPath, res);
43436
+ }));
43437
+ router.post("/control-response", asyncHandler5(async (req, res) => {
43189
43438
  const { heartbeat, logger: rootLogger } = req.app.locals.deps;
43190
43439
  const log2 = rootLogger.child("worker/control-response");
43191
43440
  const body = req.body;
@@ -43206,12 +43455,12 @@ function createWorkerRoutes() {
43206
43455
 
43207
43456
  // ../../packages/api/src/routes/system.ts
43208
43457
  var import_express7 = __toESM(require_express2(), 1);
43209
- function asyncHandler7(fn) {
43458
+ function asyncHandler6(fn) {
43210
43459
  return (req, res, next) => fn(req, res, next).catch(next);
43211
43460
  }
43212
43461
  function createSystemRoutes() {
43213
43462
  const router = (0, import_express7.Router)();
43214
- router.get("/health", asyncHandler7(async (req, res) => {
43463
+ router.get("/health", asyncHandler6(async (req, res) => {
43215
43464
  const { logger: rootLogger } = req.app.locals.deps;
43216
43465
  rootLogger.child("system/health").info("received system health API call", {
43217
43466
  method: req.method,
@@ -43220,7 +43469,7 @@ function createSystemRoutes() {
43220
43469
  });
43221
43470
  res.json({ status: "ok", timestamp: Date.now() });
43222
43471
  }));
43223
- router.get("/info", asyncHandler7(async (req, res) => {
43472
+ router.get("/info", asyncHandler6(async (req, res) => {
43224
43473
  const { nodeRegistry, getTransportType, config, dashboardOrigin } = req.app.locals.deps;
43225
43474
  const self2 = nodeRegistry.getSelf();
43226
43475
  res.json({
@@ -43236,7 +43485,7 @@ function createSystemRoutes() {
43236
43485
  }
43237
43486
  });
43238
43487
  }));
43239
- router.post("/transport", asyncHandler7(async (req, res) => {
43488
+ router.post("/transport", asyncHandler6(async (req, res) => {
43240
43489
  const { switchTransport } = req.app.locals.deps;
43241
43490
  if (!switchTransport) {
43242
43491
  res.status(501).json({ error: "Transport switching not available" });
@@ -43250,7 +43499,7 @@ function createSystemRoutes() {
43250
43499
  const newEndpoint = await switchTransport(type);
43251
43500
  res.json({ ok: true, transportType: type, endpoint: newEndpoint });
43252
43501
  }));
43253
- router.post("/devtunnel", asyncHandler7(async (req, res) => {
43502
+ router.post("/devtunnel", asyncHandler6(async (req, res) => {
43254
43503
  const { enableDevTunnel, disableDevTunnel, nodeRegistry, taskEngine } = req.app.locals.deps;
43255
43504
  if (!enableDevTunnel || !disableDevTunnel) {
43256
43505
  res.status(501).json({ error: "DevTunnel control not available" });
@@ -43279,7 +43528,7 @@ function createSystemRoutes() {
43279
43528
  });
43280
43529
  }
43281
43530
  }));
43282
- router.get("/metrics", asyncHandler7(async (req, res) => {
43531
+ router.get("/metrics", asyncHandler6(async (req, res) => {
43283
43532
  const { taskEngine } = req.app.locals.deps;
43284
43533
  const metrics = taskEngine.getMetrics();
43285
43534
  res.json(metrics);
@@ -43440,6 +43689,25 @@ function createServer2(deps) {
43440
43689
  }
43441
43690
  app.use(import_express9.default.json({ limit: JSON_BODY_LIMIT }));
43442
43691
  app.use(createAuthMiddleware(authConfig));
43692
+ app.use((req, res, next) => {
43693
+ void (async () => {
43694
+ if (!req.path.startsWith("/preview/")) {
43695
+ next();
43696
+ return;
43697
+ }
43698
+ if (!canServeDashboard(req)) {
43699
+ res.status(404).type("text/plain").send("Not Found");
43700
+ return;
43701
+ }
43702
+ if (deps.previewProxyManager && await handlePreviewProxyRequest(deps.previewProxyManager, deps.nodeRegistry, deps.logger, req, res)) {
43703
+ return;
43704
+ }
43705
+ if (deps.previewSessionManager && handlePreviewRequest(deps.previewSessionManager, req, res)) {
43706
+ return;
43707
+ }
43708
+ next();
43709
+ })().catch(next);
43710
+ });
43443
43711
  app.use(createRoutingMiddleware(deps.dataRouter));
43444
43712
  const largeBodyParser = import_express9.default.json({ limit: JSON_BODY_LIMIT_LARGE });
43445
43713
  app.use("/api/cluster", createClusterRoutes());
@@ -43468,37 +43736,6 @@ function createServer2(deps) {
43468
43736
  return app;
43469
43737
  }
43470
43738
 
43471
- // ../../packages/api/src/output-server.ts
43472
- var import_express10 = __toESM(require_express2(), 1);
43473
- var JSON_BODY_LIMIT_LARGE2 = "25mb";
43474
- function createOutputServer(deps) {
43475
- if (!deps.previewSessionManager) {
43476
- throw new Error("Preview session manager is required for the output server");
43477
- }
43478
- const app = (0, import_express10.default)();
43479
- app.locals.deps = deps;
43480
- app.use((req, res, next) => {
43481
- if (handlePreviewRequest(deps.previewSessionManager, req, res)) {
43482
- return;
43483
- }
43484
- next();
43485
- });
43486
- const authConfig = {
43487
- apiKey: deps.config.apiKey,
43488
- validateBearerToken: deps.config.validateBearerToken,
43489
- allowTrustedHostBypass: false
43490
- };
43491
- const largeBodyParser = import_express10.default.json({ limit: JSON_BODY_LIMIT_LARGE2 });
43492
- app.use("/api/tasks", largeBodyParser, createAuthMiddleware(authConfig), createTaskOutputRoutes({
43493
- allowRemoteProxy: false
43494
- }));
43495
- app.use("/api/nodes", createAuthMiddleware(authConfig), createLocalNodeWorkDirRoutes({
43496
- requireSelfNode: true
43497
- }));
43498
- app.use(createErrorMiddleware());
43499
- return app;
43500
- }
43501
-
43502
43739
  // ../../packages/transport/src/direct.ts
43503
43740
  var import_node_os4 = require("os");
43504
43741
  var import_node_http2 = require("http");
@@ -44382,21 +44619,10 @@ async function main() {
44382
44619
  });
44383
44620
  await meshyNode.start();
44384
44621
  const previewSessionManager = new PreviewSessionManager();
44385
- const previewPort = config.node.port + 1;
44386
- let actualPreviewPort = previewPort;
44622
+ const previewProxyManager = new PreviewProxyManager();
44387
44623
  let dashboardTransport = null;
44388
44624
  let dashboardOrigin;
44389
- let previewTransport = null;
44390
- let previewOrigin;
44391
- let outputServer = null;
44392
44625
  let deps;
44393
- async function listen(app2, port) {
44394
- return new Promise((resolve11, reject) => {
44395
- const server2 = http3.createServer(app2);
44396
- server2.listen(port, () => resolve11(server2));
44397
- server2.on("error", reject);
44398
- });
44399
- }
44400
44626
  async function closeServer(server2) {
44401
44627
  if (!server2) {
44402
44628
  return;
@@ -44424,33 +44650,15 @@ async function main() {
44424
44650
  }
44425
44651
  };
44426
44652
  }
44427
- function createPreviewTransportConfig() {
44428
- return {
44429
- type: "devtunnel",
44430
- devtunnel: {
44431
- id: resolveOrCreateDevTunnelId(
44432
- config.storage.path,
44433
- meshyNode.getNodeRegistry().getSelf().id,
44434
- "preview"
44435
- ),
44436
- allowAnonymous: true
44437
- }
44438
- };
44439
- }
44440
44653
  function setAdvertisedDashboardOrigin(origin) {
44441
44654
  dashboardOrigin = origin;
44442
44655
  deps.dashboardOrigin = origin;
44443
44656
  meshyNode.getNodeRegistry().updateDashboardOrigin(meshyNode.getNodeRegistry().getSelf().id, origin);
44444
44657
  }
44445
- function setAdvertisedPreviewOrigin(origin) {
44446
- previewOrigin = origin;
44447
- deps.previewOrigin = origin;
44448
- meshyNode.getNodeRegistry().updatePreviewOrigin(meshyNode.getNodeRegistry().getSelf().id, origin);
44449
- }
44450
44658
  function shouldPublishDashboardTunnel() {
44451
44659
  return authMetadata.enabled && (meshyNode.getTransportType() === "devtunnel" || meshyNode.isDevTunnelEnabled());
44452
44660
  }
44453
- async function stopDashboardTransport() {
44661
+ async function stopDashboardTransport(reason) {
44454
44662
  if (!dashboardTransport) {
44455
44663
  if (dashboardOrigin) {
44456
44664
  setAdvertisedDashboardOrigin(void 0);
@@ -44461,15 +44669,20 @@ async function main() {
44461
44669
  dashboardTransport = null;
44462
44670
  setAdvertisedDashboardOrigin(void 0);
44463
44671
  meshyNode.getLogger().info("stopped dashboard tunnel", {
44464
- reason: "dashboard transport no longer required",
44672
+ reason,
44465
44673
  mainTransportType: meshyNode.getTransportType(),
44466
44674
  sidecarEnabled: meshyNode.isDevTunnelEnabled()
44467
44675
  });
44468
44676
  }
44469
- async function restartDashboardTransport(transportConfig) {
44677
+ async function restartDashboardTransport(reason) {
44678
+ const transportConfig = createDashboardTransportConfig();
44470
44679
  const previousTransport = dashboardTransport;
44471
- const previousOrigin = dashboardOrigin;
44472
44680
  let nextTransport = null;
44681
+ if (previousTransport) {
44682
+ await previousTransport.stop().catch(() => void 0);
44683
+ dashboardTransport = null;
44684
+ setAdvertisedDashboardOrigin(void 0);
44685
+ }
44473
44686
  try {
44474
44687
  nextTransport = createTransport(transportConfig);
44475
44688
  await nextTransport.start(config.node.port);
@@ -44477,20 +44690,20 @@ async function main() {
44477
44690
  dashboardTransport = nextTransport;
44478
44691
  setAdvertisedDashboardOrigin(nextOrigin);
44479
44692
  meshyNode.getLogger().info("started dashboard tunnel", {
44693
+ reason,
44480
44694
  dashboardOrigin: nextOrigin,
44695
+ stableUrl: true,
44481
44696
  mainTransportType: meshyNode.getTransportType(),
44482
44697
  sidecarEnabled: meshyNode.isDevTunnelEnabled()
44483
44698
  });
44484
- if (previousTransport) {
44485
- await previousTransport.stop().catch(() => void 0);
44486
- }
44487
44699
  } catch (err) {
44488
44700
  if (nextTransport) {
44489
44701
  await nextTransport.stop().catch(() => void 0);
44490
44702
  }
44491
- dashboardTransport = previousTransport;
44492
- setAdvertisedDashboardOrigin(previousOrigin);
44703
+ dashboardTransport = null;
44704
+ setAdvertisedDashboardOrigin(void 0);
44493
44705
  meshyNode.getLogger().warn("failed to start dashboard transport", {
44706
+ reason,
44494
44707
  error: err instanceof Error ? err.message : String(err),
44495
44708
  port: config.node.port,
44496
44709
  transportType: transportConfig.type
@@ -44499,7 +44712,7 @@ async function main() {
44499
44712
  }
44500
44713
  async function syncDashboardTransport(reason) {
44501
44714
  if (!authMetadata.enabled) {
44502
- await stopDashboardTransport();
44715
+ await stopDashboardTransport("auth disabled");
44503
44716
  return;
44504
44717
  }
44505
44718
  if (!shouldPublishDashboardTunnel()) {
@@ -44509,7 +44722,7 @@ async function main() {
44509
44722
  sidecarEnabled: meshyNode.isDevTunnelEnabled(),
44510
44723
  authEnabled: authMetadata.enabled
44511
44724
  });
44512
- await stopDashboardTransport();
44725
+ await stopDashboardTransport(reason);
44513
44726
  return;
44514
44727
  }
44515
44728
  if (dashboardTransport && await dashboardTransport.isHealthy().catch(() => false)) {
@@ -44521,37 +44734,7 @@ async function main() {
44521
44734
  });
44522
44735
  return;
44523
44736
  }
44524
- await restartDashboardTransport(createDashboardTransportConfig());
44525
- }
44526
- async function restartPreviewTransport(transportConfig) {
44527
- const previousTransport = previewTransport;
44528
- const previousOrigin = previewOrigin;
44529
- let nextTransport = null;
44530
- try {
44531
- nextTransport = createTransport(transportConfig);
44532
- await nextTransport.start(actualPreviewPort);
44533
- const nextOrigin = await nextTransport.getEndpoint();
44534
- previewTransport = nextTransport;
44535
- setAdvertisedPreviewOrigin(nextOrigin);
44536
- meshyNode.getLogger().info("started output preview tunnel", {
44537
- previewOrigin: nextOrigin,
44538
- previewPort: actualPreviewPort
44539
- });
44540
- if (previousTransport) {
44541
- await previousTransport.stop().catch(() => void 0);
44542
- }
44543
- } catch (err) {
44544
- if (nextTransport) {
44545
- await nextTransport.stop().catch(() => void 0);
44546
- }
44547
- previewTransport = previousTransport;
44548
- setAdvertisedPreviewOrigin(previousOrigin);
44549
- meshyNode.getLogger().warn("failed to start preview transport", {
44550
- error: err instanceof Error ? err.message : String(err),
44551
- previewPort: actualPreviewPort,
44552
- transportType: transportConfig.type
44553
- });
44554
- }
44737
+ await restartDashboardTransport(reason);
44555
44738
  }
44556
44739
  deps = {
44557
44740
  dataRouter: meshyNode.getDataRouter(),
@@ -44571,6 +44754,7 @@ async function main() {
44571
44754
  persistNodeNamePreference: (name2) => persistDefaultNodeName(config.storage.path, name2),
44572
44755
  joinCurrentNodeToCluster: async (leaderEndpoint) => {
44573
44756
  await meshyNode.joinCluster(leaderEndpoint);
44757
+ await syncDashboardTransport("joinCluster");
44574
44758
  },
44575
44759
  leaveCurrentCluster: async () => {
44576
44760
  await meshyNode.leaveCluster();
@@ -44597,29 +44781,12 @@ async function main() {
44597
44781
  await syncDashboardTransport("disableDevTunnel");
44598
44782
  },
44599
44783
  isDevTunnelEnabled: () => meshyNode.isDevTunnelEnabled(),
44600
- dashboardOrigin,
44601
- ensurePreviewOrigin: async () => {
44602
- if (previewTransport && !await previewTransport.isHealthy()) {
44603
- await previewTransport.stop().catch(() => void 0);
44604
- previewTransport = null;
44605
- setAdvertisedPreviewOrigin(void 0);
44606
- }
44607
- if (previewOrigin?.includes("devtunnels.ms") && previewTransport) {
44608
- return previewOrigin;
44609
- }
44610
- await restartPreviewTransport(createPreviewTransportConfig());
44611
- return previewOrigin;
44612
- }
44784
+ localDashboardOrigin: `http://localhost:${config.node.port}`,
44785
+ dashboardOrigin
44613
44786
  };
44614
44787
  deps.previewSessionManager = previewSessionManager;
44615
- deps.previewPort = actualPreviewPort;
44788
+ deps.previewProxyManager = previewProxyManager;
44616
44789
  deps.dashboardOrigin = dashboardOrigin;
44617
- deps.previewOrigin = previewOrigin;
44618
- const outputApp = createOutputServer(deps);
44619
- outputServer = await listen(outputApp, previewPort);
44620
- const outputAddress = outputServer.address();
44621
- actualPreviewPort = typeof outputAddress === "object" && outputAddress ? outputAddress.port : previewPort;
44622
- deps.previewPort = actualPreviewPort;
44623
44790
  meshyNode.getLogger().info("configured node auth mode", {
44624
44791
  authEnabled: authMetadata.enabled,
44625
44792
  allowSameTenant: authMetadata.allowSameTenant,
@@ -44627,20 +44794,31 @@ async function main() {
44627
44794
  mainTransportType: meshyNode.getTransportType(),
44628
44795
  sidecarEnabled: meshyNode.isDevTunnelEnabled()
44629
44796
  });
44630
- await restartPreviewTransport(createPreviewTransportConfig());
44631
44797
  await syncDashboardTransport("startup");
44632
- const previewHealthTimer = setInterval(() => {
44798
+ const nodeTunnelHealthTimer = setInterval(() => {
44633
44799
  void (async () => {
44634
- if (!previewTransport) return;
44635
- const healthy = await previewTransport.isHealthy().catch(() => false);
44800
+ if (!meshyNode.hasPublishedNodeTunnel()) return;
44801
+ const healthy = await meshyNode.isPublishedNodeTunnelHealthy().catch(() => false);
44636
44802
  if (healthy) return;
44637
- await previewTransport.stop().catch(() => void 0);
44638
- previewTransport = null;
44639
- setAdvertisedPreviewOrigin(void 0);
44640
- meshyNode.getLogger().warn("preview transport became unhealthy and was cleared", {
44641
- previewPort: actualPreviewPort
44803
+ meshyNode.getLogger().warn("published node tunnel became unhealthy; restarting with stable id", {
44804
+ mainTransportType: meshyNode.getTransportType(),
44805
+ sidecarEnabled: meshyNode.isDevTunnelEnabled()
44642
44806
  });
44643
- await restartPreviewTransport(createPreviewTransportConfig());
44807
+ try {
44808
+ const endpoint = await meshyNode.restartPublishedNodeTunnel();
44809
+ meshyNode.getLogger().info("restarted published node tunnel", {
44810
+ endpoint,
44811
+ stableUrl: true,
44812
+ mainTransportType: meshyNode.getTransportType(),
44813
+ sidecarEnabled: meshyNode.isDevTunnelEnabled()
44814
+ });
44815
+ } catch (err) {
44816
+ meshyNode.getLogger().warn("failed to restart published node tunnel", {
44817
+ error: err instanceof Error ? err.message : String(err),
44818
+ mainTransportType: meshyNode.getTransportType(),
44819
+ sidecarEnabled: meshyNode.isDevTunnelEnabled()
44820
+ });
44821
+ }
44644
44822
  })();
44645
44823
  }, config.cluster.heartbeatInterval);
44646
44824
  const dashboardHealthTimer = setInterval(() => {
@@ -44648,12 +44826,10 @@ async function main() {
44648
44826
  if (!dashboardTransport) return;
44649
44827
  const healthy = await dashboardTransport.isHealthy().catch(() => false);
44650
44828
  if (healthy) return;
44651
- await dashboardTransport.stop().catch(() => void 0);
44652
- dashboardTransport = null;
44653
- setAdvertisedDashboardOrigin(void 0);
44654
- meshyNode.getLogger().warn("dashboard transport became unhealthy and was cleared", {
44829
+ meshyNode.getLogger().warn("dashboard tunnel became unhealthy; restarting with stable id", {
44655
44830
  port: config.node.port
44656
44831
  });
44832
+ await restartDashboardTransport("healthcheck");
44657
44833
  })();
44658
44834
  }, config.cluster.heartbeatInterval);
44659
44835
  const app = createServer2(deps);
@@ -44680,14 +44856,10 @@ async function main() {
44680
44856
  console.log("\nShutting down...");
44681
44857
  try {
44682
44858
  clearInterval(dashboardHealthTimer);
44683
- clearInterval(previewHealthTimer);
44859
+ clearInterval(nodeTunnelHealthTimer);
44684
44860
  if (dashboardTransport) {
44685
44861
  await dashboardTransport.stop();
44686
44862
  }
44687
- if (previewTransport) {
44688
- await previewTransport.stop();
44689
- }
44690
- await closeServer(outputServer);
44691
44863
  await meshyNode.stop();
44692
44864
  await closeServer(server);
44693
44865
  console.log("Goodbye!");