Rather than hitting the GitHub REST API on every incoming request, the portfolio serialises the fully mappedDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/santiagonieto09/portafolio/llms.txt
Use this file to discover all available pages before exploring further.
PortfolioSnapshot into a two-layer cache. The in-memory layer gives near-zero latency reads within the same process. The Cloudflare Cache API layer persists the snapshot across cold starts and across the multiple Worker instances that may be running in the same datacenter. Together they ensure the portfolio loads instantly for visitors, stays within GitHub’s rate limits, and continues serving content even when GitHub is temporarily unavailable.
All cache logic lives in src/infrastructure/github/snapshot-cache.ts.
Cache layers
In-memory (let memory)
A module-level variable holds the most recent snapshot as:
at is a Unix timestamp (milliseconds). This is the fastest read path — a synchronous comparison, no I/O. Its limitation is that it is scoped to a single process: a cold start or a new Worker isolate begins with memory = null.
Cloudflare Cache API (caches.default)
The snapshot is persisted as a JSON Response keyed on the synthetic URL https://portfolio.internal/snapshot. Cloudflare’s Cache API is shared across Worker instances within the same datacenter, so a cold-started isolate can warm its in-memory cache from the Cloudflare layer without calling GitHub.
The response is stored with:
| Header | Value |
|---|---|
content-type | application/json |
cache-control | public, max-age=604800 |
x-snapshot-at | Unix timestamp (ms) when the snapshot was written |
x-snapshot-at header is used for TTL validation on read, because the standard max-age may be modified or stripped by intermediate caching layers.
When caches.default is unavailable (Node.js, local dev), all Cloudflare Cache API operations are skipped silently and the module falls back to in-memory only.
Read path
readSnapshot() returns a fresh snapshot or null:
- Check
memory. If set andDate.now() - memory.at < WEEK_MS(7 × 24 × 60 × 60 × 1 000 ms), returnmemory.value. - Call
readFromCacheApi()which matcheshttps://portfolio.internal/snapshotagainstcaches.default, reads thex-snapshot-atheader, and applies the same 7-day TTL check. - On a Cloudflare Cache hit, back-fill
memoryso subsequent reads in the same process skip the Cache API entirely. - Return
nullif both layers miss or return expired data.
Stale reads
readSnapshotOrStale() is used by the degraded-mode fallback path:
readSnapshot() first. If that returns null (expired or missing), it returns memory.value without the TTL check — serving the last known-good snapshot even if it is days old. This is deliberately chosen over an error state when GitHub is temporarily unavailable.
Write path
writeSnapshot(value) is called after a successful full fetch from GitHub:
- Sets
memory = { at: Date.now(), value }immediately. - Serialises
valueto JSON and callscache.put(CACHE_URL, new Response(...))with the headers described above. - If the Cloudflare Cache API is unavailable, the
putis skipped silently — the in-memory write always succeeds.
Invalidation
invalidateSnapshot() forces the next read to bypass the cache entirely:
- Sets
memory = null. - Calls
cache.delete(CACHE_URL)oncaches.default(no-op if unavailable).
invalidatePortfolioCache() in github-api.server.ts, which is the public invalidation API exposed to the sync endpoint.
Weekly refresh
A snapshot is considered fresh for 7 days. After that, the next request triggers a full re-fetch from GitHub. Forced early invalidation is triggered byPOST /api/public/sync:
fetchPortfolio call sees a cache miss, then immediately re-populates both cache layers with fresh data.