meshy-node 0.0.6 → 0.0.7

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
@@ -22771,9 +22771,11 @@ __export(main_exports, {
22771
22771
  DEFAULT_CONFIG: () => DEFAULT_CONFIG3,
22772
22772
  DEFAULT_NODE_NAME: () => DEFAULT_NODE_NAME,
22773
22773
  DEFAULT_NODE_PORT: () => DEFAULT_NODE_PORT,
22774
+ applyStartMetadata: () => applyStartMetadata,
22774
22775
  createDefaultConfig: () => createDefaultConfig,
22775
22776
  createRuntimeDefaultConfig: () => createRuntimeDefaultConfig,
22776
22777
  formatBanner: () => formatBanner,
22778
+ formatLoadedStartMetadata: () => formatLoadedStartMetadata,
22777
22779
  getDefaultNodeName: () => getDefaultNodeName,
22778
22780
  isDirectRunPath: () => isDirectRunPath,
22779
22781
  loadConfigFile: () => loadConfigFile,
@@ -22781,12 +22783,12 @@ __export(main_exports, {
22781
22783
  mergeConfig: () => mergeConfig,
22782
22784
  parseArgs: () => parseArgs,
22783
22785
  promptStartOptions: () => promptStartOptions,
22786
+ resolveRuntimeAuthMetadata: () => resolveRuntimeAuthMetadata,
22787
+ shouldCollectStartOptions: () => shouldCollectStartOptions,
22784
22788
  shouldPromptForStartOptions: () => shouldPromptForStartOptions
22785
22789
  });
22786
22790
  module.exports = __toCommonJS(main_exports);
22787
- var fs16 = __toESM(require("fs"), 1);
22788
22791
  var nodePath = __toESM(require("path"), 1);
22789
- var readline = __toESM(require("readline/promises"), 1);
22790
22792
 
22791
22793
  // ../../packages/core/src/logger.ts
22792
22794
  var fs = __toESM(require("fs"), 1);
@@ -22810,18 +22812,19 @@ function hourlyFolder(date) {
22810
22812
  var FileWriter = class {
22811
22813
  constructor(logDir, component, clock) {
22812
22814
  this.logDir = logDir;
22813
- this.component = component;
22814
22815
  this.clock = clock;
22816
+ this.fileName = component.replace(/[/\\]/g, "-");
22815
22817
  }
22816
22818
  currentFolder = "";
22817
22819
  currentStream = null;
22820
+ fileName;
22818
22821
  write(chunk) {
22819
22822
  const folder = hourlyFolder(this.clock());
22820
22823
  if (folder !== this.currentFolder) {
22821
22824
  this.currentStream?.end();
22822
22825
  const dir = path.join(this.logDir, folder);
22823
22826
  fs.mkdirSync(dir, { recursive: true });
22824
- const filePath = path.join(dir, `${this.component}.log`);
22827
+ const filePath = path.join(dir, `${this.fileName}.log`);
22825
22828
  this.currentStream = fs.createWriteStream(filePath, { flags: "a" });
22826
22829
  this.currentFolder = folder;
22827
22830
  }
@@ -22856,6 +22859,12 @@ var MeshyLogger = class _MeshyLogger {
22856
22859
  this.log("error", msg, data);
22857
22860
  }
22858
22861
  child(component) {
22862
+ if (this.state.logDir) {
22863
+ const fileWriter = new FileWriter(this.state.logDir, component, this.state.clock);
22864
+ const writer = this.state.consoleEnabled ? new MultiWriter([process.stdout, fileWriter]) : fileWriter;
22865
+ const childState = { ...this.state, writer };
22866
+ return new _MeshyLogger(childState, component);
22867
+ }
22859
22868
  return new _MeshyLogger(this.state, component);
22860
22869
  }
22861
22870
  log(level, msg, data) {
@@ -22912,7 +22921,9 @@ function createLogger(options = {}) {
22912
22921
  level: options.level ?? "info",
22913
22922
  nodeId: options.nodeId,
22914
22923
  clock,
22915
- writer
22924
+ writer,
22925
+ logDir: options.logDir,
22926
+ consoleEnabled: options.console
22916
22927
  };
22917
22928
  return new MeshyRootLogger(state, options.component);
22918
22929
  }
@@ -22996,10 +23007,14 @@ function getTaskInitialMessageContent(task) {
22996
23007
  return normalizeTaskUserMessageContent(task.description || task.title);
22997
23008
  }
22998
23009
 
23010
+ // ../../packages/core/src/azure-cli-auth.ts
23011
+ var import_node_child_process = require("child_process");
23012
+
22999
23013
  // ../../packages/core/src/node-metadata.ts
23000
23014
  var fs2 = __toESM(require("fs"), 1);
23001
23015
  var os = __toESM(require("os"), 1);
23002
23016
  var path2 = __toESM(require("path"), 1);
23017
+ var STARTUP_TRANSPORTS = /* @__PURE__ */ new Set(["direct", "devtunnel", "tailscale"]);
23003
23018
  function getDeviceNodeName() {
23004
23019
  return os.hostname();
23005
23020
  }
@@ -23026,8 +23041,59 @@ function writeNodeMetadata(storagePath, metadata) {
23026
23041
  fs2.mkdirSync(storagePath, { recursive: true });
23027
23042
  fs2.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2) + "\n", "utf-8");
23028
23043
  }
23044
+ function normalizeAllowedUsers(allowedUsers) {
23045
+ if (!Array.isArray(allowedUsers)) {
23046
+ return [];
23047
+ }
23048
+ const unique = /* @__PURE__ */ new Set();
23049
+ for (const user of allowedUsers) {
23050
+ if (typeof user !== "string") continue;
23051
+ const normalized = user.trim().toLowerCase();
23052
+ if (normalized.length > 0) {
23053
+ unique.add(normalized);
23054
+ }
23055
+ }
23056
+ return [...unique];
23057
+ }
23058
+ function normalizeAuthMetadata(auth) {
23059
+ return {
23060
+ enabled: auth?.enabled === true,
23061
+ allowSameTenant: auth?.allowSameTenant === true,
23062
+ allowedUsers: normalizeAllowedUsers(auth?.allowedUsers)
23063
+ };
23064
+ }
23065
+ function normalizePositiveInteger(value) {
23066
+ if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
23067
+ return void 0;
23068
+ }
23069
+ return value;
23070
+ }
23071
+ function normalizeString(value) {
23072
+ if (typeof value !== "string") {
23073
+ return void 0;
23074
+ }
23075
+ const trimmed = value.trim();
23076
+ return trimmed.length > 0 ? trimmed : void 0;
23077
+ }
23078
+ function normalizeStartupTransport(value) {
23079
+ return typeof value === "string" && STARTUP_TRANSPORTS.has(value) ? value : void 0;
23080
+ }
23081
+ function normalizeStartupMetadata(startup) {
23082
+ return {
23083
+ port: normalizePositiveInteger(startup?.port),
23084
+ transport: normalizeStartupTransport(startup?.transport),
23085
+ join: normalizeString(startup?.join),
23086
+ workDir: normalizeString(startup?.workDir)
23087
+ };
23088
+ }
23089
+ function hasStartupValues(startup) {
23090
+ return startup.port !== void 0 || startup.transport !== void 0 || startup.join !== void 0 || startup.workDir !== void 0;
23091
+ }
23092
+ function resolvePersistedDefaultNodeName(storagePath) {
23093
+ return normalizeString(readNodeMetadata(storagePath).defaultNodeName);
23094
+ }
23029
23095
  function resolveDefaultNodeName(storagePath, deviceName = getDeviceNodeName()) {
23030
- const preferredName = readNodeMetadata(storagePath).defaultNodeName?.trim();
23096
+ const preferredName = resolvePersistedDefaultNodeName(storagePath);
23031
23097
  return preferredName && preferredName.length > 0 ? preferredName : deviceName;
23032
23098
  }
23033
23099
  function persistDefaultNodeName(storagePath, name, deviceName = getDeviceNodeName()) {
@@ -23040,6 +23106,46 @@ function persistDefaultNodeName(storagePath, name, deviceName = getDeviceNodeNam
23040
23106
  }
23041
23107
  writeNodeMetadata(storagePath, metadata);
23042
23108
  }
23109
+ function resolveNodeAuthMetadata(storagePath) {
23110
+ return normalizeAuthMetadata(readNodeMetadata(storagePath).auth);
23111
+ }
23112
+ function resolveNodeStartupMetadata(storagePath) {
23113
+ return normalizeStartupMetadata(readNodeMetadata(storagePath).startup);
23114
+ }
23115
+ function hasPersistedNodeStartupMetadata(storagePath) {
23116
+ return hasStartupValues(resolveNodeStartupMetadata(storagePath));
23117
+ }
23118
+ function persistNodeAuthMetadata(storagePath, auth) {
23119
+ const metadata = readNodeMetadata(storagePath);
23120
+ const normalized = normalizeAuthMetadata(auth);
23121
+ if (!normalized.enabled && !normalized.allowSameTenant && normalized.allowedUsers.length === 0) {
23122
+ delete metadata.auth;
23123
+ } else {
23124
+ metadata.auth = {
23125
+ enabled: normalized.enabled,
23126
+ allowSameTenant: normalized.allowSameTenant,
23127
+ allowedUsers: normalized.allowedUsers
23128
+ };
23129
+ }
23130
+ writeNodeMetadata(storagePath, metadata);
23131
+ }
23132
+ function persistNodeStartupMetadata(storagePath, startup) {
23133
+ const metadata = readNodeMetadata(storagePath);
23134
+ const normalized = normalizeStartupMetadata(startup);
23135
+ if (!hasStartupValues(normalized)) {
23136
+ delete metadata.startup;
23137
+ } else {
23138
+ metadata.startup = normalized;
23139
+ }
23140
+ writeNodeMetadata(storagePath, metadata);
23141
+ }
23142
+ function persistNodeStartupTransport(storagePath, transport) {
23143
+ const startup = resolveNodeStartupMetadata(storagePath);
23144
+ persistNodeStartupMetadata(storagePath, {
23145
+ ...startup,
23146
+ transport
23147
+ });
23148
+ }
23043
23149
  function resolvePersistedDevTunnelId(storagePath, kind) {
23044
23150
  return readNodeMetadata(storagePath).devTunnelIds?.[kind]?.trim() || void 0;
23045
23151
  }
@@ -23072,6 +23178,246 @@ function resolveOrCreateDevTunnelId(storagePath, nodeId, kind) {
23072
23178
  return generatedId;
23073
23179
  }
23074
23180
 
23181
+ // ../../packages/core/src/azure-cli-auth.ts
23182
+ var DEFAULT_AZ_RESOURCE = process.env.MESHY_AZ_TOKEN_RESOURCE?.trim() || "https://management.azure.com/";
23183
+ var TOKEN_REFRESH_SKEW_MS = 6e4;
23184
+ function summarizeClaims(claims) {
23185
+ return {
23186
+ tid: claims.tid,
23187
+ oid: claims.oid,
23188
+ preferred_username: claims.preferred_username,
23189
+ upn: claims.upn,
23190
+ email: claims.email,
23191
+ aud: claims.aud
23192
+ };
23193
+ }
23194
+ function decodeAzureCliJwtClaims(token) {
23195
+ const parts = token.split(".");
23196
+ if (parts.length < 2) {
23197
+ throw new Error("Token is not a JWT");
23198
+ }
23199
+ const payload = parts[1];
23200
+ if (!payload) {
23201
+ throw new Error("JWT payload is empty");
23202
+ }
23203
+ const normalized = payload.replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(payload.length / 4) * 4, "=");
23204
+ const parsed = JSON.parse(Buffer.from(normalized, "base64").toString("utf-8"));
23205
+ if (!parsed || typeof parsed !== "object") {
23206
+ throw new Error("JWT payload is not an object");
23207
+ }
23208
+ return parsed;
23209
+ }
23210
+ function normalizeIdentityValue(value) {
23211
+ return typeof value === "string" && value.trim().length > 0 ? value.trim().toLowerCase() : void 0;
23212
+ }
23213
+ function getIdentityValues(claims) {
23214
+ const values = /* @__PURE__ */ new Set();
23215
+ for (const candidate of [
23216
+ claims.oid,
23217
+ claims.preferred_username,
23218
+ claims.upn,
23219
+ claims.email,
23220
+ claims.unique_name,
23221
+ claims.sub
23222
+ ]) {
23223
+ const normalized = normalizeIdentityValue(candidate);
23224
+ if (normalized) {
23225
+ values.add(normalized);
23226
+ }
23227
+ }
23228
+ return values;
23229
+ }
23230
+ function parseExpiry(value) {
23231
+ if (typeof value === "number" && Number.isFinite(value)) {
23232
+ return value > 1e10 ? value : value * 1e3;
23233
+ }
23234
+ if (typeof value === "string") {
23235
+ const trimmed = value.trim();
23236
+ if (trimmed.length === 0) {
23237
+ throw new Error("expiresOn is empty");
23238
+ }
23239
+ if (/^\d+$/.test(trimmed)) {
23240
+ const numeric = Number(trimmed);
23241
+ return numeric > 1e10 ? numeric : numeric * 1e3;
23242
+ }
23243
+ const parsed = Date.parse(trimmed);
23244
+ if (!Number.isNaN(parsed)) {
23245
+ return parsed;
23246
+ }
23247
+ }
23248
+ throw new Error("Unable to parse Azure CLI token expiry");
23249
+ }
23250
+ function getAzureCliCommandInvocation(command, args, platform = process.platform) {
23251
+ if (platform !== "win32") {
23252
+ return { command, args };
23253
+ }
23254
+ return {
23255
+ command,
23256
+ args,
23257
+ shell: true
23258
+ };
23259
+ }
23260
+ function defaultCommandRunner(command, args) {
23261
+ const invocation = getAzureCliCommandInvocation(command, args);
23262
+ const result = (0, import_node_child_process.spawnSync)(invocation.command, invocation.args, {
23263
+ encoding: "utf-8",
23264
+ stdio: ["ignore", "pipe", "pipe"],
23265
+ shell: invocation.shell
23266
+ });
23267
+ if (result.error) {
23268
+ throw result.error;
23269
+ }
23270
+ if (result.status !== 0) {
23271
+ const message = result.stderr?.trim() || `Azure CLI command exited with code ${result.status}`;
23272
+ throw new Error(message);
23273
+ }
23274
+ return result.stdout;
23275
+ }
23276
+ var AzureCliNodeAuth = class {
23277
+ constructor(storagePath, options = {}) {
23278
+ this.storagePath = storagePath;
23279
+ this.runCommand = options.commandRunner ?? defaultCommandRunner;
23280
+ this.log = options.logger ?? { debug() {
23281
+ }, info() {
23282
+ }, warn() {
23283
+ }, error() {
23284
+ }, child() {
23285
+ return this;
23286
+ } };
23287
+ this.resource = options.resource?.trim() || DEFAULT_AZ_RESOURCE;
23288
+ this.settingsProvider = options.settingsProvider;
23289
+ }
23290
+ runCommand;
23291
+ log;
23292
+ resource;
23293
+ settingsProvider;
23294
+ cachedToken = null;
23295
+ getSettings() {
23296
+ return this.settingsProvider?.() ?? resolveNodeAuthMetadata(this.storagePath);
23297
+ }
23298
+ isEnabled() {
23299
+ return this.getSettings().enabled;
23300
+ }
23301
+ getAuthorizationHeaders() {
23302
+ if (!this.isEnabled()) {
23303
+ return {};
23304
+ }
23305
+ const token = this.getAccessToken();
23306
+ return {
23307
+ authorization: `Bearer ${token.accessToken}`
23308
+ };
23309
+ }
23310
+ validateAuthorizationHeader(header) {
23311
+ if (!this.isEnabled()) {
23312
+ return { ok: true, reason: "disabled" };
23313
+ }
23314
+ if (typeof header !== "string") {
23315
+ return { ok: false, reason: "missing" };
23316
+ }
23317
+ const token = header.startsWith("Bearer ") ? header.slice("Bearer ".length).trim() : "";
23318
+ if (!token) {
23319
+ return { ok: false, reason: "missing" };
23320
+ }
23321
+ let peerClaims;
23322
+ try {
23323
+ peerClaims = decodeAzureCliJwtClaims(token);
23324
+ } catch {
23325
+ return { ok: false, reason: "invalid" };
23326
+ }
23327
+ const local = this.getAccessToken();
23328
+ const settings = this.getSettings();
23329
+ if (isPeerIdentityAllowed(peerClaims, local.claims, settings)) {
23330
+ return {
23331
+ ok: true,
23332
+ reason: "match",
23333
+ localClaims: local.claims,
23334
+ peerClaims
23335
+ };
23336
+ }
23337
+ return {
23338
+ ok: false,
23339
+ reason: "mismatch",
23340
+ localClaims: local.claims,
23341
+ peerClaims
23342
+ };
23343
+ }
23344
+ getAccessToken() {
23345
+ if (this.cachedToken && this.cachedToken.expiresAtMs - TOKEN_REFRESH_SKEW_MS > Date.now()) {
23346
+ this.log.debug("using cached azure cli access token", {
23347
+ resource: this.resource,
23348
+ expiresAt: new Date(this.cachedToken.expiresAtMs).toISOString(),
23349
+ expiresInMs: this.cachedToken.expiresAtMs - Date.now(),
23350
+ claims: summarizeClaims(this.cachedToken.claims)
23351
+ });
23352
+ return this.cachedToken;
23353
+ }
23354
+ this.log.info("requesting azure cli access token", {
23355
+ resource: this.resource,
23356
+ cachedTokenPresent: this.cachedToken !== null
23357
+ });
23358
+ let raw;
23359
+ try {
23360
+ raw = this.runCommand("az", [
23361
+ "account",
23362
+ "get-access-token",
23363
+ "--resource",
23364
+ this.resource,
23365
+ "--output",
23366
+ "json"
23367
+ ]);
23368
+ } catch (error) {
23369
+ this.log.error("failed to execute az account get-access-token", {
23370
+ resource: this.resource,
23371
+ error: error instanceof Error ? error.message : String(error)
23372
+ });
23373
+ throw error;
23374
+ }
23375
+ const parsed = JSON.parse(raw);
23376
+ if (typeof parsed.accessToken !== "string" || parsed.accessToken.trim().length === 0) {
23377
+ this.log.error("azure cli token response did not include accessToken", {
23378
+ resource: this.resource
23379
+ });
23380
+ throw new Error("Azure CLI did not return accessToken");
23381
+ }
23382
+ const expiresAtMs = parseExpiry(parsed.expiresOn ?? parsed.expires_on);
23383
+ const claims = decodeAzureCliJwtClaims(parsed.accessToken);
23384
+ this.cachedToken = {
23385
+ accessToken: parsed.accessToken,
23386
+ expiresAtMs,
23387
+ claims
23388
+ };
23389
+ this.log.info("received azure cli access token", {
23390
+ resource: this.resource,
23391
+ expiresAt: new Date(expiresAtMs).toISOString(),
23392
+ expiresInMs: expiresAtMs - Date.now(),
23393
+ claims: summarizeClaims(claims)
23394
+ });
23395
+ return this.cachedToken;
23396
+ }
23397
+ };
23398
+ function isPeerIdentityAllowed(peerClaims, localClaims, settings) {
23399
+ const peerIdentities = getIdentityValues(peerClaims);
23400
+ const localIdentities = getIdentityValues(localClaims);
23401
+ for (const identity of peerIdentities) {
23402
+ if (localIdentities.has(identity)) {
23403
+ return true;
23404
+ }
23405
+ }
23406
+ for (const allowedUser of settings.allowedUsers) {
23407
+ if (peerIdentities.has(allowedUser)) {
23408
+ return true;
23409
+ }
23410
+ }
23411
+ if (settings.allowSameTenant) {
23412
+ const peerTenant = normalizeIdentityValue(peerClaims.tid);
23413
+ const localTenant = normalizeIdentityValue(localClaims.tid);
23414
+ if (peerTenant && localTenant && peerTenant === localTenant) {
23415
+ return true;
23416
+ }
23417
+ }
23418
+ return false;
23419
+ }
23420
+
23075
23421
  // ../../packages/core/src/file-store.ts
23076
23422
  var fs3 = __toESM(require("fs"), 1);
23077
23423
  var path3 = __toESM(require("path"), 1);
@@ -23516,6 +23862,7 @@ function parseNodeInfo(value) {
23516
23862
  lastHeartbeat: value.lastHeartbeat,
23517
23863
  transportType: typeof value.transportType === "string" ? value.transportType : void 0,
23518
23864
  devtunnelEndpoint: typeof value.devtunnelEndpoint === "string" ? value.devtunnelEndpoint : void 0,
23865
+ dashboardOrigin: typeof value.dashboardOrigin === "string" ? value.dashboardOrigin : void 0,
23519
23866
  previewOrigin: typeof value.previewOrigin === "string" ? value.previewOrigin : void 0
23520
23867
  };
23521
23868
  }
@@ -23595,6 +23942,38 @@ var EventBus = class {
23595
23942
  }
23596
23943
  };
23597
23944
 
23945
+ // ../../packages/core/src/request-auth.ts
23946
+ var requestAuthHeadersProvider = null;
23947
+ function normalizeHeaders(headers) {
23948
+ if (!headers) {
23949
+ return {};
23950
+ }
23951
+ if (headers instanceof Headers) {
23952
+ return Object.fromEntries(headers.entries());
23953
+ }
23954
+ if (Array.isArray(headers)) {
23955
+ return Object.fromEntries(headers);
23956
+ }
23957
+ return Object.fromEntries(
23958
+ Object.entries(headers).flatMap(
23959
+ ([key, value]) => value === void 0 ? [] : [[key, String(value)]]
23960
+ )
23961
+ );
23962
+ }
23963
+ function setRequestAuthHeadersProvider(provider) {
23964
+ requestAuthHeadersProvider = provider;
23965
+ }
23966
+ function applyRequestAuthHeaders(init = {}) {
23967
+ const headers = normalizeHeaders(init.headers);
23968
+ if (!Object.keys(headers).some((key) => key.toLowerCase() === "authorization") && requestAuthHeadersProvider) {
23969
+ Object.assign(headers, requestAuthHeadersProvider());
23970
+ }
23971
+ return {
23972
+ ...init,
23973
+ headers
23974
+ };
23975
+ }
23976
+
23598
23977
  // ../../packages/core/src/node-endpoints.ts
23599
23978
  var DEFAULT_NODE_REQUEST_TIMEOUT_MS = 1500;
23600
23979
  function getNodePublicEndpoint(node) {
@@ -23623,10 +24002,10 @@ function createRequestSignal(signal, timeoutMs) {
23623
24002
  async function fetchWithTimeout(url, init, timeoutMs = DEFAULT_NODE_REQUEST_TIMEOUT_MS) {
23624
24003
  const { cleanup, signal } = createRequestSignal(init?.signal, timeoutMs);
23625
24004
  try {
23626
- return await fetch(url, {
24005
+ return await fetch(url, applyRequestAuthHeaders({
23627
24006
  ...init,
23628
24007
  signal
23629
- });
24008
+ }));
23630
24009
  } finally {
23631
24010
  cleanup();
23632
24011
  }
@@ -23746,6 +24125,24 @@ var NodeRegistry = class {
23746
24125
  }
23747
24126
  }
23748
24127
  }
24128
+ updateDashboardOrigin(id, dashboardOrigin) {
24129
+ const node = this.nodes.get(id);
24130
+ if (node) {
24131
+ if (dashboardOrigin) {
24132
+ node.dashboardOrigin = dashboardOrigin;
24133
+ } else {
24134
+ delete node.dashboardOrigin;
24135
+ }
24136
+ this.store.upsertNode(node);
24137
+ }
24138
+ if (this.selfNode && this.selfNode.id === id) {
24139
+ if (dashboardOrigin) {
24140
+ this.selfNode.dashboardOrigin = dashboardOrigin;
24141
+ } else {
24142
+ delete this.selfNode.dashboardOrigin;
24143
+ }
24144
+ }
24145
+ }
23749
24146
  updatePreviewOrigin(id, previewOrigin) {
23750
24147
  const node = this.nodes.get(id);
23751
24148
  if (node) {
@@ -24000,11 +24397,11 @@ var LeaderElection = class {
24000
24397
  const announcePromises = onlineNodes.map(async (node) => {
24001
24398
  try {
24002
24399
  const endpoint = getNodePublicEndpoint(node);
24003
- await fetch(`${endpoint}/api/worker/announce`, {
24400
+ await fetch(`${endpoint}/api/worker/announce`, applyRequestAuthHeaders({
24004
24401
  method: "POST",
24005
24402
  headers: { "Content-Type": "application/json" },
24006
24403
  body: JSON.stringify({ leaderId, term })
24007
- });
24404
+ }));
24008
24405
  } catch {
24009
24406
  }
24010
24407
  });
@@ -24782,6 +25179,7 @@ var HeartbeatMonitor = class {
24782
25179
  this.nodeRegistry.updateHeartbeat(node.id, Date.now());
24783
25180
  this.nodeRegistry.updateLoad(node.id, result.load);
24784
25181
  this.applyReportedDevTunnelState(node.id, result.devtunnelEnabled, result.devtunnelEndpoint);
25182
+ this.nodeRegistry.updateDashboardOrigin(node.id, result.dashboardOrigin);
24785
25183
  this.nodeRegistry.updatePreviewOrigin(node.id, result.previewOrigin);
24786
25184
  if (result.workDirFolders) {
24787
25185
  this.nodeRegistry.updateFolders(node.id, result.workDirFolders);
@@ -24825,6 +25223,7 @@ var HeartbeatMonitor = class {
24825
25223
  load: 0,
24826
25224
  devtunnelEnabled: self.devtunnelEndpoint !== void 0,
24827
25225
  devtunnelEndpoint: self.devtunnelEndpoint,
25226
+ dashboardOrigin: self.dashboardOrigin,
24828
25227
  previewOrigin: self.previewOrigin,
24829
25228
  workDirFolders: self.workDir ? listWorkDirFolders(self.workDir) : void 0
24830
25229
  };
@@ -24842,6 +25241,7 @@ var HeartbeatMonitor = class {
24842
25241
  workDir,
24843
25242
  devtunnelEnabled,
24844
25243
  devtunnelEndpoint,
25244
+ dashboardOrigin,
24845
25245
  previewOrigin,
24846
25246
  workDirFolders
24847
25247
  } = req;
@@ -24867,6 +25267,7 @@ var HeartbeatMonitor = class {
24867
25267
  ...transportType ? { transportType } : {},
24868
25268
  ...workDir ? { workDir } : {},
24869
25269
  ...devtunnelEnabled && devtunnelEndpoint ? { devtunnelEndpoint } : {},
25270
+ ...dashboardOrigin ? { dashboardOrigin } : {},
24870
25271
  ...previewOrigin ? { previewOrigin } : {},
24871
25272
  ...workDirFolders ? { workDirFolders } : {}
24872
25273
  });
@@ -24900,6 +25301,7 @@ var HeartbeatMonitor = class {
24900
25301
  }
24901
25302
  this.nodeRegistry.updateLoad(nodeId, load);
24902
25303
  this.applyReportedDevTunnelState(nodeId, devtunnelEnabled, devtunnelEndpoint);
25304
+ this.nodeRegistry.updateDashboardOrigin(nodeId, dashboardOrigin);
24903
25305
  this.nodeRegistry.updatePreviewOrigin(nodeId, previewOrigin);
24904
25306
  if (workDirFolders) {
24905
25307
  this.nodeRegistry.updateFolders(nodeId, workDirFolders);
@@ -24947,15 +25349,16 @@ var HeartbeatMonitor = class {
24947
25349
  workDir: self.workDir,
24948
25350
  devtunnelEnabled: self.devtunnelEndpoint !== void 0,
24949
25351
  devtunnelEndpoint: self.devtunnelEndpoint,
25352
+ dashboardOrigin: self.dashboardOrigin,
24950
25353
  previewOrigin: self.previewOrigin,
24951
25354
  workDirFolders: self.workDir ? listWorkDirFolders(self.workDir) : void 0
24952
25355
  };
24953
25356
  try {
24954
- const response = await fetch(`${leaderEndpoint}/api/worker/keepalive`, {
25357
+ const response = await fetch(`${leaderEndpoint}/api/worker/keepalive`, applyRequestAuthHeaders({
24955
25358
  method: "POST",
24956
25359
  headers: { "Content-Type": "application/json" },
24957
25360
  body: JSON.stringify(request)
24958
- });
25361
+ }));
24959
25362
  if (response.ok) {
24960
25363
  const result = await response.json();
24961
25364
  this.log.debug("keepalive ok", { nodes: result.clusterState.nodes.length });
@@ -25125,11 +25528,11 @@ var HeartbeatMonitor = class {
25125
25528
  }
25126
25529
  }
25127
25530
  try {
25128
- const res = await fetch(`${leaderEndpoint}/api/worker/control-response`, {
25531
+ const res = await fetch(`${leaderEndpoint}/api/worker/control-response`, applyRequestAuthHeaders({
25129
25532
  method: "POST",
25130
25533
  headers: { "Content-Type": "application/json" },
25131
25534
  body: JSON.stringify(response)
25132
- });
25535
+ }));
25133
25536
  if (!res.ok) {
25134
25537
  this.log.warn("leader rejected control response", {
25135
25538
  requestId: request.requestId,
@@ -25219,12 +25622,12 @@ var DataRouter = class {
25219
25622
  const controller = new AbortController();
25220
25623
  const timeoutId = setTimeout(() => controller.abort(), this.config.proxyTimeout);
25221
25624
  try {
25222
- const response = await fetch(targetUrl, {
25625
+ const response = await fetch(targetUrl, applyRequestAuthHeaders({
25223
25626
  method,
25224
25627
  headers: forwardHeaders,
25225
25628
  body,
25226
25629
  signal: controller.signal
25227
- });
25630
+ }));
25228
25631
  const responseHeaders = {};
25229
25632
  response.headers.forEach((value, key) => {
25230
25633
  responseHeaders[key] = value;
@@ -25418,11 +25821,11 @@ function forwardLeaderTaskPatch(log, nodeRegistry, taskId, data, options) {
25418
25821
  log.warn(options.missingLeaderMessage, metadata);
25419
25822
  return;
25420
25823
  }
25421
- fetch(`${leaderEndpoint}/api/tasks/${taskId}`, {
25824
+ fetch(`${leaderEndpoint}/api/tasks/${taskId}`, applyRequestAuthHeaders({
25422
25825
  method: "PATCH",
25423
25826
  headers: { "Content-Type": "application/json" },
25424
25827
  body: JSON.stringify(buildLeaderTaskPatch(data))
25425
- }).then((response) => {
25828
+ })).then((response) => {
25426
25829
  if (!response.ok) {
25427
25830
  log.warn(options.rejectedMessage, {
25428
25831
  ...metadata,
@@ -25469,11 +25872,11 @@ function forwardTaskOutputToLeader(log, nodeRegistry, taskId, event) {
25469
25872
  });
25470
25873
  return;
25471
25874
  }
25472
- fetch(`${leaderEndpoint}/api/worker/output`, {
25875
+ fetch(`${leaderEndpoint}/api/worker/output`, applyRequestAuthHeaders({
25473
25876
  method: "POST",
25474
25877
  headers: { "Content-Type": "application/json" },
25475
25878
  body: JSON.stringify({ taskId, event })
25476
- }).then((response) => {
25879
+ })).then((response) => {
25477
25880
  if (!response.ok) {
25478
25881
  log.warn("leader rejected forwarded output", {
25479
25882
  taskId,
@@ -25541,7 +25944,7 @@ function registerLeaderForwarding(eventBus, nodeRegistry, log, taskId, agent) {
25541
25944
  // ../../packages/core/src/engines/claude-code-engine.ts
25542
25945
  var fs7 = __toESM(require("fs"), 1);
25543
25946
  var path7 = __toESM(require("path"), 1);
25544
- var import_node_child_process = require("child_process");
25947
+ var import_node_child_process2 = require("child_process");
25545
25948
  function resolveClaudeInvocation() {
25546
25949
  if (process.platform !== "win32") {
25547
25950
  return { command: "claude", argsPrefix: [] };
@@ -25603,7 +26006,7 @@ var ClaudeCodeEngine = class extends ExecutionEngine {
25603
26006
  this.ensureLogDir();
25604
26007
  this.logger.info("Spawning claude CLI", { taskId: task.id, title: task.title, cwd });
25605
26008
  const invocation = resolveClaudeInvocation();
25606
- const proc = (0, import_node_child_process.spawn)(invocation.command, [...invocation.argsPrefix, ...args], {
26009
+ const proc = (0, import_node_child_process2.spawn)(invocation.command, [...invocation.argsPrefix, ...args], {
25607
26010
  cwd,
25608
26011
  stdio: ["pipe", "pipe", "pipe"]
25609
26012
  });
@@ -25713,7 +26116,7 @@ var ClaudeCodeEngine = class extends ExecutionEngine {
25713
26116
  "stream-json"
25714
26117
  ];
25715
26118
  const invocation = resolveClaudeInvocation();
25716
- const proc = (0, import_node_child_process.spawn)(invocation.command, [...invocation.argsPrefix, ...args], {
26119
+ const proc = (0, import_node_child_process2.spawn)(invocation.command, [...invocation.argsPrefix, ...args], {
25717
26120
  cwd: session.cwd,
25718
26121
  stdio: ["pipe", "pipe", "pipe"]
25719
26122
  });
@@ -25848,7 +26251,7 @@ var ClaudeCodeEngine = class extends ExecutionEngine {
25848
26251
  // ../../packages/core/src/engines/codex-engine.ts
25849
26252
  var fs8 = __toESM(require("fs"), 1);
25850
26253
  var path8 = __toESM(require("path"), 1);
25851
- var import_node_child_process2 = require("child_process");
26254
+ var import_node_child_process3 = require("child_process");
25852
26255
  function buildAssistantEvent(text, timestamp = (/* @__PURE__ */ new Date()).toISOString()) {
25853
26256
  return {
25854
26257
  type: "assistant",
@@ -25907,7 +26310,7 @@ var CodexEngine = class extends ExecutionEngine {
25907
26310
  const args = this.buildArgs(prompt, imagePaths, { model: config.model });
25908
26311
  this.ensureLogDir();
25909
26312
  this.logger.info("Spawning codex CLI", { taskId: task.id, title: task.title, cwd });
25910
- const proc = (0, import_node_child_process2.spawn)("codex", args, {
26313
+ const proc = (0, import_node_child_process3.spawn)("codex", args, {
25911
26314
  cwd,
25912
26315
  stdio: ["ignore", "pipe", "pipe"]
25913
26316
  });
@@ -25934,7 +26337,7 @@ var CodexEngine = class extends ExecutionEngine {
25934
26337
  const { prompt, imagePaths } = this.prepareAssets(taskId, content);
25935
26338
  const args = this.buildArgs(prompt, imagePaths, { model, sessionId: session.sessionId });
25936
26339
  this.logger.info("Sending Codex follow-up message", { taskId, sessionId: session.sessionId });
25937
- const proc = (0, import_node_child_process2.spawn)("codex", args, {
26340
+ const proc = (0, import_node_child_process3.spawn)("codex", args, {
25938
26341
  cwd: session.cwd,
25939
26342
  stdio: ["ignore", "pipe", "pipe"]
25940
26343
  });
@@ -26300,11 +26703,11 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
26300
26703
  if (this.selfInfo.devtunnelEndpoint) {
26301
26704
  joinBody.devtunnelEndpoint = this.selfInfo.devtunnelEndpoint;
26302
26705
  }
26303
- const response = await fetch(`${seedUrl}/api/cluster/join`, {
26706
+ const response = await fetch(`${seedUrl}/api/cluster/join`, applyRequestAuthHeaders({
26304
26707
  method: "POST",
26305
26708
  headers: { "Content-Type": "application/json" },
26306
26709
  body: JSON.stringify(joinBody)
26307
- });
26710
+ }));
26308
26711
  if (!response.ok) {
26309
26712
  const body = await response.json?.().catch(() => null);
26310
26713
  if (body?.error?.code === "NOT_LEADER") {
@@ -26326,11 +26729,11 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
26326
26729
  return;
26327
26730
  }
26328
26731
  try {
26329
- await fetch(`${leaderEndpoint}/api/cluster/leave`, {
26732
+ await fetch(`${leaderEndpoint}/api/cluster/leave`, applyRequestAuthHeaders({
26330
26733
  method: "POST",
26331
26734
  headers: { "Content-Type": "application/json" },
26332
26735
  body: JSON.stringify({ nodeId: self.id })
26333
- });
26736
+ }));
26334
26737
  } catch {
26335
26738
  }
26336
26739
  const refreshedSelf = {
@@ -26355,11 +26758,11 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
26355
26758
  try {
26356
26759
  const leaderEndpoint = this.nodeRegistry.getLeaderEndpoint();
26357
26760
  if (leaderEndpoint) {
26358
- await fetch(`${leaderEndpoint}/api/cluster/leave`, {
26761
+ await fetch(`${leaderEndpoint}/api/cluster/leave`, applyRequestAuthHeaders({
26359
26762
  method: "POST",
26360
26763
  headers: { "Content-Type": "application/json" },
26361
26764
  body: JSON.stringify({ nodeId: this.selfInfo.id })
26362
- });
26765
+ }));
26363
26766
  }
26364
26767
  } catch {
26365
26768
  }
@@ -26440,11 +26843,11 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
26440
26843
  const leaderEndpoint = this.nodeRegistry.getLeaderEndpoint();
26441
26844
  if (leaderEndpoint && !this.nodeRegistry.isLeader()) {
26442
26845
  try {
26443
- await fetch(`${leaderEndpoint}/api/nodes/${this.selfInfo.id}`, {
26846
+ await fetch(`${leaderEndpoint}/api/nodes/${this.selfInfo.id}`, applyRequestAuthHeaders({
26444
26847
  method: "PATCH",
26445
26848
  headers: { "Content-Type": "application/json" },
26446
26849
  body: JSON.stringify({ endpoint: newEndpoint })
26447
- });
26850
+ }));
26448
26851
  } catch {
26449
26852
  }
26450
26853
  }
@@ -30752,6 +31155,7 @@ var NodeInfoSchema = external_exports.object({
30752
31155
  lastHeartbeat: external_exports.number(),
30753
31156
  transportType: external_exports.string().optional(),
30754
31157
  devtunnelEndpoint: external_exports.string().optional(),
31158
+ dashboardOrigin: external_exports.string().optional(),
30755
31159
  previewOrigin: external_exports.string().optional()
30756
31160
  });
30757
31161
  var JoinTaskSchema = external_exports.object({
@@ -30821,6 +31225,7 @@ var NodeInfoSchema2 = external_exports.object({
30821
31225
  lastHeartbeat: external_exports.number(),
30822
31226
  transportType: external_exports.string().optional(),
30823
31227
  devtunnelEndpoint: external_exports.string().optional(),
31228
+ dashboardOrigin: external_exports.string().optional(),
30824
31229
  previewOrigin: external_exports.string().optional()
30825
31230
  });
30826
31231
  var NodeListQuery = external_exports.object({
@@ -30947,13 +31352,113 @@ var import_express7 = __toESM(require_express2(), 1);
30947
31352
 
30948
31353
  // ../../packages/api/src/middleware/auth.ts
30949
31354
  var SKIP_AUTH_PATHS = ["/api/system/health"];
31355
+ var TRUSTED_LOCAL_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]", "::1"]);
31356
+ function normalizeHost(value) {
31357
+ if (!value) return void 0;
31358
+ const trimmed = value.trim().toLowerCase();
31359
+ if (!trimmed) return void 0;
31360
+ return trimmed.replace(/:\d+$/, "");
31361
+ }
31362
+ function collectHosts(candidates) {
31363
+ const unique = /* @__PURE__ */ new Set();
31364
+ for (const candidate of candidates) {
31365
+ if (!candidate) continue;
31366
+ for (const item of candidate.split(",")) {
31367
+ const normalized = normalizeHost(item);
31368
+ if (normalized) {
31369
+ unique.add(normalized);
31370
+ }
31371
+ }
31372
+ }
31373
+ return [...unique];
31374
+ }
31375
+ function getForwardedHosts(req) {
31376
+ const forwardedHosts = collectHosts([
31377
+ typeof req.headers["x-forwarded-host"] === "string" ? req.headers["x-forwarded-host"] : void 0
31378
+ ]);
31379
+ if (forwardedHosts.length > 0) {
31380
+ return forwardedHosts;
31381
+ }
31382
+ const forwardedHeader = typeof req.headers.forwarded === "string" ? req.headers.forwarded : void 0;
31383
+ if (!forwardedHeader) {
31384
+ return [];
31385
+ }
31386
+ const forwardedMatches = [...forwardedHeader.matchAll(/host=([^;,\s]+)/gi)];
31387
+ return collectHosts(forwardedMatches.map((match) => match[1]?.replace(/^"|"$/g, "")));
31388
+ }
31389
+ function getDirectHosts(req) {
31390
+ return collectHosts([
31391
+ req.hostname,
31392
+ typeof req.headers.host === "string" ? req.headers.host : void 0
31393
+ ]);
31394
+ }
31395
+ function getRequestHosts(req) {
31396
+ const forwardedHosts = getForwardedHosts(req);
31397
+ if (forwardedHosts.length > 0) {
31398
+ return forwardedHosts;
31399
+ }
31400
+ return getDirectHosts(req);
31401
+ }
31402
+ function isTrustedDashboardRequest(req, config) {
31403
+ const trustedHosts = new Set((config.getTrustedHosts?.() ?? []).map((host) => normalizeHost(host)).filter(Boolean));
31404
+ for (const host of getRequestHosts(req)) {
31405
+ if (TRUSTED_LOCAL_HOSTS.has(host) || trustedHosts.has(host)) {
31406
+ return true;
31407
+ }
31408
+ }
31409
+ return false;
31410
+ }
31411
+ function getAuthLogger(req) {
31412
+ const logger = req.app?.locals?.deps?.logger;
31413
+ if (logger && typeof logger.child === "function") {
31414
+ return logger.child("api/auth");
31415
+ }
31416
+ return {
31417
+ debug() {
31418
+ },
31419
+ warn() {
31420
+ }
31421
+ };
31422
+ }
30950
31423
  function createAuthMiddleware(config) {
30951
31424
  return (req, _res, next) => {
30952
- if (!config.apiKey) {
31425
+ const log = getAuthLogger(req);
31426
+ if (SKIP_AUTH_PATHS.includes(req.path)) {
30953
31427
  next();
30954
31428
  return;
30955
31429
  }
30956
- if (SKIP_AUTH_PATHS.includes(req.path)) {
31430
+ if (config.validateBearerToken) {
31431
+ if (isTrustedDashboardRequest(req, config)) {
31432
+ log.debug("skipping bearer auth for trusted dashboard request", {
31433
+ path: req.path,
31434
+ method: req.method,
31435
+ hosts: getRequestHosts(req)
31436
+ });
31437
+ next();
31438
+ return;
31439
+ }
31440
+ const result = config.validateBearerToken(req.headers.authorization);
31441
+ if (!result.ok) {
31442
+ log.warn("rejected bearer-authenticated request", {
31443
+ path: req.path,
31444
+ method: req.method,
31445
+ hosts: getRequestHosts(req),
31446
+ reason: result.reason
31447
+ });
31448
+ throw new MeshyError("VALIDATION_ERROR", "Invalid or missing bearer token", 401, {
31449
+ reason: result.reason
31450
+ });
31451
+ }
31452
+ log.debug("accepted bearer-authenticated request", {
31453
+ path: req.path,
31454
+ method: req.method,
31455
+ hosts: getRequestHosts(req),
31456
+ reason: result.reason
31457
+ });
31458
+ next();
31459
+ return;
31460
+ }
31461
+ if (!config.apiKey) {
30957
31462
  next();
30958
31463
  return;
30959
31464
  }
@@ -31645,10 +32150,10 @@ function readFileContent(root, relativePath) {
31645
32150
  }
31646
32151
 
31647
32152
  // ../../packages/api/src/output/git-diff.ts
31648
- var import_node_child_process3 = require("child_process");
32153
+ var import_node_child_process4 = require("child_process");
31649
32154
  function git(args, cwd) {
31650
32155
  try {
31651
- return (0, import_node_child_process3.execFileSync)("git", ["-C", cwd, ...args], {
32156
+ return (0, import_node_child_process4.execFileSync)("git", ["-C", cwd, ...args], {
31652
32157
  encoding: "utf-8",
31653
32158
  timeout: 1e4,
31654
32159
  stdio: ["pipe", "pipe", "pipe"]
@@ -31841,7 +32346,8 @@ async function executeWorkerControlRequest(deps, request) {
31841
32346
  return jsonResponse(request.requestId, 200, {
31842
32347
  ok: true,
31843
32348
  enabled: true,
31844
- devtunnelEndpoint
32349
+ devtunnelEndpoint,
32350
+ dashboardOrigin: deps.nodeRegistry.getSelf().dashboardOrigin
31845
32351
  });
31846
32352
  }
31847
32353
  if (!deps.disableDevTunnel) {
@@ -31850,7 +32356,8 @@ async function executeWorkerControlRequest(deps, request) {
31850
32356
  await deps.disableDevTunnel();
31851
32357
  return jsonResponse(request.requestId, 200, {
31852
32358
  ok: true,
31853
- enabled: false
32359
+ enabled: false,
32360
+ dashboardOrigin: deps.nodeRegistry.getSelf().dashboardOrigin
31854
32361
  });
31855
32362
  }
31856
32363
  case "task-cancel": {
@@ -32084,10 +32591,19 @@ function createNodeRoutes() {
32084
32591
  }
32085
32592
  if (enabled) {
32086
32593
  const devtunnelEndpoint = await enableDevTunnel();
32087
- res.json({ ok: true, enabled: true, devtunnelEndpoint });
32594
+ res.json({
32595
+ ok: true,
32596
+ enabled: true,
32597
+ devtunnelEndpoint,
32598
+ dashboardOrigin: nodeRegistry.getSelf().dashboardOrigin
32599
+ });
32088
32600
  } else {
32089
32601
  await disableDevTunnel();
32090
- res.json({ ok: true, enabled: false });
32602
+ res.json({
32603
+ ok: true,
32604
+ enabled: false,
32605
+ dashboardOrigin: nodeRegistry.getSelf().dashboardOrigin
32606
+ });
32091
32607
  }
32092
32608
  } else {
32093
32609
  const node = nodeRegistry.getNode(targetId);
@@ -32126,6 +32642,7 @@ function createNodeRoutes() {
32126
32642
  if (result?.ok) {
32127
32643
  if (nodeRegistry.getNode(targetId)) {
32128
32644
  nodeRegistry.updateDevTunnelEndpoint(targetId, result.devtunnelEndpoint);
32645
+ nodeRegistry.updateDashboardOrigin(targetId, result.dashboardOrigin);
32129
32646
  }
32130
32647
  }
32131
32648
  sendWorkerControlResponse(res, controlResponse);
@@ -32141,6 +32658,7 @@ function createNodeRoutes() {
32141
32658
  const updatedNode = nodeRegistry.getNode(targetId);
32142
32659
  if (updatedNode) {
32143
32660
  nodeRegistry.updateDevTunnelEndpoint(targetId, result.devtunnelEndpoint);
32661
+ nodeRegistry.updateDashboardOrigin(targetId, result.dashboardOrigin);
32144
32662
  }
32145
32663
  res.json(result);
32146
32664
  }
@@ -33073,13 +33591,19 @@ function createSystemRoutes() {
33073
33591
  res.json({ status: "ok", timestamp: Date.now() });
33074
33592
  }));
33075
33593
  router.get("/info", asyncHandler5(async (req, res) => {
33076
- const { nodeRegistry, getTransportType } = req.app.locals.deps;
33594
+ const { nodeRegistry, getTransportType, config, dashboardOrigin } = req.app.locals.deps;
33077
33595
  const self = nodeRegistry.getSelf();
33078
33596
  res.json({
33079
33597
  ...self,
33080
33598
  version: "0.1.0",
33081
33599
  uptime: process.uptime(),
33082
- transportType: getTransportType?.() ?? "direct"
33600
+ transportType: getTransportType?.() ?? "direct",
33601
+ dashboardOrigin: dashboardOrigin ?? self.dashboardOrigin,
33602
+ auth: config.authMetadata ?? {
33603
+ enabled: false,
33604
+ allowSameTenant: false,
33605
+ allowedUsers: []
33606
+ }
33083
33607
  });
33084
33608
  }));
33085
33609
  router.post("/transport", asyncHandler5(async (req, res) => {
@@ -33110,10 +33634,19 @@ function createSystemRoutes() {
33110
33634
  assertCanChangeNodeDevTunnel(taskEngine, nodeRegistry.getSelf().id);
33111
33635
  if (enabled) {
33112
33636
  const devtunnelEndpoint = await enableDevTunnel();
33113
- res.json({ ok: true, enabled: true, devtunnelEndpoint });
33637
+ res.json({
33638
+ ok: true,
33639
+ enabled: true,
33640
+ devtunnelEndpoint,
33641
+ dashboardOrigin: nodeRegistry.getSelf().dashboardOrigin
33642
+ });
33114
33643
  } else {
33115
33644
  await disableDevTunnel();
33116
- res.json({ ok: true, enabled: false });
33645
+ res.json({
33646
+ ok: true,
33647
+ enabled: false,
33648
+ dashboardOrigin: nodeRegistry.getSelf().dashboardOrigin
33649
+ });
33117
33650
  }
33118
33651
  }));
33119
33652
  router.get("/metrics", asyncHandler5(async (req, res) => {
@@ -33243,13 +33776,39 @@ function createServer2(deps) {
33243
33776
  if (typeof deps.heartbeat.setControlRequestHandler === "function") {
33244
33777
  deps.heartbeat.setControlRequestHandler((request) => executeWorkerControlRequest(deps, request));
33245
33778
  }
33779
+ const authConfig = {
33780
+ apiKey: deps.config.apiKey,
33781
+ validateBearerToken: deps.config.validateBearerToken,
33782
+ getTrustedHosts: () => {
33783
+ const trustedHosts = [];
33784
+ if (deps.dashboardOrigin) {
33785
+ try {
33786
+ trustedHosts.push(new URL(deps.dashboardOrigin).host);
33787
+ } catch {
33788
+ }
33789
+ }
33790
+ return trustedHosts;
33791
+ }
33792
+ };
33793
+ const isApiRequest = (req) => req.path === "/api" || req.path.startsWith("/api/");
33794
+ const canServeDashboard = (req) => !deps.config.validateBearerToken || isTrustedDashboardRequest(req, authConfig);
33246
33795
  const runtimeBaseDir = resolveRuntimeBaseDir();
33247
33796
  const staticDir = resolveStaticDir(runtimeBaseDir);
33248
33797
  if (staticDir) {
33249
- app.use(import_express7.default.static(staticDir));
33798
+ const staticMiddleware = import_express7.default.static(staticDir);
33799
+ app.use((req, res, next) => {
33800
+ if (isApiRequest(req)) {
33801
+ next();
33802
+ return;
33803
+ }
33804
+ if (!canServeDashboard(req)) {
33805
+ res.status(404).type("text/plain").send("Not Found");
33806
+ return;
33807
+ }
33808
+ staticMiddleware(req, res, next);
33809
+ });
33250
33810
  }
33251
33811
  app.use(import_express7.default.json({ limit: JSON_BODY_LIMIT }));
33252
- const authConfig = { apiKey: deps.config.apiKey };
33253
33812
  app.use(createAuthMiddleware(authConfig));
33254
33813
  app.use(createRoutingMiddleware(deps.dataRouter));
33255
33814
  const largeBodyParser = import_express7.default.json({ limit: JSON_BODY_LIMIT_LARGE });
@@ -33262,7 +33821,15 @@ function createServer2(deps) {
33262
33821
  if (staticDir) {
33263
33822
  const indexPath = path15.join(staticDir, "index.html");
33264
33823
  if (fs15.existsSync(indexPath)) {
33265
- app.get("*", (_req, res) => {
33824
+ app.get("*", (req, res, next) => {
33825
+ if (isApiRequest(req)) {
33826
+ next();
33827
+ return;
33828
+ }
33829
+ if (!canServeDashboard(req)) {
33830
+ res.status(404).type("text/plain").send("Not Found");
33831
+ return;
33832
+ }
33266
33833
  res.sendFile(indexPath);
33267
33834
  });
33268
33835
  }
@@ -33337,10 +33904,10 @@ var DirectTransport = class {
33337
33904
  };
33338
33905
 
33339
33906
  // ../../packages/transport/src/devtunnel.ts
33340
- var import_node_child_process4 = require("child_process");
33907
+ var import_node_child_process5 = require("child_process");
33341
33908
  function isInstalled(cmd) {
33342
33909
  try {
33343
- (0, import_node_child_process4.execSync)(process.platform === "win32" ? `where ${cmd}` : `command -v ${cmd}`, { stdio: "pipe" });
33910
+ (0, import_node_child_process5.execSync)(process.platform === "win32" ? `where ${cmd}` : `command -v ${cmd}`, { stdio: "pipe" });
33344
33911
  return true;
33345
33912
  } catch {
33346
33913
  return false;
@@ -33363,14 +33930,14 @@ var DevTunnelTransport = class {
33363
33930
  );
33364
33931
  }
33365
33932
  try {
33366
- (0, import_node_child_process4.execSync)("devtunnel user show", { stdio: "pipe" });
33933
+ (0, import_node_child_process5.execSync)("devtunnel user show", { stdio: "pipe" });
33367
33934
  } catch {
33368
33935
  throw new Error(
33369
33936
  "Not logged in to devtunnel. Run: devtunnel user login"
33370
33937
  );
33371
33938
  }
33372
33939
  const hostArgs = this.buildHostArgs(localPort);
33373
- const child = (0, import_node_child_process4.spawn)("devtunnel", hostArgs, {
33940
+ const child = (0, import_node_child_process5.spawn)("devtunnel", hostArgs, {
33374
33941
  stdio: ["pipe", "pipe", "pipe"]
33375
33942
  });
33376
33943
  this.process = child;
@@ -33475,7 +34042,7 @@ ${lines.join("")}`
33475
34042
  return void 0;
33476
34043
  }
33477
34044
  try {
33478
- (0, import_node_child_process4.execFileSync)("devtunnel", ["show", tunnelId], { stdio: "pipe" });
34045
+ (0, import_node_child_process5.execFileSync)("devtunnel", ["show", tunnelId], { stdio: "pipe" });
33479
34046
  return tunnelId;
33480
34047
  } catch {
33481
34048
  const createArgs = ["create", tunnelId];
@@ -33483,7 +34050,7 @@ ${lines.join("")}`
33483
34050
  createArgs.push("-a");
33484
34051
  }
33485
34052
  try {
33486
- (0, import_node_child_process4.execFileSync)("devtunnel", createArgs, { stdio: "pipe" });
34053
+ (0, import_node_child_process5.execFileSync)("devtunnel", createArgs, { stdio: "pipe" });
33487
34054
  return tunnelId;
33488
34055
  } catch (err) {
33489
34056
  throw new Error(
@@ -33498,7 +34065,7 @@ ${lines.join("")}`
33498
34065
  return;
33499
34066
  }
33500
34067
  try {
33501
- (0, import_node_child_process4.execFileSync)(
34068
+ (0, import_node_child_process5.execFileSync)(
33502
34069
  "devtunnel",
33503
34070
  ["port", "create", tunnelId, "-p", String(localPort), "--protocol", "http"],
33504
34071
  { stdio: "pipe" }
@@ -33514,7 +34081,7 @@ ${lines.join("")}`
33514
34081
  }
33515
34082
  listTunnelPorts(tunnelId) {
33516
34083
  try {
33517
- const output = (0, import_node_child_process4.execFileSync)("devtunnel", ["port", "list", tunnelId, "-j"], { stdio: "pipe" });
34084
+ const output = (0, import_node_child_process5.execFileSync)("devtunnel", ["port", "list", tunnelId, "-j"], { stdio: "pipe" });
33518
34085
  const parsed = JSON.parse(output.toString());
33519
34086
  const items = Array.isArray(parsed) ? parsed : parsed && typeof parsed === "object" && Array.isArray(parsed.ports) ? parsed.ports : parsed && typeof parsed === "object" && Array.isArray(parsed.value) ? parsed.value : [];
33520
34087
  return items.map((item) => getPortNumber(item)).filter((value) => value !== void 0);
@@ -33526,7 +34093,7 @@ ${lines.join("")}`
33526
34093
  }
33527
34094
  hasTunnelPort(tunnelId, localPort) {
33528
34095
  try {
33529
- (0, import_node_child_process4.execFileSync)(
34096
+ (0, import_node_child_process5.execFileSync)(
33530
34097
  "devtunnel",
33531
34098
  ["port", "show", tunnelId, "-p", String(localPort), "-j"],
33532
34099
  { stdio: "pipe" }
@@ -33580,7 +34147,9 @@ function createTransport(config) {
33580
34147
  }
33581
34148
  }
33582
34149
 
33583
- // src/main.ts
34150
+ // src/startup.ts
34151
+ var fs16 = __toESM(require("fs"), 1);
34152
+ var readline = __toESM(require("readline/promises"), 1);
33584
34153
  function getDefaultNodeName() {
33585
34154
  return getDeviceNodeName();
33586
34155
  }
@@ -33596,9 +34165,10 @@ function createDefaultConfig(storagePath = resolveDefaultStoragePath(), nodeName
33596
34165
  };
33597
34166
  }
33598
34167
  var DEFAULT_CONFIG3 = createDefaultConfig();
33599
- function createRuntimeDefaultConfig(fileConfig) {
34168
+ function createRuntimeDefaultConfig(fileConfig, options = {}) {
33600
34169
  const storagePath = fileConfig.storage?.path ?? resolveDefaultStoragePath();
33601
- return createDefaultConfig(storagePath, resolveDefaultNodeName(storagePath));
34170
+ const nodeName = options.ignorePersistedName ? getDeviceNodeName() : resolveDefaultNodeName(storagePath);
34171
+ return createDefaultConfig(storagePath, nodeName);
33602
34172
  }
33603
34173
  function parseArgs(argv) {
33604
34174
  const result = {};
@@ -33636,6 +34206,12 @@ function parseArgs(argv) {
33636
34206
  result.config = argv[++i];
33637
34207
  }
33638
34208
  break;
34209
+ case "--reset":
34210
+ result.reset = true;
34211
+ break;
34212
+ case "--disable-auth":
34213
+ result.disableAuth = true;
34214
+ break;
33639
34215
  }
33640
34216
  }
33641
34217
  return result;
@@ -33746,6 +34322,67 @@ async function promptStartOptions(args, fileConfig, defaults, prompt) {
33746
34322
  await closePrompt?.();
33747
34323
  }
33748
34324
  }
34325
+ function applyStartMetadata(storagePath, args) {
34326
+ const startup = resolveNodeStartupMetadata(storagePath);
34327
+ const result = { ...args };
34328
+ const loaded = {};
34329
+ const persistedName = resolvePersistedDefaultNodeName(storagePath);
34330
+ if (persistedName && result.name === void 0) {
34331
+ loaded.name = persistedName;
34332
+ }
34333
+ if (startup.port !== void 0 && result.port === void 0) {
34334
+ result.port = startup.port;
34335
+ loaded.port = startup.port;
34336
+ }
34337
+ if (startup.transport && result.transport === void 0) {
34338
+ result.transport = startup.transport;
34339
+ loaded.transport = startup.transport;
34340
+ }
34341
+ if (startup.join && result.join === void 0) {
34342
+ result.join = startup.join;
34343
+ loaded.join = startup.join;
34344
+ }
34345
+ return {
34346
+ args: result,
34347
+ loaded: Object.keys(loaded).length > 0 ? loaded : void 0
34348
+ };
34349
+ }
34350
+ function shouldCollectStartOptions(args, storagePath) {
34351
+ return args.reset === true || !hasPersistedNodeStartupMetadata(storagePath);
34352
+ }
34353
+ function resolveRuntimeAuthMetadata(storagePath, disableAuth = false) {
34354
+ const persisted = resolveNodeAuthMetadata(storagePath);
34355
+ if (disableAuth) {
34356
+ return { ...persisted, enabled: false };
34357
+ }
34358
+ if (!persisted.enabled && !persisted.allowSameTenant && persisted.allowedUsers.length === 0) {
34359
+ return {
34360
+ enabled: true,
34361
+ allowSameTenant: false,
34362
+ allowedUsers: []
34363
+ };
34364
+ }
34365
+ return persisted;
34366
+ }
34367
+ function formatLoadedStartMetadata(info, authEnabled) {
34368
+ const lines = ["Loaded startup options from metadata:"];
34369
+ if (info.name) {
34370
+ lines.push(` Node: ${info.name}`);
34371
+ }
34372
+ if (info.port !== void 0) {
34373
+ lines.push(` Port: ${info.port}`);
34374
+ }
34375
+ if (info.transport) {
34376
+ lines.push(` Transport: ${info.transport}`);
34377
+ }
34378
+ if (info.join) {
34379
+ lines.push(` Join: ${info.join}`);
34380
+ }
34381
+ lines.push(` Auth: ${authEnabled ? "enabled" : "disabled"}`);
34382
+ return lines.join("\n");
34383
+ }
34384
+
34385
+ // src/main.ts
33749
34386
  function formatBanner(info) {
33750
34387
  const lines = [
33751
34388
  `Node: ${info.name}`,
@@ -33753,6 +34390,9 @@ function formatBanner(info) {
33753
34390
  `Endpoint: ${info.endpoint}`,
33754
34391
  `Dashboard: http://localhost:${info.port}`
33755
34392
  ];
34393
+ if (info.dashboardOrigin) {
34394
+ lines.push(`Dashboard Tunnel: ${info.dashboardOrigin}`);
34395
+ }
33756
34396
  const maxLen = Math.max(...lines.map((l) => l.length));
33757
34397
  const innerWidth = maxLen + 4;
33758
34398
  const top = ` \u256D${"\u2500".repeat(innerWidth)}\u256E`;
@@ -33774,16 +34414,48 @@ async function main() {
33774
34414
  const args = parseArgs(process.argv.slice(2));
33775
34415
  const configPath = args.config ?? "./config.json";
33776
34416
  const fileConfig = loadConfigFile(configPath);
33777
- const defaults = createRuntimeDefaultConfig(fileConfig);
33778
- const resolvedArgs = await promptStartOptions(args, fileConfig, defaults);
34417
+ const storagePath = fileConfig.storage?.path ?? resolveDefaultStoragePath();
34418
+ const hydratedArgs = args.reset ? { args: { ...args }, loaded: void 0 } : applyStartMetadata(storagePath, args);
34419
+ const defaults = createRuntimeDefaultConfig(fileConfig, {
34420
+ ignorePersistedName: args.reset === true
34421
+ });
34422
+ const resolvedArgs = shouldCollectStartOptions(args, storagePath) ? await promptStartOptions(
34423
+ args.reset ? args : hydratedArgs.args,
34424
+ fileConfig,
34425
+ defaults
34426
+ ) : hydratedArgs.args;
33779
34427
  const config = mergeConfig(defaults, fileConfig, resolvedArgs);
33780
34428
  persistDefaultNodeName(config.storage.path, config.node.name);
34429
+ persistNodeStartupMetadata(config.storage.path, {
34430
+ port: config.node.port,
34431
+ transport: config.transport.type,
34432
+ join: resolvedArgs.join
34433
+ });
34434
+ const authMetadata = resolveRuntimeAuthMetadata(config.storage.path, resolvedArgs.disableAuth === true);
34435
+ if (!resolvedArgs.disableAuth) {
34436
+ persistNodeAuthMetadata(config.storage.path, authMetadata);
34437
+ }
33781
34438
  const logDir = nodePath.join(config.storage.path, "logs");
33782
34439
  const logger = createLogger({
33783
34440
  component: "node",
33784
34441
  logDir,
33785
34442
  console: true
33786
34443
  });
34444
+ const nodeAuth = new AzureCliNodeAuth(config.storage.path, {
34445
+ logger: logger.child("azure-auth"),
34446
+ settingsProvider: () => authMetadata
34447
+ });
34448
+ if (hydratedArgs.loaded) {
34449
+ console.log("");
34450
+ console.log(formatLoadedStartMetadata(hydratedArgs.loaded, authMetadata.enabled));
34451
+ console.log("");
34452
+ }
34453
+ if (authMetadata.enabled) {
34454
+ nodeAuth.getAccessToken();
34455
+ setRequestAuthHeadersProvider(() => nodeAuth.getAuthorizationHeaders());
34456
+ } else {
34457
+ setRequestAuthHeadersProvider(null);
34458
+ }
33787
34459
  const meshyNode = new MeshyNode(config, {
33788
34460
  logger,
33789
34461
  transportFactory: createTransport
@@ -33793,9 +34465,24 @@ async function main() {
33793
34465
  const previewServer = new PreviewServer(previewSessionManager);
33794
34466
  const previewPort = config.node.port + 1;
33795
34467
  const actualPreviewPort = await previewServer.start(previewPort);
34468
+ let dashboardTransport = null;
34469
+ let dashboardOrigin;
33796
34470
  let previewTransport = null;
33797
34471
  let previewOrigin;
33798
34472
  let deps;
34473
+ function createDashboardTransportConfig() {
34474
+ return {
34475
+ type: "devtunnel",
34476
+ devtunnel: {
34477
+ id: resolveOrCreateDevTunnelId(
34478
+ config.storage.path,
34479
+ meshyNode.getNodeRegistry().getSelf().id,
34480
+ "dashboard"
34481
+ ),
34482
+ allowAnonymous: false
34483
+ }
34484
+ };
34485
+ }
33799
34486
  function createPreviewTransportConfig() {
33800
34487
  return {
33801
34488
  type: "devtunnel",
@@ -33809,11 +34496,92 @@ async function main() {
33809
34496
  }
33810
34497
  };
33811
34498
  }
34499
+ function setAdvertisedDashboardOrigin(origin) {
34500
+ dashboardOrigin = origin;
34501
+ deps.dashboardOrigin = origin;
34502
+ meshyNode.getNodeRegistry().updateDashboardOrigin(meshyNode.getNodeRegistry().getSelf().id, origin);
34503
+ }
33812
34504
  function setAdvertisedPreviewOrigin(origin) {
33813
34505
  previewOrigin = origin;
33814
34506
  deps.previewOrigin = origin;
33815
34507
  meshyNode.getNodeRegistry().updatePreviewOrigin(meshyNode.getNodeRegistry().getSelf().id, origin);
33816
34508
  }
34509
+ function shouldPublishDashboardTunnel() {
34510
+ return authMetadata.enabled && (meshyNode.getTransportType() === "devtunnel" || meshyNode.isDevTunnelEnabled());
34511
+ }
34512
+ async function stopDashboardTransport() {
34513
+ if (!dashboardTransport) {
34514
+ if (dashboardOrigin) {
34515
+ setAdvertisedDashboardOrigin(void 0);
34516
+ }
34517
+ return;
34518
+ }
34519
+ await dashboardTransport.stop().catch(() => void 0);
34520
+ dashboardTransport = null;
34521
+ setAdvertisedDashboardOrigin(void 0);
34522
+ meshyNode.getLogger().info("stopped dashboard tunnel", {
34523
+ reason: "dashboard transport no longer required",
34524
+ mainTransportType: meshyNode.getTransportType(),
34525
+ sidecarEnabled: meshyNode.isDevTunnelEnabled()
34526
+ });
34527
+ }
34528
+ async function restartDashboardTransport(transportConfig) {
34529
+ const previousTransport = dashboardTransport;
34530
+ const previousOrigin = dashboardOrigin;
34531
+ let nextTransport = null;
34532
+ try {
34533
+ nextTransport = createTransport(transportConfig);
34534
+ await nextTransport.start(config.node.port);
34535
+ const nextOrigin = await nextTransport.getEndpoint();
34536
+ dashboardTransport = nextTransport;
34537
+ setAdvertisedDashboardOrigin(nextOrigin);
34538
+ meshyNode.getLogger().info("started dashboard tunnel", {
34539
+ dashboardOrigin: nextOrigin,
34540
+ mainTransportType: meshyNode.getTransportType(),
34541
+ sidecarEnabled: meshyNode.isDevTunnelEnabled()
34542
+ });
34543
+ if (previousTransport) {
34544
+ await previousTransport.stop().catch(() => void 0);
34545
+ }
34546
+ } catch (err) {
34547
+ if (nextTransport) {
34548
+ await nextTransport.stop().catch(() => void 0);
34549
+ }
34550
+ dashboardTransport = previousTransport;
34551
+ setAdvertisedDashboardOrigin(previousOrigin);
34552
+ meshyNode.getLogger().warn("failed to start dashboard transport", {
34553
+ error: err instanceof Error ? err.message : String(err),
34554
+ port: config.node.port,
34555
+ transportType: transportConfig.type
34556
+ });
34557
+ }
34558
+ }
34559
+ async function syncDashboardTransport(reason) {
34560
+ if (!authMetadata.enabled) {
34561
+ await stopDashboardTransport();
34562
+ return;
34563
+ }
34564
+ if (!shouldPublishDashboardTunnel()) {
34565
+ meshyNode.getLogger().info("skipping dashboard tunnel", {
34566
+ reason,
34567
+ mainTransportType: meshyNode.getTransportType(),
34568
+ sidecarEnabled: meshyNode.isDevTunnelEnabled(),
34569
+ authEnabled: authMetadata.enabled
34570
+ });
34571
+ await stopDashboardTransport();
34572
+ return;
34573
+ }
34574
+ if (dashboardTransport && await dashboardTransport.isHealthy().catch(() => false)) {
34575
+ meshyNode.getLogger().debug("dashboard tunnel already active", {
34576
+ reason,
34577
+ dashboardOrigin,
34578
+ mainTransportType: meshyNode.getTransportType(),
34579
+ sidecarEnabled: meshyNode.isDevTunnelEnabled()
34580
+ });
34581
+ return;
34582
+ }
34583
+ await restartDashboardTransport(createDashboardTransportConfig());
34584
+ }
33817
34585
  async function restartPreviewTransport(transportConfig) {
33818
34586
  const previousTransport = previewTransport;
33819
34587
  const previousOrigin = previewOrigin;
@@ -33849,7 +34617,11 @@ async function main() {
33849
34617
  eventBus: meshyNode.getEventBus(),
33850
34618
  engineRegistry: meshyNode.getEngineRegistry(),
33851
34619
  logger: meshyNode.getLogger(),
33852
- config: { apiKey: config.cluster.apiKey },
34620
+ config: {
34621
+ apiKey: config.cluster.apiKey,
34622
+ authMetadata,
34623
+ validateBearerToken: authMetadata.enabled ? (header) => nodeAuth.validateAuthorizationHeader(header) : void 0
34624
+ },
33853
34625
  workDir: meshyNode.getWorkDir(),
33854
34626
  persistNodeNamePreference: (name) => persistDefaultNodeName(config.storage.path, name),
33855
34627
  joinCurrentNodeToCluster: async (leaderEndpoint) => {
@@ -33859,12 +34631,28 @@ async function main() {
33859
34631
  await meshyNode.leaveCluster();
33860
34632
  },
33861
34633
  switchTransport: async (type) => {
33862
- return meshyNode.switchTransport(type);
34634
+ const endpoint = await meshyNode.switchTransport(type);
34635
+ persistNodeStartupTransport(config.storage.path, type);
34636
+ await syncDashboardTransport(`switchTransport:${type}`);
34637
+ return endpoint;
33863
34638
  },
33864
34639
  getTransportType: () => meshyNode.getTransportType(),
33865
- enableDevTunnel: async () => meshyNode.enableDevTunnel(),
33866
- disableDevTunnel: async () => meshyNode.disableDevTunnel(),
34640
+ enableDevTunnel: async () => {
34641
+ const endpoint = await meshyNode.enableDevTunnel();
34642
+ persistNodeStartupTransport(config.storage.path, "devtunnel");
34643
+ await syncDashboardTransport("enableDevTunnel");
34644
+ return endpoint;
34645
+ },
34646
+ disableDevTunnel: async () => {
34647
+ await meshyNode.disableDevTunnel();
34648
+ persistNodeStartupTransport(
34649
+ config.storage.path,
34650
+ meshyNode.getTransportType()
34651
+ );
34652
+ await syncDashboardTransport("disableDevTunnel");
34653
+ },
33867
34654
  isDevTunnelEnabled: () => meshyNode.isDevTunnelEnabled(),
34655
+ dashboardOrigin,
33868
34656
  ensurePreviewOrigin: async () => {
33869
34657
  if (previewTransport && !await previewTransport.isHealthy()) {
33870
34658
  await previewTransport.stop().catch(() => void 0);
@@ -33880,7 +34668,16 @@ async function main() {
33880
34668
  };
33881
34669
  deps.previewSessionManager = previewSessionManager;
33882
34670
  deps.previewPort = actualPreviewPort;
34671
+ deps.dashboardOrigin = dashboardOrigin;
33883
34672
  deps.previewOrigin = previewOrigin;
34673
+ meshyNode.getLogger().info("configured node auth mode", {
34674
+ authEnabled: authMetadata.enabled,
34675
+ allowSameTenant: authMetadata.allowSameTenant,
34676
+ allowedUsersCount: authMetadata.allowedUsers.length,
34677
+ mainTransportType: meshyNode.getTransportType(),
34678
+ sidecarEnabled: meshyNode.isDevTunnelEnabled()
34679
+ });
34680
+ await syncDashboardTransport("startup");
33884
34681
  const previewHealthTimer = setInterval(() => {
33885
34682
  void (async () => {
33886
34683
  if (!previewTransport) return;
@@ -33894,6 +34691,19 @@ async function main() {
33894
34691
  });
33895
34692
  })();
33896
34693
  }, config.cluster.heartbeatInterval);
34694
+ const dashboardHealthTimer = setInterval(() => {
34695
+ void (async () => {
34696
+ if (!dashboardTransport) return;
34697
+ const healthy = await dashboardTransport.isHealthy().catch(() => false);
34698
+ if (healthy) return;
34699
+ await dashboardTransport.stop().catch(() => void 0);
34700
+ dashboardTransport = null;
34701
+ setAdvertisedDashboardOrigin(void 0);
34702
+ meshyNode.getLogger().warn("dashboard transport became unhealthy and was cleared", {
34703
+ port: config.node.port
34704
+ });
34705
+ })();
34706
+ }, config.cluster.heartbeatInterval);
33897
34707
  const app = createServer2(deps);
33898
34708
  const server = app.listen(config.node.port, () => {
33899
34709
  const self = meshyNode.getNodeRegistry().getSelf();
@@ -33904,7 +34714,8 @@ async function main() {
33904
34714
  role,
33905
34715
  term,
33906
34716
  endpoint: self.endpoint,
33907
- port: config.node.port
34717
+ port: config.node.port,
34718
+ dashboardOrigin
33908
34719
  });
33909
34720
  console.log("");
33910
34721
  console.log(banner);
@@ -33916,7 +34727,11 @@ async function main() {
33916
34727
  shuttingDown = true;
33917
34728
  console.log("\nShutting down...");
33918
34729
  try {
34730
+ clearInterval(dashboardHealthTimer);
33919
34731
  clearInterval(previewHealthTimer);
34732
+ if (dashboardTransport) {
34733
+ await dashboardTransport.stop();
34734
+ }
33920
34735
  if (previewTransport) {
33921
34736
  await previewTransport.stop();
33922
34737
  }
@@ -33945,9 +34760,11 @@ if (isDirectRun) {
33945
34760
  DEFAULT_CONFIG,
33946
34761
  DEFAULT_NODE_NAME,
33947
34762
  DEFAULT_NODE_PORT,
34763
+ applyStartMetadata,
33948
34764
  createDefaultConfig,
33949
34765
  createRuntimeDefaultConfig,
33950
34766
  formatBanner,
34767
+ formatLoadedStartMetadata,
33951
34768
  getDefaultNodeName,
33952
34769
  isDirectRunPath,
33953
34770
  loadConfigFile,
@@ -33955,6 +34772,8 @@ if (isDirectRun) {
33955
34772
  mergeConfig,
33956
34773
  parseArgs,
33957
34774
  promptStartOptions,
34775
+ resolveRuntimeAuthMetadata,
34776
+ shouldCollectStartOptions,
33958
34777
  shouldPromptForStartOptions
33959
34778
  });
33960
34779
  /*! Bundled license information: