@samet-it/be-redis-common 1.1.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 ADDED
@@ -0,0 +1,24 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Samet Global
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
+
23
+ Web: https://sametglobal.com
24
+ Responsible: Mustafa Yelmer (mustafay@samet.com.tr)
package/README.md ADDED
@@ -0,0 +1,89 @@
1
+ # Samet IT : Redis Common
2
+ `ts` `component` `backend`
3
+ ```
4
+ ___
5
+ ________ ____/ (______ _________ ____ ___ ____ ___ ____ ____
6
+ / ___/ _ \/ __ / / ___/ / ___/ __ \/ __ `__ \/ __ `__ \/ __ \/ __ \
7
+ / / / __/ /_/ / (__ ) / /__/ /_/ / / / / / / / / / / / /_/ / / / /
8
+ /_/ \___/\__,_/_/____/ \___/\____/_/ /_/ /_/_/ /_/ /_/\____/_/ /_/
9
+ ```
10
+ <!-- https://patorjk.com/software/taag/#p=display&f=Slant&t=redis+common&x=none&v=4&h=3&w=80&we=false -->
11
+ - `EN`: Use it for redis connections
12
+ - `TR`: Redis (cache) bağlantıları için bu bileşeni kullanınız
13
+
14
+ ## Prerequisite
15
+ - [Help](https://github.com/samet-digital/help)
16
+ - [1 - Install Git](https://github.com/samet-digital/help/blob/main//install-git.MD)
17
+ - [2 - Build Up a Git Connection](https://github.com/samet-digital/help/blob/main//build-git-connection.MD)
18
+ - [3 - Install Node/NPM](https://github.com/samet-digital/help/blob/main//install-npm.MD)
19
+ - [4 - Create Project Folder](https://github.com/samet-digital/help/blob/main//create-project-folder.MD)
20
+ - [5 - Bind Projects Folder to Git](https://github.com/samet-digital/help/blob/main//bind-project-folder.MD)
21
+
22
+ ## Usage
23
+ - `EN`: How to add into your project?
24
+ - `TR`: Projene nasıl eklersin?
25
+
26
+ ```shell
27
+ npm i @samet-it/be-redis-common
28
+ ```
29
+
30
+ ## Environments
31
+ - [RedisCommonConf](./src/config/redis-common.config.ts)
32
+
33
+ | Name | Type | Default | Required | Secret | Description |
34
+ |-------------------|---------|---------|----------|--------|--------------------------|
35
+ | `REDIS_HOST` | string | | ✅ | ⭕ | Redis Host or IP Address |
36
+ | `REDIS_PORT` | integer | _6379_ | ✅ | ⭕ | Redis port |
37
+ | `REDIS_USER` | string | | | ⭕ | Redis User |
38
+ | `REDIS_PASS` | string | | | ⭕ | Redis Password |
39
+ | `REDIS_PREFIX` | string | | | | Prefix for keys |
40
+ | `REDIS_DB_NUMBER` | integer | | | | Redis DB number |
41
+
42
+ ## Contents
43
+ - `abstract` [RedisConnection](src/connection/redis.connection.ts) - abstract connection class
44
+ - `class` [RedisDirectConnection](src/connection/redis-direct.connection.ts) - Direct connection class
45
+ - `function` [redisConnection()](src/connection/redis-connection.fn.ts) - Direct connection function
46
+ - `abstract` [RedisChannel](src/channel/redis.channel.ts) - abstract repository
47
+ - `class` [RedisDirectChannel](src/channel/redis-direct.channel.ts) - direct repository
48
+
49
+
50
+ ## Development
51
+ > You can start to develop on it
52
+ >
53
+ ### Step 1
54
+ - [Go to project folder](https://github.com/samet-digital/help/blob/main/go-to-project-folder.MD)
55
+
56
+ ### Step 2
57
+ - `EN`: Clone the project
58
+ - `TR`: Projeyi bilgisiyarına çek
59
+ ```shell
60
+ git clone https://github.com/samet-digital/be-redis-common.git -b development
61
+ ```
62
+
63
+ ## Dependencies
64
+ - `@samet-it/be-base-common`: **samet** base common
65
+ - `@samet-it/be-cache-common`: **samet** cache common
66
+ - `@leyyo/*`: leyyo utilities
67
+ - `@nestjs/*`: nestjs framework
68
+ - `redis`: redis client
69
+
70
+ ## Commands
71
+ - [Component Commands](https://github.com/samet-digital/help/blob/main/commands-component.MD)
72
+
73
+ ## Standards
74
+ ```diff
75
+ + language: TS
76
+ + lint: eslint
77
+ + inspections: intelli-j code inspections
78
+ + ddd: domain driven development
79
+ + edd: exception driven development
80
+ ! tdd: test driven development
81
+ + ldd: log driven development
82
+ + ddd: document driven development
83
+ ```
84
+
85
+ ## History
86
+ | Date | Developer | Info | Ticket |
87
+ |------------|----------------|--------------|-------------------------|
88
+ | 2025-08-13 | Mustafa Yelmer | _Created_ | ~~[none](./README.md)~~ |
89
+ | 2026-01-11 | Mustafa Yelmer | _Refactored_ | ~~[none](./README.md)~~ |
File without changes
@@ -0,0 +1,3 @@
1
+ export * from './index.types';
2
+ export * from './redis.channel';
3
+ export * from './redis-direct.channel';
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./index.types"), exports);
18
+ __exportStar(require("./redis.channel"), exports);
19
+ __exportStar(require("./redis-direct.channel"), exports);
@@ -0,0 +1,39 @@
1
+ import type { RedisConnectionLike } from "../connection";
2
+ import type { CacheChannelProps, CacheChannelLike, CacheChannelOpt } from "@samet-it/be-cache-common";
3
+ import type { Entity } from "@samet-it/be-base-common";
4
+ import type { RedisClientType } from "redis";
5
+ import type { KeyValue } from "@leyyo/common";
6
+ /**
7
+ * Redis channel interface
8
+ * */
9
+ export interface RedisChannelLike<ID extends KeyValue, ENTITY extends Entity<ID>> extends CacheChannelLike<RedisConnectionLike, ID, ENTITY> {
10
+ /** @inheritDoc */
11
+ get props(): Readonly<RedisChannelProps>;
12
+ }
13
+ /**
14
+ * Redis channel option
15
+ * */
16
+ export interface RedisChannelOpt extends CacheChannelOpt {
17
+ }
18
+ /**
19
+ * Redis channel props
20
+ * */
21
+ export interface RedisChannelProps extends CacheChannelProps<RedisConnectionLike>, RedisChannelOpt {
22
+ /**
23
+ * Redis client
24
+ *
25
+ * @type {RedisClientType}
26
+ * */
27
+ client: RedisClientType;
28
+ }
29
+ /**
30
+ * Redis direct channel options
31
+ * */
32
+ export interface RedisDirectChannelOpt extends RedisChannelOpt {
33
+ /**
34
+ * Name for logger
35
+ *
36
+ * @type {string}
37
+ * */
38
+ name?: string;
39
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,17 @@
1
+ import { RedisChannel } from "./redis.channel";
2
+ import { type Entity } from "@samet-it/be-base-common";
3
+ import type { RedisConnectionLike } from "../connection";
4
+ import type { RedisDirectChannelOpt } from "./index.types";
5
+ import type { KeyValue } from "@leyyo/common";
6
+ /**
7
+ * Redis direct channel class
8
+ * */
9
+ export declare class RedisDirectChannel<ID extends KeyValue, ENTITY extends Entity<ID>> extends RedisChannel<ID, ENTITY> {
10
+ /**
11
+ * Constructor
12
+ *
13
+ * @param {RedisConnectionLike} conn - connection
14
+ * @param {RedisDirectChannelOpt?} opt - direct options
15
+ * */
16
+ constructor(conn: RedisConnectionLike, opt?: RedisDirectChannelOpt);
17
+ }
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RedisDirectChannel = void 0;
4
+ const redis_channel_1 = require("./redis.channel");
5
+ const be_base_common_1 = require("@samet-it/be-base-common");
6
+ /**
7
+ * Redis direct channel class
8
+ * */
9
+ class RedisDirectChannel extends redis_channel_1.RedisChannel {
10
+ /**
11
+ * Constructor
12
+ *
13
+ * @param {RedisConnectionLike} conn - connection
14
+ * @param {RedisDirectChannelOpt?} opt - direct options
15
+ * */
16
+ constructor(conn, opt) {
17
+ super(conn, opt);
18
+ this.logger = be_base_common_1.logger.of(`RedisDirect${opt.name ? '#' + opt.name : ''}`);
19
+ }
20
+ }
21
+ exports.RedisDirectChannel = RedisDirectChannel;
@@ -0,0 +1,28 @@
1
+ import type { RedisConnectionLike } from "../connection";
2
+ import type { RedisChannelProps, RedisChannelLike, RedisChannelOpt } from "./index.types";
3
+ import { type Entity } from "@samet-it/be-base-common";
4
+ import { CacheChannel } from "@samet-it/be-cache-common";
5
+ import type { KeyValue, Opt } from "@leyyo/common";
6
+ /**
7
+ * Redis abstract channel class
8
+ * */
9
+ export declare abstract class RedisChannel<ID extends KeyValue, ENTITY extends Entity<ID>> extends CacheChannel<RedisConnectionLike, ID, ENTITY> implements RedisChannelLike<ID, ENTITY> {
10
+ /** @inheritDoc */
11
+ protected _props: RedisChannelProps;
12
+ protected constructor(conn: RedisConnectionLike, opt?: RedisChannelOpt);
13
+ protected _checkError(e: Error, opt?: Opt): void;
14
+ /** @inheritDoc */
15
+ get props(): Readonly<RedisChannelProps>;
16
+ /** @inheritDoc */
17
+ $get(...paths: Array<string>): Promise<Array<string>>;
18
+ /** @inheritDoc */
19
+ $set(map: Record<string, string>): Promise<number>;
20
+ /** @inheritDoc */
21
+ $delete(...paths: string[]): Promise<number>;
22
+ /** @inheritDoc */
23
+ $addLinks(idPath: string, paths: string): Promise<number>;
24
+ /** @inheritDoc */
25
+ $expire(path: string, seconds: number): Promise<boolean>;
26
+ /** @inheritDoc */
27
+ $getLinks(idPath: string): Promise<Array<string>>;
28
+ }
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.RedisChannel = void 0;
13
+ const be_base_common_1 = require("@samet-it/be-base-common");
14
+ const be_cache_common_1 = require("@samet-it/be-cache-common");
15
+ // noinspection JSUnusedGlobalSymbols
16
+ /**
17
+ * Redis abstract channel class
18
+ * */
19
+ class RedisChannel extends be_cache_common_1.CacheChannel {
20
+ // endregion protected-property
21
+ constructor(conn, opt) {
22
+ super(conn, opt);
23
+ conn.onFirstConnected(() => __awaiter(this, void 0, void 0, function* () {
24
+ this._props.client = conn.props.client;
25
+ this._props.isConnected = true;
26
+ }));
27
+ conn.onConnected(() => __awaiter(this, void 0, void 0, function* () {
28
+ this._props.client = conn.props.client;
29
+ this._props.isConnected = true;
30
+ }));
31
+ conn.onDisconnected(() => __awaiter(this, void 0, void 0, function* () {
32
+ this._props.client = undefined;
33
+ this._props.isConnected = false;
34
+ }));
35
+ }
36
+ _checkError(e, opt) {
37
+ be_base_common_1.errorHandler.addStat(e);
38
+ if (e instanceof be_cache_common_1.CacheError) {
39
+ // todo append params
40
+ throw e;
41
+ }
42
+ else {
43
+ throw be_base_common_1.errorHandler.common.castForClass(be_cache_common_1.CacheError, e, opt);
44
+ }
45
+ }
46
+ // region getter
47
+ /** @inheritDoc */
48
+ get props() {
49
+ return this._props;
50
+ }
51
+ // endregion getter
52
+ // region native-calls
53
+ /** @inheritDoc */
54
+ $get(...paths) {
55
+ return __awaiter(this, void 0, void 0, function* () {
56
+ const { client } = this._props;
57
+ if (!client) {
58
+ return [];
59
+ }
60
+ if (paths.length < 1) {
61
+ return [];
62
+ }
63
+ if (paths.length == 1) {
64
+ const rec = (yield client.get(paths[0]));
65
+ return rec ? [rec] : [];
66
+ }
67
+ try {
68
+ return (yield client.mGet(paths));
69
+ }
70
+ catch (e) {
71
+ this._checkError(e, { redis: 'MGET' });
72
+ }
73
+ });
74
+ }
75
+ /** @inheritDoc */
76
+ $set(map) {
77
+ return __awaiter(this, void 0, void 0, function* () {
78
+ const { client } = this._props;
79
+ if (!client) {
80
+ return 0;
81
+ }
82
+ if (!map || typeof map !== 'object' || Array.isArray(map)) {
83
+ return 0;
84
+ }
85
+ const keys = Object.keys(map);
86
+ switch (keys.length) {
87
+ case 0:
88
+ return 0;
89
+ case 1:
90
+ const key = keys[0];
91
+ try {
92
+ yield client.set(key, map[key]);
93
+ }
94
+ catch (e) {
95
+ this._checkError(e, { redis: 'SET' });
96
+ }
97
+ return 1;
98
+ default:
99
+ try {
100
+ yield client.mSet(map);
101
+ }
102
+ catch (e) {
103
+ this._checkError(e, { redis: 'MSET' });
104
+ }
105
+ return keys.length;
106
+ }
107
+ });
108
+ }
109
+ /** @inheritDoc */
110
+ $delete(...paths) {
111
+ return __awaiter(this, void 0, void 0, function* () {
112
+ const { client } = this._props;
113
+ if (!client) {
114
+ return 0;
115
+ }
116
+ if (paths.length < 1) {
117
+ return 0;
118
+ }
119
+ try {
120
+ yield client.del(paths);
121
+ }
122
+ catch (e) {
123
+ this._checkError(e, { redis: 'DEL' });
124
+ }
125
+ return paths.length;
126
+ });
127
+ }
128
+ /** @inheritDoc */
129
+ $addLinks(idPath, paths) {
130
+ return __awaiter(this, void 0, void 0, function* () {
131
+ const { client } = this._props;
132
+ if (!client) {
133
+ return 0;
134
+ }
135
+ if (paths.length < 1) {
136
+ return 0;
137
+ }
138
+ try {
139
+ yield client.sAdd(idPath, paths);
140
+ }
141
+ catch (e) {
142
+ this._checkError(e, { redis: 'SADD' });
143
+ }
144
+ return paths.length;
145
+ });
146
+ }
147
+ /** @inheritDoc */
148
+ $expire(path, seconds) {
149
+ return __awaiter(this, void 0, void 0, function* () {
150
+ const { client } = this._props;
151
+ if (!client) {
152
+ return false;
153
+ }
154
+ try {
155
+ return (yield client.expire(path, seconds)) > 0;
156
+ }
157
+ catch (e) {
158
+ this._checkError(e, { redis: 'EXPIRE' });
159
+ }
160
+ });
161
+ }
162
+ /** @inheritDoc */
163
+ $getLinks(idPath) {
164
+ return __awaiter(this, void 0, void 0, function* () {
165
+ var _a;
166
+ const { client } = this._props;
167
+ if (!client) {
168
+ return [];
169
+ }
170
+ try {
171
+ return (_a = (yield client.sMembers(idPath))) !== null && _a !== void 0 ? _a : [];
172
+ }
173
+ catch (e) {
174
+ this._checkError(e, { redis: 'SMEMBERS' });
175
+ }
176
+ });
177
+ }
178
+ }
179
+ exports.RedisChannel = RedisChannel;
@@ -0,0 +1,2 @@
1
+ export * from './redis-common.config';
2
+ export * from './index.types';
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./redis-common.config"), exports);
18
+ __exportStar(require("./index.types"), exports);
@@ -0,0 +1,31 @@
1
+ import type { EnvBase } from "@leyyo/env";
2
+ export interface RedisCommonConf extends EnvBase {
3
+ /**
4
+ * Redis Protocol
5
+ * */
6
+ readonly PROTOCOL: string;
7
+ /**
8
+ * Redis Host
9
+ * */
10
+ readonly HOST: string;
11
+ /**
12
+ * Redis Port
13
+ * */
14
+ readonly PORT: number;
15
+ /**
16
+ * DB User
17
+ * */
18
+ readonly USER: string;
19
+ /**
20
+ * DB Password
21
+ * */
22
+ readonly PASS: string;
23
+ /**
24
+ * Redis prefix for keys
25
+ * */
26
+ readonly PREFIX: string;
27
+ /**
28
+ * Redis DB number
29
+ * */
30
+ readonly DB_NUMBER: number;
31
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,5 @@
1
+ import type { RedisCommonConf } from "./index.types";
2
+ /**
3
+ * Redis common config
4
+ * */
5
+ export declare const redisCommonConfig: import("@leyyo/env").EnvScopeRuntime<RedisCommonConf, "REDIS", undefined>;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.redisCommonConfig = void 0;
4
+ const env_1 = require("@leyyo/env");
5
+ /**
6
+ * Redis common config
7
+ * */
8
+ exports.redisCommonConfig = env_1.envCore.configure
9
+ .scope('RedisCommon', 'REDIS')
10
+ .start()
11
+ .field('PROTOCOL').text().def('redis').end()
12
+ .field('HOST').text().required().end()
13
+ .field('PORT').integer().def(6379).end()
14
+ .field('USER').text().end()
15
+ .field('PASS').text().end()
16
+ .field('PREFIX').text().end()
17
+ .field('DB_NUMBER').integer().end()
18
+ .finish();
@@ -0,0 +1,4 @@
1
+ export * from './index.types';
2
+ export * from './redis.connection';
3
+ export * from './redis-direct.connection';
4
+ export * from './redis-connection.fn';
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./index.types"), exports);
18
+ __exportStar(require("./redis.connection"), exports);
19
+ __exportStar(require("./redis-direct.connection"), exports);
20
+ __exportStar(require("./redis-connection.fn"), exports);
@@ -0,0 +1,74 @@
1
+ import type { CacheConnectionLike, CacheConnOpt, CacheExecOpt } from "@samet-it/be-cache-common";
2
+ import type { RedisClientType } from "redis";
3
+ import type { Entity } from "@samet-it/be-base-common";
4
+ import type { RedisDirectChannelOpt, RedisChannelLike } from "../channel";
5
+ import type { CacheConnProps } from "@samet-it/be-cache-common";
6
+ import { KeyValue } from "@leyyo/common";
7
+ /**
8
+ * Redis connection interface
9
+ * */
10
+ export interface RedisConnectionLike extends CacheConnectionLike<RedisExecOpt> {
11
+ /** @inheritDoc */
12
+ get props(): Readonly<RedisConnProps>;
13
+ }
14
+ /**
15
+ * Redis direct connection interface
16
+ * */
17
+ export interface RedisDirectConnectionLike extends RedisConnectionLike {
18
+ /**
19
+ * Create new channel
20
+ *
21
+ * @param {RedisDirectChannelOpt?} opt - direct channel options
22
+ * @return {RedisChannelLike<Entity>} - new channel
23
+ * */
24
+ newChannel<ID extends KeyValue, ENTITY extends Entity<ID>>(opt?: RedisDirectChannelOpt): RedisChannelLike<ID, ENTITY>;
25
+ }
26
+ /**
27
+ * Redis connection option
28
+ * */
29
+ export interface RedisConnOpt extends CacheConnOpt {
30
+ /**
31
+ * Redis DB number
32
+ *
33
+ * @type {number}
34
+ * */
35
+ dbNumber?: number;
36
+ }
37
+ /**
38
+ * Redis direct connection option
39
+ * */
40
+ export interface RedisConnDirectOpt extends RedisConnOpt {
41
+ /**
42
+ * logger name
43
+ *
44
+ * @type {string}
45
+ * */
46
+ name?: string;
47
+ }
48
+ /**
49
+ * Redis connection props
50
+ * */
51
+ export interface RedisConnProps extends CacheConnProps, RedisConnOpt {
52
+ /**
53
+ * Redis client
54
+ *
55
+ * @type {RedisClientType}
56
+ * */
57
+ client: RedisClientType;
58
+ /**
59
+ * Connection try count
60
+ *
61
+ * @type {number}
62
+ * */
63
+ tryCount: number;
64
+ /**
65
+ * Connection url
66
+ *
67
+ * @type {string}
68
+ * */
69
+ producedUrl: string;
70
+ }
71
+ /**
72
+ * Redis query option
73
+ * */
74
+ export type RedisExecOpt = CacheExecOpt;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,8 @@
1
+ import type { RedisConnDirectOpt, RedisDirectConnectionLike } from "./index.types";
2
+ /**
3
+ * Crete new redis connection
4
+ *
5
+ * @param {RedisConnDirectOpt} opt - option
6
+ * @return {RedisDirectConnectionLike} - new redis connection
7
+ * */
8
+ export declare function redisConnection(opt?: RedisConnDirectOpt): RedisDirectConnectionLike;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.redisConnection = redisConnection;
4
+ const redis_direct_connection_1 = require("./redis-direct.connection");
5
+ // noinspection JSUnusedGlobalSymbols
6
+ /**
7
+ * Crete new redis connection
8
+ *
9
+ * @param {RedisConnDirectOpt} opt - option
10
+ * @return {RedisDirectConnectionLike} - new redis connection
11
+ * */
12
+ function redisConnection(opt) {
13
+ return new redis_direct_connection_1.RedisDirectConnection(opt);
14
+ }
@@ -0,0 +1,18 @@
1
+ import { RedisConnection } from "./redis.connection";
2
+ import { type Entity } from "@samet-it/be-base-common";
3
+ import { type RedisDirectChannelOpt, type RedisChannelLike } from "../channel";
4
+ import type { RedisConnDirectOpt, RedisDirectConnectionLike } from "./index.types";
5
+ import type { KeyValue } from "@leyyo/common";
6
+ /**
7
+ * Redis connection direct class
8
+ * */
9
+ export declare class RedisDirectConnection extends RedisConnection implements RedisDirectConnectionLike {
10
+ /**
11
+ * Constructor
12
+ *
13
+ * @param {RedisConnDirectOpt} opt - options
14
+ * */
15
+ constructor(opt?: RedisConnDirectOpt);
16
+ /** @inheritDoc */
17
+ newChannel<ID extends KeyValue, ENTITY extends Entity<ID>>(opt?: RedisDirectChannelOpt): RedisChannelLike<ID, ENTITY>;
18
+ }
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RedisDirectConnection = void 0;
4
+ const redis_connection_1 = require("./redis.connection");
5
+ const be_base_common_1 = require("@samet-it/be-base-common");
6
+ const channel_1 = require("../channel");
7
+ /**
8
+ * Redis connection direct class
9
+ * */
10
+ class RedisDirectConnection extends redis_connection_1.RedisConnection {
11
+ /**
12
+ * Constructor
13
+ *
14
+ * @param {RedisConnDirectOpt} opt - options
15
+ * */
16
+ constructor(opt) {
17
+ super(opt);
18
+ this.logger = be_base_common_1.logger.of(`RedisConnection${(opt === null || opt === void 0 ? void 0 : opt.name) ? '#' + (opt === null || opt === void 0 ? void 0 : opt.name) : ''}`);
19
+ }
20
+ /** @inheritDoc */
21
+ newChannel(opt) {
22
+ return new channel_1.RedisDirectChannel(this, opt);
23
+ }
24
+ }
25
+ exports.RedisDirectConnection = RedisDirectConnection;
@@ -0,0 +1,48 @@
1
+ import type { RedisConnectionLike, RedisExecOpt, RedisConnProps, RedisConnOpt } from "./index.types";
2
+ import { CacheConnection } from "@samet-it/be-cache-common";
3
+ /**
4
+ * Redis connection abstract class
5
+ * */
6
+ export declare abstract class RedisConnection extends CacheConnection<RedisExecOpt> implements RedisConnectionLike {
7
+ /**
8
+ * Base/starting/min delay
9
+ *
10
+ * @type {number} - as seconds
11
+ * */
12
+ private static readonly BASE_DELAY;
13
+ /**
14
+ * Last/max delay
15
+ *
16
+ * @type {number} - as seconds
17
+ * */
18
+ private static readonly MAX_DELAY;
19
+ /**
20
+ * Try count
21
+ *
22
+ * @type {number} - times
23
+ * */
24
+ private static readonly TRY_COUNT;
25
+ /** {@inheritDoc} */
26
+ protected _props: RedisConnProps;
27
+ protected constructor(opt?: RedisConnOpt);
28
+ /** @inheritDoc */
29
+ get props(): Readonly<RedisConnProps>;
30
+ /**
31
+ * Read credentials from environment
32
+ * */
33
+ protected _readFromEnv(): void;
34
+ /**
35
+ * Build url from credentials
36
+ * */
37
+ protected _buildUrl(): void;
38
+ /**
39
+ * Generate next delay time with exponential & randomized manner
40
+ *
41
+ * @return {number}
42
+ * */
43
+ protected _delayWithJitter(): number;
44
+ /** {@inheritDoc} */
45
+ connect(): Promise<boolean>;
46
+ /** {@inheritDoc} */
47
+ ping(next?: boolean): Promise<boolean>;
48
+ }
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.RedisConnection = void 0;
46
+ const redis = __importStar(require("redis"));
47
+ const config_1 = require("../config");
48
+ const be_cache_common_1 = require("@samet-it/be-cache-common");
49
+ /**
50
+ * Redis connection abstract class
51
+ * */
52
+ class RedisConnection extends be_cache_common_1.CacheConnection {
53
+ // endregion protected-property
54
+ constructor(opt) {
55
+ super(opt);
56
+ this._props.tryCount = 0;
57
+ this._readFromEnv();
58
+ this._buildUrl();
59
+ }
60
+ // region getter
61
+ /** @inheritDoc */
62
+ get props() {
63
+ return this._props;
64
+ }
65
+ // endregion getter
66
+ // region protected-method
67
+ /**
68
+ * Read credentials from environment
69
+ * */
70
+ _readFromEnv() {
71
+ var _a, _b, _c, _d, _e, _f;
72
+ const { _props: props } = this;
73
+ let env = config_1.redisCommonConfig.valueShort;
74
+ if (props.envVariant) {
75
+ env = config_1.redisCommonConfig.configure.getVariation(props.envVariant).valueShort;
76
+ }
77
+ this._props.protocol = (_a = this._props.protocol) !== null && _a !== void 0 ? _a : env.PROTOCOL;
78
+ this._props.host = (_b = this._props.host) !== null && _b !== void 0 ? _b : env.HOST;
79
+ this._props.port = (_c = this._props.port) !== null && _c !== void 0 ? _c : env.PORT;
80
+ this._props.username = (_d = this._props.username) !== null && _d !== void 0 ? _d : env.USER;
81
+ this._props.password = (_e = this._props.password) !== null && _e !== void 0 ? _e : env.PASS;
82
+ this._props.dbNumber = (_f = this._props.dbNumber) !== null && _f !== void 0 ? _f : env.DB_NUMBER;
83
+ }
84
+ /**
85
+ * Build url from credentials
86
+ * */
87
+ _buildUrl() {
88
+ const { username, password, dbNumber, port, host, protocol } = this._props;
89
+ let _secure = '';
90
+ if (username) {
91
+ _secure = username;
92
+ if (password) {
93
+ _secure += ':' + password;
94
+ }
95
+ _secure += '@';
96
+ }
97
+ let _db = '';
98
+ if (dbNumber !== undefined) {
99
+ _db = '/' + dbNumber;
100
+ }
101
+ let _port = '';
102
+ if (port !== undefined) {
103
+ _port = ':' + port;
104
+ }
105
+ this._props.producedUrl = `${protocol}://${_secure}${host}${_port}${_db}`;
106
+ }
107
+ /**
108
+ * Generate next delay time with exponential & randomized manner
109
+ *
110
+ * @return {number}
111
+ * */
112
+ _delayWithJitter() {
113
+ const exp = Math.min(RedisConnection.BASE_DELAY * Math.pow(2, this._props.tryCount), RedisConnection.MAX_DELAY);
114
+ return exp / 2 + Math.random() * (exp / 2);
115
+ }
116
+ // endregion protected-method
117
+ // region connect
118
+ /** {@inheritDoc} */
119
+ connect() {
120
+ return __awaiter(this, void 0, void 0, function* () {
121
+ if (this._props.isConnected) {
122
+ return true;
123
+ }
124
+ if (this._props.tryCount > RedisConnection.TRY_COUNT) {
125
+ this.logger.error(`on[error/*], maximum try`);
126
+ return false;
127
+ }
128
+ try {
129
+ this._props.client = redis.createClient({ url: this._props.producedUrl });
130
+ this._props.client
131
+ .on("error", err => {
132
+ this.checkError(err, { silent: true, name: 'connection' });
133
+ this._props.tryCount++;
134
+ const old = this._props.isConnected;
135
+ this._props.isConnected = false;
136
+ if (old) {
137
+ this._triggerOnCase('disconnected', this._onDisconnected, false);
138
+ }
139
+ setTimeout(() => this.connect().then(), this._delayWithJitter());
140
+ })
141
+ .on('connect', () => {
142
+ this.logger.info(`on[connect]`);
143
+ this._props.isConnected = true;
144
+ this._props.tryCount = 0;
145
+ this._triggerOnCase('connected', this._onConnected, false);
146
+ if (this._props.isFirst === undefined) {
147
+ this._triggerOnCase('first-connected', this._onFirstConnected, true);
148
+ this._props.isFirst = false;
149
+ }
150
+ })
151
+ .on('ready', () => this.logger.info('on[ready]'))
152
+ .on('close', () => this.logger.info('on[close]'))
153
+ .on('reconnecting', () => this.logger.info('on[reconnecting]'))
154
+ .on('end', () => this.logger.info('on[end]'));
155
+ yield this._props.client.connect();
156
+ this.logger.log('Connected');
157
+ setTimeout(() => this.ping(true).then(), 30000);
158
+ }
159
+ catch (e) {
160
+ this.checkError(e, { name: 'connection' });
161
+ }
162
+ return true;
163
+ });
164
+ }
165
+ /** {@inheritDoc} */
166
+ ping(next) {
167
+ return __awaiter(this, void 0, void 0, function* () {
168
+ // this._props.client.destroy()
169
+ let result = false;
170
+ if (this._props.isConnected) {
171
+ try {
172
+ yield this._props.client.ping();
173
+ result = true;
174
+ }
175
+ catch (err) {
176
+ this.checkError(err, { silent: true, name: 'ping' });
177
+ }
178
+ }
179
+ if (next) {
180
+ setTimeout(() => this.ping(true).then(), 30000);
181
+ }
182
+ return result;
183
+ });
184
+ }
185
+ }
186
+ exports.RedisConnection = RedisConnection;
187
+ // region private-property
188
+ /**
189
+ * Base/starting/min delay
190
+ *
191
+ * @type {number} - as seconds
192
+ * */
193
+ RedisConnection.BASE_DELAY = 500; // 0.5 sec
194
+ /**
195
+ * Last/max delay
196
+ *
197
+ * @type {number} - as seconds
198
+ * */
199
+ RedisConnection.MAX_DELAY = 1000 * 60 * 60; // 1 hour
200
+ /**
201
+ * Try count
202
+ *
203
+ * @type {number} - times
204
+ * */
205
+ RedisConnection.TRY_COUNT = 100; // 100 times
@@ -0,0 +1,3 @@
1
+ export * from './connection';
2
+ export * from './config';
3
+ export * from './channel';
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./connection"), exports);
18
+ __exportStar(require("./config"), exports);
19
+ __exportStar(require("./channel"), exports);
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "@samet-it/be-redis-common",
3
+ "version": "1.1.1",
4
+ "description": "Redis common component",
5
+ "keywords": [
6
+ "redis",
7
+ "cache"
8
+ ],
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/samet-digital/be-redis-common.git"
12
+ },
13
+ "bugs": {
14
+ "email": "mustafay@samet.com.tr",
15
+ "url": "https://https://github.com/samet-digital/be-redis-common/issues"
16
+ },
17
+ "homepage": "https://https://github.com/samet-digital/be-redis-common#readme",
18
+ "author": {
19
+ "name": "Mustafa Yelmer",
20
+ "email": "mustafay@samet.com.tr"
21
+ },
22
+ "main": "dist/index.js",
23
+ "type": "commonjs",
24
+ "scripts": {
25
+ "clear": "rimraf dist && rimraf coverage",
26
+ "clear:nm": "rimraf node_modules && npm run clear",
27
+ "lint": "eslint src/**/*.ts --quiet",
28
+ "lint:verbose": "eslint src/**/*.ts",
29
+ "asset": "node -r ts-node/register commands/assets.ts",
30
+ "build": "npm run clear && tsc && npm run asset",
31
+ "test": "jest --config=jest.json --detectOpenHandles",
32
+ "coverage": "rimraf coverage && jest --config=jest.json --coverage --coverageDirectory=coverage",
33
+ "sample": "node -r ts-node/register src/sample.ts",
34
+ "publish:public": "npm run build && npm publish -access=public"
35
+ },
36
+ "files": [
37
+ "dist/*"
38
+ ],
39
+ "license": "ISC",
40
+ "devDependencies": {
41
+ "@babel/preset-env": "^7.28.0",
42
+ "@babel/preset-typescript": "^7.27.1",
43
+ "@eslint/js": "^9.33.0",
44
+ "@types/jest": "^30.0.0",
45
+ "@types/node": "^24.2.1",
46
+ "@typescript-eslint/eslint-plugin": "^8.39.1",
47
+ "@typescript-eslint/parser": "^8.39.1",
48
+ "eslint": "^9.33.0",
49
+ "eslint-config-prettier": "^10.1.8",
50
+ "eslint-config-standard": "^17.1.0",
51
+ "eslint-plugin-import": "^2.32.0",
52
+ "eslint-plugin-jsdoc": "^54.0.0",
53
+ "eslint-plugin-node": "^11.1.0",
54
+ "husky": "^9.1.7",
55
+ "jest": "^29.7.0",
56
+ "prettier": "^3.6.2",
57
+ "rimraf": "^6.0.1",
58
+ "test": "^3.3.0",
59
+ "ts-jest": "^29.4.1",
60
+ "ts-node": "^10.9.2",
61
+ "typescript": "^5.9.2",
62
+ "typescript-eslint": "^8.39.1"
63
+ },
64
+ "overrides": {
65
+ "eslint-config-standard": {
66
+ "eslint": "^9.33.0"
67
+ }
68
+ },
69
+ "dependencies": {
70
+ "@leyyo/common": "^1.2.1",
71
+ "@leyyo/env": "^1.2.1",
72
+ "@samet-it/be-base-common": "^1.1.1",
73
+ "@samet-it/be-cache-common": "^1.1.1",
74
+ "redis": "^5.10.0"
75
+ }
76
+ }