├── .editorconfig
├── .gitattributes
├── .github
└── workflows
│ ├── deploy-docs.yml
│ ├── publish.yml
│ ├── run-tests.yml
│ └── test-deploy-docs.yml
├── .gitignore
├── .markdownlint.json
├── .npmignore
├── .npmrc
├── .prettierrc.js
├── CODE_OF_CONDUCT.md
├── LICENSE.md
├── README.md
├── docs
├── .gitignore
├── README.md
├── babel.config.js
├── docs
│ ├── api
│ │ ├── client.md
│ │ ├── config.md
│ │ ├── connections.md
│ │ └── intro.md
│ ├── best-practices.md
│ ├── faq.md
│ ├── installation.md
│ ├── introduction.md
│ ├── plugins
│ │ └── rest-cache.md
│ └── redis
│ │ ├── basic.md
│ │ ├── cluster.md
│ │ ├── intro.md
│ │ ├── redlock.md
│ │ ├── sentinel.md
│ │ └── tls-auth.md
├── docusaurus.config.js
├── package.json
├── sidebars.js
├── src
│ ├── components
│ │ └── HomepageFeatures
│ │ │ ├── index.js
│ │ │ └── styles.module.css
│ └── css
│ │ └── custom.css
├── static
│ ├── .nojekyll
│ └── img
│ │ ├── docusaurus-social-card.jpg
│ │ ├── docusaurus.png
│ │ ├── favicon.ico
│ │ ├── logo.svg
│ │ ├── undraw_docusaurus_mountain.svg
│ │ ├── undraw_docusaurus_react.svg
│ │ └── undraw_docusaurus_tree.svg
└── yarn.lock
├── package.json
├── server
├── config
│ └── index.js
├── index.js
├── register.js
└── services
│ ├── connection.js
│ └── index.js
├── strapi-server.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
13 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # From https://github.com/Danimoth/gitattributes/blob/master/Web.gitattributes
2 |
3 | # Handle line endings automatically for files detected as text
4 | # and leave all files detected as binary untouched.
5 | * text=auto
6 |
7 | #
8 | # The above will handle all files NOT found below
9 | #
10 |
11 | #
12 | ## These files are text and should be normalized (Convert crlf => lf)
13 | #
14 |
15 | # source code
16 | *.php text
17 | *.css text
18 | *.sass text
19 | *.scss text
20 | *.less text
21 | *.styl text
22 | *.js text eol=lf
23 | *.coffee text
24 | *.json text
25 | *.htm text
26 | *.html text
27 | *.xml text
28 | *.svg text
29 | *.txt text
30 | *.ini text
31 | *.inc text
32 | *.pl text
33 | *.rb text
34 | *.py text
35 | *.scm text
36 | *.sql text
37 | *.sh text
38 | *.bat text
39 |
40 | # templates
41 | *.ejs text
42 | *.hbt text
43 | *.jade text
44 | *.haml text
45 | *.hbs text
46 | *.dot text
47 | *.tmpl text
48 | *.phtml text
49 |
50 | # server config
51 | .htaccess text
52 |
53 | # git config
54 | .gitattributes text
55 | .gitignore text
56 | .gitconfig text
57 |
58 | # code analysis config
59 | .jshintrc text
60 | .jscsrc text
61 | .jshintignore text
62 | .csslintrc text
63 |
64 | # misc config
65 | *.yaml text
66 | *.yml text
67 | .editorconfig text
68 |
69 | # build config
70 | *.npmignore text
71 | *.bowerrc text
72 |
73 | # Heroku
74 | Procfile text
75 | .slugignore text
76 |
77 | # Documentation
78 | *.md text
79 | LICENSE text
80 | AUTHORS text
81 |
82 |
83 | #
84 | ## These files are binary and should be left untouched
85 | #
86 |
87 | # (binary is a macro for -text -diff)
88 | *.png binary
89 | *.jpg binary
90 | *.jpeg binary
91 | *.gif binary
92 | *.ico binary
93 | *.mov binary
94 | *.mp4 binary
95 | *.mp3 binary
96 | *.flv binary
97 | *.fla binary
98 | *.swf binary
99 | *.gz binary
100 | *.zip binary
101 | *.7z binary
102 | *.ttf binary
103 | *.eot binary
104 | *.woff binary
105 | *.pyc binary
106 | *.pdf binary
107 |
--------------------------------------------------------------------------------
/.github/workflows/deploy-docs.yml:
--------------------------------------------------------------------------------
1 | name: Deploy Docs to GitHub Pages
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | defaults:
9 | run:
10 | working-directory: docs
11 |
12 | jobs:
13 | build:
14 | name: Build Docusaurus
15 | runs-on: ubuntu-latest
16 | steps:
17 | - uses: actions/checkout@v4
18 | with:
19 | fetch-depth: 0
20 | - uses: actions/setup-node@v4
21 | with:
22 | node-version: 20
23 | cache: yarn
24 |
25 | - name: Install dependencies
26 | run: yarn install --frozen-lockfile
27 | - name: Build website
28 | run: yarn build
29 |
30 | - name: Upload Build Artifact
31 | uses: actions/upload-pages-artifact@v3
32 | with:
33 | path: ./docs/build
34 |
35 | deploy:
36 | name: Deploy to GitHub Pages
37 | needs: build
38 |
39 | # Grant GITHUB_TOKEN the permissions required to make a Pages deployment
40 | permissions:
41 | pages: write # to deploy to Pages
42 | id-token: write # to verify the deployment originates from an appropriate source
43 |
44 | # Deploy to the github-pages environment
45 | environment:
46 | name: github-pages
47 | url: ${{ steps.deployment.outputs.page_url }}
48 |
49 | runs-on: ubuntu-latest
50 | steps:
51 | - name: Deploy to GitHub Pages
52 | id: deployment
53 | uses: actions/deploy-pages@v4
54 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish Package to npmjs
2 | on:
3 | release:
4 | types: [published]
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 | permissions:
9 | contents: read
10 | id-token: write
11 | steps:
12 | - uses: actions/checkout@v4
13 | - uses: actions/setup-node@v4
14 | with:
15 | node-version: '20.x'
16 | registry-url: 'https://registry.npmjs.org'
17 | - run: yarn install --frozen-lockfile
18 | - run: npm publish --provenance --access public
19 | env:
20 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
21 |
--------------------------------------------------------------------------------
/.github/workflows/run-tests.yml:
--------------------------------------------------------------------------------
1 | name: 'Standard Tests'
2 |
3 | on: push
4 |
5 | jobs:
6 | # lint:
7 | # runs-on: ubuntu-latest
8 | # strategy:
9 | # matrix:
10 | # node: [14, 16]
11 | # steps:
12 | # - uses: actions/checkout@v2
13 | # - uses: actions/setup-node@v2-beta
14 | # with:
15 | # node-version: ${{ matrix.node }}
16 | # - name: Install modules
17 | # run: yarn
18 | # - name: Run lint
19 | # run: yarn eslint
20 | vulnerabilityScan:
21 | runs-on: ubuntu-latest
22 | steps:
23 | - uses: actions/checkout@master
24 | - name: Run Snyk to check for vulnerabilities
25 | uses: snyk/actions/node@master
26 | continue-on-error: true # To make sure that SARIF upload gets called
27 | env:
28 | SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
29 | with:
30 | args: --sarif-file-output=snyk.sarif
31 | - name: Upload result to GitHub Code Scanning
32 | uses: github/codeql-action/upload-sarif@v1
33 | with:
34 | sarif_file: snyk.sarif
35 |
--------------------------------------------------------------------------------
/.github/workflows/test-deploy-docs.yml:
--------------------------------------------------------------------------------
1 | name: Test Deploy Docs to GitHub Pages
2 |
3 | on:
4 | pull_request:
5 | branches:
6 | - main
7 |
8 | defaults:
9 | run:
10 | working-directory: docs
11 |
12 | jobs:
13 | test-deploy:
14 | name: Test deployment
15 | runs-on: ubuntu-latest
16 | steps:
17 | - uses: actions/checkout@v4
18 | with:
19 | fetch-depth: 0
20 | - uses: actions/setup-node@v4
21 | with:
22 | node-version: 20
23 | cache: yarn
24 |
25 | - name: Install dependencies
26 | run: yarn install --frozen-lockfile
27 | - name: Test build website
28 | run: yarn build
29 |
--------------------------------------------------------------------------------
/.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 |
73 |
74 | ############################
75 | # Misc.
76 | ############################
77 |
78 | *#
79 | .idea
80 | nbproject
81 | .vscode/
82 |
83 |
84 | ############################
85 | # Node.js
86 | ############################
87 |
88 | lib-cov
89 | lcov.info
90 | pids
91 | logs
92 | results
93 | build
94 | node_modules
95 | .node_history
96 | package-lock.json
97 | **/package-lock.json
98 | !docs/package-lock.json
99 | *.heapsnapshot
100 |
101 |
102 | ############################
103 | # Tests
104 | ############################
105 |
106 | testApp
107 | coverage
108 | cypress/screenshots
109 | cypress/videos
110 |
111 |
112 | ############################
113 | # Documentation
114 | ############################
115 |
116 | dist
117 |
118 | ############################
119 | # Builds
120 | ############################
121 |
122 | packages/generators/app/files/public/
123 | schema.graphql
124 |
125 | ############################
126 | # Example app
127 | ############################
128 |
129 | .dev
130 | # *.cache
131 |
132 | ############################
133 | # Visual Studio Code
134 | ############################
135 |
136 | front-workspace.code-workspace
137 | .yarn
138 | .yarnrc
139 |
--------------------------------------------------------------------------------
/.markdownlint.json:
--------------------------------------------------------------------------------
1 | {
2 | "default": true,
3 | "MD033": false,
4 | "MD013": false
5 | }
6 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 | .DS_Store
4 | *.tgz
5 | *.log
6 | .idea
7 | .vscode
8 | *.sublime-project
9 | *.sublime-workspace
10 | *.swp
11 | *.swo
12 | *.bak
13 | *.tmp
14 | *.temp
15 | *.orig
16 | *.rej
17 | *.patch
18 | *.diff
19 | *.sublime-*
20 | docs*
21 | .github*
22 | .editorconfig
23 | .gitattributes
24 | .markdownlint.json
25 | .prettierrc.js
26 | CODE_OF_CONDUCT.md
27 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
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 | };
9 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | * Demonstrating empathy and kindness toward other people
21 | * Being respectful of differing opinions, viewpoints, and experiences
22 | * Giving and gracefully accepting constructive feedback
23 | * Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | * Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | * The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | * Trolling, insulting or derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | [@boazpoolman](https://twitter.com/boazpoolman) on twitter.
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright (c) 2024 Strapi Community Org - https://github.com/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.
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
Strapi Redis Plugin
3 |
4 |
Redis Connector Package for use in other plugins and packages.
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | ## Table of Contents
20 |
21 | - [🚦 Current Status](#-current-status)
22 | - [🛑 Foreword](#-foreword)
23 | - [✨ Features](#-features)
24 | - [🤔 Motivation](#-motivation)
25 | - [🖐 Requirements](#-requirements)
26 | - [⏳ Installation](#-installation)
27 | - [🔧 Configuration](#-configuration)
28 | - [Contributing](#contributing)
29 | - [License](#license)
30 |
31 | ## 🚦 Current Status
32 |
33 | This package is currently maintained and should be considered **Stable/GA** in terms of state. I/We are currently accepting contributions and/or dedicated contributors to help develop and maintain this package.
34 |
35 | For more information on contributing please see [the contrib message below](#contributing).
36 |
37 | ## 🛑 Foreword
38 |
39 | This package's lead maintainer is an employee of Strapi however this package is not officially maintained by Strapi Solutions SAS nor Strapi, Inc. and is currently maintained in the free time of the lead maintainer.
40 |
41 | > [!WARNING]
42 | **Absolutely no part of this code should be considered covered under any agreement you have with Strapi proper** including but not limited to any Enterprise and/or Cloud Agreement you have with Strapi.
43 |
44 | ## ✨ Features
45 |
46 | This plugin utilizes 2 core packages:
47 |
48 | - [ioredis](https://github.com/luin/ioredis) - for all connection management to any Redis or Redis-compatible database
49 | - [redlock](https://github.com/mike-marcacci/node-redlock) - for distributed locks related to Strapi's built in cron-tasks system
50 |
51 | These are the primary features that are finished or currently being worked on:
52 |
53 | - [ ] Updated/New Documentation outside of this README
54 | - [x] Multiple connections/databases
55 | - [x] Redlock capabilities with Strapi's built-in cron tasks
56 | - [ ] Admin Panel interface to see all existing connections
57 | - [ ] Admin Panel interface to see the stored key/values within the connections
58 | - [ ] Admin Panel interface to see the current server statistics
59 |
60 | ## 🤔 Motivation
61 |
62 | The purpose of this package is to have a universal Redis connector for all packages wanting to utilize a Redis database and/or for those wanting to develop custom functions and code within your Strapi project and would prefer a centralized Redis database for various purposes.
63 |
64 | A few examples of where Redis could be used within a Strapi application:
65 |
66 | - LRU-based response cache for REST
67 | - Apollo server GraphQL cache
68 | - IP Rate-limiting using something like [koa2-ratelimit](https://www.npmjs.com/package/koa2-ratelimit)
69 | - Server-side user session storage
70 | - So much more
71 |
72 | If you are currently using this package in your plugin and would like to be featured, please feel free to submit an issue to have your plugin added to the list below:
73 |
74 | - [strapi-plugin-rest-cache](https://www.npmjs.com/package/strapi-plugin-rest-cache)
75 | - via: [strapi-provider-rest-cache-redis](https://www.npmjs.com/package/strapi-provider-rest-cache-redis)
76 | - More plugins coming soon!
77 |
78 | Note the following packages used to use this package with Strapi v4 but have since been merged into this package:
79 |
80 | - [strapi-plugin-redcron](https://www.npmjs.com/package/strapi-plugin-redcron)
81 |
82 | ## 🖐 Requirements
83 |
84 | > [!CAUTION]
85 | > This plugin will not work with Strapi v3 projects as it utilizes APIs that don't exist in the v3!
86 |
87 | Supported Strapi Versions:
88 |
89 | | Strapi Version | Plugin Version | Supported | Tested On |
90 | |----------------|----------------|-----------|-----------|
91 | | v3.x.x | N/A | ❌ | N/A |
92 | | v4.x.x | 1.1.0 | ✅ | Sept 2024 |
93 | | v5.x.x | 2.0.0 | ✅ | Sept 2024 |
94 |
95 | ## ⏳ Installation
96 |
97 | > [!WARNING]
98 | For Strapi 4 projects you should use the `1.x.x` version of this plugin, for Strapi 5 projects you should use the `2.x.x` version of this plugin.
99 |
100 | > [!NOTE]
101 | For Strapi 5 the package name has changed from `strapi-plugin-redis` to `@strapi-community/plugin-redis`.
102 |
103 | Install the plugin in your Strapi project or your Strapi plugin.
104 |
105 | | Strapi Version | Plugin Version | Package Manager | Command |
106 | |----------------|----------------|-----------------|-------------------------------------------|
107 | | v4.x.x | 1.1.0 | Yarn | `yarn add strapi-plugin-redis@1.1.0` |
108 | | v5.x.x | Latest | Yarn | `yarn add @strapi-community/plugin-redis` |
109 | | v4.x.x | 1.1.0 | npm | `npm i strapi-plugin-redis@1.1.0` |
110 | | v5.x.x | Latest | npm | `npm i @strapi-community/plugin-redis` |
111 |
112 | ## 🔧 Configuration
113 |
114 | See our [Documentation](https://strapi-community.github.io/plugin-redis/) for more information on how to configure and use this plugin.
115 |
116 | ## Contributing
117 |
118 | 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 help ease the connection to Redis databases.
119 |
120 | Instead of reinventing the wheel every time you need to connect to Redis, the hope is to centralize the connections in a single plugin that all plugins can piggy back on.
121 |
122 | If interested please feel free to open up a GitHub issue/PR or ping `DMehaffy` on Discord.
123 |
124 | > [!NOTE]
125 | This package is maintained collectively by the [strapi community organization](https://github.com/strapi-community). While there may be a lead maintainer, they are not the sole maintainer of this code and this code does not belong to the lead maintainer.
126 |
127 | ## License
128 |
129 | See the [LICENSE](./LICENSE.md) file for licensing information.
130 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | # Dependencies
2 | /node_modules
3 |
4 | # Production
5 | /build
6 |
7 | # Generated files
8 | .docusaurus
9 | .cache-loader
10 |
11 | # Misc
12 | .DS_Store
13 | .env.local
14 | .env.development.local
15 | .env.test.local
16 | .env.production.local
17 |
18 | npm-debug.log*
19 | yarn-debug.log*
20 | yarn-error.log*
21 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # Website
2 |
3 | This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator.
4 |
5 | ### Installation
6 |
7 | ```
8 | $ yarn
9 | ```
10 |
11 | ### Local Development
12 |
13 | ```
14 | $ yarn start
15 | ```
16 |
17 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
18 |
19 | ### Build
20 |
21 | ```
22 | $ yarn build
23 | ```
24 |
25 | This command generates static content into the `build` directory and can be served using any static contents hosting service.
26 |
27 | ### Deployment
28 |
29 | Using SSH:
30 |
31 | ```
32 | $ USE_SSH=true yarn deploy
33 | ```
34 |
35 | Not using SSH:
36 |
37 | ```
38 | $ GIT_USER= yarn deploy
39 | ```
40 |
41 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
42 |
--------------------------------------------------------------------------------
/docs/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
3 | };
4 |
--------------------------------------------------------------------------------
/docs/docs/api/client.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: 'Client'
3 | slug: '/api/client'
4 | ---
5 |
6 | # API Client
7 |
8 | Accessed with: `strapi.redis.connections.default.client`
9 | *Note you can swap the default key with any other named database you have configured*
10 |
11 | From here you have full access to the [ioredis API](https://github.com/luin/ioredis/blob/master/API.md).
12 |
--------------------------------------------------------------------------------
/docs/docs/api/config.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: 'Config'
3 | slug: '/api/config'
4 | ---
5 |
6 | # API Config
7 |
8 | Access with: `strapi.redis.config`
9 |
10 | The config key contains the entire plugin config including all ioredis instances configurations. These should not be modified after bootstrapping your Strapi application (aka while the server is running).
11 |
--------------------------------------------------------------------------------
/docs/docs/api/connections.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: 'Connections'
3 | slug: '/api/connections'
4 | ---
5 |
6 | # API Connections
7 |
8 | Access with: `strapi.redis.connections`
9 |
10 | For each connection either a normal Redis client is created, or if the cluster setting is enabled and you have properly passed in an array of nodes (and optionally any cluster options) a Redis Cluster client.
11 |
--------------------------------------------------------------------------------
/docs/docs/api/intro.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: 'Introduction'
3 | slug: '/api/intro'
4 | ---
5 |
6 | # API Introduction
7 |
8 | This plugin provides a Redis client for your Strapi application. It is based on the [ioredis](https://github.com/luin/ioredis/blob/master/API.md) package and provides a simple and easy-to-use interface for connecting to a Redis (or Redis alternative) database.
9 |
10 | More detailed examples for using this packages API will be coming shortly.
11 |
--------------------------------------------------------------------------------
/docs/docs/best-practices.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: 'Best Practices'
3 | slug: '/best-practices'
4 | ---
5 |
6 | # Best Practices
7 |
8 | Best practices will be coming soon, please check back later.
9 |
--------------------------------------------------------------------------------
/docs/docs/faq.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: 'FAQ'
3 | slug: '/faq'
4 | ---
5 |
6 | # Frequently Asked Questions
7 |
8 | ## Do you plan on implementing a feature for X?
9 |
10 | Probably not unless the feature request has been opened on the [GitHub Repo](https://github.com/strapi-community/plugin-redis) and up voted by the community. However we do also accept PRs for new features.
11 |
12 | ## How do I contribute to the project?
13 |
14 | Please open up a PR on the [GitHub Repo](https://github.com/strapi-community/plugin-redis), we will review it and merge it if it meets our standards. If you would like to discuss something before you contribute you are welcome to open an issue on the repo.
15 |
16 | ## Do you plan on rewriting this in Typescript or providing Typescript support?
17 |
18 | No, we do not plan on rewriting this in Typescript or providing Types. Certainly we will accept PRs if you believe you can provide a good implementation that doesn't overly complicate the code-base but in general you should be able to use the existing types provided by the `ioredis` package.
19 |
20 | The Lead maintainer of this package has a strong preference for Javascript over Typescript and does not see the value in rewriting the package in Typescript.
21 |
22 | ## I can't get the package to work, can you help me?
23 |
24 | Please open an issue on the [GitHub Repo](https://github.com/strapi-community/plugin-redis) and we will do our best to help you. Please provide as much information as possible including the version of Strapi you are using, the version of the plugin you are using, and any error messages you are seeing.
25 |
26 | Most of the time the issue is not with this plugin and is with your Redis configuration or your Strapi configuration. In many cases certain cloud providers have very strict network firewalls or restrictions that can prevent the connection.
27 |
--------------------------------------------------------------------------------
/docs/docs/installation.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: 'Installation'
3 | slug: '/installation'
4 | ---
5 |
6 | import Tabs from '@theme/Tabs';
7 | import TabItem from '@theme/TabItem';
8 |
9 | # Installation
10 |
11 | As of plugin version 2.0.0+, the plugin package name has changed to `@strapi-community/plugin-redis`.
12 | This change was made to align with the naming convention of official Strapi plugins.
13 |
14 | As such the following table outlines the plugin versions vs the Strapi versions they are compatible with:
15 |
16 | | Strapi Version | Plugin Version |
17 | |----------------|----------------|
18 | | 5.x.x | 2.x.x |
19 | | 4.x.x | 1.x.x |
20 | | 3.x.x | N/A |
21 |
22 | ## Installation for Strapi 5.x.x
23 |
24 | To install the plugin, run the following command:
25 |
26 |
27 |
28 |
29 | ```bash
30 | yarn add @strapi-community/plugin-redis
31 | ```
32 |
33 |
34 |
35 |
36 | ```bash
37 | npm install @strapi-community/plugin-redis --save
38 | ```
39 |
40 |
41 |
42 |
43 | ## Installation for Strapi 4.x.x
44 |
45 | To install the plugin, run the following command:
46 |
47 |
48 |
49 |
50 | ```bash
51 | yarn add strapi-plugin-redis
52 | ```
53 |
54 |
55 |
56 |
57 | ```bash
58 | npm install strapi-plugin-redis --save
59 | ```
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/docs/docs/introduction.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: 'Introduction'
3 | slug: '/'
4 | ---
5 |
6 | # Introduction
7 |
8 | The purpose of this package is to have a universal Redis connector for all packages wanting to utilize a Redis database and/or for those wanting to develop custom functions and code within your Strapi project and would prefer a centralized Redis database for various purposes.
9 |
10 | This package is a wrapper around the `ioredis` package and provides a simple and easy-to-use interface for connecting to a Redis (or Redis alternative) database.
11 |
12 | Likewise, this package also includes the `redlock` package for distributed locks. Currently, if you horizontally scale Strapi and use the cron feature, you will end up with multiple instances of Strapi running the same cron job at the same time, potentially causing race conditions. This can cause issues with your database or other services that you are trying to integrate with. If enabled the Redlock option will automatically force those cron jobs to establish a lock before running the job meaning that only one instance of Strapi will run the job at a time.
13 |
14 | ## Features
15 |
16 | - **Universal Redis Connector**: This package is a universal Redis connector for all packages wanting to utilize a Redis database.
17 | - **Multiple Redis Connections**: This package supports multiple Redis connections.
18 | - **Cluster/Sentinel Support**: This package supports Redis Cluster and Redis Sentinel.
19 | - **Redlock Support**: This package supports Redlock for distributed locks.
20 | - **Automatic Redlock CronTasks**: This package automatically uses Redlock for Strapi built-in CronTasks.
21 |
22 | ## Possible Future Features
23 |
24 | - **Admin Panel Interface to see all Redis Connections**: This package may include an admin panel interface to see all Redis connections and their status.
25 | - **Admin Panel Interface to see all Redis Key/Values**: This package may include an admin panel interface to see all Redis keys and their values.
26 | - **Admin Panel Interface to see all Redis Server Status**: This package may include an admin panel interface to see all Redis server status (memory usage, CPU usage, etc).
27 |
28 | ## Common Use-cases
29 |
30 | - **Caching**: This package can be used for caching data, for example see the LRU based plugin that uses this package called [REST Cache](/plugins/rest-cache).
31 | - **Apollo Server GraphQL Cache**: This package can be used for caching Apollo Server GraphQL data.
32 | - **IP based Rate Limiting**: This package can be used for IP based rate limiting using something like [koa2-ratelimit](https://www.npmjs.com/package/koa2-ratelimit).
33 | - **Server-side User Sessions**: This package can be used for server-side user session storage and management.
34 | - **So Much More**: The possibilities are endless!
35 |
--------------------------------------------------------------------------------
/docs/docs/plugins/rest-cache.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: 'REST Cache'
3 | slug: '/plugins/rest-cache'
4 | ---
5 |
6 | # REST Cache Plugin
7 |
8 | Details on this plugin are coming soon! Please check back later.
9 |
--------------------------------------------------------------------------------
/docs/docs/redis/basic.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: 'Basic'
3 | slug: '/redis/basic'
4 | ---
5 |
6 | # Basic Single Node Config
7 |
8 | The default configuration for the Redis plugin is a single node configuration. This is the most common configuration for Redis and is the default configuration for the plugin.
9 |
10 | ```javascript
11 | // path ./config/plugins.js
12 |
13 | module.exports = {
14 | redis: {
15 | config: {
16 | settings:{
17 | debug: false,
18 | enableRedlock: true,
19 | }
20 | connections: {
21 | default: {
22 | connection: {
23 | host: '127.0.0.1',
24 | port: 6379,
25 | db: 0,
26 | },
27 | settings: {
28 | debug: false,
29 | },
30 | },
31 | },
32 | },
33 | },
34 | };
35 | ```
36 |
--------------------------------------------------------------------------------
/docs/docs/redis/cluster.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: 'Cluster'
3 | slug: '/redis/cluster'
4 | ---
5 |
6 | # Cluster Config
7 |
8 | Cluster Configuration enable coming soon! Please check back later.
9 |
--------------------------------------------------------------------------------
/docs/docs/redis/intro.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: 'Introduction'
3 | slug: '/redis/intro'
4 | ---
5 |
6 | # Configuration Introduction
7 |
8 | The Redis plugin for Strapi is a simple wrapper around the [ioredis](https://github.com/luin/ioredis) package but also includes the [redlock](https://www.npmjs.com/package/redlock) package for distributed locks. This plugin provides a simple and easy-to-use interface for connecting to a Redis (or Redis alternative) database.
9 |
10 | ## Complete Configuration
11 |
12 | This configuration table does not include **all possible options** as many of them come from [ioredis](https://github.com/luin/ioredis) directly and what is shown here is mostly those options related to the plugin specifically and showing the default values.
13 |
14 | | Key | Description | Type | Default |
15 | |-------------------------------------------|---------------------------------------------------|---------|-------------|
16 | | `settings` | The settings for the Redis plugin. | Object | N/A |
17 | | `settings.debug` | Whether to enable debug mode. | Boolean | `false` |
18 | | `settings.debugIORedis` | Whether to enable debug mode for ioredis. | Boolean | `false` |
19 | | `settings.enableRedlock` | Whether to enable redlock for distributed locks. | Boolean | `false` |
20 | | `settings.lockDelay` | The delay in milliseconds for the lock. | Number | `null` |
21 | | `settings.lockTTL` | The time-to-live in milliseconds for the lock. | Number | `5000` |
22 | | `settings.redlockConfig` | The redlock configuration. | Object | N/A |
23 | | `settings.redlockConfig.driftFactor` | The drift factor for redlock. | Number | `0.01` |
24 | | `settings.redlockConfig.retryCount` | The retry count for redlock. | Number | `10` |
25 | | `settings.redlockConfig.retryDelay` | The retry delay for redlock. | Number | `200` |
26 | | `settings.redlockConfig.retryJitter` | The retry jitter for redlock. | Number | `200` |
27 | | `connections` | The connections for the Redis plugin. | Object | N/A |
28 | | `connections.default` | The default connection for the Redis plugin. | Object | N/A |
29 | | `connections.default.connection` | The object passed to ioredis directly | Object | N/A |
30 | | `connections.default.connection.host` | The host for the connection. | String | `127.0.0.1` |
31 | | `connections.default.connection.port` | The port for the connection. | Number | `6379` |
32 | | `connections.default.connection.password` | The password for the connection. | String | `null` |
33 | | `connections.default.connection.db` | The database for the connection. | Number | `0` |
34 | | `connections.default.settings` | The settings for the connection. | Object | N/A |
35 | | `connections.default.settings.debug` | Whether to enable debug mode for this connection. | Boolean | `false` |
36 |
--------------------------------------------------------------------------------
/docs/docs/redis/redlock.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: 'Redlock'
3 | slug: '/redis/redlock'
4 | ---
5 |
6 | # Redlock Config
7 |
8 | Redlock configuration is fairly easy to get setup and additional details for using it within Strapi's Crontasks is also lightly detailed below.
9 |
10 | ```javascript
11 | // path ./config/plugins.js
12 |
13 | module.exports = {
14 | redis: {
15 | config: {
16 | settings:{
17 | enableRedlock: true,
18 | lockDelay: null,
19 | lockTTL: 5000,
20 | redlockConfig: {
21 | driftFactor: 0.01,
22 | retryCount: 10,
23 | retryDelay: 200,
24 | retryJitter: 200,
25 | },
26 | },
27 | connections: {
28 | //...
29 | },
30 | },
31 | },
32 | };
33 | ```
34 |
35 | ## Cron Task Example
36 |
37 | Adding the bypassRedlock property to your cron job will bypass the redlock logic and allow multiple instances of Strapi to run the same cron job at the same time.
38 |
39 | This plugin requires you to use the object format of the cron config. i.e if you are using the rule as the key, you will need to change it to an object with the rule as a property and the key as a unique name. This is because across your Strapi instances, Redis needs to lock onto a key that is the same across all instances.
40 |
41 | ### Normal Cron Task Example
42 |
43 | ```javascript
44 | // path ./config/cron-tasks.js
45 |
46 | module.exports = {
47 | myJob: {
48 | task: ({ strapi }) => {/* Add your own logic here */ },
49 | bypassRedlock: false, // optional
50 | options: {
51 | rule: '0 0 1 * * 1',
52 | },
53 | },
54 | };
55 | ```
56 |
57 | ### Bootstrap Example
58 |
59 | ```javascript
60 | // path ./src/index.js
61 |
62 | module.exports = {
63 | register(/* { Strapi } */) {},
64 | bootstrap({ strapi }) {
65 | strapi.cron.add({
66 | myJob: {
67 | task: async ({ strapi }) => {
68 | console.log("hello from bootstrap")
69 | },
70 | bypassRedlock: false, // optional
71 | options: {
72 | rule: '*/10 * * * * *',
73 | }
74 | },
75 | });
76 | }
77 | };
78 | ```
79 |
--------------------------------------------------------------------------------
/docs/docs/redis/sentinel.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: 'Sentinel'
3 | slug: '/redis/sentinel'
4 | ---
5 |
6 | # Redis Sentinel Replica Config (3 Node)
7 |
8 | The Redis plugin supports Redis Sentinel for high availability and failover. This is a common configuration for Redis in production environments.
9 |
10 | ```javascript
11 | // path ./config/plugins.js
12 |
13 | module.exports = {
14 | redis: {
15 | config: {
16 | settings:{
17 | debug: false,
18 | enableRedlock: true,
19 | }
20 | connections: {
21 | default: {
22 | connection: {
23 | sentinels: [
24 | { host: '192.168.1.101', port: 26379 },
25 | { host: '192.168.1.102', port: 26379 },
26 | { host: '192.168.1.103', port: 26379 },
27 | ],
28 | name: 'my-redis-replicaSet',
29 | db: 0,
30 | },
31 | settings: {
32 | debug: false,
33 | },
34 | },
35 | },
36 | },
37 | },
38 | };
39 | ```
40 |
--------------------------------------------------------------------------------
/docs/docs/redis/tls-auth.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_label: 'TLS Authentication'
3 | slug: '/redis/tls-auth'
4 | ---
5 |
6 | # TLS Authentication
7 |
8 | To enable TLS authentication, you need to provide the `tls` option in the connection configuration and load in the necessary certificates.
9 |
10 | ```javascript
11 | // path ./config/plugins.js
12 | const { readFileSync } = require('fs');
13 |
14 | module.exports = {
15 | redis: {
16 | config: {
17 | settings:{
18 | debug: false,
19 | enableRedlock: true,
20 | },
21 | connections: {
22 | default: {
23 | connection: {
24 | // @see https://github.com/luin/ioredis/blob/master/API.md#new-redisport-host-options
25 | host: '127.0.0.1',
26 | port: 6379,
27 | db: 0,
28 | username: 'username',
29 | password: 'secret',
30 | // @see https://github.com/luin/ioredis#tls-options
31 | tls: {
32 | ca: readFileSync('cert.pem'),
33 | },
34 | },
35 | settings: {
36 | debug: false,
37 | },
38 | },
39 | },
40 | },
41 | },
42 | };
43 | ```
44 |
--------------------------------------------------------------------------------
/docs/docusaurus.config.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 |
3 | import { themes as prismThemes } from 'prism-react-renderer';
4 |
5 | /** @type {import('@docusaurus/types').Config} */
6 | const config = {
7 | title: 'Strapi Plugin Redis',
8 | tagline: 'Connecting Strapi to Redis with ease',
9 | favicon: 'img/favicon.ico',
10 | url: 'https://your-docusaurus-site.example.com',
11 | baseUrl: 'plugin-redis/',
12 | organizationName: 'strapi-community', // Usually your GitHub org/user name.
13 | projectName: 'plugin-redis', // Usually your repo name.
14 | onBrokenLinks: 'throw',
15 | onBrokenMarkdownLinks: 'warn',
16 | trailingSlash: false,
17 |
18 | themes: ['@docusaurus/theme-mermaid'],
19 |
20 | i18n: {
21 | defaultLocale: 'en',
22 | locales: ['en'],
23 | },
24 |
25 | markdown: {
26 | mermaid: true,
27 | },
28 |
29 | plugins: [
30 | [
31 | '@cmfcmf/docusaurus-search-local',
32 | {
33 | indexBlog: false,
34 | },
35 | ],
36 | ],
37 |
38 | presets: [
39 | [
40 | 'classic',
41 | /** @type {import('@docusaurus/preset-classic').Options} */
42 | {
43 | docs: {
44 | routeBasePath: '/',
45 | sidebarPath: './sidebars.js',
46 | editUrl: 'https://github.com/strapi-community/plugin-redis/docs/',
47 | },
48 | blog: false,
49 | },
50 | ],
51 | ],
52 |
53 | themeConfig:
54 | /** @type {import('@docusaurus/preset-classic').ThemeConfig} */
55 | ({
56 | // Replace with your project's social card
57 | image: 'img/docusaurus-social-card.jpg',
58 | navbar: {
59 | title: 'Strapi Plugin Redis',
60 | logo: {
61 | alt: 'My Site Logo',
62 | src: 'img/logo.svg',
63 | },
64 | items: [
65 | {
66 | href: 'https://github.com/strapi-community/plugin-redis',
67 | label: 'GitHub',
68 | position: 'right',
69 | },
70 | ],
71 | },
72 | footer: {
73 | style: 'dark',
74 | copyright: `Copyright © ${new Date().getFullYear()} Strapi Community Organization`,
75 | },
76 | prism: {
77 | theme: prismThemes.github,
78 | darkTheme: prismThemes.dracula,
79 | },
80 | }),
81 | };
82 |
83 | export default config;
84 |
--------------------------------------------------------------------------------
/docs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "docs",
3 | "version": "2.0.0",
4 | "private": true,
5 | "scripts": {
6 | "docusaurus": "docusaurus",
7 | "start": "docusaurus start",
8 | "build": "docusaurus build",
9 | "swizzle": "docusaurus swizzle",
10 | "deploy": "docusaurus deploy",
11 | "clear": "docusaurus clear",
12 | "serve": "docusaurus serve",
13 | "write-translations": "docusaurus write-translations",
14 | "write-heading-ids": "docusaurus write-heading-ids"
15 | },
16 | "dependencies": {
17 | "@cmfcmf/docusaurus-search-local": "^1.2.0",
18 | "@docusaurus/core": "3.5.2",
19 | "@docusaurus/preset-classic": "3.5.2",
20 | "@docusaurus/theme-mermaid": "^3.5.2",
21 | "@mdx-js/react": "^3.0.0",
22 | "clsx": "^2.0.0",
23 | "prism-react-renderer": "^2.3.0",
24 | "react": "^18.0.0",
25 | "react-dom": "^18.0.0"
26 | },
27 | "devDependencies": {
28 | "@docusaurus/module-type-aliases": "3.5.2",
29 | "@docusaurus/types": "3.5.2"
30 | },
31 | "browserslist": {
32 | "production": [
33 | ">0.5%",
34 | "not dead",
35 | "not op_mini all"
36 | ],
37 | "development": [
38 | "last 3 chrome version",
39 | "last 3 firefox version",
40 | "last 5 safari version"
41 | ]
42 | },
43 | "resolutions": {
44 | "cheerio": "1.0.0-rc.12"
45 | },
46 | "engines": {
47 | "node": ">=18.0"
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/docs/sidebars.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 |
3 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
4 | const sidebars = {
5 | default: [
6 | {
7 | type: 'doc',
8 | id: 'introduction',
9 | },
10 | {
11 | type: 'doc',
12 | id: 'installation',
13 | },
14 | {
15 | type: 'doc',
16 | id: 'best-practices',
17 | },
18 | {
19 | type: 'doc',
20 | id: 'faq',
21 | },
22 | {
23 | type: 'category',
24 | label: 'Configuration',
25 | items: [
26 | 'redis/intro',
27 | 'redis/basic',
28 | 'redis/sentinel',
29 | 'redis/tls-auth',
30 | 'redis/cluster',
31 | 'redis/redlock',
32 | ],
33 | collapsed: false,
34 | },
35 | {
36 | type: 'category',
37 | label: 'Plugins',
38 | items: ['plugins/rest-cache'],
39 | },
40 | {
41 | type: 'category',
42 | label: 'API',
43 | items: ['api/intro', 'api/client', 'api/config', 'api/connections'],
44 | },
45 | ],
46 | };
47 |
48 | export default sidebars;
49 |
--------------------------------------------------------------------------------
/docs/src/components/HomepageFeatures/index.js:
--------------------------------------------------------------------------------
1 | import clsx from 'clsx';
2 | import Heading from '@theme/Heading';
3 | import styles from './styles.module.css';
4 |
5 | const FeatureList = [
6 | {
7 | title: 'Easy to Use',
8 | Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default,
9 | description: (
10 | <>
11 | Docusaurus was designed from the ground up to be easily installed and
12 | used to get your website up and running quickly.
13 | >
14 | ),
15 | },
16 | {
17 | title: 'Focus on What Matters',
18 | Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default,
19 | description: (
20 | <>
21 | Docusaurus lets you focus on your docs, and we'll do the chores. Go
22 | ahead and move your docs into the docs
directory.
23 | >
24 | ),
25 | },
26 | {
27 | title: 'Powered by React',
28 | Svg: require('@site/static/img/undraw_docusaurus_react.svg').default,
29 | description: (
30 | <>
31 | Extend or customize your website layout by reusing React. Docusaurus can
32 | be extended while reusing the same header and footer.
33 | >
34 | ),
35 | },
36 | ];
37 |
38 | function Feature({Svg, title, description}) {
39 | return (
40 |
41 |
42 |
43 |
44 |
45 |
{title}
46 |
{description}
47 |
48 |
49 | );
50 | }
51 |
52 | export default function HomepageFeatures() {
53 | return (
54 |
55 |
56 |
57 | {FeatureList.map((props, idx) => (
58 |
59 | ))}
60 |
61 |
62 |
63 | );
64 | }
65 |
--------------------------------------------------------------------------------
/docs/src/components/HomepageFeatures/styles.module.css:
--------------------------------------------------------------------------------
1 | .features {
2 | display: flex;
3 | align-items: center;
4 | padding: 2rem 0;
5 | width: 100%;
6 | }
7 |
8 | .featureSvg {
9 | height: 200px;
10 | width: 200px;
11 | }
12 |
--------------------------------------------------------------------------------
/docs/src/css/custom.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Any CSS included here will be global. The classic template
3 | * bundles Infima by default. Infima is a CSS framework designed to
4 | * work well for content-centric websites.
5 | */
6 |
7 | /* You can override the default Infima variables here. */
8 | :root {
9 | --ifm-color-primary: #2e8555;
10 | --ifm-color-primary-dark: #29784c;
11 | --ifm-color-primary-darker: #277148;
12 | --ifm-color-primary-darkest: #205d3b;
13 | --ifm-color-primary-light: #33925d;
14 | --ifm-color-primary-lighter: #359962;
15 | --ifm-color-primary-lightest: #3cad6e;
16 | --ifm-code-font-size: 95%;
17 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);
18 | }
19 |
20 | /* For readability concerns, you should choose a lighter palette in dark mode. */
21 | [data-theme='dark'] {
22 | --ifm-color-primary: #25c2a0;
23 | --ifm-color-primary-dark: #21af90;
24 | --ifm-color-primary-darker: #1fa588;
25 | --ifm-color-primary-darkest: #1a8870;
26 | --ifm-color-primary-light: #29d5b0;
27 | --ifm-color-primary-lighter: #32d8b4;
28 | --ifm-color-primary-lightest: #4fddbf;
29 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);
30 | }
31 |
--------------------------------------------------------------------------------
/docs/static/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-redis/0c375ca642ad2b7d426fa286385a100e22c7e9f8/docs/static/.nojekyll
--------------------------------------------------------------------------------
/docs/static/img/docusaurus-social-card.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-redis/0c375ca642ad2b7d426fa286385a100e22c7e9f8/docs/static/img/docusaurus-social-card.jpg
--------------------------------------------------------------------------------
/docs/static/img/docusaurus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-redis/0c375ca642ad2b7d426fa286385a100e22c7e9f8/docs/static/img/docusaurus.png
--------------------------------------------------------------------------------
/docs/static/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/strapi-community/plugin-redis/0c375ca642ad2b7d426fa286385a100e22c7e9f8/docs/static/img/favicon.ico
--------------------------------------------------------------------------------
/docs/static/img/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/static/img/undraw_docusaurus_mountain.svg:
--------------------------------------------------------------------------------
1 |
172 |
--------------------------------------------------------------------------------
/docs/static/img/undraw_docusaurus_react.svg:
--------------------------------------------------------------------------------
1 |
171 |
--------------------------------------------------------------------------------
/docs/static/img/undraw_docusaurus_tree.svg:
--------------------------------------------------------------------------------
1 |
41 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@strapi-community/plugin-redis",
3 | "version": "2.0.0",
4 | "description": "Plugin used to centralize management of Redis connections in Strapi",
5 | "strapi": {
6 | "displayName": "Redis",
7 | "name": "redis",
8 | "description": "Plugin used to centralize management of Redis connections in Strapi",
9 | "required": false,
10 | "kind": "plugin"
11 | },
12 | "dependencies": {
13 | "chalk": "4.1.2",
14 | "debug": "4.3.5",
15 | "ioredis": "5.4.1",
16 | "redlock": "5.0.0-beta.2"
17 | },
18 | "peerDependencies": {
19 | "@strapi/strapi": "^5.0.0"
20 | },
21 | "scripts": {},
22 | "author": {
23 | "name": "Derrick Mehaffy",
24 | "email": "derrickmehaffy@gmail.com",
25 | "url": "https://github.com/derrickmehaffy"
26 | },
27 | "maintainers": [
28 | {
29 | "name": "Strapi Community",
30 | "url": "https://github.com/strapi-community"
31 | },
32 | {
33 | "name": "Derrick Mehaffy",
34 | "email": "derrickmehaffy@gmail.com",
35 | "url": "https://github.com/derrickmehaffy",
36 | "lead": true
37 | },
38 | {
39 | "name": "Excl Networks Inc."
40 | }
41 | ],
42 | "bugs": {
43 | "url": "https://github.com/strapi-community/plugin-redis/issues"
44 | },
45 | "repository": {
46 | "type": "git",
47 | "url": "github:strapi-community/plugin-redis"
48 | },
49 | "homepage": "https://strapi-community.github.io/plugin-redis/",
50 | "license": "MIT"
51 | }
52 |
--------------------------------------------------------------------------------
/server/config/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | default: {
5 | settings: {
6 | debug: false,
7 | debugIORedis: false,
8 | redlockConfig: {
9 | driftFactor: 0.01,
10 | retryCount: 10,
11 | retryDelay: 200,
12 | retryJitter: 200,
13 | },
14 | enableRedlock: false,
15 | lockDelay: null,
16 | lockTTL: 5000,
17 | },
18 | connections: {
19 | default: {
20 | connection: {
21 | host: '127.0.0.1',
22 | port: 6379,
23 | db: 0,
24 | },
25 | },
26 | },
27 | },
28 | validator() {},
29 | };
30 |
--------------------------------------------------------------------------------
/server/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const register = require('./register');
4 | const config = require('./config');
5 | const services = require('./services');
6 |
7 | module.exports = {
8 | register,
9 | config,
10 | services,
11 | };
12 |
--------------------------------------------------------------------------------
/server/register.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const debug = require('debug');
4 | const { default: Redlock } = require('redlock');
5 |
6 | module.exports = async ({ strapi }) => {
7 | // Load plugin Config
8 | const coreConfig = strapi.config.get('plugin::redis');
9 |
10 | // Configure plugin debug
11 | if (coreConfig.settings.debug === true) {
12 | debug.enable('strapi:strapi-plugin-redis');
13 | }
14 |
15 | // Allow plugin + ioredis debug
16 | if (coreConfig.settings.debug === true && coreConfig.settings.debugIORedis === true) {
17 | debug.enable('strapi:strapi-plugin-redis,ioredis:*');
18 | }
19 |
20 | // Construct Redis API
21 | strapi.redis = {
22 | config: coreConfig,
23 | connections: {},
24 | };
25 |
26 | // Build Redis database connections
27 | await strapi.plugin('redis').service('connection').buildAll(coreConfig);
28 |
29 | // Configure Redlock
30 | if (coreConfig.settings.enableRedlock === true) {
31 | const originalAdd = strapi.cron.add;
32 | const redlockConfig = coreConfig.settings.redlockConfig;
33 |
34 | strapi.cron.add = (tasks) => {
35 | const generateRedlockFunction = (originalFunction, name) => {
36 | return async (...args) => {
37 | const connections = Object.keys(strapi.redis.connections).map((key) => {
38 | return strapi.redis.connections[key].client;
39 | });
40 | const redlock = new Redlock(connections, redlockConfig);
41 |
42 | let lock;
43 | try {
44 | lock = await redlock.acquire([name], coreConfig.settings.lockTTL);
45 | debug(`Job ${name} acquired lock`);
46 | await originalFunction(...args);
47 | } catch (e) {
48 | debug(`Job ${name} failed to acquire lock`);
49 | } finally {
50 | // wait some time so other processes will lose the lock
51 | let lockDelay = coreConfig.settings.lockDelay
52 | ? coreConfig.settings.lockDelay
53 | : coreConfig.settings.redlockConfig.retryCount *
54 | (coreConfig.settings.redlockConfig.retryDelay +
55 | coreConfig.settings.redlockConfig.retryJitter);
56 | debug(`Job ${name} waiting ${lockDelay}ms before releasing lock`);
57 | await new Promise((resolve) => setTimeout(resolve, lockDelay));
58 | if (lock) {
59 | debug(`Job ${name} releasing lock`);
60 | try {
61 | await lock.release();
62 | } catch (e) {
63 | debug(`Job ${name} failed to release lock ${e}`);
64 | }
65 | }
66 | }
67 | };
68 | };
69 | Object.keys(tasks).forEach((key) => {
70 | const taskValue = tasks[key];
71 | if (typeof taskValue === 'function') {
72 | strapi.log.info('redlock requires tasks to use the object format');
73 | return;
74 | } else if (
75 | typeof taskValue === 'object' &&
76 | taskValue &&
77 | typeof taskValue.task === 'function' &&
78 | taskValue.bypassRedlock !== true
79 | ) {
80 | // fallback to key if no name is provided
81 | const taskName = taskValue.name || key;
82 | taskValue.task = generateRedlockFunction(taskValue.task, 'redlock:' + taskName);
83 | }
84 | });
85 | originalAdd(tasks);
86 | };
87 | }
88 | };
89 |
--------------------------------------------------------------------------------
/server/services/connection.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Redis = require('ioredis');
4 | const chalk = require('chalk');
5 | const debug = require('debug')('strapi:strapi-plugin-redis');
6 |
7 | module.exports = ({ strapi }) => ({
8 | buildAll(config) {
9 | const coreConfig = config;
10 |
11 | // Loop through all connections and start building and mounting them
12 | Object.keys(coreConfig.connections).forEach((name) => {
13 | debug(`${chalk.yellow('Building')} ${name} connection`);
14 | const nameConfig = coreConfig.connections[name];
15 |
16 | // Check for cluster
17 | if (nameConfig.connection.nodes) {
18 | try {
19 | strapi.redis.connections[name] = {
20 | client: new Redis.Cluster(nameConfig.connection.nodes, nameConfig.connection.options),
21 | };
22 | debug(`${chalk.green('Built')} ${name} connection - ${chalk.blue('cluster')}`);
23 | } catch (e) {
24 | debug(`${chalk.red('Failed to build')} ${name} connection - ${chalk.blue('cluster')}`);
25 | }
26 |
27 | // Check for sentinel config
28 | } else if (nameConfig.connection.sentinels) {
29 | delete nameConfig.connection.host;
30 | delete nameConfig.connection.port;
31 | try {
32 | strapi.redis.connections[name] = {
33 | client: new Redis(nameConfig.connection),
34 | };
35 | debug(`${chalk.green('Built')} ${name} connection - ${chalk.yellow('sentinel')}`);
36 | } catch (e) {
37 | debug(`${chalk.red('Failed to build')} ${name} connection - ${chalk.yellow('sentinel')}`);
38 | }
39 |
40 | // Check for regular single connection
41 | } else {
42 | try {
43 | strapi.redis.connections[name] = {
44 | client: new Redis(nameConfig.connection),
45 | };
46 | debug(`${chalk.green('Built')} ${name} connection - ${chalk.magenta('stand-alone')}`);
47 | } catch (e) {
48 | debug(
49 | `${chalk.red('Failed to build')} ${name} connection - ${chalk.magenta('stand-alone')}`
50 | );
51 | }
52 | }
53 | });
54 | },
55 | });
56 |
--------------------------------------------------------------------------------
/server/services/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const connection = require('./connection');
4 |
5 | module.exports = {
6 | connection,
7 | };
8 |
--------------------------------------------------------------------------------
/strapi-server.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = require('./server');
4 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@ioredis/commands@^1.1.1":
6 | version "1.2.0"
7 | resolved "https://registry.yarnpkg.com/@ioredis/commands/-/commands-1.2.0.tgz#6d61b3097470af1fdbbe622795b8921d42018e11"
8 | integrity sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==
9 |
10 | ansi-styles@^4.1.0:
11 | version "4.3.0"
12 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
13 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
14 | dependencies:
15 | color-convert "^2.0.1"
16 |
17 | chalk@4.1.2:
18 | version "4.1.2"
19 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
20 | integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
21 | dependencies:
22 | ansi-styles "^4.1.0"
23 | supports-color "^7.1.0"
24 |
25 | cluster-key-slot@^1.1.0:
26 | version "1.1.2"
27 | resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac"
28 | integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==
29 |
30 | color-convert@^2.0.1:
31 | version "2.0.1"
32 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
33 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
34 | dependencies:
35 | color-name "~1.1.4"
36 |
37 | color-name@~1.1.4:
38 | version "1.1.4"
39 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
40 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
41 |
42 | debug@4.3.5:
43 | version "4.3.5"
44 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e"
45 | integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==
46 | dependencies:
47 | ms "2.1.2"
48 |
49 | debug@^4.3.4:
50 | version "4.3.4"
51 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
52 | integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
53 | dependencies:
54 | ms "2.1.2"
55 |
56 | denque@^2.1.0:
57 | version "2.1.0"
58 | resolved "https://registry.yarnpkg.com/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1"
59 | integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==
60 |
61 | has-flag@^4.0.0:
62 | version "4.0.0"
63 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
64 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
65 |
66 | ioredis@5.4.1:
67 | version "5.4.1"
68 | resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-5.4.1.tgz#1c56b70b759f01465913887375ed809134296f40"
69 | integrity sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==
70 | dependencies:
71 | "@ioredis/commands" "^1.1.1"
72 | cluster-key-slot "^1.1.0"
73 | debug "^4.3.4"
74 | denque "^2.1.0"
75 | lodash.defaults "^4.2.0"
76 | lodash.isarguments "^3.1.0"
77 | redis-errors "^1.2.0"
78 | redis-parser "^3.0.0"
79 | standard-as-callback "^2.1.0"
80 |
81 | lodash.defaults@^4.2.0:
82 | version "4.2.0"
83 | resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
84 | integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==
85 |
86 | lodash.isarguments@^3.1.0:
87 | version "3.1.0"
88 | resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a"
89 | integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==
90 |
91 | ms@2.1.2:
92 | version "2.1.2"
93 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
94 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
95 |
96 | node-abort-controller@^3.0.1:
97 | version "3.1.1"
98 | resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-3.1.1.tgz#a94377e964a9a37ac3976d848cb5c765833b8548"
99 | integrity sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==
100 |
101 | redis-errors@^1.0.0, redis-errors@^1.2.0:
102 | version "1.2.0"
103 | resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad"
104 | integrity sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==
105 |
106 | redis-parser@^3.0.0:
107 | version "3.0.0"
108 | resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4"
109 | integrity sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==
110 | dependencies:
111 | redis-errors "^1.0.0"
112 |
113 | redlock@5.0.0-beta.2:
114 | version "5.0.0-beta.2"
115 | resolved "https://registry.yarnpkg.com/redlock/-/redlock-5.0.0-beta.2.tgz#a629c07e07d001c0fdd9f2efa614144c4416fe44"
116 | integrity sha512-2RDWXg5jgRptDrB1w9O/JgSZC0j7y4SlaXnor93H/UJm/QyDiFgBKNtrh0TI6oCXqYSaSoXxFh6Sd3VtYfhRXw==
117 | dependencies:
118 | node-abort-controller "^3.0.1"
119 |
120 | standard-as-callback@^2.1.0:
121 | version "2.1.0"
122 | resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45"
123 | integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==
124 |
125 | supports-color@^7.1.0:
126 | version "7.2.0"
127 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
128 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
129 | dependencies:
130 | has-flag "^4.0.0"
131 |
--------------------------------------------------------------------------------