@xnestjs/ioredis 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +3 -0
- package/cjs/index.js +8 -0
- package/cjs/package.json +3 -0
- package/cjs/redis-client.js +73 -0
- package/cjs/redis-core.module.js +118 -0
- package/cjs/redis.constants.js +5 -0
- package/cjs/redis.decorators.js +7 -0
- package/cjs/redis.interface.js +2 -0
- package/cjs/redis.module.js +25 -0
- package/cjs/redis.utils.js +12 -0
- package/esm/index.d.ts +5 -0
- package/esm/index.js +5 -0
- package/esm/redis-client.d.ts +41 -0
- package/esm/redis-client.js +68 -0
- package/esm/redis-core.module.d.ts +14 -0
- package/esm/redis-core.module.js +115 -0
- package/esm/redis.constants.d.ts +2 -0
- package/esm/redis.constants.js +2 -0
- package/esm/redis.decorators.d.ts +1 -0
- package/esm/redis.decorators.js +3 -0
- package/esm/redis.interface.d.ts +19 -0
- package/esm/redis.interface.js +1 -0
- package/esm/redis.module.d.ts +6 -0
- package/esm/redis.module.js +22 -0
- package/esm/redis.utils.d.ts +3 -0
- package/esm/redis.utils.js +8 -0
- package/package.json +62 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Panates
|
|
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.
|
package/README.md
ADDED
package/cjs/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
tslib_1.__exportStar(require("./redis.decorators.js"), exports);
|
|
5
|
+
tslib_1.__exportStar(require("./redis.interface.js"), exports);
|
|
6
|
+
tslib_1.__exportStar(require("./redis.module.js"), exports);
|
|
7
|
+
tslib_1.__exportStar(require("./redis.utils.js"), exports);
|
|
8
|
+
tslib_1.__exportStar(require("./redis-client.js"), exports);
|
package/cjs/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RedisClient = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const ioredis_1 = tslib_1.__importDefault(require("ioredis"));
|
|
6
|
+
const putil_varhelpers_1 = require("putil-varhelpers");
|
|
7
|
+
class RedisClient extends ioredis_1.default {
|
|
8
|
+
lockPrefix;
|
|
9
|
+
/**
|
|
10
|
+
* Try to lock once
|
|
11
|
+
* @param {string} name redis-lock name
|
|
12
|
+
* @param {number} [expire] milliseconds, TTL for the redis key
|
|
13
|
+
* @returns {boolean} true: success, false: failed
|
|
14
|
+
*/
|
|
15
|
+
async tryLock(name, expire) {
|
|
16
|
+
const result = await this.set(this._getLockKey(name), '_lock_', 'PX', expire, 'NX');
|
|
17
|
+
return result !== null;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* lock, automatically retrying if failed
|
|
21
|
+
* @param {string} name redis-lock name
|
|
22
|
+
* @param {object} [options] Options
|
|
23
|
+
* @param {number} [options.expire=60000] TTL
|
|
24
|
+
* @param {number} [options.retryInterval=100] milliseconds, the interval to retry if failed
|
|
25
|
+
* @param {number} [options.maxRetries=10] max times to retry
|
|
26
|
+
*/
|
|
27
|
+
async lock(name, options) {
|
|
28
|
+
const expire = (0, putil_varhelpers_1.toNumberDef)(options?.expire, 60000);
|
|
29
|
+
const retryInterval = (0, putil_varhelpers_1.toNumberDef)(options?.retryInterval, 100);
|
|
30
|
+
const maxRetries = (0, putil_varhelpers_1.toNumberDef)(options?.maxRetries, 10);
|
|
31
|
+
let retryTimes = 0;
|
|
32
|
+
// eslint-disable-next-line no-constant-condition
|
|
33
|
+
while (1) {
|
|
34
|
+
if (await this.tryLock(name, expire)) {
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
await this._sleep(retryInterval);
|
|
39
|
+
if (retryTimes >= maxRetries) {
|
|
40
|
+
throw new Error(`Redis lock "${name}" timed out`);
|
|
41
|
+
}
|
|
42
|
+
retryTimes++;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Unlock a redis-lock by name
|
|
48
|
+
* @param {string} name redis-lock name
|
|
49
|
+
*/
|
|
50
|
+
async unlock(name) {
|
|
51
|
+
const s = 'if redis.call(\'get\', KEYS[1]) == ARGV[1] then return redis.call(\'del\', KEYS[1]) else return 0 end';
|
|
52
|
+
await this.eval(s, 1, this._getLockKey(name), '_lock_');
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Set TTL for a redis-lock
|
|
56
|
+
* @param {string} name redis-lock name
|
|
57
|
+
* @param {number} milliseconds TTL
|
|
58
|
+
*/
|
|
59
|
+
async setLockTTL(name, milliseconds) {
|
|
60
|
+
const result = await this.pexpire(this._getLockKey(name), milliseconds);
|
|
61
|
+
return !!result;
|
|
62
|
+
}
|
|
63
|
+
_getLockKey(name) {
|
|
64
|
+
return (this.lockPrefix || 'lock:') + name;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* @param {number} ms milliseconds, the sleep interval
|
|
68
|
+
*/
|
|
69
|
+
_sleep(ms) {
|
|
70
|
+
return new Promise(resolve => setTimeout(resolve, Number(ms)));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
exports.RedisClient = RedisClient;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var RedisCoreModule_1;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.RedisCoreModule = void 0;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const crypto = tslib_1.__importStar(require("crypto"));
|
|
7
|
+
const common_1 = require("@nestjs/common");
|
|
8
|
+
const core_1 = require("@nestjs/core");
|
|
9
|
+
const redis_constants_js_1 = require("./redis.constants.js");
|
|
10
|
+
const redis_utils_js_1 = require("./redis.utils.js");
|
|
11
|
+
const redis_client_js_1 = require("./redis-client.js");
|
|
12
|
+
let RedisCoreModule = RedisCoreModule_1 = class RedisCoreModule {
|
|
13
|
+
options;
|
|
14
|
+
moduleRef;
|
|
15
|
+
constructor(options, moduleRef) {
|
|
16
|
+
this.options = options;
|
|
17
|
+
this.moduleRef = moduleRef;
|
|
18
|
+
}
|
|
19
|
+
static forRoot(options = {}) {
|
|
20
|
+
const optionsProvider = {
|
|
21
|
+
provide: redis_constants_js_1.IOREDIS_MODULE_OPTIONS,
|
|
22
|
+
useValue: options
|
|
23
|
+
};
|
|
24
|
+
const connectionProvider = {
|
|
25
|
+
provide: (0, redis_utils_js_1.getRedisClientToken)(options.name),
|
|
26
|
+
useFactory: () => this.createClient(options)
|
|
27
|
+
};
|
|
28
|
+
return {
|
|
29
|
+
module: RedisCoreModule_1,
|
|
30
|
+
providers: [connectionProvider, optionsProvider],
|
|
31
|
+
exports: [connectionProvider]
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
static forRootAsync(asyncOptions) {
|
|
35
|
+
const connectionProvider = {
|
|
36
|
+
provide: (0, redis_utils_js_1.getRedisClientToken)(asyncOptions.name),
|
|
37
|
+
inject: [redis_constants_js_1.IOREDIS_MODULE_OPTIONS],
|
|
38
|
+
useFactory: async (moduleOptions) => {
|
|
39
|
+
const name = asyncOptions.name || moduleOptions.name;
|
|
40
|
+
return this.createClient({
|
|
41
|
+
...moduleOptions,
|
|
42
|
+
name
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
const asyncProviders = this.createAsyncProviders(asyncOptions);
|
|
47
|
+
return {
|
|
48
|
+
module: RedisCoreModule_1,
|
|
49
|
+
imports: asyncOptions.imports,
|
|
50
|
+
providers: [
|
|
51
|
+
...asyncProviders,
|
|
52
|
+
connectionProvider,
|
|
53
|
+
{
|
|
54
|
+
provide: redis_constants_js_1.IOREDIS_MODULE_TOKEN,
|
|
55
|
+
useValue: crypto.randomUUID()
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
exports: [connectionProvider]
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
async onApplicationShutdown() {
|
|
62
|
+
const client = this.moduleRef.get((0, redis_utils_js_1.getRedisClientToken)(this.options.name));
|
|
63
|
+
if (client)
|
|
64
|
+
await client.quit();
|
|
65
|
+
}
|
|
66
|
+
static createAsyncProviders(asyncOptions) {
|
|
67
|
+
if (asyncOptions.useExisting || asyncOptions.useFactory)
|
|
68
|
+
return [this.createAsyncOptionsProvider(asyncOptions)];
|
|
69
|
+
if (asyncOptions.useClass)
|
|
70
|
+
return [
|
|
71
|
+
this.createAsyncOptionsProvider(asyncOptions),
|
|
72
|
+
{
|
|
73
|
+
provide: asyncOptions.useClass,
|
|
74
|
+
useClass: asyncOptions.useClass
|
|
75
|
+
}
|
|
76
|
+
];
|
|
77
|
+
throw new Error('Invalid configuration. Must provide useFactory, useClass or useExisting');
|
|
78
|
+
}
|
|
79
|
+
static createAsyncOptionsProvider(asyncOptions) {
|
|
80
|
+
if (asyncOptions.useFactory) {
|
|
81
|
+
return {
|
|
82
|
+
provide: redis_constants_js_1.IOREDIS_MODULE_OPTIONS,
|
|
83
|
+
useFactory: asyncOptions.useFactory,
|
|
84
|
+
inject: asyncOptions.inject || []
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const useClass = asyncOptions.useClass || asyncOptions.useExisting;
|
|
88
|
+
if (useClass) {
|
|
89
|
+
return {
|
|
90
|
+
provide: redis_constants_js_1.IOREDIS_MODULE_OPTIONS,
|
|
91
|
+
useFactory: (optionsFactory) => optionsFactory.createOptions(asyncOptions.name),
|
|
92
|
+
inject: [useClass]
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
throw new Error('Invalid configuration. Must provide useFactory, useClass or useExisting');
|
|
96
|
+
}
|
|
97
|
+
static async createClient(options) {
|
|
98
|
+
const client = new redis_client_js_1.RedisClient(options);
|
|
99
|
+
await new Promise((resolve, reject) => {
|
|
100
|
+
client.once('ready', () => {
|
|
101
|
+
client.removeListener('error', reject);
|
|
102
|
+
resolve();
|
|
103
|
+
});
|
|
104
|
+
client.once('error', (e) => {
|
|
105
|
+
client.removeListener('ready', resolve);
|
|
106
|
+
reject(e);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
return client;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
RedisCoreModule = RedisCoreModule_1 = tslib_1.__decorate([
|
|
113
|
+
(0, common_1.Global)(),
|
|
114
|
+
(0, common_1.Module)({}),
|
|
115
|
+
tslib_1.__param(0, (0, common_1.Inject)(redis_constants_js_1.IOREDIS_MODULE_OPTIONS)),
|
|
116
|
+
tslib_1.__metadata("design:paramtypes", [Object, core_1.ModuleRef])
|
|
117
|
+
], RedisCoreModule);
|
|
118
|
+
exports.RedisCoreModule = RedisCoreModule;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IOREDIS_MODULE_TOKEN = exports.IOREDIS_MODULE_OPTIONS = void 0;
|
|
4
|
+
exports.IOREDIS_MODULE_OPTIONS = Symbol('IOREDIS_MODULE_OPTIONS');
|
|
5
|
+
exports.IOREDIS_MODULE_TOKEN = Symbol('IOREDIS_MODULE_ID');
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InjectIORedis = void 0;
|
|
4
|
+
const common_1 = require("@nestjs/common");
|
|
5
|
+
const redis_utils_js_1 = require("./redis.utils.js");
|
|
6
|
+
const InjectIORedis = (name) => (0, common_1.Inject)((0, redis_utils_js_1.getRedisClientToken)(name));
|
|
7
|
+
exports.InjectIORedis = InjectIORedis;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var RedisModule_1;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.RedisModule = void 0;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const common_1 = require("@nestjs/common");
|
|
7
|
+
const redis_core_module_js_1 = require("./redis-core.module.js");
|
|
8
|
+
let RedisModule = RedisModule_1 = class RedisModule {
|
|
9
|
+
static forRoot(options) {
|
|
10
|
+
return {
|
|
11
|
+
module: RedisModule_1,
|
|
12
|
+
imports: [redis_core_module_js_1.RedisCoreModule.forRoot(options)]
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
static forRootAsync(options) {
|
|
16
|
+
return {
|
|
17
|
+
module: RedisModule_1,
|
|
18
|
+
imports: [redis_core_module_js_1.RedisCoreModule.forRootAsync(options)]
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
RedisModule = RedisModule_1 = tslib_1.__decorate([
|
|
23
|
+
(0, common_1.Module)({})
|
|
24
|
+
], RedisModule);
|
|
25
|
+
exports.RedisModule = RedisModule;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getRedisClientToken = void 0;
|
|
4
|
+
const redis_client_js_1 = require("./redis-client.js");
|
|
5
|
+
function getRedisClientToken(name) {
|
|
6
|
+
if (!name)
|
|
7
|
+
return redis_client_js_1.RedisClient;
|
|
8
|
+
if (typeof name === 'symbol' || typeof name === 'function')
|
|
9
|
+
return name;
|
|
10
|
+
return `${name}_RedisClient`;
|
|
11
|
+
}
|
|
12
|
+
exports.getRedisClientToken = getRedisClientToken;
|
package/esm/index.d.ts
ADDED
package/esm/index.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import Redis from 'ioredis';
|
|
2
|
+
export interface LockOptions {
|
|
3
|
+
expire?: number;
|
|
4
|
+
retryInterval?: number;
|
|
5
|
+
maxRetries?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class RedisClient extends Redis {
|
|
8
|
+
lockPrefix?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Try to lock once
|
|
11
|
+
* @param {string} name redis-lock name
|
|
12
|
+
* @param {number} [expire] milliseconds, TTL for the redis key
|
|
13
|
+
* @returns {boolean} true: success, false: failed
|
|
14
|
+
*/
|
|
15
|
+
tryLock(name: any, expire: any): Promise<boolean>;
|
|
16
|
+
/**
|
|
17
|
+
* lock, automatically retrying if failed
|
|
18
|
+
* @param {string} name redis-lock name
|
|
19
|
+
* @param {object} [options] Options
|
|
20
|
+
* @param {number} [options.expire=60000] TTL
|
|
21
|
+
* @param {number} [options.retryInterval=100] milliseconds, the interval to retry if failed
|
|
22
|
+
* @param {number} [options.maxRetries=10] max times to retry
|
|
23
|
+
*/
|
|
24
|
+
lock(name: string, options?: LockOptions): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Unlock a redis-lock by name
|
|
27
|
+
* @param {string} name redis-lock name
|
|
28
|
+
*/
|
|
29
|
+
unlock(name: any): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Set TTL for a redis-lock
|
|
32
|
+
* @param {string} name redis-lock name
|
|
33
|
+
* @param {number} milliseconds TTL
|
|
34
|
+
*/
|
|
35
|
+
setLockTTL(name: any, milliseconds: any): Promise<boolean>;
|
|
36
|
+
private _getLockKey;
|
|
37
|
+
/**
|
|
38
|
+
* @param {number} ms milliseconds, the sleep interval
|
|
39
|
+
*/
|
|
40
|
+
private _sleep;
|
|
41
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import Redis from 'ioredis';
|
|
2
|
+
import { toNumberDef } from 'putil-varhelpers';
|
|
3
|
+
export class RedisClient extends Redis {
|
|
4
|
+
lockPrefix;
|
|
5
|
+
/**
|
|
6
|
+
* Try to lock once
|
|
7
|
+
* @param {string} name redis-lock name
|
|
8
|
+
* @param {number} [expire] milliseconds, TTL for the redis key
|
|
9
|
+
* @returns {boolean} true: success, false: failed
|
|
10
|
+
*/
|
|
11
|
+
async tryLock(name, expire) {
|
|
12
|
+
const result = await this.set(this._getLockKey(name), '_lock_', 'PX', expire, 'NX');
|
|
13
|
+
return result !== null;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* lock, automatically retrying if failed
|
|
17
|
+
* @param {string} name redis-lock name
|
|
18
|
+
* @param {object} [options] Options
|
|
19
|
+
* @param {number} [options.expire=60000] TTL
|
|
20
|
+
* @param {number} [options.retryInterval=100] milliseconds, the interval to retry if failed
|
|
21
|
+
* @param {number} [options.maxRetries=10] max times to retry
|
|
22
|
+
*/
|
|
23
|
+
async lock(name, options) {
|
|
24
|
+
const expire = toNumberDef(options?.expire, 60000);
|
|
25
|
+
const retryInterval = toNumberDef(options?.retryInterval, 100);
|
|
26
|
+
const maxRetries = toNumberDef(options?.maxRetries, 10);
|
|
27
|
+
let retryTimes = 0;
|
|
28
|
+
// eslint-disable-next-line no-constant-condition
|
|
29
|
+
while (1) {
|
|
30
|
+
if (await this.tryLock(name, expire)) {
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
await this._sleep(retryInterval);
|
|
35
|
+
if (retryTimes >= maxRetries) {
|
|
36
|
+
throw new Error(`Redis lock "${name}" timed out`);
|
|
37
|
+
}
|
|
38
|
+
retryTimes++;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Unlock a redis-lock by name
|
|
44
|
+
* @param {string} name redis-lock name
|
|
45
|
+
*/
|
|
46
|
+
async unlock(name) {
|
|
47
|
+
const s = 'if redis.call(\'get\', KEYS[1]) == ARGV[1] then return redis.call(\'del\', KEYS[1]) else return 0 end';
|
|
48
|
+
await this.eval(s, 1, this._getLockKey(name), '_lock_');
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Set TTL for a redis-lock
|
|
52
|
+
* @param {string} name redis-lock name
|
|
53
|
+
* @param {number} milliseconds TTL
|
|
54
|
+
*/
|
|
55
|
+
async setLockTTL(name, milliseconds) {
|
|
56
|
+
const result = await this.pexpire(this._getLockKey(name), milliseconds);
|
|
57
|
+
return !!result;
|
|
58
|
+
}
|
|
59
|
+
_getLockKey(name) {
|
|
60
|
+
return (this.lockPrefix || 'lock:') + name;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* @param {number} ms milliseconds, the sleep interval
|
|
64
|
+
*/
|
|
65
|
+
_sleep(ms) {
|
|
66
|
+
return new Promise(resolve => setTimeout(resolve, Number(ms)));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { DynamicModule, OnApplicationShutdown } from '@nestjs/common';
|
|
2
|
+
import { ModuleRef } from '@nestjs/core';
|
|
3
|
+
import { RedisModuleAsyncOptions, RedisModuleOptions } from './redis.interface.js';
|
|
4
|
+
export declare class RedisCoreModule implements OnApplicationShutdown {
|
|
5
|
+
private readonly options;
|
|
6
|
+
private readonly moduleRef;
|
|
7
|
+
constructor(options: RedisModuleOptions, moduleRef: ModuleRef);
|
|
8
|
+
static forRoot(options?: RedisModuleOptions): DynamicModule;
|
|
9
|
+
static forRootAsync(asyncOptions: RedisModuleAsyncOptions): DynamicModule;
|
|
10
|
+
onApplicationShutdown(): Promise<void>;
|
|
11
|
+
private static createAsyncProviders;
|
|
12
|
+
private static createAsyncOptionsProvider;
|
|
13
|
+
private static createClient;
|
|
14
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
var RedisCoreModule_1;
|
|
2
|
+
import { __decorate, __metadata, __param } from "tslib";
|
|
3
|
+
import * as crypto from 'crypto';
|
|
4
|
+
import { Global, Inject, Module } from '@nestjs/common';
|
|
5
|
+
import { ModuleRef } from '@nestjs/core';
|
|
6
|
+
import { IOREDIS_MODULE_OPTIONS, IOREDIS_MODULE_TOKEN } from './redis.constants.js';
|
|
7
|
+
import { getRedisClientToken } from './redis.utils.js';
|
|
8
|
+
import { RedisClient } from './redis-client.js';
|
|
9
|
+
let RedisCoreModule = RedisCoreModule_1 = class RedisCoreModule {
|
|
10
|
+
options;
|
|
11
|
+
moduleRef;
|
|
12
|
+
constructor(options, moduleRef) {
|
|
13
|
+
this.options = options;
|
|
14
|
+
this.moduleRef = moduleRef;
|
|
15
|
+
}
|
|
16
|
+
static forRoot(options = {}) {
|
|
17
|
+
const optionsProvider = {
|
|
18
|
+
provide: IOREDIS_MODULE_OPTIONS,
|
|
19
|
+
useValue: options
|
|
20
|
+
};
|
|
21
|
+
const connectionProvider = {
|
|
22
|
+
provide: getRedisClientToken(options.name),
|
|
23
|
+
useFactory: () => this.createClient(options)
|
|
24
|
+
};
|
|
25
|
+
return {
|
|
26
|
+
module: RedisCoreModule_1,
|
|
27
|
+
providers: [connectionProvider, optionsProvider],
|
|
28
|
+
exports: [connectionProvider]
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
static forRootAsync(asyncOptions) {
|
|
32
|
+
const connectionProvider = {
|
|
33
|
+
provide: getRedisClientToken(asyncOptions.name),
|
|
34
|
+
inject: [IOREDIS_MODULE_OPTIONS],
|
|
35
|
+
useFactory: async (moduleOptions) => {
|
|
36
|
+
const name = asyncOptions.name || moduleOptions.name;
|
|
37
|
+
return this.createClient({
|
|
38
|
+
...moduleOptions,
|
|
39
|
+
name
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const asyncProviders = this.createAsyncProviders(asyncOptions);
|
|
44
|
+
return {
|
|
45
|
+
module: RedisCoreModule_1,
|
|
46
|
+
imports: asyncOptions.imports,
|
|
47
|
+
providers: [
|
|
48
|
+
...asyncProviders,
|
|
49
|
+
connectionProvider,
|
|
50
|
+
{
|
|
51
|
+
provide: IOREDIS_MODULE_TOKEN,
|
|
52
|
+
useValue: crypto.randomUUID()
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
exports: [connectionProvider]
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
async onApplicationShutdown() {
|
|
59
|
+
const client = this.moduleRef.get(getRedisClientToken(this.options.name));
|
|
60
|
+
if (client)
|
|
61
|
+
await client.quit();
|
|
62
|
+
}
|
|
63
|
+
static createAsyncProviders(asyncOptions) {
|
|
64
|
+
if (asyncOptions.useExisting || asyncOptions.useFactory)
|
|
65
|
+
return [this.createAsyncOptionsProvider(asyncOptions)];
|
|
66
|
+
if (asyncOptions.useClass)
|
|
67
|
+
return [
|
|
68
|
+
this.createAsyncOptionsProvider(asyncOptions),
|
|
69
|
+
{
|
|
70
|
+
provide: asyncOptions.useClass,
|
|
71
|
+
useClass: asyncOptions.useClass
|
|
72
|
+
}
|
|
73
|
+
];
|
|
74
|
+
throw new Error('Invalid configuration. Must provide useFactory, useClass or useExisting');
|
|
75
|
+
}
|
|
76
|
+
static createAsyncOptionsProvider(asyncOptions) {
|
|
77
|
+
if (asyncOptions.useFactory) {
|
|
78
|
+
return {
|
|
79
|
+
provide: IOREDIS_MODULE_OPTIONS,
|
|
80
|
+
useFactory: asyncOptions.useFactory,
|
|
81
|
+
inject: asyncOptions.inject || []
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const useClass = asyncOptions.useClass || asyncOptions.useExisting;
|
|
85
|
+
if (useClass) {
|
|
86
|
+
return {
|
|
87
|
+
provide: IOREDIS_MODULE_OPTIONS,
|
|
88
|
+
useFactory: (optionsFactory) => optionsFactory.createOptions(asyncOptions.name),
|
|
89
|
+
inject: [useClass]
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
throw new Error('Invalid configuration. Must provide useFactory, useClass or useExisting');
|
|
93
|
+
}
|
|
94
|
+
static async createClient(options) {
|
|
95
|
+
const client = new RedisClient(options);
|
|
96
|
+
await new Promise((resolve, reject) => {
|
|
97
|
+
client.once('ready', () => {
|
|
98
|
+
client.removeListener('error', reject);
|
|
99
|
+
resolve();
|
|
100
|
+
});
|
|
101
|
+
client.once('error', (e) => {
|
|
102
|
+
client.removeListener('ready', resolve);
|
|
103
|
+
reject(e);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
return client;
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
RedisCoreModule = RedisCoreModule_1 = __decorate([
|
|
110
|
+
Global(),
|
|
111
|
+
Module({}),
|
|
112
|
+
__param(0, Inject(IOREDIS_MODULE_OPTIONS)),
|
|
113
|
+
__metadata("design:paramtypes", [Object, ModuleRef])
|
|
114
|
+
], RedisCoreModule);
|
|
115
|
+
export { RedisCoreModule };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const InjectIORedis: (name?: string) => ParameterDecorator;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { RedisOptions } from 'ioredis';
|
|
2
|
+
import { Type } from '@nestjs/common';
|
|
3
|
+
import { ModuleMetadata } from '@nestjs/common/interfaces';
|
|
4
|
+
export interface RedisModuleOptions extends RedisOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Connection name
|
|
7
|
+
*/
|
|
8
|
+
name?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface RedisModuleOptionsFactory {
|
|
11
|
+
createOptions(connectionName?: string): Promise<RedisModuleOptions> | RedisModuleOptions;
|
|
12
|
+
}
|
|
13
|
+
export interface RedisModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
|
|
14
|
+
name?: string;
|
|
15
|
+
useExisting?: Type<RedisModuleOptionsFactory>;
|
|
16
|
+
useClass?: Type<RedisModuleOptionsFactory>;
|
|
17
|
+
useFactory?: (...args: any[]) => Promise<RedisModuleOptions> | RedisModuleOptions;
|
|
18
|
+
inject?: any[];
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { DynamicModule } from '@nestjs/common';
|
|
2
|
+
import { RedisModuleAsyncOptions, RedisModuleOptions } from './redis.interface.js';
|
|
3
|
+
export declare class RedisModule {
|
|
4
|
+
static forRoot(options: RedisModuleOptions): DynamicModule;
|
|
5
|
+
static forRootAsync(options: RedisModuleAsyncOptions): DynamicModule;
|
|
6
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
var RedisModule_1;
|
|
2
|
+
import { __decorate } from "tslib";
|
|
3
|
+
import { Module } from '@nestjs/common';
|
|
4
|
+
import { RedisCoreModule } from './redis-core.module.js';
|
|
5
|
+
let RedisModule = RedisModule_1 = class RedisModule {
|
|
6
|
+
static forRoot(options) {
|
|
7
|
+
return {
|
|
8
|
+
module: RedisModule_1,
|
|
9
|
+
imports: [RedisCoreModule.forRoot(options)]
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
static forRootAsync(options) {
|
|
13
|
+
return {
|
|
14
|
+
module: RedisModule_1,
|
|
15
|
+
imports: [RedisCoreModule.forRootAsync(options)]
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
RedisModule = RedisModule_1 = __decorate([
|
|
20
|
+
Module({})
|
|
21
|
+
], RedisModule);
|
|
22
|
+
export { RedisModule };
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xnestjs/ioredis",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "NestJS extension library for ioredis",
|
|
5
|
+
"author": "Panates",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"compile": "tsc",
|
|
9
|
+
"prebuild": "npm run lint && npm run clean",
|
|
10
|
+
"build": "npm run build:cjs && npm run build:esm",
|
|
11
|
+
"build:cjs": "tsc -b tsconfig-build-cjs.json",
|
|
12
|
+
"build:esm": "tsc -b tsconfig-build-esm.json",
|
|
13
|
+
"postbuild": "cp README.md package.json ../../LICENSE ../../build/ioredis && cp ../../package.cjs.json ../../build/ioredis/cjs/package.json",
|
|
14
|
+
"lint": "eslint .",
|
|
15
|
+
"test": "jest",
|
|
16
|
+
"cover": "jest --collect-coverage",
|
|
17
|
+
"clean": "npm run clean:src && npm run clean:dist && npm run clean:cover",
|
|
18
|
+
"clean:src": "ts-cleanup -s src --all",
|
|
19
|
+
"clean:dist": "rimraf ../../build/ioredis",
|
|
20
|
+
"clean:cover": "rimraf ../../coverage/ioredis"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@nestjs/common": "^9.0.11",
|
|
26
|
+
"@nestjs/core": "^9.0.11",
|
|
27
|
+
"@nestjs/testing": "^9.0.11",
|
|
28
|
+
"@types/ioredis": "^4.28.10"
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"@nestjs/common": ">= 7.4.0",
|
|
32
|
+
"ioredis": ">= 5.x.x"
|
|
33
|
+
},
|
|
34
|
+
"type": "module",
|
|
35
|
+
"main": "cjs/index.js",
|
|
36
|
+
"module": "esm/index.js",
|
|
37
|
+
"types": "esm/index.d.ts",
|
|
38
|
+
"exports": {
|
|
39
|
+
".": {
|
|
40
|
+
"require": "./cjs/index.js",
|
|
41
|
+
"default": "./esm/index.js"
|
|
42
|
+
},
|
|
43
|
+
"./cjs": "./cjs/index.js",
|
|
44
|
+
"./esm": "./esm/index.js"
|
|
45
|
+
},
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=16.0",
|
|
48
|
+
"npm": ">=7.0.0"
|
|
49
|
+
},
|
|
50
|
+
"files": [
|
|
51
|
+
"bin/",
|
|
52
|
+
"cjs/",
|
|
53
|
+
"esm/",
|
|
54
|
+
"LICENSE",
|
|
55
|
+
"README.md"
|
|
56
|
+
],
|
|
57
|
+
"keywords": [
|
|
58
|
+
"nestjs",
|
|
59
|
+
"ioredis",
|
|
60
|
+
"redis"
|
|
61
|
+
]
|
|
62
|
+
}
|