strapi-cache 1.9.0 → 1.10.0
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
|
@@ -72,6 +72,7 @@ Full configuration example:
|
|
|
72
72
|
size: 1024 * 1024 * 1024, // Maximum size of the cache (1 GB) (only for memory cache)
|
|
73
73
|
allowStale: false, // Allow stale cache items (only for memory cache)
|
|
74
74
|
cacheableRoutes: ['/api/products', '/api/categories'], // Caches routes which start with these paths (if empty array, all '/api' routes are cached)
|
|
75
|
+
keyGenerator: (ctx) => `${ctx.request.method}:${ctx.request.url}`, // Optional custom cache key for REST requests; receives koa ctx
|
|
75
76
|
// 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
|
|
76
77
|
excludeRoutes: ['/api/products/private'], // Exclude routes which start with these paths from being cached (takes precedence over cacheableRoutes). **Note:** `excludeRoutes` takes precedence over `cacheableRoutes`.
|
|
77
78
|
provider: 'memory', // Cache provider ('memory', 'redis' or 'valkey')
|
|
@@ -109,6 +110,7 @@ Possible configuration keys are listed below; omitted keys keep the plugin defau
|
|
|
109
110
|
| `size` | Approximate max total size in bytes (in-memory provider only) | Positive integer (default: `10485760`, i.e. 10 MB) |
|
|
110
111
|
| `allowStale` | Whether stale entries may be returned (in-memory provider only) | `true` or `false` (default: `false`) |
|
|
111
112
|
| `cacheableRoutes` | Only URLs starting with one of these paths are cached; if empty, every URL under the REST API prefix matches | Array of path prefix strings (default: `[]` meaning “all API routes”) |
|
|
113
|
+
| `keyGenerator` | Custom function to build REST cache keys; receives Koa `ctx`; when omitted, default key is `${method}:${url}` | Function `(ctx) => string` (default: unset) |
|
|
112
114
|
| `cacheableEntities` | If non-empty, only these API “entity” segments are cached; **when set, this drives eligibility instead of** `cacheableRoutes` | Array of strings (e.g. collection/table names), or omit / leave empty to use `cacheableRoutes` |
|
|
113
115
|
| `excludeRoutes` | URLs starting with any of these prefixes are **never** cached; evaluated before `cacheableRoutes` / entities | Array of path prefix strings (default: `[]`) |
|
|
114
116
|
| `cacheHeaders` | Store and replay response headers with the body | `true` or `false` (default: `true`) |
|
package/dist/server/index.js
CHANGED
|
@@ -152,7 +152,13 @@ const bootstrap = ({ strapi: strapi2 }) => {
|
|
|
152
152
|
loggy.info("Plugin initialized");
|
|
153
153
|
strapi2.admin.services.permission.actionProvider.registerMany(actions);
|
|
154
154
|
};
|
|
155
|
-
const generateCacheKey = (context) => {
|
|
155
|
+
const generateCacheKey = (context, keyGenerator) => {
|
|
156
|
+
if (typeof keyGenerator === "function") {
|
|
157
|
+
const customKey = keyGenerator(context);
|
|
158
|
+
if (typeof customKey === "string") {
|
|
159
|
+
return customKey;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
156
162
|
const { url } = context.request;
|
|
157
163
|
const { method } = context.request;
|
|
158
164
|
return `${method}:${url}`;
|
|
@@ -238,10 +244,11 @@ const middleware$1 = async (ctx, next) => {
|
|
|
238
244
|
const cacheableEntities = strapi.plugin("strapi-cache").config("cacheableEntities");
|
|
239
245
|
const cacheableRoutes = strapi.plugin("strapi-cache").config("cacheableRoutes");
|
|
240
246
|
const excludeRoutes = strapi.plugin("strapi-cache").config("excludeRoutes");
|
|
247
|
+
const keyGenerator = strapi.plugin("strapi-cache").config("keyGenerator");
|
|
241
248
|
const { cacheHeaders, cacheHeadersDenyList, cacheHeadersAllowList, cacheAuthorizedRequests } = getCacheHeaderConfig();
|
|
242
249
|
const cacheStore = cacheService.getCacheInstance();
|
|
243
250
|
const { url } = ctx.request;
|
|
244
|
-
const key = generateCacheKey(ctx);
|
|
251
|
+
const key = generateCacheKey(ctx, keyGenerator);
|
|
245
252
|
const cacheEntry = await cacheStore.get(key);
|
|
246
253
|
const cacheControlHeader = ctx.request.headers["cache-control"];
|
|
247
254
|
const noCache = cacheControlHeader && cacheControlHeader.includes("no-cache");
|
|
@@ -533,6 +540,7 @@ const config = {
|
|
|
533
540
|
size: 1024 * 1024 * 10,
|
|
534
541
|
allowStale: false,
|
|
535
542
|
cacheableRoutes: [],
|
|
543
|
+
keyGenerator: void 0,
|
|
536
544
|
provider: "memory",
|
|
537
545
|
excludeRoutes: [],
|
|
538
546
|
redisConfig: env("REDIS_URL"),
|
|
@@ -568,6 +576,9 @@ const config = {
|
|
|
568
576
|
if (!Array.isArray(config2.cacheableRoutes) || config2.cacheableRoutes.some((item) => typeof item !== "string")) {
|
|
569
577
|
throw new Error(`Invalid config: cacheableRoutes must be an string array`);
|
|
570
578
|
}
|
|
579
|
+
if (config2.keyGenerator !== void 0 && typeof config2.keyGenerator !== "function") {
|
|
580
|
+
throw new Error(`Invalid config: keyGenerator must be a function`);
|
|
581
|
+
}
|
|
571
582
|
if (config2.cacheableEntities !== void 0 && (!Array.isArray(config2.cacheableEntities) || config2.cacheableEntities.some((item) => typeof item !== "string"))) {
|
|
572
583
|
throw new Error(`Invalid config: cacheableEntities must be a string array`);
|
|
573
584
|
}
|
package/dist/server/index.mjs
CHANGED
|
@@ -148,7 +148,13 @@ const bootstrap = ({ strapi: strapi2 }) => {
|
|
|
148
148
|
loggy.info("Plugin initialized");
|
|
149
149
|
strapi2.admin.services.permission.actionProvider.registerMany(actions);
|
|
150
150
|
};
|
|
151
|
-
const generateCacheKey = (context) => {
|
|
151
|
+
const generateCacheKey = (context, keyGenerator) => {
|
|
152
|
+
if (typeof keyGenerator === "function") {
|
|
153
|
+
const customKey = keyGenerator(context);
|
|
154
|
+
if (typeof customKey === "string") {
|
|
155
|
+
return customKey;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
152
158
|
const { url } = context.request;
|
|
153
159
|
const { method } = context.request;
|
|
154
160
|
return `${method}:${url}`;
|
|
@@ -234,10 +240,11 @@ const middleware$1 = async (ctx, next) => {
|
|
|
234
240
|
const cacheableEntities = strapi.plugin("strapi-cache").config("cacheableEntities");
|
|
235
241
|
const cacheableRoutes = strapi.plugin("strapi-cache").config("cacheableRoutes");
|
|
236
242
|
const excludeRoutes = strapi.plugin("strapi-cache").config("excludeRoutes");
|
|
243
|
+
const keyGenerator = strapi.plugin("strapi-cache").config("keyGenerator");
|
|
237
244
|
const { cacheHeaders, cacheHeadersDenyList, cacheHeadersAllowList, cacheAuthorizedRequests } = getCacheHeaderConfig();
|
|
238
245
|
const cacheStore = cacheService.getCacheInstance();
|
|
239
246
|
const { url } = ctx.request;
|
|
240
|
-
const key = generateCacheKey(ctx);
|
|
247
|
+
const key = generateCacheKey(ctx, keyGenerator);
|
|
241
248
|
const cacheEntry = await cacheStore.get(key);
|
|
242
249
|
const cacheControlHeader = ctx.request.headers["cache-control"];
|
|
243
250
|
const noCache = cacheControlHeader && cacheControlHeader.includes("no-cache");
|
|
@@ -529,6 +536,7 @@ const config = {
|
|
|
529
536
|
size: 1024 * 1024 * 10,
|
|
530
537
|
allowStale: false,
|
|
531
538
|
cacheableRoutes: [],
|
|
539
|
+
keyGenerator: void 0,
|
|
532
540
|
provider: "memory",
|
|
533
541
|
excludeRoutes: [],
|
|
534
542
|
redisConfig: env("REDIS_URL"),
|
|
@@ -564,6 +572,9 @@ const config = {
|
|
|
564
572
|
if (!Array.isArray(config2.cacheableRoutes) || config2.cacheableRoutes.some((item) => typeof item !== "string")) {
|
|
565
573
|
throw new Error(`Invalid config: cacheableRoutes must be an string array`);
|
|
566
574
|
}
|
|
575
|
+
if (config2.keyGenerator !== void 0 && typeof config2.keyGenerator !== "function") {
|
|
576
|
+
throw new Error(`Invalid config: keyGenerator must be a function`);
|
|
577
|
+
}
|
|
567
578
|
if (config2.cacheableEntities !== void 0 && (!Array.isArray(config2.cacheableEntities) || config2.cacheableEntities.some((item) => typeof item !== "string"))) {
|
|
568
579
|
throw new Error(`Invalid config: cacheableEntities must be a string array`);
|
|
569
580
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Core } from '@strapi/strapi';
|
|
2
2
|
import { Context } from 'koa';
|
|
3
|
-
export
|
|
3
|
+
export type CacheKeyGenerator = (context: Context) => string;
|
|
4
|
+
export declare const generateCacheKey: (context: Context, keyGenerator?: CacheKeyGenerator) => string;
|
|
4
5
|
export declare const generateGraphqlCacheKey: (payload: string, method?: 'GET' | 'POST', rootFields?: string[], strapi?: Core.Strapi) => string;
|
|
5
6
|
export declare const escapeRegExp: (s: string) => string;
|
|
6
7
|
export declare const generateEntityKey: (url: string, restApiPrefix: string) => string;
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.
|
|
2
|
+
"version": "1.10.0",
|
|
3
3
|
"keywords": [
|
|
4
4
|
"strapi cache",
|
|
5
5
|
"strapi rest cache",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"test:ts:front": "run -T tsc -p admin/tsconfig.json",
|
|
36
36
|
"test:ts:back": "run -T tsc -p server/tsconfig.json",
|
|
37
37
|
"test": "vitest run --exclude 'test/integration/**'",
|
|
38
|
-
"test:integration": "npm run build && rm -rf playground/.cache && mkdir -p playground/.yalc/strapi-cache && cp -r dist package.json LICENSE README.md playground/.yalc/strapi-cache/ && cd playground && npm
|
|
38
|
+
"test:integration": "npm run build && rm -rf playground/.cache playground/node_modules playground/.yalc && mkdir -p playground/.yalc/strapi-cache && cp -r dist package.json LICENSE README.md playground/.yalc/strapi-cache/ && node -e \"const fs=require('fs');const p='playground/.yalc/strapi-cache/package.json';const pkg=JSON.parse(fs.readFileSync(p,'utf8'));delete pkg.devDependencies;delete pkg.optionalDependencies;delete pkg.scripts;fs.writeFileSync(p,JSON.stringify(pkg,null,2));\" && cd playground && npm ci --ignore-scripts && npm rebuild better-sqlite3 @swc/core sharp --foreground-scripts && npm run build && cd .. && NODE_ENV=test jest --config jest.integration.config.js --runInBand --forceExit --detectOpenHandles",
|
|
39
39
|
"test:all": "npm test -- --run && npm run test:integration"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|