@nestjs-pipeline/cache 0.2.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.
- package/COMMERCIAL_LICENSE.txt +34 -0
- package/LICENSE +661 -0
- package/README.md +572 -0
- package/dist/adapters/cache-manager.adapter.d.ts +21 -0
- package/dist/adapters/cache-manager.adapter.d.ts.map +1 -0
- package/dist/adapters/cache-manager.adapter.js +56 -0
- package/dist/adapters/cache-manager.adapter.js.map +1 -0
- package/dist/cache.behavior.d.ts +84 -0
- package/dist/cache.behavior.d.ts.map +1 -0
- package/dist/cache.behavior.js +239 -0
- package/dist/cache.behavior.js.map +1 -0
- package/dist/cache.module.d.ts +85 -0
- package/dist/cache.module.d.ts.map +1 -0
- package/dist/cache.module.js +189 -0
- package/dist/cache.module.js.map +1 -0
- package/dist/constants/tokens.d.ts +13 -0
- package/dist/constants/tokens.d.ts.map +1 -0
- package/dist/constants/tokens.js +17 -0
- package/dist/constants/tokens.js.map +1 -0
- package/dist/errors/missing-partition.error.d.ts +18 -0
- package/dist/errors/missing-partition.error.d.ts.map +1 -0
- package/dist/errors/missing-partition.error.js +23 -0
- package/dist/errors/missing-partition.error.js.map +1 -0
- package/dist/helpers/cache-factory.d.ts +39 -0
- package/dist/helpers/cache-factory.d.ts.map +1 -0
- package/dist/helpers/cache-factory.js +152 -0
- package/dist/helpers/cache-factory.js.map +1 -0
- package/dist/helpers/cache-key.d.ts +79 -0
- package/dist/helpers/cache-key.d.ts.map +1 -0
- package/dist/helpers/cache-key.js +92 -0
- package/dist/helpers/cache-key.js.map +1 -0
- package/dist/helpers/cache.intent.d.ts +26 -0
- package/dist/helpers/cache.intent.d.ts.map +1 -0
- package/dist/helpers/cache.intent.js +24 -0
- package/dist/helpers/cache.intent.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/cache-options.interface.d.ts +120 -0
- package/dist/interfaces/cache-options.interface.d.ts.map +1 -0
- package/dist/interfaces/cache-options.interface.js +4 -0
- package/dist/interfaces/cache-options.interface.js.map +1 -0
- package/package.json +86 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { type LoggerService } from '@nestjs/common';
|
|
2
|
+
import { type IPipelineBehavior, type IPipelineBehaviorContract, type IPipelineBehaviorOptionsResolver, type IPipelineContext, type NextDelegate, PIPELINE_BEHAVIOR_CONTRACT, type PipelineItemToken } from '@nestjs-pipeline/core';
|
|
3
|
+
import type { Cache } from 'cache-manager';
|
|
4
|
+
import { type IPipelineCache } from './adapters/cache-manager.adapter';
|
|
5
|
+
import type { CacheBehaviorOptions } from './interfaces/cache-options.interface';
|
|
6
|
+
/**
|
|
7
|
+
* Unique symbol key set on `context.items` recording whether the request was served from cache (`true` on hit).
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* const isHit = context.items.get(CACHE_HIT_ITEM) === true;
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export declare const CACHE_HIT_ITEM: unique symbol;
|
|
15
|
+
/**
|
|
16
|
+
* Typed token for {@link CACHE_HIT_ITEM}: the cache hit flag. Reads and writes the same
|
|
17
|
+
* `context.items` entry through `getPipelineItem` / `requirePipelineItem`.
|
|
18
|
+
*/
|
|
19
|
+
export declare const CACHE_HIT_ITEM_TOKEN: PipelineItemToken<boolean>;
|
|
20
|
+
/**
|
|
21
|
+
* Unique symbol key set on `context.items` recording the resolved cache key string.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* const key = context.items.get(CACHE_KEY_ITEM) as string | undefined;
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare const CACHE_KEY_ITEM: unique symbol;
|
|
29
|
+
/**
|
|
30
|
+
* Typed token for {@link CACHE_KEY_ITEM}: the resolved cache key. Reads and writes the same
|
|
31
|
+
* `context.items` entry through `getPipelineItem` / `requirePipelineItem`.
|
|
32
|
+
*/
|
|
33
|
+
export declare const CACHE_KEY_ITEM_TOKEN: PipelineItemToken<string>;
|
|
34
|
+
/**
|
|
35
|
+
* Pipeline behavior that transparently caches handler results with
|
|
36
|
+
* `cache-manager` (v7) on top of Keyv.
|
|
37
|
+
*
|
|
38
|
+
* Resolution of the effective options for a handler:
|
|
39
|
+
* 1. Application-wide defaults bound to {@link CACHE_DEFAULT_OPTIONS}
|
|
40
|
+
* (via {@link CacheModule.forRoot}).
|
|
41
|
+
* 2. Per-handler options from `@UsePipeline([CacheBehavior, { ... }])`,
|
|
42
|
+
* shallow-merged on top of the defaults (handler keys win).
|
|
43
|
+
*
|
|
44
|
+
* A `key` factory is required — see {@link createPartitionedCacheKeyFactory}. Only
|
|
45
|
+
* `query` requests are cached by default; commands and events pass through
|
|
46
|
+
* untouched. On a cache miss, `null` / `undefined` results are not written.
|
|
47
|
+
* Cache hits return the value from the single explicit lookup. This behavior
|
|
48
|
+
* intentionally does not use `cache-manager.wrap()` because its background
|
|
49
|
+
* refresh callback would re-enter every downstream pipeline behavior.
|
|
50
|
+
* Cached results are JSON values. A miss returns the JSON form of the handler
|
|
51
|
+
* result that it stores (a `Date` becomes an ISO string and a class instance a
|
|
52
|
+
* plain object), so a hit and a miss return the same shape. A result that cannot
|
|
53
|
+
* be JSON-serialized is returned unchanged and not cached.
|
|
54
|
+
*
|
|
55
|
+
* Store errors fail open by default: read failures bypass caching for that
|
|
56
|
+
* execution, and write failures return the successful handler result. Set
|
|
57
|
+
* `failOpen: false` to propagate store failures instead.
|
|
58
|
+
*
|
|
59
|
+
* @example Principal/permission-scoped query cache
|
|
60
|
+
* ```ts
|
|
61
|
+
* const userCacheKey = createPartitionedCacheKeyFactory({
|
|
62
|
+
* principal: (ctx) => ctx.items.get('userId') as string | undefined,
|
|
63
|
+
* scope: (ctx) => ctx.items.get('capabilityVersion') as string | undefined,
|
|
64
|
+
* });
|
|
65
|
+
*
|
|
66
|
+
* @QueryHandler(GetUsersQuery)
|
|
67
|
+
* @UsePipeline([CacheBehavior, { key: userCacheKey, ttl: 30_000 }])
|
|
68
|
+
* export class GetUsersHandler {}
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export declare class CacheBehavior implements IPipelineBehavior, IPipelineBehaviorOptionsResolver<CacheBehaviorOptions> {
|
|
72
|
+
static readonly [PIPELINE_BEHAVIOR_CONTRACT]: IPipelineBehaviorContract;
|
|
73
|
+
private readonly logger;
|
|
74
|
+
private readonly defaults;
|
|
75
|
+
private readonly cacheAdapter;
|
|
76
|
+
constructor(cache: Cache | IPipelineCache, defaults?: CacheBehaviorOptions, logger?: LoggerService);
|
|
77
|
+
handle(context: IPipelineContext, next: NextDelegate): Promise<unknown>;
|
|
78
|
+
/** Logs a store failure and either bypasses it or propagates it. */
|
|
79
|
+
private handleStoreError;
|
|
80
|
+
private diagnose;
|
|
81
|
+
/** Shallow-merges pipeline-level options over application defaults. */
|
|
82
|
+
resolveEffectiveOptions(options?: CacheBehaviorOptions): CacheBehaviorOptions;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=cache.behavior.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.behavior.d.ts","sourceRoot":"","sources":["../src/cache.behavior.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,aAAa,EAEnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,yBAAyB,EAC9B,KAAK,gCAAgC,EACrC,KAAK,gBAAgB,EAErB,KAAK,YAAY,EACjB,0BAA0B,EAI1B,KAAK,iBAAiB,EAEvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAEL,KAAK,cAAc,EACpB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAEjF;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,eAA2B,CAAC;AAEvD;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,iBAAiB,CAAC,OAAO,CACG,CAAC;AAEhE;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,eAA2B,CAAC;AAEvD;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,iBAAiB,CAAC,MAAM,CACG,CAAC;AAY/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,qBACa,aACX,YACE,iBAAiB,EACjB,gCAAgC,CAAC,oBAAoB,CAAC;IAExD,MAAM,CAAC,QAAQ,CAAC,CAAC,0BAA0B,CAAC,EAAE,yBAAyB,CAkDrE;IAEF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuB;IAChD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAiB;gBAI5C,KAAK,EAAE,KAAK,GAAG,cAAc,EAG7B,QAAQ,CAAC,EAAE,oBAAoB,EAG/B,MAAM,CAAC,EAAE,aAAa;IAWlB,MAAM,CACV,OAAO,EAAE,gBAAgB,EACzB,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,OAAO,CAAC;IA2DnB,oEAAoE;IACpE,OAAO,CAAC,gBAAgB;IA0BxB,OAAO,CAAC,QAAQ;IAQhB,uEAAuE;IACvE,uBAAuB,CACrB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,oBAAoB;CAIxB"}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
3
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
4
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
5
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
6
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
7
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
8
|
+
};
|
|
9
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
10
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
11
|
+
};
|
|
12
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
13
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
14
|
+
};
|
|
15
|
+
var CacheBehavior_1;
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.CacheBehavior = exports.CACHE_KEY_ITEM_TOKEN = exports.CACHE_KEY_ITEM = exports.CACHE_HIT_ITEM_TOKEN = exports.CACHE_HIT_ITEM = void 0;
|
|
18
|
+
const common_1 = require("@nestjs/common");
|
|
19
|
+
const core_1 = require("@nestjs-pipeline/core");
|
|
20
|
+
const cache_manager_adapter_1 = require("./adapters/cache-manager.adapter");
|
|
21
|
+
const tokens_1 = require("./constants/tokens");
|
|
22
|
+
/**
|
|
23
|
+
* Unique symbol key set on `context.items` recording whether the request was served from cache (`true` on hit).
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* const isHit = context.items.get(CACHE_HIT_ITEM) === true;
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
exports.CACHE_HIT_ITEM = Symbol('CACHE_HIT_ITEM');
|
|
31
|
+
/**
|
|
32
|
+
* Typed token for {@link CACHE_HIT_ITEM}: the cache hit flag. Reads and writes the same
|
|
33
|
+
* `context.items` entry through `getPipelineItem` / `requirePipelineItem`.
|
|
34
|
+
*/
|
|
35
|
+
exports.CACHE_HIT_ITEM_TOKEN = (0, core_1.createPipelineItem)('CACHE_HIT_ITEM', exports.CACHE_HIT_ITEM);
|
|
36
|
+
/**
|
|
37
|
+
* Unique symbol key set on `context.items` recording the resolved cache key string.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* const key = context.items.get(CACHE_KEY_ITEM) as string | undefined;
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
exports.CACHE_KEY_ITEM = Symbol('CACHE_KEY_ITEM');
|
|
45
|
+
/**
|
|
46
|
+
* Typed token for {@link CACHE_KEY_ITEM}: the resolved cache key. Reads and writes the same
|
|
47
|
+
* `context.items` entry through `getPipelineItem` / `requirePipelineItem`.
|
|
48
|
+
*/
|
|
49
|
+
exports.CACHE_KEY_ITEM_TOKEN = (0, core_1.createPipelineItem)('CACHE_KEY_ITEM', exports.CACHE_KEY_ITEM);
|
|
50
|
+
const DEFAULT_KINDS = ['query'];
|
|
51
|
+
/** Whether this request kind is configured for caching. */
|
|
52
|
+
function inScope(options, requestKind) {
|
|
53
|
+
return (options?.kinds ?? DEFAULT_KINDS).includes(requestKind);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Pipeline behavior that transparently caches handler results with
|
|
57
|
+
* `cache-manager` (v7) on top of Keyv.
|
|
58
|
+
*
|
|
59
|
+
* Resolution of the effective options for a handler:
|
|
60
|
+
* 1. Application-wide defaults bound to {@link CACHE_DEFAULT_OPTIONS}
|
|
61
|
+
* (via {@link CacheModule.forRoot}).
|
|
62
|
+
* 2. Per-handler options from `@UsePipeline([CacheBehavior, { ... }])`,
|
|
63
|
+
* shallow-merged on top of the defaults (handler keys win).
|
|
64
|
+
*
|
|
65
|
+
* A `key` factory is required — see {@link createPartitionedCacheKeyFactory}. Only
|
|
66
|
+
* `query` requests are cached by default; commands and events pass through
|
|
67
|
+
* untouched. On a cache miss, `null` / `undefined` results are not written.
|
|
68
|
+
* Cache hits return the value from the single explicit lookup. This behavior
|
|
69
|
+
* intentionally does not use `cache-manager.wrap()` because its background
|
|
70
|
+
* refresh callback would re-enter every downstream pipeline behavior.
|
|
71
|
+
* Cached results are JSON values. A miss returns the JSON form of the handler
|
|
72
|
+
* result that it stores (a `Date` becomes an ISO string and a class instance a
|
|
73
|
+
* plain object), so a hit and a miss return the same shape. A result that cannot
|
|
74
|
+
* be JSON-serialized is returned unchanged and not cached.
|
|
75
|
+
*
|
|
76
|
+
* Store errors fail open by default: read failures bypass caching for that
|
|
77
|
+
* execution, and write failures return the successful handler result. Set
|
|
78
|
+
* `failOpen: false` to propagate store failures instead.
|
|
79
|
+
*
|
|
80
|
+
* @example Principal/permission-scoped query cache
|
|
81
|
+
* ```ts
|
|
82
|
+
* const userCacheKey = createPartitionedCacheKeyFactory({
|
|
83
|
+
* principal: (ctx) => ctx.items.get('userId') as string | undefined,
|
|
84
|
+
* scope: (ctx) => ctx.items.get('capabilityVersion') as string | undefined,
|
|
85
|
+
* });
|
|
86
|
+
*
|
|
87
|
+
* @QueryHandler(GetUsersQuery)
|
|
88
|
+
* @UsePipeline([CacheBehavior, { key: userCacheKey, ttl: 30_000 }])
|
|
89
|
+
* export class GetUsersHandler {}
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
let CacheBehavior = class CacheBehavior {
|
|
93
|
+
static { CacheBehavior_1 = this; }
|
|
94
|
+
static [core_1.PIPELINE_BEHAVIOR_CONTRACT] = {
|
|
95
|
+
order: (context) => {
|
|
96
|
+
const options = context.effectiveOptions;
|
|
97
|
+
if (!inScope(options, context.requestKind)) {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
after: ['@nestjs-pipeline/casl:CaslBehavior', 'CaslBehavior'],
|
|
102
|
+
};
|
|
103
|
+
},
|
|
104
|
+
validate: (context) => {
|
|
105
|
+
const options = context.effectiveOptions;
|
|
106
|
+
if (!inScope(options, context.requestKind)) {
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
if (!options?.key) {
|
|
110
|
+
return [
|
|
111
|
+
{
|
|
112
|
+
handlerName: context.handlerName,
|
|
113
|
+
behaviorName: CacheBehavior_1.name,
|
|
114
|
+
message: 'Active CacheBehavior requires an explicit `key` factory',
|
|
115
|
+
fix: 'Provide a key factory via createPartitionedCacheKeyFactory(...) in ' +
|
|
116
|
+
'@UsePipeline([CacheBehavior, { key: ... }]) or CacheModule.forRoot({ defaults: ... }).',
|
|
117
|
+
},
|
|
118
|
+
];
|
|
119
|
+
}
|
|
120
|
+
if (typeof options.key !== 'function') {
|
|
121
|
+
return [
|
|
122
|
+
{
|
|
123
|
+
handlerName: context.handlerName,
|
|
124
|
+
behaviorName: CacheBehavior_1.name,
|
|
125
|
+
message: `CacheBehavior key factory must be a callable function, received ${typeof options.key}`,
|
|
126
|
+
fix: 'Pass a valid function (ctx) => string to the key option in @UsePipeline([CacheBehavior, { key: ... }]).',
|
|
127
|
+
},
|
|
128
|
+
];
|
|
129
|
+
}
|
|
130
|
+
return undefined;
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
logger;
|
|
134
|
+
defaults;
|
|
135
|
+
cacheAdapter;
|
|
136
|
+
constructor(cache, defaults, logger) {
|
|
137
|
+
this.defaults = defaults ?? {};
|
|
138
|
+
this.cacheAdapter =
|
|
139
|
+
cache instanceof cache_manager_adapter_1.CacheManagerAdapter
|
|
140
|
+
? cache
|
|
141
|
+
: new cache_manager_adapter_1.CacheManagerAdapter(cache);
|
|
142
|
+
this.logger = logger ?? new common_1.Logger(CacheBehavior_1.name, { timestamp: true });
|
|
143
|
+
}
|
|
144
|
+
async handle(context, next) {
|
|
145
|
+
const options = this.resolveEffectiveOptions(context.getBehaviorOptions(CacheBehavior_1));
|
|
146
|
+
if (!inScope(options, context.requestKind))
|
|
147
|
+
return next();
|
|
148
|
+
if (options.condition && !options.condition(context))
|
|
149
|
+
return next();
|
|
150
|
+
if (!options.key) {
|
|
151
|
+
throw new TypeError(`CacheBehavior on ${context.handlerName} requires an explicit \`key\` factory. ` +
|
|
152
|
+
'A cache hit returns without running the handler, so the key must partition ' +
|
|
153
|
+
'every dimension that can change the authorized response: tenant, principal, ' +
|
|
154
|
+
'permission scope and request payload. Use createPartitionedCacheKeyFactory(...).');
|
|
155
|
+
}
|
|
156
|
+
const key = options.key(context);
|
|
157
|
+
(0, core_1.setPipelineItem)(context, exports.CACHE_KEY_ITEM_TOKEN, key);
|
|
158
|
+
let cached;
|
|
159
|
+
let canWrite = true;
|
|
160
|
+
try {
|
|
161
|
+
cached = await this.cacheAdapter.get(key);
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
this.handleStoreError('read', context, key, error, options);
|
|
165
|
+
canWrite = false;
|
|
166
|
+
}
|
|
167
|
+
if (cached !== undefined && cached !== null) {
|
|
168
|
+
(0, core_1.setPipelineItem)(context, exports.CACHE_HIT_ITEM_TOKEN, true);
|
|
169
|
+
this.diagnose('debug', `Cache hit for ${context.requestName} (${key})`);
|
|
170
|
+
return cached;
|
|
171
|
+
}
|
|
172
|
+
(0, core_1.setPipelineItem)(context, exports.CACHE_HIT_ITEM_TOKEN, false);
|
|
173
|
+
this.diagnose('debug', `Cache miss for ${context.requestName} (${key})`);
|
|
174
|
+
const result = await next();
|
|
175
|
+
if (result === undefined || result === null)
|
|
176
|
+
return result;
|
|
177
|
+
const cacheable = toJsonForm(result);
|
|
178
|
+
if (cacheable === undefined) {
|
|
179
|
+
this.diagnose('warn', `Result of ${context.requestName} is not JSON-serializable; not cached (key: ${key})`);
|
|
180
|
+
return result;
|
|
181
|
+
}
|
|
182
|
+
if (canWrite) {
|
|
183
|
+
try {
|
|
184
|
+
await this.cacheAdapter.set(key, cacheable, options.ttl);
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
this.handleStoreError('write', context, key, error, options);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return cacheable;
|
|
191
|
+
}
|
|
192
|
+
/** Logs a store failure and either bypasses it or propagates it. */
|
|
193
|
+
handleStoreError(operation, context, key, error, options) {
|
|
194
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
195
|
+
if (options.failOpen ?? true) {
|
|
196
|
+
this.diagnose('warn', `Cache ${operation} error for ${context.requestName} ` +
|
|
197
|
+
`(key: ${key}); failing open: ${message}`);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
this.diagnose('error', `Cache ${operation} error for ${context.requestName} ` +
|
|
201
|
+
`(key: ${key}); failing closed: ${message}`);
|
|
202
|
+
throw error;
|
|
203
|
+
}
|
|
204
|
+
diagnose(level, message) {
|
|
205
|
+
try {
|
|
206
|
+
this.logger[level]?.(message, CacheBehavior_1.name);
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
// Diagnostics must not replace the handler result or cache-store error.
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/** Shallow-merges pipeline-level options over application defaults. */
|
|
213
|
+
resolveEffectiveOptions(options) {
|
|
214
|
+
if (!options)
|
|
215
|
+
return this.defaults;
|
|
216
|
+
return { ...this.defaults, ...options };
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
exports.CacheBehavior = CacheBehavior;
|
|
220
|
+
exports.CacheBehavior = CacheBehavior = CacheBehavior_1 = __decorate([
|
|
221
|
+
(0, common_1.Injectable)(),
|
|
222
|
+
__param(0, (0, common_1.Inject)(tokens_1.PIPELINE_CACHE)),
|
|
223
|
+
__param(1, (0, common_1.Optional)()),
|
|
224
|
+
__param(1, (0, common_1.Inject)(tokens_1.CACHE_DEFAULT_OPTIONS)),
|
|
225
|
+
__param(2, (0, common_1.Optional)()),
|
|
226
|
+
__param(2, (0, common_1.Inject)(core_1.LOGGING_BEHAVIOR_LOGGER)),
|
|
227
|
+
__metadata("design:paramtypes", [Object, Object, Object])
|
|
228
|
+
], CacheBehavior);
|
|
229
|
+
/** JSON round-trip of a cacheable result, or `undefined` when it has no JSON form. */
|
|
230
|
+
function toJsonForm(value) {
|
|
231
|
+
try {
|
|
232
|
+
const json = JSON.stringify(value);
|
|
233
|
+
return json === undefined ? undefined : JSON.parse(json);
|
|
234
|
+
}
|
|
235
|
+
catch {
|
|
236
|
+
return undefined;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=cache.behavior.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.behavior.js","sourceRoot":"","sources":["../src/cache.behavior.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { type DynamicModule } from '@nestjs/common';
|
|
2
|
+
import type { CacheModuleAsyncOptions, CacheModuleOptions } from './interfaces/cache-options.interface';
|
|
3
|
+
/**
|
|
4
|
+
* NestJS module that builds the shared `cache-manager` instance, registers the
|
|
5
|
+
* {@link CacheBehavior}, and (optionally) application-wide default
|
|
6
|
+
* {@link CacheBehaviorOptions}.
|
|
7
|
+
*
|
|
8
|
+
* The store backend is selected declaratively (memory, redis, memcache,
|
|
9
|
+
* sqlite, postgres) or supplied directly as a pre-built cache / Keyv stores.
|
|
10
|
+
* The cache is built when the application instantiates its providers, once per
|
|
11
|
+
* application. A cache built from `store` (or the default memory store) is
|
|
12
|
+
* disconnected on application shutdown; a supplied `cache` or `stores` belongs
|
|
13
|
+
* to the caller, who closes it.
|
|
14
|
+
*
|
|
15
|
+
* @example In-memory cache (default), per-handler configuration
|
|
16
|
+
* ```ts
|
|
17
|
+
* import {
|
|
18
|
+
* CacheBehavior,
|
|
19
|
+
* CacheModule,
|
|
20
|
+
* createPartitionedCacheKeyFactory,
|
|
21
|
+
* } from '@nestjs-pipeline/cache';
|
|
22
|
+
*
|
|
23
|
+
* @Module({
|
|
24
|
+
* imports: [
|
|
25
|
+
* CacheModule.forRoot({ ttl: 30_000 }),
|
|
26
|
+
* PipelineModule.forRoot({ behaviors: [CacheBehavior] }),
|
|
27
|
+
* ],
|
|
28
|
+
* })
|
|
29
|
+
* export class AppModule {}
|
|
30
|
+
*
|
|
31
|
+
* const userQueryKey = createPartitionedCacheKeyFactory({
|
|
32
|
+
* principal: (ctx) => ctx.items.get('userId') as string | undefined,
|
|
33
|
+
* scope: (ctx) => ctx.items.get('capabilityVersion') as string | undefined,
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
* @QueryHandler(GetUserQuery)
|
|
37
|
+
* @UsePipeline([CacheBehavior, { key: userQueryKey, ttl: 60_000 }])
|
|
38
|
+
* export class GetUserHandler implements IQueryHandler<GetUserQuery> {}
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @example Redis store
|
|
42
|
+
* ```ts
|
|
43
|
+
* CacheModule.forRoot({
|
|
44
|
+
* store: { type: 'redis', url: 'redis://localhost:6379' },
|
|
45
|
+
* ttl: 60_000,
|
|
46
|
+
* })
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @example Tiered memory + postgres store
|
|
50
|
+
* ```ts
|
|
51
|
+
* CacheModule.forRoot({
|
|
52
|
+
* store: [
|
|
53
|
+
* { type: 'memory', ttl: 5_000 },
|
|
54
|
+
* { type: 'postgres', url: 'postgresql://user:pass@localhost:5432/db' },
|
|
55
|
+
* ],
|
|
56
|
+
* })
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare class CacheModule {
|
|
60
|
+
/**
|
|
61
|
+
* Registers the cache behavior, the cache instance, and optional
|
|
62
|
+
* application-wide defaults.
|
|
63
|
+
*
|
|
64
|
+
* @param options - Store configuration and default behavior options.
|
|
65
|
+
* @returns The configured global {@link DynamicModule}.
|
|
66
|
+
*/
|
|
67
|
+
static forRoot(options?: CacheModuleOptions): DynamicModule;
|
|
68
|
+
/**
|
|
69
|
+
* Registers the cache behavior with options resolved from injected
|
|
70
|
+
* dependencies (for example configuration read at startup).
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* CacheModule.forRootAsync({
|
|
75
|
+
* inject: [ConfigService],
|
|
76
|
+
* useFactory: (config: ConfigService) => ({
|
|
77
|
+
* store: { type: 'redis', url: config.getOrThrow('REDIS_URL') },
|
|
78
|
+
* ttl: 30_000,
|
|
79
|
+
* }),
|
|
80
|
+
* });
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
static forRootAsync(options: CacheModuleAsyncOptions): DynamicModule;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=cache.module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.module.d.ts","sourceRoot":"","sources":["../src/cache.module.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,aAAa,EAOnB,MAAM,gBAAgB,CAAC;AASxB,OAAO,KAAK,EAEV,uBAAuB,EACvB,kBAAkB,EACnB,MAAM,sCAAsC,CAAC;AAyD9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,qBACa,WAAW;IACtB;;;;;;OAMG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,GAAE,kBAAuB,GAAG,aAAa;IAY/D;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,uBAAuB,GAAG,aAAa;CAarE"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
3
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
4
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
5
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
6
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
7
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
8
|
+
};
|
|
9
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
10
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
11
|
+
};
|
|
12
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
13
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
14
|
+
};
|
|
15
|
+
var CacheModule_1;
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.CacheModule = void 0;
|
|
18
|
+
const common_1 = require("@nestjs/common");
|
|
19
|
+
const cache_behavior_1 = require("./cache.behavior");
|
|
20
|
+
const tokens_1 = require("./constants/tokens");
|
|
21
|
+
const cache_factory_1 = require("./helpers/cache-factory");
|
|
22
|
+
const logger = new common_1.Logger('CacheModule');
|
|
23
|
+
function storeLabel(options) {
|
|
24
|
+
if (options.cache)
|
|
25
|
+
return 'custom-cache';
|
|
26
|
+
if (options.stores && options.stores.length > 0)
|
|
27
|
+
return 'custom-stores';
|
|
28
|
+
if (!options.store)
|
|
29
|
+
return 'memory';
|
|
30
|
+
return Array.isArray(options.store)
|
|
31
|
+
? options.store.map((s) => s.type).join(', ')
|
|
32
|
+
: options.store.type;
|
|
33
|
+
}
|
|
34
|
+
/** The module owns, and closes, only a cache it built from declarative options. */
|
|
35
|
+
function ownsCache(options) {
|
|
36
|
+
return !options.cache && !(options.stores && options.stores.length > 0);
|
|
37
|
+
}
|
|
38
|
+
let CacheConnectionLifecycle = class CacheConnectionLifecycle {
|
|
39
|
+
cache;
|
|
40
|
+
options;
|
|
41
|
+
constructor(cache, options) {
|
|
42
|
+
this.cache = cache;
|
|
43
|
+
this.options = options;
|
|
44
|
+
}
|
|
45
|
+
async onApplicationShutdown() {
|
|
46
|
+
if (ownsCache(this.options))
|
|
47
|
+
await this.cache.disconnect();
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
CacheConnectionLifecycle = __decorate([
|
|
51
|
+
(0, common_1.Injectable)(),
|
|
52
|
+
__param(0, (0, common_1.Inject)(tokens_1.PIPELINE_CACHE)),
|
|
53
|
+
__param(1, (0, common_1.Inject)(tokens_1.CACHE_MODULE_OPTIONS)),
|
|
54
|
+
__metadata("design:paramtypes", [Object, Object])
|
|
55
|
+
], CacheConnectionLifecycle);
|
|
56
|
+
function cacheProviders(optionsProvider) {
|
|
57
|
+
return [
|
|
58
|
+
optionsProvider,
|
|
59
|
+
cache_behavior_1.CacheBehavior,
|
|
60
|
+
{
|
|
61
|
+
provide: tokens_1.PIPELINE_CACHE,
|
|
62
|
+
useFactory: (options) => {
|
|
63
|
+
const cache = (0, cache_factory_1.buildCache)(options);
|
|
64
|
+
logger.log(`Initialized cache with [${storeLabel(options)}] store`);
|
|
65
|
+
return cache;
|
|
66
|
+
},
|
|
67
|
+
inject: [tokens_1.CACHE_MODULE_OPTIONS],
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
provide: tokens_1.CACHE_DEFAULT_OPTIONS,
|
|
71
|
+
useFactory: (options) => ({
|
|
72
|
+
...(options.ttl !== undefined ? { ttl: options.ttl } : {}),
|
|
73
|
+
...options.defaults,
|
|
74
|
+
}),
|
|
75
|
+
inject: [tokens_1.CACHE_MODULE_OPTIONS],
|
|
76
|
+
},
|
|
77
|
+
CacheConnectionLifecycle,
|
|
78
|
+
];
|
|
79
|
+
}
|
|
80
|
+
const CACHE_EXPORTS = [cache_behavior_1.CacheBehavior, tokens_1.PIPELINE_CACHE, tokens_1.CACHE_DEFAULT_OPTIONS];
|
|
81
|
+
/**
|
|
82
|
+
* NestJS module that builds the shared `cache-manager` instance, registers the
|
|
83
|
+
* {@link CacheBehavior}, and (optionally) application-wide default
|
|
84
|
+
* {@link CacheBehaviorOptions}.
|
|
85
|
+
*
|
|
86
|
+
* The store backend is selected declaratively (memory, redis, memcache,
|
|
87
|
+
* sqlite, postgres) or supplied directly as a pre-built cache / Keyv stores.
|
|
88
|
+
* The cache is built when the application instantiates its providers, once per
|
|
89
|
+
* application. A cache built from `store` (or the default memory store) is
|
|
90
|
+
* disconnected on application shutdown; a supplied `cache` or `stores` belongs
|
|
91
|
+
* to the caller, who closes it.
|
|
92
|
+
*
|
|
93
|
+
* @example In-memory cache (default), per-handler configuration
|
|
94
|
+
* ```ts
|
|
95
|
+
* import {
|
|
96
|
+
* CacheBehavior,
|
|
97
|
+
* CacheModule,
|
|
98
|
+
* createPartitionedCacheKeyFactory,
|
|
99
|
+
* } from '@nestjs-pipeline/cache';
|
|
100
|
+
*
|
|
101
|
+
* @Module({
|
|
102
|
+
* imports: [
|
|
103
|
+
* CacheModule.forRoot({ ttl: 30_000 }),
|
|
104
|
+
* PipelineModule.forRoot({ behaviors: [CacheBehavior] }),
|
|
105
|
+
* ],
|
|
106
|
+
* })
|
|
107
|
+
* export class AppModule {}
|
|
108
|
+
*
|
|
109
|
+
* const userQueryKey = createPartitionedCacheKeyFactory({
|
|
110
|
+
* principal: (ctx) => ctx.items.get('userId') as string | undefined,
|
|
111
|
+
* scope: (ctx) => ctx.items.get('capabilityVersion') as string | undefined,
|
|
112
|
+
* });
|
|
113
|
+
*
|
|
114
|
+
* @QueryHandler(GetUserQuery)
|
|
115
|
+
* @UsePipeline([CacheBehavior, { key: userQueryKey, ttl: 60_000 }])
|
|
116
|
+
* export class GetUserHandler implements IQueryHandler<GetUserQuery> {}
|
|
117
|
+
* ```
|
|
118
|
+
*
|
|
119
|
+
* @example Redis store
|
|
120
|
+
* ```ts
|
|
121
|
+
* CacheModule.forRoot({
|
|
122
|
+
* store: { type: 'redis', url: 'redis://localhost:6379' },
|
|
123
|
+
* ttl: 60_000,
|
|
124
|
+
* })
|
|
125
|
+
* ```
|
|
126
|
+
*
|
|
127
|
+
* @example Tiered memory + postgres store
|
|
128
|
+
* ```ts
|
|
129
|
+
* CacheModule.forRoot({
|
|
130
|
+
* store: [
|
|
131
|
+
* { type: 'memory', ttl: 5_000 },
|
|
132
|
+
* { type: 'postgres', url: 'postgresql://user:pass@localhost:5432/db' },
|
|
133
|
+
* ],
|
|
134
|
+
* })
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
let CacheModule = CacheModule_1 = class CacheModule {
|
|
138
|
+
/**
|
|
139
|
+
* Registers the cache behavior, the cache instance, and optional
|
|
140
|
+
* application-wide defaults.
|
|
141
|
+
*
|
|
142
|
+
* @param options - Store configuration and default behavior options.
|
|
143
|
+
* @returns The configured global {@link DynamicModule}.
|
|
144
|
+
*/
|
|
145
|
+
static forRoot(options = {}) {
|
|
146
|
+
return {
|
|
147
|
+
module: CacheModule_1,
|
|
148
|
+
global: true,
|
|
149
|
+
providers: cacheProviders({
|
|
150
|
+
provide: tokens_1.CACHE_MODULE_OPTIONS,
|
|
151
|
+
useValue: options,
|
|
152
|
+
}),
|
|
153
|
+
exports: CACHE_EXPORTS,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Registers the cache behavior with options resolved from injected
|
|
158
|
+
* dependencies (for example configuration read at startup).
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```ts
|
|
162
|
+
* CacheModule.forRootAsync({
|
|
163
|
+
* inject: [ConfigService],
|
|
164
|
+
* useFactory: (config: ConfigService) => ({
|
|
165
|
+
* store: { type: 'redis', url: config.getOrThrow('REDIS_URL') },
|
|
166
|
+
* ttl: 30_000,
|
|
167
|
+
* }),
|
|
168
|
+
* });
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
static forRootAsync(options) {
|
|
172
|
+
return {
|
|
173
|
+
module: CacheModule_1,
|
|
174
|
+
global: true,
|
|
175
|
+
imports: options.imports ?? [],
|
|
176
|
+
providers: cacheProviders({
|
|
177
|
+
provide: tokens_1.CACHE_MODULE_OPTIONS,
|
|
178
|
+
useFactory: options.useFactory,
|
|
179
|
+
inject: options.inject ?? [],
|
|
180
|
+
}),
|
|
181
|
+
exports: CACHE_EXPORTS,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
exports.CacheModule = CacheModule;
|
|
186
|
+
exports.CacheModule = CacheModule = CacheModule_1 = __decorate([
|
|
187
|
+
(0, common_1.Module)({})
|
|
188
|
+
], CacheModule);
|
|
189
|
+
//# sourceMappingURL=cache.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.module.js","sourceRoot":"","sources":["../src/cache.module.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Injection token holding the shared `cache-manager` {@link import('cache-manager').Cache}
|
|
3
|
+
* instance built by {@link CacheModule.forRoot} or {@link CacheModule.forRootAsync}.
|
|
4
|
+
*/
|
|
5
|
+
export declare const PIPELINE_CACHE: unique symbol;
|
|
6
|
+
/**
|
|
7
|
+
* Injection token holding the module-wide default {@link CacheBehaviorOptions}
|
|
8
|
+
* merged into every handler's per-pipeline configuration.
|
|
9
|
+
*/
|
|
10
|
+
export declare const CACHE_DEFAULT_OPTIONS: unique symbol;
|
|
11
|
+
/** Injection token holding the resolved {@link CacheModuleOptions}. @internal */
|
|
12
|
+
export declare const CACHE_MODULE_OPTIONS: unique symbol;
|
|
13
|
+
//# sourceMappingURL=tokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/constants/tokens.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,eAAO,MAAM,cAAc,eAA2B,CAAC;AAEvD;;;GAGG;AACH,eAAO,MAAM,qBAAqB,eAAkC,CAAC;AAErE,iFAAiF;AACjF,eAAO,MAAM,oBAAoB,eAAiC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.CACHE_MODULE_OPTIONS = exports.CACHE_DEFAULT_OPTIONS = exports.PIPELINE_CACHE = void 0;
|
|
5
|
+
/**
|
|
6
|
+
* Injection token holding the shared `cache-manager` {@link import('cache-manager').Cache}
|
|
7
|
+
* instance built by {@link CacheModule.forRoot} or {@link CacheModule.forRootAsync}.
|
|
8
|
+
*/
|
|
9
|
+
exports.PIPELINE_CACHE = Symbol('PIPELINE_CACHE');
|
|
10
|
+
/**
|
|
11
|
+
* Injection token holding the module-wide default {@link CacheBehaviorOptions}
|
|
12
|
+
* merged into every handler's per-pipeline configuration.
|
|
13
|
+
*/
|
|
14
|
+
exports.CACHE_DEFAULT_OPTIONS = Symbol('CACHE_DEFAULT_OPTIONS');
|
|
15
|
+
/** Injection token holding the resolved {@link CacheModuleOptions}. @internal */
|
|
16
|
+
exports.CACHE_MODULE_OPTIONS = Symbol('CACHE_MODULE_OPTIONS');
|
|
17
|
+
//# sourceMappingURL=tokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/constants/tokens.ts"],"names":[],"mappings":";AAAA,sEAAsE;;;AAEtE;;;GAGG;AACU,QAAA,cAAc,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;AAEvD;;;GAGG;AACU,QAAA,qBAAqB,GAAG,MAAM,CAAC,uBAAuB,CAAC,CAAC;AAErE,iFAAiF;AACpE,QAAA,oBAAoB,GAAG,MAAM,CAAC,sBAAsB,CAAC,CAAC"}
|