meshy-node 0.1.3 → 0.1.4

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) {
@@ -32990,24 +32988,6 @@ var NodeRegistry = class {
32990
32988
  }
32991
32989
  }
32992
32990
  }
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
32991
  // -- Self --------------------------------------------------------------
33012
32992
  setSelf(info) {
33013
32993
  this.selfNode = { ...info };
@@ -34139,7 +34119,6 @@ var HeartbeatMonitor = class {
34139
34119
  this.nodeRegistry.updateLoad(node.id, result.load);
34140
34120
  this.applyReportedDevTunnelState(node.id, result.devtunnelEnabled, result.devtunnelEndpoint);
34141
34121
  this.nodeRegistry.updateDashboardOrigin(node.id, result.dashboardOrigin);
34142
- this.nodeRegistry.updatePreviewOrigin(node.id, result.previewOrigin);
34143
34122
  if (result.workDirFolders) {
34144
34123
  this.nodeRegistry.updateFolders(node.id, result.workDirFolders);
34145
34124
  }
@@ -34205,7 +34184,6 @@ var HeartbeatMonitor = class {
34205
34184
  devtunnelEnabled: self2.devtunnelEndpoint !== void 0,
34206
34185
  devtunnelEndpoint: self2.devtunnelEndpoint,
34207
34186
  dashboardOrigin: self2.dashboardOrigin,
34208
- previewOrigin: self2.previewOrigin,
34209
34187
  workDirFolders: self2.workDir ? listWorkDirFolders(self2.workDir) : void 0
34210
34188
  };
34211
34189
  return response;
@@ -34224,7 +34202,6 @@ var HeartbeatMonitor = class {
34224
34202
  devtunnelEnabled,
34225
34203
  devtunnelEndpoint,
34226
34204
  dashboardOrigin,
34227
- previewOrigin,
34228
34205
  workDirFolders
34229
34206
  } = req;
34230
34207
  const existingNode = this.nodeRegistry.getNode(nodeId);
@@ -34249,7 +34226,6 @@ var HeartbeatMonitor = class {
34249
34226
  ...workDir ? { workDir } : {},
34250
34227
  ...devtunnelEnabled && devtunnelEndpoint ? { devtunnelEndpoint } : {},
34251
34228
  ...dashboardOrigin ? { dashboardOrigin } : {},
34252
- ...previewOrigin ? { previewOrigin } : {},
34253
34229
  ...workDirFolders ? { workDirFolders } : {}
34254
34230
  });
34255
34231
  this.log.info("keepalive restored missing follower", { nodeId, endpoint: normalizedEndpoint });
@@ -34283,7 +34259,6 @@ var HeartbeatMonitor = class {
34283
34259
  this.nodeRegistry.updateLoad(nodeId, load);
34284
34260
  this.applyReportedDevTunnelState(nodeId, devtunnelEnabled, devtunnelEndpoint);
34285
34261
  this.nodeRegistry.updateDashboardOrigin(nodeId, dashboardOrigin);
34286
- this.nodeRegistry.updatePreviewOrigin(nodeId, previewOrigin);
34287
34262
  if (workDirFolders) {
34288
34263
  this.nodeRegistry.updateFolders(nodeId, workDirFolders);
34289
34264
  }
@@ -34341,7 +34316,6 @@ var HeartbeatMonitor = class {
34341
34316
  devtunnelEnabled: self2.devtunnelEndpoint !== void 0,
34342
34317
  devtunnelEndpoint: self2.devtunnelEndpoint,
34343
34318
  dashboardOrigin: self2.dashboardOrigin,
34344
- previewOrigin: self2.previewOrigin,
34345
34319
  workDirFolders: self2.workDir ? listWorkDirFolders(self2.workDir) : void 0
34346
34320
  };
34347
34321
  this.log.debug("sending keepalive request", {
@@ -34667,7 +34641,8 @@ var EXCLUDED_PATH_PREFIXES = [
34667
34641
  "/api/cluster/"
34668
34642
  ];
34669
34643
  var EXCLUDED_PATH_SUFFIXES = [
34670
- "/devtunnel"
34644
+ "/devtunnel",
34645
+ "/output/preview-sessions"
34671
34646
  ];
34672
34647
  var WRITE_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH", "DELETE"]);
34673
34648
  var DataRouter = class {
@@ -35854,6 +35829,18 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
35854
35829
  }
35855
35830
  async joinCluster(seedUrl) {
35856
35831
  const log2 = this.logger.child("node/join-cluster");
35832
+ const currentSelf = this.nodeRegistry.getSelf();
35833
+ if (this.config.transport.type !== "devtunnel" && !currentSelf.devtunnelEndpoint && !this.devtunnelTransport) {
35834
+ log2.info("enabling anonymous node tunnel before cluster join", {
35835
+ seedUrl,
35836
+ transportType: this.config.transport.type
35837
+ });
35838
+ const devtunnelEndpoint = await this.enableDevTunnel();
35839
+ log2.info("enabled anonymous node tunnel before cluster join", {
35840
+ seedUrl,
35841
+ devtunnelEndpoint
35842
+ });
35843
+ }
35857
35844
  const tasks = this.taskEngine.listTasks().tasks;
35858
35845
  const self2 = this.nodeRegistry.getSelf();
35859
35846
  const joinBody = {
@@ -35872,17 +35859,13 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
35872
35859
  if (self2.dashboardOrigin) {
35873
35860
  joinBody.dashboardOrigin = self2.dashboardOrigin;
35874
35861
  }
35875
- if (self2.previewOrigin) {
35876
- joinBody.previewOrigin = self2.previewOrigin;
35877
- }
35878
35862
  log2.info("sending cluster join request", {
35879
35863
  seedUrl,
35880
35864
  nodeId: self2.id,
35881
35865
  endpoint: self2.endpoint,
35882
35866
  taskCount: tasks.length,
35883
35867
  hasDevTunnel: !!self2.devtunnelEndpoint,
35884
- hasDashboardOrigin: !!self2.dashboardOrigin,
35885
- hasPreviewOrigin: !!self2.previewOrigin
35868
+ hasDashboardOrigin: !!self2.dashboardOrigin
35886
35869
  });
35887
35870
  let response;
35888
35871
  try {
@@ -36069,6 +36052,27 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
36069
36052
  getTransportType() {
36070
36053
  return this.config.transport.type;
36071
36054
  }
36055
+ hasPublishedNodeTunnel() {
36056
+ return this.config.transport.type === "devtunnel" || this.devtunnelTransport !== null;
36057
+ }
36058
+ async isPublishedNodeTunnelHealthy() {
36059
+ if (this.config.transport.type === "devtunnel") {
36060
+ return this.transport.isHealthy();
36061
+ }
36062
+ if (this.devtunnelTransport) {
36063
+ return this.devtunnelTransport.isHealthy();
36064
+ }
36065
+ return true;
36066
+ }
36067
+ async restartPublishedNodeTunnel() {
36068
+ if (this.config.transport.type === "devtunnel") {
36069
+ return this.restartPrimaryTransport();
36070
+ }
36071
+ if (this.devtunnelTransport) {
36072
+ return this.restartDevTunnelSidecar();
36073
+ }
36074
+ return void 0;
36075
+ }
36072
36076
  async switchTransport(transportType) {
36073
36077
  if (this.config.transport.type === transportType && this.transport) {
36074
36078
  return this.transport.getEndpoint();
@@ -36172,8 +36176,7 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
36172
36176
  workDir: currentSelf.workDir,
36173
36177
  workDirFolders: listWorkDirFolders(this.getWorkDir()),
36174
36178
  ...currentSelf.devtunnelEndpoint ? { devtunnelEndpoint: currentSelf.devtunnelEndpoint } : {},
36175
- ...currentSelf.dashboardOrigin ? { dashboardOrigin: currentSelf.dashboardOrigin } : {},
36176
- ...currentSelf.previewOrigin ? { previewOrigin: currentSelf.previewOrigin } : {}
36179
+ ...currentSelf.dashboardOrigin ? { dashboardOrigin: currentSelf.dashboardOrigin } : {}
36177
36180
  };
36178
36181
  this.selfInfo = nextSelf;
36179
36182
  this.nodeRegistry.setSelf(nextSelf);
@@ -36209,6 +36212,64 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
36209
36212
  }
36210
36213
  };
36211
36214
  }
36215
+ async restartPrimaryTransport() {
36216
+ const nextTransportConfig = this.resolveTransportConfig(this.config.transport.type, this.selfInfo.id);
36217
+ const previousTransport = this.transport;
36218
+ let nextTransport = null;
36219
+ await previousTransport.stop().catch(() => void 0);
36220
+ try {
36221
+ nextTransport = this.transportFactory(nextTransportConfig);
36222
+ await nextTransport.start(this.config.node.port);
36223
+ const nextEndpoint = await nextTransport.getEndpoint();
36224
+ this.transport = nextTransport;
36225
+ this.selfInfo.endpoint = nextEndpoint;
36226
+ this.selfInfo.transportType = this.config.transport.type;
36227
+ this.nodeRegistry.updateEndpoint(this.selfInfo.id, nextEndpoint);
36228
+ this.eventBus.emit("transport.changed", {
36229
+ nodeId: this.selfInfo.id,
36230
+ transportType: this.config.transport.type,
36231
+ endpoint: nextEndpoint
36232
+ });
36233
+ return nextEndpoint;
36234
+ } catch (err) {
36235
+ if (nextTransport) {
36236
+ await nextTransport.stop().catch(() => void 0);
36237
+ }
36238
+ this.transport = previousTransport;
36239
+ throw err;
36240
+ }
36241
+ }
36242
+ async restartDevTunnelSidecar() {
36243
+ if (!this.devtunnelTransport) {
36244
+ throw new Error("DevTunnel sidecar is not enabled");
36245
+ }
36246
+ const previousTransport = this.devtunnelTransport;
36247
+ const tunnelConfig = this.resolveStableDevTunnelConfig("sidecar", this.selfInfo.id);
36248
+ let nextTransport = null;
36249
+ await previousTransport.stop().catch(() => void 0);
36250
+ try {
36251
+ nextTransport = this.transportFactory(tunnelConfig);
36252
+ await nextTransport.start(this.config.node.port);
36253
+ const devtunnelEndpoint = await nextTransport.getEndpoint();
36254
+ this.devtunnelTransport = nextTransport;
36255
+ this.syncSelfInfoFromRegistry();
36256
+ this.selfInfo.devtunnelEndpoint = devtunnelEndpoint;
36257
+ this.nodeRegistry.setSelf(this.selfInfo);
36258
+ this.nodeRegistry.updateDevTunnelEndpoint(this.selfInfo.id, devtunnelEndpoint);
36259
+ this.eventBus.emit("transport.changed", {
36260
+ nodeId: this.selfInfo.id,
36261
+ transportType: "devtunnel",
36262
+ endpoint: devtunnelEndpoint
36263
+ });
36264
+ return devtunnelEndpoint;
36265
+ } catch (err) {
36266
+ if (nextTransport) {
36267
+ await nextTransport.stop().catch(() => void 0);
36268
+ }
36269
+ this.devtunnelTransport = previousTransport;
36270
+ throw err;
36271
+ }
36272
+ }
36212
36273
  /**
36213
36274
  * Handle a task received via pull-based dispatch (keepalive channel).
36214
36275
  * Mirrors the logic of POST /api/worker/execute but without the HTTP layer.
@@ -40408,8 +40469,7 @@ var NodeInfoSchema = external_exports.object({
40408
40469
  lastHeartbeat: external_exports.number(),
40409
40470
  transportType: external_exports.string().optional(),
40410
40471
  devtunnelEndpoint: external_exports.string().optional(),
40411
- dashboardOrigin: external_exports.string().optional(),
40412
- previewOrigin: external_exports.string().optional()
40472
+ dashboardOrigin: external_exports.string().optional()
40413
40473
  });
40414
40474
  var JoinTaskSchema = external_exports.object({
40415
40475
  id: external_exports.string(),
@@ -40441,7 +40501,6 @@ var JoinClusterBody = external_exports.object({
40441
40501
  workDirFolders: external_exports.array(external_exports.string()).optional(),
40442
40502
  devtunnelEndpoint: external_exports.string().url().optional(),
40443
40503
  dashboardOrigin: external_exports.string().url().optional(),
40444
- previewOrigin: external_exports.string().url().optional(),
40445
40504
  tasks: external_exports.array(JoinTaskSchema).default([])
40446
40505
  });
40447
40506
  var JoinClusterResponse = external_exports.object({
@@ -40484,7 +40543,6 @@ var NodeInfoSchema2 = external_exports.object({
40484
40543
  transportType: external_exports.string().optional(),
40485
40544
  devtunnelEndpoint: external_exports.string().optional(),
40486
40545
  dashboardOrigin: external_exports.string().optional(),
40487
- previewOrigin: external_exports.string().optional(),
40488
40546
  workDir: external_exports.string().optional(),
40489
40547
  workDirFolders: external_exports.array(external_exports.string()).optional()
40490
40548
  });
@@ -40935,8 +40993,7 @@ function createClusterRoutes() {
40935
40993
  endpoint: body.endpoint,
40936
40994
  taskCount: body.tasks?.length ?? 0,
40937
40995
  hasDevTunnel: !!body.devtunnelEndpoint,
40938
- hasDashboardOrigin: !!body.dashboardOrigin,
40939
- hasPreviewOrigin: !!body.previewOrigin
40996
+ hasDashboardOrigin: !!body.dashboardOrigin
40940
40997
  });
40941
40998
  const existingNodes = nodeRegistry.getAllNodes();
40942
40999
  let removedCount = 0;
@@ -40959,8 +41016,7 @@ function createClusterRoutes() {
40959
41016
  ...body.workDir && { workDir: body.workDir },
40960
41017
  ...body.workDirFolders && { workDirFolders: body.workDirFolders },
40961
41018
  ...body.devtunnelEndpoint && { devtunnelEndpoint: body.devtunnelEndpoint },
40962
- ...body.dashboardOrigin && { dashboardOrigin: body.dashboardOrigin },
40963
- ...body.previewOrigin && { previewOrigin: body.previewOrigin }
41019
+ ...body.dashboardOrigin && { dashboardOrigin: body.dashboardOrigin }
40964
41020
  };
40965
41021
  nodeRegistry.addNode(node);
40966
41022
  taskEngine.importTasks(body.tasks ?? []);
@@ -41467,9 +41523,6 @@ function computeParentPath(rootPath, currentPath, useAbsolute) {
41467
41523
  }
41468
41524
 
41469
41525
  // ../../packages/api/src/routes/node-workdir.ts
41470
- function asyncHandler2(fn) {
41471
- return (req, res, next) => fn(req, res, next).catch(next);
41472
- }
41473
41526
  function sendLocalNodeWorkDirTree(req, res, nodeId, options = {}) {
41474
41527
  const query = NodeWorkDirTreeQuery.parse(req.query);
41475
41528
  const { nodeRegistry, workDir } = req.app.locals.deps;
@@ -41489,13 +41542,6 @@ function sendLocalNodeWorkDirTree(req, res, nodeId, options = {}) {
41489
41542
  }
41490
41543
  ));
41491
41544
  }
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
41545
 
41500
41546
  // ../../packages/api/src/task-route-utils.ts
41501
41547
  var fs11 = __toESM(require("fs"), 1);
@@ -41686,42 +41732,26 @@ var MIME_MAP2 = {
41686
41732
  function getMime(filePath) {
41687
41733
  return MIME_MAP2[path13.extname(filePath).toLowerCase()] ?? "application/octet-stream";
41688
41734
  }
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
- }
41735
+ function sendPreviewAssetResponse(sessionManager, token, requestedPath, res) {
41706
41736
  const session = sessionManager.get(token);
41707
41737
  if (!session) {
41708
41738
  res.writeHead(403, { "Content-Type": "text/plain" });
41709
41739
  res.end("Invalid or expired preview token");
41710
- return true;
41740
+ return;
41711
41741
  }
41712
- const requestedPath = decodeURIComponent(match?.[2] ?? session.entryPath);
41742
+ const resolvedRequestedPath = decodeURIComponent(requestedPath ?? session.entryPath);
41713
41743
  let resolved;
41714
41744
  try {
41715
- resolved = resolvePreviewPath(session.rootPath, requestedPath).absolutePath;
41745
+ resolved = resolvePreviewPath(session.rootPath, resolvedRequestedPath).absolutePath;
41716
41746
  } catch {
41717
41747
  res.writeHead(400, { "Content-Type": "text/plain" });
41718
41748
  res.end("Invalid path");
41719
- return true;
41749
+ return;
41720
41750
  }
41721
41751
  if (!fs12.existsSync(resolved) || !fs12.statSync(resolved).isFile()) {
41722
41752
  res.writeHead(404, { "Content-Type": "text/plain" });
41723
41753
  res.end("File not found");
41724
- return true;
41754
+ return;
41725
41755
  }
41726
41756
  const mime = getMime(resolved);
41727
41757
  const content = fs12.readFileSync(resolved);
@@ -41731,6 +41761,115 @@ function handlePreviewRequest(sessionManager, req, res) {
41731
41761
  "Cache-Control": "no-cache"
41732
41762
  });
41733
41763
  res.end(content);
41764
+ }
41765
+ function handlePreviewRequest(sessionManager, req, res) {
41766
+ const url = new URL(req.url ?? "/", "http://localhost");
41767
+ if (!url.pathname.startsWith("/preview/")) {
41768
+ return false;
41769
+ }
41770
+ if (req.method !== "GET") {
41771
+ res.writeHead(405, { "Content-Type": "text/plain" });
41772
+ res.end("Method not allowed");
41773
+ return true;
41774
+ }
41775
+ const match = url.pathname.match(/^\/preview\/([a-f0-9]+)(?:\/(.*))?$/i);
41776
+ const token = match?.[1];
41777
+ if (!token) {
41778
+ res.writeHead(404, { "Content-Type": "text/plain" });
41779
+ res.end("Preview not found");
41780
+ return true;
41781
+ }
41782
+ sendPreviewAssetResponse(sessionManager, token, match?.[2], res);
41783
+ return true;
41784
+ }
41785
+
41786
+ // ../../packages/api/src/preview/preview-proxy.ts
41787
+ function parsePreviewRequest(previewUrl) {
41788
+ const pathname = new URL(previewUrl, "http://localhost").pathname;
41789
+ const match = pathname.match(/^\/preview\/([a-f0-9]+)(?:\/(.*))?$/i);
41790
+ const token = match?.[1];
41791
+ if (!token) {
41792
+ return null;
41793
+ }
41794
+ return {
41795
+ token,
41796
+ requestedPath: match?.[2]
41797
+ };
41798
+ }
41799
+ function extractPreviewToken(previewUrl) {
41800
+ return parsePreviewRequest(previewUrl)?.token ?? null;
41801
+ }
41802
+ function buildPreviewAssetProxyPath(token, requestedPath) {
41803
+ const search = new URLSearchParams({ token });
41804
+ if (requestedPath) {
41805
+ search.set("path", decodeURIComponent(requestedPath));
41806
+ }
41807
+ return `/api/worker/preview-asset?${search.toString()}`;
41808
+ }
41809
+ var PreviewProxyManager = class {
41810
+ sessions = /* @__PURE__ */ new Map();
41811
+ register(token, nodeId, expiresAt) {
41812
+ this.sessions.set(token, { token, nodeId, expiresAt });
41813
+ }
41814
+ get(token) {
41815
+ const session = this.sessions.get(token);
41816
+ if (!session) {
41817
+ return null;
41818
+ }
41819
+ if (Date.now() > session.expiresAt) {
41820
+ this.sessions.delete(token);
41821
+ return null;
41822
+ }
41823
+ return session;
41824
+ }
41825
+ cleanup() {
41826
+ const now = Date.now();
41827
+ for (const [token, session] of this.sessions) {
41828
+ if (session.expiresAt <= now) {
41829
+ this.sessions.delete(token);
41830
+ }
41831
+ }
41832
+ }
41833
+ };
41834
+ function rewritePreviewSessionPayloadForProxy(manager, payload, nodeId) {
41835
+ const token = extractPreviewToken(payload.previewUrl);
41836
+ if (!token) {
41837
+ return payload;
41838
+ }
41839
+ manager.register(token, nodeId, payload.expiresAt);
41840
+ return {
41841
+ ...payload,
41842
+ previewUrl: buildPreviewUrl("", {
41843
+ token,
41844
+ entryPath: payload.entryPath
41845
+ })
41846
+ };
41847
+ }
41848
+ async function handlePreviewProxyRequest(manager, nodeRegistry, logger27, req, res) {
41849
+ const requestPath = req.originalUrl ?? req.url;
41850
+ const previewRequest = parsePreviewRequest(requestPath);
41851
+ if (!previewRequest) {
41852
+ return false;
41853
+ }
41854
+ const session = manager.get(previewRequest.token);
41855
+ if (!session) {
41856
+ return false;
41857
+ }
41858
+ const node = nodeRegistry.getNode(session.nodeId);
41859
+ if (!node) {
41860
+ throw new MeshyError("NODE_NOT_FOUND", `Preview worker ${session.nodeId} not found`, 404);
41861
+ }
41862
+ const previewLog = logger27.child("preview-proxy");
41863
+ const proxyPath = buildPreviewAssetProxyPath(previewRequest.token, previewRequest.requestedPath);
41864
+ const { endpoint, response } = await fetchNodeWithFallback(node, proxyPath);
41865
+ previewLog.debug("proxying preview asset from assigned worker", {
41866
+ token: previewRequest.token,
41867
+ nodeId: session.nodeId,
41868
+ requestPath,
41869
+ proxyPath,
41870
+ endpoint
41871
+ });
41872
+ await sendProxyResponse(res, response);
41734
41873
  return true;
41735
41874
  }
41736
41875
 
@@ -41837,21 +41976,18 @@ function getLocalTaskOutputDiff(taskEngine, taskId) {
41837
41976
  const rootPath = getTaskOutputRoot(taskEngine, taskId);
41838
41977
  return getGitDiff(rootPath);
41839
41978
  }
41840
- async function createPreviewSessionPayload(deps, taskId, entryPath) {
41979
+ async function createPreviewSessionPayload(deps, taskId, entryPath, requestOrigin) {
41841
41980
  const previewManager = deps.previewSessionManager;
41842
41981
  if (!previewManager) {
41843
41982
  throw new MeshyError("VALIDATION_ERROR", "Preview not available on this node", 400);
41844
41983
  }
41845
- if (!deps.previewPort) {
41846
- throw new MeshyError("VALIDATION_ERROR", "Preview server not running", 400);
41847
- }
41848
41984
  const rootPath = getTaskOutputRoot(deps.taskEngine, taskId);
41849
41985
  const session = previewManager.create({
41850
41986
  taskId,
41851
41987
  rootPath,
41852
41988
  entryPath
41853
41989
  });
41854
- const origin = deps.ensurePreviewOrigin ? await deps.ensurePreviewOrigin() ?? deps.previewOrigin : deps.previewOrigin;
41990
+ const origin = requestOrigin ?? deps.dashboardOrigin ?? deps.localDashboardOrigin;
41855
41991
  if (!origin) {
41856
41992
  throw new MeshyError("VALIDATION_ERROR", "Preview origin not available", 502);
41857
41993
  }
@@ -42123,7 +42259,7 @@ function createNodeWorkdirProxyTrace(log2, nodeId, proxyPath) {
42123
42259
  }
42124
42260
  };
42125
42261
  }
42126
- function asyncHandler3(fn) {
42262
+ function asyncHandler2(fn) {
42127
42263
  return (req, res, next) => fn(req, res, next).catch(next);
42128
42264
  }
42129
42265
  async function maybeHandleRemoteNodeWorkDirRequest(req, res, nodeId) {
@@ -42158,9 +42294,8 @@ async function maybeHandleRemoteNodeWorkDirRequest(req, res, nodeId) {
42158
42294
  return true;
42159
42295
  }
42160
42296
  try {
42161
- const proxyTarget = node.previewOrigin ? { endpoint: node.previewOrigin } : node;
42162
42297
  const { endpoint, response } = await fetchNodeWithFallback(
42163
- proxyTarget,
42298
+ node,
42164
42299
  proxyPath,
42165
42300
  void 0,
42166
42301
  NODE_WORKDIR_PROXY_TIMEOUT_MS,
@@ -42197,7 +42332,7 @@ async function maybeHandleRemoteNodeWorkDirRequest(req, res, nodeId) {
42197
42332
  }
42198
42333
  function createNodeRoutes() {
42199
42334
  const router = (0, import_express3.Router)();
42200
- router.get("/", asyncHandler3(async (req, res) => {
42335
+ router.get("/", asyncHandler2(async (req, res) => {
42201
42336
  const { nodeRegistry } = req.app.locals.deps;
42202
42337
  const query = NodeListQuery.parse(req.query);
42203
42338
  let nodes = nodeRegistry.getAllNodes();
@@ -42211,7 +42346,7 @@ function createNodeRoutes() {
42211
42346
  }
42212
42347
  res.json({ nodes });
42213
42348
  }));
42214
- router.get("/:id", asyncHandler3(async (req, res) => {
42349
+ router.get("/:id", asyncHandler2(async (req, res) => {
42215
42350
  const { nodeRegistry } = req.app.locals.deps;
42216
42351
  const node = nodeRegistry.getNode(req.params.id);
42217
42352
  if (!node) {
@@ -42219,7 +42354,7 @@ function createNodeRoutes() {
42219
42354
  }
42220
42355
  res.json(node);
42221
42356
  }));
42222
- router.get("/:id/status", asyncHandler3(async (req, res) => {
42357
+ router.get("/:id/status", asyncHandler2(async (req, res) => {
42223
42358
  const { nodeRegistry, taskEngine } = req.app.locals.deps;
42224
42359
  const node = nodeRegistry.getNode(req.params.id);
42225
42360
  if (!node) {
@@ -42234,7 +42369,7 @@ function createNodeRoutes() {
42234
42369
  }));
42235
42370
  res.json({ node, tasks: taskSummary });
42236
42371
  }));
42237
- router.get("/:id/workdir/tree", asyncHandler3(async (req, res) => {
42372
+ router.get("/:id/workdir/tree", asyncHandler2(async (req, res) => {
42238
42373
  const nodeId = req.params.id;
42239
42374
  const handled = await maybeHandleRemoteNodeWorkDirRequest(req, res, nodeId);
42240
42375
  if (handled) {
@@ -42242,7 +42377,7 @@ function createNodeRoutes() {
42242
42377
  }
42243
42378
  sendLocalNodeWorkDirTree(req, res, nodeId);
42244
42379
  }));
42245
- router.patch("/:id", asyncHandler3(async (req, res) => {
42380
+ router.patch("/:id", asyncHandler2(async (req, res) => {
42246
42381
  const { nodeRegistry, persistNodeNamePreference } = req.app.locals.deps;
42247
42382
  const updates = UpdateNodeBody.parse(req.body);
42248
42383
  const nodeId = req.params.id;
@@ -42265,7 +42400,7 @@ function createNodeRoutes() {
42265
42400
  }
42266
42401
  res.json(node);
42267
42402
  }));
42268
- router.delete("/:id", asyncHandler3(async (req, res) => {
42403
+ router.delete("/:id", asyncHandler2(async (req, res) => {
42269
42404
  const { nodeRegistry, election } = req.app.locals.deps;
42270
42405
  if (!election.isLeader()) {
42271
42406
  throw new MeshyError("NOT_LEADER", "Only the leader node can delete nodes", 403);
@@ -42277,7 +42412,7 @@ function createNodeRoutes() {
42277
42412
  nodeRegistry.removeNode(req.params.id);
42278
42413
  res.json({ ok: true });
42279
42414
  }));
42280
- router.post("/:id/devtunnel", asyncHandler3(async (req, res) => {
42415
+ router.post("/:id/devtunnel", asyncHandler2(async (req, res) => {
42281
42416
  const { nodeRegistry, election, heartbeat, enableDevTunnel, disableDevTunnel, taskEngine } = req.app.locals.deps;
42282
42417
  const self2 = nodeRegistry.getSelf();
42283
42418
  const targetId = req.params.id;
@@ -42444,9 +42579,71 @@ function startLocalTaskFollowUp(deps, task, content, assignedTo, metadata) {
42444
42579
 
42445
42580
  // ../../packages/api/src/routes/task-output.ts
42446
42581
  var import_express4 = __toESM(require_express2(), 1);
42447
- function asyncHandler4(fn) {
42582
+
42583
+ // ../../packages/api/src/request-origin.ts
42584
+ function getFirstHeaderValue(value) {
42585
+ if (Array.isArray(value)) {
42586
+ return getFirstHeaderValue(value[0]);
42587
+ }
42588
+ if (typeof value !== "string") {
42589
+ return void 0;
42590
+ }
42591
+ const first = value.split(",")[0]?.trim();
42592
+ return first ? first : void 0;
42593
+ }
42594
+ function getForwardedHeaderOrigin(req) {
42595
+ const forwarded = getFirstHeaderValue(req.headers.forwarded);
42596
+ if (!forwarded) {
42597
+ return void 0;
42598
+ }
42599
+ let host;
42600
+ let proto;
42601
+ for (const segment of forwarded.split(";")) {
42602
+ const [rawKey, rawValue] = segment.split("=", 2);
42603
+ const key = rawKey?.trim().toLowerCase();
42604
+ const value = rawValue?.trim().replace(/^"|"$/g, "");
42605
+ if (!key || !value) {
42606
+ continue;
42607
+ }
42608
+ if (key === "host" && !host) {
42609
+ host = value;
42610
+ }
42611
+ if (key === "proto" && !proto) {
42612
+ proto = value;
42613
+ }
42614
+ }
42615
+ if (!host) {
42616
+ return void 0;
42617
+ }
42618
+ return `${proto ?? req.protocol ?? "http"}://${host}`;
42619
+ }
42620
+ function resolveRequestOrigin(req) {
42621
+ const forwardedOrigin = getForwardedHeaderOrigin(req);
42622
+ if (forwardedOrigin) {
42623
+ return forwardedOrigin;
42624
+ }
42625
+ const host = getFirstHeaderValue(req.headers["x-forwarded-host"]) ?? getFirstHeaderValue(req.headers.host) ?? req.get("host");
42626
+ if (!host) {
42627
+ return void 0;
42628
+ }
42629
+ const proto = getFirstHeaderValue(req.headers["x-forwarded-proto"]) ?? req.protocol ?? "http";
42630
+ return `${proto}://${host}`;
42631
+ }
42632
+
42633
+ // ../../packages/api/src/routes/task-output.ts
42634
+ function asyncHandler3(fn) {
42448
42635
  return (req, res, next) => fn(req, res, next).catch(next);
42449
42636
  }
42637
+ function isPreviewSessionPayload(value) {
42638
+ return typeof value === "object" && value !== null && typeof value.previewUrl === "string" && typeof value.entryPath === "string" && typeof value.expiresAt === "number";
42639
+ }
42640
+ function rewritePreviewPayloadIfNeeded(req, nodeId, payload) {
42641
+ const { previewProxyManager } = req.app.locals.deps;
42642
+ if (!previewProxyManager) {
42643
+ return payload;
42644
+ }
42645
+ return rewritePreviewSessionPayloadForProxy(previewProxyManager, payload, nodeId);
42646
+ }
42450
42647
  async function maybeHandleRemoteTaskOutputRequest(req, res, taskId, subPath, init, fallbackRequest) {
42451
42648
  const { taskEngine, nodeRegistry, heartbeat, logger: rootLogger } = req.app.locals.deps;
42452
42649
  const log2 = rootLogger.child("tasks/output");
@@ -42467,14 +42664,20 @@ async function maybeHandleRemoteTaskOutputRequest(req, res, taskId, subPath, ini
42467
42664
  if (!node) {
42468
42665
  throw new MeshyError("NODE_NOT_FOUND", `Assigned node ${assignedNodeId} not found`, 404);
42469
42666
  }
42470
- if (!node.previewOrigin) {
42667
+ if (!node.endpoint && !node.devtunnelEndpoint) {
42471
42668
  if (fallbackRequest && heartbeat?.requestWorkerControl) {
42472
- log2.warn("task output server origin missing, falling back to keepalive control", {
42669
+ log2.warn("worker output endpoint missing, falling back to keepalive control", {
42473
42670
  taskId,
42474
42671
  assignedTo: assignedNodeId,
42475
42672
  kind: fallbackRequest.kind
42476
42673
  });
42477
42674
  const controlResponse = await heartbeat.requestWorkerControl(assignedNodeId, fallbackRequest);
42675
+ if (fallbackRequest.kind === "task-preview-session" && controlResponse.bodyEncoding === "json" && isPreviewSessionPayload(controlResponse.body)) {
42676
+ res.status(controlResponse.statusCode).json(
42677
+ rewritePreviewPayloadIfNeeded(req, assignedNodeId, controlResponse.body)
42678
+ );
42679
+ return true;
42680
+ }
42478
42681
  sendWorkerControlResponse(res, controlResponse);
42479
42682
  return true;
42480
42683
  }
@@ -42484,31 +42687,44 @@ async function maybeHandleRemoteTaskOutputRequest(req, res, taskId, subPath, ini
42484
42687
  const proxyPath = `/api/tasks/${taskId}/output${subPath}${qs}`;
42485
42688
  try {
42486
42689
  const { endpoint, response: proxyRes } = await fetchNodeWithFallback(
42487
- { endpoint: node.previewOrigin },
42690
+ node,
42488
42691
  proxyPath,
42489
42692
  init
42490
42693
  );
42491
- log2.debug("proxying task output request to worker output server", {
42694
+ log2.debug("proxying task output request to worker node API", {
42492
42695
  taskId,
42493
42696
  assignedTo: assignedNodeId,
42494
42697
  proxyPath,
42495
- outputOrigin: endpoint
42698
+ outputEndpoint: endpoint
42496
42699
  });
42700
+ if (fallbackRequest?.kind === "task-preview-session" && proxyRes.ok) {
42701
+ const body = await proxyRes.json().catch(() => null);
42702
+ if (isPreviewSessionPayload(body)) {
42703
+ res.status(proxyRes.status).json(rewritePreviewPayloadIfNeeded(req, assignedNodeId, body));
42704
+ return true;
42705
+ }
42706
+ }
42497
42707
  await sendProxyResponse(res, proxyRes);
42498
42708
  return true;
42499
42709
  } catch (err) {
42500
42710
  if (fallbackRequest && heartbeat?.requestWorkerControl) {
42501
- log2.warn("output server proxy failed, falling back to keepalive control", {
42711
+ log2.warn("worker output proxy failed, falling back to keepalive control", {
42502
42712
  taskId,
42503
42713
  assignedTo: assignedNodeId,
42504
42714
  kind: fallbackRequest.kind,
42505
42715
  error: err instanceof Error ? err.message : String(err)
42506
42716
  });
42507
42717
  const controlResponse = await heartbeat.requestWorkerControl(assignedNodeId, fallbackRequest);
42718
+ if (fallbackRequest.kind === "task-preview-session" && controlResponse.bodyEncoding === "json" && isPreviewSessionPayload(controlResponse.body)) {
42719
+ res.status(controlResponse.statusCode).json(
42720
+ rewritePreviewPayloadIfNeeded(req, assignedNodeId, controlResponse.body)
42721
+ );
42722
+ return true;
42723
+ }
42508
42724
  sendWorkerControlResponse(res, controlResponse);
42509
42725
  return true;
42510
42726
  }
42511
- log2.warn("output server proxy error", {
42727
+ log2.warn("worker output proxy error", {
42512
42728
  taskId,
42513
42729
  assignedTo: assignedNodeId,
42514
42730
  error: err instanceof Error ? err.message : String(err)
@@ -42519,7 +42735,7 @@ async function maybeHandleRemoteTaskOutputRequest(req, res, taskId, subPath, ini
42519
42735
  function createTaskOutputRoutes(options = {}) {
42520
42736
  const router = (0, import_express4.Router)();
42521
42737
  const allowRemoteProxy = options.allowRemoteProxy ?? true;
42522
- router.get("/:id/output", asyncHandler4(async (req, res) => {
42738
+ router.get("/:id/output", asyncHandler3(async (req, res) => {
42523
42739
  const taskId = req.params.id;
42524
42740
  if (allowRemoteProxy) {
42525
42741
  const handled = await maybeHandleRemoteTaskOutputRequest(req, res, taskId, "", void 0, {
@@ -42533,7 +42749,7 @@ function createTaskOutputRoutes(options = {}) {
42533
42749
  const { taskEngine } = req.app.locals.deps;
42534
42750
  res.json(getLocalTaskOutputSummary(taskEngine, taskId));
42535
42751
  }));
42536
- router.get("/:id/output/tree", asyncHandler4(async (req, res) => {
42752
+ router.get("/:id/output/tree", asyncHandler3(async (req, res) => {
42537
42753
  const taskId = req.params.id;
42538
42754
  const query = TaskOutputTreeQuery.parse(req.query);
42539
42755
  if (allowRemoteProxy) {
@@ -42549,7 +42765,7 @@ function createTaskOutputRoutes(options = {}) {
42549
42765
  const { taskEngine } = req.app.locals.deps;
42550
42766
  res.json(getLocalTaskOutputTree(taskEngine, taskId, query.path));
42551
42767
  }));
42552
- router.get("/:id/output/content", asyncHandler4(async (req, res) => {
42768
+ router.get("/:id/output/content", asyncHandler3(async (req, res) => {
42553
42769
  const taskId = req.params.id;
42554
42770
  const query = TaskOutputContentQuery.parse(req.query);
42555
42771
  if (allowRemoteProxy) {
@@ -42565,7 +42781,7 @@ function createTaskOutputRoutes(options = {}) {
42565
42781
  const { taskEngine } = req.app.locals.deps;
42566
42782
  res.json(getLocalTaskOutputContent(taskEngine, taskId, query.path));
42567
42783
  }));
42568
- router.get("/:id/output/download", asyncHandler4(async (req, res) => {
42784
+ router.get("/:id/output/download", asyncHandler3(async (req, res) => {
42569
42785
  const taskId = req.params.id;
42570
42786
  const query = TaskOutputDownloadQuery.parse(req.query);
42571
42787
  if (allowRemoteProxy) {
@@ -42585,7 +42801,7 @@ function createTaskOutputRoutes(options = {}) {
42585
42801
  }
42586
42802
  res.send(download.content);
42587
42803
  }));
42588
- router.get("/:id/output/diff", asyncHandler4(async (req, res) => {
42804
+ router.get("/:id/output/diff", asyncHandler3(async (req, res) => {
42589
42805
  const taskId = req.params.id;
42590
42806
  if (allowRemoteProxy) {
42591
42807
  const handled = await maybeHandleRemoteTaskOutputRequest(req, res, taskId, "/diff", void 0, {
@@ -42599,7 +42815,7 @@ function createTaskOutputRoutes(options = {}) {
42599
42815
  const { taskEngine } = req.app.locals.deps;
42600
42816
  res.json(getLocalTaskOutputDiff(taskEngine, taskId));
42601
42817
  }));
42602
- router.post("/:id/output/preview-sessions", asyncHandler4(async (req, res) => {
42818
+ router.post("/:id/output/preview-sessions", asyncHandler3(async (req, res) => {
42603
42819
  const taskId = req.params.id;
42604
42820
  const body = TaskPreviewSessionBody.parse(req.body ?? {});
42605
42821
  if (allowRemoteProxy) {
@@ -42616,7 +42832,7 @@ function createTaskOutputRoutes(options = {}) {
42616
42832
  return;
42617
42833
  }
42618
42834
  }
42619
- res.json(await createPreviewSessionPayload(req.app.locals.deps, taskId, body.path));
42835
+ res.json(await createPreviewSessionPayload(req.app.locals.deps, taskId, body.path, resolveRequestOrigin(req)));
42620
42836
  }));
42621
42837
  return router;
42622
42838
  }
@@ -42625,7 +42841,7 @@ function createTaskOutputRoutes(options = {}) {
42625
42841
  var TERMINAL_STATUSES3 = /* @__PURE__ */ new Set(["completed", "failed", "cancelled", "archived"]);
42626
42842
  var ARCHIVABLE_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled", "archived"]);
42627
42843
  var ACTIVE_STATUSES = /* @__PURE__ */ new Set(["pending", "assigned", "running"]);
42628
- function asyncHandler5(fn) {
42844
+ function asyncHandler4(fn) {
42629
42845
  return (req, res, next) => fn(req, res, next).catch(next);
42630
42846
  }
42631
42847
  function withAssignedNodeMetadata(task, nodeRegistry) {
@@ -42641,7 +42857,7 @@ function withAssignedNodeMetadata(task, nodeRegistry) {
42641
42857
  }
42642
42858
  function createTaskRoutes() {
42643
42859
  const router = (0, import_express5.Router)();
42644
- router.post("/", asyncHandler5(async (req, res) => {
42860
+ router.post("/", asyncHandler4(async (req, res) => {
42645
42861
  const { taskEngine, nodeRegistry } = req.app.locals.deps;
42646
42862
  const body = CreateTaskBody.parse(req.body);
42647
42863
  const task = taskEngine.createTask({
@@ -42660,7 +42876,7 @@ function createTaskRoutes() {
42660
42876
  }
42661
42877
  res.status(201).json(withAssignedNodeMetadata(task, nodeRegistry));
42662
42878
  }));
42663
- router.get("/", asyncHandler5(async (req, res) => {
42879
+ router.get("/", asyncHandler4(async (req, res) => {
42664
42880
  const { taskEngine, nodeRegistry } = req.app.locals.deps;
42665
42881
  const query = TaskListQuery.parse(req.query);
42666
42882
  const filter = {};
@@ -42675,7 +42891,7 @@ function createTaskRoutes() {
42675
42891
  total: result.total
42676
42892
  });
42677
42893
  }));
42678
- router.post("/batch/delete", asyncHandler5(async (req, res) => {
42894
+ router.post("/batch/delete", asyncHandler4(async (req, res) => {
42679
42895
  const { taskEngine } = req.app.locals.deps;
42680
42896
  const { ids } = BatchTaskIdsBody.parse(req.body);
42681
42897
  const results = ids.map((id) => {
@@ -42688,7 +42904,7 @@ function createTaskRoutes() {
42688
42904
  });
42689
42905
  res.json({ results });
42690
42906
  }));
42691
- router.post("/batch/archive", asyncHandler5(async (req, res) => {
42907
+ router.post("/batch/archive", asyncHandler4(async (req, res) => {
42692
42908
  const { taskEngine } = req.app.locals.deps;
42693
42909
  const { ids } = BatchTaskIdsBody.parse(req.body);
42694
42910
  const results = ids.map((id) => {
@@ -42706,7 +42922,7 @@ function createTaskRoutes() {
42706
42922
  });
42707
42923
  res.json({ results });
42708
42924
  }));
42709
- router.get("/:id", asyncHandler5(async (req, res) => {
42925
+ router.get("/:id", asyncHandler4(async (req, res) => {
42710
42926
  const { taskEngine, nodeRegistry } = req.app.locals.deps;
42711
42927
  const task = taskEngine.getTask(req.params.id);
42712
42928
  if (!task) {
@@ -42714,7 +42930,7 @@ function createTaskRoutes() {
42714
42930
  }
42715
42931
  res.json(withAssignedNodeMetadata(task, nodeRegistry));
42716
42932
  }));
42717
- router.patch("/:id", asyncHandler5(async (req, res) => {
42933
+ router.patch("/:id", asyncHandler4(async (req, res) => {
42718
42934
  const { taskEngine, nodeRegistry, logger: rootLogger } = req.app.locals.deps;
42719
42935
  const log2 = rootLogger.child("tasks/patch");
42720
42936
  const updates = UpdateTaskBody.parse(req.body);
@@ -42753,7 +42969,7 @@ function createTaskRoutes() {
42753
42969
  }
42754
42970
  res.json(withAssignedNodeMetadata(task, nodeRegistry));
42755
42971
  }));
42756
- router.delete("/:id", asyncHandler5(async (req, res) => {
42972
+ router.delete("/:id", asyncHandler4(async (req, res) => {
42757
42973
  const { taskEngine } = req.app.locals.deps;
42758
42974
  const result = taskEngine.deleteTask(req.params.id);
42759
42975
  if (!result) {
@@ -42761,7 +42977,7 @@ function createTaskRoutes() {
42761
42977
  }
42762
42978
  res.json({ ok: true });
42763
42979
  }));
42764
- router.post("/:id/cancel", asyncHandler5(async (req, res) => {
42980
+ router.post("/:id/cancel", asyncHandler4(async (req, res) => {
42765
42981
  const { taskEngine, nodeRegistry, engineRegistry, heartbeat, logger: rootLogger } = req.app.locals.deps;
42766
42982
  const log2 = rootLogger.child("tasks/cancel");
42767
42983
  const task = taskEngine.getTask(req.params.id);
@@ -42798,18 +43014,18 @@ function createTaskRoutes() {
42798
43014
  }, task.id);
42799
43015
  res.json({ ok: true });
42800
43016
  }));
42801
- router.post("/:id/assign", asyncHandler5(async (req, res) => {
43017
+ router.post("/:id/assign", asyncHandler4(async (req, res) => {
42802
43018
  const { taskEngine, nodeRegistry } = req.app.locals.deps;
42803
43019
  const body = AssignTaskBody.parse(req.body);
42804
43020
  const task = taskEngine.assignTask(req.params.id, body.nodeId);
42805
43021
  res.json(withAssignedNodeMetadata(task, nodeRegistry));
42806
43022
  }));
42807
- router.post("/:id/retry", asyncHandler5(async (req, res) => {
43023
+ router.post("/:id/retry", asyncHandler4(async (req, res) => {
42808
43024
  const { taskEngine, nodeRegistry } = req.app.locals.deps;
42809
43025
  const task = taskEngine.retryTask(req.params.id);
42810
43026
  res.json(withAssignedNodeMetadata(task, nodeRegistry));
42811
43027
  }));
42812
- router.get("/:id/logs", asyncHandler5(async (req, res) => {
43028
+ router.get("/:id/logs", asyncHandler4(async (req, res) => {
42813
43029
  const { engineRegistry, taskEngine, nodeRegistry, logger: rootLogger } = req.app.locals.deps;
42814
43030
  const log2 = rootLogger.child("tasks/logs");
42815
43031
  const query = TaskLogsQuery.parse(req.query);
@@ -42876,7 +43092,7 @@ function createTaskRoutes() {
42876
43092
  });
42877
43093
  res.json(local);
42878
43094
  }));
42879
- router.post("/:id/message", asyncHandler5(async (req, res) => {
43095
+ router.post("/:id/message", asyncHandler4(async (req, res) => {
42880
43096
  const { taskEngine, engineRegistry, nodeRegistry, heartbeat, logger: rootLogger } = req.app.locals.deps;
42881
43097
  const log2 = rootLogger.child("tasks/message");
42882
43098
  const body = SendMessageBody.parse(req.body);
@@ -42972,12 +43188,12 @@ var WorkerMessageBody = external_exports.object({
42972
43188
  var WorkerTaskBody = external_exports.object({
42973
43189
  taskId: external_exports.string().min(1)
42974
43190
  });
42975
- function asyncHandler6(fn) {
43191
+ function asyncHandler5(fn) {
42976
43192
  return (req, res, next) => fn(req, res, next).catch(next);
42977
43193
  }
42978
43194
  function createWorkerRoutes() {
42979
43195
  const router = (0, import_express6.Router)();
42980
- router.post("/execute", asyncHandler6(async (req, res) => {
43196
+ router.post("/execute", asyncHandler5(async (req, res) => {
42981
43197
  const { taskEngine, engineRegistry, nodeRegistry, eventBus, logger: rootLogger, workDir } = req.app.locals.deps;
42982
43198
  const log2 = rootLogger.child("worker/execute");
42983
43199
  const task = req.body;
@@ -43050,7 +43266,7 @@ function createWorkerRoutes() {
43050
43266
  }
43051
43267
  }
43052
43268
  }));
43053
- router.post("/message", asyncHandler6(async (req, res) => {
43269
+ router.post("/message", asyncHandler5(async (req, res) => {
43054
43270
  const { engineRegistry, taskEngine, nodeRegistry, eventBus, logger: rootLogger } = req.app.locals.deps;
43055
43271
  const log2 = rootLogger.child("worker/message");
43056
43272
  const body = WorkerMessageBody.parse(req.body);
@@ -43093,7 +43309,7 @@ function createWorkerRoutes() {
43093
43309
  }
43094
43310
  res.json({ ok: true });
43095
43311
  }));
43096
- router.post("/cancel", asyncHandler6(async (req, res) => {
43312
+ router.post("/cancel", asyncHandler5(async (req, res) => {
43097
43313
  const { taskEngine, engineRegistry, logger: rootLogger } = req.app.locals.deps;
43098
43314
  const log2 = rootLogger.child("worker/cancel");
43099
43315
  const body = WorkerTaskBody.parse(req.body);
@@ -43113,7 +43329,7 @@ function createWorkerRoutes() {
43113
43329
  terminal: result.terminal
43114
43330
  });
43115
43331
  }));
43116
- router.post("/output", asyncHandler6(async (req, res) => {
43332
+ router.post("/output", asyncHandler5(async (req, res) => {
43117
43333
  const { eventBus, engineRegistry, taskEngine, logger: rootLogger } = req.app.locals.deps;
43118
43334
  const log2 = rootLogger.child("worker/output");
43119
43335
  const { taskId, event } = req.body;
@@ -43128,7 +43344,7 @@ function createWorkerRoutes() {
43128
43344
  }
43129
43345
  res.json({ ok: true });
43130
43346
  }));
43131
- router.post("/heartbeat", asyncHandler6(async (req, res) => {
43347
+ router.post("/heartbeat", asyncHandler5(async (req, res) => {
43132
43348
  const { heartbeat, logger: rootLogger } = req.app.locals.deps;
43133
43349
  const log2 = rootLogger.child("worker/heartbeat");
43134
43350
  const body = req.body;
@@ -43145,7 +43361,7 @@ function createWorkerRoutes() {
43145
43361
  });
43146
43362
  res.json(response);
43147
43363
  }));
43148
- router.post("/keepalive", asyncHandler6(async (req, res) => {
43364
+ router.post("/keepalive", asyncHandler5(async (req, res) => {
43149
43365
  const { heartbeat, logger: rootLogger } = req.app.locals.deps;
43150
43366
  const log2 = rootLogger.child("worker/keepalive");
43151
43367
  const body = req.body;
@@ -43165,27 +43381,41 @@ function createWorkerRoutes() {
43165
43381
  });
43166
43382
  res.json(response);
43167
43383
  }));
43168
- router.post("/vote", asyncHandler6(async (req, res) => {
43384
+ router.post("/vote", asyncHandler5(async (req, res) => {
43169
43385
  const { election } = req.app.locals.deps;
43170
43386
  const response = election.handleVoteRequest(req.body);
43171
43387
  res.json(response);
43172
43388
  }));
43173
- router.post("/announce", asyncHandler6(async (req, res) => {
43389
+ router.post("/announce", asyncHandler5(async (req, res) => {
43174
43390
  const { election } = req.app.locals.deps;
43175
43391
  election.handleLeaderAnnounce(req.body);
43176
43392
  res.json({ ok: true });
43177
43393
  }));
43178
- router.post("/preview-session", asyncHandler6(async (req, res) => {
43394
+ router.post("/preview-session", asyncHandler5(async (req, res) => {
43179
43395
  const { logger: rootLogger } = req.app.locals.deps;
43180
43396
  const log2 = rootLogger.child("worker/preview-session");
43181
43397
  const body = TaskPreviewSessionBody.extend({
43182
43398
  taskId: external_exports.string().min(1)
43183
43399
  }).parse(req.body ?? {});
43184
- const payload = await createPreviewSessionPayload(req.app.locals.deps, body.taskId, body.path);
43400
+ const payload = await createPreviewSessionPayload(
43401
+ req.app.locals.deps,
43402
+ body.taskId,
43403
+ body.path,
43404
+ resolveRequestOrigin(req)
43405
+ );
43185
43406
  log2.info("created preview session", { taskId: body.taskId, entryPath: payload.entryPath });
43186
43407
  res.json(payload);
43187
43408
  }));
43188
- router.post("/control-response", asyncHandler6(async (req, res) => {
43409
+ router.get("/preview-asset", asyncHandler5(async (req, res) => {
43410
+ const { previewSessionManager } = req.app.locals.deps;
43411
+ if (!previewSessionManager) {
43412
+ throw new MeshyError("VALIDATION_ERROR", "Preview not available on this node", 400);
43413
+ }
43414
+ const token = external_exports.string().min(1).parse(req.query.token);
43415
+ const requestedPath = typeof req.query.path === "string" && req.query.path.length > 0 ? req.query.path : void 0;
43416
+ sendPreviewAssetResponse(previewSessionManager, token, requestedPath, res);
43417
+ }));
43418
+ router.post("/control-response", asyncHandler5(async (req, res) => {
43189
43419
  const { heartbeat, logger: rootLogger } = req.app.locals.deps;
43190
43420
  const log2 = rootLogger.child("worker/control-response");
43191
43421
  const body = req.body;
@@ -43206,12 +43436,12 @@ function createWorkerRoutes() {
43206
43436
 
43207
43437
  // ../../packages/api/src/routes/system.ts
43208
43438
  var import_express7 = __toESM(require_express2(), 1);
43209
- function asyncHandler7(fn) {
43439
+ function asyncHandler6(fn) {
43210
43440
  return (req, res, next) => fn(req, res, next).catch(next);
43211
43441
  }
43212
43442
  function createSystemRoutes() {
43213
43443
  const router = (0, import_express7.Router)();
43214
- router.get("/health", asyncHandler7(async (req, res) => {
43444
+ router.get("/health", asyncHandler6(async (req, res) => {
43215
43445
  const { logger: rootLogger } = req.app.locals.deps;
43216
43446
  rootLogger.child("system/health").info("received system health API call", {
43217
43447
  method: req.method,
@@ -43220,7 +43450,7 @@ function createSystemRoutes() {
43220
43450
  });
43221
43451
  res.json({ status: "ok", timestamp: Date.now() });
43222
43452
  }));
43223
- router.get("/info", asyncHandler7(async (req, res) => {
43453
+ router.get("/info", asyncHandler6(async (req, res) => {
43224
43454
  const { nodeRegistry, getTransportType, config, dashboardOrigin } = req.app.locals.deps;
43225
43455
  const self2 = nodeRegistry.getSelf();
43226
43456
  res.json({
@@ -43236,7 +43466,7 @@ function createSystemRoutes() {
43236
43466
  }
43237
43467
  });
43238
43468
  }));
43239
- router.post("/transport", asyncHandler7(async (req, res) => {
43469
+ router.post("/transport", asyncHandler6(async (req, res) => {
43240
43470
  const { switchTransport } = req.app.locals.deps;
43241
43471
  if (!switchTransport) {
43242
43472
  res.status(501).json({ error: "Transport switching not available" });
@@ -43250,7 +43480,7 @@ function createSystemRoutes() {
43250
43480
  const newEndpoint = await switchTransport(type);
43251
43481
  res.json({ ok: true, transportType: type, endpoint: newEndpoint });
43252
43482
  }));
43253
- router.post("/devtunnel", asyncHandler7(async (req, res) => {
43483
+ router.post("/devtunnel", asyncHandler6(async (req, res) => {
43254
43484
  const { enableDevTunnel, disableDevTunnel, nodeRegistry, taskEngine } = req.app.locals.deps;
43255
43485
  if (!enableDevTunnel || !disableDevTunnel) {
43256
43486
  res.status(501).json({ error: "DevTunnel control not available" });
@@ -43279,7 +43509,7 @@ function createSystemRoutes() {
43279
43509
  });
43280
43510
  }
43281
43511
  }));
43282
- router.get("/metrics", asyncHandler7(async (req, res) => {
43512
+ router.get("/metrics", asyncHandler6(async (req, res) => {
43283
43513
  const { taskEngine } = req.app.locals.deps;
43284
43514
  const metrics = taskEngine.getMetrics();
43285
43515
  res.json(metrics);
@@ -43440,6 +43670,25 @@ function createServer2(deps) {
43440
43670
  }
43441
43671
  app.use(import_express9.default.json({ limit: JSON_BODY_LIMIT }));
43442
43672
  app.use(createAuthMiddleware(authConfig));
43673
+ app.use((req, res, next) => {
43674
+ void (async () => {
43675
+ if (!req.path.startsWith("/preview/")) {
43676
+ next();
43677
+ return;
43678
+ }
43679
+ if (!canServeDashboard(req)) {
43680
+ res.status(404).type("text/plain").send("Not Found");
43681
+ return;
43682
+ }
43683
+ if (deps.previewProxyManager && await handlePreviewProxyRequest(deps.previewProxyManager, deps.nodeRegistry, deps.logger, req, res)) {
43684
+ return;
43685
+ }
43686
+ if (deps.previewSessionManager && handlePreviewRequest(deps.previewSessionManager, req, res)) {
43687
+ return;
43688
+ }
43689
+ next();
43690
+ })().catch(next);
43691
+ });
43443
43692
  app.use(createRoutingMiddleware(deps.dataRouter));
43444
43693
  const largeBodyParser = import_express9.default.json({ limit: JSON_BODY_LIMIT_LARGE });
43445
43694
  app.use("/api/cluster", createClusterRoutes());
@@ -43468,37 +43717,6 @@ function createServer2(deps) {
43468
43717
  return app;
43469
43718
  }
43470
43719
 
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
43720
  // ../../packages/transport/src/direct.ts
43503
43721
  var import_node_os4 = require("os");
43504
43722
  var import_node_http2 = require("http");
@@ -44382,21 +44600,10 @@ async function main() {
44382
44600
  });
44383
44601
  await meshyNode.start();
44384
44602
  const previewSessionManager = new PreviewSessionManager();
44385
- const previewPort = config.node.port + 1;
44386
- let actualPreviewPort = previewPort;
44603
+ const previewProxyManager = new PreviewProxyManager();
44387
44604
  let dashboardTransport = null;
44388
44605
  let dashboardOrigin;
44389
- let previewTransport = null;
44390
- let previewOrigin;
44391
- let outputServer = null;
44392
44606
  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
44607
  async function closeServer(server2) {
44401
44608
  if (!server2) {
44402
44609
  return;
@@ -44424,33 +44631,15 @@ async function main() {
44424
44631
  }
44425
44632
  };
44426
44633
  }
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
44634
  function setAdvertisedDashboardOrigin(origin) {
44441
44635
  dashboardOrigin = origin;
44442
44636
  deps.dashboardOrigin = origin;
44443
44637
  meshyNode.getNodeRegistry().updateDashboardOrigin(meshyNode.getNodeRegistry().getSelf().id, origin);
44444
44638
  }
44445
- function setAdvertisedPreviewOrigin(origin) {
44446
- previewOrigin = origin;
44447
- deps.previewOrigin = origin;
44448
- meshyNode.getNodeRegistry().updatePreviewOrigin(meshyNode.getNodeRegistry().getSelf().id, origin);
44449
- }
44450
44639
  function shouldPublishDashboardTunnel() {
44451
44640
  return authMetadata.enabled && (meshyNode.getTransportType() === "devtunnel" || meshyNode.isDevTunnelEnabled());
44452
44641
  }
44453
- async function stopDashboardTransport() {
44642
+ async function stopDashboardTransport(reason) {
44454
44643
  if (!dashboardTransport) {
44455
44644
  if (dashboardOrigin) {
44456
44645
  setAdvertisedDashboardOrigin(void 0);
@@ -44461,15 +44650,20 @@ async function main() {
44461
44650
  dashboardTransport = null;
44462
44651
  setAdvertisedDashboardOrigin(void 0);
44463
44652
  meshyNode.getLogger().info("stopped dashboard tunnel", {
44464
- reason: "dashboard transport no longer required",
44653
+ reason,
44465
44654
  mainTransportType: meshyNode.getTransportType(),
44466
44655
  sidecarEnabled: meshyNode.isDevTunnelEnabled()
44467
44656
  });
44468
44657
  }
44469
- async function restartDashboardTransport(transportConfig) {
44658
+ async function restartDashboardTransport(reason) {
44659
+ const transportConfig = createDashboardTransportConfig();
44470
44660
  const previousTransport = dashboardTransport;
44471
- const previousOrigin = dashboardOrigin;
44472
44661
  let nextTransport = null;
44662
+ if (previousTransport) {
44663
+ await previousTransport.stop().catch(() => void 0);
44664
+ dashboardTransport = null;
44665
+ setAdvertisedDashboardOrigin(void 0);
44666
+ }
44473
44667
  try {
44474
44668
  nextTransport = createTransport(transportConfig);
44475
44669
  await nextTransport.start(config.node.port);
@@ -44477,20 +44671,20 @@ async function main() {
44477
44671
  dashboardTransport = nextTransport;
44478
44672
  setAdvertisedDashboardOrigin(nextOrigin);
44479
44673
  meshyNode.getLogger().info("started dashboard tunnel", {
44674
+ reason,
44480
44675
  dashboardOrigin: nextOrigin,
44676
+ stableUrl: true,
44481
44677
  mainTransportType: meshyNode.getTransportType(),
44482
44678
  sidecarEnabled: meshyNode.isDevTunnelEnabled()
44483
44679
  });
44484
- if (previousTransport) {
44485
- await previousTransport.stop().catch(() => void 0);
44486
- }
44487
44680
  } catch (err) {
44488
44681
  if (nextTransport) {
44489
44682
  await nextTransport.stop().catch(() => void 0);
44490
44683
  }
44491
- dashboardTransport = previousTransport;
44492
- setAdvertisedDashboardOrigin(previousOrigin);
44684
+ dashboardTransport = null;
44685
+ setAdvertisedDashboardOrigin(void 0);
44493
44686
  meshyNode.getLogger().warn("failed to start dashboard transport", {
44687
+ reason,
44494
44688
  error: err instanceof Error ? err.message : String(err),
44495
44689
  port: config.node.port,
44496
44690
  transportType: transportConfig.type
@@ -44499,7 +44693,7 @@ async function main() {
44499
44693
  }
44500
44694
  async function syncDashboardTransport(reason) {
44501
44695
  if (!authMetadata.enabled) {
44502
- await stopDashboardTransport();
44696
+ await stopDashboardTransport("auth disabled");
44503
44697
  return;
44504
44698
  }
44505
44699
  if (!shouldPublishDashboardTunnel()) {
@@ -44509,7 +44703,7 @@ async function main() {
44509
44703
  sidecarEnabled: meshyNode.isDevTunnelEnabled(),
44510
44704
  authEnabled: authMetadata.enabled
44511
44705
  });
44512
- await stopDashboardTransport();
44706
+ await stopDashboardTransport(reason);
44513
44707
  return;
44514
44708
  }
44515
44709
  if (dashboardTransport && await dashboardTransport.isHealthy().catch(() => false)) {
@@ -44521,37 +44715,7 @@ async function main() {
44521
44715
  });
44522
44716
  return;
44523
44717
  }
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
- }
44718
+ await restartDashboardTransport(reason);
44555
44719
  }
44556
44720
  deps = {
44557
44721
  dataRouter: meshyNode.getDataRouter(),
@@ -44571,6 +44735,7 @@ async function main() {
44571
44735
  persistNodeNamePreference: (name2) => persistDefaultNodeName(config.storage.path, name2),
44572
44736
  joinCurrentNodeToCluster: async (leaderEndpoint) => {
44573
44737
  await meshyNode.joinCluster(leaderEndpoint);
44738
+ await syncDashboardTransport("joinCluster");
44574
44739
  },
44575
44740
  leaveCurrentCluster: async () => {
44576
44741
  await meshyNode.leaveCluster();
@@ -44597,29 +44762,12 @@ async function main() {
44597
44762
  await syncDashboardTransport("disableDevTunnel");
44598
44763
  },
44599
44764
  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
- }
44765
+ localDashboardOrigin: `http://localhost:${config.node.port}`,
44766
+ dashboardOrigin
44613
44767
  };
44614
44768
  deps.previewSessionManager = previewSessionManager;
44615
- deps.previewPort = actualPreviewPort;
44769
+ deps.previewProxyManager = previewProxyManager;
44616
44770
  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
44771
  meshyNode.getLogger().info("configured node auth mode", {
44624
44772
  authEnabled: authMetadata.enabled,
44625
44773
  allowSameTenant: authMetadata.allowSameTenant,
@@ -44627,20 +44775,31 @@ async function main() {
44627
44775
  mainTransportType: meshyNode.getTransportType(),
44628
44776
  sidecarEnabled: meshyNode.isDevTunnelEnabled()
44629
44777
  });
44630
- await restartPreviewTransport(createPreviewTransportConfig());
44631
44778
  await syncDashboardTransport("startup");
44632
- const previewHealthTimer = setInterval(() => {
44779
+ const nodeTunnelHealthTimer = setInterval(() => {
44633
44780
  void (async () => {
44634
- if (!previewTransport) return;
44635
- const healthy = await previewTransport.isHealthy().catch(() => false);
44781
+ if (!meshyNode.hasPublishedNodeTunnel()) return;
44782
+ const healthy = await meshyNode.isPublishedNodeTunnelHealthy().catch(() => false);
44636
44783
  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
44784
+ meshyNode.getLogger().warn("published node tunnel became unhealthy; restarting with stable id", {
44785
+ mainTransportType: meshyNode.getTransportType(),
44786
+ sidecarEnabled: meshyNode.isDevTunnelEnabled()
44642
44787
  });
44643
- await restartPreviewTransport(createPreviewTransportConfig());
44788
+ try {
44789
+ const endpoint = await meshyNode.restartPublishedNodeTunnel();
44790
+ meshyNode.getLogger().info("restarted published node tunnel", {
44791
+ endpoint,
44792
+ stableUrl: true,
44793
+ mainTransportType: meshyNode.getTransportType(),
44794
+ sidecarEnabled: meshyNode.isDevTunnelEnabled()
44795
+ });
44796
+ } catch (err) {
44797
+ meshyNode.getLogger().warn("failed to restart published node tunnel", {
44798
+ error: err instanceof Error ? err.message : String(err),
44799
+ mainTransportType: meshyNode.getTransportType(),
44800
+ sidecarEnabled: meshyNode.isDevTunnelEnabled()
44801
+ });
44802
+ }
44644
44803
  })();
44645
44804
  }, config.cluster.heartbeatInterval);
44646
44805
  const dashboardHealthTimer = setInterval(() => {
@@ -44648,12 +44807,10 @@ async function main() {
44648
44807
  if (!dashboardTransport) return;
44649
44808
  const healthy = await dashboardTransport.isHealthy().catch(() => false);
44650
44809
  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", {
44810
+ meshyNode.getLogger().warn("dashboard tunnel became unhealthy; restarting with stable id", {
44655
44811
  port: config.node.port
44656
44812
  });
44813
+ await restartDashboardTransport("healthcheck");
44657
44814
  })();
44658
44815
  }, config.cluster.heartbeatInterval);
44659
44816
  const app = createServer2(deps);
@@ -44680,14 +44837,10 @@ async function main() {
44680
44837
  console.log("\nShutting down...");
44681
44838
  try {
44682
44839
  clearInterval(dashboardHealthTimer);
44683
- clearInterval(previewHealthTimer);
44840
+ clearInterval(nodeTunnelHealthTimer);
44684
44841
  if (dashboardTransport) {
44685
44842
  await dashboardTransport.stop();
44686
44843
  }
44687
- if (previewTransport) {
44688
- await previewTransport.stop();
44689
- }
44690
- await closeServer(outputServer);
44691
44844
  await meshyNode.stop();
44692
44845
  await closeServer(server);
44693
44846
  console.log("Goodbye!");