fix(persistence): address PR review feedback (4 low-cost improvements)
From PR #114 external review agent — adopted the real, low-cost findings; remaining items (false positives / design trade-offs) explained in PR replies: - coerceEpoch: !Number.isNaN → Number.isFinite — reject ±Infinity, which previously slipped through and produced Invalid Date via new Date(Infinity) - enforceRetentionCap pass2/pass3: decrement overflow only when idbDelete actually succeeds — a failed best-effort delete no longer under-evicts - cloudListStories: explicit column list instead of select() — avoid pulling the bulky session_jsonb when only metadata is needed - Supabase stories: composite primary key (user_id, id) + onConflict user_id,id — avoid a cross-user Session.id collision rejecting the second user's save (skeleton not yet deployed, so the migration is edited in place) typecheck + build:cf green.
This commit is contained in:
@@ -82,8 +82,9 @@ async function enforceRetentionCap(): Promise<void> {
|
||||
// Keep records that still owe the cloud a push (pending edits/soft-deletes
|
||||
// or a synced baseline) — hard-deleting them would lose that work silently.
|
||||
if (r.syncState !== "local-only") continue;
|
||||
await idbDelete(STORIES_STORE, r.id);
|
||||
overflow--;
|
||||
// Only count a slot freed when the delete actually succeeded — a failed
|
||||
// best-effort delete must not decrement overflow (would under-evict).
|
||||
if (await idbDelete(STORIES_STORE, r.id)) overflow--;
|
||||
}
|
||||
|
||||
// 3. Last-resort: if step 2 couldn't reach the cap, every remaining over-cap
|
||||
@@ -101,8 +102,7 @@ async function enforceRetentionCap(): Promise<void> {
|
||||
for (const r of live) {
|
||||
if (overflow <= 0) break;
|
||||
if (r.syncState === "local-only") continue; // already evicted in step 2
|
||||
await idbDelete(STORIES_STORE, r.id);
|
||||
overflow--;
|
||||
if (await idbDelete(STORIES_STORE, r.id)) overflow--;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
|
||||
Reference in New Issue
Block a user