{"_id":"@benskalz/swr-idb-cache","_rev":"3-a5e4d7df44a87717cd6c24704535651f","name":"@benskalz/swr-idb-cache","dist-tags":{"latest":"1.1.4"},"versions":{"1.1.2":{"name":"@benskalz/swr-idb-cache","version":"1.1.2","keywords":["swr","cache","IndexedDB","idb"],"author":{"url":"https://www.piotr.cz","name":"Piotr Konieczny","email":"hello@piotr.cz"},"license":"MIT","_id":"@benskalz/swr-idb-cache@1.1.2","maintainers":[{"name":"benskalz","email":"benskalz.npm@gmail.com"}],"homepage":"https://github.com/piotr-cz/swr-idb-cache","bugs":{"url":"https://github.com/piotr-cz/swr-idb-cache/issues"},"dist":{"shasum":"90d11f6032e6f2395818d3b392634ae55c999360","tarball":"https://registry.npmjs.org/@benskalz/swr-idb-cache/-/swr-idb-cache-1.1.2.tgz","fileCount":7,"integrity":"sha512-xSb96S0l+E8y5a7PUPPDa5wipPQR+F3S0DT9FPyFmQF1IFk9yrXU08e/mUqcRzs/YZDLCxT1MlvpafYejYlIkw==","signatures":[{"sig":"MEUCICj8fHvOiCkCirhY0ABToCB1bi1ZYdXWZdAj5x/CFt3QAiEA50udKUnpDbSG0FZNFVT6vCP59gkRF/UM6boxejOr3U0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":24822},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"import":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.ts","default":"./dist/index.js"}}},"gitHead":"212c6562610c2c92bce204703a27d79ec997897f","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"bunchee","prepare":"npm run build","npmpublish":"npm publish","types:check":"tsc --noEmit"},"_npmUser":{"name":"benskalz","email":"benskalz.npm@gmail.com"},"repository":{"url":"git+https://github.com/piotr-cz/swr-idb-cache.git","type":"git"},"_npmVersion":"8.3.1","description":"IndexedDB Cache Provider for SWR","directories":{},"_nodeVersion":"20.18.0","dependencies":{"idb":"^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"swr":"^2.0.0","react":"^18.0.0","bunchee":"^5.3.2","typescript":"^5.5.4","@types/react":"^18.3.3"},"peerDependencies":{"swr":"^2.0.0-beta.3","react":"^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"},"_npmOperationalInternal":{"tmp":"tmp/swr-idb-cache_1.1.2_1757627626491_0.8618364965405161","host":"s3://npm-registry-packages-npm-production"}},"1.1.3":{"name":"@benskalz/swr-idb-cache","version":"1.1.3","keywords":["swr","cache","IndexedDB","idb"],"author":{"url":"https://www.piotr.cz","name":"Piotr Konieczny","email":"hello@piotr.cz"},"license":"MIT","_id":"@benskalz/swr-idb-cache@1.1.3","maintainers":[{"name":"benskalz","email":"benskalz.npm@gmail.com"}],"homepage":"https://github.com/piotr-cz/swr-idb-cache","bugs":{"url":"https://github.com/piotr-cz/swr-idb-cache/issues"},"dist":{"shasum":"62401803f7df894b675fd10be500f0403bedcc36","tarball":"https://registry.npmjs.org/@benskalz/swr-idb-cache/-/swr-idb-cache-1.1.3.tgz","fileCount":7,"integrity":"sha512-k8sxxjfiAmdUBrZ4MVwpxwJ8hTd8D/Mt9olN4nsatYqD6El7gXw8+m70rtDmerSmrOK8nvmWLWKCmGT80WhiiA==","signatures":[{"sig":"MEYCIQCA8b+5GqzjUXQzIltlK5cPWO+JKBNL2AOgGbJGJgG/JQIhAMjPsy3sBPqAl03cUQqHedX28QVcJRMCQxR3mTxF+W9S","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":24882},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"import":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.ts","default":"./dist/index.js"}}},"gitHead":"5ea55638f2052dec0047adee59fd9b54c9e44e7a","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"bunchee","prepare":"npm run build","npmpublish":"npm publish","types:check":"tsc --noEmit"},"_npmUser":{"name":"benskalz","email":"benskalz.npm@gmail.com"},"repository":{"url":"git+https://github.com/piotr-cz/swr-idb-cache.git","type":"git"},"_npmVersion":"8.3.1","description":"IndexedDB Cache Provider for SWR","directories":{},"_nodeVersion":"20.18.0","dependencies":{"idb":"^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"swr":"^2.0.0","react":"^18.0.0","bunchee":"^5.3.2","typescript":"^5.5.4","@types/react":"^18.3.3"},"peerDependencies":{"swr":"^2.0.0-beta.3","react":"^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"},"_npmOperationalInternal":{"tmp":"tmp/swr-idb-cache_1.1.3_1757628402528_0.7212888354077445","host":"s3://npm-registry-packages-npm-production"}},"1.1.4":{"name":"@benskalz/swr-idb-cache","version":"1.1.4","description":"IndexedDB Cache Provider for SWR","main":"./dist/index.js","module":"./dist/index.mjs","types":"./dist/index.d.ts","exports":{".":{"import":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.ts","default":"./dist/index.js"}}},"repository":{"type":"git","url":"git+https://github.com/piotr-cz/swr-idb-cache.git"},"author":{"name":"Piotr Konieczny","email":"hello@piotr.cz","url":"https://www.piotr.cz"},"homepage":"https://github.com/piotr-cz/swr-idb-cache","license":"MIT","keywords":["swr","cache","IndexedDB","idb"],"scripts":{"build":"bunchee","npmpublish":"npm publish","prepare":"npm run build","types:check":"tsc --noEmit","test":"echo \"Error: no test specified\" && exit 1"},"dependencies":{"idb":"^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"},"devDependencies":{"@types/react":"^18.3.3","bunchee":"^5.3.2","react":"^18.0.0","swr":"^2.0.0","typescript":"^5.5.4"},"peerDependencies":{"react":"^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0","swr":"^2.0.0-beta.3"},"publishConfig":{"access":"public"},"gitHead":"b96af12a292ca1cf406490a55890d865e5cddbaa","bugs":{"url":"https://github.com/piotr-cz/swr-idb-cache/issues"},"_id":"@benskalz/swr-idb-cache@1.1.4","_nodeVersion":"20.18.0","_npmVersion":"8.3.1","dist":{"integrity":"sha512-9FQDWvQAm9QwfZS3dPiS6fZw/AO6QrsK+PBBVfXWNB93vSmWYHUdCOnxIykPiyK9hS0HcfVJLVt0Mva7GUaCzg==","shasum":"c8d4d6486d4a29b94fe3c02c764114197d7aad05","tarball":"https://registry.npmjs.org/@benskalz/swr-idb-cache/-/swr-idb-cache-1.1.4.tgz","fileCount":7,"unpackedSize":24884,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCICjLoBib8f0uCnJB+RD4qVJnta9KDOOPYWEx9ZWjT0TAAiBsMWWlk8Q5+CS2eF1Ogdsz3zC1rF/GvBvwRoZ9Ke9MPg=="}]},"_npmUser":{"name":"benskalz","email":"benskalz.npm@gmail.com"},"directories":{},"maintainers":[{"name":"benskalz","email":"benskalz.npm@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/swr-idb-cache_1.1.4_1757631869924_0.29881587184460945"},"_hasShrinkwrap":false}},"time":{"created":"2025-09-11T21:53:46.409Z","modified":"2025-09-11T23:04:30.373Z","1.1.2":"2025-09-11T21:53:46.683Z","1.1.3":"2025-09-11T22:06:42.724Z","1.1.4":"2025-09-11T23:04:30.102Z"},"bugs":{"url":"https://github.com/piotr-cz/swr-idb-cache/issues"},"author":{"name":"Piotr Konieczny","email":"hello@piotr.cz","url":"https://www.piotr.cz"},"license":"MIT","homepage":"https://github.com/piotr-cz/swr-idb-cache","keywords":["swr","cache","IndexedDB","idb"],"repository":{"type":"git","url":"git+https://github.com/piotr-cz/swr-idb-cache.git"},"description":"IndexedDB Cache Provider for SWR","maintainers":[{"name":"benskalz","email":"benskalz.npm@gmail.com"}],"readme":"# IndexedDB Cache Provider for [SWR](https://swr.vercel.app/)\r\n\r\nSynchronize SWR Cache with [IndexedDB](https://developer.mozilla.org/en-US/docs/Glossary/IndexedDB) to get offline cache.\r\n\r\nExamples of use cases include situations where you want to provide a fallback solution for fetch requests\r\nright after your app launches (when offline or with an unstable internet connection):\r\n\r\n- Progressive Web Apps\r\n- [Capacitor](https://capacitorjs.com/) Apps\r\n\r\nPlease note that the cache provider initialization process is asynchronous and until it's resolved, best practise is to render fallback component.\r\n\r\n> [!WARNING]\r\n> When passing secrets such as an API token to fetcher ([example](https://swr.vercel.app/docs/arguments)),\r\n> it will be saved in the persistent cache as a part of key generated by [stable-hash](https://github.com/shuding/stable-hash).\r\n>\r\n> To overcome this, you may use custom comparision function in SWR Config that replaces secret by it's checksum.\r\n\r\n## How does it work?\r\n\r\nLibrary reads current state of cache stored in [IndexedDB](https://developer.mozilla.org/en-US/docs/Glossary/IndexedDB) into memory using [idb](https://github.com/jakearchibald/idb) during it's initialization.\r\nThen it resolves into Cache Provider which should be passed to SWR.\r\n\r\nRead SWR Docs > [Cache](https://swr.vercel.app/docs/advanced/cache) if your are interested in more information about implementation details.\r\n\r\n\r\n## Installation\r\n\r\nUsing npm:\r\n\r\n```console\r\nnpm install --save @piotr-cz/swr-idb-cache\r\n```\r\n\r\nor Yarn:\r\n\r\n```console\r\nyarn add @piotr-cz/swr-idb-cache\r\n\r\n```\r\n\r\n\r\n## Requirements\r\n\r\n- [SWR](https://swr.vercel.app/) ^2.0.0  \r\n  *Note: For SWR 1.x use the 1.0.0-rc.2 version of this package*\r\n- Works with [React](https://reactjs.org/) ^16.11 and [Preact](https://preactjs.com/)\r\n\r\n## Setup\r\n\r\nInitialize library and when it's ready, pass it in configuration under `provider` key to SWR.\r\n\r\nTo wait until provider is resolved, use bundled `useCacheProvider` hook:\r\n\r\n```jsx\r\n// App.jsx\r\nimport { SWRConfig } from 'swr'\r\nimport { useCacheProvider } from '@piotr-cz/swr-idb-cache'\r\n\r\nfunction App() {\r\n  // Initialize\r\n  const cacheProvider = useCacheProvider({\r\n    dbName: 'my-app',\r\n    storeName: 'swr-cache',\r\n  })\r\n\r\n  // Cache Provider is being initialized - render fallback component in the meantime\r\n  if (!cacheProvider) {\r\n    return <div>Initializing cache…</div>\r\n  }\r\n\r\n  return (\r\n    <SWRConfig value={{\r\n      provider: cacheProvider,\r\n    }}>\r\n      <Dashboard />\r\n    </SWRConfig>\r\n  )\r\n}\r\n```\r\n\r\n…or library like [react-use-promise](https://github.com/bsonntag/react-use-promise):\r\n\r\n```js\r\nimport createCacheProvider from '@piotr-cz/swr-idb-cache'\r\nimport usePromise from 'react-use-promise'\r\n\r\nfunction App() {\r\n  // Initialize\r\n  const [ cacheProvider ] = usePromise(() => createCacheProvider({\r\n    dbName: 'my-app',\r\n    storeName: 'swr-cache',\r\n  }), [])\r\n\r\n  // …\r\n}\r\n\r\n```\r\n\r\n\r\n## Configuration\r\n\r\n- `dbName`: IndexedDB Database name\r\n- `storeName`: IndexedDB Store name\r\n- `storageHandler` (optional): Custom Storage handler, see [IStorageHandler interface](./src/types.ts#L31)\r\n- `version` (optional): Schema version, defaults to `1`\r\n- `onError` (optional): Database error handler, defaults to noop function\r\n\r\nNote: When using `useCacheProvider`, changing options doesn't create new cache provider.\r\n\r\n## Known issues\r\n\r\n\r\n### InvalidStateError\r\n\r\n```\r\nInvalidStateError\r\nFailed to execute 'transaction' on 'IDBDatabase': The database connection is closing.\r\n```\r\n\r\nSee idb [Issue #229](https://github.com/jakearchibald/idb/issues/229)\r\n\r\n\r\n## Recipes\r\n\r\n\r\n### Delete cache entry\r\n\r\n```jsx\r\nimport useSWR, { useSWRConfig } from 'swr'\r\n\r\nexport default function Item() {\r\n  const { data, error } = useSWR('/api/data')\r\n  const { cache } = useSWRConfig()\r\n\r\n  const handleRemove = () => {\r\n    // Remove from state\r\n    // …\r\n\r\n    // Remove from cache with key used in useSWR hook\r\n    cache.delete('/api/data')\r\n  }\r\n\r\n  return (\r\n    <main>\r\n      {/** Show item */}\r\n      {data &&\r\n        <h1>{data.label}</h1>\r\n      }\r\n\r\n      {/** Remove item */}\r\n      <button onClick={handleRemove}>\r\n        Remove\r\n      </button>\r\n    </main>\r\n  )\r\n}\r\n```\r\n\r\n\r\n### Implement Garbage Collector\r\n\r\nDefine custom storage handler that extends timestamp storage\r\n\r\n```js\r\n// custom-storage-handler.js\r\nimport { timestampStorageHandler } from '@piotr-cz/swr-idb-cache'\r\n\r\n// Define max age of 7 days\r\nconst maxAge = 7 * 24 * 60 * 60 * 1e3\r\n\r\nconst gcStorageHandler = {\r\n  ...timestampStorageHandler,\r\n  // Revive each entry only when it's timestamp is newer than expiration\r\n  revive: (key, storeObject) => \r\n    storeObject.ts > Date.now() - maxAge\r\n      // Unwrapped value\r\n      ? timestampStorageHandler.revive(key, storeObject)\r\n      // Undefined to indicate item is stale\r\n      : undefined,\r\n}\r\n\r\nexport default gcStorageHandler\r\n```\r\n\r\nPass it to configuration\r\n\r\n```diff\r\n // App.jsx\r\n import { SWRConfig } from 'swr'\r\n import { useCacheProvider } from '@piotr-cz/swr-idb-cache'\r\n\r\n+import customStorageHandler from './custom-storage-handler.js'\r\n+\r\n function App() {\r\n   // Initialize\r\n   const cacheProvider = useCacheProvider({\r\n     dbName: 'my-app',\r\n     storeName: 'swr-cache',\r\n+    storageHandler: customStorageHandler,\r\n   })\r\n\r\n   // …\r\n```\r\n\r\n\r\n### Ignore API endpoints from cache persistence\r\n\r\nDefine custom storage handler that extends timestamp storage\r\n\r\n```js\r\n// custom-storage-handler.js\r\nimport { timestampStorageHandler } from '@piotr-cz/swr-idb-cache'\r\n\r\nconst blacklistStorageHandler = {\r\n  ...timestampStorageHandler,\r\n  // Ignore entries fetched from API endpoints starting with /api/device\r\n  replace: (key, value) =>\r\n    !key.startsWith('/api/device/')\r\n      // Wrapped value\r\n      ? timestampStorageHandler.replace(key, value)\r\n      // Undefined to ignore storing value\r\n      : undefined,\r\n}\r\n\r\nexport default blacklistStorageHandler\r\n```\r\n\r\nPass it in configuration as in the [recipe above](#implement-garbage-collector)\r\n\r\n### Mocking package in tests\r\n\r\n- Use mock IndexedDB\r\n\r\n  ```shell\r\n  npm install --save-dev fake-indexeddb\r\n  ```\r\n\r\n  ```ts\r\n  // src/setupTests.ts\r\n  import 'fake-indexeddb/auto'\r\n  ```\r\n\r\n  or\r\n\r\n- Add mock cache provider with [vitest](https://vitest.dev/)\r\n\r\n  ```ts\r\n  // src/App.test.tsx\r\n  type SWRIdbCacheExports = typeof import('@piotr-cz/swr-idb-cache')\r\n\r\n  vi.mock('@piotr-cz/swr-idb-cache', async (importOriginal): Promise<SWRIdbCacheExports> => {\r\n    const mod = await importOriginal<SWRIdbCacheExports>()\r\n\r\n    return {\r\n      ...mod,\r\n      useCacheProvider: () => () => new Map(),\r\n    }\r\n  })\r\n  ```\r\n\r\n## Related packages\r\n\r\n- [`@instructure/idb-cache`](https://github.com/instructure/idb-cache)\r\n","readmeFilename":"README.md"}