@rubytech/create-maxy-code 0.1.189 → 0.1.190
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/package.json +1 -1
- package/payload/platform/neo4j/schema.cypher +16 -1
- package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +3 -4
- package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-authoring-skill-gate.test.d.ts +2 -0
- package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-authoring-skill-gate.test.d.ts.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-authoring-skill-gate.test.js +79 -0
- package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-authoring-skill-gate.test.js.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js +21 -95
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/skill-resolution.d.ts +9 -0
- package/payload/platform/plugins/admin/mcp/dist/skill-resolution.d.ts.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/skill-resolution.js +47 -0
- package/payload/platform/plugins/admin/mcp/dist/skill-resolution.js.map +1 -1
- package/payload/platform/plugins/admin/skills/file-presentation/SKILL.md +6 -12
- package/payload/platform/plugins/admin/skills/professional-document/SKILL.md +1 -1
- package/payload/platform/plugins/docs/references/admin-ui.md +1 -2
- package/payload/platform/plugins/scheduling/PLUGIN.md +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/index.js +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +0 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +7 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/system-prompt.js +1 -1
- package/payload/platform/services/claude-session-manager/dist/system-prompt.js.map +1 -1
- package/payload/platform/templates/specialists/agents/content-producer.md +2 -2
- package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
- package/payload/server/public/assets/{admin-Cst6NkUE.js → admin-Cv2A5vnQ.js} +53 -53
- package/payload/server/public/assets/{data-COwlCdrl.js → data-DIa-MKNj.js} +1 -1
- package/payload/server/public/assets/{graph-CkUZEqdW.js → graph-Y5y3kw6J.js} +1 -1
- package/payload/server/public/assets/graph-labels-BIRCh328.js +1 -0
- package/payload/server/public/assets/page-BCCqlOmj.js +1 -0
- package/payload/server/public/assets/{page-DC2hsMPj.js → page-DwNvJOvr.js} +3 -3
- package/payload/server/public/data.html +3 -3
- package/payload/server/public/graph.html +3 -3
- package/payload/server/public/index.html +4 -4
- package/payload/server/server.js +586 -292
- package/payload/server/public/assets/graph-labels-Dt1bmq6W.js +0 -1
- package/payload/server/public/assets/page-CGXxYYRR.js +0 -1
package/payload/server/server.js
CHANGED
|
@@ -756,8 +756,8 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
756
756
|
);
|
|
757
757
|
let stats = getStats(path2);
|
|
758
758
|
if (stats && stats.isDirectory()) {
|
|
759
|
-
const
|
|
760
|
-
path2 = join(path2,
|
|
759
|
+
const indexFile2 = options.index ?? "index.html";
|
|
760
|
+
path2 = join(path2, indexFile2);
|
|
761
761
|
stats = getStats(path2);
|
|
762
762
|
}
|
|
763
763
|
if (!stats) {
|
|
@@ -816,7 +816,7 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
816
816
|
|
|
817
817
|
// server/index.ts
|
|
818
818
|
import { readFileSync as readFileSync20, existsSync as existsSync23, watchFile } from "fs";
|
|
819
|
-
import { resolve as
|
|
819
|
+
import { resolve as resolve23, join as join15, basename as basename5 } from "path";
|
|
820
820
|
import { homedir as homedir2 } from "os";
|
|
821
821
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
822
822
|
|
|
@@ -1274,7 +1274,7 @@ var credsSaveQueue = Promise.resolve();
|
|
|
1274
1274
|
async function drainCredsSaveQueue(timeoutMs = 5e3) {
|
|
1275
1275
|
console.error(`${TAG2} draining credential save queue\u2026`);
|
|
1276
1276
|
const timer2 = new Promise(
|
|
1277
|
-
(
|
|
1277
|
+
(resolve24) => setTimeout(() => resolve24("timeout"), timeoutMs)
|
|
1278
1278
|
);
|
|
1279
1279
|
const result = await Promise.race([
|
|
1280
1280
|
credsSaveQueue.then(() => "drained"),
|
|
@@ -1402,11 +1402,11 @@ async function createWaSocket(opts) {
|
|
|
1402
1402
|
return sock;
|
|
1403
1403
|
}
|
|
1404
1404
|
async function waitForConnection(sock) {
|
|
1405
|
-
return new Promise((
|
|
1405
|
+
return new Promise((resolve24, reject) => {
|
|
1406
1406
|
const handler = (update) => {
|
|
1407
1407
|
if (update.connection === "open") {
|
|
1408
1408
|
sock.ev.off("connection.update", handler);
|
|
1409
|
-
|
|
1409
|
+
resolve24();
|
|
1410
1410
|
}
|
|
1411
1411
|
if (update.connection === "close") {
|
|
1412
1412
|
sock.ev.off("connection.update", handler);
|
|
@@ -1520,14 +1520,14 @@ ${inspected}`;
|
|
|
1520
1520
|
return inspect2(err, INSPECT_OPTS2);
|
|
1521
1521
|
}
|
|
1522
1522
|
function withTimeout(label, promise, timeoutMs) {
|
|
1523
|
-
return new Promise((
|
|
1523
|
+
return new Promise((resolve24, reject) => {
|
|
1524
1524
|
const timer2 = setTimeout(() => {
|
|
1525
1525
|
reject(new Error(`${label} timed out after ${timeoutMs}ms`));
|
|
1526
1526
|
}, timeoutMs);
|
|
1527
1527
|
promise.then(
|
|
1528
1528
|
(value) => {
|
|
1529
1529
|
clearTimeout(timer2);
|
|
1530
|
-
|
|
1530
|
+
resolve24(value);
|
|
1531
1531
|
},
|
|
1532
1532
|
(err) => {
|
|
1533
1533
|
clearTimeout(timer2);
|
|
@@ -2062,8 +2062,8 @@ async function persistWhatsAppMessage(input) {
|
|
|
2062
2062
|
const { givenName, familyName } = splitName(input.pushName);
|
|
2063
2063
|
const prev = sessionWriteLocks.get(input.cacheKey);
|
|
2064
2064
|
let release;
|
|
2065
|
-
const mine = new Promise((
|
|
2066
|
-
release =
|
|
2065
|
+
const mine = new Promise((resolve24) => {
|
|
2066
|
+
release = resolve24;
|
|
2067
2067
|
});
|
|
2068
2068
|
const chained = (prev ?? Promise.resolve()).then(() => mine);
|
|
2069
2069
|
sessionWriteLocks.set(input.cacheKey, chained);
|
|
@@ -3099,11 +3099,11 @@ async function connectWithReconnect(conn) {
|
|
|
3099
3099
|
console.error(
|
|
3100
3100
|
`${TAG12} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
|
|
3101
3101
|
);
|
|
3102
|
-
await new Promise((
|
|
3103
|
-
const timer2 = setTimeout(
|
|
3102
|
+
await new Promise((resolve24) => {
|
|
3103
|
+
const timer2 = setTimeout(resolve24, delay);
|
|
3104
3104
|
conn.abortController.signal.addEventListener("abort", () => {
|
|
3105
3105
|
clearTimeout(timer2);
|
|
3106
|
-
|
|
3106
|
+
resolve24();
|
|
3107
3107
|
}, { once: true });
|
|
3108
3108
|
});
|
|
3109
3109
|
}
|
|
@@ -3111,16 +3111,16 @@ async function connectWithReconnect(conn) {
|
|
|
3111
3111
|
}
|
|
3112
3112
|
}
|
|
3113
3113
|
function waitForDisconnectEvent(conn) {
|
|
3114
|
-
return new Promise((
|
|
3114
|
+
return new Promise((resolve24) => {
|
|
3115
3115
|
if (!conn.sock) {
|
|
3116
|
-
|
|
3116
|
+
resolve24();
|
|
3117
3117
|
return;
|
|
3118
3118
|
}
|
|
3119
3119
|
const sock = conn.sock;
|
|
3120
3120
|
const handler = (update) => {
|
|
3121
3121
|
if (update.connection === "close") {
|
|
3122
3122
|
sock.ev.off("connection.update", handler);
|
|
3123
|
-
|
|
3123
|
+
resolve24();
|
|
3124
3124
|
}
|
|
3125
3125
|
};
|
|
3126
3126
|
sock.ev.on("connection.update", handler);
|
|
@@ -3382,8 +3382,8 @@ async function handleInboundMessage(conn, msg) {
|
|
|
3382
3382
|
const conversationKey = isGroup ? remoteJid : senderPhone;
|
|
3383
3383
|
const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
|
|
3384
3384
|
let resolvePending;
|
|
3385
|
-
const sttPending = new Promise((
|
|
3386
|
-
resolvePending =
|
|
3385
|
+
const sttPending = new Promise((resolve24) => {
|
|
3386
|
+
resolvePending = resolve24;
|
|
3387
3387
|
});
|
|
3388
3388
|
if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
|
|
3389
3389
|
try {
|
|
@@ -3787,20 +3787,20 @@ function buildX11Env(chromiumWrapperPath, transport = "vnc") {
|
|
|
3787
3787
|
|
|
3788
3788
|
// server/routes/health.ts
|
|
3789
3789
|
function checkPort(port2, timeoutMs = 500) {
|
|
3790
|
-
return new Promise((
|
|
3790
|
+
return new Promise((resolve24) => {
|
|
3791
3791
|
const socket = createConnection2(port2, "127.0.0.1");
|
|
3792
3792
|
socket.setTimeout(timeoutMs);
|
|
3793
3793
|
socket.once("connect", () => {
|
|
3794
3794
|
socket.destroy();
|
|
3795
|
-
|
|
3795
|
+
resolve24(true);
|
|
3796
3796
|
});
|
|
3797
3797
|
socket.once("error", () => {
|
|
3798
3798
|
socket.destroy();
|
|
3799
|
-
|
|
3799
|
+
resolve24(false);
|
|
3800
3800
|
});
|
|
3801
3801
|
socket.once("timeout", () => {
|
|
3802
3802
|
socket.destroy();
|
|
3803
|
-
|
|
3803
|
+
resolve24(false);
|
|
3804
3804
|
});
|
|
3805
3805
|
});
|
|
3806
3806
|
}
|
|
@@ -3865,9 +3865,9 @@ var health_default = app;
|
|
|
3865
3865
|
|
|
3866
3866
|
// app/lib/attachments.ts
|
|
3867
3867
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
3868
|
-
import { mkdir as mkdir2,
|
|
3868
|
+
import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
|
|
3869
3869
|
import { realpathSync } from "fs";
|
|
3870
|
-
import { resolve as resolve3, extname
|
|
3870
|
+
import { resolve as resolve3, extname } from "path";
|
|
3871
3871
|
var PLATFORM_ROOT3 = process.env.MAXY_PLATFORM_ROOT ?? resolve3(process.cwd(), "../platform");
|
|
3872
3872
|
var ATTACHMENTS_ROOT = resolve3(PLATFORM_ROOT3, "..", "data/uploads");
|
|
3873
3873
|
var SUPPORTED_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -3957,18 +3957,6 @@ function validateFilePathInAccount(filePath, accountDir) {
|
|
|
3957
3957
|
}
|
|
3958
3958
|
return resolved;
|
|
3959
3959
|
}
|
|
3960
|
-
async function storeGeneratedFile(accountId, filePath) {
|
|
3961
|
-
const fileStat = await stat2(filePath);
|
|
3962
|
-
if (fileStat.size > MAX_FILE_SIZE_BYTES) {
|
|
3963
|
-
throw new Error(
|
|
3964
|
-
`File exceeds the 50 MB limit (${(fileStat.size / 1024 / 1024).toFixed(1)} MB).`
|
|
3965
|
-
);
|
|
3966
|
-
}
|
|
3967
|
-
const filename = basename(filePath);
|
|
3968
|
-
const mimeType = detectMimeType(filePath);
|
|
3969
|
-
const buffer = await readFile(filePath);
|
|
3970
|
-
return writeAttachment(accountId, filename, mimeType, fileStat.size, buffer);
|
|
3971
|
-
}
|
|
3972
3960
|
async function storeComponentArtefact(accountId, attachmentId, mimeType, content, filename) {
|
|
3973
3961
|
const buffer = Buffer.from(content, "utf-8");
|
|
3974
3962
|
if (buffer.byteLength > MAX_FILE_SIZE_BYTES) {
|
|
@@ -4548,12 +4536,12 @@ async function dispatchOnce(input) {
|
|
|
4548
4536
|
});
|
|
4549
4537
|
if (!entry) return { error: "spawn-failed" };
|
|
4550
4538
|
entry.lastInboundAt = Date.now();
|
|
4551
|
-
let
|
|
4539
|
+
let resolve24;
|
|
4552
4540
|
const turnPromise = new Promise((r) => {
|
|
4553
|
-
|
|
4541
|
+
resolve24 = r;
|
|
4554
4542
|
});
|
|
4555
4543
|
const listener = (text) => {
|
|
4556
|
-
|
|
4544
|
+
resolve24(text);
|
|
4557
4545
|
};
|
|
4558
4546
|
entry.subscribers.add(listener);
|
|
4559
4547
|
const writeOk = await writeInput(entry, input.text);
|
|
@@ -4887,8 +4875,8 @@ ${lines}]`;
|
|
|
4887
4875
|
var chat_default = app2;
|
|
4888
4876
|
|
|
4889
4877
|
// server/routes/whatsapp.ts
|
|
4890
|
-
import { join as join5, resolve as resolve6, basename
|
|
4891
|
-
import { readFile
|
|
4878
|
+
import { join as join5, resolve as resolve6, basename } from "path";
|
|
4879
|
+
import { readFile, stat as stat2 } from "fs/promises";
|
|
4892
4880
|
import { realpathSync as realpathSync2, readdirSync as readdirSync2, readFileSync as readFileSync6, existsSync as existsSync4 } from "fs";
|
|
4893
4881
|
|
|
4894
4882
|
// app/lib/whatsapp/login.ts
|
|
@@ -4995,8 +4983,8 @@ async function startLogin(opts) {
|
|
|
4995
4983
|
resetActiveLogin(accountId);
|
|
4996
4984
|
let resolveQr = null;
|
|
4997
4985
|
let rejectQr = null;
|
|
4998
|
-
const qrPromise = new Promise((
|
|
4999
|
-
resolveQr =
|
|
4986
|
+
const qrPromise = new Promise((resolve24, reject) => {
|
|
4987
|
+
resolveQr = resolve24;
|
|
5000
4988
|
rejectQr = reject;
|
|
5001
4989
|
});
|
|
5002
4990
|
const qrTimer = setTimeout(
|
|
@@ -5820,12 +5808,12 @@ app3.post("/send-document", async (c) => {
|
|
|
5820
5808
|
console.error(`${TAG17} send-document path error: ${String(err)}`);
|
|
5821
5809
|
return c.json({ error: String(err) }, 500);
|
|
5822
5810
|
}
|
|
5823
|
-
const fileStat = await
|
|
5811
|
+
const fileStat = await stat2(resolvedPath);
|
|
5824
5812
|
if (fileStat.size > MAX_FILE_SIZE_BYTES) {
|
|
5825
5813
|
return c.json({ error: `File exceeds 50 MB limit (${(fileStat.size / 1024 / 1024).toFixed(1)} MB)` }, 400);
|
|
5826
5814
|
}
|
|
5827
|
-
const buffer = Buffer.from(await
|
|
5828
|
-
const filename =
|
|
5815
|
+
const buffer = Buffer.from(await readFile(resolvedPath));
|
|
5816
|
+
const filename = basename(resolvedPath);
|
|
5829
5817
|
const mimetype = detectMimeType(resolvedPath);
|
|
5830
5818
|
const sock = getSocket(accountId);
|
|
5831
5819
|
if (!sock) {
|
|
@@ -6781,7 +6769,7 @@ var session_default = app6;
|
|
|
6781
6769
|
|
|
6782
6770
|
// server/routes/admin/logs.ts
|
|
6783
6771
|
import { existsSync as existsSync10, readdirSync as readdirSync5, readFileSync as readFileSync10, statSync as statSync5 } from "fs";
|
|
6784
|
-
import { resolve as resolve7, basename as
|
|
6772
|
+
import { resolve as resolve7, basename as basename2 } from "path";
|
|
6785
6773
|
|
|
6786
6774
|
// app/lib/logs-read-resolve.ts
|
|
6787
6775
|
import { existsSync as existsSync9 } from "fs";
|
|
@@ -6813,7 +6801,7 @@ app7.get("/", async (c) => {
|
|
|
6813
6801
|
if (accountLogDir) logDirs.push(accountLogDir);
|
|
6814
6802
|
logDirs.push(LOG_DIR);
|
|
6815
6803
|
if (fileParam) {
|
|
6816
|
-
const safe =
|
|
6804
|
+
const safe = basename2(fileParam);
|
|
6817
6805
|
const searched = [];
|
|
6818
6806
|
for (const dir of logDirs) {
|
|
6819
6807
|
const filePath = resolve7(dir, safe);
|
|
@@ -6883,7 +6871,7 @@ app7.get("/", async (c) => {
|
|
|
6883
6871
|
if (hit) {
|
|
6884
6872
|
console.info(`[admin/logs] resolved cacheKey=${cacheKeySlice} sessionId=${sessionIdSlice} via=${primaryId === cacheKey ? "cacheKey" : primaryId === sessionKeyFromConv ? "reverse-lookup" : "sessionId-fallback"}`);
|
|
6885
6873
|
try {
|
|
6886
|
-
const filename =
|
|
6874
|
+
const filename = basename2(hit.path);
|
|
6887
6875
|
const buffer = readFileSync10(hit.path);
|
|
6888
6876
|
const onDiskBytes = statSync5(hit.path).size;
|
|
6889
6877
|
const headers = {
|
|
@@ -6969,7 +6957,7 @@ app8.get("/", (c) => {
|
|
|
6969
6957
|
var claude_info_default = app8;
|
|
6970
6958
|
|
|
6971
6959
|
// server/routes/admin/attachment.ts
|
|
6972
|
-
import { readFile as
|
|
6960
|
+
import { readFile as readFile2, readdir } from "fs/promises";
|
|
6973
6961
|
import { existsSync as existsSync11 } from "fs";
|
|
6974
6962
|
import { resolve as resolve8 } from "path";
|
|
6975
6963
|
var app9 = new Hono();
|
|
@@ -6993,7 +6981,7 @@ app9.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
6993
6981
|
}
|
|
6994
6982
|
let meta;
|
|
6995
6983
|
try {
|
|
6996
|
-
meta = JSON.parse(await
|
|
6984
|
+
meta = JSON.parse(await readFile2(metaPath, "utf-8"));
|
|
6997
6985
|
} catch {
|
|
6998
6986
|
return new Response("Not found", { status: 404 });
|
|
6999
6987
|
}
|
|
@@ -7003,7 +6991,7 @@ app9.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
7003
6991
|
return new Response("Not found", { status: 404 });
|
|
7004
6992
|
}
|
|
7005
6993
|
const filePath = resolve8(dir, dataFile);
|
|
7006
|
-
const buffer = await
|
|
6994
|
+
const buffer = await readFile2(filePath);
|
|
7007
6995
|
return new Response(new Uint8Array(buffer), {
|
|
7008
6996
|
headers: {
|
|
7009
6997
|
"Content-Type": meta.mimeType,
|
|
@@ -8016,10 +8004,10 @@ function computeSpecialistDomains(accountId) {
|
|
|
8016
8004
|
const resolveDesc = (qualified) => {
|
|
8017
8005
|
if (!qualified.startsWith("mcp__")) return void 0;
|
|
8018
8006
|
const rest = qualified.slice(5);
|
|
8019
|
-
const
|
|
8020
|
-
if (
|
|
8021
|
-
const plugin = rest.slice(0,
|
|
8022
|
-
const tool = rest.slice(
|
|
8007
|
+
const sep6 = rest.indexOf("__");
|
|
8008
|
+
if (sep6 < 0) return void 0;
|
|
8009
|
+
const plugin = rest.slice(0, sep6);
|
|
8010
|
+
const tool = rest.slice(sep6 + 2);
|
|
8023
8011
|
let map = descByPlugin.get(plugin);
|
|
8024
8012
|
if (!map) {
|
|
8025
8013
|
const dir = pluginDirs.get(plugin);
|
|
@@ -8398,9 +8386,9 @@ var events_default = app14;
|
|
|
8398
8386
|
|
|
8399
8387
|
// server/routes/admin/files.ts
|
|
8400
8388
|
import { createReadStream as createReadStream2 } from "fs";
|
|
8401
|
-
import { readdir as
|
|
8389
|
+
import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3, writeFile as writeFile4, unlink as unlink2 } from "fs/promises";
|
|
8402
8390
|
import { realpathSync as realpathSync4 } from "fs";
|
|
8403
|
-
import { basename as basename4, dirname as dirname3, join as
|
|
8391
|
+
import { basename as basename4, dirname as dirname3, join as join12, resolve as resolve14, sep as sep4 } from "path";
|
|
8404
8392
|
import { Readable as Readable2 } from "stream";
|
|
8405
8393
|
|
|
8406
8394
|
// app/lib/data-path.ts
|
|
@@ -8408,6 +8396,16 @@ import { realpathSync as realpathSync3 } from "fs";
|
|
|
8408
8396
|
import { resolve as resolve12, normalize, sep as sep2, relative } from "path";
|
|
8409
8397
|
var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT ?? resolve12(process.cwd(), "../platform");
|
|
8410
8398
|
var DATA_ROOT = resolve12(PLATFORM_ROOT5, "..", "data");
|
|
8399
|
+
var ACCOUNT_PARTITION_DIRS = /* @__PURE__ */ new Set(["uploads", "accounts"]);
|
|
8400
|
+
var ACCOUNT_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
8401
|
+
function crossesForeignAccountPartition(relPath2, accountId) {
|
|
8402
|
+
const segs = relPath2.split("/").filter(Boolean);
|
|
8403
|
+
if (segs.length < 2) return false;
|
|
8404
|
+
if (!ACCOUNT_PARTITION_DIRS.has(segs[0])) return false;
|
|
8405
|
+
const owner = segs[1];
|
|
8406
|
+
if (!ACCOUNT_UUID_RE.test(owner)) return false;
|
|
8407
|
+
return owner !== accountId;
|
|
8408
|
+
}
|
|
8411
8409
|
function resolveDataPath(raw) {
|
|
8412
8410
|
const cleaned = normalize("/" + (raw ?? "").replace(/\\/g, "/")).replace(/^\/+/, "");
|
|
8413
8411
|
const absolute = resolve12(DATA_ROOT, cleaned);
|
|
@@ -8758,11 +8756,291 @@ async function cascadeDeleteDocument(params) {
|
|
|
8758
8756
|
}
|
|
8759
8757
|
}
|
|
8760
8758
|
|
|
8759
|
+
// app/lib/file-index.ts
|
|
8760
|
+
import * as fsp from "fs/promises";
|
|
8761
|
+
import { resolve as resolve13, relative as relative2, join as join11, basename as basename3, extname as extname2, sep as sep3 } from "path";
|
|
8762
|
+
import { execFile as execFile2 } from "child_process";
|
|
8763
|
+
import { promisify as promisify2 } from "util";
|
|
8764
|
+
var execFileAsync2 = promisify2(execFile2);
|
|
8765
|
+
var CONTENT_CAP = 1e5;
|
|
8766
|
+
var RECONCILE_DEBOUNCE_MS = 1e4;
|
|
8767
|
+
var lastReconcileAt = /* @__PURE__ */ new Map();
|
|
8768
|
+
var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
8769
|
+
".txt",
|
|
8770
|
+
".md",
|
|
8771
|
+
".markdown",
|
|
8772
|
+
".csv",
|
|
8773
|
+
".tsv",
|
|
8774
|
+
".json",
|
|
8775
|
+
".jsonl",
|
|
8776
|
+
".log",
|
|
8777
|
+
".yaml",
|
|
8778
|
+
".yml",
|
|
8779
|
+
".xml",
|
|
8780
|
+
".toml",
|
|
8781
|
+
".ini",
|
|
8782
|
+
".env",
|
|
8783
|
+
".sql",
|
|
8784
|
+
".sh",
|
|
8785
|
+
".py",
|
|
8786
|
+
".js",
|
|
8787
|
+
".ts",
|
|
8788
|
+
".tsx",
|
|
8789
|
+
".jsx",
|
|
8790
|
+
".css",
|
|
8791
|
+
".svg",
|
|
8792
|
+
".rtf"
|
|
8793
|
+
]);
|
|
8794
|
+
var HTML_EXTENSIONS = /* @__PURE__ */ new Set([".html", ".htm"]);
|
|
8795
|
+
var MIME_BY_EXT2 = {
|
|
8796
|
+
".pdf": "application/pdf",
|
|
8797
|
+
".txt": "text/plain",
|
|
8798
|
+
".md": "text/markdown",
|
|
8799
|
+
".markdown": "text/markdown",
|
|
8800
|
+
".csv": "text/csv",
|
|
8801
|
+
".json": "application/json",
|
|
8802
|
+
".html": "text/html",
|
|
8803
|
+
".htm": "text/html",
|
|
8804
|
+
".png": "image/png",
|
|
8805
|
+
".jpg": "image/jpeg",
|
|
8806
|
+
".jpeg": "image/jpeg",
|
|
8807
|
+
".gif": "image/gif",
|
|
8808
|
+
".webp": "image/webp"
|
|
8809
|
+
};
|
|
8810
|
+
function mimeForExt(ext) {
|
|
8811
|
+
return MIME_BY_EXT2[ext.toLowerCase()] ?? "application/octet-stream";
|
|
8812
|
+
}
|
|
8813
|
+
async function extractPdf(absolute) {
|
|
8814
|
+
const { stdout } = await execFileAsync2("pdftotext", [absolute, "-"], {
|
|
8815
|
+
maxBuffer: 10 * 1024 * 1024
|
|
8816
|
+
});
|
|
8817
|
+
return stdout.trim();
|
|
8818
|
+
}
|
|
8819
|
+
function stripHtml(html) {
|
|
8820
|
+
return html.replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
8821
|
+
}
|
|
8822
|
+
async function extractFileContent(absolute) {
|
|
8823
|
+
const ext = extname2(absolute).toLowerCase();
|
|
8824
|
+
try {
|
|
8825
|
+
if (ext === ".pdf") return (await extractPdf(absolute)).slice(0, CONTENT_CAP);
|
|
8826
|
+
if (HTML_EXTENSIONS.has(ext)) {
|
|
8827
|
+
const raw = await fsp.readFile(absolute, "utf-8");
|
|
8828
|
+
return stripHtml(raw).slice(0, CONTENT_CAP);
|
|
8829
|
+
}
|
|
8830
|
+
if (TEXT_EXTENSIONS.has(ext)) {
|
|
8831
|
+
const raw = await fsp.readFile(absolute, "utf-8");
|
|
8832
|
+
return raw.slice(0, CONTENT_CAP);
|
|
8833
|
+
}
|
|
8834
|
+
return "";
|
|
8835
|
+
} catch (err) {
|
|
8836
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
8837
|
+
console.error(`[file-index] extract-failed path="${relative2(DATA_ROOT, absolute)}" err="${msg}"`);
|
|
8838
|
+
return "";
|
|
8839
|
+
}
|
|
8840
|
+
}
|
|
8841
|
+
async function readDisplayName(absolute) {
|
|
8842
|
+
const dir = absolute.slice(0, absolute.length - basename3(absolute).length);
|
|
8843
|
+
const base = basename3(absolute);
|
|
8844
|
+
const dot = base.lastIndexOf(".");
|
|
8845
|
+
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
8846
|
+
if (base === `${stem}.meta.json`) return null;
|
|
8847
|
+
try {
|
|
8848
|
+
const raw = await fsp.readFile(join11(dir, `${stem}.meta.json`), "utf-8");
|
|
8849
|
+
const meta = JSON.parse(raw);
|
|
8850
|
+
const dn = meta.displayName ?? meta.filename;
|
|
8851
|
+
return typeof dn === "string" && dn.length > 0 ? dn : null;
|
|
8852
|
+
} catch {
|
|
8853
|
+
return null;
|
|
8854
|
+
}
|
|
8855
|
+
}
|
|
8856
|
+
async function walkSubtree(root, dataRoot, out) {
|
|
8857
|
+
let entries;
|
|
8858
|
+
try {
|
|
8859
|
+
entries = await fsp.readdir(root, { withFileTypes: true });
|
|
8860
|
+
} catch (err) {
|
|
8861
|
+
if (err.code === "ENOENT") return { clean: true };
|
|
8862
|
+
console.error(`[file-index] walk-error dir="${relative2(dataRoot, root)}" err="${err.message}"`);
|
|
8863
|
+
return { clean: false };
|
|
8864
|
+
}
|
|
8865
|
+
let clean = true;
|
|
8866
|
+
for (const entry of entries) {
|
|
8867
|
+
if (entry.isSymbolicLink()) continue;
|
|
8868
|
+
const abs = join11(root, entry.name);
|
|
8869
|
+
if (entry.isDirectory()) {
|
|
8870
|
+
const sub = await walkSubtree(abs, dataRoot, out);
|
|
8871
|
+
if (!sub.clean) clean = false;
|
|
8872
|
+
} else if (entry.isFile()) {
|
|
8873
|
+
try {
|
|
8874
|
+
const st = await fsp.stat(abs);
|
|
8875
|
+
out.push({
|
|
8876
|
+
absolute: abs,
|
|
8877
|
+
relativePath: relative2(dataRoot, abs).split(sep3).join("/"),
|
|
8878
|
+
sizeBytes: st.size,
|
|
8879
|
+
modifiedAt: st.mtime.toISOString()
|
|
8880
|
+
});
|
|
8881
|
+
} catch (err) {
|
|
8882
|
+
console.error(`[file-index] stat-error path="${relative2(dataRoot, abs)}" err="${err.message}"`);
|
|
8883
|
+
clean = false;
|
|
8884
|
+
}
|
|
8885
|
+
}
|
|
8886
|
+
}
|
|
8887
|
+
return { clean };
|
|
8888
|
+
}
|
|
8889
|
+
async function upsertFileArtifact(session, f) {
|
|
8890
|
+
await session.run(
|
|
8891
|
+
`MERGE (f:FileArtifact {accountId: $accountId, relativePath: $relativePath})
|
|
8892
|
+
SET f.name = $name,
|
|
8893
|
+
f.displayName = $displayName,
|
|
8894
|
+
f.mimeType = $mimeType,
|
|
8895
|
+
f.sizeBytes = $sizeBytes,
|
|
8896
|
+
f.modifiedAt = $modifiedAt,
|
|
8897
|
+
f.content = $content,
|
|
8898
|
+
f.embedding = $embedding`,
|
|
8899
|
+
f
|
|
8900
|
+
);
|
|
8901
|
+
}
|
|
8902
|
+
async function buildArtifact(accountId, wf, embed2) {
|
|
8903
|
+
const name = basename3(wf.absolute);
|
|
8904
|
+
const content = await extractFileContent(wf.absolute);
|
|
8905
|
+
const displayName = await readDisplayName(wf.absolute);
|
|
8906
|
+
const embedInput = `${name}
|
|
8907
|
+
${content}`.slice(0, CONTENT_CAP);
|
|
8908
|
+
let embedding = null;
|
|
8909
|
+
const embedStart = Date.now();
|
|
8910
|
+
try {
|
|
8911
|
+
embedding = await embed2(embedInput);
|
|
8912
|
+
} catch (err) {
|
|
8913
|
+
console.error(`[file-index] embed-failed path="${wf.relativePath}" err="${err.message}"`);
|
|
8914
|
+
}
|
|
8915
|
+
console.error(
|
|
8916
|
+
`[file-index] index-file account=${accountId} path="${wf.relativePath}" chars=${content.length} embed-ms=${Date.now() - embedStart}`
|
|
8917
|
+
);
|
|
8918
|
+
return {
|
|
8919
|
+
accountId,
|
|
8920
|
+
relativePath: wf.relativePath,
|
|
8921
|
+
name,
|
|
8922
|
+
displayName,
|
|
8923
|
+
mimeType: mimeForExt(extname2(wf.absolute)),
|
|
8924
|
+
sizeBytes: wf.sizeBytes,
|
|
8925
|
+
modifiedAt: wf.modifiedAt,
|
|
8926
|
+
content,
|
|
8927
|
+
embedding
|
|
8928
|
+
};
|
|
8929
|
+
}
|
|
8930
|
+
async function withSession(opts, fn) {
|
|
8931
|
+
if (opts?.session) return fn(opts.session);
|
|
8932
|
+
const session = getSession();
|
|
8933
|
+
try {
|
|
8934
|
+
return await fn(session);
|
|
8935
|
+
} finally {
|
|
8936
|
+
await session.close();
|
|
8937
|
+
}
|
|
8938
|
+
}
|
|
8939
|
+
async function reconcileFileIndex(accountId, opts) {
|
|
8940
|
+
const dataRoot = opts?.dataRoot ?? DATA_ROOT;
|
|
8941
|
+
const embed2 = opts?.embed ?? embed;
|
|
8942
|
+
const t0 = Date.now();
|
|
8943
|
+
return withSession(opts, async (session) => {
|
|
8944
|
+
const walked = [];
|
|
8945
|
+
const subtreeRoots = [
|
|
8946
|
+
resolve13(dataRoot, "uploads", accountId),
|
|
8947
|
+
resolve13(dataRoot, "accounts", accountId)
|
|
8948
|
+
];
|
|
8949
|
+
let clean = true;
|
|
8950
|
+
for (const root of subtreeRoots) {
|
|
8951
|
+
const r = await walkSubtree(root, dataRoot, walked);
|
|
8952
|
+
if (!r.clean) clean = false;
|
|
8953
|
+
}
|
|
8954
|
+
const existing = /* @__PURE__ */ new Map();
|
|
8955
|
+
const existingRes = await session.run(
|
|
8956
|
+
`MATCH (f:FileArtifact {accountId: $accountId})
|
|
8957
|
+
RETURN f.relativePath AS relativePath, f.sizeBytes AS sizeBytes,
|
|
8958
|
+
f.modifiedAt AS modifiedAt, f.embedding IS NOT NULL AS hasEmbedding`,
|
|
8959
|
+
{ accountId }
|
|
8960
|
+
);
|
|
8961
|
+
for (const rec of existingRes.records) {
|
|
8962
|
+
existing.set(rec.get("relativePath"), {
|
|
8963
|
+
sizeBytes: typeof rec.get("sizeBytes")?.toNumber === "function" ? rec.get("sizeBytes").toNumber() : Number(rec.get("sizeBytes")),
|
|
8964
|
+
modifiedAt: rec.get("modifiedAt"),
|
|
8965
|
+
hasEmbedding: rec.get("hasEmbedding") === true
|
|
8966
|
+
});
|
|
8967
|
+
}
|
|
8968
|
+
let upserted = 0;
|
|
8969
|
+
let skipped = 0;
|
|
8970
|
+
for (const wf of walked) {
|
|
8971
|
+
const prior = existing.get(wf.relativePath);
|
|
8972
|
+
const unchanged = prior && prior.sizeBytes === wf.sizeBytes && prior.modifiedAt === wf.modifiedAt && prior.hasEmbedding;
|
|
8973
|
+
if (unchanged) {
|
|
8974
|
+
skipped++;
|
|
8975
|
+
continue;
|
|
8976
|
+
}
|
|
8977
|
+
await upsertFileArtifact(session, await buildArtifact(accountId, wf, embed2));
|
|
8978
|
+
upserted++;
|
|
8979
|
+
}
|
|
8980
|
+
let pruned = 0;
|
|
8981
|
+
if (clean) {
|
|
8982
|
+
const foundPaths = walked.map((w) => w.relativePath);
|
|
8983
|
+
const pruneRes = await session.run(
|
|
8984
|
+
`MATCH (f:FileArtifact {accountId: $accountId})
|
|
8985
|
+
WHERE NOT f.relativePath IN $foundPaths
|
|
8986
|
+
DETACH DELETE f
|
|
8987
|
+
RETURN count(f) AS pruned`,
|
|
8988
|
+
{ accountId, foundPaths }
|
|
8989
|
+
);
|
|
8990
|
+
const c = pruneRes.records[0]?.get("pruned");
|
|
8991
|
+
pruned = typeof c?.toNumber === "function" ? c.toNumber() : Number(c ?? 0);
|
|
8992
|
+
}
|
|
8993
|
+
console.error(
|
|
8994
|
+
`[file-index] reconcile account=${accountId} walked=${walked.length} upserted=${upserted} skipped=${skipped} pruned=${pruned} clean=${clean} ms=${Date.now() - t0}`
|
|
8995
|
+
);
|
|
8996
|
+
return { walked: walked.length, upserted, skipped, pruned };
|
|
8997
|
+
});
|
|
8998
|
+
}
|
|
8999
|
+
async function reconcileFileIndexDebounced(accountId, opts) {
|
|
9000
|
+
const now = Date.now();
|
|
9001
|
+
const last = lastReconcileAt.get(accountId) ?? 0;
|
|
9002
|
+
if (now - last < RECONCILE_DEBOUNCE_MS) return;
|
|
9003
|
+
lastReconcileAt.set(accountId, now);
|
|
9004
|
+
try {
|
|
9005
|
+
await reconcileFileIndex(accountId, opts);
|
|
9006
|
+
} catch (err) {
|
|
9007
|
+
console.error(`[file-index] reconcile-failed account=${accountId} err="${err.message}"`);
|
|
9008
|
+
}
|
|
9009
|
+
}
|
|
9010
|
+
async function indexFile(accountId, relativePath, opts) {
|
|
9011
|
+
const dataRoot = opts?.dataRoot ?? DATA_ROOT;
|
|
9012
|
+
const embed2 = opts?.embed ?? embed;
|
|
9013
|
+
const absolute = resolve13(dataRoot, relativePath);
|
|
9014
|
+
await withSession(opts, async (session) => {
|
|
9015
|
+
const st = await fsp.stat(absolute);
|
|
9016
|
+
const wf = {
|
|
9017
|
+
absolute,
|
|
9018
|
+
relativePath,
|
|
9019
|
+
sizeBytes: st.size,
|
|
9020
|
+
modifiedAt: st.mtime.toISOString()
|
|
9021
|
+
};
|
|
9022
|
+
await upsertFileArtifact(session, await buildArtifact(accountId, wf, embed2));
|
|
9023
|
+
});
|
|
9024
|
+
}
|
|
9025
|
+
async function dropFileIndex(accountId, relativePath, opts) {
|
|
9026
|
+
await withSession(opts, async (session) => {
|
|
9027
|
+
const res = await session.run(
|
|
9028
|
+
`MATCH (f:FileArtifact {accountId: $accountId, relativePath: $relativePath})
|
|
9029
|
+
DETACH DELETE f
|
|
9030
|
+
RETURN count(f) AS dropped`,
|
|
9031
|
+
{ accountId, relativePath }
|
|
9032
|
+
);
|
|
9033
|
+
const c = res.records[0]?.get("dropped");
|
|
9034
|
+
const dropped = typeof c?.toNumber === "function" ? c.toNumber() : Number(c ?? 0);
|
|
9035
|
+
console.error(`[file-index] drop account=${accountId} path="${relativePath}" dropped=${dropped}`);
|
|
9036
|
+
});
|
|
9037
|
+
}
|
|
9038
|
+
|
|
8761
9039
|
// server/routes/admin/files.ts
|
|
8762
9040
|
var UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
8763
9041
|
async function readMeta(absDir, baseName) {
|
|
8764
9042
|
try {
|
|
8765
|
-
const raw = await readFile4(
|
|
9043
|
+
const raw = await readFile4(join12(absDir, `${baseName}.meta.json`), "utf8");
|
|
8766
9044
|
const parsed = JSON.parse(raw);
|
|
8767
9045
|
if (typeof parsed?.filename === "string") {
|
|
8768
9046
|
return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
|
|
@@ -8773,16 +9051,16 @@ async function readMeta(absDir, baseName) {
|
|
|
8773
9051
|
}
|
|
8774
9052
|
async function readAccountNames() {
|
|
8775
9053
|
const map = /* @__PURE__ */ new Map();
|
|
8776
|
-
const accountsDir =
|
|
9054
|
+
const accountsDir = resolve14(DATA_ROOT, "accounts");
|
|
8777
9055
|
let names;
|
|
8778
9056
|
try {
|
|
8779
|
-
names = await
|
|
9057
|
+
names = await readdir3(accountsDir);
|
|
8780
9058
|
} catch {
|
|
8781
9059
|
return map;
|
|
8782
9060
|
}
|
|
8783
9061
|
for (const name of names) {
|
|
8784
9062
|
if (!UUID_RE3.test(name)) continue;
|
|
8785
|
-
const configPath2 =
|
|
9063
|
+
const configPath2 = resolve14(accountsDir, name, "account.json");
|
|
8786
9064
|
try {
|
|
8787
9065
|
const raw = await readFile4(configPath2, "utf8");
|
|
8788
9066
|
const parsed = JSON.parse(raw);
|
|
@@ -8800,7 +9078,7 @@ async function readAccountNames() {
|
|
|
8800
9078
|
}
|
|
8801
9079
|
async function enrich(absolute, entry, accountNames) {
|
|
8802
9080
|
if (entry.kind === "directory" && UUID_RE3.test(entry.name)) {
|
|
8803
|
-
const meta = await readMeta(
|
|
9081
|
+
const meta = await readMeta(join12(absolute, entry.name), entry.name);
|
|
8804
9082
|
if (meta?.filename) {
|
|
8805
9083
|
entry.displayName = meta.filename;
|
|
8806
9084
|
entry.mimeType = meta.mimeType;
|
|
@@ -8852,14 +9130,14 @@ app15.get("/", requireAdminSession, async (c) => {
|
|
|
8852
9130
|
if (!info.isDirectory()) {
|
|
8853
9131
|
return c.json({ error: "Path is not a directory \u2014 use /api/admin/files/download for files" }, 400);
|
|
8854
9132
|
}
|
|
8855
|
-
const names = await
|
|
9133
|
+
const names = await readdir3(absolute);
|
|
8856
9134
|
const entries = [];
|
|
8857
9135
|
for (const name of names) {
|
|
8858
9136
|
if (UUID_RE3.test(name.replace(/\.meta\.json$/, "")) && name.endsWith(".meta.json")) {
|
|
8859
9137
|
continue;
|
|
8860
9138
|
}
|
|
8861
9139
|
try {
|
|
8862
|
-
const entryPath =
|
|
9140
|
+
const entryPath = join12(absolute, name);
|
|
8863
9141
|
const s = await stat4(entryPath);
|
|
8864
9142
|
entries.push({
|
|
8865
9143
|
name,
|
|
@@ -8895,7 +9173,8 @@ app15.get("/", requireAdminSession, async (c) => {
|
|
|
8895
9173
|
});
|
|
8896
9174
|
app15.get("/download", requireAdminSession, async (c) => {
|
|
8897
9175
|
const cacheKey = c.var.cacheKey;
|
|
8898
|
-
|
|
9176
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
9177
|
+
if (!accountId) {
|
|
8899
9178
|
console.error(`[data] auth-rejected endpoint="/api/admin/files/download" reason="no account for session"`);
|
|
8900
9179
|
return c.json({ error: "Account not found for session" }, 401);
|
|
8901
9180
|
}
|
|
@@ -8909,6 +9188,10 @@ app15.get("/download", requireAdminSession, async (c) => {
|
|
|
8909
9188
|
return c.json({ error: resolution.error }, resolution.status);
|
|
8910
9189
|
}
|
|
8911
9190
|
const { absolute, relative: relPath2 } = resolution;
|
|
9191
|
+
if (crossesForeignAccountPartition(relPath2, accountId)) {
|
|
9192
|
+
console.error(`[data] account-scope-blocked endpoint="/api/admin/files/download" path="${relPath2}" account=${accountId.slice(0, 8)}\u2026`);
|
|
9193
|
+
return c.json({ error: "Not found" }, 404);
|
|
9194
|
+
}
|
|
8912
9195
|
try {
|
|
8913
9196
|
const info = await stat4(absolute);
|
|
8914
9197
|
if (!info.isFile()) {
|
|
@@ -8973,13 +9256,13 @@ app15.post("/upload", requireAdminSession, async (c) => {
|
|
|
8973
9256
|
}
|
|
8974
9257
|
const safeName = basename4(file.name).replace(/[\0/\\]/g, "_");
|
|
8975
9258
|
const finalName = `${Date.now()}-${safeName}`;
|
|
8976
|
-
const destDir =
|
|
8977
|
-
const destPath =
|
|
9259
|
+
const destDir = resolve14(DATA_ROOT, "uploads", accountId);
|
|
9260
|
+
const destPath = resolve14(destDir, finalName);
|
|
8978
9261
|
try {
|
|
8979
9262
|
await mkdir3(destDir, { recursive: true });
|
|
8980
9263
|
const dataRootReal = realpathSync4(DATA_ROOT);
|
|
8981
9264
|
const destDirReal = realpathSync4(destDir);
|
|
8982
|
-
if (destDirReal !== dataRootReal && !destDirReal.startsWith(dataRootReal +
|
|
9265
|
+
if (destDirReal !== dataRootReal && !destDirReal.startsWith(dataRootReal + sep4)) {
|
|
8983
9266
|
console.error(`[data] path-traversal-blocked requested="uploads/${accountId}" resolved="${destDirReal}"`);
|
|
8984
9267
|
return c.json({ error: "Upload destination escapes DATA_ROOT" }, 403);
|
|
8985
9268
|
}
|
|
@@ -8992,6 +9275,9 @@ app15.post("/upload", requireAdminSession, async (c) => {
|
|
|
8992
9275
|
}
|
|
8993
9276
|
const relativeDest = `uploads/${accountId}/${finalName}`;
|
|
8994
9277
|
console.error(`[data] file-upload filename="${safeName}" size=${file.size} dest="${relativeDest}"`);
|
|
9278
|
+
void indexFile(accountId, relativeDest).catch((err) => {
|
|
9279
|
+
console.error(`[data] file-upload index-failed dest="${relativeDest}" err="${err instanceof Error ? err.message : String(err)}"`);
|
|
9280
|
+
});
|
|
8995
9281
|
return c.json({
|
|
8996
9282
|
path: relativeDest,
|
|
8997
9283
|
filename: finalName,
|
|
@@ -9032,7 +9318,7 @@ app15.delete("/", requireAdminSession, async (c) => {
|
|
|
9032
9318
|
}
|
|
9033
9319
|
const dot = base.lastIndexOf(".");
|
|
9034
9320
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
9035
|
-
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ?
|
|
9321
|
+
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join12(dirname3(absolute), `${stem}.meta.json`) : null;
|
|
9036
9322
|
await unlink2(absolute);
|
|
9037
9323
|
if (sidecarPath) {
|
|
9038
9324
|
try {
|
|
@@ -9041,6 +9327,11 @@ app15.delete("/", requireAdminSession, async (c) => {
|
|
|
9041
9327
|
}
|
|
9042
9328
|
}
|
|
9043
9329
|
console.error(`[data] file-delete path="${relPath2}" bytes=${info.size}`);
|
|
9330
|
+
try {
|
|
9331
|
+
await dropFileIndex(accountId, relPath2);
|
|
9332
|
+
} catch (err) {
|
|
9333
|
+
console.error(`[data] file-delete index-drop-failed path="${relPath2}" err="${err instanceof Error ? err.message : String(err)}"`);
|
|
9334
|
+
}
|
|
9044
9335
|
const parsed = parseAttachmentPath(relPath2);
|
|
9045
9336
|
if (parsed) {
|
|
9046
9337
|
try {
|
|
@@ -9860,6 +10151,9 @@ app16.get("/", requireAdminSession, async (c) => {
|
|
|
9860
10151
|
}
|
|
9861
10152
|
const wantsBodyFulltext = !wildcard && labels.some((l) => CONVERSATION_PARENT_LABELS.has(l));
|
|
9862
10153
|
const forwardedLabels = wildcard ? void 0 : wantsBodyFulltext ? Array.from(/* @__PURE__ */ new Set([...labels, ...MESSAGE_FAMILY_LABELS])) : labels;
|
|
10154
|
+
if (labels.includes("FileArtifact")) {
|
|
10155
|
+
await reconcileFileIndexDebounced(accountId);
|
|
10156
|
+
}
|
|
9863
10157
|
const started = Date.now();
|
|
9864
10158
|
const session = getSession();
|
|
9865
10159
|
try {
|
|
@@ -11064,43 +11358,38 @@ var WRITE_CYPHER = `
|
|
|
11064
11358
|
`;
|
|
11065
11359
|
var graph_default_view_default = app21;
|
|
11066
11360
|
|
|
11067
|
-
// server/routes/admin/file-attach.ts
|
|
11068
|
-
var app22 = new Hono();
|
|
11069
|
-
app22.post("/", async (c) => {
|
|
11070
|
-
try {
|
|
11071
|
-
const body = await c.req.json();
|
|
11072
|
-
const { filePath, accountId } = body;
|
|
11073
|
-
if (!filePath || !accountId) {
|
|
11074
|
-
return c.json({ error: "Missing required fields: filePath, accountId" }, 400);
|
|
11075
|
-
}
|
|
11076
|
-
const attachment = await storeGeneratedFile(accountId, filePath);
|
|
11077
|
-
console.error(
|
|
11078
|
-
`[admin:file-attach] stored path=${filePath} id=${attachment.attachmentId} filename=${JSON.stringify(attachment.filename)} size=${attachment.sizeBytes} mime=${attachment.mimeType}`
|
|
11079
|
-
);
|
|
11080
|
-
return c.json({
|
|
11081
|
-
attachmentId: attachment.attachmentId,
|
|
11082
|
-
filename: attachment.filename,
|
|
11083
|
-
sizeBytes: attachment.sizeBytes,
|
|
11084
|
-
mimeType: attachment.mimeType
|
|
11085
|
-
});
|
|
11086
|
-
} catch (err) {
|
|
11087
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
11088
|
-
console.error(`[admin:file-attach] error: ${message}`);
|
|
11089
|
-
return c.json({ error: message }, 500);
|
|
11090
|
-
}
|
|
11091
|
-
});
|
|
11092
|
-
var file_attach_default = app22;
|
|
11093
|
-
|
|
11094
11361
|
// server/routes/admin/sidebar-artefacts.ts
|
|
11095
11362
|
import neo4j2 from "neo4j-driver";
|
|
11096
|
-
import { readFile as readFile5, readdir as
|
|
11097
|
-
import { resolve as
|
|
11363
|
+
import { readFile as readFile5, readdir as readdir4, stat as stat5 } from "fs/promises";
|
|
11364
|
+
import { resolve as resolve15, relative as relative3, isAbsolute, sep as sep5 } from "path";
|
|
11098
11365
|
import { existsSync as existsSync16 } from "fs";
|
|
11099
11366
|
var LIMIT = 50;
|
|
11100
11367
|
var TEXT_MIME_PREFIXES = ["text/", "application/json", "application/markdown"];
|
|
11101
11368
|
var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
|
|
11102
|
-
|
|
11103
|
-
|
|
11369
|
+
function toDataRootRelPath(absPath) {
|
|
11370
|
+
if (absPath !== DATA_ROOT && !absPath.startsWith(DATA_ROOT + sep5)) return null;
|
|
11371
|
+
return relative3(DATA_ROOT, absPath);
|
|
11372
|
+
}
|
|
11373
|
+
async function resolveDocAbsPath(accountId, attachmentId) {
|
|
11374
|
+
if (!attachmentId) return null;
|
|
11375
|
+
const accountDir = resolve15(ATTACHMENTS_ROOT, accountId);
|
|
11376
|
+
const dir = resolve15(accountDir, attachmentId);
|
|
11377
|
+
try {
|
|
11378
|
+
validateFilePathInAccount(dir, accountDir);
|
|
11379
|
+
} catch {
|
|
11380
|
+
return null;
|
|
11381
|
+
}
|
|
11382
|
+
try {
|
|
11383
|
+
const entries = await readdir4(dir);
|
|
11384
|
+
const dataFile = entries.find((f) => !f.endsWith(".meta.json"));
|
|
11385
|
+
if (!dataFile) return null;
|
|
11386
|
+
return resolve15(dir, dataFile);
|
|
11387
|
+
} catch {
|
|
11388
|
+
return null;
|
|
11389
|
+
}
|
|
11390
|
+
}
|
|
11391
|
+
var app22 = new Hono();
|
|
11392
|
+
app22.get("/", requireAdminSession, async (c) => {
|
|
11104
11393
|
const cacheKey = c.var.cacheKey;
|
|
11105
11394
|
const accountId = getAccountIdForSession(cacheKey);
|
|
11106
11395
|
if (!accountId) {
|
|
@@ -11111,7 +11400,7 @@ app23.get("/", requireAdminSession, async (c) => {
|
|
|
11111
11400
|
if (docs === null) {
|
|
11112
11401
|
return c.json({ error: "Failed to load artefacts" }, 500);
|
|
11113
11402
|
}
|
|
11114
|
-
const accountDir =
|
|
11403
|
+
const accountDir = resolve15(ACCOUNTS_DIR, accountId);
|
|
11115
11404
|
const agents = await fetchAgentTemplateRows(accountDir);
|
|
11116
11405
|
const artefacts = [...docs, ...agents].sort(
|
|
11117
11406
|
(a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? "")
|
|
@@ -11152,6 +11441,7 @@ async function fetchKnowledgeDocs(accountId) {
|
|
|
11152
11441
|
}
|
|
11153
11442
|
return Promise.all(metas.map(async (m) => {
|
|
11154
11443
|
const { content, skipReason } = await readArtefactContent(accountId, m.attachmentId, m.mimeType, m.name);
|
|
11444
|
+
const absPath = await resolveDocAbsPath(accountId, m.attachmentId);
|
|
11155
11445
|
return {
|
|
11156
11446
|
id: m.id,
|
|
11157
11447
|
name: m.name,
|
|
@@ -11160,7 +11450,8 @@ async function fetchKnowledgeDocs(accountId) {
|
|
|
11160
11450
|
content,
|
|
11161
11451
|
editable: skipReason === null,
|
|
11162
11452
|
mimeType: m.mimeType,
|
|
11163
|
-
skipReason
|
|
11453
|
+
skipReason,
|
|
11454
|
+
downloadPath: absPath ? toDataRootRelPath(absPath) : null
|
|
11164
11455
|
};
|
|
11165
11456
|
}));
|
|
11166
11457
|
}
|
|
@@ -11174,8 +11465,8 @@ async function readArtefactContent(accountId, attachmentId, mimeType, displayNam
|
|
|
11174
11465
|
logSkip(displayName, "non-text-mime", mimeType);
|
|
11175
11466
|
return { content: "", skipReason: "non-text-mime" };
|
|
11176
11467
|
}
|
|
11177
|
-
const accountDir =
|
|
11178
|
-
const dir =
|
|
11468
|
+
const accountDir = resolve15(ATTACHMENTS_ROOT, accountId);
|
|
11469
|
+
const dir = resolve15(accountDir, attachmentId);
|
|
11179
11470
|
try {
|
|
11180
11471
|
validateFilePathInAccount(dir, accountDir);
|
|
11181
11472
|
} catch {
|
|
@@ -11183,13 +11474,13 @@ async function readArtefactContent(accountId, attachmentId, mimeType, displayNam
|
|
|
11183
11474
|
return { content: "", skipReason: "containment-rejected" };
|
|
11184
11475
|
}
|
|
11185
11476
|
try {
|
|
11186
|
-
const entries = await
|
|
11477
|
+
const entries = await readdir4(dir);
|
|
11187
11478
|
const dataFile = entries.find((f) => !f.endsWith(".meta.json"));
|
|
11188
11479
|
if (!dataFile) {
|
|
11189
11480
|
logSkip(displayName, "missing-on-disk", mimeType);
|
|
11190
11481
|
return { content: "", skipReason: "missing-on-disk" };
|
|
11191
11482
|
}
|
|
11192
|
-
return { content: await readFile5(
|
|
11483
|
+
return { content: await readFile5(resolve15(dir, dataFile), "utf-8"), skipReason: null };
|
|
11193
11484
|
} catch (err) {
|
|
11194
11485
|
const message = err instanceof Error ? err.message : String(err);
|
|
11195
11486
|
console.error(`[admin/sidebar-artefacts] read-failed attachmentId=${attachmentId.slice(0, 8)} error="${message}"`);
|
|
@@ -11205,8 +11496,8 @@ function logSkip(name, reason, mimeType) {
|
|
|
11205
11496
|
async function fetchAgentTemplateRows(accountDir) {
|
|
11206
11497
|
const rows = [];
|
|
11207
11498
|
for (const filename of ADMIN_AGENT_FILES) {
|
|
11208
|
-
const overridePath =
|
|
11209
|
-
const bundledPath =
|
|
11499
|
+
const overridePath = resolve15(accountDir, "agents", "admin", filename);
|
|
11500
|
+
const bundledPath = resolve15(PLATFORM_ROOT, "templates", "agents", "admin", filename);
|
|
11210
11501
|
const labelStem = filename.replace(/\.md$/, "");
|
|
11211
11502
|
const row = await readAgentTemplateRow({
|
|
11212
11503
|
id: `agent-template:admin:${filename}`,
|
|
@@ -11220,12 +11511,12 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
11220
11511
|
});
|
|
11221
11512
|
if (row) rows.push(row);
|
|
11222
11513
|
}
|
|
11223
|
-
const overrideDir =
|
|
11224
|
-
const bundledDir =
|
|
11514
|
+
const overrideDir = resolve15(accountDir, "specialists", "agents");
|
|
11515
|
+
const bundledDir = resolve15(PLATFORM_ROOT, "templates", "specialists", "agents");
|
|
11225
11516
|
const specialistNames = await unionSpecialistFilenames(overrideDir, bundledDir);
|
|
11226
11517
|
for (const filename of specialistNames) {
|
|
11227
|
-
const overridePath =
|
|
11228
|
-
const bundledPath =
|
|
11518
|
+
const overridePath = resolve15(overrideDir, filename);
|
|
11519
|
+
const bundledPath = resolve15(bundledDir, filename);
|
|
11229
11520
|
const row = await readAgentTemplateRow({
|
|
11230
11521
|
id: `agent-template:specialist:${filename}`,
|
|
11231
11522
|
displayName: filename.replace(/\.md$/, ""),
|
|
@@ -11245,7 +11536,7 @@ async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
|
11245
11536
|
for (const dir of [overrideDir, bundledDir]) {
|
|
11246
11537
|
if (!existsSync16(dir)) continue;
|
|
11247
11538
|
try {
|
|
11248
|
-
const entries = await
|
|
11539
|
+
const entries = await readdir4(dir);
|
|
11249
11540
|
for (const entry of entries) {
|
|
11250
11541
|
if (entry.endsWith(".md")) names.add(entry);
|
|
11251
11542
|
}
|
|
@@ -11292,7 +11583,11 @@ async function readAgentTemplateRow(inp) {
|
|
|
11292
11583
|
content,
|
|
11293
11584
|
editable: inp.editable,
|
|
11294
11585
|
mimeType: "text/markdown",
|
|
11295
|
-
skipReason: null
|
|
11586
|
+
skipReason: null,
|
|
11587
|
+
// Override paths live under <accountDir> (inside DATA_ROOT) and are
|
|
11588
|
+
// downloadable; bundled-fallback templates live under PLATFORM_ROOT
|
|
11589
|
+
// (outside DATA_ROOT) → null, so the client shows "not downloadable".
|
|
11590
|
+
downloadPath: toDataRootRelPath(chosenPath)
|
|
11296
11591
|
};
|
|
11297
11592
|
} catch (err) {
|
|
11298
11593
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -11303,19 +11598,19 @@ async function readAgentTemplateRow(inp) {
|
|
|
11303
11598
|
}
|
|
11304
11599
|
}
|
|
11305
11600
|
function isWithin(target, root) {
|
|
11306
|
-
const rel =
|
|
11601
|
+
const rel = relative3(root, target);
|
|
11307
11602
|
return !rel.startsWith("..") && !isAbsolute(rel);
|
|
11308
11603
|
}
|
|
11309
|
-
var sidebar_artefacts_default =
|
|
11604
|
+
var sidebar_artefacts_default = app22;
|
|
11310
11605
|
|
|
11311
11606
|
// server/routes/admin/sidebar-artefact-save.ts
|
|
11312
|
-
import { mkdir as mkdir4, readdir as
|
|
11313
|
-
import { resolve as
|
|
11607
|
+
import { mkdir as mkdir4, readdir as readdir5, stat as stat6, writeFile as writeFile5 } from "fs/promises";
|
|
11608
|
+
import { resolve as resolve16 } from "path";
|
|
11314
11609
|
import { existsSync as existsSync17 } from "fs";
|
|
11315
11610
|
var ADMIN_AGENT_FILES2 = /* @__PURE__ */ new Set(["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"]);
|
|
11316
11611
|
var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
11317
|
-
var
|
|
11318
|
-
|
|
11612
|
+
var app23 = new Hono();
|
|
11613
|
+
app23.post("/", requireAdminSession, async (c) => {
|
|
11319
11614
|
const cacheKey = c.var.cacheKey;
|
|
11320
11615
|
const accountId = getAccountIdForSession(cacheKey);
|
|
11321
11616
|
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
@@ -11323,7 +11618,7 @@ app24.post("/", requireAdminSession, async (c) => {
|
|
|
11323
11618
|
if (!body || typeof body.id !== "string" || typeof body.content !== "string") {
|
|
11324
11619
|
return c.json({ error: "id and content required" }, 400);
|
|
11325
11620
|
}
|
|
11326
|
-
const accountDir =
|
|
11621
|
+
const accountDir = resolve16(ACCOUNTS_DIR, accountId);
|
|
11327
11622
|
const resolved = await resolveSavePath(body.id, accountId, accountDir);
|
|
11328
11623
|
if (resolved.kind === "heal-race") {
|
|
11329
11624
|
c.header("Retry-After", "2");
|
|
@@ -11368,17 +11663,17 @@ async function resolveSavePath(id, accountId, accountDir) {
|
|
|
11368
11663
|
if (role !== "admin" || !ADMIN_AGENT_FILES2.has(filename)) {
|
|
11369
11664
|
return { kind: "reject", status: 400, reason: "invalid-id" };
|
|
11370
11665
|
}
|
|
11371
|
-
const parent =
|
|
11666
|
+
const parent = resolve16(accountDir, "agents", "admin");
|
|
11372
11667
|
await mkdir4(parent, { recursive: true });
|
|
11373
11668
|
try {
|
|
11374
11669
|
validateFilePathInAccount(parent, accountDir);
|
|
11375
11670
|
} catch {
|
|
11376
11671
|
return { kind: "reject", status: 400, reason: "containment-rejected" };
|
|
11377
11672
|
}
|
|
11378
|
-
return { kind: "admin-template", path:
|
|
11673
|
+
return { kind: "admin-template", path: resolve16(parent, filename) };
|
|
11379
11674
|
}
|
|
11380
11675
|
if (UUID_RE4.test(id)) {
|
|
11381
|
-
const dir =
|
|
11676
|
+
const dir = resolve16(ATTACHMENTS_ROOT, accountId, id);
|
|
11382
11677
|
if (!existsSync17(dir)) {
|
|
11383
11678
|
const attShort = id.slice(0, 8);
|
|
11384
11679
|
if (isHealPending(accountId, id)) {
|
|
@@ -11411,31 +11706,31 @@ async function resolveSavePath(id, accountId, accountDir) {
|
|
|
11411
11706
|
}
|
|
11412
11707
|
}
|
|
11413
11708
|
try {
|
|
11414
|
-
validateFilePathInAccount(dir,
|
|
11709
|
+
validateFilePathInAccount(dir, resolve16(ATTACHMENTS_ROOT, accountId));
|
|
11415
11710
|
} catch {
|
|
11416
11711
|
return { kind: "reject", status: 400, reason: "containment-rejected" };
|
|
11417
11712
|
}
|
|
11418
|
-
const entries = await
|
|
11713
|
+
const entries = await readdir5(dir);
|
|
11419
11714
|
const dataFile = entries.find((f) => !f.endsWith(".meta.json"));
|
|
11420
11715
|
if (!dataFile) {
|
|
11421
11716
|
return { kind: "reject", status: 400, reason: "not-found" };
|
|
11422
11717
|
}
|
|
11423
|
-
return { kind: "knowledge-doc", path:
|
|
11718
|
+
return { kind: "knowledge-doc", path: resolve16(dir, dataFile) };
|
|
11424
11719
|
}
|
|
11425
11720
|
return { kind: "reject", status: 400, reason: "invalid-id" };
|
|
11426
11721
|
}
|
|
11427
11722
|
function relPath(absPath, root) {
|
|
11428
11723
|
return absPath.startsWith(root) ? absPath.slice(root.length + 1) : absPath;
|
|
11429
11724
|
}
|
|
11430
|
-
var sidebar_artefact_save_default =
|
|
11725
|
+
var sidebar_artefact_save_default = app23;
|
|
11431
11726
|
|
|
11432
11727
|
// server/routes/admin/sidebar-artefact-content.ts
|
|
11433
|
-
import { readFile as readFile6, readdir as
|
|
11728
|
+
import { readFile as readFile6, readdir as readdir6 } from "fs/promises";
|
|
11434
11729
|
import { existsSync as existsSync18 } from "fs";
|
|
11435
|
-
import { resolve as
|
|
11730
|
+
import { resolve as resolve17 } from "path";
|
|
11436
11731
|
var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
11437
|
-
var
|
|
11438
|
-
|
|
11732
|
+
var app24 = new Hono();
|
|
11733
|
+
app24.get("/", requireAdminSession, async (c) => {
|
|
11439
11734
|
const cacheKey = c.var.cacheKey;
|
|
11440
11735
|
const accountId = getAccountIdForSession(cacheKey);
|
|
11441
11736
|
if (!accountId) return new Response("Unauthorized", { status: 401 });
|
|
@@ -11444,26 +11739,26 @@ app25.get("/", requireAdminSession, async (c) => {
|
|
|
11444
11739
|
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
11445
11740
|
return new Response("Not found", { status: 404 });
|
|
11446
11741
|
}
|
|
11447
|
-
const dir =
|
|
11742
|
+
const dir = resolve17(ATTACHMENTS_ROOT, accountId, id);
|
|
11448
11743
|
if (!existsSync18(dir)) {
|
|
11449
11744
|
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
11450
11745
|
return new Response("Not found", { status: 404 });
|
|
11451
11746
|
}
|
|
11452
11747
|
let meta;
|
|
11453
11748
|
try {
|
|
11454
|
-
meta = JSON.parse(await readFile6(
|
|
11749
|
+
meta = JSON.parse(await readFile6(resolve17(dir, `${id}.meta.json`), "utf-8"));
|
|
11455
11750
|
} catch {
|
|
11456
11751
|
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
11457
11752
|
return new Response("Not found", { status: 404 });
|
|
11458
11753
|
}
|
|
11459
|
-
const entries = await
|
|
11754
|
+
const entries = await readdir6(dir);
|
|
11460
11755
|
const dataFile = entries.find((f) => !f.endsWith(".meta.json"));
|
|
11461
11756
|
if (!dataFile) {
|
|
11462
11757
|
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
11463
11758
|
return new Response("Not found", { status: 404 });
|
|
11464
11759
|
}
|
|
11465
11760
|
const start = Date.now();
|
|
11466
|
-
const buffer = await readFile6(
|
|
11761
|
+
const buffer = await readFile6(resolve17(dir, dataFile));
|
|
11467
11762
|
const ms = Date.now() - start;
|
|
11468
11763
|
console.log(
|
|
11469
11764
|
`[admin/sidebar-artefact-content] account=${accountId} id=${id.slice(0, 8)} mime=${meta.mimeType} bytes=${buffer.length} ms=${ms}`
|
|
@@ -11476,7 +11771,7 @@ app25.get("/", requireAdminSession, async (c) => {
|
|
|
11476
11771
|
}
|
|
11477
11772
|
});
|
|
11478
11773
|
});
|
|
11479
|
-
var sidebar_artefact_content_default =
|
|
11774
|
+
var sidebar_artefact_content_default = app24;
|
|
11480
11775
|
|
|
11481
11776
|
// server/routes/admin/system-stats.ts
|
|
11482
11777
|
import { readFile as readFile7 } from "fs/promises";
|
|
@@ -11573,8 +11868,8 @@ async function sample() {
|
|
|
11573
11868
|
if (process.platform === "linux") return sampleLinux();
|
|
11574
11869
|
return sampleOsFallback();
|
|
11575
11870
|
}
|
|
11576
|
-
var
|
|
11577
|
-
|
|
11871
|
+
var app25 = new Hono();
|
|
11872
|
+
app25.get("/", async (c) => {
|
|
11578
11873
|
const started = Date.now();
|
|
11579
11874
|
if (!inflight) {
|
|
11580
11875
|
inflight = sample().finally(() => {
|
|
@@ -11597,14 +11892,14 @@ app26.get("/", async (c) => {
|
|
|
11597
11892
|
return c.json({ degraded: true, reason, sampledAtMs: Date.now() });
|
|
11598
11893
|
}
|
|
11599
11894
|
});
|
|
11600
|
-
var system_stats_default =
|
|
11895
|
+
var system_stats_default = app25;
|
|
11601
11896
|
|
|
11602
11897
|
// server/routes/admin/health.ts
|
|
11603
11898
|
import { existsSync as existsSync19, readFileSync as readFileSync14 } from "fs";
|
|
11604
|
-
import { resolve as
|
|
11605
|
-
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ??
|
|
11899
|
+
import { resolve as resolve18, join as join13 } from "path";
|
|
11900
|
+
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve18(process.cwd(), "..");
|
|
11606
11901
|
var brandHostname = "maxy";
|
|
11607
|
-
var brandJsonPath =
|
|
11902
|
+
var brandJsonPath = join13(PLATFORM_ROOT6, "config", "brand.json");
|
|
11608
11903
|
if (existsSync19(brandJsonPath)) {
|
|
11609
11904
|
try {
|
|
11610
11905
|
const brand = JSON.parse(readFileSync14(brandJsonPath, "utf-8"));
|
|
@@ -11612,7 +11907,7 @@ if (existsSync19(brandJsonPath)) {
|
|
|
11612
11907
|
} catch {
|
|
11613
11908
|
}
|
|
11614
11909
|
}
|
|
11615
|
-
var VERSION_FILE =
|
|
11910
|
+
var VERSION_FILE = resolve18(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
|
|
11616
11911
|
var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
11617
11912
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
11618
11913
|
function readVersion() {
|
|
@@ -11642,8 +11937,8 @@ async function probeConversationDb() {
|
|
|
11642
11937
|
});
|
|
11643
11938
|
}
|
|
11644
11939
|
}
|
|
11645
|
-
var
|
|
11646
|
-
|
|
11940
|
+
var app26 = new Hono();
|
|
11941
|
+
app26.get("/", async (c) => {
|
|
11647
11942
|
const version = readVersion();
|
|
11648
11943
|
const probe = await probeConversationDb();
|
|
11649
11944
|
const uptimeMs = Date.now() - new Date(PROCESS_STARTED_AT).getTime();
|
|
@@ -11665,7 +11960,7 @@ app27.get("/", async (c) => {
|
|
|
11665
11960
|
uptimeMs
|
|
11666
11961
|
});
|
|
11667
11962
|
});
|
|
11668
|
-
var health_default2 =
|
|
11963
|
+
var health_default2 = app26;
|
|
11669
11964
|
|
|
11670
11965
|
// server/routes/admin/linkedin-ingest.ts
|
|
11671
11966
|
var TAG20 = "[linkedin-ingest-route]";
|
|
@@ -11761,8 +12056,8 @@ function buildInitialMessage(env) {
|
|
|
11761
12056
|
}
|
|
11762
12057
|
return header;
|
|
11763
12058
|
}
|
|
11764
|
-
var
|
|
11765
|
-
|
|
12059
|
+
var app27 = new Hono();
|
|
12060
|
+
app27.post("/", requireAdminSession, async (c) => {
|
|
11766
12061
|
let body;
|
|
11767
12062
|
try {
|
|
11768
12063
|
body = await c.req.json();
|
|
@@ -11816,7 +12111,7 @@ app28.post("/", requireAdminSession, async (c) => {
|
|
|
11816
12111
|
);
|
|
11817
12112
|
return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: claudeSessionId }, 202);
|
|
11818
12113
|
});
|
|
11819
|
-
var linkedin_ingest_default =
|
|
12114
|
+
var linkedin_ingest_default = app27;
|
|
11820
12115
|
|
|
11821
12116
|
// server/routes/admin/post-turn-context.ts
|
|
11822
12117
|
import neo4j3 from "neo4j-driver";
|
|
@@ -11858,8 +12153,8 @@ function pruneProperties(raw) {
|
|
|
11858
12153
|
}
|
|
11859
12154
|
return out;
|
|
11860
12155
|
}
|
|
11861
|
-
var
|
|
11862
|
-
|
|
12156
|
+
var app28 = new Hono();
|
|
12157
|
+
app28.get("/", async (c) => {
|
|
11863
12158
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
11864
12159
|
if (!isLoopbackAddr2(remoteAddr)) {
|
|
11865
12160
|
console.error(`${TAG21} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -11919,7 +12214,7 @@ app29.get("/", async (c) => {
|
|
|
11919
12214
|
await session.close();
|
|
11920
12215
|
}
|
|
11921
12216
|
});
|
|
11922
|
-
var post_turn_context_default =
|
|
12217
|
+
var post_turn_context_default = app28;
|
|
11923
12218
|
|
|
11924
12219
|
// server/routes/admin/public-session-context.ts
|
|
11925
12220
|
import neo4j4 from "neo4j-driver";
|
|
@@ -11961,8 +12256,8 @@ function pruneProperties2(raw) {
|
|
|
11961
12256
|
}
|
|
11962
12257
|
return out;
|
|
11963
12258
|
}
|
|
11964
|
-
var
|
|
11965
|
-
|
|
12259
|
+
var app29 = new Hono();
|
|
12260
|
+
app29.get("/", async (c) => {
|
|
11966
12261
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
11967
12262
|
if (!isLoopbackAddr3(remoteAddr)) {
|
|
11968
12263
|
console.error(`${TAG22} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -12021,15 +12316,15 @@ app30.get("/", async (c) => {
|
|
|
12021
12316
|
await session.close();
|
|
12022
12317
|
}
|
|
12023
12318
|
});
|
|
12024
|
-
var public_session_context_default =
|
|
12319
|
+
var public_session_context_default = app29;
|
|
12025
12320
|
|
|
12026
12321
|
// server/routes/admin/public-session-exit.ts
|
|
12027
12322
|
var TAG23 = "[public-session-exit-route]";
|
|
12028
12323
|
function isLoopbackAddr4(addr) {
|
|
12029
12324
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
12030
12325
|
}
|
|
12031
|
-
var
|
|
12032
|
-
|
|
12326
|
+
var app30 = new Hono();
|
|
12327
|
+
app30.post("/", async (c) => {
|
|
12033
12328
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
12034
12329
|
if (!isLoopbackAddr4(remoteAddr)) {
|
|
12035
12330
|
console.error(`${TAG23} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -12056,15 +12351,15 @@ app31.post("/", async (c) => {
|
|
|
12056
12351
|
handlePublicSessionExit(sessionId);
|
|
12057
12352
|
return c.json({ ok: true });
|
|
12058
12353
|
});
|
|
12059
|
-
var public_session_exit_default =
|
|
12354
|
+
var public_session_exit_default = app30;
|
|
12060
12355
|
|
|
12061
12356
|
// server/routes/admin/access-session-evict.ts
|
|
12062
12357
|
var TAG24 = "[access-session-evict]";
|
|
12063
12358
|
function isLoopbackAddr5(addr) {
|
|
12064
12359
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
12065
12360
|
}
|
|
12066
|
-
var
|
|
12067
|
-
|
|
12361
|
+
var app31 = new Hono();
|
|
12362
|
+
app31.post("/", async (c) => {
|
|
12068
12363
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
12069
12364
|
if (!isLoopbackAddr5(remoteAddr)) {
|
|
12070
12365
|
console.error(`${TAG24} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -12092,49 +12387,48 @@ app32.post("/", async (c) => {
|
|
|
12092
12387
|
console.log(`${TAG24} grantId=${grantId} dropped=${dropped}`);
|
|
12093
12388
|
return c.json({ ok: true, dropped });
|
|
12094
12389
|
});
|
|
12095
|
-
var access_session_evict_default =
|
|
12390
|
+
var access_session_evict_default = app31;
|
|
12096
12391
|
|
|
12097
12392
|
// server/routes/admin/index.ts
|
|
12098
|
-
var
|
|
12099
|
-
|
|
12100
|
-
|
|
12101
|
-
|
|
12102
|
-
|
|
12103
|
-
|
|
12104
|
-
|
|
12105
|
-
|
|
12106
|
-
|
|
12107
|
-
|
|
12108
|
-
|
|
12109
|
-
|
|
12110
|
-
|
|
12111
|
-
|
|
12112
|
-
|
|
12113
|
-
|
|
12114
|
-
|
|
12115
|
-
|
|
12116
|
-
|
|
12117
|
-
|
|
12118
|
-
|
|
12119
|
-
|
|
12120
|
-
|
|
12121
|
-
|
|
12122
|
-
|
|
12123
|
-
|
|
12124
|
-
|
|
12125
|
-
|
|
12126
|
-
var admin_default = app33;
|
|
12393
|
+
var app32 = new Hono();
|
|
12394
|
+
app32.route("/session", session_default);
|
|
12395
|
+
app32.route("/logs", logs_default);
|
|
12396
|
+
app32.route("/claude-info", claude_info_default);
|
|
12397
|
+
app32.route("/attachment", attachment_default);
|
|
12398
|
+
app32.route("/agents", agents_default);
|
|
12399
|
+
app32.route("/sessions", sessions_default);
|
|
12400
|
+
app32.route("/claude-sessions", claude_sessions_default);
|
|
12401
|
+
app32.route("/log-ingest", log_ingest_default);
|
|
12402
|
+
app32.route("/events", events_default);
|
|
12403
|
+
app32.route("/files", files_default);
|
|
12404
|
+
app32.route("/graph-search", graph_search_default);
|
|
12405
|
+
app32.route("/graph-subgraph", graph_subgraph_default);
|
|
12406
|
+
app32.route("/graph-delete", graph_delete_default);
|
|
12407
|
+
app32.route("/graph-restore", graph_restore_default);
|
|
12408
|
+
app32.route("/graph-labels-in-graph", graph_labels_in_graph_default);
|
|
12409
|
+
app32.route("/graph-default-view", graph_default_view_default);
|
|
12410
|
+
app32.route("/sidebar-artefacts", sidebar_artefacts_default);
|
|
12411
|
+
app32.route("/sidebar-artefact-save", sidebar_artefact_save_default);
|
|
12412
|
+
app32.route("/sidebar-artefact-content", sidebar_artefact_content_default);
|
|
12413
|
+
app32.route("/system-stats", system_stats_default);
|
|
12414
|
+
app32.route("/health-brand", health_default2);
|
|
12415
|
+
app32.route("/linkedin-ingest", linkedin_ingest_default);
|
|
12416
|
+
app32.route("/post-turn-context", post_turn_context_default);
|
|
12417
|
+
app32.route("/public-session-context", public_session_context_default);
|
|
12418
|
+
app32.route("/public-session-exit", public_session_exit_default);
|
|
12419
|
+
app32.route("/access-session-evict", access_session_evict_default);
|
|
12420
|
+
var admin_default = app32;
|
|
12127
12421
|
|
|
12128
12422
|
// app/lib/access-gate.ts
|
|
12129
12423
|
import neo4j5 from "neo4j-driver";
|
|
12130
12424
|
import { readFileSync as readFileSync15 } from "fs";
|
|
12131
|
-
import { resolve as
|
|
12425
|
+
import { resolve as resolve19 } from "path";
|
|
12132
12426
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
12133
|
-
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ??
|
|
12427
|
+
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve19(process.cwd(), "..");
|
|
12134
12428
|
var driver = null;
|
|
12135
12429
|
function readPassword() {
|
|
12136
12430
|
if (process.env.NEO4J_PASSWORD) return process.env.NEO4J_PASSWORD;
|
|
12137
|
-
const passwordFile =
|
|
12431
|
+
const passwordFile = resolve19(PLATFORM_ROOT7, "config/.neo4j-password");
|
|
12138
12432
|
try {
|
|
12139
12433
|
return readFileSync15(passwordFile, "utf-8").trim();
|
|
12140
12434
|
} catch {
|
|
@@ -12337,8 +12631,8 @@ async function generateNewMagicToken(grantId) {
|
|
|
12337
12631
|
var TAG25 = "[access-verify]";
|
|
12338
12632
|
var MINT_TAG = "[access-session-mint]";
|
|
12339
12633
|
var COOKIE_NAME = "__access_session";
|
|
12340
|
-
var
|
|
12341
|
-
|
|
12634
|
+
var app33 = new Hono();
|
|
12635
|
+
app33.post("/", async (c) => {
|
|
12342
12636
|
const ip = c.var.clientIp || "unknown";
|
|
12343
12637
|
let body;
|
|
12344
12638
|
try {
|
|
@@ -12420,13 +12714,13 @@ app34.post("/", async (c) => {
|
|
|
12420
12714
|
displayName: grant.displayName
|
|
12421
12715
|
});
|
|
12422
12716
|
});
|
|
12423
|
-
var verify_token_default =
|
|
12717
|
+
var verify_token_default = app33;
|
|
12424
12718
|
|
|
12425
12719
|
// app/lib/access-email.ts
|
|
12426
12720
|
import { spawn as spawn2 } from "child_process";
|
|
12427
|
-
import { resolve as
|
|
12428
|
-
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT ??
|
|
12429
|
-
var SEND_SCRIPT =
|
|
12721
|
+
import { resolve as resolve20 } from "path";
|
|
12722
|
+
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT ?? resolve20(process.cwd(), "..");
|
|
12723
|
+
var SEND_SCRIPT = resolve20(
|
|
12430
12724
|
PLATFORM_ROOT8,
|
|
12431
12725
|
"plugins",
|
|
12432
12726
|
"email",
|
|
@@ -12483,9 +12777,9 @@ async function sendMagicLinkEmail(payload) {
|
|
|
12483
12777
|
|
|
12484
12778
|
// server/routes/access/request-magic-link.ts
|
|
12485
12779
|
var TAG26 = "[access-request-link]";
|
|
12486
|
-
var
|
|
12780
|
+
var app34 = new Hono();
|
|
12487
12781
|
var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
|
|
12488
|
-
|
|
12782
|
+
app34.post("/", async (c) => {
|
|
12489
12783
|
let body;
|
|
12490
12784
|
try {
|
|
12491
12785
|
body = await c.req.json();
|
|
@@ -12559,17 +12853,17 @@ app35.post("/", async (c) => {
|
|
|
12559
12853
|
);
|
|
12560
12854
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
12561
12855
|
});
|
|
12562
|
-
var request_magic_link_default =
|
|
12856
|
+
var request_magic_link_default = app34;
|
|
12563
12857
|
|
|
12564
12858
|
// server/routes/access/index.ts
|
|
12565
|
-
var
|
|
12566
|
-
|
|
12567
|
-
|
|
12568
|
-
var access_default =
|
|
12859
|
+
var app35 = new Hono();
|
|
12860
|
+
app35.route("/verify-token", verify_token_default);
|
|
12861
|
+
app35.route("/request-magic-link", request_magic_link_default);
|
|
12862
|
+
var access_default = app35;
|
|
12569
12863
|
|
|
12570
12864
|
// server/routes/sites.ts
|
|
12571
12865
|
import { existsSync as existsSync20, readFileSync as readFileSync16, realpathSync as realpathSync5, statSync as statSync7 } from "fs";
|
|
12572
|
-
import { resolve as
|
|
12866
|
+
import { resolve as resolve21 } from "path";
|
|
12573
12867
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
12574
12868
|
var MIME = {
|
|
12575
12869
|
".html": "text/html; charset=utf-8",
|
|
@@ -12600,8 +12894,8 @@ function getExt(p) {
|
|
|
12600
12894
|
if (idx < p.lastIndexOf("/")) return "";
|
|
12601
12895
|
return p.slice(idx).toLowerCase();
|
|
12602
12896
|
}
|
|
12603
|
-
var
|
|
12604
|
-
|
|
12897
|
+
var app36 = new Hono();
|
|
12898
|
+
app36.get("/:rel{.*}", (c) => {
|
|
12605
12899
|
const reqPath = c.req.path;
|
|
12606
12900
|
const rawRel = c.req.param("rel") ?? "";
|
|
12607
12901
|
const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
@@ -12626,8 +12920,8 @@ app37.get("/:rel{.*}", (c) => {
|
|
|
12626
12920
|
}
|
|
12627
12921
|
segments.push(seg);
|
|
12628
12922
|
}
|
|
12629
|
-
const rootDir =
|
|
12630
|
-
let filePath = segments.length === 0 ? rootDir :
|
|
12923
|
+
const rootDir = resolve21(account.accountDir, "sites");
|
|
12924
|
+
let filePath = segments.length === 0 ? rootDir : resolve21(rootDir, ...segments);
|
|
12631
12925
|
if (filePath !== rootDir && !filePath.startsWith(rootDir + "/")) {
|
|
12632
12926
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
12633
12927
|
return c.text("Forbidden", 403);
|
|
@@ -12647,7 +12941,7 @@ app37.get("/:rel{.*}", (c) => {
|
|
|
12647
12941
|
return c.redirect(target, 301);
|
|
12648
12942
|
}
|
|
12649
12943
|
if (stat7?.isDirectory()) {
|
|
12650
|
-
filePath =
|
|
12944
|
+
filePath = resolve21(filePath, "index.html");
|
|
12651
12945
|
}
|
|
12652
12946
|
if (!filePath.startsWith(rootDir + "/")) {
|
|
12653
12947
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
@@ -12704,7 +12998,7 @@ app37.get("/:rel{.*}", (c) => {
|
|
|
12704
12998
|
"X-Content-Type-Options": "nosniff"
|
|
12705
12999
|
});
|
|
12706
13000
|
});
|
|
12707
|
-
var sites_default =
|
|
13001
|
+
var sites_default = app36;
|
|
12708
13002
|
|
|
12709
13003
|
// app/lib/visitor-token.ts
|
|
12710
13004
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
@@ -12785,7 +13079,7 @@ var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
|
12785
13079
|
|
|
12786
13080
|
// app/lib/brand-config.ts
|
|
12787
13081
|
import { existsSync as existsSync21, readFileSync as readFileSync18 } from "fs";
|
|
12788
|
-
import { join as
|
|
13082
|
+
import { join as join14 } from "path";
|
|
12789
13083
|
var cached2 = null;
|
|
12790
13084
|
var cachedAttempted = false;
|
|
12791
13085
|
function readBrandConfig() {
|
|
@@ -12793,7 +13087,7 @@ function readBrandConfig() {
|
|
|
12793
13087
|
cachedAttempted = true;
|
|
12794
13088
|
const platformRoot = process.env.MAXY_PLATFORM_ROOT;
|
|
12795
13089
|
if (!platformRoot) return null;
|
|
12796
|
-
const brandPath =
|
|
13090
|
+
const brandPath = join14(platformRoot, "config", "brand.json");
|
|
12797
13091
|
if (!existsSync21(brandPath)) return null;
|
|
12798
13092
|
try {
|
|
12799
13093
|
cached2 = JSON.parse(readFileSync18(brandPath, "utf-8"));
|
|
@@ -12804,7 +13098,7 @@ function readBrandConfig() {
|
|
|
12804
13098
|
}
|
|
12805
13099
|
|
|
12806
13100
|
// server/routes/visitor-consent.ts
|
|
12807
|
-
var
|
|
13101
|
+
var app37 = new Hono();
|
|
12808
13102
|
var CONSENT_COOKIE_NAME = "mxy_consent";
|
|
12809
13103
|
var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
|
|
12810
13104
|
var DEFAULT_CONSENT_COPY = {
|
|
@@ -12849,17 +13143,17 @@ function siteSlugFromReferer(referer) {
|
|
|
12849
13143
|
return "";
|
|
12850
13144
|
}
|
|
12851
13145
|
}
|
|
12852
|
-
|
|
13146
|
+
app37.options("/consent", (c) => {
|
|
12853
13147
|
const origin = getOrigin(c);
|
|
12854
13148
|
setCorsHeaders(c, origin);
|
|
12855
13149
|
return c.body(null, 204);
|
|
12856
13150
|
});
|
|
12857
|
-
|
|
13151
|
+
app37.options("/brand-config", (c) => {
|
|
12858
13152
|
const origin = getOrigin(c);
|
|
12859
13153
|
setCorsHeaders(c, origin);
|
|
12860
13154
|
return c.body(null, 204);
|
|
12861
13155
|
});
|
|
12862
|
-
|
|
13156
|
+
app37.post("/consent", async (c) => {
|
|
12863
13157
|
const origin = getOrigin(c);
|
|
12864
13158
|
setCorsHeaders(c, origin);
|
|
12865
13159
|
let raw;
|
|
@@ -12899,7 +13193,7 @@ app38.post("/consent", async (c) => {
|
|
|
12899
13193
|
console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
|
|
12900
13194
|
return c.body(null, 204);
|
|
12901
13195
|
});
|
|
12902
|
-
|
|
13196
|
+
app37.get("/brand-config", (c) => {
|
|
12903
13197
|
const origin = getOrigin(c);
|
|
12904
13198
|
setCorsHeaders(c, origin);
|
|
12905
13199
|
const brand = readBrandConfig();
|
|
@@ -12909,7 +13203,7 @@ app38.get("/brand-config", (c) => {
|
|
|
12909
13203
|
c.header("Cache-Control", "public, max-age=300");
|
|
12910
13204
|
return c.json({ consent: { copy, palette } });
|
|
12911
13205
|
});
|
|
12912
|
-
var visitor_consent_default =
|
|
13206
|
+
var visitor_consent_default = app37;
|
|
12913
13207
|
|
|
12914
13208
|
// server/routes/listings.ts
|
|
12915
13209
|
function getCookie(headerValue, name) {
|
|
@@ -12930,14 +13224,14 @@ function appendConsentParams(pageUrl, token) {
|
|
|
12930
13224
|
const hashIdx = pageUrl.indexOf("#");
|
|
12931
13225
|
const hash = hashIdx >= 0 ? pageUrl.slice(hashIdx) : "";
|
|
12932
13226
|
const base = hashIdx >= 0 ? pageUrl.slice(0, hashIdx) : pageUrl;
|
|
12933
|
-
const
|
|
12934
|
-
return base +
|
|
13227
|
+
const sep6 = base.indexOf("?") >= 0 ? "&" : "?";
|
|
13228
|
+
return base + sep6 + `consent=needed&v=${encodeURIComponent(token)}` + hash;
|
|
12935
13229
|
}
|
|
12936
13230
|
}
|
|
12937
13231
|
var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
|
|
12938
13232
|
var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
12939
|
-
var
|
|
12940
|
-
|
|
13233
|
+
var app38 = new Hono();
|
|
13234
|
+
app38.get("/:slug/click", async (c) => {
|
|
12941
13235
|
const slug = c.req.param("slug") ?? "";
|
|
12942
13236
|
const rawSession = c.req.query("session") ?? "";
|
|
12943
13237
|
const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
|
|
@@ -13001,10 +13295,10 @@ app39.get("/:slug/click", async (c) => {
|
|
|
13001
13295
|
console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
13002
13296
|
return c.redirect(redirectUrl, 302);
|
|
13003
13297
|
});
|
|
13004
|
-
var listings_default =
|
|
13298
|
+
var listings_default = app38;
|
|
13005
13299
|
|
|
13006
13300
|
// server/routes/visitor-event.ts
|
|
13007
|
-
var
|
|
13301
|
+
var app39 = new Hono();
|
|
13008
13302
|
var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
|
|
13009
13303
|
var buckets = /* @__PURE__ */ new Map();
|
|
13010
13304
|
var RATE_LIMIT = 60;
|
|
@@ -13071,12 +13365,12 @@ function originAllowed(origin, allowlist) {
|
|
|
13071
13365
|
return false;
|
|
13072
13366
|
}
|
|
13073
13367
|
}
|
|
13074
|
-
|
|
13368
|
+
app39.options("/event", (c) => {
|
|
13075
13369
|
const origin = getOrigin2(c);
|
|
13076
13370
|
setCorsHeaders2(c, origin);
|
|
13077
13371
|
return c.body(null, 204);
|
|
13078
13372
|
});
|
|
13079
|
-
|
|
13373
|
+
app39.post("/event", async (c) => {
|
|
13080
13374
|
const origin = getOrigin2(c);
|
|
13081
13375
|
setCorsHeaders2(c, origin);
|
|
13082
13376
|
const ua = c.req.header("user-agent") ?? "";
|
|
@@ -13281,7 +13575,7 @@ async function writeEvent(opts) {
|
|
|
13281
13575
|
);
|
|
13282
13576
|
}
|
|
13283
13577
|
}
|
|
13284
|
-
var visitor_event_default =
|
|
13578
|
+
var visitor_event_default = app39;
|
|
13285
13579
|
|
|
13286
13580
|
// app/lib/graph-health.ts
|
|
13287
13581
|
var HOUR_MS = 60 * 60 * 1e3;
|
|
@@ -13426,7 +13720,7 @@ function broadcastAdminShutdown(reason) {
|
|
|
13426
13720
|
// ../lib/entitlement/src/index.ts
|
|
13427
13721
|
import { createPublicKey, createHash as createHash4, verify as cryptoVerify } from "crypto";
|
|
13428
13722
|
import { existsSync as existsSync22, readFileSync as readFileSync19, statSync as statSync8 } from "fs";
|
|
13429
|
-
import { resolve as
|
|
13723
|
+
import { resolve as resolve22 } from "path";
|
|
13430
13724
|
|
|
13431
13725
|
// ../lib/entitlement/src/canonicalize.ts
|
|
13432
13726
|
function canonicalize(value) {
|
|
@@ -13461,7 +13755,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
|
|
|
13461
13755
|
var GRACE_DAYS = 7;
|
|
13462
13756
|
var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
|
|
13463
13757
|
function pubkeyPath(brand) {
|
|
13464
|
-
return
|
|
13758
|
+
return resolve22(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
|
|
13465
13759
|
}
|
|
13466
13760
|
var memo = null;
|
|
13467
13761
|
function memoKey(mtimeMs, account) {
|
|
@@ -13473,7 +13767,7 @@ function resolveEntitlement(brand, account) {
|
|
|
13473
13767
|
if (brand.commercialMode !== true) {
|
|
13474
13768
|
return logResolved(implicitTrust(account), null);
|
|
13475
13769
|
}
|
|
13476
|
-
const entitlementPath =
|
|
13770
|
+
const entitlementPath = resolve22(brand.configDir, "entitlement.json");
|
|
13477
13771
|
if (!existsSync22(entitlementPath)) {
|
|
13478
13772
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
13479
13773
|
}
|
|
@@ -13664,7 +13958,7 @@ function clientFrom(c) {
|
|
|
13664
13958
|
);
|
|
13665
13959
|
}
|
|
13666
13960
|
var PLATFORM_ROOT9 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
13667
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT9 ?
|
|
13961
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT9 ? join15(PLATFORM_ROOT9, "config", "brand.json") : "";
|
|
13668
13962
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
13669
13963
|
if (BRAND_JSON_PATH && !existsSync23(BRAND_JSON_PATH)) {
|
|
13670
13964
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
@@ -13690,7 +13984,7 @@ var brandLoginOpts = {
|
|
|
13690
13984
|
bodyFont: BRAND.defaultFonts?.body,
|
|
13691
13985
|
logoContainsName: !!BRAND.logoContainsName
|
|
13692
13986
|
};
|
|
13693
|
-
var ALIAS_DOMAINS_PATH =
|
|
13987
|
+
var ALIAS_DOMAINS_PATH = join15(homedir2(), BRAND.configDir, "alias-domains.json");
|
|
13694
13988
|
function loadAliasDomains() {
|
|
13695
13989
|
try {
|
|
13696
13990
|
if (!existsSync23(ALIAS_DOMAINS_PATH)) return null;
|
|
@@ -13718,9 +14012,9 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
|
|
|
13718
14012
|
function isPublicHost(host) {
|
|
13719
14013
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
13720
14014
|
}
|
|
13721
|
-
var
|
|
13722
|
-
|
|
13723
|
-
|
|
14015
|
+
var app40 = new Hono();
|
|
14016
|
+
app40.use("*", clientIpMiddleware);
|
|
14017
|
+
app40.use("*", async (c, next) => {
|
|
13724
14018
|
await next();
|
|
13725
14019
|
c.header("X-Content-Type-Options", "nosniff");
|
|
13726
14020
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
@@ -13730,7 +14024,7 @@ app41.use("*", async (c, next) => {
|
|
|
13730
14024
|
);
|
|
13731
14025
|
});
|
|
13732
14026
|
var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
|
|
13733
|
-
|
|
14027
|
+
app40.use("*", async (c, next) => {
|
|
13734
14028
|
if (!HTTP_LOG_PATHS.has(c.req.path)) {
|
|
13735
14029
|
await next();
|
|
13736
14030
|
return;
|
|
@@ -13763,7 +14057,7 @@ var PUBLIC_ALLOWED_PREFIXES = [
|
|
|
13763
14057
|
"/sites/"
|
|
13764
14058
|
];
|
|
13765
14059
|
var PUBLIC_ALLOWED_EXACT = ["/favicon.ico"];
|
|
13766
|
-
|
|
14060
|
+
app40.use("*", async (c, next) => {
|
|
13767
14061
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
13768
14062
|
if (!isPublicHost(host)) {
|
|
13769
14063
|
await next();
|
|
@@ -13803,7 +14097,7 @@ function resolveRemoteAuthOpts() {
|
|
|
13803
14097
|
return brandLoginOpts;
|
|
13804
14098
|
}
|
|
13805
14099
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
13806
|
-
|
|
14100
|
+
app40.post("/__remote-auth/login", async (c) => {
|
|
13807
14101
|
const client = clientFrom(c);
|
|
13808
14102
|
const clientIp = client.ip || "unknown";
|
|
13809
14103
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -13848,7 +14142,7 @@ app41.post("/__remote-auth/login", async (c) => {
|
|
|
13848
14142
|
}
|
|
13849
14143
|
});
|
|
13850
14144
|
});
|
|
13851
|
-
|
|
14145
|
+
app40.get("/__remote-auth/logout", (c) => {
|
|
13852
14146
|
const client = clientFrom(c);
|
|
13853
14147
|
const clientIp = client.ip || "unknown";
|
|
13854
14148
|
console.error(`[remote-auth] logout ip=${clientIp}`);
|
|
@@ -13861,7 +14155,7 @@ app41.get("/__remote-auth/logout", (c) => {
|
|
|
13861
14155
|
}
|
|
13862
14156
|
});
|
|
13863
14157
|
});
|
|
13864
|
-
|
|
14158
|
+
app40.post("/__remote-auth/change-password", async (c) => {
|
|
13865
14159
|
const client = clientFrom(c);
|
|
13866
14160
|
const clientIp = client.ip || "unknown";
|
|
13867
14161
|
const rateLimited = checkRateLimit(client);
|
|
@@ -13912,13 +14206,13 @@ app41.post("/__remote-auth/change-password", async (c) => {
|
|
|
13912
14206
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
13913
14207
|
}
|
|
13914
14208
|
});
|
|
13915
|
-
|
|
14209
|
+
app40.get("/__remote-auth/setup", (c) => {
|
|
13916
14210
|
if (isRemoteAuthConfigured()) {
|
|
13917
14211
|
return c.redirect("/");
|
|
13918
14212
|
}
|
|
13919
14213
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
|
|
13920
14214
|
});
|
|
13921
|
-
|
|
14215
|
+
app40.post("/__remote-auth/set-initial-password", async (c) => {
|
|
13922
14216
|
if (isRemoteAuthConfigured()) {
|
|
13923
14217
|
return c.redirect("/");
|
|
13924
14218
|
}
|
|
@@ -13956,10 +14250,10 @@ app41.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
13956
14250
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
13957
14251
|
}
|
|
13958
14252
|
});
|
|
13959
|
-
|
|
14253
|
+
app40.get("/api/remote-auth/status", (c) => {
|
|
13960
14254
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
13961
14255
|
});
|
|
13962
|
-
|
|
14256
|
+
app40.post("/api/remote-auth/set-password", async (c) => {
|
|
13963
14257
|
let body;
|
|
13964
14258
|
try {
|
|
13965
14259
|
body = await c.req.json();
|
|
@@ -13990,9 +14284,9 @@ app41.post("/api/remote-auth/set-password", async (c) => {
|
|
|
13990
14284
|
return c.json({ error: "Failed to save password" }, 500);
|
|
13991
14285
|
}
|
|
13992
14286
|
});
|
|
13993
|
-
|
|
14287
|
+
app40.route("/api/_client-error", client_error_default);
|
|
13994
14288
|
console.log("[client-error-route] mounted");
|
|
13995
|
-
|
|
14289
|
+
app40.use("*", async (c, next) => {
|
|
13996
14290
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
13997
14291
|
const path2 = c.req.path;
|
|
13998
14292
|
if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/")) {
|
|
@@ -14025,12 +14319,12 @@ app41.use("*", async (c, next) => {
|
|
|
14025
14319
|
console.error(`[remote-auth] login required ip=${clientIp} path=${path2} ${disambig}`);
|
|
14026
14320
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
|
|
14027
14321
|
});
|
|
14028
|
-
|
|
14029
|
-
|
|
14030
|
-
|
|
14031
|
-
|
|
14032
|
-
|
|
14033
|
-
|
|
14322
|
+
app40.route("/api/health", health_default);
|
|
14323
|
+
app40.route("/api/chat", chat_default);
|
|
14324
|
+
app40.route("/api/whatsapp", whatsapp_default);
|
|
14325
|
+
app40.route("/api/onboarding", onboarding_default);
|
|
14326
|
+
app40.route("/api/admin", admin_default);
|
|
14327
|
+
app40.route("/api/access", access_default);
|
|
14034
14328
|
var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
|
|
14035
14329
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
14036
14330
|
var IMAGE_MIME = {
|
|
@@ -14042,7 +14336,7 @@ var IMAGE_MIME = {
|
|
|
14042
14336
|
".svg": "image/svg+xml",
|
|
14043
14337
|
".ico": "image/x-icon"
|
|
14044
14338
|
};
|
|
14045
|
-
|
|
14339
|
+
app40.get("/agent-assets/:slug/:filename", (c) => {
|
|
14046
14340
|
const slug = c.req.param("slug");
|
|
14047
14341
|
const filename = c.req.param("filename");
|
|
14048
14342
|
if (!SAFE_SLUG_RE2.test(slug)) {
|
|
@@ -14058,8 +14352,8 @@ app41.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
14058
14352
|
console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
|
|
14059
14353
|
return c.text("Not found", 404);
|
|
14060
14354
|
}
|
|
14061
|
-
const filePath =
|
|
14062
|
-
const expectedDir =
|
|
14355
|
+
const filePath = resolve23(account.accountDir, "agents", slug, "assets", filename);
|
|
14356
|
+
const expectedDir = resolve23(account.accountDir, "agents", slug, "assets");
|
|
14063
14357
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
14064
14358
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
14065
14359
|
return c.text("Forbidden", 403);
|
|
@@ -14077,7 +14371,7 @@ app41.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
14077
14371
|
"Cache-Control": "public, max-age=3600"
|
|
14078
14372
|
});
|
|
14079
14373
|
});
|
|
14080
|
-
|
|
14374
|
+
app40.get("/generated/:filename", (c) => {
|
|
14081
14375
|
const filename = c.req.param("filename");
|
|
14082
14376
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
14083
14377
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -14088,8 +14382,8 @@ app41.get("/generated/:filename", (c) => {
|
|
|
14088
14382
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
14089
14383
|
return c.text("Not found", 404);
|
|
14090
14384
|
}
|
|
14091
|
-
const filePath =
|
|
14092
|
-
const expectedDir =
|
|
14385
|
+
const filePath = resolve23(account.accountDir, "generated", filename);
|
|
14386
|
+
const expectedDir = resolve23(account.accountDir, "generated");
|
|
14093
14387
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
14094
14388
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
14095
14389
|
return c.text("Forbidden", 403);
|
|
@@ -14107,10 +14401,10 @@ app41.get("/generated/:filename", (c) => {
|
|
|
14107
14401
|
"Cache-Control": "public, max-age=86400"
|
|
14108
14402
|
});
|
|
14109
14403
|
});
|
|
14110
|
-
|
|
14111
|
-
|
|
14112
|
-
|
|
14113
|
-
|
|
14404
|
+
app40.route("/sites", sites_default);
|
|
14405
|
+
app40.route("/listings", listings_default);
|
|
14406
|
+
app40.route("/v", visitor_event_default);
|
|
14407
|
+
app40.route("/v", visitor_consent_default);
|
|
14114
14408
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
14115
14409
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
14116
14410
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
@@ -14133,7 +14427,7 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
14133
14427
|
function readInstalledVersion() {
|
|
14134
14428
|
try {
|
|
14135
14429
|
if (!PLATFORM_ROOT9) return "unknown";
|
|
14136
|
-
const versionFile =
|
|
14430
|
+
const versionFile = join15(PLATFORM_ROOT9, "config", `.${BRAND.hostname}-version`);
|
|
14137
14431
|
if (!existsSync23(versionFile)) return "unknown";
|
|
14138
14432
|
const content = readFileSync20(versionFile, "utf-8").trim();
|
|
14139
14433
|
return content || "unknown";
|
|
@@ -14176,7 +14470,7 @@ var clientErrorReporterScript = `<script>
|
|
|
14176
14470
|
function cachedHtml(file) {
|
|
14177
14471
|
let html = htmlCache.get(file);
|
|
14178
14472
|
if (!html) {
|
|
14179
|
-
html = readFileSync20(
|
|
14473
|
+
html = readFileSync20(resolve23(process.cwd(), "public", file), "utf-8");
|
|
14180
14474
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
14181
14475
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
14182
14476
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -14192,14 +14486,14 @@ ${clientErrorReporterScript}
|
|
|
14192
14486
|
}
|
|
14193
14487
|
var brandedHtmlCache = /* @__PURE__ */ new Map();
|
|
14194
14488
|
function loadBrandingCache(agentSlug) {
|
|
14195
|
-
const configDir2 =
|
|
14489
|
+
const configDir2 = join15(homedir2(), BRAND.configDir);
|
|
14196
14490
|
try {
|
|
14197
|
-
const accountJsonPath =
|
|
14491
|
+
const accountJsonPath = join15(configDir2, "account.json");
|
|
14198
14492
|
if (!existsSync23(accountJsonPath)) return null;
|
|
14199
14493
|
const account = JSON.parse(readFileSync20(accountJsonPath, "utf-8"));
|
|
14200
14494
|
const accountId = account.accountId;
|
|
14201
14495
|
if (!accountId) return null;
|
|
14202
|
-
const cachePath =
|
|
14496
|
+
const cachePath = join15(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
14203
14497
|
if (!existsSync23(cachePath)) return null;
|
|
14204
14498
|
return JSON.parse(readFileSync20(cachePath, "utf-8"));
|
|
14205
14499
|
} catch {
|
|
@@ -14208,8 +14502,8 @@ function loadBrandingCache(agentSlug) {
|
|
|
14208
14502
|
}
|
|
14209
14503
|
function resolveDefaultSlug() {
|
|
14210
14504
|
try {
|
|
14211
|
-
const configDir2 =
|
|
14212
|
-
const accountJsonPath =
|
|
14505
|
+
const configDir2 = join15(homedir2(), BRAND.configDir);
|
|
14506
|
+
const accountJsonPath = join15(configDir2, "account.json");
|
|
14213
14507
|
if (!existsSync23(accountJsonPath)) return null;
|
|
14214
14508
|
const account = JSON.parse(readFileSync20(accountJsonPath, "utf-8"));
|
|
14215
14509
|
return account.defaultAgent || null;
|
|
@@ -14247,7 +14541,7 @@ function brandedPublicHtml(agentSlug) {
|
|
|
14247
14541
|
function escapeHtml(s) {
|
|
14248
14542
|
return s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
14249
14543
|
}
|
|
14250
|
-
|
|
14544
|
+
app40.get("/", (c) => {
|
|
14251
14545
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14252
14546
|
if (isPublicHost(host)) {
|
|
14253
14547
|
const defaultSlug = resolveDefaultSlug();
|
|
@@ -14255,12 +14549,12 @@ app41.get("/", (c) => {
|
|
|
14255
14549
|
}
|
|
14256
14550
|
return c.html(cachedHtml("index.html"));
|
|
14257
14551
|
});
|
|
14258
|
-
|
|
14552
|
+
app40.get("/public", (c) => {
|
|
14259
14553
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14260
14554
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14261
14555
|
return c.html(cachedHtml("public.html"));
|
|
14262
14556
|
});
|
|
14263
|
-
|
|
14557
|
+
app40.get("/chat", (c) => {
|
|
14264
14558
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14265
14559
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14266
14560
|
return c.html(cachedHtml("public.html"));
|
|
@@ -14279,12 +14573,12 @@ async function logViewerFetch(c, next) {
|
|
|
14279
14573
|
duration_ms: Date.now() - start
|
|
14280
14574
|
});
|
|
14281
14575
|
}
|
|
14282
|
-
|
|
14283
|
-
|
|
14284
|
-
|
|
14576
|
+
app40.use("/vnc-viewer.html", logViewerFetch);
|
|
14577
|
+
app40.use("/vnc-popout.html", logViewerFetch);
|
|
14578
|
+
app40.get("/vnc-popout.html", (c) => {
|
|
14285
14579
|
let html = htmlCache.get("vnc-popout.html");
|
|
14286
14580
|
if (!html) {
|
|
14287
|
-
html = readFileSync20(
|
|
14581
|
+
html = readFileSync20(resolve23(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
14288
14582
|
const name = escapeHtml(BRAND.productName);
|
|
14289
14583
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
14290
14584
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -14294,7 +14588,7 @@ app41.get("/vnc-popout.html", (c) => {
|
|
|
14294
14588
|
}
|
|
14295
14589
|
return c.html(html);
|
|
14296
14590
|
});
|
|
14297
|
-
|
|
14591
|
+
app40.post("/api/vnc/client-event", async (c) => {
|
|
14298
14592
|
let body;
|
|
14299
14593
|
try {
|
|
14300
14594
|
body = await c.req.json();
|
|
@@ -14315,25 +14609,25 @@ app41.post("/api/vnc/client-event", async (c) => {
|
|
|
14315
14609
|
});
|
|
14316
14610
|
return c.json({ ok: true });
|
|
14317
14611
|
});
|
|
14318
|
-
|
|
14612
|
+
app40.get("/g/:slug", (c) => {
|
|
14319
14613
|
return c.html(brandedPublicHtml());
|
|
14320
14614
|
});
|
|
14321
|
-
|
|
14615
|
+
app40.get("/graph", (c) => {
|
|
14322
14616
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14323
14617
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14324
14618
|
return c.html(cachedHtml("graph.html"));
|
|
14325
14619
|
});
|
|
14326
|
-
|
|
14620
|
+
app40.get("/sessions", (c) => {
|
|
14327
14621
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14328
14622
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14329
14623
|
return c.html(cachedHtml("sessions.html"));
|
|
14330
14624
|
});
|
|
14331
|
-
|
|
14625
|
+
app40.get("/data", (c) => {
|
|
14332
14626
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14333
14627
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14334
14628
|
return c.html(cachedHtml("data.html"));
|
|
14335
14629
|
});
|
|
14336
|
-
|
|
14630
|
+
app40.get("/:slug", async (c, next) => {
|
|
14337
14631
|
const slug = c.req.param("slug");
|
|
14338
14632
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
14339
14633
|
const branding = loadBrandingCache(slug);
|
|
@@ -14343,15 +14637,15 @@ app41.get("/:slug", async (c, next) => {
|
|
|
14343
14637
|
await next();
|
|
14344
14638
|
});
|
|
14345
14639
|
if (brandFaviconPath !== "/favicon.ico") {
|
|
14346
|
-
|
|
14640
|
+
app40.get("/favicon.ico", (c) => {
|
|
14347
14641
|
c.header("Cache-Control", "public, max-age=300");
|
|
14348
14642
|
return c.redirect(brandFaviconPath, 302);
|
|
14349
14643
|
});
|
|
14350
14644
|
}
|
|
14351
|
-
|
|
14645
|
+
app40.use("/*", serveStatic({ root: "./public" }));
|
|
14352
14646
|
var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
|
|
14353
14647
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
14354
|
-
var httpServer = serve({ fetch:
|
|
14648
|
+
var httpServer = serve({ fetch: app40.fetch, port, hostname });
|
|
14355
14649
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
14356
14650
|
{
|
|
14357
14651
|
const loopHist = monitorEventLoopDelay({ resolution: 50 });
|
|
@@ -14387,7 +14681,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
14387
14681
|
}
|
|
14388
14682
|
try {
|
|
14389
14683
|
const registered = [];
|
|
14390
|
-
for (const r of
|
|
14684
|
+
for (const r of app40.routes ?? []) {
|
|
14391
14685
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
14392
14686
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
14393
14687
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|
|
@@ -14502,7 +14796,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
14502
14796
|
}
|
|
14503
14797
|
init({
|
|
14504
14798
|
configDir: configDirForWhatsApp,
|
|
14505
|
-
platformRoot:
|
|
14799
|
+
platformRoot: resolve23(process.env.MAXY_PLATFORM_ROOT ?? join15(__dirname, "..")),
|
|
14506
14800
|
accountConfig: bootAccountConfig,
|
|
14507
14801
|
onMessage: async (msg) => {
|
|
14508
14802
|
if (process.env.WHATSAPP_PTY_BRIDGE_ENABLED === "true" && msg.text && !msg.isOwnerMirror) {
|