codexmobile-relay / server /codex-data-hidden-state.js
Codex
deploy: CodexMobile Relay
90f0300
Raw
History Blame Contribute Delete
4.09 kB
import fs from 'node:fs/promises';
import path from 'node:path';
import { statePath } from './runtime-paths.js';
export const DELETED_MESSAGES_PATH = statePath('deleted-messages.json');
export const HIDDEN_SESSIONS_PATH = statePath('hidden-sessions.json');
export function emptyDeletedMessagesState() {
return { version: 1, sessions: {} };
}
export function emptyHiddenSessionsState() {
return { version: 1, sessions: {} };
}
export async function readDeletedMessagesState() {
try {
const raw = await fs.readFile(DELETED_MESSAGES_PATH, 'utf8');
const parsed = JSON.parse(raw);
return {
version: 1,
sessions: parsed && typeof parsed.sessions === 'object' && !Array.isArray(parsed.sessions)
? parsed.sessions
: {}
};
} catch (error) {
if (error.code !== 'ENOENT') {
console.warn('[sessions] Failed to read deleted message state:', error.message);
}
return emptyDeletedMessagesState();
}
}
export async function writeDeletedMessagesState(state) {
await fs.mkdir(path.dirname(DELETED_MESSAGES_PATH), { recursive: true });
await fs.writeFile(
DELETED_MESSAGES_PATH,
JSON.stringify({ version: 1, sessions: state.sessions || {} }, null, 2),
'utf8'
);
}
export async function readHiddenSessionsState() {
try {
const raw = await fs.readFile(HIDDEN_SESSIONS_PATH, 'utf8');
const parsed = JSON.parse(raw);
return {
version: 1,
sessions: parsed && typeof parsed.sessions === 'object' && !Array.isArray(parsed.sessions)
? parsed.sessions
: {}
};
} catch (error) {
if (error.code !== 'ENOENT') {
console.warn('[sessions] Failed to read hidden session state:', error.message);
}
return emptyHiddenSessionsState();
}
}
export async function writeHiddenSessionsState(state) {
await fs.mkdir(path.dirname(HIDDEN_SESSIONS_PATH), { recursive: true });
await fs.writeFile(
HIDDEN_SESSIONS_PATH,
JSON.stringify({ version: 1, sessions: state.sessions || {} }, null, 2),
'utf8'
);
}
export async function readHiddenSessionIds() {
const state = await readHiddenSessionsState();
return new Set(Object.keys(state.sessions || {}));
}
export async function hideSessionInMobile(session) {
const id = String(session?.id || '').trim();
if (!id) {
const error = new Error('Session id is required');
error.statusCode = 400;
throw error;
}
const state = await readHiddenSessionsState();
const existing = state.sessions[id];
state.sessions[id] = {
hiddenAt: existing?.hiddenAt || new Date().toISOString(),
projectId: session.projectId || existing?.projectId || null,
projectPath: session.cwd || existing?.projectPath || null,
title: session.title || existing?.title || null
};
await writeHiddenSessionsState(state);
return { sessionId: id, hiddenAt: state.sessions[id].hiddenAt };
}
export async function readDeletedMessageIds(sessionId) {
const id = String(sessionId || '').trim();
if (!id) {
return new Set();
}
const state = await readDeletedMessagesState();
return new Set(Object.keys(state.sessions?.[id] || {}));
}
export function filterDeletedMessages(messages, deletedIds) {
if (!deletedIds.size) {
return messages;
}
return messages.filter((message) => !deletedIds.has(String(message.id || '')));
}
export async function hideSessionMessage(sessionId, messageId) {
const id = String(sessionId || '').trim();
const itemId = String(messageId || '').trim();
if (!id || !itemId) {
const error = new Error('sessionId and messageId are required');
error.statusCode = 400;
throw error;
}
const state = await readDeletedMessagesState();
if (!state.sessions[id] || typeof state.sessions[id] !== 'object' || Array.isArray(state.sessions[id])) {
state.sessions[id] = {};
}
const existing = state.sessions[id][itemId];
const deletedAt = existing?.deletedAt || new Date().toISOString();
state.sessions[id][itemId] = { deletedAt };
await writeDeletedMessagesState(state);
return { sessionId: id, messageId: itemId, deletedAt };
}