{"id":15041087,"url":"https://github.com/azu/kvs","last_synced_at":"2026-01-18T09:01:38.437Z","repository":{"id":43414722,"uuid":"285625240","full_name":"azu/kvs","owner":"azu","description":"Lightweight key-value storage library for Browser, Node.js, and In-Memory.","archived":false,"fork":false,"pushed_at":"2024-01-26T22:10:09.000Z","size":2226,"stargazers_count":183,"open_issues_count":2,"forks_count":6,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-10-30T05:57:36.729Z","etag":null,"topics":["browser","db","indexeddb","javascript","kvs","memory","node","webworker"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/azu.png","metadata":{"funding":{"github":"azu"},"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-08-06T16:58:42.000Z","updated_at":"2024-10-24T20:11:37.000Z","dependencies_parsed_at":"2024-06-18T15:52:13.356Z","dependency_job_id":null,"html_url":"https://github.com/azu/kvs","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/azu%2Fkvs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/azu%2Fkvs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/azu%2Fkvs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/azu%2Fkvs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/azu","download_url":"https://codeload.github.com/azu/kvs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247242679,"owners_count":20907134,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["browser","db","indexeddb","javascript","kvs","memory","node","webworker"],"created_at":"2024-09-24T20:45:31.590Z","updated_at":"2026-01-18T09:01:38.399Z","avatar_url":"https://github.com/azu.png","language":"TypeScript","readme":"# KVS [![Actions Status: test](https://github.com/azu/kvs/workflows/test/badge.svg)](https://github.com/azu/kvs/actions?query=workflow%3A\"test\")\n\nKey Value storage for Browser, Node.js, and In-Memory.\n\nIt is a monorepo for key-value storage.\n\n## Motivation\n\nI want to get universal storage library that works on Browser and Node.js.\n\nPreviously, I've created [localstorage-ponyfill](https://github.com/azu/localstorage-ponyfill) for this purpose.\nHowever, [Window.localStorage](https://developer.mozilla.org/docs/Web/API/Window/localStorage) does not work on [Web Workers](https://developer.mozilla.org/docs/Web/API/Web_Workers_API) or [Service Worker](https://developer.mozilla.org/docs/Web/API/Service_Worker_API)\n\n`@kvs/*` packages provide async storage API using [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) etc and resolve this issue.\n\n## Common Features\n\nKVS libraries provide following common features.\n\n- Key-Value Storage\n- Async Read, and Write API\n    - provide `get`, `set`, `has`, `delete`, and `clear` API\n- Migration API\n    - Upgrade storage data via `version` and `upgrade` method\n- Tiny packages\n    - Almost package size is **1kb**(gzip)\n- TypeScript\n    - All packages are written by TypeScript\n\n## Support Browsers\n\n- A browser that support [AsyncIterator](https://caniuse.com/#feat=mdn-javascript_builtins_symbol_asynciterator)\n    - It requires ES2018+ supports\n- Chromium-based(Google Chrome and MSEdge), Firefox, and macOS Safari\n\n## Packages\n\n- Universal\n    - [@kvs/env](./packages/env): Use suitable storage for platform\n        - Use IndexedDB for Browser, and Use node-localstorage for Node.js\n- Browser\n    - [@kvs/indexeddb](./packages/indexeddb): Use [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API)\n        - For WebWorker and ServiceWorker\n    - [@kvs/localstorage](./packages/localstorage): Use [localStorage](https://developer.mozilla.org/docs/Web/API/Window/localStorage)\n        - For Browser\n- Node.js\n    - [@kvs/node-localstorage](./packages/node-localstorage): Use [node-localstorage](https://github.com/lmaccherone/node-localstorage)\n        - For Node.js\n- In-Memory\n    - [@kvs/memorystorage](./packages/memorystorage): In-Memory Storage\n        - For debugging and testing\n- Sync Version\n    - [@kvs/storage-sync](./packages/storage-sync): Sync version of [@kvs/localstorage](./packages/localstorage)\n\nIf you want to custom implementation, please see [@kvs/storage](./packages/storage) and test it with [@kvs/common-test-case](./packages/common-test-case).\n\n## Usage\n\n[@kvs/env](./packages/env) support Browser and Node.js.\nIn fact, browser use [@kvs/indexeddb](./packages/indexeddb) and Node.js use [@kvs/node-localstorage](./packages/node-localstorage).\n\n```js\nimport { KVSIndexedDB, kvsIndexedDB } from \"@kvs/env\";\n(async () =\u003e {\n    const storage = await kvsEnvStorage({\n        name: \"database-name\",\n        version: 1\n    });\n    await storage.set(\"a1\", \"string\"); \n    const a1 = await storage.get(\"a1\");\n    console.log(a1); // =\u003e \"string\"\n})();\n```\n\n### API\n\n[@kvs/types](./packages/types) define common interface.\n\nEach constructor function like `kvsEnvStorage` return `KVS` object that has following methods.\nAlso, `KVS` object define [Symbol.asyncIterator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/asyncIterator), and you can iterate the storage by [for await...of](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of).\n\n```ts\nexport type KVS\u003cSchema extends StorageSchema\u003e = {\n    /**\n     * Returns the value associated to the key.\n     * If the key does not exist, returns `undefined`.\n     */\n    get\u003cK extends StoreNames\u003cSchema\u003e\u003e(key: K): Promise\u003cStoreValue\u003cSchema, K\u003e | undefined\u003e;\n    /**\n     * Sets the value for the key in the storage. Returns the storage.\n     */\n    set\u003cK extends StoreNames\u003cSchema\u003e\u003e(key: K, value: StoreValue\u003cSchema, K\u003e | undefined): Promise\u003cKVS\u003cSchema\u003e\u003e;\n    /**\n     * Returns a boolean asserting whether a value has been associated to the key in the storage.\n     */\n    has(key: StoreNames\u003cSchema\u003e): Promise\u003cboolean\u003e;\n    /**\n     * Returns true if an key in the storage existed and has been removed.\n     * Returns false if the key does not exist.\n     */\n    delete(key: StoreNames\u003cSchema\u003e): Promise\u003cboolean\u003e;\n    /**\n     * Removes all key-value pairs from the storage.\n     * Note: clear method does not delete the storage.\n     * In other words, after clear(), the storage still has internal metadata like version.\n     */\n    clear(): Promise\u003cvoid\u003e;\n    /**\n     * Drop the storage.\n     * It delete all data that includes metadata completely.\n     */\n    dropInstance(): Promise\u003cvoid\u003e;\n    /*\n     * Close the KVS connection\n     * DB-like KVS close the connection via this method\n     * Of course, localStorage-like KVS implement do nothing. It is just noop function\n     */\n    close(): Promise\u003cvoid\u003e;\n} \u0026 AsyncIterable\u003c[StoreNames\u003cSchema\u003e, StoreValue\u003cSchema, StoreNames\u003cSchema\u003e\u003e]\u003e;\n```\n\n### Basic Usage\n\n```ts\nimport assert from \"assert\";\nimport { kvsEnvStorage } from \"@kvs/env\";\n(async () =\u003e {\n    type StorageSchema = {\n        a1: string;\n        b2: number;\n        c3: boolean;\n    };\n    // open database and initialize it\n    const storage = await kvsEnvStorage\u003cStorageSchema\u003e({\n        name: \"database-name\",\n        version: 1\n    });\n    // set\n    await storage.set(\"a1\", \"string\"); // type check\n    await storage.set(\"b2\", 42);\n    await storage.set(\"c3\", false);\n    // has\n    console.log(await storage.has(\"a1\")); // =\u003e true\n    // get\n    const a1 = await storage.get(\"a1\"); // a1 will be string type\n    const b2 = await storage.get(\"b2\");\n    const c3 = await storage.get(\"c3\");\n    assert.strictEqual(a1, \"string\");\n    assert.strictEqual(b2, 42);\n    assert.strictEqual(c3, false);\n    // iterate\n    for await (const [key, value] of storage) {\n        console.log([key, value]);\n    }\n    // delete\n    await storage.delete(\"a1\");\n    // clear all data\n    await storage.clear();\n})();\n```\n\n\n### Migration\n\nKVS support migration feature.\nYou can define `upgrade` and use it as migration function. \n\n```ts\nimport { kvsEnvStorage } from \"@kvs/env\";\n(async () =\u003e {\n    // Defaut version: 1 \n    // when update version 1 → 2, call upgrace function\n    const storage = await kvsEnvStorage({\n        name: \"database-name\",\n        version: 2,\n        async upgrade({ kvs, oldVersion }) {\n            if (oldVersion \u003c 2) {\n                await kvs.set(\"v1\", \"v1-migrated-value\"); // modify storage as migration\n            }\n            return;\n        }\n    });\n    assert.strictEqual(await storage.get(\"v1\"), \"v1-migrated-value\");\n})();\n```\n\n### First Initializing\n\nWhen open database at first time, this library also call `upgrade` function with `{ oldVersion: 0, newVersion: 1 }`.\nSo, You can implement `0` to `1` migration as initializing database.\n\n```ts\nimport { KVSIndexedDB, kvsIndexedDB } from \"@kvs/env\";\n(async () =\u003e {\n    const storage = await kvsEnvStorage({\n        name: \"database-name\",\n        version: 1,\n        async upgrade({ kvs, oldVersion, newVersion }) {\n            console.log(oldVersion); // =\u003e 0\n            console.log(newVersion); // =\u003e 1\n        }\n    });\n})();\n```\n\n### TypeScript\n\nKVS packages support `Schema` type.\nIt helps you to define a schema of the storage. \n\n```ts\nimport { KVSIndexedDB, kvsIndexedDB } from \"@kvs/env\";\n(async () =\u003e {\n    type StorageSchema = {\n        a1: string;\n        b2: number;\n        c3: boolean;\n    };\n    const storage = await kvsEnvStorage\u003cStorageSchema\u003e({\n        name: \"database-name\",\n        version: 1\n    });\n    await storage.set(\"a1\", \"string\"); // type check\n    await storage.set(\"b2\", 42);\n    await storage.set(\"c3\", false);\n    const a1 = await storage.get(\"a1\"); // a1 will be string type\n    const b2 = await storage.get(\"b2\");\n    const c3 = await storage.get(\"c3\");\n    assert.strictEqual(a1, \"string\");\n    assert.strictEqual(b2, 42);\n    assert.strictEqual(c3, false);\n})();\n```\n\n### Tips: Initial Data\n\nYou can also set up initial data using `upgrade` function.\nThis approach help you to improve `Scheme` typing.\n\n```ts\n(async () =\u003e {\n    type UnixTimeStamp = number;\n    type Scheme = {\n        timeStamp: UnixTimeStamp\n    };\n    const storage = await kvsEnvStorage\u003cScheme\u003e({\n        name: \"test-data\",\n        version: 1,\n        async upgrade({ kvs, oldVersion, newVersion }) {\n            // Initialize data\n            // oldVersion is 0 and newVersion is 1 at first time\n            if (oldVersion \u003c 1) {\n                await kvs.set(\"timeStamp\", Date.now());\n            }\n        }\n    });\n    const timeStamp = await storage.get(\"timeStamp\");\n    console.log(timeStamp); // =\u003e timestamp\n})()\n```\n\n## Related\n\n- [azu/localstorage-ponyfill](https://github.com/azu/localstorage-ponyfill)\n    - It provides storage API based on localStorage API\n- [KV Storage](https://github.com/WICG/kv-storage)\n    - This proposal aims to create \"async local storage\", but it is suspended\n    - @kvs project aims to be similar one\n- [localForage](https://github.com/localForage/localForage)\n    - It has same concept and similar API.\n    - However, [localForage](https://github.com/localForage/localForage) size is large `~8.8kB`(gzipped)\n- [Unstorage](https://github.com/unjs/unstorage)\n    - Unstorage has various cloud storage support\n    - However, Unstorage API is too rich for me\n    - IndexedDB is not supported yet - Issue: https://github.com/unjs/unstorage/issues/10\n- [idb](https://github.com/jakearchibald/idb)\n    - @kvs type interface inspired by idb\n    - If you want to use only IndexedDB directly, I recommend to use idb\n    - It has low level API for IndexedDB\n\n## Changelog\n\nSee [Releases page](https://github.com/azu/kv/releases).\n\n## Development\n\nThis repository use [Yarn](https://classic.yarnpkg.com/).\nYou need to build before editing each packages.\n\n    # install and link\n    yarn install\n    # build all package\n    yarn run build\n\n## Running tests\n\nRunning test via `yarn test` command.\n\n\n    yarn test\n\n## Contributing\n\nPull requests and stars are always welcome.\n\nFor bugs and feature requests, [please create an issue](https://github.com/azu/kv/issues).\n\n1. Fork it!\n2. Create your feature branch: `git checkout -b my-new-feature`\n3. Commit your changes: `git commit -am 'Add some feature'`\n4. Push to the branch: `git push origin my-new-feature`\n5. Submit a pull request :D\n\n## Author\n\n- [github/azu](https://github.com/azu)\n- [twitter/azu_re](https://twitter.com/azu_re)\n\n## License\n\nMIT © azu\n","funding_links":["https://github.com/sponsors/azu"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fazu%2Fkvs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fazu%2Fkvs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fazu%2Fkvs/lists"}