@rubytech/create-sitedesk-code 0.1.512 → 0.1.513
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/payload/platform/docs/superpowers/plans/2026-07-27-task-2028-declared-file-write-deny.md +303 -0
- package/payload/platform/docs/superpowers/specs/2026-07-27-task-2028-declared-file-write-deny-design.md +126 -0
- package/payload/platform/lib/account-schema-regions/dist/index.d.ts +5 -0
- package/payload/platform/lib/account-schema-regions/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/account-schema-regions/dist/index.js +5 -0
- package/payload/platform/lib/account-schema-regions/dist/index.js.map +1 -1
- package/payload/platform/lib/account-schema-regions/src/index.ts +5 -0
- package/payload/platform/plugins/admin/hooks/__tests__/fs-schema-guard-bash.test.sh +14 -0
- package/payload/platform/plugins/admin/hooks/__tests__/fs-schema-guard.test.sh +38 -0
- package/payload/platform/plugins/admin/hooks/fs-schema-guard-bash-post.sh +11 -0
- package/payload/platform/plugins/admin/hooks/fs-schema-guard.sh +25 -1
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +6 -0
- package/payload/platform/plugins/cloudflare/PLUGIN.md +1 -1
- package/payload/platform/plugins/cloudflare/bin/schema-exposed-dirs.mjs +1 -1
- package/payload/platform/plugins/scheduling/PLUGIN.md +1 -1
- package/payload/platform/scripts/__tests__/account-schema-owned-dirs.test.sh +26 -0
- package/payload/platform/scripts/lib/account-schema-owned-dirs.py +40 -4
- package/payload/platform/scripts/logs-read.sh +47 -24
- package/payload/platform/scripts/logs-read.test.sh +73 -31
- package/payload/platform/scripts/provision-worktree.sh +80 -0
- package/payload/server/{chunk-2WAXM5N2.js → chunk-S6HYTIU3.js} +2 -3
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/server.js +89 -41
package/payload/server/server.js
CHANGED
|
@@ -118,7 +118,7 @@ import {
|
|
|
118
118
|
vncLog,
|
|
119
119
|
walkPremiumBundles,
|
|
120
120
|
writeAdminUserAndPerson
|
|
121
|
-
} from "./chunk-
|
|
121
|
+
} from "./chunk-S6HYTIU3.js";
|
|
122
122
|
import {
|
|
123
123
|
D1_MAX_SQL_STATEMENT_BYTES,
|
|
124
124
|
D1_QUERY_MAX_BODY_BYTES,
|
|
@@ -5105,6 +5105,18 @@ function resolvePlatformAccountId(accountsDir = ACCOUNTS_DIR) {
|
|
|
5105
5105
|
return routed ?? houseId;
|
|
5106
5106
|
}
|
|
5107
5107
|
|
|
5108
|
+
// app/lib/whatsapp/account-id-shape.ts
|
|
5109
|
+
var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
5110
|
+
function isUuidAccountId(id) {
|
|
5111
|
+
return UUID_RE2.test(id);
|
|
5112
|
+
}
|
|
5113
|
+
function warnNonUuidAccount(caller2, accountId) {
|
|
5114
|
+
if (isUuidAccountId(accountId)) return;
|
|
5115
|
+
console.error(
|
|
5116
|
+
`[whatsapp-account-scope] op=non-uuid-account caller=${caller2} accountId=${accountId}`
|
|
5117
|
+
);
|
|
5118
|
+
}
|
|
5119
|
+
|
|
5108
5120
|
// app/lib/managed-service.ts
|
|
5109
5121
|
import { join as join7 } from "path";
|
|
5110
5122
|
import { readFileSync as readFileSync9 } from "fs";
|
|
@@ -6221,8 +6233,9 @@ function buildSelfChatDispatch(input) {
|
|
|
6221
6233
|
isGroup: false
|
|
6222
6234
|
}),
|
|
6223
6235
|
media: [],
|
|
6224
|
-
// Self-chat is the owner: the session scopes to the house account (Task 1383)
|
|
6225
|
-
|
|
6236
|
+
// Self-chat is the owner: the session scopes to the house account (Task 1383),
|
|
6237
|
+
// named by its platform UUID (Task 1850).
|
|
6238
|
+
effectiveAccountId: input.platformAccountId,
|
|
6226
6239
|
// Task 1575 — self-chat is unambiguously the owner, so attribute the spawn
|
|
6227
6240
|
// to the owner userId even when the owner phone is unbound in users.json.
|
|
6228
6241
|
ownerSelfPhone: true
|
|
@@ -6353,20 +6366,26 @@ function resolveReadStoreKey(accountId) {
|
|
|
6353
6366
|
}
|
|
6354
6367
|
function resolveInboundPersistAccount(args) {
|
|
6355
6368
|
const result = args.accessResult;
|
|
6356
|
-
|
|
6357
|
-
|
|
6358
|
-
|
|
6359
|
-
return args.connPlatformAccountId;
|
|
6369
|
+
const account = result?.allowed && result.reason === "account-manager" && result.effectiveAccountId ? result.effectiveAccountId : args.connPlatformAccountId;
|
|
6370
|
+
warnNonUuidAccount("inbound-persist", account);
|
|
6371
|
+
return account;
|
|
6360
6372
|
}
|
|
6361
6373
|
function resolveConversationPersistAccount(sendAccountId, counterpartyPhone) {
|
|
6362
6374
|
const conn = findConnectionByKey(Array.from(connections2.values()), sendAccountId);
|
|
6363
|
-
if (!conn)
|
|
6375
|
+
if (!conn) {
|
|
6376
|
+
warnNonUuidAccount("reply-append-no-connection", sendAccountId);
|
|
6377
|
+
return sendAccountId;
|
|
6378
|
+
}
|
|
6364
6379
|
const access = checkDmAccess({
|
|
6365
6380
|
senderPhone: counterpartyPhone,
|
|
6366
6381
|
selfPhone: conn.selfPhone ?? "",
|
|
6367
6382
|
config: whatsAppConfig,
|
|
6383
|
+
// The per-number sub-config is keyed by the credential DIRNAME.
|
|
6368
6384
|
accountConfig: whatsAppConfig.accounts?.[conn.accountId],
|
|
6369
|
-
|
|
6385
|
+
// Task 1850 — the account SCOPE is the platform UUID. The gate assigns this
|
|
6386
|
+
// to `effectiveAccountId` for every non-manager admit, and that value reaches
|
|
6387
|
+
// the graph and the spawn; the dirname is a credential path, not an account.
|
|
6388
|
+
accountId: conn.platformAccountId,
|
|
6370
6389
|
isValidAccount: (id) => isValidAccountId(id)
|
|
6371
6390
|
});
|
|
6372
6391
|
return resolveInboundPersistAccount({
|
|
@@ -6700,8 +6719,11 @@ function monitorInbound(conn) {
|
|
|
6700
6719
|
senderPhone,
|
|
6701
6720
|
selfPhone: conn.selfPhone ?? "",
|
|
6702
6721
|
config: whatsAppConfig,
|
|
6722
|
+
// Keyed by the credential DIRNAME — a per-number sub-config.
|
|
6703
6723
|
accountConfig: whatsAppConfig.accounts?.[conn.accountId],
|
|
6704
|
-
|
|
6724
|
+
// Task 1850 — the account SCOPE is the platform UUID, never the
|
|
6725
|
+
// dirname. See resolveConversationPersistAccount.
|
|
6726
|
+
accountId: conn.platformAccountId,
|
|
6705
6727
|
isValidAccount: (id) => isValidAccountId(id)
|
|
6706
6728
|
});
|
|
6707
6729
|
const persistAccountId = resolveInboundPersistAccount({
|
|
@@ -6894,6 +6916,7 @@ function monitorInbound(conn) {
|
|
|
6894
6916
|
};
|
|
6895
6917
|
dispatchInboundPayload(conn, buildSelfChatDispatch({
|
|
6896
6918
|
accountId: conn.accountId,
|
|
6919
|
+
platformAccountId: conn.platformAccountId,
|
|
6897
6920
|
selfPhone: conn.selfPhone,
|
|
6898
6921
|
remoteJid,
|
|
6899
6922
|
text: decision.text,
|
|
@@ -7043,7 +7066,7 @@ async function handleInboundMessage(conn, msg) {
|
|
|
7043
7066
|
selfPhone,
|
|
7044
7067
|
config: whatsAppConfig,
|
|
7045
7068
|
accountConfig: whatsAppConfig.accounts?.[conn.accountId],
|
|
7046
|
-
accountId: conn.
|
|
7069
|
+
accountId: conn.platformAccountId,
|
|
7047
7070
|
isValidAccount: (id) => isValidAccountId(id),
|
|
7048
7071
|
resolvePersonByPhone
|
|
7049
7072
|
});
|
|
@@ -8152,6 +8175,11 @@ function createScheduleInjectRoutes(deps) {
|
|
|
8152
8175
|
// server/index.ts
|
|
8153
8176
|
var import_dist9 = __toESM(require_dist(), 1);
|
|
8154
8177
|
|
|
8178
|
+
// app/lib/whatsapp/gateway/manages-account.ts
|
|
8179
|
+
function managesAccountFor(effectiveAccountId, connPlatformAccountId) {
|
|
8180
|
+
return effectiveAccountId === connPlatformAccountId ? "none" : effectiveAccountId;
|
|
8181
|
+
}
|
|
8182
|
+
|
|
8155
8183
|
// app/lib/whatsapp/socket-resolution-error.ts
|
|
8156
8184
|
function formatPresentKeys(presentKeys) {
|
|
8157
8185
|
return presentKeys.join(",") || "none";
|
|
@@ -11569,13 +11597,13 @@ async function runPortalIndexPush(root) {
|
|
|
11569
11597
|
import { existsSync as existsSync12, readdirSync as readdirSync9, statSync as statSync5 } from "fs";
|
|
11570
11598
|
import { join as join17 } from "path";
|
|
11571
11599
|
var GOOGLE_PENDING_LIFETIME_SEC = 600;
|
|
11572
|
-
var
|
|
11600
|
+
var UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
11573
11601
|
function runGooglePendingAudit(accountsDir, nowMs, emit, readMtimeMs = (path3) => statSync5(path3).mtimeMs) {
|
|
11574
11602
|
let scanned = 0;
|
|
11575
11603
|
let stranded = 0;
|
|
11576
11604
|
if (existsSync12(accountsDir)) {
|
|
11577
11605
|
for (const accountId of readdirSync9(accountsDir)) {
|
|
11578
|
-
if (!
|
|
11606
|
+
if (!UUID_RE3.test(accountId)) continue;
|
|
11579
11607
|
const pendingPath2 = join17(accountsDir, accountId, "secrets", "google", "pending-oauth.enc");
|
|
11580
11608
|
try {
|
|
11581
11609
|
if (!existsSync12(pendingPath2)) continue;
|
|
@@ -11721,8 +11749,8 @@ async function loadTitleCacheOutcome(accountDir) {
|
|
|
11721
11749
|
async function loadTitleCache(accountDir) {
|
|
11722
11750
|
return (await loadTitleCacheOutcome(accountDir)).cache;
|
|
11723
11751
|
}
|
|
11724
|
-
async function saveTitleCacheMerged(accountDir, updates) {
|
|
11725
|
-
if (updates.size === 0) return;
|
|
11752
|
+
async function saveTitleCacheMerged(accountDir, updates, evict) {
|
|
11753
|
+
if (updates.size === 0 && (evict === void 0 || evict.size === 0)) return 0;
|
|
11726
11754
|
const path3 = titleCachePath(accountDir);
|
|
11727
11755
|
let merged;
|
|
11728
11756
|
try {
|
|
@@ -11732,6 +11760,12 @@ async function saveTitleCacheMerged(accountDir, updates) {
|
|
|
11732
11760
|
merged = /* @__PURE__ */ new Map();
|
|
11733
11761
|
}
|
|
11734
11762
|
for (const [sessionId, entry] of updates) merged.set(sessionId, entry);
|
|
11763
|
+
let evicted = 0;
|
|
11764
|
+
if (evict !== void 0) {
|
|
11765
|
+
for (const sessionId of evict) {
|
|
11766
|
+
if (merged.delete(sessionId)) evicted += 1;
|
|
11767
|
+
}
|
|
11768
|
+
}
|
|
11735
11769
|
const tmp = `${path3}.tmp.${process.pid}.${Date.now()}.${nextTmpSeq()}`;
|
|
11736
11770
|
try {
|
|
11737
11771
|
await writeFile5(tmp, serializeTitleCache(merged), "utf8");
|
|
@@ -11747,6 +11781,7 @@ async function saveTitleCacheMerged(accountDir, updates) {
|
|
|
11747
11781
|
}
|
|
11748
11782
|
throw err;
|
|
11749
11783
|
}
|
|
11784
|
+
return evicted;
|
|
11750
11785
|
}
|
|
11751
11786
|
function lastAiTitleIn(text, initial) {
|
|
11752
11787
|
let aiTitle = initial;
|
|
@@ -11986,13 +12021,14 @@ function findSessionProjectDir(sessionId) {
|
|
|
11986
12021
|
const jsonlPath = findExistingJsonlForSessionId(cfg, sessionId);
|
|
11987
12022
|
return jsonlPath ? dirname5(jsonlPath) : null;
|
|
11988
12023
|
}
|
|
11989
|
-
function
|
|
12024
|
+
function enumerateJsonlsWithSkips(projectsRoot) {
|
|
11990
12025
|
const out = [];
|
|
12026
|
+
let skipped = 0;
|
|
11991
12027
|
let slugs;
|
|
11992
12028
|
try {
|
|
11993
12029
|
slugs = readdirSync12(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
11994
12030
|
} catch (err) {
|
|
11995
|
-
if (err.code === "ENOENT") return out;
|
|
12031
|
+
if (err.code === "ENOENT") return { files: out, skipped };
|
|
11996
12032
|
throw err;
|
|
11997
12033
|
}
|
|
11998
12034
|
for (const slug of slugs) {
|
|
@@ -12003,6 +12039,7 @@ function enumerateJsonls(projectsRoot) {
|
|
|
12003
12039
|
} catch (err) {
|
|
12004
12040
|
const code = err.code ?? "unknown";
|
|
12005
12041
|
console.error(`[admin-sessions-list] slug-skipped slug=${slug} code=${code}`);
|
|
12042
|
+
skipped += 1;
|
|
12006
12043
|
continue;
|
|
12007
12044
|
}
|
|
12008
12045
|
for (const entry of entries2) {
|
|
@@ -12016,6 +12053,7 @@ function enumerateJsonls(projectsRoot) {
|
|
|
12016
12053
|
} catch (err) {
|
|
12017
12054
|
const code = err.code ?? "unknown";
|
|
12018
12055
|
console.error(`[admin-sessions-list] subagents-skipped slug=${slug} code=${code}`);
|
|
12056
|
+
skipped += 1;
|
|
12019
12057
|
continue;
|
|
12020
12058
|
}
|
|
12021
12059
|
for (const sub of subEntries) {
|
|
@@ -12031,6 +12069,7 @@ function enumerateJsonls(projectsRoot) {
|
|
|
12031
12069
|
} catch (err) {
|
|
12032
12070
|
const code = err.code ?? "unknown";
|
|
12033
12071
|
console.error(`[admin-sessions-list] archive-skipped slug=${slug} code=${code}`);
|
|
12072
|
+
skipped += 1;
|
|
12034
12073
|
continue;
|
|
12035
12074
|
}
|
|
12036
12075
|
for (const arc of archiveEntries) {
|
|
@@ -12041,7 +12080,10 @@ function enumerateJsonls(projectsRoot) {
|
|
|
12041
12080
|
}
|
|
12042
12081
|
}
|
|
12043
12082
|
}
|
|
12044
|
-
return out;
|
|
12083
|
+
return { files: out, skipped };
|
|
12084
|
+
}
|
|
12085
|
+
function enumerateJsonls(projectsRoot) {
|
|
12086
|
+
return enumerateJsonlsWithSkips(projectsRoot).files;
|
|
12045
12087
|
}
|
|
12046
12088
|
async function fetchLiveSessions() {
|
|
12047
12089
|
const out = /* @__PURE__ */ new Map();
|
|
@@ -12182,7 +12224,6 @@ async function computeSessionList(scopeAccountId) {
|
|
|
12182
12224
|
return { sessions: [], accountId: scopeAccountId };
|
|
12183
12225
|
}
|
|
12184
12226
|
const projectsRoot = join21(configDir2, "projects");
|
|
12185
|
-
const jsonls = enumerateJsonls(projectsRoot);
|
|
12186
12227
|
const liveSessions = await fetchLiveSessions();
|
|
12187
12228
|
const accountDir = scopeAccountId ? resolve15(ACCOUNTS_DIR, scopeAccountId) : null;
|
|
12188
12229
|
const userTitles = await loadUserTitlesAsync(accountDir);
|
|
@@ -12216,6 +12257,7 @@ async function computeSessionList(scopeAccountId) {
|
|
|
12216
12257
|
const cacheLoad = await loadTitleCacheOutcome(titleCacheDir);
|
|
12217
12258
|
const titleCache = cacheLoad.cache;
|
|
12218
12259
|
const cacheUpdates = /* @__PURE__ */ new Map();
|
|
12260
|
+
const { files: jsonls, skipped: enumSkipped } = enumerateJsonlsWithSkips(projectsRoot);
|
|
12219
12261
|
let enumeratedCount = 0;
|
|
12220
12262
|
let scopedCount = 0;
|
|
12221
12263
|
let titleCacheHits = 0;
|
|
@@ -12227,6 +12269,7 @@ async function computeSessionList(scopeAccountId) {
|
|
|
12227
12269
|
let tailReadFails = 0;
|
|
12228
12270
|
let tailBytes = 0;
|
|
12229
12271
|
let cacheWriteFails = 0;
|
|
12272
|
+
let evicted = 0;
|
|
12230
12273
|
const walkStartedAt = Date.now();
|
|
12231
12274
|
for (const { path: path3, isSubagent, archived } of jsonls) {
|
|
12232
12275
|
const lastSlash = path3.lastIndexOf("/");
|
|
@@ -12389,9 +12432,13 @@ async function computeSessionList(scopeAccountId) {
|
|
|
12389
12432
|
console.error(`[admin-sessions-list] op=channel-name-unresolved sessionId=${m.sessionId.slice(0, 8)} channel=${m.channel} senderId= reason=no-senderId`);
|
|
12390
12433
|
}
|
|
12391
12434
|
rows.sort((a, b) => a.startedAt < b.startedAt ? 1 : -1);
|
|
12392
|
-
|
|
12435
|
+
const evictIds = /* @__PURE__ */ new Set();
|
|
12436
|
+
if (enumSkipped === 0 && seenIds.size > 0) {
|
|
12437
|
+
for (const sessionId of titleCache.keys()) if (!seenIds.has(sessionId)) evictIds.add(sessionId);
|
|
12438
|
+
}
|
|
12439
|
+
if (titleCacheDir && (cacheUpdates.size > 0 || evictIds.size > 0)) {
|
|
12393
12440
|
try {
|
|
12394
|
-
await saveTitleCacheMerged(titleCacheDir, cacheUpdates);
|
|
12441
|
+
evicted = await saveTitleCacheMerged(titleCacheDir, cacheUpdates, evictIds);
|
|
12395
12442
|
} catch (err) {
|
|
12396
12443
|
cacheWriteFails += 1;
|
|
12397
12444
|
console.error(
|
|
@@ -12401,7 +12448,7 @@ async function computeSessionList(scopeAccountId) {
|
|
|
12401
12448
|
}
|
|
12402
12449
|
const bytesMB = (titleBytes + tailBytes) / (1024 * 1024);
|
|
12403
12450
|
console.log(
|
|
12404
|
-
`[admin-sessions-list] op=list-walk enumerated=${enumeratedCount} scoped=${scopedCount} cacheLoad=${cacheLoad.state} cacheEntries=${titleCache.size} cacheDropped=${cacheLoad.dropped} titleCacheHits=${titleCacheHits} bodyScans=${bodyScans} titleReadFails=${titleReadFails} tailReads=${tailReads} tailModelMiss=${tailModelMiss} tailReadFails=${tailReadFails} titleBytesMB=${(titleBytes / (1024 * 1024)).toFixed(3)} bytesMB=${bytesMB.toFixed(3)} cacheWriteFails=${cacheWriteFails} ms=${Date.now() - walkStartedAt}`
|
|
12451
|
+
`[admin-sessions-list] op=list-walk enumerated=${enumeratedCount} scoped=${scopedCount} cacheLoad=${cacheLoad.state} cacheEntries=${titleCache.size} cacheDropped=${cacheLoad.dropped} titleCacheHits=${titleCacheHits} bodyScans=${bodyScans} titleReadFails=${titleReadFails} tailReads=${tailReads} tailModelMiss=${tailModelMiss} tailReadFails=${tailReadFails} titleBytesMB=${(titleBytes / (1024 * 1024)).toFixed(3)} bytesMB=${bytesMB.toFixed(3)} cacheWriteFails=${cacheWriteFails} evicted=${evicted} enumSkipped=${enumSkipped} ms=${Date.now() - walkStartedAt}`
|
|
12405
12452
|
);
|
|
12406
12453
|
console.log(
|
|
12407
12454
|
`[admin-sessions-list] rows=${rows.length} live=${liveCount} subagents=${subagentCount} archived=${archivedCount} channelInList=whatsapp:${channelInList.whatsapp},telegram:${channelInList.telegram},webchat:${channelInList.webchat} channelNameCandidates=${channelNameCandidates} channelNamesResolved=${channelNamesResolved} (operator=${operatorResolvedCount} store=${storeResolvedCount}) unknownChannel=${unknownChannelCount} excludedPublicWebchat=${excludedPublicWebchatCount} titles user=${titleSourceCounts.user} ai=${titleSourceCounts.ai} first=${titleSourceCounts["first-message"]} prefix=${titleSourceCounts.prefix} personNames=${personNameCount} adminNames=${adminNameCount} accountId=${scopeAccountId ? scopeAccountId.slice(0, 8) : "unset"}`
|
|
@@ -19460,7 +19507,7 @@ async function restoreNode(params) {
|
|
|
19460
19507
|
}
|
|
19461
19508
|
|
|
19462
19509
|
// app/lib/file-delete-cascade.ts
|
|
19463
|
-
var
|
|
19510
|
+
var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
19464
19511
|
function parseAttachmentPath(relPath) {
|
|
19465
19512
|
const segments = relPath.split("/").filter(Boolean);
|
|
19466
19513
|
if (segments.length !== 5) return null;
|
|
@@ -19468,7 +19515,7 @@ function parseAttachmentPath(relPath) {
|
|
|
19468
19515
|
const accountId = segments[1];
|
|
19469
19516
|
const attachmentId = segments[3];
|
|
19470
19517
|
const filename = segments[4];
|
|
19471
|
-
if (!
|
|
19518
|
+
if (!UUID_RE4.test(accountId) || !UUID_RE4.test(attachmentId)) return null;
|
|
19472
19519
|
const dot = filename.lastIndexOf(".");
|
|
19473
19520
|
if (dot === -1) return null;
|
|
19474
19521
|
const stem = filename.slice(0, dot);
|
|
@@ -20076,7 +20123,7 @@ function classifyAccountRoot(schemaMd, rootEntries) {
|
|
|
20076
20123
|
|
|
20077
20124
|
// server/routes/admin/files.ts
|
|
20078
20125
|
var UPLOAD_TMP_DIR = ".uploads-tmp";
|
|
20079
|
-
var
|
|
20126
|
+
var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
20080
20127
|
async function readMeta(absDir, baseName) {
|
|
20081
20128
|
try {
|
|
20082
20129
|
const raw = await readFile9(join38(absDir, `${baseName}.meta.json`), "utf8");
|
|
@@ -20098,7 +20145,7 @@ async function readAccountNames() {
|
|
|
20098
20145
|
return map;
|
|
20099
20146
|
}
|
|
20100
20147
|
for (const name of names) {
|
|
20101
|
-
if (!
|
|
20148
|
+
if (!UUID_RE5.test(name)) continue;
|
|
20102
20149
|
const configPath2 = resolve27(accountsDir, name, "account.json");
|
|
20103
20150
|
try {
|
|
20104
20151
|
const raw = await readFile9(configPath2, "utf8");
|
|
@@ -20133,7 +20180,7 @@ async function servableFilesIn(dirAbs, uuid) {
|
|
|
20133
20180
|
return out;
|
|
20134
20181
|
}
|
|
20135
20182
|
async function enrich(absolute, entry, accountNames) {
|
|
20136
|
-
if (entry.kind === "directory" &&
|
|
20183
|
+
if (entry.kind === "directory" && UUID_RE5.test(entry.name)) {
|
|
20137
20184
|
const dirAbs = join38(absolute, entry.name);
|
|
20138
20185
|
const meta = await readMeta(dirAbs, entry.name);
|
|
20139
20186
|
if (meta?.filename) {
|
|
@@ -20168,7 +20215,7 @@ async function enrich(absolute, entry, accountNames) {
|
|
|
20168
20215
|
if (entry.kind === "file") {
|
|
20169
20216
|
const dot = entry.name.lastIndexOf(".");
|
|
20170
20217
|
const base = dot === -1 ? entry.name : entry.name.slice(0, dot);
|
|
20171
|
-
if (
|
|
20218
|
+
if (UUID_RE5.test(base)) {
|
|
20172
20219
|
const meta = await readMeta(absolute, base);
|
|
20173
20220
|
if (meta?.filename) {
|
|
20174
20221
|
entry.displayName = meta.filename;
|
|
@@ -20181,7 +20228,7 @@ async function enrich(absolute, entry, accountNames) {
|
|
|
20181
20228
|
function buildDisplayPath(relPath, accountNames) {
|
|
20182
20229
|
if (relPath === "." || relPath === "") return [];
|
|
20183
20230
|
return relPath.split("/").filter(Boolean).map((seg) => {
|
|
20184
|
-
const dn =
|
|
20231
|
+
const dn = UUID_RE5.test(seg) ? accountNames.get(seg) : void 0;
|
|
20185
20232
|
return dn ? { name: seg, displayName: dn } : { name: seg };
|
|
20186
20233
|
});
|
|
20187
20234
|
}
|
|
@@ -20193,13 +20240,13 @@ function parseGroupPath(raw, sessionAccountId) {
|
|
|
20193
20240
|
}
|
|
20194
20241
|
const segs = trimmed.split("/").filter(Boolean);
|
|
20195
20242
|
if (segs.length !== 3) return null;
|
|
20196
|
-
if (segs[0] !== "accounts" || !
|
|
20243
|
+
if (segs[0] !== "accounts" || !UUID_RE5.test(segs[1])) return null;
|
|
20197
20244
|
if (segs[2] !== "@home" && segs[2] !== "@system") return null;
|
|
20198
20245
|
return { view: segs[2].slice(1), accountRel: `accounts/${segs[1]}` };
|
|
20199
20246
|
}
|
|
20200
20247
|
function isAccountRoot(relPath) {
|
|
20201
20248
|
const segs = relPath.split("/").filter(Boolean);
|
|
20202
|
-
return segs.length === 2 && segs[0] === "accounts" &&
|
|
20249
|
+
return segs.length === 2 && segs[0] === "accounts" && UUID_RE5.test(segs[1]);
|
|
20203
20250
|
}
|
|
20204
20251
|
function sortDirEntries(entries2) {
|
|
20205
20252
|
entries2.sort((a, b) => {
|
|
@@ -20247,11 +20294,11 @@ function isProtectedFromRename(relPath) {
|
|
|
20247
20294
|
if (segments.length === 3 && segments[0] === "accounts" && segments[2] === "uploads") {
|
|
20248
20295
|
return true;
|
|
20249
20296
|
}
|
|
20250
|
-
if (segments.length === 4 && segments[0] === "accounts" && segments[2] === "uploads" &&
|
|
20297
|
+
if (segments.length === 4 && segments[0] === "accounts" && segments[2] === "uploads" && UUID_RE5.test(segments[3])) {
|
|
20251
20298
|
return true;
|
|
20252
20299
|
}
|
|
20253
20300
|
if (parseAttachmentPath(relPath) !== null) return true;
|
|
20254
|
-
if (
|
|
20301
|
+
if (UUID_RE5.test(base.replace(/\.meta\.json$/, "")) && base.endsWith(".meta.json")) {
|
|
20255
20302
|
return true;
|
|
20256
20303
|
}
|
|
20257
20304
|
return false;
|
|
@@ -20327,10 +20374,10 @@ app23.get("/", requireAdminSession, async (c) => {
|
|
|
20327
20374
|
const isAccountParent = segs.length === 1 && segs[0] === "accounts";
|
|
20328
20375
|
const entries2 = [];
|
|
20329
20376
|
for (const name of names) {
|
|
20330
|
-
if (
|
|
20377
|
+
if (UUID_RE5.test(name.replace(/\.meta\.json$/, "")) && name.endsWith(".meta.json")) {
|
|
20331
20378
|
continue;
|
|
20332
20379
|
}
|
|
20333
|
-
if (isAccountParent &&
|
|
20380
|
+
if (isAccountParent && UUID_RE5.test(name) && name !== accountId) {
|
|
20334
20381
|
continue;
|
|
20335
20382
|
}
|
|
20336
20383
|
const childRel = relPath === "" || relPath === "." ? name : `${relPath}/${name}`;
|
|
@@ -21050,8 +21097,8 @@ app23.delete("/", requireAdminSession, async (c) => {
|
|
|
21050
21097
|
const dot = base.lastIndexOf(".");
|
|
21051
21098
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
21052
21099
|
const containerDir = dirname13(absolute);
|
|
21053
|
-
const sidecarPath =
|
|
21054
|
-
const isAttachmentContainer =
|
|
21100
|
+
const sidecarPath = UUID_RE5.test(stem) && base !== `${stem}.meta.json` ? join38(containerDir, `${stem}.meta.json`) : null;
|
|
21101
|
+
const isAttachmentContainer = UUID_RE5.test(stem) && basename11(containerDir) === stem;
|
|
21055
21102
|
await unlink4(absolute);
|
|
21056
21103
|
if (sidecarPath) {
|
|
21057
21104
|
try {
|
|
@@ -27652,7 +27699,7 @@ var visitor_event_default = app65;
|
|
|
27652
27699
|
// server/routes/session.ts
|
|
27653
27700
|
import { resolve as resolve37 } from "path";
|
|
27654
27701
|
import { existsSync as existsSync43, writeFileSync as writeFileSync16, mkdirSync as mkdirSync10 } from "fs";
|
|
27655
|
-
var
|
|
27702
|
+
var UUID_RE6 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
27656
27703
|
function writeBrandingCache(accountId, agentSlug, branding) {
|
|
27657
27704
|
try {
|
|
27658
27705
|
const cacheDir = resolve37(MAXY_DIR, "branding-cache", accountId);
|
|
@@ -27667,7 +27714,7 @@ function parseVisitorCookie2(cookieHeader) {
|
|
|
27667
27714
|
const match = cookieHeader.match(/(?:^|;\s*)maxy_visitor=([^;]*)/);
|
|
27668
27715
|
if (!match) return null;
|
|
27669
27716
|
const value = decodeURIComponent(match[1]).trim();
|
|
27670
|
-
return
|
|
27717
|
+
return UUID_RE6.test(value) ? value : null;
|
|
27671
27718
|
}
|
|
27672
27719
|
function parseAccessSessionId2(cookieHeader) {
|
|
27673
27720
|
if (!cookieHeader) return null;
|
|
@@ -27765,7 +27812,7 @@ app66.post("/", async (c) => {
|
|
|
27765
27812
|
);
|
|
27766
27813
|
}
|
|
27767
27814
|
}
|
|
27768
|
-
if (body.session_key && typeof body.session_key === "string" &&
|
|
27815
|
+
if (body.session_key && typeof body.session_key === "string" && UUID_RE6.test(body.session_key)) {
|
|
27769
27816
|
if (visitorId) {
|
|
27770
27817
|
const recent = await findRecentConversation(visitorId, accountId, agentSlug).catch(() => null);
|
|
27771
27818
|
if (recent) {
|
|
@@ -32126,6 +32173,7 @@ var waGateway = new WaGateway({
|
|
|
32126
32173
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
32127
32174
|
},
|
|
32128
32175
|
ensureChannelSession: async ({ accountId, effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath, passive, text, msgId, ownerSelfPhone, replyContext }) => {
|
|
32176
|
+
warnNonUuidAccount("channel-spawn", effectiveAccountId);
|
|
32129
32177
|
if (passive) {
|
|
32130
32178
|
const phoneHash = createHash8("sha256").update(senderId).digest("hex").slice(0, 12);
|
|
32131
32179
|
const prompt = (text ?? "").trim();
|
|
@@ -32174,7 +32222,7 @@ var waGateway = new WaGateway({
|
|
|
32174
32222
|
return;
|
|
32175
32223
|
}
|
|
32176
32224
|
if (role === "admin") {
|
|
32177
|
-
const managesAccount = effectiveAccountId
|
|
32225
|
+
const managesAccount = managesAccountFor(effectiveAccountId, resolveReadStoreKey(accountId));
|
|
32178
32226
|
console.error(`[whatsapp-native] op=account-manager-route senderId=${senderId} managesAccount=${managesAccount} effectiveAccount=${effectiveAccountId} source=gate`);
|
|
32179
32227
|
}
|
|
32180
32228
|
const req = buildWaSpawnRequest({
|