strapi-cache 1.4.7-rc.4 → 1.4.8-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/LICENSE +21 -0
- package/README.md +4 -2
- package/dist/server/index.js +51 -16
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +51 -16
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/config/index.d.ts +3 -1
- package/dist/server/src/index.d.ts +3 -1
- package/package.json +1 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Christoph Tupi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**A powerful LRU-Cache plugin for Strapi v5**
|
|
4
4
|
Boost your API performance with automatic in-memory or Redis caching for REST and GraphQL requests.
|
|
5
5
|
|
|
6
|
-

|
|
7
7
|

|
|
8
8
|

|
|
9
9
|

|
|
@@ -51,7 +51,9 @@ In your Strapi project, navigate to `config/plugins.js` and add the following co
|
|
|
51
51
|
allowStale: false, // Allow stale cache items (only for memory cache)
|
|
52
52
|
cacheableRoutes: ['/api/products', '/api/categories'], // Caches routes which start with these paths (if empty array, all '/api' routes are cached)
|
|
53
53
|
provider: 'memory', // Cache provider ('memory' or 'redis')
|
|
54
|
-
|
|
54
|
+
redisConfig: env('REDIS_URL', 'redis://localhost:6379'), // Redis config takes either a string or an object see https://ioredis.readthedocs.io/en/stable/README for references to what object is available, the object or string is passed directly to ioredis client (if using Redis)
|
|
55
|
+
cacheHeaders: true, // Plugin also stores response headers in the cache (set to false if you don't want to cache headers)
|
|
56
|
+
cacheAuthorizedRequests: false, // Cache requests with authorization headers (set to true if you want to cache authorized requests)
|
|
55
57
|
},
|
|
56
58
|
},
|
|
57
59
|
```
|
package/dist/server/index.js
CHANGED
|
@@ -102,9 +102,8 @@ const bootstrap = ({ strapi: strapi2 }) => {
|
|
|
102
102
|
};
|
|
103
103
|
const generateCacheKey = (context) => {
|
|
104
104
|
const { url } = context.request;
|
|
105
|
-
const decodedUrl = decodeURIComponent(url);
|
|
106
105
|
const { method } = context.request;
|
|
107
|
-
return `${method}:${
|
|
106
|
+
return `${method}:${url}`;
|
|
108
107
|
};
|
|
109
108
|
const generateGraphqlCacheKey = (payload) => {
|
|
110
109
|
const hash = crypto.createHash("sha256").update(payload).digest("base64url");
|
|
@@ -148,6 +147,8 @@ const decodeBufferToText = (buffer) => {
|
|
|
148
147
|
const middleware$1 = async (ctx, next) => {
|
|
149
148
|
const cacheService = strapi.plugin("strapi-cache").services.service;
|
|
150
149
|
const cacheableRoutes = strapi.plugin("strapi-cache").config("cacheableRoutes");
|
|
150
|
+
const cacheHeaders = strapi.plugin("strapi-cache").config("cacheHeaders");
|
|
151
|
+
const cacheAuthorizedRequests = strapi.plugin("strapi-cache").config("cacheAuthorizedRequests");
|
|
151
152
|
const cacheStore = cacheService.getCacheInstance();
|
|
152
153
|
const { url } = ctx.request;
|
|
153
154
|
const key = generateCacheKey(ctx);
|
|
@@ -155,12 +156,17 @@ const middleware$1 = async (ctx, next) => {
|
|
|
155
156
|
const cacheControlHeader = ctx.request.headers["cache-control"];
|
|
156
157
|
const noCache = cacheControlHeader && cacheControlHeader.includes("no-cache");
|
|
157
158
|
const routeIsCachable = cacheableRoutes.some((route) => url.startsWith(route)) || cacheableRoutes.length === 0 && url.startsWith("/api");
|
|
159
|
+
const authorizationHeader = ctx.request.headers["authorization"];
|
|
160
|
+
if (authorizationHeader && !cacheAuthorizedRequests) {
|
|
161
|
+
loggy.info(`Authorized request bypassing cache: ${key}`);
|
|
162
|
+
await next();
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
158
165
|
if (cacheEntry && !noCache) {
|
|
159
166
|
loggy.info(`HIT with key: ${key}`);
|
|
160
167
|
ctx.status = 200;
|
|
161
168
|
ctx.body = cacheEntry.body;
|
|
162
169
|
ctx.set(cacheEntry.headers);
|
|
163
|
-
ctx.set({ "Access-Control-Allow-Origin": "*", "Content-Encoding": "identity" });
|
|
164
170
|
return;
|
|
165
171
|
}
|
|
166
172
|
await next();
|
|
@@ -171,15 +177,19 @@ const middleware$1 = async (ctx, next) => {
|
|
|
171
177
|
const contentEncoding = ctx.response.headers["content-encoding"];
|
|
172
178
|
const decompressed = await decompressBuffer(buf, contentEncoding);
|
|
173
179
|
const responseText = decodeBufferToText(decompressed);
|
|
174
|
-
|
|
180
|
+
const headersToStore = cacheHeaders ? ctx.response.headers : null;
|
|
181
|
+
await cacheStore.set(key, { body: responseText, headers: headersToStore });
|
|
175
182
|
ctx.body = buf;
|
|
176
183
|
} else {
|
|
177
|
-
|
|
184
|
+
const headersToStore = cacheHeaders ? ctx.response.headers : null;
|
|
185
|
+
await cacheStore.set(key, { body: ctx.body, headers: headersToStore });
|
|
178
186
|
}
|
|
179
187
|
}
|
|
180
188
|
};
|
|
181
189
|
const middleware = async (ctx, next) => {
|
|
182
190
|
const cacheService = strapi.plugin("strapi-cache").services.service;
|
|
191
|
+
const cacheHeaders = strapi.plugin("strapi-cache").config("cacheHeaders");
|
|
192
|
+
const cacheAuthorizedRequests = strapi.plugin("strapi-cache").config("cacheAuthorizedRequests");
|
|
183
193
|
const cacheStore = cacheService.getCacheInstance();
|
|
184
194
|
const { url } = ctx.request;
|
|
185
195
|
const originalReq = ctx.req;
|
|
@@ -196,38 +206,51 @@ const middleware = async (ctx, next) => {
|
|
|
196
206
|
clonedReq.connection = originalReq.connection;
|
|
197
207
|
ctx.req = clonedReq;
|
|
198
208
|
ctx.request.req = clonedReq;
|
|
199
|
-
const key = generateGraphqlCacheKey(body);
|
|
200
209
|
const isIntrospectionQuery = body.includes("IntrospectionQuery");
|
|
201
210
|
if (isIntrospectionQuery) {
|
|
202
211
|
loggy.info("Skipping cache for introspection query");
|
|
203
212
|
await next();
|
|
204
213
|
return;
|
|
205
214
|
}
|
|
215
|
+
const key = generateGraphqlCacheKey(body);
|
|
206
216
|
const cacheEntry = await cacheStore.get(key);
|
|
207
217
|
const cacheControlHeader = ctx.request.headers["cache-control"];
|
|
208
218
|
const noCache = cacheControlHeader && cacheControlHeader.includes("no-cache");
|
|
219
|
+
const authorizationHeader = ctx.request.headers["authorization"];
|
|
220
|
+
if (authorizationHeader && !cacheAuthorizedRequests) {
|
|
221
|
+
loggy.info(`Authorized request bypassing cache: ${key}`);
|
|
222
|
+
await next();
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
209
225
|
if (cacheEntry && !noCache) {
|
|
210
226
|
loggy.info(`HIT with key: ${key}`);
|
|
211
227
|
ctx.status = 200;
|
|
212
228
|
ctx.body = cacheEntry.body;
|
|
213
229
|
ctx.set(cacheEntry.headers);
|
|
214
|
-
ctx.set({ "Content-Encoding": "identity" });
|
|
215
230
|
return;
|
|
216
231
|
}
|
|
217
232
|
await next();
|
|
218
233
|
if (ctx.method === "POST" && ctx.status >= 200 && ctx.status < 300 && url.startsWith("/graphql")) {
|
|
219
234
|
loggy.info(`MISS with key: ${key}`);
|
|
235
|
+
const headers = ctx.request.headers;
|
|
236
|
+
const authorizationHeader2 = headers["authorization"];
|
|
237
|
+
if (authorizationHeader2 && !cacheAuthorizedRequests) {
|
|
238
|
+
loggy.info(`Authorized request not caching: ${key}`);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
220
241
|
if (ctx.body instanceof Stream__default.default) {
|
|
221
242
|
const buf = await streamToBuffer(ctx.body);
|
|
222
243
|
const contentEncoding = ctx.response.headers["content-encoding"];
|
|
223
244
|
const decompressed = await decompressBuffer(buf, contentEncoding);
|
|
224
245
|
const responseText = decodeBufferToText(decompressed);
|
|
225
|
-
|
|
246
|
+
const headersToStore = cacheHeaders ? ctx.response.headers : null;
|
|
247
|
+
await cacheStore.set(key, { body: responseText, headers: headersToStore });
|
|
226
248
|
ctx.body = buf;
|
|
227
249
|
} else {
|
|
250
|
+
const headersToStore = cacheHeaders ? ctx.response.headers : null;
|
|
228
251
|
await cacheStore.set(key, {
|
|
229
252
|
body: ctx.body,
|
|
230
|
-
headers:
|
|
253
|
+
headers: headersToStore
|
|
231
254
|
});
|
|
232
255
|
}
|
|
233
256
|
}
|
|
@@ -249,7 +272,9 @@ const config = {
|
|
|
249
272
|
allowStale: false,
|
|
250
273
|
cacheableRoutes: [],
|
|
251
274
|
provider: "memory",
|
|
252
|
-
|
|
275
|
+
redisConfig: env("REDIS_URL"),
|
|
276
|
+
cacheHeaders: true,
|
|
277
|
+
cacheAuthorizedRequests: false
|
|
253
278
|
}),
|
|
254
279
|
validator: (config2) => {
|
|
255
280
|
if (typeof config2.debug !== "boolean") {
|
|
@@ -276,8 +301,14 @@ const config = {
|
|
|
276
301
|
if (config2.provider !== "memory" && config2.provider !== "redis") {
|
|
277
302
|
throw new Error(`Invalid config: provider must be 'memory' or 'redis'`);
|
|
278
303
|
}
|
|
279
|
-
if (config2.provider === "redis" && !config2.
|
|
280
|
-
throw new Error(`Invalid config:
|
|
304
|
+
if (config2.provider === "redis" && !config2.redisConfig && (typeof config2.redisConfig !== "string" || typeof config2.redisConfig !== "object")) {
|
|
305
|
+
throw new Error(`Invalid config: redisConfig must be set when using redis provider`);
|
|
306
|
+
}
|
|
307
|
+
if (typeof config2.cacheHeaders !== "boolean") {
|
|
308
|
+
throw new Error(`Invalid config: cacheHeaders must be a boolean`);
|
|
309
|
+
}
|
|
310
|
+
if (typeof config2.cacheAuthorizedRequests !== "boolean") {
|
|
311
|
+
throw new Error(`Invalid config: cacheAuthorizedRequests must be a boolean`);
|
|
281
312
|
}
|
|
282
313
|
}
|
|
283
314
|
};
|
|
@@ -480,10 +511,14 @@ class RedisCacheProvider {
|
|
|
480
511
|
loggy.error("Redis provider already initialized");
|
|
481
512
|
return;
|
|
482
513
|
}
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
514
|
+
try {
|
|
515
|
+
const redisUrl = this.strapi.plugin("strapi-cache").config("redisConfig") || "redis://localhost:6379";
|
|
516
|
+
this.client = new Redis__default.default(redisUrl);
|
|
517
|
+
this.initialized = true;
|
|
518
|
+
loggy.info("Redis provider initialized");
|
|
519
|
+
} catch (error) {
|
|
520
|
+
loggy.error(error);
|
|
521
|
+
}
|
|
487
522
|
}
|
|
488
523
|
get ready() {
|
|
489
524
|
if (!this.initialized) {
|
package/dist/server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../server/src/utils/log.ts","../../server/src/utils/invalidateCache.ts","../../server/src/permissions.ts","../../server/src/bootstrap.ts","../../server/src/utils/key.ts","../../server/src/utils/body.ts","../../server/src/middlewares/cache.ts","../../server/src/middlewares/graphql.ts","../../server/src/middlewares/index.ts","../../server/src/register.ts","../../server/src/config/index.ts","../../server/src/content-types/index.ts","../../server/src/controllers/controller.ts","../../server/src/controllers/index.ts","../../server/src/policies/index.ts","../../server/src/routes/purge.ts","../../server/src/routes/index.ts","../../server/src/utils/withTimeout.ts","../../server/src/services/memory/provider.ts","../../server/src/services/redis/provider.ts","../../server/src/services/resolver.ts","../../server/src/services/index.ts","../../server/src/index.ts"],"sourcesContent":["export const loggy = {\n info: (msg: string) => {\n const shouldDebug = strapi.plugin('strapi-cache').config('debug') ?? false;\n if (!shouldDebug) {\n return;\n }\n strapi.log.info(`[STRAPI CACHE] ${msg}`);\n },\n error: (msg: string) => {\n const shouldDebug = strapi.plugin('strapi-cache').config('debug') ?? false;\n if (!shouldDebug) {\n return;\n }\n strapi.log.error(`[STRAPI CACHE] ${msg}`);\n },\n warn: (msg: string) => {\n const shouldDebug = strapi.plugin('strapi-cache').config('debug') ?? false;\n if (!shouldDebug) {\n return;\n }\n strapi.log.warn(`[STRAPI CACHE] ${msg}`);\n },\n};\n","import { Core } from '@strapi/strapi';\nimport { CacheProvider } from 'src/types/cache.types';\nimport { loggy } from './log';\n\nexport async function invalidateCache(event: any, cacheStore: CacheProvider, strapi: Core.Strapi) {\n const { model } = event;\n const uid = model.uid;\n\n try {\n const contentType = strapi.contentType(uid);\n\n if (!contentType || !contentType.kind) {\n loggy.info(`Content type ${uid} not found`);\n return;\n }\n\n const pluralName =\n contentType.kind === 'singleType'\n ? contentType.info.singularName\n : contentType.info.pluralName;\n const apiPath = `/api/${pluralName}`;\n const regex = new RegExp(`^.*:${apiPath}(/.*)?(\\\\?.*)?$`);\n\n await cacheStore.clearByRegexp([regex]);\n loggy.info(`Invalidated cache for ${apiPath}`);\n } catch (error) {\n loggy.error('Cache invalidation error:');\n loggy.error(error);\n }\n}\n\nexport async function invalidateGraphqlCache(\n event: any,\n cacheStore: CacheProvider,\n strapi: Core.Strapi\n) {\n try {\n const graphqlRegex = new RegExp(`^POST:\\/graphql(:.*)?$`);\n\n await cacheStore.clearByRegexp([graphqlRegex]);\n loggy.info(`Invalidated cache for ${graphqlRegex}`);\n } catch (error) {\n loggy.error('Cache invalidation error:');\n loggy.error(error);\n }\n}\n","export const actions = [\n {\n section: 'plugins',\n displayName: 'Purge Cache',\n uid: 'purge-cache',\n pluginName: 'strapi-cache',\n },\n];\n","import type { Core } from '@strapi/strapi';\nimport { invalidateCache, invalidateGraphqlCache } from './utils/invalidateCache';\nimport { CacheService } from './types/cache.types';\nimport { loggy } from './utils/log';\nimport { actions } from './permissions';\n\nconst bootstrap = ({ strapi }: { strapi: Core.Strapi }) => {\n loggy.info('Initializing');\n try {\n const cacheService = strapi.plugin('strapi-cache').services.service as CacheService;\n const cacheStore = cacheService.getCacheInstance();\n cacheStore.init();\n\n strapi.db.lifecycles.subscribe({\n async afterCreate(event) {\n await invalidateCache(event, cacheStore, strapi);\n await invalidateGraphqlCache(event, cacheStore, strapi);\n },\n async afterUpdate(event) {\n await invalidateCache(event, cacheStore, strapi);\n await invalidateGraphqlCache(event, cacheStore, strapi);\n },\n async afterDelete(event) {\n await invalidateCache(event, cacheStore, strapi);\n await invalidateGraphqlCache(event, cacheStore, strapi);\n },\n });\n\n if (!cacheStore) {\n loggy.error('Plugin could not be initialized');\n return;\n }\n } catch (error) {\n loggy.error('Plugin could not be initialized');\n return;\n }\n loggy.info('Plugin initialized');\n\n strapi.admin.services.permission.actionProvider.registerMany(actions);\n};\n\nexport default bootstrap;\n","import { createHash } from 'crypto';\nimport { Context } from 'koa';\n\nexport const generateCacheKey = (context: Context) => {\n const { url } = context.request;\n const decodedUrl = decodeURIComponent(url);\n const { method } = context.request;\n\n return `${method}:${decodedUrl}`;\n};\n\nexport const generateGraphqlCacheKey = (payload: string) => {\n const hash = createHash('sha256').update(payload).digest('base64url');\n return `POST:/graphql:${hash}`;\n};\n","import { Stream } from 'stream';\nimport { createGunzip, createBrotliDecompress, createInflate } from 'zlib';\n\nexport const streamToBuffer = (stream: Stream): Promise<Buffer> => {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n stream.on('data', (chunk) => chunks.push(chunk));\n stream.on('end', () => resolve(Buffer.concat(chunks)));\n stream.on('error', reject);\n });\n};\n\nexport const decompressBuffer = async (buffer: Buffer, encoding?: string): Promise<Buffer> => {\n return new Promise((resolve, reject) => {\n let decompressStream;\n switch (encoding) {\n case 'gzip':\n decompressStream = createGunzip();\n break;\n case 'br':\n decompressStream = createBrotliDecompress();\n break;\n case 'deflate':\n decompressStream = createInflate();\n break;\n default:\n return resolve(buffer);\n }\n\n const chunks: Buffer[] = [];\n decompressStream.on('data', (chunk) => chunks.push(chunk));\n decompressStream.on('end', () => resolve(Buffer.concat(chunks)));\n decompressStream.on('error', reject);\n\n decompressStream.end(buffer);\n });\n};\n\nexport const decodeBufferToText = (buffer: Buffer): string => {\n const decoder = new TextDecoder('utf-8');\n return decoder.decode(buffer);\n};\n","import { Context } from 'koa';\nimport { generateCacheKey } from '../utils/key';\nimport { CacheService } from '../../src/types/cache.types';\nimport { loggy } from '../utils/log';\nimport Stream from 'stream';\nimport { decodeBufferToText, decompressBuffer, streamToBuffer } from '../../src/utils/body';\n\nconst middleware = async (ctx: Context, next: any) => {\n const cacheService = strapi.plugin('strapi-cache').services.service as CacheService;\n const cacheableRoutes = strapi.plugin('strapi-cache').config('cacheableRoutes') as string[];\n const cacheStore = cacheService.getCacheInstance();\n const { url } = ctx.request;\n const key = generateCacheKey(ctx);\n const cacheEntry = await cacheStore.get(key);\n const cacheControlHeader = ctx.request.headers['cache-control'];\n const noCache = cacheControlHeader && cacheControlHeader.includes('no-cache');\n const routeIsCachable =\n cacheableRoutes.some((route) => url.startsWith(route)) ||\n (cacheableRoutes.length === 0 && url.startsWith('/api'));\n\n if (cacheEntry && !noCache) {\n loggy.info(`HIT with key: ${key}`);\n ctx.status = 200;\n ctx.body = cacheEntry.body;\n ctx.set(cacheEntry.headers);\n ctx.set({ 'Access-Control-Allow-Origin': '*', 'Content-Encoding': 'identity' });\n return;\n }\n\n await next();\n\n if (ctx.method === 'GET' && ctx.status >= 200 && ctx.status < 300 && routeIsCachable) {\n loggy.info(`MISS with key: ${key}`);\n\n if (ctx.body instanceof Stream) {\n const buf = await streamToBuffer(ctx.body);\n const contentEncoding = ctx.response.headers['content-encoding'];\n const decompressed = await decompressBuffer(buf, contentEncoding);\n const responseText = decodeBufferToText(decompressed);\n\n await cacheStore.set(key, { body: responseText, headers: ctx.response.headers });\n ctx.body = buf;\n } else {\n await cacheStore.set(key, { body: ctx.body, headers: ctx.response.headers });\n }\n }\n};\n\nexport default middleware;\n","import rawBody from 'raw-body';\nimport { generateGraphqlCacheKey } from '../utils/key';\nimport Stream, { Readable } from 'stream';\nimport { loggy } from '../utils/log';\nimport { CacheService } from '../../src/types/cache.types';\nimport { decodeBufferToText, decompressBuffer, streamToBuffer } from '../../src/utils/body';\n\nconst middleware = async (ctx: any, next: any) => {\n const cacheService = strapi.plugin('strapi-cache').services.service as CacheService;\n const cacheStore = cacheService.getCacheInstance();\n const { url } = ctx.request;\n\n const originalReq = ctx.req;\n const bodyBuffer = await rawBody(originalReq);\n const body = bodyBuffer.toString();\n\n const clonedReq = new Readable();\n clonedReq.push(bodyBuffer);\n clonedReq.push(null);\n\n (clonedReq as any).headers = { ...originalReq.headers };\n (clonedReq as any).method = originalReq.method;\n (clonedReq as any).url = originalReq.url;\n (clonedReq as any).httpVersion = originalReq.httpVersion;\n (clonedReq as any).socket = originalReq.socket;\n (clonedReq as any).connection = originalReq.connection;\n\n ctx.req = clonedReq;\n ctx.request.req = clonedReq;\n\n const key = generateGraphqlCacheKey(body);\n\n const isIntrospectionQuery = body.includes('IntrospectionQuery');\n if (isIntrospectionQuery) {\n loggy.info('Skipping cache for introspection query');\n await next();\n return;\n }\n\n const cacheEntry = await cacheStore.get(key);\n const cacheControlHeader = ctx.request.headers['cache-control'];\n const noCache = cacheControlHeader && cacheControlHeader.includes('no-cache');\n\n if (cacheEntry && !noCache) {\n loggy.info(`HIT with key: ${key}`);\n ctx.status = 200;\n ctx.body = cacheEntry.body;\n ctx.set(cacheEntry.headers);\n ctx.set({ 'Content-Encoding': 'identity' });\n return;\n }\n\n await next();\n\n if (\n ctx.method === 'POST' &&\n ctx.status >= 200 &&\n ctx.status < 300 &&\n url.startsWith('/graphql')\n ) {\n loggy.info(`MISS with key: ${key}`);\n\n if (ctx.body instanceof Stream) {\n const buf = await streamToBuffer(ctx.body);\n const contentEncoding = ctx.response.headers['content-encoding']; // e.g., gzip, br, deflate\n const decompressed = await decompressBuffer(buf, contentEncoding);\n const responseText = decodeBufferToText(decompressed);\n\n await cacheStore.set(key, { body: responseText, headers: ctx.response.headers });\n ctx.body = buf;\n } else {\n await cacheStore.set(key, {\n body: ctx.body,\n headers: ctx.response.headers,\n });\n }\n }\n};\n\nexport default middleware;\n","import cache from './cache';\nimport graphql from './graphql';\n\nexport default {\n graphql,\n cache,\n};\n","import type { Core } from '@strapi/strapi';\nimport middlewares from './middlewares';\n\nconst register = ({ strapi }: { strapi: Core.Strapi }) => {\n strapi.server.use(middlewares.cache);\n strapi.server.use(middlewares.graphql);\n};\n\nexport default register;\n","export default {\n default: ({ env }) => ({\n debug: false,\n max: 1000,\n ttl: 1000 * 60 * 60,\n size: 1024 * 1014 * 10,\n allowStale: false,\n cacheableRoutes: [],\n provider: 'memory',\n redisUrl: env('REDIS_URL'),\n }),\n validator: (config) => {\n if (typeof config.debug !== 'boolean') {\n throw new Error(`Invalid config: debug must be a boolean`);\n }\n if (typeof config.max !== 'number') {\n throw new Error(`Invalid config: max must be a number`);\n }\n if (typeof config.ttl !== 'number') {\n throw new Error(`Invalid config: ttl must be a number`);\n }\n if (typeof config.size !== 'number') {\n throw new Error(`Invalid config: size must be a number`);\n }\n if (typeof config.allowStale !== 'boolean') {\n throw new Error(`Invalid config: allowStale must be a boolean`);\n }\n if (\n !Array.isArray(config.cacheableRoutes) ||\n config.cacheableRoutes.some((item) => typeof item !== 'string')\n ) {\n throw new Error(`Invalid config: cacheableRoutes must be an string array`);\n }\n if (typeof config.provider !== 'string') {\n throw new Error(`Invalid config: provider must be a string`);\n }\n if (config.provider !== 'memory' && config.provider !== 'redis') {\n throw new Error(`Invalid config: provider must be 'memory' or 'redis'`);\n }\n if (config.provider === 'redis' && !config.redisUrl && typeof config.redisUrl !== 'string') {\n throw new Error(`Invalid config: redisUrl must be set when using redis provider`);\n }\n },\n};\n","export default {};\n","import type { Core } from '@strapi/strapi';\nimport { Context } from 'koa';\nimport { CacheService } from 'src/types/cache.types';\n\nconst controller = ({ strapi }: { strapi: Core.Strapi }) => ({\n async purgeCache(ctx: Context) {\n const service = strapi.plugin('strapi-cache').service('service') as CacheService;\n\n await service.getCacheInstance().reset();\n\n ctx.body = {\n message: 'Cache purged successfully',\n };\n },\n async purgeCacheByKey(ctx: Context) {\n const { key } = ctx.params;\n const service = strapi.plugin('strapi-cache').service('service') as CacheService;\n const regex = new RegExp(`(^|\\/)${key}(\\/|\\\\?|$)`);\n\n await service.getCacheInstance().clearByRegexp([regex]);\n\n ctx.body = {\n message: `Cache purged successfully for key: ${key}`,\n };\n },\n async cacheableRoutes(ctx: Context) {\n const cacheableRoutes = strapi.plugin('strapi-cache').config('cacheableRoutes');\n ctx.body = cacheableRoutes;\n },\n});\n\nexport default controller;\n","import controller from './controller';\n\nexport default {\n controller,\n};\n","export default {};\n","export default [\n {\n method: 'POST',\n path: '/purge-cache',\n handler: 'controller.purgeCache',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: {\n actions: ['plugin::strapi-cache.purge-cache'],\n },\n },\n ],\n },\n },\n {\n method: 'POST',\n path: '/purge-cache/:key',\n handler: 'controller.purgeCacheByKey',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: {\n actions: ['plugin::strapi-cache.purge-cache'],\n },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/cacheable-routes',\n handler: 'controller.cacheableRoutes',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: {\n actions: ['plugin::strapi-cache.purge-cache'],\n },\n },\n ],\n },\n },\n];\n","import purgeRoute from './purge';\n\nconst routes = {\n 'purge-route': {\n type: 'admin',\n routes: purgeRoute,\n },\n};\n\nexport default routes;\n","export const withTimeout = (callback: () => Promise<any>, ms: number) => {\n let timeout: NodeJS.Timeout | null = null;\n\n return Promise.race([\n callback().then((result) => {\n if (timeout) {\n clearTimeout(timeout);\n }\n return result;\n }),\n new Promise((_, reject) => {\n timeout = setTimeout(() => {\n reject(new Error('timeout'));\n }, ms);\n }),\n ]);\n};\n","import type { Core } from '@strapi/strapi';\nimport { LRUCache } from 'lru-cache';\nimport { withTimeout } from '../../utils/withTimeout';\nimport { CacheProvider, CacheService } from '../../types/cache.types';\nimport { loggy } from '../../utils/log';\n\nexport class InMemoryCacheProvider implements CacheProvider {\n private initialized = false;\n private provider!: LRUCache<string, any>;\n\n constructor(private strapi: Core.Strapi) {}\n\n init(): void {\n if (this.initialized) {\n loggy.error('Provider already initialized');\n return;\n }\n\n this.initialized = true;\n\n const max = Number(this.strapi.plugin('strapi-cache').config('max'));\n const ttl = Number(this.strapi.plugin('strapi-cache').config('ttl'));\n const size = Number(this.strapi.plugin('strapi-cache').config('size'));\n const allowStale = Boolean(this.strapi.plugin('strapi-cache').config('allowStale'));\n\n this.provider = new LRUCache({\n max,\n ttl,\n size,\n allowStale,\n });\n\n loggy.info('Provider initialized');\n }\n\n get ready(): boolean {\n if (!this.initialized) {\n loggy.info('Provider not initialized');\n return false;\n }\n\n return true;\n }\n\n async get(key: string): Promise<any | null> {\n if (!this.ready) return null;\n\n const timeout = 1000;\n return withTimeout(\n () =>\n new Promise((resolve) => {\n resolve(this.provider.get(key));\n }),\n timeout\n ).catch((error) => {\n loggy.error(`Error during get: ${error?.message || error}`);\n return null;\n });\n }\n\n async set(key: string, val: any): Promise<any | null> {\n if (!this.ready) return null;\n\n try {\n return this.provider.set(key, val);\n } catch (error) {\n loggy.error(`Error during set: ${error}`);\n return null;\n }\n }\n\n async del(key: string): Promise<any | null> {\n if (!this.ready) return null;\n\n try {\n loggy.info(`PURGING KEY: ${key}`);\n return this.provider.delete(key);\n } catch (error) {\n loggy.error(`Error during delete: ${error}`);\n return null;\n }\n }\n\n async keys(): Promise<string[] | null> {\n if (!this.ready) return null;\n\n try {\n return Array.from(this.provider.keys());\n } catch (error) {\n loggy.error(`Error fetching keys: ${error}`);\n return null;\n }\n }\n\n async reset(): Promise<any | null> {\n if (!this.ready) return null;\n\n try {\n const allKeys = await this.keys();\n if (!allKeys) return null;\n\n loggy.info(`PURGING ALL KEYS: ${allKeys.length}`);\n await Promise.all(allKeys.map((key) => this.del(key)));\n return true;\n } catch (error) {\n loggy.error(`Error during reset: ${error}`);\n return null;\n }\n }\n\n async clearByRegexp(regExps: RegExp[]): Promise<void> {\n const keys = (await this.keys()) || [];\n const matches = keys.filter((key) => regExps.some((re) => re.test(key)));\n await Promise.all(matches.map((key) => this.del(key)));\n }\n}\n","import type { Core } from '@strapi/strapi';\nimport Redis from 'ioredis';\nimport { withTimeout } from '../../utils/withTimeout';\nimport { CacheProvider } from '../../types/cache.types';\nimport { loggy } from '../../utils/log';\n\nexport class RedisCacheProvider implements CacheProvider {\n private initialized = false;\n private client!: Redis;\n\n constructor(private strapi: Core.Strapi) {}\n\n init(): void {\n if (this.initialized) {\n loggy.error('Redis provider already initialized');\n return;\n }\n\n const redisUrl =\n this.strapi.plugin('strapi-cache').config('redisUrl') || 'redis://localhost:6379';\n\n this.client = new Redis(redisUrl);\n this.initialized = true;\n\n loggy.info('Redis provider initialized');\n }\n\n get ready(): boolean {\n if (!this.initialized) {\n loggy.info('Redis provider not initialized');\n return false;\n }\n\n return true;\n }\n\n async get(key: string): Promise<any | null> {\n if (!this.ready) return null;\n\n const timeout = 1000;\n return withTimeout(() => this.client.get(key), timeout)\n .then((data) => (data ? JSON.parse(data) : null))\n .catch((error) => {\n loggy.error(`Redis get error: ${error?.message || error}`);\n return null;\n });\n }\n\n async set(key: string, val: any): Promise<any | null> {\n if (!this.ready) return null;\n\n try {\n const ttl = Number(this.strapi.plugin('strapi-cache').config('ttl'));\n const serialized = JSON.stringify(val);\n if (ttl > 0) {\n await this.client.set(key, serialized, 'EX', ttl);\n } else {\n await this.client.set(key, serialized);\n }\n return val;\n } catch (error) {\n loggy.error(`Redis set error: ${error}`);\n return null;\n }\n }\n\n async del(key: string): Promise<any | null> {\n if (!this.ready) return null;\n\n try {\n loggy.info(`Redis PURGING KEY: ${key}`);\n await this.client.del(key);\n return true;\n } catch (error) {\n loggy.error(`Redis del error: ${error}`);\n return null;\n }\n }\n\n async keys(): Promise<string[] | null> {\n if (!this.ready) return null;\n\n try {\n const keys = await this.client.keys('*');\n return keys;\n } catch (error) {\n loggy.error(`Redis keys error: ${error}`);\n return null;\n }\n }\n\n async reset(): Promise<any | null> {\n if (!this.ready) return null;\n\n try {\n loggy.info(`Redis FLUSHING ALL KEYS`);\n await this.client.flushdb();\n return true;\n } catch (error) {\n loggy.error(`Redis reset error: ${error}`);\n return null;\n }\n }\n\n async clearByRegexp(regExps: RegExp[]): Promise<void> {\n const keys = await this.keys();\n if (!keys) return;\n\n const toDelete = keys.filter((key) => regExps.some((re) => re.test(key)));\n await Promise.all(toDelete.map((key) => this.del(key)));\n }\n}\n","import type { Core } from '@strapi/strapi';\nimport { InMemoryCacheProvider } from './memory/provider';\nimport { RedisCacheProvider } from './redis/provider';\nimport { CacheProvider } from '../../src/types/cache.types';\nimport { loggy } from '../../src/utils/log';\n\nexport const resolveCacheProvider = (strapi: Core.Strapi): CacheProvider => {\n const providerType = strapi.plugin('strapi-cache').config('provider') || 'memory';\n\n loggy.info(`Selected cache provider: ${providerType}`);\n\n let instance: CacheProvider;\n\n switch (providerType) {\n case 'redis':\n instance = new RedisCacheProvider(strapi);\n break;\n default:\n instance = new InMemoryCacheProvider(strapi);\n break;\n }\n\n return instance;\n};\n","import type { Core } from '@strapi/strapi';\nimport { resolveCacheProvider } from './resolver';\nimport { CacheProvider, CacheService } from '../../src/types/cache.types';\nimport { loggy } from '../../src/utils/log';\n\nconst service = ({ strapi }: { strapi: Core.Strapi }): CacheService => {\n let instance: null | CacheProvider = null;\n\n return {\n getCacheInstance() {\n if (!instance) {\n loggy.info('Initializing cache service from provider config...');\n instance = resolveCacheProvider(strapi);\n }\n return instance;\n },\n };\n};\n\nexport default {\n service,\n};\n","/**\n * Application methods\n */\nimport bootstrap from './bootstrap';\nimport register from './register';\n\n/**\n * Plugin server methods\n */\nimport config from './config';\nimport contentTypes from './content-types';\nimport controllers from './controllers';\nimport middlewares from './middlewares';\nimport policies from './policies';\nimport routes from './routes';\nimport services from './services';\n\nexport default {\n register,\n bootstrap,\n destroy() {},\n config,\n controllers,\n routes,\n services,\n contentTypes,\n policies,\n middlewares,\n};\n"],"names":["strapi","createHash","createGunzip","createBrotliDecompress","createInflate","middleware","Stream","rawBody","Readable","graphql","cache","config","service","LRUCache","Redis"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../server/src/utils/log.ts","../../server/src/utils/invalidateCache.ts","../../server/src/permissions.ts","../../server/src/bootstrap.ts","../../server/src/utils/key.ts","../../server/src/utils/body.ts","../../server/src/middlewares/cache.ts","../../server/src/middlewares/graphql.ts","../../server/src/middlewares/index.ts","../../server/src/register.ts","../../server/src/config/index.ts","../../server/src/content-types/index.ts","../../server/src/controllers/controller.ts","../../server/src/controllers/index.ts","../../server/src/policies/index.ts","../../server/src/routes/purge.ts","../../server/src/routes/index.ts","../../server/src/utils/withTimeout.ts","../../server/src/services/memory/provider.ts","../../server/src/services/redis/provider.ts","../../server/src/services/resolver.ts","../../server/src/services/index.ts","../../server/src/index.ts"],"sourcesContent":["export const loggy = {\n info: (msg: string) => {\n const shouldDebug = strapi.plugin('strapi-cache').config('debug') ?? false;\n if (!shouldDebug) {\n return;\n }\n strapi.log.info(`[STRAPI CACHE] ${msg}`);\n },\n error: (msg: string) => {\n const shouldDebug = strapi.plugin('strapi-cache').config('debug') ?? false;\n if (!shouldDebug) {\n return;\n }\n strapi.log.error(`[STRAPI CACHE] ${msg}`);\n },\n warn: (msg: string) => {\n const shouldDebug = strapi.plugin('strapi-cache').config('debug') ?? false;\n if (!shouldDebug) {\n return;\n }\n strapi.log.warn(`[STRAPI CACHE] ${msg}`);\n },\n};\n","import { Core } from '@strapi/strapi';\nimport { CacheProvider } from 'src/types/cache.types';\nimport { loggy } from './log';\n\nexport async function invalidateCache(event: any, cacheStore: CacheProvider, strapi: Core.Strapi) {\n const { model } = event;\n const uid = model.uid;\n\n try {\n const contentType = strapi.contentType(uid);\n\n if (!contentType || !contentType.kind) {\n loggy.info(`Content type ${uid} not found`);\n return;\n }\n\n const pluralName =\n contentType.kind === 'singleType'\n ? contentType.info.singularName\n : contentType.info.pluralName;\n const apiPath = `/api/${pluralName}`;\n const regex = new RegExp(`^.*:${apiPath}(/.*)?(\\\\?.*)?$`);\n\n await cacheStore.clearByRegexp([regex]);\n loggy.info(`Invalidated cache for ${apiPath}`);\n } catch (error) {\n loggy.error('Cache invalidation error:');\n loggy.error(error);\n }\n}\n\nexport async function invalidateGraphqlCache(\n event: any,\n cacheStore: CacheProvider,\n strapi: Core.Strapi\n) {\n try {\n const graphqlRegex = new RegExp(`^POST:\\/graphql(:.*)?$`);\n\n await cacheStore.clearByRegexp([graphqlRegex]);\n loggy.info(`Invalidated cache for ${graphqlRegex}`);\n } catch (error) {\n loggy.error('Cache invalidation error:');\n loggy.error(error);\n }\n}\n","export const actions = [\n {\n section: 'plugins',\n displayName: 'Purge Cache',\n uid: 'purge-cache',\n pluginName: 'strapi-cache',\n },\n];\n","import type { Core } from '@strapi/strapi';\nimport { invalidateCache, invalidateGraphqlCache } from './utils/invalidateCache';\nimport { CacheService } from './types/cache.types';\nimport { loggy } from './utils/log';\nimport { actions } from './permissions';\n\nconst bootstrap = ({ strapi }: { strapi: Core.Strapi }) => {\n loggy.info('Initializing');\n try {\n const cacheService = strapi.plugin('strapi-cache').services.service as CacheService;\n const cacheStore = cacheService.getCacheInstance();\n cacheStore.init();\n\n strapi.db.lifecycles.subscribe({\n async afterCreate(event) {\n await invalidateCache(event, cacheStore, strapi);\n await invalidateGraphqlCache(event, cacheStore, strapi);\n },\n async afterUpdate(event) {\n await invalidateCache(event, cacheStore, strapi);\n await invalidateGraphqlCache(event, cacheStore, strapi);\n },\n async afterDelete(event) {\n await invalidateCache(event, cacheStore, strapi);\n await invalidateGraphqlCache(event, cacheStore, strapi);\n },\n });\n\n if (!cacheStore) {\n loggy.error('Plugin could not be initialized');\n return;\n }\n } catch (error) {\n loggy.error('Plugin could not be initialized');\n return;\n }\n loggy.info('Plugin initialized');\n\n strapi.admin.services.permission.actionProvider.registerMany(actions);\n};\n\nexport default bootstrap;\n","import { createHash } from 'crypto';\nimport { Context } from 'koa';\n\nexport const generateCacheKey = (context: Context) => {\n const { url } = context.request;\n const { method } = context.request;\n\n return `${method}:${url}`;\n};\n\nexport const generateGraphqlCacheKey = (payload: string) => {\n const hash = createHash('sha256').update(payload).digest('base64url');\n return `POST:/graphql:${hash}`;\n};\n","import { Stream } from 'stream';\nimport { createGunzip, createBrotliDecompress, createInflate } from 'zlib';\n\nexport const streamToBuffer = (stream: Stream): Promise<Buffer> => {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n stream.on('data', (chunk) => chunks.push(chunk));\n stream.on('end', () => resolve(Buffer.concat(chunks)));\n stream.on('error', reject);\n });\n};\n\nexport const decompressBuffer = async (buffer: Buffer, encoding?: string): Promise<Buffer> => {\n return new Promise((resolve, reject) => {\n let decompressStream;\n switch (encoding) {\n case 'gzip':\n decompressStream = createGunzip();\n break;\n case 'br':\n decompressStream = createBrotliDecompress();\n break;\n case 'deflate':\n decompressStream = createInflate();\n break;\n default:\n return resolve(buffer);\n }\n\n const chunks: Buffer[] = [];\n decompressStream.on('data', (chunk) => chunks.push(chunk));\n decompressStream.on('end', () => resolve(Buffer.concat(chunks)));\n decompressStream.on('error', reject);\n\n decompressStream.end(buffer);\n });\n};\n\nexport const decodeBufferToText = (buffer: Buffer): string => {\n const decoder = new TextDecoder('utf-8');\n return decoder.decode(buffer);\n};\n","import { Context } from 'koa';\nimport { generateCacheKey } from '../utils/key';\nimport { CacheService } from '../../src/types/cache.types';\nimport { loggy } from '../utils/log';\nimport Stream from 'stream';\nimport { decodeBufferToText, decompressBuffer, streamToBuffer } from '../../src/utils/body';\n\nconst middleware = async (ctx: Context, next: any) => {\n const cacheService = strapi.plugin('strapi-cache').services.service as CacheService;\n const cacheableRoutes = strapi.plugin('strapi-cache').config('cacheableRoutes') as string[];\n const cacheHeaders = strapi.plugin('strapi-cache').config('cacheHeaders') as boolean;\n const cacheAuthorizedRequests = strapi\n .plugin('strapi-cache')\n .config('cacheAuthorizedRequests') as boolean;\n const cacheStore = cacheService.getCacheInstance();\n const { url } = ctx.request;\n const key = generateCacheKey(ctx);\n const cacheEntry = await cacheStore.get(key);\n const cacheControlHeader = ctx.request.headers['cache-control'];\n const noCache = cacheControlHeader && cacheControlHeader.includes('no-cache');\n const routeIsCachable =\n cacheableRoutes.some((route) => url.startsWith(route)) ||\n (cacheableRoutes.length === 0 && url.startsWith('/api'));\n const authorizationHeader = ctx.request.headers['authorization'];\n\n if (authorizationHeader && !cacheAuthorizedRequests) {\n loggy.info(`Authorized request bypassing cache: ${key}`);\n await next();\n return;\n }\n\n if (cacheEntry && !noCache) {\n loggy.info(`HIT with key: ${key}`);\n ctx.status = 200;\n ctx.body = cacheEntry.body;\n ctx.set(cacheEntry.headers);\n return;\n }\n\n await next();\n\n if (ctx.method === 'GET' && ctx.status >= 200 && ctx.status < 300 && routeIsCachable) {\n loggy.info(`MISS with key: ${key}`);\n\n if (ctx.body instanceof Stream) {\n const buf = await streamToBuffer(ctx.body);\n const contentEncoding = ctx.response.headers['content-encoding'];\n const decompressed = await decompressBuffer(buf, contentEncoding);\n const responseText = decodeBufferToText(decompressed);\n\n const headersToStore = cacheHeaders ? ctx.response.headers : null;\n await cacheStore.set(key, { body: responseText, headers: headersToStore });\n ctx.body = buf;\n } else {\n const headersToStore = cacheHeaders ? ctx.response.headers : null;\n await cacheStore.set(key, { body: ctx.body, headers: headersToStore });\n }\n }\n};\n\nexport default middleware;\n","import rawBody from 'raw-body';\nimport { generateGraphqlCacheKey } from '../utils/key';\nimport Stream, { Readable } from 'stream';\nimport { loggy } from '../utils/log';\nimport { CacheService } from '../../src/types/cache.types';\nimport { decodeBufferToText, decompressBuffer, streamToBuffer } from '../../src/utils/body';\n\nconst middleware = async (ctx: any, next: any) => {\n const cacheService = strapi.plugin('strapi-cache').services.service as CacheService;\n const cacheHeaders = strapi.plugin('strapi-cache').config('cacheHeaders') as boolean;\n const cacheAuthorizedRequests = strapi\n .plugin('strapi-cache')\n .config('cacheAuthorizedRequests') as boolean;\n const cacheStore = cacheService.getCacheInstance();\n const { url } = ctx.request;\n\n const originalReq = ctx.req;\n const bodyBuffer = await rawBody(originalReq);\n const body = bodyBuffer.toString();\n\n const clonedReq = new Readable();\n clonedReq.push(bodyBuffer);\n clonedReq.push(null);\n\n (clonedReq as any).headers = { ...originalReq.headers };\n (clonedReq as any).method = originalReq.method;\n (clonedReq as any).url = originalReq.url;\n (clonedReq as any).httpVersion = originalReq.httpVersion;\n (clonedReq as any).socket = originalReq.socket;\n (clonedReq as any).connection = originalReq.connection;\n\n ctx.req = clonedReq;\n ctx.request.req = clonedReq;\n\n const isIntrospectionQuery = body.includes('IntrospectionQuery');\n if (isIntrospectionQuery) {\n loggy.info('Skipping cache for introspection query');\n await next();\n return;\n }\n\n const key = generateGraphqlCacheKey(body);\n const cacheEntry = await cacheStore.get(key);\n const cacheControlHeader = ctx.request.headers['cache-control'];\n const noCache = cacheControlHeader && cacheControlHeader.includes('no-cache');\n const authorizationHeader = ctx.request.headers['authorization'];\n\n if (authorizationHeader && !cacheAuthorizedRequests) {\n loggy.info(`Authorized request bypassing cache: ${key}`);\n await next();\n return;\n }\n\n if (cacheEntry && !noCache) {\n loggy.info(`HIT with key: ${key}`);\n ctx.status = 200;\n ctx.body = cacheEntry.body;\n ctx.set(cacheEntry.headers);\n return;\n }\n\n await next();\n\n if (\n ctx.method === 'POST' &&\n ctx.status >= 200 &&\n ctx.status < 300 &&\n url.startsWith('/graphql')\n ) {\n loggy.info(`MISS with key: ${key}`);\n const headers = ctx.request.headers;\n const authorizationHeader = headers['authorization'];\n if (authorizationHeader && !cacheAuthorizedRequests) {\n loggy.info(`Authorized request not caching: ${key}`);\n return;\n }\n\n if (ctx.body instanceof Stream) {\n const buf = await streamToBuffer(ctx.body);\n const contentEncoding = ctx.response.headers['content-encoding']; // e.g., gzip, br, deflate\n const decompressed = await decompressBuffer(buf, contentEncoding);\n const responseText = decodeBufferToText(decompressed);\n\n const headersToStore = cacheHeaders ? ctx.response.headers : null;\n await cacheStore.set(key, { body: responseText, headers: headersToStore });\n ctx.body = buf;\n } else {\n const headersToStore = cacheHeaders ? ctx.response.headers : null;\n await cacheStore.set(key, {\n body: ctx.body,\n headers: headersToStore,\n });\n }\n }\n};\n\nexport default middleware;\n","import cache from './cache';\nimport graphql from './graphql';\n\nexport default {\n graphql,\n cache,\n};\n","import type { Core } from '@strapi/strapi';\nimport middlewares from './middlewares';\n\nconst register = ({ strapi }: { strapi: Core.Strapi }) => {\n strapi.server.use(middlewares.cache);\n strapi.server.use(middlewares.graphql);\n};\n\nexport default register;\n","export default {\n default: ({ env }) => ({\n debug: false,\n max: 1000,\n ttl: 1000 * 60 * 60,\n size: 1024 * 1014 * 10,\n allowStale: false,\n cacheableRoutes: [],\n provider: 'memory',\n redisConfig: env('REDIS_URL'),\n cacheHeaders: true,\n cacheAuthorizedRequests: false,\n }),\n validator: (config) => {\n if (typeof config.debug !== 'boolean') {\n throw new Error(`Invalid config: debug must be a boolean`);\n }\n if (typeof config.max !== 'number') {\n throw new Error(`Invalid config: max must be a number`);\n }\n if (typeof config.ttl !== 'number') {\n throw new Error(`Invalid config: ttl must be a number`);\n }\n if (typeof config.size !== 'number') {\n throw new Error(`Invalid config: size must be a number`);\n }\n if (typeof config.allowStale !== 'boolean') {\n throw new Error(`Invalid config: allowStale must be a boolean`);\n }\n if (\n !Array.isArray(config.cacheableRoutes) ||\n config.cacheableRoutes.some((item) => typeof item !== 'string')\n ) {\n throw new Error(`Invalid config: cacheableRoutes must be an string array`);\n }\n if (typeof config.provider !== 'string') {\n throw new Error(`Invalid config: provider must be a string`);\n }\n if (config.provider !== 'memory' && config.provider !== 'redis') {\n throw new Error(`Invalid config: provider must be 'memory' or 'redis'`);\n }\n if (\n config.provider === 'redis' &&\n !config.redisConfig &&\n (typeof config.redisConfig !== 'string' || typeof config.redisConfig !== 'object')\n ) {\n throw new Error(`Invalid config: redisConfig must be set when using redis provider`);\n }\n if (typeof config.cacheHeaders !== 'boolean') {\n throw new Error(`Invalid config: cacheHeaders must be a boolean`);\n }\n if (typeof config.cacheAuthorizedRequests !== 'boolean') {\n throw new Error(`Invalid config: cacheAuthorizedRequests must be a boolean`);\n }\n },\n};\n","export default {};\n","import type { Core } from '@strapi/strapi';\nimport { Context } from 'koa';\nimport { CacheService } from 'src/types/cache.types';\n\nconst controller = ({ strapi }: { strapi: Core.Strapi }) => ({\n async purgeCache(ctx: Context) {\n const service = strapi.plugin('strapi-cache').service('service') as CacheService;\n\n await service.getCacheInstance().reset();\n\n ctx.body = {\n message: 'Cache purged successfully',\n };\n },\n async purgeCacheByKey(ctx: Context) {\n const { key } = ctx.params;\n const service = strapi.plugin('strapi-cache').service('service') as CacheService;\n const regex = new RegExp(`(^|\\/)${key}(\\/|\\\\?|$)`);\n\n await service.getCacheInstance().clearByRegexp([regex]);\n\n ctx.body = {\n message: `Cache purged successfully for key: ${key}`,\n };\n },\n async cacheableRoutes(ctx: Context) {\n const cacheableRoutes = strapi.plugin('strapi-cache').config('cacheableRoutes');\n ctx.body = cacheableRoutes;\n },\n});\n\nexport default controller;\n","import controller from './controller';\n\nexport default {\n controller,\n};\n","export default {};\n","export default [\n {\n method: 'POST',\n path: '/purge-cache',\n handler: 'controller.purgeCache',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: {\n actions: ['plugin::strapi-cache.purge-cache'],\n },\n },\n ],\n },\n },\n {\n method: 'POST',\n path: '/purge-cache/:key',\n handler: 'controller.purgeCacheByKey',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: {\n actions: ['plugin::strapi-cache.purge-cache'],\n },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/cacheable-routes',\n handler: 'controller.cacheableRoutes',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: {\n actions: ['plugin::strapi-cache.purge-cache'],\n },\n },\n ],\n },\n },\n];\n","import purgeRoute from './purge';\n\nconst routes = {\n 'purge-route': {\n type: 'admin',\n routes: purgeRoute,\n },\n};\n\nexport default routes;\n","export const withTimeout = (callback: () => Promise<any>, ms: number) => {\n let timeout: NodeJS.Timeout | null = null;\n\n return Promise.race([\n callback().then((result) => {\n if (timeout) {\n clearTimeout(timeout);\n }\n return result;\n }),\n new Promise((_, reject) => {\n timeout = setTimeout(() => {\n reject(new Error('timeout'));\n }, ms);\n }),\n ]);\n};\n","import type { Core } from '@strapi/strapi';\nimport { LRUCache } from 'lru-cache';\nimport { withTimeout } from '../../utils/withTimeout';\nimport { CacheProvider, CacheService } from '../../types/cache.types';\nimport { loggy } from '../../utils/log';\n\nexport class InMemoryCacheProvider implements CacheProvider {\n private initialized = false;\n private provider!: LRUCache<string, any>;\n\n constructor(private strapi: Core.Strapi) {}\n\n init(): void {\n if (this.initialized) {\n loggy.error('Provider already initialized');\n return;\n }\n\n this.initialized = true;\n\n const max = Number(this.strapi.plugin('strapi-cache').config('max'));\n const ttl = Number(this.strapi.plugin('strapi-cache').config('ttl'));\n const size = Number(this.strapi.plugin('strapi-cache').config('size'));\n const allowStale = Boolean(this.strapi.plugin('strapi-cache').config('allowStale'));\n\n this.provider = new LRUCache({\n max,\n ttl,\n size,\n allowStale,\n });\n\n loggy.info('Provider initialized');\n }\n\n get ready(): boolean {\n if (!this.initialized) {\n loggy.info('Provider not initialized');\n return false;\n }\n\n return true;\n }\n\n async get(key: string): Promise<any | null> {\n if (!this.ready) return null;\n\n const timeout = 1000;\n return withTimeout(\n () =>\n new Promise((resolve) => {\n resolve(this.provider.get(key));\n }),\n timeout\n ).catch((error) => {\n loggy.error(`Error during get: ${error?.message || error}`);\n return null;\n });\n }\n\n async set(key: string, val: any): Promise<any | null> {\n if (!this.ready) return null;\n\n try {\n return this.provider.set(key, val);\n } catch (error) {\n loggy.error(`Error during set: ${error}`);\n return null;\n }\n }\n\n async del(key: string): Promise<any | null> {\n if (!this.ready) return null;\n\n try {\n loggy.info(`PURGING KEY: ${key}`);\n return this.provider.delete(key);\n } catch (error) {\n loggy.error(`Error during delete: ${error}`);\n return null;\n }\n }\n\n async keys(): Promise<string[] | null> {\n if (!this.ready) return null;\n\n try {\n return Array.from(this.provider.keys());\n } catch (error) {\n loggy.error(`Error fetching keys: ${error}`);\n return null;\n }\n }\n\n async reset(): Promise<any | null> {\n if (!this.ready) return null;\n\n try {\n const allKeys = await this.keys();\n if (!allKeys) return null;\n\n loggy.info(`PURGING ALL KEYS: ${allKeys.length}`);\n await Promise.all(allKeys.map((key) => this.del(key)));\n return true;\n } catch (error) {\n loggy.error(`Error during reset: ${error}`);\n return null;\n }\n }\n\n async clearByRegexp(regExps: RegExp[]): Promise<void> {\n const keys = (await this.keys()) || [];\n const matches = keys.filter((key) => regExps.some((re) => re.test(key)));\n await Promise.all(matches.map((key) => this.del(key)));\n }\n}\n","import type { Core } from '@strapi/strapi';\nimport Redis from 'ioredis';\nimport { withTimeout } from '../../utils/withTimeout';\nimport { CacheProvider } from '../../types/cache.types';\nimport { loggy } from '../../utils/log';\n\nexport class RedisCacheProvider implements CacheProvider {\n private initialized = false;\n private client!: Redis;\n\n constructor(private strapi: Core.Strapi) {}\n\n init(): void {\n if (this.initialized) {\n loggy.error('Redis provider already initialized');\n return;\n }\n try {\n const redisUrl =\n this.strapi.plugin('strapi-cache').config('redisConfig') || 'redis://localhost:6379';\n this.client = new Redis(redisUrl);\n this.initialized = true;\n\n loggy.info('Redis provider initialized');\n } catch (error) {\n loggy.error(error);\n }\n }\n\n get ready(): boolean {\n if (!this.initialized) {\n loggy.info('Redis provider not initialized');\n return false;\n }\n\n return true;\n }\n\n async get(key: string): Promise<any | null> {\n if (!this.ready) return null;\n\n const timeout = 1000;\n return withTimeout(() => this.client.get(key), timeout)\n .then((data) => (data ? JSON.parse(data) : null))\n .catch((error) => {\n loggy.error(`Redis get error: ${error?.message || error}`);\n return null;\n });\n }\n\n async set(key: string, val: any): Promise<any | null> {\n if (!this.ready) return null;\n\n try {\n const ttl = Number(this.strapi.plugin('strapi-cache').config('ttl'));\n const serialized = JSON.stringify(val);\n if (ttl > 0) {\n await this.client.set(key, serialized, 'EX', ttl);\n } else {\n await this.client.set(key, serialized);\n }\n return val;\n } catch (error) {\n loggy.error(`Redis set error: ${error}`);\n return null;\n }\n }\n\n async del(key: string): Promise<any | null> {\n if (!this.ready) return null;\n\n try {\n loggy.info(`Redis PURGING KEY: ${key}`);\n await this.client.del(key);\n return true;\n } catch (error) {\n loggy.error(`Redis del error: ${error}`);\n return null;\n }\n }\n\n async keys(): Promise<string[] | null> {\n if (!this.ready) return null;\n\n try {\n const keys = await this.client.keys('*');\n return keys;\n } catch (error) {\n loggy.error(`Redis keys error: ${error}`);\n return null;\n }\n }\n\n async reset(): Promise<any | null> {\n if (!this.ready) return null;\n\n try {\n loggy.info(`Redis FLUSHING ALL KEYS`);\n await this.client.flushdb();\n return true;\n } catch (error) {\n loggy.error(`Redis reset error: ${error}`);\n return null;\n }\n }\n\n async clearByRegexp(regExps: RegExp[]): Promise<void> {\n const keys = await this.keys();\n if (!keys) return;\n\n const toDelete = keys.filter((key) => regExps.some((re) => re.test(key)));\n await Promise.all(toDelete.map((key) => this.del(key)));\n }\n}\n","import type { Core } from '@strapi/strapi';\nimport { InMemoryCacheProvider } from './memory/provider';\nimport { RedisCacheProvider } from './redis/provider';\nimport { CacheProvider } from '../../src/types/cache.types';\nimport { loggy } from '../../src/utils/log';\n\nexport const resolveCacheProvider = (strapi: Core.Strapi): CacheProvider => {\n const providerType = strapi.plugin('strapi-cache').config('provider') || 'memory';\n\n loggy.info(`Selected cache provider: ${providerType}`);\n\n let instance: CacheProvider;\n\n switch (providerType) {\n case 'redis':\n instance = new RedisCacheProvider(strapi);\n break;\n default:\n instance = new InMemoryCacheProvider(strapi);\n break;\n }\n\n return instance;\n};\n","import type { Core } from '@strapi/strapi';\nimport { resolveCacheProvider } from './resolver';\nimport { CacheProvider, CacheService } from '../../src/types/cache.types';\nimport { loggy } from '../../src/utils/log';\n\nconst service = ({ strapi }: { strapi: Core.Strapi }): CacheService => {\n let instance: null | CacheProvider = null;\n\n return {\n getCacheInstance() {\n if (!instance) {\n loggy.info('Initializing cache service from provider config...');\n instance = resolveCacheProvider(strapi);\n }\n return instance;\n },\n };\n};\n\nexport default {\n service,\n};\n","/**\n * Application methods\n */\nimport bootstrap from './bootstrap';\nimport register from './register';\n\n/**\n * Plugin server methods\n */\nimport config from './config';\nimport contentTypes from './content-types';\nimport controllers from './controllers';\nimport middlewares from './middlewares';\nimport policies from './policies';\nimport routes from './routes';\nimport services from './services';\n\nexport default {\n register,\n bootstrap,\n destroy() {},\n config,\n controllers,\n routes,\n services,\n contentTypes,\n policies,\n middlewares,\n};\n"],"names":["strapi","createHash","createGunzip","createBrotliDecompress","createInflate","middleware","Stream","rawBody","Readable","authorizationHeader","graphql","cache","config","service","LRUCache","Redis"],"mappings":"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"}
|
package/dist/server/index.mjs
CHANGED
|
@@ -97,9 +97,8 @@ const bootstrap = ({ strapi: strapi2 }) => {
|
|
|
97
97
|
};
|
|
98
98
|
const generateCacheKey = (context) => {
|
|
99
99
|
const { url } = context.request;
|
|
100
|
-
const decodedUrl = decodeURIComponent(url);
|
|
101
100
|
const { method } = context.request;
|
|
102
|
-
return `${method}:${
|
|
101
|
+
return `${method}:${url}`;
|
|
103
102
|
};
|
|
104
103
|
const generateGraphqlCacheKey = (payload) => {
|
|
105
104
|
const hash = createHash("sha256").update(payload).digest("base64url");
|
|
@@ -143,6 +142,8 @@ const decodeBufferToText = (buffer) => {
|
|
|
143
142
|
const middleware$1 = async (ctx, next) => {
|
|
144
143
|
const cacheService = strapi.plugin("strapi-cache").services.service;
|
|
145
144
|
const cacheableRoutes = strapi.plugin("strapi-cache").config("cacheableRoutes");
|
|
145
|
+
const cacheHeaders = strapi.plugin("strapi-cache").config("cacheHeaders");
|
|
146
|
+
const cacheAuthorizedRequests = strapi.plugin("strapi-cache").config("cacheAuthorizedRequests");
|
|
146
147
|
const cacheStore = cacheService.getCacheInstance();
|
|
147
148
|
const { url } = ctx.request;
|
|
148
149
|
const key = generateCacheKey(ctx);
|
|
@@ -150,12 +151,17 @@ const middleware$1 = async (ctx, next) => {
|
|
|
150
151
|
const cacheControlHeader = ctx.request.headers["cache-control"];
|
|
151
152
|
const noCache = cacheControlHeader && cacheControlHeader.includes("no-cache");
|
|
152
153
|
const routeIsCachable = cacheableRoutes.some((route) => url.startsWith(route)) || cacheableRoutes.length === 0 && url.startsWith("/api");
|
|
154
|
+
const authorizationHeader = ctx.request.headers["authorization"];
|
|
155
|
+
if (authorizationHeader && !cacheAuthorizedRequests) {
|
|
156
|
+
loggy.info(`Authorized request bypassing cache: ${key}`);
|
|
157
|
+
await next();
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
153
160
|
if (cacheEntry && !noCache) {
|
|
154
161
|
loggy.info(`HIT with key: ${key}`);
|
|
155
162
|
ctx.status = 200;
|
|
156
163
|
ctx.body = cacheEntry.body;
|
|
157
164
|
ctx.set(cacheEntry.headers);
|
|
158
|
-
ctx.set({ "Access-Control-Allow-Origin": "*", "Content-Encoding": "identity" });
|
|
159
165
|
return;
|
|
160
166
|
}
|
|
161
167
|
await next();
|
|
@@ -166,15 +172,19 @@ const middleware$1 = async (ctx, next) => {
|
|
|
166
172
|
const contentEncoding = ctx.response.headers["content-encoding"];
|
|
167
173
|
const decompressed = await decompressBuffer(buf, contentEncoding);
|
|
168
174
|
const responseText = decodeBufferToText(decompressed);
|
|
169
|
-
|
|
175
|
+
const headersToStore = cacheHeaders ? ctx.response.headers : null;
|
|
176
|
+
await cacheStore.set(key, { body: responseText, headers: headersToStore });
|
|
170
177
|
ctx.body = buf;
|
|
171
178
|
} else {
|
|
172
|
-
|
|
179
|
+
const headersToStore = cacheHeaders ? ctx.response.headers : null;
|
|
180
|
+
await cacheStore.set(key, { body: ctx.body, headers: headersToStore });
|
|
173
181
|
}
|
|
174
182
|
}
|
|
175
183
|
};
|
|
176
184
|
const middleware = async (ctx, next) => {
|
|
177
185
|
const cacheService = strapi.plugin("strapi-cache").services.service;
|
|
186
|
+
const cacheHeaders = strapi.plugin("strapi-cache").config("cacheHeaders");
|
|
187
|
+
const cacheAuthorizedRequests = strapi.plugin("strapi-cache").config("cacheAuthorizedRequests");
|
|
178
188
|
const cacheStore = cacheService.getCacheInstance();
|
|
179
189
|
const { url } = ctx.request;
|
|
180
190
|
const originalReq = ctx.req;
|
|
@@ -191,38 +201,51 @@ const middleware = async (ctx, next) => {
|
|
|
191
201
|
clonedReq.connection = originalReq.connection;
|
|
192
202
|
ctx.req = clonedReq;
|
|
193
203
|
ctx.request.req = clonedReq;
|
|
194
|
-
const key = generateGraphqlCacheKey(body);
|
|
195
204
|
const isIntrospectionQuery = body.includes("IntrospectionQuery");
|
|
196
205
|
if (isIntrospectionQuery) {
|
|
197
206
|
loggy.info("Skipping cache for introspection query");
|
|
198
207
|
await next();
|
|
199
208
|
return;
|
|
200
209
|
}
|
|
210
|
+
const key = generateGraphqlCacheKey(body);
|
|
201
211
|
const cacheEntry = await cacheStore.get(key);
|
|
202
212
|
const cacheControlHeader = ctx.request.headers["cache-control"];
|
|
203
213
|
const noCache = cacheControlHeader && cacheControlHeader.includes("no-cache");
|
|
214
|
+
const authorizationHeader = ctx.request.headers["authorization"];
|
|
215
|
+
if (authorizationHeader && !cacheAuthorizedRequests) {
|
|
216
|
+
loggy.info(`Authorized request bypassing cache: ${key}`);
|
|
217
|
+
await next();
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
204
220
|
if (cacheEntry && !noCache) {
|
|
205
221
|
loggy.info(`HIT with key: ${key}`);
|
|
206
222
|
ctx.status = 200;
|
|
207
223
|
ctx.body = cacheEntry.body;
|
|
208
224
|
ctx.set(cacheEntry.headers);
|
|
209
|
-
ctx.set({ "Content-Encoding": "identity" });
|
|
210
225
|
return;
|
|
211
226
|
}
|
|
212
227
|
await next();
|
|
213
228
|
if (ctx.method === "POST" && ctx.status >= 200 && ctx.status < 300 && url.startsWith("/graphql")) {
|
|
214
229
|
loggy.info(`MISS with key: ${key}`);
|
|
230
|
+
const headers = ctx.request.headers;
|
|
231
|
+
const authorizationHeader2 = headers["authorization"];
|
|
232
|
+
if (authorizationHeader2 && !cacheAuthorizedRequests) {
|
|
233
|
+
loggy.info(`Authorized request not caching: ${key}`);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
215
236
|
if (ctx.body instanceof Stream) {
|
|
216
237
|
const buf = await streamToBuffer(ctx.body);
|
|
217
238
|
const contentEncoding = ctx.response.headers["content-encoding"];
|
|
218
239
|
const decompressed = await decompressBuffer(buf, contentEncoding);
|
|
219
240
|
const responseText = decodeBufferToText(decompressed);
|
|
220
|
-
|
|
241
|
+
const headersToStore = cacheHeaders ? ctx.response.headers : null;
|
|
242
|
+
await cacheStore.set(key, { body: responseText, headers: headersToStore });
|
|
221
243
|
ctx.body = buf;
|
|
222
244
|
} else {
|
|
245
|
+
const headersToStore = cacheHeaders ? ctx.response.headers : null;
|
|
223
246
|
await cacheStore.set(key, {
|
|
224
247
|
body: ctx.body,
|
|
225
|
-
headers:
|
|
248
|
+
headers: headersToStore
|
|
226
249
|
});
|
|
227
250
|
}
|
|
228
251
|
}
|
|
@@ -244,7 +267,9 @@ const config = {
|
|
|
244
267
|
allowStale: false,
|
|
245
268
|
cacheableRoutes: [],
|
|
246
269
|
provider: "memory",
|
|
247
|
-
|
|
270
|
+
redisConfig: env("REDIS_URL"),
|
|
271
|
+
cacheHeaders: true,
|
|
272
|
+
cacheAuthorizedRequests: false
|
|
248
273
|
}),
|
|
249
274
|
validator: (config2) => {
|
|
250
275
|
if (typeof config2.debug !== "boolean") {
|
|
@@ -271,8 +296,14 @@ const config = {
|
|
|
271
296
|
if (config2.provider !== "memory" && config2.provider !== "redis") {
|
|
272
297
|
throw new Error(`Invalid config: provider must be 'memory' or 'redis'`);
|
|
273
298
|
}
|
|
274
|
-
if (config2.provider === "redis" && !config2.
|
|
275
|
-
throw new Error(`Invalid config:
|
|
299
|
+
if (config2.provider === "redis" && !config2.redisConfig && (typeof config2.redisConfig !== "string" || typeof config2.redisConfig !== "object")) {
|
|
300
|
+
throw new Error(`Invalid config: redisConfig must be set when using redis provider`);
|
|
301
|
+
}
|
|
302
|
+
if (typeof config2.cacheHeaders !== "boolean") {
|
|
303
|
+
throw new Error(`Invalid config: cacheHeaders must be a boolean`);
|
|
304
|
+
}
|
|
305
|
+
if (typeof config2.cacheAuthorizedRequests !== "boolean") {
|
|
306
|
+
throw new Error(`Invalid config: cacheAuthorizedRequests must be a boolean`);
|
|
276
307
|
}
|
|
277
308
|
}
|
|
278
309
|
};
|
|
@@ -475,10 +506,14 @@ class RedisCacheProvider {
|
|
|
475
506
|
loggy.error("Redis provider already initialized");
|
|
476
507
|
return;
|
|
477
508
|
}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
509
|
+
try {
|
|
510
|
+
const redisUrl = this.strapi.plugin("strapi-cache").config("redisConfig") || "redis://localhost:6379";
|
|
511
|
+
this.client = new Redis(redisUrl);
|
|
512
|
+
this.initialized = true;
|
|
513
|
+
loggy.info("Redis provider initialized");
|
|
514
|
+
} catch (error) {
|
|
515
|
+
loggy.error(error);
|
|
516
|
+
}
|
|
482
517
|
}
|
|
483
518
|
get ready() {
|
|
484
519
|
if (!this.initialized) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../../server/src/utils/log.ts","../../server/src/utils/invalidateCache.ts","../../server/src/permissions.ts","../../server/src/bootstrap.ts","../../server/src/utils/key.ts","../../server/src/utils/body.ts","../../server/src/middlewares/cache.ts","../../server/src/middlewares/graphql.ts","../../server/src/middlewares/index.ts","../../server/src/register.ts","../../server/src/config/index.ts","../../server/src/content-types/index.ts","../../server/src/controllers/controller.ts","../../server/src/controllers/index.ts","../../server/src/policies/index.ts","../../server/src/routes/purge.ts","../../server/src/routes/index.ts","../../server/src/utils/withTimeout.ts","../../server/src/services/memory/provider.ts","../../server/src/services/redis/provider.ts","../../server/src/services/resolver.ts","../../server/src/services/index.ts","../../server/src/index.ts"],"sourcesContent":["export const loggy = {\n info: (msg: string) => {\n const shouldDebug = strapi.plugin('strapi-cache').config('debug') ?? false;\n if (!shouldDebug) {\n return;\n }\n strapi.log.info(`[STRAPI CACHE] ${msg}`);\n },\n error: (msg: string) => {\n const shouldDebug = strapi.plugin('strapi-cache').config('debug') ?? false;\n if (!shouldDebug) {\n return;\n }\n strapi.log.error(`[STRAPI CACHE] ${msg}`);\n },\n warn: (msg: string) => {\n const shouldDebug = strapi.plugin('strapi-cache').config('debug') ?? false;\n if (!shouldDebug) {\n return;\n }\n strapi.log.warn(`[STRAPI CACHE] ${msg}`);\n },\n};\n","import { Core } from '@strapi/strapi';\nimport { CacheProvider } from 'src/types/cache.types';\nimport { loggy } from './log';\n\nexport async function invalidateCache(event: any, cacheStore: CacheProvider, strapi: Core.Strapi) {\n const { model } = event;\n const uid = model.uid;\n\n try {\n const contentType = strapi.contentType(uid);\n\n if (!contentType || !contentType.kind) {\n loggy.info(`Content type ${uid} not found`);\n return;\n }\n\n const pluralName =\n contentType.kind === 'singleType'\n ? contentType.info.singularName\n : contentType.info.pluralName;\n const apiPath = `/api/${pluralName}`;\n const regex = new RegExp(`^.*:${apiPath}(/.*)?(\\\\?.*)?$`);\n\n await cacheStore.clearByRegexp([regex]);\n loggy.info(`Invalidated cache for ${apiPath}`);\n } catch (error) {\n loggy.error('Cache invalidation error:');\n loggy.error(error);\n }\n}\n\nexport async function invalidateGraphqlCache(\n event: any,\n cacheStore: CacheProvider,\n strapi: Core.Strapi\n) {\n try {\n const graphqlRegex = new RegExp(`^POST:\\/graphql(:.*)?$`);\n\n await cacheStore.clearByRegexp([graphqlRegex]);\n loggy.info(`Invalidated cache for ${graphqlRegex}`);\n } catch (error) {\n loggy.error('Cache invalidation error:');\n loggy.error(error);\n }\n}\n","export const actions = [\n {\n section: 'plugins',\n displayName: 'Purge Cache',\n uid: 'purge-cache',\n pluginName: 'strapi-cache',\n },\n];\n","import type { Core } from '@strapi/strapi';\nimport { invalidateCache, invalidateGraphqlCache } from './utils/invalidateCache';\nimport { CacheService } from './types/cache.types';\nimport { loggy } from './utils/log';\nimport { actions } from './permissions';\n\nconst bootstrap = ({ strapi }: { strapi: Core.Strapi }) => {\n loggy.info('Initializing');\n try {\n const cacheService = strapi.plugin('strapi-cache').services.service as CacheService;\n const cacheStore = cacheService.getCacheInstance();\n cacheStore.init();\n\n strapi.db.lifecycles.subscribe({\n async afterCreate(event) {\n await invalidateCache(event, cacheStore, strapi);\n await invalidateGraphqlCache(event, cacheStore, strapi);\n },\n async afterUpdate(event) {\n await invalidateCache(event, cacheStore, strapi);\n await invalidateGraphqlCache(event, cacheStore, strapi);\n },\n async afterDelete(event) {\n await invalidateCache(event, cacheStore, strapi);\n await invalidateGraphqlCache(event, cacheStore, strapi);\n },\n });\n\n if (!cacheStore) {\n loggy.error('Plugin could not be initialized');\n return;\n }\n } catch (error) {\n loggy.error('Plugin could not be initialized');\n return;\n }\n loggy.info('Plugin initialized');\n\n strapi.admin.services.permission.actionProvider.registerMany(actions);\n};\n\nexport default bootstrap;\n","import { createHash } from 'crypto';\nimport { Context } from 'koa';\n\nexport const generateCacheKey = (context: Context) => {\n const { url } = context.request;\n const decodedUrl = decodeURIComponent(url);\n const { method } = context.request;\n\n return `${method}:${decodedUrl}`;\n};\n\nexport const generateGraphqlCacheKey = (payload: string) => {\n const hash = createHash('sha256').update(payload).digest('base64url');\n return `POST:/graphql:${hash}`;\n};\n","import { Stream } from 'stream';\nimport { createGunzip, createBrotliDecompress, createInflate } from 'zlib';\n\nexport const streamToBuffer = (stream: Stream): Promise<Buffer> => {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n stream.on('data', (chunk) => chunks.push(chunk));\n stream.on('end', () => resolve(Buffer.concat(chunks)));\n stream.on('error', reject);\n });\n};\n\nexport const decompressBuffer = async (buffer: Buffer, encoding?: string): Promise<Buffer> => {\n return new Promise((resolve, reject) => {\n let decompressStream;\n switch (encoding) {\n case 'gzip':\n decompressStream = createGunzip();\n break;\n case 'br':\n decompressStream = createBrotliDecompress();\n break;\n case 'deflate':\n decompressStream = createInflate();\n break;\n default:\n return resolve(buffer);\n }\n\n const chunks: Buffer[] = [];\n decompressStream.on('data', (chunk) => chunks.push(chunk));\n decompressStream.on('end', () => resolve(Buffer.concat(chunks)));\n decompressStream.on('error', reject);\n\n decompressStream.end(buffer);\n });\n};\n\nexport const decodeBufferToText = (buffer: Buffer): string => {\n const decoder = new TextDecoder('utf-8');\n return decoder.decode(buffer);\n};\n","import { Context } from 'koa';\nimport { generateCacheKey } from '../utils/key';\nimport { CacheService } from '../../src/types/cache.types';\nimport { loggy } from '../utils/log';\nimport Stream from 'stream';\nimport { decodeBufferToText, decompressBuffer, streamToBuffer } from '../../src/utils/body';\n\nconst middleware = async (ctx: Context, next: any) => {\n const cacheService = strapi.plugin('strapi-cache').services.service as CacheService;\n const cacheableRoutes = strapi.plugin('strapi-cache').config('cacheableRoutes') as string[];\n const cacheStore = cacheService.getCacheInstance();\n const { url } = ctx.request;\n const key = generateCacheKey(ctx);\n const cacheEntry = await cacheStore.get(key);\n const cacheControlHeader = ctx.request.headers['cache-control'];\n const noCache = cacheControlHeader && cacheControlHeader.includes('no-cache');\n const routeIsCachable =\n cacheableRoutes.some((route) => url.startsWith(route)) ||\n (cacheableRoutes.length === 0 && url.startsWith('/api'));\n\n if (cacheEntry && !noCache) {\n loggy.info(`HIT with key: ${key}`);\n ctx.status = 200;\n ctx.body = cacheEntry.body;\n ctx.set(cacheEntry.headers);\n ctx.set({ 'Access-Control-Allow-Origin': '*', 'Content-Encoding': 'identity' });\n return;\n }\n\n await next();\n\n if (ctx.method === 'GET' && ctx.status >= 200 && ctx.status < 300 && routeIsCachable) {\n loggy.info(`MISS with key: ${key}`);\n\n if (ctx.body instanceof Stream) {\n const buf = await streamToBuffer(ctx.body);\n const contentEncoding = ctx.response.headers['content-encoding'];\n const decompressed = await decompressBuffer(buf, contentEncoding);\n const responseText = decodeBufferToText(decompressed);\n\n await cacheStore.set(key, { body: responseText, headers: ctx.response.headers });\n ctx.body = buf;\n } else {\n await cacheStore.set(key, { body: ctx.body, headers: ctx.response.headers });\n }\n }\n};\n\nexport default middleware;\n","import rawBody from 'raw-body';\nimport { generateGraphqlCacheKey } from '../utils/key';\nimport Stream, { Readable } from 'stream';\nimport { loggy } from '../utils/log';\nimport { CacheService } from '../../src/types/cache.types';\nimport { decodeBufferToText, decompressBuffer, streamToBuffer } from '../../src/utils/body';\n\nconst middleware = async (ctx: any, next: any) => {\n const cacheService = strapi.plugin('strapi-cache').services.service as CacheService;\n const cacheStore = cacheService.getCacheInstance();\n const { url } = ctx.request;\n\n const originalReq = ctx.req;\n const bodyBuffer = await rawBody(originalReq);\n const body = bodyBuffer.toString();\n\n const clonedReq = new Readable();\n clonedReq.push(bodyBuffer);\n clonedReq.push(null);\n\n (clonedReq as any).headers = { ...originalReq.headers };\n (clonedReq as any).method = originalReq.method;\n (clonedReq as any).url = originalReq.url;\n (clonedReq as any).httpVersion = originalReq.httpVersion;\n (clonedReq as any).socket = originalReq.socket;\n (clonedReq as any).connection = originalReq.connection;\n\n ctx.req = clonedReq;\n ctx.request.req = clonedReq;\n\n const key = generateGraphqlCacheKey(body);\n\n const isIntrospectionQuery = body.includes('IntrospectionQuery');\n if (isIntrospectionQuery) {\n loggy.info('Skipping cache for introspection query');\n await next();\n return;\n }\n\n const cacheEntry = await cacheStore.get(key);\n const cacheControlHeader = ctx.request.headers['cache-control'];\n const noCache = cacheControlHeader && cacheControlHeader.includes('no-cache');\n\n if (cacheEntry && !noCache) {\n loggy.info(`HIT with key: ${key}`);\n ctx.status = 200;\n ctx.body = cacheEntry.body;\n ctx.set(cacheEntry.headers);\n ctx.set({ 'Content-Encoding': 'identity' });\n return;\n }\n\n await next();\n\n if (\n ctx.method === 'POST' &&\n ctx.status >= 200 &&\n ctx.status < 300 &&\n url.startsWith('/graphql')\n ) {\n loggy.info(`MISS with key: ${key}`);\n\n if (ctx.body instanceof Stream) {\n const buf = await streamToBuffer(ctx.body);\n const contentEncoding = ctx.response.headers['content-encoding']; // e.g., gzip, br, deflate\n const decompressed = await decompressBuffer(buf, contentEncoding);\n const responseText = decodeBufferToText(decompressed);\n\n await cacheStore.set(key, { body: responseText, headers: ctx.response.headers });\n ctx.body = buf;\n } else {\n await cacheStore.set(key, {\n body: ctx.body,\n headers: ctx.response.headers,\n });\n }\n }\n};\n\nexport default middleware;\n","import cache from './cache';\nimport graphql from './graphql';\n\nexport default {\n graphql,\n cache,\n};\n","import type { Core } from '@strapi/strapi';\nimport middlewares from './middlewares';\n\nconst register = ({ strapi }: { strapi: Core.Strapi }) => {\n strapi.server.use(middlewares.cache);\n strapi.server.use(middlewares.graphql);\n};\n\nexport default register;\n","export default {\n default: ({ env }) => ({\n debug: false,\n max: 1000,\n ttl: 1000 * 60 * 60,\n size: 1024 * 1014 * 10,\n allowStale: false,\n cacheableRoutes: [],\n provider: 'memory',\n redisUrl: env('REDIS_URL'),\n }),\n validator: (config) => {\n if (typeof config.debug !== 'boolean') {\n throw new Error(`Invalid config: debug must be a boolean`);\n }\n if (typeof config.max !== 'number') {\n throw new Error(`Invalid config: max must be a number`);\n }\n if (typeof config.ttl !== 'number') {\n throw new Error(`Invalid config: ttl must be a number`);\n }\n if (typeof config.size !== 'number') {\n throw new Error(`Invalid config: size must be a number`);\n }\n if (typeof config.allowStale !== 'boolean') {\n throw new Error(`Invalid config: allowStale must be a boolean`);\n }\n if (\n !Array.isArray(config.cacheableRoutes) ||\n config.cacheableRoutes.some((item) => typeof item !== 'string')\n ) {\n throw new Error(`Invalid config: cacheableRoutes must be an string array`);\n }\n if (typeof config.provider !== 'string') {\n throw new Error(`Invalid config: provider must be a string`);\n }\n if (config.provider !== 'memory' && config.provider !== 'redis') {\n throw new Error(`Invalid config: provider must be 'memory' or 'redis'`);\n }\n if (config.provider === 'redis' && !config.redisUrl && typeof config.redisUrl !== 'string') {\n throw new Error(`Invalid config: redisUrl must be set when using redis provider`);\n }\n },\n};\n","export default {};\n","import type { Core } from '@strapi/strapi';\nimport { Context } from 'koa';\nimport { CacheService } from 'src/types/cache.types';\n\nconst controller = ({ strapi }: { strapi: Core.Strapi }) => ({\n async purgeCache(ctx: Context) {\n const service = strapi.plugin('strapi-cache').service('service') as CacheService;\n\n await service.getCacheInstance().reset();\n\n ctx.body = {\n message: 'Cache purged successfully',\n };\n },\n async purgeCacheByKey(ctx: Context) {\n const { key } = ctx.params;\n const service = strapi.plugin('strapi-cache').service('service') as CacheService;\n const regex = new RegExp(`(^|\\/)${key}(\\/|\\\\?|$)`);\n\n await service.getCacheInstance().clearByRegexp([regex]);\n\n ctx.body = {\n message: `Cache purged successfully for key: ${key}`,\n };\n },\n async cacheableRoutes(ctx: Context) {\n const cacheableRoutes = strapi.plugin('strapi-cache').config('cacheableRoutes');\n ctx.body = cacheableRoutes;\n },\n});\n\nexport default controller;\n","import controller from './controller';\n\nexport default {\n controller,\n};\n","export default {};\n","export default [\n {\n method: 'POST',\n path: '/purge-cache',\n handler: 'controller.purgeCache',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: {\n actions: ['plugin::strapi-cache.purge-cache'],\n },\n },\n ],\n },\n },\n {\n method: 'POST',\n path: '/purge-cache/:key',\n handler: 'controller.purgeCacheByKey',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: {\n actions: ['plugin::strapi-cache.purge-cache'],\n },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/cacheable-routes',\n handler: 'controller.cacheableRoutes',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: {\n actions: ['plugin::strapi-cache.purge-cache'],\n },\n },\n ],\n },\n },\n];\n","import purgeRoute from './purge';\n\nconst routes = {\n 'purge-route': {\n type: 'admin',\n routes: purgeRoute,\n },\n};\n\nexport default routes;\n","export const withTimeout = (callback: () => Promise<any>, ms: number) => {\n let timeout: NodeJS.Timeout | null = null;\n\n return Promise.race([\n callback().then((result) => {\n if (timeout) {\n clearTimeout(timeout);\n }\n return result;\n }),\n new Promise((_, reject) => {\n timeout = setTimeout(() => {\n reject(new Error('timeout'));\n }, ms);\n }),\n ]);\n};\n","import type { Core } from '@strapi/strapi';\nimport { LRUCache } from 'lru-cache';\nimport { withTimeout } from '../../utils/withTimeout';\nimport { CacheProvider, CacheService } from '../../types/cache.types';\nimport { loggy } from '../../utils/log';\n\nexport class InMemoryCacheProvider implements CacheProvider {\n private initialized = false;\n private provider!: LRUCache<string, any>;\n\n constructor(private strapi: Core.Strapi) {}\n\n init(): void {\n if (this.initialized) {\n loggy.error('Provider already initialized');\n return;\n }\n\n this.initialized = true;\n\n const max = Number(this.strapi.plugin('strapi-cache').config('max'));\n const ttl = Number(this.strapi.plugin('strapi-cache').config('ttl'));\n const size = Number(this.strapi.plugin('strapi-cache').config('size'));\n const allowStale = Boolean(this.strapi.plugin('strapi-cache').config('allowStale'));\n\n this.provider = new LRUCache({\n max,\n ttl,\n size,\n allowStale,\n });\n\n loggy.info('Provider initialized');\n }\n\n get ready(): boolean {\n if (!this.initialized) {\n loggy.info('Provider not initialized');\n return false;\n }\n\n return true;\n }\n\n async get(key: string): Promise<any | null> {\n if (!this.ready) return null;\n\n const timeout = 1000;\n return withTimeout(\n () =>\n new Promise((resolve) => {\n resolve(this.provider.get(key));\n }),\n timeout\n ).catch((error) => {\n loggy.error(`Error during get: ${error?.message || error}`);\n return null;\n });\n }\n\n async set(key: string, val: any): Promise<any | null> {\n if (!this.ready) return null;\n\n try {\n return this.provider.set(key, val);\n } catch (error) {\n loggy.error(`Error during set: ${error}`);\n return null;\n }\n }\n\n async del(key: string): Promise<any | null> {\n if (!this.ready) return null;\n\n try {\n loggy.info(`PURGING KEY: ${key}`);\n return this.provider.delete(key);\n } catch (error) {\n loggy.error(`Error during delete: ${error}`);\n return null;\n }\n }\n\n async keys(): Promise<string[] | null> {\n if (!this.ready) return null;\n\n try {\n return Array.from(this.provider.keys());\n } catch (error) {\n loggy.error(`Error fetching keys: ${error}`);\n return null;\n }\n }\n\n async reset(): Promise<any | null> {\n if (!this.ready) return null;\n\n try {\n const allKeys = await this.keys();\n if (!allKeys) return null;\n\n loggy.info(`PURGING ALL KEYS: ${allKeys.length}`);\n await Promise.all(allKeys.map((key) => this.del(key)));\n return true;\n } catch (error) {\n loggy.error(`Error during reset: ${error}`);\n return null;\n }\n }\n\n async clearByRegexp(regExps: RegExp[]): Promise<void> {\n const keys = (await this.keys()) || [];\n const matches = keys.filter((key) => regExps.some((re) => re.test(key)));\n await Promise.all(matches.map((key) => this.del(key)));\n }\n}\n","import type { Core } from '@strapi/strapi';\nimport Redis from 'ioredis';\nimport { withTimeout } from '../../utils/withTimeout';\nimport { CacheProvider } from '../../types/cache.types';\nimport { loggy } from '../../utils/log';\n\nexport class RedisCacheProvider implements CacheProvider {\n private initialized = false;\n private client!: Redis;\n\n constructor(private strapi: Core.Strapi) {}\n\n init(): void {\n if (this.initialized) {\n loggy.error('Redis provider already initialized');\n return;\n }\n\n const redisUrl =\n this.strapi.plugin('strapi-cache').config('redisUrl') || 'redis://localhost:6379';\n\n this.client = new Redis(redisUrl);\n this.initialized = true;\n\n loggy.info('Redis provider initialized');\n }\n\n get ready(): boolean {\n if (!this.initialized) {\n loggy.info('Redis provider not initialized');\n return false;\n }\n\n return true;\n }\n\n async get(key: string): Promise<any | null> {\n if (!this.ready) return null;\n\n const timeout = 1000;\n return withTimeout(() => this.client.get(key), timeout)\n .then((data) => (data ? JSON.parse(data) : null))\n .catch((error) => {\n loggy.error(`Redis get error: ${error?.message || error}`);\n return null;\n });\n }\n\n async set(key: string, val: any): Promise<any | null> {\n if (!this.ready) return null;\n\n try {\n const ttl = Number(this.strapi.plugin('strapi-cache').config('ttl'));\n const serialized = JSON.stringify(val);\n if (ttl > 0) {\n await this.client.set(key, serialized, 'EX', ttl);\n } else {\n await this.client.set(key, serialized);\n }\n return val;\n } catch (error) {\n loggy.error(`Redis set error: ${error}`);\n return null;\n }\n }\n\n async del(key: string): Promise<any | null> {\n if (!this.ready) return null;\n\n try {\n loggy.info(`Redis PURGING KEY: ${key}`);\n await this.client.del(key);\n return true;\n } catch (error) {\n loggy.error(`Redis del error: ${error}`);\n return null;\n }\n }\n\n async keys(): Promise<string[] | null> {\n if (!this.ready) return null;\n\n try {\n const keys = await this.client.keys('*');\n return keys;\n } catch (error) {\n loggy.error(`Redis keys error: ${error}`);\n return null;\n }\n }\n\n async reset(): Promise<any | null> {\n if (!this.ready) return null;\n\n try {\n loggy.info(`Redis FLUSHING ALL KEYS`);\n await this.client.flushdb();\n return true;\n } catch (error) {\n loggy.error(`Redis reset error: ${error}`);\n return null;\n }\n }\n\n async clearByRegexp(regExps: RegExp[]): Promise<void> {\n const keys = await this.keys();\n if (!keys) return;\n\n const toDelete = keys.filter((key) => regExps.some((re) => re.test(key)));\n await Promise.all(toDelete.map((key) => this.del(key)));\n }\n}\n","import type { Core } from '@strapi/strapi';\nimport { InMemoryCacheProvider } from './memory/provider';\nimport { RedisCacheProvider } from './redis/provider';\nimport { CacheProvider } from '../../src/types/cache.types';\nimport { loggy } from '../../src/utils/log';\n\nexport const resolveCacheProvider = (strapi: Core.Strapi): CacheProvider => {\n const providerType = strapi.plugin('strapi-cache').config('provider') || 'memory';\n\n loggy.info(`Selected cache provider: ${providerType}`);\n\n let instance: CacheProvider;\n\n switch (providerType) {\n case 'redis':\n instance = new RedisCacheProvider(strapi);\n break;\n default:\n instance = new InMemoryCacheProvider(strapi);\n break;\n }\n\n return instance;\n};\n","import type { Core } from '@strapi/strapi';\nimport { resolveCacheProvider } from './resolver';\nimport { CacheProvider, CacheService } from '../../src/types/cache.types';\nimport { loggy } from '../../src/utils/log';\n\nconst service = ({ strapi }: { strapi: Core.Strapi }): CacheService => {\n let instance: null | CacheProvider = null;\n\n return {\n getCacheInstance() {\n if (!instance) {\n loggy.info('Initializing cache service from provider config...');\n instance = resolveCacheProvider(strapi);\n }\n return instance;\n },\n };\n};\n\nexport default {\n service,\n};\n","/**\n * Application methods\n */\nimport bootstrap from './bootstrap';\nimport register from './register';\n\n/**\n * Plugin server methods\n */\nimport config from './config';\nimport contentTypes from './content-types';\nimport controllers from './controllers';\nimport middlewares from './middlewares';\nimport policies from './policies';\nimport routes from './routes';\nimport services from './services';\n\nexport default {\n register,\n bootstrap,\n destroy() {},\n config,\n controllers,\n routes,\n services,\n contentTypes,\n policies,\n middlewares,\n};\n"],"names":["strapi","middleware","graphql","cache","config","service"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../../server/src/utils/log.ts","../../server/src/utils/invalidateCache.ts","../../server/src/permissions.ts","../../server/src/bootstrap.ts","../../server/src/utils/key.ts","../../server/src/utils/body.ts","../../server/src/middlewares/cache.ts","../../server/src/middlewares/graphql.ts","../../server/src/middlewares/index.ts","../../server/src/register.ts","../../server/src/config/index.ts","../../server/src/content-types/index.ts","../../server/src/controllers/controller.ts","../../server/src/controllers/index.ts","../../server/src/policies/index.ts","../../server/src/routes/purge.ts","../../server/src/routes/index.ts","../../server/src/utils/withTimeout.ts","../../server/src/services/memory/provider.ts","../../server/src/services/redis/provider.ts","../../server/src/services/resolver.ts","../../server/src/services/index.ts","../../server/src/index.ts"],"sourcesContent":["export const loggy = {\n info: (msg: string) => {\n const shouldDebug = strapi.plugin('strapi-cache').config('debug') ?? false;\n if (!shouldDebug) {\n return;\n }\n strapi.log.info(`[STRAPI CACHE] ${msg}`);\n },\n error: (msg: string) => {\n const shouldDebug = strapi.plugin('strapi-cache').config('debug') ?? false;\n if (!shouldDebug) {\n return;\n }\n strapi.log.error(`[STRAPI CACHE] ${msg}`);\n },\n warn: (msg: string) => {\n const shouldDebug = strapi.plugin('strapi-cache').config('debug') ?? false;\n if (!shouldDebug) {\n return;\n }\n strapi.log.warn(`[STRAPI CACHE] ${msg}`);\n },\n};\n","import { Core } from '@strapi/strapi';\nimport { CacheProvider } from 'src/types/cache.types';\nimport { loggy } from './log';\n\nexport async function invalidateCache(event: any, cacheStore: CacheProvider, strapi: Core.Strapi) {\n const { model } = event;\n const uid = model.uid;\n\n try {\n const contentType = strapi.contentType(uid);\n\n if (!contentType || !contentType.kind) {\n loggy.info(`Content type ${uid} not found`);\n return;\n }\n\n const pluralName =\n contentType.kind === 'singleType'\n ? contentType.info.singularName\n : contentType.info.pluralName;\n const apiPath = `/api/${pluralName}`;\n const regex = new RegExp(`^.*:${apiPath}(/.*)?(\\\\?.*)?$`);\n\n await cacheStore.clearByRegexp([regex]);\n loggy.info(`Invalidated cache for ${apiPath}`);\n } catch (error) {\n loggy.error('Cache invalidation error:');\n loggy.error(error);\n }\n}\n\nexport async function invalidateGraphqlCache(\n event: any,\n cacheStore: CacheProvider,\n strapi: Core.Strapi\n) {\n try {\n const graphqlRegex = new RegExp(`^POST:\\/graphql(:.*)?$`);\n\n await cacheStore.clearByRegexp([graphqlRegex]);\n loggy.info(`Invalidated cache for ${graphqlRegex}`);\n } catch (error) {\n loggy.error('Cache invalidation error:');\n loggy.error(error);\n }\n}\n","export const actions = [\n {\n section: 'plugins',\n displayName: 'Purge Cache',\n uid: 'purge-cache',\n pluginName: 'strapi-cache',\n },\n];\n","import type { Core } from '@strapi/strapi';\nimport { invalidateCache, invalidateGraphqlCache } from './utils/invalidateCache';\nimport { CacheService } from './types/cache.types';\nimport { loggy } from './utils/log';\nimport { actions } from './permissions';\n\nconst bootstrap = ({ strapi }: { strapi: Core.Strapi }) => {\n loggy.info('Initializing');\n try {\n const cacheService = strapi.plugin('strapi-cache').services.service as CacheService;\n const cacheStore = cacheService.getCacheInstance();\n cacheStore.init();\n\n strapi.db.lifecycles.subscribe({\n async afterCreate(event) {\n await invalidateCache(event, cacheStore, strapi);\n await invalidateGraphqlCache(event, cacheStore, strapi);\n },\n async afterUpdate(event) {\n await invalidateCache(event, cacheStore, strapi);\n await invalidateGraphqlCache(event, cacheStore, strapi);\n },\n async afterDelete(event) {\n await invalidateCache(event, cacheStore, strapi);\n await invalidateGraphqlCache(event, cacheStore, strapi);\n },\n });\n\n if (!cacheStore) {\n loggy.error('Plugin could not be initialized');\n return;\n }\n } catch (error) {\n loggy.error('Plugin could not be initialized');\n return;\n }\n loggy.info('Plugin initialized');\n\n strapi.admin.services.permission.actionProvider.registerMany(actions);\n};\n\nexport default bootstrap;\n","import { createHash } from 'crypto';\nimport { Context } from 'koa';\n\nexport const generateCacheKey = (context: Context) => {\n const { url } = context.request;\n const { method } = context.request;\n\n return `${method}:${url}`;\n};\n\nexport const generateGraphqlCacheKey = (payload: string) => {\n const hash = createHash('sha256').update(payload).digest('base64url');\n return `POST:/graphql:${hash}`;\n};\n","import { Stream } from 'stream';\nimport { createGunzip, createBrotliDecompress, createInflate } from 'zlib';\n\nexport const streamToBuffer = (stream: Stream): Promise<Buffer> => {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n stream.on('data', (chunk) => chunks.push(chunk));\n stream.on('end', () => resolve(Buffer.concat(chunks)));\n stream.on('error', reject);\n });\n};\n\nexport const decompressBuffer = async (buffer: Buffer, encoding?: string): Promise<Buffer> => {\n return new Promise((resolve, reject) => {\n let decompressStream;\n switch (encoding) {\n case 'gzip':\n decompressStream = createGunzip();\n break;\n case 'br':\n decompressStream = createBrotliDecompress();\n break;\n case 'deflate':\n decompressStream = createInflate();\n break;\n default:\n return resolve(buffer);\n }\n\n const chunks: Buffer[] = [];\n decompressStream.on('data', (chunk) => chunks.push(chunk));\n decompressStream.on('end', () => resolve(Buffer.concat(chunks)));\n decompressStream.on('error', reject);\n\n decompressStream.end(buffer);\n });\n};\n\nexport const decodeBufferToText = (buffer: Buffer): string => {\n const decoder = new TextDecoder('utf-8');\n return decoder.decode(buffer);\n};\n","import { Context } from 'koa';\nimport { generateCacheKey } from '../utils/key';\nimport { CacheService } from '../../src/types/cache.types';\nimport { loggy } from '../utils/log';\nimport Stream from 'stream';\nimport { decodeBufferToText, decompressBuffer, streamToBuffer } from '../../src/utils/body';\n\nconst middleware = async (ctx: Context, next: any) => {\n const cacheService = strapi.plugin('strapi-cache').services.service as CacheService;\n const cacheableRoutes = strapi.plugin('strapi-cache').config('cacheableRoutes') as string[];\n const cacheHeaders = strapi.plugin('strapi-cache').config('cacheHeaders') as boolean;\n const cacheAuthorizedRequests = strapi\n .plugin('strapi-cache')\n .config('cacheAuthorizedRequests') as boolean;\n const cacheStore = cacheService.getCacheInstance();\n const { url } = ctx.request;\n const key = generateCacheKey(ctx);\n const cacheEntry = await cacheStore.get(key);\n const cacheControlHeader = ctx.request.headers['cache-control'];\n const noCache = cacheControlHeader && cacheControlHeader.includes('no-cache');\n const routeIsCachable =\n cacheableRoutes.some((route) => url.startsWith(route)) ||\n (cacheableRoutes.length === 0 && url.startsWith('/api'));\n const authorizationHeader = ctx.request.headers['authorization'];\n\n if (authorizationHeader && !cacheAuthorizedRequests) {\n loggy.info(`Authorized request bypassing cache: ${key}`);\n await next();\n return;\n }\n\n if (cacheEntry && !noCache) {\n loggy.info(`HIT with key: ${key}`);\n ctx.status = 200;\n ctx.body = cacheEntry.body;\n ctx.set(cacheEntry.headers);\n return;\n }\n\n await next();\n\n if (ctx.method === 'GET' && ctx.status >= 200 && ctx.status < 300 && routeIsCachable) {\n loggy.info(`MISS with key: ${key}`);\n\n if (ctx.body instanceof Stream) {\n const buf = await streamToBuffer(ctx.body);\n const contentEncoding = ctx.response.headers['content-encoding'];\n const decompressed = await decompressBuffer(buf, contentEncoding);\n const responseText = decodeBufferToText(decompressed);\n\n const headersToStore = cacheHeaders ? ctx.response.headers : null;\n await cacheStore.set(key, { body: responseText, headers: headersToStore });\n ctx.body = buf;\n } else {\n const headersToStore = cacheHeaders ? ctx.response.headers : null;\n await cacheStore.set(key, { body: ctx.body, headers: headersToStore });\n }\n }\n};\n\nexport default middleware;\n","import rawBody from 'raw-body';\nimport { generateGraphqlCacheKey } from '../utils/key';\nimport Stream, { Readable } from 'stream';\nimport { loggy } from '../utils/log';\nimport { CacheService } from '../../src/types/cache.types';\nimport { decodeBufferToText, decompressBuffer, streamToBuffer } from '../../src/utils/body';\n\nconst middleware = async (ctx: any, next: any) => {\n const cacheService = strapi.plugin('strapi-cache').services.service as CacheService;\n const cacheHeaders = strapi.plugin('strapi-cache').config('cacheHeaders') as boolean;\n const cacheAuthorizedRequests = strapi\n .plugin('strapi-cache')\n .config('cacheAuthorizedRequests') as boolean;\n const cacheStore = cacheService.getCacheInstance();\n const { url } = ctx.request;\n\n const originalReq = ctx.req;\n const bodyBuffer = await rawBody(originalReq);\n const body = bodyBuffer.toString();\n\n const clonedReq = new Readable();\n clonedReq.push(bodyBuffer);\n clonedReq.push(null);\n\n (clonedReq as any).headers = { ...originalReq.headers };\n (clonedReq as any).method = originalReq.method;\n (clonedReq as any).url = originalReq.url;\n (clonedReq as any).httpVersion = originalReq.httpVersion;\n (clonedReq as any).socket = originalReq.socket;\n (clonedReq as any).connection = originalReq.connection;\n\n ctx.req = clonedReq;\n ctx.request.req = clonedReq;\n\n const isIntrospectionQuery = body.includes('IntrospectionQuery');\n if (isIntrospectionQuery) {\n loggy.info('Skipping cache for introspection query');\n await next();\n return;\n }\n\n const key = generateGraphqlCacheKey(body);\n const cacheEntry = await cacheStore.get(key);\n const cacheControlHeader = ctx.request.headers['cache-control'];\n const noCache = cacheControlHeader && cacheControlHeader.includes('no-cache');\n const authorizationHeader = ctx.request.headers['authorization'];\n\n if (authorizationHeader && !cacheAuthorizedRequests) {\n loggy.info(`Authorized request bypassing cache: ${key}`);\n await next();\n return;\n }\n\n if (cacheEntry && !noCache) {\n loggy.info(`HIT with key: ${key}`);\n ctx.status = 200;\n ctx.body = cacheEntry.body;\n ctx.set(cacheEntry.headers);\n return;\n }\n\n await next();\n\n if (\n ctx.method === 'POST' &&\n ctx.status >= 200 &&\n ctx.status < 300 &&\n url.startsWith('/graphql')\n ) {\n loggy.info(`MISS with key: ${key}`);\n const headers = ctx.request.headers;\n const authorizationHeader = headers['authorization'];\n if (authorizationHeader && !cacheAuthorizedRequests) {\n loggy.info(`Authorized request not caching: ${key}`);\n return;\n }\n\n if (ctx.body instanceof Stream) {\n const buf = await streamToBuffer(ctx.body);\n const contentEncoding = ctx.response.headers['content-encoding']; // e.g., gzip, br, deflate\n const decompressed = await decompressBuffer(buf, contentEncoding);\n const responseText = decodeBufferToText(decompressed);\n\n const headersToStore = cacheHeaders ? ctx.response.headers : null;\n await cacheStore.set(key, { body: responseText, headers: headersToStore });\n ctx.body = buf;\n } else {\n const headersToStore = cacheHeaders ? ctx.response.headers : null;\n await cacheStore.set(key, {\n body: ctx.body,\n headers: headersToStore,\n });\n }\n }\n};\n\nexport default middleware;\n","import cache from './cache';\nimport graphql from './graphql';\n\nexport default {\n graphql,\n cache,\n};\n","import type { Core } from '@strapi/strapi';\nimport middlewares from './middlewares';\n\nconst register = ({ strapi }: { strapi: Core.Strapi }) => {\n strapi.server.use(middlewares.cache);\n strapi.server.use(middlewares.graphql);\n};\n\nexport default register;\n","export default {\n default: ({ env }) => ({\n debug: false,\n max: 1000,\n ttl: 1000 * 60 * 60,\n size: 1024 * 1014 * 10,\n allowStale: false,\n cacheableRoutes: [],\n provider: 'memory',\n redisConfig: env('REDIS_URL'),\n cacheHeaders: true,\n cacheAuthorizedRequests: false,\n }),\n validator: (config) => {\n if (typeof config.debug !== 'boolean') {\n throw new Error(`Invalid config: debug must be a boolean`);\n }\n if (typeof config.max !== 'number') {\n throw new Error(`Invalid config: max must be a number`);\n }\n if (typeof config.ttl !== 'number') {\n throw new Error(`Invalid config: ttl must be a number`);\n }\n if (typeof config.size !== 'number') {\n throw new Error(`Invalid config: size must be a number`);\n }\n if (typeof config.allowStale !== 'boolean') {\n throw new Error(`Invalid config: allowStale must be a boolean`);\n }\n if (\n !Array.isArray(config.cacheableRoutes) ||\n config.cacheableRoutes.some((item) => typeof item !== 'string')\n ) {\n throw new Error(`Invalid config: cacheableRoutes must be an string array`);\n }\n if (typeof config.provider !== 'string') {\n throw new Error(`Invalid config: provider must be a string`);\n }\n if (config.provider !== 'memory' && config.provider !== 'redis') {\n throw new Error(`Invalid config: provider must be 'memory' or 'redis'`);\n }\n if (\n config.provider === 'redis' &&\n !config.redisConfig &&\n (typeof config.redisConfig !== 'string' || typeof config.redisConfig !== 'object')\n ) {\n throw new Error(`Invalid config: redisConfig must be set when using redis provider`);\n }\n if (typeof config.cacheHeaders !== 'boolean') {\n throw new Error(`Invalid config: cacheHeaders must be a boolean`);\n }\n if (typeof config.cacheAuthorizedRequests !== 'boolean') {\n throw new Error(`Invalid config: cacheAuthorizedRequests must be a boolean`);\n }\n },\n};\n","export default {};\n","import type { Core } from '@strapi/strapi';\nimport { Context } from 'koa';\nimport { CacheService } from 'src/types/cache.types';\n\nconst controller = ({ strapi }: { strapi: Core.Strapi }) => ({\n async purgeCache(ctx: Context) {\n const service = strapi.plugin('strapi-cache').service('service') as CacheService;\n\n await service.getCacheInstance().reset();\n\n ctx.body = {\n message: 'Cache purged successfully',\n };\n },\n async purgeCacheByKey(ctx: Context) {\n const { key } = ctx.params;\n const service = strapi.plugin('strapi-cache').service('service') as CacheService;\n const regex = new RegExp(`(^|\\/)${key}(\\/|\\\\?|$)`);\n\n await service.getCacheInstance().clearByRegexp([regex]);\n\n ctx.body = {\n message: `Cache purged successfully for key: ${key}`,\n };\n },\n async cacheableRoutes(ctx: Context) {\n const cacheableRoutes = strapi.plugin('strapi-cache').config('cacheableRoutes');\n ctx.body = cacheableRoutes;\n },\n});\n\nexport default controller;\n","import controller from './controller';\n\nexport default {\n controller,\n};\n","export default {};\n","export default [\n {\n method: 'POST',\n path: '/purge-cache',\n handler: 'controller.purgeCache',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: {\n actions: ['plugin::strapi-cache.purge-cache'],\n },\n },\n ],\n },\n },\n {\n method: 'POST',\n path: '/purge-cache/:key',\n handler: 'controller.purgeCacheByKey',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: {\n actions: ['plugin::strapi-cache.purge-cache'],\n },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/cacheable-routes',\n handler: 'controller.cacheableRoutes',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: {\n actions: ['plugin::strapi-cache.purge-cache'],\n },\n },\n ],\n },\n },\n];\n","import purgeRoute from './purge';\n\nconst routes = {\n 'purge-route': {\n type: 'admin',\n routes: purgeRoute,\n },\n};\n\nexport default routes;\n","export const withTimeout = (callback: () => Promise<any>, ms: number) => {\n let timeout: NodeJS.Timeout | null = null;\n\n return Promise.race([\n callback().then((result) => {\n if (timeout) {\n clearTimeout(timeout);\n }\n return result;\n }),\n new Promise((_, reject) => {\n timeout = setTimeout(() => {\n reject(new Error('timeout'));\n }, ms);\n }),\n ]);\n};\n","import type { Core } from '@strapi/strapi';\nimport { LRUCache } from 'lru-cache';\nimport { withTimeout } from '../../utils/withTimeout';\nimport { CacheProvider, CacheService } from '../../types/cache.types';\nimport { loggy } from '../../utils/log';\n\nexport class InMemoryCacheProvider implements CacheProvider {\n private initialized = false;\n private provider!: LRUCache<string, any>;\n\n constructor(private strapi: Core.Strapi) {}\n\n init(): void {\n if (this.initialized) {\n loggy.error('Provider already initialized');\n return;\n }\n\n this.initialized = true;\n\n const max = Number(this.strapi.plugin('strapi-cache').config('max'));\n const ttl = Number(this.strapi.plugin('strapi-cache').config('ttl'));\n const size = Number(this.strapi.plugin('strapi-cache').config('size'));\n const allowStale = Boolean(this.strapi.plugin('strapi-cache').config('allowStale'));\n\n this.provider = new LRUCache({\n max,\n ttl,\n size,\n allowStale,\n });\n\n loggy.info('Provider initialized');\n }\n\n get ready(): boolean {\n if (!this.initialized) {\n loggy.info('Provider not initialized');\n return false;\n }\n\n return true;\n }\n\n async get(key: string): Promise<any | null> {\n if (!this.ready) return null;\n\n const timeout = 1000;\n return withTimeout(\n () =>\n new Promise((resolve) => {\n resolve(this.provider.get(key));\n }),\n timeout\n ).catch((error) => {\n loggy.error(`Error during get: ${error?.message || error}`);\n return null;\n });\n }\n\n async set(key: string, val: any): Promise<any | null> {\n if (!this.ready) return null;\n\n try {\n return this.provider.set(key, val);\n } catch (error) {\n loggy.error(`Error during set: ${error}`);\n return null;\n }\n }\n\n async del(key: string): Promise<any | null> {\n if (!this.ready) return null;\n\n try {\n loggy.info(`PURGING KEY: ${key}`);\n return this.provider.delete(key);\n } catch (error) {\n loggy.error(`Error during delete: ${error}`);\n return null;\n }\n }\n\n async keys(): Promise<string[] | null> {\n if (!this.ready) return null;\n\n try {\n return Array.from(this.provider.keys());\n } catch (error) {\n loggy.error(`Error fetching keys: ${error}`);\n return null;\n }\n }\n\n async reset(): Promise<any | null> {\n if (!this.ready) return null;\n\n try {\n const allKeys = await this.keys();\n if (!allKeys) return null;\n\n loggy.info(`PURGING ALL KEYS: ${allKeys.length}`);\n await Promise.all(allKeys.map((key) => this.del(key)));\n return true;\n } catch (error) {\n loggy.error(`Error during reset: ${error}`);\n return null;\n }\n }\n\n async clearByRegexp(regExps: RegExp[]): Promise<void> {\n const keys = (await this.keys()) || [];\n const matches = keys.filter((key) => regExps.some((re) => re.test(key)));\n await Promise.all(matches.map((key) => this.del(key)));\n }\n}\n","import type { Core } from '@strapi/strapi';\nimport Redis from 'ioredis';\nimport { withTimeout } from '../../utils/withTimeout';\nimport { CacheProvider } from '../../types/cache.types';\nimport { loggy } from '../../utils/log';\n\nexport class RedisCacheProvider implements CacheProvider {\n private initialized = false;\n private client!: Redis;\n\n constructor(private strapi: Core.Strapi) {}\n\n init(): void {\n if (this.initialized) {\n loggy.error('Redis provider already initialized');\n return;\n }\n try {\n const redisUrl =\n this.strapi.plugin('strapi-cache').config('redisConfig') || 'redis://localhost:6379';\n this.client = new Redis(redisUrl);\n this.initialized = true;\n\n loggy.info('Redis provider initialized');\n } catch (error) {\n loggy.error(error);\n }\n }\n\n get ready(): boolean {\n if (!this.initialized) {\n loggy.info('Redis provider not initialized');\n return false;\n }\n\n return true;\n }\n\n async get(key: string): Promise<any | null> {\n if (!this.ready) return null;\n\n const timeout = 1000;\n return withTimeout(() => this.client.get(key), timeout)\n .then((data) => (data ? JSON.parse(data) : null))\n .catch((error) => {\n loggy.error(`Redis get error: ${error?.message || error}`);\n return null;\n });\n }\n\n async set(key: string, val: any): Promise<any | null> {\n if (!this.ready) return null;\n\n try {\n const ttl = Number(this.strapi.plugin('strapi-cache').config('ttl'));\n const serialized = JSON.stringify(val);\n if (ttl > 0) {\n await this.client.set(key, serialized, 'EX', ttl);\n } else {\n await this.client.set(key, serialized);\n }\n return val;\n } catch (error) {\n loggy.error(`Redis set error: ${error}`);\n return null;\n }\n }\n\n async del(key: string): Promise<any | null> {\n if (!this.ready) return null;\n\n try {\n loggy.info(`Redis PURGING KEY: ${key}`);\n await this.client.del(key);\n return true;\n } catch (error) {\n loggy.error(`Redis del error: ${error}`);\n return null;\n }\n }\n\n async keys(): Promise<string[] | null> {\n if (!this.ready) return null;\n\n try {\n const keys = await this.client.keys('*');\n return keys;\n } catch (error) {\n loggy.error(`Redis keys error: ${error}`);\n return null;\n }\n }\n\n async reset(): Promise<any | null> {\n if (!this.ready) return null;\n\n try {\n loggy.info(`Redis FLUSHING ALL KEYS`);\n await this.client.flushdb();\n return true;\n } catch (error) {\n loggy.error(`Redis reset error: ${error}`);\n return null;\n }\n }\n\n async clearByRegexp(regExps: RegExp[]): Promise<void> {\n const keys = await this.keys();\n if (!keys) return;\n\n const toDelete = keys.filter((key) => regExps.some((re) => re.test(key)));\n await Promise.all(toDelete.map((key) => this.del(key)));\n }\n}\n","import type { Core } from '@strapi/strapi';\nimport { InMemoryCacheProvider } from './memory/provider';\nimport { RedisCacheProvider } from './redis/provider';\nimport { CacheProvider } from '../../src/types/cache.types';\nimport { loggy } from '../../src/utils/log';\n\nexport const resolveCacheProvider = (strapi: Core.Strapi): CacheProvider => {\n const providerType = strapi.plugin('strapi-cache').config('provider') || 'memory';\n\n loggy.info(`Selected cache provider: ${providerType}`);\n\n let instance: CacheProvider;\n\n switch (providerType) {\n case 'redis':\n instance = new RedisCacheProvider(strapi);\n break;\n default:\n instance = new InMemoryCacheProvider(strapi);\n break;\n }\n\n return instance;\n};\n","import type { Core } from '@strapi/strapi';\nimport { resolveCacheProvider } from './resolver';\nimport { CacheProvider, CacheService } from '../../src/types/cache.types';\nimport { loggy } from '../../src/utils/log';\n\nconst service = ({ strapi }: { strapi: Core.Strapi }): CacheService => {\n let instance: null | CacheProvider = null;\n\n return {\n getCacheInstance() {\n if (!instance) {\n loggy.info('Initializing cache service from provider config...');\n instance = resolveCacheProvider(strapi);\n }\n return instance;\n },\n };\n};\n\nexport default {\n service,\n};\n","/**\n * Application methods\n */\nimport bootstrap from './bootstrap';\nimport register from './register';\n\n/**\n * Plugin server methods\n */\nimport config from './config';\nimport contentTypes from './content-types';\nimport controllers from './controllers';\nimport middlewares from './middlewares';\nimport policies from './policies';\nimport routes from './routes';\nimport services from './services';\n\nexport default {\n register,\n bootstrap,\n destroy() {},\n config,\n controllers,\n routes,\n services,\n contentTypes,\n policies,\n middlewares,\n};\n"],"names":["strapi","middleware","authorizationHeader","graphql","cache","config","service"],"mappings":"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"}
|
package/package.json
CHANGED