meshy-node 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/main.cjs CHANGED
@@ -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
- if (Object.keys(metadata).length === 0) {
23032
- if (fs2.existsSync(metadataPath)) {
23033
- fs2.rmSync(metadataPath, { force: true });
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
- fs2.mkdirSync(storagePath, { recursive: true });
23038
- fs2.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2) + "\n", "utf-8");
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 = { ...this.config.transport, type: transportType };
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.type = transportType;
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 tunnel = this.transportFactory({ type: "devtunnel" });
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({ tasks: result.tasks, total: result.total });
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 child = (0, import_node_child_process4.spawn)("devtunnel", ["host", "-p", String(localPort), "-a"], {
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
- const url = parsePublicUrl(text);
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
- lines.push(data.toString());
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: false
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({ type: "devtunnel" });
33656
+ await restartPreviewTransport(createPreviewTransportConfig());
33443
33657
  return previewOrigin;
33444
33658
  }
33445
33659
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "meshy-node",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "private": false,
5
5
  "description": "Standalone Meshy node package with bundled runtime and dashboard assets.",
6
6
  "type": "commonjs",