Repository navigation
2.3 Networking and Caching
Relevant source files
The following files were used as context for generating this wiki page:
This page details the networking abstraction, error handling, browser-side local storage caching, Electron disk caching, freshness/TTL policies, and offline behavior implemented in VariantScope. All network requests and cache operations route through a unified architectural layer that decouples browser execution from Electron desktop operations.
1. Unified HTTP Abstraction (src/core/http.js)
All network communication across VariantScope flows through getJson(), an abstraction layer defined in src/core/http.js:101-104. Depending on the runtime environment, getJson() automatically dispatches requests either via browser fetch() or through the Electron preload IPC bridge.
-
HttpError: Custom error class extendingErrorsrc/core/http.js:10-17. It exposes a classificationkind("blocked","offline","http","aborted", or"invalid") and an optional HTTPstatuscode. -
isElectron(): Detects whether the app is running inside the Electron preload bridge by inspectingwindow.api.fetchJsonsrc/core/http.js:20-21. -
abortable(): Wraps promises with anAbortSignallistener to immediately cancel in-flight requests when a search or operation is aborted src/core/http.js:24-32.
-
Browser Path (
viaBrowser): Checks the local storage cache unlessnoCacheis true src/core/http.js:55-62. If missing, it performs afetch()request with a 20-second timeout (TIMEOUT_MS) src/core/http.js:7-67 and up to one retry for rate limits (429) or server errors (>=500) src/core/http.js:65-92. Successful responses are written to the browser cache src/core/http.js:83. -
Desktop Path (
viaElectron): Delegates network calls to the main process viawindow.api.fetchJson()src/core/http.js:35-51, routing requests through an allowlisted, CORS-free, rate-limited environment with native disk caching.
graph TD
A["getJson(url, options)"] --> B{"isElectron()"}
B -->|Yes| C["viaElectron(url, options)"]
B -->|No| D["viaBrowser(url, options)"]
C --> E["window.api.fetchJson()"]
D --> F{"noCache?"}
F -->|No| G["cacheGet(key)"]
G -->|Hit| H["Return Cached Data"]
F -->|Yes| I["fetch(url)"]
G -->|Miss| I
I --> J["cacheSet(key, data)"]
J --> K["Return Fresh Data"]
Sources: src/core/http.js:1-104, tests/unit/http.test.js:1-134
2. Freshness and TTL Policy (src/core/freshness.js)
VariantScope separates data retention from data freshness. Cached records are never purged automatically due to age; instead, they are flagged as stale after a fixed Time-To-Live (TTL) duration.
-
OUT_OF_DATE_MS: Set to7 * 24 * 60 * 60 * 1000(7 days) src/core/freshness.js:3. -
isOutOfDate(): Compares a givenfetchedAttimestamp against the current system time usingOUT_OF_DATE_MSsrc/core/freshness.js:6-8. -
groupFor(): Normalizes and validates gene symbols (e.g.,"tp53"->"TP53") to ensure only safe, alphanumeric symbols are used as storage keys and file tags src/core/freshness.js:10-16.
graph TD
A["isOutOfDate(fetchedAt)"] --> B["Calculate age: Date.now() - fetchedAt"]
B --> C{"Age > OUT_OF_DATE_MS (7 days)?"}
C -->|Yes| D["Flag entry as stale: stale = true"]
C -->|No| E["Flag entry as fresh: stale = false"]
Sources: src/core/freshness.js:1-16, src/core/cache.js:1-109
3. Browser-Side Caching (src/core/cache.js)
In non-Electron environments (such as GitHub Pages or local web development), VariantScope uses an in-memory Map backed by browser localStorage src/core/cache.js:1-7.
-
Storage Wrapper:
storage()safely accesseswindow.localStorageinside atry/catchblock to gracefully handle private browsing modes, storage quotas, or sandboxed frames src/core/cache.js:9-16. -
Key Formatting: Stored API responses use prefixed keys structured as
vs:http:<gene_tag>:<method>\n<url>\n<body>src/core/cache.js:5-6. -
Group Listing and Deletion:
cacheListGroups()scanslocalStorageand memory to compute byte sizes and entry counts per gene src/core/cache.js:56-80.cacheDeleteGroups()removes cached responses for specified gene tags without disturbing user preferences like themes or recent searches src/core/cache.js:82-104.
graph TD
A["cacheGet(key, options)"] --> B["read(key)"]
B --> C{"Found in memory?"}
C -->|Yes| D["Return memory entry"]
C -->|No| E["Read localStorage viaPREFIX + key"]
E --> F{"Found in localStorage?"}
F -->|Yes| G["Populate memory Map & return entry"]
F -->|No| H["Return null"]
D --> I{"Expired & !allowStale?"}
G --> I
I -->|Yes| J["Return null"]
I -->|No| K["Return {value, savedAt, stale}"]
Sources: src/core/cache.js:1-109
4. Electron Disk Caching (electron/disk-cache.js)
In the desktop application, responses are persisted to disk in the user's userData folder through createDiskCache() electron/disk-cache.js:17.
-
File Naming: Each cached response is stored in a separate JSON file named
<gene_tag>~<hash>.json, where the hash is computed via SHA-256 over the request key electron/disk-cache.js:19-22. This allows gene groups to be listed, sized, and deleted efficiently without parsing file bodies. -
Atomic Writes:
set()writes data atomically by outputting to a temporary file (<file>.<pid>.tmp) and performing an atomicrename()operation, preventing half-written files during crashes electron/disk-cache.js:46-52. -
Group Management:
listGroups()inspects file stats to aggregate byte sizes and entry counts per gene electron/disk-cache.js:55-68, whiledeleteGroups()targets specific gene tags or performs a full cache wipe ("all") electron/disk-cache.js:70-86.
graph TD
A["cache.set(key, data, status, group)"] --> B["Ensure directory exists: mkdir(dir)"]
B --> C["Compute SHA-256 hash of key"]
C --> D["Generate temp file path: <file>.<pid>.tmp"]
D --> E["Write JSON {fetchedAt, status, data}"]
E --> F["Atomic rename temp file to <group>~<hash>.json"]
Sources: electron/disk-cache.js:1-93, tests/unit/disk-cache.test.js:1-96
5. Electron IPC and Preload Bridge (electron/preload.cjs)
Communication between the sandboxed renderer process and the Node.js main process is strictly restricted through a context bridge electron/preload.cjs:1-2.
The preload script exposes exactly six validated functions on window.api electron/preload.cjs:12-69:
-
fetchJson(url, options): Invokes thefetch-jsonIPC channel after validating URL and option boundaries electron/preload.cjs:14-32. -
saveFile(kind, suggestedName, data): Triggers native file save dialogs for CSV exports or PNG snapshots electron/preload.cjs:35-42. -
openExternal(url): Opens allowlisted external URLs in the system browser electron/preload.cjs:44-48. -
listCache(): Queries disk cache metrics grouped by gene electron/preload.cjs:50-53. -
deleteCache(target): Purges disk cache entries for specific gene arrays or"all"electron/preload.cjs:55-63. -
getAppInfo(): Retrieves application version, platform, and architecture details electron/preload.cjs:65-68.
Input parameters are rigorously guarded using requireString() to enforce string types and maximum length constraints electron/preload.cjs:5-10.
graph TD
A["Renderer Process (src/core/http.js)"] -->|"window.api.fetchJson()"| B["Preload Bridge (electron/preload.cjs)"]
B -->|"ipcRenderer.invoke('fetch-json')"| C["Main Process (electron/fetcher.js)"]
C -->|Disk Cache lookup| D["Disk Cache (electron/disk-cache.js)"]
D -->|Cache Hit/Miss| C
C -->|HTTPS Request if Miss| E["External API (UniProt/AlphaFold/ClinVar/gnomAD)"]
E --> C
C -->|JSON Reply| B
B -->|Resolved Promise| A
Sources: electron/preload.cjs:1-69, electron/disk-cache.js:1-93
Content imported from DeepWiki.