├── src ├── index.ts ├── types.ts ├── typings │ └── index.d.ts ├── config │ └── config.default.ts └── app.ts ├── test ├── fixtures │ ├── ts │ │ ├── .gitignore │ │ ├── package.json │ │ ├── config │ │ │ ├── config.ts │ │ │ └── plugin.ts │ │ ├── tsconfig.json │ │ └── app │ │ │ ├── router.ts │ │ │ └── controller │ │ │ └── home.ts │ ├── multi │ │ ├── package.json │ │ ├── config │ │ │ ├── plugin.js │ │ │ └── config.default.js │ │ └── app │ │ │ ├── router.js │ │ │ └── controller │ │ │ └── home.js │ ├── single │ │ ├── package.json │ │ ├── config │ │ │ ├── plugin.js │ │ │ └── config.default.js │ │ └── app │ │ │ ├── router.js │ │ │ └── controller │ │ │ └── home.js │ └── redis-session │ │ └── config │ │ └── config.default.js └── app.test.ts ├── .eslintignore ├── __snapshots__ └── app.test.ts.js ├── .eslintrc ├── .gitignore ├── tsconfig.json ├── .github └── workflows │ ├── release.yml │ ├── nodejs.yml │ └── pkg.pr.new.yml ├── LICENSE ├── CHANGELOG.md ├── package.json └── README.md /src/index.ts: -------------------------------------------------------------------------------- 1 | import './types.js'; 2 | -------------------------------------------------------------------------------- /test/fixtures/ts/.gitignore: -------------------------------------------------------------------------------- 1 | *.js 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | test/fixtures 2 | coverage 3 | __snapshots__ 4 | -------------------------------------------------------------------------------- /test/fixtures/multi/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "multi" 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/single/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "single" 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/ts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ts", 3 | "version": "1.0.0" 4 | } -------------------------------------------------------------------------------- /test/fixtures/multi/config/plugin.js: -------------------------------------------------------------------------------- 1 | exports.redis = { 2 | enable: true, 3 | package: '@eggjs/redis', 4 | }; 5 | -------------------------------------------------------------------------------- /test/fixtures/single/config/plugin.js: -------------------------------------------------------------------------------- 1 | exports.redis = { 2 | enable: true, 3 | package: '@eggjs/redis', 4 | }; 5 | -------------------------------------------------------------------------------- /__snapshots__/app.test.ts.js: -------------------------------------------------------------------------------- 1 | exports['test/app.test.ts single should keep config stable 1'] = { 2 | "name": "" 3 | } 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "eslint-config-egg/typescript", 4 | "eslint-config-egg/lib/rules/enforce-node-prefix" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/ts/config/config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | keys: 'keys', 3 | redis: { 4 | client: { 5 | host: '127.0.0.1', 6 | port: 6379, 7 | db: '0', 8 | password: '', 9 | }, 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/fixtures/ts/config/plugin.ts: -------------------------------------------------------------------------------- 1 | import { EggPlugin } from 'egg'; 2 | 3 | const plugin: EggPlugin = { 4 | redis: { 5 | enable: true, 6 | package: '@eggjs/redis', 7 | } 8 | }; 9 | 10 | export default plugin; 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | logs/ 2 | npm-debug.log 3 | node_modules/ 4 | coverage/ 5 | test/fixtures/**/run 6 | .DS_Store 7 | .tshy* 8 | .eslintcache 9 | dist 10 | package-lock.json 11 | .package-lock.json 12 | test/fixtures/**/*.d.ts 13 | run/ 14 | -------------------------------------------------------------------------------- /test/fixtures/single/config/config.default.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.keys = 'keys'; 4 | 5 | exports.redis = { 6 | client: { 7 | host: '127.0.0.1', 8 | port: 6379, 9 | db: '0', 10 | password: '', 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import type { SessionRedisConfig } from './config/config.default.js'; 2 | 3 | declare module '@eggjs/core' { 4 | // add EggAppConfig overrides types 5 | interface EggAppConfig { 6 | sessionRedis: SessionRedisConfig; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/fixtures/redis-session/config/config.default.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.keys = 'keys'; 4 | 5 | exports.redis = { 6 | client: { 7 | host: '127.0.0.1', 8 | port: 6379, 9 | db: 0, 10 | password: '', 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@eggjs/tsconfig", 3 | "compilerOptions": { 4 | "strict": true, 5 | "noImplicitAny": true, 6 | "target": "ES2022", 7 | "module": "NodeNext", 8 | "moduleResolution": "NodeNext" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/fixtures/ts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "baseUrl": ".", 5 | "module": "commonjs", 6 | "lib": ["es7"], 7 | "strict": true 8 | }, 9 | "include": [ 10 | "../../../**/*" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /src/typings/index.d.ts: -------------------------------------------------------------------------------- 1 | // make sure to import egg typings and let typescript know about it 2 | // @see https://github.com/whxaxes/blog/issues/11 3 | // and https://www.typescriptlang.org/docs/handbook/declaration-merging.html 4 | import 'egg'; 5 | import '@eggjs/redis'; 6 | -------------------------------------------------------------------------------- /test/fixtures/multi/app/router.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(app) { 4 | app.get('/get', 'home.get'); 5 | app.get('/set', 'home.set'); 6 | app.get('/setKey', 'home.setKey'); 7 | app.get('/remove', 'home.remove'); 8 | app.get('/maxAge', 'home.maxAge'); 9 | }; 10 | -------------------------------------------------------------------------------- /test/fixtures/single/app/router.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(app) { 4 | app.get('/get', 'home.get'); 5 | app.get('/set', 'home.set'); 6 | app.get('/setKey', 'home.setKey'); 7 | app.get('/remove', 'home.remove'); 8 | app.get('/maxAge', 'home.maxAge'); 9 | }; 10 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | jobs: 8 | release: 9 | name: Node.js 10 | uses: eggjs/github-actions/.github/workflows/node-release.yml@master 11 | secrets: 12 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 13 | GIT_TOKEN: ${{ secrets.GIT_TOKEN }} 14 | -------------------------------------------------------------------------------- /test/fixtures/ts/app/router.ts: -------------------------------------------------------------------------------- 1 | import { Application } from 'egg'; 2 | 3 | export default (app: Application) => { 4 | const controller = app.controller; 5 | app.get('/get', controller.home.get); 6 | app.get('/set', controller.home.set); 7 | app.get('/setKey', controller.home.setKey); 8 | app.get('/remove', controller.home.remove); 9 | app.get('/maxAge', controller.home.maxAge); 10 | } 11 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | Job: 11 | name: Node.js 12 | uses: node-modules/github-actions/.github/workflows/node-test-mysql.yml@master 13 | with: 14 | version: '18.19.0, 18, 20, 22' 15 | secrets: 16 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 17 | -------------------------------------------------------------------------------- /test/fixtures/multi/config/config.default.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.keys = 'keys'; 4 | 5 | exports.redis = { 6 | clients: { 7 | session: { 8 | host: '127.0.0.1', 9 | port: 6379, 10 | db: 0, 11 | password: '', 12 | }, 13 | cache: { 14 | host: '127.0.0.1', 15 | port: 6379, 16 | db: 1, 17 | password: '', 18 | }, 19 | }, 20 | }; 21 | 22 | exports.sessionRedis = { 23 | name: 'session', 24 | }; 25 | -------------------------------------------------------------------------------- /src/config/config.default.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * session-redis default config 3 | * @member Config#sessionRedis 4 | * @property {String} name - redis instance name 5 | */ 6 | export interface SessionRedisConfig { 7 | /** 8 | * redis instance name 9 | * 10 | * Default to `''`, use `app.redis` for session store 11 | * 12 | * If name present, use `app.redis.getSingletonInstance(name)` for session store 13 | */ 14 | name: string; 15 | } 16 | 17 | export default { 18 | sessionRedis: { 19 | name: '', 20 | } as SessionRedisConfig, 21 | }; 22 | -------------------------------------------------------------------------------- /.github/workflows/pkg.pr.new.yml: -------------------------------------------------------------------------------- 1 | name: Publish Any Commit 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | build: 6 | runs-on: ubuntu-latest 7 | 8 | steps: 9 | - name: Checkout code 10 | uses: actions/checkout@v4 11 | 12 | - run: corepack enable 13 | - uses: actions/setup-node@v4 14 | with: 15 | node-version: 20 16 | 17 | - name: Install dependencies 18 | run: npm install 19 | 20 | - name: Build 21 | run: npm run prepublishOnly --if-present 22 | 23 | - run: npx pkg-pr-new publish 24 | -------------------------------------------------------------------------------- /test/fixtures/multi/app/controller/home.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.get = async function (ctx) { 4 | ctx.body = ctx.session; 5 | }; 6 | 7 | exports.set = async function (ctx) { 8 | ctx.session = ctx.query; 9 | ctx.body = ctx.session; 10 | }; 11 | 12 | exports.setKey = async function (ctx) { 13 | ctx.session.key = ctx.query.key; 14 | ctx.body = ctx.session; 15 | }; 16 | 17 | exports.remove = async function (ctx) { 18 | ctx.session = null; 19 | ctx.body = ctx.session; 20 | }; 21 | 22 | exports.maxAge = async function (ctx) { 23 | ctx.session.maxAge = Number(this.query.maxAge); 24 | ctx.body = ctx.session; 25 | }; 26 | -------------------------------------------------------------------------------- /test/fixtures/single/app/controller/home.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.get = async function (ctx) { 4 | ctx.body = ctx.session; 5 | }; 6 | 7 | exports.set = async function (ctx) { 8 | ctx.session = ctx.query; 9 | ctx.body = ctx.session; 10 | }; 11 | 12 | exports.setKey = async function (ctx) { 13 | ctx.session.key = ctx.query.key; 14 | ctx.body = ctx.session; 15 | }; 16 | 17 | exports.remove = async function (ctx) { 18 | ctx.session = null; 19 | ctx.body = ctx.session; 20 | }; 21 | 22 | exports.maxAge = async function (ctx) { 23 | ctx.session.maxAge = Number(this.query.maxAge); 24 | ctx.body = ctx.session; 25 | }; 26 | -------------------------------------------------------------------------------- /test/fixtures/ts/app/controller/home.ts: -------------------------------------------------------------------------------- 1 | import { Controller } from 'egg'; 2 | 3 | // add home controller 4 | declare module 'egg' { 5 | interface IController { 6 | home: HomeController; 7 | } 8 | 9 | interface Context { 10 | [key: string | symbol]: any; 11 | } 12 | } 13 | 14 | export default class HomeController extends Controller { 15 | async get () { 16 | this.ctx.body = this.ctx.session; 17 | }; 18 | 19 | async set () { 20 | this.ctx.session = this.ctx.query; 21 | this.ctx.body = this.ctx.session; 22 | }; 23 | 24 | async setKey () { 25 | this.ctx.session.key = this.ctx.query.key; 26 | this.ctx.body = this.ctx.session; 27 | }; 28 | 29 | async remove () { 30 | this.ctx.session = null; 31 | this.ctx.body = this.ctx.session; 32 | }; 33 | 34 | async maxAge () { 35 | this.ctx.session.maxAge = Number(this.ctx.query.maxAge); 36 | this.ctx.body = this.ctx.session; 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Alibaba Group Holding Limited and other contributors. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/app.ts: -------------------------------------------------------------------------------- 1 | import type { EggCore, ILifecycleBoot } from '@eggjs/core'; 2 | 3 | const ONE_DAY = 1000 * 60 * 60 * 24; 4 | 5 | export default class AppBoot implements ILifecycleBoot { 6 | constructor(private readonly app: EggCore) {} 7 | 8 | async didLoad() { 9 | const { app } = this; 10 | const name = app.config.sessionRedis.name; 11 | const redis = name ? app.redis.getSingletonInstance(name) : app.redis; 12 | if (!redis) { 13 | throw new TypeError(`redis instance [${name}] not exists`); 14 | } 15 | 16 | /** 17 | * @member Application#sessionStore 18 | * @property {Function} get - get redis session store 19 | * @property {Function} set - set the redis session store 20 | * @property {Function} destroy - destroy of redis session store 21 | * @example 22 | * ```js 23 | * this.app.sessionStore.set('SESSION_KEY', { a: 1 }, 6000); 24 | * this.app.sessionStore.get('SESSION_KEY'); 25 | * this.app.sessionStore.destroy('SESSION_KEY'); 26 | * ``` 27 | */ 28 | app.sessionStore = { 29 | async get(key) { 30 | const res = await redis.get(key); 31 | if (!res) return null; 32 | return JSON.parse(res); 33 | }, 34 | 35 | async set(key, value, maxAge?) { 36 | maxAge = typeof maxAge === 'number' ? maxAge : ONE_DAY; 37 | value = JSON.stringify(value); 38 | await redis.set(key, value, 'PX', maxAge); 39 | }, 40 | 41 | async destroy(key) { 42 | await redis.del(key); 43 | }, 44 | }; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [3.0.0](https://github.com/eggjs/session-redis/compare/v2.1.0...v3.0.0) (2025-01-21) 4 | 5 | 6 | ### ⚠ BREAKING CHANGES 7 | 8 | * drop Node.js < 18.19.0 support 9 | 10 | part of https://github.com/eggjs/egg/issues/3644 11 | 12 | https://github.com/eggjs/egg/issues/5257 13 | 14 | ### Features 15 | 16 | * support cjs and esm both by tshy ([#8](https://github.com/eggjs/session-redis/issues/8)) ([eded033](https://github.com/eggjs/session-redis/commit/eded033b95e6330a55add352ce869b8a1a314a46)) 17 | 18 | 2.1.0 / 2018-09-10 19 | ================== 20 | 21 | **features** 22 | * [[`51b1de3`](http://github.com/eggjs/egg-session-redis/commit/51b1de3eba07ac6fd18f5e4a7d56647365550b3b)] - feat: add typescript support (#6) (songyazhao <<59256790@qq.com>>) 23 | 24 | 2.0.1 / 2018-08-23 25 | ================== 26 | 27 | **fixes** 28 | * [[`9e87f65`](http://github.com/eggjs/egg-session-redis/commit/9e87f6571f8e15d716fed2c443002b77179191d4)] - fix: fix maxage=session error (#7) (章 <<403724532@qq.com>>) 29 | 30 | 2.0.0 / 2018-07-01 31 | ================== 32 | 33 | **others** 34 | * [[`a4bc19f`](http://github.com/eggjs/egg-session-redis/commit/a4bc19f70f6b735e4ede807ba594d74bdd6438d9)] - refactor: use async function (#4) (Baffin Lee <>) 35 | * [[`d209504`](http://github.com/eggjs/egg-session-redis/commit/d2095040f1342f92f51d51d98f9e9069535393f8)] - docs: update usage of single instance. (#3) (xcold <>) 36 | * [[`be4178a`](http://github.com/eggjs/egg-session-redis/commit/be4178ac3a8c1e8e3ba38f6ba5cb5080870132e4)] - docs: add usage for only one instance (dead-horse <>) 37 | 38 | 1.0.0 / 2017-03-02 39 | ================== 40 | 41 | * feat: first implement (#1) 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@eggjs/session-redis", 3 | "version": "3.0.0", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "description": "redis store plugin for egg session", 8 | "eggPlugin": { 9 | "name": "sessionRedis", 10 | "dependencies": [ 11 | "redis", 12 | "session" 13 | ], 14 | "exports": { 15 | "import": "./dist/esm", 16 | "require": "./dist/commonjs", 17 | "typescript": "./src" 18 | } 19 | }, 20 | "keywords": [ 21 | "egg", 22 | "eggPlugin", 23 | "egg-plugin", 24 | "session", 25 | "redis" 26 | ], 27 | "repository": { 28 | "type": "git", 29 | "url": "git+https://github.com/eggjs/session-redis.git" 30 | }, 31 | "bugs": { 32 | "url": "https://github.com/eggjs/egg/issues" 33 | }, 34 | "homepage": "https://github.com/eggjs/session-redis#readme", 35 | "author": "dead-horse", 36 | "license": "MIT", 37 | "engines": { 38 | "node": ">= 18.19.0" 39 | }, 40 | "dependencies": { 41 | "@eggjs/core": "^6.3.1" 42 | }, 43 | "devDependencies": { 44 | "@arethetypeswrong/cli": "^0.17.3", 45 | "@eggjs/bin": "7", 46 | "@eggjs/mock": "^6.0.5", 47 | "@eggjs/redis": "^3.0.0", 48 | "@eggjs/supertest": "^8.2.0", 49 | "@eggjs/tsconfig": "1", 50 | "@types/mocha": "10", 51 | "@types/node": "22", 52 | "egg": "^4.0.3", 53 | "eslint": "8", 54 | "eslint-config-egg": "14", 55 | "rimraf": "6", 56 | "snap-shot-it": "^7.9.10", 57 | "tshy": "3", 58 | "tshy-after": "1", 59 | "typescript": "5" 60 | }, 61 | "scripts": { 62 | "lint": "eslint --cache src test --ext .ts", 63 | "pretest": "npm run clean && npm run lint -- --fix", 64 | "test": "egg-bin test", 65 | "preci": "npm run clean && npm run lint", 66 | "ci": "egg-bin cov", 67 | "postci": "npm run prepublishOnly && npm run clean", 68 | "clean": "rimraf dist", 69 | "prepublishOnly": "tshy && tshy-after && attw --pack" 70 | }, 71 | "type": "module", 72 | "tshy": { 73 | "exports": { 74 | ".": "./src/index.ts", 75 | "./package.json": "./package.json" 76 | } 77 | }, 78 | "exports": { 79 | ".": { 80 | "import": { 81 | "types": "./dist/esm/index.d.ts", 82 | "default": "./dist/esm/index.js" 83 | }, 84 | "require": { 85 | "types": "./dist/commonjs/index.d.ts", 86 | "default": "./dist/commonjs/index.js" 87 | } 88 | }, 89 | "./package.json": "./package.json" 90 | }, 91 | "files": [ 92 | "dist", 93 | "src" 94 | ], 95 | "types": "./dist/commonjs/index.d.ts", 96 | "main": "./dist/commonjs/index.js", 97 | "module": "./dist/esm/index.js" 98 | } 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # @eggjs/session-redis 2 | 3 | [![NPM version][npm-image]][npm-url] 4 | [![Node.js CI](https://github.com/eggjs/session-redis/actions/workflows/nodejs.yml/badge.svg)](https://github.com/eggjs/session-redis/actions/workflows/nodejs.yml) 5 | [![Test coverage][codecov-image]][codecov-url] 6 | [![Known Vulnerabilities][snyk-image]][snyk-url] 7 | [![npm download][download-image]][download-url] 8 | [![Node.js Version](https://img.shields.io/node/v/@eggjs/session-redis.svg?style=flat)](https://nodejs.org/en/download/) 9 | [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://makeapullrequest.com) 10 | ![CodeRabbit Pull Request Reviews](https://img.shields.io/coderabbit/prs/github/eggjs/session-redis) 11 | 12 | [npm-image]: https://img.shields.io/npm/v/@eggjs/session-redis.svg?style=flat-square 13 | [npm-url]: https://npmjs.org/package/@eggjs/session-redis 14 | [codecov-image]: https://img.shields.io/codecov/c/github/eggjs/session-redis.svg?style=flat-square 15 | [codecov-url]: https://codecov.io/github/eggjs/session-redis?branch=master 16 | [snyk-image]: https://snyk.io/test/npm/@eggjs/session-redis/badge.svg?style=flat-square 17 | [snyk-url]: https://snyk.io/test/npm/@eggjs/session-redis 18 | [download-image]: https://img.shields.io/npm/dm/@eggjs/session-redis.svg?style=flat-square 19 | [download-url]: https://npmjs.org/package/@eggjs/session-redis 20 | 21 | A session extension for store session in redis. 22 | 23 | ## Install 24 | 25 | ```bash 26 | npm i @eggjs/session-redis @eggjs/redis 27 | ``` 28 | 29 | ## Usage 30 | 31 | This module dependent on [@eggjs/redis](https://github.com/eggjs/redis) plugin, so we must enable both. 32 | 33 | ```js 34 | // {app_root}/config/plugin.js 35 | exports.sessionRedis = { 36 | enable: true, 37 | package: '@eggjs/session-redis', 38 | }; 39 | 40 | exports.redis = { 41 | enable: true, 42 | package: '@eggjs/redis', 43 | }; 44 | ``` 45 | 46 | ## Configuration 47 | 48 | If we only have one redis instance: 49 | 50 | ```js 51 | // {app_root}/config/config.default.js 52 | exports.redis = { 53 | client: { 54 | host: 'your redis host', 55 | port: 'your redis port', 56 | password: '', 57 | db: '0', 58 | }, 59 | agent:true 60 | }; 61 | // no need to set any sessionRedis config 62 | ``` 63 | 64 | If we have more than one redis instance, we need to configure which instance to be used as session store. 65 | 66 | ```js 67 | // {app_root}/config/config.default.js 68 | 69 | exports.redis = { 70 | clients: { 71 | session: { /* config */ }, 72 | cache: { /* config */ }, 73 | }, 74 | }; 75 | 76 | exports.sessionRedis = { 77 | name: 'session', // specific instance `session` as the session store 78 | }; 79 | ``` 80 | 81 | ## Questions & Suggestions 82 | 83 | Please open an issue [here](https://github.com/eggjs/egg/issues). 84 | 85 | ## License 86 | 87 | [MIT](LICENSE) 88 | 89 | ## Contributors 90 | 91 | [![Contributors](https://contrib.rocks/image?repo=eggjs/session-redis)](https://github.com/eggjs/session-redis/graphs/contributors) 92 | 93 | Made with [contributors-img](https://contrib.rocks). 94 | -------------------------------------------------------------------------------- /test/app.test.ts: -------------------------------------------------------------------------------- 1 | import { scheduler } from 'node:timers/promises'; 2 | import { TestAgent } from '@eggjs/supertest'; 3 | import assert from 'node:assert'; 4 | import { mm, MockApplication } from '@eggjs/mock'; 5 | import snapshot from 'snap-shot-it'; 6 | 7 | describe('test/app.test.ts', () => { 8 | [ 9 | 'single', 10 | 'multi', 11 | 'ts', 12 | ].forEach(name => { 13 | describe(name, () => { 14 | let app: MockApplication; 15 | let agent: TestAgent; 16 | before(() => { 17 | app = mm.app({ 18 | baseDir: name, 19 | }); 20 | return app.ready(); 21 | }); 22 | beforeEach(() => { 23 | agent = new TestAgent(app.callback()); 24 | }); 25 | afterEach(mm.restore); 26 | after(() => app.close()); 27 | 28 | if (name === 'single') { 29 | it('should keep config stable', () => { 30 | snapshot(app.config.sessionRedis); 31 | }); 32 | } 33 | 34 | it('should get empty session and do not set cookie when session not populated', async () => { 35 | await agent 36 | .get('/get') 37 | .expect(200) 38 | .expect({}) 39 | .expect(res => { 40 | assert(!res.get('Set-Cookie')!.join('').match(/EGG_SESS/)); 41 | }); 42 | }); 43 | 44 | it('should ctx.session= change the session', async () => { 45 | await agent 46 | .get('/set?foo=bar') 47 | .expect(200) 48 | .expect({ foo: 'bar' }) 49 | .expect('set-cookie', /EGG_SESS=.*?;/); 50 | }); 51 | 52 | it('should ctx.session.key= change the session', async () => { 53 | await agent 54 | .get('/set?key=foo&foo=bar') 55 | .expect(200) 56 | .expect({ key: 'foo', foo: 'bar' }) 57 | .expect('set-cookie', /EGG_SESS=.*?;/); 58 | 59 | await agent 60 | .get('/setKey?key=bar') 61 | .expect(200) 62 | .expect({ key: 'bar', foo: 'bar' }) 63 | .expect('set-cookie', /EGG_SESS=.*?;/); 64 | }); 65 | 66 | it('should ctx.session=null remove the session', async () => { 67 | await agent 68 | .get('/set?key=foo&foo=bar') 69 | .expect(200) 70 | .expect({ key: 'foo', foo: 'bar' }) 71 | .expect('set-cookie', /EGG_SESS=.*?;/); 72 | 73 | await agent 74 | .get('/remove') 75 | .expect(204) 76 | .expect('set-cookie', /EGG_SESS=;/); 77 | 78 | await agent 79 | .get('/get') 80 | .expect(200) 81 | .expect({}); 82 | }); 83 | 84 | it('should ctx.session.maxAge= change maxAge', async () => { 85 | await agent 86 | .get('/set?key=foo&foo=bar') 87 | .expect(200) 88 | .expect({ key: 'foo', foo: 'bar' }) 89 | .expect('set-cookie', /EGG_SESS=.*?;/); 90 | 91 | let cookie = ''; 92 | 93 | await agent 94 | .get('/maxAge?maxAge=100') 95 | .expect(200) 96 | .expect({ key: 'foo', foo: 'bar' }) 97 | .expect(res => { 98 | cookie = res.get('Set-Cookie')!.join(';'); 99 | assert(cookie.match(/EGG_SESS=.*?;/)); 100 | assert(cookie.match(/expires=/)); 101 | }); 102 | 103 | await scheduler.wait(200); 104 | 105 | await agent 106 | .get('/get') 107 | .expect(200) 108 | .expect({}); 109 | 110 | await app.httpRequest() 111 | .get('/get') 112 | .set('cookie', cookie) 113 | .expect(200) 114 | .expect({}); 115 | }); 116 | }); 117 | }); 118 | }); 119 | --------------------------------------------------------------------------------