fix: cross-client settings sync and sidebar session pagination
- Paginate /experimental/session via time.updated fallback so sidebar loads past the 200-item first page when server omits x-next-cursor. - VSCode extension persists all settings in shared ~/.config/openchamber/settings.json (not only opencodeBinary), matching Desktop and Web. Canonical read from disk with globalState fallback for eager migration of pre-existing users. - Desktop settings sync: guard the contextBridge read-only __OPENCHAMBER_HOME__ assignment that was silently throwing a TypeError and skipping the whole applySettings chain — leaving server-synced values (autoDeleteAfterDays, autoDeleteEnabled, sessionRetentionAction) stuck at local defaults. Also wait for Zustand persist hydration before applying server settings to avoid overwrite races.
This commit is contained in:
@@ -69,6 +69,7 @@ export async function listGlobalSessionPages(
|
||||
},
|
||||
): Promise<GlobalSessionRecord[]> {
|
||||
const all: GlobalSessionRecord[] = [];
|
||||
const seenIds = new Set<string>();
|
||||
let cursor: number | undefined;
|
||||
|
||||
while (true) {
|
||||
@@ -76,23 +77,41 @@ export async function listGlobalSessionPages(
|
||||
() => apiClient.experimental.session.list({
|
||||
archived: options.archived,
|
||||
limit: options.pageSize,
|
||||
...(cursor ? { cursor } : {}),
|
||||
...(cursor !== undefined ? { cursor } : {}),
|
||||
}),
|
||||
{ attempts: 3, delay: 500, retryIf: () => true },
|
||||
);
|
||||
|
||||
const payload = Array.isArray(response.data) ? (response.data as GlobalSessionRecord[]) : [];
|
||||
if (payload.length === 0) {
|
||||
break;
|
||||
if (payload.length === 0) break;
|
||||
|
||||
let appended = 0;
|
||||
for (const session of payload) {
|
||||
if (!session?.id || seenIds.has(session.id)) continue;
|
||||
seenIds.add(session.id);
|
||||
all.push(session);
|
||||
appended += 1;
|
||||
}
|
||||
if (appended > 0) {
|
||||
options.onPage?.(payload);
|
||||
}
|
||||
|
||||
all.push(...payload);
|
||||
options.onPage?.(payload);
|
||||
// Stop on partial page — nothing more to fetch.
|
||||
if (payload.length < options.pageSize) break;
|
||||
|
||||
// Prefer server header; fall back to last session's `time.updated`
|
||||
// (cursor semantics on server = "updated strictly before this timestamp").
|
||||
const headerCursor = toNumber(readResponseHeader(response, "x-next-cursor"));
|
||||
const lastUpdated = payload[payload.length - 1]?.time?.updated;
|
||||
const nextCursor = headerCursor
|
||||
?? (typeof lastUpdated === "number" && Number.isFinite(lastUpdated) ? lastUpdated : undefined);
|
||||
|
||||
if (nextCursor === undefined) break;
|
||||
// Loop guard: cursor must move backwards in time.
|
||||
if (cursor !== undefined && nextCursor >= cursor) break;
|
||||
// Every id in this page already seen — stop to avoid spinning.
|
||||
if (appended === 0) break;
|
||||
|
||||
const nextCursor = toNumber(readResponseHeader(response, "x-next-cursor"));
|
||||
if (!nextCursor) {
|
||||
break;
|
||||
}
|
||||
cursor = nextCursor;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user