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 +6 -6
- package/dist/server/index.js +34 -12
- package/dist/server/index.mjs +35 -13
- package/package.json +2 -1
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
|
|
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 '
|
|
56
|
-
redisConfig: env('REDIS_URL', 'redis://localhost:6379'), // Redis config
|
|
57
|
-
redisClusterNodes: [], // If provided any cluster node (this list is not empty), initialize
|
|
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
|
|
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.
|
package/dist/server/index.js
CHANGED
|
@@ -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 '
|
|
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(
|
|
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 (
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
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
|
-
|
|
867
|
+
loggy.info("Valkey provider initialized");
|
|
855
868
|
} else {
|
|
856
|
-
|
|
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:
|
package/dist/server/index.mjs
CHANGED
|
@@ -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 '
|
|
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(
|
|
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 (
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
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
|
-
|
|
863
|
+
loggy.info("Valkey provider initialized");
|
|
851
864
|
} else {
|
|
852
|
-
|
|
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"
|