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 +3 -1
- package/dist/_chunks/{de-Dihl3Ias.mjs → de-C_gFyhHL.mjs} +1 -1
- package/dist/_chunks/{de-BABI25Ju.js → de-l6MDDAXu.js} +1 -1
- package/dist/_chunks/{en-DYulQU0k.js → en-D9w03LyX.js} +1 -1
- package/dist/_chunks/{en-CLhkAQFN.mjs → en-bK2OKwtN.mjs} +1 -1
- package/dist/_chunks/{index-BS9N2eCV.mjs → index-BInrGFOe.mjs} +6 -5
- package/dist/_chunks/{index-7Lm6jbM0.js → index-BjBoZhpS.js} +6 -5
- package/dist/_chunks/{index-dynpWXaG.mjs → index-BwjcxGep.mjs} +54 -9
- package/dist/_chunks/{index-BJj5EZfj.js → index-Dwrl1jfJ.js} +54 -9
- package/dist/admin/index.js +1 -2
- package/dist/admin/index.mjs +1 -2
- package/dist/admin/src/components/PurgeModal/index.d.ts +2 -1
- package/dist/admin/src/hooks/useCacheOperations.d.ts +1 -0
- package/dist/server/index.js +12 -10
- package/dist/server/index.mjs +12 -10
- package/dist/server/src/utils/invalidateCache.d.ts +1 -1
- package/package.json +1 -1
- package/dist/_chunks/de-BABI25Ju.js.map +0 -1
- package/dist/_chunks/de-Dihl3Ias.mjs.map +0 -1
- package/dist/_chunks/en-CLhkAQFN.mjs.map +0 -1
- package/dist/_chunks/en-DYulQU0k.js.map +0 -1
- package/dist/_chunks/index-7Lm6jbM0.js.map +0 -1
- package/dist/_chunks/index-BJj5EZfj.js.map +0 -1
- package/dist/_chunks/index-BS9N2eCV.mjs.map +0 -1
- package/dist/_chunks/index-dynpWXaG.mjs.map +0 -1
- package/dist/admin/index.js.map +0 -1
- package/dist/admin/index.mjs.map +0 -1
- package/dist/server/index.js.map +0 -1
- package/dist/server/index.mjs.map +0 -1
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
|
-
- [
|
|
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-
|
|
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: "
|
|
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-
|
|
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: "
|
|
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(
|
|
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-
|
|
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-
|
|
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(
|
|
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-
|
|
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-
|
|
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
|
package/dist/admin/index.js
CHANGED
package/dist/admin/index.mjs
CHANGED
|
@@ -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
|
};
|
package/dist/server/index.js
CHANGED
|
@@ -51,7 +51,7 @@ async function invalidateCache(event, cacheStore, strapi2) {
|
|
|
51
51
|
loggy.error(error);
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
-
async function invalidateGraphqlCache(
|
|
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(
|
|
88
|
+
await invalidateGraphqlCache(cacheStore);
|
|
89
89
|
},
|
|
90
90
|
async afterUpdate(event) {
|
|
91
91
|
await invalidateCache(event, cacheStore, strapi2);
|
|
92
|
-
await invalidateGraphqlCache(
|
|
92
|
+
await invalidateGraphqlCache(cacheStore);
|
|
93
93
|
},
|
|
94
94
|
async afterDelete(event) {
|
|
95
95
|
await invalidateCache(event, cacheStore, strapi2);
|
|
96
|
-
await invalidateGraphqlCache(
|
|
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
|
-
|
|
797
|
-
|
|
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
|
package/dist/server/index.mjs
CHANGED
|
@@ -47,7 +47,7 @@ async function invalidateCache(event, cacheStore, strapi2) {
|
|
|
47
47
|
loggy.error(error);
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
|
-
async function invalidateGraphqlCache(
|
|
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(
|
|
84
|
+
await invalidateGraphqlCache(cacheStore);
|
|
85
85
|
},
|
|
86
86
|
async afterUpdate(event) {
|
|
87
87
|
await invalidateCache(event, cacheStore, strapi2);
|
|
88
|
-
await invalidateGraphqlCache(
|
|
88
|
+
await invalidateGraphqlCache(cacheStore);
|
|
89
89
|
},
|
|
90
90
|
async afterDelete(event) {
|
|
91
91
|
await invalidateCache(event, cacheStore, strapi2);
|
|
92
|
-
await invalidateGraphqlCache(
|
|
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
|
-
|
|
793
|
-
|
|
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(
|
|
4
|
+
export declare function invalidateGraphqlCache(cacheStore: CacheProvider): Promise<void>;
|
package/package.json
CHANGED
|
@@ -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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"}
|
package/dist/admin/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
|
package/dist/admin/index.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
package/dist/server/index.js.map
DELETED
|
@@ -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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"}
|