strapi-cache 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # 🧠 strapi-cache
2
2
 
3
3
  **A powerful LRU-Cache plugin for Strapi v5**
4
- Boost your API performance with automatic in-memory caching for REST and GraphQL requests.
4
+ Boost your API performance with automatic in-memory or Redis caching for REST and GraphQL requests.
5
5
 
6
6
  ![npm version](https://img.shields.io/badge/version-1.0.0-blue)
7
7
  ![Strapi Version](https://img.shields.io/badge/strapi-v5-blue)
@@ -17,6 +17,7 @@ Boost your API performance with automatic in-memory caching for REST and GraphQL
17
17
  - ♻️ **LRU (Least Recently Used) caching strategy**
18
18
  - 🔧 Simple integration with Strapi config
19
19
  - 📦 Lightweight with zero overhead
20
+ - 🗄️ **Supports in-memory and Redis caching**
20
21
 
21
22
  ---
22
23
 
@@ -44,22 +45,24 @@ In your Strapi project, navigate to `config/plugins.js` and add the following co
44
45
  enabled: true,
45
46
  config: {
46
47
  debug: false, // Enable debug logs
47
- max: 1000, // Maximum number of items in the cache
48
+ max: 1000, // Maximum number of items in the cache (only for memory cache)
48
49
  ttl: 1000 * 60 * 60, // Time to live for cache items (1 hour)
49
- size: 1024 * 1024 * 1024, // Maximum size of the cache (1 GB)
50
- allowStale: false, // Allow stale cache items
50
+ size: 1024 * 1024 * 1024, // Maximum size of the cache (1 GB) (only for memory cache)
51
+ allowStale: false, // Allow stale cache items (only for memory cache)
51
52
  cacheableRoutes: ['/api/products', '/api/categories'], // Caches routes which start with these paths (if empty array, all '/api' routes are cached)
52
- },
53
+ provider: 'memory', // Cache provider ('memory' or 'redis')
54
+ redisUrl: env('REDIS_URL', 'redis://localhost:6379'), // Redis URL (if using Redis)
55
+ },
53
56
  },
54
57
  ```
55
58
 
56
59
  ## 🗂️ How It Works
57
60
 
58
- - **In-Memory Storage**: The plugin keeps cached data in memory using an LRU strategy. It checks the cache before querying the database.
59
- - **Powered by `lru-cache`**: Uses the popular `lru-cache` library for managing the cache efficiently.
61
+ - **Storage**: The plugin keeps cached data in memory or Redis, depending on the configuration.
62
+ - **Packages**: Uses [lru-cache](https://github.com/isaacs/node-lru-cache) for in-memory cache. Uses [ioredis](https://github.com/redis/ioredis) for Redis caching.
60
63
  - **Automatic Invalidation**: Cache is cleared automatically when content is updated, deleted, or created. (GraphQL cache clears on any content update.)
61
64
  - **`no-cache` Header Support**: Respects the `no-cache` header, letting you skip the cache by setting `Cache-Control: no-cache` in your request.
62
- - **Default Cached Requests**: By default, caches all GET requests to `/api` and POST requests to `/graphql`. You can customize which content types to cache in the settings (only for GET requests).
65
+ - **Default Cached Requests**: By default, caches all GET requests to `/api` and POST requests to `/graphql`. You can customize which content types to cache in the config (only for GET requests).
63
66
 
64
67
  ## 🔮 Planned Features
65
68
 
@@ -67,7 +70,7 @@ In your Strapi project, navigate to `config/plugins.js` and add the following co
67
70
  - [x] **GraphQL Caching**: Cache GraphQL queries.
68
71
  - [ ] **Purge Cache in Settings**: Add a UI option in the Strapi admin panel to manually purge the cache.
69
72
  - [x] **Route/Content-Type Specific Caching**: Allow users to define which routes should be cached based.
70
- - [ ] **Switchable Cache Providers**: Explore support for other caching providers like Redis for distributed caching.
73
+ - [x] **Switchable Cache Providers**: Explore support for other caching providers like Redis for distributed caching.
71
74
 
72
75
  ## 🛠️ Contributing
73
76
 
@@ -3,8 +3,10 @@ const crypto = require("crypto");
3
3
  const rawBody = require("raw-body");
4
4
  const stream = require("stream");
5
5
  const lruCache = require("lru-cache");
6
+ const Redis = require("ioredis");
6
7
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
7
8
  const rawBody__default = /* @__PURE__ */ _interopDefault(rawBody);
9
+ const Redis__default = /* @__PURE__ */ _interopDefault(Redis);
8
10
  const loggy = {
9
11
  info: (msg) => {
10
12
  const shouldDebug = strapi.plugin("strapi-cache").config("debug") ?? false;
@@ -110,18 +112,15 @@ const middleware$1 = async (ctx, next) => {
110
112
  const routeIsCachable = cacheableRoutes.some((route) => url.startsWith(route)) || cacheableRoutes.length === 0 && url.startsWith("/api");
111
113
  if (cacheEntry && !noCache) {
112
114
  loggy.info(`HIT with key: ${key}`);
113
- ctx.status = 304;
114
- ctx.body = null;
115
- ctx.set(cacheEntry.headers);
115
+ ctx.status = 200;
116
+ ctx.body = cacheEntry;
117
+ ctx.set({ "Access-Control-Allow-Origin": "*" });
116
118
  return;
117
119
  }
118
120
  await next();
119
- if (ctx.body && ctx.method === "GET" && ctx.status >= 200 && ctx.status <= 300 && routeIsCachable) {
121
+ if (ctx.body && ctx.method === "GET" && ctx.status >= 200 && ctx.status < 300 && routeIsCachable) {
120
122
  loggy.info(`MISS with key: ${key}`);
121
- await cacheStore.set(key, {
122
- body: ctx.body,
123
- headers: ctx.response.headers
124
- });
123
+ await cacheStore.set(key, ctx.body);
125
124
  }
126
125
  };
127
126
  const middleware = async (ctx, next) => {
@@ -154,7 +153,7 @@ const middleware = async (ctx, next) => {
154
153
  return;
155
154
  }
156
155
  await next();
157
- if (ctx.body && ctx.method === "POST" && ctx.status >= 200 && ctx.status <= 300 && url.startsWith("/graphql")) {
156
+ if (ctx.body && ctx.method === "POST" && ctx.status >= 200 && ctx.status < 300 && url.startsWith("/graphql")) {
158
157
  loggy.info(`MISS with key: ${key}`);
159
158
  await cacheStore.set(key, {
160
159
  body: ctx.body,
@@ -177,7 +176,9 @@ const config = {
177
176
  ttl: 1e3 * 60 * 60,
178
177
  size: 1024 * 1014 * 10,
179
178
  allowStale: false,
180
- contentTypes: []
179
+ cacheableRoutes: [],
180
+ provider: "memory",
181
+ redisUrl: env("REDIS_URL")
181
182
  }),
182
183
  validator: (config2) => {
183
184
  if (typeof config2.debug !== "boolean") {
@@ -198,6 +199,15 @@ const config = {
198
199
  if (!Array.isArray(config2.cacheableRoutes) || config2.cacheableRoutes.some((item) => typeof item !== "string")) {
199
200
  throw new Error(`Invalid config: cacheableRoutes must be an string array`);
200
201
  }
202
+ if (typeof config2.provider !== "string") {
203
+ throw new Error(`Invalid config: provider must be a string`);
204
+ }
205
+ if (config2.provider !== "memory" && config2.provider !== "redis") {
206
+ throw new Error(`Invalid config: provider must be 'memory' or 'redis'`);
207
+ }
208
+ if (config2.provider === "redis" && !config2.redisUrl && typeof config2.redisUrl !== "string") {
209
+ throw new Error(`Invalid config: redisUrl must be set when using redis provider`);
210
+ }
201
211
  }
202
212
  };
203
213
  const contentTypes = {};
@@ -243,158 +253,203 @@ const withTimeout = (callback, ms) => {
243
253
  })
244
254
  ]);
245
255
  };
256
+ class InMemoryCacheProvider {
257
+ constructor(strapi2) {
258
+ this.strapi = strapi2;
259
+ this.initialized = false;
260
+ }
261
+ init() {
262
+ if (this.initialized) {
263
+ loggy.error("Provider already initialized");
264
+ return;
265
+ }
266
+ this.initialized = true;
267
+ const max = Number(this.strapi.plugin("strapi-cache").config("max"));
268
+ const ttl = Number(this.strapi.plugin("strapi-cache").config("ttl"));
269
+ const size = Number(this.strapi.plugin("strapi-cache").config("size"));
270
+ const allowStale = Boolean(this.strapi.plugin("strapi-cache").config("allowStale"));
271
+ this.provider = new lruCache.LRUCache({
272
+ max,
273
+ ttl,
274
+ size,
275
+ allowStale
276
+ });
277
+ loggy.info("Provider initialized");
278
+ }
279
+ get ready() {
280
+ if (!this.initialized) {
281
+ loggy.info("Provider not initialized");
282
+ return false;
283
+ }
284
+ return true;
285
+ }
286
+ async get(key) {
287
+ if (!this.ready) return null;
288
+ const timeout = 1e3;
289
+ return withTimeout(
290
+ () => new Promise((resolve) => {
291
+ resolve(this.provider.get(key));
292
+ }),
293
+ timeout
294
+ ).catch((error) => {
295
+ loggy.error(`Error during get: ${error?.message || error}`);
296
+ return null;
297
+ });
298
+ }
299
+ async set(key, val) {
300
+ if (!this.ready) return null;
301
+ try {
302
+ return this.provider.set(key, val);
303
+ } catch (error) {
304
+ loggy.error(`Error during set: ${error}`);
305
+ return null;
306
+ }
307
+ }
308
+ async del(key) {
309
+ if (!this.ready) return null;
310
+ try {
311
+ loggy.info(`PURGING KEY: ${key}`);
312
+ return this.provider.delete(key);
313
+ } catch (error) {
314
+ loggy.error(`Error during delete: ${error}`);
315
+ return null;
316
+ }
317
+ }
318
+ async keys() {
319
+ if (!this.ready) return null;
320
+ try {
321
+ return Array.from(this.provider.keys());
322
+ } catch (error) {
323
+ loggy.error(`Error fetching keys: ${error}`);
324
+ return null;
325
+ }
326
+ }
327
+ async reset() {
328
+ if (!this.ready) return null;
329
+ try {
330
+ const allKeys = await this.keys();
331
+ if (!allKeys) return null;
332
+ loggy.info(`PURGING ALL KEYS: ${allKeys.length}`);
333
+ await Promise.all(allKeys.map((key) => this.del(key)));
334
+ return true;
335
+ } catch (error) {
336
+ loggy.error(`Error during reset: ${error}`);
337
+ return null;
338
+ }
339
+ }
340
+ async clearByRegexp(regExps) {
341
+ const keys = await this.keys() || [];
342
+ const matches = keys.filter((key) => regExps.some((re) => re.test(key)));
343
+ await Promise.all(matches.map((key) => this.del(key)));
344
+ }
345
+ }
346
+ class RedisCacheProvider {
347
+ constructor(strapi2) {
348
+ this.strapi = strapi2;
349
+ this.initialized = false;
350
+ }
351
+ init() {
352
+ if (this.initialized) {
353
+ loggy.error("Redis provider already initialized");
354
+ return;
355
+ }
356
+ const redisUrl = this.strapi.plugin("strapi-cache").config("redisUrl") || "redis://localhost:6379";
357
+ this.client = new Redis__default.default(redisUrl);
358
+ this.initialized = true;
359
+ loggy.info("Redis provider initialized");
360
+ }
361
+ get ready() {
362
+ if (!this.initialized) {
363
+ loggy.info("Redis provider not initialized");
364
+ return false;
365
+ }
366
+ return true;
367
+ }
368
+ async get(key) {
369
+ if (!this.ready) return null;
370
+ const timeout = 1e3;
371
+ return withTimeout(() => this.client.get(key), timeout).then((data) => data ? JSON.parse(data) : null).catch((error) => {
372
+ loggy.error(`Redis get error: ${error?.message || error}`);
373
+ return null;
374
+ });
375
+ }
376
+ async set(key, val) {
377
+ if (!this.ready) return null;
378
+ try {
379
+ const ttl = Number(this.strapi.plugin("strapi-cache").config("ttl"));
380
+ const serialized = JSON.stringify(val);
381
+ if (ttl > 0) {
382
+ await this.client.set(key, serialized, "EX", ttl);
383
+ } else {
384
+ await this.client.set(key, serialized);
385
+ }
386
+ return val;
387
+ } catch (error) {
388
+ loggy.error(`Redis set error: ${error}`);
389
+ return null;
390
+ }
391
+ }
392
+ async del(key) {
393
+ if (!this.ready) return null;
394
+ try {
395
+ loggy.info(`Redis PURGING KEY: ${key}`);
396
+ await this.client.del(key);
397
+ return true;
398
+ } catch (error) {
399
+ loggy.error(`Redis del error: ${error}`);
400
+ return null;
401
+ }
402
+ }
403
+ async keys() {
404
+ if (!this.ready) return null;
405
+ try {
406
+ const keys = await this.client.keys("*");
407
+ return keys;
408
+ } catch (error) {
409
+ loggy.error(`Redis keys error: ${error}`);
410
+ return null;
411
+ }
412
+ }
413
+ async reset() {
414
+ if (!this.ready) return null;
415
+ try {
416
+ loggy.info(`Redis FLUSHING ALL KEYS`);
417
+ await this.client.flushdb();
418
+ return true;
419
+ } catch (error) {
420
+ loggy.error(`Redis reset error: ${error}`);
421
+ return null;
422
+ }
423
+ }
424
+ async clearByRegexp(regExps) {
425
+ const keys = await this.keys();
426
+ if (!keys) return;
427
+ const toDelete = keys.filter((key) => regExps.some((re) => re.test(key)));
428
+ await Promise.all(toDelete.map((key) => this.del(key)));
429
+ }
430
+ }
431
+ const resolveCacheProvider = (strapi2) => {
432
+ const providerType = strapi2.plugin("strapi-cache").config("provider") || "memory";
433
+ loggy.info(`Selected cache provider: ${providerType}`);
434
+ let instance;
435
+ switch (providerType) {
436
+ case "redis":
437
+ instance = new RedisCacheProvider(strapi2);
438
+ break;
439
+ default:
440
+ instance = new InMemoryCacheProvider(strapi2);
441
+ break;
442
+ }
443
+ return instance;
444
+ };
246
445
  const service = ({ strapi: strapi2 }) => {
247
- let cacheInstance = null;
446
+ let instance = null;
248
447
  return {
249
448
  createCache() {
250
- if (cacheInstance) {
251
- return cacheInstance;
449
+ if (!instance) {
450
+ loggy.info("Initializing cache service from provider config...");
451
+ instance = resolveCacheProvider(strapi2);
252
452
  }
253
- let initialized = false;
254
- let provider;
255
- loggy.info("Creating provider");
256
- const instance = {
257
- init() {
258
- if (initialized) {
259
- loggy.error("Provider already initialized");
260
- return;
261
- }
262
- initialized = true;
263
- const max = strapi2.plugin("strapi-cache").config("max");
264
- const ttl = strapi2.plugin("strapi-cache").config("ttl");
265
- const size = strapi2.plugin("strapi-cache").config("size");
266
- const allowStale = strapi2.plugin("strapi-cache").config("allowStale");
267
- provider = new lruCache.LRUCache({
268
- max: Number(max),
269
- ttl: Number(ttl),
270
- size: Number(size),
271
- allowStale: allowStale ? true : false
272
- });
273
- loggy.info("Provider initialized");
274
- },
275
- /**
276
- * @param {string} key
277
- */
278
- async get(key) {
279
- if (!initialized) {
280
- loggy.error("Provider not initialized");
281
- return null;
282
- }
283
- if (!this.ready) {
284
- loggy.error("Provider not ready");
285
- return null;
286
- }
287
- const getTimeout = 1e3;
288
- return withTimeout(async () => await provider.get(key), getTimeout).catch((error) => {
289
- if (error?.message === "timeout") {
290
- loggy.error(`Provider timed-out after ${getTimeout}ms.`);
291
- } else {
292
- loggy.error(`Provider errored:`);
293
- loggy.error(error);
294
- }
295
- return null;
296
- });
297
- },
298
- /**
299
- * @param {string} key
300
- * @param {any} val
301
- */
302
- async set(key, val) {
303
- if (!initialized) {
304
- loggy.error("Provider not initialized");
305
- return null;
306
- }
307
- if (!this.ready) {
308
- loggy.error("Provider not ready");
309
- return null;
310
- }
311
- try {
312
- const size = provider.size;
313
- return provider.set(key, val);
314
- } catch (error) {
315
- loggy.error(`Provider errored:`);
316
- loggy.error(error);
317
- return null;
318
- }
319
- },
320
- /**
321
- * @param {string} key
322
- */
323
- async del(key) {
324
- if (!initialized) {
325
- loggy.error("Provider not initialized");
326
- return null;
327
- }
328
- if (!this.ready) {
329
- loggy.error("Provider not ready");
330
- return null;
331
- }
332
- try {
333
- loggy.info(`PURGING KEY: ${key}`);
334
- return provider.delete(key);
335
- } catch (error) {
336
- loggy.error(`Provider errored:`);
337
- loggy.error(error);
338
- return null;
339
- }
340
- },
341
- async keys() {
342
- if (!initialized) {
343
- loggy.error("Provider not initialized");
344
- return null;
345
- }
346
- if (!this.ready) {
347
- loggy.error("Provider not ready");
348
- return null;
349
- }
350
- try {
351
- return Array.from(provider.keys());
352
- } catch (error) {
353
- loggy.error(`Provider errored:`);
354
- loggy.error(error);
355
- return null;
356
- }
357
- },
358
- async reset() {
359
- if (!initialized) {
360
- loggy.error("Provider not initialized");
361
- return null;
362
- }
363
- if (!this.ready) {
364
- loggy.error("Provider not ready");
365
- return null;
366
- }
367
- try {
368
- const allKeys = await this.keys();
369
- if (!allKeys) {
370
- loggy.error("Provider not ready");
371
- return null;
372
- }
373
- loggy.info(`PURGING ALL KEYS: ${allKeys.length}`);
374
- return this.keys().then((keys) => Promise.all(allKeys.map((key) => this.del(key))));
375
- } catch (error) {
376
- loggy.error(`Provider errored:`);
377
- loggy.error(error);
378
- return null;
379
- }
380
- },
381
- get ready() {
382
- if (!initialized) {
383
- loggy.info("Provider not initialized");
384
- return false;
385
- }
386
- return true;
387
- },
388
- /**
389
- * @param {RegExp[]} regExps
390
- */
391
- async clearByRegexp(regExps = []) {
392
- const keys = await this.keys() || [];
393
- const toDelete = keys.filter((key) => regExps.some((re) => re.test(key)));
394
- await Promise.all(toDelete.map((key) => this.del(key)));
395
- }
396
- };
397
- cacheInstance = instance;
398
453
  return instance;
399
454
  }
400
455
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../server/src/utils/log.ts","../../server/src/utils/invalidateCache.ts","../../server/src/bootstrap.ts","../../server/src/destroy.ts","../../server/src/utils/key.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/content-api.ts","../../server/src/routes/index.ts","../../server/src/utils/withTimeout.ts","../../server/src/services/service.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","import type { Core } from '@strapi/strapi';\nimport { invalidateCache, invalidateGraphqlCache } from './utils/invalidateCache';\nimport { CacheService } from './types/cache.types';\nimport { loggy } from './utils/log';\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.createCache();\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\nexport default bootstrap;\n","import type { Core } from '@strapi/strapi';\n\nconst destroy = ({ strapi }: { strapi: Core.Strapi }) => {\n // destroy phase\n};\n\nexport default destroy;\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 { Context } from 'koa';\nimport { generateCacheKey } from '../utils/key';\nimport { CacheService } from 'src/types/cache.types';\nimport { loggy } from '../utils/log';\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.createCache();\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 = 304;\n ctx.body = null;\n ctx.set(cacheEntry.headers);\n return;\n }\n\n await next();\n\n if (\n ctx.body &&\n ctx.method === 'GET' &&\n ctx.status >= 200 &&\n ctx.status <= 300 &&\n routeIsCachable\n ) {\n loggy.info(`MISS with key: ${key}`);\n await cacheStore.set(key, {\n body: ctx.body,\n headers: ctx.response.headers,\n });\n }\n};\n\nexport default middleware;\n","import rawBody from 'raw-body';\nimport { generateGraphqlCacheKey } from '../utils/key';\nimport { Readable } from 'stream';\nimport { loggy } from '../utils/log';\n\nconst middleware = async (ctx: any, next: any) => {\n const cacheService = strapi.plugin('strapi-cache').services.service;\n const cacheStore = cacheService.createCache();\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 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 return;\n }\n\n await next();\n\n if (\n ctx.body &&\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 await cacheStore.set(key, {\n body: ctx.body,\n headers: ctx.response.headers,\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 contentTypes: [],\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 },\n};\n","export default {};\n","import type { Core } from '@strapi/strapi';\nimport { Context } from 'koa';\n\nconst controller = ({ strapi }: { strapi: Core.Strapi }) => ({\n index(ctx: Context) {\n ctx.body = strapi\n .plugin('strapi-cache')\n // the name of the service file & the method.\n .service('service')\n .getWelcomeMessage();\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: 'GET',\n path: '/',\n // name of the controller file & the method.\n handler: 'controller.index',\n config: {\n policies: [],\n },\n },\n];\n","import contentAPIRoutes from './content-api';\n\nconst routes = {\n 'content-api': {\n type: 'content-api',\n routes: contentAPIRoutes,\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 '../../src/utils/withTimeout';\nimport { CacheProvider, CacheService } from '../types/cache.types';\nimport { loggy } from '../utils/log';\n\nconst service = ({ strapi }: { strapi: Core.Strapi }): CacheService => {\n let cacheInstance: CacheProvider | null = null;\n return {\n createCache() {\n if (cacheInstance) {\n return cacheInstance;\n }\n\n let initialized = false;\n let provider: LRUCache<string, any>;\n\n loggy.info('Creating provider');\n\n const instance: CacheProvider = {\n init() {\n if (initialized) {\n loggy.error('Provider already initialized');\n return;\n }\n\n initialized = true;\n const max = strapi.plugin('strapi-cache').config('max');\n const ttl = strapi.plugin('strapi-cache').config('ttl');\n const size = strapi.plugin('strapi-cache').config('size');\n const allowStale = strapi.plugin('strapi-cache').config('allowStale');\n\n provider = new LRUCache({\n max: Number(max),\n ttl: Number(ttl),\n size: Number(size),\n allowStale: allowStale ? true : false,\n });\n loggy.info('Provider initialized');\n },\n\n /**\n * @param {string} key\n */\n async get(key: string) {\n if (!initialized) {\n loggy.error('Provider not initialized');\n return null;\n }\n\n if (!this.ready) {\n loggy.error('Provider not ready');\n return null;\n }\n\n const getTimeout = 1000;\n return withTimeout(async () => await provider.get(key), getTimeout).catch((error) => {\n if (error?.message === 'timeout') {\n loggy.error(`Provider timed-out after ${getTimeout}ms.`);\n } else {\n loggy.error(`Provider errored:`);\n loggy.error(error);\n }\n return null;\n });\n },\n\n /**\n * @param {string} key\n * @param {any} val\n */\n async set(key: string, val: any) {\n if (!initialized) {\n loggy.error('Provider not initialized');\n return null;\n }\n\n if (!this.ready) {\n loggy.error('Provider not ready');\n return null;\n }\n\n try {\n const size = provider.size;\n return provider.set(key, val);\n } catch (error) {\n loggy.error(`Provider errored:`);\n loggy.error(error);\n return null;\n }\n },\n\n /**\n * @param {string} key\n */\n async del(key: string) {\n if (!initialized) {\n loggy.error('Provider not initialized');\n return null;\n }\n\n if (!this.ready) {\n loggy.error('Provider not ready');\n return null;\n }\n\n try {\n loggy.info(`PURGING KEY: ${key}`);\n return provider.delete(key);\n } catch (error) {\n loggy.error(`Provider errored:`);\n loggy.error(error);\n return null;\n }\n },\n\n async keys() {\n if (!initialized) {\n loggy.error('Provider not initialized');\n return null;\n }\n\n if (!this.ready) {\n loggy.error('Provider not ready');\n return null;\n }\n\n try {\n return Array.from(provider.keys());\n } catch (error) {\n loggy.error(`Provider errored:`);\n loggy.error(error);\n return null;\n }\n },\n\n async reset() {\n if (!initialized) {\n loggy.error('Provider not initialized');\n return null;\n }\n\n if (!this.ready) {\n loggy.error('Provider not ready');\n return null;\n }\n\n try {\n const allKeys = await this.keys();\n if (!allKeys) {\n loggy.error('Provider not ready');\n return null;\n }\n loggy.info(`PURGING ALL KEYS: ${allKeys.length}`);\n return this.keys().then((keys) => Promise.all(allKeys.map((key) => this.del(key))));\n } catch (error) {\n loggy.error(`Provider errored:`);\n loggy.error(error);\n return null;\n }\n },\n\n get ready() {\n if (!initialized) {\n loggy.info('Provider not initialized');\n return false;\n }\n\n return true;\n },\n\n /**\n * @param {RegExp[]} regExps\n */\n async clearByRegexp(regExps: RegExp[] = []) {\n const keys = (await this.keys()) || [];\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 cacheInstance = instance;\n return instance;\n },\n };\n};\n\nexport default service;\n","import service from './service';\n\nexport default {\n service,\n};\n","/**\n * Application methods\n */\nimport bootstrap from './bootstrap';\nimport destroy from './destroy';\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","middleware","rawBody","Readable","graphql","cache","config","LRUCache"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../server/src/utils/log.ts","../../server/src/utils/invalidateCache.ts","../../server/src/bootstrap.ts","../../server/src/destroy.ts","../../server/src/utils/key.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/content-api.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","import type { Core } from '@strapi/strapi';\nimport { invalidateCache, invalidateGraphqlCache } from './utils/invalidateCache';\nimport { CacheService } from './types/cache.types';\nimport { loggy } from './utils/log';\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.createCache();\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\nexport default bootstrap;\n","import type { Core } from '@strapi/strapi';\n\nconst destroy = ({ strapi }: { strapi: Core.Strapi }) => {\n // destroy phase\n};\n\nexport default destroy;\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 { Context } from 'koa';\nimport { generateCacheKey } from '../utils/key';\nimport { CacheService } from 'src/types/cache.types';\nimport { loggy } from '../utils/log';\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.createCache();\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;\n ctx.set({ 'Access-Control-Allow-Origin': '*' });\n return;\n }\n\n await next();\n\n if (\n ctx.body &&\n ctx.method === 'GET' &&\n ctx.status >= 200 &&\n ctx.status < 300 &&\n routeIsCachable\n ) {\n loggy.info(`MISS with key: ${key}`);\n await cacheStore.set(key, ctx.body);\n }\n};\n\nexport default middleware;\n","import rawBody from 'raw-body';\nimport { generateGraphqlCacheKey } from '../utils/key';\nimport { Readable } from 'stream';\nimport { loggy } from '../utils/log';\n\nconst middleware = async (ctx: any, next: any) => {\n const cacheService = strapi.plugin('strapi-cache').services.service;\n const cacheStore = cacheService.createCache();\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 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 return;\n }\n\n await next();\n\n if (\n ctx.body &&\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 await cacheStore.set(key, {\n body: ctx.body,\n headers: ctx.response.headers,\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';\n\nconst controller = ({ strapi }: { strapi: Core.Strapi }) => ({\n index(ctx: Context) {\n ctx.body = strapi\n .plugin('strapi-cache')\n // the name of the service file & the method.\n .service('service')\n .getWelcomeMessage();\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: 'GET',\n path: '/',\n // name of the controller file & the method.\n handler: 'controller.index',\n config: {\n policies: [],\n },\n },\n];\n","import contentAPIRoutes from './content-api';\n\nconst routes = {\n 'content-api': {\n type: 'content-api',\n routes: contentAPIRoutes,\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 { CacheService } from '../../src/types/cache.types';\nimport { loggy } from '../../src/utils/log';\n\nconst service = ({ strapi }: { strapi: Core.Strapi }): CacheService => {\n let instance = null;\n\n return {\n createCache() {\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 destroy from './destroy';\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","middleware","rawBody","Readable","graphql","cache","config","LRUCache","Redis"],"mappings":";;;;;;;;;AAAO,MAAM,QAAQ;AAAA,EACnB,MAAM,CAAC,QAAgB;AACrB,UAAM,cAAc,OAAO,OAAO,cAAc,EAAE,OAAO,OAAO,KAAK;AACrE,QAAI,CAAC,aAAa;AAChB;AAAA,IAAA;AAEF,WAAO,IAAI,KAAK,kBAAkB,GAAG,EAAE;AAAA,EACzC;AAAA,EACA,OAAO,CAAC,QAAgB;AACtB,UAAM,cAAc,OAAO,OAAO,cAAc,EAAE,OAAO,OAAO,KAAK;AACrE,QAAI,CAAC,aAAa;AAChB;AAAA,IAAA;AAEF,WAAO,IAAI,MAAM,kBAAkB,GAAG,EAAE;AAAA,EAC1C;AAAA,EACA,MAAM,CAAC,QAAgB;AACrB,UAAM,cAAc,OAAO,OAAO,cAAc,EAAE,OAAO,OAAO,KAAK;AACrE,QAAI,CAAC,aAAa;AAChB;AAAA,IAAA;AAEF,WAAO,IAAI,KAAK,kBAAkB,GAAG,EAAE;AAAA,EAAA;AAE3C;AClBsB,eAAA,gBAAgB,OAAY,YAA2BA,SAAqB;AAC1F,QAAA,EAAE,UAAU;AAClB,QAAM,MAAM,MAAM;AAEd,MAAA;AACI,UAAA,cAAcA,QAAO,YAAY,GAAG;AAE1C,QAAI,CAAC,eAAe,CAAC,YAAY,MAAM;AAC/B,YAAA,KAAK,gBAAgB,GAAG,YAAY;AAC1C;AAAA,IAAA;AAGI,UAAA,aACJ,YAAY,SAAS,eACjB,YAAY,KAAK,eACjB,YAAY,KAAK;AACjB,UAAA,UAAU,QAAQ,UAAU;AAClC,UAAM,QAAQ,IAAI,OAAO,OAAO,OAAO,iBAAiB;AAExD,UAAM,WAAW,cAAc,CAAC,KAAK,CAAC;AAChC,UAAA,KAAK,yBAAyB,OAAO,EAAE;AAAA,WACtC,OAAO;AACd,UAAM,MAAM,2BAA2B;AACvC,UAAM,MAAM,KAAK;AAAA,EAAA;AAErB;AAEsB,eAAA,uBACpB,OACA,YACAA,SACA;AACI,MAAA;AACI,UAAA,eAAe,IAAI,OAAO,uBAAwB;AAExD,UAAM,WAAW,cAAc,CAAC,YAAY,CAAC;AACvC,UAAA,KAAK,yBAAyB,YAAY,EAAE;AAAA,WAC3C,OAAO;AACd,UAAM,MAAM,2BAA2B;AACvC,UAAM,MAAM,KAAK;AAAA,EAAA;AAErB;ACxCA,MAAM,YAAY,CAAC,EAAE,QAAAA,cAAsC;AACzD,QAAM,KAAK,cAAc;AACrB,MAAA;AACF,UAAM,eAAeA,QAAO,OAAO,cAAc,EAAE,SAAS;AACtD,UAAA,aAAa,aAAa,YAAY;AAC5C,eAAW,KAAK;AAET,IAAAA,QAAA,GAAG,WAAW,UAAU;AAAA,MAC7B,MAAM,YAAY,OAAO;AACjB,cAAA,gBAAgB,OAAO,YAAYA,OAAM;AACzC,cAAA,uBAAuB,OAAO,YAAYA,OAAM;AAAA,MACxD;AAAA,MACA,MAAM,YAAY,OAAO;AACjB,cAAA,gBAAgB,OAAO,YAAYA,OAAM;AACzC,cAAA,uBAAuB,OAAO,YAAYA,OAAM;AAAA,MACxD;AAAA,MACA,MAAM,YAAY,OAAO;AACjB,cAAA,gBAAgB,OAAO,YAAYA,OAAM;AACzC,cAAA,uBAAuB,OAAO,YAAYA,OAAM;AAAA,MAAA;AAAA,IACxD,CACD;AAED,QAAI,CAAC,YAAY;AACf,YAAM,MAAM,iCAAiC;AAC7C;AAAA,IAAA;AAAA,WAEK,OAAO;AACd,UAAM,MAAM,iCAAiC;AAC7C;AAAA,EAAA;AAEF,QAAM,KAAK,oBAAoB;AACjC;AClCA,MAAM,UAAU,CAAC,EAAE,QAAAA,cAAsC;AAEzD;ACDa,MAAA,mBAAmB,CAAC,YAAqB;AAC9C,QAAA,EAAE,QAAQ,QAAQ;AAClB,QAAA,EAAE,WAAW,QAAQ;AAEpB,SAAA,GAAG,MAAM,IAAI,GAAG;AACzB;AAEa,MAAA,0BAA0B,CAAC,YAAoB;AACpD,QAAA,OAAOC,kBAAW,QAAQ,EAAE,OAAO,OAAO,EAAE,OAAO,WAAW;AACpE,SAAO,iBAAiB,IAAI;AAC9B;ACRA,MAAMC,eAAa,OAAO,KAAc,SAAc;AACpD,QAAM,eAAe,OAAO,OAAO,cAAc,EAAE,SAAS;AAC5D,QAAM,kBAAkB,OAAO,OAAO,cAAc,EAAE,OAAO,iBAAiB;AACxE,QAAA,aAAa,aAAa,YAAY;AACtC,QAAA,EAAE,QAAQ,IAAI;AACd,QAAA,MAAM,iBAAiB,GAAG;AAChC,QAAM,aAAa,MAAM,WAAW,IAAI,GAAG;AAC3C,QAAM,qBAAqB,IAAI,QAAQ,QAAQ,eAAe;AAC9D,QAAM,UAAU,sBAAsB,mBAAmB,SAAS,UAAU;AAC5E,QAAM,kBACJ,gBAAgB,KAAK,CAAC,UAAU,IAAI,WAAW,KAAK,CAAC,KACpD,gBAAgB,WAAW,KAAK,IAAI,WAAW,MAAM;AAEpD,MAAA,cAAc,CAAC,SAAS;AACpB,UAAA,KAAK,iBAAiB,GAAG,EAAE;AACjC,QAAI,SAAS;AACb,QAAI,OAAO;AACX,QAAI,IAAI,EAAE,+BAA+B,IAAA,CAAK;AAC9C;AAAA,EAAA;AAGF,QAAM,KAAK;AAGT,MAAA,IAAI,QACJ,IAAI,WAAW,SACf,IAAI,UAAU,OACd,IAAI,SAAS,OACb,iBACA;AACM,UAAA,KAAK,kBAAkB,GAAG,EAAE;AAClC,UAAM,WAAW,IAAI,KAAK,IAAI,IAAI;AAAA,EAAA;AAEtC;ACjCA,MAAM,aAAa,OAAO,KAAU,SAAc;AAChD,QAAM,eAAe,OAAO,OAAO,cAAc,EAAE,SAAS;AACtD,QAAA,aAAa,aAAa,YAAY;AACtC,QAAA,EAAE,QAAQ,IAAI;AAEpB,QAAM,cAAc,IAAI;AAClB,QAAA,aAAa,MAAMC,iBAAA,QAAQ,WAAW;AACtC,QAAA,OAAO,WAAW,SAAS;AAE3B,QAAA,YAAY,IAAIC,gBAAS;AAC/B,YAAU,KAAK,UAAU;AACzB,YAAU,KAAK,IAAI;AAElB,YAAkB,UAAU,EAAE,GAAG,YAAY,QAAQ;AACrD,YAAkB,SAAS,YAAY;AACvC,YAAkB,MAAM,YAAY;AACpC,YAAkB,cAAc,YAAY;AAC5C,YAAkB,SAAS,YAAY;AACvC,YAAkB,aAAa,YAAY;AAE5C,MAAI,MAAM;AACV,MAAI,QAAQ,MAAM;AAEZ,QAAA,MAAM,wBAAwB,IAAI;AACxC,QAAM,aAAa,MAAM,WAAW,IAAI,GAAG;AAC3C,QAAM,qBAAqB,IAAI,QAAQ,QAAQ,eAAe;AAC9D,QAAM,UAAU,sBAAsB,mBAAmB,SAAS,UAAU;AAExE,MAAA,cAAc,CAAC,SAAS;AACpB,UAAA,KAAK,iBAAiB,GAAG,EAAE;AACjC,QAAI,SAAS;AACb,QAAI,OAAO,WAAW;AAClB,QAAA,IAAI,WAAW,OAAO;AAC1B;AAAA,EAAA;AAGF,QAAM,KAAK;AAEX,MACE,IAAI,QACJ,IAAI,WAAW,UACf,IAAI,UAAU,OACd,IAAI,SAAS,OACb,IAAI,WAAW,UAAU,GACzB;AACM,UAAA,KAAK,kBAAkB,GAAG,EAAE;AAC5B,UAAA,WAAW,IAAI,KAAK;AAAA,MACxB,MAAM,IAAI;AAAA,MACV,SAAS,IAAI,SAAS;AAAA,IAAA,CACvB;AAAA,EAAA;AAEL;ACrDA,MAAe,cAAA;AAAA,EAAA,SACbC;AAAAA,EACAC,OAAAA;AACF;ACHA,MAAM,WAAW,CAAC,EAAE,QAAAN,cAAsC;AACjD,EAAAA,QAAA,OAAO,IAAI,YAAY,KAAK;AAC5B,EAAAA,QAAA,OAAO,IAAI,YAAY,OAAO;AACvC;ACNA,MAAe,SAAA;AAAA,EACb,SAAS,CAAC,EAAE,WAAW;AAAA,IACrB,OAAO;AAAA,IACP,KAAK;AAAA,IACL,KAAK,MAAO,KAAK;AAAA,IACjB,MAAM,OAAO,OAAO;AAAA,IACpB,YAAY;AAAA,IACZ,iBAAiB,CAAC;AAAA,IAClB,UAAU;AAAA,IACV,UAAU,IAAI,WAAW;AAAA,EAAA;AAAA,EAE3B,WAAW,CAACO,YAAW;AACjB,QAAA,OAAOA,QAAO,UAAU,WAAW;AAC/B,YAAA,IAAI,MAAM,yCAAyC;AAAA,IAAA;AAEvD,QAAA,OAAOA,QAAO,QAAQ,UAAU;AAC5B,YAAA,IAAI,MAAM,sCAAsC;AAAA,IAAA;AAEpD,QAAA,OAAOA,QAAO,QAAQ,UAAU;AAC5B,YAAA,IAAI,MAAM,sCAAsC;AAAA,IAAA;AAEpD,QAAA,OAAOA,QAAO,SAAS,UAAU;AAC7B,YAAA,IAAI,MAAM,uCAAuC;AAAA,IAAA;AAErD,QAAA,OAAOA,QAAO,eAAe,WAAW;AACpC,YAAA,IAAI,MAAM,8CAA8C;AAAA,IAAA;AAEhE,QACE,CAAC,MAAM,QAAQA,QAAO,eAAe,KACrCA,QAAO,gBAAgB,KAAK,CAAC,SAAS,OAAO,SAAS,QAAQ,GAC9D;AACM,YAAA,IAAI,MAAM,yDAAyD;AAAA,IAAA;AAEvE,QAAA,OAAOA,QAAO,aAAa,UAAU;AACjC,YAAA,IAAI,MAAM,2CAA2C;AAAA,IAAA;AAE7D,QAAIA,QAAO,aAAa,YAAYA,QAAO,aAAa,SAAS;AACzD,YAAA,IAAI,MAAM,sDAAsD;AAAA,IAAA;AAEpE,QAAAA,QAAO,aAAa,WAAW,CAACA,QAAO,YAAY,OAAOA,QAAO,aAAa,UAAU;AACpF,YAAA,IAAI,MAAM,gEAAgE;AAAA,IAAA;AAAA,EAClF;AAEJ;AC3CA,MAAA,eAAe,CAAC;ACGhB,MAAM,aAAa,CAAC,EAAE,QAAAP,eAAuC;AAAA,EAC3D,MAAM,KAAc;AACd,QAAA,OAAOA,QACR,OAAO,cAAc,EAErB,QAAQ,SAAS,EACjB,kBAAkB;AAAA,EAAA;AAEzB;ACTA,MAAe,cAAA;AAAA,EACb;AACF;ACJA,MAAA,WAAe,CAAC;ACAhB,MAAe,mBAAA;AAAA,EACb;AAAA,IACE,QAAQ;AAAA,IACR,MAAM;AAAA;AAAA,IAEN,SAAS;AAAA,IACT,QAAQ;AAAA,MACN,UAAU,CAAA;AAAA,IAAC;AAAA,EACb;AAEJ;ACRA,MAAM,SAAS;AAAA,EACb,eAAe;AAAA,IACb,MAAM;AAAA,IACN,QAAQ;AAAA,EAAA;AAEZ;ACPa,MAAA,cAAc,CAAC,UAA8B,OAAe;AACvE,MAAI,UAAiC;AAErC,SAAO,QAAQ,KAAK;AAAA,IAClB,SAAS,EAAE,KAAK,CAAC,WAAW;AAC1B,UAAI,SAAS;AACX,qBAAa,OAAO;AAAA,MAAA;AAEf,aAAA;AAAA,IAAA,CACR;AAAA,IACD,IAAI,QAAQ,CAAC,GAAG,WAAW;AACzB,gBAAU,WAAW,MAAM;AAClB,eAAA,IAAI,MAAM,SAAS,CAAC;AAAA,SAC1B,EAAE;AAAA,IACN,CAAA;AAAA,EAAA,CACF;AACH;ACVO,MAAM,sBAA+C;AAAA,EAI1D,YAAoBA,SAAqB;AAArB,SAAA,SAAAA;AAHpB,SAAQ,cAAc;AAAA,EAAA;AAAA,EAKtB,OAAa;AACX,QAAI,KAAK,aAAa;AACpB,YAAM,MAAM,8BAA8B;AAC1C;AAAA,IAAA;AAGF,SAAK,cAAc;AAEb,UAAA,MAAM,OAAO,KAAK,OAAO,OAAO,cAAc,EAAE,OAAO,KAAK,CAAC;AAC7D,UAAA,MAAM,OAAO,KAAK,OAAO,OAAO,cAAc,EAAE,OAAO,KAAK,CAAC;AAC7D,UAAA,OAAO,OAAO,KAAK,OAAO,OAAO,cAAc,EAAE,OAAO,MAAM,CAAC;AAC/D,UAAA,aAAa,QAAQ,KAAK,OAAO,OAAO,cAAc,EAAE,OAAO,YAAY,CAAC;AAE7E,SAAA,WAAW,IAAIQ,kBAAS;AAAA,MAC3B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA,CACD;AAED,UAAM,KAAK,sBAAsB;AAAA,EAAA;AAAA,EAGnC,IAAI,QAAiB;AACf,QAAA,CAAC,KAAK,aAAa;AACrB,YAAM,KAAK,0BAA0B;AAC9B,aAAA;AAAA,IAAA;AAGF,WAAA;AAAA,EAAA;AAAA,EAGT,MAAM,IAAI,KAAkC;AACtC,QAAA,CAAC,KAAK,MAAc,QAAA;AAExB,UAAM,UAAU;AACT,WAAA;AAAA,MACL,MACE,IAAI,QAAQ,CAAC,YAAY;AACvB,gBAAQ,KAAK,SAAS,IAAI,GAAG,CAAC;AAAA,MAAA,CAC/B;AAAA,MACH;AAAA,IAAA,EACA,MAAM,CAAC,UAAU;AACjB,YAAM,MAAM,qBAAqB,OAAO,WAAW,KAAK,EAAE;AACnD,aAAA;AAAA,IAAA,CACR;AAAA,EAAA;AAAA,EAGH,MAAM,IAAI,KAAa,KAA+B;AAChD,QAAA,CAAC,KAAK,MAAc,QAAA;AAEpB,QAAA;AACF,aAAO,KAAK,SAAS,IAAI,KAAK,GAAG;AAAA,aAC1B,OAAO;AACR,YAAA,MAAM,qBAAqB,KAAK,EAAE;AACjC,aAAA;AAAA,IAAA;AAAA,EACT;AAAA,EAGF,MAAM,IAAI,KAAkC;AACtC,QAAA,CAAC,KAAK,MAAc,QAAA;AAEpB,QAAA;AACI,YAAA,KAAK,gBAAgB,GAAG,EAAE;AACzB,aAAA,KAAK,SAAS,OAAO,GAAG;AAAA,aACxB,OAAO;AACR,YAAA,MAAM,wBAAwB,KAAK,EAAE;AACpC,aAAA;AAAA,IAAA;AAAA,EACT;AAAA,EAGF,MAAM,OAAiC;AACjC,QAAA,CAAC,KAAK,MAAc,QAAA;AAEpB,QAAA;AACF,aAAO,MAAM,KAAK,KAAK,SAAS,MAAM;AAAA,aAC/B,OAAO;AACR,YAAA,MAAM,wBAAwB,KAAK,EAAE;AACpC,aAAA;AAAA,IAAA;AAAA,EACT;AAAA,EAGF,MAAM,QAA6B;AAC7B,QAAA,CAAC,KAAK,MAAc,QAAA;AAEpB,QAAA;AACI,YAAA,UAAU,MAAM,KAAK,KAAK;AAC5B,UAAA,CAAC,QAAgB,QAAA;AAErB,YAAM,KAAK,qBAAqB,QAAQ,MAAM,EAAE;AAC1C,YAAA,QAAQ,IAAI,QAAQ,IAAI,CAAC,QAAQ,KAAK,IAAI,GAAG,CAAC,CAAC;AAC9C,aAAA;AAAA,aACA,OAAO;AACR,YAAA,MAAM,uBAAuB,KAAK,EAAE;AACnC,aAAA;AAAA,IAAA;AAAA,EACT;AAAA,EAGF,MAAM,cAAc,SAAkC;AACpD,UAAM,OAAQ,MAAM,KAAK,UAAW,CAAC;AACrC,UAAM,UAAU,KAAK,OAAO,CAAC,QAAQ,QAAQ,KAAK,CAAC,OAAO,GAAG,KAAK,GAAG,CAAC,CAAC;AACjE,UAAA,QAAQ,IAAI,QAAQ,IAAI,CAAC,QAAQ,KAAK,IAAI,GAAG,CAAC,CAAC;AAAA,EAAA;AAEzD;AC7GO,MAAM,mBAA4C;AAAA,EAIvD,YAAoBR,SAAqB;AAArB,SAAA,SAAAA;AAHpB,SAAQ,cAAc;AAAA,EAAA;AAAA,EAKtB,OAAa;AACX,QAAI,KAAK,aAAa;AACpB,YAAM,MAAM,oCAAoC;AAChD;AAAA,IAAA;AAGI,UAAA,WACJ,KAAK,OAAO,OAAO,cAAc,EAAE,OAAO,UAAU,KAAK;AAEtD,SAAA,SAAS,IAAIS,eAAA,QAAM,QAAQ;AAChC,SAAK,cAAc;AAEnB,UAAM,KAAK,4BAA4B;AAAA,EAAA;AAAA,EAGzC,IAAI,QAAiB;AACf,QAAA,CAAC,KAAK,aAAa;AACrB,YAAM,KAAK,gCAAgC;AACpC,aAAA;AAAA,IAAA;AAGF,WAAA;AAAA,EAAA;AAAA,EAGT,MAAM,IAAI,KAAkC;AACtC,QAAA,CAAC,KAAK,MAAc,QAAA;AAExB,UAAM,UAAU;AACT,WAAA,YAAY,MAAM,KAAK,OAAO,IAAI,GAAG,GAAG,OAAO,EACnD,KAAK,CAAC,SAAU,OAAO,KAAK,MAAM,IAAI,IAAI,IAAK,EAC/C,MAAM,CAAC,UAAU;AAChB,YAAM,MAAM,oBAAoB,OAAO,WAAW,KAAK,EAAE;AAClD,aAAA;AAAA,IAAA,CACR;AAAA,EAAA;AAAA,EAGL,MAAM,IAAI,KAAa,KAA+B;AAChD,QAAA,CAAC,KAAK,MAAc,QAAA;AAEpB,QAAA;AACI,YAAA,MAAM,OAAO,KAAK,OAAO,OAAO,cAAc,EAAE,OAAO,KAAK,CAAC;AAC7D,YAAA,aAAa,KAAK,UAAU,GAAG;AACrC,UAAI,MAAM,GAAG;AACX,cAAM,KAAK,OAAO,IAAI,KAAK,YAAY,MAAM,GAAG;AAAA,MAAA,OAC3C;AACL,cAAM,KAAK,OAAO,IAAI,KAAK,UAAU;AAAA,MAAA;AAEhC,aAAA;AAAA,aACA,OAAO;AACR,YAAA,MAAM,oBAAoB,KAAK,EAAE;AAChC,aAAA;AAAA,IAAA;AAAA,EACT;AAAA,EAGF,MAAM,IAAI,KAAkC;AACtC,QAAA,CAAC,KAAK,MAAc,QAAA;AAEpB,QAAA;AACI,YAAA,KAAK,sBAAsB,GAAG,EAAE;AAChC,YAAA,KAAK,OAAO,IAAI,GAAG;AAClB,aAAA;AAAA,aACA,OAAO;AACR,YAAA,MAAM,oBAAoB,KAAK,EAAE;AAChC,aAAA;AAAA,IAAA;AAAA,EACT;AAAA,EAGF,MAAM,OAAiC;AACjC,QAAA,CAAC,KAAK,MAAc,QAAA;AAEpB,QAAA;AACF,YAAM,OAAO,MAAM,KAAK,OAAO,KAAK,GAAG;AAChC,aAAA;AAAA,aACA,OAAO;AACR,YAAA,MAAM,qBAAqB,KAAK,EAAE;AACjC,aAAA;AAAA,IAAA;AAAA,EACT;AAAA,EAGF,MAAM,QAA6B;AAC7B,QAAA,CAAC,KAAK,MAAc,QAAA;AAEpB,QAAA;AACF,YAAM,KAAK,yBAAyB;AAC9B,YAAA,KAAK,OAAO,QAAQ;AACnB,aAAA;AAAA,aACA,OAAO;AACR,YAAA,MAAM,sBAAsB,KAAK,EAAE;AAClC,aAAA;AAAA,IAAA;AAAA,EACT;AAAA,EAGF,MAAM,cAAc,SAAkC;AAC9C,UAAA,OAAO,MAAM,KAAK,KAAK;AAC7B,QAAI,CAAC,KAAM;AAEX,UAAM,WAAW,KAAK,OAAO,CAAC,QAAQ,QAAQ,KAAK,CAAC,OAAO,GAAG,KAAK,GAAG,CAAC,CAAC;AAClE,UAAA,QAAQ,IAAI,SAAS,IAAI,CAAC,QAAQ,KAAK,IAAI,GAAG,CAAC,CAAC;AAAA,EAAA;AAE1D;ACzGa,MAAA,uBAAuB,CAACT,YAAuC;AAC1E,QAAM,eAAeA,QAAO,OAAO,cAAc,EAAE,OAAO,UAAU,KAAK;AAEnE,QAAA,KAAK,4BAA4B,YAAY,EAAE;AAEjD,MAAA;AAEJ,UAAQ,cAAc;AAAA,IACpB,KAAK;AACQ,iBAAA,IAAI,mBAAmBA,OAAM;AACxC;AAAA,IACF;AACa,iBAAA,IAAI,sBAAsBA,OAAM;AAC3C;AAAA,EAAA;AAGG,SAAA;AACT;AClBA,MAAM,UAAU,CAAC,EAAE,QAAAA,cAAoD;AACrE,MAAI,WAAW;AAER,SAAA;AAAA,IACL,cAAc;AACZ,UAAI,CAAC,UAAU;AACb,cAAM,KAAK,oDAAoD;AAC/D,mBAAW,qBAAqBA,OAAM;AAAA,MAAA;AAEjC,aAAA;AAAA,IAAA;AAAA,EAEX;AACF;AAEA,MAAe,WAAA;AAAA,EACb;AACF;ACHA,MAAe,QAAA;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;;"}
@@ -2,6 +2,7 @@ import { createHash } from "crypto";
2
2
  import rawBody from "raw-body";
3
3
  import { Readable } from "stream";
4
4
  import { LRUCache } from "lru-cache";
5
+ import Redis from "ioredis";
5
6
  const loggy = {
6
7
  info: (msg) => {
7
8
  const shouldDebug = strapi.plugin("strapi-cache").config("debug") ?? false;
@@ -107,18 +108,15 @@ const middleware$1 = async (ctx, next) => {
107
108
  const routeIsCachable = cacheableRoutes.some((route) => url.startsWith(route)) || cacheableRoutes.length === 0 && url.startsWith("/api");
108
109
  if (cacheEntry && !noCache) {
109
110
  loggy.info(`HIT with key: ${key}`);
110
- ctx.status = 304;
111
- ctx.body = null;
112
- ctx.set(cacheEntry.headers);
111
+ ctx.status = 200;
112
+ ctx.body = cacheEntry;
113
+ ctx.set({ "Access-Control-Allow-Origin": "*" });
113
114
  return;
114
115
  }
115
116
  await next();
116
- if (ctx.body && ctx.method === "GET" && ctx.status >= 200 && ctx.status <= 300 && routeIsCachable) {
117
+ if (ctx.body && ctx.method === "GET" && ctx.status >= 200 && ctx.status < 300 && routeIsCachable) {
117
118
  loggy.info(`MISS with key: ${key}`);
118
- await cacheStore.set(key, {
119
- body: ctx.body,
120
- headers: ctx.response.headers
121
- });
119
+ await cacheStore.set(key, ctx.body);
122
120
  }
123
121
  };
124
122
  const middleware = async (ctx, next) => {
@@ -151,7 +149,7 @@ const middleware = async (ctx, next) => {
151
149
  return;
152
150
  }
153
151
  await next();
154
- if (ctx.body && ctx.method === "POST" && ctx.status >= 200 && ctx.status <= 300 && url.startsWith("/graphql")) {
152
+ if (ctx.body && ctx.method === "POST" && ctx.status >= 200 && ctx.status < 300 && url.startsWith("/graphql")) {
155
153
  loggy.info(`MISS with key: ${key}`);
156
154
  await cacheStore.set(key, {
157
155
  body: ctx.body,
@@ -174,7 +172,9 @@ const config = {
174
172
  ttl: 1e3 * 60 * 60,
175
173
  size: 1024 * 1014 * 10,
176
174
  allowStale: false,
177
- contentTypes: []
175
+ cacheableRoutes: [],
176
+ provider: "memory",
177
+ redisUrl: env("REDIS_URL")
178
178
  }),
179
179
  validator: (config2) => {
180
180
  if (typeof config2.debug !== "boolean") {
@@ -195,6 +195,15 @@ const config = {
195
195
  if (!Array.isArray(config2.cacheableRoutes) || config2.cacheableRoutes.some((item) => typeof item !== "string")) {
196
196
  throw new Error(`Invalid config: cacheableRoutes must be an string array`);
197
197
  }
198
+ if (typeof config2.provider !== "string") {
199
+ throw new Error(`Invalid config: provider must be a string`);
200
+ }
201
+ if (config2.provider !== "memory" && config2.provider !== "redis") {
202
+ throw new Error(`Invalid config: provider must be 'memory' or 'redis'`);
203
+ }
204
+ if (config2.provider === "redis" && !config2.redisUrl && typeof config2.redisUrl !== "string") {
205
+ throw new Error(`Invalid config: redisUrl must be set when using redis provider`);
206
+ }
198
207
  }
199
208
  };
200
209
  const contentTypes = {};
@@ -240,158 +249,203 @@ const withTimeout = (callback, ms) => {
240
249
  })
241
250
  ]);
242
251
  };
252
+ class InMemoryCacheProvider {
253
+ constructor(strapi2) {
254
+ this.strapi = strapi2;
255
+ this.initialized = false;
256
+ }
257
+ init() {
258
+ if (this.initialized) {
259
+ loggy.error("Provider already initialized");
260
+ return;
261
+ }
262
+ this.initialized = true;
263
+ const max = Number(this.strapi.plugin("strapi-cache").config("max"));
264
+ const ttl = Number(this.strapi.plugin("strapi-cache").config("ttl"));
265
+ const size = Number(this.strapi.plugin("strapi-cache").config("size"));
266
+ const allowStale = Boolean(this.strapi.plugin("strapi-cache").config("allowStale"));
267
+ this.provider = new LRUCache({
268
+ max,
269
+ ttl,
270
+ size,
271
+ allowStale
272
+ });
273
+ loggy.info("Provider initialized");
274
+ }
275
+ get ready() {
276
+ if (!this.initialized) {
277
+ loggy.info("Provider not initialized");
278
+ return false;
279
+ }
280
+ return true;
281
+ }
282
+ async get(key) {
283
+ if (!this.ready) return null;
284
+ const timeout = 1e3;
285
+ return withTimeout(
286
+ () => new Promise((resolve) => {
287
+ resolve(this.provider.get(key));
288
+ }),
289
+ timeout
290
+ ).catch((error) => {
291
+ loggy.error(`Error during get: ${error?.message || error}`);
292
+ return null;
293
+ });
294
+ }
295
+ async set(key, val) {
296
+ if (!this.ready) return null;
297
+ try {
298
+ return this.provider.set(key, val);
299
+ } catch (error) {
300
+ loggy.error(`Error during set: ${error}`);
301
+ return null;
302
+ }
303
+ }
304
+ async del(key) {
305
+ if (!this.ready) return null;
306
+ try {
307
+ loggy.info(`PURGING KEY: ${key}`);
308
+ return this.provider.delete(key);
309
+ } catch (error) {
310
+ loggy.error(`Error during delete: ${error}`);
311
+ return null;
312
+ }
313
+ }
314
+ async keys() {
315
+ if (!this.ready) return null;
316
+ try {
317
+ return Array.from(this.provider.keys());
318
+ } catch (error) {
319
+ loggy.error(`Error fetching keys: ${error}`);
320
+ return null;
321
+ }
322
+ }
323
+ async reset() {
324
+ if (!this.ready) return null;
325
+ try {
326
+ const allKeys = await this.keys();
327
+ if (!allKeys) return null;
328
+ loggy.info(`PURGING ALL KEYS: ${allKeys.length}`);
329
+ await Promise.all(allKeys.map((key) => this.del(key)));
330
+ return true;
331
+ } catch (error) {
332
+ loggy.error(`Error during reset: ${error}`);
333
+ return null;
334
+ }
335
+ }
336
+ async clearByRegexp(regExps) {
337
+ const keys = await this.keys() || [];
338
+ const matches = keys.filter((key) => regExps.some((re) => re.test(key)));
339
+ await Promise.all(matches.map((key) => this.del(key)));
340
+ }
341
+ }
342
+ class RedisCacheProvider {
343
+ constructor(strapi2) {
344
+ this.strapi = strapi2;
345
+ this.initialized = false;
346
+ }
347
+ init() {
348
+ if (this.initialized) {
349
+ loggy.error("Redis provider already initialized");
350
+ return;
351
+ }
352
+ const redisUrl = this.strapi.plugin("strapi-cache").config("redisUrl") || "redis://localhost:6379";
353
+ this.client = new Redis(redisUrl);
354
+ this.initialized = true;
355
+ loggy.info("Redis provider initialized");
356
+ }
357
+ get ready() {
358
+ if (!this.initialized) {
359
+ loggy.info("Redis provider not initialized");
360
+ return false;
361
+ }
362
+ return true;
363
+ }
364
+ async get(key) {
365
+ if (!this.ready) return null;
366
+ const timeout = 1e3;
367
+ return withTimeout(() => this.client.get(key), timeout).then((data) => data ? JSON.parse(data) : null).catch((error) => {
368
+ loggy.error(`Redis get error: ${error?.message || error}`);
369
+ return null;
370
+ });
371
+ }
372
+ async set(key, val) {
373
+ if (!this.ready) return null;
374
+ try {
375
+ const ttl = Number(this.strapi.plugin("strapi-cache").config("ttl"));
376
+ const serialized = JSON.stringify(val);
377
+ if (ttl > 0) {
378
+ await this.client.set(key, serialized, "EX", ttl);
379
+ } else {
380
+ await this.client.set(key, serialized);
381
+ }
382
+ return val;
383
+ } catch (error) {
384
+ loggy.error(`Redis set error: ${error}`);
385
+ return null;
386
+ }
387
+ }
388
+ async del(key) {
389
+ if (!this.ready) return null;
390
+ try {
391
+ loggy.info(`Redis PURGING KEY: ${key}`);
392
+ await this.client.del(key);
393
+ return true;
394
+ } catch (error) {
395
+ loggy.error(`Redis del error: ${error}`);
396
+ return null;
397
+ }
398
+ }
399
+ async keys() {
400
+ if (!this.ready) return null;
401
+ try {
402
+ const keys = await this.client.keys("*");
403
+ return keys;
404
+ } catch (error) {
405
+ loggy.error(`Redis keys error: ${error}`);
406
+ return null;
407
+ }
408
+ }
409
+ async reset() {
410
+ if (!this.ready) return null;
411
+ try {
412
+ loggy.info(`Redis FLUSHING ALL KEYS`);
413
+ await this.client.flushdb();
414
+ return true;
415
+ } catch (error) {
416
+ loggy.error(`Redis reset error: ${error}`);
417
+ return null;
418
+ }
419
+ }
420
+ async clearByRegexp(regExps) {
421
+ const keys = await this.keys();
422
+ if (!keys) return;
423
+ const toDelete = keys.filter((key) => regExps.some((re) => re.test(key)));
424
+ await Promise.all(toDelete.map((key) => this.del(key)));
425
+ }
426
+ }
427
+ const resolveCacheProvider = (strapi2) => {
428
+ const providerType = strapi2.plugin("strapi-cache").config("provider") || "memory";
429
+ loggy.info(`Selected cache provider: ${providerType}`);
430
+ let instance;
431
+ switch (providerType) {
432
+ case "redis":
433
+ instance = new RedisCacheProvider(strapi2);
434
+ break;
435
+ default:
436
+ instance = new InMemoryCacheProvider(strapi2);
437
+ break;
438
+ }
439
+ return instance;
440
+ };
243
441
  const service = ({ strapi: strapi2 }) => {
244
- let cacheInstance = null;
442
+ let instance = null;
245
443
  return {
246
444
  createCache() {
247
- if (cacheInstance) {
248
- return cacheInstance;
445
+ if (!instance) {
446
+ loggy.info("Initializing cache service from provider config...");
447
+ instance = resolveCacheProvider(strapi2);
249
448
  }
250
- let initialized = false;
251
- let provider;
252
- loggy.info("Creating provider");
253
- const instance = {
254
- init() {
255
- if (initialized) {
256
- loggy.error("Provider already initialized");
257
- return;
258
- }
259
- initialized = true;
260
- const max = strapi2.plugin("strapi-cache").config("max");
261
- const ttl = strapi2.plugin("strapi-cache").config("ttl");
262
- const size = strapi2.plugin("strapi-cache").config("size");
263
- const allowStale = strapi2.plugin("strapi-cache").config("allowStale");
264
- provider = new LRUCache({
265
- max: Number(max),
266
- ttl: Number(ttl),
267
- size: Number(size),
268
- allowStale: allowStale ? true : false
269
- });
270
- loggy.info("Provider initialized");
271
- },
272
- /**
273
- * @param {string} key
274
- */
275
- async get(key) {
276
- if (!initialized) {
277
- loggy.error("Provider not initialized");
278
- return null;
279
- }
280
- if (!this.ready) {
281
- loggy.error("Provider not ready");
282
- return null;
283
- }
284
- const getTimeout = 1e3;
285
- return withTimeout(async () => await provider.get(key), getTimeout).catch((error) => {
286
- if (error?.message === "timeout") {
287
- loggy.error(`Provider timed-out after ${getTimeout}ms.`);
288
- } else {
289
- loggy.error(`Provider errored:`);
290
- loggy.error(error);
291
- }
292
- return null;
293
- });
294
- },
295
- /**
296
- * @param {string} key
297
- * @param {any} val
298
- */
299
- async set(key, val) {
300
- if (!initialized) {
301
- loggy.error("Provider not initialized");
302
- return null;
303
- }
304
- if (!this.ready) {
305
- loggy.error("Provider not ready");
306
- return null;
307
- }
308
- try {
309
- const size = provider.size;
310
- return provider.set(key, val);
311
- } catch (error) {
312
- loggy.error(`Provider errored:`);
313
- loggy.error(error);
314
- return null;
315
- }
316
- },
317
- /**
318
- * @param {string} key
319
- */
320
- async del(key) {
321
- if (!initialized) {
322
- loggy.error("Provider not initialized");
323
- return null;
324
- }
325
- if (!this.ready) {
326
- loggy.error("Provider not ready");
327
- return null;
328
- }
329
- try {
330
- loggy.info(`PURGING KEY: ${key}`);
331
- return provider.delete(key);
332
- } catch (error) {
333
- loggy.error(`Provider errored:`);
334
- loggy.error(error);
335
- return null;
336
- }
337
- },
338
- async keys() {
339
- if (!initialized) {
340
- loggy.error("Provider not initialized");
341
- return null;
342
- }
343
- if (!this.ready) {
344
- loggy.error("Provider not ready");
345
- return null;
346
- }
347
- try {
348
- return Array.from(provider.keys());
349
- } catch (error) {
350
- loggy.error(`Provider errored:`);
351
- loggy.error(error);
352
- return null;
353
- }
354
- },
355
- async reset() {
356
- if (!initialized) {
357
- loggy.error("Provider not initialized");
358
- return null;
359
- }
360
- if (!this.ready) {
361
- loggy.error("Provider not ready");
362
- return null;
363
- }
364
- try {
365
- const allKeys = await this.keys();
366
- if (!allKeys) {
367
- loggy.error("Provider not ready");
368
- return null;
369
- }
370
- loggy.info(`PURGING ALL KEYS: ${allKeys.length}`);
371
- return this.keys().then((keys) => Promise.all(allKeys.map((key) => this.del(key))));
372
- } catch (error) {
373
- loggy.error(`Provider errored:`);
374
- loggy.error(error);
375
- return null;
376
- }
377
- },
378
- get ready() {
379
- if (!initialized) {
380
- loggy.info("Provider not initialized");
381
- return false;
382
- }
383
- return true;
384
- },
385
- /**
386
- * @param {RegExp[]} regExps
387
- */
388
- async clearByRegexp(regExps = []) {
389
- const keys = await this.keys() || [];
390
- const toDelete = keys.filter((key) => regExps.some((re) => re.test(key)));
391
- await Promise.all(toDelete.map((key) => this.del(key)));
392
- }
393
- };
394
- cacheInstance = instance;
395
449
  return instance;
396
450
  }
397
451
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../../server/src/utils/log.ts","../../server/src/utils/invalidateCache.ts","../../server/src/bootstrap.ts","../../server/src/destroy.ts","../../server/src/utils/key.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/content-api.ts","../../server/src/routes/index.ts","../../server/src/utils/withTimeout.ts","../../server/src/services/service.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","import type { Core } from '@strapi/strapi';\nimport { invalidateCache, invalidateGraphqlCache } from './utils/invalidateCache';\nimport { CacheService } from './types/cache.types';\nimport { loggy } from './utils/log';\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.createCache();\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\nexport default bootstrap;\n","import type { Core } from '@strapi/strapi';\n\nconst destroy = ({ strapi }: { strapi: Core.Strapi }) => {\n // destroy phase\n};\n\nexport default destroy;\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 { Context } from 'koa';\nimport { generateCacheKey } from '../utils/key';\nimport { CacheService } from 'src/types/cache.types';\nimport { loggy } from '../utils/log';\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.createCache();\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 = 304;\n ctx.body = null;\n ctx.set(cacheEntry.headers);\n return;\n }\n\n await next();\n\n if (\n ctx.body &&\n ctx.method === 'GET' &&\n ctx.status >= 200 &&\n ctx.status <= 300 &&\n routeIsCachable\n ) {\n loggy.info(`MISS with key: ${key}`);\n await cacheStore.set(key, {\n body: ctx.body,\n headers: ctx.response.headers,\n });\n }\n};\n\nexport default middleware;\n","import rawBody from 'raw-body';\nimport { generateGraphqlCacheKey } from '../utils/key';\nimport { Readable } from 'stream';\nimport { loggy } from '../utils/log';\n\nconst middleware = async (ctx: any, next: any) => {\n const cacheService = strapi.plugin('strapi-cache').services.service;\n const cacheStore = cacheService.createCache();\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 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 return;\n }\n\n await next();\n\n if (\n ctx.body &&\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 await cacheStore.set(key, {\n body: ctx.body,\n headers: ctx.response.headers,\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 contentTypes: [],\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 },\n};\n","export default {};\n","import type { Core } from '@strapi/strapi';\nimport { Context } from 'koa';\n\nconst controller = ({ strapi }: { strapi: Core.Strapi }) => ({\n index(ctx: Context) {\n ctx.body = strapi\n .plugin('strapi-cache')\n // the name of the service file & the method.\n .service('service')\n .getWelcomeMessage();\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: 'GET',\n path: '/',\n // name of the controller file & the method.\n handler: 'controller.index',\n config: {\n policies: [],\n },\n },\n];\n","import contentAPIRoutes from './content-api';\n\nconst routes = {\n 'content-api': {\n type: 'content-api',\n routes: contentAPIRoutes,\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 '../../src/utils/withTimeout';\nimport { CacheProvider, CacheService } from '../types/cache.types';\nimport { loggy } from '../utils/log';\n\nconst service = ({ strapi }: { strapi: Core.Strapi }): CacheService => {\n let cacheInstance: CacheProvider | null = null;\n return {\n createCache() {\n if (cacheInstance) {\n return cacheInstance;\n }\n\n let initialized = false;\n let provider: LRUCache<string, any>;\n\n loggy.info('Creating provider');\n\n const instance: CacheProvider = {\n init() {\n if (initialized) {\n loggy.error('Provider already initialized');\n return;\n }\n\n initialized = true;\n const max = strapi.plugin('strapi-cache').config('max');\n const ttl = strapi.plugin('strapi-cache').config('ttl');\n const size = strapi.plugin('strapi-cache').config('size');\n const allowStale = strapi.plugin('strapi-cache').config('allowStale');\n\n provider = new LRUCache({\n max: Number(max),\n ttl: Number(ttl),\n size: Number(size),\n allowStale: allowStale ? true : false,\n });\n loggy.info('Provider initialized');\n },\n\n /**\n * @param {string} key\n */\n async get(key: string) {\n if (!initialized) {\n loggy.error('Provider not initialized');\n return null;\n }\n\n if (!this.ready) {\n loggy.error('Provider not ready');\n return null;\n }\n\n const getTimeout = 1000;\n return withTimeout(async () => await provider.get(key), getTimeout).catch((error) => {\n if (error?.message === 'timeout') {\n loggy.error(`Provider timed-out after ${getTimeout}ms.`);\n } else {\n loggy.error(`Provider errored:`);\n loggy.error(error);\n }\n return null;\n });\n },\n\n /**\n * @param {string} key\n * @param {any} val\n */\n async set(key: string, val: any) {\n if (!initialized) {\n loggy.error('Provider not initialized');\n return null;\n }\n\n if (!this.ready) {\n loggy.error('Provider not ready');\n return null;\n }\n\n try {\n const size = provider.size;\n return provider.set(key, val);\n } catch (error) {\n loggy.error(`Provider errored:`);\n loggy.error(error);\n return null;\n }\n },\n\n /**\n * @param {string} key\n */\n async del(key: string) {\n if (!initialized) {\n loggy.error('Provider not initialized');\n return null;\n }\n\n if (!this.ready) {\n loggy.error('Provider not ready');\n return null;\n }\n\n try {\n loggy.info(`PURGING KEY: ${key}`);\n return provider.delete(key);\n } catch (error) {\n loggy.error(`Provider errored:`);\n loggy.error(error);\n return null;\n }\n },\n\n async keys() {\n if (!initialized) {\n loggy.error('Provider not initialized');\n return null;\n }\n\n if (!this.ready) {\n loggy.error('Provider not ready');\n return null;\n }\n\n try {\n return Array.from(provider.keys());\n } catch (error) {\n loggy.error(`Provider errored:`);\n loggy.error(error);\n return null;\n }\n },\n\n async reset() {\n if (!initialized) {\n loggy.error('Provider not initialized');\n return null;\n }\n\n if (!this.ready) {\n loggy.error('Provider not ready');\n return null;\n }\n\n try {\n const allKeys = await this.keys();\n if (!allKeys) {\n loggy.error('Provider not ready');\n return null;\n }\n loggy.info(`PURGING ALL KEYS: ${allKeys.length}`);\n return this.keys().then((keys) => Promise.all(allKeys.map((key) => this.del(key))));\n } catch (error) {\n loggy.error(`Provider errored:`);\n loggy.error(error);\n return null;\n }\n },\n\n get ready() {\n if (!initialized) {\n loggy.info('Provider not initialized');\n return false;\n }\n\n return true;\n },\n\n /**\n * @param {RegExp[]} regExps\n */\n async clearByRegexp(regExps: RegExp[] = []) {\n const keys = (await this.keys()) || [];\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 cacheInstance = instance;\n return instance;\n },\n };\n};\n\nexport default service;\n","import service from './service';\n\nexport default {\n service,\n};\n","/**\n * Application methods\n */\nimport bootstrap from './bootstrap';\nimport destroy from './destroy';\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"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../../server/src/utils/log.ts","../../server/src/utils/invalidateCache.ts","../../server/src/bootstrap.ts","../../server/src/destroy.ts","../../server/src/utils/key.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/content-api.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","import type { Core } from '@strapi/strapi';\nimport { invalidateCache, invalidateGraphqlCache } from './utils/invalidateCache';\nimport { CacheService } from './types/cache.types';\nimport { loggy } from './utils/log';\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.createCache();\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\nexport default bootstrap;\n","import type { Core } from '@strapi/strapi';\n\nconst destroy = ({ strapi }: { strapi: Core.Strapi }) => {\n // destroy phase\n};\n\nexport default destroy;\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 { Context } from 'koa';\nimport { generateCacheKey } from '../utils/key';\nimport { CacheService } from 'src/types/cache.types';\nimport { loggy } from '../utils/log';\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.createCache();\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;\n ctx.set({ 'Access-Control-Allow-Origin': '*' });\n return;\n }\n\n await next();\n\n if (\n ctx.body &&\n ctx.method === 'GET' &&\n ctx.status >= 200 &&\n ctx.status < 300 &&\n routeIsCachable\n ) {\n loggy.info(`MISS with key: ${key}`);\n await cacheStore.set(key, ctx.body);\n }\n};\n\nexport default middleware;\n","import rawBody from 'raw-body';\nimport { generateGraphqlCacheKey } from '../utils/key';\nimport { Readable } from 'stream';\nimport { loggy } from '../utils/log';\n\nconst middleware = async (ctx: any, next: any) => {\n const cacheService = strapi.plugin('strapi-cache').services.service;\n const cacheStore = cacheService.createCache();\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 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 return;\n }\n\n await next();\n\n if (\n ctx.body &&\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 await cacheStore.set(key, {\n body: ctx.body,\n headers: ctx.response.headers,\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';\n\nconst controller = ({ strapi }: { strapi: Core.Strapi }) => ({\n index(ctx: Context) {\n ctx.body = strapi\n .plugin('strapi-cache')\n // the name of the service file & the method.\n .service('service')\n .getWelcomeMessage();\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: 'GET',\n path: '/',\n // name of the controller file & the method.\n handler: 'controller.index',\n config: {\n policies: [],\n },\n },\n];\n","import contentAPIRoutes from './content-api';\n\nconst routes = {\n 'content-api': {\n type: 'content-api',\n routes: contentAPIRoutes,\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 { CacheService } from '../../src/types/cache.types';\nimport { loggy } from '../../src/utils/log';\n\nconst service = ({ strapi }: { strapi: Core.Strapi }): CacheService => {\n let instance = null;\n\n return {\n createCache() {\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 destroy from './destroy';\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"],"mappings":"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"}
@@ -7,7 +7,9 @@ declare const _default: {
7
7
  ttl: number;
8
8
  size: number;
9
9
  allowStale: boolean;
10
- contentTypes: any[];
10
+ cacheableRoutes: any[];
11
+ provider: string;
12
+ redisUrl: any;
11
13
  };
12
14
  validator: (config: any) => void;
13
15
  };
@@ -20,7 +20,9 @@ declare const _default: {
20
20
  ttl: number;
21
21
  size: number;
22
22
  allowStale: boolean;
23
- contentTypes: any[];
23
+ cacheableRoutes: any[];
24
+ provider: string;
25
+ redisUrl: any;
24
26
  };
25
27
  validator: (config: any) => void;
26
28
  };
@@ -1,6 +1,8 @@
1
+ import type { Core } from '@strapi/strapi';
2
+ import { CacheService } from '../../src/types/cache.types';
1
3
  declare const _default: {
2
4
  service: ({ strapi }: {
3
- strapi: import("@strapi/types/dist/core").Strapi;
4
- }) => import("../types/cache.types").CacheService;
5
+ strapi: Core.Strapi;
6
+ }) => CacheService;
5
7
  };
6
8
  export default _default;
@@ -0,0 +1,16 @@
1
+ import type { Core } from '@strapi/strapi';
2
+ import { CacheProvider } from '../../types/cache.types';
3
+ export declare class InMemoryCacheProvider implements CacheProvider {
4
+ private strapi;
5
+ private initialized;
6
+ private provider;
7
+ constructor(strapi: Core.Strapi);
8
+ init(): void;
9
+ get ready(): boolean;
10
+ get(key: string): Promise<any | null>;
11
+ set(key: string, val: any): Promise<any | null>;
12
+ del(key: string): Promise<any | null>;
13
+ keys(): Promise<string[] | null>;
14
+ reset(): Promise<any | null>;
15
+ clearByRegexp(regExps: RegExp[]): Promise<void>;
16
+ }
@@ -0,0 +1,6 @@
1
+ import type { Core } from '@strapi/strapi';
2
+ import type { CacheService } from '../../types/cache.types';
3
+ declare const service: ({ strapi }: {
4
+ strapi: Core.Strapi;
5
+ }) => CacheService;
6
+ export default service;
@@ -0,0 +1,16 @@
1
+ import type { Core } from '@strapi/strapi';
2
+ import { CacheProvider } from '../../types/cache.types';
3
+ export declare class RedisCacheProvider implements CacheProvider {
4
+ private strapi;
5
+ private initialized;
6
+ private client;
7
+ constructor(strapi: Core.Strapi);
8
+ init(): void;
9
+ get ready(): boolean;
10
+ get(key: string): Promise<any | null>;
11
+ set(key: string, val: any): Promise<any | null>;
12
+ del(key: string): Promise<any | null>;
13
+ keys(): Promise<string[] | null>;
14
+ reset(): Promise<any | null>;
15
+ clearByRegexp(regExps: RegExp[]): Promise<void>;
16
+ }
@@ -0,0 +1,6 @@
1
+ import type { Core } from '@strapi/strapi';
2
+ import type { CacheService } from '../../types/cache.types';
3
+ declare const service: ({ strapi }: {
4
+ strapi: Core.Strapi;
5
+ }) => CacheService;
6
+ export default service;
@@ -0,0 +1,3 @@
1
+ import type { Core } from '@strapi/strapi';
2
+ import { CacheProvider } from '../../src/types/cache.types';
3
+ export declare const resolveCacheProvider: (strapi: Core.Strapi) => CacheProvider;
@@ -0,0 +1,3 @@
1
+ export declare function etagMatch(ctx: any, etagCached: any): boolean;
2
+ export declare function etagLookup(cacheKey: any): Promise<any>;
3
+ export declare function etagGenerate(ctx: any): string;
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.2.0",
2
+ "version": "1.3.0",
3
3
  "keywords": [
4
4
  "strapi cache",
5
5
  "strapi rest cache",
@@ -39,6 +39,7 @@
39
39
  "dependencies": {
40
40
  "@strapi/design-system": "^2.0.0-rc.21",
41
41
  "@strapi/icons": "^2.0.0-rc.21",
42
+ "ioredis": "^5.6.1",
42
43
  "lru-cache": "^11.1.0",
43
44
  "raw-body": "^3.0.0",
44
45
  "react-intl": "^7.1.10"