@keyv/redis 5.1.0 → 5.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -38,6 +38,7 @@ Redis storage adapter for [Keyv](https://github.com/jaredwray/keyv).
38
38
  * [Clustering](#clustering)
39
39
  * [Sentinel](#sentinel)
40
40
  * [TLS Support](#tls-support)
41
+ * [Keyv Redis Options](#keyv-redis-options)
41
42
  * [API](#api)
42
43
  * [Using Custom Redis Client Events](#using-custom-redis-client-events)
43
44
  * [Migrating from v3 to v4](#migrating-from-v3-to-v4)
@@ -79,21 +80,20 @@ Here you can pass in the Redis options directly:
79
80
  import Keyv from 'keyv';
80
81
  import KeyvRedis from '@keyv/redis';
81
82
 
82
- const redisOptions = {
83
- url: 'redis://localhost:6379', // The Redis server URL (use 'rediss' for TLS)
84
- password: 'your_password', // Optional password if Redis has authentication enabled
83
+ const uri = "redis://localhost:6379";
85
84
 
86
- socket: {
87
- host: 'localhost', // Hostname of the Redis server
88
- port: 6379, // Port number
89
- reconnectStrategy: (retries) => Math.min(retries * 50, 2000), // Custom reconnect logic
90
-
91
- tls: false, // Enable TLS if you need to connect over SSL
92
- keepAlive: 30000, // Keep-alive timeout (in milliseconds)
93
- }
85
+ // NOTE: please use the settings that you need to configure. Check out Keyv Redis Options section
86
+ const options = {
87
+ namespace: "test",
88
+ keyPrefixSeparator: "->",
89
+ clearBatchSize: 100,
90
+ useUnlink: true,
91
+ noNamespaceAffectsAll: true,
94
92
  };
95
93
 
96
- const keyv = new Keyv(new KeyvRedis(redisOptions));
94
+ const keyvRedis = new KeyvRedis(uri, options);
95
+
96
+ const keyv = new Keyv(keyvRedis);
97
97
  ```
98
98
 
99
99
  Or you can create a new Redis instance and pass it in with `KeyvOptions` such as setting the `store`:
@@ -465,6 +465,60 @@ const tlsOptions = {
465
465
  const keyv = new Keyv({ store: new KeyvRedis(tlsOptions) });
466
466
  ```
467
467
 
468
+ # Keyv Redis Options
469
+
470
+ Here are all the options that you can set on the constructor
471
+
472
+ ```ts
473
+ export type KeyvRedisOptions = {
474
+ /**
475
+ * Namespace for the current instance.
476
+ */
477
+ namespace?: string;
478
+ /**
479
+ * Separator to use between namespace and key.
480
+ */
481
+ keyPrefixSeparator?: string;
482
+ /**
483
+ * Number of keys to delete in a single batch.
484
+ */
485
+ clearBatchSize?: number;
486
+ /**
487
+ * Enable Unlink instead of using Del for clearing keys. This is more performant but may not be supported by all Redis versions.
488
+ */
489
+ useUnlink?: boolean;
490
+
491
+ /**
492
+ * Whether to allow clearing all keys when no namespace is set.
493
+ * If set to true and no namespace is set, iterate() will return all keys.
494
+ * Defaults to `false`.
495
+ */
496
+ noNamespaceAffectsAll?: boolean;
497
+
498
+ /**
499
+ * This is used to throw an error if the client is not connected when trying to connect. By default, this is
500
+ * set to true so that it throws an error when trying to connect to the Redis server fails.
501
+ */
502
+ throwOnConnectError?: boolean;
503
+
504
+ /**
505
+ * This is used to throw an error if at any point there is a failure. Use this if you want to
506
+ * ensure that all operations are successful and you want to handle errors. By default, this is
507
+ * set to false so that it does not throw an error on every operation and instead emits an error event
508
+ * and returns no-op responses.
509
+ * @default false
510
+ */
511
+ throwOnErrors?: boolean;
512
+
513
+ /**
514
+ * Timeout in milliseconds for the connection. Default is undefined, which uses the default timeout of the Redis client.
515
+ * If set, it will throw an error if the connection does not succeed within the specified time.
516
+ * @default undefined
517
+ */
518
+ connectionTimeout?: number;
519
+ };
520
+ ```
521
+
468
522
  # API
469
523
  * **constructor([connection], [options])**
470
524
  * **namespace** - The namespace to use for the keys.
@@ -530,14 +584,10 @@ const keyv = new Keyv({ store: redis, namespace: 'my-namespace', useKeyPrefix: f
530
584
 
531
585
  This will make it so the storage adapter `@keyv/redis` will handle the namespace and not the `keyv` instance. If you leave it on it will just look duplicated like `my-namespace:my-namespace:key`.
532
586
 
533
-
534
-
535
587
  # About Redis Sets and its Support in v4
536
588
 
537
589
  We no longer support redis sets. This is due to the fact that it caused significant performance issues and was not a good fit for the library.
538
590
 
539
-
540
-
541
591
  # Using with NestJS
542
592
 
543
593
  > You can integrate `@keyv/redis` with NestJS by creating a custom `CacheModule`. This allows you to use Keyv as a cache store in your application.
package/dist/index.cjs CHANGED
@@ -42,9 +42,9 @@ __export(index_exports, {
42
42
  });
43
43
  module.exports = __toCommonJS(index_exports);
44
44
  var import_client = require("@redis/client");
45
+ var import_cluster_key_slot = __toESM(require("cluster-key-slot"), 1);
45
46
  var import_hookified = require("hookified");
46
47
  var import_keyv = require("keyv");
47
- var import_cluster_key_slot = __toESM(require("cluster-key-slot"), 1);
48
48
  var import_client2 = require("@redis/client");
49
49
  var import_keyv2 = require("keyv");
50
50
  var RedisErrorMessages = /* @__PURE__ */ ((RedisErrorMessages2) => {
@@ -79,7 +79,10 @@ var KeyvRedis = class extends import_hookified.Hookified {
79
79
  };
80
80
  if (connect) {
81
81
  if (typeof connect === "string") {
82
- this._client = (0, import_client.createClient)({ url: connect, socket });
82
+ this._client = (0, import_client.createClient)({
83
+ url: connect,
84
+ socket
85
+ });
83
86
  } else if (connect.connect !== void 0) {
84
87
  if (this.isClientSentinel(connect)) {
85
88
  this._client = connect;
@@ -90,9 +93,13 @@ var KeyvRedis = class extends import_hookified.Hookified {
90
93
  }
91
94
  } else if (connect instanceof Object) {
92
95
  if (connect.sentinelRootNodes !== void 0) {
93
- this._client = (0, import_client.createSentinel)(connect);
96
+ this._client = (0, import_client.createSentinel)(
97
+ connect
98
+ );
94
99
  } else if (connect.rootNodes === void 0) {
95
- this._client = (0, import_client.createClient)(connect);
100
+ this._client = (0, import_client.createClient)(
101
+ connect
102
+ );
96
103
  } else {
97
104
  this._client = (0, import_client.createCluster)(connect);
98
105
  }
@@ -373,7 +380,9 @@ var KeyvRedis = class extends import_hookified.Hookified {
373
380
  multi.exists(prefixedKey);
374
381
  }
375
382
  const results = await multi.exec();
376
- return results.map((result) => typeof result === "number" && result === 1);
383
+ return results.map(
384
+ (result) => typeof result === "number" && result === 1
385
+ );
377
386
  } catch (error) {
378
387
  this.emit("error", error);
379
388
  if (this._throwOnErrors) {
@@ -534,7 +543,9 @@ var KeyvRedis = class extends import_hookified.Hookified {
534
543
  async getMasterNodes() {
535
544
  if (this.isCluster()) {
536
545
  const cluster = await this.getClient();
537
- const nodes = cluster.masters.map(async (main) => cluster.nodeClient(main));
546
+ const nodes = cluster.masters.map(
547
+ async (main) => cluster.nodeClient(main)
548
+ );
538
549
  return Promise.all(nodes);
539
550
  }
540
551
  return [await this.getClient()];
@@ -550,7 +561,10 @@ var KeyvRedis = class extends import_hookified.Hookified {
550
561
  const match = namespace ? `${namespace}${this._keyPrefixSeparator}*` : "*";
551
562
  let cursor = "0";
552
563
  do {
553
- const result = await client.scan(cursor, { MATCH: match, TYPE: "string" });
564
+ const result = await client.scan(cursor, {
565
+ MATCH: match,
566
+ TYPE: "string"
567
+ });
554
568
  cursor = result.cursor.toString();
555
569
  let { keys } = result;
556
570
  if (!namespace && !this._noNamespaceAffectsAll) {
@@ -577,29 +591,37 @@ var KeyvRedis = class extends import_hookified.Hookified {
577
591
  async clear() {
578
592
  try {
579
593
  const clients = await this.getMasterNodes();
580
- await Promise.all(clients.map(async (client) => {
581
- if (!this._namespace && this._noNamespaceAffectsAll) {
582
- await client.flushDb();
583
- return;
584
- }
585
- let cursor = "0";
586
- const batchSize = this._clearBatchSize;
587
- const match = this._namespace ? `${this._namespace}${this._keyPrefixSeparator}*` : "*";
588
- const deletePromises = [];
589
- do {
590
- const result = await client.scan(cursor, { MATCH: match, COUNT: batchSize, TYPE: "string" });
591
- cursor = result.cursor.toString();
592
- let { keys } = result;
593
- if (keys.length === 0) {
594
- continue;
594
+ await Promise.all(
595
+ clients.map(async (client) => {
596
+ if (!this._namespace && this._noNamespaceAffectsAll) {
597
+ await client.flushDb();
598
+ return;
595
599
  }
596
- if (!this._namespace) {
597
- keys = keys.filter((key) => !key.includes(this._keyPrefixSeparator));
598
- }
599
- deletePromises.push(this.clearWithClusterSupport(keys));
600
- } while (cursor !== "0");
601
- await Promise.all(deletePromises);
602
- }));
600
+ let cursor = "0";
601
+ const batchSize = this._clearBatchSize;
602
+ const match = this._namespace ? `${this._namespace}${this._keyPrefixSeparator}*` : "*";
603
+ const deletePromises = [];
604
+ do {
605
+ const result = await client.scan(cursor, {
606
+ MATCH: match,
607
+ COUNT: batchSize,
608
+ TYPE: "string"
609
+ });
610
+ cursor = result.cursor.toString();
611
+ let { keys } = result;
612
+ if (keys.length === 0) {
613
+ continue;
614
+ }
615
+ if (!this._namespace) {
616
+ keys = keys.filter(
617
+ (key) => !key.includes(this._keyPrefixSeparator)
618
+ );
619
+ }
620
+ deletePromises.push(this.clearWithClusterSupport(keys));
621
+ } while (cursor !== "0");
622
+ await Promise.all(deletePromises);
623
+ })
624
+ );
603
625
  } catch (error) {
604
626
  this.emit("error", error);
605
627
  }
@@ -611,13 +633,15 @@ var KeyvRedis = class extends import_hookified.Hookified {
611
633
  async mget(keys) {
612
634
  const slotMap = this.getSlotMap(keys);
613
635
  const valueMap = /* @__PURE__ */ new Map();
614
- await Promise.all(Array.from(slotMap.entries(), async ([slot, keys2]) => {
615
- const client = await this.getSlotMaster(slot);
616
- const values = await client.mGet(keys2);
617
- for (const [index, value] of values.entries()) {
618
- valueMap.set(keys2[index], value ?? void 0);
619
- }
620
- }));
636
+ await Promise.all(
637
+ Array.from(slotMap.entries(), async ([slot, keys2]) => {
638
+ const client = await this.getSlotMaster(slot);
639
+ const values = await client.mGet(keys2);
640
+ for (const [index, value] of values.entries()) {
641
+ valueMap.set(keys2[index], value ?? void 0);
642
+ }
643
+ })
644
+ );
621
645
  return keys.map((key) => valueMap.get(key));
622
646
  }
623
647
  /**
@@ -627,10 +651,12 @@ var KeyvRedis = class extends import_hookified.Hookified {
627
651
  async clearWithClusterSupport(keys) {
628
652
  if (keys.length > 0) {
629
653
  const slotMap = this.getSlotMap(keys);
630
- await Promise.all(Array.from(slotMap.entries(), async ([slot, keys2]) => {
631
- const client = await this.getSlotMaster(slot);
632
- return this._useUnlink ? client.unlink(keys2) : client.del(keys2);
633
- }));
654
+ await Promise.all(
655
+ Array.from(slotMap.entries(), async ([slot, keys2]) => {
656
+ const client = await this.getSlotMaster(slot);
657
+ return this._useUnlink ? client.unlink(keys2) : client.del(keys2);
658
+ })
659
+ );
634
660
  }
635
661
  }
636
662
  /**
@@ -712,15 +738,11 @@ var KeyvRedis = class extends import_hookified.Hookified {
712
738
  });
713
739
  }
714
740
  async createTimeoutPromise(timeoutMs) {
715
- return new Promise((_, reject) => (
716
- // eslint-disable-next-line no-promise-executor-return
717
- setTimeout(
718
- () => {
719
- reject(new Error(`Redis timed out after ${timeoutMs}ms`));
720
- },
721
- timeoutMs
722
- )
723
- ));
741
+ return new Promise(
742
+ (_, reject) => setTimeout(() => {
743
+ reject(new Error(`Redis timed out after ${timeoutMs}ms`));
744
+ }, timeoutMs)
745
+ );
724
746
  }
725
747
  };
726
748
  function createKeyv(connect, options) {
@@ -728,7 +750,10 @@ function createKeyv(connect, options) {
728
750
  const adapter = new KeyvRedis(connect, options);
729
751
  if (options?.namespace) {
730
752
  adapter.namespace = options.namespace;
731
- const keyv2 = new import_keyv.Keyv(adapter, { namespace: options?.namespace, useKeyPrefix: false });
753
+ const keyv2 = new import_keyv.Keyv(adapter, {
754
+ namespace: options?.namespace,
755
+ useKeyPrefix: false
756
+ });
732
757
  if (options?.throwOnConnectError) {
733
758
  keyv2.throwOnErrors = true;
734
759
  }
package/dist/index.d.cts CHANGED
@@ -51,7 +51,7 @@ type KeyvRedisPropertyOptions = KeyvRedisOptions & {
51
51
  /**
52
52
  * Dialect used by the adapter. This is legacy so Keyv knows what is iteratable.
53
53
  */
54
- dialect: 'redis';
54
+ dialect: "redis";
55
55
  /**
56
56
  * URL used to connect to the Redis server. This is legacy so Keyv knows what is iteratable.
57
57
  */
package/dist/index.d.ts CHANGED
@@ -51,7 +51,7 @@ type KeyvRedisPropertyOptions = KeyvRedisOptions & {
51
51
  /**
52
52
  * Dialect used by the adapter. This is legacy so Keyv knows what is iteratable.
53
53
  */
54
- dialect: 'redis';
54
+ dialect: "redis";
55
55
  /**
56
56
  * URL used to connect to the Redis server. This is legacy so Keyv knows what is iteratable.
57
57
  */
package/dist/index.js CHANGED
@@ -4,17 +4,15 @@ import {
4
4
  createCluster,
5
5
  createSentinel
6
6
  } from "@redis/client";
7
+ import calculateSlot from "cluster-key-slot";
7
8
  import { Hookified } from "hookified";
8
9
  import { Keyv } from "keyv";
9
- import calculateSlot from "cluster-key-slot";
10
10
  import {
11
11
  createClient as createClient2,
12
12
  createCluster as createCluster2,
13
13
  createSentinel as createSentinel2
14
14
  } from "@redis/client";
15
- import {
16
- Keyv as Keyv2
17
- } from "keyv";
15
+ import { Keyv as Keyv2 } from "keyv";
18
16
  var RedisErrorMessages = /* @__PURE__ */ ((RedisErrorMessages2) => {
19
17
  RedisErrorMessages2["RedisClientNotConnectedThrown"] = "Redis client is not connected or has failed to connect. This is thrown because throwOnConnectError is set to true.";
20
18
  return RedisErrorMessages2;
@@ -47,7 +45,10 @@ var KeyvRedis = class extends Hookified {
47
45
  };
48
46
  if (connect) {
49
47
  if (typeof connect === "string") {
50
- this._client = createClient({ url: connect, socket });
48
+ this._client = createClient({
49
+ url: connect,
50
+ socket
51
+ });
51
52
  } else if (connect.connect !== void 0) {
52
53
  if (this.isClientSentinel(connect)) {
53
54
  this._client = connect;
@@ -58,9 +59,13 @@ var KeyvRedis = class extends Hookified {
58
59
  }
59
60
  } else if (connect instanceof Object) {
60
61
  if (connect.sentinelRootNodes !== void 0) {
61
- this._client = createSentinel(connect);
62
+ this._client = createSentinel(
63
+ connect
64
+ );
62
65
  } else if (connect.rootNodes === void 0) {
63
- this._client = createClient(connect);
66
+ this._client = createClient(
67
+ connect
68
+ );
64
69
  } else {
65
70
  this._client = createCluster(connect);
66
71
  }
@@ -341,7 +346,9 @@ var KeyvRedis = class extends Hookified {
341
346
  multi.exists(prefixedKey);
342
347
  }
343
348
  const results = await multi.exec();
344
- return results.map((result) => typeof result === "number" && result === 1);
349
+ return results.map(
350
+ (result) => typeof result === "number" && result === 1
351
+ );
345
352
  } catch (error) {
346
353
  this.emit("error", error);
347
354
  if (this._throwOnErrors) {
@@ -502,7 +509,9 @@ var KeyvRedis = class extends Hookified {
502
509
  async getMasterNodes() {
503
510
  if (this.isCluster()) {
504
511
  const cluster = await this.getClient();
505
- const nodes = cluster.masters.map(async (main) => cluster.nodeClient(main));
512
+ const nodes = cluster.masters.map(
513
+ async (main) => cluster.nodeClient(main)
514
+ );
506
515
  return Promise.all(nodes);
507
516
  }
508
517
  return [await this.getClient()];
@@ -518,7 +527,10 @@ var KeyvRedis = class extends Hookified {
518
527
  const match = namespace ? `${namespace}${this._keyPrefixSeparator}*` : "*";
519
528
  let cursor = "0";
520
529
  do {
521
- const result = await client.scan(cursor, { MATCH: match, TYPE: "string" });
530
+ const result = await client.scan(cursor, {
531
+ MATCH: match,
532
+ TYPE: "string"
533
+ });
522
534
  cursor = result.cursor.toString();
523
535
  let { keys } = result;
524
536
  if (!namespace && !this._noNamespaceAffectsAll) {
@@ -545,29 +557,37 @@ var KeyvRedis = class extends Hookified {
545
557
  async clear() {
546
558
  try {
547
559
  const clients = await this.getMasterNodes();
548
- await Promise.all(clients.map(async (client) => {
549
- if (!this._namespace && this._noNamespaceAffectsAll) {
550
- await client.flushDb();
551
- return;
552
- }
553
- let cursor = "0";
554
- const batchSize = this._clearBatchSize;
555
- const match = this._namespace ? `${this._namespace}${this._keyPrefixSeparator}*` : "*";
556
- const deletePromises = [];
557
- do {
558
- const result = await client.scan(cursor, { MATCH: match, COUNT: batchSize, TYPE: "string" });
559
- cursor = result.cursor.toString();
560
- let { keys } = result;
561
- if (keys.length === 0) {
562
- continue;
563
- }
564
- if (!this._namespace) {
565
- keys = keys.filter((key) => !key.includes(this._keyPrefixSeparator));
560
+ await Promise.all(
561
+ clients.map(async (client) => {
562
+ if (!this._namespace && this._noNamespaceAffectsAll) {
563
+ await client.flushDb();
564
+ return;
566
565
  }
567
- deletePromises.push(this.clearWithClusterSupport(keys));
568
- } while (cursor !== "0");
569
- await Promise.all(deletePromises);
570
- }));
566
+ let cursor = "0";
567
+ const batchSize = this._clearBatchSize;
568
+ const match = this._namespace ? `${this._namespace}${this._keyPrefixSeparator}*` : "*";
569
+ const deletePromises = [];
570
+ do {
571
+ const result = await client.scan(cursor, {
572
+ MATCH: match,
573
+ COUNT: batchSize,
574
+ TYPE: "string"
575
+ });
576
+ cursor = result.cursor.toString();
577
+ let { keys } = result;
578
+ if (keys.length === 0) {
579
+ continue;
580
+ }
581
+ if (!this._namespace) {
582
+ keys = keys.filter(
583
+ (key) => !key.includes(this._keyPrefixSeparator)
584
+ );
585
+ }
586
+ deletePromises.push(this.clearWithClusterSupport(keys));
587
+ } while (cursor !== "0");
588
+ await Promise.all(deletePromises);
589
+ })
590
+ );
571
591
  } catch (error) {
572
592
  this.emit("error", error);
573
593
  }
@@ -579,13 +599,15 @@ var KeyvRedis = class extends Hookified {
579
599
  async mget(keys) {
580
600
  const slotMap = this.getSlotMap(keys);
581
601
  const valueMap = /* @__PURE__ */ new Map();
582
- await Promise.all(Array.from(slotMap.entries(), async ([slot, keys2]) => {
583
- const client = await this.getSlotMaster(slot);
584
- const values = await client.mGet(keys2);
585
- for (const [index, value] of values.entries()) {
586
- valueMap.set(keys2[index], value ?? void 0);
587
- }
588
- }));
602
+ await Promise.all(
603
+ Array.from(slotMap.entries(), async ([slot, keys2]) => {
604
+ const client = await this.getSlotMaster(slot);
605
+ const values = await client.mGet(keys2);
606
+ for (const [index, value] of values.entries()) {
607
+ valueMap.set(keys2[index], value ?? void 0);
608
+ }
609
+ })
610
+ );
589
611
  return keys.map((key) => valueMap.get(key));
590
612
  }
591
613
  /**
@@ -595,10 +617,12 @@ var KeyvRedis = class extends Hookified {
595
617
  async clearWithClusterSupport(keys) {
596
618
  if (keys.length > 0) {
597
619
  const slotMap = this.getSlotMap(keys);
598
- await Promise.all(Array.from(slotMap.entries(), async ([slot, keys2]) => {
599
- const client = await this.getSlotMaster(slot);
600
- return this._useUnlink ? client.unlink(keys2) : client.del(keys2);
601
- }));
620
+ await Promise.all(
621
+ Array.from(slotMap.entries(), async ([slot, keys2]) => {
622
+ const client = await this.getSlotMaster(slot);
623
+ return this._useUnlink ? client.unlink(keys2) : client.del(keys2);
624
+ })
625
+ );
602
626
  }
603
627
  }
604
628
  /**
@@ -680,15 +704,11 @@ var KeyvRedis = class extends Hookified {
680
704
  });
681
705
  }
682
706
  async createTimeoutPromise(timeoutMs) {
683
- return new Promise((_, reject) => (
684
- // eslint-disable-next-line no-promise-executor-return
685
- setTimeout(
686
- () => {
687
- reject(new Error(`Redis timed out after ${timeoutMs}ms`));
688
- },
689
- timeoutMs
690
- )
691
- ));
707
+ return new Promise(
708
+ (_, reject) => setTimeout(() => {
709
+ reject(new Error(`Redis timed out after ${timeoutMs}ms`));
710
+ }, timeoutMs)
711
+ );
692
712
  }
693
713
  };
694
714
  function createKeyv(connect, options) {
@@ -696,7 +716,10 @@ function createKeyv(connect, options) {
696
716
  const adapter = new KeyvRedis(connect, options);
697
717
  if (options?.namespace) {
698
718
  adapter.namespace = options.namespace;
699
- const keyv2 = new Keyv(adapter, { namespace: options?.namespace, useKeyPrefix: false });
719
+ const keyv2 = new Keyv(adapter, {
720
+ namespace: options?.namespace,
721
+ useKeyPrefix: false
722
+ });
700
723
  if (options?.throwOnConnectError) {
701
724
  keyv2.throwOnErrors = true;
702
725
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keyv/redis",
3
- "version": "5.1.0",
3
+ "version": "5.1.1",
4
4
  "description": "Redis storage adapter for Keyv",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -42,14 +42,14 @@
42
42
  "keyv": "^5.5.0"
43
43
  },
44
44
  "devDependencies": {
45
+ "@biomejs/biome": "^2.2.0",
45
46
  "@faker-js/faker": "^9.9.0",
46
47
  "@vitest/coverage-v8": "^3.2.4",
47
48
  "rimraf": "^6.0.1",
48
49
  "timekeeper": "^2.3.1",
49
50
  "tsd": "^0.32.0",
50
51
  "vitest": "^3.2.4",
51
- "xo": "^1.2.1",
52
- "@keyv/test-suite": "^2.1.0"
52
+ "@keyv/test-suite": "^2.1.1"
53
53
  },
54
54
  "tsd": {
55
55
  "directory": "test"
@@ -63,8 +63,8 @@
63
63
  ],
64
64
  "scripts": {
65
65
  "build": "rimraf ./dist && tsup src/index.ts --format cjs,esm --dts --clean",
66
- "test": "xo --fix && vitest run --coverage",
67
- "test:ci": "xo && vitest --run --sequence.setupFiles=list --coverage",
66
+ "test": "biome check --write && vitest run --coverage",
67
+ "test:ci": "biome check && vitest --run --sequence.setupFiles=list --coverage",
68
68
  "clean": "rimraf ./node_modules ./coverage ./dist"
69
69
  }
70
70
  }