{"id":43997476,"url":"https://github.com/vixcpp/cache","last_synced_at":"2026-04-05T17:04:47.897Z","repository":{"id":333234733,"uuid":"1132798222","full_name":"vixcpp/cache","owner":"vixcpp","description":"HTTP cache engine for Vix. Pluggable cache stores, cache policies, and keying strategies for high-performance HTTP response caching.","archived":false,"fork":false,"pushed_at":"2026-02-03T12:23:24.000Z","size":39,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-04T02:37:36.384Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vixcpp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-12T13:18:35.000Z","updated_at":"2026-02-03T12:23:27.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/vixcpp/cache","commit_stats":null,"previous_names":["vixcpp/cache"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/vixcpp/cache","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vixcpp%2Fcache","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vixcpp%2Fcache/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vixcpp%2Fcache/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vixcpp%2Fcache/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vixcpp","download_url":"https://codeload.github.com/vixcpp/cache/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vixcpp%2Fcache/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29194009,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-07T07:37:03.739Z","status":"ssl_error","status_checked_at":"2026-02-07T07:37:03.029Z","response_time":63,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-02-07T12:02:34.016Z","updated_at":"2026-02-07T12:03:01.915Z","avatar_url":"https://github.com/vixcpp.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Vix Cache\n\nOffline-first HTTP cache • Deterministic policy • Memory + File stores • LRU eviction • Cache keys • Pruning\n\nThe Vix **cache** module provides a small, fast, predictable caching layer designed for **offline-first runtimes**.\n\nIt is built around a few explicit primitives:\n\n* `Cache` — the main entry point\n* `CachePolicy` — deterministic caching rules (TTL, stale windows)\n* `CacheContext` — request context (online/offline/network-error)\n* Stores: `MemoryStore`, `FileStore`, `LruMemoryStore`\n* `CacheKey` — stable key builder (normalizes query + optional vary headers)\n\nThis module is used by higher layers (e.g. HTTP GET cache middleware), but it is intentionally usable as a **standalone library**.\n\n---\n\n## Why this module exists\n\nIn offline-first systems, caching is not just a performance optimization.\nIt is part of **correctness under failure**:\n\n* if the device is **offline**, you must be able to serve previously validated data\n* if the network is **unstable**, you must be able to fall back to stale data safely\n* behavior must be **observable**, explicit, and testable\n\nThis module makes all caching decisions explicit with:\n\n* a `CachePolicy`\n* a `CacheContext`\n* a time `t_ms`\n\nSo you can test cache behavior as pure logic.\n\n---\n\n## Quick start (run the smoke tests)\n\nThe module includes runnable smoke tests (copy/paste friendly examples).\n\n```bash\nvix run modules/cache/tests/cache_smoke_test.cpp\nvix run modules/cache/tests/cache_context_mapper_smoke_test.cpp\n```\n\n(Exact paths may differ in your tree; the files shown below are the reference examples.)\n\n---\n\n## Core concepts\n\n### 1) CachePolicy\n\n`CachePolicy` defines deterministic time windows:\n\n* `ttl_ms` — fresh window (normal caching)\n* `allow_stale_if_offline` + `stale_if_offline_ms` — stale window when offline\n* `allow_stale_if_error` + `stale_if_error_ms` — stale window on network errors\n\nExample:\n\n```cpp\nvix::cache::CachePolicy policy;\npolicy.ttl_ms = 100;\npolicy.allow_stale_if_offline = true;\npolicy.stale_if_offline_ms = 10'000;\npolicy.allow_stale_if_error = true;\npolicy.stale_if_error_ms = 5'000;\n```\n\n---\n\n### 2) CacheContext\n\nThe same cached entry may be acceptable or rejected depending on the context:\n\n* `CacheContext::Online()`\n* `CacheContext::Offline()`\n* `CacheContext::NetworkError()`\n\nExample:\n\n```cpp\nauto got = cache.get(key, t_now, vix::cache::CacheContext::Offline());\n```\n\nThis is how you express: “accept stale data when offline, but not forever”.\n\n---\n\n### 3) Stores\n\nThe cache separates **policy** from **storage**.\n\n#### MemoryStore\n\n* in-memory map\n* fastest\n* ideal for servers / ephemeral caching\n\n#### FileStore\n\n* persists cache to disk\n* reloads on startup\n* suitable for local-first apps and edge runtimes\n\n#### LruMemoryStore\n\n* in-memory LRU eviction\n* bounded size via `max_entries`\n* good for servers that must cap memory\n\n---\n\n## Minimal usage\n\n```cpp\n#include \u003cmemory\u003e\n#include \u003cvix/cache/Cache.hpp\u003e\n#include \u003cvix/cache/CacheEntry.hpp\u003e\n#include \u003cvix/cache/CachePolicy.hpp\u003e\n#include \u003cvix/cache/CacheContext.hpp\u003e\n#include \u003cvix/cache/MemoryStore.hpp\u003e\n\nint main()\n{\n  using namespace vix::cache;\n\n  auto store = std::make_shared\u003cMemoryStore\u003e();\n\n  CachePolicy policy;\n  policy.ttl_ms = 10'000;\n  policy.allow_stale_if_offline = true;\n  policy.stale_if_offline_ms = 60'000;\n\n  Cache cache(policy, store);\n\n  const std::string key = \"GET:/api/users?page=1\";\n  const std::int64_t t0 = 1000; // example time\n\n  CacheEntry e;\n  e.status = 200;\n  e.body = R\"({\\\"ok\\\":true})\";\n  e.created_at_ms = t0;\n\n  cache.put(key, e);\n\n  auto got = cache.get(key, t0 + 5, CacheContext::Online());\n  if (got) {\n    // use got-\u003estatus / got-\u003ebody / got-\u003eheaders\n  }\n}\n```\n\n---\n\n## Offline-first behavior (from the context mapper smoke test)\n\nThe recommended pattern is:\n\n1. Determine connectivity context (online/offline/error)\n2. If **offline** → cache only\n3. If **online** → attempt network\n4. If **network error** → fall back to cache with `NetworkError` context\n\nThis logic is demonstrated as a testable pure function in:\n\n* `cache_context_mapper_smoke_test.cpp`\n\nIt validates the key offline-first behaviors:\n\n* offline + cached entry → **CacheHit**\n* offline + no entry → **OfflineMiss**\n* online + network ok → **NetOk** + cache populated\n* online + network error → **CacheHit** if `allow_stale_if_error`\n\n---\n\n## FileStore persistence\n\nThe file store smoke test validates:\n\n* entries persist to disk\n* new cache instance can reload the data\n* offline stale rules still apply after reload\n\nExample config (conceptual):\n\n```cpp\nvix::cache::FileStore::Config cfg;\ncfg.file_path = \"./build/.vix_test/cache_http.json\";\ncfg.pretty_json = true;\n\nauto store = std::make_shared\u003cvix::cache::FileStore\u003e(cfg);\n```\n\n---\n\n## Header normalization\n\nWhen inserting entries, the cache normalizes header keys to **lower-case**.\n\nThis ensures consistent lookup and avoids duplicated keys (case variants).\n\nThe smoke test verifies:\n\n* `Content-Type` becomes `content-type`\n* `X-Powered-By` becomes `x-powered-by`\n\n---\n\n## LRU eviction\n\n`LruMemoryStore` supports eviction via `max_entries`.\n\nThe smoke test demonstrates:\n\n* LRU behavior is stable\n* touching an entry updates its recency\n* inserting beyond capacity evicts the least recently used key\n\nExample:\n\n```cpp\nauto store = std::make_shared\u003cvix::cache::LruMemoryStore\u003e(\n  vix::cache::LruMemoryStore::Config{.max_entries = 2048}\n);\n```\n\n---\n\n## Pruning stale entries\n\n`Cache::prune(t_ms)` removes entries that are too old under the active policy.\n\nThe test demonstrates:\n\n* stale entries removed\n* fresh entries kept\n\nThis is useful for:\n\n* periodic cleanup loops\n* memory-bounded caches\n* long-running edge runtimes\n\n---\n\n## CacheKey builder\n\n`CacheKey::fromRequest()` generates stable cache keys by:\n\n* normalizing query params order (`b=2\u0026a=1` → `a=1\u0026b=2`)\n* optionally varying on selected headers (`Accept`, etc.)\n\nExample:\n\n```cpp\nstd::unordered_map\u003cstd::string, std::string\u003e headers;\nheaders[\"Accept\"] = \"application/json\";\nheaders[\"X-Device\"] = \"mobile\";\n\nauto k = vix::cache::CacheKey::fromRequest(\n  \"GET\",\n  \"/api/users\",\n  \"b=2\u0026a=1\",\n  headers,\n  {\"Accept\"}\n);\n```\n\nThis is critical to avoid cache fragmentation and to keep behavior deterministic.\n\n---\n\n## How cache fits in the umbrella\n\n* `cache` provides the offline-first caching core\n* `middleware` builds HTTP GET caching on top (control headers, debug headers, bypass)\n* `sync` and offline engines can reuse the same policy/context model\n\n---\n\n## Directory layout\n\nTypical layout:\n\n```\nmodules/cache/\n│\n├─ include/vix/cache/\n│  ├─ Cache.hpp\n│  ├─ CacheEntry.hpp\n│  ├─ CachePolicy.hpp\n│  ├─ CacheContext.hpp\n│  ├─ CacheContextMapper.hpp\n│  ├─ CacheKey.hpp\n│  ├─ MemoryStore.hpp\n│  ├─ FileStore.hpp\n│  ├─ LruMemoryStore.hpp\n│  └─ ...\n│\n└─ tests/\n   ├─ cache_smoke_test.cpp\n   └─ cache_context_mapper_smoke_test.cpp\n```\n\n---\n\n## License\n\nMIT — same as Vix.cpp\n\nRepository: [https://github.com/vixcpp/vix](https://github.com/vixcpp/vix)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvixcpp%2Fcache","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvixcpp%2Fcache","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvixcpp%2Fcache/lists"}