From 3e00af792d1db8baa0ea37973cd249ca76e6fa6e Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Mon, 20 Jul 2026 14:04:09 +0300 Subject: [PATCH 1/7] chore: add PUBLIC_CACHE_DEBOUNCE_MS env var --- .env.example | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index bd75d8f..72c017c 100644 --- a/.env.example +++ b/.env.example @@ -8,4 +8,5 @@ ITEMS_TIMEOUT=600 ITEMS_STALE=600 PUBLIC_CATALOG_HREF=/ PUBLIC_DEVPORTAL_HREF=/ -PUBLIC_PUZZLE_HREF=/ \ No newline at end of file +PUBLIC_PUZZLE_HREF=/ +PUBLIC_CACHE_DEBOUNCE_MS=500 \ No newline at end of file From 00b550cd09061978bbbb4b88fcad3de5ccd9c2c7 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Mon, 20 Jul 2026 14:12:58 +0300 Subject: [PATCH 2/7] feat(helm): expose cache.debounceMs as PUBLIC_CACHE_DEBOUNCE_MS --- helm/templates/configmap.yaml | 1 + helm/values.yaml | 3 +++ 2 files changed, 4 insertions(+) diff --git a/helm/templates/configmap.yaml b/helm/templates/configmap.yaml index 2c8ce02..34535de 100644 --- a/helm/templates/configmap.yaml +++ b/helm/templates/configmap.yaml @@ -17,6 +17,7 @@ data: PUBLIC_CATALOG_HREF: 'http://catalog' PUBLIC_DEVPORTAL_HREF: 'http://developer-portal' PUBLIC_PUZZLE_HREF: '' + PUBLIC_CACHE_DEBOUNCE_MS: {{ .Values.cache.debounceMs | quote }} npm_config_cache: /tmp/ # default.conf: {{ tpl (.Files.Get "config/default.conf") . | quote }} {{- end }} diff --git a/helm/values.yaml b/helm/values.yaml index c10943b..7e0e30d 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -26,6 +26,9 @@ env: port: 8080 targetPort: 8080 +cache: + debounceMs: 500 + resources: enabled: true value: From 5823219de9fcde5af2ad188eae716f0c5732cfe1 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Mon, 20 Jul 2026 14:18:50 +0300 Subject: [PATCH 3/7] feat: add demoCache localStorage util --- src/lib/cache/demoCache.ts | 39 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/lib/cache/demoCache.ts diff --git a/src/lib/cache/demoCache.ts b/src/lib/cache/demoCache.ts new file mode 100644 index 0000000..15a39dd --- /dev/null +++ b/src/lib/cache/demoCache.ts @@ -0,0 +1,39 @@ +import type { File } from '$lib/types'; + +const NAMESPACE = 'demo-cache:v1'; + +interface CacheEntry { + files: File[]; + savedAt: number; +} + +function available(): boolean { + return typeof localStorage !== 'undefined'; +} + +export function cacheKey(client: string, name: string): string { + return `${NAMESPACE}:${client}/${name}`; +} + +export function loadCache(key: string): File[] | null { + if (!available()) return null; + const raw = localStorage.getItem(key); + if (raw === null) return null; + try { + const entry = JSON.parse(raw) as CacheEntry; + return Array.isArray(entry.files) ? entry.files : null; + } catch { + return null; + } +} + +export function saveCache(key: string, files: File[]): void { + if (!available()) return; + const entry: CacheEntry = { files, savedAt: Date.now() }; + localStorage.setItem(key, JSON.stringify(entry)); +} + +export function clearCache(key: string): void { + if (!available()) return; + localStorage.removeItem(key); +} From 1bd434481325143498fabeb229d840ccc62ee96a Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Mon, 20 Jul 2026 14:20:15 +0300 Subject: [PATCH 4/7] feat: emit edited files from flems component via onChange --- src/lib/components/flems.svelte | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib/components/flems.svelte b/src/lib/components/flems.svelte index 4a68d3c..6adbbf3 100644 --- a/src/lib/components/flems.svelte +++ b/src/lib/components/flems.svelte @@ -3,6 +3,7 @@ import type { File, Link } from '$lib/types'; export let files: File[]; export let links: Link[]; + export let onChange: ((files: File[]) => void) | undefined = undefined; const flemsBaseConfig = { shareButton: false, @@ -14,6 +15,12 @@ let flemsInstance: any; + function wireOnChange() { + if (!flemsInstance || !onChange) return; + flemsInstance.onchange = (state: { files: File[] }) => + onChange?.(state.files.map((f) => ({ name: f.name, content: f.content }))); + } + $: if (flemsInstance) { flemsInstance.set({ ...flemsBaseConfig, @@ -29,6 +36,7 @@ files, links: links.map((link) => ({ ...link, url: window.location.origin + link.url })) }); + wireOnChange(); }); From d627e9d4e5258b087752a678ee53607e7477e3c1 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Mon, 20 Jul 2026 14:25:17 +0300 Subject: [PATCH 5/7] feat: cache demo edits with Loaded-from-cache banner and clear button --- src/routes/demo/[client]/[name]/+page.svelte | 101 ++++++++++++++----- 1 file changed, 78 insertions(+), 23 deletions(-) diff --git a/src/routes/demo/[client]/[name]/+page.svelte b/src/routes/demo/[client]/[name]/+page.svelte index e7a9d98..e794182 100644 --- a/src/routes/demo/[client]/[name]/+page.svelte +++ b/src/routes/demo/[client]/[name]/+page.svelte @@ -1,31 +1,86 @@ -
-
- -
- + +
From b4e944369de9e2ef4fd0457a0d52a18f0a9004cb Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Mon, 20 Jul 2026 14:41:37 +0300 Subject: [PATCH 6/7] fix: register Flems onchange, react to demo switches, harden cache - Call flemsInstance.onchange(fn) instead of assigning it; the Flems API exposes onchange as a registrar, so assignment left autosave dead. - Recompute cache key + reload files reactively on same-route demo navigation (component is reused; only data updates). - Show the 'Loaded from cache' banner only when actually restored from cache, not after a fresh-edit autosave. - Clear pending save timer on demo switch and component destroy; save under the key captured at edit time. - NaN/negative-safe debounce parsing (allows 0); guard localStorage writes and drop the unused savedAt field. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/lib/cache/demoCache.ts | 22 +++++----- src/lib/components/flems.svelte | 7 +++- src/routes/demo/[client]/[name]/+page.svelte | 42 ++++++++++++++------ 3 files changed, 47 insertions(+), 24 deletions(-) diff --git a/src/lib/cache/demoCache.ts b/src/lib/cache/demoCache.ts index 15a39dd..3ecd8e8 100644 --- a/src/lib/cache/demoCache.ts +++ b/src/lib/cache/demoCache.ts @@ -2,11 +2,6 @@ import type { File } from '$lib/types'; const NAMESPACE = 'demo-cache:v1'; -interface CacheEntry { - files: File[]; - savedAt: number; -} - function available(): boolean { return typeof localStorage !== 'undefined'; } @@ -20,8 +15,8 @@ export function loadCache(key: string): File[] | null { const raw = localStorage.getItem(key); if (raw === null) return null; try { - const entry = JSON.parse(raw) as CacheEntry; - return Array.isArray(entry.files) ? entry.files : null; + const files = JSON.parse(raw) as File[]; + return Array.isArray(files) ? files : null; } catch { return null; } @@ -29,11 +24,18 @@ export function loadCache(key: string): File[] | null { export function saveCache(key: string, files: File[]): void { if (!available()) return; - const entry: CacheEntry = { files, savedAt: Date.now() }; - localStorage.setItem(key, JSON.stringify(entry)); + try { + localStorage.setItem(key, JSON.stringify(files)); + } catch { + // Ignore quota / private-mode write failures — caching is best-effort. + } } export function clearCache(key: string): void { if (!available()) return; - localStorage.removeItem(key); + try { + localStorage.removeItem(key); + } catch { + // Ignore — clearing is best-effort. + } } diff --git a/src/lib/components/flems.svelte b/src/lib/components/flems.svelte index 6adbbf3..92f9d7b 100644 --- a/src/lib/components/flems.svelte +++ b/src/lib/components/flems.svelte @@ -17,8 +17,11 @@ function wireOnChange() { if (!flemsInstance || !onChange) return; - flemsInstance.onchange = (state: { files: File[] }) => - onChange?.(state.files.map((f) => ({ name: f.name, content: f.content }))); + // Flems' `onchange` is a registrar you CALL to install a handler, + // not a settable property (`onchange: fn => actions.onchange = fn`). + flemsInstance.onchange((state: { files: File[] }) => + onChange?.(state.files.map((f) => ({ name: f.name, content: f.content }))) + ); } $: if (flemsInstance) { diff --git a/src/routes/demo/[client]/[name]/+page.svelte b/src/routes/demo/[client]/[name]/+page.svelte index e794182..66354a1 100644 --- a/src/routes/demo/[client]/[name]/+page.svelte +++ b/src/routes/demo/[client]/[name]/+page.svelte @@ -1,5 +1,5 @@