cache-entanglement
Efficiently manage interconnected caches with automatic dependency tracking and updates.
✨ Features
- Declare dependencies between caches
- Automatic invalidation and updates
- Sync and async cache creation functions
- Key-based namespace resolution
- Lifespan and garbage collection handling
🚀 Quick Start
import { CacheEntanglementSync } from 'cache-entanglement'
const name = new CacheEntanglementSync((key, state, value: string) => value)
const age = new CacheEntanglementSync((key, state, value: number) => value)
const user = new CacheEntanglementSync((key, state) => {
const { name, age } = state
return { name: name.raw, age: age.raw }
}, {
dependencies: { name, age },
})
name.cache('john', 'John')
age.cache('john', 20)
user.cache('john/user')
user.get('john/user').raw // { name: 'John', age: 20 }
age.update('john', 21)
user.get('john/user').raw // { name: 'John', age: 21 }
📦 Installation
Node.js
npm i cache-entanglement
// CommonJS
const { CacheEntanglementSync, CacheEntanglementAsync } = require('cache-entanglement')
// ESM
import { CacheEntanglementSync, CacheEntanglementAsync } from 'cache-entanglement'
Browser (ESM)
import { CacheEntanglementSync, CacheEntanglementAsync } from 'https://cdn.jsdelivr.net/npm/cache-entanglement@1.x.x/+esm'
📚 How It Works
Key Naming Convention for Dependencies
Keys must reflect their dependency path. For example:
const company = new CacheEntanglementSync((key, state, name: string) => name)
const employee = new CacheEntanglementSync((key, { company }, name: string) => {
return { name, companyName: company.raw }
}, {
dependencies: { company },
})
company.cache('github', 'GitHub')
employee.cache('github/john', 'John')
By naming the employee key as github/john
, it indicates dependency on the github
key from the company
cache. Updates to company:github
automatically propagate.
You can continue chaining dependencies:
const card = new CacheEntanglementSync((key, { employee }, tel: string) => ({
...employee.clone(),
tel,
}), {
dependencies: { employee },
})
card.cache('github/john/card', 'xxx-xxxx-xxxx')
Async Cache Example
class FileManager {
constructor() {
this.content = new CacheEntanglementAsync(async (key, state, path: string) => {
return await fs.readFile(path)
})
}
async getContent(path: string) {
return await this.content.cache(`key:${path}`, path)
}
}
🔁 Handling Dependencies
const articleComments = new CacheEntanglementSync((key, state, comments: string[]) => comments)
const articleContent = new CacheEntanglementSync((key, state, content: string) => content)
const article = new CacheEntanglementSync((key, state) => {
return {
articleComments: state.articleComments.raw,
articleContent: state.articleContent.raw,
}
}, {
dependencies: { articleComments, articleContent },
})
function postArticle(content: string) {
const id = uuid()
articleComments.cache(id, [])
articleContent.cache(id, content)
article.cache(id)
}
function addComment(id: string, comment: string) {
if (!articleComments.exists(id)) throw new Error(`Missing article: ${id}`)
const comments = articleComments.get(id).clone('array-shallow-copy')
comments.push(comment)
articleComments.update(id, comments)
}
🕒 Lifespan & Garbage Collection
Use the lifespan
option to keep entries alive for a guaranteed duration:
const cache = new CacheEntanglementSync((key, state, value: string) => value, {
lifespan: '5m' // or 1000 * 60 * 5
})
cache.cache('my-key', 'hello')
The cache remains alive for 5 minutes after each access. If garbage collected after expiration, it'll regenerate on the next .cache()
call.
🪝 beforeUpdateHook
A hook you can use to pre-assign dependencies from within the parent:
const user = new CacheEntanglementSync((key, state, _name, _age) => {
return {
name: state.name.clone(),
age: state.age.clone(),
}
}, {
dependencies: { name, age },
beforeUpdateHook: (key, dependencyKey, _name, _age) => {
name.cache(key, _name)
age.cache(key, _age)
}
})
user.cache('john', 'John', 20)
⚠️ Avoid using .update()
within beforeUpdateHook
to prevent recursion.
🧩 TypeScript Usage
import { CacheEntanglementSync } from 'cache-entanglement'
class MyClass {
private readonly _myCache = new CacheEntanglementSync((key, state) => {
// your logic
})
}
License
MIT