mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-21 06:11:45 +00:00
852f0085d1
- Add offline CRUD to todoRepo, budgetRepo, reservationRepo, accommodationRepo, dayRepo, tripRepo, fileRepo with optimistic Dexie writes and mutation queue - Wire all store slices (todo, budget, reservations, files, dayNotes, assignments, tripStore) through repos for offline-aware writes - Cover archive/unarchive, file toggleStar/update/delete, assignment create/delete, day title/notes update offline paths - Migrate service worker from generateSW to injectManifest (custom sw.ts) with runtime-configurable api-data (7d/500) and map-tiles (30d/1000) cache policies - Add Settings → Offline cache configuration UI with save/reset and live SW postMessage - Extend mutationQueue flush to cover all writable Dexie tables
81 lines
2.6 KiB
TypeScript
81 lines
2.6 KiB
TypeScript
/**
|
|
* SW cache configuration — shared between the service worker and the main thread.
|
|
* Uses a dedicated 'trek-sw-config' IndexedDB database (separate from trek-offline)
|
|
* so the SW can read it without needing to know the full trek-offline schema versions.
|
|
*/
|
|
import Dexie, { type Table } from 'dexie';
|
|
|
|
export interface SwCacheConfig {
|
|
apiTtlDays: number;
|
|
apiMaxEntries: number;
|
|
tilesTtlDays: number;
|
|
tilesMaxEntries: number;
|
|
}
|
|
|
|
export const DEFAULT_SW_CONFIG: SwCacheConfig = {
|
|
apiTtlDays: 7,
|
|
apiMaxEntries: 500,
|
|
tilesTtlDays: 30,
|
|
tilesMaxEntries: 1000,
|
|
};
|
|
|
|
export const SW_CONFIG_BOUNDS = {
|
|
ttlMin: 1,
|
|
ttlMax: 365,
|
|
entriesMin: 10,
|
|
entriesMax: 5000,
|
|
};
|
|
|
|
export function validateSwConfig(raw: Partial<SwCacheConfig>): SwCacheConfig {
|
|
const clamp = (v: unknown, min: number, max: number, def: number): number => {
|
|
const n = Number(v);
|
|
return Number.isFinite(n) && n > 0 ? Math.max(min, Math.min(max, Math.round(n))) : def;
|
|
};
|
|
return {
|
|
apiTtlDays: clamp(raw.apiTtlDays, SW_CONFIG_BOUNDS.ttlMin, SW_CONFIG_BOUNDS.ttlMax, DEFAULT_SW_CONFIG.apiTtlDays),
|
|
apiMaxEntries: clamp(raw.apiMaxEntries, SW_CONFIG_BOUNDS.entriesMin, SW_CONFIG_BOUNDS.entriesMax, DEFAULT_SW_CONFIG.apiMaxEntries),
|
|
tilesTtlDays: clamp(raw.tilesTtlDays, SW_CONFIG_BOUNDS.ttlMin, SW_CONFIG_BOUNDS.ttlMax, DEFAULT_SW_CONFIG.tilesTtlDays),
|
|
tilesMaxEntries:clamp(raw.tilesMaxEntries, SW_CONFIG_BOUNDS.entriesMin, SW_CONFIG_BOUNDS.entriesMax, DEFAULT_SW_CONFIG.tilesMaxEntries),
|
|
};
|
|
}
|
|
|
|
// ── Dedicated IDB for SW config ───────────────────────────────────────────────
|
|
|
|
interface SwConfigRow extends SwCacheConfig {
|
|
id: 'singleton';
|
|
updatedAt: number;
|
|
}
|
|
|
|
class SwConfigDb extends Dexie {
|
|
config!: Table<SwConfigRow, 'singleton'>;
|
|
constructor() {
|
|
super('trek-sw-config');
|
|
this.version(1).stores({ config: 'id' });
|
|
}
|
|
}
|
|
|
|
let _db: SwConfigDb | null = null;
|
|
|
|
function getDb(): SwConfigDb {
|
|
if (!_db) _db = new SwConfigDb();
|
|
return _db;
|
|
}
|
|
|
|
export async function readSwConfigFromIDB(): Promise<SwCacheConfig | null> {
|
|
try {
|
|
const row = await getDb().config.get('singleton');
|
|
return row ? validateSwConfig(row) : null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export async function saveSwConfig(cfg: SwCacheConfig): Promise<void> {
|
|
const validated = validateSwConfig(cfg);
|
|
await getDb().config.put({ id: 'singleton', ...validated, updatedAt: Date.now() });
|
|
}
|
|
|
|
export async function loadSwConfig(): Promise<SwCacheConfig> {
|
|
return (await readSwConfigFromIDB()) ?? { ...DEFAULT_SW_CONFIG };
|
|
}
|