@rubytech/create-maxy-code 0.1.192 → 0.1.194
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/deployment.md +6 -4
- package/payload/platform/plugins/docs/references/projects-guide.md +21 -0
- package/payload/platform/plugins/work/PLUGIN.md +2 -0
- package/payload/platform/plugins/work/skills/execute-task/SKILL.md +101 -0
- 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 +12 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/server/{chunk-WWD4TCJJ.js → chunk-EXIPYITB.js} +2 -0
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/assets/AdminShell-BoJbnn6d.js +1 -0
- package/payload/server/public/assets/{Checkbox-DsHqjzGj.js → Checkbox-G-kyM1P1.js} +1 -1
- package/payload/server/public/assets/{admin-CWOprOdW.js → admin-B-GDNkoN.js} +1 -1
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-DROzw8rH.js → architectureDiagram-Q4EWVU46-BGgdXdD2.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-Dw9sieJu.js → blockDiagram-DXYQGD6D-DKWoL4Rp.js} +1 -1
- package/payload/server/public/assets/{brand-BQW2DYy_.css → brand-MbpD2Bhr.css} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-fnwntjFK.js → c4Diagram-AHTNJAMY-Ca6rs6F4.js} +1 -1
- package/payload/server/public/assets/channel-BwsV7WTV.js +1 -0
- package/payload/server/public/assets/{chunk-336JU56O-DVpyamlA.js → chunk-336JU56O-DcdMZImV.js} +2 -2
- package/payload/server/public/assets/{chunk-426QAEUC-yiGugjCx.js → chunk-426QAEUC-9FSP-c1z.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-BAPL_MqI.js → chunk-4TB4RGXK-CC1QpEvA.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-Ba-5D35r.js → chunk-5FUZZQ4R-o1b70dEE.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-BtDS8-t9.js → chunk-5PVQY5BW-C7VCYRz9.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-CqcdpDg_.js → chunk-EDXVE4YY-B8d5xj_4.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-CaBy9U1e.js → chunk-ENJZ2VHE-SSbr4n2X.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-BdPjOce4.js → chunk-ICPOFSXX-Cgj9YSpX.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-CK6wx_FD.js → chunk-OYMX7WX6-DNEEcCqI.js} +1 -1
- package/payload/server/public/assets/{chunk-U2HBQHQK-DyZFy43o.js → chunk-U2HBQHQK-DuaoK83q.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-CMTofLbX.js → chunk-X2U36JSP-CzMp0dpq.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-YfFrkYbQ.js → chunk-YZCP3GAM-B2wBDwSa.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-BVfvS5n3.js → chunk-ZZ45TVLE-DkyF7XKW.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-CEWNfHVo.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BBjzRxux.js +1 -0
- package/payload/server/public/assets/clone-CXtSonnn.js +1 -0
- package/payload/server/public/assets/{dagre-ComHkUs6.js → dagre-AGj1P0p4.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-BB-QqzpF.js → dagre-KV5264BT-Cnrxcu6A.js} +1 -1
- package/payload/server/public/assets/data-Bg0Frxt3.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-CpQQszhw.js → diagram-5BDNPKRD-gyFYSx73.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-DLdElVzs.js → diagram-G4DWMVQ6-DFmZEv5C.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-JQ3ceLSO.js → diagram-MMDJMWI5-DA4qbuEW.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-D_-AtVPR.js → diagram-TYMM5635-D4n-8gig.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-Dq50MKD-.js → erDiagram-SMLLAGMA-CigRMjF1.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-CEdKm-zL.js → flowDiagram-DWJPFMVM-ClS27acA.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-CpTomdNN.js → ganttDiagram-T4ZO3ILL-Dr1IulXe.js} +1 -1
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-VU-gjbee.js → gitGraphDiagram-UUTBAWPF-lwLibdPs.js} +1 -1
- package/payload/server/public/assets/{graph-BXaY_xoS.js → graph-CpozZ74I.js} +2 -2
- package/payload/server/public/assets/{graph-labels-EqZyoU25.js → graph-labels-C2y666R0.js} +1 -1
- package/payload/server/public/assets/{graphlib-nLzyerxi.js → graphlib-DBvoJMrc.js} +1 -1
- package/payload/server/public/assets/{infoDiagram-42DDH7IO-ThwX5Xgr.js → infoDiagram-42DDH7IO-D4kReEIV.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-DaKxxHLW.js → ishikawaDiagram-UXIWVN3A-BnteQRQ0.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-DtMAHpWz.js → journeyDiagram-VCZTEJTY-CXu6hLyJ.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-s898dJRu.js → kanban-definition-6JOO6SKY-CGDW2jle.js} +1 -1
- package/payload/server/public/assets/{line-D96q2CLD.js → line-pdg5hxC3.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-CqFLtzz8.js → mermaid-parser.core-o3lIIK3Z.js} +1 -1
- package/payload/server/public/assets/{mermaid.core-o9rmBTu-.js → mermaid.core-DLR6Q3rV.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-BM8KKsaM.js → mindmap-definition-QFDTVHPH-CH4cB0Dn.js} +1 -1
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-B66Y-dcU.js → pieDiagram-DEJITSTG-Ba4voL_Y.js} +1 -1
- package/payload/server/public/assets/{public-ClAaV52O.js → public-C8mil9h0.js} +3 -3
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-Bv4mojq8.js → quadrantDiagram-34T5L4WZ-Cqn2xehe.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-BNYdfEKS.js → requirementDiagram-MS252O5E-DLfNx99l.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-Do8BgX92.js → sankeyDiagram-XADWPNL6-uck_V-cb.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-VN57FKth.js → sequenceDiagram-FGHM5R23-DmQalqud.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-CCtRfCg0.js → stateDiagram-FHFEXIEX-DUdWeVRa.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-DNTpFwdy.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-ja01S9Wd.js → timeline-definition-GMOUNBTQ-BgL1wM5n.js} +1 -1
- package/payload/server/public/assets/{useSelectionMode-ejMSaa52.js → useSelectionMode-BLpVlOgm.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-wWbiL1f6.js → vennDiagram-DHZGUBPP-7FHjIqPi.js} +1 -1
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-BZgue-PK.js → wardleyDiagram-NUSXRM2D-BHzo4V1J.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-B_ynYRnW.js → xychartDiagram-5P7HB3ND-DtuWhqwh.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 +6 -6
- package/payload/server/public/public.html +5 -5
- package/payload/server/server.js +309 -280
- package/payload/server/public/assets/AdminShell-CdgotOLV.js +0 -1
- package/payload/server/public/assets/channel-DEl-UCEn.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-BZ9e1dmR.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-B1_4kXdN.js +0 -1
- package/payload/server/public/assets/clone-CNXfxCnl.js +0 -1
- package/payload/server/public/assets/data-DEsRsfI1.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-Cz319KBI.js +0 -1
- /package/payload/server/public/assets/{brand-DKUA91KU.js → brand-CYcGHhlS.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
COMMERCIAL_MODE,
|
|
10
10
|
GREETING_DIRECTIVE,
|
|
11
11
|
Hono,
|
|
12
|
+
INSTALL_OWNER_FILE,
|
|
12
13
|
LOG_DIR,
|
|
13
14
|
MAXY_DIR,
|
|
14
15
|
PLATFORM_ROOT,
|
|
@@ -83,7 +84,7 @@ import {
|
|
|
83
84
|
vncLog,
|
|
84
85
|
walkPremiumBundles,
|
|
85
86
|
writeAdminUserAndPerson
|
|
86
|
-
} from "./chunk-
|
|
87
|
+
} from "./chunk-EXIPYITB.js";
|
|
87
88
|
import {
|
|
88
89
|
__commonJS,
|
|
89
90
|
__toESM
|
|
@@ -815,8 +816,8 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
815
816
|
};
|
|
816
817
|
|
|
817
818
|
// server/index.ts
|
|
818
|
-
import { readFileSync as
|
|
819
|
-
import { resolve as resolve23, join as
|
|
819
|
+
import { readFileSync as readFileSync21, existsSync as existsSync21, watchFile } from "fs";
|
|
820
|
+
import { resolve as resolve23, join as join16, basename as basename6 } from "path";
|
|
820
821
|
import { homedir as homedir2 } from "os";
|
|
821
822
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
822
823
|
|
|
@@ -6325,19 +6326,32 @@ app4.post("/set-pin", async (c) => {
|
|
|
6325
6326
|
}
|
|
6326
6327
|
console.log(`[set-pin] wrote users.json + account.json admins: userId=${userId.slice(0, 8)}\u2026 role=owner`);
|
|
6327
6328
|
if (process.platform === "linux") {
|
|
6328
|
-
|
|
6329
|
-
|
|
6329
|
+
let installOwner = null;
|
|
6330
|
+
if (existsSync6(INSTALL_OWNER_FILE)) {
|
|
6331
|
+
try {
|
|
6332
|
+
const raw = readFileSync8(INSTALL_OWNER_FILE, "utf-8").trim();
|
|
6333
|
+
if (raw.length > 0) installOwner = raw;
|
|
6334
|
+
} catch (err) {
|
|
6335
|
+
console.error(`[set-pin] install-owner-read-failed path=${INSTALL_OWNER_FILE} error=${err instanceof Error ? err.message : String(err)}`);
|
|
6336
|
+
}
|
|
6337
|
+
}
|
|
6338
|
+
if (!installOwner) {
|
|
6339
|
+
console.error(`[set-pin] smbpasswd sync failed owner=<unknown> rc=-1 reason=install-owner-file-missing path=${INSTALL_OWNER_FILE}`);
|
|
6340
|
+
} else {
|
|
6341
|
+
const smbProc = spawnSync2("sudo", ["-n", "smbpasswd", "-a", "-s", installOwner], {
|
|
6342
|
+
input: `${body.pin}
|
|
6330
6343
|
${body.pin}
|
|
6331
6344
|
`,
|
|
6332
|
-
|
|
6333
|
-
|
|
6334
|
-
|
|
6335
|
-
|
|
6336
|
-
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
|
|
6345
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
6346
|
+
encoding: "utf-8",
|
|
6347
|
+
timeout: 1e4
|
|
6348
|
+
});
|
|
6349
|
+
if (smbProc.status === 0) {
|
|
6350
|
+
console.log(`[set-pin] smbpasswd sync ok owner=${installOwner} userId=${userId.slice(0, 8)}\u2026`);
|
|
6351
|
+
} else {
|
|
6352
|
+
const stderr = (smbProc.stderr ?? "").trim().slice(0, 200);
|
|
6353
|
+
console.error(`[set-pin] smbpasswd sync failed owner=${installOwner} rc=${smbProc.status} stderr=${JSON.stringify(stderr)}`);
|
|
6354
|
+
}
|
|
6341
6355
|
}
|
|
6342
6356
|
} else {
|
|
6343
6357
|
console.log(`[set-pin] smb-password-sync-skipped reason=non-linux platform=${process.platform}`);
|
|
@@ -7245,24 +7259,6 @@ function openResumeStreamLog(accountId, sessionId) {
|
|
|
7245
7259
|
}
|
|
7246
7260
|
return createWriteStream(resolvePath(dir, `${sessionId}.log`), { flags: "a" });
|
|
7247
7261
|
}
|
|
7248
|
-
var healPending = /* @__PURE__ */ new Map();
|
|
7249
|
-
function markHealPending(accountId, attachmentId) {
|
|
7250
|
-
let set = healPending.get(accountId);
|
|
7251
|
-
if (!set) {
|
|
7252
|
-
set = /* @__PURE__ */ new Set();
|
|
7253
|
-
healPending.set(accountId, set);
|
|
7254
|
-
}
|
|
7255
|
-
set.add(attachmentId);
|
|
7256
|
-
}
|
|
7257
|
-
function clearHealPending(accountId, attachmentId) {
|
|
7258
|
-
const set = healPending.get(accountId);
|
|
7259
|
-
if (!set) return;
|
|
7260
|
-
set.delete(attachmentId);
|
|
7261
|
-
if (set.size === 0) healPending.delete(accountId);
|
|
7262
|
-
}
|
|
7263
|
-
function isHealPending(accountId, attachmentId) {
|
|
7264
|
-
return healPending.get(accountId)?.has(attachmentId) ?? false;
|
|
7265
|
-
}
|
|
7266
7262
|
function validateAndShapeAttachments(raws, conversationAccountId, sessionId, messageId, streamLogPath) {
|
|
7267
7263
|
const chips = [];
|
|
7268
7264
|
let valid = 0;
|
|
@@ -7640,17 +7636,14 @@ app11.post("/:id/resume", async (c) => {
|
|
|
7640
7636
|
textOffset: c2.textOffset
|
|
7641
7637
|
};
|
|
7642
7638
|
if (!c2.artefactAttachmentId || !c2.artefactMimeType || !c2.artefactTitle) return base;
|
|
7643
|
-
markHealPending(accountId, c2.artefactAttachmentId);
|
|
7644
7639
|
try {
|
|
7645
7640
|
const dataObj = JSON.parse(c2.data);
|
|
7646
7641
|
const bytesPick = pickComponentBytes(dataObj);
|
|
7647
7642
|
if (!bytesPick) {
|
|
7648
|
-
clearHealPending(accountId, c2.artefactAttachmentId);
|
|
7649
7643
|
return base;
|
|
7650
7644
|
}
|
|
7651
7645
|
const filename = bytesPick.mimeType === "text/html" ? `${c2.artefactTitle}.html` : `${c2.artefactTitle}.md`;
|
|
7652
7646
|
await storeComponentArtefact(accountId, c2.artefactAttachmentId, bytesPick.mimeType, bytesPick.content, filename);
|
|
7653
|
-
clearHealPending(accountId, c2.artefactAttachmentId);
|
|
7654
7647
|
streamLogPath.write(
|
|
7655
7648
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] [component-persist] heal componentName=${c2.name} attachmentId=${c2.artefactAttachmentId.slice(0, 8)} mimeType=${bytesPick.mimeType} bytes=${bytesPick.content.length} outcome=ok
|
|
7656
7649
|
`
|
|
@@ -7662,7 +7655,6 @@ app11.post("/:id/resume", async (c) => {
|
|
|
7662
7655
|
artefactTitle: c2.artefactTitle
|
|
7663
7656
|
};
|
|
7664
7657
|
} catch (writeErr) {
|
|
7665
|
-
clearHealPending(accountId, c2.artefactAttachmentId);
|
|
7666
7658
|
const reason2 = writeErr instanceof Error ? writeErr.message : String(writeErr);
|
|
7667
7659
|
streamLogPath.write(
|
|
7668
7660
|
`[${(/* @__PURE__ */ new Date()).toISOString()}] [component-persist] heal componentName=${c2.name} attachmentId=${c2.artefactAttachmentId.slice(0, 8)} outcome=disk-fail reason=${JSON.stringify(reason2.slice(0, 200))}
|
|
@@ -11733,11 +11725,9 @@ function isWithin(target, root) {
|
|
|
11733
11725
|
var sidebar_artefacts_default = app22;
|
|
11734
11726
|
|
|
11735
11727
|
// server/routes/admin/sidebar-artefact-save.ts
|
|
11736
|
-
import { mkdir as mkdir4,
|
|
11728
|
+
import { mkdir as mkdir4, stat as stat6, writeFile as writeFile5 } from "fs/promises";
|
|
11737
11729
|
import { resolve as resolve16 } from "path";
|
|
11738
|
-
import { existsSync as existsSync17 } from "fs";
|
|
11739
11730
|
var ADMIN_AGENT_FILES2 = /* @__PURE__ */ new Set(["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"]);
|
|
11740
|
-
var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
11741
11731
|
var app23 = new Hono();
|
|
11742
11732
|
app23.post("/", requireAdminSession, async (c) => {
|
|
11743
11733
|
const cacheKey = c.var.cacheKey;
|
|
@@ -11748,11 +11738,7 @@ app23.post("/", requireAdminSession, async (c) => {
|
|
|
11748
11738
|
return c.json({ error: "id and content required" }, 400);
|
|
11749
11739
|
}
|
|
11750
11740
|
const accountDir = resolve16(ACCOUNTS_DIR, accountId);
|
|
11751
|
-
const resolved = await resolveSavePath(body.id,
|
|
11752
|
-
if (resolved.kind === "heal-race") {
|
|
11753
|
-
c.header("Retry-After", "2");
|
|
11754
|
-
return c.json({ error: "heal-race", reason: resolved.reason }, 503);
|
|
11755
|
-
}
|
|
11741
|
+
const resolved = await resolveSavePath(body.id, accountDir);
|
|
11756
11742
|
if (resolved.kind === "reject") {
|
|
11757
11743
|
console.error(
|
|
11758
11744
|
`[admin/sidebar-artefact-save] auth-rejected reason=${resolved.reason} path=${body.id}`
|
|
@@ -11781,77 +11767,119 @@ app23.post("/", requireAdminSession, async (c) => {
|
|
|
11781
11767
|
);
|
|
11782
11768
|
return c.json({ updatedAt });
|
|
11783
11769
|
});
|
|
11784
|
-
async function resolveSavePath(id,
|
|
11785
|
-
if (id.startsWith("agent-template:")) {
|
|
11786
|
-
|
|
11787
|
-
|
|
11788
|
-
|
|
11789
|
-
|
|
11790
|
-
|
|
11791
|
-
|
|
11792
|
-
|
|
11793
|
-
|
|
11794
|
-
|
|
11795
|
-
|
|
11796
|
-
|
|
11770
|
+
async function resolveSavePath(id, accountDir) {
|
|
11771
|
+
if (!id.startsWith("agent-template:")) {
|
|
11772
|
+
return { kind: "reject", status: 400, reason: "invalid-id" };
|
|
11773
|
+
}
|
|
11774
|
+
const parts = id.split(":");
|
|
11775
|
+
if (parts.length !== 3) return { kind: "reject", status: 400, reason: "invalid-id" };
|
|
11776
|
+
const [, role, filename] = parts;
|
|
11777
|
+
if (role === "specialist") {
|
|
11778
|
+
return { kind: "reject", status: 403, reason: "specialist-write-blocked" };
|
|
11779
|
+
}
|
|
11780
|
+
if (role !== "admin" || !ADMIN_AGENT_FILES2.has(filename)) {
|
|
11781
|
+
return { kind: "reject", status: 400, reason: "invalid-id" };
|
|
11782
|
+
}
|
|
11783
|
+
const parent = resolve16(accountDir, "agents", "admin");
|
|
11784
|
+
await mkdir4(parent, { recursive: true });
|
|
11785
|
+
try {
|
|
11786
|
+
validateFilePathInAccount(parent, accountDir);
|
|
11787
|
+
} catch {
|
|
11788
|
+
return { kind: "reject", status: 400, reason: "containment-rejected" };
|
|
11789
|
+
}
|
|
11790
|
+
return { kind: "admin-template", path: resolve16(parent, filename) };
|
|
11791
|
+
}
|
|
11792
|
+
function relPath(absPath, root) {
|
|
11793
|
+
return absPath.startsWith(root) ? absPath.slice(root.length + 1) : absPath;
|
|
11794
|
+
}
|
|
11795
|
+
var sidebar_artefact_save_default = app23;
|
|
11796
|
+
|
|
11797
|
+
// server/routes/admin/sidebar-sessions.ts
|
|
11798
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync14, statSync as statSync7 } from "fs";
|
|
11799
|
+
import { join as join13 } from "path";
|
|
11800
|
+
var RC_URL_RE = /https:\/\/claude\.ai\/code\/session_[A-Za-z0-9_-]+/;
|
|
11801
|
+
var SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.jsonl$/i;
|
|
11802
|
+
var TITLE_MAX = 80;
|
|
11803
|
+
var app24 = new Hono();
|
|
11804
|
+
function projectsDirForAccount(accountId) {
|
|
11805
|
+
const configDir2 = process.env.CLAUDE_CONFIG_DIR;
|
|
11806
|
+
if (!configDir2) return null;
|
|
11807
|
+
const accountCwd = join13(DATA_ROOT, "accounts", accountId);
|
|
11808
|
+
const slug = accountCwd.replace(/\//g, "-");
|
|
11809
|
+
return join13(configDir2, "projects", slug);
|
|
11810
|
+
}
|
|
11811
|
+
function firstUserMessage(body) {
|
|
11812
|
+
for (const line of body.split("\n")) {
|
|
11813
|
+
if (!line || line[0] !== "{") continue;
|
|
11814
|
+
let parsed;
|
|
11797
11815
|
try {
|
|
11798
|
-
|
|
11816
|
+
parsed = JSON.parse(line);
|
|
11799
11817
|
} catch {
|
|
11800
|
-
|
|
11818
|
+
continue;
|
|
11801
11819
|
}
|
|
11802
|
-
|
|
11820
|
+
if (!parsed || typeof parsed !== "object") continue;
|
|
11821
|
+
const row = parsed;
|
|
11822
|
+
if (row.type !== "user" || !row.message || row.message.role !== "user") continue;
|
|
11823
|
+
const content = row.message.content;
|
|
11824
|
+
if (typeof content !== "string") continue;
|
|
11825
|
+
const trimmed = content.trim().replace(/\s+/g, " ");
|
|
11826
|
+
if (!trimmed) continue;
|
|
11827
|
+
return trimmed.length > TITLE_MAX ? trimmed.slice(0, TITLE_MAX - 1) + "\u2026" : trimmed;
|
|
11803
11828
|
}
|
|
11804
|
-
|
|
11805
|
-
|
|
11806
|
-
|
|
11807
|
-
|
|
11808
|
-
|
|
11809
|
-
|
|
11810
|
-
|
|
11811
|
-
|
|
11812
|
-
|
|
11813
|
-
|
|
11814
|
-
|
|
11815
|
-
|
|
11816
|
-
|
|
11817
|
-
|
|
11818
|
-
|
|
11819
|
-
|
|
11820
|
-
|
|
11821
|
-
|
|
11822
|
-
|
|
11823
|
-
|
|
11824
|
-
|
|
11825
|
-
return { kind: "reject", status: 400, reason: "not-found" };
|
|
11826
|
-
} catch (neoErr) {
|
|
11827
|
-
const reason = neoErr instanceof Error ? neoErr.message.slice(0, 120) : String(neoErr).slice(0, 120);
|
|
11828
|
-
console.error(`[admin/sidebar-artefact-save] heal-race attachmentId=${attShort} outcome=neo4j-fail reason="${reason}"`);
|
|
11829
|
-
return { kind: "heal-race", reason: "neo4j-fail" };
|
|
11830
|
-
} finally {
|
|
11831
|
-
try {
|
|
11832
|
-
await session.close();
|
|
11833
|
-
} catch {
|
|
11834
|
-
}
|
|
11835
|
-
}
|
|
11829
|
+
return null;
|
|
11830
|
+
}
|
|
11831
|
+
app24.get("/", requireAdminSession, async (c) => {
|
|
11832
|
+
const cacheKey = c.var.cacheKey;
|
|
11833
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
11834
|
+
if (!accountId) {
|
|
11835
|
+
return c.json({ error: "Account not found for session" }, 401);
|
|
11836
|
+
}
|
|
11837
|
+
const projectsDir = projectsDirForAccount(accountId);
|
|
11838
|
+
if (!projectsDir) {
|
|
11839
|
+
console.error(`[admin-sessions-list] account=${accountId} no-claude-config-dir`);
|
|
11840
|
+
return c.json({ sessions: [] });
|
|
11841
|
+
}
|
|
11842
|
+
let entries;
|
|
11843
|
+
try {
|
|
11844
|
+
entries = readdirSync8(projectsDir);
|
|
11845
|
+
} catch (err) {
|
|
11846
|
+
const code = err.code;
|
|
11847
|
+
if (code === "ENOENT") {
|
|
11848
|
+
console.log(`[admin-sessions-list] account=${accountId} rows=0 reason=no-projects-dir`);
|
|
11849
|
+
return c.json({ sessions: [] });
|
|
11836
11850
|
}
|
|
11851
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
11852
|
+
console.error(`[admin-sessions-list] account=${accountId} readdir-failed error="${message}"`);
|
|
11853
|
+
return c.json({ error: "projects-dir-unreadable" }, 500);
|
|
11854
|
+
}
|
|
11855
|
+
const rows = [];
|
|
11856
|
+
for (const name of entries) {
|
|
11857
|
+
if (!SESSION_ID_RE.test(name)) continue;
|
|
11858
|
+
const sessionId = name.slice(0, -".jsonl".length);
|
|
11859
|
+
const path2 = join13(projectsDir, name);
|
|
11860
|
+
let body;
|
|
11861
|
+
let mtimeMs;
|
|
11837
11862
|
try {
|
|
11838
|
-
|
|
11863
|
+
body = readFileSync14(path2, "utf8");
|
|
11864
|
+
mtimeMs = statSync7(path2).mtimeMs;
|
|
11839
11865
|
} catch {
|
|
11840
|
-
|
|
11841
|
-
}
|
|
11842
|
-
const entries = await readdir5(dir);
|
|
11843
|
-
const dataFile = entries.find((f) => !f.endsWith(".meta.json"));
|
|
11844
|
-
if (!dataFile) {
|
|
11845
|
-
return { kind: "reject", status: 400, reason: "not-found" };
|
|
11866
|
+
continue;
|
|
11846
11867
|
}
|
|
11847
|
-
|
|
11868
|
+
const urlMatch = body.match(RC_URL_RE);
|
|
11869
|
+
if (!urlMatch) continue;
|
|
11870
|
+
const title = firstUserMessage(body) ?? sessionId.slice(0, 8);
|
|
11871
|
+
rows.push({
|
|
11872
|
+
sessionId,
|
|
11873
|
+
title,
|
|
11874
|
+
url: urlMatch[0],
|
|
11875
|
+
capturedAt: new Date(mtimeMs).toISOString()
|
|
11876
|
+
});
|
|
11848
11877
|
}
|
|
11849
|
-
|
|
11850
|
-
}
|
|
11851
|
-
|
|
11852
|
-
|
|
11853
|
-
|
|
11854
|
-
var sidebar_artefact_save_default = app23;
|
|
11878
|
+
rows.sort((a, b) => a.capturedAt < b.capturedAt ? 1 : -1);
|
|
11879
|
+
console.log(`[admin-sessions-list] account=${accountId} rows=${rows.length}`);
|
|
11880
|
+
return c.json({ sessions: rows });
|
|
11881
|
+
});
|
|
11882
|
+
var sidebar_sessions_default = app24;
|
|
11855
11883
|
|
|
11856
11884
|
// server/routes/admin/system-stats.ts
|
|
11857
11885
|
import { readFile as readFile5 } from "fs/promises";
|
|
@@ -11948,8 +11976,8 @@ async function sample() {
|
|
|
11948
11976
|
if (process.platform === "linux") return sampleLinux();
|
|
11949
11977
|
return sampleOsFallback();
|
|
11950
11978
|
}
|
|
11951
|
-
var
|
|
11952
|
-
|
|
11979
|
+
var app25 = new Hono();
|
|
11980
|
+
app25.get("/", async (c) => {
|
|
11953
11981
|
const started = Date.now();
|
|
11954
11982
|
if (!inflight) {
|
|
11955
11983
|
inflight = sample().finally(() => {
|
|
@@ -11972,17 +12000,17 @@ app24.get("/", async (c) => {
|
|
|
11972
12000
|
return c.json({ degraded: true, reason, sampledAtMs: Date.now() });
|
|
11973
12001
|
}
|
|
11974
12002
|
});
|
|
11975
|
-
var system_stats_default =
|
|
12003
|
+
var system_stats_default = app25;
|
|
11976
12004
|
|
|
11977
12005
|
// server/routes/admin/health.ts
|
|
11978
|
-
import { existsSync as
|
|
11979
|
-
import { resolve as resolve17, join as
|
|
12006
|
+
import { existsSync as existsSync17, readFileSync as readFileSync15 } from "fs";
|
|
12007
|
+
import { resolve as resolve17, join as join14 } from "path";
|
|
11980
12008
|
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve17(process.cwd(), "..");
|
|
11981
12009
|
var brandHostname = "maxy";
|
|
11982
|
-
var brandJsonPath =
|
|
11983
|
-
if (
|
|
12010
|
+
var brandJsonPath = join14(PLATFORM_ROOT6, "config", "brand.json");
|
|
12011
|
+
if (existsSync17(brandJsonPath)) {
|
|
11984
12012
|
try {
|
|
11985
|
-
const brand = JSON.parse(
|
|
12013
|
+
const brand = JSON.parse(readFileSync15(brandJsonPath, "utf-8"));
|
|
11986
12014
|
if (brand.hostname) brandHostname = brand.hostname;
|
|
11987
12015
|
} catch {
|
|
11988
12016
|
}
|
|
@@ -11991,8 +12019,8 @@ var VERSION_FILE = resolve17(PLATFORM_ROOT6, `config/.${brandHostname}-version`)
|
|
|
11991
12019
|
var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
11992
12020
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
11993
12021
|
function readVersion() {
|
|
11994
|
-
if (!
|
|
11995
|
-
return
|
|
12022
|
+
if (!existsSync17(VERSION_FILE)) return "unknown";
|
|
12023
|
+
return readFileSync15(VERSION_FILE, "utf-8").trim() || "unknown";
|
|
11996
12024
|
}
|
|
11997
12025
|
async function probeConversationDb() {
|
|
11998
12026
|
let session;
|
|
@@ -12017,8 +12045,8 @@ async function probeConversationDb() {
|
|
|
12017
12045
|
});
|
|
12018
12046
|
}
|
|
12019
12047
|
}
|
|
12020
|
-
var
|
|
12021
|
-
|
|
12048
|
+
var app26 = new Hono();
|
|
12049
|
+
app26.get("/", async (c) => {
|
|
12022
12050
|
const version = readVersion();
|
|
12023
12051
|
const probe = await probeConversationDb();
|
|
12024
12052
|
const uptimeMs = Date.now() - new Date(PROCESS_STARTED_AT).getTime();
|
|
@@ -12040,7 +12068,7 @@ app25.get("/", async (c) => {
|
|
|
12040
12068
|
uptimeMs
|
|
12041
12069
|
});
|
|
12042
12070
|
});
|
|
12043
|
-
var health_default2 =
|
|
12071
|
+
var health_default2 = app26;
|
|
12044
12072
|
|
|
12045
12073
|
// server/routes/admin/linkedin-ingest.ts
|
|
12046
12074
|
var TAG20 = "[linkedin-ingest-route]";
|
|
@@ -12136,8 +12164,8 @@ function buildInitialMessage(env) {
|
|
|
12136
12164
|
}
|
|
12137
12165
|
return header;
|
|
12138
12166
|
}
|
|
12139
|
-
var
|
|
12140
|
-
|
|
12167
|
+
var app27 = new Hono();
|
|
12168
|
+
app27.post("/", requireAdminSession, async (c) => {
|
|
12141
12169
|
let body;
|
|
12142
12170
|
try {
|
|
12143
12171
|
body = await c.req.json();
|
|
@@ -12191,7 +12219,7 @@ app26.post("/", requireAdminSession, async (c) => {
|
|
|
12191
12219
|
);
|
|
12192
12220
|
return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: claudeSessionId }, 202);
|
|
12193
12221
|
});
|
|
12194
|
-
var linkedin_ingest_default =
|
|
12222
|
+
var linkedin_ingest_default = app27;
|
|
12195
12223
|
|
|
12196
12224
|
// server/routes/admin/post-turn-context.ts
|
|
12197
12225
|
import neo4j2 from "neo4j-driver";
|
|
@@ -12233,8 +12261,8 @@ function pruneProperties(raw) {
|
|
|
12233
12261
|
}
|
|
12234
12262
|
return out;
|
|
12235
12263
|
}
|
|
12236
|
-
var
|
|
12237
|
-
|
|
12264
|
+
var app28 = new Hono();
|
|
12265
|
+
app28.get("/", async (c) => {
|
|
12238
12266
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
12239
12267
|
if (!isLoopbackAddr2(remoteAddr)) {
|
|
12240
12268
|
console.error(`${TAG21} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -12294,7 +12322,7 @@ app27.get("/", async (c) => {
|
|
|
12294
12322
|
await session.close();
|
|
12295
12323
|
}
|
|
12296
12324
|
});
|
|
12297
|
-
var post_turn_context_default =
|
|
12325
|
+
var post_turn_context_default = app28;
|
|
12298
12326
|
|
|
12299
12327
|
// server/routes/admin/public-session-context.ts
|
|
12300
12328
|
import neo4j3 from "neo4j-driver";
|
|
@@ -12336,8 +12364,8 @@ function pruneProperties2(raw) {
|
|
|
12336
12364
|
}
|
|
12337
12365
|
return out;
|
|
12338
12366
|
}
|
|
12339
|
-
var
|
|
12340
|
-
|
|
12367
|
+
var app29 = new Hono();
|
|
12368
|
+
app29.get("/", async (c) => {
|
|
12341
12369
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
12342
12370
|
if (!isLoopbackAddr3(remoteAddr)) {
|
|
12343
12371
|
console.error(`${TAG22} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -12396,15 +12424,15 @@ app28.get("/", async (c) => {
|
|
|
12396
12424
|
await session.close();
|
|
12397
12425
|
}
|
|
12398
12426
|
});
|
|
12399
|
-
var public_session_context_default =
|
|
12427
|
+
var public_session_context_default = app29;
|
|
12400
12428
|
|
|
12401
12429
|
// server/routes/admin/public-session-exit.ts
|
|
12402
12430
|
var TAG23 = "[public-session-exit-route]";
|
|
12403
12431
|
function isLoopbackAddr4(addr) {
|
|
12404
12432
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
12405
12433
|
}
|
|
12406
|
-
var
|
|
12407
|
-
|
|
12434
|
+
var app30 = new Hono();
|
|
12435
|
+
app30.post("/", async (c) => {
|
|
12408
12436
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
12409
12437
|
if (!isLoopbackAddr4(remoteAddr)) {
|
|
12410
12438
|
console.error(`${TAG23} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -12431,15 +12459,15 @@ app29.post("/", async (c) => {
|
|
|
12431
12459
|
handlePublicSessionExit(sessionId);
|
|
12432
12460
|
return c.json({ ok: true });
|
|
12433
12461
|
});
|
|
12434
|
-
var public_session_exit_default =
|
|
12462
|
+
var public_session_exit_default = app30;
|
|
12435
12463
|
|
|
12436
12464
|
// server/routes/admin/access-session-evict.ts
|
|
12437
12465
|
var TAG24 = "[access-session-evict]";
|
|
12438
12466
|
function isLoopbackAddr5(addr) {
|
|
12439
12467
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
12440
12468
|
}
|
|
12441
|
-
var
|
|
12442
|
-
|
|
12469
|
+
var app31 = new Hono();
|
|
12470
|
+
app31.post("/", async (c) => {
|
|
12443
12471
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
12444
12472
|
if (!isLoopbackAddr5(remoteAddr)) {
|
|
12445
12473
|
console.error(`${TAG24} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -12467,40 +12495,41 @@ app30.post("/", async (c) => {
|
|
|
12467
12495
|
console.log(`${TAG24} grantId=${grantId} dropped=${dropped}`);
|
|
12468
12496
|
return c.json({ ok: true, dropped });
|
|
12469
12497
|
});
|
|
12470
|
-
var access_session_evict_default =
|
|
12498
|
+
var access_session_evict_default = app31;
|
|
12471
12499
|
|
|
12472
12500
|
// server/routes/admin/index.ts
|
|
12473
|
-
var
|
|
12474
|
-
|
|
12475
|
-
|
|
12476
|
-
|
|
12477
|
-
|
|
12478
|
-
|
|
12479
|
-
|
|
12480
|
-
|
|
12481
|
-
|
|
12482
|
-
|
|
12483
|
-
|
|
12484
|
-
|
|
12485
|
-
|
|
12486
|
-
|
|
12487
|
-
|
|
12488
|
-
|
|
12489
|
-
|
|
12490
|
-
|
|
12491
|
-
|
|
12492
|
-
|
|
12493
|
-
|
|
12494
|
-
|
|
12495
|
-
|
|
12496
|
-
|
|
12497
|
-
|
|
12498
|
-
|
|
12499
|
-
|
|
12501
|
+
var app32 = new Hono();
|
|
12502
|
+
app32.route("/session", session_default);
|
|
12503
|
+
app32.route("/logs", logs_default);
|
|
12504
|
+
app32.route("/claude-info", claude_info_default);
|
|
12505
|
+
app32.route("/attachment", attachment_default);
|
|
12506
|
+
app32.route("/agents", agents_default);
|
|
12507
|
+
app32.route("/sessions", sessions_default);
|
|
12508
|
+
app32.route("/claude-sessions", claude_sessions_default);
|
|
12509
|
+
app32.route("/log-ingest", log_ingest_default);
|
|
12510
|
+
app32.route("/events", events_default);
|
|
12511
|
+
app32.route("/files", files_default);
|
|
12512
|
+
app32.route("/graph-search", graph_search_default);
|
|
12513
|
+
app32.route("/graph-subgraph", graph_subgraph_default);
|
|
12514
|
+
app32.route("/graph-delete", graph_delete_default);
|
|
12515
|
+
app32.route("/graph-restore", graph_restore_default);
|
|
12516
|
+
app32.route("/graph-labels-in-graph", graph_labels_in_graph_default);
|
|
12517
|
+
app32.route("/graph-default-view", graph_default_view_default);
|
|
12518
|
+
app32.route("/sidebar-artefacts", sidebar_artefacts_default);
|
|
12519
|
+
app32.route("/sidebar-artefact-save", sidebar_artefact_save_default);
|
|
12520
|
+
app32.route("/sidebar-sessions", sidebar_sessions_default);
|
|
12521
|
+
app32.route("/system-stats", system_stats_default);
|
|
12522
|
+
app32.route("/health-brand", health_default2);
|
|
12523
|
+
app32.route("/linkedin-ingest", linkedin_ingest_default);
|
|
12524
|
+
app32.route("/post-turn-context", post_turn_context_default);
|
|
12525
|
+
app32.route("/public-session-context", public_session_context_default);
|
|
12526
|
+
app32.route("/public-session-exit", public_session_exit_default);
|
|
12527
|
+
app32.route("/access-session-evict", access_session_evict_default);
|
|
12528
|
+
var admin_default = app32;
|
|
12500
12529
|
|
|
12501
12530
|
// app/lib/access-gate.ts
|
|
12502
12531
|
import neo4j4 from "neo4j-driver";
|
|
12503
|
-
import { readFileSync as
|
|
12532
|
+
import { readFileSync as readFileSync16 } from "fs";
|
|
12504
12533
|
import { resolve as resolve18 } from "path";
|
|
12505
12534
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
12506
12535
|
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve18(process.cwd(), "..");
|
|
@@ -12509,7 +12538,7 @@ function readPassword() {
|
|
|
12509
12538
|
if (process.env.NEO4J_PASSWORD) return process.env.NEO4J_PASSWORD;
|
|
12510
12539
|
const passwordFile = resolve18(PLATFORM_ROOT7, "config/.neo4j-password");
|
|
12511
12540
|
try {
|
|
12512
|
-
return
|
|
12541
|
+
return readFileSync16(passwordFile, "utf-8").trim();
|
|
12513
12542
|
} catch {
|
|
12514
12543
|
throw new Error(
|
|
12515
12544
|
`Neo4j password not found. Expected at ${passwordFile} or in NEO4J_PASSWORD env var.`
|
|
@@ -12710,8 +12739,8 @@ async function generateNewMagicToken(grantId) {
|
|
|
12710
12739
|
var TAG25 = "[access-verify]";
|
|
12711
12740
|
var MINT_TAG = "[access-session-mint]";
|
|
12712
12741
|
var COOKIE_NAME = "__access_session";
|
|
12713
|
-
var
|
|
12714
|
-
|
|
12742
|
+
var app33 = new Hono();
|
|
12743
|
+
app33.post("/", async (c) => {
|
|
12715
12744
|
const ip = c.var.clientIp || "unknown";
|
|
12716
12745
|
let body;
|
|
12717
12746
|
try {
|
|
@@ -12793,7 +12822,7 @@ app32.post("/", async (c) => {
|
|
|
12793
12822
|
displayName: grant.displayName
|
|
12794
12823
|
});
|
|
12795
12824
|
});
|
|
12796
|
-
var verify_token_default =
|
|
12825
|
+
var verify_token_default = app33;
|
|
12797
12826
|
|
|
12798
12827
|
// app/lib/access-email.ts
|
|
12799
12828
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -12856,9 +12885,9 @@ async function sendMagicLinkEmail(payload) {
|
|
|
12856
12885
|
|
|
12857
12886
|
// server/routes/access/request-magic-link.ts
|
|
12858
12887
|
var TAG26 = "[access-request-link]";
|
|
12859
|
-
var
|
|
12888
|
+
var app34 = new Hono();
|
|
12860
12889
|
var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
|
|
12861
|
-
|
|
12890
|
+
app34.post("/", async (c) => {
|
|
12862
12891
|
let body;
|
|
12863
12892
|
try {
|
|
12864
12893
|
body = await c.req.json();
|
|
@@ -12932,16 +12961,16 @@ app33.post("/", async (c) => {
|
|
|
12932
12961
|
);
|
|
12933
12962
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
12934
12963
|
});
|
|
12935
|
-
var request_magic_link_default =
|
|
12964
|
+
var request_magic_link_default = app34;
|
|
12936
12965
|
|
|
12937
12966
|
// server/routes/access/index.ts
|
|
12938
|
-
var
|
|
12939
|
-
|
|
12940
|
-
|
|
12941
|
-
var access_default =
|
|
12967
|
+
var app35 = new Hono();
|
|
12968
|
+
app35.route("/verify-token", verify_token_default);
|
|
12969
|
+
app35.route("/request-magic-link", request_magic_link_default);
|
|
12970
|
+
var access_default = app35;
|
|
12942
12971
|
|
|
12943
12972
|
// server/routes/sites.ts
|
|
12944
|
-
import { existsSync as
|
|
12973
|
+
import { existsSync as existsSync18, readFileSync as readFileSync17, realpathSync as realpathSync5, statSync as statSync8 } from "fs";
|
|
12945
12974
|
import { resolve as resolve20 } from "path";
|
|
12946
12975
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
12947
12976
|
var MIME = {
|
|
@@ -12973,8 +13002,8 @@ function getExt(p) {
|
|
|
12973
13002
|
if (idx < p.lastIndexOf("/")) return "";
|
|
12974
13003
|
return p.slice(idx).toLowerCase();
|
|
12975
13004
|
}
|
|
12976
|
-
var
|
|
12977
|
-
|
|
13005
|
+
var app36 = new Hono();
|
|
13006
|
+
app36.get("/:rel{.*}", (c) => {
|
|
12978
13007
|
const reqPath = c.req.path;
|
|
12979
13008
|
const rawRel = c.req.param("rel") ?? "";
|
|
12980
13009
|
const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
@@ -13007,7 +13036,7 @@ app35.get("/:rel{.*}", (c) => {
|
|
|
13007
13036
|
}
|
|
13008
13037
|
let stat8;
|
|
13009
13038
|
try {
|
|
13010
|
-
stat8 =
|
|
13039
|
+
stat8 = existsSync18(filePath) ? statSync8(filePath) : null;
|
|
13011
13040
|
} catch {
|
|
13012
13041
|
stat8 = null;
|
|
13013
13042
|
}
|
|
@@ -13026,7 +13055,7 @@ app35.get("/:rel{.*}", (c) => {
|
|
|
13026
13055
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
13027
13056
|
return c.text("Forbidden", 403);
|
|
13028
13057
|
}
|
|
13029
|
-
if (!
|
|
13058
|
+
if (!existsSync18(filePath)) {
|
|
13030
13059
|
console.error(`[sites] not-found path=${reqPath} status=404`);
|
|
13031
13060
|
return c.text("Not found", 404);
|
|
13032
13061
|
}
|
|
@@ -13045,7 +13074,7 @@ app35.get("/:rel{.*}", (c) => {
|
|
|
13045
13074
|
}
|
|
13046
13075
|
let body;
|
|
13047
13076
|
try {
|
|
13048
|
-
body =
|
|
13077
|
+
body = readFileSync17(realPath);
|
|
13049
13078
|
} catch (err) {
|
|
13050
13079
|
const code = err?.code;
|
|
13051
13080
|
if (code === "EISDIR") {
|
|
@@ -13077,11 +13106,11 @@ app35.get("/:rel{.*}", (c) => {
|
|
|
13077
13106
|
"X-Content-Type-Options": "nosniff"
|
|
13078
13107
|
});
|
|
13079
13108
|
});
|
|
13080
|
-
var sites_default =
|
|
13109
|
+
var sites_default = app36;
|
|
13081
13110
|
|
|
13082
13111
|
// app/lib/visitor-token.ts
|
|
13083
13112
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
13084
|
-
import { mkdirSync as mkdirSync4, readFileSync as
|
|
13113
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync18, writeFileSync as writeFileSync6 } from "fs";
|
|
13085
13114
|
import { dirname as dirname4 } from "path";
|
|
13086
13115
|
var TOKEN_PREFIX = "v1.";
|
|
13087
13116
|
var SECRET_BYTES = 32;
|
|
@@ -13090,7 +13119,7 @@ var cachedSecret = null;
|
|
|
13090
13119
|
function getSecret() {
|
|
13091
13120
|
if (cachedSecret) return cachedSecret;
|
|
13092
13121
|
try {
|
|
13093
|
-
const hex2 =
|
|
13122
|
+
const hex2 = readFileSync18(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
13094
13123
|
if (hex2.length === SECRET_BYTES * 2) {
|
|
13095
13124
|
cachedSecret = Buffer.from(hex2, "hex");
|
|
13096
13125
|
return cachedSecret;
|
|
@@ -13104,7 +13133,7 @@ function getSecret() {
|
|
|
13104
13133
|
console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
|
|
13105
13134
|
} catch {
|
|
13106
13135
|
}
|
|
13107
|
-
const hex =
|
|
13136
|
+
const hex = readFileSync18(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
13108
13137
|
cachedSecret = Buffer.from(hex, "hex");
|
|
13109
13138
|
return cachedSecret;
|
|
13110
13139
|
}
|
|
@@ -13157,8 +13186,8 @@ var VISITOR_COOKIE_NAME = "mxy_v";
|
|
|
13157
13186
|
var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
13158
13187
|
|
|
13159
13188
|
// app/lib/brand-config.ts
|
|
13160
|
-
import { existsSync as
|
|
13161
|
-
import { join as
|
|
13189
|
+
import { existsSync as existsSync19, readFileSync as readFileSync19 } from "fs";
|
|
13190
|
+
import { join as join15 } from "path";
|
|
13162
13191
|
var cached2 = null;
|
|
13163
13192
|
var cachedAttempted = false;
|
|
13164
13193
|
function readBrandConfig() {
|
|
@@ -13166,10 +13195,10 @@ function readBrandConfig() {
|
|
|
13166
13195
|
cachedAttempted = true;
|
|
13167
13196
|
const platformRoot = process.env.MAXY_PLATFORM_ROOT;
|
|
13168
13197
|
if (!platformRoot) return null;
|
|
13169
|
-
const brandPath =
|
|
13170
|
-
if (!
|
|
13198
|
+
const brandPath = join15(platformRoot, "config", "brand.json");
|
|
13199
|
+
if (!existsSync19(brandPath)) return null;
|
|
13171
13200
|
try {
|
|
13172
|
-
cached2 = JSON.parse(
|
|
13201
|
+
cached2 = JSON.parse(readFileSync19(brandPath, "utf-8"));
|
|
13173
13202
|
return cached2;
|
|
13174
13203
|
} catch {
|
|
13175
13204
|
return null;
|
|
@@ -13177,7 +13206,7 @@ function readBrandConfig() {
|
|
|
13177
13206
|
}
|
|
13178
13207
|
|
|
13179
13208
|
// server/routes/visitor-consent.ts
|
|
13180
|
-
var
|
|
13209
|
+
var app37 = new Hono();
|
|
13181
13210
|
var CONSENT_COOKIE_NAME = "mxy_consent";
|
|
13182
13211
|
var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
|
|
13183
13212
|
var DEFAULT_CONSENT_COPY = {
|
|
@@ -13222,17 +13251,17 @@ function siteSlugFromReferer(referer) {
|
|
|
13222
13251
|
return "";
|
|
13223
13252
|
}
|
|
13224
13253
|
}
|
|
13225
|
-
|
|
13254
|
+
app37.options("/consent", (c) => {
|
|
13226
13255
|
const origin = getOrigin(c);
|
|
13227
13256
|
setCorsHeaders(c, origin);
|
|
13228
13257
|
return c.body(null, 204);
|
|
13229
13258
|
});
|
|
13230
|
-
|
|
13259
|
+
app37.options("/brand-config", (c) => {
|
|
13231
13260
|
const origin = getOrigin(c);
|
|
13232
13261
|
setCorsHeaders(c, origin);
|
|
13233
13262
|
return c.body(null, 204);
|
|
13234
13263
|
});
|
|
13235
|
-
|
|
13264
|
+
app37.post("/consent", async (c) => {
|
|
13236
13265
|
const origin = getOrigin(c);
|
|
13237
13266
|
setCorsHeaders(c, origin);
|
|
13238
13267
|
let raw;
|
|
@@ -13272,7 +13301,7 @@ app36.post("/consent", async (c) => {
|
|
|
13272
13301
|
console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
|
|
13273
13302
|
return c.body(null, 204);
|
|
13274
13303
|
});
|
|
13275
|
-
|
|
13304
|
+
app37.get("/brand-config", (c) => {
|
|
13276
13305
|
const origin = getOrigin(c);
|
|
13277
13306
|
setCorsHeaders(c, origin);
|
|
13278
13307
|
const brand = readBrandConfig();
|
|
@@ -13282,7 +13311,7 @@ app36.get("/brand-config", (c) => {
|
|
|
13282
13311
|
c.header("Cache-Control", "public, max-age=300");
|
|
13283
13312
|
return c.json({ consent: { copy, palette } });
|
|
13284
13313
|
});
|
|
13285
|
-
var visitor_consent_default =
|
|
13314
|
+
var visitor_consent_default = app37;
|
|
13286
13315
|
|
|
13287
13316
|
// server/routes/listings.ts
|
|
13288
13317
|
function getCookie(headerValue, name) {
|
|
@@ -13309,8 +13338,8 @@ function appendConsentParams(pageUrl, token) {
|
|
|
13309
13338
|
}
|
|
13310
13339
|
var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
|
|
13311
13340
|
var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
13312
|
-
var
|
|
13313
|
-
|
|
13341
|
+
var app38 = new Hono();
|
|
13342
|
+
app38.get("/:slug/click", async (c) => {
|
|
13314
13343
|
const slug = c.req.param("slug") ?? "";
|
|
13315
13344
|
const rawSession = c.req.query("session") ?? "";
|
|
13316
13345
|
const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
|
|
@@ -13374,10 +13403,10 @@ app37.get("/:slug/click", async (c) => {
|
|
|
13374
13403
|
console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
13375
13404
|
return c.redirect(redirectUrl, 302);
|
|
13376
13405
|
});
|
|
13377
|
-
var listings_default =
|
|
13406
|
+
var listings_default = app38;
|
|
13378
13407
|
|
|
13379
13408
|
// server/routes/visitor-event.ts
|
|
13380
|
-
var
|
|
13409
|
+
var app39 = new Hono();
|
|
13381
13410
|
var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
|
|
13382
13411
|
var buckets = /* @__PURE__ */ new Map();
|
|
13383
13412
|
var RATE_LIMIT = 60;
|
|
@@ -13444,12 +13473,12 @@ function originAllowed(origin, allowlist) {
|
|
|
13444
13473
|
return false;
|
|
13445
13474
|
}
|
|
13446
13475
|
}
|
|
13447
|
-
|
|
13476
|
+
app39.options("/event", (c) => {
|
|
13448
13477
|
const origin = getOrigin2(c);
|
|
13449
13478
|
setCorsHeaders2(c, origin);
|
|
13450
13479
|
return c.body(null, 204);
|
|
13451
13480
|
});
|
|
13452
|
-
|
|
13481
|
+
app39.post("/event", async (c) => {
|
|
13453
13482
|
const origin = getOrigin2(c);
|
|
13454
13483
|
setCorsHeaders2(c, origin);
|
|
13455
13484
|
const ua = c.req.header("user-agent") ?? "";
|
|
@@ -13654,7 +13683,7 @@ async function writeEvent(opts) {
|
|
|
13654
13683
|
);
|
|
13655
13684
|
}
|
|
13656
13685
|
}
|
|
13657
|
-
var visitor_event_default =
|
|
13686
|
+
var visitor_event_default = app39;
|
|
13658
13687
|
|
|
13659
13688
|
// app/lib/graph-health.ts
|
|
13660
13689
|
var HOUR_MS = 60 * 60 * 1e3;
|
|
@@ -13901,7 +13930,7 @@ function broadcastAdminShutdown(reason) {
|
|
|
13901
13930
|
|
|
13902
13931
|
// ../lib/entitlement/src/index.ts
|
|
13903
13932
|
import { createPublicKey, createHash as createHash4, verify as cryptoVerify } from "crypto";
|
|
13904
|
-
import { existsSync as
|
|
13933
|
+
import { existsSync as existsSync20, readFileSync as readFileSync20, statSync as statSync9 } from "fs";
|
|
13905
13934
|
import { resolve as resolve22 } from "path";
|
|
13906
13935
|
|
|
13907
13936
|
// ../lib/entitlement/src/canonicalize.ts
|
|
@@ -13950,10 +13979,10 @@ function resolveEntitlement(brand, account) {
|
|
|
13950
13979
|
return logResolved(implicitTrust(account), null);
|
|
13951
13980
|
}
|
|
13952
13981
|
const entitlementPath = resolve22(brand.configDir, "entitlement.json");
|
|
13953
|
-
if (!
|
|
13982
|
+
if (!existsSync20(entitlementPath)) {
|
|
13954
13983
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
13955
13984
|
}
|
|
13956
|
-
const stat8 =
|
|
13985
|
+
const stat8 = statSync9(entitlementPath);
|
|
13957
13986
|
const key = memoKey(stat8.mtimeMs, account);
|
|
13958
13987
|
if (memo && memo.key === key) {
|
|
13959
13988
|
return memo.result;
|
|
@@ -13965,7 +13994,7 @@ function resolveEntitlement(brand, account) {
|
|
|
13965
13994
|
function verifyAndResolve(brand, entitlementPath, account) {
|
|
13966
13995
|
let pubkeyPem;
|
|
13967
13996
|
try {
|
|
13968
|
-
pubkeyPem =
|
|
13997
|
+
pubkeyPem = readFileSync20(pubkeyPath(brand), "utf-8");
|
|
13969
13998
|
} catch (err) {
|
|
13970
13999
|
return logResolved(anonymousFallback("pubkey-missing"), {
|
|
13971
14000
|
reason: "pubkey-missing"
|
|
@@ -13979,7 +14008,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
|
|
|
13979
14008
|
}
|
|
13980
14009
|
let envelope;
|
|
13981
14010
|
try {
|
|
13982
|
-
envelope = JSON.parse(
|
|
14011
|
+
envelope = JSON.parse(readFileSync20(entitlementPath, "utf-8"));
|
|
13983
14012
|
} catch {
|
|
13984
14013
|
return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
|
|
13985
14014
|
}
|
|
@@ -14140,14 +14169,14 @@ function clientFrom(c) {
|
|
|
14140
14169
|
);
|
|
14141
14170
|
}
|
|
14142
14171
|
var PLATFORM_ROOT9 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
14143
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT9 ?
|
|
14172
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT9 ? join16(PLATFORM_ROOT9, "config", "brand.json") : "";
|
|
14144
14173
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
14145
|
-
if (BRAND_JSON_PATH && !
|
|
14174
|
+
if (BRAND_JSON_PATH && !existsSync21(BRAND_JSON_PATH)) {
|
|
14146
14175
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
14147
14176
|
}
|
|
14148
|
-
if (BRAND_JSON_PATH &&
|
|
14177
|
+
if (BRAND_JSON_PATH && existsSync21(BRAND_JSON_PATH)) {
|
|
14149
14178
|
try {
|
|
14150
|
-
const parsed = JSON.parse(
|
|
14179
|
+
const parsed = JSON.parse(readFileSync21(BRAND_JSON_PATH, "utf-8"));
|
|
14151
14180
|
BRAND = { ...BRAND, ...parsed };
|
|
14152
14181
|
} catch (err) {
|
|
14153
14182
|
console.error(`[brand] Failed to parse brand.json: ${err.message}`);
|
|
@@ -14166,11 +14195,11 @@ var brandLoginOpts = {
|
|
|
14166
14195
|
bodyFont: BRAND.defaultFonts?.body,
|
|
14167
14196
|
logoContainsName: !!BRAND.logoContainsName
|
|
14168
14197
|
};
|
|
14169
|
-
var ALIAS_DOMAINS_PATH =
|
|
14198
|
+
var ALIAS_DOMAINS_PATH = join16(homedir2(), BRAND.configDir, "alias-domains.json");
|
|
14170
14199
|
function loadAliasDomains() {
|
|
14171
14200
|
try {
|
|
14172
|
-
if (!
|
|
14173
|
-
const parsed = JSON.parse(
|
|
14201
|
+
if (!existsSync21(ALIAS_DOMAINS_PATH)) return null;
|
|
14202
|
+
const parsed = JSON.parse(readFileSync21(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
14174
14203
|
if (!Array.isArray(parsed)) {
|
|
14175
14204
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
14176
14205
|
return null;
|
|
@@ -14194,9 +14223,9 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
|
|
|
14194
14223
|
function isPublicHost(host) {
|
|
14195
14224
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
14196
14225
|
}
|
|
14197
|
-
var
|
|
14198
|
-
|
|
14199
|
-
|
|
14226
|
+
var app40 = new Hono();
|
|
14227
|
+
app40.use("*", clientIpMiddleware);
|
|
14228
|
+
app40.use("*", async (c, next) => {
|
|
14200
14229
|
await next();
|
|
14201
14230
|
c.header("X-Content-Type-Options", "nosniff");
|
|
14202
14231
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
@@ -14206,7 +14235,7 @@ app39.use("*", async (c, next) => {
|
|
|
14206
14235
|
);
|
|
14207
14236
|
});
|
|
14208
14237
|
var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
|
|
14209
|
-
|
|
14238
|
+
app40.use("*", async (c, next) => {
|
|
14210
14239
|
if (!HTTP_LOG_PATHS.has(c.req.path)) {
|
|
14211
14240
|
await next();
|
|
14212
14241
|
return;
|
|
@@ -14239,7 +14268,7 @@ var PUBLIC_ALLOWED_PREFIXES = [
|
|
|
14239
14268
|
"/sites/"
|
|
14240
14269
|
];
|
|
14241
14270
|
var PUBLIC_ALLOWED_EXACT = ["/favicon.ico"];
|
|
14242
|
-
|
|
14271
|
+
app40.use("*", async (c, next) => {
|
|
14243
14272
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14244
14273
|
if (!isPublicHost(host)) {
|
|
14245
14274
|
await next();
|
|
@@ -14279,7 +14308,7 @@ function resolveRemoteAuthOpts() {
|
|
|
14279
14308
|
return brandLoginOpts;
|
|
14280
14309
|
}
|
|
14281
14310
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
14282
|
-
|
|
14311
|
+
app40.post("/__remote-auth/login", async (c) => {
|
|
14283
14312
|
const client = clientFrom(c);
|
|
14284
14313
|
const clientIp = client.ip || "unknown";
|
|
14285
14314
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -14324,7 +14353,7 @@ app39.post("/__remote-auth/login", async (c) => {
|
|
|
14324
14353
|
}
|
|
14325
14354
|
});
|
|
14326
14355
|
});
|
|
14327
|
-
|
|
14356
|
+
app40.get("/__remote-auth/logout", (c) => {
|
|
14328
14357
|
const client = clientFrom(c);
|
|
14329
14358
|
const clientIp = client.ip || "unknown";
|
|
14330
14359
|
console.error(`[remote-auth] logout ip=${clientIp}`);
|
|
@@ -14337,7 +14366,7 @@ app39.get("/__remote-auth/logout", (c) => {
|
|
|
14337
14366
|
}
|
|
14338
14367
|
});
|
|
14339
14368
|
});
|
|
14340
|
-
|
|
14369
|
+
app40.post("/__remote-auth/change-password", async (c) => {
|
|
14341
14370
|
const client = clientFrom(c);
|
|
14342
14371
|
const clientIp = client.ip || "unknown";
|
|
14343
14372
|
const rateLimited = checkRateLimit(client);
|
|
@@ -14388,13 +14417,13 @@ app39.post("/__remote-auth/change-password", async (c) => {
|
|
|
14388
14417
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
14389
14418
|
}
|
|
14390
14419
|
});
|
|
14391
|
-
|
|
14420
|
+
app40.get("/__remote-auth/setup", (c) => {
|
|
14392
14421
|
if (isRemoteAuthConfigured()) {
|
|
14393
14422
|
return c.redirect("/");
|
|
14394
14423
|
}
|
|
14395
14424
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
|
|
14396
14425
|
});
|
|
14397
|
-
|
|
14426
|
+
app40.post("/__remote-auth/set-initial-password", async (c) => {
|
|
14398
14427
|
if (isRemoteAuthConfigured()) {
|
|
14399
14428
|
return c.redirect("/");
|
|
14400
14429
|
}
|
|
@@ -14432,10 +14461,10 @@ app39.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
14432
14461
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
14433
14462
|
}
|
|
14434
14463
|
});
|
|
14435
|
-
|
|
14464
|
+
app40.get("/api/remote-auth/status", (c) => {
|
|
14436
14465
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
14437
14466
|
});
|
|
14438
|
-
|
|
14467
|
+
app40.post("/api/remote-auth/set-password", async (c) => {
|
|
14439
14468
|
let body;
|
|
14440
14469
|
try {
|
|
14441
14470
|
body = await c.req.json();
|
|
@@ -14466,9 +14495,9 @@ app39.post("/api/remote-auth/set-password", async (c) => {
|
|
|
14466
14495
|
return c.json({ error: "Failed to save password" }, 500);
|
|
14467
14496
|
}
|
|
14468
14497
|
});
|
|
14469
|
-
|
|
14498
|
+
app40.route("/api/_client-error", client_error_default);
|
|
14470
14499
|
console.log("[client-error-route] mounted");
|
|
14471
|
-
|
|
14500
|
+
app40.use("*", async (c, next) => {
|
|
14472
14501
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14473
14502
|
const path2 = c.req.path;
|
|
14474
14503
|
if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/")) {
|
|
@@ -14501,12 +14530,12 @@ app39.use("*", async (c, next) => {
|
|
|
14501
14530
|
console.error(`[remote-auth] login required ip=${clientIp} path=${path2} ${disambig}`);
|
|
14502
14531
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
|
|
14503
14532
|
});
|
|
14504
|
-
|
|
14505
|
-
|
|
14506
|
-
|
|
14507
|
-
|
|
14508
|
-
|
|
14509
|
-
|
|
14533
|
+
app40.route("/api/health", health_default);
|
|
14534
|
+
app40.route("/api/chat", chat_default);
|
|
14535
|
+
app40.route("/api/whatsapp", whatsapp_default);
|
|
14536
|
+
app40.route("/api/onboarding", onboarding_default);
|
|
14537
|
+
app40.route("/api/admin", admin_default);
|
|
14538
|
+
app40.route("/api/access", access_default);
|
|
14510
14539
|
var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
|
|
14511
14540
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
14512
14541
|
var IMAGE_MIME = {
|
|
@@ -14518,7 +14547,7 @@ var IMAGE_MIME = {
|
|
|
14518
14547
|
".svg": "image/svg+xml",
|
|
14519
14548
|
".ico": "image/x-icon"
|
|
14520
14549
|
};
|
|
14521
|
-
|
|
14550
|
+
app40.get("/agent-assets/:slug/:filename", (c) => {
|
|
14522
14551
|
const slug = c.req.param("slug");
|
|
14523
14552
|
const filename = c.req.param("filename");
|
|
14524
14553
|
if (!SAFE_SLUG_RE2.test(slug)) {
|
|
@@ -14540,20 +14569,20 @@ app39.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
14540
14569
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
14541
14570
|
return c.text("Forbidden", 403);
|
|
14542
14571
|
}
|
|
14543
|
-
if (!
|
|
14572
|
+
if (!existsSync21(filePath)) {
|
|
14544
14573
|
console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
|
|
14545
14574
|
return c.text("Not found", 404);
|
|
14546
14575
|
}
|
|
14547
14576
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
14548
14577
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
14549
14578
|
console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
|
|
14550
|
-
const body =
|
|
14579
|
+
const body = readFileSync21(filePath);
|
|
14551
14580
|
return c.body(body, 200, {
|
|
14552
14581
|
"Content-Type": contentType,
|
|
14553
14582
|
"Cache-Control": "public, max-age=3600"
|
|
14554
14583
|
});
|
|
14555
14584
|
});
|
|
14556
|
-
|
|
14585
|
+
app40.get("/generated/:filename", (c) => {
|
|
14557
14586
|
const filename = c.req.param("filename");
|
|
14558
14587
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
14559
14588
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -14570,29 +14599,29 @@ app39.get("/generated/:filename", (c) => {
|
|
|
14570
14599
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
14571
14600
|
return c.text("Forbidden", 403);
|
|
14572
14601
|
}
|
|
14573
|
-
if (!
|
|
14602
|
+
if (!existsSync21(filePath)) {
|
|
14574
14603
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
14575
14604
|
return c.text("Not found", 404);
|
|
14576
14605
|
}
|
|
14577
14606
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
14578
14607
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
14579
14608
|
console.log(`[generated] serve file=${filename} status=200`);
|
|
14580
|
-
const body =
|
|
14609
|
+
const body = readFileSync21(filePath);
|
|
14581
14610
|
return c.body(body, 200, {
|
|
14582
14611
|
"Content-Type": contentType,
|
|
14583
14612
|
"Cache-Control": "public, max-age=86400"
|
|
14584
14613
|
});
|
|
14585
14614
|
});
|
|
14586
|
-
|
|
14587
|
-
|
|
14588
|
-
|
|
14589
|
-
|
|
14615
|
+
app40.route("/sites", sites_default);
|
|
14616
|
+
app40.route("/listings", listings_default);
|
|
14617
|
+
app40.route("/v", visitor_event_default);
|
|
14618
|
+
app40.route("/v", visitor_consent_default);
|
|
14590
14619
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
14591
14620
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
14592
14621
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
14593
|
-
if (BRAND_JSON_PATH &&
|
|
14622
|
+
if (BRAND_JSON_PATH && existsSync21(BRAND_JSON_PATH)) {
|
|
14594
14623
|
try {
|
|
14595
|
-
const fullBrand = JSON.parse(
|
|
14624
|
+
const fullBrand = JSON.parse(readFileSync21(BRAND_JSON_PATH, "utf-8"));
|
|
14596
14625
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
14597
14626
|
brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
|
|
14598
14627
|
} catch {
|
|
@@ -14609,9 +14638,9 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
14609
14638
|
function readInstalledVersion() {
|
|
14610
14639
|
try {
|
|
14611
14640
|
if (!PLATFORM_ROOT9) return "unknown";
|
|
14612
|
-
const versionFile =
|
|
14613
|
-
if (!
|
|
14614
|
-
const content =
|
|
14641
|
+
const versionFile = join16(PLATFORM_ROOT9, "config", `.${BRAND.hostname}-version`);
|
|
14642
|
+
if (!existsSync21(versionFile)) return "unknown";
|
|
14643
|
+
const content = readFileSync21(versionFile, "utf-8").trim();
|
|
14615
14644
|
return content || "unknown";
|
|
14616
14645
|
} catch {
|
|
14617
14646
|
return "unknown";
|
|
@@ -14652,7 +14681,7 @@ var clientErrorReporterScript = `<script>
|
|
|
14652
14681
|
function cachedHtml(file) {
|
|
14653
14682
|
let html = htmlCache.get(file);
|
|
14654
14683
|
if (!html) {
|
|
14655
|
-
html =
|
|
14684
|
+
html = readFileSync21(resolve23(process.cwd(), "public", file), "utf-8");
|
|
14656
14685
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
14657
14686
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
14658
14687
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -14668,26 +14697,26 @@ ${clientErrorReporterScript}
|
|
|
14668
14697
|
}
|
|
14669
14698
|
var brandedHtmlCache = /* @__PURE__ */ new Map();
|
|
14670
14699
|
function loadBrandingCache(agentSlug) {
|
|
14671
|
-
const configDir2 =
|
|
14700
|
+
const configDir2 = join16(homedir2(), BRAND.configDir);
|
|
14672
14701
|
try {
|
|
14673
|
-
const accountJsonPath =
|
|
14674
|
-
if (!
|
|
14675
|
-
const account = JSON.parse(
|
|
14702
|
+
const accountJsonPath = join16(configDir2, "account.json");
|
|
14703
|
+
if (!existsSync21(accountJsonPath)) return null;
|
|
14704
|
+
const account = JSON.parse(readFileSync21(accountJsonPath, "utf-8"));
|
|
14676
14705
|
const accountId = account.accountId;
|
|
14677
14706
|
if (!accountId) return null;
|
|
14678
|
-
const cachePath =
|
|
14679
|
-
if (!
|
|
14680
|
-
return JSON.parse(
|
|
14707
|
+
const cachePath = join16(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
14708
|
+
if (!existsSync21(cachePath)) return null;
|
|
14709
|
+
return JSON.parse(readFileSync21(cachePath, "utf-8"));
|
|
14681
14710
|
} catch {
|
|
14682
14711
|
return null;
|
|
14683
14712
|
}
|
|
14684
14713
|
}
|
|
14685
14714
|
function resolveDefaultSlug() {
|
|
14686
14715
|
try {
|
|
14687
|
-
const configDir2 =
|
|
14688
|
-
const accountJsonPath =
|
|
14689
|
-
if (!
|
|
14690
|
-
const account = JSON.parse(
|
|
14716
|
+
const configDir2 = join16(homedir2(), BRAND.configDir);
|
|
14717
|
+
const accountJsonPath = join16(configDir2, "account.json");
|
|
14718
|
+
if (!existsSync21(accountJsonPath)) return null;
|
|
14719
|
+
const account = JSON.parse(readFileSync21(accountJsonPath, "utf-8"));
|
|
14691
14720
|
return account.defaultAgent || null;
|
|
14692
14721
|
} catch {
|
|
14693
14722
|
return null;
|
|
@@ -14723,7 +14752,7 @@ function brandedPublicHtml(agentSlug) {
|
|
|
14723
14752
|
function escapeHtml(s) {
|
|
14724
14753
|
return s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
14725
14754
|
}
|
|
14726
|
-
|
|
14755
|
+
app40.get("/", (c) => {
|
|
14727
14756
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14728
14757
|
if (isPublicHost(host)) {
|
|
14729
14758
|
const defaultSlug = resolveDefaultSlug();
|
|
@@ -14731,12 +14760,12 @@ app39.get("/", (c) => {
|
|
|
14731
14760
|
}
|
|
14732
14761
|
return c.html(cachedHtml("index.html"));
|
|
14733
14762
|
});
|
|
14734
|
-
|
|
14763
|
+
app40.get("/public", (c) => {
|
|
14735
14764
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14736
14765
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14737
14766
|
return c.html(cachedHtml("public.html"));
|
|
14738
14767
|
});
|
|
14739
|
-
|
|
14768
|
+
app40.get("/chat", (c) => {
|
|
14740
14769
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14741
14770
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14742
14771
|
return c.html(cachedHtml("public.html"));
|
|
@@ -14755,12 +14784,12 @@ async function logViewerFetch(c, next) {
|
|
|
14755
14784
|
duration_ms: Date.now() - start
|
|
14756
14785
|
});
|
|
14757
14786
|
}
|
|
14758
|
-
|
|
14759
|
-
|
|
14760
|
-
|
|
14787
|
+
app40.use("/vnc-viewer.html", logViewerFetch);
|
|
14788
|
+
app40.use("/vnc-popout.html", logViewerFetch);
|
|
14789
|
+
app40.get("/vnc-popout.html", (c) => {
|
|
14761
14790
|
let html = htmlCache.get("vnc-popout.html");
|
|
14762
14791
|
if (!html) {
|
|
14763
|
-
html =
|
|
14792
|
+
html = readFileSync21(resolve23(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
14764
14793
|
const name = escapeHtml(BRAND.productName);
|
|
14765
14794
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
14766
14795
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -14770,7 +14799,7 @@ app39.get("/vnc-popout.html", (c) => {
|
|
|
14770
14799
|
}
|
|
14771
14800
|
return c.html(html);
|
|
14772
14801
|
});
|
|
14773
|
-
|
|
14802
|
+
app40.post("/api/vnc/client-event", async (c) => {
|
|
14774
14803
|
let body;
|
|
14775
14804
|
try {
|
|
14776
14805
|
body = await c.req.json();
|
|
@@ -14791,25 +14820,25 @@ app39.post("/api/vnc/client-event", async (c) => {
|
|
|
14791
14820
|
});
|
|
14792
14821
|
return c.json({ ok: true });
|
|
14793
14822
|
});
|
|
14794
|
-
|
|
14823
|
+
app40.get("/g/:slug", (c) => {
|
|
14795
14824
|
return c.html(brandedPublicHtml());
|
|
14796
14825
|
});
|
|
14797
|
-
|
|
14826
|
+
app40.get("/graph", (c) => {
|
|
14798
14827
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14799
14828
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14800
14829
|
return c.html(cachedHtml("graph.html"));
|
|
14801
14830
|
});
|
|
14802
|
-
|
|
14831
|
+
app40.get("/sessions", (c) => {
|
|
14803
14832
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14804
14833
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14805
14834
|
return c.html(cachedHtml("sessions.html"));
|
|
14806
14835
|
});
|
|
14807
|
-
|
|
14836
|
+
app40.get("/data", (c) => {
|
|
14808
14837
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14809
14838
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14810
14839
|
return c.html(cachedHtml("data.html"));
|
|
14811
14840
|
});
|
|
14812
|
-
|
|
14841
|
+
app40.get("/:slug", async (c, next) => {
|
|
14813
14842
|
const slug = c.req.param("slug");
|
|
14814
14843
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
14815
14844
|
const branding = loadBrandingCache(slug);
|
|
@@ -14819,15 +14848,15 @@ app39.get("/:slug", async (c, next) => {
|
|
|
14819
14848
|
await next();
|
|
14820
14849
|
});
|
|
14821
14850
|
if (brandFaviconPath !== "/favicon.ico") {
|
|
14822
|
-
|
|
14851
|
+
app40.get("/favicon.ico", (c) => {
|
|
14823
14852
|
c.header("Cache-Control", "public, max-age=300");
|
|
14824
14853
|
return c.redirect(brandFaviconPath, 302);
|
|
14825
14854
|
});
|
|
14826
14855
|
}
|
|
14827
|
-
|
|
14856
|
+
app40.use("/*", serveStatic({ root: "./public" }));
|
|
14828
14857
|
var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
|
|
14829
14858
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
14830
|
-
var httpServer = serve({ fetch:
|
|
14859
|
+
var httpServer = serve({ fetch: app40.fetch, port, hostname });
|
|
14831
14860
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
14832
14861
|
{
|
|
14833
14862
|
const loopHist = monitorEventLoopDelay({ resolution: 50 });
|
|
@@ -14863,7 +14892,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
14863
14892
|
}
|
|
14864
14893
|
try {
|
|
14865
14894
|
const registered = [];
|
|
14866
|
-
for (const r of
|
|
14895
|
+
for (const r of app40.routes ?? []) {
|
|
14867
14896
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
14868
14897
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
14869
14898
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|
|
@@ -14885,8 +14914,8 @@ try {
|
|
|
14885
14914
|
}
|
|
14886
14915
|
(async () => {
|
|
14887
14916
|
try {
|
|
14888
|
-
if (!
|
|
14889
|
-
const usersRaw =
|
|
14917
|
+
if (!existsSync21(USERS_FILE)) return;
|
|
14918
|
+
const usersRaw = readFileSync21(USERS_FILE, "utf-8").trim();
|
|
14890
14919
|
if (!usersRaw) return;
|
|
14891
14920
|
const users = JSON.parse(usersRaw);
|
|
14892
14921
|
const userId = users[0]?.userId;
|
|
@@ -14981,7 +15010,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
14981
15010
|
}
|
|
14982
15011
|
init({
|
|
14983
15012
|
configDir: configDirForWhatsApp,
|
|
14984
|
-
platformRoot: resolve23(process.env.MAXY_PLATFORM_ROOT ??
|
|
15013
|
+
platformRoot: resolve23(process.env.MAXY_PLATFORM_ROOT ?? join16(__dirname, "..")),
|
|
14985
15014
|
accountConfig: bootAccountConfig,
|
|
14986
15015
|
onMessage: async (msg) => {
|
|
14987
15016
|
if (process.env.WHATSAPP_PTY_BRIDGE_ENABLED === "true" && msg.text && !msg.isOwnerMirror) {
|