@rubytech/create-maxy-code 0.1.284 → 0.1.285
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__/installer-settings-permissions.test.js +86 -8
- package/dist/index.js +1 -1
- package/dist/permissions-seed.js +72 -11
- package/package.json +1 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +5 -1
- package/payload/platform/plugins/docs/references/admin-ui.md +2 -0
- package/payload/platform/plugins/docs/references/platform.md +2 -0
- package/payload/server/public/assets/AdminShell-DwPVr9K1.js +1 -0
- package/payload/server/public/assets/{Checkbox-syHoU9nY.js → Checkbox-BdDmGlvK.js} +1 -1
- package/payload/server/public/assets/{admin-DyuZ4NT5.js → admin-BYtGQJ0d.js} +1 -1
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-DsionCio.js → architectureDiagram-Q4EWVU46-CBx_GoUY.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-NOG5yVZk.js → blockDiagram-DXYQGD6D-DvWR4fpv.js} +1 -1
- package/payload/server/public/assets/{browser-XrVAUQdG.js → browser-2PXsTraZ.js} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-DwFV1k9I.js → c4Diagram-AHTNJAMY-BbSOxeeU.js} +1 -1
- package/payload/server/public/assets/channel-C4NqYS8u.js +1 -0
- package/payload/server/public/assets/{chunk-336JU56O-iJ4ISPCi.js → chunk-336JU56O-DJzmXTk5.js} +2 -2
- package/payload/server/public/assets/{chunk-426QAEUC-sWe0Iexz.js → chunk-426QAEUC-BSwzskM5.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-kKNYi2_i.js → chunk-4TB4RGXK-C-fH8BTZ.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-Car3r0he.js → chunk-5FUZZQ4R-DW-MaiGX.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-DR9EfLvj.js → chunk-5PVQY5BW-DlKbwC1X.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-DLUWVRZV.js → chunk-EDXVE4YY-DnkdxwAt.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-B4bNJo6C.js → chunk-ENJZ2VHE-BTfezWsj.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-Qzl8Ki0l.js → chunk-ICPOFSXX-BGg8uTtu.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-BenBO6O_.js → chunk-OYMX7WX6-CYJInav8.js} +1 -1
- package/payload/server/public/assets/{chunk-U2HBQHQK-DewM8R0D.js → chunk-U2HBQHQK-B6kD6ZHU.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-C22Q6Ea4.js → chunk-X2U36JSP-7tvWkjym.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-DfUUNTnA.js → chunk-YZCP3GAM-D6NjOb5l.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-CUT6zma2.js → chunk-ZZ45TVLE-Dqz69eJy.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-CI3_kz04.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-UP3RcKH9.js +1 -0
- package/payload/server/public/assets/clone-CvAPweMB.js +1 -0
- package/payload/server/public/assets/{dagre-KV5264BT-D4EGb60h.js → dagre-KV5264BT-DswETLwm.js} +1 -1
- package/payload/server/public/assets/{dagre-CYXRIdv0.js → dagre-di-KHpsq.js} +1 -1
- package/payload/server/public/assets/{data-tcu3MXmK.js → data-B6vpe0Zj.js} +1 -1
- package/payload/server/public/assets/{diagram-5BDNPKRD-BzieCEfT.js → diagram-5BDNPKRD-DWmq_Zkl.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-DDbO71XD.js → diagram-G4DWMVQ6-BVi6yjLL.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-DqQ_UXDA.js → diagram-MMDJMWI5-D6XKyUAT.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-CFyxA1aZ.js → diagram-TYMM5635-sU1d7P6W.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-BMaEBbOK.js → erDiagram-SMLLAGMA-CY6qPZvu.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-De5ChZQP.js → flowDiagram-DWJPFMVM-CE9hd869.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-CXEMPVaK.js → ganttDiagram-T4ZO3ILL-Cbb885gt.js} +1 -1
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-OZedr_6y.js → gitGraphDiagram-UUTBAWPF-BNzO3jBu.js} +1 -1
- package/payload/server/public/assets/{graph-I4GyC2MW.js → graph-DfegJdnT.js} +1 -1
- package/payload/server/public/assets/{graph-labels-DSDTSBfM.js → graph-labels-BG4aqzs6.js} +1 -1
- package/payload/server/public/assets/{graphlib-CN4nhD2U.js → graphlib-CIzKPoW_.js} +1 -1
- package/payload/server/public/assets/{infoDiagram-42DDH7IO-CSqg4nRL.js → infoDiagram-42DDH7IO-DWGtofAT.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-ChlzrZyx.js → ishikawaDiagram-UXIWVN3A-UG1rus6G.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-DsrK55ZO.js → journeyDiagram-VCZTEJTY-CYhHYXmj.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-DYF-_Rym.js → kanban-definition-6JOO6SKY-CWHj9DHX.js} +1 -1
- package/payload/server/public/assets/{line-3zmwI8XK.js → line-vMN9CmXx.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-BrcX8-cl.js → mermaid-parser.core-5X7WWCZe.js} +1 -1
- package/payload/server/public/assets/{mermaid.core-CBdz3b1N.js → mermaid.core-B0zUZsT6.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-BqCqlYZb.js → mindmap-definition-QFDTVHPH-BGr68ynR.js} +1 -1
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-D5LiILuM.js → pieDiagram-DEJITSTG-Bo3zU_w2.js} +1 -1
- package/payload/server/public/assets/{public-udi_Z7la.js → public-DCZ92LR9.js} +3 -3
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-C3iuI5l_.js → quadrantDiagram-34T5L4WZ-o-dLMRj-.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-CTPOw5qQ.js → requirementDiagram-MS252O5E-D_O_ZclX.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-D_5aVlYp.js → sankeyDiagram-XADWPNL6-Doz7uWIn.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-D7h5vocM.js → sequenceDiagram-FGHM5R23-r1VW_jgc.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-DyZjuwPj.js → stateDiagram-FHFEXIEX-B7O06aua.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-Bo1g66pA.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-BqpVYJz_.js → timeline-definition-GMOUNBTQ-WS2AL0yL.js} +1 -1
- package/payload/server/public/assets/{useSelectionMode-BnRcJeg2.css → useSelectionMode-lFraIQzT.css} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-Czflml0e.js → vennDiagram-DHZGUBPP-_-FLcVAh.js} +1 -1
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-Cqz3pSTK.js → wardleyDiagram-NUSXRM2D-nZ3oO0ih.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-CS5dEuUO.js → xychartDiagram-5P7HB3ND-CqTdRM37.js} +1 -1
- package/payload/server/public/browser.html +4 -4
- package/payload/server/public/data.html +5 -5
- package/payload/server/public/graph.html +6 -6
- package/payload/server/public/index.html +5 -5
- package/payload/server/public/public.html +4 -4
- package/payload/server/server.js +236 -155
- package/payload/server/public/assets/AdminShell-8Y7-maNi.js +0 -1
- package/payload/server/public/assets/channel-D8Go_zJk.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-BLb1mzrT.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-Ctj5qYTS.js +0 -1
- package/payload/server/public/assets/clone-DGZ2vydA.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BiW9pGXy.js +0 -1
- /package/payload/server/public/assets/{useSelectionMode-BPzPjKP_.js → useSelectionMode-mzxTOyBv.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -6861,8 +6861,8 @@ app3.get("/group-info", async (c) => {
|
|
|
6861
6861
|
var whatsapp_default = app3;
|
|
6862
6862
|
|
|
6863
6863
|
// server/routes/whatsapp-reader.ts
|
|
6864
|
-
import { readFileSync as
|
|
6865
|
-
import { basename as basename2, dirname, join as
|
|
6864
|
+
import { readFileSync as readFileSync10, watch, statSync as statSync4, openSync, readSync, closeSync } from "fs";
|
|
6865
|
+
import { basename as basename2, dirname, join as join9, resolve as resolve9, sep as sep2 } from "path";
|
|
6866
6866
|
|
|
6867
6867
|
// server/routes/admin/sidebar-sessions.ts
|
|
6868
6868
|
import { readdirSync as readdirSync4, readFileSync as readFileSync8, statSync as statSync2 } from "fs";
|
|
@@ -7118,16 +7118,115 @@ app4.get("/", requireAdminSession, async (c) => {
|
|
|
7118
7118
|
var sidebar_sessions_default = app4;
|
|
7119
7119
|
|
|
7120
7120
|
// app/lib/whatsapp-reader/select-sessions.ts
|
|
7121
|
-
function
|
|
7122
|
-
return rows.filter((r) => r.role === "admin" && r.channel === "whatsapp").sort((a, b) => b.startedAt.localeCompare(a.startedAt)).map((r) => ({
|
|
7121
|
+
function selectAdminChannelSessions(rows) {
|
|
7122
|
+
return rows.filter((r) => r.role === "admin" && (r.channel === "whatsapp" || r.channel === "telegram")).sort((a, b) => b.startedAt.localeCompare(a.startedAt)).map((r) => ({
|
|
7123
7123
|
sessionId: r.sessionId,
|
|
7124
7124
|
projectDir: r.projectDir,
|
|
7125
7125
|
title: r.title,
|
|
7126
7126
|
senderId: r.senderId,
|
|
7127
|
-
startedAt: r.startedAt
|
|
7127
|
+
startedAt: r.startedAt,
|
|
7128
|
+
channel: r.channel,
|
|
7129
|
+
operatorName: null
|
|
7128
7130
|
}));
|
|
7129
7131
|
}
|
|
7130
7132
|
|
|
7133
|
+
// app/lib/admin-identity/pin-validator.ts
|
|
7134
|
+
import { createHash as createHash2 } from "crypto";
|
|
7135
|
+
import { existsSync as existsSync6, readFileSync as readFileSync9, readdirSync as readdirSync5, statSync as statSync3 } from "fs";
|
|
7136
|
+
import { join as join8 } from "path";
|
|
7137
|
+
function hashPin(pin) {
|
|
7138
|
+
return createHash2("sha256").update(pin).digest("hex");
|
|
7139
|
+
}
|
|
7140
|
+
function readUsersFile(usersFilePath) {
|
|
7141
|
+
if (!existsSync6(usersFilePath)) return null;
|
|
7142
|
+
const raw = readFileSync9(usersFilePath, "utf-8").trim();
|
|
7143
|
+
if (!raw) return [];
|
|
7144
|
+
return JSON.parse(raw);
|
|
7145
|
+
}
|
|
7146
|
+
function validatePin(pin, usersFilePath) {
|
|
7147
|
+
let users;
|
|
7148
|
+
try {
|
|
7149
|
+
users = readUsersFile(usersFilePath);
|
|
7150
|
+
} catch (err) {
|
|
7151
|
+
return { kind: "corrupt", message: err instanceof Error ? err.message : String(err) };
|
|
7152
|
+
}
|
|
7153
|
+
if (users === null || users.length === 0) return { kind: "unavailable" };
|
|
7154
|
+
const inputHash = hashPin(pin);
|
|
7155
|
+
const matched = users.find((u) => u.pin === inputHash);
|
|
7156
|
+
return matched ? { kind: "match", userId: matched.userId } : { kind: "miss" };
|
|
7157
|
+
}
|
|
7158
|
+
function scanForOrphanedAccountAdmins(users, accountsDir) {
|
|
7159
|
+
const known = new Set(users.map((u) => u.userId));
|
|
7160
|
+
const orphans = [];
|
|
7161
|
+
if (!existsSync6(accountsDir)) return orphans;
|
|
7162
|
+
let entries;
|
|
7163
|
+
try {
|
|
7164
|
+
entries = readdirSync5(accountsDir);
|
|
7165
|
+
} catch {
|
|
7166
|
+
return orphans;
|
|
7167
|
+
}
|
|
7168
|
+
for (const entry of entries) {
|
|
7169
|
+
if (entry.startsWith(".")) continue;
|
|
7170
|
+
const accountDir = join8(accountsDir, entry);
|
|
7171
|
+
try {
|
|
7172
|
+
if (!statSync3(accountDir).isDirectory()) continue;
|
|
7173
|
+
} catch {
|
|
7174
|
+
continue;
|
|
7175
|
+
}
|
|
7176
|
+
const accountJsonPath = join8(accountDir, "account.json");
|
|
7177
|
+
if (!existsSync6(accountJsonPath)) continue;
|
|
7178
|
+
try {
|
|
7179
|
+
const config = JSON.parse(readFileSync9(accountJsonPath, "utf-8"));
|
|
7180
|
+
const admins = config.admins ?? [];
|
|
7181
|
+
for (const a of admins) {
|
|
7182
|
+
if (typeof a.userId === "string" && !known.has(a.userId)) orphans.push(a.userId);
|
|
7183
|
+
}
|
|
7184
|
+
} catch {
|
|
7185
|
+
continue;
|
|
7186
|
+
}
|
|
7187
|
+
}
|
|
7188
|
+
return orphans;
|
|
7189
|
+
}
|
|
7190
|
+
|
|
7191
|
+
// app/lib/whatsapp/inbound/resolve-admin-userid.ts
|
|
7192
|
+
function classifyAdminUserId(users, admins, senderPhone) {
|
|
7193
|
+
const matched = users.find((u) => typeof u.phone === "string" && phonesMatch(u.phone, senderPhone));
|
|
7194
|
+
if (!matched) return { kind: "no-users-binding" };
|
|
7195
|
+
return admins.some((a) => a.userId === matched.userId) ? { kind: "resolved", userId: matched.userId } : { kind: "userid-not-admin", userId: matched.userId };
|
|
7196
|
+
}
|
|
7197
|
+
function pickAdminUserId(users, admins, senderPhone) {
|
|
7198
|
+
const r = classifyAdminUserId(users, admins, senderPhone);
|
|
7199
|
+
return r.kind === "resolved" ? r.userId : null;
|
|
7200
|
+
}
|
|
7201
|
+
function resolveAdminUserId(params) {
|
|
7202
|
+
try {
|
|
7203
|
+
const users = readUsersFile(USERS_FILE);
|
|
7204
|
+
if (!users) return null;
|
|
7205
|
+
const account = listValidAccounts().find((a) => a.accountId === params.accountId);
|
|
7206
|
+
const admins = account?.config.admins ?? [];
|
|
7207
|
+
const direct = pickAdminUserId(users, admins, params.senderPhone);
|
|
7208
|
+
if (direct) return direct;
|
|
7209
|
+
const mapped = resolveViaLidMap(readLidMap() ?? {}, params.senderPhone);
|
|
7210
|
+
if (!mapped) return null;
|
|
7211
|
+
const viaLid = pickAdminUserId(users, admins, mapped);
|
|
7212
|
+
if (viaLid) {
|
|
7213
|
+
console.error(`[lid-map] resolved-via-cache lid=${params.senderPhone} userId=${viaLid.slice(0, 8)}`);
|
|
7214
|
+
}
|
|
7215
|
+
return viaLid;
|
|
7216
|
+
} catch {
|
|
7217
|
+
return null;
|
|
7218
|
+
}
|
|
7219
|
+
}
|
|
7220
|
+
|
|
7221
|
+
// app/lib/whatsapp-reader/resolve-operator-name.ts
|
|
7222
|
+
function resolveOperatorDisplay(userIdRes, nameRes) {
|
|
7223
|
+
if (userIdRes.kind === "no-users-binding") return { name: null, reason: "no-binding" };
|
|
7224
|
+
if (userIdRes.kind === "userid-not-admin") return { name: null, reason: "not-admin" };
|
|
7225
|
+
if (nameRes && nameRes.source === "neo4j") return { name: nameRes.joined, reason: null };
|
|
7226
|
+
if (nameRes && nameRes.reason === "neo4j-unreachable") return { name: null, reason: "neo4j-unreachable" };
|
|
7227
|
+
return { name: null, reason: "no-person-name" };
|
|
7228
|
+
}
|
|
7229
|
+
|
|
7131
7230
|
// app/lib/whatsapp-reader/parse-transcript.ts
|
|
7132
7231
|
var CLI_MARKER_PREFIXES2 = ["<local-command-", "<command-name>", "<command-message>"];
|
|
7133
7232
|
var CHANNEL_WRAPPER = /^<channel\b[^>]*>\n?([\s\S]*?)\n?<\/channel>$/;
|
|
@@ -7227,17 +7326,17 @@ var app5 = new Hono();
|
|
|
7227
7326
|
app5.get("/conversations", requireAdminSession, async (c) => {
|
|
7228
7327
|
const cfg = claudeConfigDir();
|
|
7229
7328
|
if (!cfg) return c.json({ conversations: [] });
|
|
7230
|
-
const projectsRoot =
|
|
7329
|
+
const projectsRoot = join9(cfg, "projects");
|
|
7231
7330
|
const userTitles = loadUserTitles(ACCOUNTS_DIR ?? null);
|
|
7232
7331
|
const rows = [];
|
|
7233
7332
|
for (const { path: path2 } of enumerateJsonls(projectsRoot)) {
|
|
7234
7333
|
const sessionId = basename2(path2).replace(/\.jsonl$/, "");
|
|
7235
7334
|
const projectDir = dirname(path2);
|
|
7236
|
-
const meta = readSidecarMeta(
|
|
7237
|
-
if (meta.role !== "admin" || meta.channel !== "whatsapp") continue;
|
|
7335
|
+
const meta = readSidecarMeta(join9(projectDir, `${sessionId}.meta.json`));
|
|
7336
|
+
if (meta.role !== "admin" || meta.channel !== "whatsapp" && meta.channel !== "telegram") continue;
|
|
7238
7337
|
let body = "";
|
|
7239
7338
|
try {
|
|
7240
|
-
body =
|
|
7339
|
+
body = readFileSync10(path2, "utf8");
|
|
7241
7340
|
} catch {
|
|
7242
7341
|
}
|
|
7243
7342
|
const { title } = resolveTitle(body, sessionId, userTitles);
|
|
@@ -7251,10 +7350,41 @@ app5.get("/conversations", requireAdminSession, async (c) => {
|
|
|
7251
7350
|
senderId: meta.senderId
|
|
7252
7351
|
});
|
|
7253
7352
|
}
|
|
7254
|
-
|
|
7353
|
+
const selected = selectAdminChannelSessions(rows);
|
|
7354
|
+
const account = resolveAccount();
|
|
7355
|
+
let users = [];
|
|
7356
|
+
if (account) {
|
|
7357
|
+
try {
|
|
7358
|
+
users = readUsersFile(USERS_FILE) ?? [];
|
|
7359
|
+
} catch (err) {
|
|
7360
|
+
console.error(`[wa-reader] op=users-file-unreadable reason=${err instanceof Error ? err.message : String(err)}`);
|
|
7361
|
+
users = [];
|
|
7362
|
+
}
|
|
7363
|
+
}
|
|
7364
|
+
const admins = account?.config.admins ?? [];
|
|
7365
|
+
const nameBySender = /* @__PURE__ */ new Map();
|
|
7366
|
+
const distinct = [...new Set(selected.map((r) => r.senderId).filter((s) => !!s))];
|
|
7367
|
+
await Promise.all(
|
|
7368
|
+
distinct.map(async (senderId) => {
|
|
7369
|
+
if (!account) {
|
|
7370
|
+
nameBySender.set(senderId, null);
|
|
7371
|
+
return;
|
|
7372
|
+
}
|
|
7373
|
+
const idRes = classifyAdminUserId(users, admins, senderId);
|
|
7374
|
+
const nameRes = idRes.kind === "resolved" ? await loadAdminUserName(account.accountId, idRes.userId) : null;
|
|
7375
|
+
const { name, reason } = resolveOperatorDisplay(idRes, nameRes);
|
|
7376
|
+
if (reason) console.error(`[wa-reader] op=operator-unresolved senderId=${senderId} reason=${reason}`);
|
|
7377
|
+
nameBySender.set(senderId, name);
|
|
7378
|
+
})
|
|
7379
|
+
);
|
|
7380
|
+
const conversations = selected.map((r) => ({
|
|
7381
|
+
...r,
|
|
7382
|
+
operatorName: r.senderId ? nameBySender.get(r.senderId) ?? null : null
|
|
7383
|
+
}));
|
|
7384
|
+
return c.json({ conversations });
|
|
7255
7385
|
});
|
|
7256
7386
|
function readFrom(path2, from) {
|
|
7257
|
-
const end =
|
|
7387
|
+
const end = statSync4(path2).size;
|
|
7258
7388
|
if (end <= from) return { buf: Buffer.alloc(0), end: from };
|
|
7259
7389
|
const fd = openSync(path2, "r");
|
|
7260
7390
|
try {
|
|
@@ -7265,41 +7395,73 @@ function readFrom(path2, from) {
|
|
|
7265
7395
|
closeSync(fd);
|
|
7266
7396
|
}
|
|
7267
7397
|
}
|
|
7398
|
+
function resumeOffset(lastEventId, fileEnd) {
|
|
7399
|
+
if (!lastEventId) return 0;
|
|
7400
|
+
const n = Number(lastEventId);
|
|
7401
|
+
if (!Number.isFinite(n) || n < 0) return 0;
|
|
7402
|
+
return Math.min(n, fileEnd);
|
|
7403
|
+
}
|
|
7268
7404
|
app5.get("/stream", requireAdminSession, (c) => {
|
|
7269
7405
|
const sessionId = c.req.query("sessionId") ?? "";
|
|
7270
7406
|
const projectDir = c.req.query("projectDir") ?? "";
|
|
7271
7407
|
const cfg = claudeConfigDir();
|
|
7272
|
-
const projectsRoot = cfg ? resolve9(
|
|
7408
|
+
const projectsRoot = cfg ? resolve9(join9(cfg, "projects")) : null;
|
|
7273
7409
|
if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId)) {
|
|
7274
7410
|
return c.json({ error: "bad session reference" }, 400);
|
|
7275
7411
|
}
|
|
7276
|
-
const jsonlPath = resolve9(
|
|
7412
|
+
const jsonlPath = resolve9(join9(projectDir, `${sessionId}.jsonl`));
|
|
7277
7413
|
if (!jsonlPath.startsWith(projectsRoot + sep2)) {
|
|
7278
7414
|
return c.json({ error: "bad session reference" }, 400);
|
|
7279
7415
|
}
|
|
7280
7416
|
const encoder = new TextEncoder();
|
|
7281
|
-
const send = (controller, turn) => controller.enqueue(encoder.encode(`
|
|
7417
|
+
const send = (controller, turn, id) => controller.enqueue(encoder.encode(`id: ${id}
|
|
7418
|
+
data: ${JSON.stringify(turn)}
|
|
7282
7419
|
|
|
7283
7420
|
`));
|
|
7421
|
+
const connId = `${sessionId.slice(0, 8)}-${process.hrtime.bigint().toString(36).slice(-6)}`;
|
|
7422
|
+
const startedAt = Date.now();
|
|
7423
|
+
const lastEventId = c.req.header("Last-Event-ID");
|
|
7284
7424
|
const readable = new ReadableStream({
|
|
7285
7425
|
start(controller) {
|
|
7286
|
-
|
|
7426
|
+
const fileEnd0 = (() => {
|
|
7427
|
+
try {
|
|
7428
|
+
return statSync4(jsonlPath).size;
|
|
7429
|
+
} catch {
|
|
7430
|
+
return 0;
|
|
7431
|
+
}
|
|
7432
|
+
})();
|
|
7433
|
+
let offset = resumeOffset(lastEventId, fileEnd0);
|
|
7434
|
+
console.log(`[wa-stream] op=open conn=${connId} sessionId=${sessionId} channel=reader resume=${offset}`);
|
|
7287
7435
|
const drain = () => {
|
|
7288
7436
|
try {
|
|
7289
7437
|
const { buf, end } = readFrom(jsonlPath, offset);
|
|
7290
7438
|
if (end <= offset) return;
|
|
7291
7439
|
const { lines, nextOffset } = splitNewLines(buf, offset);
|
|
7292
7440
|
offset = nextOffset;
|
|
7293
|
-
|
|
7441
|
+
let n = 0;
|
|
7442
|
+
for (const turn of parseTranscript(lines)) {
|
|
7443
|
+
send(controller, turn, offset);
|
|
7444
|
+
n++;
|
|
7445
|
+
}
|
|
7446
|
+
if (n > 0) console.log(`[wa-stream] op=drain conn=${connId} turns=${n}`);
|
|
7294
7447
|
} catch {
|
|
7295
7448
|
}
|
|
7296
7449
|
};
|
|
7297
|
-
|
|
7298
|
-
|
|
7299
|
-
|
|
7300
|
-
|
|
7301
|
-
|
|
7302
|
-
|
|
7450
|
+
if (offset === 0) {
|
|
7451
|
+
try {
|
|
7452
|
+
const { buf, end } = readFrom(jsonlPath, 0);
|
|
7453
|
+
offset = end;
|
|
7454
|
+
let n = 0;
|
|
7455
|
+
for (const turn of parseTranscript(buf.toString("utf8").split("\n"))) {
|
|
7456
|
+
send(controller, turn, offset);
|
|
7457
|
+
n++;
|
|
7458
|
+
}
|
|
7459
|
+
console.log(`[wa-stream] op=backlog conn=${connId} turns=${n} bytes=${end}`);
|
|
7460
|
+
} catch {
|
|
7461
|
+
controller.enqueue(encoder.encode('event: error\ndata: "read-failed"\n\n'));
|
|
7462
|
+
}
|
|
7463
|
+
} else {
|
|
7464
|
+
drain();
|
|
7303
7465
|
}
|
|
7304
7466
|
let watcher = null;
|
|
7305
7467
|
try {
|
|
@@ -7307,9 +7469,18 @@ app5.get("/stream", requireAdminSession, (c) => {
|
|
|
7307
7469
|
} catch {
|
|
7308
7470
|
}
|
|
7309
7471
|
const poll = setInterval(drain, 1e3);
|
|
7472
|
+
const heartbeat = setInterval(() => {
|
|
7473
|
+
try {
|
|
7474
|
+
controller.enqueue(encoder.encode(": ping\n\n"));
|
|
7475
|
+
console.log(`[wa-stream] op=heartbeat conn=${connId}`);
|
|
7476
|
+
} catch {
|
|
7477
|
+
}
|
|
7478
|
+
}, 2e4);
|
|
7310
7479
|
c.req.raw.signal.addEventListener("abort", () => {
|
|
7311
7480
|
watcher?.close();
|
|
7312
7481
|
clearInterval(poll);
|
|
7482
|
+
clearInterval(heartbeat);
|
|
7483
|
+
console.log(`[wa-stream] op=close conn=${connId} ranMs=${Date.now() - startedAt} reason=client-abort`);
|
|
7313
7484
|
try {
|
|
7314
7485
|
controller.close();
|
|
7315
7486
|
} catch {
|
|
@@ -7325,8 +7496,8 @@ var whatsapp_reader_default = app5;
|
|
|
7325
7496
|
|
|
7326
7497
|
// server/routes/telegram.ts
|
|
7327
7498
|
import { homedir } from "os";
|
|
7328
|
-
import { resolve as resolve10, join as
|
|
7329
|
-
import { existsSync as
|
|
7499
|
+
import { resolve as resolve10, join as join10 } from "path";
|
|
7500
|
+
import { existsSync as existsSync7, readFileSync as readFileSync11 } from "fs";
|
|
7330
7501
|
|
|
7331
7502
|
// app/lib/telegram/access-control.ts
|
|
7332
7503
|
function checkTelegramAccess(params) {
|
|
@@ -7377,10 +7548,10 @@ var TAG21 = "[telegram-inbound]";
|
|
|
7377
7548
|
var DISPATCH_TIMEOUT_MS = 12e4;
|
|
7378
7549
|
function configDirName() {
|
|
7379
7550
|
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? resolve10(process.cwd(), "..");
|
|
7380
|
-
const brandPath =
|
|
7381
|
-
if (
|
|
7551
|
+
const brandPath = join10(platformRoot2, "config", "brand.json");
|
|
7552
|
+
if (existsSync7(brandPath)) {
|
|
7382
7553
|
try {
|
|
7383
|
-
return JSON.parse(
|
|
7554
|
+
return JSON.parse(readFileSync11(brandPath, "utf-8")).configDir ?? ".maxy";
|
|
7384
7555
|
} catch {
|
|
7385
7556
|
}
|
|
7386
7557
|
}
|
|
@@ -7412,11 +7583,11 @@ app6.post("/", async (c) => {
|
|
|
7412
7583
|
return c.json({ ok: false }, 400);
|
|
7413
7584
|
}
|
|
7414
7585
|
const sp = secretPath(botType);
|
|
7415
|
-
if (!
|
|
7586
|
+
if (!existsSync7(sp)) {
|
|
7416
7587
|
console.error(`${TAG21} op=reject reason=no-secret-file botType=${botType}`);
|
|
7417
7588
|
return c.json({ ok: false }, 401);
|
|
7418
7589
|
}
|
|
7419
|
-
const expected =
|
|
7590
|
+
const expected = readFileSync11(sp, "utf-8").trim();
|
|
7420
7591
|
const got = c.req.header("x-telegram-bot-api-secret-token") ?? "";
|
|
7421
7592
|
if (got !== expected) {
|
|
7422
7593
|
console.error(`${TAG21} op=reject reason=bad-secret botType=${botType}`);
|
|
@@ -7479,12 +7650,12 @@ var telegram_default = app6;
|
|
|
7479
7650
|
|
|
7480
7651
|
// server/routes/onboarding.ts
|
|
7481
7652
|
import { spawn, spawnSync as spawnSync2, execFileSync as execFileSync2 } from "child_process";
|
|
7482
|
-
import { openSync as openSync2, closeSync as closeSync2, writeFileSync as writeFileSync6, writeSync, existsSync as
|
|
7483
|
-
import { createHash as
|
|
7653
|
+
import { openSync as openSync2, closeSync as closeSync2, writeFileSync as writeFileSync6, writeSync, existsSync as existsSync9, readFileSync as readFileSync13, unlinkSync } from "fs";
|
|
7654
|
+
import { createHash as createHash3, randomUUID as randomUUID7 } from "crypto";
|
|
7484
7655
|
|
|
7485
7656
|
// ../lib/admins-write/src/index.ts
|
|
7486
|
-
import { existsSync as
|
|
7487
|
-
import { dirname as dirname2, join as
|
|
7657
|
+
import { existsSync as existsSync8, readFileSync as readFileSync12, writeFileSync as writeFileSync5, renameSync, mkdirSync as mkdirSync2, readdirSync as readdirSync6, statSync as statSync5 } from "fs";
|
|
7658
|
+
import { dirname as dirname2, join as join11 } from "path";
|
|
7488
7659
|
function logLine(input, result) {
|
|
7489
7660
|
const userIdShort = input.userId.slice(0, 8);
|
|
7490
7661
|
console.error(
|
|
@@ -7501,8 +7672,8 @@ function writeAdminEntry(input) {
|
|
|
7501
7672
|
const result = { usersJsonResult: "noop", accountJsonResult: "noop" };
|
|
7502
7673
|
try {
|
|
7503
7674
|
let users = [];
|
|
7504
|
-
if (
|
|
7505
|
-
const raw =
|
|
7675
|
+
if (existsSync8(input.usersFile)) {
|
|
7676
|
+
const raw = readFileSync12(input.usersFile, "utf-8").trim();
|
|
7506
7677
|
if (raw) {
|
|
7507
7678
|
const parsed = JSON.parse(raw);
|
|
7508
7679
|
if (!Array.isArray(parsed)) {
|
|
@@ -7526,11 +7697,11 @@ function writeAdminEntry(input) {
|
|
|
7526
7697
|
return result;
|
|
7527
7698
|
}
|
|
7528
7699
|
try {
|
|
7529
|
-
const accountJsonPath =
|
|
7530
|
-
if (!
|
|
7700
|
+
const accountJsonPath = join11(input.accountDir, "account.json");
|
|
7701
|
+
if (!existsSync8(accountJsonPath)) {
|
|
7531
7702
|
throw new Error(`account.json not found at ${accountJsonPath}`);
|
|
7532
7703
|
}
|
|
7533
|
-
const config = JSON.parse(
|
|
7704
|
+
const config = JSON.parse(readFileSync12(accountJsonPath, "utf-8"));
|
|
7534
7705
|
const admins = config.admins ?? [];
|
|
7535
7706
|
if (admins.some((a) => a.userId === input.userId)) {
|
|
7536
7707
|
result.accountJsonResult = "noop";
|
|
@@ -7554,9 +7725,9 @@ function checkAdminAuthInvariant(input) {
|
|
|
7554
7725
|
usersWithoutAccount: []
|
|
7555
7726
|
};
|
|
7556
7727
|
const usersUserIds = /* @__PURE__ */ new Set();
|
|
7557
|
-
if (
|
|
7728
|
+
if (existsSync8(input.usersFile)) {
|
|
7558
7729
|
try {
|
|
7559
|
-
const raw =
|
|
7730
|
+
const raw = readFileSync12(input.usersFile, "utf-8").trim();
|
|
7560
7731
|
if (raw) {
|
|
7561
7732
|
const users = JSON.parse(raw);
|
|
7562
7733
|
for (const u of users) {
|
|
@@ -7569,10 +7740,10 @@ function checkAdminAuthInvariant(input) {
|
|
|
7569
7740
|
}
|
|
7570
7741
|
}
|
|
7571
7742
|
const accountUserIds = /* @__PURE__ */ new Set();
|
|
7572
|
-
if (
|
|
7743
|
+
if (existsSync8(input.accountsDir)) {
|
|
7573
7744
|
let entries;
|
|
7574
7745
|
try {
|
|
7575
|
-
entries =
|
|
7746
|
+
entries = readdirSync6(input.accountsDir);
|
|
7576
7747
|
} catch (err) {
|
|
7577
7748
|
const msg = err instanceof Error ? err.message : String(err);
|
|
7578
7749
|
console.error(`[${input.tag}] accounts-dir unreadable accountsDir=${input.accountsDir} error=${msg}`);
|
|
@@ -7581,17 +7752,17 @@ function checkAdminAuthInvariant(input) {
|
|
|
7581
7752
|
}
|
|
7582
7753
|
for (const entry of entries) {
|
|
7583
7754
|
if (entry.startsWith(".")) continue;
|
|
7584
|
-
const accountDir =
|
|
7755
|
+
const accountDir = join11(input.accountsDir, entry);
|
|
7585
7756
|
try {
|
|
7586
|
-
if (!
|
|
7757
|
+
if (!statSync5(accountDir).isDirectory()) continue;
|
|
7587
7758
|
} catch {
|
|
7588
7759
|
continue;
|
|
7589
7760
|
}
|
|
7590
|
-
const accountJsonPath =
|
|
7591
|
-
if (!
|
|
7761
|
+
const accountJsonPath = join11(accountDir, "account.json");
|
|
7762
|
+
if (!existsSync8(accountJsonPath)) continue;
|
|
7592
7763
|
let admins = [];
|
|
7593
7764
|
try {
|
|
7594
|
-
const config = JSON.parse(
|
|
7765
|
+
const config = JSON.parse(readFileSync12(accountJsonPath, "utf-8"));
|
|
7595
7766
|
admins = config.admins ?? [];
|
|
7596
7767
|
} catch (err) {
|
|
7597
7768
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -7627,12 +7798,12 @@ function checkAdminAuthInvariant(input) {
|
|
|
7627
7798
|
}
|
|
7628
7799
|
|
|
7629
7800
|
// server/routes/onboarding.ts
|
|
7630
|
-
function
|
|
7631
|
-
return
|
|
7801
|
+
function hashPin2(pin) {
|
|
7802
|
+
return createHash3("sha256").update(pin).digest("hex");
|
|
7632
7803
|
}
|
|
7633
|
-
function
|
|
7634
|
-
if (!
|
|
7635
|
-
const raw =
|
|
7804
|
+
function readUsersFile2() {
|
|
7805
|
+
if (!existsSync9(USERS_FILE)) return null;
|
|
7806
|
+
const raw = readFileSync13(USERS_FILE, "utf-8").trim();
|
|
7636
7807
|
if (!raw) return [];
|
|
7637
7808
|
return JSON.parse(raw);
|
|
7638
7809
|
}
|
|
@@ -7733,7 +7904,7 @@ app7.post("/claude-auth", async (c) => {
|
|
|
7733
7904
|
app7.post("/set-pin", async (c) => {
|
|
7734
7905
|
let existingUsers = null;
|
|
7735
7906
|
try {
|
|
7736
|
-
existingUsers =
|
|
7907
|
+
existingUsers = readUsersFile2();
|
|
7737
7908
|
} catch (err) {
|
|
7738
7909
|
console.error(`[set-pin] users.json corrupt: ${err instanceof Error ? err.message : String(err)}`);
|
|
7739
7910
|
return c.json({ error: "User configuration is corrupt." }, 400);
|
|
@@ -7754,7 +7925,7 @@ app7.post("/set-pin", async (c) => {
|
|
|
7754
7925
|
if (!fullName) {
|
|
7755
7926
|
return c.json({ error: "Your name is required." }, 400);
|
|
7756
7927
|
}
|
|
7757
|
-
const hash =
|
|
7928
|
+
const hash = hashPin2(body.pin);
|
|
7758
7929
|
const account = resolveAccount();
|
|
7759
7930
|
const existingOwnerUserId = account?.config.admins?.find((a) => a.role === "owner")?.userId;
|
|
7760
7931
|
const userId = existingOwnerUserId ?? randomUUID7();
|
|
@@ -7786,9 +7957,9 @@ app7.post("/set-pin", async (c) => {
|
|
|
7786
7957
|
console.log(`[set-pin] wrote users.json + account.json admins: userId=${userId.slice(0, 8)}\u2026 role=owner`);
|
|
7787
7958
|
if (process.platform === "linux") {
|
|
7788
7959
|
let installOwner = null;
|
|
7789
|
-
if (
|
|
7960
|
+
if (existsSync9(INSTALL_OWNER_FILE)) {
|
|
7790
7961
|
try {
|
|
7791
|
-
const raw =
|
|
7962
|
+
const raw = readFileSync13(INSTALL_OWNER_FILE, "utf-8").trim();
|
|
7792
7963
|
if (raw.length > 0) installOwner = raw;
|
|
7793
7964
|
} catch (err) {
|
|
7794
7965
|
console.error(`[set-pin] install-owner-read-failed path=${INSTALL_OWNER_FILE} error=${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -7835,7 +8006,7 @@ ${body.pin}
|
|
|
7835
8006
|
app7.delete("/set-pin", async (c) => {
|
|
7836
8007
|
let users = null;
|
|
7837
8008
|
try {
|
|
7838
|
-
users =
|
|
8009
|
+
users = readUsersFile2();
|
|
7839
8010
|
} catch (err) {
|
|
7840
8011
|
console.error(`[set-pin] users.json corrupt on DELETE: ${err instanceof Error ? err.message : String(err)}`);
|
|
7841
8012
|
return c.json({ error: "User configuration is corrupt." }, 400);
|
|
@@ -7850,7 +8021,7 @@ app7.delete("/set-pin", async (c) => {
|
|
|
7850
8021
|
return c.json({ error: "Invalid request" }, 400);
|
|
7851
8022
|
}
|
|
7852
8023
|
if (!body.currentPin) return c.json({ error: "Current PIN required." }, 400);
|
|
7853
|
-
const inputHash =
|
|
8024
|
+
const inputHash = hashPin2(body.currentPin);
|
|
7854
8025
|
const matchedUser = users.find((u) => u.pin === inputHash);
|
|
7855
8026
|
if (!matchedUser) {
|
|
7856
8027
|
console.log(`[set-pin] DELETE PIN mismatch: input=${inputHash.slice(0, 8)}\u2026`);
|
|
@@ -7869,9 +8040,9 @@ app7.delete("/set-pin", async (c) => {
|
|
|
7869
8040
|
var onboarding_default = app7;
|
|
7870
8041
|
|
|
7871
8042
|
// server/routes/client-error.ts
|
|
7872
|
-
import { appendFileSync, existsSync as
|
|
7873
|
-
import { join as
|
|
7874
|
-
var CLIENT_ERRORS_LOG =
|
|
8043
|
+
import { appendFileSync, existsSync as existsSync10, renameSync as renameSync2, statSync as statSync6 } from "fs";
|
|
8044
|
+
import { join as join12 } from "path";
|
|
8045
|
+
var CLIENT_ERRORS_LOG = join12(LOG_DIR, "client-errors.log");
|
|
7875
8046
|
var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
7876
8047
|
var MAX_BODY_SIZE = 8 * 1024;
|
|
7877
8048
|
var MAX_STACK_LEN = 2e3;
|
|
@@ -7914,8 +8085,8 @@ function stackHead(stack) {
|
|
|
7914
8085
|
}
|
|
7915
8086
|
function rotateIfNeeded() {
|
|
7916
8087
|
try {
|
|
7917
|
-
if (!
|
|
7918
|
-
const stats =
|
|
8088
|
+
if (!existsSync10(CLIENT_ERRORS_LOG)) return;
|
|
8089
|
+
const stats = statSync6(CLIENT_ERRORS_LOG);
|
|
7919
8090
|
if (stats.size < MAX_LOG_SIZE) return;
|
|
7920
8091
|
renameSync2(CLIENT_ERRORS_LOG, CLIENT_ERRORS_LOG + ".1");
|
|
7921
8092
|
} catch (err) {
|
|
@@ -8029,66 +8200,6 @@ var client_error_default = app8;
|
|
|
8029
8200
|
|
|
8030
8201
|
// server/routes/admin/session.ts
|
|
8031
8202
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
8032
|
-
|
|
8033
|
-
// app/lib/admin-identity/pin-validator.ts
|
|
8034
|
-
import { createHash as createHash3 } from "crypto";
|
|
8035
|
-
import { existsSync as existsSync10, readFileSync as readFileSync13, readdirSync as readdirSync6, statSync as statSync6 } from "fs";
|
|
8036
|
-
import { join as join12 } from "path";
|
|
8037
|
-
function hashPin2(pin) {
|
|
8038
|
-
return createHash3("sha256").update(pin).digest("hex");
|
|
8039
|
-
}
|
|
8040
|
-
function readUsersFile2(usersFilePath) {
|
|
8041
|
-
if (!existsSync10(usersFilePath)) return null;
|
|
8042
|
-
const raw = readFileSync13(usersFilePath, "utf-8").trim();
|
|
8043
|
-
if (!raw) return [];
|
|
8044
|
-
return JSON.parse(raw);
|
|
8045
|
-
}
|
|
8046
|
-
function validatePin(pin, usersFilePath) {
|
|
8047
|
-
let users;
|
|
8048
|
-
try {
|
|
8049
|
-
users = readUsersFile2(usersFilePath);
|
|
8050
|
-
} catch (err) {
|
|
8051
|
-
return { kind: "corrupt", message: err instanceof Error ? err.message : String(err) };
|
|
8052
|
-
}
|
|
8053
|
-
if (users === null || users.length === 0) return { kind: "unavailable" };
|
|
8054
|
-
const inputHash = hashPin2(pin);
|
|
8055
|
-
const matched = users.find((u) => u.pin === inputHash);
|
|
8056
|
-
return matched ? { kind: "match", userId: matched.userId } : { kind: "miss" };
|
|
8057
|
-
}
|
|
8058
|
-
function scanForOrphanedAccountAdmins(users, accountsDir) {
|
|
8059
|
-
const known = new Set(users.map((u) => u.userId));
|
|
8060
|
-
const orphans = [];
|
|
8061
|
-
if (!existsSync10(accountsDir)) return orphans;
|
|
8062
|
-
let entries;
|
|
8063
|
-
try {
|
|
8064
|
-
entries = readdirSync6(accountsDir);
|
|
8065
|
-
} catch {
|
|
8066
|
-
return orphans;
|
|
8067
|
-
}
|
|
8068
|
-
for (const entry of entries) {
|
|
8069
|
-
if (entry.startsWith(".")) continue;
|
|
8070
|
-
const accountDir = join12(accountsDir, entry);
|
|
8071
|
-
try {
|
|
8072
|
-
if (!statSync6(accountDir).isDirectory()) continue;
|
|
8073
|
-
} catch {
|
|
8074
|
-
continue;
|
|
8075
|
-
}
|
|
8076
|
-
const accountJsonPath = join12(accountDir, "account.json");
|
|
8077
|
-
if (!existsSync10(accountJsonPath)) continue;
|
|
8078
|
-
try {
|
|
8079
|
-
const config = JSON.parse(readFileSync13(accountJsonPath, "utf-8"));
|
|
8080
|
-
const admins = config.admins ?? [];
|
|
8081
|
-
for (const a of admins) {
|
|
8082
|
-
if (typeof a.userId === "string" && !known.has(a.userId)) orphans.push(a.userId);
|
|
8083
|
-
}
|
|
8084
|
-
} catch {
|
|
8085
|
-
continue;
|
|
8086
|
-
}
|
|
8087
|
-
}
|
|
8088
|
-
return orphans;
|
|
8089
|
-
}
|
|
8090
|
-
|
|
8091
|
-
// server/routes/admin/session.ts
|
|
8092
8203
|
async function resolveUserIdentity(accountId, userId) {
|
|
8093
8204
|
const result = await loadAdminUserName(accountId, userId);
|
|
8094
8205
|
if (result.source === "neo4j") {
|
|
@@ -8209,7 +8320,7 @@ app9.post("/", async (c) => {
|
|
|
8209
8320
|
if (verdict.kind === "miss") {
|
|
8210
8321
|
let users = [];
|
|
8211
8322
|
try {
|
|
8212
|
-
users =
|
|
8323
|
+
users = readUsersFile(USERS_FILE) ?? [];
|
|
8213
8324
|
} catch {
|
|
8214
8325
|
}
|
|
8215
8326
|
const orphanUserIds = scanForOrphanedAccountAdmins(users, ACCOUNTS_DIR);
|
|
@@ -16060,36 +16171,6 @@ var WaGateway = class {
|
|
|
16060
16171
|
}
|
|
16061
16172
|
};
|
|
16062
16173
|
|
|
16063
|
-
// app/lib/whatsapp/inbound/resolve-admin-userid.ts
|
|
16064
|
-
function classifyAdminUserId(users, admins, senderPhone) {
|
|
16065
|
-
const matched = users.find((u) => typeof u.phone === "string" && phonesMatch(u.phone, senderPhone));
|
|
16066
|
-
if (!matched) return { kind: "no-users-binding" };
|
|
16067
|
-
return admins.some((a) => a.userId === matched.userId) ? { kind: "resolved", userId: matched.userId } : { kind: "userid-not-admin", userId: matched.userId };
|
|
16068
|
-
}
|
|
16069
|
-
function pickAdminUserId(users, admins, senderPhone) {
|
|
16070
|
-
const r = classifyAdminUserId(users, admins, senderPhone);
|
|
16071
|
-
return r.kind === "resolved" ? r.userId : null;
|
|
16072
|
-
}
|
|
16073
|
-
function resolveAdminUserId(params) {
|
|
16074
|
-
try {
|
|
16075
|
-
const users = readUsersFile2(USERS_FILE);
|
|
16076
|
-
if (!users) return null;
|
|
16077
|
-
const account = listValidAccounts().find((a) => a.accountId === params.accountId);
|
|
16078
|
-
const admins = account?.config.admins ?? [];
|
|
16079
|
-
const direct = pickAdminUserId(users, admins, params.senderPhone);
|
|
16080
|
-
if (direct) return direct;
|
|
16081
|
-
const mapped = resolveViaLidMap(readLidMap() ?? {}, params.senderPhone);
|
|
16082
|
-
if (!mapped) return null;
|
|
16083
|
-
const viaLid = pickAdminUserId(users, admins, mapped);
|
|
16084
|
-
if (viaLid) {
|
|
16085
|
-
console.error(`[lid-map] resolved-via-cache lid=${params.senderPhone} userId=${viaLid.slice(0, 8)}`);
|
|
16086
|
-
}
|
|
16087
|
-
return viaLid;
|
|
16088
|
-
} catch {
|
|
16089
|
-
return null;
|
|
16090
|
-
}
|
|
16091
|
-
}
|
|
16092
|
-
|
|
16093
16174
|
// app/lib/whatsapp/inbound/channel-admin-binding-drift.ts
|
|
16094
16175
|
function findChannelAdminBindingDrift(adminPhones, admins, users) {
|
|
16095
16176
|
const drift = [];
|
|
@@ -16103,7 +16184,7 @@ function findChannelAdminBindingDrift(adminPhones, admins, users) {
|
|
|
16103
16184
|
function warnOnChannelAdminBindingDrift() {
|
|
16104
16185
|
let users;
|
|
16105
16186
|
try {
|
|
16106
|
-
users =
|
|
16187
|
+
users = readUsersFile(USERS_FILE) ?? [];
|
|
16107
16188
|
} catch {
|
|
16108
16189
|
return;
|
|
16109
16190
|
}
|