@rubytech/create-maxy-code 0.1.387 → 0.1.389
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/dist/__tests__/joblogic-excluded.test.js +39 -0
- package/dist/index.js +21 -0
- package/package.json +1 -1
- package/payload/platform/config/brand.json +1 -1
- package/payload/platform/plugins/.claude-plugin/marketplace.json +0 -5
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +21 -2
- package/payload/platform/plugins/docs/references/admin-session.md +4 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +18 -1
- package/payload/platform/plugins/docs/references/joblogic.md +2 -0
- package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +7 -3
- package/payload/platform/plugins/whatsapp/skills/manage-whatsapp-config/SKILL.md +2 -0
- package/payload/platform/plugins/work/PLUGIN.md +3 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/session-metering.test.d.ts +2 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/session-metering.test.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/session-metering.test.js +98 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/session-metering.test.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/index.js +16 -0
- package/payload/platform/plugins/work/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/work/mcp/dist/tools/session-metering.d.ts +53 -0
- package/payload/platform/plugins/work/mcp/dist/tools/session-metering.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/session-metering.js +80 -0
- package/payload/platform/plugins/work/mcp/dist/tools/session-metering.js.map +1 -0
- package/payload/platform/plugins/work/mcp/package.json +2 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +98 -8
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pricing.d.ts +45 -0
- package/payload/platform/services/claude-session-manager/dist/pricing.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/pricing.js +57 -0
- package/payload/platform/services/claude-session-manager/dist/pricing.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/session-metering.d.ts +38 -0
- package/payload/platform/services/claude-session-manager/dist/session-metering.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/session-metering.js +292 -0
- package/payload/platform/services/claude-session-manager/dist/session-metering.js.map +1 -0
- package/payload/platform/templates/specialists/agents/project-manager.md +1 -1
- package/payload/server/public/assets/{AdminLoginScreens-BejIjbmU.js → AdminLoginScreens-CerrEc_m.js} +1 -1
- package/payload/server/public/assets/AdminShell-cRTvNRbo.js +1 -0
- package/payload/server/public/assets/{Checkbox-1F1tzqca.js → Checkbox-Dh2pLMFN.js} +1 -1
- package/payload/server/public/assets/{Transcript-DkGa4CQH.js → Transcript-B_GVJujB.js} +1 -1
- package/payload/server/public/assets/{admin-DqQARkjy.js → admin-BXaYelnR.js} +1 -1
- package/payload/server/public/assets/{browser-nDtEK6RC.js → browser-fhjGE7fH.js} +1 -1
- package/payload/server/public/assets/calendar-PnZudAtc.js +1 -0
- package/payload/server/public/assets/chat-Dy_zrjKS.js +1 -0
- package/payload/server/public/assets/chevron-left-IB6TmMZ_.js +1 -0
- package/payload/server/public/assets/data-B2IcjAj6.js +1 -0
- package/payload/server/public/assets/{graph-DFyicKd7.js → graph-CycO3tkW.js} +2 -2
- package/payload/server/public/assets/{graph-labels-D3BQdcpD.js → graph-labels-DlSsSpBV.js} +1 -1
- package/payload/server/public/assets/{operator-BxrjWdT9.js → operator-L4kBC-zS.js} +1 -1
- package/payload/server/public/assets/page-D5E-Ng4D.js +1 -0
- package/payload/server/public/assets/page-M8sD9LOi.js +32 -0
- package/payload/server/public/assets/{public-DbdqfdYq.js → public-BmnajF3K.js} +1 -1
- package/payload/server/public/assets/{rotate-ccw-BkX8HODe.js → rotate-ccw-W5HhvAbo.js} +1 -1
- package/payload/server/public/assets/useSubAccountSwitcher-D1TI1xvd.css +1 -0
- package/payload/server/public/assets/useSubAccountSwitcher-UqZbmzYy.js +9 -0
- package/payload/server/public/browser.html +4 -4
- package/payload/server/public/calendar.html +5 -5
- package/payload/server/public/chat.html +8 -8
- package/payload/server/public/data.html +7 -7
- package/payload/server/public/graph.html +8 -8
- package/payload/server/public/index.html +10 -10
- package/payload/server/public/operator.html +10 -10
- package/payload/server/public/public.html +8 -8
- package/payload/server/server.js +444 -315
- package/payload/platform/plugins/joblogic/.claude-plugin/plugin.json +0 -21
- package/payload/platform/plugins/joblogic/PLUGIN.md +0 -182
- package/payload/platform/plugins/joblogic/lib/mcp-spawn-tee/index.js +0 -193
- package/payload/platform/plugins/joblogic/lib/mcp-spawn-tee/package.json +0 -3
- package/payload/platform/plugins/joblogic/mcp/dist/index.d.ts +0 -2
- package/payload/platform/plugins/joblogic/mcp/dist/index.d.ts.map +0 -1
- package/payload/platform/plugins/joblogic/mcp/dist/index.js +0 -229
- package/payload/platform/plugins/joblogic/mcp/dist/index.js.map +0 -1
- package/payload/platform/plugins/joblogic/mcp/dist/lib/auth.d.ts +0 -31
- package/payload/platform/plugins/joblogic/mcp/dist/lib/auth.d.ts.map +0 -1
- package/payload/platform/plugins/joblogic/mcp/dist/lib/auth.js +0 -78
- package/payload/platform/plugins/joblogic/mcp/dist/lib/auth.js.map +0 -1
- package/payload/platform/plugins/joblogic/mcp/dist/lib/client.d.ts +0 -35
- package/payload/platform/plugins/joblogic/mcp/dist/lib/client.d.ts.map +0 -1
- package/payload/platform/plugins/joblogic/mcp/dist/lib/client.js +0 -106
- package/payload/platform/plugins/joblogic/mcp/dist/lib/client.js.map +0 -1
- package/payload/platform/plugins/joblogic/mcp/dist/lib/idempotency.d.ts +0 -8
- package/payload/platform/plugins/joblogic/mcp/dist/lib/idempotency.d.ts.map +0 -1
- package/payload/platform/plugins/joblogic/mcp/dist/lib/idempotency.js +0 -41
- package/payload/platform/plugins/joblogic/mcp/dist/lib/idempotency.js.map +0 -1
- package/payload/platform/plugins/joblogic/mcp/dist/lib/secrets.d.ts +0 -21
- package/payload/platform/plugins/joblogic/mcp/dist/lib/secrets.d.ts.map +0 -1
- package/payload/platform/plugins/joblogic/mcp/dist/lib/secrets.js +0 -47
- package/payload/platform/plugins/joblogic/mcp/dist/lib/secrets.js.map +0 -1
- package/payload/platform/plugins/joblogic/mcp/package.json +0 -10
- package/payload/platform/plugins/joblogic/skills/joblogic/SKILL.md +0 -32
- package/payload/server/public/assets/AdminShell-D2-uBSB5.js +0 -1
- package/payload/server/public/assets/calendar-CO4Bwmho.js +0 -1
- package/payload/server/public/assets/chat-DeIge_bC.js +0 -1
- package/payload/server/public/assets/chevron-left-DhVdq0aN.js +0 -1
- package/payload/server/public/assets/data-B1GIdzHk.js +0 -1
- package/payload/server/public/assets/page-ByDLq_o1.js +0 -1
- package/payload/server/public/assets/page-D-Ep4bXd.js +0 -32
- package/payload/server/public/assets/useSubAccountSwitcher-DMbRhLPv.js +0 -9
- package/payload/server/public/assets/useSubAccountSwitcher-DS0iqSkP.css +0 -1
package/payload/server/server.js
CHANGED
|
@@ -1307,7 +1307,7 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
1307
1307
|
// server/index.ts
|
|
1308
1308
|
import { readFileSync as readFileSync35, existsSync as existsSync33, watchFile } from "fs";
|
|
1309
1309
|
import { spawn as spawn3 } from "child_process";
|
|
1310
|
-
import { resolve as resolve33, join as join34, basename as
|
|
1310
|
+
import { resolve as resolve33, join as join34, basename as basename13 } from "path";
|
|
1311
1311
|
import { homedir as homedir3 } from "os";
|
|
1312
1312
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
1313
1313
|
|
|
@@ -1726,7 +1726,7 @@ var WhatsAppAccountSchema = z.object({
|
|
|
1726
1726
|
var WhatsAppConfigSchema = z.object({
|
|
1727
1727
|
accounts: z.record(z.string(), WhatsAppAccountSchema.optional()).optional().describe("Per-account config keyed by account ID."),
|
|
1728
1728
|
dmPolicy: DmPolicySchema.optional().default("disabled").describe("Who can message your public agent via WhatsApp DM. 'Open' lets anyone message. 'Allowlist' restricts to approved phone numbers. 'Disabled' blocks all public messages."),
|
|
1729
|
-
adminPhones: z.array(z.string()).optional().describe("Phone numbers (E.164) that route to the admin agent. Managed via add-admin-phone / remove-admin-phone."),
|
|
1729
|
+
adminPhones: z.array(z.string()).optional().describe("Phone numbers (E.164) that route to the admin agent. Managed via add-admin-phone / remove-admin-phone. Authoritative only on the account that owns the WhatsApp paired socket; a list on any other account is inert and purged at boot \u2014 use accountManagers for sub-account routing."),
|
|
1730
1730
|
accountManagers: z.record(z.string(), z.string()).optional().describe("Account-manager bindings: E.164 phone \u2192 sub-account UUID. A designated phone spawns an admin session scoped to that sub-account rather than the house. Managed via add-account-manager / remove-account-manager. A phone here must not also be in adminPhones."),
|
|
1731
1731
|
allowFrom: z.array(z.string()).optional().describe("Phone numbers allowed to message the public agent when DM policy is 'allowlist'. Add '*' for open access. Does not affect admin routing \u2014 use adminPhones for that."),
|
|
1732
1732
|
sendReadReceipts: z.boolean().optional().default(true).describe("Whether to send read receipts (blue ticks) when messages are received. Disabling may feel less responsive but preserves privacy."),
|
|
@@ -2628,27 +2628,31 @@ function isAdminPhone(phone, adminPhones) {
|
|
|
2628
2628
|
return adminPhones.some((entry) => phonesMatch(entry, normalized));
|
|
2629
2629
|
}
|
|
2630
2630
|
function checkDmAccess(params) {
|
|
2631
|
-
const { senderPhone, selfPhone } = params;
|
|
2631
|
+
const { senderPhone, selfPhone, accountId } = params;
|
|
2632
2632
|
const cfg = resolveAccountConfig(params.config, params.accountConfig);
|
|
2633
2633
|
if (phonesMatch(senderPhone, selfPhone)) {
|
|
2634
|
-
return { allowed: true, reason: "self-phone", agentType: "admin" };
|
|
2634
|
+
return { allowed: true, reason: "self-phone", agentType: "admin", effectiveAccountId: accountId };
|
|
2635
2635
|
}
|
|
2636
2636
|
if (isAdminPhone(senderPhone, cfg.adminPhones)) {
|
|
2637
|
-
return { allowed: true, reason: "admin-binding", agentType: "admin" };
|
|
2637
|
+
return { allowed: true, reason: "admin-binding", agentType: "admin", effectiveAccountId: accountId };
|
|
2638
2638
|
}
|
|
2639
|
-
|
|
2640
|
-
|
|
2639
|
+
const managedSub = managedAccountFor(cfg.accountManagers, senderPhone);
|
|
2640
|
+
if (managedSub) {
|
|
2641
|
+
if (params.isValidAccount && !params.isValidAccount(managedSub)) {
|
|
2642
|
+
return { allowed: false, reason: "account-manager-unresolved", agentType: "admin" };
|
|
2643
|
+
}
|
|
2644
|
+
return { allowed: true, reason: "account-manager", agentType: "admin", effectiveAccountId: managedSub };
|
|
2641
2645
|
}
|
|
2642
2646
|
switch (cfg.dmPolicy) {
|
|
2643
2647
|
case "open":
|
|
2644
|
-
return { allowed: true, reason: "dm-policy-open", agentType: "public" };
|
|
2648
|
+
return { allowed: true, reason: "dm-policy-open", agentType: "public", effectiveAccountId: accountId };
|
|
2645
2649
|
case "allowlist": {
|
|
2646
2650
|
const inList = cfg.allowFrom.some((entry) => {
|
|
2647
2651
|
if (entry === "*") return true;
|
|
2648
2652
|
return phonesMatch(entry, senderPhone);
|
|
2649
2653
|
});
|
|
2650
2654
|
if (inList) {
|
|
2651
|
-
return { allowed: true, reason: "allowlist-match", agentType: "public" };
|
|
2655
|
+
return { allowed: true, reason: "allowlist-match", agentType: "public", effectiveAccountId: accountId };
|
|
2652
2656
|
}
|
|
2653
2657
|
return { allowed: false, reason: "not-in-allowlist", agentType: "public" };
|
|
2654
2658
|
}
|
|
@@ -4100,7 +4104,9 @@ function buildSelfChatDispatch(input) {
|
|
|
4100
4104
|
senderPhone,
|
|
4101
4105
|
isGroup: false
|
|
4102
4106
|
}),
|
|
4103
|
-
media: []
|
|
4107
|
+
media: [],
|
|
4108
|
+
// Self-chat is the owner: the session scopes to the house account (Task 1383).
|
|
4109
|
+
effectiveAccountId: input.accountId
|
|
4104
4110
|
};
|
|
4105
4111
|
}
|
|
4106
4112
|
async function init(opts) {
|
|
@@ -4748,12 +4754,24 @@ async function handleInboundMessage(conn, msg) {
|
|
|
4748
4754
|
config: whatsAppConfig,
|
|
4749
4755
|
accountConfig: whatsAppConfig.accounts?.[conn.accountId],
|
|
4750
4756
|
accountId: conn.accountId,
|
|
4757
|
+
isValidAccount: (id) => listValidAccounts().some((a) => a.accountId === id),
|
|
4751
4758
|
resolvePersonByPhone
|
|
4752
4759
|
});
|
|
4753
4760
|
}
|
|
4754
4761
|
console.error(
|
|
4755
4762
|
`${TAG13} inbound account=${conn.accountId} from=${senderPhone} group=${isGroup} access=${accessResult.allowed ? "allowed" : "blocked"}(${accessResult.reason}) agent=${accessResult.agentType}` + (extracted.mediaType ? ` media=${extracted.mediaType}` : "") + (mediaResult ? ` mediaPath=${mediaResult.path}` : "") + (extracted.quotedMessage ? ` replyTo=${extracted.quotedMessage.id}` : "")
|
|
4756
4763
|
);
|
|
4764
|
+
if (!accessResult.allowed && accessResult.reason === "account-manager-unresolved") {
|
|
4765
|
+
console.error(
|
|
4766
|
+
`[whatsapp-native] op=account-manager-reject senderId=${senderPhone} reason=unresolved-effective-account`
|
|
4767
|
+
);
|
|
4768
|
+
}
|
|
4769
|
+
if (accessResult.allowed && accessResult.reason === "account-manager" && accessResult.effectiveAccountId === conn.accountId) {
|
|
4770
|
+
console.error(
|
|
4771
|
+
`[whatsapp-native] op=escalation-tripwire senderId=${senderPhone} reason=account-manager-routed-to-house effectiveAccount=${accessResult.effectiveAccountId}`
|
|
4772
|
+
);
|
|
4773
|
+
return;
|
|
4774
|
+
}
|
|
4757
4775
|
if (!accessResult.allowed) return;
|
|
4758
4776
|
if (isCustomerTurnSuppressed(accessResult.agentType, isHouseManagedService())) {
|
|
4759
4777
|
console.error(
|
|
@@ -4801,7 +4819,10 @@ async function handleInboundMessage(conn, msg) {
|
|
|
4801
4819
|
composing,
|
|
4802
4820
|
cacheKey,
|
|
4803
4821
|
media: mediaResult?.path ? [{ path: mediaResult.path, type: extracted.mediaType, mimetype: mediaResult.mimetype }] : [],
|
|
4804
|
-
replyContext: extracted.quotedMessage
|
|
4822
|
+
replyContext: extracted.quotedMessage,
|
|
4823
|
+
// Task 1383 — the gate's single resolution feeds the spawn (house or the
|
|
4824
|
+
// bound sub-account); the router never re-resolves.
|
|
4825
|
+
effectiveAccountId: accessResult.effectiveAccountId
|
|
4805
4826
|
};
|
|
4806
4827
|
if (accessResult.agentType === "public") {
|
|
4807
4828
|
const hoursResult = await isBusinessOpen(conn.accountId);
|
|
@@ -5719,8 +5740,8 @@ function webchatTurnTimeoutMs() {
|
|
|
5719
5740
|
return Number(process.env.WEBCHAT_TURN_TIMEOUT_MS ?? String(2 * 6e4));
|
|
5720
5741
|
}
|
|
5721
5742
|
function createChatRoutes(deps) {
|
|
5722
|
-
const
|
|
5723
|
-
|
|
5743
|
+
const app57 = new Hono();
|
|
5744
|
+
app57.post("/", async (c) => {
|
|
5724
5745
|
console.log(`[chat-route] entered route=public method=POST`);
|
|
5725
5746
|
const contentType = c.req.header("content-type") ?? "";
|
|
5726
5747
|
const account = resolveAccount();
|
|
@@ -5983,7 +6004,7 @@ ${result.result.text}` : result.result.text;
|
|
|
5983
6004
|
}
|
|
5984
6005
|
});
|
|
5985
6006
|
});
|
|
5986
|
-
return
|
|
6007
|
+
return app57;
|
|
5987
6008
|
}
|
|
5988
6009
|
|
|
5989
6010
|
// app/lib/channel-pty-bridge/admin-session-id.ts
|
|
@@ -6004,8 +6025,8 @@ function isLoopbackAddr(addr) {
|
|
|
6004
6025
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
6005
6026
|
}
|
|
6006
6027
|
function createScheduleInjectRoutes(deps) {
|
|
6007
|
-
const
|
|
6008
|
-
|
|
6028
|
+
const app57 = new Hono();
|
|
6029
|
+
app57.post("/", async (c) => {
|
|
6009
6030
|
const env = c.env;
|
|
6010
6031
|
const remoteAddr = env?.incoming?.socket?.remoteAddress ?? "";
|
|
6011
6032
|
if (!isLoopbackAddr(remoteAddr)) {
|
|
@@ -6044,12 +6065,22 @@ function createScheduleInjectRoutes(deps) {
|
|
|
6044
6065
|
console.error(`${TAG16} op=received eventId=${eventId} channel=${channel} destination=${destination} account=${houseAccountId}`);
|
|
6045
6066
|
if (channel === "whatsapp") {
|
|
6046
6067
|
const effectiveAccount2 = deps.effectiveAccountFor(houseAccountId, account.accountDir, destination);
|
|
6068
|
+
if (effectiveAccount2 === null) {
|
|
6069
|
+
console.error(`${TAG16} op=schedule-account-manager-reject eventId=${eventId} destination=${destination} reason=unresolved-effective-account`);
|
|
6070
|
+
return c.json({ ok: false, error: "account-manager-unresolved" }, 403);
|
|
6071
|
+
}
|
|
6047
6072
|
console.error(`${TAG16} op=effective-account eventId=${eventId} effectiveAccount=${effectiveAccount2}`);
|
|
6048
6073
|
const sessionId2 = adminSessionIdFor(effectiveAccount2, destination);
|
|
6049
6074
|
const reply2 = (text) => deps.sendWhatsAppText(houseAccountId, destination, text);
|
|
6050
6075
|
try {
|
|
6051
6076
|
await deps.waHandleInbound({
|
|
6052
6077
|
accountId: houseAccountId,
|
|
6078
|
+
// Task 1383 — the router (ensureChannelSession) no longer re-resolves
|
|
6079
|
+
// the accountManagers map; it consumes this value. The scheduler
|
|
6080
|
+
// supplies its own resolution (effectiveAccountFor, computed above) so
|
|
6081
|
+
// a manager destination scopes the spawned session to the sub-account,
|
|
6082
|
+
// exactly as a real inbound now does via the gate.
|
|
6083
|
+
effectiveAccountId: effectiveAccount2,
|
|
6053
6084
|
senderId: destination,
|
|
6054
6085
|
role: "admin",
|
|
6055
6086
|
personId: null,
|
|
@@ -6093,7 +6124,7 @@ function createScheduleInjectRoutes(deps) {
|
|
|
6093
6124
|
console.error(`${TAG16} op=inject-spawn eventId=${eventId} sessionId=${sessionId} result=ok status=-`);
|
|
6094
6125
|
return c.json({ ok: true }, 200);
|
|
6095
6126
|
});
|
|
6096
|
-
return
|
|
6127
|
+
return app57;
|
|
6097
6128
|
}
|
|
6098
6129
|
|
|
6099
6130
|
// app/lib/telegram/outbound/send-text.ts
|
|
@@ -6120,7 +6151,7 @@ import { randomUUID as randomUUID6 } from "crypto";
|
|
|
6120
6151
|
|
|
6121
6152
|
// app/lib/whatsapp/config-persist.ts
|
|
6122
6153
|
import { readFileSync as readFileSync10, writeFileSync as writeFileSync4, existsSync as existsSync5 } from "fs";
|
|
6123
|
-
import { resolve as resolve8, join as join8 } from "path";
|
|
6154
|
+
import { resolve as resolve8, join as join8, dirname as dirname2, basename as basename2 } from "path";
|
|
6124
6155
|
var TAG17 = "[whatsapp:config]";
|
|
6125
6156
|
function configPath(accountDir) {
|
|
6126
6157
|
return resolve8(accountDir, "account.json");
|
|
@@ -6195,6 +6226,16 @@ function addAdminPhone(accountDir, phone) {
|
|
|
6195
6226
|
}
|
|
6196
6227
|
try {
|
|
6197
6228
|
const config = readConfig(accountDir);
|
|
6229
|
+
const targetId = typeof config.accountId === "string" && config.accountId ? config.accountId : basename2(resolve8(accountDir));
|
|
6230
|
+
const socketOwner = resolveHouseOrSoleAccountId(dirname2(resolve8(accountDir)));
|
|
6231
|
+
if (targetId !== socketOwner) {
|
|
6232
|
+
console.error(`${TAG17} add-admin-phone rejected accountId=${targetId} reason=not-socket-account`);
|
|
6233
|
+
return {
|
|
6234
|
+
ok: false,
|
|
6235
|
+
reason: "not-socket-account",
|
|
6236
|
+
error: `${targetId} does not own the WhatsApp paired socket, so its admin phones are never consulted. To route a phone to a sub-account, bind it as an account manager (add-account-manager) instead.`
|
|
6237
|
+
};
|
|
6238
|
+
}
|
|
6198
6239
|
if (!config.whatsapp || typeof config.whatsapp !== "object") {
|
|
6199
6240
|
config.whatsapp = {};
|
|
6200
6241
|
}
|
|
@@ -6270,6 +6311,44 @@ function readAdminPhones(accountDir) {
|
|
|
6270
6311
|
return [];
|
|
6271
6312
|
}
|
|
6272
6313
|
}
|
|
6314
|
+
function purgeNonSocketAdminPhones(accountDir, socketOwnerId) {
|
|
6315
|
+
try {
|
|
6316
|
+
const config = readConfig(accountDir);
|
|
6317
|
+
const wa = config.whatsapp;
|
|
6318
|
+
if (!wa || typeof wa !== "object") return { removed: [] };
|
|
6319
|
+
const targetId = typeof config.accountId === "string" && config.accountId ? config.accountId : basename2(resolve8(accountDir));
|
|
6320
|
+
if (targetId === socketOwnerId) return { removed: [] };
|
|
6321
|
+
const adminPhones = Array.isArray(wa.adminPhones) ? wa.adminPhones.filter((p) => typeof p === "string") : [];
|
|
6322
|
+
if (adminPhones.length === 0) return { removed: [] };
|
|
6323
|
+
delete wa.adminPhones;
|
|
6324
|
+
writeConfig(accountDir, config);
|
|
6325
|
+
for (const phone of adminPhones) {
|
|
6326
|
+
console.error(`[admin-identity] op=purge-nonsocket-adminphone accountId=${targetId} phone=${phone} removed=true`);
|
|
6327
|
+
}
|
|
6328
|
+
return { removed: adminPhones };
|
|
6329
|
+
} catch (err) {
|
|
6330
|
+
console.error(`[admin-identity] purge-nonsocket-adminphone failed dir=${accountDir}: ${String(err)}`);
|
|
6331
|
+
return { removed: [] };
|
|
6332
|
+
}
|
|
6333
|
+
}
|
|
6334
|
+
function purgeNonSocketAdminPhonesAtBoot() {
|
|
6335
|
+
let socketOwner;
|
|
6336
|
+
try {
|
|
6337
|
+
socketOwner = resolveHouseOrSoleAccountId(ACCOUNTS_DIR);
|
|
6338
|
+
} catch (err) {
|
|
6339
|
+
console.error(`[admin-identity] purge-nonsocket-adminphone skipped \u2014 cannot resolve socket owner: ${String(err)}`);
|
|
6340
|
+
return;
|
|
6341
|
+
}
|
|
6342
|
+
let accounts;
|
|
6343
|
+
try {
|
|
6344
|
+
accounts = listValidAccounts();
|
|
6345
|
+
} catch {
|
|
6346
|
+
return;
|
|
6347
|
+
}
|
|
6348
|
+
for (const acct of accounts) {
|
|
6349
|
+
purgeNonSocketAdminPhones(acct.accountDir, socketOwner);
|
|
6350
|
+
}
|
|
6351
|
+
}
|
|
6273
6352
|
function setAccountManager(accountDir, phone, subAccountId) {
|
|
6274
6353
|
const normalized = phone.trim();
|
|
6275
6354
|
if (!E164_PATTERN.test(normalized)) {
|
|
@@ -6798,7 +6877,7 @@ function listActiveLoginAccountIds() {
|
|
|
6798
6877
|
// app/lib/whatsapp/outbound/send-document.ts
|
|
6799
6878
|
import { realpathSync as realpathSync3 } from "fs";
|
|
6800
6879
|
import { readFile, stat as stat2 } from "fs/promises";
|
|
6801
|
-
import { resolve as resolve9, basename as
|
|
6880
|
+
import { resolve as resolve9, basename as basename3 } from "path";
|
|
6802
6881
|
var TAG19 = "[whatsapp:outbound]";
|
|
6803
6882
|
var WHATSAPP_DOCUMENT_MAX_BYTES = 100 * 1024 * 1024;
|
|
6804
6883
|
var lastDocumentOutboundAt = /* @__PURE__ */ new Map();
|
|
@@ -6833,7 +6912,7 @@ async function sendWhatsAppDocument(input) {
|
|
|
6833
6912
|
const accountResolved = realpathSync3(accountDir);
|
|
6834
6913
|
if (!resolvedPath.startsWith(accountResolved + "/")) {
|
|
6835
6914
|
const sanitised = filePath.replace(accountDir, "<account>/");
|
|
6836
|
-
console.error(`${TAG19} document REJECTED path=${sanitised} reason=outside_account_directory`);
|
|
6915
|
+
console.error(`${TAG19} document REJECTED path=${sanitised} reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
|
|
6837
6916
|
return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
|
|
6838
6917
|
}
|
|
6839
6918
|
} catch (err) {
|
|
@@ -6853,7 +6932,7 @@ async function sendWhatsAppDocument(input) {
|
|
|
6853
6932
|
error: `File exceeds 100 MB limit (${(fileStat.size / 1024 / 1024).toFixed(1)} MB)`
|
|
6854
6933
|
};
|
|
6855
6934
|
}
|
|
6856
|
-
const filename =
|
|
6935
|
+
const filename = basename3(resolvedPath);
|
|
6857
6936
|
const jid = normalizeJid2(to);
|
|
6858
6937
|
const sock = getSocket(accountId);
|
|
6859
6938
|
if (!sock) {
|
|
@@ -7142,7 +7221,8 @@ app2.post("/config", async (c) => {
|
|
|
7142
7221
|
return c.json({ ok: false, error: 'Missing required field "phone" (E.164 format, e.g. +441234567890).' }, 400);
|
|
7143
7222
|
}
|
|
7144
7223
|
const result = addAdminPhone(account.accountDir, phone);
|
|
7145
|
-
|
|
7224
|
+
const reasonTail = !result.ok && result.reason ? ` reason=${result.reason}` : "";
|
|
7225
|
+
console.error(`${TAG21} config action=add-admin-phone accountId=${account.accountId} phone=${phone} ok=${result.ok}${reasonTail}`);
|
|
7146
7226
|
return c.json(result, result.ok ? 200 : 400);
|
|
7147
7227
|
}
|
|
7148
7228
|
case "remove-admin-phone": {
|
|
@@ -7501,11 +7581,11 @@ var whatsapp_default = app2;
|
|
|
7501
7581
|
|
|
7502
7582
|
// server/routes/whatsapp-reader.ts
|
|
7503
7583
|
import { readFileSync as readFileSync15, watch, statSync as statSync5, openSync, readSync, closeSync, existsSync as existsSync8, readdirSync as readdirSync8, realpathSync as realpathSync4 } from "fs";
|
|
7504
|
-
import { basename as
|
|
7584
|
+
import { basename as basename5, dirname as dirname4, isAbsolute, join as join14, relative as relative2, resolve as resolve12, sep as sep3 } from "path";
|
|
7505
7585
|
|
|
7506
7586
|
// server/routes/admin/sidebar-sessions.ts
|
|
7507
7587
|
import { readdirSync as readdirSync5, readFileSync as readFileSync12, statSync as statSync3 } from "fs";
|
|
7508
|
-
import { basename as
|
|
7588
|
+
import { basename as basename4, dirname as dirname3, join as join11, resolve as resolve11 } from "path";
|
|
7509
7589
|
|
|
7510
7590
|
// app/lib/whatsapp-reader/select-sessions.ts
|
|
7511
7591
|
function isReaderChannelSession(role, channel) {
|
|
@@ -7586,7 +7666,7 @@ function findSessionProjectDir(sessionId) {
|
|
|
7586
7666
|
const cfg = claudeConfigDir();
|
|
7587
7667
|
if (!cfg) return null;
|
|
7588
7668
|
for (const { path: path2 } of enumerateJsonls(join11(cfg, "projects"))) {
|
|
7589
|
-
if (
|
|
7669
|
+
if (basename4(path2) === `${sessionId}.jsonl`) return dirname3(path2);
|
|
7590
7670
|
}
|
|
7591
7671
|
return null;
|
|
7592
7672
|
}
|
|
@@ -8315,8 +8395,8 @@ app4.get("/conversations", requireAdminSession, async (c) => {
|
|
|
8315
8395
|
const rows = [];
|
|
8316
8396
|
let sessionRowsExcludedUntagged = 0;
|
|
8317
8397
|
for (const { path: path2 } of enumerateJsonls(projectsRoot)) {
|
|
8318
|
-
const sessionId =
|
|
8319
|
-
const projectDir =
|
|
8398
|
+
const sessionId = basename5(path2).replace(/\.jsonl$/, "");
|
|
8399
|
+
const projectDir = dirname4(path2);
|
|
8320
8400
|
const meta = readSidecarMeta(join14(projectDir, `${sessionId}.meta.json`));
|
|
8321
8401
|
if (!isReaderChannelSession(meta.role, meta.channel)) continue;
|
|
8322
8402
|
if (multiAccount) {
|
|
@@ -8846,7 +8926,7 @@ var whatsapp_reader_default = app4;
|
|
|
8846
8926
|
|
|
8847
8927
|
// server/routes/public-reader.ts
|
|
8848
8928
|
import { statSync as statSync6, openSync as openSync2, readSync as readSync2, closeSync as closeSync2, watch as watch2, readFileSync as readFileSync16, readdirSync as readdirSync9 } from "fs";
|
|
8849
|
-
import { basename as
|
|
8929
|
+
import { basename as basename6, dirname as dirname5, join as join15, resolve as resolve13, sep as sep4 } from "path";
|
|
8850
8930
|
|
|
8851
8931
|
// app/lib/whatsapp-reader/delivered-kinds.ts
|
|
8852
8932
|
var PUBLIC_DELIVERED_KINDS = /* @__PURE__ */ new Set([
|
|
@@ -8921,8 +9001,8 @@ function enumeratePublicRows() {
|
|
|
8921
9001
|
if (!cfg) return [];
|
|
8922
9002
|
const rows = [];
|
|
8923
9003
|
for (const { path: path2 } of enumerateJsonls(join15(cfg, "projects"))) {
|
|
8924
|
-
const sessionId =
|
|
8925
|
-
const projectDir =
|
|
9004
|
+
const sessionId = basename6(path2).replace(/\.jsonl$/, "");
|
|
9005
|
+
const projectDir = dirname5(path2);
|
|
8926
9006
|
const meta = readSidecarMeta(join15(projectDir, `${sessionId}.meta.json`));
|
|
8927
9007
|
rows.push({
|
|
8928
9008
|
sessionId,
|
|
@@ -9140,7 +9220,7 @@ app5.get("/attachment/:attachmentId", (c) => {
|
|
|
9140
9220
|
var public_reader_default = app5;
|
|
9141
9221
|
|
|
9142
9222
|
// server/routes/webchat.ts
|
|
9143
|
-
import { basename as
|
|
9223
|
+
import { basename as basename7, dirname as dirname6 } from "path";
|
|
9144
9224
|
import { join as join18 } from "path";
|
|
9145
9225
|
import { existsSync as existsSync10, readdirSync as readdirSync11, readFileSync as readFileSync19, renameSync as renameSync3, statSync as statSync7, writeFileSync as writeFileSync7 } from "fs";
|
|
9146
9226
|
|
|
@@ -9538,8 +9618,8 @@ function latestAdminWebchatSessionId(requesterUserId, primaryUserId, scopeAccoun
|
|
|
9538
9618
|
let best = null;
|
|
9539
9619
|
for (const { path: path2, isSubagent, archived } of enumerateJsonls(join18(cfg, "projects"))) {
|
|
9540
9620
|
if (isSubagent || archived) continue;
|
|
9541
|
-
const id =
|
|
9542
|
-
const meta = readSidecarMeta(join18(
|
|
9621
|
+
const id = basename7(path2).slice(0, -".jsonl".length);
|
|
9622
|
+
const meta = readSidecarMeta(join18(dirname6(path2), `${id}.meta.json`));
|
|
9543
9623
|
if (meta.role !== "admin" || meta.channel !== "webchat") continue;
|
|
9544
9624
|
if (multiAccount && meta.accountId !== scopeAccountId) continue;
|
|
9545
9625
|
let mtimeMs;
|
|
@@ -9562,7 +9642,7 @@ function latestAdminWebchatSessionId(requesterUserId, primaryUserId, scopeAccoun
|
|
|
9562
9642
|
function overrideKnownNonArchived(id) {
|
|
9563
9643
|
const { projectDir } = locateSession(id);
|
|
9564
9644
|
if (projectDir === null) return sessionSidecarExists(id);
|
|
9565
|
-
return
|
|
9645
|
+
return basename7(projectDir) !== "archive";
|
|
9566
9646
|
}
|
|
9567
9647
|
function resolveCanonical(accountId, accountDir, requesterUserId, primaryUserId, scopeAccountId, multiAccount) {
|
|
9568
9648
|
const bootstrapAccountId = scopeAccountId ?? accountId;
|
|
@@ -9598,8 +9678,8 @@ async function reapplyLeversViaManager() {
|
|
|
9598
9678
|
var WEBCHAT_SEND_TURN_WINDOW_MS = Number(process.env.WEBCHAT_SEND_TURN_WINDOW_MS ?? String(15e3));
|
|
9599
9679
|
var sendSeq = 0;
|
|
9600
9680
|
function createWebchatRoutes(deps) {
|
|
9601
|
-
const
|
|
9602
|
-
|
|
9681
|
+
const app57 = new Hono();
|
|
9682
|
+
app57.post("/send", requireAdminSession, async (c) => {
|
|
9603
9683
|
let accountId;
|
|
9604
9684
|
try {
|
|
9605
9685
|
accountId = resolvePlatformAccountId();
|
|
@@ -9799,7 +9879,7 @@ ${note}` : note;
|
|
|
9799
9879
|
if (turnTimer.unref) turnTimer.unref();
|
|
9800
9880
|
return c.json({ ok: true });
|
|
9801
9881
|
});
|
|
9802
|
-
|
|
9882
|
+
app57.post("/interrupt", requireAdminSession, async (c) => {
|
|
9803
9883
|
const cacheKey = c.get("cacheKey");
|
|
9804
9884
|
const requesterUserId = (cacheKey ? getUserIdForSession(cacheKey) : void 0) ?? null;
|
|
9805
9885
|
const primaryUserId = resolvePrimaryAdminUserId();
|
|
@@ -9827,7 +9907,7 @@ ${note}` : note;
|
|
|
9827
9907
|
}
|
|
9828
9908
|
return c.json({ ok: true, stopped: outcome.stopped, intId: outcome.intId, deadChild: outcome.deadChild }, 200);
|
|
9829
9909
|
});
|
|
9830
|
-
|
|
9910
|
+
app57.post("/settings", requireAdminSession, async (c) => {
|
|
9831
9911
|
const body = await c.req.json().catch(() => null);
|
|
9832
9912
|
const op = body?.op;
|
|
9833
9913
|
const value = body?.value;
|
|
@@ -9867,7 +9947,7 @@ ${note}` : note;
|
|
|
9867
9947
|
console.log(`[webchat:settings] op=${op} outcome=accepted value=${value} settingsApplied=${settingsApplied}`);
|
|
9868
9948
|
return c.json({ ok: true, settingsApplied });
|
|
9869
9949
|
});
|
|
9870
|
-
|
|
9950
|
+
app57.get("/session", requireAdminSession, async (c) => {
|
|
9871
9951
|
let accountId;
|
|
9872
9952
|
try {
|
|
9873
9953
|
accountId = resolvePlatformAccountId();
|
|
@@ -9930,8 +10010,8 @@ ${note}` : note;
|
|
|
9930
10010
|
let projectDir = null;
|
|
9931
10011
|
if (cfg) {
|
|
9932
10012
|
for (const { path: path2 } of enumerateJsonls(join18(cfg, "projects"))) {
|
|
9933
|
-
if (
|
|
9934
|
-
projectDir =
|
|
10013
|
+
if (basename7(path2) === `${sessionId}.jsonl`) {
|
|
10014
|
+
projectDir = dirname6(path2);
|
|
9935
10015
|
break;
|
|
9936
10016
|
}
|
|
9937
10017
|
}
|
|
@@ -9945,7 +10025,7 @@ ${note}` : note;
|
|
|
9945
10025
|
const indicators = await fetchComposerIndicators(sessionId);
|
|
9946
10026
|
return c.json({ sessionId, projectDir, sizeBytes: jsonlSizeBytes(projectDir, sessionId), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${sessionId}`) ?? null, deliveryFailure: deps.deliveryFailureFor?.(`session:${sessionId}`) ?? null, ...indicators, ...readLevers(account) });
|
|
9947
10027
|
});
|
|
9948
|
-
|
|
10028
|
+
app57.post("/permission-verdict", requireAdminSession, async (c) => {
|
|
9949
10029
|
const body = await c.req.json().catch(() => null);
|
|
9950
10030
|
const sessionId = body?.sessionId;
|
|
9951
10031
|
const requestId = body?.request_id;
|
|
@@ -9962,7 +10042,7 @@ ${note}` : note;
|
|
|
9962
10042
|
const ok = deps.resolvePermissionVerdict?.(`session:${sessionId}`, requestId, behavior) ?? false;
|
|
9963
10043
|
return c.json({ ok });
|
|
9964
10044
|
});
|
|
9965
|
-
return
|
|
10045
|
+
return app57;
|
|
9966
10046
|
}
|
|
9967
10047
|
|
|
9968
10048
|
// server/routes/webchat-greeting.ts
|
|
@@ -10369,7 +10449,7 @@ import { createHash as createHash3, randomUUID as randomUUID7 } from "crypto";
|
|
|
10369
10449
|
|
|
10370
10450
|
// ../lib/admins-write/src/index.ts
|
|
10371
10451
|
import { existsSync as existsSync14, readFileSync as readFileSync23, writeFileSync as writeFileSync9, renameSync as renameSync5, mkdirSync as mkdirSync5, readdirSync as readdirSync13, statSync as statSync8, appendFileSync as appendFileSync2 } from "fs";
|
|
10372
|
-
import { dirname as
|
|
10452
|
+
import { dirname as dirname7, join as join22 } from "path";
|
|
10373
10453
|
function id8(value) {
|
|
10374
10454
|
return value.slice(0, 8);
|
|
10375
10455
|
}
|
|
@@ -10382,7 +10462,7 @@ function appendUsersAuditLine(audit, fields) {
|
|
|
10382
10462
|
const line = `[users-audit] action=${fields.action} actor=${actor}${sess} field=${fields.field} rowsBefore=${fields.rowsBefore} rowsAfter=${fields.rowsAfter} ts=${(/* @__PURE__ */ new Date()).toISOString()}
|
|
10383
10463
|
`;
|
|
10384
10464
|
try {
|
|
10385
|
-
mkdirSync5(
|
|
10465
|
+
mkdirSync5(dirname7(audit.logFile), { recursive: true, mode: 448 });
|
|
10386
10466
|
appendFileSync2(audit.logFile, line, { mode: 384 });
|
|
10387
10467
|
} catch (err) {
|
|
10388
10468
|
console.error(
|
|
@@ -10400,7 +10480,7 @@ function logLine(input, result) {
|
|
|
10400
10480
|
);
|
|
10401
10481
|
}
|
|
10402
10482
|
function writeFileAtomic(filePath, contents, mode) {
|
|
10403
|
-
mkdirSync5(
|
|
10483
|
+
mkdirSync5(dirname7(filePath), { recursive: true });
|
|
10404
10484
|
const tempPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
|
|
10405
10485
|
writeFileSync9(tempPath, contents, mode !== void 0 ? { mode } : void 0);
|
|
10406
10486
|
renameSync5(tempPath, filePath);
|
|
@@ -11249,7 +11329,7 @@ var accounts_default = app12;
|
|
|
11249
11329
|
|
|
11250
11330
|
// server/routes/admin/logs.ts
|
|
11251
11331
|
import { existsSync as existsSync18, readdirSync as readdirSync14, readFileSync as readFileSync25, statSync as statSync10 } from "fs";
|
|
11252
|
-
import { resolve as resolve16, basename as
|
|
11332
|
+
import { resolve as resolve16, basename as basename8 } from "path";
|
|
11253
11333
|
|
|
11254
11334
|
// app/lib/logs-read-resolve.ts
|
|
11255
11335
|
import { existsSync as existsSync17 } from "fs";
|
|
@@ -11281,7 +11361,7 @@ app13.get("/", async (c) => {
|
|
|
11281
11361
|
if (accountLogDir) logDirs.push(accountLogDir);
|
|
11282
11362
|
logDirs.push(LOG_DIR);
|
|
11283
11363
|
if (fileParam) {
|
|
11284
|
-
const safe =
|
|
11364
|
+
const safe = basename8(fileParam);
|
|
11285
11365
|
const searched = [];
|
|
11286
11366
|
for (const dir of logDirs) {
|
|
11287
11367
|
const filePath = resolve16(dir, safe);
|
|
@@ -11351,7 +11431,7 @@ app13.get("/", async (c) => {
|
|
|
11351
11431
|
if (hit) {
|
|
11352
11432
|
console.info(`[admin/logs] resolved cacheKey=${cacheKeySlice} sessionId=${sessionIdSlice} via=${primaryId === cacheKey ? "cacheKey" : primaryId === sessionKeyFromConv ? "reverse-lookup" : "sessionId-fallback"}`);
|
|
11353
11433
|
try {
|
|
11354
|
-
const filename =
|
|
11434
|
+
const filename = basename8(hit.path);
|
|
11355
11435
|
const buffer = readFileSync25(hit.path);
|
|
11356
11436
|
const onDiskBytes = statSync10(hit.path).size;
|
|
11357
11437
|
const headers = {
|
|
@@ -12285,7 +12365,7 @@ var sessions_default = app17;
|
|
|
12285
12365
|
|
|
12286
12366
|
// app/lib/claude-agent/spawn-context.ts
|
|
12287
12367
|
import { existsSync as existsSync22, readFileSync as readFileSync27, readdirSync as readdirSync16, statSync as statSync11 } from "fs";
|
|
12288
|
-
import { dirname as
|
|
12368
|
+
import { dirname as dirname8, resolve as resolve19, join as join25 } from "path";
|
|
12289
12369
|
async function resolveOwnerProfileBlock(accountId, userId) {
|
|
12290
12370
|
if (!userId) return { ok: false, reason: "missing-user-id" };
|
|
12291
12371
|
try {
|
|
@@ -12392,7 +12472,7 @@ function listPluginDirs() {
|
|
|
12392
12472
|
}
|
|
12393
12473
|
}
|
|
12394
12474
|
}
|
|
12395
|
-
const premiumRoot = resolve19(
|
|
12475
|
+
const premiumRoot = resolve19(dirname8(PLATFORM_ROOT), "premium-plugins");
|
|
12396
12476
|
if (existsSync22(premiumRoot)) {
|
|
12397
12477
|
for (const bundle of readdirSync16(premiumRoot)) {
|
|
12398
12478
|
const bundlePlugins = join25(premiumRoot, bundle, "plugins");
|
|
@@ -12841,7 +12921,7 @@ import { createReadStream as createReadStream2, createWriteStream as createWrite
|
|
|
12841
12921
|
import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3, unlink as unlink2, rename } from "fs/promises";
|
|
12842
12922
|
import { realpathSync as realpathSync5 } from "fs";
|
|
12843
12923
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
12844
|
-
import { basename as
|
|
12924
|
+
import { basename as basename10, dirname as dirname9, join as join27, relative as relative4, resolve as resolve22, sep as sep6 } from "path";
|
|
12845
12925
|
import { Readable as Readable2 } from "stream";
|
|
12846
12926
|
|
|
12847
12927
|
// ../lib/graph-trash/src/index.ts
|
|
@@ -13159,7 +13239,7 @@ async function cascadeDeleteDocument(params) {
|
|
|
13159
13239
|
|
|
13160
13240
|
// app/lib/file-index.ts
|
|
13161
13241
|
import * as fsp from "fs/promises";
|
|
13162
|
-
import { resolve as resolve21, relative as relative3, join as join26, basename as
|
|
13242
|
+
import { resolve as resolve21, relative as relative3, join as join26, basename as basename9, extname as extname2, sep as sep5 } from "path";
|
|
13163
13243
|
import { tmpdir as tmpdir2 } from "os";
|
|
13164
13244
|
import { execFile as execFile2 } from "child_process";
|
|
13165
13245
|
import { promisify as promisify2 } from "util";
|
|
@@ -13297,8 +13377,8 @@ async function extractFileContent(absolute) {
|
|
|
13297
13377
|
}
|
|
13298
13378
|
}
|
|
13299
13379
|
async function readDisplayName(absolute) {
|
|
13300
|
-
const dir = absolute.slice(0, absolute.length -
|
|
13301
|
-
const base =
|
|
13380
|
+
const dir = absolute.slice(0, absolute.length - basename9(absolute).length);
|
|
13381
|
+
const base = basename9(absolute);
|
|
13302
13382
|
const dot = base.lastIndexOf(".");
|
|
13303
13383
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
13304
13384
|
if (base === `${stem}.meta.json`) return null;
|
|
@@ -13436,7 +13516,7 @@ async function cascadeTrashLinkedKnowledgeDocs(session, accountId, relativePaths
|
|
|
13436
13516
|
return { kds, sections, chunks };
|
|
13437
13517
|
}
|
|
13438
13518
|
async function buildArtifact(accountId, wf, embed2) {
|
|
13439
|
-
const name =
|
|
13519
|
+
const name = basename9(wf.absolute);
|
|
13440
13520
|
const { content, route } = await extractFileContent(wf.absolute);
|
|
13441
13521
|
const displayName = await readDisplayName(wf.absolute);
|
|
13442
13522
|
const embedInput = `${name}
|
|
@@ -13966,7 +14046,7 @@ app21.get("/download", requireAdminSession, async (c) => {
|
|
|
13966
14046
|
if (!info.isFile()) {
|
|
13967
14047
|
return c.json({ error: "Path is not a file" }, 400);
|
|
13968
14048
|
}
|
|
13969
|
-
const filename =
|
|
14049
|
+
const filename = basename10(absolute);
|
|
13970
14050
|
const mimeType = detectMimeType(absolute);
|
|
13971
14051
|
const nodeStream = createReadStream2(absolute);
|
|
13972
14052
|
const webStream = Readable2.toWeb(nodeStream);
|
|
@@ -14071,7 +14151,7 @@ app21.get("/download-zip", requireAdminSession, async (c) => {
|
|
|
14071
14151
|
const info = await stat4(absolute);
|
|
14072
14152
|
if (info.isDirectory()) {
|
|
14073
14153
|
dirsWalked++;
|
|
14074
|
-
const parentAbs =
|
|
14154
|
+
const parentAbs = dirname9(absolute);
|
|
14075
14155
|
for await (const fileAbs of walkRegularFiles(absolute)) {
|
|
14076
14156
|
const within = relative4(absolute, fileAbs).split(sep6).join("/");
|
|
14077
14157
|
const fileRel = relPath === "" || relPath === "." ? within : `${relPath}/${within}`;
|
|
@@ -14082,7 +14162,7 @@ app21.get("/download-zip", requireAdminSession, async (c) => {
|
|
|
14082
14162
|
if (over) return over;
|
|
14083
14163
|
}
|
|
14084
14164
|
} else if (info.isFile()) {
|
|
14085
|
-
const over = await addFile(absolute, info.size,
|
|
14165
|
+
const over = await addFile(absolute, info.size, basename10(absolute));
|
|
14086
14166
|
if (over) return over;
|
|
14087
14167
|
} else {
|
|
14088
14168
|
return c.json({ error: "Path is not a file or directory" }, 400);
|
|
@@ -14111,12 +14191,12 @@ function dataUploadCeiling() {
|
|
|
14111
14191
|
}
|
|
14112
14192
|
async function resolveUploadTarget(c, accountId, uid) {
|
|
14113
14193
|
const rawName = c.req.query("filename") ?? "";
|
|
14114
|
-
const safeName =
|
|
14194
|
+
const safeName = basename10(rawName).replace(/[\0/\\]/g, "_");
|
|
14115
14195
|
if (!safeName) return { ok: false, status: 400, error: "filename query param required" };
|
|
14116
14196
|
const rawRelpath = c.req.query("relpath") ?? "";
|
|
14117
14197
|
const relpath = rawRelpath !== "" ? rawRelpath : null;
|
|
14118
14198
|
const token = c.req.query("token") ?? "";
|
|
14119
|
-
const finalName = relpath ?
|
|
14199
|
+
const finalName = relpath ? basename10(relpath).replace(/[\0/\\]/g, "_") : `${Date.now()}-${safeName}`;
|
|
14120
14200
|
const mimeType = (c.req.header("content-type") ?? "").split(";")[0].trim();
|
|
14121
14201
|
if (!SUPPORTED_MIME_TYPES.has(mimeType)) {
|
|
14122
14202
|
console.error(`[data-upload] op=reject-mime uid=${uid} mime="${mimeType}" token=${token} rel="${relpath ?? ""}"`);
|
|
@@ -14125,7 +14205,7 @@ async function resolveUploadTarget(c, accountId, uid) {
|
|
|
14125
14205
|
const rawDir = c.req.query("path") ?? "";
|
|
14126
14206
|
const base = resolveOwnAccountWrite(rawDir, accountId, "POST /api/admin/files/upload");
|
|
14127
14207
|
if (!base.ok) return { ok: false, status: base.status, error: base.error };
|
|
14128
|
-
const relDir = relpath ?
|
|
14208
|
+
const relDir = relpath ? dirname9(relpath) : ".";
|
|
14129
14209
|
const destRel = relDir === "." ? base.relative : join27(base.relative, relDir);
|
|
14130
14210
|
if (crossesForeignAccountPartition(destRel, accountId)) {
|
|
14131
14211
|
console.error(`[data] account-scope-blocked endpoint="POST /api/admin/files/upload" path="${destRel}" account=${accountId.slice(0, 8)}\u2026`);
|
|
@@ -14486,7 +14566,7 @@ app21.delete("/", requireAdminSession, async (c) => {
|
|
|
14486
14566
|
console.error(`[data] account-scope-blocked endpoint="DELETE /api/admin/files" path="${relPath}" account=${accountId.slice(0, 8)}\u2026`);
|
|
14487
14567
|
return c.json({ error: "Not found" }, 404);
|
|
14488
14568
|
}
|
|
14489
|
-
const base =
|
|
14569
|
+
const base = basename10(absolute);
|
|
14490
14570
|
const protection = isProtectedFromDeletion(relPath);
|
|
14491
14571
|
if (protection.protected) {
|
|
14492
14572
|
console.error(`[data] file-delete blocked path="${relPath}" reason="protected" rule="${protection.rule}"`);
|
|
@@ -14502,7 +14582,7 @@ app21.delete("/", requireAdminSession, async (c) => {
|
|
|
14502
14582
|
}
|
|
14503
14583
|
const dot = base.lastIndexOf(".");
|
|
14504
14584
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
14505
|
-
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join27(
|
|
14585
|
+
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join27(dirname9(absolute), `${stem}.meta.json`) : null;
|
|
14506
14586
|
await unlink2(absolute);
|
|
14507
14587
|
if (sidecarPath) {
|
|
14508
14588
|
try {
|
|
@@ -14598,8 +14678,8 @@ app21.post("/rename", requireAdminSession, async (c) => {
|
|
|
14598
14678
|
console.error(`[data] file-rename blocked path="${src.relative}" reason="protected"`);
|
|
14599
14679
|
return c.json({ error: "Protected entry \u2014 refusing to rename" }, 403);
|
|
14600
14680
|
}
|
|
14601
|
-
const destAbs = resolve22(
|
|
14602
|
-
const newRel = `${
|
|
14681
|
+
const destAbs = resolve22(dirname9(src.absolute), newName);
|
|
14682
|
+
const newRel = `${dirname9(src.relative)}/${newName}`.replace(/^\.\//, "");
|
|
14603
14683
|
if (isProtectedFromRename(newRel)) {
|
|
14604
14684
|
console.error(`[data] file-rename blocked path="${newRel}" reason="protected-target"`);
|
|
14605
14685
|
return c.json({ error: "That name is reserved" }, 403);
|
|
@@ -16730,7 +16810,7 @@ var graph_default_view_default = app27;
|
|
|
16730
16810
|
|
|
16731
16811
|
// server/routes/admin/sidebar-artefacts.ts
|
|
16732
16812
|
import { readdir as readdir4, stat as stat5 } from "fs/promises";
|
|
16733
|
-
import { resolve as resolve23, relative as relative5, isAbsolute as isAbsolute2, sep as sep7, basename as
|
|
16813
|
+
import { resolve as resolve23, relative as relative5, isAbsolute as isAbsolute2, sep as sep7, basename as basename11 } from "path";
|
|
16734
16814
|
import { existsSync as existsSync25 } from "fs";
|
|
16735
16815
|
var LIMIT = 50;
|
|
16736
16816
|
var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
|
|
@@ -16783,7 +16863,7 @@ async function fetchAccountFileArtefacts(accountId) {
|
|
|
16783
16863
|
const modifiedAt = r.get("modifiedAt") ?? "";
|
|
16784
16864
|
return {
|
|
16785
16865
|
id: `account-file:${relativePath}`,
|
|
16786
|
-
name: displayName ??
|
|
16866
|
+
name: displayName ?? basename11(relativePath),
|
|
16787
16867
|
kind: "account-file",
|
|
16788
16868
|
updatedAt: modifiedAt,
|
|
16789
16869
|
mimeType,
|
|
@@ -17071,6 +17151,36 @@ app32.post("/", requireAdminSession, async (c) => {
|
|
|
17071
17151
|
});
|
|
17072
17152
|
var session_rename_default = app32;
|
|
17073
17153
|
|
|
17154
|
+
// server/routes/admin/session-usage.ts
|
|
17155
|
+
var app33 = new Hono();
|
|
17156
|
+
app33.get("/", requireAdminSession, async (c) => {
|
|
17157
|
+
const sessionId = c.req.query("sessionId") ?? "";
|
|
17158
|
+
if (!SESSION_ID_RE2.test(sessionId)) {
|
|
17159
|
+
return c.json({ error: "sessionId must be a v4 UUID" }, 400);
|
|
17160
|
+
}
|
|
17161
|
+
let res;
|
|
17162
|
+
try {
|
|
17163
|
+
res = await fetch(`${managerBase("session-usage:wrapper")}/${sessionId}/metering`);
|
|
17164
|
+
} catch (err) {
|
|
17165
|
+
console.error(`[session-usage] sessionId=${sessionId.slice(0, 8)} manager-unreachable err=${err instanceof Error ? err.message : String(err)}`);
|
|
17166
|
+
return c.json({ error: "manager-unreachable" }, 502);
|
|
17167
|
+
}
|
|
17168
|
+
if (res.status === 200) {
|
|
17169
|
+
const summary = await res.json().catch(() => null);
|
|
17170
|
+
if (!summary) {
|
|
17171
|
+
console.error(`[session-usage] sessionId=${sessionId.slice(0, 8)} manager-bad-json`);
|
|
17172
|
+
return c.json({ error: "manager-bad-json" }, 502);
|
|
17173
|
+
}
|
|
17174
|
+
return c.json(summary);
|
|
17175
|
+
}
|
|
17176
|
+
if (res.status === 404) {
|
|
17177
|
+
return c.json({ error: "session-not-found" }, 404);
|
|
17178
|
+
}
|
|
17179
|
+
console.error(`[session-usage] sessionId=${sessionId.slice(0, 8)} manager-status=${res.status}`);
|
|
17180
|
+
return c.json({ error: `manager-status-${res.status}` }, 502);
|
|
17181
|
+
});
|
|
17182
|
+
var session_usage_default = app33;
|
|
17183
|
+
|
|
17074
17184
|
// server/routes/admin/session-rc-spawn.ts
|
|
17075
17185
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
17076
17186
|
var ACCOUNT_UUID_RE2 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
@@ -17116,8 +17226,8 @@ function shapeWebchatResponse(sessionId, manager) {
|
|
|
17116
17226
|
const landed = redirected ? manager.sessionId : sessionId;
|
|
17117
17227
|
return { sessionId: landed, outcome, target: `/chat?session=${landed}` };
|
|
17118
17228
|
}
|
|
17119
|
-
var
|
|
17120
|
-
|
|
17229
|
+
var app34 = new Hono();
|
|
17230
|
+
app34.post("/", requireAdminSession, async (c) => {
|
|
17121
17231
|
let body;
|
|
17122
17232
|
try {
|
|
17123
17233
|
body = await c.req.json();
|
|
@@ -17200,7 +17310,7 @@ app33.post("/", requireAdminSession, async (c) => {
|
|
|
17200
17310
|
}
|
|
17201
17311
|
return c.json(parsed ?? {});
|
|
17202
17312
|
});
|
|
17203
|
-
var session_rc_spawn_default =
|
|
17313
|
+
var session_rc_spawn_default = app34;
|
|
17204
17314
|
|
|
17205
17315
|
// server/routes/admin/session-reseat.ts
|
|
17206
17316
|
import { randomUUID as randomUUID11 } from "crypto";
|
|
@@ -17223,9 +17333,9 @@ function resolveReseatPlan(body, mintId = randomUUID11, adminUserId, authenticat
|
|
|
17223
17333
|
if (authenticatedName) payload.authenticatedName = authenticatedName;
|
|
17224
17334
|
return { sessionId, payload };
|
|
17225
17335
|
}
|
|
17226
|
-
var
|
|
17336
|
+
var app35 = new Hono();
|
|
17227
17337
|
var reseatsInFlight = /* @__PURE__ */ new Set();
|
|
17228
|
-
|
|
17338
|
+
app35.post("/", requireAdminSession, async (c) => {
|
|
17229
17339
|
let body;
|
|
17230
17340
|
try {
|
|
17231
17341
|
body = await c.req.json();
|
|
@@ -17313,7 +17423,7 @@ app34.post("/", requireAdminSession, async (c) => {
|
|
|
17313
17423
|
reseatsInFlight.delete(fromSessionId);
|
|
17314
17424
|
}
|
|
17315
17425
|
});
|
|
17316
|
-
var session_reseat_default =
|
|
17426
|
+
var session_reseat_default = app35;
|
|
17317
17427
|
|
|
17318
17428
|
// server/routes/admin/system-stats.ts
|
|
17319
17429
|
import { readFile as readFile5 } from "fs/promises";
|
|
@@ -17410,8 +17520,8 @@ async function sample() {
|
|
|
17410
17520
|
if (process.platform === "linux") return sampleLinux();
|
|
17411
17521
|
return sampleOsFallback();
|
|
17412
17522
|
}
|
|
17413
|
-
var
|
|
17414
|
-
|
|
17523
|
+
var app36 = new Hono();
|
|
17524
|
+
app36.get("/", async (c) => {
|
|
17415
17525
|
const started = Date.now();
|
|
17416
17526
|
if (!inflight) {
|
|
17417
17527
|
inflight = sample().finally(() => {
|
|
@@ -17434,7 +17544,7 @@ app35.get("/", async (c) => {
|
|
|
17434
17544
|
return c.json({ degraded: true, reason, sampledAtMs: Date.now() });
|
|
17435
17545
|
}
|
|
17436
17546
|
});
|
|
17437
|
-
var system_stats_default =
|
|
17547
|
+
var system_stats_default = app36;
|
|
17438
17548
|
|
|
17439
17549
|
// server/routes/admin/health.ts
|
|
17440
17550
|
import { existsSync as existsSync26, readFileSync as readFileSync29 } from "fs";
|
|
@@ -17479,8 +17589,8 @@ async function probeConversationDb() {
|
|
|
17479
17589
|
});
|
|
17480
17590
|
}
|
|
17481
17591
|
}
|
|
17482
|
-
var
|
|
17483
|
-
|
|
17592
|
+
var app37 = new Hono();
|
|
17593
|
+
app37.get("/", async (c) => {
|
|
17484
17594
|
const version = readVersion();
|
|
17485
17595
|
const probe = await probeConversationDb();
|
|
17486
17596
|
const uptimeMs = Date.now() - new Date(PROCESS_STARTED_AT).getTime();
|
|
@@ -17502,7 +17612,7 @@ app36.get("/", async (c) => {
|
|
|
17502
17612
|
uptimeMs
|
|
17503
17613
|
});
|
|
17504
17614
|
});
|
|
17505
|
-
var health_default2 =
|
|
17615
|
+
var health_default2 = app37;
|
|
17506
17616
|
|
|
17507
17617
|
// server/routes/admin/linkedin-ingest.ts
|
|
17508
17618
|
import { randomUUID as randomUUID12 } from "crypto";
|
|
@@ -17728,8 +17838,8 @@ function buildInitialMessage(env) {
|
|
|
17728
17838
|
}
|
|
17729
17839
|
return header;
|
|
17730
17840
|
}
|
|
17731
|
-
var
|
|
17732
|
-
|
|
17841
|
+
var app38 = new Hono();
|
|
17842
|
+
app38.post("/", requireAdminSession, async (c) => {
|
|
17733
17843
|
let body;
|
|
17734
17844
|
try {
|
|
17735
17845
|
body = await c.req.json();
|
|
@@ -17774,7 +17884,7 @@ app37.post("/", requireAdminSession, async (c) => {
|
|
|
17774
17884
|
);
|
|
17775
17885
|
return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: spawned.sessionId }, 202);
|
|
17776
17886
|
});
|
|
17777
|
-
var linkedin_ingest_default =
|
|
17887
|
+
var linkedin_ingest_default = app38;
|
|
17778
17888
|
|
|
17779
17889
|
// server/routes/admin/post-turn-context.ts
|
|
17780
17890
|
import neo4j3 from "neo4j-driver";
|
|
@@ -17816,8 +17926,8 @@ function pruneProperties(raw) {
|
|
|
17816
17926
|
}
|
|
17817
17927
|
return out;
|
|
17818
17928
|
}
|
|
17819
|
-
var
|
|
17820
|
-
|
|
17929
|
+
var app39 = new Hono();
|
|
17930
|
+
app39.get("/", async (c) => {
|
|
17821
17931
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
17822
17932
|
if (!isLoopbackAddr3(remoteAddr)) {
|
|
17823
17933
|
console.error(`${TAG28} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -17877,7 +17987,7 @@ app38.get("/", async (c) => {
|
|
|
17877
17987
|
await session.close();
|
|
17878
17988
|
}
|
|
17879
17989
|
});
|
|
17880
|
-
var post_turn_context_default =
|
|
17990
|
+
var post_turn_context_default = app39;
|
|
17881
17991
|
|
|
17882
17992
|
// app/lib/slice-writes.ts
|
|
17883
17993
|
import neo4j4 from "neo4j-driver";
|
|
@@ -17987,8 +18097,8 @@ var TAG29 = "[public-session-context]";
|
|
|
17987
18097
|
function isLoopbackAddr4(addr) {
|
|
17988
18098
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
17989
18099
|
}
|
|
17990
|
-
var
|
|
17991
|
-
|
|
18100
|
+
var app40 = new Hono();
|
|
18101
|
+
app40.get("/", async (c) => {
|
|
17992
18102
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
17993
18103
|
if (!isLoopbackAddr4(remoteAddr)) {
|
|
17994
18104
|
console.error(`${TAG29} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -18028,7 +18138,7 @@ app39.get("/", async (c) => {
|
|
|
18028
18138
|
await session.close();
|
|
18029
18139
|
}
|
|
18030
18140
|
});
|
|
18031
|
-
var public_session_context_default =
|
|
18141
|
+
var public_session_context_default = app40;
|
|
18032
18142
|
|
|
18033
18143
|
// app/lib/webchat/gateway/instance.ts
|
|
18034
18144
|
var instance2 = null;
|
|
@@ -18044,8 +18154,8 @@ var TAG30 = "[public-session-exit-route]";
|
|
|
18044
18154
|
function isLoopbackAddr5(addr) {
|
|
18045
18155
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
18046
18156
|
}
|
|
18047
|
-
var
|
|
18048
|
-
|
|
18157
|
+
var app41 = new Hono();
|
|
18158
|
+
app41.post("/", async (c) => {
|
|
18049
18159
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
18050
18160
|
if (!isLoopbackAddr5(remoteAddr)) {
|
|
18051
18161
|
console.error(`${TAG30} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -18077,15 +18187,15 @@ app40.post("/", async (c) => {
|
|
|
18077
18187
|
gateway.handlePublicSessionExit(sessionId);
|
|
18078
18188
|
return c.json({ ok: true });
|
|
18079
18189
|
});
|
|
18080
|
-
var public_session_exit_default =
|
|
18190
|
+
var public_session_exit_default = app41;
|
|
18081
18191
|
|
|
18082
18192
|
// server/routes/admin/access-session-evict.ts
|
|
18083
18193
|
var TAG31 = "[access-session-evict]";
|
|
18084
18194
|
function isLoopbackAddr6(addr) {
|
|
18085
18195
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
18086
18196
|
}
|
|
18087
|
-
var
|
|
18088
|
-
|
|
18197
|
+
var app42 = new Hono();
|
|
18198
|
+
app42.post("/", async (c) => {
|
|
18089
18199
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
18090
18200
|
if (!isLoopbackAddr6(remoteAddr)) {
|
|
18091
18201
|
console.error(`${TAG31} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -18113,7 +18223,7 @@ app41.post("/", async (c) => {
|
|
|
18113
18223
|
console.log(`${TAG31} grantId=${grantId} dropped=${dropped}`);
|
|
18114
18224
|
return c.json({ ok: true, dropped });
|
|
18115
18225
|
});
|
|
18116
|
-
var access_session_evict_default =
|
|
18226
|
+
var access_session_evict_default = app42;
|
|
18117
18227
|
|
|
18118
18228
|
// server/routes/admin/enrol-person.ts
|
|
18119
18229
|
var TAG32 = "[enrol]";
|
|
@@ -18121,8 +18231,8 @@ function isLoopbackAddr7(addr) {
|
|
|
18121
18231
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
18122
18232
|
}
|
|
18123
18233
|
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
18124
|
-
var
|
|
18125
|
-
|
|
18234
|
+
var app43 = new Hono();
|
|
18235
|
+
app43.post("/", async (c) => {
|
|
18126
18236
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
18127
18237
|
if (!isLoopbackAddr7(remoteAddr)) {
|
|
18128
18238
|
console.error(`${TAG32} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -18185,11 +18295,11 @@ app42.post("/", async (c) => {
|
|
|
18185
18295
|
);
|
|
18186
18296
|
return c.json({ personId, grant }, 200);
|
|
18187
18297
|
});
|
|
18188
|
-
var enrol_person_default =
|
|
18298
|
+
var enrol_person_default = app43;
|
|
18189
18299
|
|
|
18190
18300
|
// server/routes/admin/browser.ts
|
|
18191
|
-
var
|
|
18192
|
-
|
|
18301
|
+
var app44 = new Hono();
|
|
18302
|
+
app44.post("/launch", requireAdminSession, async (c) => {
|
|
18193
18303
|
try {
|
|
18194
18304
|
const transport = resolveBrowserTransport(c.req.raw, c.env?.incoming?.socket?.remoteAddress);
|
|
18195
18305
|
console.error(`[admin/browser/launch] op=request transport=${transport}`);
|
|
@@ -18217,7 +18327,7 @@ app43.post("/launch", requireAdminSession, async (c) => {
|
|
|
18217
18327
|
);
|
|
18218
18328
|
}
|
|
18219
18329
|
});
|
|
18220
|
-
var browser_default =
|
|
18330
|
+
var browser_default = app44;
|
|
18221
18331
|
|
|
18222
18332
|
// server/routes/admin/calendar.ts
|
|
18223
18333
|
import { existsSync as existsSync27 } from "fs";
|
|
@@ -18363,7 +18473,7 @@ function readAvailabilityConfig(accountDir) {
|
|
|
18363
18473
|
}
|
|
18364
18474
|
|
|
18365
18475
|
// server/routes/admin/calendar.ts
|
|
18366
|
-
var
|
|
18476
|
+
var app45 = new Hono();
|
|
18367
18477
|
function normalizeAttendees(raw) {
|
|
18368
18478
|
if (!Array.isArray(raw)) return [];
|
|
18369
18479
|
return raw.map((a) => {
|
|
@@ -18394,7 +18504,7 @@ function mapMeeting(r) {
|
|
|
18394
18504
|
privateNote: r.get("privateNote")
|
|
18395
18505
|
};
|
|
18396
18506
|
}
|
|
18397
|
-
|
|
18507
|
+
app45.get("/meetings", requireAdminSession, async (c) => {
|
|
18398
18508
|
const cacheKey = c.var.cacheKey;
|
|
18399
18509
|
const accountId = getAccountIdForSession(cacheKey);
|
|
18400
18510
|
if (!accountId) {
|
|
@@ -18457,7 +18567,7 @@ function icsFilename(title) {
|
|
|
18457
18567
|
const slug = (title ?? "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60);
|
|
18458
18568
|
return `${slug || "meeting"}.ics`;
|
|
18459
18569
|
}
|
|
18460
|
-
|
|
18570
|
+
app45.get("/meetings/:id/ics", requireAdminSession, async (c) => {
|
|
18461
18571
|
const cacheKey = c.var.cacheKey;
|
|
18462
18572
|
const accountId = getAccountIdForSession(cacheKey);
|
|
18463
18573
|
if (!accountId) {
|
|
@@ -18515,7 +18625,7 @@ app44.get("/meetings/:id/ics", requireAdminSession, async (c) => {
|
|
|
18515
18625
|
await session.close();
|
|
18516
18626
|
}
|
|
18517
18627
|
});
|
|
18518
|
-
|
|
18628
|
+
app45.patch("/meetings/:id", requireAdminSession, async (c) => {
|
|
18519
18629
|
const cacheKey = c.var.cacheKey;
|
|
18520
18630
|
const accountId = getAccountIdForSession(cacheKey);
|
|
18521
18631
|
if (!accountId) {
|
|
@@ -18559,7 +18669,7 @@ app44.patch("/meetings/:id", requireAdminSession, async (c) => {
|
|
|
18559
18669
|
await session.close();
|
|
18560
18670
|
}
|
|
18561
18671
|
});
|
|
18562
|
-
|
|
18672
|
+
app45.post("/meetings/:id/attendees", requireAdminSession, async (c) => {
|
|
18563
18673
|
const cacheKey = c.var.cacheKey;
|
|
18564
18674
|
const accountId = getAccountIdForSession(cacheKey);
|
|
18565
18675
|
if (!accountId) {
|
|
@@ -18609,7 +18719,7 @@ app44.post("/meetings/:id/attendees", requireAdminSession, async (c) => {
|
|
|
18609
18719
|
await session.close();
|
|
18610
18720
|
}
|
|
18611
18721
|
});
|
|
18612
|
-
|
|
18722
|
+
app45.delete("/meetings/:id/attendees", requireAdminSession, async (c) => {
|
|
18613
18723
|
const cacheKey = c.var.cacheKey;
|
|
18614
18724
|
const accountId = getAccountIdForSession(cacheKey);
|
|
18615
18725
|
if (!accountId) {
|
|
@@ -18655,7 +18765,7 @@ app44.delete("/meetings/:id/attendees", requireAdminSession, async (c) => {
|
|
|
18655
18765
|
await session.close();
|
|
18656
18766
|
}
|
|
18657
18767
|
});
|
|
18658
|
-
|
|
18768
|
+
app45.delete("/meetings/:id", requireAdminSession, async (c) => {
|
|
18659
18769
|
const cacheKey = c.var.cacheKey;
|
|
18660
18770
|
const accountId = getAccountIdForSession(cacheKey);
|
|
18661
18771
|
if (!accountId) {
|
|
@@ -18685,7 +18795,7 @@ app44.delete("/meetings/:id", requireAdminSession, async (c) => {
|
|
|
18685
18795
|
await session.close();
|
|
18686
18796
|
}
|
|
18687
18797
|
});
|
|
18688
|
-
|
|
18798
|
+
app45.get("/booking-link", requireAdminSession, (c) => {
|
|
18689
18799
|
try {
|
|
18690
18800
|
const account = resolveAccount();
|
|
18691
18801
|
if (!account) {
|
|
@@ -18708,53 +18818,54 @@ app44.get("/booking-link", requireAdminSession, (c) => {
|
|
|
18708
18818
|
return c.json({ bookingDomain: null });
|
|
18709
18819
|
}
|
|
18710
18820
|
});
|
|
18711
|
-
var calendar_default =
|
|
18821
|
+
var calendar_default = app45;
|
|
18712
18822
|
|
|
18713
18823
|
// server/routes/admin/index.ts
|
|
18714
|
-
var
|
|
18715
|
-
|
|
18716
|
-
|
|
18717
|
-
|
|
18718
|
-
|
|
18719
|
-
|
|
18720
|
-
|
|
18721
|
-
|
|
18722
|
-
|
|
18723
|
-
|
|
18724
|
-
|
|
18725
|
-
|
|
18726
|
-
|
|
18727
|
-
|
|
18728
|
-
|
|
18729
|
-
|
|
18730
|
-
|
|
18731
|
-
|
|
18732
|
-
|
|
18733
|
-
|
|
18734
|
-
|
|
18735
|
-
|
|
18736
|
-
|
|
18737
|
-
|
|
18738
|
-
|
|
18739
|
-
|
|
18740
|
-
|
|
18741
|
-
|
|
18742
|
-
|
|
18743
|
-
|
|
18744
|
-
|
|
18745
|
-
|
|
18746
|
-
|
|
18747
|
-
|
|
18748
|
-
|
|
18749
|
-
|
|
18750
|
-
|
|
18824
|
+
var app46 = new Hono();
|
|
18825
|
+
app46.route("/session", session_default);
|
|
18826
|
+
app46.route("/accounts", accounts_default);
|
|
18827
|
+
app46.route("/logs", logs_default);
|
|
18828
|
+
app46.route("/claude-info", claude_info_default);
|
|
18829
|
+
app46.route("/attachment", attachment_default);
|
|
18830
|
+
app46.route("/agents", agents_default);
|
|
18831
|
+
app46.route("/sessions", sessions_default);
|
|
18832
|
+
app46.route("/claude-sessions", claude_sessions_default);
|
|
18833
|
+
app46.route("/log-ingest", log_ingest_default);
|
|
18834
|
+
app46.route("/events", events_default);
|
|
18835
|
+
app46.route("/files", files_default);
|
|
18836
|
+
app46.route("/graph-search", graph_search_default);
|
|
18837
|
+
app46.route("/graph-subgraph", graph_subgraph_default);
|
|
18838
|
+
app46.route("/graph-delete", graph_delete_default);
|
|
18839
|
+
app46.route("/graph-restore", graph_restore_default);
|
|
18840
|
+
app46.route("/graph-labels-in-graph", graph_labels_in_graph_default);
|
|
18841
|
+
app46.route("/graph-default-view", graph_default_view_default);
|
|
18842
|
+
app46.route("/sidebar-artefacts", sidebar_artefacts_default);
|
|
18843
|
+
app46.route("/sidebar-sessions", sidebar_sessions_default);
|
|
18844
|
+
app46.route("/session-delete", session_delete_default);
|
|
18845
|
+
app46.route("/session-stop", session_stop_default);
|
|
18846
|
+
app46.route("/session-archive", session_archive_default);
|
|
18847
|
+
app46.route("/session-rename", session_rename_default);
|
|
18848
|
+
app46.route("/session-usage", session_usage_default);
|
|
18849
|
+
app46.route("/browser", browser_default);
|
|
18850
|
+
app46.route("/session-rc-spawn", session_rc_spawn_default);
|
|
18851
|
+
app46.route("/session-reseat", session_reseat_default);
|
|
18852
|
+
app46.route("/system-stats", system_stats_default);
|
|
18853
|
+
app46.route("/health-brand", health_default2);
|
|
18854
|
+
app46.route("/linkedin-ingest", linkedin_ingest_default);
|
|
18855
|
+
app46.route("/post-turn-context", post_turn_context_default);
|
|
18856
|
+
app46.route("/public-session-context", public_session_context_default);
|
|
18857
|
+
app46.route("/public-session-exit", public_session_exit_default);
|
|
18858
|
+
app46.route("/access-session-evict", access_session_evict_default);
|
|
18859
|
+
app46.route("/enrol-person", enrol_person_default);
|
|
18860
|
+
app46.route("/calendar", calendar_default);
|
|
18861
|
+
var admin_default = app46;
|
|
18751
18862
|
|
|
18752
18863
|
// server/routes/access/verify-token.ts
|
|
18753
18864
|
var TAG33 = "[access-verify]";
|
|
18754
18865
|
var MINT_TAG = "[access-session-mint]";
|
|
18755
18866
|
var COOKIE_NAME = "__access_session";
|
|
18756
|
-
var
|
|
18757
|
-
|
|
18867
|
+
var app47 = new Hono();
|
|
18868
|
+
app47.post("/", async (c) => {
|
|
18758
18869
|
const ip = c.var.clientIp || "unknown";
|
|
18759
18870
|
let body;
|
|
18760
18871
|
try {
|
|
@@ -18836,7 +18947,7 @@ app46.post("/", async (c) => {
|
|
|
18836
18947
|
displayName: grant.displayName
|
|
18837
18948
|
});
|
|
18838
18949
|
});
|
|
18839
|
-
var verify_token_default =
|
|
18950
|
+
var verify_token_default = app47;
|
|
18840
18951
|
|
|
18841
18952
|
// app/lib/access-email.ts
|
|
18842
18953
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -18899,9 +19010,9 @@ async function sendMagicLinkEmail(payload) {
|
|
|
18899
19010
|
|
|
18900
19011
|
// server/routes/access/request-magic-link.ts
|
|
18901
19012
|
var TAG34 = "[access-request-link]";
|
|
18902
|
-
var
|
|
19013
|
+
var app48 = new Hono();
|
|
18903
19014
|
var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
|
|
18904
|
-
|
|
19015
|
+
app48.post("/", async (c) => {
|
|
18905
19016
|
let body;
|
|
18906
19017
|
try {
|
|
18907
19018
|
body = await c.req.json();
|
|
@@ -18975,13 +19086,13 @@ app47.post("/", async (c) => {
|
|
|
18975
19086
|
);
|
|
18976
19087
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
18977
19088
|
});
|
|
18978
|
-
var request_magic_link_default =
|
|
19089
|
+
var request_magic_link_default = app48;
|
|
18979
19090
|
|
|
18980
19091
|
// server/routes/access/index.ts
|
|
18981
|
-
var
|
|
18982
|
-
|
|
18983
|
-
|
|
18984
|
-
var access_default =
|
|
19092
|
+
var app49 = new Hono();
|
|
19093
|
+
app49.route("/verify-token", verify_token_default);
|
|
19094
|
+
app49.route("/request-magic-link", request_magic_link_default);
|
|
19095
|
+
var access_default = app49;
|
|
18985
19096
|
|
|
18986
19097
|
// server/routes/sites.ts
|
|
18987
19098
|
import { existsSync as existsSync28, readFileSync as readFileSync31, realpathSync as realpathSync6, statSync as statSync12 } from "fs";
|
|
@@ -19016,8 +19127,8 @@ function getExt(p) {
|
|
|
19016
19127
|
if (idx < p.lastIndexOf("/")) return "";
|
|
19017
19128
|
return p.slice(idx).toLowerCase();
|
|
19018
19129
|
}
|
|
19019
|
-
var
|
|
19020
|
-
|
|
19130
|
+
var app50 = new Hono();
|
|
19131
|
+
app50.get("/:rel{.*}", (c) => {
|
|
19021
19132
|
const reqPath = c.req.path;
|
|
19022
19133
|
const rawRel = c.req.param("rel") ?? "";
|
|
19023
19134
|
const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
@@ -19120,12 +19231,12 @@ app49.get("/:rel{.*}", (c) => {
|
|
|
19120
19231
|
"X-Content-Type-Options": "nosniff"
|
|
19121
19232
|
});
|
|
19122
19233
|
});
|
|
19123
|
-
var sites_default =
|
|
19234
|
+
var sites_default = app50;
|
|
19124
19235
|
|
|
19125
19236
|
// app/lib/visitor-token.ts
|
|
19126
19237
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
19127
19238
|
import { mkdirSync as mkdirSync7, readFileSync as readFileSync32, writeFileSync as writeFileSync11 } from "fs";
|
|
19128
|
-
import { dirname as
|
|
19239
|
+
import { dirname as dirname10 } from "path";
|
|
19129
19240
|
var TOKEN_PREFIX = "v1.";
|
|
19130
19241
|
var SECRET_BYTES = 32;
|
|
19131
19242
|
var DEFAULT_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
@@ -19142,7 +19253,7 @@ function getSecret() {
|
|
|
19142
19253
|
}
|
|
19143
19254
|
const fresh = randomBytes(SECRET_BYTES).toString("hex");
|
|
19144
19255
|
try {
|
|
19145
|
-
mkdirSync7(
|
|
19256
|
+
mkdirSync7(dirname10(VISITOR_TOKEN_SECRET_FILE), { recursive: true, mode: 448 });
|
|
19146
19257
|
writeFileSync11(VISITOR_TOKEN_SECRET_FILE, fresh, { mode: 384, flag: "wx" });
|
|
19147
19258
|
console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
|
|
19148
19259
|
} catch {
|
|
@@ -19220,7 +19331,7 @@ function readBrandConfig() {
|
|
|
19220
19331
|
}
|
|
19221
19332
|
|
|
19222
19333
|
// server/routes/visitor-consent.ts
|
|
19223
|
-
var
|
|
19334
|
+
var app51 = new Hono();
|
|
19224
19335
|
var CONSENT_COOKIE_NAME = "mxy_consent";
|
|
19225
19336
|
var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
|
|
19226
19337
|
var DEFAULT_CONSENT_COPY = {
|
|
@@ -19265,17 +19376,17 @@ function siteSlugFromReferer(referer) {
|
|
|
19265
19376
|
return "";
|
|
19266
19377
|
}
|
|
19267
19378
|
}
|
|
19268
|
-
|
|
19379
|
+
app51.options("/consent", (c) => {
|
|
19269
19380
|
const origin = getOrigin(c);
|
|
19270
19381
|
setCorsHeaders(c, origin);
|
|
19271
19382
|
return c.body(null, 204);
|
|
19272
19383
|
});
|
|
19273
|
-
|
|
19384
|
+
app51.options("/brand-config", (c) => {
|
|
19274
19385
|
const origin = getOrigin(c);
|
|
19275
19386
|
setCorsHeaders(c, origin);
|
|
19276
19387
|
return c.body(null, 204);
|
|
19277
19388
|
});
|
|
19278
|
-
|
|
19389
|
+
app51.post("/consent", async (c) => {
|
|
19279
19390
|
const origin = getOrigin(c);
|
|
19280
19391
|
setCorsHeaders(c, origin);
|
|
19281
19392
|
let raw;
|
|
@@ -19315,7 +19426,7 @@ app50.post("/consent", async (c) => {
|
|
|
19315
19426
|
console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
|
|
19316
19427
|
return c.body(null, 204);
|
|
19317
19428
|
});
|
|
19318
|
-
|
|
19429
|
+
app51.get("/brand-config", (c) => {
|
|
19319
19430
|
const origin = getOrigin(c);
|
|
19320
19431
|
setCorsHeaders(c, origin);
|
|
19321
19432
|
const brand = readBrandConfig();
|
|
@@ -19325,7 +19436,7 @@ app50.get("/brand-config", (c) => {
|
|
|
19325
19436
|
c.header("Cache-Control", "public, max-age=300");
|
|
19326
19437
|
return c.json({ consent: { copy, palette } });
|
|
19327
19438
|
});
|
|
19328
|
-
var visitor_consent_default =
|
|
19439
|
+
var visitor_consent_default = app51;
|
|
19329
19440
|
|
|
19330
19441
|
// server/routes/listings.ts
|
|
19331
19442
|
function getCookie(headerValue, name) {
|
|
@@ -19352,8 +19463,8 @@ function appendConsentParams(pageUrl, token) {
|
|
|
19352
19463
|
}
|
|
19353
19464
|
var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
|
|
19354
19465
|
var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
19355
|
-
var
|
|
19356
|
-
|
|
19466
|
+
var app52 = new Hono();
|
|
19467
|
+
app52.get("/:slug/click", async (c) => {
|
|
19357
19468
|
const slug = c.req.param("slug") ?? "";
|
|
19358
19469
|
const rawSession = c.req.query("session") ?? "";
|
|
19359
19470
|
const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
|
|
@@ -19417,10 +19528,10 @@ app51.get("/:slug/click", async (c) => {
|
|
|
19417
19528
|
console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
19418
19529
|
return c.redirect(redirectUrl, 302);
|
|
19419
19530
|
});
|
|
19420
|
-
var listings_default =
|
|
19531
|
+
var listings_default = app52;
|
|
19421
19532
|
|
|
19422
19533
|
// server/routes/visitor-event.ts
|
|
19423
|
-
var
|
|
19534
|
+
var app53 = new Hono();
|
|
19424
19535
|
var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
|
|
19425
19536
|
var buckets = /* @__PURE__ */ new Map();
|
|
19426
19537
|
var RATE_LIMIT = 60;
|
|
@@ -19487,12 +19598,12 @@ function originAllowed(origin, allowlist) {
|
|
|
19487
19598
|
return false;
|
|
19488
19599
|
}
|
|
19489
19600
|
}
|
|
19490
|
-
|
|
19601
|
+
app53.options("/event", (c) => {
|
|
19491
19602
|
const origin = getOrigin2(c);
|
|
19492
19603
|
setCorsHeaders2(c, origin);
|
|
19493
19604
|
return c.body(null, 204);
|
|
19494
19605
|
});
|
|
19495
|
-
|
|
19606
|
+
app53.post("/event", async (c) => {
|
|
19496
19607
|
const origin = getOrigin2(c);
|
|
19497
19608
|
setCorsHeaders2(c, origin);
|
|
19498
19609
|
const ua = c.req.header("user-agent") ?? "";
|
|
@@ -19697,7 +19808,7 @@ async function writeEvent(opts) {
|
|
|
19697
19808
|
);
|
|
19698
19809
|
}
|
|
19699
19810
|
}
|
|
19700
|
-
var visitor_event_default =
|
|
19811
|
+
var visitor_event_default = app53;
|
|
19701
19812
|
|
|
19702
19813
|
// server/routes/session.ts
|
|
19703
19814
|
import { resolve as resolve27 } from "path";
|
|
@@ -19743,8 +19854,8 @@ function withVisitorCookie(response, visitorId) {
|
|
|
19743
19854
|
headers
|
|
19744
19855
|
});
|
|
19745
19856
|
}
|
|
19746
|
-
var
|
|
19747
|
-
|
|
19857
|
+
var app54 = new Hono();
|
|
19858
|
+
app54.post("/", async (c) => {
|
|
19748
19859
|
let body;
|
|
19749
19860
|
try {
|
|
19750
19861
|
body = await c.req.json();
|
|
@@ -19891,7 +20002,7 @@ app53.post("/", async (c) => {
|
|
|
19891
20002
|
newVisitorId
|
|
19892
20003
|
);
|
|
19893
20004
|
});
|
|
19894
|
-
var session_default2 =
|
|
20005
|
+
var session_default2 = app54;
|
|
19895
20006
|
|
|
19896
20007
|
// server/lib/calendar-slots.ts
|
|
19897
20008
|
var WEEKDAYS = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
|
|
@@ -19974,17 +20085,17 @@ function computeOpenSlots(config, busy, fromISO, toISO) {
|
|
|
19974
20085
|
}
|
|
19975
20086
|
|
|
19976
20087
|
// server/routes/calendar-public.ts
|
|
19977
|
-
var
|
|
20088
|
+
var app55 = new Hono();
|
|
19978
20089
|
function setCors(c) {
|
|
19979
20090
|
c.header("Access-Control-Allow-Origin", "*");
|
|
19980
20091
|
c.header("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
19981
20092
|
c.header("Access-Control-Allow-Headers", "content-type");
|
|
19982
20093
|
}
|
|
19983
|
-
|
|
20094
|
+
app55.options("/free-busy", (c) => {
|
|
19984
20095
|
setCors(c);
|
|
19985
20096
|
return c.body(null, 204);
|
|
19986
20097
|
});
|
|
19987
|
-
|
|
20098
|
+
app55.get("/free-busy", async (c) => {
|
|
19988
20099
|
setCors(c);
|
|
19989
20100
|
const from = c.req.query("from");
|
|
19990
20101
|
const to = c.req.query("to");
|
|
@@ -20026,7 +20137,7 @@ app54.get("/free-busy", async (c) => {
|
|
|
20026
20137
|
await session.close();
|
|
20027
20138
|
}
|
|
20028
20139
|
});
|
|
20029
|
-
var calendar_public_default =
|
|
20140
|
+
var calendar_public_default = app55;
|
|
20030
20141
|
|
|
20031
20142
|
// app/lib/graph-health.ts
|
|
20032
20143
|
var import_dist4 = __toESM(require_dist3(), 1);
|
|
@@ -20250,7 +20361,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
20250
20361
|
|
|
20251
20362
|
// app/lib/migrate-uploads.ts
|
|
20252
20363
|
import { mkdir as mkdir5, readdir as readdir5, rename as rename2, rm as rm3 } from "fs/promises";
|
|
20253
|
-
import { dirname as
|
|
20364
|
+
import { dirname as dirname11, relative as relative6, resolve as resolve29 } from "path";
|
|
20254
20365
|
var ACCOUNT_UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
20255
20366
|
async function walkFiles(dir) {
|
|
20256
20367
|
const out = [];
|
|
@@ -20282,7 +20393,7 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
|
|
|
20282
20393
|
for (const oldAbs of files) {
|
|
20283
20394
|
const suffix = relative6(srcDir, oldAbs);
|
|
20284
20395
|
const newAbs = resolve29(destDir, suffix);
|
|
20285
|
-
await mkdir5(
|
|
20396
|
+
await mkdir5(dirname11(newAbs), { recursive: true });
|
|
20286
20397
|
await rename2(oldAbs, newAbs);
|
|
20287
20398
|
moved++;
|
|
20288
20399
|
const oldRel = relative6(dataRoot, oldAbs);
|
|
@@ -20792,8 +20903,8 @@ var streamSSE = (c, cb, onError) => {
|
|
|
20792
20903
|
|
|
20793
20904
|
// app/lib/whatsapp/gateway/routes.ts
|
|
20794
20905
|
function createWaChannelRoutes(deps) {
|
|
20795
|
-
const
|
|
20796
|
-
|
|
20906
|
+
const app57 = new Hono();
|
|
20907
|
+
app57.get("/wa-channel/inbound", (c) => {
|
|
20797
20908
|
const senderId = c.req.query("senderId");
|
|
20798
20909
|
if (!senderId) return c.json({ error: "senderId required" }, 400);
|
|
20799
20910
|
return streamSSE(c, async (stream2) => {
|
|
@@ -20811,7 +20922,7 @@ function createWaChannelRoutes(deps) {
|
|
|
20811
20922
|
}
|
|
20812
20923
|
});
|
|
20813
20924
|
});
|
|
20814
|
-
|
|
20925
|
+
app57.post("/wa-channel/reply", async (c) => {
|
|
20815
20926
|
const body = await c.req.json().catch(() => null);
|
|
20816
20927
|
const senderId = body?.senderId;
|
|
20817
20928
|
const text = body?.text;
|
|
@@ -20832,7 +20943,7 @@ function createWaChannelRoutes(deps) {
|
|
|
20832
20943
|
console.error(`[whatsapp-native] op=reply-dispatch senderId=${senderId} bytes=${bytes}`);
|
|
20833
20944
|
return c.json({ ok: true });
|
|
20834
20945
|
});
|
|
20835
|
-
|
|
20946
|
+
app57.post("/wa-channel/reply-document", async (c) => {
|
|
20836
20947
|
const body = await c.req.json().catch(() => null);
|
|
20837
20948
|
const senderId = body?.senderId;
|
|
20838
20949
|
const files = body?.files;
|
|
@@ -20871,7 +20982,7 @@ function createWaChannelRoutes(deps) {
|
|
|
20871
20982
|
}
|
|
20872
20983
|
return c.json({ ok: true, results });
|
|
20873
20984
|
});
|
|
20874
|
-
|
|
20985
|
+
app57.post("/wa-channel/ready", async (c) => {
|
|
20875
20986
|
const body = await c.req.json().catch(() => null);
|
|
20876
20987
|
const senderId = body?.senderId;
|
|
20877
20988
|
if (typeof senderId !== "string") {
|
|
@@ -20880,7 +20991,7 @@ function createWaChannelRoutes(deps) {
|
|
|
20880
20991
|
deps.onReady?.(senderId);
|
|
20881
20992
|
return c.json({ ok: true });
|
|
20882
20993
|
});
|
|
20883
|
-
|
|
20994
|
+
app57.post("/wa-channel/received", async (c) => {
|
|
20884
20995
|
const body = await c.req.json().catch(() => null);
|
|
20885
20996
|
const senderId = body?.senderId;
|
|
20886
20997
|
const waMessageId = body?.waMessageId;
|
|
@@ -20890,7 +21001,7 @@ function createWaChannelRoutes(deps) {
|
|
|
20890
21001
|
deps.onReceived?.(senderId, waMessageId);
|
|
20891
21002
|
return c.json({ ok: true });
|
|
20892
21003
|
});
|
|
20893
|
-
|
|
21004
|
+
app57.post("/wa-channel/turn-end", async (c) => {
|
|
20894
21005
|
const body = await c.req.json().catch(() => null);
|
|
20895
21006
|
const senderId = body?.senderId;
|
|
20896
21007
|
const sessionId = body?.sessionId;
|
|
@@ -20921,7 +21032,7 @@ function createWaChannelRoutes(deps) {
|
|
|
20921
21032
|
console.error(`[whatsapp-native] op=turn-end sessionId=${sid} replied=no delivered=fallback bytes=${bytes}`);
|
|
20922
21033
|
return c.json({ ok: true, delivered: "fallback" });
|
|
20923
21034
|
});
|
|
20924
|
-
return
|
|
21035
|
+
return app57;
|
|
20925
21036
|
}
|
|
20926
21037
|
|
|
20927
21038
|
// app/lib/whatsapp/gateway/wa-gateway.ts
|
|
@@ -20934,9 +21045,11 @@ var WaGateway = class {
|
|
|
20934
21045
|
}
|
|
20935
21046
|
hub = new InboundHub();
|
|
20936
21047
|
replies = /* @__PURE__ */ new Map();
|
|
20937
|
-
// Per-sender document-delivery context
|
|
20938
|
-
//
|
|
20939
|
-
//
|
|
21048
|
+
// Per-sender document-delivery context, set on every inbound. Its presence is
|
|
21049
|
+
// the reply-only guard: a sender with no inbound has no context, so a file
|
|
21050
|
+
// reply to a cold recipient is refused. `accountId` is the Baileys socket
|
|
21051
|
+
// owner (reply transport); `maxyAccountId` (Task 1390) is the sender's
|
|
21052
|
+
// effective session account — the file-path validation scope.
|
|
20940
21053
|
docContexts = /* @__PURE__ */ new Map();
|
|
20941
21054
|
spawning = /* @__PURE__ */ new Set();
|
|
20942
21055
|
seq = 0;
|
|
@@ -20991,7 +21104,7 @@ var WaGateway = class {
|
|
|
20991
21104
|
const mediaField = openable.length > 0 ? `media=${openable.map((m) => m.type).join(",")} mediaPaths=${openable.map((m) => m.path).join(",")}` : input.media.some((m) => m.type === "audio") ? "media=audio mediaPath=transcribed" : "media=none";
|
|
20992
21105
|
const source = input.source ?? "user";
|
|
20993
21106
|
this.replies.set(input.senderId, input.reply);
|
|
20994
|
-
this.docContexts.set(input.senderId, { accountId: input.accountId });
|
|
21107
|
+
this.docContexts.set(input.senderId, { accountId: input.accountId, maxyAccountId: input.effectiveAccountId });
|
|
20995
21108
|
this.hub.deliver(
|
|
20996
21109
|
{
|
|
20997
21110
|
senderId: input.senderId,
|
|
@@ -21011,6 +21124,7 @@ var WaGateway = class {
|
|
|
21011
21124
|
try {
|
|
21012
21125
|
await this.deps.ensureChannelSession({
|
|
21013
21126
|
accountId: input.accountId,
|
|
21127
|
+
effectiveAccountId: input.effectiveAccountId,
|
|
21014
21128
|
senderId: input.senderId,
|
|
21015
21129
|
role: input.role ?? "admin",
|
|
21016
21130
|
personId: input.personId ?? null,
|
|
@@ -21033,7 +21147,7 @@ var WaGateway = class {
|
|
|
21033
21147
|
async sendDocument(senderId, filePath, caption) {
|
|
21034
21148
|
const ctx = this.docContexts.get(senderId);
|
|
21035
21149
|
if (!ctx) throw new WaReplyError(`no conversation for sender ${senderId}`, false);
|
|
21036
|
-
return this.deps.sendDocument({ senderId, accountId: ctx.accountId, filePath, caption });
|
|
21150
|
+
return this.deps.sendDocument({ senderId, accountId: ctx.accountId, maxyAccountId: ctx.maxyAccountId, filePath, caption });
|
|
21037
21151
|
}
|
|
21038
21152
|
};
|
|
21039
21153
|
|
|
@@ -21222,8 +21336,8 @@ var InboundHub2 = class {
|
|
|
21222
21336
|
|
|
21223
21337
|
// app/lib/webchat/gateway/routes.ts
|
|
21224
21338
|
function createWebchatChannelRoutes(deps) {
|
|
21225
|
-
const
|
|
21226
|
-
|
|
21339
|
+
const app57 = new Hono();
|
|
21340
|
+
app57.get("/webchat-channel/inbound", (c) => {
|
|
21227
21341
|
const key = c.req.query("key");
|
|
21228
21342
|
if (!key) return c.json({ error: "key required" }, 400);
|
|
21229
21343
|
return streamSSE(c, async (stream2) => {
|
|
@@ -21241,7 +21355,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
21241
21355
|
}
|
|
21242
21356
|
});
|
|
21243
21357
|
});
|
|
21244
|
-
|
|
21358
|
+
app57.post("/webchat-channel/reply", async (c) => {
|
|
21245
21359
|
const body = await c.req.json().catch(() => null);
|
|
21246
21360
|
const key = body?.key;
|
|
21247
21361
|
const text = body?.text;
|
|
@@ -21251,7 +21365,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
21251
21365
|
deps.onReply?.(key, text);
|
|
21252
21366
|
return c.json({ ok: true });
|
|
21253
21367
|
});
|
|
21254
|
-
|
|
21368
|
+
app57.post("/webchat-channel/connector-auth", async (c) => {
|
|
21255
21369
|
const body = await c.req.json().catch(() => null);
|
|
21256
21370
|
const key = body?.key;
|
|
21257
21371
|
const sessionId = body?.sessionId;
|
|
@@ -21264,7 +21378,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
21264
21378
|
const result = await deps.onConnectorAuth({ key, sessionId, name, completed });
|
|
21265
21379
|
return c.json(result);
|
|
21266
21380
|
});
|
|
21267
|
-
|
|
21381
|
+
app57.post("/webchat-channel/ready", async (c) => {
|
|
21268
21382
|
const body = await c.req.json().catch(() => null);
|
|
21269
21383
|
const key = body?.key;
|
|
21270
21384
|
if (typeof key !== "string") {
|
|
@@ -21273,7 +21387,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
21273
21387
|
deps.onReady?.(key);
|
|
21274
21388
|
return c.json({ ok: true });
|
|
21275
21389
|
});
|
|
21276
|
-
|
|
21390
|
+
app57.post("/webchat-channel/permission-request", async (c) => {
|
|
21277
21391
|
const body = await c.req.json().catch(() => null);
|
|
21278
21392
|
const key = body?.key;
|
|
21279
21393
|
const requestId = body?.request_id;
|
|
@@ -21287,7 +21401,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
21287
21401
|
const verdict = await deps.awaitPermissionVerdict({ key, requestId, toolName, description, inputPreview });
|
|
21288
21402
|
return c.json(verdict);
|
|
21289
21403
|
});
|
|
21290
|
-
|
|
21404
|
+
app57.post("/webchat-channel/received", async (c) => {
|
|
21291
21405
|
const body = await c.req.json().catch(() => null);
|
|
21292
21406
|
const key = body?.key;
|
|
21293
21407
|
const messageId = body?.messageId;
|
|
@@ -21297,7 +21411,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
21297
21411
|
deps.onReceived?.(key, messageId);
|
|
21298
21412
|
return c.json({ ok: true });
|
|
21299
21413
|
});
|
|
21300
|
-
|
|
21414
|
+
app57.post("/webchat-channel/turn-end", async (c) => {
|
|
21301
21415
|
const body = await c.req.json().catch(() => null);
|
|
21302
21416
|
const key = body?.key;
|
|
21303
21417
|
const sessionId = body?.sessionId;
|
|
@@ -21317,7 +21431,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
21317
21431
|
console.error(`[webchat-native] op=turn-undelivered channel=webchat key=${k} sessionId=${sid} bytes=${finalBytes}`);
|
|
21318
21432
|
return c.json({ ok: true, delivered: "undelivered" });
|
|
21319
21433
|
});
|
|
21320
|
-
return
|
|
21434
|
+
return app57;
|
|
21321
21435
|
}
|
|
21322
21436
|
|
|
21323
21437
|
// app/lib/webchat/gateway/webchat-gateway.ts
|
|
@@ -21946,17 +22060,8 @@ var WHATSAPP_SEND_DOCUMENT = "whatsapp-send-document";
|
|
|
21946
22060
|
function platformRoot() {
|
|
21947
22061
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
21948
22062
|
}
|
|
21949
|
-
function makeWhatsAppSendFile(entry) {
|
|
22063
|
+
function makeWhatsAppSendFile(entry, maxyAccountId) {
|
|
21950
22064
|
return async (filePath, caption) => {
|
|
21951
|
-
let maxyAccountId;
|
|
21952
|
-
try {
|
|
21953
|
-
maxyAccountId = resolvePlatformAccountId();
|
|
21954
|
-
} catch (err) {
|
|
21955
|
-
console.error(
|
|
21956
|
-
`${TAG35} file-delivery reject reason=account-unresolved sender=${entry.senderId} message=${err instanceof Error ? err.message : String(err)}`
|
|
21957
|
-
);
|
|
21958
|
-
return { ok: false, error: "account-unresolved" };
|
|
21959
|
-
}
|
|
21960
22065
|
const result = await sendWhatsAppDocument({
|
|
21961
22066
|
to: entry.senderId,
|
|
21962
22067
|
filePath,
|
|
@@ -21972,12 +22077,12 @@ function makeWhatsAppSendFile(entry) {
|
|
|
21972
22077
|
return { ok: false, error: result.error };
|
|
21973
22078
|
};
|
|
21974
22079
|
}
|
|
21975
|
-
function makeWhatsAppFileDelivery(entry) {
|
|
22080
|
+
function makeWhatsAppFileDelivery(entry, maxyAccountId) {
|
|
21976
22081
|
const shared = makeFileDelivery({
|
|
21977
22082
|
entry,
|
|
21978
22083
|
tag: TAG35,
|
|
21979
22084
|
channel: "whatsapp",
|
|
21980
|
-
sendFile: makeWhatsAppSendFile(entry)
|
|
22085
|
+
sendFile: makeWhatsAppSendFile(entry, maxyAccountId)
|
|
21981
22086
|
});
|
|
21982
22087
|
let turnStartedAt = null;
|
|
21983
22088
|
let routeCalls = [];
|
|
@@ -22061,7 +22166,7 @@ function startNativeFileFollower(input) {
|
|
|
22061
22166
|
return startFollower({
|
|
22062
22167
|
entry,
|
|
22063
22168
|
tag: "[whatsapp-adaptor]",
|
|
22064
|
-
fileDelivery: makeWhatsAppFileDelivery(entry),
|
|
22169
|
+
fileDelivery: makeWhatsAppFileDelivery(entry, input.maxyAccountId),
|
|
22065
22170
|
// A resumed session's JSONL already holds prior SendUserFile tool_uses;
|
|
22066
22171
|
// suppress replay so historical files are not re-sent on attach.
|
|
22067
22172
|
suppressResumeReplay: true,
|
|
@@ -22184,8 +22289,8 @@ var InboundHub3 = class {
|
|
|
22184
22289
|
|
|
22185
22290
|
// app/lib/telegram/gateway/routes.ts
|
|
22186
22291
|
function createTelegramChannelRoutes(deps) {
|
|
22187
|
-
const
|
|
22188
|
-
|
|
22292
|
+
const app57 = new Hono();
|
|
22293
|
+
app57.get("/tg-channel/inbound", (c) => {
|
|
22189
22294
|
const key = c.req.query("key");
|
|
22190
22295
|
if (!key) return c.json({ error: "key required" }, 400);
|
|
22191
22296
|
return streamSSE(c, async (stream2) => {
|
|
@@ -22203,7 +22308,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
22203
22308
|
}
|
|
22204
22309
|
});
|
|
22205
22310
|
});
|
|
22206
|
-
|
|
22311
|
+
app57.post("/tg-channel/reply", async (c) => {
|
|
22207
22312
|
const body = await c.req.json().catch(() => null);
|
|
22208
22313
|
const key = body?.key;
|
|
22209
22314
|
const text = body?.text;
|
|
@@ -22219,7 +22324,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
22219
22324
|
console.error(`[telegram-native] op=reply key=${key} bytes=${Buffer.byteLength(text, "utf8")}`);
|
|
22220
22325
|
return c.json({ ok: true });
|
|
22221
22326
|
});
|
|
22222
|
-
|
|
22327
|
+
app57.post("/tg-channel/ready", async (c) => {
|
|
22223
22328
|
const body = await c.req.json().catch(() => null);
|
|
22224
22329
|
const key = body?.key;
|
|
22225
22330
|
if (typeof key !== "string") {
|
|
@@ -22228,7 +22333,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
22228
22333
|
deps.onReady?.(key);
|
|
22229
22334
|
return c.json({ ok: true });
|
|
22230
22335
|
});
|
|
22231
|
-
|
|
22336
|
+
app57.post("/tg-channel/received", async (c) => {
|
|
22232
22337
|
const body = await c.req.json().catch(() => null);
|
|
22233
22338
|
const key = body?.key;
|
|
22234
22339
|
const messageId = body?.messageId;
|
|
@@ -22238,7 +22343,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
22238
22343
|
deps.onReceived?.(key, messageId);
|
|
22239
22344
|
return c.json({ ok: true });
|
|
22240
22345
|
});
|
|
22241
|
-
|
|
22346
|
+
app57.post("/tg-channel/turn-end", async (c) => {
|
|
22242
22347
|
const body = await c.req.json().catch(() => null);
|
|
22243
22348
|
const key = body?.key;
|
|
22244
22349
|
const sessionId = body?.sessionId;
|
|
@@ -22263,7 +22368,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
22263
22368
|
console.error(`[telegram-native] op=turn-fallback key=${key} sessionId=${sid} bytes=${Buffer.byteLength(finalText, "utf8")}`);
|
|
22264
22369
|
return c.json({ ok: true, delivered: "fallback" });
|
|
22265
22370
|
});
|
|
22266
|
-
return
|
|
22371
|
+
return app57;
|
|
22267
22372
|
}
|
|
22268
22373
|
|
|
22269
22374
|
// app/lib/telegram/gateway/telegram-gateway.ts
|
|
@@ -22375,7 +22480,7 @@ function buildTelegramSpawnRequest(input) {
|
|
|
22375
22480
|
// app/lib/telegram/outbound/send-document.ts
|
|
22376
22481
|
import { realpathSync as realpathSync7 } from "fs";
|
|
22377
22482
|
import { readFile as readFile7, stat as stat7 } from "fs/promises";
|
|
22378
|
-
import { resolve as resolve30, basename as
|
|
22483
|
+
import { resolve as resolve30, basename as basename12 } from "path";
|
|
22379
22484
|
var TAG36 = "[telegram:outbound]";
|
|
22380
22485
|
var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
|
|
22381
22486
|
async function sendTelegramDocument(input) {
|
|
@@ -22392,7 +22497,7 @@ async function sendTelegramDocument(input) {
|
|
|
22392
22497
|
resolvedPath = realpathSync7(filePath);
|
|
22393
22498
|
const accountResolved = realpathSync7(accountDir);
|
|
22394
22499
|
if (!resolvedPath.startsWith(accountResolved + "/")) {
|
|
22395
|
-
console.error(`${TAG36} document REJECTED reason=outside_account_directory`);
|
|
22500
|
+
console.error(`${TAG36} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
|
|
22396
22501
|
return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
|
|
22397
22502
|
}
|
|
22398
22503
|
} catch (err) {
|
|
@@ -22412,7 +22517,7 @@ async function sendTelegramDocument(input) {
|
|
|
22412
22517
|
error: `File exceeds 50 MB limit (${(fileStat.size / 1024 / 1024).toFixed(1)} MB)`
|
|
22413
22518
|
};
|
|
22414
22519
|
}
|
|
22415
|
-
const filename =
|
|
22520
|
+
const filename = basename12(resolvedPath);
|
|
22416
22521
|
const buffer = Buffer.from(await readFile7(resolvedPath));
|
|
22417
22522
|
const form = new FormData();
|
|
22418
22523
|
form.append("chat_id", String(chatId));
|
|
@@ -22459,21 +22564,12 @@ function makeTelegramSendFile(entry) {
|
|
|
22459
22564
|
console.error(`${TAG37} file-delivery reject reason=no-reply-target sender=${entry.senderId} role=${entry.role}`);
|
|
22460
22565
|
return { ok: false, error: "no-reply-target" };
|
|
22461
22566
|
}
|
|
22462
|
-
let maxyAccountId;
|
|
22463
|
-
try {
|
|
22464
|
-
maxyAccountId = resolvePlatformAccountId();
|
|
22465
|
-
} catch (err) {
|
|
22466
|
-
console.error(
|
|
22467
|
-
`${TAG37} file-delivery reject reason=account-unresolved sender=${entry.senderId} message=${err instanceof Error ? err.message : String(err)}`
|
|
22468
|
-
);
|
|
22469
|
-
return { ok: false, error: "account-unresolved" };
|
|
22470
|
-
}
|
|
22471
22567
|
const result = await sendTelegramDocument({
|
|
22472
22568
|
botToken,
|
|
22473
22569
|
chatId: Number(entry.replyTarget),
|
|
22474
22570
|
filePath,
|
|
22475
22571
|
caption,
|
|
22476
|
-
maxyAccountId,
|
|
22572
|
+
maxyAccountId: entry.accountId,
|
|
22477
22573
|
platformRoot: platformRoot2()
|
|
22478
22574
|
});
|
|
22479
22575
|
return result.ok ? { ok: true } : { ok: false, error: result.error };
|
|
@@ -22705,6 +22801,10 @@ function findChannelAdminBindingDrift(adminPhones, admins, users) {
|
|
|
22705
22801
|
}
|
|
22706
22802
|
return drift;
|
|
22707
22803
|
}
|
|
22804
|
+
function classifyAdminPhonesForAccount(isSocketOwner, adminPhones, admins, users) {
|
|
22805
|
+
if (!isSocketOwner) return { nonSocketPhones: [...adminPhones], drift: [] };
|
|
22806
|
+
return { nonSocketPhones: [], drift: findChannelAdminBindingDrift(adminPhones, admins, users) };
|
|
22807
|
+
}
|
|
22708
22808
|
function warnOnChannelAdminBindingDrift() {
|
|
22709
22809
|
let users;
|
|
22710
22810
|
try {
|
|
@@ -22718,10 +22818,27 @@ function warnOnChannelAdminBindingDrift() {
|
|
|
22718
22818
|
} catch {
|
|
22719
22819
|
return;
|
|
22720
22820
|
}
|
|
22821
|
+
let socketOwner;
|
|
22822
|
+
try {
|
|
22823
|
+
socketOwner = resolveHouseOrSoleAccountId(ACCOUNTS_DIR);
|
|
22824
|
+
} catch {
|
|
22825
|
+
socketOwner = null;
|
|
22826
|
+
}
|
|
22721
22827
|
const validAccountIds = accounts.map((a) => a.accountId);
|
|
22722
22828
|
for (const acct of accounts) {
|
|
22723
22829
|
const adminPhones = readAdminPhones(acct.accountDir);
|
|
22724
|
-
const
|
|
22830
|
+
const isSocketOwner = socketOwner === null || acct.accountId === socketOwner;
|
|
22831
|
+
const { nonSocketPhones, drift } = classifyAdminPhonesForAccount(
|
|
22832
|
+
isSocketOwner,
|
|
22833
|
+
adminPhones,
|
|
22834
|
+
acct.config.admins ?? [],
|
|
22835
|
+
users
|
|
22836
|
+
);
|
|
22837
|
+
for (const phone of nonSocketPhones) {
|
|
22838
|
+
console.error(
|
|
22839
|
+
`[admin-identity] adminphones-on-non-socket-account accountId=${acct.accountId} phone=${phone} count=${nonSocketPhones.length}`
|
|
22840
|
+
);
|
|
22841
|
+
}
|
|
22725
22842
|
for (const d of drift) {
|
|
22726
22843
|
const tail = d.reason === "userid-not-admin" ? ` userId=${d.userId}` : "";
|
|
22727
22844
|
console.error(
|
|
@@ -23073,20 +23190,19 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
|
|
|
23073
23190
|
function isPublicHost(host) {
|
|
23074
23191
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
23075
23192
|
}
|
|
23076
|
-
var
|
|
23193
|
+
var app56 = new Hono();
|
|
23077
23194
|
var nativeFileFollowers = /* @__PURE__ */ new Map();
|
|
23078
23195
|
var waGateway = new WaGateway({
|
|
23079
23196
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
23080
23197
|
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve33(process.env.MAXY_PLATFORM_ROOT ?? join34(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
23081
|
-
// Task 751 — file delivery on the native channel
|
|
23082
|
-
//
|
|
23083
|
-
|
|
23084
|
-
|
|
23085
|
-
|
|
23086
|
-
|
|
23087
|
-
|
|
23088
|
-
|
|
23089
|
-
}
|
|
23198
|
+
// Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
|
|
23199
|
+
// path-validation scope) is the sender's effective SESSION account, resolved
|
|
23200
|
+
// once at the inbound gate and threaded here via the gateway's per-sender doc
|
|
23201
|
+
// context. For an account-manager that is the bound sub-account (where the
|
|
23202
|
+
// session's files live); using the house account (resolvePlatformAccountId)
|
|
23203
|
+
// rejected an in-account file as outside_account_directory. `accountId` stays
|
|
23204
|
+
// the house Baileys socket (the reply transport, two-account invariant).
|
|
23205
|
+
sendDocument: async ({ senderId, accountId, maxyAccountId, filePath, caption }) => {
|
|
23090
23206
|
const result = await sendWhatsAppDocument({
|
|
23091
23207
|
to: senderId,
|
|
23092
23208
|
filePath,
|
|
@@ -23097,12 +23213,10 @@ var waGateway = new WaGateway({
|
|
|
23097
23213
|
});
|
|
23098
23214
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
23099
23215
|
},
|
|
23100
|
-
ensureChannelSession: async ({ accountId, senderId, role, personId, gatewayUrl, serverPath }) => {
|
|
23101
|
-
const houseDir = role === "admin" ? listValidAccounts().find((a) => a.accountId === accountId)?.accountDir ?? null : null;
|
|
23102
|
-
const managed = houseDir ? managedAccountFor(readAccountManagers(houseDir), senderId) : null;
|
|
23103
|
-
const effectiveAccountId = managed ?? accountId;
|
|
23216
|
+
ensureChannelSession: async ({ accountId, effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath }) => {
|
|
23104
23217
|
if (role === "admin") {
|
|
23105
|
-
|
|
23218
|
+
const managesAccount = effectiveAccountId !== accountId ? effectiveAccountId : "none";
|
|
23219
|
+
console.error(`[whatsapp-native] op=account-manager-route senderId=${senderId} managesAccount=${managesAccount} effectiveAccount=${effectiveAccountId} source=gate`);
|
|
23106
23220
|
}
|
|
23107
23221
|
const req = buildWaSpawnRequest({ accountId: effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath });
|
|
23108
23222
|
const userId = role === "admin" ? resolveAdminUserId({ accountId: effectiveAccountId, senderPhone: senderId }) ?? void 0 : void 0;
|
|
@@ -23122,6 +23236,10 @@ var waGateway = new WaGateway({
|
|
|
23122
23236
|
sessionId: req.sessionId,
|
|
23123
23237
|
senderId,
|
|
23124
23238
|
accountId,
|
|
23239
|
+
// Task 1390 — the file-path validation scope is the sender's effective
|
|
23240
|
+
// session account (the sub-account for an account-manager), not the house
|
|
23241
|
+
// socket account. accountId stays the getSocket key.
|
|
23242
|
+
maxyAccountId: effectiveAccountId,
|
|
23125
23243
|
onClose: () => {
|
|
23126
23244
|
if (nativeFileFollowers.get(senderId) === ac) nativeFileFollowers.delete(senderId);
|
|
23127
23245
|
}
|
|
@@ -23129,7 +23247,7 @@ var waGateway = new WaGateway({
|
|
|
23129
23247
|
nativeFileFollowers.set(senderId, ac);
|
|
23130
23248
|
}
|
|
23131
23249
|
});
|
|
23132
|
-
|
|
23250
|
+
app56.route("/", waGateway.routes());
|
|
23133
23251
|
waGateway.startSweeper();
|
|
23134
23252
|
var webchatGateway = new WebchatGateway({
|
|
23135
23253
|
gatewayUrl: webchatGatewayUrl(),
|
|
@@ -23212,7 +23330,7 @@ var webchatGateway = new WebchatGateway({
|
|
|
23212
23330
|
firePublicSessionEndReview: (input) => firePublicSessionEndReview(input)
|
|
23213
23331
|
});
|
|
23214
23332
|
setWebchatGateway(webchatGateway);
|
|
23215
|
-
|
|
23333
|
+
app56.route("/", webchatGateway.routes());
|
|
23216
23334
|
webchatGateway.startSweeper();
|
|
23217
23335
|
webchatGateway.startPublicReaper();
|
|
23218
23336
|
var telegramFileFollowers = /* @__PURE__ */ new Map();
|
|
@@ -23245,7 +23363,7 @@ var telegramGateway = new TelegramGateway({
|
|
|
23245
23363
|
}
|
|
23246
23364
|
});
|
|
23247
23365
|
setTelegramGateway(telegramGateway);
|
|
23248
|
-
|
|
23366
|
+
app56.route("/", telegramGateway.routes());
|
|
23249
23367
|
telegramGateway.startSweeper();
|
|
23250
23368
|
var chatRoutes = createChatRoutes({
|
|
23251
23369
|
handleInbound: (input) => webchatGateway.handleInbound(input),
|
|
@@ -23264,21 +23382,26 @@ var scheduleInjectRoutes = createScheduleInjectRoutes({
|
|
|
23264
23382
|
const sent = await sendTelegramText(botToken, chatId, text);
|
|
23265
23383
|
if (!sent.ok) throw new Error(sent.error ?? "telegram send failed");
|
|
23266
23384
|
},
|
|
23267
|
-
effectiveAccountFor: (accountId, accountDir, destination) =>
|
|
23385
|
+
effectiveAccountFor: (accountId, accountDir, destination) => {
|
|
23386
|
+
const managedSub = managedAccountFor(readAccountManagers(accountDir), destination);
|
|
23387
|
+
if (managedSub === null) return accountId;
|
|
23388
|
+
if (!listValidAccounts().some((a) => a.accountId === managedSub)) return null;
|
|
23389
|
+
return managedSub;
|
|
23390
|
+
}
|
|
23268
23391
|
});
|
|
23269
|
-
|
|
23270
|
-
|
|
23392
|
+
app56.route("/api/channel/schedule-inject", scheduleInjectRoutes);
|
|
23393
|
+
app56.use("*", clientIpMiddleware);
|
|
23271
23394
|
function allowsSameOriginFraming(path2) {
|
|
23272
23395
|
return path2 === "/vnc-viewer.html" || path2.startsWith("/api/admin/attachment/") || path2.startsWith("/api/public-reader/attachment/") || path2 === "/api/admin/files/download";
|
|
23273
23396
|
}
|
|
23274
|
-
|
|
23397
|
+
app56.use("*", async (c, next) => {
|
|
23275
23398
|
await next();
|
|
23276
23399
|
c.header("X-Content-Type-Options", "nosniff");
|
|
23277
23400
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
23278
23401
|
c.header("X-Frame-Options", allowsSameOriginFraming(c.req.path) ? "SAMEORIGIN" : "DENY");
|
|
23279
23402
|
});
|
|
23280
23403
|
var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
|
|
23281
|
-
|
|
23404
|
+
app56.use("*", async (c, next) => {
|
|
23282
23405
|
if (!HTTP_LOG_PATHS.has(c.req.path)) {
|
|
23283
23406
|
await next();
|
|
23284
23407
|
return;
|
|
@@ -23296,7 +23419,7 @@ app55.use("*", async (c, next) => {
|
|
|
23296
23419
|
});
|
|
23297
23420
|
}
|
|
23298
23421
|
});
|
|
23299
|
-
|
|
23422
|
+
app56.use("*", async (c, next) => {
|
|
23300
23423
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
23301
23424
|
if (isOperatorHost(host, getOperatorDomains()) || !isPublicHost(host)) {
|
|
23302
23425
|
await next();
|
|
@@ -23334,7 +23457,7 @@ function resolveRemoteAuthOpts(c) {
|
|
|
23334
23457
|
return { ...brandLoginOpts, origin };
|
|
23335
23458
|
}
|
|
23336
23459
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
23337
|
-
|
|
23460
|
+
app56.post("/__remote-auth/login", async (c) => {
|
|
23338
23461
|
const client = clientFrom(c);
|
|
23339
23462
|
const clientIp = client.ip || "unknown";
|
|
23340
23463
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -23379,7 +23502,7 @@ app55.post("/__remote-auth/login", async (c) => {
|
|
|
23379
23502
|
}
|
|
23380
23503
|
});
|
|
23381
23504
|
});
|
|
23382
|
-
|
|
23505
|
+
app56.get("/__remote-auth/logout", (c) => {
|
|
23383
23506
|
const client = clientFrom(c);
|
|
23384
23507
|
const clientIp = client.ip || "unknown";
|
|
23385
23508
|
console.error(`[remote-auth] logout ip=${clientIp}`);
|
|
@@ -23392,7 +23515,7 @@ app55.get("/__remote-auth/logout", (c) => {
|
|
|
23392
23515
|
}
|
|
23393
23516
|
});
|
|
23394
23517
|
});
|
|
23395
|
-
|
|
23518
|
+
app56.post("/__remote-auth/change-password", async (c) => {
|
|
23396
23519
|
const client = clientFrom(c);
|
|
23397
23520
|
const clientIp = client.ip || "unknown";
|
|
23398
23521
|
const rateLimited = checkRateLimit(client);
|
|
@@ -23451,13 +23574,13 @@ app55.post("/__remote-auth/change-password", async (c) => {
|
|
|
23451
23574
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
23452
23575
|
}
|
|
23453
23576
|
});
|
|
23454
|
-
|
|
23577
|
+
app56.get("/__remote-auth/setup", (c) => {
|
|
23455
23578
|
if (isRemoteAuthConfigured()) {
|
|
23456
23579
|
return c.redirect("/");
|
|
23457
23580
|
}
|
|
23458
23581
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "setup" }), 200);
|
|
23459
23582
|
});
|
|
23460
|
-
|
|
23583
|
+
app56.post("/__remote-auth/set-initial-password", async (c) => {
|
|
23461
23584
|
if (isRemoteAuthConfigured()) {
|
|
23462
23585
|
return c.redirect("/");
|
|
23463
23586
|
}
|
|
@@ -23495,10 +23618,10 @@ app55.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
23495
23618
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
23496
23619
|
}
|
|
23497
23620
|
});
|
|
23498
|
-
|
|
23621
|
+
app56.get("/api/remote-auth/status", (c) => {
|
|
23499
23622
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
23500
23623
|
});
|
|
23501
|
-
|
|
23624
|
+
app56.post("/api/remote-auth/set-password", async (c) => {
|
|
23502
23625
|
let body;
|
|
23503
23626
|
try {
|
|
23504
23627
|
body = await c.req.json();
|
|
@@ -23537,10 +23660,10 @@ app55.post("/api/remote-auth/set-password", async (c) => {
|
|
|
23537
23660
|
return c.json({ error: "Failed to save password" }, 500);
|
|
23538
23661
|
}
|
|
23539
23662
|
});
|
|
23540
|
-
|
|
23663
|
+
app56.route("/api/_client-error", client_error_default);
|
|
23541
23664
|
console.log("[client-error-route] mounted");
|
|
23542
23665
|
var PWA_PUBLIC_PATHS = /* @__PURE__ */ new Set(["/sw.js", ...PWA_SURFACES.map((s) => s.manifestPath)]);
|
|
23543
|
-
|
|
23666
|
+
app56.use("*", async (c, next) => {
|
|
23544
23667
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
23545
23668
|
const path2 = c.req.path;
|
|
23546
23669
|
if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/") || // Public free/busy is read by the booking page (a separate Cloudflare Pages
|
|
@@ -23584,26 +23707,26 @@ app55.use("*", async (c, next) => {
|
|
|
23584
23707
|
}
|
|
23585
23708
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), redirect: path2 }), 200);
|
|
23586
23709
|
});
|
|
23587
|
-
|
|
23588
|
-
|
|
23589
|
-
|
|
23590
|
-
|
|
23591
|
-
|
|
23592
|
-
|
|
23710
|
+
app56.route("/api/health", health_default);
|
|
23711
|
+
app56.route("/api/chat", chatRoutes);
|
|
23712
|
+
app56.route("/api/whatsapp", whatsapp_default);
|
|
23713
|
+
app56.route("/api/whatsapp-reader", whatsapp_reader_default);
|
|
23714
|
+
app56.route("/api/public-reader", public_reader_default);
|
|
23715
|
+
app56.route("/api/webchat", createWebchatRoutes({
|
|
23593
23716
|
handleInbound: (input) => webchatGateway.handleInbound(input),
|
|
23594
23717
|
// Task 940 — the permission relay's pointer read + verdict write.
|
|
23595
23718
|
pendingPromptFor: (key) => webchatGateway.pendingPromptFor(key),
|
|
23596
23719
|
deliveryFailureFor: (key) => webchatGateway.deliveryFailureFor(key),
|
|
23597
23720
|
resolvePermissionVerdict: (key, requestId, behavior) => webchatGateway.resolvePermissionVerdict(key, requestId, behavior)
|
|
23598
23721
|
}));
|
|
23599
|
-
|
|
23600
|
-
|
|
23601
|
-
|
|
23602
|
-
|
|
23603
|
-
|
|
23604
|
-
|
|
23605
|
-
|
|
23606
|
-
|
|
23722
|
+
app56.route("/api/webchat/greeting", webchat_greeting_default);
|
|
23723
|
+
app56.route("/api/telegram", telegram_default);
|
|
23724
|
+
app56.route("/api/quickbooks", quickbooks_default);
|
|
23725
|
+
app56.route("/api/onboarding", onboarding_default);
|
|
23726
|
+
app56.route("/api/admin", admin_default);
|
|
23727
|
+
app56.route("/api/access", access_default);
|
|
23728
|
+
app56.route("/api/session", session_default2);
|
|
23729
|
+
app56.route("/api/calendar", calendar_public_default);
|
|
23607
23730
|
var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
|
|
23608
23731
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
23609
23732
|
var IMAGE_MIME = {
|
|
@@ -23615,7 +23738,7 @@ var IMAGE_MIME = {
|
|
|
23615
23738
|
".svg": "image/svg+xml",
|
|
23616
23739
|
".ico": "image/x-icon"
|
|
23617
23740
|
};
|
|
23618
|
-
|
|
23741
|
+
app56.get("/agent-assets/:slug/:filename", (c) => {
|
|
23619
23742
|
const slug = c.req.param("slug");
|
|
23620
23743
|
const filename = c.req.param("filename");
|
|
23621
23744
|
if (!SAFE_SLUG_RE2.test(slug)) {
|
|
@@ -23650,7 +23773,7 @@ app55.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
23650
23773
|
"Cache-Control": "public, max-age=3600"
|
|
23651
23774
|
});
|
|
23652
23775
|
});
|
|
23653
|
-
|
|
23776
|
+
app56.get("/generated/:filename", (c) => {
|
|
23654
23777
|
const filename = c.req.param("filename");
|
|
23655
23778
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
23656
23779
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -23680,10 +23803,10 @@ app55.get("/generated/:filename", (c) => {
|
|
|
23680
23803
|
"Cache-Control": "public, max-age=86400"
|
|
23681
23804
|
});
|
|
23682
23805
|
});
|
|
23683
|
-
|
|
23684
|
-
|
|
23685
|
-
|
|
23686
|
-
|
|
23806
|
+
app56.route("/sites", sites_default);
|
|
23807
|
+
app56.route("/listings", listings_default);
|
|
23808
|
+
app56.route("/v", visitor_event_default);
|
|
23809
|
+
app56.route("/v", visitor_consent_default);
|
|
23687
23810
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
23688
23811
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
23689
23812
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
@@ -23838,7 +23961,7 @@ function brandedPublicHtml(agentSlug) {
|
|
|
23838
23961
|
function agentUnavailableHtml() {
|
|
23839
23962
|
return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>${escapeHtml(BRAND.productName)}</title></head><body style="font-family:system-ui,sans-serif;max-width:32rem;margin:4rem auto;padding:0 1.5rem;color:#222"><h1 style="font-size:1.25rem">Agent unavailable</h1><p>This agent isn't available right now. If you reached this page from a saved link, the agent may have been turned off.</p></body></html>`;
|
|
23840
23963
|
}
|
|
23841
|
-
|
|
23964
|
+
app56.get("/", (c) => {
|
|
23842
23965
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
23843
23966
|
const klass = classifyHost(host, getOperatorDomains(), isPublicHost);
|
|
23844
23967
|
if (klass === "operator") {
|
|
@@ -23860,12 +23983,12 @@ app55.get("/", (c) => {
|
|
|
23860
23983
|
console.log(`[host-class] host=${host} class=admin served=index.html`);
|
|
23861
23984
|
return c.html(cachedHtml("index.html"));
|
|
23862
23985
|
});
|
|
23863
|
-
|
|
23986
|
+
app56.get("/public", (c) => {
|
|
23864
23987
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
23865
23988
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
23866
23989
|
return c.html(cachedHtml("public.html"));
|
|
23867
23990
|
});
|
|
23868
|
-
|
|
23991
|
+
app56.get("/public-chat", (c) => {
|
|
23869
23992
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
23870
23993
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
23871
23994
|
return c.html(cachedHtml("public.html"));
|
|
@@ -23884,9 +24007,9 @@ async function logViewerFetch(c, next) {
|
|
|
23884
24007
|
duration_ms: Date.now() - start
|
|
23885
24008
|
});
|
|
23886
24009
|
}
|
|
23887
|
-
|
|
23888
|
-
|
|
23889
|
-
|
|
24010
|
+
app56.use("/vnc-viewer.html", logViewerFetch);
|
|
24011
|
+
app56.use("/vnc-popout.html", logViewerFetch);
|
|
24012
|
+
app56.get("/vnc-popout.html", (c) => {
|
|
23890
24013
|
let html = htmlCache.get("vnc-popout.html");
|
|
23891
24014
|
if (!html) {
|
|
23892
24015
|
html = readFileSync35(resolve33(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
@@ -23899,7 +24022,7 @@ app55.get("/vnc-popout.html", (c) => {
|
|
|
23899
24022
|
}
|
|
23900
24023
|
return c.html(html);
|
|
23901
24024
|
});
|
|
23902
|
-
|
|
24025
|
+
app56.post("/api/vnc/client-event", async (c) => {
|
|
23903
24026
|
let body;
|
|
23904
24027
|
try {
|
|
23905
24028
|
body = await c.req.json();
|
|
@@ -23920,11 +24043,11 @@ app55.post("/api/vnc/client-event", async (c) => {
|
|
|
23920
24043
|
});
|
|
23921
24044
|
return c.json({ ok: true });
|
|
23922
24045
|
});
|
|
23923
|
-
|
|
24046
|
+
app56.get("/g/:slug", (c) => {
|
|
23924
24047
|
return c.html(brandedPublicHtml(resolveDefaultSlug() ?? void 0));
|
|
23925
24048
|
});
|
|
23926
24049
|
for (const pwa of PWA_SURFACES) {
|
|
23927
|
-
|
|
24050
|
+
app56.get(pwa.manifestPath, (c) => {
|
|
23928
24051
|
const manifest = buildManifest(pwa, {
|
|
23929
24052
|
productName: BRAND.productName,
|
|
23930
24053
|
appIcon192: brandAppIcon192Path,
|
|
@@ -23940,7 +24063,7 @@ for (const pwa of PWA_SURFACES) {
|
|
|
23940
24063
|
return c.body(JSON.stringify(manifest));
|
|
23941
24064
|
});
|
|
23942
24065
|
}
|
|
23943
|
-
|
|
24066
|
+
app56.get("/sw.js", (c) => {
|
|
23944
24067
|
if (SW_SOURCE == null) {
|
|
23945
24068
|
console.error("[pwa] op=sw status=500 reason=sw-source-missing");
|
|
23946
24069
|
return c.text("Service worker unavailable", 500);
|
|
@@ -23949,12 +24072,12 @@ app55.get("/sw.js", (c) => {
|
|
|
23949
24072
|
console.log(`[pwa] op=sw status=200 ct=${SW_CONTENT_TYPE}`);
|
|
23950
24073
|
return c.body(SW_SOURCE);
|
|
23951
24074
|
});
|
|
23952
|
-
|
|
24075
|
+
app56.get("/graph", (c) => {
|
|
23953
24076
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
23954
24077
|
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
23955
24078
|
return c.html(cachedHtml("graph.html"));
|
|
23956
24079
|
});
|
|
23957
|
-
|
|
24080
|
+
app56.get("/chat", (c) => {
|
|
23958
24081
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
23959
24082
|
if (isOperatorHost(host, getOperatorDomains())) {
|
|
23960
24083
|
console.log(`[host-class] host=${host} class=operator served=operator.html`);
|
|
@@ -23963,22 +24086,22 @@ app55.get("/chat", (c) => {
|
|
|
23963
24086
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
23964
24087
|
return c.html(cachedHtml("chat.html"));
|
|
23965
24088
|
});
|
|
23966
|
-
|
|
24089
|
+
app56.get("/data", (c) => {
|
|
23967
24090
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
23968
24091
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
23969
24092
|
return c.html(cachedHtml("data.html"));
|
|
23970
24093
|
});
|
|
23971
|
-
|
|
24094
|
+
app56.get("/calendar", (c) => {
|
|
23972
24095
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
23973
24096
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
23974
24097
|
return c.html(cachedHtml("calendar.html"));
|
|
23975
24098
|
});
|
|
23976
|
-
|
|
24099
|
+
app56.get("/browser", (c) => {
|
|
23977
24100
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
23978
24101
|
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
23979
24102
|
return c.html(cachedHtml("browser.html"));
|
|
23980
24103
|
});
|
|
23981
|
-
|
|
24104
|
+
app56.get("/:slug", async (c, next) => {
|
|
23982
24105
|
const slug = c.req.param("slug");
|
|
23983
24106
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
23984
24107
|
const account = resolveAccount();
|
|
@@ -23993,13 +24116,13 @@ app55.get("/:slug", async (c, next) => {
|
|
|
23993
24116
|
await next();
|
|
23994
24117
|
});
|
|
23995
24118
|
if (brandFaviconPath !== "/favicon.ico") {
|
|
23996
|
-
|
|
24119
|
+
app56.get("/favicon.ico", (c) => {
|
|
23997
24120
|
c.header("Cache-Control", "public, max-age=300");
|
|
23998
24121
|
return c.redirect(brandFaviconPath, 302);
|
|
23999
24122
|
});
|
|
24000
24123
|
}
|
|
24001
|
-
|
|
24002
|
-
|
|
24124
|
+
app56.use("/*", serveStatic({ root: "./public" }));
|
|
24125
|
+
app56.all("*", (c) => {
|
|
24003
24126
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
24004
24127
|
const path2 = c.req.path;
|
|
24005
24128
|
if (isPublicHost(host)) {
|
|
@@ -24013,7 +24136,7 @@ app55.all("*", (c) => {
|
|
|
24013
24136
|
});
|
|
24014
24137
|
var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
|
|
24015
24138
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
24016
|
-
var httpServer = serve({ fetch:
|
|
24139
|
+
var httpServer = serve({ fetch: app56.fetch, port, hostname });
|
|
24017
24140
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
24018
24141
|
{
|
|
24019
24142
|
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join34(__dirname, "..");
|
|
@@ -24113,7 +24236,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
24113
24236
|
}
|
|
24114
24237
|
try {
|
|
24115
24238
|
const registered = [];
|
|
24116
|
-
for (const r of
|
|
24239
|
+
for (const r of app56.routes ?? []) {
|
|
24117
24240
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
24118
24241
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
24119
24242
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|
|
@@ -24243,7 +24366,7 @@ try {
|
|
|
24243
24366
|
} catch (err) {
|
|
24244
24367
|
console.error(`[graph-health] account-enumeration unavailable reason=${err instanceof Error ? err.message : String(err)}`);
|
|
24245
24368
|
}
|
|
24246
|
-
var configDirForWhatsApp =
|
|
24369
|
+
var configDirForWhatsApp = basename13(MAXY_DIR) || ".maxy";
|
|
24247
24370
|
var bootAccount = resolveAccount();
|
|
24248
24371
|
if (bootAccount) {
|
|
24249
24372
|
migrateRemovedConfigKeys(bootAccount.accountDir);
|
|
@@ -24263,6 +24386,7 @@ reconcileEnabledPlugins(bootAccount?.accountDir, bootAccount?.config, bootAccoun
|
|
|
24263
24386
|
for (const acct of listValidAccounts()) {
|
|
24264
24387
|
cleanupLeakedPremiumSubs(acct.accountDir, acct.config, acct.accountId);
|
|
24265
24388
|
}
|
|
24389
|
+
purgeNonSocketAdminPhonesAtBoot();
|
|
24266
24390
|
warnOnChannelAdminBindingDrift();
|
|
24267
24391
|
var bootEnabled = Array.isArray(bootAccountConfig?.enabledPlugins) ? bootAccountConfig.enabledPlugins : [];
|
|
24268
24392
|
var bootDelivered = [];
|
|
@@ -24322,6 +24446,10 @@ init({
|
|
|
24322
24446
|
console.error(`[whatsapp:route] dropped reason=no-text-no-media senderId=${msg.senderPhone} mediaCount=${msg.media.length}`);
|
|
24323
24447
|
return;
|
|
24324
24448
|
}
|
|
24449
|
+
if (!msg.effectiveAccountId) {
|
|
24450
|
+
console.error(`[whatsapp:route] op=dropped reason=no-effective-account senderId=${msg.senderPhone}`);
|
|
24451
|
+
return;
|
|
24452
|
+
}
|
|
24325
24453
|
if (decision.role === "public") {
|
|
24326
24454
|
console.error(`[whatsapp:route] op=routed agentType=public personId=${decision.personId} senderId=${msg.senderPhone}`);
|
|
24327
24455
|
}
|
|
@@ -24330,6 +24458,7 @@ init({
|
|
|
24330
24458
|
});
|
|
24331
24459
|
await waGateway.handleInbound({
|
|
24332
24460
|
accountId: msg.accountId,
|
|
24461
|
+
effectiveAccountId: msg.effectiveAccountId,
|
|
24333
24462
|
senderId: msg.senderPhone,
|
|
24334
24463
|
role: decision.role,
|
|
24335
24464
|
personId: decision.personId,
|