@axiom-lattice/gateway 2.1.100 → 2.1.102
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 +25 -0
- package/dist/{WechatChannelAdapter-QQYOHZTL.mjs → WechatChannelAdapter-WSDKR4OA.mjs} +23 -17
- package/dist/WechatChannelAdapter-WSDKR4OA.mjs.map +1 -0
- package/dist/chunk-R4ZO3HZ3.mjs +46 -0
- package/dist/chunk-R4ZO3HZ3.mjs.map +1 -0
- package/dist/index.js +325 -94
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +64 -67
- package/dist/index.mjs.map +1 -1
- package/dist/resources-3DGHISBZ.mjs +183 -0
- package/dist/resources-3DGHISBZ.mjs.map +1 -0
- package/package.json +6 -6
- package/src/channels/wechat/WechatChannelAdapter.ts +3 -3
- package/src/channels/wechat/__tests__/context-store.test.ts +148 -0
- package/src/channels/wechat/context-store.ts +22 -15
- package/src/controllers/__tests__/mime.test.ts +74 -0
- package/src/controllers/__tests__/resources.test.ts +99 -0
- package/src/controllers/resources.ts +252 -0
- package/src/controllers/sandbox.ts +1 -30
- package/src/controllers/workspace.ts +25 -45
- package/src/index.ts +24 -0
- package/src/routes/resource-routes.ts +24 -0
- package/src/utils/mime.ts +43 -0
- package/dist/WechatChannelAdapter-QQYOHZTL.mjs.map +0 -1
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({
|
|
@@ -311,31 +358,37 @@ var init_wechat_client = __esm({
|
|
|
311
358
|
});
|
|
312
359
|
|
|
313
360
|
// src/channels/wechat/context-store.ts
|
|
314
|
-
function
|
|
315
|
-
|
|
361
|
+
function makeKey(installationId, senderId) {
|
|
362
|
+
return `${installationId}::${senderId}`;
|
|
363
|
+
}
|
|
364
|
+
function getContextToken(installationId, senderId) {
|
|
365
|
+
const key = makeKey(installationId, senderId);
|
|
366
|
+
const entry = store.get(key);
|
|
316
367
|
if (!entry) return void 0;
|
|
317
368
|
if (Date.now() - entry.updatedAt > TOKEN_TTL_MS) {
|
|
318
|
-
deleteContextToken(senderId);
|
|
369
|
+
deleteContextToken(installationId, senderId);
|
|
319
370
|
return void 0;
|
|
320
371
|
}
|
|
321
372
|
return entry.token;
|
|
322
373
|
}
|
|
323
|
-
function setContextToken(senderId, token) {
|
|
324
|
-
const
|
|
374
|
+
function setContextToken(installationId, senderId, token) {
|
|
375
|
+
const key = makeKey(installationId, senderId);
|
|
376
|
+
const existingTimer = timers.get(key);
|
|
325
377
|
if (existingTimer) clearTimeout(existingTimer);
|
|
326
|
-
store.set(
|
|
378
|
+
store.set(key, { token, installationId, senderId, updatedAt: Date.now() });
|
|
327
379
|
const timer = setTimeout(() => {
|
|
328
|
-
store.delete(
|
|
329
|
-
timers.delete(
|
|
380
|
+
store.delete(key);
|
|
381
|
+
timers.delete(key);
|
|
330
382
|
}, TOKEN_TTL_MS);
|
|
331
|
-
timers.set(
|
|
383
|
+
timers.set(key, timer);
|
|
332
384
|
}
|
|
333
|
-
function deleteContextToken(senderId) {
|
|
334
|
-
|
|
335
|
-
|
|
385
|
+
function deleteContextToken(installationId, senderId) {
|
|
386
|
+
const key = makeKey(installationId, senderId);
|
|
387
|
+
store.delete(key);
|
|
388
|
+
const timer = timers.get(key);
|
|
336
389
|
if (timer) {
|
|
337
390
|
clearTimeout(timer);
|
|
338
|
-
timers.delete(
|
|
391
|
+
timers.delete(key);
|
|
339
392
|
}
|
|
340
393
|
}
|
|
341
394
|
var TOKEN_TTL_MS, store, timers;
|
|
@@ -402,7 +455,7 @@ var init_WechatChannelAdapter = __esm({
|
|
|
402
455
|
const text = extractText(msg);
|
|
403
456
|
if (!text) return null;
|
|
404
457
|
if (msg.context_token) {
|
|
405
|
-
setContextToken(senderId, msg.context_token);
|
|
458
|
+
setContextToken(installation.id, senderId, msg.context_token);
|
|
406
459
|
}
|
|
407
460
|
return {
|
|
408
461
|
channel: "wechat",
|
|
@@ -428,13 +481,13 @@ var init_WechatChannelAdapter = __esm({
|
|
|
428
481
|
},
|
|
429
482
|
async sendReply(replyTarget, message, installation) {
|
|
430
483
|
const senderId = replyTarget.rawTarget.senderId;
|
|
431
|
-
const contextToken = getContextToken(senderId);
|
|
484
|
+
const contextToken = getContextToken(installation.id, senderId);
|
|
432
485
|
if (!contextToken) {
|
|
433
486
|
logger4.warn("WeChat context token expired, cannot send reply", {
|
|
434
487
|
installationId: installation.id,
|
|
435
488
|
senderId
|
|
436
489
|
});
|
|
437
|
-
deleteContextToken(senderId);
|
|
490
|
+
deleteContextToken(installation.id, senderId);
|
|
438
491
|
return;
|
|
439
492
|
}
|
|
440
493
|
const { botToken } = installation.config;
|
|
@@ -1139,6 +1192,190 @@ var init_a2a = __esm({
|
|
|
1139
1192
|
}
|
|
1140
1193
|
});
|
|
1141
1194
|
|
|
1195
|
+
// src/controllers/resources.ts
|
|
1196
|
+
var resources_exports = {};
|
|
1197
|
+
__export(resources_exports, {
|
|
1198
|
+
ResourceController: () => ResourceController
|
|
1199
|
+
});
|
|
1200
|
+
var import_core35, ResourceController;
|
|
1201
|
+
var init_resources = __esm({
|
|
1202
|
+
"src/controllers/resources.ts"() {
|
|
1203
|
+
"use strict";
|
|
1204
|
+
import_core35 = require("@axiom-lattice/core");
|
|
1205
|
+
init_mime();
|
|
1206
|
+
ResourceController = class {
|
|
1207
|
+
constructor(deps) {
|
|
1208
|
+
this.deps = deps;
|
|
1209
|
+
}
|
|
1210
|
+
async createShare(request, reply) {
|
|
1211
|
+
const userId = request.user ? request.user.id ?? "unknown" : "unknown";
|
|
1212
|
+
const tenantId = request.headers["x-tenant-id"] || "default";
|
|
1213
|
+
const workspaceId = request.headers["x-workspace-id"];
|
|
1214
|
+
const projectId = request.headers["x-project-id"];
|
|
1215
|
+
const body = request.body;
|
|
1216
|
+
if (!workspaceId || !projectId) {
|
|
1217
|
+
return reply.status(400).send({ error: "x-workspace-id and x-project-id headers required" });
|
|
1218
|
+
}
|
|
1219
|
+
const payload = (0, import_core35.createSharePayload)(
|
|
1220
|
+
tenantId,
|
|
1221
|
+
workspaceId,
|
|
1222
|
+
projectId,
|
|
1223
|
+
userId,
|
|
1224
|
+
body
|
|
1225
|
+
);
|
|
1226
|
+
const token = (0, import_core35.generateToken)();
|
|
1227
|
+
try {
|
|
1228
|
+
await this.deps.store.create({ ...payload, token });
|
|
1229
|
+
this.deps.logger.info(
|
|
1230
|
+
"Share created",
|
|
1231
|
+
{ token, resourcePath: body.resourcePath, userId }
|
|
1232
|
+
);
|
|
1233
|
+
} catch {
|
|
1234
|
+
return reply.status(500).send({ error: "Failed to create share" });
|
|
1235
|
+
}
|
|
1236
|
+
return reply.status(201).send({ token, url: `/s/${token}` });
|
|
1237
|
+
}
|
|
1238
|
+
async listShares(request, reply) {
|
|
1239
|
+
const userId = request.user ? request.user.id ?? "unknown" : "unknown";
|
|
1240
|
+
const tenantId = request.headers["x-tenant-id"] || "default";
|
|
1241
|
+
const shares = await this.deps.store.listByUser(tenantId, userId);
|
|
1242
|
+
return reply.send(shares);
|
|
1243
|
+
}
|
|
1244
|
+
async updateShare(request, reply) {
|
|
1245
|
+
const { token } = request.params;
|
|
1246
|
+
const userId = request.user ? request.user.id : void 0;
|
|
1247
|
+
const patch = request.body;
|
|
1248
|
+
const record = await this.deps.store.findByToken(token);
|
|
1249
|
+
if (!record || record.createdBy !== userId) {
|
|
1250
|
+
return reply.status(404).send({ error: "Share not found" });
|
|
1251
|
+
}
|
|
1252
|
+
await this.deps.store.update(token, patch);
|
|
1253
|
+
if (patch.revoked) {
|
|
1254
|
+
this.deps.cache.invalidate(token);
|
|
1255
|
+
}
|
|
1256
|
+
return reply.send({ ok: true });
|
|
1257
|
+
}
|
|
1258
|
+
async revokeShare(request, reply) {
|
|
1259
|
+
const { token } = request.params;
|
|
1260
|
+
const userId = request.user ? request.user.id : void 0;
|
|
1261
|
+
const record = await this.deps.store.findByToken(token);
|
|
1262
|
+
if (!record || record.createdBy !== userId) {
|
|
1263
|
+
return reply.status(404).send({ error: "Share not found" });
|
|
1264
|
+
}
|
|
1265
|
+
await this.deps.store.update(token, { revoked: true });
|
|
1266
|
+
this.deps.cache.invalidate(token);
|
|
1267
|
+
return reply.send({ ok: true });
|
|
1268
|
+
}
|
|
1269
|
+
async resolveResource(request, reply) {
|
|
1270
|
+
const params = request.params;
|
|
1271
|
+
const { token } = params;
|
|
1272
|
+
const subPath = params["*"] ?? "";
|
|
1273
|
+
const cached = this.deps.cache.get(token);
|
|
1274
|
+
if (cached && !cached.requiresUnlock) {
|
|
1275
|
+
return this._serveFile(cached.address, token, subPath, reply);
|
|
1276
|
+
}
|
|
1277
|
+
const record = await this.deps.store.findByToken(token);
|
|
1278
|
+
if (!record || record.revoked) return reply.status(404).send("Not found");
|
|
1279
|
+
if (record.expiresAt && new Date(record.expiresAt) < /* @__PURE__ */ new Date()) {
|
|
1280
|
+
return reply.status(410).send("Expired");
|
|
1281
|
+
}
|
|
1282
|
+
if (!this._isInternalRequest(request)) {
|
|
1283
|
+
if (record.visibility === "password") {
|
|
1284
|
+
const unlocked = this._isUnlocked(request, token);
|
|
1285
|
+
if (!unlocked) {
|
|
1286
|
+
this.deps.cache.set(token, { address: record.address, requiresUnlock: true });
|
|
1287
|
+
return reply.type("text/html").send(this._passwordPage(token));
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
if (record.maxAccess !== null) {
|
|
1292
|
+
const ok = await this.deps.store.atomicIncrementAccess(token);
|
|
1293
|
+
if (!ok) return reply.status(410).send("Access limit reached");
|
|
1294
|
+
} else {
|
|
1295
|
+
this.deps.store.incrementAccess(token).catch(() => {
|
|
1296
|
+
});
|
|
1297
|
+
}
|
|
1298
|
+
this.deps.cache.set(token, {
|
|
1299
|
+
address: record.address,
|
|
1300
|
+
requiresUnlock: record.visibility === "password" && !this._isInternalRequest(request)
|
|
1301
|
+
});
|
|
1302
|
+
return this._serveFile(record.address, token, subPath, reply);
|
|
1303
|
+
}
|
|
1304
|
+
async unlockShare(request, reply) {
|
|
1305
|
+
const { token } = request.params;
|
|
1306
|
+
const { password } = request.body;
|
|
1307
|
+
const record = await this.deps.store.findByToken(token);
|
|
1308
|
+
if (!record || !record.passwordHash) {
|
|
1309
|
+
return reply.status(404).send({ error: "Invalid request" });
|
|
1310
|
+
}
|
|
1311
|
+
const valid = password === record.passwordHash;
|
|
1312
|
+
if (!valid) {
|
|
1313
|
+
return reply.status(401).send({ error: "Incorrect password" });
|
|
1314
|
+
}
|
|
1315
|
+
reply.header(
|
|
1316
|
+
"Set-Cookie",
|
|
1317
|
+
`share_unlock_${token}=1; Max-Age=86400; Path=/s/${token}; SameSite=Lax; HttpOnly; Secure`
|
|
1318
|
+
);
|
|
1319
|
+
return reply.send({ ok: true });
|
|
1320
|
+
}
|
|
1321
|
+
_isInternalRequest(request) {
|
|
1322
|
+
const user = request.user;
|
|
1323
|
+
return !!user && !!user.id;
|
|
1324
|
+
}
|
|
1325
|
+
_isUnlocked(request, token) {
|
|
1326
|
+
const cookie = request.headers.cookie ?? "";
|
|
1327
|
+
return cookie.includes(`share_unlock_${token}=1`);
|
|
1328
|
+
}
|
|
1329
|
+
async _serveFile(address, token, subPath, reply) {
|
|
1330
|
+
const provider = this.deps.sandboxManager.getDefaultProvider();
|
|
1331
|
+
const resolver = provider.getResourceResolver();
|
|
1332
|
+
const fullPath = subPath ? this._resolveSafeSubPath(address.resourcePath, subPath) : address.resourcePath;
|
|
1333
|
+
let buf;
|
|
1334
|
+
try {
|
|
1335
|
+
buf = await resolver.resolve({ ...address, resourcePath: fullPath });
|
|
1336
|
+
} catch (err) {
|
|
1337
|
+
this.deps.logger.warn(
|
|
1338
|
+
"Resource resolution failed",
|
|
1339
|
+
{ token, resourcePath: fullPath, error: err.message }
|
|
1340
|
+
);
|
|
1341
|
+
return reply.status(404).send("File not found");
|
|
1342
|
+
}
|
|
1343
|
+
const filename = fullPath.split("/").pop() || "download";
|
|
1344
|
+
const isHtml = !subPath && /\.(html|htm)$/i.test(filename);
|
|
1345
|
+
if (isHtml) {
|
|
1346
|
+
buf = this._injectBaseTag(buf, token);
|
|
1347
|
+
}
|
|
1348
|
+
const contentType = getContentTypeFromFilename(filename);
|
|
1349
|
+
return reply.status(200).type(contentType).header("Content-Disposition", `inline; filename="${filename}"`).header("Access-Control-Allow-Origin", "*").send(buf);
|
|
1350
|
+
}
|
|
1351
|
+
_resolveSafeSubPath(entryFile, subPath) {
|
|
1352
|
+
if (!subPath) return entryFile;
|
|
1353
|
+
if (subPath.includes("..")) throw new Error("Path traversal denied");
|
|
1354
|
+
const entryDir = entryFile.replace(/[^/]+$/, "");
|
|
1355
|
+
return (entryDir + subPath).replace(/\/+/g, "/");
|
|
1356
|
+
}
|
|
1357
|
+
_injectBaseTag(buf, token) {
|
|
1358
|
+
const html = buf.toString("utf-8");
|
|
1359
|
+
if (/<base\b/i.test(html)) return buf;
|
|
1360
|
+
const baseTag = `<base href="/s/${token}/">`;
|
|
1361
|
+
if (html.includes("</head>")) {
|
|
1362
|
+
return Buffer.from(html.replace("</head>", `${baseTag}</head>`), "utf-8");
|
|
1363
|
+
}
|
|
1364
|
+
if (html.includes("<head>")) {
|
|
1365
|
+
return Buffer.from(html.replace("<head>", `<head>${baseTag}`), "utf-8");
|
|
1366
|
+
}
|
|
1367
|
+
if (html.includes("<html>")) {
|
|
1368
|
+
return Buffer.from(html.replace("<html>", `<html>${baseTag}`), "utf-8");
|
|
1369
|
+
}
|
|
1370
|
+
return Buffer.from(baseTag + html, "utf-8");
|
|
1371
|
+
}
|
|
1372
|
+
_passwordPage(token) {
|
|
1373
|
+
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>`;
|
|
1374
|
+
}
|
|
1375
|
+
};
|
|
1376
|
+
}
|
|
1377
|
+
});
|
|
1378
|
+
|
|
1142
1379
|
// src/index.ts
|
|
1143
1380
|
var index_exports = {};
|
|
1144
1381
|
__export(index_exports, {
|
|
@@ -4189,31 +4426,7 @@ var sandboxService = new SandboxService();
|
|
|
4189
4426
|
|
|
4190
4427
|
// src/controllers/sandbox.ts
|
|
4191
4428
|
var import_core18 = require("@axiom-lattice/core");
|
|
4192
|
-
|
|
4193
|
-
const segments = path3.replace(/\/+$/, "").split("/");
|
|
4194
|
-
return segments[segments.length - 1] || "download";
|
|
4195
|
-
}
|
|
4196
|
-
var EXT_TO_MIME = {
|
|
4197
|
-
".txt": "text/plain",
|
|
4198
|
-
".html": "text/html",
|
|
4199
|
-
".css": "text/css",
|
|
4200
|
-
".js": "application/javascript",
|
|
4201
|
-
".json": "application/json",
|
|
4202
|
-
".pdf": "application/pdf",
|
|
4203
|
-
".png": "image/png",
|
|
4204
|
-
".jpg": "image/jpeg",
|
|
4205
|
-
".jpeg": "image/jpeg",
|
|
4206
|
-
".gif": "image/gif",
|
|
4207
|
-
".webp": "image/webp",
|
|
4208
|
-
".svg": "image/svg+xml",
|
|
4209
|
-
".zip": "application/zip",
|
|
4210
|
-
".csv": "text/csv",
|
|
4211
|
-
".xml": "application/xml"
|
|
4212
|
-
};
|
|
4213
|
-
function getContentTypeFromFilename(filename) {
|
|
4214
|
-
const ext = filename.includes(".") ? filename.slice(filename.lastIndexOf(".")).toLowerCase() : "";
|
|
4215
|
-
return EXT_TO_MIME[ext] ?? "application/octet-stream";
|
|
4216
|
-
}
|
|
4429
|
+
init_mime();
|
|
4217
4430
|
function registerSandboxProxyRoutes(app2) {
|
|
4218
4431
|
app2.post(
|
|
4219
4432
|
"/api/assistants/:assistantId/threads/:threadId/sandbox/uploadfile",
|
|
@@ -4312,6 +4525,7 @@ var import_core19 = require("@axiom-lattice/core");
|
|
|
4312
4525
|
var import_core20 = require("@axiom-lattice/core");
|
|
4313
4526
|
var import_core21 = require("@axiom-lattice/core");
|
|
4314
4527
|
var import_uuid2 = require("uuid");
|
|
4528
|
+
init_mime();
|
|
4315
4529
|
var WorkspaceController = class {
|
|
4316
4530
|
constructor() {
|
|
4317
4531
|
this.workspaceStore = (0, import_core19.getStoreLattice)("default", "workspace").store;
|
|
@@ -4483,32 +4697,6 @@ var WorkspaceController = class {
|
|
|
4483
4697
|
};
|
|
4484
4698
|
}
|
|
4485
4699
|
}
|
|
4486
|
-
getFilenameFromPath(filePath) {
|
|
4487
|
-
const segments = filePath.split("/");
|
|
4488
|
-
return segments[segments.length - 1] || "download";
|
|
4489
|
-
}
|
|
4490
|
-
getMimeType(filename) {
|
|
4491
|
-
const ext = filename.split(".").pop()?.toLowerCase() || "";
|
|
4492
|
-
const mimeTypes = {
|
|
4493
|
-
pdf: "application/pdf",
|
|
4494
|
-
csv: "text/csv",
|
|
4495
|
-
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
4496
|
-
xls: "application/vnd.ms-excel",
|
|
4497
|
-
txt: "text/plain",
|
|
4498
|
-
json: "application/json",
|
|
4499
|
-
png: "image/png",
|
|
4500
|
-
jpg: "image/jpeg",
|
|
4501
|
-
jpeg: "image/jpeg",
|
|
4502
|
-
gif: "image/gif",
|
|
4503
|
-
svg: "image/svg+xml",
|
|
4504
|
-
html: "text/html",
|
|
4505
|
-
htm: "text/html",
|
|
4506
|
-
mp3: "audio/mpeg",
|
|
4507
|
-
mp4: "video/mp4",
|
|
4508
|
-
webm: "video/webm"
|
|
4509
|
-
};
|
|
4510
|
-
return mimeTypes[ext] || "application/octet-stream";
|
|
4511
|
-
}
|
|
4512
4700
|
isBinaryContentType(filename) {
|
|
4513
4701
|
const ext = filename.split(".").pop()?.toLowerCase() || "";
|
|
4514
4702
|
const binaryExtensions = /* @__PURE__ */ new Set([
|
|
@@ -4561,25 +4749,29 @@ var WorkspaceController = class {
|
|
|
4561
4749
|
workspaceId,
|
|
4562
4750
|
projectId
|
|
4563
4751
|
};
|
|
4564
|
-
const filename2 =
|
|
4752
|
+
const filename2 = getFilenameFromPath(resolvedPath);
|
|
4565
4753
|
const isBinary = this.isBinaryContentType(filename2);
|
|
4566
4754
|
const volumeBackend = await sandboxManager.getVolumeBackendForPath(volumeConfig, resolvedPath);
|
|
4567
4755
|
let buf;
|
|
4568
|
-
if (volumeBackend
|
|
4569
|
-
|
|
4570
|
-
|
|
4756
|
+
if (volumeBackend) {
|
|
4757
|
+
if (isBinary && volumeBackend.readBinary) {
|
|
4758
|
+
buf = await volumeBackend.readBinary(resolvedPath);
|
|
4759
|
+
} else {
|
|
4760
|
+
const fileData = await volumeBackend.readRaw(resolvedPath);
|
|
4761
|
+
buf = Buffer.from(fileData.content.join("\n"), "utf-8");
|
|
4762
|
+
}
|
|
4571
4763
|
} else {
|
|
4572
4764
|
const sandbox = await sandboxManager.getSandboxFromConfig(volumeConfig);
|
|
4573
4765
|
buf = await sandbox.file.downloadFile({ file: resolvedPath });
|
|
4574
4766
|
}
|
|
4575
|
-
const inferredContentType =
|
|
4767
|
+
const inferredContentType = getContentTypeFromFilename(filename2);
|
|
4576
4768
|
const contentDisposition = `attachment; filename*=UTF-8''${encodeURIComponent(filename2)}`;
|
|
4577
4769
|
return reply.status(200).type(inferredContentType).header("Content-Disposition", contentDisposition).send(buf);
|
|
4578
4770
|
}
|
|
4579
4771
|
const { backend } = await this.getBackend(tenantId, workspaceId, projectId, assistantId, resolvedPath);
|
|
4580
4772
|
const content = await backend.read(resolvedPath, 0, Infinity);
|
|
4581
|
-
const filename =
|
|
4582
|
-
const mimeType =
|
|
4773
|
+
const filename = getFilenameFromPath(resolvedPath);
|
|
4774
|
+
const mimeType = getContentTypeFromFilename(filename);
|
|
4583
4775
|
const buffer = Buffer.from(content, "utf-8");
|
|
4584
4776
|
return reply.status(200).type(mimeType).header("Content-Disposition", `attachment; filename*=UTF-8''${encodeURIComponent(filename)}`).send(buffer);
|
|
4585
4777
|
} catch (error) {
|
|
@@ -4611,18 +4803,22 @@ var WorkspaceController = class {
|
|
|
4611
4803
|
workspaceId,
|
|
4612
4804
|
projectId
|
|
4613
4805
|
};
|
|
4614
|
-
const filename2 =
|
|
4806
|
+
const filename2 = getFilenameFromPath(resolvedPath);
|
|
4615
4807
|
const isBinary = this.isBinaryContentType(filename2);
|
|
4616
4808
|
const volumeBackend = await sandboxManager.getVolumeBackendForPath(volumeConfig, resolvedPath);
|
|
4617
4809
|
let buf;
|
|
4618
|
-
if (volumeBackend
|
|
4619
|
-
|
|
4620
|
-
|
|
4810
|
+
if (volumeBackend) {
|
|
4811
|
+
if (isBinary && volumeBackend.readBinary) {
|
|
4812
|
+
buf = await volumeBackend.readBinary(resolvedPath);
|
|
4813
|
+
} else {
|
|
4814
|
+
const fileData = await volumeBackend.readRaw(resolvedPath);
|
|
4815
|
+
buf = Buffer.from(fileData.content.join("\n"), "utf-8");
|
|
4816
|
+
}
|
|
4621
4817
|
} else {
|
|
4622
4818
|
const sandbox = await sandboxManager.getSandboxFromConfig(volumeConfig);
|
|
4623
4819
|
buf = await sandbox.file.downloadFile({ file: resolvedPath });
|
|
4624
4820
|
}
|
|
4625
|
-
const inferredContentType =
|
|
4821
|
+
const inferredContentType = getContentTypeFromFilename(filename2);
|
|
4626
4822
|
try {
|
|
4627
4823
|
const contentType = inferredContentType;
|
|
4628
4824
|
const isHtml = contentType?.toLowerCase().includes("text/html") || filename2.toLowerCase().endsWith(".html") || filename2.toLowerCase().endsWith(".htm");
|
|
@@ -4655,8 +4851,8 @@ var WorkspaceController = class {
|
|
|
4655
4851
|
}
|
|
4656
4852
|
const { backend } = await this.getBackend(tenantId, workspaceId, projectId, assistantId, resolvedPath);
|
|
4657
4853
|
const content = await backend.read(resolvedPath, 0, Infinity);
|
|
4658
|
-
const filename =
|
|
4659
|
-
const mimeType =
|
|
4854
|
+
const filename = getFilenameFromPath(resolvedPath);
|
|
4855
|
+
const mimeType = getContentTypeFromFilename(filename);
|
|
4660
4856
|
let finalContent = content;
|
|
4661
4857
|
const isHtmlFs = mimeType?.toLowerCase().includes("text/html") || filename.toLowerCase().endsWith(".html") || filename.toLowerCase().endsWith(".htm");
|
|
4662
4858
|
if (isHtmlFs) {
|
|
@@ -8460,6 +8656,23 @@ var registerLatticeRoutes = (app2, channelDeps) => {
|
|
|
8460
8656
|
);
|
|
8461
8657
|
};
|
|
8462
8658
|
|
|
8659
|
+
// src/routes/resource-routes.ts
|
|
8660
|
+
function registerResourceRoutes(app2, controller) {
|
|
8661
|
+
app2.get("/s/:token", controller.resolveResource.bind(controller));
|
|
8662
|
+
app2.get("/s/:token/*", controller.resolveResource.bind(controller));
|
|
8663
|
+
app2.post("/s/:token/unlock", controller.unlockShare.bind(controller));
|
|
8664
|
+
app2.options("/s/:token", async (_req, reply) => {
|
|
8665
|
+
reply.header("Access-Control-Allow-Origin", "*");
|
|
8666
|
+
reply.header("Access-Control-Allow-Methods", "GET, OPTIONS, POST");
|
|
8667
|
+
reply.header("Access-Control-Allow-Headers", "Content-Type");
|
|
8668
|
+
return reply.status(204).send();
|
|
8669
|
+
});
|
|
8670
|
+
app2.post("/api/resources/share", controller.createShare.bind(controller));
|
|
8671
|
+
app2.get("/api/resources/shares", controller.listShares.bind(controller));
|
|
8672
|
+
app2.patch("/api/resources/share/:token", controller.updateShare.bind(controller));
|
|
8673
|
+
app2.delete("/api/resources/share/:token", controller.revokeShare.bind(controller));
|
|
8674
|
+
}
|
|
8675
|
+
|
|
8463
8676
|
// src/router/MessageRouter.ts
|
|
8464
8677
|
var import_core32 = require("@axiom-lattice/core");
|
|
8465
8678
|
var import_crypto9 = require("crypto");
|
|
@@ -8944,7 +9157,7 @@ function createAuditLoggerMiddleware() {
|
|
|
8944
9157
|
}
|
|
8945
9158
|
|
|
8946
9159
|
// src/index.ts
|
|
8947
|
-
var
|
|
9160
|
+
var import_core36 = require("@axiom-lattice/core");
|
|
8948
9161
|
|
|
8949
9162
|
// src/swagger.ts
|
|
8950
9163
|
var import_swagger = __toESM(require("@fastify/swagger"));
|
|
@@ -9261,7 +9474,7 @@ _AgentTaskConsumer.agent_run_endpoint = "http://localhost:4001/api/runs";
|
|
|
9261
9474
|
var AgentTaskConsumer = _AgentTaskConsumer;
|
|
9262
9475
|
|
|
9263
9476
|
// src/index.ts
|
|
9264
|
-
var
|
|
9477
|
+
var import_core37 = require("@axiom-lattice/core");
|
|
9265
9478
|
var import_protocols5 = require("@axiom-lattice/protocols");
|
|
9266
9479
|
var import_meta = {};
|
|
9267
9480
|
process.on("unhandledRejection", (reason, promise) => {
|
|
@@ -9277,11 +9490,11 @@ var DEFAULT_LOGGER_CONFIG = {
|
|
|
9277
9490
|
var loggerLattice = initializeLogger(DEFAULT_LOGGER_CONFIG);
|
|
9278
9491
|
var logger5 = loggerLattice.client;
|
|
9279
9492
|
function initializeLogger(config) {
|
|
9280
|
-
if (
|
|
9281
|
-
|
|
9493
|
+
if (import_core37.loggerLatticeManager.hasLattice("default")) {
|
|
9494
|
+
import_core37.loggerLatticeManager.removeLattice("default");
|
|
9282
9495
|
}
|
|
9283
|
-
(0,
|
|
9284
|
-
return (0,
|
|
9496
|
+
(0, import_core37.registerLoggerLattice)("default", config);
|
|
9497
|
+
return (0, import_core37.getLoggerLattice)("default");
|
|
9285
9498
|
}
|
|
9286
9499
|
var app = (0, import_fastify.default)({
|
|
9287
9500
|
logger: false,
|
|
@@ -9318,6 +9531,7 @@ app.addHook("preHandler", async (request, reply) => {
|
|
|
9318
9531
|
if (!authRequired) return;
|
|
9319
9532
|
if (request.method === "OPTIONS") return;
|
|
9320
9533
|
if (PUBLIC_ROUTES.some((r) => request.url === r)) return;
|
|
9534
|
+
if (request.url.startsWith("/s/")) return;
|
|
9321
9535
|
const urlPath = request.url.split("?")[0];
|
|
9322
9536
|
if (urlPath.includes("/viewfile") || urlPath.includes("/downloadfile")) return;
|
|
9323
9537
|
return reply.status(401).send({
|
|
@@ -9392,7 +9606,7 @@ app.setErrorHandler((error, request, reply) => {
|
|
|
9392
9606
|
});
|
|
9393
9607
|
function getConfiguredSandboxProvider() {
|
|
9394
9608
|
const sandboxProviderType = process.env.SANDBOX_PROVIDER_TYPE || "microsandbox-remote";
|
|
9395
|
-
return (0,
|
|
9609
|
+
return (0, import_core37.createSandboxProvider)({
|
|
9396
9610
|
type: sandboxProviderType,
|
|
9397
9611
|
remoteBaseURL: process.env.SANDBOX_BASE_URL,
|
|
9398
9612
|
microsandboxServiceBaseURL: process.env.MICROSANDBOX_SERVICE_BASE_URL,
|
|
@@ -9428,7 +9642,7 @@ var start = async (config) => {
|
|
|
9428
9642
|
const { getStoreLattice: getStore2 } = await import("@axiom-lattice/core");
|
|
9429
9643
|
const bindingStore = getStore2("default", "channelBinding").store;
|
|
9430
9644
|
const installationStore = getStore2("default", "channelInstallation").store;
|
|
9431
|
-
(0,
|
|
9645
|
+
(0, import_core36.setBindingRegistry)(bindingStore);
|
|
9432
9646
|
const router = new MessageRouter({
|
|
9433
9647
|
middlewares: [
|
|
9434
9648
|
createDeduplicationMiddleware(),
|
|
@@ -9454,8 +9668,8 @@ var start = async (config) => {
|
|
|
9454
9668
|
});
|
|
9455
9669
|
}
|
|
9456
9670
|
try {
|
|
9457
|
-
const menuStore = (0,
|
|
9458
|
-
(0,
|
|
9671
|
+
const menuStore = (0, import_core37.getStoreLattice)("default", "menu").store;
|
|
9672
|
+
(0, import_core36.setMenuRegistry)(menuStore);
|
|
9459
9673
|
logger5.info("Menu registry initialized");
|
|
9460
9674
|
} catch {
|
|
9461
9675
|
}
|
|
@@ -9463,10 +9677,27 @@ var start = async (config) => {
|
|
|
9463
9677
|
setChannelControllerDeps({ adapterRegistry, router: channelDeps.router });
|
|
9464
9678
|
}
|
|
9465
9679
|
registerLatticeRoutes(app, channelDeps);
|
|
9466
|
-
if (!
|
|
9467
|
-
|
|
9680
|
+
if (!import_core37.sandboxLatticeManager.hasLattice("default")) {
|
|
9681
|
+
import_core37.sandboxLatticeManager.registerLattice("default", getConfiguredSandboxProvider());
|
|
9468
9682
|
logger5.info("Registered sandbox manager from env configuration");
|
|
9469
9683
|
}
|
|
9684
|
+
try {
|
|
9685
|
+
const { ResourceController: ResourceController2 } = await Promise.resolve().then(() => (init_resources(), resources_exports));
|
|
9686
|
+
const sharedResourceStore = (0, import_core37.getStoreLattice)("default", "sharedResource").store;
|
|
9687
|
+
const cache = new import_core37.TokenCache();
|
|
9688
|
+
const resourceController = new ResourceController2({
|
|
9689
|
+
store: sharedResourceStore,
|
|
9690
|
+
sandboxManager: import_core37.sandboxLatticeManager,
|
|
9691
|
+
cache,
|
|
9692
|
+
logger: logger5
|
|
9693
|
+
});
|
|
9694
|
+
registerResourceRoutes(app, resourceController);
|
|
9695
|
+
logger5.info("Resource share routes registered");
|
|
9696
|
+
} catch (err) {
|
|
9697
|
+
logger5.warn("Resource share infrastructure unavailable", {
|
|
9698
|
+
error: err instanceof Error ? err.message : String(err)
|
|
9699
|
+
});
|
|
9700
|
+
}
|
|
9470
9701
|
if (channelDeps && process.env.CHANNELS_ENABLED !== "false") {
|
|
9471
9702
|
const { connectAllChannels } = await import("@axiom-lattice/core");
|
|
9472
9703
|
try {
|
|
@@ -9496,7 +9727,7 @@ var start = async (config) => {
|
|
|
9496
9727
|
agentTaskConsumer.startPollingQueue();
|
|
9497
9728
|
}
|
|
9498
9729
|
}
|
|
9499
|
-
|
|
9730
|
+
import_core37.agentInstanceManager.restore().then((stats) => {
|
|
9500
9731
|
logger5.info(`Agent recovery complete: ${stats.restored} threads restored, ${stats.errors} errors`);
|
|
9501
9732
|
}).catch((error) => {
|
|
9502
9733
|
logger5.error("Agent recovery failed", { error });
|