refactor: normalize session route fields

Co-authored-by: adam91holt <adam91holt@users.noreply.github.com>
This commit is contained in:
Peter Steinberger
2026-01-17 05:28:52 +00:00
parent a624878973
commit f4f20c6762
2 changed files with 54 additions and 0 deletions

View File

@@ -157,6 +157,27 @@ describe("sessions", () => {
expect(store["agent:main:two"]?.sessionId).toBe("sess-2");
});
it("normalizes last route fields on write", async () => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-sessions-"));
const storePath = path.join(dir, "sessions.json");
await fs.writeFile(storePath, "{}", "utf-8");
await updateSessionStore(storePath, (store) => {
store["agent:main:main"] = {
sessionId: "sess-normalized",
updatedAt: 1,
lastChannel: " WhatsApp ",
lastTo: " +1555 ",
lastAccountId: " acct-1 ",
};
});
const store = loadSessionStore(storePath);
expect(store["agent:main:main"]?.lastChannel).toBe("whatsapp");
expect(store["agent:main:main"]?.lastTo).toBe("+1555");
expect(store["agent:main:main"]?.lastAccountId).toBe("acct-1");
});
it("updateSessionStore keeps deletions when concurrent writes happen", async () => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-sessions-"));
const storePath = path.join(dir, "sessions.json");

View File

@@ -4,6 +4,8 @@ import path from "node:path";
import JSON5 from "json5";
import { getFileMtimeMs, isCacheEnabled, resolveCacheTtlMs } from "../cache-utils.js";
import { normalizeAccountId } from "../../utils/account-id.js";
import { normalizeMessageChannel } from "../../utils/message-channel.js";
import { mergeSessionEntry, type SessionEntry } from "./types.js";
// ============================================================================
@@ -41,6 +43,35 @@ function invalidateSessionStoreCache(storePath: string): void {
SESSION_STORE_CACHE.delete(storePath);
}
function normalizeSessionEntryDelivery(entry: SessionEntry): SessionEntry {
const normalizedLastChannel = normalizeMessageChannel(entry.lastChannel) ?? undefined;
const normalizedLastTo = typeof entry.lastTo === "string" ? entry.lastTo.trim() : undefined;
const normalizedLastAccountId = normalizeAccountId(entry.lastAccountId);
if (
normalizedLastChannel === entry.lastChannel &&
normalizedLastTo === entry.lastTo &&
normalizedLastAccountId === entry.lastAccountId
) {
return entry;
}
return {
...entry,
lastChannel: normalizedLastChannel,
lastTo: normalizedLastTo || undefined,
lastAccountId: normalizedLastAccountId,
};
}
function normalizeSessionStore(store: Record<string, SessionEntry>): void {
for (const [key, entry] of Object.entries(store)) {
if (!entry) continue;
const normalized = normalizeSessionEntryDelivery(entry);
if (normalized !== entry) {
store[key] = normalized;
}
}
}
export function clearSessionStoreCacheForTest(): void {
SESSION_STORE_CACHE.clear();
}
@@ -114,6 +145,8 @@ async function saveSessionStoreUnlocked(
// Invalidate cache on write to ensure consistency
invalidateSessionStoreCache(storePath);
normalizeSessionStore(store);
await fs.promises.mkdir(path.dirname(storePath), { recursive: true });
const json = JSON.stringify(store, null, 2);