meshy-node 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dashboard/assets/DashboardPage-JeeIeAmu.js +205 -0
- package/dashboard/assets/{DiffTab-dBUCX2wA.js → DiffTab-aDF2LESi.js} +1 -1
- package/dashboard/assets/{FilesTab-CVOmz6J4.js → FilesTab-OaQpvvhB.js} +1 -1
- package/dashboard/assets/{PreviewTab-wOQI0Jve.js → PreviewTab-B90YmJvT.js} +1 -1
- package/dashboard/assets/{folder-BAyQ0haY.js → folder-_tAVJh-g.js} +1 -1
- package/dashboard/assets/{index-oSMR3Dci.js → index-BwIQRcjg.js} +1 -1
- package/dashboard/index.html +1 -1
- package/main.cjs +253 -39
- package/package.json +1 -1
- package/dashboard/assets/DashboardPage-Dw4TA1Va.js +0 -205
package/main.cjs
CHANGED
|
@@ -23015,12 +23015,22 @@ function readNodeMetadata(storagePath) {
|
|
|
23015
23015
|
return {};
|
|
23016
23016
|
}
|
|
23017
23017
|
}
|
|
23018
|
+
function writeNodeMetadata(storagePath, metadata) {
|
|
23019
|
+
const metadataPath = getNodeMetadataPath(storagePath);
|
|
23020
|
+
if (Object.keys(metadata).length === 0) {
|
|
23021
|
+
if (fs2.existsSync(metadataPath)) {
|
|
23022
|
+
fs2.rmSync(metadataPath, { force: true });
|
|
23023
|
+
}
|
|
23024
|
+
return;
|
|
23025
|
+
}
|
|
23026
|
+
fs2.mkdirSync(storagePath, { recursive: true });
|
|
23027
|
+
fs2.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2) + "\n", "utf-8");
|
|
23028
|
+
}
|
|
23018
23029
|
function resolveDefaultNodeName(storagePath, deviceName = getDeviceNodeName()) {
|
|
23019
23030
|
const preferredName = readNodeMetadata(storagePath).defaultNodeName?.trim();
|
|
23020
23031
|
return preferredName && preferredName.length > 0 ? preferredName : deviceName;
|
|
23021
23032
|
}
|
|
23022
23033
|
function persistDefaultNodeName(storagePath, name, deviceName = getDeviceNodeName()) {
|
|
23023
|
-
const metadataPath = getNodeMetadataPath(storagePath);
|
|
23024
23034
|
const metadata = readNodeMetadata(storagePath);
|
|
23025
23035
|
const normalizedName = name.trim();
|
|
23026
23036
|
if (normalizedName.length > 0 && normalizedName !== deviceName) {
|
|
@@ -23028,14 +23038,38 @@ function persistDefaultNodeName(storagePath, name, deviceName = getDeviceNodeNam
|
|
|
23028
23038
|
} else {
|
|
23029
23039
|
delete metadata.defaultNodeName;
|
|
23030
23040
|
}
|
|
23031
|
-
|
|
23032
|
-
|
|
23033
|
-
|
|
23041
|
+
writeNodeMetadata(storagePath, metadata);
|
|
23042
|
+
}
|
|
23043
|
+
function resolvePersistedDevTunnelId(storagePath, kind) {
|
|
23044
|
+
return readNodeMetadata(storagePath).devTunnelIds?.[kind]?.trim() || void 0;
|
|
23045
|
+
}
|
|
23046
|
+
function createDefaultDevTunnelId(nodeId, kind) {
|
|
23047
|
+
const normalizedNodeId = nodeId.trim().toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
23048
|
+
const safeNodeId = normalizedNodeId.length > 0 ? normalizedNodeId : "node";
|
|
23049
|
+
return `meshy-${kind}-${safeNodeId}`;
|
|
23050
|
+
}
|
|
23051
|
+
function persistDevTunnelId(storagePath, kind, id) {
|
|
23052
|
+
const metadata = readNodeMetadata(storagePath);
|
|
23053
|
+
const normalizedId = id?.trim();
|
|
23054
|
+
if (normalizedId) {
|
|
23055
|
+
metadata.devTunnelIds ??= {};
|
|
23056
|
+
metadata.devTunnelIds[kind] = normalizedId;
|
|
23057
|
+
} else if (metadata.devTunnelIds) {
|
|
23058
|
+
delete metadata.devTunnelIds[kind];
|
|
23059
|
+
if (Object.keys(metadata.devTunnelIds).length === 0) {
|
|
23060
|
+
delete metadata.devTunnelIds;
|
|
23034
23061
|
}
|
|
23035
|
-
return;
|
|
23036
23062
|
}
|
|
23037
|
-
|
|
23038
|
-
|
|
23063
|
+
writeNodeMetadata(storagePath, metadata);
|
|
23064
|
+
}
|
|
23065
|
+
function resolveOrCreateDevTunnelId(storagePath, nodeId, kind) {
|
|
23066
|
+
const existingId = resolvePersistedDevTunnelId(storagePath, kind);
|
|
23067
|
+
if (existingId) {
|
|
23068
|
+
return existingId;
|
|
23069
|
+
}
|
|
23070
|
+
const generatedId = createDefaultDevTunnelId(nodeId, kind);
|
|
23071
|
+
persistDevTunnelId(storagePath, kind, generatedId);
|
|
23072
|
+
return generatedId;
|
|
23039
23073
|
}
|
|
23040
23074
|
|
|
23041
23075
|
// ../../packages/core/src/file-store.ts
|
|
@@ -23491,7 +23525,7 @@ function parseTask(value) {
|
|
|
23491
23525
|
}
|
|
23492
23526
|
const status = asTaskStatus(value.status);
|
|
23493
23527
|
const priority = asTaskPriority(value.priority);
|
|
23494
|
-
if (typeof value.id !== "string" || typeof value.title !== "string" || typeof value.description !== "string" || typeof value.agent !== "string" || value.project !== null && typeof value.project !== "string" || value.effectiveProjectPath !== null && value.effectiveProjectPath !== void 0 && typeof value.effectiveProjectPath !== "string" || !isPlainObject(value.payload) || status === null || priority === null || value.assignedTo !== null && typeof value.assignedTo !== "string" || typeof value.createdBy !== "string" || value.result !== null && !isPlainObject(value.result) || value.error !== null && typeof value.error !== "string" || typeof value.retryCount !== "number" || !Number.isFinite(value.retryCount) || typeof value.maxRetries !== "number" || !Number.isFinite(value.maxRetries) || typeof value.createdAt !== "number" || !Number.isFinite(value.createdAt) || typeof value.updatedAt !== "number" || !Number.isFinite(value.updatedAt)) {
|
|
23528
|
+
if (typeof value.id !== "string" || typeof value.title !== "string" || typeof value.description !== "string" || typeof value.agent !== "string" || value.project !== null && typeof value.project !== "string" || value.effectiveProjectPath !== null && value.effectiveProjectPath !== void 0 && typeof value.effectiveProjectPath !== "string" || !isPlainObject(value.payload) || status === null || priority === null || value.assignedTo !== null && typeof value.assignedTo !== "string" || value.assignedNodeName !== void 0 && value.assignedNodeName !== null && typeof value.assignedNodeName !== "string" || typeof value.createdBy !== "string" || value.result !== null && !isPlainObject(value.result) || value.error !== null && typeof value.error !== "string" || typeof value.retryCount !== "number" || !Number.isFinite(value.retryCount) || typeof value.maxRetries !== "number" || !Number.isFinite(value.maxRetries) || typeof value.createdAt !== "number" || !Number.isFinite(value.createdAt) || typeof value.updatedAt !== "number" || !Number.isFinite(value.updatedAt)) {
|
|
23495
23529
|
return null;
|
|
23496
23530
|
}
|
|
23497
23531
|
return {
|
|
@@ -23505,6 +23539,7 @@ function parseTask(value) {
|
|
|
23505
23539
|
status,
|
|
23506
23540
|
priority,
|
|
23507
23541
|
assignedTo: value.assignedTo,
|
|
23542
|
+
assignedNodeName: typeof value.assignedNodeName === "string" ? value.assignedNodeName : null,
|
|
23508
23543
|
createdBy: value.createdBy,
|
|
23509
23544
|
result: value.result === null ? null : clone(value.result),
|
|
23510
23545
|
error: value.error,
|
|
@@ -24029,6 +24064,7 @@ var TaskEngine = class {
|
|
|
24029
24064
|
status: "pending",
|
|
24030
24065
|
priority: input.priority ?? "normal",
|
|
24031
24066
|
assignedTo: null,
|
|
24067
|
+
assignedNodeName: null,
|
|
24032
24068
|
createdBy: input.createdBy,
|
|
24033
24069
|
result: null,
|
|
24034
24070
|
error: null,
|
|
@@ -24133,6 +24169,7 @@ var TaskEngine = class {
|
|
|
24133
24169
|
status: "pending",
|
|
24134
24170
|
retryCount: newRetryCount,
|
|
24135
24171
|
assignedTo: null,
|
|
24172
|
+
assignedNodeName: null,
|
|
24136
24173
|
error,
|
|
24137
24174
|
updatedAt: now
|
|
24138
24175
|
});
|
|
@@ -24178,6 +24215,7 @@ var TaskEngine = class {
|
|
|
24178
24215
|
const updated = this.store.updateTask(taskId, {
|
|
24179
24216
|
status: "assigned",
|
|
24180
24217
|
assignedTo: nodeId,
|
|
24218
|
+
assignedNodeName: node.name,
|
|
24181
24219
|
updatedAt: now
|
|
24182
24220
|
});
|
|
24183
24221
|
this.eventBus.emit("task.assigned", { taskId, nodeId });
|
|
@@ -24214,6 +24252,7 @@ var TaskEngine = class {
|
|
|
24214
24252
|
this.store.updateTask(task.id, {
|
|
24215
24253
|
status: "assigned",
|
|
24216
24254
|
assignedTo: targetNode.id,
|
|
24255
|
+
assignedNodeName: targetNode.name,
|
|
24217
24256
|
updatedAt: assignedAt
|
|
24218
24257
|
});
|
|
24219
24258
|
nodeLoad.set(targetNode.id, (nodeLoad.get(targetNode.id) ?? 0) + 1);
|
|
@@ -24291,6 +24330,7 @@ var TaskEngine = class {
|
|
|
24291
24330
|
status: "pending",
|
|
24292
24331
|
retryCount: newRetryCount,
|
|
24293
24332
|
assignedTo: null,
|
|
24333
|
+
assignedNodeName: null,
|
|
24294
24334
|
error,
|
|
24295
24335
|
updatedAt: now
|
|
24296
24336
|
});
|
|
@@ -24333,6 +24373,7 @@ var TaskEngine = class {
|
|
|
24333
24373
|
status: "pending",
|
|
24334
24374
|
retryCount: 0,
|
|
24335
24375
|
assignedTo: null,
|
|
24376
|
+
assignedNodeName: null,
|
|
24336
24377
|
error: null,
|
|
24337
24378
|
result: null,
|
|
24338
24379
|
updatedAt: now
|
|
@@ -26054,11 +26095,12 @@ var MeshyNode = class {
|
|
|
26054
26095
|
this.eventBus = new EventBus();
|
|
26055
26096
|
this.store = new FileStore();
|
|
26056
26097
|
this.store.open(this.config.storage.path);
|
|
26098
|
+
const nodeId = this.loadOrCreateNodeId();
|
|
26057
26099
|
this.nodeRegistry = new NodeRegistry(this.store, this.eventBus, this.logger);
|
|
26100
|
+
this.config.transport = this.resolveTransportConfig(this.config.transport.type, nodeId);
|
|
26058
26101
|
this.transport = this.transportFactory(this.config.transport);
|
|
26059
26102
|
await this.transport.start(this.config.node.port);
|
|
26060
26103
|
const endpoint = await this.transport.getEndpoint();
|
|
26061
|
-
const nodeId = this.loadOrCreateNodeId();
|
|
26062
26104
|
const now = Date.now();
|
|
26063
26105
|
const workDir = path10.resolve(this.config.node.workDir ?? process.cwd());
|
|
26064
26106
|
this.selfInfo = {
|
|
@@ -26254,7 +26296,7 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
26254
26296
|
let nextTransport = null;
|
|
26255
26297
|
await this.transport.stop();
|
|
26256
26298
|
try {
|
|
26257
|
-
const newTransportConfig =
|
|
26299
|
+
const newTransportConfig = this.resolveTransportConfig(transportType, this.selfInfo.id);
|
|
26258
26300
|
nextTransport = this.transportFactory(newTransportConfig);
|
|
26259
26301
|
await nextTransport.start(this.config.node.port);
|
|
26260
26302
|
const newEndpoint = await nextTransport.getEndpoint();
|
|
@@ -26262,7 +26304,7 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
26262
26304
|
this.selfInfo.endpoint = newEndpoint;
|
|
26263
26305
|
this.selfInfo.transportType = transportType;
|
|
26264
26306
|
this.nodeRegistry.updateEndpoint(this.selfInfo.id, newEndpoint);
|
|
26265
|
-
this.config.transport
|
|
26307
|
+
this.config.transport = newTransportConfig;
|
|
26266
26308
|
this.eventBus.emit("transport.changed", {
|
|
26267
26309
|
nodeId: this.selfInfo.id,
|
|
26268
26310
|
transportType,
|
|
@@ -26294,7 +26336,8 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
26294
26336
|
if (this.devtunnelTransport) {
|
|
26295
26337
|
return this.devtunnelTransport.getEndpoint();
|
|
26296
26338
|
}
|
|
26297
|
-
const
|
|
26339
|
+
const tunnelConfig = this.resolveStableDevTunnelConfig("sidecar", this.selfInfo.id);
|
|
26340
|
+
const tunnel = this.transportFactory(tunnelConfig);
|
|
26298
26341
|
this.devtunnelTransport = tunnel;
|
|
26299
26342
|
try {
|
|
26300
26343
|
await tunnel.start(this.config.node.port);
|
|
@@ -26338,6 +26381,35 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
26338
26381
|
this.selfInfo.role = current.role;
|
|
26339
26382
|
this.selfInfo.status = current.status;
|
|
26340
26383
|
}
|
|
26384
|
+
cloneTransportConfig(config) {
|
|
26385
|
+
return {
|
|
26386
|
+
type: config.type,
|
|
26387
|
+
...config.direct ? { direct: { ...config.direct } } : {},
|
|
26388
|
+
...config.devtunnel ? { devtunnel: { ...config.devtunnel } } : {}
|
|
26389
|
+
};
|
|
26390
|
+
}
|
|
26391
|
+
resolveTransportConfig(transportType, nodeId) {
|
|
26392
|
+
if (transportType === "devtunnel") {
|
|
26393
|
+
return this.resolveStableDevTunnelConfig("node", nodeId, this.config.transport.devtunnel);
|
|
26394
|
+
}
|
|
26395
|
+
const nextConfig = this.cloneTransportConfig(this.config.transport);
|
|
26396
|
+
nextConfig.type = transportType;
|
|
26397
|
+
return nextConfig;
|
|
26398
|
+
}
|
|
26399
|
+
resolveStableDevTunnelConfig(kind, nodeId, currentConfig) {
|
|
26400
|
+
const explicitId = currentConfig?.id?.trim();
|
|
26401
|
+
const tunnelId = explicitId || resolveOrCreateDevTunnelId(this.config.storage.path, nodeId, kind);
|
|
26402
|
+
if (explicitId) {
|
|
26403
|
+
persistDevTunnelId(this.config.storage.path, kind, explicitId);
|
|
26404
|
+
}
|
|
26405
|
+
return {
|
|
26406
|
+
type: "devtunnel",
|
|
26407
|
+
devtunnel: {
|
|
26408
|
+
id: tunnelId,
|
|
26409
|
+
allowAnonymous: currentConfig?.allowAnonymous ?? true
|
|
26410
|
+
}
|
|
26411
|
+
};
|
|
26412
|
+
}
|
|
26341
26413
|
/**
|
|
26342
26414
|
* Handle a task received via pull-based dispatch (keepalive channel).
|
|
26343
26415
|
* Mirrors the logic of POST /api/worker/execute but without the HTTP layer.
|
|
@@ -30634,6 +30706,7 @@ var TaskListResponse = external_exports.object({
|
|
|
30634
30706
|
status: external_exports.enum(["pending", "assigned", "running", "completed", "failed", "cancelled", "archived"]),
|
|
30635
30707
|
priority: external_exports.enum(["low", "normal", "high", "critical"]),
|
|
30636
30708
|
assignedTo: external_exports.string().nullable(),
|
|
30709
|
+
assignedNodeName: external_exports.string().nullable().optional(),
|
|
30637
30710
|
createdBy: external_exports.string(),
|
|
30638
30711
|
result: external_exports.record(external_exports.unknown()).nullable(),
|
|
30639
30712
|
error: external_exports.string().nullable(),
|
|
@@ -31969,10 +32042,23 @@ var ACTIVE_STATUSES = /* @__PURE__ */ new Set(["pending", "assigned", "running"]
|
|
|
31969
32042
|
function asyncHandler3(fn) {
|
|
31970
32043
|
return (req, res, next) => fn(req, res, next).catch(next);
|
|
31971
32044
|
}
|
|
32045
|
+
function withAssignedNodeName(task, nodeRegistry) {
|
|
32046
|
+
if (task.assignedNodeName || !task.assignedTo) {
|
|
32047
|
+
return task;
|
|
32048
|
+
}
|
|
32049
|
+
const node = nodeRegistry.getNode(task.assignedTo);
|
|
32050
|
+
if (!node?.name) {
|
|
32051
|
+
return task;
|
|
32052
|
+
}
|
|
32053
|
+
return {
|
|
32054
|
+
...task,
|
|
32055
|
+
assignedNodeName: node.name
|
|
32056
|
+
};
|
|
32057
|
+
}
|
|
31972
32058
|
function createTaskRoutes() {
|
|
31973
32059
|
const router = (0, import_express3.Router)();
|
|
31974
32060
|
router.post("/", asyncHandler3(async (req, res) => {
|
|
31975
|
-
const { taskEngine } = req.app.locals.deps;
|
|
32061
|
+
const { taskEngine, nodeRegistry } = req.app.locals.deps;
|
|
31976
32062
|
const body = CreateTaskBody.parse(req.body);
|
|
31977
32063
|
const task = taskEngine.createTask({
|
|
31978
32064
|
title: body.title,
|
|
@@ -31985,13 +32071,13 @@ function createTaskRoutes() {
|
|
|
31985
32071
|
});
|
|
31986
32072
|
if (body.assignTo) {
|
|
31987
32073
|
const assigned = taskEngine.assignTask(task.id, body.assignTo);
|
|
31988
|
-
res.status(201).json(assigned);
|
|
32074
|
+
res.status(201).json(withAssignedNodeName(assigned, nodeRegistry));
|
|
31989
32075
|
return;
|
|
31990
32076
|
}
|
|
31991
|
-
res.status(201).json(task);
|
|
32077
|
+
res.status(201).json(withAssignedNodeName(task, nodeRegistry));
|
|
31992
32078
|
}));
|
|
31993
32079
|
router.get("/", asyncHandler3(async (req, res) => {
|
|
31994
|
-
const { taskEngine } = req.app.locals.deps;
|
|
32080
|
+
const { taskEngine, nodeRegistry } = req.app.locals.deps;
|
|
31995
32081
|
const query = TaskListQuery.parse(req.query);
|
|
31996
32082
|
const filter = {};
|
|
31997
32083
|
if (query.status) filter.status = query.status;
|
|
@@ -32000,7 +32086,10 @@ function createTaskRoutes() {
|
|
|
32000
32086
|
if (query.limit) filter.limit = query.limit;
|
|
32001
32087
|
if (query.offset) filter.offset = query.offset;
|
|
32002
32088
|
const result = taskEngine.listTasks(filter);
|
|
32003
|
-
res.json({
|
|
32089
|
+
res.json({
|
|
32090
|
+
tasks: result.tasks.map((task) => withAssignedNodeName(task, nodeRegistry)),
|
|
32091
|
+
total: result.total
|
|
32092
|
+
});
|
|
32004
32093
|
}));
|
|
32005
32094
|
router.post("/batch/delete", asyncHandler3(async (req, res) => {
|
|
32006
32095
|
const { taskEngine } = req.app.locals.deps;
|
|
@@ -32034,15 +32123,15 @@ function createTaskRoutes() {
|
|
|
32034
32123
|
res.json({ results });
|
|
32035
32124
|
}));
|
|
32036
32125
|
router.get("/:id", asyncHandler3(async (req, res) => {
|
|
32037
|
-
const { taskEngine } = req.app.locals.deps;
|
|
32126
|
+
const { taskEngine, nodeRegistry } = req.app.locals.deps;
|
|
32038
32127
|
const task = taskEngine.getTask(req.params.id);
|
|
32039
32128
|
if (!task) {
|
|
32040
32129
|
throw new MeshyError("TASK_NOT_FOUND", `Task ${req.params.id} not found`, 404);
|
|
32041
32130
|
}
|
|
32042
|
-
res.json(task);
|
|
32131
|
+
res.json(withAssignedNodeName(task, nodeRegistry));
|
|
32043
32132
|
}));
|
|
32044
32133
|
router.patch("/:id", asyncHandler3(async (req, res) => {
|
|
32045
|
-
const { taskEngine, logger: rootLogger } = req.app.locals.deps;
|
|
32134
|
+
const { taskEngine, nodeRegistry, logger: rootLogger } = req.app.locals.deps;
|
|
32046
32135
|
const log = rootLogger.child("tasks/patch");
|
|
32047
32136
|
const updates = UpdateTaskBody.parse(req.body);
|
|
32048
32137
|
const existing = taskEngine.getTask(req.params.id);
|
|
@@ -32055,7 +32144,7 @@ function createTaskRoutes() {
|
|
|
32055
32144
|
currentStatus: existing.status,
|
|
32056
32145
|
incomingStatus: updates.status
|
|
32057
32146
|
});
|
|
32058
|
-
res.json(existing);
|
|
32147
|
+
res.json(withAssignedNodeName(existing, nodeRegistry));
|
|
32059
32148
|
return;
|
|
32060
32149
|
}
|
|
32061
32150
|
if (updates.status === "archived" && !ARCHIVABLE_STATUSES.has(existing.status)) {
|
|
@@ -32071,14 +32160,14 @@ function createTaskRoutes() {
|
|
|
32071
32160
|
currentStatus: existing.status,
|
|
32072
32161
|
incomingStatus: updates.status
|
|
32073
32162
|
});
|
|
32074
|
-
res.json(existing);
|
|
32163
|
+
res.json(withAssignedNodeName(existing, nodeRegistry));
|
|
32075
32164
|
return;
|
|
32076
32165
|
}
|
|
32077
32166
|
const task = taskEngine.updateTask(req.params.id, updates);
|
|
32078
32167
|
if (!task) {
|
|
32079
32168
|
throw new MeshyError("TASK_NOT_FOUND", `Task ${req.params.id} not found`, 404);
|
|
32080
32169
|
}
|
|
32081
|
-
res.json(task);
|
|
32170
|
+
res.json(withAssignedNodeName(task, nodeRegistry));
|
|
32082
32171
|
}));
|
|
32083
32172
|
router.delete("/:id", asyncHandler3(async (req, res) => {
|
|
32084
32173
|
const { taskEngine } = req.app.locals.deps;
|
|
@@ -32126,15 +32215,15 @@ function createTaskRoutes() {
|
|
|
32126
32215
|
res.json({ ok: true });
|
|
32127
32216
|
}));
|
|
32128
32217
|
router.post("/:id/assign", asyncHandler3(async (req, res) => {
|
|
32129
|
-
const { taskEngine } = req.app.locals.deps;
|
|
32218
|
+
const { taskEngine, nodeRegistry } = req.app.locals.deps;
|
|
32130
32219
|
const body = AssignTaskBody.parse(req.body);
|
|
32131
32220
|
const task = taskEngine.assignTask(req.params.id, body.nodeId);
|
|
32132
|
-
res.json(task);
|
|
32221
|
+
res.json(withAssignedNodeName(task, nodeRegistry));
|
|
32133
32222
|
}));
|
|
32134
32223
|
router.post("/:id/retry", asyncHandler3(async (req, res) => {
|
|
32135
|
-
const { taskEngine } = req.app.locals.deps;
|
|
32224
|
+
const { taskEngine, nodeRegistry } = req.app.locals.deps;
|
|
32136
32225
|
const task = taskEngine.retryTask(req.params.id);
|
|
32137
|
-
res.json(task);
|
|
32226
|
+
res.json(withAssignedNodeName(task, nodeRegistry));
|
|
32138
32227
|
}));
|
|
32139
32228
|
router.get("/:id/logs", asyncHandler3(async (req, res) => {
|
|
32140
32229
|
const { engineRegistry, taskEngine, nodeRegistry, logger: rootLogger } = req.app.locals.deps;
|
|
@@ -33045,6 +33134,10 @@ function isInstalled(cmd) {
|
|
|
33045
33134
|
var DevTunnelTransport = class {
|
|
33046
33135
|
process = null;
|
|
33047
33136
|
publicUrl = null;
|
|
33137
|
+
config;
|
|
33138
|
+
constructor(config) {
|
|
33139
|
+
this.config = config ?? { id: "", allowAnonymous: true };
|
|
33140
|
+
}
|
|
33048
33141
|
async start(localPort) {
|
|
33049
33142
|
if (this.process) {
|
|
33050
33143
|
throw new Error("Transport already started");
|
|
@@ -33061,7 +33154,8 @@ var DevTunnelTransport = class {
|
|
|
33061
33154
|
"Not logged in to devtunnel. Run: devtunnel user login"
|
|
33062
33155
|
);
|
|
33063
33156
|
}
|
|
33064
|
-
const
|
|
33157
|
+
const hostArgs = this.buildHostArgs(localPort);
|
|
33158
|
+
const child = (0, import_node_child_process4.spawn)("devtunnel", hostArgs, {
|
|
33065
33159
|
stdio: ["pipe", "pipe", "pipe"]
|
|
33066
33160
|
});
|
|
33067
33161
|
this.process = child;
|
|
@@ -33075,16 +33169,20 @@ var DevTunnelTransport = class {
|
|
|
33075
33169
|
const onData = (data) => {
|
|
33076
33170
|
const text = data.toString();
|
|
33077
33171
|
lines.push(text);
|
|
33078
|
-
|
|
33079
|
-
if (url) {
|
|
33080
|
-
clearTimeout(timeout);
|
|
33081
|
-
child.stdout?.removeListener("data", onData);
|
|
33082
|
-
child.stderr?.removeListener("data", onErrData);
|
|
33083
|
-
resolve10(url.replace(/\/+$/, ""));
|
|
33084
|
-
}
|
|
33172
|
+
maybeResolve(text);
|
|
33085
33173
|
};
|
|
33086
33174
|
const onErrData = (data) => {
|
|
33087
|
-
|
|
33175
|
+
const text = data.toString();
|
|
33176
|
+
lines.push(text);
|
|
33177
|
+
maybeResolve(text);
|
|
33178
|
+
};
|
|
33179
|
+
const maybeResolve = (text) => {
|
|
33180
|
+
const url = parsePublicUrl(text);
|
|
33181
|
+
if (!url) return;
|
|
33182
|
+
clearTimeout(timeout);
|
|
33183
|
+
child.stdout?.removeListener("data", onData);
|
|
33184
|
+
child.stderr?.removeListener("data", onErrData);
|
|
33185
|
+
resolve10(url.replace(/\/+$/, ""));
|
|
33088
33186
|
};
|
|
33089
33187
|
child.stdout?.on("data", onData);
|
|
33090
33188
|
child.stderr?.on("data", onErrData);
|
|
@@ -33141,14 +33239,117 @@ ${lines.join("")}`
|
|
|
33141
33239
|
return {
|
|
33142
33240
|
estimatedLatency: 100,
|
|
33143
33241
|
maxPayloadSize: 1e7,
|
|
33144
|
-
persistent:
|
|
33242
|
+
persistent: this.config.id.trim().length > 0
|
|
33145
33243
|
};
|
|
33146
33244
|
}
|
|
33245
|
+
buildHostArgs(localPort) {
|
|
33246
|
+
const tunnelId = this.ensureTunnelExists();
|
|
33247
|
+
if (!tunnelId) {
|
|
33248
|
+
const args = ["host", "-p", String(localPort)];
|
|
33249
|
+
if (this.config.allowAnonymous !== false) {
|
|
33250
|
+
args.push("-a");
|
|
33251
|
+
}
|
|
33252
|
+
return args;
|
|
33253
|
+
}
|
|
33254
|
+
this.ensureTunnelPort(tunnelId, localPort);
|
|
33255
|
+
return ["host", tunnelId];
|
|
33256
|
+
}
|
|
33257
|
+
ensureTunnelExists() {
|
|
33258
|
+
const tunnelId = this.config.id.trim();
|
|
33259
|
+
if (!tunnelId) {
|
|
33260
|
+
return void 0;
|
|
33261
|
+
}
|
|
33262
|
+
try {
|
|
33263
|
+
(0, import_node_child_process4.execFileSync)("devtunnel", ["show", tunnelId], { stdio: "pipe" });
|
|
33264
|
+
return tunnelId;
|
|
33265
|
+
} catch {
|
|
33266
|
+
const createArgs = ["create", tunnelId];
|
|
33267
|
+
if (this.config.allowAnonymous !== false) {
|
|
33268
|
+
createArgs.push("-a");
|
|
33269
|
+
}
|
|
33270
|
+
try {
|
|
33271
|
+
(0, import_node_child_process4.execFileSync)("devtunnel", createArgs, { stdio: "pipe" });
|
|
33272
|
+
return tunnelId;
|
|
33273
|
+
} catch (err) {
|
|
33274
|
+
throw new Error(
|
|
33275
|
+
`Failed to create devtunnel "${tunnelId}": ${formatCommandError(err)}`
|
|
33276
|
+
);
|
|
33277
|
+
}
|
|
33278
|
+
}
|
|
33279
|
+
}
|
|
33280
|
+
ensureTunnelPort(tunnelId, localPort) {
|
|
33281
|
+
const ports = this.listTunnelPorts(tunnelId);
|
|
33282
|
+
if (ports.includes(localPort)) {
|
|
33283
|
+
return;
|
|
33284
|
+
}
|
|
33285
|
+
try {
|
|
33286
|
+
(0, import_node_child_process4.execFileSync)(
|
|
33287
|
+
"devtunnel",
|
|
33288
|
+
["port", "create", tunnelId, "-p", String(localPort), "--protocol", "http"],
|
|
33289
|
+
{ stdio: "pipe" }
|
|
33290
|
+
);
|
|
33291
|
+
} catch (err) {
|
|
33292
|
+
if (this.isExistingPortConflict(err) && this.hasTunnelPort(tunnelId, localPort)) {
|
|
33293
|
+
return;
|
|
33294
|
+
}
|
|
33295
|
+
throw new Error(
|
|
33296
|
+
`Failed to configure port ${localPort} for devtunnel "${tunnelId}": ${formatCommandError(err)}`
|
|
33297
|
+
);
|
|
33298
|
+
}
|
|
33299
|
+
}
|
|
33300
|
+
listTunnelPorts(tunnelId) {
|
|
33301
|
+
try {
|
|
33302
|
+
const output = (0, import_node_child_process4.execFileSync)("devtunnel", ["port", "list", tunnelId, "-j"], { stdio: "pipe" });
|
|
33303
|
+
const parsed = JSON.parse(output.toString());
|
|
33304
|
+
const items = Array.isArray(parsed) ? parsed : parsed && typeof parsed === "object" && Array.isArray(parsed.ports) ? parsed.ports : parsed && typeof parsed === "object" && Array.isArray(parsed.value) ? parsed.value : [];
|
|
33305
|
+
return items.map((item) => getPortNumber(item)).filter((value) => value !== void 0);
|
|
33306
|
+
} catch (err) {
|
|
33307
|
+
throw new Error(
|
|
33308
|
+
`Failed to list ports for devtunnel "${tunnelId}": ${formatCommandError(err)}`
|
|
33309
|
+
);
|
|
33310
|
+
}
|
|
33311
|
+
}
|
|
33312
|
+
hasTunnelPort(tunnelId, localPort) {
|
|
33313
|
+
try {
|
|
33314
|
+
(0, import_node_child_process4.execFileSync)(
|
|
33315
|
+
"devtunnel",
|
|
33316
|
+
["port", "show", tunnelId, "-p", String(localPort), "-j"],
|
|
33317
|
+
{ stdio: "pipe" }
|
|
33318
|
+
);
|
|
33319
|
+
return true;
|
|
33320
|
+
} catch {
|
|
33321
|
+
return false;
|
|
33322
|
+
}
|
|
33323
|
+
}
|
|
33324
|
+
isExistingPortConflict(error) {
|
|
33325
|
+
return formatCommandError(error).toLowerCase().includes("conflicts with an existing port");
|
|
33326
|
+
}
|
|
33147
33327
|
};
|
|
33148
33328
|
function parsePublicUrl(output) {
|
|
33149
33329
|
const match = output.match(/https?:\/\/[^\s"',]+/);
|
|
33150
33330
|
return match ? match[0] : null;
|
|
33151
33331
|
}
|
|
33332
|
+
function formatCommandError(error) {
|
|
33333
|
+
if (!error || typeof error !== "object") {
|
|
33334
|
+
return String(error);
|
|
33335
|
+
}
|
|
33336
|
+
const stdout = "stdout" in error && typeof error.stdout === "string" ? error.stdout : Buffer.isBuffer(error.stdout) ? error.stdout.toString() : "";
|
|
33337
|
+
const stderr = "stderr" in error && typeof error.stderr === "string" ? error.stderr : Buffer.isBuffer(error.stderr) ? error.stderr.toString() : "";
|
|
33338
|
+
const message = "message" in error && typeof error.message === "string" ? error.message : String(error);
|
|
33339
|
+
const details = `${stdout}
|
|
33340
|
+
${stderr}`.trim();
|
|
33341
|
+
return details.length > 0 ? details : message;
|
|
33342
|
+
}
|
|
33343
|
+
function getPortNumber(value) {
|
|
33344
|
+
if (!value || typeof value !== "object") {
|
|
33345
|
+
return void 0;
|
|
33346
|
+
}
|
|
33347
|
+
const portValue = "portNumber" in value ? value.portNumber : "port" in value ? value.port : void 0;
|
|
33348
|
+
return typeof portValue === "number" ? Number.isFinite(portValue) ? portValue : void 0 : typeof portValue === "string" ? (() => {
|
|
33349
|
+
const parsed = Number(portValue);
|
|
33350
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
33351
|
+
})() : void 0;
|
|
33352
|
+
}
|
|
33152
33353
|
|
|
33153
33354
|
// ../../packages/transport/src/interface.ts
|
|
33154
33355
|
function createTransport(config) {
|
|
@@ -33156,7 +33357,7 @@ function createTransport(config) {
|
|
|
33156
33357
|
case "direct":
|
|
33157
33358
|
return new DirectTransport(config.direct?.host);
|
|
33158
33359
|
case "devtunnel":
|
|
33159
|
-
return new DevTunnelTransport();
|
|
33360
|
+
return new DevTunnelTransport(config.devtunnel);
|
|
33160
33361
|
case "tailscale":
|
|
33161
33362
|
throw new Error(`Transport type "${config.type}" is not implemented yet`);
|
|
33162
33363
|
default:
|
|
@@ -33380,6 +33581,19 @@ async function main() {
|
|
|
33380
33581
|
let previewTransport = null;
|
|
33381
33582
|
let previewOrigin;
|
|
33382
33583
|
let deps;
|
|
33584
|
+
function createPreviewTransportConfig() {
|
|
33585
|
+
return {
|
|
33586
|
+
type: "devtunnel",
|
|
33587
|
+
devtunnel: {
|
|
33588
|
+
id: resolveOrCreateDevTunnelId(
|
|
33589
|
+
config.storage.path,
|
|
33590
|
+
meshyNode.getNodeRegistry().getSelf().id,
|
|
33591
|
+
"preview"
|
|
33592
|
+
),
|
|
33593
|
+
allowAnonymous: true
|
|
33594
|
+
}
|
|
33595
|
+
};
|
|
33596
|
+
}
|
|
33383
33597
|
function setAdvertisedPreviewOrigin(origin) {
|
|
33384
33598
|
previewOrigin = origin;
|
|
33385
33599
|
deps.previewOrigin = origin;
|
|
@@ -33439,7 +33653,7 @@ async function main() {
|
|
|
33439
33653
|
if (previewOrigin?.includes("devtunnels.ms") && previewTransport) {
|
|
33440
33654
|
return previewOrigin;
|
|
33441
33655
|
}
|
|
33442
|
-
await restartPreviewTransport(
|
|
33656
|
+
await restartPreviewTransport(createPreviewTransportConfig());
|
|
33443
33657
|
return previewOrigin;
|
|
33444
33658
|
}
|
|
33445
33659
|
};
|