{"_id":"@021.is/spine-cache","_rev":"2-eb9c3625a287cc76f9cb678b93677497","name":"@021.is/spine-cache","dist-tags":{"latest":"0.4.3"},"versions":{"0.4.0":{"name":"@021.is/spine-cache","version":"0.4.0","license":"MIT","_id":"@021.is/spine-cache@0.4.0","maintainers":[{"name":"edvone","email":"edvard@edvone.dev"}],"homepage":"https://github.com/021is/spine-ts#readme","bugs":{"url":"https://github.com/021is/spine-ts/issues"},"dist":{"shasum":"62506698cc362a6e50ac08a4ca03be58c0b24bed","tarball":"https://registry.npmjs.org/@021.is/spine-cache/-/spine-cache-0.4.0.tgz","fileCount":4,"integrity":"sha512-hJU1EdYeF7T5ngP00FtxPhVj+nYlotimsm0j8L4FlZMgCX7ZTALbsdJioD5LWGwB5YKFUNw6kHkoFhSJURW8uQ==","signatures":[{"sig":"MEUCIQDT+gtEN7WIXD3NYM3yCbGdgNvQDpIqi8Om7kBX4wdoagIgMSorY+1u78HgGAJk8QcuDppay4UR1YNZZ4hbF3XsNw0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":4712},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"e4434c6f59db8f586e0f05ffdb3b88a96e68e67b","scripts":{"build":"tsup src/index.ts --format esm --dts --clean","typecheck":"tsc --noEmit"},"_npmUser":{"name":"edvone","email":"edvard@edvone.dev"},"repository":{"url":"git+https://github.com/021is/spine-ts.git","type":"git","directory":"packages/cache"},"_npmVersion":"10.9.4","description":"Cache helpers with TTL + tag invalidation. Wraps Next.js `unstable_cache` and `cache()` patterns; in-memory store for non-Next runtimes.","directories":{},"_nodeVersion":"22.22.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/spine-cache_0.4.0_1779981936092_0.511522778762614","host":"s3://npm-registry-packages-npm-production"}},"0.4.3":{"name":"@021.is/spine-cache","version":"0.4.3","license":"MIT","description":"Cache helpers with TTL + tag invalidation. Wraps Next.js `unstable_cache` and `cache()` patterns; in-memory store for non-Next runtimes.","type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"build":"tsup src/index.ts --format esm --dts --clean","typecheck":"tsc --noEmit"},"repository":{"type":"git","url":"git+https://github.com/021is/spine-ts.git","directory":"packages/cache"},"publishConfig":{"access":"public"},"_id":"@021.is/spine-cache@0.4.3","gitHead":"b9f9333776fa55686cc2feb05f851aa6000b0e05","bugs":{"url":"https://github.com/021is/spine-ts/issues"},"homepage":"https://github.com/021is/spine-ts#readme","_nodeVersion":"22.22.0","_npmVersion":"10.9.4","dist":{"integrity":"sha512-mb+eajiNUK8pSG48TGRkNTpd2ukQYMbQK3AdVrdoo+mcdZ0A1vn7OSz+mRFkITymj0borT3lfa6HHnJ/d/+SXg==","shasum":"d3a6fd093e06357d5aee8a9019cd1987d4c5e391","tarball":"https://registry.npmjs.org/@021.is/spine-cache/-/spine-cache-0.4.3.tgz","fileCount":5,"unpackedSize":5997,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIDEIylbpzxwGowlzPuZhUN3vSqR0rdcd6qjdk4hQoq7/AiEArU3AKsebAGj31FoHV6oJOFN3W3+AV3HANbdJyC2CdfA="}]},"_npmUser":{"name":"edvone","email":"edvard@edvone.dev"},"directories":{},"maintainers":[{"name":"edvone","email":"edvard@edvone.dev"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/spine-cache_0.4.3_1779995227910_0.16369409572594473"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-28T15:25:35.863Z","modified":"2026-05-28T19:07:08.205Z","0.4.0":"2026-05-28T15:25:36.245Z","0.4.3":"2026-05-28T19:07:08.067Z"},"bugs":{"url":"https://github.com/021is/spine-ts/issues"},"license":"MIT","homepage":"https://github.com/021is/spine-ts#readme","repository":{"type":"git","url":"git+https://github.com/021is/spine-ts.git","directory":"packages/cache"},"description":"Cache helpers with TTL + tag invalidation. Wraps Next.js `unstable_cache` and `cache()` patterns; in-memory store for non-Next runtimes.","maintainers":[{"name":"edvone","email":"edvard@edvone.dev"}],"readme":"# @021.is/spine-cache\n\nTTL + tag-invalidation cache with **single-flight dedupe**. Fixes the classic N+1: 10 components asking for the same user concurrently → 1 backend call.\n\n## Use\n\n```ts\nimport { makeMemoryCache, makeKey } from \"@021.is/spine-cache\";\n\nconst cache = makeMemoryCache();\n\nasync function getUser(id: string) {\n  return cache.fetch(\n    makeKey(\"user\", id),\n    async () => db.user.findUniqueOrThrow({ where: { id } }),\n    { ttlMs: 60_000, tags: [\"user\", `user:${id}`] },\n  );\n}\n\n// Invalidate by key or by tag\ncache.invalidate(makeKey(\"user\", id));\ncache.invalidateTag(\"user\"); // wipes ALL user entries\n```\n\n## Why single-flight matters\n\nWithout dedupe: 10 concurrent components each call `getUser(\"u_1\")` → 10 DB hits. With dedupe: 1 promise shared → 1 DB hit.\n\n## Helpers\n\n- `makeKey(\"user\", id, \"lang\", \"en\")` → `\"user:u_1:lang:en\"` (readable in dashboards)\n- `cache.size()` for observability\n- `cache.clear()` for tests\n\n## Why not Next.js `unstable_cache` directly\n\nYou can combine them — `unstable_cache` for cross-request, `spine-cache` for in-request dedupe. spine-cache is process-local (no Redis), zero deps.\n","readmeFilename":"README.md"}