strapi-cache 1.5.7-rc.2 → 1.5.7
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 +1 -28
- package/dist/_chunks/de-Bw-yMVQV.js +1 -0
- package/dist/_chunks/de-Bw-yMVQV.js.map +1 -0
- package/dist/_chunks/de-OlWEMza0.mjs +1 -0
- package/dist/_chunks/de-OlWEMza0.mjs.map +1 -0
- package/dist/_chunks/en-3qeM6Pow.js +1 -0
- package/dist/_chunks/en-3qeM6Pow.js.map +1 -0
- package/dist/_chunks/en-CFA1lEXn.mjs +1 -0
- package/dist/_chunks/en-CFA1lEXn.mjs.map +1 -0
- package/dist/admin/index.js +6 -1
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/index.mjs +6 -1
- package/dist/admin/index.mjs.map +1 -0
- package/dist/admin/src/components/PurgeEntityButton/index.d.ts +1 -1
- package/dist/server/index.js +67 -4
- package/dist/server/index.js.map +1 -0
- package/dist/server/index.mjs +67 -4
- package/dist/server/index.mjs.map +1 -0
- package/dist/server/src/config/index.d.ts +1 -0
- package/dist/server/src/index.d.ts +1 -0
- package/dist/server/src/services/redis/provider.d.ts +1 -0
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -60,6 +60,7 @@ In your Strapi project, navigate to `config/plugins.js` and add the following co
|
|
|
60
60
|
cacheAuthorizedRequests: false, // Cache requests with authorization headers (set to true if you want to cache authorized requests)
|
|
61
61
|
cacheGetTimeoutInMs: 1000, // Timeout for getting cached data in milliseconds (default is 1 second)
|
|
62
62
|
autoPurgeCache: true, // Automatically purge cache on content CRUD operations
|
|
63
|
+
autoPurgeCacheOnStart: true, // Automatically purge cache on Strapi startup
|
|
63
64
|
},
|
|
64
65
|
},
|
|
65
66
|
```
|
|
@@ -95,34 +96,6 @@ All of these routes are protected by the policies `admin::isAuthenticatedAdmin`
|
|
|
95
96
|
|
|
96
97
|
If you encounter any issues, please feel free to open an issue on the [GitHub repo](https://github.com/TupiC/strapi-cache/issues/new).
|
|
97
98
|
|
|
98
|
-
## 🛠️ Troubleshooting
|
|
99
|
-
|
|
100
|
-
If you encounter an error like:
|
|
101
|
-
|
|
102
|
-
```
|
|
103
|
-
Access to fetch at 'http://your-backend.com' from origin 'http://your-origin.com' has been blocked by CORS policy:
|
|
104
|
-
Request header field cache-control is not allowed by Access-Control-Allow-Headers in preflight response.
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
You might need to adjust your CORS middleware settings in Strapi:
|
|
108
|
-
|
|
109
|
-
```javascript
|
|
110
|
-
// config/middlewares.{js,ts}
|
|
111
|
-
'strapi::cors';
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
with:
|
|
115
|
-
|
|
116
|
-
```javascript
|
|
117
|
-
// config/middlewares.{js,ts}
|
|
118
|
-
{
|
|
119
|
-
name: "strapi::cors",
|
|
120
|
-
config: {
|
|
121
|
-
headers: ["Content-Type", "Authorization", "Cache-Control"], // Add 'Cache-Control' to the allowed headers
|
|
122
|
-
},
|
|
123
|
-
},
|
|
124
|
-
```
|
|
125
|
-
|
|
126
99
|
## 🛠️ Contributing
|
|
127
100
|
|
|
128
101
|
Contributions are welcome! If you have suggestions or improvements, please open an issue or submit a pull request.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"de-Bw-yMVQV.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"de-OlWEMza0.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"en-3qeM6Pow.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"en-CFA1lEXn.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;"}
|
package/dist/admin/index.js
CHANGED
|
@@ -161,7 +161,11 @@ function PurgeCacheButton() {
|
|
|
161
161
|
function PurgeEntityButton() {
|
|
162
162
|
const { formatMessage } = reactIntl.useIntl();
|
|
163
163
|
const { id, isSingleType, contentType } = admin.unstable_useContentManagerContext();
|
|
164
|
-
const
|
|
164
|
+
const apiPath = isSingleType ? contentType?.info.singularName : id;
|
|
165
|
+
if (!apiPath) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
const keyToUse = encodeURIComponent(apiPath);
|
|
165
169
|
const contentTypeName = isSingleType ? contentType?.info.singularName : contentType?.info.pluralName;
|
|
166
170
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
167
171
|
PurgeModal,
|
|
@@ -207,3 +211,4 @@ const index = {
|
|
|
207
211
|
}
|
|
208
212
|
};
|
|
209
213
|
module.exports = index;
|
|
214
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../admin/src/pluginId.ts","../../admin/src/components/Initializer.tsx","../../admin/src/permission.ts","../../admin/src/components/PurgeModal/PurgeButton/index.tsx","../../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","export const pluginPermissions = {\n purge: [{ action: 'plugin::strapi-cache.purge-cache', subject: null }],\n};\n","import { Button } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\n\nfunction PurgeButton({ onClick }: { onClick: () => void }) {\n const formatMessage = useIntl().formatMessage;\n\n return (\n <Button onClick={onClick}>\n {formatMessage({\n id: 'strapi-cache.cache.confirm',\n defaultMessage: 'Yes, confirm',\n })}\n </Button>\n );\n}\n\nexport default PurgeButton;\n","import { useIntl } from 'react-intl';\nimport { Archive } from '@strapi/icons';\nimport { Button, Modal } from '@strapi/design-system';\nimport { useNotification, useRBAC } from '@strapi/strapi/admin';\nimport { pluginPermissions } from '../../permission';\nimport { Typography } from '@strapi/design-system';\nimport { useFetchClient } from '@strapi/strapi/admin';\nimport { useEffect, useState } from 'react';\nimport PurgeButton from './PurgeButton';\n\nexport type PurgeProps = {\n buttonText: string;\n buttonWidth?: string;\n keyToUse?: string;\n contentTypeName?: string;\n};\n\nfunction PurgeModal({ buttonText, keyToUse, buttonWidth, contentTypeName }: PurgeProps) {\n const { allowedActions } = useRBAC(pluginPermissions);\n const formatMessage = useIntl().formatMessage;\n const { post, get } = useFetchClient();\n const { toggleNotification } = useNotification();\n const [cacheableRoutes, setCacheableRoutes] = useState<string[]>();\n\n useEffect(() => {\n if (!allowedActions.canPurgeCache) {\n return;\n }\n const fetchCacheableRoutes = async () => {\n try {\n const { data } = await get('/strapi-cache/cacheable-routes');\n return data;\n } catch (error) {\n toggleNotification({\n type: 'warning',\n message: formatMessage({\n id: 'strapi-cache.cache.routes.fetch-error',\n defaultMessage: 'Unable to fetch cacheable routes. Cache purge may not work correctly.',\n }),\n });\n return undefined;\n }\n };\n fetchCacheableRoutes().then((data) => {\n setCacheableRoutes(data);\n });\n }, [allowedActions.canPurgeCache]);\n\n const isCacheableRoute = () => {\n if (!keyToUse || !cacheableRoutes) {\n return false;\n }\n\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 = () => {\n if (!keyToUse) {\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 return;\n }\n\n post(`/strapi-cache/purge-cache/${keyToUse}`, undefined, {\n headers: {\n 'Content-Type': 'application/json',\n },\n })\n .then(() => {\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: `\"${keyToUse}\"`,\n }\n ),\n });\n })\n .catch(() => {\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: `\"${keyToUse}\"`,\n }\n ),\n });\n });\n };\n\n if (!allowedActions.canPurgeCache || !isCacheableRoute()) {\n return null;\n }\n\n return (\n <Modal.Root>\n <Modal.Trigger>\n <Button width={buttonWidth} 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 <PurgeButton onClick={clearCache}></PurgeButton>\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\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","useIntl","jsx","Button","useRBAC","useFetchClient","useNotification","useState","jsxs","Modal","Archive","Typography","useContentManagerContext"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAO,MAAM,YAAY;ACQzB,MAAM,cAAc,CAAC,EAAE,gBAAkC;AACjD,QAAA,MAAMA,aAAO,SAAS;AAE5BC,QAAAA,UAAU,MAAM;AACd,QAAI,QAAQ,SAAS;AAAA,EACvB,GAAG,EAAE;AAEE,SAAA;AACT;AChBO,MAAM,oBAAoB;AAAA,EAC/B,OAAO,CAAC,EAAE,QAAQ,oCAAoC,SAAS,KAAM,CAAA;AACvE;ACCA,SAAS,YAAY,EAAE,WAAoC;AACnD,QAAA,gBAAgBC,oBAAU;AAG9B,SAAAC,2BAAA,IAACC,aAAO,QAAA,EAAA,SACL,UAAc,cAAA;AAAA,IACb,IAAI;AAAA,IACJ,gBAAgB;AAAA,EACjB,CAAA,GACH;AAEJ;ACGA,SAAS,WAAW,EAAE,YAAY,UAAU,aAAa,mBAA+B;AACtF,QAAM,EAAE,eAAA,IAAmBC,MAAA,QAAQ,iBAAiB;AAC9C,QAAA,gBAAgBH,oBAAU;AAChC,QAAM,EAAE,MAAM,IAAI,IAAII,qBAAe;AAC/B,QAAA,EAAE,mBAAmB,IAAIC,sBAAgB;AAC/C,QAAM,CAAC,iBAAiB,kBAAkB,IAAIC,eAAmB;AAEjEP,QAAAA,UAAU,MAAM;AACV,QAAA,CAAC,eAAe,eAAe;AACjC;AAAA,IAAA;AAEF,UAAM,uBAAuB,YAAY;AACnC,UAAA;AACF,cAAM,EAAE,KAAA,IAAS,MAAM,IAAI,gCAAgC;AACpD,eAAA;AAAA,eACA,OAAO;AACK,2BAAA;AAAA,UACjB,MAAM;AAAA,UACN,SAAS,cAAc;AAAA,YACrB,IAAI;AAAA,YACJ,gBAAgB;AAAA,UACjB,CAAA;AAAA,QAAA,CACF;AACM,eAAA;AAAA,MAAA;AAAA,IAEX;AACqB,yBAAA,EAAE,KAAK,CAAC,SAAS;AACpC,yBAAmB,IAAI;AAAA,IAAA,CACxB;AAAA,EAAA,GACA,CAAC,eAAe,aAAa,CAAC;AAEjC,QAAM,mBAAmB,MAAM;AACzB,QAAA,CAAC,YAAY,CAAC,iBAAiB;AAC1B,aAAA;AAAA,IAAA;AAGT,WACE,gBAAgB,WAAW,KAC3B,gBAAgB,KAAK,CAAC,UAAU;AAC9B,aAAO,MAAM,SAAS,QAAQ,KAAM,mBAAmB,MAAM,SAAS,eAAe;AAAA,IAAA,CACtF;AAAA,EAEL;AAEA,QAAM,aAAa,MAAM;AACvB,QAAI,CAAC,UAAU;AACM,yBAAA;AAAA,QACjB,MAAM;AAAA,QACN,SAAS,cAAc;AAAA,UACrB,IAAI;AAAA,UACJ,gBAAgB;AAAA,QACjB,CAAA;AAAA,MAAA,CACF;AACD;AAAA,IAAA;AAGG,SAAA,6BAA6B,QAAQ,IAAI,QAAW;AAAA,MACvD,SAAS;AAAA,QACP,gBAAgB;AAAA,MAAA;AAAA,IAClB,CACD,EACE,KAAK,MAAM;AACS,yBAAA;AAAA,QACjB,MAAM;AAAA,QACN,SAAS;AAAA,UACP;AAAA,YACE,IAAI;AAAA,YACJ,gBAAgB;AAAA,UAClB;AAAA,UACA;AAAA,YACE,KAAK,IAAI,QAAQ;AAAA,UAAA;AAAA,QACnB;AAAA,MACF,CACD;AAAA,IAAA,CACF,EACA,MAAM,MAAM;AACQ,yBAAA;AAAA,QACjB,MAAM;AAAA,QACN,SAAS;AAAA,UACP;AAAA,YACE,IAAI;AAAA,YACJ,gBAAgB;AAAA,UAClB;AAAA,UACA;AAAA,YACE,KAAK,IAAI,QAAQ;AAAA,UAAA;AAAA,QACnB;AAAA,MACF,CACD;AAAA,IAAA,CACF;AAAA,EACL;AAEA,MAAI,CAAC,eAAe,iBAAiB,CAAC,oBAAoB;AACjD,WAAA;AAAA,EAAA;AAIP,SAAAQ,gCAACC,aAAAA,MAAM,MAAN,EACC,UAAA;AAAA,IAAAP,+BAACO,aAAAA,MAAM,SAAN,EACC,UAAAP,2BAAAA,IAACC,uBAAO,OAAO,aAAa,WAAWD,+BAACQ,MAAAA,SAAQ,CAAA,CAAA,GAAI,SAAQ,UACzD,qBACH,CAAA,GACF;AAAA,IACAF,2BAAAA,KAACC,aAAM,MAAA,SAAN,EACC,UAAA;AAAA,MAACP,2BAAAA,IAAAO,aAAA,MAAM,QAAN,EACC,UAAAP,2BAAA,IAACO,mBAAM,OAAN,EAAa,sBAAW,EAC3B,CAAA;AAAA,qCACCA,aAAM,MAAA,MAAN,EACC,UAACP,2BAAAA,IAAAS,aAAA,YAAA,EAAW,SAAQ,SACjB,UAAA;AAAA,QACC;AAAA,UACE,IAAI;AAAA,UACJ,gBAAgB;AAAA,QAClB;AAAA,QACA,EAAE,KAAK,IAAI,QAAQ,IAAI;AAAA,SAE3B,EACF,CAAA;AAAA,MACAH,2BAAAA,KAACC,aAAM,MAAA,QAAN,EACC,UAAA;AAAA,QAAAP,2BAAAA,IAACO,mBAAM,OAAN,EACC,yCAACN,aAAO,QAAA,EAAA,SAAQ,YACb,UAAc,cAAA;AAAA,UACb,IAAI;AAAA,UACJ,gBAAgB;AAAA,QAAA,CACjB,GACH,EACF,CAAA;AAAA,QACAD,+BAACO,aAAAA,MAAM,OAAN,EACC,yCAAC,aAAY,EAAA,SAAS,YAAY,EACpC,CAAA;AAAA,MAAA,EACF,CAAA;AAAA,IAAA,EACF,CAAA;AAAA,EAAA,GACF;AAEJ;AClJA,SAAS,mBAAmB;AACpB,QAAA,EAAE,YAAY,IAAIG,wCAAyB;AAC3C,QAAA,EAAE,cAAc,IAAIX,kBAAQ;AAC5B,QAAA,WAAW,aAAa,KAAK;AAGjC,SAAAC,2BAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,YAAY,cAAc;AAAA,QACxB,IAAI;AAAA,QACJ,gBAAgB;AAAA,MAAA,CACjB;AAAA,MACD;AAAA,IAAA;AAAA,EACD;AAEL;ACdA,SAAS,oBAAoB;AACrB,QAAA,EAAE,cAAc,IAAID,kBAAQ;AAClC,QAAM,EAAE,IAAI,cAAc,YAAA,IAAgBW,MAAAA,kCAAyB;AACnE,QAAM,UAAU,eAAe,aAAa,KAAK,eAAe;AAEhE,MAAI,CAAC,SAAS;AACL,WAAA;AAAA,EAAA;AAGH,QAAA,WAAW,mBAAmB,OAAO;AAC3C,QAAM,kBAAkB,eACpB,aAAa,KAAK,eAClB,aAAa,KAAK;AAGpB,SAAAV,2BAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAY;AAAA,MACZ,YAAY,cAAc;AAAA,QACxB,IAAI;AAAA,QACJ,gBAAgB;AAAA,MAAA,CACjB;AAAA,MACD;AAAA,MACA;AAAA,IAAA;AAAA,EACD;AAEL;ACxBA,MAAe,QAAA;AAAA,EACb,SAAS,KAAU;AACjB,QAAI,eAAe;AAAA,MACjB,IAAI;AAAA,MACJ,aAAa;AAAA,MACb,SAAS;AAAA,MACT,MAAM;AAAA,IAAA,CACP;AAED,QAAI,UAAU,iBAAiB,EAAE,gBAAgB,YAAY,WAAW;AAAA,MACtE,MAAM;AAAA,MACN,WAAW;AAAA,IAAA,CACZ;AAED,QAAI,UAAU,iBAAiB,EAAE,gBAAgB,YAAY,eAAe;AAAA,MAC1E,MAAM;AAAA,MACN,WAAW;AAAA,IAAA,CACZ;AAAA,EACH;AAAA,EAEA,MAAM,cAAc,EAAE,WAAkC;AACtD,WAAO,QAAQ;AAAA,MACb,QAAQ,IAAI,OAAO,WAAW;AACxB,YAAA;AACF,gBAAM,EAAE,SAAS,KAAA,IAAS,MAAM,qCAAA,uBAAA,OAAA,EAAA,0BAAA,MAAA,QAAA,QAAA,EAAA,KAAA,MAAA,QAAA,2BAAA,CAAA,GAAA,0BAAA,MAAA,qCAAA,2BAAA,CAAA,EAAA,CAAA,GAAA,kBAAA,MAAA,SAAA,CAAA;AAEzB,iBAAA,EAAE,MAAM,OAAO;AAAA,QAAA,QAChB;AACN,iBAAO,EAAE,MAAM,CAAC,GAAG,OAAO;AAAA,QAAA;AAAA,MAE7B,CAAA;AAAA,IACH;AAAA,EAAA;AAEJ;;"}
|
package/dist/admin/index.mjs
CHANGED
|
@@ -160,7 +160,11 @@ function PurgeCacheButton() {
|
|
|
160
160
|
function PurgeEntityButton() {
|
|
161
161
|
const { formatMessage } = useIntl();
|
|
162
162
|
const { id, isSingleType, contentType } = unstable_useContentManagerContext();
|
|
163
|
-
const
|
|
163
|
+
const apiPath = isSingleType ? contentType?.info.singularName : id;
|
|
164
|
+
if (!apiPath) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
const keyToUse = encodeURIComponent(apiPath);
|
|
164
168
|
const contentTypeName = isSingleType ? contentType?.info.singularName : contentType?.info.pluralName;
|
|
165
169
|
return /* @__PURE__ */ jsx(
|
|
166
170
|
PurgeModal,
|
|
@@ -208,3 +212,4 @@ const index = {
|
|
|
208
212
|
export {
|
|
209
213
|
index as default
|
|
210
214
|
};
|
|
215
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../../admin/src/pluginId.ts","../../admin/src/components/Initializer.tsx","../../admin/src/permission.ts","../../admin/src/components/PurgeModal/PurgeButton/index.tsx","../../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","export const pluginPermissions = {\n purge: [{ action: 'plugin::strapi-cache.purge-cache', subject: null }],\n};\n","import { Button } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\n\nfunction PurgeButton({ onClick }: { onClick: () => void }) {\n const formatMessage = useIntl().formatMessage;\n\n return (\n <Button onClick={onClick}>\n {formatMessage({\n id: 'strapi-cache.cache.confirm',\n defaultMessage: 'Yes, confirm',\n })}\n </Button>\n );\n}\n\nexport default PurgeButton;\n","import { useIntl } from 'react-intl';\nimport { Archive } from '@strapi/icons';\nimport { Button, Modal } from '@strapi/design-system';\nimport { useNotification, useRBAC } from '@strapi/strapi/admin';\nimport { pluginPermissions } from '../../permission';\nimport { Typography } from '@strapi/design-system';\nimport { useFetchClient } from '@strapi/strapi/admin';\nimport { useEffect, useState } from 'react';\nimport PurgeButton from './PurgeButton';\n\nexport type PurgeProps = {\n buttonText: string;\n buttonWidth?: string;\n keyToUse?: string;\n contentTypeName?: string;\n};\n\nfunction PurgeModal({ buttonText, keyToUse, buttonWidth, contentTypeName }: PurgeProps) {\n const { allowedActions } = useRBAC(pluginPermissions);\n const formatMessage = useIntl().formatMessage;\n const { post, get } = useFetchClient();\n const { toggleNotification } = useNotification();\n const [cacheableRoutes, setCacheableRoutes] = useState<string[]>();\n\n useEffect(() => {\n if (!allowedActions.canPurgeCache) {\n return;\n }\n const fetchCacheableRoutes = async () => {\n try {\n const { data } = await get('/strapi-cache/cacheable-routes');\n return data;\n } catch (error) {\n toggleNotification({\n type: 'warning',\n message: formatMessage({\n id: 'strapi-cache.cache.routes.fetch-error',\n defaultMessage: 'Unable to fetch cacheable routes. Cache purge may not work correctly.',\n }),\n });\n return undefined;\n }\n };\n fetchCacheableRoutes().then((data) => {\n setCacheableRoutes(data);\n });\n }, [allowedActions.canPurgeCache]);\n\n const isCacheableRoute = () => {\n if (!keyToUse || !cacheableRoutes) {\n return false;\n }\n\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 = () => {\n if (!keyToUse) {\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 return;\n }\n\n post(`/strapi-cache/purge-cache/${keyToUse}`, undefined, {\n headers: {\n 'Content-Type': 'application/json',\n },\n })\n .then(() => {\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: `\"${keyToUse}\"`,\n }\n ),\n });\n })\n .catch(() => {\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: `\"${keyToUse}\"`,\n }\n ),\n });\n });\n };\n\n if (!allowedActions.canPurgeCache || !isCacheableRoute()) {\n return null;\n }\n\n return (\n <Modal.Root>\n <Modal.Trigger>\n <Button width={buttonWidth} 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 <PurgeButton onClick={clearCache}></PurgeButton>\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\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":["useContentManagerContext"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare function PurgeEntityButton(): import("react/jsx-runtime").JSX.Element;
|
|
1
|
+
declare function PurgeEntityButton(): import("react/jsx-runtime").JSX.Element | null;
|
|
2
2
|
export default PurgeEntityButton;
|
package/dist/server/index.js
CHANGED
|
@@ -73,6 +73,7 @@ const bootstrap = ({ strapi: strapi2 }) => {
|
|
|
73
73
|
try {
|
|
74
74
|
const cacheService = strapi2.plugin("strapi-cache").services.service;
|
|
75
75
|
const autoPurgeCache = strapi2.plugin("strapi-cache").config("autoPurgeCache");
|
|
76
|
+
const autoPurgeCacheOnStart = strapi2.plugin("strapi-cache").config("autoPurgeCacheOnStart");
|
|
76
77
|
const cacheStore = cacheService.getCacheInstance();
|
|
77
78
|
if (!cacheStore) {
|
|
78
79
|
loggy.error("Plugin could not be initialized");
|
|
@@ -95,6 +96,13 @@ const bootstrap = ({ strapi: strapi2 }) => {
|
|
|
95
96
|
}
|
|
96
97
|
});
|
|
97
98
|
}
|
|
99
|
+
if (autoPurgeCacheOnStart) {
|
|
100
|
+
cacheStore.reset().then(() => {
|
|
101
|
+
loggy.info("Cache purged successfully");
|
|
102
|
+
}).catch((error) => {
|
|
103
|
+
loggy.error(`Error purging cache on start: ${error.message}`);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
98
106
|
} catch (error) {
|
|
99
107
|
loggy.error("Plugin could not be initialized");
|
|
100
108
|
return;
|
|
@@ -199,6 +207,26 @@ const middleware$1 = async (ctx, next) => {
|
|
|
199
207
|
ctx.body = cacheEntry.body;
|
|
200
208
|
if (cacheHeaders) {
|
|
201
209
|
ctx.set(cacheEntry.headers);
|
|
210
|
+
}
|
|
211
|
+
const middlewaresConfig = strapi.config.get("middlewares");
|
|
212
|
+
const corsMiddleware = middlewaresConfig.find((mw) => mw.name === "strapi::cors");
|
|
213
|
+
if (corsMiddleware) {
|
|
214
|
+
loggy.info("CORS middleware is set, checking allowed origins");
|
|
215
|
+
const corsConfig = corsMiddleware?.config;
|
|
216
|
+
const origin = ctx?.request?.headers?.origin;
|
|
217
|
+
let allowedOrigins = corsConfig?.origin ?? "*";
|
|
218
|
+
if (typeof allowedOrigins === "string") {
|
|
219
|
+
allowedOrigins = [allowedOrigins];
|
|
220
|
+
}
|
|
221
|
+
if (allowedOrigins.includes(origin)) {
|
|
222
|
+
loggy.info(`Setting Access-Control-Allow-Origin to ${origin}`);
|
|
223
|
+
ctx.set("Access-Control-Allow-Origin", origin);
|
|
224
|
+
} else if (typeof origin === "undefined" || allowedOrigins.includes("*")) {
|
|
225
|
+
loggy.info("No origin header or * in allowed origins, setting to *");
|
|
226
|
+
ctx.set("Access-Control-Allow-Origin", "*");
|
|
227
|
+
}
|
|
228
|
+
} else {
|
|
229
|
+
loggy.info("No CORS middleware set, setting to request origin or *");
|
|
202
230
|
ctx.set("Access-Control-Allow-Origin", ctx.request.headers.origin || "*");
|
|
203
231
|
}
|
|
204
232
|
return;
|
|
@@ -265,6 +293,26 @@ const middleware = async (ctx, next) => {
|
|
|
265
293
|
ctx.body = cacheEntry.body;
|
|
266
294
|
if (cacheHeaders) {
|
|
267
295
|
ctx.set(cacheEntry.headers);
|
|
296
|
+
}
|
|
297
|
+
const middlewaresConfig = strapi.config.get("middlewares");
|
|
298
|
+
const corsMiddleware = middlewaresConfig.find((mw) => mw.name === "strapi::cors");
|
|
299
|
+
if (corsMiddleware) {
|
|
300
|
+
loggy.info("CORS middleware is set, checking allowed origins");
|
|
301
|
+
const corsConfig = corsMiddleware?.config;
|
|
302
|
+
const origin = ctx?.request?.headers?.origin;
|
|
303
|
+
let allowedOrigins = corsConfig?.origin ?? "*";
|
|
304
|
+
if (typeof allowedOrigins === "string") {
|
|
305
|
+
allowedOrigins = [allowedOrigins];
|
|
306
|
+
}
|
|
307
|
+
if (allowedOrigins.includes(origin)) {
|
|
308
|
+
loggy.info(`Setting Access-Control-Allow-Origin to ${origin}`);
|
|
309
|
+
ctx.set("Access-Control-Allow-Origin", origin);
|
|
310
|
+
} else if (typeof origin === "undefined" || allowedOrigins.includes("*")) {
|
|
311
|
+
loggy.info("No origin header or * in allowed origins, setting to *");
|
|
312
|
+
ctx.set("Access-Control-Allow-Origin", "*");
|
|
313
|
+
}
|
|
314
|
+
} else {
|
|
315
|
+
loggy.info("No CORS middleware set, setting to request origin or *");
|
|
268
316
|
ctx.set("Access-Control-Allow-Origin", ctx.request.headers.origin || "*");
|
|
269
317
|
}
|
|
270
318
|
return;
|
|
@@ -321,7 +369,8 @@ const config = {
|
|
|
321
369
|
cacheHeadersAllowList: [],
|
|
322
370
|
cacheAuthorizedRequests: false,
|
|
323
371
|
cacheGetTimeoutInMs: 1e3,
|
|
324
|
-
autoPurgeCache: true
|
|
372
|
+
autoPurgeCache: true,
|
|
373
|
+
autoPurgeCacheOnStart: true
|
|
325
374
|
}),
|
|
326
375
|
validator: (config2) => {
|
|
327
376
|
if (typeof config2.debug !== "boolean") {
|
|
@@ -382,6 +431,9 @@ const config = {
|
|
|
382
431
|
if (typeof config2.autoPurgeCache !== "boolean") {
|
|
383
432
|
throw new Error(`Invalid config: autoPurgeCache must be a boolean`);
|
|
384
433
|
}
|
|
434
|
+
if (typeof config2.autoPurgeCacheOnStart !== "boolean") {
|
|
435
|
+
throw new Error(`Invalid config: autoPurgeCacheOnStart must be a boolean`);
|
|
436
|
+
}
|
|
385
437
|
}
|
|
386
438
|
};
|
|
387
439
|
const contentTypes = {};
|
|
@@ -591,6 +643,7 @@ class RedisCacheProvider {
|
|
|
591
643
|
this.cacheGetTimeoutInMs = Number(
|
|
592
644
|
this.strapi.plugin("strapi-cache").config("cacheGetTimeoutInMs")
|
|
593
645
|
);
|
|
646
|
+
this.keyPrefix = this.strapi.plugin("strapi-cache").config("redisConfig")?.["keyPrefix"] ?? "";
|
|
594
647
|
if (redisClusterNodes.length) {
|
|
595
648
|
const redisClusterOptions = this.strapi.plugin("strapi-cache").config("redisClusterOptions");
|
|
596
649
|
if (!redisClusterOptions["redisOptions"]) {
|
|
@@ -640,8 +693,9 @@ class RedisCacheProvider {
|
|
|
640
693
|
async del(key) {
|
|
641
694
|
if (!this.ready) return null;
|
|
642
695
|
try {
|
|
643
|
-
|
|
644
|
-
|
|
696
|
+
const relativeKey = key.slice(this.keyPrefix.length);
|
|
697
|
+
loggy.info(`Redis PURGING KEY: ${relativeKey}`);
|
|
698
|
+
await this.client.del(relativeKey);
|
|
645
699
|
return true;
|
|
646
700
|
} catch (error) {
|
|
647
701
|
loggy.error(`Redis del error: ${error}`);
|
|
@@ -651,7 +705,7 @@ class RedisCacheProvider {
|
|
|
651
705
|
async keys() {
|
|
652
706
|
if (!this.ready) return null;
|
|
653
707
|
try {
|
|
654
|
-
const keys = await this.client.keys(
|
|
708
|
+
const keys = await this.client.keys(`${this.keyPrefix}*`);
|
|
655
709
|
return keys;
|
|
656
710
|
} catch (error) {
|
|
657
711
|
loggy.error(`Redis keys error: ${error}`);
|
|
@@ -661,6 +715,14 @@ class RedisCacheProvider {
|
|
|
661
715
|
async reset() {
|
|
662
716
|
if (!this.ready) return null;
|
|
663
717
|
try {
|
|
718
|
+
if (this.keyPrefix) {
|
|
719
|
+
loggy.info(`Redis FLUSHING NAMESPACE: ${this.keyPrefix}`);
|
|
720
|
+
const keys = await this.keys();
|
|
721
|
+
if (!keys) return null;
|
|
722
|
+
const toDelete = keys.filter((key) => key.startsWith(this.keyPrefix));
|
|
723
|
+
await Promise.all(toDelete.map((key) => this.del(key)));
|
|
724
|
+
return true;
|
|
725
|
+
}
|
|
664
726
|
loggy.info(`Redis FLUSHING ALL KEYS`);
|
|
665
727
|
await this.client.flushdb();
|
|
666
728
|
return true;
|
|
@@ -719,3 +781,4 @@ const index = {
|
|
|
719
781
|
middlewares
|
|
720
782
|
};
|
|
721
783
|
module.exports = index;
|
|
784
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../server/src/utils/log.ts","../../server/src/utils/invalidateCache.ts","../../server/src/permissions.ts","../../server/src/bootstrap.ts","../../server/src/utils/key.ts","../../server/src/utils/body.ts","../../server/src/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\n try {\n const contentType = strapi.contentType(uid);\n\n if (!contentType || !contentType.kind) {\n loggy.info(`Content type ${uid} not found`);\n return;\n }\n\n const pluralName =\n contentType.kind === 'singleType'\n ? contentType.info.singularName\n : contentType.info.pluralName;\n const apiPath = `/api/${pluralName}`;\n const regex = new RegExp(`^.*:${apiPath}(/.*)?(\\\\?.*)?$`);\n\n await cacheStore.clearByRegexp([regex]);\n loggy.info(`Invalidated cache for ${apiPath}`);\n } catch (error) {\n loggy.error('Cache invalidation error:');\n loggy.error(error);\n }\n}\n\nexport async function invalidateGraphqlCache(\n event: any,\n cacheStore: CacheProvider,\n strapi: Core.Strapi\n) {\n try {\n const graphqlRegex = new RegExp(`^POST:\\/graphql(:.*)?$`);\n\n await cacheStore.clearByRegexp([graphqlRegex]);\n loggy.info(`Invalidated cache for ${graphqlRegex}`);\n } catch (error) {\n loggy.error('Cache invalidation error:');\n loggy.error(error);\n }\n}\n","export const actions = [\n {\n section: 'plugins',\n displayName: 'Purge Cache',\n uid: 'purge-cache',\n pluginName: 'strapi-cache',\n },\n];\n","import type { Core } from '@strapi/strapi';\nimport { invalidateCache, invalidateGraphqlCache } from './utils/invalidateCache';\nimport { CacheService } from './types/cache.types';\nimport { loggy } from './utils/log';\nimport { actions } from './permissions';\n\nconst bootstrap = ({ strapi }: { strapi: Core.Strapi }) => {\n loggy.info('Initializing');\n try {\n const cacheService = strapi.plugin('strapi-cache').services.service as CacheService;\n const 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","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 { 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 routeIsCachable =\n cacheableRoutes.some((route) => url.startsWith(route)) ||\n (cacheableRoutes.length === 0 && url.startsWith('/api'));\n const authorizationHeader = ctx.request.headers['authorization'];\n\n if (authorizationHeader && !cacheAuthorizedRequests) {\n loggy.info(`Authorized request bypassing cache: ${key}`);\n await next();\n return;\n }\n\n if (cacheEntry && !noCache) {\n loggy.info(`HIT with key: ${key}`);\n ctx.status = 200;\n ctx.body = cacheEntry.body;\n\n if (cacheHeaders) {\n ctx.set(cacheEntry.headers);\n }\n\n const middlewaresConfig = strapi.config.get('middlewares') as any[];\n const corsMiddleware = middlewaresConfig.find((mw: any) => mw.name === 'strapi::cors');\n\n if (corsMiddleware) {\n loggy.info('CORS middleware is set, checking allowed origins');\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 (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 if (ctx.body instanceof Stream) {\n const buf = await streamToBuffer(ctx.body);\n const contentEncoding = ctx.response.headers['content-encoding'];\n const decompressed = await decompressBuffer(buf, contentEncoding);\n const responseText = decodeBufferToText(decompressed);\n\n await cacheStore.set(key, { body: responseText, headers: headersToStore });\n ctx.body = buf;\n } else {\n await cacheStore.set(key, { body: ctx.body, headers: headersToStore });\n }\n }\n};\n\nexport default middleware;\n","import rawBody from 'raw-body';\nimport { generateGraphqlCacheKey } from '../utils/key';\nimport Stream, { Readable } from 'stream';\nimport { loggy } from '../utils/log';\nimport { CacheService } from '../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 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 const middlewaresConfig = strapi.config.get('middlewares') as any[];\n const corsMiddleware = middlewaresConfig.find((mw: any) => mw.name === 'strapi::cors');\n\n if (corsMiddleware) {\n loggy.info('CORS middleware is set, checking allowed origins');\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 (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 if (ctx.body instanceof Stream) {\n const buf = await streamToBuffer(ctx.body);\n const contentEncoding = ctx.response.headers['content-encoding'];\n const decompressed = await decompressBuffer(buf, contentEncoding);\n const responseText = decodeBufferToText(decompressed);\n\n await cacheStore.set(key, { body: responseText, headers: headersToStore });\n ctx.body = buf;\n } else {\n await cacheStore.set(key, { body: ctx.body, headers: headersToStore });\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 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 }),\n validator: (config) => {\n if (typeof config.debug !== 'boolean') {\n throw new Error(`Invalid config: debug must be a boolean`);\n }\n if (typeof config.max !== 'number') {\n throw new Error(`Invalid config: max must be a number`);\n }\n if (typeof config.ttl !== 'number') {\n throw new Error(`Invalid config: ttl must be a number`);\n }\n if (typeof config.size !== 'number') {\n throw new Error(`Invalid config: size must be a number`);\n }\n if (typeof config.allowStale !== 'boolean') {\n throw new Error(`Invalid config: allowStale must be a boolean`);\n }\n if (\n !Array.isArray(config.cacheableRoutes) ||\n config.cacheableRoutes.some((item) => typeof item !== 'string')\n ) {\n throw new Error(`Invalid config: cacheableRoutes must be an string array`);\n }\n if (typeof config.provider !== 'string') {\n throw new Error(`Invalid config: provider must be a string`);\n }\n if (config.provider !== 'memory' && config.provider !== 'redis') {\n throw new Error(`Invalid config: provider must be 'memory' or 'redis'`);\n }\n if (config.provider === 'redis') {\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(`Invalid config: redisConfig must be a string or object when using redis provider`);\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 },\n};\n","export default {};\n","import type { Core } from '@strapi/strapi';\nimport { Context } from 'koa';\nimport { CacheService } from 'src/types/cache.types';\n\nconst controller = ({ strapi }: { strapi: Core.Strapi }) => ({\n async purgeCache(ctx: Context) {\n const service = strapi.plugin('strapi-cache').service('service') as CacheService;\n\n await service.getCacheInstance().reset();\n\n ctx.body = {\n message: 'Cache purged successfully',\n };\n },\n async purgeCacheByKey(ctx: Context) {\n const { key } = ctx.params;\n const service = strapi.plugin('strapi-cache').service('service') as CacheService;\n const regex = new RegExp(`(^|\\/)?${key}(\\/|\\\\?|$)`);\n\n await service.getCacheInstance().clearByRegexp([regex]);\n\n ctx.body = {\n message: `Cache purged successfully for key: ${key}`,\n };\n },\n async cacheableRoutes(ctx: Context) {\n const cacheableRoutes = strapi.plugin('strapi-cache').config('cacheableRoutes');\n ctx.body = cacheableRoutes;\n },\n});\n\nexport default controller;\n","import controller from './controller';\n\nexport default {\n controller,\n};\n","export default {};\n","export default [\n {\n method: 'POST',\n path: '/purge-cache',\n handler: 'controller.purgeCache',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: {\n actions: ['plugin::strapi-cache.purge-cache'],\n },\n },\n ],\n },\n },\n {\n method: 'POST',\n path: '/purge-cache/:key',\n handler: 'controller.purgeCacheByKey',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: {\n actions: ['plugin::strapi-cache.purge-cache'],\n },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/cacheable-routes',\n handler: 'controller.cacheableRoutes',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: {\n actions: ['plugin::strapi-cache.purge-cache'],\n },\n },\n ],\n },\n },\n];\n","import purgeRoute from './purge';\n\nconst routes = {\n 'purge-route': {\n type: 'admin',\n routes: purgeRoute,\n },\n};\n\nexport default routes;\n","export const withTimeout = (callback: () => Promise<any>, ms: number) => {\n let timeout: NodeJS.Timeout | null = null;\n\n return Promise.race([\n callback().then((result) => {\n if (timeout) {\n clearTimeout(timeout);\n }\n return result;\n }),\n new Promise((_, reject) => {\n timeout = setTimeout(() => {\n reject(new Error('timeout'));\n }, ms);\n }),\n ]);\n};\n","import type { Core } from '@strapi/strapi';\nimport { LRUCache } from 'lru-cache';\nimport { withTimeout } from '../../utils/withTimeout';\nimport { CacheProvider, CacheService } from '../../types/cache.types';\nimport { loggy } from '../../utils/log';\n\nexport class InMemoryCacheProvider implements CacheProvider {\n private initialized = false;\n private provider!: LRUCache<string, any>;\n 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[] =\n this.strapi.plugin('strapi-cache').config('redisClusterNodes');\n this.cacheGetTimeoutInMs = Number(\n this.strapi.plugin('strapi-cache').config('cacheGetTimeoutInMs')\n );\n this.keyPrefix = this.strapi.plugin('strapi-cache').config('redisConfig')?.[\"keyPrefix\"] as string | undefined ?? \"\";\n if (redisClusterNodes.length) {\n const redisClusterOptions: ClusterOptions =\n this.strapi.plugin('strapi-cache').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 if (!keys) return;\n\n const toDelete = keys.filter((key) => regExps.some((re) => re.test(key)));\n await Promise.all(toDelete.map((key) => this.del(key)));\n }\n}\n","import type { Core } from '@strapi/strapi';\nimport { InMemoryCacheProvider } from './memory/provider';\nimport { RedisCacheProvider } from './redis/provider';\nimport { CacheProvider } from '../../src/types/cache.types';\nimport { loggy } from '../../src/utils/log';\n\nexport const resolveCacheProvider = (strapi: Core.Strapi): CacheProvider => {\n const providerType = strapi.plugin('strapi-cache').config('provider') || 'memory';\n\n loggy.info(`Selected cache provider: ${providerType}`);\n\n let instance: CacheProvider;\n\n switch (providerType) {\n case 'redis':\n instance = new RedisCacheProvider(strapi);\n break;\n default:\n instance = new InMemoryCacheProvider(strapi);\n break;\n }\n\n return instance;\n};\n","import type { Core } from '@strapi/strapi';\nimport { resolveCacheProvider } from './resolver';\nimport { CacheProvider, CacheService } from '../../src/types/cache.types';\nimport { loggy } from '../../src/utils/log';\n\nconst service = ({ strapi }: { strapi: Core.Strapi }): CacheService => {\n let instance: null | CacheProvider = null;\n\n return {\n getCacheInstance() {\n if (!instance) {\n loggy.info('Initializing cache service from provider config...');\n instance = resolveCacheProvider(strapi);\n }\n return instance;\n },\n };\n};\n\nexport default {\n service,\n};\n","/**\n * Application methods\n */\nimport bootstrap from './bootstrap';\nimport register from './register';\n\n/**\n * Plugin server methods\n */\nimport config from './config';\nimport contentTypes from './content-types';\nimport controllers from './controllers';\nimport middlewares from './middlewares';\nimport policies from './policies';\nimport routes from './routes';\nimport services from './services';\n\nexport default {\n register,\n bootstrap,\n destroy() {},\n config,\n controllers,\n routes,\n services,\n contentTypes,\n policies,\n middlewares,\n};\n"],"names":["strapi","createHash","createGunzip","createBrotliDecompress","createInflate","middleware","Stream","rawBody","Readable","authorizationHeader","graphql","cache","config","service","LRUCache","Redis"],"mappings":"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"}
|
package/dist/server/index.mjs
CHANGED
|
@@ -69,6 +69,7 @@ const bootstrap = ({ strapi: strapi2 }) => {
|
|
|
69
69
|
try {
|
|
70
70
|
const cacheService = strapi2.plugin("strapi-cache").services.service;
|
|
71
71
|
const autoPurgeCache = strapi2.plugin("strapi-cache").config("autoPurgeCache");
|
|
72
|
+
const autoPurgeCacheOnStart = strapi2.plugin("strapi-cache").config("autoPurgeCacheOnStart");
|
|
72
73
|
const cacheStore = cacheService.getCacheInstance();
|
|
73
74
|
if (!cacheStore) {
|
|
74
75
|
loggy.error("Plugin could not be initialized");
|
|
@@ -91,6 +92,13 @@ const bootstrap = ({ strapi: strapi2 }) => {
|
|
|
91
92
|
}
|
|
92
93
|
});
|
|
93
94
|
}
|
|
95
|
+
if (autoPurgeCacheOnStart) {
|
|
96
|
+
cacheStore.reset().then(() => {
|
|
97
|
+
loggy.info("Cache purged successfully");
|
|
98
|
+
}).catch((error) => {
|
|
99
|
+
loggy.error(`Error purging cache on start: ${error.message}`);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
94
102
|
} catch (error) {
|
|
95
103
|
loggy.error("Plugin could not be initialized");
|
|
96
104
|
return;
|
|
@@ -195,6 +203,26 @@ const middleware$1 = async (ctx, next) => {
|
|
|
195
203
|
ctx.body = cacheEntry.body;
|
|
196
204
|
if (cacheHeaders) {
|
|
197
205
|
ctx.set(cacheEntry.headers);
|
|
206
|
+
}
|
|
207
|
+
const middlewaresConfig = strapi.config.get("middlewares");
|
|
208
|
+
const corsMiddleware = middlewaresConfig.find((mw) => mw.name === "strapi::cors");
|
|
209
|
+
if (corsMiddleware) {
|
|
210
|
+
loggy.info("CORS middleware is set, checking allowed origins");
|
|
211
|
+
const corsConfig = corsMiddleware?.config;
|
|
212
|
+
const origin = ctx?.request?.headers?.origin;
|
|
213
|
+
let allowedOrigins = corsConfig?.origin ?? "*";
|
|
214
|
+
if (typeof allowedOrigins === "string") {
|
|
215
|
+
allowedOrigins = [allowedOrigins];
|
|
216
|
+
}
|
|
217
|
+
if (allowedOrigins.includes(origin)) {
|
|
218
|
+
loggy.info(`Setting Access-Control-Allow-Origin to ${origin}`);
|
|
219
|
+
ctx.set("Access-Control-Allow-Origin", origin);
|
|
220
|
+
} else if (typeof origin === "undefined" || allowedOrigins.includes("*")) {
|
|
221
|
+
loggy.info("No origin header or * in allowed origins, setting to *");
|
|
222
|
+
ctx.set("Access-Control-Allow-Origin", "*");
|
|
223
|
+
}
|
|
224
|
+
} else {
|
|
225
|
+
loggy.info("No CORS middleware set, setting to request origin or *");
|
|
198
226
|
ctx.set("Access-Control-Allow-Origin", ctx.request.headers.origin || "*");
|
|
199
227
|
}
|
|
200
228
|
return;
|
|
@@ -261,6 +289,26 @@ const middleware = async (ctx, next) => {
|
|
|
261
289
|
ctx.body = cacheEntry.body;
|
|
262
290
|
if (cacheHeaders) {
|
|
263
291
|
ctx.set(cacheEntry.headers);
|
|
292
|
+
}
|
|
293
|
+
const middlewaresConfig = strapi.config.get("middlewares");
|
|
294
|
+
const corsMiddleware = middlewaresConfig.find((mw) => mw.name === "strapi::cors");
|
|
295
|
+
if (corsMiddleware) {
|
|
296
|
+
loggy.info("CORS middleware is set, checking allowed origins");
|
|
297
|
+
const corsConfig = corsMiddleware?.config;
|
|
298
|
+
const origin = ctx?.request?.headers?.origin;
|
|
299
|
+
let allowedOrigins = corsConfig?.origin ?? "*";
|
|
300
|
+
if (typeof allowedOrigins === "string") {
|
|
301
|
+
allowedOrigins = [allowedOrigins];
|
|
302
|
+
}
|
|
303
|
+
if (allowedOrigins.includes(origin)) {
|
|
304
|
+
loggy.info(`Setting Access-Control-Allow-Origin to ${origin}`);
|
|
305
|
+
ctx.set("Access-Control-Allow-Origin", origin);
|
|
306
|
+
} else if (typeof origin === "undefined" || allowedOrigins.includes("*")) {
|
|
307
|
+
loggy.info("No origin header or * in allowed origins, setting to *");
|
|
308
|
+
ctx.set("Access-Control-Allow-Origin", "*");
|
|
309
|
+
}
|
|
310
|
+
} else {
|
|
311
|
+
loggy.info("No CORS middleware set, setting to request origin or *");
|
|
264
312
|
ctx.set("Access-Control-Allow-Origin", ctx.request.headers.origin || "*");
|
|
265
313
|
}
|
|
266
314
|
return;
|
|
@@ -317,7 +365,8 @@ const config = {
|
|
|
317
365
|
cacheHeadersAllowList: [],
|
|
318
366
|
cacheAuthorizedRequests: false,
|
|
319
367
|
cacheGetTimeoutInMs: 1e3,
|
|
320
|
-
autoPurgeCache: true
|
|
368
|
+
autoPurgeCache: true,
|
|
369
|
+
autoPurgeCacheOnStart: true
|
|
321
370
|
}),
|
|
322
371
|
validator: (config2) => {
|
|
323
372
|
if (typeof config2.debug !== "boolean") {
|
|
@@ -378,6 +427,9 @@ const config = {
|
|
|
378
427
|
if (typeof config2.autoPurgeCache !== "boolean") {
|
|
379
428
|
throw new Error(`Invalid config: autoPurgeCache must be a boolean`);
|
|
380
429
|
}
|
|
430
|
+
if (typeof config2.autoPurgeCacheOnStart !== "boolean") {
|
|
431
|
+
throw new Error(`Invalid config: autoPurgeCacheOnStart must be a boolean`);
|
|
432
|
+
}
|
|
381
433
|
}
|
|
382
434
|
};
|
|
383
435
|
const contentTypes = {};
|
|
@@ -587,6 +639,7 @@ class RedisCacheProvider {
|
|
|
587
639
|
this.cacheGetTimeoutInMs = Number(
|
|
588
640
|
this.strapi.plugin("strapi-cache").config("cacheGetTimeoutInMs")
|
|
589
641
|
);
|
|
642
|
+
this.keyPrefix = this.strapi.plugin("strapi-cache").config("redisConfig")?.["keyPrefix"] ?? "";
|
|
590
643
|
if (redisClusterNodes.length) {
|
|
591
644
|
const redisClusterOptions = this.strapi.plugin("strapi-cache").config("redisClusterOptions");
|
|
592
645
|
if (!redisClusterOptions["redisOptions"]) {
|
|
@@ -636,8 +689,9 @@ class RedisCacheProvider {
|
|
|
636
689
|
async del(key) {
|
|
637
690
|
if (!this.ready) return null;
|
|
638
691
|
try {
|
|
639
|
-
|
|
640
|
-
|
|
692
|
+
const relativeKey = key.slice(this.keyPrefix.length);
|
|
693
|
+
loggy.info(`Redis PURGING KEY: ${relativeKey}`);
|
|
694
|
+
await this.client.del(relativeKey);
|
|
641
695
|
return true;
|
|
642
696
|
} catch (error) {
|
|
643
697
|
loggy.error(`Redis del error: ${error}`);
|
|
@@ -647,7 +701,7 @@ class RedisCacheProvider {
|
|
|
647
701
|
async keys() {
|
|
648
702
|
if (!this.ready) return null;
|
|
649
703
|
try {
|
|
650
|
-
const keys = await this.client.keys(
|
|
704
|
+
const keys = await this.client.keys(`${this.keyPrefix}*`);
|
|
651
705
|
return keys;
|
|
652
706
|
} catch (error) {
|
|
653
707
|
loggy.error(`Redis keys error: ${error}`);
|
|
@@ -657,6 +711,14 @@ class RedisCacheProvider {
|
|
|
657
711
|
async reset() {
|
|
658
712
|
if (!this.ready) return null;
|
|
659
713
|
try {
|
|
714
|
+
if (this.keyPrefix) {
|
|
715
|
+
loggy.info(`Redis FLUSHING NAMESPACE: ${this.keyPrefix}`);
|
|
716
|
+
const keys = await this.keys();
|
|
717
|
+
if (!keys) return null;
|
|
718
|
+
const toDelete = keys.filter((key) => key.startsWith(this.keyPrefix));
|
|
719
|
+
await Promise.all(toDelete.map((key) => this.del(key)));
|
|
720
|
+
return true;
|
|
721
|
+
}
|
|
660
722
|
loggy.info(`Redis FLUSHING ALL KEYS`);
|
|
661
723
|
await this.client.flushdb();
|
|
662
724
|
return true;
|
|
@@ -717,3 +779,4 @@ const index = {
|
|
|
717
779
|
export {
|
|
718
780
|
index as default
|
|
719
781
|
};
|
|
782
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../../server/src/utils/log.ts","../../server/src/utils/invalidateCache.ts","../../server/src/permissions.ts","../../server/src/bootstrap.ts","../../server/src/utils/key.ts","../../server/src/utils/body.ts","../../server/src/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\n try {\n const contentType = strapi.contentType(uid);\n\n if (!contentType || !contentType.kind) {\n loggy.info(`Content type ${uid} not found`);\n return;\n }\n\n const pluralName =\n contentType.kind === 'singleType'\n ? contentType.info.singularName\n : contentType.info.pluralName;\n const apiPath = `/api/${pluralName}`;\n const regex = new RegExp(`^.*:${apiPath}(/.*)?(\\\\?.*)?$`);\n\n await cacheStore.clearByRegexp([regex]);\n loggy.info(`Invalidated cache for ${apiPath}`);\n } catch (error) {\n loggy.error('Cache invalidation error:');\n loggy.error(error);\n }\n}\n\nexport async function invalidateGraphqlCache(\n event: any,\n cacheStore: CacheProvider,\n strapi: Core.Strapi\n) {\n try {\n const graphqlRegex = new RegExp(`^POST:\\/graphql(:.*)?$`);\n\n await cacheStore.clearByRegexp([graphqlRegex]);\n loggy.info(`Invalidated cache for ${graphqlRegex}`);\n } catch (error) {\n loggy.error('Cache invalidation error:');\n loggy.error(error);\n }\n}\n","export const actions = [\n {\n section: 'plugins',\n displayName: 'Purge Cache',\n uid: 'purge-cache',\n pluginName: 'strapi-cache',\n },\n];\n","import type { Core } from '@strapi/strapi';\nimport { invalidateCache, invalidateGraphqlCache } from './utils/invalidateCache';\nimport { CacheService } from './types/cache.types';\nimport { loggy } from './utils/log';\nimport { actions } from './permissions';\n\nconst bootstrap = ({ strapi }: { strapi: Core.Strapi }) => {\n loggy.info('Initializing');\n try {\n const cacheService = strapi.plugin('strapi-cache').services.service as CacheService;\n const 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","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 { 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 routeIsCachable =\n cacheableRoutes.some((route) => url.startsWith(route)) ||\n (cacheableRoutes.length === 0 && url.startsWith('/api'));\n const authorizationHeader = ctx.request.headers['authorization'];\n\n if (authorizationHeader && !cacheAuthorizedRequests) {\n loggy.info(`Authorized request bypassing cache: ${key}`);\n await next();\n return;\n }\n\n if (cacheEntry && !noCache) {\n loggy.info(`HIT with key: ${key}`);\n ctx.status = 200;\n ctx.body = cacheEntry.body;\n\n if (cacheHeaders) {\n ctx.set(cacheEntry.headers);\n }\n\n const middlewaresConfig = strapi.config.get('middlewares') as any[];\n const corsMiddleware = middlewaresConfig.find((mw: any) => mw.name === 'strapi::cors');\n\n if (corsMiddleware) {\n loggy.info('CORS middleware is set, checking allowed origins');\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 (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 if (ctx.body instanceof Stream) {\n const buf = await streamToBuffer(ctx.body);\n const contentEncoding = ctx.response.headers['content-encoding'];\n const decompressed = await decompressBuffer(buf, contentEncoding);\n const responseText = decodeBufferToText(decompressed);\n\n await cacheStore.set(key, { body: responseText, headers: headersToStore });\n ctx.body = buf;\n } else {\n await cacheStore.set(key, { body: ctx.body, headers: headersToStore });\n }\n }\n};\n\nexport default middleware;\n","import rawBody from 'raw-body';\nimport { generateGraphqlCacheKey } from '../utils/key';\nimport Stream, { Readable } from 'stream';\nimport { loggy } from '../utils/log';\nimport { CacheService } from '../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 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 const middlewaresConfig = strapi.config.get('middlewares') as any[];\n const corsMiddleware = middlewaresConfig.find((mw: any) => mw.name === 'strapi::cors');\n\n if (corsMiddleware) {\n loggy.info('CORS middleware is set, checking allowed origins');\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 (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 if (ctx.body instanceof Stream) {\n const buf = await streamToBuffer(ctx.body);\n const contentEncoding = ctx.response.headers['content-encoding'];\n const decompressed = await decompressBuffer(buf, contentEncoding);\n const responseText = decodeBufferToText(decompressed);\n\n await cacheStore.set(key, { body: responseText, headers: headersToStore });\n ctx.body = buf;\n } else {\n await cacheStore.set(key, { body: ctx.body, headers: headersToStore });\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 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 }),\n validator: (config) => {\n if (typeof config.debug !== 'boolean') {\n throw new Error(`Invalid config: debug must be a boolean`);\n }\n if (typeof config.max !== 'number') {\n throw new Error(`Invalid config: max must be a number`);\n }\n if (typeof config.ttl !== 'number') {\n throw new Error(`Invalid config: ttl must be a number`);\n }\n if (typeof config.size !== 'number') {\n throw new Error(`Invalid config: size must be a number`);\n }\n if (typeof config.allowStale !== 'boolean') {\n throw new Error(`Invalid config: allowStale must be a boolean`);\n }\n if (\n !Array.isArray(config.cacheableRoutes) ||\n config.cacheableRoutes.some((item) => typeof item !== 'string')\n ) {\n throw new Error(`Invalid config: cacheableRoutes must be an string array`);\n }\n if (typeof config.provider !== 'string') {\n throw new Error(`Invalid config: provider must be a string`);\n }\n if (config.provider !== 'memory' && config.provider !== 'redis') {\n throw new Error(`Invalid config: provider must be 'memory' or 'redis'`);\n }\n if (config.provider === 'redis') {\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(`Invalid config: redisConfig must be a string or object when using redis provider`);\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 },\n};\n","export default {};\n","import type { Core } from '@strapi/strapi';\nimport { Context } from 'koa';\nimport { CacheService } from 'src/types/cache.types';\n\nconst controller = ({ strapi }: { strapi: Core.Strapi }) => ({\n async purgeCache(ctx: Context) {\n const service = strapi.plugin('strapi-cache').service('service') as CacheService;\n\n await service.getCacheInstance().reset();\n\n ctx.body = {\n message: 'Cache purged successfully',\n };\n },\n async purgeCacheByKey(ctx: Context) {\n const { key } = ctx.params;\n const service = strapi.plugin('strapi-cache').service('service') as CacheService;\n const regex = new RegExp(`(^|\\/)?${key}(\\/|\\\\?|$)`);\n\n await service.getCacheInstance().clearByRegexp([regex]);\n\n ctx.body = {\n message: `Cache purged successfully for key: ${key}`,\n };\n },\n async cacheableRoutes(ctx: Context) {\n const cacheableRoutes = strapi.plugin('strapi-cache').config('cacheableRoutes');\n ctx.body = cacheableRoutes;\n },\n});\n\nexport default controller;\n","import controller from './controller';\n\nexport default {\n controller,\n};\n","export default {};\n","export default [\n {\n method: 'POST',\n path: '/purge-cache',\n handler: 'controller.purgeCache',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: {\n actions: ['plugin::strapi-cache.purge-cache'],\n },\n },\n ],\n },\n },\n {\n method: 'POST',\n path: '/purge-cache/:key',\n handler: 'controller.purgeCacheByKey',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: {\n actions: ['plugin::strapi-cache.purge-cache'],\n },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/cacheable-routes',\n handler: 'controller.cacheableRoutes',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'plugin::content-manager.hasPermissions',\n config: {\n actions: ['plugin::strapi-cache.purge-cache'],\n },\n },\n ],\n },\n },\n];\n","import purgeRoute from './purge';\n\nconst routes = {\n 'purge-route': {\n type: 'admin',\n routes: purgeRoute,\n },\n};\n\nexport default routes;\n","export const withTimeout = (callback: () => Promise<any>, ms: number) => {\n let timeout: NodeJS.Timeout | null = null;\n\n return Promise.race([\n callback().then((result) => {\n if (timeout) {\n clearTimeout(timeout);\n }\n return result;\n }),\n new Promise((_, reject) => {\n timeout = setTimeout(() => {\n reject(new Error('timeout'));\n }, ms);\n }),\n ]);\n};\n","import type { Core } from '@strapi/strapi';\nimport { LRUCache } from 'lru-cache';\nimport { withTimeout } from '../../utils/withTimeout';\nimport { CacheProvider, CacheService } from '../../types/cache.types';\nimport { loggy } from '../../utils/log';\n\nexport class InMemoryCacheProvider implements CacheProvider {\n private initialized = false;\n private provider!: LRUCache<string, any>;\n 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[] =\n this.strapi.plugin('strapi-cache').config('redisClusterNodes');\n this.cacheGetTimeoutInMs = Number(\n this.strapi.plugin('strapi-cache').config('cacheGetTimeoutInMs')\n );\n this.keyPrefix = this.strapi.plugin('strapi-cache').config('redisConfig')?.[\"keyPrefix\"] as string | undefined ?? \"\";\n if (redisClusterNodes.length) {\n const redisClusterOptions: ClusterOptions =\n this.strapi.plugin('strapi-cache').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 if (!keys) return;\n\n const toDelete = keys.filter((key) => regExps.some((re) => re.test(key)));\n await Promise.all(toDelete.map((key) => this.del(key)));\n }\n}\n","import type { Core } from '@strapi/strapi';\nimport { InMemoryCacheProvider } from './memory/provider';\nimport { RedisCacheProvider } from './redis/provider';\nimport { CacheProvider } from '../../src/types/cache.types';\nimport { loggy } from '../../src/utils/log';\n\nexport const resolveCacheProvider = (strapi: Core.Strapi): CacheProvider => {\n const providerType = strapi.plugin('strapi-cache').config('provider') || 'memory';\n\n loggy.info(`Selected cache provider: ${providerType}`);\n\n let instance: CacheProvider;\n\n switch (providerType) {\n case 'redis':\n instance = new RedisCacheProvider(strapi);\n break;\n default:\n instance = new InMemoryCacheProvider(strapi);\n break;\n }\n\n return instance;\n};\n","import type { Core } from '@strapi/strapi';\nimport { resolveCacheProvider } from './resolver';\nimport { CacheProvider, CacheService } from '../../src/types/cache.types';\nimport { loggy } from '../../src/utils/log';\n\nconst service = ({ strapi }: { strapi: Core.Strapi }): CacheService => {\n let instance: null | CacheProvider = null;\n\n return {\n getCacheInstance() {\n if (!instance) {\n loggy.info('Initializing cache service from provider config...');\n instance = resolveCacheProvider(strapi);\n }\n return instance;\n },\n };\n};\n\nexport default {\n service,\n};\n","/**\n * Application methods\n */\nimport bootstrap from './bootstrap';\nimport register from './register';\n\n/**\n * Plugin server methods\n */\nimport config from './config';\nimport contentTypes from './content-types';\nimport controllers from './controllers';\nimport middlewares from './middlewares';\nimport policies from './policies';\nimport routes from './routes';\nimport services from './services';\n\nexport default {\n register,\n bootstrap,\n destroy() {},\n config,\n controllers,\n routes,\n services,\n contentTypes,\n policies,\n middlewares,\n};\n"],"names":["strapi","middleware","authorizationHeader","graphql","cache","config","service"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.5.7
|
|
2
|
+
"version": "1.5.7",
|
|
3
3
|
"keywords": [
|
|
4
4
|
"strapi cache",
|
|
5
5
|
"strapi rest cache",
|
|
@@ -42,8 +42,7 @@
|
|
|
42
42
|
"ioredis": "^5.6.1",
|
|
43
43
|
"lru-cache": "^11.1.0",
|
|
44
44
|
"raw-body": "^3.0.0",
|
|
45
|
-
"react-intl": "^7.1.10"
|
|
46
|
-
"strapi-cache": "file:.yalc/strapi-cache"
|
|
45
|
+
"react-intl": "^7.1.10"
|
|
47
46
|
},
|
|
48
47
|
"devDependencies": {
|
|
49
48
|
"@strapi/sdk-plugin": "^5.3.2",
|