strapi-cache 1.9.0 → 1.10.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 +27 -25
- package/dist/server/index.js +36 -7
- package/dist/server/index.mjs +36 -7
- package/dist/server/src/config/index.d.ts +1 -0
- package/dist/server/src/index.d.ts +1 -0
- package/dist/server/src/utils/key.d.ts +4 -1
- package/package.json +2 -2
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 + GraphQL 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')
|
|
@@ -96,31 +97,32 @@ Full configuration example:
|
|
|
96
97
|
|
|
97
98
|
Possible configuration keys are listed below; omitted keys keep the plugin defaults.
|
|
98
99
|
|
|
99
|
-
| Key | Description
|
|
100
|
-
| ------------------------- |
|
|
101
|
-
| `debug` | Log cache decisions and operations to the server console
|
|
102
|
-
| `provider` | Where entries are stored
|
|
103
|
-
| `redisConfig` | Redis/Valkey connection: URL string or client options passed to ioredis/iovalkey
|
|
104
|
-
| `redisClusterNodes` | Seed nodes for Redis cluster mode; non-empty list switches to a cluster client
|
|
105
|
-
| `redisClusterOptions` | Options for the cluster client (e.g. `scaleReads`); `redisOptions` often come from `redisConfig`
|
|
106
|
-
| `redisScanDeleteCount` | `COUNT` hint for `SCAN` when purging keys (Redis/Valkey)
|
|
107
|
-
| `max` | Maximum number of entries (in-memory provider only)
|
|
108
|
-
| `ttl` | Time-to-live for each entry, in milliseconds
|
|
109
|
-
| `size` | Approximate max total size in bytes (in-memory provider only)
|
|
110
|
-
| `allowStale` | Whether stale entries may be returned (in-memory provider only)
|
|
111
|
-
| `cacheableRoutes` | Only URLs starting with one of these paths are cached; if empty, every URL under the REST API prefix matches
|
|
112
|
-
| `
|
|
113
|
-
| `
|
|
114
|
-
| `
|
|
115
|
-
| `
|
|
116
|
-
| `
|
|
117
|
-
| `
|
|
118
|
-
| `
|
|
119
|
-
| `
|
|
120
|
-
| `
|
|
121
|
-
| `
|
|
122
|
-
| `
|
|
123
|
-
| `
|
|
100
|
+
| Key | Description | Possible values |
|
|
101
|
+
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
102
|
+
| `debug` | Log cache decisions and operations to the server console | `true` or `false` (default: `false`) |
|
|
103
|
+
| `provider` | Where entries are stored | `'memory'`, `'redis'`, or `'valkey'` (default: `'memory'`) |
|
|
104
|
+
| `redisConfig` | Redis/Valkey connection: URL string or client options passed to ioredis/iovalkey | String or object; **required** when `provider` is `'redis'` or `'valkey'`. Default: value of `REDIS_URL` from the environment |
|
|
105
|
+
| `redisClusterNodes` | Seed nodes for Redis cluster mode; non-empty list switches to a cluster client | Array of `{ host: string, port: number }` (default: `[]`) |
|
|
106
|
+
| `redisClusterOptions` | Options for the cluster client (e.g. `scaleReads`); `redisOptions` often come from `redisConfig` | Object (default: `{}`) |
|
|
107
|
+
| `redisScanDeleteCount` | `COUNT` hint for `SCAN` when purging keys (Redis/Valkey) | Positive number (default: `100`) |
|
|
108
|
+
| `max` | Maximum number of entries (in-memory provider only) | Positive integer (default: `1000`) |
|
|
109
|
+
| `ttl` | Time-to-live for each entry, in milliseconds | Non-negative number (default: `3600000`, i.e. 1 hour) |
|
|
110
|
+
| `size` | Approximate max total size in bytes (in-memory provider only) | Positive integer (default: `10485760`, i.e. 10 MB) |
|
|
111
|
+
| `allowStale` | Whether stale entries may be returned (in-memory provider only) | `true` or `false` (default: `false`) |
|
|
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}`; for graphql, if set, the ctx gets additional fields: `rootFields` and `operationName` which may be useful for invalidation logic | Function `(ctx) => string` (default: unset) |
|
|
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` |
|
|
115
|
+
| `excludeRoutes` | URLs starting with any of these prefixes are **never** cached; evaluated before `cacheableRoutes` / entities | Array of path prefix strings (default: `[]`) |
|
|
116
|
+
| `cacheHeaders` | Store and replay response headers with the body | `true` or `false` (default: `true`) |
|
|
117
|
+
| `cacheHeadersDenyList` | Header names (lowercase) to strip when `cacheHeaders` is `true` | Array of strings (default: `[]`) |
|
|
118
|
+
| `cacheHeadersAllowList` | If non-empty, only these header names (lowercase) are stored; if empty, all headers are stored (subject to deny list) | Array of strings (default: `[]`) |
|
|
119
|
+
| `cacheAuthorizedRequests` | Whether to cache requests that include an `Authorization` header | `true` or `false` (default: `false`) |
|
|
120
|
+
| `cacheGetTimeoutInMs` | Max time to wait for a cache read before treating it as a miss | Milliseconds (default: `1000`) |
|
|
121
|
+
| `autoPurgeCache` | Invalidate relevant REST cache entries after content create/update/delete | `true` or `false` (default: `true`) |
|
|
122
|
+
| `autoPurgeGraphQL` | Invalidate GraphQL cache after content create/update/delete | `true` or `false` (default: `false` if omitted; set `true` to enable) |
|
|
123
|
+
| `autoPurgeCacheOnStart` | Clear the cache when Strapi starts | `true` or `false` (default: `true`) |
|
|
124
|
+
| `disableAdminPopups` | Turn off admin UI notifications for cache actions | `true` or `false` (default: `false`) |
|
|
125
|
+
| `disableAdminButtons` | Hide manual purge controls in the admin (list and edit views) | `true` or `false` (default: `false`) |
|
|
124
126
|
|
|
125
127
|
## 🔍 Routes
|
|
126
128
|
|
package/dist/server/index.js
CHANGED
|
@@ -31,6 +31,9 @@ const loggy = {
|
|
|
31
31
|
strapi.log.warn(`[STRAPI CACHE] ${msg}`);
|
|
32
32
|
}
|
|
33
33
|
};
|
|
34
|
+
const escapeRegex = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
35
|
+
const getGraphqlEndpoint = (strapi2) => strapi2.plugin("graphql")?.config("endpoint", "/graphql") ?? "/graphql";
|
|
36
|
+
const getGraphqlAllKeysRegex = (strapi2) => new RegExp(`^(GET|POST):${escapeRegex(getGraphqlEndpoint(strapi2))}.*`);
|
|
34
37
|
async function invalidateCache(event, cacheStore, strapi2) {
|
|
35
38
|
const { model } = event;
|
|
36
39
|
const uid = model.uid;
|
|
@@ -63,7 +66,7 @@ async function invalidateGraphqlCache(event, cacheStore, strapi2) {
|
|
|
63
66
|
const contentType = strapi2.contentType(model.uid);
|
|
64
67
|
if (!contentType || !contentType.info) {
|
|
65
68
|
loggy.info(`Content type ${model.uid} not found, purging all GraphQL cache`);
|
|
66
|
-
const graphqlRegex2 =
|
|
69
|
+
const graphqlRegex2 = getGraphqlAllKeysRegex(strapi2);
|
|
67
70
|
await cacheStore.clearByRegexp([graphqlRegex2]);
|
|
68
71
|
return;
|
|
69
72
|
}
|
|
@@ -72,12 +75,14 @@ async function invalidateGraphqlCache(event, cacheStore, strapi2) {
|
|
|
72
75
|
const fieldNames = [...new Set([singularName, pluralName].filter(Boolean))];
|
|
73
76
|
if (fieldNames.length === 0) {
|
|
74
77
|
loggy.info(`No field names for ${model.uid}, purging all GraphQL cache`);
|
|
75
|
-
const graphqlRegex2 =
|
|
78
|
+
const graphqlRegex2 = getGraphqlAllKeysRegex(strapi2);
|
|
76
79
|
await cacheStore.clearByRegexp([graphqlRegex2]);
|
|
77
80
|
return;
|
|
78
81
|
}
|
|
79
|
-
const escapedNames = fieldNames.map((name) => name
|
|
80
|
-
const graphqlRegex = new RegExp(
|
|
82
|
+
const escapedNames = fieldNames.map((name) => escapeRegex(name)).join("|");
|
|
83
|
+
const graphqlRegex = new RegExp(
|
|
84
|
+
`^(GET|POST):${escapeRegex(getGraphqlEndpoint(strapi2))}:[^:]*\\b(${escapedNames})\\b[^:]*:`
|
|
85
|
+
);
|
|
81
86
|
await cacheStore.clearByRegexp([graphqlRegex]);
|
|
82
87
|
loggy.info(`Invalidated GraphQL cache for ${model.uid} (${fieldNames.join(", ")})`);
|
|
83
88
|
} catch (error) {
|
|
@@ -152,7 +157,22 @@ const bootstrap = ({ strapi: strapi2 }) => {
|
|
|
152
157
|
loggy.info("Plugin initialized");
|
|
153
158
|
strapi2.admin.services.permission.actionProvider.registerMany(actions);
|
|
154
159
|
};
|
|
155
|
-
const
|
|
160
|
+
const getCustomCacheKey = (context, keyGenerator) => {
|
|
161
|
+
if (typeof keyGenerator !== "function") {
|
|
162
|
+
return void 0;
|
|
163
|
+
}
|
|
164
|
+
const customKey = keyGenerator(context);
|
|
165
|
+
if (typeof customKey === "string") {
|
|
166
|
+
return customKey;
|
|
167
|
+
}
|
|
168
|
+
return void 0;
|
|
169
|
+
};
|
|
170
|
+
const resolveGraphqlCacheKey = (context, fallbackKey, keyGenerator) => getCustomCacheKey(context, keyGenerator) ?? fallbackKey;
|
|
171
|
+
const generateCacheKey = (context, keyGenerator) => {
|
|
172
|
+
const customKey = getCustomCacheKey(context, keyGenerator);
|
|
173
|
+
if (customKey !== void 0) {
|
|
174
|
+
return customKey;
|
|
175
|
+
}
|
|
156
176
|
const { url } = context.request;
|
|
157
177
|
const { method } = context.request;
|
|
158
178
|
return `${method}:${url}`;
|
|
@@ -238,10 +258,11 @@ const middleware$1 = async (ctx, next) => {
|
|
|
238
258
|
const cacheableEntities = strapi.plugin("strapi-cache").config("cacheableEntities");
|
|
239
259
|
const cacheableRoutes = strapi.plugin("strapi-cache").config("cacheableRoutes");
|
|
240
260
|
const excludeRoutes = strapi.plugin("strapi-cache").config("excludeRoutes");
|
|
261
|
+
const keyGenerator = strapi.plugin("strapi-cache").config("keyGenerator");
|
|
241
262
|
const { cacheHeaders, cacheHeadersDenyList, cacheHeadersAllowList, cacheAuthorizedRequests } = getCacheHeaderConfig();
|
|
242
263
|
const cacheStore = cacheService.getCacheInstance();
|
|
243
264
|
const { url } = ctx.request;
|
|
244
|
-
const key = generateCacheKey(ctx);
|
|
265
|
+
const key = generateCacheKey(ctx, keyGenerator);
|
|
245
266
|
const cacheEntry = await cacheStore.get(key);
|
|
246
267
|
const cacheControlHeader = ctx.request.headers["cache-control"];
|
|
247
268
|
const noCache = cacheControlHeader && cacheControlHeader.includes("no-cache");
|
|
@@ -395,6 +416,7 @@ const middleware = async (ctx, next) => {
|
|
|
395
416
|
return;
|
|
396
417
|
}
|
|
397
418
|
const cacheService = strapi.plugin("strapi-cache").services.service;
|
|
419
|
+
const keyGenerator = strapi.plugin("strapi-cache").config("keyGenerator");
|
|
398
420
|
const { cacheHeaders, cacheHeadersDenyList, cacheHeadersAllowList, cacheAuthorizedRequests } = getCacheHeaderConfig();
|
|
399
421
|
const cacheStore = cacheService.getCacheInstance();
|
|
400
422
|
const isGet = method === "GET";
|
|
@@ -424,7 +446,10 @@ const middleware = async (ctx, next) => {
|
|
|
424
446
|
}
|
|
425
447
|
const payload = parseGraphqlPayload(body, isGet);
|
|
426
448
|
const rootFields = getRootFieldsFromQuery(payload.query);
|
|
427
|
-
const
|
|
449
|
+
const graphqlKey = generateGraphqlCacheKey(body, isGet ? "GET" : "POST", rootFields, strapi);
|
|
450
|
+
ctx.rootFields = rootFields.length ? rootFields : void 0;
|
|
451
|
+
ctx.operationName = payload.operationName;
|
|
452
|
+
const key = resolveGraphqlCacheKey(ctx, graphqlKey, keyGenerator);
|
|
428
453
|
loggy.info(
|
|
429
454
|
`GraphQL request: ${JSON.stringify({
|
|
430
455
|
operationName: payload.operationName,
|
|
@@ -533,6 +558,7 @@ const config = {
|
|
|
533
558
|
size: 1024 * 1024 * 10,
|
|
534
559
|
allowStale: false,
|
|
535
560
|
cacheableRoutes: [],
|
|
561
|
+
keyGenerator: void 0,
|
|
536
562
|
provider: "memory",
|
|
537
563
|
excludeRoutes: [],
|
|
538
564
|
redisConfig: env("REDIS_URL"),
|
|
@@ -568,6 +594,9 @@ const config = {
|
|
|
568
594
|
if (!Array.isArray(config2.cacheableRoutes) || config2.cacheableRoutes.some((item) => typeof item !== "string")) {
|
|
569
595
|
throw new Error(`Invalid config: cacheableRoutes must be an string array`);
|
|
570
596
|
}
|
|
597
|
+
if (config2.keyGenerator !== void 0 && typeof config2.keyGenerator !== "function") {
|
|
598
|
+
throw new Error(`Invalid config: keyGenerator must be a function`);
|
|
599
|
+
}
|
|
571
600
|
if (config2.cacheableEntities !== void 0 && (!Array.isArray(config2.cacheableEntities) || config2.cacheableEntities.some((item) => typeof item !== "string"))) {
|
|
572
601
|
throw new Error(`Invalid config: cacheableEntities must be a string array`);
|
|
573
602
|
}
|
package/dist/server/index.mjs
CHANGED
|
@@ -27,6 +27,9 @@ const loggy = {
|
|
|
27
27
|
strapi.log.warn(`[STRAPI CACHE] ${msg}`);
|
|
28
28
|
}
|
|
29
29
|
};
|
|
30
|
+
const escapeRegex = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
31
|
+
const getGraphqlEndpoint = (strapi2) => strapi2.plugin("graphql")?.config("endpoint", "/graphql") ?? "/graphql";
|
|
32
|
+
const getGraphqlAllKeysRegex = (strapi2) => new RegExp(`^(GET|POST):${escapeRegex(getGraphqlEndpoint(strapi2))}.*`);
|
|
30
33
|
async function invalidateCache(event, cacheStore, strapi2) {
|
|
31
34
|
const { model } = event;
|
|
32
35
|
const uid = model.uid;
|
|
@@ -59,7 +62,7 @@ async function invalidateGraphqlCache(event, cacheStore, strapi2) {
|
|
|
59
62
|
const contentType = strapi2.contentType(model.uid);
|
|
60
63
|
if (!contentType || !contentType.info) {
|
|
61
64
|
loggy.info(`Content type ${model.uid} not found, purging all GraphQL cache`);
|
|
62
|
-
const graphqlRegex2 =
|
|
65
|
+
const graphqlRegex2 = getGraphqlAllKeysRegex(strapi2);
|
|
63
66
|
await cacheStore.clearByRegexp([graphqlRegex2]);
|
|
64
67
|
return;
|
|
65
68
|
}
|
|
@@ -68,12 +71,14 @@ async function invalidateGraphqlCache(event, cacheStore, strapi2) {
|
|
|
68
71
|
const fieldNames = [...new Set([singularName, pluralName].filter(Boolean))];
|
|
69
72
|
if (fieldNames.length === 0) {
|
|
70
73
|
loggy.info(`No field names for ${model.uid}, purging all GraphQL cache`);
|
|
71
|
-
const graphqlRegex2 =
|
|
74
|
+
const graphqlRegex2 = getGraphqlAllKeysRegex(strapi2);
|
|
72
75
|
await cacheStore.clearByRegexp([graphqlRegex2]);
|
|
73
76
|
return;
|
|
74
77
|
}
|
|
75
|
-
const escapedNames = fieldNames.map((name) => name
|
|
76
|
-
const graphqlRegex = new RegExp(
|
|
78
|
+
const escapedNames = fieldNames.map((name) => escapeRegex(name)).join("|");
|
|
79
|
+
const graphqlRegex = new RegExp(
|
|
80
|
+
`^(GET|POST):${escapeRegex(getGraphqlEndpoint(strapi2))}:[^:]*\\b(${escapedNames})\\b[^:]*:`
|
|
81
|
+
);
|
|
77
82
|
await cacheStore.clearByRegexp([graphqlRegex]);
|
|
78
83
|
loggy.info(`Invalidated GraphQL cache for ${model.uid} (${fieldNames.join(", ")})`);
|
|
79
84
|
} catch (error) {
|
|
@@ -148,7 +153,22 @@ const bootstrap = ({ strapi: strapi2 }) => {
|
|
|
148
153
|
loggy.info("Plugin initialized");
|
|
149
154
|
strapi2.admin.services.permission.actionProvider.registerMany(actions);
|
|
150
155
|
};
|
|
151
|
-
const
|
|
156
|
+
const getCustomCacheKey = (context, keyGenerator) => {
|
|
157
|
+
if (typeof keyGenerator !== "function") {
|
|
158
|
+
return void 0;
|
|
159
|
+
}
|
|
160
|
+
const customKey = keyGenerator(context);
|
|
161
|
+
if (typeof customKey === "string") {
|
|
162
|
+
return customKey;
|
|
163
|
+
}
|
|
164
|
+
return void 0;
|
|
165
|
+
};
|
|
166
|
+
const resolveGraphqlCacheKey = (context, fallbackKey, keyGenerator) => getCustomCacheKey(context, keyGenerator) ?? fallbackKey;
|
|
167
|
+
const generateCacheKey = (context, keyGenerator) => {
|
|
168
|
+
const customKey = getCustomCacheKey(context, keyGenerator);
|
|
169
|
+
if (customKey !== void 0) {
|
|
170
|
+
return customKey;
|
|
171
|
+
}
|
|
152
172
|
const { url } = context.request;
|
|
153
173
|
const { method } = context.request;
|
|
154
174
|
return `${method}:${url}`;
|
|
@@ -234,10 +254,11 @@ const middleware$1 = async (ctx, next) => {
|
|
|
234
254
|
const cacheableEntities = strapi.plugin("strapi-cache").config("cacheableEntities");
|
|
235
255
|
const cacheableRoutes = strapi.plugin("strapi-cache").config("cacheableRoutes");
|
|
236
256
|
const excludeRoutes = strapi.plugin("strapi-cache").config("excludeRoutes");
|
|
257
|
+
const keyGenerator = strapi.plugin("strapi-cache").config("keyGenerator");
|
|
237
258
|
const { cacheHeaders, cacheHeadersDenyList, cacheHeadersAllowList, cacheAuthorizedRequests } = getCacheHeaderConfig();
|
|
238
259
|
const cacheStore = cacheService.getCacheInstance();
|
|
239
260
|
const { url } = ctx.request;
|
|
240
|
-
const key = generateCacheKey(ctx);
|
|
261
|
+
const key = generateCacheKey(ctx, keyGenerator);
|
|
241
262
|
const cacheEntry = await cacheStore.get(key);
|
|
242
263
|
const cacheControlHeader = ctx.request.headers["cache-control"];
|
|
243
264
|
const noCache = cacheControlHeader && cacheControlHeader.includes("no-cache");
|
|
@@ -391,6 +412,7 @@ const middleware = async (ctx, next) => {
|
|
|
391
412
|
return;
|
|
392
413
|
}
|
|
393
414
|
const cacheService = strapi.plugin("strapi-cache").services.service;
|
|
415
|
+
const keyGenerator = strapi.plugin("strapi-cache").config("keyGenerator");
|
|
394
416
|
const { cacheHeaders, cacheHeadersDenyList, cacheHeadersAllowList, cacheAuthorizedRequests } = getCacheHeaderConfig();
|
|
395
417
|
const cacheStore = cacheService.getCacheInstance();
|
|
396
418
|
const isGet = method === "GET";
|
|
@@ -420,7 +442,10 @@ const middleware = async (ctx, next) => {
|
|
|
420
442
|
}
|
|
421
443
|
const payload = parseGraphqlPayload(body, isGet);
|
|
422
444
|
const rootFields = getRootFieldsFromQuery(payload.query);
|
|
423
|
-
const
|
|
445
|
+
const graphqlKey = generateGraphqlCacheKey(body, isGet ? "GET" : "POST", rootFields, strapi);
|
|
446
|
+
ctx.rootFields = rootFields.length ? rootFields : void 0;
|
|
447
|
+
ctx.operationName = payload.operationName;
|
|
448
|
+
const key = resolveGraphqlCacheKey(ctx, graphqlKey, keyGenerator);
|
|
424
449
|
loggy.info(
|
|
425
450
|
`GraphQL request: ${JSON.stringify({
|
|
426
451
|
operationName: payload.operationName,
|
|
@@ -529,6 +554,7 @@ const config = {
|
|
|
529
554
|
size: 1024 * 1024 * 10,
|
|
530
555
|
allowStale: false,
|
|
531
556
|
cacheableRoutes: [],
|
|
557
|
+
keyGenerator: void 0,
|
|
532
558
|
provider: "memory",
|
|
533
559
|
excludeRoutes: [],
|
|
534
560
|
redisConfig: env("REDIS_URL"),
|
|
@@ -564,6 +590,9 @@ const config = {
|
|
|
564
590
|
if (!Array.isArray(config2.cacheableRoutes) || config2.cacheableRoutes.some((item) => typeof item !== "string")) {
|
|
565
591
|
throw new Error(`Invalid config: cacheableRoutes must be an string array`);
|
|
566
592
|
}
|
|
593
|
+
if (config2.keyGenerator !== void 0 && typeof config2.keyGenerator !== "function") {
|
|
594
|
+
throw new Error(`Invalid config: keyGenerator must be a function`);
|
|
595
|
+
}
|
|
567
596
|
if (config2.cacheableEntities !== void 0 && (!Array.isArray(config2.cacheableEntities) || config2.cacheableEntities.some((item) => typeof item !== "string"))) {
|
|
568
597
|
throw new Error(`Invalid config: cacheableEntities must be a string array`);
|
|
569
598
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
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 getCustomCacheKey: (context: Context, keyGenerator?: CacheKeyGenerator) => string;
|
|
5
|
+
export declare const resolveGraphqlCacheKey: (context: Context, fallbackKey: string, keyGenerator?: CacheKeyGenerator) => string;
|
|
6
|
+
export declare const generateCacheKey: (context: Context, keyGenerator?: CacheKeyGenerator) => string;
|
|
4
7
|
export declare const generateGraphqlCacheKey: (payload: string, method?: 'GET' | 'POST', rootFields?: string[], strapi?: Core.Strapi) => string;
|
|
5
8
|
export declare const escapeRegExp: (s: string) => string;
|
|
6
9
|
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.1",
|
|
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": {
|