KV-backed Pull Cache
createKvPullCache implements the PullCache interface using any async key-value
store. Use it to persist ciphertext-at-rest in environments that lack IndexedDB
(React Native, Electron, Node.js workers) or to share a cache across browser tabs.
Interface
import { createKvPullCache } from "@drakkar.software/starfish-client"
import type { KvStore, KvPullCacheOptions } from "@drakkar.software/starfish-client"
interface KvStore {
get(key: string): Promise<string | null | undefined>
set(key: string, value: string): Promise<void>
}
interface KvPullCacheOptions {
/** Key prefix prepended to every cache key. Default "". */
prefix?: string
/** Maximum age in ms before an entry is considered expired. Default: no expiry. */
maxAgeMs?: number
}
Usage
import { StarfishClient, createKvPullCache } from "@drakkar.software/starfish-client"
import { MMKV } from "react-native-mmkv"
// Wrap MMKV (React Native) as a KvStore
const mmkv = new MMKV()
const kv: KvStore = {
get: async (key) => mmkv.getString(key) ?? null,
set: async (key, value) => mmkv.set(key, value),
}
const client = new StarfishClient({
baseUrl: "https://api.example.com",
cache: createKvPullCache(kv, {
prefix: "starfish.",
maxAgeMs: 5 * 60 * 1000, // 5 minutes
}),
})
Adapters for common stores
AsyncStorage (React Native)
import AsyncStorage from "@react-native-async-storage/async-storage"
const cache = createKvPullCache({
get: AsyncStorage.getItem,
set: AsyncStorage.setItem,
}, { prefix: "sf." })
localStorage (browser, sync)
Wrap synchronous APIs in an async shim:
const cache = createKvPullCache({
get: async (key) => localStorage.getItem(key),
set: async (key, value) => localStorage.setItem(key, value),
})
Electron electron-store
import Store from "electron-store"
const store = new Store()
const cache = createKvPullCache({
get: async (key) => store.get(key) as string ?? null,
set: async (key, value) => store.set(key, value),
})
TTL expiry
When maxAgeMs is set, each cached entry is stored as an envelope:
{ "payload": "<the pull result JSON>", "_cachedAt": 1716000000000 }
On read, if Date.now() - _cachedAt > maxAgeMs, the entry is treated as a miss
(returns null). The stale value is not deleted from the KV store — the next
successful pull overwrites it.
Error handling
All get and set operations are wrapped in try/catch. Errors from the KV store
are swallowed silently: a read error returns null (cache miss), a write error is
ignored. This ensures a broken or unavailable KV store never blocks normal sync
operations.
Thread safety
The KV store's get and set are called independently. If multiple instances share
a KV store, the last writer wins — same as any pull cache. For single-writer setups
(one client per process) this is safe.