strapi-cache 1.8.1 → 1.8.2-rc.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
@@ -17,7 +17,7 @@ Boost your API performance with automatic in-memory or Redis caching for REST an
17
17
  - ♻️ **LRU (Least Recently Used) caching strategy**
18
18
  - 🔧 Simple integration with Strapi config
19
19
  - 📦 Lightweight with zero overhead
20
- - 🗄️ **Supports in-memory and Redis caching**
20
+ - 🗄️ **Supports in-memory, Redis and Valkey caching**
21
21
 
22
22
  ---
23
23
 
@@ -52,9 +52,9 @@ In your Strapi project, navigate to `config/plugins.js` and add the following co
52
52
  cacheableRoutes: ['/api/products', '/api/categories'], // Caches routes which start with these paths (if empty array, all '/api' routes are cached)
53
53
  // cacheableEntities: ['products', 'categories'], // (Optional) Specify which entities to cache. When set, only these entities will be cached (ignores cacheableRoutes). If not set (undefined), cacheableRoutes logic is used
54
54
  excludeRoutes: ['/api/products/private'], // (NEW) Exclude routes which start with these paths from being cached (takes precedence over cacheableRoutes). **Note:** `excludeRoutes` takes precedence over `cacheableRoutes`.
55
- provider: 'memory', // Cache provider ('memory' or 'redis')
56
- redisConfig: env('REDIS_URL', 'redis://localhost:6379'), // Redis config takes either a string or an object see https://github.com/redis/ioredis for references to what object is available, the object or string is passed directly to ioredis client (if using Redis)
57
- redisClusterNodes: [], // If provided any cluster node (this list is not empty), initialize ioredis redis cluster client. Each object must have keys 'host' and 'port'. See https://github.com/redis/ioredis for references
55
+ provider: 'memory', // Cache provider ('memory', 'redis' or 'valkey')
56
+ redisConfig: env('REDIS_URL', 'redis://localhost:6379'), // Redis/Valkey config: string or object. See https://github.com/redis/ioredis (Redis) or https://github.com/valkey-io/iovalkey (Valkey)
57
+ redisClusterNodes: [], // If provided any cluster node (this list is not empty), initialize cluster client. Each object must have keys 'host' and 'port'
58
58
  redisClusterOptions: {}, // Options for ioredis redis cluster client. redisOptions key is taken from redisConfig parameter above if not set here. See https://github.com/redis/ioredis for references
59
59
  cacheHeaders: true, // Plugin also stores response headers in the cache (set to false if you don't want to cache headers)
60
60
  cacheHeadersDenyList: ['access-control-allow-origin', 'content-encoding'], // Headers to exclude from the cache (must be lowercase, if empty array, no headers are excluded, cacheHeaders must be true)
@@ -83,8 +83,8 @@ All of these routes are protected by the policies `admin::isAuthenticatedAdmin`
83
83
 
84
84
  ## 🗂️ How It Works
85
85
 
86
- - **Storage**: The plugin keeps cached data in memory or Redis, depending on the configuration.
87
- - **Packages**: Uses [lru-cache](https://github.com/isaacs/node-lru-cache) for in-memory cache. Uses [ioredis](https://github.com/redis/ioredis) for Redis caching.
86
+ - **Storage**: The plugin keeps cached data in memory, Redis or Valkey, depending on the configuration.
87
+ - **Packages**: Uses [lru-cache](https://github.com/isaacs/node-lru-cache) for in-memory cache. Uses [ioredis](https://github.com/redis/ioredis) for Redis and [iovalkey](https://github.com/valkey-io/iovalkey) for Valkey caching.
88
88
  - **Automatic Invalidation**: Cache is cleared automatically when content is updated, deleted, or created. (GraphQL cache clears on any content update.)
89
89
  - **`no-cache` Header Support**: Respects the `no-cache` header, letting you skip the cache by setting `Cache-Control: no-cache` in your request.
90
90
  - **Default Cached Requests**: By default, caches all GET requests to `/api` (or whatever prefix you defined) and POST requests to `/graphql`. You can customize which routes or entities to cache using `cacheableRoutes` or `cacheableEntities` config options.
@@ -5,6 +5,7 @@ const zlib = require("zlib");
5
5
  const rawBody = require("raw-body");
6
6
  const lruCache = require("lru-cache");
7
7
  const ioredis = require("ioredis");
8
+ const iovalkey = require("iovalkey");
8
9
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
9
10
  const Stream__default = /* @__PURE__ */ _interopDefault(Stream);
10
11
  const rawBody__default = /* @__PURE__ */ _interopDefault(rawBody);
@@ -567,16 +568,18 @@ const config = {
567
568
  if (typeof config2.provider !== "string") {
568
569
  throw new Error(`Invalid config: provider must be a string`);
569
570
  }
570
- if (config2.provider !== "memory" && config2.provider !== "redis") {
571
- throw new Error(`Invalid config: provider must be 'memory' or 'redis'`);
571
+ if (config2.provider !== "memory" && config2.provider !== "redis" && config2.provider !== "valkey") {
572
+ throw new Error(`Invalid config: provider must be 'memory', 'redis' or 'valkey'`);
572
573
  }
573
- if (config2.provider === "redis") {
574
+ if (config2.provider === "redis" || config2.provider === "valkey") {
574
575
  if (!config2.redisConfig) {
575
- throw new Error(`Invalid config: redisConfig must be set when using redis provider`);
576
+ throw new Error(
577
+ `Invalid config: redisConfig must be set when using redis or valkey provider`
578
+ );
576
579
  }
577
580
  if (typeof config2.redisConfig !== "string" && typeof config2.redisConfig !== "object") {
578
581
  throw new Error(
579
- `Invalid config: redisConfig must be a string or object when using redis provider`
582
+ `Invalid config: redisConfig must be a string or object when using redis or valkey provider`
580
583
  );
581
584
  }
582
585
  if (!Array.isArray(config2.redisClusterNodes) || config2.redisClusterNodes.some((item) => !("host" in item && "port" in item))) {
@@ -840,23 +843,41 @@ class RedisCacheProvider {
840
843
  return;
841
844
  }
842
845
  try {
846
+ const provider = this.strapi.plugin("strapi-cache").config("provider") || "redis";
843
847
  const redisConfig = this.strapi.plugin("strapi-cache").config("redisConfig") || "redis://localhost:6379";
844
848
  const redisClusterNodes = this.strapi.plugin("strapi-cache").config("redisClusterNodes");
845
849
  this.cacheGetTimeoutInMs = Number(
846
850
  this.strapi.plugin("strapi-cache").config("cacheGetTimeoutInMs")
847
851
  );
848
852
  this.keyPrefix = this.strapi.plugin("strapi-cache").config("redisConfig")?.["keyPrefix"] ?? "";
849
- if (redisClusterNodes.length) {
850
- const redisClusterOptions = this.strapi.plugin("strapi-cache").config("redisClusterOptions");
851
- if (!redisClusterOptions["redisOptions"]) {
852
- redisClusterOptions.redisOptions = redisConfig;
853
+ if (provider === "valkey") {
854
+ if (redisClusterNodes.length) {
855
+ const redisClusterOptions = this.strapi.plugin("strapi-cache").config("redisClusterOptions") ?? {};
856
+ const clusterOptions = { ...redisClusterOptions };
857
+ if (!clusterOptions["redisOptions"]) {
858
+ clusterOptions["redisOptions"] = redisConfig;
859
+ }
860
+ this.client = new iovalkey.Cluster(
861
+ redisClusterNodes,
862
+ clusterOptions
863
+ );
864
+ } else {
865
+ this.client = new iovalkey.Redis(redisConfig);
853
866
  }
854
- this.client = new ioredis.Redis.Cluster(redisClusterNodes, redisClusterOptions);
867
+ loggy.info("Valkey provider initialized");
855
868
  } else {
856
- this.client = new ioredis.Redis(redisConfig);
869
+ if (redisClusterNodes.length) {
870
+ const redisClusterOptions = this.strapi.plugin("strapi-cache").config("redisClusterOptions");
871
+ if (!redisClusterOptions["redisOptions"]) {
872
+ redisClusterOptions.redisOptions = redisConfig;
873
+ }
874
+ this.client = new ioredis.Redis.Cluster(redisClusterNodes, redisClusterOptions);
875
+ } else {
876
+ this.client = new ioredis.Redis(redisConfig);
877
+ }
878
+ loggy.info("Redis provider initialized");
857
879
  }
858
880
  this.initialized = true;
859
- loggy.info("Redis provider initialized");
860
881
  } catch (error) {
861
882
  loggy.error(error);
862
883
  }
@@ -960,6 +981,7 @@ const resolveCacheProvider = (strapi2) => {
960
981
  let instance;
961
982
  switch (providerType) {
962
983
  case "redis":
984
+ case "valkey":
963
985
  instance = new RedisCacheProvider(strapi2);
964
986
  break;
965
987
  default:
@@ -3,7 +3,8 @@ import Stream, { Readable } from "stream";
3
3
  import { createInflate, createBrotliDecompress, createGunzip } from "zlib";
4
4
  import rawBody from "raw-body";
5
5
  import { LRUCache } from "lru-cache";
6
- import { Redis } from "ioredis";
6
+ import { Redis as Redis$1 } from "ioredis";
7
+ import { Cluster, Redis } from "iovalkey";
7
8
  const loggy = {
8
9
  info: (msg) => {
9
10
  const shouldDebug = strapi.plugin("strapi-cache").config("debug") ?? false;
@@ -563,16 +564,18 @@ const config = {
563
564
  if (typeof config2.provider !== "string") {
564
565
  throw new Error(`Invalid config: provider must be a string`);
565
566
  }
566
- if (config2.provider !== "memory" && config2.provider !== "redis") {
567
- throw new Error(`Invalid config: provider must be 'memory' or 'redis'`);
567
+ if (config2.provider !== "memory" && config2.provider !== "redis" && config2.provider !== "valkey") {
568
+ throw new Error(`Invalid config: provider must be 'memory', 'redis' or 'valkey'`);
568
569
  }
569
- if (config2.provider === "redis") {
570
+ if (config2.provider === "redis" || config2.provider === "valkey") {
570
571
  if (!config2.redisConfig) {
571
- throw new Error(`Invalid config: redisConfig must be set when using redis provider`);
572
+ throw new Error(
573
+ `Invalid config: redisConfig must be set when using redis or valkey provider`
574
+ );
572
575
  }
573
576
  if (typeof config2.redisConfig !== "string" && typeof config2.redisConfig !== "object") {
574
577
  throw new Error(
575
- `Invalid config: redisConfig must be a string or object when using redis provider`
578
+ `Invalid config: redisConfig must be a string or object when using redis or valkey provider`
576
579
  );
577
580
  }
578
581
  if (!Array.isArray(config2.redisClusterNodes) || config2.redisClusterNodes.some((item) => !("host" in item && "port" in item))) {
@@ -836,23 +839,41 @@ class RedisCacheProvider {
836
839
  return;
837
840
  }
838
841
  try {
842
+ const provider = this.strapi.plugin("strapi-cache").config("provider") || "redis";
839
843
  const redisConfig = this.strapi.plugin("strapi-cache").config("redisConfig") || "redis://localhost:6379";
840
844
  const redisClusterNodes = this.strapi.plugin("strapi-cache").config("redisClusterNodes");
841
845
  this.cacheGetTimeoutInMs = Number(
842
846
  this.strapi.plugin("strapi-cache").config("cacheGetTimeoutInMs")
843
847
  );
844
848
  this.keyPrefix = this.strapi.plugin("strapi-cache").config("redisConfig")?.["keyPrefix"] ?? "";
845
- if (redisClusterNodes.length) {
846
- const redisClusterOptions = this.strapi.plugin("strapi-cache").config("redisClusterOptions");
847
- if (!redisClusterOptions["redisOptions"]) {
848
- redisClusterOptions.redisOptions = redisConfig;
849
+ if (provider === "valkey") {
850
+ if (redisClusterNodes.length) {
851
+ const redisClusterOptions = this.strapi.plugin("strapi-cache").config("redisClusterOptions") ?? {};
852
+ const clusterOptions = { ...redisClusterOptions };
853
+ if (!clusterOptions["redisOptions"]) {
854
+ clusterOptions["redisOptions"] = redisConfig;
855
+ }
856
+ this.client = new Cluster(
857
+ redisClusterNodes,
858
+ clusterOptions
859
+ );
860
+ } else {
861
+ this.client = new Redis(redisConfig);
849
862
  }
850
- this.client = new Redis.Cluster(redisClusterNodes, redisClusterOptions);
863
+ loggy.info("Valkey provider initialized");
851
864
  } else {
852
- this.client = new Redis(redisConfig);
865
+ if (redisClusterNodes.length) {
866
+ const redisClusterOptions = this.strapi.plugin("strapi-cache").config("redisClusterOptions");
867
+ if (!redisClusterOptions["redisOptions"]) {
868
+ redisClusterOptions.redisOptions = redisConfig;
869
+ }
870
+ this.client = new Redis$1.Cluster(redisClusterNodes, redisClusterOptions);
871
+ } else {
872
+ this.client = new Redis$1(redisConfig);
873
+ }
874
+ loggy.info("Redis provider initialized");
853
875
  }
854
876
  this.initialized = true;
855
- loggy.info("Redis provider initialized");
856
877
  } catch (error) {
857
878
  loggy.error(error);
858
879
  }
@@ -956,6 +977,7 @@ const resolveCacheProvider = (strapi2) => {
956
977
  let instance;
957
978
  switch (providerType) {
958
979
  case "redis":
980
+ case "valkey":
959
981
  instance = new RedisCacheProvider(strapi2);
960
982
  break;
961
983
  default:
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.8.1",
2
+ "version": "1.8.2-rc.1",
3
3
  "keywords": [
4
4
  "strapi cache",
5
5
  "strapi rest cache",
@@ -42,6 +42,7 @@
42
42
  "@strapi/design-system": "^2.0.1",
43
43
  "@strapi/icons": "^2.0.1",
44
44
  "ioredis": "^5.6.1",
45
+ "iovalkey": "^0.3.3",
45
46
  "lru-cache": "^11.1.0",
46
47
  "raw-body": "^3.0.0",
47
48
  "react-intl": "^7.1.10"