@rubytech/create-maxy 1.0.765 → 1.0.767
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/plugins/docs/references/platform.md +1 -1
- package/payload/server/public/assets/{Checkbox-BRLBdX7n.js → Checkbox-DlTVC_SK.js} +1 -1
- package/payload/server/public/assets/admin-5VyxFsbL.js +352 -0
- package/payload/server/public/assets/data-Cq9rV3ET.js +1 -0
- package/payload/server/public/assets/graph-DBtM5lGI.js +1 -0
- package/payload/server/public/assets/{jsx-runtime-BRkYVd7p.css → jsx-runtime-DplVGra_.css} +1 -1
- package/payload/server/public/assets/{page-v5z5MBB6.js → page-B6a957B_.js} +1 -1
- package/payload/server/public/assets/{page-BscgOyqp.js → page-DoFL4ahl.js} +1 -1
- package/payload/server/public/assets/{public-CQ_WMUng.js → public-DQfai2bC.js} +1 -1
- package/payload/server/public/assets/{share-2-Cc99o2of.js → share-2-C0BFGdnr.js} +1 -1
- package/payload/server/public/assets/{useVoiceRecorder-C2CyyNiy.js → useVoiceRecorder-DDAifykV.js} +1 -1
- package/payload/server/public/data.html +5 -5
- package/payload/server/public/graph.html +6 -6
- package/payload/server/public/index.html +8 -8
- package/payload/server/public/public.html +5 -5
- package/payload/server/server.js +313 -143
- package/payload/server/public/assets/admin-g-Fjko8R.js +0 -352
- package/payload/server/public/assets/data-DVeGdjv2.js +0 -1
- package/payload/server/public/assets/graph-DHBGJFDX.js +0 -1
- /package/payload/server/public/assets/{jsx-runtime-B4QFltsm.js → jsx-runtime-ChGcT0jq.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -606,8 +606,8 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
606
606
|
};
|
|
607
607
|
|
|
608
608
|
// server/index.ts
|
|
609
|
-
import { readFileSync as readFileSync16, existsSync as
|
|
610
|
-
import { resolve as
|
|
609
|
+
import { readFileSync as readFileSync16, existsSync as existsSync22, watchFile } from "fs";
|
|
610
|
+
import { resolve as resolve23, join as join10, basename as basename7 } from "path";
|
|
611
611
|
import { homedir as homedir2 } from "os";
|
|
612
612
|
|
|
613
613
|
// app/lib/agent-slug-pattern.ts
|
|
@@ -1351,9 +1351,9 @@ function discoverAllSources(configDir2, accountLogDir2) {
|
|
|
1351
1351
|
}
|
|
1352
1352
|
function readNewLines(filepath, prev) {
|
|
1353
1353
|
if (!existsSync3(filepath)) return null;
|
|
1354
|
-
const
|
|
1355
|
-
const size =
|
|
1356
|
-
const inode =
|
|
1354
|
+
const stat7 = statSync3(filepath);
|
|
1355
|
+
const size = stat7.size;
|
|
1356
|
+
const inode = stat7.ino;
|
|
1357
1357
|
let startOffset = 0;
|
|
1358
1358
|
let rotated = false;
|
|
1359
1359
|
let truncated = false;
|
|
@@ -2692,7 +2692,7 @@ var credsSaveQueue = Promise.resolve();
|
|
|
2692
2692
|
async function drainCredsSaveQueue(timeoutMs = 5e3) {
|
|
2693
2693
|
console.error(`${TAG3} draining credential save queue\u2026`);
|
|
2694
2694
|
const timer2 = new Promise(
|
|
2695
|
-
(
|
|
2695
|
+
(resolve24) => setTimeout(() => resolve24("timeout"), timeoutMs)
|
|
2696
2696
|
);
|
|
2697
2697
|
const result = await Promise.race([
|
|
2698
2698
|
credsSaveQueue.then(() => "drained"),
|
|
@@ -2820,11 +2820,11 @@ async function createWaSocket(opts) {
|
|
|
2820
2820
|
return sock;
|
|
2821
2821
|
}
|
|
2822
2822
|
async function waitForConnection(sock) {
|
|
2823
|
-
return new Promise((
|
|
2823
|
+
return new Promise((resolve24, reject) => {
|
|
2824
2824
|
const handler = (update) => {
|
|
2825
2825
|
if (update.connection === "open") {
|
|
2826
2826
|
sock.ev.off("connection.update", handler);
|
|
2827
|
-
|
|
2827
|
+
resolve24();
|
|
2828
2828
|
}
|
|
2829
2829
|
if (update.connection === "close") {
|
|
2830
2830
|
sock.ev.off("connection.update", handler);
|
|
@@ -2938,14 +2938,14 @@ ${inspected}`;
|
|
|
2938
2938
|
return inspect2(err, INSPECT_OPTS2);
|
|
2939
2939
|
}
|
|
2940
2940
|
function withTimeout(label, promise, timeoutMs) {
|
|
2941
|
-
return new Promise((
|
|
2941
|
+
return new Promise((resolve24, reject) => {
|
|
2942
2942
|
const timer2 = setTimeout(() => {
|
|
2943
2943
|
reject(new Error(`${label} timed out after ${timeoutMs}ms`));
|
|
2944
2944
|
}, timeoutMs);
|
|
2945
2945
|
promise.then(
|
|
2946
2946
|
(value) => {
|
|
2947
2947
|
clearTimeout(timer2);
|
|
2948
|
-
|
|
2948
|
+
resolve24(value);
|
|
2949
2949
|
},
|
|
2950
2950
|
(err) => {
|
|
2951
2951
|
clearTimeout(timer2);
|
|
@@ -4159,11 +4159,11 @@ async function connectWithReconnect(conn) {
|
|
|
4159
4159
|
console.error(
|
|
4160
4160
|
`${TAG11} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
|
|
4161
4161
|
);
|
|
4162
|
-
await new Promise((
|
|
4163
|
-
const timer2 = setTimeout(
|
|
4162
|
+
await new Promise((resolve24) => {
|
|
4163
|
+
const timer2 = setTimeout(resolve24, delay);
|
|
4164
4164
|
conn.abortController.signal.addEventListener("abort", () => {
|
|
4165
4165
|
clearTimeout(timer2);
|
|
4166
|
-
|
|
4166
|
+
resolve24();
|
|
4167
4167
|
}, { once: true });
|
|
4168
4168
|
});
|
|
4169
4169
|
}
|
|
@@ -4171,16 +4171,16 @@ async function connectWithReconnect(conn) {
|
|
|
4171
4171
|
}
|
|
4172
4172
|
}
|
|
4173
4173
|
function waitForDisconnectEvent(conn) {
|
|
4174
|
-
return new Promise((
|
|
4174
|
+
return new Promise((resolve24) => {
|
|
4175
4175
|
if (!conn.sock) {
|
|
4176
|
-
|
|
4176
|
+
resolve24();
|
|
4177
4177
|
return;
|
|
4178
4178
|
}
|
|
4179
4179
|
const sock = conn.sock;
|
|
4180
4180
|
const handler = (update) => {
|
|
4181
4181
|
if (update.connection === "close") {
|
|
4182
4182
|
sock.ev.off("connection.update", handler);
|
|
4183
|
-
|
|
4183
|
+
resolve24();
|
|
4184
4184
|
}
|
|
4185
4185
|
};
|
|
4186
4186
|
sock.ev.on("connection.update", handler);
|
|
@@ -4397,8 +4397,8 @@ async function handleInboundMessage(conn, msg) {
|
|
|
4397
4397
|
const conversationKey = isGroup ? remoteJid : senderPhone;
|
|
4398
4398
|
const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
|
|
4399
4399
|
let resolvePending;
|
|
4400
|
-
const sttPending = new Promise((
|
|
4401
|
-
resolvePending =
|
|
4400
|
+
const sttPending = new Promise((resolve24) => {
|
|
4401
|
+
resolvePending = resolve24;
|
|
4402
4402
|
});
|
|
4403
4403
|
if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
|
|
4404
4404
|
try {
|
|
@@ -4511,20 +4511,20 @@ async function probeApiKey() {
|
|
|
4511
4511
|
return result.status;
|
|
4512
4512
|
}
|
|
4513
4513
|
function checkPort(port2, timeoutMs = 500) {
|
|
4514
|
-
return new Promise((
|
|
4514
|
+
return new Promise((resolve24) => {
|
|
4515
4515
|
const socket = createConnection(port2, "127.0.0.1");
|
|
4516
4516
|
socket.setTimeout(timeoutMs);
|
|
4517
4517
|
socket.once("connect", () => {
|
|
4518
4518
|
socket.destroy();
|
|
4519
|
-
|
|
4519
|
+
resolve24(true);
|
|
4520
4520
|
});
|
|
4521
4521
|
socket.once("error", () => {
|
|
4522
4522
|
socket.destroy();
|
|
4523
|
-
|
|
4523
|
+
resolve24(false);
|
|
4524
4524
|
});
|
|
4525
4525
|
socket.once("timeout", () => {
|
|
4526
4526
|
socket.destroy();
|
|
4527
|
-
|
|
4527
|
+
resolve24(false);
|
|
4528
4528
|
});
|
|
4529
4529
|
});
|
|
4530
4530
|
}
|
|
@@ -6734,8 +6734,8 @@ async function startLogin(opts) {
|
|
|
6734
6734
|
resetActiveLogin(accountId);
|
|
6735
6735
|
let resolveQr = null;
|
|
6736
6736
|
let rejectQr = null;
|
|
6737
|
-
const qrPromise = new Promise((
|
|
6738
|
-
resolveQr =
|
|
6737
|
+
const qrPromise = new Promise((resolve24, reject) => {
|
|
6738
|
+
resolveQr = resolve24;
|
|
6739
6739
|
rejectQr = reject;
|
|
6740
6740
|
});
|
|
6741
6741
|
const qrTimer = setTimeout(
|
|
@@ -9697,8 +9697,8 @@ function resolveDataPath(raw) {
|
|
|
9697
9697
|
if (resolvedReal !== dataRootReal && !resolvedReal.startsWith(dataRootReal + sep)) {
|
|
9698
9698
|
return { ok: false, status: 403, error: "Path escapes DATA_ROOT", resolved: resolvedReal };
|
|
9699
9699
|
}
|
|
9700
|
-
const
|
|
9701
|
-
return { ok: true, absolute: resolvedReal, dataRootReal, relative:
|
|
9700
|
+
const relPath2 = relative(dataRootReal, resolvedReal) || ".";
|
|
9701
|
+
return { ok: true, absolute: resolvedReal, dataRootReal, relative: relPath2 };
|
|
9702
9702
|
}
|
|
9703
9703
|
|
|
9704
9704
|
// ../lib/graph-trash/src/index.ts
|
|
@@ -9932,8 +9932,8 @@ async function restoreNode(params) {
|
|
|
9932
9932
|
|
|
9933
9933
|
// app/lib/file-delete-cascade.ts
|
|
9934
9934
|
var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
9935
|
-
function parseAttachmentPath(
|
|
9936
|
-
const segments =
|
|
9935
|
+
function parseAttachmentPath(relPath2) {
|
|
9936
|
+
const segments = relPath2.split("/").filter(Boolean);
|
|
9937
9937
|
if (segments.length !== 4) return null;
|
|
9938
9938
|
if (segments[0] !== "uploads") return null;
|
|
9939
9939
|
const accountId = segments[1];
|
|
@@ -10076,9 +10076,9 @@ async function enrich(absolute, entry, accountNames) {
|
|
|
10076
10076
|
}
|
|
10077
10077
|
}
|
|
10078
10078
|
}
|
|
10079
|
-
function buildDisplayPath(
|
|
10080
|
-
if (
|
|
10081
|
-
return
|
|
10079
|
+
function buildDisplayPath(relPath2, accountNames) {
|
|
10080
|
+
if (relPath2 === "." || relPath2 === "") return [];
|
|
10081
|
+
return relPath2.split("/").filter(Boolean).map((seg) => {
|
|
10082
10082
|
const dn = UUID_RE3.test(seg) ? accountNames.get(seg) : void 0;
|
|
10083
10083
|
return dn ? { name: seg, displayName: dn } : { name: seg };
|
|
10084
10084
|
});
|
|
@@ -10098,7 +10098,7 @@ app22.get("/", requireAdminSession, async (c) => {
|
|
|
10098
10098
|
}
|
|
10099
10099
|
return c.json({ error: resolution.error }, resolution.status);
|
|
10100
10100
|
}
|
|
10101
|
-
const { absolute, relative:
|
|
10101
|
+
const { absolute, relative: relPath2 } = resolution;
|
|
10102
10102
|
try {
|
|
10103
10103
|
const info = await stat4(absolute);
|
|
10104
10104
|
if (!info.isDirectory()) {
|
|
@@ -10131,17 +10131,17 @@ app22.get("/", requireAdminSession, async (c) => {
|
|
|
10131
10131
|
const bKey = b.displayName ?? b.name;
|
|
10132
10132
|
return aKey.localeCompare(bKey);
|
|
10133
10133
|
});
|
|
10134
|
-
const displayPath = buildDisplayPath(
|
|
10135
|
-
console.error(`[data] file-list path="${
|
|
10136
|
-
return c.json({ path:
|
|
10134
|
+
const displayPath = buildDisplayPath(relPath2, accountNames);
|
|
10135
|
+
console.error(`[data] file-list path="${relPath2}" entries=${entries.length}`);
|
|
10136
|
+
return c.json({ path: relPath2, displayPath, entries });
|
|
10137
10137
|
} catch (err) {
|
|
10138
10138
|
const code = err.code;
|
|
10139
10139
|
if (code === "ENOENT") {
|
|
10140
|
-
console.error(`[data] file-list not-found path="${
|
|
10140
|
+
console.error(`[data] file-list not-found path="${relPath2}"`);
|
|
10141
10141
|
return c.json({ error: "Not found" }, 404);
|
|
10142
10142
|
}
|
|
10143
10143
|
const message = err instanceof Error ? err.message : String(err);
|
|
10144
|
-
console.error(`[data] file-list error path="${
|
|
10144
|
+
console.error(`[data] file-list error path="${relPath2}" err="${message}"`);
|
|
10145
10145
|
return c.json({ error: message }, 500);
|
|
10146
10146
|
}
|
|
10147
10147
|
});
|
|
@@ -10160,7 +10160,7 @@ app22.get("/download", requireAdminSession, async (c) => {
|
|
|
10160
10160
|
}
|
|
10161
10161
|
return c.json({ error: resolution.error }, resolution.status);
|
|
10162
10162
|
}
|
|
10163
|
-
const { absolute, relative:
|
|
10163
|
+
const { absolute, relative: relPath2 } = resolution;
|
|
10164
10164
|
try {
|
|
10165
10165
|
const info = await stat4(absolute);
|
|
10166
10166
|
if (!info.isFile()) {
|
|
@@ -10170,7 +10170,7 @@ app22.get("/download", requireAdminSession, async (c) => {
|
|
|
10170
10170
|
const mimeType = detectMimeType(absolute);
|
|
10171
10171
|
const nodeStream = createReadStream3(absolute);
|
|
10172
10172
|
const webStream = Readable2.toWeb(nodeStream);
|
|
10173
|
-
console.error(`[data] file-download path="${
|
|
10173
|
+
console.error(`[data] file-download path="${relPath2}" size=${info.size}`);
|
|
10174
10174
|
const safeQuotedName = filename.replace(/[\r\n"\\]/g, "_");
|
|
10175
10175
|
const encodedName = encodeURIComponent(filename);
|
|
10176
10176
|
return new Response(webStream, {
|
|
@@ -10185,11 +10185,11 @@ app22.get("/download", requireAdminSession, async (c) => {
|
|
|
10185
10185
|
} catch (err) {
|
|
10186
10186
|
const code = err.code;
|
|
10187
10187
|
if (code === "ENOENT") {
|
|
10188
|
-
console.error(`[data] file-download not-found path="${
|
|
10188
|
+
console.error(`[data] file-download not-found path="${relPath2}"`);
|
|
10189
10189
|
return c.json({ error: "Not found" }, 404);
|
|
10190
10190
|
}
|
|
10191
10191
|
const message = err instanceof Error ? err.message : String(err);
|
|
10192
|
-
console.error(`[data] file-download error path="${
|
|
10192
|
+
console.error(`[data] file-download error path="${relPath2}" err="${message}"`);
|
|
10193
10193
|
return c.json({ error: message }, 500);
|
|
10194
10194
|
}
|
|
10195
10195
|
});
|
|
@@ -10267,11 +10267,11 @@ app22.delete("/", requireAdminSession, async (c) => {
|
|
|
10267
10267
|
}
|
|
10268
10268
|
return c.json({ error: resolution.error }, resolution.status);
|
|
10269
10269
|
}
|
|
10270
|
-
const { absolute, relative:
|
|
10270
|
+
const { absolute, relative: relPath2 } = resolution;
|
|
10271
10271
|
const base = basename6(absolute);
|
|
10272
|
-
const segments =
|
|
10272
|
+
const segments = relPath2.split("/").filter(Boolean);
|
|
10273
10273
|
if (base === "account.json" || segments.includes(".git")) {
|
|
10274
|
-
console.error(`[data] file-delete blocked path="${
|
|
10274
|
+
console.error(`[data] file-delete blocked path="${relPath2}" reason="protected"`);
|
|
10275
10275
|
return c.json({ error: "Protected file \u2014 refusing to delete" }, 403);
|
|
10276
10276
|
}
|
|
10277
10277
|
try {
|
|
@@ -10292,29 +10292,29 @@ app22.delete("/", requireAdminSession, async (c) => {
|
|
|
10292
10292
|
} catch {
|
|
10293
10293
|
}
|
|
10294
10294
|
}
|
|
10295
|
-
console.error(`[data] file-delete path="${
|
|
10296
|
-
const parsed = parseAttachmentPath(
|
|
10295
|
+
console.error(`[data] file-delete path="${relPath2}" bytes=${info.size}`);
|
|
10296
|
+
const parsed = parseAttachmentPath(relPath2);
|
|
10297
10297
|
if (parsed) {
|
|
10298
10298
|
try {
|
|
10299
10299
|
const { nodes } = await cascadeDeleteDocument({
|
|
10300
10300
|
accountId,
|
|
10301
10301
|
attachmentId: parsed.attachmentId
|
|
10302
10302
|
});
|
|
10303
|
-
console.error(`[data] file-delete graph-cascade path="${
|
|
10303
|
+
console.error(`[data] file-delete graph-cascade path="${relPath2}" nodes=${nodes}`);
|
|
10304
10304
|
} catch (err) {
|
|
10305
10305
|
const message = err instanceof Error ? err.message : String(err);
|
|
10306
|
-
console.error(`[data] file-delete graph-cascade-failed path="${
|
|
10306
|
+
console.error(`[data] file-delete graph-cascade-failed path="${relPath2}" err="${message}"`);
|
|
10307
10307
|
}
|
|
10308
10308
|
}
|
|
10309
10309
|
return c.json({ ok: true });
|
|
10310
10310
|
} catch (err) {
|
|
10311
10311
|
const code = err.code;
|
|
10312
10312
|
if (code === "ENOENT") {
|
|
10313
|
-
console.error(`[data] file-delete not-found path="${
|
|
10313
|
+
console.error(`[data] file-delete not-found path="${relPath2}"`);
|
|
10314
10314
|
return c.json({ error: "Not found" }, 404);
|
|
10315
10315
|
}
|
|
10316
10316
|
const message = err instanceof Error ? err.message : String(err);
|
|
10317
|
-
console.error(`[data] file-delete error path="${
|
|
10317
|
+
console.error(`[data] file-delete error path="${relPath2}" err="${message}"`);
|
|
10318
10318
|
return c.json({ error: message }, 500);
|
|
10319
10319
|
}
|
|
10320
10320
|
});
|
|
@@ -11769,32 +11769,57 @@ async function fetchKnowledgeDocs(accountId) {
|
|
|
11769
11769
|
await session.close();
|
|
11770
11770
|
}
|
|
11771
11771
|
return Promise.all(metas.map(async (m) => {
|
|
11772
|
-
const content = await readArtefactContent(accountId, m.attachmentId, m.mimeType);
|
|
11773
|
-
return {
|
|
11772
|
+
const { content, skipReason } = await readArtefactContent(accountId, m.attachmentId, m.mimeType, m.name);
|
|
11773
|
+
return {
|
|
11774
|
+
id: m.id,
|
|
11775
|
+
name: m.name,
|
|
11776
|
+
kind: "knowledge-doc",
|
|
11777
|
+
updatedAt: m.updatedAt,
|
|
11778
|
+
content,
|
|
11779
|
+
editable: skipReason === null,
|
|
11780
|
+
mimeType: m.mimeType,
|
|
11781
|
+
skipReason
|
|
11782
|
+
};
|
|
11774
11783
|
}));
|
|
11775
11784
|
}
|
|
11776
|
-
async function readArtefactContent(accountId, attachmentId, mimeType) {
|
|
11777
|
-
if (!attachmentId)
|
|
11785
|
+
async function readArtefactContent(accountId, attachmentId, mimeType, displayName) {
|
|
11786
|
+
if (!attachmentId) {
|
|
11787
|
+
logSkip(displayName, "null-attachmentId", mimeType);
|
|
11788
|
+
return { content: "", skipReason: "null-attachmentId" };
|
|
11789
|
+
}
|
|
11778
11790
|
const isText = TEXT_MIME_PREFIXES.some((p) => mimeType.startsWith(p));
|
|
11779
|
-
if (!isText)
|
|
11791
|
+
if (!isText) {
|
|
11792
|
+
logSkip(displayName, "non-text-mime", mimeType);
|
|
11793
|
+
return { content: "", skipReason: "non-text-mime" };
|
|
11794
|
+
}
|
|
11780
11795
|
const accountDir = resolve20(ATTACHMENTS_ROOT, accountId);
|
|
11781
11796
|
const dir = resolve20(accountDir, attachmentId);
|
|
11782
11797
|
try {
|
|
11783
11798
|
validateFilePathInAccount(dir, accountDir);
|
|
11784
11799
|
} catch {
|
|
11785
|
-
|
|
11800
|
+
logSkip(displayName, "containment-rejected", mimeType);
|
|
11801
|
+
return { content: "", skipReason: "containment-rejected" };
|
|
11786
11802
|
}
|
|
11787
11803
|
try {
|
|
11788
11804
|
const entries = await readdir3(dir);
|
|
11789
11805
|
const dataFile = entries.find((f) => !f.endsWith(".meta.json"));
|
|
11790
|
-
if (!dataFile)
|
|
11791
|
-
|
|
11806
|
+
if (!dataFile) {
|
|
11807
|
+
logSkip(displayName, "missing-on-disk", mimeType);
|
|
11808
|
+
return { content: "", skipReason: "missing-on-disk" };
|
|
11809
|
+
}
|
|
11810
|
+
return { content: await readFile5(resolve20(dir, dataFile), "utf-8"), skipReason: null };
|
|
11792
11811
|
} catch (err) {
|
|
11793
11812
|
const message = err instanceof Error ? err.message : String(err);
|
|
11794
11813
|
console.error(`[admin/sidebar-artefacts] read-failed attachmentId=${attachmentId.slice(0, 8)} error="${message}"`);
|
|
11795
|
-
|
|
11814
|
+
logSkip(displayName, "missing-on-disk", mimeType);
|
|
11815
|
+
return { content: "", skipReason: "missing-on-disk" };
|
|
11796
11816
|
}
|
|
11797
11817
|
}
|
|
11818
|
+
function logSkip(name, reason, mimeType) {
|
|
11819
|
+
console.log(
|
|
11820
|
+
`[admin/sidebar-artefacts] content-skipped name="${name}" reason=${reason} mimeType=${mimeType || "none"}`
|
|
11821
|
+
);
|
|
11822
|
+
}
|
|
11798
11823
|
async function fetchAgentTemplateRows(accountDir) {
|
|
11799
11824
|
const rows = [];
|
|
11800
11825
|
for (const filename of ADMIN_AGENT_FILES) {
|
|
@@ -11808,7 +11833,8 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
11808
11833
|
overridePath,
|
|
11809
11834
|
overrideRoot: accountDir,
|
|
11810
11835
|
bundledPath,
|
|
11811
|
-
bundledRoot: PLATFORM_ROOT
|
|
11836
|
+
bundledRoot: PLATFORM_ROOT,
|
|
11837
|
+
editable: true
|
|
11812
11838
|
});
|
|
11813
11839
|
if (row) rows.push(row);
|
|
11814
11840
|
}
|
|
@@ -11825,7 +11851,8 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
11825
11851
|
overridePath,
|
|
11826
11852
|
overrideRoot: accountDir,
|
|
11827
11853
|
bundledPath,
|
|
11828
|
-
bundledRoot: PLATFORM_ROOT
|
|
11854
|
+
bundledRoot: PLATFORM_ROOT,
|
|
11855
|
+
editable: false
|
|
11829
11856
|
});
|
|
11830
11857
|
if (row) rows.push(row);
|
|
11831
11858
|
}
|
|
@@ -11880,7 +11907,10 @@ async function readAgentTemplateRow(inp) {
|
|
|
11880
11907
|
name: inp.displayName,
|
|
11881
11908
|
kind: "agent-template",
|
|
11882
11909
|
updatedAt: st.mtime.toISOString(),
|
|
11883
|
-
content
|
|
11910
|
+
content,
|
|
11911
|
+
editable: inp.editable,
|
|
11912
|
+
mimeType: "text/markdown",
|
|
11913
|
+
skipReason: null
|
|
11884
11914
|
};
|
|
11885
11915
|
} catch (err) {
|
|
11886
11916
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -11896,32 +11926,172 @@ function isWithin(target, root) {
|
|
|
11896
11926
|
}
|
|
11897
11927
|
var sidebar_artefacts_default = app32;
|
|
11898
11928
|
|
|
11899
|
-
// server/routes/admin/
|
|
11929
|
+
// server/routes/admin/sidebar-artefact-save.ts
|
|
11930
|
+
import { mkdir as mkdir4, readdir as readdir4, stat as stat6, writeFile as writeFile5 } from "fs/promises";
|
|
11931
|
+
import { resolve as resolve21 } from "path";
|
|
11932
|
+
import { existsSync as existsSync20 } from "fs";
|
|
11933
|
+
var ADMIN_AGENT_FILES2 = /* @__PURE__ */ new Set(["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"]);
|
|
11934
|
+
var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
11900
11935
|
var app33 = new Hono();
|
|
11901
|
-
app33.
|
|
11902
|
-
|
|
11903
|
-
|
|
11904
|
-
|
|
11905
|
-
|
|
11906
|
-
|
|
11907
|
-
|
|
11908
|
-
|
|
11909
|
-
|
|
11910
|
-
|
|
11911
|
-
|
|
11912
|
-
|
|
11913
|
-
|
|
11914
|
-
|
|
11915
|
-
|
|
11916
|
-
|
|
11917
|
-
|
|
11918
|
-
|
|
11919
|
-
|
|
11920
|
-
|
|
11921
|
-
|
|
11922
|
-
|
|
11923
|
-
|
|
11924
|
-
|
|
11936
|
+
app33.post("/", requireAdminSession, async (c) => {
|
|
11937
|
+
const sessionKey = c.var.sessionKey;
|
|
11938
|
+
const accountId = getAccountIdForSession(sessionKey);
|
|
11939
|
+
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
11940
|
+
const body = await safeJson(c);
|
|
11941
|
+
if (!body || typeof body.id !== "string" || typeof body.content !== "string") {
|
|
11942
|
+
return c.json({ error: "id and content required" }, 400);
|
|
11943
|
+
}
|
|
11944
|
+
const accountDir = resolve21(ACCOUNTS_DIR, accountId);
|
|
11945
|
+
const resolved = await resolveSavePath(body.id, accountId, accountDir);
|
|
11946
|
+
if (resolved.kind === "reject") {
|
|
11947
|
+
console.error(
|
|
11948
|
+
`[admin/sidebar-artefact-save] auth-rejected reason=${resolved.reason} path=${body.id}`
|
|
11949
|
+
);
|
|
11950
|
+
return c.json({ error: resolved.reason }, resolved.status);
|
|
11951
|
+
}
|
|
11952
|
+
const start = Date.now();
|
|
11953
|
+
try {
|
|
11954
|
+
await writeFile5(resolved.path, body.content, "utf-8");
|
|
11955
|
+
} catch (err) {
|
|
11956
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
11957
|
+
console.error(
|
|
11958
|
+
`[admin/sidebar-artefact-save] write-failed path=${relPath(resolved.path, accountDir)} error="${message}"`
|
|
11959
|
+
);
|
|
11960
|
+
return c.json({ error: "Write failed" }, 500);
|
|
11961
|
+
}
|
|
11962
|
+
let updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
11963
|
+
try {
|
|
11964
|
+
const st = await stat6(resolved.path);
|
|
11965
|
+
updatedAt = st.mtime.toISOString();
|
|
11966
|
+
} catch {
|
|
11967
|
+
}
|
|
11968
|
+
const ms = Date.now() - start;
|
|
11969
|
+
console.log(
|
|
11970
|
+
`[admin/sidebar-artefact-save] account=${accountId} path=${relPath(resolved.path, accountDir)} bytes=${body.content.length} ms=${ms}`
|
|
11971
|
+
);
|
|
11972
|
+
return c.json({ updatedAt });
|
|
11973
|
+
});
|
|
11974
|
+
async function resolveSavePath(id, accountId, accountDir) {
|
|
11975
|
+
if (id.startsWith("agent-template:")) {
|
|
11976
|
+
const parts = id.split(":");
|
|
11977
|
+
if (parts.length !== 3) return { kind: "reject", status: 400, reason: "invalid-id" };
|
|
11978
|
+
const [, role, filename] = parts;
|
|
11979
|
+
if (role === "specialist") {
|
|
11980
|
+
return { kind: "reject", status: 403, reason: "specialist-write-blocked" };
|
|
11981
|
+
}
|
|
11982
|
+
if (role !== "admin" || !ADMIN_AGENT_FILES2.has(filename)) {
|
|
11983
|
+
return { kind: "reject", status: 400, reason: "invalid-id" };
|
|
11984
|
+
}
|
|
11985
|
+
const parent = resolve21(accountDir, "agents", "admin");
|
|
11986
|
+
await mkdir4(parent, { recursive: true });
|
|
11987
|
+
try {
|
|
11988
|
+
validateFilePathInAccount(parent, accountDir);
|
|
11989
|
+
} catch {
|
|
11990
|
+
return { kind: "reject", status: 400, reason: "containment-rejected" };
|
|
11991
|
+
}
|
|
11992
|
+
return { kind: "admin-template", path: resolve21(parent, filename) };
|
|
11993
|
+
}
|
|
11994
|
+
if (UUID_RE4.test(id)) {
|
|
11995
|
+
const dir = resolve21(ATTACHMENTS_ROOT, accountId, id);
|
|
11996
|
+
if (!existsSync20(dir)) {
|
|
11997
|
+
return { kind: "reject", status: 400, reason: "not-found" };
|
|
11998
|
+
}
|
|
11999
|
+
try {
|
|
12000
|
+
validateFilePathInAccount(dir, resolve21(ATTACHMENTS_ROOT, accountId));
|
|
12001
|
+
} catch {
|
|
12002
|
+
return { kind: "reject", status: 400, reason: "containment-rejected" };
|
|
12003
|
+
}
|
|
12004
|
+
const entries = await readdir4(dir);
|
|
12005
|
+
const dataFile = entries.find((f) => !f.endsWith(".meta.json"));
|
|
12006
|
+
if (!dataFile) {
|
|
12007
|
+
return { kind: "reject", status: 400, reason: "not-found" };
|
|
12008
|
+
}
|
|
12009
|
+
return { kind: "knowledge-doc", path: resolve21(dir, dataFile) };
|
|
12010
|
+
}
|
|
12011
|
+
return { kind: "reject", status: 400, reason: "invalid-id" };
|
|
12012
|
+
}
|
|
12013
|
+
function relPath(absPath, root) {
|
|
12014
|
+
return absPath.startsWith(root) ? absPath.slice(root.length + 1) : absPath;
|
|
12015
|
+
}
|
|
12016
|
+
var sidebar_artefact_save_default = app33;
|
|
12017
|
+
|
|
12018
|
+
// server/routes/admin/sidebar-artefact-content.ts
|
|
12019
|
+
import { readFile as readFile6, readdir as readdir5 } from "fs/promises";
|
|
12020
|
+
import { existsSync as existsSync21 } from "fs";
|
|
12021
|
+
import { resolve as resolve22 } from "path";
|
|
12022
|
+
var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
12023
|
+
var app34 = new Hono();
|
|
12024
|
+
app34.get("/", requireAdminSession, async (c) => {
|
|
12025
|
+
const sessionKey = c.var.sessionKey;
|
|
12026
|
+
const accountId = getAccountIdForSession(sessionKey);
|
|
12027
|
+
if (!accountId) return new Response("Unauthorized", { status: 401 });
|
|
12028
|
+
const id = c.req.query("id") ?? "";
|
|
12029
|
+
if (!UUID_RE5.test(id)) {
|
|
12030
|
+
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
12031
|
+
return new Response("Not found", { status: 404 });
|
|
12032
|
+
}
|
|
12033
|
+
const dir = resolve22(ATTACHMENTS_ROOT, accountId, id);
|
|
12034
|
+
if (!existsSync21(dir)) {
|
|
12035
|
+
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
12036
|
+
return new Response("Not found", { status: 404 });
|
|
12037
|
+
}
|
|
12038
|
+
let meta;
|
|
12039
|
+
try {
|
|
12040
|
+
meta = JSON.parse(await readFile6(resolve22(dir, `${id}.meta.json`), "utf-8"));
|
|
12041
|
+
} catch {
|
|
12042
|
+
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
12043
|
+
return new Response("Not found", { status: 404 });
|
|
12044
|
+
}
|
|
12045
|
+
const entries = await readdir5(dir);
|
|
12046
|
+
const dataFile = entries.find((f) => !f.endsWith(".meta.json"));
|
|
12047
|
+
if (!dataFile) {
|
|
12048
|
+
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
12049
|
+
return new Response("Not found", { status: 404 });
|
|
12050
|
+
}
|
|
12051
|
+
const start = Date.now();
|
|
12052
|
+
const buffer = await readFile6(resolve22(dir, dataFile));
|
|
12053
|
+
const ms = Date.now() - start;
|
|
12054
|
+
console.log(
|
|
12055
|
+
`[admin/sidebar-artefact-content] account=${accountId} id=${id.slice(0, 8)} mime=${meta.mimeType} bytes=${buffer.length} ms=${ms}`
|
|
12056
|
+
);
|
|
12057
|
+
return new Response(new Uint8Array(buffer), {
|
|
12058
|
+
headers: {
|
|
12059
|
+
"Content-Type": meta.mimeType,
|
|
12060
|
+
"Content-Disposition": `inline; filename="${meta.filename}"`,
|
|
12061
|
+
"Cache-Control": "private, max-age=3600"
|
|
12062
|
+
}
|
|
12063
|
+
});
|
|
12064
|
+
});
|
|
12065
|
+
var sidebar_artefact_content_default = app34;
|
|
12066
|
+
|
|
12067
|
+
// server/routes/admin/index.ts
|
|
12068
|
+
var app35 = new Hono();
|
|
12069
|
+
app35.route("/session", session_default2);
|
|
12070
|
+
app35.route("/chat", chat_default2);
|
|
12071
|
+
app35.route("/compact", compact_default);
|
|
12072
|
+
app35.route("/logs", logs_default);
|
|
12073
|
+
app35.route("/claude-info", claude_info_default);
|
|
12074
|
+
app35.route("/attachment", attachment_default);
|
|
12075
|
+
app35.route("/agents", agents_default);
|
|
12076
|
+
app35.route("/sessions", sessions_default);
|
|
12077
|
+
app35.route("/browser", browser_default);
|
|
12078
|
+
app35.route("/device-browser", device_browser_default);
|
|
12079
|
+
app35.route("/events", events_default);
|
|
12080
|
+
app35.route("/cloudflare", cloudflare_default);
|
|
12081
|
+
app35.route("/files", files_default);
|
|
12082
|
+
app35.route("/graph-search", graph_search_default);
|
|
12083
|
+
app35.route("/graph-subgraph", graph_subgraph_default);
|
|
12084
|
+
app35.route("/graph-delete", graph_delete_default);
|
|
12085
|
+
app35.route("/graph-restore", graph_restore_default);
|
|
12086
|
+
app35.route("/graph-labels-in-graph", graph_labels_in_graph_default);
|
|
12087
|
+
app35.route("/graph-default-view", graph_default_view_default);
|
|
12088
|
+
app35.route("/file-attach", file_attach_default);
|
|
12089
|
+
app35.route("/adherence", adherence_default);
|
|
12090
|
+
app35.route("/sidebar-projects", sidebar_projects_default);
|
|
12091
|
+
app35.route("/sidebar-artefacts", sidebar_artefacts_default);
|
|
12092
|
+
app35.route("/sidebar-artefact-save", sidebar_artefact_save_default);
|
|
12093
|
+
app35.route("/sidebar-artefact-content", sidebar_artefact_content_default);
|
|
12094
|
+
var admin_default = app35;
|
|
11925
12095
|
|
|
11926
12096
|
// app/lib/graph-health.ts
|
|
11927
12097
|
var HOUR_MS = 60 * 60 * 1e3;
|
|
@@ -12023,10 +12193,10 @@ function clientFrom(c) {
|
|
|
12023
12193
|
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
12024
12194
|
var BRAND_JSON_PATH = PLATFORM_ROOT7 ? join10(PLATFORM_ROOT7, "config", "brand.json") : "";
|
|
12025
12195
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", domain: "getmaxy.com" };
|
|
12026
|
-
if (BRAND_JSON_PATH && !
|
|
12196
|
+
if (BRAND_JSON_PATH && !existsSync22(BRAND_JSON_PATH)) {
|
|
12027
12197
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
12028
12198
|
}
|
|
12029
|
-
if (BRAND_JSON_PATH &&
|
|
12199
|
+
if (BRAND_JSON_PATH && existsSync22(BRAND_JSON_PATH)) {
|
|
12030
12200
|
try {
|
|
12031
12201
|
const parsed = JSON.parse(readFileSync16(BRAND_JSON_PATH, "utf-8"));
|
|
12032
12202
|
BRAND = { ...BRAND, ...parsed };
|
|
@@ -12050,7 +12220,7 @@ var brandLoginOpts = {
|
|
|
12050
12220
|
var ALIAS_DOMAINS_PATH2 = join10(homedir2(), BRAND.configDir, "alias-domains.json");
|
|
12051
12221
|
function loadAliasDomains() {
|
|
12052
12222
|
try {
|
|
12053
|
-
if (!
|
|
12223
|
+
if (!existsSync22(ALIAS_DOMAINS_PATH2)) return null;
|
|
12054
12224
|
const parsed = JSON.parse(readFileSync16(ALIAS_DOMAINS_PATH2, "utf-8"));
|
|
12055
12225
|
if (!Array.isArray(parsed)) {
|
|
12056
12226
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
@@ -12075,9 +12245,9 @@ watchFile(ALIAS_DOMAINS_PATH2, { interval: 2e3 }, () => {
|
|
|
12075
12245
|
function isPublicHost(host) {
|
|
12076
12246
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
12077
12247
|
}
|
|
12078
|
-
var
|
|
12079
|
-
|
|
12080
|
-
|
|
12248
|
+
var app36 = new Hono();
|
|
12249
|
+
app36.use("*", clientIpMiddleware);
|
|
12250
|
+
app36.use("*", async (c, next) => {
|
|
12081
12251
|
await next();
|
|
12082
12252
|
c.header("X-Content-Type-Options", "nosniff");
|
|
12083
12253
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
@@ -12100,7 +12270,7 @@ var PUBLIC_ALLOWED_PREFIXES = [
|
|
|
12100
12270
|
"/g/"
|
|
12101
12271
|
];
|
|
12102
12272
|
var PUBLIC_ALLOWED_EXACT = ["/favicon.ico"];
|
|
12103
|
-
|
|
12273
|
+
app36.use("*", async (c, next) => {
|
|
12104
12274
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
12105
12275
|
if (!isPublicHost(host)) {
|
|
12106
12276
|
await next();
|
|
@@ -12140,7 +12310,7 @@ function resolveRemoteAuthOpts() {
|
|
|
12140
12310
|
return brandLoginOpts;
|
|
12141
12311
|
}
|
|
12142
12312
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
12143
|
-
|
|
12313
|
+
app36.post("/__remote-auth/login", async (c) => {
|
|
12144
12314
|
const client = clientFrom(c);
|
|
12145
12315
|
const clientIp = client.ip || "unknown";
|
|
12146
12316
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -12184,7 +12354,7 @@ app34.post("/__remote-auth/login", async (c) => {
|
|
|
12184
12354
|
}
|
|
12185
12355
|
});
|
|
12186
12356
|
});
|
|
12187
|
-
|
|
12357
|
+
app36.get("/__remote-auth/logout", (c) => {
|
|
12188
12358
|
return new Response(null, {
|
|
12189
12359
|
status: 302,
|
|
12190
12360
|
headers: {
|
|
@@ -12194,7 +12364,7 @@ app34.get("/__remote-auth/logout", (c) => {
|
|
|
12194
12364
|
}
|
|
12195
12365
|
});
|
|
12196
12366
|
});
|
|
12197
|
-
|
|
12367
|
+
app36.post("/__remote-auth/change-password", async (c) => {
|
|
12198
12368
|
const client = clientFrom(c);
|
|
12199
12369
|
const clientIp = client.ip || "unknown";
|
|
12200
12370
|
const rateLimited = checkRateLimit(client);
|
|
@@ -12244,13 +12414,13 @@ app34.post("/__remote-auth/change-password", async (c) => {
|
|
|
12244
12414
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
12245
12415
|
}
|
|
12246
12416
|
});
|
|
12247
|
-
|
|
12417
|
+
app36.get("/__remote-auth/setup", (c) => {
|
|
12248
12418
|
if (isRemoteAuthConfigured()) {
|
|
12249
12419
|
return c.redirect("/");
|
|
12250
12420
|
}
|
|
12251
12421
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
|
|
12252
12422
|
});
|
|
12253
|
-
|
|
12423
|
+
app36.post("/__remote-auth/set-initial-password", async (c) => {
|
|
12254
12424
|
if (isRemoteAuthConfigured()) {
|
|
12255
12425
|
return c.redirect("/");
|
|
12256
12426
|
}
|
|
@@ -12286,10 +12456,10 @@ app34.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
12286
12456
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
12287
12457
|
}
|
|
12288
12458
|
});
|
|
12289
|
-
|
|
12459
|
+
app36.get("/api/remote-auth/status", (c) => {
|
|
12290
12460
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
12291
12461
|
});
|
|
12292
|
-
|
|
12462
|
+
app36.post("/api/remote-auth/set-password", async (c) => {
|
|
12293
12463
|
let body;
|
|
12294
12464
|
try {
|
|
12295
12465
|
body = await c.req.json();
|
|
@@ -12319,9 +12489,9 @@ app34.post("/api/remote-auth/set-password", async (c) => {
|
|
|
12319
12489
|
return c.json({ error: "Failed to save password" }, 500);
|
|
12320
12490
|
}
|
|
12321
12491
|
});
|
|
12322
|
-
|
|
12492
|
+
app36.route("/api/_client-error", client_error_default);
|
|
12323
12493
|
console.log("[client-error-route] mounted");
|
|
12324
|
-
|
|
12494
|
+
app36.use("*", async (c, next) => {
|
|
12325
12495
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
12326
12496
|
const path2 = c.req.path;
|
|
12327
12497
|
if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/")) {
|
|
@@ -12354,15 +12524,15 @@ app34.use("*", async (c, next) => {
|
|
|
12354
12524
|
console.error(`[remote-auth] login required ip=${clientIp} path=${path2} ${disambig}`);
|
|
12355
12525
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
|
|
12356
12526
|
});
|
|
12357
|
-
|
|
12358
|
-
|
|
12359
|
-
|
|
12360
|
-
|
|
12361
|
-
|
|
12362
|
-
|
|
12363
|
-
|
|
12364
|
-
|
|
12365
|
-
|
|
12527
|
+
app36.route("/api/health", health_default);
|
|
12528
|
+
app36.route("/api/session", session_default);
|
|
12529
|
+
app36.route("/api/chat", chat_default);
|
|
12530
|
+
app36.route("/api/group", group_default);
|
|
12531
|
+
app36.route("/api/access", access_default);
|
|
12532
|
+
app36.route("/api/telegram", telegram_default);
|
|
12533
|
+
app36.route("/api/whatsapp", whatsapp_default);
|
|
12534
|
+
app36.route("/api/onboarding", onboarding_default);
|
|
12535
|
+
app36.route("/api/admin", admin_default);
|
|
12366
12536
|
var SAFE_SLUG_RE = /^[a-z][a-z0-9-]{2,49}$/;
|
|
12367
12537
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
12368
12538
|
var IMAGE_MIME = {
|
|
@@ -12374,7 +12544,7 @@ var IMAGE_MIME = {
|
|
|
12374
12544
|
".svg": "image/svg+xml",
|
|
12375
12545
|
".ico": "image/x-icon"
|
|
12376
12546
|
};
|
|
12377
|
-
|
|
12547
|
+
app36.get("/agent-assets/:slug/:filename", (c) => {
|
|
12378
12548
|
const slug = c.req.param("slug");
|
|
12379
12549
|
const filename = c.req.param("filename");
|
|
12380
12550
|
if (!SAFE_SLUG_RE.test(slug)) {
|
|
@@ -12390,13 +12560,13 @@ app34.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
12390
12560
|
console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
|
|
12391
12561
|
return c.text("Not found", 404);
|
|
12392
12562
|
}
|
|
12393
|
-
const filePath =
|
|
12394
|
-
const expectedDir =
|
|
12563
|
+
const filePath = resolve23(account.accountDir, "agents", slug, "assets", filename);
|
|
12564
|
+
const expectedDir = resolve23(account.accountDir, "agents", slug, "assets");
|
|
12395
12565
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
12396
12566
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
12397
12567
|
return c.text("Forbidden", 403);
|
|
12398
12568
|
}
|
|
12399
|
-
if (!
|
|
12569
|
+
if (!existsSync22(filePath)) {
|
|
12400
12570
|
console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
|
|
12401
12571
|
return c.text("Not found", 404);
|
|
12402
12572
|
}
|
|
@@ -12409,7 +12579,7 @@ app34.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
12409
12579
|
"Cache-Control": "public, max-age=3600"
|
|
12410
12580
|
});
|
|
12411
12581
|
});
|
|
12412
|
-
|
|
12582
|
+
app36.get("/generated/:filename", (c) => {
|
|
12413
12583
|
const filename = c.req.param("filename");
|
|
12414
12584
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
12415
12585
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -12420,13 +12590,13 @@ app34.get("/generated/:filename", (c) => {
|
|
|
12420
12590
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
12421
12591
|
return c.text("Not found", 404);
|
|
12422
12592
|
}
|
|
12423
|
-
const filePath =
|
|
12424
|
-
const expectedDir =
|
|
12593
|
+
const filePath = resolve23(account.accountDir, "generated", filename);
|
|
12594
|
+
const expectedDir = resolve23(account.accountDir, "generated");
|
|
12425
12595
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
12426
12596
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
12427
12597
|
return c.text("Forbidden", 403);
|
|
12428
12598
|
}
|
|
12429
|
-
if (!
|
|
12599
|
+
if (!existsSync22(filePath)) {
|
|
12430
12600
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
12431
12601
|
return c.text("Not found", 404);
|
|
12432
12602
|
}
|
|
@@ -12442,7 +12612,7 @@ app34.get("/generated/:filename", (c) => {
|
|
|
12442
12612
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
12443
12613
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
12444
12614
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
12445
|
-
if (BRAND_JSON_PATH &&
|
|
12615
|
+
if (BRAND_JSON_PATH && existsSync22(BRAND_JSON_PATH)) {
|
|
12446
12616
|
try {
|
|
12447
12617
|
const fullBrand = JSON.parse(readFileSync16(BRAND_JSON_PATH, "utf-8"));
|
|
12448
12618
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
@@ -12462,7 +12632,7 @@ function readInstalledVersion() {
|
|
|
12462
12632
|
try {
|
|
12463
12633
|
if (!PLATFORM_ROOT7) return "unknown";
|
|
12464
12634
|
const versionFile = join10(PLATFORM_ROOT7, "config", `.${BRAND.hostname}-version`);
|
|
12465
|
-
if (!
|
|
12635
|
+
if (!existsSync22(versionFile)) return "unknown";
|
|
12466
12636
|
const content = readFileSync16(versionFile, "utf-8").trim();
|
|
12467
12637
|
return content || "unknown";
|
|
12468
12638
|
} catch {
|
|
@@ -12504,7 +12674,7 @@ var clientErrorReporterScript = `<script>
|
|
|
12504
12674
|
function cachedHtml(file) {
|
|
12505
12675
|
let html = htmlCache.get(file);
|
|
12506
12676
|
if (!html) {
|
|
12507
|
-
html = readFileSync16(
|
|
12677
|
+
html = readFileSync16(resolve23(process.cwd(), "public", file), "utf-8");
|
|
12508
12678
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
12509
12679
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
12510
12680
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -12523,12 +12693,12 @@ function loadBrandingCache(agentSlug) {
|
|
|
12523
12693
|
const configDir2 = join10(homedir2(), BRAND.configDir);
|
|
12524
12694
|
try {
|
|
12525
12695
|
const accountJsonPath = join10(configDir2, "account.json");
|
|
12526
|
-
if (!
|
|
12696
|
+
if (!existsSync22(accountJsonPath)) return null;
|
|
12527
12697
|
const account = JSON.parse(readFileSync16(accountJsonPath, "utf-8"));
|
|
12528
12698
|
const accountId = account.accountId;
|
|
12529
12699
|
if (!accountId) return null;
|
|
12530
12700
|
const cachePath = join10(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
12531
|
-
if (!
|
|
12701
|
+
if (!existsSync22(cachePath)) return null;
|
|
12532
12702
|
return JSON.parse(readFileSync16(cachePath, "utf-8"));
|
|
12533
12703
|
} catch {
|
|
12534
12704
|
return null;
|
|
@@ -12538,7 +12708,7 @@ function resolveDefaultSlug() {
|
|
|
12538
12708
|
try {
|
|
12539
12709
|
const configDir2 = join10(homedir2(), BRAND.configDir);
|
|
12540
12710
|
const accountJsonPath = join10(configDir2, "account.json");
|
|
12541
|
-
if (!
|
|
12711
|
+
if (!existsSync22(accountJsonPath)) return null;
|
|
12542
12712
|
const account = JSON.parse(readFileSync16(accountJsonPath, "utf-8"));
|
|
12543
12713
|
return account.defaultAgent || null;
|
|
12544
12714
|
} catch {
|
|
@@ -12575,7 +12745,7 @@ function brandedPublicHtml(agentSlug) {
|
|
|
12575
12745
|
function escapeHtml(s) {
|
|
12576
12746
|
return s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
12577
12747
|
}
|
|
12578
|
-
|
|
12748
|
+
app36.get("/", (c) => {
|
|
12579
12749
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
12580
12750
|
if (isPublicHost(host)) {
|
|
12581
12751
|
const defaultSlug = resolveDefaultSlug();
|
|
@@ -12583,12 +12753,12 @@ app34.get("/", (c) => {
|
|
|
12583
12753
|
}
|
|
12584
12754
|
return c.html(cachedHtml("index.html"));
|
|
12585
12755
|
});
|
|
12586
|
-
|
|
12756
|
+
app36.get("/public", (c) => {
|
|
12587
12757
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
12588
12758
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
12589
12759
|
return c.html(cachedHtml("public.html"));
|
|
12590
12760
|
});
|
|
12591
|
-
|
|
12761
|
+
app36.get("/chat", (c) => {
|
|
12592
12762
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
12593
12763
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
12594
12764
|
return c.html(cachedHtml("public.html"));
|
|
@@ -12607,12 +12777,12 @@ async function logViewerFetch(c, next) {
|
|
|
12607
12777
|
duration_ms: Date.now() - start
|
|
12608
12778
|
});
|
|
12609
12779
|
}
|
|
12610
|
-
|
|
12611
|
-
|
|
12612
|
-
|
|
12780
|
+
app36.use("/vnc-viewer.html", logViewerFetch);
|
|
12781
|
+
app36.use("/vnc-popout.html", logViewerFetch);
|
|
12782
|
+
app36.get("/vnc-popout.html", (c) => {
|
|
12613
12783
|
let html = htmlCache.get("vnc-popout.html");
|
|
12614
12784
|
if (!html) {
|
|
12615
|
-
html = readFileSync16(
|
|
12785
|
+
html = readFileSync16(resolve23(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
12616
12786
|
const name = escapeHtml(BRAND.productName);
|
|
12617
12787
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
12618
12788
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -12622,7 +12792,7 @@ app34.get("/vnc-popout.html", (c) => {
|
|
|
12622
12792
|
}
|
|
12623
12793
|
return c.html(html);
|
|
12624
12794
|
});
|
|
12625
|
-
|
|
12795
|
+
app36.post("/api/vnc/client-event", async (c) => {
|
|
12626
12796
|
let body;
|
|
12627
12797
|
try {
|
|
12628
12798
|
body = await c.req.json();
|
|
@@ -12643,20 +12813,20 @@ app34.post("/api/vnc/client-event", async (c) => {
|
|
|
12643
12813
|
});
|
|
12644
12814
|
return c.json({ ok: true });
|
|
12645
12815
|
});
|
|
12646
|
-
|
|
12816
|
+
app36.get("/g/:slug", (c) => {
|
|
12647
12817
|
return c.html(brandedPublicHtml());
|
|
12648
12818
|
});
|
|
12649
|
-
|
|
12819
|
+
app36.get("/graph", (c) => {
|
|
12650
12820
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
12651
12821
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
12652
12822
|
return c.html(cachedHtml("graph.html"));
|
|
12653
12823
|
});
|
|
12654
|
-
|
|
12824
|
+
app36.get("/data", (c) => {
|
|
12655
12825
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
12656
12826
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
12657
12827
|
return c.html(cachedHtml("data.html"));
|
|
12658
12828
|
});
|
|
12659
|
-
|
|
12829
|
+
app36.get("/:slug", async (c, next) => {
|
|
12660
12830
|
const slug = c.req.param("slug");
|
|
12661
12831
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
12662
12832
|
const branding = loadBrandingCache(slug);
|
|
@@ -12665,10 +12835,10 @@ app34.get("/:slug", async (c, next) => {
|
|
|
12665
12835
|
}
|
|
12666
12836
|
await next();
|
|
12667
12837
|
});
|
|
12668
|
-
|
|
12838
|
+
app36.use("/*", serveStatic({ root: "./public" }));
|
|
12669
12839
|
var port = parseInt(process.env.MAXY_UI_INTERNAL_PORT ?? process.env.PORT ?? "19199", 10);
|
|
12670
12840
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
12671
|
-
var httpServer = serve({ fetch:
|
|
12841
|
+
var httpServer = serve({ fetch: app36.fetch, port, hostname });
|
|
12672
12842
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
12673
12843
|
var SUBAPP_MANIFEST = [
|
|
12674
12844
|
{ prefix: "/api/health", file: "server/routes/health.ts", subapp: health_default },
|
|
@@ -12688,7 +12858,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
12688
12858
|
}
|
|
12689
12859
|
try {
|
|
12690
12860
|
const registered = [];
|
|
12691
|
-
for (const r of
|
|
12861
|
+
for (const r of app36.routes ?? []) {
|
|
12692
12862
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
12693
12863
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
12694
12864
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|
|
@@ -12702,7 +12872,7 @@ try {
|
|
|
12702
12872
|
(async () => {
|
|
12703
12873
|
try {
|
|
12704
12874
|
let userId = "";
|
|
12705
|
-
if (
|
|
12875
|
+
if (existsSync22(USERS_FILE)) {
|
|
12706
12876
|
const users = JSON.parse(readFileSync16(USERS_FILE, "utf-8").trim() || "[]");
|
|
12707
12877
|
userId = users[0]?.userId ?? "";
|
|
12708
12878
|
}
|
|
@@ -12755,7 +12925,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
12755
12925
|
}
|
|
12756
12926
|
init({
|
|
12757
12927
|
configDir: configDirForWhatsApp,
|
|
12758
|
-
platformRoot:
|
|
12928
|
+
platformRoot: resolve23(process.env.MAXY_PLATFORM_ROOT ?? join10(__dirname, "..")),
|
|
12759
12929
|
accountConfig: bootAccountConfig,
|
|
12760
12930
|
onMessage: async (msg) => {
|
|
12761
12931
|
try {
|