meshy-node 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dashboard/assets/DashboardPage-vJKpJw48.js +200 -0
- package/dashboard/assets/{DiffTab-B22VET7i.js → DiffTab-RBHpHnzj.js} +4 -4
- package/dashboard/assets/{FilesTab-DkODTD1c.js → FilesTab-tWHzvDgF.js} +1 -1
- package/dashboard/assets/{PreviewTab-CtdlW-8Z.js → PreviewTab-DUfl_tjX.js} +1 -1
- package/dashboard/assets/{folder-D6MCA6XV.js → folder-DLwF1-Yt.js} +1 -1
- package/dashboard/assets/{index-Br1FoGY0.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 +887 -68
- package/package.json +1 -1
- package/dashboard/assets/DashboardPage-Cq9h6J6k.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
|
}
|
|
@@ -23746,6 +24125,24 @@ var NodeRegistry = class {
|
|
|
23746
24125
|
}
|
|
23747
24126
|
}
|
|
23748
24127
|
}
|
|
24128
|
+
updateDashboardOrigin(id, dashboardOrigin) {
|
|
24129
|
+
const node = this.nodes.get(id);
|
|
24130
|
+
if (node) {
|
|
24131
|
+
if (dashboardOrigin) {
|
|
24132
|
+
node.dashboardOrigin = dashboardOrigin;
|
|
24133
|
+
} else {
|
|
24134
|
+
delete node.dashboardOrigin;
|
|
24135
|
+
}
|
|
24136
|
+
this.store.upsertNode(node);
|
|
24137
|
+
}
|
|
24138
|
+
if (this.selfNode && this.selfNode.id === id) {
|
|
24139
|
+
if (dashboardOrigin) {
|
|
24140
|
+
this.selfNode.dashboardOrigin = dashboardOrigin;
|
|
24141
|
+
} else {
|
|
24142
|
+
delete this.selfNode.dashboardOrigin;
|
|
24143
|
+
}
|
|
24144
|
+
}
|
|
24145
|
+
}
|
|
23749
24146
|
updatePreviewOrigin(id, previewOrigin) {
|
|
23750
24147
|
const node = this.nodes.get(id);
|
|
23751
24148
|
if (node) {
|
|
@@ -24000,11 +24397,11 @@ var LeaderElection = class {
|
|
|
24000
24397
|
const announcePromises = onlineNodes.map(async (node) => {
|
|
24001
24398
|
try {
|
|
24002
24399
|
const endpoint = getNodePublicEndpoint(node);
|
|
24003
|
-
await fetch(`${endpoint}/api/worker/announce`, {
|
|
24400
|
+
await fetch(`${endpoint}/api/worker/announce`, applyRequestAuthHeaders({
|
|
24004
24401
|
method: "POST",
|
|
24005
24402
|
headers: { "Content-Type": "application/json" },
|
|
24006
24403
|
body: JSON.stringify({ leaderId, term })
|
|
24007
|
-
});
|
|
24404
|
+
}));
|
|
24008
24405
|
} catch {
|
|
24009
24406
|
}
|
|
24010
24407
|
});
|
|
@@ -24782,6 +25179,7 @@ var HeartbeatMonitor = class {
|
|
|
24782
25179
|
this.nodeRegistry.updateHeartbeat(node.id, Date.now());
|
|
24783
25180
|
this.nodeRegistry.updateLoad(node.id, result.load);
|
|
24784
25181
|
this.applyReportedDevTunnelState(node.id, result.devtunnelEnabled, result.devtunnelEndpoint);
|
|
25182
|
+
this.nodeRegistry.updateDashboardOrigin(node.id, result.dashboardOrigin);
|
|
24785
25183
|
this.nodeRegistry.updatePreviewOrigin(node.id, result.previewOrigin);
|
|
24786
25184
|
if (result.workDirFolders) {
|
|
24787
25185
|
this.nodeRegistry.updateFolders(node.id, result.workDirFolders);
|
|
@@ -24825,6 +25223,7 @@ var HeartbeatMonitor = class {
|
|
|
24825
25223
|
load: 0,
|
|
24826
25224
|
devtunnelEnabled: self.devtunnelEndpoint !== void 0,
|
|
24827
25225
|
devtunnelEndpoint: self.devtunnelEndpoint,
|
|
25226
|
+
dashboardOrigin: self.dashboardOrigin,
|
|
24828
25227
|
previewOrigin: self.previewOrigin,
|
|
24829
25228
|
workDirFolders: self.workDir ? listWorkDirFolders(self.workDir) : void 0
|
|
24830
25229
|
};
|
|
@@ -24842,6 +25241,7 @@ var HeartbeatMonitor = class {
|
|
|
24842
25241
|
workDir,
|
|
24843
25242
|
devtunnelEnabled,
|
|
24844
25243
|
devtunnelEndpoint,
|
|
25244
|
+
dashboardOrigin,
|
|
24845
25245
|
previewOrigin,
|
|
24846
25246
|
workDirFolders
|
|
24847
25247
|
} = req;
|
|
@@ -24867,6 +25267,7 @@ var HeartbeatMonitor = class {
|
|
|
24867
25267
|
...transportType ? { transportType } : {},
|
|
24868
25268
|
...workDir ? { workDir } : {},
|
|
24869
25269
|
...devtunnelEnabled && devtunnelEndpoint ? { devtunnelEndpoint } : {},
|
|
25270
|
+
...dashboardOrigin ? { dashboardOrigin } : {},
|
|
24870
25271
|
...previewOrigin ? { previewOrigin } : {},
|
|
24871
25272
|
...workDirFolders ? { workDirFolders } : {}
|
|
24872
25273
|
});
|
|
@@ -24900,6 +25301,7 @@ var HeartbeatMonitor = class {
|
|
|
24900
25301
|
}
|
|
24901
25302
|
this.nodeRegistry.updateLoad(nodeId, load);
|
|
24902
25303
|
this.applyReportedDevTunnelState(nodeId, devtunnelEnabled, devtunnelEndpoint);
|
|
25304
|
+
this.nodeRegistry.updateDashboardOrigin(nodeId, dashboardOrigin);
|
|
24903
25305
|
this.nodeRegistry.updatePreviewOrigin(nodeId, previewOrigin);
|
|
24904
25306
|
if (workDirFolders) {
|
|
24905
25307
|
this.nodeRegistry.updateFolders(nodeId, workDirFolders);
|
|
@@ -24947,15 +25349,16 @@ var HeartbeatMonitor = class {
|
|
|
24947
25349
|
workDir: self.workDir,
|
|
24948
25350
|
devtunnelEnabled: self.devtunnelEndpoint !== void 0,
|
|
24949
25351
|
devtunnelEndpoint: self.devtunnelEndpoint,
|
|
25352
|
+
dashboardOrigin: self.dashboardOrigin,
|
|
24950
25353
|
previewOrigin: self.previewOrigin,
|
|
24951
25354
|
workDirFolders: self.workDir ? listWorkDirFolders(self.workDir) : void 0
|
|
24952
25355
|
};
|
|
24953
25356
|
try {
|
|
24954
|
-
const response = await fetch(`${leaderEndpoint}/api/worker/keepalive`, {
|
|
25357
|
+
const response = await fetch(`${leaderEndpoint}/api/worker/keepalive`, applyRequestAuthHeaders({
|
|
24955
25358
|
method: "POST",
|
|
24956
25359
|
headers: { "Content-Type": "application/json" },
|
|
24957
25360
|
body: JSON.stringify(request)
|
|
24958
|
-
});
|
|
25361
|
+
}));
|
|
24959
25362
|
if (response.ok) {
|
|
24960
25363
|
const result = await response.json();
|
|
24961
25364
|
this.log.debug("keepalive ok", { nodes: result.clusterState.nodes.length });
|
|
@@ -25125,11 +25528,11 @@ var HeartbeatMonitor = class {
|
|
|
25125
25528
|
}
|
|
25126
25529
|
}
|
|
25127
25530
|
try {
|
|
25128
|
-
const res = await fetch(`${leaderEndpoint}/api/worker/control-response`, {
|
|
25531
|
+
const res = await fetch(`${leaderEndpoint}/api/worker/control-response`, applyRequestAuthHeaders({
|
|
25129
25532
|
method: "POST",
|
|
25130
25533
|
headers: { "Content-Type": "application/json" },
|
|
25131
25534
|
body: JSON.stringify(response)
|
|
25132
|
-
});
|
|
25535
|
+
}));
|
|
25133
25536
|
if (!res.ok) {
|
|
25134
25537
|
this.log.warn("leader rejected control response", {
|
|
25135
25538
|
requestId: request.requestId,
|
|
@@ -25219,12 +25622,12 @@ var DataRouter = class {
|
|
|
25219
25622
|
const controller = new AbortController();
|
|
25220
25623
|
const timeoutId = setTimeout(() => controller.abort(), this.config.proxyTimeout);
|
|
25221
25624
|
try {
|
|
25222
|
-
const response = await fetch(targetUrl, {
|
|
25625
|
+
const response = await fetch(targetUrl, applyRequestAuthHeaders({
|
|
25223
25626
|
method,
|
|
25224
25627
|
headers: forwardHeaders,
|
|
25225
25628
|
body,
|
|
25226
25629
|
signal: controller.signal
|
|
25227
|
-
});
|
|
25630
|
+
}));
|
|
25228
25631
|
const responseHeaders = {};
|
|
25229
25632
|
response.headers.forEach((value, key) => {
|
|
25230
25633
|
responseHeaders[key] = value;
|
|
@@ -25418,11 +25821,11 @@ function forwardLeaderTaskPatch(log, nodeRegistry, taskId, data, options) {
|
|
|
25418
25821
|
log.warn(options.missingLeaderMessage, metadata);
|
|
25419
25822
|
return;
|
|
25420
25823
|
}
|
|
25421
|
-
fetch(`${leaderEndpoint}/api/tasks/${taskId}`, {
|
|
25824
|
+
fetch(`${leaderEndpoint}/api/tasks/${taskId}`, applyRequestAuthHeaders({
|
|
25422
25825
|
method: "PATCH",
|
|
25423
25826
|
headers: { "Content-Type": "application/json" },
|
|
25424
25827
|
body: JSON.stringify(buildLeaderTaskPatch(data))
|
|
25425
|
-
}).then((response) => {
|
|
25828
|
+
})).then((response) => {
|
|
25426
25829
|
if (!response.ok) {
|
|
25427
25830
|
log.warn(options.rejectedMessage, {
|
|
25428
25831
|
...metadata,
|
|
@@ -25469,11 +25872,11 @@ function forwardTaskOutputToLeader(log, nodeRegistry, taskId, event) {
|
|
|
25469
25872
|
});
|
|
25470
25873
|
return;
|
|
25471
25874
|
}
|
|
25472
|
-
fetch(`${leaderEndpoint}/api/worker/output`, {
|
|
25875
|
+
fetch(`${leaderEndpoint}/api/worker/output`, applyRequestAuthHeaders({
|
|
25473
25876
|
method: "POST",
|
|
25474
25877
|
headers: { "Content-Type": "application/json" },
|
|
25475
25878
|
body: JSON.stringify({ taskId, event })
|
|
25476
|
-
}).then((response) => {
|
|
25879
|
+
})).then((response) => {
|
|
25477
25880
|
if (!response.ok) {
|
|
25478
25881
|
log.warn("leader rejected forwarded output", {
|
|
25479
25882
|
taskId,
|
|
@@ -25541,7 +25944,7 @@ function registerLeaderForwarding(eventBus, nodeRegistry, log, taskId, agent) {
|
|
|
25541
25944
|
// ../../packages/core/src/engines/claude-code-engine.ts
|
|
25542
25945
|
var fs7 = __toESM(require("fs"), 1);
|
|
25543
25946
|
var path7 = __toESM(require("path"), 1);
|
|
25544
|
-
var
|
|
25947
|
+
var import_node_child_process2 = require("child_process");
|
|
25545
25948
|
function resolveClaudeInvocation() {
|
|
25546
25949
|
if (process.platform !== "win32") {
|
|
25547
25950
|
return { command: "claude", argsPrefix: [] };
|
|
@@ -25603,7 +26006,7 @@ var ClaudeCodeEngine = class extends ExecutionEngine {
|
|
|
25603
26006
|
this.ensureLogDir();
|
|
25604
26007
|
this.logger.info("Spawning claude CLI", { taskId: task.id, title: task.title, cwd });
|
|
25605
26008
|
const invocation = resolveClaudeInvocation();
|
|
25606
|
-
const proc = (0,
|
|
26009
|
+
const proc = (0, import_node_child_process2.spawn)(invocation.command, [...invocation.argsPrefix, ...args], {
|
|
25607
26010
|
cwd,
|
|
25608
26011
|
stdio: ["pipe", "pipe", "pipe"]
|
|
25609
26012
|
});
|
|
@@ -25713,7 +26116,7 @@ var ClaudeCodeEngine = class extends ExecutionEngine {
|
|
|
25713
26116
|
"stream-json"
|
|
25714
26117
|
];
|
|
25715
26118
|
const invocation = resolveClaudeInvocation();
|
|
25716
|
-
const proc = (0,
|
|
26119
|
+
const proc = (0, import_node_child_process2.spawn)(invocation.command, [...invocation.argsPrefix, ...args], {
|
|
25717
26120
|
cwd: session.cwd,
|
|
25718
26121
|
stdio: ["pipe", "pipe", "pipe"]
|
|
25719
26122
|
});
|
|
@@ -25848,7 +26251,7 @@ var ClaudeCodeEngine = class extends ExecutionEngine {
|
|
|
25848
26251
|
// ../../packages/core/src/engines/codex-engine.ts
|
|
25849
26252
|
var fs8 = __toESM(require("fs"), 1);
|
|
25850
26253
|
var path8 = __toESM(require("path"), 1);
|
|
25851
|
-
var
|
|
26254
|
+
var import_node_child_process3 = require("child_process");
|
|
25852
26255
|
function buildAssistantEvent(text, timestamp = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
25853
26256
|
return {
|
|
25854
26257
|
type: "assistant",
|
|
@@ -25907,7 +26310,7 @@ var CodexEngine = class extends ExecutionEngine {
|
|
|
25907
26310
|
const args = this.buildArgs(prompt, imagePaths, { model: config.model });
|
|
25908
26311
|
this.ensureLogDir();
|
|
25909
26312
|
this.logger.info("Spawning codex CLI", { taskId: task.id, title: task.title, cwd });
|
|
25910
|
-
const proc = (0,
|
|
26313
|
+
const proc = (0, import_node_child_process3.spawn)("codex", args, {
|
|
25911
26314
|
cwd,
|
|
25912
26315
|
stdio: ["ignore", "pipe", "pipe"]
|
|
25913
26316
|
});
|
|
@@ -25934,7 +26337,7 @@ var CodexEngine = class extends ExecutionEngine {
|
|
|
25934
26337
|
const { prompt, imagePaths } = this.prepareAssets(taskId, content);
|
|
25935
26338
|
const args = this.buildArgs(prompt, imagePaths, { model, sessionId: session.sessionId });
|
|
25936
26339
|
this.logger.info("Sending Codex follow-up message", { taskId, sessionId: session.sessionId });
|
|
25937
|
-
const proc = (0,
|
|
26340
|
+
const proc = (0, import_node_child_process3.spawn)("codex", args, {
|
|
25938
26341
|
cwd: session.cwd,
|
|
25939
26342
|
stdio: ["ignore", "pipe", "pipe"]
|
|
25940
26343
|
});
|
|
@@ -26300,11 +26703,11 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
26300
26703
|
if (this.selfInfo.devtunnelEndpoint) {
|
|
26301
26704
|
joinBody.devtunnelEndpoint = this.selfInfo.devtunnelEndpoint;
|
|
26302
26705
|
}
|
|
26303
|
-
const response = await fetch(`${seedUrl}/api/cluster/join`, {
|
|
26706
|
+
const response = await fetch(`${seedUrl}/api/cluster/join`, applyRequestAuthHeaders({
|
|
26304
26707
|
method: "POST",
|
|
26305
26708
|
headers: { "Content-Type": "application/json" },
|
|
26306
26709
|
body: JSON.stringify(joinBody)
|
|
26307
|
-
});
|
|
26710
|
+
}));
|
|
26308
26711
|
if (!response.ok) {
|
|
26309
26712
|
const body = await response.json?.().catch(() => null);
|
|
26310
26713
|
if (body?.error?.code === "NOT_LEADER") {
|
|
@@ -26326,11 +26729,11 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
26326
26729
|
return;
|
|
26327
26730
|
}
|
|
26328
26731
|
try {
|
|
26329
|
-
await fetch(`${leaderEndpoint}/api/cluster/leave`, {
|
|
26732
|
+
await fetch(`${leaderEndpoint}/api/cluster/leave`, applyRequestAuthHeaders({
|
|
26330
26733
|
method: "POST",
|
|
26331
26734
|
headers: { "Content-Type": "application/json" },
|
|
26332
26735
|
body: JSON.stringify({ nodeId: self.id })
|
|
26333
|
-
});
|
|
26736
|
+
}));
|
|
26334
26737
|
} catch {
|
|
26335
26738
|
}
|
|
26336
26739
|
const refreshedSelf = {
|
|
@@ -26355,11 +26758,11 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
26355
26758
|
try {
|
|
26356
26759
|
const leaderEndpoint = this.nodeRegistry.getLeaderEndpoint();
|
|
26357
26760
|
if (leaderEndpoint) {
|
|
26358
|
-
await fetch(`${leaderEndpoint}/api/cluster/leave`, {
|
|
26761
|
+
await fetch(`${leaderEndpoint}/api/cluster/leave`, applyRequestAuthHeaders({
|
|
26359
26762
|
method: "POST",
|
|
26360
26763
|
headers: { "Content-Type": "application/json" },
|
|
26361
26764
|
body: JSON.stringify({ nodeId: this.selfInfo.id })
|
|
26362
|
-
});
|
|
26765
|
+
}));
|
|
26363
26766
|
}
|
|
26364
26767
|
} catch {
|
|
26365
26768
|
}
|
|
@@ -26440,11 +26843,11 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
26440
26843
|
const leaderEndpoint = this.nodeRegistry.getLeaderEndpoint();
|
|
26441
26844
|
if (leaderEndpoint && !this.nodeRegistry.isLeader()) {
|
|
26442
26845
|
try {
|
|
26443
|
-
await fetch(`${leaderEndpoint}/api/nodes/${this.selfInfo.id}`, {
|
|
26846
|
+
await fetch(`${leaderEndpoint}/api/nodes/${this.selfInfo.id}`, applyRequestAuthHeaders({
|
|
26444
26847
|
method: "PATCH",
|
|
26445
26848
|
headers: { "Content-Type": "application/json" },
|
|
26446
26849
|
body: JSON.stringify({ endpoint: newEndpoint })
|
|
26447
|
-
});
|
|
26850
|
+
}));
|
|
26448
26851
|
} catch {
|
|
26449
26852
|
}
|
|
26450
26853
|
}
|
|
@@ -30752,6 +31155,7 @@ var NodeInfoSchema = external_exports.object({
|
|
|
30752
31155
|
lastHeartbeat: external_exports.number(),
|
|
30753
31156
|
transportType: external_exports.string().optional(),
|
|
30754
31157
|
devtunnelEndpoint: external_exports.string().optional(),
|
|
31158
|
+
dashboardOrigin: external_exports.string().optional(),
|
|
30755
31159
|
previewOrigin: external_exports.string().optional()
|
|
30756
31160
|
});
|
|
30757
31161
|
var JoinTaskSchema = external_exports.object({
|
|
@@ -30821,6 +31225,7 @@ var NodeInfoSchema2 = external_exports.object({
|
|
|
30821
31225
|
lastHeartbeat: external_exports.number(),
|
|
30822
31226
|
transportType: external_exports.string().optional(),
|
|
30823
31227
|
devtunnelEndpoint: external_exports.string().optional(),
|
|
31228
|
+
dashboardOrigin: external_exports.string().optional(),
|
|
30824
31229
|
previewOrigin: external_exports.string().optional()
|
|
30825
31230
|
});
|
|
30826
31231
|
var NodeListQuery = external_exports.object({
|
|
@@ -30947,13 +31352,113 @@ var import_express7 = __toESM(require_express2(), 1);
|
|
|
30947
31352
|
|
|
30948
31353
|
// ../../packages/api/src/middleware/auth.ts
|
|
30949
31354
|
var SKIP_AUTH_PATHS = ["/api/system/health"];
|
|
31355
|
+
var TRUSTED_LOCAL_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]", "::1"]);
|
|
31356
|
+
function normalizeHost(value) {
|
|
31357
|
+
if (!value) return void 0;
|
|
31358
|
+
const trimmed = value.trim().toLowerCase();
|
|
31359
|
+
if (!trimmed) return void 0;
|
|
31360
|
+
return trimmed.replace(/:\d+$/, "");
|
|
31361
|
+
}
|
|
31362
|
+
function collectHosts(candidates) {
|
|
31363
|
+
const unique = /* @__PURE__ */ new Set();
|
|
31364
|
+
for (const candidate of candidates) {
|
|
31365
|
+
if (!candidate) continue;
|
|
31366
|
+
for (const item of candidate.split(",")) {
|
|
31367
|
+
const normalized = normalizeHost(item);
|
|
31368
|
+
if (normalized) {
|
|
31369
|
+
unique.add(normalized);
|
|
31370
|
+
}
|
|
31371
|
+
}
|
|
31372
|
+
}
|
|
31373
|
+
return [...unique];
|
|
31374
|
+
}
|
|
31375
|
+
function getForwardedHosts(req) {
|
|
31376
|
+
const forwardedHosts = collectHosts([
|
|
31377
|
+
typeof req.headers["x-forwarded-host"] === "string" ? req.headers["x-forwarded-host"] : void 0
|
|
31378
|
+
]);
|
|
31379
|
+
if (forwardedHosts.length > 0) {
|
|
31380
|
+
return forwardedHosts;
|
|
31381
|
+
}
|
|
31382
|
+
const forwardedHeader = typeof req.headers.forwarded === "string" ? req.headers.forwarded : void 0;
|
|
31383
|
+
if (!forwardedHeader) {
|
|
31384
|
+
return [];
|
|
31385
|
+
}
|
|
31386
|
+
const forwardedMatches = [...forwardedHeader.matchAll(/host=([^;,\s]+)/gi)];
|
|
31387
|
+
return collectHosts(forwardedMatches.map((match) => match[1]?.replace(/^"|"$/g, "")));
|
|
31388
|
+
}
|
|
31389
|
+
function getDirectHosts(req) {
|
|
31390
|
+
return collectHosts([
|
|
31391
|
+
req.hostname,
|
|
31392
|
+
typeof req.headers.host === "string" ? req.headers.host : void 0
|
|
31393
|
+
]);
|
|
31394
|
+
}
|
|
31395
|
+
function getRequestHosts(req) {
|
|
31396
|
+
const forwardedHosts = getForwardedHosts(req);
|
|
31397
|
+
if (forwardedHosts.length > 0) {
|
|
31398
|
+
return forwardedHosts;
|
|
31399
|
+
}
|
|
31400
|
+
return getDirectHosts(req);
|
|
31401
|
+
}
|
|
31402
|
+
function isTrustedDashboardRequest(req, config) {
|
|
31403
|
+
const trustedHosts = new Set((config.getTrustedHosts?.() ?? []).map((host) => normalizeHost(host)).filter(Boolean));
|
|
31404
|
+
for (const host of getRequestHosts(req)) {
|
|
31405
|
+
if (TRUSTED_LOCAL_HOSTS.has(host) || trustedHosts.has(host)) {
|
|
31406
|
+
return true;
|
|
31407
|
+
}
|
|
31408
|
+
}
|
|
31409
|
+
return false;
|
|
31410
|
+
}
|
|
31411
|
+
function getAuthLogger(req) {
|
|
31412
|
+
const logger = req.app?.locals?.deps?.logger;
|
|
31413
|
+
if (logger && typeof logger.child === "function") {
|
|
31414
|
+
return logger.child("api/auth");
|
|
31415
|
+
}
|
|
31416
|
+
return {
|
|
31417
|
+
debug() {
|
|
31418
|
+
},
|
|
31419
|
+
warn() {
|
|
31420
|
+
}
|
|
31421
|
+
};
|
|
31422
|
+
}
|
|
30950
31423
|
function createAuthMiddleware(config) {
|
|
30951
31424
|
return (req, _res, next) => {
|
|
30952
|
-
|
|
31425
|
+
const log = getAuthLogger(req);
|
|
31426
|
+
if (SKIP_AUTH_PATHS.includes(req.path)) {
|
|
30953
31427
|
next();
|
|
30954
31428
|
return;
|
|
30955
31429
|
}
|
|
30956
|
-
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) {
|
|
30957
31462
|
next();
|
|
30958
31463
|
return;
|
|
30959
31464
|
}
|
|
@@ -31645,10 +32150,10 @@ function readFileContent(root, relativePath) {
|
|
|
31645
32150
|
}
|
|
31646
32151
|
|
|
31647
32152
|
// ../../packages/api/src/output/git-diff.ts
|
|
31648
|
-
var
|
|
32153
|
+
var import_node_child_process4 = require("child_process");
|
|
31649
32154
|
function git(args, cwd) {
|
|
31650
32155
|
try {
|
|
31651
|
-
return (0,
|
|
32156
|
+
return (0, import_node_child_process4.execFileSync)("git", ["-C", cwd, ...args], {
|
|
31652
32157
|
encoding: "utf-8",
|
|
31653
32158
|
timeout: 1e4,
|
|
31654
32159
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -31841,7 +32346,8 @@ async function executeWorkerControlRequest(deps, request) {
|
|
|
31841
32346
|
return jsonResponse(request.requestId, 200, {
|
|
31842
32347
|
ok: true,
|
|
31843
32348
|
enabled: true,
|
|
31844
|
-
devtunnelEndpoint
|
|
32349
|
+
devtunnelEndpoint,
|
|
32350
|
+
dashboardOrigin: deps.nodeRegistry.getSelf().dashboardOrigin
|
|
31845
32351
|
});
|
|
31846
32352
|
}
|
|
31847
32353
|
if (!deps.disableDevTunnel) {
|
|
@@ -31850,7 +32356,8 @@ async function executeWorkerControlRequest(deps, request) {
|
|
|
31850
32356
|
await deps.disableDevTunnel();
|
|
31851
32357
|
return jsonResponse(request.requestId, 200, {
|
|
31852
32358
|
ok: true,
|
|
31853
|
-
enabled: false
|
|
32359
|
+
enabled: false,
|
|
32360
|
+
dashboardOrigin: deps.nodeRegistry.getSelf().dashboardOrigin
|
|
31854
32361
|
});
|
|
31855
32362
|
}
|
|
31856
32363
|
case "task-cancel": {
|
|
@@ -32084,10 +32591,19 @@ function createNodeRoutes() {
|
|
|
32084
32591
|
}
|
|
32085
32592
|
if (enabled) {
|
|
32086
32593
|
const devtunnelEndpoint = await enableDevTunnel();
|
|
32087
|
-
res.json({
|
|
32594
|
+
res.json({
|
|
32595
|
+
ok: true,
|
|
32596
|
+
enabled: true,
|
|
32597
|
+
devtunnelEndpoint,
|
|
32598
|
+
dashboardOrigin: nodeRegistry.getSelf().dashboardOrigin
|
|
32599
|
+
});
|
|
32088
32600
|
} else {
|
|
32089
32601
|
await disableDevTunnel();
|
|
32090
|
-
res.json({
|
|
32602
|
+
res.json({
|
|
32603
|
+
ok: true,
|
|
32604
|
+
enabled: false,
|
|
32605
|
+
dashboardOrigin: nodeRegistry.getSelf().dashboardOrigin
|
|
32606
|
+
});
|
|
32091
32607
|
}
|
|
32092
32608
|
} else {
|
|
32093
32609
|
const node = nodeRegistry.getNode(targetId);
|
|
@@ -32126,6 +32642,7 @@ function createNodeRoutes() {
|
|
|
32126
32642
|
if (result?.ok) {
|
|
32127
32643
|
if (nodeRegistry.getNode(targetId)) {
|
|
32128
32644
|
nodeRegistry.updateDevTunnelEndpoint(targetId, result.devtunnelEndpoint);
|
|
32645
|
+
nodeRegistry.updateDashboardOrigin(targetId, result.dashboardOrigin);
|
|
32129
32646
|
}
|
|
32130
32647
|
}
|
|
32131
32648
|
sendWorkerControlResponse(res, controlResponse);
|
|
@@ -32141,6 +32658,7 @@ function createNodeRoutes() {
|
|
|
32141
32658
|
const updatedNode = nodeRegistry.getNode(targetId);
|
|
32142
32659
|
if (updatedNode) {
|
|
32143
32660
|
nodeRegistry.updateDevTunnelEndpoint(targetId, result.devtunnelEndpoint);
|
|
32661
|
+
nodeRegistry.updateDashboardOrigin(targetId, result.dashboardOrigin);
|
|
32144
32662
|
}
|
|
32145
32663
|
res.json(result);
|
|
32146
32664
|
}
|
|
@@ -33073,13 +33591,19 @@ function createSystemRoutes() {
|
|
|
33073
33591
|
res.json({ status: "ok", timestamp: Date.now() });
|
|
33074
33592
|
}));
|
|
33075
33593
|
router.get("/info", asyncHandler5(async (req, res) => {
|
|
33076
|
-
const { nodeRegistry, getTransportType } = req.app.locals.deps;
|
|
33594
|
+
const { nodeRegistry, getTransportType, config, dashboardOrigin } = req.app.locals.deps;
|
|
33077
33595
|
const self = nodeRegistry.getSelf();
|
|
33078
33596
|
res.json({
|
|
33079
33597
|
...self,
|
|
33080
33598
|
version: "0.1.0",
|
|
33081
33599
|
uptime: process.uptime(),
|
|
33082
|
-
transportType: getTransportType?.() ?? "direct"
|
|
33600
|
+
transportType: getTransportType?.() ?? "direct",
|
|
33601
|
+
dashboardOrigin: dashboardOrigin ?? self.dashboardOrigin,
|
|
33602
|
+
auth: config.authMetadata ?? {
|
|
33603
|
+
enabled: false,
|
|
33604
|
+
allowSameTenant: false,
|
|
33605
|
+
allowedUsers: []
|
|
33606
|
+
}
|
|
33083
33607
|
});
|
|
33084
33608
|
}));
|
|
33085
33609
|
router.post("/transport", asyncHandler5(async (req, res) => {
|
|
@@ -33110,10 +33634,19 @@ function createSystemRoutes() {
|
|
|
33110
33634
|
assertCanChangeNodeDevTunnel(taskEngine, nodeRegistry.getSelf().id);
|
|
33111
33635
|
if (enabled) {
|
|
33112
33636
|
const devtunnelEndpoint = await enableDevTunnel();
|
|
33113
|
-
res.json({
|
|
33637
|
+
res.json({
|
|
33638
|
+
ok: true,
|
|
33639
|
+
enabled: true,
|
|
33640
|
+
devtunnelEndpoint,
|
|
33641
|
+
dashboardOrigin: nodeRegistry.getSelf().dashboardOrigin
|
|
33642
|
+
});
|
|
33114
33643
|
} else {
|
|
33115
33644
|
await disableDevTunnel();
|
|
33116
|
-
res.json({
|
|
33645
|
+
res.json({
|
|
33646
|
+
ok: true,
|
|
33647
|
+
enabled: false,
|
|
33648
|
+
dashboardOrigin: nodeRegistry.getSelf().dashboardOrigin
|
|
33649
|
+
});
|
|
33117
33650
|
}
|
|
33118
33651
|
}));
|
|
33119
33652
|
router.get("/metrics", asyncHandler5(async (req, res) => {
|
|
@@ -33243,13 +33776,39 @@ function createServer2(deps) {
|
|
|
33243
33776
|
if (typeof deps.heartbeat.setControlRequestHandler === "function") {
|
|
33244
33777
|
deps.heartbeat.setControlRequestHandler((request) => executeWorkerControlRequest(deps, request));
|
|
33245
33778
|
}
|
|
33779
|
+
const authConfig = {
|
|
33780
|
+
apiKey: deps.config.apiKey,
|
|
33781
|
+
validateBearerToken: deps.config.validateBearerToken,
|
|
33782
|
+
getTrustedHosts: () => {
|
|
33783
|
+
const trustedHosts = [];
|
|
33784
|
+
if (deps.dashboardOrigin) {
|
|
33785
|
+
try {
|
|
33786
|
+
trustedHosts.push(new URL(deps.dashboardOrigin).host);
|
|
33787
|
+
} catch {
|
|
33788
|
+
}
|
|
33789
|
+
}
|
|
33790
|
+
return trustedHosts;
|
|
33791
|
+
}
|
|
33792
|
+
};
|
|
33793
|
+
const isApiRequest = (req) => req.path === "/api" || req.path.startsWith("/api/");
|
|
33794
|
+
const canServeDashboard = (req) => !deps.config.validateBearerToken || isTrustedDashboardRequest(req, authConfig);
|
|
33246
33795
|
const runtimeBaseDir = resolveRuntimeBaseDir();
|
|
33247
33796
|
const staticDir = resolveStaticDir(runtimeBaseDir);
|
|
33248
33797
|
if (staticDir) {
|
|
33249
|
-
|
|
33798
|
+
const staticMiddleware = import_express7.default.static(staticDir);
|
|
33799
|
+
app.use((req, res, next) => {
|
|
33800
|
+
if (isApiRequest(req)) {
|
|
33801
|
+
next();
|
|
33802
|
+
return;
|
|
33803
|
+
}
|
|
33804
|
+
if (!canServeDashboard(req)) {
|
|
33805
|
+
res.status(404).type("text/plain").send("Not Found");
|
|
33806
|
+
return;
|
|
33807
|
+
}
|
|
33808
|
+
staticMiddleware(req, res, next);
|
|
33809
|
+
});
|
|
33250
33810
|
}
|
|
33251
33811
|
app.use(import_express7.default.json({ limit: JSON_BODY_LIMIT }));
|
|
33252
|
-
const authConfig = { apiKey: deps.config.apiKey };
|
|
33253
33812
|
app.use(createAuthMiddleware(authConfig));
|
|
33254
33813
|
app.use(createRoutingMiddleware(deps.dataRouter));
|
|
33255
33814
|
const largeBodyParser = import_express7.default.json({ limit: JSON_BODY_LIMIT_LARGE });
|
|
@@ -33262,7 +33821,15 @@ function createServer2(deps) {
|
|
|
33262
33821
|
if (staticDir) {
|
|
33263
33822
|
const indexPath = path15.join(staticDir, "index.html");
|
|
33264
33823
|
if (fs15.existsSync(indexPath)) {
|
|
33265
|
-
app.get("*", (
|
|
33824
|
+
app.get("*", (req, res, next) => {
|
|
33825
|
+
if (isApiRequest(req)) {
|
|
33826
|
+
next();
|
|
33827
|
+
return;
|
|
33828
|
+
}
|
|
33829
|
+
if (!canServeDashboard(req)) {
|
|
33830
|
+
res.status(404).type("text/plain").send("Not Found");
|
|
33831
|
+
return;
|
|
33832
|
+
}
|
|
33266
33833
|
res.sendFile(indexPath);
|
|
33267
33834
|
});
|
|
33268
33835
|
}
|
|
@@ -33337,10 +33904,10 @@ var DirectTransport = class {
|
|
|
33337
33904
|
};
|
|
33338
33905
|
|
|
33339
33906
|
// ../../packages/transport/src/devtunnel.ts
|
|
33340
|
-
var
|
|
33907
|
+
var import_node_child_process5 = require("child_process");
|
|
33341
33908
|
function isInstalled(cmd) {
|
|
33342
33909
|
try {
|
|
33343
|
-
(0,
|
|
33910
|
+
(0, import_node_child_process5.execSync)(process.platform === "win32" ? `where ${cmd}` : `command -v ${cmd}`, { stdio: "pipe" });
|
|
33344
33911
|
return true;
|
|
33345
33912
|
} catch {
|
|
33346
33913
|
return false;
|
|
@@ -33363,14 +33930,14 @@ var DevTunnelTransport = class {
|
|
|
33363
33930
|
);
|
|
33364
33931
|
}
|
|
33365
33932
|
try {
|
|
33366
|
-
(0,
|
|
33933
|
+
(0, import_node_child_process5.execSync)("devtunnel user show", { stdio: "pipe" });
|
|
33367
33934
|
} catch {
|
|
33368
33935
|
throw new Error(
|
|
33369
33936
|
"Not logged in to devtunnel. Run: devtunnel user login"
|
|
33370
33937
|
);
|
|
33371
33938
|
}
|
|
33372
33939
|
const hostArgs = this.buildHostArgs(localPort);
|
|
33373
|
-
const child = (0,
|
|
33940
|
+
const child = (0, import_node_child_process5.spawn)("devtunnel", hostArgs, {
|
|
33374
33941
|
stdio: ["pipe", "pipe", "pipe"]
|
|
33375
33942
|
});
|
|
33376
33943
|
this.process = child;
|
|
@@ -33475,7 +34042,7 @@ ${lines.join("")}`
|
|
|
33475
34042
|
return void 0;
|
|
33476
34043
|
}
|
|
33477
34044
|
try {
|
|
33478
|
-
(0,
|
|
34045
|
+
(0, import_node_child_process5.execFileSync)("devtunnel", ["show", tunnelId], { stdio: "pipe" });
|
|
33479
34046
|
return tunnelId;
|
|
33480
34047
|
} catch {
|
|
33481
34048
|
const createArgs = ["create", tunnelId];
|
|
@@ -33483,7 +34050,7 @@ ${lines.join("")}`
|
|
|
33483
34050
|
createArgs.push("-a");
|
|
33484
34051
|
}
|
|
33485
34052
|
try {
|
|
33486
|
-
(0,
|
|
34053
|
+
(0, import_node_child_process5.execFileSync)("devtunnel", createArgs, { stdio: "pipe" });
|
|
33487
34054
|
return tunnelId;
|
|
33488
34055
|
} catch (err) {
|
|
33489
34056
|
throw new Error(
|
|
@@ -33498,7 +34065,7 @@ ${lines.join("")}`
|
|
|
33498
34065
|
return;
|
|
33499
34066
|
}
|
|
33500
34067
|
try {
|
|
33501
|
-
(0,
|
|
34068
|
+
(0, import_node_child_process5.execFileSync)(
|
|
33502
34069
|
"devtunnel",
|
|
33503
34070
|
["port", "create", tunnelId, "-p", String(localPort), "--protocol", "http"],
|
|
33504
34071
|
{ stdio: "pipe" }
|
|
@@ -33514,7 +34081,7 @@ ${lines.join("")}`
|
|
|
33514
34081
|
}
|
|
33515
34082
|
listTunnelPorts(tunnelId) {
|
|
33516
34083
|
try {
|
|
33517
|
-
const output = (0,
|
|
34084
|
+
const output = (0, import_node_child_process5.execFileSync)("devtunnel", ["port", "list", tunnelId, "-j"], { stdio: "pipe" });
|
|
33518
34085
|
const parsed = JSON.parse(output.toString());
|
|
33519
34086
|
const items = Array.isArray(parsed) ? parsed : parsed && typeof parsed === "object" && Array.isArray(parsed.ports) ? parsed.ports : parsed && typeof parsed === "object" && Array.isArray(parsed.value) ? parsed.value : [];
|
|
33520
34087
|
return items.map((item) => getPortNumber(item)).filter((value) => value !== void 0);
|
|
@@ -33526,7 +34093,7 @@ ${lines.join("")}`
|
|
|
33526
34093
|
}
|
|
33527
34094
|
hasTunnelPort(tunnelId, localPort) {
|
|
33528
34095
|
try {
|
|
33529
|
-
(0,
|
|
34096
|
+
(0, import_node_child_process5.execFileSync)(
|
|
33530
34097
|
"devtunnel",
|
|
33531
34098
|
["port", "show", tunnelId, "-p", String(localPort), "-j"],
|
|
33532
34099
|
{ stdio: "pipe" }
|
|
@@ -33580,7 +34147,9 @@ function createTransport(config) {
|
|
|
33580
34147
|
}
|
|
33581
34148
|
}
|
|
33582
34149
|
|
|
33583
|
-
// src/
|
|
34150
|
+
// src/startup.ts
|
|
34151
|
+
var fs16 = __toESM(require("fs"), 1);
|
|
34152
|
+
var readline = __toESM(require("readline/promises"), 1);
|
|
33584
34153
|
function getDefaultNodeName() {
|
|
33585
34154
|
return getDeviceNodeName();
|
|
33586
34155
|
}
|
|
@@ -33596,9 +34165,10 @@ function createDefaultConfig(storagePath = resolveDefaultStoragePath(), nodeName
|
|
|
33596
34165
|
};
|
|
33597
34166
|
}
|
|
33598
34167
|
var DEFAULT_CONFIG3 = createDefaultConfig();
|
|
33599
|
-
function createRuntimeDefaultConfig(fileConfig) {
|
|
34168
|
+
function createRuntimeDefaultConfig(fileConfig, options = {}) {
|
|
33600
34169
|
const storagePath = fileConfig.storage?.path ?? resolveDefaultStoragePath();
|
|
33601
|
-
|
|
34170
|
+
const nodeName = options.ignorePersistedName ? getDeviceNodeName() : resolveDefaultNodeName(storagePath);
|
|
34171
|
+
return createDefaultConfig(storagePath, nodeName);
|
|
33602
34172
|
}
|
|
33603
34173
|
function parseArgs(argv) {
|
|
33604
34174
|
const result = {};
|
|
@@ -33636,6 +34206,12 @@ function parseArgs(argv) {
|
|
|
33636
34206
|
result.config = argv[++i];
|
|
33637
34207
|
}
|
|
33638
34208
|
break;
|
|
34209
|
+
case "--reset":
|
|
34210
|
+
result.reset = true;
|
|
34211
|
+
break;
|
|
34212
|
+
case "--disable-auth":
|
|
34213
|
+
result.disableAuth = true;
|
|
34214
|
+
break;
|
|
33639
34215
|
}
|
|
33640
34216
|
}
|
|
33641
34217
|
return result;
|
|
@@ -33746,6 +34322,67 @@ async function promptStartOptions(args, fileConfig, defaults, prompt) {
|
|
|
33746
34322
|
await closePrompt?.();
|
|
33747
34323
|
}
|
|
33748
34324
|
}
|
|
34325
|
+
function applyStartMetadata(storagePath, args) {
|
|
34326
|
+
const startup = resolveNodeStartupMetadata(storagePath);
|
|
34327
|
+
const result = { ...args };
|
|
34328
|
+
const loaded = {};
|
|
34329
|
+
const persistedName = resolvePersistedDefaultNodeName(storagePath);
|
|
34330
|
+
if (persistedName && result.name === void 0) {
|
|
34331
|
+
loaded.name = persistedName;
|
|
34332
|
+
}
|
|
34333
|
+
if (startup.port !== void 0 && result.port === void 0) {
|
|
34334
|
+
result.port = startup.port;
|
|
34335
|
+
loaded.port = startup.port;
|
|
34336
|
+
}
|
|
34337
|
+
if (startup.transport && result.transport === void 0) {
|
|
34338
|
+
result.transport = startup.transport;
|
|
34339
|
+
loaded.transport = startup.transport;
|
|
34340
|
+
}
|
|
34341
|
+
if (startup.join && result.join === void 0) {
|
|
34342
|
+
result.join = startup.join;
|
|
34343
|
+
loaded.join = startup.join;
|
|
34344
|
+
}
|
|
34345
|
+
return {
|
|
34346
|
+
args: result,
|
|
34347
|
+
loaded: Object.keys(loaded).length > 0 ? loaded : void 0
|
|
34348
|
+
};
|
|
34349
|
+
}
|
|
34350
|
+
function shouldCollectStartOptions(args, storagePath) {
|
|
34351
|
+
return args.reset === true || !hasPersistedNodeStartupMetadata(storagePath);
|
|
34352
|
+
}
|
|
34353
|
+
function resolveRuntimeAuthMetadata(storagePath, disableAuth = false) {
|
|
34354
|
+
const persisted = resolveNodeAuthMetadata(storagePath);
|
|
34355
|
+
if (disableAuth) {
|
|
34356
|
+
return { ...persisted, enabled: false };
|
|
34357
|
+
}
|
|
34358
|
+
if (!persisted.enabled && !persisted.allowSameTenant && persisted.allowedUsers.length === 0) {
|
|
34359
|
+
return {
|
|
34360
|
+
enabled: true,
|
|
34361
|
+
allowSameTenant: false,
|
|
34362
|
+
allowedUsers: []
|
|
34363
|
+
};
|
|
34364
|
+
}
|
|
34365
|
+
return persisted;
|
|
34366
|
+
}
|
|
34367
|
+
function formatLoadedStartMetadata(info, authEnabled) {
|
|
34368
|
+
const lines = ["Loaded startup options from metadata:"];
|
|
34369
|
+
if (info.name) {
|
|
34370
|
+
lines.push(` Node: ${info.name}`);
|
|
34371
|
+
}
|
|
34372
|
+
if (info.port !== void 0) {
|
|
34373
|
+
lines.push(` Port: ${info.port}`);
|
|
34374
|
+
}
|
|
34375
|
+
if (info.transport) {
|
|
34376
|
+
lines.push(` Transport: ${info.transport}`);
|
|
34377
|
+
}
|
|
34378
|
+
if (info.join) {
|
|
34379
|
+
lines.push(` Join: ${info.join}`);
|
|
34380
|
+
}
|
|
34381
|
+
lines.push(` Auth: ${authEnabled ? "enabled" : "disabled"}`);
|
|
34382
|
+
return lines.join("\n");
|
|
34383
|
+
}
|
|
34384
|
+
|
|
34385
|
+
// src/main.ts
|
|
33749
34386
|
function formatBanner(info) {
|
|
33750
34387
|
const lines = [
|
|
33751
34388
|
`Node: ${info.name}`,
|
|
@@ -33753,6 +34390,9 @@ function formatBanner(info) {
|
|
|
33753
34390
|
`Endpoint: ${info.endpoint}`,
|
|
33754
34391
|
`Dashboard: http://localhost:${info.port}`
|
|
33755
34392
|
];
|
|
34393
|
+
if (info.dashboardOrigin) {
|
|
34394
|
+
lines.push(`Dashboard Tunnel: ${info.dashboardOrigin}`);
|
|
34395
|
+
}
|
|
33756
34396
|
const maxLen = Math.max(...lines.map((l) => l.length));
|
|
33757
34397
|
const innerWidth = maxLen + 4;
|
|
33758
34398
|
const top = ` \u256D${"\u2500".repeat(innerWidth)}\u256E`;
|
|
@@ -33774,16 +34414,48 @@ async function main() {
|
|
|
33774
34414
|
const args = parseArgs(process.argv.slice(2));
|
|
33775
34415
|
const configPath = args.config ?? "./config.json";
|
|
33776
34416
|
const fileConfig = loadConfigFile(configPath);
|
|
33777
|
-
const
|
|
33778
|
-
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;
|
|
33779
34427
|
const config = mergeConfig(defaults, fileConfig, resolvedArgs);
|
|
33780
34428
|
persistDefaultNodeName(config.storage.path, config.node.name);
|
|
34429
|
+
persistNodeStartupMetadata(config.storage.path, {
|
|
34430
|
+
port: config.node.port,
|
|
34431
|
+
transport: config.transport.type,
|
|
34432
|
+
join: resolvedArgs.join
|
|
34433
|
+
});
|
|
34434
|
+
const authMetadata = resolveRuntimeAuthMetadata(config.storage.path, resolvedArgs.disableAuth === true);
|
|
34435
|
+
if (!resolvedArgs.disableAuth) {
|
|
34436
|
+
persistNodeAuthMetadata(config.storage.path, authMetadata);
|
|
34437
|
+
}
|
|
33781
34438
|
const logDir = nodePath.join(config.storage.path, "logs");
|
|
33782
34439
|
const logger = createLogger({
|
|
33783
34440
|
component: "node",
|
|
33784
34441
|
logDir,
|
|
33785
34442
|
console: true
|
|
33786
34443
|
});
|
|
34444
|
+
const nodeAuth = new AzureCliNodeAuth(config.storage.path, {
|
|
34445
|
+
logger: logger.child("azure-auth"),
|
|
34446
|
+
settingsProvider: () => authMetadata
|
|
34447
|
+
});
|
|
34448
|
+
if (hydratedArgs.loaded) {
|
|
34449
|
+
console.log("");
|
|
34450
|
+
console.log(formatLoadedStartMetadata(hydratedArgs.loaded, authMetadata.enabled));
|
|
34451
|
+
console.log("");
|
|
34452
|
+
}
|
|
34453
|
+
if (authMetadata.enabled) {
|
|
34454
|
+
nodeAuth.getAccessToken();
|
|
34455
|
+
setRequestAuthHeadersProvider(() => nodeAuth.getAuthorizationHeaders());
|
|
34456
|
+
} else {
|
|
34457
|
+
setRequestAuthHeadersProvider(null);
|
|
34458
|
+
}
|
|
33787
34459
|
const meshyNode = new MeshyNode(config, {
|
|
33788
34460
|
logger,
|
|
33789
34461
|
transportFactory: createTransport
|
|
@@ -33793,9 +34465,24 @@ async function main() {
|
|
|
33793
34465
|
const previewServer = new PreviewServer(previewSessionManager);
|
|
33794
34466
|
const previewPort = config.node.port + 1;
|
|
33795
34467
|
const actualPreviewPort = await previewServer.start(previewPort);
|
|
34468
|
+
let dashboardTransport = null;
|
|
34469
|
+
let dashboardOrigin;
|
|
33796
34470
|
let previewTransport = null;
|
|
33797
34471
|
let previewOrigin;
|
|
33798
34472
|
let deps;
|
|
34473
|
+
function createDashboardTransportConfig() {
|
|
34474
|
+
return {
|
|
34475
|
+
type: "devtunnel",
|
|
34476
|
+
devtunnel: {
|
|
34477
|
+
id: resolveOrCreateDevTunnelId(
|
|
34478
|
+
config.storage.path,
|
|
34479
|
+
meshyNode.getNodeRegistry().getSelf().id,
|
|
34480
|
+
"dashboard"
|
|
34481
|
+
),
|
|
34482
|
+
allowAnonymous: false
|
|
34483
|
+
}
|
|
34484
|
+
};
|
|
34485
|
+
}
|
|
33799
34486
|
function createPreviewTransportConfig() {
|
|
33800
34487
|
return {
|
|
33801
34488
|
type: "devtunnel",
|
|
@@ -33809,11 +34496,92 @@ async function main() {
|
|
|
33809
34496
|
}
|
|
33810
34497
|
};
|
|
33811
34498
|
}
|
|
34499
|
+
function setAdvertisedDashboardOrigin(origin) {
|
|
34500
|
+
dashboardOrigin = origin;
|
|
34501
|
+
deps.dashboardOrigin = origin;
|
|
34502
|
+
meshyNode.getNodeRegistry().updateDashboardOrigin(meshyNode.getNodeRegistry().getSelf().id, origin);
|
|
34503
|
+
}
|
|
33812
34504
|
function setAdvertisedPreviewOrigin(origin) {
|
|
33813
34505
|
previewOrigin = origin;
|
|
33814
34506
|
deps.previewOrigin = origin;
|
|
33815
34507
|
meshyNode.getNodeRegistry().updatePreviewOrigin(meshyNode.getNodeRegistry().getSelf().id, origin);
|
|
33816
34508
|
}
|
|
34509
|
+
function shouldPublishDashboardTunnel() {
|
|
34510
|
+
return authMetadata.enabled && (meshyNode.getTransportType() === "devtunnel" || meshyNode.isDevTunnelEnabled());
|
|
34511
|
+
}
|
|
34512
|
+
async function stopDashboardTransport() {
|
|
34513
|
+
if (!dashboardTransport) {
|
|
34514
|
+
if (dashboardOrigin) {
|
|
34515
|
+
setAdvertisedDashboardOrigin(void 0);
|
|
34516
|
+
}
|
|
34517
|
+
return;
|
|
34518
|
+
}
|
|
34519
|
+
await dashboardTransport.stop().catch(() => void 0);
|
|
34520
|
+
dashboardTransport = null;
|
|
34521
|
+
setAdvertisedDashboardOrigin(void 0);
|
|
34522
|
+
meshyNode.getLogger().info("stopped dashboard tunnel", {
|
|
34523
|
+
reason: "dashboard transport no longer required",
|
|
34524
|
+
mainTransportType: meshyNode.getTransportType(),
|
|
34525
|
+
sidecarEnabled: meshyNode.isDevTunnelEnabled()
|
|
34526
|
+
});
|
|
34527
|
+
}
|
|
34528
|
+
async function restartDashboardTransport(transportConfig) {
|
|
34529
|
+
const previousTransport = dashboardTransport;
|
|
34530
|
+
const previousOrigin = dashboardOrigin;
|
|
34531
|
+
let nextTransport = null;
|
|
34532
|
+
try {
|
|
34533
|
+
nextTransport = createTransport(transportConfig);
|
|
34534
|
+
await nextTransport.start(config.node.port);
|
|
34535
|
+
const nextOrigin = await nextTransport.getEndpoint();
|
|
34536
|
+
dashboardTransport = nextTransport;
|
|
34537
|
+
setAdvertisedDashboardOrigin(nextOrigin);
|
|
34538
|
+
meshyNode.getLogger().info("started dashboard tunnel", {
|
|
34539
|
+
dashboardOrigin: nextOrigin,
|
|
34540
|
+
mainTransportType: meshyNode.getTransportType(),
|
|
34541
|
+
sidecarEnabled: meshyNode.isDevTunnelEnabled()
|
|
34542
|
+
});
|
|
34543
|
+
if (previousTransport) {
|
|
34544
|
+
await previousTransport.stop().catch(() => void 0);
|
|
34545
|
+
}
|
|
34546
|
+
} catch (err) {
|
|
34547
|
+
if (nextTransport) {
|
|
34548
|
+
await nextTransport.stop().catch(() => void 0);
|
|
34549
|
+
}
|
|
34550
|
+
dashboardTransport = previousTransport;
|
|
34551
|
+
setAdvertisedDashboardOrigin(previousOrigin);
|
|
34552
|
+
meshyNode.getLogger().warn("failed to start dashboard transport", {
|
|
34553
|
+
error: err instanceof Error ? err.message : String(err),
|
|
34554
|
+
port: config.node.port,
|
|
34555
|
+
transportType: transportConfig.type
|
|
34556
|
+
});
|
|
34557
|
+
}
|
|
34558
|
+
}
|
|
34559
|
+
async function syncDashboardTransport(reason) {
|
|
34560
|
+
if (!authMetadata.enabled) {
|
|
34561
|
+
await stopDashboardTransport();
|
|
34562
|
+
return;
|
|
34563
|
+
}
|
|
34564
|
+
if (!shouldPublishDashboardTunnel()) {
|
|
34565
|
+
meshyNode.getLogger().info("skipping dashboard tunnel", {
|
|
34566
|
+
reason,
|
|
34567
|
+
mainTransportType: meshyNode.getTransportType(),
|
|
34568
|
+
sidecarEnabled: meshyNode.isDevTunnelEnabled(),
|
|
34569
|
+
authEnabled: authMetadata.enabled
|
|
34570
|
+
});
|
|
34571
|
+
await stopDashboardTransport();
|
|
34572
|
+
return;
|
|
34573
|
+
}
|
|
34574
|
+
if (dashboardTransport && await dashboardTransport.isHealthy().catch(() => false)) {
|
|
34575
|
+
meshyNode.getLogger().debug("dashboard tunnel already active", {
|
|
34576
|
+
reason,
|
|
34577
|
+
dashboardOrigin,
|
|
34578
|
+
mainTransportType: meshyNode.getTransportType(),
|
|
34579
|
+
sidecarEnabled: meshyNode.isDevTunnelEnabled()
|
|
34580
|
+
});
|
|
34581
|
+
return;
|
|
34582
|
+
}
|
|
34583
|
+
await restartDashboardTransport(createDashboardTransportConfig());
|
|
34584
|
+
}
|
|
33817
34585
|
async function restartPreviewTransport(transportConfig) {
|
|
33818
34586
|
const previousTransport = previewTransport;
|
|
33819
34587
|
const previousOrigin = previewOrigin;
|
|
@@ -33849,7 +34617,11 @@ async function main() {
|
|
|
33849
34617
|
eventBus: meshyNode.getEventBus(),
|
|
33850
34618
|
engineRegistry: meshyNode.getEngineRegistry(),
|
|
33851
34619
|
logger: meshyNode.getLogger(),
|
|
33852
|
-
config: {
|
|
34620
|
+
config: {
|
|
34621
|
+
apiKey: config.cluster.apiKey,
|
|
34622
|
+
authMetadata,
|
|
34623
|
+
validateBearerToken: authMetadata.enabled ? (header) => nodeAuth.validateAuthorizationHeader(header) : void 0
|
|
34624
|
+
},
|
|
33853
34625
|
workDir: meshyNode.getWorkDir(),
|
|
33854
34626
|
persistNodeNamePreference: (name) => persistDefaultNodeName(config.storage.path, name),
|
|
33855
34627
|
joinCurrentNodeToCluster: async (leaderEndpoint) => {
|
|
@@ -33859,12 +34631,28 @@ async function main() {
|
|
|
33859
34631
|
await meshyNode.leaveCluster();
|
|
33860
34632
|
},
|
|
33861
34633
|
switchTransport: async (type) => {
|
|
33862
|
-
|
|
34634
|
+
const endpoint = await meshyNode.switchTransport(type);
|
|
34635
|
+
persistNodeStartupTransport(config.storage.path, type);
|
|
34636
|
+
await syncDashboardTransport(`switchTransport:${type}`);
|
|
34637
|
+
return endpoint;
|
|
33863
34638
|
},
|
|
33864
34639
|
getTransportType: () => meshyNode.getTransportType(),
|
|
33865
|
-
enableDevTunnel: async () =>
|
|
33866
|
-
|
|
34640
|
+
enableDevTunnel: async () => {
|
|
34641
|
+
const endpoint = await meshyNode.enableDevTunnel();
|
|
34642
|
+
persistNodeStartupTransport(config.storage.path, "devtunnel");
|
|
34643
|
+
await syncDashboardTransport("enableDevTunnel");
|
|
34644
|
+
return endpoint;
|
|
34645
|
+
},
|
|
34646
|
+
disableDevTunnel: async () => {
|
|
34647
|
+
await meshyNode.disableDevTunnel();
|
|
34648
|
+
persistNodeStartupTransport(
|
|
34649
|
+
config.storage.path,
|
|
34650
|
+
meshyNode.getTransportType()
|
|
34651
|
+
);
|
|
34652
|
+
await syncDashboardTransport("disableDevTunnel");
|
|
34653
|
+
},
|
|
33867
34654
|
isDevTunnelEnabled: () => meshyNode.isDevTunnelEnabled(),
|
|
34655
|
+
dashboardOrigin,
|
|
33868
34656
|
ensurePreviewOrigin: async () => {
|
|
33869
34657
|
if (previewTransport && !await previewTransport.isHealthy()) {
|
|
33870
34658
|
await previewTransport.stop().catch(() => void 0);
|
|
@@ -33880,7 +34668,16 @@ async function main() {
|
|
|
33880
34668
|
};
|
|
33881
34669
|
deps.previewSessionManager = previewSessionManager;
|
|
33882
34670
|
deps.previewPort = actualPreviewPort;
|
|
34671
|
+
deps.dashboardOrigin = dashboardOrigin;
|
|
33883
34672
|
deps.previewOrigin = previewOrigin;
|
|
34673
|
+
meshyNode.getLogger().info("configured node auth mode", {
|
|
34674
|
+
authEnabled: authMetadata.enabled,
|
|
34675
|
+
allowSameTenant: authMetadata.allowSameTenant,
|
|
34676
|
+
allowedUsersCount: authMetadata.allowedUsers.length,
|
|
34677
|
+
mainTransportType: meshyNode.getTransportType(),
|
|
34678
|
+
sidecarEnabled: meshyNode.isDevTunnelEnabled()
|
|
34679
|
+
});
|
|
34680
|
+
await syncDashboardTransport("startup");
|
|
33884
34681
|
const previewHealthTimer = setInterval(() => {
|
|
33885
34682
|
void (async () => {
|
|
33886
34683
|
if (!previewTransport) return;
|
|
@@ -33894,6 +34691,19 @@ async function main() {
|
|
|
33894
34691
|
});
|
|
33895
34692
|
})();
|
|
33896
34693
|
}, config.cluster.heartbeatInterval);
|
|
34694
|
+
const dashboardHealthTimer = setInterval(() => {
|
|
34695
|
+
void (async () => {
|
|
34696
|
+
if (!dashboardTransport) return;
|
|
34697
|
+
const healthy = await dashboardTransport.isHealthy().catch(() => false);
|
|
34698
|
+
if (healthy) return;
|
|
34699
|
+
await dashboardTransport.stop().catch(() => void 0);
|
|
34700
|
+
dashboardTransport = null;
|
|
34701
|
+
setAdvertisedDashboardOrigin(void 0);
|
|
34702
|
+
meshyNode.getLogger().warn("dashboard transport became unhealthy and was cleared", {
|
|
34703
|
+
port: config.node.port
|
|
34704
|
+
});
|
|
34705
|
+
})();
|
|
34706
|
+
}, config.cluster.heartbeatInterval);
|
|
33897
34707
|
const app = createServer2(deps);
|
|
33898
34708
|
const server = app.listen(config.node.port, () => {
|
|
33899
34709
|
const self = meshyNode.getNodeRegistry().getSelf();
|
|
@@ -33904,7 +34714,8 @@ async function main() {
|
|
|
33904
34714
|
role,
|
|
33905
34715
|
term,
|
|
33906
34716
|
endpoint: self.endpoint,
|
|
33907
|
-
port: config.node.port
|
|
34717
|
+
port: config.node.port,
|
|
34718
|
+
dashboardOrigin
|
|
33908
34719
|
});
|
|
33909
34720
|
console.log("");
|
|
33910
34721
|
console.log(banner);
|
|
@@ -33916,7 +34727,11 @@ async function main() {
|
|
|
33916
34727
|
shuttingDown = true;
|
|
33917
34728
|
console.log("\nShutting down...");
|
|
33918
34729
|
try {
|
|
34730
|
+
clearInterval(dashboardHealthTimer);
|
|
33919
34731
|
clearInterval(previewHealthTimer);
|
|
34732
|
+
if (dashboardTransport) {
|
|
34733
|
+
await dashboardTransport.stop();
|
|
34734
|
+
}
|
|
33920
34735
|
if (previewTransport) {
|
|
33921
34736
|
await previewTransport.stop();
|
|
33922
34737
|
}
|
|
@@ -33945,9 +34760,11 @@ if (isDirectRun) {
|
|
|
33945
34760
|
DEFAULT_CONFIG,
|
|
33946
34761
|
DEFAULT_NODE_NAME,
|
|
33947
34762
|
DEFAULT_NODE_PORT,
|
|
34763
|
+
applyStartMetadata,
|
|
33948
34764
|
createDefaultConfig,
|
|
33949
34765
|
createRuntimeDefaultConfig,
|
|
33950
34766
|
formatBanner,
|
|
34767
|
+
formatLoadedStartMetadata,
|
|
33951
34768
|
getDefaultNodeName,
|
|
33952
34769
|
isDirectRunPath,
|
|
33953
34770
|
loadConfigFile,
|
|
@@ -33955,6 +34772,8 @@ if (isDirectRun) {
|
|
|
33955
34772
|
mergeConfig,
|
|
33956
34773
|
parseArgs,
|
|
33957
34774
|
promptStartOptions,
|
|
34775
|
+
resolveRuntimeAuthMetadata,
|
|
34776
|
+
shouldCollectStartOptions,
|
|
33958
34777
|
shouldPromptForStartOptions
|
|
33959
34778
|
});
|
|
33960
34779
|
/*! Bundled license information:
|