refactor(sync): namespace IndexedDB by userId

Each user gets their own IDB database (keepnotes-{userId}), preventing
data leaks between users on the same device. Add initDb(userId) called
on mount and destroyDb() for logout cleanup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Frederic Cabassut
2026-03-09 01:10:37 +01:00
committed by Fred Cabassut
co-authored by Claude Opus 4.6
parent 263fbbdf15
commit abb9ffcf95
2 changed files with 35 additions and 3 deletions
+31 -3
View File
@@ -1,7 +1,7 @@
import { openDB, type IDBPDatabase } from 'idb';
import { openDB, deleteDB, type IDBPDatabase } from 'idb';
import type { Note } from '$lib/types/index.js';
const DB_NAME = 'crumbs';
const DB_PREFIX = 'crumbs';
const DB_VERSION = 2;
export interface PendingAttachment {
@@ -51,10 +51,23 @@ export interface SyncQueueItem {
}
let dbPromise: Promise<IDBPDatabase<CrumbsDB>> | null = null;
let currentUserId: number | null = null;
/**
* Initialize the IDB for a specific user. Must be called before any
* other IDB operation (typically after login when userId is known).
*/
export function initDb(userId: number): void {
if (currentUserId !== userId) {
dbPromise = null;
currentUserId = userId;
}
}
export function getDb(): Promise<IDBPDatabase<CrumbsDB>> {
if (!dbPromise) {
dbPromise = openDB<CrumbsDB>(DB_NAME, DB_VERSION, {
const dbName = currentUserId ? `${DB_PREFIX}-${currentUserId}` : DB_PREFIX;
dbPromise = openDB<CrumbsDB>(dbName, DB_VERSION, {
upgrade(db) {
// Notes store
if (!db.objectStoreNames.contains('notes')) {
@@ -87,6 +100,21 @@ export function getDb(): Promise<IDBPDatabase<CrumbsDB>> {
return dbPromise;
}
/**
* Delete the current user's IDB (call on logout).
*/
export async function destroyDb(): Promise<void> {
if (dbPromise) {
const db = await dbPromise;
db.close();
dbPromise = null;
}
if (currentUserId) {
await deleteDB(`${DB_PREFIX}-${currentUserId}`);
currentUserId = null;
}
}
// Notes operations
export async function getAllNotes(): Promise<Note[]> {
const db = await getDb();
+4
View File
@@ -4,6 +4,7 @@
import Toast from '$lib/components/Layout/Toast.svelte';
import { loadNotes } from '$lib/stores/notes.js';
import { startSync, stopSync } from '$lib/sync/client.js';
import { initDb } from '$lib/sync/idb.js';
import { onMount, onDestroy } from 'svelte';
let { data, children } = $props();
@@ -11,6 +12,9 @@
onMount(() => {
sidebarOpen = window.matchMedia('(min-width: 1024px)').matches;
if (data.user) {
initDb(data.user.id);
}
loadNotes();
startSync();
});