123
This commit is contained in:
26
node_modules/connect-redis/.eslintrc
generated
vendored
Normal file
26
node_modules/connect-redis/.eslintrc
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": ["@typescript-eslint"],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier"
|
||||
],
|
||||
"env": {
|
||||
"node": true,
|
||||
"es6": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"sourceType": "module",
|
||||
"project": "./tsconfig.json",
|
||||
"ecmaVersion": 2020
|
||||
},
|
||||
"rules": {
|
||||
"prefer-const": 0,
|
||||
"@typescript-eslint/no-explicit-any": 0,
|
||||
"@typescript-eslint/no-empty-function": 0,
|
||||
"@typescript-eslint/explicit-function-return-type": 0,
|
||||
"@typescript-eslint/no-unused-vars": [2, {"argsIgnorePattern": "^_"}]
|
||||
}
|
||||
}
|
||||
30
node_modules/connect-redis/.github/release-drafter.yml
generated
vendored
Normal file
30
node_modules/connect-redis/.github/release-drafter.yml
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
name-template: "v$RESOLVED_VERSION"
|
||||
tag-template: "v$RESOLVED_VERSION"
|
||||
template: |
|
||||
$CHANGES
|
||||
category-template: "#### $TITLE"
|
||||
change-template: "* #$NUMBER - $TITLE (@$AUTHOR)"
|
||||
categories:
|
||||
- title: "Breaking changes"
|
||||
label: "breaking"
|
||||
- title: "Enhancements"
|
||||
label: "enhancement"
|
||||
- title: "Bug fixes"
|
||||
label: "bug"
|
||||
- title: "Maintenance"
|
||||
label: "chore"
|
||||
|
||||
version-resolver:
|
||||
major:
|
||||
labels:
|
||||
- "breaking"
|
||||
minor:
|
||||
labels:
|
||||
- "enhancement"
|
||||
patch:
|
||||
labels:
|
||||
- "bug"
|
||||
- "chore"
|
||||
|
||||
exclude-labels:
|
||||
- "skip-changelog"
|
||||
23
node_modules/connect-redis/.github/workflows/build.yml
generated
vendored
Normal file
23
node_modules/connect-redis/.github/workflows/build.yml
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
name: build
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node: [16, 18, 20]
|
||||
name: Node v${{ matrix.node }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
- run: sudo apt-get install -y redis-server
|
||||
- run: npm install
|
||||
- run: npm run fmt-check
|
||||
- run: npm run lint
|
||||
- run: npm test
|
||||
13
node_modules/connect-redis/.github/workflows/release.yml
generated
vendored
Normal file
13
node_modules/connect-redis/.github/workflows/release.yml
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
name: release-draft
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
jobs:
|
||||
update_release_draft:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: release-drafter/release-drafter@master
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
17
node_modules/connect-redis/.github/workflows/stale.yml
generated
vendored
Normal file
17
node_modules/connect-redis/.github/workflows/stale.yml
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
name: stale-issues-prs
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v3
|
||||
with:
|
||||
stale-issue-message: "This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days."
|
||||
stale-pr-message: "This PR is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days."
|
||||
close-issue-message: "This issue was closed because it has been stalled for 5 days with no activity."
|
||||
days-before-stale: 30
|
||||
days-before-close: 5
|
||||
stale-issue-label: stale
|
||||
5
node_modules/connect-redis/.prettierrc
generated
vendored
Normal file
5
node_modules/connect-redis/.prettierrc
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"semi": false,
|
||||
"bracketSpacing": false,
|
||||
"plugins": ["prettier-plugin-organize-imports"]
|
||||
}
|
||||
48
node_modules/connect-redis/dist/cjs/index.d.ts
generated
vendored
Normal file
48
node_modules/connect-redis/dist/cjs/index.d.ts
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
import { SessionData, Store } from "express-session";
|
||||
interface NormalizedRedisClient {
|
||||
get(key: string): Promise<string | null>;
|
||||
set(key: string, value: string, ttl?: number): Promise<string | null>;
|
||||
expire(key: string, ttl: number): Promise<number | boolean>;
|
||||
scanIterator(match: string, count: number): AsyncIterable<string>;
|
||||
del(key: string[]): Promise<number>;
|
||||
mget(key: string[]): Promise<(string | null)[]>;
|
||||
}
|
||||
interface Serializer {
|
||||
parse(s: string): SessionData | Promise<SessionData>;
|
||||
stringify(s: SessionData): string;
|
||||
}
|
||||
interface RedisStoreOptions {
|
||||
client: any;
|
||||
prefix?: string;
|
||||
scanCount?: number;
|
||||
serializer?: Serializer;
|
||||
ttl?: number | {
|
||||
(sess: SessionData): number;
|
||||
};
|
||||
disableTTL?: boolean;
|
||||
disableTouch?: boolean;
|
||||
}
|
||||
declare class RedisStore extends Store {
|
||||
client: NormalizedRedisClient;
|
||||
prefix: string;
|
||||
scanCount: number;
|
||||
serializer: Serializer;
|
||||
ttl: number | {
|
||||
(sess: SessionData): number;
|
||||
};
|
||||
disableTTL: boolean;
|
||||
disableTouch: boolean;
|
||||
constructor(opts: RedisStoreOptions);
|
||||
private normalizeClient;
|
||||
get(sid: string, cb?: (_err?: unknown, _data?: any) => void): Promise<void>;
|
||||
set(sid: string, sess: SessionData, cb?: (_err?: unknown, _data?: any) => void): Promise<void>;
|
||||
touch(sid: string, sess: SessionData, cb?: (_err?: unknown, _data?: any) => void): Promise<void>;
|
||||
destroy(sid: string, cb?: (_err?: unknown, _data?: any) => void): Promise<void>;
|
||||
clear(cb?: (_err?: unknown, _data?: any) => void): Promise<void>;
|
||||
length(cb?: (_err?: unknown, _data?: any) => void): Promise<void>;
|
||||
ids(cb?: (_err?: unknown, _data?: any) => void): Promise<void>;
|
||||
all(cb?: (_err?: unknown, _data?: any) => void): Promise<void>;
|
||||
private _getTTL;
|
||||
private _getAllKeys;
|
||||
}
|
||||
export default RedisStore;
|
||||
179
node_modules/connect-redis/dist/cjs/index.js
generated
vendored
Normal file
179
node_modules/connect-redis/dist/cjs/index.js
generated
vendored
Normal file
@ -0,0 +1,179 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const express_session_1 = require("express-session");
|
||||
const noop = (_err, _data) => { };
|
||||
class RedisStore extends express_session_1.Store {
|
||||
constructor(opts) {
|
||||
super();
|
||||
this.prefix = opts.prefix == null ? "sess:" : opts.prefix;
|
||||
this.scanCount = opts.scanCount || 100;
|
||||
this.serializer = opts.serializer || JSON;
|
||||
this.ttl = opts.ttl || 86400; // One day in seconds.
|
||||
this.disableTTL = opts.disableTTL || false;
|
||||
this.disableTouch = opts.disableTouch || false;
|
||||
this.client = this.normalizeClient(opts.client);
|
||||
}
|
||||
// Create a redis and ioredis compatible client
|
||||
normalizeClient(client) {
|
||||
let isRedis = "scanIterator" in client;
|
||||
return {
|
||||
get: (key) => client.get(key),
|
||||
set: (key, val, ttl) => {
|
||||
if (ttl) {
|
||||
return isRedis
|
||||
? client.set(key, val, { EX: ttl })
|
||||
: client.set(key, val, "EX", ttl);
|
||||
}
|
||||
return client.set(key, val);
|
||||
},
|
||||
del: (key) => client.del(key),
|
||||
expire: (key, ttl) => client.expire(key, ttl),
|
||||
mget: (keys) => (isRedis ? client.mGet(keys) : client.mget(keys)),
|
||||
scanIterator: (match, count) => {
|
||||
if (isRedis)
|
||||
return client.scanIterator({ MATCH: match, COUNT: count });
|
||||
// ioredis impl.
|
||||
return (async function* () {
|
||||
let [c, xs] = await client.scan("0", "MATCH", match, "COUNT", count);
|
||||
for (let key of xs)
|
||||
yield key;
|
||||
while (c !== "0") {
|
||||
;
|
||||
[c, xs] = await client.scan(c, "MATCH", match, "COUNT", count);
|
||||
for (let key of xs)
|
||||
yield key;
|
||||
}
|
||||
})();
|
||||
},
|
||||
};
|
||||
}
|
||||
async get(sid, cb = noop) {
|
||||
let key = this.prefix + sid;
|
||||
try {
|
||||
let data = await this.client.get(key);
|
||||
if (!data)
|
||||
return cb();
|
||||
return cb(null, await this.serializer.parse(data));
|
||||
}
|
||||
catch (err) {
|
||||
return cb(err);
|
||||
}
|
||||
}
|
||||
async set(sid, sess, cb = noop) {
|
||||
let key = this.prefix + sid;
|
||||
let ttl = this._getTTL(sess);
|
||||
try {
|
||||
let val = this.serializer.stringify(sess);
|
||||
if (ttl > 0) {
|
||||
if (this.disableTTL)
|
||||
await this.client.set(key, val);
|
||||
else
|
||||
await this.client.set(key, val, ttl);
|
||||
return cb();
|
||||
}
|
||||
else {
|
||||
return this.destroy(sid, cb);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
return cb(err);
|
||||
}
|
||||
}
|
||||
async touch(sid, sess, cb = noop) {
|
||||
let key = this.prefix + sid;
|
||||
if (this.disableTouch || this.disableTTL)
|
||||
return cb();
|
||||
try {
|
||||
await this.client.expire(key, this._getTTL(sess));
|
||||
return cb();
|
||||
}
|
||||
catch (err) {
|
||||
return cb(err);
|
||||
}
|
||||
}
|
||||
async destroy(sid, cb = noop) {
|
||||
let key = this.prefix + sid;
|
||||
try {
|
||||
await this.client.del([key]);
|
||||
return cb();
|
||||
}
|
||||
catch (err) {
|
||||
return cb(err);
|
||||
}
|
||||
}
|
||||
async clear(cb = noop) {
|
||||
try {
|
||||
let keys = await this._getAllKeys();
|
||||
if (!keys.length)
|
||||
return cb();
|
||||
await this.client.del(keys);
|
||||
return cb();
|
||||
}
|
||||
catch (err) {
|
||||
return cb(err);
|
||||
}
|
||||
}
|
||||
async length(cb = noop) {
|
||||
try {
|
||||
let keys = await this._getAllKeys();
|
||||
return cb(null, keys.length);
|
||||
}
|
||||
catch (err) {
|
||||
return cb(err);
|
||||
}
|
||||
}
|
||||
async ids(cb = noop) {
|
||||
let len = this.prefix.length;
|
||||
try {
|
||||
let keys = await this._getAllKeys();
|
||||
return cb(null, keys.map((k) => k.substring(len)));
|
||||
}
|
||||
catch (err) {
|
||||
return cb(err);
|
||||
}
|
||||
}
|
||||
async all(cb = noop) {
|
||||
let len = this.prefix.length;
|
||||
try {
|
||||
let keys = await this._getAllKeys();
|
||||
if (keys.length === 0)
|
||||
return cb(null, []);
|
||||
let data = await this.client.mget(keys);
|
||||
let results = data.reduce((acc, raw, idx) => {
|
||||
if (!raw)
|
||||
return acc;
|
||||
let sess = this.serializer.parse(raw);
|
||||
sess.id = keys[idx].substring(len);
|
||||
acc.push(sess);
|
||||
return acc;
|
||||
}, []);
|
||||
return cb(null, results);
|
||||
}
|
||||
catch (err) {
|
||||
return cb(err);
|
||||
}
|
||||
}
|
||||
_getTTL(sess) {
|
||||
if (typeof this.ttl === "function") {
|
||||
return this.ttl(sess);
|
||||
}
|
||||
let ttl;
|
||||
if (sess && sess.cookie && sess.cookie.expires) {
|
||||
let ms = Number(new Date(sess.cookie.expires)) - Date.now();
|
||||
ttl = Math.ceil(ms / 1000);
|
||||
}
|
||||
else {
|
||||
ttl = this.ttl;
|
||||
}
|
||||
return ttl;
|
||||
}
|
||||
async _getAllKeys() {
|
||||
let pattern = this.prefix + "*";
|
||||
let keys = [];
|
||||
for await (let key of this.client.scanIterator(pattern, this.scanCount)) {
|
||||
keys.push(key);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
exports.default = RedisStore;
|
||||
1
node_modules/connect-redis/dist/cjs/index_test.d.ts
generated
vendored
Normal file
1
node_modules/connect-redis/dist/cjs/index_test.d.ts
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
export {};
|
||||
124
node_modules/connect-redis/dist/cjs/index_test.js
generated
vendored
Normal file
124
node_modules/connect-redis/dist/cjs/index_test.js
generated
vendored
Normal file
@ -0,0 +1,124 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const blue_tape_1 = __importDefault(require("blue-tape"));
|
||||
const express_session_1 = require("express-session");
|
||||
const ioredis_1 = require("ioredis");
|
||||
const node_util_1 = require("node:util");
|
||||
const redis_1 = require("redis");
|
||||
const _1 = __importDefault(require("./"));
|
||||
const redisSrv = __importStar(require("./testdata/server"));
|
||||
(0, blue_tape_1.default)("setup", async () => {
|
||||
await redisSrv.connect();
|
||||
});
|
||||
(0, blue_tape_1.default)("defaults", async (t) => {
|
||||
let client = (0, redis_1.createClient)({ url: `redis://localhost:${redisSrv.port}` });
|
||||
await client.connect();
|
||||
let store = new _1.default({ client });
|
||||
t.ok(store.client, "stores client");
|
||||
t.equal(store.prefix, "sess:", "defaults to sess:");
|
||||
t.equal(store.ttl, 86400, "defaults to one day");
|
||||
t.equal(store.scanCount, 100, "defaults SCAN count to 100");
|
||||
t.equal(store.serializer, JSON, "defaults to JSON serialization");
|
||||
t.equal(store.disableTouch, false, "defaults to having `touch` enabled");
|
||||
t.equal(store.disableTTL, false, "defaults to having `ttl` enabled");
|
||||
await client.disconnect();
|
||||
});
|
||||
(0, blue_tape_1.default)("redis", async (t) => {
|
||||
let client = (0, redis_1.createClient)({ url: `redis://localhost:${redisSrv.port}` });
|
||||
await client.connect();
|
||||
let store = new _1.default({ client });
|
||||
await lifecycleTest(store, client, t);
|
||||
await client.disconnect();
|
||||
});
|
||||
(0, blue_tape_1.default)("ioredis", async (t) => {
|
||||
let client = new ioredis_1.Redis(`redis://localhost:${redisSrv.port}`);
|
||||
let store = new _1.default({ client });
|
||||
await lifecycleTest(store, client, t);
|
||||
client.disconnect();
|
||||
});
|
||||
(0, blue_tape_1.default)("teardown", redisSrv.disconnect);
|
||||
async function lifecycleTest(store, client, t) {
|
||||
const P = (f) => (0, node_util_1.promisify)(f).bind(store);
|
||||
let res = await P(store.clear)();
|
||||
let sess = { foo: "bar" };
|
||||
await P(store.set)("123", sess);
|
||||
res = await P(store.get)("123");
|
||||
t.same(res, sess, "store.get");
|
||||
let ttl = await client.ttl("sess:123");
|
||||
t.ok(ttl >= 86399, "check one day ttl");
|
||||
ttl = 60;
|
||||
let expires = new Date(Date.now() + ttl * 1000).toISOString();
|
||||
await P(store.set)("456", { cookie: { expires } });
|
||||
ttl = await client.ttl("sess:456");
|
||||
t.ok(ttl <= 60, "check expires ttl");
|
||||
ttl = 90;
|
||||
let expires2 = new Date(Date.now() + ttl * 1000).toISOString();
|
||||
await P(store.touch)("456", { cookie: { expires: expires2 } });
|
||||
ttl = await client.ttl("sess:456");
|
||||
t.ok(ttl > 60, "check expires ttl touch");
|
||||
res = await P(store.length)();
|
||||
t.equal(res, 2, "stored two keys length");
|
||||
res = await P(store.ids)();
|
||||
res.sort();
|
||||
t.same(res, ["123", "456"], "stored two keys ids");
|
||||
res = await P(store.all)();
|
||||
res.sort((a, b) => (a.id > b.id ? 1 : -1));
|
||||
t.same(res, [
|
||||
{ id: "123", foo: "bar" },
|
||||
{ id: "456", cookie: { expires } },
|
||||
], "stored two keys data");
|
||||
await P(store.destroy)("456");
|
||||
res = await P(store.length)();
|
||||
t.equal(res, 1, "one key remains");
|
||||
res = await P(store.clear)();
|
||||
res = await P(store.length)();
|
||||
t.equal(res, 0, "no keys remain");
|
||||
let count = 1000;
|
||||
await load(store, count);
|
||||
res = await P(store.length)();
|
||||
t.equal(res, count, "bulk count");
|
||||
await P(store.clear)();
|
||||
res = await P(store.length)();
|
||||
t.equal(res, 0, "bulk clear");
|
||||
expires = new Date(Date.now() + ttl * 1000).toISOString(); // expires in the future
|
||||
res = await P(store.set)("789", { cookie: { expires } });
|
||||
res = await P(store.length)();
|
||||
t.equal(res, 1, "one key exists (session 789)");
|
||||
expires = new Date(Date.now() - ttl * 1000).toISOString(); // expires in the past
|
||||
await P(store.set)("789", { cookie: { expires } });
|
||||
res = await P(store.length)();
|
||||
t.equal(res, 0, "no key remains and that includes session 789");
|
||||
}
|
||||
async function load(store, count) {
|
||||
let cookie = new express_session_1.Cookie();
|
||||
for (let sid = 0; sid < count; sid++) {
|
||||
cookie.expires = new Date(Date.now() + 1000);
|
||||
await store.set("s" + sid, { cookie });
|
||||
}
|
||||
}
|
||||
48
node_modules/connect-redis/dist/esm/index.d.ts
generated
vendored
Normal file
48
node_modules/connect-redis/dist/esm/index.d.ts
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
import { SessionData, Store } from "express-session";
|
||||
interface NormalizedRedisClient {
|
||||
get(key: string): Promise<string | null>;
|
||||
set(key: string, value: string, ttl?: number): Promise<string | null>;
|
||||
expire(key: string, ttl: number): Promise<number | boolean>;
|
||||
scanIterator(match: string, count: number): AsyncIterable<string>;
|
||||
del(key: string[]): Promise<number>;
|
||||
mget(key: string[]): Promise<(string | null)[]>;
|
||||
}
|
||||
interface Serializer {
|
||||
parse(s: string): SessionData | Promise<SessionData>;
|
||||
stringify(s: SessionData): string;
|
||||
}
|
||||
interface RedisStoreOptions {
|
||||
client: any;
|
||||
prefix?: string;
|
||||
scanCount?: number;
|
||||
serializer?: Serializer;
|
||||
ttl?: number | {
|
||||
(sess: SessionData): number;
|
||||
};
|
||||
disableTTL?: boolean;
|
||||
disableTouch?: boolean;
|
||||
}
|
||||
declare class RedisStore extends Store {
|
||||
client: NormalizedRedisClient;
|
||||
prefix: string;
|
||||
scanCount: number;
|
||||
serializer: Serializer;
|
||||
ttl: number | {
|
||||
(sess: SessionData): number;
|
||||
};
|
||||
disableTTL: boolean;
|
||||
disableTouch: boolean;
|
||||
constructor(opts: RedisStoreOptions);
|
||||
private normalizeClient;
|
||||
get(sid: string, cb?: (_err?: unknown, _data?: any) => void): Promise<void>;
|
||||
set(sid: string, sess: SessionData, cb?: (_err?: unknown, _data?: any) => void): Promise<void>;
|
||||
touch(sid: string, sess: SessionData, cb?: (_err?: unknown, _data?: any) => void): Promise<void>;
|
||||
destroy(sid: string, cb?: (_err?: unknown, _data?: any) => void): Promise<void>;
|
||||
clear(cb?: (_err?: unknown, _data?: any) => void): Promise<void>;
|
||||
length(cb?: (_err?: unknown, _data?: any) => void): Promise<void>;
|
||||
ids(cb?: (_err?: unknown, _data?: any) => void): Promise<void>;
|
||||
all(cb?: (_err?: unknown, _data?: any) => void): Promise<void>;
|
||||
private _getTTL;
|
||||
private _getAllKeys;
|
||||
}
|
||||
export default RedisStore;
|
||||
177
node_modules/connect-redis/dist/esm/index.js
generated
vendored
Normal file
177
node_modules/connect-redis/dist/esm/index.js
generated
vendored
Normal file
@ -0,0 +1,177 @@
|
||||
import { Store } from "express-session";
|
||||
const noop = (_err, _data) => { };
|
||||
class RedisStore extends Store {
|
||||
constructor(opts) {
|
||||
super();
|
||||
this.prefix = opts.prefix == null ? "sess:" : opts.prefix;
|
||||
this.scanCount = opts.scanCount || 100;
|
||||
this.serializer = opts.serializer || JSON;
|
||||
this.ttl = opts.ttl || 86400; // One day in seconds.
|
||||
this.disableTTL = opts.disableTTL || false;
|
||||
this.disableTouch = opts.disableTouch || false;
|
||||
this.client = this.normalizeClient(opts.client);
|
||||
}
|
||||
// Create a redis and ioredis compatible client
|
||||
normalizeClient(client) {
|
||||
let isRedis = "scanIterator" in client;
|
||||
return {
|
||||
get: (key) => client.get(key),
|
||||
set: (key, val, ttl) => {
|
||||
if (ttl) {
|
||||
return isRedis
|
||||
? client.set(key, val, { EX: ttl })
|
||||
: client.set(key, val, "EX", ttl);
|
||||
}
|
||||
return client.set(key, val);
|
||||
},
|
||||
del: (key) => client.del(key),
|
||||
expire: (key, ttl) => client.expire(key, ttl),
|
||||
mget: (keys) => (isRedis ? client.mGet(keys) : client.mget(keys)),
|
||||
scanIterator: (match, count) => {
|
||||
if (isRedis)
|
||||
return client.scanIterator({ MATCH: match, COUNT: count });
|
||||
// ioredis impl.
|
||||
return (async function* () {
|
||||
let [c, xs] = await client.scan("0", "MATCH", match, "COUNT", count);
|
||||
for (let key of xs)
|
||||
yield key;
|
||||
while (c !== "0") {
|
||||
;
|
||||
[c, xs] = await client.scan(c, "MATCH", match, "COUNT", count);
|
||||
for (let key of xs)
|
||||
yield key;
|
||||
}
|
||||
})();
|
||||
},
|
||||
};
|
||||
}
|
||||
async get(sid, cb = noop) {
|
||||
let key = this.prefix + sid;
|
||||
try {
|
||||
let data = await this.client.get(key);
|
||||
if (!data)
|
||||
return cb();
|
||||
return cb(null, await this.serializer.parse(data));
|
||||
}
|
||||
catch (err) {
|
||||
return cb(err);
|
||||
}
|
||||
}
|
||||
async set(sid, sess, cb = noop) {
|
||||
let key = this.prefix + sid;
|
||||
let ttl = this._getTTL(sess);
|
||||
try {
|
||||
let val = this.serializer.stringify(sess);
|
||||
if (ttl > 0) {
|
||||
if (this.disableTTL)
|
||||
await this.client.set(key, val);
|
||||
else
|
||||
await this.client.set(key, val, ttl);
|
||||
return cb();
|
||||
}
|
||||
else {
|
||||
return this.destroy(sid, cb);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
return cb(err);
|
||||
}
|
||||
}
|
||||
async touch(sid, sess, cb = noop) {
|
||||
let key = this.prefix + sid;
|
||||
if (this.disableTouch || this.disableTTL)
|
||||
return cb();
|
||||
try {
|
||||
await this.client.expire(key, this._getTTL(sess));
|
||||
return cb();
|
||||
}
|
||||
catch (err) {
|
||||
return cb(err);
|
||||
}
|
||||
}
|
||||
async destroy(sid, cb = noop) {
|
||||
let key = this.prefix + sid;
|
||||
try {
|
||||
await this.client.del([key]);
|
||||
return cb();
|
||||
}
|
||||
catch (err) {
|
||||
return cb(err);
|
||||
}
|
||||
}
|
||||
async clear(cb = noop) {
|
||||
try {
|
||||
let keys = await this._getAllKeys();
|
||||
if (!keys.length)
|
||||
return cb();
|
||||
await this.client.del(keys);
|
||||
return cb();
|
||||
}
|
||||
catch (err) {
|
||||
return cb(err);
|
||||
}
|
||||
}
|
||||
async length(cb = noop) {
|
||||
try {
|
||||
let keys = await this._getAllKeys();
|
||||
return cb(null, keys.length);
|
||||
}
|
||||
catch (err) {
|
||||
return cb(err);
|
||||
}
|
||||
}
|
||||
async ids(cb = noop) {
|
||||
let len = this.prefix.length;
|
||||
try {
|
||||
let keys = await this._getAllKeys();
|
||||
return cb(null, keys.map((k) => k.substring(len)));
|
||||
}
|
||||
catch (err) {
|
||||
return cb(err);
|
||||
}
|
||||
}
|
||||
async all(cb = noop) {
|
||||
let len = this.prefix.length;
|
||||
try {
|
||||
let keys = await this._getAllKeys();
|
||||
if (keys.length === 0)
|
||||
return cb(null, []);
|
||||
let data = await this.client.mget(keys);
|
||||
let results = data.reduce((acc, raw, idx) => {
|
||||
if (!raw)
|
||||
return acc;
|
||||
let sess = this.serializer.parse(raw);
|
||||
sess.id = keys[idx].substring(len);
|
||||
acc.push(sess);
|
||||
return acc;
|
||||
}, []);
|
||||
return cb(null, results);
|
||||
}
|
||||
catch (err) {
|
||||
return cb(err);
|
||||
}
|
||||
}
|
||||
_getTTL(sess) {
|
||||
if (typeof this.ttl === "function") {
|
||||
return this.ttl(sess);
|
||||
}
|
||||
let ttl;
|
||||
if (sess && sess.cookie && sess.cookie.expires) {
|
||||
let ms = Number(new Date(sess.cookie.expires)) - Date.now();
|
||||
ttl = Math.ceil(ms / 1000);
|
||||
}
|
||||
else {
|
||||
ttl = this.ttl;
|
||||
}
|
||||
return ttl;
|
||||
}
|
||||
async _getAllKeys() {
|
||||
let pattern = this.prefix + "*";
|
||||
let keys = [];
|
||||
for await (let key of this.client.scanIterator(pattern, this.scanCount)) {
|
||||
keys.push(key);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
export default RedisStore;
|
||||
1
node_modules/connect-redis/dist/esm/index_test.d.ts
generated
vendored
Normal file
1
node_modules/connect-redis/dist/esm/index_test.d.ts
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
export {};
|
||||
96
node_modules/connect-redis/dist/esm/index_test.js
generated
vendored
Normal file
96
node_modules/connect-redis/dist/esm/index_test.js
generated
vendored
Normal file
@ -0,0 +1,96 @@
|
||||
import test from "blue-tape";
|
||||
import { Cookie } from "express-session";
|
||||
import { Redis } from "ioredis";
|
||||
import { promisify } from "node:util";
|
||||
import { createClient } from "redis";
|
||||
import RedisStore from "./";
|
||||
import * as redisSrv from "./testdata/server";
|
||||
test("setup", async () => {
|
||||
await redisSrv.connect();
|
||||
});
|
||||
test("defaults", async (t) => {
|
||||
let client = createClient({ url: `redis://localhost:${redisSrv.port}` });
|
||||
await client.connect();
|
||||
let store = new RedisStore({ client });
|
||||
t.ok(store.client, "stores client");
|
||||
t.equal(store.prefix, "sess:", "defaults to sess:");
|
||||
t.equal(store.ttl, 86400, "defaults to one day");
|
||||
t.equal(store.scanCount, 100, "defaults SCAN count to 100");
|
||||
t.equal(store.serializer, JSON, "defaults to JSON serialization");
|
||||
t.equal(store.disableTouch, false, "defaults to having `touch` enabled");
|
||||
t.equal(store.disableTTL, false, "defaults to having `ttl` enabled");
|
||||
await client.disconnect();
|
||||
});
|
||||
test("redis", async (t) => {
|
||||
let client = createClient({ url: `redis://localhost:${redisSrv.port}` });
|
||||
await client.connect();
|
||||
let store = new RedisStore({ client });
|
||||
await lifecycleTest(store, client, t);
|
||||
await client.disconnect();
|
||||
});
|
||||
test("ioredis", async (t) => {
|
||||
let client = new Redis(`redis://localhost:${redisSrv.port}`);
|
||||
let store = new RedisStore({ client });
|
||||
await lifecycleTest(store, client, t);
|
||||
client.disconnect();
|
||||
});
|
||||
test("teardown", redisSrv.disconnect);
|
||||
async function lifecycleTest(store, client, t) {
|
||||
const P = (f) => promisify(f).bind(store);
|
||||
let res = await P(store.clear)();
|
||||
let sess = { foo: "bar" };
|
||||
await P(store.set)("123", sess);
|
||||
res = await P(store.get)("123");
|
||||
t.same(res, sess, "store.get");
|
||||
let ttl = await client.ttl("sess:123");
|
||||
t.ok(ttl >= 86399, "check one day ttl");
|
||||
ttl = 60;
|
||||
let expires = new Date(Date.now() + ttl * 1000).toISOString();
|
||||
await P(store.set)("456", { cookie: { expires } });
|
||||
ttl = await client.ttl("sess:456");
|
||||
t.ok(ttl <= 60, "check expires ttl");
|
||||
ttl = 90;
|
||||
let expires2 = new Date(Date.now() + ttl * 1000).toISOString();
|
||||
await P(store.touch)("456", { cookie: { expires: expires2 } });
|
||||
ttl = await client.ttl("sess:456");
|
||||
t.ok(ttl > 60, "check expires ttl touch");
|
||||
res = await P(store.length)();
|
||||
t.equal(res, 2, "stored two keys length");
|
||||
res = await P(store.ids)();
|
||||
res.sort();
|
||||
t.same(res, ["123", "456"], "stored two keys ids");
|
||||
res = await P(store.all)();
|
||||
res.sort((a, b) => (a.id > b.id ? 1 : -1));
|
||||
t.same(res, [
|
||||
{ id: "123", foo: "bar" },
|
||||
{ id: "456", cookie: { expires } },
|
||||
], "stored two keys data");
|
||||
await P(store.destroy)("456");
|
||||
res = await P(store.length)();
|
||||
t.equal(res, 1, "one key remains");
|
||||
res = await P(store.clear)();
|
||||
res = await P(store.length)();
|
||||
t.equal(res, 0, "no keys remain");
|
||||
let count = 1000;
|
||||
await load(store, count);
|
||||
res = await P(store.length)();
|
||||
t.equal(res, count, "bulk count");
|
||||
await P(store.clear)();
|
||||
res = await P(store.length)();
|
||||
t.equal(res, 0, "bulk clear");
|
||||
expires = new Date(Date.now() + ttl * 1000).toISOString(); // expires in the future
|
||||
res = await P(store.set)("789", { cookie: { expires } });
|
||||
res = await P(store.length)();
|
||||
t.equal(res, 1, "one key exists (session 789)");
|
||||
expires = new Date(Date.now() - ttl * 1000).toISOString(); // expires in the past
|
||||
await P(store.set)("789", { cookie: { expires } });
|
||||
res = await P(store.length)();
|
||||
t.equal(res, 0, "no key remains and that includes session 789");
|
||||
}
|
||||
async function load(store, count) {
|
||||
let cookie = new Cookie();
|
||||
for (let sid = 0; sid < count; sid++) {
|
||||
cookie.expires = new Date(Date.now() + 1000);
|
||||
await store.set("s" + sid, { cookie });
|
||||
}
|
||||
}
|
||||
1
node_modules/connect-redis/dist/esm/package.json
generated
vendored
Normal file
1
node_modules/connect-redis/dist/esm/package.json
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"type":"module"}
|
||||
208
node_modules/connect-redis/index.ts
generated
vendored
Normal file
208
node_modules/connect-redis/index.ts
generated
vendored
Normal file
@ -0,0 +1,208 @@
|
||||
import {SessionData, Store} from "express-session"
|
||||
|
||||
const noop = (_err?: unknown, _data?: any) => {}
|
||||
|
||||
interface NormalizedRedisClient {
|
||||
get(key: string): Promise<string | null>
|
||||
set(key: string, value: string, ttl?: number): Promise<string | null>
|
||||
expire(key: string, ttl: number): Promise<number | boolean>
|
||||
scanIterator(match: string, count: number): AsyncIterable<string>
|
||||
del(key: string[]): Promise<number>
|
||||
mget(key: string[]): Promise<(string | null)[]>
|
||||
}
|
||||
|
||||
interface Serializer {
|
||||
parse(s: string): SessionData | Promise<SessionData>
|
||||
stringify(s: SessionData): string
|
||||
}
|
||||
|
||||
interface RedisStoreOptions {
|
||||
client: any
|
||||
prefix?: string
|
||||
scanCount?: number
|
||||
serializer?: Serializer
|
||||
ttl?: number | {(sess: SessionData): number}
|
||||
disableTTL?: boolean
|
||||
disableTouch?: boolean
|
||||
}
|
||||
|
||||
class RedisStore extends Store {
|
||||
client: NormalizedRedisClient
|
||||
prefix: string
|
||||
scanCount: number
|
||||
serializer: Serializer
|
||||
ttl: number | {(sess: SessionData): number}
|
||||
disableTTL: boolean
|
||||
disableTouch: boolean
|
||||
|
||||
constructor(opts: RedisStoreOptions) {
|
||||
super()
|
||||
this.prefix = opts.prefix == null ? "sess:" : opts.prefix
|
||||
this.scanCount = opts.scanCount || 100
|
||||
this.serializer = opts.serializer || JSON
|
||||
this.ttl = opts.ttl || 86400 // One day in seconds.
|
||||
this.disableTTL = opts.disableTTL || false
|
||||
this.disableTouch = opts.disableTouch || false
|
||||
this.client = this.normalizeClient(opts.client)
|
||||
}
|
||||
|
||||
// Create a redis and ioredis compatible client
|
||||
private normalizeClient(client: any): NormalizedRedisClient {
|
||||
let isRedis = "scanIterator" in client
|
||||
return {
|
||||
get: (key) => client.get(key),
|
||||
set: (key, val, ttl) => {
|
||||
if (ttl) {
|
||||
return isRedis
|
||||
? client.set(key, val, {EX: ttl})
|
||||
: client.set(key, val, "EX", ttl)
|
||||
}
|
||||
return client.set(key, val)
|
||||
},
|
||||
del: (key) => client.del(key),
|
||||
expire: (key, ttl) => client.expire(key, ttl),
|
||||
mget: (keys) => (isRedis ? client.mGet(keys) : client.mget(keys)),
|
||||
scanIterator: (match, count) => {
|
||||
if (isRedis) return client.scanIterator({MATCH: match, COUNT: count})
|
||||
|
||||
// ioredis impl.
|
||||
return (async function* () {
|
||||
let [c, xs] = await client.scan("0", "MATCH", match, "COUNT", count)
|
||||
for (let key of xs) yield key
|
||||
while (c !== "0") {
|
||||
;[c, xs] = await client.scan(c, "MATCH", match, "COUNT", count)
|
||||
for (let key of xs) yield key
|
||||
}
|
||||
})()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async get(sid: string, cb = noop) {
|
||||
let key = this.prefix + sid
|
||||
try {
|
||||
let data = await this.client.get(key)
|
||||
if (!data) return cb()
|
||||
return cb(null, await this.serializer.parse(data))
|
||||
} catch (err) {
|
||||
return cb(err)
|
||||
}
|
||||
}
|
||||
|
||||
async set(sid: string, sess: SessionData, cb = noop) {
|
||||
let key = this.prefix + sid
|
||||
let ttl = this._getTTL(sess)
|
||||
try {
|
||||
let val = this.serializer.stringify(sess)
|
||||
if (ttl > 0) {
|
||||
if (this.disableTTL) await this.client.set(key, val)
|
||||
else await this.client.set(key, val, ttl)
|
||||
return cb()
|
||||
} else {
|
||||
return this.destroy(sid, cb)
|
||||
}
|
||||
} catch (err) {
|
||||
return cb(err)
|
||||
}
|
||||
}
|
||||
|
||||
async touch(sid: string, sess: SessionData, cb = noop) {
|
||||
let key = this.prefix + sid
|
||||
if (this.disableTouch || this.disableTTL) return cb()
|
||||
try {
|
||||
await this.client.expire(key, this._getTTL(sess))
|
||||
return cb()
|
||||
} catch (err) {
|
||||
return cb(err)
|
||||
}
|
||||
}
|
||||
|
||||
async destroy(sid: string, cb = noop) {
|
||||
let key = this.prefix + sid
|
||||
try {
|
||||
await this.client.del([key])
|
||||
return cb()
|
||||
} catch (err) {
|
||||
return cb(err)
|
||||
}
|
||||
}
|
||||
|
||||
async clear(cb = noop) {
|
||||
try {
|
||||
let keys = await this._getAllKeys()
|
||||
if (!keys.length) return cb()
|
||||
await this.client.del(keys)
|
||||
return cb()
|
||||
} catch (err) {
|
||||
return cb(err)
|
||||
}
|
||||
}
|
||||
|
||||
async length(cb = noop) {
|
||||
try {
|
||||
let keys = await this._getAllKeys()
|
||||
return cb(null, keys.length)
|
||||
} catch (err) {
|
||||
return cb(err)
|
||||
}
|
||||
}
|
||||
|
||||
async ids(cb = noop) {
|
||||
let len = this.prefix.length
|
||||
try {
|
||||
let keys = await this._getAllKeys()
|
||||
return cb(
|
||||
null,
|
||||
keys.map((k) => k.substring(len)),
|
||||
)
|
||||
} catch (err) {
|
||||
return cb(err)
|
||||
}
|
||||
}
|
||||
|
||||
async all(cb = noop) {
|
||||
let len = this.prefix.length
|
||||
try {
|
||||
let keys = await this._getAllKeys()
|
||||
if (keys.length === 0) return cb(null, [])
|
||||
|
||||
let data = await this.client.mget(keys)
|
||||
let results = data.reduce((acc, raw, idx) => {
|
||||
if (!raw) return acc
|
||||
let sess = this.serializer.parse(raw) as any
|
||||
sess.id = keys[idx].substring(len)
|
||||
acc.push(sess)
|
||||
return acc
|
||||
}, [] as SessionData[])
|
||||
return cb(null, results)
|
||||
} catch (err) {
|
||||
return cb(err)
|
||||
}
|
||||
}
|
||||
|
||||
private _getTTL(sess: SessionData) {
|
||||
if (typeof this.ttl === "function") {
|
||||
return this.ttl(sess)
|
||||
}
|
||||
|
||||
let ttl
|
||||
if (sess && sess.cookie && sess.cookie.expires) {
|
||||
let ms = Number(new Date(sess.cookie.expires)) - Date.now()
|
||||
ttl = Math.ceil(ms / 1000)
|
||||
} else {
|
||||
ttl = this.ttl
|
||||
}
|
||||
return ttl
|
||||
}
|
||||
|
||||
private async _getAllKeys() {
|
||||
let pattern = this.prefix + "*"
|
||||
let keys = []
|
||||
for await (let key of this.client.scanIterator(pattern, this.scanCount)) {
|
||||
keys.push(key)
|
||||
}
|
||||
return keys
|
||||
}
|
||||
}
|
||||
|
||||
export default RedisStore
|
||||
131
node_modules/connect-redis/index_test.ts
generated
vendored
Normal file
131
node_modules/connect-redis/index_test.ts
generated
vendored
Normal file
@ -0,0 +1,131 @@
|
||||
import test from "blue-tape"
|
||||
import {Cookie} from "express-session"
|
||||
import {Redis} from "ioredis"
|
||||
import {promisify} from "node:util"
|
||||
import {createClient} from "redis"
|
||||
import RedisStore from "./"
|
||||
import * as redisSrv from "./testdata/server"
|
||||
|
||||
test("setup", async () => {
|
||||
await redisSrv.connect()
|
||||
})
|
||||
|
||||
test("defaults", async (t) => {
|
||||
let client = createClient({url: `redis://localhost:${redisSrv.port}`})
|
||||
await client.connect()
|
||||
|
||||
let store = new RedisStore({client})
|
||||
|
||||
t.ok(store.client, "stores client")
|
||||
t.equal(store.prefix, "sess:", "defaults to sess:")
|
||||
t.equal(store.ttl, 86400, "defaults to one day")
|
||||
t.equal(store.scanCount, 100, "defaults SCAN count to 100")
|
||||
t.equal(store.serializer, JSON, "defaults to JSON serialization")
|
||||
t.equal(store.disableTouch, false, "defaults to having `touch` enabled")
|
||||
t.equal(store.disableTTL, false, "defaults to having `ttl` enabled")
|
||||
await client.disconnect()
|
||||
})
|
||||
|
||||
test("redis", async (t) => {
|
||||
let client = createClient({url: `redis://localhost:${redisSrv.port}`})
|
||||
await client.connect()
|
||||
let store = new RedisStore({client})
|
||||
await lifecycleTest(store, client, t)
|
||||
await client.disconnect()
|
||||
})
|
||||
|
||||
test("ioredis", async (t) => {
|
||||
let client = new Redis(`redis://localhost:${redisSrv.port}`)
|
||||
let store = new RedisStore({client})
|
||||
await lifecycleTest(store, client, t)
|
||||
client.disconnect()
|
||||
})
|
||||
|
||||
test("teardown", redisSrv.disconnect)
|
||||
|
||||
async function lifecycleTest(
|
||||
store: RedisStore,
|
||||
client: any,
|
||||
t: test.Test,
|
||||
): Promise<void> {
|
||||
const P = (f: any) => promisify(f).bind(store)
|
||||
let res = await P(store.clear)()
|
||||
|
||||
let sess = {foo: "bar"}
|
||||
await P(store.set)("123", sess)
|
||||
|
||||
res = await P(store.get)("123")
|
||||
t.same(res, sess, "store.get")
|
||||
|
||||
let ttl = await client.ttl("sess:123")
|
||||
t.ok(ttl >= 86399, "check one day ttl")
|
||||
|
||||
ttl = 60
|
||||
let expires = new Date(Date.now() + ttl * 1000).toISOString()
|
||||
await P(store.set)("456", {cookie: {expires}})
|
||||
ttl = await client.ttl("sess:456")
|
||||
t.ok(ttl <= 60, "check expires ttl")
|
||||
|
||||
ttl = 90
|
||||
let expires2 = new Date(Date.now() + ttl * 1000).toISOString()
|
||||
await P(store.touch)("456", {cookie: {expires: expires2}})
|
||||
ttl = await client.ttl("sess:456")
|
||||
t.ok(ttl > 60, "check expires ttl touch")
|
||||
|
||||
res = await P(store.length)()
|
||||
t.equal(res, 2, "stored two keys length")
|
||||
|
||||
res = await P(store.ids)()
|
||||
res.sort()
|
||||
t.same(res, ["123", "456"], "stored two keys ids")
|
||||
|
||||
res = await P(store.all)()
|
||||
res.sort((a: any, b: any) => (a.id > b.id ? 1 : -1))
|
||||
t.same(
|
||||
res,
|
||||
[
|
||||
{id: "123", foo: "bar"},
|
||||
{id: "456", cookie: {expires}},
|
||||
],
|
||||
"stored two keys data",
|
||||
)
|
||||
|
||||
await P(store.destroy)("456")
|
||||
res = await P(store.length)()
|
||||
t.equal(res, 1, "one key remains")
|
||||
|
||||
res = await P(store.clear)()
|
||||
|
||||
res = await P(store.length)()
|
||||
t.equal(res, 0, "no keys remain")
|
||||
|
||||
let count = 1000
|
||||
await load(store, count)
|
||||
|
||||
res = await P(store.length)()
|
||||
t.equal(res, count, "bulk count")
|
||||
|
||||
await P(store.clear)()
|
||||
res = await P(store.length)()
|
||||
t.equal(res, 0, "bulk clear")
|
||||
|
||||
expires = new Date(Date.now() + ttl * 1000).toISOString() // expires in the future
|
||||
res = await P(store.set)("789", {cookie: {expires}})
|
||||
|
||||
res = await P(store.length)()
|
||||
t.equal(res, 1, "one key exists (session 789)")
|
||||
|
||||
expires = new Date(Date.now() - ttl * 1000).toISOString() // expires in the past
|
||||
await P(store.set)("789", {cookie: {expires}})
|
||||
|
||||
res = await P(store.length)()
|
||||
t.equal(res, 0, "no key remains and that includes session 789")
|
||||
}
|
||||
|
||||
async function load(store: RedisStore, count: number) {
|
||||
let cookie = new Cookie()
|
||||
for (let sid = 0; sid < count; sid++) {
|
||||
cookie.expires = new Date(Date.now() + 1000)
|
||||
await store.set("s" + sid, {cookie})
|
||||
}
|
||||
}
|
||||
21
node_modules/connect-redis/license
generated
vendored
Normal file
21
node_modules/connect-redis/license
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2010-2023 TJ Holowaychuk
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
64
node_modules/connect-redis/package.json
generated
vendored
Normal file
64
node_modules/connect-redis/package.json
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
{
|
||||
"name": "connect-redis",
|
||||
"description": "Redis session store for Connect",
|
||||
"version": "7.1.1",
|
||||
"author": "TJ Holowaychuk <tj@vision-media.ca>",
|
||||
"contributors": [
|
||||
"Marc Harter <wavded@gmail.com>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"main": "./dist/esm/index.js",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/esm/index.js",
|
||||
"require": "./dist/cjs/index.js",
|
||||
"default": "./dist/esm/index.js"
|
||||
}
|
||||
},
|
||||
"types": "./dist/esm/index.d.ts",
|
||||
"scripts": {
|
||||
"prepublishOnly": "rm -rf dist && tsc & tsc --project tsconfig.esm.json && echo '{\"type\":\"module\"}' > dist/esm/package.json",
|
||||
"build": "npm run prepublishOnly",
|
||||
"test": "nyc ts-node node_modules/blue-tape/bin/blue-tape \"**/*_test.ts\"",
|
||||
"lint": "tsc --noemit && eslint --max-warnings 0 --ext ts testdata *.ts",
|
||||
"fmt": "prettier --write .",
|
||||
"fmt-check": "prettier --check ."
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@github.com:tj/connect-redis.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/blue-tape": "^0.1.36",
|
||||
"@types/express-session": "^1.17.10",
|
||||
"@types/node": "^20.11.5",
|
||||
"@typescript-eslint/eslint-plugin": "^6.19.0",
|
||||
"@typescript-eslint/parser": "^6.19.0",
|
||||
"blue-tape": "^1.0.0",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"express-session": "^1.17.3",
|
||||
"ioredis": "^5.3.2",
|
||||
"nyc": "^15.1.0",
|
||||
"prettier": "^3.2.4",
|
||||
"prettier-plugin-organize-imports": "^3.2.4",
|
||||
"redis": "^4.6.12",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"express-session": ">=1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/tj/connect-redis/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"connect",
|
||||
"redis",
|
||||
"session",
|
||||
"express"
|
||||
]
|
||||
}
|
||||
139
node_modules/connect-redis/readme.md
generated
vendored
Normal file
139
node_modules/connect-redis/readme.md
generated
vendored
Normal file
@ -0,0 +1,139 @@
|
||||
 [](https://npmjs.com/package/connect-redis) [](https://gitter.im/jlongster/prettier) 
|
||||
|
||||
**connect-redis** provides Redis session storage for Express.
|
||||
|
||||
## Installation
|
||||
|
||||
**connect-redis** requires `express-session` to installed and one of the following compatible Redis clients:
|
||||
|
||||
- [`redis`][1]
|
||||
- [`ioredis`][2]
|
||||
|
||||
Install with `redis`:
|
||||
|
||||
```sh
|
||||
npm install redis connect-redis express-session
|
||||
```
|
||||
|
||||
Install with `ioredis`:
|
||||
|
||||
```sh
|
||||
npm install ioredis connect-redis express-session
|
||||
```
|
||||
|
||||
## Importing
|
||||
|
||||
**connect-redis** supports both CommonJS (`require`) and ESM (`import`) modules.
|
||||
|
||||
Import using ESM/Typescript:
|
||||
|
||||
```js
|
||||
import RedisStore from "connect-redis"
|
||||
```
|
||||
|
||||
Require using CommonJS:
|
||||
|
||||
```js
|
||||
const RedisStore = require("connect-redis").default
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
Full setup using [`redis`][1] package:
|
||||
|
||||
```js
|
||||
import RedisStore from "connect-redis"
|
||||
import session from "express-session"
|
||||
import {createClient} from "redis"
|
||||
|
||||
// Initialize client.
|
||||
let redisClient = createClient()
|
||||
redisClient.connect().catch(console.error)
|
||||
|
||||
// Initialize store.
|
||||
let redisStore = new RedisStore({
|
||||
client: redisClient,
|
||||
prefix: "myapp:",
|
||||
})
|
||||
|
||||
// Initialize session storage.
|
||||
app.use(
|
||||
session({
|
||||
store: redisStore,
|
||||
resave: false, // required: force lightweight session keep alive (touch)
|
||||
saveUninitialized: false, // recommended: only save session when data exists
|
||||
secret: "keyboard cat",
|
||||
}),
|
||||
)
|
||||
```
|
||||
|
||||
### RedisStore(options)
|
||||
|
||||
#### Options
|
||||
|
||||
##### client
|
||||
|
||||
An instance of [`redis`][1] or [`ioredis`][2].
|
||||
|
||||
##### prefix
|
||||
|
||||
Key prefix in Redis (default: `sess:`).
|
||||
|
||||
**Note**: This prefix appends to whatever prefix you may have set on the `client` itself.
|
||||
|
||||
**Note**: You may need unique prefixes for different applications sharing the same Redis instance. This limits bulk commands exposed in `express-session` (like `length`, `all`, `keys`, and `clear`) to a single application's data.
|
||||
|
||||
##### ttl
|
||||
|
||||
If the session cookie has a `expires` date, `connect-redis` will use it as the TTL.
|
||||
|
||||
Otherwise, it will expire the session using the `ttl` option (default: `86400` seconds or one day).
|
||||
|
||||
```ts
|
||||
interface RedisStoreOptions {
|
||||
...
|
||||
ttl?: number | {(sess: SessionData): number}
|
||||
}
|
||||
```
|
||||
|
||||
`ttl` also has external callback support. You can use it for dynamic TTL generation. It has access to `session` data.
|
||||
|
||||
**Note**: The TTL is reset every time a user interacts with the server. You can disable this behavior in _some_ instances by using `disableTouch`.
|
||||
|
||||
**Note**: `express-session` does not update `expires` until the end of the request life cycle. _Calling `session.save()` manually beforehand will have the previous value_.
|
||||
|
||||
##### disableTouch
|
||||
|
||||
Disables resetting the TTL when using `touch` (default: `false`)
|
||||
|
||||
The `express-session` package uses `touch` to signal to the store that the user has interacted with the session but hasn't changed anything in its data. Typically, this helps keep the users session alive if session changes are infrequent but you may want to disable it to cut down the extra calls or to prevent users from keeping sessions open too long. Also consider enabling if you store a lot of data on the session.
|
||||
|
||||
Ref: <https://github.com/expressjs/session#storetouchsid-session-callback>
|
||||
|
||||
##### disableTTL
|
||||
|
||||
Disables key expiration completely (default: `false`)
|
||||
|
||||
This option disables key expiration requiring the user to manually manage key cleanup outside of `connect-redis`. Only use if you know what you are doing and have an exceptional case where you need to manage your own expiration in Redis.
|
||||
|
||||
**Note**: This has no effect on `express-session` setting cookie expiration.
|
||||
|
||||
##### serializer
|
||||
|
||||
Provide a custom encoder/decoder to use when storing and retrieving session data from Redis (default: `JSON.parse` and `JSON.stringify`).
|
||||
|
||||
Optionally `parse` method can be async if need be.
|
||||
|
||||
```ts
|
||||
interface Serializer {
|
||||
parse(string): object | Promise<object>
|
||||
stringify(object): string
|
||||
}
|
||||
```
|
||||
|
||||
##### scanCount
|
||||
|
||||
Value used for _count_ parameter in [Redis `SCAN` command](https://redis.io/commands/scan#the-count-option). Used for `ids()` and `all()` methods (default: `100`).
|
||||
|
||||
[1]: https://github.com/NodeRedis/node-redis
|
||||
[2]: https://github.com/luin/ioredis
|
||||
7
node_modules/connect-redis/tsconfig.esm.json
generated
vendored
Normal file
7
node_modules/connect-redis/tsconfig.esm.json
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "es2020",
|
||||
"outDir": "./dist/esm"
|
||||
}
|
||||
}
|
||||
18
node_modules/connect-redis/tsconfig.json
generated
vendored
Normal file
18
node_modules/connect-redis/tsconfig.json
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2020",
|
||||
"module": "commonjs",
|
||||
"isolatedModules": true,
|
||||
"strict": true,
|
||||
"noImplicitReturns": true,
|
||||
"noUnusedLocals": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"moduleResolution": "node",
|
||||
"declaration": true,
|
||||
"outDir": "./dist/cjs",
|
||||
"esModuleInterop": true,
|
||||
"resolveJsonModule": true,
|
||||
},
|
||||
"exclude": ["node_modules", "dist"],
|
||||
}
|
||||
Reference in New Issue
Block a user