
Security News
Feross on TBPN: How North Korea Hijacked Axios
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.
@inlay/cache
Advanced tools
Every Inlay XRPC component response may include a [`CachePolicy`](https://pdsls.dev/at://did:plc:mdg3w2kpadcyxy33pizokzf3/com.atproto.lexicon.schema/at.inlay.defs#schema:cachePolicy) — a lifetime and a set of invalidation tags:
Every Inlay XRPC component response may include a CachePolicy — a lifetime and a set of invalidation tags:
{
"life": "hours",
"tags": [
// Invalidate me when this record changes
{ "$type": "at.inlay.defs#tagRecord", "uri": "at://did:plc:abc/app.bsky.actor.profile/self" }
]
}
This package lets you build that policy declaratively. Instead of constructing the object by hand, call cacheLife and cacheTagRecord anywhere during your handler — including inside async helper functions.
A server runtime can collect these calls and produce the cache policy object.
npm install @inlay/cache
import { $ } from "@inlay/core";
import { cacheLife, cacheTagRecord, cacheTagLink } from "@inlay/cache";
async function fetchRecord(uri) {
cacheTagRecord(uri); // Invalidate me when this record changes
cacheLife("max");
const [, , repo, collection, rkey] = uri.split("/");
const params = new URLSearchParams({ repo, collection, rkey });
const res = await fetch(
`https://slingshot.microcosm.blue/xrpc/com.atproto.repo.getRecord?${params}`
);
return (await res.json()).value;
}
async function fetchProfileStats(did) {
cacheLife("hours");
cacheTagLink(`at://${did}`, "app.bsky.graph.follow"); // Invalidate me on backlinks
const params = new URLSearchParams({ actor: did });
const res = await fetch(
`https://public.api.bsky.app/xrpc/app.bsky.actor.getProfile?${params}`
);
const data = await res.json();
return { followersCount: data.followersCount };
}
async function ProfileCard({ uri }) {
const profile = await fetchRecord(uri);
const did = uri.split("/")[2];
const stats = await fetchProfileStats(did);
return $("org.atsui.Stack", { gap: "small" },
$("org.atsui.Avatar", { src: profile.avatar, did }),
$("org.atsui.Text", {}, profile.displayName),
$("org.atsui.Text", {}, `${stats.followersCount} followers`),
);
}
A server runtime could then provide a way to run ProfileCard and collect its cache policy:
{
"node": {
"$": "$",
"type": "org.atsui.Stack",
"props": {
"gap": "small",
"children": [
{ "$": "$", "type": "org.atsui.Avatar", "props": { "src": "...", "did": "did:plc:ragtjsm2j2vknwkz3zp4oxrd" }, "key": "0" },
{ "$": "$", "type": "org.atsui.Text", "props": { "children": ["Paul Frazee"] }, "key": "1" },
{ "$": "$", "type": "org.atsui.Text", "props": { "children": ["308032 followers"] }, "key": "2" }
]
}
},
"cache": {
"life": "hours",
"tags": [
{ "$type": "at.inlay.defs#tagRecord", "uri": "at://did:plc:ragtjsm2j2vknwkz3zp4oxrd/app.bsky.actor.profile/self" },
{ "$type": "at.inlay.defs#tagLink", "subject": "at://did:plc:ragtjsm2j2vknwkz3zp4oxrd", "from": "app.bsky.graph.follow" }
]
}
}
There is no prescribed server runtime. Cache functions write to a Dispatcher on Symbol.for("inlay.cache"). Your server provides the implementation. Minimal example:
import { AsyncLocalStorage } from "node:async_hooks";
import { serializeTree } from "@inlay/core";
import type { Dispatcher } from "@inlay/cache";
const LIFE_ORDER = ["seconds", "minutes", "hours", "max"];
const cacheStore = new AsyncLocalStorage();
// Install the dispatcher — cache functions will write here
globalThis[Symbol.for("inlay.cache")] = {
cacheLife(life) { cacheStore.getStore().lives.push(life); },
cacheTag(tag) { cacheStore.getStore().tags.push(tag); },
} satisfies Dispatcher;
// Run a handler and collect its cache policy
async function runHandler(handler, props) {
const state = { lives: [], tags: [] };
const node = await cacheStore.run(state, () => handler(props));
const life = state.lives.reduce((a, b) =>
LIFE_ORDER.indexOf(a) < LIFE_ORDER.indexOf(b) ? a : b
);
return {
node: serializeTree(node),
cache: { life, tags: state.tags },
};
}
const result = await runHandler(ProfileCard, {
uri: "at://did:plc:ragtjsm2j2vknwkz3zp4oxrd/app.bsky.actor.profile/self",
});
console.log(JSON.stringify(result, null, 2));
// => { node: { ... }, cache: { life: "hours", tags: [...] } }
Installation happens via a global so that coordination doesn't depend on package versioning or hoisting working correctly. Helpers like fetchRecord and fetchProfileStats can be moved into libraries.
| Function | Description |
|---|---|
cacheLife(life) | Set cache duration. Strictest (shortest) call wins. Values: "seconds", "minutes", "hours", "max" |
cacheTagRecord(uri) | Invalidate when this AT Protocol record is created, updated, or deleted |
cacheTagLink(subject, from?) | Invalidate when any record linking to subject changes. Optionally restrict to a specific collection |
Life — "seconds" | "minutes" | "hours" | "max"CacheTag — TagRecord | TagLinkTagRecord — { $type: "at.inlay.defs#tagRecord", uri: string }TagLink — { $type: "at.inlay.defs#tagLink", subject: string, from?: string }Dispatcher — interface for the server runtime to implementFAQs
Every Inlay XRPC component response may include a [`CachePolicy`](https://pdsls.dev/at://did:plc:mdg3w2kpadcyxy33pizokzf3/com.atproto.lexicon.schema/at.inlay.defs#schema:cachePolicy) — a lifetime and a set of invalidation tags:
The npm package @inlay/cache receives a total of 251 weekly downloads. As such, @inlay/cache popularity was classified as not popular.
We found that @inlay/cache demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.

Security News
OpenSSF has issued a high-severity advisory warning open source developers of an active Slack-based campaign using impersonation to deliver malware.

Research
/Security News
Malicious packages published to npm, PyPI, Go Modules, crates.io, and Packagist impersonate developer tooling to fetch staged malware, steal credentials and wallets, and enable remote access.