├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .github
├── FUNDING.yml
└── workflows
│ ├── docs.yml
│ ├── gh-release.yml
│ └── tests.yml
├── .gitignore
├── .markdownlint.json
├── .nvmrc
├── .prettierrc.js
├── .vscode
├── launch.json
└── settings.json
├── BENCHMARKS.md
├── CHANGELOG.md
├── LICENSE
├── README.md
├── data
├── data.json
└── uploads
│ ├── a-bug-is-becoming-a-meme-on-the-internet.jpg
│ ├── beautiful-picture.jpg
│ ├── daviddoe@strapi.io.jpg
│ ├── default-image.png
│ ├── favicon.png
│ ├── sarahbaker@strapi.io.jpg
│ ├── the-internet-s-own-boy.jpg
│ ├── this-shrimp-is-awesome.jpg
│ ├── we-love-pizza.jpg
│ └── what-s-inside-a-black-hole.jpg
├── docs
├── .vitepress
│ ├── config.js
│ └── theme
│ │ ├── Layout.vue
│ │ ├── custom.css
│ │ └── index.js
├── guide
│ ├── api
│ │ ├── admin-routes.md
│ │ └── index.md
│ ├── index.md
│ ├── installation.md
│ ├── provider
│ │ ├── couchbase.md
│ │ ├── custom-provider.md
│ │ ├── index.md
│ │ ├── memory.md
│ │ └── redis.md
│ └── strategy
│ │ ├── cache-content-type.md
│ │ ├── cache-custom-routes.md
│ │ ├── cache-keys.md
│ │ ├── debug.md
│ │ └── index.md
├── index.md
└── public
│ ├── fluent-emoji-cloud-with-lightning.svg
│ ├── icon.png
│ ├── logo-rest-cache-dark.svg
│ └── logo-rest-cache-light.svg
├── jest.config.js
├── lerna.json
├── package.json
├── packages
├── strapi-plugin-rest-cache
│ ├── .prettierrc
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── admin
│ │ └── src
│ │ │ ├── .eslintrc
│ │ │ ├── components
│ │ │ ├── EditViewInfoInjectedComponent
│ │ │ │ └── index.js
│ │ │ ├── EditViewInjectedComponent
│ │ │ │ └── index.js
│ │ │ ├── EntityCacheInformation
│ │ │ │ └── index.js
│ │ │ ├── Initializer
│ │ │ │ └── index.js
│ │ │ ├── ListViewInjectedComponent
│ │ │ │ └── index.js
│ │ │ ├── PluginIcon
│ │ │ │ └── index.js
│ │ │ └── PurgeCacheButton
│ │ │ │ └── index.js
│ │ │ ├── hooks
│ │ │ ├── index.js
│ │ │ └── useCacheStrategy
│ │ │ │ ├── index.js
│ │ │ │ ├── init.js
│ │ │ │ └── reducer.js
│ │ │ ├── index.js
│ │ │ ├── pages
│ │ │ ├── App
│ │ │ │ └── index.js
│ │ │ └── HomePage
│ │ │ │ └── index.js
│ │ │ ├── permissions.js
│ │ │ ├── pluginId.js
│ │ │ └── translations
│ │ │ ├── en.json
│ │ │ └── fr.json
│ ├── package.json
│ ├── server
│ │ ├── bootstrap.js
│ │ ├── config
│ │ │ └── index.js
│ │ ├── controllers
│ │ │ ├── config.js
│ │ │ ├── index.js
│ │ │ └── purge.js
│ │ ├── index.js
│ │ ├── middlewares
│ │ │ ├── index.js
│ │ │ ├── purge.js
│ │ │ ├── purgeAdmin.js
│ │ │ └── recv.js
│ │ ├── permissions-actions.js
│ │ ├── pluginId.js
│ │ ├── routes
│ │ │ ├── admin
│ │ │ │ ├── config.js
│ │ │ │ ├── index.js
│ │ │ │ └── purge.js
│ │ │ └── index.js
│ │ ├── services
│ │ │ ├── cacheConfig.js
│ │ │ ├── cacheStore.js
│ │ │ └── index.js
│ │ ├── types
│ │ │ ├── CacheContentTypeConfig.js
│ │ │ ├── CacheKeysConfig.js
│ │ │ ├── CachePluginStrategy.js
│ │ │ ├── CacheProvider.js
│ │ │ ├── CacheRouteConfig.js
│ │ │ └── index.js
│ │ └── utils
│ │ │ ├── config
│ │ │ ├── deepFreeze.js
│ │ │ ├── getRelatedModelsUid.js
│ │ │ ├── getRouteRegExp.js
│ │ │ ├── resolveUserStrategy.js
│ │ │ └── routeExists.js
│ │ │ ├── etags
│ │ │ ├── etagGenerate.js
│ │ │ ├── etagLookup.js
│ │ │ └── etagMatch.js
│ │ │ ├── keys
│ │ │ ├── generateCacheKey.js
│ │ │ ├── generateHeadersKey.js
│ │ │ └── generateQueryParamsKey.js
│ │ │ ├── middlewares
│ │ │ ├── createRouter.js
│ │ │ └── shouldLookup.js
│ │ │ └── store
│ │ │ ├── deserialize.js
│ │ │ ├── serialize.js
│ │ │ └── withTimeout.js
│ ├── strapi-admin.js
│ └── strapi-server.js
├── strapi-provider-rest-cache-couchbase
│ ├── CHANGELOG.md
│ ├── lib
│ │ ├── CouchbaseCacheProvider.js
│ │ └── index.js
│ └── package.json
├── strapi-provider-rest-cache-memory
│ ├── CHANGELOG.md
│ ├── lib
│ │ ├── MemoryCacheProvider.js
│ │ └── index.js
│ └── package.json
└── strapi-provider-rest-cache-redis
│ ├── CHANGELOG.md
│ ├── lib
│ ├── RedisCacheProvider.js
│ └── index.js
│ └── package.json
├── playgrounds
├── couchbase
│ ├── .editorconfig
│ ├── .env.example
│ ├── .eslintignore
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── config
│ │ └── plugins.js
│ ├── docker-compose.yml
│ ├── favicon.ico
│ ├── package.json
│ ├── public
│ │ ├── robots.txt
│ │ └── uploads
│ │ │ └── .gitkeep
│ ├── src
│ │ └── .gitkeep
│ ├── tests
│ │ └── .gitkeep
│ └── yarn.lock
├── memory
│ ├── .editorconfig
│ ├── .env.example
│ ├── .eslintignore
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── config
│ │ └── plugins.js
│ ├── favicon.ico
│ ├── package.json
│ ├── public
│ │ ├── robots.txt
│ │ └── uploads
│ │ │ └── .gitkeep
│ └── yarn.lock
└── redis
│ ├── .editorconfig
│ ├── .env.example
│ ├── .eslintignore
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── config
│ └── plugins.js
│ ├── docker-compose.yml
│ ├── favicon.ico
│ ├── package.json
│ ├── public
│ ├── robots.txt
│ └── uploads
│ │ └── .gitkeep
│ └── yarn.lock
├── shared
├── config
│ ├── admin.js
│ ├── api.js
│ ├── cache-strategy.js
│ ├── database.js
│ ├── env
│ │ └── test
│ │ │ └── database.js
│ ├── logger.js
│ ├── middlewares.js
│ └── server.js
├── src
│ ├── admin
│ │ ├── app.example.js
│ │ └── webpack.config.example.js
│ ├── api
│ │ ├── .gitkeep
│ │ ├── article
│ │ │ ├── content-types
│ │ │ │ └── article
│ │ │ │ │ └── schema.json
│ │ │ ├── controllers
│ │ │ │ └── article.js
│ │ │ ├── routes
│ │ │ │ └── article.js
│ │ │ └── services
│ │ │ │ └── article.js
│ │ ├── category
│ │ │ ├── content-types
│ │ │ │ └── category
│ │ │ │ │ └── schema.json
│ │ │ ├── controllers
│ │ │ │ └── category.js
│ │ │ ├── routes
│ │ │ │ ├── category.js
│ │ │ │ └── custom-category.js
│ │ │ └── services
│ │ │ │ └── category.js
│ │ ├── global
│ │ │ ├── content-types
│ │ │ │ └── global
│ │ │ │ │ └── schema.json
│ │ │ ├── controllers
│ │ │ │ └── global.js
│ │ │ ├── routes
│ │ │ │ └── global.js
│ │ │ └── services
│ │ │ │ └── global.js
│ │ ├── homepage
│ │ │ ├── content-types
│ │ │ │ └── homepage
│ │ │ │ │ └── schema.json
│ │ │ ├── controllers
│ │ │ │ └── homepage.js
│ │ │ ├── routes
│ │ │ │ └── homepage.js
│ │ │ └── services
│ │ │ │ └── homepage.js
│ │ └── writer
│ │ │ ├── content-types
│ │ │ └── writer
│ │ │ │ └── schema.json
│ │ │ ├── controllers
│ │ │ └── writer.js
│ │ │ ├── routes
│ │ │ └── writer.js
│ │ │ └── services
│ │ │ └── writer.js
│ ├── bootstrap.js
│ ├── components
│ │ ├── sections
│ │ │ ├── hero.json
│ │ │ └── highlight.json
│ │ └── shared
│ │ │ └── seo.json
│ ├── extensions
│ │ └── .gitkeep
│ └── index.js
├── start-profiler.js
└── tests
│ ├── .eslintrc
│ ├── helpers
│ └── strapi.js
│ └── single-type-default.test.js
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | types
2 | tests
3 | **/node_modules/**
4 | CHANGELOG.md
5 | **/admin/**
6 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | commonjs: true,
4 | es2021: true,
5 | node: true,
6 | },
7 | extends: ["eslint:recommended", "plugin:import/recommended", "prettier"],
8 | overrides: [
9 | {
10 | env: {
11 | node: true,
12 | },
13 | files: [".eslintrc.{js,cjs}"],
14 | parserOptions: {
15 | sourceType: "script",
16 | },
17 | },
18 | ],
19 | parserOptions: {
20 | ecmaVersion: "latest",
21 | },
22 | rules: {
23 | "no-undef": "off",
24 | },
25 | };
26 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | open_collective: strapi
2 |
--------------------------------------------------------------------------------
/.github/workflows/docs.yml:
--------------------------------------------------------------------------------
1 | name: docs
2 |
3 | on:
4 | # trigger deployment on push to main branch and if docs/ is updated
5 | push:
6 | branches: [main]
7 | paths:
8 | - "docs/**"
9 | # trigger deployment manually
10 | workflow_dispatch:
11 |
12 | jobs:
13 | docs:
14 | runs-on: ubuntu-latest
15 |
16 | steps:
17 | - uses: actions/checkout@v2
18 | with:
19 | # fetch all commits to get last updated time or other git log info
20 | fetch-depth: 0
21 |
22 | - name: Setup Node.js
23 | uses: actions/setup-node@v1
24 | with:
25 | # choose node.js version to use
26 | node-version: "14"
27 |
28 | # cache node_modules
29 | - name: Cache dependencies
30 | uses: actions/cache@v2
31 | id: yarn-cache
32 | with:
33 | path: |
34 | **/node_modules
35 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
36 | restore-keys: |
37 | ${{ runner.os }}-yarn-
38 |
39 | # install dependencies if the cache did not hit
40 | - name: Install dependencies
41 | if: steps.yarn-cache.outputs.cache-hit != 'true'
42 | run: yarn --frozen-lockfile
43 |
44 | # run build script
45 | - name: Build VitePress site
46 | run: yarn docs:build
47 |
48 | # please check out the docs of the workflow for more details
49 | # @see https://github.com/crazy-max/ghaction-github-pages
50 | - name: Deploy to GitHub Pages
51 | uses: crazy-max/ghaction-github-pages@v2
52 | with:
53 | # deploy to gh-pages branch
54 | target_branch: gh-pages
55 | # deploy the default output dir of VitePress
56 | build_dir: docs/.vitepress/dist
57 | env:
58 | # @see https://docs.github.com/en/actions/reference/authentication-in-a-workflow#about-the-github_token-secret
59 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
60 |
--------------------------------------------------------------------------------
/.github/workflows/gh-release.yml:
--------------------------------------------------------------------------------
1 | name: release
2 |
3 | on:
4 | # trigger release on every tag push
5 | push:
6 | tags:
7 | - 'v*.*.*'
8 |
9 | jobs:
10 | release:
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | # extract tag from the github ref (e.g. refs/tags/v1.2.3)
15 | - name: Set up tag meta
16 | id: meta
17 | run: |
18 | echo ::set-output name=tag::${GITHUB_REF#refs/tags/}
19 |
20 | # create a new release on github with discussion
21 | - name: Create release
22 | uses: softprops/action-gh-release@v1
23 | env:
24 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
25 | with:
26 | tag_name: ${{ steps.meta.outputs.tag }}
27 | name: Release ${{ steps.meta.outputs.tag }}
28 | body: View [CHANGELOG.md](https://github.com/strapi-community/strapi-plugin-rest-cache/blob/main/CHANGELOG.md) for details
29 | draft: false
30 | prerelease: false
31 | discussion_category_name: announcements
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: tests
2 |
3 | on:
4 | workflow_call:
5 | push:
6 | branches: [main]
7 | paths:
8 | - ".github/**"
9 | - "data/**"
10 | - "packages/**"
11 | - "playgrounds/**"
12 | - "shared/**"
13 | pull_request:
14 | branches: [main]
15 | paths:
16 | - ".github/**"
17 | - "data/**"
18 | - "packages/**"
19 | - "playgrounds/**"
20 | - "shared/**"
21 |
22 | jobs:
23 | linters:
24 | runs-on: ubuntu-latest
25 |
26 | steps:
27 | - uses: actions/checkout@v2
28 | - uses: actions/setup-node@v1
29 | with:
30 | node-version: 18.x
31 |
32 | # cache node_modules
33 | - name: Cache dependencies
34 | uses: actions/cache@v2
35 | id: yarn-cache
36 | with:
37 | path: |
38 | **/node_modules
39 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
40 | restore-keys: |
41 | ${{ runner.os }}-yarn-
42 |
43 | # install dependencies if the cache did not hit
44 | - name: Install dependencies
45 | if: steps.yarn-cache.outputs.cache-hit != 'true'
46 | run: yarn --frozen-lockfile
47 |
48 | - run: yarn test:lint
49 |
50 | e2e_memory:
51 | runs-on: ubuntu-latest
52 | needs: [linters]
53 |
54 | steps:
55 | - uses: actions/checkout@v2
56 | - uses: actions/setup-node@v1
57 | with:
58 | node-version: 18.x
59 |
60 | # cache node_modules
61 | - name: Cache dependencies
62 | uses: actions/cache@v2
63 | id: yarn-cache
64 | with:
65 | path: |
66 | **/node_modules
67 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
68 | restore-keys: |
69 | ${{ runner.os }}-yarn-
70 |
71 | # install dependencies if the cache did not hit
72 | - name: Install dependencies
73 | if: steps.yarn-cache.outputs.cache-hit != 'true'
74 | run: yarn --frozen-lockfile
75 |
76 | - run: yarn postinstall:memory
77 |
78 | - name: Run Memory e2e tests
79 | working-directory: playgrounds/memory
80 | run: yarn test:e2e
81 |
82 | e2e_redis:
83 | runs-on: ubuntu-latest
84 | needs: [linters]
85 |
86 | services:
87 | redis:
88 | image: bitnami/redis:latest
89 | env:
90 | ALLOW_EMPTY_PASSWORD: yes
91 | ports:
92 | # Opens tcp port 6379 on the host and service container
93 | - 6379:6379
94 |
95 | steps:
96 | - uses: actions/checkout@v2
97 | - uses: actions/setup-node@v1
98 | with:
99 | node-version: 18.x
100 |
101 | # cache node_modules
102 | - name: Cache dependencies
103 | uses: actions/cache@v2
104 | id: yarn-cache
105 | with:
106 | path: |
107 | **/node_modules
108 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
109 | restore-keys: |
110 | ${{ runner.os }}-yarn-
111 |
112 | # install dependencies if the cache did not hit
113 | - name: Install dependencies
114 | if: steps.yarn-cache.outputs.cache-hit != 'true'
115 | run: yarn --frozen-lockfile
116 |
117 | - run: yarn postinstall:redis
118 |
119 | - name: Run Redis e2e tests
120 | working-directory: playgrounds/redis
121 | run: yarn test:e2e
122 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # TypeScript v1 declaration files
45 | typings/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env
73 | .env.test
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 |
78 | # Next.js build output
79 | .next
80 |
81 | # Nuxt.js build / generate output
82 | .nuxt
83 | dist
84 |
85 | # Gatsby files
86 | .cache/
87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
88 | # https://nextjs.org/blog/next-9-1#public-directory-support
89 | # public
90 |
91 | # vuepress build output
92 | .vuepress/dist
93 |
94 | # Serverless directories
95 | .serverless/
96 |
97 | # FuseBox cache
98 | .fusebox/
99 |
100 | # DynamoDB Local files
101 | .dynamodb/
102 |
103 | # TernJS port file
104 | .tern-port
105 |
106 | # vuepress
107 | .temp
108 | .profile
109 | cache
110 |
111 | # Strapi
112 | .strapi-updater.json
113 |
--------------------------------------------------------------------------------
/.markdownlint.json:
--------------------------------------------------------------------------------
1 | {
2 | "default": true,
3 | "MD024": false,
4 | "MD013": false,
5 | "MD034": false
6 | }
7 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | v14.19.1
2 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | endOfLine: 'lf',
3 | semi: true,
4 | singleQuote: true,
5 | tabWidth: 2,
6 | trailingComma: 'es5',
7 | printWidth: 100,
8 | };
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Run mocha",
9 | "type": "node",
10 | "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
11 | "stopOnEntry": false,
12 | "args": ["./tests/*.test.js", "--no-timeouts", "--exit"],
13 | "cwd": "${workspaceFolder}",
14 | "runtimeExecutable": null,
15 | "request": "launch"
16 | }
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "typescript.tsdk": "node_modules/typescript/lib"
3 | }
4 |
--------------------------------------------------------------------------------
/BENCHMARKS.md:
--------------------------------------------------------------------------------
1 | # Benchmarks
2 |
3 | ## Context
4 |
5 | - Rest cache version: `4.2.4`
6 | - Strapi version: `4.1.5`
7 | - Node version: `16.13.2`
8 | - Endpoint used: `/api/homepage?populate=*` from `shared/api`
9 |
10 | ## Runs
11 |
12 | ### Cache disabled (reference)
13 |
14 | ```sh
15 | $ ENABLE_CACHE=false yarn profile:memory
16 | ```
17 |
18 | | Stat | 2.5% | 50% | 97.5% | 99% | Avg | Stdev | Max |
19 | | ----------- | ------- | ------- | ------- | ------- | ---------- | --------- | ------- |
20 | | **Latency** | 2424 ms | 2555 ms | 2921 ms | 3012 ms | 2565.12 ms | 133.23 | 3401 ms |
21 |
22 | | Stat | 1% | 2.5% | 50% | 97.5% | Avg | Stdev | Min |
23 | | ------------- | --- | ---- | ------ | ------- | ------ | ------ | ------ |
24 | | **Req/Sec** | 0 | 0 | 386 | 1000 | 383.34 | 382.38 | 39 |
25 | | **Bytes/Sec** | 0 B | 0 B | 453 kB | 1.17 MB | 450 kB | 449 kB | 45.7 kB |
26 |
27 | ### Cache enabled (without etag)
28 |
29 | ```sh
30 | $ ENABLE_ETAG=false yarn profile:memory
31 | ```
32 |
33 | | Stat | 2.5% | 50% | 97.5% | 99% | Avg | Stdev | Max |
34 | | ----------- | ------ | ------ | ------ | ------ | --------- | ------- | ------ |
35 | | **Latency** | 113 ms | 116 ms | 166 ms | 175 ms | 120.04 ms | 12.86 ms | 275 ms |
36 |
37 | | Stat | 1% | 2.5% | 50% | 97.5% | Avg | Stdev | Min |
38 | | ------------- | ------- | ------- | ------- | ------- | ------- | ------ | ------- |
39 | | **Req/Sec** | 7451 | 7523 | 8287 | 8687 | 8293.49 | 306.35 | 6381 |
40 | | **Bytes/Sec** | 8.85 MB | 8.93 MB | 9.84 MB | 10.3 MB | 9.84 MB | 364 kB | 7.57 MB |
41 |
42 | ### Cache enabled (with etag)
43 |
44 | ```sh
45 | $ yarn profile:memory
46 | ```
47 |
48 | | Stat | 2.5% | 50% | 97.5% | 99% | Avg | Stdev | Max |
49 | | ----------- | ------ | ------ | ------ | ------ | --------- | -------- | ------ |
50 | | **Latency** | 119 ms | 125 ms | 185 ms | 197 ms | 131.05 ms | 16.87 ms | 307 ms |
51 |
52 | | Stat | 1% | 2.5% | 50% | 97.5% | Avg | Stdev | Min |
53 | | ------------- | ------- | ------- | ------- | ------- | ------- | ------ | ------- |
54 | | **Req/Sec** | 6551 | 6559 | 7651 | 8231 | 7599.39 | 472.94 | 6100 |
55 | | **Bytes/Sec** | 8.05 MB | 8.07 MB | 9.4 MB | 10.1 MB | 9.34 MB | 581 kB | 7.5 MB |
56 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2022 Strapi Community.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
Strapi REST Cache Plugin
3 |
4 |
Speed-up HTTP requests with LRU cache.
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | ## Table of Contents
17 |
18 | - [🚦 Current Status](#-current-status)
19 | - [✨ Features](#-features)
20 | - [🤔 Motivation](#-motivation)
21 | - [🖐 Requirements](#-requirements)
22 | - [🚚 Getting Started](#-getting-started)
23 | - [Contributing](#contributing)
24 | - [License](#license)
25 |
26 | ## 🚦 Current Status
27 |
28 | This package is currently under development and should be consider **ALPHA** in terms of state. I/We are currently accepting contributions and/or dedicated contributors to help develop and maintain this package.
29 |
30 | ## ✨ Features
31 |
32 | This plugin provide a way to cache **HTTP requests** in order to **improve performance**. It's get inspired by varnish cache which is a popular caching solution.
33 |
34 | The cache content is stored by a **provider**, which can be either an in-memory provider, a redis connection, a file system, or any other custom provider.
35 | You can set a **strategy** to tell what to cache and how much time responses should be cached. The cache will be invalidated when the related Content-Type is updated, so you **never have to worry about stale data**.
36 |
37 | ## 🖐 Requirements
38 |
39 | Supported Strapi Versions:
40 |
41 | - Strapi v4.0.x (recently tested as of January 2022)
42 | - Strapi v4.1.x (recently tested as of March 2022)
43 | - Strapi v4.x.x (Assumed, but possibly not tested)
44 |
45 | **If you are looking for a plugin for Strapi v3.x, please check the [strapi-middleware-cache](https://github.com/patrixr/strapi-middleware-cache/).**
46 |
47 | ## 🚚 Getting Started
48 |
49 | [Read the Docs to Learn More.](https://strapi-community.github.io/strapi-plugin-rest-cache/)
50 |
51 | ## Contributing
52 |
53 | I/We are actively looking for contributors, maintainers, and others to help shape this package. As this plugins sole purpose within the Strapi community is to be used by other developers and plugin maintainers to get fast responses time.
54 |
55 | If interested please feel free to email the lead maintainer Sacha at: sacha@digisquad.io or ping `stf#3254` on Discord.
56 |
57 | ## License
58 |
59 | See the [LICENSE](./LICENSE.md) file for licensing information.
60 |
--------------------------------------------------------------------------------
/data/uploads/a-bug-is-becoming-a-meme-on-the-internet.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-rest-cache/7e08dc4715b0c231b9f6646045b5c9a8674b58fd/data/uploads/a-bug-is-becoming-a-meme-on-the-internet.jpg
--------------------------------------------------------------------------------
/data/uploads/beautiful-picture.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-rest-cache/7e08dc4715b0c231b9f6646045b5c9a8674b58fd/data/uploads/beautiful-picture.jpg
--------------------------------------------------------------------------------
/data/uploads/daviddoe@strapi.io.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-rest-cache/7e08dc4715b0c231b9f6646045b5c9a8674b58fd/data/uploads/daviddoe@strapi.io.jpg
--------------------------------------------------------------------------------
/data/uploads/default-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-rest-cache/7e08dc4715b0c231b9f6646045b5c9a8674b58fd/data/uploads/default-image.png
--------------------------------------------------------------------------------
/data/uploads/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-rest-cache/7e08dc4715b0c231b9f6646045b5c9a8674b58fd/data/uploads/favicon.png
--------------------------------------------------------------------------------
/data/uploads/sarahbaker@strapi.io.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-rest-cache/7e08dc4715b0c231b9f6646045b5c9a8674b58fd/data/uploads/sarahbaker@strapi.io.jpg
--------------------------------------------------------------------------------
/data/uploads/the-internet-s-own-boy.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-rest-cache/7e08dc4715b0c231b9f6646045b5c9a8674b58fd/data/uploads/the-internet-s-own-boy.jpg
--------------------------------------------------------------------------------
/data/uploads/this-shrimp-is-awesome.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-rest-cache/7e08dc4715b0c231b9f6646045b5c9a8674b58fd/data/uploads/this-shrimp-is-awesome.jpg
--------------------------------------------------------------------------------
/data/uploads/we-love-pizza.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-rest-cache/7e08dc4715b0c231b9f6646045b5c9a8674b58fd/data/uploads/we-love-pizza.jpg
--------------------------------------------------------------------------------
/data/uploads/what-s-inside-a-black-hole.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-rest-cache/7e08dc4715b0c231b9f6646045b5c9a8674b58fd/data/uploads/what-s-inside-a-black-hole.jpg
--------------------------------------------------------------------------------
/docs/.vitepress/config.js:
--------------------------------------------------------------------------------
1 | import { createRequire } from 'module'
2 | import { defineConfig } from 'vitepress'
3 |
4 | const require = createRequire(import.meta.url)
5 | const pkg = require('strapi-plugin-rest-cache/package.json')
6 |
7 | export default defineConfig({
8 | title: "REST Cache",
9 | description: "Speed-up HTTP requests with LRU cache",
10 | base: "/strapi-plugin-rest-cache/",
11 | lastUpdated: true,
12 | themeConfig: {
13 | socialLinks: [
14 | { icon: 'github', link: 'https://github.com/strapi-community/strapi-plugin-rest-cache' },
15 | ],
16 | editLink: {
17 | pattern: 'https://github.com/strapi-community/strapi-plugin-rest-cache/edit/main/docs/:path',
18 | text: 'Edit this page on GitHub'
19 | },
20 | logo: {
21 | src: "/icon.png",
22 | },
23 | outline: [2,3],
24 | footer: {
25 | message: 'Made with ❤️ by Strapi Community'
26 | },
27 | nav: [
28 | {
29 | text: "Guide",
30 | link: "/guide/",
31 | activeMatch: '/guide/',
32 | },
33 | {
34 | text: pkg.version,
35 | items: [
36 | {
37 | text: 'Changelog',
38 | link: 'https://github.com/strapi-community/strapi-plugin-rest-cache/blob/main/CHANGELOG.md'
39 | },
40 | {
41 | text: 'Strapi Community',
42 | link: 'https://github.com/strapi-community'
43 | }
44 | ]
45 | }
46 | ],
47 | sidebar: {
48 | '/guide/': [
49 | {
50 | text: 'Guide',
51 | items: [
52 | { text: 'Introduction', link: '/guide/' },
53 | { text: 'Installation', link: '/guide/installation' },
54 | ]
55 | },
56 | {
57 | text: 'Provider',
58 | collapsible: true,
59 | items: [
60 | { text: 'Provider configuration', link: '/guide/provider/' },
61 | { text: 'Provider: Memory', link: '/guide/provider/memory' },
62 | { text: 'Provider: Redis', link: '/guide/provider/redis' },
63 | { text: 'Provider: Couchbase', link: '/guide/provider/couchbase' },
64 | { text: 'Custom provider', link: '/guide/provider/custom-provider' },
65 | ]
66 | },
67 | {
68 | text: 'Strategy',
69 | collapsible: true,
70 | items: [
71 | { text: 'Strategy configuration', link: '/guide/strategy/' },
72 | { text: 'Cache content type', link: '/guide/strategy/cache-content-type' },
73 | { text: 'Cache custom routes', link: '/guide/strategy/cache-custom-routes' },
74 | { text: 'Cache keys', link: '/guide/strategy/cache-keys' },
75 | { text: 'Debug mode', link: '/guide/strategy/debug' },
76 | ]
77 | },
78 | {
79 | text: 'API',
80 | collapsible: true,
81 | items: [
82 | { text: 'Services', link: '/guide/api/' },
83 | { text: 'Admin Routes', link: '/guide/api/admin-routes' },
84 | ]
85 | }
86 | ],
87 | '/reference/': [
88 | {
89 | text: 'Reference',
90 | collapsible: true,
91 | items: [
92 | { text: 'Configuration', link: '/reference/configuration' },
93 | { text: 'Routes', link: '/reference/routes' },
94 | { text: 'Services', link: '/reference/services' },
95 | ]
96 | }
97 | ]
98 | }
99 | }
100 | })
101 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/Layout.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/custom.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --vp-c-brand: #8e75ff;
3 | --vp-c-brand-light: #a091ed;
4 | --vp-c-brand-lighter: #a091ed;
5 | --vp-c-brand-dark: #8e75ff;
6 | --vp-c-brand-darker: #8e75ff;
7 | }
--------------------------------------------------------------------------------
/docs/.vitepress/theme/index.js:
--------------------------------------------------------------------------------
1 | import DefaultTheme from 'vitepress/theme'
2 | import Layout from './Layout.vue'
3 | import './custom.css'
4 |
5 | export default {
6 | ...DefaultTheme,
7 | // override the Layout with a wrapper component that
8 | // injects the slots
9 | Layout
10 | }
--------------------------------------------------------------------------------
/docs/guide/api/admin-routes.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Admin Routes
3 | ---
4 |
5 | # Admin Routes
6 |
7 | This plugin exposes a few admin routes that can be used to interact with the cache from Strapi admin panel.
8 |
9 | ## [GET] /config/strategy
10 |
11 | ## [GET] /config/provider
12 |
13 | ## [POST] /purge
14 |
--------------------------------------------------------------------------------
/docs/guide/api/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Services
3 | ---
4 |
5 | # Services
6 |
7 | This plugin exposes a few services that can be used to interact with the cache.
8 |
9 | ## cacheConfig
10 |
11 | This service is used to interact with the plugin configuration.
12 |
13 | ### `getUids()`
14 |
15 | Get all uid of cached contentTypes
16 |
17 | ```js
18 | const uids = strapi.plugins["rest-cache"].services.cacheConfig.getUids();
19 | ```
20 |
21 | ### `getRelatedCachedUid(uid)`
22 |
23 | Return the intersection of cached contentTypes and the related contentTypes of a given contentType uid
24 |
25 | ```js
26 | const relatedUids = strapi.plugins[
27 | "rest-cache"
28 | ].services.cacheConfig.getRelatedCachedUid("api::article.article");
29 | ```
30 |
31 | ### `get(uid)`
32 |
33 | Get related `CacheContentTypeConfig` with an uid
34 |
35 | ```js
36 | const contentTypeConfig = strapi.plugins["rest-cache"].services.cacheConfig.get(
37 | "api::article.article"
38 | );
39 | ```
40 |
41 | ### `getCacheKeysRegexp(uid, params, wildcard)`
42 |
43 | Get regexs to match all `CacheContentTypeConfig` keys with given params
44 |
45 | ```js
46 | const regExps = strapi.plugins[
47 | "rest-cache"
48 | ].services.cacheConfig.getCacheKeysRegexp("api::article.article", {
49 | lang: "en",
50 | });
51 | ```
52 |
53 | ### `isCached()`
54 |
55 | Check if a cache configuration exists for a contentType uid
56 |
57 | ```js
58 | const isContentTypeCached = strapi.plugins[
59 | "rest-cache"
60 | ].services.cacheConfig.isCached("api::article.article");
61 | ```
62 |
63 | ## cacheStore
64 |
65 | This service is used to interact with the cache store.
66 |
67 | ### `get(key)`
68 |
69 | ### `set(key, val, maxAge)`
70 |
71 | ### `del(key)`
72 |
73 | ### `keys()`
74 |
75 | ### `reset()`
76 |
77 | ### `init()`
78 |
79 | ### `ready`
80 |
81 | ### `clearByRegexp(regExps)`
82 |
83 | ### `clearByUid(uid, params, wildcard)`
84 |
--------------------------------------------------------------------------------
/docs/guide/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Introduction
3 | ---
4 |
5 | # {{ $frontmatter.title }}
6 |
7 | This plugin inject a middleware that caches incoming `GET` requests on the strapi API, based on query params and Content-Type UID.
8 | The cache is automatically busted everytime a `PUT`, `PATCH`, `POST`, or `DELETE` request comes in or when an entity is updated through the admin panel. It can also be programmatically cleared via exposed services or admin routes.
9 |
10 | The cache content is stored by a [**provider**](./provider/index.md), which can be either an in-memory provider, a redis connection, a file system, or any other custom provider.
11 |
12 | You can set a [**strategy**](./strategy/index.md) to tell what to cache and how much time responses should be cached. The cache will be invalidated when the related Content-Type is updated, so you **never have to worry about stale data**.
13 |
14 | In addition, you can interact with the plugin through the admin panel, api admin routes or programmatically using internal services.
15 |
--------------------------------------------------------------------------------
/docs/guide/installation.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Installation
3 | ---
4 |
5 | # {{ $frontmatter.title }}
6 |
7 | 1. Add required dependencies
8 |
9 | :::: code-group
10 |
11 | ```bash [memory (default)]
12 | yarn add strapi-plugin-rest-cache
13 | ```
14 |
15 | ```bash [redis]
16 | yarn add \
17 | strapi-plugin-rest-cache \
18 | strapi-plugin-redis \
19 | strapi-provider-rest-cache-redis
20 | ```
21 |
22 | ```bash [couchbase]
23 | yarn add \
24 | strapi-plugin-rest-cache \
25 | strapi-provider-rest-cache-couchbase
26 | ```
27 |
28 | ::::
29 |
30 | ::: info
31 | This plugin is only compatible with Strapi v4.0.0 and above.
32 | If you are looking for a plugin for Strapi v3.x, please check the [strapi-middleware-cache](https://github.com/patrixr/strapi-middleware-cache/).
33 | :::
34 |
35 | 1. Enable the plugin in `./config/plugins.js`
36 |
37 | :::: code-group
38 |
39 | ```js [memory (default)]
40 | module.exports = {
41 | "rest-cache": {
42 | config: {
43 | provider: {
44 | name: "memory",
45 | options: {
46 | max: 32767,
47 | maxAge: 3600,
48 | },
49 | },
50 | strategy: {
51 | contentTypes: [
52 | // list of Content-Types UID to cache
53 | "api::category.category",
54 | "api::article.article",
55 | "api::global.global",
56 | "api::homepage.homepage",
57 | ],
58 | },
59 | },
60 | },
61 | };
62 | ```
63 |
64 | ```js [redis]
65 | module.exports = {
66 | // Step 1: Configure the redis connection
67 | // @see https://github.com/strapi-community/strapi-plugin-redis
68 | redis: {
69 | // ...
70 | },
71 | // Step 2: Configure the redis cache plugin
72 | "rest-cache": {
73 | config: {
74 | provider: {
75 | name: "redis",
76 | options: {
77 | max: 32767,
78 | connection: "default",
79 | },
80 | },
81 | strategy: {
82 | // if you are using keyPrefix for your Redis, please add
83 | keysPrefix: "",
84 | contentTypes: [
85 | // list of Content-Types UID to cache
86 | "api::category.category",
87 | "api::article.article",
88 | "api::global.global",
89 | "api::homepage.homepage",
90 | ],
91 | },
92 | },
93 | },
94 | };
95 | ```
96 |
97 | ```js [couchbase]
98 | module.exports = {
99 | "rest-cache": {
100 | config: {
101 | provider: {
102 | name: "couchbase",
103 | max: 32767,
104 | options: {
105 | connectionString: "couchbase://127.0.0.1:8091",
106 | connectionOptions: {
107 | username: "Administrator",
108 | password: "couchbase",
109 | },
110 | bucket: "test-bucket",
111 | ttl: 2,
112 | },
113 | },
114 | strategy: {
115 | contentTypes: [
116 | // list of Content-Types UID to cache
117 | "api::category.category",
118 | "api::article.article",
119 | "api::global.global",
120 | "api::homepage.homepage",
121 | ],
122 | },
123 | },
124 | },
125 | };
126 | ```
127 |
128 | ::::
129 |
--------------------------------------------------------------------------------
/docs/guide/provider/couchbase.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Couchbase provider
3 | ---
4 |
5 | # Couchbase provider
6 |
7 | ## Installation
8 |
9 | ```bash
10 | yarn add \
11 | strapi-plugin-rest-cache \
12 | strapi-provider-rest-cache-couchbase
13 | ```
14 |
15 | ## Configuration
16 |
17 | ```js
18 | module.exports = {
19 | "rest-cache": {
20 | config: {
21 | provider: {
22 | name: "couchbase",
23 | max: 32767,
24 | options: {
25 | connectionString: "couchbase://127.0.0.1:8091",
26 | connectionOptions: {
27 | username: "Administrator",
28 | password: "couchbase",
29 | },
30 | bucket: "test-bucket",
31 | ttl: 2,
32 | },
33 | },
34 | strategy: {
35 | contentTypes: [
36 | // list of Content-Types UID to cache
37 | "api::category.category",
38 | "api::article.article",
39 | "api::global.global",
40 | "api::homepage.homepage",
41 | ],
42 | },
43 | },
44 | },
45 | };
46 | ```
47 |
--------------------------------------------------------------------------------
/docs/guide/provider/custom-provider.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Custom provider
3 | ---
4 |
5 | # Create a custom provider
6 |
7 | ## Extends the `CacheProvider` class
8 |
9 | ```js
10 | // file: /custom-rest-cache-provider/MyCacheProvider.js
11 | const { CacheProvider } = require("strapi-plugin-rest-cache/server/types");
12 |
13 | class MyCacheProvider extends CacheProvider {
14 | // implement your custom provider here
15 | }
16 |
17 | module.exports = {
18 | MyCacheProvider,
19 | };
20 | ```
21 |
22 | ::: details View abstract CacheProvider class
23 |
24 | ```js
25 | /**
26 | * Abstract Class CacheProvider.
27 | *
28 | * @class CacheProvider
29 | */
30 | class CacheProvider {
31 | constructor() {
32 | if (this.constructor === CacheProvider) {
33 | throw new Error("CacheProvider class can't be instantiated.");
34 | }
35 | }
36 |
37 | /**
38 | * @param {string} key
39 | */
40 | async get(key) {
41 | throw new Error("Method 'get()' must be implemented.");
42 | }
43 |
44 | /**
45 | * @param {string} key
46 | * @param {any} val
47 | * @param {number=} maxAge
48 | */
49 | async set(key, val, maxAge = 3600) {
50 | throw new Error("Method 'set()' must be implemented.");
51 | }
52 |
53 | /**
54 | * @param {string|string[]} key
55 | */
56 | async del(key) {
57 | throw new Error("Method 'del()' must be implemented.");
58 | }
59 |
60 | async keys() {
61 | throw new Error("Method 'keys()' must be implemented.");
62 | }
63 |
64 | get ready() {
65 | throw new Error("getter 'ready' must be implemented.");
66 | }
67 | }
68 | ```
69 |
70 | :::
71 |
72 | ## Export the provider
73 |
74 | ```js
75 | // file: /custom-rest-cache-provider/index.js
76 | const couchbase = require("couchbase");
77 |
78 | const { MyCacheProvider } = require("./MyCacheProvider");
79 |
80 | module.exports = {
81 | provider: "custom",
82 | name: "Custom provider",
83 |
84 | async init(options, { strapi }) {
85 | // here you can initialize your provider connection
86 | const client = await couchbase.connect(options.clients);
87 |
88 | // then return your provider instance
89 | return new MyCacheProvider(client);
90 | },
91 | };
92 | ```
93 |
94 | ## Use your custom cache provider
95 |
96 | ```js
97 | // file: /config/plugins.js
98 |
99 | module.exports = {
100 | "rest-cache": {
101 | config: {
102 | provider: {
103 | name: "../custom-rest-cache-provider/index.js",
104 | // your provider options
105 | // will be passed to the provider init function
106 | options: {},
107 | },
108 | strategy: {
109 | // ...
110 | },
111 | },
112 | },
113 | };
114 | ```
115 |
--------------------------------------------------------------------------------
/docs/guide/provider/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Cache provider configuration
3 | ---
4 |
5 | # Cache provider configuration
6 |
7 | By default, the **strapi-plugin-rest-cache** use **strapi-provider-rest-cache-memory** which is an in-memory provider. It's not persisted and will be lost when the server restarts.
8 |
9 | Alternatively, you can use:
10 |
11 | - **strapi-provider-rest-cache-redis** which is a bridge between the cache plugin and the [strapi-plugin-redis](https://github.com/strapi-community/strapi-plugin-redis)
12 | - **strapi-provider-rest-cache-couchbase** which connect to a couchbase cluster and store the cache in a bucket
13 | - Your custom provider
14 |
15 | You have to set the provider name in the plugin configuration so it will be initialized once the plugin is bootstrapped. At this time only one provider can be used at a time.
16 |
17 | You can also set the provider `getTimeout` which is the time in milliseconds to wait for the provider to respond, **if the provider is not responding, the cache will be considered as a miss**.
18 |
19 | ```js {6-17}
20 | // file: /config/plugins.js
21 |
22 | module.exports = ({ env }) => ({
23 | 'rest-cache': {
24 | config: {
25 | provider: /* @type {Provider} */ {
26 | // name can be an alias:
27 | name: "my-provider", // try to require 'strapi-provider-rest-cache-my-provider'
28 | // a full package name:
29 | name: "@org/my-cache-provider", // try to require '@org/my-cache-provider'
30 | // or a relative path:
31 | name: "../path/to/my-provider",
32 |
33 | // provider options
34 | getTimeout: 500, // in milliseconds (default: 500)
35 | options: {},
36 | },
37 | strategy: {
38 | // ...
39 | },
40 | },
41 | },
42 | });
43 | ```
44 |
45 | Note that each provider has its own configuration, so you will have to refer to the provider documentation to know how to configure it.
46 |
47 | ::: tip
48 | Check the [memory](./memory.md), [redis](./redis.md) or [couchbase](./couchbase.md) documentation for more details for advanced provider configuration.
49 | :::
50 |
51 | ## `Provider` reference
52 |
53 | ### `name`
54 |
55 | The name of the provider.
56 | Will try to load the package with `strapi-rest-cache-provider-` and fallback with ``, so you can either use a package name or an absolute path.
57 |
58 | - **Type:** `string`
59 | - **Default:** `'memory'`
60 |
61 | ### `getTimeout`
62 |
63 | Time in milliseconds to wait for the provider to respond on cache lookup requests, if the provider is not responding, the cache will be considered as a miss
64 |
65 | - **Type:** `number`
66 | - **Default:** `500`
67 |
68 | ### `options`
69 |
70 | Object passed to the provider constructor.
71 |
72 | - **Type:** `any`
73 | - **Default:** `{}`
74 |
--------------------------------------------------------------------------------
/docs/guide/provider/memory.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Memory provider
3 | ---
4 |
5 | # Memory provider
6 |
7 | The memory provider allow you to store cached content in memory. It use a simple key-value store with LRU algorithm provided by the default provider of [`node-cache-manager`](https://github.com/BryanDonovan/node-cache-manager) module which uses [`lru-node`](https://github.com/isaacs/node-lru-cache/tree/v6.0.0).
8 |
9 | ## Installation
10 |
11 | ::: info
12 | This provider is already installed with the plugin.
13 | :::
14 |
15 | ## Configuration
16 |
17 | ```js {6-16}
18 | // file: /config/plugins.js
19 |
20 | module.exports = ({ env }) => ({
21 | 'rest-cache': {
22 | config: {
23 | provider: {
24 | name: 'memory',
25 | getTimeout: 500,
26 | options: {
27 | // The maximum size of the cache
28 | max: 32767,
29 | // Update to the current time whenever it is retrieved from cache, causing it to not expire
30 | updateAgeOnGet: false,
31 | // ...
32 | },
33 | },
34 | strategy: {
35 | // ...
36 | },
37 | },
38 | },
39 | });
40 | ```
41 |
42 | ::: tip
43 | View full options available on [`lru-cache`](https://github.com/isaacs/node-lru-cache/tree/v6.0.0#options) documentation.
44 | :::
45 |
--------------------------------------------------------------------------------
/docs/guide/provider/redis.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Redis provider
3 | ---
4 |
5 | # Redis provider
6 |
7 | ## Installation
8 |
9 | ```bash
10 | yarn add \
11 | strapi-plugin-rest-cache \
12 | strapi-plugin-redis \
13 | strapi-provider-rest-cache-redis
14 | ```
15 |
16 | ## Configuration
17 |
18 | ```js
19 | module.exports = {
20 | // Step 1: Configure the redis connection
21 | // @see https://github.com/strapi-community/strapi-plugin-redis
22 | redis: {
23 | // ...
24 | },
25 | // Step 2: Configure the redis cache plugin
26 | "rest-cache": {
27 | config: {
28 | provider: {
29 | name: "redis",
30 | options: {
31 | max: 32767,
32 | connection: "default",
33 | },
34 | },
35 | strategy: {
36 | // if you are using keyPrefix for your Redis, please add
37 | keysPrefix: "",
38 | contentTypes: [
39 | // list of Content-Types UID to cache
40 | "api::category.category",
41 | "api::article.article",
42 | "api::global.global",
43 | "api::homepage.homepage",
44 | ],
45 | },
46 | },
47 | },
48 | };
49 | ```
50 |
51 | ::: warning
52 | Ensure `redis` plugin configuration come before `strapi-plugin-rest-cache`
53 | :::
54 |
--------------------------------------------------------------------------------
/docs/guide/strategy/cache-content-type.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Content types
3 | ---
4 |
5 | # Content types
6 |
7 | The plugin will **only inject cache middleware to Content-Types which have been explicitely enabled**. This can be done by setting the `config.strategy.contentTypes` configuration.
8 |
9 | It accept either a string or an object, so we can configure differently each Content-Type.
10 |
11 | ```js {10-19}
12 | // file: /config/plugins.js
13 |
14 | module.exports = ({ env }) => ({
15 | 'rest-cache': {
16 | config: {,
17 | provider: {
18 | // ...
19 | },
20 | strategy: {
21 | contentTypes: /* @type {(string|CacheContentTypeConfig)[]} */ [
22 | // can be a string (the Content-Type UID)
23 | "api::article.article",
24 |
25 | // or a custom CacheContentTypeConfig object
26 | {
27 | contentType: "api::pages.pages",
28 | // ...
29 | },
30 | ],
31 | },
32 | },
33 | },
34 | });
35 | ```
36 |
37 | ## `CacheContentTypeConfig` reference
38 |
39 | ### `injectDefaultRoutes`
40 |
41 | When enabled, inject [default routes](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest-api.html#api-endpoints) for each content type.
42 |
43 | - **Type:** `boolean`
44 | - **Default:** `true`
45 |
46 | ### `hitpass`
47 |
48 | When true, the cache plugin will not lookup for cache and serve fresh response from backend instead. Also, the response is not stored in the cache.
49 |
50 | - **Type:** `(ctx: Context) => boolean | boolean`
51 | - **Default:** _(inherit from `CachePluginStrategy` if set)_
52 |
53 | ### `routes`
54 |
55 | Additionnal routes to register for this content type.
56 |
57 | - **Type:** [`CacheRouteConfig[]`](./cache-custom-routes.md#cacherouteconfig-reference)
58 | - **Default:** `[]`
59 |
60 | ### `contentType`
61 |
62 | Content-Type UID to cache (e.g. `api::article.article`).
63 |
64 | - **Type:** `string`
65 | - **Default:** `''`
66 |
67 | ### `keys`
68 |
69 | Options used to generate the cache keys.
70 |
71 | - **Type:** [`CacheKeysConfig`](./cache-keys.md#cachekeysconfig-reference)
72 | - **Default:** _(inherit from `CachePluginStrategy` if set)_
73 |
74 | ### `maxAge`
75 |
76 | Default max age for cached entries.
77 |
78 | - **Type:** `number`
79 | - **Default:** _(inherit from `CachePluginStrategy` if set)_
80 |
--------------------------------------------------------------------------------
/docs/guide/strategy/cache-custom-routes.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Cache custom routes
3 | ---
4 |
5 | # {{ $frontmatter.title }}
6 |
7 | By default the plugin registers a middleware to intercept all [predefined routes](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest-api.html#api-endpoints), but you can also enable it on custom routes.
8 |
9 | ```js {13-18}
10 | // file: /config/plugins.js
11 |
12 | module.exports = ({ env }) => ({
13 | 'rest-cache': {
14 | config: {,
15 | provider: {
16 | // ...
17 | },
18 | strategy: {
19 | contentTypes: [
20 | {
21 | contentType: "api::pages.pages",
22 | routes: /* @type {CacheRouteConfig[]} */ [
23 | {
24 | path: '/api/pages/slug/:slug+', // note that we set the /api prefix here
25 | method: 'GET', // can be omitted, defaults to GET
26 | },
27 | ],
28 | },
29 | ],
30 | },
31 | },
32 | },
33 | });
34 | ```
35 |
36 | ::: warning
37 | At this time a custom route can only be registered within a single Content-Type.
38 | :::
39 |
40 | ## `CacheRouteConfig` reference
41 |
42 | ### `path`
43 |
44 | Refer to an [existing route path in strapi](https://docs.strapi.io/developer-docs/latest/development/backend-customization/routes.html) on which the cache middleware will be registered.
45 | A warning will be displayed if the path does not exist.
46 |
47 | - **Type:** `string`
48 | - **Default:** `GET`
49 |
50 | ### `method`
51 |
52 | Refer to an [existing route method in strapi](https://docs.strapi.io/developer-docs/latest/development/backend-customization/routes.html) on which the cache middleware will be registered.
53 | A warning will be displayed if the path does not exist.
54 |
55 | - **Type:** `'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'`
56 | - **Default:** `GET`
57 |
58 | ::: tip
59 | Cache lookup is performed only on `GET` requests, and cache invalidation is performed on all other requests.
60 | :::
61 |
62 | ### `hitpass`
63 |
64 | When true, the cache plugin will not lookup for cache and serve fresh response from backend instead. Also, the response is not stored in the cache.
65 |
66 | - **Type:** `(ctx: Context) => boolean | boolean`
67 | - **Default:** _(inherit from `CacheContentTypeConfig` if set)_
68 |
69 | ### `keys`
70 |
71 | Options used to generate the cache keys.
72 |
73 | - **Type:** [`CacheKeysConfig`](./cache-keys.md#cachekeysconfig-reference)
74 | - **Default:** _(inherit from `CacheContentTypeConfig` if set)_
75 |
76 | ### `maxAge`
77 |
78 | Default max age for cached entries.
79 |
80 | - **Type:** `number`
81 | - **Default:** _(inherit from `CacheContentTypeConfig` if set)_
82 |
--------------------------------------------------------------------------------
/docs/guide/strategy/cache-keys.md:
--------------------------------------------------------------------------------
1 | # Cache keys configuration
2 |
3 | By default, the cache plugin will compute a cache key based on the request method, the request path and the request query parameters.
4 |
5 | You can customize this behavior by providing a `keys` option in either the `CachePluginStrategy` to customize global behavior, or on each route in `CacheRouteConfig` so that you can customize the behavior for each route.
6 |
7 | ::::code-group
8 |
9 | ```js {13-16} [public cache]
10 | // file: /config/plugins.js
11 |
12 | module.exports = ({ env }) => ({
13 | 'rest-cache': {
14 | config: {,
15 | provider: {
16 | // ...
17 | },
18 | strategy: {
19 | contentTypes: [
20 | {
21 | contentType: 'api::homepage.homepage',
22 | hitpass: false, // never check if we should bypass the cache
23 | keys: {
24 | useQueryParams: false, // disable query parameters in cache keys
25 | },
26 | },
27 | ],
28 | },
29 | },
30 | },
31 | });
32 | ```
33 |
34 | ```js {13-16} [user cache]
35 | // file: /config/plugins.js
36 |
37 | module.exports = ({ env }) => ({
38 | 'rest-cache': {
39 | config: {,
40 | provider: {
41 | // ...
42 | },
43 | strategy: {
44 | contentTypes: [
45 | {
46 | contentType: 'api::orders.orders',
47 | hitpass: false, // never check if we should bypass the cache
48 | keys: {
49 | useHeaders: ['authorization'], // use the authorization header value in cache keys
50 | },
51 | },
52 | ],
53 | },
54 | },
55 | },
56 | });
57 | ```
58 |
59 | ::::
60 |
61 | ::: warning
62 | When using `authorization` header in cache keys, you will not be able to clear the cache for a specific user.
63 | :::
64 |
65 | ## `CacheKeysConfig` reference
66 |
67 | ### `useQueryParams`
68 |
69 | When set to `true`, all query parameters will be used to generate the cache key.
70 | If an array is provided, only the query parameters specified in the array will be used.
71 | You can totally disable query parameters by setting this option to `false`.
72 |
73 | - **Type:** `boolean|string[]`
74 | - **Default:** `true`
75 |
76 | ### `useHeaders`
77 |
78 | Headers to use to generate the cache key.
79 |
80 | - **Type:** `string[]`
81 | - **Default:** `[]`
82 |
--------------------------------------------------------------------------------
/docs/guide/strategy/debug.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Debug mode
3 | ---
4 |
5 | # Debug mode
6 |
7 | This plugins use [debug](https://www.npmjs.com/package/debug) module to log messages that can help during development.
8 | You can enable debug mode by setting the environment variable `DEBUG=strapi:strapi-plugin-rest-cache` before starting strapi.
9 |
10 | eg. `DEBUG=strapi:strapi-plugin-rest-cache yarn strapi develop`
11 |
12 | You can also enable debug mode by setting the [`config.strategy.debug`](./index.md#debug) configuration option to `true`.
13 |
--------------------------------------------------------------------------------
/docs/guide/strategy/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Cache strategy configuration
3 | ---
4 |
5 | # Cache strategy configuration
6 |
7 | The plugin will **only inject cache middleware to Content-Types which have been explicitely enabled**. This can be done by setting the `config.strategy.contentTypes` configuration.
8 |
9 | It accept either a string or an object, so we can configure differently each Content-Type.
10 |
11 | ```js {9-14}
12 | // file: /config/plugins.js
13 |
14 | module.exports = ({ env }) => ({
15 | 'rest-cache': {
16 | config: {,
17 | provider: {
18 | // ...
19 | },
20 | strategy: /* @type {CachePluginStrategy} */ {
21 | keysPrefix: 'project-name',
22 | maxAge: 3600000,
23 | debug: true,
24 | contentTypes: [ /** ... */ ],
25 | },
26 | },
27 | },
28 | });
29 | ```
30 |
31 | In addition to the **contentType** configuration, you can also set the default **maxAge**, **hitpass** and **keys** configuration, enables **ETag** and **X-Cache** headers or tune how the plugin will work for each route.
32 |
33 | ::: warning
34 | The plugin will not cache any request if the `Authorization` header is present on the request or if the `Cookie` header is present on the request. This is to prevent caching of private data.
35 |
36 | You can change this behavior by setting the `config.strategy.hitpass` configuration.
37 | :::
38 |
39 | ## `CachePluginStrategy` reference
40 |
41 | ### `debug`
42 |
43 | Enable extra log with [debug](https://www.npmjs.com/package/debug) package. This is usefull only when configuring the plugin.
44 |
45 | - **Type:** `boolean`
46 | - **Default:** `false`
47 |
48 | ### `enableEtag`
49 |
50 | Enable etag generation for response. Also enable etag lookup when `If-None-Match` header is present on requests.
51 | This add extra CPU overhead due to the etag computation but save bandwidth by sending `304 Not Modified` response.
52 |
53 | - **Type:** `boolean`
54 | - **Default:** `false`
55 |
56 | ### `enableXCacheHeaders`
57 |
58 | Add extra `X-Cache` headers to responses. This is usefull when configuring the plugin or when using behind a reverse proxy.
59 |
60 | - **Type:** `boolean`
61 | - **Default:** `false`
62 |
63 | ### `enableAdminCTBMiddleware`
64 |
65 | Register a middleware to handle cache invalidation requests performed using the admin UI.
66 |
67 | - **Type:** `boolean`
68 | - **Default:** `true`
69 |
70 | ### `resetOnStartup`
71 |
72 | Delete all cache entries from the provider on startup. This is usefull when performing a migration using an external cache provider.
73 |
74 | - **Type:** `boolean`
75 | - **Default:** `false`
76 |
77 | ### `clearRelatedCache`
78 |
79 | Try to delete all cache entries related to the deleted entry.
80 |
81 | - **Type:** `boolean`
82 | - **Default:** `true`
83 |
84 | ### `keysPrefix`
85 |
86 | Prefix added to the cache keys.
87 |
88 | - **Type:** `string`
89 | - **Default:** `''`
90 |
91 | ### `hitpass`
92 |
93 | When true, the cache plugin will not lookup for cache and serve fresh response from backend instead. Also, the response is not stored in the cache.
94 |
95 | - **Type:** `(ctx: Context) => boolean`
96 | - **Default:**
97 |
98 | ```js
99 | function hitpass(ctx) {
100 | // ignore cache when authorization or cookie headers are present
101 | return Boolean(
102 | ctx.request.headers.authorization || ctx.request.headers.cookie
103 | );
104 | }
105 | ```
106 |
107 | ### `keys`
108 |
109 | Options used to generate the cache keys.
110 |
111 | - **Type:** [`CacheKeysConfig`](#cachekeysconfig)
112 |
113 | ### `maxAge`
114 |
115 | Default max age for cached entries.
116 |
117 | - **Type:** `number`
118 | - **Default:** `3600000` (1 hour)
119 |
120 | ### `contentTypes`
121 |
122 | Specify each content types that should be cached. If a string is provided, default configuration from [`CacheContentTypeConfig`](#cachecontenttypeconfig) will be used
123 |
124 | - **Type:** [`(string|CacheContentTypeConfig)[]`](#cachecontenttypeconfig)
125 | - **Default:** `[]`
126 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: home
3 |
4 | hero:
5 | name: REST Cache
6 | text: API cache for Strapi
7 | tagline: Speed-up HTTP requests with LRU cache
8 | image:
9 | src: /fluent-emoji-cloud-with-lightning.svg
10 | alt: ""
11 | actions:
12 | - theme: brand
13 | text: Guide
14 | link: /guide/
15 | - theme: alt
16 | text: View on GitHub
17 | link: https://github.com/strapi-community/strapi-plugin-rest-cache
18 | features:
19 | - icon: ⚡
20 | title: Respond in ~1ms
21 | details: Give your Strapi blazing fast response times with this plugin.
22 | - icon: 🔀
23 | title: Cache storage providers
24 | details: Choose between in-memory, redis or couchbase to store your cached content.
25 | - icon: 🛠️
26 | title: Customizable
27 | details: Want more? Use the internal API or add your own custom cache storage engine.
28 | ---
29 |
--------------------------------------------------------------------------------
/docs/public/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-rest-cache/7e08dc4715b0c231b9f6646045b5c9a8674b58fd/docs/public/icon.png
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = async () => ({
4 | verbose: true,
5 | });
6 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "packages": ["packages/*", "playgrounds/*"],
3 | "version": "4.2.9",
4 | "npmClient": "yarn",
5 | "useWorkspaces": true
6 | }
7 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@strapi-plugin-rest-cache/monorepo",
3 | "private": true,
4 | "version": "1.0.0",
5 | "description": "Speed-up HTTP requests with LRU cache",
6 | "workspaces": [
7 | "./packages/*",
8 | "./playgrounds/*"
9 | ],
10 | "scripts": {
11 | "postinstall": "run-s postinstall:*",
12 | "postinstall:memory": "cpy . ../playgrounds/memory/ --cwd=shared",
13 | "postinstall:redis": "cpy . ../playgrounds/redis/ --cwd=shared",
14 | "postinstall:couchbase": "cpy . ../playgrounds/couchbase/ --cwd=shared",
15 | "docs:dev": "vitepress dev docs",
16 | "docs:build": "vitepress build docs",
17 | "docs:serve": "vitepress serve docs",
18 | "dev:memory": "yarn workspace @strapi-plugin-rest-cache/playground-memory develop",
19 | "dev:redis": "yarn workspace @strapi-plugin-rest-cache/playground-redis develop",
20 | "dev:couchbase": "yarn workspace @strapi-plugin-rest-cache/playground-couchbase develop",
21 | "profile:memory": "cd ./playgrounds/memory && 0x -o -D .profile -P 'autocannon --warmup [ -c 1 -d 3 ] -c 100 -p 10 -d 120 http://localhost:1337/api/homepage?populate=*' start-profiler.js",
22 | "profile:redis": "cd ./playgrounds/redis && 0x -o -D .profile -P 'autocannon --warmup [ -c 1 -d 3 ] -c 100 -p 10 -d 120 http://localhost:1337/api/homepage?populate=*' start-profiler.js",
23 | "profile:couchbase": "cd ./playgrounds/couchbase && 0x -o -D .profile -P 'autocannon --warmup [ -c 1 -d 3 ] -c 100 -p 10 -d 120 http://localhost:1337/api/homepage?populate=*' start-profiler.js",
24 | "lint": "lerna run lint --stream",
25 | "test:lint": "lerna run test:lint --stream",
26 | "test:e2e": "run-s test:e2e:*",
27 | "test:e2e:memory": "yarn workspace @strapi-plugin-rest-cache/playground-memory test:e2e",
28 | "test:e2e:redis": "yarn workspace @strapi-plugin-rest-cache/playground-redis test:e2e",
29 | "test:e2e:couchbase": "yarn workspace @strapi-plugin-rest-cache/playground-couchbase test:e2e"
30 | },
31 | "license": "MIT",
32 | "resolutions": {
33 | "**/colors": "1.4.0",
34 | "semver": "7.5.4",
35 | "vuepress-vite": "2.0.0-beta.66",
36 | "d3-color": "3.1.0"
37 | },
38 | "devDependencies": {
39 | "0x": "^5.5.0",
40 | "@giscus/vue": "^2.2.6",
41 | "@vuepress/plugin-register-components": "^2.0.0-beta.36",
42 | "@vuepress/plugin-search": "^2.0.0-beta.36",
43 | "autocannon": "^7.7.1",
44 | "copyfiles": "^2.4.1",
45 | "cpy-cli": "^4.1.0",
46 | "eslint": "^8.11.0",
47 | "eslint-config-prettier": "^8.8.0",
48 | "eslint-plugin-import": "^2.27.5",
49 | "jest": "^29.6.1",
50 | "lerna": "^5.0.0",
51 | "lint-staged": "^12.3.7",
52 | "mermaid": "^9.4.0",
53 | "mime-types": "^2.1.35",
54 | "npm-run-all": "^4.1.5",
55 | "prettier": "^2.6.0",
56 | "supertest": "^6.3.3",
57 | "vitepress": "^1.0.0-alpha.33",
58 | "vue": "^3.2.45",
59 | "vuepress": "^2.0.0-beta.36",
60 | "yorkie": "^2.0.0"
61 | },
62 | "engines": {
63 | "node": ">=14.0.0",
64 | "npm": ">=6.0.0"
65 | },
66 | "lint-staged": {
67 | "{packages,playgrounds}/**/*.{ts,js}": [
68 | "prettier --write"
69 | ],
70 | "docs/**/*.md": [
71 | "prettier --write"
72 | ]
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "es5",
3 | "singleQuote": true
4 | }
5 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/README.md:
--------------------------------------------------------------------------------
1 |
2 |
Strapi REST Cache Plugin
3 |
4 |
Speed-up HTTP requests with LRU cache.
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | ## Table of Contents
17 |
18 | - [🚦 Current Status](#-current-status)
19 | - [✨ Features](#-features)
20 | - [🤔 Motivation](#-motivation)
21 | - [🖐 Requirements](#-requirements)
22 | - [🚚 Getting Started](#-getting-started)
23 | - [Contributing](#contributing)
24 | - [License](#license)
25 |
26 | ## 🚦 Current Status
27 |
28 | This package is currently under development and should be consider **ALPHA** in terms of state. I/We are currently accepting contributions and/or dedicated contributors to help develop and maintain this package.
29 |
30 | ## ✨ Features
31 |
32 | This plugin provide a way to cache **HTTP requests** in order to **improve performance**. It's get inspired by varnish cache which is a popular caching solution.
33 |
34 | The cache content is stored by a **provider**, which can be either an in-memory provider, a redis connection, a file system, or any other custom provider.
35 | You can set a **strategy** to tell what to cache and how much time responses should be cached. The cache will be invalidated when the related Content-Type is updated, so you **never have to worry about stale data**.
36 |
37 | ## 🖐 Requirements
38 |
39 | Supported Strapi Versions:
40 |
41 | - Strapi v4.0.x (recently tested as of January 2022)
42 | - Strapi v4.x.x (Assumed, but possibly not tested)
43 |
44 | **If you are looking for a plugin for Strapi v3.x, please check the [strapi-middleware-cache](https://github.com/patrixr/strapi-middleware-cache/).**
45 |
46 | ## 🚚 Getting Started
47 |
48 | [Read the Docs to Learn More.](https://strapi-community.github.io/strapi-plugin-rest-cache/)
49 |
50 | ## Contributing
51 |
52 | I/We are actively looking for contributors, maintainers, and others to help shape this package. As this plugins sole purpose within the Strapi community is to be used by other developers and plugin maintainers to get fast responses time.
53 |
54 | If interested please feel free to email the lead maintainer Sacha at: sacha@digisquad.io or ping `stf#3254` on Discord.
55 |
56 | ## License
57 |
58 | See the [LICENSE](./LICENSE.md) file for licensing information.
59 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/admin/src/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@strapi-community/admin"
3 | }
4 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/admin/src/components/EditViewInfoInjectedComponent/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useCMEditViewDataManager, useRBAC } from '@strapi/helper-plugin';
3 |
4 | import cachePermissions from '../../permissions';
5 | import EntityCacheInformation from '../EntityCacheInformation';
6 |
7 | function EditViewInfoInjectedComponent() {
8 | const { allowedActions } = useRBAC(cachePermissions);
9 | const { slug } = useCMEditViewDataManager();
10 |
11 | if (!allowedActions.canReadStrategy) {
12 | return null;
13 | }
14 |
15 | return ;
16 | }
17 |
18 | export default EditViewInfoInjectedComponent;
19 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/admin/src/components/EditViewInjectedComponent/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useCMEditViewDataManager, useRBAC } from '@strapi/helper-plugin';
3 | import cachePermissions from '../../permissions';
4 | import PurgeCacheButton from '../PurgeCacheButton';
5 |
6 | function EditViewInjectedComponent() {
7 | const { allowedActions } = useRBAC(cachePermissions);
8 |
9 | const {
10 | slug,
11 | isCreatingEntry,
12 | hasDraftAndPublish,
13 | initialData,
14 | isSingleType,
15 | } = useCMEditViewDataManager();
16 |
17 | if (isCreatingEntry) {
18 | return null;
19 | }
20 |
21 | if (hasDraftAndPublish && initialData.publishedAt === null) {
22 | return null;
23 | }
24 |
25 | if (!allowedActions.canReadStrategy || !allowedActions.canPurge) {
26 | return null;
27 | }
28 |
29 | return (
30 |
35 | );
36 | }
37 |
38 | export default EditViewInjectedComponent;
39 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/admin/src/components/EntityCacheInformation/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { useIntl } from 'react-intl';
4 | import { Status } from '@strapi/design-system/Status';
5 | import { Typography } from '@strapi/design-system/Typography';
6 | import { Box } from '@strapi/design-system/Box';
7 |
8 | import { useCacheStrategy } from '../../hooks';
9 |
10 | function EntityCacheInformation({ contentType }) {
11 | const { strategy } = useCacheStrategy();
12 | const { formatMessage } = useIntl();
13 |
14 | if (
15 | !strategy?.contentTypes?.find(
16 | (config) => config.contentType === contentType
17 | )
18 | ) {
19 | return null;
20 | }
21 |
22 | return (
23 |
24 |
25 |
26 | {formatMessage({
27 | id: 'cache.info-box.entity-cached',
28 | defaultMessage: 'This entity is cached via REST Cache plugin',
29 | })}
30 |
31 |
32 |
33 | );
34 | }
35 |
36 | EntityCacheInformation.propTypes = {
37 | contentType: PropTypes.string.isRequired,
38 | };
39 |
40 | export default EntityCacheInformation;
41 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/admin/src/components/Initializer/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * Initializer
4 | *
5 | */
6 |
7 | import { useEffect, useRef } from 'react';
8 | import PropTypes from 'prop-types';
9 | import pluginId from '../../pluginId';
10 |
11 | function Initializer({ setPlugin }) {
12 | const ref = useRef();
13 | ref.current = setPlugin;
14 |
15 | useEffect(() => {
16 | ref.current(pluginId);
17 | }, []);
18 |
19 | return null;
20 | }
21 |
22 | Initializer.propTypes = {
23 | setPlugin: PropTypes.func.isRequired,
24 | };
25 |
26 | export default Initializer;
27 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/admin/src/components/ListViewInjectedComponent/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | // import { useIntl } from 'react-intl';
3 | // import { Button } from '@strapi/design-system/Button';
4 | // import Refresh from '@strapi/icons/Refresh';
5 | import {
6 | // ConfirmDialog,
7 | // useNotification,
8 | // hasPermissions,
9 | // useRBACProvider,
10 | // useCMEditViewDataManager,
11 | useRBAC,
12 | // request,
13 | } from '@strapi/helper-plugin';
14 | import { useRouteMatch } from 'react-router-dom';
15 | // import cachePermissions from '../../permissions';
16 | import cachePermissions from '../../permissions';
17 | import PurgeCacheButton from '../PurgeCacheButton';
18 |
19 | function ListViewInjectedComponent() {
20 | const {
21 | params: { slug },
22 | } = useRouteMatch('/content-manager/:kind/:slug?');
23 | const { allowedActions } = useRBAC(cachePermissions);
24 |
25 | if (!allowedActions.canReadStrategy || !allowedActions.canPurge) {
26 | return null;
27 | }
28 |
29 | return ;
30 | }
31 |
32 | export default ListViewInjectedComponent;
33 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/admin/src/components/PluginIcon/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Information from '@strapi/icons/Information';
3 |
4 | function PluginIcon() {
5 | return ;
6 | }
7 |
8 | export default PluginIcon;
9 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/admin/src/components/PurgeCacheButton/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { useIntl } from 'react-intl';
3 | import { Button } from '@strapi/design-system/Button';
4 | import Refresh from '@strapi/icons/Refresh';
5 | import { ConfirmDialog, useNotification, request } from '@strapi/helper-plugin';
6 | import PropTypes from 'prop-types';
7 |
8 | import pluginId from '../../pluginId';
9 | import { useCacheStrategy } from '../../hooks';
10 |
11 | function PurgeCacheButton({ contentType, params, wildcard }) {
12 | const { strategy } = useCacheStrategy();
13 |
14 | const [showConfirmModal, setShowConfirmModal] = useState(false);
15 | const [isModalConfirmButtonLoading, setIsModalConfirmButtonLoading] =
16 | useState(false);
17 | const { formatMessage } = useIntl();
18 | const toggleNotification = useNotification();
19 |
20 | const abortController = new AbortController();
21 | const { signal } = abortController;
22 |
23 | useEffect(() => {
24 | return () => {
25 | abortController.abort();
26 | };
27 | // eslint-disable-next-line react-hooks/exhaustive-deps
28 | }, []);
29 |
30 | const toggleConfirmModal = () =>
31 | setShowConfirmModal((prevState) => !prevState);
32 |
33 | const handleConfirmDelete = async () => {
34 | try {
35 | // Show the loading state
36 | setIsModalConfirmButtonLoading(true);
37 |
38 | await request(`/${pluginId}/purge`, {
39 | method: 'POST',
40 | signal,
41 | body: {
42 | contentType,
43 | params,
44 | wildcard,
45 | },
46 | });
47 |
48 | toggleNotification({
49 | type: 'success',
50 | message: {
51 | id: 'cache.purge.success',
52 | defaultMessage: 'Cache purged successfully',
53 | },
54 | });
55 |
56 | setIsModalConfirmButtonLoading(false);
57 |
58 | toggleConfirmModal();
59 | } catch (err) {
60 | const errorMessage = err?.response?.payload?.error?.message;
61 | setIsModalConfirmButtonLoading(false);
62 | toggleConfirmModal();
63 |
64 | if (errorMessage) {
65 | toggleNotification({
66 | type: 'warning',
67 | message: { id: 'cache.purge.error', defaultMessage: errorMessage },
68 | });
69 | } else {
70 | toggleNotification({
71 | type: 'warning',
72 | message: { id: 'notification.error' },
73 | });
74 | }
75 | }
76 | };
77 |
78 | if (
79 | !strategy?.contentTypes?.find(
80 | (config) => config.contentType === contentType
81 | )
82 | ) {
83 | return null;
84 | }
85 |
86 | return (
87 | <>
88 | }
92 | variant="danger"
93 | >
94 | {formatMessage({
95 | id: 'cache.purge.delete-entry',
96 | defaultMessage: 'Purge REST Cache',
97 | })}
98 |
99 | }
114 | rightButtonText={{
115 | id: 'cache.purge.confirm-modal-confirm',
116 | defaultMessage: 'Purge REST Cache',
117 | }}
118 | />
119 | >
120 | );
121 | }
122 |
123 | PurgeCacheButton.propTypes = {
124 | contentType: PropTypes.string.isRequired,
125 | params: PropTypes.object,
126 | wildcard: PropTypes.bool,
127 | };
128 | PurgeCacheButton.defaultProps = {
129 | params: {},
130 | wildcard: undefined,
131 | };
132 |
133 | export default PurgeCacheButton;
134 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/admin/src/hooks/index.js:
--------------------------------------------------------------------------------
1 | export { default as useCacheStrategy } from './useCacheStrategy';
2 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/admin/src/hooks/useCacheStrategy/index.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useReducer, useRef } from 'react';
2 | import { request, useNotification } from '@strapi/helper-plugin';
3 | import init from './init';
4 | import pluginId from '../../pluginId';
5 | import reducer, { initialState } from './reducer';
6 |
7 | const useCacheStrategy = (shouldFetchData = true) => {
8 | const [{ strategy, isLoading }, dispatch] = useReducer(
9 | reducer,
10 | initialState,
11 | () => init(initialState, shouldFetchData)
12 | );
13 | const toggleNotification = useNotification();
14 |
15 | const isMounted = useRef(true);
16 | const abortController = new AbortController();
17 | const { signal } = abortController;
18 |
19 | useEffect(() => {
20 | if (shouldFetchData) {
21 | fetchCacheStrategy();
22 | }
23 |
24 | return () => {
25 | abortController.abort();
26 | isMounted.current = false;
27 | };
28 | // eslint-disable-next-line react-hooks/exhaustive-deps
29 | }, [shouldFetchData]);
30 |
31 | const fetchCacheStrategy = async () => {
32 | try {
33 | dispatch({
34 | type: 'GET_DATA',
35 | });
36 |
37 | const { strategy } = await request(`/${pluginId}/config/strategy`, {
38 | method: 'GET',
39 | signal,
40 | });
41 |
42 | dispatch({
43 | type: 'GET_DATA_SUCCEEDED',
44 | data: strategy,
45 | });
46 | } catch (err) {
47 | const message = err?.response?.payload?.message ?? 'An error occured';
48 |
49 | if (isMounted.current) {
50 | dispatch({
51 | type: 'GET_DATA_ERROR',
52 | });
53 |
54 | if (message !== 'Forbidden') {
55 | toggleNotification({
56 | type: 'warning',
57 | message,
58 | });
59 | }
60 | }
61 | }
62 | };
63 |
64 | return { strategy, isLoading, getData: fetchCacheStrategy };
65 | };
66 |
67 | export default useCacheStrategy;
68 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/admin/src/hooks/useCacheStrategy/init.js:
--------------------------------------------------------------------------------
1 | const init = (initialState, shouldFetchData) => ({
2 | ...initialState,
3 | isLoading: shouldFetchData,
4 | });
5 |
6 | export default init;
7 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/admin/src/hooks/useCacheStrategy/reducer.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable consistent-return */
2 | import produce from 'immer';
3 |
4 | export const initialState = {
5 | strategy: {},
6 | isLoading: true,
7 | };
8 |
9 | const reducer = (state, action) =>
10 | produce(state, (draftState) => {
11 | switch (action.type) {
12 | case 'GET_DATA': {
13 | draftState.isLoading = true;
14 | draftState.strategy = {};
15 | break;
16 | }
17 | case 'GET_DATA_SUCCEEDED': {
18 | draftState.strategy = action.data;
19 | draftState.isLoading = false;
20 | break;
21 | }
22 | case 'GET_DATA_ERROR': {
23 | draftState.isLoading = false;
24 | break;
25 | }
26 | default:
27 | return draftState;
28 | }
29 | });
30 |
31 | export default reducer;
32 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/admin/src/index.js:
--------------------------------------------------------------------------------
1 | import { prefixPluginTranslations } from '@strapi/helper-plugin';
2 | import pluginPkg from '../../package.json';
3 | import pluginId from './pluginId';
4 |
5 | import Initializer from './components/Initializer';
6 | import EditViewInfoInjectedComponent from './components/EditViewInfoInjectedComponent';
7 | import EditViewInjectedComponent from './components/EditViewInjectedComponent';
8 | import ListViewInjectedComponent from './components/ListViewInjectedComponent';
9 |
10 | const { name } = pluginPkg.strapi;
11 |
12 | export default {
13 | register(app) {
14 | app.registerPlugin({
15 | id: pluginId,
16 | initializer: Initializer,
17 | isReady: true,
18 | name,
19 | });
20 | },
21 | bootstrap(app) {
22 | app.injectContentManagerComponent('editView', 'informations', {
23 | name: 'EditViewInfoInjectedComponent',
24 | Component: EditViewInfoInjectedComponent,
25 | });
26 | app.injectContentManagerComponent('editView', 'right-links', {
27 | name: 'EditViewInjectedComponent',
28 | Component: EditViewInjectedComponent,
29 | });
30 | app.injectContentManagerComponent('listView', 'actions', {
31 | name: 'ListViewInjectedComponent',
32 | Component: ListViewInjectedComponent,
33 | });
34 | },
35 | async registerTrads({ locales }) {
36 | const importedTrads = await Promise.all(
37 | locales.map((locale) =>
38 | import(`./translations/${locale}.json`)
39 | .then(({ default: data }) => ({
40 | data: prefixPluginTranslations(data, pluginId),
41 | locale,
42 | }))
43 | .catch(() => ({
44 | data: {},
45 | locale,
46 | }))
47 | )
48 | );
49 |
50 | return Promise.resolve(importedTrads);
51 | },
52 | };
53 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/admin/src/pages/App/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * This component is the skeleton around the actual pages, and should only
4 | * contain code that should be seen on all pages. (e.g. navigation bar)
5 | *
6 | */
7 |
8 | import React from 'react';
9 | import { Switch, Route } from 'react-router-dom';
10 | import { NotFound } from '@strapi/helper-plugin';
11 | import pluginId from '../../pluginId';
12 | import HomePage from '../HomePage';
13 |
14 | function App() {
15 | return (
16 |
17 |
18 |
19 |
20 |
21 |
22 | );
23 | }
24 |
25 | export default App;
26 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/admin/src/pages/HomePage/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * HomePage
4 | *
5 | */
6 |
7 | import React, { memo } from 'react';
8 | import PurgeCacheButton from '../../components/PurgeCacheButton';
9 | // import PropTypes from 'prop-types';
10 | import pluginId from '../../pluginId';
11 |
12 | function HomePage() {
13 | return (
14 |
15 |
{pluginId}'s HomePage
16 |
Happy coding
17 |
18 |
19 | );
20 | }
21 |
22 | export default memo(HomePage);
23 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/admin/src/permissions.js:
--------------------------------------------------------------------------------
1 | // import pluginId from './pluginId';
2 |
3 | const pluginPermissions = {
4 | purge: [{ action: `plugin::rest-cache.cache.purge`, subject: null }],
5 | readStrategy: [
6 | {
7 | action: `plugin::rest-cache.cache.read-strategy`,
8 | subject: null,
9 | },
10 | ],
11 | readProvider: [
12 | {
13 | action: `plugin::rest-cache.cache.read-provider`,
14 | subject: null,
15 | },
16 | ],
17 | };
18 |
19 | export default pluginPermissions;
20 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/admin/src/pluginId.js:
--------------------------------------------------------------------------------
1 | import pluginPkg from '../../package.json';
2 |
3 | // const pluginId = pluginPkg.name.replace(/^strapi-plugin-/i, '');
4 |
5 | export default pluginPkg.strapi.name;
6 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/admin/src/translations/en.json:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/admin/src/translations/fr.json:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "strapi-plugin-rest-cache",
3 | "version": "4.2.9",
4 | "description": "Speed-up HTTP requests with LRU cache",
5 | "license": "MIT",
6 | "strapi": {
7 | "displayName": "REST Cache",
8 | "name": "rest-cache",
9 | "description": "Speed-up HTTP requests with LRU cache",
10 | "kind": "plugin"
11 | },
12 | "keywords": [
13 | "strapi",
14 | "plugin",
15 | "rest",
16 | "cache",
17 | "http",
18 | "lru"
19 | ],
20 | "files": [
21 | "admin/**/*.js",
22 | "admin/**/*.json",
23 | "server/**/*.js",
24 | "strapi-admin.js",
25 | "strapi-server.js"
26 | ],
27 | "author": {
28 | "name": "Strapi Community",
29 | "url": "https://github.com/strapi-community/"
30 | },
31 | "maintainers": [
32 | {
33 | "name": "Sacha Stafyniak",
34 | "email": "sacha@digisquad.io",
35 | "url": "https://digisquad.io"
36 | },
37 | {
38 | "name": "Patrick R",
39 | "url": "https://github.com/patrixr/"
40 | },
41 | {
42 | "name": "Davide Pellegatta",
43 | "email": "davide.pellegatta@gmail.com"
44 | }
45 | ],
46 | "repository": {
47 | "type": "git",
48 | "url": "git+https://github.com/strapi-community/strapi-plugin-rest-cache.git",
49 | "directory": "packages/strapi-plugin-rest-cache"
50 | },
51 | "bugs": {
52 | "url": "https://github.com/strapi-community/strapi-plugin-rest-cache/issues"
53 | },
54 | "homepage": "https://strapi-community.github.io/strapi-plugin-rest-cache/",
55 | "scripts": {
56 | "lint": "run-s eslint:server:fix prettier:fix",
57 | "eslint:server": "eslint ./server",
58 | "eslint:server:fix": "eslint ./server --fix",
59 | "prettier": "prettier --check ./{admin,server}/**/*",
60 | "prettier:fix": "prettier --write ./{admin,server}/**/*",
61 | "test": "run-s test:*",
62 | "test:lint": "run-s eslint:server prettier"
63 | },
64 | "dependencies": {
65 | "@koa/router": "^10.1.1",
66 | "chalk": "^4.1.2",
67 | "debug": "^4.3.4",
68 | "lodash": "^4.17.21",
69 | "path": "^0.12.7",
70 | "strapi-provider-rest-cache-memory": "^4.2.9"
71 | },
72 | "devDependencies": {
73 | "@strapi/strapi": "^4.11.7",
74 | "koa": "^2.11.0",
75 | "npm-run-all": "^4.1.5",
76 | "react": "^17.0.2",
77 | "react-intl": "^5.24.7",
78 | "react-redux": "^7.2.2",
79 | "redux": "^4.0.5",
80 | "styled-components": "^5.2.3"
81 | },
82 | "peerDependencies": {
83 | "@strapi/strapi": "^4.0.5"
84 | },
85 | "engines": {
86 | "node": ">=14.0.0",
87 | "npm": ">=6.0.0"
88 | },
89 | "gitHead": "80f7c4b1c3915484e282597292cd1f5c749cbe8f"
90 | }
91 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/bootstrap.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @typedef {import('@strapi/strapi').Strapi} Strapi
5 | */
6 | const chalk = require('chalk');
7 | const debug = require('debug');
8 |
9 | const { CacheProvider } = require('./types');
10 | const { resolveUserStrategy } = require('./utils/config/resolveUserStrategy');
11 | const { createRouter } = require('./utils/middlewares/createRouter');
12 |
13 | const permissionsActions = require('./permissions-actions');
14 |
15 | const createProvider = async (providerConfig, { strapi }) => {
16 | const providerName = providerConfig.name.toLowerCase();
17 | let provider;
18 |
19 | let modulePath;
20 | try {
21 | modulePath = require.resolve(`strapi-provider-rest-cache-${providerName}`);
22 | } catch (error) {
23 | if (error.code === 'MODULE_NOT_FOUND') {
24 | modulePath = providerName;
25 | } else {
26 | throw error;
27 | }
28 | }
29 |
30 | try {
31 | // eslint-disable-next-line
32 | provider = require(modulePath);
33 | } catch (err) {
34 | throw new Error(
35 | `Could not load REST Cache provider "${providerName}". You may need to install a provider plugin "yarn add strapi-provider-rest-cache-${providerName}".`
36 | );
37 | }
38 |
39 | const providerInstance = await provider.init(providerConfig.options, {
40 | strapi,
41 | });
42 |
43 | if (!(providerInstance instanceof CacheProvider)) {
44 | throw new Error(
45 | `Could not load REST Cache provider "${providerName}". The package "strapi-provider-rest-cache-${providerName}" does not export a CacheProvider instance.`
46 | );
47 | }
48 |
49 | return Object.freeze(providerInstance);
50 | };
51 |
52 | /**
53 | * @param {{ strapi: Strapi }} strapi
54 | */
55 | async function bootstrap({ strapi }) {
56 | // resolve user configuration, check for missing or invalid options
57 | const pluginOption = strapi.config.get('plugin.rest-cache');
58 | const cacheStore = strapi.plugin('rest-cache').service('cacheStore');
59 |
60 | if (pluginOption.strategy.debug === true) {
61 | debug.enable('strapi:strapi-plugin-rest-cache');
62 | }
63 |
64 | const strategy = resolveUserStrategy(strapi, pluginOption.strategy);
65 | strapi.config.set('plugin.rest-cache', {
66 | ...pluginOption,
67 | strategy,
68 | });
69 |
70 | debug('strapi:strapi-plugin-rest-cache')('[STRATEGY]: %O', strategy);
71 |
72 | // watch for changes in any roles -> clear all cache
73 | // need to be done before lifecycles are registered
74 | if (strapi.plugin('users-permissions')) {
75 | strapi.db.lifecycles.subscribe({
76 | models: ['plugin::users-permissions.role'],
77 | async beforeDelete() {
78 | await cacheStore.reset();
79 | },
80 | });
81 | }
82 |
83 | // register cache provider
84 | const provider = await createProvider(pluginOption.provider, { strapi });
85 | strapi.plugin('rest-cache').service('cacheStore').init(provider);
86 |
87 | // boostrap plugin permissions
88 | await strapi.admin.services.permission.actionProvider.registerMany(
89 | permissionsActions.actions
90 | );
91 |
92 | // boostrap cache middlewares
93 | const router = createRouter(strapi, strategy);
94 | strapi.server.router.use(router.routes());
95 |
96 | strapi.log.info(
97 | `Using REST Cache plugin with provider "${chalk.cyan(
98 | pluginOption.provider.name
99 | )}"`
100 | );
101 |
102 | if (strategy.resetOnStartup) {
103 | strapi.log.warn('Reset cache on startup is enabled');
104 | await strapi.plugin('rest-cache').service('cacheStore').reset();
105 | }
106 | }
107 |
108 | module.exports = {
109 | bootstrap,
110 | };
111 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/config/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const config = {
4 | default: () => ({
5 | provider: {
6 | name: 'memory',
7 | getTimeout: 500,
8 | options: {},
9 | },
10 | strategy: {
11 | debug: false,
12 | enableEtag: false,
13 | enableXCacheHeaders: false,
14 | enableAdminCTBMiddleware: true,
15 | resetOnStartup: false,
16 | clearRelatedCache: true,
17 | keysPrefix: '',
18 | keys: {
19 | useHeaders: [],
20 | useQueryParams: true,
21 | },
22 | hitpass: (ctx) =>
23 | Boolean(
24 | ctx.request.headers.authorization || ctx.request.headers.cookie
25 | ),
26 | maxAge: 3600000,
27 | contentTypes: [],
28 | },
29 | }),
30 | validator() {},
31 | };
32 |
33 | module.exports = {
34 | config,
35 | };
36 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/controllers/config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @typedef {import('@strapi/strapi').Strapi} Strapi
5 | * @typedef {import('koa').Context} Context
6 | */
7 |
8 | /**
9 | * @param {{ strapi: Strapi }} strapi
10 | */
11 | function createConfigController({ strapi }) {
12 | return {
13 | /**
14 | * @param {Context} ctx
15 | */
16 | async strategy(ctx) {
17 | const { strategy } = strapi.config.get('plugin.rest-cache');
18 | ctx.body = { strategy };
19 | },
20 | /**
21 | * @param {Context} ctx
22 | */
23 | async provider(ctx) {
24 | const { provider } = strapi.config.get('plugin.rest-cache');
25 | ctx.body = { provider };
26 | },
27 | };
28 | }
29 | module.exports = {
30 | createConfigController,
31 | };
32 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/controllers/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { createPurgeController: purge } = require('./purge');
4 | const { createConfigController: config } = require('./config');
5 |
6 | const controllers = {
7 | purge,
8 | config,
9 | };
10 |
11 | module.exports = {
12 | controllers,
13 | };
14 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/controllers/purge.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @typedef {import('@strapi/strapi').Strapi} Strapi
5 | * @typedef {import('koa').Context} Context
6 | */
7 |
8 | /**
9 | * @param {{ strapi: Strapi }} strapi
10 | */
11 | function createPurgeController({ strapi }) {
12 | return {
13 | /**
14 | * @param {Context} ctx
15 | */
16 | async index(ctx) {
17 | const { contentType, params, wildcard } = ctx.request.body;
18 |
19 | if (!contentType) {
20 | ctx.badRequest('contentType is required');
21 | return;
22 | }
23 |
24 | const cacheConfigService = strapi
25 | .plugin('rest-cache')
26 | .service('cacheConfig');
27 |
28 | const cacheStoreService = strapi
29 | .plugin('rest-cache')
30 | .service('cacheStore');
31 |
32 | if (!cacheConfigService.isCached(contentType)) {
33 | ctx.badRequest('contentType is not cached', { contentType });
34 | return;
35 | }
36 |
37 | await cacheStoreService.clearByUid(contentType, params, wildcard);
38 |
39 | // send no-content status
40 | // ctx.status = 204;
41 | ctx.body = {};
42 | },
43 | };
44 | }
45 |
46 | module.exports = {
47 | createPurgeController,
48 | };
49 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { bootstrap } = require('./bootstrap');
4 | const { services } = require('./services');
5 | const { config } = require('./config');
6 | const { controllers } = require('./controllers');
7 | const { middlewares } = require('./middlewares');
8 | const { routes } = require('./routes');
9 |
10 | module.exports = {
11 | bootstrap,
12 | destroy() {},
13 | config,
14 | controllers,
15 | routes,
16 | services,
17 | contentTypes: {},
18 | policies: {},
19 | middlewares,
20 | };
21 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/middlewares/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { createRecv: recv } = require('./recv');
4 | const { createPurge: purge } = require('./purge');
5 | const { createPurgeAdmin: purgeAdmin } = require('./purgeAdmin');
6 |
7 | const middlewares = {
8 | recv,
9 | purge,
10 | purgeAdmin,
11 | };
12 |
13 | module.exports = {
14 | middlewares,
15 | };
16 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/middlewares/purge.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @param {{ contentType: string }} options
5 | * @param {{ strapi: import('@strapi/strapi').Strapi }} context
6 | */
7 |
8 | function createPurge(options, { strapi }) {
9 | if (!options.contentType) {
10 | throw new Error(
11 | 'REST Cache: unable to initialize purge middleware: options.contentType is required'
12 | );
13 | }
14 |
15 | const cacheConf = strapi.plugin('rest-cache').service('cacheConfig');
16 | const cacheStore = strapi.plugin('rest-cache').service('cacheStore');
17 |
18 | if (!cacheConf.isCached(options.contentType)) {
19 | throw new Error(
20 | `REST Cache: unable to initialize purge middleware: no configuration found for contentType "${options.contentType}"`
21 | );
22 | }
23 |
24 | return async function purge(ctx, next) {
25 | await next();
26 |
27 | if (!(ctx.status >= 200 && ctx.status <= 300)) return;
28 |
29 | await cacheStore.clearByUid(options.contentType, ctx.params);
30 | };
31 | }
32 |
33 | module.exports = {
34 | createPurge,
35 | };
36 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/middlewares/purgeAdmin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @param {{ }} options
5 | * @param {{ strapi: import('@strapi/strapi').Strapi }} context
6 | */
7 |
8 | function createPurgeAdmin(options, { strapi }) {
9 | const cacheConfig = strapi.plugin('rest-cache').service('cacheConfig');
10 | const cacheStore = strapi.plugin('rest-cache').service('cacheStore');
11 |
12 | return async function purgeAdmin(ctx, next) {
13 | // uid:
14 | // - application::sport.sport
15 | // - plugins::users-permissions.user
16 | const { model: uid, ...params } = ctx.params;
17 |
18 | if (!uid) {
19 | await next();
20 | return;
21 | }
22 |
23 | if (!cacheConfig.isCached(uid)) {
24 | await next();
25 | return;
26 | }
27 |
28 | await next();
29 |
30 | if (!(ctx.status >= 200 && ctx.status <= 300)) return;
31 |
32 | await cacheStore.clearByUid(uid, params);
33 | };
34 | }
35 |
36 | module.exports = {
37 | createPurgeAdmin,
38 | };
39 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/middlewares/recv.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @typedef {import('../types').CacheRouteConfig} CacheRouteConfig
5 | */
6 |
7 | const chalk = require('chalk');
8 | const debug = require('debug')('strapi:strapi-plugin-rest-cache');
9 |
10 | const { generateCacheKey } = require('../utils/keys/generateCacheKey');
11 | const { shouldLookup } = require('../utils/middlewares/shouldLookup');
12 | const { etagGenerate } = require('../utils/etags/etagGenerate');
13 | const { etagLookup } = require('../utils/etags/etagLookup');
14 | const { etagMatch } = require('../utils/etags/etagMatch');
15 |
16 | /**
17 | * @param {{ cacheRouteConfig: CacheRouteConfig }} options
18 | * @param {{ strapi: import('@strapi/strapi').Strapi }} context
19 | */
20 | function createRecv(options, { strapi }) {
21 | if (!options?.cacheRouteConfig) {
22 | throw new Error(
23 | 'REST Cache: unable to initialize recv middleware: options.cacheRouteConfig is required'
24 | );
25 | }
26 | const store = strapi.plugin('rest-cache').service('cacheStore');
27 | const { strategy } = strapi.config.get('plugin.rest-cache');
28 | const { cacheRouteConfig } = options;
29 | const { hitpass, maxAge, keys } = cacheRouteConfig;
30 | const { enableEtag = false, enableXCacheHeaders = false } = strategy;
31 |
32 | return async function recv(ctx, next) {
33 | // hash
34 | const cacheKey = generateCacheKey(ctx, keys);
35 |
36 | // hitpass check
37 | const lookup = shouldLookup(ctx, hitpass);
38 |
39 | // keep track of the etag
40 | let etagCached = null;
41 |
42 | if (lookup) {
43 | // lookup cached etag
44 | if (enableEtag) {
45 | etagCached = await etagLookup(cacheKey);
46 |
47 | if (etagCached && etagMatch(ctx, etagCached)) {
48 | if (enableXCacheHeaders) {
49 | ctx.set('X-Cache', 'HIT');
50 | }
51 |
52 | // etag match -> send HTTP 304 Not Modified
53 | ctx.body = null;
54 | ctx.status = 304;
55 | return;
56 | }
57 |
58 | // etag miss
59 | }
60 |
61 | const cacheEntry = await store.get(cacheKey);
62 |
63 | // hit cache
64 | if (cacheEntry) {
65 | debug(`[RECV] GET ${cacheKey} ${chalk.green('HIT')}`);
66 |
67 | if (enableXCacheHeaders) {
68 | ctx.set('X-Cache', 'HIT');
69 | }
70 |
71 | if (etagCached) {
72 | // send back cached etag on hit
73 | ctx.set('ETag', `"${etagCached}"`);
74 | }
75 |
76 | ctx.status = 200;
77 | ctx.body = cacheEntry;
78 | return;
79 | }
80 | }
81 |
82 | // fetch backend
83 | await next();
84 |
85 | // fetch done
86 | if (!lookup) {
87 | debug(`[RECV] GET ${cacheKey} ${chalk.magenta('HITPASS')}`);
88 |
89 | if (enableXCacheHeaders) {
90 | ctx.set('X-Cache', 'HITPASS');
91 | }
92 |
93 | // do not store hitpass response content
94 | return;
95 | }
96 |
97 | // deliver
98 | debug(`[RECV] GET ${cacheKey} ${chalk.yellow('MISS')}`);
99 |
100 | if (enableXCacheHeaders) {
101 | ctx.set('X-Cache', 'MISS');
102 | }
103 |
104 | if (ctx.body && ctx.status >= 200 && ctx.status <= 300) {
105 | // @TODO check Cache-Control response header
106 |
107 | if (enableEtag) {
108 | const etag = etagGenerate(ctx, cacheKey);
109 |
110 | ctx.set('ETag', `"${etag}"`);
111 |
112 | // persist etag asynchronously
113 | store.set(`${cacheKey}_etag`, etag, maxAge).catch(() => {
114 | debug(
115 | `[RECV] GET ${cacheKey} ${chalk.yellow(
116 | 'Unable to store ETag in cache'
117 | )}`
118 | );
119 | });
120 | }
121 |
122 | // persist cache asynchronously
123 | store.set(cacheKey, ctx.body, maxAge).catch(() => {
124 | debug(
125 | `[RECV] GET ${cacheKey} ${chalk.yellow(
126 | 'Unable to store Content in cache'
127 | )}`
128 | );
129 | });
130 | }
131 | };
132 | }
133 |
134 | module.exports = {
135 | createRecv,
136 | };
137 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/permissions-actions.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | actions: [
5 | {
6 | section: 'plugins',
7 | displayName: 'Purge cache',
8 | uid: 'cache.purge',
9 | subCategory: 'purge',
10 | pluginName: 'rest-cache',
11 | },
12 | {
13 | section: 'plugins',
14 | displayName: 'Read cache strategy configuration',
15 | uid: 'cache.read-strategy',
16 | subCategory: 'read',
17 | pluginName: 'rest-cache',
18 | },
19 | {
20 | section: 'plugins',
21 | displayName: 'Read cache provider configuration',
22 | uid: 'cache.read-provider',
23 | subCategory: 'read',
24 | pluginName: 'rest-cache',
25 | },
26 | ],
27 | };
28 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/pluginId.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // eslint-disable-next-line import/extensions
4 | const packageJson = require('../package.json');
5 |
6 | module.exports = packageJson.strapi.name;
7 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/routes/admin/config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const pluginId = require('../../pluginId');
4 |
5 | module.exports = [
6 | {
7 | method: 'GET',
8 | path: '/config/strategy',
9 | handler: 'config.strategy',
10 | config: {
11 | policies: [
12 | 'admin::isAuthenticatedAdmin',
13 | {
14 | name: 'plugin::content-manager.hasPermissions',
15 | config: { actions: [`plugin::${pluginId}.cache.read-strategy`] },
16 | },
17 | ],
18 | },
19 | },
20 | {
21 | method: 'GET',
22 | path: '/config/provider',
23 | handler: 'config.provider',
24 | config: {
25 | policies: [
26 | 'admin::isAuthenticatedAdmin',
27 | {
28 | name: 'plugin::content-manager.hasPermissions',
29 | config: { actions: [`plugin::${pluginId}.cache.read-provider`] },
30 | },
31 | ],
32 | },
33 | },
34 | ];
35 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/routes/admin/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const configRoutes = require('./config');
4 | const purgeRoutes = require('./purge');
5 |
6 | module.exports = {
7 | type: 'admin',
8 | routes: [...configRoutes, ...purgeRoutes],
9 | };
10 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/routes/admin/purge.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const pluginId = require('../../pluginId');
4 |
5 | module.exports = [
6 | {
7 | method: 'POST',
8 | path: '/purge',
9 | handler: 'purge.index',
10 | config: {
11 | policies: [
12 | 'admin::isAuthenticatedAdmin',
13 | {
14 | name: 'plugin::content-manager.hasPermissions',
15 | config: { actions: [`plugin::${pluginId}.cache.purge`] },
16 | },
17 | ],
18 | },
19 | },
20 | ];
21 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/routes/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const admin = require('./admin');
4 |
5 | const routes = {
6 | admin,
7 | };
8 |
9 | module.exports = {
10 | routes,
11 | };
12 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/services/cacheConfig.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @typedef {import('@strapi/strapi').Strapi} Strapi
5 | */
6 |
7 | const { getRouteRegExp } = require('../utils/config/getRouteRegExp');
8 |
9 | /**
10 | * @param {{ strapi: Strapi }} strapi
11 | */
12 |
13 | function createCacheConfigService({ strapi }) {
14 | return {
15 | /**
16 | * Get all uid of cached contentTypes
17 | *
18 | * uid:
19 | * - api::sport.sport
20 | * - plugin::users-permissions.user
21 | *
22 | * @return {string[]}
23 | */
24 | getUids() {
25 | const { strategy } = strapi.config.get('plugin.rest-cache');
26 | return strategy.contentTypes.map((cacheConf) => cacheConf.contentType);
27 | },
28 |
29 | /**
30 | * Return the intersection of cached contentTypes and the related contentTypes of a given contentType uid
31 | *
32 | * uid:
33 | * - api::sport.sport
34 | * - plugin::users-permissions.user
35 | *
36 | * @return {string[]}
37 | */
38 | getRelatedCachedUid(uid) {
39 | const cacheConf = this.get(uid);
40 | if (!cacheConf) {
41 | return [];
42 | }
43 |
44 | const cached = this.getUids();
45 | const related = cacheConf.relatedContentTypeUid;
46 |
47 | return related.filter((relatedUid) => cached.includes(relatedUid));
48 | },
49 |
50 | /**
51 | * Get related ModelCacheConfig with an uid
52 | *
53 | * uid:
54 | * - api::sport.sport
55 | * - plugin::users-permissions.user
56 | *
57 | * @param {string} uid
58 | * @return {CacheContentTypeConfig | undefined}
59 | */
60 | get(uid) {
61 | const { strategy } = strapi.config.get('plugin.rest-cache');
62 | return strategy.contentTypes.find(
63 | (cacheConf) => cacheConf.contentType === uid
64 | );
65 | },
66 |
67 | /**
68 | * Get regexs to match all ModelCacheConfig keys with given params
69 | *
70 | * @param {string} uid
71 | * @param {any} params
72 | * @param {boolean=} wildcard
73 | * @return {RegExp[]}
74 | */
75 | getCacheKeysRegexp(uid, params, wildcard = false) {
76 | const cacheConf = this.get(uid);
77 | if (!cacheConf) {
78 | return [];
79 | }
80 |
81 | const regExps = [];
82 |
83 | const routes = cacheConf.routes.filter((route) => route.method === 'GET');
84 |
85 | for (const route of routes) {
86 | regExps.push(...getRouteRegExp(route, params, wildcard));
87 | }
88 |
89 | return regExps;
90 | },
91 |
92 | /**
93 | * Check if a cache configuration exists for a contentType uid
94 | *
95 | * uid:
96 | * - api::sport.sport
97 | * - plugin::users-permissions.user
98 | *
99 | * @param {string} uid
100 | * @return {boolean}
101 | */
102 | isCached(uid) {
103 | return !!this.get(uid);
104 | },
105 |
106 | /**
107 | * @deprecated use strapi.plugin('rest-cache').service('cacheStore').clearByUid instead
108 | */
109 | async clearCache(uid, params = {}, wildcard = false) {
110 | strapi.log.warn(
111 | 'REST Cache cacheConfig.clearCache is deprecated, use cacheStore.clearByUid instead'
112 | );
113 | strapi
114 | .plugin('rest-cache')
115 | .service('cacheStore')
116 | .clearByUid(uid, params, wildcard);
117 | },
118 | };
119 | }
120 |
121 | module.exports = { createCacheConfigService };
122 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/services/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { createCacheConfigService: cacheConfig } = require('./cacheConfig');
4 | const { createCacheStoreService: cacheStore } = require('./cacheStore');
5 |
6 | const services = {
7 | cacheConfig,
8 | cacheStore,
9 | };
10 |
11 | module.exports = { services };
12 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/types/CacheContentTypeConfig.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @typedef {import('./CacheRouteConfig').CacheRouteConfig} CacheRouteConfig
5 | * @typedef {import('koa').Context} Context
6 | * @typedef {(ctx: Context) => boolean} CachePluginHitpass
7 | */
8 | const { CacheKeysConfig } = require('./CacheKeysConfig');
9 |
10 | class CacheContentTypeConfig {
11 | singleType = false;
12 |
13 | injectDefaultRoutes = true;
14 |
15 | maxAge = 3600000;
16 |
17 | /**
18 | * @type {CachePluginHitpass | boolean}
19 | */
20 | hitpass = false;
21 |
22 | /**
23 | * @type {CacheKeysConfig}
24 | */
25 | keys;
26 |
27 | /**
28 | * @type {string=}
29 | */
30 | plugin;
31 |
32 | /**
33 | * @type {CacheRouteConfig[]}
34 | */
35 | routes = [];
36 |
37 | /**
38 | * @type {string}
39 | */
40 | contentType;
41 |
42 | /**
43 | * @type {string[]}
44 | */
45 | relatedContentTypeUid = [];
46 |
47 | constructor(options = {}) {
48 | const {
49 | singleType = false,
50 | injectDefaultRoutes = true,
51 | maxAge = true,
52 | hitpass = false,
53 | keys = new CacheKeysConfig(),
54 | routes = [],
55 | relatedContentTypeUid = [],
56 | contentType,
57 | plugin,
58 | } = options;
59 |
60 | this.singleType = singleType;
61 | this.injectDefaultRoutes = injectDefaultRoutes;
62 | this.maxAge = maxAge;
63 | this.hitpass = hitpass;
64 | this.keys = keys;
65 | this.routes = routes;
66 | this.relatedContentTypeUid = relatedContentTypeUid;
67 | this.contentType = contentType;
68 | this.plugin = plugin;
69 | }
70 | }
71 |
72 | module.exports = { CacheContentTypeConfig };
73 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/types/CacheKeysConfig.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | class CacheKeysConfig {
4 | /**
5 | * @type {string[]}
6 | */
7 | useHeaders = [];
8 |
9 | /**
10 | * @type {Boolean|string[]}
11 | */
12 | useQueryParams = true;
13 |
14 | constructor(options = {}) {
15 | const { useHeaders = [], useQueryParams = true } = options;
16 | this.useHeaders = useHeaders;
17 | this.useQueryParams = useQueryParams;
18 |
19 | this.useHeaders.sort();
20 | }
21 | }
22 |
23 | module.exports = { CacheKeysConfig };
24 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/types/CachePluginStrategy.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @typedef {import('./CacheContentTypeConfig').CacheContentTypeConfig} CacheContentTypeConfig
5 | */
6 | const { CacheKeysConfig } = require('./CacheKeysConfig');
7 |
8 | class CachePluginStrategy {
9 | debug = false;
10 |
11 | enableEtag = false;
12 |
13 | enableXCacheHeaders = false;
14 |
15 | enableAdminCTBMiddleware = true;
16 |
17 | resetOnStartup = false;
18 |
19 | clearRelatedCache = false;
20 |
21 | maxAge = 3600000;
22 |
23 | keysPrefix = '';
24 |
25 | /**
26 | * @type {CacheContentTypeConfig[]}
27 | */
28 | contentTypes = [];
29 |
30 | /**
31 | * @type {CacheKeysConfig}
32 | */
33 | keys;
34 |
35 | constructor(options = {}) {
36 | const {
37 | debug = false,
38 | enableEtag = false,
39 | enableXCacheHeaders = false,
40 | enableAdminCTBMiddleware = true,
41 | resetOnStartup = false,
42 | clearRelatedCache = true,
43 | maxAge = 3600000,
44 | keysPrefix = '',
45 | contentTypes = [],
46 | keys = new CacheKeysConfig(),
47 | } = options;
48 |
49 | this.debug = debug;
50 | this.enableEtag = enableEtag;
51 | this.enableXCacheHeaders = enableXCacheHeaders;
52 | this.enableAdminCTBMiddleware = enableAdminCTBMiddleware;
53 | this.resetOnStartup = resetOnStartup;
54 | this.clearRelatedCache = clearRelatedCache;
55 | this.maxAge = maxAge;
56 | this.keysPrefix = keysPrefix;
57 | this.contentTypes = contentTypes;
58 | this.keys = keys;
59 | }
60 | }
61 |
62 | module.exports = { CachePluginStrategy };
63 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/types/CacheProvider.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* eslint-disable class-methods-use-this */
4 | /* eslint-disable no-unused-vars */
5 |
6 | /**
7 | * Abstract Class CacheProvider.
8 | *
9 | * @class CacheProvider
10 | */
11 | class CacheProvider {
12 | constructor() {
13 | if (this.constructor === CacheProvider) {
14 | throw new Error("CacheProvider class can't be instantiated.");
15 | }
16 | }
17 |
18 | /**
19 | * @param {string} key
20 | */
21 | async get(key) {
22 | throw new Error("Method 'get()' must be implemented.");
23 | }
24 |
25 | /**
26 | * @param {string} key
27 | * @param {any} val
28 | * @param {number=} maxAge
29 | */
30 | async set(key, val, maxAge = 3600) {
31 | throw new Error("Method 'set()' must be implemented.");
32 | }
33 |
34 | /**
35 | * @param {string|string[]} key
36 | */
37 | async del(key) {
38 | throw new Error("Method 'del()' must be implemented.");
39 | }
40 |
41 | async keys() {
42 | throw new Error("Method 'keys()' must be implemented.");
43 | }
44 |
45 | get ready() {
46 | throw new Error("getter 'ready' must be implemented.");
47 | }
48 | }
49 |
50 | module.exports = {
51 | CacheProvider,
52 | };
53 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/types/CacheRouteConfig.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @typedef {(ctx: Context) => boolean} CachePluginHitpass
5 | */
6 | const { CacheKeysConfig } = require('./CacheKeysConfig');
7 |
8 | class CacheRouteConfig {
9 | maxAge = 3600000;
10 |
11 | /**
12 | * @type {string}
13 | */
14 | path;
15 |
16 | /**
17 | * @type {'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'}
18 | */
19 | method = 'GET';
20 |
21 | /**
22 | * @type {string[]}
23 | */
24 | paramNames = [];
25 |
26 | /**
27 | * @type {CacheKeysConfig}
28 | */
29 | keys;
30 |
31 | /**
32 | * @type {CachePluginHitpass | boolean}
33 | */
34 | hitpass = false;
35 |
36 | constructor(options = {}) {
37 | const {
38 | path,
39 | method = 'GET',
40 | paramNames = [],
41 | maxAge = 3600000,
42 | hitpass = false,
43 | keys = new CacheKeysConfig(),
44 | } = options;
45 | this.path = path;
46 | this.method = method;
47 | this.paramNames = paramNames;
48 | this.maxAge = maxAge;
49 | this.hitpass = hitpass;
50 | this.keys = keys;
51 | }
52 | }
53 |
54 | module.exports = {
55 | CacheRouteConfig,
56 | };
57 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/types/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { CachePluginStrategy } = require('./CachePluginStrategy');
4 | const { CacheRouteConfig } = require('./CacheRouteConfig');
5 | const { CacheProvider } = require('./CacheProvider');
6 | const { CacheContentTypeConfig } = require('./CacheContentTypeConfig');
7 | const { CacheKeysConfig } = require('./CacheKeysConfig');
8 |
9 | module.exports = {
10 | CachePluginStrategy,
11 | CacheRouteConfig,
12 | CacheProvider,
13 | CacheContentTypeConfig,
14 | CacheKeysConfig,
15 | };
16 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/utils/config/deepFreeze.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function deepFreeze(object) {
4 | // Retrieve the property names defined on object
5 | const propNames = Object.getOwnPropertyNames(object);
6 |
7 | // Freeze properties before freezing self
8 | for (const name of propNames) {
9 | const value = object[name];
10 |
11 | if (value && typeof value === 'object') {
12 | deepFreeze(value);
13 | }
14 | }
15 |
16 | return Object.freeze(object);
17 | }
18 |
19 | module.exports = { deepFreeze };
20 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/utils/config/getRelatedModelsUid.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @typedef {import('@strapi/strapi').Strapi} Strapi
5 | */
6 |
7 | /**
8 | * Get models uid that is related to a ModelCacheConfig
9 | *
10 | * @param {Strapi} strapi
11 | * @param {string} uid The contentType used to find related caches to purge
12 | * @return {string[]} Array of related models uid
13 | */
14 | function getRelatedModelsUid(strapi, uid) {
15 | if (!uid) {
16 | return [];
17 | }
18 |
19 | const models = strapi.contentTypes;
20 |
21 | const { components } = strapi;
22 | const modelObj = models[uid];
23 | const modelAttributes = modelObj?.attributes ?? {};
24 | /**
25 | * @type {any[]}
26 | */
27 | const relatedComponents = [];
28 | /**
29 | * @type {any}
30 | */
31 | const relatedModels = {};
32 |
33 | // first, look for direct relations in other contentTypes
34 | for (const key in modelAttributes) {
35 | if (!Object.hasOwnProperty.call(modelAttributes, key)) {
36 | continue;
37 | }
38 |
39 | const attr = modelAttributes[key];
40 |
41 | if (attr.type !== 'relation') continue;
42 | if (!attr.target) continue;
43 |
44 | relatedModels[attr.target] = models[attr.target];
45 | }
46 |
47 | // second, look for relations to current model in components
48 | for (const compKey in components) {
49 | if (!Object.hasOwnProperty.call(components, compKey)) {
50 | continue;
51 | }
52 |
53 | const compObj = components[compKey];
54 | const attributes = compObj?.attributes ?? {};
55 |
56 | for (const key in attributes) {
57 | if (!Object.hasOwnProperty.call(attributes, key)) {
58 | continue;
59 | }
60 |
61 | const attr = attributes[key];
62 |
63 | if (attr.type !== 'relation') continue;
64 | if (!attr.target) continue;
65 |
66 | if (attr.target === uid) {
67 | relatedComponents.push(compKey);
68 | }
69 | }
70 | }
71 |
72 | // third, look for nested components with relations to current model
73 | for (const compKey in components) {
74 | if (!Object.hasOwnProperty.call(components, compKey)) {
75 | continue;
76 | }
77 | const compObj = components[compKey];
78 | const attributes = compObj?.attributes ?? {};
79 |
80 | // check if current component contains another component that contains a relation to the current model
81 | // look one level deeper
82 | for (const key in attributes) {
83 | if (!Object.hasOwnProperty.call(attributes, key)) {
84 | continue;
85 | }
86 |
87 | const attr = attributes[key];
88 |
89 | if (attr.type !== 'component') continue;
90 | if (!attr.component) continue;
91 | if (!relatedComponents.includes(attr.component)) continue;
92 | if (relatedComponents.includes(compKey)) continue;
93 |
94 | relatedComponents.push(compKey);
95 | }
96 | }
97 |
98 | // finally locate all the models that have the related components in their models
99 | for (const modelKey in models) {
100 | if (!Object.hasOwnProperty.call(models, modelKey)) {
101 | continue;
102 | }
103 |
104 | const otherModelObj = models[modelKey];
105 | const attributes = otherModelObj?.attributes ?? {};
106 |
107 | for (const key in attributes) {
108 | if (!Object.hasOwnProperty.call(attributes, key)) {
109 | continue;
110 | }
111 | const attr = attributes[key];
112 |
113 | if (attr.type !== 'component') continue;
114 | if (!attr.component) continue;
115 | if (!relatedComponents.includes(attr.component)) continue;
116 | if (relatedModels[modelKey]) continue;
117 |
118 | relatedModels[modelKey] = models[modelKey];
119 | }
120 | }
121 |
122 | const relatedModelUid = [];
123 |
124 | Object.values(relatedModels).reduce((acc, model) => {
125 | if (model.uid) {
126 | acc.push(model.uid);
127 | }
128 | return acc;
129 | }, relatedModelUid);
130 |
131 | return relatedModelUid;
132 | }
133 |
134 | module.exports = { getRelatedModelsUid };
135 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/utils/config/getRouteRegExp.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @typedef {import('../../types').CacheRouteConfig} CacheRouteConfig
5 | * @typedef {import('koa').Context} Context
6 | */
7 |
8 | /**
9 | * Get regexs to match CustomRoute keys with given params
10 | *
11 | * @param {CacheRouteConfig} route
12 | * @param {any} params
13 | * @param {boolean=} wildcard
14 | * @return {RegExp[]}
15 | */
16 | function getRouteRegExp(route, params, wildcard = false) {
17 | // route not contains any params -> clear
18 | if (!route.paramNames || !route.paramNames.length) {
19 | return [new RegExp(`^${route.path}\\?`)];
20 | }
21 |
22 | // wildcard: clear all routes
23 | if (wildcard) {
24 | let pattern = route.path;
25 | for (const paramName of route.paramNames) {
26 | pattern = pattern
27 | .replace(new RegExp(`:${paramName}([^\\/#\\?]*)`, 'g'), '([^\\/#\\?]+)')
28 | .replace('//', '/');
29 | }
30 |
31 | return [new RegExp(`^${pattern}\\?`)];
32 | }
33 |
34 | if (!params) {
35 | return [];
36 | }
37 |
38 | const paramNames = Object.keys(params);
39 | const regExps = [];
40 |
41 | let pattern = route.path;
42 | for (const paramName of paramNames) {
43 | pattern = pattern
44 | .replace(new RegExp(`:${paramName}([^\\/#\\?]*)`, 'g'), params[paramName])
45 | .replace('//', '/');
46 | }
47 |
48 | // add if pattern does not contain any unresolved params
49 | if (!pattern.includes(':')) {
50 | regExps.push(new RegExp(`^${pattern}\\?`));
51 | }
52 |
53 | return regExps;
54 | }
55 |
56 | module.exports = { getRouteRegExp };
57 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/utils/config/routeExists.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @typedef {import('../../types').CacheRouteConfig} CacheRouteConfig
5 | */
6 |
7 | /**
8 | * Check if a custom route is registered in strapi
9 | *
10 | * @param {Strapi} strapi
11 | * @param {CacheRouteConfig} route
12 | * @return {boolean}
13 | */
14 | function routeExists(strapi, route) {
15 | // check api routes
16 | const allRoutes = [
17 | ...strapi.server.listRoutes(),
18 | ...strapi.server.api('content-api').listRoutes(),
19 | ...strapi.server.api('admin').listRoutes(),
20 | ];
21 | const match = allRoutes.find(
22 | (routeLayer) =>
23 | routeLayer.methods.includes(route.method) &&
24 | routeLayer.path.match(new RegExp(`^${route.path}/?`)) // match with optional leading slash
25 | );
26 |
27 | return Boolean(match);
28 | }
29 |
30 | module.exports = { routeExists };
31 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/utils/etags/etagGenerate.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const crypto = require('crypto');
4 |
5 | function etagGenerate(ctx) {
6 | const type = typeof ctx.body;
7 | const etag = crypto
8 | .createHash('md5')
9 | .update(type === 'string' ? ctx.body : JSON.stringify(ctx.body))
10 | .digest('hex');
11 |
12 | return etag;
13 | }
14 | module.exports = {
15 | etagGenerate,
16 | };
17 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/utils/etags/etagLookup.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | async function etagLookup(cacheKey) {
4 | const store = strapi.plugin('rest-cache').service('cacheStore');
5 | const etagCached = await store.get(`${cacheKey}_etag`);
6 |
7 | if (etagCached) {
8 | return etagCached;
9 | }
10 |
11 | return null;
12 | }
13 |
14 | module.exports = { etagLookup };
15 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/utils/etags/etagMatch.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function etagMatch(ctx, etagCached) {
4 | const ifNoneMatch = ctx.request.headers['if-none-match'];
5 |
6 | if (!ifNoneMatch) {
7 | return false;
8 | }
9 |
10 | return ifNoneMatch.indexOf(`"${etagCached}"`) !== -1;
11 | }
12 |
13 | module.exports = { etagMatch };
14 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/utils/keys/generateCacheKey.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { toLower } = require('lodash/fp');
4 | const path = require('path');
5 | const { generateHeadersKey } = require('./generateHeadersKey');
6 | const { generateQueryParamsKey } = require('./generateQueryParamsKey');
7 |
8 | function generateCacheKey(
9 | ctx,
10 | keys = {
11 | useQueryParams: false, // @todo: array or boolean => can be optimized
12 | useHeaders: [],
13 | }
14 | ) {
15 | let querySuffix = '';
16 | let headersSuffix = '';
17 |
18 | if (keys.useQueryParams !== false) {
19 | querySuffix = generateQueryParamsKey(ctx, keys.useQueryParams);
20 | }
21 |
22 | if (keys.useHeaders.length > 0) {
23 | headersSuffix = generateHeadersKey(ctx, keys.useHeaders);
24 | }
25 |
26 | const requestPath = toLower(path.posix.normalize(ctx.request.path)).replace(
27 | /\/$/,
28 | ''
29 | );
30 |
31 | return `${requestPath}?${querySuffix}&${headersSuffix}`;
32 | }
33 |
34 | module.exports = { generateCacheKey };
35 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/utils/keys/generateHeadersKey.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function generateHeadersKey(ctx, useHeaders = []) {
4 | return useHeaders
5 | .filter((k) => ctx.request.header[k.toLowerCase()] !== undefined)
6 | .map((k) => `${k.toLowerCase()}=${ctx.request.header[k.toLowerCase()]}`) // headers are key insensitive
7 | .join(',');
8 | }
9 |
10 | module.exports = { generateHeadersKey };
11 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/utils/keys/generateQueryParamsKey.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function generateQueryParamsKey(
4 | ctx,
5 | useQueryParams = true // @todo: array or boolean => can be optimized
6 | ) {
7 | let keys = [];
8 |
9 | if (useQueryParams === true) {
10 | keys = Object.keys(ctx.query);
11 | } else if (useQueryParams.length > 0) {
12 | keys = Object.keys(ctx.query).filter((key) => useQueryParams.includes(key));
13 | }
14 |
15 | if (keys.length === 0) {
16 | return '';
17 | }
18 |
19 | keys.sort();
20 |
21 | return keys
22 | .map(
23 | (k) =>
24 | `${k}=${
25 | typeof ctx.query[k] === 'object'
26 | ? JSON.stringify(ctx.query[k])
27 | : ctx.query[k]
28 | }`
29 | ) // query strings are key sensitive
30 | .join(',');
31 | }
32 |
33 | module.exports = { generateQueryParamsKey };
34 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/utils/middlewares/createRouter.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Router = require('@koa/router');
4 | const chalk = require('chalk');
5 | const debug = require('debug')('strapi:strapi-plugin-rest-cache');
6 |
7 | /**
8 | * @typedef {import('../../types').CachePluginStrategy} CachePluginStrategy
9 | */
10 |
11 | // @see https://github.com/strapi/strapi/blob/master/packages/core/content-manager/server/routes/admin.js
12 | const adminRoutes = {
13 | post: [
14 | '/content-manager/single-types/:model/actions/publish',
15 | '/content-manager/single-types/:model/actions/unpublish',
16 | '/content-manager/collection-types/:model',
17 | '/content-manager/collection-types/:model/:id/actions/publish',
18 | '/content-manager/collection-types/:model/:id/actions/unpublish',
19 | '/content-manager/collection-types/:model/actions/bulkDelete',
20 | ],
21 | put: [
22 | '/content-manager/single-types/:model',
23 | '/content-manager/collection-types/:model/:id',
24 | ],
25 | delete: [
26 | '/content-manager/single-types/:model',
27 | '/content-manager/collection-types/:model/:id',
28 | ],
29 | };
30 |
31 | /**
32 | * @param {Strapi} strapi
33 | * @param {CachePluginStrategy} strategy
34 | * @return {Router}
35 | */
36 | function createRouter(strapi, strategy) {
37 | const router = new Router();
38 |
39 | const createRecvMiddleware = strapi.plugin('rest-cache').middleware('recv');
40 | const createPurgeMiddleware = strapi.plugin('rest-cache').middleware('purge');
41 | const createPurgeAdminMiddleware = strapi
42 | .plugin('rest-cache')
43 | .middleware('purgeAdmin');
44 | const purgeAdminMiddleware = createPurgeAdminMiddleware({}, { strapi });
45 |
46 | for (const cacheConf of strategy.contentTypes) {
47 | debug(`[REGISTER] ${chalk.cyan(cacheConf.contentType)} routes middlewares`);
48 |
49 | const purgeMiddleware = createPurgeMiddleware(
50 | { contentType: cacheConf.contentType },
51 | { strapi }
52 | );
53 |
54 | for (const route of cacheConf.routes) {
55 | switch (route.method) {
56 | case 'DELETE': {
57 | debug(`[REGISTER] DELETE ${route.path} ${chalk.redBright('purge')}`);
58 | router.delete(route.path, purgeMiddleware);
59 | break;
60 | }
61 | case 'PUT': {
62 | debug(`[REGISTER] PUT ${route.path} ${chalk.redBright('purge')}`);
63 | router.put(route.path, purgeMiddleware);
64 | break;
65 | }
66 | case 'PATCH': {
67 | debug(`[REGISTER] PATCH ${route.path} ${chalk.redBright('purge')}`);
68 | router.patch(route.path, purgeMiddleware);
69 | break;
70 | }
71 | case 'POST': {
72 | debug(`[REGISTER] POST ${route.path} ${chalk.redBright('purge')}`);
73 | router.post(route.path, purgeMiddleware);
74 | break;
75 | }
76 | case 'GET': {
77 | const vary = route.keys.useHeaders
78 | .map((name) => name.toLowerCase())
79 | .join(',');
80 |
81 | debug(
82 | `[REGISTER] GET ${route.path} ${chalk.green('recv')} ${chalk.grey(
83 | `maxAge=${route.maxAge}`
84 | )}${vary && chalk.grey(` vary=${vary}`)}`
85 | );
86 |
87 | router.get(
88 | route.path,
89 | createRecvMiddleware({ cacheRouteConfig: route }, { strapi })
90 | );
91 | break;
92 | }
93 | default:
94 | break;
95 | }
96 | }
97 | }
98 |
99 | // --- Admin REST endpoints
100 | if (strategy.enableAdminCTBMiddleware) {
101 | debug(`[REGISTER] ${chalk.magentaBright('admin')} routes middlewares`);
102 |
103 | for (const route of adminRoutes.post) {
104 | debug(`[REGISTER] POST ${route} ${chalk.magentaBright('purge-admin')}`);
105 | router.post(route, purgeAdminMiddleware);
106 | }
107 | for (const route of adminRoutes.put) {
108 | debug(`[REGISTER] PUT ${route} ${chalk.magentaBright('purge-admin')}`);
109 | router.put(route, purgeAdminMiddleware);
110 | }
111 | for (const route of adminRoutes.delete) {
112 | debug(`[REGISTER] DELETE ${route} ${chalk.magentaBright('purge-admin')}`);
113 | router.delete(route, purgeAdminMiddleware);
114 | }
115 | }
116 |
117 | return router;
118 | }
119 |
120 | module.exports = { createRouter };
121 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/utils/middlewares/shouldLookup.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function shouldLookup(
4 | ctx,
5 | hitpass // @todo: function or boolean => can be optimized
6 | ) {
7 | const type = typeof hitpass;
8 |
9 | if (type === 'boolean') {
10 | return !hitpass;
11 | }
12 |
13 | if (type === 'function') {
14 | return !hitpass(ctx);
15 | }
16 |
17 | return false;
18 | }
19 |
20 | module.exports = {
21 | shouldLookup,
22 | };
23 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/utils/store/deserialize.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @param {string} str
5 | * @return {any}
6 | */
7 | function deserialize(str) {
8 | if (!str) {
9 | return null;
10 | }
11 | return JSON.parse(str).data;
12 | }
13 |
14 | module.exports = { deserialize };
15 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/utils/store/serialize.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @param {any} data
5 | * @return {string}
6 | */
7 | function serialize(data) {
8 | return JSON.stringify({ data });
9 | }
10 |
11 | module.exports = { serialize };
12 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/server/utils/store/withTimeout.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Reject promise after timeout
5 | *
6 | * @todo this is slow, we should find a way to do this in a faster way
7 | * @param {Promise} callback
8 | * @param {number} ms
9 | * @return {Promise}
10 | */
11 | function withTimeout(callback, ms) {
12 | let timeout;
13 |
14 | return Promise.race([
15 | callback().then((result) => {
16 | clearTimeout(timeout);
17 | return result;
18 | }),
19 | new Promise((_, reject) => {
20 | timeout = setTimeout(() => {
21 | reject(new Error('timeout'));
22 | }, ms);
23 | }),
24 | ]);
25 | }
26 |
27 | module.exports = {
28 | withTimeout,
29 | };
30 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/strapi-admin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = require('./admin/src').default;
4 |
--------------------------------------------------------------------------------
/packages/strapi-plugin-rest-cache/strapi-server.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = require('./server');
4 |
--------------------------------------------------------------------------------
/packages/strapi-provider-rest-cache-couchbase/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## [4.2.4](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.2.3...v4.2.4) (2022-03-19)
7 |
8 | **Note:** Version bump only for package strapi-provider-rest-cache-couchbase
9 |
10 |
11 |
12 |
13 |
14 | ## [4.2.3](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.2.2...v4.2.3) (2022-03-18)
15 |
16 | **Note:** Version bump only for package strapi-provider-rest-cache-couchbase
17 |
18 |
19 |
20 |
21 |
22 | ## [4.2.2](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.2.1...v4.2.2) (2022-03-15)
23 |
24 |
25 | ### Bug Fixes
26 |
27 | * ensure keyprefix is not undefined ([9134f52](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/9134f52a0ea8a8399db4af59a5dc689742104739))
28 |
29 |
30 |
31 |
32 |
33 | ## [4.2.1](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.2.0...v4.2.1) (2022-03-11)
34 |
35 |
36 | ### Bug Fixes
37 |
38 | * empty keys returned by providers ([fb5c79c](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/fb5c79c490309e8bd4458726fe8aedacbfae503b))
39 |
40 |
41 |
42 |
43 |
44 | # [4.2.0](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.1.0...v4.2.0) (2022-03-09)
45 |
46 | **Note:** Version bump only for package strapi-provider-rest-cache-couchbase
47 |
48 |
49 |
50 |
51 |
52 | # [4.1.0](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.6...v4.1.0) (2022-03-05)
53 |
54 | **Note:** Version bump only for package strapi-provider-rest-cache-couchbase
55 |
56 |
57 |
58 |
59 |
60 | ## [4.0.6](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.5...v4.0.6) (2022-03-02)
61 |
62 | **Note:** Version bump only for package strapi-provider-rest-cache-couchbase
63 |
64 | ## [4.0.5](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.4...v4.0.5) (2022-03-02)
65 |
66 | **Note:** Version bump only for package strapi-provider-rest-cache-couchbase
67 |
68 | ## [4.0.4](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.3...v4.0.4) (2022-02-26)
69 |
70 | **Note:** Version bump only for package strapi-provider-rest-cache-couchbase
71 |
72 | ## [4.0.3](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.2...v4.0.3) (2022-02-26)
73 |
74 | **Note:** Version bump only for package strapi-provider-rest-cache-couchbase
75 |
76 | ## [4.0.2](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.1...v4.0.2) (2022-02-24)
77 |
78 | ### Bug Fixes
79 |
80 | - use short plugin name ([8daf416](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/8daf41643c2479c0df19a2fe137cae7ec395ec78))
81 |
82 | ## [4.0.1](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.0...v4.0.1) (2022-02-24)
83 |
84 | ### Bug Fixes
85 |
86 | - empty npm packages ([1fde26a](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/1fde26a1da956c854661b036bc48483c49f9f75e))
87 |
88 | # Change Log
89 |
--------------------------------------------------------------------------------
/packages/strapi-provider-rest-cache-couchbase/lib/CouchbaseCacheProvider.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const cacheManager = require("cache-manager");
4 | const couchbaseStore = require("cache-manager-couchbase");
5 | const { CacheProvider } = require("strapi-plugin-rest-cache/server/types");
6 |
7 | class CouchbaseCacheProvider extends CacheProvider {
8 | constructor(options) {
9 | super();
10 | this.cache = cacheManager.caching({
11 | store: couchbaseStore,
12 | ...options,
13 | });
14 | }
15 |
16 | /**
17 | * @param {string} key
18 | */
19 | async get(key) {
20 | return this.cache.get(key);
21 | }
22 |
23 | /**
24 | * @param {string} key
25 | * @param {any} val
26 | * @param {number=} maxAge
27 | */
28 | async set(key, val, maxAge = 3600) {
29 | // TODO: When we upgrade the cache manager >=5.x.x, need to multiply this not divide
30 | const options = {
31 | ttl: maxAge / 1000,
32 | };
33 | return this.cache.set(key, val, options);
34 | }
35 |
36 | /**
37 | * @param {string|string[]} key
38 | */
39 | async del(key) {
40 | return this.cache.del(key);
41 | }
42 |
43 | async keys() {
44 | return this.cache.keys();
45 | }
46 |
47 | get ready() {
48 | return this.cache.store.getClient() != null;
49 | }
50 | }
51 |
52 | module.exports = {
53 | CouchbaseCacheProvider,
54 | };
55 |
--------------------------------------------------------------------------------
/packages/strapi-provider-rest-cache-couchbase/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const { CouchbaseCacheProvider } = require("./CouchbaseCacheProvider");
4 |
5 | module.exports = {
6 | provider: "couchbase",
7 | name: "Couchbase",
8 |
9 | async init(options, { strapi }) {
10 | if (
11 | options.connectionString == null ||
12 | options.connectionString === "undefined"
13 | ) {
14 | throw new Error(
15 | `Could not initialize REST Cache provider "couchbase". Missing 'connectionString'`
16 | );
17 | }
18 | if (
19 | options.connectionOptions == null ||
20 | options.connectionOptions === "undefined"
21 | ) {
22 | throw new Error(
23 | `Could not initialize REST Cache provider "couchbase". Missing 'connectionOptions'`
24 | );
25 | }
26 | if (
27 | options.connectionOptions.username == null ||
28 | options.connectionOptions.username === "undefined"
29 | ) {
30 | throw new Error(
31 | `Could not initialize REST Cache provider "couchbase". Missing 'connectionOptions.username'`
32 | );
33 | }
34 | if (
35 | options.connectionOptions.password == null ||
36 | options.connectionOptions.password === "undefined"
37 | ) {
38 | throw new Error(
39 | `Could not initialize REST Cache provider "couchbase". Missing 'connectionOptions.password'`
40 | );
41 | }
42 | if (options.bucket == null || options.bucket === "undefined") {
43 | throw new Error(
44 | `Could not initialize REST Cache provider "couchbase". Missing 'bucket'`
45 | );
46 | }
47 |
48 | const provider = new CouchbaseCacheProvider(options);
49 |
50 | strapi.log.info(
51 | `CouchbaseCacheProvider initialised with connectionString: "${options.connectionString}", bucket: "${options.bucket}", scope: "${options.scope}", collection: "${options.collection}",`
52 | );
53 |
54 | return provider;
55 | },
56 | };
57 |
--------------------------------------------------------------------------------
/packages/strapi-provider-rest-cache-couchbase/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "strapi-provider-rest-cache-couchbase",
3 | "version": "4.2.9",
4 | "description": "Speed-up HTTP requests with Couchbase database",
5 | "license": "MIT",
6 | "strapi": {
7 | "displayName": "REST Cache (couchbase)",
8 | "name": "strapi-provider-rest-cache-couchbase",
9 | "description": "Couchbase provider for REST Cache plugin",
10 | "kind": "plugin"
11 | },
12 | "keywords": [
13 | "strapi",
14 | "provider",
15 | "rest-cache",
16 | "couchbase"
17 | ],
18 | "author": {
19 | "name": "Strapi Community",
20 | "url": "https://github.com/strapi-community/"
21 | },
22 | "maintainers": [
23 | {
24 | "name": "Davide Pellegatta",
25 | "email": "davide.pellegatta@gmail.com",
26 | "url": "https://github.com/davidepellegatta/"
27 | },
28 | {
29 | "name": "Patrick R",
30 | "url": "https://github.com/patrixr/"
31 | }
32 | ],
33 | "repository": {
34 | "type": "git",
35 | "url": "git+https://github.com/strapi-community/strapi-plugin-rest-cache.git",
36 | "directory": "packages/strapi-provider-rest-cache-couchbase"
37 | },
38 | "bugs": {
39 | "url": "https://github.com/strapi-community/strapi-plugin-rest-cache/issues"
40 | },
41 | "homepage": "https://github.com/strapi-community/strapi-plugin-rest-cache#readme",
42 | "main": "lib/index.js",
43 | "files": [
44 | "lib/**/*.js"
45 | ],
46 | "scripts": {
47 | "lint": "run-s eslint:fix prettier:fix",
48 | "eslint": "eslint ./lib",
49 | "eslint:fix": "eslint ./lib --fix",
50 | "prettier": "prettier --check ./lib",
51 | "prettier:fix": "prettier --write ./lib",
52 | "test": "run-s test:*",
53 | "test:lint": "run-s eslint prettier"
54 | },
55 | "dependencies": {
56 | "cache-manager": "^3.6.0",
57 | "cache-manager-couchbase": "^0.1.5"
58 | },
59 | "devDependencies": {
60 | "@strapi/strapi": "^4.11.7",
61 | "strapi-plugin-rest-cache": "^4.2.9"
62 | },
63 | "peerDependencies": {
64 | "@strapi/strapi": "^4.0.0",
65 | "strapi-plugin-rest-cache": "^4.0.0"
66 | },
67 | "engines": {
68 | "node": ">=14.0.0",
69 | "npm": ">=6.0.0"
70 | },
71 | "gitHead": "80f7c4b1c3915484e282597292cd1f5c749cbe8f"
72 | }
73 |
--------------------------------------------------------------------------------
/packages/strapi-provider-rest-cache-memory/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## [4.2.4](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.2.3...v4.2.4) (2022-03-19)
7 |
8 | **Note:** Version bump only for package strapi-provider-rest-cache-memory
9 |
10 |
11 |
12 |
13 |
14 | ## [4.2.3](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.2.2...v4.2.3) (2022-03-18)
15 |
16 | **Note:** Version bump only for package strapi-provider-rest-cache-memory
17 |
18 |
19 |
20 |
21 |
22 | ## [4.2.2](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.2.1...v4.2.2) (2022-03-15)
23 |
24 | **Note:** Version bump only for package strapi-provider-rest-cache-memory
25 |
26 |
27 |
28 |
29 |
30 | ## [4.2.1](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.2.0...v4.2.1) (2022-03-11)
31 |
32 |
33 | ### Bug Fixes
34 |
35 | * empty keys returned by providers ([fb5c79c](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/fb5c79c490309e8bd4458726fe8aedacbfae503b))
36 |
37 |
38 |
39 |
40 |
41 | # [4.2.0](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.1.0...v4.2.0) (2022-03-09)
42 |
43 | **Note:** Version bump only for package strapi-provider-rest-cache-memory
44 |
45 |
46 |
47 |
48 |
49 | # [4.1.0](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.6...v4.1.0) (2022-03-05)
50 |
51 | **Note:** Version bump only for package strapi-provider-rest-cache-memory
52 |
53 |
54 |
55 |
56 |
57 | ## [4.0.6](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.5...v4.0.6) (2022-03-02)
58 |
59 | **Note:** Version bump only for package strapi-provider-rest-cache-memory
60 |
61 | ## [4.0.5](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.4...v4.0.5) (2022-03-02)
62 |
63 | **Note:** Version bump only for package strapi-provider-rest-cache-memory
64 |
65 | ## [4.0.4](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.3...v4.0.4) (2022-02-26)
66 |
67 | **Note:** Version bump only for package strapi-provider-rest-cache-memory
68 |
69 | ## [4.0.3](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.2...v4.0.3) (2022-02-26)
70 |
71 | **Note:** Version bump only for package strapi-provider-rest-cache-memory
72 |
73 | ## [4.0.2](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.1...v4.0.2) (2022-02-24)
74 |
75 | ### Bug Fixes
76 |
77 | - use short plugin name ([8daf416](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/8daf41643c2479c0df19a2fe137cae7ec395ec78))
78 |
79 | ## [4.0.1](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.0...v4.0.1) (2022-02-24)
80 |
81 | ### Bug Fixes
82 |
83 | - empty npm packages ([1fde26a](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/1fde26a1da956c854661b036bc48483c49f9f75e))
84 |
85 | # [4.0.0](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.0-alpha.1...v4.0.0) (2022-01-31)
86 |
87 | ### Bug Fixes
88 |
89 | - peerDependencies fixed version ([4b5e317](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/4b5e317ae9319a91f90d7d7fb62fbcb7401d67af))
90 |
91 | ### Features
92 |
93 | - **core:** add keysPrefix strategy option ([8ed2149](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/8ed21495fadd2d2d709c741c3bccdc48d17376bd))
94 |
95 | # [4.0.0-alpha.1](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.0-alpha.0...v4.0.0-alpha.1) (2022-01-31)
96 |
97 | ### Bug Fixes
98 |
99 | - peerDependencies fixed version ([f43ef96](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/f43ef96b87c274618ecd041b733ecfa22c824c74))
100 |
101 | # [4.0.0-alpha.0](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v1.0.1-alpha.0...v4.0.0-alpha.0) (2022-01-31)
102 |
103 | **Note:** Version bump only for package strapi-provider-rest-cache-memory
104 |
--------------------------------------------------------------------------------
/packages/strapi-provider-rest-cache-memory/lib/MemoryCacheProvider.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | /* eslint-disable class-methods-use-this */
4 | const cacheManager = require("cache-manager");
5 | const { CacheProvider } = require("strapi-plugin-rest-cache/server/types");
6 |
7 | class MemoryCacheProvider extends CacheProvider {
8 | constructor(options) {
9 | super();
10 | this.cache = cacheManager.caching({ store: "memory", ...options });
11 | }
12 |
13 | /**
14 | * @param {string} key
15 | */
16 | async get(key) {
17 | return this.cache.get(key);
18 | }
19 |
20 | /**
21 | * @param {string} key
22 | * @param {any} val
23 | * @param {number=} maxAge
24 | */
25 | async set(key, val, maxAge = 3600) {
26 | // TODO: When we upgrade the cache manager >=5.x.x, need to multiply this not divide
27 | const options = {
28 | ttl: maxAge / 1000,
29 | };
30 | return this.cache.set(key, val, options);
31 | }
32 |
33 | /**
34 | * @param {string|string[]} key
35 | */
36 | async del(key) {
37 | return this.cache.del(key);
38 | }
39 |
40 | async keys() {
41 | return this.cache.keys();
42 | }
43 |
44 | get ready() {
45 | return true;
46 | }
47 | }
48 |
49 | module.exports = {
50 | MemoryCacheProvider,
51 | };
52 |
--------------------------------------------------------------------------------
/packages/strapi-provider-rest-cache-memory/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | /**
4 | * @typedef {import('@strapi/strapi').Strapi} Strapi
5 | */
6 |
7 | const { MemoryCacheProvider } = require("./MemoryCacheProvider");
8 |
9 | module.exports = {
10 | provider: "memory",
11 | name: "Memory",
12 |
13 | async init(options /* , { strapi } */) {
14 | return new MemoryCacheProvider(options);
15 | },
16 | };
17 |
--------------------------------------------------------------------------------
/packages/strapi-provider-rest-cache-memory/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "strapi-provider-rest-cache-memory",
3 | "version": "4.2.9",
4 | "description": "Speed-up HTTP requests with LRU cache",
5 | "license": "MIT",
6 | "strapi": {
7 | "displayName": "REST Cache (memory)",
8 | "name": "strapi-provider-rest-cache-memory",
9 | "description": "In-memory provider for REST Cache plugin",
10 | "kind": "plugin"
11 | },
12 | "keywords": [
13 | "strapi",
14 | "provider",
15 | "rest-cache",
16 | "memory"
17 | ],
18 | "author": {
19 | "name": "Strapi Community",
20 | "url": "https://github.com/strapi-community/"
21 | },
22 | "maintainers": [
23 | {
24 | "name": "Sacha Stafyniak",
25 | "email": "sacha@digisquad.io",
26 | "url": "https://digisquad.io"
27 | },
28 | {
29 | "name": "Patrick R",
30 | "url": "https://github.com/patrixr/"
31 | }
32 | ],
33 | "repository": {
34 | "type": "git",
35 | "url": "git+https://github.com/strapi-community/strapi-plugin-rest-cache.git",
36 | "directory": "packages/strapi-provider-rest-cache-memory"
37 | },
38 | "bugs": {
39 | "url": "https://github.com/strapi-community/strapi-plugin-rest-cache/issues"
40 | },
41 | "homepage": "https://strapi-community.github.io/strapi-plugin-rest-cache/",
42 | "main": "lib/index.js",
43 | "files": [
44 | "lib/**/*.js"
45 | ],
46 | "scripts": {
47 | "lint": "run-s eslint:fix prettier:fix",
48 | "eslint": "eslint ./lib",
49 | "eslint:fix": "eslint ./lib --fix",
50 | "prettier": "prettier --check ./lib",
51 | "prettier:fix": "prettier --write ./lib",
52 | "test": "run-s test:*",
53 | "test:lint": "run-s eslint prettier"
54 | },
55 | "dependencies": {
56 | "cache-manager": "^3.6.0"
57 | },
58 | "devDependencies": {
59 | "@strapi/strapi": "^4.11.7",
60 | "strapi-plugin-rest-cache": "^4.2.9"
61 | },
62 | "peerDependencies": {
63 | "@strapi/strapi": "^4.0.0",
64 | "strapi-plugin-rest-cache": "^4.0.0"
65 | },
66 | "engines": {
67 | "node": ">=14.0.0",
68 | "npm": ">=6.0.0"
69 | },
70 | "gitHead": "80f7c4b1c3915484e282597292cd1f5c749cbe8f"
71 | }
72 |
--------------------------------------------------------------------------------
/packages/strapi-provider-rest-cache-redis/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## [4.2.4](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.2.3...v4.2.4) (2022-03-19)
7 |
8 | **Note:** Version bump only for package strapi-provider-rest-cache-redis
9 |
10 |
11 |
12 |
13 |
14 | ## [4.2.3](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.2.2...v4.2.3) (2022-03-18)
15 |
16 | **Note:** Version bump only for package strapi-provider-rest-cache-redis
17 |
18 |
19 |
20 |
21 |
22 | ## [4.2.2](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.2.1...v4.2.2) (2022-03-15)
23 |
24 |
25 | ### Bug Fixes
26 |
27 | * ensure keyprefix is not undefined ([9134f52](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/9134f52a0ea8a8399db4af59a5dc689742104739))
28 |
29 |
30 |
31 |
32 |
33 | ## [4.2.1](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.2.0...v4.2.1) (2022-03-11)
34 |
35 |
36 | ### Bug Fixes
37 |
38 | * empty keys returned by providers ([fb5c79c](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/fb5c79c490309e8bd4458726fe8aedacbfae503b))
39 |
40 |
41 |
42 |
43 |
44 | # [4.2.0](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.1.0...v4.2.0) (2022-03-09)
45 |
46 | **Note:** Version bump only for package strapi-provider-rest-cache-redis
47 |
48 |
49 |
50 |
51 |
52 | # [4.1.0](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.6...v4.1.0) (2022-03-05)
53 |
54 | **Note:** Version bump only for package strapi-provider-rest-cache-redis
55 |
56 |
57 |
58 |
59 |
60 | ## [4.0.6](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.5...v4.0.6) (2022-03-02)
61 |
62 | **Note:** Version bump only for package strapi-provider-rest-cache-redis
63 |
64 | ## [4.0.5](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.4...v4.0.5) (2022-03-02)
65 |
66 | **Note:** Version bump only for package strapi-provider-rest-cache-redis
67 |
68 | ## [4.0.4](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.3...v4.0.4) (2022-02-26)
69 |
70 | **Note:** Version bump only for package strapi-provider-rest-cache-redis
71 |
72 | ## [4.0.3](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.2...v4.0.3) (2022-02-26)
73 |
74 | **Note:** Version bump only for package strapi-provider-rest-cache-redis
75 |
76 | ## [4.0.2](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.1...v4.0.2) (2022-02-24)
77 |
78 | ### Bug Fixes
79 |
80 | - use short plugin name ([8daf416](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/8daf41643c2479c0df19a2fe137cae7ec395ec78))
81 |
82 | ## [4.0.1](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.0...v4.0.1) (2022-02-24)
83 |
84 | ### Bug Fixes
85 |
86 | - empty npm packages ([1fde26a](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/1fde26a1da956c854661b036bc48483c49f9f75e))
87 |
88 | # [4.0.0](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.0-alpha.1...v4.0.0) (2022-01-31)
89 |
90 | ### Bug Fixes
91 |
92 | - peerDependencies fixed version ([4b5e317](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/4b5e317ae9319a91f90d7d7fb62fbcb7401d67af))
93 |
94 | ### Features
95 |
96 | - **core:** add keysPrefix strategy option ([8ed2149](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/8ed21495fadd2d2d709c741c3bccdc48d17376bd))
97 |
98 | # [4.0.0-alpha.1](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.0-alpha.0...v4.0.0-alpha.1) (2022-01-31)
99 |
100 | ### Bug Fixes
101 |
102 | - peerDependencies fixed version ([f43ef96](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/f43ef96b87c274618ecd041b733ecfa22c824c74))
103 |
104 | # [4.0.0-alpha.0](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v1.0.1-alpha.0...v4.0.0-alpha.0) (2022-01-31)
105 |
106 | ### Bug Fixes
107 |
108 | - **redis:** remove ready listener on error ([9a90fa2](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/9a90fa2938650a826dcf293ddda292d8d8f3a175))
109 |
--------------------------------------------------------------------------------
/packages/strapi-provider-rest-cache-redis/lib/RedisCacheProvider.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const cacheManager = require("cache-manager");
4 | const redisStore = require("cache-manager-ioredis");
5 | const { CacheProvider } = require("strapi-plugin-rest-cache/server/types");
6 |
7 | class RedisCacheProvider extends CacheProvider {
8 | constructor(client, options) {
9 | super();
10 | this.client = client;
11 | this.cache = cacheManager.caching({
12 | store: redisStore,
13 | redisInstance: client,
14 | ...options,
15 | });
16 | }
17 |
18 | /**
19 | * @param {string} key
20 | */
21 | async get(key) {
22 | return this.cache.get(key);
23 | }
24 |
25 | /**
26 | * @param {string} key
27 | * @param {any} val
28 | * @param {number=} maxAge
29 | */
30 | async set(key, val, maxAge = 3600) {
31 | // TODO: When we upgrade the cache manager >=5.x.x, need to multiply this not divide
32 | const options = {
33 | ttl: maxAge / 1000,
34 | };
35 | return this.cache.set(key, val, options);
36 | }
37 |
38 | /**
39 | * @param {string|string[]} key
40 | */
41 | async del(key) {
42 | return this.cache.del(key);
43 | }
44 |
45 | async keys(prefix = "") {
46 | return this.cache.keys(`${prefix}*`);
47 | }
48 |
49 | get ready() {
50 | const client = this.cache.store.getClient();
51 | return client.status === "ready";
52 | }
53 | }
54 |
55 | module.exports = {
56 | RedisCacheProvider,
57 | };
58 |
--------------------------------------------------------------------------------
/packages/strapi-provider-rest-cache-redis/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | /**
4 | * @typedef {import('@strapi/strapi').Strapi} Strapi
5 | */
6 | const { RedisCacheProvider } = require("./RedisCacheProvider");
7 |
8 | function waitForRedis(client) {
9 | return new Promise((resolve, reject) => {
10 | const onReady = () => {
11 | strapi.log.info('REST Cache provider "redis": connection established');
12 |
13 | // eslint-disable-next-line no-use-before-define
14 | client.off("error", onError);
15 | resolve();
16 | };
17 | const onError = (error) => {
18 | client.off("ready", onReady);
19 | reject(
20 | new Error(
21 | `Could not initialize REST Cache provider "redis": ${error?.message}`
22 | )
23 | );
24 | };
25 |
26 | if (client.status === "ready") {
27 | return onReady();
28 | }
29 |
30 | client.once("ready", onReady);
31 | client.once("error", onError);
32 | });
33 | }
34 |
35 | module.exports = {
36 | provider: "redis",
37 | name: "Redis",
38 |
39 | async init(options, { strapi }) {
40 | if (!strapi.redis) {
41 | throw new Error(
42 | `Could not initialize REST Cache provider "redis". The package "strapi-plugin-redis" is required.`
43 | );
44 | }
45 |
46 | const connectionName = options.connection || "default";
47 | const { client } = strapi.redis.connections[connectionName] ?? {};
48 |
49 | if (!client) {
50 | throw new Error(
51 | `Could not initialize REST Cache provider "redis". No connection found with name "${connectionName}".`
52 | );
53 | }
54 |
55 | return waitForRedis(client).then(
56 | () => new RedisCacheProvider(client, options)
57 | );
58 | },
59 | };
60 |
--------------------------------------------------------------------------------
/packages/strapi-provider-rest-cache-redis/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "strapi-provider-rest-cache-redis",
3 | "version": "4.2.9",
4 | "description": "Speed-up HTTP requests with LRU cache",
5 | "license": "MIT",
6 | "strapi": {
7 | "displayName": "REST Cache (redis)",
8 | "name": "strapi-provider-rest-cache-redis",
9 | "description": "Redis provider for REST Cache plugin",
10 | "kind": "plugin"
11 | },
12 | "keywords": [
13 | "strapi",
14 | "provider",
15 | "rest-cache",
16 | "redis"
17 | ],
18 | "author": {
19 | "name": "Strapi Community",
20 | "url": "https://github.com/strapi-community/"
21 | },
22 | "maintainers": [
23 | {
24 | "name": "Sacha Stafyniak",
25 | "email": "sacha@digisquad.io",
26 | "url": "https://digisquad.io"
27 | },
28 | {
29 | "name": "Patrick R",
30 | "url": "https://github.com/patrixr/"
31 | }
32 | ],
33 | "repository": {
34 | "type": "git",
35 | "url": "git+https://github.com/strapi-community/strapi-plugin-rest-cache.git",
36 | "directory": "packages/strapi-provider-rest-cache-redis"
37 | },
38 | "bugs": {
39 | "url": "https://github.com/strapi-community/strapi-plugin-rest-cache/issues"
40 | },
41 | "homepage": "https://strapi-community.github.io/strapi-plugin-rest-cache/",
42 | "main": "lib/index.js",
43 | "files": [
44 | "lib/**/*.js"
45 | ],
46 | "scripts": {
47 | "lint": "run-s eslint:fix prettier:fix",
48 | "eslint": "eslint ./lib",
49 | "eslint:fix": "eslint ./lib --fix",
50 | "prettier": "prettier --check ./lib",
51 | "prettier:fix": "prettier --write ./lib",
52 | "test": "run-s test:*",
53 | "test:lint": "run-s eslint prettier"
54 | },
55 | "dependencies": {
56 | "cache-manager": "^3.6.0",
57 | "cache-manager-ioredis": "^2.1.0"
58 | },
59 | "devDependencies": {
60 | "@strapi/strapi": "^4.11.7",
61 | "strapi-plugin-redis": "^1.0.1",
62 | "strapi-plugin-rest-cache": "^4.2.9"
63 | },
64 | "peerDependencies": {
65 | "@strapi/strapi": "^4.0.0",
66 | "strapi-plugin-rest-cache": "^4.0.0"
67 | },
68 | "engines": {
69 | "node": ">=14.0.0",
70 | "npm": ">=6.0.0"
71 | },
72 | "gitHead": "80f7c4b1c3915484e282597292cd1f5c749cbe8f"
73 | }
74 |
--------------------------------------------------------------------------------
/playgrounds/couchbase/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [{package.json,*.yml}]
12 | indent_style = space
13 | indent_size = 2
14 |
15 | [*.md]
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/playgrounds/couchbase/.env.example:
--------------------------------------------------------------------------------
1 | HOST=0.0.0.0
2 | PORT=1337
3 |
--------------------------------------------------------------------------------
/playgrounds/couchbase/.eslintignore:
--------------------------------------------------------------------------------
1 | .cache
2 | build
3 | **/node_modules/**
4 |
--------------------------------------------------------------------------------
/playgrounds/couchbase/.gitignore:
--------------------------------------------------------------------------------
1 | ############################
2 | # OS X
3 | ############################
4 |
5 | .DS_Store
6 | .AppleDouble
7 | .LSOverride
8 | Icon
9 | .Spotlight-V100
10 | .Trashes
11 | ._*
12 |
13 |
14 | ############################
15 | # Linux
16 | ############################
17 |
18 | *~
19 |
20 |
21 | ############################
22 | # Windows
23 | ############################
24 |
25 | Thumbs.db
26 | ehthumbs.db
27 | Desktop.ini
28 | $RECYCLE.BIN/
29 | *.cab
30 | *.msi
31 | *.msm
32 | *.msp
33 |
34 |
35 | ############################
36 | # Packages
37 | ############################
38 |
39 | *.7z
40 | *.csv
41 | *.dat
42 | *.dmg
43 | *.gz
44 | *.iso
45 | *.jar
46 | *.rar
47 | *.tar
48 | *.zip
49 | *.com
50 | *.class
51 | *.dll
52 | *.exe
53 | *.o
54 | *.seed
55 | *.so
56 | *.swo
57 | *.swp
58 | *.swn
59 | *.swm
60 | *.out
61 | *.pid
62 |
63 |
64 | ############################
65 | # Logs and databases
66 | ############################
67 |
68 | .tmp
69 | *.log
70 | *.sql
71 | *.sqlite
72 | *.sqlite3
73 |
74 |
75 | ############################
76 | # Misc.
77 | ############################
78 |
79 | *#
80 | ssl
81 | .idea
82 | nbproject
83 | public/uploads/*
84 | !public/uploads/.gitkeep
85 |
86 | ############################
87 | # Node.js
88 | ############################
89 |
90 | lib-cov
91 | lcov.info
92 | pids
93 | logs
94 | results
95 | node_modules
96 | .node_history
97 |
98 | ############################
99 | # Tests
100 | ############################
101 |
102 | testApp
103 | coverage
104 |
105 | ############################
106 | # Strapi
107 | ############################
108 |
109 | .env
110 | license.txt
111 | exports
112 | *.cache
113 | build
114 | .strapi-updater.json
115 |
116 | ############################
117 | # Shared files copied from the project root
118 | ############################
119 | config
120 | !config/plugins.js
121 | data
122 | src
123 | !src/.gitkeep
124 | tests
125 | !tests/.gitkeep
126 | start-profiler.js
--------------------------------------------------------------------------------
/playgrounds/couchbase/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## [4.2.4](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.2.3...v4.2.4) (2022-03-19)
7 |
8 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-couchbase
9 |
10 |
11 |
12 |
13 |
14 | ## [4.2.3](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.2.2...v4.2.3) (2022-03-18)
15 |
16 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-couchbase
17 |
18 |
19 |
20 |
21 |
22 | ## [4.2.2](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.2.1...v4.2.2) (2022-03-15)
23 |
24 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-couchbase
25 |
26 |
27 |
28 |
29 |
30 | ## [4.2.1](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.2.0...v4.2.1) (2022-03-11)
31 |
32 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-couchbase
33 |
34 |
35 |
36 |
37 |
38 | # [4.2.0](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.1.0...v4.2.0) (2022-03-09)
39 |
40 |
41 | ### Features
42 |
43 | * expose new clearByUid and clearByRegexp functions in cacheStore service ([c7d67fd](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/c7d67fd532ccca66df90b3621061ba2d65b70fe1))
44 |
45 |
46 |
47 |
48 |
49 | # [4.1.0](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.6...v4.1.0) (2022-03-05)
50 |
51 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-couchbase
52 |
53 |
54 |
55 |
56 |
57 | ## [4.0.6](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.5...v4.0.6) (2022-03-02)
58 |
59 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-couchbase
60 |
61 |
62 |
63 |
64 |
65 | ## [4.0.5](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.4...v4.0.5) (2022-03-02)
66 |
67 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-couchbase
68 |
69 |
70 |
71 |
72 |
73 | ## [4.0.4](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.3...v4.0.4) (2022-02-26)
74 |
75 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-couchbase
76 |
77 |
78 |
79 |
80 |
81 | ## [4.0.3](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.2...v4.0.3) (2022-02-26)
82 |
83 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-couchbase
84 |
85 |
86 |
87 |
88 |
89 | ## [4.0.2](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.1...v4.0.2) (2022-02-24)
90 |
91 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-couchbase
92 |
93 |
94 |
95 |
96 |
97 | ## [4.0.1](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.0...v4.0.1) (2022-02-24)
98 |
99 |
100 | ### Bug Fixes
101 |
102 | * empty npm packages ([1fde26a](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/1fde26a1da956c854661b036bc48483c49f9f75e))
103 |
104 |
105 |
106 |
107 |
108 | # [4.0.0](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.0-alpha.1...v4.0.0) (2022-01-31)
109 |
110 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-memory
111 |
112 |
113 |
114 |
115 |
116 | # [4.0.0-alpha.1](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.0-alpha.0...v4.0.0-alpha.1) (2022-01-31)
117 |
118 |
119 | ### Bug Fixes
120 |
121 | * peerDependencies fixed version ([f43ef96](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/f43ef96b87c274618ecd041b733ecfa22c824c74))
122 |
123 |
124 |
125 |
126 |
127 | # [4.0.0-alpha.0](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v1.0.1-alpha.0...v4.0.0-alpha.0) (2022-01-31)
128 |
129 |
130 | * feat(core)!: add keys alterations options ([a4214f2](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/a4214f2fb90259400c1c5a9701b83221ac2fa1bb))
131 |
132 |
133 | ### BREAKING CHANGES
134 |
135 | * move headers to keys.useHeaders
136 | add keys.useQueryParams option
137 |
--------------------------------------------------------------------------------
/playgrounds/couchbase/README.md:
--------------------------------------------------------------------------------
1 | # 🚀 Getting started with Strapi
2 |
3 | Strapi comes with a full featured [Command Line Interface](https://docs.strapi.io/developer-docs/latest/developer-resources/cli/CLI.html) (CLI) which lets you scaffold and manage your project in seconds.
4 |
5 | ### `develop`
6 |
7 | Start your Strapi application with autoReload enabled. [Learn more](https://docs.strapi.io/developer-docs/latest/developer-resources/cli/CLI.html#strapi-develop)
8 |
9 | ```
10 | npm run develop
11 | # or
12 | yarn develop
13 | ```
14 |
15 | ### `start`
16 |
17 | Start your Strapi application with autoReload disabled. [Learn more](https://docs.strapi.io/developer-docs/latest/developer-resources/cli/CLI.html#strapi-start)
18 |
19 | ```
20 | npm run start
21 | # or
22 | yarn start
23 | ```
24 |
25 | ### `build`
26 |
27 | Build your admin panel. [Learn more](https://docs.strapi.io/developer-docs/latest/developer-resources/cli/CLI.html#strapi-build)
28 |
29 | ```
30 | npm run build
31 | # or
32 | yarn build
33 | ```
34 |
35 | ## ⚙️ Deployment
36 |
37 | Strapi gives you many possible deployment options for your project. Find the one that suits you on the [deployment section of the documentation](https://docs.strapi.io/developer-docs/latest/setup-deployment-guides/deployment.html).
38 |
39 | ## 📚 Learn more
40 |
41 | - [Resource center](https://strapi.io/resource-center) - Strapi resource center.
42 | - [Strapi documentation](https://docs.strapi.io) - Official Strapi documentation.
43 | - [Strapi tutorials](https://strapi.io/tutorials) - List of tutorials made by the core team and the community.
44 | - [Strapi blog](https://docs.strapi.io) - Official Strapi blog containing articles made by the Strapi team and the community.
45 | - [Changelog](https://strapi.io/changelog) - Find out about the Strapi product updates, new features and general improvements.
46 |
47 | Feel free to check out the [Strapi GitHub repository](https://github.com/strapi/strapi). Your feedback and contributions are welcome!
48 |
49 | ## ✨ Community
50 |
51 | - [Discord](https://discord.strapi.io) - Come chat with the Strapi community including the core team.
52 | - [Forum](https://forum.strapi.io/) - Place to discuss, ask questions and find answers, show your Strapi project and get feedback or just talk with other Community members.
53 | - [Awesome Strapi](https://github.com/strapi/awesome-strapi) - A curated list of awesome things related to Strapi.
54 |
55 | ---
56 |
57 | 🤫 Psst! [Strapi is hiring](https://strapi.io/careers).
58 |
--------------------------------------------------------------------------------
/playgrounds/couchbase/config/plugins.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = ({ env }) => ({
4 | "rest-cache": {
5 | enabled: env.bool("ENABLE_CACHE", true),
6 | config: {
7 | provider: {
8 | name: "couchbase",
9 | max: 32767,
10 | options: {
11 | connectionString: "couchbase://127.0.0.1:8091",
12 | connectionOptions: {
13 | username: "Administrator",
14 | password: "Administrator",
15 | },
16 | bucket: "testbucket",
17 | ttl: 2,
18 | },
19 | },
20 |
21 | // loads shared config (from /shared folder)
22 | strategy: require("./cache-strategy")({ env }),
23 | },
24 | },
25 | "users-permissions": {
26 | config: {
27 | jwtSecret: env("JWT_SECRET", "b46375d2efd1c69d8efcdcb46d3acd67a"),
28 | },
29 | },
30 | });
31 |
--------------------------------------------------------------------------------
/playgrounds/couchbase/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 |
3 | services:
4 | couchbase:
5 | image: 'couchbase:enterprise-6.6.3'
6 | ports:
7 | - '8091-8094:8091-8094'
8 | - '11210:11210'
--------------------------------------------------------------------------------
/playgrounds/couchbase/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-rest-cache/7e08dc4715b0c231b9f6646045b5c9a8674b58fd/playgrounds/couchbase/favicon.ico
--------------------------------------------------------------------------------
/playgrounds/couchbase/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@strapi-plugin-rest-cache/playground-couchbase",
3 | "private": true,
4 | "version": "4.2.9",
5 | "description": "A Strapi application",
6 | "scripts": {
7 | "develop": "strapi develop",
8 | "start": "strapi start",
9 | "build": "strapi build",
10 | "strapi": "strapi",
11 | "test": "run-s test:*",
12 | "test:e2e": "jest --detectOpenHandles --forceExit"
13 | },
14 | "dependencies": {
15 | "@strapi/plugin-i18n": "4.11.7",
16 | "@strapi/plugin-users-permissions": "4.11.7",
17 | "@strapi/strapi": "4.11.7",
18 | "better-sqlite3": "8.0.1",
19 | "strapi-plugin-rest-cache": "^4.2.9",
20 | "strapi-provider-rest-cache-couchbase": "^4.2.9"
21 | },
22 | "author": {
23 | "name": "A Strapi developer"
24 | },
25 | "strapi": {
26 | "uuid": "89bd2494-df0e-4b1d-9e55-c46ec3e9952f"
27 | },
28 | "engines": {
29 | "node": ">=12.x.x",
30 | "npm": ">=6.0.0"
31 | },
32 | "license": "MIT"
33 | }
34 |
--------------------------------------------------------------------------------
/playgrounds/couchbase/public/robots.txt:
--------------------------------------------------------------------------------
1 | # To prevent search engines from seeing the site altogether, uncomment the next two lines:
2 | # User-Agent: *
3 | # Disallow: /
4 |
--------------------------------------------------------------------------------
/playgrounds/couchbase/public/uploads/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-rest-cache/7e08dc4715b0c231b9f6646045b5c9a8674b58fd/playgrounds/couchbase/public/uploads/.gitkeep
--------------------------------------------------------------------------------
/playgrounds/couchbase/src/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-rest-cache/7e08dc4715b0c231b9f6646045b5c9a8674b58fd/playgrounds/couchbase/src/.gitkeep
--------------------------------------------------------------------------------
/playgrounds/couchbase/tests/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-rest-cache/7e08dc4715b0c231b9f6646045b5c9a8674b58fd/playgrounds/couchbase/tests/.gitkeep
--------------------------------------------------------------------------------
/playgrounds/memory/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [{package.json,*.yml}]
12 | indent_style = space
13 | indent_size = 2
14 |
15 | [*.md]
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/playgrounds/memory/.env.example:
--------------------------------------------------------------------------------
1 | HOST=0.0.0.0
2 | PORT=1337
3 |
--------------------------------------------------------------------------------
/playgrounds/memory/.eslintignore:
--------------------------------------------------------------------------------
1 | .cache
2 | build
3 | **/node_modules/**
4 |
--------------------------------------------------------------------------------
/playgrounds/memory/.gitignore:
--------------------------------------------------------------------------------
1 | ############################
2 | # OS X
3 | ############################
4 |
5 | .DS_Store
6 | .AppleDouble
7 | .LSOverride
8 | Icon
9 | .Spotlight-V100
10 | .Trashes
11 | ._*
12 |
13 |
14 | ############################
15 | # Linux
16 | ############################
17 |
18 | *~
19 |
20 |
21 | ############################
22 | # Windows
23 | ############################
24 |
25 | Thumbs.db
26 | ehthumbs.db
27 | Desktop.ini
28 | $RECYCLE.BIN/
29 | *.cab
30 | *.msi
31 | *.msm
32 | *.msp
33 |
34 |
35 | ############################
36 | # Packages
37 | ############################
38 |
39 | *.7z
40 | *.csv
41 | *.dat
42 | *.dmg
43 | *.gz
44 | *.iso
45 | *.jar
46 | *.rar
47 | *.tar
48 | *.zip
49 | *.com
50 | *.class
51 | *.dll
52 | *.exe
53 | *.o
54 | *.seed
55 | *.so
56 | *.swo
57 | *.swp
58 | *.swn
59 | *.swm
60 | *.out
61 | *.pid
62 |
63 |
64 | ############################
65 | # Logs and databases
66 | ############################
67 |
68 | .tmp
69 | *.log
70 | *.sql
71 | *.sqlite
72 | *.sqlite3
73 |
74 |
75 | ############################
76 | # Misc.
77 | ############################
78 |
79 | *#
80 | ssl
81 | .idea
82 | nbproject
83 | public/uploads/*
84 | !public/uploads/.gitkeep
85 |
86 | ############################
87 | # Node.js
88 | ############################
89 |
90 | lib-cov
91 | lcov.info
92 | pids
93 | logs
94 | results
95 | node_modules
96 | .node_history
97 |
98 | ############################
99 | # Tests
100 | ############################
101 |
102 | testApp
103 | coverage
104 |
105 | ############################
106 | # Strapi
107 | ############################
108 |
109 | .env
110 | license.txt
111 | exports
112 | *.cache
113 | build
114 | .strapi-updater.json
115 |
116 | ############################
117 | # Shared files copied from the project root
118 | ############################
119 | config
120 | !config/plugins.js
121 | data
122 | src
123 | !src/.gitkeep
124 | tests
125 | !tests/.gitkeep
126 | start-profiler.js
--------------------------------------------------------------------------------
/playgrounds/memory/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## [4.2.4](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.2.3...v4.2.4) (2022-03-19)
7 |
8 |
9 | ### Bug Fixes
10 |
11 | * **perfs:** split keys computation into smaller functions ([5aba888](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/5aba8888cf132be241ef8a1ced7a83bfb1a626cb))
12 |
13 |
14 |
15 |
16 |
17 | ## [4.2.3](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.2.2...v4.2.3) (2022-03-18)
18 |
19 |
20 | ### Bug Fixes
21 |
22 | * **etag:** send a 304 (Not Modified) when valid If-None-Match header contains multiple values ([ccf936a](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/ccf936a02fbbb04a13bcf8143dd6009a3d1148c5))
23 |
24 |
25 |
26 |
27 |
28 | ## [4.2.2](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.2.1...v4.2.2) (2022-03-15)
29 |
30 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-memory
31 |
32 |
33 |
34 |
35 |
36 | ## [4.2.1](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.2.0...v4.2.1) (2022-03-11)
37 |
38 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-memory
39 |
40 |
41 |
42 |
43 |
44 | # [4.2.0](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.1.0...v4.2.0) (2022-03-09)
45 |
46 |
47 | ### Features
48 |
49 | * expose new clearByUid and clearByRegexp functions in cacheStore service ([c7d67fd](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/c7d67fd532ccca66df90b3621061ba2d65b70fe1))
50 |
51 |
52 |
53 |
54 |
55 | # [4.1.0](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.6...v4.1.0) (2022-03-05)
56 |
57 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-memory
58 |
59 |
60 |
61 |
62 |
63 | ## [4.0.6](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.5...v4.0.6) (2022-03-02)
64 |
65 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-memory
66 |
67 |
68 |
69 |
70 |
71 | ## [4.0.5](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.4...v4.0.5) (2022-03-02)
72 |
73 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-memory
74 |
75 |
76 |
77 |
78 |
79 | ## [4.0.4](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.3...v4.0.4) (2022-02-26)
80 |
81 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-memory
82 |
83 |
84 |
85 |
86 |
87 | ## [4.0.3](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.2...v4.0.3) (2022-02-26)
88 |
89 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-memory
90 |
91 |
92 |
93 |
94 |
95 | ## [4.0.2](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.1...v4.0.2) (2022-02-24)
96 |
97 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-memory
98 |
99 |
100 |
101 |
102 |
103 | ## [4.0.1](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.0...v4.0.1) (2022-02-24)
104 |
105 |
106 | ### Bug Fixes
107 |
108 | * empty npm packages ([1fde26a](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/1fde26a1da956c854661b036bc48483c49f9f75e))
109 |
110 |
111 |
112 |
113 |
114 | # [4.0.0](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.0-alpha.1...v4.0.0) (2022-01-31)
115 |
116 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-memory
117 |
118 |
119 |
120 |
121 |
122 | # [4.0.0-alpha.1](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.0-alpha.0...v4.0.0-alpha.1) (2022-01-31)
123 |
124 |
125 | ### Bug Fixes
126 |
127 | * peerDependencies fixed version ([f43ef96](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/f43ef96b87c274618ecd041b733ecfa22c824c74))
128 |
129 |
130 |
131 |
132 |
133 | # [4.0.0-alpha.0](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v1.0.1-alpha.0...v4.0.0-alpha.0) (2022-01-31)
134 |
135 |
136 | * feat(core)!: add keys alterations options ([a4214f2](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/a4214f2fb90259400c1c5a9701b83221ac2fa1bb))
137 |
138 |
139 | ### BREAKING CHANGES
140 |
141 | * move headers to keys.useHeaders
142 | add keys.useQueryParams option
143 |
--------------------------------------------------------------------------------
/playgrounds/memory/README.md:
--------------------------------------------------------------------------------
1 | # 🚀 Getting started with Strapi
2 |
3 | Strapi comes with a full featured [Command Line Interface](https://docs.strapi.io/developer-docs/latest/developer-resources/cli/CLI.html) (CLI) which lets you scaffold and manage your project in seconds.
4 |
5 | ### `develop`
6 |
7 | Start your Strapi application with autoReload enabled. [Learn more](https://docs.strapi.io/developer-docs/latest/developer-resources/cli/CLI.html#strapi-develop)
8 |
9 | ```
10 | npm run develop
11 | # or
12 | yarn develop
13 | ```
14 |
15 | ### `start`
16 |
17 | Start your Strapi application with autoReload disabled. [Learn more](https://docs.strapi.io/developer-docs/latest/developer-resources/cli/CLI.html#strapi-start)
18 |
19 | ```
20 | npm run start
21 | # or
22 | yarn start
23 | ```
24 |
25 | ### `build`
26 |
27 | Build your admin panel. [Learn more](https://docs.strapi.io/developer-docs/latest/developer-resources/cli/CLI.html#strapi-build)
28 |
29 | ```
30 | npm run build
31 | # or
32 | yarn build
33 | ```
34 |
35 | ## ⚙️ Deployment
36 |
37 | Strapi gives you many possible deployment options for your project. Find the one that suits you on the [deployment section of the documentation](https://docs.strapi.io/developer-docs/latest/setup-deployment-guides/deployment.html).
38 |
39 | ## 📚 Learn more
40 |
41 | - [Resource center](https://strapi.io/resource-center) - Strapi resource center.
42 | - [Strapi documentation](https://docs.strapi.io) - Official Strapi documentation.
43 | - [Strapi tutorials](https://strapi.io/tutorials) - List of tutorials made by the core team and the community.
44 | - [Strapi blog](https://docs.strapi.io) - Official Strapi blog containing articles made by the Strapi team and the community.
45 | - [Changelog](https://strapi.io/changelog) - Find out about the Strapi product updates, new features and general improvements.
46 |
47 | Feel free to check out the [Strapi GitHub repository](https://github.com/strapi/strapi). Your feedback and contributions are welcome!
48 |
49 | ## ✨ Community
50 |
51 | - [Discord](https://discord.strapi.io) - Come chat with the Strapi community including the core team.
52 | - [Forum](https://forum.strapi.io/) - Place to discuss, ask questions and find answers, show your Strapi project and get feedback or just talk with other Community members.
53 | - [Awesome Strapi](https://github.com/strapi/awesome-strapi) - A curated list of awesome things related to Strapi.
54 |
55 | ---
56 |
57 | 🤫 Psst! [Strapi is hiring](https://strapi.io/careers).
58 |
--------------------------------------------------------------------------------
/playgrounds/memory/config/plugins.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = ({ env }) => ({
4 | "rest-cache": {
5 | enabled: env.bool("ENABLE_CACHE", true),
6 | config: {
7 | provider: {
8 | name: "memory",
9 | max: 32767,
10 | },
11 | // loads shared config (from /shared folder)
12 | strategy: require("./cache-strategy")({ env }),
13 | },
14 | },
15 | "users-permissions": {
16 | config: {
17 | jwtSecret: env("JWT_SECRET", "b46375d2efd1c69d8efcdcb46d3acd67a"),
18 | },
19 | },
20 | });
21 |
--------------------------------------------------------------------------------
/playgrounds/memory/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-rest-cache/7e08dc4715b0c231b9f6646045b5c9a8674b58fd/playgrounds/memory/favicon.ico
--------------------------------------------------------------------------------
/playgrounds/memory/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@strapi-plugin-rest-cache/playground-memory",
3 | "private": true,
4 | "version": "4.2.9",
5 | "description": "A Strapi application",
6 | "scripts": {
7 | "develop": "strapi develop",
8 | "start": "strapi start",
9 | "build": "strapi build",
10 | "strapi": "strapi",
11 | "test": "run-s test:*",
12 | "test:e2e": "jest --detectOpenHandles --forceExit"
13 | },
14 | "dependencies": {
15 | "@strapi/plugin-i18n": "4.11.7",
16 | "@strapi/plugin-users-permissions": "4.11.7",
17 | "@strapi/strapi": "4.11.7",
18 | "better-sqlite3": "8.0.1",
19 | "strapi-plugin-rest-cache": "^4.2.9"
20 | },
21 | "devDependencies": {
22 | "jest": "^27.5.1",
23 | "npm-run-all": "^4.1.5",
24 | "supertest": "^6.2.2"
25 | },
26 | "author": {
27 | "name": "A Strapi developer"
28 | },
29 | "strapi": {
30 | "uuid": "89bd2494-df0e-4b1d-9e55-c46ec3e9952f"
31 | },
32 | "engines": {
33 | "node": ">=12.x.x",
34 | "npm": ">=6.0.0"
35 | },
36 | "license": "MIT"
37 | }
38 |
--------------------------------------------------------------------------------
/playgrounds/memory/public/robots.txt:
--------------------------------------------------------------------------------
1 | # To prevent search engines from seeing the site altogether, uncomment the next two lines:
2 | # User-Agent: *
3 | # Disallow: /
4 |
--------------------------------------------------------------------------------
/playgrounds/memory/public/uploads/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-rest-cache/7e08dc4715b0c231b9f6646045b5c9a8674b58fd/playgrounds/memory/public/uploads/.gitkeep
--------------------------------------------------------------------------------
/playgrounds/redis/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [{package.json,*.yml}]
12 | indent_style = space
13 | indent_size = 2
14 |
15 | [*.md]
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/playgrounds/redis/.env.example:
--------------------------------------------------------------------------------
1 | HOST=0.0.0.0
2 | PORT=1337
3 |
--------------------------------------------------------------------------------
/playgrounds/redis/.eslintignore:
--------------------------------------------------------------------------------
1 | .cache
2 | build
3 | **/node_modules/**
4 |
--------------------------------------------------------------------------------
/playgrounds/redis/.gitignore:
--------------------------------------------------------------------------------
1 | ############################
2 | # OS X
3 | ############################
4 |
5 | .DS_Store
6 | .AppleDouble
7 | .LSOverride
8 | Icon
9 | .Spotlight-V100
10 | .Trashes
11 | ._*
12 |
13 |
14 | ############################
15 | # Linux
16 | ############################
17 |
18 | *~
19 |
20 |
21 | ############################
22 | # Windows
23 | ############################
24 |
25 | Thumbs.db
26 | ehthumbs.db
27 | Desktop.ini
28 | $RECYCLE.BIN/
29 | *.cab
30 | *.msi
31 | *.msm
32 | *.msp
33 |
34 |
35 | ############################
36 | # Packages
37 | ############################
38 |
39 | *.7z
40 | *.csv
41 | *.dat
42 | *.dmg
43 | *.gz
44 | *.iso
45 | *.jar
46 | *.rar
47 | *.tar
48 | *.zip
49 | *.com
50 | *.class
51 | *.dll
52 | *.exe
53 | *.o
54 | *.seed
55 | *.so
56 | *.swo
57 | *.swp
58 | *.swn
59 | *.swm
60 | *.out
61 | *.pid
62 |
63 |
64 | ############################
65 | # Logs and databases
66 | ############################
67 |
68 | .tmp
69 | *.log
70 | *.sql
71 | *.sqlite
72 | *.sqlite3
73 |
74 |
75 | ############################
76 | # Misc.
77 | ############################
78 |
79 | *#
80 | ssl
81 | .idea
82 | nbproject
83 | public/uploads/*
84 | !public/uploads/.gitkeep
85 |
86 | ############################
87 | # Node.js
88 | ############################
89 |
90 | lib-cov
91 | lcov.info
92 | pids
93 | logs
94 | results
95 | node_modules
96 | .node_history
97 |
98 | ############################
99 | # Tests
100 | ############################
101 |
102 | testApp
103 | coverage
104 |
105 | ############################
106 | # Strapi
107 | ############################
108 |
109 | .env
110 | license.txt
111 | exports
112 | *.cache
113 | build
114 | .strapi-updater.json
115 |
116 | ############################
117 | # Shared files copied from the project root
118 | ############################
119 | config
120 | !config/plugins.js
121 | data
122 | src
123 | !src/.gitkeep
124 | tests
125 | !tests/.gitkeep
126 | start-profiler.js
--------------------------------------------------------------------------------
/playgrounds/redis/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## [4.2.4](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.2.3...v4.2.4) (2022-03-19)
7 |
8 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-redis
9 |
10 |
11 |
12 |
13 |
14 | ## [4.2.3](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.2.2...v4.2.3) (2022-03-18)
15 |
16 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-redis
17 |
18 |
19 |
20 |
21 |
22 | ## [4.2.2](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.2.1...v4.2.2) (2022-03-15)
23 |
24 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-redis
25 |
26 |
27 |
28 |
29 |
30 | ## [4.2.1](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.2.0...v4.2.1) (2022-03-11)
31 |
32 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-redis
33 |
34 |
35 |
36 |
37 |
38 | # [4.2.0](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.1.0...v4.2.0) (2022-03-09)
39 |
40 |
41 | ### Features
42 |
43 | * expose new clearByUid and clearByRegexp functions in cacheStore service ([c7d67fd](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/c7d67fd532ccca66df90b3621061ba2d65b70fe1))
44 |
45 |
46 |
47 |
48 |
49 | # [4.1.0](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.6...v4.1.0) (2022-03-05)
50 |
51 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-redis
52 |
53 |
54 |
55 |
56 |
57 | ## [4.0.6](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.5...v4.0.6) (2022-03-02)
58 |
59 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-redis
60 |
61 |
62 |
63 |
64 |
65 | ## [4.0.5](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.4...v4.0.5) (2022-03-02)
66 |
67 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-redis
68 |
69 |
70 |
71 |
72 |
73 | ## [4.0.4](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.3...v4.0.4) (2022-02-26)
74 |
75 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-redis
76 |
77 |
78 |
79 |
80 |
81 | ## [4.0.3](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.2...v4.0.3) (2022-02-26)
82 |
83 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-redis
84 |
85 |
86 |
87 |
88 |
89 | ## [4.0.2](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.1...v4.0.2) (2022-02-24)
90 |
91 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-redis
92 |
93 |
94 |
95 |
96 |
97 | ## [4.0.1](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.0...v4.0.1) (2022-02-24)
98 |
99 |
100 | ### Bug Fixes
101 |
102 | * empty npm packages ([1fde26a](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/1fde26a1da956c854661b036bc48483c49f9f75e))
103 |
104 |
105 |
106 |
107 |
108 | # [4.0.0](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.0-alpha.1...v4.0.0) (2022-01-31)
109 |
110 | **Note:** Version bump only for package @strapi-plugin-rest-cache/playground-redis
111 |
112 |
113 |
114 |
115 |
116 | # [4.0.0-alpha.1](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v4.0.0-alpha.0...v4.0.0-alpha.1) (2022-01-31)
117 |
118 |
119 | ### Bug Fixes
120 |
121 | * peerDependencies fixed version ([f43ef96](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/f43ef96b87c274618ecd041b733ecfa22c824c74))
122 |
123 |
124 |
125 |
126 |
127 | # [4.0.0-alpha.0](https://github.com/strapi-community/strapi-plugin-rest-cache/compare/v1.0.1-alpha.0...v4.0.0-alpha.0) (2022-01-31)
128 |
129 |
130 | * feat(core)!: add keys alterations options ([a4214f2](https://github.com/strapi-community/strapi-plugin-rest-cache/commit/a4214f2fb90259400c1c5a9701b83221ac2fa1bb))
131 |
132 |
133 | ### BREAKING CHANGES
134 |
135 | * move headers to keys.useHeaders
136 | add keys.useQueryParams option
137 |
--------------------------------------------------------------------------------
/playgrounds/redis/README.md:
--------------------------------------------------------------------------------
1 | # 🚀 Getting started with Strapi
2 |
3 | Strapi comes with a full featured [Command Line Interface](https://docs.strapi.io/developer-docs/latest/developer-resources/cli/CLI.html) (CLI) which lets you scaffold and manage your project in seconds.
4 |
5 | ### `develop`
6 |
7 | Start your Strapi application with autoReload enabled. [Learn more](https://docs.strapi.io/developer-docs/latest/developer-resources/cli/CLI.html#strapi-develop)
8 |
9 | ```
10 | npm run develop
11 | # or
12 | yarn develop
13 | ```
14 |
15 | ### `start`
16 |
17 | Start your Strapi application with autoReload disabled. [Learn more](https://docs.strapi.io/developer-docs/latest/developer-resources/cli/CLI.html#strapi-start)
18 |
19 | ```
20 | npm run start
21 | # or
22 | yarn start
23 | ```
24 |
25 | ### `build`
26 |
27 | Build your admin panel. [Learn more](https://docs.strapi.io/developer-docs/latest/developer-resources/cli/CLI.html#strapi-build)
28 |
29 | ```
30 | npm run build
31 | # or
32 | yarn build
33 | ```
34 |
35 | ## ⚙️ Deployment
36 |
37 | Strapi gives you many possible deployment options for your project. Find the one that suits you on the [deployment section of the documentation](https://docs.strapi.io/developer-docs/latest/setup-deployment-guides/deployment.html).
38 |
39 | ## 📚 Learn more
40 |
41 | - [Resource center](https://strapi.io/resource-center) - Strapi resource center.
42 | - [Strapi documentation](https://docs.strapi.io) - Official Strapi documentation.
43 | - [Strapi tutorials](https://strapi.io/tutorials) - List of tutorials made by the core team and the community.
44 | - [Strapi blog](https://docs.strapi.io) - Official Strapi blog containing articles made by the Strapi team and the community.
45 | - [Changelog](https://strapi.io/changelog) - Find out about the Strapi product updates, new features and general improvements.
46 |
47 | Feel free to check out the [Strapi GitHub repository](https://github.com/strapi/strapi). Your feedback and contributions are welcome!
48 |
49 | ## ✨ Community
50 |
51 | - [Discord](https://discord.strapi.io) - Come chat with the Strapi community including the core team.
52 | - [Forum](https://forum.strapi.io/) - Place to discuss, ask questions and find answers, show your Strapi project and get feedback or just talk with other Community members.
53 | - [Awesome Strapi](https://github.com/strapi/awesome-strapi) - A curated list of awesome things related to Strapi.
54 |
55 | ---
56 |
57 | 🤫 Psst! [Strapi is hiring](https://strapi.io/careers).
58 |
--------------------------------------------------------------------------------
/playgrounds/redis/config/plugins.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = ({ env }) => ({
4 | redis: {
5 | config: {
6 | debug: true,
7 | connections: {
8 | default: {
9 | connection: {
10 | host: "127.0.0.1",
11 | port: 6379,
12 | db: 0,
13 | },
14 | settings: {
15 | debug: false,
16 | cluster: false,
17 | },
18 | },
19 | },
20 | redlock: {
21 | enabled: true,
22 | databases: ["default"],
23 | options: {
24 | driftFactor: 0.01,
25 | retryCount: 10,
26 | retryDelay: 200,
27 | retryJitter: 200,
28 | automaticExtensionThreshold: 500,
29 | },
30 | },
31 | },
32 | },
33 | "rest-cache": {
34 | enabled: env.bool("ENABLE_CACHE", true),
35 | config: {
36 | provider: {
37 | name: "redis",
38 | options: {
39 | max: 32767,
40 | connection: "default",
41 | },
42 | },
43 | // loads shared config (from /shared folder)
44 | strategy: require("./cache-strategy")({ env }),
45 | },
46 | },
47 | "users-permissions": {
48 | config: {
49 | jwtSecret: env("JWT_SECRET", "b46375d2efd1c69d8efcdcb46d3acd67a"),
50 | },
51 | },
52 | });
53 |
--------------------------------------------------------------------------------
/playgrounds/redis/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 |
3 | services:
4 | redis:
5 | image: 'bitnami/redis:latest'
6 | environment:
7 | - ALLOW_EMPTY_PASSWORD=yes
8 | ports:
9 | - '6379:6379'
--------------------------------------------------------------------------------
/playgrounds/redis/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-rest-cache/7e08dc4715b0c231b9f6646045b5c9a8674b58fd/playgrounds/redis/favicon.ico
--------------------------------------------------------------------------------
/playgrounds/redis/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@strapi-plugin-rest-cache/playground-redis",
3 | "private": true,
4 | "version": "4.2.9",
5 | "description": "A Strapi application",
6 | "scripts": {
7 | "develop": "strapi develop",
8 | "start": "strapi start",
9 | "build": "strapi build",
10 | "strapi": "strapi",
11 | "test": "run-s test:*",
12 | "test:e2e": "jest --detectOpenHandles --forceExit"
13 | },
14 | "dependencies": {
15 | "@strapi/plugin-i18n": "4.11.7",
16 | "@strapi/plugin-users-permissions": "4.11.7",
17 | "@strapi/strapi": "4.11.7",
18 | "better-sqlite3": "8.0.1",
19 | "strapi-plugin-redis": "^1.0.1",
20 | "strapi-plugin-rest-cache": "^4.2.9",
21 | "strapi-provider-rest-cache-redis": "^4.2.9"
22 | },
23 | "devDependencies": {
24 | "jest": "^27.5.1",
25 | "npm-run-all": "^4.1.5",
26 | "supertest": "^6.2.2"
27 | },
28 | "author": {
29 | "name": "A Strapi developer"
30 | },
31 | "strapi": {
32 | "uuid": "89bd2494-df0e-4b1d-9e55-c46ec3e9952f"
33 | },
34 | "engines": {
35 | "node": ">=12.x.x",
36 | "npm": ">=6.0.0"
37 | },
38 | "license": "MIT"
39 | }
40 |
--------------------------------------------------------------------------------
/playgrounds/redis/public/robots.txt:
--------------------------------------------------------------------------------
1 | # To prevent search engines from seeing the site altogether, uncomment the next two lines:
2 | # User-Agent: *
3 | # Disallow: /
4 |
--------------------------------------------------------------------------------
/playgrounds/redis/public/uploads/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-rest-cache/7e08dc4715b0c231b9f6646045b5c9a8674b58fd/playgrounds/redis/public/uploads/.gitkeep
--------------------------------------------------------------------------------
/shared/config/admin.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = ({ env }) => ({
4 | auth: {
5 | secret: env("ADMIN_JWT_SECRET", "b46375d2efd1c69d8efcdcb46d3acd67"),
6 | },
7 | apiToken: {
8 | salt: env("API_TOKEN_SALT", "changeme"),
9 | },
10 | transfer: {
11 | token: {
12 | salt: env("TRANSFER_TOKEN_SALT", "changeme"),
13 | },
14 | },
15 | });
16 |
--------------------------------------------------------------------------------
/shared/config/api.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = {
4 | rest: {
5 | defaultLimit: 25,
6 | maxLimit: 100,
7 | withCount: true,
8 | },
9 | };
10 |
--------------------------------------------------------------------------------
/shared/config/cache-strategy.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = ({ env }) => ({
4 | debug: false,
5 | maxAge: env.int("ENABLE_MAX_AGE", 3600000),
6 | enableEtag: env.bool("ENABLE_ETAG", true),
7 | enableXCacheHeaders: env.bool("ENABLE_XCACHE_HEADERS", true),
8 | enableAdminCTBMiddleware: env.bool("ENABLE_ADMIN_CTB_MIDDLEWARE", true),
9 | resetOnStartup: env.bool("RESET_STARTUP", false),
10 | clearRelatedCache: env.bool("CREAR_RELATED_CACHE", true),
11 | keysPrefix: env.bool("KEYS_PREFIX", ''),
12 | keys: env.json("KEYS", {
13 | useHeaders: [],
14 | useQueryParams: true,
15 | }),
16 | hitpass: (ctx) =>
17 | Boolean(
18 | ctx.request.headers.authorization || ctx.request.headers.cookie
19 | ),
20 | contentTypes: [
21 | "api::article.article",
22 | "api::global.global",
23 | "api::homepage.homepage",
24 | {
25 | contentType: "api::category.category",
26 | maxAge: 3600000,
27 | hitpass: false,
28 | keys: {
29 | useQueryParams: false,
30 | useHeaders: ["accept-encoding"],
31 | },
32 | routes: [
33 | {
34 | path: "/api/categories/slug/:slug+",
35 | keys: {
36 | useQueryParams: ["populate", "locale"],
37 | useHeaders: [],
38 | },
39 | maxAge: 18000,
40 | method: "GET",
41 | },
42 | ],
43 | },
44 | ],
45 | });
--------------------------------------------------------------------------------
/shared/config/database.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const path = require("path");
4 |
5 | module.exports = ({ env }) => ({
6 | connection: {
7 | client: "sqlite",
8 | connection: {
9 | filename: path.join(
10 | __dirname,
11 | "..",
12 | env("DATABASE_FILENAME", ".tmp/data.db")
13 | ),
14 | },
15 | useNullAsDefault: true,
16 | },
17 | });
18 |
--------------------------------------------------------------------------------
/shared/config/env/test/database.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const { join } = require("path");
4 |
5 | module.exports = () => ({
6 | connection: {
7 | client: "sqlite",
8 | connection: {
9 | filename: join(__dirname, "../../../", ".tmp/tests.db"),
10 | },
11 | useNullAsDefault: true,
12 | },
13 | });
14 |
--------------------------------------------------------------------------------
/shared/config/logger.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = ({ env }) => ({
4 | level: env("STRAPI_LOG_LEVEL", "error"),
5 | });
--------------------------------------------------------------------------------
/shared/config/middlewares.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = [
4 | "strapi::errors",
5 | "strapi::security",
6 | "strapi::cors",
7 | "strapi::poweredBy",
8 | // "strapi::logger",
9 | "strapi::query",
10 | "strapi::session",
11 | "strapi::body",
12 | "strapi::favicon",
13 | "strapi::public",
14 | ];
15 |
--------------------------------------------------------------------------------
/shared/config/server.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = ({ env }) => ({
4 | host: env("HOST", "0.0.0.0"),
5 | port: env.int("PORT", 1337),
6 | app: {
7 | keys: env.array("APP_KEYS", ["testKey1", "testKey2"]),
8 | },
9 | });
10 |
--------------------------------------------------------------------------------
/shared/src/admin/app.example.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | export default {
4 | config: {
5 | locales: [
6 | // 'ar',
7 | // 'fr',
8 | // 'cs',
9 | // 'de',
10 | // 'dk',
11 | // 'es',
12 | // 'he',
13 | // 'id',
14 | // 'it',
15 | // 'ja',
16 | // 'ko',
17 | // 'ms',
18 | // 'nl',
19 | // 'no',
20 | // 'pl',
21 | // 'pt-BR',
22 | // 'pt',
23 | // 'ru',
24 | // 'sk',
25 | // 'sv',
26 | // 'th',
27 | // 'tr',
28 | // 'uk',
29 | // 'vi',
30 | // 'zh-Hans',
31 | // 'zh',
32 | ],
33 | },
34 | bootstrap(app) {
35 | console.log(app);
36 | },
37 | };
38 |
--------------------------------------------------------------------------------
/shared/src/admin/webpack.config.example.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | /* eslint-disable no-unused-vars */
4 | module.exports = (config, webpack) =>
5 | // Note: we provide webpack above so you should not `require` it
6 | // Perform customizations to webpack config
7 | // Important: return the modified config
8 | config;
9 |
--------------------------------------------------------------------------------
/shared/src/api/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-rest-cache/7e08dc4715b0c231b9f6646045b5c9a8674b58fd/shared/src/api/.gitkeep
--------------------------------------------------------------------------------
/shared/src/api/article/content-types/article/schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "kind": "collectionType",
3 | "collectionName": "articles",
4 | "info": {
5 | "singularName": "article",
6 | "pluralName": "articles",
7 | "displayName": "Article",
8 | "name": "article"
9 | },
10 | "options": {
11 | "increments": true,
12 | "timestamps": true,
13 | "draftAndPublish": true
14 | },
15 | "pluginOptions": {},
16 | "attributes": {
17 | "title": {
18 | "type": "string",
19 | "required": true
20 | },
21 | "description": {
22 | "type": "text",
23 | "required": true
24 | },
25 | "content": {
26 | "type": "richtext",
27 | "required": true
28 | },
29 | "slug": {
30 | "type": "uid",
31 | "targetField": "title",
32 | "required": true
33 | },
34 | "category": {
35 | "type": "relation",
36 | "relation": "manyToOne",
37 | "target": "api::category.category",
38 | "inversedBy": "articles"
39 | },
40 | "image": {
41 | "allowedTypes": [
42 | "images"
43 | ],
44 | "type": "media",
45 | "multiple": false
46 | },
47 | "author": {
48 | "type": "relation",
49 | "relation": "manyToOne",
50 | "target": "api::writer.writer",
51 | "inversedBy": "articles"
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/shared/src/api/article/controllers/article.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | /**
4 | * article controller
5 | */
6 |
7 | const { createCoreController } = require("@strapi/strapi").factories;
8 |
9 | module.exports = createCoreController("api::article.article");
10 |
--------------------------------------------------------------------------------
/shared/src/api/article/routes/article.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | /**
4 | * article router.
5 | */
6 |
7 | const { createCoreRouter } = require("@strapi/strapi").factories;
8 |
9 | module.exports = createCoreRouter("api::article.article");
10 |
--------------------------------------------------------------------------------
/shared/src/api/article/services/article.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | /**
4 | * article service.
5 | */
6 |
7 | const { createCoreService } = require("@strapi/strapi").factories;
8 |
9 | module.exports = createCoreService("api::article.article");
10 |
--------------------------------------------------------------------------------
/shared/src/api/category/content-types/category/schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "kind": "collectionType",
3 | "collectionName": "categories",
4 | "info": {
5 | "singularName": "category",
6 | "pluralName": "categories",
7 | "displayName": "Category",
8 | "name": "category"
9 | },
10 | "options": {
11 | "increments": true,
12 | "timestamps": true
13 | },
14 | "attributes": {
15 | "name": {
16 | "type": "string",
17 | "required": true
18 | },
19 | "slug": {
20 | "type": "uid",
21 | "targetField": "name",
22 | "required": true
23 | },
24 | "articles": {
25 | "type": "relation",
26 | "relation": "oneToMany",
27 | "target": "api::article.article",
28 | "mappedBy": "category"
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/shared/src/api/category/controllers/category.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | /**
4 | * category controller
5 | */
6 |
7 | const { createCoreController } = require("@strapi/strapi").factories;
8 |
9 | module.exports = createCoreController(
10 | "api::category.category",
11 | ({ strapi }) => ({
12 | async findBySlug(ctx) {
13 | const { slug } = ctx.params;
14 | const { query } = ctx;
15 |
16 | let populate;
17 | if (query.populate) {
18 | if (query.populate === "*") {
19 | populate = true;
20 | } else {
21 | populate = query.populate.split(",");
22 | }
23 | }
24 |
25 | const category = await strapi.db.query("api::category.category").findOne({
26 | where: {
27 | slug,
28 | },
29 | populate,
30 | });
31 |
32 | const sanitizedEntity = await this.sanitizeOutput(category, ctx);
33 |
34 | return this.transformResponse(sanitizedEntity);
35 | },
36 | })
37 | );
38 |
--------------------------------------------------------------------------------
/shared/src/api/category/routes/category.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | /**
4 | * category router.
5 | */
6 |
7 | const { createCoreRouter } = require("@strapi/strapi").factories;
8 |
9 | module.exports = createCoreRouter("api::category.category");
10 |
--------------------------------------------------------------------------------
/shared/src/api/category/routes/custom-category.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = {
4 | routes: [
5 | {
6 | method: "GET",
7 | path: "/categories/slug/:slug+",
8 | handler: "category.findBySlug",
9 | },
10 | ],
11 | };
12 |
--------------------------------------------------------------------------------
/shared/src/api/category/services/category.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | /**
4 | * category service.
5 | */
6 |
7 | const { createCoreService } = require("@strapi/strapi").factories;
8 |
9 | module.exports = createCoreService("api::category.category");
10 |
--------------------------------------------------------------------------------
/shared/src/api/global/content-types/global/schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "kind": "singleType",
3 | "collectionName": "globals",
4 | "info": {
5 | "singularName": "global",
6 | "pluralName": "globals",
7 | "displayName": "Global",
8 | "name": "global"
9 | },
10 | "options": {
11 | "increments": true,
12 | "timestamps": true,
13 | "draftAndPublish": false
14 | },
15 | "attributes": {
16 | "siteName": {
17 | "type": "string",
18 | "required": true
19 | },
20 | "defaultSeo": {
21 | "type": "component",
22 | "repeatable": false,
23 | "component": "shared.seo",
24 | "required": true
25 | },
26 | "favicon": {
27 | "allowedTypes": [
28 | "images",
29 | "files",
30 | "videos"
31 | ],
32 | "type": "media",
33 | "multiple": false
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/shared/src/api/global/controllers/global.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | /**
4 | * global controller
5 | */
6 |
7 | const { createCoreController } = require("@strapi/strapi").factories;
8 |
9 | module.exports = createCoreController("api::global.global");
10 |
--------------------------------------------------------------------------------
/shared/src/api/global/routes/global.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | /**
4 | * global router.
5 | */
6 |
7 | const { createCoreRouter } = require("@strapi/strapi").factories;
8 |
9 | module.exports = createCoreRouter("api::global.global");
10 |
--------------------------------------------------------------------------------
/shared/src/api/global/services/global.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | /**
4 | * global service.
5 | */
6 |
7 | const { createCoreService } = require("@strapi/strapi").factories;
8 |
9 | module.exports = createCoreService("api::global.global");
10 |
--------------------------------------------------------------------------------
/shared/src/api/homepage/content-types/homepage/schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "kind": "singleType",
3 | "collectionName": "homepages",
4 | "info": {
5 | "singularName": "homepage",
6 | "pluralName": "homepages",
7 | "displayName": "Homepage",
8 | "name": "homepage",
9 | "description": ""
10 | },
11 | "options": {
12 | "increments": true,
13 | "timestamps": true,
14 | "draftAndPublish": false
15 | },
16 | "pluginOptions": {
17 | "i18n": {
18 | "localized": true
19 | }
20 | },
21 | "attributes": {
22 | "seo": {
23 | "type": "component",
24 | "repeatable": false,
25 | "component": "shared.seo",
26 | "pluginOptions": {
27 | "i18n": {
28 | "localized": true
29 | }
30 | }
31 | },
32 | "hero": {
33 | "type": "component",
34 | "repeatable": false,
35 | "component": "sections.hero",
36 | "required": true,
37 | "pluginOptions": {
38 | "i18n": {
39 | "localized": true
40 | }
41 | }
42 | },
43 | "highlights": {
44 | "type": "component",
45 | "repeatable": false,
46 | "component": "sections.highlight",
47 | "pluginOptions": {
48 | "i18n": {
49 | "localized": true
50 | }
51 | }
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/shared/src/api/homepage/controllers/homepage.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | /**
4 | * homepage controller
5 | */
6 |
7 | const { createCoreController } = require("@strapi/strapi").factories;
8 |
9 | module.exports = createCoreController("api::homepage.homepage", {
10 | config: {
11 | find: {
12 | auth: false,
13 | },
14 | },
15 | });
16 |
--------------------------------------------------------------------------------
/shared/src/api/homepage/routes/homepage.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | /**
4 | * homepage router.
5 | */
6 |
7 | const { createCoreRouter } = require("@strapi/strapi").factories;
8 |
9 | module.exports = createCoreRouter("api::homepage.homepage");
10 |
--------------------------------------------------------------------------------
/shared/src/api/homepage/services/homepage.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | /**
4 | * homepage service.
5 | */
6 |
7 | const { createCoreService } = require("@strapi/strapi").factories;
8 |
9 | module.exports = createCoreService("api::homepage.homepage");
10 |
--------------------------------------------------------------------------------
/shared/src/api/writer/content-types/writer/schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "kind": "collectionType",
3 | "collectionName": "writers",
4 | "info": {
5 | "singularName": "writer",
6 | "pluralName": "writers",
7 | "displayName": "Writer",
8 | "name": "writer"
9 | },
10 | "options": {
11 | "increments": true,
12 | "timestamps": true
13 | },
14 | "attributes": {
15 | "name": {
16 | "type": "string"
17 | },
18 | "picture": {
19 | "allowedTypes": [
20 | "images",
21 | "files",
22 | "videos"
23 | ],
24 | "type": "media",
25 | "multiple": false
26 | },
27 | "articles": {
28 | "type": "relation",
29 | "relation": "oneToMany",
30 | "target": "api::article.article",
31 | "mappedBy": "author"
32 | },
33 | "email": {
34 | "type": "string"
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/shared/src/api/writer/controllers/writer.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | /**
4 | * writer controller
5 | */
6 |
7 | const { createCoreController } = require("@strapi/strapi").factories;
8 |
9 | module.exports = createCoreController("api::writer.writer");
10 |
--------------------------------------------------------------------------------
/shared/src/api/writer/routes/writer.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | /**
4 | * writer router.
5 | */
6 |
7 | const { createCoreRouter } = require("@strapi/strapi").factories;
8 |
9 | module.exports = createCoreRouter("api::writer.writer");
10 |
--------------------------------------------------------------------------------
/shared/src/api/writer/services/writer.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | /**
4 | * writer service.
5 | */
6 |
7 | const { createCoreService } = require("@strapi/strapi").factories;
8 |
9 | module.exports = createCoreService("api::writer.writer");
10 |
--------------------------------------------------------------------------------
/shared/src/components/sections/hero.json:
--------------------------------------------------------------------------------
1 | {
2 | "collectionName": "components_decoration_heroes",
3 | "info": {
4 | "name": "Hero",
5 | "icon": "address-card"
6 | },
7 | "options": {},
8 | "attributes": {
9 | "title": {
10 | "type": "string",
11 | "required": true
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/shared/src/components/sections/highlight.json:
--------------------------------------------------------------------------------
1 | {
2 | "collectionName": "components_sections_highlights",
3 | "info": {
4 | "displayName": "Highlight",
5 | "icon": "award"
6 | },
7 | "options": {},
8 | "attributes": {
9 | "articles": {
10 | "type": "relation",
11 | "relation": "oneToMany",
12 | "target": "api::article.article"
13 | },
14 | "category": {
15 | "type": "relation",
16 | "relation": "oneToOne",
17 | "target": "api::category.category"
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/shared/src/components/shared/seo.json:
--------------------------------------------------------------------------------
1 | {
2 | "collectionName": "components_shared_seos",
3 | "info": {
4 | "name": "Seo",
5 | "icon": "allergies"
6 | },
7 | "options": {},
8 | "attributes": {
9 | "metaTitle": {
10 | "type": "string",
11 | "required": true
12 | },
13 | "metaDescription": {
14 | "type": "text",
15 | "required": true
16 | },
17 | "shareImage": {
18 | "allowedTypes": [
19 | "images"
20 | ],
21 | "type": "media",
22 | "multiple": false
23 | },
24 | "highlights": {
25 | "type": "component",
26 | "repeatable": false,
27 | "component": "sections.highlight"
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/shared/src/extensions/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-rest-cache/7e08dc4715b0c231b9f6646045b5c9a8674b58fd/shared/src/extensions/.gitkeep
--------------------------------------------------------------------------------
/shared/src/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const { bootstrap } = require("./bootstrap");
4 |
5 | module.exports = {
6 | /**
7 | * An asynchronous register function that runs before
8 | * your application is initialized.
9 | *
10 | * This gives you an opportunity to extend code.
11 | */
12 | register(/* { strapi } */) {},
13 |
14 | /**
15 | * An asynchronous bootstrap function that runs before
16 | * your application gets started.
17 | *
18 | * This gives you an opportunity to set up your data model,
19 | * run jobs, or perform some special logic.
20 | */
21 | bootstrap
22 | };
23 |
--------------------------------------------------------------------------------
/shared/start-profiler.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | process.env.NODE_ENV = 'test';
4 |
5 | const Strapi = require("@strapi/strapi");
6 |
7 | async function setup() {
8 | Strapi({
9 | dir: __dirname,
10 | });
11 | await strapi.start();
12 |
13 | return Promise.resolve(strapi);
14 | }
15 |
16 | // eslint-disable-next-line no-console
17 | setup().catch(console.error);
18 |
--------------------------------------------------------------------------------
/shared/tests/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@strapi-community/tests"
3 | }
4 |
--------------------------------------------------------------------------------
/shared/tests/helpers/strapi.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const { existsSync, unlinkSync } = require("fs");
4 | const Strapi = require("@strapi/strapi");
5 | const supertest = require("supertest");
6 | const { join } = require("path");
7 |
8 | let adminToken;
9 |
10 | function agent() {
11 | return supertest.agent(strapi.server.httpServer);
12 | }
13 | function adminAgent() {
14 | return supertest
15 | .agent(strapi.server.httpServer)
16 | .auth(adminToken, { type: "bearer" });
17 | }
18 |
19 | async function setup() {
20 | Strapi({
21 | dir: join(__dirname, "../../"),
22 | });
23 | await strapi.start();
24 |
25 | // create first admin
26 | await agent().post("/admin/register-admin").send({
27 | email: "admin@strapi.io",
28 | firstname: "admin",
29 | lastname: "admin",
30 | password: "Password123",
31 | });
32 |
33 | const response = await agent().post("/admin/login").send({
34 | email: "admin@strapi.io",
35 | password: "Password123",
36 | });
37 |
38 | adminToken = response.body.data.token;
39 |
40 | return Promise.resolve(strapi);
41 | }
42 |
43 | async function teardown() {
44 | const dbSettings = strapi.config.get("database.connection.connection");
45 |
46 | // close server to release the db-file
47 | await strapi.destroy();
48 |
49 | // delete test database after all tests
50 | if (dbSettings && dbSettings.filename) {
51 | const tmpDbFile = `${dbSettings.filename}`;
52 |
53 | if (existsSync(tmpDbFile)) {
54 | unlinkSync(tmpDbFile);
55 | }
56 | }
57 |
58 | return Promise.resolve();
59 | }
60 |
61 | module.exports = {
62 | setup,
63 | teardown,
64 | agent,
65 | adminAgent,
66 | };
67 |
--------------------------------------------------------------------------------