strapi-cache 1.6.2-rc.3 → 1.7.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
@@ -91,10 +91,12 @@ All of these routes are protected by the policies `admin::isAuthenticatedAdmin`
91
91
  - [x] **Cache Invalidation**: Automatically invalidate cache on content updates, deletions, or creations.
92
92
  - [x] **GraphQL Caching**: Cache GraphQL queries.
93
93
  - [x] **Purge Cache Button**: Add a UI option in the Strapi admin panel to manually purge the cache for content-types.
94
- - [ ] **Purge Whole Cache Button**: Add a UI option in the Strapi admin settings panel to purge the whole cache.
94
+ - [x] **Purge Whole Cache Button**: Add a UI option in the Strapi admin settings panel to purge the whole cache.
95
95
  - [x] **Route/Content-Type Specific Caching**: Allow users to define which routes should be cached based.
96
96
  - [x] **Switchable Cache Providers**: Explore support for other caching providers like Redis for distributed caching.
97
97
 
98
+ If you have any feature requests or suggestions, please open a dedicated issue.
99
+
98
100
  ## 🛑 Problems
99
101
 
100
102
  If you encounter any issues, please feel free to open an issue on the [GitHub repo](https://github.com/TupiC/strapi-cache/issues/new).
@@ -5,6 +5,7 @@ const de = {
5
5
  "strapi-cache.cache.cancel": "Nein, abbrechen",
6
6
  "strapi-cache.cache.confirm": "Ja, leeren",
7
7
  "strapi-cache.cache.purge.confirmation": "Dies löscht alle Schlüssel, bei denen {key} Teil des Schlüssels ist. Sind Sie sicher, dass Sie den Cache leeren möchten?",
8
+ "strapi-cache.cache.purge.confirmation-all": "Dies löscht alle Schlüssel aus dem Cache. Sind Sie sicher, dass Sie den gesamten Cache leeren möchten?",
8
9
  "strapi-cache.cache.purge.success": "Cache erfolgreich für {key} geleert",
9
10
  "strapi-cache.cache.purge.error": "Fehler beim Leeren des Caches für {key}",
10
11
  "strapi-cache.cache.purge.no-content-type": "Kein Inhaltstyp gefunden",
@@ -15,4 +16,3 @@ const de = {
15
16
  export {
16
17
  de as default
17
18
  };
18
- //# sourceMappingURL=de-Dihl3Ias.mjs.map
@@ -7,6 +7,7 @@ const de = {
7
7
  "strapi-cache.cache.cancel": "Nein, abbrechen",
8
8
  "strapi-cache.cache.confirm": "Ja, leeren",
9
9
  "strapi-cache.cache.purge.confirmation": "Dies löscht alle Schlüssel, bei denen {key} Teil des Schlüssels ist. Sind Sie sicher, dass Sie den Cache leeren möchten?",
10
+ "strapi-cache.cache.purge.confirmation-all": "Dies löscht alle Schlüssel aus dem Cache. Sind Sie sicher, dass Sie den gesamten Cache leeren möchten?",
10
11
  "strapi-cache.cache.purge.success": "Cache erfolgreich für {key} geleert",
11
12
  "strapi-cache.cache.purge.error": "Fehler beim Leeren des Caches für {key}",
12
13
  "strapi-cache.cache.purge.no-content-type": "Kein Inhaltstyp gefunden",
@@ -15,4 +16,3 @@ const de = {
15
16
  "strapi-cache.settings.key-placeholder": "Cache-Schlüssel zum Leeren eingeben"
16
17
  };
17
18
  exports.default = de;
18
- //# sourceMappingURL=de-BABI25Ju.js.map
@@ -7,6 +7,7 @@ const en = {
7
7
  "strapi-cache.cache.cancel": "No, cancel",
8
8
  "strapi-cache.cache.confirm": "Yes, purge",
9
9
  "strapi-cache.cache.purge.confirmation": "This purges all keys where {key} is part of the key. Are you sure you want to purge the cache?",
10
+ "strapi-cache.cache.purge.confirmation-all": "This purges all items in the cache. Are you sure you want to purge the cache?",
10
11
  "strapi-cache.cache.purge.success": "Cache purged successfully for {key}",
11
12
  "strapi-cache.cache.purge.error": "Error purging cache for {key}",
12
13
  "strapi-cache.cache.purge.no-content-type": "No content type found",
@@ -15,4 +16,3 @@ const en = {
15
16
  "strapi-cache.settings.key-placeholder": "Enter cache key to purge"
16
17
  };
17
18
  exports.default = en;
18
- //# sourceMappingURL=en-DYulQU0k.js.map
@@ -5,6 +5,7 @@ const en = {
5
5
  "strapi-cache.cache.cancel": "No, cancel",
6
6
  "strapi-cache.cache.confirm": "Yes, purge",
7
7
  "strapi-cache.cache.purge.confirmation": "This purges all keys where {key} is part of the key. Are you sure you want to purge the cache?",
8
+ "strapi-cache.cache.purge.confirmation-all": "This purges all items in the cache. Are you sure you want to purge the cache?",
8
9
  "strapi-cache.cache.purge.success": "Cache purged successfully for {key}",
9
10
  "strapi-cache.cache.purge.error": "Error purging cache for {key}",
10
11
  "strapi-cache.cache.purge.no-content-type": "No content type found",
@@ -15,4 +16,3 @@ const en = {
15
16
  export {
16
17
  en as default
17
18
  };
18
- //# sourceMappingURL=en-CLhkAQFN.mjs.map
@@ -1,7 +1,7 @@
1
1
  import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import { Typography, TextInput } from "@strapi/design-system";
3
3
  import { useIntl } from "react-intl";
4
- import { P as PurgeModal } from "./index-dynpWXaG.mjs";
4
+ import { P as PurgeModal } from "./index-BwjcxGep.mjs";
5
5
  import { useState } from "react";
6
6
  const SettingsPage = () => {
7
7
  const { formatMessage } = useIntl();
@@ -11,7 +11,7 @@ const SettingsPage = () => {
11
11
  id: "strapi-cache.name",
12
12
  defaultMessage: "Strapi Cache Settings"
13
13
  }) }),
14
- /* @__PURE__ */ jsx("div", { style: { marginTop: "16px", marginBottom: "24px" }, children: /* @__PURE__ */ jsx(Typography, { variant: "omega", children: formatMessage({
14
+ /* @__PURE__ */ jsx("div", { style: { marginTop: "16px", marginBottom: "16px" }, children: /* @__PURE__ */ jsx(Typography, { variant: "omega", children: formatMessage({
15
15
  id: "strapi-cache.settings.description",
16
16
  defaultMessage: 'Enter a cache key below and click "Purge Cache" to clear specific cached content.'
17
17
  }) }) }),
@@ -23,7 +23,8 @@ const SettingsPage = () => {
23
23
  justifyContent: "center",
24
24
  alignItems: "center",
25
25
  gap: "12px",
26
- maxWidth: "400px"
26
+ maxWidth: "400px",
27
+ marginBottom: "16px"
27
28
  },
28
29
  children: [
29
30
  /* @__PURE__ */ jsx("div", { style: { flex: 1 }, children: /* @__PURE__ */ jsx(
@@ -42,10 +43,10 @@ const SettingsPage = () => {
42
43
  /* @__PURE__ */ jsx(PurgeModal, { buttonText: "Purge Cache", keyToUse, isSettingsPage: true })
43
44
  ]
44
45
  }
45
- )
46
+ ),
47
+ /* @__PURE__ */ jsx(PurgeModal, { buttonText: "Purge All", isPurgeAll: true, isSettingsPage: true })
46
48
  ] });
47
49
  };
48
50
  export {
49
51
  SettingsPage as default
50
52
  };
51
- //# sourceMappingURL=index-BS9N2eCV.mjs.map
@@ -3,7 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const jsxRuntime = require("react/jsx-runtime");
4
4
  const designSystem = require("@strapi/design-system");
5
5
  const reactIntl = require("react-intl");
6
- const index = require("./index-BJj5EZfj.js");
6
+ const index = require("./index-Dwrl1jfJ.js");
7
7
  const react = require("react");
8
8
  const SettingsPage = () => {
9
9
  const { formatMessage } = reactIntl.useIntl();
@@ -13,7 +13,7 @@ const SettingsPage = () => {
13
13
  id: "strapi-cache.name",
14
14
  defaultMessage: "Strapi Cache Settings"
15
15
  }) }),
16
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: "16px", marginBottom: "24px" }, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: formatMessage({
16
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: "16px", marginBottom: "16px" }, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: formatMessage({
17
17
  id: "strapi-cache.settings.description",
18
18
  defaultMessage: 'Enter a cache key below and click "Purge Cache" to clear specific cached content.'
19
19
  }) }) }),
@@ -25,7 +25,8 @@ const SettingsPage = () => {
25
25
  justifyContent: "center",
26
26
  alignItems: "center",
27
27
  gap: "12px",
28
- maxWidth: "400px"
28
+ maxWidth: "400px",
29
+ marginBottom: "16px"
29
30
  },
30
31
  children: [
31
32
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1 }, children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -44,8 +45,8 @@ const SettingsPage = () => {
44
45
  /* @__PURE__ */ jsxRuntime.jsx(index.PurgeModal, { buttonText: "Purge Cache", keyToUse, isSettingsPage: true })
45
46
  ]
46
47
  }
47
- )
48
+ ),
49
+ /* @__PURE__ */ jsxRuntime.jsx(index.PurgeModal, { buttonText: "Purge All", isPurgeAll: true, isSettingsPage: true })
48
50
  ] });
49
51
  };
50
52
  exports.default = SettingsPage;
51
- //# sourceMappingURL=index-7Lm6jbM0.js.map
@@ -122,9 +122,33 @@ const useCacheOperations = () => {
122
122
  };
123
123
  }
124
124
  };
125
+ const clearAllCache = async () => {
126
+ try {
127
+ await post(
128
+ `/strapi-cache/purge-cache`,
129
+ {},
130
+ {
131
+ headers: {
132
+ "Content-Type": "application/json"
133
+ }
134
+ }
135
+ );
136
+ return {
137
+ success: true,
138
+ message: "All cache purged successfully"
139
+ };
140
+ } catch (error) {
141
+ return {
142
+ success: false,
143
+ message: "Error purging all cache",
144
+ error
145
+ };
146
+ }
147
+ };
125
148
  return {
126
149
  isCacheableRoute,
127
- clearCache
150
+ clearCache,
151
+ clearAllCache
128
152
  };
129
153
  };
130
154
  const useCacheNotifications = (config) => {
@@ -197,11 +221,12 @@ function PurgeModal({
197
221
  keyToUse,
198
222
  buttonWidth,
199
223
  contentTypeName,
200
- isSettingsPage
224
+ isSettingsPage,
225
+ isPurgeAll
201
226
  }) {
202
227
  const { canPurgeCache } = useCachePermissions();
203
228
  const { config, error: configError } = useCacheConfig(canPurgeCache);
204
- const { isCacheableRoute, clearCache } = useCacheOperations();
229
+ const { isCacheableRoute, clearCache, clearAllCache } = useCacheOperations();
205
230
  const { showConfigFetchError, showPurgeSuccess, showPurgeError, showNoContentTypeWarning } = useCacheNotifications(config);
206
231
  const formatMessage = useIntl().formatMessage;
207
232
  useEffect(() => {
@@ -210,6 +235,15 @@ function PurgeModal({
210
235
  }
211
236
  }, [configError, showConfigFetchError]);
212
237
  const handleClearCache = async () => {
238
+ if (isPurgeAll) {
239
+ const result2 = await clearAllCache();
240
+ if (result2.success) {
241
+ showPurgeSuccess("all keys");
242
+ } else {
243
+ showPurgeError("all keys");
244
+ }
245
+ return;
246
+ }
213
247
  if (!keyToUse) {
214
248
  showNoContentTypeWarning();
215
249
  return;
@@ -221,14 +255,26 @@ function PurgeModal({
221
255
  showPurgeError(keyToUse);
222
256
  }
223
257
  };
224
- if (!canPurgeCache || !isSettingsPage && !isCacheableRoute(keyToUse, contentTypeName, config)) {
258
+ if (!canPurgeCache || !isPurgeAll && !isSettingsPage && !isCacheableRoute(keyToUse, contentTypeName, config)) {
225
259
  return null;
226
260
  }
227
261
  return /* @__PURE__ */ jsxs(Modal.Root, { children: [
228
- /* @__PURE__ */ jsx(Modal.Trigger, { children: /* @__PURE__ */ jsx(Button, { width: buttonWidth, disabled: !keyToUse, startIcon: /* @__PURE__ */ jsx(Archive, {}), variant: "danger", children: buttonText }) }),
262
+ /* @__PURE__ */ jsx(Modal.Trigger, { children: /* @__PURE__ */ jsx(
263
+ Button,
264
+ {
265
+ width: buttonWidth,
266
+ disabled: !isPurgeAll && !keyToUse,
267
+ startIcon: /* @__PURE__ */ jsx(Archive, {}),
268
+ variant: "danger",
269
+ children: buttonText
270
+ }
271
+ ) }),
229
272
  /* @__PURE__ */ jsxs(Modal.Content, { children: [
230
273
  /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: buttonText }) }),
231
- /* @__PURE__ */ jsx(Modal.Body, { children: /* @__PURE__ */ jsx(Typography, { variant: "omega", children: formatMessage(
274
+ /* @__PURE__ */ jsx(Modal.Body, { children: /* @__PURE__ */ jsx(Typography, { variant: "omega", children: isPurgeAll ? formatMessage({
275
+ id: "strapi-cache.cache.purge.confirmation-all",
276
+ defaultMessage: "This purges all items in the cache. Are you sure you want to purge the cache?"
277
+ }) : formatMessage(
232
278
  {
233
279
  id: "strapi-cache.cache.purge.confirmation",
234
280
  defaultMessage: "Are you sure you want to purge the cache?"
@@ -317,7 +363,7 @@ const index = {
317
363
  },
318
364
  id: "settings",
319
365
  to: `${PLUGIN_ID}/settings`,
320
- Component: () => import("./index-BS9N2eCV.mjs"),
366
+ Component: () => import("./index-BInrGFOe.mjs"),
321
367
  permissions: []
322
368
  }
323
369
  ]
@@ -327,7 +373,7 @@ const index = {
327
373
  return Promise.all(
328
374
  locales.map(async (locale) => {
329
375
  try {
330
- const { default: data } = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/de.json": () => import("./de-Dihl3Ias.mjs"), "./translations/en.json": () => import("./en-CLhkAQFN.mjs") }), `./translations/${locale}.json`, 3);
376
+ const { default: data } = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/de.json": () => import("./de-C_gFyhHL.mjs"), "./translations/en.json": () => import("./en-bK2OKwtN.mjs") }), `./translations/${locale}.json`, 3);
331
377
  return { data, locale };
332
378
  } catch {
333
379
  return { data: {}, locale };
@@ -340,4 +386,3 @@ export {
340
386
  PurgeModal as P,
341
387
  index as i
342
388
  };
343
- //# sourceMappingURL=index-dynpWXaG.mjs.map
@@ -123,9 +123,33 @@ const useCacheOperations = () => {
123
123
  };
124
124
  }
125
125
  };
126
+ const clearAllCache = async () => {
127
+ try {
128
+ await post(
129
+ `/strapi-cache/purge-cache`,
130
+ {},
131
+ {
132
+ headers: {
133
+ "Content-Type": "application/json"
134
+ }
135
+ }
136
+ );
137
+ return {
138
+ success: true,
139
+ message: "All cache purged successfully"
140
+ };
141
+ } catch (error) {
142
+ return {
143
+ success: false,
144
+ message: "Error purging all cache",
145
+ error
146
+ };
147
+ }
148
+ };
126
149
  return {
127
150
  isCacheableRoute,
128
- clearCache
151
+ clearCache,
152
+ clearAllCache
129
153
  };
130
154
  };
131
155
  const useCacheNotifications = (config) => {
@@ -198,11 +222,12 @@ function PurgeModal({
198
222
  keyToUse,
199
223
  buttonWidth,
200
224
  contentTypeName,
201
- isSettingsPage
225
+ isSettingsPage,
226
+ isPurgeAll
202
227
  }) {
203
228
  const { canPurgeCache } = useCachePermissions();
204
229
  const { config, error: configError } = useCacheConfig(canPurgeCache);
205
- const { isCacheableRoute, clearCache } = useCacheOperations();
230
+ const { isCacheableRoute, clearCache, clearAllCache } = useCacheOperations();
206
231
  const { showConfigFetchError, showPurgeSuccess, showPurgeError, showNoContentTypeWarning } = useCacheNotifications(config);
207
232
  const formatMessage = reactIntl.useIntl().formatMessage;
208
233
  react.useEffect(() => {
@@ -211,6 +236,15 @@ function PurgeModal({
211
236
  }
212
237
  }, [configError, showConfigFetchError]);
213
238
  const handleClearCache = async () => {
239
+ if (isPurgeAll) {
240
+ const result2 = await clearAllCache();
241
+ if (result2.success) {
242
+ showPurgeSuccess("all keys");
243
+ } else {
244
+ showPurgeError("all keys");
245
+ }
246
+ return;
247
+ }
214
248
  if (!keyToUse) {
215
249
  showNoContentTypeWarning();
216
250
  return;
@@ -222,14 +256,26 @@ function PurgeModal({
222
256
  showPurgeError(keyToUse);
223
257
  }
224
258
  };
225
- if (!canPurgeCache || !isSettingsPage && !isCacheableRoute(keyToUse, contentTypeName, config)) {
259
+ if (!canPurgeCache || !isPurgeAll && !isSettingsPage && !isCacheableRoute(keyToUse, contentTypeName, config)) {
226
260
  return null;
227
261
  }
228
262
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Root, { children: [
229
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { width: buttonWidth, disabled: !keyToUse, startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Archive, {}), variant: "danger", children: buttonText }) }),
263
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(
264
+ designSystem.Button,
265
+ {
266
+ width: buttonWidth,
267
+ disabled: !isPurgeAll && !keyToUse,
268
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Archive, {}),
269
+ variant: "danger",
270
+ children: buttonText
271
+ }
272
+ ) }),
230
273
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Content, { children: [
231
274
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Title, { children: buttonText }) }),
232
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: formatMessage(
275
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: isPurgeAll ? formatMessage({
276
+ id: "strapi-cache.cache.purge.confirmation-all",
277
+ defaultMessage: "This purges all items in the cache. Are you sure you want to purge the cache?"
278
+ }) : formatMessage(
233
279
  {
234
280
  id: "strapi-cache.cache.purge.confirmation",
235
281
  defaultMessage: "Are you sure you want to purge the cache?"
@@ -318,7 +364,7 @@ const index = {
318
364
  },
319
365
  id: "settings",
320
366
  to: `${PLUGIN_ID}/settings`,
321
- Component: () => Promise.resolve().then(() => require("./index-7Lm6jbM0.js")),
367
+ Component: () => Promise.resolve().then(() => require("./index-BjBoZhpS.js")),
322
368
  permissions: []
323
369
  }
324
370
  ]
@@ -328,7 +374,7 @@ const index = {
328
374
  return Promise.all(
329
375
  locales.map(async (locale) => {
330
376
  try {
331
- const { default: data } = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/de.json": () => Promise.resolve().then(() => require("./de-BABI25Ju.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-DYulQU0k.js")) }), `./translations/${locale}.json`, 3);
377
+ const { default: data } = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/de.json": () => Promise.resolve().then(() => require("./de-l6MDDAXu.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-D9w03LyX.js")) }), `./translations/${locale}.json`, 3);
332
378
  return { data, locale };
333
379
  } catch {
334
380
  return { data: {}, locale };
@@ -339,4 +385,3 @@ const index = {
339
385
  };
340
386
  exports.PurgeModal = PurgeModal;
341
387
  exports.index = index;
342
- //# sourceMappingURL=index-BJj5EZfj.js.map
@@ -1,4 +1,3 @@
1
1
  "use strict";
2
- const index = require("../_chunks/index-BJj5EZfj.js");
2
+ const index = require("../_chunks/index-Dwrl1jfJ.js");
3
3
  module.exports = index.index;
4
- //# sourceMappingURL=index.js.map
@@ -1,5 +1,4 @@
1
- import { i } from "../_chunks/index-dynpWXaG.mjs";
1
+ import { i } from "../_chunks/index-BwjcxGep.mjs";
2
2
  export {
3
3
  i as default
4
4
  };
5
- //# sourceMappingURL=index.mjs.map
@@ -4,6 +4,7 @@ export type PurgeProps = {
4
4
  keyToUse?: string;
5
5
  contentTypeName?: string;
6
6
  isSettingsPage?: boolean;
7
+ isPurgeAll?: boolean;
7
8
  };
8
- declare function PurgeModal({ buttonText, keyToUse, buttonWidth, contentTypeName, isSettingsPage, }: PurgeProps): import("react/jsx-runtime").JSX.Element | null;
9
+ declare function PurgeModal({ buttonText, keyToUse, buttonWidth, contentTypeName, isSettingsPage, isPurgeAll, }: PurgeProps): import("react/jsx-runtime").JSX.Element | null;
9
10
  export default PurgeModal;
@@ -7,4 +7,5 @@ export type CacheOperationResult = {
7
7
  export declare const useCacheOperations: () => {
8
8
  isCacheableRoute: (keyToUse?: string, contentTypeName?: string, config?: CacheConfig) => boolean;
9
9
  clearCache: (keyToUse?: string) => Promise<CacheOperationResult>;
10
+ clearAllCache: () => Promise<CacheOperationResult>;
10
11
  };
@@ -51,7 +51,7 @@ async function invalidateCache(event, cacheStore, strapi2) {
51
51
  loggy.error(error);
52
52
  }
53
53
  }
54
- async function invalidateGraphqlCache(event, cacheStore, strapi2) {
54
+ async function invalidateGraphqlCache(cacheStore) {
55
55
  try {
56
56
  const graphqlRegex = new RegExp(`^POST:/graphql(:.*)?$`);
57
57
  await cacheStore.clearByRegexp([graphqlRegex]);
@@ -85,15 +85,15 @@ const bootstrap = ({ strapi: strapi2 }) => {
85
85
  strapi2.db.lifecycles.subscribe({
86
86
  async afterCreate(event) {
87
87
  await invalidateCache(event, cacheStore, strapi2);
88
- await invalidateGraphqlCache(event, cacheStore, strapi2);
88
+ await invalidateGraphqlCache(cacheStore);
89
89
  },
90
90
  async afterUpdate(event) {
91
91
  await invalidateCache(event, cacheStore, strapi2);
92
- await invalidateGraphqlCache(event, cacheStore, strapi2);
92
+ await invalidateGraphqlCache(cacheStore);
93
93
  },
94
94
  async afterDelete(event) {
95
95
  await invalidateCache(event, cacheStore, strapi2);
96
- await invalidateGraphqlCache(event, cacheStore, strapi2);
96
+ await invalidateGraphqlCache(cacheStore);
97
97
  }
98
98
  });
99
99
  }
@@ -120,6 +120,7 @@ const generateGraphqlCacheKey = (payload) => {
120
120
  const hash = crypto.createHash("sha256").update(payload).digest("base64url");
121
121
  return `POST:/graphql:${hash}`;
122
122
  };
123
+ const escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
123
124
  const streamToBuffer = (stream) => {
124
125
  return new Promise((resolve, reject) => {
125
126
  const chunks = [];
@@ -498,7 +499,6 @@ const controller = ({ strapi: strapi2 }) => ({
498
499
  return;
499
500
  }
500
501
  const service2 = strapi2.plugin("strapi-cache").service("service");
501
- const escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
502
502
  const regex = new RegExp(escapeRegExp(key));
503
503
  await service2.getCacheInstance().clearByRegexp([regex]);
504
504
  ctx.body = {
@@ -682,7 +682,10 @@ class InMemoryCacheProvider {
682
682
  }
683
683
  }
684
684
  async clearByRegexp(regExps) {
685
- const keys = await this.keys() || [];
685
+ const keys = await this.keys();
686
+ if (!keys) {
687
+ return;
688
+ }
686
689
  const matches = keys.filter((key) => regExps.some((re) => re.test(key)));
687
690
  await Promise.all(matches.map((key) => this.del(key)));
688
691
  }
@@ -793,10 +796,10 @@ class RedisCacheProvider {
793
796
  }
794
797
  async clearByRegexp(regExps) {
795
798
  const keys = await this.keys();
796
- loggy.info(JSON.stringify(keys));
797
- if (!keys) return;
799
+ if (!keys) {
800
+ return;
801
+ }
798
802
  const toDelete = keys.filter((key) => regExps.some((re) => re.test(key)));
799
- loggy.info(JSON.stringify(toDelete));
800
803
  await Promise.all(toDelete.map((key) => this.del(key)));
801
804
  }
802
805
  }
@@ -843,4 +846,3 @@ const index = {
843
846
  middlewares
844
847
  };
845
848
  module.exports = index;
846
- //# sourceMappingURL=index.js.map
@@ -47,7 +47,7 @@ async function invalidateCache(event, cacheStore, strapi2) {
47
47
  loggy.error(error);
48
48
  }
49
49
  }
50
- async function invalidateGraphqlCache(event, cacheStore, strapi2) {
50
+ async function invalidateGraphqlCache(cacheStore) {
51
51
  try {
52
52
  const graphqlRegex = new RegExp(`^POST:/graphql(:.*)?$`);
53
53
  await cacheStore.clearByRegexp([graphqlRegex]);
@@ -81,15 +81,15 @@ const bootstrap = ({ strapi: strapi2 }) => {
81
81
  strapi2.db.lifecycles.subscribe({
82
82
  async afterCreate(event) {
83
83
  await invalidateCache(event, cacheStore, strapi2);
84
- await invalidateGraphqlCache(event, cacheStore, strapi2);
84
+ await invalidateGraphqlCache(cacheStore);
85
85
  },
86
86
  async afterUpdate(event) {
87
87
  await invalidateCache(event, cacheStore, strapi2);
88
- await invalidateGraphqlCache(event, cacheStore, strapi2);
88
+ await invalidateGraphqlCache(cacheStore);
89
89
  },
90
90
  async afterDelete(event) {
91
91
  await invalidateCache(event, cacheStore, strapi2);
92
- await invalidateGraphqlCache(event, cacheStore, strapi2);
92
+ await invalidateGraphqlCache(cacheStore);
93
93
  }
94
94
  });
95
95
  }
@@ -116,6 +116,7 @@ const generateGraphqlCacheKey = (payload) => {
116
116
  const hash = createHash("sha256").update(payload).digest("base64url");
117
117
  return `POST:/graphql:${hash}`;
118
118
  };
119
+ const escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
119
120
  const streamToBuffer = (stream) => {
120
121
  return new Promise((resolve, reject) => {
121
122
  const chunks = [];
@@ -494,7 +495,6 @@ const controller = ({ strapi: strapi2 }) => ({
494
495
  return;
495
496
  }
496
497
  const service2 = strapi2.plugin("strapi-cache").service("service");
497
- const escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
498
498
  const regex = new RegExp(escapeRegExp(key));
499
499
  await service2.getCacheInstance().clearByRegexp([regex]);
500
500
  ctx.body = {
@@ -678,7 +678,10 @@ class InMemoryCacheProvider {
678
678
  }
679
679
  }
680
680
  async clearByRegexp(regExps) {
681
- const keys = await this.keys() || [];
681
+ const keys = await this.keys();
682
+ if (!keys) {
683
+ return;
684
+ }
682
685
  const matches = keys.filter((key) => regExps.some((re) => re.test(key)));
683
686
  await Promise.all(matches.map((key) => this.del(key)));
684
687
  }
@@ -789,10 +792,10 @@ class RedisCacheProvider {
789
792
  }
790
793
  async clearByRegexp(regExps) {
791
794
  const keys = await this.keys();
792
- loggy.info(JSON.stringify(keys));
793
- if (!keys) return;
795
+ if (!keys) {
796
+ return;
797
+ }
794
798
  const toDelete = keys.filter((key) => regExps.some((re) => re.test(key)));
795
- loggy.info(JSON.stringify(toDelete));
796
799
  await Promise.all(toDelete.map((key) => this.del(key)));
797
800
  }
798
801
  }
@@ -841,4 +844,3 @@ const index = {
841
844
  export {
842
845
  index as default
843
846
  };
844
- //# sourceMappingURL=index.mjs.map
@@ -1,4 +1,4 @@
1
1
  import { Core } from '@strapi/strapi';
2
2
  import { CacheProvider } from 'src/types/cache.types';
3
3
  export declare function invalidateCache(event: any, cacheStore: CacheProvider, strapi: Core.Strapi): Promise<void>;
4
- export declare function invalidateGraphqlCache(event: any, cacheStore: CacheProvider, strapi: Core.Strapi): Promise<void>;
4
+ export declare function invalidateGraphqlCache(cacheStore: CacheProvider): Promise<void>;
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.6.2-rc.3",
2
+ "version": "1.7.0",
3
3
  "keywords": [
4
4
  "strapi cache",
5
5
  "strapi rest cache",
@@ -1 +0,0 @@
1
- {"version":3,"file":"de-BABI25Ju.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"de-Dihl3Ias.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"en-CLhkAQFN.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"en-DYulQU0k.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-7Lm6jbM0.js","sources":["../../admin/src/components/SettingsPage/index.tsx"],"sourcesContent":["import { TextInput, Typography } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\nimport PurgeModal from '../PurgeModal';\nimport { useState } from 'react';\n\nconst SettingsPage = () => {\n const { formatMessage } = useIntl();\n const [keyToUse, setKeyToUse] = useState<string>('');\n\n return (\n <div style={{ padding: '20px' }}>\n <Typography variant=\"alpha\" as=\"h1\">\n {formatMessage({\n id: 'strapi-cache.name',\n defaultMessage: 'Strapi Cache Settings',\n })}\n </Typography>\n\n <div style={{ marginTop: '16px', marginBottom: '24px' }}>\n <Typography variant=\"omega\">\n {formatMessage({\n id: 'strapi-cache.settings.description',\n defaultMessage:\n 'Enter a cache key below and click \"Purge Cache\" to clear specific cached content.',\n })}\n </Typography>\n </div>\n\n <div\n style={{\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n gap: '12px',\n maxWidth: '400px',\n }}\n >\n <div style={{ flex: 1 }}>\n <TextInput\n placeholder={formatMessage({\n id: 'strapi-cache.settings.key-placeholder',\n defaultMessage: 'Enter cache key to purge',\n })}\n size=\"M\"\n type=\"text\"\n value={keyToUse}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setKeyToUse(e.target.value)}\n />\n </div>\n <PurgeModal buttonText=\"Purge Cache\" keyToUse={keyToUse} isSettingsPage />\n </div>\n </div>\n );\n};\n\nexport default SettingsPage;\n"],"names":["useIntl","useState","jsx","Typography","jsxs","TextInput","PurgeModal"],"mappings":";;;;;;;AAKA,MAAM,eAAe,MAAM;AACnB,QAAA,EAAE,cAAc,IAAIA,kBAAQ;AAClC,QAAM,CAAC,UAAU,WAAW,IAAIC,MAAAA,SAAiB,EAAE;AAEnD,yCACG,OAAI,EAAA,OAAO,EAAE,SAAS,OACrB,GAAA,UAAA;AAAA,IAAAC,+BAACC,aAAAA,YAAW,EAAA,SAAQ,SAAQ,IAAG,MAC5B,UAAc,cAAA;AAAA,MACb,IAAI;AAAA,MACJ,gBAAgB;AAAA,IACjB,CAAA,GACH;AAAA,IAECD,2BAAA,IAAA,OAAA,EAAI,OAAO,EAAE,WAAW,QAAQ,cAAc,OAC7C,GAAA,UAAAA,2BAAA,IAACC,yBAAW,EAAA,SAAQ,SACjB,UAAc,cAAA;AAAA,MACb,IAAI;AAAA,MACJ,gBACE;AAAA,IAAA,CACH,GACH,EACF,CAAA;AAAA,IAEAC,2BAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,OAAO;AAAA,UACL,SAAS;AAAA,UACT,gBAAgB;AAAA,UAChB,YAAY;AAAA,UACZ,KAAK;AAAA,UACL,UAAU;AAAA,QACZ;AAAA,QAEA,UAAA;AAAA,UAAAF,2BAAA,IAAC,OAAI,EAAA,OAAO,EAAE,MAAM,KAClB,UAAAA,2BAAA;AAAA,YAACG,aAAA;AAAA,YAAA;AAAA,cACC,aAAa,cAAc;AAAA,gBACzB,IAAI;AAAA,gBACJ,gBAAgB;AAAA,cAAA,CACjB;AAAA,cACD,MAAK;AAAA,cACL,MAAK;AAAA,cACL,OAAO;AAAA,cACP,UAAU,CAAC,MAA2C,YAAY,EAAE,OAAO,KAAK;AAAA,YAAA;AAAA,UAAA,GAEpF;AAAA,yCACCC,MAAW,YAAA,EAAA,YAAW,eAAc,UAAoB,gBAAc,KAAC,CAAA;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAC1E,GACF;AAEJ;;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-BJj5EZfj.js","sources":["../../admin/src/pluginId.ts","../../admin/src/components/Initializer.tsx","../../admin/src/hooks/useCacheConfig.ts","../../admin/src/permission.ts","../../admin/src/hooks/useCachePermissions.ts","../../admin/src/hooks/useCacheOperations.ts","../../admin/src/hooks/useCacheNotifications.ts","../../admin/src/components/PurgeModal/index.tsx","../../admin/src/components/PurgeCacheButton/index.tsx","../../admin/src/components/PurgeEntityButton/index.tsx","../../admin/src/index.ts"],"sourcesContent":["export const PLUGIN_ID = 'strapi-cache';\n","import { useEffect, useRef } from 'react';\n\nimport { PLUGIN_ID } from '../pluginId';\n\ntype InitializerProps = {\n setPlugin: (id: string) => void;\n};\n\nconst Initializer = ({ setPlugin }: InitializerProps) => {\n const ref = useRef(setPlugin);\n\n useEffect(() => {\n ref.current(PLUGIN_ID);\n }, []);\n\n return null;\n};\n\nexport { Initializer };\n","import { useState, useEffect } from 'react';\nimport { useFetchClient } from '@strapi/strapi/admin';\n\nexport type CacheConfig = {\n cacheableRoutes: string[];\n disableAdminPopups: boolean;\n};\n\nexport const useCacheConfig = (enabled: boolean = true) => {\n const [config, setConfig] = useState<CacheConfig>();\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const { get } = useFetchClient();\n\n useEffect(() => {\n if (!enabled) {\n return;\n }\n\n const fetchConfig = async () => {\n setIsLoading(true);\n setError(null);\n\n try {\n const { data } = await get('/strapi-cache/config');\n setConfig(data);\n } catch (error: any) {\n setError(error);\n } finally {\n setIsLoading(false);\n }\n };\n\n fetchConfig();\n }, [enabled, get]);\n\n return {\n config,\n isLoading,\n error,\n refetch: () => {\n const fetchConfig = async () => {\n setIsLoading(true);\n setError(null);\n\n try {\n const { data } = await get('/strapi-cache/config');\n setConfig(data);\n } catch (error: any) {\n setError(error);\n } finally {\n setIsLoading(false);\n }\n };\n fetchConfig();\n },\n };\n};\n","export const pluginPermissions = {\n purge: [{ action: 'plugin::strapi-cache.purge-cache', subject: null }],\n};\n","import { useRBAC } from '@strapi/strapi/admin';\nimport { pluginPermissions } from '../permission';\n\nexport const useCachePermissions = () => {\n const { allowedActions } = useRBAC(pluginPermissions);\n\n return {\n canPurgeCache: allowedActions.canPurgeCache,\n allowedActions,\n };\n};\n","import { useFetchClient } from '@strapi/strapi/admin';\nimport { CacheConfig } from './useCacheConfig';\n\nexport type CacheOperationResult = {\n success: boolean;\n message?: string;\n error?: Error;\n};\n\nexport const useCacheOperations = () => {\n const { post } = useFetchClient();\n\n const isCacheableRoute = (\n keyToUse?: string,\n contentTypeName?: string,\n config?: CacheConfig\n ): boolean => {\n if (!keyToUse || !config) {\n return false;\n }\n\n const { cacheableRoutes } = config;\n return (\n cacheableRoutes.length === 0 ||\n cacheableRoutes.some((route) => {\n return route.includes(keyToUse) || (contentTypeName && route.includes(contentTypeName));\n })\n );\n };\n\n const clearCache = async (keyToUse?: string): Promise<CacheOperationResult> => {\n if (!keyToUse) {\n return {\n success: false,\n message: 'No content type found',\n };\n }\n\n try {\n await post(\n `/strapi-cache/purge-cache/key`,\n { key: keyToUse },\n {\n headers: {\n 'Content-Type': 'application/json',\n },\n }\n );\n\n return {\n success: true,\n message: `Cache purged successfully for key: \"${keyToUse}\"`,\n };\n } catch (error: any) {\n return {\n success: false,\n message: `Error purging cache for key: \"${keyToUse}\"`,\n error,\n };\n }\n };\n\n return {\n isCacheableRoute,\n clearCache,\n };\n};\n","import { useIntl } from 'react-intl';\nimport { useNotification } from '@strapi/strapi/admin';\nimport { CacheConfig } from './useCacheConfig';\n\nexport const useCacheNotifications = (config?: CacheConfig) => {\n const formatMessage = useIntl().formatMessage;\n const { toggleNotification } = useNotification();\n\n const showConfigFetchError = (error: Error) => {\n // only show error notification if its not a permissions error and popups are not disabled\n const isPermissionError =\n (error as any)?.response?.status === 403 || (error as any)?.response?.status === 401;\n\n if (!isPermissionError && !config?.disableAdminPopups) {\n toggleNotification({\n type: 'warning',\n message: formatMessage({\n id: 'strapi-cache.cache.routes.fetch-error',\n defaultMessage: 'Unable to fetch cache config. Cache purge may not work correctly.',\n }),\n });\n }\n };\n\n const showPurgeSuccess = (key: string) => {\n if (!config?.disableAdminPopups) {\n toggleNotification({\n type: 'success',\n message: formatMessage(\n {\n id: 'strapi-cache.cache.purge.success',\n defaultMessage: 'Cache purged successfully',\n },\n {\n key: `\"${key}\"`,\n }\n ),\n });\n }\n };\n\n const showPurgeError = (key: string) => {\n if (!config?.disableAdminPopups) {\n toggleNotification({\n type: 'danger',\n message: formatMessage(\n {\n id: 'strapi-cache.cache.purge.error',\n defaultMessage: 'Error purging cache',\n },\n {\n key: `\"${key}\"`,\n }\n ),\n });\n }\n };\n\n const showNoContentTypeWarning = () => {\n if (!config?.disableAdminPopups) {\n toggleNotification({\n type: 'warning',\n message: formatMessage({\n id: 'strapi-cache.cache.purge.no-content-type',\n defaultMessage: 'No content type found',\n }),\n });\n }\n };\n\n return {\n showConfigFetchError,\n showPurgeSuccess,\n showPurgeError,\n showNoContentTypeWarning,\n };\n};\n","import { useIntl } from 'react-intl';\nimport { Archive } from '@strapi/icons';\nimport { Button, Modal } from '@strapi/design-system';\nimport { Typography } from '@strapi/design-system';\nimport { useEffect } from 'react';\nimport {\n useCacheConfig,\n useCachePermissions,\n useCacheOperations,\n useCacheNotifications,\n} from '../../hooks';\n\nexport type PurgeProps = {\n buttonText: string;\n buttonWidth?: string;\n keyToUse?: string;\n contentTypeName?: string;\n isSettingsPage?: boolean;\n};\n\nfunction PurgeModal({\n buttonText,\n keyToUse,\n buttonWidth,\n contentTypeName,\n isSettingsPage,\n}: PurgeProps) {\n const { canPurgeCache } = useCachePermissions();\n const { config, error: configError } = useCacheConfig(canPurgeCache);\n const { isCacheableRoute, clearCache } = useCacheOperations();\n const { showConfigFetchError, showPurgeSuccess, showPurgeError, showNoContentTypeWarning } =\n useCacheNotifications(config);\n const formatMessage = useIntl().formatMessage;\n\n useEffect(() => {\n if (configError) {\n showConfigFetchError(configError);\n }\n }, [configError, showConfigFetchError]);\n\n const handleClearCache = async () => {\n if (!keyToUse) {\n showNoContentTypeWarning();\n return;\n }\n\n const result = await clearCache(keyToUse);\n\n if (result.success) {\n showPurgeSuccess(keyToUse);\n } else {\n showPurgeError(keyToUse);\n }\n };\n\n if (!canPurgeCache || (!isSettingsPage && !isCacheableRoute(keyToUse, contentTypeName, config))) {\n return null;\n }\n\n return (\n <Modal.Root>\n <Modal.Trigger>\n <Button width={buttonWidth} disabled={!keyToUse} startIcon={<Archive />} variant=\"danger\">\n {buttonText}\n </Button>\n </Modal.Trigger>\n <Modal.Content>\n <Modal.Header>\n <Modal.Title>{buttonText}</Modal.Title>\n </Modal.Header>\n <Modal.Body>\n <Typography variant=\"omega\">\n {formatMessage(\n {\n id: 'strapi-cache.cache.purge.confirmation',\n defaultMessage: 'Are you sure you want to purge the cache?',\n },\n { key: `\"${keyToUse}\"` }\n )}\n </Typography>\n </Modal.Body>\n <Modal.Footer>\n <Modal.Close>\n <Button variant=\"tertiary\">\n {formatMessage({\n id: 'strapi-cache.cache.cancel',\n defaultMessage: 'No, cancel',\n })}\n </Button>\n </Modal.Close>\n <Modal.Close>\n <Button onClick={handleClearCache}>\n {formatMessage({\n id: 'strapi-cache.cache.confirm',\n defaultMessage: 'Yes, confirm',\n })}\n </Button>\n </Modal.Close>\n </Modal.Footer>\n </Modal.Content>\n </Modal.Root>\n );\n}\n\nexport default PurgeModal;\n","import { unstable_useContentManagerContext as useContentManagerContext } from '@strapi/strapi/admin';\nimport PurgeModal from '../PurgeModal';\nimport { useIntl } from 'react-intl';\n\nfunction PurgeCacheButton() {\n const { contentType } = useContentManagerContext();\n const { formatMessage } = useIntl();\n const keyToUse = contentType?.info.pluralName;\n\n return (\n <PurgeModal\n buttonText={formatMessage({\n id: 'strapi-cache.cache.purge',\n defaultMessage: 'Purge Cache',\n })}\n keyToUse={keyToUse}\n ></PurgeModal>\n );\n}\n\nexport default PurgeCacheButton;\n","import { unstable_useContentManagerContext as useContentManagerContext } from '@strapi/strapi/admin';\nimport PurgeModal from '../PurgeModal';\nimport { useIntl } from 'react-intl';\n\nfunction PurgeEntityButton() {\n const { formatMessage } = useIntl();\n const { id, isSingleType, contentType } = useContentManagerContext();\n const apiPath = isSingleType ? contentType?.info.singularName : id;\n\n if (!apiPath) {\n return null;\n }\n\n const keyToUse = encodeURIComponent(apiPath);\n const contentTypeName = isSingleType\n ? contentType?.info.singularName\n : contentType?.info.pluralName;\n\n return (\n <PurgeModal\n buttonWidth=\"100%\"\n buttonText={formatMessage({\n id: 'strapi-cache.cache.purge.entity',\n defaultMessage: 'Purge Entity Cache',\n })}\n keyToUse={keyToUse}\n contentTypeName={contentTypeName}\n ></PurgeModal>\n );\n}\n\nexport default PurgeEntityButton;\n","import { PLUGIN_ID } from './pluginId';\nimport { Initializer } from './components/Initializer';\nimport PurgeCacheButton from './components/PurgeCacheButton';\nimport PurgeEntityButton from './components/PurgeEntityButton';\n\nexport default {\n register(app: any) {\n app.registerPlugin({\n id: PLUGIN_ID,\n initializer: Initializer,\n isReady: false,\n name: PLUGIN_ID,\n });\n\n app.getPlugin('content-manager').injectComponent('listView', 'actions', {\n name: PurgeCacheButton,\n Component: PurgeCacheButton,\n });\n\n app.getPlugin('content-manager').injectComponent('editView', 'right-links', {\n name: PurgeEntityButton,\n Component: PurgeEntityButton,\n });\n\n app.createSettingSection(\n {\n id: PLUGIN_ID,\n intlLabel: {\n id: 'strapi-cache.settings.link',\n defaultMessage: 'Strapi Cache',\n },\n },\n [\n {\n intlLabel: {\n id: 'strapi-cache.settings.link',\n defaultMessage: 'Strapi Cache',\n },\n id: 'settings',\n to: `${PLUGIN_ID}/settings`,\n Component: () => import('./components/SettingsPage'),\n permissions: [],\n },\n ]\n );\n },\n\n async registerTrads({ locales }: { locales: string[] }) {\n return Promise.all(\n locales.map(async (locale) => {\n try {\n const { default: data } = await import(`./translations/${locale}.json`);\n\n return { data, locale };\n } catch {\n return { data: {}, locale };\n }\n })\n );\n },\n};\n"],"names":["useRef","useEffect","useState","useFetchClient","error","useRBAC","useIntl","useNotification","jsxs","Modal","jsx","Button","Archive","Typography","useContentManagerContext"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-BS9N2eCV.mjs","sources":["../../admin/src/components/SettingsPage/index.tsx"],"sourcesContent":["import { TextInput, Typography } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\nimport PurgeModal from '../PurgeModal';\nimport { useState } from 'react';\n\nconst SettingsPage = () => {\n const { formatMessage } = useIntl();\n const [keyToUse, setKeyToUse] = useState<string>('');\n\n return (\n <div style={{ padding: '20px' }}>\n <Typography variant=\"alpha\" as=\"h1\">\n {formatMessage({\n id: 'strapi-cache.name',\n defaultMessage: 'Strapi Cache Settings',\n })}\n </Typography>\n\n <div style={{ marginTop: '16px', marginBottom: '24px' }}>\n <Typography variant=\"omega\">\n {formatMessage({\n id: 'strapi-cache.settings.description',\n defaultMessage:\n 'Enter a cache key below and click \"Purge Cache\" to clear specific cached content.',\n })}\n </Typography>\n </div>\n\n <div\n style={{\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n gap: '12px',\n maxWidth: '400px',\n }}\n >\n <div style={{ flex: 1 }}>\n <TextInput\n placeholder={formatMessage({\n id: 'strapi-cache.settings.key-placeholder',\n defaultMessage: 'Enter cache key to purge',\n })}\n size=\"M\"\n type=\"text\"\n value={keyToUse}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setKeyToUse(e.target.value)}\n />\n </div>\n <PurgeModal buttonText=\"Purge Cache\" keyToUse={keyToUse} isSettingsPage />\n </div>\n </div>\n );\n};\n\nexport default SettingsPage;\n"],"names":[],"mappings":";;;;;AAKA,MAAM,eAAe,MAAM;AACnB,QAAA,EAAE,cAAc,IAAI,QAAQ;AAClC,QAAM,CAAC,UAAU,WAAW,IAAI,SAAiB,EAAE;AAEnD,8BACG,OAAI,EAAA,OAAO,EAAE,SAAS,OACrB,GAAA,UAAA;AAAA,IAAA,oBAAC,YAAW,EAAA,SAAQ,SAAQ,IAAG,MAC5B,UAAc,cAAA;AAAA,MACb,IAAI;AAAA,MACJ,gBAAgB;AAAA,IACjB,CAAA,GACH;AAAA,IAEC,oBAAA,OAAA,EAAI,OAAO,EAAE,WAAW,QAAQ,cAAc,OAC7C,GAAA,UAAA,oBAAC,YAAW,EAAA,SAAQ,SACjB,UAAc,cAAA;AAAA,MACb,IAAI;AAAA,MACJ,gBACE;AAAA,IAAA,CACH,GACH,EACF,CAAA;AAAA,IAEA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,OAAO;AAAA,UACL,SAAS;AAAA,UACT,gBAAgB;AAAA,UAChB,YAAY;AAAA,UACZ,KAAK;AAAA,UACL,UAAU;AAAA,QACZ;AAAA,QAEA,UAAA;AAAA,UAAA,oBAAC,OAAI,EAAA,OAAO,EAAE,MAAM,KAClB,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,aAAa,cAAc;AAAA,gBACzB,IAAI;AAAA,gBACJ,gBAAgB;AAAA,cAAA,CACjB;AAAA,cACD,MAAK;AAAA,cACL,MAAK;AAAA,cACL,OAAO;AAAA,cACP,UAAU,CAAC,MAA2C,YAAY,EAAE,OAAO,KAAK;AAAA,YAAA;AAAA,UAAA,GAEpF;AAAA,8BACC,YAAW,EAAA,YAAW,eAAc,UAAoB,gBAAc,KAAC,CAAA;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAC1E,GACF;AAEJ;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-dynpWXaG.mjs","sources":["../../admin/src/pluginId.ts","../../admin/src/components/Initializer.tsx","../../admin/src/hooks/useCacheConfig.ts","../../admin/src/permission.ts","../../admin/src/hooks/useCachePermissions.ts","../../admin/src/hooks/useCacheOperations.ts","../../admin/src/hooks/useCacheNotifications.ts","../../admin/src/components/PurgeModal/index.tsx","../../admin/src/components/PurgeCacheButton/index.tsx","../../admin/src/components/PurgeEntityButton/index.tsx","../../admin/src/index.ts"],"sourcesContent":["export const PLUGIN_ID = 'strapi-cache';\n","import { useEffect, useRef } from 'react';\n\nimport { PLUGIN_ID } from '../pluginId';\n\ntype InitializerProps = {\n setPlugin: (id: string) => void;\n};\n\nconst Initializer = ({ setPlugin }: InitializerProps) => {\n const ref = useRef(setPlugin);\n\n useEffect(() => {\n ref.current(PLUGIN_ID);\n }, []);\n\n return null;\n};\n\nexport { Initializer };\n","import { useState, useEffect } from 'react';\nimport { useFetchClient } from '@strapi/strapi/admin';\n\nexport type CacheConfig = {\n cacheableRoutes: string[];\n disableAdminPopups: boolean;\n};\n\nexport const useCacheConfig = (enabled: boolean = true) => {\n const [config, setConfig] = useState<CacheConfig>();\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const { get } = useFetchClient();\n\n useEffect(() => {\n if (!enabled) {\n return;\n }\n\n const fetchConfig = async () => {\n setIsLoading(true);\n setError(null);\n\n try {\n const { data } = await get('/strapi-cache/config');\n setConfig(data);\n } catch (error: any) {\n setError(error);\n } finally {\n setIsLoading(false);\n }\n };\n\n fetchConfig();\n }, [enabled, get]);\n\n return {\n config,\n isLoading,\n error,\n refetch: () => {\n const fetchConfig = async () => {\n setIsLoading(true);\n setError(null);\n\n try {\n const { data } = await get('/strapi-cache/config');\n setConfig(data);\n } catch (error: any) {\n setError(error);\n } finally {\n setIsLoading(false);\n }\n };\n fetchConfig();\n },\n };\n};\n","export const pluginPermissions = {\n purge: [{ action: 'plugin::strapi-cache.purge-cache', subject: null }],\n};\n","import { useRBAC } from '@strapi/strapi/admin';\nimport { pluginPermissions } from '../permission';\n\nexport const useCachePermissions = () => {\n const { allowedActions } = useRBAC(pluginPermissions);\n\n return {\n canPurgeCache: allowedActions.canPurgeCache,\n allowedActions,\n };\n};\n","import { useFetchClient } from '@strapi/strapi/admin';\nimport { CacheConfig } from './useCacheConfig';\n\nexport type CacheOperationResult = {\n success: boolean;\n message?: string;\n error?: Error;\n};\n\nexport const useCacheOperations = () => {\n const { post } = useFetchClient();\n\n const isCacheableRoute = (\n keyToUse?: string,\n contentTypeName?: string,\n config?: CacheConfig\n ): boolean => {\n if (!keyToUse || !config) {\n return false;\n }\n\n const { cacheableRoutes } = config;\n return (\n cacheableRoutes.length === 0 ||\n cacheableRoutes.some((route) => {\n return route.includes(keyToUse) || (contentTypeName && route.includes(contentTypeName));\n })\n );\n };\n\n const clearCache = async (keyToUse?: string): Promise<CacheOperationResult> => {\n if (!keyToUse) {\n return {\n success: false,\n message: 'No content type found',\n };\n }\n\n try {\n await post(\n `/strapi-cache/purge-cache/key`,\n { key: keyToUse },\n {\n headers: {\n 'Content-Type': 'application/json',\n },\n }\n );\n\n return {\n success: true,\n message: `Cache purged successfully for key: \"${keyToUse}\"`,\n };\n } catch (error: any) {\n return {\n success: false,\n message: `Error purging cache for key: \"${keyToUse}\"`,\n error,\n };\n }\n };\n\n return {\n isCacheableRoute,\n clearCache,\n };\n};\n","import { useIntl } from 'react-intl';\nimport { useNotification } from '@strapi/strapi/admin';\nimport { CacheConfig } from './useCacheConfig';\n\nexport const useCacheNotifications = (config?: CacheConfig) => {\n const formatMessage = useIntl().formatMessage;\n const { toggleNotification } = useNotification();\n\n const showConfigFetchError = (error: Error) => {\n // only show error notification if its not a permissions error and popups are not disabled\n const isPermissionError =\n (error as any)?.response?.status === 403 || (error as any)?.response?.status === 401;\n\n if (!isPermissionError && !config?.disableAdminPopups) {\n toggleNotification({\n type: 'warning',\n message: formatMessage({\n id: 'strapi-cache.cache.routes.fetch-error',\n defaultMessage: 'Unable to fetch cache config. Cache purge may not work correctly.',\n }),\n });\n }\n };\n\n const showPurgeSuccess = (key: string) => {\n if (!config?.disableAdminPopups) {\n toggleNotification({\n type: 'success',\n message: formatMessage(\n {\n id: 'strapi-cache.cache.purge.success',\n defaultMessage: 'Cache purged successfully',\n },\n {\n key: `\"${key}\"`,\n }\n ),\n });\n }\n };\n\n const showPurgeError = (key: string) => {\n if (!config?.disableAdminPopups) {\n toggleNotification({\n type: 'danger',\n message: formatMessage(\n {\n id: 'strapi-cache.cache.purge.error',\n defaultMessage: 'Error purging cache',\n },\n {\n key: `\"${key}\"`,\n }\n ),\n });\n }\n };\n\n const showNoContentTypeWarning = () => {\n if (!config?.disableAdminPopups) {\n toggleNotification({\n type: 'warning',\n message: formatMessage({\n id: 'strapi-cache.cache.purge.no-content-type',\n defaultMessage: 'No content type found',\n }),\n });\n }\n };\n\n return {\n showConfigFetchError,\n showPurgeSuccess,\n showPurgeError,\n showNoContentTypeWarning,\n };\n};\n","import { useIntl } from 'react-intl';\nimport { Archive } from '@strapi/icons';\nimport { Button, Modal } from '@strapi/design-system';\nimport { Typography } from '@strapi/design-system';\nimport { useEffect } from 'react';\nimport {\n useCacheConfig,\n useCachePermissions,\n useCacheOperations,\n useCacheNotifications,\n} from '../../hooks';\n\nexport type PurgeProps = {\n buttonText: string;\n buttonWidth?: string;\n keyToUse?: string;\n contentTypeName?: string;\n isSettingsPage?: boolean;\n};\n\nfunction PurgeModal({\n buttonText,\n keyToUse,\n buttonWidth,\n contentTypeName,\n isSettingsPage,\n}: PurgeProps) {\n const { canPurgeCache } = useCachePermissions();\n const { config, error: configError } = useCacheConfig(canPurgeCache);\n const { isCacheableRoute, clearCache } = useCacheOperations();\n const { showConfigFetchError, showPurgeSuccess, showPurgeError, showNoContentTypeWarning } =\n useCacheNotifications(config);\n const formatMessage = useIntl().formatMessage;\n\n useEffect(() => {\n if (configError) {\n showConfigFetchError(configError);\n }\n }, [configError, showConfigFetchError]);\n\n const handleClearCache = async () => {\n if (!keyToUse) {\n showNoContentTypeWarning();\n return;\n }\n\n const result = await clearCache(keyToUse);\n\n if (result.success) {\n showPurgeSuccess(keyToUse);\n } else {\n showPurgeError(keyToUse);\n }\n };\n\n if (!canPurgeCache || (!isSettingsPage && !isCacheableRoute(keyToUse, contentTypeName, config))) {\n return null;\n }\n\n return (\n <Modal.Root>\n <Modal.Trigger>\n <Button width={buttonWidth} disabled={!keyToUse} startIcon={<Archive />} variant=\"danger\">\n {buttonText}\n </Button>\n </Modal.Trigger>\n <Modal.Content>\n <Modal.Header>\n <Modal.Title>{buttonText}</Modal.Title>\n </Modal.Header>\n <Modal.Body>\n <Typography variant=\"omega\">\n {formatMessage(\n {\n id: 'strapi-cache.cache.purge.confirmation',\n defaultMessage: 'Are you sure you want to purge the cache?',\n },\n { key: `\"${keyToUse}\"` }\n )}\n </Typography>\n </Modal.Body>\n <Modal.Footer>\n <Modal.Close>\n <Button variant=\"tertiary\">\n {formatMessage({\n id: 'strapi-cache.cache.cancel',\n defaultMessage: 'No, cancel',\n })}\n </Button>\n </Modal.Close>\n <Modal.Close>\n <Button onClick={handleClearCache}>\n {formatMessage({\n id: 'strapi-cache.cache.confirm',\n defaultMessage: 'Yes, confirm',\n })}\n </Button>\n </Modal.Close>\n </Modal.Footer>\n </Modal.Content>\n </Modal.Root>\n );\n}\n\nexport default PurgeModal;\n","import { unstable_useContentManagerContext as useContentManagerContext } from '@strapi/strapi/admin';\nimport PurgeModal from '../PurgeModal';\nimport { useIntl } from 'react-intl';\n\nfunction PurgeCacheButton() {\n const { contentType } = useContentManagerContext();\n const { formatMessage } = useIntl();\n const keyToUse = contentType?.info.pluralName;\n\n return (\n <PurgeModal\n buttonText={formatMessage({\n id: 'strapi-cache.cache.purge',\n defaultMessage: 'Purge Cache',\n })}\n keyToUse={keyToUse}\n ></PurgeModal>\n );\n}\n\nexport default PurgeCacheButton;\n","import { unstable_useContentManagerContext as useContentManagerContext } from '@strapi/strapi/admin';\nimport PurgeModal from '../PurgeModal';\nimport { useIntl } from 'react-intl';\n\nfunction PurgeEntityButton() {\n const { formatMessage } = useIntl();\n const { id, isSingleType, contentType } = useContentManagerContext();\n const apiPath = isSingleType ? contentType?.info.singularName : id;\n\n if (!apiPath) {\n return null;\n }\n\n const keyToUse = encodeURIComponent(apiPath);\n const contentTypeName = isSingleType\n ? contentType?.info.singularName\n : contentType?.info.pluralName;\n\n return (\n <PurgeModal\n buttonWidth=\"100%\"\n buttonText={formatMessage({\n id: 'strapi-cache.cache.purge.entity',\n defaultMessage: 'Purge Entity Cache',\n })}\n keyToUse={keyToUse}\n contentTypeName={contentTypeName}\n ></PurgeModal>\n );\n}\n\nexport default PurgeEntityButton;\n","import { PLUGIN_ID } from './pluginId';\nimport { Initializer } from './components/Initializer';\nimport PurgeCacheButton from './components/PurgeCacheButton';\nimport PurgeEntityButton from './components/PurgeEntityButton';\n\nexport default {\n register(app: any) {\n app.registerPlugin({\n id: PLUGIN_ID,\n initializer: Initializer,\n isReady: false,\n name: PLUGIN_ID,\n });\n\n app.getPlugin('content-manager').injectComponent('listView', 'actions', {\n name: PurgeCacheButton,\n Component: PurgeCacheButton,\n });\n\n app.getPlugin('content-manager').injectComponent('editView', 'right-links', {\n name: PurgeEntityButton,\n Component: PurgeEntityButton,\n });\n\n app.createSettingSection(\n {\n id: PLUGIN_ID,\n intlLabel: {\n id: 'strapi-cache.settings.link',\n defaultMessage: 'Strapi Cache',\n },\n },\n [\n {\n intlLabel: {\n id: 'strapi-cache.settings.link',\n defaultMessage: 'Strapi Cache',\n },\n id: 'settings',\n to: `${PLUGIN_ID}/settings`,\n Component: () => import('./components/SettingsPage'),\n permissions: [],\n },\n ]\n );\n },\n\n async registerTrads({ locales }: { locales: string[] }) {\n return Promise.all(\n locales.map(async (locale) => {\n try {\n const { default: data } = await import(`./translations/${locale}.json`);\n\n return { data, locale };\n } catch {\n return { data: {}, locale };\n }\n })\n );\n },\n};\n"],"names":["error","useContentManagerContext"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sources":["../../server/src/utils/log.ts","../../server/src/utils/invalidateCache.ts","../../server/src/permissions.ts","../../server/src/bootstrap.ts","../../server/src/utils/key.ts","../../server/src/utils/body.ts","../../server/src/utils/header.ts","../../server/src/middlewares/cache.ts","../../server/src/middlewares/graphql.ts","../../server/src/middlewares/index.ts","../../server/src/register.ts","../../server/src/config/index.ts","../../server/src/content-types/index.ts","../../server/src/controllers/controller.ts","../../server/src/controllers/index.ts","../../server/src/policies/index.ts","../../server/src/routes/purge.ts","../../server/src/routes/index.ts","../../server/src/utils/withTimeout.ts","../../server/src/services/memory/provider.ts","../../server/src/services/redis/provider.ts","../../server/src/services/resolver.ts","../../server/src/services/index.ts","../../server/src/index.ts"],"sourcesContent":["export const loggy = {\n info: (msg: string) => {\n const shouldDebug = strapi.plugin('strapi-cache').config('debug') ?? false;\n if (!shouldDebug) {\n return;\n }\n strapi.log.info(`[STRAPI CACHE] ${msg}`);\n },\n error: (msg: string) => {\n const shouldDebug = strapi.plugin('strapi-cache').config('debug') ?? false;\n if (!shouldDebug) {\n return;\n }\n strapi.log.error(`[STRAPI CACHE] ${msg}`);\n },\n warn: (msg: string) => {\n const shouldDebug = strapi.plugin('strapi-cache').config('debug') ?? false;\n if (!shouldDebug) {\n return;\n }\n strapi.log.warn(`[STRAPI CACHE] ${msg}`);\n },\n};\n","import { Core } from '@strapi/strapi';\nimport { CacheProvider } from 'src/types/cache.types';\nimport { loggy } from './log';\n\nexport async function invalidateCache(event: any, cacheStore: CacheProvider, strapi: Core.Strapi) {\n const { model } = event;\n const uid = model.uid;\n const restApiPrefix = strapi.config.get('api.rest.prefix', '/api');\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 = `${restApiPrefix}/${pluralName}`;\n const regex = new RegExp(`^.*:${apiPath}(/.*)?(\\\\?.*)?$`);\n\n await cacheStore.clearByRegexp([regex]);\n loggy.info(`Invalidated cache for ${apiPath}`);\n } catch (error) {\n loggy.error('Cache invalidation error:');\n loggy.error(error);\n }\n}\n\nexport async function invalidateGraphqlCache(\n event: any,\n cacheStore: CacheProvider,\n strapi: Core.Strapi\n) {\n try {\n const graphqlRegex = new RegExp(`^POST:\\/graphql(:.*)?$`);\n\n await cacheStore.clearByRegexp([graphqlRegex]);\n loggy.info(`Invalidated cache for ${graphqlRegex}`);\n } catch (error) {\n loggy.error('Cache invalidation error:');\n loggy.error(error);\n }\n}\n","export const actions = [\n {\n section: 'plugins',\n displayName: 'Purge Cache',\n uid: 'purge-cache',\n pluginName: 'strapi-cache',\n },\n];\n","import type { Core } from '@strapi/strapi';\nimport { invalidateCache, invalidateGraphqlCache } from './utils/invalidateCache';\nimport { CacheService } from './types/cache.types';\nimport { loggy } from './utils/log';\nimport { actions } from './permissions';\n\nconst bootstrap = ({ strapi }: { strapi: Core.Strapi }) => {\n loggy.info('Initializing');\n try {\n const cacheService = strapi.plugin('strapi-cache').services.service as CacheService;\n const autoPurgeCache = strapi.plugin('strapi-cache').config('autoPurgeCache') as boolean;\n const autoPurgeCacheOnStart = strapi.plugin('strapi-cache').config('autoPurgeCacheOnStart') as boolean;\n const cacheStore = cacheService.getCacheInstance();\n\n if (!cacheStore) {\n loggy.error('Plugin could not be initialized');\n return;\n }\n\n cacheStore.init();\n\n if (autoPurgeCache) {\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\n if (autoPurgeCacheOnStart) {\n cacheStore.reset().then(() => {\n loggy.info('Cache purged successfully');\n }).catch((error) => {\n loggy.error(`Error purging cache on start: ${error.message}`);\n })\n }\n } catch (error) {\n loggy.error('Plugin could not be initialized');\n return;\n }\n loggy.info('Plugin initialized');\n\n strapi.admin.services.permission.actionProvider.registerMany(actions);\n};\n\nexport default bootstrap;\n","import { createHash } from 'crypto';\nimport { Context } from 'koa';\n\nexport const generateCacheKey = (context: Context) => {\n const { url } = context.request;\n const { method } = context.request;\n\n return `${method}:${url}`;\n};\n\nexport const generateGraphqlCacheKey = (payload: string) => {\n const hash = createHash('sha256').update(payload).digest('base64url');\n return `POST:/graphql:${hash}`;\n};\n\nexport const escapeRegExp = (s: string) => s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n","import { Stream } from 'stream';\nimport { createGunzip, createBrotliDecompress, createInflate } from 'zlib';\n\nexport const streamToBuffer = (stream: Stream): Promise<Buffer> => {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n stream.on('data', (chunk) => chunks.push(chunk));\n stream.on('end', () => resolve(Buffer.concat(chunks)));\n stream.on('error', reject);\n });\n};\n\nexport const decompressBuffer = async (buffer: Buffer, encoding?: string): Promise<Buffer> => {\n return new Promise((resolve, reject) => {\n let decompressStream;\n switch (encoding) {\n case 'gzip':\n decompressStream = createGunzip();\n break;\n case 'br':\n decompressStream = createBrotliDecompress();\n break;\n case 'deflate':\n decompressStream = createInflate();\n break;\n default:\n return resolve(buffer);\n }\n\n const chunks: Buffer[] = [];\n decompressStream.on('data', (chunk) => chunks.push(chunk));\n decompressStream.on('end', () => resolve(Buffer.concat(chunks)));\n decompressStream.on('error', reject);\n\n decompressStream.end(buffer);\n });\n};\n\nexport const decodeBufferToText = (buffer: Buffer): string => {\n const decoder = new TextDecoder('utf-8');\n return decoder.decode(buffer);\n};\n","import { Context } from 'koa';\nimport { OutgoingHttpHeaders } from 'http';\n\nexport function getHeadersToStore(\n ctx: Context,\n cacheHeaders: boolean,\n cacheHeadersAllowList: string[] = [],\n cacheHeadersDenyList: string[] = []\n): OutgoingHttpHeaders | null {\n let headersToStore: OutgoingHttpHeaders | null = null;\n\n if (cacheHeaders) {\n let headers = ctx.response.headers;\n\n if (cacheHeadersAllowList.length) {\n headers = Object.fromEntries(\n Object.entries(headers).filter(([key]) => cacheHeadersAllowList.includes(key.toLowerCase()))\n );\n }\n\n if (cacheHeadersDenyList.length) {\n headers = Object.fromEntries(\n Object.entries(headers).filter(([key]) => !cacheHeadersDenyList.includes(key.toLowerCase()))\n );\n }\n\n headersToStore = headers;\n }\n\n return headersToStore;\n}\n\nexport function getCacheHeaderConfig() {\n const cacheHeaders = strapi.plugin('strapi-cache').config('cacheHeaders') as boolean;\n const cacheHeadersDenyList = strapi\n .plugin('strapi-cache')\n .config('cacheHeadersDenyList') as string[];\n const cacheHeadersAllowList = strapi\n .plugin('strapi-cache')\n .config('cacheHeadersAllowList') as string[];\n const cacheAuthorizedRequests = strapi\n .plugin('strapi-cache')\n .config('cacheAuthorizedRequests') as boolean;\n\n return {\n cacheHeaders,\n cacheHeadersDenyList,\n cacheHeadersAllowList,\n cacheAuthorizedRequests,\n };\n}\n","import { Context } from 'koa';\nimport { generateCacheKey } from '../utils/key';\nimport { CacheService } from '../../src/types/cache.types';\nimport { loggy } from '../utils/log';\nimport Stream from 'stream';\nimport { decodeBufferToText, decompressBuffer, streamToBuffer } from '../utils/body';\nimport { getCacheHeaderConfig, getHeadersToStore } from '../utils/header';\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 excludeRoutes = strapi.plugin('strapi-cache').config('excludeRoutes') as string[];\n const { cacheHeaders, cacheHeadersDenyList, cacheHeadersAllowList, cacheAuthorizedRequests } =\n getCacheHeaderConfig();\n const cacheStore = cacheService.getCacheInstance();\n const { url } = ctx.request;\n const key = generateCacheKey(ctx);\n const cacheEntry = await cacheStore.get(key);\n const cacheControlHeader = ctx.request.headers['cache-control'];\n const noCache = cacheControlHeader && cacheControlHeader.includes('no-cache');\n const restApiPrefix = strapi.config.get('api.rest.prefix', '/api');\n\n const routeIsExcluded = excludeRoutes.some((route) => url.startsWith(route));\n \n if (routeIsExcluded) {\n loggy.info(`Route excluded from cache: ${url}`);\n await next();\n return;\n }\n\n const routeIsCachable =\n cacheableRoutes.some((route) => url.startsWith(route)) ||\n (cacheableRoutes.length === 0 && url.startsWith(restApiPrefix));\n\n const authorizationHeader = ctx.request.headers['authorization'];\n\n if (authorizationHeader && !cacheAuthorizedRequests) {\n loggy.info(`Authorized request bypassing cache: ${key}`);\n await next();\n return;\n }\n\n const middlewaresConfig = strapi.config.get('middlewares') as any[];\n const corsMiddleware = middlewaresConfig.find((mw: any) => mw.name === 'strapi::cors');\n\n const corsConfig = corsMiddleware?.config;\n const origin = ctx?.request?.headers?.origin;\n let allowedOrigins = corsConfig?.origin ?? '*';\n\n if (typeof allowedOrigins === 'string') {\n allowedOrigins = [allowedOrigins];\n }\n\n if (cacheEntry && !noCache) {\n loggy.info(`HIT with key: ${key}`);\n ctx.status = 200;\n ctx.body = cacheEntry.body;\n\n if (cacheHeaders) {\n ctx.set(cacheEntry.headers);\n }\n\n if (corsMiddleware) {\n loggy.info('CORS middleware is set, checking allowed origins');\n if (allowedOrigins.includes(origin)) {\n loggy.info(`Setting Access-Control-Allow-Origin to ${origin}`);\n ctx.set('Access-Control-Allow-Origin', origin);\n } else if (typeof origin === 'undefined' || allowedOrigins.includes('*')) {\n loggy.info('No origin header or * in allowed origins, setting to *');\n ctx.set('Access-Control-Allow-Origin', '*');\n }\n } else {\n loggy.info('No CORS middleware set, setting to request origin or *');\n ctx.set('Access-Control-Allow-Origin', ctx.request.headers.origin || '*');\n }\n\n return;\n }\n\n await next();\n\n if (ctx.method === 'GET' && ctx.status >= 200 && ctx.status < 300 && routeIsCachable) {\n loggy.info(`MISS with key: ${key}`);\n const headersToStore = getHeadersToStore(\n ctx,\n cacheHeaders,\n cacheHeadersAllowList,\n cacheHeadersDenyList\n );\n\n let setCache = true;\n\n if (corsMiddleware) {\n if (allowedOrigins.includes(origin)) {\n //do nothing as the origin is allowed\n } else if (typeof origin === 'undefined' || allowedOrigins.includes('*')) {\n //do nothing as the origin is undefined (POSTMAN) or allowedOrigins includes '*'\n } else {\n setCache = false;\n }\n }\n\n if (ctx.body instanceof Stream) {\n const buf = await streamToBuffer(ctx.body);\n const contentEncoding = ctx.response.headers['content-encoding'];\n const decompressed = await decompressBuffer(buf, contentEncoding);\n const responseText = decodeBufferToText(decompressed);\n if (setCache) {\n await cacheStore.set(key, { body: responseText, headers: headersToStore });\n }\n ctx.body = buf;\n } else {\n if (setCache) {\n await cacheStore.set(key, { body: ctx.body, headers: headersToStore });\n }\n }\n }\n};\n\nexport default middleware;\n","import rawBody from 'raw-body';\nimport { generateGraphqlCacheKey } from '../utils/key';\nimport Stream, { Readable } from 'stream';\nimport { loggy } from '../utils/log';\nimport { CacheService } from '../types/cache.types';\nimport { decodeBufferToText, decompressBuffer, streamToBuffer } from '../utils/body';\nimport { getCacheHeaderConfig, getHeadersToStore } from '../utils/header';\n\nconst middleware = async (ctx: any, next: any) => {\n const cacheService = strapi.plugin('strapi-cache').services.service as CacheService;\n const { cacheHeaders, cacheHeadersDenyList, cacheHeadersAllowList, cacheAuthorizedRequests } =\n getCacheHeaderConfig();\n const cacheStore = cacheService.getCacheInstance();\n const { url } = ctx.request;\n\n const originalReq = ctx.req;\n const bodyBuffer = await rawBody(originalReq);\n const body = bodyBuffer.toString();\n\n const clonedReq = new Readable();\n clonedReq.push(bodyBuffer);\n clonedReq.push(null);\n\n (clonedReq as any).headers = { ...originalReq.headers };\n (clonedReq as any).method = originalReq.method;\n (clonedReq as any).url = originalReq.url;\n (clonedReq as any).httpVersion = originalReq.httpVersion;\n (clonedReq as any).socket = originalReq.socket;\n (clonedReq as any).connection = originalReq.connection;\n\n ctx.req = clonedReq;\n ctx.request.req = clonedReq;\n\n const isIntrospectionQuery = body.includes('IntrospectionQuery');\n if (isIntrospectionQuery) {\n loggy.info('Skipping cache for introspection query');\n await next();\n return;\n }\n\n const key = generateGraphqlCacheKey(body);\n const cacheEntry = await cacheStore.get(key);\n const cacheControlHeader = ctx.request.headers['cache-control'];\n const noCache = cacheControlHeader && cacheControlHeader.includes('no-cache');\n const authorizationHeader = ctx.request.headers['authorization'];\n\n if (authorizationHeader && !cacheAuthorizedRequests) {\n loggy.info(`Authorized request bypassing cache: ${key}`);\n await next();\n return;\n }\n\n const middlewaresConfig = strapi.config.get('middlewares') as any[];\n const corsMiddleware = middlewaresConfig.find((mw: any) => mw.name === 'strapi::cors');\n\n const corsConfig = corsMiddleware?.config;\n const origin = ctx?.request?.headers?.origin;\n let allowedOrigins = corsConfig?.origin ?? '*';\n\n if (typeof allowedOrigins === 'string') {\n allowedOrigins = [allowedOrigins];\n }\n\n if (cacheEntry && !noCache) {\n loggy.info(`HIT with key: ${key}`);\n ctx.status = 200;\n ctx.body = cacheEntry.body;\n if (cacheHeaders) {\n ctx.set(cacheEntry.headers);\n }\n\n if (corsMiddleware) {\n loggy.info('CORS middleware is set, checking allowed origins');\n\n if (allowedOrigins.includes(origin)) {\n loggy.info(`Setting Access-Control-Allow-Origin to ${origin}`);\n ctx.set('Access-Control-Allow-Origin', origin);\n } else if (typeof origin === 'undefined' || allowedOrigins.includes('*')) {\n loggy.info('No origin header or * in allowed origins, setting to *');\n ctx.set('Access-Control-Allow-Origin', '*');\n }\n } else {\n loggy.info('No CORS middleware set, setting to request origin or *');\n ctx.set('Access-Control-Allow-Origin', ctx.request.headers.origin || '*');\n }\n return;\n }\n\n await next();\n\n if (\n ctx.method === 'POST' &&\n ctx.status >= 200 &&\n ctx.status < 300 &&\n url.startsWith('/graphql')\n ) {\n loggy.info(`MISS with key: ${key}`);\n const headers = ctx.request.headers;\n const authorizationHeader = headers['authorization'];\n\n if (authorizationHeader && !cacheAuthorizedRequests) {\n loggy.info(`Authorized request not caching: ${key}`);\n return;\n }\n\n const headersToStore = getHeadersToStore(\n ctx,\n cacheHeaders,\n cacheHeadersAllowList,\n cacheHeadersDenyList\n );\n\n let setCache = true;\n\n if (corsMiddleware) {\n if (allowedOrigins.includes(origin)) {\n //do nothing as the origin is allowed\n } else if (typeof origin === 'undefined' || allowedOrigins.includes('*')) {\n //do nothing as the origin is undefined (POSTMAN) or allowedOrigins includes '*'\n } else {\n setCache = false;\n }\n }\n\n if (ctx.body instanceof Stream) {\n const buf = await streamToBuffer(ctx.body);\n const contentEncoding = ctx.response.headers['content-encoding'];\n const decompressed = await decompressBuffer(buf, contentEncoding);\n const responseText = decodeBufferToText(decompressed);\n if (setCache) {\n await cacheStore.set(key, { body: responseText, headers: headersToStore });\n }\n ctx.body = buf;\n } else {\n if (setCache) {\n await cacheStore.set(key, { body: ctx.body, headers: headersToStore });\n }\n }\n }\n};\n\nexport default middleware;\n","import cache from './cache';\nimport graphql from './graphql';\n\nexport default {\n graphql,\n cache,\n};\n","import type { Core } from '@strapi/strapi';\nimport middlewares from './middlewares';\n\nconst register = ({ strapi }: { strapi: Core.Strapi }) => {\n strapi.server.use(middlewares.cache);\n strapi.server.use(middlewares.graphql);\n};\n\nexport default register;\n","export default {\n default: ({ env }) => ({\n debug: false,\n max: 1000,\n ttl: 1000 * 60 * 60,\n size: 1024 * 1024 * 10,\n allowStale: false,\n cacheableRoutes: [],\n provider: 'memory',\n excludeRoutes: [],\n redisConfig: env('REDIS_URL'),\n redisClusterNodes: [],\n redisClusterOptions: {},\n cacheHeaders: true,\n cacheHeadersDenyList: [],\n cacheHeadersAllowList: [],\n cacheAuthorizedRequests: false,\n cacheGetTimeoutInMs: 1000,\n autoPurgeCache: true,\n autoPurgeCacheOnStart: true,\n disableAdminPopups: false,\n }),\n validator: (config) => {\n if (typeof config.debug !== 'boolean') {\n throw new Error(`Invalid config: debug must be a boolean`);\n }\n if (typeof config.max !== 'number') {\n throw new Error(`Invalid config: max must be a number`);\n }\n if (typeof config.ttl !== 'number') {\n throw new Error(`Invalid config: ttl must be a number`);\n }\n if (typeof config.size !== 'number') {\n throw new Error(`Invalid config: size must be a number`);\n }\n if (typeof config.allowStale !== 'boolean') {\n throw new Error(`Invalid config: allowStale must be a boolean`);\n }\n if (\n !Array.isArray(config.cacheableRoutes) ||\n config.cacheableRoutes.some((item) => typeof item !== 'string')\n ) {\n throw new Error(`Invalid config: cacheableRoutes must be an string array`);\n }\n if (\n !Array.isArray(config.excludeRoutes) ||\n config.excludeRoutes.some((item) => typeof item !== 'string')\n ) {\n throw new Error(`Invalid config: excludeRoutes must be a 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') {\n if (!config.redisConfig) {\n throw new Error(`Invalid config: redisConfig must be set when using redis provider`);\n }\n if (typeof config.redisConfig !== 'string' && typeof config.redisConfig !== 'object') {\n throw new Error(\n `Invalid config: redisConfig must be a string or object when using redis provider`\n );\n }\n if (\n !Array.isArray(config.redisClusterNodes) ||\n config.redisClusterNodes.some((item) => !('host' in item && 'port' in item))\n ) {\n throw new Error(\n `Invalid config: redisClusterNodes must be as a list of objects with keys 'host' and 'port'`\n );\n }\n if (typeof config.redisClusterOptions !== 'object') {\n throw new Error(`Invalid config: redisClusterOptions must be an object`);\n }\n }\n if (typeof config.cacheHeaders !== 'boolean') {\n throw new Error(`Invalid config: cacheHeaders must be a boolean`);\n }\n if (\n !Array.isArray(config.cacheHeadersDenyList) ||\n config.cacheHeadersDenyList.some((item) => typeof item !== 'string')\n ) {\n throw new Error(`Invalid config: cacheHeadersDenyList must be an string array`);\n }\n if (\n !Array.isArray(config.cacheHeadersAllowList) ||\n config.cacheHeadersAllowList.some((item) => typeof item !== 'string')\n ) {\n throw new Error(`Invalid config: cacheHeadersAllowList must be an string array`);\n }\n if (typeof config.cacheAuthorizedRequests !== 'boolean') {\n throw new Error(`Invalid config: cacheAuthorizedRequests must be a boolean`);\n }\n if (typeof config.cacheGetTimeoutInMs !== 'number') {\n throw new Error(`Invalid config: cacheGetTimeoutInMs must be a number`);\n }\n if (typeof config.autoPurgeCache !== 'boolean') {\n throw new Error(`Invalid config: autoPurgeCache must be a boolean`);\n }\n if (typeof config.autoPurgeCacheOnStart !== 'boolean') {\n throw new Error(`Invalid config: autoPurgeCacheOnStart must be a boolean`);\n }\n if (typeof config.disableAdminPopups !== 'boolean') {\n throw new Error(`Invalid config: disableAdminPopups must be a boolean`);\n }\n },\n};\n","export default {};\n","import type { Core } from '@strapi/strapi';\nimport { Context } from 'koa';\nimport { CacheService } from 'src/types/cache.types';\n\ninterface PluginConfig {\n cacheableRoutes: string[];\n disableAdminPopups: boolean;\n}\n\nconst controller = ({ strapi }: { strapi: Core.Strapi }) => ({\n async purgeCache(ctx: Context) {\n const service = strapi.plugin('strapi-cache').service('service') as CacheService;\n\n await service.getCacheInstance().reset();\n\n ctx.body = {\n message: 'Cache purged successfully',\n };\n },\n async purgeCacheByKey(ctx: Context) {\n const { key } = ctx.request.body as { key?: string };\n\n if (!key || typeof key !== 'string' || key.trim() === '') {\n ctx.status = 400;\n ctx.body = {\n error: 'Key is required and must be a non-empty string',\n };\n return;\n }\n\n const service = strapi.plugin('strapi-cache').service('service') as CacheService;\n const escapeRegExp = (s: string) => s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const regex = new RegExp(escapeRegExp(key));\n\n await service.getCacheInstance().clearByRegexp([regex]);\n\n ctx.body = {\n message: `Cache purged successfully for key: ${key}`,\n };\n },\n async config(ctx: Context) {\n try {\n // construct config object with only the properties needed by admin\n const config: PluginConfig = {\n cacheableRoutes: strapi.plugin('strapi-cache').config('cacheableRoutes') ?? [],\n disableAdminPopups: strapi.plugin('strapi-cache').config('disableAdminPopups') ?? false,\n };\n\n ctx.body = config;\n } catch (error) {\n console.error('Error constructing config:', error);\n ctx.status = 500;\n ctx.body = { error: 'Configuration not available' };\n }\n },\n});\n\nexport default controller;\n","import controller from './controller';\n\nexport default {\n controller,\n};\n","export default {};\n","export default [\n {\n method: 'POST',\n path: '/purge-cache',\n handler: 'controller.purgeCache',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: {\n actions: ['plugin::strapi-cache.purge-cache'],\n },\n },\n ],\n },\n },\n {\n method: 'POST',\n path: '/purge-cache/key',\n handler: 'controller.purgeCacheByKey',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: {\n actions: ['plugin::strapi-cache.purge-cache'],\n },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/config',\n handler: 'controller.config',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: {\n actions: ['plugin::strapi-cache.purge-cache'],\n },\n },\n ],\n },\n },\n];\n","import purgeRoute from './purge';\n\nconst routes = {\n 'purge-route': {\n type: 'admin',\n routes: purgeRoute,\n },\n};\n\nexport default routes;\n","export const withTimeout = (callback: () => Promise<any>, ms: number) => {\n let timeout: NodeJS.Timeout | null = null;\n\n return Promise.race([\n callback().then((result) => {\n if (timeout) {\n clearTimeout(timeout);\n }\n return result;\n }),\n new Promise((_, reject) => {\n timeout = setTimeout(() => {\n reject(new Error('timeout'));\n }, ms);\n }),\n ]);\n};\n","import type { Core } from '@strapi/strapi';\nimport { LRUCache } from 'lru-cache';\nimport { withTimeout } from '../../utils/withTimeout';\nimport { CacheProvider, CacheService } from '../../types/cache.types';\nimport { loggy } from '../../utils/log';\n\nexport class InMemoryCacheProvider implements CacheProvider {\n private initialized = false;\n private provider!: LRUCache<string, any>;\n private cacheGetTimeoutInMs: number;\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 this.cacheGetTimeoutInMs = Number(\n this.strapi.plugin('strapi-cache').config('cacheGetTimeoutInMs')\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 return withTimeout(\n () =>\n new Promise((resolve) => {\n resolve(this.provider.get(key));\n }),\n this.cacheGetTimeoutInMs\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, Cluster, ClusterNode, ClusterOptions } 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 | Cluster;\n private cacheGetTimeoutInMs: number;\n private keyPrefix: string;\n\n constructor(private strapi: Core.Strapi) {}\n\n init(): void {\n if (this.initialized) {\n loggy.error('Redis provider already initialized');\n return;\n }\n try {\n const redisConfig =\n this.strapi.plugin('strapi-cache').config('redisConfig') || 'redis://localhost:6379';\n const redisClusterNodes: ClusterNode[] = this.strapi\n .plugin('strapi-cache')\n .config('redisClusterNodes');\n this.cacheGetTimeoutInMs = Number(\n this.strapi.plugin('strapi-cache').config('cacheGetTimeoutInMs')\n );\n this.keyPrefix =\n (this.strapi.plugin('strapi-cache').config('redisConfig')?.['keyPrefix'] as\n | string\n | undefined) ?? '';\n if (redisClusterNodes.length) {\n const redisClusterOptions: ClusterOptions = this.strapi\n .plugin('strapi-cache')\n .config('redisClusterOptions');\n if (!redisClusterOptions['redisOptions']) {\n redisClusterOptions.redisOptions = redisConfig;\n }\n this.client = new Redis.Cluster(redisClusterNodes, redisClusterOptions);\n } else {\n this.client = new Redis(redisConfig);\n }\n this.initialized = true;\n\n loggy.info('Redis provider initialized');\n } catch (error) {\n loggy.error(error);\n }\n }\n\n get ready(): boolean {\n if (!this.initialized) {\n loggy.info('Redis provider not initialized');\n return false;\n }\n\n return true;\n }\n\n async get(key: string): Promise<any | null> {\n if (!this.ready) return null;\n\n return withTimeout(() => this.client.get(key), this.cacheGetTimeoutInMs)\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 // plugin ttl is ms, ioredis ttl is s, so we convert here\n const ttlInMs = Number(this.strapi.plugin('strapi-cache').config('ttl'));\n const ttlInS = Number((ttlInMs / 1000).toFixed());\n const serialized = JSON.stringify(val);\n if (ttlInS > 0) {\n await this.client.set(key, serialized, 'EX', ttlInS);\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 const relativeKey = key.slice(this.keyPrefix.length);\n loggy.info(`Redis PURGING KEY: ${relativeKey}`);\n await this.client.del(relativeKey);\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(`${this.keyPrefix}*`);\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 if (this.keyPrefix) {\n loggy.info(`Redis FLUSHING NAMESPACE: ${this.keyPrefix}`);\n const keys = await this.keys();\n if (!keys) return null;\n\n const toDelete = keys.filter((key) => key.startsWith(this.keyPrefix));\n await Promise.all(toDelete.map((key) => this.del(key)));\n return true;\n }\n\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\n loggy.info(JSON.stringify(keys));\n if (!keys) return;\n\n const toDelete = keys.filter((key) => regExps.some((re) => re.test(key)));\n loggy.info(JSON.stringify(toDelete));\n await Promise.all(toDelete.map((key) => this.del(key)));\n }\n}\n","import type { Core } from '@strapi/strapi';\nimport { InMemoryCacheProvider } from './memory/provider';\nimport { RedisCacheProvider } from './redis/provider';\nimport { CacheProvider } from '../../src/types/cache.types';\nimport { loggy } from '../../src/utils/log';\n\nexport const resolveCacheProvider = (strapi: Core.Strapi): CacheProvider => {\n const providerType = strapi.plugin('strapi-cache').config('provider') || 'memory';\n\n loggy.info(`Selected cache provider: ${providerType}`);\n\n let instance: CacheProvider;\n\n switch (providerType) {\n case 'redis':\n instance = new RedisCacheProvider(strapi);\n break;\n default:\n instance = new InMemoryCacheProvider(strapi);\n break;\n }\n\n return instance;\n};\n","import type { Core } from '@strapi/strapi';\nimport { resolveCacheProvider } from './resolver';\nimport { CacheProvider, CacheService } from '../../src/types/cache.types';\nimport { loggy } from '../../src/utils/log';\n\nconst service = ({ strapi }: { strapi: Core.Strapi }): CacheService => {\n let instance: null | CacheProvider = null;\n\n return {\n getCacheInstance() {\n if (!instance) {\n loggy.info('Initializing cache service from provider config...');\n instance = resolveCacheProvider(strapi);\n }\n return instance;\n },\n };\n};\n\nexport default {\n service,\n};\n","/**\n * Application methods\n */\nimport bootstrap from './bootstrap';\nimport register from './register';\n\n/**\n * Plugin server methods\n */\nimport config from './config';\nimport contentTypes from './content-types';\nimport controllers from './controllers';\nimport middlewares from './middlewares';\nimport policies from './policies';\nimport routes from './routes';\nimport services from './services';\n\nexport default {\n register,\n bootstrap,\n destroy() {},\n config,\n controllers,\n routes,\n services,\n contentTypes,\n policies,\n middlewares,\n};\n"],"names":["strapi","createHash","createGunzip","createBrotliDecompress","createInflate","middleware","Stream","rawBody","Readable","authorizationHeader","graphql","cache","config","service","LRUCache","Redis"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.mjs","sources":["../../server/src/utils/log.ts","../../server/src/utils/invalidateCache.ts","../../server/src/permissions.ts","../../server/src/bootstrap.ts","../../server/src/utils/key.ts","../../server/src/utils/body.ts","../../server/src/utils/header.ts","../../server/src/middlewares/cache.ts","../../server/src/middlewares/graphql.ts","../../server/src/middlewares/index.ts","../../server/src/register.ts","../../server/src/config/index.ts","../../server/src/content-types/index.ts","../../server/src/controllers/controller.ts","../../server/src/controllers/index.ts","../../server/src/policies/index.ts","../../server/src/routes/purge.ts","../../server/src/routes/index.ts","../../server/src/utils/withTimeout.ts","../../server/src/services/memory/provider.ts","../../server/src/services/redis/provider.ts","../../server/src/services/resolver.ts","../../server/src/services/index.ts","../../server/src/index.ts"],"sourcesContent":["export const loggy = {\n info: (msg: string) => {\n const shouldDebug = strapi.plugin('strapi-cache').config('debug') ?? false;\n if (!shouldDebug) {\n return;\n }\n strapi.log.info(`[STRAPI CACHE] ${msg}`);\n },\n error: (msg: string) => {\n const shouldDebug = strapi.plugin('strapi-cache').config('debug') ?? false;\n if (!shouldDebug) {\n return;\n }\n strapi.log.error(`[STRAPI CACHE] ${msg}`);\n },\n warn: (msg: string) => {\n const shouldDebug = strapi.plugin('strapi-cache').config('debug') ?? false;\n if (!shouldDebug) {\n return;\n }\n strapi.log.warn(`[STRAPI CACHE] ${msg}`);\n },\n};\n","import { Core } from '@strapi/strapi';\nimport { CacheProvider } from 'src/types/cache.types';\nimport { loggy } from './log';\n\nexport async function invalidateCache(event: any, cacheStore: CacheProvider, strapi: Core.Strapi) {\n const { model } = event;\n const uid = model.uid;\n const restApiPrefix = strapi.config.get('api.rest.prefix', '/api');\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 = `${restApiPrefix}/${pluralName}`;\n const regex = new RegExp(`^.*:${apiPath}(/.*)?(\\\\?.*)?$`);\n\n await cacheStore.clearByRegexp([regex]);\n loggy.info(`Invalidated cache for ${apiPath}`);\n } catch (error) {\n loggy.error('Cache invalidation error:');\n loggy.error(error);\n }\n}\n\nexport async function invalidateGraphqlCache(\n event: any,\n cacheStore: CacheProvider,\n strapi: Core.Strapi\n) {\n try {\n const graphqlRegex = new RegExp(`^POST:\\/graphql(:.*)?$`);\n\n await cacheStore.clearByRegexp([graphqlRegex]);\n loggy.info(`Invalidated cache for ${graphqlRegex}`);\n } catch (error) {\n loggy.error('Cache invalidation error:');\n loggy.error(error);\n }\n}\n","export const actions = [\n {\n section: 'plugins',\n displayName: 'Purge Cache',\n uid: 'purge-cache',\n pluginName: 'strapi-cache',\n },\n];\n","import type { Core } from '@strapi/strapi';\nimport { invalidateCache, invalidateGraphqlCache } from './utils/invalidateCache';\nimport { CacheService } from './types/cache.types';\nimport { loggy } from './utils/log';\nimport { actions } from './permissions';\n\nconst bootstrap = ({ strapi }: { strapi: Core.Strapi }) => {\n loggy.info('Initializing');\n try {\n const cacheService = strapi.plugin('strapi-cache').services.service as CacheService;\n const autoPurgeCache = strapi.plugin('strapi-cache').config('autoPurgeCache') as boolean;\n const autoPurgeCacheOnStart = strapi.plugin('strapi-cache').config('autoPurgeCacheOnStart') as boolean;\n const cacheStore = cacheService.getCacheInstance();\n\n if (!cacheStore) {\n loggy.error('Plugin could not be initialized');\n return;\n }\n\n cacheStore.init();\n\n if (autoPurgeCache) {\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\n if (autoPurgeCacheOnStart) {\n cacheStore.reset().then(() => {\n loggy.info('Cache purged successfully');\n }).catch((error) => {\n loggy.error(`Error purging cache on start: ${error.message}`);\n })\n }\n } catch (error) {\n loggy.error('Plugin could not be initialized');\n return;\n }\n loggy.info('Plugin initialized');\n\n strapi.admin.services.permission.actionProvider.registerMany(actions);\n};\n\nexport default bootstrap;\n","import { createHash } from 'crypto';\nimport { Context } from 'koa';\n\nexport const generateCacheKey = (context: Context) => {\n const { url } = context.request;\n const { method } = context.request;\n\n return `${method}:${url}`;\n};\n\nexport const generateGraphqlCacheKey = (payload: string) => {\n const hash = createHash('sha256').update(payload).digest('base64url');\n return `POST:/graphql:${hash}`;\n};\n\nexport const escapeRegExp = (s: string) => s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n","import { Stream } from 'stream';\nimport { createGunzip, createBrotliDecompress, createInflate } from 'zlib';\n\nexport const streamToBuffer = (stream: Stream): Promise<Buffer> => {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n stream.on('data', (chunk) => chunks.push(chunk));\n stream.on('end', () => resolve(Buffer.concat(chunks)));\n stream.on('error', reject);\n });\n};\n\nexport const decompressBuffer = async (buffer: Buffer, encoding?: string): Promise<Buffer> => {\n return new Promise((resolve, reject) => {\n let decompressStream;\n switch (encoding) {\n case 'gzip':\n decompressStream = createGunzip();\n break;\n case 'br':\n decompressStream = createBrotliDecompress();\n break;\n case 'deflate':\n decompressStream = createInflate();\n break;\n default:\n return resolve(buffer);\n }\n\n const chunks: Buffer[] = [];\n decompressStream.on('data', (chunk) => chunks.push(chunk));\n decompressStream.on('end', () => resolve(Buffer.concat(chunks)));\n decompressStream.on('error', reject);\n\n decompressStream.end(buffer);\n });\n};\n\nexport const decodeBufferToText = (buffer: Buffer): string => {\n const decoder = new TextDecoder('utf-8');\n return decoder.decode(buffer);\n};\n","import { Context } from 'koa';\nimport { OutgoingHttpHeaders } from 'http';\n\nexport function getHeadersToStore(\n ctx: Context,\n cacheHeaders: boolean,\n cacheHeadersAllowList: string[] = [],\n cacheHeadersDenyList: string[] = []\n): OutgoingHttpHeaders | null {\n let headersToStore: OutgoingHttpHeaders | null = null;\n\n if (cacheHeaders) {\n let headers = ctx.response.headers;\n\n if (cacheHeadersAllowList.length) {\n headers = Object.fromEntries(\n Object.entries(headers).filter(([key]) => cacheHeadersAllowList.includes(key.toLowerCase()))\n );\n }\n\n if (cacheHeadersDenyList.length) {\n headers = Object.fromEntries(\n Object.entries(headers).filter(([key]) => !cacheHeadersDenyList.includes(key.toLowerCase()))\n );\n }\n\n headersToStore = headers;\n }\n\n return headersToStore;\n}\n\nexport function getCacheHeaderConfig() {\n const cacheHeaders = strapi.plugin('strapi-cache').config('cacheHeaders') as boolean;\n const cacheHeadersDenyList = strapi\n .plugin('strapi-cache')\n .config('cacheHeadersDenyList') as string[];\n const cacheHeadersAllowList = strapi\n .plugin('strapi-cache')\n .config('cacheHeadersAllowList') as string[];\n const cacheAuthorizedRequests = strapi\n .plugin('strapi-cache')\n .config('cacheAuthorizedRequests') as boolean;\n\n return {\n cacheHeaders,\n cacheHeadersDenyList,\n cacheHeadersAllowList,\n cacheAuthorizedRequests,\n };\n}\n","import { Context } from 'koa';\nimport { generateCacheKey } from '../utils/key';\nimport { CacheService } from '../../src/types/cache.types';\nimport { loggy } from '../utils/log';\nimport Stream from 'stream';\nimport { decodeBufferToText, decompressBuffer, streamToBuffer } from '../utils/body';\nimport { getCacheHeaderConfig, getHeadersToStore } from '../utils/header';\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 excludeRoutes = strapi.plugin('strapi-cache').config('excludeRoutes') as string[];\n const { cacheHeaders, cacheHeadersDenyList, cacheHeadersAllowList, cacheAuthorizedRequests } =\n getCacheHeaderConfig();\n const cacheStore = cacheService.getCacheInstance();\n const { url } = ctx.request;\n const key = generateCacheKey(ctx);\n const cacheEntry = await cacheStore.get(key);\n const cacheControlHeader = ctx.request.headers['cache-control'];\n const noCache = cacheControlHeader && cacheControlHeader.includes('no-cache');\n const restApiPrefix = strapi.config.get('api.rest.prefix', '/api');\n\n const routeIsExcluded = excludeRoutes.some((route) => url.startsWith(route));\n \n if (routeIsExcluded) {\n loggy.info(`Route excluded from cache: ${url}`);\n await next();\n return;\n }\n\n const routeIsCachable =\n cacheableRoutes.some((route) => url.startsWith(route)) ||\n (cacheableRoutes.length === 0 && url.startsWith(restApiPrefix));\n\n const authorizationHeader = ctx.request.headers['authorization'];\n\n if (authorizationHeader && !cacheAuthorizedRequests) {\n loggy.info(`Authorized request bypassing cache: ${key}`);\n await next();\n return;\n }\n\n const middlewaresConfig = strapi.config.get('middlewares') as any[];\n const corsMiddleware = middlewaresConfig.find((mw: any) => mw.name === 'strapi::cors');\n\n const corsConfig = corsMiddleware?.config;\n const origin = ctx?.request?.headers?.origin;\n let allowedOrigins = corsConfig?.origin ?? '*';\n\n if (typeof allowedOrigins === 'string') {\n allowedOrigins = [allowedOrigins];\n }\n\n if (cacheEntry && !noCache) {\n loggy.info(`HIT with key: ${key}`);\n ctx.status = 200;\n ctx.body = cacheEntry.body;\n\n if (cacheHeaders) {\n ctx.set(cacheEntry.headers);\n }\n\n if (corsMiddleware) {\n loggy.info('CORS middleware is set, checking allowed origins');\n if (allowedOrigins.includes(origin)) {\n loggy.info(`Setting Access-Control-Allow-Origin to ${origin}`);\n ctx.set('Access-Control-Allow-Origin', origin);\n } else if (typeof origin === 'undefined' || allowedOrigins.includes('*')) {\n loggy.info('No origin header or * in allowed origins, setting to *');\n ctx.set('Access-Control-Allow-Origin', '*');\n }\n } else {\n loggy.info('No CORS middleware set, setting to request origin or *');\n ctx.set('Access-Control-Allow-Origin', ctx.request.headers.origin || '*');\n }\n\n return;\n }\n\n await next();\n\n if (ctx.method === 'GET' && ctx.status >= 200 && ctx.status < 300 && routeIsCachable) {\n loggy.info(`MISS with key: ${key}`);\n const headersToStore = getHeadersToStore(\n ctx,\n cacheHeaders,\n cacheHeadersAllowList,\n cacheHeadersDenyList\n );\n\n let setCache = true;\n\n if (corsMiddleware) {\n if (allowedOrigins.includes(origin)) {\n //do nothing as the origin is allowed\n } else if (typeof origin === 'undefined' || allowedOrigins.includes('*')) {\n //do nothing as the origin is undefined (POSTMAN) or allowedOrigins includes '*'\n } else {\n setCache = false;\n }\n }\n\n if (ctx.body instanceof Stream) {\n const buf = await streamToBuffer(ctx.body);\n const contentEncoding = ctx.response.headers['content-encoding'];\n const decompressed = await decompressBuffer(buf, contentEncoding);\n const responseText = decodeBufferToText(decompressed);\n if (setCache) {\n await cacheStore.set(key, { body: responseText, headers: headersToStore });\n }\n ctx.body = buf;\n } else {\n if (setCache) {\n await cacheStore.set(key, { body: ctx.body, headers: headersToStore });\n }\n }\n }\n};\n\nexport default middleware;\n","import rawBody from 'raw-body';\nimport { generateGraphqlCacheKey } from '../utils/key';\nimport Stream, { Readable } from 'stream';\nimport { loggy } from '../utils/log';\nimport { CacheService } from '../types/cache.types';\nimport { decodeBufferToText, decompressBuffer, streamToBuffer } from '../utils/body';\nimport { getCacheHeaderConfig, getHeadersToStore } from '../utils/header';\n\nconst middleware = async (ctx: any, next: any) => {\n const cacheService = strapi.plugin('strapi-cache').services.service as CacheService;\n const { cacheHeaders, cacheHeadersDenyList, cacheHeadersAllowList, cacheAuthorizedRequests } =\n getCacheHeaderConfig();\n const cacheStore = cacheService.getCacheInstance();\n const { url } = ctx.request;\n\n const originalReq = ctx.req;\n const bodyBuffer = await rawBody(originalReq);\n const body = bodyBuffer.toString();\n\n const clonedReq = new Readable();\n clonedReq.push(bodyBuffer);\n clonedReq.push(null);\n\n (clonedReq as any).headers = { ...originalReq.headers };\n (clonedReq as any).method = originalReq.method;\n (clonedReq as any).url = originalReq.url;\n (clonedReq as any).httpVersion = originalReq.httpVersion;\n (clonedReq as any).socket = originalReq.socket;\n (clonedReq as any).connection = originalReq.connection;\n\n ctx.req = clonedReq;\n ctx.request.req = clonedReq;\n\n const isIntrospectionQuery = body.includes('IntrospectionQuery');\n if (isIntrospectionQuery) {\n loggy.info('Skipping cache for introspection query');\n await next();\n return;\n }\n\n const key = generateGraphqlCacheKey(body);\n const cacheEntry = await cacheStore.get(key);\n const cacheControlHeader = ctx.request.headers['cache-control'];\n const noCache = cacheControlHeader && cacheControlHeader.includes('no-cache');\n const authorizationHeader = ctx.request.headers['authorization'];\n\n if (authorizationHeader && !cacheAuthorizedRequests) {\n loggy.info(`Authorized request bypassing cache: ${key}`);\n await next();\n return;\n }\n\n const middlewaresConfig = strapi.config.get('middlewares') as any[];\n const corsMiddleware = middlewaresConfig.find((mw: any) => mw.name === 'strapi::cors');\n\n const corsConfig = corsMiddleware?.config;\n const origin = ctx?.request?.headers?.origin;\n let allowedOrigins = corsConfig?.origin ?? '*';\n\n if (typeof allowedOrigins === 'string') {\n allowedOrigins = [allowedOrigins];\n }\n\n if (cacheEntry && !noCache) {\n loggy.info(`HIT with key: ${key}`);\n ctx.status = 200;\n ctx.body = cacheEntry.body;\n if (cacheHeaders) {\n ctx.set(cacheEntry.headers);\n }\n\n if (corsMiddleware) {\n loggy.info('CORS middleware is set, checking allowed origins');\n\n if (allowedOrigins.includes(origin)) {\n loggy.info(`Setting Access-Control-Allow-Origin to ${origin}`);\n ctx.set('Access-Control-Allow-Origin', origin);\n } else if (typeof origin === 'undefined' || allowedOrigins.includes('*')) {\n loggy.info('No origin header or * in allowed origins, setting to *');\n ctx.set('Access-Control-Allow-Origin', '*');\n }\n } else {\n loggy.info('No CORS middleware set, setting to request origin or *');\n ctx.set('Access-Control-Allow-Origin', ctx.request.headers.origin || '*');\n }\n return;\n }\n\n await next();\n\n if (\n ctx.method === 'POST' &&\n ctx.status >= 200 &&\n ctx.status < 300 &&\n url.startsWith('/graphql')\n ) {\n loggy.info(`MISS with key: ${key}`);\n const headers = ctx.request.headers;\n const authorizationHeader = headers['authorization'];\n\n if (authorizationHeader && !cacheAuthorizedRequests) {\n loggy.info(`Authorized request not caching: ${key}`);\n return;\n }\n\n const headersToStore = getHeadersToStore(\n ctx,\n cacheHeaders,\n cacheHeadersAllowList,\n cacheHeadersDenyList\n );\n\n let setCache = true;\n\n if (corsMiddleware) {\n if (allowedOrigins.includes(origin)) {\n //do nothing as the origin is allowed\n } else if (typeof origin === 'undefined' || allowedOrigins.includes('*')) {\n //do nothing as the origin is undefined (POSTMAN) or allowedOrigins includes '*'\n } else {\n setCache = false;\n }\n }\n\n if (ctx.body instanceof Stream) {\n const buf = await streamToBuffer(ctx.body);\n const contentEncoding = ctx.response.headers['content-encoding'];\n const decompressed = await decompressBuffer(buf, contentEncoding);\n const responseText = decodeBufferToText(decompressed);\n if (setCache) {\n await cacheStore.set(key, { body: responseText, headers: headersToStore });\n }\n ctx.body = buf;\n } else {\n if (setCache) {\n await cacheStore.set(key, { body: ctx.body, headers: headersToStore });\n }\n }\n }\n};\n\nexport default middleware;\n","import cache from './cache';\nimport graphql from './graphql';\n\nexport default {\n graphql,\n cache,\n};\n","import type { Core } from '@strapi/strapi';\nimport middlewares from './middlewares';\n\nconst register = ({ strapi }: { strapi: Core.Strapi }) => {\n strapi.server.use(middlewares.cache);\n strapi.server.use(middlewares.graphql);\n};\n\nexport default register;\n","export default {\n default: ({ env }) => ({\n debug: false,\n max: 1000,\n ttl: 1000 * 60 * 60,\n size: 1024 * 1024 * 10,\n allowStale: false,\n cacheableRoutes: [],\n provider: 'memory',\n excludeRoutes: [],\n redisConfig: env('REDIS_URL'),\n redisClusterNodes: [],\n redisClusterOptions: {},\n cacheHeaders: true,\n cacheHeadersDenyList: [],\n cacheHeadersAllowList: [],\n cacheAuthorizedRequests: false,\n cacheGetTimeoutInMs: 1000,\n autoPurgeCache: true,\n autoPurgeCacheOnStart: true,\n disableAdminPopups: false,\n }),\n validator: (config) => {\n if (typeof config.debug !== 'boolean') {\n throw new Error(`Invalid config: debug must be a boolean`);\n }\n if (typeof config.max !== 'number') {\n throw new Error(`Invalid config: max must be a number`);\n }\n if (typeof config.ttl !== 'number') {\n throw new Error(`Invalid config: ttl must be a number`);\n }\n if (typeof config.size !== 'number') {\n throw new Error(`Invalid config: size must be a number`);\n }\n if (typeof config.allowStale !== 'boolean') {\n throw new Error(`Invalid config: allowStale must be a boolean`);\n }\n if (\n !Array.isArray(config.cacheableRoutes) ||\n config.cacheableRoutes.some((item) => typeof item !== 'string')\n ) {\n throw new Error(`Invalid config: cacheableRoutes must be an string array`);\n }\n if (\n !Array.isArray(config.excludeRoutes) ||\n config.excludeRoutes.some((item) => typeof item !== 'string')\n ) {\n throw new Error(`Invalid config: excludeRoutes must be a 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') {\n if (!config.redisConfig) {\n throw new Error(`Invalid config: redisConfig must be set when using redis provider`);\n }\n if (typeof config.redisConfig !== 'string' && typeof config.redisConfig !== 'object') {\n throw new Error(\n `Invalid config: redisConfig must be a string or object when using redis provider`\n );\n }\n if (\n !Array.isArray(config.redisClusterNodes) ||\n config.redisClusterNodes.some((item) => !('host' in item && 'port' in item))\n ) {\n throw new Error(\n `Invalid config: redisClusterNodes must be as a list of objects with keys 'host' and 'port'`\n );\n }\n if (typeof config.redisClusterOptions !== 'object') {\n throw new Error(`Invalid config: redisClusterOptions must be an object`);\n }\n }\n if (typeof config.cacheHeaders !== 'boolean') {\n throw new Error(`Invalid config: cacheHeaders must be a boolean`);\n }\n if (\n !Array.isArray(config.cacheHeadersDenyList) ||\n config.cacheHeadersDenyList.some((item) => typeof item !== 'string')\n ) {\n throw new Error(`Invalid config: cacheHeadersDenyList must be an string array`);\n }\n if (\n !Array.isArray(config.cacheHeadersAllowList) ||\n config.cacheHeadersAllowList.some((item) => typeof item !== 'string')\n ) {\n throw new Error(`Invalid config: cacheHeadersAllowList must be an string array`);\n }\n if (typeof config.cacheAuthorizedRequests !== 'boolean') {\n throw new Error(`Invalid config: cacheAuthorizedRequests must be a boolean`);\n }\n if (typeof config.cacheGetTimeoutInMs !== 'number') {\n throw new Error(`Invalid config: cacheGetTimeoutInMs must be a number`);\n }\n if (typeof config.autoPurgeCache !== 'boolean') {\n throw new Error(`Invalid config: autoPurgeCache must be a boolean`);\n }\n if (typeof config.autoPurgeCacheOnStart !== 'boolean') {\n throw new Error(`Invalid config: autoPurgeCacheOnStart must be a boolean`);\n }\n if (typeof config.disableAdminPopups !== 'boolean') {\n throw new Error(`Invalid config: disableAdminPopups must be a boolean`);\n }\n },\n};\n","export default {};\n","import type { Core } from '@strapi/strapi';\nimport { Context } from 'koa';\nimport { CacheService } from 'src/types/cache.types';\n\ninterface PluginConfig {\n cacheableRoutes: string[];\n disableAdminPopups: boolean;\n}\n\nconst controller = ({ strapi }: { strapi: Core.Strapi }) => ({\n async purgeCache(ctx: Context) {\n const service = strapi.plugin('strapi-cache').service('service') as CacheService;\n\n await service.getCacheInstance().reset();\n\n ctx.body = {\n message: 'Cache purged successfully',\n };\n },\n async purgeCacheByKey(ctx: Context) {\n const { key } = ctx.request.body as { key?: string };\n\n if (!key || typeof key !== 'string' || key.trim() === '') {\n ctx.status = 400;\n ctx.body = {\n error: 'Key is required and must be a non-empty string',\n };\n return;\n }\n\n const service = strapi.plugin('strapi-cache').service('service') as CacheService;\n const escapeRegExp = (s: string) => s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const regex = new RegExp(escapeRegExp(key));\n\n await service.getCacheInstance().clearByRegexp([regex]);\n\n ctx.body = {\n message: `Cache purged successfully for key: ${key}`,\n };\n },\n async config(ctx: Context) {\n try {\n // construct config object with only the properties needed by admin\n const config: PluginConfig = {\n cacheableRoutes: strapi.plugin('strapi-cache').config('cacheableRoutes') ?? [],\n disableAdminPopups: strapi.plugin('strapi-cache').config('disableAdminPopups') ?? false,\n };\n\n ctx.body = config;\n } catch (error) {\n console.error('Error constructing config:', error);\n ctx.status = 500;\n ctx.body = { error: 'Configuration not available' };\n }\n },\n});\n\nexport default controller;\n","import controller from './controller';\n\nexport default {\n controller,\n};\n","export default {};\n","export default [\n {\n method: 'POST',\n path: '/purge-cache',\n handler: 'controller.purgeCache',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: {\n actions: ['plugin::strapi-cache.purge-cache'],\n },\n },\n ],\n },\n },\n {\n method: 'POST',\n path: '/purge-cache/key',\n handler: 'controller.purgeCacheByKey',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: {\n actions: ['plugin::strapi-cache.purge-cache'],\n },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/config',\n handler: 'controller.config',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: {\n actions: ['plugin::strapi-cache.purge-cache'],\n },\n },\n ],\n },\n },\n];\n","import purgeRoute from './purge';\n\nconst routes = {\n 'purge-route': {\n type: 'admin',\n routes: purgeRoute,\n },\n};\n\nexport default routes;\n","export const withTimeout = (callback: () => Promise<any>, ms: number) => {\n let timeout: NodeJS.Timeout | null = null;\n\n return Promise.race([\n callback().then((result) => {\n if (timeout) {\n clearTimeout(timeout);\n }\n return result;\n }),\n new Promise((_, reject) => {\n timeout = setTimeout(() => {\n reject(new Error('timeout'));\n }, ms);\n }),\n ]);\n};\n","import type { Core } from '@strapi/strapi';\nimport { LRUCache } from 'lru-cache';\nimport { withTimeout } from '../../utils/withTimeout';\nimport { CacheProvider, CacheService } from '../../types/cache.types';\nimport { loggy } from '../../utils/log';\n\nexport class InMemoryCacheProvider implements CacheProvider {\n private initialized = false;\n private provider!: LRUCache<string, any>;\n private cacheGetTimeoutInMs: number;\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 this.cacheGetTimeoutInMs = Number(\n this.strapi.plugin('strapi-cache').config('cacheGetTimeoutInMs')\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 return withTimeout(\n () =>\n new Promise((resolve) => {\n resolve(this.provider.get(key));\n }),\n this.cacheGetTimeoutInMs\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, Cluster, ClusterNode, ClusterOptions } 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 | Cluster;\n private cacheGetTimeoutInMs: number;\n private keyPrefix: string;\n\n constructor(private strapi: Core.Strapi) {}\n\n init(): void {\n if (this.initialized) {\n loggy.error('Redis provider already initialized');\n return;\n }\n try {\n const redisConfig =\n this.strapi.plugin('strapi-cache').config('redisConfig') || 'redis://localhost:6379';\n const redisClusterNodes: ClusterNode[] = this.strapi\n .plugin('strapi-cache')\n .config('redisClusterNodes');\n this.cacheGetTimeoutInMs = Number(\n this.strapi.plugin('strapi-cache').config('cacheGetTimeoutInMs')\n );\n this.keyPrefix =\n (this.strapi.plugin('strapi-cache').config('redisConfig')?.['keyPrefix'] as\n | string\n | undefined) ?? '';\n if (redisClusterNodes.length) {\n const redisClusterOptions: ClusterOptions = this.strapi\n .plugin('strapi-cache')\n .config('redisClusterOptions');\n if (!redisClusterOptions['redisOptions']) {\n redisClusterOptions.redisOptions = redisConfig;\n }\n this.client = new Redis.Cluster(redisClusterNodes, redisClusterOptions);\n } else {\n this.client = new Redis(redisConfig);\n }\n this.initialized = true;\n\n loggy.info('Redis provider initialized');\n } catch (error) {\n loggy.error(error);\n }\n }\n\n get ready(): boolean {\n if (!this.initialized) {\n loggy.info('Redis provider not initialized');\n return false;\n }\n\n return true;\n }\n\n async get(key: string): Promise<any | null> {\n if (!this.ready) return null;\n\n return withTimeout(() => this.client.get(key), this.cacheGetTimeoutInMs)\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 // plugin ttl is ms, ioredis ttl is s, so we convert here\n const ttlInMs = Number(this.strapi.plugin('strapi-cache').config('ttl'));\n const ttlInS = Number((ttlInMs / 1000).toFixed());\n const serialized = JSON.stringify(val);\n if (ttlInS > 0) {\n await this.client.set(key, serialized, 'EX', ttlInS);\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 const relativeKey = key.slice(this.keyPrefix.length);\n loggy.info(`Redis PURGING KEY: ${relativeKey}`);\n await this.client.del(relativeKey);\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(`${this.keyPrefix}*`);\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 if (this.keyPrefix) {\n loggy.info(`Redis FLUSHING NAMESPACE: ${this.keyPrefix}`);\n const keys = await this.keys();\n if (!keys) return null;\n\n const toDelete = keys.filter((key) => key.startsWith(this.keyPrefix));\n await Promise.all(toDelete.map((key) => this.del(key)));\n return true;\n }\n\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\n loggy.info(JSON.stringify(keys));\n if (!keys) return;\n\n const toDelete = keys.filter((key) => regExps.some((re) => re.test(key)));\n loggy.info(JSON.stringify(toDelete));\n await Promise.all(toDelete.map((key) => this.del(key)));\n }\n}\n","import type { Core } from '@strapi/strapi';\nimport { InMemoryCacheProvider } from './memory/provider';\nimport { RedisCacheProvider } from './redis/provider';\nimport { CacheProvider } from '../../src/types/cache.types';\nimport { loggy } from '../../src/utils/log';\n\nexport const resolveCacheProvider = (strapi: Core.Strapi): CacheProvider => {\n const providerType = strapi.plugin('strapi-cache').config('provider') || 'memory';\n\n loggy.info(`Selected cache provider: ${providerType}`);\n\n let instance: CacheProvider;\n\n switch (providerType) {\n case 'redis':\n instance = new RedisCacheProvider(strapi);\n break;\n default:\n instance = new InMemoryCacheProvider(strapi);\n break;\n }\n\n return instance;\n};\n","import type { Core } from '@strapi/strapi';\nimport { resolveCacheProvider } from './resolver';\nimport { CacheProvider, CacheService } from '../../src/types/cache.types';\nimport { loggy } from '../../src/utils/log';\n\nconst service = ({ strapi }: { strapi: Core.Strapi }): CacheService => {\n let instance: null | CacheProvider = null;\n\n return {\n getCacheInstance() {\n if (!instance) {\n loggy.info('Initializing cache service from provider config...');\n instance = resolveCacheProvider(strapi);\n }\n return instance;\n },\n };\n};\n\nexport default {\n service,\n};\n","/**\n * Application methods\n */\nimport bootstrap from './bootstrap';\nimport register from './register';\n\n/**\n * Plugin server methods\n */\nimport config from './config';\nimport contentTypes from './content-types';\nimport controllers from './controllers';\nimport middlewares from './middlewares';\nimport policies from './policies';\nimport routes from './routes';\nimport services from './services';\n\nexport default {\n register,\n bootstrap,\n destroy() {},\n config,\n controllers,\n routes,\n services,\n contentTypes,\n policies,\n middlewares,\n};\n"],"names":["strapi","middleware","authorizationHeader","graphql","cache","config","service"],"mappings":"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"}