@bymax-one/nest-cache 1.0.0

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.
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+
3
+ // src/shared/constants/error-codes.ts
4
+ var CACHE_ERROR_CODES = {
5
+ CONNECTION_FAILED: "cache.connection_failed",
6
+ COMMAND_TIMEOUT: "cache.command_timeout",
7
+ CONNECTION_LOST: "cache.connection_lost",
8
+ SERIALIZATION_FAILED: "cache.serialization_failed",
9
+ DESERIALIZATION_FAILED: "cache.deserialization_failed",
10
+ INVALID_NAMESPACE: "cache.invalid_namespace",
11
+ INVALID_KEY: "cache.invalid_key",
12
+ SCRIPT_NOT_REGISTERED: "cache.script_not_registered",
13
+ SCRIPT_EXECUTION_FAILED: "cache.script_execution_failed",
14
+ SCRIPT_REGISTRY_MISSING: "cache.script_registry_missing",
15
+ FLUSH_DISABLED_IN_PRODUCTION: "cache.flush_disabled_in_production",
16
+ CLUSTER_MISCONFIGURED: "cache.cluster_misconfigured",
17
+ SENTINEL_MISCONFIGURED: "cache.sentinel_misconfigured",
18
+ SHUTDOWN_TIMEOUT: "cache.shutdown_timeout",
19
+ UNSUPPORTED_IN_CLUSTER: "cache.unsupported_in_cluster"
20
+ };
21
+
22
+ // src/shared/constants/event-names.ts
23
+ var CACHE_EVENT_NAMES = {
24
+ CONNECT: "connect",
25
+ READY: "ready",
26
+ ERROR: "error",
27
+ CLOSE: "close",
28
+ RECONNECTING: "reconnecting",
29
+ END: "end"
30
+ };
31
+
32
+ exports.CACHE_ERROR_CODES = CACHE_ERROR_CODES;
33
+ exports.CACHE_EVENT_NAMES = CACHE_EVENT_NAMES;
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Cache connection event types.
3
+ *
4
+ * Layer: shared — zero-dependency. Emitted by the connection manager and
5
+ * surfaced to consumers through the optional `events.onEvent` callback.
6
+ */
7
+ /** Connection lifecycle events propagated from the underlying Redis client. */
8
+ type CacheEventName = 'connect' | 'ready' | 'error' | 'close' | 'reconnecting' | 'end';
9
+ /** Coarse connection status derived from the lifecycle events. */
10
+ type CacheConnectionStatus = 'connecting' | 'ready' | 'reconnecting' | 'closed';
11
+
12
+ /**
13
+ * Cache configuration value types.
14
+ *
15
+ * Layer: shared — zero-dependency. Semantic aliases used across the public API
16
+ * to make key-building intent explicit at call sites (spec §11.2, §D11/D17).
17
+ */
18
+ /**
19
+ * A logical key namespace. Every key in an application shares one namespace,
20
+ * which guarantees tenant/app isolation — keys from one namespace never collide
21
+ * with another. Must be non-empty and must not contain the key separator.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const namespace: CacheNamespace = 'app' // single-app default
26
+ * const tenant: CacheNamespace = 'tenant-42' // per-tenant isolation
27
+ * ```
28
+ */
29
+ type CacheNamespace = string;
30
+ /**
31
+ * A logical key prefix that groups related entities under a namespace. Combined
32
+ * by the key builder as `{namespace}{sep}{prefix}{sep}{id}`.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * const prefix: CacheKeyPrefix = 'user' // → app:user:1
37
+ * const session: CacheKeyPrefix = 'session' // → app:session:abc
38
+ * ```
39
+ */
40
+ type CacheKeyPrefix = string;
41
+
42
+ /**
43
+ * JSON-serializable value type.
44
+ *
45
+ * Layer: shared — zero-dependency. Describes exactly what the default
46
+ * `JsonSerializer` can round-trip through `JSON.stringify`/`JSON.parse`.
47
+ */
48
+ /**
49
+ * A value that survives a JSON round-trip without loss.
50
+ *
51
+ * Deliberately excludes `Date`, `Map`, `Set`, `BigInt`, `undefined`, functions,
52
+ * and class instances — these either throw, silently drop, or change type under
53
+ * `JSON.stringify`. A consumer that needs them must supply a custom
54
+ * `ISerializer`; the typed `get<T>`/`set<T>` API does not constrain `T` to this
55
+ * type so a custom serializer stays unrestricted.
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * const ok: SerializableValue = { id: 1, tags: ['a'], active: true, parent: null }
60
+ * // const bad: SerializableValue = { when: new Date() } // WRONG: Date is not serializable
61
+ * ```
62
+ */
63
+ type SerializableValue = string | number | boolean | null | SerializableValue[] | {
64
+ [key: string]: SerializableValue;
65
+ };
66
+
67
+ /**
68
+ * Canonical cache error codes for `@bymax-one/nest-cache`.
69
+ *
70
+ * Layer: shared — zero-dependency, importable in any runtime (browser, edge,
71
+ * Node). The server subpath's `CacheException` maps these codes to messages and
72
+ * HTTP statuses.
73
+ */
74
+ /**
75
+ * String error codes thrown by the cache library, namespaced under `cache.`.
76
+ *
77
+ * Append-only: new codes may be added, but existing values must never be
78
+ * renamed or removed without a major version bump — consumers switch on them.
79
+ */
80
+ declare const CACHE_ERROR_CODES: {
81
+ readonly CONNECTION_FAILED: "cache.connection_failed";
82
+ readonly COMMAND_TIMEOUT: "cache.command_timeout";
83
+ readonly CONNECTION_LOST: "cache.connection_lost";
84
+ readonly SERIALIZATION_FAILED: "cache.serialization_failed";
85
+ readonly DESERIALIZATION_FAILED: "cache.deserialization_failed";
86
+ readonly INVALID_NAMESPACE: "cache.invalid_namespace";
87
+ readonly INVALID_KEY: "cache.invalid_key";
88
+ readonly SCRIPT_NOT_REGISTERED: "cache.script_not_registered";
89
+ readonly SCRIPT_EXECUTION_FAILED: "cache.script_execution_failed";
90
+ readonly SCRIPT_REGISTRY_MISSING: "cache.script_registry_missing";
91
+ readonly FLUSH_DISABLED_IN_PRODUCTION: "cache.flush_disabled_in_production";
92
+ readonly CLUSTER_MISCONFIGURED: "cache.cluster_misconfigured";
93
+ readonly SENTINEL_MISCONFIGURED: "cache.sentinel_misconfigured";
94
+ readonly SHUTDOWN_TIMEOUT: "cache.shutdown_timeout";
95
+ readonly UNSUPPORTED_IN_CLUSTER: "cache.unsupported_in_cluster";
96
+ };
97
+ /** Union of every cache error code string value. */
98
+ type CacheErrorCode = (typeof CACHE_ERROR_CODES)[keyof typeof CACHE_ERROR_CODES];
99
+
100
+ /**
101
+ * Connection lifecycle event names, keyed by symbolic name. Each value is a
102
+ * {@link CacheEventName}; the `satisfies` clause keeps the object and the union
103
+ * in lock-step — adding an event to the union without a key here is a type error.
104
+ */
105
+ declare const CACHE_EVENT_NAMES: {
106
+ readonly CONNECT: "connect";
107
+ readonly READY: "ready";
108
+ readonly ERROR: "error";
109
+ readonly CLOSE: "close";
110
+ readonly RECONNECTING: "reconnecting";
111
+ readonly END: "end";
112
+ };
113
+
114
+ export { CACHE_ERROR_CODES, CACHE_EVENT_NAMES, type CacheConnectionStatus, type CacheErrorCode, type CacheEventName, type CacheKeyPrefix, type CacheNamespace, type SerializableValue };
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Cache connection event types.
3
+ *
4
+ * Layer: shared — zero-dependency. Emitted by the connection manager and
5
+ * surfaced to consumers through the optional `events.onEvent` callback.
6
+ */
7
+ /** Connection lifecycle events propagated from the underlying Redis client. */
8
+ type CacheEventName = 'connect' | 'ready' | 'error' | 'close' | 'reconnecting' | 'end';
9
+ /** Coarse connection status derived from the lifecycle events. */
10
+ type CacheConnectionStatus = 'connecting' | 'ready' | 'reconnecting' | 'closed';
11
+
12
+ /**
13
+ * Cache configuration value types.
14
+ *
15
+ * Layer: shared — zero-dependency. Semantic aliases used across the public API
16
+ * to make key-building intent explicit at call sites (spec §11.2, §D11/D17).
17
+ */
18
+ /**
19
+ * A logical key namespace. Every key in an application shares one namespace,
20
+ * which guarantees tenant/app isolation — keys from one namespace never collide
21
+ * with another. Must be non-empty and must not contain the key separator.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const namespace: CacheNamespace = 'app' // single-app default
26
+ * const tenant: CacheNamespace = 'tenant-42' // per-tenant isolation
27
+ * ```
28
+ */
29
+ type CacheNamespace = string;
30
+ /**
31
+ * A logical key prefix that groups related entities under a namespace. Combined
32
+ * by the key builder as `{namespace}{sep}{prefix}{sep}{id}`.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * const prefix: CacheKeyPrefix = 'user' // → app:user:1
37
+ * const session: CacheKeyPrefix = 'session' // → app:session:abc
38
+ * ```
39
+ */
40
+ type CacheKeyPrefix = string;
41
+
42
+ /**
43
+ * JSON-serializable value type.
44
+ *
45
+ * Layer: shared — zero-dependency. Describes exactly what the default
46
+ * `JsonSerializer` can round-trip through `JSON.stringify`/`JSON.parse`.
47
+ */
48
+ /**
49
+ * A value that survives a JSON round-trip without loss.
50
+ *
51
+ * Deliberately excludes `Date`, `Map`, `Set`, `BigInt`, `undefined`, functions,
52
+ * and class instances — these either throw, silently drop, or change type under
53
+ * `JSON.stringify`. A consumer that needs them must supply a custom
54
+ * `ISerializer`; the typed `get<T>`/`set<T>` API does not constrain `T` to this
55
+ * type so a custom serializer stays unrestricted.
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * const ok: SerializableValue = { id: 1, tags: ['a'], active: true, parent: null }
60
+ * // const bad: SerializableValue = { when: new Date() } // WRONG: Date is not serializable
61
+ * ```
62
+ */
63
+ type SerializableValue = string | number | boolean | null | SerializableValue[] | {
64
+ [key: string]: SerializableValue;
65
+ };
66
+
67
+ /**
68
+ * Canonical cache error codes for `@bymax-one/nest-cache`.
69
+ *
70
+ * Layer: shared — zero-dependency, importable in any runtime (browser, edge,
71
+ * Node). The server subpath's `CacheException` maps these codes to messages and
72
+ * HTTP statuses.
73
+ */
74
+ /**
75
+ * String error codes thrown by the cache library, namespaced under `cache.`.
76
+ *
77
+ * Append-only: new codes may be added, but existing values must never be
78
+ * renamed or removed without a major version bump — consumers switch on them.
79
+ */
80
+ declare const CACHE_ERROR_CODES: {
81
+ readonly CONNECTION_FAILED: "cache.connection_failed";
82
+ readonly COMMAND_TIMEOUT: "cache.command_timeout";
83
+ readonly CONNECTION_LOST: "cache.connection_lost";
84
+ readonly SERIALIZATION_FAILED: "cache.serialization_failed";
85
+ readonly DESERIALIZATION_FAILED: "cache.deserialization_failed";
86
+ readonly INVALID_NAMESPACE: "cache.invalid_namespace";
87
+ readonly INVALID_KEY: "cache.invalid_key";
88
+ readonly SCRIPT_NOT_REGISTERED: "cache.script_not_registered";
89
+ readonly SCRIPT_EXECUTION_FAILED: "cache.script_execution_failed";
90
+ readonly SCRIPT_REGISTRY_MISSING: "cache.script_registry_missing";
91
+ readonly FLUSH_DISABLED_IN_PRODUCTION: "cache.flush_disabled_in_production";
92
+ readonly CLUSTER_MISCONFIGURED: "cache.cluster_misconfigured";
93
+ readonly SENTINEL_MISCONFIGURED: "cache.sentinel_misconfigured";
94
+ readonly SHUTDOWN_TIMEOUT: "cache.shutdown_timeout";
95
+ readonly UNSUPPORTED_IN_CLUSTER: "cache.unsupported_in_cluster";
96
+ };
97
+ /** Union of every cache error code string value. */
98
+ type CacheErrorCode = (typeof CACHE_ERROR_CODES)[keyof typeof CACHE_ERROR_CODES];
99
+
100
+ /**
101
+ * Connection lifecycle event names, keyed by symbolic name. Each value is a
102
+ * {@link CacheEventName}; the `satisfies` clause keeps the object and the union
103
+ * in lock-step — adding an event to the union without a key here is a type error.
104
+ */
105
+ declare const CACHE_EVENT_NAMES: {
106
+ readonly CONNECT: "connect";
107
+ readonly READY: "ready";
108
+ readonly ERROR: "error";
109
+ readonly CLOSE: "close";
110
+ readonly RECONNECTING: "reconnecting";
111
+ readonly END: "end";
112
+ };
113
+
114
+ export { CACHE_ERROR_CODES, CACHE_EVENT_NAMES, type CacheConnectionStatus, type CacheErrorCode, type CacheEventName, type CacheKeyPrefix, type CacheNamespace, type SerializableValue };
@@ -0,0 +1,30 @@
1
+ // src/shared/constants/error-codes.ts
2
+ var CACHE_ERROR_CODES = {
3
+ CONNECTION_FAILED: "cache.connection_failed",
4
+ COMMAND_TIMEOUT: "cache.command_timeout",
5
+ CONNECTION_LOST: "cache.connection_lost",
6
+ SERIALIZATION_FAILED: "cache.serialization_failed",
7
+ DESERIALIZATION_FAILED: "cache.deserialization_failed",
8
+ INVALID_NAMESPACE: "cache.invalid_namespace",
9
+ INVALID_KEY: "cache.invalid_key",
10
+ SCRIPT_NOT_REGISTERED: "cache.script_not_registered",
11
+ SCRIPT_EXECUTION_FAILED: "cache.script_execution_failed",
12
+ SCRIPT_REGISTRY_MISSING: "cache.script_registry_missing",
13
+ FLUSH_DISABLED_IN_PRODUCTION: "cache.flush_disabled_in_production",
14
+ CLUSTER_MISCONFIGURED: "cache.cluster_misconfigured",
15
+ SENTINEL_MISCONFIGURED: "cache.sentinel_misconfigured",
16
+ SHUTDOWN_TIMEOUT: "cache.shutdown_timeout",
17
+ UNSUPPORTED_IN_CLUSTER: "cache.unsupported_in_cluster"
18
+ };
19
+
20
+ // src/shared/constants/event-names.ts
21
+ var CACHE_EVENT_NAMES = {
22
+ CONNECT: "connect",
23
+ READY: "ready",
24
+ ERROR: "error",
25
+ CLOSE: "close",
26
+ RECONNECTING: "reconnecting",
27
+ END: "end"
28
+ };
29
+
30
+ export { CACHE_ERROR_CODES, CACHE_EVENT_NAMES };
package/package.json ADDED
@@ -0,0 +1,123 @@
1
+ {
2
+ "name": "@bymax-one/nest-cache",
3
+ "version": "1.0.0",
4
+ "description": "Typed Redis cache for NestJS based on ioredis 5, with namespace strategy, Pub/Sub and Lua script management.",
5
+ "author": "Bymax One <support@bymax.one>",
6
+ "license": "MIT",
7
+ "homepage": "https://github.com/bymaxone/nest-cache#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/bymaxone/nest-cache.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/bymaxone/nest-cache/issues"
14
+ },
15
+ "type": "module",
16
+ "sideEffects": false,
17
+ "files": [
18
+ "dist",
19
+ "LICENSE",
20
+ "README.md",
21
+ "CHANGELOG.md"
22
+ ],
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/server/index.d.ts",
26
+ "import": "./dist/server/index.mjs",
27
+ "require": "./dist/server/index.cjs"
28
+ },
29
+ "./shared": {
30
+ "types": "./dist/shared/index.d.ts",
31
+ "import": "./dist/shared/index.mjs",
32
+ "require": "./dist/shared/index.cjs"
33
+ }
34
+ },
35
+ "lint-staged": {
36
+ "*.{ts,tsx,js,mjs,cjs}": [
37
+ "eslint --fix",
38
+ "prettier --write"
39
+ ],
40
+ "*.{json,md,yml,yaml}": [
41
+ "prettier --write"
42
+ ]
43
+ },
44
+ "dependencies": {},
45
+ "peerDependencies": {
46
+ "@nestjs/common": "^11.0.0",
47
+ "@nestjs/core": "^11.0.0",
48
+ "ioredis": "^5.0.0",
49
+ "reflect-metadata": "^0.2.0"
50
+ },
51
+ "devDependencies": {
52
+ "@commitlint/cli": "^21.2.1",
53
+ "@commitlint/config-conventional": "^21.2.0",
54
+ "@eslint/js": "^9.39.4",
55
+ "@nestjs/common": "^11.1.20",
56
+ "@nestjs/core": "^11.1.20",
57
+ "@nestjs/testing": "^11.1.20",
58
+ "@stryker-mutator/core": "^9",
59
+ "@stryker-mutator/jest-runner": "^9",
60
+ "@stryker-mutator/typescript-checker": "^9",
61
+ "@types/jest": "^30.0.0",
62
+ "@types/node": "^24",
63
+ "@typescript-eslint/eslint-plugin": "^8.59.3",
64
+ "@typescript-eslint/parser": "^8.59.3",
65
+ "eslint": "^9.39.4",
66
+ "eslint-config-prettier": "^10.1.8",
67
+ "eslint-import-resolver-typescript": "^4.4.4",
68
+ "eslint-plugin-import": "^2.32.0",
69
+ "eslint-plugin-prettier": "^5.5.5",
70
+ "eslint-plugin-security": "^4.0.0",
71
+ "globals": "^17.6.0",
72
+ "husky": "^9.1.7",
73
+ "ioredis": "^5.10.1",
74
+ "ioredis-mock": "^8.13.1",
75
+ "jest": "^30.4.2",
76
+ "lint-staged": "^17.2.0",
77
+ "prettier": "^3.8.3",
78
+ "reflect-metadata": "^0.2.2",
79
+ "rxjs": "^7.8.0",
80
+ "testcontainers": "^12.0.1",
81
+ "ts-jest": "^29.4.9",
82
+ "ts-node": "^10.9.2",
83
+ "tsup": "^8.5.1",
84
+ "typescript": "^5.9.3"
85
+ },
86
+ "keywords": [
87
+ "cache",
88
+ "redis",
89
+ "ioredis",
90
+ "nestjs",
91
+ "typescript",
92
+ "sentinel",
93
+ "cluster",
94
+ "pubsub",
95
+ "lua"
96
+ ],
97
+ "engines": {
98
+ "node": ">=24.0.0"
99
+ },
100
+ "publishConfig": {
101
+ "access": "public",
102
+ "registry": "https://registry.npmjs.org/"
103
+ },
104
+ "scripts": {
105
+ "build": "pnpm clean && tsup",
106
+ "lint": "eslint src scripts",
107
+ "lint:fix": "eslint src scripts --fix",
108
+ "test": "jest",
109
+ "test:cov": "jest --coverage",
110
+ "test:watch": "jest --watch",
111
+ "test:e2e": "jest --config jest.e2e.config.ts --runInBand",
112
+ "test:all": "pnpm test && pnpm test:e2e",
113
+ "test:cov:all": "jest --config jest.coverage.config.ts --coverage",
114
+ "mutation": "stryker run",
115
+ "mutation:incremental": "stryker run --incremental",
116
+ "mutation:dry-run": "stryker run --dryRunOnly",
117
+ "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.server.json",
118
+ "test:types": "tsc --noEmit -p tsconfig.typetest.json",
119
+ "size": "node scripts/check-size.mjs",
120
+ "clean": "rm -rf dist coverage",
121
+ "release": "pnpm publish --provenance"
122
+ }
123
+ }