meshy-node 0.0.5 → 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/README.md +1 -1
- package/dashboard/assets/DashboardPage-vJKpJw48.js +200 -0
- package/dashboard/assets/{DiffTab-BnEEacma.js → DiffTab-RBHpHnzj.js} +3 -3
- package/dashboard/assets/{FilesTab-BA_AQGff.js → FilesTab-tWHzvDgF.js} +2 -2
- package/dashboard/assets/{PreviewTab-F2z-8pM5.js → PreviewTab-DUfl_tjX.js} +1 -1
- package/dashboard/assets/{folder-TnLGJD38.js → folder-DLwF1-Yt.js} +1 -1
- package/dashboard/assets/{index-Cf2Ckzj8.js → index-B-YQV-_s.js} +4 -4
- package/dashboard/assets/index-bj-TBurH.css +1 -0
- package/dashboard/index.html +2 -2
- package/main.cjs +1151 -111
- package/package.json +1 -1
- package/dashboard/assets/DashboardPage-Du861ESc.js +0 -200
- package/dashboard/assets/index-CS0F09J4.css +0 -1
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.
|
|
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 =
|
|
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
|
}
|
|
@@ -23672,6 +24051,10 @@ var NodeRegistry = class {
|
|
|
23672
24051
|
endpoint: info.endpoint
|
|
23673
24052
|
});
|
|
23674
24053
|
}
|
|
24054
|
+
upsertNode(info) {
|
|
24055
|
+
this.nodes.set(info.id, { ...info });
|
|
24056
|
+
this.store.upsertNode(info);
|
|
24057
|
+
}
|
|
23675
24058
|
removeNode(id) {
|
|
23676
24059
|
this.nodes.delete(id);
|
|
23677
24060
|
this.store.removeNode(id);
|
|
@@ -23742,6 +24125,24 @@ var NodeRegistry = class {
|
|
|
23742
24125
|
}
|
|
23743
24126
|
}
|
|
23744
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
|
+
}
|
|
23745
24146
|
updatePreviewOrigin(id, previewOrigin) {
|
|
23746
24147
|
const node = this.nodes.get(id);
|
|
23747
24148
|
if (node) {
|
|
@@ -23996,11 +24397,11 @@ var LeaderElection = class {
|
|
|
23996
24397
|
const announcePromises = onlineNodes.map(async (node) => {
|
|
23997
24398
|
try {
|
|
23998
24399
|
const endpoint = getNodePublicEndpoint(node);
|
|
23999
|
-
await fetch(`${endpoint}/api/worker/announce`, {
|
|
24400
|
+
await fetch(`${endpoint}/api/worker/announce`, applyRequestAuthHeaders({
|
|
24000
24401
|
method: "POST",
|
|
24001
24402
|
headers: { "Content-Type": "application/json" },
|
|
24002
24403
|
body: JSON.stringify({ leaderId, term })
|
|
24003
|
-
});
|
|
24404
|
+
}));
|
|
24004
24405
|
} catch {
|
|
24005
24406
|
}
|
|
24006
24407
|
});
|
|
@@ -24092,6 +24493,44 @@ var TaskEngine = class {
|
|
|
24092
24493
|
const tasks = this.store.getAllTasks(filter);
|
|
24093
24494
|
return { tasks, total: tasks.length };
|
|
24094
24495
|
}
|
|
24496
|
+
importTasks(tasks) {
|
|
24497
|
+
let created = 0;
|
|
24498
|
+
let updated = 0;
|
|
24499
|
+
for (const task of tasks) {
|
|
24500
|
+
const existing = this.store.getTask(task.id);
|
|
24501
|
+
if (!existing) {
|
|
24502
|
+
this.store.createTask(task);
|
|
24503
|
+
created++;
|
|
24504
|
+
this.eventBus.emit("task.created", {
|
|
24505
|
+
taskId: task.id,
|
|
24506
|
+
title: task.title,
|
|
24507
|
+
priority: task.priority
|
|
24508
|
+
});
|
|
24509
|
+
this.eventBus.emit("task.status", {
|
|
24510
|
+
taskId: task.id,
|
|
24511
|
+
status: task.status,
|
|
24512
|
+
...task.result ? { result: task.result } : {},
|
|
24513
|
+
...task.error ? { error: task.error } : {}
|
|
24514
|
+
});
|
|
24515
|
+
continue;
|
|
24516
|
+
}
|
|
24517
|
+
if (existing.updatedAt > task.updatedAt) {
|
|
24518
|
+
continue;
|
|
24519
|
+
}
|
|
24520
|
+
const previousStatus = existing.status;
|
|
24521
|
+
this.store.updateTask(task.id, task);
|
|
24522
|
+
updated++;
|
|
24523
|
+
if (task.status !== previousStatus) {
|
|
24524
|
+
this.eventBus.emit("task.status", {
|
|
24525
|
+
taskId: task.id,
|
|
24526
|
+
status: task.status,
|
|
24527
|
+
...task.result ? { result: task.result } : {},
|
|
24528
|
+
...task.error ? { error: task.error } : {}
|
|
24529
|
+
});
|
|
24530
|
+
}
|
|
24531
|
+
}
|
|
24532
|
+
return { created, updated };
|
|
24533
|
+
}
|
|
24095
24534
|
updateTask(id, updates) {
|
|
24096
24535
|
const existing = this.store.getTask(id);
|
|
24097
24536
|
if (!existing) return null;
|
|
@@ -24740,6 +25179,7 @@ var HeartbeatMonitor = class {
|
|
|
24740
25179
|
this.nodeRegistry.updateHeartbeat(node.id, Date.now());
|
|
24741
25180
|
this.nodeRegistry.updateLoad(node.id, result.load);
|
|
24742
25181
|
this.applyReportedDevTunnelState(node.id, result.devtunnelEnabled, result.devtunnelEndpoint);
|
|
25182
|
+
this.nodeRegistry.updateDashboardOrigin(node.id, result.dashboardOrigin);
|
|
24743
25183
|
this.nodeRegistry.updatePreviewOrigin(node.id, result.previewOrigin);
|
|
24744
25184
|
if (result.workDirFolders) {
|
|
24745
25185
|
this.nodeRegistry.updateFolders(node.id, result.workDirFolders);
|
|
@@ -24783,17 +25223,76 @@ var HeartbeatMonitor = class {
|
|
|
24783
25223
|
load: 0,
|
|
24784
25224
|
devtunnelEnabled: self.devtunnelEndpoint !== void 0,
|
|
24785
25225
|
devtunnelEndpoint: self.devtunnelEndpoint,
|
|
25226
|
+
dashboardOrigin: self.dashboardOrigin,
|
|
24786
25227
|
previewOrigin: self.previewOrigin,
|
|
24787
25228
|
workDirFolders: self.workDir ? listWorkDirFolders(self.workDir) : void 0
|
|
24788
25229
|
};
|
|
24789
25230
|
}
|
|
24790
25231
|
// ── Leader: handle keepalive from follower ──────────────────────────
|
|
24791
25232
|
handleKeepalive(req) {
|
|
24792
|
-
const {
|
|
25233
|
+
const {
|
|
25234
|
+
nodeId,
|
|
25235
|
+
name,
|
|
25236
|
+
endpoint,
|
|
25237
|
+
status,
|
|
25238
|
+
load,
|
|
25239
|
+
capabilities,
|
|
25240
|
+
transportType,
|
|
25241
|
+
workDir,
|
|
25242
|
+
devtunnelEnabled,
|
|
25243
|
+
devtunnelEndpoint,
|
|
25244
|
+
dashboardOrigin,
|
|
25245
|
+
previewOrigin,
|
|
25246
|
+
workDirFolders
|
|
25247
|
+
} = req;
|
|
25248
|
+
const existingNode = this.nodeRegistry.getNode(nodeId);
|
|
25249
|
+
const normalizedName = name ?? existingNode?.name ?? nodeId;
|
|
25250
|
+
const normalizedEndpoint = endpoint ?? existingNode?.endpoint ?? devtunnelEndpoint ?? "";
|
|
25251
|
+
const normalizedCapabilities = capabilities ?? existingNode?.capabilities ?? [];
|
|
25252
|
+
const currentCapabilities = existingNode?.capabilities ?? [];
|
|
24793
25253
|
this.log.debug("keepalive received", { nodeId, status });
|
|
24794
25254
|
this.followerMissedMap.set(nodeId, 0);
|
|
24795
|
-
|
|
24796
|
-
const
|
|
25255
|
+
let node = existingNode;
|
|
25256
|
+
const now = Date.now();
|
|
25257
|
+
if (!node) {
|
|
25258
|
+
this.nodeRegistry.addNode({
|
|
25259
|
+
id: nodeId,
|
|
25260
|
+
name: normalizedName,
|
|
25261
|
+
endpoint: normalizedEndpoint,
|
|
25262
|
+
role: "follower",
|
|
25263
|
+
status,
|
|
25264
|
+
capabilities: normalizedCapabilities,
|
|
25265
|
+
joinedAt: now,
|
|
25266
|
+
lastHeartbeat: now,
|
|
25267
|
+
...transportType ? { transportType } : {},
|
|
25268
|
+
...workDir ? { workDir } : {},
|
|
25269
|
+
...devtunnelEnabled && devtunnelEndpoint ? { devtunnelEndpoint } : {},
|
|
25270
|
+
...dashboardOrigin ? { dashboardOrigin } : {},
|
|
25271
|
+
...previewOrigin ? { previewOrigin } : {},
|
|
25272
|
+
...workDirFolders ? { workDirFolders } : {}
|
|
25273
|
+
});
|
|
25274
|
+
this.log.info("keepalive restored missing follower", { nodeId, endpoint: normalizedEndpoint });
|
|
25275
|
+
node = this.nodeRegistry.getNode(nodeId);
|
|
25276
|
+
}
|
|
25277
|
+
this.nodeRegistry.updateHeartbeat(nodeId, now);
|
|
25278
|
+
node = this.nodeRegistry.getNode(nodeId);
|
|
25279
|
+
if (node && normalizedEndpoint && node.endpoint !== normalizedEndpoint) {
|
|
25280
|
+
this.nodeRegistry.updateEndpoint(nodeId, normalizedEndpoint);
|
|
25281
|
+
node = this.nodeRegistry.getNode(nodeId);
|
|
25282
|
+
}
|
|
25283
|
+
if (node && (node.name !== normalizedName || node.transportType !== transportType || node.workDir !== workDir || currentCapabilities.length !== normalizedCapabilities.length || currentCapabilities.some((capability, index) => capability !== normalizedCapabilities[index]))) {
|
|
25284
|
+
this.nodeRegistry.upsertNode({
|
|
25285
|
+
...node,
|
|
25286
|
+
name: normalizedName,
|
|
25287
|
+
endpoint: normalizedEndpoint || node.endpoint,
|
|
25288
|
+
status,
|
|
25289
|
+
lastHeartbeat: now,
|
|
25290
|
+
capabilities: normalizedCapabilities,
|
|
25291
|
+
...transportType ? { transportType } : {},
|
|
25292
|
+
...workDir ? { workDir } : {}
|
|
25293
|
+
});
|
|
25294
|
+
node = this.nodeRegistry.getNode(nodeId);
|
|
25295
|
+
}
|
|
24797
25296
|
if (node && node.status === "offline") {
|
|
24798
25297
|
this.nodeRegistry.updateStatus(nodeId, status);
|
|
24799
25298
|
this.log.info("keepalive restored node", { nodeId, status });
|
|
@@ -24802,6 +25301,7 @@ var HeartbeatMonitor = class {
|
|
|
24802
25301
|
}
|
|
24803
25302
|
this.nodeRegistry.updateLoad(nodeId, load);
|
|
24804
25303
|
this.applyReportedDevTunnelState(nodeId, devtunnelEnabled, devtunnelEndpoint);
|
|
25304
|
+
this.nodeRegistry.updateDashboardOrigin(nodeId, dashboardOrigin);
|
|
24805
25305
|
this.nodeRegistry.updatePreviewOrigin(nodeId, previewOrigin);
|
|
24806
25306
|
if (workDirFolders) {
|
|
24807
25307
|
this.nodeRegistry.updateFolders(nodeId, workDirFolders);
|
|
@@ -24840,19 +25340,25 @@ var HeartbeatMonitor = class {
|
|
|
24840
25340
|
const self = this.nodeRegistry.getSelf();
|
|
24841
25341
|
const request = {
|
|
24842
25342
|
nodeId: self.id,
|
|
25343
|
+
name: self.name,
|
|
25344
|
+
endpoint: self.endpoint,
|
|
24843
25345
|
status: self.status,
|
|
24844
25346
|
load: 0,
|
|
25347
|
+
capabilities: self.capabilities,
|
|
25348
|
+
transportType: self.transportType,
|
|
25349
|
+
workDir: self.workDir,
|
|
24845
25350
|
devtunnelEnabled: self.devtunnelEndpoint !== void 0,
|
|
24846
25351
|
devtunnelEndpoint: self.devtunnelEndpoint,
|
|
25352
|
+
dashboardOrigin: self.dashboardOrigin,
|
|
24847
25353
|
previewOrigin: self.previewOrigin,
|
|
24848
25354
|
workDirFolders: self.workDir ? listWorkDirFolders(self.workDir) : void 0
|
|
24849
25355
|
};
|
|
24850
25356
|
try {
|
|
24851
|
-
const response = await fetch(`${leaderEndpoint}/api/worker/keepalive`, {
|
|
25357
|
+
const response = await fetch(`${leaderEndpoint}/api/worker/keepalive`, applyRequestAuthHeaders({
|
|
24852
25358
|
method: "POST",
|
|
24853
25359
|
headers: { "Content-Type": "application/json" },
|
|
24854
25360
|
body: JSON.stringify(request)
|
|
24855
|
-
});
|
|
25361
|
+
}));
|
|
24856
25362
|
if (response.ok) {
|
|
24857
25363
|
const result = await response.json();
|
|
24858
25364
|
this.log.debug("keepalive ok", { nodes: result.clusterState.nodes.length });
|
|
@@ -25022,11 +25528,11 @@ var HeartbeatMonitor = class {
|
|
|
25022
25528
|
}
|
|
25023
25529
|
}
|
|
25024
25530
|
try {
|
|
25025
|
-
const res = await fetch(`${leaderEndpoint}/api/worker/control-response`, {
|
|
25531
|
+
const res = await fetch(`${leaderEndpoint}/api/worker/control-response`, applyRequestAuthHeaders({
|
|
25026
25532
|
method: "POST",
|
|
25027
25533
|
headers: { "Content-Type": "application/json" },
|
|
25028
25534
|
body: JSON.stringify(response)
|
|
25029
|
-
});
|
|
25535
|
+
}));
|
|
25030
25536
|
if (!res.ok) {
|
|
25031
25537
|
this.log.warn("leader rejected control response", {
|
|
25032
25538
|
requestId: request.requestId,
|
|
@@ -25116,12 +25622,12 @@ var DataRouter = class {
|
|
|
25116
25622
|
const controller = new AbortController();
|
|
25117
25623
|
const timeoutId = setTimeout(() => controller.abort(), this.config.proxyTimeout);
|
|
25118
25624
|
try {
|
|
25119
|
-
const response = await fetch(targetUrl, {
|
|
25625
|
+
const response = await fetch(targetUrl, applyRequestAuthHeaders({
|
|
25120
25626
|
method,
|
|
25121
25627
|
headers: forwardHeaders,
|
|
25122
25628
|
body,
|
|
25123
25629
|
signal: controller.signal
|
|
25124
|
-
});
|
|
25630
|
+
}));
|
|
25125
25631
|
const responseHeaders = {};
|
|
25126
25632
|
response.headers.forEach((value, key) => {
|
|
25127
25633
|
responseHeaders[key] = value;
|
|
@@ -25315,11 +25821,11 @@ function forwardLeaderTaskPatch(log, nodeRegistry, taskId, data, options) {
|
|
|
25315
25821
|
log.warn(options.missingLeaderMessage, metadata);
|
|
25316
25822
|
return;
|
|
25317
25823
|
}
|
|
25318
|
-
fetch(`${leaderEndpoint}/api/tasks/${taskId}`, {
|
|
25824
|
+
fetch(`${leaderEndpoint}/api/tasks/${taskId}`, applyRequestAuthHeaders({
|
|
25319
25825
|
method: "PATCH",
|
|
25320
25826
|
headers: { "Content-Type": "application/json" },
|
|
25321
25827
|
body: JSON.stringify(buildLeaderTaskPatch(data))
|
|
25322
|
-
}).then((response) => {
|
|
25828
|
+
})).then((response) => {
|
|
25323
25829
|
if (!response.ok) {
|
|
25324
25830
|
log.warn(options.rejectedMessage, {
|
|
25325
25831
|
...metadata,
|
|
@@ -25366,11 +25872,11 @@ function forwardTaskOutputToLeader(log, nodeRegistry, taskId, event) {
|
|
|
25366
25872
|
});
|
|
25367
25873
|
return;
|
|
25368
25874
|
}
|
|
25369
|
-
fetch(`${leaderEndpoint}/api/worker/output`, {
|
|
25875
|
+
fetch(`${leaderEndpoint}/api/worker/output`, applyRequestAuthHeaders({
|
|
25370
25876
|
method: "POST",
|
|
25371
25877
|
headers: { "Content-Type": "application/json" },
|
|
25372
25878
|
body: JSON.stringify({ taskId, event })
|
|
25373
|
-
}).then((response) => {
|
|
25879
|
+
})).then((response) => {
|
|
25374
25880
|
if (!response.ok) {
|
|
25375
25881
|
log.warn("leader rejected forwarded output", {
|
|
25376
25882
|
taskId,
|
|
@@ -25438,7 +25944,7 @@ function registerLeaderForwarding(eventBus, nodeRegistry, log, taskId, agent) {
|
|
|
25438
25944
|
// ../../packages/core/src/engines/claude-code-engine.ts
|
|
25439
25945
|
var fs7 = __toESM(require("fs"), 1);
|
|
25440
25946
|
var path7 = __toESM(require("path"), 1);
|
|
25441
|
-
var
|
|
25947
|
+
var import_node_child_process2 = require("child_process");
|
|
25442
25948
|
function resolveClaudeInvocation() {
|
|
25443
25949
|
if (process.platform !== "win32") {
|
|
25444
25950
|
return { command: "claude", argsPrefix: [] };
|
|
@@ -25500,7 +26006,7 @@ var ClaudeCodeEngine = class extends ExecutionEngine {
|
|
|
25500
26006
|
this.ensureLogDir();
|
|
25501
26007
|
this.logger.info("Spawning claude CLI", { taskId: task.id, title: task.title, cwd });
|
|
25502
26008
|
const invocation = resolveClaudeInvocation();
|
|
25503
|
-
const proc = (0,
|
|
26009
|
+
const proc = (0, import_node_child_process2.spawn)(invocation.command, [...invocation.argsPrefix, ...args], {
|
|
25504
26010
|
cwd,
|
|
25505
26011
|
stdio: ["pipe", "pipe", "pipe"]
|
|
25506
26012
|
});
|
|
@@ -25610,7 +26116,7 @@ var ClaudeCodeEngine = class extends ExecutionEngine {
|
|
|
25610
26116
|
"stream-json"
|
|
25611
26117
|
];
|
|
25612
26118
|
const invocation = resolveClaudeInvocation();
|
|
25613
|
-
const proc = (0,
|
|
26119
|
+
const proc = (0, import_node_child_process2.spawn)(invocation.command, [...invocation.argsPrefix, ...args], {
|
|
25614
26120
|
cwd: session.cwd,
|
|
25615
26121
|
stdio: ["pipe", "pipe", "pipe"]
|
|
25616
26122
|
});
|
|
@@ -25745,7 +26251,7 @@ var ClaudeCodeEngine = class extends ExecutionEngine {
|
|
|
25745
26251
|
// ../../packages/core/src/engines/codex-engine.ts
|
|
25746
26252
|
var fs8 = __toESM(require("fs"), 1);
|
|
25747
26253
|
var path8 = __toESM(require("path"), 1);
|
|
25748
|
-
var
|
|
26254
|
+
var import_node_child_process3 = require("child_process");
|
|
25749
26255
|
function buildAssistantEvent(text, timestamp = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
25750
26256
|
return {
|
|
25751
26257
|
type: "assistant",
|
|
@@ -25804,7 +26310,7 @@ var CodexEngine = class extends ExecutionEngine {
|
|
|
25804
26310
|
const args = this.buildArgs(prompt, imagePaths, { model: config.model });
|
|
25805
26311
|
this.ensureLogDir();
|
|
25806
26312
|
this.logger.info("Spawning codex CLI", { taskId: task.id, title: task.title, cwd });
|
|
25807
|
-
const proc = (0,
|
|
26313
|
+
const proc = (0, import_node_child_process3.spawn)("codex", args, {
|
|
25808
26314
|
cwd,
|
|
25809
26315
|
stdio: ["ignore", "pipe", "pipe"]
|
|
25810
26316
|
});
|
|
@@ -25831,7 +26337,7 @@ var CodexEngine = class extends ExecutionEngine {
|
|
|
25831
26337
|
const { prompt, imagePaths } = this.prepareAssets(taskId, content);
|
|
25832
26338
|
const args = this.buildArgs(prompt, imagePaths, { model, sessionId: session.sessionId });
|
|
25833
26339
|
this.logger.info("Sending Codex follow-up message", { taskId, sessionId: session.sessionId });
|
|
25834
|
-
const proc = (0,
|
|
26340
|
+
const proc = (0, import_node_child_process3.spawn)("codex", args, {
|
|
25835
26341
|
cwd: session.cwd,
|
|
25836
26342
|
stdio: ["ignore", "pipe", "pipe"]
|
|
25837
26343
|
});
|
|
@@ -26191,16 +26697,17 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
26191
26697
|
id: this.selfInfo.id,
|
|
26192
26698
|
endpoint: this.selfInfo.endpoint,
|
|
26193
26699
|
name: this.config.node.name,
|
|
26194
|
-
capabilities: []
|
|
26700
|
+
capabilities: [],
|
|
26701
|
+
tasks: this.taskEngine.listTasks().tasks
|
|
26195
26702
|
};
|
|
26196
26703
|
if (this.selfInfo.devtunnelEndpoint) {
|
|
26197
26704
|
joinBody.devtunnelEndpoint = this.selfInfo.devtunnelEndpoint;
|
|
26198
26705
|
}
|
|
26199
|
-
const response = await fetch(`${seedUrl}/api/cluster/join`, {
|
|
26706
|
+
const response = await fetch(`${seedUrl}/api/cluster/join`, applyRequestAuthHeaders({
|
|
26200
26707
|
method: "POST",
|
|
26201
26708
|
headers: { "Content-Type": "application/json" },
|
|
26202
26709
|
body: JSON.stringify(joinBody)
|
|
26203
|
-
});
|
|
26710
|
+
}));
|
|
26204
26711
|
if (!response.ok) {
|
|
26205
26712
|
const body = await response.json?.().catch(() => null);
|
|
26206
26713
|
if (body?.error?.code === "NOT_LEADER") {
|
|
@@ -26212,13 +26719,36 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
26212
26719
|
throw new Error(`Failed to join cluster via ${seedUrl}: ${response.status}`);
|
|
26213
26720
|
}
|
|
26214
26721
|
const data = await response.json();
|
|
26215
|
-
|
|
26216
|
-
|
|
26217
|
-
|
|
26218
|
-
|
|
26219
|
-
|
|
26722
|
+
this.applyClusterState(data.nodes, data.leaderId, data.term);
|
|
26723
|
+
}
|
|
26724
|
+
async leaveCluster() {
|
|
26725
|
+
const leader = this.nodeRegistry.getLeader();
|
|
26726
|
+
const leaderEndpoint = this.nodeRegistry.getLeaderEndpoint();
|
|
26727
|
+
const self = this.nodeRegistry.getSelf();
|
|
26728
|
+
if (!leader || !leaderEndpoint || leader.id === self.id) {
|
|
26729
|
+
return;
|
|
26220
26730
|
}
|
|
26221
|
-
|
|
26731
|
+
try {
|
|
26732
|
+
await fetch(`${leaderEndpoint}/api/cluster/leave`, applyRequestAuthHeaders({
|
|
26733
|
+
method: "POST",
|
|
26734
|
+
headers: { "Content-Type": "application/json" },
|
|
26735
|
+
body: JSON.stringify({ nodeId: self.id })
|
|
26736
|
+
}));
|
|
26737
|
+
} catch {
|
|
26738
|
+
}
|
|
26739
|
+
const refreshedSelf = {
|
|
26740
|
+
...self,
|
|
26741
|
+
role: "follower",
|
|
26742
|
+
status: "online",
|
|
26743
|
+
lastHeartbeat: Date.now(),
|
|
26744
|
+
workDirFolders: listWorkDirFolders(this.getWorkDir())
|
|
26745
|
+
};
|
|
26746
|
+
this.selfInfo = refreshedSelf;
|
|
26747
|
+
this.nodeRegistry.setSelf(refreshedSelf);
|
|
26748
|
+
this.nodeRegistry.syncFromHeartbeat([refreshedSelf]);
|
|
26749
|
+
this.nodeRegistry.clearLeader();
|
|
26750
|
+
this.election.stepDown();
|
|
26751
|
+
await this.election.startElection();
|
|
26222
26752
|
}
|
|
26223
26753
|
async stop() {
|
|
26224
26754
|
if (!this.started) return;
|
|
@@ -26228,11 +26758,11 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
26228
26758
|
try {
|
|
26229
26759
|
const leaderEndpoint = this.nodeRegistry.getLeaderEndpoint();
|
|
26230
26760
|
if (leaderEndpoint) {
|
|
26231
|
-
await fetch(`${leaderEndpoint}/api/cluster/leave`, {
|
|
26761
|
+
await fetch(`${leaderEndpoint}/api/cluster/leave`, applyRequestAuthHeaders({
|
|
26232
26762
|
method: "POST",
|
|
26233
26763
|
headers: { "Content-Type": "application/json" },
|
|
26234
26764
|
body: JSON.stringify({ nodeId: this.selfInfo.id })
|
|
26235
|
-
});
|
|
26765
|
+
}));
|
|
26236
26766
|
}
|
|
26237
26767
|
} catch {
|
|
26238
26768
|
}
|
|
@@ -26313,11 +26843,11 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
26313
26843
|
const leaderEndpoint = this.nodeRegistry.getLeaderEndpoint();
|
|
26314
26844
|
if (leaderEndpoint && !this.nodeRegistry.isLeader()) {
|
|
26315
26845
|
try {
|
|
26316
|
-
await fetch(`${leaderEndpoint}/api/nodes/${this.selfInfo.id}`, {
|
|
26846
|
+
await fetch(`${leaderEndpoint}/api/nodes/${this.selfInfo.id}`, applyRequestAuthHeaders({
|
|
26317
26847
|
method: "PATCH",
|
|
26318
26848
|
headers: { "Content-Type": "application/json" },
|
|
26319
26849
|
body: JSON.stringify({ endpoint: newEndpoint })
|
|
26320
|
-
});
|
|
26850
|
+
}));
|
|
26321
26851
|
} catch {
|
|
26322
26852
|
}
|
|
26323
26853
|
}
|
|
@@ -26381,6 +26911,22 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
26381
26911
|
this.selfInfo.role = current.role;
|
|
26382
26912
|
this.selfInfo.status = current.status;
|
|
26383
26913
|
}
|
|
26914
|
+
applyClusterState(nodes, leaderId, term) {
|
|
26915
|
+
const remoteSelf = nodes.find((node) => node.id === this.selfInfo.id);
|
|
26916
|
+
const nextSelf = {
|
|
26917
|
+
...this.selfInfo,
|
|
26918
|
+
...remoteSelf ?? {},
|
|
26919
|
+
transportType: this.config.transport.type,
|
|
26920
|
+
workDir: this.selfInfo.workDir,
|
|
26921
|
+
workDirFolders: listWorkDirFolders(this.getWorkDir()),
|
|
26922
|
+
...this.selfInfo.devtunnelEndpoint ? { devtunnelEndpoint: this.selfInfo.devtunnelEndpoint } : {},
|
|
26923
|
+
...this.selfInfo.previewOrigin ? { previewOrigin: this.selfInfo.previewOrigin } : {}
|
|
26924
|
+
};
|
|
26925
|
+
this.selfInfo = nextSelf;
|
|
26926
|
+
this.nodeRegistry.setSelf(nextSelf);
|
|
26927
|
+
this.nodeRegistry.syncFromHeartbeat(nodes);
|
|
26928
|
+
this.election.handleLeaderAnnounce({ leaderId, term });
|
|
26929
|
+
}
|
|
26384
26930
|
cloneTransportConfig(config) {
|
|
26385
26931
|
return {
|
|
26386
26932
|
type: config.type,
|
|
@@ -30609,14 +31155,36 @@ var NodeInfoSchema = external_exports.object({
|
|
|
30609
31155
|
lastHeartbeat: external_exports.number(),
|
|
30610
31156
|
transportType: external_exports.string().optional(),
|
|
30611
31157
|
devtunnelEndpoint: external_exports.string().optional(),
|
|
31158
|
+
dashboardOrigin: external_exports.string().optional(),
|
|
30612
31159
|
previewOrigin: external_exports.string().optional()
|
|
30613
31160
|
});
|
|
31161
|
+
var JoinTaskSchema = external_exports.object({
|
|
31162
|
+
id: external_exports.string(),
|
|
31163
|
+
title: external_exports.string(),
|
|
31164
|
+
description: external_exports.string(),
|
|
31165
|
+
agent: external_exports.string(),
|
|
31166
|
+
project: external_exports.string().nullable(),
|
|
31167
|
+
effectiveProjectPath: external_exports.string().nullable(),
|
|
31168
|
+
payload: external_exports.record(external_exports.unknown()),
|
|
31169
|
+
status: external_exports.enum(["pending", "assigned", "running", "completed", "failed", "cancelled", "archived"]),
|
|
31170
|
+
priority: external_exports.enum(["low", "normal", "high", "critical"]),
|
|
31171
|
+
assignedTo: external_exports.string().nullable(),
|
|
31172
|
+
assignedNodeName: external_exports.string().nullable().optional(),
|
|
31173
|
+
createdBy: external_exports.string(),
|
|
31174
|
+
result: external_exports.record(external_exports.unknown()).nullable(),
|
|
31175
|
+
error: external_exports.string().nullable(),
|
|
31176
|
+
retryCount: external_exports.number(),
|
|
31177
|
+
maxRetries: external_exports.number(),
|
|
31178
|
+
createdAt: external_exports.number(),
|
|
31179
|
+
updatedAt: external_exports.number()
|
|
31180
|
+
});
|
|
30614
31181
|
var JoinClusterBody = external_exports.object({
|
|
30615
31182
|
id: external_exports.string().min(1),
|
|
30616
31183
|
endpoint: external_exports.string().url(),
|
|
30617
31184
|
name: external_exports.string().min(1),
|
|
30618
31185
|
capabilities: external_exports.array(external_exports.string()).default([]),
|
|
30619
|
-
devtunnelEndpoint: external_exports.string().url().optional()
|
|
31186
|
+
devtunnelEndpoint: external_exports.string().url().optional(),
|
|
31187
|
+
tasks: external_exports.array(JoinTaskSchema).default([])
|
|
30620
31188
|
});
|
|
30621
31189
|
var JoinClusterResponse = external_exports.object({
|
|
30622
31190
|
clusterId: external_exports.string(),
|
|
@@ -30640,6 +31208,10 @@ var ElectionBody = external_exports.object({
|
|
|
30640
31208
|
candidateId: external_exports.string(),
|
|
30641
31209
|
term: external_exports.number().int().min(1)
|
|
30642
31210
|
});
|
|
31211
|
+
var ConnectClusterBody = external_exports.object({
|
|
31212
|
+
leaderEndpoint: external_exports.string().url(),
|
|
31213
|
+
transport: external_exports.literal("devtunnel")
|
|
31214
|
+
});
|
|
30643
31215
|
|
|
30644
31216
|
// ../../packages/api/src/schemas/nodes.ts
|
|
30645
31217
|
var NodeInfoSchema2 = external_exports.object({
|
|
@@ -30653,6 +31225,7 @@ var NodeInfoSchema2 = external_exports.object({
|
|
|
30653
31225
|
lastHeartbeat: external_exports.number(),
|
|
30654
31226
|
transportType: external_exports.string().optional(),
|
|
30655
31227
|
devtunnelEndpoint: external_exports.string().optional(),
|
|
31228
|
+
dashboardOrigin: external_exports.string().optional(),
|
|
30656
31229
|
previewOrigin: external_exports.string().optional()
|
|
30657
31230
|
});
|
|
30658
31231
|
var NodeListQuery = external_exports.object({
|
|
@@ -30707,6 +31280,7 @@ var TaskListResponse = external_exports.object({
|
|
|
30707
31280
|
priority: external_exports.enum(["low", "normal", "high", "critical"]),
|
|
30708
31281
|
assignedTo: external_exports.string().nullable(),
|
|
30709
31282
|
assignedNodeName: external_exports.string().nullable().optional(),
|
|
31283
|
+
assignedNodeAvailable: external_exports.boolean().optional(),
|
|
30710
31284
|
createdBy: external_exports.string(),
|
|
30711
31285
|
result: external_exports.record(external_exports.unknown()).nullable(),
|
|
30712
31286
|
error: external_exports.string().nullable(),
|
|
@@ -30778,13 +31352,113 @@ var import_express7 = __toESM(require_express2(), 1);
|
|
|
30778
31352
|
|
|
30779
31353
|
// ../../packages/api/src/middleware/auth.ts
|
|
30780
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
|
+
}
|
|
30781
31423
|
function createAuthMiddleware(config) {
|
|
30782
31424
|
return (req, _res, next) => {
|
|
30783
|
-
|
|
31425
|
+
const log = getAuthLogger(req);
|
|
31426
|
+
if (SKIP_AUTH_PATHS.includes(req.path)) {
|
|
30784
31427
|
next();
|
|
30785
31428
|
return;
|
|
30786
31429
|
}
|
|
30787
|
-
if (
|
|
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) {
|
|
30788
31462
|
next();
|
|
30789
31463
|
return;
|
|
30790
31464
|
}
|
|
@@ -30885,13 +31559,32 @@ function createErrorMiddleware() {
|
|
|
30885
31559
|
|
|
30886
31560
|
// ../../packages/api/src/routes/cluster.ts
|
|
30887
31561
|
var import_express = __toESM(require_express2(), 1);
|
|
31562
|
+
var CONNECTIVITY_TIMEOUT_MS = 8e3;
|
|
31563
|
+
async function verifyHealth(endpoint) {
|
|
31564
|
+
const controller = new AbortController();
|
|
31565
|
+
const timer = setTimeout(() => controller.abort(), CONNECTIVITY_TIMEOUT_MS);
|
|
31566
|
+
try {
|
|
31567
|
+
const response = await fetch(`${endpoint}/api/system/health`, {
|
|
31568
|
+
signal: controller.signal
|
|
31569
|
+
});
|
|
31570
|
+
if (!response.ok) {
|
|
31571
|
+
throw new Error(`health check returned ${response.status}`);
|
|
31572
|
+
}
|
|
31573
|
+
} catch (err) {
|
|
31574
|
+
throw new Error(
|
|
31575
|
+
`Failed to verify connectivity for ${endpoint}: ${err instanceof Error ? err.message : String(err)}`
|
|
31576
|
+
);
|
|
31577
|
+
} finally {
|
|
31578
|
+
clearTimeout(timer);
|
|
31579
|
+
}
|
|
31580
|
+
}
|
|
30888
31581
|
function asyncHandler(fn) {
|
|
30889
31582
|
return (req, res, next) => fn(req, res, next).catch(next);
|
|
30890
31583
|
}
|
|
30891
31584
|
function createClusterRoutes() {
|
|
30892
31585
|
const router = (0, import_express.Router)();
|
|
30893
31586
|
router.post("/join", asyncHandler(async (req, res) => {
|
|
30894
|
-
const { nodeRegistry, election } = req.app.locals.deps;
|
|
31587
|
+
const { nodeRegistry, election, taskEngine } = req.app.locals.deps;
|
|
30895
31588
|
if (!election.isLeader()) {
|
|
30896
31589
|
const leaderEndpoint = nodeRegistry.getLeaderEndpoint();
|
|
30897
31590
|
res.status(421).json({
|
|
@@ -30922,6 +31615,7 @@ function createClusterRoutes() {
|
|
|
30922
31615
|
...body.devtunnelEndpoint && { devtunnelEndpoint: body.devtunnelEndpoint }
|
|
30923
31616
|
};
|
|
30924
31617
|
nodeRegistry.addNode(node);
|
|
31618
|
+
taskEngine.importTasks(body.tasks ?? []);
|
|
30925
31619
|
const clusterState = nodeRegistry.getClusterState();
|
|
30926
31620
|
res.status(201).json({
|
|
30927
31621
|
clusterId: clusterState.clusterId ?? nanoid(),
|
|
@@ -30930,13 +31624,50 @@ function createClusterRoutes() {
|
|
|
30930
31624
|
nodes: clusterState.nodes
|
|
30931
31625
|
});
|
|
30932
31626
|
}));
|
|
31627
|
+
router.post("/connect", asyncHandler(async (req, res) => {
|
|
31628
|
+
const {
|
|
31629
|
+
nodeRegistry,
|
|
31630
|
+
joinCurrentNodeToCluster
|
|
31631
|
+
} = req.app.locals.deps;
|
|
31632
|
+
const body = ConnectClusterBody.parse(req.body);
|
|
31633
|
+
if (!joinCurrentNodeToCluster) {
|
|
31634
|
+
throw new MeshyError("VALIDATION_ERROR", "Join flow is not available on this node", 501);
|
|
31635
|
+
}
|
|
31636
|
+
await verifyHealth(body.leaderEndpoint);
|
|
31637
|
+
await joinCurrentNodeToCluster(body.leaderEndpoint);
|
|
31638
|
+
const self = nodeRegistry.getSelf();
|
|
31639
|
+
const clusterState = nodeRegistry.getClusterState();
|
|
31640
|
+
res.json({
|
|
31641
|
+
ok: true,
|
|
31642
|
+
transport: body.transport,
|
|
31643
|
+
self,
|
|
31644
|
+
leaderId: clusterState.leaderId,
|
|
31645
|
+
term: clusterState.term,
|
|
31646
|
+
nodes: clusterState.nodes
|
|
31647
|
+
});
|
|
31648
|
+
}));
|
|
30933
31649
|
router.post("/leave", asyncHandler(async (req, res) => {
|
|
30934
|
-
const { nodeRegistry
|
|
31650
|
+
const { nodeRegistry } = req.app.locals.deps;
|
|
30935
31651
|
const { nodeId } = req.body;
|
|
30936
31652
|
nodeRegistry.removeNode(nodeId);
|
|
30937
|
-
eventBus.emit("node.left", { nodeId, reason: "left" });
|
|
30938
31653
|
res.json({ ok: true });
|
|
30939
31654
|
}));
|
|
31655
|
+
router.post("/disconnect", asyncHandler(async (req, res) => {
|
|
31656
|
+
const { leaveCurrentCluster, nodeRegistry } = req.app.locals.deps;
|
|
31657
|
+
if (!leaveCurrentCluster) {
|
|
31658
|
+
throw new MeshyError("VALIDATION_ERROR", "Leave flow is not available on this node", 501);
|
|
31659
|
+
}
|
|
31660
|
+
await leaveCurrentCluster();
|
|
31661
|
+
const self = nodeRegistry.getSelf();
|
|
31662
|
+
const clusterState = nodeRegistry.getClusterState();
|
|
31663
|
+
res.json({
|
|
31664
|
+
ok: true,
|
|
31665
|
+
self,
|
|
31666
|
+
leaderId: clusterState.leaderId,
|
|
31667
|
+
term: clusterState.term,
|
|
31668
|
+
nodes: clusterState.nodes
|
|
31669
|
+
});
|
|
31670
|
+
}));
|
|
30940
31671
|
router.get("/state", asyncHandler(async (req, res) => {
|
|
30941
31672
|
const { nodeRegistry, taskEngine } = req.app.locals.deps;
|
|
30942
31673
|
const clusterState = nodeRegistry.getClusterState();
|
|
@@ -31419,10 +32150,10 @@ function readFileContent(root, relativePath) {
|
|
|
31419
32150
|
}
|
|
31420
32151
|
|
|
31421
32152
|
// ../../packages/api/src/output/git-diff.ts
|
|
31422
|
-
var
|
|
32153
|
+
var import_node_child_process4 = require("child_process");
|
|
31423
32154
|
function git(args, cwd) {
|
|
31424
32155
|
try {
|
|
31425
|
-
return (0,
|
|
32156
|
+
return (0, import_node_child_process4.execFileSync)("git", ["-C", cwd, ...args], {
|
|
31426
32157
|
encoding: "utf-8",
|
|
31427
32158
|
timeout: 1e4,
|
|
31428
32159
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -31615,7 +32346,8 @@ async function executeWorkerControlRequest(deps, request) {
|
|
|
31615
32346
|
return jsonResponse(request.requestId, 200, {
|
|
31616
32347
|
ok: true,
|
|
31617
32348
|
enabled: true,
|
|
31618
|
-
devtunnelEndpoint
|
|
32349
|
+
devtunnelEndpoint,
|
|
32350
|
+
dashboardOrigin: deps.nodeRegistry.getSelf().dashboardOrigin
|
|
31619
32351
|
});
|
|
31620
32352
|
}
|
|
31621
32353
|
if (!deps.disableDevTunnel) {
|
|
@@ -31624,7 +32356,8 @@ async function executeWorkerControlRequest(deps, request) {
|
|
|
31624
32356
|
await deps.disableDevTunnel();
|
|
31625
32357
|
return jsonResponse(request.requestId, 200, {
|
|
31626
32358
|
ok: true,
|
|
31627
|
-
enabled: false
|
|
32359
|
+
enabled: false,
|
|
32360
|
+
dashboardOrigin: deps.nodeRegistry.getSelf().dashboardOrigin
|
|
31628
32361
|
});
|
|
31629
32362
|
}
|
|
31630
32363
|
case "task-cancel": {
|
|
@@ -31826,7 +32559,7 @@ function createNodeRoutes() {
|
|
|
31826
32559
|
res.json(node);
|
|
31827
32560
|
}));
|
|
31828
32561
|
router.delete("/:id", asyncHandler2(async (req, res) => {
|
|
31829
|
-
const { nodeRegistry,
|
|
32562
|
+
const { nodeRegistry, election } = req.app.locals.deps;
|
|
31830
32563
|
if (!election.isLeader()) {
|
|
31831
32564
|
throw new MeshyError("NOT_LEADER", "Only the leader node can delete nodes", 403);
|
|
31832
32565
|
}
|
|
@@ -31835,7 +32568,6 @@ function createNodeRoutes() {
|
|
|
31835
32568
|
throw new MeshyError("NODE_NOT_FOUND", `Node ${req.params.id} not found`, 404);
|
|
31836
32569
|
}
|
|
31837
32570
|
nodeRegistry.removeNode(req.params.id);
|
|
31838
|
-
eventBus.emit("node.left", { nodeId: req.params.id, reason: "deleted" });
|
|
31839
32571
|
res.json({ ok: true });
|
|
31840
32572
|
}));
|
|
31841
32573
|
router.post("/:id/devtunnel", asyncHandler2(async (req, res) => {
|
|
@@ -31859,10 +32591,19 @@ function createNodeRoutes() {
|
|
|
31859
32591
|
}
|
|
31860
32592
|
if (enabled) {
|
|
31861
32593
|
const devtunnelEndpoint = await enableDevTunnel();
|
|
31862
|
-
res.json({
|
|
32594
|
+
res.json({
|
|
32595
|
+
ok: true,
|
|
32596
|
+
enabled: true,
|
|
32597
|
+
devtunnelEndpoint,
|
|
32598
|
+
dashboardOrigin: nodeRegistry.getSelf().dashboardOrigin
|
|
32599
|
+
});
|
|
31863
32600
|
} else {
|
|
31864
32601
|
await disableDevTunnel();
|
|
31865
|
-
res.json({
|
|
32602
|
+
res.json({
|
|
32603
|
+
ok: true,
|
|
32604
|
+
enabled: false,
|
|
32605
|
+
dashboardOrigin: nodeRegistry.getSelf().dashboardOrigin
|
|
32606
|
+
});
|
|
31866
32607
|
}
|
|
31867
32608
|
} else {
|
|
31868
32609
|
const node = nodeRegistry.getNode(targetId);
|
|
@@ -31901,6 +32642,7 @@ function createNodeRoutes() {
|
|
|
31901
32642
|
if (result?.ok) {
|
|
31902
32643
|
if (nodeRegistry.getNode(targetId)) {
|
|
31903
32644
|
nodeRegistry.updateDevTunnelEndpoint(targetId, result.devtunnelEndpoint);
|
|
32645
|
+
nodeRegistry.updateDashboardOrigin(targetId, result.dashboardOrigin);
|
|
31904
32646
|
}
|
|
31905
32647
|
}
|
|
31906
32648
|
sendWorkerControlResponse(res, controlResponse);
|
|
@@ -31916,6 +32658,7 @@ function createNodeRoutes() {
|
|
|
31916
32658
|
const updatedNode = nodeRegistry.getNode(targetId);
|
|
31917
32659
|
if (updatedNode) {
|
|
31918
32660
|
nodeRegistry.updateDevTunnelEndpoint(targetId, result.devtunnelEndpoint);
|
|
32661
|
+
nodeRegistry.updateDashboardOrigin(targetId, result.dashboardOrigin);
|
|
31919
32662
|
}
|
|
31920
32663
|
res.json(result);
|
|
31921
32664
|
}
|
|
@@ -32042,17 +32785,15 @@ var ACTIVE_STATUSES = /* @__PURE__ */ new Set(["pending", "assigned", "running"]
|
|
|
32042
32785
|
function asyncHandler3(fn) {
|
|
32043
32786
|
return (req, res, next) => fn(req, res, next).catch(next);
|
|
32044
32787
|
}
|
|
32045
|
-
function
|
|
32046
|
-
if (
|
|
32788
|
+
function withAssignedNodeMetadata(task, nodeRegistry) {
|
|
32789
|
+
if (!task.assignedTo) {
|
|
32047
32790
|
return task;
|
|
32048
32791
|
}
|
|
32049
32792
|
const node = nodeRegistry.getNode(task.assignedTo);
|
|
32050
|
-
if (!node?.name) {
|
|
32051
|
-
return task;
|
|
32052
|
-
}
|
|
32053
32793
|
return {
|
|
32054
32794
|
...task,
|
|
32055
|
-
assignedNodeName: node
|
|
32795
|
+
assignedNodeName: task.assignedNodeName ?? node?.name ?? null,
|
|
32796
|
+
assignedNodeAvailable: node?.status !== "offline" && Boolean(node)
|
|
32056
32797
|
};
|
|
32057
32798
|
}
|
|
32058
32799
|
function createTaskRoutes() {
|
|
@@ -32071,10 +32812,10 @@ function createTaskRoutes() {
|
|
|
32071
32812
|
});
|
|
32072
32813
|
if (body.assignTo) {
|
|
32073
32814
|
const assigned = taskEngine.assignTask(task.id, body.assignTo);
|
|
32074
|
-
res.status(201).json(
|
|
32815
|
+
res.status(201).json(withAssignedNodeMetadata(assigned, nodeRegistry));
|
|
32075
32816
|
return;
|
|
32076
32817
|
}
|
|
32077
|
-
res.status(201).json(
|
|
32818
|
+
res.status(201).json(withAssignedNodeMetadata(task, nodeRegistry));
|
|
32078
32819
|
}));
|
|
32079
32820
|
router.get("/", asyncHandler3(async (req, res) => {
|
|
32080
32821
|
const { taskEngine, nodeRegistry } = req.app.locals.deps;
|
|
@@ -32087,7 +32828,7 @@ function createTaskRoutes() {
|
|
|
32087
32828
|
if (query.offset) filter.offset = query.offset;
|
|
32088
32829
|
const result = taskEngine.listTasks(filter);
|
|
32089
32830
|
res.json({
|
|
32090
|
-
tasks: result.tasks.map((task) =>
|
|
32831
|
+
tasks: result.tasks.map((task) => withAssignedNodeMetadata(task, nodeRegistry)),
|
|
32091
32832
|
total: result.total
|
|
32092
32833
|
});
|
|
32093
32834
|
}));
|
|
@@ -32128,7 +32869,7 @@ function createTaskRoutes() {
|
|
|
32128
32869
|
if (!task) {
|
|
32129
32870
|
throw new MeshyError("TASK_NOT_FOUND", `Task ${req.params.id} not found`, 404);
|
|
32130
32871
|
}
|
|
32131
|
-
res.json(
|
|
32872
|
+
res.json(withAssignedNodeMetadata(task, nodeRegistry));
|
|
32132
32873
|
}));
|
|
32133
32874
|
router.patch("/:id", asyncHandler3(async (req, res) => {
|
|
32134
32875
|
const { taskEngine, nodeRegistry, logger: rootLogger } = req.app.locals.deps;
|
|
@@ -32144,7 +32885,7 @@ function createTaskRoutes() {
|
|
|
32144
32885
|
currentStatus: existing.status,
|
|
32145
32886
|
incomingStatus: updates.status
|
|
32146
32887
|
});
|
|
32147
|
-
res.json(
|
|
32888
|
+
res.json(withAssignedNodeMetadata(existing, nodeRegistry));
|
|
32148
32889
|
return;
|
|
32149
32890
|
}
|
|
32150
32891
|
if (updates.status === "archived" && !ARCHIVABLE_STATUSES.has(existing.status)) {
|
|
@@ -32160,14 +32901,14 @@ function createTaskRoutes() {
|
|
|
32160
32901
|
currentStatus: existing.status,
|
|
32161
32902
|
incomingStatus: updates.status
|
|
32162
32903
|
});
|
|
32163
|
-
res.json(
|
|
32904
|
+
res.json(withAssignedNodeMetadata(existing, nodeRegistry));
|
|
32164
32905
|
return;
|
|
32165
32906
|
}
|
|
32166
32907
|
const task = taskEngine.updateTask(req.params.id, updates);
|
|
32167
32908
|
if (!task) {
|
|
32168
32909
|
throw new MeshyError("TASK_NOT_FOUND", `Task ${req.params.id} not found`, 404);
|
|
32169
32910
|
}
|
|
32170
|
-
res.json(
|
|
32911
|
+
res.json(withAssignedNodeMetadata(task, nodeRegistry));
|
|
32171
32912
|
}));
|
|
32172
32913
|
router.delete("/:id", asyncHandler3(async (req, res) => {
|
|
32173
32914
|
const { taskEngine } = req.app.locals.deps;
|
|
@@ -32218,12 +32959,12 @@ function createTaskRoutes() {
|
|
|
32218
32959
|
const { taskEngine, nodeRegistry } = req.app.locals.deps;
|
|
32219
32960
|
const body = AssignTaskBody.parse(req.body);
|
|
32220
32961
|
const task = taskEngine.assignTask(req.params.id, body.nodeId);
|
|
32221
|
-
res.json(
|
|
32962
|
+
res.json(withAssignedNodeMetadata(task, nodeRegistry));
|
|
32222
32963
|
}));
|
|
32223
32964
|
router.post("/:id/retry", asyncHandler3(async (req, res) => {
|
|
32224
32965
|
const { taskEngine, nodeRegistry } = req.app.locals.deps;
|
|
32225
32966
|
const task = taskEngine.retryTask(req.params.id);
|
|
32226
|
-
res.json(
|
|
32967
|
+
res.json(withAssignedNodeMetadata(task, nodeRegistry));
|
|
32227
32968
|
}));
|
|
32228
32969
|
router.get("/:id/logs", asyncHandler3(async (req, res) => {
|
|
32229
32970
|
const { engineRegistry, taskEngine, nodeRegistry, logger: rootLogger } = req.app.locals.deps;
|
|
@@ -32308,26 +33049,18 @@ function createTaskRoutes() {
|
|
|
32308
33049
|
}
|
|
32309
33050
|
if (task.assignedTo && task.assignedTo !== nodeRegistry.getSelf()?.id) {
|
|
32310
33051
|
const node = nodeRegistry.getNode(task.assignedTo);
|
|
32311
|
-
const selfId = nodeRegistry.getSelf()?.id ?? null;
|
|
32312
33052
|
if (!node || node.status === "offline") {
|
|
32313
|
-
log.warn("assigned worker unavailable
|
|
33053
|
+
log.warn("assigned worker unavailable for follow-up", {
|
|
32314
33054
|
taskId: task.id,
|
|
32315
|
-
assignedTo: task.assignedTo,
|
|
32316
|
-
nodeFound: Boolean(node),
|
|
32317
|
-
nodeStatus: node?.status,
|
|
32318
|
-
reassignedTo: selfId
|
|
32319
|
-
});
|
|
32320
|
-
startLocalTaskFollowUp({
|
|
32321
|
-
taskEngine,
|
|
32322
|
-
engineRegistry,
|
|
32323
|
-
logger: log
|
|
32324
|
-
}, task, body.content, selfId, {
|
|
32325
33055
|
assignedTo: task.assignedTo,
|
|
32326
33056
|
nodeFound: Boolean(node),
|
|
32327
33057
|
nodeStatus: node?.status
|
|
32328
33058
|
});
|
|
32329
|
-
|
|
32330
|
-
|
|
33059
|
+
throw new MeshyError(
|
|
33060
|
+
"NODE_OFFLINE",
|
|
33061
|
+
`Task ${task.id} is unavailable because ${task.assignedNodeName ?? task.assignedTo} is no longer reachable`,
|
|
33062
|
+
409
|
|
33063
|
+
);
|
|
32331
33064
|
}
|
|
32332
33065
|
taskEngine.updateTask(task.id, { status: "running" });
|
|
32333
33066
|
let workerEndpoint = node.endpoint;
|
|
@@ -32858,13 +33591,19 @@ function createSystemRoutes() {
|
|
|
32858
33591
|
res.json({ status: "ok", timestamp: Date.now() });
|
|
32859
33592
|
}));
|
|
32860
33593
|
router.get("/info", asyncHandler5(async (req, res) => {
|
|
32861
|
-
const { nodeRegistry, getTransportType } = req.app.locals.deps;
|
|
33594
|
+
const { nodeRegistry, getTransportType, config, dashboardOrigin } = req.app.locals.deps;
|
|
32862
33595
|
const self = nodeRegistry.getSelf();
|
|
32863
33596
|
res.json({
|
|
32864
33597
|
...self,
|
|
32865
33598
|
version: "0.1.0",
|
|
32866
33599
|
uptime: process.uptime(),
|
|
32867
|
-
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
|
+
}
|
|
32868
33607
|
});
|
|
32869
33608
|
}));
|
|
32870
33609
|
router.post("/transport", asyncHandler5(async (req, res) => {
|
|
@@ -32895,10 +33634,19 @@ function createSystemRoutes() {
|
|
|
32895
33634
|
assertCanChangeNodeDevTunnel(taskEngine, nodeRegistry.getSelf().id);
|
|
32896
33635
|
if (enabled) {
|
|
32897
33636
|
const devtunnelEndpoint = await enableDevTunnel();
|
|
32898
|
-
res.json({
|
|
33637
|
+
res.json({
|
|
33638
|
+
ok: true,
|
|
33639
|
+
enabled: true,
|
|
33640
|
+
devtunnelEndpoint,
|
|
33641
|
+
dashboardOrigin: nodeRegistry.getSelf().dashboardOrigin
|
|
33642
|
+
});
|
|
32899
33643
|
} else {
|
|
32900
33644
|
await disableDevTunnel();
|
|
32901
|
-
res.json({
|
|
33645
|
+
res.json({
|
|
33646
|
+
ok: true,
|
|
33647
|
+
enabled: false,
|
|
33648
|
+
dashboardOrigin: nodeRegistry.getSelf().dashboardOrigin
|
|
33649
|
+
});
|
|
32902
33650
|
}
|
|
32903
33651
|
}));
|
|
32904
33652
|
router.get("/metrics", asyncHandler5(async (req, res) => {
|
|
@@ -33028,13 +33776,39 @@ function createServer2(deps) {
|
|
|
33028
33776
|
if (typeof deps.heartbeat.setControlRequestHandler === "function") {
|
|
33029
33777
|
deps.heartbeat.setControlRequestHandler((request) => executeWorkerControlRequest(deps, request));
|
|
33030
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);
|
|
33031
33795
|
const runtimeBaseDir = resolveRuntimeBaseDir();
|
|
33032
33796
|
const staticDir = resolveStaticDir(runtimeBaseDir);
|
|
33033
33797
|
if (staticDir) {
|
|
33034
|
-
|
|
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
|
+
});
|
|
33035
33810
|
}
|
|
33036
33811
|
app.use(import_express7.default.json({ limit: JSON_BODY_LIMIT }));
|
|
33037
|
-
const authConfig = { apiKey: deps.config.apiKey };
|
|
33038
33812
|
app.use(createAuthMiddleware(authConfig));
|
|
33039
33813
|
app.use(createRoutingMiddleware(deps.dataRouter));
|
|
33040
33814
|
const largeBodyParser = import_express7.default.json({ limit: JSON_BODY_LIMIT_LARGE });
|
|
@@ -33047,7 +33821,15 @@ function createServer2(deps) {
|
|
|
33047
33821
|
if (staticDir) {
|
|
33048
33822
|
const indexPath = path15.join(staticDir, "index.html");
|
|
33049
33823
|
if (fs15.existsSync(indexPath)) {
|
|
33050
|
-
app.get("*", (
|
|
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
|
+
}
|
|
33051
33833
|
res.sendFile(indexPath);
|
|
33052
33834
|
});
|
|
33053
33835
|
}
|
|
@@ -33122,10 +33904,10 @@ var DirectTransport = class {
|
|
|
33122
33904
|
};
|
|
33123
33905
|
|
|
33124
33906
|
// ../../packages/transport/src/devtunnel.ts
|
|
33125
|
-
var
|
|
33907
|
+
var import_node_child_process5 = require("child_process");
|
|
33126
33908
|
function isInstalled(cmd) {
|
|
33127
33909
|
try {
|
|
33128
|
-
(0,
|
|
33910
|
+
(0, import_node_child_process5.execSync)(process.platform === "win32" ? `where ${cmd}` : `command -v ${cmd}`, { stdio: "pipe" });
|
|
33129
33911
|
return true;
|
|
33130
33912
|
} catch {
|
|
33131
33913
|
return false;
|
|
@@ -33148,14 +33930,14 @@ var DevTunnelTransport = class {
|
|
|
33148
33930
|
);
|
|
33149
33931
|
}
|
|
33150
33932
|
try {
|
|
33151
|
-
(0,
|
|
33933
|
+
(0, import_node_child_process5.execSync)("devtunnel user show", { stdio: "pipe" });
|
|
33152
33934
|
} catch {
|
|
33153
33935
|
throw new Error(
|
|
33154
33936
|
"Not logged in to devtunnel. Run: devtunnel user login"
|
|
33155
33937
|
);
|
|
33156
33938
|
}
|
|
33157
33939
|
const hostArgs = this.buildHostArgs(localPort);
|
|
33158
|
-
const child = (0,
|
|
33940
|
+
const child = (0, import_node_child_process5.spawn)("devtunnel", hostArgs, {
|
|
33159
33941
|
stdio: ["pipe", "pipe", "pipe"]
|
|
33160
33942
|
});
|
|
33161
33943
|
this.process = child;
|
|
@@ -33260,7 +34042,7 @@ ${lines.join("")}`
|
|
|
33260
34042
|
return void 0;
|
|
33261
34043
|
}
|
|
33262
34044
|
try {
|
|
33263
|
-
(0,
|
|
34045
|
+
(0, import_node_child_process5.execFileSync)("devtunnel", ["show", tunnelId], { stdio: "pipe" });
|
|
33264
34046
|
return tunnelId;
|
|
33265
34047
|
} catch {
|
|
33266
34048
|
const createArgs = ["create", tunnelId];
|
|
@@ -33268,7 +34050,7 @@ ${lines.join("")}`
|
|
|
33268
34050
|
createArgs.push("-a");
|
|
33269
34051
|
}
|
|
33270
34052
|
try {
|
|
33271
|
-
(0,
|
|
34053
|
+
(0, import_node_child_process5.execFileSync)("devtunnel", createArgs, { stdio: "pipe" });
|
|
33272
34054
|
return tunnelId;
|
|
33273
34055
|
} catch (err) {
|
|
33274
34056
|
throw new Error(
|
|
@@ -33283,7 +34065,7 @@ ${lines.join("")}`
|
|
|
33283
34065
|
return;
|
|
33284
34066
|
}
|
|
33285
34067
|
try {
|
|
33286
|
-
(0,
|
|
34068
|
+
(0, import_node_child_process5.execFileSync)(
|
|
33287
34069
|
"devtunnel",
|
|
33288
34070
|
["port", "create", tunnelId, "-p", String(localPort), "--protocol", "http"],
|
|
33289
34071
|
{ stdio: "pipe" }
|
|
@@ -33299,7 +34081,7 @@ ${lines.join("")}`
|
|
|
33299
34081
|
}
|
|
33300
34082
|
listTunnelPorts(tunnelId) {
|
|
33301
34083
|
try {
|
|
33302
|
-
const output = (0,
|
|
34084
|
+
const output = (0, import_node_child_process5.execFileSync)("devtunnel", ["port", "list", tunnelId, "-j"], { stdio: "pipe" });
|
|
33303
34085
|
const parsed = JSON.parse(output.toString());
|
|
33304
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 : [];
|
|
33305
34087
|
return items.map((item) => getPortNumber(item)).filter((value) => value !== void 0);
|
|
@@ -33311,7 +34093,7 @@ ${lines.join("")}`
|
|
|
33311
34093
|
}
|
|
33312
34094
|
hasTunnelPort(tunnelId, localPort) {
|
|
33313
34095
|
try {
|
|
33314
|
-
(0,
|
|
34096
|
+
(0, import_node_child_process5.execFileSync)(
|
|
33315
34097
|
"devtunnel",
|
|
33316
34098
|
["port", "show", tunnelId, "-p", String(localPort), "-j"],
|
|
33317
34099
|
{ stdio: "pipe" }
|
|
@@ -33365,7 +34147,9 @@ function createTransport(config) {
|
|
|
33365
34147
|
}
|
|
33366
34148
|
}
|
|
33367
34149
|
|
|
33368
|
-
// src/
|
|
34150
|
+
// src/startup.ts
|
|
34151
|
+
var fs16 = __toESM(require("fs"), 1);
|
|
34152
|
+
var readline = __toESM(require("readline/promises"), 1);
|
|
33369
34153
|
function getDefaultNodeName() {
|
|
33370
34154
|
return getDeviceNodeName();
|
|
33371
34155
|
}
|
|
@@ -33381,9 +34165,10 @@ function createDefaultConfig(storagePath = resolveDefaultStoragePath(), nodeName
|
|
|
33381
34165
|
};
|
|
33382
34166
|
}
|
|
33383
34167
|
var DEFAULT_CONFIG3 = createDefaultConfig();
|
|
33384
|
-
function createRuntimeDefaultConfig(fileConfig) {
|
|
34168
|
+
function createRuntimeDefaultConfig(fileConfig, options = {}) {
|
|
33385
34169
|
const storagePath = fileConfig.storage?.path ?? resolveDefaultStoragePath();
|
|
33386
|
-
|
|
34170
|
+
const nodeName = options.ignorePersistedName ? getDeviceNodeName() : resolveDefaultNodeName(storagePath);
|
|
34171
|
+
return createDefaultConfig(storagePath, nodeName);
|
|
33387
34172
|
}
|
|
33388
34173
|
function parseArgs(argv) {
|
|
33389
34174
|
const result = {};
|
|
@@ -33421,6 +34206,12 @@ function parseArgs(argv) {
|
|
|
33421
34206
|
result.config = argv[++i];
|
|
33422
34207
|
}
|
|
33423
34208
|
break;
|
|
34209
|
+
case "--reset":
|
|
34210
|
+
result.reset = true;
|
|
34211
|
+
break;
|
|
34212
|
+
case "--disable-auth":
|
|
34213
|
+
result.disableAuth = true;
|
|
34214
|
+
break;
|
|
33424
34215
|
}
|
|
33425
34216
|
}
|
|
33426
34217
|
return result;
|
|
@@ -33531,6 +34322,67 @@ async function promptStartOptions(args, fileConfig, defaults, prompt) {
|
|
|
33531
34322
|
await closePrompt?.();
|
|
33532
34323
|
}
|
|
33533
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
|
|
33534
34386
|
function formatBanner(info) {
|
|
33535
34387
|
const lines = [
|
|
33536
34388
|
`Node: ${info.name}`,
|
|
@@ -33538,6 +34390,9 @@ function formatBanner(info) {
|
|
|
33538
34390
|
`Endpoint: ${info.endpoint}`,
|
|
33539
34391
|
`Dashboard: http://localhost:${info.port}`
|
|
33540
34392
|
];
|
|
34393
|
+
if (info.dashboardOrigin) {
|
|
34394
|
+
lines.push(`Dashboard Tunnel: ${info.dashboardOrigin}`);
|
|
34395
|
+
}
|
|
33541
34396
|
const maxLen = Math.max(...lines.map((l) => l.length));
|
|
33542
34397
|
const innerWidth = maxLen + 4;
|
|
33543
34398
|
const top = ` \u256D${"\u2500".repeat(innerWidth)}\u256E`;
|
|
@@ -33559,16 +34414,48 @@ async function main() {
|
|
|
33559
34414
|
const args = parseArgs(process.argv.slice(2));
|
|
33560
34415
|
const configPath = args.config ?? "./config.json";
|
|
33561
34416
|
const fileConfig = loadConfigFile(configPath);
|
|
33562
|
-
const
|
|
33563
|
-
const
|
|
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;
|
|
33564
34427
|
const config = mergeConfig(defaults, fileConfig, resolvedArgs);
|
|
33565
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
|
+
}
|
|
33566
34438
|
const logDir = nodePath.join(config.storage.path, "logs");
|
|
33567
34439
|
const logger = createLogger({
|
|
33568
34440
|
component: "node",
|
|
33569
34441
|
logDir,
|
|
33570
34442
|
console: true
|
|
33571
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
|
+
}
|
|
33572
34459
|
const meshyNode = new MeshyNode(config, {
|
|
33573
34460
|
logger,
|
|
33574
34461
|
transportFactory: createTransport
|
|
@@ -33578,9 +34465,24 @@ async function main() {
|
|
|
33578
34465
|
const previewServer = new PreviewServer(previewSessionManager);
|
|
33579
34466
|
const previewPort = config.node.port + 1;
|
|
33580
34467
|
const actualPreviewPort = await previewServer.start(previewPort);
|
|
34468
|
+
let dashboardTransport = null;
|
|
34469
|
+
let dashboardOrigin;
|
|
33581
34470
|
let previewTransport = null;
|
|
33582
34471
|
let previewOrigin;
|
|
33583
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
|
+
}
|
|
33584
34486
|
function createPreviewTransportConfig() {
|
|
33585
34487
|
return {
|
|
33586
34488
|
type: "devtunnel",
|
|
@@ -33594,11 +34496,92 @@ async function main() {
|
|
|
33594
34496
|
}
|
|
33595
34497
|
};
|
|
33596
34498
|
}
|
|
34499
|
+
function setAdvertisedDashboardOrigin(origin) {
|
|
34500
|
+
dashboardOrigin = origin;
|
|
34501
|
+
deps.dashboardOrigin = origin;
|
|
34502
|
+
meshyNode.getNodeRegistry().updateDashboardOrigin(meshyNode.getNodeRegistry().getSelf().id, origin);
|
|
34503
|
+
}
|
|
33597
34504
|
function setAdvertisedPreviewOrigin(origin) {
|
|
33598
34505
|
previewOrigin = origin;
|
|
33599
34506
|
deps.previewOrigin = origin;
|
|
33600
34507
|
meshyNode.getNodeRegistry().updatePreviewOrigin(meshyNode.getNodeRegistry().getSelf().id, origin);
|
|
33601
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
|
+
}
|
|
33602
34585
|
async function restartPreviewTransport(transportConfig) {
|
|
33603
34586
|
const previousTransport = previewTransport;
|
|
33604
34587
|
const previousOrigin = previewOrigin;
|
|
@@ -33634,16 +34617,42 @@ async function main() {
|
|
|
33634
34617
|
eventBus: meshyNode.getEventBus(),
|
|
33635
34618
|
engineRegistry: meshyNode.getEngineRegistry(),
|
|
33636
34619
|
logger: meshyNode.getLogger(),
|
|
33637
|
-
config: {
|
|
34620
|
+
config: {
|
|
34621
|
+
apiKey: config.cluster.apiKey,
|
|
34622
|
+
authMetadata,
|
|
34623
|
+
validateBearerToken: authMetadata.enabled ? (header) => nodeAuth.validateAuthorizationHeader(header) : void 0
|
|
34624
|
+
},
|
|
33638
34625
|
workDir: meshyNode.getWorkDir(),
|
|
33639
34626
|
persistNodeNamePreference: (name) => persistDefaultNodeName(config.storage.path, name),
|
|
34627
|
+
joinCurrentNodeToCluster: async (leaderEndpoint) => {
|
|
34628
|
+
await meshyNode.joinCluster(leaderEndpoint);
|
|
34629
|
+
},
|
|
34630
|
+
leaveCurrentCluster: async () => {
|
|
34631
|
+
await meshyNode.leaveCluster();
|
|
34632
|
+
},
|
|
33640
34633
|
switchTransport: async (type) => {
|
|
33641
|
-
|
|
34634
|
+
const endpoint = await meshyNode.switchTransport(type);
|
|
34635
|
+
persistNodeStartupTransport(config.storage.path, type);
|
|
34636
|
+
await syncDashboardTransport(`switchTransport:${type}`);
|
|
34637
|
+
return endpoint;
|
|
33642
34638
|
},
|
|
33643
34639
|
getTransportType: () => meshyNode.getTransportType(),
|
|
33644
|
-
enableDevTunnel: async () =>
|
|
33645
|
-
|
|
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
|
+
},
|
|
33646
34654
|
isDevTunnelEnabled: () => meshyNode.isDevTunnelEnabled(),
|
|
34655
|
+
dashboardOrigin,
|
|
33647
34656
|
ensurePreviewOrigin: async () => {
|
|
33648
34657
|
if (previewTransport && !await previewTransport.isHealthy()) {
|
|
33649
34658
|
await previewTransport.stop().catch(() => void 0);
|
|
@@ -33659,7 +34668,16 @@ async function main() {
|
|
|
33659
34668
|
};
|
|
33660
34669
|
deps.previewSessionManager = previewSessionManager;
|
|
33661
34670
|
deps.previewPort = actualPreviewPort;
|
|
34671
|
+
deps.dashboardOrigin = dashboardOrigin;
|
|
33662
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");
|
|
33663
34681
|
const previewHealthTimer = setInterval(() => {
|
|
33664
34682
|
void (async () => {
|
|
33665
34683
|
if (!previewTransport) return;
|
|
@@ -33673,6 +34691,19 @@ async function main() {
|
|
|
33673
34691
|
});
|
|
33674
34692
|
})();
|
|
33675
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);
|
|
33676
34707
|
const app = createServer2(deps);
|
|
33677
34708
|
const server = app.listen(config.node.port, () => {
|
|
33678
34709
|
const self = meshyNode.getNodeRegistry().getSelf();
|
|
@@ -33683,7 +34714,8 @@ async function main() {
|
|
|
33683
34714
|
role,
|
|
33684
34715
|
term,
|
|
33685
34716
|
endpoint: self.endpoint,
|
|
33686
|
-
port: config.node.port
|
|
34717
|
+
port: config.node.port,
|
|
34718
|
+
dashboardOrigin
|
|
33687
34719
|
});
|
|
33688
34720
|
console.log("");
|
|
33689
34721
|
console.log(banner);
|
|
@@ -33695,7 +34727,11 @@ async function main() {
|
|
|
33695
34727
|
shuttingDown = true;
|
|
33696
34728
|
console.log("\nShutting down...");
|
|
33697
34729
|
try {
|
|
34730
|
+
clearInterval(dashboardHealthTimer);
|
|
33698
34731
|
clearInterval(previewHealthTimer);
|
|
34732
|
+
if (dashboardTransport) {
|
|
34733
|
+
await dashboardTransport.stop();
|
|
34734
|
+
}
|
|
33699
34735
|
if (previewTransport) {
|
|
33700
34736
|
await previewTransport.stop();
|
|
33701
34737
|
}
|
|
@@ -33724,9 +34760,11 @@ if (isDirectRun) {
|
|
|
33724
34760
|
DEFAULT_CONFIG,
|
|
33725
34761
|
DEFAULT_NODE_NAME,
|
|
33726
34762
|
DEFAULT_NODE_PORT,
|
|
34763
|
+
applyStartMetadata,
|
|
33727
34764
|
createDefaultConfig,
|
|
33728
34765
|
createRuntimeDefaultConfig,
|
|
33729
34766
|
formatBanner,
|
|
34767
|
+
formatLoadedStartMetadata,
|
|
33730
34768
|
getDefaultNodeName,
|
|
33731
34769
|
isDirectRunPath,
|
|
33732
34770
|
loadConfigFile,
|
|
@@ -33734,6 +34772,8 @@ if (isDirectRun) {
|
|
|
33734
34772
|
mergeConfig,
|
|
33735
34773
|
parseArgs,
|
|
33736
34774
|
promptStartOptions,
|
|
34775
|
+
resolveRuntimeAuthMetadata,
|
|
34776
|
+
shouldCollectStartOptions,
|
|
33737
34777
|
shouldPromptForStartOptions
|
|
33738
34778
|
});
|
|
33739
34779
|
/*! Bundled license information:
|