meshy-node 0.0.6 → 0.0.8
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-D5VZZBFL.js +200 -0
- package/dashboard/assets/{DiffTab-B22VET7i.js → DiffTab-DHa2twrY.js} +4 -4
- package/dashboard/assets/{FilesTab-DkODTD1c.js → FilesTab-DI35HxWK.js} +1 -1
- package/dashboard/assets/{PreviewTab-CtdlW-8Z.js → PreviewTab-CAEInFgg.js} +1 -1
- package/dashboard/assets/{folder-D6MCA6XV.js → folder-0eOoupgZ.js} +1 -1
- package/dashboard/assets/index-Bx5CT0VB.css +1 -0
- package/dashboard/assets/{index-Br1FoGY0.js → index-CRdTxsjS.js} +4 -4
- package/dashboard/index.html +2 -2
- package/main.cjs +1678 -293
- 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
|
@@ -14251,11 +14251,11 @@ var require_mime_types = __commonJS({
|
|
|
14251
14251
|
}
|
|
14252
14252
|
return exts[0];
|
|
14253
14253
|
}
|
|
14254
|
-
function lookup(
|
|
14255
|
-
if (!
|
|
14254
|
+
function lookup(path17) {
|
|
14255
|
+
if (!path17 || typeof path17 !== "string") {
|
|
14256
14256
|
return false;
|
|
14257
14257
|
}
|
|
14258
|
-
var extension2 = extname3("x." +
|
|
14258
|
+
var extension2 = extname3("x." + path17).toLowerCase().substr(1);
|
|
14259
14259
|
if (!extension2) {
|
|
14260
14260
|
return false;
|
|
14261
14261
|
}
|
|
@@ -17773,7 +17773,7 @@ var require_path_to_regexp = __commonJS({
|
|
|
17773
17773
|
"use strict";
|
|
17774
17774
|
module2.exports = pathToRegexp;
|
|
17775
17775
|
var MATCHING_GROUP_REGEXP = /\\.|\((?:\?<(.*?)>)?(?!\?)/g;
|
|
17776
|
-
function pathToRegexp(
|
|
17776
|
+
function pathToRegexp(path17, keys, options) {
|
|
17777
17777
|
options = options || {};
|
|
17778
17778
|
keys = keys || [];
|
|
17779
17779
|
var strict = options.strict;
|
|
@@ -17787,8 +17787,8 @@ var require_path_to_regexp = __commonJS({
|
|
|
17787
17787
|
var pos = 0;
|
|
17788
17788
|
var backtrack = "";
|
|
17789
17789
|
var m;
|
|
17790
|
-
if (
|
|
17791
|
-
while (m = MATCHING_GROUP_REGEXP.exec(
|
|
17790
|
+
if (path17 instanceof RegExp) {
|
|
17791
|
+
while (m = MATCHING_GROUP_REGEXP.exec(path17.source)) {
|
|
17792
17792
|
if (m[0][0] === "\\") continue;
|
|
17793
17793
|
keys.push({
|
|
17794
17794
|
name: m[1] || name++,
|
|
@@ -17796,18 +17796,18 @@ var require_path_to_regexp = __commonJS({
|
|
|
17796
17796
|
offset: m.index
|
|
17797
17797
|
});
|
|
17798
17798
|
}
|
|
17799
|
-
return
|
|
17799
|
+
return path17;
|
|
17800
17800
|
}
|
|
17801
|
-
if (Array.isArray(
|
|
17802
|
-
|
|
17801
|
+
if (Array.isArray(path17)) {
|
|
17802
|
+
path17 = path17.map(function(value) {
|
|
17803
17803
|
return pathToRegexp(value, keys, options).source;
|
|
17804
17804
|
});
|
|
17805
|
-
return new RegExp(
|
|
17805
|
+
return new RegExp(path17.join("|"), flags);
|
|
17806
17806
|
}
|
|
17807
|
-
if (typeof
|
|
17807
|
+
if (typeof path17 !== "string") {
|
|
17808
17808
|
throw new TypeError("path must be a string, array of strings, or regular expression");
|
|
17809
17809
|
}
|
|
17810
|
-
|
|
17810
|
+
path17 = path17.replace(
|
|
17811
17811
|
/\\.|(\/)?(\.)?:(\w+)(\(.*?\))?(\*)?(\?)?|[.*]|\/\(/g,
|
|
17812
17812
|
function(match, slash, format, key, capture, star, optional, offset) {
|
|
17813
17813
|
if (match[0] === "\\") {
|
|
@@ -17824,7 +17824,7 @@ var require_path_to_regexp = __commonJS({
|
|
|
17824
17824
|
if (slash || format) {
|
|
17825
17825
|
backtrack = "";
|
|
17826
17826
|
} else {
|
|
17827
|
-
backtrack +=
|
|
17827
|
+
backtrack += path17.slice(pos, offset);
|
|
17828
17828
|
}
|
|
17829
17829
|
pos = offset + match.length;
|
|
17830
17830
|
if (match === "*") {
|
|
@@ -17854,7 +17854,7 @@ var require_path_to_regexp = __commonJS({
|
|
|
17854
17854
|
return result;
|
|
17855
17855
|
}
|
|
17856
17856
|
);
|
|
17857
|
-
while (m = MATCHING_GROUP_REGEXP.exec(
|
|
17857
|
+
while (m = MATCHING_GROUP_REGEXP.exec(path17)) {
|
|
17858
17858
|
if (m[0][0] === "\\") continue;
|
|
17859
17859
|
if (keysOffset + i === keys.length || keys[keysOffset + i].offset > m.index) {
|
|
17860
17860
|
keys.splice(keysOffset + i, 0, {
|
|
@@ -17866,13 +17866,13 @@ var require_path_to_regexp = __commonJS({
|
|
|
17866
17866
|
}
|
|
17867
17867
|
i++;
|
|
17868
17868
|
}
|
|
17869
|
-
|
|
17869
|
+
path17 += strict ? "" : path17[path17.length - 1] === "/" ? "?" : "/?";
|
|
17870
17870
|
if (end) {
|
|
17871
|
-
|
|
17872
|
-
} else if (
|
|
17873
|
-
|
|
17871
|
+
path17 += "$";
|
|
17872
|
+
} else if (path17[path17.length - 1] !== "/") {
|
|
17873
|
+
path17 += lookahead ? "(?=/|$)" : "(?:/|$)";
|
|
17874
17874
|
}
|
|
17875
|
-
return new RegExp("^" +
|
|
17875
|
+
return new RegExp("^" + path17, flags);
|
|
17876
17876
|
}
|
|
17877
17877
|
}
|
|
17878
17878
|
});
|
|
@@ -17885,19 +17885,19 @@ var require_layer = __commonJS({
|
|
|
17885
17885
|
var debug = require_src()("express:router:layer");
|
|
17886
17886
|
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
17887
17887
|
module2.exports = Layer;
|
|
17888
|
-
function Layer(
|
|
17888
|
+
function Layer(path17, options, fn) {
|
|
17889
17889
|
if (!(this instanceof Layer)) {
|
|
17890
|
-
return new Layer(
|
|
17890
|
+
return new Layer(path17, options, fn);
|
|
17891
17891
|
}
|
|
17892
|
-
debug("new %o",
|
|
17892
|
+
debug("new %o", path17);
|
|
17893
17893
|
var opts = options || {};
|
|
17894
17894
|
this.handle = fn;
|
|
17895
17895
|
this.name = fn.name || "<anonymous>";
|
|
17896
17896
|
this.params = void 0;
|
|
17897
17897
|
this.path = void 0;
|
|
17898
|
-
this.regexp = pathRegexp(
|
|
17899
|
-
this.regexp.fast_star =
|
|
17900
|
-
this.regexp.fast_slash =
|
|
17898
|
+
this.regexp = pathRegexp(path17, this.keys = [], opts);
|
|
17899
|
+
this.regexp.fast_star = path17 === "*";
|
|
17900
|
+
this.regexp.fast_slash = path17 === "/" && opts.end === false;
|
|
17901
17901
|
}
|
|
17902
17902
|
Layer.prototype.handle_error = function handle_error(error, req, res, next) {
|
|
17903
17903
|
var fn = this.handle;
|
|
@@ -17921,20 +17921,20 @@ var require_layer = __commonJS({
|
|
|
17921
17921
|
next(err);
|
|
17922
17922
|
}
|
|
17923
17923
|
};
|
|
17924
|
-
Layer.prototype.match = function match(
|
|
17924
|
+
Layer.prototype.match = function match(path17) {
|
|
17925
17925
|
var match2;
|
|
17926
|
-
if (
|
|
17926
|
+
if (path17 != null) {
|
|
17927
17927
|
if (this.regexp.fast_slash) {
|
|
17928
17928
|
this.params = {};
|
|
17929
17929
|
this.path = "";
|
|
17930
17930
|
return true;
|
|
17931
17931
|
}
|
|
17932
17932
|
if (this.regexp.fast_star) {
|
|
17933
|
-
this.params = { "0": decode_param(
|
|
17934
|
-
this.path =
|
|
17933
|
+
this.params = { "0": decode_param(path17) };
|
|
17934
|
+
this.path = path17;
|
|
17935
17935
|
return true;
|
|
17936
17936
|
}
|
|
17937
|
-
match2 = this.regexp.exec(
|
|
17937
|
+
match2 = this.regexp.exec(path17);
|
|
17938
17938
|
}
|
|
17939
17939
|
if (!match2) {
|
|
17940
17940
|
this.params = void 0;
|
|
@@ -18027,10 +18027,10 @@ var require_route = __commonJS({
|
|
|
18027
18027
|
var slice = Array.prototype.slice;
|
|
18028
18028
|
var toString = Object.prototype.toString;
|
|
18029
18029
|
module2.exports = Route;
|
|
18030
|
-
function Route(
|
|
18031
|
-
this.path =
|
|
18030
|
+
function Route(path17) {
|
|
18031
|
+
this.path = path17;
|
|
18032
18032
|
this.stack = [];
|
|
18033
|
-
debug("new %o",
|
|
18033
|
+
debug("new %o", path17);
|
|
18034
18034
|
this.methods = {};
|
|
18035
18035
|
}
|
|
18036
18036
|
Route.prototype._handles_method = function _handles_method(method) {
|
|
@@ -18243,8 +18243,8 @@ var require_router = __commonJS({
|
|
|
18243
18243
|
if (++sync > 100) {
|
|
18244
18244
|
return setImmediate(next, err);
|
|
18245
18245
|
}
|
|
18246
|
-
var
|
|
18247
|
-
if (
|
|
18246
|
+
var path17 = getPathname(req);
|
|
18247
|
+
if (path17 == null) {
|
|
18248
18248
|
return done(layerError);
|
|
18249
18249
|
}
|
|
18250
18250
|
var layer;
|
|
@@ -18252,7 +18252,7 @@ var require_router = __commonJS({
|
|
|
18252
18252
|
var route;
|
|
18253
18253
|
while (match !== true && idx < stack.length) {
|
|
18254
18254
|
layer = stack[idx++];
|
|
18255
|
-
match = matchLayer(layer,
|
|
18255
|
+
match = matchLayer(layer, path17);
|
|
18256
18256
|
route = layer.route;
|
|
18257
18257
|
if (typeof match !== "boolean") {
|
|
18258
18258
|
layerError = layerError || match;
|
|
@@ -18290,18 +18290,18 @@ var require_router = __commonJS({
|
|
|
18290
18290
|
} else if (route) {
|
|
18291
18291
|
layer.handle_request(req, res, next);
|
|
18292
18292
|
} else {
|
|
18293
|
-
trim_prefix(layer, layerError, layerPath,
|
|
18293
|
+
trim_prefix(layer, layerError, layerPath, path17);
|
|
18294
18294
|
}
|
|
18295
18295
|
sync = 0;
|
|
18296
18296
|
});
|
|
18297
18297
|
}
|
|
18298
|
-
function trim_prefix(layer, layerError, layerPath,
|
|
18298
|
+
function trim_prefix(layer, layerError, layerPath, path17) {
|
|
18299
18299
|
if (layerPath.length !== 0) {
|
|
18300
|
-
if (layerPath !==
|
|
18300
|
+
if (layerPath !== path17.slice(0, layerPath.length)) {
|
|
18301
18301
|
next(layerError);
|
|
18302
18302
|
return;
|
|
18303
18303
|
}
|
|
18304
|
-
var c =
|
|
18304
|
+
var c = path17[layerPath.length];
|
|
18305
18305
|
if (c && c !== "/" && c !== ".") return next(layerError);
|
|
18306
18306
|
debug("trim prefix (%s) from url %s", layerPath, req.url);
|
|
18307
18307
|
removed = layerPath;
|
|
@@ -18379,7 +18379,7 @@ var require_router = __commonJS({
|
|
|
18379
18379
|
};
|
|
18380
18380
|
proto.use = function use(fn) {
|
|
18381
18381
|
var offset = 0;
|
|
18382
|
-
var
|
|
18382
|
+
var path17 = "/";
|
|
18383
18383
|
if (typeof fn !== "function") {
|
|
18384
18384
|
var arg = fn;
|
|
18385
18385
|
while (Array.isArray(arg) && arg.length !== 0) {
|
|
@@ -18387,7 +18387,7 @@ var require_router = __commonJS({
|
|
|
18387
18387
|
}
|
|
18388
18388
|
if (typeof arg !== "function") {
|
|
18389
18389
|
offset = 1;
|
|
18390
|
-
|
|
18390
|
+
path17 = fn;
|
|
18391
18391
|
}
|
|
18392
18392
|
}
|
|
18393
18393
|
var callbacks = flatten(slice.call(arguments, offset));
|
|
@@ -18399,8 +18399,8 @@ var require_router = __commonJS({
|
|
|
18399
18399
|
if (typeof fn !== "function") {
|
|
18400
18400
|
throw new TypeError("Router.use() requires a middleware function but got a " + gettype(fn));
|
|
18401
18401
|
}
|
|
18402
|
-
debug("use %o %s",
|
|
18403
|
-
var layer = new Layer(
|
|
18402
|
+
debug("use %o %s", path17, fn.name || "<anonymous>");
|
|
18403
|
+
var layer = new Layer(path17, {
|
|
18404
18404
|
sensitive: this.caseSensitive,
|
|
18405
18405
|
strict: false,
|
|
18406
18406
|
end: false
|
|
@@ -18410,9 +18410,9 @@ var require_router = __commonJS({
|
|
|
18410
18410
|
}
|
|
18411
18411
|
return this;
|
|
18412
18412
|
};
|
|
18413
|
-
proto.route = function route(
|
|
18414
|
-
var route2 = new Route(
|
|
18415
|
-
var layer = new Layer(
|
|
18413
|
+
proto.route = function route(path17) {
|
|
18414
|
+
var route2 = new Route(path17);
|
|
18415
|
+
var layer = new Layer(path17, {
|
|
18416
18416
|
sensitive: this.caseSensitive,
|
|
18417
18417
|
strict: this.strict,
|
|
18418
18418
|
end: true
|
|
@@ -18422,8 +18422,8 @@ var require_router = __commonJS({
|
|
|
18422
18422
|
return route2;
|
|
18423
18423
|
};
|
|
18424
18424
|
methods.concat("all").forEach(function(method) {
|
|
18425
|
-
proto[method] = function(
|
|
18426
|
-
var route = this.route(
|
|
18425
|
+
proto[method] = function(path17) {
|
|
18426
|
+
var route = this.route(path17);
|
|
18427
18427
|
route[method].apply(route, slice.call(arguments, 1));
|
|
18428
18428
|
return this;
|
|
18429
18429
|
};
|
|
@@ -18459,9 +18459,9 @@ var require_router = __commonJS({
|
|
|
18459
18459
|
}
|
|
18460
18460
|
return toString.call(obj).replace(objectRegExp, "$1");
|
|
18461
18461
|
}
|
|
18462
|
-
function matchLayer(layer,
|
|
18462
|
+
function matchLayer(layer, path17) {
|
|
18463
18463
|
try {
|
|
18464
|
-
return layer.match(
|
|
18464
|
+
return layer.match(path17);
|
|
18465
18465
|
} catch (err) {
|
|
18466
18466
|
return err;
|
|
18467
18467
|
}
|
|
@@ -18579,13 +18579,13 @@ var require_view = __commonJS({
|
|
|
18579
18579
|
"../../node_modules/.pnpm/express@4.22.1/node_modules/express/lib/view.js"(exports2, module2) {
|
|
18580
18580
|
"use strict";
|
|
18581
18581
|
var debug = require_src()("express:view");
|
|
18582
|
-
var
|
|
18582
|
+
var path17 = require("path");
|
|
18583
18583
|
var fs17 = require("fs");
|
|
18584
|
-
var dirname3 =
|
|
18585
|
-
var basename4 =
|
|
18586
|
-
var extname3 =
|
|
18587
|
-
var
|
|
18588
|
-
var resolve10 =
|
|
18584
|
+
var dirname3 = path17.dirname;
|
|
18585
|
+
var basename4 = path17.basename;
|
|
18586
|
+
var extname3 = path17.extname;
|
|
18587
|
+
var join13 = path17.join;
|
|
18588
|
+
var resolve10 = path17.resolve;
|
|
18589
18589
|
module2.exports = View;
|
|
18590
18590
|
function View(name, options) {
|
|
18591
18591
|
var opts = options || {};
|
|
@@ -18614,17 +18614,17 @@ var require_view = __commonJS({
|
|
|
18614
18614
|
this.path = this.lookup(fileName);
|
|
18615
18615
|
}
|
|
18616
18616
|
View.prototype.lookup = function lookup(name) {
|
|
18617
|
-
var
|
|
18617
|
+
var path18;
|
|
18618
18618
|
var roots = [].concat(this.root);
|
|
18619
18619
|
debug('lookup "%s"', name);
|
|
18620
|
-
for (var i = 0; i < roots.length && !
|
|
18620
|
+
for (var i = 0; i < roots.length && !path18; i++) {
|
|
18621
18621
|
var root = roots[i];
|
|
18622
18622
|
var loc = resolve10(root, name);
|
|
18623
18623
|
var dir = dirname3(loc);
|
|
18624
18624
|
var file = basename4(loc);
|
|
18625
|
-
|
|
18625
|
+
path18 = this.resolve(dir, file);
|
|
18626
18626
|
}
|
|
18627
|
-
return
|
|
18627
|
+
return path18;
|
|
18628
18628
|
};
|
|
18629
18629
|
View.prototype.render = function render(options, callback) {
|
|
18630
18630
|
debug('render "%s"', this.path);
|
|
@@ -18632,21 +18632,21 @@ var require_view = __commonJS({
|
|
|
18632
18632
|
};
|
|
18633
18633
|
View.prototype.resolve = function resolve11(dir, file) {
|
|
18634
18634
|
var ext = this.ext;
|
|
18635
|
-
var
|
|
18636
|
-
var stat = tryStat(
|
|
18635
|
+
var path18 = join13(dir, file);
|
|
18636
|
+
var stat = tryStat(path18);
|
|
18637
18637
|
if (stat && stat.isFile()) {
|
|
18638
|
-
return
|
|
18638
|
+
return path18;
|
|
18639
18639
|
}
|
|
18640
|
-
|
|
18641
|
-
stat = tryStat(
|
|
18640
|
+
path18 = join13(dir, basename4(file, ext), "index" + ext);
|
|
18641
|
+
stat = tryStat(path18);
|
|
18642
18642
|
if (stat && stat.isFile()) {
|
|
18643
|
-
return
|
|
18643
|
+
return path18;
|
|
18644
18644
|
}
|
|
18645
18645
|
};
|
|
18646
|
-
function tryStat(
|
|
18647
|
-
debug('stat "%s"',
|
|
18646
|
+
function tryStat(path18) {
|
|
18647
|
+
debug('stat "%s"', path18);
|
|
18648
18648
|
try {
|
|
18649
|
-
return fs17.statSync(
|
|
18649
|
+
return fs17.statSync(path18);
|
|
18650
18650
|
} catch (e) {
|
|
18651
18651
|
return void 0;
|
|
18652
18652
|
}
|
|
@@ -19002,7 +19002,7 @@ var require_types = __commonJS({
|
|
|
19002
19002
|
var require_mime = __commonJS({
|
|
19003
19003
|
"../../node_modules/.pnpm/mime@1.6.0/node_modules/mime/mime.js"(exports2, module2) {
|
|
19004
19004
|
"use strict";
|
|
19005
|
-
var
|
|
19005
|
+
var path17 = require("path");
|
|
19006
19006
|
var fs17 = require("fs");
|
|
19007
19007
|
function Mime() {
|
|
19008
19008
|
this.types = /* @__PURE__ */ Object.create(null);
|
|
@@ -19032,8 +19032,8 @@ var require_mime = __commonJS({
|
|
|
19032
19032
|
this.define(map);
|
|
19033
19033
|
this._loading = null;
|
|
19034
19034
|
};
|
|
19035
|
-
Mime.prototype.lookup = function(
|
|
19036
|
-
var ext =
|
|
19035
|
+
Mime.prototype.lookup = function(path18, fallback) {
|
|
19036
|
+
var ext = path18.replace(/^.*[\.\/\\]/, "").toLowerCase();
|
|
19037
19037
|
return this.types[ext] || fallback || this.default_type;
|
|
19038
19038
|
};
|
|
19039
19039
|
Mime.prototype.extension = function(mimeType) {
|
|
@@ -19268,28 +19268,28 @@ var require_send = __commonJS({
|
|
|
19268
19268
|
var ms = require_ms2();
|
|
19269
19269
|
var onFinished = require_on_finished();
|
|
19270
19270
|
var parseRange = require_range_parser();
|
|
19271
|
-
var
|
|
19271
|
+
var path17 = require("path");
|
|
19272
19272
|
var statuses = require_statuses();
|
|
19273
19273
|
var Stream = require("stream");
|
|
19274
19274
|
var util2 = require("util");
|
|
19275
|
-
var extname3 =
|
|
19276
|
-
var
|
|
19277
|
-
var normalize =
|
|
19278
|
-
var resolve10 =
|
|
19279
|
-
var sep3 =
|
|
19275
|
+
var extname3 = path17.extname;
|
|
19276
|
+
var join13 = path17.join;
|
|
19277
|
+
var normalize = path17.normalize;
|
|
19278
|
+
var resolve10 = path17.resolve;
|
|
19279
|
+
var sep3 = path17.sep;
|
|
19280
19280
|
var BYTES_RANGE_REGEXP = /^ *bytes=/;
|
|
19281
19281
|
var MAX_MAXAGE = 60 * 60 * 24 * 365 * 1e3;
|
|
19282
19282
|
var UP_PATH_REGEXP = /(?:^|[\\/])\.\.(?:[\\/]|$)/;
|
|
19283
19283
|
module2.exports = send;
|
|
19284
19284
|
module2.exports.mime = mime;
|
|
19285
|
-
function send(req,
|
|
19286
|
-
return new SendStream(req,
|
|
19285
|
+
function send(req, path18, options) {
|
|
19286
|
+
return new SendStream(req, path18, options);
|
|
19287
19287
|
}
|
|
19288
|
-
function SendStream(req,
|
|
19288
|
+
function SendStream(req, path18, options) {
|
|
19289
19289
|
Stream.call(this);
|
|
19290
19290
|
var opts = options || {};
|
|
19291
19291
|
this.options = opts;
|
|
19292
|
-
this.path =
|
|
19292
|
+
this.path = path18;
|
|
19293
19293
|
this.req = req;
|
|
19294
19294
|
this._acceptRanges = opts.acceptRanges !== void 0 ? Boolean(opts.acceptRanges) : true;
|
|
19295
19295
|
this._cacheControl = opts.cacheControl !== void 0 ? Boolean(opts.cacheControl) : true;
|
|
@@ -19335,8 +19335,8 @@ var require_send = __commonJS({
|
|
|
19335
19335
|
this._index = index2;
|
|
19336
19336
|
return this;
|
|
19337
19337
|
}, "send.index: pass index as option");
|
|
19338
|
-
SendStream.prototype.root = function root(
|
|
19339
|
-
this._root = resolve10(String(
|
|
19338
|
+
SendStream.prototype.root = function root(path18) {
|
|
19339
|
+
this._root = resolve10(String(path18));
|
|
19340
19340
|
debug("root %s", this._root);
|
|
19341
19341
|
return this;
|
|
19342
19342
|
};
|
|
@@ -19449,10 +19449,10 @@ var require_send = __commonJS({
|
|
|
19449
19449
|
var lastModified = this.res.getHeader("Last-Modified");
|
|
19450
19450
|
return parseHttpDate(lastModified) <= parseHttpDate(ifRange);
|
|
19451
19451
|
};
|
|
19452
|
-
SendStream.prototype.redirect = function redirect(
|
|
19452
|
+
SendStream.prototype.redirect = function redirect(path18) {
|
|
19453
19453
|
var res = this.res;
|
|
19454
19454
|
if (hasListeners(this, "directory")) {
|
|
19455
|
-
this.emit("directory", res,
|
|
19455
|
+
this.emit("directory", res, path18);
|
|
19456
19456
|
return;
|
|
19457
19457
|
}
|
|
19458
19458
|
if (this.hasTrailingSlash()) {
|
|
@@ -19472,42 +19472,42 @@ var require_send = __commonJS({
|
|
|
19472
19472
|
SendStream.prototype.pipe = function pipe(res) {
|
|
19473
19473
|
var root = this._root;
|
|
19474
19474
|
this.res = res;
|
|
19475
|
-
var
|
|
19476
|
-
if (
|
|
19475
|
+
var path18 = decode(this.path);
|
|
19476
|
+
if (path18 === -1) {
|
|
19477
19477
|
this.error(400);
|
|
19478
19478
|
return res;
|
|
19479
19479
|
}
|
|
19480
|
-
if (~
|
|
19480
|
+
if (~path18.indexOf("\0")) {
|
|
19481
19481
|
this.error(400);
|
|
19482
19482
|
return res;
|
|
19483
19483
|
}
|
|
19484
19484
|
var parts;
|
|
19485
19485
|
if (root !== null) {
|
|
19486
|
-
if (
|
|
19487
|
-
|
|
19486
|
+
if (path18) {
|
|
19487
|
+
path18 = normalize("." + sep3 + path18);
|
|
19488
19488
|
}
|
|
19489
|
-
if (UP_PATH_REGEXP.test(
|
|
19490
|
-
debug('malicious path "%s"',
|
|
19489
|
+
if (UP_PATH_REGEXP.test(path18)) {
|
|
19490
|
+
debug('malicious path "%s"', path18);
|
|
19491
19491
|
this.error(403);
|
|
19492
19492
|
return res;
|
|
19493
19493
|
}
|
|
19494
|
-
parts =
|
|
19495
|
-
|
|
19494
|
+
parts = path18.split(sep3);
|
|
19495
|
+
path18 = normalize(join13(root, path18));
|
|
19496
19496
|
} else {
|
|
19497
|
-
if (UP_PATH_REGEXP.test(
|
|
19498
|
-
debug('malicious path "%s"',
|
|
19497
|
+
if (UP_PATH_REGEXP.test(path18)) {
|
|
19498
|
+
debug('malicious path "%s"', path18);
|
|
19499
19499
|
this.error(403);
|
|
19500
19500
|
return res;
|
|
19501
19501
|
}
|
|
19502
|
-
parts = normalize(
|
|
19503
|
-
|
|
19502
|
+
parts = normalize(path18).split(sep3);
|
|
19503
|
+
path18 = resolve10(path18);
|
|
19504
19504
|
}
|
|
19505
19505
|
if (containsDotFile(parts)) {
|
|
19506
19506
|
var access = this._dotfiles;
|
|
19507
19507
|
if (access === void 0) {
|
|
19508
19508
|
access = parts[parts.length - 1][0] === "." ? this._hidden ? "allow" : "ignore" : "allow";
|
|
19509
19509
|
}
|
|
19510
|
-
debug('%s dotfile "%s"', access,
|
|
19510
|
+
debug('%s dotfile "%s"', access, path18);
|
|
19511
19511
|
switch (access) {
|
|
19512
19512
|
case "allow":
|
|
19513
19513
|
break;
|
|
@@ -19521,13 +19521,13 @@ var require_send = __commonJS({
|
|
|
19521
19521
|
}
|
|
19522
19522
|
}
|
|
19523
19523
|
if (this._index.length && this.hasTrailingSlash()) {
|
|
19524
|
-
this.sendIndex(
|
|
19524
|
+
this.sendIndex(path18);
|
|
19525
19525
|
return res;
|
|
19526
19526
|
}
|
|
19527
|
-
this.sendFile(
|
|
19527
|
+
this.sendFile(path18);
|
|
19528
19528
|
return res;
|
|
19529
19529
|
};
|
|
19530
|
-
SendStream.prototype.send = function send2(
|
|
19530
|
+
SendStream.prototype.send = function send2(path18, stat) {
|
|
19531
19531
|
var len = stat.size;
|
|
19532
19532
|
var options = this.options;
|
|
19533
19533
|
var opts = {};
|
|
@@ -19539,9 +19539,9 @@ var require_send = __commonJS({
|
|
|
19539
19539
|
this.headersAlreadySent();
|
|
19540
19540
|
return;
|
|
19541
19541
|
}
|
|
19542
|
-
debug('pipe "%s"',
|
|
19543
|
-
this.setHeader(
|
|
19544
|
-
this.type(
|
|
19542
|
+
debug('pipe "%s"', path18);
|
|
19543
|
+
this.setHeader(path18, stat);
|
|
19544
|
+
this.type(path18);
|
|
19545
19545
|
if (this.isConditionalGET()) {
|
|
19546
19546
|
if (this.isPreconditionFailure()) {
|
|
19547
19547
|
this.error(412);
|
|
@@ -19590,26 +19590,26 @@ var require_send = __commonJS({
|
|
|
19590
19590
|
res.end();
|
|
19591
19591
|
return;
|
|
19592
19592
|
}
|
|
19593
|
-
this.stream(
|
|
19593
|
+
this.stream(path18, opts);
|
|
19594
19594
|
};
|
|
19595
|
-
SendStream.prototype.sendFile = function sendFile(
|
|
19595
|
+
SendStream.prototype.sendFile = function sendFile(path18) {
|
|
19596
19596
|
var i = 0;
|
|
19597
19597
|
var self = this;
|
|
19598
|
-
debug('stat "%s"',
|
|
19599
|
-
fs17.stat(
|
|
19600
|
-
if (err && err.code === "ENOENT" && !extname3(
|
|
19598
|
+
debug('stat "%s"', path18);
|
|
19599
|
+
fs17.stat(path18, function onstat(err, stat) {
|
|
19600
|
+
if (err && err.code === "ENOENT" && !extname3(path18) && path18[path18.length - 1] !== sep3) {
|
|
19601
19601
|
return next(err);
|
|
19602
19602
|
}
|
|
19603
19603
|
if (err) return self.onStatError(err);
|
|
19604
|
-
if (stat.isDirectory()) return self.redirect(
|
|
19605
|
-
self.emit("file",
|
|
19606
|
-
self.send(
|
|
19604
|
+
if (stat.isDirectory()) return self.redirect(path18);
|
|
19605
|
+
self.emit("file", path18, stat);
|
|
19606
|
+
self.send(path18, stat);
|
|
19607
19607
|
});
|
|
19608
19608
|
function next(err) {
|
|
19609
19609
|
if (self._extensions.length <= i) {
|
|
19610
19610
|
return err ? self.onStatError(err) : self.error(404);
|
|
19611
19611
|
}
|
|
19612
|
-
var p =
|
|
19612
|
+
var p = path18 + "." + self._extensions[i++];
|
|
19613
19613
|
debug('stat "%s"', p);
|
|
19614
19614
|
fs17.stat(p, function(err2, stat) {
|
|
19615
19615
|
if (err2) return next(err2);
|
|
@@ -19619,7 +19619,7 @@ var require_send = __commonJS({
|
|
|
19619
19619
|
});
|
|
19620
19620
|
}
|
|
19621
19621
|
};
|
|
19622
|
-
SendStream.prototype.sendIndex = function sendIndex(
|
|
19622
|
+
SendStream.prototype.sendIndex = function sendIndex(path18) {
|
|
19623
19623
|
var i = -1;
|
|
19624
19624
|
var self = this;
|
|
19625
19625
|
function next(err) {
|
|
@@ -19627,7 +19627,7 @@ var require_send = __commonJS({
|
|
|
19627
19627
|
if (err) return self.onStatError(err);
|
|
19628
19628
|
return self.error(404);
|
|
19629
19629
|
}
|
|
19630
|
-
var p =
|
|
19630
|
+
var p = join13(path18, self._index[i]);
|
|
19631
19631
|
debug('stat "%s"', p);
|
|
19632
19632
|
fs17.stat(p, function(err2, stat) {
|
|
19633
19633
|
if (err2) return next(err2);
|
|
@@ -19638,10 +19638,10 @@ var require_send = __commonJS({
|
|
|
19638
19638
|
}
|
|
19639
19639
|
next();
|
|
19640
19640
|
};
|
|
19641
|
-
SendStream.prototype.stream = function stream(
|
|
19641
|
+
SendStream.prototype.stream = function stream(path18, options) {
|
|
19642
19642
|
var self = this;
|
|
19643
19643
|
var res = this.res;
|
|
19644
|
-
var stream2 = fs17.createReadStream(
|
|
19644
|
+
var stream2 = fs17.createReadStream(path18, options);
|
|
19645
19645
|
this.emit("stream", stream2);
|
|
19646
19646
|
stream2.pipe(res);
|
|
19647
19647
|
function cleanup() {
|
|
@@ -19656,10 +19656,10 @@ var require_send = __commonJS({
|
|
|
19656
19656
|
self.emit("end");
|
|
19657
19657
|
});
|
|
19658
19658
|
};
|
|
19659
|
-
SendStream.prototype.type = function type(
|
|
19659
|
+
SendStream.prototype.type = function type(path18) {
|
|
19660
19660
|
var res = this.res;
|
|
19661
19661
|
if (res.getHeader("Content-Type")) return;
|
|
19662
|
-
var type2 = mime.lookup(
|
|
19662
|
+
var type2 = mime.lookup(path18);
|
|
19663
19663
|
if (!type2) {
|
|
19664
19664
|
debug("no content-type");
|
|
19665
19665
|
return;
|
|
@@ -19668,9 +19668,9 @@ var require_send = __commonJS({
|
|
|
19668
19668
|
debug("content-type %s", type2);
|
|
19669
19669
|
res.setHeader("Content-Type", type2 + (charset ? "; charset=" + charset : ""));
|
|
19670
19670
|
};
|
|
19671
|
-
SendStream.prototype.setHeader = function setHeader(
|
|
19671
|
+
SendStream.prototype.setHeader = function setHeader(path18, stat) {
|
|
19672
19672
|
var res = this.res;
|
|
19673
|
-
this.emit("headers", res,
|
|
19673
|
+
this.emit("headers", res, path18, stat);
|
|
19674
19674
|
if (this._acceptRanges && !res.getHeader("Accept-Ranges")) {
|
|
19675
19675
|
debug("accept ranges");
|
|
19676
19676
|
res.setHeader("Accept-Ranges", "bytes");
|
|
@@ -19729,9 +19729,9 @@ var require_send = __commonJS({
|
|
|
19729
19729
|
}
|
|
19730
19730
|
return err instanceof Error ? createError(status, err, { expose: false }) : createError(status, err);
|
|
19731
19731
|
}
|
|
19732
|
-
function decode(
|
|
19732
|
+
function decode(path18) {
|
|
19733
19733
|
try {
|
|
19734
|
-
return decodeURIComponent(
|
|
19734
|
+
return decodeURIComponent(path18);
|
|
19735
19735
|
} catch (err) {
|
|
19736
19736
|
return -1;
|
|
19737
19737
|
}
|
|
@@ -20641,10 +20641,10 @@ var require_utils2 = __commonJS({
|
|
|
20641
20641
|
var querystring = require("querystring");
|
|
20642
20642
|
exports2.etag = createETagGenerator({ weak: false });
|
|
20643
20643
|
exports2.wetag = createETagGenerator({ weak: true });
|
|
20644
|
-
exports2.isAbsolute = function(
|
|
20645
|
-
if ("/" ===
|
|
20646
|
-
if (":" ===
|
|
20647
|
-
if ("\\\\" ===
|
|
20644
|
+
exports2.isAbsolute = function(path17) {
|
|
20645
|
+
if ("/" === path17[0]) return true;
|
|
20646
|
+
if (":" === path17[1] && ("\\" === path17[2] || "/" === path17[2])) return true;
|
|
20647
|
+
if ("\\\\" === path17.substring(0, 2)) return true;
|
|
20648
20648
|
};
|
|
20649
20649
|
exports2.flatten = deprecate.function(
|
|
20650
20650
|
flatten,
|
|
@@ -20855,7 +20855,7 @@ var require_application = __commonJS({
|
|
|
20855
20855
|
};
|
|
20856
20856
|
app.use = function use(fn) {
|
|
20857
20857
|
var offset = 0;
|
|
20858
|
-
var
|
|
20858
|
+
var path17 = "/";
|
|
20859
20859
|
if (typeof fn !== "function") {
|
|
20860
20860
|
var arg = fn;
|
|
20861
20861
|
while (Array.isArray(arg) && arg.length !== 0) {
|
|
@@ -20863,7 +20863,7 @@ var require_application = __commonJS({
|
|
|
20863
20863
|
}
|
|
20864
20864
|
if (typeof arg !== "function") {
|
|
20865
20865
|
offset = 1;
|
|
20866
|
-
|
|
20866
|
+
path17 = fn;
|
|
20867
20867
|
}
|
|
20868
20868
|
}
|
|
20869
20869
|
var fns = flatten(slice.call(arguments, offset));
|
|
@@ -20874,12 +20874,12 @@ var require_application = __commonJS({
|
|
|
20874
20874
|
var router = this._router;
|
|
20875
20875
|
fns.forEach(function(fn2) {
|
|
20876
20876
|
if (!fn2 || !fn2.handle || !fn2.set) {
|
|
20877
|
-
return router.use(
|
|
20877
|
+
return router.use(path17, fn2);
|
|
20878
20878
|
}
|
|
20879
|
-
debug(".use app under %s",
|
|
20880
|
-
fn2.mountpath =
|
|
20879
|
+
debug(".use app under %s", path17);
|
|
20880
|
+
fn2.mountpath = path17;
|
|
20881
20881
|
fn2.parent = this;
|
|
20882
|
-
router.use(
|
|
20882
|
+
router.use(path17, function mounted_app(req, res, next) {
|
|
20883
20883
|
var orig = req.app;
|
|
20884
20884
|
fn2.handle(req, res, function(err) {
|
|
20885
20885
|
setPrototypeOf(req, orig.request);
|
|
@@ -20891,9 +20891,9 @@ var require_application = __commonJS({
|
|
|
20891
20891
|
}, this);
|
|
20892
20892
|
return this;
|
|
20893
20893
|
};
|
|
20894
|
-
app.route = function route(
|
|
20894
|
+
app.route = function route(path17) {
|
|
20895
20895
|
this.lazyrouter();
|
|
20896
|
-
return this._router.route(
|
|
20896
|
+
return this._router.route(path17);
|
|
20897
20897
|
};
|
|
20898
20898
|
app.engine = function engine(ext, fn) {
|
|
20899
20899
|
if (typeof fn !== "function") {
|
|
@@ -20944,7 +20944,7 @@ var require_application = __commonJS({
|
|
|
20944
20944
|
}
|
|
20945
20945
|
return this;
|
|
20946
20946
|
};
|
|
20947
|
-
app.path = function
|
|
20947
|
+
app.path = function path17() {
|
|
20948
20948
|
return this.parent ? this.parent.path() + this.mountpath : "";
|
|
20949
20949
|
};
|
|
20950
20950
|
app.enabled = function enabled(setting) {
|
|
@@ -20960,19 +20960,19 @@ var require_application = __commonJS({
|
|
|
20960
20960
|
return this.set(setting, false);
|
|
20961
20961
|
};
|
|
20962
20962
|
methods.forEach(function(method) {
|
|
20963
|
-
app[method] = function(
|
|
20963
|
+
app[method] = function(path17) {
|
|
20964
20964
|
if (method === "get" && arguments.length === 1) {
|
|
20965
|
-
return this.set(
|
|
20965
|
+
return this.set(path17);
|
|
20966
20966
|
}
|
|
20967
20967
|
this.lazyrouter();
|
|
20968
|
-
var route = this._router.route(
|
|
20968
|
+
var route = this._router.route(path17);
|
|
20969
20969
|
route[method].apply(route, slice.call(arguments, 1));
|
|
20970
20970
|
return this;
|
|
20971
20971
|
};
|
|
20972
20972
|
});
|
|
20973
|
-
app.all = function all(
|
|
20973
|
+
app.all = function all(path17) {
|
|
20974
20974
|
this.lazyrouter();
|
|
20975
|
-
var route = this._router.route(
|
|
20975
|
+
var route = this._router.route(path17);
|
|
20976
20976
|
var args = slice.call(arguments, 1);
|
|
20977
20977
|
for (var i = 0; i < methods.length; i++) {
|
|
20978
20978
|
route[methods[i]].apply(route, args);
|
|
@@ -21731,7 +21731,7 @@ var require_request = __commonJS({
|
|
|
21731
21731
|
var subdomains2 = !isIP(hostname2) ? hostname2.split(".").reverse() : [hostname2];
|
|
21732
21732
|
return subdomains2.slice(offset);
|
|
21733
21733
|
});
|
|
21734
|
-
defineGetter(req, "path", function
|
|
21734
|
+
defineGetter(req, "path", function path17() {
|
|
21735
21735
|
return parse(this).pathname;
|
|
21736
21736
|
});
|
|
21737
21737
|
defineGetter(req, "hostname", function hostname2() {
|
|
@@ -22054,7 +22054,7 @@ var require_response = __commonJS({
|
|
|
22054
22054
|
var http2 = require("http");
|
|
22055
22055
|
var isAbsolute2 = require_utils2().isAbsolute;
|
|
22056
22056
|
var onFinished = require_on_finished();
|
|
22057
|
-
var
|
|
22057
|
+
var path17 = require("path");
|
|
22058
22058
|
var statuses = require_statuses();
|
|
22059
22059
|
var merge = require_utils_merge();
|
|
22060
22060
|
var sign = require_cookie_signature().sign;
|
|
@@ -22063,9 +22063,9 @@ var require_response = __commonJS({
|
|
|
22063
22063
|
var setCharset = require_utils2().setCharset;
|
|
22064
22064
|
var cookie = require_cookie();
|
|
22065
22065
|
var send = require_send();
|
|
22066
|
-
var extname3 =
|
|
22066
|
+
var extname3 = path17.extname;
|
|
22067
22067
|
var mime = send.mime;
|
|
22068
|
-
var resolve10 =
|
|
22068
|
+
var resolve10 = path17.resolve;
|
|
22069
22069
|
var vary = require_vary();
|
|
22070
22070
|
var res = Object.create(http2.ServerResponse.prototype);
|
|
22071
22071
|
module2.exports = res;
|
|
@@ -22242,26 +22242,26 @@ var require_response = __commonJS({
|
|
|
22242
22242
|
this.type("txt");
|
|
22243
22243
|
return this.send(body);
|
|
22244
22244
|
};
|
|
22245
|
-
res.sendFile = function sendFile(
|
|
22245
|
+
res.sendFile = function sendFile(path18, options, callback) {
|
|
22246
22246
|
var done = callback;
|
|
22247
22247
|
var req = this.req;
|
|
22248
22248
|
var res2 = this;
|
|
22249
22249
|
var next = req.next;
|
|
22250
22250
|
var opts = options || {};
|
|
22251
|
-
if (!
|
|
22251
|
+
if (!path18) {
|
|
22252
22252
|
throw new TypeError("path argument is required to res.sendFile");
|
|
22253
22253
|
}
|
|
22254
|
-
if (typeof
|
|
22254
|
+
if (typeof path18 !== "string") {
|
|
22255
22255
|
throw new TypeError("path must be a string to res.sendFile");
|
|
22256
22256
|
}
|
|
22257
22257
|
if (typeof options === "function") {
|
|
22258
22258
|
done = options;
|
|
22259
22259
|
opts = {};
|
|
22260
22260
|
}
|
|
22261
|
-
if (!opts.root && !isAbsolute2(
|
|
22261
|
+
if (!opts.root && !isAbsolute2(path18)) {
|
|
22262
22262
|
throw new TypeError("path must be absolute or specify root to res.sendFile");
|
|
22263
22263
|
}
|
|
22264
|
-
var pathname = encodeURI(
|
|
22264
|
+
var pathname = encodeURI(path18);
|
|
22265
22265
|
var file = send(req, pathname, opts);
|
|
22266
22266
|
sendfile(res2, file, opts, function(err) {
|
|
22267
22267
|
if (done) return done(err);
|
|
@@ -22271,7 +22271,7 @@ var require_response = __commonJS({
|
|
|
22271
22271
|
}
|
|
22272
22272
|
});
|
|
22273
22273
|
};
|
|
22274
|
-
res.sendfile = function(
|
|
22274
|
+
res.sendfile = function(path18, options, callback) {
|
|
22275
22275
|
var done = callback;
|
|
22276
22276
|
var req = this.req;
|
|
22277
22277
|
var res2 = this;
|
|
@@ -22281,7 +22281,7 @@ var require_response = __commonJS({
|
|
|
22281
22281
|
done = options;
|
|
22282
22282
|
opts = {};
|
|
22283
22283
|
}
|
|
22284
|
-
var file = send(req,
|
|
22284
|
+
var file = send(req, path18, opts);
|
|
22285
22285
|
sendfile(res2, file, opts, function(err) {
|
|
22286
22286
|
if (done) return done(err);
|
|
22287
22287
|
if (err && err.code === "EISDIR") return next();
|
|
@@ -22294,7 +22294,7 @@ var require_response = __commonJS({
|
|
|
22294
22294
|
res.sendfile,
|
|
22295
22295
|
"res.sendfile: Use res.sendFile instead"
|
|
22296
22296
|
);
|
|
22297
|
-
res.download = function download(
|
|
22297
|
+
res.download = function download(path18, filename, options, callback) {
|
|
22298
22298
|
var done = callback;
|
|
22299
22299
|
var name = filename;
|
|
22300
22300
|
var opts = options || null;
|
|
@@ -22311,7 +22311,7 @@ var require_response = __commonJS({
|
|
|
22311
22311
|
opts = filename;
|
|
22312
22312
|
}
|
|
22313
22313
|
var headers = {
|
|
22314
|
-
"Content-Disposition": contentDisposition(name ||
|
|
22314
|
+
"Content-Disposition": contentDisposition(name || path18)
|
|
22315
22315
|
};
|
|
22316
22316
|
if (opts && opts.headers) {
|
|
22317
22317
|
var keys = Object.keys(opts.headers);
|
|
@@ -22324,7 +22324,7 @@ var require_response = __commonJS({
|
|
|
22324
22324
|
}
|
|
22325
22325
|
opts = Object.create(opts);
|
|
22326
22326
|
opts.headers = headers;
|
|
22327
|
-
var fullPath = !opts.root ? resolve10(
|
|
22327
|
+
var fullPath = !opts.root ? resolve10(path18) : path18;
|
|
22328
22328
|
return this.sendFile(fullPath, opts, done);
|
|
22329
22329
|
};
|
|
22330
22330
|
res.contentType = res.type = function contentType(type) {
|
|
@@ -22625,11 +22625,11 @@ var require_serve_static = __commonJS({
|
|
|
22625
22625
|
}
|
|
22626
22626
|
var forwardError = !fallthrough;
|
|
22627
22627
|
var originalUrl = parseUrl.original(req);
|
|
22628
|
-
var
|
|
22629
|
-
if (
|
|
22630
|
-
|
|
22628
|
+
var path17 = parseUrl(req).pathname;
|
|
22629
|
+
if (path17 === "/" && originalUrl.pathname.substr(-1) !== "/") {
|
|
22630
|
+
path17 = "";
|
|
22631
22631
|
}
|
|
22632
|
-
var stream = send(req,
|
|
22632
|
+
var stream = send(req, path17, opts);
|
|
22633
22633
|
stream.on("directory", onDirectory);
|
|
22634
22634
|
if (setHeaders) {
|
|
22635
22635
|
stream.on("headers", setHeaders);
|
|
@@ -22771,9 +22771,12 @@ __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,
|
|
22777
|
+
ensureStartupRequirements: () => ensureStartupRequirements,
|
|
22776
22778
|
formatBanner: () => formatBanner,
|
|
22779
|
+
formatLoadedStartMetadata: () => formatLoadedStartMetadata,
|
|
22777
22780
|
getDefaultNodeName: () => getDefaultNodeName,
|
|
22778
22781
|
isDirectRunPath: () => isDirectRunPath,
|
|
22779
22782
|
loadConfigFile: () => loadConfigFile,
|
|
@@ -22781,12 +22784,14 @@ __export(main_exports, {
|
|
|
22781
22784
|
mergeConfig: () => mergeConfig,
|
|
22782
22785
|
parseArgs: () => parseArgs,
|
|
22783
22786
|
promptStartOptions: () => promptStartOptions,
|
|
22784
|
-
|
|
22787
|
+
resolveRuntimeAuthMetadata: () => resolveRuntimeAuthMetadata,
|
|
22788
|
+
resolveStartupRequirementsMetadata: () => resolveStartupRequirementsMetadata,
|
|
22789
|
+
shouldCollectStartOptions: () => shouldCollectStartOptions,
|
|
22790
|
+
shouldPromptForStartOptions: () => shouldPromptForStartOptions,
|
|
22791
|
+
shouldSkipStartupRequirementsCheck: () => shouldSkipStartupRequirementsCheck
|
|
22785
22792
|
});
|
|
22786
22793
|
module.exports = __toCommonJS(main_exports);
|
|
22787
|
-
var fs16 = __toESM(require("fs"), 1);
|
|
22788
22794
|
var nodePath = __toESM(require("path"), 1);
|
|
22789
|
-
var readline = __toESM(require("readline/promises"), 1);
|
|
22790
22795
|
|
|
22791
22796
|
// ../../packages/core/src/logger.ts
|
|
22792
22797
|
var fs = __toESM(require("fs"), 1);
|
|
@@ -22810,18 +22815,19 @@ function hourlyFolder(date) {
|
|
|
22810
22815
|
var FileWriter = class {
|
|
22811
22816
|
constructor(logDir, component, clock) {
|
|
22812
22817
|
this.logDir = logDir;
|
|
22813
|
-
this.component = component;
|
|
22814
22818
|
this.clock = clock;
|
|
22819
|
+
this.fileName = component.replace(/[/\\]/g, "-");
|
|
22815
22820
|
}
|
|
22816
22821
|
currentFolder = "";
|
|
22817
22822
|
currentStream = null;
|
|
22823
|
+
fileName;
|
|
22818
22824
|
write(chunk) {
|
|
22819
22825
|
const folder = hourlyFolder(this.clock());
|
|
22820
22826
|
if (folder !== this.currentFolder) {
|
|
22821
22827
|
this.currentStream?.end();
|
|
22822
22828
|
const dir = path.join(this.logDir, folder);
|
|
22823
22829
|
fs.mkdirSync(dir, { recursive: true });
|
|
22824
|
-
const filePath = path.join(dir, `${this.
|
|
22830
|
+
const filePath = path.join(dir, `${this.fileName}.log`);
|
|
22825
22831
|
this.currentStream = fs.createWriteStream(filePath, { flags: "a" });
|
|
22826
22832
|
this.currentFolder = folder;
|
|
22827
22833
|
}
|
|
@@ -22856,6 +22862,12 @@ var MeshyLogger = class _MeshyLogger {
|
|
|
22856
22862
|
this.log("error", msg, data);
|
|
22857
22863
|
}
|
|
22858
22864
|
child(component) {
|
|
22865
|
+
if (this.state.logDir) {
|
|
22866
|
+
const fileWriter = new FileWriter(this.state.logDir, component, this.state.clock);
|
|
22867
|
+
const writer = this.state.consoleEnabled ? new MultiWriter([process.stdout, fileWriter]) : fileWriter;
|
|
22868
|
+
const childState = { ...this.state, writer };
|
|
22869
|
+
return new _MeshyLogger(childState, component);
|
|
22870
|
+
}
|
|
22859
22871
|
return new _MeshyLogger(this.state, component);
|
|
22860
22872
|
}
|
|
22861
22873
|
log(level, msg, data) {
|
|
@@ -22912,7 +22924,9 @@ function createLogger(options = {}) {
|
|
|
22912
22924
|
level: options.level ?? "info",
|
|
22913
22925
|
nodeId: options.nodeId,
|
|
22914
22926
|
clock,
|
|
22915
|
-
writer
|
|
22927
|
+
writer,
|
|
22928
|
+
logDir: options.logDir,
|
|
22929
|
+
consoleEnabled: options.console
|
|
22916
22930
|
};
|
|
22917
22931
|
return new MeshyRootLogger(state, options.component);
|
|
22918
22932
|
}
|
|
@@ -22996,10 +23010,14 @@ function getTaskInitialMessageContent(task) {
|
|
|
22996
23010
|
return normalizeTaskUserMessageContent(task.description || task.title);
|
|
22997
23011
|
}
|
|
22998
23012
|
|
|
23013
|
+
// ../../packages/core/src/azure-cli-auth.ts
|
|
23014
|
+
var import_node_child_process = require("child_process");
|
|
23015
|
+
|
|
22999
23016
|
// ../../packages/core/src/node-metadata.ts
|
|
23000
23017
|
var fs2 = __toESM(require("fs"), 1);
|
|
23001
23018
|
var os = __toESM(require("os"), 1);
|
|
23002
23019
|
var path2 = __toESM(require("path"), 1);
|
|
23020
|
+
var STARTUP_TRANSPORTS = /* @__PURE__ */ new Set(["direct", "devtunnel", "tailscale"]);
|
|
23003
23021
|
function getDeviceNodeName() {
|
|
23004
23022
|
return os.hostname();
|
|
23005
23023
|
}
|
|
@@ -23026,8 +23044,59 @@ function writeNodeMetadata(storagePath, metadata) {
|
|
|
23026
23044
|
fs2.mkdirSync(storagePath, { recursive: true });
|
|
23027
23045
|
fs2.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2) + "\n", "utf-8");
|
|
23028
23046
|
}
|
|
23047
|
+
function normalizeAllowedUsers(allowedUsers) {
|
|
23048
|
+
if (!Array.isArray(allowedUsers)) {
|
|
23049
|
+
return [];
|
|
23050
|
+
}
|
|
23051
|
+
const unique = /* @__PURE__ */ new Set();
|
|
23052
|
+
for (const user of allowedUsers) {
|
|
23053
|
+
if (typeof user !== "string") continue;
|
|
23054
|
+
const normalized = user.trim().toLowerCase();
|
|
23055
|
+
if (normalized.length > 0) {
|
|
23056
|
+
unique.add(normalized);
|
|
23057
|
+
}
|
|
23058
|
+
}
|
|
23059
|
+
return [...unique];
|
|
23060
|
+
}
|
|
23061
|
+
function normalizeAuthMetadata(auth) {
|
|
23062
|
+
return {
|
|
23063
|
+
enabled: auth?.enabled === true,
|
|
23064
|
+
allowSameTenant: auth?.allowSameTenant === true,
|
|
23065
|
+
allowedUsers: normalizeAllowedUsers(auth?.allowedUsers)
|
|
23066
|
+
};
|
|
23067
|
+
}
|
|
23068
|
+
function normalizePositiveInteger(value) {
|
|
23069
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
|
|
23070
|
+
return void 0;
|
|
23071
|
+
}
|
|
23072
|
+
return value;
|
|
23073
|
+
}
|
|
23074
|
+
function normalizeString(value) {
|
|
23075
|
+
if (typeof value !== "string") {
|
|
23076
|
+
return void 0;
|
|
23077
|
+
}
|
|
23078
|
+
const trimmed = value.trim();
|
|
23079
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
23080
|
+
}
|
|
23081
|
+
function normalizeStartupTransport(value) {
|
|
23082
|
+
return typeof value === "string" && STARTUP_TRANSPORTS.has(value) ? value : void 0;
|
|
23083
|
+
}
|
|
23084
|
+
function normalizeStartupMetadata(startup) {
|
|
23085
|
+
return {
|
|
23086
|
+
port: normalizePositiveInteger(startup?.port),
|
|
23087
|
+
transport: normalizeStartupTransport(startup?.transport),
|
|
23088
|
+
join: normalizeString(startup?.join),
|
|
23089
|
+
workDir: normalizeString(startup?.workDir)
|
|
23090
|
+
};
|
|
23091
|
+
}
|
|
23092
|
+
function hasStartupValues(startup) {
|
|
23093
|
+
return startup.port !== void 0 || startup.transport !== void 0 || startup.join !== void 0 || startup.workDir !== void 0;
|
|
23094
|
+
}
|
|
23095
|
+
function resolvePersistedDefaultNodeName(storagePath) {
|
|
23096
|
+
return normalizeString(readNodeMetadata(storagePath).defaultNodeName);
|
|
23097
|
+
}
|
|
23029
23098
|
function resolveDefaultNodeName(storagePath, deviceName = getDeviceNodeName()) {
|
|
23030
|
-
const preferredName =
|
|
23099
|
+
const preferredName = resolvePersistedDefaultNodeName(storagePath);
|
|
23031
23100
|
return preferredName && preferredName.length > 0 ? preferredName : deviceName;
|
|
23032
23101
|
}
|
|
23033
23102
|
function persistDefaultNodeName(storagePath, name, deviceName = getDeviceNodeName()) {
|
|
@@ -23040,6 +23109,46 @@ function persistDefaultNodeName(storagePath, name, deviceName = getDeviceNodeNam
|
|
|
23040
23109
|
}
|
|
23041
23110
|
writeNodeMetadata(storagePath, metadata);
|
|
23042
23111
|
}
|
|
23112
|
+
function resolveNodeAuthMetadata(storagePath) {
|
|
23113
|
+
return normalizeAuthMetadata(readNodeMetadata(storagePath).auth);
|
|
23114
|
+
}
|
|
23115
|
+
function resolveNodeStartupMetadata(storagePath) {
|
|
23116
|
+
return normalizeStartupMetadata(readNodeMetadata(storagePath).startup);
|
|
23117
|
+
}
|
|
23118
|
+
function hasPersistedNodeStartupMetadata(storagePath) {
|
|
23119
|
+
return hasStartupValues(resolveNodeStartupMetadata(storagePath));
|
|
23120
|
+
}
|
|
23121
|
+
function persistNodeAuthMetadata(storagePath, auth) {
|
|
23122
|
+
const metadata = readNodeMetadata(storagePath);
|
|
23123
|
+
const normalized = normalizeAuthMetadata(auth);
|
|
23124
|
+
if (!normalized.enabled && !normalized.allowSameTenant && normalized.allowedUsers.length === 0) {
|
|
23125
|
+
delete metadata.auth;
|
|
23126
|
+
} else {
|
|
23127
|
+
metadata.auth = {
|
|
23128
|
+
enabled: normalized.enabled,
|
|
23129
|
+
allowSameTenant: normalized.allowSameTenant,
|
|
23130
|
+
allowedUsers: normalized.allowedUsers
|
|
23131
|
+
};
|
|
23132
|
+
}
|
|
23133
|
+
writeNodeMetadata(storagePath, metadata);
|
|
23134
|
+
}
|
|
23135
|
+
function persistNodeStartupMetadata(storagePath, startup) {
|
|
23136
|
+
const metadata = readNodeMetadata(storagePath);
|
|
23137
|
+
const normalized = normalizeStartupMetadata(startup);
|
|
23138
|
+
if (!hasStartupValues(normalized)) {
|
|
23139
|
+
delete metadata.startup;
|
|
23140
|
+
} else {
|
|
23141
|
+
metadata.startup = normalized;
|
|
23142
|
+
}
|
|
23143
|
+
writeNodeMetadata(storagePath, metadata);
|
|
23144
|
+
}
|
|
23145
|
+
function persistNodeStartupTransport(storagePath, transport) {
|
|
23146
|
+
const startup = resolveNodeStartupMetadata(storagePath);
|
|
23147
|
+
persistNodeStartupMetadata(storagePath, {
|
|
23148
|
+
...startup,
|
|
23149
|
+
transport
|
|
23150
|
+
});
|
|
23151
|
+
}
|
|
23043
23152
|
function resolvePersistedDevTunnelId(storagePath, kind) {
|
|
23044
23153
|
return readNodeMetadata(storagePath).devTunnelIds?.[kind]?.trim() || void 0;
|
|
23045
23154
|
}
|
|
@@ -23072,6 +23181,246 @@ function resolveOrCreateDevTunnelId(storagePath, nodeId, kind) {
|
|
|
23072
23181
|
return generatedId;
|
|
23073
23182
|
}
|
|
23074
23183
|
|
|
23184
|
+
// ../../packages/core/src/azure-cli-auth.ts
|
|
23185
|
+
var DEFAULT_AZ_RESOURCE = process.env.MESHY_AZ_TOKEN_RESOURCE?.trim() || "https://management.azure.com/";
|
|
23186
|
+
var TOKEN_REFRESH_SKEW_MS = 6e4;
|
|
23187
|
+
function summarizeClaims(claims) {
|
|
23188
|
+
return {
|
|
23189
|
+
tid: claims.tid,
|
|
23190
|
+
oid: claims.oid,
|
|
23191
|
+
preferred_username: claims.preferred_username,
|
|
23192
|
+
upn: claims.upn,
|
|
23193
|
+
email: claims.email,
|
|
23194
|
+
aud: claims.aud
|
|
23195
|
+
};
|
|
23196
|
+
}
|
|
23197
|
+
function decodeAzureCliJwtClaims(token) {
|
|
23198
|
+
const parts = token.split(".");
|
|
23199
|
+
if (parts.length < 2) {
|
|
23200
|
+
throw new Error("Token is not a JWT");
|
|
23201
|
+
}
|
|
23202
|
+
const payload = parts[1];
|
|
23203
|
+
if (!payload) {
|
|
23204
|
+
throw new Error("JWT payload is empty");
|
|
23205
|
+
}
|
|
23206
|
+
const normalized = payload.replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(payload.length / 4) * 4, "=");
|
|
23207
|
+
const parsed = JSON.parse(Buffer.from(normalized, "base64").toString("utf-8"));
|
|
23208
|
+
if (!parsed || typeof parsed !== "object") {
|
|
23209
|
+
throw new Error("JWT payload is not an object");
|
|
23210
|
+
}
|
|
23211
|
+
return parsed;
|
|
23212
|
+
}
|
|
23213
|
+
function normalizeIdentityValue(value) {
|
|
23214
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim().toLowerCase() : void 0;
|
|
23215
|
+
}
|
|
23216
|
+
function getIdentityValues(claims) {
|
|
23217
|
+
const values = /* @__PURE__ */ new Set();
|
|
23218
|
+
for (const candidate of [
|
|
23219
|
+
claims.oid,
|
|
23220
|
+
claims.preferred_username,
|
|
23221
|
+
claims.upn,
|
|
23222
|
+
claims.email,
|
|
23223
|
+
claims.unique_name,
|
|
23224
|
+
claims.sub
|
|
23225
|
+
]) {
|
|
23226
|
+
const normalized = normalizeIdentityValue(candidate);
|
|
23227
|
+
if (normalized) {
|
|
23228
|
+
values.add(normalized);
|
|
23229
|
+
}
|
|
23230
|
+
}
|
|
23231
|
+
return values;
|
|
23232
|
+
}
|
|
23233
|
+
function parseExpiry(value) {
|
|
23234
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
23235
|
+
return value > 1e10 ? value : value * 1e3;
|
|
23236
|
+
}
|
|
23237
|
+
if (typeof value === "string") {
|
|
23238
|
+
const trimmed = value.trim();
|
|
23239
|
+
if (trimmed.length === 0) {
|
|
23240
|
+
throw new Error("expiresOn is empty");
|
|
23241
|
+
}
|
|
23242
|
+
if (/^\d+$/.test(trimmed)) {
|
|
23243
|
+
const numeric = Number(trimmed);
|
|
23244
|
+
return numeric > 1e10 ? numeric : numeric * 1e3;
|
|
23245
|
+
}
|
|
23246
|
+
const parsed = Date.parse(trimmed);
|
|
23247
|
+
if (!Number.isNaN(parsed)) {
|
|
23248
|
+
return parsed;
|
|
23249
|
+
}
|
|
23250
|
+
}
|
|
23251
|
+
throw new Error("Unable to parse Azure CLI token expiry");
|
|
23252
|
+
}
|
|
23253
|
+
function getAzureCliCommandInvocation(command, args, platform = process.platform) {
|
|
23254
|
+
if (platform !== "win32") {
|
|
23255
|
+
return { command, args };
|
|
23256
|
+
}
|
|
23257
|
+
return {
|
|
23258
|
+
command,
|
|
23259
|
+
args,
|
|
23260
|
+
shell: true
|
|
23261
|
+
};
|
|
23262
|
+
}
|
|
23263
|
+
function defaultCommandRunner(command, args) {
|
|
23264
|
+
const invocation = getAzureCliCommandInvocation(command, args);
|
|
23265
|
+
const result = (0, import_node_child_process.spawnSync)(invocation.command, invocation.args, {
|
|
23266
|
+
encoding: "utf-8",
|
|
23267
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
23268
|
+
shell: invocation.shell
|
|
23269
|
+
});
|
|
23270
|
+
if (result.error) {
|
|
23271
|
+
throw result.error;
|
|
23272
|
+
}
|
|
23273
|
+
if (result.status !== 0) {
|
|
23274
|
+
const message = result.stderr?.trim() || `Azure CLI command exited with code ${result.status}`;
|
|
23275
|
+
throw new Error(message);
|
|
23276
|
+
}
|
|
23277
|
+
return result.stdout;
|
|
23278
|
+
}
|
|
23279
|
+
var AzureCliNodeAuth = class {
|
|
23280
|
+
constructor(storagePath, options = {}) {
|
|
23281
|
+
this.storagePath = storagePath;
|
|
23282
|
+
this.runCommand = options.commandRunner ?? defaultCommandRunner;
|
|
23283
|
+
this.log = options.logger ?? { debug() {
|
|
23284
|
+
}, info() {
|
|
23285
|
+
}, warn() {
|
|
23286
|
+
}, error() {
|
|
23287
|
+
}, child() {
|
|
23288
|
+
return this;
|
|
23289
|
+
} };
|
|
23290
|
+
this.resource = options.resource?.trim() || DEFAULT_AZ_RESOURCE;
|
|
23291
|
+
this.settingsProvider = options.settingsProvider;
|
|
23292
|
+
}
|
|
23293
|
+
runCommand;
|
|
23294
|
+
log;
|
|
23295
|
+
resource;
|
|
23296
|
+
settingsProvider;
|
|
23297
|
+
cachedToken = null;
|
|
23298
|
+
getSettings() {
|
|
23299
|
+
return this.settingsProvider?.() ?? resolveNodeAuthMetadata(this.storagePath);
|
|
23300
|
+
}
|
|
23301
|
+
isEnabled() {
|
|
23302
|
+
return this.getSettings().enabled;
|
|
23303
|
+
}
|
|
23304
|
+
getAuthorizationHeaders() {
|
|
23305
|
+
if (!this.isEnabled()) {
|
|
23306
|
+
return {};
|
|
23307
|
+
}
|
|
23308
|
+
const token = this.getAccessToken();
|
|
23309
|
+
return {
|
|
23310
|
+
authorization: `Bearer ${token.accessToken}`
|
|
23311
|
+
};
|
|
23312
|
+
}
|
|
23313
|
+
validateAuthorizationHeader(header) {
|
|
23314
|
+
if (!this.isEnabled()) {
|
|
23315
|
+
return { ok: true, reason: "disabled" };
|
|
23316
|
+
}
|
|
23317
|
+
if (typeof header !== "string") {
|
|
23318
|
+
return { ok: false, reason: "missing" };
|
|
23319
|
+
}
|
|
23320
|
+
const token = header.startsWith("Bearer ") ? header.slice("Bearer ".length).trim() : "";
|
|
23321
|
+
if (!token) {
|
|
23322
|
+
return { ok: false, reason: "missing" };
|
|
23323
|
+
}
|
|
23324
|
+
let peerClaims;
|
|
23325
|
+
try {
|
|
23326
|
+
peerClaims = decodeAzureCliJwtClaims(token);
|
|
23327
|
+
} catch {
|
|
23328
|
+
return { ok: false, reason: "invalid" };
|
|
23329
|
+
}
|
|
23330
|
+
const local = this.getAccessToken();
|
|
23331
|
+
const settings = this.getSettings();
|
|
23332
|
+
if (isPeerIdentityAllowed(peerClaims, local.claims, settings)) {
|
|
23333
|
+
return {
|
|
23334
|
+
ok: true,
|
|
23335
|
+
reason: "match",
|
|
23336
|
+
localClaims: local.claims,
|
|
23337
|
+
peerClaims
|
|
23338
|
+
};
|
|
23339
|
+
}
|
|
23340
|
+
return {
|
|
23341
|
+
ok: false,
|
|
23342
|
+
reason: "mismatch",
|
|
23343
|
+
localClaims: local.claims,
|
|
23344
|
+
peerClaims
|
|
23345
|
+
};
|
|
23346
|
+
}
|
|
23347
|
+
getAccessToken() {
|
|
23348
|
+
if (this.cachedToken && this.cachedToken.expiresAtMs - TOKEN_REFRESH_SKEW_MS > Date.now()) {
|
|
23349
|
+
this.log.debug("using cached azure cli access token", {
|
|
23350
|
+
resource: this.resource,
|
|
23351
|
+
expiresAt: new Date(this.cachedToken.expiresAtMs).toISOString(),
|
|
23352
|
+
expiresInMs: this.cachedToken.expiresAtMs - Date.now(),
|
|
23353
|
+
claims: summarizeClaims(this.cachedToken.claims)
|
|
23354
|
+
});
|
|
23355
|
+
return this.cachedToken;
|
|
23356
|
+
}
|
|
23357
|
+
this.log.info("requesting azure cli access token", {
|
|
23358
|
+
resource: this.resource,
|
|
23359
|
+
cachedTokenPresent: this.cachedToken !== null
|
|
23360
|
+
});
|
|
23361
|
+
let raw;
|
|
23362
|
+
try {
|
|
23363
|
+
raw = this.runCommand("az", [
|
|
23364
|
+
"account",
|
|
23365
|
+
"get-access-token",
|
|
23366
|
+
"--resource",
|
|
23367
|
+
this.resource,
|
|
23368
|
+
"--output",
|
|
23369
|
+
"json"
|
|
23370
|
+
]);
|
|
23371
|
+
} catch (error) {
|
|
23372
|
+
this.log.error("failed to execute az account get-access-token", {
|
|
23373
|
+
resource: this.resource,
|
|
23374
|
+
error: error instanceof Error ? error.message : String(error)
|
|
23375
|
+
});
|
|
23376
|
+
throw error;
|
|
23377
|
+
}
|
|
23378
|
+
const parsed = JSON.parse(raw);
|
|
23379
|
+
if (typeof parsed.accessToken !== "string" || parsed.accessToken.trim().length === 0) {
|
|
23380
|
+
this.log.error("azure cli token response did not include accessToken", {
|
|
23381
|
+
resource: this.resource
|
|
23382
|
+
});
|
|
23383
|
+
throw new Error("Azure CLI did not return accessToken");
|
|
23384
|
+
}
|
|
23385
|
+
const expiresAtMs = parseExpiry(parsed.expiresOn ?? parsed.expires_on);
|
|
23386
|
+
const claims = decodeAzureCliJwtClaims(parsed.accessToken);
|
|
23387
|
+
this.cachedToken = {
|
|
23388
|
+
accessToken: parsed.accessToken,
|
|
23389
|
+
expiresAtMs,
|
|
23390
|
+
claims
|
|
23391
|
+
};
|
|
23392
|
+
this.log.info("received azure cli access token", {
|
|
23393
|
+
resource: this.resource,
|
|
23394
|
+
expiresAt: new Date(expiresAtMs).toISOString(),
|
|
23395
|
+
expiresInMs: expiresAtMs - Date.now(),
|
|
23396
|
+
claims: summarizeClaims(claims)
|
|
23397
|
+
});
|
|
23398
|
+
return this.cachedToken;
|
|
23399
|
+
}
|
|
23400
|
+
};
|
|
23401
|
+
function isPeerIdentityAllowed(peerClaims, localClaims, settings) {
|
|
23402
|
+
const peerIdentities = getIdentityValues(peerClaims);
|
|
23403
|
+
const localIdentities = getIdentityValues(localClaims);
|
|
23404
|
+
for (const identity of peerIdentities) {
|
|
23405
|
+
if (localIdentities.has(identity)) {
|
|
23406
|
+
return true;
|
|
23407
|
+
}
|
|
23408
|
+
}
|
|
23409
|
+
for (const allowedUser of settings.allowedUsers) {
|
|
23410
|
+
if (peerIdentities.has(allowedUser)) {
|
|
23411
|
+
return true;
|
|
23412
|
+
}
|
|
23413
|
+
}
|
|
23414
|
+
if (settings.allowSameTenant) {
|
|
23415
|
+
const peerTenant = normalizeIdentityValue(peerClaims.tid);
|
|
23416
|
+
const localTenant = normalizeIdentityValue(localClaims.tid);
|
|
23417
|
+
if (peerTenant && localTenant && peerTenant === localTenant) {
|
|
23418
|
+
return true;
|
|
23419
|
+
}
|
|
23420
|
+
}
|
|
23421
|
+
return false;
|
|
23422
|
+
}
|
|
23423
|
+
|
|
23075
23424
|
// ../../packages/core/src/file-store.ts
|
|
23076
23425
|
var fs3 = __toESM(require("fs"), 1);
|
|
23077
23426
|
var path3 = __toESM(require("path"), 1);
|
|
@@ -23516,6 +23865,7 @@ function parseNodeInfo(value) {
|
|
|
23516
23865
|
lastHeartbeat: value.lastHeartbeat,
|
|
23517
23866
|
transportType: typeof value.transportType === "string" ? value.transportType : void 0,
|
|
23518
23867
|
devtunnelEndpoint: typeof value.devtunnelEndpoint === "string" ? value.devtunnelEndpoint : void 0,
|
|
23868
|
+
dashboardOrigin: typeof value.dashboardOrigin === "string" ? value.dashboardOrigin : void 0,
|
|
23519
23869
|
previewOrigin: typeof value.previewOrigin === "string" ? value.previewOrigin : void 0
|
|
23520
23870
|
};
|
|
23521
23871
|
}
|
|
@@ -23595,6 +23945,38 @@ var EventBus = class {
|
|
|
23595
23945
|
}
|
|
23596
23946
|
};
|
|
23597
23947
|
|
|
23948
|
+
// ../../packages/core/src/request-auth.ts
|
|
23949
|
+
var requestAuthHeadersProvider = null;
|
|
23950
|
+
function normalizeHeaders(headers) {
|
|
23951
|
+
if (!headers) {
|
|
23952
|
+
return {};
|
|
23953
|
+
}
|
|
23954
|
+
if (headers instanceof Headers) {
|
|
23955
|
+
return Object.fromEntries(headers.entries());
|
|
23956
|
+
}
|
|
23957
|
+
if (Array.isArray(headers)) {
|
|
23958
|
+
return Object.fromEntries(headers);
|
|
23959
|
+
}
|
|
23960
|
+
return Object.fromEntries(
|
|
23961
|
+
Object.entries(headers).flatMap(
|
|
23962
|
+
([key, value]) => value === void 0 ? [] : [[key, String(value)]]
|
|
23963
|
+
)
|
|
23964
|
+
);
|
|
23965
|
+
}
|
|
23966
|
+
function setRequestAuthHeadersProvider(provider) {
|
|
23967
|
+
requestAuthHeadersProvider = provider;
|
|
23968
|
+
}
|
|
23969
|
+
function applyRequestAuthHeaders(init = {}) {
|
|
23970
|
+
const headers = normalizeHeaders(init.headers);
|
|
23971
|
+
if (!Object.keys(headers).some((key) => key.toLowerCase() === "authorization") && requestAuthHeadersProvider) {
|
|
23972
|
+
Object.assign(headers, requestAuthHeadersProvider());
|
|
23973
|
+
}
|
|
23974
|
+
return {
|
|
23975
|
+
...init,
|
|
23976
|
+
headers
|
|
23977
|
+
};
|
|
23978
|
+
}
|
|
23979
|
+
|
|
23598
23980
|
// ../../packages/core/src/node-endpoints.ts
|
|
23599
23981
|
var DEFAULT_NODE_REQUEST_TIMEOUT_MS = 1500;
|
|
23600
23982
|
function getNodePublicEndpoint(node) {
|
|
@@ -23623,22 +24005,27 @@ function createRequestSignal(signal, timeoutMs) {
|
|
|
23623
24005
|
async function fetchWithTimeout(url, init, timeoutMs = DEFAULT_NODE_REQUEST_TIMEOUT_MS) {
|
|
23624
24006
|
const { cleanup, signal } = createRequestSignal(init?.signal, timeoutMs);
|
|
23625
24007
|
try {
|
|
23626
|
-
return await fetch(url, {
|
|
24008
|
+
return await fetch(url, applyRequestAuthHeaders({
|
|
23627
24009
|
...init,
|
|
23628
24010
|
signal
|
|
23629
|
-
});
|
|
24011
|
+
}));
|
|
23630
24012
|
} finally {
|
|
23631
24013
|
cleanup();
|
|
23632
24014
|
}
|
|
23633
24015
|
}
|
|
23634
|
-
async function fetchNodeWithFallback(node,
|
|
24016
|
+
async function fetchNodeWithFallback(node, path17, init, timeoutMs = DEFAULT_NODE_REQUEST_TIMEOUT_MS, trace) {
|
|
23635
24017
|
let lastError;
|
|
23636
|
-
|
|
24018
|
+
const endpoints = getNodeRequestEndpoints(node);
|
|
24019
|
+
for (const [index, endpoint] of endpoints.entries()) {
|
|
24020
|
+
const attempt = index + 1;
|
|
24021
|
+
trace?.onAttempt?.({ attempt, endpoint, path: path17, timeoutMs, totalEndpoints: endpoints.length });
|
|
23637
24022
|
try {
|
|
23638
|
-
const response = await fetchWithTimeout(`${endpoint}${
|
|
24023
|
+
const response = await fetchWithTimeout(`${endpoint}${path17}`, init, timeoutMs);
|
|
24024
|
+
trace?.onResponse?.({ attempt, endpoint, path: path17, response, timeoutMs, totalEndpoints: endpoints.length });
|
|
23639
24025
|
return { endpoint, response };
|
|
23640
24026
|
} catch (error) {
|
|
23641
24027
|
lastError = error;
|
|
24028
|
+
trace?.onError?.({ attempt, endpoint, error, path: path17, timeoutMs, totalEndpoints: endpoints.length });
|
|
23642
24029
|
}
|
|
23643
24030
|
}
|
|
23644
24031
|
throw lastError instanceof Error ? lastError : new Error("No reachable node endpoint");
|
|
@@ -23746,6 +24133,24 @@ var NodeRegistry = class {
|
|
|
23746
24133
|
}
|
|
23747
24134
|
}
|
|
23748
24135
|
}
|
|
24136
|
+
updateDashboardOrigin(id, dashboardOrigin) {
|
|
24137
|
+
const node = this.nodes.get(id);
|
|
24138
|
+
if (node) {
|
|
24139
|
+
if (dashboardOrigin) {
|
|
24140
|
+
node.dashboardOrigin = dashboardOrigin;
|
|
24141
|
+
} else {
|
|
24142
|
+
delete node.dashboardOrigin;
|
|
24143
|
+
}
|
|
24144
|
+
this.store.upsertNode(node);
|
|
24145
|
+
}
|
|
24146
|
+
if (this.selfNode && this.selfNode.id === id) {
|
|
24147
|
+
if (dashboardOrigin) {
|
|
24148
|
+
this.selfNode.dashboardOrigin = dashboardOrigin;
|
|
24149
|
+
} else {
|
|
24150
|
+
delete this.selfNode.dashboardOrigin;
|
|
24151
|
+
}
|
|
24152
|
+
}
|
|
24153
|
+
}
|
|
23749
24154
|
updatePreviewOrigin(id, previewOrigin) {
|
|
23750
24155
|
const node = this.nodes.get(id);
|
|
23751
24156
|
if (node) {
|
|
@@ -23935,15 +24340,18 @@ var LeaderElection = class {
|
|
|
23935
24340
|
if (announce.term < this.currentTerm) {
|
|
23936
24341
|
return;
|
|
23937
24342
|
}
|
|
23938
|
-
|
|
23939
|
-
|
|
23940
|
-
|
|
23941
|
-
|
|
23942
|
-
|
|
23943
|
-
|
|
23944
|
-
|
|
23945
|
-
|
|
23946
|
-
|
|
24343
|
+
this.adoptLeader(announce);
|
|
24344
|
+
}
|
|
24345
|
+
/**
|
|
24346
|
+
* Explicit cluster joins are operator-driven reconfiguration, not normal
|
|
24347
|
+
* election traffic. Force the local node to follow the joined leader even
|
|
24348
|
+
* if this node previously incremented its term while detached.
|
|
24349
|
+
*/
|
|
24350
|
+
adoptLeaderFromJoin(announce) {
|
|
24351
|
+
this.currentTerm = announce.term;
|
|
24352
|
+
this.votedForTerm = announce.term;
|
|
24353
|
+
this.votedForCandidate = announce.leaderId;
|
|
24354
|
+
this.adoptLeader(announce);
|
|
23947
24355
|
}
|
|
23948
24356
|
// ── Leader Lease ─────────────────────────────────────────────────────
|
|
23949
24357
|
isLeader() {
|
|
@@ -23955,6 +24363,18 @@ var LeaderElection = class {
|
|
|
23955
24363
|
stepDown() {
|
|
23956
24364
|
this.leader = false;
|
|
23957
24365
|
}
|
|
24366
|
+
/**
|
|
24367
|
+
* Adopt local leadership without running an election.
|
|
24368
|
+
* Used when a follower explicitly detaches from a leader and becomes
|
|
24369
|
+
* a solo node immediately.
|
|
24370
|
+
*/
|
|
24371
|
+
assumeLeadership() {
|
|
24372
|
+
const self = this.nodeRegistry.getSelf();
|
|
24373
|
+
this.currentTerm = Math.max(this.currentTerm, 1);
|
|
24374
|
+
this.votedForTerm = this.currentTerm;
|
|
24375
|
+
this.votedForCandidate = self.id;
|
|
24376
|
+
this.becomeLeader();
|
|
24377
|
+
}
|
|
23958
24378
|
/** Manually promote this node to leader. */
|
|
23959
24379
|
async promote() {
|
|
23960
24380
|
const self = this.nodeRegistry.getSelf();
|
|
@@ -23992,6 +24412,15 @@ var LeaderElection = class {
|
|
|
23992
24412
|
term: this.currentTerm
|
|
23993
24413
|
});
|
|
23994
24414
|
}
|
|
24415
|
+
adoptLeader(announce) {
|
|
24416
|
+
this.currentTerm = announce.term;
|
|
24417
|
+
this.leader = false;
|
|
24418
|
+
this.nodeRegistry.setLeader(announce.leaderId, announce.term);
|
|
24419
|
+
this.eventBus.emit("election.complete", {
|
|
24420
|
+
leaderId: announce.leaderId,
|
|
24421
|
+
term: announce.term
|
|
24422
|
+
});
|
|
24423
|
+
}
|
|
23995
24424
|
async broadcastAnnounce(leaderId, term) {
|
|
23996
24425
|
const self = this.nodeRegistry.getSelf();
|
|
23997
24426
|
const onlineNodes = this.nodeRegistry.getOnlineNodes().filter(
|
|
@@ -24000,11 +24429,11 @@ var LeaderElection = class {
|
|
|
24000
24429
|
const announcePromises = onlineNodes.map(async (node) => {
|
|
24001
24430
|
try {
|
|
24002
24431
|
const endpoint = getNodePublicEndpoint(node);
|
|
24003
|
-
await fetch(`${endpoint}/api/worker/announce`, {
|
|
24432
|
+
await fetch(`${endpoint}/api/worker/announce`, applyRequestAuthHeaders({
|
|
24004
24433
|
method: "POST",
|
|
24005
24434
|
headers: { "Content-Type": "application/json" },
|
|
24006
24435
|
body: JSON.stringify({ leaderId, term })
|
|
24007
|
-
});
|
|
24436
|
+
}));
|
|
24008
24437
|
} catch {
|
|
24009
24438
|
}
|
|
24010
24439
|
});
|
|
@@ -24593,6 +25022,12 @@ function listWorkDirFolders(workDir) {
|
|
|
24593
25022
|
|
|
24594
25023
|
// ../../packages/core/src/heartbeat.ts
|
|
24595
25024
|
var MISSED_HEARTBEAT_THRESHOLD = 3;
|
|
25025
|
+
function formatError(error) {
|
|
25026
|
+
return error instanceof Error ? error.message : String(error);
|
|
25027
|
+
}
|
|
25028
|
+
function truncateForLog(value, max = 240) {
|
|
25029
|
+
return !value || value.length <= max ? value : `${value.slice(0, max - 3)}...`;
|
|
25030
|
+
}
|
|
24596
25031
|
var HeartbeatMonitor = class {
|
|
24597
25032
|
constructor(nodeRegistry, election, eventBus, config, logger) {
|
|
24598
25033
|
this.nodeRegistry = nodeRegistry;
|
|
@@ -24770,10 +25205,40 @@ var HeartbeatMonitor = class {
|
|
|
24770
25205
|
};
|
|
24771
25206
|
const promises2 = followers.map(async (node) => {
|
|
24772
25207
|
try {
|
|
24773
|
-
const { response } = await fetchNodeWithFallback(node, "/api/worker/heartbeat", {
|
|
25208
|
+
const { endpoint, response } = await fetchNodeWithFallback(node, "/api/worker/heartbeat", {
|
|
24774
25209
|
method: "POST",
|
|
24775
25210
|
headers: { "Content-Type": "application/json" },
|
|
24776
25211
|
body: JSON.stringify(request)
|
|
25212
|
+
}, void 0, {
|
|
25213
|
+
onAttempt: ({ attempt, endpoint: targetEndpoint, totalEndpoints, timeoutMs }) => {
|
|
25214
|
+
this.log.info("sending heartbeat request", {
|
|
25215
|
+
nodeId: node.id,
|
|
25216
|
+
endpoint: targetEndpoint,
|
|
25217
|
+
attempt,
|
|
25218
|
+
totalEndpoints,
|
|
25219
|
+
timeoutMs,
|
|
25220
|
+
term: request.term
|
|
25221
|
+
});
|
|
25222
|
+
},
|
|
25223
|
+
onError: ({ attempt, endpoint: targetEndpoint, error, totalEndpoints }) => {
|
|
25224
|
+
this.log.warn("heartbeat request attempt failed", {
|
|
25225
|
+
nodeId: node.id,
|
|
25226
|
+
endpoint: targetEndpoint,
|
|
25227
|
+
attempt,
|
|
25228
|
+
totalEndpoints,
|
|
25229
|
+
error: formatError(error)
|
|
25230
|
+
});
|
|
25231
|
+
},
|
|
25232
|
+
onResponse: ({ attempt, endpoint: targetEndpoint, response: heartbeatResponse, totalEndpoints }) => {
|
|
25233
|
+
this.log.info("heartbeat response received", {
|
|
25234
|
+
nodeId: node.id,
|
|
25235
|
+
endpoint: targetEndpoint,
|
|
25236
|
+
attempt,
|
|
25237
|
+
totalEndpoints,
|
|
25238
|
+
ok: heartbeatResponse.ok,
|
|
25239
|
+
statusCode: heartbeatResponse.status
|
|
25240
|
+
});
|
|
25241
|
+
}
|
|
24777
25242
|
});
|
|
24778
25243
|
if (response.ok) {
|
|
24779
25244
|
const result = await response.json();
|
|
@@ -24782,6 +25247,7 @@ var HeartbeatMonitor = class {
|
|
|
24782
25247
|
this.nodeRegistry.updateHeartbeat(node.id, Date.now());
|
|
24783
25248
|
this.nodeRegistry.updateLoad(node.id, result.load);
|
|
24784
25249
|
this.applyReportedDevTunnelState(node.id, result.devtunnelEnabled, result.devtunnelEndpoint);
|
|
25250
|
+
this.nodeRegistry.updateDashboardOrigin(node.id, result.dashboardOrigin);
|
|
24785
25251
|
this.nodeRegistry.updatePreviewOrigin(node.id, result.previewOrigin);
|
|
24786
25252
|
if (result.workDirFolders) {
|
|
24787
25253
|
this.nodeRegistry.updateFolders(node.id, result.workDirFolders);
|
|
@@ -24789,11 +25255,27 @@ var HeartbeatMonitor = class {
|
|
|
24789
25255
|
if (result.status !== node.status) {
|
|
24790
25256
|
this.nodeRegistry.updateStatus(node.id, result.status);
|
|
24791
25257
|
}
|
|
25258
|
+
this.log.info("heartbeat response applied", {
|
|
25259
|
+
nodeId: node.id,
|
|
25260
|
+
endpoint,
|
|
25261
|
+
reportedStatus: result.status,
|
|
25262
|
+
load: result.load,
|
|
25263
|
+
workDirFolders: result.workDirFolders?.length ?? 0
|
|
25264
|
+
});
|
|
24792
25265
|
return;
|
|
24793
25266
|
}
|
|
24794
|
-
|
|
24795
|
-
|
|
24796
|
-
|
|
25267
|
+
const body = truncateForLog(await response.text().catch(() => void 0));
|
|
25268
|
+
this.recordFollowerMiss(node, {
|
|
25269
|
+
endpoint,
|
|
25270
|
+
reason: "non-ok heartbeat response",
|
|
25271
|
+
statusCode: response.status,
|
|
25272
|
+
body
|
|
25273
|
+
});
|
|
25274
|
+
} catch (error) {
|
|
25275
|
+
this.recordFollowerMiss(node, {
|
|
25276
|
+
reason: "heartbeat request threw",
|
|
25277
|
+
error: formatError(error)
|
|
25278
|
+
});
|
|
24797
25279
|
}
|
|
24798
25280
|
});
|
|
24799
25281
|
await Promise.all(promises2);
|
|
@@ -24817,7 +25299,7 @@ var HeartbeatMonitor = class {
|
|
|
24817
25299
|
term: req.term,
|
|
24818
25300
|
nodeCount: req.clusterState.nodes.length
|
|
24819
25301
|
});
|
|
24820
|
-
|
|
25302
|
+
const response = {
|
|
24821
25303
|
nodeId: self.id,
|
|
24822
25304
|
status: self.status,
|
|
24823
25305
|
runningTasks: [],
|
|
@@ -24825,9 +25307,11 @@ var HeartbeatMonitor = class {
|
|
|
24825
25307
|
load: 0,
|
|
24826
25308
|
devtunnelEnabled: self.devtunnelEndpoint !== void 0,
|
|
24827
25309
|
devtunnelEndpoint: self.devtunnelEndpoint,
|
|
25310
|
+
dashboardOrigin: self.dashboardOrigin,
|
|
24828
25311
|
previewOrigin: self.previewOrigin,
|
|
24829
25312
|
workDirFolders: self.workDir ? listWorkDirFolders(self.workDir) : void 0
|
|
24830
25313
|
};
|
|
25314
|
+
return response;
|
|
24831
25315
|
}
|
|
24832
25316
|
// ── Leader: handle keepalive from follower ──────────────────────────
|
|
24833
25317
|
handleKeepalive(req) {
|
|
@@ -24842,6 +25326,7 @@ var HeartbeatMonitor = class {
|
|
|
24842
25326
|
workDir,
|
|
24843
25327
|
devtunnelEnabled,
|
|
24844
25328
|
devtunnelEndpoint,
|
|
25329
|
+
dashboardOrigin,
|
|
24845
25330
|
previewOrigin,
|
|
24846
25331
|
workDirFolders
|
|
24847
25332
|
} = req;
|
|
@@ -24850,7 +25335,6 @@ var HeartbeatMonitor = class {
|
|
|
24850
25335
|
const normalizedEndpoint = endpoint ?? existingNode?.endpoint ?? devtunnelEndpoint ?? "";
|
|
24851
25336
|
const normalizedCapabilities = capabilities ?? existingNode?.capabilities ?? [];
|
|
24852
25337
|
const currentCapabilities = existingNode?.capabilities ?? [];
|
|
24853
|
-
this.log.debug("keepalive received", { nodeId, status });
|
|
24854
25338
|
this.followerMissedMap.set(nodeId, 0);
|
|
24855
25339
|
let node = existingNode;
|
|
24856
25340
|
const now = Date.now();
|
|
@@ -24867,6 +25351,7 @@ var HeartbeatMonitor = class {
|
|
|
24867
25351
|
...transportType ? { transportType } : {},
|
|
24868
25352
|
...workDir ? { workDir } : {},
|
|
24869
25353
|
...devtunnelEnabled && devtunnelEndpoint ? { devtunnelEndpoint } : {},
|
|
25354
|
+
...dashboardOrigin ? { dashboardOrigin } : {},
|
|
24870
25355
|
...previewOrigin ? { previewOrigin } : {},
|
|
24871
25356
|
...workDirFolders ? { workDirFolders } : {}
|
|
24872
25357
|
});
|
|
@@ -24900,6 +25385,7 @@ var HeartbeatMonitor = class {
|
|
|
24900
25385
|
}
|
|
24901
25386
|
this.nodeRegistry.updateLoad(nodeId, load);
|
|
24902
25387
|
this.applyReportedDevTunnelState(nodeId, devtunnelEnabled, devtunnelEndpoint);
|
|
25388
|
+
this.nodeRegistry.updateDashboardOrigin(nodeId, dashboardOrigin);
|
|
24903
25389
|
this.nodeRegistry.updatePreviewOrigin(nodeId, previewOrigin);
|
|
24904
25390
|
if (workDirFolders) {
|
|
24905
25391
|
this.nodeRegistry.updateFolders(nodeId, workDirFolders);
|
|
@@ -24915,7 +25401,7 @@ var HeartbeatMonitor = class {
|
|
|
24915
25401
|
if (controlRequests.length > 0) {
|
|
24916
25402
|
this.queuedControlRequests.delete(nodeId);
|
|
24917
25403
|
}
|
|
24918
|
-
|
|
25404
|
+
const response = {
|
|
24919
25405
|
leaderId: self.id,
|
|
24920
25406
|
term: this.election.getCurrentTerm(),
|
|
24921
25407
|
timestamp: Date.now(),
|
|
@@ -24927,6 +25413,7 @@ var HeartbeatMonitor = class {
|
|
|
24927
25413
|
followUpMessages: followUpMessages.length > 0 ? followUpMessages : void 0,
|
|
24928
25414
|
controlRequests: controlRequests.length > 0 ? controlRequests : void 0
|
|
24929
25415
|
};
|
|
25416
|
+
return response;
|
|
24930
25417
|
}
|
|
24931
25418
|
// ── Follower: send keepalive to leader ──────────────────────────────
|
|
24932
25419
|
async sendKeepalive() {
|
|
@@ -24947,18 +25434,33 @@ var HeartbeatMonitor = class {
|
|
|
24947
25434
|
workDir: self.workDir,
|
|
24948
25435
|
devtunnelEnabled: self.devtunnelEndpoint !== void 0,
|
|
24949
25436
|
devtunnelEndpoint: self.devtunnelEndpoint,
|
|
25437
|
+
dashboardOrigin: self.dashboardOrigin,
|
|
24950
25438
|
previewOrigin: self.previewOrigin,
|
|
24951
25439
|
workDirFolders: self.workDir ? listWorkDirFolders(self.workDir) : void 0
|
|
24952
25440
|
};
|
|
25441
|
+
this.log.info("sending keepalive request", {
|
|
25442
|
+
nodeId: self.id,
|
|
25443
|
+
leaderEndpoint,
|
|
25444
|
+
status: self.status,
|
|
25445
|
+
workDirFolders: request.workDirFolders?.length ?? 0,
|
|
25446
|
+
devtunnelEnabled: request.devtunnelEnabled
|
|
25447
|
+
});
|
|
24953
25448
|
try {
|
|
24954
|
-
const response = await fetch(`${leaderEndpoint}/api/worker/keepalive`, {
|
|
25449
|
+
const response = await fetch(`${leaderEndpoint}/api/worker/keepalive`, applyRequestAuthHeaders({
|
|
24955
25450
|
method: "POST",
|
|
24956
25451
|
headers: { "Content-Type": "application/json" },
|
|
24957
25452
|
body: JSON.stringify(request)
|
|
24958
|
-
});
|
|
25453
|
+
}));
|
|
24959
25454
|
if (response.ok) {
|
|
24960
25455
|
const result = await response.json();
|
|
24961
|
-
this.log.
|
|
25456
|
+
this.log.info("keepalive response received", {
|
|
25457
|
+
leaderId: result.leaderId,
|
|
25458
|
+
term: result.term,
|
|
25459
|
+
nodeCount: result.clusterState.nodes.length,
|
|
25460
|
+
dispatchedTaskCount: result.dispatchedTasks?.length ?? 0,
|
|
25461
|
+
followUpCount: result.followUpMessages?.length ?? 0,
|
|
25462
|
+
controlRequestCount: result.controlRequests?.length ?? 0
|
|
25463
|
+
});
|
|
24962
25464
|
this.lastHeartbeatTime = Date.now();
|
|
24963
25465
|
this.missedCount = 0;
|
|
24964
25466
|
this.nodeRegistry.setLeader(result.leaderId, result.term);
|
|
@@ -24988,10 +25490,17 @@ var HeartbeatMonitor = class {
|
|
|
24988
25490
|
));
|
|
24989
25491
|
}
|
|
24990
25492
|
} else {
|
|
24991
|
-
this.log.warn("keepalive
|
|
25493
|
+
this.log.warn("keepalive request returned non-ok response", {
|
|
25494
|
+
leaderEndpoint,
|
|
25495
|
+
statusCode: response.status,
|
|
25496
|
+
body: truncateForLog(await response.text().catch(() => void 0))
|
|
25497
|
+
});
|
|
24992
25498
|
}
|
|
24993
25499
|
} catch (err) {
|
|
24994
|
-
this.log.warn("keepalive
|
|
25500
|
+
this.log.warn("keepalive request failed", {
|
|
25501
|
+
leaderEndpoint,
|
|
25502
|
+
error: formatError(err)
|
|
25503
|
+
});
|
|
24995
25504
|
}
|
|
24996
25505
|
}
|
|
24997
25506
|
// ── Accessors ───────────────────────────────────────────────────────
|
|
@@ -25004,13 +25513,30 @@ var HeartbeatMonitor = class {
|
|
|
25004
25513
|
canPushToNode(nodeId) {
|
|
25005
25514
|
const node = this.nodeRegistry.getNode(nodeId);
|
|
25006
25515
|
if (!node) return false;
|
|
25007
|
-
if (node.
|
|
25008
|
-
return
|
|
25516
|
+
if (node.status === "offline") return false;
|
|
25517
|
+
return !!(node.devtunnelEndpoint || node.endpoint);
|
|
25009
25518
|
}
|
|
25010
25519
|
// ── Private helpers ─────────────────────────────────────────────────
|
|
25011
25520
|
startLeaderMode() {
|
|
25012
25521
|
this.heartbeatTimer = setInterval(() => {
|
|
25013
|
-
|
|
25522
|
+
const self = this.nodeRegistry.getSelf();
|
|
25523
|
+
if (self.workDir) {
|
|
25524
|
+
this.nodeRegistry.updateFolders(self.id, listWorkDirFolders(self.workDir));
|
|
25525
|
+
}
|
|
25526
|
+
const now = Date.now();
|
|
25527
|
+
const followers = this.nodeRegistry.getAllNodes().filter((node) => node.id !== self.id);
|
|
25528
|
+
for (const node of followers) {
|
|
25529
|
+
if (node.status === "offline") continue;
|
|
25530
|
+
const elapsed = now - node.lastHeartbeat;
|
|
25531
|
+
if (elapsed >= this.config.electionTimeout) {
|
|
25532
|
+
this.log.warn("marking node offline from stale follower keepalive", {
|
|
25533
|
+
nodeId: node.id,
|
|
25534
|
+
lastHeartbeat: node.lastHeartbeat,
|
|
25535
|
+
elapsed
|
|
25536
|
+
});
|
|
25537
|
+
this.nodeRegistry.updateStatus(node.id, "offline");
|
|
25538
|
+
}
|
|
25539
|
+
}
|
|
25014
25540
|
}, this.config.heartbeatInterval);
|
|
25015
25541
|
}
|
|
25016
25542
|
startFollowerMode() {
|
|
@@ -25044,10 +25570,21 @@ var HeartbeatMonitor = class {
|
|
|
25044
25570
|
}
|
|
25045
25571
|
}, this.config.electionTimeout);
|
|
25046
25572
|
}
|
|
25047
|
-
recordFollowerMiss(node) {
|
|
25573
|
+
recordFollowerMiss(node, details) {
|
|
25048
25574
|
const current = this.followerMissedMap.get(node.id) ?? 0;
|
|
25049
25575
|
const newCount = current + 1;
|
|
25050
25576
|
this.followerMissedMap.set(node.id, newCount);
|
|
25577
|
+
const everReached = this.followerEverReachedMap.get(node.id) ?? false;
|
|
25578
|
+
this.log.warn("recorded heartbeat miss", {
|
|
25579
|
+
nodeId: node.id,
|
|
25580
|
+
misses: newCount,
|
|
25581
|
+
everReached,
|
|
25582
|
+
endpoint: details.endpoint,
|
|
25583
|
+
statusCode: details.statusCode,
|
|
25584
|
+
reason: details.reason,
|
|
25585
|
+
error: details.error,
|
|
25586
|
+
body: details.body
|
|
25587
|
+
});
|
|
25051
25588
|
if (newCount >= MISSED_HEARTBEAT_THRESHOLD) {
|
|
25052
25589
|
const freshNode = this.nodeRegistry.getNode(node.id);
|
|
25053
25590
|
if (freshNode) {
|
|
@@ -25056,13 +25593,20 @@ var HeartbeatMonitor = class {
|
|
|
25056
25593
|
this.log.debug("miss threshold but lastHeartbeat recent \u2014 skip offline", {
|
|
25057
25594
|
nodeId: node.id,
|
|
25058
25595
|
elapsed,
|
|
25059
|
-
everReached
|
|
25596
|
+
everReached
|
|
25060
25597
|
});
|
|
25061
25598
|
return;
|
|
25062
25599
|
}
|
|
25063
25600
|
}
|
|
25064
|
-
|
|
25065
|
-
|
|
25601
|
+
this.log.warn("marking node offline", {
|
|
25602
|
+
nodeId: node.id,
|
|
25603
|
+
everReached,
|
|
25604
|
+
misses: newCount,
|
|
25605
|
+
endpoint: details.endpoint,
|
|
25606
|
+
statusCode: details.statusCode,
|
|
25607
|
+
reason: details.reason,
|
|
25608
|
+
error: details.error
|
|
25609
|
+
});
|
|
25066
25610
|
this.nodeRegistry.updateStatus(node.id, "offline");
|
|
25067
25611
|
}
|
|
25068
25612
|
}
|
|
@@ -25125,11 +25669,11 @@ var HeartbeatMonitor = class {
|
|
|
25125
25669
|
}
|
|
25126
25670
|
}
|
|
25127
25671
|
try {
|
|
25128
|
-
const res = await fetch(`${leaderEndpoint}/api/worker/control-response`, {
|
|
25672
|
+
const res = await fetch(`${leaderEndpoint}/api/worker/control-response`, applyRequestAuthHeaders({
|
|
25129
25673
|
method: "POST",
|
|
25130
25674
|
headers: { "Content-Type": "application/json" },
|
|
25131
25675
|
body: JSON.stringify(response)
|
|
25132
|
-
});
|
|
25676
|
+
}));
|
|
25133
25677
|
if (!res.ok) {
|
|
25134
25678
|
this.log.warn("leader rejected control response", {
|
|
25135
25679
|
requestId: request.requestId,
|
|
@@ -25174,9 +25718,9 @@ var DataRouter = class {
|
|
|
25174
25718
|
/**
|
|
25175
25719
|
* Returns true if the request should be proxied to the leader.
|
|
25176
25720
|
*/
|
|
25177
|
-
shouldProxy(method,
|
|
25721
|
+
shouldProxy(method, path17) {
|
|
25178
25722
|
if (this.election.isLeader()) return false;
|
|
25179
|
-
if (this.isExcludedPath(
|
|
25723
|
+
if (this.isExcludedPath(path17)) return false;
|
|
25180
25724
|
if (method.toUpperCase() === "GET") return false;
|
|
25181
25725
|
return WRITE_METHODS.has(method.toUpperCase());
|
|
25182
25726
|
}
|
|
@@ -25219,12 +25763,12 @@ var DataRouter = class {
|
|
|
25219
25763
|
const controller = new AbortController();
|
|
25220
25764
|
const timeoutId = setTimeout(() => controller.abort(), this.config.proxyTimeout);
|
|
25221
25765
|
try {
|
|
25222
|
-
const response = await fetch(targetUrl, {
|
|
25766
|
+
const response = await fetch(targetUrl, applyRequestAuthHeaders({
|
|
25223
25767
|
method,
|
|
25224
25768
|
headers: forwardHeaders,
|
|
25225
25769
|
body,
|
|
25226
25770
|
signal: controller.signal
|
|
25227
|
-
});
|
|
25771
|
+
}));
|
|
25228
25772
|
const responseHeaders = {};
|
|
25229
25773
|
response.headers.forEach((value, key) => {
|
|
25230
25774
|
responseHeaders[key] = value;
|
|
@@ -25277,8 +25821,8 @@ var DataRouter = class {
|
|
|
25277
25821
|
};
|
|
25278
25822
|
}
|
|
25279
25823
|
// ── Helpers ───────────────────────────────────────────────────────────
|
|
25280
|
-
isExcludedPath(
|
|
25281
|
-
return EXCLUDED_PATH_PREFIXES.some((prefix) =>
|
|
25824
|
+
isExcludedPath(path17) {
|
|
25825
|
+
return EXCLUDED_PATH_PREFIXES.some((prefix) => path17.startsWith(prefix)) || EXCLUDED_PATH_SUFFIXES.some((suffix) => path17.endsWith(suffix));
|
|
25282
25826
|
}
|
|
25283
25827
|
};
|
|
25284
25828
|
|
|
@@ -25418,11 +25962,11 @@ function forwardLeaderTaskPatch(log, nodeRegistry, taskId, data, options) {
|
|
|
25418
25962
|
log.warn(options.missingLeaderMessage, metadata);
|
|
25419
25963
|
return;
|
|
25420
25964
|
}
|
|
25421
|
-
fetch(`${leaderEndpoint}/api/tasks/${taskId}`, {
|
|
25965
|
+
fetch(`${leaderEndpoint}/api/tasks/${taskId}`, applyRequestAuthHeaders({
|
|
25422
25966
|
method: "PATCH",
|
|
25423
25967
|
headers: { "Content-Type": "application/json" },
|
|
25424
25968
|
body: JSON.stringify(buildLeaderTaskPatch(data))
|
|
25425
|
-
}).then((response) => {
|
|
25969
|
+
})).then((response) => {
|
|
25426
25970
|
if (!response.ok) {
|
|
25427
25971
|
log.warn(options.rejectedMessage, {
|
|
25428
25972
|
...metadata,
|
|
@@ -25469,11 +26013,11 @@ function forwardTaskOutputToLeader(log, nodeRegistry, taskId, event) {
|
|
|
25469
26013
|
});
|
|
25470
26014
|
return;
|
|
25471
26015
|
}
|
|
25472
|
-
fetch(`${leaderEndpoint}/api/worker/output`, {
|
|
26016
|
+
fetch(`${leaderEndpoint}/api/worker/output`, applyRequestAuthHeaders({
|
|
25473
26017
|
method: "POST",
|
|
25474
26018
|
headers: { "Content-Type": "application/json" },
|
|
25475
26019
|
body: JSON.stringify({ taskId, event })
|
|
25476
|
-
}).then((response) => {
|
|
26020
|
+
})).then((response) => {
|
|
25477
26021
|
if (!response.ok) {
|
|
25478
26022
|
log.warn("leader rejected forwarded output", {
|
|
25479
26023
|
taskId,
|
|
@@ -25541,7 +26085,7 @@ function registerLeaderForwarding(eventBus, nodeRegistry, log, taskId, agent) {
|
|
|
25541
26085
|
// ../../packages/core/src/engines/claude-code-engine.ts
|
|
25542
26086
|
var fs7 = __toESM(require("fs"), 1);
|
|
25543
26087
|
var path7 = __toESM(require("path"), 1);
|
|
25544
|
-
var
|
|
26088
|
+
var import_node_child_process2 = require("child_process");
|
|
25545
26089
|
function resolveClaudeInvocation() {
|
|
25546
26090
|
if (process.platform !== "win32") {
|
|
25547
26091
|
return { command: "claude", argsPrefix: [] };
|
|
@@ -25603,7 +26147,7 @@ var ClaudeCodeEngine = class extends ExecutionEngine {
|
|
|
25603
26147
|
this.ensureLogDir();
|
|
25604
26148
|
this.logger.info("Spawning claude CLI", { taskId: task.id, title: task.title, cwd });
|
|
25605
26149
|
const invocation = resolveClaudeInvocation();
|
|
25606
|
-
const proc = (0,
|
|
26150
|
+
const proc = (0, import_node_child_process2.spawn)(invocation.command, [...invocation.argsPrefix, ...args], {
|
|
25607
26151
|
cwd,
|
|
25608
26152
|
stdio: ["pipe", "pipe", "pipe"]
|
|
25609
26153
|
});
|
|
@@ -25713,7 +26257,7 @@ var ClaudeCodeEngine = class extends ExecutionEngine {
|
|
|
25713
26257
|
"stream-json"
|
|
25714
26258
|
];
|
|
25715
26259
|
const invocation = resolveClaudeInvocation();
|
|
25716
|
-
const proc = (0,
|
|
26260
|
+
const proc = (0, import_node_child_process2.spawn)(invocation.command, [...invocation.argsPrefix, ...args], {
|
|
25717
26261
|
cwd: session.cwd,
|
|
25718
26262
|
stdio: ["pipe", "pipe", "pipe"]
|
|
25719
26263
|
});
|
|
@@ -25848,7 +26392,7 @@ var ClaudeCodeEngine = class extends ExecutionEngine {
|
|
|
25848
26392
|
// ../../packages/core/src/engines/codex-engine.ts
|
|
25849
26393
|
var fs8 = __toESM(require("fs"), 1);
|
|
25850
26394
|
var path8 = __toESM(require("path"), 1);
|
|
25851
|
-
var
|
|
26395
|
+
var import_node_child_process3 = require("child_process");
|
|
25852
26396
|
function buildAssistantEvent(text, timestamp = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
25853
26397
|
return {
|
|
25854
26398
|
type: "assistant",
|
|
@@ -25907,7 +26451,7 @@ var CodexEngine = class extends ExecutionEngine {
|
|
|
25907
26451
|
const args = this.buildArgs(prompt, imagePaths, { model: config.model });
|
|
25908
26452
|
this.ensureLogDir();
|
|
25909
26453
|
this.logger.info("Spawning codex CLI", { taskId: task.id, title: task.title, cwd });
|
|
25910
|
-
const proc = (0,
|
|
26454
|
+
const proc = (0, import_node_child_process3.spawn)("codex", args, {
|
|
25911
26455
|
cwd,
|
|
25912
26456
|
stdio: ["ignore", "pipe", "pipe"]
|
|
25913
26457
|
});
|
|
@@ -25934,7 +26478,7 @@ var CodexEngine = class extends ExecutionEngine {
|
|
|
25934
26478
|
const { prompt, imagePaths } = this.prepareAssets(taskId, content);
|
|
25935
26479
|
const args = this.buildArgs(prompt, imagePaths, { model, sessionId: session.sessionId });
|
|
25936
26480
|
this.logger.info("Sending Codex follow-up message", { taskId, sessionId: session.sessionId });
|
|
25937
|
-
const proc = (0,
|
|
26481
|
+
const proc = (0, import_node_child_process3.spawn)("codex", args, {
|
|
25938
26482
|
cwd: session.cwd,
|
|
25939
26483
|
stdio: ["ignore", "pipe", "pipe"]
|
|
25940
26484
|
});
|
|
@@ -26290,23 +26834,53 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
26290
26834
|
this.started = true;
|
|
26291
26835
|
}
|
|
26292
26836
|
async joinCluster(seedUrl) {
|
|
26837
|
+
const log = this.logger.child("node/join-cluster");
|
|
26838
|
+
const tasks = this.taskEngine.listTasks().tasks;
|
|
26293
26839
|
const joinBody = {
|
|
26294
26840
|
id: this.selfInfo.id,
|
|
26295
26841
|
endpoint: this.selfInfo.endpoint,
|
|
26296
26842
|
name: this.config.node.name,
|
|
26297
26843
|
capabilities: [],
|
|
26298
|
-
tasks
|
|
26844
|
+
tasks
|
|
26299
26845
|
};
|
|
26300
26846
|
if (this.selfInfo.devtunnelEndpoint) {
|
|
26301
26847
|
joinBody.devtunnelEndpoint = this.selfInfo.devtunnelEndpoint;
|
|
26302
26848
|
}
|
|
26303
|
-
|
|
26304
|
-
|
|
26305
|
-
|
|
26306
|
-
|
|
26849
|
+
log.info("sending cluster join request", {
|
|
26850
|
+
seedUrl,
|
|
26851
|
+
nodeId: this.selfInfo.id,
|
|
26852
|
+
endpoint: this.selfInfo.endpoint,
|
|
26853
|
+
taskCount: tasks.length,
|
|
26854
|
+
hasDevTunnel: !!this.selfInfo.devtunnelEndpoint
|
|
26855
|
+
});
|
|
26856
|
+
let response;
|
|
26857
|
+
try {
|
|
26858
|
+
response = await fetch(`${seedUrl}/api/cluster/join`, applyRequestAuthHeaders({
|
|
26859
|
+
method: "POST",
|
|
26860
|
+
headers: { "Content-Type": "application/json" },
|
|
26861
|
+
body: JSON.stringify(joinBody)
|
|
26862
|
+
}));
|
|
26863
|
+
} catch (error) {
|
|
26864
|
+
log.warn("cluster join request failed", {
|
|
26865
|
+
seedUrl,
|
|
26866
|
+
error: error instanceof Error ? error.message : String(error)
|
|
26867
|
+
});
|
|
26868
|
+
throw error;
|
|
26869
|
+
}
|
|
26870
|
+
log.info("received cluster join response", {
|
|
26871
|
+
seedUrl,
|
|
26872
|
+
ok: response.ok,
|
|
26873
|
+
statusCode: response.status
|
|
26307
26874
|
});
|
|
26308
26875
|
if (!response.ok) {
|
|
26309
26876
|
const body = await response.json?.().catch(() => null);
|
|
26877
|
+
log.warn("cluster join request rejected", {
|
|
26878
|
+
seedUrl,
|
|
26879
|
+
statusCode: response.status,
|
|
26880
|
+
code: body?.error?.code,
|
|
26881
|
+
message: body?.error?.message,
|
|
26882
|
+
leaderEndpoint: body?.error?.leaderEndpoint
|
|
26883
|
+
});
|
|
26310
26884
|
if (body?.error?.code === "NOT_LEADER") {
|
|
26311
26885
|
const leader = body.error.leaderEndpoint;
|
|
26312
26886
|
throw new Error(
|
|
@@ -26316,22 +26890,51 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
26316
26890
|
throw new Error(`Failed to join cluster via ${seedUrl}: ${response.status}`);
|
|
26317
26891
|
}
|
|
26318
26892
|
const data = await response.json();
|
|
26893
|
+
log.info("applied joined cluster state", {
|
|
26894
|
+
seedUrl,
|
|
26895
|
+
leaderId: data.leaderId,
|
|
26896
|
+
term: data.term,
|
|
26897
|
+
nodeCount: data.nodes.length
|
|
26898
|
+
});
|
|
26319
26899
|
this.applyClusterState(data.nodes, data.leaderId, data.term);
|
|
26320
26900
|
}
|
|
26321
26901
|
async leaveCluster() {
|
|
26902
|
+
const log = this.logger.child("node/leave-cluster");
|
|
26322
26903
|
const leader = this.nodeRegistry.getLeader();
|
|
26323
26904
|
const leaderEndpoint = this.nodeRegistry.getLeaderEndpoint();
|
|
26324
26905
|
const self = this.nodeRegistry.getSelf();
|
|
26325
26906
|
if (!leader || !leaderEndpoint || leader.id === self.id) {
|
|
26907
|
+
log.info("skipping cluster leave request", {
|
|
26908
|
+
hasLeader: !!leader,
|
|
26909
|
+
leaderEndpoint,
|
|
26910
|
+
selfId: self.id
|
|
26911
|
+
});
|
|
26326
26912
|
return;
|
|
26327
26913
|
}
|
|
26328
26914
|
try {
|
|
26329
|
-
|
|
26915
|
+
log.info("sending cluster leave request", {
|
|
26916
|
+
leaderId: leader.id,
|
|
26917
|
+
leaderEndpoint,
|
|
26918
|
+
nodeId: self.id
|
|
26919
|
+
});
|
|
26920
|
+
const response = await fetch(`${leaderEndpoint}/api/cluster/leave`, applyRequestAuthHeaders({
|
|
26330
26921
|
method: "POST",
|
|
26331
26922
|
headers: { "Content-Type": "application/json" },
|
|
26332
26923
|
body: JSON.stringify({ nodeId: self.id })
|
|
26924
|
+
}));
|
|
26925
|
+
log.info("received cluster leave response", {
|
|
26926
|
+
leaderId: leader.id,
|
|
26927
|
+
leaderEndpoint,
|
|
26928
|
+
ok: response.ok,
|
|
26929
|
+
statusCode: response.status
|
|
26930
|
+
});
|
|
26931
|
+
} catch (error) {
|
|
26932
|
+
log.warn("cluster leave request failed", {
|
|
26933
|
+
leaderId: leader.id,
|
|
26934
|
+
leaderEndpoint,
|
|
26935
|
+
nodeId: self.id,
|
|
26936
|
+
error: error instanceof Error ? error.message : String(error)
|
|
26333
26937
|
});
|
|
26334
|
-
} catch {
|
|
26335
26938
|
}
|
|
26336
26939
|
const refreshedSelf = {
|
|
26337
26940
|
...self,
|
|
@@ -26344,8 +26947,13 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
26344
26947
|
this.nodeRegistry.setSelf(refreshedSelf);
|
|
26345
26948
|
this.nodeRegistry.syncFromHeartbeat([refreshedSelf]);
|
|
26346
26949
|
this.nodeRegistry.clearLeader();
|
|
26347
|
-
this.election.
|
|
26348
|
-
|
|
26950
|
+
this.election.assumeLeadership();
|
|
26951
|
+
this.syncSelfInfoFromRegistry();
|
|
26952
|
+
log.info("detached from leader and assumed solo leadership", {
|
|
26953
|
+
previousLeaderId: leader.id,
|
|
26954
|
+
nodeId: refreshedSelf.id,
|
|
26955
|
+
term: this.election.getCurrentTerm()
|
|
26956
|
+
});
|
|
26349
26957
|
}
|
|
26350
26958
|
async stop() {
|
|
26351
26959
|
if (!this.started) return;
|
|
@@ -26355,13 +26963,26 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
26355
26963
|
try {
|
|
26356
26964
|
const leaderEndpoint = this.nodeRegistry.getLeaderEndpoint();
|
|
26357
26965
|
if (leaderEndpoint) {
|
|
26358
|
-
|
|
26966
|
+
this.logger.info("sending shutdown cluster leave request", {
|
|
26967
|
+
leaderEndpoint,
|
|
26968
|
+
nodeId: this.selfInfo.id
|
|
26969
|
+
});
|
|
26970
|
+
const response = await fetch(`${leaderEndpoint}/api/cluster/leave`, applyRequestAuthHeaders({
|
|
26359
26971
|
method: "POST",
|
|
26360
26972
|
headers: { "Content-Type": "application/json" },
|
|
26361
26973
|
body: JSON.stringify({ nodeId: this.selfInfo.id })
|
|
26974
|
+
}));
|
|
26975
|
+
this.logger.info("received shutdown cluster leave response", {
|
|
26976
|
+
leaderEndpoint,
|
|
26977
|
+
ok: response.ok,
|
|
26978
|
+
statusCode: response.status
|
|
26362
26979
|
});
|
|
26363
26980
|
}
|
|
26364
|
-
} catch {
|
|
26981
|
+
} catch (error) {
|
|
26982
|
+
this.logger.warn("shutdown cluster leave request failed", {
|
|
26983
|
+
nodeId: this.selfInfo.id,
|
|
26984
|
+
error: error instanceof Error ? error.message : String(error)
|
|
26985
|
+
});
|
|
26365
26986
|
}
|
|
26366
26987
|
if (this.devtunnelTransport) {
|
|
26367
26988
|
await this.devtunnelTransport.stop();
|
|
@@ -26440,11 +27061,11 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
26440
27061
|
const leaderEndpoint = this.nodeRegistry.getLeaderEndpoint();
|
|
26441
27062
|
if (leaderEndpoint && !this.nodeRegistry.isLeader()) {
|
|
26442
27063
|
try {
|
|
26443
|
-
await fetch(`${leaderEndpoint}/api/nodes/${this.selfInfo.id}`, {
|
|
27064
|
+
await fetch(`${leaderEndpoint}/api/nodes/${this.selfInfo.id}`, applyRequestAuthHeaders({
|
|
26444
27065
|
method: "PATCH",
|
|
26445
27066
|
headers: { "Content-Type": "application/json" },
|
|
26446
27067
|
body: JSON.stringify({ endpoint: newEndpoint })
|
|
26447
|
-
});
|
|
27068
|
+
}));
|
|
26448
27069
|
} catch {
|
|
26449
27070
|
}
|
|
26450
27071
|
}
|
|
@@ -26522,7 +27143,7 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
26522
27143
|
this.selfInfo = nextSelf;
|
|
26523
27144
|
this.nodeRegistry.setSelf(nextSelf);
|
|
26524
27145
|
this.nodeRegistry.syncFromHeartbeat(nodes);
|
|
26525
|
-
this.election.
|
|
27146
|
+
this.election.adoptLeaderFromJoin({ leaderId, term });
|
|
26526
27147
|
}
|
|
26527
27148
|
cloneTransportConfig(config) {
|
|
26528
27149
|
return {
|
|
@@ -27161,8 +27782,8 @@ function getErrorMap() {
|
|
|
27161
27782
|
|
|
27162
27783
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
|
|
27163
27784
|
var makeIssue = (params) => {
|
|
27164
|
-
const { data, path:
|
|
27165
|
-
const fullPath = [...
|
|
27785
|
+
const { data, path: path17, errorMaps, issueData } = params;
|
|
27786
|
+
const fullPath = [...path17, ...issueData.path || []];
|
|
27166
27787
|
const fullIssue = {
|
|
27167
27788
|
...issueData,
|
|
27168
27789
|
path: fullPath
|
|
@@ -27278,11 +27899,11 @@ var errorUtil;
|
|
|
27278
27899
|
|
|
27279
27900
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
|
|
27280
27901
|
var ParseInputLazyPath = class {
|
|
27281
|
-
constructor(parent, value,
|
|
27902
|
+
constructor(parent, value, path17, key) {
|
|
27282
27903
|
this._cachedPath = [];
|
|
27283
27904
|
this.parent = parent;
|
|
27284
27905
|
this.data = value;
|
|
27285
|
-
this._path =
|
|
27906
|
+
this._path = path17;
|
|
27286
27907
|
this._key = key;
|
|
27287
27908
|
}
|
|
27288
27909
|
get path() {
|
|
@@ -30752,6 +31373,7 @@ var NodeInfoSchema = external_exports.object({
|
|
|
30752
31373
|
lastHeartbeat: external_exports.number(),
|
|
30753
31374
|
transportType: external_exports.string().optional(),
|
|
30754
31375
|
devtunnelEndpoint: external_exports.string().optional(),
|
|
31376
|
+
dashboardOrigin: external_exports.string().optional(),
|
|
30755
31377
|
previewOrigin: external_exports.string().optional()
|
|
30756
31378
|
});
|
|
30757
31379
|
var JoinTaskSchema = external_exports.object({
|
|
@@ -30821,6 +31443,7 @@ var NodeInfoSchema2 = external_exports.object({
|
|
|
30821
31443
|
lastHeartbeat: external_exports.number(),
|
|
30822
31444
|
transportType: external_exports.string().optional(),
|
|
30823
31445
|
devtunnelEndpoint: external_exports.string().optional(),
|
|
31446
|
+
dashboardOrigin: external_exports.string().optional(),
|
|
30824
31447
|
previewOrigin: external_exports.string().optional()
|
|
30825
31448
|
});
|
|
30826
31449
|
var NodeListQuery = external_exports.object({
|
|
@@ -30947,13 +31570,113 @@ var import_express7 = __toESM(require_express2(), 1);
|
|
|
30947
31570
|
|
|
30948
31571
|
// ../../packages/api/src/middleware/auth.ts
|
|
30949
31572
|
var SKIP_AUTH_PATHS = ["/api/system/health"];
|
|
31573
|
+
var TRUSTED_LOCAL_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]", "::1"]);
|
|
31574
|
+
function normalizeHost(value) {
|
|
31575
|
+
if (!value) return void 0;
|
|
31576
|
+
const trimmed = value.trim().toLowerCase();
|
|
31577
|
+
if (!trimmed) return void 0;
|
|
31578
|
+
return trimmed.replace(/:\d+$/, "");
|
|
31579
|
+
}
|
|
31580
|
+
function collectHosts(candidates) {
|
|
31581
|
+
const unique = /* @__PURE__ */ new Set();
|
|
31582
|
+
for (const candidate of candidates) {
|
|
31583
|
+
if (!candidate) continue;
|
|
31584
|
+
for (const item of candidate.split(",")) {
|
|
31585
|
+
const normalized = normalizeHost(item);
|
|
31586
|
+
if (normalized) {
|
|
31587
|
+
unique.add(normalized);
|
|
31588
|
+
}
|
|
31589
|
+
}
|
|
31590
|
+
}
|
|
31591
|
+
return [...unique];
|
|
31592
|
+
}
|
|
31593
|
+
function getForwardedHosts(req) {
|
|
31594
|
+
const forwardedHosts = collectHosts([
|
|
31595
|
+
typeof req.headers["x-forwarded-host"] === "string" ? req.headers["x-forwarded-host"] : void 0
|
|
31596
|
+
]);
|
|
31597
|
+
if (forwardedHosts.length > 0) {
|
|
31598
|
+
return forwardedHosts;
|
|
31599
|
+
}
|
|
31600
|
+
const forwardedHeader = typeof req.headers.forwarded === "string" ? req.headers.forwarded : void 0;
|
|
31601
|
+
if (!forwardedHeader) {
|
|
31602
|
+
return [];
|
|
31603
|
+
}
|
|
31604
|
+
const forwardedMatches = [...forwardedHeader.matchAll(/host=([^;,\s]+)/gi)];
|
|
31605
|
+
return collectHosts(forwardedMatches.map((match) => match[1]?.replace(/^"|"$/g, "")));
|
|
31606
|
+
}
|
|
31607
|
+
function getDirectHosts(req) {
|
|
31608
|
+
return collectHosts([
|
|
31609
|
+
req.hostname,
|
|
31610
|
+
typeof req.headers.host === "string" ? req.headers.host : void 0
|
|
31611
|
+
]);
|
|
31612
|
+
}
|
|
31613
|
+
function getRequestHosts(req) {
|
|
31614
|
+
const forwardedHosts = getForwardedHosts(req);
|
|
31615
|
+
if (forwardedHosts.length > 0) {
|
|
31616
|
+
return forwardedHosts;
|
|
31617
|
+
}
|
|
31618
|
+
return getDirectHosts(req);
|
|
31619
|
+
}
|
|
31620
|
+
function isTrustedDashboardRequest(req, config) {
|
|
31621
|
+
const trustedHosts = new Set((config.getTrustedHosts?.() ?? []).map((host) => normalizeHost(host)).filter(Boolean));
|
|
31622
|
+
for (const host of getRequestHosts(req)) {
|
|
31623
|
+
if (TRUSTED_LOCAL_HOSTS.has(host) || trustedHosts.has(host)) {
|
|
31624
|
+
return true;
|
|
31625
|
+
}
|
|
31626
|
+
}
|
|
31627
|
+
return false;
|
|
31628
|
+
}
|
|
31629
|
+
function getAuthLogger(req) {
|
|
31630
|
+
const logger = req.app?.locals?.deps?.logger;
|
|
31631
|
+
if (logger && typeof logger.child === "function") {
|
|
31632
|
+
return logger.child("api/auth");
|
|
31633
|
+
}
|
|
31634
|
+
return {
|
|
31635
|
+
debug() {
|
|
31636
|
+
},
|
|
31637
|
+
warn() {
|
|
31638
|
+
}
|
|
31639
|
+
};
|
|
31640
|
+
}
|
|
30950
31641
|
function createAuthMiddleware(config) {
|
|
30951
31642
|
return (req, _res, next) => {
|
|
30952
|
-
|
|
31643
|
+
const log = getAuthLogger(req);
|
|
31644
|
+
if (SKIP_AUTH_PATHS.includes(req.path)) {
|
|
30953
31645
|
next();
|
|
30954
31646
|
return;
|
|
30955
31647
|
}
|
|
30956
|
-
if (
|
|
31648
|
+
if (config.validateBearerToken) {
|
|
31649
|
+
if (isTrustedDashboardRequest(req, config)) {
|
|
31650
|
+
log.debug("skipping bearer auth for trusted dashboard request", {
|
|
31651
|
+
path: req.path,
|
|
31652
|
+
method: req.method,
|
|
31653
|
+
hosts: getRequestHosts(req)
|
|
31654
|
+
});
|
|
31655
|
+
next();
|
|
31656
|
+
return;
|
|
31657
|
+
}
|
|
31658
|
+
const result = config.validateBearerToken(req.headers.authorization);
|
|
31659
|
+
if (!result.ok) {
|
|
31660
|
+
log.warn("rejected bearer-authenticated request", {
|
|
31661
|
+
path: req.path,
|
|
31662
|
+
method: req.method,
|
|
31663
|
+
hosts: getRequestHosts(req),
|
|
31664
|
+
reason: result.reason
|
|
31665
|
+
});
|
|
31666
|
+
throw new MeshyError("VALIDATION_ERROR", "Invalid or missing bearer token", 401, {
|
|
31667
|
+
reason: result.reason
|
|
31668
|
+
});
|
|
31669
|
+
}
|
|
31670
|
+
log.debug("accepted bearer-authenticated request", {
|
|
31671
|
+
path: req.path,
|
|
31672
|
+
method: req.method,
|
|
31673
|
+
hosts: getRequestHosts(req),
|
|
31674
|
+
reason: result.reason
|
|
31675
|
+
});
|
|
31676
|
+
next();
|
|
31677
|
+
return;
|
|
31678
|
+
}
|
|
31679
|
+
if (!config.apiKey) {
|
|
30957
31680
|
next();
|
|
30958
31681
|
return;
|
|
30959
31682
|
}
|
|
@@ -31055,19 +31778,31 @@ function createErrorMiddleware() {
|
|
|
31055
31778
|
// ../../packages/api/src/routes/cluster.ts
|
|
31056
31779
|
var import_express = __toESM(require_express2(), 1);
|
|
31057
31780
|
var CONNECTIVITY_TIMEOUT_MS = 8e3;
|
|
31058
|
-
|
|
31781
|
+
function formatError2(error) {
|
|
31782
|
+
return error instanceof Error ? error.message : String(error);
|
|
31783
|
+
}
|
|
31784
|
+
async function verifyHealth(endpoint, log) {
|
|
31059
31785
|
const controller = new AbortController();
|
|
31060
31786
|
const timer = setTimeout(() => controller.abort(), CONNECTIVITY_TIMEOUT_MS);
|
|
31787
|
+
const url = `${endpoint}/api/system/health`;
|
|
31061
31788
|
try {
|
|
31062
|
-
|
|
31789
|
+
log.info("sending leader health check", { endpoint, url, timeoutMs: CONNECTIVITY_TIMEOUT_MS });
|
|
31790
|
+
const response = await fetch(url, {
|
|
31063
31791
|
signal: controller.signal
|
|
31064
31792
|
});
|
|
31793
|
+
log.info("received leader health check response", {
|
|
31794
|
+
endpoint,
|
|
31795
|
+
url,
|
|
31796
|
+
ok: response.ok,
|
|
31797
|
+
statusCode: response.status
|
|
31798
|
+
});
|
|
31065
31799
|
if (!response.ok) {
|
|
31066
31800
|
throw new Error(`health check returned ${response.status}`);
|
|
31067
31801
|
}
|
|
31068
31802
|
} catch (err) {
|
|
31803
|
+
log.warn("leader health check failed", { endpoint, url, error: formatError2(err) });
|
|
31069
31804
|
throw new Error(
|
|
31070
|
-
`Failed to verify connectivity for ${endpoint}: ${
|
|
31805
|
+
`Failed to verify connectivity for ${endpoint}: ${formatError2(err)}`
|
|
31071
31806
|
);
|
|
31072
31807
|
} finally {
|
|
31073
31808
|
clearTimeout(timer);
|
|
@@ -31079,9 +31814,11 @@ function asyncHandler(fn) {
|
|
|
31079
31814
|
function createClusterRoutes() {
|
|
31080
31815
|
const router = (0, import_express.Router)();
|
|
31081
31816
|
router.post("/join", asyncHandler(async (req, res) => {
|
|
31082
|
-
const { nodeRegistry, election, taskEngine } = req.app.locals.deps;
|
|
31817
|
+
const { nodeRegistry, election, taskEngine, logger: rootLogger } = req.app.locals.deps;
|
|
31818
|
+
const log = rootLogger.child("cluster/join");
|
|
31083
31819
|
if (!election.isLeader()) {
|
|
31084
31820
|
const leaderEndpoint = nodeRegistry.getLeaderEndpoint();
|
|
31821
|
+
log.warn("rejected cluster join because node is not leader", { leaderEndpoint });
|
|
31085
31822
|
res.status(421).json({
|
|
31086
31823
|
error: {
|
|
31087
31824
|
code: "NOT_LEADER",
|
|
@@ -31092,10 +31829,19 @@ function createClusterRoutes() {
|
|
|
31092
31829
|
return;
|
|
31093
31830
|
}
|
|
31094
31831
|
const body = JoinClusterBody.parse(req.body);
|
|
31832
|
+
log.info("received cluster join request", {
|
|
31833
|
+
nodeId: body.id,
|
|
31834
|
+
name: body.name,
|
|
31835
|
+
endpoint: body.endpoint,
|
|
31836
|
+
taskCount: body.tasks?.length ?? 0,
|
|
31837
|
+
hasDevTunnel: !!body.devtunnelEndpoint
|
|
31838
|
+
});
|
|
31095
31839
|
const existingNodes = nodeRegistry.getAllNodes();
|
|
31840
|
+
let removedCount = 0;
|
|
31096
31841
|
for (const existing of existingNodes) {
|
|
31097
31842
|
if (existing.id === body.id || existing.endpoint === body.endpoint || existing.name === body.name) {
|
|
31098
31843
|
nodeRegistry.removeNode(existing.id);
|
|
31844
|
+
removedCount++;
|
|
31099
31845
|
}
|
|
31100
31846
|
}
|
|
31101
31847
|
const node = {
|
|
@@ -31111,6 +31857,12 @@ function createClusterRoutes() {
|
|
|
31111
31857
|
};
|
|
31112
31858
|
nodeRegistry.addNode(node);
|
|
31113
31859
|
taskEngine.importTasks(body.tasks ?? []);
|
|
31860
|
+
log.info("accepted cluster join request", {
|
|
31861
|
+
nodeId: node.id,
|
|
31862
|
+
endpoint: node.endpoint,
|
|
31863
|
+
removedCount,
|
|
31864
|
+
importedTaskCount: body.tasks?.length ?? 0
|
|
31865
|
+
});
|
|
31114
31866
|
const clusterState = nodeRegistry.getClusterState();
|
|
31115
31867
|
res.status(201).json({
|
|
31116
31868
|
clusterId: clusterState.clusterId ?? nanoid(),
|
|
@@ -31122,14 +31874,22 @@ function createClusterRoutes() {
|
|
|
31122
31874
|
router.post("/connect", asyncHandler(async (req, res) => {
|
|
31123
31875
|
const {
|
|
31124
31876
|
nodeRegistry,
|
|
31125
|
-
joinCurrentNodeToCluster
|
|
31877
|
+
joinCurrentNodeToCluster,
|
|
31878
|
+
logger: rootLogger
|
|
31126
31879
|
} = req.app.locals.deps;
|
|
31880
|
+
const log = rootLogger.child("cluster/connect");
|
|
31127
31881
|
const body = ConnectClusterBody.parse(req.body);
|
|
31882
|
+
log.info("received cluster connect request", {
|
|
31883
|
+
leaderEndpoint: body.leaderEndpoint,
|
|
31884
|
+
transport: body.transport
|
|
31885
|
+
});
|
|
31128
31886
|
if (!joinCurrentNodeToCluster) {
|
|
31129
31887
|
throw new MeshyError("VALIDATION_ERROR", "Join flow is not available on this node", 501);
|
|
31130
31888
|
}
|
|
31131
|
-
await verifyHealth(body.leaderEndpoint);
|
|
31889
|
+
await verifyHealth(body.leaderEndpoint, log);
|
|
31890
|
+
log.info("leader health check succeeded", { leaderEndpoint: body.leaderEndpoint });
|
|
31132
31891
|
await joinCurrentNodeToCluster(body.leaderEndpoint);
|
|
31892
|
+
log.info("completed cluster connect request", { leaderEndpoint: body.leaderEndpoint });
|
|
31133
31893
|
const self = nodeRegistry.getSelf();
|
|
31134
31894
|
const clusterState = nodeRegistry.getClusterState();
|
|
31135
31895
|
res.json({
|
|
@@ -31142,17 +31902,22 @@ function createClusterRoutes() {
|
|
|
31142
31902
|
});
|
|
31143
31903
|
}));
|
|
31144
31904
|
router.post("/leave", asyncHandler(async (req, res) => {
|
|
31145
|
-
const { nodeRegistry } = req.app.locals.deps;
|
|
31905
|
+
const { nodeRegistry, logger: rootLogger } = req.app.locals.deps;
|
|
31906
|
+
const log = rootLogger.child("cluster/leave");
|
|
31146
31907
|
const { nodeId } = req.body;
|
|
31908
|
+
log.info("received cluster leave request", { nodeId });
|
|
31147
31909
|
nodeRegistry.removeNode(nodeId);
|
|
31148
31910
|
res.json({ ok: true });
|
|
31149
31911
|
}));
|
|
31150
31912
|
router.post("/disconnect", asyncHandler(async (req, res) => {
|
|
31151
|
-
const { leaveCurrentCluster, nodeRegistry } = req.app.locals.deps;
|
|
31913
|
+
const { leaveCurrentCluster, nodeRegistry, logger: rootLogger } = req.app.locals.deps;
|
|
31914
|
+
const log = rootLogger.child("cluster/disconnect");
|
|
31915
|
+
log.info("received cluster disconnect request");
|
|
31152
31916
|
if (!leaveCurrentCluster) {
|
|
31153
31917
|
throw new MeshyError("VALIDATION_ERROR", "Leave flow is not available on this node", 501);
|
|
31154
31918
|
}
|
|
31155
31919
|
await leaveCurrentCluster();
|
|
31920
|
+
log.info("completed cluster disconnect request");
|
|
31156
31921
|
const self = nodeRegistry.getSelf();
|
|
31157
31922
|
const clusterState = nodeRegistry.getClusterState();
|
|
31158
31923
|
res.json({
|
|
@@ -31645,10 +32410,10 @@ function readFileContent(root, relativePath) {
|
|
|
31645
32410
|
}
|
|
31646
32411
|
|
|
31647
32412
|
// ../../packages/api/src/output/git-diff.ts
|
|
31648
|
-
var
|
|
32413
|
+
var import_node_child_process4 = require("child_process");
|
|
31649
32414
|
function git(args, cwd) {
|
|
31650
32415
|
try {
|
|
31651
|
-
return (0,
|
|
32416
|
+
return (0, import_node_child_process4.execFileSync)("git", ["-C", cwd, ...args], {
|
|
31652
32417
|
encoding: "utf-8",
|
|
31653
32418
|
timeout: 1e4,
|
|
31654
32419
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -31841,7 +32606,8 @@ async function executeWorkerControlRequest(deps, request) {
|
|
|
31841
32606
|
return jsonResponse(request.requestId, 200, {
|
|
31842
32607
|
ok: true,
|
|
31843
32608
|
enabled: true,
|
|
31844
|
-
devtunnelEndpoint
|
|
32609
|
+
devtunnelEndpoint,
|
|
32610
|
+
dashboardOrigin: deps.nodeRegistry.getSelf().dashboardOrigin
|
|
31845
32611
|
});
|
|
31846
32612
|
}
|
|
31847
32613
|
if (!deps.disableDevTunnel) {
|
|
@@ -31850,7 +32616,8 @@ async function executeWorkerControlRequest(deps, request) {
|
|
|
31850
32616
|
await deps.disableDevTunnel();
|
|
31851
32617
|
return jsonResponse(request.requestId, 200, {
|
|
31852
32618
|
ok: true,
|
|
31853
|
-
enabled: false
|
|
32619
|
+
enabled: false,
|
|
32620
|
+
dashboardOrigin: deps.nodeRegistry.getSelf().dashboardOrigin
|
|
31854
32621
|
});
|
|
31855
32622
|
}
|
|
31856
32623
|
case "task-cancel": {
|
|
@@ -32084,10 +32851,19 @@ function createNodeRoutes() {
|
|
|
32084
32851
|
}
|
|
32085
32852
|
if (enabled) {
|
|
32086
32853
|
const devtunnelEndpoint = await enableDevTunnel();
|
|
32087
|
-
res.json({
|
|
32854
|
+
res.json({
|
|
32855
|
+
ok: true,
|
|
32856
|
+
enabled: true,
|
|
32857
|
+
devtunnelEndpoint,
|
|
32858
|
+
dashboardOrigin: nodeRegistry.getSelf().dashboardOrigin
|
|
32859
|
+
});
|
|
32088
32860
|
} else {
|
|
32089
32861
|
await disableDevTunnel();
|
|
32090
|
-
res.json({
|
|
32862
|
+
res.json({
|
|
32863
|
+
ok: true,
|
|
32864
|
+
enabled: false,
|
|
32865
|
+
dashboardOrigin: nodeRegistry.getSelf().dashboardOrigin
|
|
32866
|
+
});
|
|
32091
32867
|
}
|
|
32092
32868
|
} else {
|
|
32093
32869
|
const node = nodeRegistry.getNode(targetId);
|
|
@@ -32126,6 +32902,7 @@ function createNodeRoutes() {
|
|
|
32126
32902
|
if (result?.ok) {
|
|
32127
32903
|
if (nodeRegistry.getNode(targetId)) {
|
|
32128
32904
|
nodeRegistry.updateDevTunnelEndpoint(targetId, result.devtunnelEndpoint);
|
|
32905
|
+
nodeRegistry.updateDashboardOrigin(targetId, result.dashboardOrigin);
|
|
32129
32906
|
}
|
|
32130
32907
|
}
|
|
32131
32908
|
sendWorkerControlResponse(res, controlResponse);
|
|
@@ -32141,6 +32918,7 @@ function createNodeRoutes() {
|
|
|
32141
32918
|
const updatedNode = nodeRegistry.getNode(targetId);
|
|
32142
32919
|
if (updatedNode) {
|
|
32143
32920
|
nodeRegistry.updateDevTunnelEndpoint(targetId, result.devtunnelEndpoint);
|
|
32921
|
+
nodeRegistry.updateDashboardOrigin(targetId, result.dashboardOrigin);
|
|
32144
32922
|
}
|
|
32145
32923
|
res.json(result);
|
|
32146
32924
|
}
|
|
@@ -33025,13 +33803,40 @@ function createWorkerRoutes() {
|
|
|
33025
33803
|
res.json({ ok: true });
|
|
33026
33804
|
}));
|
|
33027
33805
|
router.post("/heartbeat", asyncHandler4(async (req, res) => {
|
|
33028
|
-
const { heartbeat } = req.app.locals.deps;
|
|
33029
|
-
const
|
|
33806
|
+
const { heartbeat, logger: rootLogger } = req.app.locals.deps;
|
|
33807
|
+
const log = rootLogger.child("worker/heartbeat");
|
|
33808
|
+
const body = req.body;
|
|
33809
|
+
log.info("received worker heartbeat API call", {
|
|
33810
|
+
leaderId: body.leaderId,
|
|
33811
|
+
term: body.term,
|
|
33812
|
+
nodeCount: body.clusterState?.nodes?.length ?? 0
|
|
33813
|
+
});
|
|
33814
|
+
const response = heartbeat.handleHeartbeat(body);
|
|
33815
|
+
log.info("completed worker heartbeat API call", {
|
|
33816
|
+
nodeId: response.nodeId,
|
|
33817
|
+
status: response.status,
|
|
33818
|
+
load: response.load
|
|
33819
|
+
});
|
|
33030
33820
|
res.json(response);
|
|
33031
33821
|
}));
|
|
33032
33822
|
router.post("/keepalive", asyncHandler4(async (req, res) => {
|
|
33033
|
-
const { heartbeat } = req.app.locals.deps;
|
|
33034
|
-
const
|
|
33823
|
+
const { heartbeat, logger: rootLogger } = req.app.locals.deps;
|
|
33824
|
+
const log = rootLogger.child("worker/keepalive");
|
|
33825
|
+
const body = req.body;
|
|
33826
|
+
log.info("received worker keepalive API call", {
|
|
33827
|
+
nodeId: body.nodeId,
|
|
33828
|
+
status: body.status,
|
|
33829
|
+
endpoint: body.endpoint
|
|
33830
|
+
});
|
|
33831
|
+
const response = heartbeat.handleKeepalive(body);
|
|
33832
|
+
log.info("completed worker keepalive API call", {
|
|
33833
|
+
leaderId: response.leaderId,
|
|
33834
|
+
term: response.term,
|
|
33835
|
+
nodeCount: response.clusterState.nodes.length,
|
|
33836
|
+
dispatchedTaskCount: response.dispatchedTasks?.length ?? 0,
|
|
33837
|
+
followUpCount: response.followUpMessages?.length ?? 0,
|
|
33838
|
+
controlRequestCount: response.controlRequests?.length ?? 0
|
|
33839
|
+
});
|
|
33035
33840
|
res.json(response);
|
|
33036
33841
|
}));
|
|
33037
33842
|
router.post("/vote", asyncHandler4(async (req, res) => {
|
|
@@ -33055,8 +33860,19 @@ function createWorkerRoutes() {
|
|
|
33055
33860
|
res.json(payload);
|
|
33056
33861
|
}));
|
|
33057
33862
|
router.post("/control-response", asyncHandler4(async (req, res) => {
|
|
33058
|
-
const { heartbeat } = req.app.locals.deps;
|
|
33059
|
-
const
|
|
33863
|
+
const { heartbeat, logger: rootLogger } = req.app.locals.deps;
|
|
33864
|
+
const log = rootLogger.child("worker/control-response");
|
|
33865
|
+
const body = req.body;
|
|
33866
|
+
log.info("received worker control response API call", {
|
|
33867
|
+
requestId: body.requestId,
|
|
33868
|
+
ok: body.ok,
|
|
33869
|
+
statusCode: body.statusCode
|
|
33870
|
+
});
|
|
33871
|
+
const handled = heartbeat.handleWorkerControlResponse?.(body) ?? false;
|
|
33872
|
+
log.info("completed worker control response API call", {
|
|
33873
|
+
requestId: body.requestId,
|
|
33874
|
+
handled
|
|
33875
|
+
});
|
|
33060
33876
|
res.json({ ok: true, handled });
|
|
33061
33877
|
}));
|
|
33062
33878
|
return router;
|
|
@@ -33069,17 +33885,29 @@ function asyncHandler5(fn) {
|
|
|
33069
33885
|
}
|
|
33070
33886
|
function createSystemRoutes() {
|
|
33071
33887
|
const router = (0, import_express5.Router)();
|
|
33072
|
-
router.get("/health", asyncHandler5(async (
|
|
33888
|
+
router.get("/health", asyncHandler5(async (req, res) => {
|
|
33889
|
+
const { logger: rootLogger } = req.app.locals.deps;
|
|
33890
|
+
rootLogger.child("system/health").info("received system health API call", {
|
|
33891
|
+
method: req.method,
|
|
33892
|
+
path: req.originalUrl || req.url,
|
|
33893
|
+
remoteAddress: req.ip || req.socket.remoteAddress
|
|
33894
|
+
});
|
|
33073
33895
|
res.json({ status: "ok", timestamp: Date.now() });
|
|
33074
33896
|
}));
|
|
33075
33897
|
router.get("/info", asyncHandler5(async (req, res) => {
|
|
33076
|
-
const { nodeRegistry, getTransportType } = req.app.locals.deps;
|
|
33898
|
+
const { nodeRegistry, getTransportType, config, dashboardOrigin } = req.app.locals.deps;
|
|
33077
33899
|
const self = nodeRegistry.getSelf();
|
|
33078
33900
|
res.json({
|
|
33079
33901
|
...self,
|
|
33080
33902
|
version: "0.1.0",
|
|
33081
33903
|
uptime: process.uptime(),
|
|
33082
|
-
transportType: getTransportType?.() ?? "direct"
|
|
33904
|
+
transportType: getTransportType?.() ?? "direct",
|
|
33905
|
+
dashboardOrigin: dashboardOrigin ?? self.dashboardOrigin,
|
|
33906
|
+
auth: config.authMetadata ?? {
|
|
33907
|
+
enabled: false,
|
|
33908
|
+
allowSameTenant: false,
|
|
33909
|
+
allowedUsers: []
|
|
33910
|
+
}
|
|
33083
33911
|
});
|
|
33084
33912
|
}));
|
|
33085
33913
|
router.post("/transport", asyncHandler5(async (req, res) => {
|
|
@@ -33110,10 +33938,19 @@ function createSystemRoutes() {
|
|
|
33110
33938
|
assertCanChangeNodeDevTunnel(taskEngine, nodeRegistry.getSelf().id);
|
|
33111
33939
|
if (enabled) {
|
|
33112
33940
|
const devtunnelEndpoint = await enableDevTunnel();
|
|
33113
|
-
res.json({
|
|
33941
|
+
res.json({
|
|
33942
|
+
ok: true,
|
|
33943
|
+
enabled: true,
|
|
33944
|
+
devtunnelEndpoint,
|
|
33945
|
+
dashboardOrigin: nodeRegistry.getSelf().dashboardOrigin
|
|
33946
|
+
});
|
|
33114
33947
|
} else {
|
|
33115
33948
|
await disableDevTunnel();
|
|
33116
|
-
res.json({
|
|
33949
|
+
res.json({
|
|
33950
|
+
ok: true,
|
|
33951
|
+
enabled: false,
|
|
33952
|
+
dashboardOrigin: nodeRegistry.getSelf().dashboardOrigin
|
|
33953
|
+
});
|
|
33117
33954
|
}
|
|
33118
33955
|
}));
|
|
33119
33956
|
router.get("/metrics", asyncHandler5(async (req, res) => {
|
|
@@ -33243,13 +34080,39 @@ function createServer2(deps) {
|
|
|
33243
34080
|
if (typeof deps.heartbeat.setControlRequestHandler === "function") {
|
|
33244
34081
|
deps.heartbeat.setControlRequestHandler((request) => executeWorkerControlRequest(deps, request));
|
|
33245
34082
|
}
|
|
34083
|
+
const authConfig = {
|
|
34084
|
+
apiKey: deps.config.apiKey,
|
|
34085
|
+
validateBearerToken: deps.config.validateBearerToken,
|
|
34086
|
+
getTrustedHosts: () => {
|
|
34087
|
+
const trustedHosts = [];
|
|
34088
|
+
if (deps.dashboardOrigin) {
|
|
34089
|
+
try {
|
|
34090
|
+
trustedHosts.push(new URL(deps.dashboardOrigin).host);
|
|
34091
|
+
} catch {
|
|
34092
|
+
}
|
|
34093
|
+
}
|
|
34094
|
+
return trustedHosts;
|
|
34095
|
+
}
|
|
34096
|
+
};
|
|
34097
|
+
const isApiRequest = (req) => req.path === "/api" || req.path.startsWith("/api/");
|
|
34098
|
+
const canServeDashboard = (req) => !deps.config.validateBearerToken || isTrustedDashboardRequest(req, authConfig);
|
|
33246
34099
|
const runtimeBaseDir = resolveRuntimeBaseDir();
|
|
33247
34100
|
const staticDir = resolveStaticDir(runtimeBaseDir);
|
|
33248
34101
|
if (staticDir) {
|
|
33249
|
-
|
|
34102
|
+
const staticMiddleware = import_express7.default.static(staticDir);
|
|
34103
|
+
app.use((req, res, next) => {
|
|
34104
|
+
if (isApiRequest(req)) {
|
|
34105
|
+
next();
|
|
34106
|
+
return;
|
|
34107
|
+
}
|
|
34108
|
+
if (!canServeDashboard(req)) {
|
|
34109
|
+
res.status(404).type("text/plain").send("Not Found");
|
|
34110
|
+
return;
|
|
34111
|
+
}
|
|
34112
|
+
staticMiddleware(req, res, next);
|
|
34113
|
+
});
|
|
33250
34114
|
}
|
|
33251
34115
|
app.use(import_express7.default.json({ limit: JSON_BODY_LIMIT }));
|
|
33252
|
-
const authConfig = { apiKey: deps.config.apiKey };
|
|
33253
34116
|
app.use(createAuthMiddleware(authConfig));
|
|
33254
34117
|
app.use(createRoutingMiddleware(deps.dataRouter));
|
|
33255
34118
|
const largeBodyParser = import_express7.default.json({ limit: JSON_BODY_LIMIT_LARGE });
|
|
@@ -33262,7 +34125,15 @@ function createServer2(deps) {
|
|
|
33262
34125
|
if (staticDir) {
|
|
33263
34126
|
const indexPath = path15.join(staticDir, "index.html");
|
|
33264
34127
|
if (fs15.existsSync(indexPath)) {
|
|
33265
|
-
app.get("*", (
|
|
34128
|
+
app.get("*", (req, res, next) => {
|
|
34129
|
+
if (isApiRequest(req)) {
|
|
34130
|
+
next();
|
|
34131
|
+
return;
|
|
34132
|
+
}
|
|
34133
|
+
if (!canServeDashboard(req)) {
|
|
34134
|
+
res.status(404).type("text/plain").send("Not Found");
|
|
34135
|
+
return;
|
|
34136
|
+
}
|
|
33266
34137
|
res.sendFile(indexPath);
|
|
33267
34138
|
});
|
|
33268
34139
|
}
|
|
@@ -33337,10 +34208,10 @@ var DirectTransport = class {
|
|
|
33337
34208
|
};
|
|
33338
34209
|
|
|
33339
34210
|
// ../../packages/transport/src/devtunnel.ts
|
|
33340
|
-
var
|
|
34211
|
+
var import_node_child_process5 = require("child_process");
|
|
33341
34212
|
function isInstalled(cmd) {
|
|
33342
34213
|
try {
|
|
33343
|
-
(0,
|
|
34214
|
+
(0, import_node_child_process5.execSync)(process.platform === "win32" ? `where ${cmd}` : `command -v ${cmd}`, { stdio: "pipe" });
|
|
33344
34215
|
return true;
|
|
33345
34216
|
} catch {
|
|
33346
34217
|
return false;
|
|
@@ -33363,14 +34234,14 @@ var DevTunnelTransport = class {
|
|
|
33363
34234
|
);
|
|
33364
34235
|
}
|
|
33365
34236
|
try {
|
|
33366
|
-
(0,
|
|
34237
|
+
(0, import_node_child_process5.execSync)("devtunnel user show", { stdio: "pipe" });
|
|
33367
34238
|
} catch {
|
|
33368
34239
|
throw new Error(
|
|
33369
34240
|
"Not logged in to devtunnel. Run: devtunnel user login"
|
|
33370
34241
|
);
|
|
33371
34242
|
}
|
|
33372
34243
|
const hostArgs = this.buildHostArgs(localPort);
|
|
33373
|
-
const child = (0,
|
|
34244
|
+
const child = (0, import_node_child_process5.spawn)("devtunnel", hostArgs, {
|
|
33374
34245
|
stdio: ["pipe", "pipe", "pipe"]
|
|
33375
34246
|
});
|
|
33376
34247
|
this.process = child;
|
|
@@ -33475,7 +34346,7 @@ ${lines.join("")}`
|
|
|
33475
34346
|
return void 0;
|
|
33476
34347
|
}
|
|
33477
34348
|
try {
|
|
33478
|
-
(0,
|
|
34349
|
+
(0, import_node_child_process5.execFileSync)("devtunnel", ["show", tunnelId], { stdio: "pipe" });
|
|
33479
34350
|
return tunnelId;
|
|
33480
34351
|
} catch {
|
|
33481
34352
|
const createArgs = ["create", tunnelId];
|
|
@@ -33483,7 +34354,7 @@ ${lines.join("")}`
|
|
|
33483
34354
|
createArgs.push("-a");
|
|
33484
34355
|
}
|
|
33485
34356
|
try {
|
|
33486
|
-
(0,
|
|
34357
|
+
(0, import_node_child_process5.execFileSync)("devtunnel", createArgs, { stdio: "pipe" });
|
|
33487
34358
|
return tunnelId;
|
|
33488
34359
|
} catch (err) {
|
|
33489
34360
|
throw new Error(
|
|
@@ -33498,7 +34369,7 @@ ${lines.join("")}`
|
|
|
33498
34369
|
return;
|
|
33499
34370
|
}
|
|
33500
34371
|
try {
|
|
33501
|
-
(0,
|
|
34372
|
+
(0, import_node_child_process5.execFileSync)(
|
|
33502
34373
|
"devtunnel",
|
|
33503
34374
|
["port", "create", tunnelId, "-p", String(localPort), "--protocol", "http"],
|
|
33504
34375
|
{ stdio: "pipe" }
|
|
@@ -33514,7 +34385,7 @@ ${lines.join("")}`
|
|
|
33514
34385
|
}
|
|
33515
34386
|
listTunnelPorts(tunnelId) {
|
|
33516
34387
|
try {
|
|
33517
|
-
const output = (0,
|
|
34388
|
+
const output = (0, import_node_child_process5.execFileSync)("devtunnel", ["port", "list", tunnelId, "-j"], { stdio: "pipe" });
|
|
33518
34389
|
const parsed = JSON.parse(output.toString());
|
|
33519
34390
|
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
34391
|
return items.map((item) => getPortNumber(item)).filter((value) => value !== void 0);
|
|
@@ -33526,7 +34397,7 @@ ${lines.join("")}`
|
|
|
33526
34397
|
}
|
|
33527
34398
|
hasTunnelPort(tunnelId, localPort) {
|
|
33528
34399
|
try {
|
|
33529
|
-
(0,
|
|
34400
|
+
(0, import_node_child_process5.execFileSync)(
|
|
33530
34401
|
"devtunnel",
|
|
33531
34402
|
["port", "show", tunnelId, "-p", String(localPort), "-j"],
|
|
33532
34403
|
{ stdio: "pipe" }
|
|
@@ -33580,25 +34451,282 @@ function createTransport(config) {
|
|
|
33580
34451
|
}
|
|
33581
34452
|
}
|
|
33582
34453
|
|
|
33583
|
-
// src/
|
|
34454
|
+
// src/startup.ts
|
|
34455
|
+
var fs16 = __toESM(require("fs"), 1);
|
|
34456
|
+
var path16 = __toESM(require("path"), 1);
|
|
34457
|
+
var readline = __toESM(require("readline/promises"), 1);
|
|
34458
|
+
var import_node_child_process6 = require("child_process");
|
|
33584
34459
|
function getDefaultNodeName() {
|
|
33585
34460
|
return getDeviceNodeName();
|
|
33586
34461
|
}
|
|
33587
34462
|
var DEFAULT_NODE_NAME = getDefaultNodeName();
|
|
33588
34463
|
var DEFAULT_NODE_PORT = 12345;
|
|
33589
34464
|
var SUPPORTED_TRANSPORTS = ["direct", "devtunnel", "tailscale"];
|
|
34465
|
+
var STARTUP_REQUIREMENTS = ["az", "devtunnel", "claude", "codex"];
|
|
33590
34466
|
function createDefaultConfig(storagePath = resolveDefaultStoragePath(), nodeName = DEFAULT_NODE_NAME) {
|
|
33591
34467
|
return {
|
|
33592
34468
|
node: { name: nodeName, port: DEFAULT_NODE_PORT },
|
|
33593
34469
|
transport: { type: "direct" },
|
|
33594
|
-
cluster: { seeds: [], heartbeatInterval:
|
|
34470
|
+
cluster: { seeds: [], heartbeatInterval: 12e3, electionTimeout: 36e3, apiKey: "" },
|
|
33595
34471
|
storage: { path: storagePath }
|
|
33596
34472
|
};
|
|
33597
34473
|
}
|
|
33598
34474
|
var DEFAULT_CONFIG3 = createDefaultConfig();
|
|
33599
|
-
function createRuntimeDefaultConfig(fileConfig) {
|
|
34475
|
+
function createRuntimeDefaultConfig(fileConfig, options = {}) {
|
|
33600
34476
|
const storagePath = fileConfig.storage?.path ?? resolveDefaultStoragePath();
|
|
33601
|
-
|
|
34477
|
+
const nodeName = options.ignorePersistedName ? getDeviceNodeName() : resolveDefaultNodeName(storagePath);
|
|
34478
|
+
return createDefaultConfig(storagePath, nodeName);
|
|
34479
|
+
}
|
|
34480
|
+
function writeLine(stream, message = "") {
|
|
34481
|
+
stream.write(`${message}
|
|
34482
|
+
`);
|
|
34483
|
+
}
|
|
34484
|
+
function createPromptSession(prompt) {
|
|
34485
|
+
if (prompt) {
|
|
34486
|
+
return {
|
|
34487
|
+
ask: prompt,
|
|
34488
|
+
close: async () => void 0
|
|
34489
|
+
};
|
|
34490
|
+
}
|
|
34491
|
+
if (!shouldPromptForStartOptions()) {
|
|
34492
|
+
return void 0;
|
|
34493
|
+
}
|
|
34494
|
+
const rl = readline.createInterface({
|
|
34495
|
+
input: process.stdin,
|
|
34496
|
+
output: process.stdout
|
|
34497
|
+
});
|
|
34498
|
+
return {
|
|
34499
|
+
ask: (question) => rl.question(question),
|
|
34500
|
+
close: async () => rl.close()
|
|
34501
|
+
};
|
|
34502
|
+
}
|
|
34503
|
+
function createDefaultCommandRunner(platform) {
|
|
34504
|
+
return (command, args, interactive = false) => {
|
|
34505
|
+
const result = (0, import_node_child_process6.spawnSync)(command, args, {
|
|
34506
|
+
encoding: "utf-8",
|
|
34507
|
+
shell: platform === "win32",
|
|
34508
|
+
stdio: interactive ? "inherit" : "pipe"
|
|
34509
|
+
});
|
|
34510
|
+
return {
|
|
34511
|
+
ok: result.status === 0 && !result.error,
|
|
34512
|
+
status: result.status,
|
|
34513
|
+
stdout: typeof result.stdout === "string" ? result.stdout : "",
|
|
34514
|
+
stderr: typeof result.stderr === "string" ? result.stderr : "",
|
|
34515
|
+
error: result.error?.message
|
|
34516
|
+
};
|
|
34517
|
+
};
|
|
34518
|
+
}
|
|
34519
|
+
function getNodeMetadataPath2(storagePath) {
|
|
34520
|
+
return path16.join(storagePath, "metadata.json");
|
|
34521
|
+
}
|
|
34522
|
+
function readStartupMetadataFile(storagePath) {
|
|
34523
|
+
try {
|
|
34524
|
+
const raw = JSON.parse(fs16.readFileSync(getNodeMetadataPath2(storagePath), "utf-8"));
|
|
34525
|
+
return typeof raw === "object" && raw !== null ? raw : {};
|
|
34526
|
+
} catch {
|
|
34527
|
+
return {};
|
|
34528
|
+
}
|
|
34529
|
+
}
|
|
34530
|
+
function writeStartupMetadataFile(storagePath, metadata) {
|
|
34531
|
+
fs16.mkdirSync(storagePath, { recursive: true });
|
|
34532
|
+
fs16.writeFileSync(getNodeMetadataPath2(storagePath), JSON.stringify(metadata, null, 2) + "\n", "utf-8");
|
|
34533
|
+
}
|
|
34534
|
+
function formatLocalDate(now) {
|
|
34535
|
+
const year = now.getFullYear();
|
|
34536
|
+
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
34537
|
+
const day = String(now.getDate()).padStart(2, "0");
|
|
34538
|
+
return `${year}-${month}-${day}`;
|
|
34539
|
+
}
|
|
34540
|
+
function isYesAnswer(value) {
|
|
34541
|
+
const normalized = value.trim().toLowerCase();
|
|
34542
|
+
return normalized === "y" || normalized === "yes";
|
|
34543
|
+
}
|
|
34544
|
+
async function confirm(ask, question) {
|
|
34545
|
+
const answer = await ask(`${question} [y/N]: `);
|
|
34546
|
+
return isYesAnswer(answer);
|
|
34547
|
+
}
|
|
34548
|
+
function isCommandAvailable(commandRunner, platform, command) {
|
|
34549
|
+
const lookupCommand = platform === "win32" ? "where" : "which";
|
|
34550
|
+
return commandRunner(lookupCommand, [command], false).ok;
|
|
34551
|
+
}
|
|
34552
|
+
function buildInstallCommand(requirement, platform) {
|
|
34553
|
+
switch (requirement) {
|
|
34554
|
+
case "az":
|
|
34555
|
+
if (platform === "darwin") {
|
|
34556
|
+
return { command: "brew", args: ["install", "azure-cli"] };
|
|
34557
|
+
}
|
|
34558
|
+
if (platform === "win32") {
|
|
34559
|
+
return { command: "winget", args: ["install", "--exact", "--id", "Microsoft.AzureCLI"] };
|
|
34560
|
+
}
|
|
34561
|
+
return void 0;
|
|
34562
|
+
case "devtunnel":
|
|
34563
|
+
if (platform === "darwin") {
|
|
34564
|
+
return { command: "brew", args: ["install", "--cask", "devtunnel"] };
|
|
34565
|
+
}
|
|
34566
|
+
if (platform === "win32") {
|
|
34567
|
+
return { command: "winget", args: ["install", "--exact", "--id", "Microsoft.devtunnel"] };
|
|
34568
|
+
}
|
|
34569
|
+
return void 0;
|
|
34570
|
+
case "claude":
|
|
34571
|
+
if (platform === "darwin") {
|
|
34572
|
+
return { command: "bash", args: ["-lc", "curl -fsSL https://claude.ai/install.sh | bash"] };
|
|
34573
|
+
}
|
|
34574
|
+
if (platform === "win32") {
|
|
34575
|
+
return {
|
|
34576
|
+
command: "powershell",
|
|
34577
|
+
args: ["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", "irm https://claude.ai/install.ps1 | iex"]
|
|
34578
|
+
};
|
|
34579
|
+
}
|
|
34580
|
+
return void 0;
|
|
34581
|
+
case "codex":
|
|
34582
|
+
return { command: "npm", args: ["install", "-g", "@openai/codex"] };
|
|
34583
|
+
}
|
|
34584
|
+
}
|
|
34585
|
+
function buildLoginCommand(requirement) {
|
|
34586
|
+
if (requirement === "az") {
|
|
34587
|
+
return { command: "az", args: ["login"] };
|
|
34588
|
+
}
|
|
34589
|
+
return { command: "devtunnel", args: ["user", "login"] };
|
|
34590
|
+
}
|
|
34591
|
+
function isAuthenticated(requirement, commandRunner) {
|
|
34592
|
+
const command = requirement === "az" ? { command: "az", args: ["account", "show"] } : { command: "devtunnel", args: ["user", "show"] };
|
|
34593
|
+
return commandRunner(command.command, command.args, false).ok;
|
|
34594
|
+
}
|
|
34595
|
+
function isRequirementSatisfied(requirement, status) {
|
|
34596
|
+
if (!status || status.installed !== true || status.status !== "ok") {
|
|
34597
|
+
return false;
|
|
34598
|
+
}
|
|
34599
|
+
if (requirement === "az" || requirement === "devtunnel") {
|
|
34600
|
+
return status.authenticated === true;
|
|
34601
|
+
}
|
|
34602
|
+
return true;
|
|
34603
|
+
}
|
|
34604
|
+
function resolveStartupRequirementsMetadata(storagePath) {
|
|
34605
|
+
const metadata = readStartupMetadataFile(storagePath).startupRequirements;
|
|
34606
|
+
return metadata && typeof metadata === "object" ? metadata : {};
|
|
34607
|
+
}
|
|
34608
|
+
function shouldSkipStartupRequirementsCheck(storagePath, now = /* @__PURE__ */ new Date()) {
|
|
34609
|
+
const metadata = resolveStartupRequirementsMetadata(storagePath);
|
|
34610
|
+
if (metadata.lastCheckedOn !== formatLocalDate(now)) {
|
|
34611
|
+
return false;
|
|
34612
|
+
}
|
|
34613
|
+
return STARTUP_REQUIREMENTS.every((requirement) => isRequirementSatisfied(requirement, metadata.components?.[requirement]));
|
|
34614
|
+
}
|
|
34615
|
+
async function ensureRequirementInstalled(requirement, platform, ask, commandRunner, stdout, stderr) {
|
|
34616
|
+
if (isCommandAvailable(commandRunner, platform, requirement)) {
|
|
34617
|
+
return { installed: true, status: "ok" };
|
|
34618
|
+
}
|
|
34619
|
+
if (!ask) {
|
|
34620
|
+
writeLine(stderr, `Missing required component "${requirement}". Start in a TTY to install it automatically.`);
|
|
34621
|
+
return { installed: false, status: "missing" };
|
|
34622
|
+
}
|
|
34623
|
+
const install = buildInstallCommand(requirement, platform);
|
|
34624
|
+
if (!install) {
|
|
34625
|
+
writeLine(stderr, `Missing required component "${requirement}", and automatic install is not supported on ${platform}.`);
|
|
34626
|
+
return { installed: false, status: "unsupported-platform" };
|
|
34627
|
+
}
|
|
34628
|
+
if (!await confirm(ask, `Required component "${requirement}" is missing. Install it now?`)) {
|
|
34629
|
+
return { installed: false, status: "missing" };
|
|
34630
|
+
}
|
|
34631
|
+
writeLine(stdout, `Installing ${requirement}...`);
|
|
34632
|
+
const result = commandRunner(install.command, install.args, true);
|
|
34633
|
+
if (!result.ok) {
|
|
34634
|
+
writeLine(stderr, `Failed to install ${requirement}.`);
|
|
34635
|
+
return { installed: false, status: "install-failed" };
|
|
34636
|
+
}
|
|
34637
|
+
return isCommandAvailable(commandRunner, platform, requirement) ? { installed: true, status: "ok" } : { installed: false, status: "install-failed" };
|
|
34638
|
+
}
|
|
34639
|
+
async function ensureRequirementAuthenticated(requirement, ask, commandRunner, stdout, stderr) {
|
|
34640
|
+
if (isAuthenticated(requirement, commandRunner)) {
|
|
34641
|
+
return { authenticated: true, status: "ok" };
|
|
34642
|
+
}
|
|
34643
|
+
if (!ask) {
|
|
34644
|
+
writeLine(stderr, `${requirement} is installed but not logged in. Start in a TTY to log in automatically.`);
|
|
34645
|
+
return { authenticated: false, status: "not-authenticated" };
|
|
34646
|
+
}
|
|
34647
|
+
if (!await confirm(ask, `"${requirement}" is installed but not logged in. Log in now?`)) {
|
|
34648
|
+
return { authenticated: false, status: "not-authenticated" };
|
|
34649
|
+
}
|
|
34650
|
+
writeLine(stdout, `Opening ${requirement} login...`);
|
|
34651
|
+
const login = buildLoginCommand(requirement);
|
|
34652
|
+
const result = commandRunner(login.command, login.args, true);
|
|
34653
|
+
if (!result.ok) {
|
|
34654
|
+
writeLine(stderr, `Failed to complete ${requirement} login.`);
|
|
34655
|
+
return { authenticated: false, status: "login-failed" };
|
|
34656
|
+
}
|
|
34657
|
+
return isAuthenticated(requirement, commandRunner) ? { authenticated: true, status: "ok" } : { authenticated: false, status: "login-failed" };
|
|
34658
|
+
}
|
|
34659
|
+
async function ensureStartupRequirements(storagePath, options = {}) {
|
|
34660
|
+
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
34661
|
+
if (shouldSkipStartupRequirementsCheck(storagePath, now)) {
|
|
34662
|
+
return {
|
|
34663
|
+
skipped: true,
|
|
34664
|
+
metadata: resolveStartupRequirementsMetadata(storagePath)
|
|
34665
|
+
};
|
|
34666
|
+
}
|
|
34667
|
+
const platform = options.platform ?? process.platform;
|
|
34668
|
+
const stdout = options.stdout ?? process.stdout;
|
|
34669
|
+
const stderr = options.stderr ?? process.stderr;
|
|
34670
|
+
const commandRunner = options.commandRunner ?? createDefaultCommandRunner(platform);
|
|
34671
|
+
const promptSession = createPromptSession(options.prompt);
|
|
34672
|
+
const checkedAt = now.toISOString();
|
|
34673
|
+
const checkedOn = formatLocalDate(now);
|
|
34674
|
+
const components = {};
|
|
34675
|
+
try {
|
|
34676
|
+
for (const requirement of STARTUP_REQUIREMENTS) {
|
|
34677
|
+
const installResult = await ensureRequirementInstalled(
|
|
34678
|
+
requirement,
|
|
34679
|
+
platform,
|
|
34680
|
+
promptSession?.ask,
|
|
34681
|
+
commandRunner,
|
|
34682
|
+
stdout,
|
|
34683
|
+
stderr
|
|
34684
|
+
);
|
|
34685
|
+
if (!installResult.installed) {
|
|
34686
|
+
components[requirement] = {
|
|
34687
|
+
installed: false,
|
|
34688
|
+
status: installResult.status,
|
|
34689
|
+
checkedAt
|
|
34690
|
+
};
|
|
34691
|
+
continue;
|
|
34692
|
+
}
|
|
34693
|
+
if (requirement === "az" || requirement === "devtunnel") {
|
|
34694
|
+
const authResult = await ensureRequirementAuthenticated(
|
|
34695
|
+
requirement,
|
|
34696
|
+
promptSession?.ask,
|
|
34697
|
+
commandRunner,
|
|
34698
|
+
stdout,
|
|
34699
|
+
stderr
|
|
34700
|
+
);
|
|
34701
|
+
components[requirement] = {
|
|
34702
|
+
installed: true,
|
|
34703
|
+
authenticated: authResult.authenticated,
|
|
34704
|
+
status: authResult.status,
|
|
34705
|
+
checkedAt
|
|
34706
|
+
};
|
|
34707
|
+
continue;
|
|
34708
|
+
}
|
|
34709
|
+
components[requirement] = {
|
|
34710
|
+
installed: true,
|
|
34711
|
+
status: "ok",
|
|
34712
|
+
checkedAt
|
|
34713
|
+
};
|
|
34714
|
+
}
|
|
34715
|
+
} finally {
|
|
34716
|
+
await promptSession?.close();
|
|
34717
|
+
}
|
|
34718
|
+
const metadataFile = readStartupMetadataFile(storagePath);
|
|
34719
|
+
const metadata = {
|
|
34720
|
+
lastCheckedAt: checkedAt,
|
|
34721
|
+
lastCheckedOn: checkedOn,
|
|
34722
|
+
components
|
|
34723
|
+
};
|
|
34724
|
+
metadataFile.startupRequirements = metadata;
|
|
34725
|
+
writeStartupMetadataFile(storagePath, metadataFile);
|
|
34726
|
+
return {
|
|
34727
|
+
skipped: false,
|
|
34728
|
+
metadata
|
|
34729
|
+
};
|
|
33602
34730
|
}
|
|
33603
34731
|
function parseArgs(argv) {
|
|
33604
34732
|
const result = {};
|
|
@@ -33636,13 +34764,19 @@ function parseArgs(argv) {
|
|
|
33636
34764
|
result.config = argv[++i];
|
|
33637
34765
|
}
|
|
33638
34766
|
break;
|
|
34767
|
+
case "--reset":
|
|
34768
|
+
result.reset = true;
|
|
34769
|
+
break;
|
|
34770
|
+
case "--disable-auth":
|
|
34771
|
+
result.disableAuth = true;
|
|
34772
|
+
break;
|
|
33639
34773
|
}
|
|
33640
34774
|
}
|
|
33641
34775
|
return result;
|
|
33642
34776
|
}
|
|
33643
|
-
function loadConfigFile(
|
|
34777
|
+
function loadConfigFile(path17) {
|
|
33644
34778
|
try {
|
|
33645
|
-
const raw = fs16.readFileSync(
|
|
34779
|
+
const raw = fs16.readFileSync(path17, "utf-8");
|
|
33646
34780
|
return JSON.parse(raw);
|
|
33647
34781
|
} catch {
|
|
33648
34782
|
return {};
|
|
@@ -33746,6 +34880,67 @@ async function promptStartOptions(args, fileConfig, defaults, prompt) {
|
|
|
33746
34880
|
await closePrompt?.();
|
|
33747
34881
|
}
|
|
33748
34882
|
}
|
|
34883
|
+
function applyStartMetadata(storagePath, args) {
|
|
34884
|
+
const startup = resolveNodeStartupMetadata(storagePath);
|
|
34885
|
+
const result = { ...args };
|
|
34886
|
+
const loaded = {};
|
|
34887
|
+
const persistedName = resolvePersistedDefaultNodeName(storagePath);
|
|
34888
|
+
if (persistedName && result.name === void 0) {
|
|
34889
|
+
loaded.name = persistedName;
|
|
34890
|
+
}
|
|
34891
|
+
if (startup.port !== void 0 && result.port === void 0) {
|
|
34892
|
+
result.port = startup.port;
|
|
34893
|
+
loaded.port = startup.port;
|
|
34894
|
+
}
|
|
34895
|
+
if (startup.transport && result.transport === void 0) {
|
|
34896
|
+
result.transport = startup.transport;
|
|
34897
|
+
loaded.transport = startup.transport;
|
|
34898
|
+
}
|
|
34899
|
+
if (startup.join && result.join === void 0) {
|
|
34900
|
+
result.join = startup.join;
|
|
34901
|
+
loaded.join = startup.join;
|
|
34902
|
+
}
|
|
34903
|
+
return {
|
|
34904
|
+
args: result,
|
|
34905
|
+
loaded: Object.keys(loaded).length > 0 ? loaded : void 0
|
|
34906
|
+
};
|
|
34907
|
+
}
|
|
34908
|
+
function shouldCollectStartOptions(args, storagePath) {
|
|
34909
|
+
return args.reset === true || !hasPersistedNodeStartupMetadata(storagePath);
|
|
34910
|
+
}
|
|
34911
|
+
function resolveRuntimeAuthMetadata(storagePath, disableAuth = false) {
|
|
34912
|
+
const persisted = resolveNodeAuthMetadata(storagePath);
|
|
34913
|
+
if (disableAuth) {
|
|
34914
|
+
return { ...persisted, enabled: false };
|
|
34915
|
+
}
|
|
34916
|
+
if (!persisted.enabled && !persisted.allowSameTenant && persisted.allowedUsers.length === 0) {
|
|
34917
|
+
return {
|
|
34918
|
+
enabled: true,
|
|
34919
|
+
allowSameTenant: false,
|
|
34920
|
+
allowedUsers: []
|
|
34921
|
+
};
|
|
34922
|
+
}
|
|
34923
|
+
return persisted;
|
|
34924
|
+
}
|
|
34925
|
+
function formatLoadedStartMetadata(info, authEnabled) {
|
|
34926
|
+
const lines = ["Loaded startup options from metadata:"];
|
|
34927
|
+
if (info.name) {
|
|
34928
|
+
lines.push(` Node: ${info.name}`);
|
|
34929
|
+
}
|
|
34930
|
+
if (info.port !== void 0) {
|
|
34931
|
+
lines.push(` Port: ${info.port}`);
|
|
34932
|
+
}
|
|
34933
|
+
if (info.transport) {
|
|
34934
|
+
lines.push(` Transport: ${info.transport}`);
|
|
34935
|
+
}
|
|
34936
|
+
if (info.join) {
|
|
34937
|
+
lines.push(` Join: ${info.join}`);
|
|
34938
|
+
}
|
|
34939
|
+
lines.push(` Auth: ${authEnabled ? "enabled" : "disabled"}`);
|
|
34940
|
+
return lines.join("\n");
|
|
34941
|
+
}
|
|
34942
|
+
|
|
34943
|
+
// src/main.ts
|
|
33749
34944
|
function formatBanner(info) {
|
|
33750
34945
|
const lines = [
|
|
33751
34946
|
`Node: ${info.name}`,
|
|
@@ -33753,6 +34948,9 @@ function formatBanner(info) {
|
|
|
33753
34948
|
`Endpoint: ${info.endpoint}`,
|
|
33754
34949
|
`Dashboard: http://localhost:${info.port}`
|
|
33755
34950
|
];
|
|
34951
|
+
if (info.dashboardOrigin) {
|
|
34952
|
+
lines.push(`Dashboard Tunnel: ${info.dashboardOrigin}`);
|
|
34953
|
+
}
|
|
33756
34954
|
const maxLen = Math.max(...lines.map((l) => l.length));
|
|
33757
34955
|
const innerWidth = maxLen + 4;
|
|
33758
34956
|
const top = ` \u256D${"\u2500".repeat(innerWidth)}\u256E`;
|
|
@@ -33774,16 +34972,53 @@ async function main() {
|
|
|
33774
34972
|
const args = parseArgs(process.argv.slice(2));
|
|
33775
34973
|
const configPath = args.config ?? "./config.json";
|
|
33776
34974
|
const fileConfig = loadConfigFile(configPath);
|
|
33777
|
-
const
|
|
33778
|
-
const
|
|
34975
|
+
const storagePath = fileConfig.storage?.path ?? resolveDefaultStoragePath();
|
|
34976
|
+
const hydratedArgs = args.reset ? { args: { ...args }, loaded: void 0 } : applyStartMetadata(storagePath, args);
|
|
34977
|
+
const defaults = createRuntimeDefaultConfig(fileConfig, {
|
|
34978
|
+
ignorePersistedName: args.reset === true
|
|
34979
|
+
});
|
|
34980
|
+
const resolvedArgs = shouldCollectStartOptions(args, storagePath) ? await promptStartOptions(
|
|
34981
|
+
args.reset ? args : hydratedArgs.args,
|
|
34982
|
+
fileConfig,
|
|
34983
|
+
defaults
|
|
34984
|
+
) : hydratedArgs.args;
|
|
33779
34985
|
const config = mergeConfig(defaults, fileConfig, resolvedArgs);
|
|
33780
34986
|
persistDefaultNodeName(config.storage.path, config.node.name);
|
|
34987
|
+
persistNodeStartupMetadata(config.storage.path, {
|
|
34988
|
+
port: config.node.port,
|
|
34989
|
+
transport: config.transport.type,
|
|
34990
|
+
join: resolvedArgs.join
|
|
34991
|
+
});
|
|
34992
|
+
const authMetadata = resolveRuntimeAuthMetadata(config.storage.path, resolvedArgs.disableAuth === true);
|
|
34993
|
+
if (!resolvedArgs.disableAuth) {
|
|
34994
|
+
persistNodeAuthMetadata(config.storage.path, authMetadata);
|
|
34995
|
+
}
|
|
34996
|
+
console.log("Checking startup requirements (az, devtunnel, claude, codex)...");
|
|
34997
|
+
const startupRequirements = await ensureStartupRequirements(config.storage.path);
|
|
34998
|
+
console.log(
|
|
34999
|
+
startupRequirements.skipped ? "Startup requirements already verified today; skipping checks." : "Startup requirements check complete."
|
|
35000
|
+
);
|
|
33781
35001
|
const logDir = nodePath.join(config.storage.path, "logs");
|
|
33782
35002
|
const logger = createLogger({
|
|
33783
35003
|
component: "node",
|
|
33784
35004
|
logDir,
|
|
33785
35005
|
console: true
|
|
33786
35006
|
});
|
|
35007
|
+
const nodeAuth = new AzureCliNodeAuth(config.storage.path, {
|
|
35008
|
+
logger: logger.child("azure-auth"),
|
|
35009
|
+
settingsProvider: () => authMetadata
|
|
35010
|
+
});
|
|
35011
|
+
if (hydratedArgs.loaded) {
|
|
35012
|
+
console.log("");
|
|
35013
|
+
console.log(formatLoadedStartMetadata(hydratedArgs.loaded, authMetadata.enabled));
|
|
35014
|
+
console.log("");
|
|
35015
|
+
}
|
|
35016
|
+
if (authMetadata.enabled) {
|
|
35017
|
+
nodeAuth.getAccessToken();
|
|
35018
|
+
setRequestAuthHeadersProvider(() => nodeAuth.getAuthorizationHeaders());
|
|
35019
|
+
} else {
|
|
35020
|
+
setRequestAuthHeadersProvider(null);
|
|
35021
|
+
}
|
|
33787
35022
|
const meshyNode = new MeshyNode(config, {
|
|
33788
35023
|
logger,
|
|
33789
35024
|
transportFactory: createTransport
|
|
@@ -33793,9 +35028,24 @@ async function main() {
|
|
|
33793
35028
|
const previewServer = new PreviewServer(previewSessionManager);
|
|
33794
35029
|
const previewPort = config.node.port + 1;
|
|
33795
35030
|
const actualPreviewPort = await previewServer.start(previewPort);
|
|
35031
|
+
let dashboardTransport = null;
|
|
35032
|
+
let dashboardOrigin;
|
|
33796
35033
|
let previewTransport = null;
|
|
33797
35034
|
let previewOrigin;
|
|
33798
35035
|
let deps;
|
|
35036
|
+
function createDashboardTransportConfig() {
|
|
35037
|
+
return {
|
|
35038
|
+
type: "devtunnel",
|
|
35039
|
+
devtunnel: {
|
|
35040
|
+
id: resolveOrCreateDevTunnelId(
|
|
35041
|
+
config.storage.path,
|
|
35042
|
+
meshyNode.getNodeRegistry().getSelf().id,
|
|
35043
|
+
"dashboard"
|
|
35044
|
+
),
|
|
35045
|
+
allowAnonymous: false
|
|
35046
|
+
}
|
|
35047
|
+
};
|
|
35048
|
+
}
|
|
33799
35049
|
function createPreviewTransportConfig() {
|
|
33800
35050
|
return {
|
|
33801
35051
|
type: "devtunnel",
|
|
@@ -33809,11 +35059,92 @@ async function main() {
|
|
|
33809
35059
|
}
|
|
33810
35060
|
};
|
|
33811
35061
|
}
|
|
35062
|
+
function setAdvertisedDashboardOrigin(origin) {
|
|
35063
|
+
dashboardOrigin = origin;
|
|
35064
|
+
deps.dashboardOrigin = origin;
|
|
35065
|
+
meshyNode.getNodeRegistry().updateDashboardOrigin(meshyNode.getNodeRegistry().getSelf().id, origin);
|
|
35066
|
+
}
|
|
33812
35067
|
function setAdvertisedPreviewOrigin(origin) {
|
|
33813
35068
|
previewOrigin = origin;
|
|
33814
35069
|
deps.previewOrigin = origin;
|
|
33815
35070
|
meshyNode.getNodeRegistry().updatePreviewOrigin(meshyNode.getNodeRegistry().getSelf().id, origin);
|
|
33816
35071
|
}
|
|
35072
|
+
function shouldPublishDashboardTunnel() {
|
|
35073
|
+
return authMetadata.enabled && (meshyNode.getTransportType() === "devtunnel" || meshyNode.isDevTunnelEnabled());
|
|
35074
|
+
}
|
|
35075
|
+
async function stopDashboardTransport() {
|
|
35076
|
+
if (!dashboardTransport) {
|
|
35077
|
+
if (dashboardOrigin) {
|
|
35078
|
+
setAdvertisedDashboardOrigin(void 0);
|
|
35079
|
+
}
|
|
35080
|
+
return;
|
|
35081
|
+
}
|
|
35082
|
+
await dashboardTransport.stop().catch(() => void 0);
|
|
35083
|
+
dashboardTransport = null;
|
|
35084
|
+
setAdvertisedDashboardOrigin(void 0);
|
|
35085
|
+
meshyNode.getLogger().info("stopped dashboard tunnel", {
|
|
35086
|
+
reason: "dashboard transport no longer required",
|
|
35087
|
+
mainTransportType: meshyNode.getTransportType(),
|
|
35088
|
+
sidecarEnabled: meshyNode.isDevTunnelEnabled()
|
|
35089
|
+
});
|
|
35090
|
+
}
|
|
35091
|
+
async function restartDashboardTransport(transportConfig) {
|
|
35092
|
+
const previousTransport = dashboardTransport;
|
|
35093
|
+
const previousOrigin = dashboardOrigin;
|
|
35094
|
+
let nextTransport = null;
|
|
35095
|
+
try {
|
|
35096
|
+
nextTransport = createTransport(transportConfig);
|
|
35097
|
+
await nextTransport.start(config.node.port);
|
|
35098
|
+
const nextOrigin = await nextTransport.getEndpoint();
|
|
35099
|
+
dashboardTransport = nextTransport;
|
|
35100
|
+
setAdvertisedDashboardOrigin(nextOrigin);
|
|
35101
|
+
meshyNode.getLogger().info("started dashboard tunnel", {
|
|
35102
|
+
dashboardOrigin: nextOrigin,
|
|
35103
|
+
mainTransportType: meshyNode.getTransportType(),
|
|
35104
|
+
sidecarEnabled: meshyNode.isDevTunnelEnabled()
|
|
35105
|
+
});
|
|
35106
|
+
if (previousTransport) {
|
|
35107
|
+
await previousTransport.stop().catch(() => void 0);
|
|
35108
|
+
}
|
|
35109
|
+
} catch (err) {
|
|
35110
|
+
if (nextTransport) {
|
|
35111
|
+
await nextTransport.stop().catch(() => void 0);
|
|
35112
|
+
}
|
|
35113
|
+
dashboardTransport = previousTransport;
|
|
35114
|
+
setAdvertisedDashboardOrigin(previousOrigin);
|
|
35115
|
+
meshyNode.getLogger().warn("failed to start dashboard transport", {
|
|
35116
|
+
error: err instanceof Error ? err.message : String(err),
|
|
35117
|
+
port: config.node.port,
|
|
35118
|
+
transportType: transportConfig.type
|
|
35119
|
+
});
|
|
35120
|
+
}
|
|
35121
|
+
}
|
|
35122
|
+
async function syncDashboardTransport(reason) {
|
|
35123
|
+
if (!authMetadata.enabled) {
|
|
35124
|
+
await stopDashboardTransport();
|
|
35125
|
+
return;
|
|
35126
|
+
}
|
|
35127
|
+
if (!shouldPublishDashboardTunnel()) {
|
|
35128
|
+
meshyNode.getLogger().info("skipping dashboard tunnel", {
|
|
35129
|
+
reason,
|
|
35130
|
+
mainTransportType: meshyNode.getTransportType(),
|
|
35131
|
+
sidecarEnabled: meshyNode.isDevTunnelEnabled(),
|
|
35132
|
+
authEnabled: authMetadata.enabled
|
|
35133
|
+
});
|
|
35134
|
+
await stopDashboardTransport();
|
|
35135
|
+
return;
|
|
35136
|
+
}
|
|
35137
|
+
if (dashboardTransport && await dashboardTransport.isHealthy().catch(() => false)) {
|
|
35138
|
+
meshyNode.getLogger().debug("dashboard tunnel already active", {
|
|
35139
|
+
reason,
|
|
35140
|
+
dashboardOrigin,
|
|
35141
|
+
mainTransportType: meshyNode.getTransportType(),
|
|
35142
|
+
sidecarEnabled: meshyNode.isDevTunnelEnabled()
|
|
35143
|
+
});
|
|
35144
|
+
return;
|
|
35145
|
+
}
|
|
35146
|
+
await restartDashboardTransport(createDashboardTransportConfig());
|
|
35147
|
+
}
|
|
33817
35148
|
async function restartPreviewTransport(transportConfig) {
|
|
33818
35149
|
const previousTransport = previewTransport;
|
|
33819
35150
|
const previousOrigin = previewOrigin;
|
|
@@ -33849,7 +35180,11 @@ async function main() {
|
|
|
33849
35180
|
eventBus: meshyNode.getEventBus(),
|
|
33850
35181
|
engineRegistry: meshyNode.getEngineRegistry(),
|
|
33851
35182
|
logger: meshyNode.getLogger(),
|
|
33852
|
-
config: {
|
|
35183
|
+
config: {
|
|
35184
|
+
apiKey: config.cluster.apiKey,
|
|
35185
|
+
authMetadata,
|
|
35186
|
+
validateBearerToken: authMetadata.enabled ? (header) => nodeAuth.validateAuthorizationHeader(header) : void 0
|
|
35187
|
+
},
|
|
33853
35188
|
workDir: meshyNode.getWorkDir(),
|
|
33854
35189
|
persistNodeNamePreference: (name) => persistDefaultNodeName(config.storage.path, name),
|
|
33855
35190
|
joinCurrentNodeToCluster: async (leaderEndpoint) => {
|
|
@@ -33859,12 +35194,28 @@ async function main() {
|
|
|
33859
35194
|
await meshyNode.leaveCluster();
|
|
33860
35195
|
},
|
|
33861
35196
|
switchTransport: async (type) => {
|
|
33862
|
-
|
|
35197
|
+
const endpoint = await meshyNode.switchTransport(type);
|
|
35198
|
+
persistNodeStartupTransport(config.storage.path, type);
|
|
35199
|
+
await syncDashboardTransport(`switchTransport:${type}`);
|
|
35200
|
+
return endpoint;
|
|
33863
35201
|
},
|
|
33864
35202
|
getTransportType: () => meshyNode.getTransportType(),
|
|
33865
|
-
enableDevTunnel: async () =>
|
|
33866
|
-
|
|
35203
|
+
enableDevTunnel: async () => {
|
|
35204
|
+
const endpoint = await meshyNode.enableDevTunnel();
|
|
35205
|
+
persistNodeStartupTransport(config.storage.path, "devtunnel");
|
|
35206
|
+
await syncDashboardTransport("enableDevTunnel");
|
|
35207
|
+
return endpoint;
|
|
35208
|
+
},
|
|
35209
|
+
disableDevTunnel: async () => {
|
|
35210
|
+
await meshyNode.disableDevTunnel();
|
|
35211
|
+
persistNodeStartupTransport(
|
|
35212
|
+
config.storage.path,
|
|
35213
|
+
meshyNode.getTransportType()
|
|
35214
|
+
);
|
|
35215
|
+
await syncDashboardTransport("disableDevTunnel");
|
|
35216
|
+
},
|
|
33867
35217
|
isDevTunnelEnabled: () => meshyNode.isDevTunnelEnabled(),
|
|
35218
|
+
dashboardOrigin,
|
|
33868
35219
|
ensurePreviewOrigin: async () => {
|
|
33869
35220
|
if (previewTransport && !await previewTransport.isHealthy()) {
|
|
33870
35221
|
await previewTransport.stop().catch(() => void 0);
|
|
@@ -33880,7 +35231,16 @@ async function main() {
|
|
|
33880
35231
|
};
|
|
33881
35232
|
deps.previewSessionManager = previewSessionManager;
|
|
33882
35233
|
deps.previewPort = actualPreviewPort;
|
|
35234
|
+
deps.dashboardOrigin = dashboardOrigin;
|
|
33883
35235
|
deps.previewOrigin = previewOrigin;
|
|
35236
|
+
meshyNode.getLogger().info("configured node auth mode", {
|
|
35237
|
+
authEnabled: authMetadata.enabled,
|
|
35238
|
+
allowSameTenant: authMetadata.allowSameTenant,
|
|
35239
|
+
allowedUsersCount: authMetadata.allowedUsers.length,
|
|
35240
|
+
mainTransportType: meshyNode.getTransportType(),
|
|
35241
|
+
sidecarEnabled: meshyNode.isDevTunnelEnabled()
|
|
35242
|
+
});
|
|
35243
|
+
await syncDashboardTransport("startup");
|
|
33884
35244
|
const previewHealthTimer = setInterval(() => {
|
|
33885
35245
|
void (async () => {
|
|
33886
35246
|
if (!previewTransport) return;
|
|
@@ -33894,6 +35254,19 @@ async function main() {
|
|
|
33894
35254
|
});
|
|
33895
35255
|
})();
|
|
33896
35256
|
}, config.cluster.heartbeatInterval);
|
|
35257
|
+
const dashboardHealthTimer = setInterval(() => {
|
|
35258
|
+
void (async () => {
|
|
35259
|
+
if (!dashboardTransport) return;
|
|
35260
|
+
const healthy = await dashboardTransport.isHealthy().catch(() => false);
|
|
35261
|
+
if (healthy) return;
|
|
35262
|
+
await dashboardTransport.stop().catch(() => void 0);
|
|
35263
|
+
dashboardTransport = null;
|
|
35264
|
+
setAdvertisedDashboardOrigin(void 0);
|
|
35265
|
+
meshyNode.getLogger().warn("dashboard transport became unhealthy and was cleared", {
|
|
35266
|
+
port: config.node.port
|
|
35267
|
+
});
|
|
35268
|
+
})();
|
|
35269
|
+
}, config.cluster.heartbeatInterval);
|
|
33897
35270
|
const app = createServer2(deps);
|
|
33898
35271
|
const server = app.listen(config.node.port, () => {
|
|
33899
35272
|
const self = meshyNode.getNodeRegistry().getSelf();
|
|
@@ -33904,7 +35277,8 @@ async function main() {
|
|
|
33904
35277
|
role,
|
|
33905
35278
|
term,
|
|
33906
35279
|
endpoint: self.endpoint,
|
|
33907
|
-
port: config.node.port
|
|
35280
|
+
port: config.node.port,
|
|
35281
|
+
dashboardOrigin
|
|
33908
35282
|
});
|
|
33909
35283
|
console.log("");
|
|
33910
35284
|
console.log(banner);
|
|
@@ -33916,7 +35290,11 @@ async function main() {
|
|
|
33916
35290
|
shuttingDown = true;
|
|
33917
35291
|
console.log("\nShutting down...");
|
|
33918
35292
|
try {
|
|
35293
|
+
clearInterval(dashboardHealthTimer);
|
|
33919
35294
|
clearInterval(previewHealthTimer);
|
|
35295
|
+
if (dashboardTransport) {
|
|
35296
|
+
await dashboardTransport.stop();
|
|
35297
|
+
}
|
|
33920
35298
|
if (previewTransport) {
|
|
33921
35299
|
await previewTransport.stop();
|
|
33922
35300
|
}
|
|
@@ -33945,9 +35323,12 @@ if (isDirectRun) {
|
|
|
33945
35323
|
DEFAULT_CONFIG,
|
|
33946
35324
|
DEFAULT_NODE_NAME,
|
|
33947
35325
|
DEFAULT_NODE_PORT,
|
|
35326
|
+
applyStartMetadata,
|
|
33948
35327
|
createDefaultConfig,
|
|
33949
35328
|
createRuntimeDefaultConfig,
|
|
35329
|
+
ensureStartupRequirements,
|
|
33950
35330
|
formatBanner,
|
|
35331
|
+
formatLoadedStartMetadata,
|
|
33951
35332
|
getDefaultNodeName,
|
|
33952
35333
|
isDirectRunPath,
|
|
33953
35334
|
loadConfigFile,
|
|
@@ -33955,7 +35336,11 @@ if (isDirectRun) {
|
|
|
33955
35336
|
mergeConfig,
|
|
33956
35337
|
parseArgs,
|
|
33957
35338
|
promptStartOptions,
|
|
33958
|
-
|
|
35339
|
+
resolveRuntimeAuthMetadata,
|
|
35340
|
+
resolveStartupRequirementsMetadata,
|
|
35341
|
+
shouldCollectStartOptions,
|
|
35342
|
+
shouldPromptForStartOptions,
|
|
35343
|
+
shouldSkipStartupRequirementsCheck
|
|
33959
35344
|
});
|
|
33960
35345
|
/*! Bundled license information:
|
|
33961
35346
|
|