@axiom-lattice/gateway 2.1.101 → 2.1.103
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/.turbo/turbo-build.log +22 -18
- package/CHANGELOG.md +24 -0
- package/dist/chunk-R4ZO3HZ3.mjs +46 -0
- package/dist/chunk-R4ZO3HZ3.mjs.map +1 -0
- package/dist/index.js +339 -72
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +49 -60
- package/dist/index.mjs.map +1 -1
- package/dist/resources-NE6DFF5I.mjs +233 -0
- package/dist/resources-NE6DFF5I.mjs.map +1 -0
- package/package.json +11 -8
- package/src/controllers/__tests__/mime.test.ts +74 -0
- package/src/controllers/__tests__/resources.test.ts +99 -0
- package/src/controllers/resources.ts +299 -0
- package/src/controllers/sandbox.ts +1 -30
- package/src/controllers/workspace.ts +9 -36
- package/src/index.ts +24 -0
- package/src/routes/resource-routes.ts +24 -0
- package/src/utils/mime.ts +43 -0
package/dist/index.js
CHANGED
|
@@ -30,6 +30,53 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
30
30
|
));
|
|
31
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
32
|
|
|
33
|
+
// src/utils/mime.ts
|
|
34
|
+
function getContentTypeFromFilename(filename) {
|
|
35
|
+
const ext = filename.includes(".") ? filename.slice(filename.lastIndexOf(".")).toLowerCase() : "";
|
|
36
|
+
return EXT_TO_MIME[ext] ?? "application/octet-stream";
|
|
37
|
+
}
|
|
38
|
+
function getFilenameFromPath(path3) {
|
|
39
|
+
const segments = path3.replace(/\/+$/, "").split("/");
|
|
40
|
+
return segments[segments.length - 1] || "download";
|
|
41
|
+
}
|
|
42
|
+
var EXT_TO_MIME;
|
|
43
|
+
var init_mime = __esm({
|
|
44
|
+
"src/utils/mime.ts"() {
|
|
45
|
+
"use strict";
|
|
46
|
+
EXT_TO_MIME = {
|
|
47
|
+
".txt": "text/plain",
|
|
48
|
+
".html": "text/html",
|
|
49
|
+
".htm": "text/html",
|
|
50
|
+
".css": "text/css",
|
|
51
|
+
".js": "application/javascript",
|
|
52
|
+
".mjs": "application/javascript",
|
|
53
|
+
".json": "application/json",
|
|
54
|
+
".pdf": "application/pdf",
|
|
55
|
+
".png": "image/png",
|
|
56
|
+
".jpg": "image/jpeg",
|
|
57
|
+
".jpeg": "image/jpeg",
|
|
58
|
+
".gif": "image/gif",
|
|
59
|
+
".webp": "image/webp",
|
|
60
|
+
".svg": "image/svg+xml",
|
|
61
|
+
".ico": "image/x-icon",
|
|
62
|
+
".zip": "application/zip",
|
|
63
|
+
".csv": "text/csv",
|
|
64
|
+
".xml": "application/xml",
|
|
65
|
+
".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
66
|
+
".xls": "application/vnd.ms-excel",
|
|
67
|
+
".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
68
|
+
".ppt": "application/vnd.ms-powerpoint",
|
|
69
|
+
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
70
|
+
".doc": "application/msword",
|
|
71
|
+
".mp4": "video/mp4",
|
|
72
|
+
".webm": "video/webm",
|
|
73
|
+
".mp3": "audio/mpeg",
|
|
74
|
+
".wav": "audio/wav",
|
|
75
|
+
".ogg": "audio/ogg"
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
33
80
|
// src/logger/Logger.ts
|
|
34
81
|
var import_pino, import_pino_pretty, import_pino_roll, PinoLoggerFactory, Logger;
|
|
35
82
|
var init_Logger = __esm({
|
|
@@ -1145,6 +1192,240 @@ var init_a2a = __esm({
|
|
|
1145
1192
|
}
|
|
1146
1193
|
});
|
|
1147
1194
|
|
|
1195
|
+
// src/controllers/resources.ts
|
|
1196
|
+
var resources_exports = {};
|
|
1197
|
+
__export(resources_exports, {
|
|
1198
|
+
ResourceController: () => ResourceController
|
|
1199
|
+
});
|
|
1200
|
+
var import_bcryptjs, import_core35, ResourceController;
|
|
1201
|
+
var init_resources = __esm({
|
|
1202
|
+
"src/controllers/resources.ts"() {
|
|
1203
|
+
"use strict";
|
|
1204
|
+
import_bcryptjs = __toESM(require("bcryptjs"));
|
|
1205
|
+
import_core35 = require("@axiom-lattice/core");
|
|
1206
|
+
init_mime();
|
|
1207
|
+
ResourceController = class {
|
|
1208
|
+
constructor(deps) {
|
|
1209
|
+
this.deps = deps;
|
|
1210
|
+
}
|
|
1211
|
+
async createShare(request, reply) {
|
|
1212
|
+
const userId = request.user ? request.user.id ?? "unknown" : "unknown";
|
|
1213
|
+
const tenantId = request.headers["x-tenant-id"] || "default";
|
|
1214
|
+
const workspaceId = request.headers["x-workspace-id"];
|
|
1215
|
+
const projectId = request.headers["x-project-id"];
|
|
1216
|
+
const body = request.body;
|
|
1217
|
+
if (!workspaceId || !projectId) {
|
|
1218
|
+
return reply.status(400).send({ error: "x-workspace-id and x-project-id headers required" });
|
|
1219
|
+
}
|
|
1220
|
+
const payload = (0, import_core35.createSharePayload)(
|
|
1221
|
+
tenantId,
|
|
1222
|
+
workspaceId,
|
|
1223
|
+
projectId,
|
|
1224
|
+
userId,
|
|
1225
|
+
body
|
|
1226
|
+
);
|
|
1227
|
+
const token = (0, import_core35.generateToken)();
|
|
1228
|
+
try {
|
|
1229
|
+
await this.deps.store.create({ ...payload, token });
|
|
1230
|
+
this.deps.logger.info(
|
|
1231
|
+
"[share] created",
|
|
1232
|
+
{ token, originalPath: body.resourcePath, normalizedPath: payload.address.resourcePath, volume: payload.address.volume, userId }
|
|
1233
|
+
);
|
|
1234
|
+
} catch {
|
|
1235
|
+
return reply.status(500).send({ error: "Failed to create share" });
|
|
1236
|
+
}
|
|
1237
|
+
return reply.status(201).send({ token, url: `/s/${token}` });
|
|
1238
|
+
}
|
|
1239
|
+
async listShares(request, reply) {
|
|
1240
|
+
const userId = request.user ? request.user.id ?? "unknown" : "unknown";
|
|
1241
|
+
const tenantId = request.headers["x-tenant-id"] || "default";
|
|
1242
|
+
const shares = await this.deps.store.listByUser(tenantId, userId);
|
|
1243
|
+
return reply.send(shares);
|
|
1244
|
+
}
|
|
1245
|
+
async updateShare(request, reply) {
|
|
1246
|
+
const { token } = request.params;
|
|
1247
|
+
const userId = request.user ? request.user.id : void 0;
|
|
1248
|
+
const patch = request.body;
|
|
1249
|
+
const record = await this.deps.store.findByToken(token);
|
|
1250
|
+
if (!record || record.createdBy !== userId) {
|
|
1251
|
+
return reply.status(404).send({ error: "Share not found" });
|
|
1252
|
+
}
|
|
1253
|
+
await this.deps.store.update(token, patch);
|
|
1254
|
+
if (patch.revoked) {
|
|
1255
|
+
this.deps.cache.invalidate(token);
|
|
1256
|
+
}
|
|
1257
|
+
return reply.send({ ok: true });
|
|
1258
|
+
}
|
|
1259
|
+
async revokeShare(request, reply) {
|
|
1260
|
+
const { token } = request.params;
|
|
1261
|
+
const userId = request.user ? request.user.id : void 0;
|
|
1262
|
+
const record = await this.deps.store.findByToken(token);
|
|
1263
|
+
if (!record || record.createdBy !== userId) {
|
|
1264
|
+
return reply.status(404).send({ error: "Share not found" });
|
|
1265
|
+
}
|
|
1266
|
+
await this.deps.store.update(token, { revoked: true });
|
|
1267
|
+
this.deps.cache.invalidate(token);
|
|
1268
|
+
return reply.send({ ok: true });
|
|
1269
|
+
}
|
|
1270
|
+
async resolveResource(request, reply) {
|
|
1271
|
+
const params = request.params;
|
|
1272
|
+
const { token } = params;
|
|
1273
|
+
const subPath = params["*"] ?? "";
|
|
1274
|
+
this.deps.logger.info("[share] resolve start", { token, subPath });
|
|
1275
|
+
const cached = this.deps.cache.get(token);
|
|
1276
|
+
if (cached && !cached.requiresUnlock) {
|
|
1277
|
+
this.deps.logger.info("[share] cache hit", { token, volume: cached.address.volume, resourcePath: cached.address.resourcePath });
|
|
1278
|
+
return this._serveFile(cached.address, token, subPath, cached.sandboxConfig ?? { tenantId: "default", workspaceId: "", projectId: "", assistantId: null }, reply);
|
|
1279
|
+
}
|
|
1280
|
+
this.deps.logger.info("[share] cache miss, querying DB", { token });
|
|
1281
|
+
const record = await this.deps.store.findByToken(token);
|
|
1282
|
+
if (!record || record.revoked) {
|
|
1283
|
+
this.deps.logger.warn("[share] token not found or revoked", { token, found: !!record, revoked: record?.revoked });
|
|
1284
|
+
return reply.status(404).send("Not found");
|
|
1285
|
+
}
|
|
1286
|
+
if (record.expiresAt && new Date(record.expiresAt) < /* @__PURE__ */ new Date()) {
|
|
1287
|
+
this.deps.logger.info("[share] token expired", { token, expiresAt: record.expiresAt });
|
|
1288
|
+
return reply.status(410).send("Expired");
|
|
1289
|
+
}
|
|
1290
|
+
this.deps.logger.info("[share] record found", {
|
|
1291
|
+
token,
|
|
1292
|
+
volume: record.address.volume,
|
|
1293
|
+
resourcePath: record.address.resourcePath,
|
|
1294
|
+
visibility: record.visibility,
|
|
1295
|
+
workspaceId: record.workspaceId,
|
|
1296
|
+
projectId: record.projectId
|
|
1297
|
+
});
|
|
1298
|
+
const isInternal = this._isInternalRequest(request);
|
|
1299
|
+
if (!isInternal) {
|
|
1300
|
+
if (record.visibility === "password") {
|
|
1301
|
+
const unlocked = this._isUnlocked(request, token);
|
|
1302
|
+
if (!unlocked) {
|
|
1303
|
+
this.deps.logger.info("[share] password protected, returning password page", { token });
|
|
1304
|
+
this.deps.cache.set(token, {
|
|
1305
|
+
address: record.address,
|
|
1306
|
+
requiresUnlock: true,
|
|
1307
|
+
sandboxConfig: { tenantId: record.tenantId, workspaceId: record.workspaceId, projectId: record.projectId, assistantId: record.assistantId }
|
|
1308
|
+
});
|
|
1309
|
+
return reply.type("text/html").send(this._passwordPage(token));
|
|
1310
|
+
}
|
|
1311
|
+
this.deps.logger.info("[share] password unlocked", { token });
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
if (record.maxAccess !== null) {
|
|
1315
|
+
const ok = await this.deps.store.atomicIncrementAccess(token);
|
|
1316
|
+
if (!ok) return reply.status(410).send("Access limit reached");
|
|
1317
|
+
} else {
|
|
1318
|
+
this.deps.store.incrementAccess(token).catch(() => {
|
|
1319
|
+
});
|
|
1320
|
+
}
|
|
1321
|
+
const sandboxConfig = { tenantId: record.tenantId, workspaceId: record.workspaceId, projectId: record.projectId, assistantId: record.assistantId };
|
|
1322
|
+
this.deps.cache.set(token, {
|
|
1323
|
+
address: record.address,
|
|
1324
|
+
requiresUnlock: record.visibility === "password" && !isInternal,
|
|
1325
|
+
sandboxConfig
|
|
1326
|
+
});
|
|
1327
|
+
return this._serveFile(record.address, token, subPath, sandboxConfig, reply);
|
|
1328
|
+
}
|
|
1329
|
+
async unlockShare(request, reply) {
|
|
1330
|
+
const { token } = request.params;
|
|
1331
|
+
const { password } = request.body;
|
|
1332
|
+
const record = await this.deps.store.findByToken(token);
|
|
1333
|
+
if (!record || !record.passwordHash) {
|
|
1334
|
+
return reply.status(404).send({ error: "Invalid request" });
|
|
1335
|
+
}
|
|
1336
|
+
const valid = await import_bcryptjs.default.compare(password, record.passwordHash);
|
|
1337
|
+
if (!valid) {
|
|
1338
|
+
return reply.status(401).send({ error: "Incorrect password" });
|
|
1339
|
+
}
|
|
1340
|
+
reply.header(
|
|
1341
|
+
"Set-Cookie",
|
|
1342
|
+
`share_unlock_${token}=1; Max-Age=86400; Path=/s/${token}; SameSite=Lax; HttpOnly; Secure`
|
|
1343
|
+
);
|
|
1344
|
+
return reply.send({ ok: true });
|
|
1345
|
+
}
|
|
1346
|
+
_isInternalRequest(request) {
|
|
1347
|
+
const user = request.user;
|
|
1348
|
+
return !!user && !!user.id;
|
|
1349
|
+
}
|
|
1350
|
+
_isUnlocked(request, token) {
|
|
1351
|
+
const cookie = request.headers.cookie ?? "";
|
|
1352
|
+
return cookie.includes(`share_unlock_${token}=1`);
|
|
1353
|
+
}
|
|
1354
|
+
async _serveFile(address, token, subPath, sandboxConfig, reply) {
|
|
1355
|
+
const provider = this.deps.sandboxManager.getDefaultProvider();
|
|
1356
|
+
const resolver = provider.getResourceResolver();
|
|
1357
|
+
const sandboxPath = subPath ? this._resolveSafeSubPath(address.resourcePath, subPath) : address.resourcePath;
|
|
1358
|
+
this.deps.logger.info("[share] serving file", {
|
|
1359
|
+
token,
|
|
1360
|
+
volume: address.volume,
|
|
1361
|
+
sandboxPath,
|
|
1362
|
+
subPath: subPath || "(none)",
|
|
1363
|
+
tenantId: sandboxConfig.tenantId,
|
|
1364
|
+
workspaceId: sandboxConfig.workspaceId,
|
|
1365
|
+
projectId: sandboxConfig.projectId
|
|
1366
|
+
});
|
|
1367
|
+
let buf;
|
|
1368
|
+
try {
|
|
1369
|
+
buf = await resolver.resolve({ ...address, resourcePath: sandboxPath });
|
|
1370
|
+
this.deps.logger.info("[share] resolved via volume FS", { token, size: buf.length });
|
|
1371
|
+
} catch (err) {
|
|
1372
|
+
this.deps.logger.warn("[share] volume FS failed, trying sandbox fallback", {
|
|
1373
|
+
token,
|
|
1374
|
+
path: sandboxPath,
|
|
1375
|
+
error: err.message
|
|
1376
|
+
});
|
|
1377
|
+
try {
|
|
1378
|
+
const sandbox = await this.deps.sandboxManager.getSandboxFromConfig({
|
|
1379
|
+
assistant_id: sandboxConfig.assistantId ?? "",
|
|
1380
|
+
thread_id: "",
|
|
1381
|
+
tenantId: sandboxConfig.tenantId,
|
|
1382
|
+
workspaceId: sandboxConfig.workspaceId,
|
|
1383
|
+
projectId: sandboxConfig.projectId
|
|
1384
|
+
});
|
|
1385
|
+
buf = await sandbox.file.downloadFile({ file: `/project/${sandboxPath}` });
|
|
1386
|
+
this.deps.logger.info("[share] resolved via sandbox fallback", { token, size: buf.length });
|
|
1387
|
+
} catch (err2) {
|
|
1388
|
+
this.deps.logger.warn("[share] all resolution attempts failed", { token, resourcePath: sandboxPath, error: err2.message });
|
|
1389
|
+
return reply.status(404).send("File not found");
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
const fullPath = sandboxPath;
|
|
1393
|
+
const filename = fullPath.split("/").pop() || "download";
|
|
1394
|
+
const isHtml = !subPath && /\.(html|htm)$/i.test(filename);
|
|
1395
|
+
if (isHtml) {
|
|
1396
|
+
buf = this._injectBaseTag(buf, token);
|
|
1397
|
+
}
|
|
1398
|
+
const contentType = getContentTypeFromFilename(filename);
|
|
1399
|
+
return reply.status(200).type(contentType).header("Content-Disposition", `inline; filename="${filename}"`).header("Access-Control-Allow-Origin", "*").send(buf);
|
|
1400
|
+
}
|
|
1401
|
+
_resolveSafeSubPath(entryFile, subPath) {
|
|
1402
|
+
if (!subPath) return entryFile;
|
|
1403
|
+
if (subPath.includes("..")) throw new Error("Path traversal denied");
|
|
1404
|
+
const entryDir = entryFile.replace(/[^/]+$/, "");
|
|
1405
|
+
return (entryDir + subPath).replace(/\/+/g, "/");
|
|
1406
|
+
}
|
|
1407
|
+
_injectBaseTag(buf, token) {
|
|
1408
|
+
const html = buf.toString("utf-8");
|
|
1409
|
+
if (/<base\b/i.test(html)) return buf;
|
|
1410
|
+
const baseTag = `<base href="/s/${token}/">`;
|
|
1411
|
+
if (html.includes("</head>")) {
|
|
1412
|
+
return Buffer.from(html.replace("</head>", `${baseTag}</head>`), "utf-8");
|
|
1413
|
+
}
|
|
1414
|
+
if (html.includes("<head>")) {
|
|
1415
|
+
return Buffer.from(html.replace("<head>", `<head>${baseTag}`), "utf-8");
|
|
1416
|
+
}
|
|
1417
|
+
if (html.includes("<html>")) {
|
|
1418
|
+
return Buffer.from(html.replace("<html>", `<html>${baseTag}`), "utf-8");
|
|
1419
|
+
}
|
|
1420
|
+
return Buffer.from(baseTag + html, "utf-8");
|
|
1421
|
+
}
|
|
1422
|
+
_passwordPage(token) {
|
|
1423
|
+
return `<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Password Protected</title><style>body{font-family:-apple-system,BlinkMacSystemFont,sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0;background:#f5f5f5}.card{background:#fff;padding:32px;border-radius:12px;box-shadow:0 2px 8px rgba(0,0,0,.1);width:100%;max-width:360px;text-align:center}h2{margin:0 0 8px;font-size:20px}p{margin:0 0 20px;color:#666;font-size:14px}input{width:100%;padding:10px 12px;border:1px solid #d9d9d9;border-radius:8px;font-size:14px;box-sizing:border-box;margin-bottom:12px}button{width:100%;padding:10px;background:#6366f1;color:#fff;border:none;border-radius:8px;font-size:14px;cursor:pointer}.error{color:#ef4444;font-size:13px;margin-top:8px;display:none}</style></head><body><div class="card"><h2>Password Protected</h2><p>This share requires a password to access.</p><form id="f"><input type="password" id="p" placeholder="Enter password" required><button type="submit">Unlock</button><div class="error" id="e">Incorrect password</div></form></div><script>document.getElementById('f').onsubmit=async(e)=>{e.preventDefault();const r=await fetch('/s/${token}/unlock',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({password:document.getElementById('p').value})});if(r.ok)location.reload();else document.getElementById('e').style.display='block'}</script></body></html>`;
|
|
1424
|
+
}
|
|
1425
|
+
};
|
|
1426
|
+
}
|
|
1427
|
+
});
|
|
1428
|
+
|
|
1148
1429
|
// src/index.ts
|
|
1149
1430
|
var index_exports = {};
|
|
1150
1431
|
__export(index_exports, {
|
|
@@ -4195,31 +4476,7 @@ var sandboxService = new SandboxService();
|
|
|
4195
4476
|
|
|
4196
4477
|
// src/controllers/sandbox.ts
|
|
4197
4478
|
var import_core18 = require("@axiom-lattice/core");
|
|
4198
|
-
|
|
4199
|
-
const segments = path3.replace(/\/+$/, "").split("/");
|
|
4200
|
-
return segments[segments.length - 1] || "download";
|
|
4201
|
-
}
|
|
4202
|
-
var EXT_TO_MIME = {
|
|
4203
|
-
".txt": "text/plain",
|
|
4204
|
-
".html": "text/html",
|
|
4205
|
-
".css": "text/css",
|
|
4206
|
-
".js": "application/javascript",
|
|
4207
|
-
".json": "application/json",
|
|
4208
|
-
".pdf": "application/pdf",
|
|
4209
|
-
".png": "image/png",
|
|
4210
|
-
".jpg": "image/jpeg",
|
|
4211
|
-
".jpeg": "image/jpeg",
|
|
4212
|
-
".gif": "image/gif",
|
|
4213
|
-
".webp": "image/webp",
|
|
4214
|
-
".svg": "image/svg+xml",
|
|
4215
|
-
".zip": "application/zip",
|
|
4216
|
-
".csv": "text/csv",
|
|
4217
|
-
".xml": "application/xml"
|
|
4218
|
-
};
|
|
4219
|
-
function getContentTypeFromFilename(filename) {
|
|
4220
|
-
const ext = filename.includes(".") ? filename.slice(filename.lastIndexOf(".")).toLowerCase() : "";
|
|
4221
|
-
return EXT_TO_MIME[ext] ?? "application/octet-stream";
|
|
4222
|
-
}
|
|
4479
|
+
init_mime();
|
|
4223
4480
|
function registerSandboxProxyRoutes(app2) {
|
|
4224
4481
|
app2.post(
|
|
4225
4482
|
"/api/assistants/:assistantId/threads/:threadId/sandbox/uploadfile",
|
|
@@ -4318,6 +4575,7 @@ var import_core19 = require("@axiom-lattice/core");
|
|
|
4318
4575
|
var import_core20 = require("@axiom-lattice/core");
|
|
4319
4576
|
var import_core21 = require("@axiom-lattice/core");
|
|
4320
4577
|
var import_uuid2 = require("uuid");
|
|
4578
|
+
init_mime();
|
|
4321
4579
|
var WorkspaceController = class {
|
|
4322
4580
|
constructor() {
|
|
4323
4581
|
this.workspaceStore = (0, import_core19.getStoreLattice)("default", "workspace").store;
|
|
@@ -4489,32 +4747,6 @@ var WorkspaceController = class {
|
|
|
4489
4747
|
};
|
|
4490
4748
|
}
|
|
4491
4749
|
}
|
|
4492
|
-
getFilenameFromPath(filePath) {
|
|
4493
|
-
const segments = filePath.split("/");
|
|
4494
|
-
return segments[segments.length - 1] || "download";
|
|
4495
|
-
}
|
|
4496
|
-
getMimeType(filename) {
|
|
4497
|
-
const ext = filename.split(".").pop()?.toLowerCase() || "";
|
|
4498
|
-
const mimeTypes = {
|
|
4499
|
-
pdf: "application/pdf",
|
|
4500
|
-
csv: "text/csv",
|
|
4501
|
-
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
4502
|
-
xls: "application/vnd.ms-excel",
|
|
4503
|
-
txt: "text/plain",
|
|
4504
|
-
json: "application/json",
|
|
4505
|
-
png: "image/png",
|
|
4506
|
-
jpg: "image/jpeg",
|
|
4507
|
-
jpeg: "image/jpeg",
|
|
4508
|
-
gif: "image/gif",
|
|
4509
|
-
svg: "image/svg+xml",
|
|
4510
|
-
html: "text/html",
|
|
4511
|
-
htm: "text/html",
|
|
4512
|
-
mp3: "audio/mpeg",
|
|
4513
|
-
mp4: "video/mp4",
|
|
4514
|
-
webm: "video/webm"
|
|
4515
|
-
};
|
|
4516
|
-
return mimeTypes[ext] || "application/octet-stream";
|
|
4517
|
-
}
|
|
4518
4750
|
isBinaryContentType(filename) {
|
|
4519
4751
|
const ext = filename.split(".").pop()?.toLowerCase() || "";
|
|
4520
4752
|
const binaryExtensions = /* @__PURE__ */ new Set([
|
|
@@ -4567,7 +4799,7 @@ var WorkspaceController = class {
|
|
|
4567
4799
|
workspaceId,
|
|
4568
4800
|
projectId
|
|
4569
4801
|
};
|
|
4570
|
-
const filename2 =
|
|
4802
|
+
const filename2 = getFilenameFromPath(resolvedPath);
|
|
4571
4803
|
const isBinary = this.isBinaryContentType(filename2);
|
|
4572
4804
|
const volumeBackend = await sandboxManager.getVolumeBackendForPath(volumeConfig, resolvedPath);
|
|
4573
4805
|
let buf;
|
|
@@ -4582,14 +4814,14 @@ var WorkspaceController = class {
|
|
|
4582
4814
|
const sandbox = await sandboxManager.getSandboxFromConfig(volumeConfig);
|
|
4583
4815
|
buf = await sandbox.file.downloadFile({ file: resolvedPath });
|
|
4584
4816
|
}
|
|
4585
|
-
const inferredContentType =
|
|
4817
|
+
const inferredContentType = getContentTypeFromFilename(filename2);
|
|
4586
4818
|
const contentDisposition = `attachment; filename*=UTF-8''${encodeURIComponent(filename2)}`;
|
|
4587
4819
|
return reply.status(200).type(inferredContentType).header("Content-Disposition", contentDisposition).send(buf);
|
|
4588
4820
|
}
|
|
4589
4821
|
const { backend } = await this.getBackend(tenantId, workspaceId, projectId, assistantId, resolvedPath);
|
|
4590
4822
|
const content = await backend.read(resolvedPath, 0, Infinity);
|
|
4591
|
-
const filename =
|
|
4592
|
-
const mimeType =
|
|
4823
|
+
const filename = getFilenameFromPath(resolvedPath);
|
|
4824
|
+
const mimeType = getContentTypeFromFilename(filename);
|
|
4593
4825
|
const buffer = Buffer.from(content, "utf-8");
|
|
4594
4826
|
return reply.status(200).type(mimeType).header("Content-Disposition", `attachment; filename*=UTF-8''${encodeURIComponent(filename)}`).send(buffer);
|
|
4595
4827
|
} catch (error) {
|
|
@@ -4621,7 +4853,7 @@ var WorkspaceController = class {
|
|
|
4621
4853
|
workspaceId,
|
|
4622
4854
|
projectId
|
|
4623
4855
|
};
|
|
4624
|
-
const filename2 =
|
|
4856
|
+
const filename2 = getFilenameFromPath(resolvedPath);
|
|
4625
4857
|
const isBinary = this.isBinaryContentType(filename2);
|
|
4626
4858
|
const volumeBackend = await sandboxManager.getVolumeBackendForPath(volumeConfig, resolvedPath);
|
|
4627
4859
|
let buf;
|
|
@@ -4636,7 +4868,7 @@ var WorkspaceController = class {
|
|
|
4636
4868
|
const sandbox = await sandboxManager.getSandboxFromConfig(volumeConfig);
|
|
4637
4869
|
buf = await sandbox.file.downloadFile({ file: resolvedPath });
|
|
4638
4870
|
}
|
|
4639
|
-
const inferredContentType =
|
|
4871
|
+
const inferredContentType = getContentTypeFromFilename(filename2);
|
|
4640
4872
|
try {
|
|
4641
4873
|
const contentType = inferredContentType;
|
|
4642
4874
|
const isHtml = contentType?.toLowerCase().includes("text/html") || filename2.toLowerCase().endsWith(".html") || filename2.toLowerCase().endsWith(".htm");
|
|
@@ -4669,8 +4901,8 @@ var WorkspaceController = class {
|
|
|
4669
4901
|
}
|
|
4670
4902
|
const { backend } = await this.getBackend(tenantId, workspaceId, projectId, assistantId, resolvedPath);
|
|
4671
4903
|
const content = await backend.read(resolvedPath, 0, Infinity);
|
|
4672
|
-
const filename =
|
|
4673
|
-
const mimeType =
|
|
4904
|
+
const filename = getFilenameFromPath(resolvedPath);
|
|
4905
|
+
const mimeType = getContentTypeFromFilename(filename);
|
|
4674
4906
|
let finalContent = content;
|
|
4675
4907
|
const isHtmlFs = mimeType?.toLowerCase().includes("text/html") || filename.toLowerCase().endsWith(".html") || filename.toLowerCase().endsWith(".htm");
|
|
4676
4908
|
if (isHtmlFs) {
|
|
@@ -8474,6 +8706,23 @@ var registerLatticeRoutes = (app2, channelDeps) => {
|
|
|
8474
8706
|
);
|
|
8475
8707
|
};
|
|
8476
8708
|
|
|
8709
|
+
// src/routes/resource-routes.ts
|
|
8710
|
+
function registerResourceRoutes(app2, controller) {
|
|
8711
|
+
app2.get("/s/:token", controller.resolveResource.bind(controller));
|
|
8712
|
+
app2.get("/s/:token/*", controller.resolveResource.bind(controller));
|
|
8713
|
+
app2.post("/s/:token/unlock", controller.unlockShare.bind(controller));
|
|
8714
|
+
app2.options("/s/:token", async (_req, reply) => {
|
|
8715
|
+
reply.header("Access-Control-Allow-Origin", "*");
|
|
8716
|
+
reply.header("Access-Control-Allow-Methods", "GET, OPTIONS, POST");
|
|
8717
|
+
reply.header("Access-Control-Allow-Headers", "Content-Type");
|
|
8718
|
+
return reply.status(204).send();
|
|
8719
|
+
});
|
|
8720
|
+
app2.post("/api/resources/share", controller.createShare.bind(controller));
|
|
8721
|
+
app2.get("/api/resources/shares", controller.listShares.bind(controller));
|
|
8722
|
+
app2.patch("/api/resources/share/:token", controller.updateShare.bind(controller));
|
|
8723
|
+
app2.delete("/api/resources/share/:token", controller.revokeShare.bind(controller));
|
|
8724
|
+
}
|
|
8725
|
+
|
|
8477
8726
|
// src/router/MessageRouter.ts
|
|
8478
8727
|
var import_core32 = require("@axiom-lattice/core");
|
|
8479
8728
|
var import_crypto9 = require("crypto");
|
|
@@ -8958,7 +9207,7 @@ function createAuditLoggerMiddleware() {
|
|
|
8958
9207
|
}
|
|
8959
9208
|
|
|
8960
9209
|
// src/index.ts
|
|
8961
|
-
var
|
|
9210
|
+
var import_core36 = require("@axiom-lattice/core");
|
|
8962
9211
|
|
|
8963
9212
|
// src/swagger.ts
|
|
8964
9213
|
var import_swagger = __toESM(require("@fastify/swagger"));
|
|
@@ -9275,7 +9524,7 @@ _AgentTaskConsumer.agent_run_endpoint = "http://localhost:4001/api/runs";
|
|
|
9275
9524
|
var AgentTaskConsumer = _AgentTaskConsumer;
|
|
9276
9525
|
|
|
9277
9526
|
// src/index.ts
|
|
9278
|
-
var
|
|
9527
|
+
var import_core37 = require("@axiom-lattice/core");
|
|
9279
9528
|
var import_protocols5 = require("@axiom-lattice/protocols");
|
|
9280
9529
|
var import_meta = {};
|
|
9281
9530
|
process.on("unhandledRejection", (reason, promise) => {
|
|
@@ -9291,11 +9540,11 @@ var DEFAULT_LOGGER_CONFIG = {
|
|
|
9291
9540
|
var loggerLattice = initializeLogger(DEFAULT_LOGGER_CONFIG);
|
|
9292
9541
|
var logger5 = loggerLattice.client;
|
|
9293
9542
|
function initializeLogger(config) {
|
|
9294
|
-
if (
|
|
9295
|
-
|
|
9543
|
+
if (import_core37.loggerLatticeManager.hasLattice("default")) {
|
|
9544
|
+
import_core37.loggerLatticeManager.removeLattice("default");
|
|
9296
9545
|
}
|
|
9297
|
-
(0,
|
|
9298
|
-
return (0,
|
|
9546
|
+
(0, import_core37.registerLoggerLattice)("default", config);
|
|
9547
|
+
return (0, import_core37.getLoggerLattice)("default");
|
|
9299
9548
|
}
|
|
9300
9549
|
var app = (0, import_fastify.default)({
|
|
9301
9550
|
logger: false,
|
|
@@ -9332,6 +9581,7 @@ app.addHook("preHandler", async (request, reply) => {
|
|
|
9332
9581
|
if (!authRequired) return;
|
|
9333
9582
|
if (request.method === "OPTIONS") return;
|
|
9334
9583
|
if (PUBLIC_ROUTES.some((r) => request.url === r)) return;
|
|
9584
|
+
if (request.url.startsWith("/s/")) return;
|
|
9335
9585
|
const urlPath = request.url.split("?")[0];
|
|
9336
9586
|
if (urlPath.includes("/viewfile") || urlPath.includes("/downloadfile")) return;
|
|
9337
9587
|
return reply.status(401).send({
|
|
@@ -9406,7 +9656,7 @@ app.setErrorHandler((error, request, reply) => {
|
|
|
9406
9656
|
});
|
|
9407
9657
|
function getConfiguredSandboxProvider() {
|
|
9408
9658
|
const sandboxProviderType = process.env.SANDBOX_PROVIDER_TYPE || "microsandbox-remote";
|
|
9409
|
-
return (0,
|
|
9659
|
+
return (0, import_core37.createSandboxProvider)({
|
|
9410
9660
|
type: sandboxProviderType,
|
|
9411
9661
|
remoteBaseURL: process.env.SANDBOX_BASE_URL,
|
|
9412
9662
|
microsandboxServiceBaseURL: process.env.MICROSANDBOX_SERVICE_BASE_URL,
|
|
@@ -9442,7 +9692,7 @@ var start = async (config) => {
|
|
|
9442
9692
|
const { getStoreLattice: getStore2 } = await import("@axiom-lattice/core");
|
|
9443
9693
|
const bindingStore = getStore2("default", "channelBinding").store;
|
|
9444
9694
|
const installationStore = getStore2("default", "channelInstallation").store;
|
|
9445
|
-
(0,
|
|
9695
|
+
(0, import_core36.setBindingRegistry)(bindingStore);
|
|
9446
9696
|
const router = new MessageRouter({
|
|
9447
9697
|
middlewares: [
|
|
9448
9698
|
createDeduplicationMiddleware(),
|
|
@@ -9468,8 +9718,8 @@ var start = async (config) => {
|
|
|
9468
9718
|
});
|
|
9469
9719
|
}
|
|
9470
9720
|
try {
|
|
9471
|
-
const menuStore = (0,
|
|
9472
|
-
(0,
|
|
9721
|
+
const menuStore = (0, import_core37.getStoreLattice)("default", "menu").store;
|
|
9722
|
+
(0, import_core36.setMenuRegistry)(menuStore);
|
|
9473
9723
|
logger5.info("Menu registry initialized");
|
|
9474
9724
|
} catch {
|
|
9475
9725
|
}
|
|
@@ -9477,10 +9727,27 @@ var start = async (config) => {
|
|
|
9477
9727
|
setChannelControllerDeps({ adapterRegistry, router: channelDeps.router });
|
|
9478
9728
|
}
|
|
9479
9729
|
registerLatticeRoutes(app, channelDeps);
|
|
9480
|
-
if (!
|
|
9481
|
-
|
|
9730
|
+
if (!import_core37.sandboxLatticeManager.hasLattice("default")) {
|
|
9731
|
+
import_core37.sandboxLatticeManager.registerLattice("default", getConfiguredSandboxProvider());
|
|
9482
9732
|
logger5.info("Registered sandbox manager from env configuration");
|
|
9483
9733
|
}
|
|
9734
|
+
try {
|
|
9735
|
+
const { ResourceController: ResourceController2 } = await Promise.resolve().then(() => (init_resources(), resources_exports));
|
|
9736
|
+
const sharedResourceStore = (0, import_core37.getStoreLattice)("default", "sharedResource").store;
|
|
9737
|
+
const cache = new import_core37.TokenCache();
|
|
9738
|
+
const resourceController = new ResourceController2({
|
|
9739
|
+
store: sharedResourceStore,
|
|
9740
|
+
sandboxManager: import_core37.sandboxLatticeManager,
|
|
9741
|
+
cache,
|
|
9742
|
+
logger: logger5
|
|
9743
|
+
});
|
|
9744
|
+
registerResourceRoutes(app, resourceController);
|
|
9745
|
+
logger5.info("Resource share routes registered");
|
|
9746
|
+
} catch (err) {
|
|
9747
|
+
logger5.warn("Resource share infrastructure unavailable", {
|
|
9748
|
+
error: err instanceof Error ? err.message : String(err)
|
|
9749
|
+
});
|
|
9750
|
+
}
|
|
9484
9751
|
if (channelDeps && process.env.CHANNELS_ENABLED !== "false") {
|
|
9485
9752
|
const { connectAllChannels } = await import("@axiom-lattice/core");
|
|
9486
9753
|
try {
|
|
@@ -9510,7 +9777,7 @@ var start = async (config) => {
|
|
|
9510
9777
|
agentTaskConsumer.startPollingQueue();
|
|
9511
9778
|
}
|
|
9512
9779
|
}
|
|
9513
|
-
|
|
9780
|
+
import_core37.agentInstanceManager.restore().then((stats) => {
|
|
9514
9781
|
logger5.info(`Agent recovery complete: ${stats.restored} threads restored, ${stats.errors} errors`);
|
|
9515
9782
|
}).catch((error) => {
|
|
9516
9783
|
logger5.error("Agent recovery failed", { error });
|