meshy-node 0.2.4 → 0.2.6

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
@@ -25760,7 +25760,7 @@ var require_application = __commonJS({
25760
25760
  "../../node_modules/.pnpm/express@4.22.1/node_modules/express/lib/application.js"(exports2, module2) {
25761
25761
  "use strict";
25762
25762
  var finalhandler = require_finalhandler();
25763
- var Router11 = require_router();
25763
+ var Router12 = require_router();
25764
25764
  var methods = require_methods();
25765
25765
  var middleware = require_init();
25766
25766
  var query = require_query();
@@ -25825,7 +25825,7 @@ var require_application = __commonJS({
25825
25825
  };
25826
25826
  app.lazyrouter = function lazyrouter() {
25827
25827
  if (!this._router) {
25828
- this._router = new Router11({
25828
+ this._router = new Router12({
25829
25829
  caseSensitive: this.enabled("case sensitive routing"),
25830
25830
  strict: this.enabled("strict routing")
25831
25831
  });
@@ -27690,7 +27690,7 @@ var require_express = __commonJS({
27690
27690
  var mixin = require_merge_descriptors();
27691
27691
  var proto = require_application();
27692
27692
  var Route = require_route();
27693
- var Router11 = require_router();
27693
+ var Router12 = require_router();
27694
27694
  var req = require_request();
27695
27695
  var res = require_response();
27696
27696
  exports2 = module2.exports = createApplication;
@@ -27713,7 +27713,7 @@ var require_express = __commonJS({
27713
27713
  exports2.request = req;
27714
27714
  exports2.response = res;
27715
27715
  exports2.Route = Route;
27716
- exports2.Router = Router11;
27716
+ exports2.Router = Router12;
27717
27717
  exports2.json = bodyParser.json;
27718
27718
  exports2.query = require_query();
27719
27719
  exports2.raw = bodyParser.raw;
@@ -32335,6 +32335,7 @@ var fs3 = __toESM(require("fs"), 1);
32335
32335
  var path3 = __toESM(require("path"), 1);
32336
32336
 
32337
32337
  // ../../packages/core/src/shared/types.ts
32338
+ var DEFAULT_TASK_SHARE_TENANT = "72f988bf-86f1-41af-91ab-2d7cd011db47";
32338
32339
  var TASK_EXECUTION_MODES = ["bypass", "plan", "edit", "dangerous"];
32339
32340
  var MeshyError = class extends Error {
32340
32341
  constructor(code, message, statusCode, details) {
@@ -32387,6 +32388,7 @@ var FILE_NAMES = {
32387
32388
  cluster: "cluster.json",
32388
32389
  nodes: "nodes.json",
32389
32390
  tasks: "tasks.json",
32391
+ shares: "shares.json",
32390
32392
  election: "election.json"
32391
32393
  };
32392
32394
  var FileStore = class {
@@ -32395,6 +32397,7 @@ var FileStore = class {
32395
32397
  cluster = null;
32396
32398
  nodes = /* @__PURE__ */ new Map();
32397
32399
  tasks = /* @__PURE__ */ new Map();
32400
+ shares = /* @__PURE__ */ new Map();
32398
32401
  election = /* @__PURE__ */ new Map();
32399
32402
  dirtySections = /* @__PURE__ */ new Set();
32400
32403
  constructor(options = {}) {
@@ -32410,6 +32413,7 @@ var FileStore = class {
32410
32413
  this.cluster = this.loadCluster();
32411
32414
  this.replaceMap(this.nodes, this.loadNodes());
32412
32415
  this.replaceMap(this.tasks, this.loadTasks());
32416
+ this.replaceMap(this.shares, this.loadTaskShares());
32413
32417
  this.replaceMap(this.election, this.loadElection());
32414
32418
  this.flushDirtySections();
32415
32419
  }
@@ -32422,6 +32426,7 @@ var FileStore = class {
32422
32426
  this.cluster = null;
32423
32427
  this.nodes.clear();
32424
32428
  this.tasks.clear();
32429
+ this.shares.clear();
32425
32430
  this.election.clear();
32426
32431
  this.dirtySections.clear();
32427
32432
  }
@@ -32562,6 +32567,46 @@ var FileStore = class {
32562
32567
  }
32563
32568
  return metrics;
32564
32569
  }
32570
+ createTaskShare(share) {
32571
+ this.ensureOpen();
32572
+ const copy = clone(share);
32573
+ this.shares.set(copy.id, copy);
32574
+ this.persistSection("shares");
32575
+ return clone(copy);
32576
+ }
32577
+ getTaskShare(id) {
32578
+ this.ensureOpen();
32579
+ const share = this.shares.get(id);
32580
+ return share === void 0 ? null : clone(share);
32581
+ }
32582
+ getTaskShareByTaskId(taskId) {
32583
+ this.ensureOpen();
32584
+ for (const share of this.shares.values()) {
32585
+ if (share.taskId === taskId && share.revokedAt === void 0) {
32586
+ return clone(share);
32587
+ }
32588
+ }
32589
+ return null;
32590
+ }
32591
+ getAllTaskShares() {
32592
+ this.ensureOpen();
32593
+ return Array.from(this.shares.values(), (share) => clone(share));
32594
+ }
32595
+ updateTaskShare(id, updates) {
32596
+ this.ensureOpen();
32597
+ const current = this.shares.get(id);
32598
+ if (current === void 0) {
32599
+ return null;
32600
+ }
32601
+ const merged = {
32602
+ ...current,
32603
+ ...clone(updates),
32604
+ id: current.id
32605
+ };
32606
+ this.shares.set(id, merged);
32607
+ this.persistSection("shares");
32608
+ return clone(merged);
32609
+ }
32565
32610
  getElectionValue(key) {
32566
32611
  this.ensureOpen();
32567
32612
  return this.election.get(key) ?? null;
@@ -32633,6 +32678,26 @@ var FileStore = class {
32633
32678
  }
32634
32679
  return tasks;
32635
32680
  }
32681
+ loadTaskShares() {
32682
+ const raw = this.readJsonFile("shares");
32683
+ if (!isPlainObject(raw)) {
32684
+ this.markDirty("shares");
32685
+ return /* @__PURE__ */ new Map();
32686
+ }
32687
+ const shares = /* @__PURE__ */ new Map();
32688
+ for (const [key, value] of Object.entries(raw)) {
32689
+ const share = parseTaskShare(value);
32690
+ if (share === null) {
32691
+ this.markDirty("shares");
32692
+ continue;
32693
+ }
32694
+ if (share.id !== key) {
32695
+ this.markDirty("shares");
32696
+ }
32697
+ shares.set(share.id, share);
32698
+ }
32699
+ return shares;
32700
+ }
32636
32701
  loadElection() {
32637
32702
  const raw = this.readJsonFile("election");
32638
32703
  if (!isPlainObject(raw)) {
@@ -32698,6 +32763,8 @@ var FileStore = class {
32698
32763
  return Object.fromEntries(sortEntries(this.nodes));
32699
32764
  case "tasks":
32700
32765
  return Object.fromEntries(sortEntries(this.tasks));
32766
+ case "shares":
32767
+ return Object.fromEntries(sortEntries(this.shares));
32701
32768
  case "election":
32702
32769
  return Object.fromEntries(sortEntries(this.election));
32703
32770
  }
@@ -32824,6 +32891,29 @@ function parseTask(value) {
32824
32891
  updatedAt: value.updatedAt
32825
32892
  };
32826
32893
  }
32894
+ function parseTaskShare(value) {
32895
+ if (!isPlainObject(value)) {
32896
+ return null;
32897
+ }
32898
+ if (typeof value.id !== "string" || typeof value.taskId !== "string" || typeof value.createdAt !== "number" || !Number.isFinite(value.createdAt) || value.revokedAt !== void 0 && (typeof value.revokedAt !== "number" || !Number.isFinite(value.revokedAt))) {
32899
+ return null;
32900
+ }
32901
+ return {
32902
+ id: value.id,
32903
+ taskId: value.taskId,
32904
+ tenant: asTaskShareTenant(value.tenant) ?? DEFAULT_TASK_SHARE_TENANT,
32905
+ scope: asTaskShareScope(value.scope) ?? "chat",
32906
+ createdAt: value.createdAt,
32907
+ revokedAt: typeof value.revokedAt === "number" ? value.revokedAt : void 0
32908
+ };
32909
+ }
32910
+ function asTaskShareTenant(value) {
32911
+ if (value === "microsoft") return DEFAULT_TASK_SHARE_TENANT;
32912
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
32913
+ }
32914
+ function asTaskShareScope(value) {
32915
+ return value === "chat" || value === "filesPreview" ? value : null;
32916
+ }
32827
32917
  function asNodeRole(value) {
32828
32918
  return isNodeRole(value) ? value : null;
32829
32919
  }
@@ -33887,6 +33977,19 @@ var TaskEngine = class {
33887
33977
  getMetrics() {
33888
33978
  return this.store.getTaskMetrics();
33889
33979
  }
33980
+ // ── Task Shares ─────────────────────────────────────────────────────
33981
+ createTaskShare(share) {
33982
+ return this.store.createTaskShare(share);
33983
+ }
33984
+ getTaskShare(id) {
33985
+ return this.store.getTaskShare(id);
33986
+ }
33987
+ getTaskShareByTaskId(taskId) {
33988
+ return this.store.getTaskShareByTaskId(taskId);
33989
+ }
33990
+ updateTaskShare(id, updates) {
33991
+ return this.store.updateTaskShare(id, updates);
33992
+ }
33890
33993
  // ── Helpers ──────────────────────────────────────────────────────────
33891
33994
  /** Calculate exponential backoff: min(2^retryCount * 1000, 30000) ms */
33892
33995
  getRetryBackoff(retryCount) {
@@ -41487,6 +41590,10 @@ var SendMessageBody = external_exports.union([
41487
41590
  var TaskLogsQuery = external_exports.object({
41488
41591
  after: external_exports.coerce.number().int().min(0).optional()
41489
41592
  });
41593
+ var CreateTaskShareBody = external_exports.object({
41594
+ tenant: external_exports.string().trim().min(1).max(128).default(DEFAULT_TASK_SHARE_TENANT),
41595
+ scope: external_exports.enum(["chat", "filesPreview"]).default("chat")
41596
+ }).default({});
41490
41597
  var TaskOutputTreeQuery = external_exports.object({
41491
41598
  path: external_exports.string().default(".")
41492
41599
  });
@@ -41504,7 +41611,7 @@ var BatchTaskIdsBody = external_exports.object({
41504
41611
  // ../../packages/api/src/app/server.ts
41505
41612
  var path17 = __toESM(require("path"), 1);
41506
41613
  var fs15 = __toESM(require("fs"), 1);
41507
- var import_express11 = __toESM(require_express2(), 1);
41614
+ var import_express12 = __toESM(require_express2(), 1);
41508
41615
 
41509
41616
  // ../../packages/api/src/middleware/auth.ts
41510
41617
  var SKIP_AUTH_PATHS = ["/api/system/health"];
@@ -44595,6 +44702,25 @@ function withAssignedNodeMetadata(task, nodeRegistry) {
44595
44702
  assignedNodeAvailable: node?.status !== "offline" && Boolean(node)
44596
44703
  };
44597
44704
  }
44705
+ function withShareMetadata(task, taskEngine, shareOrigin) {
44706
+ const share = taskEngine.getTaskShareByTaskId?.(task.id) ?? null;
44707
+ if (!share) return task;
44708
+ return {
44709
+ ...task,
44710
+ activeShare: {
44711
+ shareId: share.id,
44712
+ tenant: share.tenant,
44713
+ scope: share.scope,
44714
+ ...shareOrigin ? { url: buildShareUrl(shareOrigin, share.id) } : {}
44715
+ }
44716
+ };
44717
+ }
44718
+ function toTaskResponse(task, nodeRegistry, taskEngine, shareOrigin) {
44719
+ return withShareMetadata(withAssignedNodeMetadata(task, nodeRegistry), taskEngine, shareOrigin);
44720
+ }
44721
+ function buildShareUrl(origin, shareId) {
44722
+ return `${origin.replace(/\/+$/, "")}/shared/tasks/${encodeURIComponent(shareId)}`;
44723
+ }
44598
44724
  function createTaskRoutes() {
44599
44725
  const router = (0, import_express7.Router)();
44600
44726
  router.post("/", asyncHandler6(async (req, res) => {
@@ -44620,7 +44746,7 @@ function createTaskRoutes() {
44620
44746
  res.status(201).json(withAssignedNodeMetadata(task, nodeRegistry));
44621
44747
  }));
44622
44748
  router.get("/", asyncHandler6(async (req, res) => {
44623
- const { taskEngine, nodeRegistry } = req.app.locals.deps;
44749
+ const { taskEngine, nodeRegistry, shareOrigin } = req.app.locals.deps;
44624
44750
  const query = TaskListQuery.parse(req.query);
44625
44751
  const filter = {};
44626
44752
  if (query.status) filter.status = query.status;
@@ -44630,7 +44756,7 @@ function createTaskRoutes() {
44630
44756
  if (query.offset) filter.offset = query.offset;
44631
44757
  const result = taskEngine.listTasks(filter);
44632
44758
  res.json({
44633
- tasks: result.tasks.map((task) => withAssignedNodeMetadata(task, nodeRegistry)),
44759
+ tasks: result.tasks.map((task) => toTaskResponse(task, nodeRegistry, taskEngine, shareOrigin)),
44634
44760
  total: result.total
44635
44761
  });
44636
44762
  }));
@@ -44666,12 +44792,63 @@ function createTaskRoutes() {
44666
44792
  res.json({ results });
44667
44793
  }));
44668
44794
  router.get("/:id", asyncHandler6(async (req, res) => {
44669
- const { taskEngine, nodeRegistry } = req.app.locals.deps;
44670
- const task = taskEngine.getTask(req.params.id);
44795
+ const { taskEngine, nodeRegistry, shareOrigin } = req.app.locals.deps;
44796
+ const taskId = req.params.id;
44797
+ const task = taskEngine.getTask(taskId);
44671
44798
  if (!task) {
44672
- throw new MeshyError("TASK_NOT_FOUND", `Task ${req.params.id} not found`, 404);
44799
+ throw new MeshyError("TASK_NOT_FOUND", `Task ${taskId} not found`, 404);
44673
44800
  }
44674
- res.json(withAssignedNodeMetadata(task, nodeRegistry));
44801
+ res.json(toTaskResponse(task, nodeRegistry, taskEngine, shareOrigin));
44802
+ }));
44803
+ router.post("/:id/share", asyncHandler6(async (req, res) => {
44804
+ const { taskEngine, ensureShareTunnel } = req.app.locals.deps;
44805
+ const body = CreateTaskShareBody.parse(req.body ?? {});
44806
+ const taskId = req.params.id;
44807
+ const task = taskEngine.getTask(taskId);
44808
+ if (!task) {
44809
+ throw new MeshyError("TASK_NOT_FOUND", `Task ${taskId} not found`, 404);
44810
+ }
44811
+ if (!ensureShareTunnel) {
44812
+ throw new MeshyError("VALIDATION_ERROR", "Share tunnel is not available", 503);
44813
+ }
44814
+ const shareOrigin = await ensureShareTunnel();
44815
+ const shareId = task.id;
44816
+ const existing = taskEngine.getTaskShareByTaskId(task.id);
44817
+ if (existing?.id === shareId) {
44818
+ const updated = taskEngine.updateTaskShare(existing.id, {
44819
+ tenant: body.tenant,
44820
+ scope: body.scope
44821
+ }) ?? existing;
44822
+ res.json({ shareId: updated.id, tenant: updated.tenant, scope: updated.scope, url: buildShareUrl(shareOrigin, updated.id) });
44823
+ return;
44824
+ }
44825
+ if (existing) {
44826
+ taskEngine.updateTaskShare(existing.id, { revokedAt: Date.now() });
44827
+ }
44828
+ const share = taskEngine.createTaskShare({
44829
+ id: shareId,
44830
+ taskId: task.id,
44831
+ tenant: body.tenant,
44832
+ scope: body.scope,
44833
+ createdAt: Date.now()
44834
+ });
44835
+ res.status(existing ? 200 : 201).json({ shareId: share.id, tenant: share.tenant, scope: share.scope, url: buildShareUrl(shareOrigin, share.id) });
44836
+ }));
44837
+ router.delete("/:id/share", asyncHandler6(async (req, res) => {
44838
+ const { taskEngine } = req.app.locals.deps;
44839
+ const taskId = req.params.id;
44840
+ const task = taskEngine.getTask(taskId);
44841
+ if (!task) {
44842
+ throw new MeshyError("TASK_NOT_FOUND", `Task ${taskId} not found`, 404);
44843
+ }
44844
+ const existing = taskEngine.getTaskShareByTaskId(task.id);
44845
+ if (!existing) {
44846
+ res.json({ ok: true, stopped: false });
44847
+ return;
44848
+ }
44849
+ const revokedAt = Date.now();
44850
+ const updated = taskEngine.updateTaskShare(existing.id, { revokedAt }) ?? { ...existing, revokedAt };
44851
+ res.json({ ok: true, stopped: true, shareId: updated.id });
44675
44852
  }));
44676
44853
  router.patch("/:id", asyncHandler6(async (req, res) => {
44677
44854
  const { taskEngine, nodeRegistry, logger: rootLogger } = req.app.locals.deps;
@@ -44914,20 +45091,174 @@ function createTaskRoutes() {
44914
45091
  return router;
44915
45092
  }
44916
45093
 
44917
- // ../../packages/api/src/routes/worker.ts
45094
+ // ../../packages/api/src/routes/shared.ts
44918
45095
  var import_express8 = __toESM(require_express2(), 1);
45096
+ function asyncHandler7(fn) {
45097
+ return (req, res, next) => fn(req, res, next).catch(next);
45098
+ }
45099
+ function assertActiveShare(share) {
45100
+ if (!share) {
45101
+ throw new MeshyError("TASK_NOT_FOUND", "Shared conversation not found", 404);
45102
+ }
45103
+ if (share.revokedAt !== void 0) {
45104
+ throw new MeshyError("VALIDATION_ERROR", "Shared conversation has been revoked", 410);
45105
+ }
45106
+ return share;
45107
+ }
45108
+ function assertFilesPreviewShare(share) {
45109
+ if (share.scope !== "filesPreview") {
45110
+ throw new MeshyError("VALIDATION_ERROR", "Shared conversation does not include files or preview", 403);
45111
+ }
45112
+ }
45113
+ function getTaskPayloadForShare(task) {
45114
+ return task.payload.initialMessage === void 0 ? {} : { initialMessage: task.payload.initialMessage };
45115
+ }
45116
+ function toSharedConversation(share, task) {
45117
+ return {
45118
+ id: task.id,
45119
+ shareId: share.id,
45120
+ title: task.title,
45121
+ description: task.description,
45122
+ agent: task.agent,
45123
+ status: task.status,
45124
+ priority: task.priority,
45125
+ assignedNodeName: task.assignedNodeName ?? null,
45126
+ tenant: share.tenant,
45127
+ scope: share.scope,
45128
+ payload: getTaskPayloadForShare(task),
45129
+ createdAt: task.createdAt,
45130
+ updatedAt: task.updatedAt
45131
+ };
45132
+ }
45133
+ function createSharedRoutes() {
45134
+ const router = (0, import_express8.Router)();
45135
+ router.get("/conversations/:shareId", asyncHandler7(async (req, res) => {
45136
+ const { taskEngine } = req.app.locals.deps;
45137
+ const shareId = req.params.shareId;
45138
+ const share = assertActiveShare(taskEngine.getTaskShare(shareId));
45139
+ const task = taskEngine.getTask(share.taskId);
45140
+ if (!task) {
45141
+ throw new MeshyError("TASK_NOT_FOUND", "Shared conversation task not found", 404);
45142
+ }
45143
+ res.json(toSharedConversation(share, task));
45144
+ }));
45145
+ router.get("/conversations/:shareId/logs", asyncHandler7(async (req, res) => {
45146
+ const { taskEngine, engineRegistry } = req.app.locals.deps;
45147
+ const query = TaskLogsQuery.parse(req.query);
45148
+ const shareId = req.params.shareId;
45149
+ const share = assertActiveShare(taskEngine.getTaskShare(shareId));
45150
+ const task = taskEngine.getTask(share.taskId);
45151
+ if (!task) {
45152
+ throw new MeshyError("TASK_NOT_FOUND", "Shared conversation task not found", 404);
45153
+ }
45154
+ res.json(readLocalTaskLogs(engineRegistry, task.id, query.after ?? 0, task.agent));
45155
+ }));
45156
+ router.get("/conversations/:shareId/output", asyncHandler7(async (req, res) => {
45157
+ const { taskEngine } = req.app.locals.deps;
45158
+ const shareId = req.params.shareId;
45159
+ const share = assertActiveShare(taskEngine.getTaskShare(shareId));
45160
+ assertFilesPreviewShare(share);
45161
+ const handled = await maybeHandleRemoteTaskOutputRequest(
45162
+ req,
45163
+ res,
45164
+ share.taskId,
45165
+ "",
45166
+ void 0,
45167
+ createNodeMessage("task.output.summary", { taskId: share.taskId }, { expectsResponse: true })
45168
+ );
45169
+ if (handled) return;
45170
+ res.json(getLocalTaskOutputSummary(req.app.locals.deps.taskEngine, share.taskId));
45171
+ }));
45172
+ router.get("/conversations/:shareId/output/tree", asyncHandler7(async (req, res) => {
45173
+ const { taskEngine } = req.app.locals.deps;
45174
+ const query = TaskOutputTreeQuery.parse(req.query);
45175
+ const shareId = req.params.shareId;
45176
+ const share = assertActiveShare(taskEngine.getTaskShare(shareId));
45177
+ assertFilesPreviewShare(share);
45178
+ const handled = await maybeHandleRemoteTaskOutputRequest(
45179
+ req,
45180
+ res,
45181
+ share.taskId,
45182
+ "/tree",
45183
+ void 0,
45184
+ createNodeMessage("task.output.tree", { taskId: share.taskId, path: query.path }, { expectsResponse: true })
45185
+ );
45186
+ if (handled) return;
45187
+ res.json(getLocalTaskOutputTree(req.app.locals.deps.taskEngine, share.taskId, query.path));
45188
+ }));
45189
+ router.get("/conversations/:shareId/output/content", asyncHandler7(async (req, res) => {
45190
+ const { taskEngine } = req.app.locals.deps;
45191
+ const query = TaskOutputContentQuery.parse(req.query);
45192
+ const shareId = req.params.shareId;
45193
+ const share = assertActiveShare(taskEngine.getTaskShare(shareId));
45194
+ assertFilesPreviewShare(share);
45195
+ const handled = await maybeHandleRemoteTaskOutputRequest(
45196
+ req,
45197
+ res,
45198
+ share.taskId,
45199
+ "/content",
45200
+ void 0,
45201
+ createNodeMessage("task.output.content", { taskId: share.taskId, path: query.path }, { expectsResponse: true })
45202
+ );
45203
+ if (handled) return;
45204
+ const content = getLocalTaskOutputContent(req.app.locals.deps.taskEngine, share.taskId, query.path);
45205
+ res.json({
45206
+ ...content,
45207
+ downloadUrl: `/api/shared/conversations/${encodeURIComponent(share.id)}/output/download?path=${encodeURIComponent(query.path)}`
45208
+ });
45209
+ }));
45210
+ router.get("/conversations/:shareId/output/download", asyncHandler7(async (req, res) => {
45211
+ const { taskEngine } = req.app.locals.deps;
45212
+ const query = TaskOutputDownloadQuery.parse(req.query);
45213
+ const shareId = req.params.shareId;
45214
+ const share = assertActiveShare(taskEngine.getTaskShare(shareId));
45215
+ assertFilesPreviewShare(share);
45216
+ const handled = await maybeHandleRemoteTaskOutputRequest(
45217
+ req,
45218
+ res,
45219
+ share.taskId,
45220
+ "/download",
45221
+ void 0,
45222
+ createNodeMessage("task.output.download", { taskId: share.taskId, path: query.path }, { expectsResponse: true })
45223
+ );
45224
+ if (handled) return;
45225
+ const download = getLocalTaskOutputDownload(req.app.locals.deps.taskEngine, share.taskId, query.path);
45226
+ for (const [key, value] of Object.entries(download.headers)) {
45227
+ res.setHeader(key, value);
45228
+ }
45229
+ res.send(download.content);
45230
+ }));
45231
+ router.post("/conversations/:shareId/output/preview-sessions", asyncHandler7(async (req, res) => {
45232
+ const { taskEngine } = req.app.locals.deps;
45233
+ const body = TaskPreviewSessionBody.parse(req.body ?? {});
45234
+ const shareId = req.params.shareId;
45235
+ const share = assertActiveShare(taskEngine.getTaskShare(shareId));
45236
+ assertFilesPreviewShare(share);
45237
+ const handled = await maybeHandleRemoteTaskOutputRequest(req, res, share.taskId, "/preview-sessions", {
45238
+ method: "POST",
45239
+ headers: { "Content-Type": "application/json" },
45240
+ body: JSON.stringify(body)
45241
+ }, createNodeMessage("task.preview.create", { taskId: share.taskId, path: body.path }, { expectsResponse: true }));
45242
+ if (handled) return;
45243
+ res.json(await createPreviewSessionPayload(req.app.locals.deps, share.taskId, body.path, resolveRequestOrigin(req)));
45244
+ }));
45245
+ return router;
45246
+ }
45247
+
45248
+ // ../../packages/api/src/routes/worker.ts
45249
+ var import_express9 = __toESM(require_express2(), 1);
44919
45250
  var WorkerMessageBody = external_exports.object({
44920
45251
  taskId: external_exports.string().min(1)
44921
45252
  }).and(SendMessageBody);
44922
45253
  var WorkerTaskBody = external_exports.object({
44923
45254
  taskId: external_exports.string().min(1)
44924
45255
  });
44925
- function asyncHandler7(fn) {
45256
+ function asyncHandler8(fn) {
44926
45257
  return (req, res, next) => fn(req, res, next).catch(next);
44927
45258
  }
44928
45259
  function createWorkerRoutes() {
44929
- const router = (0, import_express8.Router)();
44930
- router.post("/execute", asyncHandler7(async (req, res) => {
45260
+ const router = (0, import_express9.Router)();
45261
+ router.post("/execute", asyncHandler8(async (req, res) => {
44931
45262
  const { taskEngine, engineRegistry, nodeRegistry, eventBus, logger: rootLogger, workDir } = req.app.locals.deps;
44932
45263
  const log2 = rootLogger.child("worker/execute");
44933
45264
  const task = req.body;
@@ -44944,7 +45275,7 @@ function createWorkerRoutes() {
44944
45275
  });
44945
45276
  res.json({ ok: true });
44946
45277
  }));
44947
- router.post("/message", asyncHandler7(async (req, res) => {
45278
+ router.post("/message", asyncHandler8(async (req, res) => {
44948
45279
  const { engineRegistry, taskEngine, nodeRegistry, eventBus, logger: rootLogger } = req.app.locals.deps;
44949
45280
  const log2 = rootLogger.child("worker/message");
44950
45281
  const body = WorkerMessageBody.parse(req.body);
@@ -44994,7 +45325,7 @@ function createWorkerRoutes() {
44994
45325
  }
44995
45326
  res.json({ ok: true });
44996
45327
  }));
44997
- router.post("/cancel", asyncHandler7(async (req, res) => {
45328
+ router.post("/cancel", asyncHandler8(async (req, res) => {
44998
45329
  const { taskEngine, engineRegistry, logger: rootLogger } = req.app.locals.deps;
44999
45330
  const log2 = rootLogger.child("worker/cancel");
45000
45331
  const body = WorkerTaskBody.parse(req.body);
@@ -45014,7 +45345,7 @@ function createWorkerRoutes() {
45014
45345
  terminal: result.terminal
45015
45346
  });
45016
45347
  }));
45017
- router.post("/output", asyncHandler7(async (req, res) => {
45348
+ router.post("/output", asyncHandler8(async (req, res) => {
45018
45349
  const { eventBus, engineRegistry, taskEngine, logger: rootLogger } = req.app.locals.deps;
45019
45350
  const log2 = rootLogger.child("worker/output");
45020
45351
  const { taskId, event } = req.body;
@@ -45029,7 +45360,7 @@ function createWorkerRoutes() {
45029
45360
  }
45030
45361
  res.json({ ok: true });
45031
45362
  }));
45032
- router.post("/heartbeat", asyncHandler7(async (req, res) => {
45363
+ router.post("/heartbeat", asyncHandler8(async (req, res) => {
45033
45364
  const { heartbeat, logger: rootLogger } = req.app.locals.deps;
45034
45365
  const log2 = rootLogger.child("worker/heartbeat");
45035
45366
  const body = req.body;
@@ -45046,7 +45377,7 @@ function createWorkerRoutes() {
45046
45377
  });
45047
45378
  res.json(response);
45048
45379
  }));
45049
- router.post("/keepalive", asyncHandler7(async (req, res) => {
45380
+ router.post("/keepalive", asyncHandler8(async (req, res) => {
45050
45381
  const { heartbeat, logger: rootLogger } = req.app.locals.deps;
45051
45382
  const log2 = rootLogger.child("worker/keepalive");
45052
45383
  const body = req.body;
@@ -45064,17 +45395,17 @@ function createWorkerRoutes() {
45064
45395
  });
45065
45396
  res.json(response);
45066
45397
  }));
45067
- router.post("/vote", asyncHandler7(async (req, res) => {
45398
+ router.post("/vote", asyncHandler8(async (req, res) => {
45068
45399
  const { election } = req.app.locals.deps;
45069
45400
  const response = election.handleVoteRequest(req.body);
45070
45401
  res.json(response);
45071
45402
  }));
45072
- router.post("/announce", asyncHandler7(async (req, res) => {
45403
+ router.post("/announce", asyncHandler8(async (req, res) => {
45073
45404
  const { election } = req.app.locals.deps;
45074
45405
  election.handleLeaderAnnounce(req.body);
45075
45406
  res.json({ ok: true });
45076
45407
  }));
45077
- router.post("/preview-session", asyncHandler7(async (req, res) => {
45408
+ router.post("/preview-session", asyncHandler8(async (req, res) => {
45078
45409
  const { logger: rootLogger } = req.app.locals.deps;
45079
45410
  const log2 = rootLogger.child("worker/preview-session");
45080
45411
  const body = TaskPreviewSessionBody.extend({
@@ -45089,7 +45420,7 @@ function createWorkerRoutes() {
45089
45420
  log2.info("created preview session", { taskId: body.taskId, entryPath: payload.entryPath });
45090
45421
  res.json(payload);
45091
45422
  }));
45092
- router.get("/preview-asset", asyncHandler7(async (req, res) => {
45423
+ router.get("/preview-asset", asyncHandler8(async (req, res) => {
45093
45424
  const { previewSessionManager } = req.app.locals.deps;
45094
45425
  if (!previewSessionManager) {
45095
45426
  throw new MeshyError("VALIDATION_ERROR", "Preview not available on this node", 400);
@@ -45098,7 +45429,7 @@ function createWorkerRoutes() {
45098
45429
  const requestedPath = typeof req.query.path === "string" && req.query.path.length > 0 ? req.query.path : void 0;
45099
45430
  sendPreviewAssetResponse(previewSessionManager, token, requestedPath, res);
45100
45431
  }));
45101
- router.post("/control-response", asyncHandler7(async (req, res) => {
45432
+ router.post("/control-response", asyncHandler8(async (req, res) => {
45102
45433
  const { heartbeat, logger: rootLogger } = req.app.locals.deps;
45103
45434
  const log2 = rootLogger.child("worker/control-response");
45104
45435
  const body = normalizeNodeMessageResponse(req.body);
@@ -45125,7 +45456,7 @@ function normalizeNodeMessageResponse(value) {
45125
45456
  }
45126
45457
 
45127
45458
  // ../../packages/api/src/routes/system.ts
45128
- var import_express9 = __toESM(require_express2(), 1);
45459
+ var import_express10 = __toESM(require_express2(), 1);
45129
45460
 
45130
45461
  // ../../packages/api/src/app/system-info.ts
45131
45462
  var os5 = __toESM(require("os"), 1);
@@ -45243,12 +45574,12 @@ function buildNodeSettingsSnapshot(options) {
45243
45574
  }
45244
45575
 
45245
45576
  // ../../packages/api/src/routes/system.ts
45246
- function asyncHandler8(fn) {
45577
+ function asyncHandler9(fn) {
45247
45578
  return (req, res, next) => fn(req, res, next).catch(next);
45248
45579
  }
45249
45580
  function createSystemRoutes() {
45250
- const router = (0, import_express9.Router)();
45251
- router.get("/health", asyncHandler8(async (req, res) => {
45581
+ const router = (0, import_express10.Router)();
45582
+ router.get("/health", asyncHandler9(async (req, res) => {
45252
45583
  const { logger: rootLogger } = req.app.locals.deps;
45253
45584
  rootLogger.child("system/health").info("received system health API call", {
45254
45585
  method: req.method,
@@ -45257,7 +45588,7 @@ function createSystemRoutes() {
45257
45588
  });
45258
45589
  res.json({ status: "ok", timestamp: Date.now() });
45259
45590
  }));
45260
- router.get("/info", asyncHandler8(async (req, res) => {
45591
+ router.get("/info", asyncHandler9(async (req, res) => {
45261
45592
  const {
45262
45593
  nodeRegistry,
45263
45594
  getTransportType,
@@ -45301,7 +45632,7 @@ function createSystemRoutes() {
45301
45632
  packages: settingsSnapshot.packages
45302
45633
  });
45303
45634
  }));
45304
- router.post("/transport", asyncHandler8(async (req, res) => {
45635
+ router.post("/transport", asyncHandler9(async (req, res) => {
45305
45636
  const { switchTransport } = req.app.locals.deps;
45306
45637
  if (!switchTransport) {
45307
45638
  res.status(501).json({ error: "Transport switching not available" });
@@ -45315,7 +45646,7 @@ function createSystemRoutes() {
45315
45646
  const newEndpoint = await switchTransport(type);
45316
45647
  res.json({ ok: true, transportType: type, endpoint: newEndpoint });
45317
45648
  }));
45318
- router.post("/devtunnel", asyncHandler8(async (req, res) => {
45649
+ router.post("/devtunnel", asyncHandler9(async (req, res) => {
45319
45650
  const { enableDevTunnel, disableDevTunnel, nodeRegistry, taskEngine } = req.app.locals.deps;
45320
45651
  if (!enableDevTunnel || !disableDevTunnel) {
45321
45652
  res.status(501).json({ error: "DevTunnel control not available" });
@@ -45344,7 +45675,7 @@ function createSystemRoutes() {
45344
45675
  });
45345
45676
  }
45346
45677
  }));
45347
- router.get("/metrics", asyncHandler8(async (req, res) => {
45678
+ router.get("/metrics", asyncHandler9(async (req, res) => {
45348
45679
  const { taskEngine } = req.app.locals.deps;
45349
45680
  const metrics = taskEngine.getMetrics();
45350
45681
  res.json(metrics);
@@ -45353,7 +45684,7 @@ function createSystemRoutes() {
45353
45684
  }
45354
45685
 
45355
45686
  // ../../packages/api/src/routes/events.ts
45356
- var import_express10 = __toESM(require_express2(), 1);
45687
+ var import_express11 = __toESM(require_express2(), 1);
45357
45688
  var HEARTBEAT_INTERVAL_MS = 15e3;
45358
45689
  var CATEGORY_MAP = {
45359
45690
  tasks: "task.",
@@ -45389,7 +45720,7 @@ function shouldIncludeEvent(eventName, categories) {
45389
45720
  });
45390
45721
  }
45391
45722
  function createEventRoutes() {
45392
- const router = (0, import_express10.Router)();
45723
+ const router = (0, import_express11.Router)();
45393
45724
  router.get("/", (req, res) => {
45394
45725
  const { eventBus } = req.app.locals.deps;
45395
45726
  const categories = parseFilter(req.query.filter);
@@ -45437,6 +45768,40 @@ data: ${JSON.stringify(data)}
45437
45768
  // ../../packages/api/src/app/server.ts
45438
45769
  var JSON_BODY_LIMIT = "1mb";
45439
45770
  var JSON_BODY_LIMIT_LARGE = "25mb";
45771
+ var TRUSTED_LOCAL_HOSTS2 = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]", "::1"]);
45772
+ function normalizeHost2(value) {
45773
+ const trimmed = value?.trim().toLowerCase();
45774
+ return trimmed ? trimmed.replace(/:\d+$/, "") : void 0;
45775
+ }
45776
+ function collectForwardedHosts(value) {
45777
+ if (typeof value !== "string") {
45778
+ return [];
45779
+ }
45780
+ return value.split(",").map((item) => normalizeHost2(item)).filter((host) => Boolean(host));
45781
+ }
45782
+ function getRequestHosts2(req) {
45783
+ const forwardedHosts = collectForwardedHosts(req.headers["x-forwarded-host"]);
45784
+ if (forwardedHosts.length > 0) {
45785
+ return forwardedHosts;
45786
+ }
45787
+ return [normalizeHost2(req.hostname), normalizeHost2(typeof req.headers.host === "string" ? req.headers.host : void 0)].filter((host) => Boolean(host));
45788
+ }
45789
+ function getOriginHost(origin) {
45790
+ if (!origin) return void 0;
45791
+ try {
45792
+ return normalizeHost2(new URL(origin).host);
45793
+ } catch {
45794
+ return void 0;
45795
+ }
45796
+ }
45797
+ function isShareHostRequest(req, shareOrigin) {
45798
+ const shareHost = getOriginHost(shareOrigin);
45799
+ if (!shareHost) return false;
45800
+ return getRequestHosts2(req).some((host) => !TRUSTED_LOCAL_HOSTS2.has(host) && host === shareHost);
45801
+ }
45802
+ function isAllowedSharePath(pathname) {
45803
+ return pathname === "/favicon.ico" || pathname === "/api/shared" || pathname.startsWith("/api/shared/") || pathname === "/preview" || pathname.startsWith("/preview/") || pathname === "/shared" || pathname.startsWith("/shared/") || pathname === "/assets" || pathname.startsWith("/assets/");
45804
+ }
45440
45805
  function resolveRuntimeBaseDir() {
45441
45806
  const entryPath = process.argv[1];
45442
45807
  if (typeof entryPath === "string" && entryPath.length > 0) {
@@ -45467,7 +45832,7 @@ function resolveStaticDir(baseDir) {
45467
45832
  return null;
45468
45833
  }
45469
45834
  function createServer2(deps) {
45470
- const app = (0, import_express11.default)();
45835
+ const app = (0, import_express12.default)();
45471
45836
  app.locals.deps = deps;
45472
45837
  if (typeof deps.heartbeat.setNodeMessageHandler === "function") {
45473
45838
  deps.heartbeat.setNodeMessageHandler((message) => handleNodeMessage(deps, message));
@@ -45483,15 +45848,32 @@ function createServer2(deps) {
45483
45848
  } catch {
45484
45849
  }
45485
45850
  }
45851
+ if (deps.shareOrigin) {
45852
+ try {
45853
+ trustedHosts.push(new URL(deps.shareOrigin).host);
45854
+ } catch {
45855
+ }
45856
+ }
45486
45857
  return trustedHosts;
45487
45858
  }
45488
45859
  };
45489
45860
  const isApiRequest = (req) => req.path === "/api" || req.path.startsWith("/api/");
45490
45861
  const canServeDashboard = (req) => !deps.config.validateBearerToken || isTrustedDashboardRequest(req, authConfig);
45862
+ app.use((req, res, next) => {
45863
+ if (!isShareHostRequest(req, deps.shareOrigin)) {
45864
+ next();
45865
+ return;
45866
+ }
45867
+ if (isAllowedSharePath(req.path)) {
45868
+ next();
45869
+ return;
45870
+ }
45871
+ res.status(404).type("text/plain").send("Not Found");
45872
+ });
45491
45873
  const runtimeBaseDir = resolveRuntimeBaseDir();
45492
45874
  const staticDir = resolveStaticDir(runtimeBaseDir);
45493
45875
  if (staticDir) {
45494
- const staticMiddleware = import_express11.default.static(staticDir);
45876
+ const staticMiddleware = import_express12.default.static(staticDir);
45495
45877
  app.use((req, res, next) => {
45496
45878
  if (isApiRequest(req)) {
45497
45879
  next();
@@ -45504,7 +45886,7 @@ function createServer2(deps) {
45504
45886
  staticMiddleware(req, res, next);
45505
45887
  });
45506
45888
  }
45507
- app.use(import_express11.default.json({ limit: JSON_BODY_LIMIT }));
45889
+ app.use(import_express12.default.json({ limit: JSON_BODY_LIMIT }));
45508
45890
  app.use(createAuthMiddleware(authConfig));
45509
45891
  app.use((req, res, next) => {
45510
45892
  void (async () => {
@@ -45526,12 +45908,13 @@ function createServer2(deps) {
45526
45908
  })().catch(next);
45527
45909
  });
45528
45910
  app.use(createRoutingMiddleware(deps.dataRouter));
45529
- const largeBodyParser = import_express11.default.json({ limit: JSON_BODY_LIMIT_LARGE });
45911
+ const largeBodyParser = import_express12.default.json({ limit: JSON_BODY_LIMIT_LARGE });
45530
45912
  app.use("/api/cluster", createClusterRoutes());
45531
45913
  app.use("/api/cluster-control", createClusterControlRoutes());
45532
45914
  app.use("/api/node", largeBodyParser, createNodeMessageRoutes());
45533
45915
  app.use("/api/nodes", createNodeRoutes());
45534
45916
  app.use("/api/tasks", largeBodyParser, createTaskRoutes());
45917
+ app.use("/api/shared", createSharedRoutes());
45535
45918
  app.use("/api/worker", largeBodyParser, createWorkerRoutes());
45536
45919
  app.use("/api/system", createSystemRoutes());
45537
45920
  app.use("/api/events", createEventRoutes());
@@ -45751,8 +46134,24 @@ ${lines.join("")}`
45751
46134
  return args;
45752
46135
  }
45753
46136
  this.ensureTunnelPort(tunnelId, localPort);
46137
+ this.ensureTunnelAccess(tunnelId);
45754
46138
  return ["host", tunnelId];
45755
46139
  }
46140
+ ensureTunnelAccess(tunnelId) {
46141
+ if (this.config.access !== "tenant") {
46142
+ return;
46143
+ }
46144
+ try {
46145
+ (0, import_node_child_process9.execFileSync)("devtunnel", ["access", "create", tunnelId, "--tenant"], { stdio: "pipe" });
46146
+ } catch (err) {
46147
+ if (isExistingTenantAccessError(err)) {
46148
+ return;
46149
+ }
46150
+ throw new Error(
46151
+ `Failed to configure tenant access for devtunnel "${tunnelId}": ${formatCommandError(err)}`
46152
+ );
46153
+ }
46154
+ }
45756
46155
  ensureTunnelExists() {
45757
46156
  const tunnelId = this.config.id.trim();
45758
46157
  if (!tunnelId) {
@@ -45847,6 +46246,10 @@ function normalizeDevTunnelUrl(value) {
45847
46246
  return null;
45848
46247
  }
45849
46248
  }
46249
+ function isExistingTenantAccessError(error) {
46250
+ const message = formatCommandError(error).toLowerCase();
46251
+ return message.includes("already exists") || message.includes("conflict") || message.includes("duplicate");
46252
+ }
45850
46253
  function formatCommandError(error) {
45851
46254
  if (!error || typeof error !== "object") {
45852
46255
  return String(error);
@@ -46624,7 +47027,9 @@ async function main() {
46624
47027
  const previewSessionManager = new PreviewSessionManager();
46625
47028
  const previewProxyManager = new PreviewProxyManager();
46626
47029
  let dashboardTransport = null;
47030
+ let shareTransport = null;
46627
47031
  let dashboardOrigin;
47032
+ let shareOrigin;
46628
47033
  let deps;
46629
47034
  async function closeServer(server2) {
46630
47035
  if (!server2) {
@@ -46653,11 +47058,29 @@ async function main() {
46653
47058
  }
46654
47059
  };
46655
47060
  }
47061
+ function createShareTransportConfig() {
47062
+ return {
47063
+ type: "devtunnel",
47064
+ devtunnel: {
47065
+ id: resolveOrCreateDevTunnelId(
47066
+ config.storage.path,
47067
+ meshyNode.getNodeRegistry().getSelf().id,
47068
+ "share"
47069
+ ),
47070
+ allowAnonymous: false,
47071
+ access: "tenant"
47072
+ }
47073
+ };
47074
+ }
46656
47075
  function setAdvertisedDashboardOrigin(origin) {
46657
47076
  dashboardOrigin = origin;
46658
47077
  deps.dashboardOrigin = origin;
46659
47078
  meshyNode.getNodeRegistry().updateDashboardOrigin(meshyNode.getNodeRegistry().getSelf().id, origin);
46660
47079
  }
47080
+ function setShareOrigin(origin) {
47081
+ shareOrigin = origin;
47082
+ deps.shareOrigin = origin;
47083
+ }
46661
47084
  function shouldPublishDashboardTunnel() {
46662
47085
  return authMetadata.enabled && (meshyNode.getTransportType() === "devtunnel" || meshyNode.isDevTunnelEnabled());
46663
47086
  }
@@ -46739,6 +47162,27 @@ async function main() {
46739
47162
  }
46740
47163
  await restartDashboardTransport(reason);
46741
47164
  }
47165
+ async function ensureShareTunnel() {
47166
+ if (shareTransport && shareOrigin && await shareTransport.isHealthy().catch(() => false)) {
47167
+ return shareOrigin;
47168
+ }
47169
+ if (shareTransport) {
47170
+ await shareTransport.stop().catch(() => void 0);
47171
+ shareTransport = null;
47172
+ setShareOrigin(void 0);
47173
+ }
47174
+ const nextTransport = createTransport(createShareTransportConfig());
47175
+ await nextTransport.start(config.node.port);
47176
+ const nextOrigin = await nextTransport.getEndpoint();
47177
+ shareTransport = nextTransport;
47178
+ setShareOrigin(nextOrigin);
47179
+ meshyNode.getLogger().info("started share tunnel", {
47180
+ shareOrigin: nextOrigin,
47181
+ tenantAccess: true,
47182
+ stableUrl: true
47183
+ });
47184
+ return nextOrigin;
47185
+ }
46742
47186
  deps = {
46743
47187
  dataRouter: meshyNode.getDataRouter(),
46744
47188
  taskEngine: meshyNode.getTaskEngine(),
@@ -46791,11 +47235,14 @@ async function main() {
46791
47235
  isDevTunnelEnabled: () => meshyNode.isDevTunnelEnabled(),
46792
47236
  localDashboardOrigin,
46793
47237
  dashboardOrigin,
47238
+ shareOrigin,
47239
+ ensureShareTunnel,
46794
47240
  runtimeMetadata
46795
47241
  };
46796
47242
  deps.previewSessionManager = previewSessionManager;
46797
47243
  deps.previewProxyManager = previewProxyManager;
46798
47244
  deps.dashboardOrigin = dashboardOrigin;
47245
+ deps.shareOrigin = shareOrigin;
46799
47246
  meshyNode.getLogger().info("configured node auth mode", {
46800
47247
  authEnabled: authMetadata.enabled,
46801
47248
  allowSameTenant: authMetadata.allowSameTenant,
@@ -46869,6 +47316,9 @@ async function main() {
46869
47316
  if (dashboardTransport) {
46870
47317
  await dashboardTransport.stop();
46871
47318
  }
47319
+ if (shareTransport) {
47320
+ await shareTransport.stop();
47321
+ }
46872
47322
  await meshyNode.stop();
46873
47323
  await closeServer(server);
46874
47324
  console.log("Goodbye!");