From 320548ed1c388d39308ac4b30369e1062fecb748 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 14 Mar 2024 12:54:41 +0100 Subject: [PATCH 1/4] fix(pkg): make `ioredis` dependency optional (#410) --- docs/2.drivers/redis.md | 6 ++++++ package.json | 8 ++++++-- pnpm-lock.yaml | 19 ++++++++++++++++--- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/docs/2.drivers/redis.md b/docs/2.drivers/redis.md index 42cbf126..0ded181b 100644 --- a/docs/2.drivers/redis.md +++ b/docs/2.drivers/redis.md @@ -16,6 +16,12 @@ Learn more about Redis. Unstorage uses [`ioredis`](https://github.com/luin/ioredis) internally to connect to Redis. :: +To use it, you will need to install `ioredis` in your project: + +```bash [Terminal] +npm i ioredis +``` + Usage with single Redis instance: ```js diff --git a/package.json b/package.json index 68e06a7d..57c13f97 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,6 @@ "chokidar": "^3.6.0", "destr": "^2.0.3", "h3": "^1.11.1", - "ioredis": "^5.3.2", "listhen": "^1.7.2", "lru-cache": "^10.2.0", "mri": "^1.2.0", @@ -80,6 +79,7 @@ "eslint-config-unjs": "^0.2.1", "fake-indexeddb": "^5.0.2", "idb-keyval": "^6.2.1", + "ioredis": "^5.3.2", "ioredis-mock": "^8.9.0", "jiti": "^1.21.0", "jsdom": "^24.0.0", @@ -107,7 +107,8 @@ "@planetscale/database": "^1.16.0", "@upstash/redis": "^1.28.4", "@vercel/kv": "^0.2.4", - "idb-keyval": "^6.2.1" + "idb-keyval": "^6.2.1", + "ioredis": "^5.3.2" }, "peerDependenciesMeta": { "@azure/app-configuration": { @@ -145,6 +146,9 @@ }, "idb-keyval": { "optional": true + }, + "ioredis": { + "optional": true } }, "packageManager": "pnpm@8.15.4" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ac572b0c..34749b75 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,9 +17,6 @@ dependencies: h3: specifier: ^1.11.1 version: 1.11.1 - ioredis: - specifier: ^5.3.2 - version: 5.3.2 listhen: specifier: ^1.7.2 version: 1.7.2 @@ -112,6 +109,9 @@ devDependencies: idb-keyval: specifier: ^6.2.1 version: 6.2.1 + ioredis: + specifier: ^5.3.2 + version: 5.3.2 ioredis-mock: specifier: ^8.9.0 version: 8.9.0(@types/ioredis-mock@8.2.5)(ioredis@5.3.2) @@ -1005,6 +1005,7 @@ packages: /@ioredis/commands@1.2.0: resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==} + dev: true /@istanbuljs/schema@0.1.3: resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} @@ -2572,6 +2573,7 @@ packages: /cluster-key-slot@1.1.2: resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} engines: {node: '>=0.10.0'} + dev: true /color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} @@ -2876,6 +2878,7 @@ packages: optional: true dependencies: ms: 2.1.2 + dev: true /decimal.js@10.4.3: resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} @@ -2960,6 +2963,7 @@ packages: /denque@2.1.0: resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} engines: {node: '>=0.10'} + dev: true /depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} @@ -4419,6 +4423,7 @@ packages: standard-as-callback: 2.1.0 transitivePeerDependencies: - supports-color + dev: true /ip-address@9.0.5: resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} @@ -4977,6 +4982,7 @@ packages: /lodash.defaults@4.2.0: resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + dev: true /lodash.includes@4.3.0: resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} @@ -4984,6 +4990,7 @@ packages: /lodash.isarguments@3.1.0: resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} + dev: true /lodash.isboolean@3.0.3: resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} @@ -5131,6 +5138,7 @@ packages: /memory-pager@1.5.0: resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==} + requiresBuild: true dev: true /merge-descriptors@1.0.1: @@ -5431,6 +5439,7 @@ packages: /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: true /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -6415,12 +6424,14 @@ packages: /redis-errors@1.2.0: resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} engines: {node: '>=4'} + dev: true /redis-parser@3.0.0: resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} engines: {node: '>=4'} dependencies: redis-errors: 1.2.0 + dev: true /regexp-tree@0.1.27: resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} @@ -6853,6 +6864,7 @@ packages: /sparse-bitfield@3.0.3: resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==} + requiresBuild: true dependencies: memory-pager: 1.5.0 dev: true @@ -6898,6 +6910,7 @@ packages: /standard-as-callback@2.1.0: resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} + dev: true /statuses@2.0.1: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} From aaa56eb382d2640b8a3ea3900881ab2c63d821ad Mon Sep 17 00:00:00 2001 From: kongmoumou <35442047+kongmoumou@users.noreply.github.com> Date: Thu, 14 Mar 2024 19:55:02 +0800 Subject: [PATCH 2/4] docs: update link (#408) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 36f2cfaf..a54f55e6 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Unstorage provides an async Key-Value storage API with conventional features lik - Binary and raw value support - State [snapshots](https://unstorage.unjs.io/getting-started/utils#snapshots) and hydration - Storage watcher -- HTTP Storage with [built-in server](https://unstorage.unjs.io/getting-started/http-server) +- HTTP Storage with [built-in server](https://unstorage.unjs.io/guide/http-server) ## Usage From d8316dc4ab75a54fccf1e9511b103a93d75db803 Mon Sep 17 00:00:00 2001 From: Connor Pearson Date: Thu, 14 Mar 2024 12:56:12 +0100 Subject: [PATCH 3/4] fix(vercel-kv): add missing driver name (#355) --- src/drivers/vercel-kv.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/drivers/vercel-kv.ts b/src/drivers/vercel-kv.ts index 984eb5c8..e18a9bd0 100644 --- a/src/drivers/vercel-kv.ts +++ b/src/drivers/vercel-kv.ts @@ -21,6 +21,8 @@ export interface VercelKVOptions extends Partial { ttl?: number; } +const DRIVER_NAME = "vercel-kv"; + export default defineDriver((opts) => { const base = normalizeKey(opts?.base); const r = (...keys: string[]) => joinKeys(base, ...keys); @@ -60,6 +62,7 @@ export default defineDriver((opts) => { }; return { + name: DRIVER_NAME, hasItem(key) { return getClient().exists(r(key)).then(Boolean); }, From 85bdbb74e73b53bfcfdd6dd747b4015e8dc23cfd Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 14 Mar 2024 12:59:39 +0100 Subject: [PATCH 4/4] fix(setItems): call driver native `setItems` only to avoid duplicate write (#392) --- src/storage.ts | 2 +- test/storage.test.ts | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/storage.ts b/src/storage.ts index d53c755d..fe435525 100644 --- a/src/storage.ts +++ b/src/storage.ts @@ -231,7 +231,7 @@ export function createStorage( async setItems(items, commonOptions) { await runBatch(items, commonOptions, async (batch) => { if (batch.driver.setItems) { - await asyncCall( + return asyncCall( batch.driver.setItems, batch.items.map((item) => ({ key: item.relativeKey, diff --git a/test/storage.test.ts b/test/storage.test.ts index aac85e67..5249da7d 100644 --- a/test/storage.test.ts +++ b/test/storage.test.ts @@ -160,3 +160,33 @@ describe("utils", () => { expect(async () => await storage.setItem("foo", [])).not.toThrow(); }); }); + +describe("Regression", () => { + it("setItems doeesn't upload twice", async () => { + /** + * https://github.com/unjs/unstorage/pull/392 + */ + + const setItem = vi.fn(); + const setItems = vi.fn(); + + const driver = memory(); + const storage = createStorage({ + driver: { + ...driver, + setItem: (...args) => { + setItem(...args); + return driver.setItem?.(...args); + }, + setItems: (...args) => { + setItems(...args); + return driver.setItems?.(...args); + }, + }, + }); + + await storage.setItems([{ key: "foo.txt", value: "bar" }]); + expect(setItem).toHaveBeenCalledTimes(0); + expect(setItems).toHaveBeenCalledTimes(1); + }); +});